ql_os.c revision 281955
1249259Sdim/* 2249259Sdim * Copyright (c) 2013-2014 Qlogic Corporation 3249259Sdim * All rights reserved. 4249259Sdim * 5249259Sdim * Redistribution and use in source and binary forms, with or without 6249259Sdim * modification, are permitted provided that the following conditions 7249259Sdim * are met: 8249259Sdim * 9249259Sdim * 1. Redistributions of source code must retain the above copyright 10249259Sdim * notice, this list of conditions and the following disclaimer. 11249259Sdim * 2. Redistributions in binary form must reproduce the above copyright 12249259Sdim * notice, this list of conditions and the following disclaimer in the 13249259Sdim * documentation and/or other materials provided with the distribution. 14249259Sdim * 15249259Sdim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16251662Sdim * and ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17251662Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18321369Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19321369Sdim * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20321369Sdim * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21321369Sdim * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22321369Sdim * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23249259Sdim * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24321369Sdim * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25249259Sdim * POSSIBILITY OF SUCH DAMAGE. 26276479Sdim */ 27249259Sdim 28249259Sdim/* 29249259Sdim * File: ql_os.c 30249259Sdim * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 31249259Sdim */ 32321369Sdim 33321369Sdim#include <sys/cdefs.h> 34249259Sdim__FBSDID("$FreeBSD: stable/10/sys/dev/qlxgbe/ql_os.c 281955 2015-04-24 23:26:44Z hiren $"); 35261991Sdim 36251662Sdim 37249259Sdim#include "ql_os.h" 38249259Sdim#include "ql_hw.h" 39249259Sdim#include "ql_def.h" 40321369Sdim#include "ql_inline.h" 41321369Sdim#include "ql_ver.h" 42288943Sdim#include "ql_glbl.h" 43321369Sdim#include "ql_dbg.h" 44276479Sdim#include <sys/smp.h> 45276479Sdim 46321369Sdim/* 47321369Sdim * Some PCI Configuration Space Related Defines 48261991Sdim */ 49276479Sdim 50321369Sdim#ifndef PCI_VENDOR_QLOGIC 51249259Sdim#define PCI_VENDOR_QLOGIC 0x1077 52261991Sdim#endif 53321369Sdim 54321369Sdim#ifndef PCI_PRODUCT_QLOGIC_ISP8030 55321369Sdim#define PCI_PRODUCT_QLOGIC_ISP8030 0x8030 56321369Sdim#endif 57321369Sdim 58249259Sdim#define PCI_QLOGIC_ISP8030 \ 59249259Sdim ((PCI_PRODUCT_QLOGIC_ISP8030 << 16) | PCI_VENDOR_QLOGIC) 60249259Sdim 61251662Sdim/* 62276479Sdim * static functions 63276479Sdim */ 64251662Sdimstatic int qla_alloc_parent_dma_tag(qla_host_t *ha); 65251662Sdimstatic void qla_free_parent_dma_tag(qla_host_t *ha); 66251662Sdimstatic int qla_alloc_xmt_bufs(qla_host_t *ha); 67249259Sdimstatic void qla_free_xmt_bufs(qla_host_t *ha); 68249259Sdimstatic int qla_alloc_rcv_bufs(qla_host_t *ha); 69261991Sdimstatic void qla_free_rcv_bufs(qla_host_t *ha); 70261991Sdimstatic void qla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb); 71261991Sdim 72261991Sdimstatic void qla_init_ifnet(device_t dev, qla_host_t *ha); 73261991Sdimstatic int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS); 74276479Sdimstatic int qla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS); 75261991Sdimstatic void qla_release(qla_host_t *ha); 76276479Sdimstatic void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 77276479Sdim int error); 78276479Sdimstatic void qla_stop(qla_host_t *ha); 79276479Sdimstatic int qla_send(qla_host_t *ha, struct mbuf **m_headp); 80276479Sdimstatic void qla_tx_done(void *context, int pending); 81276479Sdimstatic void qla_get_peer(qla_host_t *ha); 82276479Sdimstatic void qla_error_recovery(void *context, int pending); 83276479Sdim 84276479Sdim/* 85276479Sdim * Hooks to the Operating Systems 86276479Sdim */ 87276479Sdimstatic int qla_pci_probe (device_t); 88276479Sdimstatic int qla_pci_attach (device_t); 89261991Sdimstatic int qla_pci_detach (device_t); 90276479Sdim 91276479Sdimstatic void qla_init(void *arg); 92276479Sdimstatic int qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 93276479Sdimstatic int qla_media_change(struct ifnet *ifp); 94296417Sdimstatic void qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr); 95276479Sdimstatic void qla_start(struct ifnet *ifp); 96288943Sdim 97276479Sdimstatic device_method_t qla_pci_methods[] = { 98276479Sdim /* Device interface */ 99276479Sdim DEVMETHOD(device_probe, qla_pci_probe), 100276479Sdim DEVMETHOD(device_attach, qla_pci_attach), 101261991Sdim DEVMETHOD(device_detach, qla_pci_detach), 102276479Sdim { 0, 0 } 103276479Sdim}; 104276479Sdim 105261991Sdimstatic driver_t qla_pci_driver = { 106276479Sdim "ql", qla_pci_methods, sizeof (qla_host_t), 107276479Sdim}; 108261991Sdim 109261991Sdimstatic devclass_t qla83xx_devclass; 110276479Sdim 111276479SdimDRIVER_MODULE(qla83xx, pci, qla_pci_driver, qla83xx_devclass, 0, 0); 112276479Sdim 113276479SdimMODULE_DEPEND(qla83xx, pci, 1, 1, 1); 114276479SdimMODULE_DEPEND(qla83xx, ether, 1, 1, 1); 115276479Sdim 116321369SdimMALLOC_DEFINE(M_QLA83XXBUF, "qla83xxbuf", "Buffers for qla83xx driver"); 117261991Sdim 118261991Sdim#define QL_STD_REPLENISH_THRES 0 119261991Sdim#define QL_JUMBO_REPLENISH_THRES 32 120321369Sdim 121261991Sdim 122261991Sdimstatic char dev_str[64]; 123261991Sdim 124321369Sdim/* 125276479Sdim * Name: qla_pci_probe 126276479Sdim * Function: Validate the PCI device to be a QLA80XX device 127276479Sdim */ 128321369Sdimstatic int 129261991Sdimqla_pci_probe(device_t dev) 130321369Sdim{ 131261991Sdim switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 132261991Sdim case PCI_QLOGIC_ISP8030: 133261991Sdim snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d", 134261991Sdim "Qlogic ISP 83xx PCI CNA Adapter-Ethernet Function", 135261991Sdim QLA_VERSION_MAJOR, QLA_VERSION_MINOR, 136261991Sdim QLA_VERSION_BUILD); 137261991Sdim device_set_desc(dev, dev_str); 138261991Sdim break; 139261991Sdim default: 140261991Sdim return (ENXIO); 141321369Sdim } 142276479Sdim 143276479Sdim if (bootverbose) 144276479Sdim printf("%s: %s\n ", __func__, dev_str); 145276479Sdim 146276479Sdim return (BUS_PROBE_DEFAULT); 147276479Sdim} 148276479Sdim 149276479Sdimstatic void 150276479Sdimqla_add_sysctls(qla_host_t *ha) 151276479Sdim{ 152321369Sdim device_t dev = ha->pci_dev; 153261991Sdim 154261991Sdim SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 155261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 156321369Sdim OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, 157261991Sdim (void *)ha, 0, 158261991Sdim qla_sysctl_get_stats, "I", "Statistics"); 159261991Sdim 160261991Sdim SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), 161261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 162261991Sdim OID_AUTO, "fw_version", CTLFLAG_RD, 163261991Sdim ha->fw_ver_str, 0, "firmware version"); 164261991Sdim 165261991Sdim SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 166261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 167261991Sdim OID_AUTO, "link_status", CTLTYPE_INT | CTLFLAG_RW, 168261991Sdim (void *)ha, 0, 169261991Sdim qla_sysctl_get_link_status, "I", "Link Status"); 170261991Sdim 171261991Sdim ha->dbg_level = 0; 172261991Sdim SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 173261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 174321369Sdim OID_AUTO, "debug", CTLFLAG_RW, 175321369Sdim &ha->dbg_level, ha->dbg_level, "Debug Level"); 176321369Sdim 177261991Sdim ha->std_replenish = QL_STD_REPLENISH_THRES; 178276479Sdim SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 179276479Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 180276479Sdim OID_AUTO, "std_replenish", CTLFLAG_RW, 181276479Sdim &ha->std_replenish, ha->std_replenish, 182276479Sdim "Threshold for Replenishing Standard Frames"); 183276479Sdim 184276479Sdim SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 185261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 186321369Sdim OID_AUTO, "ipv4_lro", 187261991Sdim CTLFLAG_RD, &ha->ipv4_lro, 188261991Sdim "number of ipv4 lro completions"); 189261991Sdim 190261991Sdim SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 191276479Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 192261991Sdim OID_AUTO, "ipv6_lro", 193276479Sdim CTLFLAG_RD, &ha->ipv6_lro, 194276479Sdim "number of ipv6 lro completions"); 195276479Sdim 196276479Sdim SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 197276479Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 198276479Sdim OID_AUTO, "tx_tso_frames", 199276479Sdim CTLFLAG_RD, &ha->tx_tso_frames, 200276479Sdim "number of Tx TSO Frames"); 201261991Sdim 202276479Sdim SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 203261991Sdim SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 204321369Sdim OID_AUTO, "hw_vlan_tx_frames", 205276479Sdim CTLFLAG_RD, &ha->hw_vlan_tx_frames, 206276479Sdim "number of Tx VLAN Frames"); 207276479Sdim 208276479Sdim return; 209276479Sdim} 210276479Sdim 211276479Sdimstatic void 212276479Sdimqla_watchdog(void *arg) 213276479Sdim{ 214276479Sdim qla_host_t *ha = arg; 215276479Sdim qla_hw_t *hw; 216276479Sdim struct ifnet *ifp; 217276479Sdim uint32_t i; 218276479Sdim qla_hw_tx_cntxt_t *hw_tx_cntxt; 219276479Sdim 220321369Sdim hw = &ha->hw; 221276479Sdim ifp = ha->ifp; 222296417Sdim 223276479Sdim if (ha->flags.qla_watchdog_exit) { 224321369Sdim ha->qla_watchdog_exited = 1; 225288943Sdim return; 226296417Sdim } 227288943Sdim ha->qla_watchdog_exited = 0; 228321369Sdim 229276479Sdim if (!ha->flags.qla_watchdog_pause) { 230296417Sdim if (ql_hw_check_health(ha) || ha->qla_initiate_recovery || 231276479Sdim (ha->msg_from_peer == QL_PEER_MSG_RESET)) { 232321369Sdim ha->qla_watchdog_paused = 1; 233261991Sdim ha->flags.qla_watchdog_pause = 1; 234296417Sdim ha->qla_initiate_recovery = 0; 235261991Sdim ha->err_inject = 0; 236321369Sdim taskqueue_enqueue(ha->err_tq, &ha->err_task); 237321369Sdim } else { 238321369Sdim for (i = 0; i < ha->hw.num_tx_rings; i++) { 239276479Sdim hw_tx_cntxt = &hw->tx_cntxt[i]; 240276479Sdim if (qla_le32_to_host(*(hw_tx_cntxt->tx_cons)) != 241276479Sdim hw_tx_cntxt->txr_comp) { 242276479Sdim taskqueue_enqueue(ha->tx_tq, 243261991Sdim &ha->tx_task); 244276479Sdim break; 245288943Sdim } 246288943Sdim } 247288943Sdim 248288943Sdim if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) { 249288943Sdim taskqueue_enqueue(ha->tx_tq, &ha->tx_task); 250288943Sdim } 251288943Sdim ha->qla_watchdog_paused = 0; 252276479Sdim } 253276479Sdim 254276479Sdim } else { 255276479Sdim ha->qla_watchdog_paused = 1; 256276479Sdim } 257276479Sdim 258288943Sdim ha->watchdog_ticks = ha->watchdog_ticks++ % 1000; 259276479Sdim callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 260276479Sdim qla_watchdog, ha); 261276479Sdim} 262276479Sdim 263276479Sdim/* 264276479Sdim * Name: qla_pci_attach 265276479Sdim * Function: attaches the device to the operating system 266276479Sdim */ 267288943Sdimstatic int 268276479Sdimqla_pci_attach(device_t dev) 269276479Sdim{ 270276479Sdim qla_host_t *ha = NULL; 271261991Sdim uint32_t rsrc_len; 272261991Sdim int i; 273261991Sdim 274296417Sdim QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 275261991Sdim 276261991Sdim if ((ha = device_get_softc(dev)) == NULL) { 277261991Sdim device_printf(dev, "cannot get softc\n"); 278261991Sdim return (ENOMEM); 279261991Sdim } 280276479Sdim 281276479Sdim memset(ha, 0, sizeof (qla_host_t)); 282261991Sdim 283261991Sdim if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8030) { 284261991Sdim device_printf(dev, "device is not ISP8030\n"); 285296417Sdim return (ENXIO); 286261991Sdim } 287261991Sdim 288280031Sdim ha->pci_func = pci_get_function(dev); 289280031Sdim 290280031Sdim ha->pci_dev = dev; 291280031Sdim 292280031Sdim pci_enable_busmaster(dev); 293280031Sdim 294280031Sdim ha->reg_rid = PCIR_BAR(0); 295280031Sdim ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid, 296280031Sdim RF_ACTIVE); 297280031Sdim 298280031Sdim if (ha->pci_reg == NULL) { 299280031Sdim device_printf(dev, "unable to map any ports\n"); 300280031Sdim goto qla_pci_attach_err; 301261991Sdim } 302261991Sdim 303261991Sdim rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY, 304261991Sdim ha->reg_rid); 305321369Sdim 306321369Sdim mtx_init(&ha->hw_lock, "qla83xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF); 307321369Sdim 308261991Sdim mtx_init(&ha->tx_lock, "qla83xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF); 309261991Sdim 310321369Sdim qla_add_sysctls(ha); 311261991Sdim ql_hw_add_sysctls(ha); 312261991Sdim 313261991Sdim ha->flags.lock_init = 1; 314261991Sdim 315261991Sdim ha->reg_rid1 = PCIR_BAR(2); 316276479Sdim ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 317261991Sdim &ha->reg_rid1, RF_ACTIVE); 318261991Sdim 319261991Sdim ha->msix_count = pci_msix_count(dev); 320261991Sdim 321261991Sdim if (ha->msix_count < (ha->hw.num_sds_rings + 1)) { 322261991Sdim device_printf(dev, "%s: msix_count[%d] not enough\n", __func__, 323261991Sdim ha->msix_count); 324261991Sdim goto qla_pci_attach_err; 325276479Sdim } 326261991Sdim 327261991Sdim QL_DPRINT2(ha, (dev, "%s: ha %p pci_func 0x%x rsrc_count 0x%08x" 328261991Sdim " msix_count 0x%x pci_reg %p\n", __func__, ha, 329261991Sdim ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg)); 330261991Sdim 331261991Sdim ha->msix_count = ha->hw.num_sds_rings + 1; 332261991Sdim 333261991Sdim if (pci_alloc_msix(dev, &ha->msix_count)) { 334261991Sdim device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__, 335261991Sdim ha->msix_count); 336261991Sdim ha->msix_count = 0; 337261991Sdim goto qla_pci_attach_err; 338261991Sdim } 339261991Sdim 340261991Sdim ha->mbx_irq_rid = 1; 341261991Sdim ha->mbx_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 342261991Sdim &ha->mbx_irq_rid, 343261991Sdim (RF_ACTIVE | RF_SHAREABLE)); 344261991Sdim if (ha->mbx_irq == NULL) { 345261991Sdim device_printf(dev, "could not allocate mbx interrupt\n"); 346276479Sdim goto qla_pci_attach_err; 347261991Sdim } 348261991Sdim if (bus_setup_intr(dev, ha->mbx_irq, (INTR_TYPE_NET | INTR_MPSAFE), 349261991Sdim NULL, ql_mbx_isr, ha, &ha->mbx_handle)) { 350261991Sdim device_printf(dev, "could not setup mbx interrupt\n"); 351261991Sdim goto qla_pci_attach_err; 352261991Sdim } 353261991Sdim 354261991Sdim 355261991Sdim for (i = 0; i < ha->hw.num_sds_rings; i++) { 356261991Sdim ha->irq_vec[i].sds_idx = i; 357261991Sdim ha->irq_vec[i].ha = ha; 358261991Sdim ha->irq_vec[i].irq_rid = 2 + i; 359261991Sdim 360261991Sdim ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 361276479Sdim &ha->irq_vec[i].irq_rid, 362276479Sdim (RF_ACTIVE | RF_SHAREABLE)); 363276479Sdim 364276479Sdim if (ha->irq_vec[i].irq == NULL) { 365276479Sdim device_printf(dev, "could not allocate interrupt\n"); 366276479Sdim goto qla_pci_attach_err; 367276479Sdim } 368276479Sdim if (bus_setup_intr(dev, ha->irq_vec[i].irq, 369276479Sdim (INTR_TYPE_NET | INTR_MPSAFE), 370276479Sdim NULL, ql_isr, &ha->irq_vec[i], 371276479Sdim &ha->irq_vec[i].handle)) { 372276479Sdim device_printf(dev, "could not setup interrupt\n"); 373276479Sdim goto qla_pci_attach_err; 374276479Sdim } 375276479Sdim } 376276479Sdim 377276479Sdim printf("%s: mp__ncpus %d sds %d rds %d msi-x %d\n", __func__, mp_ncpus, 378276479Sdim ha->hw.num_sds_rings, ha->hw.num_rds_rings, ha->msix_count); 379276479Sdim 380276479Sdim /* initialize hardware */ 381276479Sdim if (ql_init_hw(ha)) { 382276479Sdim device_printf(dev, "%s: ql_init_hw failed\n", __func__); 383276479Sdim goto qla_pci_attach_err; 384261991Sdim } 385261991Sdim 386261991Sdim device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__, 387261991Sdim ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 388276479Sdim ha->fw_ver_build); 389276479Sdim snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d", 390276479Sdim ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 391276479Sdim ha->fw_ver_build); 392276479Sdim 393276479Sdim ql_read_mac_addr(ha); 394276479Sdim 395276479Sdim /* allocate parent dma tag */ 396276479Sdim if (qla_alloc_parent_dma_tag(ha)) { 397276479Sdim device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n", 398276479Sdim __func__); 399276479Sdim goto qla_pci_attach_err; 400276479Sdim } 401261991Sdim 402276479Sdim /* alloc all dma buffers */ 403276479Sdim if (ql_alloc_dma(ha)) { 404276479Sdim device_printf(dev, "%s: ql_alloc_dma failed\n", __func__); 405276479Sdim goto qla_pci_attach_err; 406276479Sdim } 407276479Sdim qla_get_peer(ha); 408276479Sdim 409276479Sdim /* create the o.s ethernet interface */ 410276479Sdim qla_init_ifnet(dev, ha); 411276479Sdim 412276479Sdim ha->flags.qla_watchdog_active = 1; 413261991Sdim ha->flags.qla_watchdog_pause = 1; 414276479Sdim 415276479Sdim 416276479Sdim TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha); 417261991Sdim ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT, 418261991Sdim taskqueue_thread_enqueue, &ha->tx_tq); 419296417Sdim taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq", 420296417Sdim device_get_nameunit(ha->pci_dev)); 421296417Sdim 422261991Sdim callout_init(&ha->tx_callout, TRUE); 423276479Sdim ha->flags.qla_callout_init = 1; 424321369Sdim 425261991Sdim /* create ioctl device interface */ 426261991Sdim if (ql_make_cdev(ha)) { 427249259Sdim device_printf(dev, "%s: ql_make_cdev failed\n", __func__); 428249259Sdim goto qla_pci_attach_err; 429249259Sdim } 430249259Sdim 431249259Sdim callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 432249259Sdim qla_watchdog, ha); 433249259Sdim 434249259Sdim TASK_INIT(&ha->err_task, 0, qla_error_recovery, ha); 435249259Sdim ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT, 436249259Sdim taskqueue_thread_enqueue, &ha->err_tq); 437249259Sdim taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq", 438249259Sdim device_get_nameunit(ha->pci_dev)); 439249259Sdim 440249259Sdim QL_DPRINT2(ha, (dev, "%s: exit 0\n", __func__)); 441261991Sdim return (0); 442261991Sdim 443288943Sdimqla_pci_attach_err: 444276479Sdim 445321369Sdim qla_release(ha); 446296417Sdim 447251662Sdim QL_DPRINT2(ha, (dev, "%s: exit ENXIO\n", __func__)); 448249259Sdim return (ENXIO); 449321369Sdim} 450249259Sdim 451276479Sdim/* 452261991Sdim * Name: qla_pci_detach 453249259Sdim * Function: Unhooks the device from the operating system 454261991Sdim */ 455261991Sdimstatic int 456261991Sdimqla_pci_detach(device_t dev) 457261991Sdim{ 458276479Sdim qla_host_t *ha = NULL; 459261991Sdim struct ifnet *ifp; 460261991Sdim 461276479Sdim QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 462261991Sdim 463261991Sdim if ((ha = device_get_softc(dev)) == NULL) { 464276479Sdim device_printf(dev, "cannot get softc\n"); 465249259Sdim return (ENOMEM); 466288943Sdim } 467321369Sdim 468251662Sdim ifp = ha->ifp; 469321369Sdim 470321369Sdim (void)QLA_LOCK(ha, __func__, 0); 471321369Sdim qla_stop(ha); 472321369Sdim QLA_UNLOCK(ha, __func__); 473321369Sdim 474321369Sdim qla_release(ha); 475249259Sdim 476249259Sdim QL_DPRINT2(ha, (dev, "%s: exit\n", __func__)); 477249259Sdim 478249259Sdim return (0); 479249259Sdim} 480321369Sdim 481321369Sdim/* 482249259Sdim * SYSCTL Related Callbacks 483249259Sdim */ 484249259Sdimstatic int 485249259Sdimqla_sysctl_get_stats(SYSCTL_HANDLER_ARGS) 486249259Sdim{ 487276479Sdim int err, ret = 0; 488249259Sdim qla_host_t *ha; 489249259Sdim 490276479Sdim err = sysctl_handle_int(oidp, &ret, 0, req); 491276479Sdim 492276479Sdim if (err || !req->newptr) 493276479Sdim return (err); 494276479Sdim 495276479Sdim if (ret == 1) { 496276479Sdim ha = (qla_host_t *)arg1; 497276479Sdim ql_get_stats(ha); 498276479Sdim } 499276479Sdim return (err); 500276479Sdim} 501276479Sdimstatic int 502276479Sdimqla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS) 503276479Sdim{ 504276479Sdim int err, ret = 0; 505276479Sdim qla_host_t *ha; 506276479Sdim 507276479Sdim err = sysctl_handle_int(oidp, &ret, 0, req); 508276479Sdim 509276479Sdim if (err || !req->newptr) 510276479Sdim return (err); 511276479Sdim 512276479Sdim if (ret == 1) { 513276479Sdim ha = (qla_host_t *)arg1; 514276479Sdim ql_hw_link_status(ha); 515276479Sdim } 516276479Sdim return (err); 517276479Sdim} 518276479Sdim 519276479Sdim/* 520276479Sdim * Name: qla_release 521276479Sdim * Function: Releases the resources allocated for the device 522276479Sdim */ 523276479Sdimstatic void 524276479Sdimqla_release(qla_host_t *ha) 525276479Sdim{ 526276479Sdim device_t dev; 527276479Sdim int i; 528249259Sdim 529249259Sdim dev = ha->pci_dev; 530249259Sdim 531276479Sdim if (ha->err_tq) { 532249259Sdim taskqueue_drain(ha->err_tq, &ha->err_task); 533261991Sdim taskqueue_free(ha->err_tq); 534249259Sdim } 535249259Sdim 536321369Sdim if (ha->tx_tq) { 537321369Sdim taskqueue_drain(ha->tx_tq, &ha->tx_task); 538321369Sdim taskqueue_free(ha->tx_tq); 539321369Sdim } 540321369Sdim 541321369Sdim ql_del_cdev(ha); 542321369Sdim 543321369Sdim if (ha->flags.qla_watchdog_active) { 544249259Sdim ha->flags.qla_watchdog_exit = 1; 545249259Sdim 546249259Sdim while (ha->qla_watchdog_exited == 0) 547296417Sdim qla_mdelay(__func__, 1); 548321369Sdim } 549296417Sdim 550296417Sdim if (ha->flags.qla_callout_init) 551296417Sdim callout_stop(&ha->tx_callout); 552296417Sdim 553321369Sdim if (ha->ifp != NULL) 554321369Sdim ether_ifdetach(ha->ifp); 555280031Sdim 556249259Sdim ql_free_dma(ha); 557296417Sdim qla_free_parent_dma_tag(ha); 558249259Sdim 559249259Sdim if (ha->mbx_handle) 560276479Sdim (void)bus_teardown_intr(dev, ha->mbx_irq, ha->mbx_handle); 561249259Sdim 562249259Sdim if (ha->mbx_irq) 563249259Sdim (void) bus_release_resource(dev, SYS_RES_IRQ, ha->mbx_irq_rid, 564249259Sdim ha->mbx_irq); 565249259Sdim 566249259Sdim for (i = 0; i < ha->hw.num_sds_rings; i++) { 567249259Sdim 568249259Sdim if (ha->irq_vec[i].handle) { 569249259Sdim (void)bus_teardown_intr(dev, ha->irq_vec[i].irq, 570249259Sdim ha->irq_vec[i].handle); 571249259Sdim } 572249259Sdim 573249259Sdim if (ha->irq_vec[i].irq) { 574249259Sdim (void)bus_release_resource(dev, SYS_RES_IRQ, 575249259Sdim ha->irq_vec[i].irq_rid, 576249259Sdim ha->irq_vec[i].irq); 577249259Sdim } 578249259Sdim } 579249259Sdim 580249259Sdim if (ha->msix_count) 581249259Sdim pci_release_msi(dev); 582249259Sdim 583249259Sdim if (ha->flags.lock_init) { 584249259Sdim mtx_destroy(&ha->tx_lock); 585249259Sdim mtx_destroy(&ha->hw_lock); 586249259Sdim } 587321369Sdim 588321369Sdim if (ha->pci_reg) 589321369Sdim (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid, 590321369Sdim ha->pci_reg); 591321369Sdim 592321369Sdim if (ha->pci_reg1) 593321369Sdim (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1, 594321369Sdim ha->pci_reg1); 595321369Sdim} 596321369Sdim 597321369Sdim/* 598321369Sdim * DMA Related Functions 599321369Sdim */ 600321369Sdim 601249259Sdimstatic void 602321369Sdimqla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 603321369Sdim{ 604321369Sdim *((bus_addr_t *)arg) = 0; 605321369Sdim 606321369Sdim if (error) { 607321369Sdim printf("%s: bus_dmamap_load failed (%d)\n", __func__, error); 608321369Sdim return; 609321369Sdim } 610321369Sdim 611321369Sdim *((bus_addr_t *)arg) = segs[0].ds_addr; 612321369Sdim 613321369Sdim return; 614321369Sdim} 615321369Sdim 616321369Sdimint 617249259Sdimql_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 618321369Sdim{ 619249259Sdim int ret = 0; 620249259Sdim device_t dev; 621249259Sdim bus_addr_t b_addr; 622321369Sdim 623321369Sdim dev = ha->pci_dev; 624321369Sdim 625249259Sdim QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 626321369Sdim 627249259Sdim ret = bus_dma_tag_create( 628249259Sdim ha->parent_tag,/* parent */ 629249259Sdim dma_buf->alignment, 630321369Sdim ((bus_size_t)(1ULL << 32)),/* boundary */ 631321369Sdim BUS_SPACE_MAXADDR, /* lowaddr */ 632321369Sdim BUS_SPACE_MAXADDR, /* highaddr */ 633249259Sdim NULL, NULL, /* filter, filterarg */ 634321369Sdim dma_buf->size, /* maxsize */ 635249259Sdim 1, /* nsegments */ 636249259Sdim dma_buf->size, /* maxsegsize */ 637249259Sdim 0, /* flags */ 638288943Sdim NULL, NULL, /* lockfunc, lockarg */ 639288943Sdim &dma_buf->dma_tag); 640288943Sdim 641249259Sdim if (ret) { 642288943Sdim device_printf(dev, "%s: could not create dma tag\n", __func__); 643288943Sdim goto ql_alloc_dmabuf_exit; 644288943Sdim } 645249259Sdim ret = bus_dmamem_alloc(dma_buf->dma_tag, 646249259Sdim (void **)&dma_buf->dma_b, 647321369Sdim (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT), 648321369Sdim &dma_buf->dma_map); 649321369Sdim if (ret) { 650321369Sdim bus_dma_tag_destroy(dma_buf->dma_tag); 651321369Sdim device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__); 652321369Sdim goto ql_alloc_dmabuf_exit; 653321369Sdim } 654321369Sdim 655321369Sdim ret = bus_dmamap_load(dma_buf->dma_tag, 656321369Sdim dma_buf->dma_map, 657321369Sdim dma_buf->dma_b, 658276479Sdim dma_buf->size, 659249259Sdim qla_dmamap_callback, 660276479Sdim &b_addr, BUS_DMA_NOWAIT); 661249259Sdim 662249259Sdim if (ret || !b_addr) { 663249259Sdim bus_dma_tag_destroy(dma_buf->dma_tag); 664296417Sdim bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, 665249259Sdim dma_buf->dma_map); 666296417Sdim ret = -1; 667296417Sdim goto ql_alloc_dmabuf_exit; 668296417Sdim } 669249259Sdim 670261991Sdim dma_buf->dma_addr = b_addr; 671261991Sdim 672249259Sdimql_alloc_dmabuf_exit: 673314564Sdim QL_DPRINT2(ha, (dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n", 674249259Sdim __func__, ret, (void *)dma_buf->dma_tag, 675249259Sdim (void *)dma_buf->dma_map, (void *)dma_buf->dma_b, 676249259Sdim dma_buf->size)); 677249259Sdim 678276479Sdim return ret; 679276479Sdim} 680249259Sdim 681321369Sdimvoid 682249259Sdimql_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 683321369Sdim{ 684321369Sdim bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map); 685249259Sdim bus_dma_tag_destroy(dma_buf->dma_tag); 686321369Sdim} 687321369Sdim 688249259Sdimstatic int 689249259Sdimqla_alloc_parent_dma_tag(qla_host_t *ha) 690249259Sdim{ 691249259Sdim int ret; 692261991Sdim device_t dev; 693261991Sdim 694261991Sdim dev = ha->pci_dev; 695261991Sdim 696261991Sdim /* 697251662Sdim * Allocate parent DMA Tag 698249259Sdim */ 699261991Sdim ret = bus_dma_tag_create( 700251662Sdim bus_get_dma_tag(dev), /* parent */ 701249259Sdim 1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */ 702321369Sdim BUS_SPACE_MAXADDR, /* lowaddr */ 703251662Sdim BUS_SPACE_MAXADDR, /* highaddr */ 704249259Sdim NULL, NULL, /* filter, filterarg */ 705261991Sdim BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 706276479Sdim 0, /* nsegments */ 707261991Sdim BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 708261991Sdim 0, /* flags */ 709261991Sdim NULL, NULL, /* lockfunc, lockarg */ 710261991Sdim &ha->parent_tag); 711261991Sdim 712321369Sdim if (ret) { 713261991Sdim device_printf(dev, "%s: could not create parent dma tag\n", 714261991Sdim __func__); 715261991Sdim return (-1); 716321369Sdim } 717276479Sdim 718276479Sdim ha->flags.parent_tag = 1; 719276479Sdim 720321369Sdim return (0); 721261991Sdim} 722261991Sdim 723261991Sdimstatic void 724321369Sdimqla_free_parent_dma_tag(qla_host_t *ha) 725261991Sdim{ 726261991Sdim if (ha->flags.parent_tag) { 727261991Sdim bus_dma_tag_destroy(ha->parent_tag); 728261991Sdim ha->flags.parent_tag = 0; 729321369Sdim } 730276479Sdim} 731276479Sdim 732276479Sdim/* 733321369Sdim * Name: qla_init_ifnet 734261991Sdim * Function: Creates the Network Device Interface and Registers it with the O.S 735261991Sdim */ 736261991Sdim 737321369Sdimstatic void 738261991Sdimqla_init_ifnet(device_t dev, qla_host_t *ha) 739261991Sdim{ 740261991Sdim struct ifnet *ifp; 741261991Sdim 742321369Sdim QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 743276479Sdim 744276479Sdim ifp = ha->ifp = if_alloc(IFT_ETHER); 745276479Sdim 746276479Sdim if (ifp == NULL) 747321369Sdim panic("%s: cannot if_alloc()\n", device_get_nameunit(dev)); 748261991Sdim 749261991Sdim if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 750261991Sdim 751261991Sdim#if __FreeBSD_version >= 1000000 752261991Sdim if_initbaudrate(ifp, IF_Gbps(10)); 753261991Sdim ifp->if_capabilities = IFCAP_LINKSTATE; 754261991Sdim#else 755261991Sdim ifp->if_mtu = ETHERMTU; 756261991Sdim ifp->if_baudrate = (1 * 1000 * 1000 *1000); 757261991Sdim 758261991Sdim#endif /* #if __FreeBSD_version >= 1000000 */ 759261991Sdim 760261991Sdim ifp->if_init = qla_init; 761261991Sdim ifp->if_softc = ha; 762321369Sdim ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 763261991Sdim ifp->if_ioctl = qla_ioctl; 764261991Sdim ifp->if_start = qla_start; 765261991Sdim 766321369Sdim IFQ_SET_MAXLEN(&ifp->if_snd, qla_get_ifq_snd_maxlen(ha)); 767261991Sdim ifp->if_snd.ifq_drv_maxlen = qla_get_ifq_snd_maxlen(ha); 768261991Sdim IFQ_SET_READY(&ifp->if_snd); 769261991Sdim 770261991Sdim ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 771321369Sdim 772276479Sdim ether_ifattach(ifp, qla_get_mac_addr(ha)); 773276479Sdim 774276479Sdim ifp->if_capabilities = IFCAP_HWCSUM | 775276479Sdim IFCAP_TSO4 | 776276479Sdim IFCAP_JUMBO_MTU; 777276479Sdim 778321369Sdim ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 779276479Sdim ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 780276479Sdim 781276479Sdim ifp->if_capenable = ifp->if_capabilities; 782321369Sdim 783276479Sdim ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 784276479Sdim 785276479Sdim ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status); 786321369Sdim 787276479Sdim ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0, 788276479Sdim NULL); 789276479Sdim ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL); 790288943Sdim 791296417Sdim ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO)); 792288943Sdim 793288943Sdim QL_DPRINT2(ha, (dev, "%s: exit\n", __func__)); 794288943Sdim 795288943Sdim return; 796296417Sdim} 797288943Sdim 798276479Sdimstatic void 799288943Sdimqla_init_locked(qla_host_t *ha) 800296417Sdim{ 801288943Sdim struct ifnet *ifp = ha->ifp; 802276479Sdim 803276479Sdim qla_stop(ha); 804288943Sdim 805288943Sdim if (qla_alloc_xmt_bufs(ha) != 0) 806288943Sdim return; 807288943Sdim 808288943Sdim if (qla_alloc_rcv_bufs(ha) != 0) 809276479Sdim return; 810276479Sdim 811276479Sdim bcopy(IF_LLADDR(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN); 812288943Sdim 813288943Sdim ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 814288943Sdim 815288943Sdim ha->flags.stop_rcv = 0; 816276479Sdim if (ql_init_hw_if(ha) == 0) { 817276479Sdim ifp = ha->ifp; 818276479Sdim ifp->if_drv_flags |= IFF_DRV_RUNNING; 819276479Sdim ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 820288943Sdim ha->flags.qla_watchdog_pause = 0; 821276479Sdim ha->hw_vlan_tx_frames = 0; 822276479Sdim ha->tx_tso_frames = 0; 823276479Sdim } 824276479Sdim 825288943Sdim return; 826296417Sdim} 827276479Sdim 828276479Sdimstatic void 829276479Sdimqla_init(void *arg) 830276479Sdim{ 831276479Sdim qla_host_t *ha; 832288943Sdim 833276479Sdim ha = (qla_host_t *)arg; 834276479Sdim 835276479Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 836288943Sdim 837276479Sdim (void)QLA_LOCK(ha, __func__, 0); 838276479Sdim qla_init_locked(ha); 839276479Sdim QLA_UNLOCK(ha, __func__); 840276479Sdim 841276479Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 842288943Sdim} 843276479Sdim 844276479Sdimstatic int 845276479Sdimqla_set_multi(qla_host_t *ha, uint32_t add_multi) 846276479Sdim{ 847276479Sdim uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; 848288943Sdim struct ifmultiaddr *ifma; 849276479Sdim int mcnt = 0; 850276479Sdim struct ifnet *ifp = ha->ifp; 851276479Sdim int ret = 0; 852276479Sdim 853288943Sdim if_maddr_rlock(ifp); 854288943Sdim 855296417Sdim TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 856276479Sdim 857276479Sdim if (ifma->ifma_addr->sa_family != AF_LINK) 858276479Sdim continue; 859276479Sdim 860276479Sdim if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) 861276479Sdim break; 862276479Sdim 863309124Sdim bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 864309124Sdim &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); 865309124Sdim 866309124Sdim mcnt++; 867309124Sdim } 868309124Sdim 869288943Sdim if_maddr_runlock(ifp); 870276479Sdim 871276479Sdim if (QLA_LOCK(ha, __func__, 1) == 0) { 872276479Sdim ret = ql_hw_set_multi(ha, mta, mcnt, add_multi); 873276479Sdim QLA_UNLOCK(ha, __func__); 874276479Sdim } 875288943Sdim 876276479Sdim return (ret); 877276479Sdim} 878276479Sdim 879276479Sdimstatic int 880276479Sdimqla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 881276479Sdim{ 882276479Sdim int ret = 0; 883276479Sdim struct ifreq *ifr = (struct ifreq *)data; 884276479Sdim struct ifaddr *ifa = (struct ifaddr *)data; 885276479Sdim qla_host_t *ha; 886321369Sdim 887261991Sdim ha = (qla_host_t *)ifp->if_softc; 888261991Sdim 889261991Sdim switch (cmd) { 890321369Sdim case SIOCSIFADDR: 891261991Sdim QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n", 892261991Sdim __func__, cmd)); 893288943Sdim 894288943Sdim if (ifa->ifa_addr->sa_family == AF_INET) { 895276479Sdim ifp->if_flags |= IFF_UP; 896261991Sdim if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 897261991Sdim (void)QLA_LOCK(ha, __func__, 0); 898261991Sdim qla_init_locked(ha); 899261991Sdim QLA_UNLOCK(ha, __func__); 900288943Sdim } 901276479Sdim QL_DPRINT4(ha, (ha->pci_dev, 902261991Sdim "%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n", 903261991Sdim __func__, cmd, 904261991Sdim ntohl(IA_SIN(ifa)->sin_addr.s_addr))); 905261991Sdim 906288943Sdim arp_ifinit(ifp, ifa); 907276479Sdim } else { 908288943Sdim ether_ioctl(ifp, cmd, data); 909288943Sdim } 910288943Sdim break; 911288943Sdim 912288943Sdim case SIOCSIFMTU: 913288943Sdim QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n", 914288943Sdim __func__, cmd)); 915288943Sdim 916288943Sdim if (ifr->ifr_mtu > QLA_MAX_MTU) { 917261991Sdim ret = EINVAL; 918261991Sdim } else { 919261991Sdim (void) QLA_LOCK(ha, __func__, 0); 920261991Sdim ifp->if_mtu = ifr->ifr_mtu; 921288943Sdim ha->max_frame_size = 922276479Sdim ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 923288943Sdim if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 924288943Sdim ret = ql_set_max_mtu(ha, ha->max_frame_size, 925288943Sdim ha->hw.rcv_cntxt_id); 926288943Sdim } 927288943Sdim 928288943Sdim if (ifp->if_mtu > ETHERMTU) 929288943Sdim ha->std_replenish = QL_JUMBO_REPLENISH_THRES; 930288943Sdim else 931288943Sdim ha->std_replenish = QL_STD_REPLENISH_THRES; 932288943Sdim 933288943Sdim 934288943Sdim QLA_UNLOCK(ha, __func__); 935288943Sdim 936288943Sdim if (ret) 937288943Sdim ret = EINVAL; 938288943Sdim } 939288943Sdim 940288943Sdim break; 941288943Sdim 942288943Sdim case SIOCSIFFLAGS: 943288943Sdim QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n", 944288943Sdim __func__, cmd)); 945288943Sdim 946261991Sdim (void)QLA_LOCK(ha, __func__, 0); 947261991Sdim 948261991Sdim if (ifp->if_flags & IFF_UP) { 949261991Sdim if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 950288943Sdim if ((ifp->if_flags ^ ha->if_flags) & 951288943Sdim IFF_PROMISC) { 952288943Sdim ret = ql_set_promisc(ha); 953288943Sdim } else if ((ifp->if_flags ^ ha->if_flags) & 954276479Sdim IFF_ALLMULTI) { 955261991Sdim ret = ql_set_allmulti(ha); 956261991Sdim } 957261991Sdim } else { 958261991Sdim qla_init_locked(ha); 959288943Sdim ha->max_frame_size = ifp->if_mtu + 960276479Sdim ETHER_HDR_LEN + ETHER_CRC_LEN; 961261991Sdim ret = ql_set_max_mtu(ha, ha->max_frame_size, 962261991Sdim ha->hw.rcv_cntxt_id); 963261991Sdim } 964261991Sdim } else { 965280031Sdim if (ifp->if_drv_flags & IFF_DRV_RUNNING) 966280031Sdim qla_stop(ha); 967288943Sdim ha->if_flags = ifp->if_flags; 968288943Sdim } 969280031Sdim 970280031Sdim QLA_UNLOCK(ha, __func__); 971280031Sdim break; 972280031Sdim 973280031Sdim case SIOCADDMULTI: 974288943Sdim QL_DPRINT4(ha, (ha->pci_dev, 975276479Sdim "%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd)); 976261991Sdim 977261991Sdim if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 978261991Sdim if (qla_set_multi(ha, 1)) 979261991Sdim ret = EINVAL; 980261991Sdim } 981261991Sdim break; 982261991Sdim 983288943Sdim case SIOCDELMULTI: 984276479Sdim QL_DPRINT4(ha, (ha->pci_dev, 985288943Sdim "%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd)); 986288943Sdim 987288943Sdim if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 988288943Sdim if (qla_set_multi(ha, 0)) 989288943Sdim ret = EINVAL; 990288943Sdim } 991288943Sdim break; 992288943Sdim 993288943Sdim case SIOCSIFMEDIA: 994288943Sdim case SIOCGIFMEDIA: 995288943Sdim QL_DPRINT4(ha, (ha->pci_dev, 996288943Sdim "%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n", 997261991Sdim __func__, cmd)); 998261991Sdim ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd); 999261991Sdim break; 1000261991Sdim 1001261991Sdim case SIOCSIFCAP: 1002261991Sdim { 1003261991Sdim int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 1004288943Sdim 1005288943Sdim QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n", 1006276479Sdim __func__, cmd)); 1007261991Sdim 1008261991Sdim if (mask & IFCAP_HWCSUM) 1009288943Sdim ifp->if_capenable ^= IFCAP_HWCSUM; 1010288943Sdim if (mask & IFCAP_TSO4) 1011261991Sdim ifp->if_capenable ^= IFCAP_TSO4; 1012261991Sdim if (mask & IFCAP_VLAN_HWTAGGING) 1013288943Sdim ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1014288943Sdim if (mask & IFCAP_VLAN_HWTSO) 1015276479Sdim ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1016276479Sdim 1017261991Sdim if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1018261991Sdim qla_init(ha); 1019261991Sdim 1020261991Sdim VLAN_CAPABILITIES(ifp); 1021261991Sdim break; 1022321369Sdim } 1023261991Sdim 1024261991Sdim default: 1025261991Sdim QL_DPRINT4(ha, (ha->pci_dev, "%s: default (0x%lx)\n", 1026261991Sdim __func__, cmd)); 1027261991Sdim ret = ether_ioctl(ifp, cmd, data); 1028261991Sdim break; 1029261991Sdim } 1030261991Sdim 1031276479Sdim return (ret); 1032276479Sdim} 1033261991Sdim 1034261991Sdimstatic int 1035276479Sdimqla_media_change(struct ifnet *ifp) 1036261991Sdim{ 1037261991Sdim qla_host_t *ha; 1038276479Sdim struct ifmedia *ifm; 1039276479Sdim int ret = 0; 1040276479Sdim 1041276479Sdim ha = (qla_host_t *)ifp->if_softc; 1042276479Sdim 1043261991Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1044261991Sdim 1045261991Sdim ifm = &ha->media; 1046261991Sdim 1047321369Sdim if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1048261991Sdim ret = EINVAL; 1049261991Sdim 1050261991Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1051261991Sdim 1052261991Sdim return (ret); 1053261991Sdim} 1054261991Sdim 1055261991Sdimstatic void 1056261991Sdimqla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1057288943Sdim{ 1058261991Sdim qla_host_t *ha; 1059261991Sdim 1060288943Sdim ha = (qla_host_t *)ifp->if_softc; 1061276479Sdim 1062276479Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1063261991Sdim 1064261991Sdim ifmr->ifm_status = IFM_AVALID; 1065261991Sdim ifmr->ifm_active = IFM_ETHER; 1066261991Sdim 1067261991Sdim ql_update_link_state(ha); 1068261991Sdim if (ha->hw.link_up) { 1069261991Sdim ifmr->ifm_status |= IFM_ACTIVE; 1070261991Sdim ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha)); 1071261991Sdim } 1072261991Sdim 1073261991Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: exit (%s)\n", __func__,\ 1074288943Sdim (ha->hw.link_up ? "link_up" : "link_down"))); 1075288943Sdim 1076261991Sdim return; 1077261991Sdim} 1078261991Sdim 1079261991Sdimstatic void 1080261991Sdimqla_start(struct ifnet *ifp) 1081261991Sdim{ 1082261991Sdim struct mbuf *m_head; 1083261991Sdim qla_host_t *ha = (qla_host_t *)ifp->if_softc; 1084261991Sdim 1085261991Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1086261991Sdim 1087261991Sdim if (!mtx_trylock(&ha->tx_lock)) { 1088261991Sdim QL_DPRINT8(ha, (ha->pci_dev, 1089261991Sdim "%s: mtx_trylock(&ha->tx_lock) failed\n", __func__)); 1090261991Sdim return; 1091261991Sdim } 1092261991Sdim 1093261991Sdim if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1094261991Sdim IFF_DRV_RUNNING) { 1095261991Sdim QL_DPRINT8(ha, 1096261991Sdim (ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__)); 1097261991Sdim QLA_TX_UNLOCK(ha); 1098261991Sdim return; 1099261991Sdim } 1100261991Sdim 1101261991Sdim if (!ha->watchdog_ticks) 1102261991Sdim ql_update_link_state(ha); 1103261991Sdim 1104261991Sdim if (!ha->hw.link_up) { 1105261991Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: link down\n", __func__)); 1106261991Sdim QLA_TX_UNLOCK(ha); 1107261991Sdim return; 1108280031Sdim } 1109261991Sdim 1110261991Sdim while (ifp->if_snd.ifq_head != NULL) { 1111276479Sdim IF_DEQUEUE(&ifp->if_snd, m_head); 1112276479Sdim 1113280031Sdim if (m_head == NULL) { 1114276479Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: m_head == NULL\n", 1115276479Sdim __func__)); 1116261991Sdim break; 1117261991Sdim } 1118261991Sdim 1119261991Sdim if (qla_send(ha, &m_head)) { 1120288943Sdim if (m_head == NULL) 1121261991Sdim break; 1122261991Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: PREPEND\n", __func__)); 1123276479Sdim ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1124276479Sdim IF_PREPEND(&ifp->if_snd, m_head); 1125276479Sdim break; 1126276479Sdim } 1127276479Sdim /* Send a copy of the frame to the BPF listener */ 1128288943Sdim ETHER_BPF_MTAP(ifp, m_head); 1129288943Sdim } 1130288943Sdim QLA_TX_UNLOCK(ha); 1131276479Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1132276479Sdim return; 1133276479Sdim} 1134276479Sdim 1135276479Sdimstatic int 1136276479Sdimqla_send(qla_host_t *ha, struct mbuf **m_headp) 1137276479Sdim{ 1138276479Sdim bus_dma_segment_t segs[QLA_MAX_SEGMENTS]; 1139276479Sdim bus_dmamap_t map; 1140276479Sdim int nsegs; 1141276479Sdim int ret = -1; 1142276479Sdim uint32_t tx_idx; 1143276479Sdim struct mbuf *m_head = *m_headp; 1144276479Sdim uint32_t txr_idx = ha->txr_idx; 1145276479Sdim 1146276479Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1147276479Sdim 1148276479Sdim /* check if flowid is set */ 1149276479Sdim if (M_HASHTYPE_GET(m_head) != M_HASHTYPE_NONE) 1150276479Sdim txr_idx = m_head->m_pkthdr.flowid & (ha->hw.num_tx_rings - 1); 1151276479Sdim 1152276479Sdim tx_idx = ha->hw.tx_cntxt[txr_idx].txr_next; 1153276479Sdim map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map; 1154276479Sdim 1155276479Sdim ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs, 1156296417Sdim BUS_DMA_NOWAIT); 1157296417Sdim 1158261991Sdim if (ret == EFBIG) { 1159276479Sdim 1160261991Sdim struct mbuf *m; 1161261991Sdim 1162261991Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: EFBIG [%d]\n", __func__, 1163261991Sdim m_head->m_pkthdr.len)); 1164261991Sdim 1165261991Sdim m = m_defrag(m_head, M_NOWAIT); 1166296417Sdim if (m == NULL) { 1167296417Sdim ha->err_tx_defrag++; 1168296417Sdim m_freem(m_head); 1169296417Sdim *m_headp = NULL; 1170296417Sdim device_printf(ha->pci_dev, 1171296417Sdim "%s: m_defrag() = NULL [%d]\n", 1172296417Sdim __func__, ret); 1173296417Sdim return (ENOBUFS); 1174296417Sdim } 1175296417Sdim m_head = m; 1176296417Sdim *m_headp = m_head; 1177296417Sdim 1178314564Sdim if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, 1179249259Sdim segs, &nsegs, BUS_DMA_NOWAIT))) { 1180249259Sdim 1181249259Sdim ha->err_tx_dmamap_load++; 1182249259Sdim 1183249259Sdim device_printf(ha->pci_dev, 1184249259Sdim "%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n", 1185249259Sdim __func__, ret, m_head->m_pkthdr.len); 1186249259Sdim 1187249259Sdim if (ret != ENOMEM) { 1188249259Sdim m_freem(m_head); 1189249259Sdim *m_headp = NULL; 1190249259Sdim } 1191249259Sdim return (ret); 1192249259Sdim } 1193249259Sdim 1194288943Sdim } else if (ret) { 1195288943Sdim 1196288943Sdim ha->err_tx_dmamap_load++; 1197321369Sdim 1198321369Sdim device_printf(ha->pci_dev, 1199321369Sdim "%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n", 1200288943Sdim __func__, ret, m_head->m_pkthdr.len); 1201251662Sdim 1202249259Sdim if (ret != ENOMEM) { 1203249259Sdim m_freem(m_head); 1204249259Sdim *m_headp = NULL; 1205276479Sdim } 1206249259Sdim return (ret); 1207249259Sdim } 1208249259Sdim 1209296417Sdim QL_ASSERT(ha, (nsegs != 0), ("qla_send: empty packet")); 1210296417Sdim 1211249259Sdim bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE); 1212249259Sdim 1213249259Sdim if (!(ret = ql_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) { 1214296417Sdim 1215249259Sdim ha->tx_ring[txr_idx].count++; 1216296417Sdim ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head; 1217249259Sdim } else { 1218321369Sdim if (ret == EINVAL) { 1219276479Sdim if (m_head) 1220276479Sdim m_freem(m_head); 1221288943Sdim *m_headp = NULL; 1222276479Sdim } 1223276479Sdim } 1224249259Sdim 1225296417Sdim QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1226276479Sdim return (ret); 1227276479Sdim} 1228276479Sdim 1229276479Sdimstatic void 1230261991Sdimqla_stop(qla_host_t *ha) 1231251662Sdim{ 1232251662Sdim struct ifnet *ifp = ha->ifp; 1233261991Sdim device_t dev; 1234251662Sdim 1235249259Sdim dev = ha->pci_dev; 1236251662Sdim 1237261991Sdim ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); 1238251662Sdim 1239249259Sdim ha->flags.qla_watchdog_pause = 1; 1240249259Sdim 1241261991Sdim while (!ha->qla_watchdog_paused) 1242276479Sdim qla_mdelay(__func__, 1); 1243288943Sdim 1244249259Sdim ha->flags.stop_rcv = 1; 1245249259Sdim ql_hw_stop_rcv(ha); 1246249259Sdim 1247261991Sdim ql_del_hw_if(ha); 1248276479Sdim 1249249259Sdim qla_free_xmt_bufs(ha); 1250249259Sdim qla_free_rcv_bufs(ha); 1251261991Sdim 1252261991Sdim return; 1253249259Sdim} 1254249259Sdim 1255249259Sdim/* 1256249259Sdim * Buffer Management Functions for Transmit and Receive Rings 1257276479Sdim */ 1258251662Sdimstatic int 1259249259Sdimqla_alloc_xmt_bufs(qla_host_t *ha) 1260249259Sdim{ 1261288943Sdim int ret = 0; 1262249259Sdim uint32_t i, j; 1263249259Sdim qla_tx_buf_t *txb; 1264249259Sdim 1265261991Sdim if (bus_dma_tag_create(NULL, /* parent */ 1266249259Sdim 1, 0, /* alignment, bounds */ 1267249259Sdim BUS_SPACE_MAXADDR, /* lowaddr */ 1268276479Sdim BUS_SPACE_MAXADDR, /* highaddr */ 1269251662Sdim NULL, NULL, /* filter, filterarg */ 1270251662Sdim QLA_MAX_TSO_FRAME_SIZE, /* maxsize */ 1271249259Sdim QLA_MAX_SEGMENTS, /* nsegments */ 1272288943Sdim PAGE_SIZE, /* maxsegsize */ 1273249259Sdim BUS_DMA_ALLOCNOW, /* flags */ 1274249259Sdim NULL, /* lockfunc */ 1275261991Sdim NULL, /* lockfuncarg */ 1276251662Sdim &ha->tx_tag)) { 1277251662Sdim device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n", 1278251662Sdim __func__); 1279251662Sdim return (ENOMEM); 1280276479Sdim } 1281276479Sdim 1282261991Sdim for (i = 0; i < ha->hw.num_tx_rings; i++) { 1283276479Sdim bzero((void *)ha->tx_ring[i].tx_buf, 1284276479Sdim (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1285276479Sdim } 1286276479Sdim 1287276479Sdim for (j = 0; j < ha->hw.num_tx_rings; j++) { 1288276479Sdim for (i = 0; i < NUM_TX_DESCRIPTORS; i++) { 1289249259Sdim 1290249259Sdim txb = &ha->tx_ring[j].tx_buf[i]; 1291261991Sdim 1292261991Sdim if ((ret = bus_dmamap_create(ha->tx_tag, 1293261991Sdim BUS_DMA_NOWAIT, &txb->map))) { 1294249259Sdim 1295296417Sdim ha->err_tx_dmamap_create++; 1296249259Sdim device_printf(ha->pci_dev, 1297249259Sdim "%s: bus_dmamap_create failed[%d]\n", 1298261991Sdim __func__, ret); 1299261991Sdim 1300261991Sdim qla_free_xmt_bufs(ha); 1301261991Sdim 1302288943Sdim return (ret); 1303261991Sdim } 1304288943Sdim } 1305261991Sdim } 1306261991Sdim 1307276479Sdim return 0; 1308261991Sdim} 1309288943Sdim 1310261991Sdim/* 1311261991Sdim * Release mbuf after it sent on the wire 1312249259Sdim */ 1313249259Sdimstatic void 1314261991Sdimqla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb) 1315261991Sdim{ 1316261991Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1317261991Sdim 1318261991Sdim if (txb->m_head && txb->map) { 1319261991Sdim 1320261991Sdim bus_dmamap_unload(ha->tx_tag, txb->map); 1321261991Sdim 1322261991Sdim m_freem(txb->m_head); 1323261991Sdim txb->m_head = NULL; 1324261991Sdim } 1325261991Sdim 1326261991Sdim if (txb->map) 1327261991Sdim bus_dmamap_destroy(ha->tx_tag, txb->map); 1328261991Sdim 1329261991Sdim QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1330261991Sdim} 1331261991Sdim 1332261991Sdimstatic void 1333261991Sdimqla_free_xmt_bufs(qla_host_t *ha) 1334261991Sdim{ 1335261991Sdim int i, j; 1336261991Sdim 1337261991Sdim for (j = 0; j < ha->hw.num_tx_rings; j++) { 1338276479Sdim for (i = 0; i < NUM_TX_DESCRIPTORS; i++) 1339261991Sdim qla_clear_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]); 1340261991Sdim } 1341261991Sdim 1342249259Sdim if (ha->tx_tag != NULL) { 1343249259Sdim bus_dma_tag_destroy(ha->tx_tag); 1344249259Sdim ha->tx_tag = NULL; 1345249259Sdim } 1346288943Sdim 1347249259Sdim for (i = 0; i < ha->hw.num_tx_rings; i++) { 1348249259Sdim bzero((void *)ha->tx_ring[i].tx_buf, 1349261991Sdim (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1350261991Sdim } 1351261991Sdim return; 1352288943Sdim} 1353261991Sdim 1354261991Sdim 1355249259Sdimstatic int 1356261991Sdimqla_alloc_rcv_std(qla_host_t *ha) 1357261991Sdim{ 1358249259Sdim int i, j, k, r, ret = 0; 1359261991Sdim qla_rx_buf_t *rxb; 1360276479Sdim qla_rx_ring_t *rx_ring; 1361276479Sdim 1362276479Sdim for (r = 0; r < ha->hw.num_rds_rings; r++) { 1363276479Sdim 1364276479Sdim rx_ring = &ha->rx_ring[r]; 1365276479Sdim 1366276479Sdim for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1367276479Sdim 1368276479Sdim rxb = &rx_ring->rx_buf[i]; 1369249259Sdim 1370261991Sdim ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, 1371261991Sdim &rxb->map); 1372261991Sdim 1373261991Sdim if (ret) { 1374261991Sdim device_printf(ha->pci_dev, 1375261991Sdim "%s: dmamap[%d, %d] failed\n", 1376261991Sdim __func__, r, i); 1377261991Sdim 1378261991Sdim for (k = 0; k < r; k++) { 1379249259Sdim for (j = 0; j < NUM_RX_DESCRIPTORS; 1380249259Sdim j++) { 1381261991Sdim rxb = &ha->rx_ring[k].rx_buf[j]; 1382261991Sdim bus_dmamap_destroy(ha->rx_tag, 1383261991Sdim rxb->map); 1384249259Sdim } 1385251662Sdim } 1386249259Sdim 1387249259Sdim for (j = 0; j < i; j++) { 1388276479Sdim bus_dmamap_destroy(ha->rx_tag, 1389276479Sdim rx_ring->rx_buf[j].map); 1390276479Sdim } 1391276479Sdim goto qla_alloc_rcv_std_err; 1392276479Sdim } 1393261991Sdim } 1394249259Sdim } 1395261991Sdim 1396251662Sdim qla_init_hw_rcv_descriptors(ha); 1397251662Sdim 1398251662Sdim 1399261991Sdim for (r = 0; r < ha->hw.num_rds_rings; r++) { 1400261991Sdim 1401261991Sdim rx_ring = &ha->rx_ring[r]; 1402261991Sdim 1403261991Sdim for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1404261991Sdim rxb = &rx_ring->rx_buf[i]; 1405249259Sdim rxb->handle = i; 1406249259Sdim if (!(ret = ql_get_mbuf(ha, rxb, NULL))) { 1407276479Sdim /* 1408276479Sdim * set the physical address in the 1409276479Sdim * corresponding descriptor entry in the 1410276479Sdim * receive ring/queue for the hba 1411276479Sdim */ 1412276479Sdim qla_set_hw_rcv_desc(ha, r, i, rxb->handle, 1413276479Sdim rxb->paddr, 1414276479Sdim (rxb->m_head)->m_pkthdr.len); 1415276479Sdim } else { 1416276479Sdim device_printf(ha->pci_dev, 1417276479Sdim "%s: ql_get_mbuf [%d, %d] failed\n", 1418276479Sdim __func__, r, i); 1419276479Sdim bus_dmamap_destroy(ha->rx_tag, rxb->map); 1420276479Sdim goto qla_alloc_rcv_std_err; 1421261991Sdim } 1422261991Sdim } 1423261991Sdim } 1424261991Sdim return 0; 1425261991Sdim 1426261991Sdimqla_alloc_rcv_std_err: 1427261991Sdim return (-1); 1428249259Sdim} 1429249259Sdim 1430261991Sdimstatic void 1431249259Sdimqla_free_rcv_std(qla_host_t *ha) 1432261991Sdim{ 1433261991Sdim int i, r; 1434261991Sdim qla_rx_buf_t *rxb; 1435261991Sdim 1436261991Sdim for (r = 0; r < ha->hw.num_rds_rings; r++) { 1437261991Sdim for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1438261991Sdim rxb = &ha->rx_ring[r].rx_buf[i]; 1439261991Sdim if (rxb->m_head != NULL) { 1440261991Sdim bus_dmamap_unload(ha->rx_tag, rxb->map); 1441261991Sdim bus_dmamap_destroy(ha->rx_tag, rxb->map); 1442261991Sdim m_freem(rxb->m_head); 1443261991Sdim rxb->m_head = NULL; 1444261991Sdim } 1445251662Sdim } 1446261991Sdim } 1447261991Sdim return; 1448261991Sdim} 1449261991Sdim 1450261991Sdimstatic int 1451251662Sdimqla_alloc_rcv_bufs(qla_host_t *ha) 1452261991Sdim{ 1453261991Sdim int i, ret = 0; 1454261991Sdim 1455261991Sdim if (bus_dma_tag_create(NULL, /* parent */ 1456261991Sdim 1, 0, /* alignment, bounds */ 1457261991Sdim BUS_SPACE_MAXADDR, /* lowaddr */ 1458249259Sdim BUS_SPACE_MAXADDR, /* highaddr */ 1459249259Sdim NULL, NULL, /* filter, filterarg */ 1460276479Sdim MJUM9BYTES, /* maxsize */ 1461276479Sdim 1, /* nsegments */ 1462276479Sdim MJUM9BYTES, /* maxsegsize */ 1463276479Sdim BUS_DMA_ALLOCNOW, /* flags */ 1464276479Sdim NULL, /* lockfunc */ 1465276479Sdim NULL, /* lockfuncarg */ 1466276479Sdim &ha->rx_tag)) { 1467249259Sdim 1468261991Sdim device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n", 1469288943Sdim __func__); 1470288943Sdim 1471288943Sdim return (ENOMEM); 1472288943Sdim } 1473288943Sdim 1474276479Sdim bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS)); 1475261991Sdim 1476288943Sdim for (i = 0; i < ha->hw.num_sds_rings; i++) { 1477288943Sdim ha->hw.sds[i].sdsr_next = 0; 1478261991Sdim ha->hw.sds[i].rxb_free = NULL; 1479261991Sdim ha->hw.sds[i].rx_free = 0; 1480288943Sdim } 1481288943Sdim 1482288943Sdim ret = qla_alloc_rcv_std(ha); 1483288943Sdim 1484288943Sdim return (ret); 1485288943Sdim} 1486288943Sdim 1487288943Sdimstatic void 1488280031Sdimqla_free_rcv_bufs(qla_host_t *ha) 1489288943Sdim{ 1490288943Sdim int i; 1491288943Sdim 1492276479Sdim qla_free_rcv_std(ha); 1493261991Sdim 1494261991Sdim if (ha->rx_tag != NULL) { 1495261991Sdim bus_dma_tag_destroy(ha->rx_tag); 1496261991Sdim ha->rx_tag = NULL; 1497261991Sdim } 1498249259Sdim 1499249259Sdim bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS)); 1500249259Sdim 1501249259Sdim for (i = 0; i < ha->hw.num_sds_rings; i++) { 1502249259Sdim ha->hw.sds[i].sdsr_next = 0; 1503321369Sdim ha->hw.sds[i].rxb_free = NULL; 1504 ha->hw.sds[i].rx_free = 0; 1505 } 1506 1507 return; 1508} 1509 1510int 1511ql_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp) 1512{ 1513 register struct mbuf *mp = nmp; 1514 struct ifnet *ifp; 1515 int ret = 0; 1516 uint32_t offset; 1517 bus_dma_segment_t segs[1]; 1518 int nsegs; 1519 1520 QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1521 1522 ifp = ha->ifp; 1523 1524 if (mp == NULL) { 1525 1526 mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1527 1528 if (mp == NULL) { 1529 ha->err_m_getcl++; 1530 ret = ENOBUFS; 1531 device_printf(ha->pci_dev, 1532 "%s: m_getcl failed\n", __func__); 1533 goto exit_ql_get_mbuf; 1534 } 1535 mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1536 } else { 1537 mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1538 mp->m_data = mp->m_ext.ext_buf; 1539 mp->m_next = NULL; 1540 } 1541 1542 offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL); 1543 if (offset) { 1544 offset = 8 - offset; 1545 m_adj(mp, offset); 1546 } 1547 1548 /* 1549 * Using memory from the mbuf cluster pool, invoke the bus_dma 1550 * machinery to arrange the memory mapping. 1551 */ 1552 ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map, 1553 mp, segs, &nsegs, BUS_DMA_NOWAIT); 1554 rxb->paddr = segs[0].ds_addr; 1555 1556 if (ret || !rxb->paddr || (nsegs != 1)) { 1557 m_free(mp); 1558 rxb->m_head = NULL; 1559 device_printf(ha->pci_dev, 1560 "%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n", 1561 __func__, ret, (long long unsigned int)rxb->paddr, 1562 nsegs); 1563 ret = -1; 1564 goto exit_ql_get_mbuf; 1565 } 1566 rxb->m_head = mp; 1567 bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD); 1568 1569exit_ql_get_mbuf: 1570 QL_DPRINT2(ha, (ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret)); 1571 return (ret); 1572} 1573 1574static void 1575qla_tx_done(void *context, int pending) 1576{ 1577 qla_host_t *ha = context; 1578 struct ifnet *ifp; 1579 1580 ifp = ha->ifp; 1581 1582 if (!ifp) 1583 return; 1584 1585 if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1586 QL_DPRINT8(ha, (ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__)); 1587 return; 1588 } 1589 ql_hw_tx_done(ha); 1590 1591 qla_start(ha->ifp); 1592} 1593 1594static void 1595qla_get_peer(qla_host_t *ha) 1596{ 1597 device_t *peers; 1598 int count, i, slot; 1599 int my_slot = pci_get_slot(ha->pci_dev); 1600 1601 if (device_get_children(device_get_parent(ha->pci_dev), &peers, &count)) 1602 return; 1603 1604 for (i = 0; i < count; i++) { 1605 slot = pci_get_slot(peers[i]); 1606 1607 if ((slot >= 0) && (slot == my_slot) && 1608 (pci_get_device(peers[i]) == 1609 pci_get_device(ha->pci_dev))) { 1610 if (ha->pci_dev != peers[i]) 1611 ha->peer_dev = peers[i]; 1612 } 1613 } 1614} 1615 1616static void 1617qla_send_msg_to_peer(qla_host_t *ha, uint32_t msg_to_peer) 1618{ 1619 qla_host_t *ha_peer; 1620 1621 if (ha->peer_dev) { 1622 if ((ha_peer = device_get_softc(ha->peer_dev)) != NULL) { 1623 1624 ha_peer->msg_from_peer = msg_to_peer; 1625 } 1626 } 1627} 1628 1629static void 1630qla_error_recovery(void *context, int pending) 1631{ 1632 qla_host_t *ha = context; 1633 uint32_t msecs_100 = 100; 1634 struct ifnet *ifp = ha->ifp; 1635 1636 (void)QLA_LOCK(ha, __func__, 0); 1637 1638 ha->flags.stop_rcv = 1; 1639 1640 ql_hw_stop_rcv(ha); 1641 1642 ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); 1643 1644 QLA_UNLOCK(ha, __func__); 1645 1646 if ((ha->pci_func & 0x1) == 0) { 1647 1648 if (!ha->msg_from_peer) { 1649 qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET); 1650 1651 while ((ha->msg_from_peer != QL_PEER_MSG_ACK) && 1652 msecs_100--) 1653 qla_mdelay(__func__, 100); 1654 } 1655 1656 ha->msg_from_peer = 0; 1657 1658 ql_minidump(ha); 1659 1660 (void) ql_init_hw(ha); 1661 qla_free_xmt_bufs(ha); 1662 qla_free_rcv_bufs(ha); 1663 1664 qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK); 1665 1666 } else { 1667 if (ha->msg_from_peer == QL_PEER_MSG_RESET) { 1668 1669 ha->msg_from_peer = 0; 1670 1671 qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK); 1672 } else { 1673 qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET); 1674 } 1675 1676 while ((ha->msg_from_peer != QL_PEER_MSG_ACK) && msecs_100--) 1677 qla_mdelay(__func__, 100); 1678 ha->msg_from_peer = 0; 1679 1680 (void) ql_init_hw(ha); 1681 qla_free_xmt_bufs(ha); 1682 qla_free_rcv_bufs(ha); 1683 } 1684 (void)QLA_LOCK(ha, __func__, 0); 1685 1686 if (qla_alloc_xmt_bufs(ha) != 0) { 1687 QLA_UNLOCK(ha, __func__); 1688 return; 1689 } 1690 1691 if (qla_alloc_rcv_bufs(ha) != 0) { 1692 QLA_UNLOCK(ha, __func__); 1693 return; 1694 } 1695 1696 ha->flags.stop_rcv = 0; 1697 if (ql_init_hw_if(ha) == 0) { 1698 ifp = ha->ifp; 1699 ifp->if_drv_flags |= IFF_DRV_RUNNING; 1700 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1701 ha->flags.qla_watchdog_pause = 0; 1702 } 1703 1704 QLA_UNLOCK(ha, __func__); 1705} 1706 1707