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