LCOV - code coverage report
Current view: top level - libflash - ipmi-hiomap.c (source / functions) Hit Total Coverage
Test: skiboot.info Lines: 425 461 92.2 %
Date: 2024-01-02 21:04:04 Functions: 26 26 100.0 %
Branches: 0 0 -

           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                 :            : #define pr_fmt(fmt) "HIOMAP: " fmt
       5                 :            : 
       6                 :            : #include <hiomap.h>
       7                 :            : #include <inttypes.h>
       8                 :            : #include <ipmi.h>
       9                 :            : #include <lpc.h>
      10                 :            : #include <mem_region-malloc.h>
      11                 :            : #include <stdbool.h>
      12                 :            : #include <stdint.h>
      13                 :            : #include <string.h>
      14                 :            : 
      15                 :            : #include <ccan/container_of/container_of.h>
      16                 :            : 
      17                 :            : #include "errors.h"
      18                 :            : #include "ipmi-hiomap.h"
      19                 :            : 
      20                 :            : #define CMD_OP_HIOMAP_EVENT     0x0f
      21                 :            : 
      22                 :            : struct ipmi_hiomap_result {
      23                 :            :         struct ipmi_hiomap *ctx;
      24                 :            :         int16_t cc;
      25                 :            : };
      26                 :            : 
      27                 :            : #define RESULT_INIT(_name, _ctx) struct ipmi_hiomap_result _name = { _ctx, -1 }
      28                 :            : 
      29                 :        222 : static inline uint32_t blocks_to_bytes(struct ipmi_hiomap *ctx, uint16_t blocks)
      30                 :            : {
      31                 :        222 :         return blocks << ctx->block_size_shift;
      32                 :            : }
      33                 :            : 
      34                 :         80 : static inline uint16_t bytes_to_blocks(struct ipmi_hiomap *ctx, uint32_t bytes)
      35                 :            : {
      36                 :         80 :         return bytes >> ctx->block_size_shift;
      37                 :            : }
      38                 :            : 
      39                 :         80 : static inline uint16_t bytes_to_blocks_align_up(struct ipmi_hiomap *ctx,
      40                 :            :                                                 uint32_t pos, uint32_t len)
      41                 :            : {
      42                 :         80 :         uint32_t block_size = 1 << ctx->block_size_shift;
      43                 :         80 :         uint32_t delta = pos & (block_size - 1);
      44                 :         80 :         uint32_t aligned = ALIGN_UP((len + delta), block_size);
      45                 :         80 :         uint32_t blocks = aligned >> ctx->block_size_shift;
      46                 :            :         /* Our protocol can handle block count < sizeof(u16) */
      47                 :         80 :         uint32_t mask = ((1 << 16) - 1);
      48                 :            : 
      49                 :         80 :         assert(!(blocks & ~mask));
      50                 :            : 
      51                 :         80 :         return blocks & mask;
      52                 :            : }
      53                 :            : 
      54                 :            : /* Call under ctx->lock */
      55                 :        282 : static int hiomap_protocol_ready(struct ipmi_hiomap *ctx)
      56                 :            : {
      57                 :        282 :         if (!(ctx->bmc_state & HIOMAP_E_DAEMON_READY))
      58                 :          2 :                 return FLASH_ERR_DEVICE_GONE;
      59                 :        280 :         if (ctx->bmc_state & HIOMAP_E_FLASH_LOST)
      60                 :          6 :                 return FLASH_ERR_AGAIN;
      61                 :            : 
      62                 :        274 :         return 0;
      63                 :            : }
      64                 :            : 
      65                 :        282 : static int hiomap_queue_msg_sync(struct ipmi_hiomap *ctx, struct ipmi_msg *msg)
      66                 :            : {
      67                 :            :         int rc;
      68                 :            : 
      69                 :            :         /*
      70                 :            :          * There's an unavoidable TOCTOU race here with the BMC sending an
      71                 :            :          * event saying it's no-longer available right after we test but before
      72                 :            :          * we call into the IPMI stack to send the message.
      73                 :            :          * hiomap_queue_msg_sync() exists to capture the race in a single
      74                 :            :          * location.
      75                 :            :          */
      76                 :        282 :         lock(&ctx->lock);
      77                 :        282 :         rc = hiomap_protocol_ready(ctx);
      78                 :        282 :         unlock(&ctx->lock);
      79                 :        282 :         if (rc) {
      80                 :          8 :                 ipmi_free_msg(msg);
      81                 :          8 :                 return rc;
      82                 :            :         }
      83                 :            : 
      84                 :        274 :         ipmi_queue_msg_sync(msg);
      85                 :            : 
      86                 :        274 :         return 0;
      87                 :            : }
      88                 :            : 
      89                 :            : /* Call under ctx->lock */
      90                 :         66 : static int hiomap_window_valid(struct ipmi_hiomap *ctx, uint64_t pos,
      91                 :            :                                 uint64_t len)
      92                 :            : {
      93                 :         66 :         if (ctx->bmc_state & HIOMAP_E_FLASH_LOST)
      94                 :          5 :                 return FLASH_ERR_AGAIN;
      95                 :         61 :         if (ctx->bmc_state & HIOMAP_E_PROTOCOL_RESET)
      96                 :          0 :                 return FLASH_ERR_AGAIN;
      97                 :         61 :         if (ctx->bmc_state & HIOMAP_E_WINDOW_RESET)
      98                 :          0 :                 return FLASH_ERR_AGAIN;
      99                 :         61 :         if (ctx->window_state == closed_window)
     100                 :         41 :                 return FLASH_ERR_PARM_ERROR;
     101                 :         20 :         if (pos < ctx->current.cur_pos)
     102                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     103                 :         20 :         if ((pos + len) > (ctx->current.cur_pos + ctx->current.size))
     104                 :          5 :                 return FLASH_ERR_PARM_ERROR;
     105                 :            : 
     106                 :         15 :         return 0;
     107                 :            : }
     108                 :            : 
     109                 :        320 : static void ipmi_hiomap_cmd_cb(struct ipmi_msg *msg)
     110                 :            : {
     111                 :        320 :         struct ipmi_hiomap_result *res = msg->user_data;
     112                 :        320 :         struct ipmi_hiomap *ctx = res->ctx;
     113                 :            : 
     114                 :        320 :         res->cc = msg->cc;
     115                 :        320 :         if (msg->cc != IPMI_CC_NO_ERROR) {
     116                 :         12 :                 ipmi_free_msg(msg);
     117                 :         12 :                 return;
     118                 :            :         }
     119                 :            : 
     120                 :            :         /* We at least need the command and sequence */
     121                 :        308 :         if (msg->resp_size < 2) {
     122                 :          4 :                 prerror("Illegal response size: %u\n", msg->resp_size);
     123                 :          4 :                 res->cc = IPMI_ERR_UNSPECIFIED;
     124                 :          4 :                 ipmi_free_msg(msg);
     125                 :          4 :                 return;
     126                 :            :         }
     127                 :            : 
     128                 :        304 :         if (msg->data[1] != ctx->seq) {
     129                 :          1 :                 prerror("Unmatched sequence number: wanted %u got %u\n",
     130                 :            :                         ctx->seq, msg->data[1]);
     131                 :          1 :                 res->cc = IPMI_ERR_UNSPECIFIED;
     132                 :          1 :                 ipmi_free_msg(msg);
     133                 :          1 :                 return;
     134                 :            :         }
     135                 :            : 
     136                 :        303 :         switch (msg->data[0]) {
     137                 :         56 :         case HIOMAP_C_GET_INFO:
     138                 :            :         {
     139                 :            :                 struct hiomap_v2_info *parms;
     140                 :            : 
     141                 :         56 :                 if (msg->resp_size != 6) {
     142                 :          2 :                         prerror("%u: Unexpected response size: %u\n", msg->data[0],
     143                 :            :                                 msg->resp_size);
     144                 :          2 :                         res->cc = IPMI_ERR_UNSPECIFIED;
     145                 :          2 :                         break;
     146                 :            :                 }
     147                 :            : 
     148                 :         54 :                 ctx->version = msg->data[2];
     149                 :         54 :                 if (ctx->version < 2) {
     150                 :          0 :                         prerror("Failed to negotiate protocol v2 or higher: %d\n",
     151                 :            :                                 ctx->version);
     152                 :          0 :                         res->cc = IPMI_ERR_UNSPECIFIED;
     153                 :          0 :                         break;
     154                 :            :                 }
     155                 :            : 
     156                 :         54 :                 parms = (struct hiomap_v2_info *)&msg->data[3];
     157                 :         54 :                 ctx->block_size_shift = parms->block_size_shift;
     158                 :         54 :                 ctx->timeout = le16_to_cpu(parms->timeout);
     159                 :         54 :                 break;
     160                 :            :         }
     161                 :         53 :         case HIOMAP_C_GET_FLASH_INFO:
     162                 :            :         {
     163                 :            :                 struct hiomap_v2_flash_info *parms;
     164                 :            : 
     165                 :         53 :                 if (msg->resp_size != 6) {
     166                 :          2 :                         prerror("%u: Unexpected response size: %u\n", msg->data[0],
     167                 :            :                                 msg->resp_size);
     168                 :          2 :                         res->cc = IPMI_ERR_UNSPECIFIED;
     169                 :          2 :                         break;
     170                 :            :                 }
     171                 :            : 
     172                 :         51 :                 parms = (struct hiomap_v2_flash_info *)&msg->data[2];
     173                 :         51 :                 ctx->total_size =
     174                 :         51 :                         blocks_to_bytes(ctx, le16_to_cpu(parms->total_size));
     175                 :         51 :                 ctx->erase_granule =
     176                 :         51 :                         blocks_to_bytes(ctx, le16_to_cpu(parms->erase_granule));
     177                 :         51 :                 break;
     178                 :            :         }
     179                 :         44 :         case HIOMAP_C_CREATE_READ_WINDOW:
     180                 :            :         case HIOMAP_C_CREATE_WRITE_WINDOW:
     181                 :            :         {
     182                 :            :                 struct hiomap_v2_create_window *parms;
     183                 :            : 
     184                 :         44 :                 if (msg->resp_size != 8) {
     185                 :          4 :                         prerror("%u: Unexpected response size: %u\n", msg->data[0],
     186                 :            :                                 msg->resp_size);
     187                 :          4 :                         res->cc = IPMI_ERR_UNSPECIFIED;
     188                 :          4 :                         break;
     189                 :            :                 }
     190                 :            : 
     191                 :         40 :                 parms = (struct hiomap_v2_create_window *)&msg->data[2];
     192                 :            : 
     193                 :         40 :                 ctx->current.lpc_addr =
     194                 :         40 :                         blocks_to_bytes(ctx, le16_to_cpu(parms->lpc_addr));
     195                 :         40 :                 ctx->current.size =
     196                 :         40 :                         blocks_to_bytes(ctx, le16_to_cpu(parms->size));
     197                 :         40 :                 ctx->current.cur_pos =
     198                 :         40 :                         blocks_to_bytes(ctx, le16_to_cpu(parms->offset));
     199                 :            : 
     200                 :         40 :                 lock(&ctx->lock);
     201                 :         40 :                 if (msg->data[0] == HIOMAP_C_CREATE_READ_WINDOW)
     202                 :         12 :                         ctx->window_state = read_window;
     203                 :            :                 else
     204                 :         28 :                         ctx->window_state = write_window;
     205                 :         40 :                 unlock(&ctx->lock);
     206                 :            : 
     207                 :         40 :                 break;
     208                 :            :         }
     209                 :        150 :         case HIOMAP_C_MARK_DIRTY:
     210                 :            :         case HIOMAP_C_FLUSH:
     211                 :            :         case HIOMAP_C_ACK:
     212                 :            :         case HIOMAP_C_ERASE:
     213                 :            :         case HIOMAP_C_RESET:
     214                 :        150 :                 if (msg->resp_size != 2) {
     215                 :          4 :                         prerror("%u: Unexpected response size: %u\n", msg->data[0],
     216                 :            :                                 msg->resp_size);
     217                 :          4 :                         res->cc = IPMI_ERR_UNSPECIFIED;
     218                 :          4 :                         break;
     219                 :            :                 }
     220                 :        146 :                 break;
     221                 :          0 :         default:
     222                 :          0 :                 prlog(PR_WARNING, "Unimplemented command handler: %u\n",
     223                 :            :                       msg->data[0]);
     224                 :          0 :                 break;
     225                 :            :         };
     226                 :        303 :         ipmi_free_msg(msg);
     227                 :            : }
     228                 :            : 
     229                 :         57 : static void hiomap_init(struct ipmi_hiomap *ctx)
     230                 :            : {
     231                 :            :         /*
     232                 :            :          * Speculatively mark the daemon as available so we attempt to perform
     233                 :            :          * the handshake without immediately bailing out.
     234                 :            :          */
     235                 :         57 :         lock(&ctx->lock);
     236                 :         57 :         ctx->bmc_state = HIOMAP_E_DAEMON_READY;
     237                 :         57 :         unlock(&ctx->lock);
     238                 :         57 : }
     239                 :            : 
     240                 :         58 : static int hiomap_get_info(struct ipmi_hiomap *ctx)
     241                 :            : {
     242                 :         58 :         RESULT_INIT(res, ctx);
     243                 :            :         unsigned char req[3];
     244                 :            :         struct ipmi_msg *msg;
     245                 :            :         int rc;
     246                 :            : 
     247                 :            :         /* Negotiate protocol version 2 */
     248                 :         58 :         req[0] = HIOMAP_C_GET_INFO;
     249                 :         58 :         req[1] = ++ctx->seq;
     250                 :         58 :         req[2] = HIOMAP_V2;
     251                 :            : 
     252                 :         58 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     253                 :         58 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     254                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 6);
     255                 :            : 
     256                 :         58 :         rc = hiomap_queue_msg_sync(ctx, msg);
     257                 :         58 :         if (rc)
     258                 :          0 :                 return rc;
     259                 :            : 
     260                 :         58 :         if (res.cc != IPMI_CC_NO_ERROR) {
     261                 :          4 :                 prerror("%s failed: %d\n", __func__, res.cc);
     262                 :          4 :                 return FLASH_ERR_PARM_ERROR; /* XXX: Find something better? */
     263                 :            :         }
     264                 :            : 
     265                 :         54 :         return 0;
     266                 :            : }
     267                 :            : 
     268                 :         55 : static int hiomap_get_flash_info(struct ipmi_hiomap *ctx)
     269                 :            : {
     270                 :         55 :         RESULT_INIT(res, ctx);
     271                 :            :         unsigned char req[2];
     272                 :            :         struct ipmi_msg *msg;
     273                 :            :         int rc;
     274                 :            : 
     275                 :         55 :         req[0] = HIOMAP_C_GET_FLASH_INFO;
     276                 :         55 :         req[1] = ++ctx->seq;
     277                 :         55 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     278                 :         55 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     279                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2 + 2 + 2);
     280                 :            : 
     281                 :         55 :         rc = hiomap_queue_msg_sync(ctx, msg);
     282                 :         55 :         if (rc)
     283                 :          0 :                 return rc;
     284                 :            : 
     285                 :         55 :         if (res.cc != IPMI_CC_NO_ERROR) {
     286                 :          4 :                 prerror("%s failed: %d\n", __func__, res.cc);
     287                 :          4 :                 return FLASH_ERR_PARM_ERROR; /* XXX: Find something better? */
     288                 :            :         }
     289                 :            : 
     290                 :         51 :         return 0;
     291                 :            : }
     292                 :            : 
     293                 :         53 : static int hiomap_window_move(struct ipmi_hiomap *ctx, uint8_t command,
     294                 :            :                               uint64_t pos, uint64_t len, uint64_t *size)
     295                 :            : {
     296                 :            :         enum lpc_window_state want_state;
     297                 :            :         struct hiomap_v2_range *range;
     298                 :         53 :         RESULT_INIT(res, ctx);
     299                 :            :         unsigned char req[6];
     300                 :            :         struct ipmi_msg *msg;
     301                 :            :         bool valid_state;
     302                 :            :         bool is_read;
     303                 :            :         int rc;
     304                 :            : 
     305                 :         53 :         is_read = (command == HIOMAP_C_CREATE_READ_WINDOW);
     306                 :         53 :         want_state = is_read ? read_window : write_window;
     307                 :            : 
     308                 :         53 :         lock(&ctx->lock);
     309                 :            : 
     310                 :         53 :         valid_state = want_state == ctx->window_state;
     311                 :         53 :         rc = hiomap_window_valid(ctx, pos, len);
     312                 :         53 :         if (valid_state && !rc) {
     313                 :          3 :                 unlock(&ctx->lock);
     314                 :          3 :                 *size = len;
     315                 :          3 :                 return 0;
     316                 :            :         }
     317                 :            : 
     318                 :         50 :         ctx->window_state = closed_window;
     319                 :            : 
     320                 :         50 :         unlock(&ctx->lock);
     321                 :            : 
     322                 :         50 :         req[0] = command;
     323                 :         50 :         req[1] = ++ctx->seq;
     324                 :            : 
     325                 :         50 :         range = (struct hiomap_v2_range *)&req[2];
     326                 :         50 :         range->offset = cpu_to_le16(bytes_to_blocks(ctx, pos));
     327                 :         50 :         range->size = cpu_to_le16(bytes_to_blocks_align_up(ctx, pos, len));
     328                 :            : 
     329                 :         50 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     330                 :         50 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     331                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req),
     332                 :            :                          2 + 2 + 2 + 2);
     333                 :            : 
     334                 :         50 :         rc = hiomap_queue_msg_sync(ctx, msg);
     335                 :         50 :         if (rc)
     336                 :          4 :                 return rc;
     337                 :            : 
     338                 :         46 :         if (res.cc != IPMI_CC_NO_ERROR) {
     339                 :          6 :                 prlog(PR_INFO, "%s failed: %d\n", __func__, res.cc);
     340                 :          6 :                 return FLASH_ERR_PARM_ERROR; /* XXX: Find something better? */
     341                 :            :         }
     342                 :            : 
     343                 :         40 :         lock(&ctx->lock);
     344                 :         40 :         *size = len;
     345                 :            :         /* Is length past the end of the window? */
     346                 :         40 :         if ((pos + len) > (ctx->current.cur_pos + ctx->current.size))
     347                 :            :                 /* Adjust size to meet current window */
     348                 :          5 :                 *size = (ctx->current.cur_pos + ctx->current.size) - pos;
     349                 :            : 
     350                 :         40 :         if (len != 0 && *size == 0) {
     351                 :          0 :                 unlock(&ctx->lock);
     352                 :          0 :                 prerror("Invalid window properties: len: %"PRIu64", size: %"PRIu64"\n",
     353                 :            :                         len, *size);
     354                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     355                 :            :         }
     356                 :            : 
     357                 :         40 :         prlog(PR_DEBUG, "Opened %s window from 0x%x for %u bytes at 0x%x\n",
     358                 :            :               (command == HIOMAP_C_CREATE_READ_WINDOW) ? "read" : "write",
     359                 :            :               ctx->current.cur_pos, ctx->current.size, ctx->current.lpc_addr);
     360                 :            : 
     361                 :         40 :         unlock(&ctx->lock);
     362                 :            : 
     363                 :         40 :         return 0;
     364                 :            : }
     365                 :            : 
     366                 :         15 : static int hiomap_mark_dirty(struct ipmi_hiomap *ctx, uint64_t offset,
     367                 :            :                               uint64_t size)
     368                 :            : {
     369                 :            :         struct hiomap_v2_range *range;
     370                 :            :         enum lpc_window_state state;
     371                 :         15 :         RESULT_INIT(res, ctx);
     372                 :            :         unsigned char req[6];
     373                 :            :         struct ipmi_msg *msg;
     374                 :            :         uint32_t pos;
     375                 :            :         int rc;
     376                 :            : 
     377                 :         15 :         lock(&ctx->lock);
     378                 :         15 :         state = ctx->window_state;
     379                 :         15 :         unlock(&ctx->lock);
     380                 :            : 
     381                 :         15 :         if (state != write_window)
     382                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     383                 :            : 
     384                 :         15 :         req[0] = HIOMAP_C_MARK_DIRTY;
     385                 :         15 :         req[1] = ++ctx->seq;
     386                 :            : 
     387                 :         15 :         pos = offset - ctx->current.cur_pos;
     388                 :         15 :         range = (struct hiomap_v2_range *)&req[2];
     389                 :         15 :         range->offset = cpu_to_le16(bytes_to_blocks(ctx, pos));
     390                 :         15 :         range->size = cpu_to_le16(bytes_to_blocks_align_up(ctx, pos, size));
     391                 :            : 
     392                 :         15 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     393                 :         15 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     394                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2);
     395                 :            : 
     396                 :         15 :         rc = hiomap_queue_msg_sync(ctx, msg);
     397                 :         15 :         if (rc)
     398                 :          1 :                 return rc;
     399                 :            : 
     400                 :         14 :         if (res.cc != IPMI_CC_NO_ERROR) {
     401                 :          3 :                 prerror("%s failed: %d\n", __func__, res.cc);
     402                 :          3 :                 return FLASH_ERR_PARM_ERROR;
     403                 :            :         }
     404                 :            : 
     405                 :         11 :         prlog(PR_DEBUG, "Marked flash dirty at 0x%" PRIx64 " for %" PRIu64 "\n",
     406                 :            :               offset, size);
     407                 :            : 
     408                 :         11 :         return 0;
     409                 :            : }
     410                 :            : 
     411                 :         22 : static int hiomap_flush(struct ipmi_hiomap *ctx)
     412                 :            : {
     413                 :            :         enum lpc_window_state state;
     414                 :         22 :         RESULT_INIT(res, ctx);
     415                 :            :         unsigned char req[2];
     416                 :            :         struct ipmi_msg *msg;
     417                 :            :         int rc;
     418                 :            : 
     419                 :         22 :         lock(&ctx->lock);
     420                 :         22 :         state = ctx->window_state;
     421                 :         22 :         unlock(&ctx->lock);
     422                 :            : 
     423                 :         22 :         if (state != write_window)
     424                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     425                 :            : 
     426                 :         22 :         req[0] = HIOMAP_C_FLUSH;
     427                 :         22 :         req[1] = ++ctx->seq;
     428                 :            : 
     429                 :         22 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     430                 :         22 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     431                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2);
     432                 :            : 
     433                 :         22 :         rc = hiomap_queue_msg_sync(ctx, msg);
     434                 :         22 :         if (rc)
     435                 :          0 :                 return rc;
     436                 :            : 
     437                 :         22 :         if (res.cc != IPMI_CC_NO_ERROR) {
     438                 :          3 :                 prerror("%s failed: %d\n", __func__, res.cc);
     439                 :          3 :                 return FLASH_ERR_PARM_ERROR;
     440                 :            :         }
     441                 :            : 
     442                 :         19 :         prlog(PR_DEBUG, "Flushed writes\n");
     443                 :            : 
     444                 :         19 :         return 0;
     445                 :            : }
     446                 :            : 
     447                 :         67 : static int hiomap_ack(struct ipmi_hiomap *ctx, uint8_t ack)
     448                 :            : {
     449                 :         67 :         RESULT_INIT(res, ctx);
     450                 :            :         unsigned char req[3];
     451                 :            :         struct ipmi_msg *msg;
     452                 :            :         int rc;
     453                 :            : 
     454                 :         67 :         req[0] = HIOMAP_C_ACK;
     455                 :         67 :         req[1] = ++ctx->seq;
     456                 :         67 :         req[2] = ack;
     457                 :            : 
     458                 :         67 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     459                 :         67 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     460                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2);
     461                 :            : 
     462                 :         67 :         rc = hiomap_queue_msg_sync(ctx, msg);
     463                 :         67 :         if (rc)
     464                 :          2 :                 return rc;
     465                 :            : 
     466                 :         65 :         if (res.cc != IPMI_CC_NO_ERROR) {
     467                 :          6 :                 prlog(PR_DEBUG, "%s failed: %d\n", __func__, res.cc);
     468                 :          6 :                 return FLASH_ERR_PARM_ERROR;
     469                 :            :         }
     470                 :            : 
     471                 :         59 :         prlog(PR_DEBUG, "Acked events: 0x%x\n", ack);
     472                 :            : 
     473                 :         59 :         return 0;
     474                 :            : }
     475                 :            : 
     476                 :         15 : static int hiomap_erase(struct ipmi_hiomap *ctx, uint64_t offset,
     477                 :            :                          uint64_t size)
     478                 :            : {
     479                 :            :         struct hiomap_v2_range *range;
     480                 :            :         enum lpc_window_state state;
     481                 :         15 :         RESULT_INIT(res, ctx);
     482                 :            :         unsigned char req[6];
     483                 :            :         struct ipmi_msg *msg;
     484                 :            :         uint32_t pos;
     485                 :            :         int rc;
     486                 :            : 
     487                 :         15 :         lock(&ctx->lock);
     488                 :         15 :         state = ctx->window_state;
     489                 :         15 :         unlock(&ctx->lock);
     490                 :            : 
     491                 :         15 :         if (state != write_window)
     492                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     493                 :            : 
     494                 :         15 :         req[0] = HIOMAP_C_ERASE;
     495                 :         15 :         req[1] = ++ctx->seq;
     496                 :            : 
     497                 :         15 :         pos = offset - ctx->current.cur_pos;
     498                 :         15 :         range = (struct hiomap_v2_range *)&req[2];
     499                 :         15 :         range->offset = cpu_to_le16(bytes_to_blocks(ctx, pos));
     500                 :         15 :         range->size = cpu_to_le16(bytes_to_blocks_align_up(ctx, pos, size));
     501                 :            : 
     502                 :         15 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     503                 :         15 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     504                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2);
     505                 :         15 :         rc = hiomap_queue_msg_sync(ctx, msg);
     506                 :         15 :         if (rc)
     507                 :          1 :                 return rc;
     508                 :            : 
     509                 :         14 :         if (res.cc != IPMI_CC_NO_ERROR) {
     510                 :          3 :                 prerror("%s failed: %d\n", __func__, res.cc);
     511                 :          3 :                 return FLASH_ERR_PARM_ERROR;
     512                 :            :         }
     513                 :            : 
     514                 :         11 :         prlog(PR_DEBUG, "Erased flash at 0x%" PRIx64 " for %" PRIu64 "\n",
     515                 :            :               offset, size);
     516                 :            : 
     517                 :         11 :         return 0;
     518                 :            : }
     519                 :            : 
     520                 :         46 : static bool hiomap_reset(struct ipmi_hiomap *ctx)
     521                 :            : {
     522                 :         46 :         RESULT_INIT(res, ctx);
     523                 :            :         unsigned char req[2];
     524                 :            :         struct ipmi_msg *msg;
     525                 :            : 
     526                 :         46 :         prlog(PR_NOTICE, "Reset\n");
     527                 :            : 
     528                 :         46 :         req[0] = HIOMAP_C_RESET;
     529                 :         46 :         req[1] = ++ctx->seq;
     530                 :         46 :         msg = ipmi_mkmsg(IPMI_DEFAULT_INTERFACE,
     531                 :         46 :                          bmc_platform->sw->ipmi_oem_hiomap_cmd,
     532                 :            :                          ipmi_hiomap_cmd_cb, &res, req, sizeof(req), 2);
     533                 :         46 :         ipmi_queue_msg_sync(msg);
     534                 :            : 
     535                 :         46 :         if (res.cc != IPMI_CC_NO_ERROR) {
     536                 :          0 :                 prlog(PR_ERR, "%s failed: %d\n", __func__, res.cc);
     537                 :          0 :                 return false;
     538                 :            :         }
     539                 :            : 
     540                 :         46 :         return true;
     541                 :            : }
     542                 :            : 
     543                 :         24 : static void hiomap_event(uint8_t events, void *context)
     544                 :            : {
     545                 :         24 :         struct ipmi_hiomap *ctx = context;
     546                 :            : 
     547                 :         24 :         prlog(PR_DEBUG, "Received events: 0x%x\n", events);
     548                 :            : 
     549                 :         24 :         lock(&ctx->lock);
     550                 :         24 :         ctx->bmc_state = events | (ctx->bmc_state & HIOMAP_E_ACK_MASK);
     551                 :         24 :         unlock(&ctx->lock);
     552                 :         24 : }
     553                 :            : 
     554                 :         13 : static int lpc_window_read(struct ipmi_hiomap *ctx, uint32_t pos,
     555                 :            :                            void *buf, uint32_t len)
     556                 :            : {
     557                 :         13 :         uint32_t off = ctx->current.lpc_addr + (pos - ctx->current.cur_pos);
     558                 :            : 
     559                 :         13 :         if ((ctx->current.lpc_addr + ctx->current.size) < (off + len))
     560                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     561                 :            : 
     562                 :         13 :         return lpc_fw_read(off, buf, len);
     563                 :            : }
     564                 :            : 
     565                 :         15 : static int lpc_window_write(struct ipmi_hiomap *ctx, uint32_t pos,
     566                 :            :                             const void *buf, uint32_t len)
     567                 :            : {
     568                 :         15 :         uint32_t off = ctx->current.lpc_addr + (pos - ctx->current.cur_pos);
     569                 :            :         enum lpc_window_state state;
     570                 :            : 
     571                 :         15 :         lock(&ctx->lock);
     572                 :         15 :         state = ctx->window_state;
     573                 :         15 :         unlock(&ctx->lock);
     574                 :            : 
     575                 :         15 :         if (state != write_window)
     576                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     577                 :            : 
     578                 :         15 :         if ((ctx->current.lpc_addr + ctx->current.size) < (off + len))
     579                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     580                 :            : 
     581                 :         15 :         return lpc_fw_write(off, buf, len);
     582                 :            : }
     583                 :            : 
     584                 :            : /* Best-effort asynchronous event handling by blocklevel callbacks */
     585                 :         54 : static int ipmi_hiomap_handle_events(struct ipmi_hiomap *ctx)
     586                 :            : {
     587                 :            :         uint8_t status;
     588                 :            :         int rc;
     589                 :            : 
     590                 :         54 :         lock(&ctx->lock);
     591                 :            : 
     592                 :         54 :         status = ctx->bmc_state;
     593                 :            : 
     594                 :            :         /*
     595                 :            :          * Immediately clear the ackable events to make sure we don't race to
     596                 :            :          * clear them after dropping the lock, as we may lose protocol or
     597                 :            :          * window state if a race materialises. In the event of a failure where
     598                 :            :          * we haven't completed the recovery, the state we mask out below gets
     599                 :            :          * OR'ed back in to avoid losing it.
     600                 :            :          */
     601                 :         54 :         ctx->bmc_state &= ~HIOMAP_E_ACK_MASK;
     602                 :            : 
     603                 :            :         /*
     604                 :            :          * We won't be attempting to restore window state -
     605                 :            :          * ipmi_hiomap_handle_events() is followed by hiomap_window_move() in
     606                 :            :          * all cases. Attempting restoration after HIOMAP_E_PROTOCOL_RESET or
     607                 :            :          * HIOMAP_E_WINDOW_RESET can be wasteful if we immediately shift the
     608                 :            :          * window elsewhere, and if it does not need to be shifted with respect
     609                 :            :          * to the subsequent request then hiomap_window_move() will handle
     610                 :            :          * re-opening it from the closed state.
     611                 :            :          *
     612                 :            :          * Therefore it is enough to mark the window as closed to consider it
     613                 :            :          * recovered.
     614                 :            :          */
     615                 :         54 :         if (status & (HIOMAP_E_PROTOCOL_RESET | HIOMAP_E_WINDOW_RESET))
     616                 :         10 :                 ctx->window_state = closed_window;
     617                 :            : 
     618                 :         54 :         unlock(&ctx->lock);
     619                 :            : 
     620                 :            :         /*
     621                 :            :          * If there's anything to acknowledge, do so in the one request to
     622                 :            :          * minimise overhead. By sending the ACK prior to performing the
     623                 :            :          * protocol recovery we ensure that even with coalesced resets we still
     624                 :            :          * end up in the recovered state and not unknowingly stuck in a reset
     625                 :            :          * state. We may receive reset events after the ACK but prior to the
     626                 :            :          * recovery procedures being run, but this just means that we will
     627                 :            :          * needlessly perform recovery on the following invocation of
     628                 :            :          * ipmi_hiomap_handle_events(). If the reset event is a
     629                 :            :          * HIOMAP_E_WINDOW_RESET it is enough that the window is already marked
     630                 :            :          * as closed above - future accesses will force it to be re-opened and
     631                 :            :          * the BMC's cache must be valid if opening the window is successful.
     632                 :            :          */
     633                 :         54 :         if (status & HIOMAP_E_ACK_MASK) {
     634                 :            :                 /* ACK is unversioned, can send it if the daemon is ready */
     635                 :         10 :                 rc = hiomap_ack(ctx, status & HIOMAP_E_ACK_MASK);
     636                 :         10 :                 if (rc) {
     637                 :          3 :                         prlog(PR_DEBUG, "Failed to ack events: 0x%x\n",
     638                 :            :                               status & HIOMAP_E_ACK_MASK);
     639                 :          3 :                         goto restore;
     640                 :            :                 }
     641                 :            :         }
     642                 :            : 
     643                 :         51 :         if (status & HIOMAP_E_PROTOCOL_RESET) {
     644                 :          6 :                 prlog(PR_INFO, "Protocol was reset\n");
     645                 :            : 
     646                 :          6 :                 rc = hiomap_get_info(ctx);
     647                 :          6 :                 if (rc) {
     648                 :          1 :                         prerror("Failure to renegotiate after protocol reset\n");
     649                 :          1 :                         goto restore;
     650                 :            :                 }
     651                 :            : 
     652                 :          5 :                 rc = hiomap_get_flash_info(ctx);
     653                 :          5 :                 if (rc) {
     654                 :          1 :                         prerror("Failure to fetch flash info after protocol reset\n");
     655                 :          1 :                         goto restore;
     656                 :            :                 }
     657                 :            : 
     658                 :          4 :                 prlog(PR_INFO, "Restored state after protocol reset\n");
     659                 :            :         }
     660                 :            : 
     661                 :            :         /*
     662                 :            :          * As there's no change to the protocol on HIOMAP_E_WINDOW_RESET we
     663                 :            :          * simply need to open a window to recover, which as mentioned above is
     664                 :            :          * handled by hiomap_window_move() after our cleanup here.
     665                 :            :          */
     666                 :            : 
     667                 :         49 :         return 0;
     668                 :            : 
     669                 :          5 : restore:
     670                 :            :         /*
     671                 :            :          * Conservatively restore the events to the un-acked state to avoid
     672                 :            :          * losing events due to races. It might cause us to restore state more
     673                 :            :          * than necessary, but never less than necessary.
     674                 :            :          */
     675                 :          5 :         lock(&ctx->lock);
     676                 :          5 :         ctx->bmc_state |= (status & HIOMAP_E_ACK_MASK);
     677                 :          5 :         unlock(&ctx->lock);
     678                 :            : 
     679                 :          5 :         return rc;
     680                 :            : }
     681                 :            : 
     682                 :         18 : static int ipmi_hiomap_read(struct blocklevel_device *bl, uint64_t pos,
     683                 :            :                             void *buf, uint64_t len)
     684                 :            : {
     685                 :            :         struct ipmi_hiomap *ctx;
     686                 :            :         uint64_t size;
     687                 :         18 :         int rc = 0;
     688                 :            : 
     689                 :            :         /* LPC is only 32bit */
     690                 :         18 :         if (pos > UINT_MAX || len > UINT_MAX)
     691                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     692                 :            : 
     693                 :         18 :         ctx = container_of(bl, struct ipmi_hiomap, bl);
     694                 :            : 
     695                 :         18 :         rc = ipmi_hiomap_handle_events(ctx);
     696                 :         18 :         if (rc)
     697                 :          2 :                 return rc;
     698                 :            : 
     699                 :         16 :         prlog(PR_TRACE, "Flash read at %#" PRIx64 " for %#" PRIx64 "\n", pos,
     700                 :            :               len);
     701                 :         28 :         while (len > 0) {
     702                 :            :                 /* Move window and get a new size to read */
     703                 :         18 :                 rc = hiomap_window_move(ctx, HIOMAP_C_CREATE_READ_WINDOW, pos,
     704                 :            :                                         len, &size);
     705                 :         18 :                 if (rc)
     706                 :          5 :                         return rc;
     707                 :            : 
     708                 :            :                 /* Perform the read for this window */
     709                 :         13 :                 rc = lpc_window_read(ctx, pos, buf, size);
     710                 :         13 :                 if (rc)
     711                 :          0 :                         return rc;
     712                 :            : 
     713                 :            :                 /* Check we can trust what we read */
     714                 :         13 :                 lock(&ctx->lock);
     715                 :         13 :                 rc = hiomap_window_valid(ctx, pos, size);
     716                 :         13 :                 unlock(&ctx->lock);
     717                 :         13 :                 if (rc)
     718                 :          1 :                         return rc;
     719                 :            : 
     720                 :         12 :                 len -= size;
     721                 :         12 :                 pos += size;
     722                 :         12 :                 buf += size;
     723                 :            :         }
     724                 :         10 :         return rc;
     725                 :            : 
     726                 :            : }
     727                 :            : 
     728                 :         17 : static int ipmi_hiomap_write(struct blocklevel_device *bl, uint64_t pos,
     729                 :            :                              const void *buf, uint64_t len)
     730                 :            : {
     731                 :            :         struct ipmi_hiomap *ctx;
     732                 :            :         uint64_t size;
     733                 :         17 :         int rc = 0;
     734                 :            : 
     735                 :            :         /* LPC is only 32bit */
     736                 :         17 :         if (pos > UINT_MAX || len > UINT_MAX)
     737                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     738                 :            : 
     739                 :         17 :         ctx = container_of(bl, struct ipmi_hiomap, bl);
     740                 :            : 
     741                 :         17 :         rc = ipmi_hiomap_handle_events(ctx);
     742                 :         17 :         if (rc)
     743                 :          0 :                 return rc;
     744                 :            : 
     745                 :         17 :         prlog(PR_TRACE, "Flash write at %#" PRIx64 " for %#" PRIx64 "\n", pos,
     746                 :            :               len);
     747                 :         25 :         while (len > 0) {
     748                 :            :                 /* Move window and get a new size to read */
     749                 :         19 :                 rc = hiomap_window_move(ctx, HIOMAP_C_CREATE_WRITE_WINDOW, pos,
     750                 :            :                                         len, &size);
     751                 :         19 :                 if (rc)
     752                 :          4 :                         return rc;
     753                 :            : 
     754                 :            :                 /* Perform the write for this window */
     755                 :         15 :                 rc = lpc_window_write(ctx, pos, buf, size);
     756                 :         15 :                 if (rc)
     757                 :          0 :                         return rc;
     758                 :            : 
     759                 :            :                 /*
     760                 :            :                  * Unlike ipmi_hiomap_read() we don't explicitly test if the
     761                 :            :                  * window is still valid after completing the LPC accesses as
     762                 :            :                  * the following hiomap_mark_dirty() will implicitly check for
     763                 :            :                  * us. In the case of a read operation there's no requirement
     764                 :            :                  * that a command that validates window state follows, so the
     765                 :            :                  * read implementation explicitly performs a check.
     766                 :            :                  */
     767                 :            : 
     768                 :         15 :                 rc = hiomap_mark_dirty(ctx, pos, size);
     769                 :         15 :                 if (rc)
     770                 :          4 :                         return rc;
     771                 :            : 
     772                 :            :                 /*
     773                 :            :                  * The BMC *should* flush if the window is implicitly closed,
     774                 :            :                  * but do an explicit flush here to be sure.
     775                 :            :                  *
     776                 :            :                  * XXX: Removing this could improve performance
     777                 :            :                  */
     778                 :         11 :                 rc = hiomap_flush(ctx);
     779                 :         11 :                 if (rc)
     780                 :          3 :                         return rc;
     781                 :            : 
     782                 :          8 :                 len -= size;
     783                 :          8 :                 pos += size;
     784                 :          8 :                 buf += size;
     785                 :            :         }
     786                 :          6 :         return rc;
     787                 :            : }
     788                 :            : 
     789                 :         18 : static int ipmi_hiomap_erase(struct blocklevel_device *bl, uint64_t pos,
     790                 :            :                              uint64_t len)
     791                 :            : {
     792                 :            :         struct ipmi_hiomap *ctx;
     793                 :            :         int rc;
     794                 :            : 
     795                 :            :         /* LPC is only 32bit */
     796                 :         18 :         if (pos > UINT_MAX || len > UINT_MAX)
     797                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     798                 :            : 
     799                 :         18 :         ctx = container_of(bl, struct ipmi_hiomap, bl);
     800                 :            : 
     801                 :         18 :         rc = ipmi_hiomap_handle_events(ctx);
     802                 :         18 :         if (rc)
     803                 :          3 :                 return rc;
     804                 :            : 
     805                 :         15 :         prlog(PR_TRACE, "Flash erase at 0x%08x for 0x%08x\n", (u32) pos,
     806                 :            :               (u32) len);
     807                 :         26 :         while (len > 0) {
     808                 :            :                 uint64_t size;
     809                 :            : 
     810                 :            :                 /* Move window and get a new size to erase */
     811                 :         16 :                 rc = hiomap_window_move(ctx, HIOMAP_C_CREATE_WRITE_WINDOW, pos,
     812                 :            :                                         len, &size);
     813                 :         16 :                 if (rc)
     814                 :          5 :                         return rc;
     815                 :            : 
     816                 :         15 :                 rc = hiomap_erase(ctx, pos, size);
     817                 :         15 :                 if (rc)
     818                 :          4 :                         return rc;
     819                 :            : 
     820                 :            :                 /*
     821                 :            :                  * Flush directly, don't mark that region dirty otherwise it
     822                 :            :                  * isn't clear if a write happened there or not
     823                 :            :                  */
     824                 :         11 :                 rc = hiomap_flush(ctx);
     825                 :         11 :                 if (rc)
     826                 :          0 :                         return rc;
     827                 :            : 
     828                 :         11 :                 len -= size;
     829                 :         11 :                 pos += size;
     830                 :            :         }
     831                 :            : 
     832                 :         10 :         return 0;
     833                 :            : }
     834                 :            : 
     835                 :          1 : static int ipmi_hiomap_get_flash_info(struct blocklevel_device *bl,
     836                 :            :                                       const char **name, uint64_t *total_size,
     837                 :            :                                       uint32_t *erase_granule)
     838                 :            : {
     839                 :            :         struct ipmi_hiomap *ctx;
     840                 :            :         int rc;
     841                 :            : 
     842                 :          1 :         ctx = container_of(bl, struct ipmi_hiomap, bl);
     843                 :            : 
     844                 :          1 :         rc = ipmi_hiomap_handle_events(ctx);
     845                 :          1 :         if (rc)
     846                 :          0 :                 return rc;
     847                 :            : 
     848                 :          1 :         rc = hiomap_get_flash_info(ctx);
     849                 :          1 :         if (rc)
     850                 :          0 :                 return rc;
     851                 :            : 
     852                 :          1 :         ctx->bl.erase_mask = ctx->erase_granule - 1;
     853                 :            : 
     854                 :          1 :         if (name)
     855                 :          1 :                 *name = NULL;
     856                 :          1 :         if (total_size)
     857                 :          1 :                 *total_size = ctx->total_size;
     858                 :          1 :         if (erase_granule)
     859                 :          1 :                 *erase_granule = ctx->erase_granule;
     860                 :            : 
     861                 :          1 :         return 0;
     862                 :            : }
     863                 :            : 
     864                 :         57 : int ipmi_hiomap_init(struct blocklevel_device **bl)
     865                 :            : {
     866                 :            :         struct ipmi_hiomap *ctx;
     867                 :            :         int rc;
     868                 :            : 
     869                 :         57 :         if (!bmc_platform->sw->ipmi_oem_hiomap_cmd)
     870                 :            :                 /* FIXME: Find a better error code */
     871                 :          0 :                 return FLASH_ERR_DEVICE_GONE;
     872                 :            : 
     873                 :         57 :         if (!bl)
     874                 :          0 :                 return FLASH_ERR_PARM_ERROR;
     875                 :            : 
     876                 :         57 :         *bl = NULL;
     877                 :            : 
     878                 :         57 :         ctx = zalloc(sizeof(struct ipmi_hiomap));
     879                 :         57 :         if (!ctx)
     880                 :          0 :                 return FLASH_ERR_MALLOC_FAILED;
     881                 :            : 
     882                 :         57 :         init_lock(&ctx->lock);
     883                 :            : 
     884                 :         57 :         ctx->bl.read = &ipmi_hiomap_read;
     885                 :         57 :         ctx->bl.write = &ipmi_hiomap_write;
     886                 :         57 :         ctx->bl.erase = &ipmi_hiomap_erase;
     887                 :         57 :         ctx->bl.get_info = &ipmi_hiomap_get_flash_info;
     888                 :         57 :         ctx->bl.exit = &ipmi_hiomap_exit;
     889                 :            : 
     890                 :         57 :         hiomap_init(ctx);
     891                 :            : 
     892                 :            :         /* Ack all pending ack-able events to avoid spurious failures */
     893                 :         57 :         rc = hiomap_ack(ctx, HIOMAP_E_ACK_MASK);
     894                 :         57 :         if (rc) {
     895                 :          5 :                 prlog(PR_DEBUG, "Failed to ack events: 0x%x\n",
     896                 :            :                       HIOMAP_E_ACK_MASK);
     897                 :          5 :                 goto err;
     898                 :            :         }
     899                 :            : 
     900                 :         52 :         rc = ipmi_sel_register(CMD_OP_HIOMAP_EVENT, hiomap_event, ctx);
     901                 :         52 :         if (rc < 0)
     902                 :          0 :                 goto err;
     903                 :            : 
     904                 :            :         /* Negotiate protocol behaviour */
     905                 :         52 :         rc = hiomap_get_info(ctx);
     906                 :         52 :         if (rc) {
     907                 :          3 :                 prerror("Failed to get hiomap parameters: %d\n", rc);
     908                 :          3 :                 goto err;
     909                 :            :         }
     910                 :            : 
     911                 :            :         /* Grab the flash parameters */
     912                 :         49 :         rc = hiomap_get_flash_info(ctx);
     913                 :         49 :         if (rc) {
     914                 :          3 :                 prerror("Failed to get flash parameters: %d\n", rc);
     915                 :          3 :                 goto err;
     916                 :            :         }
     917                 :            : 
     918                 :         46 :         prlog(PR_NOTICE, "Negotiated hiomap protocol v%u\n", ctx->version);
     919                 :         46 :         prlog(PR_NOTICE, "Block size is %uKiB\n",
     920                 :            :               1 << (ctx->block_size_shift - 10));
     921                 :         46 :         prlog(PR_NOTICE, "BMC suggested flash timeout of %us\n", ctx->timeout);
     922                 :         46 :         prlog(PR_NOTICE, "Flash size is %uMiB\n", ctx->total_size >> 20);
     923                 :         46 :         prlog(PR_NOTICE, "Erase granule size is %uKiB\n",
     924                 :            :               ctx->erase_granule >> 10);
     925                 :            : 
     926                 :         46 :         ctx->bl.keep_alive = 0;
     927                 :            : 
     928                 :         46 :         *bl = &(ctx->bl);
     929                 :            : 
     930                 :         46 :         return 0;
     931                 :            : 
     932                 :         11 : err:
     933                 :         11 :         free(ctx);
     934                 :            : 
     935                 :         11 :         return rc;
     936                 :            : }
     937                 :            : 
     938                 :         46 : bool ipmi_hiomap_exit(struct blocklevel_device *bl)
     939                 :            : {
     940                 :         46 :         bool status = true;
     941                 :            : 
     942                 :            :         struct ipmi_hiomap *ctx;
     943                 :         46 :         if (bl) {
     944                 :         46 :                 ctx = container_of(bl, struct ipmi_hiomap, bl);
     945                 :         46 :                 status = hiomap_reset(ctx);
     946                 :         46 :                 free(ctx);
     947                 :            :         }
     948                 :            : 
     949                 :         46 :         return status;
     950                 :            : }

Generated by: LCOV version 1.14