xref: /spdk/lib/iscsi/iscsi_rpc.c (revision d1165a653907c85812beba21bf9cb6c657cf3bf1)
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright (C) 2008-2012 Daisuke Aoyama <aoyama@peach.ne.jp>.
5  *   Copyright (c) Intel Corporation.
6  *   All rights reserved.
7  *
8  *   Redistribution and use in source and binary forms, with or without
9  *   modification, are permitted provided that the following conditions
10  *   are met:
11  *
12  *     * Redistributions of source code must retain the above copyright
13  *       notice, this list of conditions and the following disclaimer.
14  *     * Redistributions in binary form must reproduce the above copyright
15  *       notice, this list of conditions and the following disclaimer in
16  *       the documentation and/or other materials provided with the
17  *       distribution.
18  *     * Neither the name of Intel Corporation nor the names of its
19  *       contributors may be used to endorse or promote products derived
20  *       from this software without specific prior written permission.
21  *
22  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33  */
34 
35 #include "iscsi/iscsi.h"
36 #include "iscsi/conn.h"
37 #include "iscsi/tgt_node.h"
38 #include "iscsi/portal_grp.h"
39 #include "iscsi/init_grp.h"
40 
41 #include "spdk/rpc.h"
42 #include "spdk/util.h"
43 #include "spdk/event.h"
44 
45 #include "spdk_internal/log.h"
46 
47 static void
48 dump_initiator_group(struct spdk_json_write_ctx *w, struct spdk_iscsi_init_grp *ig)
49 {
50 	struct spdk_iscsi_initiator_name *iname;
51 	struct spdk_iscsi_initiator_netmask *imask;
52 
53 	spdk_json_write_object_begin(w);
54 
55 	spdk_json_write_name(w, "initiators");
56 	spdk_json_write_array_begin(w);
57 	TAILQ_FOREACH(iname, &ig->initiator_head, tailq) {
58 		spdk_json_write_string(w, iname->name);
59 	}
60 	spdk_json_write_array_end(w);
61 
62 	spdk_json_write_name(w, "tag");
63 	spdk_json_write_int32(w, ig->tag);
64 
65 	spdk_json_write_name(w, "netmasks");
66 	spdk_json_write_array_begin(w);
67 	TAILQ_FOREACH(imask, &ig->netmask_head, tailq) {
68 		spdk_json_write_string(w, imask->mask);
69 	}
70 	spdk_json_write_array_end(w);
71 
72 	spdk_json_write_object_end(w);
73 }
74 
75 static void
76 spdk_rpc_get_initiator_groups(struct spdk_jsonrpc_request *request,
77 			      const struct spdk_json_val *params)
78 {
79 	struct spdk_json_write_ctx *w;
80 	struct spdk_iscsi_init_grp *ig;
81 
82 	if (params != NULL) {
83 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
84 						 "get_initiator_groups requires no parameters");
85 		return;
86 	}
87 
88 	w = spdk_jsonrpc_begin_result(request);
89 	if (w == NULL) {
90 		return;
91 	}
92 
93 	spdk_json_write_array_begin(w);
94 
95 	TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
96 		dump_initiator_group(w, ig);
97 	}
98 
99 	spdk_json_write_array_end(w);
100 
101 	spdk_jsonrpc_end_result(request, w);
102 }
103 SPDK_RPC_REGISTER("get_initiator_groups", spdk_rpc_get_initiator_groups)
104 
105 struct rpc_initiator_list {
106 	size_t num_initiators;
107 	char *initiators[MAX_INITIATOR];
108 };
109 
110 static int
111 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
112 {
113 	struct rpc_initiator_list *list = out;
114 
115 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
116 				      &list->num_initiators, sizeof(char *));
117 }
118 
119 static void
120 free_rpc_initiator_list(struct rpc_initiator_list *list)
121 {
122 	size_t i;
123 
124 	for (i = 0; i < list->num_initiators; i++) {
125 		free(list->initiators[i]);
126 	}
127 }
128 
129 struct rpc_netmask_list {
130 	size_t num_netmasks;
131 	char *netmasks[MAX_NETMASK];
132 };
133 
134 static int
135 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
136 {
137 	struct rpc_netmask_list *list = out;
138 
139 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
140 				      &list->num_netmasks, sizeof(char *));
141 }
142 
143 static void
144 free_rpc_netmask_list(struct rpc_netmask_list *list)
145 {
146 	size_t i;
147 
148 	for (i = 0; i < list->num_netmasks; i++) {
149 		free(list->netmasks[i]);
150 	}
151 }
152 
153 struct rpc_initiator_group {
154 	int32_t tag;
155 	struct rpc_initiator_list initiator_list;
156 	struct rpc_netmask_list netmask_list;
157 };
158 
159 static void
160 free_rpc_initiator_group(struct rpc_initiator_group *ig)
161 {
162 	free_rpc_initiator_list(&ig->initiator_list);
163 	free_rpc_netmask_list(&ig->netmask_list);
164 }
165 
166 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
167 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
168 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
169 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
170 };
171 
172 static void
173 spdk_rpc_add_initiator_group(struct spdk_jsonrpc_request *request,
174 			     const struct spdk_json_val *params)
175 {
176 	struct rpc_initiator_group req = {};
177 	struct spdk_json_write_ctx *w;
178 
179 	if (spdk_json_decode_object(params, rpc_initiator_group_decoders,
180 				    SPDK_COUNTOF(rpc_initiator_group_decoders), &req)) {
181 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
182 		goto invalid;
183 	}
184 
185 	if (req.initiator_list.num_initiators == 0 ||
186 	    req.netmask_list.num_netmasks == 0) {
187 		goto invalid;
188 	}
189 
190 	if (spdk_iscsi_init_grp_create_from_initiator_list(req.tag,
191 			req.initiator_list.num_initiators,
192 			req.initiator_list.initiators,
193 			req.netmask_list.num_netmasks,
194 			req.netmask_list.netmasks)) {
195 		SPDK_ERRLOG("create_from_initiator_list failed\n");
196 		goto invalid;
197 	}
198 
199 	free_rpc_initiator_group(&req);
200 
201 	w = spdk_jsonrpc_begin_result(request);
202 	if (w == NULL) {
203 		return;
204 	}
205 
206 	spdk_json_write_bool(w, true);
207 	spdk_jsonrpc_end_result(request, w);
208 	return;
209 
210 invalid:
211 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
212 	free_rpc_initiator_group(&req);
213 }
214 SPDK_RPC_REGISTER("add_initiator_group", spdk_rpc_add_initiator_group)
215 
216 static const struct spdk_json_object_decoder rpc_add_or_delete_initiators_decoders[] = {
217 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
218 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list, true},
219 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list, true},
220 };
221 
222 static void
223 spdk_rpc_add_initiators_to_initiator_group(struct spdk_jsonrpc_request *request,
224 		const struct spdk_json_val *params)
225 {
226 	struct rpc_initiator_group req = {};
227 	struct spdk_json_write_ctx *w;
228 
229 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
230 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
231 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
232 		goto invalid;
233 	}
234 
235 	if (spdk_iscsi_init_grp_add_initiators_from_initiator_list(req.tag,
236 			req.initiator_list.num_initiators,
237 			req.initiator_list.initiators,
238 			req.netmask_list.num_netmasks,
239 			req.netmask_list.netmasks)) {
240 		SPDK_ERRLOG("add_initiators_from_initiator_list failed\n");
241 		goto invalid;
242 	}
243 
244 	free_rpc_initiator_group(&req);
245 
246 	w = spdk_jsonrpc_begin_result(request);
247 	if (w == NULL) {
248 		return;
249 	}
250 
251 	spdk_json_write_bool(w, true);
252 	spdk_jsonrpc_end_result(request, w);
253 	return;
254 
255 invalid:
256 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
257 	free_rpc_initiator_group(&req);
258 }
259 SPDK_RPC_REGISTER("add_initiators_to_initiator_group", spdk_rpc_add_initiators_to_initiator_group)
260 
261 static void
262 spdk_rpc_delete_initiators_from_initiator_group(struct spdk_jsonrpc_request *request,
263 		const struct spdk_json_val *params)
264 {
265 	struct rpc_initiator_group req = {};
266 	struct spdk_json_write_ctx *w;
267 
268 	if (spdk_json_decode_object(params, rpc_add_or_delete_initiators_decoders,
269 				    SPDK_COUNTOF(rpc_add_or_delete_initiators_decoders), &req)) {
270 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
271 		goto invalid;
272 	}
273 
274 	if (spdk_iscsi_init_grp_delete_initiators_from_initiator_list(req.tag,
275 			req.initiator_list.num_initiators,
276 			req.initiator_list.initiators,
277 			req.netmask_list.num_netmasks,
278 			req.netmask_list.netmasks)) {
279 		SPDK_ERRLOG("delete_initiators_from_initiator_list failed\n");
280 		goto invalid;
281 	}
282 
283 	free_rpc_initiator_group(&req);
284 
285 	w = spdk_jsonrpc_begin_result(request);
286 	if (w == NULL) {
287 		return;
288 	}
289 
290 	spdk_json_write_bool(w, true);
291 	spdk_jsonrpc_end_result(request, w);
292 	return;
293 
294 invalid:
295 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
296 	free_rpc_initiator_group(&req);
297 }
298 SPDK_RPC_REGISTER("delete_initiators_from_initiator_group",
299 		  spdk_rpc_delete_initiators_from_initiator_group)
300 
301 struct rpc_delete_initiator_group {
302 	int32_t tag;
303 };
304 
305 static const struct spdk_json_object_decoder rpc_delete_initiator_group_decoders[] = {
306 	{"tag", offsetof(struct rpc_delete_initiator_group, tag), spdk_json_decode_int32},
307 };
308 
309 static void
310 spdk_rpc_delete_initiator_group(struct spdk_jsonrpc_request *request,
311 				const struct spdk_json_val *params)
312 {
313 	struct rpc_delete_initiator_group req = {};
314 	struct spdk_json_write_ctx *w;
315 	struct spdk_iscsi_init_grp *ig;
316 
317 	if (spdk_json_decode_object(params, rpc_delete_initiator_group_decoders,
318 				    SPDK_COUNTOF(rpc_delete_initiator_group_decoders),
319 				    &req)) {
320 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
321 		goto invalid;
322 	}
323 
324 	ig = spdk_iscsi_init_grp_unregister(req.tag);
325 	if (!ig) {
326 		goto invalid;
327 	}
328 	spdk_iscsi_tgt_node_delete_map(NULL, ig);
329 	spdk_iscsi_init_grp_destroy(ig);
330 
331 	w = spdk_jsonrpc_begin_result(request);
332 	if (w == NULL) {
333 		return;
334 	}
335 
336 	spdk_json_write_bool(w, true);
337 	spdk_jsonrpc_end_result(request, w);
338 	return;
339 
340 invalid:
341 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
342 }
343 SPDK_RPC_REGISTER("delete_initiator_group", spdk_rpc_delete_initiator_group)
344 
345 static void
346 dump_target_node(struct spdk_json_write_ctx *w, struct spdk_iscsi_tgt_node *tgtnode)
347 {
348 	struct spdk_iscsi_pg_map *pg_map;
349 	struct spdk_iscsi_ig_map *ig_map;
350 	int i;
351 
352 	spdk_json_write_object_begin(w);
353 
354 	spdk_json_write_name(w, "name");
355 	spdk_json_write_string(w, tgtnode->name);
356 
357 	if (tgtnode->alias) {
358 		spdk_json_write_name(w, "alias_name");
359 		spdk_json_write_string(w, tgtnode->alias);
360 	}
361 
362 	spdk_json_write_name(w, "pg_ig_maps");
363 	spdk_json_write_array_begin(w);
364 	TAILQ_FOREACH(pg_map, &tgtnode->pg_map_head, tailq) {
365 		TAILQ_FOREACH(ig_map, &pg_map->ig_map_head, tailq) {
366 			spdk_json_write_object_begin(w);
367 			spdk_json_write_name(w, "pg_tag");
368 			spdk_json_write_int32(w, pg_map->pg->tag);
369 			spdk_json_write_name(w, "ig_tag");
370 			spdk_json_write_int32(w, ig_map->ig->tag);
371 			spdk_json_write_object_end(w);
372 		}
373 	}
374 	spdk_json_write_array_end(w);
375 
376 	spdk_json_write_name(w, "luns");
377 	spdk_json_write_array_begin(w);
378 	for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
379 		struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(tgtnode->dev, i);
380 
381 		if (lun) {
382 			spdk_json_write_object_begin(w);
383 			spdk_json_write_name(w, "bdev_name");
384 			spdk_json_write_string(w, spdk_scsi_lun_get_bdev_name(lun));
385 			spdk_json_write_name(w, "id");
386 			spdk_json_write_int32(w, spdk_scsi_lun_get_id(lun));
387 			spdk_json_write_object_end(w);
388 		}
389 	}
390 	spdk_json_write_array_end(w);
391 
392 	spdk_json_write_name(w, "queue_depth");
393 	spdk_json_write_int32(w, tgtnode->queue_depth);
394 
395 	spdk_json_write_name(w, "disable_chap");
396 	spdk_json_write_bool(w, tgtnode->disable_chap);
397 
398 	spdk_json_write_name(w, "require_chap");
399 	spdk_json_write_bool(w, tgtnode->require_chap);
400 
401 	spdk_json_write_name(w, "mutual_chap");
402 	spdk_json_write_bool(w, tgtnode->mutual_chap);
403 
404 	spdk_json_write_name(w, "chap_group");
405 	spdk_json_write_int32(w, tgtnode->chap_group);
406 
407 	spdk_json_write_name(w, "header_digest");
408 	spdk_json_write_bool(w, tgtnode->header_digest);
409 
410 	spdk_json_write_name(w, "data_digest");
411 	spdk_json_write_bool(w, tgtnode->data_digest);
412 
413 	spdk_json_write_object_end(w);
414 }
415 
416 static void
417 spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request,
418 			  const struct spdk_json_val *params)
419 {
420 	struct spdk_json_write_ctx *w;
421 	struct spdk_iscsi_tgt_node *tgtnode;
422 
423 	if (params != NULL) {
424 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
425 						 "get_target_nodes requires no parameters");
426 		return;
427 	}
428 
429 	w = spdk_jsonrpc_begin_result(request);
430 	if (w == NULL) {
431 		return;
432 	}
433 
434 	spdk_json_write_array_begin(w);
435 
436 	TAILQ_FOREACH(tgtnode, &g_spdk_iscsi.target_head, tailq) {
437 		dump_target_node(w, tgtnode);
438 	}
439 
440 	spdk_json_write_array_end(w);
441 
442 	spdk_jsonrpc_end_result(request, w);
443 }
444 SPDK_RPC_REGISTER("get_target_nodes", spdk_rpc_get_target_nodes)
445 
446 struct rpc_pg_ig_map {
447 	int32_t pg_tag;
448 	int32_t ig_tag;
449 };
450 
451 static const struct spdk_json_object_decoder rpc_pg_ig_map_decoders[] = {
452 	{"pg_tag", offsetof(struct rpc_pg_ig_map, pg_tag), spdk_json_decode_int32},
453 	{"ig_tag", offsetof(struct rpc_pg_ig_map, ig_tag), spdk_json_decode_int32},
454 };
455 
456 static int
457 decode_rpc_pg_ig_map(const struct spdk_json_val *val, void *out)
458 {
459 	struct rpc_pg_ig_map *pg_ig_map = out;
460 
461 	return spdk_json_decode_object(val, rpc_pg_ig_map_decoders,
462 				       SPDK_COUNTOF(rpc_pg_ig_map_decoders),
463 				       pg_ig_map);
464 }
465 
466 struct rpc_pg_ig_maps {
467 	size_t num_maps;
468 	struct rpc_pg_ig_map maps[MAX_TARGET_MAP];
469 };
470 
471 static int
472 decode_rpc_pg_ig_maps(const struct spdk_json_val *val, void *out)
473 {
474 	struct rpc_pg_ig_maps *pg_ig_maps = out;
475 
476 	return spdk_json_decode_array(val, decode_rpc_pg_ig_map, pg_ig_maps->maps,
477 				      MAX_TARGET_MAP, &pg_ig_maps->num_maps,
478 				      sizeof(struct rpc_pg_ig_map));
479 }
480 
481 #define RPC_CONSTRUCT_TARGET_NODE_MAX_LUN	64
482 
483 struct rpc_lun {
484 	char *bdev_name;
485 	int32_t lun_id;
486 };
487 
488 static const struct spdk_json_object_decoder rpc_lun_decoders[] = {
489 	{"bdev_name", offsetof(struct rpc_lun, bdev_name), spdk_json_decode_string},
490 	{"lun_id", offsetof(struct rpc_lun, lun_id), spdk_json_decode_int32},
491 };
492 
493 static int
494 decode_rpc_lun(const struct spdk_json_val *val, void *out)
495 {
496 	struct rpc_lun *lun = out;
497 
498 	return spdk_json_decode_object(val, rpc_lun_decoders,
499 				       SPDK_COUNTOF(rpc_lun_decoders), lun);
500 }
501 
502 struct rpc_luns {
503 	size_t num_luns;
504 	struct rpc_lun luns[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
505 };
506 
507 static int
508 decode_rpc_luns(const struct spdk_json_val *val, void *out)
509 {
510 	struct rpc_luns *luns = out;
511 
512 	return spdk_json_decode_array(val, decode_rpc_lun, luns->luns,
513 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
514 				      &luns->num_luns, sizeof(struct rpc_lun));
515 }
516 
517 static void
518 free_rpc_luns(struct rpc_luns *p)
519 {
520 	size_t i;
521 
522 	for (i = 0; i < p->num_luns; i++) {
523 		free(p->luns[i].bdev_name);
524 	}
525 }
526 
527 struct rpc_target_node {
528 	char *name;
529 	char *alias_name;
530 
531 	struct rpc_pg_ig_maps pg_ig_maps;
532 	struct rpc_luns luns;
533 
534 	int32_t queue_depth;
535 	bool disable_chap;
536 	bool require_chap;
537 	bool mutual_chap;
538 	int32_t chap_group;
539 
540 	bool header_digest;
541 	bool data_digest;
542 };
543 
544 static void
545 free_rpc_target_node(struct rpc_target_node *req)
546 {
547 	free(req->name);
548 	free(req->alias_name);
549 	free_rpc_luns(&req->luns);
550 }
551 
552 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
553 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
554 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
555 	{"pg_ig_maps", offsetof(struct rpc_target_node, pg_ig_maps), decode_rpc_pg_ig_maps},
556 	{"luns", offsetof(struct rpc_target_node, luns), decode_rpc_luns},
557 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
558 	{"disable_chap", offsetof(struct rpc_target_node, disable_chap), spdk_json_decode_bool, true},
559 	{"require_chap", offsetof(struct rpc_target_node, require_chap), spdk_json_decode_bool, true},
560 	{"mutual_chap", offsetof(struct rpc_target_node, mutual_chap), spdk_json_decode_bool, true},
561 	{"chap_group", offsetof(struct rpc_target_node, chap_group), spdk_json_decode_int32, true},
562 	{"header_digest", offsetof(struct rpc_target_node, header_digest), spdk_json_decode_bool, true},
563 	{"data_digest", offsetof(struct rpc_target_node, data_digest), spdk_json_decode_bool, true},
564 };
565 
566 static void
567 spdk_rpc_construct_target_node(struct spdk_jsonrpc_request *request,
568 			       const struct spdk_json_val *params)
569 {
570 	struct rpc_target_node req = {};
571 	struct spdk_json_write_ctx *w;
572 	struct spdk_iscsi_tgt_node *target;
573 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
574 	char *bdev_names[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN] = {0};
575 	int32_t lun_ids[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN] = {0};
576 	size_t i;
577 
578 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
579 				    SPDK_COUNTOF(rpc_target_node_decoders),
580 				    &req)) {
581 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
582 		goto invalid;
583 	}
584 
585 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
586 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
587 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
588 	}
589 
590 	for (i = 0; i < req.luns.num_luns; i++) {
591 		bdev_names[i] = req.luns.luns[i].bdev_name;
592 		lun_ids[i] = req.luns.luns[i].lun_id;
593 	}
594 
595 	/*
596 	 * Use default parameters in a few places:
597 	 *  index = -1 : automatically pick an index for the new target node
598 	 *  alias = NULL
599 	 */
600 	target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name,
601 					       pg_tags,
602 					       ig_tags,
603 					       req.pg_ig_maps.num_maps,
604 					       (const char **)bdev_names,
605 					       lun_ids,
606 					       req.luns.num_luns,
607 					       req.queue_depth,
608 					       req.disable_chap,
609 					       req.require_chap,
610 					       req.mutual_chap,
611 					       req.chap_group,
612 					       req.header_digest,
613 					       req.data_digest);
614 
615 	if (target == NULL) {
616 		goto invalid;
617 	}
618 
619 	free_rpc_target_node(&req);
620 
621 	w = spdk_jsonrpc_begin_result(request);
622 	if (w == NULL) {
623 		return;
624 	}
625 
626 	spdk_json_write_bool(w, true);
627 	spdk_jsonrpc_end_result(request, w);
628 	return;
629 
630 invalid:
631 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
632 	free_rpc_target_node(&req);
633 }
634 SPDK_RPC_REGISTER("construct_target_node", spdk_rpc_construct_target_node)
635 
636 struct rpc_tgt_node_pg_ig_maps {
637 	char *name;
638 	struct rpc_pg_ig_maps pg_ig_maps;
639 };
640 
641 static const struct spdk_json_object_decoder rpc_tgt_node_pg_ig_maps_decoders[] = {
642 	{"name", offsetof(struct rpc_tgt_node_pg_ig_maps, name), spdk_json_decode_string},
643 	{"pg_ig_maps", offsetof(struct rpc_tgt_node_pg_ig_maps, pg_ig_maps), decode_rpc_pg_ig_maps},
644 };
645 
646 static void
647 spdk_rpc_add_pg_ig_maps(struct spdk_jsonrpc_request *request,
648 			const struct spdk_json_val *params)
649 {
650 	struct rpc_tgt_node_pg_ig_maps req = {};
651 	struct spdk_json_write_ctx *w;
652 	struct spdk_iscsi_tgt_node *target;
653 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
654 	size_t i;
655 	int rc;
656 
657 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
658 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
659 				    &req)) {
660 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
661 		goto invalid;
662 	}
663 
664 	target = spdk_iscsi_find_tgt_node(req.name);
665 	if (target == NULL) {
666 		SPDK_ERRLOG("target is not found\n");
667 		goto invalid;
668 	}
669 
670 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
671 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
672 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
673 	}
674 
675 	rc = spdk_iscsi_tgt_node_add_pg_ig_maps(target, pg_tags, ig_tags,
676 						req.pg_ig_maps.num_maps);
677 	if (rc < 0) {
678 		SPDK_ERRLOG("add pg-ig maps failed\n");
679 		goto invalid;
680 	}
681 
682 	free(req.name);
683 
684 	w = spdk_jsonrpc_begin_result(request);
685 	if (w != NULL) {
686 		spdk_json_write_bool(w, true);
687 		spdk_jsonrpc_end_result(request, w);
688 	}
689 	return;
690 
691 invalid:
692 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
693 					 "Invalid parameters");
694 	free(req.name);
695 }
696 SPDK_RPC_REGISTER("add_pg_ig_maps", spdk_rpc_add_pg_ig_maps)
697 
698 static void
699 spdk_rpc_delete_pg_ig_maps(struct spdk_jsonrpc_request *request,
700 			   const struct spdk_json_val *params)
701 {
702 	struct rpc_tgt_node_pg_ig_maps req = {};
703 	struct spdk_json_write_ctx *w;
704 	struct spdk_iscsi_tgt_node *target;
705 	int32_t pg_tags[MAX_TARGET_MAP] = {0}, ig_tags[MAX_TARGET_MAP] = {0};
706 	size_t i;
707 	int rc;
708 
709 	if (spdk_json_decode_object(params, rpc_tgt_node_pg_ig_maps_decoders,
710 				    SPDK_COUNTOF(rpc_tgt_node_pg_ig_maps_decoders),
711 				    &req)) {
712 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
713 		goto invalid;
714 	}
715 
716 	target = spdk_iscsi_find_tgt_node(req.name);
717 	if (target == NULL) {
718 		SPDK_ERRLOG("target is not found\n");
719 		goto invalid;
720 	}
721 
722 	for (i = 0; i < req.pg_ig_maps.num_maps; i++) {
723 		pg_tags[i] = req.pg_ig_maps.maps[i].pg_tag;
724 		ig_tags[i] = req.pg_ig_maps.maps[i].ig_tag;
725 	}
726 
727 	rc = spdk_iscsi_tgt_node_delete_pg_ig_maps(target, pg_tags, ig_tags,
728 			req.pg_ig_maps.num_maps);
729 	if (rc < 0) {
730 		SPDK_ERRLOG("remove pg-ig maps failed\n");
731 		goto invalid;
732 	}
733 
734 	free(req.name);
735 
736 	w = spdk_jsonrpc_begin_result(request);
737 	if (w != NULL) {
738 		spdk_json_write_bool(w, true);
739 		spdk_jsonrpc_end_result(request, w);
740 	}
741 	return;
742 
743 invalid:
744 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
745 					 "Invalid parameters");
746 	free(req.name);
747 }
748 SPDK_RPC_REGISTER("delete_pg_ig_maps", spdk_rpc_delete_pg_ig_maps)
749 
750 struct rpc_delete_target_node {
751 	char *name;
752 };
753 
754 static void
755 free_rpc_delete_target_node(struct rpc_delete_target_node *r)
756 {
757 	free(r->name);
758 }
759 
760 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = {
761 	{"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string},
762 };
763 
764 static void
765 spdk_rpc_delete_target_node(struct spdk_jsonrpc_request *request,
766 			    const struct spdk_json_val *params)
767 {
768 	struct rpc_delete_target_node req = {};
769 	struct spdk_json_write_ctx *w;
770 
771 	if (spdk_json_decode_object(params, rpc_delete_target_node_decoders,
772 				    SPDK_COUNTOF(rpc_delete_target_node_decoders),
773 				    &req)) {
774 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
775 		goto invalid;
776 	}
777 
778 	if (req.name == NULL) {
779 		SPDK_ERRLOG("missing name param\n");
780 		goto invalid;
781 	}
782 
783 	if (spdk_iscsi_shutdown_tgt_node_by_name(req.name)) {
784 		SPDK_ERRLOG("shutdown_tgt_node_by_name failed\n");
785 		goto invalid;
786 	}
787 
788 	free_rpc_delete_target_node(&req);
789 
790 	w = spdk_jsonrpc_begin_result(request);
791 	if (w == NULL) {
792 		return;
793 	}
794 
795 	spdk_json_write_bool(w, true);
796 	spdk_jsonrpc_end_result(request, w);
797 	return;
798 
799 invalid:
800 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
801 	free_rpc_delete_target_node(&req);
802 }
803 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node)
804 
805 static void
806 dump_portal_group(struct spdk_json_write_ctx *w, struct spdk_iscsi_portal_grp *pg)
807 {
808 	struct spdk_iscsi_portal *portal;
809 
810 	spdk_json_write_object_begin(w);
811 
812 	spdk_json_write_name(w, "portals");
813 	spdk_json_write_array_begin(w);
814 	TAILQ_FOREACH(portal, &pg->head, per_pg_tailq) {
815 		spdk_json_write_object_begin(w);
816 		spdk_json_write_name(w, "host");
817 		spdk_json_write_string(w, portal->host);
818 		spdk_json_write_name(w, "port");
819 		spdk_json_write_string(w, portal->port);
820 		spdk_json_write_name(w, "cpumask");
821 		spdk_json_write_string_fmt(w, "0x%s", spdk_cpuset_fmt(portal->cpumask));
822 		spdk_json_write_object_end(w);
823 	}
824 	spdk_json_write_array_end(w);
825 
826 	spdk_json_write_name(w, "tag");
827 	spdk_json_write_int32(w, pg->tag);
828 
829 	spdk_json_write_object_end(w);
830 }
831 
832 static void
833 spdk_rpc_get_portal_groups(struct spdk_jsonrpc_request *request,
834 			   const struct spdk_json_val *params)
835 {
836 	struct spdk_json_write_ctx *w;
837 	struct spdk_iscsi_portal_grp *pg;
838 
839 	if (params != NULL) {
840 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
841 						 "get_portal_groups requires no parameters");
842 		return;
843 	}
844 
845 	w = spdk_jsonrpc_begin_result(request);
846 	if (w == NULL) {
847 		return;
848 	}
849 
850 	spdk_json_write_array_begin(w);
851 
852 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
853 		dump_portal_group(w, pg);
854 	}
855 
856 	spdk_json_write_array_end(w);
857 
858 	spdk_jsonrpc_end_result(request, w);
859 }
860 SPDK_RPC_REGISTER("get_portal_groups", spdk_rpc_get_portal_groups)
861 
862 struct rpc_portal {
863 	char *host;
864 	char *port;
865 	char *cpumask;
866 };
867 
868 struct rpc_portal_list {
869 	size_t num_portals;
870 	struct rpc_portal portals[MAX_PORTAL];
871 };
872 
873 struct rpc_portal_group {
874 	int32_t tag;
875 	struct rpc_portal_list portal_list;
876 };
877 
878 static void
879 free_rpc_portal(struct rpc_portal *portal)
880 {
881 	free(portal->host);
882 	free(portal->port);
883 	free(portal->cpumask);
884 }
885 
886 static void
887 free_rpc_portal_list(struct rpc_portal_list *pl)
888 {
889 	size_t i;
890 
891 	for (i = 0; i < pl->num_portals; i++) {
892 		free_rpc_portal(&pl->portals[i]);
893 	}
894 	pl->num_portals = 0;
895 }
896 
897 static void
898 free_rpc_portal_group(struct rpc_portal_group *pg)
899 {
900 	free_rpc_portal_list(&pg->portal_list);
901 }
902 
903 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
904 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
905 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
906 	{"cpumask", offsetof(struct rpc_portal, cpumask), spdk_json_decode_string, true},
907 };
908 
909 static int
910 decode_rpc_portal(const struct spdk_json_val *val, void *out)
911 {
912 	struct rpc_portal *portal = out;
913 
914 	return spdk_json_decode_object(val, rpc_portal_decoders,
915 				       SPDK_COUNTOF(rpc_portal_decoders),
916 				       portal);
917 }
918 
919 static int
920 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
921 {
922 	struct rpc_portal_list *list = out;
923 
924 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
925 				      sizeof(struct rpc_portal));
926 }
927 
928 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
929 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
930 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
931 };
932 
933 static void
934 spdk_rpc_add_portal_group(struct spdk_jsonrpc_request *request,
935 			  const struct spdk_json_val *params)
936 {
937 	struct rpc_portal_group req = {};
938 	struct spdk_iscsi_portal_grp *pg = NULL;
939 	struct spdk_iscsi_portal *portal;
940 	struct spdk_json_write_ctx *w;
941 	size_t i = 0;
942 	int rc = -1;
943 
944 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
945 				    SPDK_COUNTOF(rpc_portal_group_decoders),
946 				    &req)) {
947 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
948 		goto out;
949 	}
950 
951 	pg = spdk_iscsi_portal_grp_create(req.tag);
952 	if (pg == NULL) {
953 		SPDK_ERRLOG("portal_grp_create failed\n");
954 		goto out;
955 	}
956 	for (i = 0; i < req.portal_list.num_portals; i++) {
957 		portal = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
958 						  req.portal_list.portals[i].port,
959 						  req.portal_list.portals[i].cpumask);
960 		if (portal == NULL) {
961 			SPDK_ERRLOG("portal_create failed\n");
962 			goto out;
963 		}
964 		spdk_iscsi_portal_grp_add_portal(pg, portal);
965 	}
966 
967 	rc = spdk_iscsi_portal_grp_open(pg);
968 	if (rc != 0) {
969 		SPDK_ERRLOG("portal_grp_open failed\n");
970 		goto out;
971 	}
972 
973 	rc = spdk_iscsi_portal_grp_register(pg);
974 	if (rc != 0) {
975 		SPDK_ERRLOG("portal_grp_register failed\n");
976 	}
977 
978 out:
979 	if (rc == 0) {
980 		w = spdk_jsonrpc_begin_result(request);
981 		if (w != NULL) {
982 			spdk_json_write_bool(w, true);
983 			spdk_jsonrpc_end_result(request, w);
984 		}
985 	} else {
986 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
987 
988 		if (pg != NULL) {
989 			spdk_iscsi_portal_grp_release(pg);
990 		}
991 	}
992 	free_rpc_portal_group(&req);
993 }
994 SPDK_RPC_REGISTER("add_portal_group", spdk_rpc_add_portal_group)
995 
996 struct rpc_delete_portal_group {
997 	int32_t tag;
998 };
999 
1000 static const struct spdk_json_object_decoder rpc_delete_portal_group_decoders[] = {
1001 	{"tag", offsetof(struct rpc_delete_portal_group, tag), spdk_json_decode_int32},
1002 };
1003 
1004 static void
1005 spdk_rpc_delete_portal_group(struct spdk_jsonrpc_request *request,
1006 			     const struct spdk_json_val *params)
1007 {
1008 	struct rpc_delete_portal_group req = {};
1009 	struct spdk_json_write_ctx *w;
1010 	struct spdk_iscsi_portal_grp *pg;
1011 
1012 	if (spdk_json_decode_object(params, rpc_delete_portal_group_decoders,
1013 				    SPDK_COUNTOF(rpc_delete_portal_group_decoders),
1014 				    &req)) {
1015 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1016 		goto invalid;
1017 	}
1018 
1019 	pg = spdk_iscsi_portal_grp_unregister(req.tag);
1020 	if (!pg) {
1021 		goto invalid;
1022 	}
1023 
1024 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
1025 	spdk_iscsi_portal_grp_release(pg);
1026 
1027 	w = spdk_jsonrpc_begin_result(request);
1028 	if (w == NULL) {
1029 		return;
1030 	}
1031 
1032 	spdk_json_write_bool(w, true);
1033 	spdk_jsonrpc_end_result(request, w);
1034 	return;
1035 
1036 invalid:
1037 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
1038 }
1039 SPDK_RPC_REGISTER("delete_portal_group", spdk_rpc_delete_portal_group)
1040 
1041 static void
1042 spdk_rpc_get_iscsi_connections(struct spdk_jsonrpc_request *request,
1043 			       const struct spdk_json_val *params)
1044 {
1045 	struct spdk_json_write_ctx *w;
1046 	struct spdk_iscsi_conn *conns = g_conns_array;
1047 	int i;
1048 	uint16_t tsih;
1049 
1050 	if (params != NULL) {
1051 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1052 						 "get_iscsi_connections requires no parameters");
1053 		return;
1054 	}
1055 
1056 	w = spdk_jsonrpc_begin_result(request);
1057 	if (w == NULL) {
1058 		return;
1059 	}
1060 
1061 	spdk_json_write_array_begin(w);
1062 
1063 	for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) {
1064 		struct spdk_iscsi_conn *c = &conns[i];
1065 
1066 		if (!c->is_valid) {
1067 			continue;
1068 		}
1069 
1070 		spdk_json_write_object_begin(w);
1071 
1072 		spdk_json_write_name(w, "id");
1073 		spdk_json_write_int32(w, c->id);
1074 
1075 		spdk_json_write_name(w, "cid");
1076 		spdk_json_write_int32(w, c->cid);
1077 
1078 		/*
1079 		 * If we try to return data for a connection that has not
1080 		 *  logged in yet, the session will not be set.  So in this
1081 		 *  case, return -1 for the tsih rather than segfaulting
1082 		 *  on the null c->sess.
1083 		 */
1084 		if (c->sess == NULL) {
1085 			tsih = -1;
1086 		} else {
1087 			tsih = c->sess->tsih;
1088 		}
1089 		spdk_json_write_name(w, "tsih");
1090 		spdk_json_write_int32(w, tsih);
1091 
1092 		spdk_json_write_name(w, "lcore_id");
1093 		spdk_json_write_int32(w, c->lcore);
1094 
1095 		spdk_json_write_name(w, "initiator_addr");
1096 		spdk_json_write_string(w, c->initiator_addr);
1097 
1098 		spdk_json_write_name(w, "target_addr");
1099 		spdk_json_write_string(w, c->target_addr);
1100 
1101 		spdk_json_write_name(w, "target_node_name");
1102 		spdk_json_write_string(w, c->target_short_name);
1103 
1104 		spdk_json_write_object_end(w);
1105 	}
1106 	spdk_json_write_array_end(w);
1107 
1108 	spdk_jsonrpc_end_result(request, w);
1109 }
1110 SPDK_RPC_REGISTER("get_iscsi_connections", spdk_rpc_get_iscsi_connections)
1111 
1112 struct rpc_target_lun {
1113 	char *name;
1114 	char *bdev_name;
1115 	int32_t lun_id;
1116 };
1117 
1118 static void
1119 free_rpc_target_lun(struct rpc_target_lun *req)
1120 {
1121 	free(req->name);
1122 	free(req->bdev_name);
1123 }
1124 
1125 static const struct spdk_json_object_decoder rpc_target_lun_decoders[] = {
1126 	{"name", offsetof(struct rpc_target_lun, name), spdk_json_decode_string},
1127 	{"bdev_name", offsetof(struct rpc_target_lun, bdev_name), spdk_json_decode_string},
1128 	{"lun_id", offsetof(struct rpc_target_lun, lun_id), spdk_json_decode_int32, true},
1129 };
1130 
1131 static void
1132 spdk_rpc_target_node_add_lun(struct spdk_jsonrpc_request *request,
1133 			     const struct spdk_json_val *params)
1134 {
1135 	struct rpc_target_lun req = {};
1136 	struct spdk_json_write_ctx *w;
1137 	struct spdk_iscsi_tgt_node *target;
1138 	int rc;
1139 
1140 	req.lun_id = -1;
1141 
1142 	if (spdk_json_decode_object(params, rpc_target_lun_decoders,
1143 				    SPDK_COUNTOF(rpc_target_lun_decoders), &req)) {
1144 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
1145 		goto invalid;
1146 	}
1147 
1148 	target = spdk_iscsi_find_tgt_node(req.name);
1149 	if (target == NULL) {
1150 		SPDK_ERRLOG("target is not found\n");
1151 		goto invalid;
1152 	}
1153 
1154 	rc = spdk_iscsi_tgt_node_add_lun(target, req.bdev_name, req.lun_id);
1155 	if (rc < 0) {
1156 		SPDK_ERRLOG("add lun failed\n");
1157 		goto invalid;
1158 	}
1159 
1160 	free_rpc_target_lun(&req);
1161 
1162 	w = spdk_jsonrpc_begin_result(request);
1163 	if (w == NULL) {
1164 		return;
1165 	}
1166 
1167 	spdk_json_write_bool(w, true);
1168 	spdk_jsonrpc_end_result(request, w);
1169 	return;
1170 
1171 invalid:
1172 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1173 					 "Invalid parameters");
1174 	free_rpc_target_lun(&req);
1175 }
1176 SPDK_RPC_REGISTER("target_node_add_lun", spdk_rpc_target_node_add_lun)
1177 
1178 static void
1179 spdk_rpc_get_iscsi_global_params(struct spdk_jsonrpc_request *request,
1180 				 const struct spdk_json_val *params)
1181 {
1182 	struct spdk_json_write_ctx *w;
1183 
1184 	if (params != NULL) {
1185 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1186 						 "get_iscsi_global_params requires no parameters");
1187 		return;
1188 	}
1189 
1190 	w = spdk_jsonrpc_begin_result(request);
1191 	if (w == NULL) {
1192 		return;
1193 	}
1194 
1195 	spdk_json_write_object_begin(w);
1196 
1197 	spdk_json_write_name(w, "auth_file");
1198 	spdk_json_write_string(w, g_spdk_iscsi.authfile);
1199 
1200 	spdk_json_write_name(w, "node_base");
1201 	spdk_json_write_string(w, g_spdk_iscsi.nodebase);
1202 
1203 	spdk_json_write_name(w, "max_sessions");
1204 	spdk_json_write_uint32(w, g_spdk_iscsi.MaxSessions);
1205 
1206 	spdk_json_write_name(w, "max_connections_per_session");
1207 	spdk_json_write_uint32(w, g_spdk_iscsi.MaxConnectionsPerSession);
1208 
1209 	spdk_json_write_name(w, "max_queue_depth");
1210 	spdk_json_write_uint32(w, g_spdk_iscsi.MaxQueueDepth);
1211 
1212 	spdk_json_write_name(w, "default_time2wait");
1213 	spdk_json_write_uint32(w, g_spdk_iscsi.DefaultTime2Wait);
1214 
1215 	spdk_json_write_name(w, "default_time2retain");
1216 	spdk_json_write_uint32(w, g_spdk_iscsi.DefaultTime2Retain);
1217 
1218 	spdk_json_write_name(w, "immediate_data");
1219 	spdk_json_write_bool(w, g_spdk_iscsi.ImmediateData);
1220 
1221 	spdk_json_write_name(w, "allow_duplicated_isid");
1222 	spdk_json_write_bool(w, g_spdk_iscsi.AllowDuplicateIsid);
1223 
1224 	spdk_json_write_name(w, "error_recovery_level");
1225 	spdk_json_write_uint32(w, g_spdk_iscsi.ErrorRecoveryLevel);
1226 
1227 	spdk_json_write_name(w, "timeout");
1228 	spdk_json_write_int32(w, g_spdk_iscsi.timeout);
1229 
1230 	spdk_json_write_name(w, "nop_in_interval");
1231 	spdk_json_write_int32(w, g_spdk_iscsi.nopininterval);
1232 
1233 	spdk_json_write_name(w, "discovery_auth_method");
1234 	if (g_spdk_iscsi.no_discovery_auth != 0) {
1235 		spdk_json_write_string(w, "none");
1236 	} else if (g_spdk_iscsi.req_discovery_auth == 0) {
1237 		spdk_json_write_string(w, "auto");
1238 	} else if (g_spdk_iscsi.req_discovery_auth_mutual != 0) {
1239 		spdk_json_write_string(w, "chap mutual");
1240 	} else {
1241 		spdk_json_write_string(w, "chap");
1242 	}
1243 
1244 	spdk_json_write_name(w, "discovery_auth_group");
1245 	spdk_json_write_int32(w, g_spdk_iscsi.discovery_auth_group);
1246 
1247 	spdk_json_write_name(w, "min_connections_per_core");
1248 	spdk_json_write_int32(w, spdk_iscsi_conn_get_min_per_core());
1249 
1250 	spdk_json_write_object_end(w);
1251 
1252 	spdk_jsonrpc_end_result(request, w);
1253 }
1254 SPDK_RPC_REGISTER("get_iscsi_global_params", spdk_rpc_get_iscsi_global_params)
1255