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 0 : rpc_decode_action_on_timeout(const struct spdk_json_val *val, void *out)
30 : {
31 0 : enum spdk_bdev_timeout_action *action = out;
32 :
33 0 : if (spdk_json_strequal(val, "none") == true) {
34 0 : *action = SPDK_BDEV_NVME_TIMEOUT_ACTION_NONE;
35 0 : } else if (spdk_json_strequal(val, "abort") == true) {
36 0 : *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 0 : 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 0 : rpc_bdev_nvme_set_options(struct spdk_jsonrpc_request *request,
79 : const struct spdk_json_val *params)
80 : {
81 0 : struct spdk_bdev_nvme_opts opts;
82 : int rc;
83 :
84 0 : bdev_nvme_get_opts(&opts);
85 0 : 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 0 : rc = bdev_nvme_set_opts(&opts);
95 0 : if (rc == -EPERM) {
96 0 : spdk_jsonrpc_send_error_response(request, -EPERM,
97 : "RPC not permitted with nvme controllers already attached");
98 0 : } else if (rc) {
99 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
100 : } else {
101 0 : spdk_jsonrpc_send_bool_response(request, true);
102 : }
103 :
104 0 : return;
105 : }
106 0 : 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 0 : rpc_bdev_nvme_set_hotplug_done(void *ctx)
121 : {
122 0 : struct spdk_jsonrpc_request *request = ctx;
123 :
124 0 : spdk_jsonrpc_send_bool_response(request, true);
125 0 : }
126 :
127 : static void
128 0 : rpc_bdev_nvme_set_hotplug(struct spdk_jsonrpc_request *request,
129 : const struct spdk_json_val *params)
130 : {
131 0 : struct rpc_bdev_nvme_hotplug req = {false, 0};
132 : int rc;
133 :
134 0 : 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 0 : rc = bdev_nvme_set_hotplug(req.enabled, req.period_us, rpc_bdev_nvme_set_hotplug_done,
142 : request);
143 0 : if (rc) {
144 0 : goto invalid;
145 : }
146 :
147 0 : return;
148 0 : invalid:
149 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, spdk_strerror(-rc));
150 : }
151 0 : 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 0 : free_rpc_bdev_nvme_attach_controller(struct rpc_bdev_nvme_attach_controller *req)
179 : {
180 0 : free(req->name);
181 0 : free(req->trtype);
182 0 : free(req->adrfam);
183 0 : free(req->traddr);
184 0 : free(req->trsvcid);
185 0 : free(req->priority);
186 0 : free(req->subnqn);
187 0 : free(req->hostnqn);
188 0 : free(req->hostaddr);
189 0 : free(req->hostsvcid);
190 0 : free(req->psk);
191 0 : spdk_memset_s(req->drv_opts.psk, sizeof(req->drv_opts.psk), 0, sizeof(req->drv_opts.psk));
192 0 : }
193 :
194 : static int
195 0 : bdev_nvme_decode_reftag(const struct spdk_json_val *val, void *out)
196 : {
197 0 : uint32_t *flag = out;
198 0 : bool reftag;
199 : int rc;
200 :
201 0 : rc = spdk_json_decode_bool(val, &reftag);
202 0 : if (rc == 0 && reftag == true) {
203 0 : *flag |= SPDK_NVME_IO_FLAGS_PRCHK_REFTAG;
204 : }
205 :
206 0 : return rc;
207 : }
208 :
209 : static int
210 0 : bdev_nvme_decode_guard(const struct spdk_json_val *val, void *out)
211 : {
212 0 : uint32_t *flag = out;
213 0 : bool guard;
214 : int rc;
215 :
216 0 : rc = spdk_json_decode_bool(val, &guard);
217 0 : if (rc == 0 && guard == true) {
218 0 : *flag |= SPDK_NVME_IO_FLAGS_PRCHK_GUARD;
219 : }
220 :
221 0 : return rc;
222 : }
223 :
224 : static int
225 0 : bdev_nvme_decode_multipath(const struct spdk_json_val *val, void *out)
226 : {
227 0 : enum bdev_nvme_multipath_mode *multipath = out;
228 :
229 0 : if (spdk_json_strequal(val, "failover") == true) {
230 0 : *multipath = BDEV_NVME_MP_MODE_FAILOVER;
231 0 : } else if (spdk_json_strequal(val, "multipath") == true) {
232 0 : *multipath = BDEV_NVME_MP_MODE_MULTIPATH;
233 0 : } else if (spdk_json_strequal(val, "disable") == true) {
234 0 : *multipath = BDEV_NVME_MP_MODE_DISABLE;
235 : } else {
236 0 : SPDK_NOTICELOG("Invalid parameter value: multipath\n");
237 0 : return -EINVAL;
238 : }
239 :
240 0 : 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 0 : free_rpc_bdev_nvme_attach_controller_ctx(struct rpc_bdev_nvme_attach_controller_ctx *ctx)
282 : {
283 0 : free_rpc_bdev_nvme_attach_controller(&ctx->req);
284 0 : free(ctx->names);
285 0 : free(ctx);
286 0 : }
287 :
288 : static void
289 0 : rpc_bdev_nvme_attach_controller_examined(void *cb_ctx)
290 : {
291 0 : struct rpc_bdev_nvme_attach_controller_ctx *ctx = cb_ctx;
292 0 : struct spdk_jsonrpc_request *request = ctx->request;
293 : struct spdk_json_write_ctx *w;
294 : size_t i;
295 :
296 0 : w = spdk_jsonrpc_begin_result(request);
297 0 : spdk_json_write_array_begin(w);
298 0 : for (i = 0; i < ctx->bdev_count; i++) {
299 0 : spdk_json_write_string(w, ctx->names[i]);
300 : }
301 0 : spdk_json_write_array_end(w);
302 0 : spdk_jsonrpc_end_result(request, w);
303 :
304 0 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
305 0 : }
306 :
307 : static void
308 0 : rpc_bdev_nvme_attach_controller_done(void *cb_ctx, size_t bdev_count, int rc)
309 : {
310 0 : struct rpc_bdev_nvme_attach_controller_ctx *ctx = cb_ctx;
311 0 : struct spdk_jsonrpc_request *request = ctx->request;
312 :
313 0 : if (rc < 0) {
314 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INVALID_PARAMS, "Invalid parameters");
315 0 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
316 0 : return;
317 : }
318 :
319 0 : ctx->bdev_count = bdev_count;
320 0 : spdk_bdev_wait_for_examine(rpc_bdev_nvme_attach_controller_examined, ctx);
321 : }
322 :
323 : static int
324 0 : 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 0 : if (stat(fname, &statbuf) != 0) {
331 0 : SPDK_ERRLOG("Could not read permissions for PSK file\n");
332 0 : return -EACCES;
333 : }
334 :
335 0 : if ((statbuf.st_mode & TCP_PSK_INVALID_PERMISSIONS) != 0) {
336 0 : SPDK_ERRLOG("Incorrect permissions for PSK file\n");
337 0 : return -EPERM;
338 : }
339 0 : if ((size_t)statbuf.st_size >= bufsz) {
340 0 : SPDK_ERRLOG("Invalid PSK: too long\n");
341 0 : return -EINVAL;
342 : }
343 0 : psk_file = fopen(fname, "r");
344 0 : if (psk_file == NULL) {
345 0 : SPDK_ERRLOG("Could not open PSK file\n");
346 0 : return -EINVAL;
347 : }
348 :
349 0 : memset(buf, 0, bufsz);
350 0 : rc = fread(buf, 1, statbuf.st_size, psk_file);
351 0 : 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 0 : fclose(psk_file);
358 0 : return 0;
359 : }
360 :
361 : static void
362 0 : 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 0 : 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 0 : struct nvme_ctrlr *ctrlr = NULL;
370 : size_t len, maxlen;
371 0 : bool multipath = false;
372 : int rc;
373 :
374 0 : ctx = calloc(1, sizeof(*ctx));
375 0 : if (!ctx) {
376 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
377 0 : return;
378 : }
379 :
380 0 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.drv_opts, sizeof(ctx->req.drv_opts));
381 0 : 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 0 : ctx->req.multipath = BDEV_NVME_MP_MODE_FAILOVER;
385 0 : ctx->req.max_bdevs = DEFAULT_MAX_BDEVS_PER_RPC;
386 :
387 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_attach_controller_decoders,
388 : SPDK_COUNTOF(rpc_bdev_nvme_attach_controller_decoders),
389 0 : &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 0 : 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 0 : ctx->names = calloc(ctx->req.max_bdevs, sizeof(char *));
402 0 : 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 0 : rc = spdk_nvme_transport_id_populate_trstring(&trid, ctx->req.trtype);
409 0 : 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 0 : rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype);
418 0 : assert(rc == 0);
419 :
420 : /* Parse traddr */
421 0 : maxlen = sizeof(trid.traddr);
422 0 : len = strnlen(ctx->req.traddr, maxlen);
423 0 : 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 0 : memcpy(trid.traddr, ctx->req.traddr, len + 1);
429 :
430 : /* Parse adrfam */
431 0 : if (ctx->req.adrfam) {
432 0 : rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam);
433 0 : 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 0 : if (ctx->req.trsvcid) {
443 0 : maxlen = sizeof(trid.trsvcid);
444 0 : len = strnlen(ctx->req.trsvcid, maxlen);
445 0 : 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 0 : memcpy(trid.trsvcid, ctx->req.trsvcid, len + 1);
451 : }
452 :
453 : /* Parse priority for the NVMe-oF transport connection */
454 0 : if (ctx->req.priority) {
455 0 : trid.priority = spdk_strtol(ctx->req.priority, 10);
456 : }
457 :
458 : /* Parse subnqn */
459 0 : if (ctx->req.subnqn) {
460 0 : maxlen = sizeof(trid.subnqn);
461 0 : len = strnlen(ctx->req.subnqn, maxlen);
462 0 : 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 0 : memcpy(trid.subnqn, ctx->req.subnqn, len + 1);
468 : }
469 :
470 0 : if (ctx->req.hostnqn) {
471 0 : snprintf(ctx->req.drv_opts.hostnqn, sizeof(ctx->req.drv_opts.hostnqn), "%s",
472 : ctx->req.hostnqn);
473 : }
474 :
475 0 : if (ctx->req.psk) {
476 0 : if (!g_tls_log) {
477 0 : SPDK_NOTICELOG("TLS support is considered experimental\n");
478 0 : g_tls_log = true;
479 : }
480 0 : rc = tcp_load_psk(ctx->req.psk, ctx->req.drv_opts.psk, sizeof(ctx->req.drv_opts.psk));
481 0 : if (rc) {
482 0 : spdk_jsonrpc_send_error_response_fmt(request, -EINVAL, "Could not retrieve PSK from file: %s",
483 : ctx->req.psk);
484 0 : goto cleanup;
485 : }
486 0 : rc = snprintf(ctx->req.bdev_opts.psk_path, sizeof(ctx->req.bdev_opts.psk_path), "%s", ctx->req.psk);
487 0 : 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 0 : if (ctx->req.hostaddr) {
495 0 : maxlen = sizeof(ctx->req.drv_opts.src_addr);
496 0 : len = strnlen(ctx->req.hostaddr, maxlen);
497 0 : 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 0 : snprintf(ctx->req.drv_opts.src_addr, maxlen, "%s", ctx->req.hostaddr);
503 : }
504 :
505 0 : if (ctx->req.hostsvcid) {
506 0 : maxlen = sizeof(ctx->req.drv_opts.src_svcid);
507 0 : len = strnlen(ctx->req.hostsvcid, maxlen);
508 0 : 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 0 : snprintf(ctx->req.drv_opts.src_svcid, maxlen, "%s", ctx->req.hostsvcid);
514 : }
515 :
516 0 : ctrlr = nvme_ctrlr_get_by_name(ctx->req.name);
517 :
518 0 : if (ctrlr) {
519 : /* This controller already exists. Check what the user wants to do. */
520 0 : if (ctx->req.multipath == BDEV_NVME_MP_MODE_DISABLE) {
521 : /* The user does not want to do any form of multipathing. */
522 0 : 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 0 : goto cleanup;
526 : }
527 :
528 0 : 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 0 : drv_opts = spdk_nvme_ctrlr_get_opts(ctrlr->ctrlr);
533 0 : ctrlr_trid = spdk_nvme_ctrlr_get_transport_id(ctrlr->ctrlr);
534 :
535 0 : if (strncmp(trid.traddr, ctrlr_trid->traddr, sizeof(trid.traddr)) == 0 &&
536 0 : strncmp(trid.trsvcid, ctrlr_trid->trsvcid, sizeof(trid.trsvcid)) == 0 &&
537 0 : strncmp(ctx->req.drv_opts.src_addr, drv_opts->src_addr, sizeof(drv_opts->src_addr)) == 0 &&
538 0 : 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 0 : 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 0 : goto cleanup;
544 : }
545 :
546 0 : if (strncmp(trid.subnqn,
547 0 : 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 0 : 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 0 : 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 0 : ctx->req.bdev_opts.prchk_flags = ctrlr->opts.prchk_flags;
572 : }
573 :
574 0 : if (ctx->req.multipath == BDEV_NVME_MP_MODE_MULTIPATH) {
575 0 : multipath = true;
576 : }
577 :
578 0 : 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 0 : ctx->request = request;
586 : /* Should already be zero due to the calloc(), but set explicitly for clarity. */
587 0 : ctx->req.bdev_opts.from_discovery_service = false;
588 0 : 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 0 : if (rc) {
592 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
593 0 : goto cleanup;
594 : }
595 :
596 0 : return;
597 :
598 0 : cleanup:
599 0 : free_rpc_bdev_nvme_attach_controller_ctx(ctx);
600 : }
601 0 : SPDK_RPC_REGISTER("bdev_nvme_attach_controller", rpc_bdev_nvme_attach_controller,
602 : SPDK_RPC_RUNTIME)
603 :
604 : static void
605 0 : rpc_dump_nvme_bdev_controller_info(struct nvme_bdev_ctrlr *nbdev_ctrlr, void *ctx)
606 : {
607 0 : struct spdk_json_write_ctx *w = ctx;
608 : struct nvme_ctrlr *nvme_ctrlr;
609 :
610 0 : spdk_json_write_object_begin(w);
611 0 : spdk_json_write_named_string(w, "name", nbdev_ctrlr->name);
612 :
613 0 : spdk_json_write_named_array_begin(w, "ctrlrs");
614 0 : TAILQ_FOREACH(nvme_ctrlr, &nbdev_ctrlr->ctrlrs, tailq) {
615 0 : nvme_ctrlr_info_json(w, nvme_ctrlr);
616 : }
617 0 : spdk_json_write_array_end(w);
618 0 : spdk_json_write_object_end(w);
619 0 : }
620 :
621 : struct rpc_bdev_nvme_get_controllers {
622 : char *name;
623 : };
624 :
625 : static void
626 0 : free_rpc_bdev_nvme_get_controllers(struct rpc_bdev_nvme_get_controllers *r)
627 : {
628 0 : free(r->name);
629 0 : }
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 0 : rpc_bdev_nvme_get_controllers(struct spdk_jsonrpc_request *request,
637 : const struct spdk_json_val *params)
638 : {
639 0 : struct rpc_bdev_nvme_get_controllers req = {};
640 : struct spdk_json_write_ctx *w;
641 0 : struct nvme_bdev_ctrlr *nbdev_ctrlr = NULL;
642 :
643 0 : 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 0 : if (req.name) {
653 0 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
654 0 : 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 0 : w = spdk_jsonrpc_begin_result(request);
662 0 : spdk_json_write_array_begin(w);
663 :
664 0 : if (nbdev_ctrlr != NULL) {
665 0 : rpc_dump_nvme_bdev_controller_info(nbdev_ctrlr, w);
666 : } else {
667 0 : nvme_bdev_ctrlr_for_each(rpc_dump_nvme_bdev_controller_info, w);
668 : }
669 :
670 0 : spdk_json_write_array_end(w);
671 :
672 0 : spdk_jsonrpc_end_result(request, w);
673 :
674 0 : cleanup:
675 0 : free_rpc_bdev_nvme_get_controllers(&req);
676 0 : }
677 0 : 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 0 : free_rpc_bdev_nvme_detach_controller(struct rpc_bdev_nvme_detach_controller *req)
692 : {
693 0 : free(req->name);
694 0 : free(req->trtype);
695 0 : free(req->adrfam);
696 0 : free(req->traddr);
697 0 : free(req->trsvcid);
698 0 : free(req->subnqn);
699 0 : free(req->hostaddr);
700 0 : free(req->hostsvcid);
701 0 : }
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 0 : rpc_bdev_nvme_detach_controller_done(void *arg, int rc)
716 : {
717 0 : struct spdk_jsonrpc_request *request = arg;
718 :
719 0 : if (rc == 0) {
720 0 : spdk_jsonrpc_send_bool_response(request, true);
721 : } else {
722 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
723 : }
724 0 : }
725 :
726 : static void
727 0 : rpc_bdev_nvme_detach_controller(struct spdk_jsonrpc_request *request,
728 : const struct spdk_json_val *params)
729 : {
730 0 : struct rpc_bdev_nvme_detach_controller req = {NULL};
731 0 : struct nvme_path_id path = {};
732 : size_t len, maxlen;
733 0 : int rc = 0;
734 :
735 0 : 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 0 : if (req.trtype != NULL) {
744 0 : rc = spdk_nvme_transport_id_populate_trstring(&path.trid, req.trtype);
745 0 : 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 0 : rc = spdk_nvme_transport_id_parse_trtype(&path.trid.trtype, req.trtype);
753 0 : 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 0 : if (req.traddr != NULL) {
762 0 : maxlen = sizeof(path.trid.traddr);
763 0 : len = strnlen(req.traddr, maxlen);
764 0 : 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 0 : memcpy(path.trid.traddr, req.traddr, len + 1);
770 : }
771 :
772 0 : if (req.adrfam != NULL) {
773 0 : rc = spdk_nvme_transport_id_parse_adrfam(&path.trid.adrfam, req.adrfam);
774 0 : 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 0 : if (req.trsvcid != NULL) {
783 0 : maxlen = sizeof(path.trid.trsvcid);
784 0 : len = strnlen(req.trsvcid, maxlen);
785 0 : 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 0 : memcpy(path.trid.trsvcid, req.trsvcid, len + 1);
791 : }
792 :
793 : /* Parse subnqn */
794 0 : if (req.subnqn != NULL) {
795 0 : maxlen = sizeof(path.trid.subnqn);
796 0 : len = strnlen(req.subnqn, maxlen);
797 0 : 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 0 : memcpy(path.trid.subnqn, req.subnqn, len + 1);
803 : }
804 :
805 0 : 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 0 : 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 0 : rc = bdev_nvme_delete(req.name, &path, rpc_bdev_nvme_detach_controller_done, request);
828 :
829 0 : if (rc != 0) {
830 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
831 : }
832 :
833 0 : cleanup:
834 0 : free_rpc_bdev_nvme_detach_controller(&req);
835 0 : }
836 0 : 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 0 : free_rpc_apply_firmware(struct rpc_apply_firmware *req)
846 : {
847 0 : free(req->filename);
848 0 : free(req->bdev_name);
849 0 : }
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 0 : apply_firmware_cleanup(struct firmware_update_info *firm_ctx)
875 : {
876 0 : assert(firm_ctx != NULL);
877 0 : assert(firm_ctx->orig_thread == spdk_get_thread());
878 :
879 0 : if (firm_ctx->fw_image) {
880 0 : spdk_free(firm_ctx->fw_image);
881 : }
882 :
883 0 : free_rpc_apply_firmware(&firm_ctx->req);
884 :
885 0 : if (firm_ctx->ch) {
886 0 : spdk_put_io_channel(firm_ctx->ch);
887 : }
888 :
889 0 : if (firm_ctx->desc) {
890 0 : spdk_bdev_close(firm_ctx->desc);
891 : }
892 :
893 0 : free(firm_ctx);
894 0 : }
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 0 : rpc_bdev_nvme_apply_firmware(struct spdk_jsonrpc_request *request,
1016 : const struct spdk_json_val *params)
1017 : {
1018 : int rc;
1019 0 : int fd = -1;
1020 0 : struct stat fw_stat;
1021 : struct spdk_bdev *bdev;
1022 0 : struct spdk_nvme_cmd cmd = {};
1023 : struct firmware_update_info *firm_ctx;
1024 :
1025 0 : firm_ctx = calloc(1, sizeof(struct firmware_update_info));
1026 0 : 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 0 : firm_ctx->fw_image = NULL;
1032 0 : firm_ctx->request = request;
1033 0 : firm_ctx->orig_thread = spdk_get_thread();
1034 :
1035 0 : if (spdk_json_decode_object(params, rpc_apply_firmware_decoders,
1036 0 : 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 0 : 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 0 : bdev = spdk_bdev_desc_get_bdev(firm_ctx->desc);
1050 :
1051 0 : 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 0 : firm_ctx->ch = spdk_bdev_get_io_channel(firm_ctx->desc);
1059 0 : 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 0 : fd = open(firm_ctx->req.filename, O_RDONLY);
1066 0 : if (fd < 0) {
1067 0 : spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_INTERNAL_ERROR,
1068 : "open file failed.");
1069 0 : 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 0 : err:
1124 0 : apply_firmware_cleanup(firm_ctx);
1125 : }
1126 0 : 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 0 : 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 0 : free_rpc_bdev_nvme_controller_op_req(struct rpc_bdev_nvme_controller_op_req *r)
1292 : {
1293 0 : free(r->name);
1294 0 : }
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 0 : rpc_bdev_nvme_controller_op_cb(void *cb_arg, int rc)
1303 : {
1304 0 : struct spdk_jsonrpc_request *request = cb_arg;
1305 :
1306 0 : if (rc == 0) {
1307 0 : spdk_jsonrpc_send_bool_response(request, true);
1308 : } else {
1309 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1310 : }
1311 0 : }
1312 :
1313 : static void
1314 0 : 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 0 : struct rpc_bdev_nvme_controller_op_req req = {NULL};
1319 : struct nvme_bdev_ctrlr *nbdev_ctrlr;
1320 : struct nvme_ctrlr *nvme_ctrlr;
1321 :
1322 0 : 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 0 : nbdev_ctrlr = nvme_bdev_ctrlr_get_by_name(req.name);
1331 0 : 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 0 : if (req.cntlid == 0) {
1338 0 : 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 0 : exit:
1350 0 : free_rpc_bdev_nvme_controller_op_req(&req);
1351 0 : }
1352 :
1353 : static void
1354 0 : rpc_bdev_nvme_reset_controller(struct spdk_jsonrpc_request *request,
1355 : const struct spdk_json_val *params)
1356 : {
1357 0 : rpc_bdev_nvme_controller_op(request, params, NVME_CTRLR_OP_RESET);
1358 0 : }
1359 0 : 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 0 : 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 0 : 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 0 : 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 0 : free_rpc_bdev_nvme_start_discovery(struct rpc_bdev_nvme_start_discovery *req)
1609 : {
1610 0 : free(req->name);
1611 0 : free(req->trtype);
1612 0 : free(req->adrfam);
1613 0 : free(req->traddr);
1614 0 : free(req->trsvcid);
1615 0 : free(req->hostnqn);
1616 0 : }
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 0 : rpc_bdev_nvme_start_discovery_done(void *ctx, int status)
1639 : {
1640 0 : struct spdk_jsonrpc_request *request = ctx;
1641 :
1642 0 : if (status != 0) {
1643 0 : spdk_jsonrpc_send_error_response(request, status, spdk_strerror(-status));
1644 : } else {
1645 0 : spdk_jsonrpc_send_bool_response(request, true);
1646 : }
1647 0 : }
1648 :
1649 : static void
1650 0 : 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 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
1661 0 : if (!ctx) {
1662 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1663 0 : return;
1664 : }
1665 :
1666 0 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.opts, sizeof(ctx->req.opts));
1667 :
1668 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_start_discovery_decoders,
1669 : SPDK_COUNTOF(rpc_bdev_nvme_start_discovery_decoders),
1670 0 : &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 0 : rc = spdk_nvme_transport_id_populate_trstring(&trid, ctx->req.trtype);
1679 0 : 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 0 : rc = spdk_nvme_transport_id_parse_trtype(&trid.trtype, ctx->req.trtype);
1688 0 : assert(rc == 0);
1689 :
1690 : /* Parse traddr */
1691 0 : maxlen = sizeof(trid.traddr);
1692 0 : len = strnlen(ctx->req.traddr, maxlen);
1693 0 : 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 0 : memcpy(trid.traddr, ctx->req.traddr, len + 1);
1699 :
1700 : /* Parse adrfam */
1701 0 : if (ctx->req.adrfam) {
1702 0 : rc = spdk_nvme_transport_id_parse_adrfam(&trid.adrfam, ctx->req.adrfam);
1703 0 : 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 0 : if (ctx->req.trsvcid) {
1713 0 : maxlen = sizeof(trid.trsvcid);
1714 0 : len = strnlen(ctx->req.trsvcid, maxlen);
1715 0 : 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 0 : memcpy(trid.trsvcid, ctx->req.trsvcid, len + 1);
1721 : }
1722 :
1723 0 : if (ctx->req.hostnqn) {
1724 0 : snprintf(ctx->req.opts.hostnqn, sizeof(ctx->req.opts.hostnqn), "%s",
1725 : ctx->req.hostnqn);
1726 : }
1727 :
1728 0 : if (ctx->req.attach_timeout_ms != 0) {
1729 0 : ctx->req.wait_for_attach = true;
1730 : }
1731 :
1732 0 : ctx->request = request;
1733 0 : cb_fn = ctx->req.wait_for_attach ? rpc_bdev_nvme_start_discovery_done : NULL;
1734 0 : cb_ctx = ctx->req.wait_for_attach ? request : NULL;
1735 0 : 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 0 : if (rc) {
1738 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1739 0 : } else if (!ctx->req.wait_for_attach) {
1740 0 : rpc_bdev_nvme_start_discovery_done(request, 0);
1741 : }
1742 :
1743 0 : cleanup:
1744 0 : free_rpc_bdev_nvme_start_discovery(&ctx->req);
1745 0 : free(ctx);
1746 : }
1747 0 : 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 0 : rpc_bdev_nvme_stop_discovery_done(void *cb_ctx)
1765 : {
1766 0 : struct rpc_bdev_nvme_stop_discovery_ctx *ctx = cb_ctx;
1767 :
1768 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1769 0 : free(ctx->req.name);
1770 0 : free(ctx);
1771 0 : }
1772 :
1773 : static void
1774 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
1781 0 : if (!ctx) {
1782 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1783 0 : return;
1784 : }
1785 :
1786 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_stop_discovery_decoders,
1787 : SPDK_COUNTOF(rpc_bdev_nvme_stop_discovery_decoders),
1788 0 : &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 0 : ctx->request = request;
1796 0 : rc = bdev_nvme_stop_discovery(ctx->req.name, rpc_bdev_nvme_stop_discovery_done, ctx);
1797 0 : if (rc) {
1798 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
1799 0 : goto cleanup;
1800 : }
1801 :
1802 0 : return;
1803 :
1804 0 : cleanup:
1805 0 : free(ctx->req.name);
1806 0 : free(ctx);
1807 : }
1808 0 : SPDK_RPC_REGISTER("bdev_nvme_stop_discovery", rpc_bdev_nvme_stop_discovery,
1809 : SPDK_RPC_RUNTIME)
1810 :
1811 : static void
1812 0 : 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 0 : w = spdk_jsonrpc_begin_result(request);
1818 0 : bdev_nvme_get_discovery_info(w);
1819 0 : spdk_jsonrpc_end_result(request, w);
1820 0 : }
1821 0 : 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 0 : free_rpc_add_error_injection(struct rpc_add_error_injection *req)
1842 : {
1843 0 : free(req->name);
1844 0 : }
1845 :
1846 : static int
1847 0 : rpc_error_injection_decode_cmd_type(const struct spdk_json_val *val, void *out)
1848 : {
1849 0 : int *cmd_type = out;
1850 :
1851 0 : if (spdk_json_strequal(val, "admin")) {
1852 0 : *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 0 : 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 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
1924 0 : if (!ctx) {
1925 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
1926 0 : return;
1927 : }
1928 0 : ctx->rpc.err_count = 1;
1929 0 : ctx->request = request;
1930 :
1931 0 : if (spdk_json_decode_object(params,
1932 : rpc_add_error_injection_decoders,
1933 : SPDK_COUNTOF(rpc_add_error_injection_decoders),
1934 0 : &ctx->rpc)) {
1935 0 : spdk_jsonrpc_send_error_response(request, -EINVAL,
1936 : "Failed to parse the request");
1937 0 : goto cleanup;
1938 : }
1939 :
1940 0 : nvme_ctrlr = nvme_ctrlr_get_by_name(ctx->rpc.name);
1941 0 : 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 0 : 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 0 : rc = spdk_nvme_qpair_add_cmd_error_injection(nvme_ctrlr->ctrlr, NULL, ctx->rpc.opc,
1956 0 : ctx->rpc.do_not_submit, ctx->rpc.timeout_in_us, ctx->rpc.err_count,
1957 0 : ctx->rpc.sct, ctx->rpc.sc);
1958 0 : if (rc) {
1959 0 : spdk_jsonrpc_send_error_response(request, -rc,
1960 : "Failed to add the error injection");
1961 : } else {
1962 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
1963 : }
1964 : }
1965 :
1966 0 : cleanup:
1967 0 : free_rpc_add_error_injection(&ctx->rpc);
1968 0 : free(ctx);
1969 : }
1970 0 : 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 0 : 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 0 : 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 0 : 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 0 : 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 0 : free_rpc_bdev_nvme_start_mdns_discovery(struct rpc_bdev_nvme_start_mdns_discovery *req)
2383 : {
2384 0 : free(req->name);
2385 0 : free(req->svcname);
2386 0 : free(req->hostnqn);
2387 0 : }
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 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
2408 0 : if (!ctx) {
2409 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2410 0 : return;
2411 : }
2412 :
2413 0 : spdk_nvme_ctrlr_get_default_ctrlr_opts(&ctx->req.opts, sizeof(ctx->req.opts));
2414 :
2415 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_start_mdns_discovery_decoders,
2416 : SPDK_COUNTOF(rpc_bdev_nvme_start_mdns_discovery_decoders),
2417 0 : &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 0 : if (ctx->req.hostnqn) {
2425 0 : snprintf(ctx->req.opts.hostnqn, sizeof(ctx->req.opts.hostnqn), "%s",
2426 : ctx->req.hostnqn);
2427 : }
2428 0 : ctx->request = request;
2429 0 : rc = bdev_nvme_start_mdns_discovery(ctx->req.name, ctx->req.svcname, &ctx->req.opts,
2430 : &ctx->req.bdev_opts);
2431 0 : if (rc) {
2432 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2433 : } else {
2434 0 : spdk_jsonrpc_send_bool_response(request, true);
2435 : }
2436 :
2437 0 : cleanup:
2438 0 : free_rpc_bdev_nvme_start_mdns_discovery(&ctx->req);
2439 0 : free(ctx);
2440 : }
2441 0 : 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 0 : 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 0 : ctx = calloc(1, sizeof(*ctx));
2465 0 : if (!ctx) {
2466 0 : spdk_jsonrpc_send_error_response(request, -ENOMEM, spdk_strerror(ENOMEM));
2467 0 : return;
2468 : }
2469 :
2470 0 : if (spdk_json_decode_object(params, rpc_bdev_nvme_stop_mdns_discovery_decoders,
2471 : SPDK_COUNTOF(rpc_bdev_nvme_stop_mdns_discovery_decoders),
2472 0 : &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 0 : ctx->request = request;
2480 0 : rc = bdev_nvme_stop_mdns_discovery(ctx->req.name);
2481 :
2482 0 : if (rc) {
2483 0 : spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc));
2484 0 : goto cleanup;
2485 : }
2486 0 : spdk_jsonrpc_send_bool_response(ctx->request, true);
2487 :
2488 0 : cleanup:
2489 0 : free(ctx->req.name);
2490 0 : free(ctx);
2491 : }
2492 0 : SPDK_RPC_REGISTER("bdev_nvme_stop_mdns_discovery", rpc_bdev_nvme_stop_mdns_discovery,
2493 : SPDK_RPC_RUNTIME)
2494 :
2495 : static void
2496 0 : rpc_bdev_nvme_get_mdns_discovery_info(struct spdk_jsonrpc_request *request,
2497 : const struct spdk_json_val *params)
2498 : {
2499 0 : bdev_nvme_get_mdns_discovery_info(request);
2500 0 : }
2501 :
2502 0 : 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 0 : SPDK_RPC_REGISTER("bdev_nvme_get_path_iostat", rpc_bdev_nvme_get_path_iostat,
2701 : SPDK_RPC_RUNTIME)
|