xref: /spdk/lib/nvmf/nvmf_rpc.c (revision b37db06935181fd0e8f5592a96d860040abaa201)
1488570ebSJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2016 Intel Corporation. All rights reserved.
336ac75b9SAlexey Marchuk  *   Copyright (c) 2018-2021 Mellanox Technologies LTD. All rights reserved.
497385af1SAlexey Marchuk  *   Copyright (c) 2021 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5a54a6a26SSeth Howell  */
6a54a6a26SSeth Howell 
7a54a6a26SSeth Howell #include "spdk/bdev.h"
8a54a6a26SSeth Howell #include "spdk/log.h"
9a54a6a26SSeth Howell #include "spdk/rpc.h"
10a54a6a26SSeth Howell #include "spdk/env.h"
11a54a6a26SSeth Howell #include "spdk/nvme.h"
12a54a6a26SSeth Howell #include "spdk/nvmf.h"
13a54a6a26SSeth Howell #include "spdk/string.h"
14a54a6a26SSeth Howell #include "spdk/util.h"
154cc04a12SShuhei Matsumoto #include "spdk/bit_array.h"
16e2d54380Skyuho.son #include "spdk/config.h"
17a54a6a26SSeth Howell 
1844e2f510SSeth Howell #include "spdk_internal/assert.h"
19a54a6a26SSeth Howell 
202167c68dSJan Kryl #include "nvmf_internal.h"
212167c68dSJan Kryl 
22ecbceb22SMarcin Spiewak static int rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state);
23ecbceb22SMarcin Spiewak 
24a54a6a26SSeth Howell static int
25a54a6a26SSeth Howell json_write_hex_str(struct spdk_json_write_ctx *w, const void *data, size_t size)
26a54a6a26SSeth Howell {
27a54a6a26SSeth Howell 	static const char hex_char[16] = "0123456789ABCDEF";
28a54a6a26SSeth Howell 	const uint8_t *buf = data;
29a54a6a26SSeth Howell 	char *str, *out;
30a54a6a26SSeth Howell 	int rc;
31a54a6a26SSeth Howell 
32a54a6a26SSeth Howell 	str = malloc(size * 2 + 1);
33a54a6a26SSeth Howell 	if (str == NULL) {
34a54a6a26SSeth Howell 		return -1;
35a54a6a26SSeth Howell 	}
36a54a6a26SSeth Howell 
37a54a6a26SSeth Howell 	out = str;
38a54a6a26SSeth Howell 	while (size--) {
39a54a6a26SSeth Howell 		unsigned byte = *buf++;
40a54a6a26SSeth Howell 
41a54a6a26SSeth Howell 		out[0] = hex_char[(byte >> 4) & 0xF];
42a54a6a26SSeth Howell 		out[1] = hex_char[byte & 0xF];
43a54a6a26SSeth Howell 
44a54a6a26SSeth Howell 		out += 2;
45a54a6a26SSeth Howell 	}
46a54a6a26SSeth Howell 	*out = '\0';
47a54a6a26SSeth Howell 
48a54a6a26SSeth Howell 	rc = spdk_json_write_string(w, str);
49a54a6a26SSeth Howell 	free(str);
50a54a6a26SSeth Howell 
51a54a6a26SSeth Howell 	return rc;
52a54a6a26SSeth Howell }
53a54a6a26SSeth Howell 
54a54a6a26SSeth Howell static int
55a54a6a26SSeth Howell hex_nybble_to_num(char c)
56a54a6a26SSeth Howell {
57a54a6a26SSeth Howell 	if (c >= '0' && c <= '9') {
58a54a6a26SSeth Howell 		return c - '0';
59a54a6a26SSeth Howell 	}
60a54a6a26SSeth Howell 
61a54a6a26SSeth Howell 	if (c >= 'a' && c <= 'f') {
62a54a6a26SSeth Howell 		return c - 'a' + 0xA;
63a54a6a26SSeth Howell 	}
64a54a6a26SSeth Howell 
65a54a6a26SSeth Howell 	if (c >= 'A' && c <= 'F') {
66a54a6a26SSeth Howell 		return c - 'A' + 0xA;
67a54a6a26SSeth Howell 	}
68a54a6a26SSeth Howell 
69a54a6a26SSeth Howell 	return -1;
70a54a6a26SSeth Howell }
71a54a6a26SSeth Howell 
72a54a6a26SSeth Howell static int
73a54a6a26SSeth Howell hex_byte_to_num(const char *str)
74a54a6a26SSeth Howell {
75a54a6a26SSeth Howell 	int hi, lo;
76a54a6a26SSeth Howell 
77a54a6a26SSeth Howell 	hi = hex_nybble_to_num(str[0]);
78a54a6a26SSeth Howell 	if (hi < 0) {
79a54a6a26SSeth Howell 		return hi;
80a54a6a26SSeth Howell 	}
81a54a6a26SSeth Howell 
82a54a6a26SSeth Howell 	lo = hex_nybble_to_num(str[1]);
83a54a6a26SSeth Howell 	if (lo < 0) {
84a54a6a26SSeth Howell 		return lo;
85a54a6a26SSeth Howell 	}
86a54a6a26SSeth Howell 
87a54a6a26SSeth Howell 	return hi * 16 + lo;
88a54a6a26SSeth Howell }
89a54a6a26SSeth Howell 
90a54a6a26SSeth Howell static int
91a54a6a26SSeth Howell decode_hex_string_be(const char *str, uint8_t *out, size_t size)
92a54a6a26SSeth Howell {
93a54a6a26SSeth Howell 	size_t i;
94a54a6a26SSeth Howell 
95a54a6a26SSeth Howell 	/* Decode a string in "ABCDEF012345" format to its binary representation */
96a54a6a26SSeth Howell 	for (i = 0; i < size; i++) {
97a54a6a26SSeth Howell 		int num = hex_byte_to_num(str);
98a54a6a26SSeth Howell 
99a54a6a26SSeth Howell 		if (num < 0) {
100a54a6a26SSeth Howell 			/* Invalid hex byte or end of string */
101a54a6a26SSeth Howell 			return -1;
102a54a6a26SSeth Howell 		}
103a54a6a26SSeth Howell 
104a54a6a26SSeth Howell 		out[i] = (uint8_t)num;
105a54a6a26SSeth Howell 		str += 2;
106a54a6a26SSeth Howell 	}
107a54a6a26SSeth Howell 
108a54a6a26SSeth Howell 	if (i != size || *str != '\0') {
109a54a6a26SSeth Howell 		/* Length mismatch */
110a54a6a26SSeth Howell 		return -1;
111a54a6a26SSeth Howell 	}
112a54a6a26SSeth Howell 
113a54a6a26SSeth Howell 	return 0;
114a54a6a26SSeth Howell }
115a54a6a26SSeth Howell 
116a54a6a26SSeth Howell static int
117a54a6a26SSeth Howell decode_ns_nguid(const struct spdk_json_val *val, void *out)
118a54a6a26SSeth Howell {
119a54a6a26SSeth Howell 	char *str = NULL;
120a54a6a26SSeth Howell 	int rc;
121a54a6a26SSeth Howell 
122a54a6a26SSeth Howell 	rc = spdk_json_decode_string(val, &str);
123a54a6a26SSeth Howell 	if (rc == 0) {
124a54a6a26SSeth Howell 		/* 16-byte NGUID */
125a54a6a26SSeth Howell 		rc = decode_hex_string_be(str, out, 16);
126a54a6a26SSeth Howell 	}
127a54a6a26SSeth Howell 
128a54a6a26SSeth Howell 	free(str);
129a54a6a26SSeth Howell 	return rc;
130a54a6a26SSeth Howell }
131a54a6a26SSeth Howell 
132a54a6a26SSeth Howell static int
133a54a6a26SSeth Howell decode_ns_eui64(const struct spdk_json_val *val, void *out)
134a54a6a26SSeth Howell {
135a54a6a26SSeth Howell 	char *str = NULL;
136a54a6a26SSeth Howell 	int rc;
137a54a6a26SSeth Howell 
138a54a6a26SSeth Howell 	rc = spdk_json_decode_string(val, &str);
139a54a6a26SSeth Howell 	if (rc == 0) {
140a54a6a26SSeth Howell 		/* 8-byte EUI-64 */
141a54a6a26SSeth Howell 		rc = decode_hex_string_be(str, out, 8);
142a54a6a26SSeth Howell 	}
143a54a6a26SSeth Howell 
144a54a6a26SSeth Howell 	free(str);
145a54a6a26SSeth Howell 	return rc;
146a54a6a26SSeth Howell }
147a54a6a26SSeth Howell 
148f8433aadSSeth Howell struct rpc_get_subsystem {
149dfafab22SJacek Kalwas 	char *nqn;
150f8433aadSSeth Howell 	char *tgt_name;
151f8433aadSSeth Howell };
152f8433aadSSeth Howell 
153f8433aadSSeth Howell static const struct spdk_json_object_decoder rpc_get_subsystem_decoders[] = {
154dfafab22SJacek Kalwas 	{"nqn", offsetof(struct rpc_get_subsystem, nqn), spdk_json_decode_string, true},
155f8433aadSSeth Howell 	{"tgt_name", offsetof(struct rpc_get_subsystem, tgt_name), spdk_json_decode_string, true},
156f8433aadSSeth Howell };
157f8433aadSSeth Howell 
158a54a6a26SSeth Howell static void
159a54a6a26SSeth Howell dump_nvmf_subsystem(struct spdk_json_write_ctx *w, struct spdk_nvmf_subsystem *subsystem)
160a54a6a26SSeth Howell {
161a54a6a26SSeth Howell 	struct spdk_nvmf_host			*host;
162c79d4eefSJacek Kalwas 	struct spdk_nvmf_subsystem_listener	*listener;
163a54a6a26SSeth Howell 
164a54a6a26SSeth Howell 	spdk_json_write_object_begin(w);
165a54a6a26SSeth Howell 
166a54a6a26SSeth Howell 	spdk_json_write_named_string(w, "nqn", spdk_nvmf_subsystem_get_nqn(subsystem));
167a54a6a26SSeth Howell 	spdk_json_write_name(w, "subtype");
168a54a6a26SSeth Howell 	if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) {
169a54a6a26SSeth Howell 		spdk_json_write_string(w, "NVMe");
170a54a6a26SSeth Howell 	} else {
171a54a6a26SSeth Howell 		spdk_json_write_string(w, "Discovery");
172a54a6a26SSeth Howell 	}
173a54a6a26SSeth Howell 
174a54a6a26SSeth Howell 	spdk_json_write_named_array_begin(w, "listen_addresses");
175a54a6a26SSeth Howell 
176a54a6a26SSeth Howell 	for (listener = spdk_nvmf_subsystem_get_first_listener(subsystem); listener != NULL;
177a54a6a26SSeth Howell 	     listener = spdk_nvmf_subsystem_get_next_listener(subsystem, listener)) {
178a54a6a26SSeth Howell 		const struct spdk_nvme_transport_id *trid;
179a54a6a26SSeth Howell 
180c79d4eefSJacek Kalwas 		trid = spdk_nvmf_subsystem_listener_get_trid(listener);
181a54a6a26SSeth Howell 
182a54a6a26SSeth Howell 		spdk_json_write_object_begin(w);
183f5260201SWojciech Panfil 		nvmf_transport_listen_dump_trid(trid, w);
184a54a6a26SSeth Howell 		spdk_json_write_object_end(w);
185a54a6a26SSeth Howell 	}
186a54a6a26SSeth Howell 	spdk_json_write_array_end(w);
187a54a6a26SSeth Howell 
188a54a6a26SSeth Howell 	spdk_json_write_named_bool(w, "allow_any_host",
189a54a6a26SSeth Howell 				   spdk_nvmf_subsystem_get_allow_any_host(subsystem));
190a54a6a26SSeth Howell 
191a54a6a26SSeth Howell 	spdk_json_write_named_array_begin(w, "hosts");
192a54a6a26SSeth Howell 
193a54a6a26SSeth Howell 	for (host = spdk_nvmf_subsystem_get_first_host(subsystem); host != NULL;
194a54a6a26SSeth Howell 	     host = spdk_nvmf_subsystem_get_next_host(subsystem, host)) {
195a54a6a26SSeth Howell 		spdk_json_write_object_begin(w);
196a54a6a26SSeth Howell 		spdk_json_write_named_string(w, "nqn", spdk_nvmf_host_get_nqn(host));
1973f4f8ad0SKonrad Sztyber 		if (host->dhchap_key != NULL) {
1983f4f8ad0SKonrad Sztyber 			spdk_json_write_named_string(w, "dhchap_key",
1993f4f8ad0SKonrad Sztyber 						     spdk_key_get_name(host->dhchap_key));
2003f4f8ad0SKonrad Sztyber 		}
201aa13730dSKonrad Sztyber 		if (host->dhchap_ctrlr_key != NULL) {
202aa13730dSKonrad Sztyber 			spdk_json_write_named_string(w, "dhchap_ctrlr_key",
203aa13730dSKonrad Sztyber 						     spdk_key_get_name(host->dhchap_ctrlr_key));
204aa13730dSKonrad Sztyber 		}
205a54a6a26SSeth Howell 		spdk_json_write_object_end(w);
206a54a6a26SSeth Howell 	}
207a54a6a26SSeth Howell 	spdk_json_write_array_end(w);
208a54a6a26SSeth Howell 
209a54a6a26SSeth Howell 	if (spdk_nvmf_subsystem_get_type(subsystem) == SPDK_NVMF_SUBTYPE_NVME) {
210a54a6a26SSeth Howell 		struct spdk_nvmf_ns *ns;
211a54a6a26SSeth Howell 		struct spdk_nvmf_ns_opts ns_opts;
212a54a6a26SSeth Howell 		uint32_t max_namespaces;
213a54a6a26SSeth Howell 
214a54a6a26SSeth Howell 		spdk_json_write_named_string(w, "serial_number", spdk_nvmf_subsystem_get_sn(subsystem));
215a54a6a26SSeth Howell 
216a54a6a26SSeth Howell 		spdk_json_write_named_string(w, "model_number", spdk_nvmf_subsystem_get_mn(subsystem));
217a54a6a26SSeth Howell 
218a54a6a26SSeth Howell 		max_namespaces = spdk_nvmf_subsystem_get_max_namespaces(subsystem);
219a54a6a26SSeth Howell 		if (max_namespaces != 0) {
220a54a6a26SSeth Howell 			spdk_json_write_named_uint32(w, "max_namespaces", max_namespaces);
221a54a6a26SSeth Howell 		}
222a54a6a26SSeth Howell 
223be6a01efSJonathan Teh 		spdk_json_write_named_uint32(w, "min_cntlid", spdk_nvmf_subsystem_get_min_cntlid(subsystem));
224be6a01efSJonathan Teh 		spdk_json_write_named_uint32(w, "max_cntlid", spdk_nvmf_subsystem_get_max_cntlid(subsystem));
225be6a01efSJonathan Teh 
226a54a6a26SSeth Howell 		spdk_json_write_named_array_begin(w, "namespaces");
227a54a6a26SSeth Howell 		for (ns = spdk_nvmf_subsystem_get_first_ns(subsystem); ns != NULL;
228a54a6a26SSeth Howell 		     ns = spdk_nvmf_subsystem_get_next_ns(subsystem, ns)) {
229a54a6a26SSeth Howell 			spdk_nvmf_ns_get_opts(ns, &ns_opts, sizeof(ns_opts));
230a54a6a26SSeth Howell 			spdk_json_write_object_begin(w);
231a54a6a26SSeth Howell 			spdk_json_write_named_int32(w, "nsid", spdk_nvmf_ns_get_id(ns));
232a54a6a26SSeth Howell 			spdk_json_write_named_string(w, "bdev_name",
233a54a6a26SSeth Howell 						     spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns)));
234a54a6a26SSeth Howell 			/* NOTE: "name" is kept for compatibility only - new code should use bdev_name. */
235a54a6a26SSeth Howell 			spdk_json_write_named_string(w, "name",
236a54a6a26SSeth Howell 						     spdk_bdev_get_name(spdk_nvmf_ns_get_bdev(ns)));
237a54a6a26SSeth Howell 
238a54a6a26SSeth Howell 			if (!spdk_mem_all_zero(ns_opts.nguid, sizeof(ns_opts.nguid))) {
239a54a6a26SSeth Howell 				spdk_json_write_name(w, "nguid");
240a54a6a26SSeth Howell 				json_write_hex_str(w, ns_opts.nguid, sizeof(ns_opts.nguid));
241a54a6a26SSeth Howell 			}
242a54a6a26SSeth Howell 
243a54a6a26SSeth Howell 			if (!spdk_mem_all_zero(ns_opts.eui64, sizeof(ns_opts.eui64))) {
244a54a6a26SSeth Howell 				spdk_json_write_name(w, "eui64");
245a54a6a26SSeth Howell 				json_write_hex_str(w, ns_opts.eui64, sizeof(ns_opts.eui64));
246a54a6a26SSeth Howell 			}
247a54a6a26SSeth Howell 
24895a367d6SArtur Paszkiewicz 			if (!spdk_uuid_is_null(&ns_opts.uuid)) {
2498cffbe01SKonrad Sztyber 				spdk_json_write_named_uuid(w, "uuid", &ns_opts.uuid);
250a54a6a26SSeth Howell 			}
251a54a6a26SSeth Howell 
252fb5650ceSAbhineet Pandey 			if (spdk_nvmf_subsystem_get_ana_reporting(subsystem)) {
253694fa34dSShuhei Matsumoto 				spdk_json_write_named_uint32(w, "anagrpid", ns_opts.anagrpid);
254694fa34dSShuhei Matsumoto 			}
255694fa34dSShuhei Matsumoto 
256a54a6a26SSeth Howell 			spdk_json_write_object_end(w);
257a54a6a26SSeth Howell 		}
258a54a6a26SSeth Howell 		spdk_json_write_array_end(w);
259a54a6a26SSeth Howell 	}
260a54a6a26SSeth Howell 	spdk_json_write_object_end(w);
261a54a6a26SSeth Howell }
262a54a6a26SSeth Howell 
263a54a6a26SSeth Howell static void
264e569a578SSeth Howell rpc_nvmf_get_subsystems(struct spdk_jsonrpc_request *request,
265a54a6a26SSeth Howell 			const struct spdk_json_val *params)
266a54a6a26SSeth Howell {
267f8433aadSSeth Howell 	struct rpc_get_subsystem req = { 0 };
268a54a6a26SSeth Howell 	struct spdk_json_write_ctx *w;
269dfafab22SJacek Kalwas 	struct spdk_nvmf_subsystem *subsystem = NULL;
270a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
271a54a6a26SSeth Howell 
272f8433aadSSeth Howell 	if (params) {
273f8433aadSSeth Howell 		if (spdk_json_decode_object(params, rpc_get_subsystem_decoders,
274f8433aadSSeth Howell 					    SPDK_COUNTOF(rpc_get_subsystem_decoders),
275f8433aadSSeth Howell 					    &req)) {
276f8433aadSSeth Howell 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
277f8433aadSSeth Howell 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
278a54a6a26SSeth Howell 			return;
279a54a6a26SSeth Howell 		}
280f8433aadSSeth Howell 	}
281a54a6a26SSeth Howell 
282f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(req.tgt_name);
283a54a6a26SSeth Howell 	if (!tgt) {
284a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
285a54a6a26SSeth Howell 						 "Unable to find a target.");
286f8433aadSSeth Howell 		free(req.tgt_name);
287dfafab22SJacek Kalwas 		free(req.nqn);
288a54a6a26SSeth Howell 		return;
289a54a6a26SSeth Howell 	}
290a54a6a26SSeth Howell 
291dfafab22SJacek Kalwas 	if (req.nqn) {
292dfafab22SJacek Kalwas 		subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn);
293dfafab22SJacek Kalwas 		if (!subsystem) {
294dfafab22SJacek Kalwas 			SPDK_ERRLOG("subsystem '%s' does not exist\n", req.nqn);
295dfafab22SJacek Kalwas 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
296dfafab22SJacek Kalwas 			free(req.tgt_name);
297dfafab22SJacek Kalwas 			free(req.nqn);
298dfafab22SJacek Kalwas 			return;
299dfafab22SJacek Kalwas 		}
300dfafab22SJacek Kalwas 	}
301dfafab22SJacek Kalwas 
302a54a6a26SSeth Howell 	w = spdk_jsonrpc_begin_result(request);
303a54a6a26SSeth Howell 	spdk_json_write_array_begin(w);
304dfafab22SJacek Kalwas 
305dfafab22SJacek Kalwas 	if (subsystem) {
306a54a6a26SSeth Howell 		dump_nvmf_subsystem(w, subsystem);
307dfafab22SJacek Kalwas 	} else {
308dfafab22SJacek Kalwas 		for (subsystem = spdk_nvmf_subsystem_get_first(tgt); subsystem != NULL;
309dfafab22SJacek Kalwas 		     subsystem = spdk_nvmf_subsystem_get_next(subsystem)) {
310dfafab22SJacek Kalwas 			dump_nvmf_subsystem(w, subsystem);
311a54a6a26SSeth Howell 		}
312dfafab22SJacek Kalwas 	}
313dfafab22SJacek Kalwas 
314a54a6a26SSeth Howell 	spdk_json_write_array_end(w);
315a54a6a26SSeth Howell 	spdk_jsonrpc_end_result(request, w);
316f8433aadSSeth Howell 	free(req.tgt_name);
317dfafab22SJacek Kalwas 	free(req.nqn);
318a54a6a26SSeth Howell }
319e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_get_subsystems", rpc_nvmf_get_subsystems, SPDK_RPC_RUNTIME)
320a54a6a26SSeth Howell 
321a54a6a26SSeth Howell struct rpc_subsystem_create {
322a54a6a26SSeth Howell 	char *nqn;
323a54a6a26SSeth Howell 	char *serial_number;
324a54a6a26SSeth Howell 	char *model_number;
325f8433aadSSeth Howell 	char *tgt_name;
326a54a6a26SSeth Howell 	uint32_t max_namespaces;
327a54a6a26SSeth Howell 	bool allow_any_host;
3281da94ed7SShuhei Matsumoto 	bool ana_reporting;
329be6a01efSJonathan Teh 	uint16_t min_cntlid;
330be6a01efSJonathan Teh 	uint16_t max_cntlid;
331c7feb85dSHaoqian He 	uint64_t max_discard_size_kib;
332c7feb85dSHaoqian He 	uint64_t max_write_zeroes_size_kib;
33360241941SKarl Bonde Torp 	bool passthrough;
334a54a6a26SSeth Howell };
335a54a6a26SSeth Howell 
336a54a6a26SSeth Howell static const struct spdk_json_object_decoder rpc_subsystem_create_decoders[] = {
337a54a6a26SSeth Howell 	{"nqn", offsetof(struct rpc_subsystem_create, nqn), spdk_json_decode_string},
338a54a6a26SSeth Howell 	{"serial_number", offsetof(struct rpc_subsystem_create, serial_number), spdk_json_decode_string, true},
339a54a6a26SSeth Howell 	{"model_number", offsetof(struct rpc_subsystem_create, model_number), spdk_json_decode_string, true},
340f8433aadSSeth Howell 	{"tgt_name", offsetof(struct rpc_subsystem_create, tgt_name), spdk_json_decode_string, true},
341a54a6a26SSeth Howell 	{"max_namespaces", offsetof(struct rpc_subsystem_create, max_namespaces), spdk_json_decode_uint32, true},
342a54a6a26SSeth Howell 	{"allow_any_host", offsetof(struct rpc_subsystem_create, allow_any_host), spdk_json_decode_bool, true},
3431da94ed7SShuhei Matsumoto 	{"ana_reporting", offsetof(struct rpc_subsystem_create, ana_reporting), spdk_json_decode_bool, true},
344be6a01efSJonathan Teh 	{"min_cntlid", offsetof(struct rpc_subsystem_create, min_cntlid), spdk_json_decode_uint16, true},
345be6a01efSJonathan Teh 	{"max_cntlid", offsetof(struct rpc_subsystem_create, max_cntlid), spdk_json_decode_uint16, true},
346c7feb85dSHaoqian He 	{"max_discard_size_kib", offsetof(struct rpc_subsystem_create, max_discard_size_kib), spdk_json_decode_uint64, true},
347c7feb85dSHaoqian He 	{"max_write_zeroes_size_kib", offsetof(struct rpc_subsystem_create, max_write_zeroes_size_kib), spdk_json_decode_uint64, true},
34860241941SKarl Bonde Torp 	{"passthrough", offsetof(struct rpc_subsystem_create, passthrough), spdk_json_decode_bool, true},
349a54a6a26SSeth Howell };
350a54a6a26SSeth Howell 
351a54a6a26SSeth Howell static void
352e569a578SSeth Howell rpc_nvmf_subsystem_started(struct spdk_nvmf_subsystem *subsystem,
353a54a6a26SSeth Howell 			   void *cb_arg, int status)
354a54a6a26SSeth Howell {
355a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request = cb_arg;
356a54a6a26SSeth Howell 
357c29247e1SAlexey Marchuk 	if (!status) {
358d73077b8Syidong0635 		spdk_jsonrpc_send_bool_response(request, true);
359c29247e1SAlexey Marchuk 	} else {
360c29247e1SAlexey Marchuk 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
361c29247e1SAlexey Marchuk 						     "Subsystem %s start failed",
362c29247e1SAlexey Marchuk 						     subsystem->subnqn);
36397385af1SAlexey Marchuk 		spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
364c29247e1SAlexey Marchuk 	}
365a54a6a26SSeth Howell }
366a54a6a26SSeth Howell 
367a54a6a26SSeth Howell static void
368e569a578SSeth Howell rpc_nvmf_create_subsystem(struct spdk_jsonrpc_request *request,
369a54a6a26SSeth Howell 			  const struct spdk_json_val *params)
370a54a6a26SSeth Howell {
371a54a6a26SSeth Howell 	struct rpc_subsystem_create *req;
372c29247e1SAlexey Marchuk 	struct spdk_nvmf_subsystem *subsystem = NULL;
373a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
374c29247e1SAlexey Marchuk 	int rc = -1;
375a54a6a26SSeth Howell 
376a54a6a26SSeth Howell 	req = calloc(1, sizeof(*req));
377a54a6a26SSeth Howell 	if (!req) {
378c29247e1SAlexey Marchuk 		SPDK_ERRLOG("Memory allocation failed\n");
379c29247e1SAlexey Marchuk 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
380c29247e1SAlexey Marchuk 						 "Memory allocation failed");
381c29247e1SAlexey Marchuk 		return;
382a54a6a26SSeth Howell 	}
383be6a01efSJonathan Teh 	req->min_cntlid = NVMF_MIN_CNTLID;
384be6a01efSJonathan Teh 	req->max_cntlid = NVMF_MAX_CNTLID;
385a54a6a26SSeth Howell 
386a54a6a26SSeth Howell 	if (spdk_json_decode_object(params, rpc_subsystem_create_decoders,
387a54a6a26SSeth Howell 				    SPDK_COUNTOF(rpc_subsystem_create_decoders),
388a54a6a26SSeth Howell 				    req)) {
389a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
390c29247e1SAlexey Marchuk 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
391c29247e1SAlexey Marchuk 		goto cleanup;
392a54a6a26SSeth Howell 	}
393a54a6a26SSeth Howell 
394f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(req->tgt_name);
395a54a6a26SSeth Howell 	if (!tgt) {
396c29247e1SAlexey Marchuk 		SPDK_ERRLOG("Unable to find target %s\n", req->tgt_name);
397c29247e1SAlexey Marchuk 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
398c29247e1SAlexey Marchuk 						     "Unable to find target %s", req->tgt_name);
399c29247e1SAlexey Marchuk 		goto cleanup;
400a54a6a26SSeth Howell 	}
401a54a6a26SSeth Howell 
402a54a6a26SSeth Howell 	subsystem = spdk_nvmf_subsystem_create(tgt, req->nqn, SPDK_NVMF_SUBTYPE_NVME,
403a54a6a26SSeth Howell 					       req->max_namespaces);
404a54a6a26SSeth Howell 	if (!subsystem) {
405c29247e1SAlexey Marchuk 		SPDK_ERRLOG("Unable to create subsystem %s\n", req->nqn);
406c29247e1SAlexey Marchuk 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
407c29247e1SAlexey Marchuk 						     "Unable to create subsystem %s", req->nqn);
408c29247e1SAlexey Marchuk 		goto cleanup;
409a54a6a26SSeth Howell 	}
410a54a6a26SSeth Howell 
411a54a6a26SSeth Howell 	if (req->serial_number) {
412a54a6a26SSeth Howell 		if (spdk_nvmf_subsystem_set_sn(subsystem, req->serial_number)) {
413a54a6a26SSeth Howell 			SPDK_ERRLOG("Subsystem %s: invalid serial number '%s'\n", req->nqn, req->serial_number);
414c29247e1SAlexey Marchuk 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
415c29247e1SAlexey Marchuk 							     "Invalid SN %s", req->serial_number);
416c29247e1SAlexey Marchuk 			goto cleanup;
417a54a6a26SSeth Howell 		}
418a54a6a26SSeth Howell 	}
419a54a6a26SSeth Howell 
420a54a6a26SSeth Howell 	if (req->model_number) {
421a54a6a26SSeth Howell 		if (spdk_nvmf_subsystem_set_mn(subsystem, req->model_number)) {
422a54a6a26SSeth Howell 			SPDK_ERRLOG("Subsystem %s: invalid model number '%s'\n", req->nqn, req->model_number);
423c29247e1SAlexey Marchuk 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
424c29247e1SAlexey Marchuk 							     "Invalid MN %s", req->model_number);
425c29247e1SAlexey Marchuk 			goto cleanup;
426a54a6a26SSeth Howell 		}
427a54a6a26SSeth Howell 	}
428a54a6a26SSeth Howell 
429a54a6a26SSeth Howell 	spdk_nvmf_subsystem_set_allow_any_host(subsystem, req->allow_any_host);
430a54a6a26SSeth Howell 
4311da94ed7SShuhei Matsumoto 	spdk_nvmf_subsystem_set_ana_reporting(subsystem, req->ana_reporting);
4321da94ed7SShuhei Matsumoto 
433096538c8SAbhineet Pandey 	if (spdk_nvmf_subsystem_set_cntlid_range(subsystem, req->min_cntlid, req->max_cntlid)) {
434be6a01efSJonathan Teh 		SPDK_ERRLOG("Subsystem %s: invalid cntlid range [%u-%u]\n", req->nqn, req->min_cntlid,
435be6a01efSJonathan Teh 			    req->max_cntlid);
436be6a01efSJonathan Teh 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
437be6a01efSJonathan Teh 						     "Invalid cntlid range [%u-%u]", req->min_cntlid, req->max_cntlid);
438be6a01efSJonathan Teh 		goto cleanup;
439be6a01efSJonathan Teh 	}
440be6a01efSJonathan Teh 
441c7feb85dSHaoqian He 	subsystem->max_discard_size_kib = req->max_discard_size_kib;
442c7feb85dSHaoqian He 
443c7feb85dSHaoqian He 	/* max_write_zeroes_size_kib must be aligned to 4 and power of 2 */
444c7feb85dSHaoqian He 	if (req->max_write_zeroes_size_kib == 0 || (req->max_write_zeroes_size_kib > 2 &&
445c7feb85dSHaoqian He 			spdk_u64_is_pow2(req->max_write_zeroes_size_kib))) {
446c7feb85dSHaoqian He 		subsystem->max_write_zeroes_size_kib = req->max_write_zeroes_size_kib;
447c7feb85dSHaoqian He 	} else {
448c7feb85dSHaoqian He 		SPDK_ERRLOG("Subsystem %s: invalid max_write_zeroes_size_kib %"PRIu64"\n", req->nqn,
449c7feb85dSHaoqian He 			    req->max_write_zeroes_size_kib);
450c7feb85dSHaoqian He 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
4519b143bcaSPierre Lestringant 						     "Invalid max_write_zeroes_size_kib %"PRIu64, req->max_write_zeroes_size_kib);
452c7feb85dSHaoqian He 		goto cleanup;
453c7feb85dSHaoqian He 	}
454c7feb85dSHaoqian He 
45560241941SKarl Bonde Torp 	subsystem->passthrough = req->passthrough;
45660241941SKarl Bonde Torp 
457c29247e1SAlexey Marchuk 	rc = spdk_nvmf_subsystem_start(subsystem,
458e569a578SSeth Howell 				       rpc_nvmf_subsystem_started,
459a54a6a26SSeth Howell 				       request);
46097385af1SAlexey Marchuk 	if (rc) {
46197385af1SAlexey Marchuk 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
46297385af1SAlexey Marchuk 						 "Failed to start subsystem");
46397385af1SAlexey Marchuk 	}
464a54a6a26SSeth Howell 
465c29247e1SAlexey Marchuk cleanup:
466a54a6a26SSeth Howell 	free(req->nqn);
467f8433aadSSeth Howell 	free(req->tgt_name);
468a54a6a26SSeth Howell 	free(req->serial_number);
469a54a6a26SSeth Howell 	free(req->model_number);
470a54a6a26SSeth Howell 	free(req);
471c29247e1SAlexey Marchuk 
472c29247e1SAlexey Marchuk 	if (rc && subsystem) {
47397385af1SAlexey Marchuk 		spdk_nvmf_subsystem_destroy(subsystem, NULL, NULL);
474c29247e1SAlexey Marchuk 	}
475a54a6a26SSeth Howell }
476e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_create_subsystem", rpc_nvmf_create_subsystem, SPDK_RPC_RUNTIME)
477a54a6a26SSeth Howell 
478a54a6a26SSeth Howell struct rpc_delete_subsystem {
479a54a6a26SSeth Howell 	char *nqn;
480f8433aadSSeth Howell 	char *tgt_name;
481a54a6a26SSeth Howell };
482a54a6a26SSeth Howell 
483a54a6a26SSeth Howell static void
484a54a6a26SSeth Howell free_rpc_delete_subsystem(struct rpc_delete_subsystem *r)
485a54a6a26SSeth Howell {
486a54a6a26SSeth Howell 	free(r->nqn);
487f8433aadSSeth Howell 	free(r->tgt_name);
488a54a6a26SSeth Howell }
489a54a6a26SSeth Howell 
4908dd1cd21SBen Walker static void
4918dd1cd21SBen Walker rpc_nvmf_subsystem_destroy_complete_cb(void *cb_arg)
49297385af1SAlexey Marchuk {
49397385af1SAlexey Marchuk 	struct spdk_jsonrpc_request *request = cb_arg;
49497385af1SAlexey Marchuk 
49597385af1SAlexey Marchuk 	spdk_jsonrpc_send_bool_response(request, true);
49697385af1SAlexey Marchuk }
49797385af1SAlexey Marchuk 
498a54a6a26SSeth Howell static void
499e569a578SSeth Howell rpc_nvmf_subsystem_stopped(struct spdk_nvmf_subsystem *subsystem,
500a54a6a26SSeth Howell 			   void *cb_arg, int status)
501a54a6a26SSeth Howell {
502a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request = cb_arg;
50397385af1SAlexey Marchuk 	int rc;
504a54a6a26SSeth Howell 
5059cb21ad6SSeth Howell 	nvmf_subsystem_remove_all_listeners(subsystem, true);
50697385af1SAlexey Marchuk 	rc = spdk_nvmf_subsystem_destroy(subsystem, rpc_nvmf_subsystem_destroy_complete_cb, request);
50797385af1SAlexey Marchuk 	if (rc) {
50897385af1SAlexey Marchuk 		if (rc == -EINPROGRESS) {
50997385af1SAlexey Marchuk 			/* response will be sent in completion callback */
51097385af1SAlexey Marchuk 			return;
51197385af1SAlexey Marchuk 		} else {
51297385af1SAlexey Marchuk 			SPDK_ERRLOG("Subsystem destruction failed, rc %d\n", rc);
51397385af1SAlexey Marchuk 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
51497385af1SAlexey Marchuk 							     "Subsystem destruction failed, rc %d", rc);
51597385af1SAlexey Marchuk 			return;
51697385af1SAlexey Marchuk 		}
51797385af1SAlexey Marchuk 	}
518d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
519a54a6a26SSeth Howell }
520a54a6a26SSeth Howell 
521a54a6a26SSeth Howell static const struct spdk_json_object_decoder rpc_delete_subsystem_decoders[] = {
522a54a6a26SSeth Howell 	{"nqn", offsetof(struct rpc_delete_subsystem, nqn), spdk_json_decode_string},
523f8433aadSSeth Howell 	{"tgt_name", offsetof(struct rpc_delete_subsystem, tgt_name), spdk_json_decode_string, true},
524a54a6a26SSeth Howell };
525a54a6a26SSeth Howell 
526a54a6a26SSeth Howell static void
527e569a578SSeth Howell rpc_nvmf_delete_subsystem(struct spdk_jsonrpc_request *request,
528a54a6a26SSeth Howell 			  const struct spdk_json_val *params)
529a54a6a26SSeth Howell {
530f8433aadSSeth Howell 	struct rpc_delete_subsystem req = { 0 };
531a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
532a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
5338ff8bf07SSeth Howell 	int rc;
534a54a6a26SSeth Howell 
535a54a6a26SSeth Howell 	if (spdk_json_decode_object(params, rpc_delete_subsystem_decoders,
536a54a6a26SSeth Howell 				    SPDK_COUNTOF(rpc_delete_subsystem_decoders),
537a54a6a26SSeth Howell 				    &req)) {
538a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
539a54a6a26SSeth Howell 		goto invalid;
540a54a6a26SSeth Howell 	}
541a54a6a26SSeth Howell 
542a54a6a26SSeth Howell 	if (req.nqn == NULL) {
543a54a6a26SSeth Howell 		SPDK_ERRLOG("missing name param\n");
544a54a6a26SSeth Howell 		goto invalid;
545a54a6a26SSeth Howell 	}
546a54a6a26SSeth Howell 
547f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(req.tgt_name);
548a54a6a26SSeth Howell 	if (!tgt) {
549a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
550a54a6a26SSeth Howell 						 "Unable to find a target.");
551a54a6a26SSeth Howell 		goto invalid_custom_response;
552a54a6a26SSeth Howell 	}
553a54a6a26SSeth Howell 
554a54a6a26SSeth Howell 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, req.nqn);
555a54a6a26SSeth Howell 	if (!subsystem) {
556a54a6a26SSeth Howell 		goto invalid;
557a54a6a26SSeth Howell 	}
558a54a6a26SSeth Howell 
559a54a6a26SSeth Howell 	free_rpc_delete_subsystem(&req);
560a54a6a26SSeth Howell 
5618ff8bf07SSeth Howell 	rc = spdk_nvmf_subsystem_stop(subsystem,
562e569a578SSeth Howell 				      rpc_nvmf_subsystem_stopped,
563a54a6a26SSeth Howell 				      request);
5648ff8bf07SSeth Howell 	if (rc == -EBUSY) {
5658ff8bf07SSeth Howell 		SPDK_ERRLOG("Subsystem currently in another state change try again later.\n");
5668ff8bf07SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
5678ff8bf07SSeth Howell 						 "Subsystem currently in another state change try again later.");
5688ff8bf07SSeth Howell 	} else if (rc != 0) {
5698ff8bf07SSeth Howell 		SPDK_ERRLOG("Unable to change state on subsystem. rc=%d\n", rc);
5708ff8bf07SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
5718ff8bf07SSeth Howell 						     "Unable to change state on subsystem. rc=%d", rc);
5728ff8bf07SSeth Howell 	}
573a54a6a26SSeth Howell 
574a54a6a26SSeth Howell 	return;
575a54a6a26SSeth Howell 
576a54a6a26SSeth Howell invalid:
577a54a6a26SSeth Howell 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
578a54a6a26SSeth Howell invalid_custom_response:
579a54a6a26SSeth Howell 	free_rpc_delete_subsystem(&req);
580a54a6a26SSeth Howell }
581e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_delete_subsystem", rpc_nvmf_delete_subsystem, SPDK_RPC_RUNTIME)
582a54a6a26SSeth Howell 
583a54a6a26SSeth Howell struct rpc_listen_address {
5848ee34f93SJim Harris 	char *trtype;
585a54a6a26SSeth Howell 	char *adrfam;
586a54a6a26SSeth Howell 	char *traddr;
587a54a6a26SSeth Howell 	char *trsvcid;
588a54a6a26SSeth Howell };
589a54a6a26SSeth Howell 
590a54a6a26SSeth Howell static const struct spdk_json_object_decoder rpc_listen_address_decoders[] = {
5918ee34f93SJim Harris 	{"trtype", offsetof(struct rpc_listen_address, trtype), spdk_json_decode_string, true},
592a54a6a26SSeth Howell 	{"adrfam", offsetof(struct rpc_listen_address, adrfam), spdk_json_decode_string, true},
593a54a6a26SSeth Howell 	{"traddr", offsetof(struct rpc_listen_address, traddr), spdk_json_decode_string},
5949a1cf1c5SJacek Kalwas 	{"trsvcid", offsetof(struct rpc_listen_address, trsvcid), spdk_json_decode_string, true},
595a54a6a26SSeth Howell };
596a54a6a26SSeth Howell 
597a54a6a26SSeth Howell static int
598a54a6a26SSeth Howell decode_rpc_listen_address(const struct spdk_json_val *val, void *out)
599a54a6a26SSeth Howell {
600a54a6a26SSeth Howell 	struct rpc_listen_address *req = (struct rpc_listen_address *)out;
601b93e775bSJacek Kalwas 
602e43b1b86SKonrad Sztyber 	return spdk_json_decode_object(val, rpc_listen_address_decoders,
603e43b1b86SKonrad Sztyber 				       SPDK_COUNTOF(rpc_listen_address_decoders), req);
604a54a6a26SSeth Howell }
605a54a6a26SSeth Howell 
606a54a6a26SSeth Howell static void
607a54a6a26SSeth Howell free_rpc_listen_address(struct rpc_listen_address *r)
608a54a6a26SSeth Howell {
6098ee34f93SJim Harris 	free(r->trtype);
610a54a6a26SSeth Howell 	free(r->adrfam);
611a54a6a26SSeth Howell 	free(r->traddr);
612a54a6a26SSeth Howell 	free(r->trsvcid);
613a54a6a26SSeth Howell }
614a54a6a26SSeth Howell 
615a54a6a26SSeth Howell enum nvmf_rpc_listen_op {
616a54a6a26SSeth Howell 	NVMF_RPC_LISTEN_ADD,
617a54a6a26SSeth Howell 	NVMF_RPC_LISTEN_REMOVE,
618c8cb51d4SShuhei Matsumoto 	NVMF_RPC_LISTEN_SET_ANA_STATE,
619a54a6a26SSeth Howell };
620a54a6a26SSeth Howell 
621a54a6a26SSeth Howell struct nvmf_rpc_listener_ctx {
622a54a6a26SSeth Howell 	char				*nqn;
623f8433aadSSeth Howell 	char				*tgt_name;
624a54a6a26SSeth Howell 	struct spdk_nvmf_tgt		*tgt;
625d1b0d2cbSSeth Howell 	struct spdk_nvmf_transport	*transport;
626a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem	*subsystem;
627a54a6a26SSeth Howell 	struct rpc_listen_address	address;
628c8cb51d4SShuhei Matsumoto 	char				*ana_state_str;
629c8cb51d4SShuhei Matsumoto 	enum spdk_nvme_ana_state	ana_state;
6306d716c47SShuhei Matsumoto 	uint32_t			anagrpid;
631a54a6a26SSeth Howell 
632a54a6a26SSeth Howell 	struct spdk_jsonrpc_request	*request;
633a54a6a26SSeth Howell 	struct spdk_nvme_transport_id	trid;
634a54a6a26SSeth Howell 	enum nvmf_rpc_listen_op		op;
635a54a6a26SSeth Howell 	bool				response_sent;
63687a062e6SJacek Kalwas 	struct spdk_nvmf_listen_opts	opts;
6377662387cSKrzysztof Karas 
638248c547dSKarl Bonde Torp 	/* Hole at bytes 705-711 */
639248c547dSKarl Bonde Torp 	uint8_t reserved1[7];
640248c547dSKarl Bonde Torp 
641248c547dSKarl Bonde Torp 	/* Additional options for listener creation.
642248c547dSKarl Bonde Torp 	 * Must be 8-byte aligned. */
6437662387cSKrzysztof Karas 	struct spdk_nvmf_listener_opts	listener_opts;
644a54a6a26SSeth Howell };
645a54a6a26SSeth Howell 
646a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_listener_decoder[] = {
647a54a6a26SSeth Howell 	{"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string},
648a54a6a26SSeth Howell 	{"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address},
649f8433aadSSeth Howell 	{"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true},
6507662387cSKrzysztof Karas 	{"secure_channel", offsetof(struct nvmf_rpc_listener_ctx, listener_opts.secure_channel), spdk_json_decode_bool, true},
651ecbceb22SMarcin Spiewak 	{"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string, true},
652248c547dSKarl Bonde Torp 	{"sock_impl", offsetof(struct nvmf_rpc_listener_ctx, listener_opts.sock_impl), spdk_json_decode_string, true},
653a54a6a26SSeth Howell };
654a54a6a26SSeth Howell 
655a54a6a26SSeth Howell static void
656a54a6a26SSeth Howell nvmf_rpc_listener_ctx_free(struct nvmf_rpc_listener_ctx *ctx)
657a54a6a26SSeth Howell {
658a54a6a26SSeth Howell 	free(ctx->nqn);
659f8433aadSSeth Howell 	free(ctx->tgt_name);
660a54a6a26SSeth Howell 	free_rpc_listen_address(&ctx->address);
661c8cb51d4SShuhei Matsumoto 	free(ctx->ana_state_str);
662a54a6a26SSeth Howell 	free(ctx);
663a54a6a26SSeth Howell }
664a54a6a26SSeth Howell 
665a54a6a26SSeth Howell static void
666a54a6a26SSeth Howell nvmf_rpc_listen_resumed(struct spdk_nvmf_subsystem *subsystem,
667a54a6a26SSeth Howell 			void *cb_arg, int status)
668a54a6a26SSeth Howell {
669a54a6a26SSeth Howell 	struct nvmf_rpc_listener_ctx *ctx = cb_arg;
670a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request;
671a54a6a26SSeth Howell 
672a54a6a26SSeth Howell 	request = ctx->request;
673a54a6a26SSeth Howell 	if (ctx->response_sent) {
674a54a6a26SSeth Howell 		/* If an error occurred, the response has already been sent. */
675a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
676a54a6a26SSeth Howell 		return;
677a54a6a26SSeth Howell 	}
678a54a6a26SSeth Howell 
679a54a6a26SSeth Howell 	nvmf_rpc_listener_ctx_free(ctx);
680a54a6a26SSeth Howell 
681d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
682a54a6a26SSeth Howell }
683a54a6a26SSeth Howell 
684a54a6a26SSeth Howell static void
6856fc8c8c2SBen Walker nvmf_rpc_subsystem_listen(void *cb_arg, int status)
6866fc8c8c2SBen Walker {
6876fc8c8c2SBen Walker 	struct nvmf_rpc_listener_ctx *ctx = cb_arg;
6886fc8c8c2SBen Walker 
6896fc8c8c2SBen Walker 	if (status) {
6906fc8c8c2SBen Walker 		/* Destroy the listener that we just created. Ignore the error code because
6916fc8c8c2SBen Walker 		 * the RPC is failing already anyway. */
6926fc8c8c2SBen Walker 		spdk_nvmf_tgt_stop_listen(ctx->tgt, &ctx->trid);
6936fc8c8c2SBen Walker 
6946fc8c8c2SBen Walker 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
6956fc8c8c2SBen Walker 						 "Invalid parameters");
6966fc8c8c2SBen Walker 		ctx->response_sent = true;
6976fc8c8c2SBen Walker 	}
6986fc8c8c2SBen Walker 
6996fc8c8c2SBen Walker 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
7006fc8c8c2SBen Walker 		if (!ctx->response_sent) {
701c8cb51d4SShuhei Matsumoto 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
702c8cb51d4SShuhei Matsumoto 							 "Internal error");
7036fc8c8c2SBen Walker 		}
7046fc8c8c2SBen Walker 		nvmf_rpc_listener_ctx_free(ctx);
7056fc8c8c2SBen Walker 		/* Can't really do anything to recover here - subsystem will remain paused. */
7066fc8c8c2SBen Walker 	}
7076fc8c8c2SBen Walker }
708d1b0d2cbSSeth Howell static void
709d1b0d2cbSSeth Howell nvmf_rpc_stop_listen_async_done(void *cb_arg, int status)
710d1b0d2cbSSeth Howell {
711d1b0d2cbSSeth Howell 	struct nvmf_rpc_listener_ctx *ctx = cb_arg;
712d1b0d2cbSSeth Howell 
713d1b0d2cbSSeth Howell 	if (status) {
714c8cb51d4SShuhei Matsumoto 		SPDK_ERRLOG("Unable to stop listener.\n");
715d1b0d2cbSSeth Howell 		spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
716c8cb51d4SShuhei Matsumoto 						     "error stopping listener: %d", status);
717d1b0d2cbSSeth Howell 		ctx->response_sent = true;
718d1b0d2cbSSeth Howell 	}
719d1b0d2cbSSeth Howell 
720d1b0d2cbSSeth Howell 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
721d1b0d2cbSSeth Howell 		if (!ctx->response_sent) {
722c8cb51d4SShuhei Matsumoto 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
723c8cb51d4SShuhei Matsumoto 							 "Internal error");
724c8cb51d4SShuhei Matsumoto 		}
725c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
726c8cb51d4SShuhei Matsumoto 		/* Can't really do anything to recover here - subsystem will remain paused. */
727c8cb51d4SShuhei Matsumoto 	}
728c8cb51d4SShuhei Matsumoto }
729c8cb51d4SShuhei Matsumoto 
730c8cb51d4SShuhei Matsumoto static void
731c8cb51d4SShuhei Matsumoto nvmf_rpc_set_ana_state_done(void *cb_arg, int status)
732c8cb51d4SShuhei Matsumoto {
733c8cb51d4SShuhei Matsumoto 	struct nvmf_rpc_listener_ctx *ctx = cb_arg;
734c8cb51d4SShuhei Matsumoto 
735c8cb51d4SShuhei Matsumoto 	if (status) {
736c8cb51d4SShuhei Matsumoto 		SPDK_ERRLOG("Unable to set ANA state.\n");
737c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
738c8cb51d4SShuhei Matsumoto 						     "error setting ANA state: %d", status);
739c8cb51d4SShuhei Matsumoto 		ctx->response_sent = true;
740c8cb51d4SShuhei Matsumoto 	}
741c8cb51d4SShuhei Matsumoto 
742c8cb51d4SShuhei Matsumoto 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, nvmf_rpc_listen_resumed, ctx)) {
743c8cb51d4SShuhei Matsumoto 		if (!ctx->response_sent) {
744c8cb51d4SShuhei Matsumoto 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
745c8cb51d4SShuhei Matsumoto 							 "Internal error");
746d1b0d2cbSSeth Howell 		}
747d1b0d2cbSSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
748d1b0d2cbSSeth Howell 		/* Can't really do anything to recover here - subsystem will remain paused. */
749d1b0d2cbSSeth Howell 	}
750d1b0d2cbSSeth Howell }
7516fc8c8c2SBen Walker 
7526fc8c8c2SBen Walker static void
753c40f35b7SBen Walker nvmf_rpc_listen_paused(struct spdk_nvmf_subsystem *subsystem,
754c40f35b7SBen Walker 		       void *cb_arg, int status)
755a54a6a26SSeth Howell {
756a54a6a26SSeth Howell 	struct nvmf_rpc_listener_ctx *ctx = cb_arg;
757c40f35b7SBen Walker 	int rc;
758a54a6a26SSeth Howell 
75951ed4866SJacek Kalwas 	switch (ctx->op) {
76051ed4866SJacek Kalwas 	case NVMF_RPC_LISTEN_ADD:
761ee9e3438SJacek Kalwas 		if (nvmf_subsystem_find_listener(subsystem, &ctx->trid)) {
762ee9e3438SJacek Kalwas 			SPDK_ERRLOG("Listener already exists\n");
7635d5e4d33SSlawomir Ptak 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
7645d5e4d33SSlawomir Ptak 							 "Invalid parameters");
7655d5e4d33SSlawomir Ptak 			ctx->response_sent = true;
76651ed4866SJacek Kalwas 			break;
7676fc8c8c2SBen Walker 		}
7686fc8c8c2SBen Walker 
76951ed4866SJacek Kalwas 		rc = spdk_nvmf_tgt_listen_ext(ctx->tgt, &ctx->trid, &ctx->opts);
77051ed4866SJacek Kalwas 		if (rc) {
771a54a6a26SSeth Howell 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
772a54a6a26SSeth Howell 							 "Invalid parameters");
773a54a6a26SSeth Howell 			ctx->response_sent = true;
77451ed4866SJacek Kalwas 			break;
775a54a6a26SSeth Howell 		}
77651ed4866SJacek Kalwas 
77751ed4866SJacek Kalwas 		spdk_nvmf_subsystem_add_listener_ext(ctx->subsystem, &ctx->trid, nvmf_rpc_subsystem_listen, ctx,
77851ed4866SJacek Kalwas 						     &ctx->listener_opts);
779d1b0d2cbSSeth Howell 		return;
78051ed4866SJacek Kalwas 	case NVMF_RPC_LISTEN_REMOVE:
78151ed4866SJacek Kalwas 		rc = spdk_nvmf_subsystem_remove_listener(subsystem, &ctx->trid);
78251ed4866SJacek Kalwas 		if (rc) {
783f209637cSAlexey Marchuk 			SPDK_ERRLOG("Unable to remove listener, rc %d\n", rc);
784f209637cSAlexey Marchuk 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
785f209637cSAlexey Marchuk 							 "Invalid parameters");
786f209637cSAlexey Marchuk 			ctx->response_sent = true;
78751ed4866SJacek Kalwas 			break;
78851ed4866SJacek Kalwas 		}
78951ed4866SJacek Kalwas 
79051ed4866SJacek Kalwas 		spdk_nvmf_transport_stop_listen_async(ctx->transport, &ctx->trid, subsystem,
79151ed4866SJacek Kalwas 						      nvmf_rpc_stop_listen_async_done, ctx);
79251ed4866SJacek Kalwas 		return;
79351ed4866SJacek Kalwas 	case NVMF_RPC_LISTEN_SET_ANA_STATE:
794fb5650ceSAbhineet Pandey 		spdk_nvmf_subsystem_set_ana_state(subsystem, &ctx->trid, ctx->ana_state, ctx->anagrpid,
795c8cb51d4SShuhei Matsumoto 						  nvmf_rpc_set_ana_state_done, ctx);
796c8cb51d4SShuhei Matsumoto 		return;
79751ed4866SJacek Kalwas 	default:
79844e2f510SSeth Howell 		SPDK_UNREACHABLE();
799a54a6a26SSeth Howell 	}
800a54a6a26SSeth Howell 
801a54a6a26SSeth Howell 	if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_listen_resumed, ctx)) {
802a54a6a26SSeth Howell 		if (!ctx->response_sent) {
803c8cb51d4SShuhei Matsumoto 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
804c8cb51d4SShuhei Matsumoto 							 "Internal error");
805a54a6a26SSeth Howell 		}
80651ed4866SJacek Kalwas 
807a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
808a54a6a26SSeth Howell 		/* Can't really do anything to recover here - subsystem will remain paused. */
809a54a6a26SSeth Howell 	}
810a54a6a26SSeth Howell }
811a54a6a26SSeth Howell 
812a54a6a26SSeth Howell static int
813a54a6a26SSeth Howell rpc_listen_address_to_trid(const struct rpc_listen_address *address,
814a54a6a26SSeth Howell 			   struct spdk_nvme_transport_id *trid)
815a54a6a26SSeth Howell {
816a54a6a26SSeth Howell 	size_t len;
817a54a6a26SSeth Howell 
818a54a6a26SSeth Howell 	memset(trid, 0, sizeof(*trid));
819a54a6a26SSeth Howell 
8208ee34f93SJim Harris 	if (spdk_nvme_transport_id_populate_trstring(trid, address->trtype)) {
8218ee34f93SJim Harris 		SPDK_ERRLOG("Invalid trtype string: %s\n", address->trtype);
8227ed0904bSSeth Howell 		return -EINVAL;
8237ed0904bSSeth Howell 	}
8247ed0904bSSeth Howell 
8258ee34f93SJim Harris 	if (spdk_nvme_transport_id_parse_trtype(&trid->trtype, address->trtype)) {
8268ee34f93SJim Harris 		SPDK_ERRLOG("Invalid trtype type: %s\n", address->trtype);
827a54a6a26SSeth Howell 		return -EINVAL;
828a54a6a26SSeth Howell 	}
829a54a6a26SSeth Howell 
830a54a6a26SSeth Howell 	if (address->adrfam) {
831a54a6a26SSeth Howell 		if (spdk_nvme_transport_id_parse_adrfam(&trid->adrfam, address->adrfam)) {
832a54a6a26SSeth Howell 			SPDK_ERRLOG("Invalid adrfam: %s\n", address->adrfam);
833a54a6a26SSeth Howell 			return -EINVAL;
834a54a6a26SSeth Howell 		}
835a54a6a26SSeth Howell 	} else {
836a54a6a26SSeth Howell 		trid->adrfam = SPDK_NVMF_ADRFAM_IPV4;
837a54a6a26SSeth Howell 	}
838a54a6a26SSeth Howell 
839a54a6a26SSeth Howell 	len = strlen(address->traddr);
840a54a6a26SSeth Howell 	if (len > sizeof(trid->traddr) - 1) {
841a54a6a26SSeth Howell 		SPDK_ERRLOG("Transport address longer than %zu characters: %s\n",
842a54a6a26SSeth Howell 			    sizeof(trid->traddr) - 1, address->traddr);
843a54a6a26SSeth Howell 		return -EINVAL;
844a54a6a26SSeth Howell 	}
845a54a6a26SSeth Howell 	memcpy(trid->traddr, address->traddr, len + 1);
846a54a6a26SSeth Howell 
8479a1cf1c5SJacek Kalwas 	trid->trsvcid[0] = '\0';
8489a1cf1c5SJacek Kalwas 	if (address->trsvcid) {
849a54a6a26SSeth Howell 		len = strlen(address->trsvcid);
850a54a6a26SSeth Howell 		if (len > sizeof(trid->trsvcid) - 1) {
851a54a6a26SSeth Howell 			SPDK_ERRLOG("Transport service id longer than %zu characters: %s\n",
852a54a6a26SSeth Howell 				    sizeof(trid->trsvcid) - 1, address->trsvcid);
853a54a6a26SSeth Howell 			return -EINVAL;
854a54a6a26SSeth Howell 		}
855a54a6a26SSeth Howell 		memcpy(trid->trsvcid, address->trsvcid, len + 1);
8569a1cf1c5SJacek Kalwas 	}
857a54a6a26SSeth Howell 
858a54a6a26SSeth Howell 	return 0;
859a54a6a26SSeth Howell }
860a54a6a26SSeth Howell 
861a54a6a26SSeth Howell static void
862e569a578SSeth Howell rpc_nvmf_subsystem_add_listener(struct spdk_jsonrpc_request *request,
863a54a6a26SSeth Howell 				const struct spdk_json_val *params)
864a54a6a26SSeth Howell {
865a54a6a26SSeth Howell 	struct nvmf_rpc_listener_ctx *ctx;
866a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
867a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
8688ff8bf07SSeth Howell 	int rc;
869a54a6a26SSeth Howell 
870a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
871a54a6a26SSeth Howell 	if (!ctx) {
872a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
873a54a6a26SSeth Howell 		return;
874a54a6a26SSeth Howell 	}
875a54a6a26SSeth Howell 
876a54a6a26SSeth Howell 	ctx->request = request;
877a54a6a26SSeth Howell 
8787662387cSKrzysztof Karas 	spdk_nvmf_subsystem_listener_opts_init(&ctx->listener_opts, sizeof(ctx->listener_opts));
8797662387cSKrzysztof Karas 
88087a062e6SJacek Kalwas 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_listener_decoder,
881a54a6a26SSeth Howell 					    SPDK_COUNTOF(nvmf_rpc_listener_decoder),
882a54a6a26SSeth Howell 					    ctx)) {
88387a062e6SJacek Kalwas 		SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
884a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
885a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
886a54a6a26SSeth Howell 		return;
887a54a6a26SSeth Howell 	}
888a54a6a26SSeth Howell 
889f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
890a54a6a26SSeth Howell 	if (!tgt) {
891a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
892a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
893a54a6a26SSeth Howell 						 "Unable to find a target.");
894a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
895a54a6a26SSeth Howell 		return;
896a54a6a26SSeth Howell 	}
897a54a6a26SSeth Howell 	ctx->tgt = tgt;
898a54a6a26SSeth Howell 
899a54a6a26SSeth Howell 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
900a54a6a26SSeth Howell 	if (!subsystem) {
901a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
902a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
903a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
904a54a6a26SSeth Howell 		return;
905a54a6a26SSeth Howell 	}
906a54a6a26SSeth Howell 
907a54a6a26SSeth Howell 	ctx->subsystem = subsystem;
908a54a6a26SSeth Howell 
909a54a6a26SSeth Howell 	if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
910a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
911a54a6a26SSeth Howell 						 "Invalid parameters");
912a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
913a54a6a26SSeth Howell 		return;
914a54a6a26SSeth Howell 	}
915a54a6a26SSeth Howell 
916a54a6a26SSeth Howell 	ctx->op = NVMF_RPC_LISTEN_ADD;
9179a1c2cabSJacek Kalwas 	spdk_nvmf_listen_opts_init(&ctx->opts, sizeof(ctx->opts));
91887a062e6SJacek Kalwas 	ctx->opts.transport_specific = params;
91929773365SKonrad Sztyber 	if (spdk_nvmf_subsystem_get_allow_any_host(subsystem) && ctx->listener_opts.secure_channel) {
9204becb0d1SBoris Glimcher 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
9214becb0d1SBoris Glimcher 						 "Cannot establish secure channel, when 'allow_any_host' is set");
9224becb0d1SBoris Glimcher 		nvmf_rpc_listener_ctx_free(ctx);
9234becb0d1SBoris Glimcher 		return;
9244becb0d1SBoris Glimcher 	}
9257662387cSKrzysztof Karas 	ctx->opts.secure_channel = ctx->listener_opts.secure_channel;
926a54a6a26SSeth Howell 
927ecbceb22SMarcin Spiewak 	if (ctx->ana_state_str) {
928ecbceb22SMarcin Spiewak 		if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) {
929ecbceb22SMarcin Spiewak 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
930ecbceb22SMarcin Spiewak 							 "Invalid parameters");
931ecbceb22SMarcin Spiewak 			nvmf_rpc_listener_ctx_free(ctx);
932ecbceb22SMarcin Spiewak 			return;
933ecbceb22SMarcin Spiewak 		}
934ecbceb22SMarcin Spiewak 		ctx->listener_opts.ana_state = ctx->ana_state;
935ecbceb22SMarcin Spiewak 	}
936ecbceb22SMarcin Spiewak 
937248c547dSKarl Bonde Torp 	ctx->opts.sock_impl = ctx->listener_opts.sock_impl;
938248c547dSKarl Bonde Torp 
939312a9d60SBen Walker 	rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx);
9408ff8bf07SSeth Howell 	if (rc != 0) {
941a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
942a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
943a54a6a26SSeth Howell 	}
944a54a6a26SSeth Howell }
945e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_add_listener", rpc_nvmf_subsystem_add_listener,
946a54a6a26SSeth Howell 		  SPDK_RPC_RUNTIME);
947a54a6a26SSeth Howell 
948a54a6a26SSeth Howell static void
949e569a578SSeth Howell rpc_nvmf_subsystem_remove_listener(struct spdk_jsonrpc_request *request,
950a54a6a26SSeth Howell 				   const struct spdk_json_val *params)
951a54a6a26SSeth Howell {
952a54a6a26SSeth Howell 	struct nvmf_rpc_listener_ctx *ctx;
953a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
954a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
9558ff8bf07SSeth Howell 	int rc;
956a54a6a26SSeth Howell 
957a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
958a54a6a26SSeth Howell 	if (!ctx) {
959a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
960a54a6a26SSeth Howell 		return;
961a54a6a26SSeth Howell 	}
962a54a6a26SSeth Howell 
963a54a6a26SSeth Howell 	ctx->request = request;
964a54a6a26SSeth Howell 
965a54a6a26SSeth Howell 	if (spdk_json_decode_object(params, nvmf_rpc_listener_decoder,
966a54a6a26SSeth Howell 				    SPDK_COUNTOF(nvmf_rpc_listener_decoder),
967a54a6a26SSeth Howell 				    ctx)) {
968a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
969a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
970a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
971a54a6a26SSeth Howell 		return;
972a54a6a26SSeth Howell 	}
973a54a6a26SSeth Howell 
974f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
975a54a6a26SSeth Howell 	if (!tgt) {
976a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
977a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
978a54a6a26SSeth Howell 						 "Unable to find a target.");
979a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
980a54a6a26SSeth Howell 		return;
981a54a6a26SSeth Howell 	}
982a54a6a26SSeth Howell 	ctx->tgt = tgt;
983a54a6a26SSeth Howell 
984a54a6a26SSeth Howell 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
985a54a6a26SSeth Howell 	if (!subsystem) {
986a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
987a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
988a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
989a54a6a26SSeth Howell 		return;
990a54a6a26SSeth Howell 	}
991a54a6a26SSeth Howell 
992a54a6a26SSeth Howell 	ctx->subsystem = subsystem;
993a54a6a26SSeth Howell 
994a54a6a26SSeth Howell 	if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
995a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
996a54a6a26SSeth Howell 						 "Invalid parameters");
997a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
998a54a6a26SSeth Howell 		return;
999a54a6a26SSeth Howell 	}
1000a54a6a26SSeth Howell 
1001d1b0d2cbSSeth Howell 	ctx->transport = spdk_nvmf_tgt_get_transport(tgt, ctx->trid.trstring);
1002d1b0d2cbSSeth Howell 	if (!ctx->transport) {
1003de8ac98bSJacek Kalwas 		SPDK_ERRLOG("Unable to find %s transport. The transport must be created first also make sure it is properly registered.\n",
1004de8ac98bSJacek Kalwas 			    ctx->trid.trstring);
1005d1b0d2cbSSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1006d1b0d2cbSSeth Howell 						 "Invalid parameters");
1007d1b0d2cbSSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
1008d1b0d2cbSSeth Howell 		return;
1009d1b0d2cbSSeth Howell 	}
1010d1b0d2cbSSeth Howell 
1011a54a6a26SSeth Howell 	ctx->op = NVMF_RPC_LISTEN_REMOVE;
1012a54a6a26SSeth Howell 
1013312a9d60SBen Walker 	rc = spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx);
10148ff8bf07SSeth Howell 	if (rc != 0) {
1015a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1016a54a6a26SSeth Howell 		nvmf_rpc_listener_ctx_free(ctx);
1017a54a6a26SSeth Howell 	}
1018a54a6a26SSeth Howell }
1019e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_remove_listener", rpc_nvmf_subsystem_remove_listener,
1020a54a6a26SSeth Howell 		  SPDK_RPC_RUNTIME);
1021a54a6a26SSeth Howell 
1022470e8518SSlawomir Ptak struct nvmf_rpc_referral_ctx {
1023470e8518SSlawomir Ptak 	char				*tgt_name;
1024470e8518SSlawomir Ptak 	struct rpc_listen_address	address;
1025470e8518SSlawomir Ptak 	bool				secure_channel;
1026020c4e11SKonrad Sztyber 	char				*subnqn;
1027470e8518SSlawomir Ptak };
1028470e8518SSlawomir Ptak 
1029470e8518SSlawomir Ptak static const struct spdk_json_object_decoder nvmf_rpc_referral_decoder[] = {
1030470e8518SSlawomir Ptak 	{"address", offsetof(struct nvmf_rpc_referral_ctx, address), decode_rpc_listen_address},
1031470e8518SSlawomir Ptak 	{"tgt_name", offsetof(struct nvmf_rpc_referral_ctx, tgt_name), spdk_json_decode_string, true},
1032470e8518SSlawomir Ptak 	{"secure_channel", offsetof(struct nvmf_rpc_referral_ctx, secure_channel), spdk_json_decode_bool, true},
1033020c4e11SKonrad Sztyber 	{"subnqn", offsetof(struct nvmf_rpc_referral_ctx, subnqn), spdk_json_decode_string, true},
1034470e8518SSlawomir Ptak };
1035470e8518SSlawomir Ptak 
1036470e8518SSlawomir Ptak static void
1037470e8518SSlawomir Ptak nvmf_rpc_referral_ctx_free(struct nvmf_rpc_referral_ctx *ctx)
1038470e8518SSlawomir Ptak {
1039470e8518SSlawomir Ptak 	free(ctx->tgt_name);
1040020c4e11SKonrad Sztyber 	free(ctx->subnqn);
1041470e8518SSlawomir Ptak 	free_rpc_listen_address(&ctx->address);
1042470e8518SSlawomir Ptak }
1043470e8518SSlawomir Ptak 
1044470e8518SSlawomir Ptak static void
1045470e8518SSlawomir Ptak rpc_nvmf_add_referral(struct spdk_jsonrpc_request *request,
1046470e8518SSlawomir Ptak 		      const struct spdk_json_val *params)
1047470e8518SSlawomir Ptak {
1048ec37689bSKonrad Sztyber 	struct nvmf_rpc_referral_ctx ctx = {};
1049bd2bd356SKonrad Sztyber 	struct spdk_nvme_transport_id trid = {};
1050470e8518SSlawomir Ptak 	struct spdk_nvmf_tgt *tgt;
1051206ace4aSKonrad Sztyber 	struct spdk_nvmf_referral_opts opts = {};
1052470e8518SSlawomir Ptak 	int rc;
1053470e8518SSlawomir Ptak 
1054470e8518SSlawomir Ptak 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_referral_decoder,
1055470e8518SSlawomir Ptak 					    SPDK_COUNTOF(nvmf_rpc_referral_decoder),
1056ec37689bSKonrad Sztyber 					    &ctx)) {
1057470e8518SSlawomir Ptak 		SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
1058470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1059ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1060470e8518SSlawomir Ptak 		return;
1061470e8518SSlawomir Ptak 	}
1062470e8518SSlawomir Ptak 
1063ec37689bSKonrad Sztyber 	tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1064470e8518SSlawomir Ptak 	if (!tgt) {
1065470e8518SSlawomir Ptak 		SPDK_ERRLOG("Unable to find a target object.\n");
1066470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1067470e8518SSlawomir Ptak 						 "Unable to find a target.");
1068ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1069470e8518SSlawomir Ptak 		return;
1070470e8518SSlawomir Ptak 	}
1071470e8518SSlawomir Ptak 
1072ec37689bSKonrad Sztyber 	if (rpc_listen_address_to_trid(&ctx.address, &trid)) {
1073bd2bd356SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1074470e8518SSlawomir Ptak 						 "Invalid parameters");
1075ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1076470e8518SSlawomir Ptak 		return;
1077470e8518SSlawomir Ptak 	}
1078470e8518SSlawomir Ptak 
1079020c4e11SKonrad Sztyber 	if (ctx.subnqn != NULL) {
1080020c4e11SKonrad Sztyber 		rc = snprintf(trid.subnqn, sizeof(trid.subnqn), "%s", ctx.subnqn);
1081020c4e11SKonrad Sztyber 		if (rc < 0 || (size_t)rc >= sizeof(trid.subnqn)) {
1082020c4e11SKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1083020c4e11SKonrad Sztyber 							 "Invalid subsystem NQN");
1084020c4e11SKonrad Sztyber 			nvmf_rpc_referral_ctx_free(&ctx);
1085020c4e11SKonrad Sztyber 			return;
1086020c4e11SKonrad Sztyber 		}
1087020c4e11SKonrad Sztyber 	}
1088020c4e11SKonrad Sztyber 
1089bd2bd356SKonrad Sztyber 	if ((trid.trtype == SPDK_NVME_TRANSPORT_TCP ||
1090bd2bd356SKonrad Sztyber 	     trid.trtype == SPDK_NVME_TRANSPORT_RDMA) &&
1091bd2bd356SKonrad Sztyber 	    !strlen(trid.trsvcid)) {
1092470e8518SSlawomir Ptak 		SPDK_ERRLOG("Service ID is required.\n");
1093470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1094470e8518SSlawomir Ptak 						 "Service ID is required.");
1095ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1096470e8518SSlawomir Ptak 		return;
1097470e8518SSlawomir Ptak 	}
1098470e8518SSlawomir Ptak 
1099206ace4aSKonrad Sztyber 	opts.size = SPDK_SIZEOF(&opts, secure_channel);
1100206ace4aSKonrad Sztyber 	opts.trid = trid;
1101206ace4aSKonrad Sztyber 	opts.secure_channel = ctx.secure_channel;
1102206ace4aSKonrad Sztyber 
1103206ace4aSKonrad Sztyber 	rc = spdk_nvmf_tgt_add_referral(tgt, &opts);
1104470e8518SSlawomir Ptak 	if (rc != 0) {
1105470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1106470e8518SSlawomir Ptak 						 "Internal error");
1107ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1108470e8518SSlawomir Ptak 		return;
1109470e8518SSlawomir Ptak 	}
1110470e8518SSlawomir Ptak 
1111ec37689bSKonrad Sztyber 	nvmf_rpc_referral_ctx_free(&ctx);
1112470e8518SSlawomir Ptak 
1113470e8518SSlawomir Ptak 	spdk_jsonrpc_send_bool_response(request, true);
1114470e8518SSlawomir Ptak }
1115470e8518SSlawomir Ptak 
1116470e8518SSlawomir Ptak SPDK_RPC_REGISTER("nvmf_discovery_add_referral", rpc_nvmf_add_referral,
1117470e8518SSlawomir Ptak 		  SPDK_RPC_RUNTIME);
1118470e8518SSlawomir Ptak 
1119470e8518SSlawomir Ptak static void
1120470e8518SSlawomir Ptak rpc_nvmf_remove_referral(struct spdk_jsonrpc_request *request,
1121470e8518SSlawomir Ptak 			 const struct spdk_json_val *params)
1122470e8518SSlawomir Ptak {
1123ec37689bSKonrad Sztyber 	struct nvmf_rpc_referral_ctx ctx = {};
1124bd2bd356SKonrad Sztyber 	struct spdk_nvme_transport_id trid = {};
1125206ace4aSKonrad Sztyber 	struct spdk_nvmf_referral_opts opts = {};
1126470e8518SSlawomir Ptak 	struct spdk_nvmf_tgt *tgt;
1127020c4e11SKonrad Sztyber 	int rc;
1128470e8518SSlawomir Ptak 
1129470e8518SSlawomir Ptak 	if (spdk_json_decode_object(params, nvmf_rpc_referral_decoder,
1130470e8518SSlawomir Ptak 				    SPDK_COUNTOF(nvmf_rpc_referral_decoder),
1131ec37689bSKonrad Sztyber 				    &ctx)) {
1132470e8518SSlawomir Ptak 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1133470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1134ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1135470e8518SSlawomir Ptak 		return;
1136470e8518SSlawomir Ptak 	}
1137470e8518SSlawomir Ptak 
1138ec37689bSKonrad Sztyber 	tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
1139470e8518SSlawomir Ptak 	if (!tgt) {
1140470e8518SSlawomir Ptak 		SPDK_ERRLOG("Unable to find a target object.\n");
1141470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1142470e8518SSlawomir Ptak 						 "Unable to find a target.");
1143ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1144470e8518SSlawomir Ptak 		return;
1145470e8518SSlawomir Ptak 	}
1146470e8518SSlawomir Ptak 
1147ec37689bSKonrad Sztyber 	if (rpc_listen_address_to_trid(&ctx.address, &trid)) {
1148bd2bd356SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1149470e8518SSlawomir Ptak 						 "Invalid parameters");
1150ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1151470e8518SSlawomir Ptak 		return;
1152470e8518SSlawomir Ptak 	}
1153470e8518SSlawomir Ptak 
1154020c4e11SKonrad Sztyber 	if (ctx.subnqn != NULL) {
1155020c4e11SKonrad Sztyber 		rc = snprintf(trid.subnqn, sizeof(trid.subnqn), "%s", ctx.subnqn);
1156020c4e11SKonrad Sztyber 		if (rc < 0 || (size_t)rc >= sizeof(trid.subnqn)) {
1157020c4e11SKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1158020c4e11SKonrad Sztyber 							 "Invalid subsystem NQN");
1159020c4e11SKonrad Sztyber 			nvmf_rpc_referral_ctx_free(&ctx);
1160020c4e11SKonrad Sztyber 			return;
1161020c4e11SKonrad Sztyber 		}
1162020c4e11SKonrad Sztyber 	}
1163020c4e11SKonrad Sztyber 
1164206ace4aSKonrad Sztyber 	opts.size = SPDK_SIZEOF(&opts, secure_channel);
1165206ace4aSKonrad Sztyber 	opts.trid = trid;
1166206ace4aSKonrad Sztyber 
1167206ace4aSKonrad Sztyber 	if (spdk_nvmf_tgt_remove_referral(tgt, &opts)) {
1168470e8518SSlawomir Ptak 		SPDK_ERRLOG("Failed to remove referral.\n");
1169470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1170470e8518SSlawomir Ptak 						 "Unable to remove a referral.");
1171ec37689bSKonrad Sztyber 		nvmf_rpc_referral_ctx_free(&ctx);
1172470e8518SSlawomir Ptak 		return;
1173470e8518SSlawomir Ptak 	}
1174470e8518SSlawomir Ptak 
1175ec37689bSKonrad Sztyber 	nvmf_rpc_referral_ctx_free(&ctx);
1176470e8518SSlawomir Ptak 
1177470e8518SSlawomir Ptak 	spdk_jsonrpc_send_bool_response(request, true);
1178470e8518SSlawomir Ptak }
1179470e8518SSlawomir Ptak 
1180470e8518SSlawomir Ptak SPDK_RPC_REGISTER("nvmf_discovery_remove_referral", rpc_nvmf_remove_referral,
1181470e8518SSlawomir Ptak 		  SPDK_RPC_RUNTIME);
1182470e8518SSlawomir Ptak 
1183470e8518SSlawomir Ptak static void
1184470e8518SSlawomir Ptak dump_nvmf_referral(struct spdk_json_write_ctx *w,
1185470e8518SSlawomir Ptak 		   struct spdk_nvmf_referral *referral)
1186470e8518SSlawomir Ptak {
1187470e8518SSlawomir Ptak 	spdk_json_write_object_begin(w);
1188470e8518SSlawomir Ptak 
1189470e8518SSlawomir Ptak 	spdk_json_write_named_object_begin(w, "address");
1190470e8518SSlawomir Ptak 	nvmf_transport_listen_dump_trid(&referral->trid, w);
1191470e8518SSlawomir Ptak 	spdk_json_write_object_end(w);
1192470e8518SSlawomir Ptak 	spdk_json_write_named_bool(w, "secure_channel",
1193470e8518SSlawomir Ptak 				   referral->entry.treq.secure_channel == SPDK_NVMF_TREQ_SECURE_CHANNEL_REQUIRED);
1194020c4e11SKonrad Sztyber 	spdk_json_write_named_string(w, "subnqn", referral->trid.subnqn);
1195470e8518SSlawomir Ptak 
1196470e8518SSlawomir Ptak 	spdk_json_write_object_end(w);
1197470e8518SSlawomir Ptak }
1198470e8518SSlawomir Ptak 
1199470e8518SSlawomir Ptak struct rpc_get_referrals_ctx {
1200470e8518SSlawomir Ptak 	char *tgt_name;
1201470e8518SSlawomir Ptak };
1202470e8518SSlawomir Ptak 
1203470e8518SSlawomir Ptak static const struct spdk_json_object_decoder rpc_get_referrals_decoders[] = {
1204470e8518SSlawomir Ptak 	{"tgt_name", offsetof(struct rpc_get_referrals_ctx, tgt_name), spdk_json_decode_string, true},
1205470e8518SSlawomir Ptak };
1206470e8518SSlawomir Ptak 
1207470e8518SSlawomir Ptak static void
1208470e8518SSlawomir Ptak free_rpc_get_referrals_ctx(struct rpc_get_referrals_ctx *ctx)
1209470e8518SSlawomir Ptak {
1210470e8518SSlawomir Ptak 	free(ctx->tgt_name);
1211470e8518SSlawomir Ptak 	free(ctx);
1212470e8518SSlawomir Ptak }
1213470e8518SSlawomir Ptak 
1214470e8518SSlawomir Ptak static void
1215470e8518SSlawomir Ptak rpc_nvmf_get_referrals(struct spdk_jsonrpc_request *request,
1216470e8518SSlawomir Ptak 		       const struct spdk_json_val *params)
1217470e8518SSlawomir Ptak {
1218470e8518SSlawomir Ptak 	struct rpc_get_referrals_ctx *ctx;
1219470e8518SSlawomir Ptak 	struct spdk_nvmf_tgt *tgt;
1220470e8518SSlawomir Ptak 	struct spdk_json_write_ctx *w;
1221470e8518SSlawomir Ptak 	struct spdk_nvmf_referral *referral;
1222470e8518SSlawomir Ptak 
1223470e8518SSlawomir Ptak 	ctx = calloc(1, sizeof(*ctx));
1224470e8518SSlawomir Ptak 	if (!ctx) {
1225470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1226470e8518SSlawomir Ptak 						 "Out of memory");
1227470e8518SSlawomir Ptak 		return;
1228470e8518SSlawomir Ptak 	}
1229470e8518SSlawomir Ptak 
1230470e8518SSlawomir Ptak 	if (params) {
1231470e8518SSlawomir Ptak 		if (spdk_json_decode_object(params, rpc_get_referrals_decoders,
1232470e8518SSlawomir Ptak 					    SPDK_COUNTOF(rpc_get_referrals_decoders),
1233470e8518SSlawomir Ptak 					    ctx)) {
1234470e8518SSlawomir Ptak 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
1235470e8518SSlawomir Ptak 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1236470e8518SSlawomir Ptak 							 "Invalid parameters");
1237470e8518SSlawomir Ptak 			free_rpc_get_referrals_ctx(ctx);
1238470e8518SSlawomir Ptak 			return;
1239470e8518SSlawomir Ptak 		}
1240470e8518SSlawomir Ptak 	}
1241470e8518SSlawomir Ptak 
1242470e8518SSlawomir Ptak 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1243470e8518SSlawomir Ptak 	if (!tgt) {
1244470e8518SSlawomir Ptak 		SPDK_ERRLOG("Unable to find a target object.\n");
1245470e8518SSlawomir Ptak 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1246470e8518SSlawomir Ptak 						 "Unable to find a target");
1247470e8518SSlawomir Ptak 		free_rpc_get_referrals_ctx(ctx);
1248470e8518SSlawomir Ptak 		return;
1249470e8518SSlawomir Ptak 	}
1250470e8518SSlawomir Ptak 
1251470e8518SSlawomir Ptak 	w = spdk_jsonrpc_begin_result(request);
1252470e8518SSlawomir Ptak 
1253470e8518SSlawomir Ptak 	spdk_json_write_array_begin(w);
1254470e8518SSlawomir Ptak 
1255470e8518SSlawomir Ptak 	TAILQ_FOREACH(referral, &tgt->referrals, link) {
1256470e8518SSlawomir Ptak 		dump_nvmf_referral(w, referral);
1257470e8518SSlawomir Ptak 	}
1258470e8518SSlawomir Ptak 
1259470e8518SSlawomir Ptak 	spdk_json_write_array_end(w);
1260470e8518SSlawomir Ptak 
1261470e8518SSlawomir Ptak 	spdk_jsonrpc_end_result(request, w);
1262470e8518SSlawomir Ptak 
1263470e8518SSlawomir Ptak 	free_rpc_get_referrals_ctx(ctx);
1264470e8518SSlawomir Ptak }
1265470e8518SSlawomir Ptak SPDK_RPC_REGISTER("nvmf_discovery_get_referrals", rpc_nvmf_get_referrals,
1266470e8518SSlawomir Ptak 		  SPDK_RPC_RUNTIME);
1267470e8518SSlawomir Ptak 
1268c8cb51d4SShuhei Matsumoto static const struct spdk_json_object_decoder nvmf_rpc_set_ana_state_decoder[] = {
1269c8cb51d4SShuhei Matsumoto 	{"nqn", offsetof(struct nvmf_rpc_listener_ctx, nqn), spdk_json_decode_string},
1270c8cb51d4SShuhei Matsumoto 	{"listen_address", offsetof(struct nvmf_rpc_listener_ctx, address), decode_rpc_listen_address},
1271c8cb51d4SShuhei Matsumoto 	{"ana_state", offsetof(struct nvmf_rpc_listener_ctx, ana_state_str), spdk_json_decode_string},
1272c8cb51d4SShuhei Matsumoto 	{"tgt_name", offsetof(struct nvmf_rpc_listener_ctx, tgt_name), spdk_json_decode_string, true},
12736d716c47SShuhei Matsumoto 	{"anagrpid", offsetof(struct nvmf_rpc_listener_ctx, anagrpid), spdk_json_decode_uint32, true},
1274c8cb51d4SShuhei Matsumoto };
1275c8cb51d4SShuhei Matsumoto 
1276c8cb51d4SShuhei Matsumoto static int
1277c8cb51d4SShuhei Matsumoto rpc_ana_state_parse(const char *str, enum spdk_nvme_ana_state *ana_state)
1278c8cb51d4SShuhei Matsumoto {
1279c8cb51d4SShuhei Matsumoto 	if (ana_state == NULL || str == NULL) {
1280c8cb51d4SShuhei Matsumoto 		return -EINVAL;
1281c8cb51d4SShuhei Matsumoto 	}
1282c8cb51d4SShuhei Matsumoto 
1283c8cb51d4SShuhei Matsumoto 	if (strcasecmp(str, "optimized") == 0) {
1284c8cb51d4SShuhei Matsumoto 		*ana_state = SPDK_NVME_ANA_OPTIMIZED_STATE;
1285c8cb51d4SShuhei Matsumoto 	} else if (strcasecmp(str, "non_optimized") == 0) {
1286c8cb51d4SShuhei Matsumoto 		*ana_state = SPDK_NVME_ANA_NON_OPTIMIZED_STATE;
1287c8cb51d4SShuhei Matsumoto 	} else if (strcasecmp(str, "inaccessible") == 0) {
1288c8cb51d4SShuhei Matsumoto 		*ana_state = SPDK_NVME_ANA_INACCESSIBLE_STATE;
1289c8cb51d4SShuhei Matsumoto 	} else {
1290c8cb51d4SShuhei Matsumoto 		return -ENOENT;
1291c8cb51d4SShuhei Matsumoto 	}
1292c8cb51d4SShuhei Matsumoto 
1293c8cb51d4SShuhei Matsumoto 	return 0;
1294c8cb51d4SShuhei Matsumoto }
1295c8cb51d4SShuhei Matsumoto 
1296c8cb51d4SShuhei Matsumoto static void
1297c8cb51d4SShuhei Matsumoto rpc_nvmf_subsystem_listener_set_ana_state(struct spdk_jsonrpc_request *request,
1298c8cb51d4SShuhei Matsumoto 		const struct spdk_json_val *params)
1299c8cb51d4SShuhei Matsumoto {
1300c8cb51d4SShuhei Matsumoto 	struct nvmf_rpc_listener_ctx *ctx;
1301c8cb51d4SShuhei Matsumoto 	struct spdk_nvmf_subsystem *subsystem;
1302c8cb51d4SShuhei Matsumoto 	struct spdk_nvmf_tgt *tgt;
1303c8cb51d4SShuhei Matsumoto 
1304c8cb51d4SShuhei Matsumoto 	ctx = calloc(1, sizeof(*ctx));
1305c8cb51d4SShuhei Matsumoto 	if (!ctx) {
1306c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1307c8cb51d4SShuhei Matsumoto 						 "Out of memory");
1308c8cb51d4SShuhei Matsumoto 		return;
1309c8cb51d4SShuhei Matsumoto 	}
1310c8cb51d4SShuhei Matsumoto 
1311c8cb51d4SShuhei Matsumoto 	ctx->request = request;
1312c8cb51d4SShuhei Matsumoto 
1313c8cb51d4SShuhei Matsumoto 	if (spdk_json_decode_object(params, nvmf_rpc_set_ana_state_decoder,
1314c8cb51d4SShuhei Matsumoto 				    SPDK_COUNTOF(nvmf_rpc_set_ana_state_decoder),
1315c8cb51d4SShuhei Matsumoto 				    ctx)) {
1316c8cb51d4SShuhei Matsumoto 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1317c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1318c8cb51d4SShuhei Matsumoto 						 "Invalid parameters");
1319c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1320c8cb51d4SShuhei Matsumoto 		return;
1321c8cb51d4SShuhei Matsumoto 	}
1322c8cb51d4SShuhei Matsumoto 
1323c8cb51d4SShuhei Matsumoto 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1324c8cb51d4SShuhei Matsumoto 	if (!tgt) {
1325c8cb51d4SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find a target object.\n");
1326c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
13279b143bcaSPierre Lestringant 						 "Unable to find a target.");
1328c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1329c8cb51d4SShuhei Matsumoto 		return;
1330c8cb51d4SShuhei Matsumoto 	}
1331c8cb51d4SShuhei Matsumoto 
1332c8cb51d4SShuhei Matsumoto 	ctx->tgt = tgt;
1333c8cb51d4SShuhei Matsumoto 
1334c8cb51d4SShuhei Matsumoto 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1335c8cb51d4SShuhei Matsumoto 	if (!subsystem) {
1336c8cb51d4SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1337c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1338c8cb51d4SShuhei Matsumoto 						     "Unable to find subsystem with NQN %s",
1339c8cb51d4SShuhei Matsumoto 						     ctx->nqn);
1340c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1341c8cb51d4SShuhei Matsumoto 		return;
1342c8cb51d4SShuhei Matsumoto 	}
1343c8cb51d4SShuhei Matsumoto 
1344c8cb51d4SShuhei Matsumoto 	ctx->subsystem = subsystem;
1345c8cb51d4SShuhei Matsumoto 
1346c8cb51d4SShuhei Matsumoto 	if (rpc_listen_address_to_trid(&ctx->address, &ctx->trid)) {
1347c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1348c8cb51d4SShuhei Matsumoto 						 "Invalid parameters");
1349c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1350c8cb51d4SShuhei Matsumoto 		return;
1351c8cb51d4SShuhei Matsumoto 	}
1352c8cb51d4SShuhei Matsumoto 
1353c8cb51d4SShuhei Matsumoto 	if (rpc_ana_state_parse(ctx->ana_state_str, &ctx->ana_state)) {
1354c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1355c8cb51d4SShuhei Matsumoto 						 "Invalid parameters");
1356c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1357c8cb51d4SShuhei Matsumoto 		return;
1358c8cb51d4SShuhei Matsumoto 	}
1359c8cb51d4SShuhei Matsumoto 
1360c8cb51d4SShuhei Matsumoto 	ctx->op = NVMF_RPC_LISTEN_SET_ANA_STATE;
1361c8cb51d4SShuhei Matsumoto 
1362312a9d60SBen Walker 	if (spdk_nvmf_subsystem_pause(subsystem, 0, nvmf_rpc_listen_paused, ctx)) {
1363c8cb51d4SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1364c8cb51d4SShuhei Matsumoto 						 "Internal error");
1365c8cb51d4SShuhei Matsumoto 		nvmf_rpc_listener_ctx_free(ctx);
1366c8cb51d4SShuhei Matsumoto 	}
1367c8cb51d4SShuhei Matsumoto }
1368c8cb51d4SShuhei Matsumoto SPDK_RPC_REGISTER("nvmf_subsystem_listener_set_ana_state",
1369c8cb51d4SShuhei Matsumoto 		  rpc_nvmf_subsystem_listener_set_ana_state, SPDK_RPC_RUNTIME);
1370c8cb51d4SShuhei Matsumoto 
1371aafada11SJacek Kalwas struct nvmf_rpc_ns_params {
1372a54a6a26SSeth Howell 	char *bdev_name;
1373a54a6a26SSeth Howell 	char *ptpl_file;
1374a54a6a26SSeth Howell 	uint32_t nsid;
1375a54a6a26SSeth Howell 	char nguid[16];
1376a54a6a26SSeth Howell 	char eui64[8];
1377a54a6a26SSeth Howell 	struct spdk_uuid uuid;
1378694fa34dSShuhei Matsumoto 	uint32_t anagrpid;
1379d37555b4SJonas Pfefferle 	bool no_auto_visible;
1380afdec00eSShuhei Matsumoto 	bool hide_metadata;
1381a54a6a26SSeth Howell };
1382a54a6a26SSeth Howell 
1383a54a6a26SSeth Howell static const struct spdk_json_object_decoder rpc_ns_params_decoders[] = {
1384aafada11SJacek Kalwas 	{"nsid", offsetof(struct nvmf_rpc_ns_params, nsid), spdk_json_decode_uint32, true},
1385aafada11SJacek Kalwas 	{"bdev_name", offsetof(struct nvmf_rpc_ns_params, bdev_name), spdk_json_decode_string},
1386aafada11SJacek Kalwas 	{"ptpl_file", offsetof(struct nvmf_rpc_ns_params, ptpl_file), spdk_json_decode_string, true},
1387aafada11SJacek Kalwas 	{"nguid", offsetof(struct nvmf_rpc_ns_params, nguid), decode_ns_nguid, true},
1388aafada11SJacek Kalwas 	{"eui64", offsetof(struct nvmf_rpc_ns_params, eui64), decode_ns_eui64, true},
1389aafada11SJacek Kalwas 	{"uuid", offsetof(struct nvmf_rpc_ns_params, uuid), spdk_json_decode_uuid, true},
1390aafada11SJacek Kalwas 	{"anagrpid", offsetof(struct nvmf_rpc_ns_params, anagrpid), spdk_json_decode_uint32, true},
1391d37555b4SJonas Pfefferle 	{"no_auto_visible", offsetof(struct nvmf_rpc_ns_params, no_auto_visible), spdk_json_decode_bool, true},
1392afdec00eSShuhei Matsumoto 	{"hide_metadata", offsetof(struct nvmf_rpc_ns_params, hide_metadata), spdk_json_decode_bool, true},
1393a54a6a26SSeth Howell };
1394a54a6a26SSeth Howell 
1395a54a6a26SSeth Howell static int
1396a54a6a26SSeth Howell decode_rpc_ns_params(const struct spdk_json_val *val, void *out)
1397a54a6a26SSeth Howell {
1398aafada11SJacek Kalwas 	struct nvmf_rpc_ns_params *ns_params = out;
1399a54a6a26SSeth Howell 
1400a54a6a26SSeth Howell 	return spdk_json_decode_object(val, rpc_ns_params_decoders,
1401a54a6a26SSeth Howell 				       SPDK_COUNTOF(rpc_ns_params_decoders),
1402a54a6a26SSeth Howell 				       ns_params);
1403a54a6a26SSeth Howell }
1404a54a6a26SSeth Howell 
1405a54a6a26SSeth Howell struct nvmf_rpc_ns_ctx {
1406a54a6a26SSeth Howell 	char *nqn;
1407f8433aadSSeth Howell 	char *tgt_name;
1408aafada11SJacek Kalwas 	struct nvmf_rpc_ns_params ns_params;
1409a54a6a26SSeth Howell 
1410a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request;
14115e952d84SJacek Kalwas 	const struct spdk_json_val *params;
1412a54a6a26SSeth Howell 	bool response_sent;
1413a54a6a26SSeth Howell };
1414a54a6a26SSeth Howell 
1415a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ns_decoder[] = {
1416a54a6a26SSeth Howell 	{"nqn", offsetof(struct nvmf_rpc_ns_ctx, nqn), spdk_json_decode_string},
1417a54a6a26SSeth Howell 	{"namespace", offsetof(struct nvmf_rpc_ns_ctx, ns_params), decode_rpc_ns_params},
1418f8433aadSSeth Howell 	{"tgt_name", offsetof(struct nvmf_rpc_ns_ctx, tgt_name), spdk_json_decode_string, true},
1419a54a6a26SSeth Howell };
1420a54a6a26SSeth Howell 
1421a54a6a26SSeth Howell static void
1422a54a6a26SSeth Howell nvmf_rpc_ns_ctx_free(struct nvmf_rpc_ns_ctx *ctx)
1423a54a6a26SSeth Howell {
1424a54a6a26SSeth Howell 	free(ctx->nqn);
1425f8433aadSSeth Howell 	free(ctx->tgt_name);
1426a54a6a26SSeth Howell 	free(ctx->ns_params.bdev_name);
1427a54a6a26SSeth Howell 	free(ctx->ns_params.ptpl_file);
1428a54a6a26SSeth Howell 	free(ctx);
1429a54a6a26SSeth Howell }
1430a54a6a26SSeth Howell 
1431a54a6a26SSeth Howell static void
14321b249c38SSeth Howell nvmf_rpc_ns_failback_resumed(struct spdk_nvmf_subsystem *subsystem,
14331b249c38SSeth Howell 			     void *cb_arg, int status)
14341b249c38SSeth Howell {
14351b249c38SSeth Howell 	struct nvmf_rpc_ns_ctx *ctx = cb_arg;
14361b249c38SSeth Howell 	struct spdk_jsonrpc_request *request = ctx->request;
14371b249c38SSeth Howell 
14381b249c38SSeth Howell 	if (status) {
14391b249c38SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
14401b249c38SSeth Howell 						 "Unable to add ns, subsystem in invalid state");
14411b249c38SSeth Howell 	} else {
14421b249c38SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
14431b249c38SSeth Howell 						 "Unable to add ns, subsystem in active state");
14441b249c38SSeth Howell 	}
14451b249c38SSeth Howell 
14461b249c38SSeth Howell 	nvmf_rpc_ns_ctx_free(ctx);
14471b249c38SSeth Howell }
14481b249c38SSeth Howell 
14491b249c38SSeth Howell static void
1450a54a6a26SSeth Howell nvmf_rpc_ns_resumed(struct spdk_nvmf_subsystem *subsystem,
1451a54a6a26SSeth Howell 		    void *cb_arg, int status)
1452a54a6a26SSeth Howell {
1453a54a6a26SSeth Howell 	struct nvmf_rpc_ns_ctx *ctx = cb_arg;
1454a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request = ctx->request;
1455a54a6a26SSeth Howell 	uint32_t nsid = ctx->ns_params.nsid;
1456a54a6a26SSeth Howell 	bool response_sent = ctx->response_sent;
1457a54a6a26SSeth Howell 	struct spdk_json_write_ctx *w;
14581b249c38SSeth Howell 	int rc;
14591b249c38SSeth Howell 
14601b249c38SSeth Howell 	/* The case where the call to add the namespace was successful, but the subsystem couldn't be resumed. */
14611b249c38SSeth Howell 	if (status && !ctx->response_sent) {
14621b249c38SSeth Howell 		rc = spdk_nvmf_subsystem_remove_ns(subsystem, nsid);
14631b249c38SSeth Howell 		if (rc != 0) {
14641b249c38SSeth Howell 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
14651b249c38SSeth Howell 							 "Unable to add ns, subsystem in invalid state");
14661b249c38SSeth Howell 			nvmf_rpc_ns_ctx_free(ctx);
14671b249c38SSeth Howell 			return;
14681b249c38SSeth Howell 		}
14691b249c38SSeth Howell 
14701b249c38SSeth Howell 		rc = spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_failback_resumed, ctx);
14711b249c38SSeth Howell 		if (rc != 0) {
14721b249c38SSeth Howell 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
14731b249c38SSeth Howell 			nvmf_rpc_ns_ctx_free(ctx);
14741b249c38SSeth Howell 			return;
14751b249c38SSeth Howell 		}
14761b249c38SSeth Howell 
14771b249c38SSeth Howell 		return;
14781b249c38SSeth Howell 	}
1479a54a6a26SSeth Howell 
1480a54a6a26SSeth Howell 	nvmf_rpc_ns_ctx_free(ctx);
1481a54a6a26SSeth Howell 
1482a54a6a26SSeth Howell 	if (response_sent) {
1483a54a6a26SSeth Howell 		return;
1484a54a6a26SSeth Howell 	}
1485a54a6a26SSeth Howell 
1486a54a6a26SSeth Howell 	w = spdk_jsonrpc_begin_result(request);
1487a54a6a26SSeth Howell 	spdk_json_write_uint32(w, nsid);
1488a54a6a26SSeth Howell 	spdk_jsonrpc_end_result(request, w);
1489a54a6a26SSeth Howell }
1490a54a6a26SSeth Howell 
1491a54a6a26SSeth Howell static void
1492a54a6a26SSeth Howell nvmf_rpc_ns_paused(struct spdk_nvmf_subsystem *subsystem,
1493a54a6a26SSeth Howell 		   void *cb_arg, int status)
1494a54a6a26SSeth Howell {
1495a54a6a26SSeth Howell 	struct nvmf_rpc_ns_ctx *ctx = cb_arg;
1496a54a6a26SSeth Howell 	struct spdk_nvmf_ns_opts ns_opts;
1497a54a6a26SSeth Howell 
1498a54a6a26SSeth Howell 	spdk_nvmf_ns_opts_get_defaults(&ns_opts, sizeof(ns_opts));
1499a54a6a26SSeth Howell 	ns_opts.nsid = ctx->ns_params.nsid;
15005e952d84SJacek Kalwas 	ns_opts.transport_specific = ctx->params;
1501a54a6a26SSeth Howell 
1502a54a6a26SSeth Howell 	SPDK_STATIC_ASSERT(sizeof(ns_opts.nguid) == sizeof(ctx->ns_params.nguid), "size mismatch");
1503a54a6a26SSeth Howell 	memcpy(ns_opts.nguid, ctx->ns_params.nguid, sizeof(ns_opts.nguid));
1504a54a6a26SSeth Howell 
1505a54a6a26SSeth Howell 	SPDK_STATIC_ASSERT(sizeof(ns_opts.eui64) == sizeof(ctx->ns_params.eui64), "size mismatch");
1506a54a6a26SSeth Howell 	memcpy(ns_opts.eui64, ctx->ns_params.eui64, sizeof(ns_opts.eui64));
1507a54a6a26SSeth Howell 
150895a367d6SArtur Paszkiewicz 	if (!spdk_uuid_is_null(&ctx->ns_params.uuid)) {
1509a54a6a26SSeth Howell 		ns_opts.uuid = ctx->ns_params.uuid;
1510a54a6a26SSeth Howell 	}
1511a54a6a26SSeth Howell 
1512694fa34dSShuhei Matsumoto 	ns_opts.anagrpid = ctx->ns_params.anagrpid;
1513d37555b4SJonas Pfefferle 	ns_opts.no_auto_visible = ctx->ns_params.no_auto_visible;
1514afdec00eSShuhei Matsumoto 	ns_opts.hide_metadata = ctx->ns_params.hide_metadata;
1515694fa34dSShuhei Matsumoto 
1516a22d8a53SShuhei Matsumoto 	ctx->ns_params.nsid = spdk_nvmf_subsystem_add_ns_ext(subsystem, ctx->ns_params.bdev_name,
1517a22d8a53SShuhei Matsumoto 			      &ns_opts, sizeof(ns_opts),
1518a54a6a26SSeth Howell 			      ctx->ns_params.ptpl_file);
1519a54a6a26SSeth Howell 	if (ctx->ns_params.nsid == 0) {
1520a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to add namespace\n");
1521a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1522a54a6a26SSeth Howell 						 "Invalid parameters");
1523a54a6a26SSeth Howell 		ctx->response_sent = true;
1524a54a6a26SSeth Howell 		goto resume;
1525a54a6a26SSeth Howell 	}
1526a54a6a26SSeth Howell 
1527a54a6a26SSeth Howell resume:
1528a54a6a26SSeth Howell 	if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_resumed, ctx)) {
1529a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1530a54a6a26SSeth Howell 		nvmf_rpc_ns_ctx_free(ctx);
1531a54a6a26SSeth Howell 	}
1532a54a6a26SSeth Howell }
1533a54a6a26SSeth Howell 
1534a54a6a26SSeth Howell static void
1535e569a578SSeth Howell rpc_nvmf_subsystem_add_ns(struct spdk_jsonrpc_request *request,
1536a54a6a26SSeth Howell 			  const struct spdk_json_val *params)
1537a54a6a26SSeth Howell {
1538a54a6a26SSeth Howell 	struct nvmf_rpc_ns_ctx *ctx;
1539a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
1540a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
15418ff8bf07SSeth Howell 	int rc;
1542a54a6a26SSeth Howell 
1543a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
1544a54a6a26SSeth Howell 	if (!ctx) {
1545a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1546a54a6a26SSeth Howell 		return;
1547a54a6a26SSeth Howell 	}
1548a54a6a26SSeth Howell 
15495e952d84SJacek Kalwas 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_subsystem_ns_decoder,
15505e952d84SJacek Kalwas 					    SPDK_COUNTOF(nvmf_rpc_subsystem_ns_decoder), ctx)) {
1551a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1552a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1553a54a6a26SSeth Howell 		nvmf_rpc_ns_ctx_free(ctx);
1554a54a6a26SSeth Howell 		return;
1555a54a6a26SSeth Howell 	}
1556a54a6a26SSeth Howell 
1557a54a6a26SSeth Howell 	ctx->request = request;
15585e952d84SJacek Kalwas 	ctx->params = params;
1559a54a6a26SSeth Howell 	ctx->response_sent = false;
1560a54a6a26SSeth Howell 
1561f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1562a54a6a26SSeth Howell 	if (!tgt) {
1563a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
1564a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1565a54a6a26SSeth Howell 						 "Unable to find a target.");
1566a54a6a26SSeth Howell 		nvmf_rpc_ns_ctx_free(ctx);
1567a54a6a26SSeth Howell 		return;
1568a54a6a26SSeth Howell 	}
1569a54a6a26SSeth Howell 
1570a54a6a26SSeth Howell 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1571a54a6a26SSeth Howell 	if (!subsystem) {
1572a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1573a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1574a54a6a26SSeth Howell 		nvmf_rpc_ns_ctx_free(ctx);
1575a54a6a26SSeth Howell 		return;
1576a54a6a26SSeth Howell 	}
1577a54a6a26SSeth Howell 
1578312a9d60SBen Walker 	rc = spdk_nvmf_subsystem_pause(subsystem, ctx->ns_params.nsid, nvmf_rpc_ns_paused, ctx);
15798ff8bf07SSeth Howell 	if (rc != 0) {
1580a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1581a54a6a26SSeth Howell 		nvmf_rpc_ns_ctx_free(ctx);
1582a54a6a26SSeth Howell 	}
1583a54a6a26SSeth Howell }
1584e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_add_ns", rpc_nvmf_subsystem_add_ns, SPDK_RPC_RUNTIME)
1585a54a6a26SSeth Howell 
1586698b2423SShuhei Matsumoto struct nvmf_rpc_ana_group_ctx {
1587698b2423SShuhei Matsumoto 	char *nqn;
1588698b2423SShuhei Matsumoto 	char *tgt_name;
1589698b2423SShuhei Matsumoto 	uint32_t nsid;
1590698b2423SShuhei Matsumoto 	uint32_t anagrpid;
1591698b2423SShuhei Matsumoto 
1592698b2423SShuhei Matsumoto 	struct spdk_jsonrpc_request *request;
1593698b2423SShuhei Matsumoto 	bool response_sent;
1594698b2423SShuhei Matsumoto };
1595698b2423SShuhei Matsumoto 
1596698b2423SShuhei Matsumoto static const struct spdk_json_object_decoder nvmf_rpc_subsystem_ana_group_decoder[] = {
1597698b2423SShuhei Matsumoto 	{"nqn", offsetof(struct nvmf_rpc_ana_group_ctx, nqn), spdk_json_decode_string},
1598698b2423SShuhei Matsumoto 	{"nsid", offsetof(struct nvmf_rpc_ana_group_ctx, nsid), spdk_json_decode_uint32},
1599698b2423SShuhei Matsumoto 	{"anagrpid", offsetof(struct nvmf_rpc_ana_group_ctx, anagrpid), spdk_json_decode_uint32},
1600698b2423SShuhei Matsumoto 	{"tgt_name", offsetof(struct nvmf_rpc_ana_group_ctx, tgt_name), spdk_json_decode_string, true},
1601698b2423SShuhei Matsumoto };
1602698b2423SShuhei Matsumoto 
1603698b2423SShuhei Matsumoto static void
1604698b2423SShuhei Matsumoto nvmf_rpc_ana_group_ctx_free(struct nvmf_rpc_ana_group_ctx *ctx)
1605698b2423SShuhei Matsumoto {
1606698b2423SShuhei Matsumoto 	free(ctx->nqn);
1607698b2423SShuhei Matsumoto 	free(ctx->tgt_name);
1608698b2423SShuhei Matsumoto 	free(ctx);
1609698b2423SShuhei Matsumoto }
1610698b2423SShuhei Matsumoto 
1611698b2423SShuhei Matsumoto static void
1612698b2423SShuhei Matsumoto nvmf_rpc_anagrpid_resumed(struct spdk_nvmf_subsystem *subsystem,
1613698b2423SShuhei Matsumoto 			  void *cb_arg, int status)
1614698b2423SShuhei Matsumoto {
1615698b2423SShuhei Matsumoto 	struct nvmf_rpc_ana_group_ctx *ctx = cb_arg;
1616698b2423SShuhei Matsumoto 	struct spdk_jsonrpc_request *request = ctx->request;
1617698b2423SShuhei Matsumoto 	bool response_sent = ctx->response_sent;
1618698b2423SShuhei Matsumoto 
1619698b2423SShuhei Matsumoto 	nvmf_rpc_ana_group_ctx_free(ctx);
1620698b2423SShuhei Matsumoto 
1621698b2423SShuhei Matsumoto 	if (response_sent) {
1622698b2423SShuhei Matsumoto 		return;
1623698b2423SShuhei Matsumoto 	}
1624698b2423SShuhei Matsumoto 
1625698b2423SShuhei Matsumoto 	spdk_jsonrpc_send_bool_response(request, true);
1626698b2423SShuhei Matsumoto }
1627698b2423SShuhei Matsumoto 
1628698b2423SShuhei Matsumoto static void
1629698b2423SShuhei Matsumoto nvmf_rpc_ana_group(struct spdk_nvmf_subsystem *subsystem,
1630698b2423SShuhei Matsumoto 		   void *cb_arg, int status)
1631698b2423SShuhei Matsumoto {
1632698b2423SShuhei Matsumoto 	struct nvmf_rpc_ana_group_ctx *ctx = cb_arg;
1633698b2423SShuhei Matsumoto 	int rc;
1634698b2423SShuhei Matsumoto 
1635698b2423SShuhei Matsumoto 	rc = spdk_nvmf_subsystem_set_ns_ana_group(subsystem, ctx->nsid, ctx->anagrpid);
1636698b2423SShuhei Matsumoto 	if (rc != 0) {
1637698b2423SShuhei Matsumoto 		SPDK_ERRLOG("Unable to change ANA group ID\n");
1638698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1639698b2423SShuhei Matsumoto 						 "Invalid parameters");
1640698b2423SShuhei Matsumoto 		ctx->response_sent = true;
1641698b2423SShuhei Matsumoto 	}
1642698b2423SShuhei Matsumoto 
1643698b2423SShuhei Matsumoto 	if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_anagrpid_resumed, ctx)) {
1644698b2423SShuhei Matsumoto 		if (!ctx->response_sent) {
1645698b2423SShuhei Matsumoto 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1646698b2423SShuhei Matsumoto 							 "Internal error");
1647698b2423SShuhei Matsumoto 		}
1648698b2423SShuhei Matsumoto 		nvmf_rpc_ana_group_ctx_free(ctx);
1649698b2423SShuhei Matsumoto 	}
1650698b2423SShuhei Matsumoto }
1651698b2423SShuhei Matsumoto 
1652698b2423SShuhei Matsumoto static void
1653698b2423SShuhei Matsumoto rpc_nvmf_subsystem_set_ns_ana_group(struct spdk_jsonrpc_request *request,
1654698b2423SShuhei Matsumoto 				    const struct spdk_json_val *params)
1655698b2423SShuhei Matsumoto {
1656698b2423SShuhei Matsumoto 	struct nvmf_rpc_ana_group_ctx *ctx;
1657698b2423SShuhei Matsumoto 	struct spdk_nvmf_subsystem *subsystem;
1658698b2423SShuhei Matsumoto 	struct spdk_nvmf_tgt *tgt;
1659698b2423SShuhei Matsumoto 	int rc;
1660698b2423SShuhei Matsumoto 
1661698b2423SShuhei Matsumoto 	ctx = calloc(1, sizeof(*ctx));
1662698b2423SShuhei Matsumoto 	if (!ctx) {
1663698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1664698b2423SShuhei Matsumoto 		return;
1665698b2423SShuhei Matsumoto 	}
1666698b2423SShuhei Matsumoto 
1667698b2423SShuhei Matsumoto 	if (spdk_json_decode_object(params, nvmf_rpc_subsystem_ana_group_decoder,
1668698b2423SShuhei Matsumoto 				    SPDK_COUNTOF(nvmf_rpc_subsystem_ana_group_decoder), ctx)) {
1669698b2423SShuhei Matsumoto 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1670698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1671698b2423SShuhei Matsumoto 		nvmf_rpc_ana_group_ctx_free(ctx);
1672698b2423SShuhei Matsumoto 		return;
1673698b2423SShuhei Matsumoto 	}
1674698b2423SShuhei Matsumoto 
1675698b2423SShuhei Matsumoto 	ctx->request = request;
1676698b2423SShuhei Matsumoto 	ctx->response_sent = false;
1677698b2423SShuhei Matsumoto 
1678698b2423SShuhei Matsumoto 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1679698b2423SShuhei Matsumoto 	if (!tgt) {
1680698b2423SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find a target object.\n");
1681698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1682698b2423SShuhei Matsumoto 						 "Unable to find a target.");
1683698b2423SShuhei Matsumoto 		nvmf_rpc_ana_group_ctx_free(ctx);
1684698b2423SShuhei Matsumoto 		return;
1685698b2423SShuhei Matsumoto 	}
1686698b2423SShuhei Matsumoto 
1687698b2423SShuhei Matsumoto 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1688698b2423SShuhei Matsumoto 	if (!subsystem) {
1689698b2423SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1690698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1691698b2423SShuhei Matsumoto 		nvmf_rpc_ana_group_ctx_free(ctx);
1692698b2423SShuhei Matsumoto 		return;
1693698b2423SShuhei Matsumoto 	}
1694698b2423SShuhei Matsumoto 
1695698b2423SShuhei Matsumoto 	rc = spdk_nvmf_subsystem_pause(subsystem, ctx->nsid, nvmf_rpc_ana_group, ctx);
1696698b2423SShuhei Matsumoto 	if (rc != 0) {
1697698b2423SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1698698b2423SShuhei Matsumoto 		nvmf_rpc_ana_group_ctx_free(ctx);
1699698b2423SShuhei Matsumoto 	}
1700698b2423SShuhei Matsumoto }
1701698b2423SShuhei Matsumoto SPDK_RPC_REGISTER("nvmf_subsystem_set_ns_ana_group", rpc_nvmf_subsystem_set_ns_ana_group,
1702698b2423SShuhei Matsumoto 		  SPDK_RPC_RUNTIME)
1703698b2423SShuhei Matsumoto 
1704a54a6a26SSeth Howell struct nvmf_rpc_remove_ns_ctx {
1705a54a6a26SSeth Howell 	char *nqn;
1706f8433aadSSeth Howell 	char *tgt_name;
1707a54a6a26SSeth Howell 	uint32_t nsid;
1708a54a6a26SSeth Howell 
1709a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request;
1710a54a6a26SSeth Howell 	bool response_sent;
1711a54a6a26SSeth Howell };
1712a54a6a26SSeth Howell 
1713a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_subsystem_remove_ns_decoder[] = {
1714a54a6a26SSeth Howell 	{"nqn", offsetof(struct nvmf_rpc_remove_ns_ctx, nqn), spdk_json_decode_string},
1715a54a6a26SSeth Howell 	{"nsid", offsetof(struct nvmf_rpc_remove_ns_ctx, nsid), spdk_json_decode_uint32},
1716f8433aadSSeth Howell 	{"tgt_name", offsetof(struct nvmf_rpc_remove_ns_ctx, tgt_name), spdk_json_decode_string, true},
1717a54a6a26SSeth Howell };
1718a54a6a26SSeth Howell 
1719a54a6a26SSeth Howell static void
1720a54a6a26SSeth Howell nvmf_rpc_remove_ns_ctx_free(struct nvmf_rpc_remove_ns_ctx *ctx)
1721a54a6a26SSeth Howell {
1722a54a6a26SSeth Howell 	free(ctx->nqn);
1723f8433aadSSeth Howell 	free(ctx->tgt_name);
1724a54a6a26SSeth Howell 	free(ctx);
1725a54a6a26SSeth Howell }
1726a54a6a26SSeth Howell 
1727a54a6a26SSeth Howell static void
1728a54a6a26SSeth Howell nvmf_rpc_remove_ns_resumed(struct spdk_nvmf_subsystem *subsystem,
1729a54a6a26SSeth Howell 			   void *cb_arg, int status)
1730a54a6a26SSeth Howell {
1731a54a6a26SSeth Howell 	struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg;
1732a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request = ctx->request;
1733a54a6a26SSeth Howell 	bool response_sent = ctx->response_sent;
1734a54a6a26SSeth Howell 
1735a54a6a26SSeth Howell 	nvmf_rpc_remove_ns_ctx_free(ctx);
1736a54a6a26SSeth Howell 
1737a54a6a26SSeth Howell 	if (response_sent) {
1738a54a6a26SSeth Howell 		return;
1739a54a6a26SSeth Howell 	}
1740a54a6a26SSeth Howell 
1741d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
1742a54a6a26SSeth Howell }
1743a54a6a26SSeth Howell 
1744a54a6a26SSeth Howell static void
1745a54a6a26SSeth Howell nvmf_rpc_remove_ns_paused(struct spdk_nvmf_subsystem *subsystem,
1746a54a6a26SSeth Howell 			  void *cb_arg, int status)
1747a54a6a26SSeth Howell {
1748a54a6a26SSeth Howell 	struct nvmf_rpc_remove_ns_ctx *ctx = cb_arg;
1749a54a6a26SSeth Howell 	int ret;
1750a54a6a26SSeth Howell 
1751a54a6a26SSeth Howell 	ret = spdk_nvmf_subsystem_remove_ns(subsystem, ctx->nsid);
1752a54a6a26SSeth Howell 	if (ret < 0) {
1753a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to remove namespace ID %u\n", ctx->nsid);
1754a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1755a54a6a26SSeth Howell 						 "Invalid parameters");
1756a54a6a26SSeth Howell 		ctx->response_sent = true;
1757a54a6a26SSeth Howell 	}
1758a54a6a26SSeth Howell 
1759a54a6a26SSeth Howell 	if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_remove_ns_resumed, ctx)) {
1760a54a6a26SSeth Howell 		if (!ctx->response_sent) {
1761a54a6a26SSeth Howell 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1762a54a6a26SSeth Howell 		}
1763a54a6a26SSeth Howell 		nvmf_rpc_remove_ns_ctx_free(ctx);
1764a54a6a26SSeth Howell 	}
1765a54a6a26SSeth Howell }
1766a54a6a26SSeth Howell 
1767a54a6a26SSeth Howell static void
1768e569a578SSeth Howell rpc_nvmf_subsystem_remove_ns(struct spdk_jsonrpc_request *request,
1769a54a6a26SSeth Howell 			     const struct spdk_json_val *params)
1770a54a6a26SSeth Howell {
1771a54a6a26SSeth Howell 	struct nvmf_rpc_remove_ns_ctx *ctx;
1772a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
1773a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
17748ff8bf07SSeth Howell 	int rc;
1775a54a6a26SSeth Howell 
1776a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
1777a54a6a26SSeth Howell 	if (!ctx) {
1778a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1779a54a6a26SSeth Howell 		return;
1780a54a6a26SSeth Howell 	}
1781a54a6a26SSeth Howell 
1782a54a6a26SSeth Howell 	if (spdk_json_decode_object(params, nvmf_rpc_subsystem_remove_ns_decoder,
1783a54a6a26SSeth Howell 				    SPDK_COUNTOF(nvmf_rpc_subsystem_remove_ns_decoder),
1784a54a6a26SSeth Howell 				    ctx)) {
1785a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1786a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1787a54a6a26SSeth Howell 		nvmf_rpc_remove_ns_ctx_free(ctx);
1788a54a6a26SSeth Howell 		return;
1789a54a6a26SSeth Howell 	}
1790a54a6a26SSeth Howell 
1791f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1792a54a6a26SSeth Howell 	if (!tgt) {
1793a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
1794a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1795a54a6a26SSeth Howell 						 "Unable to find a target.");
1796a54a6a26SSeth Howell 		nvmf_rpc_remove_ns_ctx_free(ctx);
1797a54a6a26SSeth Howell 		return;
1798a54a6a26SSeth Howell 	}
1799a54a6a26SSeth Howell 
1800a54a6a26SSeth Howell 	ctx->request = request;
1801a54a6a26SSeth Howell 	ctx->response_sent = false;
1802a54a6a26SSeth Howell 
1803a54a6a26SSeth Howell 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1804a54a6a26SSeth Howell 	if (!subsystem) {
1805a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1806a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1807a54a6a26SSeth Howell 		nvmf_rpc_remove_ns_ctx_free(ctx);
1808a54a6a26SSeth Howell 		return;
1809a54a6a26SSeth Howell 	}
1810a54a6a26SSeth Howell 
1811312a9d60SBen Walker 	rc = spdk_nvmf_subsystem_pause(subsystem, ctx->nsid, nvmf_rpc_remove_ns_paused, ctx);
18128ff8bf07SSeth Howell 	if (rc != 0) {
1813a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1814a54a6a26SSeth Howell 		nvmf_rpc_remove_ns_ctx_free(ctx);
1815a54a6a26SSeth Howell 	}
1816a54a6a26SSeth Howell }
1817e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_remove_ns", rpc_nvmf_subsystem_remove_ns, SPDK_RPC_RUNTIME)
1818a54a6a26SSeth Howell 
1819d37555b4SJonas Pfefferle struct nvmf_rpc_ns_visible_ctx {
1820d37555b4SJonas Pfefferle 	struct spdk_jsonrpc_request *request;
1821d37555b4SJonas Pfefferle 	char *nqn;
1822d37555b4SJonas Pfefferle 	uint32_t nsid;
1823d37555b4SJonas Pfefferle 	char *host;
1824d37555b4SJonas Pfefferle 	char *tgt_name;
1825d37555b4SJonas Pfefferle 	bool visible;
1826d37555b4SJonas Pfefferle 	bool response_sent;
1827d37555b4SJonas Pfefferle };
1828d37555b4SJonas Pfefferle 
1829d37555b4SJonas Pfefferle static const struct spdk_json_object_decoder nvmf_rpc_ns_visible_decoder[] = {
1830d37555b4SJonas Pfefferle 	{"nqn", offsetof(struct nvmf_rpc_ns_visible_ctx, nqn), spdk_json_decode_string},
1831d37555b4SJonas Pfefferle 	{"nsid", offsetof(struct nvmf_rpc_ns_visible_ctx, nsid), spdk_json_decode_uint32},
1832d37555b4SJonas Pfefferle 	{"host", offsetof(struct nvmf_rpc_ns_visible_ctx, host), spdk_json_decode_string},
1833d37555b4SJonas Pfefferle 	{"tgt_name", offsetof(struct nvmf_rpc_ns_visible_ctx, tgt_name), spdk_json_decode_string, true},
1834d37555b4SJonas Pfefferle };
1835d37555b4SJonas Pfefferle 
1836d37555b4SJonas Pfefferle static void
1837d37555b4SJonas Pfefferle nvmf_rpc_ns_visible_ctx_free(struct nvmf_rpc_ns_visible_ctx *ctx)
1838d37555b4SJonas Pfefferle {
1839d37555b4SJonas Pfefferle 	free(ctx->nqn);
1840d37555b4SJonas Pfefferle 	free(ctx->host);
1841d37555b4SJonas Pfefferle 	free(ctx->tgt_name);
1842d37555b4SJonas Pfefferle 	free(ctx);
1843d37555b4SJonas Pfefferle }
1844d37555b4SJonas Pfefferle 
1845d37555b4SJonas Pfefferle static void
1846d37555b4SJonas Pfefferle nvmf_rpc_ns_visible_resumed(struct spdk_nvmf_subsystem *subsystem,
1847d37555b4SJonas Pfefferle 			    void *cb_arg, int status)
1848d37555b4SJonas Pfefferle {
1849d37555b4SJonas Pfefferle 	struct nvmf_rpc_ns_visible_ctx *ctx = cb_arg;
1850d37555b4SJonas Pfefferle 	struct spdk_jsonrpc_request *request = ctx->request;
1851d37555b4SJonas Pfefferle 	bool response_sent = ctx->response_sent;
1852d37555b4SJonas Pfefferle 
1853d37555b4SJonas Pfefferle 	nvmf_rpc_ns_visible_ctx_free(ctx);
1854d37555b4SJonas Pfefferle 
1855d37555b4SJonas Pfefferle 	if (!response_sent) {
1856d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_bool_response(request, true);
1857d37555b4SJonas Pfefferle 	}
1858d37555b4SJonas Pfefferle }
1859d37555b4SJonas Pfefferle 
1860d37555b4SJonas Pfefferle static void
1861d37555b4SJonas Pfefferle nvmf_rpc_ns_visible_paused(struct spdk_nvmf_subsystem *subsystem,
1862d37555b4SJonas Pfefferle 			   void *cb_arg, int status)
1863d37555b4SJonas Pfefferle {
1864d37555b4SJonas Pfefferle 	struct nvmf_rpc_ns_visible_ctx *ctx = cb_arg;
1865d37555b4SJonas Pfefferle 	int ret;
1866d37555b4SJonas Pfefferle 
1867d37555b4SJonas Pfefferle 	if (ctx->visible) {
1868d37555b4SJonas Pfefferle 		ret = spdk_nvmf_ns_add_host(subsystem, ctx->nsid, ctx->host, 0);
1869d37555b4SJonas Pfefferle 	} else {
1870d37555b4SJonas Pfefferle 		ret = spdk_nvmf_ns_remove_host(subsystem, ctx->nsid, ctx->host, 0);
1871d37555b4SJonas Pfefferle 	}
1872d37555b4SJonas Pfefferle 	if (ret < 0) {
1873d37555b4SJonas Pfefferle 		SPDK_ERRLOG("Unable to add/remove %s to namespace ID %u\n", ctx->host, ctx->nsid);
1874d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1875d37555b4SJonas Pfefferle 						 "Invalid parameters");
1876d37555b4SJonas Pfefferle 		ctx->response_sent = true;
1877d37555b4SJonas Pfefferle 	}
1878d37555b4SJonas Pfefferle 
1879d37555b4SJonas Pfefferle 	if (spdk_nvmf_subsystem_resume(subsystem, nvmf_rpc_ns_visible_resumed, ctx)) {
1880d37555b4SJonas Pfefferle 		if (!ctx->response_sent) {
1881d37555b4SJonas Pfefferle 			spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1882d37555b4SJonas Pfefferle 		}
1883d37555b4SJonas Pfefferle 		nvmf_rpc_ns_visible_ctx_free(ctx);
1884d37555b4SJonas Pfefferle 	}
1885d37555b4SJonas Pfefferle }
1886d37555b4SJonas Pfefferle 
1887d37555b4SJonas Pfefferle static void
1888d37555b4SJonas Pfefferle nvmf_rpc_ns_visible(struct spdk_jsonrpc_request *request,
1889d37555b4SJonas Pfefferle 		    const struct spdk_json_val *params,
1890d37555b4SJonas Pfefferle 		    bool visible)
1891d37555b4SJonas Pfefferle {
1892d37555b4SJonas Pfefferle 	struct nvmf_rpc_ns_visible_ctx *ctx;
1893d37555b4SJonas Pfefferle 	struct spdk_nvmf_subsystem *subsystem;
1894d37555b4SJonas Pfefferle 	struct spdk_nvmf_tgt *tgt;
1895d37555b4SJonas Pfefferle 	int rc;
1896d37555b4SJonas Pfefferle 
1897d37555b4SJonas Pfefferle 	ctx = calloc(1, sizeof(*ctx));
1898d37555b4SJonas Pfefferle 	if (!ctx) {
1899d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
1900d37555b4SJonas Pfefferle 		return;
1901d37555b4SJonas Pfefferle 	}
1902d37555b4SJonas Pfefferle 	ctx->visible = visible;
1903d37555b4SJonas Pfefferle 
1904d37555b4SJonas Pfefferle 	if (spdk_json_decode_object(params, nvmf_rpc_ns_visible_decoder,
1905d37555b4SJonas Pfefferle 				    SPDK_COUNTOF(nvmf_rpc_ns_visible_decoder),
1906d37555b4SJonas Pfefferle 				    ctx)) {
1907d37555b4SJonas Pfefferle 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1908d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1909d37555b4SJonas Pfefferle 		nvmf_rpc_ns_visible_ctx_free(ctx);
1910d37555b4SJonas Pfefferle 		return;
1911d37555b4SJonas Pfefferle 	}
1912d37555b4SJonas Pfefferle 	ctx->request = request;
1913d37555b4SJonas Pfefferle 
1914d37555b4SJonas Pfefferle 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
1915d37555b4SJonas Pfefferle 	if (!tgt) {
1916d37555b4SJonas Pfefferle 		SPDK_ERRLOG("Unable to find a target object.\n");
1917d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1918d37555b4SJonas Pfefferle 						 "Unable to find a target.");
1919d37555b4SJonas Pfefferle 		nvmf_rpc_ns_visible_ctx_free(ctx);
1920d37555b4SJonas Pfefferle 		return;
1921d37555b4SJonas Pfefferle 	}
1922d37555b4SJonas Pfefferle 
1923d37555b4SJonas Pfefferle 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
1924d37555b4SJonas Pfefferle 	if (!subsystem) {
1925d37555b4SJonas Pfefferle 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
1926d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1927d37555b4SJonas Pfefferle 		nvmf_rpc_ns_visible_ctx_free(ctx);
1928d37555b4SJonas Pfefferle 		return;
1929d37555b4SJonas Pfefferle 	}
1930d37555b4SJonas Pfefferle 
1931d37555b4SJonas Pfefferle 	rc = spdk_nvmf_subsystem_pause(subsystem, ctx->nsid, nvmf_rpc_ns_visible_paused, ctx);
1932d37555b4SJonas Pfefferle 	if (rc != 0) {
1933d37555b4SJonas Pfefferle 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
1934d37555b4SJonas Pfefferle 		nvmf_rpc_ns_visible_ctx_free(ctx);
1935d37555b4SJonas Pfefferle 	}
1936d37555b4SJonas Pfefferle }
1937d37555b4SJonas Pfefferle 
1938d37555b4SJonas Pfefferle static void
1939d37555b4SJonas Pfefferle rpc_nvmf_ns_add_host(struct spdk_jsonrpc_request *request,
1940d37555b4SJonas Pfefferle 		     const struct spdk_json_val *params)
1941d37555b4SJonas Pfefferle {
1942d37555b4SJonas Pfefferle 	nvmf_rpc_ns_visible(request, params, true);
1943d37555b4SJonas Pfefferle }
1944d37555b4SJonas Pfefferle SPDK_RPC_REGISTER("nvmf_ns_add_host", rpc_nvmf_ns_add_host, SPDK_RPC_RUNTIME)
1945d37555b4SJonas Pfefferle 
1946d37555b4SJonas Pfefferle static void
1947d37555b4SJonas Pfefferle rpc_nvmf_ns_remove_host(struct spdk_jsonrpc_request *request,
1948d37555b4SJonas Pfefferle 			const struct spdk_json_val *params)
1949d37555b4SJonas Pfefferle {
1950d37555b4SJonas Pfefferle 	nvmf_rpc_ns_visible(request, params, false);
1951d37555b4SJonas Pfefferle }
1952d37555b4SJonas Pfefferle SPDK_RPC_REGISTER("nvmf_ns_remove_host", rpc_nvmf_ns_remove_host, SPDK_RPC_RUNTIME)
1953d37555b4SJonas Pfefferle 
1954a54a6a26SSeth Howell struct nvmf_rpc_host_ctx {
19556723bd0cSBen Walker 	struct spdk_jsonrpc_request *request;
1956a54a6a26SSeth Howell 	char *nqn;
1957a54a6a26SSeth Howell 	char *host;
1958f8433aadSSeth Howell 	char *tgt_name;
19593f4f8ad0SKonrad Sztyber 	char *dhchap_key;
1960aa13730dSKonrad Sztyber 	char *dhchap_ctrlr_key;
1961a54a6a26SSeth Howell 	bool allow_any_host;
1962a54a6a26SSeth Howell };
1963a54a6a26SSeth Howell 
1964a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_subsystem_host_decoder[] = {
1965a54a6a26SSeth Howell 	{"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string},
1966a54a6a26SSeth Howell 	{"host", offsetof(struct nvmf_rpc_host_ctx, host), spdk_json_decode_string},
1967f8433aadSSeth Howell 	{"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true},
19683f4f8ad0SKonrad Sztyber 	{"dhchap_key", offsetof(struct nvmf_rpc_host_ctx, dhchap_key), spdk_json_decode_string, true},
1969aa13730dSKonrad Sztyber 	{"dhchap_ctrlr_key", offsetof(struct nvmf_rpc_host_ctx, dhchap_ctrlr_key), spdk_json_decode_string, true},
1970a54a6a26SSeth Howell };
1971a54a6a26SSeth Howell 
1972a54a6a26SSeth Howell static void
1973a54a6a26SSeth Howell nvmf_rpc_host_ctx_free(struct nvmf_rpc_host_ctx *ctx)
1974a54a6a26SSeth Howell {
1975a54a6a26SSeth Howell 	free(ctx->nqn);
1976a54a6a26SSeth Howell 	free(ctx->host);
1977f8433aadSSeth Howell 	free(ctx->tgt_name);
19783f4f8ad0SKonrad Sztyber 	free(ctx->dhchap_key);
1979aa13730dSKonrad Sztyber 	free(ctx->dhchap_ctrlr_key);
1980a54a6a26SSeth Howell }
1981a54a6a26SSeth Howell 
1982a54a6a26SSeth Howell static void
1983e569a578SSeth Howell rpc_nvmf_subsystem_add_host(struct spdk_jsonrpc_request *request,
1984a54a6a26SSeth Howell 			    const struct spdk_json_val *params)
1985a54a6a26SSeth Howell {
1986ce594c1eSBen Walker 	struct nvmf_rpc_host_ctx ctx = {};
1987a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
19883f4f8ad0SKonrad Sztyber 	struct spdk_nvmf_host_opts opts = {};
1989a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
1990aa13730dSKonrad Sztyber 	struct spdk_key *key = NULL, *ckey = NULL;
19918ff8bf07SSeth Howell 	int rc;
1992a54a6a26SSeth Howell 
19936803032dSKrzysztof Karas 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_subsystem_host_decoder,
1994a54a6a26SSeth Howell 					    SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder),
1995ce594c1eSBen Walker 					    &ctx)) {
1996a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1997a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1998012e50f8SKonrad Sztyber 		goto out;
1999a54a6a26SSeth Howell 	}
2000a54a6a26SSeth Howell 
2001ce594c1eSBen Walker 	tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
2002a54a6a26SSeth Howell 	if (!tgt) {
2003a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
2004a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2005a54a6a26SSeth Howell 						 "Unable to find a target.");
2006012e50f8SKonrad Sztyber 		goto out;
2007a54a6a26SSeth Howell 	}
2008a54a6a26SSeth Howell 
2009ce594c1eSBen Walker 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn);
2010a54a6a26SSeth Howell 	if (!subsystem) {
2011ce594c1eSBen Walker 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn);
2012a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2013012e50f8SKonrad Sztyber 		goto out;
2014a54a6a26SSeth Howell 	}
2015a54a6a26SSeth Howell 
20163f4f8ad0SKonrad Sztyber 	if (ctx.dhchap_key != NULL) {
20173f4f8ad0SKonrad Sztyber 		key = spdk_keyring_get_key(ctx.dhchap_key);
20183f4f8ad0SKonrad Sztyber 		if (key == NULL) {
20193f4f8ad0SKonrad Sztyber 			SPDK_ERRLOG("Unable to find DH-HMAC-CHAP key: %s\n", ctx.dhchap_key);
20203f4f8ad0SKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
20213f4f8ad0SKonrad Sztyber 							 "Invalid parameters");
2022012e50f8SKonrad Sztyber 			goto out;
20238ff8bf07SSeth Howell 		}
20243f4f8ad0SKonrad Sztyber 	}
2025ce594c1eSBen Walker 
2026aa13730dSKonrad Sztyber 	if (ctx.dhchap_ctrlr_key != NULL) {
2027aa13730dSKonrad Sztyber 		ckey = spdk_keyring_get_key(ctx.dhchap_ctrlr_key);
2028aa13730dSKonrad Sztyber 		if (ckey == NULL) {
2029aa13730dSKonrad Sztyber 			SPDK_ERRLOG("Unable to find DH-HMAC-CHAP ctrlr key: %s\n",
2030aa13730dSKonrad Sztyber 				    ctx.dhchap_ctrlr_key);
2031aa13730dSKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2032aa13730dSKonrad Sztyber 							 "Invalid parameters");
2033aa13730dSKonrad Sztyber 			goto out;
2034aa13730dSKonrad Sztyber 		}
2035aa13730dSKonrad Sztyber 	}
2036aa13730dSKonrad Sztyber 
2037aa13730dSKonrad Sztyber 	opts.size = SPDK_SIZEOF(&opts, dhchap_ctrlr_key);
20383f4f8ad0SKonrad Sztyber 	opts.params = params;
20393f4f8ad0SKonrad Sztyber 	opts.dhchap_key = key;
2040aa13730dSKonrad Sztyber 	opts.dhchap_ctrlr_key = ckey;
20413f4f8ad0SKonrad Sztyber 	rc = spdk_nvmf_subsystem_add_host_ext(subsystem, ctx.host, &opts);
20423f4f8ad0SKonrad Sztyber 	if (rc != 0) {
20433f4f8ad0SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
2044012e50f8SKonrad Sztyber 		goto out;
20453f4f8ad0SKonrad Sztyber 	}
20463f4f8ad0SKonrad Sztyber 
2047d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
2048012e50f8SKonrad Sztyber out:
2049aa13730dSKonrad Sztyber 	spdk_keyring_put_key(ckey);
2050012e50f8SKonrad Sztyber 	spdk_keyring_put_key(key);
2051ce594c1eSBen Walker 	nvmf_rpc_host_ctx_free(&ctx);
2052a54a6a26SSeth Howell }
2053e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_add_host", rpc_nvmf_subsystem_add_host, SPDK_RPC_RUNTIME)
2054a54a6a26SSeth Howell 
2055a54a6a26SSeth Howell static void
20566723bd0cSBen Walker rpc_nvmf_subsystem_remove_host_done(void *_ctx, int status)
20576723bd0cSBen Walker {
20586723bd0cSBen Walker 	struct nvmf_rpc_host_ctx *ctx = _ctx;
20596723bd0cSBen Walker 
2060d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(ctx->request, true);
20616723bd0cSBen Walker 	nvmf_rpc_host_ctx_free(ctx);
20626723bd0cSBen Walker 	free(ctx);
20636723bd0cSBen Walker }
20646723bd0cSBen Walker 
20656723bd0cSBen Walker static void
2066e569a578SSeth Howell rpc_nvmf_subsystem_remove_host(struct spdk_jsonrpc_request *request,
2067a54a6a26SSeth Howell 			       const struct spdk_json_val *params)
2068a54a6a26SSeth Howell {
20696723bd0cSBen Walker 	struct nvmf_rpc_host_ctx *ctx;
2070a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
2071a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
20728ff8bf07SSeth Howell 	int rc;
2073a54a6a26SSeth Howell 
20746723bd0cSBen Walker 	ctx = calloc(1, sizeof(*ctx));
20756723bd0cSBen Walker 	if (ctx == NULL) {
20766723bd0cSBen Walker 		SPDK_ERRLOG("Unable to allocate context to perform RPC\n");
20776723bd0cSBen Walker 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
2078a54a6a26SSeth Howell 		return;
2079a54a6a26SSeth Howell 	}
2080a54a6a26SSeth Howell 
20816723bd0cSBen Walker 	ctx->request = request;
20826723bd0cSBen Walker 
20836723bd0cSBen Walker 	if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder,
20846723bd0cSBen Walker 				    SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder),
20856723bd0cSBen Walker 				    ctx)) {
20866723bd0cSBen Walker 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
20876723bd0cSBen Walker 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
20886723bd0cSBen Walker 		nvmf_rpc_host_ctx_free(ctx);
20896723bd0cSBen Walker 		free(ctx);
20906723bd0cSBen Walker 		return;
20916723bd0cSBen Walker 	}
20926723bd0cSBen Walker 
20936723bd0cSBen Walker 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2094a54a6a26SSeth Howell 	if (!tgt) {
2095a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
2096a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2097a54a6a26SSeth Howell 						 "Unable to find a target.");
20986723bd0cSBen Walker 		nvmf_rpc_host_ctx_free(ctx);
20996723bd0cSBen Walker 		free(ctx);
2100a54a6a26SSeth Howell 		return;
2101a54a6a26SSeth Howell 	}
2102a54a6a26SSeth Howell 
21036723bd0cSBen Walker 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
2104a54a6a26SSeth Howell 	if (!subsystem) {
21056723bd0cSBen Walker 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
2106a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
21076723bd0cSBen Walker 		nvmf_rpc_host_ctx_free(ctx);
21086723bd0cSBen Walker 		free(ctx);
2109a54a6a26SSeth Howell 		return;
2110a54a6a26SSeth Howell 	}
2111a54a6a26SSeth Howell 
21126723bd0cSBen Walker 	rc = spdk_nvmf_subsystem_remove_host(subsystem, ctx->host);
21138ff8bf07SSeth Howell 	if (rc != 0) {
2114a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
21156723bd0cSBen Walker 		nvmf_rpc_host_ctx_free(ctx);
21166723bd0cSBen Walker 		free(ctx);
2117ce594c1eSBen Walker 		return;
21188ff8bf07SSeth Howell 	}
2119ce594c1eSBen Walker 
21206723bd0cSBen Walker 	rc = spdk_nvmf_subsystem_disconnect_host(subsystem, ctx->host,
21216723bd0cSBen Walker 			rpc_nvmf_subsystem_remove_host_done,
21226723bd0cSBen Walker 			ctx);
21236723bd0cSBen Walker 	if (rc != 0) {
21246723bd0cSBen Walker 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
21256723bd0cSBen Walker 		nvmf_rpc_host_ctx_free(ctx);
21266723bd0cSBen Walker 		free(ctx);
21276723bd0cSBen Walker 		return;
21286723bd0cSBen Walker 	}
2129a54a6a26SSeth Howell }
2130e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_remove_host", rpc_nvmf_subsystem_remove_host,
2131a54a6a26SSeth Howell 		  SPDK_RPC_RUNTIME)
2132a54a6a26SSeth Howell 
21338a4b7226SKonrad Sztyber static void
21348a4b7226SKonrad Sztyber rpc_nvmf_subsystem_set_keys(struct spdk_jsonrpc_request *request,
21358a4b7226SKonrad Sztyber 			    const struct spdk_json_val *params)
21368a4b7226SKonrad Sztyber {
21378a4b7226SKonrad Sztyber 	struct nvmf_rpc_host_ctx ctx = {};
21388a4b7226SKonrad Sztyber 	struct spdk_nvmf_subsystem *subsystem;
21398a4b7226SKonrad Sztyber 	struct spdk_nvmf_subsystem_key_opts opts = {};
21408a4b7226SKonrad Sztyber 	struct spdk_nvmf_tgt *tgt;
21418a4b7226SKonrad Sztyber 	struct spdk_key *key = NULL, *ckey = NULL;
21428a4b7226SKonrad Sztyber 	int rc;
21438a4b7226SKonrad Sztyber 
21448a4b7226SKonrad Sztyber 	if (spdk_json_decode_object(params, nvmf_rpc_subsystem_host_decoder,
21458a4b7226SKonrad Sztyber 				    SPDK_COUNTOF(nvmf_rpc_subsystem_host_decoder), &ctx)) {
21468a4b7226SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
21478a4b7226SKonrad Sztyber 						 "Invalid parameters");
21488a4b7226SKonrad Sztyber 		goto out;
21498a4b7226SKonrad Sztyber 	}
21508a4b7226SKonrad Sztyber 
21518a4b7226SKonrad Sztyber 	tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
21528a4b7226SKonrad Sztyber 	if (!tgt) {
21538a4b7226SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
21548a4b7226SKonrad Sztyber 						 "Invalid parameters");
21558a4b7226SKonrad Sztyber 		goto out;
21568a4b7226SKonrad Sztyber 	}
21578a4b7226SKonrad Sztyber 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn);
21588a4b7226SKonrad Sztyber 	if (!subsystem) {
21598a4b7226SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
21608a4b7226SKonrad Sztyber 						 "Invalid parameters");
21618a4b7226SKonrad Sztyber 		goto out;
21628a4b7226SKonrad Sztyber 	}
21638a4b7226SKonrad Sztyber 
21648a4b7226SKonrad Sztyber 	if (ctx.dhchap_key != NULL) {
21658a4b7226SKonrad Sztyber 		key = spdk_keyring_get_key(ctx.dhchap_key);
21668a4b7226SKonrad Sztyber 		if (key == NULL) {
21678a4b7226SKonrad Sztyber 			SPDK_ERRLOG("Unable to find DH-HMAC-CHAP key: %s\n", ctx.dhchap_key);
21688a4b7226SKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
21698a4b7226SKonrad Sztyber 							 "Invalid parameters");
21708a4b7226SKonrad Sztyber 			goto out;
21718a4b7226SKonrad Sztyber 		}
21728a4b7226SKonrad Sztyber 	}
21738a4b7226SKonrad Sztyber 	if (ctx.dhchap_ctrlr_key != NULL) {
21748a4b7226SKonrad Sztyber 		ckey = spdk_keyring_get_key(ctx.dhchap_ctrlr_key);
21758a4b7226SKonrad Sztyber 		if (ckey == NULL) {
21768a4b7226SKonrad Sztyber 			SPDK_ERRLOG("Unable to find DH-HMAC-CHAP ctrlr key: %s\n",
21778a4b7226SKonrad Sztyber 				    ctx.dhchap_ctrlr_key);
21788a4b7226SKonrad Sztyber 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
21798a4b7226SKonrad Sztyber 							 "Invalid parameters");
21808a4b7226SKonrad Sztyber 			goto out;
21818a4b7226SKonrad Sztyber 		}
21828a4b7226SKonrad Sztyber 	}
21838a4b7226SKonrad Sztyber 
21848a4b7226SKonrad Sztyber 	opts.size = SPDK_SIZEOF(&opts, dhchap_ctrlr_key);
21858a4b7226SKonrad Sztyber 	opts.dhchap_key = key;
21868a4b7226SKonrad Sztyber 	opts.dhchap_ctrlr_key = ckey;
21878a4b7226SKonrad Sztyber 	rc = spdk_nvmf_subsystem_set_keys(subsystem, ctx.host, &opts);
21888a4b7226SKonrad Sztyber 	if (rc != 0) {
21898a4b7226SKonrad Sztyber 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
21908a4b7226SKonrad Sztyber 		goto out;
21918a4b7226SKonrad Sztyber 	}
21928a4b7226SKonrad Sztyber 
21938a4b7226SKonrad Sztyber 	spdk_jsonrpc_send_bool_response(request, true);
21948a4b7226SKonrad Sztyber out:
21958a4b7226SKonrad Sztyber 	spdk_keyring_put_key(ckey);
21968a4b7226SKonrad Sztyber 	spdk_keyring_put_key(key);
21978a4b7226SKonrad Sztyber 	nvmf_rpc_host_ctx_free(&ctx);
21988a4b7226SKonrad Sztyber }
21998a4b7226SKonrad Sztyber SPDK_RPC_REGISTER("nvmf_subsystem_set_keys", rpc_nvmf_subsystem_set_keys, SPDK_RPC_RUNTIME)
2200a54a6a26SSeth Howell 
2201a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_subsystem_any_host_decoder[] = {
2202a54a6a26SSeth Howell 	{"nqn", offsetof(struct nvmf_rpc_host_ctx, nqn), spdk_json_decode_string},
2203a54a6a26SSeth Howell 	{"allow_any_host", offsetof(struct nvmf_rpc_host_ctx, allow_any_host), spdk_json_decode_bool},
2204f8433aadSSeth Howell 	{"tgt_name", offsetof(struct nvmf_rpc_host_ctx, tgt_name), spdk_json_decode_string, true},
2205a54a6a26SSeth Howell };
2206a54a6a26SSeth Howell 
2207a54a6a26SSeth Howell static void
2208e569a578SSeth Howell rpc_nvmf_subsystem_allow_any_host(struct spdk_jsonrpc_request *request,
2209a54a6a26SSeth Howell 				  const struct spdk_json_val *params)
2210a54a6a26SSeth Howell {
2211ce594c1eSBen Walker 	struct nvmf_rpc_host_ctx ctx = {};
2212a54a6a26SSeth Howell 	struct spdk_nvmf_subsystem *subsystem;
2213a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
22148ff8bf07SSeth Howell 	int rc;
2215a54a6a26SSeth Howell 
2216a54a6a26SSeth Howell 	if (spdk_json_decode_object(params, nvmf_rpc_subsystem_any_host_decoder,
2217a54a6a26SSeth Howell 				    SPDK_COUNTOF(nvmf_rpc_subsystem_any_host_decoder),
2218ce594c1eSBen Walker 				    &ctx)) {
2219a54a6a26SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
2220a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2221ce594c1eSBen Walker 		nvmf_rpc_host_ctx_free(&ctx);
2222a54a6a26SSeth Howell 		return;
2223a54a6a26SSeth Howell 	}
2224a54a6a26SSeth Howell 
2225ce594c1eSBen Walker 	tgt = spdk_nvmf_get_tgt(ctx.tgt_name);
2226a54a6a26SSeth Howell 	if (!tgt) {
2227a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
2228a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2229a54a6a26SSeth Howell 						 "Unable to find a target.");
2230ce594c1eSBen Walker 		nvmf_rpc_host_ctx_free(&ctx);
2231a54a6a26SSeth Howell 		return;
2232a54a6a26SSeth Howell 	}
2233a54a6a26SSeth Howell 
2234ce594c1eSBen Walker 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx.nqn);
2235a54a6a26SSeth Howell 	if (!subsystem) {
2236ce594c1eSBen Walker 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx.nqn);
2237a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2238ce594c1eSBen Walker 		nvmf_rpc_host_ctx_free(&ctx);
2239a54a6a26SSeth Howell 		return;
2240a54a6a26SSeth Howell 	}
2241a54a6a26SSeth Howell 
2242ce594c1eSBen Walker 	rc = spdk_nvmf_subsystem_set_allow_any_host(subsystem, ctx.allow_any_host);
22438ff8bf07SSeth Howell 	if (rc != 0) {
2244a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Internal error");
2245ce594c1eSBen Walker 		nvmf_rpc_host_ctx_free(&ctx);
2246ce594c1eSBen Walker 		return;
22478ff8bf07SSeth Howell 	}
2248ce594c1eSBen Walker 
2249d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
2250ce594c1eSBen Walker 	nvmf_rpc_host_ctx_free(&ctx);
2251a54a6a26SSeth Howell }
2252e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_subsystem_allow_any_host", rpc_nvmf_subsystem_allow_any_host,
2253a54a6a26SSeth Howell 		  SPDK_RPC_RUNTIME)
2254a54a6a26SSeth Howell 
2255c9b89ef1SSeth Howell struct nvmf_rpc_target_ctx {
2256c9b89ef1SSeth Howell 	char *name;
2257c9b89ef1SSeth Howell 	uint32_t max_subsystems;
22583d8904c6SAlexey Marchuk 	char *discovery_filter;
2259c9b89ef1SSeth Howell };
2260c9b89ef1SSeth Howell 
22613d8904c6SAlexey Marchuk static int
22623d8904c6SAlexey Marchuk decode_discovery_filter(const struct spdk_json_val *val, void *out)
22633d8904c6SAlexey Marchuk {
2264dc9f61a3SKonrad Sztyber 	uint32_t *_filter = out;
2265dc9f61a3SKonrad Sztyber 	uint32_t filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY;
22663d8904c6SAlexey Marchuk 	char *tokens = spdk_json_strdup(val);
22673d8904c6SAlexey Marchuk 	char *tok;
2268*b37db069SXuQi 	char *sp = NULL;
22693d8904c6SAlexey Marchuk 	int rc = -EINVAL;
22703d8904c6SAlexey Marchuk 	bool all_specified = false;
22713d8904c6SAlexey Marchuk 
22723d8904c6SAlexey Marchuk 	if (!tokens) {
22733d8904c6SAlexey Marchuk 		return -ENOMEM;
22743d8904c6SAlexey Marchuk 	}
22753d8904c6SAlexey Marchuk 
2276*b37db069SXuQi 	tok = strtok_r(tokens, ",", &sp);
22773d8904c6SAlexey Marchuk 	while (tok) {
22783d8904c6SAlexey Marchuk 		if (strncmp(tok, "match_any", 9) == 0) {
22793d8904c6SAlexey Marchuk 			if (filter != SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY) {
22803d8904c6SAlexey Marchuk 				goto out;
22813d8904c6SAlexey Marchuk 			}
22823d8904c6SAlexey Marchuk 			filter = SPDK_NVMF_TGT_DISCOVERY_MATCH_ANY;
22833d8904c6SAlexey Marchuk 			all_specified = true;
22843d8904c6SAlexey Marchuk 		} else {
22853d8904c6SAlexey Marchuk 			if (all_specified) {
22863d8904c6SAlexey Marchuk 				goto out;
22873d8904c6SAlexey Marchuk 			}
22883d8904c6SAlexey Marchuk 			if (strncmp(tok, "transport", 9) == 0) {
22893d8904c6SAlexey Marchuk 				filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_TYPE;
22903d8904c6SAlexey Marchuk 			} else if (strncmp(tok, "address", 7) == 0) {
22913d8904c6SAlexey Marchuk 				filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_ADDRESS;
22923d8904c6SAlexey Marchuk 			} else if (strncmp(tok, "svcid", 5) == 0) {
22933d8904c6SAlexey Marchuk 				filter |= SPDK_NVMF_TGT_DISCOVERY_MATCH_TRANSPORT_SVCID;
22943d8904c6SAlexey Marchuk 			} else {
22953d8904c6SAlexey Marchuk 				SPDK_ERRLOG("Invalid value %s\n", tok);
22963d8904c6SAlexey Marchuk 				goto out;
22973d8904c6SAlexey Marchuk 			}
22983d8904c6SAlexey Marchuk 		}
22993d8904c6SAlexey Marchuk 
2300*b37db069SXuQi 		tok = strtok_r(NULL, ",", &sp);
23013d8904c6SAlexey Marchuk 	}
23023d8904c6SAlexey Marchuk 
23033d8904c6SAlexey Marchuk 	rc = 0;
23043d8904c6SAlexey Marchuk 	*_filter = filter;
23053d8904c6SAlexey Marchuk 
23063d8904c6SAlexey Marchuk out:
23073d8904c6SAlexey Marchuk 	free(tokens);
23083d8904c6SAlexey Marchuk 
23093d8904c6SAlexey Marchuk 	return rc;
23103d8904c6SAlexey Marchuk }
23113d8904c6SAlexey Marchuk 
2312c9b89ef1SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_create_target_decoder[] = {
2313c9b89ef1SSeth Howell 	{"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string},
2314c9b89ef1SSeth Howell 	{"max_subsystems", offsetof(struct nvmf_rpc_target_ctx, max_subsystems), spdk_json_decode_uint32, true},
23153d8904c6SAlexey Marchuk 	{"discovery_filter", offsetof(struct nvmf_rpc_target_ctx, discovery_filter), decode_discovery_filter, true}
2316c9b89ef1SSeth Howell };
2317c9b89ef1SSeth Howell 
2318c9b89ef1SSeth Howell static void
2319e569a578SSeth Howell rpc_nvmf_create_target(struct spdk_jsonrpc_request *request,
2320c9b89ef1SSeth Howell 		       const struct spdk_json_val *params)
2321c9b89ef1SSeth Howell {
2322c9b89ef1SSeth Howell 	struct spdk_nvmf_target_opts	opts;
2323c9b89ef1SSeth Howell 	struct nvmf_rpc_target_ctx	ctx = {0};
2324c9b89ef1SSeth Howell 	struct spdk_nvmf_tgt		*tgt;
2325c9b89ef1SSeth Howell 	struct spdk_json_write_ctx	*w;
2326c9b89ef1SSeth Howell 
2327c9b89ef1SSeth Howell 	/* Decode parameters the first time to get the transport type */
2328c9b89ef1SSeth Howell 	if (spdk_json_decode_object(params, nvmf_rpc_create_target_decoder,
2329c9b89ef1SSeth Howell 				    SPDK_COUNTOF(nvmf_rpc_create_target_decoder),
2330c9b89ef1SSeth Howell 				    &ctx)) {
2331c9b89ef1SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
2332c9b89ef1SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
23333d8904c6SAlexey Marchuk 		goto out;
2334c9b89ef1SSeth Howell 	}
2335c9b89ef1SSeth Howell 
2336c9b89ef1SSeth Howell 	snprintf(opts.name, NVMF_TGT_NAME_MAX_LENGTH, "%s", ctx.name);
2337c9b89ef1SSeth Howell 	opts.max_subsystems = ctx.max_subsystems;
233863454e89SKonrad Sztyber 	opts.size = SPDK_SIZEOF(&opts, discovery_filter);
2339c9b89ef1SSeth Howell 
2340c9b89ef1SSeth Howell 	if (spdk_nvmf_get_tgt(opts.name) != NULL) {
2341c9b89ef1SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2342c9b89ef1SSeth Howell 						 "Target already exists.");
23433d8904c6SAlexey Marchuk 		goto out;
2344c9b89ef1SSeth Howell 	}
2345c9b89ef1SSeth Howell 
2346c9b89ef1SSeth Howell 	tgt = spdk_nvmf_tgt_create(&opts);
2347c9b89ef1SSeth Howell 
2348c9b89ef1SSeth Howell 	if (tgt == NULL) {
2349c9b89ef1SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2350c9b89ef1SSeth Howell 						 "Unable to create the requested target.");
23513d8904c6SAlexey Marchuk 		goto out;
2352c9b89ef1SSeth Howell 	}
2353c9b89ef1SSeth Howell 
2354c9b89ef1SSeth Howell 	w = spdk_jsonrpc_begin_result(request);
2355c9b89ef1SSeth Howell 	spdk_json_write_string(w, spdk_nvmf_tgt_get_name(tgt));
2356c9b89ef1SSeth Howell 	spdk_jsonrpc_end_result(request, w);
23573d8904c6SAlexey Marchuk out:
2358c9b89ef1SSeth Howell 	free(ctx.name);
23593d8904c6SAlexey Marchuk 	free(ctx.discovery_filter);
2360c9b89ef1SSeth Howell }
2361e2a4288cSMonica Kenguva /* private */ SPDK_RPC_REGISTER("nvmf_create_target", rpc_nvmf_create_target, SPDK_RPC_RUNTIME);
2362c9b89ef1SSeth Howell 
2363099489b2SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_destroy_target_decoder[] = {
2364099489b2SSeth Howell 	{"name", offsetof(struct nvmf_rpc_target_ctx, name), spdk_json_decode_string},
2365099489b2SSeth Howell };
2366099489b2SSeth Howell 
2367099489b2SSeth Howell static void
2368099489b2SSeth Howell nvmf_rpc_destroy_target_done(void *ctx, int status)
2369099489b2SSeth Howell {
2370099489b2SSeth Howell 	struct spdk_jsonrpc_request	*request = ctx;
2371099489b2SSeth Howell 
2372d73077b8Syidong0635 	spdk_jsonrpc_send_bool_response(request, true);
2373099489b2SSeth Howell }
2374099489b2SSeth Howell 
2375099489b2SSeth Howell static void
2376e569a578SSeth Howell rpc_nvmf_delete_target(struct spdk_jsonrpc_request *request,
2377099489b2SSeth Howell 		       const struct spdk_json_val *params)
2378099489b2SSeth Howell {
2379099489b2SSeth Howell 	struct nvmf_rpc_target_ctx	ctx = {0};
2380099489b2SSeth Howell 	struct spdk_nvmf_tgt		*tgt;
2381099489b2SSeth Howell 
2382099489b2SSeth Howell 	/* Decode parameters the first time to get the transport type */
2383099489b2SSeth Howell 	if (spdk_json_decode_object(params, nvmf_rpc_destroy_target_decoder,
2384099489b2SSeth Howell 				    SPDK_COUNTOF(nvmf_rpc_destroy_target_decoder),
2385099489b2SSeth Howell 				    &ctx)) {
2386099489b2SSeth Howell 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
2387099489b2SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2388099489b2SSeth Howell 		free(ctx.name);
2389099489b2SSeth Howell 		return;
2390099489b2SSeth Howell 	}
2391099489b2SSeth Howell 
2392099489b2SSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx.name);
2393099489b2SSeth Howell 
2394099489b2SSeth Howell 	if (tgt == NULL) {
2395099489b2SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2396099489b2SSeth Howell 						 "The specified target doesn't exist, cannot delete it.");
2397099489b2SSeth Howell 		free(ctx.name);
2398099489b2SSeth Howell 		return;
2399099489b2SSeth Howell 	}
2400099489b2SSeth Howell 
2401099489b2SSeth Howell 	spdk_nvmf_tgt_destroy(tgt, nvmf_rpc_destroy_target_done, request);
2402099489b2SSeth Howell 	free(ctx.name);
2403099489b2SSeth Howell }
2404e2a4288cSMonica Kenguva /* private */ SPDK_RPC_REGISTER("nvmf_delete_target", rpc_nvmf_delete_target, SPDK_RPC_RUNTIME);
2405099489b2SSeth Howell 
2406208e089aSSeth Howell static void
2407e569a578SSeth Howell rpc_nvmf_get_targets(struct spdk_jsonrpc_request *request,
2408208e089aSSeth Howell 		     const struct spdk_json_val *params)
2409208e089aSSeth Howell {
2410208e089aSSeth Howell 	struct spdk_json_write_ctx	*w;
2411208e089aSSeth Howell 	struct spdk_nvmf_tgt		*tgt;
2412208e089aSSeth Howell 	const char			*name;
2413208e089aSSeth Howell 
2414208e089aSSeth Howell 	if (params != NULL) {
2415208e089aSSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2416208e089aSSeth Howell 						 "nvmf_get_targets has no parameters.");
2417208e089aSSeth Howell 		return;
2418208e089aSSeth Howell 	}
2419208e089aSSeth Howell 
2420208e089aSSeth Howell 	w = spdk_jsonrpc_begin_result(request);
2421208e089aSSeth Howell 	spdk_json_write_array_begin(w);
2422208e089aSSeth Howell 
2423208e089aSSeth Howell 	tgt = spdk_nvmf_get_first_tgt();
2424208e089aSSeth Howell 
2425208e089aSSeth Howell 	while (tgt != NULL) {
2426208e089aSSeth Howell 		name = spdk_nvmf_tgt_get_name(tgt);
2427208e089aSSeth Howell 		spdk_json_write_string(w, name);
2428208e089aSSeth Howell 		tgt = spdk_nvmf_get_next_tgt(tgt);
2429208e089aSSeth Howell 	}
2430208e089aSSeth Howell 
2431208e089aSSeth Howell 	spdk_json_write_array_end(w);
2432208e089aSSeth Howell 	spdk_jsonrpc_end_result(request, w);
2433208e089aSSeth Howell }
2434e2a4288cSMonica Kenguva /* private */ SPDK_RPC_REGISTER("nvmf_get_targets", rpc_nvmf_get_targets, SPDK_RPC_RUNTIME);
2435208e089aSSeth Howell 
2436a54a6a26SSeth Howell struct nvmf_rpc_create_transport_ctx {
2437a54a6a26SSeth Howell 	char				*trtype;
2438f8433aadSSeth Howell 	char				*tgt_name;
2439a54a6a26SSeth Howell 	struct spdk_nvmf_transport_opts	opts;
2440a54a6a26SSeth Howell 	struct spdk_jsonrpc_request	*request;
2441fb4398efSAlexey Marchuk 	struct spdk_nvmf_transport	*transport;
2442fb4398efSAlexey Marchuk 	int				status;
2443a54a6a26SSeth Howell };
2444a54a6a26SSeth Howell 
24451551197dSAlexey Marchuk /**
24461551197dSAlexey Marchuk  * `max_qpairs_per_ctrlr` represents both admin and IO qpairs, that confuses
24471551197dSAlexey Marchuk  * users when they configure a transport using RPC. So it was decided to
24481551197dSAlexey Marchuk  * deprecate `max_qpairs_per_ctrlr` RPC parameter and use `max_io_qpairs_per_ctrlr`
24491551197dSAlexey Marchuk  * But internal logic remains unchanged and SPDK expects that
24501551197dSAlexey Marchuk  * spdk_nvmf_transport_opts::max_qpairs_per_ctrlr includes an admin qpair.
24511551197dSAlexey Marchuk  * This function parses the number of IO qpairs and adds +1 for admin qpair.
24521551197dSAlexey Marchuk  */
24531551197dSAlexey Marchuk static int
24541551197dSAlexey Marchuk nvmf_rpc_decode_max_io_qpairs(const struct spdk_json_val *val, void *out)
24551551197dSAlexey Marchuk {
24561551197dSAlexey Marchuk 	uint16_t *i = out;
24571551197dSAlexey Marchuk 	int rc;
24581551197dSAlexey Marchuk 
24591551197dSAlexey Marchuk 	rc = spdk_json_number_to_uint16(val, i);
24601551197dSAlexey Marchuk 	if (rc == 0) {
24611551197dSAlexey Marchuk 		(*i)++;
24621551197dSAlexey Marchuk 	}
24631551197dSAlexey Marchuk 
24641551197dSAlexey Marchuk 	return rc;
24651551197dSAlexey Marchuk }
24661551197dSAlexey Marchuk 
2467a54a6a26SSeth Howell static const struct spdk_json_object_decoder nvmf_rpc_create_transport_decoder[] = {
2468a54a6a26SSeth Howell 	{	"trtype", offsetof(struct nvmf_rpc_create_transport_ctx, trtype), spdk_json_decode_string},
2469a54a6a26SSeth Howell 	{
2470a54a6a26SSeth Howell 		"max_queue_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_queue_depth),
2471a54a6a26SSeth Howell 		spdk_json_decode_uint16, true
2472a54a6a26SSeth Howell 	},
2473a54a6a26SSeth Howell 	{
24741551197dSAlexey Marchuk 		"max_io_qpairs_per_ctrlr", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_qpairs_per_ctrlr),
24751551197dSAlexey Marchuk 		nvmf_rpc_decode_max_io_qpairs, true
2476a54a6a26SSeth Howell 	},
2477a54a6a26SSeth Howell 	{
2478a54a6a26SSeth Howell 		"in_capsule_data_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.in_capsule_data_size),
2479a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2480a54a6a26SSeth Howell 	},
2481a54a6a26SSeth Howell 	{
2482a54a6a26SSeth Howell 		"max_io_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_io_size),
2483a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2484a54a6a26SSeth Howell 	},
2485a54a6a26SSeth Howell 	{
2486a54a6a26SSeth Howell 		"io_unit_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.io_unit_size),
2487a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2488a54a6a26SSeth Howell 	},
2489a54a6a26SSeth Howell 	{
2490a54a6a26SSeth Howell 		"max_aq_depth", offsetof(struct nvmf_rpc_create_transport_ctx, opts.max_aq_depth),
2491a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2492a54a6a26SSeth Howell 	},
2493a54a6a26SSeth Howell 	{
2494a54a6a26SSeth Howell 		"num_shared_buffers", offsetof(struct nvmf_rpc_create_transport_ctx, opts.num_shared_buffers),
2495a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2496a54a6a26SSeth Howell 	},
2497a54a6a26SSeth Howell 	{
2498a54a6a26SSeth Howell 		"buf_cache_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.buf_cache_size),
2499a54a6a26SSeth Howell 		spdk_json_decode_uint32, true
2500a54a6a26SSeth Howell 	},
2501a54a6a26SSeth Howell 	{
2502a54a6a26SSeth Howell 		"dif_insert_or_strip", offsetof(struct nvmf_rpc_create_transport_ctx, opts.dif_insert_or_strip),
2503a54a6a26SSeth Howell 		spdk_json_decode_bool, true
2504a54a6a26SSeth Howell 	},
2505a54a6a26SSeth Howell 	{
250626e0ef9aSShuhei Matsumoto 		"abort_timeout_sec", offsetof(struct nvmf_rpc_create_transport_ctx, opts.abort_timeout_sec),
250726e0ef9aSShuhei Matsumoto 		spdk_json_decode_uint32, true
250826e0ef9aSShuhei Matsumoto 	},
250926e0ef9aSShuhei Matsumoto 	{
2510aa1d0398SKonrad Sztyber 		"zcopy", offsetof(struct nvmf_rpc_create_transport_ctx, opts.zcopy),
2511aa1d0398SKonrad Sztyber 		spdk_json_decode_bool, true
2512aa1d0398SKonrad Sztyber 	},
2513aa1d0398SKonrad Sztyber 	{
2514f8433aadSSeth Howell 		"tgt_name", offsetof(struct nvmf_rpc_create_transport_ctx, tgt_name),
2515f8433aadSSeth Howell 		spdk_json_decode_string, true
2516f8433aadSSeth Howell 	},
251743022da3SJacek Kalwas 	{
251843022da3SJacek Kalwas 		"acceptor_poll_rate", offsetof(struct nvmf_rpc_create_transport_ctx, opts.acceptor_poll_rate),
251943022da3SJacek Kalwas 		spdk_json_decode_uint32, true
252043022da3SJacek Kalwas 	},
252179606beeSKonrad Sztyber 	{
252279606beeSKonrad Sztyber 		"ack_timeout", offsetof(struct nvmf_rpc_create_transport_ctx, opts.ack_timeout),
252379606beeSKonrad Sztyber 		spdk_json_decode_uint32, true
25247dab13c0SAlexey Marchuk 	},
25257dab13c0SAlexey Marchuk 	{
25267dab13c0SAlexey Marchuk 		"data_wr_pool_size", offsetof(struct nvmf_rpc_create_transport_ctx, opts.data_wr_pool_size),
25277dab13c0SAlexey Marchuk 		spdk_json_decode_uint32, true
252865335336SKonrad Sztyber 	},
252965335336SKonrad Sztyber 	{
253065335336SKonrad Sztyber 		"disable_command_passthru", offsetof(struct nvmf_rpc_create_transport_ctx, opts.disable_command_passthru),
253165335336SKonrad Sztyber 		spdk_json_decode_bool, true
253279606beeSKonrad Sztyber 	}
2533a54a6a26SSeth Howell };
2534a54a6a26SSeth Howell 
2535a54a6a26SSeth Howell static void
2536a54a6a26SSeth Howell nvmf_rpc_create_transport_ctx_free(struct nvmf_rpc_create_transport_ctx *ctx)
2537a54a6a26SSeth Howell {
2538a54a6a26SSeth Howell 	free(ctx->trtype);
2539f8433aadSSeth Howell 	free(ctx->tgt_name);
2540a54a6a26SSeth Howell 	free(ctx);
2541a54a6a26SSeth Howell }
2542a54a6a26SSeth Howell 
2543a54a6a26SSeth Howell static void
2544fb4398efSAlexey Marchuk nvmf_rpc_transport_destroy_done_cb(void *cb_arg)
2545fb4398efSAlexey Marchuk {
2546fb4398efSAlexey Marchuk 	struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
2547fb4398efSAlexey Marchuk 
2548fb4398efSAlexey Marchuk 	spdk_jsonrpc_send_error_response_fmt(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2549fb4398efSAlexey Marchuk 					     "Failed to add transport to tgt.(%d)", ctx->status);
2550fb4398efSAlexey Marchuk 	nvmf_rpc_create_transport_ctx_free(ctx);
2551fb4398efSAlexey Marchuk }
2552fb4398efSAlexey Marchuk 
2553fb4398efSAlexey Marchuk static void
2554a54a6a26SSeth Howell nvmf_rpc_tgt_add_transport_done(void *cb_arg, int status)
2555a54a6a26SSeth Howell {
2556a54a6a26SSeth Howell 	struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
2557a54a6a26SSeth Howell 
2558a54a6a26SSeth Howell 	if (status) {
2559a54a6a26SSeth Howell 		SPDK_ERRLOG("Failed to add transport to tgt.(%d)\n", status);
2560fb4398efSAlexey Marchuk 		ctx->status = status;
2561fb4398efSAlexey Marchuk 		spdk_nvmf_transport_destroy(ctx->transport, nvmf_rpc_transport_destroy_done_cb, ctx);
2562a54a6a26SSeth Howell 		return;
2563a54a6a26SSeth Howell 	}
2564a54a6a26SSeth Howell 
2565fb4398efSAlexey Marchuk 	spdk_jsonrpc_send_bool_response(ctx->request, true);
2566fb4398efSAlexey Marchuk 	nvmf_rpc_create_transport_ctx_free(ctx);
2567a54a6a26SSeth Howell }
2568a54a6a26SSeth Howell 
2569a54a6a26SSeth Howell static void
257096073478SJacek Kalwas nvmf_rpc_create_transport_done(void *cb_arg, struct spdk_nvmf_transport *transport)
257196073478SJacek Kalwas {
257296073478SJacek Kalwas 	struct nvmf_rpc_create_transport_ctx *ctx = cb_arg;
257396073478SJacek Kalwas 
257496073478SJacek Kalwas 	if (!transport) {
257596073478SJacek Kalwas 		SPDK_ERRLOG("Failed to create transport.\n");
257696073478SJacek Kalwas 		spdk_jsonrpc_send_error_response(ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
257796073478SJacek Kalwas 						 "Failed to create transport.");
257896073478SJacek Kalwas 		nvmf_rpc_create_transport_ctx_free(ctx);
257996073478SJacek Kalwas 		return;
258096073478SJacek Kalwas 	}
258196073478SJacek Kalwas 
258296073478SJacek Kalwas 	ctx->transport = transport;
258396073478SJacek Kalwas 
258496073478SJacek Kalwas 	spdk_nvmf_tgt_add_transport(spdk_nvmf_get_tgt(ctx->tgt_name), transport,
258596073478SJacek Kalwas 				    nvmf_rpc_tgt_add_transport_done, ctx);
258696073478SJacek Kalwas }
258796073478SJacek Kalwas 
258896073478SJacek Kalwas static void
2589e569a578SSeth Howell rpc_nvmf_create_transport(struct spdk_jsonrpc_request *request,
2590a54a6a26SSeth Howell 			  const struct spdk_json_val *params)
2591a54a6a26SSeth Howell {
2592a54a6a26SSeth Howell 	struct nvmf_rpc_create_transport_ctx *ctx;
2593a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
259496073478SJacek Kalwas 	int rc;
2595a54a6a26SSeth Howell 
2596a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
2597a54a6a26SSeth Howell 	if (!ctx) {
2598a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR, "Out of memory");
2599a54a6a26SSeth Howell 		return;
2600a54a6a26SSeth Howell 	}
2601a54a6a26SSeth Howell 
2602a54a6a26SSeth Howell 	/* Decode parameters the first time to get the transport type */
2603f766d1e4SDarek Stojaczyk 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder,
2604a54a6a26SSeth Howell 					    SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
2605a54a6a26SSeth Howell 					    ctx)) {
2606f766d1e4SDarek Stojaczyk 		SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
2607a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2608a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2609a54a6a26SSeth Howell 		return;
2610a54a6a26SSeth Howell 	}
2611a54a6a26SSeth Howell 
2612f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2613a54a6a26SSeth Howell 	if (!tgt) {
2614a54a6a26SSeth Howell 		SPDK_ERRLOG("Unable to find a target object.\n");
2615a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2616a54a6a26SSeth Howell 						 "Unable to find a target.");
2617a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2618a54a6a26SSeth Howell 		return;
2619a54a6a26SSeth Howell 	}
2620a54a6a26SSeth Howell 
2621a54a6a26SSeth Howell 	/* Initialize all the transport options (based on transport type) and decode the
2622a54a6a26SSeth Howell 	 * parameters again to update any options passed in rpc create transport call.
2623a54a6a26SSeth Howell 	 */
26243b16c6ddSZiye Yang 	if (!spdk_nvmf_transport_opts_init(ctx->trtype, &ctx->opts, sizeof(ctx->opts))) {
2625a54a6a26SSeth Howell 		/* This can happen if user specifies PCIE transport type which isn't valid for
2626a54a6a26SSeth Howell 		 * NVMe-oF.
2627a54a6a26SSeth Howell 		 */
2628a54a6a26SSeth Howell 		SPDK_ERRLOG("Invalid transport type '%s'\n", ctx->trtype);
2629a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
263010f712bcSwanghailiangx 						     "Invalid transport type '%s'", ctx->trtype);
2631a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2632a54a6a26SSeth Howell 		return;
2633a54a6a26SSeth Howell 	}
2634a54a6a26SSeth Howell 
2635f766d1e4SDarek Stojaczyk 	if (spdk_json_decode_object_relaxed(params, nvmf_rpc_create_transport_decoder,
2636a54a6a26SSeth Howell 					    SPDK_COUNTOF(nvmf_rpc_create_transport_decoder),
2637a54a6a26SSeth Howell 					    ctx)) {
2638f766d1e4SDarek Stojaczyk 		SPDK_ERRLOG("spdk_json_decode_object_relaxed failed\n");
2639a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2640a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2641a54a6a26SSeth Howell 		return;
2642a54a6a26SSeth Howell 	}
2643a54a6a26SSeth Howell 
2644b397546eSSeth Howell 	if (spdk_nvmf_tgt_get_transport(tgt, ctx->trtype)) {
2645a54a6a26SSeth Howell 		SPDK_ERRLOG("Transport type '%s' already exists\n", ctx->trtype);
2646a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
264710f712bcSwanghailiangx 						     "Transport type '%s' already exists", ctx->trtype);
2648a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2649a54a6a26SSeth Howell 		return;
2650a54a6a26SSeth Howell 	}
2651a54a6a26SSeth Howell 
2652f766d1e4SDarek Stojaczyk 	/* Transport can parse additional params themselves */
2653f766d1e4SDarek Stojaczyk 	ctx->opts.transport_specific = params;
265496073478SJacek Kalwas 	ctx->request = request;
2655f766d1e4SDarek Stojaczyk 
265696073478SJacek Kalwas 	rc = spdk_nvmf_transport_create_async(ctx->trtype, &ctx->opts, nvmf_rpc_create_transport_done, ctx);
265796073478SJacek Kalwas 	if (rc) {
2658a54a6a26SSeth Howell 		SPDK_ERRLOG("Transport type '%s' create failed\n", ctx->trtype);
2659a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
266010f712bcSwanghailiangx 						     "Transport type '%s' create failed", ctx->trtype);
2661a54a6a26SSeth Howell 		nvmf_rpc_create_transport_ctx_free(ctx);
2662a54a6a26SSeth Howell 	}
2663a54a6a26SSeth Howell }
2664e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_create_transport", rpc_nvmf_create_transport, SPDK_RPC_RUNTIME)
2665a54a6a26SSeth Howell 
2666f8433aadSSeth Howell struct rpc_get_transport {
2667fb335cb2SJacek Kalwas 	char *trtype;
2668f8433aadSSeth Howell 	char *tgt_name;
2669f8433aadSSeth Howell };
2670f8433aadSSeth Howell 
2671f8433aadSSeth Howell static const struct spdk_json_object_decoder rpc_get_transport_decoders[] = {
2672fb335cb2SJacek Kalwas 	{"trtype", offsetof(struct rpc_get_transport, trtype), spdk_json_decode_string, true},
2673f8433aadSSeth Howell 	{"tgt_name", offsetof(struct rpc_get_transport, tgt_name), spdk_json_decode_string, true},
2674f8433aadSSeth Howell };
2675f8433aadSSeth Howell 
2676a54a6a26SSeth Howell static void
2677e569a578SSeth Howell rpc_nvmf_get_transports(struct spdk_jsonrpc_request *request,
2678a54a6a26SSeth Howell 			const struct spdk_json_val *params)
2679a54a6a26SSeth Howell {
2680f8433aadSSeth Howell 	struct rpc_get_transport req = { 0 };
2681a54a6a26SSeth Howell 	struct spdk_json_write_ctx *w;
2682fb335cb2SJacek Kalwas 	struct spdk_nvmf_transport *transport = NULL;
2683a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
2684a54a6a26SSeth Howell 
2685f8433aadSSeth Howell 	if (params) {
2686f8433aadSSeth Howell 		if (spdk_json_decode_object(params, rpc_get_transport_decoders,
2687f8433aadSSeth Howell 					    SPDK_COUNTOF(rpc_get_transport_decoders),
2688f8433aadSSeth Howell 					    &req)) {
2689f8433aadSSeth Howell 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
2690f8433aadSSeth Howell 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2691a54a6a26SSeth Howell 			return;
2692a54a6a26SSeth Howell 		}
2693f8433aadSSeth Howell 	}
2694a54a6a26SSeth Howell 
2695f8433aadSSeth Howell 	tgt = spdk_nvmf_get_tgt(req.tgt_name);
2696a54a6a26SSeth Howell 	if (!tgt) {
2697a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2698a54a6a26SSeth Howell 						 "Unable to find a target.");
2699fb335cb2SJacek Kalwas 		free(req.trtype);
2700f8433aadSSeth Howell 		free(req.tgt_name);
2701a54a6a26SSeth Howell 		return;
2702a54a6a26SSeth Howell 	}
2703a54a6a26SSeth Howell 
2704fb335cb2SJacek Kalwas 	if (req.trtype) {
2705fb335cb2SJacek Kalwas 		transport = spdk_nvmf_tgt_get_transport(tgt, req.trtype);
2706fb335cb2SJacek Kalwas 		if (transport == NULL) {
2707fb335cb2SJacek Kalwas 			SPDK_ERRLOG("transport '%s' does not exist\n", req.trtype);
2708fb335cb2SJacek Kalwas 			spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
2709fb335cb2SJacek Kalwas 			free(req.trtype);
2710fb335cb2SJacek Kalwas 			free(req.tgt_name);
2711fb335cb2SJacek Kalwas 			return;
2712fb335cb2SJacek Kalwas 		}
2713fb335cb2SJacek Kalwas 	}
2714fb335cb2SJacek Kalwas 
2715a54a6a26SSeth Howell 	w = spdk_jsonrpc_begin_result(request);
2716a54a6a26SSeth Howell 	spdk_json_write_array_begin(w);
2717fb335cb2SJacek Kalwas 
2718fb335cb2SJacek Kalwas 	if (transport) {
2719220bcf7dSJacek Kalwas 		nvmf_transport_dump_opts(transport, w, false);
2720fb335cb2SJacek Kalwas 	} else {
2721fb335cb2SJacek Kalwas 		for (transport = spdk_nvmf_transport_get_first(tgt); transport != NULL;
2722fb335cb2SJacek Kalwas 		     transport = spdk_nvmf_transport_get_next(transport)) {
2723fb335cb2SJacek Kalwas 			nvmf_transport_dump_opts(transport, w, false);
2724a54a6a26SSeth Howell 		}
2725fb335cb2SJacek Kalwas 	}
2726fb335cb2SJacek Kalwas 
2727a54a6a26SSeth Howell 	spdk_json_write_array_end(w);
2728a54a6a26SSeth Howell 	spdk_jsonrpc_end_result(request, w);
2729fb335cb2SJacek Kalwas 	free(req.trtype);
2730f8433aadSSeth Howell 	free(req.tgt_name);
2731a54a6a26SSeth Howell }
2732e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_get_transports", rpc_nvmf_get_transports, SPDK_RPC_RUNTIME)
2733a54a6a26SSeth Howell 
2734a54a6a26SSeth Howell struct rpc_nvmf_get_stats_ctx {
2735f8433aadSSeth Howell 	char *tgt_name;
2736a54a6a26SSeth Howell 	struct spdk_nvmf_tgt *tgt;
2737a54a6a26SSeth Howell 	struct spdk_jsonrpc_request *request;
2738a54a6a26SSeth Howell 	struct spdk_json_write_ctx *w;
2739a54a6a26SSeth Howell };
2740a54a6a26SSeth Howell 
2741f8433aadSSeth Howell static const struct spdk_json_object_decoder rpc_get_stats_decoders[] = {
2742f8433aadSSeth Howell 	{"tgt_name", offsetof(struct rpc_nvmf_get_stats_ctx, tgt_name), spdk_json_decode_string, true},
2743f8433aadSSeth Howell };
2744f8433aadSSeth Howell 
2745f8433aadSSeth Howell static void
2746f8433aadSSeth Howell free_get_stats_ctx(struct rpc_nvmf_get_stats_ctx *ctx)
2747f8433aadSSeth Howell {
2748f8433aadSSeth Howell 	free(ctx->tgt_name);
2749f8433aadSSeth Howell 	free(ctx);
2750f8433aadSSeth Howell }
2751f8433aadSSeth Howell 
2752a54a6a26SSeth Howell static void
2753a54a6a26SSeth Howell rpc_nvmf_get_stats_done(struct spdk_io_channel_iter *i, int status)
2754a54a6a26SSeth Howell {
2755a54a6a26SSeth Howell 	struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2756a54a6a26SSeth Howell 
2757a54a6a26SSeth Howell 	spdk_json_write_array_end(ctx->w);
2758a54a6a26SSeth Howell 	spdk_json_write_object_end(ctx->w);
2759a54a6a26SSeth Howell 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
2760f8433aadSSeth Howell 	free_get_stats_ctx(ctx);
2761a54a6a26SSeth Howell }
2762a54a6a26SSeth Howell 
2763a54a6a26SSeth Howell static void
2764e569a578SSeth Howell _rpc_nvmf_get_stats(struct spdk_io_channel_iter *i)
2765a54a6a26SSeth Howell {
2766a54a6a26SSeth Howell 	struct rpc_nvmf_get_stats_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
27678dfa1067SMaciej Szulik 	struct spdk_io_channel *ch;
27688dfa1067SMaciej Szulik 	struct spdk_nvmf_poll_group *group;
2769a54a6a26SSeth Howell 
27708dfa1067SMaciej Szulik 	ch = spdk_get_io_channel(ctx->tgt);
27718dfa1067SMaciej Szulik 	group = spdk_io_channel_get_ctx(ch);
2772a54a6a26SSeth Howell 
27738dfa1067SMaciej Szulik 	spdk_nvmf_poll_group_dump_stat(group, ctx->w);
2774a54a6a26SSeth Howell 
27758dfa1067SMaciej Szulik 	spdk_put_io_channel(ch);
2776a54a6a26SSeth Howell 	spdk_for_each_channel_continue(i, 0);
2777a54a6a26SSeth Howell }
2778a54a6a26SSeth Howell 
2779a54a6a26SSeth Howell 
2780a54a6a26SSeth Howell static void
2781e569a578SSeth Howell rpc_nvmf_get_stats(struct spdk_jsonrpc_request *request,
2782a54a6a26SSeth Howell 		   const struct spdk_json_val *params)
2783a54a6a26SSeth Howell {
2784a54a6a26SSeth Howell 	struct rpc_nvmf_get_stats_ctx *ctx;
2785a54a6a26SSeth Howell 
2786a54a6a26SSeth Howell 	ctx = calloc(1, sizeof(*ctx));
2787a54a6a26SSeth Howell 	if (!ctx) {
2788a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2789a54a6a26SSeth Howell 						 "Memory allocation error");
2790a54a6a26SSeth Howell 		return;
2791a54a6a26SSeth Howell 	}
2792a54a6a26SSeth Howell 	ctx->request = request;
2793a54a6a26SSeth Howell 
2794f8433aadSSeth Howell 	if (params) {
2795f8433aadSSeth Howell 		if (spdk_json_decode_object(params, rpc_get_stats_decoders,
2796f8433aadSSeth Howell 					    SPDK_COUNTOF(rpc_get_stats_decoders),
2797f8433aadSSeth Howell 					    ctx)) {
2798f8433aadSSeth Howell 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
2799f8433aadSSeth Howell 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
2800f8433aadSSeth Howell 			free_get_stats_ctx(ctx);
2801f8433aadSSeth Howell 			return;
2802f8433aadSSeth Howell 		}
2803f8433aadSSeth Howell 	}
2804f8433aadSSeth Howell 
2805f8433aadSSeth Howell 	ctx->tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
2806a54a6a26SSeth Howell 	if (!ctx->tgt) {
2807a54a6a26SSeth Howell 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2808a54a6a26SSeth Howell 						 "Unable to find a target.");
2809f8433aadSSeth Howell 		free_get_stats_ctx(ctx);
2810a54a6a26SSeth Howell 		return;
2811a54a6a26SSeth Howell 	}
2812a54a6a26SSeth Howell 
2813a54a6a26SSeth Howell 	ctx->w = spdk_jsonrpc_begin_result(ctx->request);
2814a54a6a26SSeth Howell 	spdk_json_write_object_begin(ctx->w);
2815a54a6a26SSeth Howell 	spdk_json_write_named_uint64(ctx->w, "tick_rate", spdk_get_ticks_hz());
2816a54a6a26SSeth Howell 	spdk_json_write_named_array_begin(ctx->w, "poll_groups");
2817a54a6a26SSeth Howell 
2818a54a6a26SSeth Howell 	spdk_for_each_channel(ctx->tgt,
2819e569a578SSeth Howell 			      _rpc_nvmf_get_stats,
2820a54a6a26SSeth Howell 			      ctx,
2821a54a6a26SSeth Howell 			      rpc_nvmf_get_stats_done);
2822a54a6a26SSeth Howell }
2823a54a6a26SSeth Howell 
2824e569a578SSeth Howell SPDK_RPC_REGISTER("nvmf_get_stats", rpc_nvmf_get_stats, SPDK_RPC_RUNTIME)
28254cc04a12SShuhei Matsumoto 
28264cc04a12SShuhei Matsumoto static void
28274cc04a12SShuhei Matsumoto dump_nvmf_ctrlr(struct spdk_json_write_ctx *w, struct spdk_nvmf_ctrlr *ctrlr)
28284cc04a12SShuhei Matsumoto {
28294cc04a12SShuhei Matsumoto 	uint32_t count;
28304cc04a12SShuhei Matsumoto 
28314cc04a12SShuhei Matsumoto 	spdk_json_write_object_begin(w);
28324cc04a12SShuhei Matsumoto 
28334cc04a12SShuhei Matsumoto 	spdk_json_write_named_uint32(w, "cntlid", ctrlr->cntlid);
28344cc04a12SShuhei Matsumoto 	spdk_json_write_named_string(w, "hostnqn", ctrlr->hostnqn);
28358cffbe01SKonrad Sztyber 	spdk_json_write_named_uuid(w, "hostid", &ctrlr->hostid);
28364cc04a12SShuhei Matsumoto 
28374cc04a12SShuhei Matsumoto 	count = spdk_bit_array_count_set(ctrlr->qpair_mask);
28384cc04a12SShuhei Matsumoto 	spdk_json_write_named_uint32(w, "num_io_qpairs", count);
28394cc04a12SShuhei Matsumoto 
28404cc04a12SShuhei Matsumoto 	spdk_json_write_object_end(w);
28414cc04a12SShuhei Matsumoto }
28424cc04a12SShuhei Matsumoto 
284383eb352bSShuhei Matsumoto static const char *
284483eb352bSShuhei Matsumoto nvmf_qpair_state_str(enum spdk_nvmf_qpair_state state)
284583eb352bSShuhei Matsumoto {
284683eb352bSShuhei Matsumoto 	switch (state) {
284783eb352bSShuhei Matsumoto 	case SPDK_NVMF_QPAIR_UNINITIALIZED:
284883eb352bSShuhei Matsumoto 		return "uninitialized";
2849db221b40SKonrad Sztyber 	case SPDK_NVMF_QPAIR_CONNECTING:
2850db221b40SKonrad Sztyber 		return "connecting";
2851781d42adSKonrad Sztyber 	case SPDK_NVMF_QPAIR_ENABLED:
2852781d42adSKonrad Sztyber 		return "enabled";
285383eb352bSShuhei Matsumoto 	case SPDK_NVMF_QPAIR_DEACTIVATING:
285483eb352bSShuhei Matsumoto 		return "deactivating";
285583eb352bSShuhei Matsumoto 	case SPDK_NVMF_QPAIR_ERROR:
285683eb352bSShuhei Matsumoto 		return "error";
285783eb352bSShuhei Matsumoto 	default:
285883eb352bSShuhei Matsumoto 		return NULL;
285983eb352bSShuhei Matsumoto 	}
286083eb352bSShuhei Matsumoto }
286183eb352bSShuhei Matsumoto 
286283eb352bSShuhei Matsumoto static void
286383eb352bSShuhei Matsumoto dump_nvmf_qpair(struct spdk_json_write_ctx *w, struct spdk_nvmf_qpair *qpair)
286483eb352bSShuhei Matsumoto {
286566ec2569SKonrad Sztyber 	struct spdk_nvme_transport_id trid = {};
286683eb352bSShuhei Matsumoto 
286783eb352bSShuhei Matsumoto 	spdk_json_write_object_begin(w);
286883eb352bSShuhei Matsumoto 
286983eb352bSShuhei Matsumoto 	spdk_json_write_named_uint32(w, "cntlid", qpair->ctrlr->cntlid);
287083eb352bSShuhei Matsumoto 	spdk_json_write_named_uint32(w, "qid", qpair->qid);
287183eb352bSShuhei Matsumoto 	spdk_json_write_named_string(w, "state", nvmf_qpair_state_str(qpair->state));
28729e6e8d1dSKonrad Sztyber 	spdk_json_write_named_string(w, "thread", spdk_thread_get_name(spdk_get_thread()));
28738a4b7226SKonrad Sztyber 	spdk_json_write_named_string(w, "hostnqn", qpair->ctrlr->hostnqn);
287483eb352bSShuhei Matsumoto 
287566ec2569SKonrad Sztyber 	if (spdk_nvmf_qpair_get_listen_trid(qpair, &trid) == 0) {
2876f5260201SWojciech Panfil 		spdk_json_write_named_object_begin(w, "listen_address");
287766ec2569SKonrad Sztyber 		nvmf_transport_listen_dump_trid(&trid, w);
2878f5260201SWojciech Panfil 		spdk_json_write_object_end(w);
2879f5260201SWojciech Panfil 		if (qpair->transport->ops->listen_dump_opts) {
288066ec2569SKonrad Sztyber 			qpair->transport->ops->listen_dump_opts(qpair->transport, &trid, w);
2881f5260201SWojciech Panfil 		}
28825c9a8a3cSShuhei Matsumoto 	}
288383eb352bSShuhei Matsumoto 
288466ec2569SKonrad Sztyber 	memset(&trid, 0, sizeof(trid));
288566ec2569SKonrad Sztyber 	if (spdk_nvmf_qpair_get_peer_trid(qpair, &trid) == 0) {
288666ec2569SKonrad Sztyber 		spdk_json_write_named_object_begin(w, "peer_address");
288766ec2569SKonrad Sztyber 		nvmf_transport_listen_dump_trid(&trid, w);
288866ec2569SKonrad Sztyber 		spdk_json_write_object_end(w);
288966ec2569SKonrad Sztyber 	}
289066ec2569SKonrad Sztyber 
28918e817b0cSKonrad Sztyber 	nvmf_qpair_auth_dump(qpair, w);
289283eb352bSShuhei Matsumoto 	spdk_json_write_object_end(w);
289383eb352bSShuhei Matsumoto }
289483eb352bSShuhei Matsumoto 
28959c1d6483SShuhei Matsumoto static const char *
28969c1d6483SShuhei Matsumoto nvme_ana_state_str(enum spdk_nvme_ana_state ana_state)
28979c1d6483SShuhei Matsumoto {
28989c1d6483SShuhei Matsumoto 	switch (ana_state) {
28999c1d6483SShuhei Matsumoto 	case SPDK_NVME_ANA_OPTIMIZED_STATE:
29009c1d6483SShuhei Matsumoto 		return "optimized";
29019c1d6483SShuhei Matsumoto 	case SPDK_NVME_ANA_NON_OPTIMIZED_STATE:
29029c1d6483SShuhei Matsumoto 		return "non_optimized";
29039c1d6483SShuhei Matsumoto 	case SPDK_NVME_ANA_INACCESSIBLE_STATE:
29049c1d6483SShuhei Matsumoto 		return "inaccessible";
29059c1d6483SShuhei Matsumoto 	case SPDK_NVME_ANA_PERSISTENT_LOSS_STATE:
29069c1d6483SShuhei Matsumoto 		return "persistent_loss";
29079c1d6483SShuhei Matsumoto 	case SPDK_NVME_ANA_CHANGE_STATE:
29089c1d6483SShuhei Matsumoto 		return "change";
29099c1d6483SShuhei Matsumoto 	default:
29109c1d6483SShuhei Matsumoto 		return NULL;
29119c1d6483SShuhei Matsumoto 	}
29129c1d6483SShuhei Matsumoto }
29139c1d6483SShuhei Matsumoto 
29149c1d6483SShuhei Matsumoto static void
29159c1d6483SShuhei Matsumoto dump_nvmf_subsystem_listener(struct spdk_json_write_ctx *w,
29169c1d6483SShuhei Matsumoto 			     struct spdk_nvmf_subsystem_listener *listener)
29179c1d6483SShuhei Matsumoto {
29189c1d6483SShuhei Matsumoto 	const struct spdk_nvme_transport_id *trid = listener->trid;
2919785d10b5SShuhei Matsumoto 	uint32_t i;
29209c1d6483SShuhei Matsumoto 
29219c1d6483SShuhei Matsumoto 	spdk_json_write_object_begin(w);
29229c1d6483SShuhei Matsumoto 
29239c1d6483SShuhei Matsumoto 	spdk_json_write_named_object_begin(w, "address");
2924f5260201SWojciech Panfil 	nvmf_transport_listen_dump_trid(trid, w);
29259c1d6483SShuhei Matsumoto 	spdk_json_write_object_end(w);
29269c1d6483SShuhei Matsumoto 
2927fb5650ceSAbhineet Pandey 	if (spdk_nvmf_subsystem_get_ana_reporting(listener->subsystem)) {
2928785d10b5SShuhei Matsumoto 		spdk_json_write_named_array_begin(w, "ana_states");
2929785d10b5SShuhei Matsumoto 		for (i = 0; i < listener->subsystem->max_nsid; i++) {
2930785d10b5SShuhei Matsumoto 			spdk_json_write_object_begin(w);
2931785d10b5SShuhei Matsumoto 			spdk_json_write_named_uint32(w, "ana_group", i + 1);
29329c1d6483SShuhei Matsumoto 			spdk_json_write_named_string(w, "ana_state",
2933785d10b5SShuhei Matsumoto 						     nvme_ana_state_str(listener->ana_state[i]));
2934785d10b5SShuhei Matsumoto 			spdk_json_write_object_end(w);
2935785d10b5SShuhei Matsumoto 		}
2936785d10b5SShuhei Matsumoto 		spdk_json_write_array_end(w);
29372a67deefSShuhei Matsumoto 	}
29389c1d6483SShuhei Matsumoto 
29399c1d6483SShuhei Matsumoto 	spdk_json_write_object_end(w);
29409c1d6483SShuhei Matsumoto }
29419c1d6483SShuhei Matsumoto 
2942f1c42383SShuhei Matsumoto struct rpc_subsystem_query_ctx {
29434cc04a12SShuhei Matsumoto 	char *nqn;
29444cc04a12SShuhei Matsumoto 	char *tgt_name;
29454cc04a12SShuhei Matsumoto 	struct spdk_nvmf_subsystem *subsystem;
29464cc04a12SShuhei Matsumoto 	struct spdk_jsonrpc_request *request;
29474cc04a12SShuhei Matsumoto 	struct spdk_json_write_ctx *w;
29484cc04a12SShuhei Matsumoto };
29494cc04a12SShuhei Matsumoto 
2950f1c42383SShuhei Matsumoto static const struct spdk_json_object_decoder rpc_subsystem_query_decoders[] = {
2951f1c42383SShuhei Matsumoto 	{"nqn", offsetof(struct rpc_subsystem_query_ctx, nqn), spdk_json_decode_string},
2952f1c42383SShuhei Matsumoto 	{"tgt_name", offsetof(struct rpc_subsystem_query_ctx, tgt_name), spdk_json_decode_string, true},
29534cc04a12SShuhei Matsumoto };
29544cc04a12SShuhei Matsumoto 
29554cc04a12SShuhei Matsumoto static void
2956f1c42383SShuhei Matsumoto free_rpc_subsystem_query_ctx(struct rpc_subsystem_query_ctx *ctx)
29574cc04a12SShuhei Matsumoto {
29584cc04a12SShuhei Matsumoto 	free(ctx->nqn);
29594cc04a12SShuhei Matsumoto 	free(ctx->tgt_name);
29604cc04a12SShuhei Matsumoto 	free(ctx);
29614cc04a12SShuhei Matsumoto }
29624cc04a12SShuhei Matsumoto 
29634cc04a12SShuhei Matsumoto static void
29644cc04a12SShuhei Matsumoto rpc_nvmf_get_controllers_paused(struct spdk_nvmf_subsystem *subsystem,
29654cc04a12SShuhei Matsumoto 				void *cb_arg, int status)
29664cc04a12SShuhei Matsumoto {
2967f1c42383SShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx = cb_arg;
29684cc04a12SShuhei Matsumoto 	struct spdk_json_write_ctx *w;
29694cc04a12SShuhei Matsumoto 	struct spdk_nvmf_ctrlr *ctrlr;
29704cc04a12SShuhei Matsumoto 
29714cc04a12SShuhei Matsumoto 	w = spdk_jsonrpc_begin_result(ctx->request);
29724cc04a12SShuhei Matsumoto 
29734cc04a12SShuhei Matsumoto 	spdk_json_write_array_begin(w);
29744cc04a12SShuhei Matsumoto 	TAILQ_FOREACH(ctrlr, &ctx->subsystem->ctrlrs, link) {
29754cc04a12SShuhei Matsumoto 		dump_nvmf_ctrlr(w, ctrlr);
29764cc04a12SShuhei Matsumoto 	}
29774cc04a12SShuhei Matsumoto 	spdk_json_write_array_end(w);
29784cc04a12SShuhei Matsumoto 
29794cc04a12SShuhei Matsumoto 	spdk_jsonrpc_end_result(ctx->request, w);
29804cc04a12SShuhei Matsumoto 
29814cc04a12SShuhei Matsumoto 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
29824cc04a12SShuhei Matsumoto 		SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
29834cc04a12SShuhei Matsumoto 		/* FIXME: RPC should fail if resuming the subsystem failed. */
29844cc04a12SShuhei Matsumoto 	}
29854cc04a12SShuhei Matsumoto 
2986f1c42383SShuhei Matsumoto 	free_rpc_subsystem_query_ctx(ctx);
29874cc04a12SShuhei Matsumoto }
29884cc04a12SShuhei Matsumoto 
29894cc04a12SShuhei Matsumoto static void
299083eb352bSShuhei Matsumoto rpc_nvmf_get_qpairs_done(struct spdk_io_channel_iter *i, int status)
299183eb352bSShuhei Matsumoto {
299283eb352bSShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
299383eb352bSShuhei Matsumoto 
299483eb352bSShuhei Matsumoto 	spdk_json_write_array_end(ctx->w);
299583eb352bSShuhei Matsumoto 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
299683eb352bSShuhei Matsumoto 
299783eb352bSShuhei Matsumoto 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
299883eb352bSShuhei Matsumoto 		SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
299983eb352bSShuhei Matsumoto 		/* FIXME: RPC should fail if resuming the subsystem failed. */
300083eb352bSShuhei Matsumoto 	}
300183eb352bSShuhei Matsumoto 
300283eb352bSShuhei Matsumoto 	free_rpc_subsystem_query_ctx(ctx);
300383eb352bSShuhei Matsumoto }
300483eb352bSShuhei Matsumoto 
300583eb352bSShuhei Matsumoto static void
300683eb352bSShuhei Matsumoto rpc_nvmf_get_qpairs(struct spdk_io_channel_iter *i)
300783eb352bSShuhei Matsumoto {
300883eb352bSShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
300983eb352bSShuhei Matsumoto 	struct spdk_io_channel *ch;
301083eb352bSShuhei Matsumoto 	struct spdk_nvmf_poll_group *group;
301183eb352bSShuhei Matsumoto 	struct spdk_nvmf_qpair *qpair;
301283eb352bSShuhei Matsumoto 
30136000920eSzhaoshushu.zss 	ch = spdk_io_channel_iter_get_channel(i);
301483eb352bSShuhei Matsumoto 	group = spdk_io_channel_get_ctx(ch);
301583eb352bSShuhei Matsumoto 
301683eb352bSShuhei Matsumoto 	TAILQ_FOREACH(qpair, &group->qpairs, link) {
301783eb352bSShuhei Matsumoto 		if (qpair->ctrlr->subsys == ctx->subsystem) {
301883eb352bSShuhei Matsumoto 			dump_nvmf_qpair(ctx->w, qpair);
301983eb352bSShuhei Matsumoto 		}
302083eb352bSShuhei Matsumoto 	}
302183eb352bSShuhei Matsumoto 
302283eb352bSShuhei Matsumoto 	spdk_for_each_channel_continue(i, 0);
302383eb352bSShuhei Matsumoto }
302483eb352bSShuhei Matsumoto 
302583eb352bSShuhei Matsumoto static void
302683eb352bSShuhei Matsumoto rpc_nvmf_get_qpairs_paused(struct spdk_nvmf_subsystem *subsystem,
302783eb352bSShuhei Matsumoto 			   void *cb_arg, int status)
302883eb352bSShuhei Matsumoto {
302983eb352bSShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx = cb_arg;
303083eb352bSShuhei Matsumoto 
303183eb352bSShuhei Matsumoto 	ctx->w = spdk_jsonrpc_begin_result(ctx->request);
303283eb352bSShuhei Matsumoto 
303383eb352bSShuhei Matsumoto 	spdk_json_write_array_begin(ctx->w);
303483eb352bSShuhei Matsumoto 
303583eb352bSShuhei Matsumoto 	spdk_for_each_channel(ctx->subsystem->tgt,
303683eb352bSShuhei Matsumoto 			      rpc_nvmf_get_qpairs,
303783eb352bSShuhei Matsumoto 			      ctx,
303883eb352bSShuhei Matsumoto 			      rpc_nvmf_get_qpairs_done);
303983eb352bSShuhei Matsumoto }
304083eb352bSShuhei Matsumoto 
304183eb352bSShuhei Matsumoto static void
30429c1d6483SShuhei Matsumoto rpc_nvmf_get_listeners_paused(struct spdk_nvmf_subsystem *subsystem,
30439c1d6483SShuhei Matsumoto 			      void *cb_arg, int status)
30449c1d6483SShuhei Matsumoto {
30459c1d6483SShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx = cb_arg;
30469c1d6483SShuhei Matsumoto 	struct spdk_json_write_ctx *w;
30479c1d6483SShuhei Matsumoto 	struct spdk_nvmf_subsystem_listener *listener;
30489c1d6483SShuhei Matsumoto 
30499c1d6483SShuhei Matsumoto 	w = spdk_jsonrpc_begin_result(ctx->request);
30509c1d6483SShuhei Matsumoto 
30519c1d6483SShuhei Matsumoto 	spdk_json_write_array_begin(w);
30529c1d6483SShuhei Matsumoto 
30539c1d6483SShuhei Matsumoto 	for (listener = spdk_nvmf_subsystem_get_first_listener(ctx->subsystem);
30549c1d6483SShuhei Matsumoto 	     listener != NULL;
30559c1d6483SShuhei Matsumoto 	     listener = spdk_nvmf_subsystem_get_next_listener(ctx->subsystem, listener)) {
30569c1d6483SShuhei Matsumoto 		dump_nvmf_subsystem_listener(w, listener);
30579c1d6483SShuhei Matsumoto 	}
30589c1d6483SShuhei Matsumoto 	spdk_json_write_array_end(w);
30599c1d6483SShuhei Matsumoto 
30609c1d6483SShuhei Matsumoto 	spdk_jsonrpc_end_result(ctx->request, w);
30619c1d6483SShuhei Matsumoto 
30629c1d6483SShuhei Matsumoto 	if (spdk_nvmf_subsystem_resume(ctx->subsystem, NULL, NULL)) {
30639c1d6483SShuhei Matsumoto 		SPDK_ERRLOG("Resuming subsystem with NQN %s failed\n", ctx->nqn);
30649c1d6483SShuhei Matsumoto 		/* FIXME: RPC should fail if resuming the subsystem failed. */
30659c1d6483SShuhei Matsumoto 	}
30669c1d6483SShuhei Matsumoto 
30679c1d6483SShuhei Matsumoto 	free_rpc_subsystem_query_ctx(ctx);
30689c1d6483SShuhei Matsumoto }
30699c1d6483SShuhei Matsumoto 
30709c1d6483SShuhei Matsumoto static void
3071f1c42383SShuhei Matsumoto _rpc_nvmf_subsystem_query(struct spdk_jsonrpc_request *request,
3072f1c42383SShuhei Matsumoto 			  const struct spdk_json_val *params,
3073f1c42383SShuhei Matsumoto 			  spdk_nvmf_subsystem_state_change_done cb_fn)
30744cc04a12SShuhei Matsumoto {
3075f1c42383SShuhei Matsumoto 	struct rpc_subsystem_query_ctx *ctx;
30764cc04a12SShuhei Matsumoto 	struct spdk_nvmf_subsystem *subsystem;
30774cc04a12SShuhei Matsumoto 	struct spdk_nvmf_tgt *tgt;
30784cc04a12SShuhei Matsumoto 
30794cc04a12SShuhei Matsumoto 	ctx = calloc(1, sizeof(*ctx));
30804cc04a12SShuhei Matsumoto 	if (!ctx) {
30814cc04a12SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
30824cc04a12SShuhei Matsumoto 						 "Out of memory");
30834cc04a12SShuhei Matsumoto 		return;
30844cc04a12SShuhei Matsumoto 	}
30854cc04a12SShuhei Matsumoto 
30864cc04a12SShuhei Matsumoto 	ctx->request = request;
30874cc04a12SShuhei Matsumoto 
3088f1c42383SShuhei Matsumoto 	if (spdk_json_decode_object(params, rpc_subsystem_query_decoders,
3089f1c42383SShuhei Matsumoto 				    SPDK_COUNTOF(rpc_subsystem_query_decoders),
30904cc04a12SShuhei Matsumoto 				    ctx)) {
30914cc04a12SShuhei Matsumoto 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
30924cc04a12SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
30934cc04a12SShuhei Matsumoto 						 "Invalid parameters");
3094f1c42383SShuhei Matsumoto 		free_rpc_subsystem_query_ctx(ctx);
30954cc04a12SShuhei Matsumoto 		return;
30964cc04a12SShuhei Matsumoto 	}
30974cc04a12SShuhei Matsumoto 
30984cc04a12SShuhei Matsumoto 	tgt = spdk_nvmf_get_tgt(ctx->tgt_name);
30994cc04a12SShuhei Matsumoto 	if (!tgt) {
31004cc04a12SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find a target object.\n");
31014cc04a12SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
31024cc04a12SShuhei Matsumoto 						 "Unable to find a target");
3103f1c42383SShuhei Matsumoto 		free_rpc_subsystem_query_ctx(ctx);
31044cc04a12SShuhei Matsumoto 		return;
31054cc04a12SShuhei Matsumoto 	}
31064cc04a12SShuhei Matsumoto 
31074cc04a12SShuhei Matsumoto 	subsystem = spdk_nvmf_tgt_find_subsystem(tgt, ctx->nqn);
31084cc04a12SShuhei Matsumoto 	if (!subsystem) {
31094cc04a12SShuhei Matsumoto 		SPDK_ERRLOG("Unable to find subsystem with NQN %s\n", ctx->nqn);
31104cc04a12SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
31114cc04a12SShuhei Matsumoto 						 "Invalid parameters");
3112f1c42383SShuhei Matsumoto 		free_rpc_subsystem_query_ctx(ctx);
31134cc04a12SShuhei Matsumoto 		return;
31144cc04a12SShuhei Matsumoto 	}
31154cc04a12SShuhei Matsumoto 
31164cc04a12SShuhei Matsumoto 	ctx->subsystem = subsystem;
31174cc04a12SShuhei Matsumoto 
3118312a9d60SBen Walker 	if (spdk_nvmf_subsystem_pause(subsystem, 0, cb_fn, ctx)) {
31194cc04a12SShuhei Matsumoto 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
31204cc04a12SShuhei Matsumoto 						 "Internal error");
3121f1c42383SShuhei Matsumoto 		free_rpc_subsystem_query_ctx(ctx);
31224cc04a12SShuhei Matsumoto 		return;
31234cc04a12SShuhei Matsumoto 	}
31244cc04a12SShuhei Matsumoto }
3125f1c42383SShuhei Matsumoto 
3126f1c42383SShuhei Matsumoto static void
3127f1c42383SShuhei Matsumoto rpc_nvmf_subsystem_get_controllers(struct spdk_jsonrpc_request *request,
3128f1c42383SShuhei Matsumoto 				   const struct spdk_json_val *params)
3129f1c42383SShuhei Matsumoto {
3130f1c42383SShuhei Matsumoto 	_rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_controllers_paused);
3131f1c42383SShuhei Matsumoto }
31324cc04a12SShuhei Matsumoto SPDK_RPC_REGISTER("nvmf_subsystem_get_controllers", rpc_nvmf_subsystem_get_controllers,
31334cc04a12SShuhei Matsumoto 		  SPDK_RPC_RUNTIME);
313483eb352bSShuhei Matsumoto 
313583eb352bSShuhei Matsumoto static void
313683eb352bSShuhei Matsumoto rpc_nvmf_subsystem_get_qpairs(struct spdk_jsonrpc_request *request,
313783eb352bSShuhei Matsumoto 			      const struct spdk_json_val *params)
313883eb352bSShuhei Matsumoto {
313983eb352bSShuhei Matsumoto 	_rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_qpairs_paused);
314083eb352bSShuhei Matsumoto }
314183eb352bSShuhei Matsumoto SPDK_RPC_REGISTER("nvmf_subsystem_get_qpairs", rpc_nvmf_subsystem_get_qpairs, SPDK_RPC_RUNTIME);
31429c1d6483SShuhei Matsumoto 
31439c1d6483SShuhei Matsumoto static void
31449c1d6483SShuhei Matsumoto rpc_nvmf_subsystem_get_listeners(struct spdk_jsonrpc_request *request,
31459c1d6483SShuhei Matsumoto 				 const struct spdk_json_val *params)
31469c1d6483SShuhei Matsumoto {
31479c1d6483SShuhei Matsumoto 	_rpc_nvmf_subsystem_query(request, params, rpc_nvmf_get_listeners_paused);
31489c1d6483SShuhei Matsumoto }
31499c1d6483SShuhei Matsumoto SPDK_RPC_REGISTER("nvmf_subsystem_get_listeners", rpc_nvmf_subsystem_get_listeners,
31509c1d6483SShuhei Matsumoto 		  SPDK_RPC_RUNTIME);
3151e2d54380Skyuho.son 
3152e2d54380Skyuho.son struct rpc_mdns_prr {
3153e2d54380Skyuho.son 	char *tgt_name;
3154e2d54380Skyuho.son };
3155e2d54380Skyuho.son 
3156e2d54380Skyuho.son static const struct spdk_json_object_decoder rpc_mdns_prr_decoders[] = {
3157e2d54380Skyuho.son 	{"tgt_name", offsetof(struct rpc_mdns_prr, tgt_name), spdk_json_decode_string, true},
3158e2d54380Skyuho.son };
3159e2d54380Skyuho.son 
3160e2d54380Skyuho.son static void
3161e2d54380Skyuho.son rpc_nvmf_publish_mdns_prr(struct spdk_jsonrpc_request *request,
3162e2d54380Skyuho.son 			  const struct spdk_json_val *params)
3163e2d54380Skyuho.son {
3164e2d54380Skyuho.son 	int rc;
3165e2d54380Skyuho.son 	struct rpc_mdns_prr req = { 0 };
3166e2d54380Skyuho.son 	struct spdk_nvmf_tgt *tgt;
3167e2d54380Skyuho.son 
3168e2d54380Skyuho.son 	if (params) {
3169e2d54380Skyuho.son 		if (spdk_json_decode_object(params, rpc_mdns_prr_decoders,
3170e2d54380Skyuho.son 					    SPDK_COUNTOF(rpc_mdns_prr_decoders),
3171e2d54380Skyuho.son 					    &req)) {
3172e2d54380Skyuho.son 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
3173e2d54380Skyuho.son 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
3174e2d54380Skyuho.son 			return;
3175e2d54380Skyuho.son 		}
3176e2d54380Skyuho.son 	}
3177e2d54380Skyuho.son 
3178e2d54380Skyuho.son 	tgt = spdk_nvmf_get_tgt(req.tgt_name);
3179e2d54380Skyuho.son 	if (!tgt) {
3180e2d54380Skyuho.son 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
3181e2d54380Skyuho.son 						 "Unable to find a target.");
3182e2d54380Skyuho.son 		free(req.tgt_name);
3183e2d54380Skyuho.son 		return;
3184e2d54380Skyuho.son 	}
3185e2d54380Skyuho.son 
3186e2d54380Skyuho.son 	rc = nvmf_publish_mdns_prr(tgt);
3187e2d54380Skyuho.son 	if (rc) {
3188e2d54380Skyuho.son 		spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
3189e2d54380Skyuho.son 		free(req.tgt_name);
3190e2d54380Skyuho.son 		return;
3191e2d54380Skyuho.son 	}
3192e2d54380Skyuho.son 
3193e2d54380Skyuho.son 	spdk_jsonrpc_send_bool_response(request, true);
3194e2d54380Skyuho.son 	free(req.tgt_name);
3195e2d54380Skyuho.son }
3196e2d54380Skyuho.son SPDK_RPC_REGISTER("nvmf_publish_mdns_prr", rpc_nvmf_publish_mdns_prr, SPDK_RPC_RUNTIME);
319748352fbbSkyuho.son 
319848352fbbSkyuho.son static void
319948352fbbSkyuho.son rpc_nvmf_stop_mdns_prr(struct spdk_jsonrpc_request *request,
320048352fbbSkyuho.son 		       const struct spdk_json_val *params)
320148352fbbSkyuho.son {
320248352fbbSkyuho.son 	struct rpc_mdns_prr req = { 0 };
320348352fbbSkyuho.son 	struct spdk_nvmf_tgt *tgt;
320448352fbbSkyuho.son 
320548352fbbSkyuho.son 	if (params) {
320648352fbbSkyuho.son 		if (spdk_json_decode_object(params, rpc_mdns_prr_decoders,
320748352fbbSkyuho.son 					    SPDK_COUNTOF(rpc_mdns_prr_decoders),
320848352fbbSkyuho.son 					    &req)) {
320948352fbbSkyuho.son 			SPDK_ERRLOG("spdk_json_decode_object failed\n");
321048352fbbSkyuho.son 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
321148352fbbSkyuho.son 			return;
321248352fbbSkyuho.son 		}
321348352fbbSkyuho.son 	}
321448352fbbSkyuho.son 
321548352fbbSkyuho.son 	tgt = spdk_nvmf_get_tgt(req.tgt_name);
321648352fbbSkyuho.son 	if (!tgt) {
321748352fbbSkyuho.son 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
321848352fbbSkyuho.son 						 "Unable to find a target.");
321948352fbbSkyuho.son 		free(req.tgt_name);
322048352fbbSkyuho.son 		return;
322148352fbbSkyuho.son 	}
322248352fbbSkyuho.son 
322348352fbbSkyuho.son 	nvmf_tgt_stop_mdns_prr(tgt);
322448352fbbSkyuho.son 
322548352fbbSkyuho.son 	spdk_jsonrpc_send_bool_response(request, true);
322648352fbbSkyuho.son 	free(req.tgt_name);
322748352fbbSkyuho.son }
322848352fbbSkyuho.son SPDK_RPC_REGISTER("nvmf_stop_mdns_prr", rpc_nvmf_stop_mdns_prr, SPDK_RPC_RUNTIME);
3229