isci_sysctl.c revision 230843
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$");
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
196void isci_sysctl_initialize(struct isci_softc *isci)
197{
198	struct sysctl_ctx_list *sysctl_ctx = device_get_sysctl_ctx(isci->device);
199	struct sysctl_oid *sysctl_tree = device_get_sysctl_tree(isci->device);
200
201	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
202	    "coalesce_timeout", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
203	    isci_sysctl_coalesce_timeout, "IU",
204	    "Interrupt coalescing timeout (in microseconds)");
205
206	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
207	    "coalesce_number", CTLTYPE_UINT | CTLFLAG_RW, isci, 0,
208	    isci_sysctl_coalesce_number, "IU",
209	    "Interrupt coalescing number");
210
211	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
212	    "reset_remote_device_on_controller0", CTLTYPE_UINT| CTLFLAG_RW,
213	    isci, 0, isci_sysctl_reset_remote_device_on_controller0, "IU",
214	    "Reset remote device on controller 0");
215
216	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
217	    "reset_remote_device_on_controller1", CTLTYPE_UINT| CTLFLAG_RW,
218	    isci, 0, isci_sysctl_reset_remote_device_on_controller1, "IU",
219	    "Reset remote device on controller 1");
220
221	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
222	    "stop_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0, isci_sysctl_stop_phy,
223	    "IU", "Stop PHY on a controller");
224
225	SYSCTL_ADD_PROC(sysctl_ctx, SYSCTL_CHILDREN(sysctl_tree), OID_AUTO,
226	    "start_phy", CTLTYPE_UINT| CTLFLAG_RW, isci, 0,
227	    isci_sysctl_start_phy, "IU", "Start PHY on a controller");
228}
229
230