LCOV - code coverage report
Current view: top level - lib/iscsi - iscsi_rpc.c (source / functions) Hit Total Coverage
Test: ut_cov_unit.info Lines: 0 800 0.0 %
Date: 2024-11-05 10:06:02 Functions: 0 103 0.0 %

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

Generated by: LCOV version 1.15