1227064Sbz/* 2250340Sdavidcs * Copyright (c) 2011-2013 Qlogic Corporation 3227064Sbz * All rights reserved. 4227064Sbz * 5227064Sbz * Redistribution and use in source and binary forms, with or without 6227064Sbz * modification, are permitted provided that the following conditions 7227064Sbz * are met: 8227064Sbz * 9227064Sbz * 1. Redistributions of source code must retain the above copyright 10227064Sbz * notice, this list of conditions and the following disclaimer. 11227064Sbz * 2. Redistributions in binary form must reproduce the above copyright 12227064Sbz * notice, this list of conditions and the following disclaimer in the 13227064Sbz * documentation and/or other materials provided with the distribution. 14227064Sbz * 15227064Sbz * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16227064Sbz * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17227064Sbz * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18227064Sbz * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19227064Sbz * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20227064Sbz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21227064Sbz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22227064Sbz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23227064Sbz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24227064Sbz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25227064Sbz * POSSIBILITY OF SUCH DAMAGE. 26227064Sbz */ 27227064Sbz 28227064Sbz/* 29227064Sbz * File: qla_os.c 30227064Sbz * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 31227064Sbz */ 32227064Sbz 33227064Sbz#include <sys/cdefs.h> 34227064Sbz__FBSDID("$FreeBSD$"); 35227064Sbz 36227064Sbz#include "qla_os.h" 37227064Sbz#include "qla_reg.h" 38227064Sbz#include "qla_hw.h" 39227064Sbz#include "qla_def.h" 40227064Sbz#include "qla_inline.h" 41227064Sbz#include "qla_ver.h" 42227064Sbz#include "qla_glbl.h" 43227064Sbz#include "qla_dbg.h" 44227064Sbz 45227064Sbz/* 46227064Sbz * Some PCI Configuration Space Related Defines 47227064Sbz */ 48227064Sbz 49227064Sbz#ifndef PCI_VENDOR_QLOGIC 50227064Sbz#define PCI_VENDOR_QLOGIC 0x1077 51227064Sbz#endif 52227064Sbz 53227064Sbz#ifndef PCI_PRODUCT_QLOGIC_ISP8020 54227064Sbz#define PCI_PRODUCT_QLOGIC_ISP8020 0x8020 55227064Sbz#endif 56227064Sbz 57227064Sbz#define PCI_QLOGIC_ISP8020 \ 58227064Sbz ((PCI_PRODUCT_QLOGIC_ISP8020 << 16) | PCI_VENDOR_QLOGIC) 59227064Sbz 60227064Sbz/* 61227064Sbz * static functions 62227064Sbz */ 63227064Sbzstatic int qla_alloc_parent_dma_tag(qla_host_t *ha); 64227064Sbzstatic void qla_free_parent_dma_tag(qla_host_t *ha); 65227064Sbzstatic int qla_alloc_xmt_bufs(qla_host_t *ha); 66227064Sbzstatic void qla_free_xmt_bufs(qla_host_t *ha); 67227064Sbzstatic int qla_alloc_rcv_bufs(qla_host_t *ha); 68227064Sbzstatic void qla_free_rcv_bufs(qla_host_t *ha); 69227064Sbz 70227064Sbzstatic void qla_init_ifnet(device_t dev, qla_host_t *ha); 71227064Sbzstatic int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS); 72227064Sbzstatic void qla_release(qla_host_t *ha); 73227064Sbzstatic void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 74227064Sbz int error); 75227064Sbzstatic void qla_stop(qla_host_t *ha); 76227064Sbzstatic int qla_send(qla_host_t *ha, struct mbuf **m_headp); 77227064Sbzstatic void qla_tx_done(void *context, int pending); 78227064Sbz 79227064Sbz/* 80227064Sbz * Hooks to the Operating Systems 81227064Sbz */ 82227064Sbzstatic int qla_pci_probe (device_t); 83227064Sbzstatic int qla_pci_attach (device_t); 84227064Sbzstatic int qla_pci_detach (device_t); 85227064Sbz 86227064Sbzstatic void qla_init(void *arg); 87227064Sbzstatic int qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 88227064Sbzstatic int qla_media_change(struct ifnet *ifp); 89227064Sbzstatic void qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr); 90227064Sbz 91227064Sbzstatic device_method_t qla_pci_methods[] = { 92227064Sbz /* Device interface */ 93227064Sbz DEVMETHOD(device_probe, qla_pci_probe), 94227064Sbz DEVMETHOD(device_attach, qla_pci_attach), 95227064Sbz DEVMETHOD(device_detach, qla_pci_detach), 96227064Sbz { 0, 0 } 97227064Sbz}; 98227064Sbz 99227064Sbzstatic driver_t qla_pci_driver = { 100227064Sbz "ql", qla_pci_methods, sizeof (qla_host_t), 101227064Sbz}; 102227064Sbz 103227064Sbzstatic devclass_t qla80xx_devclass; 104227064Sbz 105227064SbzDRIVER_MODULE(qla80xx, pci, qla_pci_driver, qla80xx_devclass, 0, 0); 106227064Sbz 107227064SbzMODULE_DEPEND(qla80xx, pci, 1, 1, 1); 108227064SbzMODULE_DEPEND(qla80xx, ether, 1, 1, 1); 109227064Sbz 110227064SbzMALLOC_DEFINE(M_QLA8XXXBUF, "qla80xxbuf", "Buffers for qla80xx driver"); 111227064Sbz 112227064Sbzuint32_t std_replenish = 8; 113227064Sbzuint32_t jumbo_replenish = 2; 114227064Sbzuint32_t rcv_pkt_thres = 128; 115227064Sbzuint32_t rcv_pkt_thres_d = 32; 116227064Sbzuint32_t snd_pkt_thres = 16; 117227064Sbzuint32_t free_pkt_thres = (NUM_TX_DESCRIPTORS / 2); 118227064Sbz 119227064Sbzstatic char dev_str[64]; 120227064Sbz 121227064Sbz/* 122227064Sbz * Name: qla_pci_probe 123227064Sbz * Function: Validate the PCI device to be a QLA80XX device 124227064Sbz */ 125227064Sbzstatic int 126227064Sbzqla_pci_probe(device_t dev) 127227064Sbz{ 128227064Sbz switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 129227064Sbz case PCI_QLOGIC_ISP8020: 130227064Sbz snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d", 131227064Sbz "Qlogic ISP 80xx PCI CNA Adapter-Ethernet Function", 132227064Sbz QLA_VERSION_MAJOR, QLA_VERSION_MINOR, 133227064Sbz QLA_VERSION_BUILD); 134227064Sbz device_set_desc(dev, dev_str); 135227064Sbz break; 136227064Sbz default: 137227064Sbz return (ENXIO); 138227064Sbz } 139227064Sbz 140227064Sbz if (bootverbose) 141227064Sbz printf("%s: %s\n ", __func__, dev_str); 142227064Sbz 143227064Sbz return (BUS_PROBE_DEFAULT); 144227064Sbz} 145227064Sbz 146227064Sbzstatic void 147227064Sbzqla_add_sysctls(qla_host_t *ha) 148227064Sbz{ 149227064Sbz device_t dev = ha->pci_dev; 150227064Sbz 151227064Sbz SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 152227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 153227064Sbz OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RD, 154227064Sbz (void *)ha, 0, 155227064Sbz qla_sysctl_get_stats, "I", "Statistics"); 156227064Sbz 157250340Sdavidcs SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), 158250340Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 159250340Sdavidcs OID_AUTO, "fw_version", CTLFLAG_RD, 160273736Shselasky ha->fw_ver_str, 0, "firmware version"); 161250340Sdavidcs 162227064Sbz dbg_level = 0; 163227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 164227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 165227064Sbz OID_AUTO, "debug", CTLFLAG_RW, 166227064Sbz &dbg_level, dbg_level, "Debug Level"); 167227064Sbz 168227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 169227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 170227064Sbz OID_AUTO, "std_replenish", CTLFLAG_RW, 171227064Sbz &std_replenish, std_replenish, 172227064Sbz "Threshold for Replenishing Standard Frames"); 173227064Sbz 174227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 175227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 176227064Sbz OID_AUTO, "jumbo_replenish", CTLFLAG_RW, 177227064Sbz &jumbo_replenish, jumbo_replenish, 178227064Sbz "Threshold for Replenishing Jumbo Frames"); 179227064Sbz 180227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 181227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 182227064Sbz OID_AUTO, "rcv_pkt_thres", CTLFLAG_RW, 183227064Sbz &rcv_pkt_thres, rcv_pkt_thres, 184227064Sbz "Threshold for # of rcv pkts to trigger indication isr"); 185227064Sbz 186227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 187227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 188227064Sbz OID_AUTO, "rcv_pkt_thres_d", CTLFLAG_RW, 189227064Sbz &rcv_pkt_thres_d, rcv_pkt_thres_d, 190227064Sbz "Threshold for # of rcv pkts to trigger indication defered"); 191227064Sbz 192227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 193227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 194227064Sbz OID_AUTO, "snd_pkt_thres", CTLFLAG_RW, 195227064Sbz &snd_pkt_thres, snd_pkt_thres, 196227064Sbz "Threshold for # of snd packets"); 197227064Sbz 198227064Sbz SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 199227064Sbz SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 200227064Sbz OID_AUTO, "free_pkt_thres", CTLFLAG_RW, 201227064Sbz &free_pkt_thres, free_pkt_thres, 202227064Sbz "Threshold for # of packets to free at a time"); 203227064Sbz 204227064Sbz return; 205227064Sbz} 206227064Sbz 207227064Sbzstatic void 208227064Sbzqla_watchdog(void *arg) 209227064Sbz{ 210227064Sbz qla_host_t *ha = arg; 211227064Sbz qla_hw_t *hw; 212227064Sbz struct ifnet *ifp; 213227064Sbz 214227064Sbz hw = &ha->hw; 215227064Sbz ifp = ha->ifp; 216227064Sbz 217227064Sbz if (ha->flags.qla_watchdog_exit) 218227064Sbz return; 219227064Sbz 220227064Sbz if (!ha->flags.qla_watchdog_pause) { 221227064Sbz if (qla_le32_to_host(*(hw->tx_cons)) != hw->txr_comp) { 222227064Sbz taskqueue_enqueue(ha->tx_tq, &ha->tx_task); 223227064Sbz } else if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) { 224227064Sbz taskqueue_enqueue(ha->tx_tq, &ha->tx_task); 225227064Sbz } 226227064Sbz } 227227064Sbz ha->watchdog_ticks = ha->watchdog_ticks++ % 1000; 228227064Sbz callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 229227064Sbz qla_watchdog, ha); 230227064Sbz} 231227064Sbz 232227064Sbz/* 233227064Sbz * Name: qla_pci_attach 234227064Sbz * Function: attaches the device to the operating system 235227064Sbz */ 236227064Sbzstatic int 237227064Sbzqla_pci_attach(device_t dev) 238227064Sbz{ 239227064Sbz qla_host_t *ha = NULL; 240227064Sbz uint32_t rsrc_len, i; 241227064Sbz 242227064Sbz QL_DPRINT2((dev, "%s: enter\n", __func__)); 243227064Sbz 244227064Sbz if ((ha = device_get_softc(dev)) == NULL) { 245227064Sbz device_printf(dev, "cannot get softc\n"); 246227064Sbz return (ENOMEM); 247227064Sbz } 248227064Sbz 249227064Sbz memset(ha, 0, sizeof (qla_host_t)); 250227064Sbz 251227064Sbz if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8020) { 252227064Sbz device_printf(dev, "device is not ISP8020\n"); 253227064Sbz return (ENXIO); 254227064Sbz } 255227064Sbz 256227064Sbz ha->pci_func = pci_get_function(dev); 257227064Sbz 258227064Sbz ha->pci_dev = dev; 259227064Sbz 260227064Sbz pci_enable_busmaster(dev); 261227064Sbz 262227064Sbz ha->reg_rid = PCIR_BAR(0); 263227064Sbz ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid, 264227064Sbz RF_ACTIVE); 265227064Sbz 266227064Sbz if (ha->pci_reg == NULL) { 267227064Sbz device_printf(dev, "unable to map any ports\n"); 268227064Sbz goto qla_pci_attach_err; 269227064Sbz } 270227064Sbz 271227064Sbz rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY, 272227064Sbz ha->reg_rid); 273227064Sbz 274227064Sbz mtx_init(&ha->hw_lock, "qla80xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF); 275227064Sbz mtx_init(&ha->tx_lock, "qla80xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF); 276227064Sbz mtx_init(&ha->rx_lock, "qla80xx_rx_lock", MTX_NETWORK_LOCK, MTX_DEF); 277227064Sbz mtx_init(&ha->rxj_lock, "qla80xx_rxj_lock", MTX_NETWORK_LOCK, MTX_DEF); 278227064Sbz ha->flags.lock_init = 1; 279227064Sbz 280227064Sbz ha->msix_count = pci_msix_count(dev); 281227064Sbz 282227064Sbz if (ha->msix_count < qla_get_msix_count(ha)) { 283227064Sbz device_printf(dev, "%s: msix_count[%d] not enough\n", __func__, 284227064Sbz ha->msix_count); 285227064Sbz goto qla_pci_attach_err; 286227064Sbz } 287227064Sbz 288227064Sbz QL_DPRINT2((dev, "%s: ha %p irq %p pci_func 0x%x rsrc_count 0x%08x" 289227064Sbz " msix_count 0x%x pci_reg %p\n", __func__, ha, 290227064Sbz ha->irq, ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg)); 291227064Sbz 292227064Sbz ha->msix_count = qla_get_msix_count(ha); 293227064Sbz 294227064Sbz if (pci_alloc_msix(dev, &ha->msix_count)) { 295227064Sbz device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__, 296227064Sbz ha->msix_count); 297227064Sbz ha->msix_count = 0; 298227064Sbz goto qla_pci_attach_err; 299227064Sbz } 300227064Sbz 301227064Sbz TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha); 302227064Sbz ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT, 303227064Sbz taskqueue_thread_enqueue, &ha->tx_tq); 304227064Sbz taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq", 305227064Sbz device_get_nameunit(ha->pci_dev)); 306227064Sbz 307227064Sbz for (i = 0; i < ha->msix_count; i++) { 308227064Sbz ha->irq_vec[i].irq_rid = i+1; 309227064Sbz ha->irq_vec[i].ha = ha; 310227064Sbz 311227064Sbz ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 312227064Sbz &ha->irq_vec[i].irq_rid, 313227064Sbz (RF_ACTIVE | RF_SHAREABLE)); 314227064Sbz 315227064Sbz if (ha->irq_vec[i].irq == NULL) { 316227064Sbz device_printf(dev, "could not allocate interrupt\n"); 317227064Sbz goto qla_pci_attach_err; 318227064Sbz } 319227064Sbz 320227064Sbz if (bus_setup_intr(dev, ha->irq_vec[i].irq, 321227064Sbz (INTR_TYPE_NET | INTR_MPSAFE), 322227064Sbz NULL, qla_isr, &ha->irq_vec[i], 323227064Sbz &ha->irq_vec[i].handle)) { 324227064Sbz device_printf(dev, "could not setup interrupt\n"); 325227064Sbz goto qla_pci_attach_err; 326227064Sbz } 327227064Sbz 328227064Sbz TASK_INIT(&ha->irq_vec[i].rcv_task, 0, qla_rcv,\ 329227064Sbz &ha->irq_vec[i]); 330227064Sbz 331227064Sbz ha->irq_vec[i].rcv_tq = taskqueue_create_fast("qla_rcvq", 332227064Sbz M_NOWAIT, taskqueue_thread_enqueue, 333227064Sbz &ha->irq_vec[i].rcv_tq); 334227064Sbz 335227064Sbz taskqueue_start_threads(&ha->irq_vec[i].rcv_tq, 1, PI_NET, 336227064Sbz "%s rcvq", 337227064Sbz device_get_nameunit(ha->pci_dev)); 338227064Sbz } 339227064Sbz 340227064Sbz qla_add_sysctls(ha); 341227064Sbz 342227064Sbz /* add hardware specific sysctls */ 343227064Sbz qla_hw_add_sysctls(ha); 344227064Sbz 345227064Sbz /* initialize hardware */ 346227064Sbz if (qla_init_hw(ha)) { 347227064Sbz device_printf(dev, "%s: qla_init_hw failed\n", __func__); 348227064Sbz goto qla_pci_attach_err; 349227064Sbz } 350227064Sbz 351227064Sbz device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__, 352227064Sbz ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 353227064Sbz ha->fw_ver_build); 354227064Sbz 355250340Sdavidcs snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d", 356250340Sdavidcs ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 357250340Sdavidcs ha->fw_ver_build); 358250340Sdavidcs 359227064Sbz //qla_get_hw_caps(ha); 360227064Sbz qla_read_mac_addr(ha); 361227064Sbz 362227064Sbz /* allocate parent dma tag */ 363227064Sbz if (qla_alloc_parent_dma_tag(ha)) { 364227064Sbz device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n", 365227064Sbz __func__); 366227064Sbz goto qla_pci_attach_err; 367227064Sbz } 368227064Sbz 369227064Sbz /* alloc all dma buffers */ 370227064Sbz if (qla_alloc_dma(ha)) { 371227064Sbz device_printf(dev, "%s: qla_alloc_dma failed\n", __func__); 372227064Sbz goto qla_pci_attach_err; 373227064Sbz } 374227064Sbz 375227064Sbz /* create the o.s ethernet interface */ 376227064Sbz qla_init_ifnet(dev, ha); 377227064Sbz 378227064Sbz ha->flags.qla_watchdog_active = 1; 379227064Sbz ha->flags.qla_watchdog_pause = 1; 380227064Sbz 381227064Sbz callout_init(&ha->tx_callout, TRUE); 382227064Sbz 383227064Sbz /* create ioctl device interface */ 384227064Sbz if (qla_make_cdev(ha)) { 385227064Sbz device_printf(dev, "%s: qla_make_cdev failed\n", __func__); 386227064Sbz goto qla_pci_attach_err; 387227064Sbz } 388227064Sbz 389227064Sbz callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 390227064Sbz qla_watchdog, ha); 391227064Sbz 392227064Sbz QL_DPRINT2((dev, "%s: exit 0\n", __func__)); 393227064Sbz return (0); 394227064Sbz 395227064Sbzqla_pci_attach_err: 396227064Sbz 397227064Sbz qla_release(ha); 398227064Sbz 399227064Sbz QL_DPRINT2((dev, "%s: exit ENXIO\n", __func__)); 400227064Sbz return (ENXIO); 401227064Sbz} 402227064Sbz 403227064Sbz/* 404227064Sbz * Name: qla_pci_detach 405227064Sbz * Function: Unhooks the device from the operating system 406227064Sbz */ 407227064Sbzstatic int 408227064Sbzqla_pci_detach(device_t dev) 409227064Sbz{ 410227064Sbz qla_host_t *ha = NULL; 411227064Sbz struct ifnet *ifp; 412227064Sbz int i; 413227064Sbz 414227064Sbz QL_DPRINT2((dev, "%s: enter\n", __func__)); 415227064Sbz 416227064Sbz if ((ha = device_get_softc(dev)) == NULL) { 417227064Sbz device_printf(dev, "cannot get softc\n"); 418227064Sbz return (ENOMEM); 419227064Sbz } 420227064Sbz 421227064Sbz ifp = ha->ifp; 422227064Sbz 423227064Sbz QLA_LOCK(ha, __func__); 424227064Sbz qla_stop(ha); 425227064Sbz QLA_UNLOCK(ha, __func__); 426227064Sbz 427227064Sbz if (ha->tx_tq) { 428227064Sbz taskqueue_drain(ha->tx_tq, &ha->tx_task); 429227064Sbz taskqueue_free(ha->tx_tq); 430227064Sbz } 431227064Sbz 432227064Sbz for (i = 0; i < ha->msix_count; i++) { 433227064Sbz taskqueue_drain(ha->irq_vec[i].rcv_tq, 434227064Sbz &ha->irq_vec[i].rcv_task); 435227064Sbz taskqueue_free(ha->irq_vec[i].rcv_tq); 436227064Sbz } 437227064Sbz 438227064Sbz qla_release(ha); 439227064Sbz 440227064Sbz QL_DPRINT2((dev, "%s: exit\n", __func__)); 441227064Sbz 442227064Sbz return (0); 443227064Sbz} 444227064Sbz 445227064Sbz/* 446227064Sbz * SYSCTL Related Callbacks 447227064Sbz */ 448227064Sbzstatic int 449227064Sbzqla_sysctl_get_stats(SYSCTL_HANDLER_ARGS) 450227064Sbz{ 451227064Sbz int err, ret = 0; 452227064Sbz qla_host_t *ha; 453227064Sbz 454227064Sbz err = sysctl_handle_int(oidp, &ret, 0, req); 455227064Sbz 456227064Sbz if (err) 457227064Sbz return (err); 458227064Sbz 459227064Sbz ha = (qla_host_t *)arg1; 460227064Sbz //qla_get_stats(ha); 461227064Sbz QL_DPRINT2((ha->pci_dev, "%s: called ret %d\n", __func__, ret)); 462227064Sbz return (err); 463227064Sbz} 464227064Sbz 465227064Sbz 466227064Sbz/* 467227064Sbz * Name: qla_release 468227064Sbz * Function: Releases the resources allocated for the device 469227064Sbz */ 470227064Sbzstatic void 471227064Sbzqla_release(qla_host_t *ha) 472227064Sbz{ 473227064Sbz device_t dev; 474227064Sbz int i; 475227064Sbz 476227064Sbz dev = ha->pci_dev; 477227064Sbz 478227064Sbz qla_del_cdev(ha); 479227064Sbz 480227064Sbz if (ha->flags.qla_watchdog_active) 481227064Sbz ha->flags.qla_watchdog_exit = 1; 482227064Sbz 483227064Sbz callout_stop(&ha->tx_callout); 484227064Sbz qla_mdelay(__func__, 100); 485227064Sbz 486227064Sbz if (ha->ifp != NULL) 487227064Sbz ether_ifdetach(ha->ifp); 488227064Sbz 489227064Sbz qla_free_dma(ha); 490227064Sbz qla_free_parent_dma_tag(ha); 491227064Sbz 492227064Sbz for (i = 0; i < ha->msix_count; i++) { 493227064Sbz if (ha->irq_vec[i].handle) 494227064Sbz (void)bus_teardown_intr(dev, ha->irq_vec[i].irq, 495227064Sbz ha->irq_vec[i].handle); 496227064Sbz if (ha->irq_vec[i].irq) 497227064Sbz (void) bus_release_resource(dev, SYS_RES_IRQ, 498227064Sbz ha->irq_vec[i].irq_rid, 499227064Sbz ha->irq_vec[i].irq); 500227064Sbz } 501227064Sbz if (ha->msix_count) 502227064Sbz pci_release_msi(dev); 503227064Sbz 504227064Sbz if (ha->flags.lock_init) { 505227064Sbz mtx_destroy(&ha->tx_lock); 506227064Sbz mtx_destroy(&ha->rx_lock); 507227064Sbz mtx_destroy(&ha->rxj_lock); 508227064Sbz mtx_destroy(&ha->hw_lock); 509227064Sbz } 510227064Sbz 511227064Sbz if (ha->pci_reg) 512227064Sbz (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid, 513227064Sbz ha->pci_reg); 514227064Sbz} 515227064Sbz 516227064Sbz/* 517227064Sbz * DMA Related Functions 518227064Sbz */ 519227064Sbz 520227064Sbzstatic void 521227064Sbzqla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 522227064Sbz{ 523227064Sbz *((bus_addr_t *)arg) = 0; 524227064Sbz 525227064Sbz if (error) { 526227064Sbz printf("%s: bus_dmamap_load failed (%d)\n", __func__, error); 527227064Sbz return; 528227064Sbz } 529227064Sbz 530227064Sbz QL_ASSERT((nsegs == 1), ("%s: %d segments returned!", __func__, nsegs)); 531227064Sbz 532227064Sbz *((bus_addr_t *)arg) = segs[0].ds_addr; 533227064Sbz 534227064Sbz return; 535227064Sbz} 536227064Sbz 537227064Sbzint 538227064Sbzqla_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 539227064Sbz{ 540227064Sbz int ret = 0; 541227064Sbz device_t dev; 542227064Sbz bus_addr_t b_addr; 543227064Sbz 544227064Sbz dev = ha->pci_dev; 545227064Sbz 546227064Sbz QL_DPRINT2((dev, "%s: enter\n", __func__)); 547227064Sbz 548227064Sbz ret = bus_dma_tag_create( 549227064Sbz ha->parent_tag,/* parent */ 550227064Sbz dma_buf->alignment, 551227064Sbz ((bus_size_t)(1ULL << 32)),/* boundary */ 552227064Sbz BUS_SPACE_MAXADDR, /* lowaddr */ 553227064Sbz BUS_SPACE_MAXADDR, /* highaddr */ 554227064Sbz NULL, NULL, /* filter, filterarg */ 555227064Sbz dma_buf->size, /* maxsize */ 556227064Sbz 1, /* nsegments */ 557227064Sbz dma_buf->size, /* maxsegsize */ 558227064Sbz 0, /* flags */ 559227064Sbz NULL, NULL, /* lockfunc, lockarg */ 560227064Sbz &dma_buf->dma_tag); 561227064Sbz 562227064Sbz if (ret) { 563227064Sbz device_printf(dev, "%s: could not create dma tag\n", __func__); 564227064Sbz goto qla_alloc_dmabuf_exit; 565227064Sbz } 566227064Sbz ret = bus_dmamem_alloc(dma_buf->dma_tag, 567227064Sbz (void **)&dma_buf->dma_b, 568227064Sbz (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT), 569227064Sbz &dma_buf->dma_map); 570227064Sbz if (ret) { 571227064Sbz bus_dma_tag_destroy(dma_buf->dma_tag); 572227064Sbz device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__); 573227064Sbz goto qla_alloc_dmabuf_exit; 574227064Sbz } 575227064Sbz 576227064Sbz ret = bus_dmamap_load(dma_buf->dma_tag, 577227064Sbz dma_buf->dma_map, 578227064Sbz dma_buf->dma_b, 579227064Sbz dma_buf->size, 580227064Sbz qla_dmamap_callback, 581227064Sbz &b_addr, BUS_DMA_NOWAIT); 582227064Sbz 583227064Sbz if (ret || !b_addr) { 584227064Sbz bus_dma_tag_destroy(dma_buf->dma_tag); 585227064Sbz bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, 586227064Sbz dma_buf->dma_map); 587227064Sbz ret = -1; 588227064Sbz goto qla_alloc_dmabuf_exit; 589227064Sbz } 590227064Sbz 591227064Sbz dma_buf->dma_addr = b_addr; 592227064Sbz 593227064Sbzqla_alloc_dmabuf_exit: 594227064Sbz QL_DPRINT2((dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n", 595227064Sbz __func__, ret, (void *)dma_buf->dma_tag, 596227064Sbz (void *)dma_buf->dma_map, (void *)dma_buf->dma_b, 597227064Sbz dma_buf->size)); 598227064Sbz 599227064Sbz return ret; 600227064Sbz} 601227064Sbz 602227064Sbzvoid 603227064Sbzqla_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 604227064Sbz{ 605227064Sbz bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map); 606227064Sbz bus_dma_tag_destroy(dma_buf->dma_tag); 607227064Sbz} 608227064Sbz 609227064Sbzstatic int 610227064Sbzqla_alloc_parent_dma_tag(qla_host_t *ha) 611227064Sbz{ 612227064Sbz int ret; 613227064Sbz device_t dev; 614227064Sbz 615227064Sbz dev = ha->pci_dev; 616227064Sbz 617227064Sbz /* 618227064Sbz * Allocate parent DMA Tag 619227064Sbz */ 620227064Sbz ret = bus_dma_tag_create( 621227064Sbz bus_get_dma_tag(dev), /* parent */ 622227064Sbz 1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */ 623227064Sbz BUS_SPACE_MAXADDR, /* lowaddr */ 624227064Sbz BUS_SPACE_MAXADDR, /* highaddr */ 625227064Sbz NULL, NULL, /* filter, filterarg */ 626227064Sbz BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 627227064Sbz 0, /* nsegments */ 628227064Sbz BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 629227064Sbz 0, /* flags */ 630227064Sbz NULL, NULL, /* lockfunc, lockarg */ 631227064Sbz &ha->parent_tag); 632227064Sbz 633227064Sbz if (ret) { 634227064Sbz device_printf(dev, "%s: could not create parent dma tag\n", 635227064Sbz __func__); 636227064Sbz return (-1); 637227064Sbz } 638227064Sbz 639227064Sbz ha->flags.parent_tag = 1; 640227064Sbz 641227064Sbz return (0); 642227064Sbz} 643227064Sbz 644227064Sbzstatic void 645227064Sbzqla_free_parent_dma_tag(qla_host_t *ha) 646227064Sbz{ 647227064Sbz if (ha->flags.parent_tag) { 648227064Sbz bus_dma_tag_destroy(ha->parent_tag); 649227064Sbz ha->flags.parent_tag = 0; 650227064Sbz } 651227064Sbz} 652227064Sbz 653227064Sbz/* 654227064Sbz * Name: qla_init_ifnet 655227064Sbz * Function: Creates the Network Device Interface and Registers it with the O.S 656227064Sbz */ 657227064Sbz 658227064Sbzstatic void 659227064Sbzqla_init_ifnet(device_t dev, qla_host_t *ha) 660227064Sbz{ 661227064Sbz struct ifnet *ifp; 662227064Sbz 663227064Sbz QL_DPRINT2((dev, "%s: enter\n", __func__)); 664227064Sbz 665227064Sbz ifp = ha->ifp = if_alloc(IFT_ETHER); 666227064Sbz 667227064Sbz if (ifp == NULL) 668227064Sbz panic("%s: cannot if_alloc()\n", device_get_nameunit(dev)); 669227064Sbz 670227064Sbz if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 671227064Sbz 672250375Sdavidcs if_initbaudrate(ifp, IF_Gbps(10)); 673227064Sbz ifp->if_init = qla_init; 674227064Sbz ifp->if_softc = ha; 675227064Sbz ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 676227064Sbz ifp->if_ioctl = qla_ioctl; 677227064Sbz ifp->if_start = qla_start; 678227064Sbz 679227064Sbz IFQ_SET_MAXLEN(&ifp->if_snd, qla_get_ifq_snd_maxlen(ha)); 680227064Sbz ifp->if_snd.ifq_drv_maxlen = qla_get_ifq_snd_maxlen(ha); 681227064Sbz IFQ_SET_READY(&ifp->if_snd); 682227064Sbz 683227064Sbz ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 684227064Sbz 685227064Sbz ether_ifattach(ifp, qla_get_mac_addr(ha)); 686227064Sbz 687227064Sbz ifp->if_capabilities = IFCAP_HWCSUM | 688227064Sbz IFCAP_TSO4 | 689227064Sbz IFCAP_JUMBO_MTU; 690227064Sbz 691227064Sbz ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 692250375Sdavidcs ifp->if_capabilities |= IFCAP_LINKSTATE; 693227064Sbz 694227064Sbz#if defined(__FreeBSD_version) && (__FreeBSD_version < 900002) 695227064Sbz ifp->if_timer = 0; 696227064Sbz ifp->if_watchdog = NULL; 697227064Sbz#endif /* #if defined(__FreeBSD_version) && (__FreeBSD_version < 900002) */ 698227064Sbz 699227064Sbz ifp->if_capenable = ifp->if_capabilities; 700227064Sbz 701227064Sbz ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 702227064Sbz 703227064Sbz ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status); 704227064Sbz 705227064Sbz ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0, 706227064Sbz NULL); 707227064Sbz ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL); 708227064Sbz 709227064Sbz ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO)); 710227064Sbz 711227064Sbz QL_DPRINT2((dev, "%s: exit\n", __func__)); 712227064Sbz 713227064Sbz return; 714227064Sbz} 715227064Sbz 716227064Sbzstatic void 717227064Sbzqla_init_locked(qla_host_t *ha) 718227064Sbz{ 719227064Sbz struct ifnet *ifp = ha->ifp; 720227064Sbz 721227064Sbz qla_stop(ha); 722227064Sbz 723227064Sbz if (qla_alloc_xmt_bufs(ha) != 0) 724227064Sbz return; 725227064Sbz 726227064Sbz if (qla_alloc_rcv_bufs(ha) != 0) 727227064Sbz return; 728227064Sbz 729227064Sbz if (qla_config_lro(ha)) 730227064Sbz return; 731227064Sbz 732227064Sbz bcopy(IF_LLADDR(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN); 733227064Sbz 734227064Sbz ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 735227064Sbz 736227064Sbz ha->flags.stop_rcv = 0; 737227064Sbz if (qla_init_hw_if(ha) == 0) { 738227064Sbz ifp = ha->ifp; 739227064Sbz ifp->if_drv_flags |= IFF_DRV_RUNNING; 740227064Sbz ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 741227064Sbz ha->flags.qla_watchdog_pause = 0; 742227064Sbz } 743227064Sbz 744227064Sbz return; 745227064Sbz} 746227064Sbz 747227064Sbzstatic void 748227064Sbzqla_init(void *arg) 749227064Sbz{ 750227064Sbz qla_host_t *ha; 751227064Sbz 752227064Sbz ha = (qla_host_t *)arg; 753227064Sbz 754227064Sbz QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__)); 755227064Sbz 756227064Sbz QLA_LOCK(ha, __func__); 757227064Sbz qla_init_locked(ha); 758227064Sbz QLA_UNLOCK(ha, __func__); 759227064Sbz 760227064Sbz QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__)); 761227064Sbz} 762227064Sbz 763227064Sbzstatic void 764227064Sbzqla_set_multi(qla_host_t *ha, uint32_t add_multi) 765227064Sbz{ 766227064Sbz uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; 767227064Sbz struct ifmultiaddr *ifma; 768227064Sbz int mcnt = 0; 769227064Sbz struct ifnet *ifp = ha->ifp; 770227064Sbz 771229613Sjhb if_maddr_rlock(ifp); 772227064Sbz 773227064Sbz TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 774227064Sbz 775227064Sbz if (ifma->ifma_addr->sa_family != AF_LINK) 776227064Sbz continue; 777227064Sbz 778227064Sbz if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) 779227064Sbz break; 780227064Sbz 781227064Sbz bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 782227064Sbz &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); 783227064Sbz 784227064Sbz mcnt++; 785227064Sbz } 786227064Sbz 787229613Sjhb if_maddr_runlock(ifp); 788227064Sbz 789227064Sbz qla_hw_set_multi(ha, mta, mcnt, add_multi); 790227064Sbz 791227064Sbz return; 792227064Sbz} 793227064Sbz 794227064Sbzstatic int 795227064Sbzqla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 796227064Sbz{ 797227064Sbz int ret = 0; 798227064Sbz struct ifreq *ifr = (struct ifreq *)data; 799227064Sbz struct ifaddr *ifa = (struct ifaddr *)data; 800227064Sbz qla_host_t *ha; 801227064Sbz 802227064Sbz ha = (qla_host_t *)ifp->if_softc; 803227064Sbz 804227064Sbz switch (cmd) { 805227064Sbz case SIOCSIFADDR: 806227064Sbz QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n", 807227064Sbz __func__, cmd)); 808227064Sbz 809227064Sbz if (ifa->ifa_addr->sa_family == AF_INET) { 810227064Sbz ifp->if_flags |= IFF_UP; 811227064Sbz if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 812227064Sbz QLA_LOCK(ha, __func__); 813227064Sbz qla_init_locked(ha); 814227064Sbz QLA_UNLOCK(ha, __func__); 815227064Sbz } 816227064Sbz QL_DPRINT4((ha->pci_dev, 817227064Sbz "%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n", 818227064Sbz __func__, cmd, ntohl(IA_SIN(ifa)->sin_addr.s_addr))); 819227064Sbz 820227064Sbz arp_ifinit(ifp, ifa); 821227064Sbz if (ntohl(IA_SIN(ifa)->sin_addr.s_addr) != INADDR_ANY) { 822227064Sbz qla_config_ipv4_addr(ha, 823227064Sbz (IA_SIN(ifa)->sin_addr.s_addr)); 824227064Sbz } 825227064Sbz } else { 826227064Sbz ether_ioctl(ifp, cmd, data); 827227064Sbz } 828227064Sbz break; 829227064Sbz 830227064Sbz case SIOCSIFMTU: 831227064Sbz QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n", 832227064Sbz __func__, cmd)); 833227064Sbz 834227064Sbz if (ifr->ifr_mtu > QLA_MAX_FRAME_SIZE - ETHER_HDR_LEN) { 835227064Sbz ret = EINVAL; 836227064Sbz } else { 837227064Sbz QLA_LOCK(ha, __func__); 838227064Sbz ifp->if_mtu = ifr->ifr_mtu; 839227064Sbz ha->max_frame_size = 840227064Sbz ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 841227064Sbz if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 842227064Sbz ret = qla_set_max_mtu(ha, ha->max_frame_size, 843227064Sbz (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id); 844227064Sbz } 845227064Sbz QLA_UNLOCK(ha, __func__); 846227064Sbz 847227064Sbz if (ret) 848227064Sbz ret = EINVAL; 849227064Sbz } 850227064Sbz 851227064Sbz break; 852227064Sbz 853227064Sbz case SIOCSIFFLAGS: 854227064Sbz QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n", 855227064Sbz __func__, cmd)); 856227064Sbz 857227064Sbz if (ifp->if_flags & IFF_UP) { 858227064Sbz if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 859227064Sbz if ((ifp->if_flags ^ ha->if_flags) & 860227064Sbz IFF_PROMISC) { 861227064Sbz qla_set_promisc(ha); 862227064Sbz } else if ((ifp->if_flags ^ ha->if_flags) & 863227064Sbz IFF_ALLMULTI) { 864227064Sbz qla_set_allmulti(ha); 865227064Sbz } 866227064Sbz } else { 867227064Sbz QLA_LOCK(ha, __func__); 868227064Sbz qla_init_locked(ha); 869227064Sbz ha->max_frame_size = ifp->if_mtu + 870227064Sbz ETHER_HDR_LEN + ETHER_CRC_LEN; 871227064Sbz ret = qla_set_max_mtu(ha, ha->max_frame_size, 872227064Sbz (ha->hw.rx_cntxt_rsp)->rx_rsp.cntxt_id); 873227064Sbz QLA_UNLOCK(ha, __func__); 874227064Sbz } 875227064Sbz } else { 876227064Sbz QLA_LOCK(ha, __func__); 877227064Sbz if (ifp->if_drv_flags & IFF_DRV_RUNNING) 878227064Sbz qla_stop(ha); 879227064Sbz ha->if_flags = ifp->if_flags; 880227064Sbz QLA_UNLOCK(ha, __func__); 881227064Sbz } 882227064Sbz break; 883227064Sbz 884227064Sbz case SIOCADDMULTI: 885227064Sbz QL_DPRINT4((ha->pci_dev, 886227064Sbz "%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd)); 887227064Sbz 888227064Sbz if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 889227064Sbz qla_set_multi(ha, 1); 890227064Sbz } 891227064Sbz break; 892227064Sbz 893227064Sbz case SIOCDELMULTI: 894227064Sbz QL_DPRINT4((ha->pci_dev, 895227064Sbz "%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd)); 896227064Sbz 897227064Sbz if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 898227064Sbz qla_set_multi(ha, 0); 899227064Sbz } 900227064Sbz break; 901227064Sbz 902227064Sbz case SIOCSIFMEDIA: 903227064Sbz case SIOCGIFMEDIA: 904227064Sbz QL_DPRINT4((ha->pci_dev, 905227064Sbz "%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n", 906227064Sbz __func__, cmd)); 907227064Sbz ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd); 908227064Sbz break; 909227064Sbz 910227064Sbz case SIOCSIFCAP: 911227064Sbz { 912227064Sbz int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 913227064Sbz 914227064Sbz QL_DPRINT4((ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n", 915227064Sbz __func__, cmd)); 916227064Sbz 917227064Sbz if (mask & IFCAP_HWCSUM) 918227064Sbz ifp->if_capenable ^= IFCAP_HWCSUM; 919227064Sbz if (mask & IFCAP_TSO4) 920227064Sbz ifp->if_capenable ^= IFCAP_TSO4; 921227064Sbz if (mask & IFCAP_TSO6) 922227064Sbz ifp->if_capenable ^= IFCAP_TSO6; 923227064Sbz if (mask & IFCAP_VLAN_HWTAGGING) 924227064Sbz ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 925227064Sbz 926227064Sbz if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 927227064Sbz qla_init(ha); 928227064Sbz 929227064Sbz VLAN_CAPABILITIES(ifp); 930227064Sbz break; 931227064Sbz } 932227064Sbz 933227064Sbz default: 934227064Sbz QL_DPRINT4((ha->pci_dev, "%s: default (0x%lx)\n", 935227064Sbz __func__, cmd)); 936227064Sbz ret = ether_ioctl(ifp, cmd, data); 937227064Sbz break; 938227064Sbz } 939227064Sbz 940227064Sbz return (ret); 941227064Sbz} 942227064Sbz 943227064Sbzstatic int 944227064Sbzqla_media_change(struct ifnet *ifp) 945227064Sbz{ 946227064Sbz qla_host_t *ha; 947227064Sbz struct ifmedia *ifm; 948227064Sbz int ret = 0; 949227064Sbz 950227064Sbz ha = (qla_host_t *)ifp->if_softc; 951227064Sbz 952227064Sbz QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__)); 953227064Sbz 954227064Sbz ifm = &ha->media; 955227064Sbz 956227064Sbz if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 957227064Sbz ret = EINVAL; 958227064Sbz 959227064Sbz QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__)); 960227064Sbz 961227064Sbz return (ret); 962227064Sbz} 963227064Sbz 964227064Sbzstatic void 965227064Sbzqla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 966227064Sbz{ 967227064Sbz qla_host_t *ha; 968227064Sbz 969227064Sbz ha = (qla_host_t *)ifp->if_softc; 970227064Sbz 971227064Sbz QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__)); 972227064Sbz 973227064Sbz ifmr->ifm_status = IFM_AVALID; 974227064Sbz ifmr->ifm_active = IFM_ETHER; 975227064Sbz 976227064Sbz qla_update_link_state(ha); 977227064Sbz if (ha->hw.flags.link_up) { 978227064Sbz ifmr->ifm_status |= IFM_ACTIVE; 979227064Sbz ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha)); 980227064Sbz } 981227064Sbz 982227064Sbz QL_DPRINT2((ha->pci_dev, "%s: exit (%s)\n", __func__,\ 983227064Sbz (ha->hw.flags.link_up ? "link_up" : "link_down"))); 984227064Sbz 985227064Sbz return; 986227064Sbz} 987227064Sbz 988227064Sbzvoid 989227064Sbzqla_start(struct ifnet *ifp) 990227064Sbz{ 991227064Sbz struct mbuf *m_head; 992227064Sbz qla_host_t *ha = (qla_host_t *)ifp->if_softc; 993227064Sbz 994227064Sbz QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__)); 995227064Sbz 996227064Sbz if (!mtx_trylock(&ha->tx_lock)) { 997227064Sbz QL_DPRINT8((ha->pci_dev, 998227064Sbz "%s: mtx_trylock(&ha->tx_lock) failed\n", __func__)); 999227064Sbz return; 1000227064Sbz } 1001227064Sbz 1002227064Sbz if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1003227064Sbz IFF_DRV_RUNNING) { 1004227064Sbz QL_DPRINT8((ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__)); 1005227064Sbz QLA_TX_UNLOCK(ha); 1006227064Sbz return; 1007227064Sbz } 1008227064Sbz 1009227064Sbz if (!ha->watchdog_ticks) 1010227064Sbz qla_update_link_state(ha); 1011227064Sbz 1012227064Sbz if (!ha->hw.flags.link_up) { 1013227064Sbz QL_DPRINT8((ha->pci_dev, "%s: link down\n", __func__)); 1014227064Sbz QLA_TX_UNLOCK(ha); 1015227064Sbz return; 1016227064Sbz } 1017227064Sbz 1018227064Sbz while (ifp->if_snd.ifq_head != NULL) { 1019227064Sbz IF_DEQUEUE(&ifp->if_snd, m_head); 1020227064Sbz 1021227064Sbz if (m_head == NULL) { 1022227064Sbz QL_DPRINT8((ha->pci_dev, "%s: m_head == NULL\n", 1023227064Sbz __func__)); 1024227064Sbz break; 1025227064Sbz } 1026227064Sbz 1027227064Sbz if (qla_send(ha, &m_head)) { 1028227064Sbz if (m_head == NULL) 1029227064Sbz break; 1030227064Sbz QL_DPRINT8((ha->pci_dev, "%s: PREPEND\n", __func__)); 1031227064Sbz ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1032227064Sbz IF_PREPEND(&ifp->if_snd, m_head); 1033227064Sbz break; 1034227064Sbz } 1035227064Sbz /* Send a copy of the frame to the BPF listener */ 1036227064Sbz ETHER_BPF_MTAP(ifp, m_head); 1037227064Sbz } 1038227064Sbz QLA_TX_UNLOCK(ha); 1039227064Sbz QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__)); 1040227064Sbz return; 1041227064Sbz} 1042227064Sbz 1043227064Sbzstatic int 1044227064Sbzqla_send(qla_host_t *ha, struct mbuf **m_headp) 1045227064Sbz{ 1046227064Sbz bus_dma_segment_t segs[QLA_MAX_SEGMENTS]; 1047227064Sbz bus_dmamap_t map; 1048227064Sbz int nsegs; 1049227064Sbz int ret = -1; 1050227064Sbz uint32_t tx_idx; 1051227064Sbz struct mbuf *m_head = *m_headp; 1052227064Sbz 1053227064Sbz QL_DPRINT8((ha->pci_dev, "%s: enter\n", __func__)); 1054227064Sbz 1055227064Sbz if ((ret = bus_dmamap_create(ha->tx_tag, BUS_DMA_NOWAIT, &map))) { 1056227064Sbz ha->err_tx_dmamap_create++; 1057227064Sbz device_printf(ha->pci_dev, 1058227064Sbz "%s: bus_dmamap_create failed[%d, %d]\n", 1059227064Sbz __func__, ret, m_head->m_pkthdr.len); 1060227064Sbz return (ret); 1061227064Sbz } 1062227064Sbz 1063227064Sbz ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs, 1064227064Sbz BUS_DMA_NOWAIT); 1065227064Sbz 1066261864Sdavidcs if (ret == EFBIG) { 1067227064Sbz 1068227064Sbz struct mbuf *m; 1069227064Sbz 1070227064Sbz QL_DPRINT8((ha->pci_dev, "%s: EFBIG [%d]\n", __func__, 1071227064Sbz m_head->m_pkthdr.len)); 1072227064Sbz 1073243857Sglebius m = m_defrag(m_head, M_NOWAIT); 1074227064Sbz if (m == NULL) { 1075227064Sbz ha->err_tx_defrag++; 1076227064Sbz m_freem(m_head); 1077227064Sbz *m_headp = NULL; 1078227064Sbz device_printf(ha->pci_dev, 1079227064Sbz "%s: m_defrag() = NULL [%d]\n", 1080227064Sbz __func__, ret); 1081227064Sbz return (ENOBUFS); 1082227064Sbz } 1083227064Sbz m_head = m; 1084227064Sbz 1085227064Sbz if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, 1086227064Sbz segs, &nsegs, BUS_DMA_NOWAIT))) { 1087227064Sbz 1088227064Sbz ha->err_tx_dmamap_load++; 1089227064Sbz 1090227064Sbz device_printf(ha->pci_dev, 1091227064Sbz "%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n", 1092227064Sbz __func__, ret, m_head->m_pkthdr.len); 1093227064Sbz 1094227064Sbz bus_dmamap_destroy(ha->tx_tag, map); 1095227064Sbz if (ret != ENOMEM) { 1096227064Sbz m_freem(m_head); 1097227064Sbz *m_headp = NULL; 1098227064Sbz } 1099227064Sbz return (ret); 1100227064Sbz } 1101227064Sbz } else if (ret) { 1102227064Sbz ha->err_tx_dmamap_load++; 1103227064Sbz 1104227064Sbz device_printf(ha->pci_dev, 1105227064Sbz "%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n", 1106227064Sbz __func__, ret, m_head->m_pkthdr.len); 1107227064Sbz 1108227064Sbz bus_dmamap_destroy(ha->tx_tag, map); 1109227064Sbz 1110227064Sbz if (ret != ENOMEM) { 1111227064Sbz m_freem(m_head); 1112227064Sbz *m_headp = NULL; 1113227064Sbz } 1114227064Sbz return (ret); 1115227064Sbz } 1116227064Sbz 1117227064Sbz QL_ASSERT((nsegs != 0), ("qla_send: empty packet")); 1118227064Sbz 1119227064Sbz bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE); 1120227064Sbz 1121227064Sbz if (!(ret = qla_hw_send(ha, segs, nsegs, &tx_idx, m_head))) { 1122227064Sbz ha->tx_buf[tx_idx].m_head = m_head; 1123227064Sbz ha->tx_buf[tx_idx].map = map; 1124227064Sbz } else { 1125227064Sbz if (ret == EINVAL) { 1126227064Sbz m_freem(m_head); 1127227064Sbz *m_headp = NULL; 1128227064Sbz } 1129227064Sbz } 1130227064Sbz 1131227064Sbz QL_DPRINT8((ha->pci_dev, "%s: exit\n", __func__)); 1132227064Sbz return (ret); 1133227064Sbz} 1134227064Sbz 1135227064Sbzstatic void 1136227064Sbzqla_stop(qla_host_t *ha) 1137227064Sbz{ 1138227064Sbz struct ifnet *ifp = ha->ifp; 1139227064Sbz device_t dev; 1140227064Sbz 1141227064Sbz dev = ha->pci_dev; 1142227064Sbz 1143227064Sbz ha->flags.qla_watchdog_pause = 1; 1144227064Sbz qla_mdelay(__func__, 100); 1145227064Sbz 1146227064Sbz ha->flags.stop_rcv = 1; 1147227064Sbz qla_hw_stop_rcv(ha); 1148227064Sbz 1149227064Sbz qla_del_hw_if(ha); 1150227064Sbz 1151227064Sbz qla_free_lro(ha); 1152227064Sbz 1153227064Sbz qla_free_xmt_bufs(ha); 1154227064Sbz qla_free_rcv_bufs(ha); 1155227064Sbz 1156227064Sbz ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); 1157227064Sbz 1158227064Sbz return; 1159227064Sbz} 1160227064Sbz 1161227064Sbz/* 1162227064Sbz * Buffer Management Functions for Transmit and Receive Rings 1163227064Sbz */ 1164227064Sbzstatic int 1165227064Sbzqla_alloc_xmt_bufs(qla_host_t *ha) 1166227064Sbz{ 1167227064Sbz if (bus_dma_tag_create(NULL, /* parent */ 1168227064Sbz 1, 0, /* alignment, bounds */ 1169227064Sbz BUS_SPACE_MAXADDR, /* lowaddr */ 1170227064Sbz BUS_SPACE_MAXADDR, /* highaddr */ 1171227064Sbz NULL, NULL, /* filter, filterarg */ 1172227064Sbz QLA_MAX_TSO_FRAME_SIZE, /* maxsize */ 1173227064Sbz QLA_MAX_SEGMENTS, /* nsegments */ 1174227064Sbz PAGE_SIZE, /* maxsegsize */ 1175227064Sbz BUS_DMA_ALLOCNOW, /* flags */ 1176227064Sbz NULL, /* lockfunc */ 1177227064Sbz NULL, /* lockfuncarg */ 1178227064Sbz &ha->tx_tag)) { 1179227064Sbz device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n", 1180227064Sbz __func__); 1181227064Sbz return (ENOMEM); 1182227064Sbz } 1183227064Sbz bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1184227064Sbz 1185227064Sbz return 0; 1186227064Sbz} 1187227064Sbz 1188227064Sbz/* 1189227064Sbz * Release mbuf after it sent on the wire 1190227064Sbz */ 1191227064Sbzstatic void 1192227064Sbzqla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb) 1193227064Sbz{ 1194227064Sbz QL_DPRINT2((ha->pci_dev, "%s: enter\n", __func__)); 1195227064Sbz 1196227064Sbz if (txb->m_head) { 1197227064Sbz 1198227064Sbz bus_dmamap_unload(ha->tx_tag, txb->map); 1199227064Sbz bus_dmamap_destroy(ha->tx_tag, txb->map); 1200227064Sbz 1201227064Sbz m_freem(txb->m_head); 1202227064Sbz txb->m_head = NULL; 1203227064Sbz } 1204227064Sbz 1205227064Sbz QL_DPRINT2((ha->pci_dev, "%s: exit\n", __func__)); 1206227064Sbz} 1207227064Sbz 1208227064Sbzstatic void 1209227064Sbzqla_free_xmt_bufs(qla_host_t *ha) 1210227064Sbz{ 1211227064Sbz int i; 1212227064Sbz 1213227064Sbz for (i = 0; i < NUM_TX_DESCRIPTORS; i++) 1214227064Sbz qla_clear_tx_buf(ha, &ha->tx_buf[i]); 1215227064Sbz 1216227064Sbz if (ha->tx_tag != NULL) { 1217227064Sbz bus_dma_tag_destroy(ha->tx_tag); 1218227064Sbz ha->tx_tag = NULL; 1219227064Sbz } 1220227064Sbz bzero((void *)ha->tx_buf, (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1221227064Sbz 1222227064Sbz return; 1223227064Sbz} 1224227064Sbz 1225227064Sbz 1226227064Sbzstatic int 1227227064Sbzqla_alloc_rcv_bufs(qla_host_t *ha) 1228227064Sbz{ 1229227064Sbz int i, j, ret = 0; 1230227064Sbz qla_rx_buf_t *rxb; 1231227064Sbz 1232227064Sbz if (bus_dma_tag_create(NULL, /* parent */ 1233227064Sbz 1, 0, /* alignment, bounds */ 1234227064Sbz BUS_SPACE_MAXADDR, /* lowaddr */ 1235227064Sbz BUS_SPACE_MAXADDR, /* highaddr */ 1236227064Sbz NULL, NULL, /* filter, filterarg */ 1237227064Sbz MJUM9BYTES, /* maxsize */ 1238227064Sbz 1, /* nsegments */ 1239227064Sbz MJUM9BYTES, /* maxsegsize */ 1240227064Sbz BUS_DMA_ALLOCNOW, /* flags */ 1241227064Sbz NULL, /* lockfunc */ 1242227064Sbz NULL, /* lockfuncarg */ 1243227064Sbz &ha->rx_tag)) { 1244227064Sbz 1245227064Sbz device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n", 1246227064Sbz __func__); 1247227064Sbz 1248227064Sbz return (ENOMEM); 1249227064Sbz } 1250227064Sbz 1251227064Sbz bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS)); 1252227064Sbz bzero((void *)ha->rx_jbuf, 1253227064Sbz (sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS)); 1254227064Sbz 1255227064Sbz for (i = 0; i < MAX_SDS_RINGS; i++) { 1256227064Sbz ha->hw.sds[i].sdsr_next = 0; 1257227064Sbz ha->hw.sds[i].rxb_free = NULL; 1258227064Sbz ha->hw.sds[i].rx_free = 0; 1259227064Sbz ha->hw.sds[i].rxjb_free = NULL; 1260227064Sbz ha->hw.sds[i].rxj_free = 0; 1261227064Sbz } 1262227064Sbz 1263227064Sbz for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1264227064Sbz 1265227064Sbz rxb = &ha->rx_buf[i]; 1266227064Sbz 1267227064Sbz ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map); 1268227064Sbz 1269227064Sbz if (ret) { 1270227064Sbz device_printf(ha->pci_dev, 1271227064Sbz "%s: dmamap[%d] failed\n", __func__, i); 1272227064Sbz 1273227064Sbz for (j = 0; j < i; j++) { 1274227064Sbz bus_dmamap_destroy(ha->rx_tag, 1275227064Sbz ha->rx_buf[j].map); 1276227064Sbz } 1277227064Sbz goto qla_alloc_rcv_bufs_failed; 1278227064Sbz } 1279227064Sbz } 1280227064Sbz 1281227064Sbz qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_NORMAL); 1282227064Sbz 1283227064Sbz for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1284227064Sbz rxb = &ha->rx_buf[i]; 1285227064Sbz rxb->handle = i; 1286227064Sbz if (!(ret = qla_get_mbuf(ha, rxb, NULL, 0))) { 1287227064Sbz /* 1288227064Sbz * set the physical address in the corresponding 1289227064Sbz * descriptor entry in the receive ring/queue for the 1290227064Sbz * hba 1291227064Sbz */ 1292227064Sbz qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_NORMAL, i, 1293227064Sbz rxb->handle, rxb->paddr, 1294227064Sbz (rxb->m_head)->m_pkthdr.len); 1295227064Sbz } else { 1296227064Sbz device_printf(ha->pci_dev, 1297227064Sbz "%s: qla_get_mbuf [standard(%d)] failed\n", 1298227064Sbz __func__, i); 1299227064Sbz bus_dmamap_destroy(ha->rx_tag, rxb->map); 1300227064Sbz goto qla_alloc_rcv_bufs_failed; 1301227064Sbz } 1302227064Sbz } 1303227064Sbz 1304227064Sbz 1305227064Sbz for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) { 1306227064Sbz 1307227064Sbz rxb = &ha->rx_jbuf[i]; 1308227064Sbz 1309227064Sbz ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, &rxb->map); 1310227064Sbz 1311227064Sbz if (ret) { 1312227064Sbz device_printf(ha->pci_dev, 1313227064Sbz "%s: dmamap[%d] failed\n", __func__, i); 1314227064Sbz 1315227064Sbz for (j = 0; j < i; j++) { 1316227064Sbz bus_dmamap_destroy(ha->rx_tag, 1317227064Sbz ha->rx_jbuf[j].map); 1318227064Sbz } 1319227064Sbz goto qla_alloc_rcv_bufs_failed; 1320227064Sbz } 1321227064Sbz } 1322227064Sbz 1323227064Sbz qla_init_hw_rcv_descriptors(ha, RDS_RING_INDEX_JUMBO); 1324227064Sbz 1325227064Sbz for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) { 1326227064Sbz rxb = &ha->rx_jbuf[i]; 1327227064Sbz rxb->handle = i; 1328227064Sbz if (!(ret = qla_get_mbuf(ha, rxb, NULL, 1))) { 1329227064Sbz /* 1330227064Sbz * set the physical address in the corresponding 1331227064Sbz * descriptor entry in the receive ring/queue for the 1332227064Sbz * hba 1333227064Sbz */ 1334227064Sbz qla_set_hw_rcv_desc(ha, RDS_RING_INDEX_JUMBO, i, 1335227064Sbz rxb->handle, rxb->paddr, 1336227064Sbz (rxb->m_head)->m_pkthdr.len); 1337227064Sbz } else { 1338227064Sbz device_printf(ha->pci_dev, 1339227064Sbz "%s: qla_get_mbuf [jumbo(%d)] failed\n", 1340227064Sbz __func__, i); 1341227064Sbz bus_dmamap_destroy(ha->rx_tag, rxb->map); 1342227064Sbz goto qla_alloc_rcv_bufs_failed; 1343227064Sbz } 1344227064Sbz } 1345227064Sbz 1346227064Sbz return (0); 1347227064Sbz 1348227064Sbzqla_alloc_rcv_bufs_failed: 1349227064Sbz qla_free_rcv_bufs(ha); 1350227064Sbz return (ret); 1351227064Sbz} 1352227064Sbz 1353227064Sbzstatic void 1354227064Sbzqla_free_rcv_bufs(qla_host_t *ha) 1355227064Sbz{ 1356227064Sbz int i; 1357227064Sbz qla_rx_buf_t *rxb; 1358227064Sbz 1359227064Sbz for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1360227064Sbz rxb = &ha->rx_buf[i]; 1361227064Sbz if (rxb->m_head != NULL) { 1362227064Sbz bus_dmamap_unload(ha->rx_tag, rxb->map); 1363227064Sbz bus_dmamap_destroy(ha->rx_tag, rxb->map); 1364227064Sbz m_freem(rxb->m_head); 1365227064Sbz rxb->m_head = NULL; 1366227064Sbz } 1367227064Sbz } 1368227064Sbz 1369227064Sbz for (i = 0; i < NUM_RX_JUMBO_DESCRIPTORS; i++) { 1370227064Sbz rxb = &ha->rx_jbuf[i]; 1371227064Sbz if (rxb->m_head != NULL) { 1372227064Sbz bus_dmamap_unload(ha->rx_tag, rxb->map); 1373227064Sbz bus_dmamap_destroy(ha->rx_tag, rxb->map); 1374227064Sbz m_freem(rxb->m_head); 1375227064Sbz rxb->m_head = NULL; 1376227064Sbz } 1377227064Sbz } 1378227064Sbz 1379227064Sbz if (ha->rx_tag != NULL) { 1380227064Sbz bus_dma_tag_destroy(ha->rx_tag); 1381227064Sbz ha->rx_tag = NULL; 1382227064Sbz } 1383227064Sbz 1384227064Sbz bzero((void *)ha->rx_buf, (sizeof(qla_rx_buf_t) * NUM_RX_DESCRIPTORS)); 1385227064Sbz bzero((void *)ha->rx_jbuf, 1386227064Sbz (sizeof(qla_rx_buf_t) * NUM_RX_JUMBO_DESCRIPTORS)); 1387227064Sbz 1388227064Sbz for (i = 0; i < MAX_SDS_RINGS; i++) { 1389227064Sbz ha->hw.sds[i].sdsr_next = 0; 1390227064Sbz ha->hw.sds[i].rxb_free = NULL; 1391227064Sbz ha->hw.sds[i].rx_free = 0; 1392227064Sbz ha->hw.sds[i].rxjb_free = NULL; 1393227064Sbz ha->hw.sds[i].rxj_free = 0; 1394227064Sbz } 1395227064Sbz 1396227064Sbz return; 1397227064Sbz} 1398227064Sbz 1399227064Sbzint 1400227064Sbzqla_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp, 1401227064Sbz uint32_t jumbo) 1402227064Sbz{ 1403227064Sbz register struct mbuf *mp = nmp; 1404227064Sbz struct ifnet *ifp; 1405227064Sbz int ret = 0; 1406227064Sbz uint32_t offset; 1407227064Sbz 1408227064Sbz QL_DPRINT2((ha->pci_dev, "%s: jumbo(0x%x) enter\n", __func__, jumbo)); 1409227064Sbz 1410227064Sbz ifp = ha->ifp; 1411227064Sbz 1412227064Sbz if (mp == NULL) { 1413227064Sbz 1414227064Sbz if (!jumbo) { 1415243857Sglebius mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1416227064Sbz 1417227064Sbz if (mp == NULL) { 1418227064Sbz ha->err_m_getcl++; 1419227064Sbz ret = ENOBUFS; 1420227064Sbz device_printf(ha->pci_dev, 1421227064Sbz "%s: m_getcl failed\n", __func__); 1422227064Sbz goto exit_qla_get_mbuf; 1423227064Sbz } 1424227064Sbz mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1425227064Sbz } else { 1426243857Sglebius mp = m_getjcl(M_NOWAIT, MT_DATA, M_PKTHDR, 1427227064Sbz MJUM9BYTES); 1428227064Sbz if (mp == NULL) { 1429227064Sbz ha->err_m_getjcl++; 1430227064Sbz ret = ENOBUFS; 1431227064Sbz device_printf(ha->pci_dev, 1432227064Sbz "%s: m_getjcl failed\n", __func__); 1433227064Sbz goto exit_qla_get_mbuf; 1434227064Sbz } 1435227064Sbz mp->m_len = mp->m_pkthdr.len = MJUM9BYTES; 1436227064Sbz } 1437227064Sbz } else { 1438227064Sbz if (!jumbo) 1439227064Sbz mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1440227064Sbz else 1441227064Sbz mp->m_len = mp->m_pkthdr.len = MJUM9BYTES; 1442227064Sbz 1443227064Sbz mp->m_data = mp->m_ext.ext_buf; 1444227064Sbz mp->m_next = NULL; 1445227064Sbz } 1446227064Sbz 1447227064Sbz 1448227064Sbz offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL); 1449227064Sbz if (offset) { 1450227064Sbz offset = 8 - offset; 1451227064Sbz m_adj(mp, offset); 1452227064Sbz } 1453227064Sbz 1454227064Sbz /* 1455227064Sbz * Using memory from the mbuf cluster pool, invoke the bus_dma 1456227064Sbz * machinery to arrange the memory mapping. 1457227064Sbz */ 1458227064Sbz ret = bus_dmamap_load(ha->rx_tag, rxb->map, 1459227064Sbz mtod(mp, void *), mp->m_len, 1460227064Sbz qla_dmamap_callback, &rxb->paddr, 1461227064Sbz BUS_DMA_NOWAIT); 1462227064Sbz if (ret || !rxb->paddr) { 1463227064Sbz m_free(mp); 1464227064Sbz rxb->m_head = NULL; 1465227064Sbz device_printf(ha->pci_dev, 1466227064Sbz "%s: bus_dmamap_load failed\n", __func__); 1467227064Sbz ret = -1; 1468227064Sbz goto exit_qla_get_mbuf; 1469227064Sbz } 1470227064Sbz rxb->m_head = mp; 1471227064Sbz bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD); 1472227064Sbz 1473227064Sbzexit_qla_get_mbuf: 1474227064Sbz QL_DPRINT2((ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret)); 1475227064Sbz return (ret); 1476227064Sbz} 1477227064Sbz 1478227064Sbzstatic void 1479227064Sbzqla_tx_done(void *context, int pending) 1480227064Sbz{ 1481227064Sbz qla_host_t *ha = context; 1482227064Sbz 1483227064Sbz qla_hw_tx_done(ha); 1484227064Sbz qla_start(ha->ifp); 1485227064Sbz} 1486227064Sbz 1487