xref: /spdk/lib/iscsi/iscsi_rpc.c (revision 179ed697b3c461d100e675915d074be717b7b9cc)
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 
44 #include "spdk_internal/log.h"
45 
46 static void
47 spdk_rpc_get_initiator_groups(struct spdk_jsonrpc_request *request,
48 			      const struct spdk_json_val *params)
49 {
50 	struct spdk_json_write_ctx *w;
51 	struct spdk_iscsi_init_grp *ig;
52 	int i;
53 
54 	if (params != NULL) {
55 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
56 						 "get_initiator_groups requires no parameters");
57 		return;
58 	}
59 
60 	w = spdk_jsonrpc_begin_result(request);
61 	if (w == NULL) {
62 		return;
63 	}
64 
65 	spdk_json_write_array_begin(w);
66 
67 	TAILQ_FOREACH(ig, &g_spdk_iscsi.ig_head, tailq) {
68 		spdk_json_write_object_begin(w);
69 
70 		spdk_json_write_name(w, "initiators");
71 		spdk_json_write_array_begin(w);
72 		for (i = 0; i < ig->ninitiators; i++) {
73 			spdk_json_write_string(w, ig->initiators[i]);
74 		}
75 		spdk_json_write_array_end(w);
76 
77 		spdk_json_write_name(w, "tag");
78 		spdk_json_write_int32(w, ig->tag);
79 
80 		spdk_json_write_name(w, "netmasks");
81 		spdk_json_write_array_begin(w);
82 		for (i = 0; i < ig->nnetmasks; i++) {
83 			spdk_json_write_string(w, ig->netmasks[i]);
84 		}
85 		spdk_json_write_array_end(w);
86 
87 		spdk_json_write_object_end(w);
88 	}
89 
90 	spdk_json_write_array_end(w);
91 
92 	spdk_jsonrpc_end_result(request, w);
93 }
94 SPDK_RPC_REGISTER("get_initiator_groups", spdk_rpc_get_initiator_groups)
95 
96 struct rpc_initiator_list {
97 	size_t num_initiators;
98 	char *initiators[MAX_INITIATOR];
99 };
100 
101 static int
102 decode_rpc_initiator_list(const struct spdk_json_val *val, void *out)
103 {
104 	struct rpc_initiator_list *list = out;
105 
106 	return spdk_json_decode_array(val, spdk_json_decode_string, list->initiators, MAX_INITIATOR,
107 				      &list->num_initiators, sizeof(char *));
108 }
109 
110 static void
111 free_rpc_initiator_list(struct rpc_initiator_list *list)
112 {
113 	size_t i;
114 
115 	for (i = 0; i < list->num_initiators; i++) {
116 		free(list->initiators[i]);
117 	}
118 }
119 
120 struct rpc_netmask_list {
121 	size_t num_netmasks;
122 	char *netmasks[MAX_NETMASK];
123 };
124 
125 static int
126 decode_rpc_netmask_list(const struct spdk_json_val *val, void *out)
127 {
128 	struct rpc_netmask_list *list = out;
129 
130 	return spdk_json_decode_array(val, spdk_json_decode_string, list->netmasks, MAX_NETMASK,
131 				      &list->num_netmasks, sizeof(char *));
132 }
133 
134 static void
135 free_rpc_netmask_list(struct rpc_netmask_list *list)
136 {
137 	size_t i;
138 
139 	for (i = 0; i < list->num_netmasks; i++) {
140 		free(list->netmasks[i]);
141 	}
142 }
143 
144 struct rpc_initiator_group {
145 	int32_t tag;
146 	struct rpc_initiator_list initiator_list;
147 	struct rpc_netmask_list netmask_list;
148 };
149 
150 static void
151 free_rpc_initiator_group(struct rpc_initiator_group *ig)
152 {
153 	free_rpc_initiator_list(&ig->initiator_list);
154 	free_rpc_netmask_list(&ig->netmask_list);
155 }
156 
157 static const struct spdk_json_object_decoder rpc_initiator_group_decoders[] = {
158 	{"tag", offsetof(struct rpc_initiator_group, tag), spdk_json_decode_int32},
159 	{"initiators", offsetof(struct rpc_initiator_group, initiator_list), decode_rpc_initiator_list},
160 	{"netmasks", offsetof(struct rpc_initiator_group, netmask_list), decode_rpc_netmask_list},
161 };
162 
163 static void
164 spdk_rpc_add_initiator_group(struct spdk_jsonrpc_request *request,
165 			     const struct spdk_json_val *params)
166 {
167 	struct rpc_initiator_group req = {};
168 	size_t i;
169 	char **initiators = NULL, **netmasks = NULL;
170 	struct spdk_json_write_ctx *w;
171 
172 	if (spdk_json_decode_object(params, rpc_initiator_group_decoders,
173 				    SPDK_COUNTOF(rpc_initiator_group_decoders), &req)) {
174 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
175 		goto invalid;
176 	}
177 
178 	if (req.initiator_list.num_initiators == 0 ||
179 	    req.netmask_list.num_netmasks == 0) {
180 		goto invalid;
181 	}
182 
183 	initiators = calloc(req.initiator_list.num_initiators, sizeof(char *));
184 	if (initiators == NULL) {
185 		goto invalid;
186 	}
187 	for (i = 0; i < req.initiator_list.num_initiators; i++) {
188 		initiators[i] = strdup(req.initiator_list.initiators[i]);
189 		if (initiators[i] == NULL) {
190 			goto invalid;
191 		}
192 	}
193 
194 	netmasks = calloc(req.netmask_list.num_netmasks, sizeof(char *));
195 	if (netmasks == NULL) {
196 		goto invalid;
197 	}
198 	for (i = 0; i < req.netmask_list.num_netmasks; i++) {
199 		netmasks[i] = strdup(req.netmask_list.netmasks[i]);
200 		if (netmasks[i] == NULL) {
201 			goto invalid;
202 		}
203 	}
204 
205 	if (spdk_iscsi_init_grp_create_from_initiator_list(req.tag,
206 			req.initiator_list.num_initiators,
207 			initiators,
208 			req.netmask_list.num_netmasks,
209 			netmasks)) {
210 		SPDK_ERRLOG("create_from_initiator_list failed\n");
211 		goto invalid;
212 	}
213 
214 	free_rpc_initiator_group(&req);
215 
216 	w = spdk_jsonrpc_begin_result(request);
217 	if (w == NULL) {
218 		return;
219 	}
220 
221 	spdk_json_write_bool(w, true);
222 	spdk_jsonrpc_end_result(request, w);
223 	return;
224 
225 invalid:
226 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
227 	if (initiators) {
228 		for (i = 0; i < req.initiator_list.num_initiators; i++) {
229 			free(initiators[i]);
230 		}
231 		free(initiators);
232 	}
233 	if (netmasks) {
234 		for (i = 0; i < req.netmask_list.num_netmasks; i++) {
235 			free(netmasks[i]);
236 		}
237 		free(netmasks);
238 	}
239 	free_rpc_initiator_group(&req);
240 }
241 SPDK_RPC_REGISTER("add_initiator_group", spdk_rpc_add_initiator_group)
242 
243 struct rpc_delete_initiator_group {
244 	int32_t tag;
245 };
246 
247 static const struct spdk_json_object_decoder rpc_delete_initiator_group_decoders[] = {
248 	{"tag", offsetof(struct rpc_delete_initiator_group, tag), spdk_json_decode_int32},
249 };
250 
251 static void
252 spdk_rpc_delete_initiator_group(struct spdk_jsonrpc_request *request,
253 				const struct spdk_json_val *params)
254 {
255 	struct rpc_delete_initiator_group req = {};
256 	struct spdk_json_write_ctx *w;
257 	struct spdk_iscsi_init_grp *ig;
258 
259 	if (spdk_json_decode_object(params, rpc_delete_initiator_group_decoders,
260 				    SPDK_COUNTOF(rpc_delete_initiator_group_decoders),
261 				    &req)) {
262 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
263 		goto invalid;
264 	}
265 
266 	if (spdk_iscsi_init_grp_deletable(req.tag)) {
267 		goto invalid;
268 	}
269 
270 	ig = spdk_iscsi_init_grp_find_by_tag(req.tag);
271 	if (!ig) {
272 		goto invalid;
273 	}
274 	spdk_iscsi_tgt_node_delete_map(NULL, ig);
275 	spdk_iscsi_init_grp_release(ig);
276 
277 	w = spdk_jsonrpc_begin_result(request);
278 	if (w == NULL) {
279 		return;
280 	}
281 
282 	spdk_json_write_bool(w, true);
283 	spdk_jsonrpc_end_result(request, w);
284 	return;
285 
286 invalid:
287 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
288 }
289 SPDK_RPC_REGISTER("delete_initiator_group", spdk_rpc_delete_initiator_group)
290 
291 static void
292 spdk_rpc_get_target_nodes(struct spdk_jsonrpc_request *request,
293 			  const struct spdk_json_val *params)
294 {
295 	struct spdk_iscsi_globals *iscsi = &g_spdk_iscsi;
296 	struct spdk_json_write_ctx *w;
297 	size_t tgt_idx;
298 	int i;
299 
300 	if (params != NULL) {
301 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
302 						 "get_target_nodes requires no parameters");
303 		return;
304 	}
305 
306 	w = spdk_jsonrpc_begin_result(request);
307 	if (w == NULL) {
308 		return;
309 	}
310 
311 	spdk_json_write_array_begin(w);
312 
313 	for (tgt_idx = 0 ; tgt_idx < MAX_ISCSI_TARGET_NODE; tgt_idx++) {
314 		struct spdk_iscsi_tgt_node *tgtnode = iscsi->target[tgt_idx];
315 
316 		if (tgtnode == NULL) {
317 			continue;
318 		}
319 
320 		spdk_json_write_object_begin(w);
321 
322 		spdk_json_write_name(w, "name");
323 		spdk_json_write_string(w, tgtnode->name);
324 
325 		if (tgtnode->alias) {
326 			spdk_json_write_name(w, "alias_name");
327 			spdk_json_write_string(w, tgtnode->alias);
328 		}
329 
330 		spdk_json_write_name(w, "pg_ig_maps");
331 		spdk_json_write_array_begin(w);
332 		for (i = 0; i < tgtnode->maxmap; i++) {
333 			spdk_json_write_object_begin(w);
334 			spdk_json_write_name(w, "pg_tag");
335 			spdk_json_write_int32(w, tgtnode->map[i].pg->tag);
336 			spdk_json_write_name(w, "ig_tag");
337 			spdk_json_write_int32(w, tgtnode->map[i].ig->tag);
338 			spdk_json_write_object_end(w);
339 		}
340 		spdk_json_write_array_end(w);
341 
342 		spdk_json_write_name(w, "luns");
343 		spdk_json_write_array_begin(w);
344 		for (i = 0; i < SPDK_SCSI_DEV_MAX_LUN; i++) {
345 			struct spdk_scsi_lun *lun = spdk_scsi_dev_get_lun(tgtnode->dev, i);
346 
347 			if (lun) {
348 				spdk_json_write_object_begin(w);
349 				spdk_json_write_name(w, "name");
350 				spdk_json_write_string(w, spdk_scsi_lun_get_name(lun));
351 				spdk_json_write_name(w, "id");
352 				spdk_json_write_int32(w, spdk_scsi_lun_get_id(lun));
353 				spdk_json_write_object_end(w);
354 			}
355 		}
356 		spdk_json_write_array_end(w);
357 
358 		spdk_json_write_name(w, "queue_depth");
359 		spdk_json_write_int32(w, tgtnode->queue_depth);
360 
361 		/*
362 		 * TODO: convert these to bool
363 		 */
364 
365 		spdk_json_write_name(w, "chap_disabled");
366 		spdk_json_write_int32(w, tgtnode->auth_chap_disabled);
367 
368 		spdk_json_write_name(w, "chap_required");
369 		spdk_json_write_int32(w, tgtnode->auth_chap_required);
370 
371 		spdk_json_write_name(w, "chap_mutual");
372 		spdk_json_write_int32(w, tgtnode->auth_chap_mutual);
373 
374 		spdk_json_write_name(w, "chap_auth_group");
375 		spdk_json_write_int32(w, tgtnode->auth_group);
376 
377 		spdk_json_write_object_end(w);
378 	}
379 	spdk_json_write_array_end(w);
380 
381 	spdk_jsonrpc_end_result(request, w);
382 }
383 SPDK_RPC_REGISTER("get_target_nodes", spdk_rpc_get_target_nodes)
384 
385 struct rpc_pg_tags {
386 	size_t num_tags;
387 	int32_t tags[MAX_TARGET_MAP];
388 };
389 
390 static int
391 decode_rpc_pg_tags(const struct spdk_json_val *val, void *out)
392 {
393 	struct rpc_pg_tags *pg_tags = out;
394 
395 	return spdk_json_decode_array(val, spdk_json_decode_int32, pg_tags->tags, MAX_TARGET_MAP,
396 				      &pg_tags->num_tags, sizeof(int32_t));
397 }
398 
399 struct rpc_ig_tags {
400 	size_t num_tags;
401 	int32_t tags[MAX_TARGET_MAP];
402 };
403 
404 static int
405 decode_rpc_ig_tags(const struct spdk_json_val *val, void *out)
406 {
407 	struct rpc_ig_tags *ig_tags = out;
408 
409 	return spdk_json_decode_array(val, spdk_json_decode_int32, ig_tags->tags, MAX_TARGET_MAP,
410 				      &ig_tags->num_tags, sizeof(int32_t));
411 }
412 
413 #define RPC_CONSTRUCT_TARGET_NODE_MAX_LUN	64
414 
415 struct rpc_lun_names {
416 	size_t num_names;
417 	char *names[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
418 };
419 
420 static int
421 decode_rpc_lun_names(const struct spdk_json_val *val, void *out)
422 {
423 	struct rpc_lun_names *lun_names = out;
424 
425 	return spdk_json_decode_array(val, spdk_json_decode_string, lun_names->names,
426 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
427 				      &lun_names->num_names, sizeof(char *));
428 }
429 
430 static void
431 free_rpc_lun_names(struct rpc_lun_names *r)
432 {
433 	size_t i;
434 
435 	for (i = 0; i < r->num_names; i++) {
436 		free(r->names[i]);
437 	}
438 }
439 
440 struct rpc_lun_ids {
441 	size_t num_ids;
442 	int32_t ids[RPC_CONSTRUCT_TARGET_NODE_MAX_LUN];
443 };
444 
445 static int
446 decode_rpc_lun_ids(const struct spdk_json_val *val, void *out)
447 {
448 	struct rpc_lun_ids *lun_ids = out;
449 
450 	return spdk_json_decode_array(val, spdk_json_decode_int32, lun_ids->ids,
451 				      RPC_CONSTRUCT_TARGET_NODE_MAX_LUN,
452 				      &lun_ids->num_ids, sizeof(int32_t));
453 }
454 
455 struct rpc_target_node {
456 	char *name;
457 	char *alias_name;
458 
459 	struct rpc_pg_tags pg_tags;
460 	struct rpc_ig_tags ig_tags;
461 
462 	struct rpc_lun_names lun_names;
463 	struct rpc_lun_ids lun_ids;
464 
465 	int32_t queue_depth;
466 	int32_t chap_disabled;
467 	int32_t chap_required;
468 	int32_t chap_mutual;
469 	int32_t chap_auth_group;
470 };
471 
472 static void
473 free_rpc_target_node(struct rpc_target_node *req)
474 {
475 	free(req->name);
476 	free(req->alias_name);
477 	free_rpc_lun_names(&req->lun_names);
478 }
479 
480 static const struct spdk_json_object_decoder rpc_target_node_decoders[] = {
481 	{"name", offsetof(struct rpc_target_node, name), spdk_json_decode_string},
482 	{"alias_name", offsetof(struct rpc_target_node, alias_name), spdk_json_decode_string},
483 	{"pg_tags", offsetof(struct rpc_target_node, pg_tags), decode_rpc_pg_tags},
484 	{"ig_tags", offsetof(struct rpc_target_node, ig_tags), decode_rpc_ig_tags},
485 	{"lun_names", offsetof(struct rpc_target_node, lun_names), decode_rpc_lun_names},
486 	{"lun_ids", offsetof(struct rpc_target_node, lun_ids), decode_rpc_lun_ids},
487 	{"queue_depth", offsetof(struct rpc_target_node, queue_depth), spdk_json_decode_int32},
488 	{"chap_disabled", offsetof(struct rpc_target_node, chap_disabled), spdk_json_decode_int32},
489 	{"chap_required", offsetof(struct rpc_target_node, chap_required), spdk_json_decode_int32},
490 	{"chap_mutual", offsetof(struct rpc_target_node, chap_mutual), spdk_json_decode_int32},
491 	{"chap_auth_group", offsetof(struct rpc_target_node, chap_auth_group), spdk_json_decode_int32},
492 };
493 
494 static void
495 spdk_rpc_construct_target_node(struct spdk_jsonrpc_request *request,
496 			       const struct spdk_json_val *params)
497 {
498 	struct rpc_target_node req = {};
499 	struct spdk_json_write_ctx *w;
500 	struct spdk_iscsi_tgt_node *target;
501 
502 	if (spdk_json_decode_object(params, rpc_target_node_decoders,
503 				    SPDK_COUNTOF(rpc_target_node_decoders),
504 				    &req)) {
505 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
506 		goto invalid;
507 	}
508 
509 	if (req.pg_tags.num_tags != req.ig_tags.num_tags) {
510 		SPDK_ERRLOG("pg_tags/ig_tags count mismatch\n");
511 		goto invalid;
512 	}
513 
514 	if (req.lun_names.num_names != req.lun_ids.num_ids) {
515 		SPDK_ERRLOG("lun_names/lun_ids count mismatch\n");
516 		goto invalid;
517 	}
518 
519 	/*
520 	 * Use default parameters in a few places:
521 	 *  index = -1 : automatically pick an index for the new target node
522 	 *  alias = NULL
523 	 *  0, 0 = disable header/data digests
524 	 */
525 	target = spdk_iscsi_tgt_node_construct(-1, req.name, req.alias_name,
526 					       req.pg_tags.tags,
527 					       req.ig_tags.tags,
528 					       req.pg_tags.num_tags,
529 					       req.lun_names.names,
530 					       req.lun_ids.ids,
531 					       req.lun_names.num_names,
532 					       req.queue_depth,
533 					       req.chap_disabled,
534 					       req.chap_required,
535 					       req.chap_mutual,
536 					       req.chap_auth_group,
537 					       0, 0);
538 
539 	if (target == NULL) {
540 		goto invalid;
541 	}
542 
543 	free_rpc_target_node(&req);
544 
545 	w = spdk_jsonrpc_begin_result(request);
546 	if (w == NULL) {
547 		return;
548 	}
549 
550 	spdk_json_write_bool(w, true);
551 	spdk_jsonrpc_end_result(request, w);
552 	return;
553 
554 invalid:
555 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
556 	free_rpc_target_node(&req);
557 }
558 SPDK_RPC_REGISTER("construct_target_node", spdk_rpc_construct_target_node)
559 
560 struct rpc_delete_target_node {
561 	char *name;
562 };
563 
564 static void
565 free_rpc_delete_target_node(struct rpc_delete_target_node *r)
566 {
567 	free(r->name);
568 }
569 
570 static const struct spdk_json_object_decoder rpc_delete_target_node_decoders[] = {
571 	{"name", offsetof(struct rpc_delete_target_node, name), spdk_json_decode_string},
572 };
573 
574 static void
575 spdk_rpc_delete_target_node(struct spdk_jsonrpc_request *request,
576 			    const struct spdk_json_val *params)
577 {
578 	struct rpc_delete_target_node req = {};
579 	struct spdk_json_write_ctx *w;
580 
581 	if (spdk_json_decode_object(params, rpc_delete_target_node_decoders,
582 				    SPDK_COUNTOF(rpc_delete_target_node_decoders),
583 				    &req)) {
584 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
585 		goto invalid;
586 	}
587 
588 	if (req.name == NULL) {
589 		SPDK_ERRLOG("missing name param\n");
590 		goto invalid;
591 	}
592 
593 	if (spdk_iscsi_shutdown_tgt_node_by_name(req.name)) {
594 		SPDK_ERRLOG("shutdown_tgt_node_by_name failed\n");
595 		goto invalid;
596 	}
597 
598 	free_rpc_delete_target_node(&req);
599 
600 	w = spdk_jsonrpc_begin_result(request);
601 	if (w == NULL) {
602 		return;
603 	}
604 
605 	spdk_json_write_bool(w, true);
606 	spdk_jsonrpc_end_result(request, w);
607 	return;
608 
609 invalid:
610 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
611 	free_rpc_delete_target_node(&req);
612 }
613 SPDK_RPC_REGISTER("delete_target_node", spdk_rpc_delete_target_node)
614 
615 static void
616 spdk_rpc_get_portal_groups(struct spdk_jsonrpc_request *request,
617 			   const struct spdk_json_val *params)
618 {
619 	struct spdk_json_write_ctx *w;
620 	struct spdk_iscsi_portal_grp *pg;
621 	struct spdk_iscsi_portal *portal;
622 
623 	if (params != NULL) {
624 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
625 						 "get_portal_groups requires no parameters");
626 		return;
627 	}
628 
629 	w = spdk_jsonrpc_begin_result(request);
630 	if (w == NULL) {
631 		return;
632 	}
633 
634 	spdk_json_write_array_begin(w);
635 
636 	TAILQ_FOREACH(pg, &g_spdk_iscsi.pg_head, tailq) {
637 		spdk_json_write_object_begin(w);
638 
639 		spdk_json_write_name(w, "portals");
640 		spdk_json_write_array_begin(w);
641 		TAILQ_FOREACH(portal, &pg->head, tailq) {
642 			spdk_json_write_object_begin(w);
643 			spdk_json_write_name(w, "host");
644 			spdk_json_write_string(w, portal->host);
645 			spdk_json_write_name(w, "port");
646 			spdk_json_write_string(w, portal->port);
647 			spdk_json_write_object_end(w);
648 		}
649 		spdk_json_write_array_end(w);
650 
651 		spdk_json_write_name(w, "tag");
652 		spdk_json_write_int32(w, pg->tag);
653 
654 		spdk_json_write_object_end(w);
655 	}
656 
657 	spdk_json_write_array_end(w);
658 
659 	spdk_jsonrpc_end_result(request, w);
660 }
661 SPDK_RPC_REGISTER("get_portal_groups", spdk_rpc_get_portal_groups)
662 
663 struct rpc_portal {
664 	char *host;
665 	char *port;
666 };
667 
668 struct rpc_portal_list {
669 	size_t num_portals;
670 	struct rpc_portal portals[MAX_PORTAL];
671 };
672 
673 struct rpc_portal_group {
674 	int32_t tag;
675 	struct rpc_portal_list portal_list;
676 };
677 
678 static void
679 free_rpc_portal(struct rpc_portal *portal)
680 {
681 	free(portal->host);
682 	portal->host = NULL;
683 	free(portal->port);
684 	portal->port = NULL;
685 }
686 
687 static void
688 free_rpc_portal_list(struct rpc_portal_list *pl)
689 {
690 	size_t i;
691 
692 	for (i = 0; i < pl->num_portals; i++) {
693 		free_rpc_portal(&pl->portals[i]);
694 	}
695 	pl->num_portals = 0;
696 }
697 
698 static void
699 free_rpc_portal_group(struct rpc_portal_group *pg)
700 {
701 	free_rpc_portal_list(&pg->portal_list);
702 }
703 
704 static const struct spdk_json_object_decoder rpc_portal_decoders[] = {
705 	{"host", offsetof(struct rpc_portal, host), spdk_json_decode_string},
706 	{"port", offsetof(struct rpc_portal, port), spdk_json_decode_string},
707 };
708 
709 static int
710 decode_rpc_portal(const struct spdk_json_val *val, void *out)
711 {
712 	struct rpc_portal *portal = out;
713 
714 	return spdk_json_decode_object(val, rpc_portal_decoders,
715 				       SPDK_COUNTOF(rpc_portal_decoders),
716 				       portal);
717 }
718 
719 static int
720 decode_rpc_portal_list(const struct spdk_json_val *val, void *out)
721 {
722 	struct rpc_portal_list *list = out;
723 
724 	return spdk_json_decode_array(val, decode_rpc_portal, list->portals, MAX_PORTAL, &list->num_portals,
725 				      sizeof(struct rpc_portal));
726 }
727 
728 static const struct spdk_json_object_decoder rpc_portal_group_decoders[] = {
729 	{"tag", offsetof(struct rpc_portal_group, tag), spdk_json_decode_int32},
730 	{"portals", offsetof(struct rpc_portal_group, portal_list), decode_rpc_portal_list},
731 };
732 
733 static void
734 spdk_rpc_add_portal_group(struct spdk_jsonrpc_request *request,
735 			  const struct spdk_json_val *params)
736 {
737 	struct rpc_portal_group req = {};
738 	struct spdk_iscsi_portal *portal_list[MAX_PORTAL] = {};
739 	struct spdk_json_write_ctx *w;
740 	size_t i;
741 	int rc = -1;
742 
743 	if (spdk_json_decode_object(params, rpc_portal_group_decoders,
744 				    SPDK_COUNTOF(rpc_portal_group_decoders),
745 				    &req)) {
746 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
747 		goto out;
748 	}
749 
750 	for (i = 0; i < req.portal_list.num_portals; i++) {
751 		portal_list[i] = spdk_iscsi_portal_create(req.portal_list.portals[i].host,
752 				 req.portal_list.portals[i].port, 0);
753 		if (portal_list[i] == NULL) {
754 			SPDK_ERRLOG("portal_list allocation failed\n");
755 			goto out;
756 		}
757 	}
758 
759 	rc = spdk_iscsi_portal_grp_create_from_portal_list(req.tag, portal_list,
760 			req.portal_list.num_portals);
761 
762 	if (rc < 0) {
763 		SPDK_ERRLOG("create_from_portal_list failed\n");
764 	}
765 
766 out:
767 	if (rc == 0) {
768 		w = spdk_jsonrpc_begin_result(request);
769 		if (w != NULL) {
770 			spdk_json_write_bool(w, true);
771 			spdk_jsonrpc_end_result(request, w);
772 		}
773 	} else {
774 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
775 
776 		for (i = 0; i < req.portal_list.num_portals; i++) {
777 			spdk_iscsi_portal_destroy(portal_list[i]);
778 		}
779 	}
780 	free_rpc_portal_group(&req);
781 }
782 SPDK_RPC_REGISTER("add_portal_group", spdk_rpc_add_portal_group)
783 
784 struct rpc_delete_portal_group {
785 	int32_t tag;
786 };
787 
788 static const struct spdk_json_object_decoder rpc_delete_portal_group_decoders[] = {
789 	{"tag", offsetof(struct rpc_delete_portal_group, tag), spdk_json_decode_int32},
790 };
791 
792 static void
793 spdk_rpc_delete_portal_group(struct spdk_jsonrpc_request *request,
794 			     const struct spdk_json_val *params)
795 {
796 	struct rpc_delete_portal_group req = {};
797 	struct spdk_json_write_ctx *w;
798 	struct spdk_iscsi_portal_grp *pg;
799 
800 	if (spdk_json_decode_object(params, rpc_delete_portal_group_decoders,
801 				    SPDK_COUNTOF(rpc_delete_portal_group_decoders),
802 				    &req)) {
803 		SPDK_ERRLOG("spdk_json_decode_object failed\n");
804 		goto invalid;
805 	}
806 
807 	if (spdk_iscsi_portal_grp_deletable(req.tag)) {
808 		goto invalid;
809 	}
810 
811 	pg = spdk_iscsi_portal_grp_find_by_tag(req.tag);
812 	if (!pg) {
813 		goto invalid;
814 	}
815 
816 	spdk_iscsi_tgt_node_delete_map(pg, NULL);
817 	spdk_iscsi_portal_grp_release(pg);
818 
819 	w = spdk_jsonrpc_begin_result(request);
820 	if (w == NULL) {
821 		return;
822 	}
823 
824 	spdk_json_write_bool(w, true);
825 	spdk_jsonrpc_end_result(request, w);
826 	return;
827 
828 invalid:
829 	spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
830 }
831 SPDK_RPC_REGISTER("delete_portal_group", spdk_rpc_delete_portal_group)
832 
833 static void
834 spdk_rpc_get_iscsi_connections(struct spdk_jsonrpc_request *request,
835 			       const struct spdk_json_val *params)
836 {
837 	struct spdk_json_write_ctx *w;
838 	struct spdk_iscsi_conn *conns = g_conns_array;
839 	int i;
840 	uint16_t tsih;
841 
842 	if (params != NULL) {
843 		spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
844 						 "get_iscsi_connections requires no parameters");
845 		return;
846 	}
847 
848 	w = spdk_jsonrpc_begin_result(request);
849 	if (w == NULL) {
850 		return;
851 	}
852 
853 	spdk_json_write_array_begin(w);
854 
855 	for (i = 0; i < MAX_ISCSI_CONNECTIONS; i++) {
856 		struct spdk_iscsi_conn *c = &conns[i];
857 
858 		if (!c->is_valid) {
859 			continue;
860 		}
861 
862 		spdk_json_write_object_begin(w);
863 
864 		spdk_json_write_name(w, "id");
865 		spdk_json_write_int32(w, c->id);
866 
867 		spdk_json_write_name(w, "cid");
868 		spdk_json_write_int32(w, c->cid);
869 
870 		/*
871 		 * If we try to return data for a connection that has not
872 		 *  logged in yet, the session will not be set.  So in this
873 		 *  case, return -1 for the tsih rather than segfaulting
874 		 *  on the null c->sess.
875 		 */
876 		if (c->sess == NULL) {
877 			tsih = -1;
878 		} else {
879 			tsih = c->sess->tsih;
880 		}
881 		spdk_json_write_name(w, "tsih");
882 		spdk_json_write_int32(w, tsih);
883 
884 		spdk_json_write_name(w, "is_idle");
885 		spdk_json_write_int32(w, c->is_idle);
886 
887 		spdk_json_write_name(w, "lcore_id");
888 		spdk_json_write_int32(w, c->lcore);
889 
890 		spdk_json_write_name(w, "initiator_addr");
891 		spdk_json_write_string(w, c->initiator_addr);
892 
893 		spdk_json_write_name(w, "target_addr");
894 		spdk_json_write_string(w, c->target_addr);
895 
896 		spdk_json_write_name(w, "target_node_name");
897 		spdk_json_write_string(w, c->target_short_name);
898 
899 		spdk_json_write_object_end(w);
900 	}
901 	spdk_json_write_array_end(w);
902 
903 	spdk_jsonrpc_end_result(request, w);
904 }
905 SPDK_RPC_REGISTER("get_iscsi_connections", spdk_rpc_get_iscsi_connections)
906