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