1 /*
2 * SPDX-License-Identifier: Apache-2.0
3 * Copyright (c) 2022 Intel Corp.
4 */
5
6 #include <zephyr/logging/log.h>
7 LOG_MODULE_DECLARE(nvme, CONFIG_NVME_LOG_LEVEL);
8
9 #include <zephyr/kernel.h>
10 #include <zephyr/sys/byteorder.h>
11
12 #include <stdio.h>
13
14 #include "nvme.h"
15
nvme_namespace_get_sector_size(struct nvme_namespace * ns)16 uint32_t nvme_namespace_get_sector_size(struct nvme_namespace *ns)
17 {
18 uint8_t flbas_fmt, lbads;
19
20 flbas_fmt = (ns->data.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
21 NVME_NS_DATA_FLBAS_FORMAT_MASK;
22 lbads = (ns->data.lbaf[flbas_fmt] >> NVME_NS_DATA_LBAF_LBADS_SHIFT) &
23 NVME_NS_DATA_LBAF_LBADS_MASK;
24
25 return 1 << lbads;
26 }
27
nvme_namespace_get_num_sectors(struct nvme_namespace * ns)28 uint64_t nvme_namespace_get_num_sectors(struct nvme_namespace *ns)
29 {
30 return ns->data.nsze;
31 }
32
nvme_namespace_get_size(struct nvme_namespace * ns)33 uint64_t nvme_namespace_get_size(struct nvme_namespace *ns)
34 {
35 return nvme_namespace_get_num_sectors(ns) *
36 nvme_namespace_get_sector_size(ns);
37 }
38
nvme_namespace_get_flags(struct nvme_namespace * ns)39 uint32_t nvme_namespace_get_flags(struct nvme_namespace *ns)
40 {
41 return ns->flags;
42 }
43
nvme_namespace_get_serial_number(struct nvme_namespace * ns)44 const char *nvme_namespace_get_serial_number(struct nvme_namespace *ns)
45 {
46 return (const char *)ns->ctrlr->cdata.sn;
47 }
48
nvme_namespace_get_model_number(struct nvme_namespace * ns)49 const char *nvme_namespace_get_model_number(struct nvme_namespace *ns)
50 {
51 return (const char *)ns->ctrlr->cdata.mn;
52 }
53
54 const struct nvme_namespace_data *
nvme_namespace_get_data(struct nvme_namespace * ns)55 nvme_namespace_get_data(struct nvme_namespace *ns)
56 {
57 return &ns->data;
58 }
59
nvme_namespace_get_stripesize(struct nvme_namespace * ns)60 uint32_t nvme_namespace_get_stripesize(struct nvme_namespace *ns)
61 {
62 if (((ns->data.nsfeat >> NVME_NS_DATA_NSFEAT_NPVALID_SHIFT) &
63 NVME_NS_DATA_NSFEAT_NPVALID_MASK) != 0) {
64 uint32_t ss = nvme_namespace_get_sector_size(ns);
65
66 if (ns->data.npwa != 0) {
67 return (ns->data.npwa + 1) * ss;
68 } else if (ns->data.npwg != 0) {
69 return (ns->data.npwg + 1) * ss;
70 }
71 }
72
73 return ns->boundary;
74 }
75
nvme_namespace_construct(struct nvme_namespace * ns,uint32_t id,struct nvme_controller * ctrlr)76 int nvme_namespace_construct(struct nvme_namespace *ns,
77 uint32_t id,
78 struct nvme_controller *ctrlr)
79 {
80 struct nvme_completion_poll_status status =
81 NVME_CPL_STATUS_POLL_INIT(status);
82 uint8_t flbas_fmt;
83 uint8_t vwc_present;
84
85 ns->ctrlr = ctrlr;
86 ns->id = id;
87
88 nvme_ctrlr_cmd_identify_namespace(ctrlr, id, &ns->data,
89 nvme_completion_poll_cb,
90 &status);
91 nvme_completion_poll(&status);
92
93 if (nvme_cpl_status_is_error(&status)) {
94 LOG_DBG("Identifying NS id %d failed", id);
95 return -EIO;
96 }
97
98 nvme_namespace_data_swapbytes(&ns->data);
99
100 if (nvme_namespace_get_num_sectors(ns) == 0) {
101 LOG_DBG("Namespace %d not present", id);
102 return -ENODEV;
103 }
104
105 flbas_fmt = (ns->data.flbas >> NVME_NS_DATA_FLBAS_FORMAT_SHIFT) &
106 NVME_NS_DATA_FLBAS_FORMAT_MASK;
107
108 /* Note: format is a 0-based value, so > is appropriate here not >=. */
109 if (flbas_fmt > ns->data.nlbaf) {
110 LOG_DBG("NS id %d: lba format %d exceeds number supported (%d)",
111 id, flbas_fmt, ns->data.nlbaf + 1);
112 return -EIO;
113 }
114
115 ns->boundary = ns->data.noiob * nvme_namespace_get_sector_size(ns);
116
117 if (nvme_controller_has_dataset_mgmt(ctrlr)) {
118 ns->flags |= NVME_NS_DEALLOCATE_SUPPORTED;
119 }
120
121 vwc_present = (ctrlr->cdata.vwc >> NVME_CTRLR_DATA_VWC_PRESENT_SHIFT) &
122 NVME_CTRLR_DATA_VWC_PRESENT_MASK;
123 if (vwc_present) {
124 ns->flags |= NVME_NS_FLUSH_SUPPORTED;
125 }
126
127 snprintf(ns->name, NVME_NAMESPACE_NAME_MAX_LENGTH, "nvme%dn%d",
128 ctrlr->id, ns->id-1);
129
130 if (nvme_namespace_disk_setup(ns, &ns->disk) != 0) {
131 LOG_ERR("Could not register no disk subsystem");
132 }
133
134 return 0;
135 }
136