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