1240616Sjimharris/*-
2253112Sjimharris * Copyright (C) 2012-2013 Intel Corporation
3240616Sjimharris * All rights reserved.
4240616Sjimharris *
5240616Sjimharris * Redistribution and use in source and binary forms, with or without
6240616Sjimharris * modification, are permitted provided that the following conditions
7240616Sjimharris * are met:
8240616Sjimharris * 1. Redistributions of source code must retain the above copyright
9240616Sjimharris *    notice, this list of conditions and the following disclaimer.
10240616Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
11240616Sjimharris *    notice, this list of conditions and the following disclaimer in the
12240616Sjimharris *    documentation and/or other materials provided with the distribution.
13240616Sjimharris *
14240616Sjimharris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15240616Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16240616Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17240616Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18240616Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19240616Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20240616Sjimharris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21240616Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22240616Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23240616Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24240616Sjimharris * SUCH DAMAGE.
25240616Sjimharris */
26240616Sjimharris
27240616Sjimharris#include <sys/cdefs.h>
28240616Sjimharris__FBSDID("$FreeBSD$");
29240616Sjimharris
30240616Sjimharris#include "nvme_private.h"
31240616Sjimharris
32240616Sjimharrisvoid
33240616Sjimharrisnvme_ctrlr_cmd_identify_controller(struct nvme_controller *ctrlr, void *payload,
34240616Sjimharris	nvme_cb_fn_t cb_fn, void *cb_arg)
35240616Sjimharris{
36241659Sjimharris	struct nvme_request *req;
37240616Sjimharris	struct nvme_command *cmd;
38240616Sjimharris
39248913Sjimharris	req = nvme_allocate_request_vaddr(payload,
40241659Sjimharris	    sizeof(struct nvme_controller_data), cb_fn, cb_arg);
41240616Sjimharris
42241659Sjimharris	cmd = &req->cmd;
43240616Sjimharris	cmd->opc = NVME_OPC_IDENTIFY;
44240616Sjimharris
45240616Sjimharris	/*
46240616Sjimharris	 * TODO: create an identify command data structure, which
47240616Sjimharris	 *  includes this CNS bit in cdw10.
48240616Sjimharris	 */
49240616Sjimharris	cmd->cdw10 = 1;
50240616Sjimharris
51241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
52240616Sjimharris}
53240616Sjimharris
54240616Sjimharrisvoid
55240616Sjimharrisnvme_ctrlr_cmd_identify_namespace(struct nvme_controller *ctrlr, uint16_t nsid,
56240616Sjimharris	void *payload, nvme_cb_fn_t cb_fn, void *cb_arg)
57240616Sjimharris{
58241659Sjimharris	struct nvme_request *req;
59240616Sjimharris	struct nvme_command *cmd;
60240616Sjimharris
61248913Sjimharris	req = nvme_allocate_request_vaddr(payload,
62241659Sjimharris	    sizeof(struct nvme_namespace_data), cb_fn, cb_arg);
63240616Sjimharris
64241659Sjimharris	cmd = &req->cmd;
65240616Sjimharris	cmd->opc = NVME_OPC_IDENTIFY;
66240616Sjimharris
67240616Sjimharris	/*
68240616Sjimharris	 * TODO: create an identify command data structure
69240616Sjimharris	 */
70240616Sjimharris	cmd->nsid = nsid;
71240616Sjimharris
72241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
73240616Sjimharris}
74240616Sjimharris
75240616Sjimharrisvoid
76240616Sjimharrisnvme_ctrlr_cmd_create_io_cq(struct nvme_controller *ctrlr,
77240616Sjimharris    struct nvme_qpair *io_que, uint16_t vector, nvme_cb_fn_t cb_fn,
78240616Sjimharris    void *cb_arg)
79240616Sjimharris{
80241659Sjimharris	struct nvme_request *req;
81240616Sjimharris	struct nvme_command *cmd;
82240616Sjimharris
83248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
84240616Sjimharris
85241659Sjimharris	cmd = &req->cmd;
86240616Sjimharris	cmd->opc = NVME_OPC_CREATE_IO_CQ;
87240616Sjimharris
88240616Sjimharris	/*
89240616Sjimharris	 * TODO: create a create io completion queue command data
90240616Sjimharris	 *  structure.
91240616Sjimharris	 */
92240616Sjimharris	cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id;
93240616Sjimharris	/* 0x3 = interrupts enabled | physically contiguous */
94240616Sjimharris	cmd->cdw11 = (vector << 16) | 0x3;
95240616Sjimharris	cmd->prp1 = io_que->cpl_bus_addr;
96240616Sjimharris
97241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
98240616Sjimharris}
99240616Sjimharris
100240616Sjimharrisvoid
101240616Sjimharrisnvme_ctrlr_cmd_create_io_sq(struct nvme_controller *ctrlr,
102240616Sjimharris    struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
103240616Sjimharris{
104241659Sjimharris	struct nvme_request *req;
105240616Sjimharris	struct nvme_command *cmd;
106240616Sjimharris
107248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
108240616Sjimharris
109241659Sjimharris	cmd = &req->cmd;
110240616Sjimharris	cmd->opc = NVME_OPC_CREATE_IO_SQ;
111240616Sjimharris
112240616Sjimharris	/*
113240616Sjimharris	 * TODO: create a create io submission queue command data
114240616Sjimharris	 *  structure.
115240616Sjimharris	 */
116240616Sjimharris	cmd->cdw10 = ((io_que->num_entries-1) << 16) | io_que->id;
117240616Sjimharris	/* 0x1 = physically contiguous */
118240616Sjimharris	cmd->cdw11 = (io_que->id << 16) | 0x1;
119240616Sjimharris	cmd->prp1 = io_que->cmd_bus_addr;
120240616Sjimharris
121241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
122240616Sjimharris}
123240616Sjimharris
124240616Sjimharrisvoid
125240616Sjimharrisnvme_ctrlr_cmd_delete_io_cq(struct nvme_controller *ctrlr,
126240616Sjimharris    struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
127240616Sjimharris{
128241659Sjimharris	struct nvme_request *req;
129240616Sjimharris	struct nvme_command *cmd;
130240616Sjimharris
131248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
132240616Sjimharris
133241659Sjimharris	cmd = &req->cmd;
134240616Sjimharris	cmd->opc = NVME_OPC_DELETE_IO_CQ;
135240616Sjimharris
136240616Sjimharris	/*
137240616Sjimharris	 * TODO: create a delete io completion queue command data
138240616Sjimharris	 *  structure.
139240616Sjimharris	 */
140240616Sjimharris	cmd->cdw10 = io_que->id;
141240616Sjimharris
142241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
143240616Sjimharris}
144240616Sjimharris
145240616Sjimharrisvoid
146240616Sjimharrisnvme_ctrlr_cmd_delete_io_sq(struct nvme_controller *ctrlr,
147240616Sjimharris    struct nvme_qpair *io_que, nvme_cb_fn_t cb_fn, void *cb_arg)
148240616Sjimharris{
149241659Sjimharris	struct nvme_request *req;
150240616Sjimharris	struct nvme_command *cmd;
151240616Sjimharris
152248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
153240616Sjimharris
154241659Sjimharris	cmd = &req->cmd;
155240616Sjimharris	cmd->opc = NVME_OPC_DELETE_IO_SQ;
156240616Sjimharris
157240616Sjimharris	/*
158240616Sjimharris	 * TODO: create a delete io submission queue command data
159240616Sjimharris	 *  structure.
160240616Sjimharris	 */
161240616Sjimharris	cmd->cdw10 = io_que->id;
162240616Sjimharris
163241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
164240616Sjimharris}
165240616Sjimharris
166240616Sjimharrisvoid
167240616Sjimharrisnvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature,
168240616Sjimharris    uint32_t cdw11, void *payload, uint32_t payload_size,
169240616Sjimharris    nvme_cb_fn_t cb_fn, void *cb_arg)
170240616Sjimharris{
171241659Sjimharris	struct nvme_request *req;
172240616Sjimharris	struct nvme_command *cmd;
173240616Sjimharris
174248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
175240616Sjimharris
176241659Sjimharris	cmd = &req->cmd;
177240616Sjimharris	cmd->opc = NVME_OPC_SET_FEATURES;
178240616Sjimharris	cmd->cdw10 = feature;
179240616Sjimharris	cmd->cdw11 = cdw11;
180240616Sjimharris
181241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
182240616Sjimharris}
183240616Sjimharris
184240616Sjimharrisvoid
185240616Sjimharrisnvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature,
186240616Sjimharris    uint32_t cdw11, void *payload, uint32_t payload_size,
187240616Sjimharris    nvme_cb_fn_t cb_fn, void *cb_arg)
188240616Sjimharris{
189241659Sjimharris	struct nvme_request *req;
190240616Sjimharris	struct nvme_command *cmd;
191240616Sjimharris
192248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
193240616Sjimharris
194241659Sjimharris	cmd = &req->cmd;
195240616Sjimharris	cmd->opc = NVME_OPC_GET_FEATURES;
196240616Sjimharris	cmd->cdw10 = feature;
197240616Sjimharris	cmd->cdw11 = cdw11;
198240616Sjimharris
199241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
200240616Sjimharris}
201240616Sjimharris
202240616Sjimharrisvoid
203240616Sjimharrisnvme_ctrlr_cmd_set_num_queues(struct nvme_controller *ctrlr,
204240616Sjimharris    uint32_t num_queues, nvme_cb_fn_t cb_fn, void *cb_arg)
205240616Sjimharris{
206240616Sjimharris	uint32_t cdw11;
207240616Sjimharris
208267620Sjimharris	cdw11 = ((num_queues - 1) << 16) | (num_queues - 1);
209240616Sjimharris	nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_NUMBER_OF_QUEUES, cdw11,
210240616Sjimharris	    NULL, 0, cb_fn, cb_arg);
211240616Sjimharris}
212240616Sjimharris
213240616Sjimharrisvoid
214248737Sjimharrisnvme_ctrlr_cmd_set_async_event_config(struct nvme_controller *ctrlr,
215240616Sjimharris    union nvme_critical_warning_state state, nvme_cb_fn_t cb_fn,
216240616Sjimharris    void *cb_arg)
217240616Sjimharris{
218240616Sjimharris	uint32_t cdw11;
219240616Sjimharris
220240616Sjimharris	cdw11 = state.raw;
221240616Sjimharris	nvme_ctrlr_cmd_set_feature(ctrlr,
222248737Sjimharris	    NVME_FEAT_ASYNC_EVENT_CONFIGURATION, cdw11, NULL, 0, cb_fn,
223240616Sjimharris	    cb_arg);
224240616Sjimharris}
225240616Sjimharris
226240616Sjimharrisvoid
227240616Sjimharrisnvme_ctrlr_cmd_set_interrupt_coalescing(struct nvme_controller *ctrlr,
228240616Sjimharris    uint32_t microseconds, uint32_t threshold, nvme_cb_fn_t cb_fn, void *cb_arg)
229240616Sjimharris{
230240616Sjimharris	uint32_t cdw11;
231240616Sjimharris
232240616Sjimharris	if ((microseconds/100) >= 0x100) {
233248773Sjimharris		nvme_printf(ctrlr, "invalid coal time %d, disabling\n",
234248773Sjimharris		    microseconds);
235240616Sjimharris		microseconds = 0;
236240616Sjimharris		threshold = 0;
237240616Sjimharris	}
238240616Sjimharris
239240616Sjimharris	if (threshold >= 0x100) {
240248773Sjimharris		nvme_printf(ctrlr, "invalid threshold %d, disabling\n",
241248773Sjimharris		    threshold);
242240616Sjimharris		threshold = 0;
243240616Sjimharris		microseconds = 0;
244240616Sjimharris	}
245240616Sjimharris
246240616Sjimharris	cdw11 = ((microseconds/100) << 8) | threshold;
247240616Sjimharris	nvme_ctrlr_cmd_set_feature(ctrlr, NVME_FEAT_INTERRUPT_COALESCING, cdw11,
248240616Sjimharris	    NULL, 0, cb_fn, cb_arg);
249240616Sjimharris}
250240616Sjimharris
251240616Sjimharrisvoid
252248740Sjimharrisnvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr, uint8_t log_page,
253248740Sjimharris    uint32_t nsid, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn,
254248740Sjimharris    void *cb_arg)
255240616Sjimharris{
256241659Sjimharris	struct nvme_request *req;
257240616Sjimharris	struct nvme_command *cmd;
258240616Sjimharris
259248913Sjimharris	req = nvme_allocate_request_vaddr(payload, payload_size, cb_fn, cb_arg);
260240616Sjimharris
261241659Sjimharris	cmd = &req->cmd;
262240616Sjimharris	cmd->opc = NVME_OPC_GET_LOG_PAGE;
263240616Sjimharris	cmd->nsid = nsid;
264248740Sjimharris	cmd->cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16;
265248740Sjimharris	cmd->cdw10 |= log_page;
266240616Sjimharris
267241660Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
268240616Sjimharris}
269248732Sjimharris
270248757Sjimharrisvoid
271248757Sjimharrisnvme_ctrlr_cmd_get_error_page(struct nvme_controller *ctrlr,
272248757Sjimharris    struct nvme_error_information_entry *payload, uint32_t num_entries,
273248757Sjimharris    nvme_cb_fn_t cb_fn, void *cb_arg)
274248757Sjimharris{
275248740Sjimharris
276248757Sjimharris	KASSERT(num_entries > 0, ("%s called with num_entries==0\n", __func__));
277248757Sjimharris
278248757Sjimharris	/* Controller's error log page entries is 0-based. */
279248773Sjimharris	KASSERT(num_entries <= (ctrlr->cdata.elpe + 1),
280248773Sjimharris	    ("%s called with num_entries=%d but (elpe+1)=%d\n", __func__,
281248773Sjimharris	    num_entries, ctrlr->cdata.elpe + 1));
282248773Sjimharris
283248773Sjimharris	if (num_entries > (ctrlr->cdata.elpe + 1))
284248757Sjimharris		num_entries = ctrlr->cdata.elpe + 1;
285248757Sjimharris
286248757Sjimharris	nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_ERROR,
287248757Sjimharris	    NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload) * num_entries,
288248757Sjimharris	    cb_fn, cb_arg);
289248757Sjimharris}
290248757Sjimharris
291248732Sjimharrisvoid
292248740Sjimharrisnvme_ctrlr_cmd_get_health_information_page(struct nvme_controller *ctrlr,
293248740Sjimharris    uint32_t nsid, struct nvme_health_information_page *payload,
294248740Sjimharris    nvme_cb_fn_t cb_fn, void *cb_arg)
295248740Sjimharris{
296248740Sjimharris
297248740Sjimharris	nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_HEALTH_INFORMATION,
298248740Sjimharris	    nsid, payload, sizeof(*payload), cb_fn, cb_arg);
299248740Sjimharris}
300248740Sjimharris
301248740Sjimharrisvoid
302248758Sjimharrisnvme_ctrlr_cmd_get_firmware_page(struct nvme_controller *ctrlr,
303248758Sjimharris    struct nvme_firmware_page *payload, nvme_cb_fn_t cb_fn, void *cb_arg)
304248758Sjimharris{
305248758Sjimharris
306248758Sjimharris	nvme_ctrlr_cmd_get_log_page(ctrlr, NVME_LOG_FIRMWARE_SLOT,
307248758Sjimharris	    NVME_GLOBAL_NAMESPACE_TAG, payload, sizeof(*payload), cb_fn,
308248758Sjimharris	    cb_arg);
309248758Sjimharris}
310248758Sjimharris
311248758Sjimharrisvoid
312248732Sjimharrisnvme_ctrlr_cmd_abort(struct nvme_controller *ctrlr, uint16_t cid,
313248732Sjimharris    uint16_t sqid, nvme_cb_fn_t cb_fn, void *cb_arg)
314248732Sjimharris{
315248732Sjimharris	struct nvme_request *req;
316248732Sjimharris	struct nvme_command *cmd;
317248732Sjimharris
318248913Sjimharris	req = nvme_allocate_request_null(cb_fn, cb_arg);
319248732Sjimharris
320248732Sjimharris	cmd = &req->cmd;
321248732Sjimharris	cmd->opc = NVME_OPC_ABORT;
322248732Sjimharris	cmd->cdw10 = (cid << 16) | sqid;
323248732Sjimharris
324248732Sjimharris	nvme_ctrlr_submit_admin_request(ctrlr, req);
325248732Sjimharris}
326