diff --git a/core/flash.c b/core/flash.c index 203b695d522a..bfa4a7207a79 100644 --- a/core/flash.c +++ b/core/flash.c @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -79,6 +80,17 @@ void flash_release(void) unlock(&flash_lock); } +bool flash_unregister(void) +{ + struct blocklevel_device *bl = system_flash->bl; + + if (bl->exit) + return bl->exit(bl); + + prlog(PR_NOTICE, "FLASH: Unregister flash device is not supported\n"); + return true; +} + static int flash_nvram_info(uint32_t *total_size) { int rc; diff --git a/hw/sbe-p9.c b/hw/sbe-p9.c index 5c63ec1cc91e..1b5f29ec1231 100644 --- a/hw/sbe-p9.c +++ b/hw/sbe-p9.c @@ -952,6 +952,12 @@ void p9_sbe_terminate(void) if (!dt_find_by_path(opal_node, "dump")) return; + /* Unregister flash. It will request BMC MBOX reset */ + if (!flash_unregister()) { + prlog(PR_DEBUG, "Failed to reset BMC MBOX\n"); + return; + } + /* Save crashing CPU details */ opal_mpipl_save_crashing_pir(); diff --git a/include/skiboot.h b/include/skiboot.h index 6cac1cfda6c1..e554325b5d86 100644 --- a/include/skiboot.h +++ b/include/skiboot.h @@ -212,6 +212,7 @@ extern int flash_start_preload_resource(enum resource_id id, uint32_t subid, extern int flash_resource_loaded(enum resource_id id, uint32_t idx); extern bool flash_reserve(void); extern void flash_release(void); +extern bool flash_unregister(void); #define FLASH_SUBPART_ALIGNMENT 0x1000 #define FLASH_SUBPART_HEADER_SIZE FLASH_SUBPART_ALIGNMENT extern int flash_subpart_info(void *part_header, uint32_t header_len, diff --git a/libflash/blocklevel.h b/libflash/blocklevel.h index 8a0e855b6c47..492918e5f948 100644 --- a/libflash/blocklevel.h +++ b/libflash/blocklevel.h @@ -35,6 +35,7 @@ struct blocklevel_device { int (*erase)(struct blocklevel_device *bl, uint64_t pos, uint64_t len); int (*get_info)(struct blocklevel_device *bl, const char **name, uint64_t *total_size, uint32_t *erase_granule); + bool (*exit)(struct blocklevel_device *bl); /* * Keep the erase mask so that blocklevel_erase() can do sanity checking diff --git a/libflash/ipmi-hiomap.c b/libflash/ipmi-hiomap.c index 5f720ef050b2..7327b83a320c 100644 --- a/libflash/ipmi-hiomap.c +++ b/libflash/ipmi-hiomap.c @@ -210,6 +210,7 @@ static void ipmi_hiomap_cmd_cb(struct ipmi_msg *msg) case HIOMAP_C_FLUSH: case HIOMAP_C_ACK: case HIOMAP_C_ERASE: + case HIOMAP_C_RESET: if (msg->resp_size != 2) { prerror("%u: Unexpected response size: %u\n", msg->data[0], msg->resp_size); @@ -516,6 +517,29 @@ static int hiomap_erase(struct ipmi_hiomap *ctx, uint64_t offset, return 0; } +static bool hiomap_reset(struct ipmi_hiomap *ctx) +{ + RESULT_INIT(res, ctx); + unsigned char req[2]; + struct ipmi_msg *msg; + + prlog(PR_NOTICE, "Reset\n"); + + req[0] = HIOMAP_C_RESET; + req[1] = ++ctx->seq; + msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE, + bmc_platform->sw->ipmi_oem_hiomap_cmd, + ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2); + ipmi_queue_msg_sync(msg); + + if (res.cc != IPMI_CC_NO_ERROR) { + prlog(PR_ERR, "%s failed: %d\n", __func__, res.cc); + return false; + } + + return true; +} + static void hiomap_event(uint8_t events, void *context) { struct ipmi_hiomap *ctx = context; @@ -906,6 +930,7 @@ int ipmi_hiomap_init(struct blocklevel_device **bl) ctx->bl.write = &ipmi_hiomap_write; ctx->bl.erase = &ipmi_hiomap_erase; ctx->bl.get_info = &ipmi_hiomap_get_flash_info; + ctx->bl.exit = &ipmi_hiomap_exit; hiomap_init(ctx); @@ -955,11 +980,16 @@ int ipmi_hiomap_init(struct blocklevel_device **bl) return rc; } -void ipmi_hiomap_exit(struct blocklevel_device *bl) +bool ipmi_hiomap_exit(struct blocklevel_device *bl) { + bool status = true; + struct ipmi_hiomap *ctx; if (bl) { ctx = container_of(bl, struct ipmi_hiomap, bl); + status = hiomap_reset(ctx); free(ctx); } + + return status; } diff --git a/libflash/ipmi-hiomap.h b/libflash/ipmi-hiomap.h index b517c1f61fe0..489d55e20863 100644 --- a/libflash/ipmi-hiomap.h +++ b/libflash/ipmi-hiomap.h @@ -40,6 +40,6 @@ struct ipmi_hiomap { }; int ipmi_hiomap_init(struct blocklevel_device **bl); -void ipmi_hiomap_exit(struct blocklevel_device *bl); +bool ipmi_hiomap_exit(struct blocklevel_device *bl); #endif /* __LIBFLASH_IPMI_HIOMAP_H */ diff --git a/libflash/mbox-flash.c b/libflash/mbox-flash.c index 5cede3c710ac..9d47fe7ea3af 100644 --- a/libflash/mbox-flash.c +++ b/libflash/mbox-flash.c @@ -803,6 +803,28 @@ static int mbox_flash_read(struct blocklevel_device *bl, uint64_t pos, return rc; } +static bool mbox_flash_reset(struct blocklevel_device *bl) +{ + int rc; + struct mbox_flash_data *mbox_flash; + struct bmc_mbox_msg msg = MSG_CREATE(MBOX_C_RESET_STATE); + + prlog(PR_NOTICE, "MBOX reset\n"); + mbox_flash = container_of(bl, struct mbox_flash_data, bl); + + rc = msg_send(mbox_flash, &msg, mbox_flash->timeout); + if (rc) { + prlog(PR_ERR, "Failed to enqueue/send BMC MBOX RESET msg\n"); + return false; + } + if (wait_for_bmc(mbox_flash, mbox_flash->timeout)) { + prlog(PR_ERR, "Error waiting for BMC\n"); + return false; + } + + return true; +} + static int mbox_flash_get_info(struct blocklevel_device *bl, const char **name, uint64_t *total_size, uint32_t *erase_granule) { @@ -1138,6 +1160,7 @@ int mbox_flash_init(struct blocklevel_device **bl) mbox_flash->bl.write = &mbox_flash_write; mbox_flash->bl.erase = &mbox_flash_erase_v2; mbox_flash->bl.get_info = &mbox_flash_get_info; + mbox_flash->bl.exit = &mbox_flash_exit; if (bmc_mbox_get_attn_reg() & MBOX_ATTN_BMC_REBOOT) rc = handle_reboot(mbox_flash); @@ -1154,11 +1177,15 @@ int mbox_flash_init(struct blocklevel_device **bl) return 0; } -void mbox_flash_exit(struct blocklevel_device *bl) +bool mbox_flash_exit(struct blocklevel_device *bl) { + bool status = true; struct mbox_flash_data *mbox_flash; if (bl) { + status = mbox_flash_reset(bl); mbox_flash = container_of(bl, struct mbox_flash_data, bl); free(mbox_flash); } + + return status; } diff --git a/libflash/mbox-flash.h b/libflash/mbox-flash.h index 7a8201c3fce6..73ac6a3e1e5a 100644 --- a/libflash/mbox-flash.h +++ b/libflash/mbox-flash.h @@ -6,7 +6,7 @@ int mbox_flash_lock(struct blocklevel_device *bl, uint64_t pos, uint64_t len); int mbox_flash_init(struct blocklevel_device **bl); -void mbox_flash_exit(struct blocklevel_device *bl); +bool mbox_flash_exit(struct blocklevel_device *bl); #endif /* __LIBFLASH_MBOX_FLASH_H */ diff --git a/libflash/test/mbox-server.c b/libflash/test/mbox-server.c index 69499dc8e208..3f879dfa4e29 100644 --- a/libflash/test/mbox-server.c +++ b/libflash/test/mbox-server.c @@ -273,6 +273,7 @@ int bmc_mbox_enqueue(struct bmc_mbox_msg *msg, switch (msg->command) { case MBOX_C_RESET_STATE: prlog(PR_INFO, "RESET_STATE\n"); + server_state.win_type = WIN_CLOSED; rc = open_window(msg, false, 0, LPC_BLOCKS); memset(msg->args, 0, sizeof(msg->args)); break; diff --git a/libflash/test/test-ipmi-hiomap.c b/libflash/test/test-ipmi-hiomap.c index 30dbe2493689..d3343fe46baa 100644 --- a/libflash/test/test-ipmi-hiomap.c +++ b/libflash/test/test-ipmi-hiomap.c @@ -479,10 +479,101 @@ static const struct scenario_event hiomap_erase_qs0l1_call = { }, }; +static const struct scenario_event hiomap_reset_call_seq_4 = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 4, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 4, + }, + }, +}; + +static const struct scenario_event hiomap_reset_call_seq_5 = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 5, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 5, + }, + }, +}; + +static const struct scenario_event hiomap_reset_call_seq_6 = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 6, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 6, + }, + }, +}; + +static const struct scenario_event hiomap_reset_call_seq_7 = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 7, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 7, + }, + }, +}; + +static const struct scenario_event hiomap_reset_call_seq_9 = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 9, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 9, + }, + }, +}; + +static const struct scenario_event hiomap_reset_call_seq_a = { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 0xa, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 0xa, + }, + }, +}; + static const struct scenario_event scenario_hiomap_init[] = { { .type = scenario_event_p, .p = &hiomap_ack_call, }, { .type = scenario_event_p, .p = &hiomap_get_info_call, }, { .type = scenario_event_p, .p = &hiomap_get_flash_info_call, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_4, }, SCENARIO_SENTINEL, }; @@ -501,6 +592,7 @@ static const struct scenario_event scenario_hiomap_event_daemon_ready[] = { { .type = scenario_event_p, .p = &hiomap_get_info_call, }, { .type = scenario_event_p, .p = &hiomap_get_flash_info_call, }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_4, }, SCENARIO_SENTINEL, }; @@ -523,6 +615,7 @@ static const struct scenario_event scenario_hiomap_event_daemon_stopped[] = { { .type = scenario_event_p, .p = &hiomap_get_flash_info_call, }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_4, }, SCENARIO_SENTINEL, }; @@ -546,6 +639,7 @@ static const struct scenario_event scenario_hiomap_event_daemon_restarted[] = { { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_DAEMON_READY } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_4, }, SCENARIO_SENTINEL, }; @@ -575,6 +669,7 @@ scenario_hiomap_event_daemon_lost_flash_control[] = { | HIOMAP_E_FLASH_LOST), } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -680,6 +775,7 @@ scenario_hiomap_event_daemon_regained_flash_control_dirty[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -822,6 +918,7 @@ static const struct scenario_event scenario_hiomap_protocol_reset_recovery[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_9, }, SCENARIO_SENTINEL, }; @@ -854,6 +951,7 @@ scenario_hiomap_protocol_read_one_block[] = { .type = scenario_event_p, .p = &hiomap_create_read_window_qs0l1_rs0l1_call, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -927,6 +1025,7 @@ scenario_hiomap_protocol_read_two_blocks[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -979,6 +1078,7 @@ scenario_hiomap_protocol_read_one_block_twice[] = { .type = scenario_event_p, .p = &hiomap_create_read_window_qs0l1_rs0l1_call, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1014,6 +1114,7 @@ scenario_hiomap_protocol_event_before_action[] = { HIOMAP_E_FLASH_LOST, } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1047,6 +1148,7 @@ scenario_hiomap_protocol_event_during_read[] = { HIOMAP_E_FLASH_LOST, } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1082,6 +1184,7 @@ scenario_hiomap_protocol_write_one_block[] = { }, { .type = scenario_event_p, .p = &hiomap_mark_dirty_qs0l1_call, }, { .type = scenario_event_p, .p = &hiomap_flush_call, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -1166,6 +1269,7 @@ scenario_hiomap_protocol_write_two_blocks[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_a, }, SCENARIO_SENTINEL, }; @@ -1248,6 +1352,7 @@ scenario_hiomap_protocol_write_one_block_twice[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_9, }, SCENARIO_SENTINEL, }; @@ -1301,6 +1406,7 @@ scenario_hiomap_protocol_event_during_write[] = { HIOMAP_E_FLASH_LOST, } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -1342,6 +1448,7 @@ scenario_hiomap_protocol_erase_one_block[] = { .type = scenario_event_p, .p = &hiomap_flush_call, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -1390,6 +1497,7 @@ scenario_hiomap_protocol_erase_two_blocks[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_a, }, SCENARIO_SENTINEL, }; @@ -1449,6 +1557,7 @@ scenario_hiomap_protocol_erase_one_block_twice[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_9, }, SCENARIO_SENTINEL, }; @@ -1516,6 +1625,7 @@ scenario_hiomap_protocol_event_during_erase[] = { HIOMAP_E_FLASH_LOST, } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -1620,6 +1730,7 @@ scenario_hiomap_protocol_get_flash_info[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1646,6 +1757,7 @@ scenario_hiomap_protocol_persistent_error[] = { { .type = scenario_event_p, .p = &hiomap_get_info_call, }, { .type = scenario_event_p, .p = &hiomap_get_flash_info_call, }, { .type = scenario_sel, .s = { .bmc_state = HIOMAP_E_PROTOCOL_RESET } }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -1744,6 +1856,7 @@ scenario_hiomap_create_read_window_error[] = { .cc = IPMI_INVALID_COMMAND_ERR, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1785,6 +1898,7 @@ scenario_hiomap_create_write_window_error[] = { .cc = IPMI_INVALID_COMMAND_ERR, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -1829,6 +1943,7 @@ static const struct scenario_event scenario_hiomap_mark_dirty_error[] = { .cc = IPMI_INVALID_COMMAND_ERR, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -1870,6 +1985,7 @@ static const struct scenario_event scenario_hiomap_flush_error[] = { .cc = IPMI_INVALID_COMMAND_ERR, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -1920,6 +2036,7 @@ static const struct scenario_event scenario_hiomap_erase_error[] = { .cc = IPMI_INVALID_COMMAND_ERR, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -2140,6 +2257,7 @@ scenario_hiomap_create_read_window_malformed_small[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -2187,6 +2305,7 @@ scenario_hiomap_create_read_window_malformed_large[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -2233,6 +2352,7 @@ scenario_hiomap_create_write_window_malformed_small[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -2280,6 +2400,7 @@ scenario_hiomap_create_write_window_malformed_large[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_5, }, SCENARIO_SENTINEL, }; @@ -2329,6 +2450,7 @@ scenario_hiomap_mark_dirty_malformed_small[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -2379,6 +2501,7 @@ scenario_hiomap_mark_dirty_malformed_large[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -2425,6 +2548,7 @@ scenario_hiomap_flush_malformed_small[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -2472,6 +2596,7 @@ scenario_hiomap_flush_malformed_large[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_7, }, SCENARIO_SENTINEL, }; @@ -2521,6 +2646,7 @@ scenario_hiomap_erase_malformed_small[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -2566,6 +2692,7 @@ scenario_hiomap_erase_malformed_large[] = { }, }, }, + { .type = scenario_event_p, .p = &hiomap_reset_call_seq_6, }, SCENARIO_SENTINEL, }; @@ -2771,6 +2898,20 @@ scenario_hiomap_protocol_recovery_failure_ack[] = { }, }, }, + { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 14, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 14, + }, + }, + }, SCENARIO_SENTINEL, }; @@ -2941,6 +3082,20 @@ scenario_hiomap_protocol_recovery_failure_get_info[] = { }, }, }, + { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 15, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 15, + }, + }, + }, SCENARIO_SENTINEL, }; @@ -3110,6 +3265,20 @@ scenario_hiomap_protocol_recovery_failure_get_flash_info[] = { }, }, }, + { + .type = scenario_cmd, + .c = { + .req = { + .cmd = HIOMAP_C_RESET, + .seq = 16, + }, + .cc = IPMI_CC_NO_ERROR, + .resp = { + .cmd = HIOMAP_C_RESET, + .seq = 16, + }, + }, + }, SCENARIO_SENTINEL, };