Loading include/spdk/nvme.h +15 −0 Original line number Diff line number Diff line Loading @@ -478,6 +478,21 @@ int spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid); int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format); /** * \brief Download a new firmware image. * * \param payload The data buffer for the firmware image. * \param size The data size will be downloaded. * \param slot The slot that the firmware image will be committed to. * * \return 0 if successfully submitted, ENOMEM if resources could not be allocated for this request, * -1 if the size is not multiple of 4. * * This function is thread safe and can be called at any point after spdk_nvme_attach(). */ int spdk_nvme_ctrlr_update_firmware(struct spdk_nvme_ctrlr *ctrlr, void *payload, uint32_t size, int slot); /** * \brief Get the identify namespace data as defined by the NVMe specification. * Loading include/spdk/nvme_spec.h +46 −1 Original line number Diff line number Diff line Loading @@ -664,7 +664,10 @@ struct __attribute__((packed)) spdk_nvme_ctrlr_data { /* number of firmware slots */ uint8_t num_slots : 3; uint8_t frmw_rsvd : 4; /* support activation without reset */ uint8_t activation_without_reset : 1; uint8_t frmw_rsvd : 3; } frmw; /** log page attributes */ Loading Loading @@ -1283,6 +1286,48 @@ struct spdk_nvme_protection_info { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_protection_info) == 8, "Incorrect size"); /** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10: commit action */ enum spdk_nvme_fw_commit_action { /** * Downloaded image replaces the image specified by * the Firmware Slot field. This image is not activated. */ SPDK_NVME_FW_COMMIT_REPLACE_IMG = 0x0, /** * Downloaded image replaces the image specified by * the Firmware Slot field. This image is activated at the next reset. */ SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG = 0x1, /** * The image specified by the Firmware Slot field is * activated at the next reset. */ SPDK_NVME_FW_COMMIT_ENABLE_IMG = 0x2, /** * The image specified by the Firmware Slot field is * requested to be activated immediately without reset. */ SPDK_NVME_FW_COMMIT_RUN_IMG = 0x3, }; /** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10 */ struct spdk_nvme_fw_commit { /** * Firmware Slot. Specifies the firmware slot that shall be used for the * Commit Action. The controller shall choose the firmware slot (slot 1 - 7) * to use for the operation if the value specified is 0h. */ uint32_t fs : 3; /** * Commit Action. Specifies the action that is taken on the image downloaded * with the Firmware Image Download command or on a previously downloaded and * placed image. */ uint32_t ca : 3; uint32_t reserved : 26; }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_fw_commit) == 4, "Incorrect size"); #define spdk_nvme_cpl_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) Loading lib/nvme/nvme_ctrlr.c +71 −0 Original line number Diff line number Diff line Loading @@ -1205,3 +1205,74 @@ spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, return spdk_nvme_ctrlr_reset(ctrlr); } int spdk_nvme_ctrlr_update_firmware(struct spdk_nvme_ctrlr *ctrlr, void *payload, uint32_t size, int slot) { struct spdk_nvme_fw_commit fw_commit; struct nvme_completion_poll_status status; int res; unsigned int size_remaining; unsigned int offset; unsigned int transfer; void *p; if (size % 4) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_update_firmware invalid size!\n"); return -1; } /* Firmware download */ size_remaining = size; offset = 0; p = payload; while (size_remaining > 0) { transfer = nvme_min(size_remaining, ctrlr->min_page_size); status.done = false; res = nvme_ctrlr_cmd_fw_image_download(ctrlr, transfer, offset, p, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_fw_image_download failed!\n"); return ENXIO; } p += transfer; offset += transfer; size_remaining -= transfer; } /* Firmware commit */ memset(&fw_commit, 0, sizeof(struct spdk_nvme_fw_commit)); fw_commit.fs = slot; fw_commit.ca = SPDK_NVME_FW_COMMIT_REPLACE_IMG; status.done = false; res = nvme_ctrlr_cmd_fw_commit(ctrlr, &fw_commit, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "nvme_ctrlr_cmd_fw_commit failed!\n"); return ENXIO; } return spdk_nvme_ctrlr_reset(ctrlr); } lib/nvme/nvme_ctrlr_cmd.c +55 −0 Original line number Diff line number Diff line Loading @@ -480,3 +480,58 @@ nvme_ctrlr_cmd_abort(struct spdk_nvme_ctrlr *ctrlr, uint16_t cid, return nvme_ctrlr_submit_admin_request(ctrlr, req); } int nvme_ctrlr_cmd_fw_commit(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_fw_commit *fw_commit, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; int rc; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_null(cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FIRMWARE_COMMIT; memcpy(&cmd->cdw10, fw_commit, sizeof(uint32_t)); rc = nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return rc; } int nvme_ctrlr_cmd_fw_image_download(struct spdk_nvme_ctrlr *ctrlr, uint32_t size, uint32_t offset, void *payload, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; int rc; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_contig(payload, size, cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; cmd->cdw10 = (size >> 2) - 1; cmd->cdw11 = offset >> 2; rc = nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return rc; } lib/nvme/nvme_internal.h +6 −0 Original line number Diff line number Diff line Loading @@ -523,6 +523,12 @@ int nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_ void *cb_arg); int nvme_ctrlr_cmd_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format, spdk_nvme_cmd_cb cb_fn, void *cb_arg); int nvme_ctrlr_cmd_fw_commit(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_fw_commit *fw_commit, spdk_nvme_cmd_cb cb_fn, void *cb_arg); int nvme_ctrlr_cmd_fw_image_download(struct spdk_nvme_ctrlr *ctrlr, uint32_t size, uint32_t offset, void *payload, spdk_nvme_cmd_cb cb_fn, void *cb_arg); void nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl); int nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr, void *devhandle); Loading Loading
include/spdk/nvme.h +15 −0 Original line number Diff line number Diff line Loading @@ -478,6 +478,21 @@ int spdk_nvme_ctrlr_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid); int spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format); /** * \brief Download a new firmware image. * * \param payload The data buffer for the firmware image. * \param size The data size will be downloaded. * \param slot The slot that the firmware image will be committed to. * * \return 0 if successfully submitted, ENOMEM if resources could not be allocated for this request, * -1 if the size is not multiple of 4. * * This function is thread safe and can be called at any point after spdk_nvme_attach(). */ int spdk_nvme_ctrlr_update_firmware(struct spdk_nvme_ctrlr *ctrlr, void *payload, uint32_t size, int slot); /** * \brief Get the identify namespace data as defined by the NVMe specification. * Loading
include/spdk/nvme_spec.h +46 −1 Original line number Diff line number Diff line Loading @@ -664,7 +664,10 @@ struct __attribute__((packed)) spdk_nvme_ctrlr_data { /* number of firmware slots */ uint8_t num_slots : 3; uint8_t frmw_rsvd : 4; /* support activation without reset */ uint8_t activation_without_reset : 1; uint8_t frmw_rsvd : 3; } frmw; /** log page attributes */ Loading Loading @@ -1283,6 +1286,48 @@ struct spdk_nvme_protection_info { }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_protection_info) == 8, "Incorrect size"); /** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10: commit action */ enum spdk_nvme_fw_commit_action { /** * Downloaded image replaces the image specified by * the Firmware Slot field. This image is not activated. */ SPDK_NVME_FW_COMMIT_REPLACE_IMG = 0x0, /** * Downloaded image replaces the image specified by * the Firmware Slot field. This image is activated at the next reset. */ SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG = 0x1, /** * The image specified by the Firmware Slot field is * activated at the next reset. */ SPDK_NVME_FW_COMMIT_ENABLE_IMG = 0x2, /** * The image specified by the Firmware Slot field is * requested to be activated immediately without reset. */ SPDK_NVME_FW_COMMIT_RUN_IMG = 0x3, }; /** Parameters for SPDK_NVME_OPC_FIRMWARE_COMMIT cdw10 */ struct spdk_nvme_fw_commit { /** * Firmware Slot. Specifies the firmware slot that shall be used for the * Commit Action. The controller shall choose the firmware slot (slot 1 - 7) * to use for the operation if the value specified is 0h. */ uint32_t fs : 3; /** * Commit Action. Specifies the action that is taken on the image downloaded * with the Firmware Image Download command or on a previously downloaded and * placed image. */ uint32_t ca : 3; uint32_t reserved : 26; }; SPDK_STATIC_ASSERT(sizeof(struct spdk_nvme_fw_commit) == 4, "Incorrect size"); #define spdk_nvme_cpl_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) Loading
lib/nvme/nvme_ctrlr.c +71 −0 Original line number Diff line number Diff line Loading @@ -1205,3 +1205,74 @@ spdk_nvme_ctrlr_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, return spdk_nvme_ctrlr_reset(ctrlr); } int spdk_nvme_ctrlr_update_firmware(struct spdk_nvme_ctrlr *ctrlr, void *payload, uint32_t size, int slot) { struct spdk_nvme_fw_commit fw_commit; struct nvme_completion_poll_status status; int res; unsigned int size_remaining; unsigned int offset; unsigned int transfer; void *p; if (size % 4) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_update_firmware invalid size!\n"); return -1; } /* Firmware download */ size_remaining = size; offset = 0; p = payload; while (size_remaining > 0) { transfer = nvme_min(size_remaining, ctrlr->min_page_size); status.done = false; res = nvme_ctrlr_cmd_fw_image_download(ctrlr, transfer, offset, p, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "spdk_nvme_ctrlr_fw_image_download failed!\n"); return ENXIO; } p += transfer; offset += transfer; size_remaining -= transfer; } /* Firmware commit */ memset(&fw_commit, 0, sizeof(struct spdk_nvme_fw_commit)); fw_commit.fs = slot; fw_commit.ca = SPDK_NVME_FW_COMMIT_REPLACE_IMG; status.done = false; res = nvme_ctrlr_cmd_fw_commit(ctrlr, &fw_commit, nvme_completion_poll_cb, &status); if (res) return res; while (status.done == false) { nvme_mutex_lock(&ctrlr->ctrlr_lock); spdk_nvme_qpair_process_completions(&ctrlr->adminq, 0); nvme_mutex_unlock(&ctrlr->ctrlr_lock); } if (spdk_nvme_cpl_is_error(&status.cpl)) { nvme_printf(ctrlr, "nvme_ctrlr_cmd_fw_commit failed!\n"); return ENXIO; } return spdk_nvme_ctrlr_reset(ctrlr); }
lib/nvme/nvme_ctrlr_cmd.c +55 −0 Original line number Diff line number Diff line Loading @@ -480,3 +480,58 @@ nvme_ctrlr_cmd_abort(struct spdk_nvme_ctrlr *ctrlr, uint16_t cid, return nvme_ctrlr_submit_admin_request(ctrlr, req); } int nvme_ctrlr_cmd_fw_commit(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_fw_commit *fw_commit, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; int rc; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_null(cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FIRMWARE_COMMIT; memcpy(&cmd->cdw10, fw_commit, sizeof(uint32_t)); rc = nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return rc; } int nvme_ctrlr_cmd_fw_image_download(struct spdk_nvme_ctrlr *ctrlr, uint32_t size, uint32_t offset, void *payload, spdk_nvme_cmd_cb cb_fn, void *cb_arg) { struct nvme_request *req; struct spdk_nvme_cmd *cmd; int rc; nvme_mutex_lock(&ctrlr->ctrlr_lock); req = nvme_allocate_request_contig(payload, size, cb_fn, cb_arg); if (req == NULL) { nvme_mutex_unlock(&ctrlr->ctrlr_lock); return ENOMEM; } cmd = &req->cmd; cmd->opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD; cmd->cdw10 = (size >> 2) - 1; cmd->cdw11 = offset >> 2; rc = nvme_ctrlr_submit_admin_request(ctrlr, req); nvme_mutex_unlock(&ctrlr->ctrlr_lock); return rc; }
lib/nvme/nvme_internal.h +6 −0 Original line number Diff line number Diff line Loading @@ -523,6 +523,12 @@ int nvme_ctrlr_cmd_delete_ns(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, spdk_ void *cb_arg); int nvme_ctrlr_cmd_format(struct spdk_nvme_ctrlr *ctrlr, uint32_t nsid, struct spdk_nvme_format *format, spdk_nvme_cmd_cb cb_fn, void *cb_arg); int nvme_ctrlr_cmd_fw_commit(struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_fw_commit *fw_commit, spdk_nvme_cmd_cb cb_fn, void *cb_arg); int nvme_ctrlr_cmd_fw_image_download(struct spdk_nvme_ctrlr *ctrlr, uint32_t size, uint32_t offset, void *payload, spdk_nvme_cmd_cb cb_fn, void *cb_arg); void nvme_completion_poll_cb(void *arg, const struct spdk_nvme_cpl *cpl); int nvme_ctrlr_construct(struct spdk_nvme_ctrlr *ctrlr, void *devhandle); Loading