Skip to content

Commit 22db7b7

Browse files
Tomasz Bursztykacarlescufi
Tomasz Bursztyka
authored andcommitted
drivers/nvme: Add namespace support
Based on FreeBSD's implementation made by James Harris, Intel Copyright 2012-2016. Namespace in this context, will be a disk. It's not exposed from DTS, as an actualy NVMe hardware controller card can bring more than one namespace (disk). Thus namespace are not instanciated through the device driver model, but statically allocated and runtime configured, depending on what the controller exposes. By default the amount of namespace supported is one as it is the most common setup. Signed-off-by: Tomasz Bursztyka <[email protected]>
1 parent 7499fae commit 22db7b7

9 files changed

+518
-3
lines changed

drivers/disk/nvme/CMakeLists.txt

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
# Copyright (c) 2022 Intel Corporation
22
# SPDX-License-Identifier: Apache-2.0
33

4-
zephyr_library_sources(nvme_controller.c nvme_cmd.c nvme_controller_cmd.c)
4+
zephyr_library_sources(
5+
nvme_controller.c
6+
nvme_cmd.c
7+
nvme_controller_cmd.c
8+
nvme_namespace.c
9+
)

drivers/disk/nvme/Kconfig

+9
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,15 @@ config NVME_REQUEST_TIMEOUT
5252
This sets the waiting time for a request to succeed.
5353
Do not touch this unless you know what you are doing.
5454

55+
config NVME_MAX_NAMESPACES
56+
int "Maximum namespace to allocate"
57+
range 1 16
58+
default 1
59+
help
60+
This sets the maximum namespace to allocate. Note that there may
61+
be much less to be actually instantiated at runtime.
62+
This option can be used to reduce the memory usage a bit then.
63+
5564
config NVME_INT_PRIORITY
5665
int "Interrupt priority"
5766
default 2

drivers/disk/nvme/nvme.h

+12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
#ifndef ZEPHYR_DRIVERS_DISK_NVME_NHME_H_
88
#define ZEPHYR_DRIVERS_DISK_NVME_NVME_H_
99

10+
#include "nvme_helpers.h"
1011
#include "nvme_cmd.h"
12+
#include "nvme_namespace.h"
1113

1214
struct nvme_registers {
1315
uint32_t cap_lo; /* controller capabilities */
@@ -444,6 +446,16 @@ struct nvme_controller {
444446

445447
/** maximum i/o size in bytes */
446448
uint32_t max_xfer_size;
449+
450+
struct nvme_namespace ns[CONFIG_NVME_MAX_NAMESPACES];
447451
};
448452

453+
static inline
454+
bool nvme_controller_has_dataset_mgmt(struct nvme_controller *ctrlr)
455+
{
456+
/* Assumes cd was byte swapped by nvme_controller_data_swapbytes() */
457+
return ((ctrlr->cdata.oncs >> NVME_CTRLR_DATA_ONCS_DSM_SHIFT) &
458+
NVME_CTRLR_DATA_ONCS_DSM_MASK);
459+
}
460+
449461
#endif /* ZEPHYR_DRIVERS_DISK_NVME_NHME_H_ */

drivers/disk/nvme/nvme_cmd.h

+4
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,10 @@ int nvme_cmd_identify_controller(struct nvme_controller *ctrlr,
382382
int nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr,
383383
nvme_cb_fn_t cb_fn, void *cb_arg);
384384

385+
int nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr,
386+
uint32_t nsid, void *payload,
387+
nvme_cb_fn_t cb_fn, void *cb_arg);
388+
385389
int nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr,
386390
struct nvme_cmd_qpair *io_queue,
387391
nvme_cb_fn_t cb_fn, void *cb_arg);

drivers/disk/nvme/nvme_controller.c

+18
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,22 @@ static int nvme_controller_identify(struct nvme_controller *nvme_ctrlr)
394394
return 0;
395395
}
396396

397+
static void nvme_controller_setup_namespaces(struct nvme_controller *nvme_ctrlr)
398+
{
399+
uint32_t i;
400+
401+
for (i = 0;
402+
i < MIN(nvme_ctrlr->cdata.nn, CONFIG_NVME_MAX_NAMESPACES); i++) {
403+
struct nvme_namespace *ns = &nvme_ctrlr->ns[i];
404+
405+
if (nvme_namespace_construct(ns, i+1, nvme_ctrlr) != 0) {
406+
break;
407+
}
408+
409+
LOG_DBG("Namespace id %u setup and running", i);
410+
}
411+
}
412+
397413
static int nvme_controller_init(const struct device *dev)
398414
{
399415
struct nvme_controller *nvme_ctrlr = dev->data;
@@ -437,6 +453,8 @@ static int nvme_controller_init(const struct device *dev)
437453
return ret;
438454
}
439455

456+
nvme_controller_setup_namespaces(nvme_ctrlr);
457+
440458
return 0;
441459
}
442460

drivers/disk/nvme/nvme_controller_cmd.c

+25-2
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,14 @@
33
* Copyright (c) 2022 Intel Corp.
44
*/
55

6-
#define LOG_LEVEL CONFIG_NVME_LOG_LEVEL
76
#include <zephyr/logging/log.h>
8-
LOG_MODULE_REGISTER(nvme_ctrlr_cmd);
7+
LOG_MODULE_DECLARE(nvme, CONFIG_NVME_LOG_LEVEL);
98

109
#include <zephyr/kernel.h>
1110
#include <zephyr/sys/byteorder.h>
1211

12+
#include <string.h>
13+
1314
#include "nvme.h"
1415
#include "nvme_helpers.h"
1516

@@ -32,6 +33,28 @@ int nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr,
3233
return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
3334
}
3435

36+
int nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr,
37+
uint32_t nsid, void *payload,
38+
nvme_cb_fn_t cb_fn, void *cb_arg)
39+
{
40+
struct nvme_request *request;
41+
42+
request = nvme_allocate_request_vaddr(
43+
payload, sizeof(struct nvme_namespace_data),
44+
cb_fn, cb_arg);
45+
if (!request) {
46+
return -ENOMEM;
47+
}
48+
49+
request->cmd.cdw0.opc = NVME_OPC_IDENTIFY;
50+
/*
51+
* TODO: create an identify command data structure
52+
*/
53+
request->cmd.nsid = sys_cpu_to_le32(nsid);
54+
55+
return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
56+
}
57+
3558
int nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr,
3659
struct nvme_cmd_qpair *io_queue,
3760
nvme_cb_fn_t cb_fn, void *cb_arg)

drivers/disk/nvme/nvme_helpers.h

+127
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
#define NVME_MAJOR(r) (((r) >> 16) & 0xffff)
1616
#define NVME_MINOR(r) (((r) >> 8) & 0xff)
1717

18+
/*
19+
* Use to mark a command to apply to all namespaces, or to retrieve global
20+
* log pages.
21+
*/
22+
#define NVME_GLOBAL_NAMESPACE_TAG ((uint32_t)0xFFFFFFFF)
23+
1824
/* Many items are expressed in terms of power of two times MPS */
1925
#define NVME_MPS_SHIFT 12
2026

@@ -342,6 +348,127 @@
342348
#define NVME_CTRLR_DATA_VWC_ALL_NO (2)
343349
#define NVME_CTRLR_DATA_VWC_ALL_YES (3)
344350

351+
/** namespace features */
352+
/* thin provisioning */
353+
#define NVME_NS_DATA_NSFEAT_THIN_PROV_SHIFT (0)
354+
#define NVME_NS_DATA_NSFEAT_THIN_PROV_MASK (0x1)
355+
/* NAWUN, NAWUPF, and NACWU fields are valid */
356+
#define NVME_NS_DATA_NSFEAT_NA_FIELDS_SHIFT (1)
357+
#define NVME_NS_DATA_NSFEAT_NA_FIELDS_MASK (0x1)
358+
/* Deallocated or Unwritten Logical Block errors supported */
359+
#define NVME_NS_DATA_NSFEAT_DEALLOC_SHIFT (2)
360+
#define NVME_NS_DATA_NSFEAT_DEALLOC_MASK (0x1)
361+
/* NGUID and EUI64 fields are not reusable */
362+
#define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_SHIFT (3)
363+
#define NVME_NS_DATA_NSFEAT_NO_ID_REUSE_MASK (0x1)
364+
/* NPWG, NPWA, NPDG, NPDA, and NOWS are valid */
365+
#define NVME_NS_DATA_NSFEAT_NPVALID_SHIFT (4)
366+
#define NVME_NS_DATA_NSFEAT_NPVALID_MASK (0x1)
367+
368+
/** formatted lba size */
369+
#define NVME_NS_DATA_FLBAS_FORMAT_SHIFT (0)
370+
#define NVME_NS_DATA_FLBAS_FORMAT_MASK (0xF)
371+
#define NVME_NS_DATA_FLBAS_EXTENDED_SHIFT (4)
372+
#define NVME_NS_DATA_FLBAS_EXTENDED_MASK (0x1)
373+
374+
/** metadata capabilities */
375+
/* metadata can be transferred as part of data prp list */
376+
#define NVME_NS_DATA_MC_EXTENDED_SHIFT (0)
377+
#define NVME_NS_DATA_MC_EXTENDED_MASK (0x1)
378+
/* metadata can be transferred with separate metadata pointer */
379+
#define NVME_NS_DATA_MC_POINTER_SHIFT (1)
380+
#define NVME_NS_DATA_MC_POINTER_MASK (0x1)
381+
382+
/** end-to-end data protection capabilities */
383+
/* protection information type 1 */
384+
#define NVME_NS_DATA_DPC_PIT1_SHIFT (0)
385+
#define NVME_NS_DATA_DPC_PIT1_MASK (0x1)
386+
/* protection information type 2 */
387+
#define NVME_NS_DATA_DPC_PIT2_SHIFT (1)
388+
#define NVME_NS_DATA_DPC_PIT2_MASK (0x1)
389+
/* protection information type 3 */
390+
#define NVME_NS_DATA_DPC_PIT3_SHIFT (2)
391+
#define NVME_NS_DATA_DPC_PIT3_MASK (0x1)
392+
/* first eight bytes of metadata */
393+
#define NVME_NS_DATA_DPC_MD_START_SHIFT (3)
394+
#define NVME_NS_DATA_DPC_MD_START_MASK (0x1)
395+
/* last eight bytes of metadata */
396+
#define NVME_NS_DATA_DPC_MD_END_SHIFT (4)
397+
#define NVME_NS_DATA_DPC_MD_END_MASK (0x1)
398+
399+
/** end-to-end data protection type settings */
400+
/* protection information type */
401+
#define NVME_NS_DATA_DPS_PIT_SHIFT (0)
402+
#define NVME_NS_DATA_DPS_PIT_MASK (0x7)
403+
/* 1 == protection info transferred at start of metadata */
404+
/* 0 == protection info transferred at end of metadata */
405+
#define NVME_NS_DATA_DPS_MD_START_SHIFT (3)
406+
#define NVME_NS_DATA_DPS_MD_START_MASK (0x1)
407+
408+
/** Namespace Multi-path I/O and Namespace Sharing Capabilities */
409+
/* the namespace may be attached to two or more controllers */
410+
#define NVME_NS_DATA_NMIC_MAY_BE_SHARED_SHIFT (0)
411+
#define NVME_NS_DATA_NMIC_MAY_BE_SHARED_MASK (0x1)
412+
413+
/** Reservation Capabilities */
414+
/* Persist Through Power Loss */
415+
#define NVME_NS_DATA_RESCAP_PTPL_SHIFT (0)
416+
#define NVME_NS_DATA_RESCAP_PTPL_MASK (0x1)
417+
/* supports the Write Exclusive */
418+
#define NVME_NS_DATA_RESCAP_WR_EX_SHIFT (1)
419+
#define NVME_NS_DATA_RESCAP_WR_EX_MASK (0x1)
420+
/* supports the Exclusive Access */
421+
#define NVME_NS_DATA_RESCAP_EX_AC_SHIFT (2)
422+
#define NVME_NS_DATA_RESCAP_EX_AC_MASK (0x1)
423+
/* supports the Write Exclusive – Registrants Only */
424+
#define NVME_NS_DATA_RESCAP_WR_EX_RO_SHIFT (3)
425+
#define NVME_NS_DATA_RESCAP_WR_EX_RO_MASK (0x1)
426+
/* supports the Exclusive Access - Registrants Only */
427+
#define NVME_NS_DATA_RESCAP_EX_AC_RO_SHIFT (4)
428+
#define NVME_NS_DATA_RESCAP_EX_AC_RO_MASK (0x1)
429+
/* supports the Write Exclusive – All Registrants */
430+
#define NVME_NS_DATA_RESCAP_WR_EX_AR_SHIFT (5)
431+
#define NVME_NS_DATA_RESCAP_WR_EX_AR_MASK (0x1)
432+
/* supports the Exclusive Access - All Registrants */
433+
#define NVME_NS_DATA_RESCAP_EX_AC_AR_SHIFT (6)
434+
#define NVME_NS_DATA_RESCAP_EX_AC_AR_MASK (0x1)
435+
/* Ignore Existing Key is used as defined in revision 1.3 or later */
436+
#define NVME_NS_DATA_RESCAP_IEKEY13_SHIFT (7)
437+
#define NVME_NS_DATA_RESCAP_IEKEY13_MASK (0x1)
438+
439+
/** Format Progress Indicator */
440+
/* percentage of the Format NVM command that remains to be completed */
441+
#define NVME_NS_DATA_FPI_PERC_SHIFT (0)
442+
#define NVME_NS_DATA_FPI_PERC_MASK (0x7f)
443+
/* namespace supports the Format Progress Indicator */
444+
#define NVME_NS_DATA_FPI_SUPP_SHIFT (7)
445+
#define NVME_NS_DATA_FPI_SUPP_MASK (0x1)
446+
447+
/** Deallocate Logical Block Features */
448+
/* deallocated logical block read behavior */
449+
#define NVME_NS_DATA_DLFEAT_READ_SHIFT (0)
450+
#define NVME_NS_DATA_DLFEAT_READ_MASK (0x07)
451+
#define NVME_NS_DATA_DLFEAT_READ_NR (0x00)
452+
#define NVME_NS_DATA_DLFEAT_READ_00 (0x01)
453+
#define NVME_NS_DATA_DLFEAT_READ_FF (0x02)
454+
/* supports the Deallocate bit in the Write Zeroes */
455+
#define NVME_NS_DATA_DLFEAT_DWZ_SHIFT (3)
456+
#define NVME_NS_DATA_DLFEAT_DWZ_MASK (0x01)
457+
/* Guard field for deallocated logical blocks is set to the CRC */
458+
#define NVME_NS_DATA_DLFEAT_GCRC_SHIFT (4)
459+
#define NVME_NS_DATA_DLFEAT_GCRC_MASK (0x01)
460+
461+
/** lba format support */
462+
/* metadata size */
463+
#define NVME_NS_DATA_LBAF_MS_SHIFT (0)
464+
#define NVME_NS_DATA_LBAF_MS_MASK (0xFFFF)
465+
/* lba data size */
466+
#define NVME_NS_DATA_LBAF_LBADS_SHIFT (16)
467+
#define NVME_NS_DATA_LBAF_LBADS_MASK (0xFF)
468+
/* relative performance */
469+
#define NVME_NS_DATA_LBAF_RP_SHIFT (24)
470+
#define NVME_NS_DATA_LBAF_RP_MASK (0x3)
471+
345472
enum nvme_critical_warning_state {
346473
NVME_CRIT_WARN_ST_AVAILABLE_SPARE = 0x1,
347474
NVME_CRIT_WARN_ST_TEMPERATURE = 0x2,

0 commit comments

Comments
 (0)