Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include "spdk/stdinc.h"
7 : : #include "spdk/nvme.h"
8 : : #include "spdk/env.h"
9 : : #include "spdk/util.h"
10 : :
11 : : #define MAX_FDP_EVENTS 0xFF
12 : :
13 : : #define SET_EVENT_TYPES ((uint8_t[]){0x0, 0x1, 0x2, 0x3, 0x80, 0x81})
14 : :
15 : : struct ns_entry {
16 : : struct spdk_nvme_ctrlr *ctrlr;
17 : : struct spdk_nvme_ns *ns;
18 : : struct ns_entry *next;
19 : : };
20 : :
21 : : static struct ns_entry *g_namespaces = NULL;
22 : : static struct spdk_nvme_transport_id g_trid;
23 : : static bool g_use_trid = false;
24 : :
25 : : static int g_outstanding_commands;
26 : : static int g_fdp_command_result;
27 : : static uint32_t g_feat_result;
28 : : static uint16_t ph_for_fdp_event;
29 : : static uint8_t rgif;
30 : : static uint8_t fdpci;
31 : : static uint16_t pid_for_ruhu;
32 : : static uint32_t g_spdk_sge_size = 4096;
33 : :
34 : : static union spdk_nvme_feat_fdp_cdw12 fdp_res;
35 : :
36 : : struct io_request {
37 : : void *contig;
38 : : uint32_t sgl_offset;
39 : : uint32_t buf_size;
40 : : };
41 : :
42 : : static void
43 : 2 : nvme_req_reset_sgl(void *cb_arg, uint32_t sgl_offset)
44 : : {
45 : 2 : struct io_request *req = (struct io_request *)cb_arg;
46 : :
47 : 2 : req->sgl_offset = sgl_offset;
48 : 2 : }
49 : :
50 : : static int
51 : 16 : nvme_req_next_sge(void *cb_arg, void **address, uint32_t *length)
52 : : {
53 : 16 : struct io_request *req = (struct io_request *)cb_arg;
54 : : uint32_t iov_len;
55 : :
56 : 16 : *address = req->contig;
57 : :
58 [ + + ]: 16 : if (req->sgl_offset) {
59 : 14 : *address += req->sgl_offset;
60 : : }
61 : :
62 : 16 : iov_len = req->buf_size - req->sgl_offset;
63 [ + + ]: 16 : if (iov_len > g_spdk_sge_size) {
64 : 14 : iov_len = g_spdk_sge_size;
65 : : }
66 : :
67 : 16 : req->sgl_offset += iov_len;
68 : 16 : *length = iov_len;
69 : :
70 : 16 : return 0;
71 : : }
72 : :
73 : : static void
74 : 3 : get_feat_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
75 : : {
76 [ + - - + ]: 3 : if (spdk_nvme_cpl_is_error(cpl)) {
77 : 0 : g_fdp_command_result = -1;
78 : : } else {
79 : 3 : g_fdp_command_result = 0;
80 : 3 : g_feat_result = cpl->cdw0;
81 : : }
82 : :
83 : 3 : g_outstanding_commands--;
84 : 3 : }
85 : :
86 : : static void
87 : 11 : cmd_completion(void *cb_arg, const struct spdk_nvme_cpl *cpl)
88 : : {
89 [ + - - + ]: 11 : if (spdk_nvme_cpl_is_error(cpl)) {
90 : 0 : g_fdp_command_result = -1;
91 : : } else {
92 : 11 : g_fdp_command_result = 0;
93 : : }
94 : :
95 : 11 : g_outstanding_commands--;
96 : 11 : }
97 : :
98 : : static void
99 : 0 : print_uint128_hex(uint64_t *v)
100 : : {
101 : 0 : unsigned long long lo = v[0], hi = v[1];
102 [ # # ]: 0 : if (hi) {
103 [ # # ]: 0 : printf("0x%llX%016llX", hi, lo);
104 : : } else {
105 [ # # ]: 0 : printf("0x%llX", lo);
106 : : }
107 : 0 : }
108 : :
109 : : static void
110 : 3 : print_uint128_dec(uint64_t *v)
111 : : {
112 : 3 : unsigned long long lo = v[0], hi = v[1];
113 [ - + ]: 3 : if (hi) {
114 : : /* can't handle large (>64-bit) decimal values for now, so fall back to hex */
115 : 0 : print_uint128_hex(v);
116 : : } else {
117 [ - + ]: 3 : printf("%llu", (unsigned long long)lo);
118 : : }
119 : 3 : }
120 : :
121 : : static int
122 : 1 : set_fdp_events(struct spdk_nvme_ns *ns)
123 : : {
124 : : int ret;
125 : 1 : uint8_t fdp_event_type_list[6] = {};
126 : 1 : uint32_t nfdp_events = 6;
127 : : uint32_t cdw11, cdw12;
128 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
129 : 1 : int nsid = spdk_nvme_ns_get_id(ns);
130 : :
131 [ - + - + ]: 1 : memcpy(fdp_event_type_list, SET_EVENT_TYPES, nfdp_events);
132 : 1 : g_outstanding_commands = 0;
133 : 1 : g_fdp_command_result = -1;
134 : :
135 : 1 : cdw11 = (nfdp_events << 16) | ph_for_fdp_event;
136 : : /* Enable FDP event */
137 : 1 : cdw12 = 1;
138 : :
139 : 1 : ret = spdk_nvme_ctrlr_cmd_set_feature_ns(ctrlr, SPDK_NVME_FEAT_FDP_EVENTS, cdw11, cdw12,
140 : : fdp_event_type_list, nfdp_events,
141 : : get_feat_completion, NULL, nsid);
142 [ - + ]: 1 : if (ret) {
143 [ # # # # ]: 0 : fprintf(stderr, "Set Feature (fdp events) failed\n\n");
144 : 0 : return -1;
145 : : }
146 : :
147 : 1 : g_outstanding_commands++;
148 [ + + ]: 11 : while (g_outstanding_commands) {
149 : 10 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
150 : : }
151 : :
152 [ - + ]: 1 : if (g_fdp_command_result) {
153 [ # # # # ]: 0 : fprintf(stderr, "Set Feature (fdp events) failed\n\n");
154 : 0 : return -1;
155 : : }
156 : :
157 [ - + - + ]: 1 : fprintf(stdout, "Set Feature: Enabling FDP events on Placement handle: #%u Success\n\n",
158 : : ph_for_fdp_event);
159 : 1 : return 0;
160 : : }
161 : :
162 : : static int
163 : 1 : get_fdp_events(struct spdk_nvme_ns *ns)
164 : : {
165 : : int ret;
166 : : uint32_t i, cdw11;
167 : 1 : struct spdk_nvme_fdp_event_desc events[MAX_FDP_EVENTS];
168 : : struct spdk_nvme_fdp_event_desc *event_desc;
169 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
170 : 1 : int nsid = spdk_nvme_ns_get_id(ns);
171 : :
172 : 1 : g_outstanding_commands = 0;
173 : 1 : g_fdp_command_result = -1;
174 : 1 : g_feat_result = 0;
175 : :
176 : 1 : cdw11 = (MAX_FDP_EVENTS << 16) | ph_for_fdp_event;
177 : :
178 : 1 : ret = spdk_nvme_ctrlr_cmd_get_feature_ns(ctrlr, SPDK_NVME_FEAT_FDP_EVENTS, cdw11,
179 : : events, MAX_FDP_EVENTS * sizeof(struct spdk_nvme_fdp_event_desc),
180 : : get_feat_completion, NULL, nsid);
181 [ - + ]: 1 : if (ret) {
182 [ # # # # ]: 0 : fprintf(stderr, "Get Feature (fdp events) failed\n\n");
183 : 0 : return -1;
184 : : }
185 : :
186 : 1 : g_outstanding_commands++;
187 [ + + ]: 4 : while (g_outstanding_commands) {
188 : 3 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
189 : : }
190 : :
191 [ - + ]: 1 : if (g_fdp_command_result) {
192 [ # # # # ]: 0 : fprintf(stderr, "Get Feature (fdp events) failed\n\n");
193 : 0 : return -1;
194 : : }
195 : :
196 [ - + - + ]: 1 : fprintf(stdout, "Get Feature: FDP Events for Placement handle: #%u\n", ph_for_fdp_event);
197 [ - + - + ]: 1 : fprintf(stdout, "========================\n");
198 [ - + - + ]: 1 : fprintf(stdout, "Number of FDP Events: %u\n", g_feat_result);
199 : :
200 : 1 : event_desc = events;
201 [ + + ]: 7 : for (i = 0; i < g_feat_result; i++) {
202 [ - + - + ]: 6 : fprintf(stdout, "FDP Event: #%u Type: %s", i,
203 [ + + ]: 6 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_RU_NOT_WRITTEN_CAPACITY ?
204 : : "RU Not Written to Capacity " :
205 : 5 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_RU_TIME_LIMIT_EXCEEDED ?
206 [ + + ]: 9 : "RU Time Limit Exceeded " :
207 : 4 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_CTRLR_RESET_MODIFY_RUH ?
208 [ + + ]: 7 : "Ctrlr Reset Modified RUH's " :
209 : 3 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_INVALID_PLACEMENT_ID ?
210 [ + + ]: 5 : "Invalid Placement Identifier " :
211 [ + + ]: 3 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_MEDIA_REALLOCATED ? "Media Reallocated " :
212 : 1 : event_desc->fdp_etype == SPDK_NVME_FDP_EVENT_IMPLICIT_MODIFIED_RUH ?
213 [ + - ]: 1 : "Implicitly modified RUH " :
214 : : "Reserved");
215 [ - + - + ]: 6 : fprintf(stdout, " Enabled: %s\n",
216 [ + + ]: 6 : event_desc->fdpeta.bits.fdp_ee ? "Yes" : "No");
217 : 6 : event_desc++;
218 : : }
219 : :
220 [ - + ]: 1 : fprintf(stdout, "\n");
221 : 1 : return 0;
222 : : }
223 : :
224 : : static int
225 : 1 : get_fdp(struct spdk_nvme_ns *ns)
226 : : {
227 : : int ret;
228 : : uint32_t cdw11;
229 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
230 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
231 : :
232 : 1 : g_outstanding_commands = 0;
233 : 1 : g_fdp_command_result = -1;
234 : 1 : g_feat_result = 0;
235 : :
236 : 1 : cdw11 = nsdata->endgid;
237 : :
238 : 1 : ret = spdk_nvme_ctrlr_cmd_get_feature(ctrlr, SPDK_NVME_FEAT_FDP, cdw11, NULL, 0,
239 : : get_feat_completion, NULL);
240 [ - + ]: 1 : if (ret) {
241 [ # # # # ]: 0 : fprintf(stderr, "Get Feature (fdp) failed\n\n");
242 : 0 : return -1;
243 : : }
244 : :
245 : 1 : g_outstanding_commands++;
246 [ + + ]: 4 : while (g_outstanding_commands) {
247 : 3 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
248 : : }
249 : :
250 [ - + ]: 1 : if (g_fdp_command_result) {
251 [ # # # # ]: 0 : fprintf(stderr, "Get Feature (fdp) failed\n\n");
252 : 0 : return -1;
253 : : }
254 : :
255 : 1 : fdp_res.raw = g_feat_result;
256 : :
257 [ - + - + ]: 1 : fprintf(stdout, "Get Feature: FDP:\n");
258 [ - + - + ]: 1 : fprintf(stdout, "=================\n");
259 [ - + - + ]: 1 : fprintf(stdout, " Enabled: %s\n",
260 [ + - ]: 1 : fdp_res.bits.fdpe ? "Yes" : "No");
261 [ - + - + ]: 1 : fprintf(stdout, " FDP configuration Index: %u\n\n", fdp_res.bits.fdpci);
262 : :
263 : 1 : return 0;
264 : : }
265 : :
266 : : static int
267 : 1 : check_fdp_write(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair)
268 : : {
269 : : int ret;
270 : : uint32_t sector_size, lba_count;
271 : : uint64_t lba;
272 : : struct io_request *req;
273 : 1 : struct spdk_nvme_ns_cmd_ext_io_opts ext_opts;
274 : :
275 : 1 : g_outstanding_commands = 0;
276 : 1 : g_fdp_command_result = -1;
277 : :
278 : 1 : ext_opts.size = SPDK_SIZEOF(&ext_opts, cdw13);
279 : 1 : ext_opts.io_flags = SPDK_NVME_IO_FLAGS_DATA_PLACEMENT_DIRECTIVE;
280 : 1 : ext_opts.metadata = NULL;
281 [ - + ]: 1 : ext_opts.cdw13 = (pid_for_ruhu << 16);
282 : :
283 : 1 : sector_size = spdk_nvme_ns_get_sector_size(ns);
284 : :
285 : 1 : req = spdk_zmalloc(sizeof(*req), 0, NULL, SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
286 [ - + ]: 1 : assert(req);
287 : :
288 : 1 : lba = 0;
289 : 1 : lba_count = 8;
290 : 1 : req->buf_size = sector_size * lba_count;
291 : 1 : req->contig = spdk_zmalloc(req->buf_size, 0x1000, NULL, SPDK_ENV_LCORE_ID_ANY,
292 : : SPDK_MALLOC_DMA);
293 [ - + ]: 1 : assert(req->contig);
294 : :
295 : 1 : ret = spdk_nvme_ns_cmd_writev_ext(ns, qpair, lba, lba_count, cmd_completion, req,
296 : : nvme_req_reset_sgl, nvme_req_next_sge, &ext_opts);
297 : :
298 [ - + ]: 1 : if (ret) {
299 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ns_cmd_writev_ext failed\n\n");
300 : 0 : spdk_free(req->contig);
301 : 0 : spdk_free(req);
302 : 0 : return -1;
303 : : }
304 : :
305 : 1 : g_outstanding_commands++;
306 [ + + ]: 204 : while (g_outstanding_commands) {
307 : 203 : spdk_nvme_qpair_process_completions(qpair, 100);
308 : : }
309 : :
310 [ - + ]: 1 : if (g_fdp_command_result) {
311 [ # # # # ]: 0 : fprintf(stderr, "FDP write on placement id: %u failed\n\n", pid_for_ruhu);
312 : : } else {
313 [ - + - + ]: 1 : fprintf(stdout, "FDP write on placement id: %u success\n\n", pid_for_ruhu);
314 : : }
315 : :
316 : 1 : spdk_free(req->contig);
317 : 1 : spdk_free(req);
318 : 1 : return g_fdp_command_result;
319 : : }
320 : :
321 : : static int
322 : 1 : reclaim_unit_handle_update(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair)
323 : : {
324 : : int ret;
325 : 1 : uint32_t npids = 1;
326 : 1 : uint16_t pid_list[1] = {};
327 : :
328 : 1 : memcpy(pid_list, &pid_for_ruhu, sizeof(pid_list));
329 : 1 : g_outstanding_commands = 0;
330 : 1 : g_fdp_command_result = -1;
331 : :
332 : 1 : ret = spdk_nvme_ns_cmd_io_mgmt_send(ns, qpair, pid_list, npids * sizeof(uint16_t),
333 : 1 : SPDK_NVME_FDP_IO_MGMT_SEND_RUHU, npids - 1, cmd_completion, NULL);
334 [ - + ]: 1 : if (ret) {
335 [ # # # # ]: 0 : fprintf(stderr, "IO management send: RUH update failed\n\n");
336 : 0 : return -1;
337 : : }
338 : :
339 : 1 : g_outstanding_commands++;
340 [ + + ]: 13 : while (g_outstanding_commands) {
341 : 12 : spdk_nvme_qpair_process_completions(qpair, 100);
342 : : }
343 : :
344 [ - + ]: 1 : if (g_fdp_command_result) {
345 [ # # # # ]: 0 : fprintf(stderr, "IO management send: RUH update failed\n\n");
346 : 0 : return -1;
347 : : }
348 : :
349 [ - + - + ]: 1 : fprintf(stdout, "IO mgmt send: RUH update for Placement ID: #%u Success\n\n",
350 : : pid_for_ruhu);
351 : 1 : return 0;
352 : : }
353 : :
354 : : static int
355 : 1 : reclaim_unit_handle_status(struct spdk_nvme_ns *ns, struct spdk_nvme_qpair *qpair)
356 : : {
357 : : int ret;
358 : : uint32_t i;
359 : : size_t fdp_ruhs_size;
360 : : struct spdk_nvme_fdp_ruhs *fdp_ruhs;
361 : : struct spdk_nvme_fdp_ruhs_desc *ruhs_desc;
362 : :
363 : 1 : g_outstanding_commands = 0;
364 : 1 : g_fdp_command_result = -1;
365 : :
366 : 1 : fdp_ruhs_size = sizeof(struct spdk_nvme_fdp_ruhs);
367 : 1 : fdp_ruhs = calloc(1, fdp_ruhs_size);
368 [ - + ]: 1 : if (!fdp_ruhs) {
369 [ # # # # ]: 0 : fprintf(stderr, "FDP reclaim unit handle status allocation failed!\n\n");
370 : 0 : return -1;
371 : : }
372 : :
373 : : /* Fetch the reclaim unit handle status header */
374 : 1 : ret = spdk_nvme_ns_cmd_io_mgmt_recv(ns, qpair, fdp_ruhs, fdp_ruhs_size,
375 : : SPDK_NVME_FDP_IO_MGMT_RECV_RUHS, 0, cmd_completion, NULL);
376 [ - + ]: 1 : if (ret) {
377 [ # # # # ]: 0 : fprintf(stderr, "IO management receive: RUH status failed\n\n");
378 : 0 : free(fdp_ruhs);
379 : 0 : return -1;
380 : : }
381 : :
382 : 1 : g_outstanding_commands++;
383 [ + + ]: 10 : while (g_outstanding_commands) {
384 : 9 : spdk_nvme_qpair_process_completions(qpair, 100);
385 : : }
386 : :
387 [ - + ]: 1 : if (g_fdp_command_result) {
388 [ # # # # ]: 0 : fprintf(stderr, "IO management receive: RUH status failed\n\n");
389 : 0 : free(fdp_ruhs);
390 : 0 : return -1;
391 : : }
392 : :
393 : 1 : fdp_ruhs_size += fdp_ruhs->nruhsd * sizeof(struct spdk_nvme_fdp_ruhs_desc);
394 : 1 : fdp_ruhs = realloc(fdp_ruhs, fdp_ruhs_size);
395 [ - + ]: 1 : if (!fdp_ruhs) {
396 [ # # # # ]: 0 : fprintf(stderr, "FDP reclaim unit handle status buffer reallocation failed!\n\n");
397 : 0 : return -1;
398 : : }
399 : :
400 : 1 : ret = spdk_nvme_ns_cmd_io_mgmt_recv(ns, qpair, fdp_ruhs, fdp_ruhs_size,
401 : : SPDK_NVME_FDP_IO_MGMT_RECV_RUHS, 0, cmd_completion, NULL);
402 [ - + ]: 1 : if (ret) {
403 [ # # # # ]: 0 : fprintf(stderr, "IO management receive: RUH status failed\n\n");
404 : 0 : free(fdp_ruhs);
405 : 0 : return -1;
406 : : }
407 : :
408 : 1 : g_outstanding_commands++;
409 [ + + ]: 9 : while (g_outstanding_commands) {
410 : 8 : spdk_nvme_qpair_process_completions(qpair, 100);
411 : : }
412 : :
413 [ - + ]: 1 : if (g_fdp_command_result) {
414 [ # # # # ]: 0 : fprintf(stderr, "IO management receive: RUH status failed\n\n");
415 : 0 : free(fdp_ruhs);
416 : 0 : return -1;
417 : : }
418 : :
419 [ - + - + ]: 1 : fprintf(stdout, "FDP Reclaim unit handle status\n");
420 [ - + - + ]: 1 : fprintf(stdout, "==============================\n");
421 : :
422 [ - + - + ]: 1 : fprintf(stdout, "Number of RUHS descriptors: %u\n", fdp_ruhs->nruhsd);
423 [ + + ]: 3 : for (i = 0; i < fdp_ruhs->nruhsd; i++) {
424 : 2 : ruhs_desc = &fdp_ruhs->ruhs_desc[i];
425 : :
426 [ - + ]: 4 : fprintf(stdout,
427 : : "RUHS Desc: #%04u PID: 0x%04x RUHID: 0x%04x ERUT: 0x%08x RUAMW: 0x%016"PRIx64"\n",
428 [ - + ]: 2 : i, ruhs_desc->pid, ruhs_desc->ruhid, ruhs_desc->earutr, ruhs_desc->ruamw);
429 : : }
430 [ - + ]: 1 : fprintf(stdout, "\n");
431 : :
432 : : /* Use this Placement Identifier for Reclaim unit handle Update */
433 : 1 : pid_for_ruhu = (&fdp_ruhs->ruhs_desc[0])->pid;
434 : :
435 : : /* Use this Placement Handle to enable FDP events */
436 [ - + ]: 1 : ph_for_fdp_event = pid_for_ruhu & ((1 << (16 - rgif)) - 1);
437 : :
438 : 1 : free(fdp_ruhs);
439 : 1 : return 0;
440 : : }
441 : :
442 : : static int
443 : 1 : get_fdp_cfg_log_page(struct spdk_nvme_ns *ns)
444 : : {
445 : : uint32_t i, j;
446 : : size_t fdp_cfg_size;
447 : : struct spdk_nvme_fdp_cfg_log_page *fdp_cfg_log_page;
448 : : struct spdk_nvme_fdp_cfg_descriptor *cfg_desc;
449 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
450 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
451 : : void *log;
452 : :
453 : 1 : g_outstanding_commands = 0;
454 : 1 : g_fdp_command_result = -1;
455 : :
456 : 1 : fdp_cfg_size = sizeof(struct spdk_nvme_fdp_cfg_log_page);
457 : 1 : fdp_cfg_log_page = calloc(1, fdp_cfg_size);
458 [ - + ]: 1 : if (!fdp_cfg_log_page) {
459 [ # # # # ]: 0 : fprintf(stderr, "FDP config log page allocation failed!\n\n");
460 : 0 : return -1;
461 : : }
462 : :
463 : : /* Fetch the FDP configurations log page header */
464 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_CONFIGURATIONS, 0,
465 [ - + ]: 1 : fdp_cfg_log_page, fdp_cfg_size, 0, 0, (nsdata->endgid << 16),
466 : : 0, cmd_completion, NULL) == 0) {
467 : 1 : g_outstanding_commands++;
468 : : } else {
469 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP config) failed\n\n");
470 : 0 : free(fdp_cfg_log_page);
471 : 0 : return -1;
472 : : }
473 : :
474 [ + + ]: 3 : while (g_outstanding_commands) {
475 : 2 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
476 : : }
477 : :
478 [ - + ]: 1 : if (g_fdp_command_result) {
479 [ # # # # ]: 0 : fprintf(stderr, "Failed to get FDP configuration log page\n\n");
480 : 0 : free(fdp_cfg_log_page);
481 : 0 : return -1;
482 : : }
483 : :
484 : 1 : fdp_cfg_size = fdp_cfg_log_page->size;
485 : 1 : fdp_cfg_log_page = realloc(fdp_cfg_log_page, fdp_cfg_size);
486 [ - + ]: 1 : if (!fdp_cfg_log_page) {
487 [ # # # # ]: 0 : fprintf(stderr, "FDP config log page reallocation failed!\n\n");
488 : 0 : return -1;
489 : : }
490 : :
491 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_CONFIGURATIONS, 0,
492 [ - + ]: 1 : fdp_cfg_log_page, fdp_cfg_size, 0, 0, (nsdata->endgid << 16),
493 : : 0, cmd_completion, NULL) == 0) {
494 : 1 : g_outstanding_commands++;
495 : : } else {
496 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP config) failed\n\n");
497 : 0 : free(fdp_cfg_log_page);
498 : 0 : return -1;
499 : : }
500 : :
501 [ + + ]: 3 : while (g_outstanding_commands) {
502 : 2 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
503 : : }
504 : :
505 [ - + ]: 1 : if (g_fdp_command_result) {
506 [ # # # # ]: 0 : fprintf(stderr, "Failed to get FDP configuration log page\n\n");
507 : 0 : free(fdp_cfg_log_page);
508 : 0 : return -1;
509 : : }
510 : :
511 [ - + - + ]: 1 : fprintf(stdout, "FDP configurations log page\n");
512 [ - + - + ]: 1 : fprintf(stdout, "===========================\n");
513 : :
514 [ - + - + ]: 1 : fprintf(stdout, "Number of FDP configurations: %u\n", fdp_cfg_log_page->ncfg + 1);
515 [ - + - + ]: 1 : fprintf(stdout, "Version: %u\n", fdp_cfg_log_page->version);
516 [ - + - + ]: 1 : fprintf(stdout, "Size: %u\n", fdp_cfg_log_page->size);
517 : :
518 : 1 : log = fdp_cfg_log_page->cfg_desc;
519 [ + + ]: 2 : for (i = 0; i <= fdp_cfg_log_page->ncfg; i++) {
520 : 1 : cfg_desc = log;
521 [ - + - + ]: 1 : fprintf(stdout, "FDP Configuration Descriptor: %u\n", i);
522 [ - + - + ]: 1 : fprintf(stdout, " Descriptor Size: %u\n", cfg_desc->ds);
523 [ - + ]: 1 : fprintf(stdout, " Reclaim Group Identifier format: %u\n",
524 [ - + ]: 1 : cfg_desc->fdpa.bits.rgif);
525 [ - + - + ]: 1 : fprintf(stdout, " FDP Volatile Write Cache: %s\n",
526 [ - + ]: 1 : cfg_desc->fdpa.bits.fdpvwc ? "Present" : "Not Present");
527 [ - + - + ]: 1 : fprintf(stdout, " FDP Configuration: %s\n",
528 [ + - ]: 1 : cfg_desc->fdpa.bits.fdpcv ? "Valid" : "Invalid");
529 [ - + - + ]: 1 : fprintf(stdout, " Vendor Specific Size: %u\n", cfg_desc->vss);
530 [ - + - + ]: 1 : fprintf(stdout, " Number of Reclaim Groups: %u\n", cfg_desc->nrg);
531 [ - + - + ]: 1 : fprintf(stdout, " Number of Recalim Unit Handles: %u\n", cfg_desc->nruh);
532 [ - + - + ]: 1 : fprintf(stdout, " Max Placement Identifiers: %u\n", cfg_desc->maxpids + 1);
533 [ - + - + ]: 1 : fprintf(stdout, " Number of Namespaces Suppprted: %u\n", cfg_desc->nns);
534 [ - + - + ]: 1 : fprintf(stdout, " Reclaim unit Nominal Size: %" PRIx64 " bytes\n", cfg_desc->runs);
535 [ - + - + ]: 1 : fprintf(stdout, " Estimated Reclaim Unit Time Limit: ");
536 [ - + ]: 1 : if (cfg_desc->erutl) {
537 [ # # # # ]: 0 : fprintf(stdout, "%u seconds\n", cfg_desc->erutl);
538 : : } else {
539 [ - + - + ]: 1 : fprintf(stdout, "Not Reported\n");
540 : : }
541 [ + + ]: 9 : for (j = 0; j < cfg_desc->nruh; j++) {
542 [ - + - + ]: 8 : fprintf(stdout, " RUH Desc #%03d: RUH Type: %s\n", j,
543 [ - + ]: 8 : cfg_desc->ruh_desc[j].ruht == SPDK_NVME_FDP_RUHT_INITIALLY_ISOLATED ? "Initially Isolated" :
544 [ # # ]: 0 : cfg_desc->ruh_desc[j].ruht == SPDK_NVME_FDP_RUHT_PERSISTENTLY_ISOLATED ? "Persistently Isolated" :
545 : : "Reserved");
546 : : }
547 [ + - ]: 1 : if (i == fdpci) {
548 : 1 : rgif = cfg_desc->fdpa.bits.rgif;
549 : : }
550 : 1 : log += cfg_desc->ds;
551 : : }
552 : :
553 [ - + ]: 1 : fprintf(stdout, "\n");
554 : 1 : free(fdp_cfg_log_page);
555 : :
556 : 1 : return 0;
557 : : }
558 : :
559 : : static int
560 : 1 : get_fdp_ruhu_log_page(struct spdk_nvme_ns *ns)
561 : : {
562 : : uint32_t i;
563 : : size_t fdp_ruhu_size;
564 : : struct spdk_nvme_fdp_ruhu_log_page *fdp_ruhu_log_page;
565 : : struct spdk_nvme_fdp_ruhu_descriptor *ruhu_desc;
566 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
567 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
568 : :
569 : 1 : g_outstanding_commands = 0;
570 : 1 : g_fdp_command_result = -1;
571 : :
572 : 1 : fdp_ruhu_size = sizeof(struct spdk_nvme_fdp_ruhu_log_page);
573 : 1 : fdp_ruhu_log_page = calloc(1, fdp_ruhu_size);
574 [ - + ]: 1 : if (!fdp_ruhu_log_page) {
575 [ # # # # ]: 0 : fprintf(stderr, "FDP Reclaim Unit Handle usage log page allocation failed!\n\n");
576 : 0 : return -1;
577 : : }
578 : :
579 : : /* Fetch the FDP RUH usage log page header */
580 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_RECLAIM_UNIT_HANDLE_USAGE, 0,
581 [ - + ]: 1 : fdp_ruhu_log_page, fdp_ruhu_size, 0, 0, (nsdata->endgid << 16),
582 : : 0, cmd_completion, NULL) == 0) {
583 : 1 : g_outstanding_commands++;
584 : : } else {
585 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(RUH usage) failed\n\n");
586 : 0 : free(fdp_ruhu_log_page);
587 : 0 : return -1;
588 : : }
589 : :
590 [ + + ]: 3 : while (g_outstanding_commands) {
591 : 2 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
592 : : }
593 : :
594 [ - + ]: 1 : if (g_fdp_command_result) {
595 [ # # # # ]: 0 : fprintf(stderr, "Failed to get Reclaim Unit Handle usage log page\n\n");
596 : 0 : free(fdp_ruhu_log_page);
597 : 0 : return -1;
598 : : }
599 : :
600 : 1 : fdp_ruhu_size += fdp_ruhu_log_page->nruh * sizeof(struct spdk_nvme_fdp_ruhu_descriptor);
601 : 1 : fdp_ruhu_log_page = realloc(fdp_ruhu_log_page, fdp_ruhu_size);
602 [ - + ]: 1 : if (!fdp_ruhu_log_page) {
603 [ # # # # ]: 0 : fprintf(stderr, "FDP Reclaim Unit Handle usage log page reallocation failed!\n\n");
604 : 0 : return -1;
605 : : }
606 : :
607 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_RECLAIM_UNIT_HANDLE_USAGE, 0,
608 [ - + ]: 1 : fdp_ruhu_log_page, fdp_ruhu_size, 0, 0, (nsdata->endgid << 16),
609 : : 0, cmd_completion, NULL) == 0) {
610 : 1 : g_outstanding_commands++;
611 : : } else {
612 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(RUH usage) failed\n\n");
613 : 0 : free(fdp_ruhu_log_page);
614 : 0 : return -1;
615 : : }
616 : :
617 [ + + ]: 3 : while (g_outstanding_commands) {
618 : 2 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
619 : : }
620 : :
621 [ - + ]: 1 : if (g_fdp_command_result) {
622 [ # # # # ]: 0 : fprintf(stderr, "Failed to get Reclaim Unit Handle usage log page\n\n");
623 : 0 : free(fdp_ruhu_log_page);
624 : 0 : return -1;
625 : : }
626 : :
627 [ - + - + ]: 1 : fprintf(stdout, "FDP reclaim unit handle usage log page\n");
628 [ - + - + ]: 1 : fprintf(stdout, "======================================\n");
629 : :
630 [ - + - + ]: 1 : fprintf(stdout, "Number of Reclaim Unit Handles: %u\n", fdp_ruhu_log_page->nruh);
631 : :
632 [ + + ]: 9 : for (i = 0; i < fdp_ruhu_log_page->nruh; i++) {
633 : 8 : ruhu_desc = &fdp_ruhu_log_page->ruhu_desc[i];
634 : :
635 [ - + - + ]: 8 : fprintf(stdout, " RUH Usage Desc #%03d: RUH Attributes: %s\n", i,
636 [ + + ]: 8 : ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_UNUSED ? "Unused" :
637 [ + - ]: 2 : ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_HOST_SPECIFIED ? "Host Specified" :
638 [ + - ]: 1 : ruhu_desc->ruha == SPDK_NVME_FDP_RUHA_CTRLR_SPECIFIED ? "Controller Specified" :
639 : : "Reserved");
640 : : }
641 : :
642 [ - + ]: 1 : fprintf(stdout, "\n");
643 : 1 : free(fdp_ruhu_log_page);
644 : :
645 : 1 : return 0;
646 : : }
647 : :
648 : : static int
649 : 1 : get_fdp_stats_log_page(struct spdk_nvme_ns *ns)
650 : : {
651 : 1 : struct spdk_nvme_fdp_stats_log_page fdp_stats_log_page;
652 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
653 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
654 : :
655 : 1 : g_outstanding_commands = 0;
656 : 1 : g_fdp_command_result = -1;
657 : :
658 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_STATISTICS, 0,
659 [ - + ]: 1 : &fdp_stats_log_page, 64, 0, 0, (nsdata->endgid << 16), 0,
660 : : cmd_completion, NULL) == 0) {
661 : 1 : g_outstanding_commands++;
662 : : } else {
663 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP stats) failed\n\n");
664 : 0 : return -1;
665 : : }
666 : :
667 [ + + ]: 3 : while (g_outstanding_commands) {
668 : 2 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
669 : : }
670 : :
671 [ - + ]: 1 : if (g_fdp_command_result) {
672 [ # # # # ]: 0 : fprintf(stderr, "Failed to get FDP statistics log page\n\n");
673 : 0 : return -1;
674 : : }
675 : :
676 [ - + - + ]: 1 : fprintf(stdout, "FDP statistics log page\n");
677 [ - + - + ]: 1 : fprintf(stdout, "=======================\n");
678 : :
679 [ - + - + ]: 1 : fprintf(stdout, "Host bytes with metadata written: ");
680 : 1 : print_uint128_dec(fdp_stats_log_page.hbmw);
681 [ - + ]: 1 : fprintf(stdout, "\n");
682 [ - + - + ]: 1 : fprintf(stdout, "Media bytes with metadata written: ");
683 : 1 : print_uint128_dec(fdp_stats_log_page.mbmw);
684 [ - + ]: 1 : fprintf(stdout, "\n");
685 [ - + - + ]: 1 : fprintf(stdout, "Media bytes erased: ");
686 : 1 : print_uint128_dec(fdp_stats_log_page.mbe);
687 [ - + - + ]: 1 : fprintf(stdout, "\n\n");
688 : :
689 : 1 : return 0;
690 : : }
691 : :
692 : : static int
693 : 1 : get_fdp_events_log_page(struct spdk_nvme_ns *ns)
694 : : {
695 : : uint32_t i;
696 : : size_t fdp_event_size;
697 : : struct spdk_nvme_fdp_events_log_page *fdp_events_log_page;
698 : : struct spdk_nvme_fdp_event *event;
699 : : struct spdk_nvme_fdp_event_media_reallocated *media_reallocated;
700 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
701 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
702 : :
703 : 1 : g_outstanding_commands = 0;
704 : 1 : g_fdp_command_result = -1;
705 : :
706 : 1 : fdp_event_size = sizeof(struct spdk_nvme_fdp_events_log_page);
707 : 1 : fdp_events_log_page = calloc(1, fdp_event_size);
708 [ - + ]: 1 : if (!fdp_events_log_page) {
709 [ # # # # ]: 0 : fprintf(stderr, "FDP events log page allocation failed!\n\n");
710 : 0 : return -1;
711 : : }
712 : :
713 : : /* Fetch the FDP events log page header */
714 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_EVENTS, 0,
715 : : fdp_events_log_page, fdp_event_size, 0,
716 [ - + ]: 1 : (SPDK_NVME_FDP_REPORT_HOST_EVENTS << 8), (nsdata->endgid << 16),
717 : : 0, cmd_completion, NULL) == 0) {
718 : 1 : g_outstanding_commands++;
719 : : } else {
720 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP events) failed\n\n");
721 : 0 : free(fdp_events_log_page);
722 : 0 : return -1;
723 : : }
724 : :
725 [ + + ]: 4 : while (g_outstanding_commands) {
726 : 3 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
727 : : }
728 : :
729 [ - + ]: 1 : if (g_fdp_command_result) {
730 [ # # # # ]: 0 : fprintf(stderr, "Failed to get eventss log page\n\n");
731 : 0 : free(fdp_events_log_page);
732 : 0 : return -1;
733 : : }
734 : :
735 : 1 : fdp_event_size += fdp_events_log_page->nevents * sizeof(struct spdk_nvme_fdp_event);
736 : 1 : fdp_events_log_page = realloc(fdp_events_log_page, fdp_event_size);
737 [ - + ]: 1 : if (!fdp_events_log_page) {
738 [ # # # # ]: 0 : fprintf(stderr, "FDP events log page reallocation failed!\n\n");
739 : 0 : return -1;
740 : : }
741 : :
742 : : /* Only fetch FDP host events here */
743 [ + - ]: 1 : if (spdk_nvme_ctrlr_cmd_get_log_page_ext(ctrlr, SPDK_NVME_LOG_FDP_EVENTS, 0,
744 : : fdp_events_log_page, fdp_event_size, 0,
745 [ - + ]: 1 : (SPDK_NVME_FDP_REPORT_HOST_EVENTS << 8), (nsdata->endgid << 16),
746 : : 0, cmd_completion, NULL) == 0) {
747 : 1 : g_outstanding_commands++;
748 : : } else {
749 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_cmd_get_log_page_ext(FDP events) failed\n\n");
750 : 0 : free(fdp_events_log_page);
751 : 0 : return -1;
752 : : }
753 : :
754 [ + + ]: 4 : while (g_outstanding_commands) {
755 : 3 : spdk_nvme_ctrlr_process_admin_completions(ctrlr);
756 : : }
757 : :
758 [ - + ]: 1 : if (g_fdp_command_result) {
759 [ # # # # ]: 0 : fprintf(stderr, "Failed to get eventss log page\n\n");
760 : 0 : free(fdp_events_log_page);
761 : 0 : return -1;
762 : : }
763 : :
764 [ - + - + ]: 1 : fprintf(stdout, "FDP events log page\n");
765 [ - + - + ]: 1 : fprintf(stdout, "===================\n");
766 [ - + - + ]: 1 : fprintf(stdout, "Number of FDP events: %u\n", fdp_events_log_page->nevents);
767 : :
768 [ + + ]: 2 : for (i = 0; i < fdp_events_log_page->nevents; i++) {
769 : 1 : event = &fdp_events_log_page->event[i];
770 : :
771 [ - + - + ]: 1 : fprintf(stdout, "FDP Event #%u:\n", i);
772 [ - + - + ]: 1 : fprintf(stdout, " Event Type: %s\n",
773 [ - + ]: 1 : event->etype == SPDK_NVME_FDP_EVENT_RU_NOT_WRITTEN_CAPACITY ? "RU Not Written to Capacity" :
774 [ # # ]: 0 : event->etype == SPDK_NVME_FDP_EVENT_RU_TIME_LIMIT_EXCEEDED ? "RU Time Limit Exceeded" :
775 [ # # ]: 0 : event->etype == SPDK_NVME_FDP_EVENT_CTRLR_RESET_MODIFY_RUH ? "Ctrlr Reset Modified RUH's" :
776 [ # # ]: 0 : event->etype == SPDK_NVME_FDP_EVENT_INVALID_PLACEMENT_ID ? "Invalid Placement Identifier" :
777 [ # # ]: 0 : event->etype == SPDK_NVME_FDP_EVENT_MEDIA_REALLOCATED ? "Media Reallocated" :
778 [ # # ]: 0 : event->etype == SPDK_NVME_FDP_EVENT_IMPLICIT_MODIFIED_RUH ? "Implicitly modified RUH" :
779 : : "Reserved");
780 [ - + - + ]: 1 : fprintf(stdout, " Placement Identifier: %s\n",
781 [ + - ]: 1 : event->fdpef.bits.piv ? "Valid" : "Invalid");
782 [ - + - + ]: 1 : fprintf(stdout, " NSID: %s\n",
783 [ + - ]: 1 : event->fdpef.bits.nsidv ? "Valid" : "Invalid");
784 [ - + - + ]: 1 : fprintf(stdout, " Location: %s\n",
785 [ + - ]: 1 : event->fdpef.bits.lv ? "Valid" : "Invalid");
786 [ + - ]: 1 : if (event->fdpef.bits.piv) {
787 [ - + - + ]: 1 : fprintf(stdout, " Placement Identifier: %u\n", event->pid);
788 : : } else {
789 [ # # # # ]: 0 : fprintf(stdout, " Placement Identifier: Reserved\n");
790 : : }
791 [ - + - + ]: 1 : fprintf(stdout, " Event Timestamp: %" PRIx64 "\n", event->timestamp);
792 [ + - ]: 1 : if (event->fdpef.bits.nsidv) {
793 [ - + - + ]: 1 : fprintf(stdout, " Namespace Identifier: %u\n", event->nsid);
794 : : } else {
795 [ # # # # ]: 0 : fprintf(stdout, " Namespace Identifier: Ignore\n");
796 : : }
797 : :
798 [ - + ]: 1 : if (event->etype == SPDK_NVME_FDP_EVENT_MEDIA_REALLOCATED) {
799 : 0 : media_reallocated = (struct spdk_nvme_fdp_event_media_reallocated *)&event->event_type_specific;
800 : :
801 [ # # # # ]: 0 : fprintf(stdout, " LBA: %s\n",
802 [ # # ]: 0 : media_reallocated->sef.bits.lbav ? "Valid" : "Invalid");
803 [ # # # # ]: 0 : fprintf(stdout, " Number of LBA's Moved: %u\n", media_reallocated->nlbam);
804 [ # # ]: 0 : if (media_reallocated->sef.bits.lbav) {
805 [ # # # # ]: 0 : fprintf(stdout, " Logical Block Address: %u\n", event->nsid);
806 : : } else {
807 [ # # # # ]: 0 : fprintf(stdout, " Logical Block Address: Ignore\n");
808 : : }
809 : : }
810 : :
811 [ + - ]: 1 : if (event->fdpef.bits.lv) {
812 [ - + - + ]: 1 : fprintf(stdout, " Reclaim Group Identifier: %u\n", event->rgid);
813 : : } else {
814 [ # # # # ]: 0 : fprintf(stdout, " Reclaim Group Identifier: Ignore\n");
815 : : }
816 [ + - ]: 1 : if (event->fdpef.bits.lv) {
817 [ - + - + ]: 1 : fprintf(stdout, " Reclaim Unit Handle Identifier: %u\n", event->ruhid);
818 : : } else {
819 [ # # # # ]: 0 : fprintf(stdout, " Reclaim Unit Handle Identifier: Ignore\n");
820 : : }
821 : : }
822 : :
823 [ - + ]: 1 : fprintf(stdout, "\n");
824 : 1 : free(fdp_events_log_page);
825 : :
826 : 1 : return 0;
827 : : }
828 : :
829 : : static int
830 : 1 : fdp_tests(struct spdk_nvme_ns *ns)
831 : : {
832 : : struct spdk_nvme_qpair *qpair;
833 : 1 : struct spdk_nvme_ctrlr *ctrlr = spdk_nvme_ns_get_ctrlr(ns);
834 : : int ret, err;
835 : :
836 : 1 : qpair = spdk_nvme_ctrlr_alloc_io_qpair(ctrlr, NULL, 0);
837 [ - + ]: 1 : if (!qpair) {
838 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_ctrlr_alloc_io_qpair() failed\n");
839 : 0 : return -EIO;
840 : : }
841 : :
842 : 1 : ret = 0;
843 : :
844 [ - + - + ]: 1 : fprintf(stdout, "==================================\n");
845 [ - + - + ]: 1 : fprintf(stdout, "== FDP tests for Namespace: #%02u ==\n", spdk_nvme_ns_get_id(ns));
846 [ - + - + ]: 1 : fprintf(stdout, "==================================\n\n");
847 : 1 : err = get_fdp(ns);
848 [ - + ]: 1 : if (err) {
849 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
850 : 0 : return err;
851 : : }
852 : :
853 [ - + ]: 1 : if (!fdp_res.bits.fdpe) {
854 [ # # # # ]: 0 : fprintf(stdout, "FDP support disabled\n");
855 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
856 : 0 : return 0;
857 : : }
858 : :
859 : 1 : fdpci = fdp_res.bits.fdpci;
860 : 1 : err = get_fdp_cfg_log_page(ns);
861 [ - + ]: 1 : if (err) {
862 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
863 : 0 : return err;
864 : : }
865 : :
866 : 1 : ret += get_fdp_ruhu_log_page(ns);
867 : 1 : ret += get_fdp_stats_log_page(ns);
868 : :
869 : 1 : err = reclaim_unit_handle_status(ns, qpair);
870 [ - + ]: 1 : if (err) {
871 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
872 : 0 : return err;
873 : : }
874 : :
875 : 1 : err = check_fdp_write(ns, qpair);
876 [ - + ]: 1 : if (err) {
877 : 0 : spdk_nvme_ctrlr_free_io_qpair(qpair);
878 : 0 : return err;
879 : : }
880 : :
881 : 1 : ret += set_fdp_events(ns);
882 : 1 : ret += reclaim_unit_handle_update(ns, qpair);
883 : :
884 : 1 : ret += get_fdp_events(ns);
885 : 1 : ret += get_fdp_events_log_page(ns);
886 : :
887 : 1 : return ret;
888 : : }
889 : :
890 : : static void
891 : 1 : register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns)
892 : : {
893 : : struct ns_entry *entry;
894 : 1 : const struct spdk_nvme_ns_data *nsdata = spdk_nvme_ns_get_data(ns);
895 : :
896 : 1 : entry = malloc(sizeof(struct ns_entry));
897 [ - + ]: 1 : if (entry == NULL) {
898 : 0 : perror("ns_entry malloc");
899 : 0 : exit(1);
900 : : }
901 : :
902 : 1 : entry->ctrlr = ctrlr;
903 : 1 : entry->ns = ns;
904 : 1 : entry->next = g_namespaces;
905 : 1 : g_namespaces = entry;
906 : :
907 [ - + ]: 1 : printf("Namespace ID: %d Endurance Group ID: %d\n", spdk_nvme_ns_get_id(ns),
908 : 1 : nsdata->endgid);
909 : 1 : }
910 : :
911 : : static bool
912 : 1 : probe_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
913 : : struct spdk_nvme_ctrlr_opts *opts)
914 : : {
915 [ - + - + ]: 1 : fprintf(stdout, "Attaching to %s\n", trid->traddr);
916 : :
917 : 1 : return true;
918 : : }
919 : :
920 : : static void
921 : 1 : attach_cb(void *cb_ctx, const struct spdk_nvme_transport_id *trid,
922 : : struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts)
923 : : {
924 : : int num_ns, nsid;
925 : : struct spdk_nvme_ns *ns;
926 : : const struct spdk_nvme_ctrlr_data *cdata;
927 : :
928 : 1 : cdata = spdk_nvme_ctrlr_get_data(ctrlr);
929 : :
930 [ + - ]: 1 : if (cdata->ctratt.bits.fdps) {
931 [ - + - + ]: 1 : fprintf(stdout, "Controller supports FDP Attached to %s\n", trid->traddr);
932 : 1 : num_ns = spdk_nvme_ctrlr_get_num_ns(ctrlr);
933 [ - + ]: 1 : if (num_ns < 1) {
934 [ # # ]: 0 : printf("No valid namespaces in controller\n");
935 : : } else {
936 [ + + ]: 2 : for (nsid = spdk_nvme_ctrlr_get_first_active_ns(ctrlr); nsid != 0;
937 : 1 : nsid = spdk_nvme_ctrlr_get_next_active_ns(ctrlr, nsid)) {
938 : 1 : ns = spdk_nvme_ctrlr_get_ns(ctrlr, nsid);
939 : 1 : register_ns(ctrlr, ns);
940 : : }
941 : : }
942 : : } else {
943 [ # # # # ]: 0 : fprintf(stdout, "Controller attached to: %s doesn't support FDP\n", trid->traddr);
944 : : }
945 : 1 : }
946 : :
947 : : static void
948 : 1 : cleanup(void)
949 : : {
950 : 1 : struct ns_entry *ns_entry = g_namespaces;
951 : 1 : struct spdk_nvme_detach_ctx *detach_ctx = NULL;
952 : :
953 [ + + ]: 2 : while (ns_entry) {
954 : 1 : struct ns_entry *next = ns_entry->next;
955 : :
956 : 1 : spdk_nvme_detach_async(ns_entry->ctrlr, &detach_ctx);
957 : :
958 : 1 : free(ns_entry);
959 : 1 : ns_entry = next;
960 : : }
961 : :
962 [ + - ]: 1 : if (detach_ctx) {
963 : 1 : spdk_nvme_detach_poll(detach_ctx);
964 : : }
965 : 1 : }
966 : :
967 : : static void
968 : 0 : usage(const char *program_name)
969 : : {
970 [ # # ]: 0 : printf("%s [options]", program_name);
971 : 0 : printf("\n");
972 [ # # ]: 0 : printf("options:\n");
973 [ # # ]: 0 : printf(" -r trid remote NVMe over Fabrics target address\n");
974 [ # # ]: 0 : printf(" Format: 'key:value [key:value] ...'\n");
975 [ # # ]: 0 : printf(" Keys:\n");
976 [ # # ]: 0 : printf(" trtype Transport type (e.g. RDMA)\n");
977 [ # # ]: 0 : printf(" adrfam Address family (e.g. IPv4, IPv6)\n");
978 [ # # ]: 0 : printf(" traddr Transport address (e.g. 192.168.100.8)\n");
979 [ # # ]: 0 : printf(" trsvcid Transport service identifier (e.g. 4420)\n");
980 [ # # ]: 0 : printf(" subnqn Subsystem NQN (default: %s)\n", SPDK_NVMF_DISCOVERY_NQN);
981 [ # # ]: 0 : printf(" Example: -r 'trtype:RDMA adrfam:IPv4 traddr:192.168.100.8 trsvcid:4420'\n");
982 [ # # ]: 0 : printf(" -h show this usage\n");
983 : 0 : }
984 : :
985 : : static int
986 : 1 : parse_args(int argc, char **argv, struct spdk_env_opts *env_opts)
987 : : {
988 : : int op;
989 : :
990 : 1 : spdk_nvme_trid_populate_transport(&g_trid, SPDK_NVME_TRANSPORT_PCIE);
991 [ - + ]: 1 : snprintf(g_trid.subnqn, sizeof(g_trid.subnqn), "%s", SPDK_NVMF_DISCOVERY_NQN);
992 : :
993 [ - + - + : 2 : while ((op = getopt(argc, argv, "r:h")) != -1) {
+ + ]
994 [ + - - ]: 1 : switch (op) {
995 : 1 : case 'r':
996 [ - + ]: 1 : if (spdk_nvme_transport_id_parse(&g_trid, optarg) != 0) {
997 [ # # # # ]: 0 : fprintf(stderr, "Error parsing transport address\n");
998 : 0 : return 1;
999 : : }
1000 : :
1001 : 1 : g_use_trid = true;
1002 : 1 : break;
1003 : 0 : case 'h':
1004 : 0 : usage(argv[0]);
1005 : 0 : exit(EXIT_SUCCESS);
1006 : 0 : default:
1007 : 0 : usage(argv[0]);
1008 : 0 : return 1;
1009 : : }
1010 : : }
1011 : :
1012 : 1 : return 0;
1013 : : }
1014 : :
1015 : : int
1016 : 1 : main(int argc, char **argv)
1017 : : {
1018 : : int rc;
1019 : 1 : struct spdk_env_opts opts;
1020 : : struct ns_entry *ns_entry;
1021 : :
1022 : 1 : spdk_env_opts_init(&opts);
1023 : 1 : rc = parse_args(argc, argv, &opts);
1024 [ - + ]: 1 : if (rc != 0) {
1025 : 0 : return rc;
1026 : : }
1027 : :
1028 : 1 : opts.name = "fdp";
1029 : 1 : opts.core_mask = "0x1";
1030 : 1 : opts.shm_id = 0;
1031 [ - + ]: 1 : if (spdk_env_init(&opts) < 0) {
1032 [ # # # # ]: 0 : fprintf(stderr, "Unable to initialize SPDK env\n");
1033 : 0 : return 1;
1034 : : }
1035 : :
1036 [ - + ]: 1 : printf("Initializing NVMe Controllers\n");
1037 : :
1038 [ - + + - ]: 1 : rc = spdk_nvme_probe(g_use_trid ? &g_trid : NULL, NULL, probe_cb, attach_cb, NULL);
1039 [ - + ]: 1 : if (rc != 0) {
1040 [ # # # # ]: 0 : fprintf(stderr, "spdk_nvme_probe() failed\n");
1041 : 0 : return 1;
1042 : : }
1043 : :
1044 [ - + ]: 1 : if (g_namespaces == NULL) {
1045 [ # # # # ]: 0 : fprintf(stderr, "no NVMe controllers found\n");
1046 : 0 : return 1;
1047 : : }
1048 : :
1049 [ - + ]: 1 : printf("Initialization complete.\n\n");
1050 : :
1051 : 1 : ns_entry = g_namespaces;
1052 [ + + ]: 2 : while (ns_entry != NULL) {
1053 : 1 : rc = fdp_tests(ns_entry->ns);
1054 [ - + ]: 1 : if (rc) {
1055 : 0 : break;
1056 : : }
1057 : 1 : ns_entry = ns_entry->next;
1058 : : }
1059 : :
1060 [ - + - + ]: 1 : printf("FDP test %s\n", rc ? "failed" : "passed");
1061 : 1 : cleanup();
1062 : :
1063 : 1 : return 0;
1064 : : }
|