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