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