1 /* 2 * Copyright (c) 2013-2016 Qlogic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25 * POSSIBILITY OF SUCH DAMAGE. 26 */ 27 /* 28 * File: ql_ioctl.c 29 * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 36 #include "ql_os.h" 37 #include "ql_hw.h" 38 #include "ql_def.h" 39 #include "ql_inline.h" 40 #include "ql_glbl.h" 41 #include "ql_ioctl.h" 42 43 static int ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 44 struct thread *td); 45 46 static struct cdevsw qla_cdevsw = { 47 .d_version = D_VERSION, 48 .d_ioctl = ql_eioctl, 49 .d_name = "qlcnic", 50 }; 51 52 int 53 ql_make_cdev(qla_host_t *ha) 54 { 55 ha->ioctl_dev = make_dev(&qla_cdevsw, 56 ha->ifp->if_dunit, 57 UID_ROOT, 58 GID_WHEEL, 59 0600, 60 "%s", 61 if_name(ha->ifp)); 62 63 if (ha->ioctl_dev == NULL) 64 return (-1); 65 66 ha->ioctl_dev->si_drv1 = ha; 67 68 return (0); 69 } 70 71 void 72 ql_del_cdev(qla_host_t *ha) 73 { 74 if (ha->ioctl_dev != NULL) 75 destroy_dev(ha->ioctl_dev); 76 return; 77 } 78 79 static int 80 ql_eioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, 81 struct thread *td) 82 { 83 qla_host_t *ha; 84 int rval = 0; 85 device_t pci_dev; 86 struct ifnet *ifp; 87 int count; 88 89 q80_offchip_mem_val_t val; 90 qla_rd_pci_ids_t *pci_ids; 91 qla_rd_fw_dump_t *fw_dump; 92 union { 93 qla_reg_val_t *rv; 94 qla_rd_flash_t *rdf; 95 qla_wr_flash_t *wrf; 96 qla_erase_flash_t *erf; 97 qla_offchip_mem_val_t *mem; 98 } u; 99 100 101 if ((ha = (qla_host_t *)dev->si_drv1) == NULL) 102 return ENXIO; 103 104 pci_dev= ha->pci_dev; 105 106 switch(cmd) { 107 108 case QLA_RDWR_REG: 109 110 u.rv = (qla_reg_val_t *)data; 111 112 if (u.rv->direct) { 113 if (u.rv->rd) { 114 u.rv->val = READ_REG32(ha, u.rv->reg); 115 } else { 116 WRITE_REG32(ha, u.rv->reg, u.rv->val); 117 } 118 } else { 119 if ((rval = ql_rdwr_indreg32(ha, u.rv->reg, &u.rv->val, 120 u.rv->rd))) 121 rval = ENXIO; 122 } 123 break; 124 125 case QLA_RD_FLASH: 126 127 if (!ha->hw.flags.fdt_valid) { 128 rval = EIO; 129 break; 130 } 131 132 u.rdf = (qla_rd_flash_t *)data; 133 if ((rval = ql_rd_flash32(ha, u.rdf->off, &u.rdf->data))) 134 rval = ENXIO; 135 break; 136 137 case QLA_WR_FLASH: 138 139 ifp = ha->ifp; 140 141 if (ifp == NULL) { 142 rval = ENXIO; 143 break; 144 } 145 146 if (ifp->if_drv_flags & (IFF_DRV_OACTIVE | IFF_DRV_RUNNING)) { 147 rval = ENXIO; 148 break; 149 } 150 151 if (!ha->hw.flags.fdt_valid) { 152 rval = EIO; 153 break; 154 } 155 156 u.wrf = (qla_wr_flash_t *)data; 157 if ((rval = ql_wr_flash_buffer(ha, u.wrf->off, u.wrf->size, 158 u.wrf->buffer))) { 159 printf("flash write failed[%d]\n", rval); 160 rval = ENXIO; 161 } 162 break; 163 164 case QLA_ERASE_FLASH: 165 166 ifp = ha->ifp; 167 168 if (ifp == NULL) { 169 rval = ENXIO; 170 break; 171 } 172 173 if (ifp->if_drv_flags & (IFF_DRV_OACTIVE | IFF_DRV_RUNNING)) { 174 rval = ENXIO; 175 break; 176 } 177 178 if (!ha->hw.flags.fdt_valid) { 179 rval = EIO; 180 break; 181 } 182 183 u.erf = (qla_erase_flash_t *)data; 184 if ((rval = ql_erase_flash(ha, u.erf->off, 185 u.erf->size))) { 186 printf("flash erase failed[%d]\n", rval); 187 rval = ENXIO; 188 } 189 break; 190 191 case QLA_RDWR_MS_MEM: 192 u.mem = (qla_offchip_mem_val_t *)data; 193 194 if ((rval = ql_rdwr_offchip_mem(ha, u.mem->off, &val, 195 u.mem->rd))) 196 rval = ENXIO; 197 else { 198 u.mem->data_lo = val.data_lo; 199 u.mem->data_hi = val.data_hi; 200 u.mem->data_ulo = val.data_ulo; 201 u.mem->data_uhi = val.data_uhi; 202 } 203 204 break; 205 206 case QLA_RD_FW_DUMP_SIZE: 207 208 if (ha->hw.mdump_init == 0) { 209 rval = EINVAL; 210 break; 211 } 212 213 fw_dump = (qla_rd_fw_dump_t *)data; 214 fw_dump->minidump_size = ha->hw.mdump_buffer_size + 215 ha->hw.mdump_template_size; 216 fw_dump->pci_func = ha->pci_func; 217 218 break; 219 220 case QLA_RD_FW_DUMP: 221 222 if (ha->hw.mdump_init == 0) { 223 rval = EINVAL; 224 break; 225 } 226 227 fw_dump = (qla_rd_fw_dump_t *)data; 228 229 if ((fw_dump->minidump == NULL) || 230 (fw_dump->minidump_size != (ha->hw.mdump_buffer_size + 231 ha->hw.mdump_template_size))) { 232 rval = EINVAL; 233 break; 234 } 235 236 (void)QLA_LOCK(ha, __func__, 0); 237 if (!ha->hw.mdump_done) 238 ha->qla_initiate_recovery = 1; 239 QLA_UNLOCK(ha, __func__); 240 241 #define QLNX_DUMP_WAIT_SECS 30 242 243 count = QLNX_DUMP_WAIT_SECS * 1000; 244 245 while (count) { 246 if (ha->hw.mdump_done) 247 break; 248 qla_mdelay(__func__, 100); 249 count -= 100; 250 } 251 252 if (!ha->hw.mdump_done) { 253 rval = ENXIO; 254 break; 255 } 256 257 (void)QLA_LOCK(ha, __func__, 0); 258 ha->hw.mdump_done = 0; 259 QLA_UNLOCK(ha, __func__); 260 261 if ((rval = copyout(ha->hw.mdump_template, 262 fw_dump->minidump, ha->hw.mdump_template_size))) { 263 rval = ENXIO; 264 break; 265 } 266 267 if ((rval = copyout(ha->hw.mdump_buffer, 268 ((uint8_t *)fw_dump->minidump + 269 ha->hw.mdump_template_size), 270 ha->hw.mdump_buffer_size))) 271 rval = ENXIO; 272 break; 273 274 case QLA_RD_PCI_IDS: 275 pci_ids = (qla_rd_pci_ids_t *)data; 276 pci_ids->ven_id = pci_get_vendor(pci_dev); 277 pci_ids->dev_id = pci_get_device(pci_dev); 278 pci_ids->subsys_ven_id = pci_get_subvendor(pci_dev); 279 pci_ids->subsys_dev_id = pci_get_subdevice(pci_dev); 280 pci_ids->rev_id = pci_read_config(pci_dev, PCIR_REVID, 1); 281 break; 282 283 default: 284 break; 285 } 286 287 return rval; 288 } 289 290