1f10a77bbSDavid C Somayajulu /* 2f10a77bbSDavid C Somayajulu * Copyright (c) 2013-2014 Qlogic Corporation 3f10a77bbSDavid C Somayajulu * All rights reserved. 4f10a77bbSDavid C Somayajulu * 5f10a77bbSDavid C Somayajulu * Redistribution and use in source and binary forms, with or without 6f10a77bbSDavid C Somayajulu * modification, are permitted provided that the following conditions 7f10a77bbSDavid C Somayajulu * are met: 8f10a77bbSDavid C Somayajulu * 9f10a77bbSDavid C Somayajulu * 1. Redistributions of source code must retain the above copyright 10f10a77bbSDavid C Somayajulu * notice, this list of conditions and the following disclaimer. 11f10a77bbSDavid C Somayajulu * 2. Redistributions in binary form must reproduce the above copyright 12f10a77bbSDavid C Somayajulu * notice, this list of conditions and the following disclaimer in the 13f10a77bbSDavid C Somayajulu * documentation and/or other materials provided with the distribution. 14f10a77bbSDavid C Somayajulu * 15f10a77bbSDavid C Somayajulu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16f10a77bbSDavid C Somayajulu * and ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17f10a77bbSDavid C Somayajulu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18f10a77bbSDavid C Somayajulu * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19f10a77bbSDavid C Somayajulu * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20f10a77bbSDavid C Somayajulu * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21f10a77bbSDavid C Somayajulu * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22f10a77bbSDavid C Somayajulu * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23f10a77bbSDavid C Somayajulu * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24f10a77bbSDavid C Somayajulu * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25f10a77bbSDavid C Somayajulu * POSSIBILITY OF SUCH DAMAGE. 26f10a77bbSDavid C Somayajulu */ 27f10a77bbSDavid C Somayajulu 28f10a77bbSDavid C Somayajulu /* 29f10a77bbSDavid C Somayajulu * File: ql_os.c 30f10a77bbSDavid C Somayajulu * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 31f10a77bbSDavid C Somayajulu */ 32f10a77bbSDavid C Somayajulu 33f10a77bbSDavid C Somayajulu #include <sys/cdefs.h> 34f10a77bbSDavid C Somayajulu __FBSDID("$FreeBSD$"); 35f10a77bbSDavid C Somayajulu 36f10a77bbSDavid C Somayajulu 37f10a77bbSDavid C Somayajulu #include "ql_os.h" 38f10a77bbSDavid C Somayajulu #include "ql_hw.h" 39f10a77bbSDavid C Somayajulu #include "ql_def.h" 40f10a77bbSDavid C Somayajulu #include "ql_inline.h" 41f10a77bbSDavid C Somayajulu #include "ql_ver.h" 42f10a77bbSDavid C Somayajulu #include "ql_glbl.h" 43f10a77bbSDavid C Somayajulu #include "ql_dbg.h" 44f10a77bbSDavid C Somayajulu #include <sys/smp.h> 45f10a77bbSDavid C Somayajulu 46f10a77bbSDavid C Somayajulu /* 47f10a77bbSDavid C Somayajulu * Some PCI Configuration Space Related Defines 48f10a77bbSDavid C Somayajulu */ 49f10a77bbSDavid C Somayajulu 50f10a77bbSDavid C Somayajulu #ifndef PCI_VENDOR_QLOGIC 51f10a77bbSDavid C Somayajulu #define PCI_VENDOR_QLOGIC 0x1077 52f10a77bbSDavid C Somayajulu #endif 53f10a77bbSDavid C Somayajulu 54f10a77bbSDavid C Somayajulu #ifndef PCI_PRODUCT_QLOGIC_ISP8030 55f10a77bbSDavid C Somayajulu #define PCI_PRODUCT_QLOGIC_ISP8030 0x8030 56f10a77bbSDavid C Somayajulu #endif 57f10a77bbSDavid C Somayajulu 58f10a77bbSDavid C Somayajulu #define PCI_QLOGIC_ISP8030 \ 59f10a77bbSDavid C Somayajulu ((PCI_PRODUCT_QLOGIC_ISP8030 << 16) | PCI_VENDOR_QLOGIC) 60f10a77bbSDavid C Somayajulu 61f10a77bbSDavid C Somayajulu /* 62f10a77bbSDavid C Somayajulu * static functions 63f10a77bbSDavid C Somayajulu */ 64f10a77bbSDavid C Somayajulu static int qla_alloc_parent_dma_tag(qla_host_t *ha); 65f10a77bbSDavid C Somayajulu static void qla_free_parent_dma_tag(qla_host_t *ha); 66f10a77bbSDavid C Somayajulu static int qla_alloc_xmt_bufs(qla_host_t *ha); 67f10a77bbSDavid C Somayajulu static void qla_free_xmt_bufs(qla_host_t *ha); 68f10a77bbSDavid C Somayajulu static int qla_alloc_rcv_bufs(qla_host_t *ha); 69f10a77bbSDavid C Somayajulu static void qla_free_rcv_bufs(qla_host_t *ha); 70f10a77bbSDavid C Somayajulu static void qla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb); 71f10a77bbSDavid C Somayajulu 72f10a77bbSDavid C Somayajulu static void qla_init_ifnet(device_t dev, qla_host_t *ha); 73f10a77bbSDavid C Somayajulu static int qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS); 74f10a77bbSDavid C Somayajulu static int qla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS); 75f10a77bbSDavid C Somayajulu static void qla_release(qla_host_t *ha); 76f10a77bbSDavid C Somayajulu static void qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, 77f10a77bbSDavid C Somayajulu int error); 78f10a77bbSDavid C Somayajulu static void qla_stop(qla_host_t *ha); 79f10a77bbSDavid C Somayajulu static int qla_send(qla_host_t *ha, struct mbuf **m_headp); 80f10a77bbSDavid C Somayajulu static void qla_tx_done(void *context, int pending); 81f10a77bbSDavid C Somayajulu static void qla_get_peer(qla_host_t *ha); 82f10a77bbSDavid C Somayajulu static void qla_error_recovery(void *context, int pending); 83f10a77bbSDavid C Somayajulu 84f10a77bbSDavid C Somayajulu /* 85f10a77bbSDavid C Somayajulu * Hooks to the Operating Systems 86f10a77bbSDavid C Somayajulu */ 87f10a77bbSDavid C Somayajulu static int qla_pci_probe (device_t); 88f10a77bbSDavid C Somayajulu static int qla_pci_attach (device_t); 89f10a77bbSDavid C Somayajulu static int qla_pci_detach (device_t); 90f10a77bbSDavid C Somayajulu 91f10a77bbSDavid C Somayajulu static void qla_init(void *arg); 92f10a77bbSDavid C Somayajulu static int qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data); 93f10a77bbSDavid C Somayajulu static int qla_media_change(struct ifnet *ifp); 94f10a77bbSDavid C Somayajulu static void qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr); 95f10a77bbSDavid C Somayajulu static void qla_start(struct ifnet *ifp); 96f10a77bbSDavid C Somayajulu 97f10a77bbSDavid C Somayajulu static device_method_t qla_pci_methods[] = { 98f10a77bbSDavid C Somayajulu /* Device interface */ 99f10a77bbSDavid C Somayajulu DEVMETHOD(device_probe, qla_pci_probe), 100f10a77bbSDavid C Somayajulu DEVMETHOD(device_attach, qla_pci_attach), 101f10a77bbSDavid C Somayajulu DEVMETHOD(device_detach, qla_pci_detach), 102f10a77bbSDavid C Somayajulu { 0, 0 } 103f10a77bbSDavid C Somayajulu }; 104f10a77bbSDavid C Somayajulu 105f10a77bbSDavid C Somayajulu static driver_t qla_pci_driver = { 106f10a77bbSDavid C Somayajulu "ql", qla_pci_methods, sizeof (qla_host_t), 107f10a77bbSDavid C Somayajulu }; 108f10a77bbSDavid C Somayajulu 109f10a77bbSDavid C Somayajulu static devclass_t qla83xx_devclass; 110f10a77bbSDavid C Somayajulu 111f10a77bbSDavid C Somayajulu DRIVER_MODULE(qla83xx, pci, qla_pci_driver, qla83xx_devclass, 0, 0); 112f10a77bbSDavid C Somayajulu 113f10a77bbSDavid C Somayajulu MODULE_DEPEND(qla83xx, pci, 1, 1, 1); 114f10a77bbSDavid C Somayajulu MODULE_DEPEND(qla83xx, ether, 1, 1, 1); 115f10a77bbSDavid C Somayajulu 116f10a77bbSDavid C Somayajulu MALLOC_DEFINE(M_QLA83XXBUF, "qla83xxbuf", "Buffers for qla83xx driver"); 117f10a77bbSDavid C Somayajulu 118f10a77bbSDavid C Somayajulu #define QL_STD_REPLENISH_THRES 0 119f10a77bbSDavid C Somayajulu #define QL_JUMBO_REPLENISH_THRES 32 120f10a77bbSDavid C Somayajulu 121f10a77bbSDavid C Somayajulu 122f10a77bbSDavid C Somayajulu static char dev_str[64]; 123f10a77bbSDavid C Somayajulu 124f10a77bbSDavid C Somayajulu /* 125f10a77bbSDavid C Somayajulu * Name: qla_pci_probe 126f10a77bbSDavid C Somayajulu * Function: Validate the PCI device to be a QLA80XX device 127f10a77bbSDavid C Somayajulu */ 128f10a77bbSDavid C Somayajulu static int 129f10a77bbSDavid C Somayajulu qla_pci_probe(device_t dev) 130f10a77bbSDavid C Somayajulu { 131f10a77bbSDavid C Somayajulu switch ((pci_get_device(dev) << 16) | (pci_get_vendor(dev))) { 132f10a77bbSDavid C Somayajulu case PCI_QLOGIC_ISP8030: 133f10a77bbSDavid C Somayajulu snprintf(dev_str, sizeof(dev_str), "%s v%d.%d.%d", 134f10a77bbSDavid C Somayajulu "Qlogic ISP 83xx PCI CNA Adapter-Ethernet Function", 135f10a77bbSDavid C Somayajulu QLA_VERSION_MAJOR, QLA_VERSION_MINOR, 136f10a77bbSDavid C Somayajulu QLA_VERSION_BUILD); 137f10a77bbSDavid C Somayajulu device_set_desc(dev, dev_str); 138f10a77bbSDavid C Somayajulu break; 139f10a77bbSDavid C Somayajulu default: 140f10a77bbSDavid C Somayajulu return (ENXIO); 141f10a77bbSDavid C Somayajulu } 142f10a77bbSDavid C Somayajulu 143f10a77bbSDavid C Somayajulu if (bootverbose) 144f10a77bbSDavid C Somayajulu printf("%s: %s\n ", __func__, dev_str); 145f10a77bbSDavid C Somayajulu 146f10a77bbSDavid C Somayajulu return (BUS_PROBE_DEFAULT); 147f10a77bbSDavid C Somayajulu } 148f10a77bbSDavid C Somayajulu 149f10a77bbSDavid C Somayajulu static void 150f10a77bbSDavid C Somayajulu qla_add_sysctls(qla_host_t *ha) 151f10a77bbSDavid C Somayajulu { 152f10a77bbSDavid C Somayajulu device_t dev = ha->pci_dev; 153f10a77bbSDavid C Somayajulu 154f10a77bbSDavid C Somayajulu SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 155f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 156f10a77bbSDavid C Somayajulu OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, 157f10a77bbSDavid C Somayajulu (void *)ha, 0, 158f10a77bbSDavid C Somayajulu qla_sysctl_get_stats, "I", "Statistics"); 159f10a77bbSDavid C Somayajulu 160f10a77bbSDavid C Somayajulu SYSCTL_ADD_STRING(device_get_sysctl_ctx(dev), 161f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 162f10a77bbSDavid C Somayajulu OID_AUTO, "fw_version", CTLFLAG_RD, 163f10a77bbSDavid C Somayajulu &ha->fw_ver_str, 0, "firmware version"); 164f10a77bbSDavid C Somayajulu 165f10a77bbSDavid C Somayajulu SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 166f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 167f10a77bbSDavid C Somayajulu OID_AUTO, "link_status", CTLTYPE_INT | CTLFLAG_RW, 168f10a77bbSDavid C Somayajulu (void *)ha, 0, 169f10a77bbSDavid C Somayajulu qla_sysctl_get_link_status, "I", "Link Status"); 170f10a77bbSDavid C Somayajulu 171f10a77bbSDavid C Somayajulu ha->dbg_level = 0; 172f10a77bbSDavid C Somayajulu SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 173f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 174f10a77bbSDavid C Somayajulu OID_AUTO, "debug", CTLFLAG_RW, 175f10a77bbSDavid C Somayajulu &ha->dbg_level, ha->dbg_level, "Debug Level"); 176f10a77bbSDavid C Somayajulu 177f10a77bbSDavid C Somayajulu ha->std_replenish = QL_STD_REPLENISH_THRES; 178f10a77bbSDavid C Somayajulu SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 179f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 180f10a77bbSDavid C Somayajulu OID_AUTO, "std_replenish", CTLFLAG_RW, 181f10a77bbSDavid C Somayajulu &ha->std_replenish, ha->std_replenish, 182f10a77bbSDavid C Somayajulu "Threshold for Replenishing Standard Frames"); 183f10a77bbSDavid C Somayajulu 184f10a77bbSDavid C Somayajulu SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 185f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 186f10a77bbSDavid C Somayajulu OID_AUTO, "ipv4_lro", 187f10a77bbSDavid C Somayajulu CTLFLAG_RD, &ha->ipv4_lro, 188f10a77bbSDavid C Somayajulu "number of ipv4 lro completions"); 189f10a77bbSDavid C Somayajulu 190f10a77bbSDavid C Somayajulu SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 191f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 192f10a77bbSDavid C Somayajulu OID_AUTO, "ipv6_lro", 193f10a77bbSDavid C Somayajulu CTLFLAG_RD, &ha->ipv6_lro, 194f10a77bbSDavid C Somayajulu "number of ipv6 lro completions"); 195f10a77bbSDavid C Somayajulu 196f10a77bbSDavid C Somayajulu SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 197f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 198f10a77bbSDavid C Somayajulu OID_AUTO, "tx_tso_frames", 199f10a77bbSDavid C Somayajulu CTLFLAG_RD, &ha->tx_tso_frames, 200f10a77bbSDavid C Somayajulu "number of Tx TSO Frames"); 201f10a77bbSDavid C Somayajulu 202f10a77bbSDavid C Somayajulu SYSCTL_ADD_QUAD(device_get_sysctl_ctx(dev), 203f10a77bbSDavid C Somayajulu SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 204f10a77bbSDavid C Somayajulu OID_AUTO, "hw_vlan_tx_frames", 205f10a77bbSDavid C Somayajulu CTLFLAG_RD, &ha->hw_vlan_tx_frames, 206f10a77bbSDavid C Somayajulu "number of Tx VLAN Frames"); 207f10a77bbSDavid C Somayajulu 208f10a77bbSDavid C Somayajulu return; 209f10a77bbSDavid C Somayajulu } 210f10a77bbSDavid C Somayajulu 211f10a77bbSDavid C Somayajulu static void 212f10a77bbSDavid C Somayajulu qla_watchdog(void *arg) 213f10a77bbSDavid C Somayajulu { 214f10a77bbSDavid C Somayajulu qla_host_t *ha = arg; 215f10a77bbSDavid C Somayajulu qla_hw_t *hw; 216f10a77bbSDavid C Somayajulu struct ifnet *ifp; 217f10a77bbSDavid C Somayajulu uint32_t i; 218f10a77bbSDavid C Somayajulu qla_hw_tx_cntxt_t *hw_tx_cntxt; 219f10a77bbSDavid C Somayajulu 220f10a77bbSDavid C Somayajulu hw = &ha->hw; 221f10a77bbSDavid C Somayajulu ifp = ha->ifp; 222f10a77bbSDavid C Somayajulu 223f10a77bbSDavid C Somayajulu if (ha->flags.qla_watchdog_exit) { 224f10a77bbSDavid C Somayajulu ha->qla_watchdog_exited = 1; 225f10a77bbSDavid C Somayajulu return; 226f10a77bbSDavid C Somayajulu } 227f10a77bbSDavid C Somayajulu ha->qla_watchdog_exited = 0; 228f10a77bbSDavid C Somayajulu 229f10a77bbSDavid C Somayajulu if (!ha->flags.qla_watchdog_pause) { 230f10a77bbSDavid C Somayajulu if (ql_hw_check_health(ha) || ha->qla_initiate_recovery || 231f10a77bbSDavid C Somayajulu (ha->msg_from_peer == QL_PEER_MSG_RESET)) { 232f10a77bbSDavid C Somayajulu ha->qla_watchdog_paused = 1; 233f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_pause = 1; 234f10a77bbSDavid C Somayajulu ha->qla_initiate_recovery = 0; 235f10a77bbSDavid C Somayajulu ha->err_inject = 0; 236f10a77bbSDavid C Somayajulu taskqueue_enqueue(ha->err_tq, &ha->err_task); 237f10a77bbSDavid C Somayajulu } else { 238f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_tx_rings; i++) { 239f10a77bbSDavid C Somayajulu hw_tx_cntxt = &hw->tx_cntxt[i]; 240f10a77bbSDavid C Somayajulu if (qla_le32_to_host(*(hw_tx_cntxt->tx_cons)) != 241f10a77bbSDavid C Somayajulu hw_tx_cntxt->txr_comp) { 242f10a77bbSDavid C Somayajulu taskqueue_enqueue(ha->tx_tq, 243f10a77bbSDavid C Somayajulu &ha->tx_task); 244f10a77bbSDavid C Somayajulu break; 245f10a77bbSDavid C Somayajulu } 246f10a77bbSDavid C Somayajulu } 247f10a77bbSDavid C Somayajulu 248f10a77bbSDavid C Somayajulu if ((ifp->if_snd.ifq_head != NULL) && QL_RUNNING(ifp)) { 249f10a77bbSDavid C Somayajulu taskqueue_enqueue(ha->tx_tq, &ha->tx_task); 250f10a77bbSDavid C Somayajulu } 251f10a77bbSDavid C Somayajulu ha->qla_watchdog_paused = 0; 252f10a77bbSDavid C Somayajulu } 253f10a77bbSDavid C Somayajulu 254f10a77bbSDavid C Somayajulu } else { 255f10a77bbSDavid C Somayajulu ha->qla_watchdog_paused = 1; 256f10a77bbSDavid C Somayajulu } 257f10a77bbSDavid C Somayajulu 258f10a77bbSDavid C Somayajulu ha->watchdog_ticks = ha->watchdog_ticks++ % 1000; 259f10a77bbSDavid C Somayajulu callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 260f10a77bbSDavid C Somayajulu qla_watchdog, ha); 261f10a77bbSDavid C Somayajulu } 262f10a77bbSDavid C Somayajulu 263f10a77bbSDavid C Somayajulu /* 264f10a77bbSDavid C Somayajulu * Name: qla_pci_attach 265f10a77bbSDavid C Somayajulu * Function: attaches the device to the operating system 266f10a77bbSDavid C Somayajulu */ 267f10a77bbSDavid C Somayajulu static int 268f10a77bbSDavid C Somayajulu qla_pci_attach(device_t dev) 269f10a77bbSDavid C Somayajulu { 270f10a77bbSDavid C Somayajulu qla_host_t *ha = NULL; 271f10a77bbSDavid C Somayajulu uint32_t rsrc_len; 272f10a77bbSDavid C Somayajulu int i; 273f10a77bbSDavid C Somayajulu 274f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 275f10a77bbSDavid C Somayajulu 276f10a77bbSDavid C Somayajulu if ((ha = device_get_softc(dev)) == NULL) { 277f10a77bbSDavid C Somayajulu device_printf(dev, "cannot get softc\n"); 278f10a77bbSDavid C Somayajulu return (ENOMEM); 279f10a77bbSDavid C Somayajulu } 280f10a77bbSDavid C Somayajulu 281f10a77bbSDavid C Somayajulu memset(ha, 0, sizeof (qla_host_t)); 282f10a77bbSDavid C Somayajulu 283f10a77bbSDavid C Somayajulu if (pci_get_device(dev) != PCI_PRODUCT_QLOGIC_ISP8030) { 284f10a77bbSDavid C Somayajulu device_printf(dev, "device is not ISP8030\n"); 285f10a77bbSDavid C Somayajulu return (ENXIO); 286f10a77bbSDavid C Somayajulu } 287f10a77bbSDavid C Somayajulu 288f10a77bbSDavid C Somayajulu ha->pci_func = pci_get_function(dev); 289f10a77bbSDavid C Somayajulu 290f10a77bbSDavid C Somayajulu ha->pci_dev = dev; 291f10a77bbSDavid C Somayajulu 292f10a77bbSDavid C Somayajulu pci_enable_busmaster(dev); 293f10a77bbSDavid C Somayajulu 294f10a77bbSDavid C Somayajulu ha->reg_rid = PCIR_BAR(0); 295f10a77bbSDavid C Somayajulu ha->pci_reg = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &ha->reg_rid, 296f10a77bbSDavid C Somayajulu RF_ACTIVE); 297f10a77bbSDavid C Somayajulu 298f10a77bbSDavid C Somayajulu if (ha->pci_reg == NULL) { 299f10a77bbSDavid C Somayajulu device_printf(dev, "unable to map any ports\n"); 300f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 301f10a77bbSDavid C Somayajulu } 302f10a77bbSDavid C Somayajulu 303f10a77bbSDavid C Somayajulu rsrc_len = (uint32_t) bus_get_resource_count(dev, SYS_RES_MEMORY, 304f10a77bbSDavid C Somayajulu ha->reg_rid); 305f10a77bbSDavid C Somayajulu 306f10a77bbSDavid C Somayajulu mtx_init(&ha->hw_lock, "qla83xx_hw_lock", MTX_NETWORK_LOCK, MTX_DEF); 307f10a77bbSDavid C Somayajulu 308f10a77bbSDavid C Somayajulu mtx_init(&ha->tx_lock, "qla83xx_tx_lock", MTX_NETWORK_LOCK, MTX_DEF); 309f10a77bbSDavid C Somayajulu 310f10a77bbSDavid C Somayajulu qla_add_sysctls(ha); 311f10a77bbSDavid C Somayajulu ql_hw_add_sysctls(ha); 312f10a77bbSDavid C Somayajulu 313f10a77bbSDavid C Somayajulu ha->flags.lock_init = 1; 314f10a77bbSDavid C Somayajulu 315f10a77bbSDavid C Somayajulu ha->reg_rid1 = PCIR_BAR(2); 316f10a77bbSDavid C Somayajulu ha->pci_reg1 = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 317f10a77bbSDavid C Somayajulu &ha->reg_rid1, RF_ACTIVE); 318f10a77bbSDavid C Somayajulu 319f10a77bbSDavid C Somayajulu ha->msix_count = pci_msix_count(dev); 320f10a77bbSDavid C Somayajulu 321f10a77bbSDavid C Somayajulu if (ha->msix_count < (ha->hw.num_sds_rings + 1)) { 322f10a77bbSDavid C Somayajulu device_printf(dev, "%s: msix_count[%d] not enough\n", __func__, 323f10a77bbSDavid C Somayajulu ha->msix_count); 324f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 325f10a77bbSDavid C Somayajulu } 326f10a77bbSDavid C Somayajulu 327f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: ha %p pci_func 0x%x rsrc_count 0x%08x" 328f10a77bbSDavid C Somayajulu " msix_count 0x%x pci_reg %p\n", __func__, ha, 329f10a77bbSDavid C Somayajulu ha->pci_func, rsrc_len, ha->msix_count, ha->pci_reg)); 330f10a77bbSDavid C Somayajulu 331f10a77bbSDavid C Somayajulu ha->msix_count = ha->hw.num_sds_rings + 1; 332f10a77bbSDavid C Somayajulu 333f10a77bbSDavid C Somayajulu if (pci_alloc_msix(dev, &ha->msix_count)) { 334f10a77bbSDavid C Somayajulu device_printf(dev, "%s: pci_alloc_msi[%d] failed\n", __func__, 335f10a77bbSDavid C Somayajulu ha->msix_count); 336f10a77bbSDavid C Somayajulu ha->msix_count = 0; 337f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 338f10a77bbSDavid C Somayajulu } 339f10a77bbSDavid C Somayajulu 340f10a77bbSDavid C Somayajulu ha->mbx_irq_rid = 1; 341f10a77bbSDavid C Somayajulu ha->mbx_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 342f10a77bbSDavid C Somayajulu &ha->mbx_irq_rid, 343f10a77bbSDavid C Somayajulu (RF_ACTIVE | RF_SHAREABLE)); 344f10a77bbSDavid C Somayajulu if (ha->mbx_irq == NULL) { 345f10a77bbSDavid C Somayajulu device_printf(dev, "could not allocate mbx interrupt\n"); 346f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 347f10a77bbSDavid C Somayajulu } 348f10a77bbSDavid C Somayajulu if (bus_setup_intr(dev, ha->mbx_irq, (INTR_TYPE_NET | INTR_MPSAFE), 349f10a77bbSDavid C Somayajulu NULL, ql_mbx_isr, ha, &ha->mbx_handle)) { 350f10a77bbSDavid C Somayajulu device_printf(dev, "could not setup mbx interrupt\n"); 351f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 352f10a77bbSDavid C Somayajulu } 353f10a77bbSDavid C Somayajulu 354f10a77bbSDavid C Somayajulu 355f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_sds_rings; i++) { 356f10a77bbSDavid C Somayajulu ha->irq_vec[i].sds_idx = i; 357f10a77bbSDavid C Somayajulu ha->irq_vec[i].ha = ha; 358f10a77bbSDavid C Somayajulu ha->irq_vec[i].irq_rid = 2 + i; 359f10a77bbSDavid C Somayajulu 360f10a77bbSDavid C Somayajulu ha->irq_vec[i].irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, 361f10a77bbSDavid C Somayajulu &ha->irq_vec[i].irq_rid, 362f10a77bbSDavid C Somayajulu (RF_ACTIVE | RF_SHAREABLE)); 363f10a77bbSDavid C Somayajulu 364f10a77bbSDavid C Somayajulu if (ha->irq_vec[i].irq == NULL) { 365f10a77bbSDavid C Somayajulu device_printf(dev, "could not allocate interrupt\n"); 366f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 367f10a77bbSDavid C Somayajulu } 368f10a77bbSDavid C Somayajulu if (bus_setup_intr(dev, ha->irq_vec[i].irq, 369f10a77bbSDavid C Somayajulu (INTR_TYPE_NET | INTR_MPSAFE), 370f10a77bbSDavid C Somayajulu NULL, ql_isr, &ha->irq_vec[i], 371f10a77bbSDavid C Somayajulu &ha->irq_vec[i].handle)) { 372f10a77bbSDavid C Somayajulu device_printf(dev, "could not setup interrupt\n"); 373f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 374f10a77bbSDavid C Somayajulu } 375f10a77bbSDavid C Somayajulu } 376f10a77bbSDavid C Somayajulu 377f10a77bbSDavid C Somayajulu printf("%s: mp__ncpus %d sds %d rds %d msi-x %d\n", __func__, mp_ncpus, 378f10a77bbSDavid C Somayajulu ha->hw.num_sds_rings, ha->hw.num_rds_rings, ha->msix_count); 379f10a77bbSDavid C Somayajulu 380f10a77bbSDavid C Somayajulu /* initialize hardware */ 381f10a77bbSDavid C Somayajulu if (ql_init_hw(ha)) { 382f10a77bbSDavid C Somayajulu device_printf(dev, "%s: ql_init_hw failed\n", __func__); 383f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 384f10a77bbSDavid C Somayajulu } 385f10a77bbSDavid C Somayajulu 386f10a77bbSDavid C Somayajulu device_printf(dev, "%s: firmware[%d.%d.%d.%d]\n", __func__, 387f10a77bbSDavid C Somayajulu ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 388f10a77bbSDavid C Somayajulu ha->fw_ver_build); 389f10a77bbSDavid C Somayajulu snprintf(ha->fw_ver_str, sizeof(ha->fw_ver_str), "%d.%d.%d.%d", 390f10a77bbSDavid C Somayajulu ha->fw_ver_major, ha->fw_ver_minor, ha->fw_ver_sub, 391f10a77bbSDavid C Somayajulu ha->fw_ver_build); 392f10a77bbSDavid C Somayajulu 393f10a77bbSDavid C Somayajulu ql_read_mac_addr(ha); 394f10a77bbSDavid C Somayajulu 395f10a77bbSDavid C Somayajulu /* allocate parent dma tag */ 396f10a77bbSDavid C Somayajulu if (qla_alloc_parent_dma_tag(ha)) { 397f10a77bbSDavid C Somayajulu device_printf(dev, "%s: qla_alloc_parent_dma_tag failed\n", 398f10a77bbSDavid C Somayajulu __func__); 399f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 400f10a77bbSDavid C Somayajulu } 401f10a77bbSDavid C Somayajulu 402f10a77bbSDavid C Somayajulu /* alloc all dma buffers */ 403f10a77bbSDavid C Somayajulu if (ql_alloc_dma(ha)) { 404f10a77bbSDavid C Somayajulu device_printf(dev, "%s: ql_alloc_dma failed\n", __func__); 405f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 406f10a77bbSDavid C Somayajulu } 407f10a77bbSDavid C Somayajulu qla_get_peer(ha); 408f10a77bbSDavid C Somayajulu 409f10a77bbSDavid C Somayajulu /* create the o.s ethernet interface */ 410f10a77bbSDavid C Somayajulu qla_init_ifnet(dev, ha); 411f10a77bbSDavid C Somayajulu 412f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_active = 1; 413f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_pause = 1; 414f10a77bbSDavid C Somayajulu 415f10a77bbSDavid C Somayajulu 416f10a77bbSDavid C Somayajulu TASK_INIT(&ha->tx_task, 0, qla_tx_done, ha); 417f10a77bbSDavid C Somayajulu ha->tx_tq = taskqueue_create_fast("qla_txq", M_NOWAIT, 418f10a77bbSDavid C Somayajulu taskqueue_thread_enqueue, &ha->tx_tq); 419f10a77bbSDavid C Somayajulu taskqueue_start_threads(&ha->tx_tq, 1, PI_NET, "%s txq", 420f10a77bbSDavid C Somayajulu device_get_nameunit(ha->pci_dev)); 421f10a77bbSDavid C Somayajulu 422f10a77bbSDavid C Somayajulu callout_init(&ha->tx_callout, TRUE); 423f10a77bbSDavid C Somayajulu ha->flags.qla_callout_init = 1; 424f10a77bbSDavid C Somayajulu 425f10a77bbSDavid C Somayajulu /* create ioctl device interface */ 426f10a77bbSDavid C Somayajulu if (ql_make_cdev(ha)) { 427f10a77bbSDavid C Somayajulu device_printf(dev, "%s: ql_make_cdev failed\n", __func__); 428f10a77bbSDavid C Somayajulu goto qla_pci_attach_err; 429f10a77bbSDavid C Somayajulu } 430f10a77bbSDavid C Somayajulu 431f10a77bbSDavid C Somayajulu callout_reset(&ha->tx_callout, QLA_WATCHDOG_CALLOUT_TICKS, 432f10a77bbSDavid C Somayajulu qla_watchdog, ha); 433f10a77bbSDavid C Somayajulu 434f10a77bbSDavid C Somayajulu TASK_INIT(&ha->err_task, 0, qla_error_recovery, ha); 435f10a77bbSDavid C Somayajulu ha->err_tq = taskqueue_create_fast("qla_errq", M_NOWAIT, 436f10a77bbSDavid C Somayajulu taskqueue_thread_enqueue, &ha->err_tq); 437f10a77bbSDavid C Somayajulu taskqueue_start_threads(&ha->err_tq, 1, PI_NET, "%s errq", 438f10a77bbSDavid C Somayajulu device_get_nameunit(ha->pci_dev)); 439f10a77bbSDavid C Somayajulu 440f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: exit 0\n", __func__)); 441f10a77bbSDavid C Somayajulu return (0); 442f10a77bbSDavid C Somayajulu 443f10a77bbSDavid C Somayajulu qla_pci_attach_err: 444f10a77bbSDavid C Somayajulu 445f10a77bbSDavid C Somayajulu qla_release(ha); 446f10a77bbSDavid C Somayajulu 447f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: exit ENXIO\n", __func__)); 448f10a77bbSDavid C Somayajulu return (ENXIO); 449f10a77bbSDavid C Somayajulu } 450f10a77bbSDavid C Somayajulu 451f10a77bbSDavid C Somayajulu /* 452f10a77bbSDavid C Somayajulu * Name: qla_pci_detach 453f10a77bbSDavid C Somayajulu * Function: Unhooks the device from the operating system 454f10a77bbSDavid C Somayajulu */ 455f10a77bbSDavid C Somayajulu static int 456f10a77bbSDavid C Somayajulu qla_pci_detach(device_t dev) 457f10a77bbSDavid C Somayajulu { 458f10a77bbSDavid C Somayajulu qla_host_t *ha = NULL; 459f10a77bbSDavid C Somayajulu struct ifnet *ifp; 460f10a77bbSDavid C Somayajulu 461f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 462f10a77bbSDavid C Somayajulu 463f10a77bbSDavid C Somayajulu if ((ha = device_get_softc(dev)) == NULL) { 464f10a77bbSDavid C Somayajulu device_printf(dev, "cannot get softc\n"); 465f10a77bbSDavid C Somayajulu return (ENOMEM); 466f10a77bbSDavid C Somayajulu } 467f10a77bbSDavid C Somayajulu 468f10a77bbSDavid C Somayajulu ifp = ha->ifp; 469f10a77bbSDavid C Somayajulu 470f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 471f10a77bbSDavid C Somayajulu qla_stop(ha); 472f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 473f10a77bbSDavid C Somayajulu 474f10a77bbSDavid C Somayajulu qla_release(ha); 475f10a77bbSDavid C Somayajulu 476f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: exit\n", __func__)); 477f10a77bbSDavid C Somayajulu 478f10a77bbSDavid C Somayajulu return (0); 479f10a77bbSDavid C Somayajulu } 480f10a77bbSDavid C Somayajulu 481f10a77bbSDavid C Somayajulu /* 482f10a77bbSDavid C Somayajulu * SYSCTL Related Callbacks 483f10a77bbSDavid C Somayajulu */ 484f10a77bbSDavid C Somayajulu static int 485f10a77bbSDavid C Somayajulu qla_sysctl_get_stats(SYSCTL_HANDLER_ARGS) 486f10a77bbSDavid C Somayajulu { 487f10a77bbSDavid C Somayajulu int err, ret = 0; 488f10a77bbSDavid C Somayajulu qla_host_t *ha; 489f10a77bbSDavid C Somayajulu 490f10a77bbSDavid C Somayajulu err = sysctl_handle_int(oidp, &ret, 0, req); 491f10a77bbSDavid C Somayajulu 492f10a77bbSDavid C Somayajulu if (err || !req->newptr) 493f10a77bbSDavid C Somayajulu return (err); 494f10a77bbSDavid C Somayajulu 495f10a77bbSDavid C Somayajulu if (ret == 1) { 496f10a77bbSDavid C Somayajulu ha = (qla_host_t *)arg1; 497f10a77bbSDavid C Somayajulu ql_get_stats(ha); 498f10a77bbSDavid C Somayajulu } 499f10a77bbSDavid C Somayajulu return (err); 500f10a77bbSDavid C Somayajulu } 501f10a77bbSDavid C Somayajulu static int 502f10a77bbSDavid C Somayajulu qla_sysctl_get_link_status(SYSCTL_HANDLER_ARGS) 503f10a77bbSDavid C Somayajulu { 504f10a77bbSDavid C Somayajulu int err, ret = 0; 505f10a77bbSDavid C Somayajulu qla_host_t *ha; 506f10a77bbSDavid C Somayajulu 507f10a77bbSDavid C Somayajulu err = sysctl_handle_int(oidp, &ret, 0, req); 508f10a77bbSDavid C Somayajulu 509f10a77bbSDavid C Somayajulu if (err || !req->newptr) 510f10a77bbSDavid C Somayajulu return (err); 511f10a77bbSDavid C Somayajulu 512f10a77bbSDavid C Somayajulu if (ret == 1) { 513f10a77bbSDavid C Somayajulu ha = (qla_host_t *)arg1; 514f10a77bbSDavid C Somayajulu ql_hw_link_status(ha); 515f10a77bbSDavid C Somayajulu } 516f10a77bbSDavid C Somayajulu return (err); 517f10a77bbSDavid C Somayajulu } 518f10a77bbSDavid C Somayajulu 519f10a77bbSDavid C Somayajulu /* 520f10a77bbSDavid C Somayajulu * Name: qla_release 521f10a77bbSDavid C Somayajulu * Function: Releases the resources allocated for the device 522f10a77bbSDavid C Somayajulu */ 523f10a77bbSDavid C Somayajulu static void 524f10a77bbSDavid C Somayajulu qla_release(qla_host_t *ha) 525f10a77bbSDavid C Somayajulu { 526f10a77bbSDavid C Somayajulu device_t dev; 527f10a77bbSDavid C Somayajulu int i; 528f10a77bbSDavid C Somayajulu 529f10a77bbSDavid C Somayajulu dev = ha->pci_dev; 530f10a77bbSDavid C Somayajulu 531f10a77bbSDavid C Somayajulu if (ha->err_tq) { 532f10a77bbSDavid C Somayajulu taskqueue_drain(ha->err_tq, &ha->err_task); 533f10a77bbSDavid C Somayajulu taskqueue_free(ha->err_tq); 534f10a77bbSDavid C Somayajulu } 535f10a77bbSDavid C Somayajulu 536f10a77bbSDavid C Somayajulu if (ha->tx_tq) { 537f10a77bbSDavid C Somayajulu taskqueue_drain(ha->tx_tq, &ha->tx_task); 538f10a77bbSDavid C Somayajulu taskqueue_free(ha->tx_tq); 539f10a77bbSDavid C Somayajulu } 540f10a77bbSDavid C Somayajulu 541f10a77bbSDavid C Somayajulu ql_del_cdev(ha); 542f10a77bbSDavid C Somayajulu 543f10a77bbSDavid C Somayajulu if (ha->flags.qla_watchdog_active) { 544f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_exit = 1; 545f10a77bbSDavid C Somayajulu 546f10a77bbSDavid C Somayajulu while (ha->qla_watchdog_exited == 0) 547f10a77bbSDavid C Somayajulu qla_mdelay(__func__, 1); 548f10a77bbSDavid C Somayajulu } 549f10a77bbSDavid C Somayajulu 550f10a77bbSDavid C Somayajulu if (ha->flags.qla_callout_init) 551f10a77bbSDavid C Somayajulu callout_stop(&ha->tx_callout); 552f10a77bbSDavid C Somayajulu 553f10a77bbSDavid C Somayajulu if (ha->ifp != NULL) 554f10a77bbSDavid C Somayajulu ether_ifdetach(ha->ifp); 555f10a77bbSDavid C Somayajulu 556f10a77bbSDavid C Somayajulu ql_free_dma(ha); 557f10a77bbSDavid C Somayajulu qla_free_parent_dma_tag(ha); 558f10a77bbSDavid C Somayajulu 559f10a77bbSDavid C Somayajulu if (ha->mbx_handle) 560f10a77bbSDavid C Somayajulu (void)bus_teardown_intr(dev, ha->mbx_irq, ha->mbx_handle); 561f10a77bbSDavid C Somayajulu 562f10a77bbSDavid C Somayajulu if (ha->mbx_irq) 563f10a77bbSDavid C Somayajulu (void) bus_release_resource(dev, SYS_RES_IRQ, ha->mbx_irq_rid, 564f10a77bbSDavid C Somayajulu ha->mbx_irq); 565f10a77bbSDavid C Somayajulu 566f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_sds_rings; i++) { 567f10a77bbSDavid C Somayajulu 568f10a77bbSDavid C Somayajulu if (ha->irq_vec[i].handle) { 569f10a77bbSDavid C Somayajulu (void)bus_teardown_intr(dev, ha->irq_vec[i].irq, 570f10a77bbSDavid C Somayajulu ha->irq_vec[i].handle); 571f10a77bbSDavid C Somayajulu } 572f10a77bbSDavid C Somayajulu 573f10a77bbSDavid C Somayajulu if (ha->irq_vec[i].irq) { 574f10a77bbSDavid C Somayajulu (void)bus_release_resource(dev, SYS_RES_IRQ, 575f10a77bbSDavid C Somayajulu ha->irq_vec[i].irq_rid, 576f10a77bbSDavid C Somayajulu ha->irq_vec[i].irq); 577f10a77bbSDavid C Somayajulu } 578f10a77bbSDavid C Somayajulu } 579f10a77bbSDavid C Somayajulu 580f10a77bbSDavid C Somayajulu if (ha->msix_count) 581f10a77bbSDavid C Somayajulu pci_release_msi(dev); 582f10a77bbSDavid C Somayajulu 583f10a77bbSDavid C Somayajulu if (ha->flags.lock_init) { 584f10a77bbSDavid C Somayajulu mtx_destroy(&ha->tx_lock); 585f10a77bbSDavid C Somayajulu mtx_destroy(&ha->hw_lock); 586f10a77bbSDavid C Somayajulu } 587f10a77bbSDavid C Somayajulu 588f10a77bbSDavid C Somayajulu if (ha->pci_reg) 589f10a77bbSDavid C Somayajulu (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid, 590f10a77bbSDavid C Somayajulu ha->pci_reg); 591f10a77bbSDavid C Somayajulu 592f10a77bbSDavid C Somayajulu if (ha->pci_reg1) 593f10a77bbSDavid C Somayajulu (void) bus_release_resource(dev, SYS_RES_MEMORY, ha->reg_rid1, 594f10a77bbSDavid C Somayajulu ha->pci_reg1); 595f10a77bbSDavid C Somayajulu } 596f10a77bbSDavid C Somayajulu 597f10a77bbSDavid C Somayajulu /* 598f10a77bbSDavid C Somayajulu * DMA Related Functions 599f10a77bbSDavid C Somayajulu */ 600f10a77bbSDavid C Somayajulu 601f10a77bbSDavid C Somayajulu static void 602f10a77bbSDavid C Somayajulu qla_dmamap_callback(void *arg, bus_dma_segment_t *segs, int nsegs, int error) 603f10a77bbSDavid C Somayajulu { 604f10a77bbSDavid C Somayajulu *((bus_addr_t *)arg) = 0; 605f10a77bbSDavid C Somayajulu 606f10a77bbSDavid C Somayajulu if (error) { 607f10a77bbSDavid C Somayajulu printf("%s: bus_dmamap_load failed (%d)\n", __func__, error); 608f10a77bbSDavid C Somayajulu return; 609f10a77bbSDavid C Somayajulu } 610f10a77bbSDavid C Somayajulu 611f10a77bbSDavid C Somayajulu *((bus_addr_t *)arg) = segs[0].ds_addr; 612f10a77bbSDavid C Somayajulu 613f10a77bbSDavid C Somayajulu return; 614f10a77bbSDavid C Somayajulu } 615f10a77bbSDavid C Somayajulu 616f10a77bbSDavid C Somayajulu int 617f10a77bbSDavid C Somayajulu ql_alloc_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 618f10a77bbSDavid C Somayajulu { 619f10a77bbSDavid C Somayajulu int ret = 0; 620f10a77bbSDavid C Somayajulu device_t dev; 621f10a77bbSDavid C Somayajulu bus_addr_t b_addr; 622f10a77bbSDavid C Somayajulu 623f10a77bbSDavid C Somayajulu dev = ha->pci_dev; 624f10a77bbSDavid C Somayajulu 625f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 626f10a77bbSDavid C Somayajulu 627f10a77bbSDavid C Somayajulu ret = bus_dma_tag_create( 628f10a77bbSDavid C Somayajulu ha->parent_tag,/* parent */ 629f10a77bbSDavid C Somayajulu dma_buf->alignment, 630f10a77bbSDavid C Somayajulu ((bus_size_t)(1ULL << 32)),/* boundary */ 631f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */ 632f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */ 633f10a77bbSDavid C Somayajulu NULL, NULL, /* filter, filterarg */ 634f10a77bbSDavid C Somayajulu dma_buf->size, /* maxsize */ 635f10a77bbSDavid C Somayajulu 1, /* nsegments */ 636f10a77bbSDavid C Somayajulu dma_buf->size, /* maxsegsize */ 637f10a77bbSDavid C Somayajulu 0, /* flags */ 638f10a77bbSDavid C Somayajulu NULL, NULL, /* lockfunc, lockarg */ 639f10a77bbSDavid C Somayajulu &dma_buf->dma_tag); 640f10a77bbSDavid C Somayajulu 641f10a77bbSDavid C Somayajulu if (ret) { 642f10a77bbSDavid C Somayajulu device_printf(dev, "%s: could not create dma tag\n", __func__); 643f10a77bbSDavid C Somayajulu goto ql_alloc_dmabuf_exit; 644f10a77bbSDavid C Somayajulu } 645f10a77bbSDavid C Somayajulu ret = bus_dmamem_alloc(dma_buf->dma_tag, 646f10a77bbSDavid C Somayajulu (void **)&dma_buf->dma_b, 647f10a77bbSDavid C Somayajulu (BUS_DMA_ZERO | BUS_DMA_COHERENT | BUS_DMA_NOWAIT), 648f10a77bbSDavid C Somayajulu &dma_buf->dma_map); 649f10a77bbSDavid C Somayajulu if (ret) { 650f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag); 651f10a77bbSDavid C Somayajulu device_printf(dev, "%s: bus_dmamem_alloc failed\n", __func__); 652f10a77bbSDavid C Somayajulu goto ql_alloc_dmabuf_exit; 653f10a77bbSDavid C Somayajulu } 654f10a77bbSDavid C Somayajulu 655f10a77bbSDavid C Somayajulu ret = bus_dmamap_load(dma_buf->dma_tag, 656f10a77bbSDavid C Somayajulu dma_buf->dma_map, 657f10a77bbSDavid C Somayajulu dma_buf->dma_b, 658f10a77bbSDavid C Somayajulu dma_buf->size, 659f10a77bbSDavid C Somayajulu qla_dmamap_callback, 660f10a77bbSDavid C Somayajulu &b_addr, BUS_DMA_NOWAIT); 661f10a77bbSDavid C Somayajulu 662f10a77bbSDavid C Somayajulu if (ret || !b_addr) { 663f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag); 664f10a77bbSDavid C Somayajulu bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, 665f10a77bbSDavid C Somayajulu dma_buf->dma_map); 666f10a77bbSDavid C Somayajulu ret = -1; 667f10a77bbSDavid C Somayajulu goto ql_alloc_dmabuf_exit; 668f10a77bbSDavid C Somayajulu } 669f10a77bbSDavid C Somayajulu 670f10a77bbSDavid C Somayajulu dma_buf->dma_addr = b_addr; 671f10a77bbSDavid C Somayajulu 672f10a77bbSDavid C Somayajulu ql_alloc_dmabuf_exit: 673f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: exit ret 0x%08x tag %p map %p b %p sz 0x%x\n", 674f10a77bbSDavid C Somayajulu __func__, ret, (void *)dma_buf->dma_tag, 675f10a77bbSDavid C Somayajulu (void *)dma_buf->dma_map, (void *)dma_buf->dma_b, 676f10a77bbSDavid C Somayajulu dma_buf->size)); 677f10a77bbSDavid C Somayajulu 678f10a77bbSDavid C Somayajulu return ret; 679f10a77bbSDavid C Somayajulu } 680f10a77bbSDavid C Somayajulu 681f10a77bbSDavid C Somayajulu void 682f10a77bbSDavid C Somayajulu ql_free_dmabuf(qla_host_t *ha, qla_dma_t *dma_buf) 683f10a77bbSDavid C Somayajulu { 684aeeb653cSJohn Baldwin bus_dmamap_unload(dma_buf->dma_tag, dma_buf->dma_map); 685f10a77bbSDavid C Somayajulu bus_dmamem_free(dma_buf->dma_tag, dma_buf->dma_b, dma_buf->dma_map); 686f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(dma_buf->dma_tag); 687f10a77bbSDavid C Somayajulu } 688f10a77bbSDavid C Somayajulu 689f10a77bbSDavid C Somayajulu static int 690f10a77bbSDavid C Somayajulu qla_alloc_parent_dma_tag(qla_host_t *ha) 691f10a77bbSDavid C Somayajulu { 692f10a77bbSDavid C Somayajulu int ret; 693f10a77bbSDavid C Somayajulu device_t dev; 694f10a77bbSDavid C Somayajulu 695f10a77bbSDavid C Somayajulu dev = ha->pci_dev; 696f10a77bbSDavid C Somayajulu 697f10a77bbSDavid C Somayajulu /* 698f10a77bbSDavid C Somayajulu * Allocate parent DMA Tag 699f10a77bbSDavid C Somayajulu */ 700f10a77bbSDavid C Somayajulu ret = bus_dma_tag_create( 701f10a77bbSDavid C Somayajulu bus_get_dma_tag(dev), /* parent */ 702f10a77bbSDavid C Somayajulu 1,((bus_size_t)(1ULL << 32)),/* alignment, boundary */ 703f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */ 704f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */ 705f10a77bbSDavid C Somayajulu NULL, NULL, /* filter, filterarg */ 706f10a77bbSDavid C Somayajulu BUS_SPACE_MAXSIZE_32BIT,/* maxsize */ 707f10a77bbSDavid C Somayajulu 0, /* nsegments */ 708f10a77bbSDavid C Somayajulu BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */ 709f10a77bbSDavid C Somayajulu 0, /* flags */ 710f10a77bbSDavid C Somayajulu NULL, NULL, /* lockfunc, lockarg */ 711f10a77bbSDavid C Somayajulu &ha->parent_tag); 712f10a77bbSDavid C Somayajulu 713f10a77bbSDavid C Somayajulu if (ret) { 714f10a77bbSDavid C Somayajulu device_printf(dev, "%s: could not create parent dma tag\n", 715f10a77bbSDavid C Somayajulu __func__); 716f10a77bbSDavid C Somayajulu return (-1); 717f10a77bbSDavid C Somayajulu } 718f10a77bbSDavid C Somayajulu 719f10a77bbSDavid C Somayajulu ha->flags.parent_tag = 1; 720f10a77bbSDavid C Somayajulu 721f10a77bbSDavid C Somayajulu return (0); 722f10a77bbSDavid C Somayajulu } 723f10a77bbSDavid C Somayajulu 724f10a77bbSDavid C Somayajulu static void 725f10a77bbSDavid C Somayajulu qla_free_parent_dma_tag(qla_host_t *ha) 726f10a77bbSDavid C Somayajulu { 727f10a77bbSDavid C Somayajulu if (ha->flags.parent_tag) { 728f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(ha->parent_tag); 729f10a77bbSDavid C Somayajulu ha->flags.parent_tag = 0; 730f10a77bbSDavid C Somayajulu } 731f10a77bbSDavid C Somayajulu } 732f10a77bbSDavid C Somayajulu 733f10a77bbSDavid C Somayajulu /* 734f10a77bbSDavid C Somayajulu * Name: qla_init_ifnet 735f10a77bbSDavid C Somayajulu * Function: Creates the Network Device Interface and Registers it with the O.S 736f10a77bbSDavid C Somayajulu */ 737f10a77bbSDavid C Somayajulu 738f10a77bbSDavid C Somayajulu static void 739f10a77bbSDavid C Somayajulu qla_init_ifnet(device_t dev, qla_host_t *ha) 740f10a77bbSDavid C Somayajulu { 741f10a77bbSDavid C Somayajulu struct ifnet *ifp; 742f10a77bbSDavid C Somayajulu 743f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 744f10a77bbSDavid C Somayajulu 745f10a77bbSDavid C Somayajulu ifp = ha->ifp = if_alloc(IFT_ETHER); 746f10a77bbSDavid C Somayajulu 747f10a77bbSDavid C Somayajulu if (ifp == NULL) 748f10a77bbSDavid C Somayajulu panic("%s: cannot if_alloc()\n", device_get_nameunit(dev)); 749f10a77bbSDavid C Somayajulu 750f10a77bbSDavid C Somayajulu if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 751f10a77bbSDavid C Somayajulu 752b245f96cSGleb Smirnoff ifp->if_baudrate = IF_Gbps(10); 753f10a77bbSDavid C Somayajulu ifp->if_capabilities = IFCAP_LINKSTATE; 754f10a77bbSDavid C Somayajulu 755f10a77bbSDavid C Somayajulu ifp->if_init = qla_init; 756f10a77bbSDavid C Somayajulu ifp->if_softc = ha; 757f10a77bbSDavid C Somayajulu ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 758f10a77bbSDavid C Somayajulu ifp->if_ioctl = qla_ioctl; 759f10a77bbSDavid C Somayajulu ifp->if_start = qla_start; 760f10a77bbSDavid C Somayajulu 761f10a77bbSDavid C Somayajulu IFQ_SET_MAXLEN(&ifp->if_snd, qla_get_ifq_snd_maxlen(ha)); 762f10a77bbSDavid C Somayajulu ifp->if_snd.ifq_drv_maxlen = qla_get_ifq_snd_maxlen(ha); 763f10a77bbSDavid C Somayajulu IFQ_SET_READY(&ifp->if_snd); 764f10a77bbSDavid C Somayajulu 765f10a77bbSDavid C Somayajulu ha->max_frame_size = ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 766f10a77bbSDavid C Somayajulu 767f10a77bbSDavid C Somayajulu ether_ifattach(ifp, qla_get_mac_addr(ha)); 768f10a77bbSDavid C Somayajulu 769f10a77bbSDavid C Somayajulu ifp->if_capabilities = IFCAP_HWCSUM | 770f10a77bbSDavid C Somayajulu IFCAP_TSO4 | 771f10a77bbSDavid C Somayajulu IFCAP_JUMBO_MTU; 772f10a77bbSDavid C Somayajulu 773f10a77bbSDavid C Somayajulu ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING | IFCAP_VLAN_MTU; 774f10a77bbSDavid C Somayajulu ifp->if_capabilities |= IFCAP_VLAN_HWTSO; 775f10a77bbSDavid C Somayajulu 776f10a77bbSDavid C Somayajulu ifp->if_capenable = ifp->if_capabilities; 777f10a77bbSDavid C Somayajulu 778*1bffa951SGleb Smirnoff ifp->if_hdrlen = sizeof(struct ether_vlan_header); 779f10a77bbSDavid C Somayajulu 780f10a77bbSDavid C Somayajulu ifmedia_init(&ha->media, IFM_IMASK, qla_media_change, qla_media_status); 781f10a77bbSDavid C Somayajulu 782f10a77bbSDavid C Somayajulu ifmedia_add(&ha->media, (IFM_ETHER | qla_get_optics(ha) | IFM_FDX), 0, 783f10a77bbSDavid C Somayajulu NULL); 784f10a77bbSDavid C Somayajulu ifmedia_add(&ha->media, (IFM_ETHER | IFM_AUTO), 0, NULL); 785f10a77bbSDavid C Somayajulu 786f10a77bbSDavid C Somayajulu ifmedia_set(&ha->media, (IFM_ETHER | IFM_AUTO)); 787f10a77bbSDavid C Somayajulu 788f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (dev, "%s: exit\n", __func__)); 789f10a77bbSDavid C Somayajulu 790f10a77bbSDavid C Somayajulu return; 791f10a77bbSDavid C Somayajulu } 792f10a77bbSDavid C Somayajulu 793f10a77bbSDavid C Somayajulu static void 794f10a77bbSDavid C Somayajulu qla_init_locked(qla_host_t *ha) 795f10a77bbSDavid C Somayajulu { 796f10a77bbSDavid C Somayajulu struct ifnet *ifp = ha->ifp; 797f10a77bbSDavid C Somayajulu 798f10a77bbSDavid C Somayajulu qla_stop(ha); 799f10a77bbSDavid C Somayajulu 800f10a77bbSDavid C Somayajulu if (qla_alloc_xmt_bufs(ha) != 0) 801f10a77bbSDavid C Somayajulu return; 802f10a77bbSDavid C Somayajulu 803f10a77bbSDavid C Somayajulu if (qla_alloc_rcv_bufs(ha) != 0) 804f10a77bbSDavid C Somayajulu return; 805f10a77bbSDavid C Somayajulu 806f10a77bbSDavid C Somayajulu bcopy(IF_LLADDR(ha->ifp), ha->hw.mac_addr, ETHER_ADDR_LEN); 807f10a77bbSDavid C Somayajulu 808f10a77bbSDavid C Somayajulu ifp->if_hwassist = CSUM_TCP | CSUM_UDP | CSUM_TSO; 809f10a77bbSDavid C Somayajulu 810f10a77bbSDavid C Somayajulu ha->flags.stop_rcv = 0; 811f10a77bbSDavid C Somayajulu if (ql_init_hw_if(ha) == 0) { 812f10a77bbSDavid C Somayajulu ifp = ha->ifp; 813f10a77bbSDavid C Somayajulu ifp->if_drv_flags |= IFF_DRV_RUNNING; 814f10a77bbSDavid C Somayajulu ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 815f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_pause = 0; 816f10a77bbSDavid C Somayajulu ha->hw_vlan_tx_frames = 0; 817f10a77bbSDavid C Somayajulu ha->tx_tso_frames = 0; 818f10a77bbSDavid C Somayajulu } 819f10a77bbSDavid C Somayajulu 820f10a77bbSDavid C Somayajulu return; 821f10a77bbSDavid C Somayajulu } 822f10a77bbSDavid C Somayajulu 823f10a77bbSDavid C Somayajulu static void 824f10a77bbSDavid C Somayajulu qla_init(void *arg) 825f10a77bbSDavid C Somayajulu { 826f10a77bbSDavid C Somayajulu qla_host_t *ha; 827f10a77bbSDavid C Somayajulu 828f10a77bbSDavid C Somayajulu ha = (qla_host_t *)arg; 829f10a77bbSDavid C Somayajulu 830f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 831f10a77bbSDavid C Somayajulu 832f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 833f10a77bbSDavid C Somayajulu qla_init_locked(ha); 834f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 835f10a77bbSDavid C Somayajulu 836f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 837f10a77bbSDavid C Somayajulu } 838f10a77bbSDavid C Somayajulu 839f10a77bbSDavid C Somayajulu static int 840f10a77bbSDavid C Somayajulu qla_set_multi(qla_host_t *ha, uint32_t add_multi) 841f10a77bbSDavid C Somayajulu { 842f10a77bbSDavid C Somayajulu uint8_t mta[Q8_MAX_NUM_MULTICAST_ADDRS * Q8_MAC_ADDR_LEN]; 843f10a77bbSDavid C Somayajulu struct ifmultiaddr *ifma; 844f10a77bbSDavid C Somayajulu int mcnt = 0; 845f10a77bbSDavid C Somayajulu struct ifnet *ifp = ha->ifp; 846f10a77bbSDavid C Somayajulu int ret = 0; 847f10a77bbSDavid C Somayajulu 848f10a77bbSDavid C Somayajulu if_maddr_rlock(ifp); 849f10a77bbSDavid C Somayajulu 850f10a77bbSDavid C Somayajulu TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 851f10a77bbSDavid C Somayajulu 852f10a77bbSDavid C Somayajulu if (ifma->ifma_addr->sa_family != AF_LINK) 853f10a77bbSDavid C Somayajulu continue; 854f10a77bbSDavid C Somayajulu 855f10a77bbSDavid C Somayajulu if (mcnt == Q8_MAX_NUM_MULTICAST_ADDRS) 856f10a77bbSDavid C Somayajulu break; 857f10a77bbSDavid C Somayajulu 858f10a77bbSDavid C Somayajulu bcopy(LLADDR((struct sockaddr_dl *) ifma->ifma_addr), 859f10a77bbSDavid C Somayajulu &mta[mcnt * Q8_MAC_ADDR_LEN], Q8_MAC_ADDR_LEN); 860f10a77bbSDavid C Somayajulu 861f10a77bbSDavid C Somayajulu mcnt++; 862f10a77bbSDavid C Somayajulu } 863f10a77bbSDavid C Somayajulu 864f10a77bbSDavid C Somayajulu if_maddr_runlock(ifp); 865f10a77bbSDavid C Somayajulu 866f10a77bbSDavid C Somayajulu if (QLA_LOCK(ha, __func__, 1) == 0) { 867f10a77bbSDavid C Somayajulu ret = ql_hw_set_multi(ha, mta, mcnt, add_multi); 868f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 869f10a77bbSDavid C Somayajulu } 870f10a77bbSDavid C Somayajulu 871f10a77bbSDavid C Somayajulu return (ret); 872f10a77bbSDavid C Somayajulu } 873f10a77bbSDavid C Somayajulu 874f10a77bbSDavid C Somayajulu static int 875f10a77bbSDavid C Somayajulu qla_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 876f10a77bbSDavid C Somayajulu { 877f10a77bbSDavid C Somayajulu int ret = 0; 878f10a77bbSDavid C Somayajulu struct ifreq *ifr = (struct ifreq *)data; 879f10a77bbSDavid C Somayajulu struct ifaddr *ifa = (struct ifaddr *)data; 880f10a77bbSDavid C Somayajulu qla_host_t *ha; 881f10a77bbSDavid C Somayajulu 882f10a77bbSDavid C Somayajulu ha = (qla_host_t *)ifp->if_softc; 883f10a77bbSDavid C Somayajulu 884f10a77bbSDavid C Somayajulu switch (cmd) { 885f10a77bbSDavid C Somayajulu case SIOCSIFADDR: 886f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFADDR (0x%lx)\n", 887f10a77bbSDavid C Somayajulu __func__, cmd)); 888f10a77bbSDavid C Somayajulu 889f10a77bbSDavid C Somayajulu if (ifa->ifa_addr->sa_family == AF_INET) { 890f10a77bbSDavid C Somayajulu ifp->if_flags |= IFF_UP; 891f10a77bbSDavid C Somayajulu if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 892f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 893f10a77bbSDavid C Somayajulu qla_init_locked(ha); 894f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 895f10a77bbSDavid C Somayajulu } 896f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, 897f10a77bbSDavid C Somayajulu "%s: SIOCSIFADDR (0x%lx) ipv4 [0x%08x]\n", 898f10a77bbSDavid C Somayajulu __func__, cmd, 899f10a77bbSDavid C Somayajulu ntohl(IA_SIN(ifa)->sin_addr.s_addr))); 900f10a77bbSDavid C Somayajulu 901f10a77bbSDavid C Somayajulu arp_ifinit(ifp, ifa); 902f10a77bbSDavid C Somayajulu } else { 903f10a77bbSDavid C Somayajulu ether_ioctl(ifp, cmd, data); 904f10a77bbSDavid C Somayajulu } 905f10a77bbSDavid C Somayajulu break; 906f10a77bbSDavid C Somayajulu 907f10a77bbSDavid C Somayajulu case SIOCSIFMTU: 908f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFMTU (0x%lx)\n", 909f10a77bbSDavid C Somayajulu __func__, cmd)); 910f10a77bbSDavid C Somayajulu 911f10a77bbSDavid C Somayajulu if (ifr->ifr_mtu > QLA_MAX_MTU) { 912f10a77bbSDavid C Somayajulu ret = EINVAL; 913f10a77bbSDavid C Somayajulu } else { 914f10a77bbSDavid C Somayajulu (void) QLA_LOCK(ha, __func__, 0); 915f10a77bbSDavid C Somayajulu ifp->if_mtu = ifr->ifr_mtu; 916f10a77bbSDavid C Somayajulu ha->max_frame_size = 917f10a77bbSDavid C Somayajulu ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN; 918f10a77bbSDavid C Somayajulu if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 919f10a77bbSDavid C Somayajulu ret = ql_set_max_mtu(ha, ha->max_frame_size, 920f10a77bbSDavid C Somayajulu ha->hw.rcv_cntxt_id); 921f10a77bbSDavid C Somayajulu } 922f10a77bbSDavid C Somayajulu 923f10a77bbSDavid C Somayajulu if (ifp->if_mtu > ETHERMTU) 924f10a77bbSDavid C Somayajulu ha->std_replenish = QL_JUMBO_REPLENISH_THRES; 925f10a77bbSDavid C Somayajulu else 926f10a77bbSDavid C Somayajulu ha->std_replenish = QL_STD_REPLENISH_THRES; 927f10a77bbSDavid C Somayajulu 928f10a77bbSDavid C Somayajulu 929f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 930f10a77bbSDavid C Somayajulu 931f10a77bbSDavid C Somayajulu if (ret) 932f10a77bbSDavid C Somayajulu ret = EINVAL; 933f10a77bbSDavid C Somayajulu } 934f10a77bbSDavid C Somayajulu 935f10a77bbSDavid C Somayajulu break; 936f10a77bbSDavid C Somayajulu 937f10a77bbSDavid C Somayajulu case SIOCSIFFLAGS: 938f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFFLAGS (0x%lx)\n", 939f10a77bbSDavid C Somayajulu __func__, cmd)); 940f10a77bbSDavid C Somayajulu 941f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 942f10a77bbSDavid C Somayajulu 943f10a77bbSDavid C Somayajulu if (ifp->if_flags & IFF_UP) { 944f10a77bbSDavid C Somayajulu if ((ifp->if_drv_flags & IFF_DRV_RUNNING)) { 945f10a77bbSDavid C Somayajulu if ((ifp->if_flags ^ ha->if_flags) & 946f10a77bbSDavid C Somayajulu IFF_PROMISC) { 947f10a77bbSDavid C Somayajulu ret = ql_set_promisc(ha); 948f10a77bbSDavid C Somayajulu } else if ((ifp->if_flags ^ ha->if_flags) & 949f10a77bbSDavid C Somayajulu IFF_ALLMULTI) { 950f10a77bbSDavid C Somayajulu ret = ql_set_allmulti(ha); 951f10a77bbSDavid C Somayajulu } 952f10a77bbSDavid C Somayajulu } else { 953f10a77bbSDavid C Somayajulu qla_init_locked(ha); 954f10a77bbSDavid C Somayajulu ha->max_frame_size = ifp->if_mtu + 955f10a77bbSDavid C Somayajulu ETHER_HDR_LEN + ETHER_CRC_LEN; 956f10a77bbSDavid C Somayajulu ret = ql_set_max_mtu(ha, ha->max_frame_size, 957f10a77bbSDavid C Somayajulu ha->hw.rcv_cntxt_id); 958f10a77bbSDavid C Somayajulu } 959f10a77bbSDavid C Somayajulu } else { 960f10a77bbSDavid C Somayajulu if (ifp->if_drv_flags & IFF_DRV_RUNNING) 961f10a77bbSDavid C Somayajulu qla_stop(ha); 962f10a77bbSDavid C Somayajulu ha->if_flags = ifp->if_flags; 963f10a77bbSDavid C Somayajulu } 964f10a77bbSDavid C Somayajulu 965f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 966f10a77bbSDavid C Somayajulu break; 967f10a77bbSDavid C Somayajulu 968f10a77bbSDavid C Somayajulu case SIOCADDMULTI: 969f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, 970f10a77bbSDavid C Somayajulu "%s: %s (0x%lx)\n", __func__, "SIOCADDMULTI", cmd)); 971f10a77bbSDavid C Somayajulu 972f10a77bbSDavid C Somayajulu if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 973f10a77bbSDavid C Somayajulu if (qla_set_multi(ha, 1)) 974f10a77bbSDavid C Somayajulu ret = EINVAL; 975f10a77bbSDavid C Somayajulu } 976f10a77bbSDavid C Somayajulu break; 977f10a77bbSDavid C Somayajulu 978f10a77bbSDavid C Somayajulu case SIOCDELMULTI: 979f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, 980f10a77bbSDavid C Somayajulu "%s: %s (0x%lx)\n", __func__, "SIOCDELMULTI", cmd)); 981f10a77bbSDavid C Somayajulu 982f10a77bbSDavid C Somayajulu if (ifp->if_drv_flags & IFF_DRV_RUNNING) { 983f10a77bbSDavid C Somayajulu if (qla_set_multi(ha, 0)) 984f10a77bbSDavid C Somayajulu ret = EINVAL; 985f10a77bbSDavid C Somayajulu } 986f10a77bbSDavid C Somayajulu break; 987f10a77bbSDavid C Somayajulu 988f10a77bbSDavid C Somayajulu case SIOCSIFMEDIA: 989f10a77bbSDavid C Somayajulu case SIOCGIFMEDIA: 990f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, 991f10a77bbSDavid C Somayajulu "%s: SIOCSIFMEDIA/SIOCGIFMEDIA (0x%lx)\n", 992f10a77bbSDavid C Somayajulu __func__, cmd)); 993f10a77bbSDavid C Somayajulu ret = ifmedia_ioctl(ifp, ifr, &ha->media, cmd); 994f10a77bbSDavid C Somayajulu break; 995f10a77bbSDavid C Somayajulu 996f10a77bbSDavid C Somayajulu case SIOCSIFCAP: 997f10a77bbSDavid C Somayajulu { 998f10a77bbSDavid C Somayajulu int mask = ifr->ifr_reqcap ^ ifp->if_capenable; 999f10a77bbSDavid C Somayajulu 1000f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, "%s: SIOCSIFCAP (0x%lx)\n", 1001f10a77bbSDavid C Somayajulu __func__, cmd)); 1002f10a77bbSDavid C Somayajulu 1003f10a77bbSDavid C Somayajulu if (mask & IFCAP_HWCSUM) 1004f10a77bbSDavid C Somayajulu ifp->if_capenable ^= IFCAP_HWCSUM; 1005f10a77bbSDavid C Somayajulu if (mask & IFCAP_TSO4) 1006f10a77bbSDavid C Somayajulu ifp->if_capenable ^= IFCAP_TSO4; 1007f10a77bbSDavid C Somayajulu if (mask & IFCAP_VLAN_HWTAGGING) 1008f10a77bbSDavid C Somayajulu ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING; 1009f10a77bbSDavid C Somayajulu if (mask & IFCAP_VLAN_HWTSO) 1010f10a77bbSDavid C Somayajulu ifp->if_capenable ^= IFCAP_VLAN_HWTSO; 1011f10a77bbSDavid C Somayajulu 1012f10a77bbSDavid C Somayajulu if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) 1013f10a77bbSDavid C Somayajulu qla_init(ha); 1014f10a77bbSDavid C Somayajulu 1015f10a77bbSDavid C Somayajulu VLAN_CAPABILITIES(ifp); 1016f10a77bbSDavid C Somayajulu break; 1017f10a77bbSDavid C Somayajulu } 1018f10a77bbSDavid C Somayajulu 1019f10a77bbSDavid C Somayajulu default: 1020f10a77bbSDavid C Somayajulu QL_DPRINT4(ha, (ha->pci_dev, "%s: default (0x%lx)\n", 1021f10a77bbSDavid C Somayajulu __func__, cmd)); 1022f10a77bbSDavid C Somayajulu ret = ether_ioctl(ifp, cmd, data); 1023f10a77bbSDavid C Somayajulu break; 1024f10a77bbSDavid C Somayajulu } 1025f10a77bbSDavid C Somayajulu 1026f10a77bbSDavid C Somayajulu return (ret); 1027f10a77bbSDavid C Somayajulu } 1028f10a77bbSDavid C Somayajulu 1029f10a77bbSDavid C Somayajulu static int 1030f10a77bbSDavid C Somayajulu qla_media_change(struct ifnet *ifp) 1031f10a77bbSDavid C Somayajulu { 1032f10a77bbSDavid C Somayajulu qla_host_t *ha; 1033f10a77bbSDavid C Somayajulu struct ifmedia *ifm; 1034f10a77bbSDavid C Somayajulu int ret = 0; 1035f10a77bbSDavid C Somayajulu 1036f10a77bbSDavid C Somayajulu ha = (qla_host_t *)ifp->if_softc; 1037f10a77bbSDavid C Somayajulu 1038f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1039f10a77bbSDavid C Somayajulu 1040f10a77bbSDavid C Somayajulu ifm = &ha->media; 1041f10a77bbSDavid C Somayajulu 1042f10a77bbSDavid C Somayajulu if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) 1043f10a77bbSDavid C Somayajulu ret = EINVAL; 1044f10a77bbSDavid C Somayajulu 1045f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1046f10a77bbSDavid C Somayajulu 1047f10a77bbSDavid C Somayajulu return (ret); 1048f10a77bbSDavid C Somayajulu } 1049f10a77bbSDavid C Somayajulu 1050f10a77bbSDavid C Somayajulu static void 1051f10a77bbSDavid C Somayajulu qla_media_status(struct ifnet *ifp, struct ifmediareq *ifmr) 1052f10a77bbSDavid C Somayajulu { 1053f10a77bbSDavid C Somayajulu qla_host_t *ha; 1054f10a77bbSDavid C Somayajulu 1055f10a77bbSDavid C Somayajulu ha = (qla_host_t *)ifp->if_softc; 1056f10a77bbSDavid C Somayajulu 1057f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1058f10a77bbSDavid C Somayajulu 1059f10a77bbSDavid C Somayajulu ifmr->ifm_status = IFM_AVALID; 1060f10a77bbSDavid C Somayajulu ifmr->ifm_active = IFM_ETHER; 1061f10a77bbSDavid C Somayajulu 1062f10a77bbSDavid C Somayajulu ql_update_link_state(ha); 1063f10a77bbSDavid C Somayajulu if (ha->hw.link_up) { 1064f10a77bbSDavid C Somayajulu ifmr->ifm_status |= IFM_ACTIVE; 1065f10a77bbSDavid C Somayajulu ifmr->ifm_active |= (IFM_FDX | qla_get_optics(ha)); 1066f10a77bbSDavid C Somayajulu } 1067f10a77bbSDavid C Somayajulu 1068f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: exit (%s)\n", __func__,\ 1069f10a77bbSDavid C Somayajulu (ha->hw.link_up ? "link_up" : "link_down"))); 1070f10a77bbSDavid C Somayajulu 1071f10a77bbSDavid C Somayajulu return; 1072f10a77bbSDavid C Somayajulu } 1073f10a77bbSDavid C Somayajulu 1074f10a77bbSDavid C Somayajulu static void 1075f10a77bbSDavid C Somayajulu qla_start(struct ifnet *ifp) 1076f10a77bbSDavid C Somayajulu { 1077f10a77bbSDavid C Somayajulu struct mbuf *m_head; 1078f10a77bbSDavid C Somayajulu qla_host_t *ha = (qla_host_t *)ifp->if_softc; 1079f10a77bbSDavid C Somayajulu 1080f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1081f10a77bbSDavid C Somayajulu 1082f10a77bbSDavid C Somayajulu if (!mtx_trylock(&ha->tx_lock)) { 1083f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, 1084f10a77bbSDavid C Somayajulu "%s: mtx_trylock(&ha->tx_lock) failed\n", __func__)); 1085f10a77bbSDavid C Somayajulu return; 1086f10a77bbSDavid C Somayajulu } 1087f10a77bbSDavid C Somayajulu 1088f10a77bbSDavid C Somayajulu if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 1089f10a77bbSDavid C Somayajulu IFF_DRV_RUNNING) { 1090f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, 1091f10a77bbSDavid C Somayajulu (ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__)); 1092f10a77bbSDavid C Somayajulu QLA_TX_UNLOCK(ha); 1093f10a77bbSDavid C Somayajulu return; 1094f10a77bbSDavid C Somayajulu } 1095f10a77bbSDavid C Somayajulu 1096f10a77bbSDavid C Somayajulu if (!ha->watchdog_ticks) 1097f10a77bbSDavid C Somayajulu ql_update_link_state(ha); 1098f10a77bbSDavid C Somayajulu 1099f10a77bbSDavid C Somayajulu if (!ha->hw.link_up) { 1100f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: link down\n", __func__)); 1101f10a77bbSDavid C Somayajulu QLA_TX_UNLOCK(ha); 1102f10a77bbSDavid C Somayajulu return; 1103f10a77bbSDavid C Somayajulu } 1104f10a77bbSDavid C Somayajulu 1105f10a77bbSDavid C Somayajulu while (ifp->if_snd.ifq_head != NULL) { 1106f10a77bbSDavid C Somayajulu IF_DEQUEUE(&ifp->if_snd, m_head); 1107f10a77bbSDavid C Somayajulu 1108f10a77bbSDavid C Somayajulu if (m_head == NULL) { 1109f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: m_head == NULL\n", 1110f10a77bbSDavid C Somayajulu __func__)); 1111f10a77bbSDavid C Somayajulu break; 1112f10a77bbSDavid C Somayajulu } 1113f10a77bbSDavid C Somayajulu 1114f10a77bbSDavid C Somayajulu if (qla_send(ha, &m_head)) { 1115f10a77bbSDavid C Somayajulu if (m_head == NULL) 1116f10a77bbSDavid C Somayajulu break; 1117f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: PREPEND\n", __func__)); 1118f10a77bbSDavid C Somayajulu ifp->if_drv_flags |= IFF_DRV_OACTIVE; 1119f10a77bbSDavid C Somayajulu IF_PREPEND(&ifp->if_snd, m_head); 1120f10a77bbSDavid C Somayajulu break; 1121f10a77bbSDavid C Somayajulu } 1122f10a77bbSDavid C Somayajulu /* Send a copy of the frame to the BPF listener */ 1123f10a77bbSDavid C Somayajulu ETHER_BPF_MTAP(ifp, m_head); 1124f10a77bbSDavid C Somayajulu } 1125f10a77bbSDavid C Somayajulu QLA_TX_UNLOCK(ha); 1126f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1127f10a77bbSDavid C Somayajulu return; 1128f10a77bbSDavid C Somayajulu } 1129f10a77bbSDavid C Somayajulu 1130f10a77bbSDavid C Somayajulu static int 1131f10a77bbSDavid C Somayajulu qla_send(qla_host_t *ha, struct mbuf **m_headp) 1132f10a77bbSDavid C Somayajulu { 1133f10a77bbSDavid C Somayajulu bus_dma_segment_t segs[QLA_MAX_SEGMENTS]; 1134f10a77bbSDavid C Somayajulu bus_dmamap_t map; 1135f10a77bbSDavid C Somayajulu int nsegs; 1136f10a77bbSDavid C Somayajulu int ret = -1; 1137f10a77bbSDavid C Somayajulu uint32_t tx_idx; 1138f10a77bbSDavid C Somayajulu struct mbuf *m_head = *m_headp; 1139f10a77bbSDavid C Somayajulu uint32_t txr_idx = ha->txr_idx; 1140f10a77bbSDavid C Somayajulu 1141f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1142f10a77bbSDavid C Somayajulu 1143f10a77bbSDavid C Somayajulu if (m_head->m_flags & M_FLOWID) 1144f10a77bbSDavid C Somayajulu txr_idx = m_head->m_pkthdr.flowid & (ha->hw.num_tx_rings - 1); 1145f10a77bbSDavid C Somayajulu 1146f10a77bbSDavid C Somayajulu tx_idx = ha->hw.tx_cntxt[txr_idx].txr_next; 1147f10a77bbSDavid C Somayajulu map = ha->tx_ring[txr_idx].tx_buf[tx_idx].map; 1148f10a77bbSDavid C Somayajulu 1149f10a77bbSDavid C Somayajulu ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, segs, &nsegs, 1150f10a77bbSDavid C Somayajulu BUS_DMA_NOWAIT); 1151f10a77bbSDavid C Somayajulu 1152f10a77bbSDavid C Somayajulu if (ret == EFBIG) { 1153f10a77bbSDavid C Somayajulu 1154f10a77bbSDavid C Somayajulu struct mbuf *m; 1155f10a77bbSDavid C Somayajulu 1156f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: EFBIG [%d]\n", __func__, 1157f10a77bbSDavid C Somayajulu m_head->m_pkthdr.len)); 1158f10a77bbSDavid C Somayajulu 1159f10a77bbSDavid C Somayajulu m = m_defrag(m_head, M_NOWAIT); 1160f10a77bbSDavid C Somayajulu if (m == NULL) { 1161f10a77bbSDavid C Somayajulu ha->err_tx_defrag++; 1162f10a77bbSDavid C Somayajulu m_freem(m_head); 1163f10a77bbSDavid C Somayajulu *m_headp = NULL; 1164f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1165f10a77bbSDavid C Somayajulu "%s: m_defrag() = NULL [%d]\n", 1166f10a77bbSDavid C Somayajulu __func__, ret); 1167f10a77bbSDavid C Somayajulu return (ENOBUFS); 1168f10a77bbSDavid C Somayajulu } 1169f10a77bbSDavid C Somayajulu m_head = m; 1170f10a77bbSDavid C Somayajulu *m_headp = m_head; 1171f10a77bbSDavid C Somayajulu 1172f10a77bbSDavid C Somayajulu if ((ret = bus_dmamap_load_mbuf_sg(ha->tx_tag, map, m_head, 1173f10a77bbSDavid C Somayajulu segs, &nsegs, BUS_DMA_NOWAIT))) { 1174f10a77bbSDavid C Somayajulu 1175f10a77bbSDavid C Somayajulu ha->err_tx_dmamap_load++; 1176f10a77bbSDavid C Somayajulu 1177f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1178f10a77bbSDavid C Somayajulu "%s: bus_dmamap_load_mbuf_sg failed0[%d, %d]\n", 1179f10a77bbSDavid C Somayajulu __func__, ret, m_head->m_pkthdr.len); 1180f10a77bbSDavid C Somayajulu 1181f10a77bbSDavid C Somayajulu if (ret != ENOMEM) { 1182f10a77bbSDavid C Somayajulu m_freem(m_head); 1183f10a77bbSDavid C Somayajulu *m_headp = NULL; 1184f10a77bbSDavid C Somayajulu } 1185f10a77bbSDavid C Somayajulu return (ret); 1186f10a77bbSDavid C Somayajulu } 1187f10a77bbSDavid C Somayajulu 1188f10a77bbSDavid C Somayajulu } else if (ret) { 1189f10a77bbSDavid C Somayajulu 1190f10a77bbSDavid C Somayajulu ha->err_tx_dmamap_load++; 1191f10a77bbSDavid C Somayajulu 1192f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1193f10a77bbSDavid C Somayajulu "%s: bus_dmamap_load_mbuf_sg failed1[%d, %d]\n", 1194f10a77bbSDavid C Somayajulu __func__, ret, m_head->m_pkthdr.len); 1195f10a77bbSDavid C Somayajulu 1196f10a77bbSDavid C Somayajulu if (ret != ENOMEM) { 1197f10a77bbSDavid C Somayajulu m_freem(m_head); 1198f10a77bbSDavid C Somayajulu *m_headp = NULL; 1199f10a77bbSDavid C Somayajulu } 1200f10a77bbSDavid C Somayajulu return (ret); 1201f10a77bbSDavid C Somayajulu } 1202f10a77bbSDavid C Somayajulu 1203f10a77bbSDavid C Somayajulu QL_ASSERT(ha, (nsegs != 0), ("qla_send: empty packet")); 1204f10a77bbSDavid C Somayajulu 1205f10a77bbSDavid C Somayajulu bus_dmamap_sync(ha->tx_tag, map, BUS_DMASYNC_PREWRITE); 1206f10a77bbSDavid C Somayajulu 1207f10a77bbSDavid C Somayajulu if (!(ret = ql_hw_send(ha, segs, nsegs, tx_idx, m_head, txr_idx))) { 1208f10a77bbSDavid C Somayajulu 1209f10a77bbSDavid C Somayajulu ha->tx_ring[txr_idx].count++; 1210f10a77bbSDavid C Somayajulu ha->tx_ring[txr_idx].tx_buf[tx_idx].m_head = m_head; 1211f10a77bbSDavid C Somayajulu } else { 1212f10a77bbSDavid C Somayajulu if (ret == EINVAL) { 1213f10a77bbSDavid C Somayajulu if (m_head) 1214f10a77bbSDavid C Somayajulu m_freem(m_head); 1215f10a77bbSDavid C Somayajulu *m_headp = NULL; 1216f10a77bbSDavid C Somayajulu } 1217f10a77bbSDavid C Somayajulu } 1218f10a77bbSDavid C Somayajulu 1219f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1220f10a77bbSDavid C Somayajulu return (ret); 1221f10a77bbSDavid C Somayajulu } 1222f10a77bbSDavid C Somayajulu 1223f10a77bbSDavid C Somayajulu static void 1224f10a77bbSDavid C Somayajulu qla_stop(qla_host_t *ha) 1225f10a77bbSDavid C Somayajulu { 1226f10a77bbSDavid C Somayajulu struct ifnet *ifp = ha->ifp; 1227f10a77bbSDavid C Somayajulu device_t dev; 1228f10a77bbSDavid C Somayajulu 1229f10a77bbSDavid C Somayajulu dev = ha->pci_dev; 1230f10a77bbSDavid C Somayajulu 1231f10a77bbSDavid C Somayajulu ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); 1232f10a77bbSDavid C Somayajulu 1233f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_pause = 1; 1234f10a77bbSDavid C Somayajulu 1235f10a77bbSDavid C Somayajulu while (!ha->qla_watchdog_paused) 1236f10a77bbSDavid C Somayajulu qla_mdelay(__func__, 1); 1237f10a77bbSDavid C Somayajulu 1238f10a77bbSDavid C Somayajulu ha->flags.stop_rcv = 1; 1239f10a77bbSDavid C Somayajulu ql_hw_stop_rcv(ha); 1240f10a77bbSDavid C Somayajulu 1241f10a77bbSDavid C Somayajulu ql_del_hw_if(ha); 1242f10a77bbSDavid C Somayajulu 1243f10a77bbSDavid C Somayajulu qla_free_xmt_bufs(ha); 1244f10a77bbSDavid C Somayajulu qla_free_rcv_bufs(ha); 1245f10a77bbSDavid C Somayajulu 1246f10a77bbSDavid C Somayajulu return; 1247f10a77bbSDavid C Somayajulu } 1248f10a77bbSDavid C Somayajulu 1249f10a77bbSDavid C Somayajulu /* 1250f10a77bbSDavid C Somayajulu * Buffer Management Functions for Transmit and Receive Rings 1251f10a77bbSDavid C Somayajulu */ 1252f10a77bbSDavid C Somayajulu static int 1253f10a77bbSDavid C Somayajulu qla_alloc_xmt_bufs(qla_host_t *ha) 1254f10a77bbSDavid C Somayajulu { 1255f10a77bbSDavid C Somayajulu int ret = 0; 1256f10a77bbSDavid C Somayajulu uint32_t i, j; 1257f10a77bbSDavid C Somayajulu qla_tx_buf_t *txb; 1258f10a77bbSDavid C Somayajulu 1259f10a77bbSDavid C Somayajulu if (bus_dma_tag_create(NULL, /* parent */ 1260f10a77bbSDavid C Somayajulu 1, 0, /* alignment, bounds */ 1261f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */ 1262f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */ 1263f10a77bbSDavid C Somayajulu NULL, NULL, /* filter, filterarg */ 1264f10a77bbSDavid C Somayajulu QLA_MAX_TSO_FRAME_SIZE, /* maxsize */ 1265f10a77bbSDavid C Somayajulu QLA_MAX_SEGMENTS, /* nsegments */ 1266f10a77bbSDavid C Somayajulu PAGE_SIZE, /* maxsegsize */ 1267f10a77bbSDavid C Somayajulu BUS_DMA_ALLOCNOW, /* flags */ 1268f10a77bbSDavid C Somayajulu NULL, /* lockfunc */ 1269f10a77bbSDavid C Somayajulu NULL, /* lockfuncarg */ 1270f10a77bbSDavid C Somayajulu &ha->tx_tag)) { 1271f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, "%s: tx_tag alloc failed\n", 1272f10a77bbSDavid C Somayajulu __func__); 1273f10a77bbSDavid C Somayajulu return (ENOMEM); 1274f10a77bbSDavid C Somayajulu } 1275f10a77bbSDavid C Somayajulu 1276f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_tx_rings; i++) { 1277f10a77bbSDavid C Somayajulu bzero((void *)ha->tx_ring[i].tx_buf, 1278f10a77bbSDavid C Somayajulu (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1279f10a77bbSDavid C Somayajulu } 1280f10a77bbSDavid C Somayajulu 1281f10a77bbSDavid C Somayajulu for (j = 0; j < ha->hw.num_tx_rings; j++) { 1282f10a77bbSDavid C Somayajulu for (i = 0; i < NUM_TX_DESCRIPTORS; i++) { 1283f10a77bbSDavid C Somayajulu 1284f10a77bbSDavid C Somayajulu txb = &ha->tx_ring[j].tx_buf[i]; 1285f10a77bbSDavid C Somayajulu 1286f10a77bbSDavid C Somayajulu if ((ret = bus_dmamap_create(ha->tx_tag, 1287f10a77bbSDavid C Somayajulu BUS_DMA_NOWAIT, &txb->map))) { 1288f10a77bbSDavid C Somayajulu 1289f10a77bbSDavid C Somayajulu ha->err_tx_dmamap_create++; 1290f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1291f10a77bbSDavid C Somayajulu "%s: bus_dmamap_create failed[%d]\n", 1292f10a77bbSDavid C Somayajulu __func__, ret); 1293f10a77bbSDavid C Somayajulu 1294f10a77bbSDavid C Somayajulu qla_free_xmt_bufs(ha); 1295f10a77bbSDavid C Somayajulu 1296f10a77bbSDavid C Somayajulu return (ret); 1297f10a77bbSDavid C Somayajulu } 1298f10a77bbSDavid C Somayajulu } 1299f10a77bbSDavid C Somayajulu } 1300f10a77bbSDavid C Somayajulu 1301f10a77bbSDavid C Somayajulu return 0; 1302f10a77bbSDavid C Somayajulu } 1303f10a77bbSDavid C Somayajulu 1304f10a77bbSDavid C Somayajulu /* 1305f10a77bbSDavid C Somayajulu * Release mbuf after it sent on the wire 1306f10a77bbSDavid C Somayajulu */ 1307f10a77bbSDavid C Somayajulu static void 1308f10a77bbSDavid C Somayajulu qla_clear_tx_buf(qla_host_t *ha, qla_tx_buf_t *txb) 1309f10a77bbSDavid C Somayajulu { 1310f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1311f10a77bbSDavid C Somayajulu 1312f10a77bbSDavid C Somayajulu if (txb->m_head && txb->map) { 1313f10a77bbSDavid C Somayajulu 1314f10a77bbSDavid C Somayajulu bus_dmamap_unload(ha->tx_tag, txb->map); 1315f10a77bbSDavid C Somayajulu 1316f10a77bbSDavid C Somayajulu m_freem(txb->m_head); 1317f10a77bbSDavid C Somayajulu txb->m_head = NULL; 1318f10a77bbSDavid C Somayajulu } 1319f10a77bbSDavid C Somayajulu 1320f10a77bbSDavid C Somayajulu if (txb->map) 1321f10a77bbSDavid C Somayajulu bus_dmamap_destroy(ha->tx_tag, txb->map); 1322f10a77bbSDavid C Somayajulu 1323f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: exit\n", __func__)); 1324f10a77bbSDavid C Somayajulu } 1325f10a77bbSDavid C Somayajulu 1326f10a77bbSDavid C Somayajulu static void 1327f10a77bbSDavid C Somayajulu qla_free_xmt_bufs(qla_host_t *ha) 1328f10a77bbSDavid C Somayajulu { 1329f10a77bbSDavid C Somayajulu int i, j; 1330f10a77bbSDavid C Somayajulu 1331f10a77bbSDavid C Somayajulu for (j = 0; j < ha->hw.num_tx_rings; j++) { 1332f10a77bbSDavid C Somayajulu for (i = 0; i < NUM_TX_DESCRIPTORS; i++) 1333f10a77bbSDavid C Somayajulu qla_clear_tx_buf(ha, &ha->tx_ring[j].tx_buf[i]); 1334f10a77bbSDavid C Somayajulu } 1335f10a77bbSDavid C Somayajulu 1336f10a77bbSDavid C Somayajulu if (ha->tx_tag != NULL) { 1337f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(ha->tx_tag); 1338f10a77bbSDavid C Somayajulu ha->tx_tag = NULL; 1339f10a77bbSDavid C Somayajulu } 1340f10a77bbSDavid C Somayajulu 1341f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_tx_rings; i++) { 1342f10a77bbSDavid C Somayajulu bzero((void *)ha->tx_ring[i].tx_buf, 1343f10a77bbSDavid C Somayajulu (sizeof(qla_tx_buf_t) * NUM_TX_DESCRIPTORS)); 1344f10a77bbSDavid C Somayajulu } 1345f10a77bbSDavid C Somayajulu return; 1346f10a77bbSDavid C Somayajulu } 1347f10a77bbSDavid C Somayajulu 1348f10a77bbSDavid C Somayajulu 1349f10a77bbSDavid C Somayajulu static int 1350f10a77bbSDavid C Somayajulu qla_alloc_rcv_std(qla_host_t *ha) 1351f10a77bbSDavid C Somayajulu { 1352f10a77bbSDavid C Somayajulu int i, j, k, r, ret = 0; 1353f10a77bbSDavid C Somayajulu qla_rx_buf_t *rxb; 1354f10a77bbSDavid C Somayajulu qla_rx_ring_t *rx_ring; 1355f10a77bbSDavid C Somayajulu 1356f10a77bbSDavid C Somayajulu for (r = 0; r < ha->hw.num_rds_rings; r++) { 1357f10a77bbSDavid C Somayajulu 1358f10a77bbSDavid C Somayajulu rx_ring = &ha->rx_ring[r]; 1359f10a77bbSDavid C Somayajulu 1360f10a77bbSDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1361f10a77bbSDavid C Somayajulu 1362f10a77bbSDavid C Somayajulu rxb = &rx_ring->rx_buf[i]; 1363f10a77bbSDavid C Somayajulu 1364f10a77bbSDavid C Somayajulu ret = bus_dmamap_create(ha->rx_tag, BUS_DMA_NOWAIT, 1365f10a77bbSDavid C Somayajulu &rxb->map); 1366f10a77bbSDavid C Somayajulu 1367f10a77bbSDavid C Somayajulu if (ret) { 1368f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1369f10a77bbSDavid C Somayajulu "%s: dmamap[%d, %d] failed\n", 1370f10a77bbSDavid C Somayajulu __func__, r, i); 1371f10a77bbSDavid C Somayajulu 1372f10a77bbSDavid C Somayajulu for (k = 0; k < r; k++) { 1373f10a77bbSDavid C Somayajulu for (j = 0; j < NUM_RX_DESCRIPTORS; 1374f10a77bbSDavid C Somayajulu j++) { 1375f10a77bbSDavid C Somayajulu rxb = &ha->rx_ring[k].rx_buf[j]; 1376f10a77bbSDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, 1377f10a77bbSDavid C Somayajulu rxb->map); 1378f10a77bbSDavid C Somayajulu } 1379f10a77bbSDavid C Somayajulu } 1380f10a77bbSDavid C Somayajulu 1381f10a77bbSDavid C Somayajulu for (j = 0; j < i; j++) { 1382f10a77bbSDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, 1383f10a77bbSDavid C Somayajulu rx_ring->rx_buf[j].map); 1384f10a77bbSDavid C Somayajulu } 1385f10a77bbSDavid C Somayajulu goto qla_alloc_rcv_std_err; 1386f10a77bbSDavid C Somayajulu } 1387f10a77bbSDavid C Somayajulu } 1388f10a77bbSDavid C Somayajulu } 1389f10a77bbSDavid C Somayajulu 1390f10a77bbSDavid C Somayajulu qla_init_hw_rcv_descriptors(ha); 1391f10a77bbSDavid C Somayajulu 1392f10a77bbSDavid C Somayajulu 1393f10a77bbSDavid C Somayajulu for (r = 0; r < ha->hw.num_rds_rings; r++) { 1394f10a77bbSDavid C Somayajulu 1395f10a77bbSDavid C Somayajulu rx_ring = &ha->rx_ring[r]; 1396f10a77bbSDavid C Somayajulu 1397f10a77bbSDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1398f10a77bbSDavid C Somayajulu rxb = &rx_ring->rx_buf[i]; 1399f10a77bbSDavid C Somayajulu rxb->handle = i; 1400f10a77bbSDavid C Somayajulu if (!(ret = ql_get_mbuf(ha, rxb, NULL))) { 1401f10a77bbSDavid C Somayajulu /* 1402f10a77bbSDavid C Somayajulu * set the physical address in the 1403f10a77bbSDavid C Somayajulu * corresponding descriptor entry in the 1404f10a77bbSDavid C Somayajulu * receive ring/queue for the hba 1405f10a77bbSDavid C Somayajulu */ 1406f10a77bbSDavid C Somayajulu qla_set_hw_rcv_desc(ha, r, i, rxb->handle, 1407f10a77bbSDavid C Somayajulu rxb->paddr, 1408f10a77bbSDavid C Somayajulu (rxb->m_head)->m_pkthdr.len); 1409f10a77bbSDavid C Somayajulu } else { 1410f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1411f10a77bbSDavid C Somayajulu "%s: ql_get_mbuf [%d, %d] failed\n", 1412f10a77bbSDavid C Somayajulu __func__, r, i); 1413f10a77bbSDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, rxb->map); 1414f10a77bbSDavid C Somayajulu goto qla_alloc_rcv_std_err; 1415f10a77bbSDavid C Somayajulu } 1416f10a77bbSDavid C Somayajulu } 1417f10a77bbSDavid C Somayajulu } 1418f10a77bbSDavid C Somayajulu return 0; 1419f10a77bbSDavid C Somayajulu 1420f10a77bbSDavid C Somayajulu qla_alloc_rcv_std_err: 1421f10a77bbSDavid C Somayajulu return (-1); 1422f10a77bbSDavid C Somayajulu } 1423f10a77bbSDavid C Somayajulu 1424f10a77bbSDavid C Somayajulu static void 1425f10a77bbSDavid C Somayajulu qla_free_rcv_std(qla_host_t *ha) 1426f10a77bbSDavid C Somayajulu { 1427f10a77bbSDavid C Somayajulu int i, r; 1428f10a77bbSDavid C Somayajulu qla_rx_buf_t *rxb; 1429f10a77bbSDavid C Somayajulu 1430f10a77bbSDavid C Somayajulu for (r = 0; r < ha->hw.num_rds_rings; r++) { 1431f10a77bbSDavid C Somayajulu for (i = 0; i < NUM_RX_DESCRIPTORS; i++) { 1432f10a77bbSDavid C Somayajulu rxb = &ha->rx_ring[r].rx_buf[i]; 1433f10a77bbSDavid C Somayajulu if (rxb->m_head != NULL) { 1434f10a77bbSDavid C Somayajulu bus_dmamap_unload(ha->rx_tag, rxb->map); 1435f10a77bbSDavid C Somayajulu bus_dmamap_destroy(ha->rx_tag, rxb->map); 1436f10a77bbSDavid C Somayajulu m_freem(rxb->m_head); 1437f10a77bbSDavid C Somayajulu rxb->m_head = NULL; 1438f10a77bbSDavid C Somayajulu } 1439f10a77bbSDavid C Somayajulu } 1440f10a77bbSDavid C Somayajulu } 1441f10a77bbSDavid C Somayajulu return; 1442f10a77bbSDavid C Somayajulu } 1443f10a77bbSDavid C Somayajulu 1444f10a77bbSDavid C Somayajulu static int 1445f10a77bbSDavid C Somayajulu qla_alloc_rcv_bufs(qla_host_t *ha) 1446f10a77bbSDavid C Somayajulu { 1447f10a77bbSDavid C Somayajulu int i, ret = 0; 1448f10a77bbSDavid C Somayajulu 1449f10a77bbSDavid C Somayajulu if (bus_dma_tag_create(NULL, /* parent */ 1450f10a77bbSDavid C Somayajulu 1, 0, /* alignment, bounds */ 1451f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* lowaddr */ 1452f10a77bbSDavid C Somayajulu BUS_SPACE_MAXADDR, /* highaddr */ 1453f10a77bbSDavid C Somayajulu NULL, NULL, /* filter, filterarg */ 1454f10a77bbSDavid C Somayajulu MJUM9BYTES, /* maxsize */ 1455f10a77bbSDavid C Somayajulu 1, /* nsegments */ 1456f10a77bbSDavid C Somayajulu MJUM9BYTES, /* maxsegsize */ 1457f10a77bbSDavid C Somayajulu BUS_DMA_ALLOCNOW, /* flags */ 1458f10a77bbSDavid C Somayajulu NULL, /* lockfunc */ 1459f10a77bbSDavid C Somayajulu NULL, /* lockfuncarg */ 1460f10a77bbSDavid C Somayajulu &ha->rx_tag)) { 1461f10a77bbSDavid C Somayajulu 1462f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, "%s: rx_tag alloc failed\n", 1463f10a77bbSDavid C Somayajulu __func__); 1464f10a77bbSDavid C Somayajulu 1465f10a77bbSDavid C Somayajulu return (ENOMEM); 1466f10a77bbSDavid C Somayajulu } 1467f10a77bbSDavid C Somayajulu 1468f10a77bbSDavid C Somayajulu bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS)); 1469f10a77bbSDavid C Somayajulu 1470f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_sds_rings; i++) { 1471f10a77bbSDavid C Somayajulu ha->hw.sds[i].sdsr_next = 0; 1472f10a77bbSDavid C Somayajulu ha->hw.sds[i].rxb_free = NULL; 1473f10a77bbSDavid C Somayajulu ha->hw.sds[i].rx_free = 0; 1474f10a77bbSDavid C Somayajulu } 1475f10a77bbSDavid C Somayajulu 1476f10a77bbSDavid C Somayajulu ret = qla_alloc_rcv_std(ha); 1477f10a77bbSDavid C Somayajulu 1478f10a77bbSDavid C Somayajulu return (ret); 1479f10a77bbSDavid C Somayajulu } 1480f10a77bbSDavid C Somayajulu 1481f10a77bbSDavid C Somayajulu static void 1482f10a77bbSDavid C Somayajulu qla_free_rcv_bufs(qla_host_t *ha) 1483f10a77bbSDavid C Somayajulu { 1484f10a77bbSDavid C Somayajulu int i; 1485f10a77bbSDavid C Somayajulu 1486f10a77bbSDavid C Somayajulu qla_free_rcv_std(ha); 1487f10a77bbSDavid C Somayajulu 1488f10a77bbSDavid C Somayajulu if (ha->rx_tag != NULL) { 1489f10a77bbSDavid C Somayajulu bus_dma_tag_destroy(ha->rx_tag); 1490f10a77bbSDavid C Somayajulu ha->rx_tag = NULL; 1491f10a77bbSDavid C Somayajulu } 1492f10a77bbSDavid C Somayajulu 1493f10a77bbSDavid C Somayajulu bzero((void *)ha->rx_ring, (sizeof(qla_rx_ring_t) * MAX_RDS_RINGS)); 1494f10a77bbSDavid C Somayajulu 1495f10a77bbSDavid C Somayajulu for (i = 0; i < ha->hw.num_sds_rings; i++) { 1496f10a77bbSDavid C Somayajulu ha->hw.sds[i].sdsr_next = 0; 1497f10a77bbSDavid C Somayajulu ha->hw.sds[i].rxb_free = NULL; 1498f10a77bbSDavid C Somayajulu ha->hw.sds[i].rx_free = 0; 1499f10a77bbSDavid C Somayajulu } 1500f10a77bbSDavid C Somayajulu 1501f10a77bbSDavid C Somayajulu return; 1502f10a77bbSDavid C Somayajulu } 1503f10a77bbSDavid C Somayajulu 1504f10a77bbSDavid C Somayajulu int 1505f10a77bbSDavid C Somayajulu ql_get_mbuf(qla_host_t *ha, qla_rx_buf_t *rxb, struct mbuf *nmp) 1506f10a77bbSDavid C Somayajulu { 1507f10a77bbSDavid C Somayajulu register struct mbuf *mp = nmp; 1508f10a77bbSDavid C Somayajulu struct ifnet *ifp; 1509f10a77bbSDavid C Somayajulu int ret = 0; 1510f10a77bbSDavid C Somayajulu uint32_t offset; 1511f10a77bbSDavid C Somayajulu bus_dma_segment_t segs[1]; 1512f10a77bbSDavid C Somayajulu int nsegs; 1513f10a77bbSDavid C Somayajulu 1514f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: enter\n", __func__)); 1515f10a77bbSDavid C Somayajulu 1516f10a77bbSDavid C Somayajulu ifp = ha->ifp; 1517f10a77bbSDavid C Somayajulu 1518f10a77bbSDavid C Somayajulu if (mp == NULL) { 1519f10a77bbSDavid C Somayajulu 1520f10a77bbSDavid C Somayajulu mp = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR); 1521f10a77bbSDavid C Somayajulu 1522f10a77bbSDavid C Somayajulu if (mp == NULL) { 1523f10a77bbSDavid C Somayajulu ha->err_m_getcl++; 1524f10a77bbSDavid C Somayajulu ret = ENOBUFS; 1525f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1526f10a77bbSDavid C Somayajulu "%s: m_getcl failed\n", __func__); 1527f10a77bbSDavid C Somayajulu goto exit_ql_get_mbuf; 1528f10a77bbSDavid C Somayajulu } 1529f10a77bbSDavid C Somayajulu mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1530f10a77bbSDavid C Somayajulu } else { 1531f10a77bbSDavid C Somayajulu mp->m_len = mp->m_pkthdr.len = MCLBYTES; 1532f10a77bbSDavid C Somayajulu mp->m_data = mp->m_ext.ext_buf; 1533f10a77bbSDavid C Somayajulu mp->m_next = NULL; 1534f10a77bbSDavid C Somayajulu } 1535f10a77bbSDavid C Somayajulu 1536f10a77bbSDavid C Somayajulu offset = (uint32_t)((unsigned long long)mp->m_data & 0x7ULL); 1537f10a77bbSDavid C Somayajulu if (offset) { 1538f10a77bbSDavid C Somayajulu offset = 8 - offset; 1539f10a77bbSDavid C Somayajulu m_adj(mp, offset); 1540f10a77bbSDavid C Somayajulu } 1541f10a77bbSDavid C Somayajulu 1542f10a77bbSDavid C Somayajulu /* 1543f10a77bbSDavid C Somayajulu * Using memory from the mbuf cluster pool, invoke the bus_dma 1544f10a77bbSDavid C Somayajulu * machinery to arrange the memory mapping. 1545f10a77bbSDavid C Somayajulu */ 1546f10a77bbSDavid C Somayajulu ret = bus_dmamap_load_mbuf_sg(ha->rx_tag, rxb->map, 1547f10a77bbSDavid C Somayajulu mp, segs, &nsegs, BUS_DMA_NOWAIT); 1548f10a77bbSDavid C Somayajulu rxb->paddr = segs[0].ds_addr; 1549f10a77bbSDavid C Somayajulu 1550f10a77bbSDavid C Somayajulu if (ret || !rxb->paddr || (nsegs != 1)) { 1551f10a77bbSDavid C Somayajulu m_free(mp); 1552f10a77bbSDavid C Somayajulu rxb->m_head = NULL; 1553f10a77bbSDavid C Somayajulu device_printf(ha->pci_dev, 1554f10a77bbSDavid C Somayajulu "%s: bus_dmamap_load failed[%d, 0x%016llx, %d]\n", 1555f10a77bbSDavid C Somayajulu __func__, ret, (long long unsigned int)rxb->paddr, 1556f10a77bbSDavid C Somayajulu nsegs); 1557f10a77bbSDavid C Somayajulu ret = -1; 1558f10a77bbSDavid C Somayajulu goto exit_ql_get_mbuf; 1559f10a77bbSDavid C Somayajulu } 1560f10a77bbSDavid C Somayajulu rxb->m_head = mp; 1561f10a77bbSDavid C Somayajulu bus_dmamap_sync(ha->rx_tag, rxb->map, BUS_DMASYNC_PREREAD); 1562f10a77bbSDavid C Somayajulu 1563f10a77bbSDavid C Somayajulu exit_ql_get_mbuf: 1564f10a77bbSDavid C Somayajulu QL_DPRINT2(ha, (ha->pci_dev, "%s: exit ret = 0x%08x\n", __func__, ret)); 1565f10a77bbSDavid C Somayajulu return (ret); 1566f10a77bbSDavid C Somayajulu } 1567f10a77bbSDavid C Somayajulu 1568f10a77bbSDavid C Somayajulu static void 1569f10a77bbSDavid C Somayajulu qla_tx_done(void *context, int pending) 1570f10a77bbSDavid C Somayajulu { 1571f10a77bbSDavid C Somayajulu qla_host_t *ha = context; 1572f10a77bbSDavid C Somayajulu struct ifnet *ifp; 1573f10a77bbSDavid C Somayajulu 1574f10a77bbSDavid C Somayajulu ifp = ha->ifp; 1575f10a77bbSDavid C Somayajulu 1576f10a77bbSDavid C Somayajulu if (!ifp) 1577f10a77bbSDavid C Somayajulu return; 1578f10a77bbSDavid C Somayajulu 1579f10a77bbSDavid C Somayajulu if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 1580f10a77bbSDavid C Somayajulu QL_DPRINT8(ha, (ha->pci_dev, "%s: !IFF_DRV_RUNNING\n", __func__)); 1581f10a77bbSDavid C Somayajulu return; 1582f10a77bbSDavid C Somayajulu } 1583f10a77bbSDavid C Somayajulu ql_hw_tx_done(ha); 1584f10a77bbSDavid C Somayajulu 1585f10a77bbSDavid C Somayajulu qla_start(ha->ifp); 1586f10a77bbSDavid C Somayajulu } 1587f10a77bbSDavid C Somayajulu 1588f10a77bbSDavid C Somayajulu static void 1589f10a77bbSDavid C Somayajulu qla_get_peer(qla_host_t *ha) 1590f10a77bbSDavid C Somayajulu { 1591f10a77bbSDavid C Somayajulu device_t *peers; 1592f10a77bbSDavid C Somayajulu int count, i, slot; 1593f10a77bbSDavid C Somayajulu int my_slot = pci_get_slot(ha->pci_dev); 1594f10a77bbSDavid C Somayajulu 1595f10a77bbSDavid C Somayajulu if (device_get_children(device_get_parent(ha->pci_dev), &peers, &count)) 1596f10a77bbSDavid C Somayajulu return; 1597f10a77bbSDavid C Somayajulu 1598f10a77bbSDavid C Somayajulu for (i = 0; i < count; i++) { 1599f10a77bbSDavid C Somayajulu slot = pci_get_slot(peers[i]); 1600f10a77bbSDavid C Somayajulu 1601f10a77bbSDavid C Somayajulu if ((slot >= 0) && (slot == my_slot) && 1602f10a77bbSDavid C Somayajulu (pci_get_device(peers[i]) == 1603f10a77bbSDavid C Somayajulu pci_get_device(ha->pci_dev))) { 1604f10a77bbSDavid C Somayajulu if (ha->pci_dev != peers[i]) 1605f10a77bbSDavid C Somayajulu ha->peer_dev = peers[i]; 1606f10a77bbSDavid C Somayajulu } 1607f10a77bbSDavid C Somayajulu } 1608f10a77bbSDavid C Somayajulu } 1609f10a77bbSDavid C Somayajulu 1610f10a77bbSDavid C Somayajulu static void 1611f10a77bbSDavid C Somayajulu qla_send_msg_to_peer(qla_host_t *ha, uint32_t msg_to_peer) 1612f10a77bbSDavid C Somayajulu { 1613f10a77bbSDavid C Somayajulu qla_host_t *ha_peer; 1614f10a77bbSDavid C Somayajulu 1615f10a77bbSDavid C Somayajulu if (ha->peer_dev) { 1616f10a77bbSDavid C Somayajulu if ((ha_peer = device_get_softc(ha->peer_dev)) != NULL) { 1617f10a77bbSDavid C Somayajulu 1618f10a77bbSDavid C Somayajulu ha_peer->msg_from_peer = msg_to_peer; 1619f10a77bbSDavid C Somayajulu } 1620f10a77bbSDavid C Somayajulu } 1621f10a77bbSDavid C Somayajulu } 1622f10a77bbSDavid C Somayajulu 1623f10a77bbSDavid C Somayajulu static void 1624f10a77bbSDavid C Somayajulu qla_error_recovery(void *context, int pending) 1625f10a77bbSDavid C Somayajulu { 1626f10a77bbSDavid C Somayajulu qla_host_t *ha = context; 1627f10a77bbSDavid C Somayajulu uint32_t msecs_100 = 100; 1628f10a77bbSDavid C Somayajulu struct ifnet *ifp = ha->ifp; 1629f10a77bbSDavid C Somayajulu 1630f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 1631f10a77bbSDavid C Somayajulu 1632f10a77bbSDavid C Somayajulu ha->flags.stop_rcv = 1; 1633f10a77bbSDavid C Somayajulu 1634f10a77bbSDavid C Somayajulu ql_hw_stop_rcv(ha); 1635f10a77bbSDavid C Somayajulu 1636f10a77bbSDavid C Somayajulu ifp->if_drv_flags &= ~(IFF_DRV_OACTIVE | IFF_DRV_RUNNING); 1637f10a77bbSDavid C Somayajulu 1638f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 1639f10a77bbSDavid C Somayajulu 1640f10a77bbSDavid C Somayajulu if ((ha->pci_func & 0x1) == 0) { 1641f10a77bbSDavid C Somayajulu 1642bcafe874SDavid C Somayajulu if (!ha->msg_from_peer) { 1643f10a77bbSDavid C Somayajulu qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET); 1644f10a77bbSDavid C Somayajulu 1645bcafe874SDavid C Somayajulu while ((ha->msg_from_peer != QL_PEER_MSG_ACK) && 1646bcafe874SDavid C Somayajulu msecs_100--) 1647f10a77bbSDavid C Somayajulu qla_mdelay(__func__, 100); 1648bcafe874SDavid C Somayajulu } 1649f10a77bbSDavid C Somayajulu 1650f10a77bbSDavid C Somayajulu ha->msg_from_peer = 0; 1651f10a77bbSDavid C Somayajulu 165267ffef6bSDavid C Somayajulu ql_minidump(ha); 165367ffef6bSDavid C Somayajulu 1654f10a77bbSDavid C Somayajulu (void) ql_init_hw(ha); 1655f10a77bbSDavid C Somayajulu qla_free_xmt_bufs(ha); 1656f10a77bbSDavid C Somayajulu qla_free_rcv_bufs(ha); 1657f10a77bbSDavid C Somayajulu 1658f10a77bbSDavid C Somayajulu qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK); 1659f10a77bbSDavid C Somayajulu 1660f10a77bbSDavid C Somayajulu } else { 1661f10a77bbSDavid C Somayajulu if (ha->msg_from_peer == QL_PEER_MSG_RESET) { 1662f10a77bbSDavid C Somayajulu 1663f10a77bbSDavid C Somayajulu ha->msg_from_peer = 0; 1664f10a77bbSDavid C Somayajulu 1665f10a77bbSDavid C Somayajulu qla_send_msg_to_peer(ha, QL_PEER_MSG_ACK); 1666f10a77bbSDavid C Somayajulu } else { 1667f10a77bbSDavid C Somayajulu qla_send_msg_to_peer(ha, QL_PEER_MSG_RESET); 1668f10a77bbSDavid C Somayajulu } 1669f10a77bbSDavid C Somayajulu 1670f10a77bbSDavid C Somayajulu while ((ha->msg_from_peer != QL_PEER_MSG_ACK) && msecs_100--) 1671f10a77bbSDavid C Somayajulu qla_mdelay(__func__, 100); 1672f10a77bbSDavid C Somayajulu ha->msg_from_peer = 0; 1673f10a77bbSDavid C Somayajulu 1674f10a77bbSDavid C Somayajulu (void) ql_init_hw(ha); 1675f10a77bbSDavid C Somayajulu qla_free_xmt_bufs(ha); 1676f10a77bbSDavid C Somayajulu qla_free_rcv_bufs(ha); 1677f10a77bbSDavid C Somayajulu } 1678f10a77bbSDavid C Somayajulu (void)QLA_LOCK(ha, __func__, 0); 1679f10a77bbSDavid C Somayajulu 1680f10a77bbSDavid C Somayajulu if (qla_alloc_xmt_bufs(ha) != 0) { 1681f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 1682f10a77bbSDavid C Somayajulu return; 1683f10a77bbSDavid C Somayajulu } 1684f10a77bbSDavid C Somayajulu 1685f10a77bbSDavid C Somayajulu if (qla_alloc_rcv_bufs(ha) != 0) { 1686f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 1687f10a77bbSDavid C Somayajulu return; 1688f10a77bbSDavid C Somayajulu } 1689f10a77bbSDavid C Somayajulu 1690f10a77bbSDavid C Somayajulu ha->flags.stop_rcv = 0; 1691f10a77bbSDavid C Somayajulu if (ql_init_hw_if(ha) == 0) { 1692f10a77bbSDavid C Somayajulu ifp = ha->ifp; 1693f10a77bbSDavid C Somayajulu ifp->if_drv_flags |= IFF_DRV_RUNNING; 1694f10a77bbSDavid C Somayajulu ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 1695f10a77bbSDavid C Somayajulu ha->flags.qla_watchdog_pause = 0; 1696f10a77bbSDavid C Somayajulu } 1697f10a77bbSDavid C Somayajulu 1698f10a77bbSDavid C Somayajulu QLA_UNLOCK(ha, __func__); 1699f10a77bbSDavid C Somayajulu } 1700f10a77bbSDavid C Somayajulu 1701