1 /*- 2 * BSD LICENSE 3 * 4 * Copyright (c) Intel Corporation. All rights reserved. 5 * Copyright (c) 2020, 2021 Mellanox Technologies LTD. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include "nvme_internal.h" 35 36 static inline struct spdk_nvme_ns_data * 37 _nvme_ns_get_data(struct spdk_nvme_ns *ns) 38 { 39 return &ns->nsdata; 40 } 41 42 /** 43 * Update Namespace flags based on Identify Controller 44 * and Identify Namespace. This can be also used for 45 * Namespace Attribute Notice events and Namespace 46 * operations such as Attach/Detach. 47 */ 48 void 49 nvme_ns_set_identify_data(struct spdk_nvme_ns *ns) 50 { 51 struct spdk_nvme_ns_data *nsdata; 52 53 nsdata = _nvme_ns_get_data(ns); 54 55 ns->flags = 0x0000; 56 57 ns->sector_size = 1 << nsdata->lbaf[nsdata->flbas.format].lbads; 58 ns->extended_lba_size = ns->sector_size; 59 60 ns->md_size = nsdata->lbaf[nsdata->flbas.format].ms; 61 if (nsdata->flbas.extended) { 62 ns->flags |= SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED; 63 ns->extended_lba_size += ns->md_size; 64 } 65 66 ns->sectors_per_max_io = spdk_nvme_ns_get_max_io_xfer_size(ns) / ns->extended_lba_size; 67 ns->sectors_per_max_io_no_md = spdk_nvme_ns_get_max_io_xfer_size(ns) / ns->sector_size; 68 if (ns->ctrlr->quirks & NVME_QUIRK_MDTS_EXCLUDE_MD) { 69 ns->sectors_per_max_io = ns->sectors_per_max_io_no_md; 70 } 71 72 if (nsdata->noiob) { 73 ns->sectors_per_stripe = nsdata->noiob; 74 SPDK_DEBUGLOG(nvme, "ns %u optimal IO boundary %" PRIu32 " blocks\n", 75 ns->id, ns->sectors_per_stripe); 76 } else if (ns->ctrlr->quirks & NVME_INTEL_QUIRK_STRIPING && 77 ns->ctrlr->cdata.vs[3] != 0) { 78 ns->sectors_per_stripe = (1ULL << ns->ctrlr->cdata.vs[3]) * ns->ctrlr->min_page_size / 79 ns->sector_size; 80 SPDK_DEBUGLOG(nvme, "ns %u stripe size quirk %" PRIu32 " blocks\n", 81 ns->id, ns->sectors_per_stripe); 82 } else { 83 ns->sectors_per_stripe = 0; 84 } 85 86 if (ns->ctrlr->cdata.oncs.dsm) { 87 ns->flags |= SPDK_NVME_NS_DEALLOCATE_SUPPORTED; 88 } 89 90 if (ns->ctrlr->cdata.oncs.compare) { 91 ns->flags |= SPDK_NVME_NS_COMPARE_SUPPORTED; 92 } 93 94 if (ns->ctrlr->cdata.vwc.present) { 95 ns->flags |= SPDK_NVME_NS_FLUSH_SUPPORTED; 96 } 97 98 if (ns->ctrlr->cdata.oncs.write_zeroes) { 99 ns->flags |= SPDK_NVME_NS_WRITE_ZEROES_SUPPORTED; 100 } 101 102 if (ns->ctrlr->cdata.oncs.write_unc) { 103 ns->flags |= SPDK_NVME_NS_WRITE_UNCORRECTABLE_SUPPORTED; 104 } 105 106 if (nsdata->nsrescap.raw) { 107 ns->flags |= SPDK_NVME_NS_RESERVATION_SUPPORTED; 108 } 109 110 ns->pi_type = SPDK_NVME_FMT_NVM_PROTECTION_DISABLE; 111 if (nsdata->lbaf[nsdata->flbas.format].ms && nsdata->dps.pit) { 112 ns->flags |= SPDK_NVME_NS_DPS_PI_SUPPORTED; 113 ns->pi_type = nsdata->dps.pit; 114 } 115 } 116 117 static int 118 nvme_ctrlr_identify_ns(struct spdk_nvme_ns *ns) 119 { 120 struct nvme_completion_poll_status *status; 121 struct spdk_nvme_ns_data *nsdata; 122 int rc; 123 124 status = calloc(1, sizeof(*status)); 125 if (!status) { 126 SPDK_ERRLOG("Failed to allocate status tracker\n"); 127 return -ENOMEM; 128 } 129 130 nsdata = _nvme_ns_get_data(ns); 131 rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS, 0, ns->id, 0, 132 nsdata, sizeof(*nsdata), 133 nvme_completion_poll_cb, status); 134 if (rc != 0) { 135 free(status); 136 return rc; 137 } 138 139 if (nvme_wait_for_completion_robust_lock(ns->ctrlr->adminq, status, 140 &ns->ctrlr->ctrlr_lock)) { 141 if (!status->timed_out) { 142 free(status); 143 } 144 /* This can occur if the namespace is not active. Simply zero the 145 * namespace data and continue. */ 146 nvme_ns_destruct(ns); 147 return 0; 148 } 149 free(status); 150 151 nvme_ns_set_identify_data(ns); 152 153 return 0; 154 } 155 156 static int 157 nvme_ctrlr_identify_ns_iocs_specific(struct spdk_nvme_ns *ns) 158 { 159 struct nvme_completion_poll_status *status; 160 struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr; 161 int rc; 162 163 switch (ns->csi) { 164 case SPDK_NVME_CSI_ZNS: 165 break; 166 default: 167 /* 168 * This switch must handle all cases for which 169 * nvme_ns_has_supported_iocs_specific_data() returns true, 170 * other cases should never happen. 171 */ 172 assert(0); 173 } 174 175 assert(!ns->nsdata_zns); 176 ns->nsdata_zns = spdk_zmalloc(sizeof(*ns->nsdata_zns), 64, NULL, SPDK_ENV_SOCKET_ID_ANY, 177 SPDK_MALLOC_SHARE); 178 if (!ns->nsdata_zns) { 179 return -ENOMEM; 180 } 181 182 status = calloc(1, sizeof(*status)); 183 if (!status) { 184 SPDK_ERRLOG("Failed to allocate status tracker\n"); 185 nvme_ns_free_zns_specific_data(ns); 186 return -ENOMEM; 187 } 188 189 rc = nvme_ctrlr_cmd_identify(ctrlr, SPDK_NVME_IDENTIFY_NS_IOCS, 0, ns->id, ns->csi, 190 ns->nsdata_zns, sizeof(*ns->nsdata_zns), 191 nvme_completion_poll_cb, status); 192 if (rc != 0) { 193 nvme_ns_free_zns_specific_data(ns); 194 free(status); 195 return rc; 196 } 197 198 if (nvme_wait_for_completion_robust_lock(ctrlr->adminq, status, &ctrlr->ctrlr_lock)) { 199 SPDK_ERRLOG("Failed to retrieve Identify IOCS Specific Namespace Data Structure\n"); 200 nvme_ns_free_zns_specific_data(ns); 201 if (!status->timed_out) { 202 free(status); 203 } 204 return -ENXIO; 205 } 206 free(status); 207 208 return 0; 209 } 210 211 static int 212 nvme_ctrlr_identify_id_desc(struct spdk_nvme_ns *ns) 213 { 214 struct nvme_completion_poll_status *status; 215 int rc; 216 217 memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list)); 218 219 if ((ns->ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) && 220 !(ns->ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS)) || 221 (ns->ctrlr->quirks & NVME_QUIRK_IDENTIFY_CNS)) { 222 SPDK_DEBUGLOG(nvme, "Version < 1.3; not attempting to retrieve NS ID Descriptor List\n"); 223 return 0; 224 } 225 226 status = calloc(1, sizeof(*status)); 227 if (!status) { 228 SPDK_ERRLOG("Failed to allocate status tracker\n"); 229 return -ENOMEM; 230 } 231 232 SPDK_DEBUGLOG(nvme, "Attempting to retrieve NS ID Descriptor List\n"); 233 rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST, 0, ns->id, 234 0, ns->id_desc_list, sizeof(ns->id_desc_list), 235 nvme_completion_poll_cb, status); 236 if (rc < 0) { 237 free(status); 238 return rc; 239 } 240 241 rc = nvme_wait_for_completion_robust_lock(ns->ctrlr->adminq, status, &ns->ctrlr->ctrlr_lock); 242 if (rc != 0) { 243 SPDK_WARNLOG("Failed to retrieve NS ID Descriptor List\n"); 244 memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list)); 245 } 246 247 if (!status->timed_out) { 248 free(status); 249 } 250 251 nvme_ns_set_id_desc_list_data(ns); 252 253 return rc; 254 } 255 256 uint32_t 257 spdk_nvme_ns_get_id(struct spdk_nvme_ns *ns) 258 { 259 return ns->id; 260 } 261 262 bool 263 spdk_nvme_ns_is_active(struct spdk_nvme_ns *ns) 264 { 265 const struct spdk_nvme_ns_data *nsdata = NULL; 266 267 /* 268 * According to the spec, valid NS has non-zero id. 269 */ 270 if (ns->id == 0) { 271 return false; 272 } 273 274 nsdata = _nvme_ns_get_data(ns); 275 276 /* 277 * According to the spec, Identify Namespace will return a zero-filled structure for 278 * inactive namespace IDs. 279 * Check NCAP since it must be nonzero for an active namespace. 280 */ 281 return nsdata->ncap != 0; 282 } 283 284 struct spdk_nvme_ctrlr * 285 spdk_nvme_ns_get_ctrlr(struct spdk_nvme_ns *ns) 286 { 287 return ns->ctrlr; 288 } 289 290 uint32_t 291 spdk_nvme_ns_get_max_io_xfer_size(struct spdk_nvme_ns *ns) 292 { 293 return ns->ctrlr->max_xfer_size; 294 } 295 296 uint32_t 297 spdk_nvme_ns_get_sector_size(struct spdk_nvme_ns *ns) 298 { 299 return ns->sector_size; 300 } 301 302 uint32_t 303 spdk_nvme_ns_get_extended_sector_size(struct spdk_nvme_ns *ns) 304 { 305 return ns->extended_lba_size; 306 } 307 308 uint64_t 309 spdk_nvme_ns_get_num_sectors(struct spdk_nvme_ns *ns) 310 { 311 return _nvme_ns_get_data(ns)->nsze; 312 } 313 314 uint64_t 315 spdk_nvme_ns_get_size(struct spdk_nvme_ns *ns) 316 { 317 return spdk_nvme_ns_get_num_sectors(ns) * spdk_nvme_ns_get_sector_size(ns); 318 } 319 320 uint32_t 321 spdk_nvme_ns_get_flags(struct spdk_nvme_ns *ns) 322 { 323 return ns->flags; 324 } 325 326 enum spdk_nvme_pi_type 327 spdk_nvme_ns_get_pi_type(struct spdk_nvme_ns *ns) { 328 return ns->pi_type; 329 } 330 331 bool 332 spdk_nvme_ns_supports_extended_lba(struct spdk_nvme_ns *ns) 333 { 334 return (ns->flags & SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED) ? true : false; 335 } 336 337 bool 338 spdk_nvme_ns_supports_compare(struct spdk_nvme_ns *ns) 339 { 340 return (ns->flags & SPDK_NVME_NS_COMPARE_SUPPORTED) ? true : false; 341 } 342 343 uint32_t 344 spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns) 345 { 346 return ns->md_size; 347 } 348 349 const struct spdk_nvme_ns_data * 350 spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns) 351 { 352 return _nvme_ns_get_data(ns); 353 } 354 355 enum spdk_nvme_dealloc_logical_block_read_value spdk_nvme_ns_get_dealloc_logical_block_read_value( 356 struct spdk_nvme_ns *ns) 357 { 358 struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr; 359 const struct spdk_nvme_ns_data *data = spdk_nvme_ns_get_data(ns); 360 361 if (ctrlr->quirks & NVME_QUIRK_READ_ZERO_AFTER_DEALLOCATE) { 362 return SPDK_NVME_DEALLOC_READ_00; 363 } else { 364 return data->dlfeat.bits.read_value; 365 } 366 } 367 368 uint32_t 369 spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns) 370 { 371 return ns->sectors_per_stripe; 372 } 373 374 static const void * 375 nvme_ns_find_id_desc(const struct spdk_nvme_ns *ns, enum spdk_nvme_nidt type, size_t *length) 376 { 377 const struct spdk_nvme_ns_id_desc *desc; 378 size_t offset; 379 380 offset = 0; 381 while (offset + 4 < sizeof(ns->id_desc_list)) { 382 desc = (const struct spdk_nvme_ns_id_desc *)&ns->id_desc_list[offset]; 383 384 if (desc->nidl == 0) { 385 /* End of list */ 386 return NULL; 387 } 388 389 /* 390 * Check if this descriptor fits within the list. 391 * 4 is the fixed-size descriptor header (not counted in NIDL). 392 */ 393 if (offset + desc->nidl + 4 > sizeof(ns->id_desc_list)) { 394 /* Descriptor longer than remaining space in list (invalid) */ 395 return NULL; 396 } 397 398 if (desc->nidt == type) { 399 *length = desc->nidl; 400 return &desc->nid[0]; 401 } 402 403 offset += 4 + desc->nidl; 404 } 405 406 return NULL; 407 } 408 409 const struct spdk_uuid * 410 spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns) 411 { 412 const struct spdk_uuid *uuid; 413 size_t uuid_size; 414 415 uuid = nvme_ns_find_id_desc(ns, SPDK_NVME_NIDT_UUID, &uuid_size); 416 if (uuid && uuid_size != sizeof(*uuid)) { 417 SPDK_WARNLOG("Invalid NIDT_UUID descriptor length reported: %zu (expected: %zu)\n", 418 uuid_size, sizeof(*uuid)); 419 return NULL; 420 } 421 422 return uuid; 423 } 424 425 static enum spdk_nvme_csi 426 nvme_ns_get_csi(const struct spdk_nvme_ns *ns) { 427 const uint8_t *csi; 428 size_t csi_size; 429 430 csi = nvme_ns_find_id_desc(ns, SPDK_NVME_NIDT_CSI, &csi_size); 431 if (csi && csi_size != sizeof(*csi)) 432 { 433 SPDK_WARNLOG("Invalid NIDT_CSI descriptor length reported: %zu (expected: %zu)\n", 434 csi_size, sizeof(*csi)); 435 return SPDK_NVME_CSI_NVM; 436 } 437 if (!csi) 438 { 439 if (ns->ctrlr->cap.bits.css & SPDK_NVME_CAP_CSS_IOCS) { 440 SPDK_WARNLOG("CSI not reported for NSID: %" PRIu32 "\n", ns->id); 441 } 442 return SPDK_NVME_CSI_NVM; 443 } 444 445 return *csi; 446 } 447 448 void 449 nvme_ns_set_id_desc_list_data(struct spdk_nvme_ns *ns) 450 { 451 ns->csi = nvme_ns_get_csi(ns); 452 } 453 454 enum spdk_nvme_csi 455 spdk_nvme_ns_get_csi(const struct spdk_nvme_ns *ns) { 456 return ns->csi; 457 } 458 459 void 460 nvme_ns_free_zns_specific_data(struct spdk_nvme_ns *ns) 461 { 462 if (!ns->id) { 463 return; 464 } 465 466 if (ns->nsdata_zns) { 467 spdk_free(ns->nsdata_zns); 468 ns->nsdata_zns = NULL; 469 } 470 } 471 472 void 473 nvme_ns_free_iocs_specific_data(struct spdk_nvme_ns *ns) 474 { 475 nvme_ns_free_zns_specific_data(ns); 476 } 477 478 bool 479 nvme_ns_has_supported_iocs_specific_data(struct spdk_nvme_ns *ns) 480 { 481 switch (ns->csi) { 482 case SPDK_NVME_CSI_NVM: 483 /* 484 * NVM Command Set Specific Identify Namespace data structure 485 * is currently all-zeroes, reserved for future use. 486 */ 487 return false; 488 case SPDK_NVME_CSI_ZNS: 489 return true; 490 default: 491 SPDK_WARNLOG("Unsupported CSI: %u for NSID: %u\n", ns->csi, ns->id); 492 return false; 493 } 494 } 495 496 uint32_t 497 spdk_nvme_ns_get_ana_group_id(const struct spdk_nvme_ns *ns) 498 { 499 return ns->ana_group_id; 500 } 501 502 enum spdk_nvme_ana_state 503 spdk_nvme_ns_get_ana_state(const struct spdk_nvme_ns *ns) { 504 return ns->ana_state; 505 } 506 507 int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id, 508 struct spdk_nvme_ctrlr *ctrlr) 509 { 510 int rc; 511 512 assert(id > 0); 513 514 ns->ctrlr = ctrlr; 515 ns->id = id; 516 517 rc = nvme_ctrlr_identify_ns(ns); 518 if (rc != 0) { 519 return rc; 520 } 521 522 /* skip Identify NS ID Descriptor List for inactive NS */ 523 if (!spdk_nvme_ns_is_active(ns)) { 524 return 0; 525 } 526 527 rc = nvme_ctrlr_identify_id_desc(ns); 528 if (rc != 0) { 529 return rc; 530 } 531 532 if (nvme_ctrlr_multi_iocs_enabled(ctrlr) && 533 nvme_ns_has_supported_iocs_specific_data(ns)) { 534 rc = nvme_ctrlr_identify_ns_iocs_specific(ns); 535 if (rc != 0) { 536 return rc; 537 } 538 } 539 540 return 0; 541 } 542 543 void nvme_ns_destruct(struct spdk_nvme_ns *ns) 544 { 545 struct spdk_nvme_ns_data *nsdata; 546 547 if (!ns->id) { 548 return; 549 } 550 551 nsdata = _nvme_ns_get_data(ns); 552 memset(nsdata, 0, sizeof(*nsdata)); 553 memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list)); 554 nvme_ns_free_iocs_specific_data(ns); 555 ns->sector_size = 0; 556 ns->extended_lba_size = 0; 557 ns->md_size = 0; 558 ns->pi_type = 0; 559 ns->sectors_per_max_io = 0; 560 ns->sectors_per_max_io_no_md = 0; 561 ns->sectors_per_stripe = 0; 562 ns->flags = 0; 563 ns->csi = SPDK_NVME_CSI_NVM; 564 } 565 566 int nvme_ns_update(struct spdk_nvme_ns *ns) 567 { 568 return nvme_ctrlr_identify_ns(ns); 569 } 570