xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 1f4f4cc75a522f897856e980a0b35d3c8fac24ed)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5  *   Copyright (c) Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "iscsi/iscsi.h"
36 #include "iscsi/conn.h"
37 #include "iscsi/tgt_node.h"
38 #include "iscsi/portal_grp.h"
39 #include "iscsi/init_grp.h"
40 
41 #include "spdk/rpc.h"
42 #include "spdk/util.h"
43 #include "spdk/event.h"
44 #include "spdk/string.h"
45 #include "spdk_internal/log.h"
46 
47 static void
48 rpc_iscsi_get_initiator_groups(struct spdk_jsonrpc_request *request,
49 			       const struct spdk_json_val *params)
50 {
51 	struct spdk_json_write_ctx *w;
52 
53 	if (params != NULL) {
54 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
55 						 "iscsi_get_initiator_groups requires no parameters");
56 		return;
57 	}
58 
59 	w = spdk_jsonrpc_begin_result(request);
60 	spdk_json_write_array_begin(w);
61 	iscsi_init_grps_info_json(w);
62 	spdk_json_write_array_end(w);
63 
64 	spdk_jsonrpc_end_result(request, w);
65 }
66 SPDK_RPC_REGISTER("iscsi_get_initiator_groups", rpc_iscsi_get_initiator_groups,
67 		  SPDK_RPC_RUNTIME)
68 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_initiator_groups, get_initiator_groups)
69 
70 struct rpc_initiator_list {
71 	size_t num_initiators;
72 	char *initiators[MAX_INITIATOR];
73 };
74 
75 static int
76 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
77 {
78 	struct rpc_initiator_list *list = out;
79 
80 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
81 				      &list->num_initiators, sizeof(char *));
82 }
83 
84 static void
85 free_rpc_initiator_list(struct rpc_initiator_list *list)
86 {
87 	size_t i;
88 
89 	for (i = 0; i < list->num_initiators; i++) {
90 		free(list->initiators[i]);
91 	}
92 }
93 
94 struct rpc_netmask_list {
95 	size_t num_netmasks;
96 	char *netmasks[MAX_NETMASK];
97 };
98 
99 static int
100 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
101 {
102 	struct rpc_netmask_list *list = out;
103 
104 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
105 				      &list->num_netmasks, sizeof(char *));
106 }
107 
108 static void
109 free_rpc_netmask_list(struct rpc_netmask_list *list)
110 {
111 	size_t i;
112 
113 	for (i = 0; i < list->num_netmasks; i++) {
114 		free(list->netmasks[i]);
115 	}
116 }
117 
118 struct rpc_initiator_group {
119 	int32_t tag;
120 	struct rpc_initiator_list initiator_list;
121 	struct rpc_netmask_list netmask_list;
122 };
123 
124 static void
125 free_rpc_initiator_group(struct rpc_initiator_group *ig)
126 {
127 	free_rpc_initiator_list(&ig->initiator_list);
128 	free_rpc_netmask_list(&ig->netmask_list);
129 }
130 
131 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
132 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
133 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
134 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
135 };
136 
137 static void
138 rpc_iscsi_create_initiator_group(struct spdk_jsonrpc_request *request,
139 				 const struct spdk_json_val *params)
140 {
141 	struct rpc_initiator_group req = {};
142 	struct spdk_json_write_ctx *w;
143 
144 	if (spdk_json_decode_object(params, rpc_initiator_group_decoders,
145 				    SPDK_COUNTOF(rpc_initiator_group_decoders), &req)) {
146 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
147 		goto invalid;
148 	}
149 
150 	if (req.initiator_list.num_initiators == 0 ||
151 	    req.netmask_list.num_netmasks == 0) {
152 		goto invalid;
153 	}
154 
155 	if (iscsi_init_grp_create_from_initiator_list(req.tag,
156 			req.initiator_list.num_initiators,
157 			req.initiator_list.initiators,
158 			req.netmask_list.num_netmasks,
159 			req.netmask_list.netmasks)) {
160 		SPDK_ERRLOG("create_from_initiator_list failed\n");
161 		goto invalid;
162 	}
163 
164 	free_rpc_initiator_group(&req);
165 
166 	w = spdk_jsonrpc_begin_result(request);
167 	spdk_json_write_bool(w, true);
168 	spdk_jsonrpc_end_result(request, w);
169 	return;
170 
171 invalid:
172 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
173 	free_rpc_initiator_group(&req);
174 }
175 SPDK_RPC_REGISTER("iscsi_create_initiator_group", rpc_iscsi_create_initiator_group,
176 		  SPDK_RPC_RUNTIME)
177 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_initiator_group, add_initiator_group)
178 
179 static const struct spdk_json_object_decoder rpc_add_or_delete_initiators_decoders[] = {
180 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
181 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list, true},
182 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list, true},
183 };
184 
185 static void
186 rpc_iscsi_initiator_group_add_initiators(struct spdk_jsonrpc_request *request,
187 		const struct spdk_json_val *params)
188 {
189 	struct rpc_initiator_group req = {};
190 	struct spdk_json_write_ctx *w;
191 
192 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
193 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
194 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
195 		goto invalid;
196 	}
197 
198 	if (iscsi_init_grp_add_initiators_from_initiator_list(req.tag,
199 			req.initiator_list.num_initiators,
200 			req.initiator_list.initiators,
201 			req.netmask_list.num_netmasks,
202 			req.netmask_list.netmasks)) {
203 		SPDK_ERRLOG("add_initiators_from_initiator_list failed\n");
204 		goto invalid;
205 	}
206 
207 	free_rpc_initiator_group(&req);
208 
209 	w = spdk_jsonrpc_begin_result(request);
210 	spdk_json_write_bool(w, true);
211 	spdk_jsonrpc_end_result(request, w);
212 	return;
213 
214 invalid:
215 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
216 	free_rpc_initiator_group(&req);
217 }
218 SPDK_RPC_REGISTER("iscsi_initiator_group_add_initiators",
219 		  rpc_iscsi_initiator_group_add_initiators, SPDK_RPC_RUNTIME)
220 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_initiator_group_add_initiators,
221 				   add_initiators_to_initiator_group)
222 
223 static void
224 rpc_iscsi_initiator_group_remove_initiators(struct spdk_jsonrpc_request *request,
225 		const struct spdk_json_val *params)
226 {
227 	struct rpc_initiator_group req = {};
228 	struct spdk_json_write_ctx *w;
229 
230 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
231 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
232 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
233 		goto invalid;
234 	}
235 
236 	if (iscsi_init_grp_delete_initiators_from_initiator_list(req.tag,
237 			req.initiator_list.num_initiators,
238 			req.initiator_list.initiators,
239 			req.netmask_list.num_netmasks,
240 			req.netmask_list.netmasks)) {
241 		SPDK_ERRLOG("delete_initiators_from_initiator_list failed\n");
242 		goto invalid;
243 	}
244 
245 	free_rpc_initiator_group(&req);
246 
247 	w = spdk_jsonrpc_begin_result(request);
248 	spdk_json_write_bool(w, true);
249 	spdk_jsonrpc_end_result(request, w);
250 	return;
251 
252 invalid:
253 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
254 	free_rpc_initiator_group(&req);
255 }
256 SPDK_RPC_REGISTER("iscsi_initiator_group_remove_initiators",
257 		  rpc_iscsi_initiator_group_remove_initiators, SPDK_RPC_RUNTIME)
258 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_initiator_group_remove_initiators,
259 				   delete_initiators_from_initiator_group)
260 
261 struct rpc_iscsi_delete_initiator_group {
262 	int32_t tag;
263 };
264 
265 static const struct spdk_json_object_decoder rpc_iscsi_delete_initiator_group_decoders[] = {
266 	{"tag", offsetof(struct rpc_iscsi_delete_initiator_group, tag), spdk_json_decode_int32},
267 };
268 
269 static void
270 rpc_iscsi_delete_initiator_group(struct spdk_jsonrpc_request *request,
271 				 const struct spdk_json_val *params)
272 {
273 	struct rpc_iscsi_delete_initiator_group req = {};
274 	struct spdk_json_write_ctx *w;
275 	struct spdk_iscsi_init_grp *ig;
276 
277 	if (spdk_json_decode_object(params, rpc_iscsi_delete_initiator_group_decoders,
278 				    SPDK_COUNTOF(rpc_iscsi_delete_initiator_group_decoders),
279 				    &req)) {
280 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
281 		goto invalid;
282 	}
283 
284 	ig = iscsi_init_grp_unregister(req.tag);
285 	if (!ig) {
286 		goto invalid;
287 	}
288 	iscsi_tgt_node_delete_map(NULL, ig);
289 	iscsi_init_grp_destroy(ig);
290 
291 	w = spdk_jsonrpc_begin_result(request);
292 	spdk_json_write_bool(w, true);
293 	spdk_jsonrpc_end_result(request, w);
294 	return;
295 
296 invalid:
297 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
298 }
299 SPDK_RPC_REGISTER("iscsi_delete_initiator_group", rpc_iscsi_delete_initiator_group,
300 		  SPDK_RPC_RUNTIME)
301 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_initiator_group, delete_initiator_group)
302 
303 static void
304 rpc_iscsi_get_target_nodes(struct spdk_jsonrpc_request *request,
305 			   const struct spdk_json_val *params)
306 {
307 	struct spdk_json_write_ctx *w;
308 
309 	if (params != NULL) {
310 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
311 						 "iscsi_get_target_nodes requires no parameters");
312 		return;
313 	}
314 
315 	w = spdk_jsonrpc_begin_result(request);
316 	spdk_json_write_array_begin(w);
317 	iscsi_tgt_nodes_info_json(w);
318 	spdk_json_write_array_end(w);
319 
320 	spdk_jsonrpc_end_result(request, w);
321 }
322 SPDK_RPC_REGISTER("iscsi_get_target_nodes", rpc_iscsi_get_target_nodes, SPDK_RPC_RUNTIME)
323 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_target_nodes, get_target_nodes)
324 
325 struct rpc_pg_ig_map {
326 	int32_t pg_tag;
327 	int32_t ig_tag;
328 };
329 
330 static const struct spdk_json_object_decoder rpc_pg_ig_map_decoders[] = {
331 	{"pg_tag", offsetof(struct rpc_pg_ig_map, pg_tag), spdk_json_decode_int32},
332 	{"ig_tag", offsetof(struct rpc_pg_ig_map, ig_tag), spdk_json_decode_int32},
333 };
334 
335 static int
336 decode_rpc_pg_ig_map(const struct spdk_json_val *val, void *out)
337 {
338 	struct rpc_pg_ig_map *pg_ig_map = out;
339 
340 	return spdk_json_decode_object(val, rpc_pg_ig_map_decoders,
341 				       SPDK_COUNTOF(rpc_pg_ig_map_decoders),
342 				       pg_ig_map);
343 }
344 
345 struct rpc_pg_ig_maps {
346 	size_t num_maps;
347 	struct rpc_pg_ig_map maps[MAX_TARGET_MAP];
348 };
349 
350 static int
351 decode_rpc_pg_ig_maps(const struct spdk_json_val *val, void *out)
352 {
353 	struct rpc_pg_ig_maps *pg_ig_maps = out;
354 
355 	return spdk_json_decode_array(val, decode_rpc_pg_ig_map, pg_ig_maps->maps,
356 				      MAX_TARGET_MAP, &pg_ig_maps->num_maps,
357 				      sizeof(struct rpc_pg_ig_map));
358 }
359 
360 #define RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN	64
361 
362 struct rpc_lun {
363 	char *bdev_name;
364 	int32_t lun_id;
365 };
366 
367 static const struct spdk_json_object_decoder rpc_lun_decoders[] = {
368 	{"bdev_name", offsetof(struct rpc_lun, bdev_name), spdk_json_decode_string},
369 	{"lun_id", offsetof(struct rpc_lun, lun_id), spdk_json_decode_int32},
370 };
371 
372 static int
373 decode_rpc_lun(const struct spdk_json_val *val, void *out)
374 {
375 	struct rpc_lun *lun = out;
376 
377 	return spdk_json_decode_object(val, rpc_lun_decoders,
378 				       SPDK_COUNTOF(rpc_lun_decoders), lun);
379 }
380 
381 struct rpc_luns {
382 	size_t num_luns;
383 	struct rpc_lun luns[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN];
384 };
385 
386 static int
387 decode_rpc_luns(const struct spdk_json_val *val, void *out)
388 {
389 	struct rpc_luns *luns = out;
390 
391 	return spdk_json_decode_array(val, decode_rpc_lun, luns->luns,
392 				      RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN,
393 				      &luns->num_luns, sizeof(struct rpc_lun));
394 }
395 
396 static void
397 free_rpc_luns(struct rpc_luns *p)
398 {
399 	size_t i;
400 
401 	for (i = 0; i < p->num_luns; i++) {
402 		free(p->luns[i].bdev_name);
403 	}
404 }
405 
406 struct rpc_target_node {
407 	char *name;
408 	char *alias_name;
409 
410 	struct rpc_pg_ig_maps pg_ig_maps;
411 	struct rpc_luns luns;
412 
413 	int32_t queue_depth;
414 	bool disable_chap;
415 	bool require_chap;
416 	bool mutual_chap;
417 	int32_t chap_group;
418 
419 	bool header_digest;
420 	bool data_digest;
421 };
422 
423 static void
424 free_rpc_target_node(struct rpc_target_node *req)
425 {
426 	free(req->name);
427 	free(req->alias_name);
428 	free_rpc_luns(&req->luns);
429 }
430 
431 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
432 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
433 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
434 	{"pg_ig_maps", offsetof(struct rpc_target_node, pg_ig_maps), decode_rpc_pg_ig_maps},
435 	{"luns", offsetof(struct rpc_target_node, luns), decode_rpc_luns},
436 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
437 	{"disable_chap", offsetof(struct rpc_target_node, disable_chap), spdk_json_decode_bool, true},
438 	{"require_chap", offsetof(struct rpc_target_node, require_chap), spdk_json_decode_bool, true},
439 	{"mutual_chap", offsetof(struct rpc_target_node, mutual_chap), spdk_json_decode_bool, true},
440 	{"chap_group", offsetof(struct rpc_target_node, chap_group), spdk_json_decode_int32, true},
441 	{"header_digest", offsetof(struct rpc_target_node, header_digest), spdk_json_decode_bool, true},
442 	{"data_digest", offsetof(struct rpc_target_node, data_digest), spdk_json_decode_bool, true},
443 };
444 
445 static void
446 rpc_iscsi_create_target_node(struct spdk_jsonrpc_request *request,
447 			     const struct spdk_json_val *params)
448 {
449 	struct rpc_target_node req = {};
450 	struct spdk_json_write_ctx *w;
451 	struct spdk_iscsi_tgt_node *target;
452 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
453 	char *bdev_names[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN] = {0};
454 	int32_t lun_ids[RPC_ISCSI_CREATE_TARGET_NODE_MAX_LUN] = {0};
455 	size_t i;
456 
457 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
458 				    SPDK_COUNTOF(rpc_target_node_decoders),
459 				    &req)) {
460 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
461 		goto invalid;
462 	}
463 
464 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
465 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
466 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
467 	}
468 
469 	for (i = 0; i < req.luns.num_luns; i++) {
470 		bdev_names[i] = req.luns.luns[i].bdev_name;
471 		lun_ids[i] = req.luns.luns[i].lun_id;
472 	}
473 
474 	/*
475 	 * Use default parameters in a few places:
476 	 *  index = -1 : automatically pick an index for the new target node
477 	 *  alias = NULL
478 	 */
479 	target = iscsi_tgt_node_construct(-1, req.name, req.alias_name,
480 					  pg_tags,
481 					  ig_tags,
482 					  req.pg_ig_maps.num_maps,
483 					  (const char **)bdev_names,
484 					  lun_ids,
485 					  req.luns.num_luns,
486 					  req.queue_depth,
487 					  req.disable_chap,
488 					  req.require_chap,
489 					  req.mutual_chap,
490 					  req.chap_group,
491 					  req.header_digest,
492 					  req.data_digest);
493 
494 	if (target == NULL) {
495 		goto invalid;
496 	}
497 
498 	free_rpc_target_node(&req);
499 
500 	w = spdk_jsonrpc_begin_result(request);
501 	spdk_json_write_bool(w, true);
502 	spdk_jsonrpc_end_result(request, w);
503 	return;
504 
505 invalid:
506 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
507 	free_rpc_target_node(&req);
508 }
509 SPDK_RPC_REGISTER("iscsi_create_target_node", rpc_iscsi_create_target_node, SPDK_RPC_RUNTIME)
510 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_target_node, construct_target_node)
511 
512 struct rpc_tgt_node_pg_ig_maps {
513 	char *name;
514 	struct rpc_pg_ig_maps pg_ig_maps;
515 };
516 
517 static const struct spdk_json_object_decoder rpc_tgt_node_pg_ig_maps_decoders[] = {
518 	{"name", offsetof(struct rpc_tgt_node_pg_ig_maps, name), spdk_json_decode_string},
519 	{"pg_ig_maps", offsetof(struct rpc_tgt_node_pg_ig_maps, pg_ig_maps), decode_rpc_pg_ig_maps},
520 };
521 
522 static void
523 rpc_iscsi_target_node_add_pg_ig_maps(struct spdk_jsonrpc_request *request,
524 				     const struct spdk_json_val *params)
525 {
526 	struct rpc_tgt_node_pg_ig_maps req = {};
527 	struct spdk_json_write_ctx *w;
528 	struct spdk_iscsi_tgt_node *target;
529 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
530 	size_t i;
531 	int rc;
532 
533 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
534 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
535 				    &req)) {
536 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
537 		goto invalid;
538 	}
539 
540 	target = iscsi_find_tgt_node(req.name);
541 	if (target == NULL) {
542 		SPDK_ERRLOG("target is not found\n");
543 		goto invalid;
544 	}
545 
546 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
547 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
548 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
549 	}
550 
551 	rc = iscsi_target_node_add_pg_ig_maps(target, pg_tags, ig_tags,
552 					      req.pg_ig_maps.num_maps);
553 	if (rc < 0) {
554 		SPDK_ERRLOG("add pg-ig maps failed\n");
555 		goto invalid;
556 	}
557 
558 	free(req.name);
559 
560 	w = spdk_jsonrpc_begin_result(request);
561 	spdk_json_write_bool(w, true);
562 	spdk_jsonrpc_end_result(request, w);
563 	return;
564 
565 invalid:
566 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
567 					 "Invalid parameters");
568 	free(req.name);
569 }
570 SPDK_RPC_REGISTER("iscsi_target_node_add_pg_ig_maps",
571 		  rpc_iscsi_target_node_add_pg_ig_maps, SPDK_RPC_RUNTIME)
572 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_add_pg_ig_maps, add_pg_ig_maps)
573 
574 static void
575 rpc_iscsi_target_node_remove_pg_ig_maps(struct spdk_jsonrpc_request *request,
576 					const struct spdk_json_val *params)
577 {
578 	struct rpc_tgt_node_pg_ig_maps req = {};
579 	struct spdk_json_write_ctx *w;
580 	struct spdk_iscsi_tgt_node *target;
581 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
582 	size_t i;
583 	int rc;
584 
585 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
586 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
587 				    &req)) {
588 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
589 		goto invalid;
590 	}
591 
592 	target = iscsi_find_tgt_node(req.name);
593 	if (target == NULL) {
594 		SPDK_ERRLOG("target is not found\n");
595 		goto invalid;
596 	}
597 
598 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
599 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
600 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
601 	}
602 
603 	rc = iscsi_target_node_remove_pg_ig_maps(target, pg_tags, ig_tags,
604 			req.pg_ig_maps.num_maps);
605 	if (rc < 0) {
606 		SPDK_ERRLOG("remove pg-ig maps failed\n");
607 		goto invalid;
608 	}
609 
610 	free(req.name);
611 
612 	w = spdk_jsonrpc_begin_result(request);
613 	spdk_json_write_bool(w, true);
614 	spdk_jsonrpc_end_result(request, w);
615 	return;
616 
617 invalid:
618 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
619 					 "Invalid parameters");
620 	free(req.name);
621 }
622 SPDK_RPC_REGISTER("iscsi_target_node_remove_pg_ig_maps",
623 		  rpc_iscsi_target_node_remove_pg_ig_maps, SPDK_RPC_RUNTIME)
624 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_remove_pg_ig_maps,
625 				   delete_pg_ig_maps)
626 
627 struct rpc_iscsi_delete_target_node {
628 	char *name;
629 };
630 
631 static void
632 free_rpc_iscsi_delete_target_node(struct rpc_iscsi_delete_target_node *r)
633 {
634 	free(r->name);
635 }
636 
637 static const struct spdk_json_object_decoder rpc_iscsi_delete_target_node_decoders[] = {
638 	{"name", offsetof(struct rpc_iscsi_delete_target_node, name), spdk_json_decode_string},
639 };
640 
641 struct rpc_iscsi_delete_target_node_ctx {
642 	struct rpc_iscsi_delete_target_node req;
643 	struct spdk_jsonrpc_request *request;
644 };
645 
646 static void
647 rpc_iscsi_delete_target_node_done(void *cb_arg, int rc)
648 {
649 	struct rpc_iscsi_delete_target_node_ctx *ctx = cb_arg;
650 	struct spdk_json_write_ctx *w;
651 
652 	free_rpc_iscsi_delete_target_node(&ctx->req);
653 
654 	w = spdk_jsonrpc_begin_result(ctx->request);
655 	spdk_json_write_bool(w, rc == 0);
656 	spdk_jsonrpc_end_result(ctx->request, w);
657 
658 	free(ctx);
659 }
660 
661 static void
662 rpc_iscsi_delete_target_node(struct spdk_jsonrpc_request *request,
663 			     const struct spdk_json_val *params)
664 {
665 	struct rpc_iscsi_delete_target_node_ctx *ctx;
666 
667 	ctx = calloc(1, sizeof(*ctx));
668 	if (!ctx) {
669 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
670 						 spdk_strerror(ENOMEM));
671 		return;
672 	}
673 
674 	if (spdk_json_decode_object(params, rpc_iscsi_delete_target_node_decoders,
675 				    SPDK_COUNTOF(rpc_iscsi_delete_target_node_decoders),
676 				    &ctx->req)) {
677 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
678 		goto invalid;
679 	}
680 
681 	if (ctx->req.name == NULL) {
682 		SPDK_ERRLOG("missing name param\n");
683 		goto invalid;
684 	}
685 
686 	ctx->request = request;
687 
688 	iscsi_shutdown_tgt_node_by_name(ctx->req.name,
689 					rpc_iscsi_delete_target_node_done, ctx);
690 	return;
691 
692 invalid:
693 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
694 	free_rpc_iscsi_delete_target_node(&ctx->req);
695 	free(ctx);
696 }
697 SPDK_RPC_REGISTER("iscsi_delete_target_node", rpc_iscsi_delete_target_node, SPDK_RPC_RUNTIME)
698 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_target_node, delete_target_node)
699 
700 static void
701 rpc_iscsi_get_portal_groups(struct spdk_jsonrpc_request *request,
702 			    const struct spdk_json_val *params)
703 {
704 	struct spdk_json_write_ctx *w;
705 
706 	if (params != NULL) {
707 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
708 						 "iscsi_get_portal_groups requires no parameters");
709 		return;
710 	}
711 
712 	w = spdk_jsonrpc_begin_result(request);
713 	spdk_json_write_array_begin(w);
714 	iscsi_portal_grps_info_json(w);
715 	spdk_json_write_array_end(w);
716 
717 	spdk_jsonrpc_end_result(request, w);
718 }
719 SPDK_RPC_REGISTER("iscsi_get_portal_groups", rpc_iscsi_get_portal_groups, SPDK_RPC_RUNTIME)
720 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_portal_groups, get_portal_groups)
721 
722 struct rpc_portal {
723 	char *host;
724 	char *port;
725 };
726 
727 struct rpc_portal_list {
728 	size_t num_portals;
729 	struct rpc_portal portals[MAX_PORTAL];
730 };
731 
732 struct rpc_portal_group {
733 	int32_t tag;
734 	struct rpc_portal_list portal_list;
735 };
736 
737 static void
738 free_rpc_portal(struct rpc_portal *portal)
739 {
740 	free(portal->host);
741 	free(portal->port);
742 }
743 
744 static void
745 free_rpc_portal_list(struct rpc_portal_list *pl)
746 {
747 	size_t i;
748 
749 	for (i = 0; i < pl->num_portals; i++) {
750 		free_rpc_portal(&pl->portals[i]);
751 	}
752 	pl->num_portals = 0;
753 }
754 
755 static void
756 free_rpc_portal_group(struct rpc_portal_group *pg)
757 {
758 	free_rpc_portal_list(&pg->portal_list);
759 }
760 
761 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
762 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
763 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
764 };
765 
766 static int
767 decode_rpc_portal(const struct spdk_json_val *val, void *out)
768 {
769 	struct rpc_portal *portal = out;
770 
771 	return spdk_json_decode_object(val, rpc_portal_decoders,
772 				       SPDK_COUNTOF(rpc_portal_decoders),
773 				       portal);
774 }
775 
776 static int
777 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
778 {
779 	struct rpc_portal_list *list = out;
780 
781 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
782 				      sizeof(struct rpc_portal));
783 }
784 
785 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
786 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
787 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
788 };
789 
790 static void
791 rpc_iscsi_create_portal_group(struct spdk_jsonrpc_request *request,
792 			      const struct spdk_json_val *params)
793 {
794 	struct rpc_portal_group req = {};
795 	struct spdk_iscsi_portal_grp *pg = NULL;
796 	struct spdk_iscsi_portal *portal;
797 	struct spdk_json_write_ctx *w;
798 	size_t i = 0;
799 	int rc = -1;
800 
801 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
802 				    SPDK_COUNTOF(rpc_portal_group_decoders),
803 				    &req)) {
804 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
805 		goto out;
806 	}
807 
808 	pg = iscsi_portal_grp_create(req.tag);
809 	if (pg == NULL) {
810 		SPDK_ERRLOG("portal_grp_create failed\n");
811 		goto out;
812 	}
813 	for (i = 0; i < req.portal_list.num_portals; i++) {
814 		portal = iscsi_portal_create(req.portal_list.portals[i].host,
815 					     req.portal_list.portals[i].port);
816 		if (portal == NULL) {
817 			SPDK_ERRLOG("portal_create failed\n");
818 			goto out;
819 		}
820 		iscsi_portal_grp_add_portal(pg, portal);
821 	}
822 
823 	rc = iscsi_portal_grp_open(pg);
824 	if (rc != 0) {
825 		SPDK_ERRLOG("portal_grp_open failed\n");
826 		goto out;
827 	}
828 
829 	rc = iscsi_portal_grp_register(pg);
830 	if (rc != 0) {
831 		SPDK_ERRLOG("portal_grp_register failed\n");
832 	}
833 
834 out:
835 	if (rc == 0) {
836 		w = spdk_jsonrpc_begin_result(request);
837 		spdk_json_write_bool(w, true);
838 		spdk_jsonrpc_end_result(request, w);
839 	} else {
840 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
841 
842 		if (pg != NULL) {
843 			iscsi_portal_grp_release(pg);
844 		}
845 	}
846 	free_rpc_portal_group(&req);
847 }
848 SPDK_RPC_REGISTER("iscsi_create_portal_group", rpc_iscsi_create_portal_group, SPDK_RPC_RUNTIME)
849 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_portal_group, add_portal_group)
850 
851 struct rpc_iscsi_delete_portal_group {
852 	int32_t tag;
853 };
854 
855 static const struct spdk_json_object_decoder rpc_iscsi_delete_portal_group_decoders[] = {
856 	{"tag", offsetof(struct rpc_iscsi_delete_portal_group, tag), spdk_json_decode_int32},
857 };
858 
859 static void
860 rpc_iscsi_delete_portal_group(struct spdk_jsonrpc_request *request,
861 			      const struct spdk_json_val *params)
862 {
863 	struct rpc_iscsi_delete_portal_group req = {};
864 	struct spdk_json_write_ctx *w;
865 	struct spdk_iscsi_portal_grp *pg;
866 
867 	if (spdk_json_decode_object(params, rpc_iscsi_delete_portal_group_decoders,
868 				    SPDK_COUNTOF(rpc_iscsi_delete_portal_group_decoders),
869 				    &req)) {
870 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
871 		goto invalid;
872 	}
873 
874 	pg = iscsi_portal_grp_unregister(req.tag);
875 	if (!pg) {
876 		goto invalid;
877 	}
878 
879 	iscsi_tgt_node_delete_map(pg, NULL);
880 	iscsi_portal_grp_release(pg);
881 
882 	w = spdk_jsonrpc_begin_result(request);
883 	spdk_json_write_bool(w, true);
884 	spdk_jsonrpc_end_result(request, w);
885 	return;
886 
887 invalid:
888 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
889 }
890 SPDK_RPC_REGISTER("iscsi_delete_portal_group", rpc_iscsi_delete_portal_group, SPDK_RPC_RUNTIME)
891 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_portal_group, delete_portal_group)
892 
893 struct rpc_portal_group_auth {
894 	int32_t tag;
895 	bool disable_chap;
896 	bool require_chap;
897 	bool mutual_chap;
898 	int32_t chap_group;
899 };
900 
901 static const struct spdk_json_object_decoder rpc_portal_group_auth_decoders[] = {
902 	{"tag", offsetof(struct rpc_portal_group_auth, tag), spdk_json_decode_int32},
903 	{"disable_chap", offsetof(struct rpc_portal_group_auth, disable_chap), spdk_json_decode_bool, true},
904 	{"require_chap", offsetof(struct rpc_portal_group_auth, require_chap), spdk_json_decode_bool, true},
905 	{"mutual_chap", offsetof(struct rpc_portal_group_auth, mutual_chap), spdk_json_decode_bool, true},
906 	{"chap_group", offsetof(struct rpc_portal_group_auth, chap_group), spdk_json_decode_int32, true},
907 };
908 
909 static void
910 rpc_iscsi_portal_group_set_auth(struct spdk_jsonrpc_request *request,
911 				const struct spdk_json_val *params)
912 {
913 	struct rpc_portal_group_auth req = {};
914 	struct spdk_json_write_ctx *w;
915 	struct spdk_iscsi_portal_grp *pg;
916 	int rc;
917 
918 	if (spdk_json_decode_object(params, rpc_portal_group_auth_decoders,
919 				    SPDK_COUNTOF(rpc_portal_group_auth_decoders), &req)) {
920 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
921 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
922 						 "Invalid parameters");
923 		return;
924 	}
925 
926 	pthread_mutex_lock(&g_iscsi.mutex);
927 
928 	pg = iscsi_portal_grp_find_by_tag(req.tag);
929 	if (pg == NULL) {
930 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
931 						     "Could not find portal group %d", req.tag);
932 		goto exit;
933 	}
934 
935 	rc = iscsi_portal_grp_set_chap_params(pg, req.disable_chap, req.require_chap,
936 					      req.mutual_chap, req.chap_group);
937 	if (rc < 0) {
938 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
939 						 "Invalid combination of auth params");
940 		goto exit;
941 	}
942 
943 	pthread_mutex_unlock(&g_iscsi.mutex);
944 
945 	w = spdk_jsonrpc_begin_result(request);
946 	spdk_json_write_bool(w, true);
947 	spdk_jsonrpc_end_result(request, w);
948 
949 	return;
950 
951 exit:
952 	pthread_mutex_unlock(&g_iscsi.mutex);
953 }
954 SPDK_RPC_REGISTER("iscsi_portal_group_set_auth", rpc_iscsi_portal_group_set_auth,
955 		  SPDK_RPC_RUNTIME)
956 
957 struct rpc_iscsi_get_connections_ctx {
958 	struct spdk_jsonrpc_request *request;
959 	struct spdk_json_write_ctx *w;
960 };
961 
962 static void
963 _rpc_iscsi_get_connections_done(struct spdk_io_channel_iter *i, int status)
964 {
965 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
966 
967 	spdk_json_write_array_end(ctx->w);
968 	spdk_jsonrpc_end_result(ctx->request, ctx->w);
969 
970 	free(ctx);
971 }
972 
973 static void
974 _rpc_iscsi_get_connections(struct spdk_io_channel_iter *i)
975 {
976 	struct rpc_iscsi_get_connections_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
977 	struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
978 	struct spdk_iscsi_poll_group *pg = spdk_io_channel_get_ctx(ch);
979 	struct spdk_iscsi_conn *conn;
980 
981 	STAILQ_FOREACH(conn, &pg->connections, link) {
982 		iscsi_conn_info_json(ctx->w, conn);
983 	}
984 
985 	spdk_for_each_channel_continue(i, 0);
986 }
987 
988 static void
989 rpc_iscsi_get_connections(struct spdk_jsonrpc_request *request,
990 			  const struct spdk_json_val *params)
991 {
992 	struct rpc_iscsi_get_connections_ctx *ctx;
993 
994 	if (params != NULL) {
995 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
996 						 "iscsi_get_connections requires no parameters");
997 		return;
998 	}
999 
1000 	ctx = calloc(1, sizeof(struct rpc_iscsi_get_connections_ctx));
1001 	if (ctx == NULL) {
1002 		SPDK_ERRLOG("Failed to allocate rpc_get_iscsi_conns_ctx struct\n");
1003 		spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1004 		return;
1005 	}
1006 
1007 	ctx->request = request;
1008 	ctx->w = spdk_jsonrpc_begin_result(request);
1009 
1010 	spdk_json_write_array_begin(ctx->w);
1011 
1012 	spdk_for_each_channel(&g_iscsi,
1013 			      _rpc_iscsi_get_connections,
1014 			      ctx,
1015 			      _rpc_iscsi_get_connections_done);
1016 }
1017 SPDK_RPC_REGISTER("iscsi_get_connections", rpc_iscsi_get_connections, SPDK_RPC_RUNTIME)
1018 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_connections, get_iscsi_connections)
1019 
1020 struct rpc_target_lun {
1021 	char *name;
1022 	char *bdev_name;
1023 	int32_t lun_id;
1024 };
1025 
1026 static void
1027 free_rpc_target_lun(struct rpc_target_lun *req)
1028 {
1029 	free(req->name);
1030 	free(req->bdev_name);
1031 }
1032 
1033 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
1034 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
1035 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
1036 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
1037 };
1038 
1039 static void
1040 rpc_iscsi_target_node_add_lun(struct spdk_jsonrpc_request *request,
1041 			      const struct spdk_json_val *params)
1042 {
1043 	struct rpc_target_lun req = {};
1044 	struct spdk_json_write_ctx *w;
1045 	struct spdk_iscsi_tgt_node *target;
1046 	int rc;
1047 
1048 	req.lun_id = -1;
1049 
1050 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
1051 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
1052 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1053 		goto invalid;
1054 	}
1055 
1056 	target = iscsi_find_tgt_node(req.name);
1057 	if (target == NULL) {
1058 		SPDK_ERRLOG("target is not found\n");
1059 		goto invalid;
1060 	}
1061 
1062 	rc = iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1063 	if (rc < 0) {
1064 		SPDK_ERRLOG("add lun failed\n");
1065 		goto invalid;
1066 	}
1067 
1068 	free_rpc_target_lun(&req);
1069 
1070 	w = spdk_jsonrpc_begin_result(request);
1071 	spdk_json_write_bool(w, true);
1072 	spdk_jsonrpc_end_result(request, w);
1073 	return;
1074 
1075 invalid:
1076 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1077 					 "Invalid parameters");
1078 	free_rpc_target_lun(&req);
1079 }
1080 SPDK_RPC_REGISTER("iscsi_target_node_add_lun", rpc_iscsi_target_node_add_lun, SPDK_RPC_RUNTIME)
1081 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_add_lun, target_node_add_lun)
1082 
1083 struct rpc_target_auth {
1084 	char *name;
1085 	bool disable_chap;
1086 	bool require_chap;
1087 	bool mutual_chap;
1088 	int32_t chap_group;
1089 };
1090 
1091 static void
1092 free_rpc_target_auth(struct rpc_target_auth *req)
1093 {
1094 	free(req->name);
1095 }
1096 
1097 static const struct spdk_json_object_decoder rpc_target_auth_decoders[] = {
1098 	{"name", offsetof(struct rpc_target_auth, name), spdk_json_decode_string},
1099 	{"disable_chap", offsetof(struct rpc_target_auth, disable_chap), spdk_json_decode_bool, true},
1100 	{"require_chap", offsetof(struct rpc_target_auth, require_chap), spdk_json_decode_bool, true},
1101 	{"mutual_chap", offsetof(struct rpc_target_auth, mutual_chap), spdk_json_decode_bool, true},
1102 	{"chap_group", offsetof(struct rpc_target_auth, chap_group), spdk_json_decode_int32, true},
1103 };
1104 
1105 static void
1106 rpc_iscsi_target_node_set_auth(struct spdk_jsonrpc_request *request,
1107 			       const struct spdk_json_val *params)
1108 {
1109 	struct rpc_target_auth req = {};
1110 	struct spdk_json_write_ctx *w;
1111 	struct spdk_iscsi_tgt_node *target;
1112 	int rc;
1113 
1114 	if (spdk_json_decode_object(params, rpc_target_auth_decoders,
1115 				    SPDK_COUNTOF(rpc_target_auth_decoders), &req)) {
1116 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1117 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1118 						 "Invalid parameters");
1119 		goto exit;
1120 	}
1121 
1122 	target = iscsi_find_tgt_node(req.name);
1123 	if (target == NULL) {
1124 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1125 						     "Could not find target %s", req.name);
1126 		goto exit;
1127 	}
1128 
1129 	rc = iscsi_tgt_node_set_chap_params(target, req.disable_chap, req.require_chap,
1130 					    req.mutual_chap, req.chap_group);
1131 	if (rc < 0) {
1132 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1133 						 "Invalid combination of auth params");
1134 		goto exit;
1135 	}
1136 
1137 	free_rpc_target_auth(&req);
1138 
1139 	w = spdk_jsonrpc_begin_result(request);
1140 	spdk_json_write_bool(w, true);
1141 	spdk_jsonrpc_end_result(request, w);
1142 	return;
1143 
1144 exit:
1145 	free_rpc_target_auth(&req);
1146 }
1147 SPDK_RPC_REGISTER("iscsi_target_node_set_auth", rpc_iscsi_target_node_set_auth,
1148 		  SPDK_RPC_RUNTIME)
1149 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_target_node_set_auth, set_iscsi_target_node_auth)
1150 
1151 static void
1152 rpc_iscsi_get_options(struct spdk_jsonrpc_request *request,
1153 		      const struct spdk_json_val *params)
1154 {
1155 	struct spdk_json_write_ctx *w;
1156 
1157 	if (params != NULL) {
1158 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1159 						 "iscsi_get_options requires no parameters");
1160 		return;
1161 	}
1162 
1163 	w = spdk_jsonrpc_begin_result(request);
1164 	iscsi_opts_info_json(w);
1165 
1166 	spdk_jsonrpc_end_result(request, w);
1167 }
1168 SPDK_RPC_REGISTER("iscsi_get_options", rpc_iscsi_get_options, SPDK_RPC_RUNTIME)
1169 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_options, get_iscsi_global_params)
1170 
1171 struct rpc_discovery_auth {
1172 	bool disable_chap;
1173 	bool require_chap;
1174 	bool mutual_chap;
1175 	int32_t chap_group;
1176 };
1177 
1178 static const struct spdk_json_object_decoder rpc_discovery_auth_decoders[] = {
1179 	{"disable_chap", offsetof(struct rpc_discovery_auth, disable_chap), spdk_json_decode_bool, true},
1180 	{"require_chap", offsetof(struct rpc_discovery_auth, require_chap), spdk_json_decode_bool, true},
1181 	{"mutual_chap", offsetof(struct rpc_discovery_auth, mutual_chap), spdk_json_decode_bool, true},
1182 	{"chap_group", offsetof(struct rpc_discovery_auth, chap_group), spdk_json_decode_int32, true},
1183 };
1184 
1185 static void
1186 rpc_iscsi_set_discovery_auth(struct spdk_jsonrpc_request *request,
1187 			     const struct spdk_json_val *params)
1188 {
1189 	struct rpc_discovery_auth req = {};
1190 	struct spdk_json_write_ctx *w;
1191 	int rc;
1192 
1193 	if (spdk_json_decode_object(params, rpc_discovery_auth_decoders,
1194 				    SPDK_COUNTOF(rpc_discovery_auth_decoders), &req)) {
1195 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1196 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1197 						 "Invalid parameters");
1198 		return;
1199 	}
1200 
1201 	rc = iscsi_set_discovery_auth(req.disable_chap, req.require_chap,
1202 				      req.mutual_chap, req.chap_group);
1203 	if (rc < 0) {
1204 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1205 						 "Invalid combination of CHAP params");
1206 		return;
1207 	}
1208 
1209 	w = spdk_jsonrpc_begin_result(request);
1210 	spdk_json_write_bool(w, true);
1211 	spdk_jsonrpc_end_result(request, w);
1212 }
1213 SPDK_RPC_REGISTER("iscsi_set_discovery_auth", rpc_iscsi_set_discovery_auth, SPDK_RPC_RUNTIME)
1214 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_discovery_auth, set_iscsi_discovery_auth)
1215 
1216 #define MAX_AUTH_SECRETS	64
1217 
1218 struct rpc_auth_secret {
1219 	char *user;
1220 	char *secret;
1221 	char *muser;
1222 	char *msecret;
1223 };
1224 
1225 static void
1226 free_rpc_auth_secret(struct rpc_auth_secret *_secret)
1227 {
1228 	free(_secret->user);
1229 	free(_secret->secret);
1230 	free(_secret->muser);
1231 	free(_secret->msecret);
1232 }
1233 
1234 static const struct spdk_json_object_decoder rpc_auth_secret_decoders[] = {
1235 	{"user", offsetof(struct rpc_auth_secret, user), spdk_json_decode_string},
1236 	{"secret", offsetof(struct rpc_auth_secret, secret), spdk_json_decode_string},
1237 	{"muser", offsetof(struct rpc_auth_secret, muser), spdk_json_decode_string, true},
1238 	{"msecret", offsetof(struct rpc_auth_secret, msecret), spdk_json_decode_string, true},
1239 };
1240 
1241 static int
1242 decode_rpc_auth_secret(const struct spdk_json_val *val, void *out)
1243 {
1244 	struct rpc_auth_secret *_secret = out;
1245 
1246 	return spdk_json_decode_object(val, rpc_auth_secret_decoders,
1247 				       SPDK_COUNTOF(rpc_auth_secret_decoders), _secret);
1248 }
1249 
1250 struct rpc_auth_secrets {
1251 	size_t num_secret;
1252 	struct rpc_auth_secret secrets[MAX_AUTH_SECRETS];
1253 };
1254 
1255 static void
1256 free_rpc_auth_secrets(struct rpc_auth_secrets *secrets)
1257 {
1258 	size_t i;
1259 
1260 	for (i = 0; i < secrets->num_secret; i++) {
1261 		free_rpc_auth_secret(&secrets->secrets[i]);
1262 	}
1263 }
1264 
1265 static int
1266 decode_rpc_auth_secrets(const struct spdk_json_val *val, void *out)
1267 {
1268 	struct rpc_auth_secrets *secrets = out;
1269 
1270 	return spdk_json_decode_array(val, decode_rpc_auth_secret, secrets->secrets,
1271 				      MAX_AUTH_SECRETS, &secrets->num_secret,
1272 				      sizeof(struct rpc_auth_secret));
1273 }
1274 
1275 struct rpc_auth_group {
1276 	int32_t tag;
1277 	struct rpc_auth_secrets secrets;
1278 };
1279 
1280 static void
1281 free_rpc_auth_group(struct rpc_auth_group *group)
1282 {
1283 	free_rpc_auth_secrets(&group->secrets);
1284 }
1285 
1286 static const struct spdk_json_object_decoder rpc_auth_group_decoders[] = {
1287 	{"tag", offsetof(struct rpc_auth_group, tag), spdk_json_decode_int32},
1288 	{"secrets", offsetof(struct rpc_auth_group, secrets), decode_rpc_auth_secrets, true},
1289 };
1290 
1291 static void
1292 rpc_iscsi_create_auth_group(struct spdk_jsonrpc_request *request,
1293 			    const struct spdk_json_val *params)
1294 {
1295 	struct rpc_auth_group req = {};
1296 	struct rpc_auth_secret *_secret;
1297 	struct spdk_json_write_ctx *w;
1298 	struct spdk_iscsi_auth_group *group = NULL;
1299 	int rc;
1300 	size_t i;
1301 
1302 	if (spdk_json_decode_object(params, rpc_auth_group_decoders,
1303 				    SPDK_COUNTOF(rpc_auth_group_decoders), &req)) {
1304 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1305 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1306 						 "Invalid parameters");
1307 		free_rpc_auth_group(&req);
1308 		return;
1309 	}
1310 
1311 	pthread_mutex_lock(&g_iscsi.mutex);
1312 
1313 	rc = iscsi_add_auth_group(req.tag, &group);
1314 	if (rc != 0) {
1315 		pthread_mutex_unlock(&g_iscsi.mutex);
1316 
1317 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1318 						     "Could not add auth group (%d), %s",
1319 						     req.tag, spdk_strerror(-rc));
1320 		free_rpc_auth_group(&req);
1321 		return;
1322 	}
1323 
1324 	for (i = 0; i < req.secrets.num_secret; i++) {
1325 		_secret = &req.secrets.secrets[i];
1326 		rc = iscsi_auth_group_add_secret(group, _secret->user, _secret->secret,
1327 						 _secret->muser, _secret->msecret);
1328 		if (rc != 0) {
1329 			iscsi_delete_auth_group(group);
1330 			pthread_mutex_unlock(&g_iscsi.mutex);
1331 
1332 			spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1333 							     "Could not add secret to auth group (%d), %s",
1334 							     req.tag, spdk_strerror(-rc));
1335 			free_rpc_auth_group(&req);
1336 			return;
1337 		}
1338 	}
1339 
1340 	pthread_mutex_unlock(&g_iscsi.mutex);
1341 
1342 	free_rpc_auth_group(&req);
1343 
1344 	w = spdk_jsonrpc_begin_result(request);
1345 	spdk_json_write_bool(w, true);
1346 	spdk_jsonrpc_end_result(request, w);
1347 }
1348 SPDK_RPC_REGISTER("iscsi_create_auth_group", rpc_iscsi_create_auth_group, SPDK_RPC_RUNTIME)
1349 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_create_auth_group, add_iscsi_auth_group)
1350 
1351 struct rpc_delete_auth_group {
1352 	int32_t tag;
1353 };
1354 
1355 static const struct spdk_json_object_decoder rpc_delete_auth_group_decoders[] = {
1356 	{"tag", offsetof(struct rpc_delete_auth_group, tag), spdk_json_decode_int32},
1357 };
1358 
1359 static void
1360 rpc_iscsi_delete_auth_group(struct spdk_jsonrpc_request *request,
1361 			    const struct spdk_json_val *params)
1362 {
1363 	struct rpc_delete_auth_group req = {};
1364 	struct spdk_json_write_ctx *w;
1365 	struct spdk_iscsi_auth_group *group;
1366 
1367 	if (spdk_json_decode_object(params, rpc_delete_auth_group_decoders,
1368 				    SPDK_COUNTOF(rpc_delete_auth_group_decoders), &req)) {
1369 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1370 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1371 						 "Invalid parameters");
1372 		return;
1373 	}
1374 
1375 	pthread_mutex_lock(&g_iscsi.mutex);
1376 
1377 	group = iscsi_find_auth_group_by_tag(req.tag);
1378 	if (group == NULL) {
1379 		pthread_mutex_unlock(&g_iscsi.mutex);
1380 
1381 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1382 						     "Could not find auth group (%d)", req.tag);
1383 		return;
1384 	}
1385 
1386 	iscsi_delete_auth_group(group);
1387 
1388 	pthread_mutex_unlock(&g_iscsi.mutex);
1389 
1390 	w = spdk_jsonrpc_begin_result(request);
1391 	spdk_json_write_bool(w, true);
1392 	spdk_jsonrpc_end_result(request, w);
1393 }
1394 SPDK_RPC_REGISTER("iscsi_delete_auth_group", rpc_iscsi_delete_auth_group, SPDK_RPC_RUNTIME)
1395 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_delete_auth_group, delete_iscsi_auth_group)
1396 
1397 struct rpc_add_auth_secret {
1398 	int32_t tag;
1399 	char *user;
1400 	char *secret;
1401 	char *muser;
1402 	char *msecret;
1403 };
1404 
1405 static void
1406 free_rpc_add_auth_secret(struct rpc_add_auth_secret *_secret)
1407 {
1408 	free(_secret->user);
1409 	free(_secret->secret);
1410 	free(_secret->muser);
1411 	free(_secret->msecret);
1412 }
1413 
1414 static const struct spdk_json_object_decoder rpc_add_auth_secret_decoders[] = {
1415 	{"tag", offsetof(struct rpc_add_auth_secret, tag), spdk_json_decode_int32},
1416 	{"user", offsetof(struct rpc_add_auth_secret, user), spdk_json_decode_string},
1417 	{"secret", offsetof(struct rpc_add_auth_secret, secret), spdk_json_decode_string},
1418 	{"muser", offsetof(struct rpc_add_auth_secret, muser), spdk_json_decode_string, true},
1419 	{"msecret", offsetof(struct rpc_add_auth_secret, msecret), spdk_json_decode_string, true},
1420 };
1421 
1422 static void
1423 rpc_iscsi_auth_group_add_secret(struct spdk_jsonrpc_request *request,
1424 				const struct spdk_json_val *params)
1425 {
1426 	struct rpc_add_auth_secret req = {};
1427 	struct spdk_json_write_ctx *w;
1428 	struct spdk_iscsi_auth_group *group;
1429 	int rc;
1430 
1431 	if (spdk_json_decode_object(params, rpc_add_auth_secret_decoders,
1432 				    SPDK_COUNTOF(rpc_add_auth_secret_decoders), &req)) {
1433 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1434 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1435 						 "Invalid parameters");
1436 		free_rpc_add_auth_secret(&req);
1437 		return;
1438 	}
1439 
1440 	pthread_mutex_lock(&g_iscsi.mutex);
1441 
1442 	group = iscsi_find_auth_group_by_tag(req.tag);
1443 	if (group == NULL) {
1444 		pthread_mutex_unlock(&g_iscsi.mutex);
1445 
1446 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1447 						     "Could not find auth group (%d)", req.tag);
1448 		free_rpc_add_auth_secret(&req);
1449 		return;
1450 	}
1451 
1452 	rc = iscsi_auth_group_add_secret(group, req.user, req.secret, req.muser, req.msecret);
1453 	if (rc != 0) {
1454 		pthread_mutex_unlock(&g_iscsi.mutex);
1455 
1456 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1457 						     "Could not add secret to auth group (%d), %s",
1458 						     req.tag, spdk_strerror(-rc));
1459 		free_rpc_add_auth_secret(&req);
1460 		return;
1461 	}
1462 
1463 	pthread_mutex_unlock(&g_iscsi.mutex);
1464 
1465 	free_rpc_add_auth_secret(&req);
1466 
1467 	w = spdk_jsonrpc_begin_result(request);
1468 	spdk_json_write_bool(w, true);
1469 	spdk_jsonrpc_end_result(request, w);
1470 }
1471 SPDK_RPC_REGISTER("iscsi_auth_group_add_secret", rpc_iscsi_auth_group_add_secret,
1472 		  SPDK_RPC_RUNTIME)
1473 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_add_secret, add_secret_to_iscsi_auth_group)
1474 
1475 
1476 struct rpc_remove_auth_secret {
1477 	int32_t tag;
1478 	char *user;
1479 };
1480 
1481 static void
1482 free_rpc_remove_auth_secret(struct rpc_remove_auth_secret *_secret)
1483 {
1484 	free(_secret->user);
1485 }
1486 
1487 static const struct spdk_json_object_decoder rpc_remove_auth_secret_decoders[] = {
1488 	{"tag", offsetof(struct rpc_remove_auth_secret, tag), spdk_json_decode_int32},
1489 	{"user", offsetof(struct rpc_remove_auth_secret, user), spdk_json_decode_string},
1490 };
1491 
1492 static void
1493 rpc_iscsi_auth_group_remove_secret(struct spdk_jsonrpc_request *request,
1494 				   const struct spdk_json_val *params)
1495 {
1496 	struct rpc_remove_auth_secret req = {};
1497 	struct spdk_json_write_ctx *w;
1498 	struct spdk_iscsi_auth_group *group;
1499 	int rc;
1500 
1501 	if (spdk_json_decode_object(params, rpc_remove_auth_secret_decoders,
1502 				    SPDK_COUNTOF(rpc_remove_auth_secret_decoders), &req)) {
1503 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1504 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1505 						 "Invalid parameters");
1506 		free_rpc_remove_auth_secret(&req);
1507 		return;
1508 	}
1509 
1510 	pthread_mutex_lock(&g_iscsi.mutex);
1511 
1512 	group = iscsi_find_auth_group_by_tag(req.tag);
1513 	if (group == NULL) {
1514 		pthread_mutex_unlock(&g_iscsi.mutex);
1515 
1516 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1517 						     "Could not find auth group (%d)", req.tag);
1518 		free_rpc_remove_auth_secret(&req);
1519 		return;
1520 	}
1521 
1522 	rc = iscsi_auth_group_delete_secret(group, req.user);
1523 	if (rc != 0) {
1524 		pthread_mutex_unlock(&g_iscsi.mutex);
1525 
1526 		spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1527 						     "Could not delete secret from CHAP group (%d), %s",
1528 						     req.tag, spdk_strerror(-rc));
1529 		free_rpc_remove_auth_secret(&req);
1530 		return;
1531 	}
1532 
1533 	pthread_mutex_unlock(&g_iscsi.mutex);
1534 
1535 	free_rpc_remove_auth_secret(&req);
1536 
1537 	w = spdk_jsonrpc_begin_result(request);
1538 	spdk_json_write_bool(w, true);
1539 	spdk_jsonrpc_end_result(request, w);
1540 }
1541 SPDK_RPC_REGISTER("iscsi_auth_group_remove_secret",
1542 		  rpc_iscsi_auth_group_remove_secret, SPDK_RPC_RUNTIME)
1543 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_auth_group_remove_secret,
1544 				   delete_secret_from_iscsi_auth_group)
1545 
1546 static void
1547 rpc_iscsi_get_auth_groups(struct spdk_jsonrpc_request *request,
1548 			  const struct spdk_json_val *params)
1549 {
1550 	struct spdk_json_write_ctx *w;
1551 
1552 	if (params != NULL) {
1553 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1554 						 "iscsi_get_auth_groups requires no parameters");
1555 		return;
1556 	}
1557 
1558 	w = spdk_jsonrpc_begin_result(request);
1559 	spdk_json_write_array_begin(w);
1560 	iscsi_auth_groups_info_json(w);
1561 	spdk_json_write_array_end(w);
1562 
1563 	spdk_jsonrpc_end_result(request, w);
1564 }
1565 SPDK_RPC_REGISTER("iscsi_get_auth_groups", rpc_iscsi_get_auth_groups, SPDK_RPC_RUNTIME)
1566 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_get_auth_groups, get_iscsi_auth_groups)
1567 
1568 static const struct spdk_json_object_decoder rpc_set_iscsi_opts_decoders[] = {
1569 	{"auth_file", offsetof(struct spdk_iscsi_opts, authfile), spdk_json_decode_string, true},
1570 	{"node_base", offsetof(struct spdk_iscsi_opts, nodebase), spdk_json_decode_string, true},
1571 	{"nop_timeout", offsetof(struct spdk_iscsi_opts, timeout), spdk_json_decode_int32, true},
1572 	{"nop_in_interval", offsetof(struct spdk_iscsi_opts, nopininterval), spdk_json_decode_int32, true},
1573 	{"no_discovery_auth", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1574 	{"req_discovery_auth", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1575 	{"req_discovery_auth_mutual", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1576 	{"discovery_auth_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1577 	{"disable_chap", offsetof(struct spdk_iscsi_opts, disable_chap), spdk_json_decode_bool, true},
1578 	{"require_chap", offsetof(struct spdk_iscsi_opts, require_chap), spdk_json_decode_bool, true},
1579 	{"mutual_chap", offsetof(struct spdk_iscsi_opts, mutual_chap), spdk_json_decode_bool, true},
1580 	{"chap_group", offsetof(struct spdk_iscsi_opts, chap_group), spdk_json_decode_int32, true},
1581 	{"max_sessions", offsetof(struct spdk_iscsi_opts, MaxSessions), spdk_json_decode_uint32, true},
1582 	{"max_queue_depth", offsetof(struct spdk_iscsi_opts, MaxQueueDepth), spdk_json_decode_uint32, true},
1583 	{"max_connections_per_session", offsetof(struct spdk_iscsi_opts, MaxConnectionsPerSession), spdk_json_decode_uint32, true},
1584 	{"default_time2wait", offsetof(struct spdk_iscsi_opts, DefaultTime2Wait), spdk_json_decode_uint32, true},
1585 	{"default_time2retain", offsetof(struct spdk_iscsi_opts, DefaultTime2Retain), spdk_json_decode_uint32, true},
1586 	{"first_burst_length", offsetof(struct spdk_iscsi_opts, FirstBurstLength), spdk_json_decode_uint32, true},
1587 	{"immediate_data", offsetof(struct spdk_iscsi_opts, ImmediateData), spdk_json_decode_bool, true},
1588 	{"error_recovery_level", offsetof(struct spdk_iscsi_opts, ErrorRecoveryLevel), spdk_json_decode_uint32, true},
1589 	{"allow_duplicated_isid", offsetof(struct spdk_iscsi_opts, AllowDuplicateIsid), spdk_json_decode_bool, true},
1590 };
1591 
1592 static void
1593 rpc_iscsi_set_options(struct spdk_jsonrpc_request *request,
1594 		      const struct spdk_json_val *params)
1595 {
1596 	struct spdk_iscsi_opts *opts;
1597 	struct spdk_json_write_ctx *w;
1598 
1599 	if (g_spdk_iscsi_opts != NULL) {
1600 		SPDK_ERRLOG("this RPC must not be called more than once.\n");
1601 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1602 						 "Must not call more than once");
1603 		return;
1604 	}
1605 
1606 	opts = iscsi_opts_alloc();
1607 	if (opts == NULL) {
1608 		SPDK_ERRLOG("iscsi_opts_alloc() failed.\n");
1609 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1610 						 "Out of memory");
1611 		return;
1612 	}
1613 
1614 	if (params != NULL) {
1615 		if (spdk_json_decode_object(params, rpc_set_iscsi_opts_decoders,
1616 					    SPDK_COUNTOF(rpc_set_iscsi_opts_decoders), opts)) {
1617 			SPDK_ERRLOG("spdk_json_decode_object() failed\n");
1618 			spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1619 							 "Invalid parameters");
1620 			iscsi_opts_free(opts);
1621 			return;
1622 		}
1623 	}
1624 
1625 	g_spdk_iscsi_opts = iscsi_opts_copy(opts);
1626 	iscsi_opts_free(opts);
1627 
1628 	if (g_spdk_iscsi_opts == NULL) {
1629 		SPDK_ERRLOG("iscsi_opts_copy() failed\n");
1630 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1631 						 "Out of memory");
1632 		return;
1633 	}
1634 
1635 	w = spdk_jsonrpc_begin_result(request);
1636 	spdk_json_write_bool(w, true);
1637 	spdk_jsonrpc_end_result(request, w);
1638 }
1639 SPDK_RPC_REGISTER("iscsi_set_options", rpc_iscsi_set_options, SPDK_RPC_STARTUP)
1640 SPDK_RPC_REGISTER_ALIAS_DEPRECATED(iscsi_set_options, set_iscsi_options)
1641