Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2016 Intel Corporation. All rights reserved.
3 : : * Copyright (c) 2019-2021 Mellanox Technologies LTD. All rights reserved.
4 : : * Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : * Copyright (c) 2022 Dell Inc, or its subsidiaries. All rights reserved.
6 : : */
7 : :
8 : : #include "spdk/stdinc.h"
9 : :
10 : : #include "bdev_nvme.h"
11 : :
12 : : #include "spdk/config.h"
13 : :
14 : : #include "spdk/string.h"
15 : : #include "spdk/rpc.h"
16 : : #include "spdk/util.h"
17 : : #include "spdk/env.h"
18 : : #include "spdk/nvme.h"
19 : : #include "spdk/nvme_spec.h"
20 : :
21 : : #include "spdk/log.h"
22 : : #include "spdk/bdev_module.h"
23 : :
24 : : #define TCP_PSK_INVALID_PERMISSIONS 0177
25 : :
26 : : static bool g_tls_log = false;
27 : :
28 : : static int
29 : 316 : rpc_decode_action_on_timeout(const struct spdk_json_val *val, void *out)
30 : : {
31 : 316 : enum spdk_bdev_timeout_action *action = out;
32 : :
33 [ + + ]: 316 : if (spdk_json_strequal(val, "none") == true) {
34 : 310 : *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE;
35 [ + - ]: 6 : } else if (spdk_json_strequal(val, "abort") == true) {
36 : 6 : *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_ABORT;
37 [ # # ]: 0 : } else if (spdk_json_strequal(val, "reset") == true) {
38 : 0 : *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_RESET;
39 : : } else {
40 : 0 : SPDK_NOTICELOG("Invalid parameter value: action_on_timeout\n");
41 : 0 : return -EINVAL;
42 : : }
43 : :
44 : 316 : return 0;
45 : : }
46 : :
47 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_options_decoders[] = {
48 : : {"action_on_timeout", offsetof(struct spdk_bdev_nvme_opts, action_on_timeout), rpc_decode_action_on_timeout, true},
49 : : {"timeout_us", offsetof(struct spdk_bdev_nvme_opts, timeout_us), spdk_json_decode_uint64, true},
50 : : {"timeout_admin_us", offsetof(struct spdk_bdev_nvme_opts, timeout_admin_us), spdk_json_decode_uint64, true},
51 : : {"keep_alive_timeout_ms", offsetof(struct spdk_bdev_nvme_opts, keep_alive_timeout_ms), spdk_json_decode_uint32, true},
52 : : {"retry_count", offsetof(struct spdk_bdev_nvme_opts, transport_retry_count), spdk_json_decode_uint32, true},
53 : : {"arbitration_burst", offsetof(struct spdk_bdev_nvme_opts, arbitration_burst), spdk_json_decode_uint32, true},
54 : : {"low_priority_weight", offsetof(struct spdk_bdev_nvme_opts, low_priority_weight), spdk_json_decode_uint32, true},
55 : : {"medium_priority_weight", offsetof(struct spdk_bdev_nvme_opts, medium_priority_weight), spdk_json_decode_uint32, true},
56 : : {"high_priority_weight", offsetof(struct spdk_bdev_nvme_opts, high_priority_weight), spdk_json_decode_uint32, true},
57 : : {"nvme_adminq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_adminq_poll_period_us), spdk_json_decode_uint64, true},
58 : : {"nvme_ioq_poll_period_us", offsetof(struct spdk_bdev_nvme_opts, nvme_ioq_poll_period_us), spdk_json_decode_uint64, true},
59 : : {"io_queue_requests", offsetof(struct spdk_bdev_nvme_opts, io_queue_requests), spdk_json_decode_uint32, true},
60 : : {"delay_cmd_submit", offsetof(struct spdk_bdev_nvme_opts, delay_cmd_submit), spdk_json_decode_bool, true},
61 : : {"transport_retry_count", offsetof(struct spdk_bdev_nvme_opts, transport_retry_count), spdk_json_decode_uint32, true},
62 : : {"bdev_retry_count", offsetof(struct spdk_bdev_nvme_opts, bdev_retry_count), spdk_json_decode_int32, true},
63 : : {"transport_ack_timeout", offsetof(struct spdk_bdev_nvme_opts, transport_ack_timeout), spdk_json_decode_uint8, true},
64 : : {"ctrlr_loss_timeout_sec", offsetof(struct spdk_bdev_nvme_opts, ctrlr_loss_timeout_sec), spdk_json_decode_int32, true},
65 : : {"reconnect_delay_sec", offsetof(struct spdk_bdev_nvme_opts, reconnect_delay_sec), spdk_json_decode_uint32, true},
66 : : {"fast_io_fail_timeout_sec", offsetof(struct spdk_bdev_nvme_opts, fast_io_fail_timeout_sec), spdk_json_decode_uint32, true},
67 : : {"disable_auto_failback", offsetof(struct spdk_bdev_nvme_opts, disable_auto_failback), spdk_json_decode_bool, true},
68 : : {"generate_uuids", offsetof(struct spdk_bdev_nvme_opts, generate_uuids), spdk_json_decode_bool, true},
69 : : {"transport_tos", offsetof(struct spdk_bdev_nvme_opts, transport_tos), spdk_json_decode_uint8, true},
70 : : {"nvme_error_stat", offsetof(struct spdk_bdev_nvme_opts, nvme_error_stat), spdk_json_decode_bool, true},
71 : : {"rdma_srq_size", offsetof(struct spdk_bdev_nvme_opts, rdma_srq_size), spdk_json_decode_uint32, true},
72 : : {"io_path_stat", offsetof(struct spdk_bdev_nvme_opts, io_path_stat), spdk_json_decode_bool, true},
73 : : {"allow_accel_sequence", offsetof(struct spdk_bdev_nvme_opts, allow_accel_sequence), spdk_json_decode_bool, true},
74 : : {"rdma_max_cq_size", offsetof(struct spdk_bdev_nvme_opts, rdma_max_cq_size), spdk_json_decode_uint32, true},
75 : : };
76 : :
77 : : static void
78 : 341 : rpc_bdev_nvme_set_options(struct spdk_jsonrpc_request *request,
79 : : const struct spdk_json_val *params)
80 : : {
81 : 140 : struct spdk_bdev_nvme_opts opts;
82 : : int rc;
83 : :
84 : 341 : bdev_nvme_get_opts(&opts);
85 [ + - - + ]: 341 : if (params && spdk_json_decode_object(params, rpc_bdev_nvme_options_decoders,
86 : : SPDK_COUNTOF(rpc_bdev_nvme_options_decoders),
87 : : &opts)) {
88 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
89 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
90 : : "spdk_json_decode_object failed");
91 : 0 : return;
92 : : }
93 : :
94 : 341 : rc = bdev_nvme_set_opts(&opts);
95 [ - + ]: 341 : if (rc == -EPERM) {
96 : 0 : spdk_jsonrpc_send_error_response(request, -EPERM,
97 : : "RPC not permitted with nvme controllers already attached");
98 [ - + ]: 341 : } else if (rc) {
99 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
100 : : } else {
101 : 341 : spdk_jsonrpc_send_bool_response(request, true);
102 : : }
103 : :
104 : 341 : return;
105 : : }
106 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_set_options", rpc_bdev_nvme_set_options,
107 : : SPDK_RPC_STARTUP | SPDK_RPC_RUNTIME)
108 : :
109 : : struct rpc_bdev_nvme_hotplug {
110 : : bool enabled;
111 : : uint64_t period_us;
112 : : };
113 : :
114 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_hotplug_decoders[] = {
115 : : {"enable", offsetof(struct rpc_bdev_nvme_hotplug, enabled), spdk_json_decode_bool, false},
116 : : {"period_us", offsetof(struct rpc_bdev_nvme_hotplug, period_us), spdk_json_decode_uint64, true},
117 : : };
118 : :
119 : : static void
120 : 248 : rpc_bdev_nvme_set_hotplug_done(void *ctx)
121 : : {
122 : 248 : struct spdk_jsonrpc_request *request = ctx;
123 : :
124 : 248 : spdk_jsonrpc_send_bool_response(request, true);
125 : 248 : }
126 : :
127 : : static void
128 : 248 : rpc_bdev_nvme_set_hotplug(struct spdk_jsonrpc_request *request,
129 : : const struct spdk_json_val *params)
130 : : {
131 : 248 : struct rpc_bdev_nvme_hotplug req = {false, 0};
132 : : int rc;
133 : :
134 [ - + ]: 248 : if (spdk_json_decode_object(params, rpc_bdev_nvme_hotplug_decoders,
135 : : SPDK_COUNTOF(rpc_bdev_nvme_hotplug_decoders), &req)) {
136 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
137 : 0 : rc = -EINVAL;
138 : 0 : goto invalid;
139 : : }
140 : :
141 [ - + ]: 248 : rc = bdev_nvme_set_hotplug(req.enabled, req.period_us, rpc_bdev_nvme_set_hotplug_done,
142 : : request);
143 [ - + ]: 248 : if (rc) {
144 : 0 : goto invalid;
145 : : }
146 : :
147 : 248 : return;
148 : 0 : invalid:
149 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
150 : : }
151 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_set_hotplug", rpc_bdev_nvme_set_hotplug, SPDK_RPC_RUNTIME)
152 : :
153 : : enum bdev_nvme_multipath_mode {
154 : : BDEV_NVME_MP_MODE_FAILOVER,
155 : : BDEV_NVME_MP_MODE_MULTIPATH,
156 : : BDEV_NVME_MP_MODE_DISABLE,
157 : : };
158 : :
159 : : struct rpc_bdev_nvme_attach_controller {
160 : : char *name;
161 : : char *trtype;
162 : : char *adrfam;
163 : : char *traddr;
164 : : char *trsvcid;
165 : : char *priority;
166 : : char *subnqn;
167 : : char *hostnqn;
168 : : char *hostaddr;
169 : : char *hostsvcid;
170 : : char *psk;
171 : : enum bdev_nvme_multipath_mode multipath;
172 : : struct nvme_ctrlr_opts bdev_opts;
173 : : struct spdk_nvme_ctrlr_opts drv_opts;
174 : : uint32_t max_bdevs;
175 : : };
176 : :
177 : : static void
178 : 786 : free_rpc_bdev_nvme_attach_controller(struct rpc_bdev_nvme_attach_controller *req)
179 : : {
180 : 786 : free(req->name);
181 : 786 : free(req->trtype);
182 : 786 : free(req->adrfam);
183 : 786 : free(req->traddr);
184 : 786 : free(req->trsvcid);
185 : 786 : free(req->priority);
186 : 786 : free(req->subnqn);
187 : 786 : free(req->hostnqn);
188 : 786 : free(req->hostaddr);
189 : 786 : free(req->hostsvcid);
190 : 786 : free(req->psk);
191 : 786 : spdk_memset_s(req->drv_opts.psk, sizeof(req->drv_opts.psk), 0, sizeof(req->drv_opts.psk));
192 : 786 : }
193 : :
194 : : static int
195 : 195 : bdev_nvme_decode_reftag(const struct spdk_json_val *val, void *out)
196 : : {
197 : 195 : uint32_t *flag = out;
198 : 127 : bool reftag;
199 : : int rc;
200 : :
201 : 195 : rc = spdk_json_decode_bool(val, &reftag);
202 [ + - - + : 195 : if (rc == 0 && reftag == true) {
- + ]
203 : 0 : *flag |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
204 : : }
205 : :
206 : 195 : return rc;
207 : : }
208 : :
209 : : static int
210 : 195 : bdev_nvme_decode_guard(const struct spdk_json_val *val, void *out)
211 : : {
212 : 195 : uint32_t *flag = out;
213 : 127 : bool guard;
214 : : int rc;
215 : :
216 : 195 : rc = spdk_json_decode_bool(val, &guard);
217 [ + - - + : 195 : if (rc == 0 && guard == true) {
- + ]
218 : 0 : *flag |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
219 : : }
220 : :
221 : 195 : return rc;
222 : : }
223 : :
224 : : static int
225 : 6 : bdev_nvme_decode_multipath(const struct spdk_json_val *val, void *out)
226 : : {
227 : 6 : enum bdev_nvme_multipath_mode *multipath = out;
228 : :
229 [ + + ]: 6 : if (spdk_json_strequal(val, "failover") == true) {
230 : 2 : *multipath = BDEV_NVME_MP_MODE_FAILOVER;
231 [ + + ]: 4 : } else if (spdk_json_strequal(val, "multipath") == true) {
232 : 2 : *multipath = BDEV_NVME_MP_MODE_MULTIPATH;
233 [ + - ]: 2 : } else if (spdk_json_strequal(val, "disable") == true) {
234 : 2 : *multipath = BDEV_NVME_MP_MODE_DISABLE;
235 : : } else {
236 : 0 : SPDK_NOTICELOG("Invalid parameter value: multipath\n");
237 : 0 : return -EINVAL;
238 : : }
239 : :
240 : 6 : return 0;
241 : : }
242 : :
243 : :
244 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_attach_controller_decoders[] = {
245 : : {"name", offsetof(struct rpc_bdev_nvme_attach_controller, name), spdk_json_decode_string},
246 : : {"trtype", offsetof(struct rpc_bdev_nvme_attach_controller, trtype), spdk_json_decode_string},
247 : : {"traddr", offsetof(struct rpc_bdev_nvme_attach_controller, traddr), spdk_json_decode_string},
248 : :
249 : : {"adrfam", offsetof(struct rpc_bdev_nvme_attach_controller, adrfam), spdk_json_decode_string, true},
250 : : {"trsvcid", offsetof(struct rpc_bdev_nvme_attach_controller, trsvcid), spdk_json_decode_string, true},
251 : : {"priority", offsetof(struct rpc_bdev_nvme_attach_controller, priority), spdk_json_decode_string, true},
252 : : {"subnqn", offsetof(struct rpc_bdev_nvme_attach_controller, subnqn), spdk_json_decode_string, true},
253 : : {"hostnqn", offsetof(struct rpc_bdev_nvme_attach_controller, hostnqn), spdk_json_decode_string, true},
254 : : {"hostaddr", offsetof(struct rpc_bdev_nvme_attach_controller, hostaddr), spdk_json_decode_string, true},
255 : : {"hostsvcid", offsetof(struct rpc_bdev_nvme_attach_controller, hostsvcid), spdk_json_decode_string, true},
256 : :
257 : : {"prchk_reftag", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.prchk_flags), bdev_nvme_decode_reftag, true},
258 : : {"prchk_guard", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.prchk_flags), bdev_nvme_decode_guard, true},
259 : : {"hdgst", offsetof(struct rpc_bdev_nvme_attach_controller, drv_opts.header_digest), spdk_json_decode_bool, true},
260 : : {"ddgst", offsetof(struct rpc_bdev_nvme_attach_controller, drv_opts.data_digest), spdk_json_decode_bool, true},
261 : : {"fabrics_connect_timeout_us", offsetof(struct rpc_bdev_nvme_attach_controller, drv_opts.fabrics_connect_timeout_us), spdk_json_decode_uint64, true},
262 : : {"multipath", offsetof(struct rpc_bdev_nvme_attach_controller, multipath), bdev_nvme_decode_multipath, true},
263 : : {"num_io_queues", offsetof(struct rpc_bdev_nvme_attach_controller, drv_opts.num_io_queues), spdk_json_decode_uint32, true},
264 : : {"ctrlr_loss_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.ctrlr_loss_timeout_sec), spdk_json_decode_int32, true},
265 : : {"reconnect_delay_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.reconnect_delay_sec), spdk_json_decode_uint32, true},
266 : : {"fast_io_fail_timeout_sec", offsetof(struct rpc_bdev_nvme_attach_controller, bdev_opts.fast_io_fail_timeout_sec), spdk_json_decode_uint32, true},
267 : : {"psk", offsetof(struct rpc_bdev_nvme_attach_controller, psk), spdk_json_decode_string, true},
268 : : {"max_bdevs", offsetof(struct rpc_bdev_nvme_attach_controller, max_bdevs), spdk_json_decode_uint32, true},
269 : : };
270 : :
271 : : #define DEFAULT_MAX_BDEVS_PER_RPC 128
272 : :
273 : : struct rpc_bdev_nvme_attach_controller_ctx {
274 : : struct rpc_bdev_nvme_attach_controller req;
275 : : size_t bdev_count;
276 : : const char **names;
277 : : struct spdk_jsonrpc_request *request;
278 : : };
279 : :
280 : : static void
281 : 786 : free_rpc_bdev_nvme_attach_controller_ctx(struct rpc_bdev_nvme_attach_controller_ctx *ctx)
282 : : {
283 : 786 : free_rpc_bdev_nvme_attach_controller(&ctx->req);
284 : 786 : free(ctx->names);
285 : 786 : free(ctx);
286 : 786 : }
287 : :
288 : : static void
289 : 763 : rpc_bdev_nvme_attach_controller_examined(void *cb_ctx)
290 : : {
291 : 763 : struct rpc_bdev_nvme_attach_controller_ctx *ctx = cb_ctx;
292 : 763 : struct spdk_jsonrpc_request *request = ctx->request;
293 : : struct spdk_json_write_ctx *w;
294 : : size_t i;
295 : :
296 : 763 : w = spdk_jsonrpc_begin_result(request);
297 : 763 : spdk_json_write_array_begin(w);
298 [ + + ]: 1601 : for (i = 0; i < ctx->bdev_count; i++) {
299 : 838 : spdk_json_write_string(w, ctx->names[i]);
300 : : }
301 : 763 : spdk_json_write_array_end(w);
302 : 763 : spdk_jsonrpc_end_result(request, w);
303 : :
304 : 763 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
305 : 763 : }
306 : :
307 : : static void
308 : 775 : rpc_bdev_nvme_attach_controller_done(void *cb_ctx, size_t bdev_count, int rc)
309 : : {
310 : 775 : struct rpc_bdev_nvme_attach_controller_ctx *ctx = cb_ctx;
311 : 775 : struct spdk_jsonrpc_request *request = ctx->request;
312 : :
313 [ + + ]: 775 : if (rc < 0) {
314 : 12 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
315 : 12 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
316 : 12 : return;
317 : : }
318 : :
319 : 763 : ctx->bdev_count = bdev_count;
320 : 763 : spdk_bdev_wait_for_examine(rpc_bdev_nvme_attach_controller_examined, ctx);
321 : : }
322 : :
323 : : static int
324 : 30 : tcp_load_psk(const char *fname, char *buf, size_t bufsz)
325 : : {
326 : : FILE *psk_file;
327 : 0 : struct stat statbuf;
328 : : int rc;
329 : :
330 [ - + - + : 30 : if (stat(fname, &statbuf) != 0) {
- + ]
331 : 0 : SPDK_ERRLOG("Could not read permissions for PSK file\n");
332 : 0 : return -EACCES;
333 : : }
334 : :
335 [ + + ]: 30 : if ((statbuf.st_mode & TCP_PSK_INVALID_PERMISSIONS) != 0) {
336 : 3 : SPDK_ERRLOG("Incorrect permissions for PSK file\n");
337 : 3 : return -EPERM;
338 : : }
339 [ - + ]: 27 : if ((size_t)statbuf.st_size >= bufsz) {
340 : 0 : SPDK_ERRLOG("Invalid PSK: too long\n");
341 : 0 : return -EINVAL;
342 : : }
343 : 27 : psk_file = fopen(fname, "r");
344 [ - + ]: 27 : if (psk_file == NULL) {
345 : 0 : SPDK_ERRLOG("Could not open PSK file\n");
346 : 0 : return -EINVAL;
347 : : }
348 : :
349 [ - + ]: 27 : memset(buf, 0, bufsz);
350 : 27 : rc = fread(buf, 1, statbuf.st_size, psk_file);
351 [ - + ]: 27 : if (rc != statbuf.st_size) {
352 : 0 : SPDK_ERRLOG("Failed to read PSK\n");
353 : 0 : fclose(psk_file);
354 : 0 : return -EINVAL;
355 : : }
356 : :
357 : 27 : fclose(psk_file);
358 : 27 : return 0;
359 : : }
360 : :
361 : : static void
362 : 786 : rpc_bdev_nvme_attach_controller(struct spdk_jsonrpc_request *request,
363 : : const struct spdk_json_val *params)
364 : : {
365 : : struct rpc_bdev_nvme_attach_controller_ctx *ctx;
366 : 786 : struct spdk_nvme_transport_id trid = {};
367 : : const struct spdk_nvme_ctrlr_opts *drv_opts;
368 : : const struct spdk_nvme_transport_id *ctrlr_trid;
369 : 786 : struct nvme_ctrlr *ctrlr = NULL;
370 : : size_t len, maxlen;
371 : 786 : bool multipath = false;
372 : : int rc;
373 : :
374 : 786 : ctx = calloc(1, sizeof(*ctx));
375 [ - + ]: 786 : if (!ctx) {
376 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
377 : 460 : return;
378 : : }
379 : :
380 : 786 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.drv_opts, sizeof(ctx->req.drv_opts));
381 : 786 : bdev_nvme_get_default_ctrlr_opts(&ctx->req.bdev_opts);
382 : : /* For now, initialize the multipath parameter to add a failover path. This maintains backward
383 : : * compatibility with past behavior. In the future, this behavior will change to "disable". */
384 : 786 : ctx->req.multipath = BDEV_NVME_MP_MODE_FAILOVER;
385 : 786 : ctx->req.max_bdevs = DEFAULT_MAX_BDEVS_PER_RPC;
386 : :
387 [ - + ]: 786 : if (spdk_json_decode_object(params, rpc_bdev_nvme_attach_controller_decoders,
388 : : SPDK_COUNTOF(rpc_bdev_nvme_attach_controller_decoders),
389 : 786 : &ctx->req)) {
390 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
391 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
392 : : "spdk_json_decode_object failed");
393 : 0 : goto cleanup;
394 : : }
395 : :
396 [ - + ]: 786 : if (ctx->req.max_bdevs == 0) {
397 : 0 : spdk_jsonrpc_send_error_response(request, -EINVAL, "max_bdevs cannot be zero");
398 : 0 : goto cleanup;
399 : : }
400 : :
401 : 786 : ctx->names = calloc(ctx->req.max_bdevs, sizeof(char *));
402 [ - + ]: 786 : if (ctx->names == NULL) {
403 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
404 : 0 : goto cleanup;
405 : : }
406 : :
407 : : /* Parse trstring */
408 : 786 : rc = spdk_nvme_transport_id_populate_trstring(&trid, ctx->req.trtype);
409 [ - + ]: 786 : if (rc < 0) {
410 : 0 : SPDK_ERRLOG("Failed to parse trtype: %s\n", ctx->req.trtype);
411 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s",
412 : : ctx->req.trtype);
413 : 0 : goto cleanup;
414 : : }
415 : :
416 : : /* Parse trtype */
417 : 786 : rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype);
418 [ - + ]: 786 : assert(rc == 0);
419 : :
420 : : /* Parse traddr */
421 : 786 : maxlen = sizeof(trid.traddr);
422 [ - + ]: 786 : len = strnlen(ctx->req.traddr, maxlen);
423 [ - + ]: 786 : if (len == maxlen) {
424 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "traddr too long: %s",
425 : : ctx->req.traddr);
426 : 0 : goto cleanup;
427 : : }
428 [ - + ]: 786 : memcpy(trid.traddr, ctx->req.traddr, len + 1);
429 : :
430 : : /* Parse adrfam */
431 [ + + ]: 786 : if (ctx->req.adrfam) {
432 : 262 : rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam);
433 [ - + ]: 262 : if (rc < 0) {
434 : 0 : SPDK_ERRLOG("Failed to parse adrfam: %s\n", ctx->req.adrfam);
435 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s",
436 : : ctx->req.adrfam);
437 : 0 : goto cleanup;
438 : : }
439 : : }
440 : :
441 : : /* Parse trsvcid */
442 [ + + ]: 786 : if (ctx->req.trsvcid) {
443 : 262 : maxlen = sizeof(trid.trsvcid);
444 [ - + ]: 262 : len = strnlen(ctx->req.trsvcid, maxlen);
445 [ - + ]: 262 : if (len == maxlen) {
446 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "trsvcid too long: %s",
447 : : ctx->req.trsvcid);
448 : 0 : goto cleanup;
449 : : }
450 [ - + ]: 262 : memcpy(trid.trsvcid, ctx->req.trsvcid, len + 1);
451 : : }
452 : :
453 : : /* Parse priority for the NVMe-oF transport connection */
454 [ - + ]: 786 : if (ctx->req.priority) {
455 : 0 : trid.priority = spdk_strtol(ctx->req.priority, 10);
456 : : }
457 : :
458 : : /* Parse subnqn */
459 [ + + ]: 786 : if (ctx->req.subnqn) {
460 : 262 : maxlen = sizeof(trid.subnqn);
461 [ - + ]: 262 : len = strnlen(ctx->req.subnqn, maxlen);
462 [ - + ]: 262 : if (len == maxlen) {
463 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "subnqn too long: %s",
464 : : ctx->req.subnqn);
465 : 0 : goto cleanup;
466 : : }
467 [ - + ]: 262 : memcpy(trid.subnqn, ctx->req.subnqn, len + 1);
468 : : }
469 : :
470 [ + + ]: 786 : if (ctx->req.hostnqn) {
471 : 348 : snprintf(ctx->req.drv_opts.hostnqn, sizeof(ctx->req.drv_opts.hostnqn), "%s",
472 : : ctx->req.hostnqn);
473 : : }
474 : :
475 [ + + ]: 786 : if (ctx->req.psk) {
476 [ - + + - ]: 30 : if (!g_tls_log) {
477 : 30 : SPDK_NOTICELOG("TLS support is considered experimental\n");
478 : 30 : g_tls_log = true;
479 : : }
480 : 30 : rc = tcp_load_psk(ctx->req.psk, ctx->req.drv_opts.psk, sizeof(ctx->req.drv_opts.psk));
481 [ + + ]: 30 : if (rc) {
482 : 3 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Could not retrieve PSK from file: %s",
483 : : ctx->req.psk);
484 : 3 : goto cleanup;
485 : : }
486 : 27 : rc = snprintf(ctx->req.bdev_opts.psk_path, sizeof(ctx->req.bdev_opts.psk_path), "%s", ctx->req.psk);
487 [ + - - + ]: 27 : if (rc < 0 || (size_t)rc >= sizeof(ctx->req.bdev_opts.psk_path)) {
488 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Could not store PSK path: %s",
489 : : ctx->req.psk);
490 : 0 : goto cleanup;
491 : : }
492 : : }
493 : :
494 [ + + ]: 783 : if (ctx->req.hostaddr) {
495 : 16 : maxlen = sizeof(ctx->req.drv_opts.src_addr);
496 [ - + ]: 16 : len = strnlen(ctx->req.hostaddr, maxlen);
497 [ - + ]: 16 : if (len == maxlen) {
498 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostaddr too long: %s",
499 : : ctx->req.hostaddr);
500 : 0 : goto cleanup;
501 : : }
502 : 16 : snprintf(ctx->req.drv_opts.src_addr, maxlen, "%s", ctx->req.hostaddr);
503 : : }
504 : :
505 [ + + ]: 783 : if (ctx->req.hostsvcid) {
506 : 12 : maxlen = sizeof(ctx->req.drv_opts.src_svcid);
507 [ - + ]: 12 : len = strnlen(ctx->req.hostsvcid, maxlen);
508 [ - + ]: 12 : if (len == maxlen) {
509 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostsvcid too long: %s",
510 : : ctx->req.hostsvcid);
511 : 0 : goto cleanup;
512 : : }
513 : 12 : snprintf(ctx->req.drv_opts.src_svcid, maxlen, "%s", ctx->req.hostsvcid);
514 : : }
515 : :
516 : 783 : ctrlr = nvme_ctrlr_get_by_name(ctx->req.name);
517 : :
518 [ + + ]: 783 : if (ctrlr) {
519 : : /* This controller already exists. Check what the user wants to do. */
520 [ + + ]: 28 : if (ctx->req.multipath == BDEV_NVME_MP_MODE_DISABLE) {
521 : : /* The user does not want to do any form of multipathing. */
522 : 2 : spdk_jsonrpc_send_error_response_fmt(request, -EALREADY,
523 : : "A controller named %s already exists and multipath is disabled\n",
524 : : ctx->req.name);
525 : 2 : goto cleanup;
526 : : }
527 : :
528 [ + + - + ]: 26 : assert(ctx->req.multipath == BDEV_NVME_MP_MODE_FAILOVER ||
529 : : ctx->req.multipath == BDEV_NVME_MP_MODE_MULTIPATH);
530 : :
531 : : /* The user wants to add this as a failover path or add this to create multipath. */
532 : 26 : drv_opts = spdk_nvme_ctrlr_get_opts(ctrlr->ctrlr);
533 : 26 : ctrlr_trid = spdk_nvme_ctrlr_get_transport_id(ctrlr->ctrlr);
534 : :
535 [ - + + - ]: 26 : if (strncmp(trid.traddr, ctrlr_trid->traddr, sizeof(trid.traddr)) == 0 &&
536 [ - + + + ]: 26 : strncmp(trid.trsvcid, ctrlr_trid->trsvcid, sizeof(trid.trsvcid)) == 0 &&
537 [ - + - + : 6 : strncmp(ctx->req.drv_opts.src_addr, drv_opts->src_addr, sizeof(drv_opts->src_addr)) == 0 &&
+ - ]
538 [ - + - + : 6 : strncmp(ctx->req.drv_opts.src_svcid, drv_opts->src_svcid, sizeof(drv_opts->src_svcid)) == 0) {
+ - ]
539 : : /* Exactly same network path can't be added a second time */
540 : 6 : spdk_jsonrpc_send_error_response_fmt(request, -EALREADY,
541 : : "A controller named %s already exists with the specified network path\n",
542 : : ctx->req.name);
543 : 6 : goto cleanup;
544 : : }
545 : :
546 [ - + ]: 20 : if (strncmp(trid.subnqn,
547 [ - + ]: 20 : ctrlr_trid->subnqn,
548 : : SPDK_NVMF_NQN_MAX_LEN) != 0) {
549 : : /* Different SUBNQN is not allowed when specifying the same controller name. */
550 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL,
551 : : "A controller named %s already exists, but uses a different subnqn (%s)\n",
552 : 0 : ctx->req.name, ctrlr_trid->subnqn);
553 : 0 : goto cleanup;
554 : : }
555 : :
556 [ - + - + : 20 : if (strncmp(ctx->req.drv_opts.hostnqn, drv_opts->hostnqn, SPDK_NVMF_NQN_MAX_LEN) != 0) {
- + ]
557 : : /* Different HOSTNQN is not allowed when specifying the same controller name. */
558 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL,
559 : : "A controller named %s already exists, but uses a different hostnqn (%s)\n",
560 : 0 : ctx->req.name, drv_opts->hostnqn);
561 : 0 : goto cleanup;
562 : : }
563 : :
564 [ - + ]: 20 : if (ctx->req.bdev_opts.prchk_flags) {
565 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL,
566 : : "A controller named %s already exists. To add a path, do not specify PI options.\n",
567 : : ctx->req.name);
568 : 0 : goto cleanup;
569 : : }
570 : :
571 : 20 : ctx->req.bdev_opts.prchk_flags = ctrlr->opts.prchk_flags;
572 : : }
573 : :
574 [ + + ]: 775 : if (ctx->req.multipath == BDEV_NVME_MP_MODE_MULTIPATH) {
575 : 2 : multipath = true;
576 : : }
577 : :
578 [ + - - + ]: 775 : if (ctx->req.drv_opts.num_io_queues == 0 || ctx->req.drv_opts.num_io_queues > UINT16_MAX + 1) {
579 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL,
580 : : "num_io_queues out of bounds, min: %u max: %u\n",
581 : : 1, UINT16_MAX + 1);
582 : 0 : goto cleanup;
583 : : }
584 : :
585 : 775 : ctx->request = request;
586 : : /* Should already be zero due to the calloc(), but set explicitly for clarity. */
587 : 775 : ctx->req.bdev_opts.from_discovery_service = false;
588 : 775 : rc = bdev_nvme_create(&trid, ctx->req.name, ctx->names, ctx->req.max_bdevs,
589 : : rpc_bdev_nvme_attach_controller_done, ctx, &ctx->req.drv_opts,
590 : : &ctx->req.bdev_opts, multipath);
591 [ - + ]: 775 : if (rc) {
592 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
593 : 0 : goto cleanup;
594 : : }
595 : :
596 : 775 : return;
597 : :
598 : 11 : cleanup:
599 : 11 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
600 : : }
601 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_attach_controller", rpc_bdev_nvme_attach_controller,
602 : : SPDK_RPC_RUNTIME)
603 : :
604 : : static void
605 : 77 : rpc_dump_nvme_bdev_controller_info(struct nvme_bdev_ctrlr *nbdev_ctrlr, void *ctx)
606 : : {
607 : 77 : struct spdk_json_write_ctx *w = ctx;
608 : : struct nvme_ctrlr *nvme_ctrlr;
609 : :
610 : 77 : spdk_json_write_object_begin(w);
611 : 77 : spdk_json_write_named_string(w, "name", nbdev_ctrlr->name);
612 : :
613 : 77 : spdk_json_write_named_array_begin(w, "ctrlrs");
614 [ + + ]: 164 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
615 : 87 : nvme_ctrlr_info_json(w, nvme_ctrlr);
616 : : }
617 : 77 : spdk_json_write_array_end(w);
618 : 77 : spdk_json_write_object_end(w);
619 : 77 : }
620 : :
621 : : struct rpc_bdev_nvme_get_controllers {
622 : : char *name;
623 : : };
624 : :
625 : : static void
626 : 95 : free_rpc_bdev_nvme_get_controllers(struct rpc_bdev_nvme_get_controllers *r)
627 : : {
628 : 95 : free(r->name);
629 : 95 : }
630 : :
631 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_get_controllers_decoders[] = {
632 : : {"name", offsetof(struct rpc_bdev_nvme_get_controllers, name), spdk_json_decode_string, true},
633 : : };
634 : :
635 : : static void
636 : 95 : rpc_bdev_nvme_get_controllers(struct spdk_jsonrpc_request *request,
637 : : const struct spdk_json_val *params)
638 : : {
639 : 95 : struct rpc_bdev_nvme_get_controllers req = {};
640 : : struct spdk_json_write_ctx *w;
641 : 95 : struct nvme_bdev_ctrlr *nbdev_ctrlr = NULL;
642 : :
643 [ + + - + ]: 95 : if (params && spdk_json_decode_object(params, rpc_bdev_nvme_get_controllers_decoders,
644 : : SPDK_COUNTOF(rpc_bdev_nvme_get_controllers_decoders),
645 : : &req)) {
646 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
647 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
648 : : "spdk_json_decode_object failed");
649 : 0 : goto cleanup;
650 : : }
651 : :
652 [ + + ]: 95 : if (req.name) {
653 : 15 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
654 [ - + ]: 15 : if (nbdev_ctrlr == NULL) {
655 : 0 : SPDK_ERRLOG("ctrlr '%s' does not exist\n", req.name);
656 : 0 : spdk_jsonrpc_send_error_response_fmt(request, EINVAL, "Controller %s does not exist", req.name);
657 : 0 : goto cleanup;
658 : : }
659 : : }
660 : :
661 : 95 : w = spdk_jsonrpc_begin_result(request);
662 : 95 : spdk_json_write_array_begin(w);
663 : :
664 [ + + ]: 95 : if (nbdev_ctrlr != NULL) {
665 : 15 : rpc_dump_nvme_bdev_controller_info(nbdev_ctrlr, w);
666 : : } else {
667 : 80 : nvme_bdev_ctrlr_for_each(rpc_dump_nvme_bdev_controller_info, w);
668 : : }
669 : :
670 : 95 : spdk_json_write_array_end(w);
671 : :
672 : 95 : spdk_jsonrpc_end_result(request, w);
673 : :
674 : 95 : cleanup:
675 : 95 : free_rpc_bdev_nvme_get_controllers(&req);
676 : 95 : }
677 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_controllers", rpc_bdev_nvme_get_controllers, SPDK_RPC_RUNTIME)
678 : :
679 : : struct rpc_bdev_nvme_detach_controller {
680 : : char *name;
681 : : char *trtype;
682 : : char *adrfam;
683 : : char *traddr;
684 : : char *trsvcid;
685 : : char *subnqn;
686 : : char *hostaddr;
687 : : char *hostsvcid;
688 : : };
689 : :
690 : : static void
691 : 81 : free_rpc_bdev_nvme_detach_controller(struct rpc_bdev_nvme_detach_controller *req)
692 : : {
693 : 81 : free(req->name);
694 : 81 : free(req->trtype);
695 : 81 : free(req->adrfam);
696 : 81 : free(req->traddr);
697 : 81 : free(req->trsvcid);
698 : 81 : free(req->subnqn);
699 : 81 : free(req->hostaddr);
700 : 81 : free(req->hostsvcid);
701 : 81 : }
702 : :
703 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_detach_controller_decoders[] = {
704 : : {"name", offsetof(struct rpc_bdev_nvme_detach_controller, name), spdk_json_decode_string},
705 : : {"trtype", offsetof(struct rpc_bdev_nvme_detach_controller, trtype), spdk_json_decode_string, true},
706 : : {"traddr", offsetof(struct rpc_bdev_nvme_detach_controller, traddr), spdk_json_decode_string, true},
707 : : {"adrfam", offsetof(struct rpc_bdev_nvme_detach_controller, adrfam), spdk_json_decode_string, true},
708 : : {"trsvcid", offsetof(struct rpc_bdev_nvme_detach_controller, trsvcid), spdk_json_decode_string, true},
709 : : {"subnqn", offsetof(struct rpc_bdev_nvme_detach_controller, subnqn), spdk_json_decode_string, true},
710 : : {"hostaddr", offsetof(struct rpc_bdev_nvme_detach_controller, hostaddr), spdk_json_decode_string, true},
711 : : {"hostsvcid", offsetof(struct rpc_bdev_nvme_detach_controller, hostsvcid), spdk_json_decode_string, true},
712 : : };
713 : :
714 : : static void
715 : 81 : rpc_bdev_nvme_detach_controller_done(void *arg, int rc)
716 : : {
717 : 81 : struct spdk_jsonrpc_request *request = arg;
718 : :
719 [ + - ]: 81 : if (rc == 0) {
720 : 81 : spdk_jsonrpc_send_bool_response(request, true);
721 : : } else {
722 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
723 : : }
724 : 81 : }
725 : :
726 : : static void
727 : 81 : rpc_bdev_nvme_detach_controller(struct spdk_jsonrpc_request *request,
728 : : const struct spdk_json_val *params)
729 : : {
730 : 81 : struct rpc_bdev_nvme_detach_controller req = {NULL};
731 : 81 : struct nvme_path_id path = {};
732 : : size_t len, maxlen;
733 : 81 : int rc = 0;
734 : :
735 [ - + ]: 81 : if (spdk_json_decode_object(params, rpc_bdev_nvme_detach_controller_decoders,
736 : : SPDK_COUNTOF(rpc_bdev_nvme_detach_controller_decoders),
737 : : &req)) {
738 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
739 : : "spdk_json_decode_object failed");
740 : 0 : goto cleanup;
741 : : }
742 : :
743 [ + + ]: 81 : if (req.trtype != NULL) {
744 : 14 : rc = spdk_nvme_transport_id_populate_trstring(&path.trid, req.trtype);
745 [ - + ]: 14 : if (rc < 0) {
746 : 0 : SPDK_ERRLOG("Failed to parse trtype: %s\n", req.trtype);
747 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s",
748 : : req.trtype);
749 : 0 : goto cleanup;
750 : : }
751 : :
752 : 14 : rc = spdk_nvme_transport_id_parse_trtype(&path.trid.trtype, req.trtype);
753 [ - + ]: 14 : if (rc < 0) {
754 : 0 : SPDK_ERRLOG("Failed to parse trtype: %s\n", req.trtype);
755 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s",
756 : : req.trtype);
757 : 0 : goto cleanup;
758 : : }
759 : : }
760 : :
761 [ + + ]: 81 : if (req.traddr != NULL) {
762 : 14 : maxlen = sizeof(path.trid.traddr);
763 [ - + ]: 14 : len = strnlen(req.traddr, maxlen);
764 [ - + ]: 14 : if (len == maxlen) {
765 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "traddr too long: %s",
766 : : req.traddr);
767 : 0 : goto cleanup;
768 : : }
769 [ - + ]: 14 : memcpy(path.trid.traddr, req.traddr, len + 1);
770 : : }
771 : :
772 [ + + ]: 81 : if (req.adrfam != NULL) {
773 : 14 : rc = spdk_nvme_transport_id_parse_adrfam(&path.trid.adrfam, req.adrfam);
774 [ - + ]: 14 : if (rc < 0) {
775 : 0 : SPDK_ERRLOG("Failed to parse adrfam: %s\n", req.adrfam);
776 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s",
777 : : req.adrfam);
778 : 0 : goto cleanup;
779 : : }
780 : : }
781 : :
782 [ + + ]: 81 : if (req.trsvcid != NULL) {
783 : 14 : maxlen = sizeof(path.trid.trsvcid);
784 [ - + ]: 14 : len = strnlen(req.trsvcid, maxlen);
785 [ - + ]: 14 : if (len == maxlen) {
786 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "trsvcid too long: %s",
787 : : req.trsvcid);
788 : 0 : goto cleanup;
789 : : }
790 [ - + ]: 14 : memcpy(path.trid.trsvcid, req.trsvcid, len + 1);
791 : : }
792 : :
793 : : /* Parse subnqn */
794 [ + + ]: 81 : if (req.subnqn != NULL) {
795 : 14 : maxlen = sizeof(path.trid.subnqn);
796 [ - + ]: 14 : len = strnlen(req.subnqn, maxlen);
797 [ - + ]: 14 : if (len == maxlen) {
798 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "subnqn too long: %s",
799 : : req.subnqn);
800 : 0 : goto cleanup;
801 : : }
802 [ - + ]: 14 : memcpy(path.trid.subnqn, req.subnqn, len + 1);
803 : : }
804 : :
805 [ - + ]: 81 : if (req.hostaddr) {
806 : 0 : maxlen = sizeof(path.hostid.hostaddr);
807 [ # # ]: 0 : len = strnlen(req.hostaddr, maxlen);
808 [ # # ]: 0 : if (len == maxlen) {
809 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostaddr too long: %s",
810 : : req.hostaddr);
811 : 0 : goto cleanup;
812 : : }
813 : 0 : snprintf(path.hostid.hostaddr, maxlen, "%s", req.hostaddr);
814 : : }
815 : :
816 [ - + ]: 81 : if (req.hostsvcid) {
817 : 0 : maxlen = sizeof(path.hostid.hostsvcid);
818 [ # # ]: 0 : len = strnlen(req.hostsvcid, maxlen);
819 [ # # ]: 0 : if (len == maxlen) {
820 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "hostsvcid too long: %s",
821 : : req.hostsvcid);
822 : 0 : goto cleanup;
823 : : }
824 : 0 : snprintf(path.hostid.hostsvcid, maxlen, "%s", req.hostsvcid);
825 : : }
826 : :
827 : 81 : rc = bdev_nvme_delete(req.name, &path, rpc_bdev_nvme_detach_controller_done, request);
828 : :
829 [ + - ]: 81 : if (rc != 0) {
830 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
831 : : }
832 : :
833 : 81 : cleanup:
834 : 81 : free_rpc_bdev_nvme_detach_controller(&req);
835 : 81 : }
836 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_detach_controller", rpc_bdev_nvme_detach_controller,
837 : : SPDK_RPC_RUNTIME)
838 : :
839 : : struct rpc_apply_firmware {
840 : : char *filename;
841 : : char *bdev_name;
842 : : };
843 : :
844 : : static void
845 : 6 : free_rpc_apply_firmware(struct rpc_apply_firmware *req)
846 : : {
847 : 6 : free(req->filename);
848 : 6 : free(req->bdev_name);
849 : 6 : }
850 : :
851 : : static const struct spdk_json_object_decoder rpc_apply_firmware_decoders[] = {
852 : : {"filename", offsetof(struct rpc_apply_firmware, filename), spdk_json_decode_string},
853 : : {"bdev_name", offsetof(struct rpc_apply_firmware, bdev_name), spdk_json_decode_string},
854 : : };
855 : :
856 : : struct firmware_update_info {
857 : : void *fw_image;
858 : : void *p;
859 : : unsigned int size;
860 : : unsigned int size_remaining;
861 : : unsigned int offset;
862 : : unsigned int transfer;
863 : : bool success;
864 : :
865 : : struct spdk_bdev_desc *desc;
866 : : struct spdk_io_channel *ch;
867 : : struct spdk_thread *orig_thread;
868 : : struct spdk_jsonrpc_request *request;
869 : : struct spdk_nvme_ctrlr *ctrlr;
870 : : struct rpc_apply_firmware req;
871 : : };
872 : :
873 : : static void
874 : 6 : apply_firmware_cleanup(struct firmware_update_info *firm_ctx)
875 : : {
876 [ - + ]: 6 : assert(firm_ctx != NULL);
877 [ - + ]: 6 : assert(firm_ctx->orig_thread == spdk_get_thread());
878 : :
879 [ - + ]: 6 : if (firm_ctx->fw_image) {
880 : 0 : spdk_free(firm_ctx->fw_image);
881 : : }
882 : :
883 : 6 : free_rpc_apply_firmware(&firm_ctx->req);
884 : :
885 [ + - ]: 6 : if (firm_ctx->ch) {
886 : 6 : spdk_put_io_channel(firm_ctx->ch);
887 : : }
888 : :
889 [ + - ]: 6 : if (firm_ctx->desc) {
890 : 6 : spdk_bdev_close(firm_ctx->desc);
891 : : }
892 : :
893 : 6 : free(firm_ctx);
894 : 6 : }
895 : :
896 : : static void
897 : 0 : _apply_firmware_complete_reset(void *ctx)
898 : : {
899 : : struct spdk_json_write_ctx *w;
900 : 0 : struct firmware_update_info *firm_ctx = ctx;
901 : :
902 [ # # ]: 0 : assert(firm_ctx->orig_thread == spdk_get_thread());
903 : :
904 [ # # # # ]: 0 : if (!firm_ctx->success) {
905 : 0 : spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
906 : : "firmware commit failed.");
907 : 0 : apply_firmware_cleanup(firm_ctx);
908 : 0 : return;
909 : : }
910 : :
911 [ # # ]: 0 : if (spdk_nvme_ctrlr_reset(firm_ctx->ctrlr) != 0) {
912 : 0 : spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
913 : : "Controller reset failed.");
914 : 0 : apply_firmware_cleanup(firm_ctx);
915 : 0 : return;
916 : : }
917 : :
918 : 0 : w = spdk_jsonrpc_begin_result(firm_ctx->request);
919 : 0 : spdk_json_write_string(w, "firmware commit succeeded. Controller reset in progress.");
920 : 0 : spdk_jsonrpc_end_result(firm_ctx->request, w);
921 : 0 : apply_firmware_cleanup(firm_ctx);
922 : : }
923 : :
924 : : static void
925 : 0 : apply_firmware_complete_reset(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
926 : : {
927 : 0 : struct firmware_update_info *firm_ctx = cb_arg;
928 : :
929 : 0 : spdk_bdev_free_io(bdev_io);
930 : :
931 : 0 : firm_ctx->success = success;
932 : :
933 : 0 : spdk_thread_exec_msg(firm_ctx->orig_thread, _apply_firmware_complete_reset, firm_ctx);
934 : 0 : }
935 : :
936 : : static void apply_firmware_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg);
937 : :
938 : : static void
939 : 0 : _apply_firmware_complete(void *ctx)
940 : : {
941 : 0 : struct spdk_nvme_cmd cmd = {};
942 : 0 : struct spdk_nvme_fw_commit fw_commit;
943 : 0 : int slot = 0;
944 : : int rc;
945 : 0 : struct firmware_update_info *firm_ctx = ctx;
946 : 0 : enum spdk_nvme_fw_commit_action commit_action = SPDK_NVME_FW_COMMIT_REPLACE_AND_ENABLE_IMG;
947 : :
948 [ # # ]: 0 : assert(firm_ctx->orig_thread == spdk_get_thread());
949 : :
950 [ # # # # ]: 0 : if (!firm_ctx->success) {
951 : 0 : spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
952 : : "firmware download failed .");
953 : 0 : apply_firmware_cleanup(firm_ctx);
954 : 0 : return;
955 : : }
956 : :
957 : 0 : firm_ctx->p += firm_ctx->transfer;
958 : 0 : firm_ctx->offset += firm_ctx->transfer;
959 : 0 : firm_ctx->size_remaining -= firm_ctx->transfer;
960 : :
961 [ # # ]: 0 : switch (firm_ctx->size_remaining) {
962 : 0 : case 0:
963 : : /* firmware download completed. Commit firmware */
964 [ # # ]: 0 : memset(&fw_commit, 0, sizeof(struct spdk_nvme_fw_commit));
965 : 0 : fw_commit.fs = slot;
966 : 0 : fw_commit.ca = commit_action;
967 : :
968 : 0 : cmd.opc = SPDK_NVME_OPC_FIRMWARE_COMMIT;
969 : 0 : memcpy(&cmd.cdw10, &fw_commit, sizeof(uint32_t));
970 : 0 : rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, NULL, 0,
971 : : apply_firmware_complete_reset, firm_ctx);
972 [ # # ]: 0 : if (rc) {
973 : 0 : spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
974 : : "firmware commit failed.");
975 : 0 : apply_firmware_cleanup(firm_ctx);
976 : 0 : return;
977 : : }
978 : 0 : break;
979 : 0 : default:
980 : 0 : firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096);
981 : 0 : cmd.opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
982 : :
983 : 0 : cmd.cdw10 = spdk_nvme_bytes_to_numd(firm_ctx->transfer);
984 : 0 : cmd.cdw11 = firm_ctx->offset >> 2;
985 : 0 : rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, firm_ctx->p,
986 : 0 : firm_ctx->transfer, apply_firmware_complete, firm_ctx);
987 [ # # ]: 0 : if (rc) {
988 : 0 : spdk_jsonrpc_send_error_response(firm_ctx->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
989 : : "firmware download failed.");
990 : 0 : apply_firmware_cleanup(firm_ctx);
991 : 0 : return;
992 : : }
993 : 0 : break;
994 : : }
995 : : }
996 : :
997 : : static void
998 : 0 : apply_firmware_complete(struct spdk_bdev_io *bdev_io, bool success, void *cb_arg)
999 : : {
1000 : 0 : struct firmware_update_info *firm_ctx = cb_arg;
1001 : :
1002 : 0 : spdk_bdev_free_io(bdev_io);
1003 : :
1004 : 0 : firm_ctx->success = success;
1005 : :
1006 : 0 : spdk_thread_exec_msg(firm_ctx->orig_thread, _apply_firmware_complete, firm_ctx);
1007 : 0 : }
1008 : :
1009 : : static void
1010 : 0 : apply_firmware_open_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *event_ctx)
1011 : : {
1012 : 0 : }
1013 : :
1014 : : static void
1015 : 6 : rpc_bdev_nvme_apply_firmware(struct spdk_jsonrpc_request *request,
1016 : : const struct spdk_json_val *params)
1017 : : {
1018 : : int rc;
1019 : 6 : int fd = -1;
1020 : 3 : struct stat fw_stat;
1021 : : struct spdk_bdev *bdev;
1022 : 6 : struct spdk_nvme_cmd cmd = {};
1023 : : struct firmware_update_info *firm_ctx;
1024 : :
1025 : 6 : firm_ctx = calloc(1, sizeof(struct firmware_update_info));
1026 [ - + ]: 6 : if (!firm_ctx) {
1027 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1028 : : "Memory allocation error.");
1029 : 0 : return;
1030 : : }
1031 : 6 : firm_ctx->fw_image = NULL;
1032 : 6 : firm_ctx->request = request;
1033 : 6 : firm_ctx->orig_thread = spdk_get_thread();
1034 : :
1035 [ - + ]: 6 : if (spdk_json_decode_object(params, rpc_apply_firmware_decoders,
1036 : 6 : SPDK_COUNTOF(rpc_apply_firmware_decoders), &firm_ctx->req)) {
1037 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1038 : : "spdk_json_decode_object failed.");
1039 : 0 : goto err;
1040 : : }
1041 : :
1042 [ - + ]: 6 : if (spdk_bdev_open_ext(firm_ctx->req.bdev_name, true, apply_firmware_open_cb, NULL,
1043 : : &firm_ctx->desc) != 0) {
1044 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1045 : : "bdev %s could not be opened",
1046 : : firm_ctx->req.bdev_name);
1047 : 0 : goto err;
1048 : : }
1049 : 6 : bdev = spdk_bdev_desc_get_bdev(firm_ctx->desc);
1050 : :
1051 [ - + ]: 6 : if ((firm_ctx->ctrlr = bdev_nvme_get_ctrlr(bdev)) == NULL) {
1052 : 0 : spdk_jsonrpc_send_error_response_fmt(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1053 : : "Controller information for %s were not found.",
1054 : : firm_ctx->req.bdev_name);
1055 : 0 : goto err;
1056 : : }
1057 : :
1058 : 6 : firm_ctx->ch = spdk_bdev_get_io_channel(firm_ctx->desc);
1059 [ - + ]: 6 : if (!firm_ctx->ch) {
1060 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1061 : : "No channels were found.");
1062 : 0 : goto err;
1063 : : }
1064 : :
1065 [ - + ]: 6 : fd = open(firm_ctx->req.filename, O_RDONLY);
1066 [ + - ]: 6 : if (fd < 0) {
1067 : 6 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1068 : : "open file failed.");
1069 : 6 : goto err;
1070 : : }
1071 : :
1072 [ # # ]: 0 : rc = fstat(fd, &fw_stat);
1073 [ # # ]: 0 : if (rc < 0) {
1074 : 0 : close(fd);
1075 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1076 : : "fstat failed.");
1077 : 0 : goto err;
1078 : : }
1079 : :
1080 : 0 : firm_ctx->size = fw_stat.st_size;
1081 [ # # ]: 0 : if (fw_stat.st_size % 4) {
1082 : 0 : close(fd);
1083 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1084 : : "Firmware image size is not multiple of 4.");
1085 : 0 : goto err;
1086 : : }
1087 : :
1088 : 0 : firm_ctx->fw_image = spdk_zmalloc(firm_ctx->size, 4096, NULL,
1089 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
1090 [ # # ]: 0 : if (!firm_ctx->fw_image) {
1091 : 0 : close(fd);
1092 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1093 : : "Memory allocation error.");
1094 : 0 : goto err;
1095 : : }
1096 : 0 : firm_ctx->p = firm_ctx->fw_image;
1097 : :
1098 [ # # ]: 0 : if (read(fd, firm_ctx->p, firm_ctx->size) != ((ssize_t)(firm_ctx->size))) {
1099 : 0 : close(fd);
1100 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1101 : : "Read firmware image failed!");
1102 : 0 : goto err;
1103 : : }
1104 : 0 : close(fd);
1105 : :
1106 : 0 : firm_ctx->offset = 0;
1107 : 0 : firm_ctx->size_remaining = firm_ctx->size;
1108 : 0 : firm_ctx->transfer = spdk_min(firm_ctx->size_remaining, 4096);
1109 : :
1110 : 0 : cmd.opc = SPDK_NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD;
1111 : 0 : cmd.cdw10 = spdk_nvme_bytes_to_numd(firm_ctx->transfer);
1112 : 0 : cmd.cdw11 = firm_ctx->offset >> 2;
1113 : :
1114 : 0 : rc = spdk_bdev_nvme_admin_passthru(firm_ctx->desc, firm_ctx->ch, &cmd, firm_ctx->p,
1115 : 0 : firm_ctx->transfer, apply_firmware_complete, firm_ctx);
1116 [ # # ]: 0 : if (rc == 0) {
1117 : : /* normal return here. */
1118 : 0 : return;
1119 : : }
1120 : :
1121 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1122 : : "Read firmware image failed!");
1123 : 6 : err:
1124 : 6 : apply_firmware_cleanup(firm_ctx);
1125 : : }
1126 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_apply_firmware", rpc_bdev_nvme_apply_firmware, SPDK_RPC_RUNTIME)
1127 : :
1128 : : struct rpc_bdev_nvme_transport_stat_ctx {
1129 : : struct spdk_jsonrpc_request *request;
1130 : : struct spdk_json_write_ctx *w;
1131 : : };
1132 : :
1133 : : static void
1134 : 0 : rpc_bdev_nvme_rdma_stats(struct spdk_json_write_ctx *w,
1135 : : struct spdk_nvme_transport_poll_group_stat *stat)
1136 : : {
1137 : : struct spdk_nvme_rdma_device_stat *device_stats;
1138 : : uint32_t i;
1139 : :
1140 : 0 : spdk_json_write_named_array_begin(w, "devices");
1141 : :
1142 [ # # ]: 0 : for (i = 0; i < stat->rdma.num_devices; i++) {
1143 : 0 : device_stats = &stat->rdma.device_stats[i];
1144 : 0 : spdk_json_write_object_begin(w);
1145 : 0 : spdk_json_write_named_string(w, "dev_name", device_stats->name);
1146 : 0 : spdk_json_write_named_uint64(w, "polls", device_stats->polls);
1147 : 0 : spdk_json_write_named_uint64(w, "idle_polls", device_stats->idle_polls);
1148 : 0 : spdk_json_write_named_uint64(w, "completions", device_stats->completions);
1149 : 0 : spdk_json_write_named_uint64(w, "queued_requests", device_stats->queued_requests);
1150 : 0 : spdk_json_write_named_uint64(w, "total_send_wrs", device_stats->total_send_wrs);
1151 : 0 : spdk_json_write_named_uint64(w, "send_doorbell_updates", device_stats->send_doorbell_updates);
1152 : 0 : spdk_json_write_named_uint64(w, "total_recv_wrs", device_stats->total_recv_wrs);
1153 : 0 : spdk_json_write_named_uint64(w, "recv_doorbell_updates", device_stats->recv_doorbell_updates);
1154 : 0 : spdk_json_write_object_end(w);
1155 : : }
1156 : 0 : spdk_json_write_array_end(w);
1157 : 0 : }
1158 : :
1159 : : static void
1160 : 0 : rpc_bdev_nvme_pcie_stats(struct spdk_json_write_ctx *w,
1161 : : struct spdk_nvme_transport_poll_group_stat *stat)
1162 : : {
1163 : 0 : spdk_json_write_named_uint64(w, "polls", stat->pcie.polls);
1164 : 0 : spdk_json_write_named_uint64(w, "idle_polls", stat->pcie.idle_polls);
1165 : 0 : spdk_json_write_named_uint64(w, "completions", stat->pcie.completions);
1166 : 0 : spdk_json_write_named_uint64(w, "cq_mmio_doorbell_updates", stat->pcie.cq_mmio_doorbell_updates);
1167 : 0 : spdk_json_write_named_uint64(w, "cq_shadow_doorbell_updates",
1168 : : stat->pcie.cq_shadow_doorbell_updates);
1169 : 0 : spdk_json_write_named_uint64(w, "queued_requests", stat->pcie.queued_requests);
1170 : 0 : spdk_json_write_named_uint64(w, "submitted_requests", stat->pcie.submitted_requests);
1171 : 0 : spdk_json_write_named_uint64(w, "sq_mmio_doorbell_updates", stat->pcie.sq_mmio_doorbell_updates);
1172 : 0 : spdk_json_write_named_uint64(w, "sq_shadow_doorbell_updates",
1173 : : stat->pcie.sq_shadow_doorbell_updates);
1174 : 0 : }
1175 : :
1176 : : static void
1177 : 0 : rpc_bdev_nvme_tcp_stats(struct spdk_json_write_ctx *w,
1178 : : struct spdk_nvme_transport_poll_group_stat *stat)
1179 : : {
1180 : 0 : spdk_json_write_named_uint64(w, "polls", stat->tcp.polls);
1181 : 0 : spdk_json_write_named_uint64(w, "idle_polls", stat->tcp.idle_polls);
1182 : 0 : spdk_json_write_named_uint64(w, "socket_completions", stat->tcp.socket_completions);
1183 : 0 : spdk_json_write_named_uint64(w, "nvme_completions", stat->tcp.nvme_completions);
1184 : 0 : spdk_json_write_named_uint64(w, "queued_requests", stat->tcp.queued_requests);
1185 : 0 : spdk_json_write_named_uint64(w, "submitted_requests", stat->tcp.submitted_requests);
1186 : 0 : }
1187 : :
1188 : : static void
1189 : 0 : rpc_bdev_nvme_stats_per_channel(struct spdk_io_channel_iter *i)
1190 : : {
1191 : : struct rpc_bdev_nvme_transport_stat_ctx *ctx;
1192 : : struct spdk_io_channel *ch;
1193 : : struct nvme_poll_group *group;
1194 : 0 : struct spdk_nvme_poll_group_stat *stat;
1195 : : struct spdk_nvme_transport_poll_group_stat *tr_stat;
1196 : : uint32_t j;
1197 : : int rc;
1198 : :
1199 : 0 : ctx = spdk_io_channel_iter_get_ctx(i);
1200 : 0 : ch = spdk_io_channel_iter_get_channel(i);
1201 : 0 : group = spdk_io_channel_get_ctx(ch);
1202 : :
1203 : 0 : rc = spdk_nvme_poll_group_get_stats(group->group, &stat);
1204 [ # # ]: 0 : if (rc) {
1205 : 0 : spdk_for_each_channel_continue(i, rc);
1206 : 0 : return;
1207 : : }
1208 : :
1209 : 0 : spdk_json_write_object_begin(ctx->w);
1210 : 0 : spdk_json_write_named_string(ctx->w, "thread", spdk_thread_get_name(spdk_get_thread()));
1211 : 0 : spdk_json_write_named_array_begin(ctx->w, "transports");
1212 : :
1213 [ # # ]: 0 : for (j = 0; j < stat->num_transports; j++) {
1214 : 0 : tr_stat = stat->transport_stat[j];
1215 : 0 : spdk_json_write_object_begin(ctx->w);
1216 : 0 : spdk_json_write_named_string(ctx->w, "trname", spdk_nvme_transport_id_trtype_str(tr_stat->trtype));
1217 : :
1218 [ # # # # ]: 0 : switch (stat->transport_stat[j]->trtype) {
1219 : 0 : case SPDK_NVME_TRANSPORT_RDMA:
1220 : 0 : rpc_bdev_nvme_rdma_stats(ctx->w, tr_stat);
1221 : 0 : break;
1222 : 0 : case SPDK_NVME_TRANSPORT_PCIE:
1223 : : case SPDK_NVME_TRANSPORT_VFIOUSER:
1224 : 0 : rpc_bdev_nvme_pcie_stats(ctx->w, tr_stat);
1225 : 0 : break;
1226 : 0 : case SPDK_NVME_TRANSPORT_TCP:
1227 : 0 : rpc_bdev_nvme_tcp_stats(ctx->w, tr_stat);
1228 : 0 : break;
1229 : 0 : default:
1230 : 0 : SPDK_WARNLOG("Can't handle trtype %d %s\n", tr_stat->trtype,
1231 : : spdk_nvme_transport_id_trtype_str(tr_stat->trtype));
1232 : : }
1233 : 0 : spdk_json_write_object_end(ctx->w);
1234 : : }
1235 : : /* transports array */
1236 : 0 : spdk_json_write_array_end(ctx->w);
1237 : 0 : spdk_json_write_object_end(ctx->w);
1238 : :
1239 : 0 : spdk_nvme_poll_group_free_stats(group->group, stat);
1240 : 0 : spdk_for_each_channel_continue(i, 0);
1241 : : }
1242 : :
1243 : : static void
1244 : 0 : rpc_bdev_nvme_stats_done(struct spdk_io_channel_iter *i, int status)
1245 : : {
1246 : 0 : struct rpc_bdev_nvme_transport_stat_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
1247 : :
1248 : 0 : spdk_json_write_array_end(ctx->w);
1249 : 0 : spdk_json_write_object_end(ctx->w);
1250 : 0 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
1251 : 0 : free(ctx);
1252 : 0 : }
1253 : :
1254 : : static void
1255 : 0 : rpc_bdev_nvme_get_transport_statistics(struct spdk_jsonrpc_request *request,
1256 : : const struct spdk_json_val *params)
1257 : : {
1258 : : struct rpc_bdev_nvme_transport_stat_ctx *ctx;
1259 : :
1260 [ # # ]: 0 : if (params) {
1261 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
1262 : : "'bdev_nvme_get_transport_statistics' requires no arguments");
1263 : 0 : return;
1264 : : }
1265 : :
1266 : 0 : ctx = calloc(1, sizeof(*ctx));
1267 [ # # ]: 0 : if (!ctx) {
1268 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1269 : : "Memory allocation error");
1270 : 0 : return;
1271 : : }
1272 : 0 : ctx->request = request;
1273 : 0 : ctx->w = spdk_jsonrpc_begin_result(ctx->request);
1274 : 0 : spdk_json_write_object_begin(ctx->w);
1275 : 0 : spdk_json_write_named_array_begin(ctx->w, "poll_groups");
1276 : :
1277 : 0 : spdk_for_each_channel(&g_nvme_bdev_ctrlrs,
1278 : : rpc_bdev_nvme_stats_per_channel,
1279 : : ctx,
1280 : : rpc_bdev_nvme_stats_done);
1281 : : }
1282 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_transport_statistics", rpc_bdev_nvme_get_transport_statistics,
1283 : : SPDK_RPC_RUNTIME)
1284 : :
1285 : : struct rpc_bdev_nvme_controller_op_req {
1286 : : char *name;
1287 : : uint16_t cntlid;
1288 : : };
1289 : :
1290 : : static void
1291 : 9 : free_rpc_bdev_nvme_controller_op_req(struct rpc_bdev_nvme_controller_op_req *r)
1292 : : {
1293 : 9 : free(r->name);
1294 : 9 : }
1295 : :
1296 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_controller_op_req_decoders[] = {
1297 : : {"name", offsetof(struct rpc_bdev_nvme_controller_op_req, name), spdk_json_decode_string},
1298 : : {"cntlid", offsetof(struct rpc_bdev_nvme_controller_op_req, cntlid), spdk_json_decode_uint16, true},
1299 : : };
1300 : :
1301 : : static void
1302 : 9 : rpc_bdev_nvme_controller_op_cb(void *cb_arg, int rc)
1303 : : {
1304 : 9 : struct spdk_jsonrpc_request *request = cb_arg;
1305 : :
1306 [ + - ]: 9 : if (rc == 0) {
1307 : 9 : spdk_jsonrpc_send_bool_response(request, true);
1308 : : } else {
1309 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1310 : : }
1311 : 9 : }
1312 : :
1313 : : static void
1314 : 9 : rpc_bdev_nvme_controller_op(struct spdk_jsonrpc_request *request,
1315 : : const struct spdk_json_val *params,
1316 : : enum nvme_ctrlr_op op)
1317 : : {
1318 : 9 : struct rpc_bdev_nvme_controller_op_req req = {NULL};
1319 : : struct nvme_bdev_ctrlr *nbdev_ctrlr;
1320 : : struct nvme_ctrlr *nvme_ctrlr;
1321 : :
1322 [ - + ]: 9 : if (spdk_json_decode_object(params, rpc_bdev_nvme_controller_op_req_decoders,
1323 : : SPDK_COUNTOF(rpc_bdev_nvme_controller_op_req_decoders),
1324 : : &req)) {
1325 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1326 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(EINVAL));
1327 : 0 : goto exit;
1328 : : }
1329 : :
1330 : 9 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
1331 [ - + ]: 9 : if (nbdev_ctrlr == NULL) {
1332 : 0 : SPDK_ERRLOG("Failed at NVMe bdev controller lookup\n");
1333 : 0 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
1334 : 0 : goto exit;
1335 : : }
1336 : :
1337 [ + - ]: 9 : if (req.cntlid == 0) {
1338 : 9 : nvme_bdev_ctrlr_op_rpc(nbdev_ctrlr, op, rpc_bdev_nvme_controller_op_cb, request);
1339 : : } else {
1340 : 0 : nvme_ctrlr = nvme_bdev_ctrlr_get_ctrlr_by_id(nbdev_ctrlr, req.cntlid);
1341 [ # # ]: 0 : if (nvme_ctrlr == NULL) {
1342 : 0 : SPDK_ERRLOG("Failed at NVMe controller lookup\n");
1343 : 0 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
1344 : 0 : goto exit;
1345 : : }
1346 : 0 : nvme_ctrlr_op_rpc(nvme_ctrlr, op, rpc_bdev_nvme_controller_op_cb, request);
1347 : : }
1348 : :
1349 : 9 : exit:
1350 : 9 : free_rpc_bdev_nvme_controller_op_req(&req);
1351 : 9 : }
1352 : :
1353 : : static void
1354 : 9 : rpc_bdev_nvme_reset_controller(struct spdk_jsonrpc_request *request,
1355 : : const struct spdk_json_val *params)
1356 : : {
1357 : 9 : rpc_bdev_nvme_controller_op(request, params, NVME_CTRLR_OP_RESET);
1358 : 9 : }
1359 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_reset_controller", rpc_bdev_nvme_reset_controller, SPDK_RPC_RUNTIME)
1360 : :
1361 : : static void
1362 : 0 : rpc_bdev_nvme_enable_controller(struct spdk_jsonrpc_request *request,
1363 : : const struct spdk_json_val *params)
1364 : : {
1365 : 0 : rpc_bdev_nvme_controller_op(request, params, NVME_CTRLR_OP_ENABLE);
1366 : 0 : }
1367 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_enable_controller", rpc_bdev_nvme_enable_controller, SPDK_RPC_RUNTIME)
1368 : :
1369 : : static void
1370 : 0 : rpc_bdev_nvme_disable_controller(struct spdk_jsonrpc_request *request,
1371 : : const struct spdk_json_val *params)
1372 : : {
1373 : 0 : rpc_bdev_nvme_controller_op(request, params, NVME_CTRLR_OP_DISABLE);
1374 : 0 : }
1375 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_disable_controller", rpc_bdev_nvme_disable_controller,
1376 : : SPDK_RPC_RUNTIME)
1377 : :
1378 : : struct rpc_get_controller_health_info {
1379 : : char *name;
1380 : : };
1381 : :
1382 : : struct spdk_nvme_health_info_context {
1383 : : struct spdk_jsonrpc_request *request;
1384 : : struct spdk_nvme_ctrlr *ctrlr;
1385 : : struct spdk_nvme_health_information_page health_page;
1386 : : };
1387 : :
1388 : : static void
1389 : 0 : free_rpc_get_controller_health_info(struct rpc_get_controller_health_info *r)
1390 : : {
1391 : 0 : free(r->name);
1392 : 0 : }
1393 : :
1394 : : static const struct spdk_json_object_decoder rpc_get_controller_health_info_decoders[] = {
1395 : : {"name", offsetof(struct rpc_get_controller_health_info, name), spdk_json_decode_string, true},
1396 : : };
1397 : :
1398 : : static void
1399 : 0 : nvme_health_info_cleanup(struct spdk_nvme_health_info_context *context, bool response)
1400 : : {
1401 [ # # ]: 0 : if (response == true) {
1402 : 0 : spdk_jsonrpc_send_error_response(context->request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1403 : : "Internal error.");
1404 : : }
1405 : :
1406 : 0 : free(context);
1407 : 0 : }
1408 : :
1409 : : static void
1410 : 0 : get_health_log_page_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
1411 : : {
1412 : : int i;
1413 : 0 : char buf[128];
1414 : 0 : struct spdk_nvme_health_info_context *context = cb_arg;
1415 : 0 : struct spdk_jsonrpc_request *request = context->request;
1416 : : struct spdk_json_write_ctx *w;
1417 : 0 : struct spdk_nvme_ctrlr *ctrlr = context->ctrlr;
1418 : 0 : const struct spdk_nvme_transport_id *trid = NULL;
1419 : 0 : const struct spdk_nvme_ctrlr_data *cdata = NULL;
1420 : 0 : struct spdk_nvme_health_information_page *health_page = NULL;
1421 : :
1422 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
1423 : 0 : nvme_health_info_cleanup(context, true);
1424 : 0 : SPDK_ERRLOG("get log page failed\n");
1425 : 0 : return;
1426 : : }
1427 : :
1428 [ # # ]: 0 : if (ctrlr == NULL) {
1429 : 0 : nvme_health_info_cleanup(context, true);
1430 : 0 : SPDK_ERRLOG("ctrlr is NULL\n");
1431 : 0 : return;
1432 : : } else {
1433 : 0 : trid = spdk_nvme_ctrlr_get_transport_id(ctrlr);
1434 : 0 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
1435 : 0 : health_page = &(context->health_page);
1436 : : }
1437 : :
1438 : 0 : w = spdk_jsonrpc_begin_result(request);
1439 : :
1440 : 0 : spdk_json_write_object_begin(w);
1441 [ # # ]: 0 : snprintf(buf, sizeof(cdata->mn) + 1, "%s", cdata->mn);
1442 : 0 : spdk_str_trim(buf);
1443 : 0 : spdk_json_write_named_string(w, "model_number", buf);
1444 [ # # ]: 0 : snprintf(buf, sizeof(cdata->sn) + 1, "%s", cdata->sn);
1445 : 0 : spdk_str_trim(buf);
1446 : 0 : spdk_json_write_named_string(w, "serial_number", buf);
1447 [ # # ]: 0 : snprintf(buf, sizeof(cdata->fr) + 1, "%s", cdata->fr);
1448 : 0 : spdk_str_trim(buf);
1449 : 0 : spdk_json_write_named_string(w, "firmware_revision", buf);
1450 : 0 : spdk_json_write_named_string(w, "traddr", trid->traddr);
1451 : 0 : spdk_json_write_named_uint64(w, "critical_warning", health_page->critical_warning.raw);
1452 : 0 : spdk_json_write_named_uint64(w, "temperature_celsius", health_page->temperature - 273);
1453 : 0 : spdk_json_write_named_uint64(w, "available_spare_percentage", health_page->available_spare);
1454 : 0 : spdk_json_write_named_uint64(w, "available_spare_threshold_percentage",
1455 : 0 : health_page->available_spare_threshold);
1456 : 0 : spdk_json_write_named_uint64(w, "percentage_used", health_page->percentage_used);
1457 : 0 : spdk_json_write_named_uint128(w, "data_units_read",
1458 : : health_page->data_units_read[0], health_page->data_units_read[1]);
1459 : 0 : spdk_json_write_named_uint128(w, "data_units_written",
1460 : : health_page->data_units_written[0], health_page->data_units_written[1]);
1461 : 0 : spdk_json_write_named_uint128(w, "host_read_commands",
1462 : : health_page->host_read_commands[0], health_page->host_read_commands[1]);
1463 : 0 : spdk_json_write_named_uint128(w, "host_write_commands",
1464 : : health_page->host_write_commands[0], health_page->host_write_commands[1]);
1465 : 0 : spdk_json_write_named_uint128(w, "controller_busy_time",
1466 : : health_page->controller_busy_time[0], health_page->controller_busy_time[1]);
1467 : 0 : spdk_json_write_named_uint128(w, "power_cycles",
1468 : : health_page->power_cycles[0], health_page->power_cycles[1]);
1469 : 0 : spdk_json_write_named_uint128(w, "power_on_hours",
1470 : : health_page->power_on_hours[0], health_page->power_on_hours[1]);
1471 : 0 : spdk_json_write_named_uint128(w, "unsafe_shutdowns",
1472 : : health_page->unsafe_shutdowns[0], health_page->unsafe_shutdowns[1]);
1473 : 0 : spdk_json_write_named_uint128(w, "media_errors",
1474 : : health_page->media_errors[0], health_page->media_errors[1]);
1475 : 0 : spdk_json_write_named_uint128(w, "num_err_log_entries",
1476 : : health_page->num_error_info_log_entries[0], health_page->num_error_info_log_entries[1]);
1477 : 0 : spdk_json_write_named_uint64(w, "warning_temperature_time_minutes", health_page->warning_temp_time);
1478 : 0 : spdk_json_write_named_uint64(w, "critical_composite_temperature_time_minutes",
1479 : 0 : health_page->critical_temp_time);
1480 [ # # ]: 0 : for (i = 0; i < 8; i++) {
1481 [ # # ]: 0 : if (health_page->temp_sensor[i] != 0) {
1482 : 0 : spdk_json_write_named_uint64(w, "temperature_sensor_celsius", health_page->temp_sensor[i] - 273);
1483 : : }
1484 : : }
1485 : 0 : spdk_json_write_object_end(w);
1486 : :
1487 : 0 : spdk_jsonrpc_end_result(request, w);
1488 : 0 : nvme_health_info_cleanup(context, false);
1489 : : }
1490 : :
1491 : : static void
1492 : 0 : get_health_log_page(struct spdk_nvme_health_info_context *context)
1493 : : {
1494 : 0 : struct spdk_nvme_ctrlr *ctrlr = context->ctrlr;
1495 : :
1496 [ # # ]: 0 : if (spdk_nvme_ctrlr_cmd_get_log_page(ctrlr, SPDK_NVME_LOG_HEALTH_INFORMATION,
1497 : : SPDK_NVME_GLOBAL_NS_TAG,
1498 : 0 : &(context->health_page), sizeof(context->health_page), 0,
1499 : : get_health_log_page_completion, context)) {
1500 : 0 : nvme_health_info_cleanup(context, true);
1501 : 0 : SPDK_ERRLOG("spdk_nvme_ctrlr_cmd_get_log_page() failed\n");
1502 : : }
1503 : 0 : }
1504 : :
1505 : : static void
1506 : 0 : get_temperature_threshold_feature_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
1507 : : {
1508 : 0 : struct spdk_nvme_health_info_context *context = cb_arg;
1509 : :
1510 [ # # # # ]: 0 : if (spdk_nvme_cpl_is_error(cpl)) {
1511 : 0 : nvme_health_info_cleanup(context, true);
1512 : 0 : SPDK_ERRLOG("feature SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD failed in completion\n");
1513 : : } else {
1514 : 0 : get_health_log_page(context);
1515 : : }
1516 : 0 : }
1517 : :
1518 : : static int
1519 : 0 : get_temperature_threshold_feature(struct spdk_nvme_health_info_context *context)
1520 : : {
1521 : 0 : struct spdk_nvme_cmd cmd = {};
1522 : :
1523 : 0 : cmd.opc = SPDK_NVME_OPC_GET_FEATURES;
1524 : 0 : cmd.cdw10 = SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD;
1525 : :
1526 : 0 : return spdk_nvme_ctrlr_cmd_admin_raw(context->ctrlr, &cmd, NULL, 0,
1527 : : get_temperature_threshold_feature_completion, context);
1528 : : }
1529 : :
1530 : : static void
1531 : 0 : get_controller_health_info(struct spdk_jsonrpc_request *request, struct spdk_nvme_ctrlr *ctrlr)
1532 : : {
1533 : : struct spdk_nvme_health_info_context *context;
1534 : :
1535 : 0 : context = calloc(1, sizeof(struct spdk_nvme_health_info_context));
1536 [ # # ]: 0 : if (!context) {
1537 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1538 : : "Memory allocation error.");
1539 : 0 : return;
1540 : : }
1541 : :
1542 : 0 : context->request = request;
1543 : 0 : context->ctrlr = ctrlr;
1544 : :
1545 [ # # ]: 0 : if (get_temperature_threshold_feature(context)) {
1546 : 0 : nvme_health_info_cleanup(context, true);
1547 : 0 : SPDK_ERRLOG("feature SPDK_NVME_FEAT_TEMPERATURE_THRESHOLD failed to submit\n");
1548 : : }
1549 : :
1550 : 0 : return;
1551 : : }
1552 : :
1553 : : static void
1554 : 0 : rpc_bdev_nvme_get_controller_health_info(struct spdk_jsonrpc_request *request,
1555 : : const struct spdk_json_val *params)
1556 : : {
1557 : 0 : struct rpc_get_controller_health_info req = {};
1558 : 0 : struct nvme_ctrlr *nvme_ctrlr = NULL;
1559 : :
1560 [ # # ]: 0 : if (!params) {
1561 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1562 : : "Missing device name");
1563 : :
1564 : 0 : return;
1565 : : }
1566 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_get_controller_health_info_decoders,
1567 : : SPDK_COUNTOF(rpc_get_controller_health_info_decoders), &req)) {
1568 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1569 : 0 : free_rpc_get_controller_health_info(&req);
1570 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1571 : : "Invalid parameters");
1572 : :
1573 : 0 : return;
1574 : : }
1575 : :
1576 : 0 : nvme_ctrlr = nvme_ctrlr_get_by_name(req.name);
1577 : :
1578 [ # # ]: 0 : if (!nvme_ctrlr) {
1579 : 0 : SPDK_ERRLOG("nvme ctrlr name '%s' does not exist\n", req.name);
1580 : 0 : free_rpc_get_controller_health_info(&req);
1581 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1582 : : "Device not found");
1583 : 0 : return;
1584 : : }
1585 : :
1586 : 0 : get_controller_health_info(request, nvme_ctrlr->ctrlr);
1587 : 0 : free_rpc_get_controller_health_info(&req);
1588 : :
1589 : 0 : return;
1590 : : }
1591 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_controller_health_info",
1592 : : rpc_bdev_nvme_get_controller_health_info, SPDK_RPC_RUNTIME)
1593 : :
1594 : : struct rpc_bdev_nvme_start_discovery {
1595 : : char *name;
1596 : : char *trtype;
1597 : : char *adrfam;
1598 : : char *traddr;
1599 : : char *trsvcid;
1600 : : char *hostnqn;
1601 : : bool wait_for_attach;
1602 : : uint64_t attach_timeout_ms;
1603 : : struct spdk_nvme_ctrlr_opts opts;
1604 : : struct nvme_ctrlr_opts bdev_opts;
1605 : : };
1606 : :
1607 : : static void
1608 : 36 : free_rpc_bdev_nvme_start_discovery(struct rpc_bdev_nvme_start_discovery *req)
1609 : : {
1610 : 36 : free(req->name);
1611 : 36 : free(req->trtype);
1612 : 36 : free(req->adrfam);
1613 : 36 : free(req->traddr);
1614 : 36 : free(req->trsvcid);
1615 : 36 : free(req->hostnqn);
1616 : 36 : }
1617 : :
1618 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_start_discovery_decoders[] = {
1619 : : {"name", offsetof(struct rpc_bdev_nvme_start_discovery, name), spdk_json_decode_string},
1620 : : {"trtype", offsetof(struct rpc_bdev_nvme_start_discovery, trtype), spdk_json_decode_string},
1621 : : {"traddr", offsetof(struct rpc_bdev_nvme_start_discovery, traddr), spdk_json_decode_string},
1622 : : {"adrfam", offsetof(struct rpc_bdev_nvme_start_discovery, adrfam), spdk_json_decode_string, true},
1623 : : {"trsvcid", offsetof(struct rpc_bdev_nvme_start_discovery, trsvcid), spdk_json_decode_string, true},
1624 : : {"hostnqn", offsetof(struct rpc_bdev_nvme_start_discovery, hostnqn), spdk_json_decode_string, true},
1625 : : {"wait_for_attach", offsetof(struct rpc_bdev_nvme_start_discovery, wait_for_attach), spdk_json_decode_bool, true},
1626 : : {"attach_timeout_ms", offsetof(struct rpc_bdev_nvme_start_discovery, attach_timeout_ms), spdk_json_decode_uint64, true},
1627 : : {"ctrlr_loss_timeout_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.ctrlr_loss_timeout_sec), spdk_json_decode_int32, true},
1628 : : {"reconnect_delay_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.reconnect_delay_sec), spdk_json_decode_uint32, true},
1629 : : {"fast_io_fail_timeout_sec", offsetof(struct rpc_bdev_nvme_start_discovery, bdev_opts.fast_io_fail_timeout_sec), spdk_json_decode_uint32, true},
1630 : : };
1631 : :
1632 : : struct rpc_bdev_nvme_start_discovery_ctx {
1633 : : struct rpc_bdev_nvme_start_discovery req;
1634 : : struct spdk_jsonrpc_request *request;
1635 : : };
1636 : :
1637 : : static void
1638 : 30 : rpc_bdev_nvme_start_discovery_done(void *ctx, int status)
1639 : : {
1640 : 30 : struct spdk_jsonrpc_request *request = ctx;
1641 : :
1642 [ + + ]: 30 : if (status != 0) {
1643 : 5 : spdk_jsonrpc_send_error_response(request, status, spdk_strerror(-status));
1644 : : } else {
1645 : 25 : spdk_jsonrpc_send_bool_response(request, true);
1646 : : }
1647 : 30 : }
1648 : :
1649 : : static void
1650 : 36 : rpc_bdev_nvme_start_discovery(struct spdk_jsonrpc_request *request,
1651 : : const struct spdk_json_val *params)
1652 : : {
1653 : : struct rpc_bdev_nvme_start_discovery_ctx *ctx;
1654 : 36 : struct spdk_nvme_transport_id trid = {};
1655 : : size_t len, maxlen;
1656 : : int rc;
1657 : : spdk_bdev_nvme_start_discovery_fn cb_fn;
1658 : : void *cb_ctx;
1659 : :
1660 : 36 : ctx = calloc(1, sizeof(*ctx));
1661 [ - + ]: 36 : if (!ctx) {
1662 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1663 : 0 : return;
1664 : : }
1665 : :
1666 : 36 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.opts, sizeof(ctx->req.opts));
1667 : :
1668 [ - + ]: 36 : if (spdk_json_decode_object(params, rpc_bdev_nvme_start_discovery_decoders,
1669 : : SPDK_COUNTOF(rpc_bdev_nvme_start_discovery_decoders),
1670 : 36 : &ctx->req)) {
1671 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1672 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1673 : : "spdk_json_decode_object failed");
1674 : 0 : goto cleanup;
1675 : : }
1676 : :
1677 : : /* Parse trstring */
1678 : 36 : rc = spdk_nvme_transport_id_populate_trstring(&trid, ctx->req.trtype);
1679 [ - + ]: 36 : if (rc < 0) {
1680 : 0 : SPDK_ERRLOG("Failed to parse trtype: %s\n", ctx->req.trtype);
1681 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse trtype: %s",
1682 : : ctx->req.trtype);
1683 : 0 : goto cleanup;
1684 : : }
1685 : :
1686 : : /* Parse trtype */
1687 : 36 : rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype);
1688 [ - + ]: 36 : assert(rc == 0);
1689 : :
1690 : : /* Parse traddr */
1691 : 36 : maxlen = sizeof(trid.traddr);
1692 [ - + ]: 36 : len = strnlen(ctx->req.traddr, maxlen);
1693 [ - + ]: 36 : if (len == maxlen) {
1694 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "traddr too long: %s",
1695 : : ctx->req.traddr);
1696 : 0 : goto cleanup;
1697 : : }
1698 [ - + ]: 36 : memcpy(trid.traddr, ctx->req.traddr, len + 1);
1699 : :
1700 : : /* Parse adrfam */
1701 [ + - ]: 36 : if (ctx->req.adrfam) {
1702 : 36 : rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam);
1703 [ - + ]: 36 : if (rc < 0) {
1704 : 0 : SPDK_ERRLOG("Failed to parse adrfam: %s\n", ctx->req.adrfam);
1705 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Failed to parse adrfam: %s",
1706 : : ctx->req.adrfam);
1707 : 0 : goto cleanup;
1708 : : }
1709 : : }
1710 : :
1711 : : /* Parse trsvcid */
1712 [ + - ]: 36 : if (ctx->req.trsvcid) {
1713 : 36 : maxlen = sizeof(trid.trsvcid);
1714 [ - + ]: 36 : len = strnlen(ctx->req.trsvcid, maxlen);
1715 [ - + ]: 36 : if (len == maxlen) {
1716 : 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "trsvcid too long: %s",
1717 : : ctx->req.trsvcid);
1718 : 0 : goto cleanup;
1719 : : }
1720 [ - + ]: 36 : memcpy(trid.trsvcid, ctx->req.trsvcid, len + 1);
1721 : : }
1722 : :
1723 [ + - ]: 36 : if (ctx->req.hostnqn) {
1724 : 36 : snprintf(ctx->req.opts.hostnqn, sizeof(ctx->req.opts.hostnqn), "%s",
1725 : : ctx->req.hostnqn);
1726 : : }
1727 : :
1728 [ + + ]: 36 : if (ctx->req.attach_timeout_ms != 0) {
1729 : 21 : ctx->req.wait_for_attach = true;
1730 : : }
1731 : :
1732 : 36 : ctx->request = request;
1733 [ - + + + ]: 36 : cb_fn = ctx->req.wait_for_attach ? rpc_bdev_nvme_start_discovery_done : NULL;
1734 [ - + + + ]: 36 : cb_ctx = ctx->req.wait_for_attach ? request : NULL;
1735 : 36 : rc = bdev_nvme_start_discovery(&trid, ctx->req.name, &ctx->req.opts, &ctx->req.bdev_opts,
1736 : : ctx->req.attach_timeout_ms, false, cb_fn, cb_ctx);
1737 [ + + ]: 36 : if (rc) {
1738 : 6 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1739 [ - + + + ]: 30 : } else if (!ctx->req.wait_for_attach) {
1740 : 3 : rpc_bdev_nvme_start_discovery_done(request, 0);
1741 : : }
1742 : :
1743 : 27 : cleanup:
1744 : 36 : free_rpc_bdev_nvme_start_discovery(&ctx->req);
1745 : 36 : free(ctx);
1746 : : }
1747 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_start_discovery", rpc_bdev_nvme_start_discovery,
1748 : : SPDK_RPC_RUNTIME)
1749 : :
1750 : : struct rpc_bdev_nvme_stop_discovery {
1751 : : char *name;
1752 : : };
1753 : :
1754 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_stop_discovery_decoders[] = {
1755 : : {"name", offsetof(struct rpc_bdev_nvme_stop_discovery, name), spdk_json_decode_string},
1756 : : };
1757 : :
1758 : : struct rpc_bdev_nvme_stop_discovery_ctx {
1759 : : struct rpc_bdev_nvme_stop_discovery req;
1760 : : struct spdk_jsonrpc_request *request;
1761 : : };
1762 : :
1763 : : static void
1764 : 19 : rpc_bdev_nvme_stop_discovery_done(void *cb_ctx)
1765 : : {
1766 : 19 : struct rpc_bdev_nvme_stop_discovery_ctx *ctx = cb_ctx;
1767 : :
1768 : 19 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1769 : 19 : free(ctx->req.name);
1770 : 19 : free(ctx);
1771 : 19 : }
1772 : :
1773 : : static void
1774 : 19 : rpc_bdev_nvme_stop_discovery(struct spdk_jsonrpc_request *request,
1775 : : const struct spdk_json_val *params)
1776 : : {
1777 : : struct rpc_bdev_nvme_stop_discovery_ctx *ctx;
1778 : : int rc;
1779 : :
1780 : 19 : ctx = calloc(1, sizeof(*ctx));
1781 [ - + ]: 19 : if (!ctx) {
1782 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1783 : 0 : return;
1784 : : }
1785 : :
1786 [ - + ]: 19 : if (spdk_json_decode_object(params, rpc_bdev_nvme_stop_discovery_decoders,
1787 : : SPDK_COUNTOF(rpc_bdev_nvme_stop_discovery_decoders),
1788 : 19 : &ctx->req)) {
1789 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
1790 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1791 : : "spdk_json_decode_object failed");
1792 : 0 : goto cleanup;
1793 : : }
1794 : :
1795 : 19 : ctx->request = request;
1796 : 19 : rc = bdev_nvme_stop_discovery(ctx->req.name, rpc_bdev_nvme_stop_discovery_done, ctx);
1797 [ - + ]: 19 : if (rc) {
1798 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1799 : 0 : goto cleanup;
1800 : : }
1801 : :
1802 : 19 : return;
1803 : :
1804 : 0 : cleanup:
1805 : 0 : free(ctx->req.name);
1806 : 0 : free(ctx);
1807 : : }
1808 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_stop_discovery", rpc_bdev_nvme_stop_discovery,
1809 : : SPDK_RPC_RUNTIME)
1810 : :
1811 : : static void
1812 : 77 : rpc_bdev_nvme_get_discovery_info(struct spdk_jsonrpc_request *request,
1813 : : const struct spdk_json_val *params)
1814 : : {
1815 : : struct spdk_json_write_ctx *w;
1816 : :
1817 : 77 : w = spdk_jsonrpc_begin_result(request);
1818 : 77 : bdev_nvme_get_discovery_info(w);
1819 : 77 : spdk_jsonrpc_end_result(request, w);
1820 : 77 : }
1821 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_discovery_info", rpc_bdev_nvme_get_discovery_info,
1822 : : SPDK_RPC_RUNTIME)
1823 : :
1824 : : enum error_injection_cmd_type {
1825 : : NVME_ADMIN_CMD = 1,
1826 : : NVME_IO_CMD,
1827 : : };
1828 : :
1829 : : struct rpc_add_error_injection {
1830 : : char *name;
1831 : : enum error_injection_cmd_type cmd_type;
1832 : : uint8_t opc;
1833 : : bool do_not_submit;
1834 : : uint64_t timeout_in_us;
1835 : : uint32_t err_count;
1836 : : uint8_t sct;
1837 : : uint8_t sc;
1838 : : };
1839 : :
1840 : : static void
1841 : 6 : free_rpc_add_error_injection(struct rpc_add_error_injection *req)
1842 : : {
1843 : 6 : free(req->name);
1844 : 6 : }
1845 : :
1846 : : static int
1847 : 6 : rpc_error_injection_decode_cmd_type(const struct spdk_json_val *val, void *out)
1848 : : {
1849 : 6 : int *cmd_type = out;
1850 : :
1851 [ + - ]: 6 : if (spdk_json_strequal(val, "admin")) {
1852 : 6 : *cmd_type = NVME_ADMIN_CMD;
1853 [ # # ]: 0 : } else if (spdk_json_strequal(val, "io")) {
1854 : 0 : *cmd_type = NVME_IO_CMD;
1855 : : } else {
1856 : 0 : SPDK_ERRLOG("Invalid parameter value: cmd_type\n");
1857 : 0 : return -EINVAL;
1858 : : }
1859 : :
1860 : 6 : return 0;
1861 : : }
1862 : :
1863 : : static const struct spdk_json_object_decoder rpc_add_error_injection_decoders[] = {
1864 : : { "name", offsetof(struct rpc_add_error_injection, name), spdk_json_decode_string },
1865 : : { "cmd_type", offsetof(struct rpc_add_error_injection, cmd_type), rpc_error_injection_decode_cmd_type },
1866 : : { "opc", offsetof(struct rpc_add_error_injection, opc), spdk_json_decode_uint8 },
1867 : : { "do_not_submit", offsetof(struct rpc_add_error_injection, do_not_submit), spdk_json_decode_bool, true },
1868 : : { "timeout_in_us", offsetof(struct rpc_add_error_injection, timeout_in_us), spdk_json_decode_uint64, true },
1869 : : { "err_count", offsetof(struct rpc_add_error_injection, err_count), spdk_json_decode_uint32, true },
1870 : : { "sct", offsetof(struct rpc_add_error_injection, sct), spdk_json_decode_uint8, true},
1871 : : { "sc", offsetof(struct rpc_add_error_injection, sc), spdk_json_decode_uint8, true},
1872 : : };
1873 : :
1874 : : struct rpc_add_error_injection_ctx {
1875 : : struct spdk_jsonrpc_request *request;
1876 : : struct rpc_add_error_injection rpc;
1877 : : };
1878 : :
1879 : : static void
1880 : 0 : rpc_add_error_injection_done(struct spdk_io_channel_iter *i, int status)
1881 : : {
1882 : 0 : struct rpc_add_error_injection_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
1883 : :
1884 [ # # ]: 0 : if (status) {
1885 : 0 : spdk_jsonrpc_send_error_response(ctx->request, status,
1886 : : "Failed to add the error injection.");
1887 : : } else {
1888 : 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1889 : : }
1890 : :
1891 : 0 : free_rpc_add_error_injection(&ctx->rpc);
1892 : 0 : free(ctx);
1893 : 0 : }
1894 : :
1895 : : static void
1896 : 0 : rpc_add_error_injection_per_channel(struct spdk_io_channel_iter *i)
1897 : : {
1898 : 0 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
1899 : 0 : struct rpc_add_error_injection_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
1900 : 0 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(ch);
1901 : 0 : struct spdk_nvme_qpair *qpair = ctrlr_ch->qpair->qpair;
1902 : 0 : struct spdk_nvme_ctrlr *ctrlr = ctrlr_ch->qpair->ctrlr->ctrlr;
1903 : 0 : int rc = 0;
1904 : :
1905 [ # # ]: 0 : if (qpair != NULL) {
1906 : 0 : rc = spdk_nvme_qpair_add_cmd_error_injection(ctrlr, qpair, ctx->rpc.opc,
1907 [ # # ]: 0 : ctx->rpc.do_not_submit, ctx->rpc.timeout_in_us, ctx->rpc.err_count,
1908 : 0 : ctx->rpc.sct, ctx->rpc.sc);
1909 : : }
1910 : :
1911 : 0 : spdk_for_each_channel_continue(i, rc);
1912 : 0 : }
1913 : :
1914 : : static void
1915 : 6 : rpc_bdev_nvme_add_error_injection(
1916 : : struct spdk_jsonrpc_request *request,
1917 : : const struct spdk_json_val *params)
1918 : : {
1919 : : struct rpc_add_error_injection_ctx *ctx;
1920 : : struct nvme_ctrlr *nvme_ctrlr;
1921 : : int rc;
1922 : :
1923 : 6 : ctx = calloc(1, sizeof(*ctx));
1924 [ - + ]: 6 : if (!ctx) {
1925 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1926 : 0 : return;
1927 : : }
1928 : 6 : ctx->rpc.err_count = 1;
1929 : 6 : ctx->request = request;
1930 : :
1931 [ - + ]: 6 : if (spdk_json_decode_object(params,
1932 : : rpc_add_error_injection_decoders,
1933 : : SPDK_COUNTOF(rpc_add_error_injection_decoders),
1934 : 6 : &ctx->rpc)) {
1935 : 0 : spdk_jsonrpc_send_error_response(request, -EINVAL,
1936 : : "Failed to parse the request");
1937 : 0 : goto cleanup;
1938 : : }
1939 : :
1940 : 6 : nvme_ctrlr = nvme_ctrlr_get_by_name(ctx->rpc.name);
1941 [ - + ]: 6 : if (nvme_ctrlr == NULL) {
1942 : 0 : SPDK_ERRLOG("No controller with specified name was found.\n");
1943 : 0 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
1944 : 0 : goto cleanup;
1945 : : }
1946 : :
1947 [ - + ]: 6 : if (ctx->rpc.cmd_type == NVME_IO_CMD) {
1948 : 0 : spdk_for_each_channel(nvme_ctrlr,
1949 : : rpc_add_error_injection_per_channel,
1950 : : ctx,
1951 : : rpc_add_error_injection_done);
1952 : :
1953 : 0 : return;
1954 : : } else {
1955 : 10 : rc = spdk_nvme_qpair_add_cmd_error_injection(nvme_ctrlr->ctrlr, NULL, ctx->rpc.opc,
1956 [ - + ]: 6 : ctx->rpc.do_not_submit, ctx->rpc.timeout_in_us, ctx->rpc.err_count,
1957 : 6 : ctx->rpc.sct, ctx->rpc.sc);
1958 [ - + ]: 6 : if (rc) {
1959 : 0 : spdk_jsonrpc_send_error_response(request, -rc,
1960 : : "Failed to add the error injection");
1961 : : } else {
1962 : 6 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1963 : : }
1964 : : }
1965 : :
1966 : 6 : cleanup:
1967 : 6 : free_rpc_add_error_injection(&ctx->rpc);
1968 : 6 : free(ctx);
1969 : : }
1970 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_add_error_injection", rpc_bdev_nvme_add_error_injection,
1971 : : SPDK_RPC_RUNTIME)
1972 : :
1973 : : struct rpc_remove_error_injection {
1974 : : char *name;
1975 : : enum error_injection_cmd_type cmd_type;
1976 : : uint8_t opc;
1977 : : };
1978 : :
1979 : : static void
1980 : 0 : free_rpc_remove_error_injection(struct rpc_remove_error_injection *req)
1981 : : {
1982 : 0 : free(req->name);
1983 : 0 : }
1984 : :
1985 : : static const struct spdk_json_object_decoder rpc_remove_error_injection_decoders[] = {
1986 : : { "name", offsetof(struct rpc_remove_error_injection, name), spdk_json_decode_string },
1987 : : { "cmd_type", offsetof(struct rpc_remove_error_injection, cmd_type), rpc_error_injection_decode_cmd_type },
1988 : : { "opc", offsetof(struct rpc_remove_error_injection, opc), spdk_json_decode_uint8 },
1989 : : };
1990 : :
1991 : : struct rpc_remove_error_injection_ctx {
1992 : : struct spdk_jsonrpc_request *request;
1993 : : struct rpc_remove_error_injection rpc;
1994 : : };
1995 : :
1996 : : static void
1997 : 0 : rpc_remove_error_injection_done(struct spdk_io_channel_iter *i, int status)
1998 : : {
1999 : 0 : struct rpc_remove_error_injection_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2000 : :
2001 [ # # ]: 0 : if (status) {
2002 : 0 : spdk_jsonrpc_send_error_response(ctx->request, status,
2003 : : "Failed to remove the error injection.");
2004 : : } else {
2005 : 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2006 : : }
2007 : :
2008 : 0 : free_rpc_remove_error_injection(&ctx->rpc);
2009 : 0 : free(ctx);
2010 : 0 : }
2011 : :
2012 : : static void
2013 : 0 : rpc_remove_error_injection_per_channel(struct spdk_io_channel_iter *i)
2014 : : {
2015 : 0 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
2016 : 0 : struct rpc_remove_error_injection_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2017 : 0 : struct nvme_ctrlr_channel *ctrlr_ch = spdk_io_channel_get_ctx(ch);
2018 : 0 : struct spdk_nvme_qpair *qpair = ctrlr_ch->qpair->qpair;
2019 : 0 : struct spdk_nvme_ctrlr *ctrlr = ctrlr_ch->qpair->ctrlr->ctrlr;
2020 : :
2021 [ # # ]: 0 : if (qpair != NULL) {
2022 : 0 : spdk_nvme_qpair_remove_cmd_error_injection(ctrlr, qpair, ctx->rpc.opc);
2023 : : }
2024 : :
2025 : 0 : spdk_for_each_channel_continue(i, 0);
2026 : 0 : }
2027 : :
2028 : : static void
2029 : 0 : rpc_bdev_nvme_remove_error_injection(struct spdk_jsonrpc_request *request,
2030 : : const struct spdk_json_val *params)
2031 : : {
2032 : : struct rpc_remove_error_injection_ctx *ctx;
2033 : : struct nvme_ctrlr *nvme_ctrlr;
2034 : :
2035 : 0 : ctx = calloc(1, sizeof(*ctx));
2036 [ # # ]: 0 : if (!ctx) {
2037 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2038 : 0 : return;
2039 : : }
2040 : 0 : ctx->request = request;
2041 : :
2042 [ # # ]: 0 : if (spdk_json_decode_object(params,
2043 : : rpc_remove_error_injection_decoders,
2044 : : SPDK_COUNTOF(rpc_remove_error_injection_decoders),
2045 : 0 : &ctx->rpc)) {
2046 : 0 : spdk_jsonrpc_send_error_response(request, -EINVAL,
2047 : : "Failed to parse the request");
2048 : 0 : goto cleanup;
2049 : : }
2050 : :
2051 : 0 : nvme_ctrlr = nvme_ctrlr_get_by_name(ctx->rpc.name);
2052 [ # # ]: 0 : if (nvme_ctrlr == NULL) {
2053 : 0 : SPDK_ERRLOG("No controller with specified name was found.\n");
2054 : 0 : spdk_jsonrpc_send_error_response(request, -ENODEV, spdk_strerror(ENODEV));
2055 : 0 : goto cleanup;
2056 : : }
2057 : :
2058 [ # # ]: 0 : if (ctx->rpc.cmd_type == NVME_IO_CMD) {
2059 : 0 : spdk_for_each_channel(nvme_ctrlr,
2060 : : rpc_remove_error_injection_per_channel,
2061 : : ctx,
2062 : : rpc_remove_error_injection_done);
2063 : 0 : return;
2064 : : } else {
2065 : 0 : spdk_nvme_qpair_remove_cmd_error_injection(nvme_ctrlr->ctrlr, NULL, ctx->rpc.opc);
2066 : 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2067 : : }
2068 : :
2069 : 0 : cleanup:
2070 : 0 : free_rpc_remove_error_injection(&ctx->rpc);
2071 : 0 : free(ctx);
2072 : : }
2073 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_remove_error_injection", rpc_bdev_nvme_remove_error_injection,
2074 : : SPDK_RPC_RUNTIME)
2075 : :
2076 : : struct rpc_get_io_paths {
2077 : : char *name;
2078 : : };
2079 : :
2080 : : static void
2081 : 0 : free_rpc_get_io_paths(struct rpc_get_io_paths *r)
2082 : : {
2083 : 0 : free(r->name);
2084 : 0 : }
2085 : :
2086 : : static const struct spdk_json_object_decoder rpc_get_io_paths_decoders[] = {
2087 : : {"name", offsetof(struct rpc_get_io_paths, name), spdk_json_decode_string, true},
2088 : : };
2089 : :
2090 : : struct rpc_get_io_paths_ctx {
2091 : : struct rpc_get_io_paths req;
2092 : : struct spdk_jsonrpc_request *request;
2093 : : struct spdk_json_write_ctx *w;
2094 : : };
2095 : :
2096 : : static void
2097 : 0 : rpc_bdev_nvme_get_io_paths_done(struct spdk_io_channel_iter *i, int status)
2098 : : {
2099 : 0 : struct rpc_get_io_paths_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2100 : :
2101 : 0 : spdk_json_write_array_end(ctx->w);
2102 : :
2103 : 0 : spdk_json_write_object_end(ctx->w);
2104 : :
2105 : 0 : spdk_jsonrpc_end_result(ctx->request, ctx->w);
2106 : :
2107 : 0 : free_rpc_get_io_paths(&ctx->req);
2108 : 0 : free(ctx);
2109 : 0 : }
2110 : :
2111 : : static void
2112 : 0 : _rpc_bdev_nvme_get_io_paths(struct spdk_io_channel_iter *i)
2113 : : {
2114 : 0 : struct spdk_io_channel *_ch = spdk_io_channel_iter_get_channel(i);
2115 : 0 : struct nvme_poll_group *group = spdk_io_channel_get_ctx(_ch);
2116 : 0 : struct rpc_get_io_paths_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2117 : : struct nvme_qpair *qpair;
2118 : : struct nvme_io_path *io_path;
2119 : : struct nvme_bdev *nbdev;
2120 : :
2121 : 0 : spdk_json_write_object_begin(ctx->w);
2122 : :
2123 : 0 : spdk_json_write_named_string(ctx->w, "thread", spdk_thread_get_name(spdk_get_thread()));
2124 : :
2125 : 0 : spdk_json_write_named_array_begin(ctx->w, "io_paths");
2126 : :
2127 [ # # ]: 0 : TAILQ_FOREACH(qpair, &group->qpair_list, tailq) {
2128 [ # # ]: 0 : TAILQ_FOREACH(io_path, &qpair->io_path_list, tailq) {
2129 : 0 : nbdev = io_path->nvme_ns->bdev;
2130 : :
2131 [ # # ]: 0 : if (ctx->req.name != NULL &&
2132 [ # # # # : 0 : strcmp(ctx->req.name, nbdev->disk.name) != 0) {
# # ]
2133 : 0 : continue;
2134 : : }
2135 : :
2136 : 0 : nvme_io_path_info_json(ctx->w, io_path);
2137 : : }
2138 : : }
2139 : :
2140 : 0 : spdk_json_write_array_end(ctx->w);
2141 : :
2142 : 0 : spdk_json_write_object_end(ctx->w);
2143 : :
2144 : 0 : spdk_for_each_channel_continue(i, 0);
2145 : 0 : }
2146 : :
2147 : : static void
2148 : 0 : rpc_bdev_nvme_get_io_paths(struct spdk_jsonrpc_request *request,
2149 : : const struct spdk_json_val *params)
2150 : : {
2151 : : struct rpc_get_io_paths_ctx *ctx;
2152 : :
2153 : 0 : ctx = calloc(1, sizeof(*ctx));
2154 [ # # ]: 0 : if (ctx == NULL) {
2155 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2156 : 0 : return;
2157 : : }
2158 : :
2159 [ # # # # ]: 0 : if (params != NULL &&
2160 : 0 : spdk_json_decode_object(params, rpc_get_io_paths_decoders,
2161 : : SPDK_COUNTOF(rpc_get_io_paths_decoders),
2162 : 0 : &ctx->req)) {
2163 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS,
2164 : : "bdev_nvme_get_io_paths requires no parameters");
2165 : :
2166 : 0 : free_rpc_get_io_paths(&ctx->req);
2167 : 0 : free(ctx);
2168 : 0 : return;
2169 : : }
2170 : :
2171 : 0 : ctx->request = request;
2172 : 0 : ctx->w = spdk_jsonrpc_begin_result(request);
2173 : :
2174 : 0 : spdk_json_write_object_begin(ctx->w);
2175 : :
2176 : 0 : spdk_json_write_named_array_begin(ctx->w, "poll_groups");
2177 : :
2178 : 0 : spdk_for_each_channel(&g_nvme_bdev_ctrlrs,
2179 : : _rpc_bdev_nvme_get_io_paths,
2180 : : ctx,
2181 : : rpc_bdev_nvme_get_io_paths_done);
2182 : : }
2183 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_io_paths", rpc_bdev_nvme_get_io_paths, SPDK_RPC_RUNTIME)
2184 : :
2185 : : struct rpc_bdev_nvme_set_preferred_path {
2186 : : char *name;
2187 : : uint16_t cntlid;
2188 : : };
2189 : :
2190 : : static void
2191 : 0 : free_rpc_bdev_nvme_set_preferred_path(struct rpc_bdev_nvme_set_preferred_path *req)
2192 : : {
2193 : 0 : free(req->name);
2194 : 0 : }
2195 : :
2196 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_set_preferred_path_decoders[] = {
2197 : : {"name", offsetof(struct rpc_bdev_nvme_set_preferred_path, name), spdk_json_decode_string},
2198 : : {"cntlid", offsetof(struct rpc_bdev_nvme_set_preferred_path, cntlid), spdk_json_decode_uint16},
2199 : : };
2200 : :
2201 : : struct rpc_bdev_nvme_set_preferred_path_ctx {
2202 : : struct rpc_bdev_nvme_set_preferred_path req;
2203 : : struct spdk_jsonrpc_request *request;
2204 : : };
2205 : :
2206 : : static void
2207 : 0 : rpc_bdev_nvme_set_preferred_path_done(void *cb_arg, int rc)
2208 : : {
2209 : 0 : struct rpc_bdev_nvme_set_preferred_path_ctx *ctx = cb_arg;
2210 : :
2211 [ # # ]: 0 : if (rc == 0) {
2212 : 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2213 : : } else {
2214 : 0 : spdk_jsonrpc_send_error_response(ctx->request, rc, spdk_strerror(-rc));
2215 : : }
2216 : :
2217 : 0 : free_rpc_bdev_nvme_set_preferred_path(&ctx->req);
2218 : 0 : free(ctx);
2219 : 0 : }
2220 : :
2221 : : static void
2222 : 0 : rpc_bdev_nvme_set_preferred_path(struct spdk_jsonrpc_request *request,
2223 : : const struct spdk_json_val *params)
2224 : : {
2225 : : struct rpc_bdev_nvme_set_preferred_path_ctx *ctx;
2226 : :
2227 : 0 : ctx = calloc(1, sizeof(*ctx));
2228 [ # # ]: 0 : if (ctx == NULL) {
2229 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2230 : 0 : return;
2231 : : }
2232 : :
2233 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_set_preferred_path_decoders,
2234 : : SPDK_COUNTOF(rpc_bdev_nvme_set_preferred_path_decoders),
2235 : 0 : &ctx->req)) {
2236 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2237 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2238 : : "spdk_json_decode_object failed");
2239 : 0 : goto cleanup;
2240 : : }
2241 : :
2242 : 0 : ctx->request = request;
2243 : :
2244 : 0 : bdev_nvme_set_preferred_path(ctx->req.name, ctx->req.cntlid,
2245 : : rpc_bdev_nvme_set_preferred_path_done, ctx);
2246 : 0 : return;
2247 : :
2248 : 0 : cleanup:
2249 : 0 : free_rpc_bdev_nvme_set_preferred_path(&ctx->req);
2250 : 0 : free(ctx);
2251 : : }
2252 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_set_preferred_path", rpc_bdev_nvme_set_preferred_path,
2253 : : SPDK_RPC_RUNTIME)
2254 : :
2255 : : struct rpc_set_multipath_policy {
2256 : : char *name;
2257 : : enum bdev_nvme_multipath_policy policy;
2258 : : enum bdev_nvme_multipath_selector selector;
2259 : : uint32_t rr_min_io;
2260 : : };
2261 : :
2262 : : static void
2263 : 0 : free_rpc_set_multipath_policy(struct rpc_set_multipath_policy *req)
2264 : : {
2265 : 0 : free(req->name);
2266 : 0 : }
2267 : :
2268 : : static int
2269 : 0 : rpc_decode_mp_policy(const struct spdk_json_val *val, void *out)
2270 : : {
2271 : 0 : enum bdev_nvme_multipath_policy *policy = out;
2272 : :
2273 [ # # ]: 0 : if (spdk_json_strequal(val, "active_passive") == true) {
2274 : 0 : *policy = BDEV_NVME_MP_POLICY_ACTIVE_PASSIVE;
2275 [ # # ]: 0 : } else if (spdk_json_strequal(val, "active_active") == true) {
2276 : 0 : *policy = BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE;
2277 : : } else {
2278 : 0 : SPDK_NOTICELOG("Invalid parameter value: policy\n");
2279 : 0 : return -EINVAL;
2280 : : }
2281 : :
2282 : 0 : return 0;
2283 : : }
2284 : :
2285 : : static int
2286 : 0 : rpc_decode_mp_selector(const struct spdk_json_val *val, void *out)
2287 : : {
2288 : 0 : enum bdev_nvme_multipath_selector *selector = out;
2289 : :
2290 [ # # ]: 0 : if (spdk_json_strequal(val, "round_robin") == true) {
2291 : 0 : *selector = BDEV_NVME_MP_SELECTOR_ROUND_ROBIN;
2292 [ # # ]: 0 : } else if (spdk_json_strequal(val, "queue_depth") == true) {
2293 : 0 : *selector = BDEV_NVME_MP_SELECTOR_QUEUE_DEPTH;
2294 : : } else {
2295 : 0 : SPDK_NOTICELOG("Invalid parameter value: selector\n");
2296 : 0 : return -EINVAL;
2297 : : }
2298 : :
2299 : 0 : return 0;
2300 : : }
2301 : :
2302 : : static const struct spdk_json_object_decoder rpc_set_multipath_policy_decoders[] = {
2303 : : {"name", offsetof(struct rpc_set_multipath_policy, name), spdk_json_decode_string},
2304 : : {"policy", offsetof(struct rpc_set_multipath_policy, policy), rpc_decode_mp_policy},
2305 : : {"selector", offsetof(struct rpc_set_multipath_policy, selector), rpc_decode_mp_selector, true},
2306 : : {"rr_min_io", offsetof(struct rpc_set_multipath_policy, rr_min_io), spdk_json_decode_uint32, true},
2307 : : };
2308 : :
2309 : : struct rpc_set_multipath_policy_ctx {
2310 : : struct rpc_set_multipath_policy req;
2311 : : struct spdk_jsonrpc_request *request;
2312 : : };
2313 : :
2314 : : static void
2315 : 0 : rpc_bdev_nvme_set_multipath_policy_done(void *cb_arg, int rc)
2316 : : {
2317 : 0 : struct rpc_set_multipath_policy_ctx *ctx = cb_arg;
2318 : :
2319 [ # # ]: 0 : if (rc == 0) {
2320 : 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2321 : : } else {
2322 : 0 : spdk_jsonrpc_send_error_response(ctx->request, rc, spdk_strerror(-rc));
2323 : : }
2324 : :
2325 : 0 : free_rpc_set_multipath_policy(&ctx->req);
2326 : 0 : free(ctx);
2327 : 0 : }
2328 : :
2329 : : static void
2330 : 0 : rpc_bdev_nvme_set_multipath_policy(struct spdk_jsonrpc_request *request,
2331 : : const struct spdk_json_val *params)
2332 : : {
2333 : : struct rpc_set_multipath_policy_ctx *ctx;
2334 : :
2335 : 0 : ctx = calloc(1, sizeof(*ctx));
2336 [ # # ]: 0 : if (ctx == NULL) {
2337 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2338 : 0 : return;
2339 : : }
2340 : :
2341 : 0 : ctx->req.rr_min_io = UINT32_MAX;
2342 : :
2343 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_set_multipath_policy_decoders,
2344 : : SPDK_COUNTOF(rpc_set_multipath_policy_decoders),
2345 : 0 : &ctx->req)) {
2346 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2347 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2348 : : "spdk_json_decode_object failed");
2349 : 0 : goto cleanup;
2350 : : }
2351 : :
2352 : 0 : ctx->request = request;
2353 : :
2354 [ # # # # ]: 0 : if (ctx->req.policy != BDEV_NVME_MP_POLICY_ACTIVE_ACTIVE && ctx->req.selector > 0) {
2355 : 0 : SPDK_ERRLOG("selector only works in active_active mode\n");
2356 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2357 : : "spdk_json_decode_object failed");
2358 : 0 : goto cleanup;
2359 : : }
2360 : :
2361 : 0 : bdev_nvme_set_multipath_policy(ctx->req.name, ctx->req.policy, ctx->req.selector,
2362 : : ctx->req.rr_min_io,
2363 : : rpc_bdev_nvme_set_multipath_policy_done, ctx);
2364 : 0 : return;
2365 : :
2366 : 0 : cleanup:
2367 : 0 : free_rpc_set_multipath_policy(&ctx->req);
2368 : 0 : free(ctx);
2369 : : }
2370 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_set_multipath_policy", rpc_bdev_nvme_set_multipath_policy,
2371 : : SPDK_RPC_RUNTIME)
2372 : :
2373 : : struct rpc_bdev_nvme_start_mdns_discovery {
2374 : : char *name;
2375 : : char *svcname;
2376 : : char *hostnqn;
2377 : : struct spdk_nvme_ctrlr_opts opts;
2378 : : struct nvme_ctrlr_opts bdev_opts;
2379 : : };
2380 : :
2381 : : static void
2382 : 4 : free_rpc_bdev_nvme_start_mdns_discovery(struct rpc_bdev_nvme_start_mdns_discovery *req)
2383 : : {
2384 : 4 : free(req->name);
2385 : 4 : free(req->svcname);
2386 : 4 : free(req->hostnqn);
2387 : 4 : }
2388 : :
2389 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_start_mdns_discovery_decoders[] = {
2390 : : {"name", offsetof(struct rpc_bdev_nvme_start_mdns_discovery, name), spdk_json_decode_string},
2391 : : {"svcname", offsetof(struct rpc_bdev_nvme_start_mdns_discovery, svcname), spdk_json_decode_string},
2392 : : {"hostnqn", offsetof(struct rpc_bdev_nvme_start_mdns_discovery, hostnqn), spdk_json_decode_string, true},
2393 : : };
2394 : :
2395 : : struct rpc_bdev_nvme_start_mdns_discovery_ctx {
2396 : : struct rpc_bdev_nvme_start_mdns_discovery req;
2397 : : struct spdk_jsonrpc_request *request;
2398 : : };
2399 : :
2400 : : static void
2401 : 4 : rpc_bdev_nvme_start_mdns_discovery(struct spdk_jsonrpc_request *request,
2402 : : const struct spdk_json_val *params)
2403 : : {
2404 : : struct rpc_bdev_nvme_start_mdns_discovery_ctx *ctx;
2405 : : int rc;
2406 : :
2407 : 4 : ctx = calloc(1, sizeof(*ctx));
2408 [ - + ]: 4 : if (!ctx) {
2409 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2410 : 0 : return;
2411 : : }
2412 : :
2413 : 4 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.opts, sizeof(ctx->req.opts));
2414 : :
2415 [ - + ]: 4 : if (spdk_json_decode_object(params, rpc_bdev_nvme_start_mdns_discovery_decoders,
2416 : : SPDK_COUNTOF(rpc_bdev_nvme_start_mdns_discovery_decoders),
2417 : 4 : &ctx->req)) {
2418 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2419 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2420 : : "spdk_json_decode_object failed");
2421 : 0 : goto cleanup;
2422 : : }
2423 : :
2424 [ + - ]: 4 : if (ctx->req.hostnqn) {
2425 [ - + ]: 4 : snprintf(ctx->req.opts.hostnqn, sizeof(ctx->req.opts.hostnqn), "%s",
2426 : : ctx->req.hostnqn);
2427 : : }
2428 : 4 : ctx->request = request;
2429 : 4 : rc = bdev_nvme_start_mdns_discovery(ctx->req.name, ctx->req.svcname, &ctx->req.opts,
2430 : : &ctx->req.bdev_opts);
2431 [ + + ]: 4 : if (rc) {
2432 : 2 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2433 : : } else {
2434 : 2 : spdk_jsonrpc_send_bool_response(request, true);
2435 : : }
2436 : :
2437 : 4 : cleanup:
2438 : 4 : free_rpc_bdev_nvme_start_mdns_discovery(&ctx->req);
2439 : 4 : free(ctx);
2440 : : }
2441 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_start_mdns_discovery", rpc_bdev_nvme_start_mdns_discovery,
2442 : : SPDK_RPC_RUNTIME)
2443 : :
2444 : : struct rpc_bdev_nvme_stop_mdns_discovery {
2445 : : char *name;
2446 : : };
2447 : :
2448 : : static const struct spdk_json_object_decoder rpc_bdev_nvme_stop_mdns_discovery_decoders[] = {
2449 : : {"name", offsetof(struct rpc_bdev_nvme_stop_mdns_discovery, name), spdk_json_decode_string},
2450 : : };
2451 : :
2452 : : struct rpc_bdev_nvme_stop_mdns_discovery_ctx {
2453 : : struct rpc_bdev_nvme_stop_mdns_discovery req;
2454 : : struct spdk_jsonrpc_request *request;
2455 : : };
2456 : :
2457 : : static void
2458 : 2 : rpc_bdev_nvme_stop_mdns_discovery(struct spdk_jsonrpc_request *request,
2459 : : const struct spdk_json_val *params)
2460 : : {
2461 : : struct rpc_bdev_nvme_stop_mdns_discovery_ctx *ctx;
2462 : : int rc;
2463 : :
2464 : 2 : ctx = calloc(1, sizeof(*ctx));
2465 [ - + ]: 2 : if (!ctx) {
2466 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2467 : 0 : return;
2468 : : }
2469 : :
2470 [ - + ]: 2 : if (spdk_json_decode_object(params, rpc_bdev_nvme_stop_mdns_discovery_decoders,
2471 : : SPDK_COUNTOF(rpc_bdev_nvme_stop_mdns_discovery_decoders),
2472 : 2 : &ctx->req)) {
2473 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2474 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2475 : : "spdk_json_decode_object failed");
2476 : 0 : goto cleanup;
2477 : : }
2478 : :
2479 : 2 : ctx->request = request;
2480 : 2 : rc = bdev_nvme_stop_mdns_discovery(ctx->req.name);
2481 : :
2482 [ - + ]: 2 : if (rc) {
2483 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2484 : 0 : goto cleanup;
2485 : : }
2486 : 2 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2487 : :
2488 : 2 : cleanup:
2489 : 2 : free(ctx->req.name);
2490 : 2 : free(ctx);
2491 : : }
2492 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_stop_mdns_discovery", rpc_bdev_nvme_stop_mdns_discovery,
2493 : : SPDK_RPC_RUNTIME)
2494 : :
2495 : : static void
2496 : 3 : rpc_bdev_nvme_get_mdns_discovery_info(struct spdk_jsonrpc_request *request,
2497 : : const struct spdk_json_val *params)
2498 : : {
2499 : 3 : bdev_nvme_get_mdns_discovery_info(request);
2500 : 3 : }
2501 : :
2502 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_mdns_discovery_info", rpc_bdev_nvme_get_mdns_discovery_info,
2503 : : SPDK_RPC_RUNTIME)
2504 : :
2505 : : struct rpc_get_path_stat {
2506 : : char *name;
2507 : : };
2508 : :
2509 : : struct path_stat {
2510 : : struct spdk_bdev_io_stat stat;
2511 : : struct spdk_nvme_transport_id trid;
2512 : : struct nvme_ns *ns;
2513 : : };
2514 : :
2515 : : struct rpc_bdev_nvme_path_stat_ctx {
2516 : : struct spdk_jsonrpc_request *request;
2517 : : struct path_stat *path_stat;
2518 : : uint32_t num_paths;
2519 : : struct spdk_bdev_desc *desc;
2520 : : };
2521 : :
2522 : : static void
2523 : 0 : free_rpc_get_path_stat(struct rpc_get_path_stat *req)
2524 : : {
2525 : 0 : free(req->name);
2526 : 0 : }
2527 : :
2528 : : static const struct spdk_json_object_decoder rpc_get_path_stat_decoders[] = {
2529 : : {"name", offsetof(struct rpc_get_path_stat, name), spdk_json_decode_string},
2530 : : };
2531 : :
2532 : : static void
2533 : 0 : dummy_bdev_event_cb(enum spdk_bdev_event_type type, struct spdk_bdev *bdev, void *ctx)
2534 : : {
2535 : 0 : }
2536 : :
2537 : : static void
2538 : 0 : rpc_bdev_nvme_path_stat_per_channel(struct spdk_io_channel_iter *i)
2539 : : {
2540 : 0 : struct rpc_bdev_nvme_path_stat_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2541 : 0 : struct spdk_io_channel *ch = spdk_io_channel_iter_get_channel(i);
2542 : 0 : struct nvme_bdev_channel *nbdev_ch = spdk_io_channel_get_ctx(ch);
2543 : : struct nvme_io_path *io_path;
2544 : : struct path_stat *path_stat;
2545 : : uint32_t j;
2546 : :
2547 [ # # ]: 0 : assert(ctx->num_paths != 0);
2548 : :
2549 [ # # ]: 0 : for (j = 0; j < ctx->num_paths; j++) {
2550 : 0 : path_stat = &ctx->path_stat[j];
2551 : :
2552 [ # # ]: 0 : STAILQ_FOREACH(io_path, &nbdev_ch->io_path_list, stailq) {
2553 [ # # ]: 0 : if (path_stat->ns == io_path->nvme_ns) {
2554 [ # # ]: 0 : assert(io_path->stat != NULL);
2555 : 0 : spdk_bdev_add_io_stat(&path_stat->stat, io_path->stat);
2556 : : }
2557 : : }
2558 : : }
2559 : :
2560 : 0 : spdk_for_each_channel_continue(i, 0);
2561 : 0 : }
2562 : :
2563 : : static void
2564 : 0 : rpc_bdev_nvme_path_stat_done(struct spdk_io_channel_iter *i, int status)
2565 : : {
2566 : 0 : struct rpc_bdev_nvme_path_stat_ctx *ctx = spdk_io_channel_iter_get_ctx(i);
2567 : 0 : struct nvme_bdev *nbdev = spdk_io_channel_iter_get_io_device(i);
2568 : : struct spdk_json_write_ctx *w;
2569 : : struct path_stat *path_stat;
2570 : : uint32_t j;
2571 : :
2572 [ # # ]: 0 : assert(ctx->num_paths != 0);
2573 : :
2574 : 0 : w = spdk_jsonrpc_begin_result(ctx->request);
2575 : 0 : spdk_json_write_object_begin(w);
2576 : 0 : spdk_json_write_named_string(w, "name", nbdev->disk.name);
2577 : 0 : spdk_json_write_named_array_begin(w, "stats");
2578 : :
2579 [ # # ]: 0 : for (j = 0; j < ctx->num_paths; j++) {
2580 : 0 : path_stat = &ctx->path_stat[j];
2581 : 0 : spdk_json_write_object_begin(w);
2582 : :
2583 : 0 : spdk_json_write_named_object_begin(w, "trid");
2584 : 0 : nvme_bdev_dump_trid_json(&path_stat->trid, w);
2585 : 0 : spdk_json_write_object_end(w);
2586 : :
2587 : 0 : spdk_json_write_named_object_begin(w, "stat");
2588 : 0 : spdk_bdev_dump_io_stat_json(&path_stat->stat, w);
2589 : 0 : spdk_json_write_object_end(w);
2590 : :
2591 : 0 : spdk_json_write_object_end(w);
2592 : : }
2593 : :
2594 : 0 : spdk_json_write_array_end(w);
2595 : 0 : spdk_json_write_object_end(w);
2596 : 0 : spdk_jsonrpc_end_result(ctx->request, w);
2597 : :
2598 : 0 : spdk_bdev_close(ctx->desc);
2599 : 0 : free(ctx->path_stat);
2600 : 0 : free(ctx);
2601 : 0 : }
2602 : :
2603 : : static void
2604 : 0 : rpc_bdev_nvme_get_path_iostat(struct spdk_jsonrpc_request *request,
2605 : : const struct spdk_json_val *params)
2606 : : {
2607 : 0 : struct rpc_get_path_stat req = {};
2608 : 0 : struct spdk_bdev_desc *desc = NULL;
2609 : : struct spdk_bdev *bdev;
2610 : : struct nvme_bdev *nbdev;
2611 : : struct nvme_ns *nvme_ns;
2612 : : struct path_stat *path_stat;
2613 : : struct rpc_bdev_nvme_path_stat_ctx *ctx;
2614 : 0 : struct spdk_bdev_nvme_opts opts;
2615 : 0 : uint32_t num_paths = 0, i = 0;
2616 : : int rc;
2617 : :
2618 : 0 : bdev_nvme_get_opts(&opts);
2619 [ # # # # ]: 0 : if (!opts.io_path_stat) {
2620 : 0 : SPDK_ERRLOG("RPC not enabled if enable_io_path_stat is false\n");
2621 : 0 : spdk_jsonrpc_send_error_response(request, -EPERM,
2622 : : "RPC not enabled if enable_io_path_stat is false");
2623 : 0 : return;
2624 : : }
2625 : :
2626 [ # # ]: 0 : if (spdk_json_decode_object(params, rpc_get_path_stat_decoders,
2627 : : SPDK_COUNTOF(rpc_get_path_stat_decoders),
2628 : : &req)) {
2629 : 0 : SPDK_ERRLOG("spdk_json_decode_object failed\n");
2630 : 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
2631 : : "spdk_json_decode_object failed");
2632 : 0 : free_rpc_get_path_stat(&req);
2633 : 0 : return;
2634 : : }
2635 : :
2636 : 0 : rc = spdk_bdev_open_ext(req.name, false, dummy_bdev_event_cb, NULL, &desc);
2637 [ # # ]: 0 : if (rc != 0) {
2638 : 0 : SPDK_ERRLOG("Failed to open bdev '%s': %d\n", req.name, rc);
2639 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2640 : 0 : free_rpc_get_path_stat(&req);
2641 : 0 : return;
2642 : : }
2643 : :
2644 : 0 : free_rpc_get_path_stat(&req);
2645 : :
2646 : 0 : ctx = calloc(1, sizeof(struct rpc_bdev_nvme_path_stat_ctx));
2647 [ # # ]: 0 : if (ctx == NULL) {
2648 : 0 : spdk_bdev_close(desc);
2649 : 0 : SPDK_ERRLOG("Failed to allocate rpc_bdev_nvme_path_stat_ctx struct\n");
2650 : 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2651 : 0 : return;
2652 : : }
2653 : :
2654 : 0 : bdev = spdk_bdev_desc_get_bdev(desc);
2655 : 0 : nbdev = bdev->ctxt;
2656 : :
2657 [ # # ]: 0 : pthread_mutex_lock(&nbdev->mutex);
2658 [ # # ]: 0 : if (nbdev->ref == 0) {
2659 : 0 : rc = -ENOENT;
2660 : 0 : goto err;
2661 : : }
2662 : :
2663 : 0 : num_paths = nbdev->ref;
2664 : 0 : path_stat = calloc(num_paths, sizeof(struct path_stat));
2665 [ # # ]: 0 : if (path_stat == NULL) {
2666 : 0 : rc = -ENOMEM;
2667 : 0 : SPDK_ERRLOG("Failed to allocate memory for path_stat.\n");
2668 : 0 : goto err;
2669 : : }
2670 : :
2671 : : /* store the history stat */
2672 [ # # ]: 0 : TAILQ_FOREACH(nvme_ns, &nbdev->nvme_ns_list, tailq) {
2673 [ # # ]: 0 : assert(i < num_paths);
2674 : 0 : path_stat[i].ns = nvme_ns;
2675 : 0 : path_stat[i].trid = nvme_ns->ctrlr->active_path_id->trid;
2676 : :
2677 [ # # ]: 0 : assert(nvme_ns->stat != NULL);
2678 [ # # # # ]: 0 : memcpy(&path_stat[i].stat, nvme_ns->stat, sizeof(struct spdk_bdev_io_stat));
2679 : 0 : i++;
2680 : : }
2681 [ # # ]: 0 : pthread_mutex_unlock(&nbdev->mutex);
2682 : :
2683 : 0 : ctx->request = request;
2684 : 0 : ctx->desc = desc;
2685 : 0 : ctx->path_stat = path_stat;
2686 : 0 : ctx->num_paths = num_paths;
2687 : :
2688 : 0 : spdk_for_each_channel(nbdev,
2689 : : rpc_bdev_nvme_path_stat_per_channel,
2690 : : ctx,
2691 : : rpc_bdev_nvme_path_stat_done);
2692 : 0 : return;
2693 : :
2694 : 0 : err:
2695 [ # # ]: 0 : pthread_mutex_unlock(&nbdev->mutex);
2696 : 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2697 : 0 : spdk_bdev_close(desc);
2698 : 0 : free(ctx);
2699 : : }
2700 : 2044 : SPDK_RPC_REGISTER("bdev_nvme_get_path_iostat", rpc_bdev_nvme_get_path_iostat,
2701 : : SPDK_RPC_RUNTIME)
|