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 88 q80_offchip_mem_val_t val; 89 qla_rd_pci_ids_t *pci_ids; 90 qla_rd_fw_dump_t *fw_dump; 91 union { 92 qla_reg_val_t *rv; 93 qla_rd_flash_t *rdf; 94 qla_wr_flash_t *wrf; 95 qla_erase_flash_t *erf; 96 qla_offchip_mem_val_t *mem; 97 } u; 98 99 100 if ((ha = (qla_host_t *)dev->si_drv1) == NULL) 101 return ENXIO; 102 103 pci_dev= ha->pci_dev; 104 105 switch(cmd) { 106 107 case QLA_RDWR_REG: 108 109 u.rv = (qla_reg_val_t *)data; 110 111 if (u.rv->direct) { 112 if (u.rv->rd) { 113 u.rv->val = READ_REG32(ha, u.rv->reg); 114 } else { 115 WRITE_REG32(ha, u.rv->reg, u.rv->val); 116 } 117 } else { 118 if ((rval = ql_rdwr_indreg32(ha, u.rv->reg, &u.rv->val, 119 u.rv->rd))) 120 rval = ENXIO; 121 } 122 break; 123 124 case QLA_RD_FLASH: 125 126 if (!ha->hw.flags.fdt_valid) { 127 rval = EIO; 128 break; 129 } 130 131 u.rdf = (qla_rd_flash_t *)data; 132 if ((rval = ql_rd_flash32(ha, u.rdf->off, &u.rdf->data))) 133 rval = ENXIO; 134 break; 135 136 case QLA_WR_FLASH: 137 138 ifp = ha->ifp; 139 140 if (ifp == NULL) { 141 rval = ENXIO; 142 break; 143 } 144 145 if (ifp->if_drv_flags & (IFF_DRV_OACTIVE | IFF_DRV_RUNNING)) { 146 rval = ENXIO; 147 break; 148 } 149 150 if (!ha->hw.flags.fdt_valid) { 151 rval = EIO; 152 break; 153 } 154 155 u.wrf = (qla_wr_flash_t *)data; 156 if ((rval = ql_wr_flash_buffer(ha, u.wrf->off, u.wrf->size, 157 u.wrf->buffer))) { 158 printf("flash write failed[%d]\n", rval); 159 rval = ENXIO; 160 } 161 break; 162 163 case QLA_ERASE_FLASH: 164 165 ifp = ha->ifp; 166 167 if (ifp == NULL) { 168 rval = ENXIO; 169 break; 170 } 171 172 if (ifp->if_drv_flags & (IFF_DRV_OACTIVE | IFF_DRV_RUNNING)) { 173 rval = ENXIO; 174 break; 175 } 176 177 if (!ha->hw.flags.fdt_valid) { 178 rval = EIO; 179 break; 180 } 181 182 u.erf = (qla_erase_flash_t *)data; 183 if ((rval = ql_erase_flash(ha, u.erf->off, 184 u.erf->size))) { 185 printf("flash erase failed[%d]\n", rval); 186 rval = ENXIO; 187 } 188 break; 189 190 case QLA_RDWR_MS_MEM: 191 u.mem = (qla_offchip_mem_val_t *)data; 192 193 if ((rval = ql_rdwr_offchip_mem(ha, u.mem->off, &val, 194 u.mem->rd))) 195 rval = ENXIO; 196 else { 197 u.mem->data_lo = val.data_lo; 198 u.mem->data_hi = val.data_hi; 199 u.mem->data_ulo = val.data_ulo; 200 u.mem->data_uhi = val.data_uhi; 201 } 202 203 break; 204 205 case QLA_RD_FW_DUMP_SIZE: 206 207 if (ha->hw.mdump_init == 0) { 208 rval = EINVAL; 209 break; 210 } 211 212 fw_dump = (qla_rd_fw_dump_t *)data; 213 fw_dump->template_size = ha->hw.dma_buf.minidump.size; 214 fw_dump->pci_func = ha->pci_func; 215 216 break; 217 218 case QLA_RD_FW_DUMP: 219 220 if (ha->hw.mdump_init == 0) { 221 rval = EINVAL; 222 break; 223 } 224 225 fw_dump = (qla_rd_fw_dump_t *)data; 226 227 if ((fw_dump->md_template == NULL) || 228 (fw_dump->template_size != ha->hw.dma_buf.minidump.size)) { 229 rval = EINVAL; 230 break; 231 } 232 233 if ((rval = copyout(ha->hw.dma_buf.minidump.dma_b, 234 fw_dump->md_template, fw_dump->template_size))) 235 rval = ENXIO; 236 break; 237 238 case QLA_RD_PCI_IDS: 239 pci_ids = (qla_rd_pci_ids_t *)data; 240 pci_ids->ven_id = pci_get_vendor(pci_dev); 241 pci_ids->dev_id = pci_get_device(pci_dev); 242 pci_ids->subsys_ven_id = pci_get_subvendor(pci_dev); 243 pci_ids->subsys_dev_id = pci_get_subdevice(pci_dev); 244 pci_ids->rev_id = pci_read_config(pci_dev, PCIR_REVID, 1); 245 break; 246 247 default: 248 break; 249 } 250 251 return rval; 252 } 253 254