]>
Commit | Line | Data |
---|---|---|
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 | ||
36 | static 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 | */ | |
48 | void | |
49 | nvme_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 | ||
105 | static int | |
106 | nvme_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 | ||
133 | static int | |
134 | nvme_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 | ||
164 | uint32_t | |
165 | spdk_nvme_ns_get_id(struct spdk_nvme_ns *ns) | |
166 | { | |
167 | return ns->id; | |
168 | } | |
169 | ||
170 | bool | |
171 | spdk_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 |
192 | struct spdk_nvme_ctrlr * |
193 | spdk_nvme_ns_get_ctrlr(struct spdk_nvme_ns *ns) | |
194 | { | |
195 | return ns->ctrlr; | |
196 | } | |
197 | ||
7c673cae FG |
198 | uint32_t |
199 | spdk_nvme_ns_get_max_io_xfer_size(struct spdk_nvme_ns *ns) | |
200 | { | |
201 | return ns->ctrlr->max_xfer_size; | |
202 | } | |
203 | ||
204 | uint32_t | |
205 | spdk_nvme_ns_get_sector_size(struct spdk_nvme_ns *ns) | |
206 | { | |
207 | return ns->sector_size; | |
208 | } | |
209 | ||
11fdf7f2 TL |
210 | uint32_t |
211 | spdk_nvme_ns_get_extended_sector_size(struct spdk_nvme_ns *ns) | |
212 | { | |
213 | return ns->extended_lba_size; | |
214 | } | |
215 | ||
7c673cae FG |
216 | uint64_t |
217 | spdk_nvme_ns_get_num_sectors(struct spdk_nvme_ns *ns) | |
218 | { | |
219 | return _nvme_ns_get_data(ns)->nsze; | |
220 | } | |
221 | ||
222 | uint64_t | |
223 | spdk_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 | ||
228 | uint32_t | |
229 | spdk_nvme_ns_get_flags(struct spdk_nvme_ns *ns) | |
230 | { | |
231 | return ns->flags; | |
232 | } | |
233 | ||
234 | enum spdk_nvme_pi_type | |
235 | spdk_nvme_ns_get_pi_type(struct spdk_nvme_ns *ns) { | |
236 | return ns->pi_type; | |
237 | } | |
238 | ||
239 | bool | |
240 | spdk_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 | ||
245 | uint32_t | |
246 | spdk_nvme_ns_get_md_size(struct spdk_nvme_ns *ns) | |
247 | { | |
248 | return ns->md_size; | |
249 | } | |
250 | ||
251 | const struct spdk_nvme_ns_data * | |
252 | spdk_nvme_ns_get_data(struct spdk_nvme_ns *ns) | |
253 | { | |
7c673cae FG |
254 | return _nvme_ns_get_data(ns); |
255 | } | |
256 | ||
11fdf7f2 TL |
257 | enum 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 | ||
270 | uint32_t | |
271 | spdk_nvme_ns_get_optimal_io_boundary(struct spdk_nvme_ns *ns) | |
272 | { | |
273 | return ns->sectors_per_stripe; | |
274 | } | |
275 | ||
276 | static 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 | ||
311 | const struct spdk_uuid * | |
312 | spdk_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 | ||
325 | int 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 | ||
343 | void 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 | } |