1 /*
2 * Copyright (c) 2022 Intel Corporation
3 * SPDX-License-Identifier: Apache-2.0
4 *
5 * Derived from FreeBSD original driver made by Jim Harris
6 */
7
8 #include <zephyr/logging/log.h>
9 LOG_MODULE_DECLARE(nvme, CONFIG_NVME_LOG_LEVEL);
10
11 #include <zephyr/kernel.h>
12 #include <zephyr/sys/byteorder.h>
13
14 #include <string.h>
15
16 #include "nvme.h"
17 #include "nvme_helpers.h"
18
nvme_ctrlr_cmd_identify_controller(struct nvme_controller * ctrlr,nvme_cb_fn_t cb_fn,void * cb_arg)19 int nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr,
20 nvme_cb_fn_t cb_fn, void *cb_arg)
21 {
22 struct nvme_request *request;
23
24 request = nvme_allocate_request_vaddr(
25 &ctrlr->cdata, sizeof(struct nvme_controller_data),
26 cb_fn, cb_arg);
27 if (!request) {
28 return -ENOMEM;
29 }
30
31 memset(&request->cmd, 0, sizeof(request->cmd));
32 request->cmd.cdw0.opc = NVME_OPC_IDENTIFY;
33 request->cmd.cdw10 = sys_cpu_to_le32(1);
34
35 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
36 }
37
nvme_ctrlr_cmd_identify_namespace(struct nvme_controller * ctrlr,uint32_t nsid,void * payload,nvme_cb_fn_t cb_fn,void * cb_arg)38 int nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr,
39 uint32_t nsid, void *payload,
40 nvme_cb_fn_t cb_fn, void *cb_arg)
41 {
42 struct nvme_request *request;
43
44 request = nvme_allocate_request_vaddr(
45 payload, sizeof(struct nvme_namespace_data),
46 cb_fn, cb_arg);
47 if (!request) {
48 return -ENOMEM;
49 }
50
51 request->cmd.cdw0.opc = NVME_OPC_IDENTIFY;
52 /*
53 * TODO: create an identify command data structure
54 */
55 request->cmd.nsid = sys_cpu_to_le32(nsid);
56
57 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
58 }
59
nvme_ctrlr_cmd_create_io_cq(struct nvme_controller * ctrlr,struct nvme_cmd_qpair * io_queue,nvme_cb_fn_t cb_fn,void * cb_arg)60 int nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr,
61 struct nvme_cmd_qpair *io_queue,
62 nvme_cb_fn_t cb_fn, void *cb_arg)
63 {
64 struct nvme_request *request;
65 struct nvme_command *cmd;
66
67 request = nvme_allocate_request_null(cb_fn, cb_arg);
68 if (!request) {
69 return -ENOMEM;
70 }
71
72 cmd = &request->cmd;
73 cmd->cdw0.opc = NVME_OPC_CREATE_IO_CQ;
74
75 /*
76 * TODO: create a create io completion queue command data
77 * structure.
78 */
79 cmd->cdw10 = sys_cpu_to_le32(((io_queue->num_entries-1) << 16) |
80 io_queue->id);
81 /* 0x3 = interrupts enabled | physically contiguous */
82 cmd->cdw11 = sys_cpu_to_le32((io_queue->vector << 16) | 0x3);
83 cmd->dptr.prp1 = sys_cpu_to_le64(io_queue->cpl_bus_addr);
84
85 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
86 }
87
nvme_ctrlr_cmd_create_io_sq(struct nvme_controller * ctrlr,struct nvme_cmd_qpair * io_queue,nvme_cb_fn_t cb_fn,void * cb_arg)88 int nvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr,
89 struct nvme_cmd_qpair *io_queue,
90 nvme_cb_fn_t cb_fn, void *cb_arg)
91 {
92 struct nvme_request *request;
93 struct nvme_command *cmd;
94
95 request = nvme_allocate_request_null(cb_fn, cb_arg);
96 if (!request) {
97 return -ENOMEM;
98 }
99
100 cmd = &request->cmd;
101 cmd->cdw0.opc = NVME_OPC_CREATE_IO_SQ;
102
103 /*
104 * TODO: create a create io submission queue command data
105 * structure.
106 */
107 cmd->cdw10 = sys_cpu_to_le32(((io_queue->num_entries - 1) << 16) |
108 io_queue->id);
109 /* 0x1 = physically contiguous */
110 cmd->cdw11 = sys_cpu_to_le32((io_queue->id << 16) | 0x1);
111 cmd->dptr.prp1 = sys_cpu_to_le64(io_queue->cmd_bus_addr);
112
113 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
114 }
115
nvme_ctrlr_cmd_delete_io_cq(struct nvme_controller * ctrlr,struct nvme_cmd_qpair * io_queue,nvme_cb_fn_t cb_fn,void * cb_arg)116 int nvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr,
117 struct nvme_cmd_qpair *io_queue,
118 nvme_cb_fn_t cb_fn, void *cb_arg)
119 {
120 struct nvme_request *request;
121 struct nvme_command *cmd;
122
123 request = nvme_allocate_request_null(cb_fn, cb_arg);
124 if (!request) {
125 return -ENOMEM;
126 }
127
128 cmd = &request->cmd;
129 cmd->cdw0.opc = NVME_OPC_DELETE_IO_CQ;
130
131 /*
132 * TODO: create a delete io completion queue command data
133 * structure.
134 */
135 cmd->cdw10 = sys_cpu_to_le32(io_queue->id);
136
137 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
138 }
139
nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller * ctrlr,struct nvme_cmd_qpair * io_queue,nvme_cb_fn_t cb_fn,void * cb_arg)140 int nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr,
141 struct nvme_cmd_qpair *io_queue,
142 nvme_cb_fn_t cb_fn, void *cb_arg)
143 {
144 struct nvme_request *request;
145 struct nvme_command *cmd;
146
147 request = nvme_allocate_request_null(cb_fn, cb_arg);
148 if (!request) {
149 return -ENOMEM;
150 }
151
152 cmd = &request->cmd;
153 cmd->cdw0.opc = NVME_OPC_DELETE_IO_SQ;
154
155 /*
156 * TODO: create a delete io submission queue command data
157 * structure.
158 */
159 cmd->cdw10 = sys_cpu_to_le32(io_queue->id);
160
161 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
162 }
163
nvme_ctrlr_cmd_set_feature(struct nvme_controller * ctrlr,uint8_t feature,uint32_t cdw11,uint32_t cdw12,uint32_t cdw13,uint32_t cdw14,uint32_t cdw15,void * payload,uint32_t payload_size,nvme_cb_fn_t cb_fn,void * cb_arg)164 int nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr,
165 uint8_t feature, uint32_t cdw11,
166 uint32_t cdw12, uint32_t cdw13,
167 uint32_t cdw14, uint32_t cdw15,
168 void *payload, uint32_t payload_size,
169 nvme_cb_fn_t cb_fn, void *cb_arg)
170 {
171 struct nvme_request *request;
172 struct nvme_command *cmd;
173
174 request = nvme_allocate_request_null(cb_fn, cb_arg);
175 if (!request) {
176 return -ENOMEM;
177 }
178
179 cmd = &request->cmd;
180 cmd->cdw0.opc = NVME_OPC_SET_FEATURES;
181 cmd->cdw10 = sys_cpu_to_le32(feature);
182 cmd->cdw11 = sys_cpu_to_le32(cdw11);
183 cmd->cdw12 = sys_cpu_to_le32(cdw12);
184 cmd->cdw13 = sys_cpu_to_le32(cdw13);
185 cmd->cdw14 = sys_cpu_to_le32(cdw14);
186 cmd->cdw15 = sys_cpu_to_le32(cdw15);
187
188 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
189 }
190
nvme_ctrlr_cmd_get_feature(struct nvme_controller * ctrlr,uint8_t feature,uint32_t cdw11,void * payload,uint32_t payload_size,nvme_cb_fn_t cb_fn,void * cb_arg)191 int nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr,
192 uint8_t feature, uint32_t cdw11,
193 void *payload, uint32_t payload_size,
194 nvme_cb_fn_t cb_fn, void *cb_arg)
195 {
196 struct nvme_request *request;
197 struct nvme_command *cmd;
198
199 request = nvme_allocate_request_null(cb_fn, cb_arg);
200 if (!request) {
201 return -ENOMEM;
202 }
203
204 cmd = &request->cmd;
205 cmd->cdw0.opc = NVME_OPC_GET_FEATURES;
206 cmd->cdw10 = sys_cpu_to_le32(feature);
207 cmd->cdw11 = sys_cpu_to_le32(cdw11);
208
209 return nvme_cmd_qpair_submit_request(ctrlr->adminq, request);
210 }
211
nvme_ctrlr_cmd_set_num_queues(struct nvme_controller * ctrlr,uint32_t num_queues,nvme_cb_fn_t cb_fn,void * cb_arg)212 int nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr,
213 uint32_t num_queues,
214 nvme_cb_fn_t cb_fn, void *cb_arg)
215 {
216 uint32_t cdw11;
217
218 cdw11 = ((num_queues - 1) << 16) | (num_queues - 1);
219
220 return nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES,
221 cdw11, 0, 0, 0, 0, NULL, 0,
222 cb_fn, cb_arg);
223 }
224