1 /*
2  * QEMU NVM Express Virtual Namespace
3  *
4  * Copyright (c) 2019 CNEX Labs
5  * Copyright (c) 2020 Samsung Electronics
6  *
7  * Authors:
8  *  Klaus Jensen      <k.jensen@samsung.com>
9  *
10  * This work is licensed under the terms of the GNU GPL, version 2. See the
11  * COPYING file in the top-level directory.
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 
24 typedef struct NvmeZone {
25     NvmeZoneDescr   d;
26     uint64_t        w_ptr;
27     QTAILQ_ENTRY(NvmeZone) entry;
28 } NvmeZone;
29 
30 typedef 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 
54 typedef 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 
nvme_ns_status(NvmeNamespace * ns)89 static inline uint16_t nvme_ns_status(NvmeNamespace *ns)
90 {
91     return ns->status;
92 }
93 
nvme_nsid(NvmeNamespace * ns)94 static inline uint32_t nvme_nsid(NvmeNamespace *ns)
95 {
96     if (ns) {
97         return ns->params.nsid;
98     }
99 
100     return 0;
101 }
102 
nvme_ns_lbaf(NvmeNamespace * ns)103 static 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 
nvme_ns_lbads(NvmeNamespace * ns)109 static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
110 {
111     return nvme_ns_lbaf(ns)->ds;
112 }
113 
114 /* convert an LBA to the equivalent in bytes */
nvme_l2b(NvmeNamespace * ns,uint64_t lba)115 static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
116 {
117     return lba << nvme_ns_lbads(ns);
118 }
119 
nvme_lsize(NvmeNamespace * ns)120 static inline size_t nvme_lsize(NvmeNamespace *ns)
121 {
122     return 1 << nvme_ns_lbads(ns);
123 }
124 
nvme_msize(NvmeNamespace * ns)125 static inline uint16_t nvme_msize(NvmeNamespace *ns)
126 {
127     return nvme_ns_lbaf(ns)->ms;
128 }
129 
nvme_m2b(NvmeNamespace * ns,uint64_t lba)130 static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
131 {
132     return nvme_msize(ns) * lba;
133 }
134 
nvme_ns_ext(NvmeNamespace * ns)135 static inline bool nvme_ns_ext(NvmeNamespace *ns)
136 {
137     return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
138 }
139 
140 /* calculate the number of LBAs that the namespace can accomodate */
nvme_ns_nlbas(NvmeNamespace * ns)141 static 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 
149 typedef struct NvmeCtrl NvmeCtrl;
150 
nvme_get_zone_state(NvmeZone * zone)151 static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
152 {
153     return zone->d.zs >> 4;
154 }
155 
nvme_set_zone_state(NvmeZone * zone,NvmeZoneState state)156 static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
157 {
158     zone->d.zs = state << 4;
159 }
160 
nvme_zone_rd_boundary(NvmeNamespace * ns,NvmeZone * zone)161 static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
162 {
163     return zone->d.zslba + ns->zone_size;
164 }
165 
nvme_zone_wr_boundary(NvmeZone * zone)166 static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
167 {
168     return zone->d.zslba + zone->d.zcap;
169 }
170 
nvme_wp_is_valid(NvmeZone * zone)171 static 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 
nvme_get_zd_extension(NvmeNamespace * ns,uint32_t zone_idx)180 static 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 
nvme_aor_inc_open(NvmeNamespace * ns)186 static 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 
nvme_aor_dec_open(NvmeNamespace * ns)195 static 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 
nvme_aor_inc_active(NvmeNamespace * ns)204 static 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 
nvme_aor_dec_active(NvmeNamespace * ns)213 static 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 
223 void nvme_ns_init_format(NvmeNamespace *ns);
224 int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
225 void nvme_ns_drain(NvmeNamespace *ns);
226 void nvme_ns_shutdown(NvmeNamespace *ns);
227 void nvme_ns_cleanup(NvmeNamespace *ns);
228 
229 #endif /* NVME_NS_H */
230