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