isci_sysctl.c revision 256231
1/*-
2 * BSD LICENSE
3 *
4 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 *   * Redistributions of source code must retain the above copyright
12 *     notice, this list of conditions and the following disclaimer.
13 *   * Redistributions in binary form must reproduce the above copyright
14 *     notice, this list of conditions and the following disclaimer in
15 *     the documentation and/or other materials provided with the
16 *     distribution.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/isci/isci_sysctl.c 256231 2013-10-09 19:37:41Z jimharris $");
33
34#include <dev/isci/isci.h>
35
36#include <sys/sysctl.h>
37
38#include <dev/isci/scil/scif_controller.h>
39#include <dev/isci/scil/scic_phy.h>
40
41static int
42isci_sysctl_coalesce_timeout(SYSCTL_HANDLER_ARGS)
43{
44	struct isci_softc *isci = (struct isci_softc *)arg1;
45	int error = sysctl_handle_int(oidp, &isci->coalesce_timeout, 0, req);
46	int i;
47
48	if (error)
49		return (error);
50
51	for (i = 0; i < isci->controller_count; i++)
52		scif_controller_set_interrupt_coalescence(
53		    isci->controllers[i].scif_controller_handle,
54		    isci->coalesce_number, isci->coalesce_timeout);
55
56	return (0);
57}
58
59static int
60isci_sysctl_coalesce_number(SYSCTL_HANDLER_ARGS)
61{
62	struct isci_softc *isci = (struct isci_softc *)arg1;
63	int error = sysctl_handle_int(oidp, &isci->coalesce_number, 0, req);
64	int i;
65
66	if (error)
67		return (error);
68
69	for (i = 0; i < isci->controller_count; i++)
70		scif_controller_set_interrupt_coalescence(
71		    isci->controllers[i].scif_controller_handle,
72		    isci->coalesce_number, isci->coalesce_timeout);
73
74	return (0);
75}
76
77static void
78isci_sysctl_reset_remote_devices(struct ISCI_CONTROLLER *controller,
79    uint32_t remote_devices_to_be_reset)
80{
81	uint32_t i = 0;
82
83	while (remote_devices_to_be_reset != 0) {
84		if (remote_devices_to_be_reset & 0x1) {
85			struct ISCI_REMOTE_DEVICE *remote_device =
86				controller->remote_device[i];
87
88			if (remote_device != NULL) {
89				mtx_lock(&controller->lock);
90				isci_remote_device_reset(remote_device, NULL);
91				mtx_unlock(&controller->lock);
92			}
93		}
94		remote_devices_to_be_reset >>= 1;
95		i++;
96	}
97}
98
99static int
100isci_sysctl_reset_remote_device_on_controller0(SYSCTL_HANDLER_ARGS)
101{
102	struct isci_softc *isci = (struct isci_softc *)arg1;
103	uint32_t remote_devices_to_be_reset = 0;
104	struct ISCI_CONTROLLER *controller = &isci->controllers[0];
105	int error = sysctl_handle_int(oidp, &remote_devices_to_be_reset, 0, req);
106
107	if (error || remote_devices_to_be_reset == 0)
108		return (error);
109
110	isci_sysctl_reset_remote_devices(controller, remote_devices_to_be_reset);
111
112	return (0);
113}
114
115static int
116isci_sysctl_reset_remote_device_on_controller1(SYSCTL_HANDLER_ARGS)
117{
118	struct isci_softc *isci = (struct isci_softc *)arg1;
119	uint32_t remote_devices_to_be_reset = 0;
120	struct ISCI_CONTROLLER *controller = &isci->controllers[1];
121	int error =
122	    sysctl_handle_int(oidp, &remote_devices_to_be_reset, 0, req);
123
124	if (error || remote_devices_to_be_reset == 0)
125		return (error);
126
127	isci_sysctl_reset_remote_devices(controller,
128	    remote_devices_to_be_reset);
129
130	return (0);
131}
132
133static void
134isci_sysctl_stop(struct ISCI_CONTROLLER *controller, uint32_t phy_to_be_stopped)
135{
136	SCI_PHY_HANDLE_T phy_handle = NULL;
137
138	scic_controller_get_phy_handle(
139	    scif_controller_get_scic_handle(controller->scif_controller_handle),
140	    phy_to_be_stopped, &phy_handle);
141
142	scic_phy_stop(phy_handle);
143}
144
145static int
146isci_sysctl_stop_phy(SYSCTL_HANDLER_ARGS)
147{
148	struct isci_softc *isci = (struct isci_softc *)arg1;
149	uint32_t phy_to_be_stopped = 0xff;
150	uint32_t controller_index, phy_index;
151	int error = sysctl_handle_int(oidp, &phy_to_be_stopped, 0, req);
152
153	controller_index = phy_to_be_stopped / SCI_MAX_PHYS;
154	phy_index = phy_to_be_stopped % SCI_MAX_PHYS;
155
156	if(error || controller_index >= isci->controller_count)
157		return (error);
158
159	isci_sysctl_stop(&isci->controllers[controller_index], phy_index);
160
161	return (0);
162}
163
164static void
165isci_sysctl_start(struct ISCI_CONTROLLER *controller,
166    uint32_t phy_to_be_started)
167{
168	SCI_PHY_HANDLE_T phy_handle = NULL;
169
170	scic_controller_get_phy_handle(
171	    scif_controller_get_scic_handle(controller->scif_controller_handle),
172	    phy_to_be_started, &phy_handle);
173
174	scic_phy_start(phy_handle);
175}
176
177static int
178isci_sysctl_start_phy(SYSCTL_HANDLER_ARGS)
179{
180	struct isci_softc *isci = (struct isci_softc *)arg1;
181	uint32_t phy_to_be_started = 0xff;
182	uint32_t controller_index, phy_index;
183	int error = sysctl_handle_int(oidp, &phy_to_be_started, 0, req);
184
185	controller_index = phy_to_be_started / SCI_MAX_PHYS;
186	phy_index = phy_to_be_started % SCI_MAX_PHYS;
187
188	if(error || controller_index >= isci->controller_count)
189		return error;
190
191	isci_sysctl_start(&isci->controllers[controller_index], phy_index);
192
193	return 0;
194}
195
196static int
197isci_sysctl_log_frozen_lun_masks(SYSCTL_HANDLER_ARGS)
198{
199	struct isci_softc	*isci = (struct isci_softc *)arg1;
200	struct ISCI_REMOTE_DEVICE *device;
201	int32_t			log_frozen_devices = 0;
202	int			error, i, j;
203
204	error = sysctl_handle_int(oidp, &log_frozen_devices, 0, req);
205
206	if (error || log_frozen_devices == 0)
207		return (error);
208
209	for (i = 0; i < isci->controller_count; i++) {
210		for (j = 0; j < SCI_MAX_REMOTE_DEVICES; j++) {
211			device = isci->controllers[i].remote_device[j];
212
213			if (device == NULL)
214				continue;
215
216			device_printf(isci->device,
217			    "controller %d device %3d frozen_lun_mask 0x%02x\n",
218			    i, j, device->frozen_lun_mask);
219		}
220	}
221
222	return (0);
223}
224
225void isci_sysctl_initialize(struct isci_softc *isci)
226{
227	struct sysctl_ctx_list *sysctl_ctx = device_get_sysctl_ctx(isci->device);
228	struct sysctl_oid *sysctl_tree = device_get_sysctl_tree(isci->device);
229
230	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
231	    "coalesce_timeout", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
232	    isci_sysctl_coalesce_timeout, "IU",
233	    "Interrupt coalescing timeout (in microseconds)");
234
235	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
236	    "coalesce_number", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
237	    isci_sysctl_coalesce_number, "IU",
238	    "Interrupt coalescing number");
239
240	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
241	    "reset_remote_device_on_controller0", CTLTYPE_UINT| CTLFLAG_RW,
242	    isci, 0, isci_sysctl_reset_remote_device_on_controller0, "IU",
243	    "Reset remote device on controller 0");
244
245	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
246	    "reset_remote_device_on_controller1", CTLTYPE_UINT| CTLFLAG_RW,
247	    isci, 0, isci_sysctl_reset_remote_device_on_controller1, "IU",
248	    "Reset remote device on controller 1");
249
250	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
251	    "stop_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0, isci_sysctl_stop_phy,
252	    "IU", "Stop PHY on a controller");
253
254	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
255	    "start_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0,
256	    isci_sysctl_start_phy, "IU", "Start PHY on a controller");
257
258	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
259	    "log_frozen_lun_masks", CTLTYPE_UINT| CTLFLAG_RW, isci, 0,
260	    isci_sysctl_log_frozen_lun_masks, "IU",
261	    "Log frozen lun masks to kernel log");
262}
263
264