1240616Sjimharris/*-
2293352Sjimharris * Copyright (C) 2012-2016 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: stable/11/sys/dev/nvme/nvme_sysctl.c 328692 2018-02-01 16:53:08Z mav $");
29240616Sjimharris
30328692Smav#include "opt_nvme.h"
31328692Smav
32240616Sjimharris#include <sys/param.h>
33240616Sjimharris#include <sys/bus.h>
34240616Sjimharris#include <sys/sysctl.h>
35240616Sjimharris
36240616Sjimharris#include "nvme_private.h"
37240616Sjimharris
38328692Smav#ifndef NVME_USE_NVD
39328692Smav#define NVME_USE_NVD 1
40328692Smav#endif
41328681Smav
42328692Smavint nvme_use_nvd = NVME_USE_NVD;
43328692Smav
44328681SmavSYSCTL_NODE(_hw, OID_AUTO, nvme, CTLFLAG_RD, 0, "NVMe sysctl tunables");
45328681SmavSYSCTL_INT(_hw_nvme, OID_AUTO, use_nvd, CTLFLAG_RDTUN,
46328681Smav    &nvme_use_nvd, 1, "1 = Create NVD devices, 0 = Create NDA devices");
47328681Smav
48241434Sjimharris/*
49241434Sjimharris * CTLTYPE_S64 and sysctl_handle_64 were added in r217616.  Define these
50241434Sjimharris *  explicitly here for older kernels that don't include the r217616
51241434Sjimharris *  changeset.
52241434Sjimharris */
53241434Sjimharris#ifndef CTLTYPE_S64
54241434Sjimharris#define CTLTYPE_S64		CTLTYPE_QUAD
55241434Sjimharris#define sysctl_handle_64	sysctl_handle_quad
56241434Sjimharris#endif
57241434Sjimharris
58240616Sjimharrisstatic void
59240616Sjimharrisnvme_dump_queue(struct nvme_qpair *qpair)
60240616Sjimharris{
61240616Sjimharris	struct nvme_completion *cpl;
62240616Sjimharris	struct nvme_command *cmd;
63240616Sjimharris	int i;
64240616Sjimharris
65240616Sjimharris	printf("id:%04Xh phase:%d\n", qpair->id, qpair->phase);
66240616Sjimharris
67240616Sjimharris	printf("Completion queue:\n");
68240616Sjimharris	for (i = 0; i < qpair->num_entries; i++) {
69240616Sjimharris		cpl = &qpair->cpl[i];
70240616Sjimharris		printf("%05d: ", i);
71240616Sjimharris		nvme_dump_completion(cpl);
72240616Sjimharris	}
73240616Sjimharris
74240616Sjimharris	printf("Submission queue:\n");
75240616Sjimharris	for (i = 0; i < qpair->num_entries; i++) {
76240616Sjimharris		cmd = &qpair->cmd[i];
77240616Sjimharris		printf("%05d: ", i);
78240616Sjimharris		nvme_dump_command(cmd);
79240616Sjimharris	}
80240616Sjimharris}
81240616Sjimharris
82240616Sjimharris
83240616Sjimharrisstatic int
84240616Sjimharrisnvme_sysctl_dump_debug(SYSCTL_HANDLER_ARGS)
85240616Sjimharris{
86240616Sjimharris	struct nvme_qpair 	*qpair = arg1;
87240616Sjimharris	uint32_t		val = 0;
88240616Sjimharris
89240616Sjimharris	int error = sysctl_handle_int(oidp, &val, 0, req);
90240616Sjimharris
91240616Sjimharris	if (error)
92240616Sjimharris		return (error);
93240616Sjimharris
94240616Sjimharris	if (val != 0)
95240616Sjimharris		nvme_dump_queue(qpair);
96240616Sjimharris
97240616Sjimharris	return (0);
98240616Sjimharris}
99240616Sjimharris
100240616Sjimharrisstatic int
101240616Sjimharrisnvme_sysctl_int_coal_time(SYSCTL_HANDLER_ARGS)
102240616Sjimharris{
103240616Sjimharris	struct nvme_controller *ctrlr = arg1;
104240616Sjimharris	uint32_t oldval = ctrlr->int_coal_time;
105240616Sjimharris	int error = sysctl_handle_int(oidp, &ctrlr->int_coal_time, 0,
106240616Sjimharris	    req);
107240616Sjimharris
108240616Sjimharris	if (error)
109240616Sjimharris		return (error);
110240616Sjimharris
111240616Sjimharris	if (oldval != ctrlr->int_coal_time)
112240616Sjimharris		nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr,
113240616Sjimharris		    ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL,
114240616Sjimharris		    NULL);
115240616Sjimharris
116240616Sjimharris	return (0);
117240616Sjimharris}
118240616Sjimharris
119240616Sjimharrisstatic int
120240616Sjimharrisnvme_sysctl_int_coal_threshold(SYSCTL_HANDLER_ARGS)
121240616Sjimharris{
122240616Sjimharris	struct nvme_controller *ctrlr = arg1;
123240616Sjimharris	uint32_t oldval = ctrlr->int_coal_threshold;
124240616Sjimharris	int error = sysctl_handle_int(oidp, &ctrlr->int_coal_threshold, 0,
125240616Sjimharris	    req);
126240616Sjimharris
127240616Sjimharris	if (error)
128240616Sjimharris		return (error);
129240616Sjimharris
130240616Sjimharris	if (oldval != ctrlr->int_coal_threshold)
131240616Sjimharris		nvme_ctrlr_cmd_set_interrupt_coalescing(ctrlr,
132240616Sjimharris		    ctrlr->int_coal_time, ctrlr->int_coal_threshold, NULL,
133240616Sjimharris		    NULL);
134240616Sjimharris
135240616Sjimharris	return (0);
136240616Sjimharris}
137240616Sjimharris
138248749Sjimharrisstatic int
139248749Sjimharrisnvme_sysctl_timeout_period(SYSCTL_HANDLER_ARGS)
140248749Sjimharris{
141248749Sjimharris	struct nvme_controller *ctrlr = arg1;
142248749Sjimharris	uint32_t oldval = ctrlr->timeout_period;
143248749Sjimharris	int error = sysctl_handle_int(oidp, &ctrlr->timeout_period, 0, req);
144248749Sjimharris
145248749Sjimharris	if (error)
146248749Sjimharris		return (error);
147248749Sjimharris
148248749Sjimharris	if (ctrlr->timeout_period > NVME_MAX_TIMEOUT_PERIOD ||
149248749Sjimharris	    ctrlr->timeout_period < NVME_MIN_TIMEOUT_PERIOD) {
150248749Sjimharris		ctrlr->timeout_period = oldval;
151248749Sjimharris		return (EINVAL);
152248749Sjimharris	}
153248749Sjimharris
154248749Sjimharris	return (0);
155248749Sjimharris}
156248749Sjimharris
157240616Sjimharrisstatic void
158241434Sjimharrisnvme_qpair_reset_stats(struct nvme_qpair *qpair)
159241434Sjimharris{
160241434Sjimharris
161241434Sjimharris	qpair->num_cmds = 0;
162241434Sjimharris	qpair->num_intr_handler_calls = 0;
163241434Sjimharris}
164241434Sjimharris
165241434Sjimharrisstatic int
166241434Sjimharrisnvme_sysctl_num_cmds(SYSCTL_HANDLER_ARGS)
167241434Sjimharris{
168241434Sjimharris	struct nvme_controller 	*ctrlr = arg1;
169241434Sjimharris	int64_t			num_cmds = 0;
170241434Sjimharris	int			i;
171241434Sjimharris
172241434Sjimharris	num_cmds = ctrlr->adminq.num_cmds;
173241434Sjimharris
174241434Sjimharris	for (i = 0; i < ctrlr->num_io_queues; i++)
175241434Sjimharris		num_cmds += ctrlr->ioq[i].num_cmds;
176241434Sjimharris
177241434Sjimharris	return (sysctl_handle_64(oidp, &num_cmds, 0, req));
178241434Sjimharris}
179241434Sjimharris
180241434Sjimharrisstatic int
181241434Sjimharrisnvme_sysctl_num_intr_handler_calls(SYSCTL_HANDLER_ARGS)
182241434Sjimharris{
183241434Sjimharris	struct nvme_controller 	*ctrlr = arg1;
184241434Sjimharris	int64_t			num_intr_handler_calls = 0;
185241434Sjimharris	int			i;
186241434Sjimharris
187241434Sjimharris	num_intr_handler_calls = ctrlr->adminq.num_intr_handler_calls;
188241434Sjimharris
189241434Sjimharris	for (i = 0; i < ctrlr->num_io_queues; i++)
190241434Sjimharris		num_intr_handler_calls += ctrlr->ioq[i].num_intr_handler_calls;
191241434Sjimharris
192241434Sjimharris	return (sysctl_handle_64(oidp, &num_intr_handler_calls, 0, req));
193241434Sjimharris}
194241434Sjimharris
195241434Sjimharrisstatic int
196241434Sjimharrisnvme_sysctl_reset_stats(SYSCTL_HANDLER_ARGS)
197241434Sjimharris{
198241434Sjimharris	struct nvme_controller 	*ctrlr = arg1;
199241434Sjimharris	uint32_t		i, val = 0;
200241434Sjimharris
201241434Sjimharris	int error = sysctl_handle_int(oidp, &val, 0, req);
202241434Sjimharris
203241434Sjimharris	if (error)
204241434Sjimharris		return (error);
205241434Sjimharris
206241434Sjimharris	if (val != 0) {
207241434Sjimharris		nvme_qpair_reset_stats(&ctrlr->adminq);
208241434Sjimharris
209241434Sjimharris		for (i = 0; i < ctrlr->num_io_queues; i++)
210241434Sjimharris			nvme_qpair_reset_stats(&ctrlr->ioq[i]);
211241434Sjimharris	}
212241434Sjimharris
213241434Sjimharris	return (0);
214241434Sjimharris}
215241434Sjimharris
216241434Sjimharris
217241434Sjimharrisstatic void
218240616Sjimharrisnvme_sysctl_initialize_queue(struct nvme_qpair *qpair,
219240616Sjimharris    struct sysctl_ctx_list *ctrlr_ctx, struct sysctl_oid *que_tree)
220240616Sjimharris{
221240616Sjimharris	struct sysctl_oid_list	*que_list = SYSCTL_CHILDREN(que_tree);
222240616Sjimharris
223240616Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_entries",
224240616Sjimharris	    CTLFLAG_RD, &qpair->num_entries, 0,
225240616Sjimharris	    "Number of entries in hardware queue");
226241664Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "num_trackers",
227241664Sjimharris	    CTLFLAG_RD, &qpair->num_trackers, 0,
228241664Sjimharris	    "Number of trackers pre-allocated for this queue pair");
229240616Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_head",
230240616Sjimharris	    CTLFLAG_RD, &qpair->sq_head, 0,
231240616Sjimharris	    "Current head of submission queue (as observed by driver)");
232240616Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "sq_tail",
233240616Sjimharris	    CTLFLAG_RD, &qpair->sq_tail, 0,
234240616Sjimharris	    "Current tail of submission queue (as observed by driver)");
235240616Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, que_list, OID_AUTO, "cq_head",
236240616Sjimharris	    CTLFLAG_RD, &qpair->cq_head, 0,
237240616Sjimharris	    "Current head of completion queue (as observed by driver)");
238240616Sjimharris
239240616Sjimharris	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_cmds",
240240616Sjimharris	    CTLFLAG_RD, &qpair->num_cmds, "Number of commands submitted");
241241434Sjimharris	SYSCTL_ADD_QUAD(ctrlr_ctx, que_list, OID_AUTO, "num_intr_handler_calls",
242241434Sjimharris	    CTLFLAG_RD, &qpair->num_intr_handler_calls,
243241434Sjimharris	    "Number of times interrupt handler was invoked (will typically be "
244241434Sjimharris	    "less than number of actual interrupts generated due to "
245241434Sjimharris	    "coalescing)");
246240616Sjimharris
247240616Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, que_list, OID_AUTO,
248240616Sjimharris	    "dump_debug", CTLTYPE_UINT | CTLFLAG_RW, qpair, 0,
249240616Sjimharris	    nvme_sysctl_dump_debug, "IU", "Dump debug data");
250240616Sjimharris}
251240616Sjimharris
252240616Sjimharrisvoid
253240616Sjimharrisnvme_sysctl_initialize_ctrlr(struct nvme_controller *ctrlr)
254240616Sjimharris{
255240616Sjimharris	struct sysctl_ctx_list	*ctrlr_ctx;
256240616Sjimharris	struct sysctl_oid	*ctrlr_tree, *que_tree;
257240616Sjimharris	struct sysctl_oid_list	*ctrlr_list;
258240616Sjimharris#define QUEUE_NAME_LENGTH	16
259240616Sjimharris	char			queue_name[QUEUE_NAME_LENGTH];
260240616Sjimharris	int			i;
261240616Sjimharris
262240616Sjimharris	ctrlr_ctx = device_get_sysctl_ctx(ctrlr->dev);
263240616Sjimharris	ctrlr_tree = device_get_sysctl_tree(ctrlr->dev);
264240616Sjimharris	ctrlr_list = SYSCTL_CHILDREN(ctrlr_tree);
265240616Sjimharris
266293352Sjimharris	SYSCTL_ADD_UINT(ctrlr_ctx, ctrlr_list, OID_AUTO, "num_cpus_per_ioq",
267293352Sjimharris	    CTLFLAG_RD, &ctrlr->num_cpus_per_ioq, 0,
268293352Sjimharris	    "Number of CPUs assigned per I/O queue pair");
269293352Sjimharris
270248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
271248763Sjimharris	    "int_coal_time", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0,
272248763Sjimharris	    nvme_sysctl_int_coal_time, "IU",
273248763Sjimharris	    "Interrupt coalescing timeout (in microseconds)");
274240616Sjimharris
275248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
276248763Sjimharris	    "int_coal_threshold", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0,
277248763Sjimharris	    nvme_sysctl_int_coal_threshold, "IU",
278248763Sjimharris	    "Interrupt coalescing threshold");
279241434Sjimharris
280248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
281248763Sjimharris	    "timeout_period", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0,
282248763Sjimharris	    nvme_sysctl_timeout_period, "IU",
283248763Sjimharris	    "Timeout period (in seconds)");
284248749Sjimharris
285248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
286248763Sjimharris	    "num_cmds", CTLTYPE_S64 | CTLFLAG_RD,
287248763Sjimharris	    ctrlr, 0, nvme_sysctl_num_cmds, "IU",
288248763Sjimharris	    "Number of commands submitted");
289241434Sjimharris
290248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
291248763Sjimharris	    "num_intr_handler_calls", CTLTYPE_S64 | CTLFLAG_RD,
292248763Sjimharris	    ctrlr, 0, nvme_sysctl_num_intr_handler_calls, "IU",
293248763Sjimharris	    "Number of times interrupt handler was invoked (will "
294248763Sjimharris	    "typically be less than number of actual interrupts "
295248763Sjimharris	    "generated due to coalescing)");
296241434Sjimharris
297248763Sjimharris	SYSCTL_ADD_PROC(ctrlr_ctx, ctrlr_list, OID_AUTO,
298248763Sjimharris	    "reset_stats", CTLTYPE_UINT | CTLFLAG_RW, ctrlr, 0,
299248763Sjimharris	    nvme_sysctl_reset_stats, "IU", "Reset statistics to zero");
300240616Sjimharris
301240616Sjimharris	que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO, "adminq",
302240616Sjimharris	    CTLFLAG_RD, NULL, "Admin Queue");
303240616Sjimharris
304240616Sjimharris	nvme_sysctl_initialize_queue(&ctrlr->adminq, ctrlr_ctx, que_tree);
305240616Sjimharris
306240616Sjimharris	for (i = 0; i < ctrlr->num_io_queues; i++) {
307240616Sjimharris		snprintf(queue_name, QUEUE_NAME_LENGTH, "ioq%d", i);
308240616Sjimharris		que_tree = SYSCTL_ADD_NODE(ctrlr_ctx, ctrlr_list, OID_AUTO,
309240616Sjimharris		    queue_name, CTLFLAG_RD, NULL, "IO Queue");
310240616Sjimharris		nvme_sysctl_initialize_queue(&ctrlr->ioq[i], ctrlr_ctx,
311240616Sjimharris		    que_tree);
312240616Sjimharris	}
313240616Sjimharris}
314