xref: /freebsd/sys/dev/nvme/nvme_ctrlr_cmd.c (revision c6ec7d31830ab1c80edae95ad5e4b9dba10c47ac)
1 /*-
2  * Copyright (C) 2012 Intel Corporation
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include "nvme_private.h"
31 
32 void
33 nvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr, void *payload,
34 	nvme_cb_fn_t cb_fn, void *cb_arg)
35 {
36 	struct nvme_request *req;
37 	struct nvme_command *cmd;
38 
39 	req = nvme_allocate_request(payload,
40 	    sizeof(struct nvme_controller_data), cb_fn, cb_arg);
41 
42 	cmd = &req->cmd;
43 	cmd->opc = NVME_OPC_IDENTIFY;
44 
45 	/*
46 	 * TODO: create an identify command data structure, which
47 	 *  includes this CNS bit in cdw10.
48 	 */
49 	cmd->cdw10 = 1;
50 
51 	nvme_ctrlr_submit_admin_request(ctrlr, req);
52 }
53 
54 void
55 nvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr, uint16_t nsid,
56 	void *payload, nvme_cb_fn_t cb_fn, void *cb_arg)
57 {
58 	struct nvme_request *req;
59 	struct nvme_command *cmd;
60 
61 	req = nvme_allocate_request(payload,
62 	    sizeof(struct nvme_namespace_data), cb_fn, cb_arg);
63 
64 	cmd = &req->cmd;
65 	cmd->opc = NVME_OPC_IDENTIFY;
66 
67 	/*
68 	 * TODO: create an identify command data structure
69 	 */
70 	cmd->nsid = nsid;
71 
72 	nvme_ctrlr_submit_admin_request(ctrlr, req);
73 }
74 
75 void
76 nvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr,
77     struct nvme_qpair *io_que, uint16_t vector, nvme_cb_fn_t cb_fn,
78     void *cb_arg)
79 {
80 	struct nvme_request *req;
81 	struct nvme_command *cmd;
82 
83 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
84 
85 	cmd = &req->cmd;
86 	cmd->opc = NVME_OPC_CREATE_IO_CQ;
87 
88 	/*
89 	 * TODO: create a create io completion queue command data
90 	 *  structure.
91 	 */
92 	cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id;
93 	/* 0x3 = interrupts enabled | physically contiguous */
94 	cmd->cdw11 = (vector << 16) | 0x3;
95 	cmd->prp1 = io_que->cpl_bus_addr;
96 
97 	nvme_ctrlr_submit_admin_request(ctrlr, req);
98 }
99 
100 void
101 nvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr,
102     struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
103 {
104 	struct nvme_request *req;
105 	struct nvme_command *cmd;
106 
107 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
108 
109 	cmd = &req->cmd;
110 	cmd->opc = NVME_OPC_CREATE_IO_SQ;
111 
112 	/*
113 	 * TODO: create a create io submission queue command data
114 	 *  structure.
115 	 */
116 	cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id;
117 	/* 0x1 = physically contiguous */
118 	cmd->cdw11 = (io_que->id << 16) | 0x1;
119 	cmd->prp1 = io_que->cmd_bus_addr;
120 
121 	nvme_ctrlr_submit_admin_request(ctrlr, req);
122 }
123 
124 void
125 nvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr,
126     struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
127 {
128 	struct nvme_request *req;
129 	struct nvme_command *cmd;
130 
131 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
132 
133 	cmd = &req->cmd;
134 	cmd->opc = NVME_OPC_DELETE_IO_CQ;
135 
136 	/*
137 	 * TODO: create a delete io completion queue command data
138 	 *  structure.
139 	 */
140 	cmd->cdw10 = io_que->id;
141 
142 	nvme_ctrlr_submit_admin_request(ctrlr, req);
143 }
144 
145 void
146 nvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr,
147     struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
148 {
149 	struct nvme_request *req;
150 	struct nvme_command *cmd;
151 
152 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
153 
154 	cmd = &req->cmd;
155 	cmd->opc = NVME_OPC_DELETE_IO_SQ;
156 
157 	/*
158 	 * TODO: create a delete io submission queue command data
159 	 *  structure.
160 	 */
161 	cmd->cdw10 = io_que->id;
162 
163 	nvme_ctrlr_submit_admin_request(ctrlr, req);
164 }
165 
166 void
167 nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature,
168     uint32_t cdw11, void *payload, uint32_t payload_size,
169     nvme_cb_fn_t cb_fn, void *cb_arg)
170 {
171 	struct nvme_request *req;
172 	struct nvme_command *cmd;
173 
174 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
175 
176 	cmd = &req->cmd;
177 	cmd->opc = NVME_OPC_SET_FEATURES;
178 	cmd->cdw10 = feature;
179 	cmd->cdw11 = cdw11;
180 
181 	nvme_ctrlr_submit_admin_request(ctrlr, req);
182 }
183 
184 void
185 nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature,
186     uint32_t cdw11, void *payload, uint32_t payload_size,
187     nvme_cb_fn_t cb_fn, void *cb_arg)
188 {
189 	struct nvme_request *req;
190 	struct nvme_command *cmd;
191 
192 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
193 
194 	cmd = &req->cmd;
195 	cmd->opc = NVME_OPC_GET_FEATURES;
196 	cmd->cdw10 = feature;
197 	cmd->cdw11 = cdw11;
198 
199 	nvme_ctrlr_submit_admin_request(ctrlr, req);
200 }
201 
202 void
203 nvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr,
204     uint32_t num_queues, nvme_cb_fn_t cb_fn, void *cb_arg)
205 {
206 	uint32_t cdw11;
207 
208 	cdw11 = ((num_queues - 1) << 16) || (num_queues - 1);
209 	nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES, cdw11,
210 	    NULL, 0, cb_fn, cb_arg);
211 }
212 
213 void
214 nvme_ctrlr_cmd_set_asynchronous_event_config(struct nvme_controller *ctrlr,
215     union nvme_critical_warning_state state, nvme_cb_fn_t cb_fn,
216     void *cb_arg)
217 {
218 	uint32_t cdw11;
219 
220 	cdw11 = state.raw;
221 	nvme_ctrlr_cmd_set_feature(ctrlr,
222 	    NVME_FEAT_ASYNCHRONOUS_EVENT_CONFIGURATION, cdw11, NULL, 0, cb_fn,
223 	    cb_arg);
224 }
225 
226 void
227 nvme_ctrlr_cmd_set_interrupt_coalescing(struct nvme_controller *ctrlr,
228     uint32_t microseconds, uint32_t threshold, nvme_cb_fn_t cb_fn, void *cb_arg)
229 {
230 	uint32_t cdw11;
231 
232 	if ((microseconds/100) >= 0x100) {
233 		KASSERT(FALSE, ("intr coal time > 255*100 microseconds\n"));
234 		printf("invalid coal time %d, disabling\n", microseconds);
235 		microseconds = 0;
236 		threshold = 0;
237 	}
238 
239 	if (threshold >= 0x100) {
240 		KASSERT(FALSE, ("intr threshold > 255\n"));
241 		printf("invalid threshold %d, disabling\n", threshold);
242 		threshold = 0;
243 		microseconds = 0;
244 	}
245 
246 	cdw11 = ((microseconds/100) << 8) | threshold;
247 	nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_INTERRUPT_COALESCING, cdw11,
248 	    NULL, 0, cb_fn, cb_arg);
249 }
250 
251 void
252 nvme_ctrlr_cmd_asynchronous_event_request(struct nvme_controller *ctrlr,
253     nvme_cb_fn_t cb_fn, void *cb_arg)
254 {
255 	struct nvme_request *req;
256 	struct nvme_command *cmd;
257 
258 	req = nvme_allocate_request(NULL, 0, cb_fn, cb_arg);
259 
260 	cmd = &req->cmd;
261 	cmd->opc = NVME_OPC_ASYNC_EVENT_REQUEST;
262 
263 	nvme_ctrlr_submit_admin_request(ctrlr, req);
264 }
265 
266 void
267 nvme_ctrlr_cmd_get_health_information_page(struct nvme_controller *ctrlr,
268     uint32_t nsid, struct nvme_health_information_page *payload,
269     nvme_cb_fn_t cb_fn, void *cb_arg)
270 {
271 	struct nvme_request *req;
272 	struct nvme_command *cmd;
273 
274 	req = nvme_allocate_request(payload, sizeof(*payload), cb_fn, cb_arg);
275 
276 	cmd = &req->cmd;
277 	cmd->opc = NVME_OPC_GET_LOG_PAGE;
278 	cmd->nsid = nsid;
279 	cmd->cdw10 = ((sizeof(*payload)/sizeof(uint32_t)) - 1) << 16;
280 	cmd->cdw10 |= NVME_LOG_HEALTH_INFORMATION;
281 
282 	nvme_ctrlr_submit_admin_request(ctrlr, req);
283 }
284