1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#ifndef NVME_NS_H
16#define NVME_NS_H
17
18#include "qemu/uuid.h"
19
20#define TYPE_NVME_NS "nvme-ns"
21#define NVME_NS(obj) \
22 OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
23
24typedef struct NvmeZone {
25 NvmeZoneDescr d;
26 uint64_t w_ptr;
27 QTAILQ_ENTRY(NvmeZone) entry;
28} NvmeZone;
29
30typedef struct NvmeNamespaceParams {
31 bool detached;
32 bool shared;
33 uint32_t nsid;
34 QemuUUID uuid;
35
36 uint16_t ms;
37 uint8_t mset;
38 uint8_t pi;
39 uint8_t pil;
40
41 uint16_t mssrl;
42 uint32_t mcl;
43 uint8_t msrc;
44
45 bool zoned;
46 bool cross_zone_read;
47 uint64_t zone_size_bs;
48 uint64_t zone_cap_bs;
49 uint32_t max_active_zones;
50 uint32_t max_open_zones;
51 uint32_t zd_extension_size;
52} NvmeNamespaceParams;
53
54typedef struct NvmeNamespace {
55 DeviceState parent_obj;
56 BlockConf blkconf;
57 int32_t bootindex;
58 int64_t size;
59 int64_t mdata_offset;
60 NvmeIdNs id_ns;
61 const uint32_t *iocs;
62 uint8_t csi;
63 uint16_t status;
64 int attached;
65
66 QTAILQ_ENTRY(NvmeNamespace) entry;
67
68 NvmeIdNsZoned *id_ns_zoned;
69 NvmeZone *zone_array;
70 QTAILQ_HEAD(, NvmeZone) exp_open_zones;
71 QTAILQ_HEAD(, NvmeZone) imp_open_zones;
72 QTAILQ_HEAD(, NvmeZone) closed_zones;
73 QTAILQ_HEAD(, NvmeZone) full_zones;
74 uint32_t num_zones;
75 uint64_t zone_size;
76 uint64_t zone_capacity;
77 uint32_t zone_size_log2;
78 uint8_t *zd_extensions;
79 int32_t nr_open_zones;
80 int32_t nr_active_zones;
81
82 NvmeNamespaceParams params;
83
84 struct {
85 uint32_t err_rec;
86 } features;
87} NvmeNamespace;
88
89static inline uint16_t nvme_ns_status(NvmeNamespace *ns)
90{
91 return ns->status;
92}
93
94static inline uint32_t nvme_nsid(NvmeNamespace *ns)
95{
96 if (ns) {
97 return ns->params.nsid;
98 }
99
100 return 0;
101}
102
103static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
104{
105 NvmeIdNs *id_ns = &ns->id_ns;
106 return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
107}
108
109static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
110{
111 return nvme_ns_lbaf(ns)->ds;
112}
113
114
115static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
116{
117 return lba << nvme_ns_lbads(ns);
118}
119
120static inline size_t nvme_lsize(NvmeNamespace *ns)
121{
122 return 1 << nvme_ns_lbads(ns);
123}
124
125static inline uint16_t nvme_msize(NvmeNamespace *ns)
126{
127 return nvme_ns_lbaf(ns)->ms;
128}
129
130static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
131{
132 return nvme_msize(ns) * lba;
133}
134
135static inline bool nvme_ns_ext(NvmeNamespace *ns)
136{
137 return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
138}
139
140
141static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
142{
143 if (nvme_msize(ns)) {
144 return ns->size / (nvme_lsize(ns) + nvme_msize(ns));
145 }
146 return ns->size >> nvme_ns_lbads(ns);
147}
148
149typedef struct NvmeCtrl NvmeCtrl;
150
151static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
152{
153 return zone->d.zs >> 4;
154}
155
156static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
157{
158 zone->d.zs = state << 4;
159}
160
161static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
162{
163 return zone->d.zslba + ns->zone_size;
164}
165
166static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
167{
168 return zone->d.zslba + zone->d.zcap;
169}
170
171static inline bool nvme_wp_is_valid(NvmeZone *zone)
172{
173 uint8_t st = nvme_get_zone_state(zone);
174
175 return st != NVME_ZONE_STATE_FULL &&
176 st != NVME_ZONE_STATE_READ_ONLY &&
177 st != NVME_ZONE_STATE_OFFLINE;
178}
179
180static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
181 uint32_t zone_idx)
182{
183 return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
184}
185
186static inline void nvme_aor_inc_open(NvmeNamespace *ns)
187{
188 assert(ns->nr_open_zones >= 0);
189 if (ns->params.max_open_zones) {
190 ns->nr_open_zones++;
191 assert(ns->nr_open_zones <= ns->params.max_open_zones);
192 }
193}
194
195static inline void nvme_aor_dec_open(NvmeNamespace *ns)
196{
197 if (ns->params.max_open_zones) {
198 assert(ns->nr_open_zones > 0);
199 ns->nr_open_zones--;
200 }
201 assert(ns->nr_open_zones >= 0);
202}
203
204static inline void nvme_aor_inc_active(NvmeNamespace *ns)
205{
206 assert(ns->nr_active_zones >= 0);
207 if (ns->params.max_active_zones) {
208 ns->nr_active_zones++;
209 assert(ns->nr_active_zones <= ns->params.max_active_zones);
210 }
211}
212
213static inline void nvme_aor_dec_active(NvmeNamespace *ns)
214{
215 if (ns->params.max_active_zones) {
216 assert(ns->nr_active_zones > 0);
217 ns->nr_active_zones--;
218 assert(ns->nr_active_zones >= ns->nr_open_zones);
219 }
220 assert(ns->nr_active_zones >= 0);
221}
222
223void nvme_ns_init_format(NvmeNamespace *ns);
224int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
225void nvme_ns_drain(NvmeNamespace *ns);
226void nvme_ns_shutdown(NvmeNamespace *ns);
227void nvme_ns_cleanup(NvmeNamespace *ns);
228
229#endif
230