18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * QLogic Fibre Channel HBA Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include "qla_target.h" 88c2ecf20Sopenharmony_ci/** 98c2ecf20Sopenharmony_ci * qla24xx_calc_iocbs() - Determine number of Command Type 3 and 108c2ecf20Sopenharmony_ci * Continuation Type 1 IOCBs to allocate. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * @vha: HA context 138c2ecf20Sopenharmony_ci * @dsds: number of data segment descriptors needed 148c2ecf20Sopenharmony_ci * 158c2ecf20Sopenharmony_ci * Returns the number of IOCB entries needed to store @dsds. 168c2ecf20Sopenharmony_ci */ 178c2ecf20Sopenharmony_cistatic inline uint16_t 188c2ecf20Sopenharmony_ciqla24xx_calc_iocbs(scsi_qla_host_t *vha, uint16_t dsds) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci uint16_t iocbs; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci iocbs = 1; 238c2ecf20Sopenharmony_ci if (dsds > 1) { 248c2ecf20Sopenharmony_ci iocbs += (dsds - 1) / 5; 258c2ecf20Sopenharmony_ci if ((dsds - 1) % 5) 268c2ecf20Sopenharmony_ci iocbs++; 278c2ecf20Sopenharmony_ci } 288c2ecf20Sopenharmony_ci return iocbs; 298c2ecf20Sopenharmony_ci} 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* 328c2ecf20Sopenharmony_ci * qla2x00_debounce_register 338c2ecf20Sopenharmony_ci * Debounce register. 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * Input: 368c2ecf20Sopenharmony_ci * port = register address. 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Returns: 398c2ecf20Sopenharmony_ci * register value. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic __inline__ uint16_t 428c2ecf20Sopenharmony_ciqla2x00_debounce_register(volatile __le16 __iomem *addr) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci volatile uint16_t first; 458c2ecf20Sopenharmony_ci volatile uint16_t second; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci do { 488c2ecf20Sopenharmony_ci first = rd_reg_word(addr); 498c2ecf20Sopenharmony_ci barrier(); 508c2ecf20Sopenharmony_ci cpu_relax(); 518c2ecf20Sopenharmony_ci second = rd_reg_word(addr); 528c2ecf20Sopenharmony_ci } while (first != second); 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci return (first); 558c2ecf20Sopenharmony_ci} 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic inline void 588c2ecf20Sopenharmony_ciqla2x00_poll(struct rsp_que *rsp) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct qla_hw_data *ha = rsp->hw; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci if (IS_P3P_TYPE(ha)) 638c2ecf20Sopenharmony_ci qla82xx_poll(0, rsp); 648c2ecf20Sopenharmony_ci else 658c2ecf20Sopenharmony_ci ha->isp_ops->intr_handler(0, rsp); 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic inline uint8_t * 698c2ecf20Sopenharmony_cihost_to_fcp_swap(uint8_t *fcp, uint32_t bsize) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci uint32_t *ifcp = (uint32_t *) fcp; 728c2ecf20Sopenharmony_ci uint32_t *ofcp = (uint32_t *) fcp; 738c2ecf20Sopenharmony_ci uint32_t iter = bsize >> 2; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (; iter ; iter--) 768c2ecf20Sopenharmony_ci *ofcp++ = swab32(*ifcp++); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci return fcp; 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_cistatic inline void 828c2ecf20Sopenharmony_cihost_to_adap(uint8_t *src, uint8_t *dst, uint32_t bsize) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci uint32_t *isrc = (uint32_t *) src; 858c2ecf20Sopenharmony_ci __le32 *odest = (__le32 *) dst; 868c2ecf20Sopenharmony_ci uint32_t iter = bsize >> 2; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci for ( ; iter--; isrc++) 898c2ecf20Sopenharmony_ci *odest++ = cpu_to_le32(*isrc); 908c2ecf20Sopenharmony_ci} 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic inline void 938c2ecf20Sopenharmony_ciqla2x00_clean_dsd_pool(struct qla_hw_data *ha, struct crc_context *ctx) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct dsd_dma *dsd, *tdsd; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* clean up allocated prev pool */ 988c2ecf20Sopenharmony_ci list_for_each_entry_safe(dsd, tdsd, &ctx->dsd_list, list) { 998c2ecf20Sopenharmony_ci dma_pool_free(ha->dl_dma_pool, dsd->dsd_addr, 1008c2ecf20Sopenharmony_ci dsd->dsd_list_dma); 1018c2ecf20Sopenharmony_ci list_del(&dsd->list); 1028c2ecf20Sopenharmony_ci kfree(dsd); 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&ctx->dsd_list); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic inline void 1088c2ecf20Sopenharmony_ciqla2x00_set_fcport_disc_state(fc_port_t *fcport, int state) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int old_val; 1118c2ecf20Sopenharmony_ci uint8_t shiftbits, mask; 1128c2ecf20Sopenharmony_ci uint8_t port_dstate_str_sz; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* This will have to change when the max no. of states > 16 */ 1158c2ecf20Sopenharmony_ci shiftbits = 4; 1168c2ecf20Sopenharmony_ci mask = (1 << shiftbits) - 1; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci port_dstate_str_sz = sizeof(port_dstate_str) / sizeof(char *); 1198c2ecf20Sopenharmony_ci fcport->disc_state = state; 1208c2ecf20Sopenharmony_ci while (1) { 1218c2ecf20Sopenharmony_ci old_val = atomic_read(&fcport->shadow_disc_state); 1228c2ecf20Sopenharmony_ci if (old_val == atomic_cmpxchg(&fcport->shadow_disc_state, 1238c2ecf20Sopenharmony_ci old_val, (old_val << shiftbits) | state)) { 1248c2ecf20Sopenharmony_ci ql_dbg(ql_dbg_disc, fcport->vha, 0x2134, 1258c2ecf20Sopenharmony_ci "FCPort %8phC disc_state transition: %s to %s - portid=%06x.\n", 1268c2ecf20Sopenharmony_ci fcport->port_name, (old_val & mask) < port_dstate_str_sz ? 1278c2ecf20Sopenharmony_ci port_dstate_str[old_val & mask] : "Unknown", 1288c2ecf20Sopenharmony_ci port_dstate_str[state], fcport->d_id.b24); 1298c2ecf20Sopenharmony_ci return; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci} 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_cistatic inline int 1358c2ecf20Sopenharmony_ciqla2x00_hba_err_chk_enabled(srb_t *sp) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci /* 1388c2ecf20Sopenharmony_ci * Uncomment when corresponding SCSI changes are done. 1398c2ecf20Sopenharmony_ci * 1408c2ecf20Sopenharmony_ci if (!sp->cmd->prot_chk) 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_ci switch (scsi_get_prot_op(GET_CMD_SP(sp))) { 1458c2ecf20Sopenharmony_ci case SCSI_PROT_READ_STRIP: 1468c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_INSERT: 1478c2ecf20Sopenharmony_ci if (ql2xenablehba_err_chk >= 1) 1488c2ecf20Sopenharmony_ci return 1; 1498c2ecf20Sopenharmony_ci break; 1508c2ecf20Sopenharmony_ci case SCSI_PROT_READ_PASS: 1518c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_PASS: 1528c2ecf20Sopenharmony_ci if (ql2xenablehba_err_chk >= 2) 1538c2ecf20Sopenharmony_ci return 1; 1548c2ecf20Sopenharmony_ci break; 1558c2ecf20Sopenharmony_ci case SCSI_PROT_READ_INSERT: 1568c2ecf20Sopenharmony_ci case SCSI_PROT_WRITE_STRIP: 1578c2ecf20Sopenharmony_ci return 1; 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci} 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_cistatic inline int 1638c2ecf20Sopenharmony_ciqla2x00_reset_active(scsi_qla_host_t *vha) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci scsi_qla_host_t *base_vha = pci_get_drvdata(vha->hw->pdev); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Test appropriate base-vha and vha flags. */ 1688c2ecf20Sopenharmony_ci return test_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags) || 1698c2ecf20Sopenharmony_ci test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags) || 1708c2ecf20Sopenharmony_ci test_bit(ISP_ABORT_RETRY, &base_vha->dpc_flags) || 1718c2ecf20Sopenharmony_ci test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags) || 1728c2ecf20Sopenharmony_ci test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_cistatic inline int 1768c2ecf20Sopenharmony_ciqla2x00_chip_is_down(scsi_qla_host_t *vha) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci return (qla2x00_reset_active(vha) || !vha->hw->flags.fw_started); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_cistatic void qla2xxx_init_sp(srb_t *sp, scsi_qla_host_t *vha, 1828c2ecf20Sopenharmony_ci struct qla_qpair *qpair, fc_port_t *fcport) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci memset(sp, 0, sizeof(*sp)); 1858c2ecf20Sopenharmony_ci sp->fcport = fcport; 1868c2ecf20Sopenharmony_ci sp->iocbs = 1; 1878c2ecf20Sopenharmony_ci sp->vha = vha; 1888c2ecf20Sopenharmony_ci sp->qpair = qpair; 1898c2ecf20Sopenharmony_ci sp->cmd_type = TYPE_SRB; 1908c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&sp->elem); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic inline srb_t * 1948c2ecf20Sopenharmony_ciqla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair, 1958c2ecf20Sopenharmony_ci fc_port_t *fcport, gfp_t flag) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci srb_t *sp = NULL; 1988c2ecf20Sopenharmony_ci uint8_t bail; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci QLA_QPAIR_MARK_BUSY(qpair, bail); 2018c2ecf20Sopenharmony_ci if (unlikely(bail)) 2028c2ecf20Sopenharmony_ci return NULL; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci sp = mempool_alloc(qpair->srb_mempool, flag); 2058c2ecf20Sopenharmony_ci if (sp) 2068c2ecf20Sopenharmony_ci qla2xxx_init_sp(sp, vha, qpair, fcport); 2078c2ecf20Sopenharmony_ci else 2088c2ecf20Sopenharmony_ci QLA_QPAIR_MARK_NOT_BUSY(qpair); 2098c2ecf20Sopenharmony_ci return sp; 2108c2ecf20Sopenharmony_ci} 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_civoid qla2xxx_rel_done_warning(srb_t *sp, int res); 2138c2ecf20Sopenharmony_civoid qla2xxx_rel_free_warning(srb_t *sp); 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_cistatic inline void 2168c2ecf20Sopenharmony_ciqla2xxx_rel_qpair_sp(struct qla_qpair *qpair, srb_t *sp) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci sp->qpair = NULL; 2198c2ecf20Sopenharmony_ci sp->done = qla2xxx_rel_done_warning; 2208c2ecf20Sopenharmony_ci sp->free = qla2xxx_rel_free_warning; 2218c2ecf20Sopenharmony_ci mempool_free(sp, qpair->srb_mempool); 2228c2ecf20Sopenharmony_ci QLA_QPAIR_MARK_NOT_BUSY(qpair); 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic inline srb_t * 2268c2ecf20Sopenharmony_ciqla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci srb_t *sp = NULL; 2298c2ecf20Sopenharmony_ci uint8_t bail; 2308c2ecf20Sopenharmony_ci struct qla_qpair *qpair; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci QLA_VHA_MARK_BUSY(vha, bail); 2338c2ecf20Sopenharmony_ci if (unlikely(bail)) 2348c2ecf20Sopenharmony_ci return NULL; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci qpair = vha->hw->base_qpair; 2378c2ecf20Sopenharmony_ci sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, flag); 2388c2ecf20Sopenharmony_ci if (!sp) 2398c2ecf20Sopenharmony_ci goto done; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci sp->vha = vha; 2428c2ecf20Sopenharmony_cidone: 2438c2ecf20Sopenharmony_ci if (!sp) 2448c2ecf20Sopenharmony_ci QLA_VHA_MARK_NOT_BUSY(vha); 2458c2ecf20Sopenharmony_ci return sp; 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistatic inline void 2498c2ecf20Sopenharmony_ciqla2x00_rel_sp(srb_t *sp) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci QLA_VHA_MARK_NOT_BUSY(sp->vha); 2528c2ecf20Sopenharmony_ci qla2xxx_rel_qpair_sp(sp->qpair, sp); 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic inline int 2568c2ecf20Sopenharmony_ciqla2x00_gid_list_size(struct qla_hw_data *ha) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci if (IS_QLAFX00(ha)) 2598c2ecf20Sopenharmony_ci return sizeof(uint32_t) * 32; 2608c2ecf20Sopenharmony_ci else 2618c2ecf20Sopenharmony_ci return sizeof(struct gid_list_info) * ha->max_fibre_devices; 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic inline void 2658c2ecf20Sopenharmony_ciqla2x00_handle_mbx_completion(struct qla_hw_data *ha, int status) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) && 2688c2ecf20Sopenharmony_ci (status & MBX_INTERRUPT) && ha->flags.mbox_int) { 2698c2ecf20Sopenharmony_ci set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); 2708c2ecf20Sopenharmony_ci clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); 2718c2ecf20Sopenharmony_ci complete(&ha->mbx_intr_comp); 2728c2ecf20Sopenharmony_ci } 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic inline void 2768c2ecf20Sopenharmony_ciqla2x00_set_retry_delay_timestamp(fc_port_t *fcport, uint16_t sts_qual) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci u8 scope; 2798c2ecf20Sopenharmony_ci u16 qual; 2808c2ecf20Sopenharmony_ci#define SQ_SCOPE_MASK 0xc000 /* SAM-6 rev5 5.3.2 */ 2818c2ecf20Sopenharmony_ci#define SQ_SCOPE_SHIFT 14 2828c2ecf20Sopenharmony_ci#define SQ_QUAL_MASK 0x3fff 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci#define SQ_MAX_WAIT_SEC 60 /* Max I/O hold off time in seconds. */ 2858c2ecf20Sopenharmony_ci#define SQ_MAX_WAIT_TIME (SQ_MAX_WAIT_SEC * 10) /* in 100ms. */ 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci if (!sts_qual) /* Common case. */ 2888c2ecf20Sopenharmony_ci return; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci scope = (sts_qual & SQ_SCOPE_MASK) >> SQ_SCOPE_SHIFT; 2918c2ecf20Sopenharmony_ci /* Handle only scope 1 or 2, which is for I-T nexus. */ 2928c2ecf20Sopenharmony_ci if (scope != 1 && scope != 2) 2938c2ecf20Sopenharmony_ci return; 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Skip processing, if retry delay timer is already in effect. */ 2968c2ecf20Sopenharmony_ci if (fcport->retry_delay_timestamp && 2978c2ecf20Sopenharmony_ci time_before(jiffies, fcport->retry_delay_timestamp)) 2988c2ecf20Sopenharmony_ci return; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci qual = sts_qual & SQ_QUAL_MASK; 3018c2ecf20Sopenharmony_ci if (qual < 1 || qual > 0x3fef) 3028c2ecf20Sopenharmony_ci return; 3038c2ecf20Sopenharmony_ci qual = min(qual, (u16)SQ_MAX_WAIT_TIME); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci /* qual is expressed in 100ms increments. */ 3068c2ecf20Sopenharmony_ci fcport->retry_delay_timestamp = jiffies + (qual * HZ / 10); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci ql_log(ql_log_warn, fcport->vha, 0x5101, 3098c2ecf20Sopenharmony_ci "%8phC: I/O throttling requested (status qualifier = %04xh), holding off I/Os for %ums.\n", 3108c2ecf20Sopenharmony_ci fcport->port_name, sts_qual, qual * 100); 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic inline bool 3148c2ecf20Sopenharmony_ciqla_is_exch_offld_enabled(struct scsi_qla_host *vha) 3158c2ecf20Sopenharmony_ci{ 3168c2ecf20Sopenharmony_ci if (qla_ini_mode_enabled(vha) && 3178c2ecf20Sopenharmony_ci (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) 3188c2ecf20Sopenharmony_ci return true; 3198c2ecf20Sopenharmony_ci else if (qla_tgt_mode_enabled(vha) && 3208c2ecf20Sopenharmony_ci (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) 3218c2ecf20Sopenharmony_ci return true; 3228c2ecf20Sopenharmony_ci else if (qla_dual_mode_enabled(vha) && 3238c2ecf20Sopenharmony_ci ((vha->ql2xiniexchg + vha->ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) 3248c2ecf20Sopenharmony_ci return true; 3258c2ecf20Sopenharmony_ci else 3268c2ecf20Sopenharmony_ci return false; 3278c2ecf20Sopenharmony_ci} 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_cistatic inline void 3308c2ecf20Sopenharmony_ciqla_cpu_update(struct qla_qpair *qpair, uint16_t cpuid) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci qpair->cpuid = cpuid; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!list_empty(&qpair->hints_list)) { 3358c2ecf20Sopenharmony_ci struct qla_qpair_hint *h; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci list_for_each_entry(h, &qpair->hints_list, hint_elem) 3388c2ecf20Sopenharmony_ci h->cpuid = qpair->cpuid; 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic inline struct qla_qpair_hint * 3438c2ecf20Sopenharmony_ciqla_qpair_to_hint(struct qla_tgt *tgt, struct qla_qpair *qpair) 3448c2ecf20Sopenharmony_ci{ 3458c2ecf20Sopenharmony_ci struct qla_qpair_hint *h; 3468c2ecf20Sopenharmony_ci u16 i; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci for (i = 0; i < tgt->ha->max_qpairs + 1; i++) { 3498c2ecf20Sopenharmony_ci h = &tgt->qphints[i]; 3508c2ecf20Sopenharmony_ci if (h->qpair == qpair) 3518c2ecf20Sopenharmony_ci return h; 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci return NULL; 3558c2ecf20Sopenharmony_ci} 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_cistatic inline void 3588c2ecf20Sopenharmony_ciqla_83xx_start_iocbs(struct qla_qpair *qpair) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci struct req_que *req = qpair->req; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci req->ring_index++; 3638c2ecf20Sopenharmony_ci if (req->ring_index == req->length) { 3648c2ecf20Sopenharmony_ci req->ring_index = 0; 3658c2ecf20Sopenharmony_ci req->ring_ptr = req->ring; 3668c2ecf20Sopenharmony_ci } else 3678c2ecf20Sopenharmony_ci req->ring_ptr++; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci wrt_reg_dword(req->req_q_in, req->ring_index); 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_cistatic inline int 3738c2ecf20Sopenharmony_ciqla2xxx_get_fc4_priority(struct scsi_qla_host *vha) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci uint32_t data; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci data = 3788c2ecf20Sopenharmony_ci ((uint8_t *)vha->hw->nvram)[NVRAM_DUAL_FCP_NVME_FLAG_OFFSET]; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci return (data >> 6) & BIT_0 ? FC4_PRIORITY_FCP : FC4_PRIORITY_NVME; 3828c2ecf20Sopenharmony_ci} 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_cienum { 3858c2ecf20Sopenharmony_ci RESOURCE_NONE, 3868c2ecf20Sopenharmony_ci RESOURCE_INI, 3878c2ecf20Sopenharmony_ci}; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_cistatic inline int 3908c2ecf20Sopenharmony_ciqla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) 3918c2ecf20Sopenharmony_ci{ 3928c2ecf20Sopenharmony_ci u16 iocbs_used, i; 3938c2ecf20Sopenharmony_ci struct qla_hw_data *ha = qp->vha->hw; 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci if (!ql2xenforce_iocb_limit) { 3968c2ecf20Sopenharmony_ci iores->res_type = RESOURCE_NONE; 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if ((iores->iocb_cnt + qp->fwres.iocbs_used) < qp->fwres.iocbs_qp_limit) { 4018c2ecf20Sopenharmony_ci qp->fwres.iocbs_used += iores->iocb_cnt; 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci } else { 4048c2ecf20Sopenharmony_ci /* no need to acquire qpair lock. It's just rough calculation */ 4058c2ecf20Sopenharmony_ci iocbs_used = ha->base_qpair->fwres.iocbs_used; 4068c2ecf20Sopenharmony_ci for (i = 0; i < ha->max_qpairs; i++) { 4078c2ecf20Sopenharmony_ci if (ha->queue_pair_map[i]) 4088c2ecf20Sopenharmony_ci iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used; 4098c2ecf20Sopenharmony_ci } 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci if ((iores->iocb_cnt + iocbs_used) < qp->fwres.iocbs_limit) { 4128c2ecf20Sopenharmony_ci qp->fwres.iocbs_used += iores->iocb_cnt; 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci } else { 4158c2ecf20Sopenharmony_ci iores->res_type = RESOURCE_NONE; 4168c2ecf20Sopenharmony_ci return -ENOSPC; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci} 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_cistatic inline void 4228c2ecf20Sopenharmony_ciqla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci switch (iores->res_type) { 4258c2ecf20Sopenharmony_ci case RESOURCE_NONE: 4268c2ecf20Sopenharmony_ci break; 4278c2ecf20Sopenharmony_ci default: 4288c2ecf20Sopenharmony_ci if (qp->fwres.iocbs_used >= iores->iocb_cnt) { 4298c2ecf20Sopenharmony_ci qp->fwres.iocbs_used -= iores->iocb_cnt; 4308c2ecf20Sopenharmony_ci } else { 4318c2ecf20Sopenharmony_ci // should not happen 4328c2ecf20Sopenharmony_ci qp->fwres.iocbs_used = 0; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci } 4368c2ecf20Sopenharmony_ci iores->res_type = RESOURCE_NONE; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci#define ISP_REG_DISCONNECT 0xffffffffU 4408c2ecf20Sopenharmony_ci/************************************************************************** 4418c2ecf20Sopenharmony_ci * qla2x00_isp_reg_stat 4428c2ecf20Sopenharmony_ci * 4438c2ecf20Sopenharmony_ci * Description: 4448c2ecf20Sopenharmony_ci * Read the host status register of ISP before aborting the command. 4458c2ecf20Sopenharmony_ci * 4468c2ecf20Sopenharmony_ci * Input: 4478c2ecf20Sopenharmony_ci * ha = pointer to host adapter structure. 4488c2ecf20Sopenharmony_ci * 4498c2ecf20Sopenharmony_ci * 4508c2ecf20Sopenharmony_ci * Returns: 4518c2ecf20Sopenharmony_ci * Either true or false. 4528c2ecf20Sopenharmony_ci * 4538c2ecf20Sopenharmony_ci * Note: Return true if there is register disconnect. 4548c2ecf20Sopenharmony_ci **************************************************************************/ 4558c2ecf20Sopenharmony_cistatic inline 4568c2ecf20Sopenharmony_ciuint32_t qla2x00_isp_reg_stat(struct qla_hw_data *ha) 4578c2ecf20Sopenharmony_ci{ 4588c2ecf20Sopenharmony_ci struct device_reg_24xx __iomem *reg = &ha->iobase->isp24; 4598c2ecf20Sopenharmony_ci struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (IS_P3P_TYPE(ha)) 4628c2ecf20Sopenharmony_ci return ((rd_reg_dword(®82->host_int)) == ISP_REG_DISCONNECT); 4638c2ecf20Sopenharmony_ci else 4648c2ecf20Sopenharmony_ci return ((rd_reg_dword(®->host_status)) == 4658c2ecf20Sopenharmony_ci ISP_REG_DISCONNECT); 4668c2ecf20Sopenharmony_ci} 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_cistatic inline 4698c2ecf20Sopenharmony_cibool qla_pci_disconnected(struct scsi_qla_host *vha, 4708c2ecf20Sopenharmony_ci struct device_reg_24xx __iomem *reg) 4718c2ecf20Sopenharmony_ci{ 4728c2ecf20Sopenharmony_ci uint32_t stat; 4738c2ecf20Sopenharmony_ci bool ret = false; 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci stat = rd_reg_dword(®->host_status); 4768c2ecf20Sopenharmony_ci if (stat == 0xffffffff) { 4778c2ecf20Sopenharmony_ci ql_log(ql_log_info, vha, 0x8041, 4788c2ecf20Sopenharmony_ci "detected PCI disconnect.\n"); 4798c2ecf20Sopenharmony_ci qla_schedule_eeh_work(vha); 4808c2ecf20Sopenharmony_ci ret = true; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci return ret; 4838c2ecf20Sopenharmony_ci} 484