static int ns_data_buffer_compare(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern) { uint32_t md_size, sector_size; uint32_t i, j, offset = 0; uint8_t *buf; sector_size = spdk_nvme_ns_get_sector_size(ns); md_size = spdk_nvme_ns_get_md_size(ns); for (i = 0; i < req->lba_count; i++) { if (req->use_extended_lba) offset = (sector_size + md_size) * i; else offset = sector_size * i; buf = (uint8_t *)req->contig + offset; for (j = 0; j < sector_size; j++) { if (buf[j] != data_pattern) { return -1; } } } return 0; }
static void register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) { struct ns_entry *entry; const struct spdk_nvme_ctrlr_data *cdata; entry = malloc(sizeof(struct ns_entry)); if (entry == NULL) { perror("ns_entry malloc"); exit(1); } cdata = spdk_nvme_ctrlr_get_data(ctrlr); entry->ns = ns; entry->size_in_ios = spdk_nvme_ns_get_size(ns) / g_io_size_bytes; entry->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(ns); snprintf(entry->name, 44, "%-20.20s (%-20.20s)", cdata->mn, cdata->sn); g_num_namespaces++; entry->next = g_namespaces; g_namespaces = entry; }
/* * LBA + Metadata without data protection bits setting, * separate metadata payload for the test case. */ static uint32_t dp_without_flags_separate_meta_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { uint32_t md_size, sector_size; req->lba_count = 16; /* separate metadata payload for the test case */ if (spdk_nvme_ns_supports_extended_lba(ns)) return 0; sector_size = spdk_nvme_ns_get_sector_size(ns);; md_size = spdk_nvme_ns_get_md_size(ns); req->contig = rte_zmalloc(NULL, sector_size * req->lba_count, 0x1000); if (!req->contig) return 0; req->metadata = rte_zmalloc(NULL, md_size * req->lba_count, 0x1000); if (!req->metadata) { rte_free(req->contig); return 0; } req->lba = 0x600000; req->use_extended_lba = false; *io_flags = 0; return req->lba_count; }
/* * No protection information with PRACT setting to 1, * both extended LBA format and separate metadata can * run the test case. */ static uint32_t dp_with_pract_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { uint32_t sector_size; req->lba_count = 8; sector_size = spdk_nvme_ns_get_sector_size(ns); /* No additional metadata buffer provided */ req->contig = rte_zmalloc(NULL, sector_size * req->lba_count, 0x1000); if (!req->contig) return 0; switch (spdk_nvme_ns_get_pi_type(ns)) { case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRACT; break; case SPDK_NVME_FMT_NVM_PROTECTION_TYPE1: case SPDK_NVME_FMT_NVM_PROTECTION_TYPE2: *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_GUARD | SPDK_NVME_IO_FLAGS_PRCHK_REFTAG | SPDK_NVME_IO_FLAGS_PRACT; break; default: *io_flags = 0; break; } req->lba = 0x100000; req->use_extended_lba = false; req->metadata = NULL; return req->lba_count; }
static void register_ns(struct spdk_nvme_ctrlr *ctrlr, struct spdk_nvme_ns *ns) { struct ns_entry *entry; const struct spdk_nvme_ctrlr_data *cdata; cdata = spdk_nvme_ctrlr_get_data(ctrlr); if (!spdk_nvme_ns_is_active(ns)) { printf("Controller %-20.20s (%-20.20s): Skipping inactive NS %u\n", cdata->mn, cdata->sn, spdk_nvme_ns_get_id(ns)); return; } if (spdk_nvme_ns_get_size(ns) < g_io_size_bytes || spdk_nvme_ns_get_sector_size(ns) > g_io_size_bytes) { printf("WARNING: controller %-20.20s (%-20.20s) ns %u has invalid " "ns size %" PRIu64 " / block size %u for I/O size %u\n", cdata->mn, cdata->sn, spdk_nvme_ns_get_id(ns), spdk_nvme_ns_get_size(ns), spdk_nvme_ns_get_sector_size(ns), g_io_size_bytes); return; } entry = malloc(sizeof(struct ns_entry)); if (entry == NULL) { perror("ns_entry malloc"); exit(1); } entry->type = ENTRY_TYPE_NVME_NS; entry->u.nvme.ctrlr = ctrlr; entry->u.nvme.ns = ns; entry->size_in_ios = spdk_nvme_ns_get_size(ns) / g_io_size_bytes; entry->io_size_blocks = g_io_size_bytes / spdk_nvme_ns_get_sector_size(ns); snprintf(entry->name, 44, "%-20.20s (%-20.20s)", cdata->mn, cdata->sn); g_num_namespaces++; entry->next = g_namespaces; g_namespaces = entry; }
static void attach_cb(void *cb_ctx, struct spdk_pci_device *dev, struct spdk_nvme_ctrlr *ctrlr, const struct spdk_nvme_ctrlr_opts *opts) { u2_ctrlr = ctrlr; u2_ns = spdk_nvme_ctrlr_get_ns(u2_ctrlr, u2_ns_id); u2_ns_sector = spdk_nvme_ns_get_sector_size(u2_ns); u2_ns_size = spdk_nvme_ns_get_size(u2_ns); u2_qpair = spdk_nvme_ctrlr_alloc_io_qpair(u2_ctrlr, 0); printf("attached to %04x:%02x:%02x.%02x!\n", spdk_pci_device_get_domain(dev), spdk_pci_device_get_bus(dev), spdk_pci_device_get_dev(dev), spdk_pci_device_get_func(dev)); }
/* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */ static uint32_t dp_without_pract_separate_meta_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { struct spdk_nvme_protection_info *pi; uint32_t md_size, sector_size; req->lba_count = 2; switch (spdk_nvme_ns_get_pi_type(ns)) { case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: return 0; default: break; } /* separate metadata payload for the test case */ if (spdk_nvme_ns_supports_extended_lba(ns)) return 0; sector_size = spdk_nvme_ns_get_sector_size(ns);; md_size = spdk_nvme_ns_get_md_size(ns); req->contig = rte_zmalloc(NULL, sector_size * req->lba_count, 0x1000); if (!req->contig) return 0; req->metadata = rte_zmalloc(NULL, md_size * req->lba_count, 0x1000); if (!req->metadata) { rte_free(req->contig); return 0; } req->lba = 0x400000; req->use_extended_lba = false; /* last 8 bytes if the metadata size bigger than 8 */ pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size - 8); /* big-endian for reference tag */ pi->ref_tag = swap32((uint32_t)req->lba); pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size * 2 - 8); /* is incremented for each subsequent logical block */ pi->ref_tag = swap32((uint32_t)req->lba + 1); *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG; return req->lba_count; }
static void ns_data_buffer_reset(struct spdk_nvme_ns *ns, struct io_request *req, uint8_t data_pattern) { uint32_t md_size, sector_size; uint32_t i, offset = 0; uint8_t *buf; sector_size = spdk_nvme_ns_get_sector_size(ns); md_size = spdk_nvme_ns_get_md_size(ns); for (i = 0; i < req->lba_count; i++) { if (req->use_extended_lba) offset = (sector_size + md_size) * i; else offset = sector_size * i; buf = (uint8_t *)req->contig + offset; memset(buf, data_pattern, sector_size); } }
/* Block Reference Tag checked for TYPE1 and TYPE2 with PRACT setting to 0 */ static uint32_t dp_without_pract_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { struct spdk_nvme_protection_info *pi; uint32_t md_size, sector_size; req->lba_count = 2; switch (spdk_nvme_ns_get_pi_type(ns)) { case SPDK_NVME_FMT_NVM_PROTECTION_TYPE3: return 0; default: break; } /* extended LBA only for the test case */ if (!(spdk_nvme_ns_supports_extended_lba(ns))) return 0; sector_size = spdk_nvme_ns_get_sector_size(ns);; md_size = spdk_nvme_ns_get_md_size(ns); req->contig = rte_zmalloc(NULL, (sector_size + md_size) * req->lba_count, 0x1000); if (!req->contig) return 0; req->lba = 0x200000; req->use_extended_lba = true; req->metadata = NULL; pi = (struct spdk_nvme_protection_info *)(req->contig + sector_size + md_size - 8); /* big-endian for reference tag */ pi->ref_tag = swap32((uint32_t)req->lba); pi = (struct spdk_nvme_protection_info *)(req->contig + (sector_size + md_size) * 2 - 8); /* is incremented for each subsequent logical block */ pi->ref_tag = swap32((uint32_t)req->lba + 1); *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_REFTAG; return req->lba_count; }
/* Application Tag checked with PRACT setting to 0 */ static uint32_t dp_without_pract_separate_meta_apptag_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { struct spdk_nvme_protection_info *pi; uint32_t md_size, sector_size; req->lba_count = 1; /* separate metadata payload for the test case */ if (spdk_nvme_ns_supports_extended_lba(ns)) return 0; sector_size = spdk_nvme_ns_get_sector_size(ns);; md_size = spdk_nvme_ns_get_md_size(ns); req->contig = rte_zmalloc(NULL, sector_size * req->lba_count, 0x1000); if (!req->contig) return 0; req->metadata = rte_zmalloc(NULL, md_size * req->lba_count, 0x1000); if (!req->metadata) { rte_free(req->contig); return 0; } req->lba = 0x500000; req->use_extended_lba = false; req->apptag_mask = 0xFFFF; req->apptag = req->lba_count; /* last 8 bytes if the metadata size bigger than 8 */ pi = (struct spdk_nvme_protection_info *)(req->metadata + md_size - 8); pi->app_tag = swap16(req->lba_count); *io_flags = SPDK_NVME_IO_FLAGS_PRCHK_APPTAG; return req->lba_count; }
/* LBA + Metadata without data protection bits setting */ static uint32_t dp_without_flags_extended_lba_test(struct spdk_nvme_ns *ns, struct io_request *req, uint32_t *io_flags) { uint32_t md_size, sector_size; req->lba_count = 16; /* extended LBA only for the test case */ if (!(spdk_nvme_ns_supports_extended_lba(ns))) return 0; sector_size = spdk_nvme_ns_get_sector_size(ns);; md_size = spdk_nvme_ns_get_md_size(ns); req->contig = rte_zmalloc(NULL, (sector_size + md_size) * req->lba_count, 0x1000); if (!req->contig) return 0; req->lba = 0x400000; req->use_extended_lba = true; req->metadata = NULL; *io_flags = 0; return req->lba_count; }
static int write_read_e2e_dp_tests(struct dev *dev, nvme_build_io_req_fn_t build_io_fn, const char *test_name) { int rc = 0; uint32_t lba_count; uint32_t io_flags = 0; struct io_request *req; struct spdk_nvme_ns *ns; struct spdk_nvme_qpair *qpair; const struct spdk_nvme_ns_data *nsdata; ns = spdk_nvme_ctrlr_get_ns(dev->ctrlr, 1); if (!ns) { fprintf(stderr, "Null namespace\n"); return 0; } if (!(spdk_nvme_ns_get_flags(ns) & SPDK_NVME_NS_DPS_PI_SUPPORTED)) return 0; nsdata = spdk_nvme_ns_get_data(ns); if (!nsdata || !spdk_nvme_ns_get_sector_size(ns)) { fprintf(stderr, "Empty nsdata or wrong sector size\n"); return 0; } req = rte_zmalloc(NULL, sizeof(*req), 0); if (!req) { fprintf(stderr, "Allocate request failed\n"); return 0; } /* IO parameters setting */ lba_count = build_io_fn(ns, req, &io_flags); if (!lba_count) { fprintf(stderr, "%s: %s bypass the test case\n", dev->name, test_name); free_req(req); return 0; } qpair = spdk_nvme_ctrlr_alloc_io_qpair(dev->ctrlr, 0); if (!qpair) { free_req(req); return -1; } ns_data_buffer_reset(ns, req, DATA_PATTERN); if (req->use_extended_lba) rc = spdk_nvme_ns_cmd_write(ns, qpair, req->contig, req->lba, lba_count, io_complete, req, io_flags); else rc = spdk_nvme_ns_cmd_write_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count, io_complete, req, io_flags, req->apptag_mask, req->apptag); if (rc != 0) { fprintf(stderr, "%s: %s write submit failed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return -1; } io_complete_flag = 0; while (!io_complete_flag) spdk_nvme_qpair_process_completions(qpair, 1); if (io_complete_flag != 1) { fprintf(stderr, "%s: %s write exec failed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return -1; } /* reset completion flag */ io_complete_flag = 0; ns_data_buffer_reset(ns, req, 0); if (req->use_extended_lba) rc = spdk_nvme_ns_cmd_read(ns, qpair, req->contig, req->lba, lba_count, io_complete, req, io_flags); else rc = spdk_nvme_ns_cmd_read_with_md(ns, qpair, req->contig, req->metadata, req->lba, lba_count, io_complete, req, io_flags, req->apptag_mask, req->apptag); if (rc != 0) { fprintf(stderr, "%s: %s read failed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return -1; } while (!io_complete_flag) spdk_nvme_qpair_process_completions(qpair, 1); if (io_complete_flag != 1) { fprintf(stderr, "%s: %s read failed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return -1; } rc = ns_data_buffer_compare(ns, req, DATA_PATTERN); if (rc < 0) { fprintf(stderr, "%s: %s write/read success, but memcmp Failed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return -1; } fprintf(stdout, "%s: %s test passed\n", dev->name, test_name); spdk_nvme_ctrlr_free_io_qpair(qpair); free_req(req); return rc; }
uint64_t spdk_nvme_ns_get_size(struct spdk_nvme_ns *ns) { return spdk_nvme_ns_get_num_sectors(ns) * spdk_nvme_ns_get_sector_size(ns); }