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