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(&reg82->host_int)) == ISP_REG_DISCONNECT);
4638c2ecf20Sopenharmony_ci	else
4648c2ecf20Sopenharmony_ci		return ((rd_reg_dword(&reg->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(&reg->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