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 41 static int 42 isci_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 59 static int 60 isci_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 77 static void 78 isci_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 99 static int 100 isci_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 115 static int 116 isci_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 133 static void 134 isci_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 145 static int 146 isci_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 164 static void 165 isci_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 177 static int 178 isci_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 196 void 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