1331722Seadler/* 2284741Sdavidcs * Copyright (c) 2013-2016 Qlogic Corporation 3250661Sdavidcs * All rights reserved. 4250661Sdavidcs * 5250661Sdavidcs * Redistribution and use in source and binary forms, with or without 6250661Sdavidcs * modification, are permitted provided that the following conditions 7250661Sdavidcs * are met: 8250661Sdavidcs * 9250661Sdavidcs * 1. Redistributions of source code must retain the above copyright 10250661Sdavidcs * notice, this list of conditions and the following disclaimer. 11250661Sdavidcs * 2. Redistributions in binary form must reproduce the above copyright 12250661Sdavidcs * notice, this list of conditions and the following disclaimer in the 13250661Sdavidcs * documentation and/or other materials provided with the distribution. 14250661Sdavidcs * 15250661Sdavidcs * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16250661Sdavidcs * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17250661Sdavidcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18250661Sdavidcs * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 19250661Sdavidcs * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 20250661Sdavidcs * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 21250661Sdavidcs * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22250661Sdavidcs * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 23250661Sdavidcs * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 24250661Sdavidcs * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 25250661Sdavidcs * POSSIBILITY OF SUCH DAMAGE. 26250661Sdavidcs */ 27250661Sdavidcs 28250661Sdavidcs/* 29250661Sdavidcs * File: ql_hw.c 30250661Sdavidcs * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656. 31298955Spfg * Content: Contains Hardware dependent functions 32250661Sdavidcs */ 33250661Sdavidcs 34250661Sdavidcs#include <sys/cdefs.h> 35250661Sdavidcs__FBSDID("$FreeBSD: stable/11/sys/dev/qlxgbe/ql_hw.c 332052 2018-04-04 23:53:29Z davidcs $"); 36250661Sdavidcs 37250661Sdavidcs#include "ql_os.h" 38250661Sdavidcs#include "ql_hw.h" 39250661Sdavidcs#include "ql_def.h" 40250661Sdavidcs#include "ql_inline.h" 41250661Sdavidcs#include "ql_ver.h" 42250661Sdavidcs#include "ql_glbl.h" 43250661Sdavidcs#include "ql_dbg.h" 44305487Sdavidcs#include "ql_minidump.h" 45250661Sdavidcs 46250661Sdavidcs/* 47250661Sdavidcs * Static Functions 48250661Sdavidcs */ 49250661Sdavidcs 50250661Sdavidcsstatic void qla_del_rcv_cntxt(qla_host_t *ha); 51250661Sdavidcsstatic int qla_init_rcv_cntxt(qla_host_t *ha); 52330555Sdavidcsstatic int qla_del_xmt_cntxt(qla_host_t *ha); 53250661Sdavidcsstatic int qla_init_xmt_cntxt(qla_host_t *ha); 54250661Sdavidcsstatic int qla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox, 55250661Sdavidcs uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause); 56284741Sdavidcsstatic int qla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx, 57284741Sdavidcs uint32_t num_intrs, uint32_t create); 58250661Sdavidcsstatic int qla_config_rss(qla_host_t *ha, uint16_t cntxt_id); 59250661Sdavidcsstatic int qla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, 60284741Sdavidcs int tenable, int rcv); 61250661Sdavidcsstatic int qla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode); 62250661Sdavidcsstatic int qla_link_event_req(qla_host_t *ha, uint16_t cntxt_id); 63250661Sdavidcs 64250661Sdavidcsstatic int qla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, 65250661Sdavidcs uint8_t *hdr); 66250661Sdavidcsstatic int qla_hw_add_all_mcast(qla_host_t *ha); 67284741Sdavidcsstatic int qla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds); 68250661Sdavidcs 69284741Sdavidcsstatic int qla_init_nic_func(qla_host_t *ha); 70284741Sdavidcsstatic int qla_stop_nic_func(qla_host_t *ha); 71284741Sdavidcsstatic int qla_query_fw_dcbx_caps(qla_host_t *ha); 72284741Sdavidcsstatic int qla_set_port_config(qla_host_t *ha, uint32_t cfg_bits); 73284741Sdavidcsstatic int qla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits); 74305488Sdavidcsstatic int qla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode); 75305488Sdavidcsstatic int qla_get_cam_search_mode(qla_host_t *ha); 76284741Sdavidcs 77305487Sdavidcsstatic void ql_minidump_free(qla_host_t *ha); 78250661Sdavidcs 79250661Sdavidcs#ifdef QL_DBG 80250661Sdavidcs 81250661Sdavidcsstatic void 82250661Sdavidcsqla_stop_pegs(qla_host_t *ha) 83250661Sdavidcs{ 84250661Sdavidcs uint32_t val = 1; 85250661Sdavidcs 86250661Sdavidcs ql_rdwr_indreg32(ha, Q8_CRB_PEG_0, &val, 0); 87250661Sdavidcs ql_rdwr_indreg32(ha, Q8_CRB_PEG_1, &val, 0); 88250661Sdavidcs ql_rdwr_indreg32(ha, Q8_CRB_PEG_2, &val, 0); 89250661Sdavidcs ql_rdwr_indreg32(ha, Q8_CRB_PEG_3, &val, 0); 90250661Sdavidcs ql_rdwr_indreg32(ha, Q8_CRB_PEG_4, &val, 0); 91250661Sdavidcs device_printf(ha->pci_dev, "%s PEGS HALTED!!!!!\n", __func__); 92250661Sdavidcs} 93250661Sdavidcs 94250661Sdavidcsstatic int 95250661Sdavidcsqla_sysctl_stop_pegs(SYSCTL_HANDLER_ARGS) 96250661Sdavidcs{ 97250661Sdavidcs int err, ret = 0; 98250661Sdavidcs qla_host_t *ha; 99250661Sdavidcs 100250661Sdavidcs err = sysctl_handle_int(oidp, &ret, 0, req); 101250661Sdavidcs 102250661Sdavidcs 103250661Sdavidcs if (err || !req->newptr) 104250661Sdavidcs return (err); 105250661Sdavidcs 106250661Sdavidcs if (ret == 1) { 107250661Sdavidcs ha = (qla_host_t *)arg1; 108322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) { 109322972Sdavidcs qla_stop_pegs(ha); 110322972Sdavidcs QLA_UNLOCK(ha, __func__); 111322972Sdavidcs } 112250661Sdavidcs } 113250661Sdavidcs 114250661Sdavidcs return err; 115250661Sdavidcs} 116250661Sdavidcs#endif /* #ifdef QL_DBG */ 117250661Sdavidcs 118284741Sdavidcsstatic int 119284741Sdavidcsqla_validate_set_port_cfg_bit(uint32_t bits) 120284741Sdavidcs{ 121284741Sdavidcs if ((bits & 0xF) > 1) 122284741Sdavidcs return (-1); 123284741Sdavidcs 124284741Sdavidcs if (((bits >> 4) & 0xF) > 2) 125284741Sdavidcs return (-1); 126284741Sdavidcs 127284741Sdavidcs if (((bits >> 8) & 0xF) > 2) 128284741Sdavidcs return (-1); 129284741Sdavidcs 130284741Sdavidcs return (0); 131284741Sdavidcs} 132284741Sdavidcs 133284741Sdavidcsstatic int 134284741Sdavidcsqla_sysctl_port_cfg(SYSCTL_HANDLER_ARGS) 135284741Sdavidcs{ 136284741Sdavidcs int err, ret = 0; 137284741Sdavidcs qla_host_t *ha; 138284741Sdavidcs uint32_t cfg_bits; 139284741Sdavidcs 140284741Sdavidcs err = sysctl_handle_int(oidp, &ret, 0, req); 141284741Sdavidcs 142284741Sdavidcs if (err || !req->newptr) 143284741Sdavidcs return (err); 144284741Sdavidcs 145322972Sdavidcs ha = (qla_host_t *)arg1; 146322972Sdavidcs 147284741Sdavidcs if ((qla_validate_set_port_cfg_bit((uint32_t)ret) == 0)) { 148284741Sdavidcs 149284741Sdavidcs err = qla_get_port_config(ha, &cfg_bits); 150284741Sdavidcs 151284741Sdavidcs if (err) 152284741Sdavidcs goto qla_sysctl_set_port_cfg_exit; 153284741Sdavidcs 154284741Sdavidcs if (ret & 0x1) { 155284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_DCBX_ENABLE; 156284741Sdavidcs } else { 157284741Sdavidcs cfg_bits &= ~Q8_PORT_CFG_BITS_DCBX_ENABLE; 158284741Sdavidcs } 159284741Sdavidcs 160284741Sdavidcs ret = ret >> 4; 161284741Sdavidcs cfg_bits &= ~Q8_PORT_CFG_BITS_PAUSE_CFG_MASK; 162284741Sdavidcs 163284741Sdavidcs if ((ret & 0xF) == 0) { 164284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_DISABLED; 165284741Sdavidcs } else if ((ret & 0xF) == 1){ 166284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_STD; 167284741Sdavidcs } else { 168284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_PAUSE_PPM; 169284741Sdavidcs } 170284741Sdavidcs 171284741Sdavidcs ret = ret >> 4; 172284741Sdavidcs cfg_bits &= ~Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK; 173284741Sdavidcs 174284741Sdavidcs if (ret == 0) { 175284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT_RCV; 176284741Sdavidcs } else if (ret == 1){ 177284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_XMT; 178284741Sdavidcs } else { 179284741Sdavidcs cfg_bits |= Q8_PORT_CFG_BITS_STDPAUSE_RCV; 180284741Sdavidcs } 181284741Sdavidcs 182322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) { 183322972Sdavidcs err = qla_set_port_config(ha, cfg_bits); 184322972Sdavidcs QLA_UNLOCK(ha, __func__); 185322972Sdavidcs } else { 186322972Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 187322972Sdavidcs } 188284741Sdavidcs } else { 189322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) { 190322972Sdavidcs err = qla_get_port_config(ha, &cfg_bits); 191322972Sdavidcs QLA_UNLOCK(ha, __func__); 192322972Sdavidcs } else { 193322972Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 194322972Sdavidcs } 195284741Sdavidcs } 196284741Sdavidcs 197284741Sdavidcsqla_sysctl_set_port_cfg_exit: 198284741Sdavidcs return err; 199284741Sdavidcs} 200284741Sdavidcs 201305488Sdavidcsstatic int 202305488Sdavidcsqla_sysctl_set_cam_search_mode(SYSCTL_HANDLER_ARGS) 203305488Sdavidcs{ 204305488Sdavidcs int err, ret = 0; 205305488Sdavidcs qla_host_t *ha; 206305488Sdavidcs 207305488Sdavidcs err = sysctl_handle_int(oidp, &ret, 0, req); 208305488Sdavidcs 209305488Sdavidcs if (err || !req->newptr) 210305488Sdavidcs return (err); 211305488Sdavidcs 212305488Sdavidcs ha = (qla_host_t *)arg1; 213305488Sdavidcs 214305488Sdavidcs if ((ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_INTERNAL) || 215305488Sdavidcs (ret == Q8_HW_CONFIG_CAM_SEARCH_MODE_AUTO)) { 216322972Sdavidcs 217322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) { 218322972Sdavidcs err = qla_set_cam_search_mode(ha, (uint32_t)ret); 219322972Sdavidcs QLA_UNLOCK(ha, __func__); 220322972Sdavidcs } else { 221322972Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 222322972Sdavidcs } 223322972Sdavidcs 224305488Sdavidcs } else { 225305488Sdavidcs device_printf(ha->pci_dev, "%s: ret = %d\n", __func__, ret); 226305488Sdavidcs } 227305488Sdavidcs 228305488Sdavidcs return (err); 229305488Sdavidcs} 230305488Sdavidcs 231305488Sdavidcsstatic int 232305488Sdavidcsqla_sysctl_get_cam_search_mode(SYSCTL_HANDLER_ARGS) 233305488Sdavidcs{ 234305488Sdavidcs int err, ret = 0; 235305488Sdavidcs qla_host_t *ha; 236305488Sdavidcs 237305488Sdavidcs err = sysctl_handle_int(oidp, &ret, 0, req); 238305488Sdavidcs 239305488Sdavidcs if (err || !req->newptr) 240305488Sdavidcs return (err); 241305488Sdavidcs 242305488Sdavidcs ha = (qla_host_t *)arg1; 243322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) == 0) { 244322972Sdavidcs err = qla_get_cam_search_mode(ha); 245322972Sdavidcs QLA_UNLOCK(ha, __func__); 246322972Sdavidcs } else { 247322972Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 248322972Sdavidcs } 249305488Sdavidcs 250305488Sdavidcs return (err); 251305488Sdavidcs} 252305488Sdavidcs 253322972Sdavidcsstatic void 254322972Sdavidcsqlnx_add_hw_mac_stats_sysctls(qla_host_t *ha) 255322972Sdavidcs{ 256322972Sdavidcs struct sysctl_ctx_list *ctx; 257322972Sdavidcs struct sysctl_oid_list *children; 258322972Sdavidcs struct sysctl_oid *ctx_oid; 259305488Sdavidcs 260322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 261322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 262322972Sdavidcs 263322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_mac", 264322972Sdavidcs CTLFLAG_RD, NULL, "stats_hw_mac"); 265322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 266322972Sdavidcs 267322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 268322972Sdavidcs OID_AUTO, "xmt_frames", 269322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_frames, 270322972Sdavidcs "xmt_frames"); 271322972Sdavidcs 272322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 273322972Sdavidcs OID_AUTO, "xmt_bytes", 274322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_bytes, 275322972Sdavidcs "xmt_frames"); 276322972Sdavidcs 277322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 278322972Sdavidcs OID_AUTO, "xmt_mcast_pkts", 279322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_mcast_pkts, 280322972Sdavidcs "xmt_mcast_pkts"); 281322972Sdavidcs 282322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 283322972Sdavidcs OID_AUTO, "xmt_bcast_pkts", 284322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_bcast_pkts, 285322972Sdavidcs "xmt_bcast_pkts"); 286322972Sdavidcs 287322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 288322972Sdavidcs OID_AUTO, "xmt_pause_frames", 289322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pause_frames, 290322972Sdavidcs "xmt_pause_frames"); 291322972Sdavidcs 292322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 293322972Sdavidcs OID_AUTO, "xmt_cntrl_pkts", 294322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_cntrl_pkts, 295322972Sdavidcs "xmt_cntrl_pkts"); 296322972Sdavidcs 297322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 298322972Sdavidcs OID_AUTO, "xmt_pkt_lt_64bytes", 299322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_64bytes, 300322972Sdavidcs "xmt_pkt_lt_64bytes"); 301322972Sdavidcs 302322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 303322972Sdavidcs OID_AUTO, "xmt_pkt_lt_127bytes", 304322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_127bytes, 305322972Sdavidcs "xmt_pkt_lt_127bytes"); 306322972Sdavidcs 307322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 308322972Sdavidcs OID_AUTO, "xmt_pkt_lt_255bytes", 309322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_255bytes, 310322972Sdavidcs "xmt_pkt_lt_255bytes"); 311322972Sdavidcs 312322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 313322972Sdavidcs OID_AUTO, "xmt_pkt_lt_511bytes", 314322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_511bytes, 315322972Sdavidcs "xmt_pkt_lt_511bytes"); 316322972Sdavidcs 317322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 318322972Sdavidcs OID_AUTO, "xmt_pkt_lt_1023bytes", 319322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1023bytes, 320322972Sdavidcs "xmt_pkt_lt_1023bytes"); 321322972Sdavidcs 322322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 323322972Sdavidcs OID_AUTO, "xmt_pkt_lt_1518bytes", 324322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_lt_1518bytes, 325322972Sdavidcs "xmt_pkt_lt_1518bytes"); 326322972Sdavidcs 327322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 328322972Sdavidcs OID_AUTO, "xmt_pkt_gt_1518bytes", 329322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.xmt_pkt_gt_1518bytes, 330322972Sdavidcs "xmt_pkt_gt_1518bytes"); 331322972Sdavidcs 332322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 333322972Sdavidcs OID_AUTO, "rcv_frames", 334322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_frames, 335322972Sdavidcs "rcv_frames"); 336322972Sdavidcs 337322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 338322972Sdavidcs OID_AUTO, "rcv_bytes", 339322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_bytes, 340322972Sdavidcs "rcv_bytes"); 341322972Sdavidcs 342322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 343322972Sdavidcs OID_AUTO, "rcv_mcast_pkts", 344322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_mcast_pkts, 345322972Sdavidcs "rcv_mcast_pkts"); 346322972Sdavidcs 347322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 348322972Sdavidcs OID_AUTO, "rcv_bcast_pkts", 349322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_bcast_pkts, 350322972Sdavidcs "rcv_bcast_pkts"); 351322972Sdavidcs 352322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 353322972Sdavidcs OID_AUTO, "rcv_pause_frames", 354322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pause_frames, 355322972Sdavidcs "rcv_pause_frames"); 356322972Sdavidcs 357322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 358322972Sdavidcs OID_AUTO, "rcv_cntrl_pkts", 359322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_cntrl_pkts, 360322972Sdavidcs "rcv_cntrl_pkts"); 361322972Sdavidcs 362322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 363322972Sdavidcs OID_AUTO, "rcv_pkt_lt_64bytes", 364322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_64bytes, 365322972Sdavidcs "rcv_pkt_lt_64bytes"); 366322972Sdavidcs 367322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 368322972Sdavidcs OID_AUTO, "rcv_pkt_lt_127bytes", 369322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_127bytes, 370322972Sdavidcs "rcv_pkt_lt_127bytes"); 371322972Sdavidcs 372322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 373322972Sdavidcs OID_AUTO, "rcv_pkt_lt_255bytes", 374322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_255bytes, 375322972Sdavidcs "rcv_pkt_lt_255bytes"); 376322972Sdavidcs 377322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 378322972Sdavidcs OID_AUTO, "rcv_pkt_lt_511bytes", 379322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_511bytes, 380322972Sdavidcs "rcv_pkt_lt_511bytes"); 381322972Sdavidcs 382322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 383322972Sdavidcs OID_AUTO, "rcv_pkt_lt_1023bytes", 384322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1023bytes, 385322972Sdavidcs "rcv_pkt_lt_1023bytes"); 386322972Sdavidcs 387322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 388322972Sdavidcs OID_AUTO, "rcv_pkt_lt_1518bytes", 389322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_lt_1518bytes, 390322972Sdavidcs "rcv_pkt_lt_1518bytes"); 391322972Sdavidcs 392322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 393322972Sdavidcs OID_AUTO, "rcv_pkt_gt_1518bytes", 394322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_pkt_gt_1518bytes, 395322972Sdavidcs "rcv_pkt_gt_1518bytes"); 396322972Sdavidcs 397322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 398322972Sdavidcs OID_AUTO, "rcv_len_error", 399322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_len_error, 400322972Sdavidcs "rcv_len_error"); 401322972Sdavidcs 402322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 403322972Sdavidcs OID_AUTO, "rcv_len_small", 404322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_len_small, 405322972Sdavidcs "rcv_len_small"); 406322972Sdavidcs 407322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 408322972Sdavidcs OID_AUTO, "rcv_len_large", 409322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_len_large, 410322972Sdavidcs "rcv_len_large"); 411322972Sdavidcs 412322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 413322972Sdavidcs OID_AUTO, "rcv_jabber", 414322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_jabber, 415322972Sdavidcs "rcv_jabber"); 416322972Sdavidcs 417322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 418322972Sdavidcs OID_AUTO, "rcv_dropped", 419322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.rcv_dropped, 420322972Sdavidcs "rcv_dropped"); 421322972Sdavidcs 422322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 423322972Sdavidcs OID_AUTO, "fcs_error", 424322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.fcs_error, 425322972Sdavidcs "fcs_error"); 426322972Sdavidcs 427322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 428322972Sdavidcs OID_AUTO, "align_error", 429322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.align_error, 430322972Sdavidcs "align_error"); 431322972Sdavidcs 432322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 433322972Sdavidcs OID_AUTO, "eswitched_frames", 434322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_frames, 435322972Sdavidcs "eswitched_frames"); 436322972Sdavidcs 437322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 438322972Sdavidcs OID_AUTO, "eswitched_bytes", 439322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_bytes, 440322972Sdavidcs "eswitched_bytes"); 441322972Sdavidcs 442322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 443322972Sdavidcs OID_AUTO, "eswitched_mcast_frames", 444322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_mcast_frames, 445322972Sdavidcs "eswitched_mcast_frames"); 446322972Sdavidcs 447322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 448322972Sdavidcs OID_AUTO, "eswitched_bcast_frames", 449322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_bcast_frames, 450322972Sdavidcs "eswitched_bcast_frames"); 451322972Sdavidcs 452322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 453322972Sdavidcs OID_AUTO, "eswitched_ucast_frames", 454322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_ucast_frames, 455322972Sdavidcs "eswitched_ucast_frames"); 456322972Sdavidcs 457322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 458322972Sdavidcs OID_AUTO, "eswitched_err_free_frames", 459322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_frames, 460322972Sdavidcs "eswitched_err_free_frames"); 461322972Sdavidcs 462322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 463322972Sdavidcs OID_AUTO, "eswitched_err_free_bytes", 464322972Sdavidcs CTLFLAG_RD, &ha->hw.mac.eswitched_err_free_bytes, 465322972Sdavidcs "eswitched_err_free_bytes"); 466322972Sdavidcs 467322972Sdavidcs return; 468322972Sdavidcs} 469322972Sdavidcs 470322972Sdavidcsstatic void 471322972Sdavidcsqlnx_add_hw_rcv_stats_sysctls(qla_host_t *ha) 472322972Sdavidcs{ 473322972Sdavidcs struct sysctl_ctx_list *ctx; 474322972Sdavidcs struct sysctl_oid_list *children; 475322972Sdavidcs struct sysctl_oid *ctx_oid; 476322972Sdavidcs 477322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 478322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 479322972Sdavidcs 480322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_rcv", 481322972Sdavidcs CTLFLAG_RD, NULL, "stats_hw_rcv"); 482322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 483322972Sdavidcs 484322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 485322972Sdavidcs OID_AUTO, "total_bytes", 486322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.total_bytes, 487322972Sdavidcs "total_bytes"); 488322972Sdavidcs 489322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 490322972Sdavidcs OID_AUTO, "total_pkts", 491322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.total_pkts, 492322972Sdavidcs "total_pkts"); 493322972Sdavidcs 494322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 495322972Sdavidcs OID_AUTO, "lro_pkt_count", 496322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.lro_pkt_count, 497322972Sdavidcs "lro_pkt_count"); 498322972Sdavidcs 499322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 500322972Sdavidcs OID_AUTO, "sw_pkt_count", 501322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.sw_pkt_count, 502322972Sdavidcs "sw_pkt_count"); 503322972Sdavidcs 504322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 505322972Sdavidcs OID_AUTO, "ip_chksum_err", 506322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.ip_chksum_err, 507322972Sdavidcs "ip_chksum_err"); 508322972Sdavidcs 509322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 510322972Sdavidcs OID_AUTO, "pkts_wo_acntxts", 511322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_wo_acntxts, 512322972Sdavidcs "pkts_wo_acntxts"); 513322972Sdavidcs 514322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 515322972Sdavidcs OID_AUTO, "pkts_dropped_no_sds_card", 516322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_card, 517322972Sdavidcs "pkts_dropped_no_sds_card"); 518322972Sdavidcs 519322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 520322972Sdavidcs OID_AUTO, "pkts_dropped_no_sds_host", 521322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_sds_host, 522322972Sdavidcs "pkts_dropped_no_sds_host"); 523322972Sdavidcs 524322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 525322972Sdavidcs OID_AUTO, "oversized_pkts", 526322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.oversized_pkts, 527322972Sdavidcs "oversized_pkts"); 528322972Sdavidcs 529322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 530322972Sdavidcs OID_AUTO, "pkts_dropped_no_rds", 531322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_dropped_no_rds, 532322972Sdavidcs "pkts_dropped_no_rds"); 533322972Sdavidcs 534322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 535322972Sdavidcs OID_AUTO, "unxpctd_mcast_pkts", 536322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.unxpctd_mcast_pkts, 537322972Sdavidcs "unxpctd_mcast_pkts"); 538322972Sdavidcs 539322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 540322972Sdavidcs OID_AUTO, "re1_fbq_error", 541322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.re1_fbq_error, 542322972Sdavidcs "re1_fbq_error"); 543322972Sdavidcs 544322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 545322972Sdavidcs OID_AUTO, "invalid_mac_addr", 546322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.invalid_mac_addr, 547322972Sdavidcs "invalid_mac_addr"); 548322972Sdavidcs 549322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 550322972Sdavidcs OID_AUTO, "rds_prime_trys", 551322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.rds_prime_trys, 552322972Sdavidcs "rds_prime_trys"); 553322972Sdavidcs 554322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 555322972Sdavidcs OID_AUTO, "rds_prime_success", 556322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.rds_prime_success, 557322972Sdavidcs "rds_prime_success"); 558322972Sdavidcs 559322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 560322972Sdavidcs OID_AUTO, "lro_flows_added", 561322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.lro_flows_added, 562322972Sdavidcs "lro_flows_added"); 563322972Sdavidcs 564322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 565322972Sdavidcs OID_AUTO, "lro_flows_deleted", 566322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.lro_flows_deleted, 567322972Sdavidcs "lro_flows_deleted"); 568322972Sdavidcs 569322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 570322972Sdavidcs OID_AUTO, "lro_flows_active", 571322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.lro_flows_active, 572322972Sdavidcs "lro_flows_active"); 573322972Sdavidcs 574322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 575322972Sdavidcs OID_AUTO, "pkts_droped_unknown", 576322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_droped_unknown, 577322972Sdavidcs "pkts_droped_unknown"); 578322972Sdavidcs 579322972Sdavidcs SYSCTL_ADD_QUAD(ctx, children, 580322972Sdavidcs OID_AUTO, "pkts_cnt_oversized", 581322972Sdavidcs CTLFLAG_RD, &ha->hw.rcv.pkts_cnt_oversized, 582322972Sdavidcs "pkts_cnt_oversized"); 583322972Sdavidcs 584322972Sdavidcs return; 585322972Sdavidcs} 586322972Sdavidcs 587322972Sdavidcsstatic void 588322972Sdavidcsqlnx_add_hw_xmt_stats_sysctls(qla_host_t *ha) 589322972Sdavidcs{ 590322972Sdavidcs struct sysctl_ctx_list *ctx; 591322972Sdavidcs struct sysctl_oid_list *children; 592322972Sdavidcs struct sysctl_oid_list *node_children; 593322972Sdavidcs struct sysctl_oid *ctx_oid; 594322972Sdavidcs int i; 595322972Sdavidcs uint8_t name_str[16]; 596322972Sdavidcs 597322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 598322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 599322972Sdavidcs 600322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_hw_xmt", 601322972Sdavidcs CTLFLAG_RD, NULL, "stats_hw_xmt"); 602322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 603322972Sdavidcs 604322972Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 605322972Sdavidcs 606322972Sdavidcs bzero(name_str, (sizeof(uint8_t) * sizeof(name_str))); 607322972Sdavidcs snprintf(name_str, sizeof(name_str), "%d", i); 608322972Sdavidcs 609322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str, 610322972Sdavidcs CTLFLAG_RD, NULL, name_str); 611322972Sdavidcs node_children = SYSCTL_CHILDREN(ctx_oid); 612322972Sdavidcs 613322972Sdavidcs /* Tx Related */ 614322972Sdavidcs 615322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 616322972Sdavidcs OID_AUTO, "total_bytes", 617322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].total_bytes, 618322972Sdavidcs "total_bytes"); 619322972Sdavidcs 620322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 621322972Sdavidcs OID_AUTO, "total_pkts", 622322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].total_pkts, 623322972Sdavidcs "total_pkts"); 624322972Sdavidcs 625322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 626322972Sdavidcs OID_AUTO, "errors", 627322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].errors, 628322972Sdavidcs "errors"); 629322972Sdavidcs 630322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 631322972Sdavidcs OID_AUTO, "pkts_dropped", 632322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].pkts_dropped, 633322972Sdavidcs "pkts_dropped"); 634322972Sdavidcs 635322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 636322972Sdavidcs OID_AUTO, "switch_pkts", 637322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].switch_pkts, 638322972Sdavidcs "switch_pkts"); 639322972Sdavidcs 640322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 641322972Sdavidcs OID_AUTO, "num_buffers", 642322972Sdavidcs CTLFLAG_RD, &ha->hw.xmt[i].num_buffers, 643322972Sdavidcs "num_buffers"); 644322972Sdavidcs } 645322972Sdavidcs 646322972Sdavidcs return; 647322972Sdavidcs} 648322972Sdavidcs 649322972Sdavidcsstatic void 650330555Sdavidcsqlnx_add_hw_mbx_cmpl_stats_sysctls(qla_host_t *ha) 651330555Sdavidcs{ 652330555Sdavidcs struct sysctl_ctx_list *ctx; 653330555Sdavidcs struct sysctl_oid_list *node_children; 654330555Sdavidcs 655330555Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 656330555Sdavidcs node_children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 657330555Sdavidcs 658330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 659330555Sdavidcs OID_AUTO, "mbx_completion_time_lt_200ms", 660330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[0], 661330555Sdavidcs "mbx_completion_time_lt_200ms"); 662330555Sdavidcs 663330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 664330555Sdavidcs OID_AUTO, "mbx_completion_time_200ms_400ms", 665330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[1], 666330555Sdavidcs "mbx_completion_time_200ms_400ms"); 667330555Sdavidcs 668330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 669330555Sdavidcs OID_AUTO, "mbx_completion_time_400ms_600ms", 670330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[2], 671330555Sdavidcs "mbx_completion_time_400ms_600ms"); 672330555Sdavidcs 673330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 674330555Sdavidcs OID_AUTO, "mbx_completion_time_600ms_800ms", 675330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[3], 676330555Sdavidcs "mbx_completion_time_600ms_800ms"); 677330555Sdavidcs 678330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 679330555Sdavidcs OID_AUTO, "mbx_completion_time_800ms_1000ms", 680330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[4], 681330555Sdavidcs "mbx_completion_time_800ms_1000ms"); 682330555Sdavidcs 683330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 684330555Sdavidcs OID_AUTO, "mbx_completion_time_1000ms_1200ms", 685330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[5], 686330555Sdavidcs "mbx_completion_time_1000ms_1200ms"); 687330555Sdavidcs 688330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 689330555Sdavidcs OID_AUTO, "mbx_completion_time_1200ms_1400ms", 690330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[6], 691330555Sdavidcs "mbx_completion_time_1200ms_1400ms"); 692330555Sdavidcs 693330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 694330555Sdavidcs OID_AUTO, "mbx_completion_time_1400ms_1600ms", 695330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[7], 696330555Sdavidcs "mbx_completion_time_1400ms_1600ms"); 697330555Sdavidcs 698330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 699330555Sdavidcs OID_AUTO, "mbx_completion_time_1600ms_1800ms", 700330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[8], 701330555Sdavidcs "mbx_completion_time_1600ms_1800ms"); 702330555Sdavidcs 703330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 704330555Sdavidcs OID_AUTO, "mbx_completion_time_1800ms_2000ms", 705330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[9], 706330555Sdavidcs "mbx_completion_time_1800ms_2000ms"); 707330555Sdavidcs 708330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 709330555Sdavidcs OID_AUTO, "mbx_completion_time_2000ms_2200ms", 710330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[10], 711330555Sdavidcs "mbx_completion_time_2000ms_2200ms"); 712330555Sdavidcs 713330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 714330555Sdavidcs OID_AUTO, "mbx_completion_time_2200ms_2400ms", 715330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[11], 716330555Sdavidcs "mbx_completion_time_2200ms_2400ms"); 717330555Sdavidcs 718330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 719330555Sdavidcs OID_AUTO, "mbx_completion_time_2400ms_2600ms", 720330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[12], 721330555Sdavidcs "mbx_completion_time_2400ms_2600ms"); 722330555Sdavidcs 723330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 724330555Sdavidcs OID_AUTO, "mbx_completion_time_2600ms_2800ms", 725330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[13], 726330555Sdavidcs "mbx_completion_time_2600ms_2800ms"); 727330555Sdavidcs 728330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 729330555Sdavidcs OID_AUTO, "mbx_completion_time_2800ms_3000ms", 730330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[14], 731330555Sdavidcs "mbx_completion_time_2800ms_3000ms"); 732330555Sdavidcs 733330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 734330555Sdavidcs OID_AUTO, "mbx_completion_time_3000ms_4000ms", 735330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[15], 736330555Sdavidcs "mbx_completion_time_3000ms_4000ms"); 737330555Sdavidcs 738330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 739330555Sdavidcs OID_AUTO, "mbx_completion_time_4000ms_5000ms", 740330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[16], 741330555Sdavidcs "mbx_completion_time_4000ms_5000ms"); 742330555Sdavidcs 743330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 744330555Sdavidcs OID_AUTO, "mbx_completion_host_mbx_cntrl_timeout", 745330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[17], 746330555Sdavidcs "mbx_completion_host_mbx_cntrl_timeout"); 747330555Sdavidcs 748330555Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 749330555Sdavidcs OID_AUTO, "mbx_completion_fw_mbx_cntrl_timeout", 750330555Sdavidcs CTLFLAG_RD, &ha->hw.mbx_comp_msecs[18], 751330555Sdavidcs "mbx_completion_fw_mbx_cntrl_timeout"); 752330555Sdavidcs return; 753330555Sdavidcs} 754330555Sdavidcs 755330555Sdavidcsstatic void 756322972Sdavidcsqlnx_add_hw_stats_sysctls(qla_host_t *ha) 757322972Sdavidcs{ 758322972Sdavidcs qlnx_add_hw_mac_stats_sysctls(ha); 759322972Sdavidcs qlnx_add_hw_rcv_stats_sysctls(ha); 760322972Sdavidcs qlnx_add_hw_xmt_stats_sysctls(ha); 761330555Sdavidcs qlnx_add_hw_mbx_cmpl_stats_sysctls(ha); 762322972Sdavidcs 763322972Sdavidcs return; 764322972Sdavidcs} 765322972Sdavidcs 766322972Sdavidcsstatic void 767322972Sdavidcsqlnx_add_drvr_sds_stats(qla_host_t *ha) 768322972Sdavidcs{ 769322972Sdavidcs struct sysctl_ctx_list *ctx; 770322972Sdavidcs struct sysctl_oid_list *children; 771322972Sdavidcs struct sysctl_oid_list *node_children; 772322972Sdavidcs struct sysctl_oid *ctx_oid; 773322972Sdavidcs int i; 774322972Sdavidcs uint8_t name_str[16]; 775322972Sdavidcs 776322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 777322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 778322972Sdavidcs 779322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_sds", 780322972Sdavidcs CTLFLAG_RD, NULL, "stats_drvr_sds"); 781322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 782322972Sdavidcs 783322972Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; i++) { 784322972Sdavidcs 785322972Sdavidcs bzero(name_str, (sizeof(uint8_t) * sizeof(name_str))); 786322972Sdavidcs snprintf(name_str, sizeof(name_str), "%d", i); 787322972Sdavidcs 788322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str, 789322972Sdavidcs CTLFLAG_RD, NULL, name_str); 790322972Sdavidcs node_children = SYSCTL_CHILDREN(ctx_oid); 791322972Sdavidcs 792322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 793322972Sdavidcs OID_AUTO, "intr_count", 794322972Sdavidcs CTLFLAG_RD, &ha->hw.sds[i].intr_count, 795322972Sdavidcs "intr_count"); 796322972Sdavidcs 797322972Sdavidcs SYSCTL_ADD_UINT(ctx, node_children, 798322972Sdavidcs OID_AUTO, "rx_free", 799322972Sdavidcs CTLFLAG_RD, &ha->hw.sds[i].rx_free, 800322972Sdavidcs ha->hw.sds[i].rx_free, "rx_free"); 801322972Sdavidcs } 802322972Sdavidcs 803322972Sdavidcs return; 804322972Sdavidcs} 805322972Sdavidcsstatic void 806322972Sdavidcsqlnx_add_drvr_rds_stats(qla_host_t *ha) 807322972Sdavidcs{ 808322972Sdavidcs struct sysctl_ctx_list *ctx; 809322972Sdavidcs struct sysctl_oid_list *children; 810322972Sdavidcs struct sysctl_oid_list *node_children; 811322972Sdavidcs struct sysctl_oid *ctx_oid; 812322972Sdavidcs int i; 813322972Sdavidcs uint8_t name_str[16]; 814322972Sdavidcs 815322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 816322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 817322972Sdavidcs 818322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_rds", 819322972Sdavidcs CTLFLAG_RD, NULL, "stats_drvr_rds"); 820322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 821322972Sdavidcs 822322972Sdavidcs for (i = 0; i < ha->hw.num_rds_rings; i++) { 823322972Sdavidcs 824322972Sdavidcs bzero(name_str, (sizeof(uint8_t) * sizeof(name_str))); 825322972Sdavidcs snprintf(name_str, sizeof(name_str), "%d", i); 826322972Sdavidcs 827322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str, 828322972Sdavidcs CTLFLAG_RD, NULL, name_str); 829322972Sdavidcs node_children = SYSCTL_CHILDREN(ctx_oid); 830322972Sdavidcs 831322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 832322972Sdavidcs OID_AUTO, "count", 833322972Sdavidcs CTLFLAG_RD, &ha->hw.rds[i].count, 834322972Sdavidcs "count"); 835322972Sdavidcs 836322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 837322972Sdavidcs OID_AUTO, "lro_pkt_count", 838322972Sdavidcs CTLFLAG_RD, &ha->hw.rds[i].lro_pkt_count, 839322972Sdavidcs "lro_pkt_count"); 840322972Sdavidcs 841322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 842322972Sdavidcs OID_AUTO, "lro_bytes", 843322972Sdavidcs CTLFLAG_RD, &ha->hw.rds[i].lro_bytes, 844322972Sdavidcs "lro_bytes"); 845322972Sdavidcs } 846322972Sdavidcs 847322972Sdavidcs return; 848322972Sdavidcs} 849322972Sdavidcs 850322972Sdavidcsstatic void 851322972Sdavidcsqlnx_add_drvr_tx_stats(qla_host_t *ha) 852322972Sdavidcs{ 853322972Sdavidcs struct sysctl_ctx_list *ctx; 854322972Sdavidcs struct sysctl_oid_list *children; 855322972Sdavidcs struct sysctl_oid_list *node_children; 856322972Sdavidcs struct sysctl_oid *ctx_oid; 857322972Sdavidcs int i; 858322972Sdavidcs uint8_t name_str[16]; 859322972Sdavidcs 860322972Sdavidcs ctx = device_get_sysctl_ctx(ha->pci_dev); 861322972Sdavidcs children = SYSCTL_CHILDREN(device_get_sysctl_tree(ha->pci_dev)); 862322972Sdavidcs 863322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats_drvr_xmt", 864322972Sdavidcs CTLFLAG_RD, NULL, "stats_drvr_xmt"); 865322972Sdavidcs children = SYSCTL_CHILDREN(ctx_oid); 866322972Sdavidcs 867322972Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 868322972Sdavidcs 869322972Sdavidcs bzero(name_str, (sizeof(uint8_t) * sizeof(name_str))); 870322972Sdavidcs snprintf(name_str, sizeof(name_str), "%d", i); 871322972Sdavidcs 872322972Sdavidcs ctx_oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, name_str, 873322972Sdavidcs CTLFLAG_RD, NULL, name_str); 874322972Sdavidcs node_children = SYSCTL_CHILDREN(ctx_oid); 875322972Sdavidcs 876322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 877322972Sdavidcs OID_AUTO, "count", 878322972Sdavidcs CTLFLAG_RD, &ha->tx_ring[i].count, 879322972Sdavidcs "count"); 880322972Sdavidcs 881322972Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV 882322972Sdavidcs SYSCTL_ADD_QUAD(ctx, node_children, 883322972Sdavidcs OID_AUTO, "iscsi_pkt_count", 884322972Sdavidcs CTLFLAG_RD, &ha->tx_ring[i].iscsi_pkt_count, 885322972Sdavidcs "iscsi_pkt_count"); 886322972Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */ 887322972Sdavidcs } 888322972Sdavidcs 889322972Sdavidcs return; 890322972Sdavidcs} 891322972Sdavidcs 892322972Sdavidcsstatic void 893322972Sdavidcsqlnx_add_drvr_stats_sysctls(qla_host_t *ha) 894322972Sdavidcs{ 895322972Sdavidcs qlnx_add_drvr_sds_stats(ha); 896322972Sdavidcs qlnx_add_drvr_rds_stats(ha); 897322972Sdavidcs qlnx_add_drvr_tx_stats(ha); 898322972Sdavidcs return; 899322972Sdavidcs} 900322972Sdavidcs 901250661Sdavidcs/* 902250661Sdavidcs * Name: ql_hw_add_sysctls 903250661Sdavidcs * Function: Add P3Plus specific sysctls 904250661Sdavidcs */ 905250661Sdavidcsvoid 906250661Sdavidcsql_hw_add_sysctls(qla_host_t *ha) 907250661Sdavidcs{ 908250661Sdavidcs device_t dev; 909250661Sdavidcs 910250661Sdavidcs dev = ha->pci_dev; 911250661Sdavidcs 912250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 913250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 914250661Sdavidcs OID_AUTO, "num_rds_rings", CTLFLAG_RD, &ha->hw.num_rds_rings, 915250661Sdavidcs ha->hw.num_rds_rings, "Number of Rcv Descriptor Rings"); 916250661Sdavidcs 917250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 918250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 919250661Sdavidcs OID_AUTO, "num_sds_rings", CTLFLAG_RD, &ha->hw.num_sds_rings, 920250661Sdavidcs ha->hw.num_sds_rings, "Number of Status Descriptor Rings"); 921250661Sdavidcs 922250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 923250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 924250661Sdavidcs OID_AUTO, "num_tx_rings", CTLFLAG_RD, &ha->hw.num_tx_rings, 925250661Sdavidcs ha->hw.num_tx_rings, "Number of Transmit Rings"); 926250661Sdavidcs 927250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 928250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 929250661Sdavidcs OID_AUTO, "tx_ring_index", CTLFLAG_RW, &ha->txr_idx, 930250661Sdavidcs ha->txr_idx, "Tx Ring Used"); 931250661Sdavidcs 932250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 933250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 934250661Sdavidcs OID_AUTO, "max_tx_segs", CTLFLAG_RD, &ha->hw.max_tx_segs, 935250661Sdavidcs ha->hw.max_tx_segs, "Max # of Segments in a non-TSO pkt"); 936250661Sdavidcs 937250661Sdavidcs ha->hw.sds_cidx_thres = 32; 938250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 939250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 940250661Sdavidcs OID_AUTO, "sds_cidx_thres", CTLFLAG_RW, &ha->hw.sds_cidx_thres, 941250661Sdavidcs ha->hw.sds_cidx_thres, 942250661Sdavidcs "Number of SDS entries to process before updating" 943250661Sdavidcs " SDS Ring Consumer Index"); 944250661Sdavidcs 945250661Sdavidcs ha->hw.rds_pidx_thres = 32; 946250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 947250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 948250661Sdavidcs OID_AUTO, "rds_pidx_thres", CTLFLAG_RW, &ha->hw.rds_pidx_thres, 949250661Sdavidcs ha->hw.rds_pidx_thres, 950250661Sdavidcs "Number of Rcv Rings Entries to post before updating" 951250661Sdavidcs " RDS Ring Producer Index"); 952250661Sdavidcs 953284741Sdavidcs ha->hw.rcv_intr_coalesce = (3 << 16) | 256; 954284741Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 955284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 956284741Sdavidcs OID_AUTO, "rcv_intr_coalesce", CTLFLAG_RW, 957284741Sdavidcs &ha->hw.rcv_intr_coalesce, 958284741Sdavidcs ha->hw.rcv_intr_coalesce, 959284741Sdavidcs "Rcv Intr Coalescing Parameters\n" 960284741Sdavidcs "\tbits 15:0 max packets\n" 961284741Sdavidcs "\tbits 31:16 max micro-seconds to wait\n" 962284741Sdavidcs "\tplease run\n" 963284741Sdavidcs "\tifconfig <if> down && ifconfig <if> up\n" 964284741Sdavidcs "\tto take effect \n"); 965258155Sdavidcs 966284741Sdavidcs ha->hw.xmt_intr_coalesce = (64 << 16) | 64; 967284741Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 968284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 969284741Sdavidcs OID_AUTO, "xmt_intr_coalesce", CTLFLAG_RW, 970284741Sdavidcs &ha->hw.xmt_intr_coalesce, 971284741Sdavidcs ha->hw.xmt_intr_coalesce, 972284741Sdavidcs "Xmt Intr Coalescing Parameters\n" 973284741Sdavidcs "\tbits 15:0 max packets\n" 974284741Sdavidcs "\tbits 31:16 max micro-seconds to wait\n" 975284741Sdavidcs "\tplease run\n" 976284741Sdavidcs "\tifconfig <if> down && ifconfig <if> up\n" 977284741Sdavidcs "\tto take effect \n"); 978284741Sdavidcs 979284741Sdavidcs SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 980284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 981284741Sdavidcs OID_AUTO, "port_cfg", CTLTYPE_INT | CTLFLAG_RW, 982284741Sdavidcs (void *)ha, 0, 983284741Sdavidcs qla_sysctl_port_cfg, "I", 984284741Sdavidcs "Set Port Configuration if values below " 985284741Sdavidcs "otherwise Get Port Configuration\n" 986284741Sdavidcs "\tBits 0-3 ; 1 = DCBX Enable; 0 = DCBX Disable\n" 987284741Sdavidcs "\tBits 4-7 : 0 = no pause; 1 = std ; 2 = ppm \n" 988284741Sdavidcs "\tBits 8-11: std pause cfg; 0 = xmt and rcv;" 989284741Sdavidcs " 1 = xmt only; 2 = rcv only;\n" 990284741Sdavidcs ); 991284741Sdavidcs 992305488Sdavidcs SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 993305488Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 994305488Sdavidcs OID_AUTO, "set_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW, 995305488Sdavidcs (void *)ha, 0, 996305488Sdavidcs qla_sysctl_set_cam_search_mode, "I", 997305488Sdavidcs "Set CAM Search Mode" 998305488Sdavidcs "\t 1 = search mode internal\n" 999305488Sdavidcs "\t 2 = search mode auto\n"); 1000305488Sdavidcs 1001305488Sdavidcs SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1002305488Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1003305488Sdavidcs OID_AUTO, "get_cam_search_mode", CTLTYPE_INT | CTLFLAG_RW, 1004305488Sdavidcs (void *)ha, 0, 1005305488Sdavidcs qla_sysctl_get_cam_search_mode, "I", 1006305488Sdavidcs "Get CAM Search Mode" 1007305488Sdavidcs "\t 1 = search mode internal\n" 1008305488Sdavidcs "\t 2 = search mode auto\n"); 1009305488Sdavidcs 1010284741Sdavidcs ha->hw.enable_9kb = 1; 1011284741Sdavidcs 1012284741Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1013284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1014284741Sdavidcs OID_AUTO, "enable_9kb", CTLFLAG_RW, &ha->hw.enable_9kb, 1015284741Sdavidcs ha->hw.enable_9kb, "Enable 9Kbyte Buffers when MTU = 9000"); 1016284741Sdavidcs 1017317109Sdavidcs ha->hw.enable_hw_lro = 1; 1018317109Sdavidcs 1019317109Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1020317109Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1021317109Sdavidcs OID_AUTO, "enable_hw_lro", CTLFLAG_RW, &ha->hw.enable_hw_lro, 1022317109Sdavidcs ha->hw.enable_hw_lro, "Enable Hardware LRO; Default is true \n" 1023317109Sdavidcs "\t 1 : Hardware LRO if LRO is enabled\n" 1024317109Sdavidcs "\t 0 : Software LRO if LRO is enabled\n" 1025317109Sdavidcs "\t Any change requires ifconfig down/up to take effect\n" 1026317109Sdavidcs "\t Note that LRO may be turned off/on via ifconfig\n"); 1027317109Sdavidcs 1028330555Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1029330555Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1030330555Sdavidcs OID_AUTO, "sp_log_index", CTLFLAG_RW, &ha->hw.sp_log_index, 1031330555Sdavidcs ha->hw.sp_log_index, "sp_log_index"); 1032330555Sdavidcs 1033330555Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1034330555Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1035330555Sdavidcs OID_AUTO, "sp_log_stop", CTLFLAG_RW, &ha->hw.sp_log_stop, 1036330555Sdavidcs ha->hw.sp_log_stop, "sp_log_stop"); 1037330555Sdavidcs 1038330555Sdavidcs ha->hw.sp_log_stop_events = 0; 1039330555Sdavidcs 1040330555Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1041330555Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1042330555Sdavidcs OID_AUTO, "sp_log_stop_events", CTLFLAG_RW, 1043330555Sdavidcs &ha->hw.sp_log_stop_events, 1044330555Sdavidcs ha->hw.sp_log_stop_events, "Slow path event log is stopped" 1045330555Sdavidcs " when OR of the following events occur \n" 1046330555Sdavidcs "\t 0x01 : Heart beat Failure\n" 1047330555Sdavidcs "\t 0x02 : Temperature Failure\n" 1048330555Sdavidcs "\t 0x04 : HW Initialization Failure\n" 1049330555Sdavidcs "\t 0x08 : Interface Initialization Failure\n" 1050330555Sdavidcs "\t 0x10 : Error Recovery Failure\n"); 1051330555Sdavidcs 1052250661Sdavidcs ha->hw.mdump_active = 0; 1053250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1054250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1055250661Sdavidcs OID_AUTO, "minidump_active", CTLFLAG_RW, &ha->hw.mdump_active, 1056250661Sdavidcs ha->hw.mdump_active, 1057305487Sdavidcs "Minidump retrieval is Active"); 1058250661Sdavidcs 1059305487Sdavidcs ha->hw.mdump_done = 0; 1060250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1061250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1062305487Sdavidcs OID_AUTO, "mdump_done", CTLFLAG_RW, 1063305487Sdavidcs &ha->hw.mdump_done, ha->hw.mdump_done, 1064305487Sdavidcs "Minidump has been done and available for retrieval"); 1065305487Sdavidcs 1066305487Sdavidcs ha->hw.mdump_capture_mask = 0xF; 1067305487Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1068305487Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1069305487Sdavidcs OID_AUTO, "minidump_capture_mask", CTLFLAG_RW, 1070305487Sdavidcs &ha->hw.mdump_capture_mask, ha->hw.mdump_capture_mask, 1071305487Sdavidcs "Minidump capture mask"); 1072250661Sdavidcs#ifdef QL_DBG 1073250661Sdavidcs 1074289635Sdavidcs ha->err_inject = 0; 1075250661Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1076250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1077250661Sdavidcs OID_AUTO, "err_inject", 1078250661Sdavidcs CTLFLAG_RW, &ha->err_inject, ha->err_inject, 1079250661Sdavidcs "Error to be injected\n" 1080250661Sdavidcs "\t\t\t 0: No Errors\n" 1081250661Sdavidcs "\t\t\t 1: rcv: rxb struct invalid\n" 1082250661Sdavidcs "\t\t\t 2: rcv: mp == NULL\n" 1083250661Sdavidcs "\t\t\t 3: lro: rxb struct invalid\n" 1084250661Sdavidcs "\t\t\t 4: lro: mp == NULL\n" 1085250661Sdavidcs "\t\t\t 5: rcv: num handles invalid\n" 1086250661Sdavidcs "\t\t\t 6: reg: indirect reg rd_wr failure\n" 1087250661Sdavidcs "\t\t\t 7: ocm: offchip memory rd_wr failure\n" 1088250661Sdavidcs "\t\t\t 8: mbx: mailbox command failure\n" 1089250661Sdavidcs "\t\t\t 9: heartbeat failure\n" 1090305488Sdavidcs "\t\t\t A: temperature failure\n" 1091332052Sdavidcs "\t\t\t 11: m_getcl or m_getjcl failure\n" 1092332052Sdavidcs "\t\t\t 13: Invalid Descriptor Count in SGL Receive\n" 1093332052Sdavidcs "\t\t\t 14: Invalid Descriptor Count in LRO Receive\n" 1094332052Sdavidcs "\t\t\t 15: peer port error recovery failure\n" 1095332052Sdavidcs "\t\t\t 16: tx_buf[next_prod_index].mbuf != NULL\n" ); 1096250661Sdavidcs 1097250661Sdavidcs SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), 1098250661Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1099250661Sdavidcs OID_AUTO, "peg_stop", CTLTYPE_INT | CTLFLAG_RW, 1100250661Sdavidcs (void *)ha, 0, 1101250661Sdavidcs qla_sysctl_stop_pegs, "I", "Peg Stop"); 1102250661Sdavidcs 1103250661Sdavidcs#endif /* #ifdef QL_DBG */ 1104250661Sdavidcs 1105284741Sdavidcs ha->hw.user_pri_nic = 0; 1106284741Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1107284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1108284741Sdavidcs OID_AUTO, "user_pri_nic", CTLFLAG_RW, &ha->hw.user_pri_nic, 1109284741Sdavidcs ha->hw.user_pri_nic, 1110284741Sdavidcs "VLAN Tag User Priority for Normal Ethernet Packets"); 1111284741Sdavidcs 1112284741Sdavidcs ha->hw.user_pri_iscsi = 4; 1113284741Sdavidcs SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), 1114284741Sdavidcs SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), 1115284741Sdavidcs OID_AUTO, "user_pri_iscsi", CTLFLAG_RW, &ha->hw.user_pri_iscsi, 1116284741Sdavidcs ha->hw.user_pri_iscsi, 1117284741Sdavidcs "VLAN Tag User Priority for iSCSI Packets"); 1118284741Sdavidcs 1119322972Sdavidcs qlnx_add_hw_stats_sysctls(ha); 1120322972Sdavidcs qlnx_add_drvr_stats_sysctls(ha); 1121322972Sdavidcs 1122322972Sdavidcs return; 1123250661Sdavidcs} 1124250661Sdavidcs 1125250661Sdavidcsvoid 1126250661Sdavidcsql_hw_link_status(qla_host_t *ha) 1127250661Sdavidcs{ 1128250661Sdavidcs device_printf(ha->pci_dev, "cable_oui\t\t 0x%08x\n", ha->hw.cable_oui); 1129250661Sdavidcs 1130250661Sdavidcs if (ha->hw.link_up) { 1131250661Sdavidcs device_printf(ha->pci_dev, "link Up\n"); 1132250661Sdavidcs } else { 1133250661Sdavidcs device_printf(ha->pci_dev, "link Down\n"); 1134250661Sdavidcs } 1135250661Sdavidcs 1136330555Sdavidcs if (ha->hw.fduplex) { 1137250661Sdavidcs device_printf(ha->pci_dev, "Full Duplex\n"); 1138250661Sdavidcs } else { 1139250661Sdavidcs device_printf(ha->pci_dev, "Half Duplex\n"); 1140250661Sdavidcs } 1141250661Sdavidcs 1142330555Sdavidcs if (ha->hw.autoneg) { 1143250661Sdavidcs device_printf(ha->pci_dev, "Auto Negotiation Enabled\n"); 1144250661Sdavidcs } else { 1145250661Sdavidcs device_printf(ha->pci_dev, "Auto Negotiation Disabled\n"); 1146250661Sdavidcs } 1147250661Sdavidcs 1148250661Sdavidcs switch (ha->hw.link_speed) { 1149250661Sdavidcs case 0x710: 1150250661Sdavidcs device_printf(ha->pci_dev, "link speed\t\t 10Gps\n"); 1151250661Sdavidcs break; 1152250661Sdavidcs 1153250661Sdavidcs case 0x3E8: 1154250661Sdavidcs device_printf(ha->pci_dev, "link speed\t\t 1Gps\n"); 1155250661Sdavidcs break; 1156250661Sdavidcs 1157250661Sdavidcs case 0x64: 1158250661Sdavidcs device_printf(ha->pci_dev, "link speed\t\t 100Mbps\n"); 1159250661Sdavidcs break; 1160250661Sdavidcs 1161250661Sdavidcs default: 1162250661Sdavidcs device_printf(ha->pci_dev, "link speed\t\t Unknown\n"); 1163250661Sdavidcs break; 1164250661Sdavidcs } 1165250661Sdavidcs 1166250661Sdavidcs switch (ha->hw.module_type) { 1167250661Sdavidcs 1168250661Sdavidcs case 0x01: 1169250661Sdavidcs device_printf(ha->pci_dev, "Module Type 10GBase-LRM\n"); 1170250661Sdavidcs break; 1171250661Sdavidcs 1172250661Sdavidcs case 0x02: 1173250661Sdavidcs device_printf(ha->pci_dev, "Module Type 10GBase-LR\n"); 1174250661Sdavidcs break; 1175250661Sdavidcs 1176250661Sdavidcs case 0x03: 1177250661Sdavidcs device_printf(ha->pci_dev, "Module Type 10GBase-SR\n"); 1178250661Sdavidcs break; 1179250661Sdavidcs 1180250661Sdavidcs case 0x04: 1181250661Sdavidcs device_printf(ha->pci_dev, 1182250661Sdavidcs "Module Type 10GE Passive Copper(Compliant)[%d m]\n", 1183250661Sdavidcs ha->hw.cable_length); 1184250661Sdavidcs break; 1185250661Sdavidcs 1186250661Sdavidcs case 0x05: 1187250661Sdavidcs device_printf(ha->pci_dev, "Module Type 10GE Active" 1188250661Sdavidcs " Limiting Copper(Compliant)[%d m]\n", 1189250661Sdavidcs ha->hw.cable_length); 1190250661Sdavidcs break; 1191250661Sdavidcs 1192250661Sdavidcs case 0x06: 1193250661Sdavidcs device_printf(ha->pci_dev, 1194250661Sdavidcs "Module Type 10GE Passive Copper" 1195250661Sdavidcs " (Legacy, Best Effort)[%d m]\n", 1196250661Sdavidcs ha->hw.cable_length); 1197250661Sdavidcs break; 1198250661Sdavidcs 1199250661Sdavidcs case 0x07: 1200250661Sdavidcs device_printf(ha->pci_dev, "Module Type 1000Base-SX\n"); 1201250661Sdavidcs break; 1202250661Sdavidcs 1203250661Sdavidcs case 0x08: 1204250661Sdavidcs device_printf(ha->pci_dev, "Module Type 1000Base-LX\n"); 1205250661Sdavidcs break; 1206250661Sdavidcs 1207250661Sdavidcs case 0x09: 1208250661Sdavidcs device_printf(ha->pci_dev, "Module Type 1000Base-CX\n"); 1209250661Sdavidcs break; 1210250661Sdavidcs 1211250661Sdavidcs case 0x0A: 1212250661Sdavidcs device_printf(ha->pci_dev, "Module Type 1000Base-T\n"); 1213250661Sdavidcs break; 1214250661Sdavidcs 1215250661Sdavidcs case 0x0B: 1216250661Sdavidcs device_printf(ha->pci_dev, "Module Type 1GE Passive Copper" 1217250661Sdavidcs "(Legacy, Best Effort)\n"); 1218250661Sdavidcs break; 1219250661Sdavidcs 1220250661Sdavidcs default: 1221250661Sdavidcs device_printf(ha->pci_dev, "Unknown Module Type 0x%x\n", 1222250661Sdavidcs ha->hw.module_type); 1223250661Sdavidcs break; 1224250661Sdavidcs } 1225250661Sdavidcs 1226250661Sdavidcs if (ha->hw.link_faults == 1) 1227250661Sdavidcs device_printf(ha->pci_dev, "SFP Power Fault\n"); 1228250661Sdavidcs} 1229250661Sdavidcs 1230250661Sdavidcs/* 1231250661Sdavidcs * Name: ql_free_dma 1232250661Sdavidcs * Function: Frees the DMA'able memory allocated in ql_alloc_dma() 1233250661Sdavidcs */ 1234250661Sdavidcsvoid 1235250661Sdavidcsql_free_dma(qla_host_t *ha) 1236250661Sdavidcs{ 1237250661Sdavidcs uint32_t i; 1238250661Sdavidcs 1239250661Sdavidcs if (ha->hw.dma_buf.flags.sds_ring) { 1240250661Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; i++) { 1241250661Sdavidcs ql_free_dmabuf(ha, &ha->hw.dma_buf.sds_ring[i]); 1242250661Sdavidcs } 1243250661Sdavidcs ha->hw.dma_buf.flags.sds_ring = 0; 1244250661Sdavidcs } 1245250661Sdavidcs 1246250661Sdavidcs if (ha->hw.dma_buf.flags.rds_ring) { 1247250661Sdavidcs for (i = 0; i < ha->hw.num_rds_rings; i++) { 1248250661Sdavidcs ql_free_dmabuf(ha, &ha->hw.dma_buf.rds_ring[i]); 1249250661Sdavidcs } 1250250661Sdavidcs ha->hw.dma_buf.flags.rds_ring = 0; 1251250661Sdavidcs } 1252250661Sdavidcs 1253250661Sdavidcs if (ha->hw.dma_buf.flags.tx_ring) { 1254250661Sdavidcs ql_free_dmabuf(ha, &ha->hw.dma_buf.tx_ring); 1255250661Sdavidcs ha->hw.dma_buf.flags.tx_ring = 0; 1256250661Sdavidcs } 1257305487Sdavidcs ql_minidump_free(ha); 1258250661Sdavidcs} 1259250661Sdavidcs 1260250661Sdavidcs/* 1261250661Sdavidcs * Name: ql_alloc_dma 1262250661Sdavidcs * Function: Allocates DMA'able memory for Tx/Rx Rings, Tx/Rx Contexts. 1263250661Sdavidcs */ 1264250661Sdavidcsint 1265250661Sdavidcsql_alloc_dma(qla_host_t *ha) 1266250661Sdavidcs{ 1267250661Sdavidcs device_t dev; 1268250661Sdavidcs uint32_t i, j, size, tx_ring_size; 1269250661Sdavidcs qla_hw_t *hw; 1270250661Sdavidcs qla_hw_tx_cntxt_t *tx_cntxt; 1271250661Sdavidcs uint8_t *vaddr; 1272250661Sdavidcs bus_addr_t paddr; 1273250661Sdavidcs 1274250661Sdavidcs dev = ha->pci_dev; 1275250661Sdavidcs 1276250661Sdavidcs QL_DPRINT2(ha, (dev, "%s: enter\n", __func__)); 1277250661Sdavidcs 1278250661Sdavidcs hw = &ha->hw; 1279250661Sdavidcs /* 1280250661Sdavidcs * Allocate Transmit Ring 1281250661Sdavidcs */ 1282250661Sdavidcs tx_ring_size = (sizeof(q80_tx_cmd_t) * NUM_TX_DESCRIPTORS); 1283250661Sdavidcs size = (tx_ring_size * ha->hw.num_tx_rings); 1284250661Sdavidcs 1285250661Sdavidcs hw->dma_buf.tx_ring.alignment = 8; 1286250661Sdavidcs hw->dma_buf.tx_ring.size = size + PAGE_SIZE; 1287250661Sdavidcs 1288250661Sdavidcs if (ql_alloc_dmabuf(ha, &hw->dma_buf.tx_ring)) { 1289250661Sdavidcs device_printf(dev, "%s: tx ring alloc failed\n", __func__); 1290250661Sdavidcs goto ql_alloc_dma_exit; 1291250661Sdavidcs } 1292250661Sdavidcs 1293250661Sdavidcs vaddr = (uint8_t *)hw->dma_buf.tx_ring.dma_b; 1294250661Sdavidcs paddr = hw->dma_buf.tx_ring.dma_addr; 1295250661Sdavidcs 1296250661Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 1297250661Sdavidcs tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i]; 1298250661Sdavidcs 1299250661Sdavidcs tx_cntxt->tx_ring_base = (q80_tx_cmd_t *)vaddr; 1300250661Sdavidcs tx_cntxt->tx_ring_paddr = paddr; 1301250661Sdavidcs 1302250661Sdavidcs vaddr += tx_ring_size; 1303250661Sdavidcs paddr += tx_ring_size; 1304250661Sdavidcs } 1305250661Sdavidcs 1306250661Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 1307250661Sdavidcs tx_cntxt = (qla_hw_tx_cntxt_t *)&hw->tx_cntxt[i]; 1308250661Sdavidcs 1309250661Sdavidcs tx_cntxt->tx_cons = (uint32_t *)vaddr; 1310250661Sdavidcs tx_cntxt->tx_cons_paddr = paddr; 1311250661Sdavidcs 1312250661Sdavidcs vaddr += sizeof (uint32_t); 1313250661Sdavidcs paddr += sizeof (uint32_t); 1314250661Sdavidcs } 1315250661Sdavidcs 1316250661Sdavidcs ha->hw.dma_buf.flags.tx_ring = 1; 1317250661Sdavidcs 1318250661Sdavidcs QL_DPRINT2(ha, (dev, "%s: tx_ring phys %p virt %p\n", 1319250661Sdavidcs __func__, (void *)(hw->dma_buf.tx_ring.dma_addr), 1320250661Sdavidcs hw->dma_buf.tx_ring.dma_b)); 1321250661Sdavidcs /* 1322250661Sdavidcs * Allocate Receive Descriptor Rings 1323250661Sdavidcs */ 1324250661Sdavidcs 1325250661Sdavidcs for (i = 0; i < hw->num_rds_rings; i++) { 1326250661Sdavidcs 1327250661Sdavidcs hw->dma_buf.rds_ring[i].alignment = 8; 1328250661Sdavidcs hw->dma_buf.rds_ring[i].size = 1329250661Sdavidcs (sizeof(q80_recv_desc_t)) * NUM_RX_DESCRIPTORS; 1330250661Sdavidcs 1331250661Sdavidcs if (ql_alloc_dmabuf(ha, &hw->dma_buf.rds_ring[i])) { 1332250661Sdavidcs device_printf(dev, "%s: rds ring[%d] alloc failed\n", 1333250661Sdavidcs __func__, i); 1334250661Sdavidcs 1335250661Sdavidcs for (j = 0; j < i; j++) 1336250661Sdavidcs ql_free_dmabuf(ha, &hw->dma_buf.rds_ring[j]); 1337250661Sdavidcs 1338250661Sdavidcs goto ql_alloc_dma_exit; 1339250661Sdavidcs } 1340250661Sdavidcs QL_DPRINT4(ha, (dev, "%s: rx_ring[%d] phys %p virt %p\n", 1341250661Sdavidcs __func__, i, (void *)(hw->dma_buf.rds_ring[i].dma_addr), 1342250661Sdavidcs hw->dma_buf.rds_ring[i].dma_b)); 1343250661Sdavidcs } 1344250661Sdavidcs 1345250661Sdavidcs hw->dma_buf.flags.rds_ring = 1; 1346250661Sdavidcs 1347250661Sdavidcs /* 1348250661Sdavidcs * Allocate Status Descriptor Rings 1349250661Sdavidcs */ 1350250661Sdavidcs 1351250661Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 1352250661Sdavidcs hw->dma_buf.sds_ring[i].alignment = 8; 1353250661Sdavidcs hw->dma_buf.sds_ring[i].size = 1354250661Sdavidcs (sizeof(q80_stat_desc_t)) * NUM_STATUS_DESCRIPTORS; 1355250661Sdavidcs 1356250661Sdavidcs if (ql_alloc_dmabuf(ha, &hw->dma_buf.sds_ring[i])) { 1357250661Sdavidcs device_printf(dev, "%s: sds ring alloc failed\n", 1358250661Sdavidcs __func__); 1359250661Sdavidcs 1360250661Sdavidcs for (j = 0; j < i; j++) 1361250661Sdavidcs ql_free_dmabuf(ha, &hw->dma_buf.sds_ring[j]); 1362250661Sdavidcs 1363250661Sdavidcs goto ql_alloc_dma_exit; 1364250661Sdavidcs } 1365250661Sdavidcs QL_DPRINT4(ha, (dev, "%s: sds_ring[%d] phys %p virt %p\n", 1366250661Sdavidcs __func__, i, 1367250661Sdavidcs (void *)(hw->dma_buf.sds_ring[i].dma_addr), 1368250661Sdavidcs hw->dma_buf.sds_ring[i].dma_b)); 1369250661Sdavidcs } 1370250661Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 1371250661Sdavidcs hw->sds[i].sds_ring_base = 1372250661Sdavidcs (q80_stat_desc_t *)hw->dma_buf.sds_ring[i].dma_b; 1373250661Sdavidcs } 1374250661Sdavidcs 1375250661Sdavidcs hw->dma_buf.flags.sds_ring = 1; 1376250661Sdavidcs 1377250661Sdavidcs return 0; 1378250661Sdavidcs 1379250661Sdavidcsql_alloc_dma_exit: 1380250661Sdavidcs ql_free_dma(ha); 1381250661Sdavidcs return -1; 1382250661Sdavidcs} 1383250661Sdavidcs 1384250661Sdavidcs#define Q8_MBX_MSEC_DELAY 5000 1385250661Sdavidcs 1386250661Sdavidcsstatic int 1387250661Sdavidcsqla_mbx_cmd(qla_host_t *ha, uint32_t *h_mbox, uint32_t n_hmbox, 1388250661Sdavidcs uint32_t *fw_mbox, uint32_t n_fwmbox, uint32_t no_pause) 1389250661Sdavidcs{ 1390250661Sdavidcs uint32_t i; 1391250661Sdavidcs uint32_t data; 1392250661Sdavidcs int ret = 0; 1393330555Sdavidcs uint64_t start_usecs; 1394330555Sdavidcs uint64_t end_usecs; 1395330555Sdavidcs uint64_t msecs_200; 1396250661Sdavidcs 1397330555Sdavidcs ql_sp_log(ha, 0, 5, no_pause, h_mbox[0], h_mbox[1], h_mbox[2], h_mbox[3]); 1398330555Sdavidcs 1399330555Sdavidcs if (ha->offline || ha->qla_initiate_recovery) { 1400330555Sdavidcs ql_sp_log(ha, 1, 2, ha->offline, ha->qla_initiate_recovery, 0, 0, 0); 1401330555Sdavidcs goto exit_qla_mbx_cmd; 1402330555Sdavidcs } 1403330555Sdavidcs 1404330555Sdavidcs if (((ha->err_inject & 0xFFFF) == INJCT_MBX_CMD_FAILURE) && 1405330555Sdavidcs (((ha->err_inject & ~0xFFFF) == ((h_mbox[0] & 0xFFFF) << 16))|| 1406330555Sdavidcs !(ha->err_inject & ~0xFFFF))) { 1407250661Sdavidcs ret = -3; 1408330555Sdavidcs QL_INITIATE_RECOVERY(ha); 1409250661Sdavidcs goto exit_qla_mbx_cmd; 1410250661Sdavidcs } 1411250661Sdavidcs 1412330555Sdavidcs start_usecs = qla_get_usec_timestamp(); 1413330555Sdavidcs 1414250661Sdavidcs if (no_pause) 1415250661Sdavidcs i = 1000; 1416250661Sdavidcs else 1417250661Sdavidcs i = Q8_MBX_MSEC_DELAY; 1418250661Sdavidcs 1419250661Sdavidcs while (i) { 1420330555Sdavidcs 1421330555Sdavidcs if (ha->qla_initiate_recovery) { 1422330555Sdavidcs ql_sp_log(ha, 2, 1, ha->qla_initiate_recovery, 0, 0, 0, 0); 1423330555Sdavidcs return (-1); 1424330555Sdavidcs } 1425330555Sdavidcs 1426250661Sdavidcs data = READ_REG32(ha, Q8_HOST_MBOX_CNTRL); 1427250661Sdavidcs if (data == 0) 1428250661Sdavidcs break; 1429250661Sdavidcs if (no_pause) { 1430250661Sdavidcs DELAY(1000); 1431250661Sdavidcs } else { 1432250661Sdavidcs qla_mdelay(__func__, 1); 1433250661Sdavidcs } 1434250661Sdavidcs i--; 1435250661Sdavidcs } 1436250661Sdavidcs 1437250661Sdavidcs if (i == 0) { 1438250661Sdavidcs device_printf(ha->pci_dev, "%s: host_mbx_cntrl 0x%08x\n", 1439250661Sdavidcs __func__, data); 1440330555Sdavidcs ql_sp_log(ha, 3, 1, data, 0, 0, 0, 0); 1441250661Sdavidcs ret = -1; 1442330555Sdavidcs ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 2)]++; 1443330555Sdavidcs QL_INITIATE_RECOVERY(ha); 1444250661Sdavidcs goto exit_qla_mbx_cmd; 1445250661Sdavidcs } 1446250661Sdavidcs 1447250661Sdavidcs for (i = 0; i < n_hmbox; i++) { 1448250661Sdavidcs WRITE_REG32(ha, (Q8_HOST_MBOX0 + (i << 2)), *h_mbox); 1449250661Sdavidcs h_mbox++; 1450250661Sdavidcs } 1451250661Sdavidcs 1452250661Sdavidcs WRITE_REG32(ha, Q8_HOST_MBOX_CNTRL, 0x1); 1453250661Sdavidcs 1454250661Sdavidcs 1455250661Sdavidcs i = Q8_MBX_MSEC_DELAY; 1456250661Sdavidcs while (i) { 1457330555Sdavidcs 1458330555Sdavidcs if (ha->qla_initiate_recovery) { 1459330555Sdavidcs ql_sp_log(ha, 4, 1, ha->qla_initiate_recovery, 0, 0, 0, 0); 1460330555Sdavidcs return (-1); 1461330555Sdavidcs } 1462330555Sdavidcs 1463250661Sdavidcs data = READ_REG32(ha, Q8_FW_MBOX_CNTRL); 1464250661Sdavidcs 1465250661Sdavidcs if ((data & 0x3) == 1) { 1466250661Sdavidcs data = READ_REG32(ha, Q8_FW_MBOX0); 1467250661Sdavidcs if ((data & 0xF000) != 0x8000) 1468250661Sdavidcs break; 1469250661Sdavidcs } 1470250661Sdavidcs if (no_pause) { 1471250661Sdavidcs DELAY(1000); 1472250661Sdavidcs } else { 1473250661Sdavidcs qla_mdelay(__func__, 1); 1474250661Sdavidcs } 1475250661Sdavidcs i--; 1476250661Sdavidcs } 1477250661Sdavidcs if (i == 0) { 1478250661Sdavidcs device_printf(ha->pci_dev, "%s: fw_mbx_cntrl 0x%08x\n", 1479250661Sdavidcs __func__, data); 1480330555Sdavidcs ql_sp_log(ha, 5, 1, data, 0, 0, 0, 0); 1481250661Sdavidcs ret = -2; 1482330555Sdavidcs ha->hw.mbx_comp_msecs[(Q8_MBX_COMP_MSECS - 1)]++; 1483330555Sdavidcs QL_INITIATE_RECOVERY(ha); 1484250661Sdavidcs goto exit_qla_mbx_cmd; 1485250661Sdavidcs } 1486250661Sdavidcs 1487250661Sdavidcs for (i = 0; i < n_fwmbox; i++) { 1488330555Sdavidcs 1489330555Sdavidcs if (ha->qla_initiate_recovery) { 1490330555Sdavidcs ql_sp_log(ha, 6, 1, ha->qla_initiate_recovery, 0, 0, 0, 0); 1491330555Sdavidcs return (-1); 1492330555Sdavidcs } 1493330555Sdavidcs 1494250661Sdavidcs *fw_mbox++ = READ_REG32(ha, (Q8_FW_MBOX0 + (i << 2))); 1495250661Sdavidcs } 1496250661Sdavidcs 1497250661Sdavidcs WRITE_REG32(ha, Q8_FW_MBOX_CNTRL, 0x0); 1498250661Sdavidcs WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0); 1499250661Sdavidcs 1500330555Sdavidcs end_usecs = qla_get_usec_timestamp(); 1501330555Sdavidcs 1502330555Sdavidcs if (end_usecs > start_usecs) { 1503330555Sdavidcs msecs_200 = (end_usecs - start_usecs)/(1000 * 200); 1504330555Sdavidcs 1505330555Sdavidcs if (msecs_200 < 15) 1506330555Sdavidcs ha->hw.mbx_comp_msecs[msecs_200]++; 1507330555Sdavidcs else if (msecs_200 < 20) 1508330555Sdavidcs ha->hw.mbx_comp_msecs[15]++; 1509330555Sdavidcs else { 1510330555Sdavidcs device_printf(ha->pci_dev, "%s: [%ld, %ld] %ld\n", __func__, 1511330555Sdavidcs start_usecs, end_usecs, msecs_200); 1512330555Sdavidcs ha->hw.mbx_comp_msecs[16]++; 1513330555Sdavidcs } 1514330555Sdavidcs } 1515330555Sdavidcs ql_sp_log(ha, 7, 5, fw_mbox[0], fw_mbox[1], fw_mbox[2], fw_mbox[3], fw_mbox[4]); 1516330555Sdavidcs 1517330555Sdavidcs 1518250661Sdavidcsexit_qla_mbx_cmd: 1519250661Sdavidcs return (ret); 1520250661Sdavidcs} 1521250661Sdavidcs 1522284741Sdavidcsint 1523284741Sdavidcsqla_get_nic_partition(qla_host_t *ha, uint32_t *supports_9kb, 1524284741Sdavidcs uint32_t *num_rcvq) 1525250661Sdavidcs{ 1526250661Sdavidcs uint32_t *mbox, err; 1527250661Sdavidcs device_t dev = ha->pci_dev; 1528250661Sdavidcs 1529250661Sdavidcs bzero(ha->hw.mbox, (sizeof (uint32_t) * Q8_NUM_MBOX)); 1530250661Sdavidcs 1531250661Sdavidcs mbox = ha->hw.mbox; 1532250661Sdavidcs 1533250661Sdavidcs mbox[0] = Q8_MBX_GET_NIC_PARTITION | (0x2 << 16) | (0x2 << 29); 1534250661Sdavidcs 1535250661Sdavidcs if (qla_mbx_cmd(ha, mbox, 2, mbox, 19, 0)) { 1536250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 1537250661Sdavidcs return (-1); 1538250661Sdavidcs } 1539250661Sdavidcs err = mbox[0] >> 25; 1540250661Sdavidcs 1541284741Sdavidcs if (supports_9kb != NULL) { 1542284741Sdavidcs if (mbox[16] & 0x80) /* bit 7 of mbox 16 */ 1543284741Sdavidcs *supports_9kb = 1; 1544284741Sdavidcs else 1545284741Sdavidcs *supports_9kb = 0; 1546284741Sdavidcs } 1547284741Sdavidcs 1548284741Sdavidcs if (num_rcvq != NULL) 1549284741Sdavidcs *num_rcvq = ((mbox[6] >> 16) & 0xFFFF); 1550284741Sdavidcs 1551250661Sdavidcs if ((err != 1) && (err != 0)) { 1552250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 1553250661Sdavidcs return (-1); 1554250661Sdavidcs } 1555250661Sdavidcs return 0; 1556250661Sdavidcs} 1557250661Sdavidcs 1558250661Sdavidcsstatic int 1559284741Sdavidcsqla_config_intr_cntxt(qla_host_t *ha, uint32_t start_idx, uint32_t num_intrs, 1560284741Sdavidcs uint32_t create) 1561250661Sdavidcs{ 1562250661Sdavidcs uint32_t i, err; 1563250661Sdavidcs device_t dev = ha->pci_dev; 1564250661Sdavidcs q80_config_intr_t *c_intr; 1565250661Sdavidcs q80_config_intr_rsp_t *c_intr_rsp; 1566250661Sdavidcs 1567250661Sdavidcs c_intr = (q80_config_intr_t *)ha->hw.mbox; 1568250661Sdavidcs bzero(c_intr, (sizeof (q80_config_intr_t))); 1569250661Sdavidcs 1570250661Sdavidcs c_intr->opcode = Q8_MBX_CONFIG_INTR; 1571250661Sdavidcs 1572250661Sdavidcs c_intr->count_version = (sizeof (q80_config_intr_t) >> 2); 1573250661Sdavidcs c_intr->count_version |= Q8_MBX_CMD_VERSION; 1574250661Sdavidcs 1575250661Sdavidcs c_intr->nentries = num_intrs; 1576250661Sdavidcs 1577250661Sdavidcs for (i = 0; i < num_intrs; i++) { 1578250661Sdavidcs if (create) { 1579250661Sdavidcs c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_CREATE; 1580284741Sdavidcs c_intr->intr[i].msix_index = start_idx + 1 + i; 1581250661Sdavidcs } else { 1582250661Sdavidcs c_intr->intr[i].cmd_type = Q8_MBX_CONFIG_INTR_DELETE; 1583284741Sdavidcs c_intr->intr[i].msix_index = 1584284741Sdavidcs ha->hw.intr_id[(start_idx + i)]; 1585250661Sdavidcs } 1586250661Sdavidcs 1587250661Sdavidcs c_intr->intr[i].cmd_type |= Q8_MBX_CONFIG_INTR_TYPE_MSI_X; 1588250661Sdavidcs } 1589250661Sdavidcs 1590250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)c_intr, 1591250661Sdavidcs (sizeof (q80_config_intr_t) >> 2), 1592250661Sdavidcs ha->hw.mbox, (sizeof (q80_config_intr_rsp_t) >> 2), 0)) { 1593330555Sdavidcs device_printf(dev, "%s: %s failed0\n", __func__, 1594330555Sdavidcs (create ? "create" : "delete")); 1595250661Sdavidcs return (-1); 1596250661Sdavidcs } 1597250661Sdavidcs 1598250661Sdavidcs c_intr_rsp = (q80_config_intr_rsp_t *)ha->hw.mbox; 1599250661Sdavidcs 1600250661Sdavidcs err = Q8_MBX_RSP_STATUS(c_intr_rsp->regcnt_status); 1601250661Sdavidcs 1602250661Sdavidcs if (err) { 1603330555Sdavidcs device_printf(dev, "%s: %s failed1 [0x%08x, %d]\n", __func__, 1604330555Sdavidcs (create ? "create" : "delete"), err, c_intr_rsp->nentries); 1605250661Sdavidcs 1606250661Sdavidcs for (i = 0; i < c_intr_rsp->nentries; i++) { 1607250661Sdavidcs device_printf(dev, "%s: [%d]:[0x%x 0x%x 0x%x]\n", 1608250661Sdavidcs __func__, i, 1609250661Sdavidcs c_intr_rsp->intr[i].status, 1610250661Sdavidcs c_intr_rsp->intr[i].intr_id, 1611250661Sdavidcs c_intr_rsp->intr[i].intr_src); 1612250661Sdavidcs } 1613250661Sdavidcs 1614250661Sdavidcs return (-1); 1615250661Sdavidcs } 1616250661Sdavidcs 1617250661Sdavidcs for (i = 0; ((i < num_intrs) && create); i++) { 1618250661Sdavidcs if (!c_intr_rsp->intr[i].status) { 1619284741Sdavidcs ha->hw.intr_id[(start_idx + i)] = 1620284741Sdavidcs c_intr_rsp->intr[i].intr_id; 1621284741Sdavidcs ha->hw.intr_src[(start_idx + i)] = 1622284741Sdavidcs c_intr_rsp->intr[i].intr_src; 1623250661Sdavidcs } 1624250661Sdavidcs } 1625250661Sdavidcs 1626250661Sdavidcs return (0); 1627250661Sdavidcs} 1628250661Sdavidcs 1629250661Sdavidcs/* 1630250661Sdavidcs * Name: qla_config_rss 1631250661Sdavidcs * Function: Configure RSS for the context/interface. 1632250661Sdavidcs */ 1633250661Sdavidcsstatic const uint64_t rss_key[] = { 0xbeac01fa6a42b73bULL, 1634250661Sdavidcs 0x8030f20c77cb2da3ULL, 1635250661Sdavidcs 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, 1636250661Sdavidcs 0x255b0ec26d5a56daULL }; 1637250661Sdavidcs 1638250661Sdavidcsstatic int 1639250661Sdavidcsqla_config_rss(qla_host_t *ha, uint16_t cntxt_id) 1640250661Sdavidcs{ 1641250661Sdavidcs q80_config_rss_t *c_rss; 1642250661Sdavidcs q80_config_rss_rsp_t *c_rss_rsp; 1643250661Sdavidcs uint32_t err, i; 1644250661Sdavidcs device_t dev = ha->pci_dev; 1645250661Sdavidcs 1646250661Sdavidcs c_rss = (q80_config_rss_t *)ha->hw.mbox; 1647250661Sdavidcs bzero(c_rss, (sizeof (q80_config_rss_t))); 1648250661Sdavidcs 1649250661Sdavidcs c_rss->opcode = Q8_MBX_CONFIG_RSS; 1650250661Sdavidcs 1651250661Sdavidcs c_rss->count_version = (sizeof (q80_config_rss_t) >> 2); 1652250661Sdavidcs c_rss->count_version |= Q8_MBX_CMD_VERSION; 1653250661Sdavidcs 1654250661Sdavidcs c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP_IP | 1655250661Sdavidcs Q8_MBX_RSS_HASH_TYPE_IPV6_TCP_IP); 1656284741Sdavidcs //c_rss->hash_type = (Q8_MBX_RSS_HASH_TYPE_IPV4_TCP | 1657284741Sdavidcs // Q8_MBX_RSS_HASH_TYPE_IPV6_TCP); 1658250661Sdavidcs 1659250661Sdavidcs c_rss->flags = Q8_MBX_RSS_FLAGS_ENABLE_RSS; 1660250661Sdavidcs c_rss->flags |= Q8_MBX_RSS_FLAGS_USE_IND_TABLE; 1661250661Sdavidcs 1662250661Sdavidcs c_rss->indtbl_mask = Q8_MBX_RSS_INDTBL_MASK; 1663250661Sdavidcs 1664250661Sdavidcs c_rss->indtbl_mask |= Q8_MBX_RSS_FLAGS_MULTI_RSS_VALID; 1665250661Sdavidcs c_rss->flags |= Q8_MBX_RSS_FLAGS_TYPE_CRSS; 1666250661Sdavidcs 1667250661Sdavidcs c_rss->cntxt_id = cntxt_id; 1668250661Sdavidcs 1669250661Sdavidcs for (i = 0; i < 5; i++) { 1670250661Sdavidcs c_rss->rss_key[i] = rss_key[i]; 1671250661Sdavidcs } 1672250661Sdavidcs 1673250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)c_rss, 1674250661Sdavidcs (sizeof (q80_config_rss_t) >> 2), 1675250661Sdavidcs ha->hw.mbox, (sizeof(q80_config_rss_rsp_t) >> 2), 0)) { 1676250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 1677250661Sdavidcs return (-1); 1678250661Sdavidcs } 1679250661Sdavidcs c_rss_rsp = (q80_config_rss_rsp_t *)ha->hw.mbox; 1680250661Sdavidcs 1681250661Sdavidcs err = Q8_MBX_RSP_STATUS(c_rss_rsp->regcnt_status); 1682250661Sdavidcs 1683250661Sdavidcs if (err) { 1684250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 1685250661Sdavidcs return (-1); 1686250661Sdavidcs } 1687250661Sdavidcs return 0; 1688250661Sdavidcs} 1689250661Sdavidcs 1690250661Sdavidcsstatic int 1691250661Sdavidcsqla_set_rss_ind_table(qla_host_t *ha, uint32_t start_idx, uint32_t count, 1692250661Sdavidcs uint16_t cntxt_id, uint8_t *ind_table) 1693250661Sdavidcs{ 1694250661Sdavidcs q80_config_rss_ind_table_t *c_rss_ind; 1695250661Sdavidcs q80_config_rss_ind_table_rsp_t *c_rss_ind_rsp; 1696250661Sdavidcs uint32_t err; 1697250661Sdavidcs device_t dev = ha->pci_dev; 1698250661Sdavidcs 1699250661Sdavidcs if ((count > Q8_RSS_IND_TBL_SIZE) || 1700250661Sdavidcs ((start_idx + count - 1) > Q8_RSS_IND_TBL_MAX_IDX)) { 1701250661Sdavidcs device_printf(dev, "%s: illegal count [%d, %d]\n", __func__, 1702250661Sdavidcs start_idx, count); 1703250661Sdavidcs return (-1); 1704250661Sdavidcs } 1705250661Sdavidcs 1706250661Sdavidcs c_rss_ind = (q80_config_rss_ind_table_t *)ha->hw.mbox; 1707250661Sdavidcs bzero(c_rss_ind, sizeof (q80_config_rss_ind_table_t)); 1708250661Sdavidcs 1709250661Sdavidcs c_rss_ind->opcode = Q8_MBX_CONFIG_RSS_TABLE; 1710250661Sdavidcs c_rss_ind->count_version = (sizeof (q80_config_rss_ind_table_t) >> 2); 1711250661Sdavidcs c_rss_ind->count_version |= Q8_MBX_CMD_VERSION; 1712250661Sdavidcs 1713250661Sdavidcs c_rss_ind->start_idx = start_idx; 1714250661Sdavidcs c_rss_ind->end_idx = start_idx + count - 1; 1715250661Sdavidcs c_rss_ind->cntxt_id = cntxt_id; 1716250661Sdavidcs bcopy(ind_table, c_rss_ind->ind_table, count); 1717250661Sdavidcs 1718250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)c_rss_ind, 1719250661Sdavidcs (sizeof (q80_config_rss_ind_table_t) >> 2), ha->hw.mbox, 1720250661Sdavidcs (sizeof(q80_config_rss_ind_table_rsp_t) >> 2), 0)) { 1721250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 1722250661Sdavidcs return (-1); 1723250661Sdavidcs } 1724250661Sdavidcs 1725250661Sdavidcs c_rss_ind_rsp = (q80_config_rss_ind_table_rsp_t *)ha->hw.mbox; 1726250661Sdavidcs err = Q8_MBX_RSP_STATUS(c_rss_ind_rsp->regcnt_status); 1727250661Sdavidcs 1728250661Sdavidcs if (err) { 1729250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 1730250661Sdavidcs return (-1); 1731250661Sdavidcs } 1732250661Sdavidcs return 0; 1733250661Sdavidcs} 1734250661Sdavidcs 1735250661Sdavidcs/* 1736250661Sdavidcs * Name: qla_config_intr_coalesce 1737250661Sdavidcs * Function: Configure Interrupt Coalescing. 1738250661Sdavidcs */ 1739250661Sdavidcsstatic int 1740284741Sdavidcsqla_config_intr_coalesce(qla_host_t *ha, uint16_t cntxt_id, int tenable, 1741284741Sdavidcs int rcv) 1742250661Sdavidcs{ 1743250661Sdavidcs q80_config_intr_coalesc_t *intrc; 1744250661Sdavidcs q80_config_intr_coalesc_rsp_t *intrc_rsp; 1745250661Sdavidcs uint32_t err, i; 1746250661Sdavidcs device_t dev = ha->pci_dev; 1747250661Sdavidcs 1748250661Sdavidcs intrc = (q80_config_intr_coalesc_t *)ha->hw.mbox; 1749250661Sdavidcs bzero(intrc, (sizeof (q80_config_intr_coalesc_t))); 1750250661Sdavidcs 1751250661Sdavidcs intrc->opcode = Q8_MBX_CONFIG_INTR_COALESCE; 1752250661Sdavidcs intrc->count_version = (sizeof (q80_config_intr_coalesc_t) >> 2); 1753250661Sdavidcs intrc->count_version |= Q8_MBX_CMD_VERSION; 1754250661Sdavidcs 1755284741Sdavidcs if (rcv) { 1756284741Sdavidcs intrc->flags = Q8_MBX_INTRC_FLAGS_RCV; 1757284741Sdavidcs intrc->max_pkts = ha->hw.rcv_intr_coalesce & 0xFFFF; 1758284741Sdavidcs intrc->max_mswait = (ha->hw.rcv_intr_coalesce >> 16) & 0xFFFF; 1759284741Sdavidcs } else { 1760284741Sdavidcs intrc->flags = Q8_MBX_INTRC_FLAGS_XMT; 1761284741Sdavidcs intrc->max_pkts = ha->hw.xmt_intr_coalesce & 0xFFFF; 1762284741Sdavidcs intrc->max_mswait = (ha->hw.xmt_intr_coalesce >> 16) & 0xFFFF; 1763284741Sdavidcs } 1764284741Sdavidcs 1765250661Sdavidcs intrc->cntxt_id = cntxt_id; 1766250661Sdavidcs 1767250661Sdavidcs if (tenable) { 1768250661Sdavidcs intrc->flags |= Q8_MBX_INTRC_FLAGS_PERIODIC; 1769250661Sdavidcs intrc->timer_type = Q8_MBX_INTRC_TIMER_PERIODIC; 1770250661Sdavidcs 1771250661Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; i++) { 1772250661Sdavidcs intrc->sds_ring_mask |= (1 << i); 1773250661Sdavidcs } 1774250661Sdavidcs intrc->ms_timeout = 1000; 1775250661Sdavidcs } 1776250661Sdavidcs 1777250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)intrc, 1778250661Sdavidcs (sizeof (q80_config_intr_coalesc_t) >> 2), 1779250661Sdavidcs ha->hw.mbox, (sizeof(q80_config_intr_coalesc_rsp_t) >> 2), 0)) { 1780250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 1781250661Sdavidcs return (-1); 1782250661Sdavidcs } 1783250661Sdavidcs intrc_rsp = (q80_config_intr_coalesc_rsp_t *)ha->hw.mbox; 1784250661Sdavidcs 1785250661Sdavidcs err = Q8_MBX_RSP_STATUS(intrc_rsp->regcnt_status); 1786250661Sdavidcs 1787250661Sdavidcs if (err) { 1788250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 1789250661Sdavidcs return (-1); 1790250661Sdavidcs } 1791250661Sdavidcs 1792250661Sdavidcs return 0; 1793250661Sdavidcs} 1794250661Sdavidcs 1795250661Sdavidcs 1796250661Sdavidcs/* 1797250661Sdavidcs * Name: qla_config_mac_addr 1798250661Sdavidcs * Function: binds a MAC address to the context/interface. 1799250661Sdavidcs * Can be unicast, multicast or broadcast. 1800250661Sdavidcs */ 1801250661Sdavidcsstatic int 1802307524Sdavidcsqla_config_mac_addr(qla_host_t *ha, uint8_t *mac_addr, uint32_t add_mac, 1803307524Sdavidcs uint32_t num_mac) 1804250661Sdavidcs{ 1805250661Sdavidcs q80_config_mac_addr_t *cmac; 1806250661Sdavidcs q80_config_mac_addr_rsp_t *cmac_rsp; 1807250661Sdavidcs uint32_t err; 1808250661Sdavidcs device_t dev = ha->pci_dev; 1809307524Sdavidcs int i; 1810307524Sdavidcs uint8_t *mac_cpy = mac_addr; 1811250661Sdavidcs 1812307524Sdavidcs if (num_mac > Q8_MAX_MAC_ADDRS) { 1813307524Sdavidcs device_printf(dev, "%s: %s num_mac [0x%x] > Q8_MAX_MAC_ADDRS\n", 1814307524Sdavidcs __func__, (add_mac ? "Add" : "Del"), num_mac); 1815307524Sdavidcs return (-1); 1816307524Sdavidcs } 1817307524Sdavidcs 1818250661Sdavidcs cmac = (q80_config_mac_addr_t *)ha->hw.mbox; 1819250661Sdavidcs bzero(cmac, (sizeof (q80_config_mac_addr_t))); 1820250661Sdavidcs 1821250661Sdavidcs cmac->opcode = Q8_MBX_CONFIG_MAC_ADDR; 1822250661Sdavidcs cmac->count_version = sizeof (q80_config_mac_addr_t) >> 2; 1823250661Sdavidcs cmac->count_version |= Q8_MBX_CMD_VERSION; 1824250661Sdavidcs 1825250661Sdavidcs if (add_mac) 1826250661Sdavidcs cmac->cmd = Q8_MBX_CMAC_CMD_ADD_MAC_ADDR; 1827250661Sdavidcs else 1828250661Sdavidcs cmac->cmd = Q8_MBX_CMAC_CMD_DEL_MAC_ADDR; 1829250661Sdavidcs 1830250661Sdavidcs cmac->cmd |= Q8_MBX_CMAC_CMD_CAM_INGRESS; 1831250661Sdavidcs 1832307524Sdavidcs cmac->nmac_entries = num_mac; 1833250661Sdavidcs cmac->cntxt_id = ha->hw.rcv_cntxt_id; 1834250661Sdavidcs 1835307524Sdavidcs for (i = 0; i < num_mac; i++) { 1836307524Sdavidcs bcopy(mac_addr, cmac->mac_addr[i].addr, Q8_ETHER_ADDR_LEN); 1837307524Sdavidcs mac_addr = mac_addr + ETHER_ADDR_LEN; 1838307524Sdavidcs } 1839307524Sdavidcs 1840250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)cmac, 1841250661Sdavidcs (sizeof (q80_config_mac_addr_t) >> 2), 1842250661Sdavidcs ha->hw.mbox, (sizeof(q80_config_mac_addr_rsp_t) >> 2), 1)) { 1843250661Sdavidcs device_printf(dev, "%s: %s failed0\n", __func__, 1844250661Sdavidcs (add_mac ? "Add" : "Del")); 1845250661Sdavidcs return (-1); 1846250661Sdavidcs } 1847250661Sdavidcs cmac_rsp = (q80_config_mac_addr_rsp_t *)ha->hw.mbox; 1848250661Sdavidcs 1849250661Sdavidcs err = Q8_MBX_RSP_STATUS(cmac_rsp->regcnt_status); 1850250661Sdavidcs 1851250661Sdavidcs if (err) { 1852307524Sdavidcs device_printf(dev, "%s: %s failed1 [0x%08x]\n", __func__, 1853307524Sdavidcs (add_mac ? "Add" : "Del"), err); 1854307524Sdavidcs for (i = 0; i < num_mac; i++) { 1855307524Sdavidcs device_printf(dev, "%s: %02x:%02x:%02x:%02x:%02x:%02x\n", 1856307524Sdavidcs __func__, mac_cpy[0], mac_cpy[1], mac_cpy[2], 1857307524Sdavidcs mac_cpy[3], mac_cpy[4], mac_cpy[5]); 1858307524Sdavidcs mac_cpy += ETHER_ADDR_LEN; 1859307524Sdavidcs } 1860250661Sdavidcs return (-1); 1861250661Sdavidcs } 1862250661Sdavidcs 1863250661Sdavidcs return 0; 1864250661Sdavidcs} 1865250661Sdavidcs 1866250661Sdavidcs 1867250661Sdavidcs/* 1868250661Sdavidcs * Name: qla_set_mac_rcv_mode 1869305487Sdavidcs * Function: Enable/Disable AllMulticast and Promiscous Modes. 1870250661Sdavidcs */ 1871250661Sdavidcsstatic int 1872250661Sdavidcsqla_set_mac_rcv_mode(qla_host_t *ha, uint32_t mode) 1873250661Sdavidcs{ 1874250661Sdavidcs q80_config_mac_rcv_mode_t *rcv_mode; 1875250661Sdavidcs uint32_t err; 1876250661Sdavidcs q80_config_mac_rcv_mode_rsp_t *rcv_mode_rsp; 1877250661Sdavidcs device_t dev = ha->pci_dev; 1878250661Sdavidcs 1879250661Sdavidcs rcv_mode = (q80_config_mac_rcv_mode_t *)ha->hw.mbox; 1880250661Sdavidcs bzero(rcv_mode, (sizeof (q80_config_mac_rcv_mode_t))); 1881250661Sdavidcs 1882250661Sdavidcs rcv_mode->opcode = Q8_MBX_CONFIG_MAC_RX_MODE; 1883250661Sdavidcs rcv_mode->count_version = sizeof (q80_config_mac_rcv_mode_t) >> 2; 1884250661Sdavidcs rcv_mode->count_version |= Q8_MBX_CMD_VERSION; 1885250661Sdavidcs 1886250661Sdavidcs rcv_mode->mode = mode; 1887250661Sdavidcs 1888250661Sdavidcs rcv_mode->cntxt_id = ha->hw.rcv_cntxt_id; 1889250661Sdavidcs 1890250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)rcv_mode, 1891250661Sdavidcs (sizeof (q80_config_mac_rcv_mode_t) >> 2), 1892250661Sdavidcs ha->hw.mbox, (sizeof(q80_config_mac_rcv_mode_rsp_t) >> 2), 1)) { 1893250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 1894250661Sdavidcs return (-1); 1895250661Sdavidcs } 1896250661Sdavidcs rcv_mode_rsp = (q80_config_mac_rcv_mode_rsp_t *)ha->hw.mbox; 1897250661Sdavidcs 1898250661Sdavidcs err = Q8_MBX_RSP_STATUS(rcv_mode_rsp->regcnt_status); 1899250661Sdavidcs 1900250661Sdavidcs if (err) { 1901250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 1902250661Sdavidcs return (-1); 1903250661Sdavidcs } 1904250661Sdavidcs 1905250661Sdavidcs return 0; 1906250661Sdavidcs} 1907250661Sdavidcs 1908250661Sdavidcsint 1909250661Sdavidcsql_set_promisc(qla_host_t *ha) 1910250661Sdavidcs{ 1911250661Sdavidcs int ret; 1912250661Sdavidcs 1913250661Sdavidcs ha->hw.mac_rcv_mode |= Q8_MBX_MAC_RCV_PROMISC_ENABLE; 1914250661Sdavidcs ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode); 1915250661Sdavidcs return (ret); 1916250661Sdavidcs} 1917250661Sdavidcs 1918284741Sdavidcsvoid 1919284741Sdavidcsqla_reset_promisc(qla_host_t *ha) 1920284741Sdavidcs{ 1921284741Sdavidcs ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_RCV_PROMISC_ENABLE; 1922284741Sdavidcs (void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode); 1923284741Sdavidcs} 1924284741Sdavidcs 1925250661Sdavidcsint 1926250661Sdavidcsql_set_allmulti(qla_host_t *ha) 1927250661Sdavidcs{ 1928250661Sdavidcs int ret; 1929250661Sdavidcs 1930250661Sdavidcs ha->hw.mac_rcv_mode |= Q8_MBX_MAC_ALL_MULTI_ENABLE; 1931250661Sdavidcs ret = qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode); 1932250661Sdavidcs return (ret); 1933250661Sdavidcs} 1934250661Sdavidcs 1935284741Sdavidcsvoid 1936284741Sdavidcsqla_reset_allmulti(qla_host_t *ha) 1937284741Sdavidcs{ 1938284741Sdavidcs ha->hw.mac_rcv_mode &= ~Q8_MBX_MAC_ALL_MULTI_ENABLE; 1939284741Sdavidcs (void)qla_set_mac_rcv_mode(ha, ha->hw.mac_rcv_mode); 1940284741Sdavidcs} 1941250661Sdavidcs 1942250661Sdavidcs/* 1943250661Sdavidcs * Name: ql_set_max_mtu 1944250661Sdavidcs * Function: 1945250661Sdavidcs * Sets the maximum transfer unit size for the specified rcv context. 1946250661Sdavidcs */ 1947250661Sdavidcsint 1948250661Sdavidcsql_set_max_mtu(qla_host_t *ha, uint32_t mtu, uint16_t cntxt_id) 1949250661Sdavidcs{ 1950250661Sdavidcs device_t dev; 1951250661Sdavidcs q80_set_max_mtu_t *max_mtu; 1952250661Sdavidcs q80_set_max_mtu_rsp_t *max_mtu_rsp; 1953250661Sdavidcs uint32_t err; 1954250661Sdavidcs 1955250661Sdavidcs dev = ha->pci_dev; 1956250661Sdavidcs 1957250661Sdavidcs max_mtu = (q80_set_max_mtu_t *)ha->hw.mbox; 1958250661Sdavidcs bzero(max_mtu, (sizeof (q80_set_max_mtu_t))); 1959250661Sdavidcs 1960250661Sdavidcs max_mtu->opcode = Q8_MBX_SET_MAX_MTU; 1961250661Sdavidcs max_mtu->count_version = (sizeof (q80_set_max_mtu_t) >> 2); 1962250661Sdavidcs max_mtu->count_version |= Q8_MBX_CMD_VERSION; 1963250661Sdavidcs 1964250661Sdavidcs max_mtu->cntxt_id = cntxt_id; 1965250661Sdavidcs max_mtu->mtu = mtu; 1966250661Sdavidcs 1967250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)max_mtu, 1968250661Sdavidcs (sizeof (q80_set_max_mtu_t) >> 2), 1969250661Sdavidcs ha->hw.mbox, (sizeof (q80_set_max_mtu_rsp_t) >> 2), 1)) { 1970250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 1971250661Sdavidcs return -1; 1972250661Sdavidcs } 1973250661Sdavidcs 1974250661Sdavidcs max_mtu_rsp = (q80_set_max_mtu_rsp_t *)ha->hw.mbox; 1975250661Sdavidcs 1976250661Sdavidcs err = Q8_MBX_RSP_STATUS(max_mtu_rsp->regcnt_status); 1977250661Sdavidcs 1978250661Sdavidcs if (err) { 1979250661Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 1980250661Sdavidcs } 1981250661Sdavidcs 1982250661Sdavidcs return 0; 1983250661Sdavidcs} 1984250661Sdavidcs 1985250661Sdavidcsstatic int 1986250661Sdavidcsqla_link_event_req(qla_host_t *ha, uint16_t cntxt_id) 1987250661Sdavidcs{ 1988250661Sdavidcs device_t dev; 1989250661Sdavidcs q80_link_event_t *lnk; 1990250661Sdavidcs q80_link_event_rsp_t *lnk_rsp; 1991250661Sdavidcs uint32_t err; 1992250661Sdavidcs 1993250661Sdavidcs dev = ha->pci_dev; 1994250661Sdavidcs 1995250661Sdavidcs lnk = (q80_link_event_t *)ha->hw.mbox; 1996250661Sdavidcs bzero(lnk, (sizeof (q80_link_event_t))); 1997250661Sdavidcs 1998250661Sdavidcs lnk->opcode = Q8_MBX_LINK_EVENT_REQ; 1999250661Sdavidcs lnk->count_version = (sizeof (q80_link_event_t) >> 2); 2000250661Sdavidcs lnk->count_version |= Q8_MBX_CMD_VERSION; 2001250661Sdavidcs 2002250661Sdavidcs lnk->cntxt_id = cntxt_id; 2003250661Sdavidcs lnk->cmd = Q8_LINK_EVENT_CMD_ENABLE_ASYNC; 2004250661Sdavidcs 2005250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)lnk, (sizeof (q80_link_event_t) >> 2), 2006250661Sdavidcs ha->hw.mbox, (sizeof (q80_link_event_rsp_t) >> 2), 0)) { 2007250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 2008250661Sdavidcs return -1; 2009250661Sdavidcs } 2010250661Sdavidcs 2011250661Sdavidcs lnk_rsp = (q80_link_event_rsp_t *)ha->hw.mbox; 2012250661Sdavidcs 2013250661Sdavidcs err = Q8_MBX_RSP_STATUS(lnk_rsp->regcnt_status); 2014250661Sdavidcs 2015250661Sdavidcs if (err) { 2016250661Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 2017250661Sdavidcs } 2018250661Sdavidcs 2019250661Sdavidcs return 0; 2020250661Sdavidcs} 2021250661Sdavidcs 2022250661Sdavidcsstatic int 2023250661Sdavidcsqla_config_fw_lro(qla_host_t *ha, uint16_t cntxt_id) 2024250661Sdavidcs{ 2025250661Sdavidcs device_t dev; 2026250661Sdavidcs q80_config_fw_lro_t *fw_lro; 2027250661Sdavidcs q80_config_fw_lro_rsp_t *fw_lro_rsp; 2028250661Sdavidcs uint32_t err; 2029250661Sdavidcs 2030250661Sdavidcs dev = ha->pci_dev; 2031250661Sdavidcs 2032250661Sdavidcs fw_lro = (q80_config_fw_lro_t *)ha->hw.mbox; 2033250661Sdavidcs bzero(fw_lro, sizeof(q80_config_fw_lro_t)); 2034250661Sdavidcs 2035250661Sdavidcs fw_lro->opcode = Q8_MBX_CONFIG_FW_LRO; 2036250661Sdavidcs fw_lro->count_version = (sizeof (q80_config_fw_lro_t) >> 2); 2037250661Sdavidcs fw_lro->count_version |= Q8_MBX_CMD_VERSION; 2038250661Sdavidcs 2039250661Sdavidcs fw_lro->flags |= Q8_MBX_FW_LRO_IPV4 | Q8_MBX_FW_LRO_IPV4_WO_DST_IP_CHK; 2040284741Sdavidcs fw_lro->flags |= Q8_MBX_FW_LRO_IPV6 | Q8_MBX_FW_LRO_IPV6_WO_DST_IP_CHK; 2041250661Sdavidcs 2042250661Sdavidcs fw_lro->cntxt_id = cntxt_id; 2043250661Sdavidcs 2044250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)fw_lro, 2045250661Sdavidcs (sizeof (q80_config_fw_lro_t) >> 2), 2046250661Sdavidcs ha->hw.mbox, (sizeof (q80_config_fw_lro_rsp_t) >> 2), 0)) { 2047250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 2048250661Sdavidcs return -1; 2049250661Sdavidcs } 2050250661Sdavidcs 2051250661Sdavidcs fw_lro_rsp = (q80_config_fw_lro_rsp_t *)ha->hw.mbox; 2052250661Sdavidcs 2053250661Sdavidcs err = Q8_MBX_RSP_STATUS(fw_lro_rsp->regcnt_status); 2054250661Sdavidcs 2055250661Sdavidcs if (err) { 2056250661Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 2057250661Sdavidcs } 2058250661Sdavidcs 2059250661Sdavidcs return 0; 2060250661Sdavidcs} 2061250661Sdavidcs 2062305488Sdavidcsstatic int 2063305488Sdavidcsqla_set_cam_search_mode(qla_host_t *ha, uint32_t search_mode) 2064305488Sdavidcs{ 2065305488Sdavidcs device_t dev; 2066305488Sdavidcs q80_hw_config_t *hw_config; 2067305488Sdavidcs q80_hw_config_rsp_t *hw_config_rsp; 2068305488Sdavidcs uint32_t err; 2069305488Sdavidcs 2070305488Sdavidcs dev = ha->pci_dev; 2071305488Sdavidcs 2072305488Sdavidcs hw_config = (q80_hw_config_t *)ha->hw.mbox; 2073305488Sdavidcs bzero(hw_config, sizeof (q80_hw_config_t)); 2074305488Sdavidcs 2075305488Sdavidcs hw_config->opcode = Q8_MBX_HW_CONFIG; 2076305488Sdavidcs hw_config->count_version = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE_COUNT; 2077305488Sdavidcs hw_config->count_version |= Q8_MBX_CMD_VERSION; 2078305488Sdavidcs 2079305488Sdavidcs hw_config->cmd = Q8_HW_CONFIG_SET_CAM_SEARCH_MODE; 2080305488Sdavidcs 2081305488Sdavidcs hw_config->u.set_cam_search_mode.mode = search_mode; 2082305488Sdavidcs 2083305488Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)hw_config, 2084305488Sdavidcs (sizeof (q80_hw_config_t) >> 2), 2085305488Sdavidcs ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) { 2086305488Sdavidcs device_printf(dev, "%s: failed\n", __func__); 2087305488Sdavidcs return -1; 2088305488Sdavidcs } 2089305488Sdavidcs hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox; 2090305488Sdavidcs 2091305488Sdavidcs err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status); 2092305488Sdavidcs 2093305488Sdavidcs if (err) { 2094305488Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 2095305488Sdavidcs } 2096305488Sdavidcs 2097305488Sdavidcs return 0; 2098305488Sdavidcs} 2099305488Sdavidcs 2100305488Sdavidcsstatic int 2101305488Sdavidcsqla_get_cam_search_mode(qla_host_t *ha) 2102305488Sdavidcs{ 2103305488Sdavidcs device_t dev; 2104305488Sdavidcs q80_hw_config_t *hw_config; 2105305488Sdavidcs q80_hw_config_rsp_t *hw_config_rsp; 2106305488Sdavidcs uint32_t err; 2107305488Sdavidcs 2108305488Sdavidcs dev = ha->pci_dev; 2109305488Sdavidcs 2110305488Sdavidcs hw_config = (q80_hw_config_t *)ha->hw.mbox; 2111305488Sdavidcs bzero(hw_config, sizeof (q80_hw_config_t)); 2112305488Sdavidcs 2113305488Sdavidcs hw_config->opcode = Q8_MBX_HW_CONFIG; 2114305488Sdavidcs hw_config->count_version = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE_COUNT; 2115305488Sdavidcs hw_config->count_version |= Q8_MBX_CMD_VERSION; 2116305488Sdavidcs 2117305488Sdavidcs hw_config->cmd = Q8_HW_CONFIG_GET_CAM_SEARCH_MODE; 2118305488Sdavidcs 2119305488Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)hw_config, 2120305488Sdavidcs (sizeof (q80_hw_config_t) >> 2), 2121305488Sdavidcs ha->hw.mbox, (sizeof (q80_hw_config_rsp_t) >> 2), 0)) { 2122305488Sdavidcs device_printf(dev, "%s: failed\n", __func__); 2123305488Sdavidcs return -1; 2124305488Sdavidcs } 2125305488Sdavidcs hw_config_rsp = (q80_hw_config_rsp_t *)ha->hw.mbox; 2126305488Sdavidcs 2127305488Sdavidcs err = Q8_MBX_RSP_STATUS(hw_config_rsp->regcnt_status); 2128305488Sdavidcs 2129305488Sdavidcs if (err) { 2130305488Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 2131305488Sdavidcs } else { 2132305488Sdavidcs device_printf(dev, "%s: cam search mode [0x%08x]\n", __func__, 2133305488Sdavidcs hw_config_rsp->u.get_cam_search_mode.mode); 2134305488Sdavidcs } 2135305488Sdavidcs 2136305488Sdavidcs return 0; 2137305488Sdavidcs} 2138305488Sdavidcs 2139250661Sdavidcsstatic int 2140284741Sdavidcsqla_get_hw_stats(qla_host_t *ha, uint32_t cmd, uint32_t rsp_size) 2141250661Sdavidcs{ 2142250661Sdavidcs device_t dev; 2143250661Sdavidcs q80_get_stats_t *stat; 2144250661Sdavidcs q80_get_stats_rsp_t *stat_rsp; 2145250661Sdavidcs uint32_t err; 2146250661Sdavidcs 2147250661Sdavidcs dev = ha->pci_dev; 2148250661Sdavidcs 2149250661Sdavidcs stat = (q80_get_stats_t *)ha->hw.mbox; 2150250661Sdavidcs bzero(stat, (sizeof (q80_get_stats_t))); 2151250661Sdavidcs 2152250661Sdavidcs stat->opcode = Q8_MBX_GET_STATS; 2153250661Sdavidcs stat->count_version = 2; 2154250661Sdavidcs stat->count_version |= Q8_MBX_CMD_VERSION; 2155250661Sdavidcs 2156250661Sdavidcs stat->cmd = cmd; 2157250661Sdavidcs 2158250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)stat, 2, 2159284741Sdavidcs ha->hw.mbox, (rsp_size >> 2), 0)) { 2160250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 2161250661Sdavidcs return -1; 2162250661Sdavidcs } 2163250661Sdavidcs 2164250661Sdavidcs stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox; 2165250661Sdavidcs 2166250661Sdavidcs err = Q8_MBX_RSP_STATUS(stat_rsp->regcnt_status); 2167250661Sdavidcs 2168250661Sdavidcs if (err) { 2169250661Sdavidcs return -1; 2170250661Sdavidcs } 2171250661Sdavidcs 2172250661Sdavidcs return 0; 2173250661Sdavidcs} 2174250661Sdavidcs 2175250661Sdavidcsvoid 2176250661Sdavidcsql_get_stats(qla_host_t *ha) 2177250661Sdavidcs{ 2178250661Sdavidcs q80_get_stats_rsp_t *stat_rsp; 2179250661Sdavidcs q80_mac_stats_t *mstat; 2180250661Sdavidcs q80_xmt_stats_t *xstat; 2181250661Sdavidcs q80_rcv_stats_t *rstat; 2182250661Sdavidcs uint32_t cmd; 2183284741Sdavidcs int i; 2184322972Sdavidcs struct ifnet *ifp = ha->ifp; 2185250661Sdavidcs 2186322972Sdavidcs if (ifp == NULL) 2187322972Sdavidcs return; 2188322972Sdavidcs 2189322972Sdavidcs if (QLA_LOCK(ha, __func__, QLA_LOCK_DEFAULT_MS_TIMEOUT, 0) != 0) { 2190322972Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 2191322972Sdavidcs return; 2192322972Sdavidcs } 2193322972Sdavidcs 2194322972Sdavidcs if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) { 2195322972Sdavidcs QLA_UNLOCK(ha, __func__); 2196322972Sdavidcs return; 2197322972Sdavidcs } 2198322972Sdavidcs 2199250661Sdavidcs stat_rsp = (q80_get_stats_rsp_t *)ha->hw.mbox; 2200250661Sdavidcs /* 2201250661Sdavidcs * Get MAC Statistics 2202250661Sdavidcs */ 2203250661Sdavidcs cmd = Q8_GET_STATS_CMD_TYPE_MAC; 2204284741Sdavidcs// cmd |= Q8_GET_STATS_CMD_CLEAR; 2205250661Sdavidcs 2206250661Sdavidcs cmd |= ((ha->pci_func & 0x1) << 16); 2207250661Sdavidcs 2208330555Sdavidcs if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) || 2209330555Sdavidcs ha->offline) 2210322972Sdavidcs goto ql_get_stats_exit; 2211322972Sdavidcs 2212284741Sdavidcs if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) { 2213250661Sdavidcs mstat = (q80_mac_stats_t *)&stat_rsp->u.mac; 2214322972Sdavidcs bcopy(mstat, &ha->hw.mac, sizeof(q80_mac_stats_t)); 2215250661Sdavidcs } else { 2216250661Sdavidcs device_printf(ha->pci_dev, "%s: mac failed [0x%08x]\n", 2217250661Sdavidcs __func__, ha->hw.mbox[0]); 2218250661Sdavidcs } 2219250661Sdavidcs /* 2220250661Sdavidcs * Get RCV Statistics 2221250661Sdavidcs */ 2222250661Sdavidcs cmd = Q8_GET_STATS_CMD_RCV | Q8_GET_STATS_CMD_TYPE_CNTXT; 2223284741Sdavidcs// cmd |= Q8_GET_STATS_CMD_CLEAR; 2224250661Sdavidcs cmd |= (ha->hw.rcv_cntxt_id << 16); 2225250661Sdavidcs 2226330555Sdavidcs if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) || 2227330555Sdavidcs ha->offline) 2228322972Sdavidcs goto ql_get_stats_exit; 2229322972Sdavidcs 2230284741Sdavidcs if (qla_get_hw_stats(ha, cmd, sizeof (q80_get_stats_rsp_t)) == 0) { 2231250661Sdavidcs rstat = (q80_rcv_stats_t *)&stat_rsp->u.rcv; 2232322972Sdavidcs bcopy(rstat, &ha->hw.rcv, sizeof(q80_rcv_stats_t)); 2233250661Sdavidcs } else { 2234250661Sdavidcs device_printf(ha->pci_dev, "%s: rcv failed [0x%08x]\n", 2235250661Sdavidcs __func__, ha->hw.mbox[0]); 2236250661Sdavidcs } 2237322972Sdavidcs 2238330555Sdavidcs if (ha->qla_watchdog_pause || (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) || 2239330555Sdavidcs ha->offline) 2240322972Sdavidcs goto ql_get_stats_exit; 2241250661Sdavidcs /* 2242250661Sdavidcs * Get XMT Statistics 2243250661Sdavidcs */ 2244330555Sdavidcs for (i = 0 ; (i < ha->hw.num_tx_rings); i++) { 2245330555Sdavidcs if (ha->qla_watchdog_pause || 2246330555Sdavidcs (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) || 2247330555Sdavidcs ha->offline) 2248330555Sdavidcs goto ql_get_stats_exit; 2249330555Sdavidcs 2250284741Sdavidcs cmd = Q8_GET_STATS_CMD_XMT | Q8_GET_STATS_CMD_TYPE_CNTXT; 2251284741Sdavidcs// cmd |= Q8_GET_STATS_CMD_CLEAR; 2252284741Sdavidcs cmd |= (ha->hw.tx_cntxt[i].tx_cntxt_id << 16); 2253250661Sdavidcs 2254284741Sdavidcs if (qla_get_hw_stats(ha, cmd, sizeof(q80_get_stats_rsp_t)) 2255284741Sdavidcs == 0) { 2256284741Sdavidcs xstat = (q80_xmt_stats_t *)&stat_rsp->u.xmt; 2257322972Sdavidcs bcopy(xstat, &ha->hw.xmt[i], sizeof(q80_xmt_stats_t)); 2258284741Sdavidcs } else { 2259284741Sdavidcs device_printf(ha->pci_dev, "%s: xmt failed [0x%08x]\n", 2260284741Sdavidcs __func__, ha->hw.mbox[0]); 2261284741Sdavidcs } 2262284741Sdavidcs } 2263250661Sdavidcs 2264322972Sdavidcsql_get_stats_exit: 2265322972Sdavidcs QLA_UNLOCK(ha, __func__); 2266284741Sdavidcs 2267284741Sdavidcs return; 2268250661Sdavidcs} 2269250661Sdavidcs 2270250661Sdavidcs/* 2271250661Sdavidcs * Name: qla_tx_tso 2272250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for 2273250661Sdavidcs * Large TCP Segment Offload. If yes, the appropriate fields in the Tx 2274250661Sdavidcs * Ring Structure are plugged in. 2275250661Sdavidcs */ 2276250661Sdavidcsstatic int 2277250661Sdavidcsqla_tx_tso(qla_host_t *ha, struct mbuf *mp, q80_tx_cmd_t *tx_cmd, uint8_t *hdr) 2278250661Sdavidcs{ 2279250661Sdavidcs struct ether_vlan_header *eh; 2280250661Sdavidcs struct ip *ip = NULL; 2281250661Sdavidcs struct ip6_hdr *ip6 = NULL; 2282250661Sdavidcs struct tcphdr *th = NULL; 2283250661Sdavidcs uint32_t ehdrlen, hdrlen, ip_hlen, tcp_hlen, tcp_opt_off; 2284250661Sdavidcs uint16_t etype, opcode, offload = 1; 2285250661Sdavidcs device_t dev; 2286250661Sdavidcs 2287250661Sdavidcs dev = ha->pci_dev; 2288250661Sdavidcs 2289250661Sdavidcs 2290250661Sdavidcs eh = mtod(mp, struct ether_vlan_header *); 2291250661Sdavidcs 2292250661Sdavidcs if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 2293250661Sdavidcs ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 2294250661Sdavidcs etype = ntohs(eh->evl_proto); 2295250661Sdavidcs } else { 2296250661Sdavidcs ehdrlen = ETHER_HDR_LEN; 2297250661Sdavidcs etype = ntohs(eh->evl_encap_proto); 2298250661Sdavidcs } 2299250661Sdavidcs 2300250661Sdavidcs hdrlen = 0; 2301250661Sdavidcs 2302250661Sdavidcs switch (etype) { 2303250661Sdavidcs case ETHERTYPE_IP: 2304250661Sdavidcs 2305250661Sdavidcs tcp_opt_off = ehdrlen + sizeof(struct ip) + 2306250661Sdavidcs sizeof(struct tcphdr); 2307250661Sdavidcs 2308250661Sdavidcs if (mp->m_len < tcp_opt_off) { 2309250661Sdavidcs m_copydata(mp, 0, tcp_opt_off, hdr); 2310250661Sdavidcs ip = (struct ip *)(hdr + ehdrlen); 2311250661Sdavidcs } else { 2312250661Sdavidcs ip = (struct ip *)(mp->m_data + ehdrlen); 2313250661Sdavidcs } 2314250661Sdavidcs 2315250661Sdavidcs ip_hlen = ip->ip_hl << 2; 2316250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_TCP_LSO; 2317250661Sdavidcs 2318250661Sdavidcs 2319250661Sdavidcs if ((ip->ip_p != IPPROTO_TCP) || 2320250661Sdavidcs (ip_hlen != sizeof (struct ip))){ 2321250661Sdavidcs /* IP Options are not supported */ 2322250661Sdavidcs 2323250661Sdavidcs offload = 0; 2324250661Sdavidcs } else 2325250661Sdavidcs th = (struct tcphdr *)((caddr_t)ip + ip_hlen); 2326250661Sdavidcs 2327250661Sdavidcs break; 2328250661Sdavidcs 2329250661Sdavidcs case ETHERTYPE_IPV6: 2330250661Sdavidcs 2331250661Sdavidcs tcp_opt_off = ehdrlen + sizeof(struct ip6_hdr) + 2332250661Sdavidcs sizeof (struct tcphdr); 2333250661Sdavidcs 2334250661Sdavidcs if (mp->m_len < tcp_opt_off) { 2335250661Sdavidcs m_copydata(mp, 0, tcp_opt_off, hdr); 2336250661Sdavidcs ip6 = (struct ip6_hdr *)(hdr + ehdrlen); 2337250661Sdavidcs } else { 2338250661Sdavidcs ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); 2339250661Sdavidcs } 2340250661Sdavidcs 2341250661Sdavidcs ip_hlen = sizeof(struct ip6_hdr); 2342250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_TCP_LSO_IPV6; 2343250661Sdavidcs 2344250661Sdavidcs if (ip6->ip6_nxt != IPPROTO_TCP) { 2345250661Sdavidcs //device_printf(dev, "%s: ipv6\n", __func__); 2346250661Sdavidcs offload = 0; 2347250661Sdavidcs } else 2348250661Sdavidcs th = (struct tcphdr *)((caddr_t)ip6 + ip_hlen); 2349250661Sdavidcs break; 2350250661Sdavidcs 2351250661Sdavidcs default: 2352250661Sdavidcs QL_DPRINT8(ha, (dev, "%s: type!=ip\n", __func__)); 2353250661Sdavidcs offload = 0; 2354250661Sdavidcs break; 2355250661Sdavidcs } 2356250661Sdavidcs 2357250661Sdavidcs if (!offload) 2358250661Sdavidcs return (-1); 2359250661Sdavidcs 2360250661Sdavidcs tcp_hlen = th->th_off << 2; 2361250661Sdavidcs hdrlen = ehdrlen + ip_hlen + tcp_hlen; 2362250661Sdavidcs 2363250661Sdavidcs if (mp->m_len < hdrlen) { 2364250661Sdavidcs if (mp->m_len < tcp_opt_off) { 2365250661Sdavidcs if (tcp_hlen > sizeof(struct tcphdr)) { 2366250661Sdavidcs m_copydata(mp, tcp_opt_off, 2367250661Sdavidcs (tcp_hlen - sizeof(struct tcphdr)), 2368250661Sdavidcs &hdr[tcp_opt_off]); 2369250661Sdavidcs } 2370250661Sdavidcs } else { 2371250661Sdavidcs m_copydata(mp, 0, hdrlen, hdr); 2372250661Sdavidcs } 2373250661Sdavidcs } 2374250661Sdavidcs 2375250661Sdavidcs tx_cmd->mss = mp->m_pkthdr.tso_segsz; 2376250661Sdavidcs 2377250661Sdavidcs tx_cmd->flags_opcode = opcode ; 2378250661Sdavidcs tx_cmd->tcp_hdr_off = ip_hlen + ehdrlen; 2379250661Sdavidcs tx_cmd->total_hdr_len = hdrlen; 2380250661Sdavidcs 2381250661Sdavidcs /* Check for Multicast least significant bit of MSB == 1 */ 2382250661Sdavidcs if (eh->evl_dhost[0] & 0x01) { 2383250661Sdavidcs tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_MULTICAST; 2384250661Sdavidcs } 2385250661Sdavidcs 2386250661Sdavidcs if (mp->m_len < hdrlen) { 2387250661Sdavidcs printf("%d\n", hdrlen); 2388250661Sdavidcs return (1); 2389250661Sdavidcs } 2390250661Sdavidcs 2391250661Sdavidcs return (0); 2392250661Sdavidcs} 2393250661Sdavidcs 2394250661Sdavidcs/* 2395250661Sdavidcs * Name: qla_tx_chksum 2396250661Sdavidcs * Function: Checks if the packet to be transmitted is a candidate for 2397250661Sdavidcs * TCP/UDP Checksum offload. If yes, the appropriate fields in the Tx 2398250661Sdavidcs * Ring Structure are plugged in. 2399250661Sdavidcs */ 2400250661Sdavidcsstatic int 2401250661Sdavidcsqla_tx_chksum(qla_host_t *ha, struct mbuf *mp, uint32_t *op_code, 2402250661Sdavidcs uint32_t *tcp_hdr_off) 2403250661Sdavidcs{ 2404250661Sdavidcs struct ether_vlan_header *eh; 2405250661Sdavidcs struct ip *ip; 2406250661Sdavidcs struct ip6_hdr *ip6; 2407250661Sdavidcs uint32_t ehdrlen, ip_hlen; 2408250661Sdavidcs uint16_t etype, opcode, offload = 1; 2409250661Sdavidcs device_t dev; 2410250661Sdavidcs uint8_t buf[sizeof(struct ip6_hdr)]; 2411250661Sdavidcs 2412250661Sdavidcs dev = ha->pci_dev; 2413250661Sdavidcs 2414250661Sdavidcs *op_code = 0; 2415250661Sdavidcs 2416322972Sdavidcs if ((mp->m_pkthdr.csum_flags & 2417322972Sdavidcs (CSUM_TCP|CSUM_UDP|CSUM_TCP_IPV6 | CSUM_UDP_IPV6)) == 0) 2418250661Sdavidcs return (-1); 2419250661Sdavidcs 2420250661Sdavidcs eh = mtod(mp, struct ether_vlan_header *); 2421250661Sdavidcs 2422250661Sdavidcs if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 2423250661Sdavidcs ehdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 2424250661Sdavidcs etype = ntohs(eh->evl_proto); 2425250661Sdavidcs } else { 2426250661Sdavidcs ehdrlen = ETHER_HDR_LEN; 2427250661Sdavidcs etype = ntohs(eh->evl_encap_proto); 2428250661Sdavidcs } 2429250661Sdavidcs 2430250661Sdavidcs 2431250661Sdavidcs switch (etype) { 2432250661Sdavidcs case ETHERTYPE_IP: 2433250661Sdavidcs ip = (struct ip *)(mp->m_data + ehdrlen); 2434250661Sdavidcs 2435250661Sdavidcs ip_hlen = sizeof (struct ip); 2436250661Sdavidcs 2437250661Sdavidcs if (mp->m_len < (ehdrlen + ip_hlen)) { 2438250661Sdavidcs m_copydata(mp, ehdrlen, sizeof(struct ip), buf); 2439250661Sdavidcs ip = (struct ip *)buf; 2440250661Sdavidcs } 2441250661Sdavidcs 2442250661Sdavidcs if (ip->ip_p == IPPROTO_TCP) 2443250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM; 2444250661Sdavidcs else if (ip->ip_p == IPPROTO_UDP) 2445250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM; 2446250661Sdavidcs else { 2447250661Sdavidcs //device_printf(dev, "%s: ipv4\n", __func__); 2448250661Sdavidcs offload = 0; 2449250661Sdavidcs } 2450250661Sdavidcs break; 2451250661Sdavidcs 2452250661Sdavidcs case ETHERTYPE_IPV6: 2453250661Sdavidcs ip6 = (struct ip6_hdr *)(mp->m_data + ehdrlen); 2454250661Sdavidcs 2455250661Sdavidcs ip_hlen = sizeof(struct ip6_hdr); 2456250661Sdavidcs 2457250661Sdavidcs if (mp->m_len < (ehdrlen + ip_hlen)) { 2458250661Sdavidcs m_copydata(mp, ehdrlen, sizeof (struct ip6_hdr), 2459250661Sdavidcs buf); 2460250661Sdavidcs ip6 = (struct ip6_hdr *)buf; 2461250661Sdavidcs } 2462250661Sdavidcs 2463250661Sdavidcs if (ip6->ip6_nxt == IPPROTO_TCP) 2464250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_TCP_CHKSUM_IPV6; 2465250661Sdavidcs else if (ip6->ip6_nxt == IPPROTO_UDP) 2466250661Sdavidcs opcode = Q8_TX_CMD_OP_XMT_UDP_CHKSUM_IPV6; 2467250661Sdavidcs else { 2468250661Sdavidcs //device_printf(dev, "%s: ipv6\n", __func__); 2469250661Sdavidcs offload = 0; 2470250661Sdavidcs } 2471250661Sdavidcs break; 2472250661Sdavidcs 2473250661Sdavidcs default: 2474250661Sdavidcs offload = 0; 2475250661Sdavidcs break; 2476250661Sdavidcs } 2477250661Sdavidcs if (!offload) 2478250661Sdavidcs return (-1); 2479250661Sdavidcs 2480250661Sdavidcs *op_code = opcode; 2481250661Sdavidcs *tcp_hdr_off = (ip_hlen + ehdrlen); 2482250661Sdavidcs 2483250661Sdavidcs return (0); 2484250661Sdavidcs} 2485250661Sdavidcs 2486250661Sdavidcs#define QLA_TX_MIN_FREE 2 2487250661Sdavidcs/* 2488250661Sdavidcs * Name: ql_hw_send 2489250661Sdavidcs * Function: Transmits a packet. It first checks if the packet is a 2490250661Sdavidcs * candidate for Large TCP Segment Offload and then for UDP/TCP checksum 2491250661Sdavidcs * offload. If either of these creteria are not met, it is transmitted 2492250661Sdavidcs * as a regular ethernet frame. 2493250661Sdavidcs */ 2494250661Sdavidcsint 2495250661Sdavidcsql_hw_send(qla_host_t *ha, bus_dma_segment_t *segs, int nsegs, 2496284741Sdavidcs uint32_t tx_idx, struct mbuf *mp, uint32_t txr_idx, uint32_t iscsi_pdu) 2497250661Sdavidcs{ 2498250661Sdavidcs struct ether_vlan_header *eh; 2499250661Sdavidcs qla_hw_t *hw = &ha->hw; 2500250661Sdavidcs q80_tx_cmd_t *tx_cmd, tso_cmd; 2501250661Sdavidcs bus_dma_segment_t *c_seg; 2502250661Sdavidcs uint32_t num_tx_cmds, hdr_len = 0; 2503250661Sdavidcs uint32_t total_length = 0, bytes, tx_cmd_count = 0, txr_next; 2504250661Sdavidcs device_t dev; 2505250661Sdavidcs int i, ret; 2506250661Sdavidcs uint8_t *src = NULL, *dst = NULL; 2507250661Sdavidcs uint8_t frame_hdr[QL_FRAME_HDR_SIZE]; 2508250661Sdavidcs uint32_t op_code = 0; 2509250661Sdavidcs uint32_t tcp_hdr_off = 0; 2510250661Sdavidcs 2511250661Sdavidcs dev = ha->pci_dev; 2512250661Sdavidcs 2513250661Sdavidcs /* 2514250661Sdavidcs * Always make sure there is atleast one empty slot in the tx_ring 2515250661Sdavidcs * tx_ring is considered full when there only one entry available 2516250661Sdavidcs */ 2517250661Sdavidcs num_tx_cmds = (nsegs + (Q8_TX_CMD_MAX_SEGMENTS - 1)) >> 2; 2518250661Sdavidcs 2519250661Sdavidcs total_length = mp->m_pkthdr.len; 2520250661Sdavidcs if (total_length > QLA_MAX_TSO_FRAME_SIZE) { 2521250661Sdavidcs device_printf(dev, "%s: total length exceeds maxlen(%d)\n", 2522250661Sdavidcs __func__, total_length); 2523324029Sdavidcs return (EINVAL); 2524250661Sdavidcs } 2525250661Sdavidcs eh = mtod(mp, struct ether_vlan_header *); 2526250661Sdavidcs 2527250661Sdavidcs if (mp->m_pkthdr.csum_flags & CSUM_TSO) { 2528250661Sdavidcs 2529250661Sdavidcs bzero((void *)&tso_cmd, sizeof(q80_tx_cmd_t)); 2530250661Sdavidcs 2531250661Sdavidcs src = frame_hdr; 2532250661Sdavidcs ret = qla_tx_tso(ha, mp, &tso_cmd, src); 2533250661Sdavidcs 2534250661Sdavidcs if (!(ret & ~1)) { 2535250661Sdavidcs /* find the additional tx_cmd descriptors required */ 2536250661Sdavidcs 2537250661Sdavidcs if (mp->m_flags & M_VLANTAG) 2538250661Sdavidcs tso_cmd.total_hdr_len += ETHER_VLAN_ENCAP_LEN; 2539250661Sdavidcs 2540250661Sdavidcs hdr_len = tso_cmd.total_hdr_len; 2541250661Sdavidcs 2542250661Sdavidcs bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN; 2543250661Sdavidcs bytes = QL_MIN(bytes, hdr_len); 2544250661Sdavidcs 2545250661Sdavidcs num_tx_cmds++; 2546250661Sdavidcs hdr_len -= bytes; 2547250661Sdavidcs 2548250661Sdavidcs while (hdr_len) { 2549250661Sdavidcs bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len); 2550250661Sdavidcs hdr_len -= bytes; 2551250661Sdavidcs num_tx_cmds++; 2552250661Sdavidcs } 2553250661Sdavidcs hdr_len = tso_cmd.total_hdr_len; 2554250661Sdavidcs 2555250661Sdavidcs if (ret == 0) 2556250661Sdavidcs src = (uint8_t *)eh; 2557250661Sdavidcs } else 2558250661Sdavidcs return (EINVAL); 2559250661Sdavidcs } else { 2560250661Sdavidcs (void)qla_tx_chksum(ha, mp, &op_code, &tcp_hdr_off); 2561250661Sdavidcs } 2562250661Sdavidcs 2563250661Sdavidcs if (hw->tx_cntxt[txr_idx].txr_free <= (num_tx_cmds + QLA_TX_MIN_FREE)) { 2564313070Sdavidcs ql_hw_tx_done_locked(ha, txr_idx); 2565250661Sdavidcs if (hw->tx_cntxt[txr_idx].txr_free <= 2566250661Sdavidcs (num_tx_cmds + QLA_TX_MIN_FREE)) { 2567250661Sdavidcs QL_DPRINT8(ha, (dev, "%s: (hw->txr_free <= " 2568250661Sdavidcs "(num_tx_cmds + QLA_TX_MIN_FREE))\n", 2569250661Sdavidcs __func__)); 2570250661Sdavidcs return (-1); 2571250661Sdavidcs } 2572250661Sdavidcs } 2573250661Sdavidcs 2574324761Sdavidcs for (i = 0; i < num_tx_cmds; i++) { 2575324761Sdavidcs int j; 2576324761Sdavidcs 2577324761Sdavidcs j = (tx_idx+i) & (NUM_TX_DESCRIPTORS - 1); 2578324761Sdavidcs 2579324761Sdavidcs if (NULL != ha->tx_ring[txr_idx].tx_buf[j].m_head) { 2580324761Sdavidcs QL_ASSERT(ha, 0, \ 2581324761Sdavidcs ("%s [%d]: txr_idx = %d tx_idx = %d mbuf = %p\n",\ 2582324761Sdavidcs __func__, __LINE__, txr_idx, j,\ 2583324761Sdavidcs ha->tx_ring[txr_idx].tx_buf[j].m_head)); 2584324761Sdavidcs return (EINVAL); 2585324761Sdavidcs } 2586324761Sdavidcs } 2587324761Sdavidcs 2588250661Sdavidcs tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[tx_idx]; 2589250661Sdavidcs 2590250661Sdavidcs if (!(mp->m_pkthdr.csum_flags & CSUM_TSO)) { 2591250661Sdavidcs 2592250661Sdavidcs if (nsegs > ha->hw.max_tx_segs) 2593250661Sdavidcs ha->hw.max_tx_segs = nsegs; 2594250661Sdavidcs 2595250661Sdavidcs bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t)); 2596250661Sdavidcs 2597250661Sdavidcs if (op_code) { 2598250661Sdavidcs tx_cmd->flags_opcode = op_code; 2599250661Sdavidcs tx_cmd->tcp_hdr_off = tcp_hdr_off; 2600250661Sdavidcs 2601250661Sdavidcs } else { 2602250661Sdavidcs tx_cmd->flags_opcode = Q8_TX_CMD_OP_XMT_ETHER; 2603250661Sdavidcs } 2604250661Sdavidcs } else { 2605250661Sdavidcs bcopy(&tso_cmd, tx_cmd, sizeof(q80_tx_cmd_t)); 2606250661Sdavidcs ha->tx_tso_frames++; 2607250661Sdavidcs } 2608250661Sdavidcs 2609250661Sdavidcs if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 2610250661Sdavidcs tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_VLAN_TAGGED; 2611284741Sdavidcs 2612284741Sdavidcs if (iscsi_pdu) 2613284741Sdavidcs eh->evl_tag |= ha->hw.user_pri_iscsi << 13; 2614284741Sdavidcs 2615250661Sdavidcs } else if (mp->m_flags & M_VLANTAG) { 2616250661Sdavidcs 2617250661Sdavidcs if (hdr_len) { /* TSO */ 2618250661Sdavidcs tx_cmd->flags_opcode |= (Q8_TX_CMD_FLAGS_VLAN_TAGGED | 2619250661Sdavidcs Q8_TX_CMD_FLAGS_HW_VLAN_ID); 2620250661Sdavidcs tx_cmd->tcp_hdr_off += ETHER_VLAN_ENCAP_LEN; 2621250661Sdavidcs } else 2622250661Sdavidcs tx_cmd->flags_opcode |= Q8_TX_CMD_FLAGS_HW_VLAN_ID; 2623250661Sdavidcs 2624250661Sdavidcs ha->hw_vlan_tx_frames++; 2625250661Sdavidcs tx_cmd->vlan_tci = mp->m_pkthdr.ether_vtag; 2626284741Sdavidcs 2627284741Sdavidcs if (iscsi_pdu) { 2628284741Sdavidcs tx_cmd->vlan_tci |= ha->hw.user_pri_iscsi << 13; 2629284741Sdavidcs mp->m_pkthdr.ether_vtag = tx_cmd->vlan_tci; 2630284741Sdavidcs } 2631250661Sdavidcs } 2632250661Sdavidcs 2633250661Sdavidcs 2634250661Sdavidcs tx_cmd->n_bufs = (uint8_t)nsegs; 2635250661Sdavidcs tx_cmd->data_len_lo = (uint8_t)(total_length & 0xFF); 2636250661Sdavidcs tx_cmd->data_len_hi = qla_host_to_le16(((uint16_t)(total_length >> 8))); 2637250661Sdavidcs tx_cmd->cntxtid = Q8_TX_CMD_PORT_CNXTID(ha->pci_func); 2638250661Sdavidcs 2639250661Sdavidcs c_seg = segs; 2640250661Sdavidcs 2641250661Sdavidcs while (1) { 2642250661Sdavidcs for (i = 0; ((i < Q8_TX_CMD_MAX_SEGMENTS) && nsegs); i++) { 2643250661Sdavidcs 2644250661Sdavidcs switch (i) { 2645250661Sdavidcs case 0: 2646250661Sdavidcs tx_cmd->buf1_addr = c_seg->ds_addr; 2647250661Sdavidcs tx_cmd->buf1_len = c_seg->ds_len; 2648250661Sdavidcs break; 2649250661Sdavidcs 2650250661Sdavidcs case 1: 2651250661Sdavidcs tx_cmd->buf2_addr = c_seg->ds_addr; 2652250661Sdavidcs tx_cmd->buf2_len = c_seg->ds_len; 2653250661Sdavidcs break; 2654250661Sdavidcs 2655250661Sdavidcs case 2: 2656250661Sdavidcs tx_cmd->buf3_addr = c_seg->ds_addr; 2657250661Sdavidcs tx_cmd->buf3_len = c_seg->ds_len; 2658250661Sdavidcs break; 2659250661Sdavidcs 2660250661Sdavidcs case 3: 2661250661Sdavidcs tx_cmd->buf4_addr = c_seg->ds_addr; 2662250661Sdavidcs tx_cmd->buf4_len = c_seg->ds_len; 2663250661Sdavidcs break; 2664250661Sdavidcs } 2665250661Sdavidcs 2666250661Sdavidcs c_seg++; 2667250661Sdavidcs nsegs--; 2668250661Sdavidcs } 2669250661Sdavidcs 2670250661Sdavidcs txr_next = hw->tx_cntxt[txr_idx].txr_next = 2671250661Sdavidcs (hw->tx_cntxt[txr_idx].txr_next + 1) & 2672250661Sdavidcs (NUM_TX_DESCRIPTORS - 1); 2673250661Sdavidcs tx_cmd_count++; 2674250661Sdavidcs 2675250661Sdavidcs if (!nsegs) 2676250661Sdavidcs break; 2677250661Sdavidcs 2678250661Sdavidcs tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next]; 2679250661Sdavidcs bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t)); 2680250661Sdavidcs } 2681250661Sdavidcs 2682250661Sdavidcs if (mp->m_pkthdr.csum_flags & CSUM_TSO) { 2683250661Sdavidcs 2684250661Sdavidcs /* TSO : Copy the header in the following tx cmd descriptors */ 2685250661Sdavidcs 2686250661Sdavidcs txr_next = hw->tx_cntxt[txr_idx].txr_next; 2687250661Sdavidcs 2688250661Sdavidcs tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next]; 2689250661Sdavidcs bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t)); 2690250661Sdavidcs 2691250661Sdavidcs bytes = sizeof(q80_tx_cmd_t) - Q8_TX_CMD_TSO_ALIGN; 2692250661Sdavidcs bytes = QL_MIN(bytes, hdr_len); 2693250661Sdavidcs 2694250661Sdavidcs dst = (uint8_t *)tx_cmd + Q8_TX_CMD_TSO_ALIGN; 2695250661Sdavidcs 2696250661Sdavidcs if (mp->m_flags & M_VLANTAG) { 2697250661Sdavidcs /* first copy the src/dst MAC addresses */ 2698250661Sdavidcs bcopy(src, dst, (ETHER_ADDR_LEN * 2)); 2699250661Sdavidcs dst += (ETHER_ADDR_LEN * 2); 2700250661Sdavidcs src += (ETHER_ADDR_LEN * 2); 2701250661Sdavidcs 2702250661Sdavidcs *((uint16_t *)dst) = htons(ETHERTYPE_VLAN); 2703250661Sdavidcs dst += 2; 2704250661Sdavidcs *((uint16_t *)dst) = htons(mp->m_pkthdr.ether_vtag); 2705250661Sdavidcs dst += 2; 2706250661Sdavidcs 2707250661Sdavidcs /* bytes left in src header */ 2708250661Sdavidcs hdr_len -= ((ETHER_ADDR_LEN * 2) + 2709250661Sdavidcs ETHER_VLAN_ENCAP_LEN); 2710250661Sdavidcs 2711250661Sdavidcs /* bytes left in TxCmd Entry */ 2712250661Sdavidcs bytes -= ((ETHER_ADDR_LEN * 2) + ETHER_VLAN_ENCAP_LEN); 2713250661Sdavidcs 2714250661Sdavidcs 2715250661Sdavidcs bcopy(src, dst, bytes); 2716250661Sdavidcs src += bytes; 2717250661Sdavidcs hdr_len -= bytes; 2718250661Sdavidcs } else { 2719250661Sdavidcs bcopy(src, dst, bytes); 2720250661Sdavidcs src += bytes; 2721250661Sdavidcs hdr_len -= bytes; 2722250661Sdavidcs } 2723250661Sdavidcs 2724250661Sdavidcs txr_next = hw->tx_cntxt[txr_idx].txr_next = 2725250661Sdavidcs (hw->tx_cntxt[txr_idx].txr_next + 1) & 2726250661Sdavidcs (NUM_TX_DESCRIPTORS - 1); 2727250661Sdavidcs tx_cmd_count++; 2728250661Sdavidcs 2729250661Sdavidcs while (hdr_len) { 2730250661Sdavidcs tx_cmd = &hw->tx_cntxt[txr_idx].tx_ring_base[txr_next]; 2731250661Sdavidcs bzero((void *)tx_cmd, sizeof(q80_tx_cmd_t)); 2732250661Sdavidcs 2733250661Sdavidcs bytes = QL_MIN((sizeof(q80_tx_cmd_t)), hdr_len); 2734250661Sdavidcs 2735250661Sdavidcs bcopy(src, tx_cmd, bytes); 2736250661Sdavidcs src += bytes; 2737250661Sdavidcs hdr_len -= bytes; 2738250661Sdavidcs 2739250661Sdavidcs txr_next = hw->tx_cntxt[txr_idx].txr_next = 2740250661Sdavidcs (hw->tx_cntxt[txr_idx].txr_next + 1) & 2741250661Sdavidcs (NUM_TX_DESCRIPTORS - 1); 2742250661Sdavidcs tx_cmd_count++; 2743250661Sdavidcs } 2744250661Sdavidcs } 2745250661Sdavidcs 2746250661Sdavidcs hw->tx_cntxt[txr_idx].txr_free = 2747250661Sdavidcs hw->tx_cntxt[txr_idx].txr_free - tx_cmd_count; 2748250661Sdavidcs 2749250661Sdavidcs QL_UPDATE_TX_PRODUCER_INDEX(ha, hw->tx_cntxt[txr_idx].txr_next,\ 2750250661Sdavidcs txr_idx); 2751250661Sdavidcs QL_DPRINT8(ha, (dev, "%s: return\n", __func__)); 2752250661Sdavidcs 2753250661Sdavidcs return (0); 2754250661Sdavidcs} 2755250661Sdavidcs 2756250661Sdavidcs 2757284741Sdavidcs 2758284741Sdavidcs#define Q8_CONFIG_IND_TBL_SIZE 32 /* < Q8_RSS_IND_TBL_SIZE and power of 2 */ 2759250661Sdavidcsstatic int 2760250661Sdavidcsqla_config_rss_ind_table(qla_host_t *ha) 2761250661Sdavidcs{ 2762250661Sdavidcs uint32_t i, count; 2763284741Sdavidcs uint8_t rss_ind_tbl[Q8_CONFIG_IND_TBL_SIZE]; 2764250661Sdavidcs 2765250661Sdavidcs 2766284741Sdavidcs for (i = 0; i < Q8_CONFIG_IND_TBL_SIZE; i++) { 2767250661Sdavidcs rss_ind_tbl[i] = i % ha->hw.num_sds_rings; 2768250661Sdavidcs } 2769250661Sdavidcs 2770284741Sdavidcs for (i = 0; i <= Q8_RSS_IND_TBL_MAX_IDX ; 2771284741Sdavidcs i = i + Q8_CONFIG_IND_TBL_SIZE) { 2772250661Sdavidcs 2773284741Sdavidcs if ((i + Q8_CONFIG_IND_TBL_SIZE) > Q8_RSS_IND_TBL_MAX_IDX) { 2774250661Sdavidcs count = Q8_RSS_IND_TBL_MAX_IDX - i + 1; 2775250661Sdavidcs } else { 2776284741Sdavidcs count = Q8_CONFIG_IND_TBL_SIZE; 2777250661Sdavidcs } 2778250661Sdavidcs 2779250661Sdavidcs if (qla_set_rss_ind_table(ha, i, count, ha->hw.rcv_cntxt_id, 2780250661Sdavidcs rss_ind_tbl)) 2781250661Sdavidcs return (-1); 2782250661Sdavidcs } 2783250661Sdavidcs 2784250661Sdavidcs return (0); 2785250661Sdavidcs} 2786250661Sdavidcs 2787317109Sdavidcsstatic int 2788317109Sdavidcsqla_config_soft_lro(qla_host_t *ha) 2789317109Sdavidcs{ 2790317109Sdavidcs int i; 2791317109Sdavidcs qla_hw_t *hw = &ha->hw; 2792317109Sdavidcs struct lro_ctrl *lro; 2793317109Sdavidcs 2794317109Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 2795317109Sdavidcs lro = &hw->sds[i].lro; 2796317109Sdavidcs 2797317109Sdavidcs bzero(lro, sizeof(struct lro_ctrl)); 2798317109Sdavidcs 2799317109Sdavidcs#if (__FreeBSD_version >= 1100101) 2800317109Sdavidcs if (tcp_lro_init_args(lro, ha->ifp, 0, NUM_RX_DESCRIPTORS)) { 2801317109Sdavidcs device_printf(ha->pci_dev, 2802317109Sdavidcs "%s: tcp_lro_init_args [%d] failed\n", 2803317109Sdavidcs __func__, i); 2804317109Sdavidcs return (-1); 2805317109Sdavidcs } 2806317109Sdavidcs#else 2807317109Sdavidcs if (tcp_lro_init(lro)) { 2808317109Sdavidcs device_printf(ha->pci_dev, 2809317109Sdavidcs "%s: tcp_lro_init [%d] failed\n", 2810317109Sdavidcs __func__, i); 2811317109Sdavidcs return (-1); 2812317109Sdavidcs } 2813317109Sdavidcs#endif /* #if (__FreeBSD_version >= 1100101) */ 2814317109Sdavidcs 2815317109Sdavidcs lro->ifp = ha->ifp; 2816317109Sdavidcs } 2817317109Sdavidcs 2818317109Sdavidcs QL_DPRINT2(ha, (ha->pci_dev, "%s: LRO initialized\n", __func__)); 2819317109Sdavidcs return (0); 2820317109Sdavidcs} 2821317109Sdavidcs 2822317109Sdavidcsstatic void 2823317109Sdavidcsqla_drain_soft_lro(qla_host_t *ha) 2824317109Sdavidcs{ 2825317109Sdavidcs int i; 2826317109Sdavidcs qla_hw_t *hw = &ha->hw; 2827317109Sdavidcs struct lro_ctrl *lro; 2828317109Sdavidcs 2829317109Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 2830317109Sdavidcs lro = &hw->sds[i].lro; 2831317109Sdavidcs 2832317109Sdavidcs#if (__FreeBSD_version >= 1100101) 2833317109Sdavidcs tcp_lro_flush_all(lro); 2834317109Sdavidcs#else 2835317109Sdavidcs struct lro_entry *queued; 2836317109Sdavidcs 2837317109Sdavidcs while ((!SLIST_EMPTY(&lro->lro_active))) { 2838317109Sdavidcs queued = SLIST_FIRST(&lro->lro_active); 2839317109Sdavidcs SLIST_REMOVE_HEAD(&lro->lro_active, next); 2840317109Sdavidcs tcp_lro_flush(lro, queued); 2841317109Sdavidcs } 2842317109Sdavidcs#endif /* #if (__FreeBSD_version >= 1100101) */ 2843317109Sdavidcs } 2844317109Sdavidcs 2845317109Sdavidcs return; 2846317109Sdavidcs} 2847317109Sdavidcs 2848317109Sdavidcsstatic void 2849317109Sdavidcsqla_free_soft_lro(qla_host_t *ha) 2850317109Sdavidcs{ 2851317109Sdavidcs int i; 2852317109Sdavidcs qla_hw_t *hw = &ha->hw; 2853317109Sdavidcs struct lro_ctrl *lro; 2854317109Sdavidcs 2855317109Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 2856317109Sdavidcs lro = &hw->sds[i].lro; 2857317109Sdavidcs tcp_lro_free(lro); 2858317109Sdavidcs } 2859317109Sdavidcs 2860317109Sdavidcs return; 2861317109Sdavidcs} 2862317109Sdavidcs 2863317109Sdavidcs 2864250661Sdavidcs/* 2865250661Sdavidcs * Name: ql_del_hw_if 2866250661Sdavidcs * Function: Destroys the hardware specific entities corresponding to an 2867250661Sdavidcs * Ethernet Interface 2868250661Sdavidcs */ 2869250661Sdavidcsvoid 2870250661Sdavidcsql_del_hw_if(qla_host_t *ha) 2871250661Sdavidcs{ 2872284741Sdavidcs uint32_t i; 2873284741Sdavidcs uint32_t num_msix; 2874250661Sdavidcs 2875284741Sdavidcs (void)qla_stop_nic_func(ha); 2876284741Sdavidcs 2877250661Sdavidcs qla_del_rcv_cntxt(ha); 2878307524Sdavidcs 2879330555Sdavidcs if(qla_del_xmt_cntxt(ha)) 2880330555Sdavidcs goto ql_del_hw_if_exit; 2881250661Sdavidcs 2882250661Sdavidcs if (ha->hw.flags.init_intr_cnxt) { 2883284741Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; ) { 2884284741Sdavidcs 2885284741Sdavidcs if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings) 2886284741Sdavidcs num_msix = Q8_MAX_INTR_VECTORS; 2887284741Sdavidcs else 2888284741Sdavidcs num_msix = ha->hw.num_sds_rings - i; 2889284741Sdavidcs 2890330555Sdavidcs if (qla_config_intr_cntxt(ha, i, num_msix, 0)) 2891330555Sdavidcs break; 2892330555Sdavidcs 2893284741Sdavidcs i += num_msix; 2894284741Sdavidcs } 2895284741Sdavidcs 2896250661Sdavidcs ha->hw.flags.init_intr_cnxt = 0; 2897250661Sdavidcs } 2898307524Sdavidcs 2899330555Sdavidcsql_del_hw_if_exit: 2900317109Sdavidcs if (ha->hw.enable_soft_lro) { 2901317109Sdavidcs qla_drain_soft_lro(ha); 2902317109Sdavidcs qla_free_soft_lro(ha); 2903317109Sdavidcs } 2904317109Sdavidcs 2905284741Sdavidcs return; 2906250661Sdavidcs} 2907250661Sdavidcs 2908284741Sdavidcsvoid 2909284741Sdavidcsqla_confirm_9kb_enable(qla_host_t *ha) 2910284741Sdavidcs{ 2911332052Sdavidcs// uint32_t supports_9kb = 0; 2912284741Sdavidcs 2913284741Sdavidcs ha->hw.mbx_intr_mask_offset = READ_REG32(ha, Q8_MBOX_INT_MASK_MSIX); 2914284741Sdavidcs 2915284741Sdavidcs /* Use MSI-X vector 0; Enable Firmware Mailbox Interrupt */ 2916284741Sdavidcs WRITE_REG32(ha, Q8_MBOX_INT_ENABLE, BIT_2); 2917284741Sdavidcs WRITE_REG32(ha, ha->hw.mbx_intr_mask_offset, 0x0); 2918284741Sdavidcs 2919332052Sdavidcs#if 0 2920284741Sdavidcs qla_get_nic_partition(ha, &supports_9kb, NULL); 2921284741Sdavidcs 2922284741Sdavidcs if (!supports_9kb) 2923332052Sdavidcs#endif 2924332052Sdavidcs ha->hw.enable_9kb = 0; 2925284741Sdavidcs 2926284741Sdavidcs return; 2927284741Sdavidcs} 2928284741Sdavidcs 2929250661Sdavidcs/* 2930250661Sdavidcs * Name: ql_init_hw_if 2931250661Sdavidcs * Function: Creates the hardware specific entities corresponding to an 2932250661Sdavidcs * Ethernet Interface - Transmit and Receive Contexts. Sets the MAC Address 2933250661Sdavidcs * corresponding to the interface. Enables LRO if allowed. 2934250661Sdavidcs */ 2935250661Sdavidcsint 2936250661Sdavidcsql_init_hw_if(qla_host_t *ha) 2937250661Sdavidcs{ 2938250661Sdavidcs device_t dev; 2939250661Sdavidcs uint32_t i; 2940250661Sdavidcs uint8_t bcast_mac[6]; 2941250661Sdavidcs qla_rdesc_t *rdesc; 2942284741Sdavidcs uint32_t num_msix; 2943250661Sdavidcs 2944250661Sdavidcs dev = ha->pci_dev; 2945250661Sdavidcs 2946250661Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; i++) { 2947250661Sdavidcs bzero(ha->hw.dma_buf.sds_ring[i].dma_b, 2948250661Sdavidcs ha->hw.dma_buf.sds_ring[i].size); 2949250661Sdavidcs } 2950250661Sdavidcs 2951284741Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; ) { 2952250661Sdavidcs 2953284741Sdavidcs if ((i + Q8_MAX_INTR_VECTORS) < ha->hw.num_sds_rings) 2954284741Sdavidcs num_msix = Q8_MAX_INTR_VECTORS; 2955284741Sdavidcs else 2956284741Sdavidcs num_msix = ha->hw.num_sds_rings - i; 2957250661Sdavidcs 2958284741Sdavidcs if (qla_config_intr_cntxt(ha, i, num_msix, 1)) { 2959250661Sdavidcs 2960284741Sdavidcs if (i > 0) { 2961284741Sdavidcs 2962284741Sdavidcs num_msix = i; 2963284741Sdavidcs 2964284741Sdavidcs for (i = 0; i < num_msix; ) { 2965284741Sdavidcs qla_config_intr_cntxt(ha, i, 2966284741Sdavidcs Q8_MAX_INTR_VECTORS, 0); 2967284741Sdavidcs i += Q8_MAX_INTR_VECTORS; 2968284741Sdavidcs } 2969284741Sdavidcs } 2970284741Sdavidcs return (-1); 2971284741Sdavidcs } 2972284741Sdavidcs 2973284741Sdavidcs i = i + num_msix; 2974284741Sdavidcs } 2975284741Sdavidcs 2976284741Sdavidcs ha->hw.flags.init_intr_cnxt = 1; 2977284741Sdavidcs 2978250661Sdavidcs /* 2979250661Sdavidcs * Create Receive Context 2980250661Sdavidcs */ 2981250661Sdavidcs if (qla_init_rcv_cntxt(ha)) { 2982250661Sdavidcs return (-1); 2983250661Sdavidcs } 2984250661Sdavidcs 2985250661Sdavidcs for (i = 0; i < ha->hw.num_rds_rings; i++) { 2986250661Sdavidcs rdesc = &ha->hw.rds[i]; 2987250661Sdavidcs rdesc->rx_next = NUM_RX_DESCRIPTORS - 2; 2988250661Sdavidcs rdesc->rx_in = 0; 2989250661Sdavidcs /* Update the RDS Producer Indices */ 2990250661Sdavidcs QL_UPDATE_RDS_PRODUCER_INDEX(ha, rdesc->prod_std,\ 2991250661Sdavidcs rdesc->rx_next); 2992250661Sdavidcs } 2993250661Sdavidcs 2994250661Sdavidcs /* 2995250661Sdavidcs * Create Transmit Context 2996250661Sdavidcs */ 2997250661Sdavidcs if (qla_init_xmt_cntxt(ha)) { 2998250661Sdavidcs qla_del_rcv_cntxt(ha); 2999250661Sdavidcs return (-1); 3000250661Sdavidcs } 3001250661Sdavidcs ha->hw.max_tx_segs = 0; 3002250661Sdavidcs 3003307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr, 1, 1)) 3004250661Sdavidcs return(-1); 3005250661Sdavidcs 3006250661Sdavidcs ha->hw.flags.unicast_mac = 1; 3007250661Sdavidcs 3008250661Sdavidcs bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF; 3009250661Sdavidcs bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF; 3010250661Sdavidcs 3011307524Sdavidcs if (qla_config_mac_addr(ha, bcast_mac, 1, 1)) 3012250661Sdavidcs return (-1); 3013250661Sdavidcs 3014250661Sdavidcs ha->hw.flags.bcast_mac = 1; 3015250661Sdavidcs 3016250661Sdavidcs /* 3017250661Sdavidcs * program any cached multicast addresses 3018250661Sdavidcs */ 3019250661Sdavidcs if (qla_hw_add_all_mcast(ha)) 3020250661Sdavidcs return (-1); 3021250661Sdavidcs 3022321494Sdavidcs if (ql_set_max_mtu(ha, ha->max_frame_size, ha->hw.rcv_cntxt_id)) 3023321494Sdavidcs return (-1); 3024321494Sdavidcs 3025250661Sdavidcs if (qla_config_rss(ha, ha->hw.rcv_cntxt_id)) 3026250661Sdavidcs return (-1); 3027250661Sdavidcs 3028250661Sdavidcs if (qla_config_rss_ind_table(ha)) 3029250661Sdavidcs return (-1); 3030250661Sdavidcs 3031284741Sdavidcs if (qla_config_intr_coalesce(ha, ha->hw.rcv_cntxt_id, 0, 1)) 3032250661Sdavidcs return (-1); 3033250661Sdavidcs 3034250661Sdavidcs if (qla_link_event_req(ha, ha->hw.rcv_cntxt_id)) 3035250661Sdavidcs return (-1); 3036250661Sdavidcs 3037317109Sdavidcs if (ha->ifp->if_capenable & IFCAP_LRO) { 3038317109Sdavidcs if (ha->hw.enable_hw_lro) { 3039317109Sdavidcs ha->hw.enable_soft_lro = 0; 3040250661Sdavidcs 3041317109Sdavidcs if (qla_config_fw_lro(ha, ha->hw.rcv_cntxt_id)) 3042317109Sdavidcs return (-1); 3043317109Sdavidcs } else { 3044317109Sdavidcs ha->hw.enable_soft_lro = 1; 3045317109Sdavidcs 3046317109Sdavidcs if (qla_config_soft_lro(ha)) 3047317109Sdavidcs return (-1); 3048317109Sdavidcs } 3049317109Sdavidcs } 3050317109Sdavidcs 3051284741Sdavidcs if (qla_init_nic_func(ha)) 3052284741Sdavidcs return (-1); 3053284741Sdavidcs 3054284741Sdavidcs if (qla_query_fw_dcbx_caps(ha)) 3055284741Sdavidcs return (-1); 3056284741Sdavidcs 3057250661Sdavidcs for (i = 0; i < ha->hw.num_sds_rings; i++) 3058250661Sdavidcs QL_ENABLE_INTERRUPTS(ha, i); 3059250661Sdavidcs 3060250661Sdavidcs return (0); 3061250661Sdavidcs} 3062250661Sdavidcs 3063250661Sdavidcsstatic int 3064284741Sdavidcsqla_map_sds_to_rds(qla_host_t *ha, uint32_t start_idx, uint32_t num_idx) 3065250661Sdavidcs{ 3066250661Sdavidcs device_t dev = ha->pci_dev; 3067250661Sdavidcs q80_rq_map_sds_to_rds_t *map_rings; 3068284741Sdavidcs q80_rsp_map_sds_to_rds_t *map_rings_rsp; 3069250661Sdavidcs uint32_t i, err; 3070250661Sdavidcs qla_hw_t *hw = &ha->hw; 3071250661Sdavidcs 3072250661Sdavidcs map_rings = (q80_rq_map_sds_to_rds_t *)ha->hw.mbox; 3073250661Sdavidcs bzero(map_rings, sizeof(q80_rq_map_sds_to_rds_t)); 3074250661Sdavidcs 3075250661Sdavidcs map_rings->opcode = Q8_MBX_MAP_SDS_TO_RDS; 3076250661Sdavidcs map_rings->count_version = (sizeof (q80_rq_map_sds_to_rds_t) >> 2); 3077250661Sdavidcs map_rings->count_version |= Q8_MBX_CMD_VERSION; 3078250661Sdavidcs 3079250661Sdavidcs map_rings->cntxt_id = hw->rcv_cntxt_id; 3080284741Sdavidcs map_rings->num_rings = num_idx; 3081250661Sdavidcs 3082284741Sdavidcs for (i = 0; i < num_idx; i++) { 3083284741Sdavidcs map_rings->sds_rds[i].sds_ring = i + start_idx; 3084284741Sdavidcs map_rings->sds_rds[i].rds_ring = i + start_idx; 3085284741Sdavidcs } 3086250661Sdavidcs 3087250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)map_rings, 3088250661Sdavidcs (sizeof (q80_rq_map_sds_to_rds_t) >> 2), 3089250661Sdavidcs ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) { 3090250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3091250661Sdavidcs return (-1); 3092250661Sdavidcs } 3093250661Sdavidcs 3094284741Sdavidcs map_rings_rsp = (q80_rsp_map_sds_to_rds_t *)ha->hw.mbox; 3095250661Sdavidcs 3096250661Sdavidcs err = Q8_MBX_RSP_STATUS(map_rings_rsp->regcnt_status); 3097250661Sdavidcs 3098250661Sdavidcs if (err) { 3099250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3100250661Sdavidcs return (-1); 3101250661Sdavidcs } 3102250661Sdavidcs 3103250661Sdavidcs return (0); 3104250661Sdavidcs} 3105250661Sdavidcs 3106250661Sdavidcs/* 3107250661Sdavidcs * Name: qla_init_rcv_cntxt 3108250661Sdavidcs * Function: Creates the Receive Context. 3109250661Sdavidcs */ 3110250661Sdavidcsstatic int 3111250661Sdavidcsqla_init_rcv_cntxt(qla_host_t *ha) 3112250661Sdavidcs{ 3113250661Sdavidcs q80_rq_rcv_cntxt_t *rcntxt; 3114250661Sdavidcs q80_rsp_rcv_cntxt_t *rcntxt_rsp; 3115250661Sdavidcs q80_stat_desc_t *sdesc; 3116250661Sdavidcs int i, j; 3117250661Sdavidcs qla_hw_t *hw = &ha->hw; 3118250661Sdavidcs device_t dev; 3119250661Sdavidcs uint32_t err; 3120250661Sdavidcs uint32_t rcntxt_sds_rings; 3121250661Sdavidcs uint32_t rcntxt_rds_rings; 3122284741Sdavidcs uint32_t max_idx; 3123250661Sdavidcs 3124250661Sdavidcs dev = ha->pci_dev; 3125250661Sdavidcs 3126250661Sdavidcs /* 3127250661Sdavidcs * Create Receive Context 3128250661Sdavidcs */ 3129250661Sdavidcs 3130250661Sdavidcs for (i = 0; i < hw->num_sds_rings; i++) { 3131250661Sdavidcs sdesc = (q80_stat_desc_t *)&hw->sds[i].sds_ring_base[0]; 3132250661Sdavidcs 3133250661Sdavidcs for (j = 0; j < NUM_STATUS_DESCRIPTORS; j++) { 3134250661Sdavidcs sdesc->data[0] = 1ULL; 3135250661Sdavidcs sdesc->data[1] = 1ULL; 3136250661Sdavidcs } 3137250661Sdavidcs } 3138250661Sdavidcs 3139250661Sdavidcs rcntxt_sds_rings = hw->num_sds_rings; 3140250661Sdavidcs if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS) 3141250661Sdavidcs rcntxt_sds_rings = MAX_RCNTXT_SDS_RINGS; 3142250661Sdavidcs 3143250661Sdavidcs rcntxt_rds_rings = hw->num_rds_rings; 3144250661Sdavidcs 3145250661Sdavidcs if (hw->num_rds_rings > MAX_RDS_RING_SETS) 3146250661Sdavidcs rcntxt_rds_rings = MAX_RDS_RING_SETS; 3147250661Sdavidcs 3148250661Sdavidcs rcntxt = (q80_rq_rcv_cntxt_t *)ha->hw.mbox; 3149250661Sdavidcs bzero(rcntxt, (sizeof (q80_rq_rcv_cntxt_t))); 3150250661Sdavidcs 3151250661Sdavidcs rcntxt->opcode = Q8_MBX_CREATE_RX_CNTXT; 3152250661Sdavidcs rcntxt->count_version = (sizeof (q80_rq_rcv_cntxt_t) >> 2); 3153250661Sdavidcs rcntxt->count_version |= Q8_MBX_CMD_VERSION; 3154250661Sdavidcs 3155250661Sdavidcs rcntxt->cap0 = Q8_RCV_CNTXT_CAP0_BASEFW | 3156250661Sdavidcs Q8_RCV_CNTXT_CAP0_LRO | 3157250661Sdavidcs Q8_RCV_CNTXT_CAP0_HW_LRO | 3158250661Sdavidcs Q8_RCV_CNTXT_CAP0_RSS | 3159250661Sdavidcs Q8_RCV_CNTXT_CAP0_SGL_LRO; 3160250661Sdavidcs 3161284741Sdavidcs if (ha->hw.enable_9kb) 3162284741Sdavidcs rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SINGLE_JUMBO; 3163284741Sdavidcs else 3164284741Sdavidcs rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_SGL_JUMBO; 3165284741Sdavidcs 3166250661Sdavidcs if (ha->hw.num_rds_rings > 1) { 3167250661Sdavidcs rcntxt->nrds_sets_rings = rcntxt_rds_rings | (1 << 5); 3168250661Sdavidcs rcntxt->cap0 |= Q8_RCV_CNTXT_CAP0_MULTI_RDS; 3169250661Sdavidcs } else 3170250661Sdavidcs rcntxt->nrds_sets_rings = 0x1 | (1 << 5); 3171250661Sdavidcs 3172250661Sdavidcs rcntxt->nsds_rings = rcntxt_sds_rings; 3173250661Sdavidcs 3174250661Sdavidcs rcntxt->rds_producer_mode = Q8_RCV_CNTXT_RDS_PROD_MODE_UNIQUE; 3175250661Sdavidcs 3176250661Sdavidcs rcntxt->rcv_vpid = 0; 3177250661Sdavidcs 3178250661Sdavidcs for (i = 0; i < rcntxt_sds_rings; i++) { 3179250661Sdavidcs rcntxt->sds[i].paddr = 3180250661Sdavidcs qla_host_to_le64(hw->dma_buf.sds_ring[i].dma_addr); 3181250661Sdavidcs rcntxt->sds[i].size = 3182250661Sdavidcs qla_host_to_le32(NUM_STATUS_DESCRIPTORS); 3183313070Sdavidcs rcntxt->sds[i].intr_id = qla_host_to_le16(hw->intr_id[i]); 3184313070Sdavidcs rcntxt->sds[i].intr_src_bit = qla_host_to_le16(0); 3185250661Sdavidcs } 3186250661Sdavidcs 3187250661Sdavidcs for (i = 0; i < rcntxt_rds_rings; i++) { 3188250661Sdavidcs rcntxt->rds[i].paddr_std = 3189250661Sdavidcs qla_host_to_le64(hw->dma_buf.rds_ring[i].dma_addr); 3190284741Sdavidcs 3191284741Sdavidcs if (ha->hw.enable_9kb) 3192284741Sdavidcs rcntxt->rds[i].std_bsize = 3193284741Sdavidcs qla_host_to_le64(MJUM9BYTES); 3194284741Sdavidcs else 3195284741Sdavidcs rcntxt->rds[i].std_bsize = qla_host_to_le64(MCLBYTES); 3196284741Sdavidcs 3197250661Sdavidcs rcntxt->rds[i].std_nentries = 3198250661Sdavidcs qla_host_to_le32(NUM_RX_DESCRIPTORS); 3199250661Sdavidcs } 3200250661Sdavidcs 3201250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)rcntxt, 3202250661Sdavidcs (sizeof (q80_rq_rcv_cntxt_t) >> 2), 3203250661Sdavidcs ha->hw.mbox, (sizeof(q80_rsp_rcv_cntxt_t) >> 2), 0)) { 3204250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3205250661Sdavidcs return (-1); 3206250661Sdavidcs } 3207250661Sdavidcs 3208250661Sdavidcs rcntxt_rsp = (q80_rsp_rcv_cntxt_t *)ha->hw.mbox; 3209250661Sdavidcs 3210250661Sdavidcs err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status); 3211250661Sdavidcs 3212250661Sdavidcs if (err) { 3213250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3214250661Sdavidcs return (-1); 3215250661Sdavidcs } 3216250661Sdavidcs 3217250661Sdavidcs for (i = 0; i < rcntxt_sds_rings; i++) { 3218250661Sdavidcs hw->sds[i].sds_consumer = rcntxt_rsp->sds_cons[i]; 3219250661Sdavidcs } 3220250661Sdavidcs 3221250661Sdavidcs for (i = 0; i < rcntxt_rds_rings; i++) { 3222250661Sdavidcs hw->rds[i].prod_std = rcntxt_rsp->rds[i].prod_std; 3223250661Sdavidcs } 3224250661Sdavidcs 3225250661Sdavidcs hw->rcv_cntxt_id = rcntxt_rsp->cntxt_id; 3226250661Sdavidcs 3227250661Sdavidcs ha->hw.flags.init_rx_cnxt = 1; 3228250661Sdavidcs 3229250661Sdavidcs if (hw->num_sds_rings > MAX_RCNTXT_SDS_RINGS) { 3230284741Sdavidcs 3231284741Sdavidcs for (i = MAX_RCNTXT_SDS_RINGS; i < hw->num_sds_rings;) { 3232284741Sdavidcs 3233284741Sdavidcs if ((i + MAX_RCNTXT_SDS_RINGS) < hw->num_sds_rings) 3234284741Sdavidcs max_idx = MAX_RCNTXT_SDS_RINGS; 3235284741Sdavidcs else 3236284741Sdavidcs max_idx = hw->num_sds_rings - i; 3237284741Sdavidcs 3238284741Sdavidcs err = qla_add_rcv_rings(ha, i, max_idx); 3239284741Sdavidcs if (err) 3240284741Sdavidcs return -1; 3241284741Sdavidcs 3242284741Sdavidcs i += max_idx; 3243284741Sdavidcs } 3244250661Sdavidcs } 3245250661Sdavidcs 3246284741Sdavidcs if (hw->num_rds_rings > 1) { 3247284741Sdavidcs 3248284741Sdavidcs for (i = 0; i < hw->num_rds_rings; ) { 3249284741Sdavidcs 3250284741Sdavidcs if ((i + MAX_SDS_TO_RDS_MAP) < hw->num_rds_rings) 3251284741Sdavidcs max_idx = MAX_SDS_TO_RDS_MAP; 3252284741Sdavidcs else 3253284741Sdavidcs max_idx = hw->num_rds_rings - i; 3254284741Sdavidcs 3255284741Sdavidcs err = qla_map_sds_to_rds(ha, i, max_idx); 3256284741Sdavidcs if (err) 3257284741Sdavidcs return -1; 3258284741Sdavidcs 3259284741Sdavidcs i += max_idx; 3260284741Sdavidcs } 3261250661Sdavidcs } 3262250661Sdavidcs 3263250661Sdavidcs return (0); 3264250661Sdavidcs} 3265250661Sdavidcs 3266250661Sdavidcsstatic int 3267284741Sdavidcsqla_add_rcv_rings(qla_host_t *ha, uint32_t sds_idx, uint32_t nsds) 3268250661Sdavidcs{ 3269250661Sdavidcs device_t dev = ha->pci_dev; 3270250661Sdavidcs q80_rq_add_rcv_rings_t *add_rcv; 3271250661Sdavidcs q80_rsp_add_rcv_rings_t *add_rcv_rsp; 3272250661Sdavidcs uint32_t i,j, err; 3273250661Sdavidcs qla_hw_t *hw = &ha->hw; 3274250661Sdavidcs 3275250661Sdavidcs add_rcv = (q80_rq_add_rcv_rings_t *)ha->hw.mbox; 3276250661Sdavidcs bzero(add_rcv, sizeof (q80_rq_add_rcv_rings_t)); 3277250661Sdavidcs 3278250661Sdavidcs add_rcv->opcode = Q8_MBX_ADD_RX_RINGS; 3279250661Sdavidcs add_rcv->count_version = (sizeof (q80_rq_add_rcv_rings_t) >> 2); 3280250661Sdavidcs add_rcv->count_version |= Q8_MBX_CMD_VERSION; 3281250661Sdavidcs 3282284741Sdavidcs add_rcv->nrds_sets_rings = nsds | (1 << 5); 3283250661Sdavidcs add_rcv->nsds_rings = nsds; 3284250661Sdavidcs add_rcv->cntxt_id = hw->rcv_cntxt_id; 3285250661Sdavidcs 3286250661Sdavidcs for (i = 0; i < nsds; i++) { 3287250661Sdavidcs 3288250661Sdavidcs j = i + sds_idx; 3289250661Sdavidcs 3290250661Sdavidcs add_rcv->sds[i].paddr = 3291250661Sdavidcs qla_host_to_le64(hw->dma_buf.sds_ring[j].dma_addr); 3292250661Sdavidcs 3293250661Sdavidcs add_rcv->sds[i].size = 3294250661Sdavidcs qla_host_to_le32(NUM_STATUS_DESCRIPTORS); 3295250661Sdavidcs 3296313070Sdavidcs add_rcv->sds[i].intr_id = qla_host_to_le16(hw->intr_id[j]); 3297313070Sdavidcs add_rcv->sds[i].intr_src_bit = qla_host_to_le16(0); 3298250661Sdavidcs 3299250661Sdavidcs } 3300313070Sdavidcs 3301284741Sdavidcs for (i = 0; (i < nsds); i++) { 3302250661Sdavidcs j = i + sds_idx; 3303284741Sdavidcs 3304250661Sdavidcs add_rcv->rds[i].paddr_std = 3305250661Sdavidcs qla_host_to_le64(hw->dma_buf.rds_ring[j].dma_addr); 3306284741Sdavidcs 3307284741Sdavidcs if (ha->hw.enable_9kb) 3308284741Sdavidcs add_rcv->rds[i].std_bsize = 3309284741Sdavidcs qla_host_to_le64(MJUM9BYTES); 3310284741Sdavidcs else 3311284741Sdavidcs add_rcv->rds[i].std_bsize = qla_host_to_le64(MCLBYTES); 3312284741Sdavidcs 3313250661Sdavidcs add_rcv->rds[i].std_nentries = 3314250661Sdavidcs qla_host_to_le32(NUM_RX_DESCRIPTORS); 3315250661Sdavidcs } 3316250661Sdavidcs 3317250661Sdavidcs 3318250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)add_rcv, 3319250661Sdavidcs (sizeof (q80_rq_add_rcv_rings_t) >> 2), 3320250661Sdavidcs ha->hw.mbox, (sizeof(q80_rsp_add_rcv_rings_t) >> 2), 0)) { 3321250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3322250661Sdavidcs return (-1); 3323250661Sdavidcs } 3324250661Sdavidcs 3325250661Sdavidcs add_rcv_rsp = (q80_rsp_add_rcv_rings_t *)ha->hw.mbox; 3326250661Sdavidcs 3327250661Sdavidcs err = Q8_MBX_RSP_STATUS(add_rcv_rsp->regcnt_status); 3328250661Sdavidcs 3329250661Sdavidcs if (err) { 3330250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3331250661Sdavidcs return (-1); 3332250661Sdavidcs } 3333250661Sdavidcs 3334284741Sdavidcs for (i = 0; i < nsds; i++) { 3335284741Sdavidcs hw->sds[(i + sds_idx)].sds_consumer = add_rcv_rsp->sds_cons[i]; 3336250661Sdavidcs } 3337284741Sdavidcs 3338284741Sdavidcs for (i = 0; i < nsds; i++) { 3339284741Sdavidcs hw->rds[(i + sds_idx)].prod_std = add_rcv_rsp->rds[i].prod_std; 3340250661Sdavidcs } 3341284741Sdavidcs 3342250661Sdavidcs return (0); 3343250661Sdavidcs} 3344250661Sdavidcs 3345250661Sdavidcs/* 3346250661Sdavidcs * Name: qla_del_rcv_cntxt 3347250661Sdavidcs * Function: Destroys the Receive Context. 3348250661Sdavidcs */ 3349250661Sdavidcsstatic void 3350250661Sdavidcsqla_del_rcv_cntxt(qla_host_t *ha) 3351250661Sdavidcs{ 3352250661Sdavidcs device_t dev = ha->pci_dev; 3353250661Sdavidcs q80_rcv_cntxt_destroy_t *rcntxt; 3354250661Sdavidcs q80_rcv_cntxt_destroy_rsp_t *rcntxt_rsp; 3355250661Sdavidcs uint32_t err; 3356250661Sdavidcs uint8_t bcast_mac[6]; 3357250661Sdavidcs 3358250661Sdavidcs if (!ha->hw.flags.init_rx_cnxt) 3359250661Sdavidcs return; 3360250661Sdavidcs 3361250661Sdavidcs if (qla_hw_del_all_mcast(ha)) 3362250661Sdavidcs return; 3363250661Sdavidcs 3364250661Sdavidcs if (ha->hw.flags.bcast_mac) { 3365250661Sdavidcs 3366250661Sdavidcs bcast_mac[0] = 0xFF; bcast_mac[1] = 0xFF; bcast_mac[2] = 0xFF; 3367250661Sdavidcs bcast_mac[3] = 0xFF; bcast_mac[4] = 0xFF; bcast_mac[5] = 0xFF; 3368250661Sdavidcs 3369307524Sdavidcs if (qla_config_mac_addr(ha, bcast_mac, 0, 1)) 3370250661Sdavidcs return; 3371250661Sdavidcs ha->hw.flags.bcast_mac = 0; 3372250661Sdavidcs 3373250661Sdavidcs } 3374250661Sdavidcs 3375250661Sdavidcs if (ha->hw.flags.unicast_mac) { 3376307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr, 0, 1)) 3377250661Sdavidcs return; 3378250661Sdavidcs ha->hw.flags.unicast_mac = 0; 3379250661Sdavidcs } 3380250661Sdavidcs 3381250661Sdavidcs rcntxt = (q80_rcv_cntxt_destroy_t *)ha->hw.mbox; 3382250661Sdavidcs bzero(rcntxt, (sizeof (q80_rcv_cntxt_destroy_t))); 3383250661Sdavidcs 3384250661Sdavidcs rcntxt->opcode = Q8_MBX_DESTROY_RX_CNTXT; 3385250661Sdavidcs rcntxt->count_version = (sizeof (q80_rcv_cntxt_destroy_t) >> 2); 3386250661Sdavidcs rcntxt->count_version |= Q8_MBX_CMD_VERSION; 3387250661Sdavidcs 3388250661Sdavidcs rcntxt->cntxt_id = ha->hw.rcv_cntxt_id; 3389250661Sdavidcs 3390250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)rcntxt, 3391250661Sdavidcs (sizeof (q80_rcv_cntxt_destroy_t) >> 2), 3392250661Sdavidcs ha->hw.mbox, (sizeof(q80_rcv_cntxt_destroy_rsp_t) >> 2), 0)) { 3393250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3394250661Sdavidcs return; 3395250661Sdavidcs } 3396250661Sdavidcs rcntxt_rsp = (q80_rcv_cntxt_destroy_rsp_t *)ha->hw.mbox; 3397250661Sdavidcs 3398250661Sdavidcs err = Q8_MBX_RSP_STATUS(rcntxt_rsp->regcnt_status); 3399250661Sdavidcs 3400250661Sdavidcs if (err) { 3401250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3402250661Sdavidcs } 3403250661Sdavidcs 3404250661Sdavidcs ha->hw.flags.init_rx_cnxt = 0; 3405250661Sdavidcs return; 3406250661Sdavidcs} 3407250661Sdavidcs 3408250661Sdavidcs/* 3409250661Sdavidcs * Name: qla_init_xmt_cntxt 3410250661Sdavidcs * Function: Creates the Transmit Context. 3411250661Sdavidcs */ 3412250661Sdavidcsstatic int 3413250661Sdavidcsqla_init_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx) 3414250661Sdavidcs{ 3415250661Sdavidcs device_t dev; 3416250661Sdavidcs qla_hw_t *hw = &ha->hw; 3417250661Sdavidcs q80_rq_tx_cntxt_t *tcntxt; 3418250661Sdavidcs q80_rsp_tx_cntxt_t *tcntxt_rsp; 3419250661Sdavidcs uint32_t err; 3420250661Sdavidcs qla_hw_tx_cntxt_t *hw_tx_cntxt; 3421313070Sdavidcs uint32_t intr_idx; 3422250661Sdavidcs 3423250661Sdavidcs hw_tx_cntxt = &hw->tx_cntxt[txr_idx]; 3424250661Sdavidcs 3425250661Sdavidcs dev = ha->pci_dev; 3426250661Sdavidcs 3427250661Sdavidcs /* 3428250661Sdavidcs * Create Transmit Context 3429250661Sdavidcs */ 3430250661Sdavidcs tcntxt = (q80_rq_tx_cntxt_t *)ha->hw.mbox; 3431250661Sdavidcs bzero(tcntxt, (sizeof (q80_rq_tx_cntxt_t))); 3432250661Sdavidcs 3433250661Sdavidcs tcntxt->opcode = Q8_MBX_CREATE_TX_CNTXT; 3434250661Sdavidcs tcntxt->count_version = (sizeof (q80_rq_tx_cntxt_t) >> 2); 3435250661Sdavidcs tcntxt->count_version |= Q8_MBX_CMD_VERSION; 3436250661Sdavidcs 3437313070Sdavidcs intr_idx = txr_idx; 3438313070Sdavidcs 3439284741Sdavidcs#ifdef QL_ENABLE_ISCSI_TLV 3440284741Sdavidcs 3441284741Sdavidcs tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO | 3442284741Sdavidcs Q8_TX_CNTXT_CAP0_TC; 3443284741Sdavidcs 3444284741Sdavidcs if (txr_idx >= (ha->hw.num_tx_rings >> 1)) { 3445284741Sdavidcs tcntxt->traffic_class = 1; 3446284741Sdavidcs } 3447284741Sdavidcs 3448313070Sdavidcs intr_idx = txr_idx % (ha->hw.num_tx_rings >> 1); 3449313070Sdavidcs 3450284741Sdavidcs#else 3451250661Sdavidcs tcntxt->cap0 = Q8_TX_CNTXT_CAP0_BASEFW | Q8_TX_CNTXT_CAP0_LSO; 3452250661Sdavidcs 3453284741Sdavidcs#endif /* #ifdef QL_ENABLE_ISCSI_TLV */ 3454284741Sdavidcs 3455250661Sdavidcs tcntxt->ntx_rings = 1; 3456250661Sdavidcs 3457250661Sdavidcs tcntxt->tx_ring[0].paddr = 3458250661Sdavidcs qla_host_to_le64(hw_tx_cntxt->tx_ring_paddr); 3459250661Sdavidcs tcntxt->tx_ring[0].tx_consumer = 3460250661Sdavidcs qla_host_to_le64(hw_tx_cntxt->tx_cons_paddr); 3461250661Sdavidcs tcntxt->tx_ring[0].nentries = qla_host_to_le16(NUM_TX_DESCRIPTORS); 3462250661Sdavidcs 3463313070Sdavidcs tcntxt->tx_ring[0].intr_id = qla_host_to_le16(hw->intr_id[intr_idx]); 3464250661Sdavidcs tcntxt->tx_ring[0].intr_src_bit = qla_host_to_le16(0); 3465250661Sdavidcs 3466250661Sdavidcs hw_tx_cntxt->txr_free = NUM_TX_DESCRIPTORS; 3467250661Sdavidcs hw_tx_cntxt->txr_next = hw_tx_cntxt->txr_comp = 0; 3468324325Sdavidcs *hw_tx_cntxt->tx_cons = 0; 3469250661Sdavidcs 3470250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)tcntxt, 3471250661Sdavidcs (sizeof (q80_rq_tx_cntxt_t) >> 2), 3472250661Sdavidcs ha->hw.mbox, 3473250661Sdavidcs (sizeof(q80_rsp_tx_cntxt_t) >> 2), 0)) { 3474250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3475250661Sdavidcs return (-1); 3476250661Sdavidcs } 3477250661Sdavidcs tcntxt_rsp = (q80_rsp_tx_cntxt_t *)ha->hw.mbox; 3478250661Sdavidcs 3479250661Sdavidcs err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status); 3480250661Sdavidcs 3481250661Sdavidcs if (err) { 3482250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3483250661Sdavidcs return -1; 3484250661Sdavidcs } 3485250661Sdavidcs 3486250661Sdavidcs hw_tx_cntxt->tx_prod_reg = tcntxt_rsp->tx_ring[0].prod_index; 3487250661Sdavidcs hw_tx_cntxt->tx_cntxt_id = tcntxt_rsp->tx_ring[0].cntxt_id; 3488250661Sdavidcs 3489284741Sdavidcs if (qla_config_intr_coalesce(ha, hw_tx_cntxt->tx_cntxt_id, 0, 0)) 3490284741Sdavidcs return (-1); 3491284741Sdavidcs 3492250661Sdavidcs return (0); 3493250661Sdavidcs} 3494250661Sdavidcs 3495250661Sdavidcs 3496250661Sdavidcs/* 3497250661Sdavidcs * Name: qla_del_xmt_cntxt 3498250661Sdavidcs * Function: Destroys the Transmit Context. 3499250661Sdavidcs */ 3500250661Sdavidcsstatic int 3501250661Sdavidcsqla_del_xmt_cntxt_i(qla_host_t *ha, uint32_t txr_idx) 3502250661Sdavidcs{ 3503250661Sdavidcs device_t dev = ha->pci_dev; 3504250661Sdavidcs q80_tx_cntxt_destroy_t *tcntxt; 3505250661Sdavidcs q80_tx_cntxt_destroy_rsp_t *tcntxt_rsp; 3506250661Sdavidcs uint32_t err; 3507250661Sdavidcs 3508250661Sdavidcs tcntxt = (q80_tx_cntxt_destroy_t *)ha->hw.mbox; 3509250661Sdavidcs bzero(tcntxt, (sizeof (q80_tx_cntxt_destroy_t))); 3510250661Sdavidcs 3511250661Sdavidcs tcntxt->opcode = Q8_MBX_DESTROY_TX_CNTXT; 3512250661Sdavidcs tcntxt->count_version = (sizeof (q80_tx_cntxt_destroy_t) >> 2); 3513250661Sdavidcs tcntxt->count_version |= Q8_MBX_CMD_VERSION; 3514250661Sdavidcs 3515250661Sdavidcs tcntxt->cntxt_id = ha->hw.tx_cntxt[txr_idx].tx_cntxt_id; 3516250661Sdavidcs 3517250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)tcntxt, 3518250661Sdavidcs (sizeof (q80_tx_cntxt_destroy_t) >> 2), 3519250661Sdavidcs ha->hw.mbox, (sizeof (q80_tx_cntxt_destroy_rsp_t) >> 2), 0)) { 3520250661Sdavidcs device_printf(dev, "%s: failed0\n", __func__); 3521250661Sdavidcs return (-1); 3522250661Sdavidcs } 3523250661Sdavidcs tcntxt_rsp = (q80_tx_cntxt_destroy_rsp_t *)ha->hw.mbox; 3524250661Sdavidcs 3525250661Sdavidcs err = Q8_MBX_RSP_STATUS(tcntxt_rsp->regcnt_status); 3526250661Sdavidcs 3527250661Sdavidcs if (err) { 3528250661Sdavidcs device_printf(dev, "%s: failed1 [0x%08x]\n", __func__, err); 3529250661Sdavidcs return (-1); 3530250661Sdavidcs } 3531250661Sdavidcs 3532250661Sdavidcs return (0); 3533250661Sdavidcs} 3534330555Sdavidcsstatic int 3535250661Sdavidcsqla_del_xmt_cntxt(qla_host_t *ha) 3536250661Sdavidcs{ 3537250661Sdavidcs uint32_t i; 3538330555Sdavidcs int ret = 0; 3539250661Sdavidcs 3540250661Sdavidcs if (!ha->hw.flags.init_tx_cnxt) 3541330555Sdavidcs return (ret); 3542250661Sdavidcs 3543250661Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 3544330555Sdavidcs if ((ret = qla_del_xmt_cntxt_i(ha, i)) != 0) 3545250661Sdavidcs break; 3546250661Sdavidcs } 3547250661Sdavidcs ha->hw.flags.init_tx_cnxt = 0; 3548330555Sdavidcs 3549330555Sdavidcs return (ret); 3550250661Sdavidcs} 3551250661Sdavidcs 3552250661Sdavidcsstatic int 3553250661Sdavidcsqla_init_xmt_cntxt(qla_host_t *ha) 3554250661Sdavidcs{ 3555250661Sdavidcs uint32_t i, j; 3556250661Sdavidcs 3557250661Sdavidcs for (i = 0; i < ha->hw.num_tx_rings; i++) { 3558250661Sdavidcs if (qla_init_xmt_cntxt_i(ha, i) != 0) { 3559330555Sdavidcs for (j = 0; j < i; j++) { 3560330555Sdavidcs if (qla_del_xmt_cntxt_i(ha, j)) 3561330555Sdavidcs break; 3562330555Sdavidcs } 3563250661Sdavidcs return (-1); 3564250661Sdavidcs } 3565250661Sdavidcs } 3566250661Sdavidcs ha->hw.flags.init_tx_cnxt = 1; 3567250661Sdavidcs return (0); 3568250661Sdavidcs} 3569250661Sdavidcs 3570250661Sdavidcsstatic int 3571307524Sdavidcsqla_hw_all_mcast(qla_host_t *ha, uint32_t add_mcast) 3572250661Sdavidcs{ 3573250661Sdavidcs int i, nmcast; 3574307524Sdavidcs uint32_t count = 0; 3575307524Sdavidcs uint8_t *mcast; 3576250661Sdavidcs 3577250661Sdavidcs nmcast = ha->hw.nmcast; 3578250661Sdavidcs 3579307524Sdavidcs QL_DPRINT2(ha, (ha->pci_dev, 3580307524Sdavidcs "%s:[0x%x] enter nmcast = %d \n", __func__, add_mcast, nmcast)); 3581307524Sdavidcs 3582307524Sdavidcs mcast = ha->hw.mac_addr_arr; 3583307524Sdavidcs memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN)); 3584307524Sdavidcs 3585250661Sdavidcs for (i = 0 ; ((i < Q8_MAX_NUM_MULTICAST_ADDRS) && nmcast); i++) { 3586250661Sdavidcs if ((ha->hw.mcast[i].addr[0] != 0) || 3587250661Sdavidcs (ha->hw.mcast[i].addr[1] != 0) || 3588250661Sdavidcs (ha->hw.mcast[i].addr[2] != 0) || 3589250661Sdavidcs (ha->hw.mcast[i].addr[3] != 0) || 3590250661Sdavidcs (ha->hw.mcast[i].addr[4] != 0) || 3591250661Sdavidcs (ha->hw.mcast[i].addr[5] != 0)) { 3592250661Sdavidcs 3593307524Sdavidcs bcopy(ha->hw.mcast[i].addr, mcast, ETHER_ADDR_LEN); 3594307524Sdavidcs mcast = mcast + ETHER_ADDR_LEN; 3595307524Sdavidcs count++; 3596332052Sdavidcs 3597332052Sdavidcs device_printf(ha->pci_dev, 3598332052Sdavidcs "%s: %x:%x:%x:%x:%x:%x \n", 3599332052Sdavidcs __func__, ha->hw.mcast[i].addr[0], 3600332052Sdavidcs ha->hw.mcast[i].addr[1], ha->hw.mcast[i].addr[2], 3601332052Sdavidcs ha->hw.mcast[i].addr[3], ha->hw.mcast[i].addr[4], 3602332052Sdavidcs ha->hw.mcast[i].addr[5]); 3603307524Sdavidcs 3604307524Sdavidcs if (count == Q8_MAX_MAC_ADDRS) { 3605307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, 3606307524Sdavidcs add_mcast, count)) { 3607307524Sdavidcs device_printf(ha->pci_dev, 3608307524Sdavidcs "%s: failed\n", __func__); 3609307524Sdavidcs return (-1); 3610307524Sdavidcs } 3611307524Sdavidcs 3612307524Sdavidcs count = 0; 3613307524Sdavidcs mcast = ha->hw.mac_addr_arr; 3614307524Sdavidcs memset(mcast, 0, 3615307524Sdavidcs (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN)); 3616250661Sdavidcs } 3617250661Sdavidcs 3618250661Sdavidcs nmcast--; 3619250661Sdavidcs } 3620250661Sdavidcs } 3621307524Sdavidcs 3622307524Sdavidcs if (count) { 3623307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mcast, 3624307524Sdavidcs count)) { 3625307524Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 3626307524Sdavidcs return (-1); 3627307524Sdavidcs } 3628307524Sdavidcs } 3629307524Sdavidcs QL_DPRINT2(ha, (ha->pci_dev, 3630307524Sdavidcs "%s:[0x%x] exit nmcast = %d \n", __func__, add_mcast, nmcast)); 3631307524Sdavidcs 3632250661Sdavidcs return 0; 3633250661Sdavidcs} 3634250661Sdavidcs 3635250661Sdavidcsstatic int 3636307524Sdavidcsqla_hw_add_all_mcast(qla_host_t *ha) 3637307524Sdavidcs{ 3638307524Sdavidcs int ret; 3639307524Sdavidcs 3640307524Sdavidcs ret = qla_hw_all_mcast(ha, 1); 3641307524Sdavidcs 3642307524Sdavidcs return (ret); 3643307524Sdavidcs} 3644307524Sdavidcs 3645324324Sdavidcsint 3646250661Sdavidcsqla_hw_del_all_mcast(qla_host_t *ha) 3647250661Sdavidcs{ 3648307524Sdavidcs int ret; 3649250661Sdavidcs 3650307524Sdavidcs ret = qla_hw_all_mcast(ha, 0); 3651250661Sdavidcs 3652307524Sdavidcs bzero(ha->hw.mcast, (sizeof (qla_mcast_t) * Q8_MAX_NUM_MULTICAST_ADDRS)); 3653307524Sdavidcs ha->hw.nmcast = 0; 3654250661Sdavidcs 3655307524Sdavidcs return (ret); 3656250661Sdavidcs} 3657250661Sdavidcs 3658250661Sdavidcsstatic int 3659307524Sdavidcsqla_hw_mac_addr_present(qla_host_t *ha, uint8_t *mta) 3660250661Sdavidcs{ 3661250661Sdavidcs int i; 3662250661Sdavidcs 3663250661Sdavidcs for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) { 3664250661Sdavidcs if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0) 3665307524Sdavidcs return (0); /* its been already added */ 3666250661Sdavidcs } 3667307524Sdavidcs return (-1); 3668307524Sdavidcs} 3669250661Sdavidcs 3670307524Sdavidcsstatic int 3671307524Sdavidcsqla_hw_add_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast) 3672307524Sdavidcs{ 3673307524Sdavidcs int i; 3674307524Sdavidcs 3675250661Sdavidcs for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) { 3676250661Sdavidcs 3677250661Sdavidcs if ((ha->hw.mcast[i].addr[0] == 0) && 3678250661Sdavidcs (ha->hw.mcast[i].addr[1] == 0) && 3679250661Sdavidcs (ha->hw.mcast[i].addr[2] == 0) && 3680250661Sdavidcs (ha->hw.mcast[i].addr[3] == 0) && 3681250661Sdavidcs (ha->hw.mcast[i].addr[4] == 0) && 3682250661Sdavidcs (ha->hw.mcast[i].addr[5] == 0)) { 3683250661Sdavidcs 3684250661Sdavidcs bcopy(mta, ha->hw.mcast[i].addr, Q8_MAC_ADDR_LEN); 3685250661Sdavidcs ha->hw.nmcast++; 3686250661Sdavidcs 3687307524Sdavidcs mta = mta + ETHER_ADDR_LEN; 3688307524Sdavidcs nmcast--; 3689307524Sdavidcs 3690307524Sdavidcs if (nmcast == 0) 3691307524Sdavidcs break; 3692250661Sdavidcs } 3693307524Sdavidcs 3694250661Sdavidcs } 3695250661Sdavidcs return 0; 3696250661Sdavidcs} 3697250661Sdavidcs 3698250661Sdavidcsstatic int 3699307524Sdavidcsqla_hw_del_mcast(qla_host_t *ha, uint8_t *mta, uint32_t nmcast) 3700250661Sdavidcs{ 3701250661Sdavidcs int i; 3702250661Sdavidcs 3703250661Sdavidcs for (i = 0; i < Q8_MAX_NUM_MULTICAST_ADDRS; i++) { 3704250661Sdavidcs if (QL_MAC_CMP(ha->hw.mcast[i].addr, mta) == 0) { 3705250661Sdavidcs 3706250661Sdavidcs ha->hw.mcast[i].addr[0] = 0; 3707250661Sdavidcs ha->hw.mcast[i].addr[1] = 0; 3708250661Sdavidcs ha->hw.mcast[i].addr[2] = 0; 3709250661Sdavidcs ha->hw.mcast[i].addr[3] = 0; 3710250661Sdavidcs ha->hw.mcast[i].addr[4] = 0; 3711250661Sdavidcs ha->hw.mcast[i].addr[5] = 0; 3712250661Sdavidcs 3713250661Sdavidcs ha->hw.nmcast--; 3714250661Sdavidcs 3715307524Sdavidcs mta = mta + ETHER_ADDR_LEN; 3716307524Sdavidcs nmcast--; 3717307524Sdavidcs 3718307524Sdavidcs if (nmcast == 0) 3719307524Sdavidcs break; 3720250661Sdavidcs } 3721250661Sdavidcs } 3722250661Sdavidcs return 0; 3723250661Sdavidcs} 3724250661Sdavidcs 3725250661Sdavidcs/* 3726250661Sdavidcs * Name: ql_hw_set_multi 3727307524Sdavidcs * Function: Sets the Multicast Addresses provided by the host O.S into the 3728250661Sdavidcs * hardware (for the given interface) 3729250661Sdavidcs */ 3730250661Sdavidcsint 3731307524Sdavidcsql_hw_set_multi(qla_host_t *ha, uint8_t *mcast_addr, uint32_t mcnt, 3732250661Sdavidcs uint32_t add_mac) 3733250661Sdavidcs{ 3734307524Sdavidcs uint8_t *mta = mcast_addr; 3735250661Sdavidcs int i; 3736250661Sdavidcs int ret = 0; 3737307524Sdavidcs uint32_t count = 0; 3738307524Sdavidcs uint8_t *mcast; 3739250661Sdavidcs 3740307524Sdavidcs mcast = ha->hw.mac_addr_arr; 3741307524Sdavidcs memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN)); 3742307524Sdavidcs 3743250661Sdavidcs for (i = 0; i < mcnt; i++) { 3744307524Sdavidcs if (mta[0] || mta[1] || mta[2] || mta[3] || mta[4] || mta[5]) { 3745307524Sdavidcs if (add_mac) { 3746307524Sdavidcs if (qla_hw_mac_addr_present(ha, mta) != 0) { 3747307524Sdavidcs bcopy(mta, mcast, ETHER_ADDR_LEN); 3748307524Sdavidcs mcast = mcast + ETHER_ADDR_LEN; 3749307524Sdavidcs count++; 3750307524Sdavidcs } 3751307524Sdavidcs } else { 3752307524Sdavidcs if (qla_hw_mac_addr_present(ha, mta) == 0) { 3753307524Sdavidcs bcopy(mta, mcast, ETHER_ADDR_LEN); 3754307524Sdavidcs mcast = mcast + ETHER_ADDR_LEN; 3755307524Sdavidcs count++; 3756307524Sdavidcs } 3757307524Sdavidcs } 3758250661Sdavidcs } 3759307524Sdavidcs if (count == Q8_MAX_MAC_ADDRS) { 3760307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, 3761307524Sdavidcs add_mac, count)) { 3762307524Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", 3763307524Sdavidcs __func__); 3764307524Sdavidcs return (-1); 3765307524Sdavidcs } 3766307524Sdavidcs 3767307524Sdavidcs if (add_mac) { 3768307524Sdavidcs qla_hw_add_mcast(ha, ha->hw.mac_addr_arr, 3769307524Sdavidcs count); 3770307524Sdavidcs } else { 3771307524Sdavidcs qla_hw_del_mcast(ha, ha->hw.mac_addr_arr, 3772307524Sdavidcs count); 3773307524Sdavidcs } 3774307524Sdavidcs 3775307524Sdavidcs count = 0; 3776307524Sdavidcs mcast = ha->hw.mac_addr_arr; 3777307524Sdavidcs memset(mcast, 0, (Q8_MAX_MAC_ADDRS * ETHER_ADDR_LEN)); 3778307524Sdavidcs } 3779250661Sdavidcs 3780250661Sdavidcs mta += Q8_MAC_ADDR_LEN; 3781250661Sdavidcs } 3782307524Sdavidcs 3783307524Sdavidcs if (count) { 3784307524Sdavidcs if (qla_config_mac_addr(ha, ha->hw.mac_addr_arr, add_mac, 3785307524Sdavidcs count)) { 3786307524Sdavidcs device_printf(ha->pci_dev, "%s: failed\n", __func__); 3787307524Sdavidcs return (-1); 3788307524Sdavidcs } 3789307524Sdavidcs if (add_mac) { 3790307524Sdavidcs qla_hw_add_mcast(ha, ha->hw.mac_addr_arr, count); 3791307524Sdavidcs } else { 3792307524Sdavidcs qla_hw_del_mcast(ha, ha->hw.mac_addr_arr, count); 3793307524Sdavidcs } 3794307524Sdavidcs } 3795307524Sdavidcs 3796250661Sdavidcs return (ret); 3797250661Sdavidcs} 3798250661Sdavidcs 3799250661Sdavidcs/* 3800313070Sdavidcs * Name: ql_hw_tx_done_locked 3801250661Sdavidcs * Function: Handle Transmit Completions 3802250661Sdavidcs */ 3803313070Sdavidcsvoid 3804313070Sdavidcsql_hw_tx_done_locked(qla_host_t *ha, uint32_t txr_idx) 3805250661Sdavidcs{ 3806250661Sdavidcs qla_tx_buf_t *txb; 3807250661Sdavidcs qla_hw_t *hw = &ha->hw; 3808250661Sdavidcs uint32_t comp_idx, comp_count = 0; 3809250661Sdavidcs qla_hw_tx_cntxt_t *hw_tx_cntxt; 3810250661Sdavidcs 3811250661Sdavidcs hw_tx_cntxt = &hw->tx_cntxt[txr_idx]; 3812250661Sdavidcs 3813250661Sdavidcs /* retrieve index of last entry in tx ring completed */ 3814250661Sdavidcs comp_idx = qla_le32_to_host(*(hw_tx_cntxt->tx_cons)); 3815250661Sdavidcs 3816250661Sdavidcs while (comp_idx != hw_tx_cntxt->txr_comp) { 3817250661Sdavidcs 3818250661Sdavidcs txb = &ha->tx_ring[txr_idx].tx_buf[hw_tx_cntxt->txr_comp]; 3819250661Sdavidcs 3820250661Sdavidcs hw_tx_cntxt->txr_comp++; 3821250661Sdavidcs if (hw_tx_cntxt->txr_comp == NUM_TX_DESCRIPTORS) 3822250661Sdavidcs hw_tx_cntxt->txr_comp = 0; 3823250661Sdavidcs 3824250661Sdavidcs comp_count++; 3825250661Sdavidcs 3826250661Sdavidcs if (txb->m_head) { 3827271849Sglebius if_inc_counter(ha->ifp, IFCOUNTER_OPACKETS, 1); 3828250661Sdavidcs 3829250661Sdavidcs bus_dmamap_sync(ha->tx_tag, txb->map, 3830250661Sdavidcs BUS_DMASYNC_POSTWRITE); 3831250661Sdavidcs bus_dmamap_unload(ha->tx_tag, txb->map); 3832250661Sdavidcs m_freem(txb->m_head); 3833250661Sdavidcs 3834250661Sdavidcs txb->m_head = NULL; 3835250661Sdavidcs } 3836250661Sdavidcs } 3837250661Sdavidcs 3838250661Sdavidcs hw_tx_cntxt->txr_free += comp_count; 3839332052Sdavidcs 3840332052Sdavidcs if (hw_tx_cntxt->txr_free > NUM_TX_DESCRIPTORS) 3841332052Sdavidcs device_printf(ha->pci_dev, "%s [%d]: txr_idx = %d txr_free = %d" 3842332052Sdavidcs "txr_next = %d txr_comp = %d\n", __func__, __LINE__, 3843332052Sdavidcs txr_idx, hw_tx_cntxt->txr_free, 3844332052Sdavidcs hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp); 3845332052Sdavidcs 3846332052Sdavidcs QL_ASSERT(ha, (hw_tx_cntxt->txr_free <= NUM_TX_DESCRIPTORS), \ 3847332052Sdavidcs ("%s [%d]: txr_idx = %d txr_free = %d txr_next = %d txr_comp = %d\n",\ 3848332052Sdavidcs __func__, __LINE__, txr_idx, hw_tx_cntxt->txr_free, \ 3849332052Sdavidcs hw_tx_cntxt->txr_next, hw_tx_cntxt->txr_comp)); 3850332052Sdavidcs 3851250661Sdavidcs return; 3852250661Sdavidcs} 3853250661Sdavidcs 3854250661Sdavidcsvoid 3855250661Sdavidcsql_update_link_state(qla_host_t *ha) 3856250661Sdavidcs{ 3857330555Sdavidcs uint32_t link_state = 0; 3858250661Sdavidcs uint32_t prev_link_state; 3859250661Sdavidcs 3860330555Sdavidcs prev_link_state = ha->hw.link_up; 3861330555Sdavidcs 3862330555Sdavidcs if (ha->ifp->if_drv_flags & IFF_DRV_RUNNING) { 3863330555Sdavidcs link_state = READ_REG32(ha, Q8_LINK_STATE); 3864330555Sdavidcs 3865330555Sdavidcs if (ha->pci_func == 0) { 3866330555Sdavidcs link_state = (((link_state & 0xF) == 1)? 1 : 0); 3867330555Sdavidcs } else { 3868330555Sdavidcs link_state = ((((link_state >> 4)& 0xF) == 1)? 1 : 0); 3869330555Sdavidcs } 3870250661Sdavidcs } 3871250661Sdavidcs 3872330555Sdavidcs atomic_store_rel_8(&ha->hw.link_up, (uint8_t)link_state); 3873250661Sdavidcs 3874250661Sdavidcs if (prev_link_state != ha->hw.link_up) { 3875250661Sdavidcs if (ha->hw.link_up) { 3876250661Sdavidcs if_link_state_change(ha->ifp, LINK_STATE_UP); 3877250661Sdavidcs } else { 3878250661Sdavidcs if_link_state_change(ha->ifp, LINK_STATE_DOWN); 3879250661Sdavidcs } 3880250661Sdavidcs } 3881250661Sdavidcs return; 3882250661Sdavidcs} 3883250661Sdavidcs 3884250661Sdavidcsint 3885250661Sdavidcsql_hw_check_health(qla_host_t *ha) 3886250661Sdavidcs{ 3887250661Sdavidcs uint32_t val; 3888250661Sdavidcs 3889250661Sdavidcs ha->hw.health_count++; 3890250661Sdavidcs 3891321496Sdavidcs if (ha->hw.health_count < 500) 3892250661Sdavidcs return 0; 3893250661Sdavidcs 3894250661Sdavidcs ha->hw.health_count = 0; 3895250661Sdavidcs 3896250661Sdavidcs val = READ_REG32(ha, Q8_ASIC_TEMPERATURE); 3897250661Sdavidcs 3898250661Sdavidcs if (((val & 0xFFFF) == 2) || ((val & 0xFFFF) == 3) || 3899250661Sdavidcs (QL_ERR_INJECT(ha, INJCT_TEMPERATURE_FAILURE))) { 3900330555Sdavidcs device_printf(ha->pci_dev, "%s: Temperature Alert" 3901330555Sdavidcs " at ts_usecs %ld ts_reg = 0x%08x\n", 3902330555Sdavidcs __func__, qla_get_usec_timestamp(), val); 3903330555Sdavidcs 3904330555Sdavidcs if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_TEMP_FAILURE) 3905330555Sdavidcs ha->hw.sp_log_stop = -1; 3906330555Sdavidcs 3907330555Sdavidcs QL_INITIATE_RECOVERY(ha); 3908250661Sdavidcs return -1; 3909250661Sdavidcs } 3910250661Sdavidcs 3911250661Sdavidcs val = READ_REG32(ha, Q8_FIRMWARE_HEARTBEAT); 3912250661Sdavidcs 3913250661Sdavidcs if ((val != ha->hw.hbeat_value) && 3914289635Sdavidcs (!(QL_ERR_INJECT(ha, INJCT_HEARTBEAT_FAILURE)))) { 3915250661Sdavidcs ha->hw.hbeat_value = val; 3916321496Sdavidcs ha->hw.hbeat_failure = 0; 3917250661Sdavidcs return 0; 3918250661Sdavidcs } 3919250661Sdavidcs 3920321496Sdavidcs ha->hw.hbeat_failure++; 3921321496Sdavidcs 3922322972Sdavidcs 3923322972Sdavidcs if ((ha->dbg_level & 0x8000) && (ha->hw.hbeat_failure == 1)) 3924322972Sdavidcs device_printf(ha->pci_dev, "%s: Heartbeat Failue 1[0x%08x]\n", 3925322972Sdavidcs __func__, val); 3926321496Sdavidcs if (ha->hw.hbeat_failure < 2) /* we ignore the first failure */ 3927321496Sdavidcs return 0; 3928330555Sdavidcs else { 3929330555Sdavidcs uint32_t peg_halt_status1; 3930330555Sdavidcs uint32_t peg_halt_status2; 3931321496Sdavidcs 3932330555Sdavidcs peg_halt_status1 = READ_REG32(ha, Q8_PEG_HALT_STATUS1); 3933330555Sdavidcs peg_halt_status2 = READ_REG32(ha, Q8_PEG_HALT_STATUS2); 3934330555Sdavidcs 3935330555Sdavidcs device_printf(ha->pci_dev, 3936330555Sdavidcs "%s: Heartbeat Failue at ts_usecs = %ld " 3937330555Sdavidcs "fw_heart_beat = 0x%08x " 3938330555Sdavidcs "peg_halt_status1 = 0x%08x " 3939330555Sdavidcs "peg_halt_status2 = 0x%08x\n", 3940330555Sdavidcs __func__, qla_get_usec_timestamp(), val, 3941330555Sdavidcs peg_halt_status1, peg_halt_status2); 3942330555Sdavidcs 3943330555Sdavidcs if (ha->hw.sp_log_stop_events & Q8_SP_LOG_STOP_HBEAT_FAILURE) 3944330555Sdavidcs ha->hw.sp_log_stop = -1; 3945330555Sdavidcs } 3946330555Sdavidcs QL_INITIATE_RECOVERY(ha); 3947330555Sdavidcs 3948250661Sdavidcs return -1; 3949250661Sdavidcs} 3950250661Sdavidcs 3951250661Sdavidcsstatic int 3952284741Sdavidcsqla_init_nic_func(qla_host_t *ha) 3953284741Sdavidcs{ 3954284741Sdavidcs device_t dev; 3955284741Sdavidcs q80_init_nic_func_t *init_nic; 3956284741Sdavidcs q80_init_nic_func_rsp_t *init_nic_rsp; 3957284741Sdavidcs uint32_t err; 3958284741Sdavidcs 3959284741Sdavidcs dev = ha->pci_dev; 3960284741Sdavidcs 3961284741Sdavidcs init_nic = (q80_init_nic_func_t *)ha->hw.mbox; 3962284741Sdavidcs bzero(init_nic, sizeof(q80_init_nic_func_t)); 3963284741Sdavidcs 3964284741Sdavidcs init_nic->opcode = Q8_MBX_INIT_NIC_FUNC; 3965284741Sdavidcs init_nic->count_version = (sizeof (q80_init_nic_func_t) >> 2); 3966284741Sdavidcs init_nic->count_version |= Q8_MBX_CMD_VERSION; 3967284741Sdavidcs 3968284741Sdavidcs init_nic->options = Q8_INIT_NIC_REG_DCBX_CHNG_AEN; 3969284741Sdavidcs init_nic->options |= Q8_INIT_NIC_REG_SFP_CHNG_AEN; 3970284741Sdavidcs init_nic->options |= Q8_INIT_NIC_REG_IDC_AEN; 3971284741Sdavidcs 3972284741Sdavidcs//qla_dump_buf8(ha, __func__, init_nic, sizeof (q80_init_nic_func_t)); 3973284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)init_nic, 3974284741Sdavidcs (sizeof (q80_init_nic_func_t) >> 2), 3975284741Sdavidcs ha->hw.mbox, (sizeof (q80_init_nic_func_rsp_t) >> 2), 0)) { 3976284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 3977284741Sdavidcs return -1; 3978284741Sdavidcs } 3979284741Sdavidcs 3980284741Sdavidcs init_nic_rsp = (q80_init_nic_func_rsp_t *)ha->hw.mbox; 3981284741Sdavidcs// qla_dump_buf8(ha, __func__, init_nic_rsp, sizeof (q80_init_nic_func_rsp_t)); 3982284741Sdavidcs 3983284741Sdavidcs err = Q8_MBX_RSP_STATUS(init_nic_rsp->regcnt_status); 3984284741Sdavidcs 3985284741Sdavidcs if (err) { 3986284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 3987332052Sdavidcs } else { 3988332052Sdavidcs device_printf(dev, "%s: successful\n", __func__); 3989332052Sdavidcs } 3990284741Sdavidcs 3991284741Sdavidcs return 0; 3992284741Sdavidcs} 3993284741Sdavidcs 3994284741Sdavidcsstatic int 3995284741Sdavidcsqla_stop_nic_func(qla_host_t *ha) 3996284741Sdavidcs{ 3997284741Sdavidcs device_t dev; 3998284741Sdavidcs q80_stop_nic_func_t *stop_nic; 3999284741Sdavidcs q80_stop_nic_func_rsp_t *stop_nic_rsp; 4000284741Sdavidcs uint32_t err; 4001284741Sdavidcs 4002284741Sdavidcs dev = ha->pci_dev; 4003284741Sdavidcs 4004284741Sdavidcs stop_nic = (q80_stop_nic_func_t *)ha->hw.mbox; 4005284741Sdavidcs bzero(stop_nic, sizeof(q80_stop_nic_func_t)); 4006284741Sdavidcs 4007284741Sdavidcs stop_nic->opcode = Q8_MBX_STOP_NIC_FUNC; 4008284741Sdavidcs stop_nic->count_version = (sizeof (q80_stop_nic_func_t) >> 2); 4009284741Sdavidcs stop_nic->count_version |= Q8_MBX_CMD_VERSION; 4010284741Sdavidcs 4011284741Sdavidcs stop_nic->options = Q8_STOP_NIC_DEREG_DCBX_CHNG_AEN; 4012284741Sdavidcs stop_nic->options |= Q8_STOP_NIC_DEREG_SFP_CHNG_AEN; 4013284741Sdavidcs 4014284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic, sizeof (q80_stop_nic_func_t)); 4015284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)stop_nic, 4016284741Sdavidcs (sizeof (q80_stop_nic_func_t) >> 2), 4017284741Sdavidcs ha->hw.mbox, (sizeof (q80_stop_nic_func_rsp_t) >> 2), 0)) { 4018284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4019284741Sdavidcs return -1; 4020284741Sdavidcs } 4021284741Sdavidcs 4022284741Sdavidcs stop_nic_rsp = (q80_stop_nic_func_rsp_t *)ha->hw.mbox; 4023284741Sdavidcs//qla_dump_buf8(ha, __func__, stop_nic_rsp, sizeof (q80_stop_nic_func_rsp_ t)); 4024284741Sdavidcs 4025284741Sdavidcs err = Q8_MBX_RSP_STATUS(stop_nic_rsp->regcnt_status); 4026284741Sdavidcs 4027284741Sdavidcs if (err) { 4028284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4029284741Sdavidcs } 4030284741Sdavidcs 4031284741Sdavidcs return 0; 4032284741Sdavidcs} 4033284741Sdavidcs 4034284741Sdavidcsstatic int 4035284741Sdavidcsqla_query_fw_dcbx_caps(qla_host_t *ha) 4036284741Sdavidcs{ 4037284741Sdavidcs device_t dev; 4038284741Sdavidcs q80_query_fw_dcbx_caps_t *fw_dcbx; 4039284741Sdavidcs q80_query_fw_dcbx_caps_rsp_t *fw_dcbx_rsp; 4040284741Sdavidcs uint32_t err; 4041284741Sdavidcs 4042284741Sdavidcs dev = ha->pci_dev; 4043284741Sdavidcs 4044284741Sdavidcs fw_dcbx = (q80_query_fw_dcbx_caps_t *)ha->hw.mbox; 4045284741Sdavidcs bzero(fw_dcbx, sizeof(q80_query_fw_dcbx_caps_t)); 4046284741Sdavidcs 4047284741Sdavidcs fw_dcbx->opcode = Q8_MBX_GET_FW_DCBX_CAPS; 4048284741Sdavidcs fw_dcbx->count_version = (sizeof (q80_query_fw_dcbx_caps_t) >> 2); 4049284741Sdavidcs fw_dcbx->count_version |= Q8_MBX_CMD_VERSION; 4050284741Sdavidcs 4051284741Sdavidcs ql_dump_buf8(ha, __func__, fw_dcbx, sizeof (q80_query_fw_dcbx_caps_t)); 4052284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)fw_dcbx, 4053284741Sdavidcs (sizeof (q80_query_fw_dcbx_caps_t) >> 2), 4054284741Sdavidcs ha->hw.mbox, (sizeof (q80_query_fw_dcbx_caps_rsp_t) >> 2), 0)) { 4055284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4056284741Sdavidcs return -1; 4057284741Sdavidcs } 4058284741Sdavidcs 4059284741Sdavidcs fw_dcbx_rsp = (q80_query_fw_dcbx_caps_rsp_t *)ha->hw.mbox; 4060284741Sdavidcs ql_dump_buf8(ha, __func__, fw_dcbx_rsp, 4061284741Sdavidcs sizeof (q80_query_fw_dcbx_caps_rsp_t)); 4062284741Sdavidcs 4063284741Sdavidcs err = Q8_MBX_RSP_STATUS(fw_dcbx_rsp->regcnt_status); 4064284741Sdavidcs 4065284741Sdavidcs if (err) { 4066284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4067284741Sdavidcs } 4068284741Sdavidcs 4069284741Sdavidcs return 0; 4070284741Sdavidcs} 4071284741Sdavidcs 4072284741Sdavidcsstatic int 4073284741Sdavidcsqla_idc_ack(qla_host_t *ha, uint32_t aen_mb1, uint32_t aen_mb2, 4074284741Sdavidcs uint32_t aen_mb3, uint32_t aen_mb4) 4075284741Sdavidcs{ 4076284741Sdavidcs device_t dev; 4077284741Sdavidcs q80_idc_ack_t *idc_ack; 4078284741Sdavidcs q80_idc_ack_rsp_t *idc_ack_rsp; 4079284741Sdavidcs uint32_t err; 4080284741Sdavidcs int count = 300; 4081284741Sdavidcs 4082284741Sdavidcs dev = ha->pci_dev; 4083284741Sdavidcs 4084284741Sdavidcs idc_ack = (q80_idc_ack_t *)ha->hw.mbox; 4085284741Sdavidcs bzero(idc_ack, sizeof(q80_idc_ack_t)); 4086284741Sdavidcs 4087284741Sdavidcs idc_ack->opcode = Q8_MBX_IDC_ACK; 4088284741Sdavidcs idc_ack->count_version = (sizeof (q80_idc_ack_t) >> 2); 4089284741Sdavidcs idc_ack->count_version |= Q8_MBX_CMD_VERSION; 4090284741Sdavidcs 4091284741Sdavidcs idc_ack->aen_mb1 = aen_mb1; 4092284741Sdavidcs idc_ack->aen_mb2 = aen_mb2; 4093284741Sdavidcs idc_ack->aen_mb3 = aen_mb3; 4094284741Sdavidcs idc_ack->aen_mb4 = aen_mb4; 4095284741Sdavidcs 4096284741Sdavidcs ha->hw.imd_compl= 0; 4097284741Sdavidcs 4098284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)idc_ack, 4099284741Sdavidcs (sizeof (q80_idc_ack_t) >> 2), 4100284741Sdavidcs ha->hw.mbox, (sizeof (q80_idc_ack_rsp_t) >> 2), 0)) { 4101284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4102284741Sdavidcs return -1; 4103284741Sdavidcs } 4104284741Sdavidcs 4105284741Sdavidcs idc_ack_rsp = (q80_idc_ack_rsp_t *)ha->hw.mbox; 4106284741Sdavidcs 4107284741Sdavidcs err = Q8_MBX_RSP_STATUS(idc_ack_rsp->regcnt_status); 4108284741Sdavidcs 4109284741Sdavidcs if (err) { 4110284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4111284741Sdavidcs return(-1); 4112284741Sdavidcs } 4113284741Sdavidcs 4114284741Sdavidcs while (count && !ha->hw.imd_compl) { 4115284741Sdavidcs qla_mdelay(__func__, 100); 4116284741Sdavidcs count--; 4117284741Sdavidcs } 4118284741Sdavidcs 4119284741Sdavidcs if (!count) 4120284741Sdavidcs return -1; 4121284741Sdavidcs else 4122284741Sdavidcs device_printf(dev, "%s: count %d\n", __func__, count); 4123284741Sdavidcs 4124284741Sdavidcs return (0); 4125284741Sdavidcs} 4126284741Sdavidcs 4127284741Sdavidcsstatic int 4128284741Sdavidcsqla_set_port_config(qla_host_t *ha, uint32_t cfg_bits) 4129284741Sdavidcs{ 4130284741Sdavidcs device_t dev; 4131284741Sdavidcs q80_set_port_cfg_t *pcfg; 4132284741Sdavidcs q80_set_port_cfg_rsp_t *pfg_rsp; 4133284741Sdavidcs uint32_t err; 4134284741Sdavidcs int count = 300; 4135284741Sdavidcs 4136284741Sdavidcs dev = ha->pci_dev; 4137284741Sdavidcs 4138284741Sdavidcs pcfg = (q80_set_port_cfg_t *)ha->hw.mbox; 4139284741Sdavidcs bzero(pcfg, sizeof(q80_set_port_cfg_t)); 4140284741Sdavidcs 4141284741Sdavidcs pcfg->opcode = Q8_MBX_SET_PORT_CONFIG; 4142284741Sdavidcs pcfg->count_version = (sizeof (q80_set_port_cfg_t) >> 2); 4143284741Sdavidcs pcfg->count_version |= Q8_MBX_CMD_VERSION; 4144284741Sdavidcs 4145284741Sdavidcs pcfg->cfg_bits = cfg_bits; 4146284741Sdavidcs 4147284741Sdavidcs device_printf(dev, "%s: cfg_bits" 4148284741Sdavidcs " [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]" 4149284741Sdavidcs " [0x%x, 0x%x, 0x%x]\n", __func__, 4150284741Sdavidcs ((cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20), 4151284741Sdavidcs ((cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5), 4152284741Sdavidcs ((cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0)); 4153284741Sdavidcs 4154284741Sdavidcs ha->hw.imd_compl= 0; 4155284741Sdavidcs 4156284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)pcfg, 4157284741Sdavidcs (sizeof (q80_set_port_cfg_t) >> 2), 4158284741Sdavidcs ha->hw.mbox, (sizeof (q80_set_port_cfg_rsp_t) >> 2), 0)) { 4159284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4160284741Sdavidcs return -1; 4161284741Sdavidcs } 4162284741Sdavidcs 4163284741Sdavidcs pfg_rsp = (q80_set_port_cfg_rsp_t *)ha->hw.mbox; 4164284741Sdavidcs 4165284741Sdavidcs err = Q8_MBX_RSP_STATUS(pfg_rsp->regcnt_status); 4166284741Sdavidcs 4167284741Sdavidcs if (err == Q8_MBX_RSP_IDC_INTRMD_RSP) { 4168284741Sdavidcs while (count && !ha->hw.imd_compl) { 4169284741Sdavidcs qla_mdelay(__func__, 100); 4170284741Sdavidcs count--; 4171284741Sdavidcs } 4172284741Sdavidcs if (count) { 4173284741Sdavidcs device_printf(dev, "%s: count %d\n", __func__, count); 4174284741Sdavidcs 4175284741Sdavidcs err = 0; 4176284741Sdavidcs } 4177284741Sdavidcs } 4178284741Sdavidcs 4179284741Sdavidcs if (err) { 4180284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4181284741Sdavidcs return(-1); 4182284741Sdavidcs } 4183284741Sdavidcs 4184284741Sdavidcs return (0); 4185284741Sdavidcs} 4186284741Sdavidcs 4187284741Sdavidcs 4188284741Sdavidcsstatic int 4189250661Sdavidcsqla_get_minidump_tmplt_size(qla_host_t *ha, uint32_t *size) 4190250661Sdavidcs{ 4191250661Sdavidcs uint32_t err; 4192250661Sdavidcs device_t dev = ha->pci_dev; 4193250661Sdavidcs q80_config_md_templ_size_t *md_size; 4194250661Sdavidcs q80_config_md_templ_size_rsp_t *md_size_rsp; 4195250661Sdavidcs 4196305487Sdavidcs#ifndef QL_LDFLASH_FW 4197284741Sdavidcs 4198305487Sdavidcs ql_minidump_template_hdr_t *hdr; 4199305487Sdavidcs 4200305487Sdavidcs hdr = (ql_minidump_template_hdr_t *)ql83xx_minidump; 4201305487Sdavidcs *size = hdr->size_of_template; 4202284741Sdavidcs return (0); 4203284741Sdavidcs 4204284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */ 4205284741Sdavidcs 4206250661Sdavidcs md_size = (q80_config_md_templ_size_t *) ha->hw.mbox; 4207250661Sdavidcs bzero(md_size, sizeof(q80_config_md_templ_size_t)); 4208250661Sdavidcs 4209250661Sdavidcs md_size->opcode = Q8_MBX_GET_MINIDUMP_TMPLT_SIZE; 4210250661Sdavidcs md_size->count_version = (sizeof (q80_config_md_templ_size_t) >> 2); 4211250661Sdavidcs md_size->count_version |= Q8_MBX_CMD_VERSION; 4212250661Sdavidcs 4213250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *) md_size, 4214250661Sdavidcs (sizeof(q80_config_md_templ_size_t) >> 2), ha->hw.mbox, 4215250661Sdavidcs (sizeof(q80_config_md_templ_size_rsp_t) >> 2), 0)) { 4216250661Sdavidcs 4217250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4218250661Sdavidcs 4219250661Sdavidcs return (-1); 4220250661Sdavidcs } 4221250661Sdavidcs 4222250661Sdavidcs md_size_rsp = (q80_config_md_templ_size_rsp_t *) ha->hw.mbox; 4223250661Sdavidcs 4224250661Sdavidcs err = Q8_MBX_RSP_STATUS(md_size_rsp->regcnt_status); 4225250661Sdavidcs 4226250661Sdavidcs if (err) { 4227250661Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4228250661Sdavidcs return(-1); 4229250661Sdavidcs } 4230250661Sdavidcs 4231250661Sdavidcs *size = md_size_rsp->templ_size; 4232250661Sdavidcs 4233250661Sdavidcs return (0); 4234250661Sdavidcs} 4235250661Sdavidcs 4236250661Sdavidcsstatic int 4237284741Sdavidcsqla_get_port_config(qla_host_t *ha, uint32_t *cfg_bits) 4238284741Sdavidcs{ 4239284741Sdavidcs device_t dev; 4240284741Sdavidcs q80_get_port_cfg_t *pcfg; 4241284741Sdavidcs q80_get_port_cfg_rsp_t *pcfg_rsp; 4242284741Sdavidcs uint32_t err; 4243284741Sdavidcs 4244284741Sdavidcs dev = ha->pci_dev; 4245284741Sdavidcs 4246284741Sdavidcs pcfg = (q80_get_port_cfg_t *)ha->hw.mbox; 4247284741Sdavidcs bzero(pcfg, sizeof(q80_get_port_cfg_t)); 4248284741Sdavidcs 4249284741Sdavidcs pcfg->opcode = Q8_MBX_GET_PORT_CONFIG; 4250284741Sdavidcs pcfg->count_version = (sizeof (q80_get_port_cfg_t) >> 2); 4251284741Sdavidcs pcfg->count_version |= Q8_MBX_CMD_VERSION; 4252284741Sdavidcs 4253284741Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *)pcfg, 4254284741Sdavidcs (sizeof (q80_get_port_cfg_t) >> 2), 4255284741Sdavidcs ha->hw.mbox, (sizeof (q80_get_port_cfg_rsp_t) >> 2), 0)) { 4256284741Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4257284741Sdavidcs return -1; 4258284741Sdavidcs } 4259284741Sdavidcs 4260284741Sdavidcs pcfg_rsp = (q80_get_port_cfg_rsp_t *)ha->hw.mbox; 4261284741Sdavidcs 4262284741Sdavidcs err = Q8_MBX_RSP_STATUS(pcfg_rsp->regcnt_status); 4263284741Sdavidcs 4264284741Sdavidcs if (err) { 4265284741Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4266284741Sdavidcs return(-1); 4267284741Sdavidcs } 4268284741Sdavidcs 4269284741Sdavidcs device_printf(dev, "%s: [cfg_bits, port type]" 4270284741Sdavidcs " [0x%08x, 0x%02x] [STD_PAUSE_DIR, PAUSE_TYPE, DCBX]" 4271284741Sdavidcs " [0x%x, 0x%x, 0x%x]\n", __func__, 4272284741Sdavidcs pcfg_rsp->cfg_bits, pcfg_rsp->phys_port_type, 4273284741Sdavidcs ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_STDPAUSE_DIR_MASK)>>20), 4274284741Sdavidcs ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_PAUSE_CFG_MASK) >> 5), 4275284741Sdavidcs ((pcfg_rsp->cfg_bits & Q8_PORT_CFG_BITS_DCBX_ENABLE) ? 1: 0) 4276284741Sdavidcs ); 4277284741Sdavidcs 4278284741Sdavidcs *cfg_bits = pcfg_rsp->cfg_bits; 4279284741Sdavidcs 4280284741Sdavidcs return (0); 4281284741Sdavidcs} 4282284741Sdavidcs 4283284741Sdavidcsint 4284313070Sdavidcsql_iscsi_pdu(qla_host_t *ha, struct mbuf *mp) 4285284741Sdavidcs{ 4286284741Sdavidcs struct ether_vlan_header *eh; 4287284741Sdavidcs uint16_t etype; 4288284741Sdavidcs struct ip *ip = NULL; 4289284741Sdavidcs struct ip6_hdr *ip6 = NULL; 4290284741Sdavidcs struct tcphdr *th = NULL; 4291284741Sdavidcs uint32_t hdrlen; 4292284741Sdavidcs uint32_t offset; 4293284741Sdavidcs uint8_t buf[sizeof(struct ip6_hdr)]; 4294284741Sdavidcs 4295284741Sdavidcs eh = mtod(mp, struct ether_vlan_header *); 4296284741Sdavidcs 4297284741Sdavidcs if (eh->evl_encap_proto == htons(ETHERTYPE_VLAN)) { 4298284741Sdavidcs hdrlen = ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN; 4299284741Sdavidcs etype = ntohs(eh->evl_proto); 4300284741Sdavidcs } else { 4301284741Sdavidcs hdrlen = ETHER_HDR_LEN; 4302284741Sdavidcs etype = ntohs(eh->evl_encap_proto); 4303284741Sdavidcs } 4304284741Sdavidcs 4305284741Sdavidcs if (etype == ETHERTYPE_IP) { 4306284741Sdavidcs 4307284741Sdavidcs offset = (hdrlen + sizeof (struct ip)); 4308284741Sdavidcs 4309284741Sdavidcs if (mp->m_len >= offset) { 4310284741Sdavidcs ip = (struct ip *)(mp->m_data + hdrlen); 4311284741Sdavidcs } else { 4312284741Sdavidcs m_copydata(mp, hdrlen, sizeof (struct ip), buf); 4313284741Sdavidcs ip = (struct ip *)buf; 4314284741Sdavidcs } 4315284741Sdavidcs 4316284741Sdavidcs if (ip->ip_p == IPPROTO_TCP) { 4317284741Sdavidcs 4318284741Sdavidcs hdrlen += ip->ip_hl << 2; 4319284741Sdavidcs offset = hdrlen + 4; 4320284741Sdavidcs 4321284741Sdavidcs if (mp->m_len >= offset) { 4322305487Sdavidcs th = (struct tcphdr *)(mp->m_data + hdrlen);; 4323284741Sdavidcs } else { 4324284741Sdavidcs m_copydata(mp, hdrlen, 4, buf); 4325284741Sdavidcs th = (struct tcphdr *)buf; 4326284741Sdavidcs } 4327284741Sdavidcs } 4328284741Sdavidcs 4329284741Sdavidcs } else if (etype == ETHERTYPE_IPV6) { 4330284741Sdavidcs 4331284741Sdavidcs offset = (hdrlen + sizeof (struct ip6_hdr)); 4332284741Sdavidcs 4333284741Sdavidcs if (mp->m_len >= offset) { 4334284741Sdavidcs ip6 = (struct ip6_hdr *)(mp->m_data + hdrlen); 4335284741Sdavidcs } else { 4336284741Sdavidcs m_copydata(mp, hdrlen, sizeof (struct ip6_hdr), buf); 4337284741Sdavidcs ip6 = (struct ip6_hdr *)buf; 4338284741Sdavidcs } 4339284741Sdavidcs 4340284741Sdavidcs if (ip6->ip6_nxt == IPPROTO_TCP) { 4341284741Sdavidcs 4342284741Sdavidcs hdrlen += sizeof(struct ip6_hdr); 4343284741Sdavidcs offset = hdrlen + 4; 4344284741Sdavidcs 4345284741Sdavidcs if (mp->m_len >= offset) { 4346305487Sdavidcs th = (struct tcphdr *)(mp->m_data + hdrlen);; 4347284741Sdavidcs } else { 4348284741Sdavidcs m_copydata(mp, hdrlen, 4, buf); 4349284741Sdavidcs th = (struct tcphdr *)buf; 4350284741Sdavidcs } 4351284741Sdavidcs } 4352284741Sdavidcs } 4353284741Sdavidcs 4354284741Sdavidcs if (th != NULL) { 4355284741Sdavidcs if ((th->th_sport == htons(3260)) || 4356284741Sdavidcs (th->th_dport == htons(3260))) 4357284741Sdavidcs return 0; 4358284741Sdavidcs } 4359284741Sdavidcs return (-1); 4360284741Sdavidcs} 4361284741Sdavidcs 4362284741Sdavidcsvoid 4363284741Sdavidcsqla_hw_async_event(qla_host_t *ha) 4364284741Sdavidcs{ 4365284741Sdavidcs switch (ha->hw.aen_mb0) { 4366284741Sdavidcs case 0x8101: 4367284741Sdavidcs (void)qla_idc_ack(ha, ha->hw.aen_mb1, ha->hw.aen_mb2, 4368284741Sdavidcs ha->hw.aen_mb3, ha->hw.aen_mb4); 4369284741Sdavidcs 4370284741Sdavidcs break; 4371284741Sdavidcs 4372284741Sdavidcs default: 4373284741Sdavidcs break; 4374284741Sdavidcs } 4375284741Sdavidcs 4376284741Sdavidcs return; 4377284741Sdavidcs} 4378284741Sdavidcs 4379284741Sdavidcs#ifdef QL_LDFLASH_FW 4380284741Sdavidcsstatic int 4381305487Sdavidcsql_get_minidump_template(qla_host_t *ha) 4382250661Sdavidcs{ 4383250661Sdavidcs uint32_t err; 4384250661Sdavidcs device_t dev = ha->pci_dev; 4385250661Sdavidcs q80_config_md_templ_cmd_t *md_templ; 4386250661Sdavidcs q80_config_md_templ_cmd_rsp_t *md_templ_rsp; 4387250661Sdavidcs 4388250661Sdavidcs md_templ = (q80_config_md_templ_cmd_t *) ha->hw.mbox; 4389250661Sdavidcs bzero(md_templ, (sizeof (q80_config_md_templ_cmd_t))); 4390250661Sdavidcs 4391250661Sdavidcs md_templ->opcode = Q8_MBX_GET_MINIDUMP_TMPLT; 4392250661Sdavidcs md_templ->count_version = ( sizeof(q80_config_md_templ_cmd_t) >> 2); 4393250661Sdavidcs md_templ->count_version |= Q8_MBX_CMD_VERSION; 4394250661Sdavidcs 4395250661Sdavidcs md_templ->buf_addr = ha->hw.dma_buf.minidump.dma_addr; 4396250661Sdavidcs md_templ->buff_size = ha->hw.dma_buf.minidump.size; 4397250661Sdavidcs 4398250661Sdavidcs if (qla_mbx_cmd(ha, (uint32_t *) md_templ, 4399250661Sdavidcs (sizeof(q80_config_md_templ_cmd_t) >> 2), 4400250661Sdavidcs ha->hw.mbox, 4401250661Sdavidcs (sizeof(q80_config_md_templ_cmd_rsp_t) >> 2), 0)) { 4402250661Sdavidcs 4403250661Sdavidcs device_printf(dev, "%s: failed\n", __func__); 4404250661Sdavidcs 4405250661Sdavidcs return (-1); 4406250661Sdavidcs } 4407250661Sdavidcs 4408250661Sdavidcs md_templ_rsp = (q80_config_md_templ_cmd_rsp_t *) ha->hw.mbox; 4409250661Sdavidcs 4410250661Sdavidcs err = Q8_MBX_RSP_STATUS(md_templ_rsp->regcnt_status); 4411250661Sdavidcs 4412250661Sdavidcs if (err) { 4413250661Sdavidcs device_printf(dev, "%s: failed [0x%08x]\n", __func__, err); 4414250661Sdavidcs return (-1); 4415250661Sdavidcs } 4416250661Sdavidcs 4417250661Sdavidcs return (0); 4418250661Sdavidcs 4419250661Sdavidcs} 4420284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */ 4421250661Sdavidcs 4422305487Sdavidcs/* 4423305487Sdavidcs * Minidump related functionality 4424305487Sdavidcs */ 4425305487Sdavidcs 4426305487Sdavidcsstatic int ql_parse_template(qla_host_t *ha); 4427305487Sdavidcs 4428305487Sdavidcsstatic uint32_t ql_rdcrb(qla_host_t *ha, 4429305487Sdavidcs ql_minidump_entry_rdcrb_t *crb_entry, 4430305487Sdavidcs uint32_t * data_buff); 4431305487Sdavidcs 4432305487Sdavidcsstatic uint32_t ql_pollrd(qla_host_t *ha, 4433305487Sdavidcs ql_minidump_entry_pollrd_t *entry, 4434305487Sdavidcs uint32_t * data_buff); 4435305487Sdavidcs 4436305487Sdavidcsstatic uint32_t ql_pollrd_modify_write(qla_host_t *ha, 4437305487Sdavidcs ql_minidump_entry_rd_modify_wr_with_poll_t *entry, 4438305487Sdavidcs uint32_t *data_buff); 4439305487Sdavidcs 4440305487Sdavidcsstatic uint32_t ql_L2Cache(qla_host_t *ha, 4441305487Sdavidcs ql_minidump_entry_cache_t *cacheEntry, 4442305487Sdavidcs uint32_t * data_buff); 4443305487Sdavidcs 4444305487Sdavidcsstatic uint32_t ql_L1Cache(qla_host_t *ha, 4445305487Sdavidcs ql_minidump_entry_cache_t *cacheEntry, 4446305487Sdavidcs uint32_t *data_buff); 4447305487Sdavidcs 4448305487Sdavidcsstatic uint32_t ql_rdocm(qla_host_t *ha, 4449305487Sdavidcs ql_minidump_entry_rdocm_t *ocmEntry, 4450305487Sdavidcs uint32_t *data_buff); 4451305487Sdavidcs 4452305487Sdavidcsstatic uint32_t ql_rdmem(qla_host_t *ha, 4453305487Sdavidcs ql_minidump_entry_rdmem_t *mem_entry, 4454305487Sdavidcs uint32_t *data_buff); 4455305487Sdavidcs 4456305487Sdavidcsstatic uint32_t ql_rdrom(qla_host_t *ha, 4457305487Sdavidcs ql_minidump_entry_rdrom_t *romEntry, 4458305487Sdavidcs uint32_t *data_buff); 4459305487Sdavidcs 4460305487Sdavidcsstatic uint32_t ql_rdmux(qla_host_t *ha, 4461305487Sdavidcs ql_minidump_entry_mux_t *muxEntry, 4462305487Sdavidcs uint32_t *data_buff); 4463305487Sdavidcs 4464305487Sdavidcsstatic uint32_t ql_rdmux2(qla_host_t *ha, 4465305487Sdavidcs ql_minidump_entry_mux2_t *muxEntry, 4466305487Sdavidcs uint32_t *data_buff); 4467305487Sdavidcs 4468305487Sdavidcsstatic uint32_t ql_rdqueue(qla_host_t *ha, 4469305487Sdavidcs ql_minidump_entry_queue_t *queueEntry, 4470305487Sdavidcs uint32_t *data_buff); 4471305487Sdavidcs 4472305487Sdavidcsstatic uint32_t ql_cntrl(qla_host_t *ha, 4473305487Sdavidcs ql_minidump_template_hdr_t *template_hdr, 4474305487Sdavidcs ql_minidump_entry_cntrl_t *crbEntry); 4475305487Sdavidcs 4476305487Sdavidcs 4477305487Sdavidcsstatic uint32_t 4478305487Sdavidcsql_minidump_size(qla_host_t *ha) 4479305487Sdavidcs{ 4480305487Sdavidcs uint32_t i, k; 4481305487Sdavidcs uint32_t size = 0; 4482305487Sdavidcs ql_minidump_template_hdr_t *hdr; 4483305487Sdavidcs 4484305487Sdavidcs hdr = (ql_minidump_template_hdr_t *)ha->hw.dma_buf.minidump.dma_b; 4485305487Sdavidcs 4486305487Sdavidcs i = 0x2; 4487305487Sdavidcs 4488305487Sdavidcs for (k = 1; k < QL_DBG_CAP_SIZE_ARRAY_LEN; k++) { 4489305487Sdavidcs if (i & ha->hw.mdump_capture_mask) 4490305487Sdavidcs size += hdr->capture_size_array[k]; 4491305487Sdavidcs i = i << 1; 4492305487Sdavidcs } 4493305487Sdavidcs return (size); 4494305487Sdavidcs} 4495305487Sdavidcs 4496305487Sdavidcsstatic void 4497305487Sdavidcsql_free_minidump_buffer(qla_host_t *ha) 4498305487Sdavidcs{ 4499305487Sdavidcs if (ha->hw.mdump_buffer != NULL) { 4500305487Sdavidcs free(ha->hw.mdump_buffer, M_QLA83XXBUF); 4501305487Sdavidcs ha->hw.mdump_buffer = NULL; 4502305487Sdavidcs ha->hw.mdump_buffer_size = 0; 4503305487Sdavidcs } 4504305487Sdavidcs return; 4505305487Sdavidcs} 4506305487Sdavidcs 4507250661Sdavidcsstatic int 4508305487Sdavidcsql_alloc_minidump_buffer(qla_host_t *ha) 4509250661Sdavidcs{ 4510305487Sdavidcs ha->hw.mdump_buffer_size = ql_minidump_size(ha); 4511305487Sdavidcs 4512305487Sdavidcs if (!ha->hw.mdump_buffer_size) 4513305487Sdavidcs return (-1); 4514305487Sdavidcs 4515305487Sdavidcs ha->hw.mdump_buffer = malloc(ha->hw.mdump_buffer_size, M_QLA83XXBUF, 4516305487Sdavidcs M_NOWAIT); 4517305487Sdavidcs 4518305487Sdavidcs if (ha->hw.mdump_buffer == NULL) 4519305487Sdavidcs return (-1); 4520305487Sdavidcs 4521305487Sdavidcs return (0); 4522305487Sdavidcs} 4523305487Sdavidcs 4524305487Sdavidcsstatic void 4525305487Sdavidcsql_free_minidump_template_buffer(qla_host_t *ha) 4526305487Sdavidcs{ 4527305487Sdavidcs if (ha->hw.mdump_template != NULL) { 4528305487Sdavidcs free(ha->hw.mdump_template, M_QLA83XXBUF); 4529305487Sdavidcs ha->hw.mdump_template = NULL; 4530305487Sdavidcs ha->hw.mdump_template_size = 0; 4531305487Sdavidcs } 4532305487Sdavidcs return; 4533305487Sdavidcs} 4534305487Sdavidcs 4535305487Sdavidcsstatic int 4536305487Sdavidcsql_alloc_minidump_template_buffer(qla_host_t *ha) 4537305487Sdavidcs{ 4538305487Sdavidcs ha->hw.mdump_template_size = ha->hw.dma_buf.minidump.size; 4539305487Sdavidcs 4540305487Sdavidcs ha->hw.mdump_template = malloc(ha->hw.mdump_template_size, 4541305487Sdavidcs M_QLA83XXBUF, M_NOWAIT); 4542305487Sdavidcs 4543305487Sdavidcs if (ha->hw.mdump_template == NULL) 4544305487Sdavidcs return (-1); 4545305487Sdavidcs 4546305487Sdavidcs return (0); 4547305487Sdavidcs} 4548305487Sdavidcs 4549305487Sdavidcsstatic int 4550305487Sdavidcsql_alloc_minidump_buffers(qla_host_t *ha) 4551305487Sdavidcs{ 4552305487Sdavidcs int ret; 4553305487Sdavidcs 4554305487Sdavidcs ret = ql_alloc_minidump_template_buffer(ha); 4555305487Sdavidcs 4556305487Sdavidcs if (ret) 4557305487Sdavidcs return (ret); 4558305487Sdavidcs 4559305487Sdavidcs ret = ql_alloc_minidump_buffer(ha); 4560305487Sdavidcs 4561305487Sdavidcs if (ret) 4562305487Sdavidcs ql_free_minidump_template_buffer(ha); 4563305487Sdavidcs 4564305487Sdavidcs return (ret); 4565305487Sdavidcs} 4566305487Sdavidcs 4567305487Sdavidcs 4568305487Sdavidcsstatic uint32_t 4569305487Sdavidcsql_validate_minidump_checksum(qla_host_t *ha) 4570305487Sdavidcs{ 4571305487Sdavidcs uint64_t sum = 0; 4572305487Sdavidcs int count; 4573305487Sdavidcs uint32_t *template_buff; 4574305487Sdavidcs 4575305487Sdavidcs count = ha->hw.dma_buf.minidump.size / sizeof (uint32_t); 4576305487Sdavidcs template_buff = ha->hw.dma_buf.minidump.dma_b; 4577305487Sdavidcs 4578305487Sdavidcs while (count-- > 0) { 4579305487Sdavidcs sum += *template_buff++; 4580305487Sdavidcs } 4581305487Sdavidcs 4582305487Sdavidcs while (sum >> 32) { 4583305487Sdavidcs sum = (sum & 0xFFFFFFFF) + (sum >> 32); 4584305487Sdavidcs } 4585305487Sdavidcs 4586305487Sdavidcs return (~sum); 4587305487Sdavidcs} 4588305487Sdavidcs 4589305487Sdavidcsint 4590305487Sdavidcsql_minidump_init(qla_host_t *ha) 4591305487Sdavidcs{ 4592284741Sdavidcs int ret = 0; 4593250661Sdavidcs uint32_t template_size = 0; 4594250661Sdavidcs device_t dev = ha->pci_dev; 4595250661Sdavidcs 4596250661Sdavidcs /* 4597250661Sdavidcs * Get Minidump Template Size 4598250661Sdavidcs */ 4599250661Sdavidcs ret = qla_get_minidump_tmplt_size(ha, &template_size); 4600250661Sdavidcs 4601250661Sdavidcs if (ret || (template_size == 0)) { 4602250661Sdavidcs device_printf(dev, "%s: failed [%d, %d]\n", __func__, ret, 4603250661Sdavidcs template_size); 4604250661Sdavidcs return (-1); 4605250661Sdavidcs } 4606250661Sdavidcs 4607250661Sdavidcs /* 4608250661Sdavidcs * Allocate Memory for Minidump Template 4609250661Sdavidcs */ 4610250661Sdavidcs 4611250661Sdavidcs ha->hw.dma_buf.minidump.alignment = 8; 4612250661Sdavidcs ha->hw.dma_buf.minidump.size = template_size; 4613250661Sdavidcs 4614284741Sdavidcs#ifdef QL_LDFLASH_FW 4615250661Sdavidcs if (ql_alloc_dmabuf(ha, &ha->hw.dma_buf.minidump)) { 4616250661Sdavidcs 4617250661Sdavidcs device_printf(dev, "%s: minidump dma alloc failed\n", __func__); 4618250661Sdavidcs 4619250661Sdavidcs return (-1); 4620250661Sdavidcs } 4621250661Sdavidcs ha->hw.dma_buf.flags.minidump = 1; 4622250661Sdavidcs 4623250661Sdavidcs /* 4624250661Sdavidcs * Retrieve Minidump Template 4625250661Sdavidcs */ 4626305487Sdavidcs ret = ql_get_minidump_template(ha); 4627284741Sdavidcs#else 4628284741Sdavidcs ha->hw.dma_buf.minidump.dma_b = ql83xx_minidump; 4629305487Sdavidcs 4630284741Sdavidcs#endif /* #ifdef QL_LDFLASH_FW */ 4631250661Sdavidcs 4632305487Sdavidcs if (ret == 0) { 4633305487Sdavidcs 4634305487Sdavidcs ret = ql_validate_minidump_checksum(ha); 4635305487Sdavidcs 4636305487Sdavidcs if (ret == 0) { 4637305487Sdavidcs 4638305487Sdavidcs ret = ql_alloc_minidump_buffers(ha); 4639305487Sdavidcs 4640305487Sdavidcs if (ret == 0) 4641305487Sdavidcs ha->hw.mdump_init = 1; 4642305487Sdavidcs else 4643305487Sdavidcs device_printf(dev, 4644305487Sdavidcs "%s: ql_alloc_minidump_buffers" 4645305487Sdavidcs " failed\n", __func__); 4646305487Sdavidcs } else { 4647305487Sdavidcs device_printf(dev, "%s: ql_validate_minidump_checksum" 4648305487Sdavidcs " failed\n", __func__); 4649305487Sdavidcs } 4650250661Sdavidcs } else { 4651305487Sdavidcs device_printf(dev, "%s: ql_get_minidump_template failed\n", 4652305487Sdavidcs __func__); 4653250661Sdavidcs } 4654250661Sdavidcs 4655305487Sdavidcs if (ret) 4656305487Sdavidcs ql_minidump_free(ha); 4657305487Sdavidcs 4658250661Sdavidcs return (ret); 4659250661Sdavidcs} 4660250661Sdavidcs 4661250661Sdavidcsstatic void 4662305487Sdavidcsql_minidump_free(qla_host_t *ha) 4663250661Sdavidcs{ 4664250661Sdavidcs ha->hw.mdump_init = 0; 4665250661Sdavidcs if (ha->hw.dma_buf.flags.minidump) { 4666250661Sdavidcs ha->hw.dma_buf.flags.minidump = 0; 4667250661Sdavidcs ql_free_dmabuf(ha, &ha->hw.dma_buf.minidump); 4668250661Sdavidcs } 4669305487Sdavidcs 4670305487Sdavidcs ql_free_minidump_template_buffer(ha); 4671305487Sdavidcs ql_free_minidump_buffer(ha); 4672305487Sdavidcs 4673250661Sdavidcs return; 4674250661Sdavidcs} 4675250661Sdavidcs 4676250661Sdavidcsvoid 4677250661Sdavidcsql_minidump(qla_host_t *ha) 4678250661Sdavidcs{ 4679250661Sdavidcs if (!ha->hw.mdump_init) 4680250661Sdavidcs return; 4681250661Sdavidcs 4682305487Sdavidcs if (ha->hw.mdump_done) 4683250661Sdavidcs return; 4684330555Sdavidcs ha->hw.mdump_usec_ts = qla_get_usec_timestamp(); 4685330555Sdavidcs ha->hw.mdump_start_seq_index = ql_stop_sequence(ha); 4686250661Sdavidcs 4687305487Sdavidcs bzero(ha->hw.mdump_buffer, ha->hw.mdump_buffer_size); 4688305487Sdavidcs bzero(ha->hw.mdump_template, ha->hw.mdump_template_size); 4689305487Sdavidcs 4690305487Sdavidcs bcopy(ha->hw.dma_buf.minidump.dma_b, ha->hw.mdump_template, 4691305487Sdavidcs ha->hw.mdump_template_size); 4692305487Sdavidcs 4693305487Sdavidcs ql_parse_template(ha); 4694305487Sdavidcs 4695250661Sdavidcs ql_start_sequence(ha, ha->hw.mdump_start_seq_index); 4696250661Sdavidcs 4697305487Sdavidcs ha->hw.mdump_done = 1; 4698305487Sdavidcs 4699250661Sdavidcs return; 4700250661Sdavidcs} 4701305487Sdavidcs 4702305487Sdavidcs 4703305487Sdavidcs/* 4704305487Sdavidcs * helper routines 4705305487Sdavidcs */ 4706305487Sdavidcsstatic void 4707305487Sdavidcsql_entry_err_chk(ql_minidump_entry_t *entry, uint32_t esize) 4708305487Sdavidcs{ 4709305487Sdavidcs if (esize != entry->hdr.entry_capture_size) { 4710305487Sdavidcs entry->hdr.entry_capture_size = esize; 4711305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SIZE_ERR_FLAG; 4712305487Sdavidcs } 4713305487Sdavidcs return; 4714305487Sdavidcs} 4715305487Sdavidcs 4716305487Sdavidcs 4717305487Sdavidcsstatic int 4718305487Sdavidcsql_parse_template(qla_host_t *ha) 4719305487Sdavidcs{ 4720305487Sdavidcs uint32_t num_of_entries, buff_level, e_cnt, esize; 4721305487Sdavidcs uint32_t end_cnt, rv = 0; 4722305487Sdavidcs char *dump_buff, *dbuff; 4723305487Sdavidcs int sane_start = 0, sane_end = 0; 4724305487Sdavidcs ql_minidump_template_hdr_t *template_hdr; 4725305487Sdavidcs ql_minidump_entry_t *entry; 4726305487Sdavidcs uint32_t capture_mask; 4727305487Sdavidcs uint32_t dump_size; 4728305487Sdavidcs 4729305487Sdavidcs /* Setup parameters */ 4730305487Sdavidcs template_hdr = (ql_minidump_template_hdr_t *)ha->hw.mdump_template; 4731305487Sdavidcs 4732305487Sdavidcs if (template_hdr->entry_type == TLHDR) 4733305487Sdavidcs sane_start = 1; 4734305487Sdavidcs 4735305487Sdavidcs dump_buff = (char *) ha->hw.mdump_buffer; 4736305487Sdavidcs 4737305487Sdavidcs num_of_entries = template_hdr->num_of_entries; 4738305487Sdavidcs 4739305487Sdavidcs entry = (ql_minidump_entry_t *) ((char *)template_hdr 4740305487Sdavidcs + template_hdr->first_entry_offset ); 4741305487Sdavidcs 4742305487Sdavidcs template_hdr->saved_state_array[QL_OCM0_ADDR_INDX] = 4743305487Sdavidcs template_hdr->ocm_window_array[ha->pci_func]; 4744305487Sdavidcs template_hdr->saved_state_array[QL_PCIE_FUNC_INDX] = ha->pci_func; 4745305487Sdavidcs 4746305487Sdavidcs capture_mask = ha->hw.mdump_capture_mask; 4747305487Sdavidcs dump_size = ha->hw.mdump_buffer_size; 4748305487Sdavidcs 4749305487Sdavidcs template_hdr->driver_capture_mask = capture_mask; 4750305487Sdavidcs 4751305487Sdavidcs QL_DPRINT80(ha, (ha->pci_dev, 4752305487Sdavidcs "%s: sane_start = %d num_of_entries = %d " 4753305487Sdavidcs "capture_mask = 0x%x dump_size = %d \n", 4754305487Sdavidcs __func__, sane_start, num_of_entries, capture_mask, dump_size)); 4755305487Sdavidcs 4756305487Sdavidcs for (buff_level = 0, e_cnt = 0; e_cnt < num_of_entries; e_cnt++) { 4757305487Sdavidcs 4758305487Sdavidcs /* 4759305487Sdavidcs * If the capture_mask of the entry does not match capture mask 4760305487Sdavidcs * skip the entry after marking the driver_flags indicator. 4761305487Sdavidcs */ 4762305487Sdavidcs 4763305487Sdavidcs if (!(entry->hdr.entry_capture_mask & capture_mask)) { 4764305487Sdavidcs 4765305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG; 4766305487Sdavidcs entry = (ql_minidump_entry_t *) ((char *) entry 4767305487Sdavidcs + entry->hdr.entry_size); 4768305487Sdavidcs continue; 4769305487Sdavidcs } 4770305487Sdavidcs 4771305487Sdavidcs /* 4772305487Sdavidcs * This is ONLY needed in implementations where 4773305487Sdavidcs * the capture buffer allocated is too small to capture 4774305487Sdavidcs * all of the required entries for a given capture mask. 4775305487Sdavidcs * We need to empty the buffer contents to a file 4776305487Sdavidcs * if possible, before processing the next entry 4777305487Sdavidcs * If the buff_full_flag is set, no further capture will happen 4778305487Sdavidcs * and all remaining non-control entries will be skipped. 4779305487Sdavidcs */ 4780305487Sdavidcs if (entry->hdr.entry_capture_size != 0) { 4781305487Sdavidcs if ((buff_level + entry->hdr.entry_capture_size) > 4782305487Sdavidcs dump_size) { 4783305487Sdavidcs /* Try to recover by emptying buffer to file */ 4784305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG; 4785305487Sdavidcs entry = (ql_minidump_entry_t *) ((char *) entry 4786305487Sdavidcs + entry->hdr.entry_size); 4787305487Sdavidcs continue; 4788305487Sdavidcs } 4789305487Sdavidcs } 4790305487Sdavidcs 4791305487Sdavidcs /* 4792305487Sdavidcs * Decode the entry type and process it accordingly 4793305487Sdavidcs */ 4794305487Sdavidcs 4795305487Sdavidcs switch (entry->hdr.entry_type) { 4796305487Sdavidcs case RDNOP: 4797305487Sdavidcs break; 4798305487Sdavidcs 4799305487Sdavidcs case RDEND: 4800305487Sdavidcs if (sane_end == 0) { 4801305487Sdavidcs end_cnt = e_cnt; 4802305487Sdavidcs } 4803305487Sdavidcs sane_end++; 4804305487Sdavidcs break; 4805305487Sdavidcs 4806305487Sdavidcs case RDCRB: 4807305487Sdavidcs dbuff = dump_buff + buff_level; 4808305487Sdavidcs esize = ql_rdcrb(ha, (void *)entry, (void *)dbuff); 4809305487Sdavidcs ql_entry_err_chk(entry, esize); 4810305487Sdavidcs buff_level += esize; 4811305487Sdavidcs break; 4812305487Sdavidcs 4813305487Sdavidcs case POLLRD: 4814305487Sdavidcs dbuff = dump_buff + buff_level; 4815305487Sdavidcs esize = ql_pollrd(ha, (void *)entry, (void *)dbuff); 4816305487Sdavidcs ql_entry_err_chk(entry, esize); 4817305487Sdavidcs buff_level += esize; 4818305487Sdavidcs break; 4819305487Sdavidcs 4820305487Sdavidcs case POLLRDMWR: 4821305487Sdavidcs dbuff = dump_buff + buff_level; 4822305487Sdavidcs esize = ql_pollrd_modify_write(ha, (void *)entry, 4823305487Sdavidcs (void *)dbuff); 4824305487Sdavidcs ql_entry_err_chk(entry, esize); 4825305487Sdavidcs buff_level += esize; 4826305487Sdavidcs break; 4827305487Sdavidcs 4828305487Sdavidcs case L2ITG: 4829305487Sdavidcs case L2DTG: 4830305487Sdavidcs case L2DAT: 4831305487Sdavidcs case L2INS: 4832305487Sdavidcs dbuff = dump_buff + buff_level; 4833305487Sdavidcs esize = ql_L2Cache(ha, (void *)entry, (void *)dbuff); 4834305487Sdavidcs if (esize == -1) { 4835305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG; 4836305487Sdavidcs } else { 4837305487Sdavidcs ql_entry_err_chk(entry, esize); 4838305487Sdavidcs buff_level += esize; 4839305487Sdavidcs } 4840305487Sdavidcs break; 4841305487Sdavidcs 4842305487Sdavidcs case L1DAT: 4843305487Sdavidcs case L1INS: 4844305487Sdavidcs dbuff = dump_buff + buff_level; 4845305487Sdavidcs esize = ql_L1Cache(ha, (void *)entry, (void *)dbuff); 4846305487Sdavidcs ql_entry_err_chk(entry, esize); 4847305487Sdavidcs buff_level += esize; 4848305487Sdavidcs break; 4849305487Sdavidcs 4850305487Sdavidcs case RDOCM: 4851305487Sdavidcs dbuff = dump_buff + buff_level; 4852305487Sdavidcs esize = ql_rdocm(ha, (void *)entry, (void *)dbuff); 4853305487Sdavidcs ql_entry_err_chk(entry, esize); 4854305487Sdavidcs buff_level += esize; 4855305487Sdavidcs break; 4856305487Sdavidcs 4857305487Sdavidcs case RDMEM: 4858305487Sdavidcs dbuff = dump_buff + buff_level; 4859305487Sdavidcs esize = ql_rdmem(ha, (void *)entry, (void *)dbuff); 4860305487Sdavidcs ql_entry_err_chk(entry, esize); 4861305487Sdavidcs buff_level += esize; 4862305487Sdavidcs break; 4863305487Sdavidcs 4864305487Sdavidcs case BOARD: 4865305487Sdavidcs case RDROM: 4866305487Sdavidcs dbuff = dump_buff + buff_level; 4867305487Sdavidcs esize = ql_rdrom(ha, (void *)entry, (void *)dbuff); 4868305487Sdavidcs ql_entry_err_chk(entry, esize); 4869305487Sdavidcs buff_level += esize; 4870305487Sdavidcs break; 4871305487Sdavidcs 4872305487Sdavidcs case RDMUX: 4873305487Sdavidcs dbuff = dump_buff + buff_level; 4874305487Sdavidcs esize = ql_rdmux(ha, (void *)entry, (void *)dbuff); 4875305487Sdavidcs ql_entry_err_chk(entry, esize); 4876305487Sdavidcs buff_level += esize; 4877305487Sdavidcs break; 4878305487Sdavidcs 4879305487Sdavidcs case RDMUX2: 4880305487Sdavidcs dbuff = dump_buff + buff_level; 4881305487Sdavidcs esize = ql_rdmux2(ha, (void *)entry, (void *)dbuff); 4882305487Sdavidcs ql_entry_err_chk(entry, esize); 4883305487Sdavidcs buff_level += esize; 4884305487Sdavidcs break; 4885305487Sdavidcs 4886305487Sdavidcs case QUEUE: 4887305487Sdavidcs dbuff = dump_buff + buff_level; 4888305487Sdavidcs esize = ql_rdqueue(ha, (void *)entry, (void *)dbuff); 4889305487Sdavidcs ql_entry_err_chk(entry, esize); 4890305487Sdavidcs buff_level += esize; 4891305487Sdavidcs break; 4892305487Sdavidcs 4893305487Sdavidcs case CNTRL: 4894305487Sdavidcs if ((rv = ql_cntrl(ha, template_hdr, (void *)entry))) { 4895305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG; 4896305487Sdavidcs } 4897305487Sdavidcs break; 4898305487Sdavidcs default: 4899305487Sdavidcs entry->hdr.driver_flags |= QL_DBG_SKIPPED_FLAG; 4900305487Sdavidcs break; 4901305487Sdavidcs } 4902305487Sdavidcs /* next entry in the template */ 4903305487Sdavidcs entry = (ql_minidump_entry_t *) ((char *) entry 4904305487Sdavidcs + entry->hdr.entry_size); 4905305487Sdavidcs } 4906305487Sdavidcs 4907305487Sdavidcs if (!sane_start || (sane_end > 1)) { 4908305487Sdavidcs device_printf(ha->pci_dev, 4909305487Sdavidcs "\n%s: Template configuration error. Check Template\n", 4910305487Sdavidcs __func__); 4911305487Sdavidcs } 4912305487Sdavidcs 4913305487Sdavidcs QL_DPRINT80(ha, (ha->pci_dev, "%s: Minidump num of entries = %d\n", 4914305487Sdavidcs __func__, template_hdr->num_of_entries)); 4915305487Sdavidcs 4916305487Sdavidcs return 0; 4917305487Sdavidcs} 4918305487Sdavidcs 4919305487Sdavidcs/* 4920305487Sdavidcs * Read CRB operation. 4921305487Sdavidcs */ 4922305487Sdavidcsstatic uint32_t 4923305487Sdavidcsql_rdcrb(qla_host_t *ha, ql_minidump_entry_rdcrb_t * crb_entry, 4924305487Sdavidcs uint32_t * data_buff) 4925305487Sdavidcs{ 4926305487Sdavidcs int loop_cnt; 4927305487Sdavidcs int ret; 4928305487Sdavidcs uint32_t op_count, addr, stride, value = 0; 4929305487Sdavidcs 4930305487Sdavidcs addr = crb_entry->addr; 4931305487Sdavidcs op_count = crb_entry->op_count; 4932305487Sdavidcs stride = crb_entry->addr_stride; 4933305487Sdavidcs 4934305487Sdavidcs for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) { 4935305487Sdavidcs 4936305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &value, 1); 4937305487Sdavidcs 4938305487Sdavidcs if (ret) 4939305487Sdavidcs return (0); 4940305487Sdavidcs 4941305487Sdavidcs *data_buff++ = addr; 4942305487Sdavidcs *data_buff++ = value; 4943305487Sdavidcs addr = addr + stride; 4944305487Sdavidcs } 4945305487Sdavidcs 4946305487Sdavidcs /* 4947305487Sdavidcs * for testing purpose we return amount of data written 4948305487Sdavidcs */ 4949305487Sdavidcs return (op_count * (2 * sizeof(uint32_t))); 4950305487Sdavidcs} 4951305487Sdavidcs 4952305487Sdavidcs/* 4953305487Sdavidcs * Handle L2 Cache. 4954305487Sdavidcs */ 4955305487Sdavidcs 4956305487Sdavidcsstatic uint32_t 4957305487Sdavidcsql_L2Cache(qla_host_t *ha, ql_minidump_entry_cache_t *cacheEntry, 4958305487Sdavidcs uint32_t * data_buff) 4959305487Sdavidcs{ 4960305487Sdavidcs int i, k; 4961305487Sdavidcs int loop_cnt; 4962305487Sdavidcs int ret; 4963305487Sdavidcs 4964305487Sdavidcs uint32_t read_value; 4965305487Sdavidcs uint32_t addr, read_addr, cntrl_addr, tag_reg_addr, cntl_value_w; 4966305487Sdavidcs uint32_t tag_value, read_cnt; 4967305487Sdavidcs volatile uint8_t cntl_value_r; 4968305487Sdavidcs long timeout; 4969305487Sdavidcs uint32_t data; 4970305487Sdavidcs 4971305487Sdavidcs loop_cnt = cacheEntry->op_count; 4972305487Sdavidcs 4973305487Sdavidcs read_addr = cacheEntry->read_addr; 4974305487Sdavidcs cntrl_addr = cacheEntry->control_addr; 4975305487Sdavidcs cntl_value_w = (uint32_t) cacheEntry->write_value; 4976305487Sdavidcs 4977305487Sdavidcs tag_reg_addr = cacheEntry->tag_reg_addr; 4978305487Sdavidcs 4979305487Sdavidcs tag_value = cacheEntry->init_tag_value; 4980305487Sdavidcs read_cnt = cacheEntry->read_addr_cnt; 4981305487Sdavidcs 4982305487Sdavidcs for (i = 0; i < loop_cnt; i++) { 4983305487Sdavidcs 4984305487Sdavidcs ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0); 4985305487Sdavidcs if (ret) 4986305487Sdavidcs return (0); 4987305487Sdavidcs 4988305487Sdavidcs if (cacheEntry->write_value != 0) { 4989305487Sdavidcs 4990305487Sdavidcs ret = ql_rdwr_indreg32(ha, cntrl_addr, 4991305487Sdavidcs &cntl_value_w, 0); 4992305487Sdavidcs if (ret) 4993305487Sdavidcs return (0); 4994305487Sdavidcs } 4995305487Sdavidcs 4996305487Sdavidcs if (cacheEntry->poll_mask != 0) { 4997305487Sdavidcs 4998305487Sdavidcs timeout = cacheEntry->poll_wait; 4999305487Sdavidcs 5000305487Sdavidcs ret = ql_rdwr_indreg32(ha, cntrl_addr, &data, 1); 5001305487Sdavidcs if (ret) 5002305487Sdavidcs return (0); 5003305487Sdavidcs 5004305487Sdavidcs cntl_value_r = (uint8_t)data; 5005305487Sdavidcs 5006305487Sdavidcs while ((cntl_value_r & cacheEntry->poll_mask) != 0) { 5007305487Sdavidcs 5008305487Sdavidcs if (timeout) { 5009305487Sdavidcs qla_mdelay(__func__, 1); 5010305487Sdavidcs timeout--; 5011305487Sdavidcs } else 5012305487Sdavidcs break; 5013305487Sdavidcs 5014305487Sdavidcs ret = ql_rdwr_indreg32(ha, cntrl_addr, 5015305487Sdavidcs &data, 1); 5016305487Sdavidcs if (ret) 5017305487Sdavidcs return (0); 5018305487Sdavidcs 5019305487Sdavidcs cntl_value_r = (uint8_t)data; 5020305487Sdavidcs } 5021305487Sdavidcs if (!timeout) { 5022305487Sdavidcs /* Report timeout error. 5023305487Sdavidcs * core dump capture failed 5024305487Sdavidcs * Skip remaining entries. 5025305487Sdavidcs * Write buffer out to file 5026305487Sdavidcs * Use driver specific fields in template header 5027305487Sdavidcs * to report this error. 5028305487Sdavidcs */ 5029305487Sdavidcs return (-1); 5030305487Sdavidcs } 5031305487Sdavidcs } 5032305487Sdavidcs 5033305487Sdavidcs addr = read_addr; 5034305487Sdavidcs for (k = 0; k < read_cnt; k++) { 5035305487Sdavidcs 5036305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &read_value, 1); 5037305487Sdavidcs if (ret) 5038305487Sdavidcs return (0); 5039305487Sdavidcs 5040305487Sdavidcs *data_buff++ = read_value; 5041305487Sdavidcs addr += cacheEntry->read_addr_stride; 5042305487Sdavidcs } 5043305487Sdavidcs 5044305487Sdavidcs tag_value += cacheEntry->tag_value_stride; 5045305487Sdavidcs } 5046305487Sdavidcs 5047305487Sdavidcs return (read_cnt * loop_cnt * sizeof(uint32_t)); 5048305487Sdavidcs} 5049305487Sdavidcs 5050305487Sdavidcs/* 5051305487Sdavidcs * Handle L1 Cache. 5052305487Sdavidcs */ 5053305487Sdavidcs 5054305487Sdavidcsstatic uint32_t 5055305487Sdavidcsql_L1Cache(qla_host_t *ha, 5056305487Sdavidcs ql_minidump_entry_cache_t *cacheEntry, 5057305487Sdavidcs uint32_t *data_buff) 5058305487Sdavidcs{ 5059305487Sdavidcs int ret; 5060305487Sdavidcs int i, k; 5061305487Sdavidcs int loop_cnt; 5062305487Sdavidcs 5063305487Sdavidcs uint32_t read_value; 5064305487Sdavidcs uint32_t addr, read_addr, cntrl_addr, tag_reg_addr; 5065305487Sdavidcs uint32_t tag_value, read_cnt; 5066305487Sdavidcs uint32_t cntl_value_w; 5067305487Sdavidcs 5068305487Sdavidcs loop_cnt = cacheEntry->op_count; 5069305487Sdavidcs 5070305487Sdavidcs read_addr = cacheEntry->read_addr; 5071305487Sdavidcs cntrl_addr = cacheEntry->control_addr; 5072305487Sdavidcs cntl_value_w = (uint32_t) cacheEntry->write_value; 5073305487Sdavidcs 5074305487Sdavidcs tag_reg_addr = cacheEntry->tag_reg_addr; 5075305487Sdavidcs 5076305487Sdavidcs tag_value = cacheEntry->init_tag_value; 5077305487Sdavidcs read_cnt = cacheEntry->read_addr_cnt; 5078305487Sdavidcs 5079305487Sdavidcs for (i = 0; i < loop_cnt; i++) { 5080305487Sdavidcs 5081305487Sdavidcs ret = ql_rdwr_indreg32(ha, tag_reg_addr, &tag_value, 0); 5082305487Sdavidcs if (ret) 5083305487Sdavidcs return (0); 5084305487Sdavidcs 5085305487Sdavidcs ret = ql_rdwr_indreg32(ha, cntrl_addr, &cntl_value_w, 0); 5086305487Sdavidcs if (ret) 5087305487Sdavidcs return (0); 5088305487Sdavidcs 5089305487Sdavidcs addr = read_addr; 5090305487Sdavidcs for (k = 0; k < read_cnt; k++) { 5091305487Sdavidcs 5092305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &read_value, 1); 5093305487Sdavidcs if (ret) 5094305487Sdavidcs return (0); 5095305487Sdavidcs 5096305487Sdavidcs *data_buff++ = read_value; 5097305487Sdavidcs addr += cacheEntry->read_addr_stride; 5098305487Sdavidcs } 5099305487Sdavidcs 5100305487Sdavidcs tag_value += cacheEntry->tag_value_stride; 5101305487Sdavidcs } 5102305487Sdavidcs 5103305487Sdavidcs return (read_cnt * loop_cnt * sizeof(uint32_t)); 5104305487Sdavidcs} 5105305487Sdavidcs 5106305487Sdavidcs/* 5107305487Sdavidcs * Reading OCM memory 5108305487Sdavidcs */ 5109305487Sdavidcs 5110305487Sdavidcsstatic uint32_t 5111305487Sdavidcsql_rdocm(qla_host_t *ha, 5112305487Sdavidcs ql_minidump_entry_rdocm_t *ocmEntry, 5113305487Sdavidcs uint32_t *data_buff) 5114305487Sdavidcs{ 5115305487Sdavidcs int i, loop_cnt; 5116305487Sdavidcs volatile uint32_t addr; 5117305487Sdavidcs volatile uint32_t value; 5118305487Sdavidcs 5119305487Sdavidcs addr = ocmEntry->read_addr; 5120305487Sdavidcs loop_cnt = ocmEntry->op_count; 5121305487Sdavidcs 5122305487Sdavidcs for (i = 0; i < loop_cnt; i++) { 5123305487Sdavidcs value = READ_REG32(ha, addr); 5124305487Sdavidcs *data_buff++ = value; 5125305487Sdavidcs addr += ocmEntry->read_addr_stride; 5126305487Sdavidcs } 5127305487Sdavidcs return (loop_cnt * sizeof(value)); 5128305487Sdavidcs} 5129305487Sdavidcs 5130305487Sdavidcs/* 5131305487Sdavidcs * Read memory 5132305487Sdavidcs */ 5133305487Sdavidcs 5134305487Sdavidcsstatic uint32_t 5135305487Sdavidcsql_rdmem(qla_host_t *ha, 5136305487Sdavidcs ql_minidump_entry_rdmem_t *mem_entry, 5137305487Sdavidcs uint32_t *data_buff) 5138305487Sdavidcs{ 5139305487Sdavidcs int ret; 5140305487Sdavidcs int i, loop_cnt; 5141305487Sdavidcs volatile uint32_t addr; 5142305487Sdavidcs q80_offchip_mem_val_t val; 5143305487Sdavidcs 5144305487Sdavidcs addr = mem_entry->read_addr; 5145305487Sdavidcs 5146305487Sdavidcs /* size in bytes / 16 */ 5147305487Sdavidcs loop_cnt = mem_entry->read_data_size / (sizeof(uint32_t) * 4); 5148305487Sdavidcs 5149305487Sdavidcs for (i = 0; i < loop_cnt; i++) { 5150305487Sdavidcs 5151305487Sdavidcs ret = ql_rdwr_offchip_mem(ha, (addr & 0x0ffffffff), &val, 1); 5152305487Sdavidcs if (ret) 5153305487Sdavidcs return (0); 5154305487Sdavidcs 5155305487Sdavidcs *data_buff++ = val.data_lo; 5156305487Sdavidcs *data_buff++ = val.data_hi; 5157305487Sdavidcs *data_buff++ = val.data_ulo; 5158305487Sdavidcs *data_buff++ = val.data_uhi; 5159305487Sdavidcs 5160305487Sdavidcs addr += (sizeof(uint32_t) * 4); 5161305487Sdavidcs } 5162305487Sdavidcs 5163305487Sdavidcs return (loop_cnt * (sizeof(uint32_t) * 4)); 5164305487Sdavidcs} 5165305487Sdavidcs 5166305487Sdavidcs/* 5167305487Sdavidcs * Read Rom 5168305487Sdavidcs */ 5169305487Sdavidcs 5170305487Sdavidcsstatic uint32_t 5171305487Sdavidcsql_rdrom(qla_host_t *ha, 5172305487Sdavidcs ql_minidump_entry_rdrom_t *romEntry, 5173305487Sdavidcs uint32_t *data_buff) 5174305487Sdavidcs{ 5175305487Sdavidcs int ret; 5176305487Sdavidcs int i, loop_cnt; 5177305487Sdavidcs uint32_t addr; 5178305487Sdavidcs uint32_t value; 5179305487Sdavidcs 5180305487Sdavidcs addr = romEntry->read_addr; 5181305487Sdavidcs loop_cnt = romEntry->read_data_size; /* This is size in bytes */ 5182305487Sdavidcs loop_cnt /= sizeof(value); 5183305487Sdavidcs 5184305487Sdavidcs for (i = 0; i < loop_cnt; i++) { 5185305487Sdavidcs 5186305487Sdavidcs ret = ql_rd_flash32(ha, addr, &value); 5187305487Sdavidcs if (ret) 5188305487Sdavidcs return (0); 5189305487Sdavidcs 5190305487Sdavidcs *data_buff++ = value; 5191305487Sdavidcs addr += sizeof(value); 5192305487Sdavidcs } 5193305487Sdavidcs 5194305487Sdavidcs return (loop_cnt * sizeof(value)); 5195305487Sdavidcs} 5196305487Sdavidcs 5197305487Sdavidcs/* 5198305487Sdavidcs * Read MUX data 5199305487Sdavidcs */ 5200305487Sdavidcs 5201305487Sdavidcsstatic uint32_t 5202305487Sdavidcsql_rdmux(qla_host_t *ha, 5203305487Sdavidcs ql_minidump_entry_mux_t *muxEntry, 5204305487Sdavidcs uint32_t *data_buff) 5205305487Sdavidcs{ 5206305487Sdavidcs int ret; 5207305487Sdavidcs int loop_cnt; 5208305487Sdavidcs uint32_t read_value, sel_value; 5209305487Sdavidcs uint32_t read_addr, select_addr; 5210305487Sdavidcs 5211305487Sdavidcs select_addr = muxEntry->select_addr; 5212305487Sdavidcs sel_value = muxEntry->select_value; 5213305487Sdavidcs read_addr = muxEntry->read_addr; 5214305487Sdavidcs 5215305487Sdavidcs for (loop_cnt = 0; loop_cnt < muxEntry->op_count; loop_cnt++) { 5216305487Sdavidcs 5217305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr, &sel_value, 0); 5218305487Sdavidcs if (ret) 5219305487Sdavidcs return (0); 5220305487Sdavidcs 5221305487Sdavidcs ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1); 5222305487Sdavidcs if (ret) 5223305487Sdavidcs return (0); 5224305487Sdavidcs 5225305487Sdavidcs *data_buff++ = sel_value; 5226305487Sdavidcs *data_buff++ = read_value; 5227305487Sdavidcs 5228305487Sdavidcs sel_value += muxEntry->select_value_stride; 5229305487Sdavidcs } 5230305487Sdavidcs 5231305487Sdavidcs return (loop_cnt * (2 * sizeof(uint32_t))); 5232305487Sdavidcs} 5233305487Sdavidcs 5234305487Sdavidcsstatic uint32_t 5235305487Sdavidcsql_rdmux2(qla_host_t *ha, 5236305487Sdavidcs ql_minidump_entry_mux2_t *muxEntry, 5237305487Sdavidcs uint32_t *data_buff) 5238305487Sdavidcs{ 5239305487Sdavidcs int ret; 5240305487Sdavidcs int loop_cnt; 5241305487Sdavidcs 5242305487Sdavidcs uint32_t select_addr_1, select_addr_2; 5243305487Sdavidcs uint32_t select_value_1, select_value_2; 5244305487Sdavidcs uint32_t select_value_count, select_value_mask; 5245305487Sdavidcs uint32_t read_addr, read_value; 5246305487Sdavidcs 5247305487Sdavidcs select_addr_1 = muxEntry->select_addr_1; 5248305487Sdavidcs select_addr_2 = muxEntry->select_addr_2; 5249305487Sdavidcs select_value_1 = muxEntry->select_value_1; 5250305487Sdavidcs select_value_2 = muxEntry->select_value_2; 5251305487Sdavidcs select_value_count = muxEntry->select_value_count; 5252305487Sdavidcs select_value_mask = muxEntry->select_value_mask; 5253305487Sdavidcs 5254305487Sdavidcs read_addr = muxEntry->read_addr; 5255305487Sdavidcs 5256305487Sdavidcs for (loop_cnt = 0; loop_cnt < muxEntry->select_value_count; 5257305487Sdavidcs loop_cnt++) { 5258305487Sdavidcs 5259305487Sdavidcs uint32_t temp_sel_val; 5260305487Sdavidcs 5261305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_1, 0); 5262305487Sdavidcs if (ret) 5263305487Sdavidcs return (0); 5264305487Sdavidcs 5265305487Sdavidcs temp_sel_val = select_value_1 & select_value_mask; 5266305487Sdavidcs 5267305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0); 5268305487Sdavidcs if (ret) 5269305487Sdavidcs return (0); 5270305487Sdavidcs 5271305487Sdavidcs ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1); 5272305487Sdavidcs if (ret) 5273305487Sdavidcs return (0); 5274305487Sdavidcs 5275305487Sdavidcs *data_buff++ = temp_sel_val; 5276305487Sdavidcs *data_buff++ = read_value; 5277305487Sdavidcs 5278305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr_1, &select_value_2, 0); 5279305487Sdavidcs if (ret) 5280305487Sdavidcs return (0); 5281305487Sdavidcs 5282305487Sdavidcs temp_sel_val = select_value_2 & select_value_mask; 5283305487Sdavidcs 5284305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr_2, &temp_sel_val, 0); 5285305487Sdavidcs if (ret) 5286305487Sdavidcs return (0); 5287305487Sdavidcs 5288305487Sdavidcs ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1); 5289305487Sdavidcs if (ret) 5290305487Sdavidcs return (0); 5291305487Sdavidcs 5292305487Sdavidcs *data_buff++ = temp_sel_val; 5293305487Sdavidcs *data_buff++ = read_value; 5294305487Sdavidcs 5295305487Sdavidcs select_value_1 += muxEntry->select_value_stride; 5296305487Sdavidcs select_value_2 += muxEntry->select_value_stride; 5297305487Sdavidcs } 5298305487Sdavidcs 5299305487Sdavidcs return (loop_cnt * (4 * sizeof(uint32_t))); 5300305487Sdavidcs} 5301305487Sdavidcs 5302305487Sdavidcs/* 5303305487Sdavidcs * Handling Queue State Reads. 5304305487Sdavidcs */ 5305305487Sdavidcs 5306305487Sdavidcsstatic uint32_t 5307305487Sdavidcsql_rdqueue(qla_host_t *ha, 5308305487Sdavidcs ql_minidump_entry_queue_t *queueEntry, 5309305487Sdavidcs uint32_t *data_buff) 5310305487Sdavidcs{ 5311305487Sdavidcs int ret; 5312305487Sdavidcs int loop_cnt, k; 5313305487Sdavidcs uint32_t read_value; 5314305487Sdavidcs uint32_t read_addr, read_stride, select_addr; 5315305487Sdavidcs uint32_t queue_id, read_cnt; 5316305487Sdavidcs 5317305487Sdavidcs read_cnt = queueEntry->read_addr_cnt; 5318305487Sdavidcs read_stride = queueEntry->read_addr_stride; 5319305487Sdavidcs select_addr = queueEntry->select_addr; 5320305487Sdavidcs 5321305487Sdavidcs for (loop_cnt = 0, queue_id = 0; loop_cnt < queueEntry->op_count; 5322305487Sdavidcs loop_cnt++) { 5323305487Sdavidcs 5324305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr, &queue_id, 0); 5325305487Sdavidcs if (ret) 5326305487Sdavidcs return (0); 5327305487Sdavidcs 5328305487Sdavidcs read_addr = queueEntry->read_addr; 5329305487Sdavidcs 5330305487Sdavidcs for (k = 0; k < read_cnt; k++) { 5331305487Sdavidcs 5332305487Sdavidcs ret = ql_rdwr_indreg32(ha, read_addr, &read_value, 1); 5333305487Sdavidcs if (ret) 5334305487Sdavidcs return (0); 5335305487Sdavidcs 5336305487Sdavidcs *data_buff++ = read_value; 5337305487Sdavidcs read_addr += read_stride; 5338305487Sdavidcs } 5339305487Sdavidcs 5340305487Sdavidcs queue_id += queueEntry->queue_id_stride; 5341305487Sdavidcs } 5342305487Sdavidcs 5343305487Sdavidcs return (loop_cnt * (read_cnt * sizeof(uint32_t))); 5344305487Sdavidcs} 5345305487Sdavidcs 5346305487Sdavidcs/* 5347305487Sdavidcs * Handling control entries. 5348305487Sdavidcs */ 5349305487Sdavidcs 5350305487Sdavidcsstatic uint32_t 5351305487Sdavidcsql_cntrl(qla_host_t *ha, 5352305487Sdavidcs ql_minidump_template_hdr_t *template_hdr, 5353305487Sdavidcs ql_minidump_entry_cntrl_t *crbEntry) 5354305487Sdavidcs{ 5355305487Sdavidcs int ret; 5356305487Sdavidcs int count; 5357305487Sdavidcs uint32_t opcode, read_value, addr, entry_addr; 5358305487Sdavidcs long timeout; 5359305487Sdavidcs 5360305487Sdavidcs entry_addr = crbEntry->addr; 5361305487Sdavidcs 5362305487Sdavidcs for (count = 0; count < crbEntry->op_count; count++) { 5363305487Sdavidcs opcode = crbEntry->opcode; 5364305487Sdavidcs 5365305487Sdavidcs if (opcode & QL_DBG_OPCODE_WR) { 5366305487Sdavidcs 5367305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, 5368305487Sdavidcs &crbEntry->value_1, 0); 5369305487Sdavidcs if (ret) 5370305487Sdavidcs return (0); 5371305487Sdavidcs 5372305487Sdavidcs opcode &= ~QL_DBG_OPCODE_WR; 5373305487Sdavidcs } 5374305487Sdavidcs 5375305487Sdavidcs if (opcode & QL_DBG_OPCODE_RW) { 5376305487Sdavidcs 5377305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1); 5378305487Sdavidcs if (ret) 5379305487Sdavidcs return (0); 5380305487Sdavidcs 5381305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0); 5382305487Sdavidcs if (ret) 5383305487Sdavidcs return (0); 5384305487Sdavidcs 5385305487Sdavidcs opcode &= ~QL_DBG_OPCODE_RW; 5386305487Sdavidcs } 5387305487Sdavidcs 5388305487Sdavidcs if (opcode & QL_DBG_OPCODE_AND) { 5389305487Sdavidcs 5390305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1); 5391305487Sdavidcs if (ret) 5392305487Sdavidcs return (0); 5393305487Sdavidcs 5394305487Sdavidcs read_value &= crbEntry->value_2; 5395305487Sdavidcs opcode &= ~QL_DBG_OPCODE_AND; 5396305487Sdavidcs 5397305487Sdavidcs if (opcode & QL_DBG_OPCODE_OR) { 5398305487Sdavidcs read_value |= crbEntry->value_3; 5399305487Sdavidcs opcode &= ~QL_DBG_OPCODE_OR; 5400305487Sdavidcs } 5401305487Sdavidcs 5402305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0); 5403305487Sdavidcs if (ret) 5404305487Sdavidcs return (0); 5405305487Sdavidcs } 5406305487Sdavidcs 5407305487Sdavidcs if (opcode & QL_DBG_OPCODE_OR) { 5408305487Sdavidcs 5409305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 1); 5410305487Sdavidcs if (ret) 5411305487Sdavidcs return (0); 5412305487Sdavidcs 5413305487Sdavidcs read_value |= crbEntry->value_3; 5414305487Sdavidcs 5415305487Sdavidcs ret = ql_rdwr_indreg32(ha, entry_addr, &read_value, 0); 5416305487Sdavidcs if (ret) 5417305487Sdavidcs return (0); 5418305487Sdavidcs 5419305487Sdavidcs opcode &= ~QL_DBG_OPCODE_OR; 5420305487Sdavidcs } 5421305487Sdavidcs 5422305487Sdavidcs if (opcode & QL_DBG_OPCODE_POLL) { 5423305487Sdavidcs 5424305487Sdavidcs opcode &= ~QL_DBG_OPCODE_POLL; 5425305487Sdavidcs timeout = crbEntry->poll_timeout; 5426305487Sdavidcs addr = entry_addr; 5427305487Sdavidcs 5428305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &read_value, 1); 5429305487Sdavidcs if (ret) 5430305487Sdavidcs return (0); 5431305487Sdavidcs 5432305487Sdavidcs while ((read_value & crbEntry->value_2) 5433305487Sdavidcs != crbEntry->value_1) { 5434305487Sdavidcs 5435305487Sdavidcs if (timeout) { 5436305487Sdavidcs qla_mdelay(__func__, 1); 5437305487Sdavidcs timeout--; 5438305487Sdavidcs } else 5439305487Sdavidcs break; 5440305487Sdavidcs 5441305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, 5442305487Sdavidcs &read_value, 1); 5443305487Sdavidcs if (ret) 5444305487Sdavidcs return (0); 5445305487Sdavidcs } 5446305487Sdavidcs 5447305487Sdavidcs if (!timeout) { 5448305487Sdavidcs /* 5449305487Sdavidcs * Report timeout error. 5450305487Sdavidcs * core dump capture failed 5451305487Sdavidcs * Skip remaining entries. 5452305487Sdavidcs * Write buffer out to file 5453305487Sdavidcs * Use driver specific fields in template header 5454305487Sdavidcs * to report this error. 5455305487Sdavidcs */ 5456305487Sdavidcs return (-1); 5457305487Sdavidcs } 5458305487Sdavidcs } 5459305487Sdavidcs 5460305487Sdavidcs if (opcode & QL_DBG_OPCODE_RDSTATE) { 5461305487Sdavidcs /* 5462305487Sdavidcs * decide which address to use. 5463305487Sdavidcs */ 5464305487Sdavidcs if (crbEntry->state_index_a) { 5465305487Sdavidcs addr = template_hdr->saved_state_array[ 5466305487Sdavidcs crbEntry-> state_index_a]; 5467305487Sdavidcs } else { 5468305487Sdavidcs addr = entry_addr; 5469305487Sdavidcs } 5470305487Sdavidcs 5471305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &read_value, 1); 5472305487Sdavidcs if (ret) 5473305487Sdavidcs return (0); 5474305487Sdavidcs 5475305487Sdavidcs template_hdr->saved_state_array[crbEntry->state_index_v] 5476305487Sdavidcs = read_value; 5477305487Sdavidcs opcode &= ~QL_DBG_OPCODE_RDSTATE; 5478305487Sdavidcs } 5479305487Sdavidcs 5480305487Sdavidcs if (opcode & QL_DBG_OPCODE_WRSTATE) { 5481305487Sdavidcs /* 5482305487Sdavidcs * decide which value to use. 5483305487Sdavidcs */ 5484305487Sdavidcs if (crbEntry->state_index_v) { 5485305487Sdavidcs read_value = template_hdr->saved_state_array[ 5486305487Sdavidcs crbEntry->state_index_v]; 5487305487Sdavidcs } else { 5488305487Sdavidcs read_value = crbEntry->value_1; 5489305487Sdavidcs } 5490305487Sdavidcs /* 5491305487Sdavidcs * decide which address to use. 5492305487Sdavidcs */ 5493305487Sdavidcs if (crbEntry->state_index_a) { 5494305487Sdavidcs addr = template_hdr->saved_state_array[ 5495305487Sdavidcs crbEntry-> state_index_a]; 5496305487Sdavidcs } else { 5497305487Sdavidcs addr = entry_addr; 5498305487Sdavidcs } 5499305487Sdavidcs 5500305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr, &read_value, 0); 5501305487Sdavidcs if (ret) 5502305487Sdavidcs return (0); 5503305487Sdavidcs 5504305487Sdavidcs opcode &= ~QL_DBG_OPCODE_WRSTATE; 5505305487Sdavidcs } 5506305487Sdavidcs 5507305487Sdavidcs if (opcode & QL_DBG_OPCODE_MDSTATE) { 5508305487Sdavidcs /* Read value from saved state using index */ 5509305487Sdavidcs read_value = template_hdr->saved_state_array[ 5510305487Sdavidcs crbEntry->state_index_v]; 5511305487Sdavidcs 5512305487Sdavidcs read_value <<= crbEntry->shl; /*Shift left operation */ 5513305487Sdavidcs read_value >>= crbEntry->shr; /*Shift right operation */ 5514305487Sdavidcs 5515305487Sdavidcs if (crbEntry->value_2) { 5516305487Sdavidcs /* check if AND mask is provided */ 5517305487Sdavidcs read_value &= crbEntry->value_2; 5518305487Sdavidcs } 5519305487Sdavidcs 5520305487Sdavidcs read_value |= crbEntry->value_3; /* OR operation */ 5521305487Sdavidcs read_value += crbEntry->value_1; /* increment op */ 5522305487Sdavidcs 5523305487Sdavidcs /* Write value back to state area. */ 5524305487Sdavidcs 5525305487Sdavidcs template_hdr->saved_state_array[crbEntry->state_index_v] 5526305487Sdavidcs = read_value; 5527305487Sdavidcs opcode &= ~QL_DBG_OPCODE_MDSTATE; 5528305487Sdavidcs } 5529305487Sdavidcs 5530305487Sdavidcs entry_addr += crbEntry->addr_stride; 5531305487Sdavidcs } 5532305487Sdavidcs 5533305487Sdavidcs return (0); 5534305487Sdavidcs} 5535305487Sdavidcs 5536305487Sdavidcs/* 5537305487Sdavidcs * Handling rd poll entry. 5538305487Sdavidcs */ 5539305487Sdavidcs 5540305487Sdavidcsstatic uint32_t 5541305487Sdavidcsql_pollrd(qla_host_t *ha, ql_minidump_entry_pollrd_t *entry, 5542305487Sdavidcs uint32_t *data_buff) 5543305487Sdavidcs{ 5544305487Sdavidcs int ret; 5545305487Sdavidcs int loop_cnt; 5546305487Sdavidcs uint32_t op_count, select_addr, select_value_stride, select_value; 5547305487Sdavidcs uint32_t read_addr, poll, mask, data_size, data; 5548305487Sdavidcs uint32_t wait_count = 0; 5549305487Sdavidcs 5550305487Sdavidcs select_addr = entry->select_addr; 5551305487Sdavidcs read_addr = entry->read_addr; 5552305487Sdavidcs select_value = entry->select_value; 5553305487Sdavidcs select_value_stride = entry->select_value_stride; 5554305487Sdavidcs op_count = entry->op_count; 5555305487Sdavidcs poll = entry->poll; 5556305487Sdavidcs mask = entry->mask; 5557305487Sdavidcs data_size = entry->data_size; 5558305487Sdavidcs 5559305487Sdavidcs for (loop_cnt = 0; loop_cnt < op_count; loop_cnt++) { 5560305487Sdavidcs 5561305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr, &select_value, 0); 5562305487Sdavidcs if (ret) 5563305487Sdavidcs return (0); 5564305487Sdavidcs 5565305487Sdavidcs wait_count = 0; 5566305487Sdavidcs 5567305487Sdavidcs while (wait_count < poll) { 5568305487Sdavidcs 5569305487Sdavidcs uint32_t temp; 5570305487Sdavidcs 5571305487Sdavidcs ret = ql_rdwr_indreg32(ha, select_addr, &temp, 1); 5572305487Sdavidcs if (ret) 5573305487Sdavidcs return (0); 5574305487Sdavidcs 5575305487Sdavidcs if ( (temp & mask) != 0 ) { 5576305487Sdavidcs break; 5577305487Sdavidcs } 5578305487Sdavidcs wait_count++; 5579305487Sdavidcs } 5580305487Sdavidcs 5581305487Sdavidcs if (wait_count == poll) { 5582305487Sdavidcs device_printf(ha->pci_dev, 5583305487Sdavidcs "%s: Error in processing entry\n", __func__); 5584305487Sdavidcs device_printf(ha->pci_dev, 5585305487Sdavidcs "%s: wait_count <0x%x> poll <0x%x>\n", 5586305487Sdavidcs __func__, wait_count, poll); 5587305487Sdavidcs return 0; 5588305487Sdavidcs } 5589305487Sdavidcs 5590305487Sdavidcs ret = ql_rdwr_indreg32(ha, read_addr, &data, 1); 5591305487Sdavidcs if (ret) 5592305487Sdavidcs return (0); 5593305487Sdavidcs 5594305487Sdavidcs *data_buff++ = select_value; 5595305487Sdavidcs *data_buff++ = data; 5596305487Sdavidcs select_value = select_value + select_value_stride; 5597305487Sdavidcs } 5598305487Sdavidcs 5599305487Sdavidcs /* 5600305487Sdavidcs * for testing purpose we return amount of data written 5601305487Sdavidcs */ 5602305487Sdavidcs return (loop_cnt * (2 * sizeof(uint32_t))); 5603305487Sdavidcs} 5604305487Sdavidcs 5605305487Sdavidcs 5606305487Sdavidcs/* 5607305487Sdavidcs * Handling rd modify write poll entry. 5608305487Sdavidcs */ 5609305487Sdavidcs 5610305487Sdavidcsstatic uint32_t 5611305487Sdavidcsql_pollrd_modify_write(qla_host_t *ha, 5612305487Sdavidcs ql_minidump_entry_rd_modify_wr_with_poll_t *entry, 5613305487Sdavidcs uint32_t *data_buff) 5614305487Sdavidcs{ 5615305487Sdavidcs int ret; 5616305487Sdavidcs uint32_t addr_1, addr_2, value_1, value_2, data; 5617305487Sdavidcs uint32_t poll, mask, data_size, modify_mask; 5618305487Sdavidcs uint32_t wait_count = 0; 5619305487Sdavidcs 5620305487Sdavidcs addr_1 = entry->addr_1; 5621305487Sdavidcs addr_2 = entry->addr_2; 5622305487Sdavidcs value_1 = entry->value_1; 5623305487Sdavidcs value_2 = entry->value_2; 5624305487Sdavidcs 5625305487Sdavidcs poll = entry->poll; 5626305487Sdavidcs mask = entry->mask; 5627305487Sdavidcs modify_mask = entry->modify_mask; 5628305487Sdavidcs data_size = entry->data_size; 5629305487Sdavidcs 5630305487Sdavidcs 5631305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_1, &value_1, 0); 5632305487Sdavidcs if (ret) 5633305487Sdavidcs return (0); 5634305487Sdavidcs 5635305487Sdavidcs wait_count = 0; 5636305487Sdavidcs while (wait_count < poll) { 5637305487Sdavidcs 5638305487Sdavidcs uint32_t temp; 5639305487Sdavidcs 5640305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1); 5641305487Sdavidcs if (ret) 5642305487Sdavidcs return (0); 5643305487Sdavidcs 5644305487Sdavidcs if ( (temp & mask) != 0 ) { 5645305487Sdavidcs break; 5646305487Sdavidcs } 5647305487Sdavidcs wait_count++; 5648305487Sdavidcs } 5649305487Sdavidcs 5650305487Sdavidcs if (wait_count == poll) { 5651305487Sdavidcs device_printf(ha->pci_dev, "%s Error in processing entry\n", 5652305487Sdavidcs __func__); 5653305487Sdavidcs } else { 5654305487Sdavidcs 5655305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_2, &data, 1); 5656305487Sdavidcs if (ret) 5657305487Sdavidcs return (0); 5658305487Sdavidcs 5659305487Sdavidcs data = (data & modify_mask); 5660305487Sdavidcs 5661305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_2, &data, 0); 5662305487Sdavidcs if (ret) 5663305487Sdavidcs return (0); 5664305487Sdavidcs 5665305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_1, &value_2, 0); 5666305487Sdavidcs if (ret) 5667305487Sdavidcs return (0); 5668305487Sdavidcs 5669305487Sdavidcs /* Poll again */ 5670305487Sdavidcs wait_count = 0; 5671305487Sdavidcs while (wait_count < poll) { 5672305487Sdavidcs 5673305487Sdavidcs uint32_t temp; 5674305487Sdavidcs 5675305487Sdavidcs ret = ql_rdwr_indreg32(ha, addr_1, &temp, 1); 5676305487Sdavidcs if (ret) 5677305487Sdavidcs return (0); 5678305487Sdavidcs 5679305487Sdavidcs if ( (temp & mask) != 0 ) { 5680305487Sdavidcs break; 5681305487Sdavidcs } 5682305487Sdavidcs wait_count++; 5683305487Sdavidcs } 5684305487Sdavidcs *data_buff++ = addr_2; 5685305487Sdavidcs *data_buff++ = data; 5686305487Sdavidcs } 5687305487Sdavidcs 5688305487Sdavidcs /* 5689305487Sdavidcs * for testing purpose we return amount of data written 5690305487Sdavidcs */ 5691305487Sdavidcs return (2 * sizeof(uint32_t)); 5692305487Sdavidcs} 5693305487Sdavidcs 5694305487Sdavidcs 5695