xref: /spdk/module/bdev/nvme/bdev_nvme_rpc.c (revision 7392cdeff7d8d8d30ec1d8f24a3eebe6f762cde4)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (c) Intel Corporation.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #include "spdk/stdinc.h"
35 
36 #include "bdev_nvme.h"
37 #include "common.h"
38 
39 #include "spdk/string.h"
40 #include "spdk/rpc.h"
41 #include "spdk/util.h"
42 
43 #include "spdk_internal/log.h"
44 #include "spdk/bdev_module.h"
45 
46 struct open_descriptors {
47 	void *desc;
48 	struct  spdk_bdev *bdev;
49 	TAILQ_ENTRY(open_descriptors) tqlst;
50 };
51 typedef TAILQ_HEAD(, open_descriptors) open_descriptors_t;
52 
53 static int
54 rpc_decode_action_on_timeout(const struct spdk_json_val *val, void *out)
55 {
56 	enum spdk_bdev_timeout_action *action = out;
57 
58 	if (spdk_json_strequal(val, "none") == true) {
59 		*action = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE;
60 	} else if (spdk_json_strequal(val, "abort") == true) {
61 		*action = SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT;
62 	} else if (spdk_json_strequal(val, "reset") == true) {
63 		*action = SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET;
64 	} else {
65 		SPDK_NOTICELOG("Invalid parameter value: action_on_timeout\n");
66 		return -EINVAL;
67 	}
68 
69 	return 0;
70 }
71 
72 static const struct spdk_json_object_decoder rpc_bdev_nvme_options_decoders[] = {
73 	{"action_on_timeout", offsetof(struct spdk_bdev_nvme_opts, action_on_timeout), rpc_decode_action_on_timeout, true},
74 	{"timeout_us", offsetof(struct spdk_bdev_nvme_opts, timeout_us), spdk_json_decode_uint64, true},
75 	{"retry_count", offsetof(struct spdk_bdev_nvme_opts, retry_count), spdk_json_decode_uint32, true},
76 	{"nvme_adminq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_adminq_poll_period_us), spdk_json_decode_uint64, true},
77 	{"nvme_ioq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_ioq_poll_period_us), spdk_json_decode_uint64, true},
78 	{"io_queue_requests", offsetof(struct spdk_bdev_nvme_opts, io_queue_requests), spdk_json_decode_uint32, true},
79 };
80 
81 static void
82 spdk_rpc_set_bdev_nvme_options(struct spdk_jsonrpc_request *request,
83 			       const struct spdk_json_val *params)
84 {
85 	struct spdk_bdev_nvme_opts opts;
86 	struct spdk_json_write_ctx *w;
87 	int rc;
88 
89 	spdk_bdev_nvme_get_opts(&opts);
90 	if (params && spdk_json_decode_object(params, rpc_bdev_nvme_options_decoders,
91 					      SPDK_COUNTOF(rpc_bdev_nvme_options_decoders),
92 					      &opts)) {
93 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
94 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
95 						 "spdk_json_decode_object failed");
96 		return;
97 	}
98 
99 	rc = spdk_bdev_nvme_set_opts(&opts);
100 	if (rc) {
101 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
102 		return;
103 	}
104 
105 	w = spdk_jsonrpc_begin_result(request);
106 	spdk_json_write_bool(w, true);
107 	spdk_jsonrpc_end_result(request, w);
108 
109 	return;
110 }
111 SPDK_RPC_REGISTER("set_bdev_nvme_options", spdk_rpc_set_bdev_nvme_options, SPDK_RPC_STARTUP)
112 
113 struct rpc_bdev_nvme_hotplug {
114 	bool enabled;
115 	uint64_t period_us;
116 };
117 
118 static const struct spdk_json_object_decoder rpc_bdev_nvme_hotplug_decoders[] = {
119 	{"enable", offsetof(struct rpc_bdev_nvme_hotplug, enabled), spdk_json_decode_bool, false},
120 	{"period_us", offsetof(struct rpc_bdev_nvme_hotplug, period_us), spdk_json_decode_uint64, true},
121 };
122 
123 static void
124 rpc_set_bdev_nvme_hotplug_done(void *ctx)
125 {
126 	struct spdk_jsonrpc_request *request = ctx;
127 	struct spdk_json_write_ctx *w = spdk_jsonrpc_begin_result(request);
128 
129 	spdk_json_write_bool(w, true);
130 	spdk_jsonrpc_end_result(request, w);
131 }
132 
133 static void
134 spdk_rpc_set_bdev_nvme_hotplug(struct spdk_jsonrpc_request *request,
135 			       const struct spdk_json_val *params)
136 {
137 	struct rpc_bdev_nvme_hotplug req = {false, 0};
138 	int rc;
139 
140 	if (spdk_json_decode_object(params, rpc_bdev_nvme_hotplug_decoders,
141 				    SPDK_COUNTOF(rpc_bdev_nvme_hotplug_decoders), &req)) {
142 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
143 		rc = -EINVAL;
144 		goto invalid;
145 	}
146 
147 	rc = spdk_bdev_nvme_set_hotplug(req.enabled, req.period_us, rpc_set_bdev_nvme_hotplug_done,
148 					request);
149 	if (rc) {
150 		goto invalid;
151 	}
152 
153 	return;
154 invalid:
155 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
156 }
157 SPDK_RPC_REGISTER("set_bdev_nvme_hotplug", spdk_rpc_set_bdev_nvme_hotplug, SPDK_RPC_RUNTIME)
158 
159 struct rpc_construct_nvme {
160 	char *name;
161 	char *trtype;
162 	char *adrfam;
163 	char *traddr;
164 	char *trsvcid;
165 	char *subnqn;
166 	char *hostnqn;
167 	char *hostaddr;
168 	char *hostsvcid;
169 	bool prchk_reftag;
170 	bool prchk_guard;
171 };
172 
173 static void
174 free_rpc_construct_nvme(struct rpc_construct_nvme *req)
175 {
176 	free(req->name);
177 	free(req->trtype);
178 	free(req->adrfam);
179 	free(req->traddr);
180 	free(req->trsvcid);
181 	free(req->subnqn);
182 	free(req->hostnqn);
183 	free(req->hostaddr);
184 	free(req->hostsvcid);
185 }
186 
187 static const struct spdk_json_object_decoder rpc_construct_nvme_decoders[] = {
188 	{"name", offsetof(struct rpc_construct_nvme, name), spdk_json_decode_string},
189 	{"trtype", offsetof(struct rpc_construct_nvme, trtype), spdk_json_decode_string},
190 	{"traddr", offsetof(struct rpc_construct_nvme, traddr), spdk_json_decode_string},
191 
192 	{"adrfam", offsetof(struct rpc_construct_nvme, adrfam), spdk_json_decode_string, true},
193 	{"trsvcid", offsetof(struct rpc_construct_nvme, trsvcid), spdk_json_decode_string, true},
194 	{"subnqn", offsetof(struct rpc_construct_nvme, subnqn), spdk_json_decode_string, true},
195 	{"hostnqn", offsetof(struct rpc_construct_nvme, hostnqn), spdk_json_decode_string, true},
196 	{"hostaddr", offsetof(struct rpc_construct_nvme, hostaddr), spdk_json_decode_string, true},
197 	{"hostsvcid", offsetof(struct rpc_construct_nvme, hostsvcid), spdk_json_decode_string, true},
198 
199 	{"prchk_reftag", offsetof(struct rpc_construct_nvme, prchk_reftag), spdk_json_decode_bool, true},
200 	{"prchk_guard", offsetof(struct rpc_construct_nvme, prchk_guard), spdk_json_decode_bool, true}
201 };
202 
203 #define NVME_MAX_BDEVS_PER_RPC 128
204 
205 struct rpc_create_nvme_bdev_ctx {
206 	struct rpc_construct_nvme req;
207 	size_t count;
208 	const char *names[NVME_MAX_BDEVS_PER_RPC];
209 	struct spdk_jsonrpc_request *request;
210 };
211 
212 static void
213 spdk_rpc_construct_nvme_bdev_done(void *cb_ctx, int rc)
214 {
215 	struct rpc_create_nvme_bdev_ctx *ctx = cb_ctx;
216 	struct spdk_jsonrpc_request *request = ctx->request;
217 	struct spdk_json_write_ctx *w;
218 	size_t i;
219 
220 	if (rc < 0) {
221 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
222 		goto exit;
223 	}
224 
225 	w = spdk_jsonrpc_begin_result(request);
226 	spdk_json_write_array_begin(w);
227 	for (i = 0; i < ctx->count; i++) {
228 		spdk_json_write_string(w, ctx->names[i]);
229 	}
230 	spdk_json_write_array_end(w);
231 	spdk_jsonrpc_end_result(request, w);
232 
233 exit:
234 	free_rpc_construct_nvme(&ctx->req);
235 	free(ctx);
236 }
237 
238 static void
239 spdk_rpc_construct_nvme_bdev(struct spdk_jsonrpc_request *request,
240 			     const struct spdk_json_val *params)
241 {
242 	struct rpc_create_nvme_bdev_ctx *ctx;
243 	struct spdk_nvme_transport_id trid = {};
244 	struct spdk_nvme_host_id hostid = {};
245 	uint32_t prchk_flags = 0;
246 	int rc;
247 
248 	ctx = calloc(1, sizeof(*ctx));
249 	if (!ctx) {
250 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
251 		return;
252 	}
253 
254 	if (spdk_json_decode_object(params, rpc_construct_nvme_decoders,
255 				    SPDK_COUNTOF(rpc_construct_nvme_decoders),
256 				    &ctx->req)) {
257 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
258 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
259 						 "spdk_json_decode_object failed");
260 		goto cleanup;
261 	}
262 
263 	/* Parse trtype */
264 	rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype);
265 	if (rc < 0) {
266 		SPDK_ERRLOG("Failed to parse trtype: %s\n", ctx->req.trtype);
267 		spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s",
268 						     ctx->req.trtype);
269 		goto cleanup;
270 	}
271 
272 	/* Parse traddr */
273 	snprintf(trid.traddr, sizeof(trid.traddr), "%s", ctx->req.traddr);
274 
275 	/* Parse adrfam */
276 	if (ctx->req.adrfam) {
277 		rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam);
278 		if (rc < 0) {
279 			SPDK_ERRLOG("Failed to parse adrfam: %s\n", ctx->req.adrfam);
280 			spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s",
281 							     ctx->req.adrfam);
282 			goto cleanup;
283 		}
284 	}
285 
286 	/* Parse trsvcid */
287 	if (ctx->req.trsvcid) {
288 		snprintf(trid.trsvcid, sizeof(trid.trsvcid), "%s", ctx->req.trsvcid);
289 	}
290 
291 	/* Parse subnqn */
292 	if (ctx->req.subnqn) {
293 		snprintf(trid.subnqn, sizeof(trid.subnqn), "%s", ctx->req.subnqn);
294 	}
295 
296 	if (ctx->req.hostaddr) {
297 		snprintf(hostid.hostaddr, sizeof(hostid.hostaddr), "%s", ctx->req.hostaddr);
298 	}
299 
300 	if (ctx->req.hostsvcid) {
301 		snprintf(hostid.hostsvcid, sizeof(hostid.hostsvcid), "%s", ctx->req.hostsvcid);
302 	}
303 
304 	if (ctx->req.prchk_reftag) {
305 		prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
306 	}
307 
308 	if (ctx->req.prchk_guard) {
309 		prchk_flags |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
310 	}
311 
312 	ctx->request = request;
313 	ctx->count = NVME_MAX_BDEVS_PER_RPC;
314 	rc = spdk_bdev_nvme_create(&trid, &hostid, ctx->req.name, ctx->names, &ctx->count, ctx->req.hostnqn,
315 				   prchk_flags, spdk_rpc_construct_nvme_bdev_done, ctx);
316 	if (rc) {
317 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
318 		goto cleanup;
319 	}
320 
321 	return;
322 
323 cleanup:
324 	free_rpc_construct_nvme(&ctx->req);
325 	free(ctx);
326 }
327 SPDK_RPC_REGISTER("construct_nvme_bdev", spdk_rpc_construct_nvme_bdev, SPDK_RPC_RUNTIME)
328 
329 static void
330 spdk_rpc_dump_nvme_controller_info(struct spdk_json_write_ctx *w,
331 				   struct nvme_bdev_ctrlr *nvme_bdev_ctrlr)
332 {
333 	struct spdk_nvme_transport_id	*trid;
334 
335 	trid = &nvme_bdev_ctrlr->trid;
336 
337 	spdk_json_write_object_begin(w);
338 	spdk_json_write_named_string(w, "name", nvme_bdev_ctrlr->name);
339 
340 	spdk_json_write_named_object_begin(w, "trid");
341 	nvme_bdev_dump_trid_json(trid, w);
342 	spdk_json_write_object_end(w);
343 
344 	spdk_json_write_object_end(w);
345 }
346 
347 struct rpc_get_nvme_controllers {
348 	char *name;
349 };
350 
351 static void
352 free_rpc_get_nvme_controllers(struct rpc_get_nvme_controllers *r)
353 {
354 	free(r->name);
355 }
356 
357 static const struct spdk_json_object_decoder rpc_get_nvme_controllers_decoders[] = {
358 	{"name", offsetof(struct rpc_get_nvme_controllers, name), spdk_json_decode_string, true},
359 };
360 
361 static void
362 spdk_rpc_get_nvme_controllers(struct spdk_jsonrpc_request *request,
363 			      const struct spdk_json_val *params)
364 {
365 	struct rpc_get_nvme_controllers req = {};
366 	struct spdk_json_write_ctx *w;
367 	struct nvme_bdev_ctrlr *ctrlr = NULL;
368 
369 	if (params && spdk_json_decode_object(params, rpc_get_nvme_controllers_decoders,
370 					      SPDK_COUNTOF(rpc_get_nvme_controllers_decoders),
371 					      &req)) {
372 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
373 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
374 						 "spdk_json_decode_object failed");
375 		goto cleanup;
376 	}
377 
378 	if (req.name) {
379 		ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
380 		if (ctrlr == NULL) {
381 			SPDK_ERRLOG("ctrlr '%s' does not exist\n", req.name);
382 			spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Controller %s does not exist", req.name);
383 			goto cleanup;
384 		}
385 	}
386 
387 	w = spdk_jsonrpc_begin_result(request);
388 	spdk_json_write_array_begin(w);
389 
390 	if (ctrlr != NULL) {
391 		spdk_rpc_dump_nvme_controller_info(w, ctrlr);
392 	} else {
393 		for (ctrlr = nvme_bdev_first_ctrlr(); ctrlr; ctrlr = nvme_bdev_next_ctrlr(ctrlr))  {
394 			spdk_rpc_dump_nvme_controller_info(w, ctrlr);
395 		}
396 	}
397 
398 	spdk_json_write_array_end(w);
399 
400 	spdk_jsonrpc_end_result(request, w);
401 
402 cleanup:
403 	free_rpc_get_nvme_controllers(&req);
404 }
405 SPDK_RPC_REGISTER("get_nvme_controllers", spdk_rpc_get_nvme_controllers, SPDK_RPC_RUNTIME)
406 
407 struct rpc_delete_nvme {
408 	char *name;
409 };
410 
411 static void
412 free_rpc_delete_nvme(struct rpc_delete_nvme *req)
413 {
414 	free(req->name);
415 }
416 
417 static const struct spdk_json_object_decoder rpc_delete_nvme_decoders[] = {
418 	{"name", offsetof(struct rpc_delete_nvme, name), spdk_json_decode_string},
419 };
420 
421 static void
422 spdk_rpc_delete_nvme_controller(struct spdk_jsonrpc_request *request,
423 				const struct spdk_json_val *params)
424 {
425 	struct rpc_delete_nvme req = {NULL};
426 	struct spdk_json_write_ctx *w;
427 	int rc = 0;
428 
429 	if (spdk_json_decode_object(params, rpc_delete_nvme_decoders,
430 				    SPDK_COUNTOF(rpc_delete_nvme_decoders),
431 				    &req)) {
432 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
433 						 "spdk_json_decode_object failed");
434 		goto cleanup;
435 	}
436 
437 	rc = spdk_bdev_nvme_delete(req.name);
438 	if (rc != 0) {
439 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
440 		goto cleanup;
441 	}
442 
443 	w = spdk_jsonrpc_begin_result(request);
444 	spdk_json_write_bool(w, true);
445 	spdk_jsonrpc_end_result(request, w);
446 
447 cleanup:
448 	free_rpc_delete_nvme(&req);
449 }
450 SPDK_RPC_REGISTER("delete_nvme_controller", spdk_rpc_delete_nvme_controller, SPDK_RPC_RUNTIME)
451 
452 struct rpc_apply_firmware {
453 	char *filename;
454 	char *bdev_name;
455 };
456 
457 static void
458 free_rpc_apply_firmware(struct rpc_apply_firmware *req)
459 {
460 	free(req->filename);
461 	free(req->bdev_name);
462 }
463 
464 static const struct spdk_json_object_decoder rpc_apply_firmware_decoders[] = {
465 	{"filename", offsetof(struct rpc_apply_firmware, filename), spdk_json_decode_string},
466 	{"bdev_name", offsetof(struct rpc_apply_firmware, bdev_name), spdk_json_decode_string},
467 };
468 
469 struct firmware_update_info {
470 	void				*fw_image;
471 	void				*p;
472 	unsigned int			size;
473 	unsigned int			size_remaining;
474 	unsigned int			offset;
475 	unsigned int			transfer;
476 
477 	void				*desc;
478 	struct spdk_io_channel		*ch;
479 	struct spdk_jsonrpc_request	*request;
480 	struct spdk_nvme_ctrlr		*ctrlr;
481 	open_descriptors_t		desc_head;
482 	struct rpc_apply_firmware	*req;
483 };
484 
485 static void
486 apply_firmware_cleanup(void *cb_arg)
487 {
488 	struct open_descriptors			*opt, *tmp;
489 	struct firmware_update_info *firm_ctx = cb_arg;
490 
491 	if (!firm_ctx) {
492 		return;
493 	}
494 
495 	if (firm_ctx->fw_image) {
496 		spdk_free(firm_ctx->fw_image);
497 	}
498 
499 	if (firm_ctx->req) {
500 		free_rpc_apply_firmware(firm_ctx->req);
501 		free(firm_ctx->req);
502 	}
503 	TAILQ_FOREACH_SAFE(opt, &firm_ctx->desc_head, tqlst, tmp) {
504 		TAILQ_REMOVE(&firm_ctx->desc_head, opt, tqlst);
505 		spdk_bdev_close(opt->desc);
506 		free(opt);
507 	}
508 	free(firm_ctx);
509 }
510 
511 static void
512 apply_firmware_complete_reset(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
513 {
514 	int					rc;
515 	struct spdk_json_write_ctx		*w;
516 	struct firmware_update_info *firm_ctx = cb_arg;
517 
518 	spdk_bdev_free_io(bdev_io);
519 
520 	if (!success) {
521 		spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
522 						 "firmware commit failed.");
523 		apply_firmware_cleanup(firm_ctx);
524 		return;
525 	}
526 
527 	if ((rc = spdk_nvme_ctrlr_reset(firm_ctx->ctrlr)) != 0) {
528 		spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
529 						 "Controller reset failed.");
530 		apply_firmware_cleanup(firm_ctx);
531 		return;
532 	}
533 
534 	w = spdk_jsonrpc_begin_result(firm_ctx->request);
535 	spdk_json_write_string(w, "firmware commit succeeded. Controller reset in progress.");
536 	spdk_jsonrpc_end_result(firm_ctx->request, w);
537 	apply_firmware_cleanup(firm_ctx);
538 }
539 
540 static void
541 apply_firmware_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
542 {
543 	struct spdk_nvme_cmd			cmd = {};
544 	struct spdk_nvme_fw_commit		fw_commit;
545 	int					slot = 0;
546 	int					rc;
547 	struct firmware_update_info *firm_ctx = cb_arg;
548 	enum spdk_nvme_fw_commit_action commit_action = SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG;
549 
550 	if (!success) {
551 		spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
552 						 "firmware download failed .");
553 		spdk_bdev_free_io(bdev_io);
554 		apply_firmware_cleanup(firm_ctx);
555 		return;
556 	}
557 
558 	firm_ctx->p += firm_ctx->transfer;
559 	firm_ctx->offset += firm_ctx->transfer;
560 	firm_ctx->size_remaining -= firm_ctx->transfer;
561 
562 	switch (firm_ctx->size_remaining) {
563 	case 0:
564 		/* firmware download completed. Commit firmware */
565 		memset(&fw_commit, 0, sizeof(struct spdk_nvme_fw_commit));
566 		fw_commit.fs = slot;
567 		fw_commit.ca = commit_action;
568 
569 		cmd.opc = SPDK_NVME_OPC_FIRMWARE_COMMIT;
570 		memcpy(&cmd.cdw10, &fw_commit, sizeof(uint32_t));
571 		rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, NULL, 0,
572 						   apply_firmware_complete_reset, firm_ctx);
573 		if (rc) {
574 			spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
575 							 "firmware commit failed.");
576 			spdk_bdev_free_io(bdev_io);
577 			apply_firmware_cleanup(firm_ctx);
578 			return;
579 		}
580 		break;
581 	default:
582 		firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096);
583 		cmd.opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
584 
585 		cmd.cdw10 = (firm_ctx->transfer >> 2) - 1;
586 		cmd.cdw11 = firm_ctx->offset >> 2;
587 		rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, firm_ctx->p,
588 						   firm_ctx->transfer, apply_firmware_complete, firm_ctx);
589 		if (rc) {
590 			spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
591 							 "firmware download failed.");
592 			spdk_bdev_free_io(bdev_io);
593 			apply_firmware_cleanup(firm_ctx);
594 			return;
595 		}
596 		break;
597 	}
598 }
599 
600 static void
601 spdk_rpc_apply_nvme_firmware(struct spdk_jsonrpc_request *request,
602 			     const struct spdk_json_val *params)
603 {
604 	int					rc;
605 	int					fd = -1;
606 	struct stat				fw_stat;
607 	struct spdk_nvme_ctrlr			*ctrlr;
608 	char					msg[1024];
609 	struct spdk_bdev			*bdev;
610 	struct spdk_bdev			*bdev2;
611 	struct open_descriptors			*opt;
612 	struct spdk_bdev_desc			*desc;
613 	struct spdk_nvme_cmd			*cmd;
614 	struct firmware_update_info		*firm_ctx;
615 
616 	firm_ctx = malloc(sizeof(struct firmware_update_info));
617 	if (!firm_ctx) {
618 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
619 						 "Memory allocation error.");
620 		return;
621 	}
622 	firm_ctx->fw_image = NULL;
623 	TAILQ_INIT(&firm_ctx->desc_head);
624 	firm_ctx->request = request;
625 
626 	firm_ctx->req = malloc(sizeof(struct rpc_apply_firmware));
627 	if (!firm_ctx->req) {
628 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
629 						 "Memory allocation error.");
630 		free(firm_ctx);
631 		return;
632 	}
633 
634 	if (spdk_json_decode_object(params, rpc_apply_firmware_decoders,
635 				    SPDK_COUNTOF(rpc_apply_firmware_decoders), firm_ctx->req)) {
636 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
637 						 "spdk_json_decode_object failed.");
638 		free(firm_ctx->req);
639 		free(firm_ctx);
640 		return;
641 	}
642 
643 	if ((bdev = spdk_bdev_get_by_name(firm_ctx->req->bdev_name)) == NULL) {
644 		snprintf(msg, sizeof(msg), "bdev %s were not found", firm_ctx->req->bdev_name);
645 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
646 		apply_firmware_cleanup(firm_ctx);
647 		return;
648 	}
649 
650 	if ((ctrlr = spdk_bdev_nvme_get_ctrlr(bdev)) == NULL) {
651 		snprintf(msg, sizeof(msg), "Controller information for %s were not found.",
652 			 firm_ctx->req->bdev_name);
653 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
654 		apply_firmware_cleanup(firm_ctx);
655 		return;
656 	}
657 	firm_ctx->ctrlr = ctrlr;
658 
659 	for (bdev2 = spdk_bdev_first(); bdev2; bdev2 = spdk_bdev_next(bdev2)) {
660 
661 		if (spdk_bdev_nvme_get_ctrlr(bdev2) != ctrlr) {
662 			continue;
663 		}
664 
665 		if (!(opt = malloc(sizeof(struct open_descriptors)))) {
666 			snprintf(msg, sizeof(msg), "Memory allocation error.");
667 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
668 			apply_firmware_cleanup(firm_ctx);
669 			return;
670 		}
671 
672 		if ((rc = spdk_bdev_open(bdev2, true, NULL, NULL, &desc)) != 0) {
673 			snprintf(msg, sizeof(msg), "Device %s is in use.", firm_ctx->req->bdev_name);
674 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, msg);
675 			free(opt);
676 			apply_firmware_cleanup(firm_ctx);
677 			return;
678 		}
679 
680 		opt->desc = desc;
681 		opt->bdev = bdev;
682 		TAILQ_INSERT_TAIL(&firm_ctx->desc_head, opt, tqlst);
683 	}
684 
685 	/*
686 	 * find a descriptor associated with our bdev
687 	 */
688 	firm_ctx->desc = NULL;
689 	TAILQ_FOREACH(opt, &firm_ctx->desc_head, tqlst) {
690 		if (opt->bdev == bdev) {
691 			firm_ctx->desc = opt->desc;
692 			break;
693 		}
694 	}
695 
696 	if (!firm_ctx->desc) {
697 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
698 						 "No descriptor were found.");
699 		apply_firmware_cleanup(firm_ctx);
700 		return;
701 	}
702 
703 	firm_ctx->ch = spdk_bdev_get_io_channel(firm_ctx->desc);
704 	if (!firm_ctx->ch) {
705 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
706 						 "No channels were found.");
707 		apply_firmware_cleanup(firm_ctx);
708 		return;
709 	}
710 
711 	fd = open(firm_ctx->req->filename, O_RDONLY);
712 	if (fd < 0) {
713 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "open file failed.");
714 		apply_firmware_cleanup(firm_ctx);
715 		return;
716 	}
717 
718 	rc = fstat(fd, &fw_stat);
719 	if (rc < 0) {
720 		close(fd);
721 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "fstat failed.");
722 		apply_firmware_cleanup(firm_ctx);
723 		return;
724 	}
725 
726 	firm_ctx->size = fw_stat.st_size;
727 	if (fw_stat.st_size % 4) {
728 		close(fd);
729 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
730 						 "Firmware image size is not multiple of 4.");
731 		apply_firmware_cleanup(firm_ctx);
732 		return;
733 	}
734 
735 	firm_ctx->fw_image = spdk_zmalloc(firm_ctx->size, 4096, NULL,
736 					  SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
737 	if (!firm_ctx->fw_image) {
738 		close(fd);
739 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
740 						 "Memory allocation error.");
741 		apply_firmware_cleanup(firm_ctx);
742 		return;
743 	}
744 	firm_ctx->p = firm_ctx->fw_image;
745 
746 	if (read(fd, firm_ctx->p, firm_ctx->size) != ((ssize_t)(firm_ctx->size))) {
747 		close(fd);
748 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
749 						 "Read firmware image failed!");
750 		apply_firmware_cleanup(firm_ctx);
751 		return;
752 	}
753 	close(fd);
754 
755 	firm_ctx->offset = 0;
756 	firm_ctx->size_remaining = firm_ctx->size;
757 	firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096);
758 
759 	cmd = malloc(sizeof(struct spdk_nvme_cmd));
760 	if (!cmd) {
761 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
762 						 "Memory allocation error.");
763 		apply_firmware_cleanup(firm_ctx);
764 		return;
765 	}
766 	memset(cmd, 0, sizeof(struct spdk_nvme_cmd));
767 	cmd->opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
768 
769 	cmd->cdw10 = (firm_ctx->transfer >> 2) - 1;
770 	cmd->cdw11 = firm_ctx->offset >> 2;
771 
772 	rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, cmd, firm_ctx->p,
773 					   firm_ctx->transfer, apply_firmware_complete, firm_ctx);
774 	if (rc) {
775 		free(cmd);
776 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
777 						 "Read firmware image failed!");
778 		apply_firmware_cleanup(firm_ctx);
779 		return;
780 	}
781 }
782 SPDK_RPC_REGISTER("apply_nvme_firmware", spdk_rpc_apply_nvme_firmware, SPDK_RPC_RUNTIME)
783