Line data Source code
1 : /*
2 : * Copyright (C) 2014-2021 Red Hat, Inc.
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Lesser General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2.1 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Lesser General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Lesser General Public
15 : * License along with this library; if not, see <http://www.gnu.org/licenses/>.
16 : *
17 : * Author: Tomas Bzatek <tbzatek@redhat.com>
18 : */
19 :
20 : #include <glib.h>
21 : #include <string.h>
22 : #include <stdio.h>
23 : #include <unistd.h>
24 : #include <sys/ioctl.h>
25 : #include <sys/stat.h>
26 : #include <errno.h>
27 : #include <fcntl.h>
28 : #include <malloc.h>
29 : #include <linux/fs.h>
30 :
31 : #include <libnvme.h>
32 :
33 : #include <blockdev/utils.h>
34 : #include <check_deps.h>
35 : #include "nvme.h"
36 : #include "nvme-private.h"
37 :
38 :
39 : /**
40 : * bd_nvme_device_self_test:
41 : * @device: a NVMe controller or namespace device (e.g. `/dev/nvme0`)
42 : * @action: self-test action to take.
43 : * @error: (out) (nullable): place to store error (if any)
44 : *
45 : * Initiates or aborts the Device Self-test operation on the controller or a namespace,
46 : * distinguished by the @device path specified. In case a controller device
47 : * is specified then the self-test operation would include all active namespaces.
48 : *
49 : * To abort a running operation, pass #BD_NVME_SELF_TEST_ACTION_ABORT as @action.
50 : * To retrieve progress of a current running operation, check the self-test log using
51 : * bd_nvme_get_self_test_log().
52 : *
53 : * Returns: %TRUE if the device self-test command was issued successfully,
54 : * %FALSE otherwise with @error set.
55 : *
56 : * Tech category: %BD_NVME_TECH_NVME-%BD_NVME_TECH_MODE_MANAGE
57 : */
58 11 : gboolean bd_nvme_device_self_test (const gchar *device, BDNVMESelfTestAction action, GError **error) {
59 : int ret;
60 11 : struct nvme_dev_self_test_args args = {
61 : .args_size = sizeof(args),
62 : .result = NULL,
63 : .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
64 : .nsid = 0xffffffff,
65 : };
66 :
67 11 : switch (action) {
68 3 : case BD_NVME_SELF_TEST_ACTION_SHORT:
69 3 : args.stc = NVME_DST_STC_SHORT;
70 3 : break;
71 2 : case BD_NVME_SELF_TEST_ACTION_EXTENDED:
72 2 : args.stc = NVME_DST_STC_LONG;
73 2 : break;
74 2 : case BD_NVME_SELF_TEST_ACTION_VENDOR_SPECIFIC:
75 2 : args.stc = NVME_DST_STC_VS;
76 2 : break;
77 2 : case BD_NVME_SELF_TEST_ACTION_ABORT:
78 2 : args.stc = NVME_DST_STC_ABORT;
79 2 : break;
80 2 : default:
81 2 : g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT,
82 : "Invalid value specified for the self-test action: %d", action);
83 2 : return FALSE;
84 : }
85 :
86 : /* open the block device */
87 9 : args.fd = _open_dev (device, error);
88 9 : if (args.fd < 0)
89 1 : return FALSE;
90 :
91 : /* get Namespace Identifier (NSID) for the @device (NVME_IOCTL_ID) */
92 8 : ret = nvme_get_nsid (args.fd, &args.nsid);
93 8 : if (ret < 0 && errno == ENOTTY)
94 : /* not a block device, assuming controller character device */
95 4 : args.nsid = 0xffffffff;
96 4 : else if (ret != 0) {
97 0 : _nvme_status_to_error (ret, FALSE, error);
98 0 : g_prefix_error (error, "Error getting Namespace Identifier (NSID): ");
99 0 : close (args.fd);
100 0 : return FALSE;
101 : }
102 :
103 8 : ret = nvme_dev_self_test (&args);
104 8 : if (ret != 0) {
105 8 : _nvme_status_to_error (ret, FALSE, error);
106 8 : g_prefix_error (error, "NVMe Device Self-test command error: ");
107 8 : close (args.fd);
108 8 : return FALSE;
109 : }
110 0 : close (args.fd);
111 :
112 0 : return TRUE;
113 : }
114 :
115 :
116 : /* returns 0xff in case of error (the NVMe standard defines total of 16 flba records) */
117 4 : static __u8 find_lbaf_for_size (int fd, __u32 nsid, guint16 lba_data_size, guint16 metadata_size, GError **error) {
118 : int ret;
119 : struct nvme_id_ns *ns_info;
120 4 : __u8 flbas = 0;
121 : guint i;
122 :
123 : /* TODO: find first attached namespace instead of hardcoding NSID = 1 */
124 4 : ns_info = _nvme_alloc (sizeof (struct nvme_id_ns), error);
125 4 : if (!ns_info)
126 0 : return 0xff;
127 4 : ret = nvme_identify_ns (fd, nsid == 0xffffffff ? 1 : nsid, ns_info);
128 4 : if (ret != 0) {
129 0 : _nvme_status_to_error (ret, FALSE, error);
130 0 : g_prefix_error (error, "NVMe Identify Namespace command error: ");
131 0 : free (ns_info);
132 0 : return 0xff;
133 : }
134 :
135 : /* return currently used lbaf */
136 4 : if (lba_data_size == 0) {
137 2 : nvme_id_ns_flbas_to_lbaf_inuse (ns_info->flbas, &flbas);
138 2 : free (ns_info);
139 2 : return flbas;
140 : }
141 :
142 4 : for (i = 0; i <= ns_info->nlbaf + ns_info->nulbaf; i++)
143 2 : if (1UL << ns_info->lbaf[i].ds == lba_data_size && GUINT16_FROM_LE (ns_info->lbaf[i].ms) == metadata_size) {
144 0 : free (ns_info);
145 0 : return i;
146 : }
147 :
148 2 : g_set_error_literal (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT,
149 : "Couldn't match desired LBA data block size in a device supported LBA format data sizes");
150 2 : free (ns_info);
151 2 : return 0xff;
152 : }
153 :
154 : /**
155 : * bd_nvme_format:
156 : * @device: NVMe namespace or controller device to format (e.g. `/dev/nvme0n1`)
157 : * @lba_data_size: desired LBA data size (i.e. a sector size) in bytes or `0` to keep current. See #BDNVMELBAFormat and bd_nvme_get_namespace_info().
158 : * @metadata_size: desired metadata size in bytes or `0` for default. See #BDNVMELBAFormat and bd_nvme_get_namespace_info().
159 : * @secure_erase: optional secure erase action to take.
160 : * @error: (out) (nullable): place to store error (if any)
161 : *
162 : * Performs low level format of the NVM media, destroying all data and metadata for either
163 : * a specific namespace or all attached namespaces to the controller. Use this command
164 : * to change LBA sector size. Optional secure erase method can be specified as well.
165 : *
166 : * Supported LBA data sizes for a given namespace can be listed using the bd_nvme_get_namespace_info()
167 : * call. In case of a special value `0` the current LBA format for a given namespace will be
168 : * retained. When called on a controller device the first namespace is used as a reference.
169 : *
170 : * Note that the NVMe controller may define a Format NVM attribute indicating that the format
171 : * operation would apply to all namespaces and a format (excluding secure erase) of any
172 : * namespace results in a format of all namespaces in the NVM subsystem. In such case and
173 : * when @device is a namespace block device the #BD_NVME_ERROR_WOULD_FORMAT_ALL_NS error
174 : * is returned to prevent further damage. This is then supposed to be handled by the caller
175 : * and bd_nvme_format() is supposed to be called on a controller device instead.
176 : *
177 : * This call blocks until the format operation has finished. To retrieve progress
178 : * of a current running operation, check the namespace info using bd_nvme_get_namespace_info().
179 : *
180 : * Returns: %TRUE if the format command finished successfully, %FALSE otherwise with @error set.
181 : *
182 : * Tech category: %BD_NVME_TECH_NVME-%BD_NVME_TECH_MODE_MANAGE
183 : */
184 5 : gboolean bd_nvme_format (const gchar *device, guint16 lba_data_size, guint16 metadata_size, BDNVMEFormatSecureErase secure_erase, GError **error) {
185 : int ret;
186 5 : gboolean ctrl_device = FALSE;
187 : struct nvme_id_ctrl *ctrl_id;
188 5 : struct nvme_format_nvm_args args = {
189 : .args_size = sizeof(args),
190 : .result = NULL,
191 : .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
192 : .nsid = 0xffffffff,
193 : .mset = NVME_FORMAT_MSET_SEPARATE /* 0 */,
194 : .pi = NVME_FORMAT_PI_DISABLE /* 0 */,
195 : .pil = NVME_FORMAT_PIL_LAST /* 0 */,
196 : .ses = NVME_FORMAT_SES_NONE,
197 : };
198 :
199 : /* open the block device */
200 5 : args.fd = _open_dev (device, error);
201 5 : if (args.fd < 0)
202 1 : return FALSE;
203 :
204 4 : ret = nvme_get_nsid (args.fd, &args.nsid);
205 4 : if (ret < 0 && errno == ENOTTY) {
206 : /* not a block device, assuming controller character device */
207 2 : args.nsid = 0xffffffff;
208 2 : ctrl_device = TRUE;
209 2 : } else if (ret != 0) {
210 0 : _nvme_status_to_error (ret, FALSE, error);
211 0 : g_prefix_error (error, "Error getting Namespace Identifier (NSID): ");
212 0 : close (args.fd);
213 0 : return FALSE;
214 : }
215 :
216 : /* check the FNA controller bit when formatting a single namespace */
217 4 : if (! ctrl_device) {
218 2 : ctrl_id = _nvme_alloc (sizeof (struct nvme_id_ctrl), error);
219 2 : if (!ctrl_id) {
220 0 : close (args.fd);
221 0 : return FALSE;
222 : }
223 2 : ret = nvme_identify_ctrl (args.fd, ctrl_id);
224 2 : if (ret != 0) {
225 0 : _nvme_status_to_error (ret, FALSE, error);
226 0 : g_prefix_error (error, "NVMe Identify Controller command error: ");
227 0 : close (args.fd);
228 0 : free (ctrl_id);
229 0 : return FALSE;
230 : }
231 : /* from nvme-cli:
232 : * FNA bit 0 set to 1: all namespaces ... shall be configured with the same
233 : * attributes and a format (excluding secure erase) of any namespace results in a
234 : * format of all namespaces.
235 : */
236 2 : if ((ctrl_id->fna & NVME_CTRL_FNA_FMT_ALL_NAMESPACES) == NVME_CTRL_FNA_FMT_ALL_NAMESPACES) {
237 : /* tell user that it would format other namespaces and that bd_nvme_format()
238 : * should be called on a controller device instead */
239 0 : g_set_error_literal (error, BD_NVME_ERROR, BD_NVME_ERROR_WOULD_FORMAT_ALL_NS,
240 : "The NVMe controller indicates it would format all namespaces.");
241 0 : close (args.fd);
242 0 : free (ctrl_id);
243 0 : return FALSE;
244 : }
245 2 : free (ctrl_id);
246 : }
247 :
248 : /* find out the desired LBA data format index */
249 4 : args.lbaf = find_lbaf_for_size (args.fd, args.nsid, lba_data_size, metadata_size, error);
250 4 : if (args.lbaf == 0xff) {
251 2 : close (args.fd);
252 2 : return FALSE;
253 : }
254 :
255 2 : switch (secure_erase) {
256 0 : case BD_NVME_FORMAT_SECURE_ERASE_USER_DATA:
257 0 : args.ses = NVME_FORMAT_SES_USER_DATA_ERASE;
258 0 : break;
259 0 : case BD_NVME_FORMAT_SECURE_ERASE_CRYPTO:
260 0 : args.ses = NVME_FORMAT_SES_CRYPTO_ERASE;
261 0 : break;
262 2 : case BD_NVME_FORMAT_SECURE_ERASE_NONE:
263 : default:
264 2 : args.ses = NVME_FORMAT_SES_NONE;
265 : }
266 :
267 2 : ret = nvme_format_nvm (&args);
268 2 : if (ret != 0) {
269 2 : _nvme_status_to_error (ret, FALSE, error);
270 2 : g_prefix_error (error, "Format NVM command error: ");
271 2 : close (args.fd);
272 2 : return FALSE;
273 : }
274 :
275 : /* rescan the namespaces if block size has changed */
276 0 : if (ctrl_device) {
277 0 : if (ioctl (args.fd, NVME_IOCTL_RESCAN) < 0) {
278 0 : g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED,
279 0 : "Failed to rescan namespaces after format: %s", strerror_l (errno, _C_LOCALE));
280 0 : close (args.fd);
281 0 : return FALSE;
282 : }
283 : } else {
284 0 : if (lba_data_size != 0) {
285 : /* from nvme-cli:
286 : * If block size has been changed by the format command up there, we should notify it to
287 : * kernel blkdev to update its own block size to the given one because blkdev will not
288 : * update by itself without re-opening fd.
289 : */
290 0 : int block_size = lba_data_size;
291 :
292 0 : if (ioctl (args.fd, BLKBSZSET, &block_size) < 0) {
293 0 : g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED,
294 0 : "Failed to set block size to %d after format: %s", block_size, strerror_l (errno, _C_LOCALE));
295 0 : close (args.fd);
296 0 : return FALSE;
297 : }
298 :
299 0 : if (ioctl (args.fd, BLKRRPART) < 0) {
300 0 : g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_FAILED,
301 0 : "Failed to re-read partition table after format: %s", strerror_l (errno, _C_LOCALE));
302 0 : close (args.fd);
303 0 : return FALSE;
304 : }
305 : }
306 : }
307 :
308 0 : close (args.fd);
309 0 : return TRUE;
310 : }
311 :
312 : /**
313 : * bd_nvme_sanitize:
314 : * @device: NVMe namespace or controller device to format (e.g. `/dev/nvme0n1`)
315 : * @action: the sanitize action to perform.
316 : * @no_dealloc: instruct the controller to not deallocate the affected media area.
317 : * @overwrite_pass_count: number of overwrite passes [1-15] or 0 for the default (16 passes).
318 : * @overwrite_pattern: a 32-bit pattern used for the Overwrite sanitize operation.
319 : * @overwrite_invert_pattern: invert the overwrite pattern between passes.
320 : * @error: (out) (nullable): place to store error (if any)
321 : *
322 : * Starts a sanitize operation or recovers from a previously failed sanitize operation.
323 : * By definition, a sanitize operation alters all user data in the NVM subsystem such
324 : * that recovery of any previous user data from any cache, the non-volatile media,
325 : * or any Controller Memory Buffer is not possible. The scope of a sanitize operation
326 : * is all locations in the NVM subsystem that are able to contain user data, including
327 : * caches, Persistent Memory Regions, and unallocated or deallocated areas of the media.
328 : *
329 : * Once started, a sanitize operation is not able to be aborted and continues after
330 : * a Controller Level Reset including across power cycles. Once the sanitize operation
331 : * has run the media affected may not be immediately ready for use unless additional
332 : * media modification mechanism is run. This is often vendor specific and also depends
333 : * on the sanitize method (@action) used. Callers to this sanitize operation should
334 : * set @no_dealloc to %TRUE for the added convenience.
335 : *
336 : * The controller also ignores Critical Warning(s) in the SMART / Health Information
337 : * log page (e.g., read only mode) and attempts to complete the sanitize operation requested.
338 : *
339 : * This call returns immediately and the actual sanitize operation is performed
340 : * in the background. Use bd_nvme_get_sanitize_log() to retrieve status and progress
341 : * of a running sanitize operation. In case a sanitize operation fails the controller
342 : * may restrict its operation until a subsequent sanitize operation is started
343 : * (i.e. retried) or an #BD_NVME_SANITIZE_ACTION_EXIT_FAILURE action is used
344 : * to acknowledge the failure explicitly.
345 : *
346 : * The @overwrite_pass_count, @overwrite_pattern and @overwrite_invert_pattern
347 : * arguments are only valid when @action is #BD_NVME_SANITIZE_ACTION_OVERWRITE.
348 : *
349 : * The sanitize operation is set to run under the Allow Unrestricted Sanitize Exit
350 : * mode.
351 : *
352 : * Returns: %TRUE if the format command finished successfully, %FALSE otherwise with @error set.
353 : *
354 : * Tech category: %BD_NVME_TECH_NVME-%BD_NVME_TECH_MODE_MANAGE
355 : */
356 9 : gboolean bd_nvme_sanitize (const gchar *device, BDNVMESanitizeAction action, gboolean no_dealloc, gint overwrite_pass_count, guint32 overwrite_pattern, gboolean overwrite_invert_pattern, GError **error) {
357 : int ret;
358 9 : struct nvme_sanitize_nvm_args args = {
359 : .args_size = sizeof(args),
360 : .result = NULL,
361 : .timeout = NVME_DEFAULT_IOCTL_TIMEOUT,
362 : .ause = TRUE,
363 : .owpass = overwrite_pass_count,
364 9 : .oipbp = overwrite_invert_pattern,
365 9 : .nodas = no_dealloc,
366 : .ovrpat = GUINT32_TO_LE (overwrite_pattern),
367 : };
368 :
369 9 : switch (action) {
370 2 : case BD_NVME_SANITIZE_ACTION_EXIT_FAILURE:
371 2 : args.sanact = NVME_SANITIZE_SANACT_EXIT_FAILURE;
372 2 : break;
373 3 : case BD_NVME_SANITIZE_ACTION_BLOCK_ERASE:
374 3 : args.sanact = NVME_SANITIZE_SANACT_START_BLOCK_ERASE;
375 3 : break;
376 2 : case BD_NVME_SANITIZE_ACTION_OVERWRITE:
377 2 : args.sanact = NVME_SANITIZE_SANACT_START_OVERWRITE;
378 2 : break;
379 2 : case BD_NVME_SANITIZE_ACTION_CRYPTO_ERASE:
380 2 : args.sanact = NVME_SANITIZE_SANACT_START_CRYPTO_ERASE;
381 2 : break;
382 0 : default:
383 0 : g_set_error (error, BD_NVME_ERROR, BD_NVME_ERROR_INVALID_ARGUMENT,
384 : "Invalid value specified for the sanitize action: %d", action);
385 0 : return FALSE;
386 : }
387 :
388 : /* open the block device */
389 9 : args.fd = _open_dev (device, error);
390 9 : if (args.fd < 0)
391 1 : return FALSE;
392 :
393 8 : ret = nvme_sanitize_nvm (&args);
394 8 : if (ret != 0) {
395 8 : _nvme_status_to_error (ret, FALSE, error);
396 8 : g_prefix_error (error, "Sanitize command error: ");
397 8 : close (args.fd);
398 8 : return FALSE;
399 : }
400 :
401 0 : close (args.fd);
402 0 : return TRUE;
403 : }
|