blob: 9b66593735955a60d725dffd3b3e664fbc4afad0 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
|
#pragma once
#include <cstdint>
#include <drivers/disk.hpp>
#include <generic/hhdm.hpp>
#include <generic/lock/spinlock.hpp>
#include <generic/lock/mutex.hpp>
#include <generic/arch.hpp>
//#define NVME_ORANGE_TRACE
#define NVME_REG_CAP 0x00 // Controller Capabilities
#define NVME_REG_VS 0x08 // Version
#define NVME_REG_CC 0x14 // Controller Configuration
#define NVME_REG_CSTS 0x1C // Controller Status
#define NVME_REG_AQA 0x24 // Admin Queue Attributes
#define NVME_REG_ASQ 0x28 // Admin Submission Queue Base Address
#define NVME_REG_ACQ 0x30 // Admin Completion Queue Base Address
#define NVME_CAP_MQES_MASK 0xFFFF // Maximum Queue Entries Supported
#define NVME_CAP_CQR (1ULL << 16) // Contiguous Queues Required
#define NVME_CAP_DSTRD_MASK (0xFULL << 32) // Doorbell Stride
#define NVME_CAP_CSS_MASK (0xFFULL << 37) // Command Sets Supported
#define NVME_CAP_MPSMIN_MASK (0xFULL << 48) // Memory Page Size Minimum
#define NVME_CAP_MPSMAX_MASK (0xFULL << 52) // Memory Page Size Maximum
#define NVME_CC_EN (1 << 0) // Enable
#define NVME_CC_CSS_NVM (0 << 4) // NVM Command Set
#define NVME_CC_SHN_NORMAL (1 << 14) // Normal shutdown
#define NVME_CSTS_RDY (1 << 0) // Ready
#define NVME_CSTS_CFS (1 << 1) // Controller Fatal Status
#define NVME_MAX_IO_QUEUES (65535)
#define NVME_MAX_QUEUE_SIZE 64
#define NVME_RESET_TIMEOUT_MS 30000
#define NVME_ENABLE_TIMEOUT_MS 30000
struct nvme_lbaf {
std::uint16_t ms;
std::uint8_t ds;
std::uint8_t rp;
};
struct nvme_command {
uint32_t cdw0;
uint32_t nsid;
uint32_t reserved[2];
uint64_t metadata;
uint64_t prp1;
uint64_t prp2;
uint32_t cdw10;
uint32_t cdw11_15[5];
};
struct nvme_completion {
uint32_t result;
uint32_t reserved;
uint16_t sq_head;
uint16_t sq_id;
uint16_t command_id;
uint16_t status;
};
struct nvme_id_ns {
std::uint64_t nsze; // Namespace Size
std::uint64_t ncap; // Namespace Capacity
std::uint64_t nuse; // Namespace Utilization
std::uint8_t nsfeat; // Namespace Features
std::uint8_t nlbaf; // Number of LBA Formats
std::uint8_t flbas; // Formatted LBA Size
std::uint8_t mc; // Metadata Capabilities
std::uint8_t dpc; // End-to-end Data Protection Capabilities
std::uint8_t dps; // End-to-end Data Protection Type Settings
std::uint8_t nmic; // Namespace Multi-path I/O and Namespace Sharing Capabilities
std::uint8_t rescap; // Reservation Capabilities
std::uint8_t fpi; // Format Progress Indicator
std::uint8_t dlfeat; // Deallocate Logical Block Features
std::uint16_t nawun; // Namespace Atomic Write Unit Normal
std::uint16_t nawupf; // Namespace Atomic Write Unit Power Fail
std::uint16_t nacwu; // Namespace Atomic Compare & Write Unit
std::uint16_t nabsn; // Namespace Atomic Boundary Size Normal
std::uint16_t nabo; // Namespace Atomic Boundary Offset
std::uint16_t nabspf; // Namespace Atomic Boundary Size Power Fail
std::uint16_t noiob; // Namespace Optimal I/O Boundary
std::uint8_t nvmcap[16]; // NVM Capacity
std::uint16_t npwg; // Namespace Preferred Write Granularity
std::uint16_t npwa; // Namespace Preferred Write Alignment
std::uint16_t npdg; // Namespace Preferred Deallocate Granularity
std::uint16_t npda; // Namespace Preferred Deallocate Alignment
std::uint16_t nows; // Namespace Optimal Write Size
std::uint16_t mssrl; // Maximum Single Source Range Length
std::uint32_t mcl; // Maximum Copy Length
std::uint8_t msrc; // Maximum Source Range Count
std::uint8_t rsvd81[11];
std::uint32_t anagrpid; // ANA Group Identifier
std::uint8_t rsvd96[3];
std::uint8_t nsattr; // Namespace Attributes
std::uint16_t nvmsetid; // NVM Set Identifier
std::uint16_t endgid; // Endurance Group Identifier
std::uint8_t nguid[16]; // Namespace Globally Unique Identifier
std::uint8_t eui64[8]; // IEEE Extended Unique Identifier
nvme_lbaf lbaf[16]; // LBA Format Support
std::uint8_t rsvd192[192];
std::uint8_t vs[3712]; // Vendor Specific
};
static_assert(sizeof(nvme_id_ns) == 4096, "nvme_id_ns must be exactly 4096 bytes");
struct nvme_queue {
std::uint64_t address;
std::size_t size;
};
struct nvme_namespace {
uint32_t nsid;
uint64_t size;
uint32_t lba_size;
uint16_t lba_shift;
bool valid;
struct nvme_id_ns* ns_data;
};
struct nvme_pair_queue {
nvme_queue sq;
nvme_queue cq;
std::uint64_t sq_tail;
std::uint64_t cq_head;
std::uint8_t phase;
std::uint8_t qid;
volatile std::uint32_t* sq_doorbell;
volatile std::uint32_t* cq_doorbell;
locks::mutex lock;
};
struct nvme_controller {
void* bar0;
uint32_t stride;
uint32_t page_size;
uint16_t max_queue_entries;
nvme_queue admin_sq;
nvme_queue admin_cq;
std::uint64_t admin_sq_tail;
std::uint64_t admin_cq_head;
std::uint8_t admin_phase;
nvme_pair_queue* main_io_queue;
nvme_namespace namespaces[256];
uint32_t num_namespaces;
uint8_t mpsmin;
void* identify;
};
struct nvme_arg_disk {
nvme_controller* ctrl;
std::uint32_t nsid;
};
namespace drivers {
namespace nvme {
static inline std::uint32_t read32(struct nvme_controller* ctrl, std::uint32_t offset) {
volatile std::uint32_t* reg = (volatile std::uint32_t*)((std::uint8_t*)ctrl->bar0 + offset);
std::uint32_t value = *reg;
arch::memory_barrier();
return value;
}
static inline void write32(struct nvme_controller* ctrl, std::uint32_t offset, std::uint32_t value) {
volatile std::uint32_t* reg = (volatile std::uint32_t*)((std::uint8_t*)ctrl->bar0 + offset);
*reg = value;
arch::memory_barrier();
}
static inline std::uint64_t read64(struct nvme_controller* ctrl, uint32_t offset) {
volatile std::uint64_t* reg = (volatile std::uint64_t*)((std::uint8_t*)ctrl->bar0 + offset);
std::uint64_t value = *reg;
arch::memory_barrier();
return value;
}
static inline void write64(struct nvme_controller* ctrl, std::uint32_t offset, std::uint32_t value) {
volatile std::uint64_t* reg = (volatile std::uint64_t*)((std::uint8_t*)ctrl->bar0 + offset);
*reg = value;
arch::memory_barrier();
}
void init();
void disable();
};
};
|