]> git.proxmox.com Git - ceph.git/blame - ceph/src/spdk/lib/nvme/nvme_ns.c
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / spdk / lib / nvme / nvme_ns.c
CommitLineData
7c673cae
FG
1/*-
2 * BSD LICENSE
3 *
4 * Copyright (c) Intel Corporation.
5 * 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
36static inline struct spdk_nvme_ns_data *
37_nvme_ns_get_data(struct spdk_nvme_ns *ns)
38{
39 return &ns->ctrlr->nsdata[ns->id - 1];
40}
41
11fdf7f2
TL
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 */
48void
49nvme_ns_set_identify_data(struct spdk_nvme_ns *ns)
7c673cae 50{
11fdf7f2 51 struct spdk_nvme_ns_data *nsdata;
7c673cae
FG
52
53 nsdata = _nvme_ns_get_data(ns);
7c673cae
FG
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;
11fdf7f2
TL
67
68 if (nsdata->noiob) {
69 ns->sectors_per_stripe = nsdata->noiob;
70 SPDK_DEBUGLOG(SPDK_LOG_NVME, "ns %u optimal IO boundary %" PRIu32 " blocks\n",
71 ns->id, ns->sectors_per_stripe);
72 } else if (ns->ctrlr->quirks & NVME_INTEL_QUIRK_STRIPING &&
73 ns->ctrlr->cdata.vs[3] != 0) {
74 ns->sectors_per_stripe = (1ULL << ns->ctrlr->cdata.vs[3]) * ns->ctrlr->min_page_size /
75 ns->sector_size;
76 SPDK_DEBUGLOG(SPDK_LOG_NVME, "ns %u stripe size quirk %" PRIu32 " blocks\n",
77 ns->id, ns->sectors_per_stripe);
78 } else {
79 ns->sectors_per_stripe = 0;
80 }
7c673cae
FG
81
82 if (ns->ctrlr->cdata.oncs.dsm) {
83 ns->flags |= SPDK_NVME_NS_DEALLOCATE_SUPPORTED;
84 }
85
86 if (ns->ctrlr->cdata.vwc.present) {
87 ns->flags |= SPDK_NVME_NS_FLUSH_SUPPORTED;
88 }
89
90 if (ns->ctrlr->cdata.oncs.write_zeroes) {
91 ns->flags |= SPDK_NVME_NS_WRITE_ZEROES_SUPPORTED;
92 }
93
94 if (nsdata->nsrescap.raw) {
95 ns->flags |= SPDK_NVME_NS_RESERVATION_SUPPORTED;
96 }
97
98 ns->pi_type = SPDK_NVME_FMT_NVM_PROTECTION_DISABLE;
99 if (nsdata->lbaf[nsdata->flbas.format].ms && nsdata->dps.pit) {
100 ns->flags |= SPDK_NVME_NS_DPS_PI_SUPPORTED;
101 ns->pi_type = nsdata->dps.pit;
102 }
11fdf7f2
TL
103}
104
105static int
106nvme_ctrlr_identify_ns(struct spdk_nvme_ns *ns)
107{
108 struct nvme_completion_poll_status status;
109 struct spdk_nvme_ns_data *nsdata;
110 int rc;
111
112 nsdata = _nvme_ns_get_data(ns);
113 rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS, 0, ns->id,
114 nsdata, sizeof(*nsdata),
115 nvme_completion_poll_cb, &status);
116 if (rc != 0) {
117 return rc;
118 }
119
120 if (spdk_nvme_wait_for_completion_robust_lock(ns->ctrlr->adminq, &status,
121 &ns->ctrlr->ctrlr_lock)) {
122 /* This can occur if the namespace is not active. Simply zero the
123 * namespace data and continue. */
124 nvme_ns_destruct(ns);
125 return 0;
126 }
127
128 nvme_ns_set_identify_data(ns);
129
130 return 0;
131}
132
133static int
134nvme_ctrlr_identify_id_desc(struct spdk_nvme_ns *ns)
135{
136 struct nvme_completion_poll_status status;
137 int rc;
138
139 memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list));
140
141 if (ns->ctrlr->vs.raw < SPDK_NVME_VERSION(1, 3, 0) ||
142 (ns->ctrlr->quirks & NVME_QUIRK_IDENTIFY_CNS)) {
143 SPDK_DEBUGLOG(SPDK_LOG_NVME, "Version < 1.3; not attempting to retrieve NS ID Descriptor List\n");
144 return 0;
145 }
146
147 SPDK_DEBUGLOG(SPDK_LOG_NVME, "Attempting to retrieve NS ID Descriptor List\n");
148 rc = nvme_ctrlr_cmd_identify(ns->ctrlr, SPDK_NVME_IDENTIFY_NS_ID_DESCRIPTOR_LIST, 0, ns->id,
149 ns->id_desc_list, sizeof(ns->id_desc_list),
150 nvme_completion_poll_cb, &status);
151 if (rc < 0) {
152 return rc;
153 }
154
155 rc = spdk_nvme_wait_for_completion_robust_lock(ns->ctrlr->adminq, &status, &ns->ctrlr->ctrlr_lock);
156 if (rc != 0) {
157 SPDK_WARNLOG("Failed to retrieve NS ID Descriptor List\n");
158 memset(ns->id_desc_list, 0, sizeof(ns->id_desc_list));
159 }
160
7c673cae
FG
161 return rc;
162}
163
164uint32_t
165spdk_nvme_ns_get_id(struct spdk_nvme_ns *ns)
166{
167 return ns->id;
168}
169
170bool
171spdk_nvme_ns_is_active(struct spdk_nvme_ns *ns)
172{
11fdf7f2
TL
173 const struct spdk_nvme_ns_data *nsdata = NULL;
174
175 /*
176 * According to the spec, valid NS has non-zero id.
177 */
178 if (ns->id == 0) {
179 return false;
180 }
181
182 nsdata = _nvme_ns_get_data(ns);
7c673cae
FG
183
184 /*
185 * According to the spec, Identify Namespace will return a zero-filled structure for
186 * inactive namespace IDs.
187 * Check NCAP since it must be nonzero for an active namespace.
188 */
189 return nsdata->ncap != 0;
190}
191
11fdf7f2
TL
192struct spdk_nvme_ctrlr *
193spdk_nvme_ns_get_ctrlr(struct spdk_nvme_ns *ns)
194{
195 return ns->ctrlr;
196}
197
7c673cae
FG
198uint32_t
199spdk_nvme_ns_get_max_io_xfer_size(struct spdk_nvme_ns *ns)
200{
201 return ns->ctrlr->max_xfer_size;
202}
203
204uint32_t
205spdk_nvme_ns_get_sector_size(struct spdk_nvme_ns *ns)
206{
207 return ns->sector_size;
208}
209
11fdf7f2
TL
210uint32_t
211spdk_nvme_ns_get_extended_sector_size(struct spdk_nvme_ns *ns)
212{
213 return ns->extended_lba_size;
214}
215
7c673cae
FG
216uint64_t
217spdk_nvme_ns_get_num_sectors(struct spdk_nvme_ns *ns)
218{
219 return _nvme_ns_get_data(ns)->nsze;
220}
221
222uint64_t
223spdk_nvme_ns_get_size(struct spdk_nvme_ns *ns)
224{
225 return spdk_nvme_ns_get_num_sectors(ns) * spdk_nvme_ns_get_sector_size(ns);
226}
227
228uint32_t
229spdk_nvme_ns_get_flags(struct spdk_nvme_ns *ns)
230{
231 return ns->flags;
232}
233
234enum spdk_nvme_pi_type
235spdk_nvme_ns_get_pi_type(struct spdk_nvme_ns *ns) {
236 return ns->pi_type;
237}
238
239bool
240spdk_nvme_ns_supports_extended_lba(struct spdk_nvme_ns *ns)
241{
242 return (ns->flags & SPDK_NVME_NS_EXTENDED_LBA_SUPPORTED) ? true : false;
243}
244
245uint32_t
246spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns)
247{
248 return ns->md_size;
249}
250
251const struct spdk_nvme_ns_data *
252spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns)
253{
7c673cae
FG
254 return _nvme_ns_get_data(ns);
255}
256
11fdf7f2
TL
257enum spdk_nvme_dealloc_logical_block_read_value spdk_nvme_ns_get_dealloc_logical_block_read_value(
258 struct spdk_nvme_ns *ns)
259{
260 struct spdk_nvme_ctrlr *ctrlr = ns->ctrlr;
261 const struct spdk_nvme_ns_data *data = spdk_nvme_ns_get_data(ns);
262
263 if (ctrlr->quirks & NVME_QUIRK_READ_ZERO_AFTER_DEALLOCATE) {
264 return SPDK_NVME_DEALLOC_READ_00;
265 } else {
266 return data->dlfeat.bits.read_value;
267 }
268}
269
270uint32_t
271spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns)
272{
273 return ns->sectors_per_stripe;
274}
275
276static const void *
277_spdk_nvme_ns_find_id_desc(const struct spdk_nvme_ns *ns, enum spdk_nvme_nidt type, size_t *length)
278{
279 const struct spdk_nvme_ns_id_desc *desc;
280 size_t offset;
281
282 offset = 0;
283 while (offset + 4 < sizeof(ns->id_desc_list)) {
284 desc = (const struct spdk_nvme_ns_id_desc *)&ns->id_desc_list[offset];
285
286 if (desc->nidl == 0) {
287 /* End of list */
288 return NULL;
289 }
290
291 /*
292 * Check if this descriptor fits within the list.
293 * 4 is the fixed-size descriptor header (not counted in NIDL).
294 */
295 if (offset + desc->nidl + 4 > sizeof(ns->id_desc_list)) {
296 /* Descriptor longer than remaining space in list (invalid) */
297 return NULL;
298 }
299
300 if (desc->nidt == type) {
301 *length = desc->nidl;
302 return &desc->nid[0];
303 }
304
305 offset += 4 + desc->nidl;
306 }
307
308 return NULL;
309}
310
311const struct spdk_uuid *
312spdk_nvme_ns_get_uuid(const struct spdk_nvme_ns *ns)
313{
314 const struct spdk_uuid *uuid;
315 size_t uuid_size;
316
317 uuid = _spdk_nvme_ns_find_id_desc(ns, SPDK_NVME_NIDT_UUID, &uuid_size);
318 if (uuid == NULL || uuid_size != sizeof(*uuid)) {
319 return NULL;
320 }
321
322 return uuid;
323}
324
325int nvme_ns_construct(struct spdk_nvme_ns *ns, uint32_t id,
7c673cae
FG
326 struct spdk_nvme_ctrlr *ctrlr)
327{
11fdf7f2
TL
328 int rc;
329
7c673cae
FG
330 assert(id > 0);
331
332 ns->ctrlr = ctrlr;
333 ns->id = id;
7c673cae 334
11fdf7f2
TL
335 rc = nvme_ctrlr_identify_ns(ns);
336 if (rc != 0) {
337 return rc;
7c673cae
FG
338 }
339
11fdf7f2 340 return nvme_ctrlr_identify_id_desc(ns);
7c673cae
FG
341}
342
343void nvme_ns_destruct(struct spdk_nvme_ns *ns)
344{
11fdf7f2 345 struct spdk_nvme_ns_data *nsdata;
7c673cae 346
11fdf7f2
TL
347 if (!ns->id) {
348 return;
349 }
350
351 nsdata = _nvme_ns_get_data(ns);
352 memset(nsdata, 0, sizeof(*nsdata));
353 ns->sector_size = 0;
354 ns->extended_lba_size = 0;
355 ns->md_size = 0;
356 ns->pi_type = 0;
357 ns->sectors_per_max_io = 0;
358 ns->sectors_per_stripe = 0;
359 ns->flags = 0;
7c673cae 360}