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