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#include "qla_def.h"
78c2ecf20Sopenharmony_ci#include "qla_target.h"
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/delay.h>
108c2ecf20Sopenharmony_ci#include <linux/slab.h>
118c2ecf20Sopenharmony_ci#include <linux/cpu.h>
128c2ecf20Sopenharmony_ci#include <linux/t10-pi.h>
138c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
148c2ecf20Sopenharmony_ci#include <scsi/scsi_bsg_fc.h>
158c2ecf20Sopenharmony_ci#include <scsi/scsi_eh.h>
168c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h>
178c2ecf20Sopenharmony_ci#include <linux/nvme-fc-driver.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_cistatic void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
208c2ecf20Sopenharmony_cistatic void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
218c2ecf20Sopenharmony_cistatic void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
228c2ecf20Sopenharmony_cistatic int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
238c2ecf20Sopenharmony_ci	sts_entry_t *);
248c2ecf20Sopenharmony_cistatic void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
258c2ecf20Sopenharmony_ci	struct purex_item *item);
268c2ecf20Sopenharmony_cistatic struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha,
278c2ecf20Sopenharmony_ci	uint16_t size);
288c2ecf20Sopenharmony_cistatic struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha,
298c2ecf20Sopenharmony_ci	void *pkt);
308c2ecf20Sopenharmony_cistatic struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha,
318c2ecf20Sopenharmony_ci	void **pkt, struct rsp_que **rsp);
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void
348c2ecf20Sopenharmony_ciqla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item)
358c2ecf20Sopenharmony_ci{
368c2ecf20Sopenharmony_ci	void *pkt = &item->iocb;
378c2ecf20Sopenharmony_ci	uint16_t pkt_size = item->size;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d,
408c2ecf20Sopenharmony_ci	       "%s: Enter\n", __func__);
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e,
438c2ecf20Sopenharmony_ci	       "-------- ELS REQ -------\n");
448c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f,
458c2ecf20Sopenharmony_ci		       pkt, pkt_size);
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt);
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciconst char *const port_state_str[] = {
518c2ecf20Sopenharmony_ci	"Unknown",
528c2ecf20Sopenharmony_ci	"UNCONFIGURED",
538c2ecf20Sopenharmony_ci	"DEAD",
548c2ecf20Sopenharmony_ci	"LOST",
558c2ecf20Sopenharmony_ci	"ONLINE"
568c2ecf20Sopenharmony_ci};
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cistatic void
598c2ecf20Sopenharmony_ciqla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct abts_entry_24xx *abts =
628c2ecf20Sopenharmony_ci	    (struct abts_entry_24xx *)&pkt->iocb;
638c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
648c2ecf20Sopenharmony_ci	struct els_entry_24xx *rsp_els;
658c2ecf20Sopenharmony_ci	struct abts_entry_24xx *abts_rsp;
668c2ecf20Sopenharmony_ci	dma_addr_t dma;
678c2ecf20Sopenharmony_ci	uint32_t fctl;
688c2ecf20Sopenharmony_ci	int rval;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x0287,
738c2ecf20Sopenharmony_ci	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n",
748c2ecf20Sopenharmony_ci	    abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id,
758c2ecf20Sopenharmony_ci	    abts->seq_id, abts->seq_cnt);
768c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
778c2ecf20Sopenharmony_ci	    "-------- ABTS RCV -------\n");
788c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
798c2ecf20Sopenharmony_ci	    (uint8_t *)abts, sizeof(*abts));
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma,
828c2ecf20Sopenharmony_ci	    GFP_KERNEL);
838c2ecf20Sopenharmony_ci	if (!rsp_els) {
848c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0287,
858c2ecf20Sopenharmony_ci		    "Failed allocate dma buffer ABTS/ELS RSP.\n");
868c2ecf20Sopenharmony_ci		return;
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_ci	/* terminate exchange */
908c2ecf20Sopenharmony_ci	rsp_els->entry_type = ELS_IOCB_TYPE;
918c2ecf20Sopenharmony_ci	rsp_els->entry_count = 1;
928c2ecf20Sopenharmony_ci	rsp_els->nport_handle = cpu_to_le16(~0);
938c2ecf20Sopenharmony_ci	rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort;
948c2ecf20Sopenharmony_ci	rsp_els->control_flags = cpu_to_le16(EPD_RX_XCHG);
958c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0283,
968c2ecf20Sopenharmony_ci	    "Sending ELS Response to terminate exchange %#x...\n",
978c2ecf20Sopenharmony_ci	    abts->rx_xch_addr_to_abort);
988c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
998c2ecf20Sopenharmony_ci	    "-------- ELS RSP -------\n");
1008c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
1018c2ecf20Sopenharmony_ci	    (uint8_t *)rsp_els, sizeof(*rsp_els));
1028c2ecf20Sopenharmony_ci	rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0);
1038c2ecf20Sopenharmony_ci	if (rval) {
1048c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0288,
1058c2ecf20Sopenharmony_ci		    "%s: iocb failed to execute -> %x\n", __func__, rval);
1068c2ecf20Sopenharmony_ci	} else if (rsp_els->comp_status) {
1078c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0289,
1088c2ecf20Sopenharmony_ci		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
1098c2ecf20Sopenharmony_ci		    __func__, rsp_els->comp_status,
1108c2ecf20Sopenharmony_ci		    rsp_els->error_subcode_1, rsp_els->error_subcode_2);
1118c2ecf20Sopenharmony_ci	} else {
1128c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x028a,
1138c2ecf20Sopenharmony_ci		    "%s: abort exchange done.\n", __func__);
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	/* send ABTS response */
1178c2ecf20Sopenharmony_ci	abts_rsp = (void *)rsp_els;
1188c2ecf20Sopenharmony_ci	memset(abts_rsp, 0, sizeof(*abts_rsp));
1198c2ecf20Sopenharmony_ci	abts_rsp->entry_type = ABTS_RSP_TYPE;
1208c2ecf20Sopenharmony_ci	abts_rsp->entry_count = 1;
1218c2ecf20Sopenharmony_ci	abts_rsp->nport_handle = abts->nport_handle;
1228c2ecf20Sopenharmony_ci	abts_rsp->vp_idx = abts->vp_idx;
1238c2ecf20Sopenharmony_ci	abts_rsp->sof_type = abts->sof_type & 0xf0;
1248c2ecf20Sopenharmony_ci	abts_rsp->rx_xch_addr = abts->rx_xch_addr;
1258c2ecf20Sopenharmony_ci	abts_rsp->d_id[0] = abts->s_id[0];
1268c2ecf20Sopenharmony_ci	abts_rsp->d_id[1] = abts->s_id[1];
1278c2ecf20Sopenharmony_ci	abts_rsp->d_id[2] = abts->s_id[2];
1288c2ecf20Sopenharmony_ci	abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;
1298c2ecf20Sopenharmony_ci	abts_rsp->s_id[0] = abts->d_id[0];
1308c2ecf20Sopenharmony_ci	abts_rsp->s_id[1] = abts->d_id[1];
1318c2ecf20Sopenharmony_ci	abts_rsp->s_id[2] = abts->d_id[2];
1328c2ecf20Sopenharmony_ci	abts_rsp->cs_ctl = abts->cs_ctl;
1338c2ecf20Sopenharmony_ci	/* include flipping bit23 in fctl */
1348c2ecf20Sopenharmony_ci	fctl = ~(abts->f_ctl[2] | 0x7F) << 16 |
1358c2ecf20Sopenharmony_ci	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;
1368c2ecf20Sopenharmony_ci	abts_rsp->f_ctl[0] = fctl >> 0 & 0xff;
1378c2ecf20Sopenharmony_ci	abts_rsp->f_ctl[1] = fctl >> 8 & 0xff;
1388c2ecf20Sopenharmony_ci	abts_rsp->f_ctl[2] = fctl >> 16 & 0xff;
1398c2ecf20Sopenharmony_ci	abts_rsp->type = FC_TYPE_BLD;
1408c2ecf20Sopenharmony_ci	abts_rsp->rx_id = abts->rx_id;
1418c2ecf20Sopenharmony_ci	abts_rsp->ox_id = abts->ox_id;
1428c2ecf20Sopenharmony_ci	abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id;
1438c2ecf20Sopenharmony_ci	abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id;
1448c2ecf20Sopenharmony_ci	abts_rsp->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0);
1458c2ecf20Sopenharmony_ci	abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
1468c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x028b,
1478c2ecf20Sopenharmony_ci	    "Sending BA ACC response to ABTS %#x...\n",
1488c2ecf20Sopenharmony_ci	    abts->rx_xch_addr_to_abort);
1498c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
1508c2ecf20Sopenharmony_ci	    "-------- ELS RSP -------\n");
1518c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
1528c2ecf20Sopenharmony_ci	    (uint8_t *)abts_rsp, sizeof(*abts_rsp));
1538c2ecf20Sopenharmony_ci	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
1548c2ecf20Sopenharmony_ci	if (rval) {
1558c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x028c,
1568c2ecf20Sopenharmony_ci		    "%s: iocb failed to execute -> %x\n", __func__, rval);
1578c2ecf20Sopenharmony_ci	} else if (abts_rsp->comp_status) {
1588c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x028d,
1598c2ecf20Sopenharmony_ci		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
1608c2ecf20Sopenharmony_ci		    __func__, abts_rsp->comp_status,
1618c2ecf20Sopenharmony_ci		    abts_rsp->payload.error.subcode1,
1628c2ecf20Sopenharmony_ci		    abts_rsp->payload.error.subcode2);
1638c2ecf20Sopenharmony_ci	} else {
1648c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x028ea,
1658c2ecf20Sopenharmony_ci		    "%s: done.\n", __func__);
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/**
1728c2ecf20Sopenharmony_ci * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
1738c2ecf20Sopenharmony_ci * @irq: interrupt number
1748c2ecf20Sopenharmony_ci * @dev_id: SCSI driver HA context
1758c2ecf20Sopenharmony_ci *
1768c2ecf20Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * Returns handled flag.
1798c2ecf20Sopenharmony_ci */
1808c2ecf20Sopenharmony_ciirqreturn_t
1818c2ecf20Sopenharmony_ciqla2100_intr_handler(int irq, void *dev_id)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
1848c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
1858c2ecf20Sopenharmony_ci	struct device_reg_2xxx __iomem *reg;
1868c2ecf20Sopenharmony_ci	int		status;
1878c2ecf20Sopenharmony_ci	unsigned long	iter;
1888c2ecf20Sopenharmony_ci	uint16_t	hccr;
1898c2ecf20Sopenharmony_ci	uint16_t	mb[8];
1908c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
1918c2ecf20Sopenharmony_ci	unsigned long	flags;
1928c2ecf20Sopenharmony_ci
1938c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
1948c2ecf20Sopenharmony_ci	if (!rsp) {
1958c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505d,
1968c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
1978c2ecf20Sopenharmony_ci		return (IRQ_NONE);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	ha = rsp->hw;
2018c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp;
2028c2ecf20Sopenharmony_ci	status = 0;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
2058c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
2068c2ecf20Sopenharmony_ci	for (iter = 50; iter--; ) {
2078c2ecf20Sopenharmony_ci		hccr = rd_reg_word(&reg->hccr);
2088c2ecf20Sopenharmony_ci		if (qla2x00_check_reg16_for_disconnect(vha, hccr))
2098c2ecf20Sopenharmony_ci			break;
2108c2ecf20Sopenharmony_ci		if (hccr & HCCR_RISC_PAUSE) {
2118c2ecf20Sopenharmony_ci			if (pci_channel_offline(ha->pdev))
2128c2ecf20Sopenharmony_ci				break;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci			/*
2158c2ecf20Sopenharmony_ci			 * Issue a "HARD" reset in order for the RISC interrupt
2168c2ecf20Sopenharmony_ci			 * bit to be cleared.  Schedule a big hammer to get
2178c2ecf20Sopenharmony_ci			 * out of the RISC PAUSED state.
2188c2ecf20Sopenharmony_ci			 */
2198c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
2208c2ecf20Sopenharmony_ci			rd_reg_word(&reg->hccr);
2218c2ecf20Sopenharmony_ci
2228c2ecf20Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
2238c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2248c2ecf20Sopenharmony_ci			break;
2258c2ecf20Sopenharmony_ci		} else if ((rd_reg_word(&reg->istatus) & ISR_RISC_INT) == 0)
2268c2ecf20Sopenharmony_ci			break;
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci		if (rd_reg_word(&reg->semaphore) & BIT_0) {
2298c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
2308c2ecf20Sopenharmony_ci			rd_reg_word(&reg->hccr);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci			/* Get mailbox data. */
2338c2ecf20Sopenharmony_ci			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
2348c2ecf20Sopenharmony_ci			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
2358c2ecf20Sopenharmony_ci				qla2x00_mbx_completion(vha, mb[0]);
2368c2ecf20Sopenharmony_ci				status |= MBX_INTERRUPT;
2378c2ecf20Sopenharmony_ci			} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
2388c2ecf20Sopenharmony_ci				mb[1] = RD_MAILBOX_REG(ha, reg, 1);
2398c2ecf20Sopenharmony_ci				mb[2] = RD_MAILBOX_REG(ha, reg, 2);
2408c2ecf20Sopenharmony_ci				mb[3] = RD_MAILBOX_REG(ha, reg, 3);
2418c2ecf20Sopenharmony_ci				qla2x00_async_event(vha, rsp, mb);
2428c2ecf20Sopenharmony_ci			} else {
2438c2ecf20Sopenharmony_ci				/*EMPTY*/
2448c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5025,
2458c2ecf20Sopenharmony_ci				    "Unrecognized interrupt type (%d).\n",
2468c2ecf20Sopenharmony_ci				    mb[0]);
2478c2ecf20Sopenharmony_ci			}
2488c2ecf20Sopenharmony_ci			/* Release mailbox registers. */
2498c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->semaphore, 0);
2508c2ecf20Sopenharmony_ci			rd_reg_word(&reg->semaphore);
2518c2ecf20Sopenharmony_ci		} else {
2528c2ecf20Sopenharmony_ci			qla2x00_process_response_queue(rsp);
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
2558c2ecf20Sopenharmony_ci			rd_reg_word(&reg->hccr);
2568c2ecf20Sopenharmony_ci		}
2578c2ecf20Sopenharmony_ci	}
2588c2ecf20Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
2598c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	return (IRQ_HANDLED);
2628c2ecf20Sopenharmony_ci}
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_cibool
2658c2ecf20Sopenharmony_ciqla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
2668c2ecf20Sopenharmony_ci{
2678c2ecf20Sopenharmony_ci	/* Check for PCI disconnection */
2688c2ecf20Sopenharmony_ci	if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) {
2698c2ecf20Sopenharmony_ci		if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
2708c2ecf20Sopenharmony_ci		    !test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
2718c2ecf20Sopenharmony_ci		    !test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
2728c2ecf20Sopenharmony_ci			qla_schedule_eeh_work(vha);
2738c2ecf20Sopenharmony_ci		}
2748c2ecf20Sopenharmony_ci		return true;
2758c2ecf20Sopenharmony_ci	} else
2768c2ecf20Sopenharmony_ci		return false;
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_cibool
2808c2ecf20Sopenharmony_ciqla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
2818c2ecf20Sopenharmony_ci{
2828c2ecf20Sopenharmony_ci	return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg);
2838c2ecf20Sopenharmony_ci}
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci/**
2868c2ecf20Sopenharmony_ci * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
2878c2ecf20Sopenharmony_ci * @irq: interrupt number
2888c2ecf20Sopenharmony_ci * @dev_id: SCSI driver HA context
2898c2ecf20Sopenharmony_ci *
2908c2ecf20Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
2918c2ecf20Sopenharmony_ci *
2928c2ecf20Sopenharmony_ci * Returns handled flag.
2938c2ecf20Sopenharmony_ci */
2948c2ecf20Sopenharmony_ciirqreturn_t
2958c2ecf20Sopenharmony_ciqla2300_intr_handler(int irq, void *dev_id)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
2988c2ecf20Sopenharmony_ci	struct device_reg_2xxx __iomem *reg;
2998c2ecf20Sopenharmony_ci	int		status;
3008c2ecf20Sopenharmony_ci	unsigned long	iter;
3018c2ecf20Sopenharmony_ci	uint32_t	stat;
3028c2ecf20Sopenharmony_ci	uint16_t	hccr;
3038c2ecf20Sopenharmony_ci	uint16_t	mb[8];
3048c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
3058c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
3068c2ecf20Sopenharmony_ci	unsigned long	flags;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
3098c2ecf20Sopenharmony_ci	if (!rsp) {
3108c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x5058,
3118c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
3128c2ecf20Sopenharmony_ci		return (IRQ_NONE);
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	ha = rsp->hw;
3168c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp;
3178c2ecf20Sopenharmony_ci	status = 0;
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
3208c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
3218c2ecf20Sopenharmony_ci	for (iter = 50; iter--; ) {
3228c2ecf20Sopenharmony_ci		stat = rd_reg_dword(&reg->u.isp2300.host_status);
3238c2ecf20Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
3248c2ecf20Sopenharmony_ci			break;
3258c2ecf20Sopenharmony_ci		if (stat & HSR_RISC_PAUSED) {
3268c2ecf20Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
3278c2ecf20Sopenharmony_ci				break;
3288c2ecf20Sopenharmony_ci
3298c2ecf20Sopenharmony_ci			hccr = rd_reg_word(&reg->hccr);
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
3328c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5026,
3338c2ecf20Sopenharmony_ci				    "Parity error -- HCCR=%x, Dumping "
3348c2ecf20Sopenharmony_ci				    "firmware.\n", hccr);
3358c2ecf20Sopenharmony_ci			else
3368c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5027,
3378c2ecf20Sopenharmony_ci				    "RISC paused -- HCCR=%x, Dumping "
3388c2ecf20Sopenharmony_ci				    "firmware.\n", hccr);
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci			/*
3418c2ecf20Sopenharmony_ci			 * Issue a "HARD" reset in order for the RISC
3428c2ecf20Sopenharmony_ci			 * interrupt bit to be cleared.  Schedule a big
3438c2ecf20Sopenharmony_ci			 * hammer to get out of the RISC PAUSED state.
3448c2ecf20Sopenharmony_ci			 */
3458c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
3468c2ecf20Sopenharmony_ci			rd_reg_word(&reg->hccr);
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
3498c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3508c2ecf20Sopenharmony_ci			break;
3518c2ecf20Sopenharmony_ci		} else if ((stat & HSR_RISC_INT) == 0)
3528c2ecf20Sopenharmony_ci			break;
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_ci		switch (stat & 0xff) {
3558c2ecf20Sopenharmony_ci		case 0x1:
3568c2ecf20Sopenharmony_ci		case 0x2:
3578c2ecf20Sopenharmony_ci		case 0x10:
3588c2ecf20Sopenharmony_ci		case 0x11:
3598c2ecf20Sopenharmony_ci			qla2x00_mbx_completion(vha, MSW(stat));
3608c2ecf20Sopenharmony_ci			status |= MBX_INTERRUPT;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci			/* Release mailbox registers. */
3638c2ecf20Sopenharmony_ci			wrt_reg_word(&reg->semaphore, 0);
3648c2ecf20Sopenharmony_ci			break;
3658c2ecf20Sopenharmony_ci		case 0x12:
3668c2ecf20Sopenharmony_ci			mb[0] = MSW(stat);
3678c2ecf20Sopenharmony_ci			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
3688c2ecf20Sopenharmony_ci			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
3698c2ecf20Sopenharmony_ci			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
3708c2ecf20Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
3718c2ecf20Sopenharmony_ci			break;
3728c2ecf20Sopenharmony_ci		case 0x13:
3738c2ecf20Sopenharmony_ci			qla2x00_process_response_queue(rsp);
3748c2ecf20Sopenharmony_ci			break;
3758c2ecf20Sopenharmony_ci		case 0x15:
3768c2ecf20Sopenharmony_ci			mb[0] = MBA_CMPLT_1_16BIT;
3778c2ecf20Sopenharmony_ci			mb[1] = MSW(stat);
3788c2ecf20Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
3798c2ecf20Sopenharmony_ci			break;
3808c2ecf20Sopenharmony_ci		case 0x16:
3818c2ecf20Sopenharmony_ci			mb[0] = MBA_SCSI_COMPLETION;
3828c2ecf20Sopenharmony_ci			mb[1] = MSW(stat);
3838c2ecf20Sopenharmony_ci			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
3848c2ecf20Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
3858c2ecf20Sopenharmony_ci			break;
3868c2ecf20Sopenharmony_ci		default:
3878c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5028,
3888c2ecf20Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
3898c2ecf20Sopenharmony_ci			break;
3908c2ecf20Sopenharmony_ci		}
3918c2ecf20Sopenharmony_ci		wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
3928c2ecf20Sopenharmony_ci		rd_reg_word_relaxed(&reg->hccr);
3938c2ecf20Sopenharmony_ci	}
3948c2ecf20Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
3958c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
3968c2ecf20Sopenharmony_ci
3978c2ecf20Sopenharmony_ci	return (IRQ_HANDLED);
3988c2ecf20Sopenharmony_ci}
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci/**
4018c2ecf20Sopenharmony_ci * qla2x00_mbx_completion() - Process mailbox command completions.
4028c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
4038c2ecf20Sopenharmony_ci * @mb0: Mailbox0 register
4048c2ecf20Sopenharmony_ci */
4058c2ecf20Sopenharmony_cistatic void
4068c2ecf20Sopenharmony_ciqla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
4078c2ecf20Sopenharmony_ci{
4088c2ecf20Sopenharmony_ci	uint16_t	cnt;
4098c2ecf20Sopenharmony_ci	uint32_t	mboxes;
4108c2ecf20Sopenharmony_ci	__le16 __iomem *wptr;
4118c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
4128c2ecf20Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
4138c2ecf20Sopenharmony_ci
4148c2ecf20Sopenharmony_ci	/* Read all mbox registers? */
4158c2ecf20Sopenharmony_ci	WARN_ON_ONCE(ha->mbx_count > 32);
4168c2ecf20Sopenharmony_ci	mboxes = (1ULL << ha->mbx_count) - 1;
4178c2ecf20Sopenharmony_ci	if (!ha->mcp)
4188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
4198c2ecf20Sopenharmony_ci	else
4208c2ecf20Sopenharmony_ci		mboxes = ha->mcp->in_mb;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	/* Load return mailbox registers. */
4238c2ecf20Sopenharmony_ci	ha->flags.mbox_int = 1;
4248c2ecf20Sopenharmony_ci	ha->mailbox_out[0] = mb0;
4258c2ecf20Sopenharmony_ci	mboxes >>= 1;
4268c2ecf20Sopenharmony_ci	wptr = MAILBOX_REG(ha, reg, 1);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
4298c2ecf20Sopenharmony_ci		if (IS_QLA2200(ha) && cnt == 8)
4308c2ecf20Sopenharmony_ci			wptr = MAILBOX_REG(ha, reg, 8);
4318c2ecf20Sopenharmony_ci		if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
4328c2ecf20Sopenharmony_ci			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
4338c2ecf20Sopenharmony_ci		else if (mboxes & BIT_0)
4348c2ecf20Sopenharmony_ci			ha->mailbox_out[cnt] = rd_reg_word(wptr);
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci		wptr++;
4378c2ecf20Sopenharmony_ci		mboxes >>= 1;
4388c2ecf20Sopenharmony_ci	}
4398c2ecf20Sopenharmony_ci}
4408c2ecf20Sopenharmony_ci
4418c2ecf20Sopenharmony_cistatic void
4428c2ecf20Sopenharmony_ciqla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
4438c2ecf20Sopenharmony_ci{
4448c2ecf20Sopenharmony_ci	static char *event[] =
4458c2ecf20Sopenharmony_ci		{ "Complete", "Request Notification", "Time Extension" };
4468c2ecf20Sopenharmony_ci	int rval;
4478c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
4488c2ecf20Sopenharmony_ci	struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
4498c2ecf20Sopenharmony_ci	__le16 __iomem *wptr;
4508c2ecf20Sopenharmony_ci	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
4518c2ecf20Sopenharmony_ci
4528c2ecf20Sopenharmony_ci	/* Seed data -- mailbox1 -> mailbox7. */
4538c2ecf20Sopenharmony_ci	if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
4548c2ecf20Sopenharmony_ci		wptr = &reg24->mailbox1;
4558c2ecf20Sopenharmony_ci	else if (IS_QLA8044(vha->hw))
4568c2ecf20Sopenharmony_ci		wptr = &reg82->mailbox_out[1];
4578c2ecf20Sopenharmony_ci	else
4588c2ecf20Sopenharmony_ci		return;
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_ci	for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
4618c2ecf20Sopenharmony_ci		mb[cnt] = rd_reg_word(wptr);
4628c2ecf20Sopenharmony_ci
4638c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x5021,
4648c2ecf20Sopenharmony_ci	    "Inter-Driver Communication %s -- "
4658c2ecf20Sopenharmony_ci	    "%04x %04x %04x %04x %04x %04x %04x.\n",
4668c2ecf20Sopenharmony_ci	    event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
4678c2ecf20Sopenharmony_ci	    mb[4], mb[5], mb[6]);
4688c2ecf20Sopenharmony_ci	switch (aen) {
4698c2ecf20Sopenharmony_ci	/* Handle IDC Error completion case. */
4708c2ecf20Sopenharmony_ci	case MBA_IDC_COMPLETE:
4718c2ecf20Sopenharmony_ci		if (mb[1] >> 15) {
4728c2ecf20Sopenharmony_ci			vha->hw->flags.idc_compl_status = 1;
4738c2ecf20Sopenharmony_ci			if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
4748c2ecf20Sopenharmony_ci				complete(&vha->hw->dcbx_comp);
4758c2ecf20Sopenharmony_ci		}
4768c2ecf20Sopenharmony_ci		break;
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	case MBA_IDC_NOTIFY:
4798c2ecf20Sopenharmony_ci		/* Acknowledgement needed? [Notify && non-zero timeout]. */
4808c2ecf20Sopenharmony_ci		timeout = (descr >> 8) & 0xf;
4818c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5022,
4828c2ecf20Sopenharmony_ci		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
4838c2ecf20Sopenharmony_ci		    vha->host_no, event[aen & 0xff], timeout);
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_ci		if (!timeout)
4868c2ecf20Sopenharmony_ci			return;
4878c2ecf20Sopenharmony_ci		rval = qla2x00_post_idc_ack_work(vha, mb);
4888c2ecf20Sopenharmony_ci		if (rval != QLA_SUCCESS)
4898c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5023,
4908c2ecf20Sopenharmony_ci			    "IDC failed to post ACK.\n");
4918c2ecf20Sopenharmony_ci		break;
4928c2ecf20Sopenharmony_ci	case MBA_IDC_TIME_EXT:
4938c2ecf20Sopenharmony_ci		vha->hw->idc_extend_tmo = descr;
4948c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5087,
4958c2ecf20Sopenharmony_ci		    "%lu Inter-Driver Communication %s -- "
4968c2ecf20Sopenharmony_ci		    "Extend timeout by=%d.\n",
4978c2ecf20Sopenharmony_ci		    vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
4988c2ecf20Sopenharmony_ci		break;
4998c2ecf20Sopenharmony_ci	}
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci#define LS_UNKNOWN	2
5038c2ecf20Sopenharmony_ciconst char *
5048c2ecf20Sopenharmony_ciqla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
5058c2ecf20Sopenharmony_ci{
5068c2ecf20Sopenharmony_ci	static const char *const link_speeds[] = {
5078c2ecf20Sopenharmony_ci		"1", "2", "?", "4", "8", "16", "32", "10"
5088c2ecf20Sopenharmony_ci	};
5098c2ecf20Sopenharmony_ci#define	QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	if (IS_QLA2100(ha) || IS_QLA2200(ha))
5128c2ecf20Sopenharmony_ci		return link_speeds[0];
5138c2ecf20Sopenharmony_ci	else if (speed == 0x13)
5148c2ecf20Sopenharmony_ci		return link_speeds[QLA_LAST_SPEED];
5158c2ecf20Sopenharmony_ci	else if (speed < QLA_LAST_SPEED)
5168c2ecf20Sopenharmony_ci		return link_speeds[speed];
5178c2ecf20Sopenharmony_ci	else
5188c2ecf20Sopenharmony_ci		return link_speeds[LS_UNKNOWN];
5198c2ecf20Sopenharmony_ci}
5208c2ecf20Sopenharmony_ci
5218c2ecf20Sopenharmony_cistatic void
5228c2ecf20Sopenharmony_ciqla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
5238c2ecf20Sopenharmony_ci{
5248c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5258c2ecf20Sopenharmony_ci
5268c2ecf20Sopenharmony_ci	/*
5278c2ecf20Sopenharmony_ci	 * 8200 AEN Interpretation:
5288c2ecf20Sopenharmony_ci	 * mb[0] = AEN code
5298c2ecf20Sopenharmony_ci	 * mb[1] = AEN Reason code
5308c2ecf20Sopenharmony_ci	 * mb[2] = LSW of Peg-Halt Status-1 Register
5318c2ecf20Sopenharmony_ci	 * mb[6] = MSW of Peg-Halt Status-1 Register
5328c2ecf20Sopenharmony_ci	 * mb[3] = LSW of Peg-Halt Status-2 register
5338c2ecf20Sopenharmony_ci	 * mb[7] = MSW of Peg-Halt Status-2 register
5348c2ecf20Sopenharmony_ci	 * mb[4] = IDC Device-State Register value
5358c2ecf20Sopenharmony_ci	 * mb[5] = IDC Driver-Presence Register value
5368c2ecf20Sopenharmony_ci	 */
5378c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
5388c2ecf20Sopenharmony_ci	    "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
5398c2ecf20Sopenharmony_ci	    mb[0], mb[1], mb[2], mb[6]);
5408c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
5418c2ecf20Sopenharmony_ci	    "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
5428c2ecf20Sopenharmony_ci	    "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
5458c2ecf20Sopenharmony_ci				IDC_HEARTBEAT_FAILURE)) {
5468c2ecf20Sopenharmony_ci		ha->flags.nic_core_hung = 1;
5478c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5060,
5488c2ecf20Sopenharmony_ci		    "83XX: F/W Error Reported: Check if reset required.\n");
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
5518c2ecf20Sopenharmony_ci			uint32_t protocol_engine_id, fw_err_code, err_level;
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci			/*
5548c2ecf20Sopenharmony_ci			 * IDC_PEG_HALT_STATUS_CHANGE interpretation:
5558c2ecf20Sopenharmony_ci			 *  - PEG-Halt Status-1 Register:
5568c2ecf20Sopenharmony_ci			 *	(LSW = mb[2], MSW = mb[6])
5578c2ecf20Sopenharmony_ci			 *	Bits 0-7   = protocol-engine ID
5588c2ecf20Sopenharmony_ci			 *	Bits 8-28  = f/w error code
5598c2ecf20Sopenharmony_ci			 *	Bits 29-31 = Error-level
5608c2ecf20Sopenharmony_ci			 *	    Error-level 0x1 = Non-Fatal error
5618c2ecf20Sopenharmony_ci			 *	    Error-level 0x2 = Recoverable Fatal error
5628c2ecf20Sopenharmony_ci			 *	    Error-level 0x4 = UnRecoverable Fatal error
5638c2ecf20Sopenharmony_ci			 *  - PEG-Halt Status-2 Register:
5648c2ecf20Sopenharmony_ci			 *	(LSW = mb[3], MSW = mb[7])
5658c2ecf20Sopenharmony_ci			 */
5668c2ecf20Sopenharmony_ci			protocol_engine_id = (mb[2] & 0xff);
5678c2ecf20Sopenharmony_ci			fw_err_code = (((mb[2] & 0xff00) >> 8) |
5688c2ecf20Sopenharmony_ci			    ((mb[6] & 0x1fff) << 8));
5698c2ecf20Sopenharmony_ci			err_level = ((mb[6] & 0xe000) >> 13);
5708c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
5718c2ecf20Sopenharmony_ci			    "Register: protocol_engine_id=0x%x "
5728c2ecf20Sopenharmony_ci			    "fw_err_code=0x%x err_level=0x%x.\n",
5738c2ecf20Sopenharmony_ci			    protocol_engine_id, fw_err_code, err_level);
5748c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
5758c2ecf20Sopenharmony_ci			    "Register: 0x%x%x.\n", mb[7], mb[3]);
5768c2ecf20Sopenharmony_ci			if (err_level == ERR_LEVEL_NON_FATAL) {
5778c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5063,
5788c2ecf20Sopenharmony_ci				    "Not a fatal error, f/w has recovered itself.\n");
5798c2ecf20Sopenharmony_ci			} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
5808c2ecf20Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5064,
5818c2ecf20Sopenharmony_ci				    "Recoverable Fatal error: Chip reset "
5828c2ecf20Sopenharmony_ci				    "required.\n");
5838c2ecf20Sopenharmony_ci				qla83xx_schedule_work(vha,
5848c2ecf20Sopenharmony_ci				    QLA83XX_NIC_CORE_RESET);
5858c2ecf20Sopenharmony_ci			} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
5868c2ecf20Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5065,
5878c2ecf20Sopenharmony_ci				    "Unrecoverable Fatal error: Set FAILED "
5888c2ecf20Sopenharmony_ci				    "state, reboot required.\n");
5898c2ecf20Sopenharmony_ci				qla83xx_schedule_work(vha,
5908c2ecf20Sopenharmony_ci				    QLA83XX_NIC_CORE_UNRECOVERABLE);
5918c2ecf20Sopenharmony_ci			}
5928c2ecf20Sopenharmony_ci		}
5938c2ecf20Sopenharmony_ci
5948c2ecf20Sopenharmony_ci		if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
5958c2ecf20Sopenharmony_ci			uint16_t peg_fw_state, nw_interface_link_up;
5968c2ecf20Sopenharmony_ci			uint16_t nw_interface_signal_detect, sfp_status;
5978c2ecf20Sopenharmony_ci			uint16_t htbt_counter, htbt_monitor_enable;
5988c2ecf20Sopenharmony_ci			uint16_t sfp_additional_info, sfp_multirate;
5998c2ecf20Sopenharmony_ci			uint16_t sfp_tx_fault, link_speed, dcbx_status;
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci			/*
6028c2ecf20Sopenharmony_ci			 * IDC_NIC_FW_REPORTED_FAILURE interpretation:
6038c2ecf20Sopenharmony_ci			 *  - PEG-to-FC Status Register:
6048c2ecf20Sopenharmony_ci			 *	(LSW = mb[2], MSW = mb[6])
6058c2ecf20Sopenharmony_ci			 *	Bits 0-7   = Peg-Firmware state
6068c2ecf20Sopenharmony_ci			 *	Bit 8      = N/W Interface Link-up
6078c2ecf20Sopenharmony_ci			 *	Bit 9      = N/W Interface signal detected
6088c2ecf20Sopenharmony_ci			 *	Bits 10-11 = SFP Status
6098c2ecf20Sopenharmony_ci			 *	  SFP Status 0x0 = SFP+ transceiver not expected
6108c2ecf20Sopenharmony_ci			 *	  SFP Status 0x1 = SFP+ transceiver not present
6118c2ecf20Sopenharmony_ci			 *	  SFP Status 0x2 = SFP+ transceiver invalid
6128c2ecf20Sopenharmony_ci			 *	  SFP Status 0x3 = SFP+ transceiver present and
6138c2ecf20Sopenharmony_ci			 *	  valid
6148c2ecf20Sopenharmony_ci			 *	Bits 12-14 = Heartbeat Counter
6158c2ecf20Sopenharmony_ci			 *	Bit 15     = Heartbeat Monitor Enable
6168c2ecf20Sopenharmony_ci			 *	Bits 16-17 = SFP Additional Info
6178c2ecf20Sopenharmony_ci			 *	  SFP info 0x0 = Unregocnized transceiver for
6188c2ecf20Sopenharmony_ci			 *	  Ethernet
6198c2ecf20Sopenharmony_ci			 *	  SFP info 0x1 = SFP+ brand validation failed
6208c2ecf20Sopenharmony_ci			 *	  SFP info 0x2 = SFP+ speed validation failed
6218c2ecf20Sopenharmony_ci			 *	  SFP info 0x3 = SFP+ access error
6228c2ecf20Sopenharmony_ci			 *	Bit 18     = SFP Multirate
6238c2ecf20Sopenharmony_ci			 *	Bit 19     = SFP Tx Fault
6248c2ecf20Sopenharmony_ci			 *	Bits 20-22 = Link Speed
6258c2ecf20Sopenharmony_ci			 *	Bits 23-27 = Reserved
6268c2ecf20Sopenharmony_ci			 *	Bits 28-30 = DCBX Status
6278c2ecf20Sopenharmony_ci			 *	  DCBX Status 0x0 = DCBX Disabled
6288c2ecf20Sopenharmony_ci			 *	  DCBX Status 0x1 = DCBX Enabled
6298c2ecf20Sopenharmony_ci			 *	  DCBX Status 0x2 = DCBX Exchange error
6308c2ecf20Sopenharmony_ci			 *	Bit 31     = Reserved
6318c2ecf20Sopenharmony_ci			 */
6328c2ecf20Sopenharmony_ci			peg_fw_state = (mb[2] & 0x00ff);
6338c2ecf20Sopenharmony_ci			nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
6348c2ecf20Sopenharmony_ci			nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
6358c2ecf20Sopenharmony_ci			sfp_status = ((mb[2] & 0x0c00) >> 10);
6368c2ecf20Sopenharmony_ci			htbt_counter = ((mb[2] & 0x7000) >> 12);
6378c2ecf20Sopenharmony_ci			htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
6388c2ecf20Sopenharmony_ci			sfp_additional_info = (mb[6] & 0x0003);
6398c2ecf20Sopenharmony_ci			sfp_multirate = ((mb[6] & 0x0004) >> 2);
6408c2ecf20Sopenharmony_ci			sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
6418c2ecf20Sopenharmony_ci			link_speed = ((mb[6] & 0x0070) >> 4);
6428c2ecf20Sopenharmony_ci			dcbx_status = ((mb[6] & 0x7000) >> 12);
6438c2ecf20Sopenharmony_ci
6448c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5066,
6458c2ecf20Sopenharmony_ci			    "Peg-to-Fc Status Register:\n"
6468c2ecf20Sopenharmony_ci			    "peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
6478c2ecf20Sopenharmony_ci			    "nw_interface_signal_detect=0x%x"
6488c2ecf20Sopenharmony_ci			    "\nsfp_statis=0x%x.\n ", peg_fw_state,
6498c2ecf20Sopenharmony_ci			    nw_interface_link_up, nw_interface_signal_detect,
6508c2ecf20Sopenharmony_ci			    sfp_status);
6518c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5067,
6528c2ecf20Sopenharmony_ci			    "htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
6538c2ecf20Sopenharmony_ci			    "sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ",
6548c2ecf20Sopenharmony_ci			    htbt_counter, htbt_monitor_enable,
6558c2ecf20Sopenharmony_ci			    sfp_additional_info, sfp_multirate);
6568c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5068,
6578c2ecf20Sopenharmony_ci			    "sfp_tx_fault=0x%x, link_state=0x%x, "
6588c2ecf20Sopenharmony_ci			    "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
6598c2ecf20Sopenharmony_ci			    dcbx_status);
6608c2ecf20Sopenharmony_ci
6618c2ecf20Sopenharmony_ci			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
6628c2ecf20Sopenharmony_ci		}
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		if (mb[1] & IDC_HEARTBEAT_FAILURE) {
6658c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5069,
6668c2ecf20Sopenharmony_ci			    "Heartbeat Failure encountered, chip reset "
6678c2ecf20Sopenharmony_ci			    "required.\n");
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
6708c2ecf20Sopenharmony_ci		}
6718c2ecf20Sopenharmony_ci	}
6728c2ecf20Sopenharmony_ci
6738c2ecf20Sopenharmony_ci	if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
6748c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x506a,
6758c2ecf20Sopenharmony_ci		    "IDC Device-State changed = 0x%x.\n", mb[4]);
6768c2ecf20Sopenharmony_ci		if (ha->flags.nic_core_reset_owner)
6778c2ecf20Sopenharmony_ci			return;
6788c2ecf20Sopenharmony_ci		qla83xx_schedule_work(vha, MBA_IDC_AEN);
6798c2ecf20Sopenharmony_ci	}
6808c2ecf20Sopenharmony_ci}
6818c2ecf20Sopenharmony_ci
6828c2ecf20Sopenharmony_ciint
6838c2ecf20Sopenharmony_ciqla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
6848c2ecf20Sopenharmony_ci{
6858c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6868c2ecf20Sopenharmony_ci	scsi_qla_host_t *vp;
6878c2ecf20Sopenharmony_ci	uint32_t vp_did;
6888c2ecf20Sopenharmony_ci	unsigned long flags;
6898c2ecf20Sopenharmony_ci	int ret = 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	if (!ha->num_vhosts)
6928c2ecf20Sopenharmony_ci		return ret;
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->vport_slock, flags);
6958c2ecf20Sopenharmony_ci	list_for_each_entry(vp, &ha->vp_list, list) {
6968c2ecf20Sopenharmony_ci		vp_did = vp->d_id.b24;
6978c2ecf20Sopenharmony_ci		if (vp_did == rscn_entry) {
6988c2ecf20Sopenharmony_ci			ret = 1;
6998c2ecf20Sopenharmony_ci			break;
7008c2ecf20Sopenharmony_ci		}
7018c2ecf20Sopenharmony_ci	}
7028c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->vport_slock, flags);
7038c2ecf20Sopenharmony_ci
7048c2ecf20Sopenharmony_ci	return ret;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_cifc_port_t *
7088c2ecf20Sopenharmony_ciqla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id)
7098c2ecf20Sopenharmony_ci{
7108c2ecf20Sopenharmony_ci	fc_port_t *f, *tf;
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	f = tf = NULL;
7138c2ecf20Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list)
7148c2ecf20Sopenharmony_ci		if (f->loop_id == loop_id)
7158c2ecf20Sopenharmony_ci			return f;
7168c2ecf20Sopenharmony_ci	return NULL;
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cifc_port_t *
7208c2ecf20Sopenharmony_ciqla2x00_find_fcport_by_wwpn(scsi_qla_host_t *vha, u8 *wwpn, u8 incl_deleted)
7218c2ecf20Sopenharmony_ci{
7228c2ecf20Sopenharmony_ci	fc_port_t *f, *tf;
7238c2ecf20Sopenharmony_ci
7248c2ecf20Sopenharmony_ci	f = tf = NULL;
7258c2ecf20Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
7268c2ecf20Sopenharmony_ci		if (memcmp(f->port_name, wwpn, WWN_SIZE) == 0) {
7278c2ecf20Sopenharmony_ci			if (incl_deleted)
7288c2ecf20Sopenharmony_ci				return f;
7298c2ecf20Sopenharmony_ci			else if (f->deleted == 0)
7308c2ecf20Sopenharmony_ci				return f;
7318c2ecf20Sopenharmony_ci		}
7328c2ecf20Sopenharmony_ci	}
7338c2ecf20Sopenharmony_ci	return NULL;
7348c2ecf20Sopenharmony_ci}
7358c2ecf20Sopenharmony_ci
7368c2ecf20Sopenharmony_cifc_port_t *
7378c2ecf20Sopenharmony_ciqla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id,
7388c2ecf20Sopenharmony_ci	u8 incl_deleted)
7398c2ecf20Sopenharmony_ci{
7408c2ecf20Sopenharmony_ci	fc_port_t *f, *tf;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	f = tf = NULL;
7438c2ecf20Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
7448c2ecf20Sopenharmony_ci		if (f->d_id.b24 == id->b24) {
7458c2ecf20Sopenharmony_ci			if (incl_deleted)
7468c2ecf20Sopenharmony_ci				return f;
7478c2ecf20Sopenharmony_ci			else if (f->deleted == 0)
7488c2ecf20Sopenharmony_ci				return f;
7498c2ecf20Sopenharmony_ci		}
7508c2ecf20Sopenharmony_ci	}
7518c2ecf20Sopenharmony_ci	return NULL;
7528c2ecf20Sopenharmony_ci}
7538c2ecf20Sopenharmony_ci
7548c2ecf20Sopenharmony_ci/* Shall be called only on supported adapters. */
7558c2ecf20Sopenharmony_cistatic void
7568c2ecf20Sopenharmony_ciqla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
7578c2ecf20Sopenharmony_ci{
7588c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
7598c2ecf20Sopenharmony_ci	bool reset_isp_needed = 0;
7608c2ecf20Sopenharmony_ci
7618c2ecf20Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x02f0,
7628c2ecf20Sopenharmony_ci	       "MPI Heartbeat stop. MPI reset is%s needed. "
7638c2ecf20Sopenharmony_ci	       "MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n",
7648c2ecf20Sopenharmony_ci	       mb[1] & BIT_8 ? "" : " not",
7658c2ecf20Sopenharmony_ci	       mb[0], mb[1], mb[2], mb[3]);
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_ci	if ((mb[1] & BIT_8) == 0)
7688c2ecf20Sopenharmony_ci		return;
7698c2ecf20Sopenharmony_ci
7708c2ecf20Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x02f1,
7718c2ecf20Sopenharmony_ci	       "MPI Heartbeat stop. FW dump needed\n");
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	if (ql2xfulldump_on_mpifail) {
7748c2ecf20Sopenharmony_ci		ha->isp_ops->fw_dump(vha);
7758c2ecf20Sopenharmony_ci		reset_isp_needed = 1;
7768c2ecf20Sopenharmony_ci	}
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	ha->isp_ops->mpi_fw_dump(vha, 1);
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_ci	if (reset_isp_needed) {
7818c2ecf20Sopenharmony_ci		vha->hw->flags.fw_init_done = 0;
7828c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
7838c2ecf20Sopenharmony_ci		qla2xxx_wake_dpc(vha);
7848c2ecf20Sopenharmony_ci	}
7858c2ecf20Sopenharmony_ci}
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_cistatic struct purex_item *
7888c2ecf20Sopenharmony_ciqla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
7898c2ecf20Sopenharmony_ci{
7908c2ecf20Sopenharmony_ci	struct purex_item *item = NULL;
7918c2ecf20Sopenharmony_ci	uint8_t item_hdr_size = sizeof(*item);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
7948c2ecf20Sopenharmony_ci		item = kzalloc(item_hdr_size +
7958c2ecf20Sopenharmony_ci		    (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
7968c2ecf20Sopenharmony_ci	} else {
7978c2ecf20Sopenharmony_ci		if (atomic_inc_return(&vha->default_item.in_use) == 1) {
7988c2ecf20Sopenharmony_ci			item = &vha->default_item;
7998c2ecf20Sopenharmony_ci			goto initialize_purex_header;
8008c2ecf20Sopenharmony_ci		} else {
8018c2ecf20Sopenharmony_ci			item = kzalloc(item_hdr_size, GFP_ATOMIC);
8028c2ecf20Sopenharmony_ci		}
8038c2ecf20Sopenharmony_ci	}
8048c2ecf20Sopenharmony_ci	if (!item) {
8058c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5092,
8068c2ecf20Sopenharmony_ci		       ">> Failed allocate purex list item.\n");
8078c2ecf20Sopenharmony_ci
8088c2ecf20Sopenharmony_ci		return NULL;
8098c2ecf20Sopenharmony_ci	}
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_ciinitialize_purex_header:
8128c2ecf20Sopenharmony_ci	item->vha = vha;
8138c2ecf20Sopenharmony_ci	item->size = size;
8148c2ecf20Sopenharmony_ci	return item;
8158c2ecf20Sopenharmony_ci}
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_cistatic void
8188c2ecf20Sopenharmony_ciqla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
8198c2ecf20Sopenharmony_ci			 void (*process_item)(struct scsi_qla_host *vha,
8208c2ecf20Sopenharmony_ci					      struct purex_item *pkt))
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct purex_list *list = &vha->purex_list;
8238c2ecf20Sopenharmony_ci	ulong flags;
8248c2ecf20Sopenharmony_ci
8258c2ecf20Sopenharmony_ci	pkt->process_item = process_item;
8268c2ecf20Sopenharmony_ci
8278c2ecf20Sopenharmony_ci	spin_lock_irqsave(&list->lock, flags);
8288c2ecf20Sopenharmony_ci	list_add_tail(&pkt->list, &list->head);
8298c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&list->lock, flags);
8308c2ecf20Sopenharmony_ci
8318c2ecf20Sopenharmony_ci	set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci/**
8358c2ecf20Sopenharmony_ci * qla24xx_copy_std_pkt() - Copy over purex ELS which is
8368c2ecf20Sopenharmony_ci * contained in a single IOCB.
8378c2ecf20Sopenharmony_ci * purex packet.
8388c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
8398c2ecf20Sopenharmony_ci * @pkt: ELS packet
8408c2ecf20Sopenharmony_ci */
8418c2ecf20Sopenharmony_cistatic struct purex_item
8428c2ecf20Sopenharmony_ci*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
8438c2ecf20Sopenharmony_ci{
8448c2ecf20Sopenharmony_ci	struct purex_item *item;
8458c2ecf20Sopenharmony_ci
8468c2ecf20Sopenharmony_ci	item = qla24xx_alloc_purex_item(vha,
8478c2ecf20Sopenharmony_ci					QLA_DEFAULT_PAYLOAD_SIZE);
8488c2ecf20Sopenharmony_ci	if (!item)
8498c2ecf20Sopenharmony_ci		return item;
8508c2ecf20Sopenharmony_ci
8518c2ecf20Sopenharmony_ci	memcpy(&item->iocb, pkt, sizeof(item->iocb));
8528c2ecf20Sopenharmony_ci	return item;
8538c2ecf20Sopenharmony_ci}
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci/**
8568c2ecf20Sopenharmony_ci * qla27xx_copy_fpin_pkt() - Copy over fpin packets that can
8578c2ecf20Sopenharmony_ci * span over multiple IOCBs.
8588c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
8598c2ecf20Sopenharmony_ci * @pkt: ELS packet
8608c2ecf20Sopenharmony_ci * @rsp: Response queue
8618c2ecf20Sopenharmony_ci */
8628c2ecf20Sopenharmony_cistatic struct purex_item *
8638c2ecf20Sopenharmony_ciqla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
8648c2ecf20Sopenharmony_ci		      struct rsp_que **rsp)
8658c2ecf20Sopenharmony_ci{
8668c2ecf20Sopenharmony_ci	struct purex_entry_24xx *purex = *pkt;
8678c2ecf20Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
8688c2ecf20Sopenharmony_ci	sts_cont_entry_t *new_pkt;
8698c2ecf20Sopenharmony_ci	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
8708c2ecf20Sopenharmony_ci	uint16_t buffer_copy_offset = 0;
8718c2ecf20Sopenharmony_ci	uint16_t entry_count, entry_count_remaining;
8728c2ecf20Sopenharmony_ci	struct purex_item *item;
8738c2ecf20Sopenharmony_ci	void *fpin_pkt = NULL;
8748c2ecf20Sopenharmony_ci
8758c2ecf20Sopenharmony_ci	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
8768c2ecf20Sopenharmony_ci	    - PURX_ELS_HEADER_SIZE;
8778c2ecf20Sopenharmony_ci	pending_bytes = total_bytes;
8788c2ecf20Sopenharmony_ci	entry_count = entry_count_remaining = purex->entry_count;
8798c2ecf20Sopenharmony_ci	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
8808c2ecf20Sopenharmony_ci		   sizeof(purex->els_frame_payload) : pending_bytes;
8818c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x509a,
8828c2ecf20Sopenharmony_ci	       "FPIN ELS, frame_size 0x%x, entry count %d\n",
8838c2ecf20Sopenharmony_ci	       total_bytes, entry_count);
8848c2ecf20Sopenharmony_ci
8858c2ecf20Sopenharmony_ci	item = qla24xx_alloc_purex_item(vha, total_bytes);
8868c2ecf20Sopenharmony_ci	if (!item)
8878c2ecf20Sopenharmony_ci		return item;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	fpin_pkt = &item->iocb;
8908c2ecf20Sopenharmony_ci
8918c2ecf20Sopenharmony_ci	memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
8928c2ecf20Sopenharmony_ci	buffer_copy_offset += no_bytes;
8938c2ecf20Sopenharmony_ci	pending_bytes -= no_bytes;
8948c2ecf20Sopenharmony_ci	--entry_count_remaining;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	((response_t *)purex)->signature = RESPONSE_PROCESSED;
8978c2ecf20Sopenharmony_ci	wmb();
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	do {
9008c2ecf20Sopenharmony_ci		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
9018c2ecf20Sopenharmony_ci			if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
9028c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5084,
9038c2ecf20Sopenharmony_ci				       "Ran out of IOCBs, partial data 0x%x\n",
9048c2ecf20Sopenharmony_ci				       buffer_copy_offset);
9058c2ecf20Sopenharmony_ci				cpu_relax();
9068c2ecf20Sopenharmony_ci				continue;
9078c2ecf20Sopenharmony_ci			}
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
9108c2ecf20Sopenharmony_ci			*pkt = new_pkt;
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_ci			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
9138c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x507a,
9148c2ecf20Sopenharmony_ci				       "Unexpected IOCB type, partial data 0x%x\n",
9158c2ecf20Sopenharmony_ci				       buffer_copy_offset);
9168c2ecf20Sopenharmony_ci				break;
9178c2ecf20Sopenharmony_ci			}
9188c2ecf20Sopenharmony_ci
9198c2ecf20Sopenharmony_ci			rsp_q->ring_index++;
9208c2ecf20Sopenharmony_ci			if (rsp_q->ring_index == rsp_q->length) {
9218c2ecf20Sopenharmony_ci				rsp_q->ring_index = 0;
9228c2ecf20Sopenharmony_ci				rsp_q->ring_ptr = rsp_q->ring;
9238c2ecf20Sopenharmony_ci			} else {
9248c2ecf20Sopenharmony_ci				rsp_q->ring_ptr++;
9258c2ecf20Sopenharmony_ci			}
9268c2ecf20Sopenharmony_ci			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
9278c2ecf20Sopenharmony_ci			    sizeof(new_pkt->data) : pending_bytes;
9288c2ecf20Sopenharmony_ci			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
9298c2ecf20Sopenharmony_ci				memcpy(((uint8_t *)fpin_pkt +
9308c2ecf20Sopenharmony_ci				    buffer_copy_offset), new_pkt->data,
9318c2ecf20Sopenharmony_ci				    no_bytes);
9328c2ecf20Sopenharmony_ci				buffer_copy_offset += no_bytes;
9338c2ecf20Sopenharmony_ci				pending_bytes -= no_bytes;
9348c2ecf20Sopenharmony_ci				--entry_count_remaining;
9358c2ecf20Sopenharmony_ci			} else {
9368c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5044,
9378c2ecf20Sopenharmony_ci				       "Attempt to copy more that we got, optimizing..%x\n",
9388c2ecf20Sopenharmony_ci				       buffer_copy_offset);
9398c2ecf20Sopenharmony_ci				memcpy(((uint8_t *)fpin_pkt +
9408c2ecf20Sopenharmony_ci				    buffer_copy_offset), new_pkt->data,
9418c2ecf20Sopenharmony_ci				    total_bytes - buffer_copy_offset);
9428c2ecf20Sopenharmony_ci			}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ci			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
9458c2ecf20Sopenharmony_ci			wmb();
9468c2ecf20Sopenharmony_ci		}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_ci		if (pending_bytes != 0 || entry_count_remaining != 0) {
9498c2ecf20Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x508b,
9508c2ecf20Sopenharmony_ci			       "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
9518c2ecf20Sopenharmony_ci			       total_bytes, entry_count_remaining);
9528c2ecf20Sopenharmony_ci			qla24xx_free_purex_item(item);
9538c2ecf20Sopenharmony_ci			return NULL;
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci	} while (entry_count_remaining > 0);
9568c2ecf20Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
9578c2ecf20Sopenharmony_ci	return item;
9588c2ecf20Sopenharmony_ci}
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci/**
9618c2ecf20Sopenharmony_ci * qla2x00_async_event() - Process aynchronous events.
9628c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
9638c2ecf20Sopenharmony_ci * @rsp: response queue
9648c2ecf20Sopenharmony_ci * @mb: Mailbox registers (0 - 3)
9658c2ecf20Sopenharmony_ci */
9668c2ecf20Sopenharmony_civoid
9678c2ecf20Sopenharmony_ciqla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
9688c2ecf20Sopenharmony_ci{
9698c2ecf20Sopenharmony_ci	uint16_t	handle_cnt;
9708c2ecf20Sopenharmony_ci	uint16_t	cnt, mbx;
9718c2ecf20Sopenharmony_ci	uint32_t	handles[5];
9728c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
9738c2ecf20Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
9748c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
9758c2ecf20Sopenharmony_ci	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
9768c2ecf20Sopenharmony_ci	uint32_t	rscn_entry, host_pid;
9778c2ecf20Sopenharmony_ci	unsigned long	flags;
9788c2ecf20Sopenharmony_ci	fc_port_t	*fcport = NULL;
9798c2ecf20Sopenharmony_ci
9808c2ecf20Sopenharmony_ci	if (!vha->hw->flags.fw_started) {
9818c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x50ff,
9828c2ecf20Sopenharmony_ci		    "Dropping AEN - %04x %04x %04x %04x.\n",
9838c2ecf20Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
9848c2ecf20Sopenharmony_ci		return;
9858c2ecf20Sopenharmony_ci	}
9868c2ecf20Sopenharmony_ci
9878c2ecf20Sopenharmony_ci	/* Setup to process RIO completion. */
9888c2ecf20Sopenharmony_ci	handle_cnt = 0;
9898c2ecf20Sopenharmony_ci	if (IS_CNA_CAPABLE(ha))
9908c2ecf20Sopenharmony_ci		goto skip_rio;
9918c2ecf20Sopenharmony_ci	switch (mb[0]) {
9928c2ecf20Sopenharmony_ci	case MBA_SCSI_COMPLETION:
9938c2ecf20Sopenharmony_ci		handles[0] = make_handle(mb[2], mb[1]);
9948c2ecf20Sopenharmony_ci		handle_cnt = 1;
9958c2ecf20Sopenharmony_ci		break;
9968c2ecf20Sopenharmony_ci	case MBA_CMPLT_1_16BIT:
9978c2ecf20Sopenharmony_ci		handles[0] = mb[1];
9988c2ecf20Sopenharmony_ci		handle_cnt = 1;
9998c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10008c2ecf20Sopenharmony_ci		break;
10018c2ecf20Sopenharmony_ci	case MBA_CMPLT_2_16BIT:
10028c2ecf20Sopenharmony_ci		handles[0] = mb[1];
10038c2ecf20Sopenharmony_ci		handles[1] = mb[2];
10048c2ecf20Sopenharmony_ci		handle_cnt = 2;
10058c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10068c2ecf20Sopenharmony_ci		break;
10078c2ecf20Sopenharmony_ci	case MBA_CMPLT_3_16BIT:
10088c2ecf20Sopenharmony_ci		handles[0] = mb[1];
10098c2ecf20Sopenharmony_ci		handles[1] = mb[2];
10108c2ecf20Sopenharmony_ci		handles[2] = mb[3];
10118c2ecf20Sopenharmony_ci		handle_cnt = 3;
10128c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10138c2ecf20Sopenharmony_ci		break;
10148c2ecf20Sopenharmony_ci	case MBA_CMPLT_4_16BIT:
10158c2ecf20Sopenharmony_ci		handles[0] = mb[1];
10168c2ecf20Sopenharmony_ci		handles[1] = mb[2];
10178c2ecf20Sopenharmony_ci		handles[2] = mb[3];
10188c2ecf20Sopenharmony_ci		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
10198c2ecf20Sopenharmony_ci		handle_cnt = 4;
10208c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10218c2ecf20Sopenharmony_ci		break;
10228c2ecf20Sopenharmony_ci	case MBA_CMPLT_5_16BIT:
10238c2ecf20Sopenharmony_ci		handles[0] = mb[1];
10248c2ecf20Sopenharmony_ci		handles[1] = mb[2];
10258c2ecf20Sopenharmony_ci		handles[2] = mb[3];
10268c2ecf20Sopenharmony_ci		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
10278c2ecf20Sopenharmony_ci		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
10288c2ecf20Sopenharmony_ci		handle_cnt = 5;
10298c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10308c2ecf20Sopenharmony_ci		break;
10318c2ecf20Sopenharmony_ci	case MBA_CMPLT_2_32BIT:
10328c2ecf20Sopenharmony_ci		handles[0] = make_handle(mb[2], mb[1]);
10338c2ecf20Sopenharmony_ci		handles[1] = make_handle(RD_MAILBOX_REG(ha, reg, 7),
10348c2ecf20Sopenharmony_ci					 RD_MAILBOX_REG(ha, reg, 6));
10358c2ecf20Sopenharmony_ci		handle_cnt = 2;
10368c2ecf20Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
10378c2ecf20Sopenharmony_ci		break;
10388c2ecf20Sopenharmony_ci	default:
10398c2ecf20Sopenharmony_ci		break;
10408c2ecf20Sopenharmony_ci	}
10418c2ecf20Sopenharmony_ciskip_rio:
10428c2ecf20Sopenharmony_ci	switch (mb[0]) {
10438c2ecf20Sopenharmony_ci	case MBA_SCSI_COMPLETION:	/* Fast Post */
10448c2ecf20Sopenharmony_ci		if (!vha->flags.online)
10458c2ecf20Sopenharmony_ci			break;
10468c2ecf20Sopenharmony_ci
10478c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
10488c2ecf20Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
10498c2ecf20Sopenharmony_ci				handles[cnt]);
10508c2ecf20Sopenharmony_ci		break;
10518c2ecf20Sopenharmony_ci
10528c2ecf20Sopenharmony_ci	case MBA_RESET:			/* Reset */
10538c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5002,
10548c2ecf20Sopenharmony_ci		    "Asynchronous RESET.\n");
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
10578c2ecf20Sopenharmony_ci		break;
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_ci	case MBA_SYSTEM_ERR:		/* System Error */
10608c2ecf20Sopenharmony_ci		mbx = 0;
10618c2ecf20Sopenharmony_ci		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
10628c2ecf20Sopenharmony_ci		    IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
10638c2ecf20Sopenharmony_ci			u16 m[4];
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_ci			m[0] = rd_reg_word(&reg24->mailbox4);
10668c2ecf20Sopenharmony_ci			m[1] = rd_reg_word(&reg24->mailbox5);
10678c2ecf20Sopenharmony_ci			m[2] = rd_reg_word(&reg24->mailbox6);
10688c2ecf20Sopenharmony_ci			mbx = m[3] = rd_reg_word(&reg24->mailbox7);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5003,
10718c2ecf20Sopenharmony_ci			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n",
10728c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]);
10738c2ecf20Sopenharmony_ci		} else
10748c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5003,
10758c2ecf20Sopenharmony_ci			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ",
10768c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3]);
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_ci		if ((IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
10798c2ecf20Sopenharmony_ci		    rd_reg_word(&reg24->mailbox7) & BIT_8)
10808c2ecf20Sopenharmony_ci			ha->isp_ops->mpi_fw_dump(vha, 1);
10818c2ecf20Sopenharmony_ci		ha->isp_ops->fw_dump(vha);
10828c2ecf20Sopenharmony_ci		ha->flags.fw_init_done = 0;
10838c2ecf20Sopenharmony_ci		QLA_FW_STOPPED(ha);
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha)) {
10868c2ecf20Sopenharmony_ci			if (mb[1] == 0 && mb[2] == 0) {
10878c2ecf20Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5004,
10888c2ecf20Sopenharmony_ci				    "Unrecoverable Hardware Error: adapter "
10898c2ecf20Sopenharmony_ci				    "marked OFFLINE!\n");
10908c2ecf20Sopenharmony_ci				vha->flags.online = 0;
10918c2ecf20Sopenharmony_ci				vha->device_flags |= DFLG_DEV_FAILED;
10928c2ecf20Sopenharmony_ci			} else {
10938c2ecf20Sopenharmony_ci				/* Check to see if MPI timeout occurred */
10948c2ecf20Sopenharmony_ci				if ((mbx & MBX_3) && (ha->port_no == 0))
10958c2ecf20Sopenharmony_ci					set_bit(MPI_RESET_NEEDED,
10968c2ecf20Sopenharmony_ci					    &vha->dpc_flags);
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
10998c2ecf20Sopenharmony_ci			}
11008c2ecf20Sopenharmony_ci		} else if (mb[1] == 0) {
11018c2ecf20Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x5005,
11028c2ecf20Sopenharmony_ci			    "Unrecoverable Hardware Error: adapter marked "
11038c2ecf20Sopenharmony_ci			    "OFFLINE!\n");
11048c2ecf20Sopenharmony_ci			vha->flags.online = 0;
11058c2ecf20Sopenharmony_ci			vha->device_flags |= DFLG_DEV_FAILED;
11068c2ecf20Sopenharmony_ci		} else
11078c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
11088c2ecf20Sopenharmony_ci		break;
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_ci	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
11118c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5006,
11128c2ecf20Sopenharmony_ci		    "ISP Request Transfer Error (%x).\n",  mb[1]);
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
11158c2ecf20Sopenharmony_ci		break;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
11188c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5007,
11198c2ecf20Sopenharmony_ci		    "ISP Response Transfer Error (%x).\n", mb[1]);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
11228c2ecf20Sopenharmony_ci		break;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_ci	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
11258c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5008,
11268c2ecf20Sopenharmony_ci		    "Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
11278c2ecf20Sopenharmony_ci		break;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci	case MBA_LOOP_INIT_ERR:
11308c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5090,
11318c2ecf20Sopenharmony_ci		    "LOOP INIT ERROR (%x).\n", mb[1]);
11328c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
11338c2ecf20Sopenharmony_ci		break;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
11368c2ecf20Sopenharmony_ci		ha->flags.lip_ae = 1;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5009,
11398c2ecf20Sopenharmony_ci		    "LIP occurred (%x).\n", mb[1]);
11408c2ecf20Sopenharmony_ci
11418c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
11428c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
11438c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
11448c2ecf20Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
11458c2ecf20Sopenharmony_ci		}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_ci		if (vha->vp_idx) {
11488c2ecf20Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
11498c2ecf20Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
11508c2ecf20Sopenharmony_ci		}
11518c2ecf20Sopenharmony_ci
11528c2ecf20Sopenharmony_ci		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
11538c2ecf20Sopenharmony_ci		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
11548c2ecf20Sopenharmony_ci
11558c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
11568c2ecf20Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
11578c2ecf20Sopenharmony_ci		break;
11588c2ecf20Sopenharmony_ci
11598c2ecf20Sopenharmony_ci	case MBA_LOOP_UP:		/* Loop Up Event */
11608c2ecf20Sopenharmony_ci		if (IS_QLA2100(ha) || IS_QLA2200(ha))
11618c2ecf20Sopenharmony_ci			ha->link_data_rate = PORT_SPEED_1GB;
11628c2ecf20Sopenharmony_ci		else
11638c2ecf20Sopenharmony_ci			ha->link_data_rate = mb[1];
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x500a,
11668c2ecf20Sopenharmony_ci		    "LOOP UP detected (%s Gbps).\n",
11678c2ecf20Sopenharmony_ci		    qla2x00_get_link_speed_str(ha, ha->link_data_rate));
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
11708c2ecf20Sopenharmony_ci			if (mb[2] & BIT_0)
11718c2ecf20Sopenharmony_ci				ql_log(ql_log_info, vha, 0x11a0,
11728c2ecf20Sopenharmony_ci				    "FEC=enabled (link up).\n");
11738c2ecf20Sopenharmony_ci		}
11748c2ecf20Sopenharmony_ci
11758c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
11768c2ecf20Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
11778c2ecf20Sopenharmony_ci
11788c2ecf20Sopenharmony_ci		break;
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	case MBA_LOOP_DOWN:		/* Loop Down Event */
11818c2ecf20Sopenharmony_ci		SAVE_TOPO(ha);
11828c2ecf20Sopenharmony_ci		ha->flags.lip_ae = 0;
11838c2ecf20Sopenharmony_ci		ha->current_topology = 0;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
11868c2ecf20Sopenharmony_ci			? rd_reg_word(&reg24->mailbox4) : 0;
11878c2ecf20Sopenharmony_ci		mbx = (IS_P3P_TYPE(ha)) ? rd_reg_word(&reg82->mailbox_out[4])
11888c2ecf20Sopenharmony_ci			: mbx;
11898c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x500b,
11908c2ecf20Sopenharmony_ci		    "LOOP DOWN detected (%x %x %x %x).\n",
11918c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3], mbx);
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
11948c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
11958c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
11968c2ecf20Sopenharmony_ci			/*
11978c2ecf20Sopenharmony_ci			 * In case of loop down, restore WWPN from
11988c2ecf20Sopenharmony_ci			 * NVRAM in case of FA-WWPN capable ISP
11998c2ecf20Sopenharmony_ci			 * Restore for Physical Port only
12008c2ecf20Sopenharmony_ci			 */
12018c2ecf20Sopenharmony_ci			if (!vha->vp_idx) {
12028c2ecf20Sopenharmony_ci				if (ha->flags.fawwpn_enabled &&
12038c2ecf20Sopenharmony_ci				    (ha->current_topology == ISP_CFG_F)) {
12048c2ecf20Sopenharmony_ci					memcpy(vha->port_name, ha->port_name, WWN_SIZE);
12058c2ecf20Sopenharmony_ci					fc_host_port_name(vha->host) =
12068c2ecf20Sopenharmony_ci					    wwn_to_u64(vha->port_name);
12078c2ecf20Sopenharmony_ci					ql_dbg(ql_dbg_init + ql_dbg_verbose,
12088c2ecf20Sopenharmony_ci					    vha, 0x00d8, "LOOP DOWN detected,"
12098c2ecf20Sopenharmony_ci					    "restore WWPN %016llx\n",
12108c2ecf20Sopenharmony_ci					    wwn_to_u64(vha->port_name));
12118c2ecf20Sopenharmony_ci				}
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci				clear_bit(VP_CONFIG_OK, &vha->vp_flags);
12148c2ecf20Sopenharmony_ci			}
12158c2ecf20Sopenharmony_ci
12168c2ecf20Sopenharmony_ci			vha->device_flags |= DFLG_NO_CABLE;
12178c2ecf20Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
12188c2ecf20Sopenharmony_ci		}
12198c2ecf20Sopenharmony_ci
12208c2ecf20Sopenharmony_ci		if (vha->vp_idx) {
12218c2ecf20Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
12228c2ecf20Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
12238c2ecf20Sopenharmony_ci		}
12248c2ecf20Sopenharmony_ci
12258c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
12268c2ecf20Sopenharmony_ci		ha->link_data_rate = PORT_SPEED_UNKNOWN;
12278c2ecf20Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
12288c2ecf20Sopenharmony_ci		break;
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	case MBA_LIP_RESET:		/* LIP reset occurred */
12318c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x500c,
12328c2ecf20Sopenharmony_ci		    "LIP reset occurred (%x).\n", mb[1]);
12338c2ecf20Sopenharmony_ci
12348c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
12358c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
12368c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
12378c2ecf20Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
12388c2ecf20Sopenharmony_ci		}
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci		if (vha->vp_idx) {
12418c2ecf20Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
12428c2ecf20Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
12438c2ecf20Sopenharmony_ci		}
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
12468c2ecf20Sopenharmony_ci
12478c2ecf20Sopenharmony_ci		ha->operating_mode = LOOP;
12488c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
12498c2ecf20Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
12508c2ecf20Sopenharmony_ci		break;
12518c2ecf20Sopenharmony_ci
12528c2ecf20Sopenharmony_ci	/* case MBA_DCBX_COMPLETE: */
12538c2ecf20Sopenharmony_ci	case MBA_POINT_TO_POINT:	/* Point-to-Point */
12548c2ecf20Sopenharmony_ci		ha->flags.lip_ae = 0;
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci		if (IS_QLA2100(ha))
12578c2ecf20Sopenharmony_ci			break;
12588c2ecf20Sopenharmony_ci
12598c2ecf20Sopenharmony_ci		if (IS_CNA_CAPABLE(ha)) {
12608c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x500d,
12618c2ecf20Sopenharmony_ci			    "DCBX Completed -- %04x %04x %04x.\n",
12628c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3]);
12638c2ecf20Sopenharmony_ci			if (ha->notify_dcbx_comp && !vha->vp_idx)
12648c2ecf20Sopenharmony_ci				complete(&ha->dcbx_comp);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci		} else
12678c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x500e,
12688c2ecf20Sopenharmony_ci			    "Asynchronous P2P MODE received.\n");
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci		/*
12718c2ecf20Sopenharmony_ci		 * Until there's a transition from loop down to loop up, treat
12728c2ecf20Sopenharmony_ci		 * this as loop down only.
12738c2ecf20Sopenharmony_ci		 */
12748c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
12758c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
12768c2ecf20Sopenharmony_ci			if (!atomic_read(&vha->loop_down_timer))
12778c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
12788c2ecf20Sopenharmony_ci				    LOOP_DOWN_TIME);
12798c2ecf20Sopenharmony_ci			if (!N2N_TOPO(ha))
12808c2ecf20Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
12818c2ecf20Sopenharmony_ci		}
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci		if (vha->vp_idx) {
12848c2ecf20Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
12858c2ecf20Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
12868c2ecf20Sopenharmony_ci		}
12878c2ecf20Sopenharmony_ci
12888c2ecf20Sopenharmony_ci		if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
12898c2ecf20Sopenharmony_ci			set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
12928c2ecf20Sopenharmony_ci		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
12938c2ecf20Sopenharmony_ci
12948c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
12958c2ecf20Sopenharmony_ci		break;
12968c2ecf20Sopenharmony_ci
12978c2ecf20Sopenharmony_ci	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
12988c2ecf20Sopenharmony_ci		if (IS_QLA2100(ha))
12998c2ecf20Sopenharmony_ci			break;
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x500f,
13028c2ecf20Sopenharmony_ci		    "Configuration change detected: value=%x.\n", mb[1]);
13038c2ecf20Sopenharmony_ci
13048c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
13058c2ecf20Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
13068c2ecf20Sopenharmony_ci			if (!atomic_read(&vha->loop_down_timer))
13078c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
13088c2ecf20Sopenharmony_ci				    LOOP_DOWN_TIME);
13098c2ecf20Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
13108c2ecf20Sopenharmony_ci		}
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		if (vha->vp_idx) {
13138c2ecf20Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
13148c2ecf20Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
13158c2ecf20Sopenharmony_ci		}
13168c2ecf20Sopenharmony_ci
13178c2ecf20Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
13188c2ecf20Sopenharmony_ci		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
13198c2ecf20Sopenharmony_ci		break;
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci	case MBA_PORT_UPDATE:		/* Port database update */
13228c2ecf20Sopenharmony_ci		/*
13238c2ecf20Sopenharmony_ci		 * Handle only global and vn-port update events
13248c2ecf20Sopenharmony_ci		 *
13258c2ecf20Sopenharmony_ci		 * Relevant inputs:
13268c2ecf20Sopenharmony_ci		 * mb[1] = N_Port handle of changed port
13278c2ecf20Sopenharmony_ci		 * OR 0xffff for global event
13288c2ecf20Sopenharmony_ci		 * mb[2] = New login state
13298c2ecf20Sopenharmony_ci		 * 7 = Port logged out
13308c2ecf20Sopenharmony_ci		 * mb[3] = LSB is vp_idx, 0xff = all vps
13318c2ecf20Sopenharmony_ci		 *
13328c2ecf20Sopenharmony_ci		 * Skip processing if:
13338c2ecf20Sopenharmony_ci		 *       Event is global, vp_idx is NOT all vps,
13348c2ecf20Sopenharmony_ci		 *           vp_idx does not match
13358c2ecf20Sopenharmony_ci		 *       Event is not global, vp_idx does not match
13368c2ecf20Sopenharmony_ci		 */
13378c2ecf20Sopenharmony_ci		if (IS_QLA2XXX_MIDTYPE(ha) &&
13388c2ecf20Sopenharmony_ci		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
13398c2ecf20Sopenharmony_ci			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
13408c2ecf20Sopenharmony_ci			break;
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci		if (mb[2] == 0x7) {
13438c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5010,
13448c2ecf20Sopenharmony_ci			    "Port %s %04x %04x %04x.\n",
13458c2ecf20Sopenharmony_ci			    mb[1] == 0xffff ? "unavailable" : "logout",
13468c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3]);
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci			if (mb[1] == 0xffff)
13498c2ecf20Sopenharmony_ci				goto global_port_update;
13508c2ecf20Sopenharmony_ci
13518c2ecf20Sopenharmony_ci			if (mb[1] == NPH_SNS_LID(ha)) {
13528c2ecf20Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
13538c2ecf20Sopenharmony_ci				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
13548c2ecf20Sopenharmony_ci				break;
13558c2ecf20Sopenharmony_ci			}
13568c2ecf20Sopenharmony_ci
13578c2ecf20Sopenharmony_ci			/* use handle_cnt for loop id/nport handle */
13588c2ecf20Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha))
13598c2ecf20Sopenharmony_ci				handle_cnt = NPH_SNS;
13608c2ecf20Sopenharmony_ci			else
13618c2ecf20Sopenharmony_ci				handle_cnt = SIMPLE_NAME_SERVER;
13628c2ecf20Sopenharmony_ci			if (mb[1] == handle_cnt) {
13638c2ecf20Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
13648c2ecf20Sopenharmony_ci				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
13658c2ecf20Sopenharmony_ci				break;
13668c2ecf20Sopenharmony_ci			}
13678c2ecf20Sopenharmony_ci
13688c2ecf20Sopenharmony_ci			/* Port logout */
13698c2ecf20Sopenharmony_ci			fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
13708c2ecf20Sopenharmony_ci			if (!fcport)
13718c2ecf20Sopenharmony_ci				break;
13728c2ecf20Sopenharmony_ci			if (atomic_read(&fcport->state) != FCS_ONLINE)
13738c2ecf20Sopenharmony_ci				break;
13748c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x508a,
13758c2ecf20Sopenharmony_ci			    "Marking port lost loopid=%04x portid=%06x.\n",
13768c2ecf20Sopenharmony_ci			    fcport->loop_id, fcport->d_id.b24);
13778c2ecf20Sopenharmony_ci			if (qla_ini_mode_enabled(vha)) {
13788c2ecf20Sopenharmony_ci				fcport->logout_on_delete = 0;
13798c2ecf20Sopenharmony_ci				qlt_schedule_sess_for_deletion(fcport);
13808c2ecf20Sopenharmony_ci			}
13818c2ecf20Sopenharmony_ci			break;
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ciglobal_port_update:
13848c2ecf20Sopenharmony_ci			if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
13858c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_state, LOOP_DOWN);
13868c2ecf20Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
13878c2ecf20Sopenharmony_ci				    LOOP_DOWN_TIME);
13888c2ecf20Sopenharmony_ci				vha->device_flags |= DFLG_NO_CABLE;
13898c2ecf20Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
13908c2ecf20Sopenharmony_ci			}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_ci			if (vha->vp_idx) {
13938c2ecf20Sopenharmony_ci				atomic_set(&vha->vp_state, VP_FAILED);
13948c2ecf20Sopenharmony_ci				fc_vport_set_state(vha->fc_vport,
13958c2ecf20Sopenharmony_ci				    FC_VPORT_FAILED);
13968c2ecf20Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
13978c2ecf20Sopenharmony_ci			}
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci			vha->flags.management_server_logged_in = 0;
14008c2ecf20Sopenharmony_ci			ha->link_data_rate = PORT_SPEED_UNKNOWN;
14018c2ecf20Sopenharmony_ci			break;
14028c2ecf20Sopenharmony_ci		}
14038c2ecf20Sopenharmony_ci
14048c2ecf20Sopenharmony_ci		/*
14058c2ecf20Sopenharmony_ci		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
14068c2ecf20Sopenharmony_ci		 * event etc. earlier indicating loop is down) then process
14078c2ecf20Sopenharmony_ci		 * it.  Otherwise ignore it and Wait for RSCN to come in.
14088c2ecf20Sopenharmony_ci		 */
14098c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
14108c2ecf20Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
14118c2ecf20Sopenharmony_ci			!ha->flags.n2n_ae  &&
14128c2ecf20Sopenharmony_ci		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
14138c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5011,
14148c2ecf20Sopenharmony_ci			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
14158c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3]);
14168c2ecf20Sopenharmony_ci			break;
14178c2ecf20Sopenharmony_ci		}
14188c2ecf20Sopenharmony_ci
14198c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5012,
14208c2ecf20Sopenharmony_ci		    "Port database changed %04x %04x %04x.\n",
14218c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
14228c2ecf20Sopenharmony_ci
14238c2ecf20Sopenharmony_ci		/*
14248c2ecf20Sopenharmony_ci		 * Mark all devices as missing so we will login again.
14258c2ecf20Sopenharmony_ci		 */
14268c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_UP);
14278c2ecf20Sopenharmony_ci		vha->scan.scan_retry = 0;
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
14308c2ecf20Sopenharmony_ci		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
14318c2ecf20Sopenharmony_ci		set_bit(VP_CONFIG_OK, &vha->vp_flags);
14328c2ecf20Sopenharmony_ci		break;
14338c2ecf20Sopenharmony_ci
14348c2ecf20Sopenharmony_ci	case MBA_RSCN_UPDATE:		/* State Change Registration */
14358c2ecf20Sopenharmony_ci		/* Check if the Vport has issued a SCR */
14368c2ecf20Sopenharmony_ci		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
14378c2ecf20Sopenharmony_ci			break;
14388c2ecf20Sopenharmony_ci		/* Only handle SCNs for our Vport index. */
14398c2ecf20Sopenharmony_ci		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
14408c2ecf20Sopenharmony_ci			break;
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5013,
14438c2ecf20Sopenharmony_ci		    "RSCN database changed -- %04x %04x %04x.\n",
14448c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
14458c2ecf20Sopenharmony_ci
14468c2ecf20Sopenharmony_ci		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
14478c2ecf20Sopenharmony_ci		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
14488c2ecf20Sopenharmony_ci				| vha->d_id.b.al_pa;
14498c2ecf20Sopenharmony_ci		if (rscn_entry == host_pid) {
14508c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5014,
14518c2ecf20Sopenharmony_ci			    "Ignoring RSCN update to local host "
14528c2ecf20Sopenharmony_ci			    "port ID (%06x).\n", host_pid);
14538c2ecf20Sopenharmony_ci			break;
14548c2ecf20Sopenharmony_ci		}
14558c2ecf20Sopenharmony_ci
14568c2ecf20Sopenharmony_ci		/* Ignore reserved bits from RSCN-payload. */
14578c2ecf20Sopenharmony_ci		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
14588c2ecf20Sopenharmony_ci
14598c2ecf20Sopenharmony_ci		/* Skip RSCNs for virtual ports on the same physical port */
14608c2ecf20Sopenharmony_ci		if (qla2x00_is_a_vp_did(vha, rscn_entry))
14618c2ecf20Sopenharmony_ci			break;
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
14648c2ecf20Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
14658c2ecf20Sopenharmony_ci		{
14668c2ecf20Sopenharmony_ci			struct event_arg ea;
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci			memset(&ea, 0, sizeof(ea));
14698c2ecf20Sopenharmony_ci			ea.id.b24 = rscn_entry;
14708c2ecf20Sopenharmony_ci			ea.id.b.rsvd_1 = rscn_entry >> 24;
14718c2ecf20Sopenharmony_ci			qla2x00_handle_rscn(vha, &ea);
14728c2ecf20Sopenharmony_ci			qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
14738c2ecf20Sopenharmony_ci		}
14748c2ecf20Sopenharmony_ci		break;
14758c2ecf20Sopenharmony_ci	case MBA_CONGN_NOTI_RECV:
14768c2ecf20Sopenharmony_ci		if (!ha->flags.scm_enabled ||
14778c2ecf20Sopenharmony_ci		    mb[1] != QLA_CON_PRIMITIVE_RECEIVED)
14788c2ecf20Sopenharmony_ci			break;
14798c2ecf20Sopenharmony_ci
14808c2ecf20Sopenharmony_ci		if (mb[2] == QLA_CONGESTION_ARB_WARNING) {
14818c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x509b,
14828c2ecf20Sopenharmony_ci			       "Congestion Warning %04x %04x.\n", mb[1], mb[2]);
14838c2ecf20Sopenharmony_ci		} else if (mb[2] == QLA_CONGESTION_ARB_ALARM) {
14848c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x509b,
14858c2ecf20Sopenharmony_ci			       "Congestion Alarm %04x %04x.\n", mb[1], mb[2]);
14868c2ecf20Sopenharmony_ci		}
14878c2ecf20Sopenharmony_ci		break;
14888c2ecf20Sopenharmony_ci	/* case MBA_RIO_RESPONSE: */
14898c2ecf20Sopenharmony_ci	case MBA_ZIO_RESPONSE:
14908c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5015,
14918c2ecf20Sopenharmony_ci		    "[R|Z]IO update completion.\n");
14928c2ecf20Sopenharmony_ci
14938c2ecf20Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha))
14948c2ecf20Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
14958c2ecf20Sopenharmony_ci		else
14968c2ecf20Sopenharmony_ci			qla2x00_process_response_queue(rsp);
14978c2ecf20Sopenharmony_ci		break;
14988c2ecf20Sopenharmony_ci
14998c2ecf20Sopenharmony_ci	case MBA_DISCARD_RND_FRAME:
15008c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5016,
15018c2ecf20Sopenharmony_ci		    "Discard RND Frame -- %04x %04x %04x.\n",
15028c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
15038c2ecf20Sopenharmony_ci		break;
15048c2ecf20Sopenharmony_ci
15058c2ecf20Sopenharmony_ci	case MBA_TRACE_NOTIFICATION:
15068c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5017,
15078c2ecf20Sopenharmony_ci		    "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
15088c2ecf20Sopenharmony_ci		break;
15098c2ecf20Sopenharmony_ci
15108c2ecf20Sopenharmony_ci	case MBA_ISP84XX_ALERT:
15118c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5018,
15128c2ecf20Sopenharmony_ci		    "ISP84XX Alert Notification -- %04x %04x %04x.\n",
15138c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
15148c2ecf20Sopenharmony_ci
15158c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
15168c2ecf20Sopenharmony_ci		switch (mb[1]) {
15178c2ecf20Sopenharmony_ci		case A84_PANIC_RECOVERY:
15188c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x5019,
15198c2ecf20Sopenharmony_ci			    "Alert 84XX: panic recovery %04x %04x.\n",
15208c2ecf20Sopenharmony_ci			    mb[2], mb[3]);
15218c2ecf20Sopenharmony_ci			break;
15228c2ecf20Sopenharmony_ci		case A84_OP_LOGIN_COMPLETE:
15238c2ecf20Sopenharmony_ci			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
15248c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501a,
15258c2ecf20Sopenharmony_ci			    "Alert 84XX: firmware version %x.\n",
15268c2ecf20Sopenharmony_ci			    ha->cs84xx->op_fw_version);
15278c2ecf20Sopenharmony_ci			break;
15288c2ecf20Sopenharmony_ci		case A84_DIAG_LOGIN_COMPLETE:
15298c2ecf20Sopenharmony_ci			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
15308c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501b,
15318c2ecf20Sopenharmony_ci			    "Alert 84XX: diagnostic firmware version %x.\n",
15328c2ecf20Sopenharmony_ci			    ha->cs84xx->diag_fw_version);
15338c2ecf20Sopenharmony_ci			break;
15348c2ecf20Sopenharmony_ci		case A84_GOLD_LOGIN_COMPLETE:
15358c2ecf20Sopenharmony_ci			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
15368c2ecf20Sopenharmony_ci			ha->cs84xx->fw_update = 1;
15378c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501c,
15388c2ecf20Sopenharmony_ci			    "Alert 84XX: gold firmware version %x.\n",
15398c2ecf20Sopenharmony_ci			    ha->cs84xx->gold_fw_version);
15408c2ecf20Sopenharmony_ci			break;
15418c2ecf20Sopenharmony_ci		default:
15428c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x501d,
15438c2ecf20Sopenharmony_ci			    "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
15448c2ecf20Sopenharmony_ci			    mb[1], mb[2], mb[3]);
15458c2ecf20Sopenharmony_ci		}
15468c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
15478c2ecf20Sopenharmony_ci		break;
15488c2ecf20Sopenharmony_ci	case MBA_DCBX_START:
15498c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x501e,
15508c2ecf20Sopenharmony_ci		    "DCBX Started -- %04x %04x %04x.\n",
15518c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
15528c2ecf20Sopenharmony_ci		break;
15538c2ecf20Sopenharmony_ci	case MBA_DCBX_PARAM_UPDATE:
15548c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x501f,
15558c2ecf20Sopenharmony_ci		    "DCBX Parameters Updated -- %04x %04x %04x.\n",
15568c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
15578c2ecf20Sopenharmony_ci		break;
15588c2ecf20Sopenharmony_ci	case MBA_FCF_CONF_ERR:
15598c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5020,
15608c2ecf20Sopenharmony_ci		    "FCF Configuration Error -- %04x %04x %04x.\n",
15618c2ecf20Sopenharmony_ci		    mb[1], mb[2], mb[3]);
15628c2ecf20Sopenharmony_ci		break;
15638c2ecf20Sopenharmony_ci	case MBA_IDC_NOTIFY:
15648c2ecf20Sopenharmony_ci		if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
15658c2ecf20Sopenharmony_ci			mb[4] = rd_reg_word(&reg24->mailbox4);
15668c2ecf20Sopenharmony_ci			if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
15678c2ecf20Sopenharmony_ci			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
15688c2ecf20Sopenharmony_ci			    (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
15698c2ecf20Sopenharmony_ci				set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
15708c2ecf20Sopenharmony_ci				/*
15718c2ecf20Sopenharmony_ci				 * Extend loop down timer since port is active.
15728c2ecf20Sopenharmony_ci				 */
15738c2ecf20Sopenharmony_ci				if (atomic_read(&vha->loop_state) == LOOP_DOWN)
15748c2ecf20Sopenharmony_ci					atomic_set(&vha->loop_down_timer,
15758c2ecf20Sopenharmony_ci					    LOOP_DOWN_TIME);
15768c2ecf20Sopenharmony_ci				qla2xxx_wake_dpc(vha);
15778c2ecf20Sopenharmony_ci			}
15788c2ecf20Sopenharmony_ci		}
15798c2ecf20Sopenharmony_ci		fallthrough;
15808c2ecf20Sopenharmony_ci	case MBA_IDC_COMPLETE:
15818c2ecf20Sopenharmony_ci		if (ha->notify_lb_portup_comp && !vha->vp_idx)
15828c2ecf20Sopenharmony_ci			complete(&ha->lb_portup_comp);
15838c2ecf20Sopenharmony_ci		fallthrough;
15848c2ecf20Sopenharmony_ci	case MBA_IDC_TIME_EXT:
15858c2ecf20Sopenharmony_ci		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
15868c2ecf20Sopenharmony_ci		    IS_QLA8044(ha))
15878c2ecf20Sopenharmony_ci			qla81xx_idc_event(vha, mb[0], mb[1]);
15888c2ecf20Sopenharmony_ci		break;
15898c2ecf20Sopenharmony_ci
15908c2ecf20Sopenharmony_ci	case MBA_IDC_AEN:
15918c2ecf20Sopenharmony_ci		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
15928c2ecf20Sopenharmony_ci			qla27xx_handle_8200_aen(vha, mb);
15938c2ecf20Sopenharmony_ci		} else if (IS_QLA83XX(ha)) {
15948c2ecf20Sopenharmony_ci			mb[4] = rd_reg_word(&reg24->mailbox4);
15958c2ecf20Sopenharmony_ci			mb[5] = rd_reg_word(&reg24->mailbox5);
15968c2ecf20Sopenharmony_ci			mb[6] = rd_reg_word(&reg24->mailbox6);
15978c2ecf20Sopenharmony_ci			mb[7] = rd_reg_word(&reg24->mailbox7);
15988c2ecf20Sopenharmony_ci			qla83xx_handle_8200_aen(vha, mb);
15998c2ecf20Sopenharmony_ci		} else {
16008c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5052,
16018c2ecf20Sopenharmony_ci			    "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n",
16028c2ecf20Sopenharmony_ci			    mb[0], mb[1], mb[2], mb[3]);
16038c2ecf20Sopenharmony_ci		}
16048c2ecf20Sopenharmony_ci		break;
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci	case MBA_DPORT_DIAGNOSTICS:
16078c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5052,
16088c2ecf20Sopenharmony_ci		    "D-Port Diagnostics: %04x %04x %04x %04x\n",
16098c2ecf20Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
16108c2ecf20Sopenharmony_ci		memcpy(vha->dport_data, mb, sizeof(vha->dport_data));
16118c2ecf20Sopenharmony_ci		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
16128c2ecf20Sopenharmony_ci			static char *results[] = {
16138c2ecf20Sopenharmony_ci			    "start", "done(pass)", "done(error)", "undefined" };
16148c2ecf20Sopenharmony_ci			static char *types[] = {
16158c2ecf20Sopenharmony_ci			    "none", "dynamic", "static", "other" };
16168c2ecf20Sopenharmony_ci			uint result = mb[1] >> 0 & 0x3;
16178c2ecf20Sopenharmony_ci			uint type = mb[1] >> 6 & 0x3;
16188c2ecf20Sopenharmony_ci			uint sw = mb[1] >> 15 & 0x1;
16198c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5052,
16208c2ecf20Sopenharmony_ci			    "D-Port Diagnostics: result=%s type=%s [sw=%u]\n",
16218c2ecf20Sopenharmony_ci			    results[result], types[type], sw);
16228c2ecf20Sopenharmony_ci			if (result == 2) {
16238c2ecf20Sopenharmony_ci				static char *reasons[] = {
16248c2ecf20Sopenharmony_ci				    "reserved", "unexpected reject",
16258c2ecf20Sopenharmony_ci				    "unexpected phase", "retry exceeded",
16268c2ecf20Sopenharmony_ci				    "timed out", "not supported",
16278c2ecf20Sopenharmony_ci				    "user stopped" };
16288c2ecf20Sopenharmony_ci				uint reason = mb[2] >> 0 & 0xf;
16298c2ecf20Sopenharmony_ci				uint phase = mb[2] >> 12 & 0xf;
16308c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5052,
16318c2ecf20Sopenharmony_ci				    "D-Port Diagnostics: reason=%s phase=%u \n",
16328c2ecf20Sopenharmony_ci				    reason < 7 ? reasons[reason] : "other",
16338c2ecf20Sopenharmony_ci				    phase >> 1);
16348c2ecf20Sopenharmony_ci			}
16358c2ecf20Sopenharmony_ci		}
16368c2ecf20Sopenharmony_ci		break;
16378c2ecf20Sopenharmony_ci
16388c2ecf20Sopenharmony_ci	case MBA_TEMPERATURE_ALERT:
16398c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x505e,
16408c2ecf20Sopenharmony_ci		    "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
16418c2ecf20Sopenharmony_ci		break;
16428c2ecf20Sopenharmony_ci
16438c2ecf20Sopenharmony_ci	case MBA_TRANS_INSERT:
16448c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5091,
16458c2ecf20Sopenharmony_ci		    "Transceiver Insertion: %04x\n", mb[1]);
16468c2ecf20Sopenharmony_ci		set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
16478c2ecf20Sopenharmony_ci		break;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci	case MBA_TRANS_REMOVE:
16508c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n");
16518c2ecf20Sopenharmony_ci		break;
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_ci	default:
16548c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5057,
16558c2ecf20Sopenharmony_ci		    "Unknown AEN:%04x %04x %04x %04x\n",
16568c2ecf20Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
16578c2ecf20Sopenharmony_ci	}
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	qlt_async_event(mb[0], vha, mb);
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci	if (!vha->vp_idx && ha->num_vhosts)
16628c2ecf20Sopenharmony_ci		qla2x00_alert_all_vps(rsp, mb);
16638c2ecf20Sopenharmony_ci}
16648c2ecf20Sopenharmony_ci
16658c2ecf20Sopenharmony_ci/**
16668c2ecf20Sopenharmony_ci * qla2x00_process_completed_request() - Process a Fast Post response.
16678c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
16688c2ecf20Sopenharmony_ci * @req: request queue
16698c2ecf20Sopenharmony_ci * @index: SRB index
16708c2ecf20Sopenharmony_ci */
16718c2ecf20Sopenharmony_civoid
16728c2ecf20Sopenharmony_ciqla2x00_process_completed_request(struct scsi_qla_host *vha,
16738c2ecf20Sopenharmony_ci				  struct req_que *req, uint32_t index)
16748c2ecf20Sopenharmony_ci{
16758c2ecf20Sopenharmony_ci	srb_t *sp;
16768c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
16778c2ecf20Sopenharmony_ci
16788c2ecf20Sopenharmony_ci	/* Validate handle. */
16798c2ecf20Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
16808c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3014,
16818c2ecf20Sopenharmony_ci		    "Invalid SCSI command index (%x).\n", index);
16828c2ecf20Sopenharmony_ci
16838c2ecf20Sopenharmony_ci		if (IS_P3P_TYPE(ha))
16848c2ecf20Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
16858c2ecf20Sopenharmony_ci		else
16868c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
16878c2ecf20Sopenharmony_ci		return;
16888c2ecf20Sopenharmony_ci	}
16898c2ecf20Sopenharmony_ci
16908c2ecf20Sopenharmony_ci	sp = req->outstanding_cmds[index];
16918c2ecf20Sopenharmony_ci	if (sp) {
16928c2ecf20Sopenharmony_ci		/* Free outstanding command slot. */
16938c2ecf20Sopenharmony_ci		req->outstanding_cmds[index] = NULL;
16948c2ecf20Sopenharmony_ci
16958c2ecf20Sopenharmony_ci		/* Save ISP completion status */
16968c2ecf20Sopenharmony_ci		sp->done(sp, DID_OK << 16);
16978c2ecf20Sopenharmony_ci	} else {
16988c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
16998c2ecf20Sopenharmony_ci
17008c2ecf20Sopenharmony_ci		if (IS_P3P_TYPE(ha))
17018c2ecf20Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
17028c2ecf20Sopenharmony_ci		else
17038c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
17048c2ecf20Sopenharmony_ci	}
17058c2ecf20Sopenharmony_ci}
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_cisrb_t *
17088c2ecf20Sopenharmony_ciqla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
17098c2ecf20Sopenharmony_ci    struct req_que *req, void *iocb)
17108c2ecf20Sopenharmony_ci{
17118c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
17128c2ecf20Sopenharmony_ci	sts_entry_t *pkt = iocb;
17138c2ecf20Sopenharmony_ci	srb_t *sp;
17148c2ecf20Sopenharmony_ci	uint16_t index;
17158c2ecf20Sopenharmony_ci
17168c2ecf20Sopenharmony_ci	index = LSW(pkt->handle);
17178c2ecf20Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
17188c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5031,
17198c2ecf20Sopenharmony_ci			   "%s: Invalid command index (%x) type %8ph.\n",
17208c2ecf20Sopenharmony_ci			   func, index, iocb);
17218c2ecf20Sopenharmony_ci		if (IS_P3P_TYPE(ha))
17228c2ecf20Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
17238c2ecf20Sopenharmony_ci		else
17248c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
17258c2ecf20Sopenharmony_ci		return NULL;
17268c2ecf20Sopenharmony_ci	}
17278c2ecf20Sopenharmony_ci	sp = req->outstanding_cmds[index];
17288c2ecf20Sopenharmony_ci	if (!sp) {
17298c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5032,
17308c2ecf20Sopenharmony_ci			"%s: Invalid completion handle (%x) -- timed-out.\n",
17318c2ecf20Sopenharmony_ci			func, index);
17328c2ecf20Sopenharmony_ci		return NULL;
17338c2ecf20Sopenharmony_ci	}
17348c2ecf20Sopenharmony_ci	if (sp->handle != index) {
17358c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5033,
17368c2ecf20Sopenharmony_ci			"%s: SRB handle (%x) mismatch %x.\n", func,
17378c2ecf20Sopenharmony_ci			sp->handle, index);
17388c2ecf20Sopenharmony_ci		return NULL;
17398c2ecf20Sopenharmony_ci	}
17408c2ecf20Sopenharmony_ci
17418c2ecf20Sopenharmony_ci	req->outstanding_cmds[index] = NULL;
17428c2ecf20Sopenharmony_ci	return sp;
17438c2ecf20Sopenharmony_ci}
17448c2ecf20Sopenharmony_ci
17458c2ecf20Sopenharmony_cistatic void
17468c2ecf20Sopenharmony_ciqla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
17478c2ecf20Sopenharmony_ci    struct mbx_entry *mbx)
17488c2ecf20Sopenharmony_ci{
17498c2ecf20Sopenharmony_ci	const char func[] = "MBX-IOCB";
17508c2ecf20Sopenharmony_ci	const char *type;
17518c2ecf20Sopenharmony_ci	fc_port_t *fcport;
17528c2ecf20Sopenharmony_ci	srb_t *sp;
17538c2ecf20Sopenharmony_ci	struct srb_iocb *lio;
17548c2ecf20Sopenharmony_ci	uint16_t *data;
17558c2ecf20Sopenharmony_ci	uint16_t status;
17568c2ecf20Sopenharmony_ci
17578c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
17588c2ecf20Sopenharmony_ci	if (!sp)
17598c2ecf20Sopenharmony_ci		return;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci	lio = &sp->u.iocb_cmd;
17628c2ecf20Sopenharmony_ci	type = sp->name;
17638c2ecf20Sopenharmony_ci	fcport = sp->fcport;
17648c2ecf20Sopenharmony_ci	data = lio->u.logio.data;
17658c2ecf20Sopenharmony_ci
17668c2ecf20Sopenharmony_ci	data[0] = MBS_COMMAND_ERROR;
17678c2ecf20Sopenharmony_ci	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
17688c2ecf20Sopenharmony_ci	    QLA_LOGIO_LOGIN_RETRIED : 0;
17698c2ecf20Sopenharmony_ci	if (mbx->entry_status) {
17708c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5043,
17718c2ecf20Sopenharmony_ci		    "Async-%s error entry - hdl=%x portid=%02x%02x%02x "
17728c2ecf20Sopenharmony_ci		    "entry-status=%x status=%x state-flag=%x "
17738c2ecf20Sopenharmony_ci		    "status-flags=%x.\n", type, sp->handle,
17748c2ecf20Sopenharmony_ci		    fcport->d_id.b.domain, fcport->d_id.b.area,
17758c2ecf20Sopenharmony_ci		    fcport->d_id.b.al_pa, mbx->entry_status,
17768c2ecf20Sopenharmony_ci		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
17778c2ecf20Sopenharmony_ci		    le16_to_cpu(mbx->status_flags));
17788c2ecf20Sopenharmony_ci
17798c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
17808c2ecf20Sopenharmony_ci		    mbx, sizeof(*mbx));
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci		goto logio_done;
17838c2ecf20Sopenharmony_ci	}
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci	status = le16_to_cpu(mbx->status);
17868c2ecf20Sopenharmony_ci	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
17878c2ecf20Sopenharmony_ci	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
17888c2ecf20Sopenharmony_ci		status = 0;
17898c2ecf20Sopenharmony_ci	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
17908c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5045,
17918c2ecf20Sopenharmony_ci		    "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n",
17928c2ecf20Sopenharmony_ci		    type, sp->handle, fcport->d_id.b.domain,
17938c2ecf20Sopenharmony_ci		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
17948c2ecf20Sopenharmony_ci		    le16_to_cpu(mbx->mb1));
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci		data[0] = MBS_COMMAND_COMPLETE;
17978c2ecf20Sopenharmony_ci		if (sp->type == SRB_LOGIN_CMD) {
17988c2ecf20Sopenharmony_ci			fcport->port_type = FCT_TARGET;
17998c2ecf20Sopenharmony_ci			if (le16_to_cpu(mbx->mb1) & BIT_0)
18008c2ecf20Sopenharmony_ci				fcport->port_type = FCT_INITIATOR;
18018c2ecf20Sopenharmony_ci			else if (le16_to_cpu(mbx->mb1) & BIT_1)
18028c2ecf20Sopenharmony_ci				fcport->flags |= FCF_FCP2_DEVICE;
18038c2ecf20Sopenharmony_ci		}
18048c2ecf20Sopenharmony_ci		goto logio_done;
18058c2ecf20Sopenharmony_ci	}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	data[0] = le16_to_cpu(mbx->mb0);
18088c2ecf20Sopenharmony_ci	switch (data[0]) {
18098c2ecf20Sopenharmony_ci	case MBS_PORT_ID_USED:
18108c2ecf20Sopenharmony_ci		data[1] = le16_to_cpu(mbx->mb1);
18118c2ecf20Sopenharmony_ci		break;
18128c2ecf20Sopenharmony_ci	case MBS_LOOP_ID_USED:
18138c2ecf20Sopenharmony_ci		break;
18148c2ecf20Sopenharmony_ci	default:
18158c2ecf20Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
18168c2ecf20Sopenharmony_ci		break;
18178c2ecf20Sopenharmony_ci	}
18188c2ecf20Sopenharmony_ci
18198c2ecf20Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x5046,
18208c2ecf20Sopenharmony_ci	    "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x "
18218c2ecf20Sopenharmony_ci	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle,
18228c2ecf20Sopenharmony_ci	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
18238c2ecf20Sopenharmony_ci	    status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
18248c2ecf20Sopenharmony_ci	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
18258c2ecf20Sopenharmony_ci	    le16_to_cpu(mbx->mb7));
18268c2ecf20Sopenharmony_ci
18278c2ecf20Sopenharmony_cilogio_done:
18288c2ecf20Sopenharmony_ci	sp->done(sp, 0);
18298c2ecf20Sopenharmony_ci}
18308c2ecf20Sopenharmony_ci
18318c2ecf20Sopenharmony_cistatic void
18328c2ecf20Sopenharmony_ciqla24xx_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
18338c2ecf20Sopenharmony_ci    struct mbx_24xx_entry *pkt)
18348c2ecf20Sopenharmony_ci{
18358c2ecf20Sopenharmony_ci	const char func[] = "MBX-IOCB2";
18368c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
18378c2ecf20Sopenharmony_ci	srb_t *sp;
18388c2ecf20Sopenharmony_ci	struct srb_iocb *si;
18398c2ecf20Sopenharmony_ci	u16 sz, i;
18408c2ecf20Sopenharmony_ci	int res;
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
18438c2ecf20Sopenharmony_ci	if (!sp)
18448c2ecf20Sopenharmony_ci		return;
18458c2ecf20Sopenharmony_ci
18468c2ecf20Sopenharmony_ci	if (sp->type == SRB_SCSI_CMD ||
18478c2ecf20Sopenharmony_ci	    sp->type == SRB_NVME_CMD ||
18488c2ecf20Sopenharmony_ci	    sp->type == SRB_TM_CMD) {
18498c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x509d,
18508c2ecf20Sopenharmony_ci			"Inconsistent event entry type %d\n", sp->type);
18518c2ecf20Sopenharmony_ci		if (IS_P3P_TYPE(ha))
18528c2ecf20Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
18538c2ecf20Sopenharmony_ci		else
18548c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
18558c2ecf20Sopenharmony_ci		return;
18568c2ecf20Sopenharmony_ci	}
18578c2ecf20Sopenharmony_ci
18588c2ecf20Sopenharmony_ci	si = &sp->u.iocb_cmd;
18598c2ecf20Sopenharmony_ci	sz = min(ARRAY_SIZE(pkt->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.in_mb));
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci	for (i = 0; i < sz; i++)
18628c2ecf20Sopenharmony_ci		si->u.mbx.in_mb[i] = pkt->mb[i];
18638c2ecf20Sopenharmony_ci
18648c2ecf20Sopenharmony_ci	res = (si->u.mbx.in_mb[0] & MBS_MASK);
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci	sp->done(sp, res);
18678c2ecf20Sopenharmony_ci}
18688c2ecf20Sopenharmony_ci
18698c2ecf20Sopenharmony_cistatic void
18708c2ecf20Sopenharmony_ciqla24xxx_nack_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
18718c2ecf20Sopenharmony_ci    struct nack_to_isp *pkt)
18728c2ecf20Sopenharmony_ci{
18738c2ecf20Sopenharmony_ci	const char func[] = "nack";
18748c2ecf20Sopenharmony_ci	srb_t *sp;
18758c2ecf20Sopenharmony_ci	int res = 0;
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
18788c2ecf20Sopenharmony_ci	if (!sp)
18798c2ecf20Sopenharmony_ci		return;
18808c2ecf20Sopenharmony_ci
18818c2ecf20Sopenharmony_ci	if (pkt->u.isp2x.status != cpu_to_le16(NOTIFY_ACK_SUCCESS))
18828c2ecf20Sopenharmony_ci		res = QLA_FUNCTION_FAILED;
18838c2ecf20Sopenharmony_ci
18848c2ecf20Sopenharmony_ci	sp->done(sp, res);
18858c2ecf20Sopenharmony_ci}
18868c2ecf20Sopenharmony_ci
18878c2ecf20Sopenharmony_cistatic void
18888c2ecf20Sopenharmony_ciqla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
18898c2ecf20Sopenharmony_ci    sts_entry_t *pkt, int iocb_type)
18908c2ecf20Sopenharmony_ci{
18918c2ecf20Sopenharmony_ci	const char func[] = "CT_IOCB";
18928c2ecf20Sopenharmony_ci	const char *type;
18938c2ecf20Sopenharmony_ci	srb_t *sp;
18948c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job;
18958c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
18968c2ecf20Sopenharmony_ci	uint16_t comp_status;
18978c2ecf20Sopenharmony_ci	int res = 0;
18988c2ecf20Sopenharmony_ci
18998c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
19008c2ecf20Sopenharmony_ci	if (!sp)
19018c2ecf20Sopenharmony_ci		return;
19028c2ecf20Sopenharmony_ci
19038c2ecf20Sopenharmony_ci	switch (sp->type) {
19048c2ecf20Sopenharmony_ci	case SRB_CT_CMD:
19058c2ecf20Sopenharmony_ci	    bsg_job = sp->u.bsg_job;
19068c2ecf20Sopenharmony_ci	    bsg_reply = bsg_job->reply;
19078c2ecf20Sopenharmony_ci
19088c2ecf20Sopenharmony_ci	    type = "ct pass-through";
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	    comp_status = le16_to_cpu(pkt->comp_status);
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_ci	    /*
19138c2ecf20Sopenharmony_ci	     * return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
19148c2ecf20Sopenharmony_ci	     * fc payload  to the caller
19158c2ecf20Sopenharmony_ci	     */
19168c2ecf20Sopenharmony_ci	    bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
19178c2ecf20Sopenharmony_ci	    bsg_job->reply_len = sizeof(struct fc_bsg_reply);
19188c2ecf20Sopenharmony_ci
19198c2ecf20Sopenharmony_ci	    if (comp_status != CS_COMPLETE) {
19208c2ecf20Sopenharmony_ci		    if (comp_status == CS_DATA_UNDERRUN) {
19218c2ecf20Sopenharmony_ci			    res = DID_OK << 16;
19228c2ecf20Sopenharmony_ci			    bsg_reply->reply_payload_rcv_len =
19238c2ecf20Sopenharmony_ci				le16_to_cpu(pkt->rsp_info_len);
19248c2ecf20Sopenharmony_ci
19258c2ecf20Sopenharmony_ci			    ql_log(ql_log_warn, vha, 0x5048,
19268c2ecf20Sopenharmony_ci				"CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n",
19278c2ecf20Sopenharmony_ci				type, comp_status,
19288c2ecf20Sopenharmony_ci				bsg_reply->reply_payload_rcv_len);
19298c2ecf20Sopenharmony_ci		    } else {
19308c2ecf20Sopenharmony_ci			    ql_log(ql_log_warn, vha, 0x5049,
19318c2ecf20Sopenharmony_ci				"CT pass-through-%s error comp_status=0x%x.\n",
19328c2ecf20Sopenharmony_ci				type, comp_status);
19338c2ecf20Sopenharmony_ci			    res = DID_ERROR << 16;
19348c2ecf20Sopenharmony_ci			    bsg_reply->reply_payload_rcv_len = 0;
19358c2ecf20Sopenharmony_ci		    }
19368c2ecf20Sopenharmony_ci		    ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
19378c2ecf20Sopenharmony_ci			pkt, sizeof(*pkt));
19388c2ecf20Sopenharmony_ci	    } else {
19398c2ecf20Sopenharmony_ci		    res = DID_OK << 16;
19408c2ecf20Sopenharmony_ci		    bsg_reply->reply_payload_rcv_len =
19418c2ecf20Sopenharmony_ci			bsg_job->reply_payload.payload_len;
19428c2ecf20Sopenharmony_ci		    bsg_job->reply_len = 0;
19438c2ecf20Sopenharmony_ci	    }
19448c2ecf20Sopenharmony_ci	    break;
19458c2ecf20Sopenharmony_ci	case SRB_CT_PTHRU_CMD:
19468c2ecf20Sopenharmony_ci	    /*
19478c2ecf20Sopenharmony_ci	     * borrowing sts_entry_24xx.comp_status.
19488c2ecf20Sopenharmony_ci	     * same location as ct_entry_24xx.comp_status
19498c2ecf20Sopenharmony_ci	     */
19508c2ecf20Sopenharmony_ci	     res = qla2x00_chk_ms_status(vha, (ms_iocb_entry_t *)pkt,
19518c2ecf20Sopenharmony_ci		 (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
19528c2ecf20Sopenharmony_ci		 sp->name);
19538c2ecf20Sopenharmony_ci	     break;
19548c2ecf20Sopenharmony_ci	}
19558c2ecf20Sopenharmony_ci
19568c2ecf20Sopenharmony_ci	sp->done(sp, res);
19578c2ecf20Sopenharmony_ci}
19588c2ecf20Sopenharmony_ci
19598c2ecf20Sopenharmony_cistatic void
19608c2ecf20Sopenharmony_ciqla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
19618c2ecf20Sopenharmony_ci    struct sts_entry_24xx *pkt, int iocb_type)
19628c2ecf20Sopenharmony_ci{
19638c2ecf20Sopenharmony_ci	struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt;
19648c2ecf20Sopenharmony_ci	const char func[] = "ELS_CT_IOCB";
19658c2ecf20Sopenharmony_ci	const char *type;
19668c2ecf20Sopenharmony_ci	srb_t *sp;
19678c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job;
19688c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
19698c2ecf20Sopenharmony_ci	uint16_t comp_status;
19708c2ecf20Sopenharmony_ci	uint32_t fw_status[3];
19718c2ecf20Sopenharmony_ci	int res;
19728c2ecf20Sopenharmony_ci	struct srb_iocb *els;
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
19758c2ecf20Sopenharmony_ci	if (!sp)
19768c2ecf20Sopenharmony_ci		return;
19778c2ecf20Sopenharmony_ci
19788c2ecf20Sopenharmony_ci	type = NULL;
19798c2ecf20Sopenharmony_ci	switch (sp->type) {
19808c2ecf20Sopenharmony_ci	case SRB_ELS_CMD_RPT:
19818c2ecf20Sopenharmony_ci	case SRB_ELS_CMD_HST:
19828c2ecf20Sopenharmony_ci		type = "els";
19838c2ecf20Sopenharmony_ci		break;
19848c2ecf20Sopenharmony_ci	case SRB_CT_CMD:
19858c2ecf20Sopenharmony_ci		type = "ct pass-through";
19868c2ecf20Sopenharmony_ci		break;
19878c2ecf20Sopenharmony_ci	case SRB_ELS_DCMD:
19888c2ecf20Sopenharmony_ci		type = "Driver ELS logo";
19898c2ecf20Sopenharmony_ci		if (iocb_type != ELS_IOCB_TYPE) {
19908c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x5047,
19918c2ecf20Sopenharmony_ci			    "Completing %s: (%p) type=%d.\n",
19928c2ecf20Sopenharmony_ci			    type, sp, sp->type);
19938c2ecf20Sopenharmony_ci			sp->done(sp, 0);
19948c2ecf20Sopenharmony_ci			return;
19958c2ecf20Sopenharmony_ci		}
19968c2ecf20Sopenharmony_ci		break;
19978c2ecf20Sopenharmony_ci	case SRB_CT_PTHRU_CMD:
19988c2ecf20Sopenharmony_ci		/* borrowing sts_entry_24xx.comp_status.
19998c2ecf20Sopenharmony_ci		   same location as ct_entry_24xx.comp_status
20008c2ecf20Sopenharmony_ci		 */
20018c2ecf20Sopenharmony_ci		res = qla2x00_chk_ms_status(sp->vha, (ms_iocb_entry_t *)pkt,
20028c2ecf20Sopenharmony_ci			(struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
20038c2ecf20Sopenharmony_ci			sp->name);
20048c2ecf20Sopenharmony_ci		sp->done(sp, res);
20058c2ecf20Sopenharmony_ci		return;
20068c2ecf20Sopenharmony_ci	default:
20078c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x503e,
20088c2ecf20Sopenharmony_ci		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
20098c2ecf20Sopenharmony_ci		return;
20108c2ecf20Sopenharmony_ci	}
20118c2ecf20Sopenharmony_ci
20128c2ecf20Sopenharmony_ci	comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
20138c2ecf20Sopenharmony_ci	fw_status[1] = le32_to_cpu(ese->error_subcode_1);
20148c2ecf20Sopenharmony_ci	fw_status[2] = le32_to_cpu(ese->error_subcode_2);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	if (iocb_type == ELS_IOCB_TYPE) {
20178c2ecf20Sopenharmony_ci		els = &sp->u.iocb_cmd;
20188c2ecf20Sopenharmony_ci		els->u.els_plogi.fw_status[0] = cpu_to_le32(fw_status[0]);
20198c2ecf20Sopenharmony_ci		els->u.els_plogi.fw_status[1] = cpu_to_le32(fw_status[1]);
20208c2ecf20Sopenharmony_ci		els->u.els_plogi.fw_status[2] = cpu_to_le32(fw_status[2]);
20218c2ecf20Sopenharmony_ci		els->u.els_plogi.comp_status = cpu_to_le16(fw_status[0]);
20228c2ecf20Sopenharmony_ci		if (comp_status == CS_COMPLETE) {
20238c2ecf20Sopenharmony_ci			res =  DID_OK << 16;
20248c2ecf20Sopenharmony_ci		} else {
20258c2ecf20Sopenharmony_ci			if (comp_status == CS_DATA_UNDERRUN) {
20268c2ecf20Sopenharmony_ci				res =  DID_OK << 16;
20278c2ecf20Sopenharmony_ci				els->u.els_plogi.len = cpu_to_le16(le32_to_cpu(
20288c2ecf20Sopenharmony_ci					ese->total_byte_count));
20298c2ecf20Sopenharmony_ci			} else {
20308c2ecf20Sopenharmony_ci				els->u.els_plogi.len = 0;
20318c2ecf20Sopenharmony_ci				res = DID_ERROR << 16;
20328c2ecf20Sopenharmony_ci			}
20338c2ecf20Sopenharmony_ci		}
20348c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_disc, vha, 0x503f,
20358c2ecf20Sopenharmony_ci		    "ELS IOCB Done -%s hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n",
20368c2ecf20Sopenharmony_ci		    type, sp->handle, comp_status, fw_status[1], fw_status[2],
20378c2ecf20Sopenharmony_ci		    le32_to_cpu(ese->total_byte_count));
20388c2ecf20Sopenharmony_ci		goto els_ct_done;
20398c2ecf20Sopenharmony_ci	}
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
20428c2ecf20Sopenharmony_ci	 * fc payload  to the caller
20438c2ecf20Sopenharmony_ci	 */
20448c2ecf20Sopenharmony_ci	bsg_job = sp->u.bsg_job;
20458c2ecf20Sopenharmony_ci	bsg_reply = bsg_job->reply;
20468c2ecf20Sopenharmony_ci	bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
20478c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
20488c2ecf20Sopenharmony_ci
20498c2ecf20Sopenharmony_ci	if (comp_status != CS_COMPLETE) {
20508c2ecf20Sopenharmony_ci		if (comp_status == CS_DATA_UNDERRUN) {
20518c2ecf20Sopenharmony_ci			res = DID_OK << 16;
20528c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
20538c2ecf20Sopenharmony_ci				le32_to_cpu(ese->total_byte_count);
20548c2ecf20Sopenharmony_ci
20558c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x503f,
20568c2ecf20Sopenharmony_ci			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
20578c2ecf20Sopenharmony_ci			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
20588c2ecf20Sopenharmony_ci			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
20598c2ecf20Sopenharmony_ci			    le32_to_cpu(ese->total_byte_count));
20608c2ecf20Sopenharmony_ci		} else {
20618c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x5040,
20628c2ecf20Sopenharmony_ci			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
20638c2ecf20Sopenharmony_ci			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
20648c2ecf20Sopenharmony_ci			    type, sp->handle, comp_status,
20658c2ecf20Sopenharmony_ci			    le32_to_cpu(ese->error_subcode_1),
20668c2ecf20Sopenharmony_ci			    le32_to_cpu(ese->error_subcode_2));
20678c2ecf20Sopenharmony_ci			res = DID_ERROR << 16;
20688c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len = 0;
20698c2ecf20Sopenharmony_ci		}
20708c2ecf20Sopenharmony_ci		memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply),
20718c2ecf20Sopenharmony_ci		       fw_status, sizeof(fw_status));
20728c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
20738c2ecf20Sopenharmony_ci		    pkt, sizeof(*pkt));
20748c2ecf20Sopenharmony_ci	}
20758c2ecf20Sopenharmony_ci	else {
20768c2ecf20Sopenharmony_ci		res =  DID_OK << 16;
20778c2ecf20Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
20788c2ecf20Sopenharmony_ci		bsg_job->reply_len = 0;
20798c2ecf20Sopenharmony_ci	}
20808c2ecf20Sopenharmony_ciels_ct_done:
20818c2ecf20Sopenharmony_ci
20828c2ecf20Sopenharmony_ci	sp->done(sp, res);
20838c2ecf20Sopenharmony_ci}
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_cistatic void
20868c2ecf20Sopenharmony_ciqla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
20878c2ecf20Sopenharmony_ci    struct logio_entry_24xx *logio)
20888c2ecf20Sopenharmony_ci{
20898c2ecf20Sopenharmony_ci	const char func[] = "LOGIO-IOCB";
20908c2ecf20Sopenharmony_ci	const char *type;
20918c2ecf20Sopenharmony_ci	fc_port_t *fcport;
20928c2ecf20Sopenharmony_ci	srb_t *sp;
20938c2ecf20Sopenharmony_ci	struct srb_iocb *lio;
20948c2ecf20Sopenharmony_ci	uint16_t *data;
20958c2ecf20Sopenharmony_ci	uint32_t iop[2];
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
20988c2ecf20Sopenharmony_ci	if (!sp)
20998c2ecf20Sopenharmony_ci		return;
21008c2ecf20Sopenharmony_ci
21018c2ecf20Sopenharmony_ci	lio = &sp->u.iocb_cmd;
21028c2ecf20Sopenharmony_ci	type = sp->name;
21038c2ecf20Sopenharmony_ci	fcport = sp->fcport;
21048c2ecf20Sopenharmony_ci	data = lio->u.logio.data;
21058c2ecf20Sopenharmony_ci
21068c2ecf20Sopenharmony_ci	data[0] = MBS_COMMAND_ERROR;
21078c2ecf20Sopenharmony_ci	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
21088c2ecf20Sopenharmony_ci		QLA_LOGIO_LOGIN_RETRIED : 0;
21098c2ecf20Sopenharmony_ci	if (logio->entry_status) {
21108c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5034,
21118c2ecf20Sopenharmony_ci		    "Async-%s error entry - %8phC hdl=%x"
21128c2ecf20Sopenharmony_ci		    "portid=%02x%02x%02x entry-status=%x.\n",
21138c2ecf20Sopenharmony_ci		    type, fcport->port_name, sp->handle, fcport->d_id.b.domain,
21148c2ecf20Sopenharmony_ci		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
21158c2ecf20Sopenharmony_ci		    logio->entry_status);
21168c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
21178c2ecf20Sopenharmony_ci		    logio, sizeof(*logio));
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci		goto logio_done;
21208c2ecf20Sopenharmony_ci	}
21218c2ecf20Sopenharmony_ci
21228c2ecf20Sopenharmony_ci	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
21238c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, sp->vha, 0x5036,
21248c2ecf20Sopenharmony_ci		    "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n",
21258c2ecf20Sopenharmony_ci		    type, sp->handle, fcport->d_id.b24, fcport->port_name,
21268c2ecf20Sopenharmony_ci		    le32_to_cpu(logio->io_parameter[0]));
21278c2ecf20Sopenharmony_ci
21288c2ecf20Sopenharmony_ci		vha->hw->exch_starvation = 0;
21298c2ecf20Sopenharmony_ci		data[0] = MBS_COMMAND_COMPLETE;
21308c2ecf20Sopenharmony_ci
21318c2ecf20Sopenharmony_ci		if (sp->type == SRB_PRLI_CMD) {
21328c2ecf20Sopenharmony_ci			lio->u.logio.iop[0] =
21338c2ecf20Sopenharmony_ci			    le32_to_cpu(logio->io_parameter[0]);
21348c2ecf20Sopenharmony_ci			lio->u.logio.iop[1] =
21358c2ecf20Sopenharmony_ci			    le32_to_cpu(logio->io_parameter[1]);
21368c2ecf20Sopenharmony_ci			goto logio_done;
21378c2ecf20Sopenharmony_ci		}
21388c2ecf20Sopenharmony_ci
21398c2ecf20Sopenharmony_ci		if (sp->type != SRB_LOGIN_CMD)
21408c2ecf20Sopenharmony_ci			goto logio_done;
21418c2ecf20Sopenharmony_ci
21428c2ecf20Sopenharmony_ci		iop[0] = le32_to_cpu(logio->io_parameter[0]);
21438c2ecf20Sopenharmony_ci		if (iop[0] & BIT_4) {
21448c2ecf20Sopenharmony_ci			fcport->port_type = FCT_TARGET;
21458c2ecf20Sopenharmony_ci			if (iop[0] & BIT_8)
21468c2ecf20Sopenharmony_ci				fcport->flags |= FCF_FCP2_DEVICE;
21478c2ecf20Sopenharmony_ci		} else if (iop[0] & BIT_5)
21488c2ecf20Sopenharmony_ci			fcport->port_type = FCT_INITIATOR;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		if (iop[0] & BIT_7)
21518c2ecf20Sopenharmony_ci			fcport->flags |= FCF_CONF_COMP_SUPPORTED;
21528c2ecf20Sopenharmony_ci
21538c2ecf20Sopenharmony_ci		if (logio->io_parameter[7] || logio->io_parameter[8])
21548c2ecf20Sopenharmony_ci			fcport->supported_classes |= FC_COS_CLASS2;
21558c2ecf20Sopenharmony_ci		if (logio->io_parameter[9] || logio->io_parameter[10])
21568c2ecf20Sopenharmony_ci			fcport->supported_classes |= FC_COS_CLASS3;
21578c2ecf20Sopenharmony_ci
21588c2ecf20Sopenharmony_ci		goto logio_done;
21598c2ecf20Sopenharmony_ci	}
21608c2ecf20Sopenharmony_ci
21618c2ecf20Sopenharmony_ci	iop[0] = le32_to_cpu(logio->io_parameter[0]);
21628c2ecf20Sopenharmony_ci	iop[1] = le32_to_cpu(logio->io_parameter[1]);
21638c2ecf20Sopenharmony_ci	lio->u.logio.iop[0] = iop[0];
21648c2ecf20Sopenharmony_ci	lio->u.logio.iop[1] = iop[1];
21658c2ecf20Sopenharmony_ci	switch (iop[0]) {
21668c2ecf20Sopenharmony_ci	case LSC_SCODE_PORTID_USED:
21678c2ecf20Sopenharmony_ci		data[0] = MBS_PORT_ID_USED;
21688c2ecf20Sopenharmony_ci		data[1] = LSW(iop[1]);
21698c2ecf20Sopenharmony_ci		break;
21708c2ecf20Sopenharmony_ci	case LSC_SCODE_NPORT_USED:
21718c2ecf20Sopenharmony_ci		data[0] = MBS_LOOP_ID_USED;
21728c2ecf20Sopenharmony_ci		break;
21738c2ecf20Sopenharmony_ci	case LSC_SCODE_CMD_FAILED:
21748c2ecf20Sopenharmony_ci		if (iop[1] == 0x0606) {
21758c2ecf20Sopenharmony_ci			/*
21768c2ecf20Sopenharmony_ci			 * PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI,
21778c2ecf20Sopenharmony_ci			 * Target side acked.
21788c2ecf20Sopenharmony_ci			 */
21798c2ecf20Sopenharmony_ci			data[0] = MBS_COMMAND_COMPLETE;
21808c2ecf20Sopenharmony_ci			goto logio_done;
21818c2ecf20Sopenharmony_ci		}
21828c2ecf20Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
21838c2ecf20Sopenharmony_ci		break;
21848c2ecf20Sopenharmony_ci	case LSC_SCODE_NOXCB:
21858c2ecf20Sopenharmony_ci		vha->hw->exch_starvation++;
21868c2ecf20Sopenharmony_ci		if (vha->hw->exch_starvation > 5) {
21878c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xd046,
21888c2ecf20Sopenharmony_ci			    "Exchange starvation. Resetting RISC\n");
21898c2ecf20Sopenharmony_ci
21908c2ecf20Sopenharmony_ci			vha->hw->exch_starvation = 0;
21918c2ecf20Sopenharmony_ci
21928c2ecf20Sopenharmony_ci			if (IS_P3P_TYPE(vha->hw))
21938c2ecf20Sopenharmony_ci				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
21948c2ecf20Sopenharmony_ci			else
21958c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
21968c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
21978c2ecf20Sopenharmony_ci		}
21988c2ecf20Sopenharmony_ci		fallthrough;
21998c2ecf20Sopenharmony_ci	default:
22008c2ecf20Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
22018c2ecf20Sopenharmony_ci		break;
22028c2ecf20Sopenharmony_ci	}
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_async, sp->vha, 0x5037,
22058c2ecf20Sopenharmony_ci	    "Async-%s failed: handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
22068c2ecf20Sopenharmony_ci	    type, sp->handle, fcport->d_id.b24, fcport->port_name,
22078c2ecf20Sopenharmony_ci	    le16_to_cpu(logio->comp_status),
22088c2ecf20Sopenharmony_ci	    le32_to_cpu(logio->io_parameter[0]),
22098c2ecf20Sopenharmony_ci	    le32_to_cpu(logio->io_parameter[1]));
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_cilogio_done:
22128c2ecf20Sopenharmony_ci	sp->done(sp, 0);
22138c2ecf20Sopenharmony_ci}
22148c2ecf20Sopenharmony_ci
22158c2ecf20Sopenharmony_cistatic void
22168c2ecf20Sopenharmony_ciqla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
22178c2ecf20Sopenharmony_ci{
22188c2ecf20Sopenharmony_ci	const char func[] = "TMF-IOCB";
22198c2ecf20Sopenharmony_ci	const char *type;
22208c2ecf20Sopenharmony_ci	fc_port_t *fcport;
22218c2ecf20Sopenharmony_ci	srb_t *sp;
22228c2ecf20Sopenharmony_ci	struct srb_iocb *iocb;
22238c2ecf20Sopenharmony_ci	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
22248c2ecf20Sopenharmony_ci
22258c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
22268c2ecf20Sopenharmony_ci	if (!sp)
22278c2ecf20Sopenharmony_ci		return;
22288c2ecf20Sopenharmony_ci
22298c2ecf20Sopenharmony_ci	iocb = &sp->u.iocb_cmd;
22308c2ecf20Sopenharmony_ci	type = sp->name;
22318c2ecf20Sopenharmony_ci	fcport = sp->fcport;
22328c2ecf20Sopenharmony_ci	iocb->u.tmf.data = QLA_SUCCESS;
22338c2ecf20Sopenharmony_ci
22348c2ecf20Sopenharmony_ci	if (sts->entry_status) {
22358c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5038,
22368c2ecf20Sopenharmony_ci		    "Async-%s error - hdl=%x entry-status(%x).\n",
22378c2ecf20Sopenharmony_ci		    type, sp->handle, sts->entry_status);
22388c2ecf20Sopenharmony_ci		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
22398c2ecf20Sopenharmony_ci	} else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
22408c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5039,
22418c2ecf20Sopenharmony_ci		    "Async-%s error - hdl=%x completion status(%x).\n",
22428c2ecf20Sopenharmony_ci		    type, sp->handle, sts->comp_status);
22438c2ecf20Sopenharmony_ci		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
22448c2ecf20Sopenharmony_ci	} else if ((le16_to_cpu(sts->scsi_status) &
22458c2ecf20Sopenharmony_ci	    SS_RESPONSE_INFO_LEN_VALID)) {
22468c2ecf20Sopenharmony_ci		host_to_fcp_swap(sts->data, sizeof(sts->data));
22478c2ecf20Sopenharmony_ci		if (le32_to_cpu(sts->rsp_data_len) < 4) {
22488c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x503b,
22498c2ecf20Sopenharmony_ci			    "Async-%s error - hdl=%x not enough response(%d).\n",
22508c2ecf20Sopenharmony_ci			    type, sp->handle, sts->rsp_data_len);
22518c2ecf20Sopenharmony_ci		} else if (sts->data[3]) {
22528c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x503c,
22538c2ecf20Sopenharmony_ci			    "Async-%s error - hdl=%x response(%x).\n",
22548c2ecf20Sopenharmony_ci			    type, sp->handle, sts->data[3]);
22558c2ecf20Sopenharmony_ci			iocb->u.tmf.data = QLA_FUNCTION_FAILED;
22568c2ecf20Sopenharmony_ci		}
22578c2ecf20Sopenharmony_ci	}
22588c2ecf20Sopenharmony_ci
22598c2ecf20Sopenharmony_ci	if (iocb->u.tmf.data != QLA_SUCCESS)
22608c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
22618c2ecf20Sopenharmony_ci		    sts, sizeof(*sts));
22628c2ecf20Sopenharmony_ci
22638c2ecf20Sopenharmony_ci	sp->done(sp, 0);
22648c2ecf20Sopenharmony_ci}
22658c2ecf20Sopenharmony_ci
22668c2ecf20Sopenharmony_cistatic void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
22678c2ecf20Sopenharmony_ci    void *tsk, srb_t *sp)
22688c2ecf20Sopenharmony_ci{
22698c2ecf20Sopenharmony_ci	fc_port_t *fcport;
22708c2ecf20Sopenharmony_ci	struct srb_iocb *iocb;
22718c2ecf20Sopenharmony_ci	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
22728c2ecf20Sopenharmony_ci	uint16_t        state_flags;
22738c2ecf20Sopenharmony_ci	struct nvmefc_fcp_req *fd;
22748c2ecf20Sopenharmony_ci	uint16_t        ret = QLA_SUCCESS;
22758c2ecf20Sopenharmony_ci	__le16		comp_status = sts->comp_status;
22768c2ecf20Sopenharmony_ci	int		logit = 0;
22778c2ecf20Sopenharmony_ci
22788c2ecf20Sopenharmony_ci	iocb = &sp->u.iocb_cmd;
22798c2ecf20Sopenharmony_ci	fcport = sp->fcport;
22808c2ecf20Sopenharmony_ci	iocb->u.nvme.comp_status = comp_status;
22818c2ecf20Sopenharmony_ci	state_flags  = le16_to_cpu(sts->state_flags);
22828c2ecf20Sopenharmony_ci	fd = iocb->u.nvme.desc;
22838c2ecf20Sopenharmony_ci
22848c2ecf20Sopenharmony_ci	if (unlikely(iocb->u.nvme.aen_op))
22858c2ecf20Sopenharmony_ci		atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci	if (unlikely(comp_status != CS_COMPLETE))
22888c2ecf20Sopenharmony_ci		logit = 1;
22898c2ecf20Sopenharmony_ci
22908c2ecf20Sopenharmony_ci	fd->transferred_length = fd->payload_length -
22918c2ecf20Sopenharmony_ci	    le32_to_cpu(sts->residual_len);
22928c2ecf20Sopenharmony_ci
22938c2ecf20Sopenharmony_ci	/*
22948c2ecf20Sopenharmony_ci	 * State flags: Bit 6 and 0.
22958c2ecf20Sopenharmony_ci	 * If 0 is set, we don't care about 6.
22968c2ecf20Sopenharmony_ci	 * both cases resp was dma'd to host buffer
22978c2ecf20Sopenharmony_ci	 * if both are 0, that is good path case.
22988c2ecf20Sopenharmony_ci	 * if six is set and 0 is clear, we need to
22998c2ecf20Sopenharmony_ci	 * copy resp data from status iocb to resp buffer.
23008c2ecf20Sopenharmony_ci	 */
23018c2ecf20Sopenharmony_ci	if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) {
23028c2ecf20Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
23038c2ecf20Sopenharmony_ci	} else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) ==
23048c2ecf20Sopenharmony_ci			(SF_FCP_RSP_DMA | SF_NVME_ERSP)) {
23058c2ecf20Sopenharmony_ci		/* Response already DMA'd to fd->rspaddr. */
23068c2ecf20Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
23078c2ecf20Sopenharmony_ci	} else if ((state_flags & SF_FCP_RSP_DMA)) {
23088c2ecf20Sopenharmony_ci		/*
23098c2ecf20Sopenharmony_ci		 * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this
23108c2ecf20Sopenharmony_ci		 * as an error.
23118c2ecf20Sopenharmony_ci		 */
23128c2ecf20Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
23138c2ecf20Sopenharmony_ci		fd->transferred_length = 0;
23148c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x307a,
23158c2ecf20Sopenharmony_ci			"Unexpected values in NVMe_RSP IU.\n");
23168c2ecf20Sopenharmony_ci		logit = 1;
23178c2ecf20Sopenharmony_ci	} else if (state_flags & SF_NVME_ERSP) {
23188c2ecf20Sopenharmony_ci		uint32_t *inbuf, *outbuf;
23198c2ecf20Sopenharmony_ci		uint16_t iter;
23208c2ecf20Sopenharmony_ci
23218c2ecf20Sopenharmony_ci		inbuf = (uint32_t *)&sts->nvme_ersp_data;
23228c2ecf20Sopenharmony_ci		outbuf = (uint32_t *)fd->rspaddr;
23238c2ecf20Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
23248c2ecf20Sopenharmony_ci		if (unlikely(le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >
23258c2ecf20Sopenharmony_ci		    sizeof(struct nvme_fc_ersp_iu))) {
23268c2ecf20Sopenharmony_ci			if (ql_mask_match(ql_dbg_io)) {
23278c2ecf20Sopenharmony_ci				WARN_ONCE(1, "Unexpected response payload length %u.\n",
23288c2ecf20Sopenharmony_ci				    iocb->u.nvme.rsp_pyld_len);
23298c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, fcport->vha, 0x5100,
23308c2ecf20Sopenharmony_ci				    "Unexpected response payload length %u.\n",
23318c2ecf20Sopenharmony_ci				    iocb->u.nvme.rsp_pyld_len);
23328c2ecf20Sopenharmony_ci			}
23338c2ecf20Sopenharmony_ci			iocb->u.nvme.rsp_pyld_len =
23348c2ecf20Sopenharmony_ci				cpu_to_le16(sizeof(struct nvme_fc_ersp_iu));
23358c2ecf20Sopenharmony_ci		}
23368c2ecf20Sopenharmony_ci		iter = le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >> 2;
23378c2ecf20Sopenharmony_ci		for (; iter; iter--)
23388c2ecf20Sopenharmony_ci			*outbuf++ = swab32(*inbuf++);
23398c2ecf20Sopenharmony_ci	}
23408c2ecf20Sopenharmony_ci
23418c2ecf20Sopenharmony_ci	if (state_flags & SF_NVME_ERSP) {
23428c2ecf20Sopenharmony_ci		struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr;
23438c2ecf20Sopenharmony_ci		u32 tgt_xfer_len;
23448c2ecf20Sopenharmony_ci
23458c2ecf20Sopenharmony_ci		tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len);
23468c2ecf20Sopenharmony_ci		if (fd->transferred_length != tgt_xfer_len) {
23478c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3079,
23488c2ecf20Sopenharmony_ci				"Dropped frame(s) detected (sent/rcvd=%u/%u).\n",
23498c2ecf20Sopenharmony_ci				tgt_xfer_len, fd->transferred_length);
23508c2ecf20Sopenharmony_ci			logit = 1;
23518c2ecf20Sopenharmony_ci		} else if (le16_to_cpu(comp_status) == CS_DATA_UNDERRUN) {
23528c2ecf20Sopenharmony_ci			/*
23538c2ecf20Sopenharmony_ci			 * Do not log if this is just an underflow and there
23548c2ecf20Sopenharmony_ci			 * is no data loss.
23558c2ecf20Sopenharmony_ci			 */
23568c2ecf20Sopenharmony_ci			logit = 0;
23578c2ecf20Sopenharmony_ci		}
23588c2ecf20Sopenharmony_ci	}
23598c2ecf20Sopenharmony_ci
23608c2ecf20Sopenharmony_ci	if (unlikely(logit))
23618c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5060,
23628c2ecf20Sopenharmony_ci		   "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x  ox_id=%x\n",
23638c2ecf20Sopenharmony_ci		   sp->name, sp->handle, comp_status,
23648c2ecf20Sopenharmony_ci		   fd->transferred_length, le32_to_cpu(sts->residual_len),
23658c2ecf20Sopenharmony_ci		   sts->ox_id);
23668c2ecf20Sopenharmony_ci
23678c2ecf20Sopenharmony_ci	/*
23688c2ecf20Sopenharmony_ci	 * If transport error then Failure (HBA rejects request)
23698c2ecf20Sopenharmony_ci	 * otherwise transport will handle.
23708c2ecf20Sopenharmony_ci	 */
23718c2ecf20Sopenharmony_ci	switch (le16_to_cpu(comp_status)) {
23728c2ecf20Sopenharmony_ci	case CS_COMPLETE:
23738c2ecf20Sopenharmony_ci		break;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci	case CS_RESET:
23768c2ecf20Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
23778c2ecf20Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
23788c2ecf20Sopenharmony_ci		fcport->nvme_flag |= NVME_FLAG_RESETTING;
23798c2ecf20Sopenharmony_ci		fallthrough;
23808c2ecf20Sopenharmony_ci	case CS_ABORTED:
23818c2ecf20Sopenharmony_ci	case CS_PORT_BUSY:
23828c2ecf20Sopenharmony_ci		fd->transferred_length = 0;
23838c2ecf20Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
23848c2ecf20Sopenharmony_ci		ret = QLA_ABORTED;
23858c2ecf20Sopenharmony_ci		break;
23868c2ecf20Sopenharmony_ci	case CS_DATA_UNDERRUN:
23878c2ecf20Sopenharmony_ci		break;
23888c2ecf20Sopenharmony_ci	default:
23898c2ecf20Sopenharmony_ci		ret = QLA_FUNCTION_FAILED;
23908c2ecf20Sopenharmony_ci		break;
23918c2ecf20Sopenharmony_ci	}
23928c2ecf20Sopenharmony_ci	sp->done(sp, ret);
23938c2ecf20Sopenharmony_ci}
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_cistatic void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
23968c2ecf20Sopenharmony_ci    struct vp_ctrl_entry_24xx *vce)
23978c2ecf20Sopenharmony_ci{
23988c2ecf20Sopenharmony_ci	const char func[] = "CTRLVP-IOCB";
23998c2ecf20Sopenharmony_ci	srb_t *sp;
24008c2ecf20Sopenharmony_ci	int rval = QLA_SUCCESS;
24018c2ecf20Sopenharmony_ci
24028c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, vce);
24038c2ecf20Sopenharmony_ci	if (!sp)
24048c2ecf20Sopenharmony_ci		return;
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci	if (vce->entry_status != 0) {
24078c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c4,
24088c2ecf20Sopenharmony_ci		    "%s: Failed to complete IOCB -- error status (%x)\n",
24098c2ecf20Sopenharmony_ci		    sp->name, vce->entry_status);
24108c2ecf20Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
24118c2ecf20Sopenharmony_ci	} else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) {
24128c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c5,
24138c2ecf20Sopenharmony_ci		    "%s: Failed to complete IOCB -- completion status (%x) vpidx %x\n",
24148c2ecf20Sopenharmony_ci		    sp->name, le16_to_cpu(vce->comp_status),
24158c2ecf20Sopenharmony_ci		    le16_to_cpu(vce->vp_idx_failed));
24168c2ecf20Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
24178c2ecf20Sopenharmony_ci	} else {
24188c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c6,
24198c2ecf20Sopenharmony_ci		    "Done %s.\n", __func__);
24208c2ecf20Sopenharmony_ci	}
24218c2ecf20Sopenharmony_ci
24228c2ecf20Sopenharmony_ci	sp->rc = rval;
24238c2ecf20Sopenharmony_ci	sp->done(sp, rval);
24248c2ecf20Sopenharmony_ci}
24258c2ecf20Sopenharmony_ci
24268c2ecf20Sopenharmony_ci/* Process a single response queue entry. */
24278c2ecf20Sopenharmony_cistatic void qla2x00_process_response_entry(struct scsi_qla_host *vha,
24288c2ecf20Sopenharmony_ci					   struct rsp_que *rsp,
24298c2ecf20Sopenharmony_ci					   sts_entry_t *pkt)
24308c2ecf20Sopenharmony_ci{
24318c2ecf20Sopenharmony_ci	sts21_entry_t *sts21_entry;
24328c2ecf20Sopenharmony_ci	sts22_entry_t *sts22_entry;
24338c2ecf20Sopenharmony_ci	uint16_t handle_cnt;
24348c2ecf20Sopenharmony_ci	uint16_t cnt;
24358c2ecf20Sopenharmony_ci
24368c2ecf20Sopenharmony_ci	switch (pkt->entry_type) {
24378c2ecf20Sopenharmony_ci	case STATUS_TYPE:
24388c2ecf20Sopenharmony_ci		qla2x00_status_entry(vha, rsp, pkt);
24398c2ecf20Sopenharmony_ci		break;
24408c2ecf20Sopenharmony_ci	case STATUS_TYPE_21:
24418c2ecf20Sopenharmony_ci		sts21_entry = (sts21_entry_t *)pkt;
24428c2ecf20Sopenharmony_ci		handle_cnt = sts21_entry->handle_count;
24438c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
24448c2ecf20Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
24458c2ecf20Sopenharmony_ci						sts21_entry->handle[cnt]);
24468c2ecf20Sopenharmony_ci		break;
24478c2ecf20Sopenharmony_ci	case STATUS_TYPE_22:
24488c2ecf20Sopenharmony_ci		sts22_entry = (sts22_entry_t *)pkt;
24498c2ecf20Sopenharmony_ci		handle_cnt = sts22_entry->handle_count;
24508c2ecf20Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
24518c2ecf20Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
24528c2ecf20Sopenharmony_ci						sts22_entry->handle[cnt]);
24538c2ecf20Sopenharmony_ci		break;
24548c2ecf20Sopenharmony_ci	case STATUS_CONT_TYPE:
24558c2ecf20Sopenharmony_ci		qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
24568c2ecf20Sopenharmony_ci		break;
24578c2ecf20Sopenharmony_ci	case MBX_IOCB_TYPE:
24588c2ecf20Sopenharmony_ci		qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
24598c2ecf20Sopenharmony_ci		break;
24608c2ecf20Sopenharmony_ci	case CT_IOCB_TYPE:
24618c2ecf20Sopenharmony_ci		qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
24628c2ecf20Sopenharmony_ci		break;
24638c2ecf20Sopenharmony_ci	default:
24648c2ecf20Sopenharmony_ci		/* Type Not Supported. */
24658c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x504a,
24668c2ecf20Sopenharmony_ci		       "Received unknown response pkt type %x entry status=%x.\n",
24678c2ecf20Sopenharmony_ci		       pkt->entry_type, pkt->entry_status);
24688c2ecf20Sopenharmony_ci		break;
24698c2ecf20Sopenharmony_ci	}
24708c2ecf20Sopenharmony_ci}
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci/**
24738c2ecf20Sopenharmony_ci * qla2x00_process_response_queue() - Process response queue entries.
24748c2ecf20Sopenharmony_ci * @rsp: response queue
24758c2ecf20Sopenharmony_ci */
24768c2ecf20Sopenharmony_civoid
24778c2ecf20Sopenharmony_ciqla2x00_process_response_queue(struct rsp_que *rsp)
24788c2ecf20Sopenharmony_ci{
24798c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha;
24808c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
24818c2ecf20Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
24828c2ecf20Sopenharmony_ci	sts_entry_t	*pkt;
24838c2ecf20Sopenharmony_ci
24848c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
24858c2ecf20Sopenharmony_ci
24868c2ecf20Sopenharmony_ci	if (!vha->flags.online)
24878c2ecf20Sopenharmony_ci		return;
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
24908c2ecf20Sopenharmony_ci		pkt = (sts_entry_t *)rsp->ring_ptr;
24918c2ecf20Sopenharmony_ci
24928c2ecf20Sopenharmony_ci		rsp->ring_index++;
24938c2ecf20Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
24948c2ecf20Sopenharmony_ci			rsp->ring_index = 0;
24958c2ecf20Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
24968c2ecf20Sopenharmony_ci		} else {
24978c2ecf20Sopenharmony_ci			rsp->ring_ptr++;
24988c2ecf20Sopenharmony_ci		}
24998c2ecf20Sopenharmony_ci
25008c2ecf20Sopenharmony_ci		if (pkt->entry_status != 0) {
25018c2ecf20Sopenharmony_ci			qla2x00_error_entry(vha, rsp, pkt);
25028c2ecf20Sopenharmony_ci			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
25038c2ecf20Sopenharmony_ci			wmb();
25048c2ecf20Sopenharmony_ci			continue;
25058c2ecf20Sopenharmony_ci		}
25068c2ecf20Sopenharmony_ci
25078c2ecf20Sopenharmony_ci		qla2x00_process_response_entry(vha, rsp, pkt);
25088c2ecf20Sopenharmony_ci		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
25098c2ecf20Sopenharmony_ci		wmb();
25108c2ecf20Sopenharmony_ci	}
25118c2ecf20Sopenharmony_ci
25128c2ecf20Sopenharmony_ci	/* Adjust ring index */
25138c2ecf20Sopenharmony_ci	wrt_reg_word(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
25148c2ecf20Sopenharmony_ci}
25158c2ecf20Sopenharmony_ci
25168c2ecf20Sopenharmony_cistatic inline void
25178c2ecf20Sopenharmony_ciqla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
25188c2ecf20Sopenharmony_ci		     uint32_t sense_len, struct rsp_que *rsp, int res)
25198c2ecf20Sopenharmony_ci{
25208c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
25218c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp = GET_CMD_SP(sp);
25228c2ecf20Sopenharmony_ci	uint32_t track_sense_len;
25238c2ecf20Sopenharmony_ci
25248c2ecf20Sopenharmony_ci	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
25258c2ecf20Sopenharmony_ci		sense_len = SCSI_SENSE_BUFFERSIZE;
25268c2ecf20Sopenharmony_ci
25278c2ecf20Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
25288c2ecf20Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
25298c2ecf20Sopenharmony_ci	track_sense_len = sense_len;
25308c2ecf20Sopenharmony_ci
25318c2ecf20Sopenharmony_ci	if (sense_len > par_sense_len)
25328c2ecf20Sopenharmony_ci		sense_len = par_sense_len;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci	memcpy(cp->sense_buffer, sense_data, sense_len);
25358c2ecf20Sopenharmony_ci
25368c2ecf20Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
25378c2ecf20Sopenharmony_ci	track_sense_len -= sense_len;
25388c2ecf20Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, track_sense_len);
25398c2ecf20Sopenharmony_ci
25408c2ecf20Sopenharmony_ci	if (track_sense_len != 0) {
25418c2ecf20Sopenharmony_ci		rsp->status_srb = sp;
25428c2ecf20Sopenharmony_ci		cp->result = res;
25438c2ecf20Sopenharmony_ci	}
25448c2ecf20Sopenharmony_ci
25458c2ecf20Sopenharmony_ci	if (sense_len) {
25468c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
25478c2ecf20Sopenharmony_ci		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
25488c2ecf20Sopenharmony_ci		    sp->vha->host_no, cp->device->id, cp->device->lun,
25498c2ecf20Sopenharmony_ci		    cp);
25508c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
25518c2ecf20Sopenharmony_ci		    cp->sense_buffer, sense_len);
25528c2ecf20Sopenharmony_ci	}
25538c2ecf20Sopenharmony_ci}
25548c2ecf20Sopenharmony_ci
25558c2ecf20Sopenharmony_cistruct scsi_dif_tuple {
25568c2ecf20Sopenharmony_ci	__be16 guard;       /* Checksum */
25578c2ecf20Sopenharmony_ci	__be16 app_tag;         /* APPL identifier */
25588c2ecf20Sopenharmony_ci	__be32 ref_tag;         /* Target LBA or indirect LBA */
25598c2ecf20Sopenharmony_ci};
25608c2ecf20Sopenharmony_ci
25618c2ecf20Sopenharmony_ci/*
25628c2ecf20Sopenharmony_ci * Checks the guard or meta-data for the type of error
25638c2ecf20Sopenharmony_ci * detected by the HBA. In case of errors, we set the
25648c2ecf20Sopenharmony_ci * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
25658c2ecf20Sopenharmony_ci * to indicate to the kernel that the HBA detected error.
25668c2ecf20Sopenharmony_ci */
25678c2ecf20Sopenharmony_cistatic inline int
25688c2ecf20Sopenharmony_ciqla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
25698c2ecf20Sopenharmony_ci{
25708c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
25718c2ecf20Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
25728c2ecf20Sopenharmony_ci	uint8_t		*ap = &sts24->data[12];
25738c2ecf20Sopenharmony_ci	uint8_t		*ep = &sts24->data[20];
25748c2ecf20Sopenharmony_ci	uint32_t	e_ref_tag, a_ref_tag;
25758c2ecf20Sopenharmony_ci	uint16_t	e_app_tag, a_app_tag;
25768c2ecf20Sopenharmony_ci	uint16_t	e_guard, a_guard;
25778c2ecf20Sopenharmony_ci
25788c2ecf20Sopenharmony_ci	/*
25798c2ecf20Sopenharmony_ci	 * swab32 of the "data" field in the beginning of qla2x00_status_entry()
25808c2ecf20Sopenharmony_ci	 * would make guard field appear at offset 2
25818c2ecf20Sopenharmony_ci	 */
25828c2ecf20Sopenharmony_ci	a_guard   = get_unaligned_le16(ap + 2);
25838c2ecf20Sopenharmony_ci	a_app_tag = get_unaligned_le16(ap + 0);
25848c2ecf20Sopenharmony_ci	a_ref_tag = get_unaligned_le32(ap + 4);
25858c2ecf20Sopenharmony_ci	e_guard   = get_unaligned_le16(ep + 2);
25868c2ecf20Sopenharmony_ci	e_app_tag = get_unaligned_le16(ep + 0);
25878c2ecf20Sopenharmony_ci	e_ref_tag = get_unaligned_le32(ep + 4);
25888c2ecf20Sopenharmony_ci
25898c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3023,
25908c2ecf20Sopenharmony_ci	    "iocb(s) %p Returned STATUS.\n", sts24);
25918c2ecf20Sopenharmony_ci
25928c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3024,
25938c2ecf20Sopenharmony_ci	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
25948c2ecf20Sopenharmony_ci	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
25958c2ecf20Sopenharmony_ci	    " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
25968c2ecf20Sopenharmony_ci	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
25978c2ecf20Sopenharmony_ci	    a_app_tag, e_app_tag, a_guard, e_guard);
25988c2ecf20Sopenharmony_ci
25998c2ecf20Sopenharmony_ci	/*
26008c2ecf20Sopenharmony_ci	 * Ignore sector if:
26018c2ecf20Sopenharmony_ci	 * For type     3: ref & app tag is all 'f's
26028c2ecf20Sopenharmony_ci	 * For type 0,1,2: app tag is all 'f's
26038c2ecf20Sopenharmony_ci	 */
26048c2ecf20Sopenharmony_ci	if (a_app_tag == be16_to_cpu(T10_PI_APP_ESCAPE) &&
26058c2ecf20Sopenharmony_ci	    (scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3 ||
26068c2ecf20Sopenharmony_ci	     a_ref_tag == be32_to_cpu(T10_PI_REF_ESCAPE))) {
26078c2ecf20Sopenharmony_ci		uint32_t blocks_done, resid;
26088c2ecf20Sopenharmony_ci		sector_t lba_s = scsi_get_lba(cmd);
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci		/* 2TB boundary case covered automatically with this */
26118c2ecf20Sopenharmony_ci		blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci		resid = scsi_bufflen(cmd) - (blocks_done *
26148c2ecf20Sopenharmony_ci		    cmd->device->sector_size);
26158c2ecf20Sopenharmony_ci
26168c2ecf20Sopenharmony_ci		scsi_set_resid(cmd, resid);
26178c2ecf20Sopenharmony_ci		cmd->result = DID_OK << 16;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci		/* Update protection tag */
26208c2ecf20Sopenharmony_ci		if (scsi_prot_sg_count(cmd)) {
26218c2ecf20Sopenharmony_ci			uint32_t i, j = 0, k = 0, num_ent;
26228c2ecf20Sopenharmony_ci			struct scatterlist *sg;
26238c2ecf20Sopenharmony_ci			struct t10_pi_tuple *spt;
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci			/* Patch the corresponding protection tags */
26268c2ecf20Sopenharmony_ci			scsi_for_each_prot_sg(cmd, sg,
26278c2ecf20Sopenharmony_ci			    scsi_prot_sg_count(cmd), i) {
26288c2ecf20Sopenharmony_ci				num_ent = sg_dma_len(sg) / 8;
26298c2ecf20Sopenharmony_ci				if (k + num_ent < blocks_done) {
26308c2ecf20Sopenharmony_ci					k += num_ent;
26318c2ecf20Sopenharmony_ci					continue;
26328c2ecf20Sopenharmony_ci				}
26338c2ecf20Sopenharmony_ci				j = blocks_done - k - 1;
26348c2ecf20Sopenharmony_ci				k = blocks_done;
26358c2ecf20Sopenharmony_ci				break;
26368c2ecf20Sopenharmony_ci			}
26378c2ecf20Sopenharmony_ci
26388c2ecf20Sopenharmony_ci			if (k != blocks_done) {
26398c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x302f,
26408c2ecf20Sopenharmony_ci				    "unexpected tag values tag:lba=%x:%llx)\n",
26418c2ecf20Sopenharmony_ci				    e_ref_tag, (unsigned long long)lba_s);
26428c2ecf20Sopenharmony_ci				return 1;
26438c2ecf20Sopenharmony_ci			}
26448c2ecf20Sopenharmony_ci
26458c2ecf20Sopenharmony_ci			spt = page_address(sg_page(sg)) + sg->offset;
26468c2ecf20Sopenharmony_ci			spt += j;
26478c2ecf20Sopenharmony_ci
26488c2ecf20Sopenharmony_ci			spt->app_tag = T10_PI_APP_ESCAPE;
26498c2ecf20Sopenharmony_ci			if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
26508c2ecf20Sopenharmony_ci				spt->ref_tag = T10_PI_REF_ESCAPE;
26518c2ecf20Sopenharmony_ci		}
26528c2ecf20Sopenharmony_ci
26538c2ecf20Sopenharmony_ci		return 0;
26548c2ecf20Sopenharmony_ci	}
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	/* check guard */
26578c2ecf20Sopenharmony_ci	if (e_guard != a_guard) {
26588c2ecf20Sopenharmony_ci		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
26598c2ecf20Sopenharmony_ci		    0x10, 0x1);
26608c2ecf20Sopenharmony_ci		set_driver_byte(cmd, DRIVER_SENSE);
26618c2ecf20Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
26628c2ecf20Sopenharmony_ci		cmd->result |= SAM_STAT_CHECK_CONDITION;
26638c2ecf20Sopenharmony_ci		return 1;
26648c2ecf20Sopenharmony_ci	}
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	/* check ref tag */
26678c2ecf20Sopenharmony_ci	if (e_ref_tag != a_ref_tag) {
26688c2ecf20Sopenharmony_ci		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
26698c2ecf20Sopenharmony_ci		    0x10, 0x3);
26708c2ecf20Sopenharmony_ci		set_driver_byte(cmd, DRIVER_SENSE);
26718c2ecf20Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
26728c2ecf20Sopenharmony_ci		cmd->result |= SAM_STAT_CHECK_CONDITION;
26738c2ecf20Sopenharmony_ci		return 1;
26748c2ecf20Sopenharmony_ci	}
26758c2ecf20Sopenharmony_ci
26768c2ecf20Sopenharmony_ci	/* check appl tag */
26778c2ecf20Sopenharmony_ci	if (e_app_tag != a_app_tag) {
26788c2ecf20Sopenharmony_ci		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
26798c2ecf20Sopenharmony_ci		    0x10, 0x2);
26808c2ecf20Sopenharmony_ci		set_driver_byte(cmd, DRIVER_SENSE);
26818c2ecf20Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
26828c2ecf20Sopenharmony_ci		cmd->result |= SAM_STAT_CHECK_CONDITION;
26838c2ecf20Sopenharmony_ci		return 1;
26848c2ecf20Sopenharmony_ci	}
26858c2ecf20Sopenharmony_ci
26868c2ecf20Sopenharmony_ci	return 1;
26878c2ecf20Sopenharmony_ci}
26888c2ecf20Sopenharmony_ci
26898c2ecf20Sopenharmony_cistatic void
26908c2ecf20Sopenharmony_ciqla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
26918c2ecf20Sopenharmony_ci				  struct req_que *req, uint32_t index)
26928c2ecf20Sopenharmony_ci{
26938c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
26948c2ecf20Sopenharmony_ci	srb_t *sp;
26958c2ecf20Sopenharmony_ci	uint16_t	comp_status;
26968c2ecf20Sopenharmony_ci	uint16_t	scsi_status;
26978c2ecf20Sopenharmony_ci	uint16_t thread_id;
26988c2ecf20Sopenharmony_ci	uint32_t rval = EXT_STATUS_OK;
26998c2ecf20Sopenharmony_ci	struct bsg_job *bsg_job = NULL;
27008c2ecf20Sopenharmony_ci	struct fc_bsg_request *bsg_request;
27018c2ecf20Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
27028c2ecf20Sopenharmony_ci	sts_entry_t *sts = pkt;
27038c2ecf20Sopenharmony_ci	struct sts_entry_24xx *sts24 = pkt;
27048c2ecf20Sopenharmony_ci
27058c2ecf20Sopenharmony_ci	/* Validate handle. */
27068c2ecf20Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
27078c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70af,
27088c2ecf20Sopenharmony_ci		    "Invalid SCSI completion handle 0x%x.\n", index);
27098c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
27108c2ecf20Sopenharmony_ci		return;
27118c2ecf20Sopenharmony_ci	}
27128c2ecf20Sopenharmony_ci
27138c2ecf20Sopenharmony_ci	sp = req->outstanding_cmds[index];
27148c2ecf20Sopenharmony_ci	if (!sp) {
27158c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70b0,
27168c2ecf20Sopenharmony_ci		    "Req:%d: Invalid ISP SCSI completion handle(0x%x)\n",
27178c2ecf20Sopenharmony_ci		    req->id, index);
27188c2ecf20Sopenharmony_ci
27198c2ecf20Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
27208c2ecf20Sopenharmony_ci		return;
27218c2ecf20Sopenharmony_ci	}
27228c2ecf20Sopenharmony_ci
27238c2ecf20Sopenharmony_ci	/* Free outstanding command slot. */
27248c2ecf20Sopenharmony_ci	req->outstanding_cmds[index] = NULL;
27258c2ecf20Sopenharmony_ci	bsg_job = sp->u.bsg_job;
27268c2ecf20Sopenharmony_ci	bsg_request = bsg_job->request;
27278c2ecf20Sopenharmony_ci	bsg_reply = bsg_job->reply;
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
27308c2ecf20Sopenharmony_ci		comp_status = le16_to_cpu(sts24->comp_status);
27318c2ecf20Sopenharmony_ci		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
27328c2ecf20Sopenharmony_ci	} else {
27338c2ecf20Sopenharmony_ci		comp_status = le16_to_cpu(sts->comp_status);
27348c2ecf20Sopenharmony_ci		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
27358c2ecf20Sopenharmony_ci	}
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci	thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
27388c2ecf20Sopenharmony_ci	switch (comp_status) {
27398c2ecf20Sopenharmony_ci	case CS_COMPLETE:
27408c2ecf20Sopenharmony_ci		if (scsi_status == 0) {
27418c2ecf20Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
27428c2ecf20Sopenharmony_ci					bsg_job->reply_payload.payload_len;
27438c2ecf20Sopenharmony_ci			vha->qla_stats.input_bytes +=
27448c2ecf20Sopenharmony_ci				bsg_reply->reply_payload_rcv_len;
27458c2ecf20Sopenharmony_ci			vha->qla_stats.input_requests++;
27468c2ecf20Sopenharmony_ci			rval = EXT_STATUS_OK;
27478c2ecf20Sopenharmony_ci		}
27488c2ecf20Sopenharmony_ci		goto done;
27498c2ecf20Sopenharmony_ci
27508c2ecf20Sopenharmony_ci	case CS_DATA_OVERRUN:
27518c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b1,
27528c2ecf20Sopenharmony_ci		    "Command completed with data overrun thread_id=%d\n",
27538c2ecf20Sopenharmony_ci		    thread_id);
27548c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
27558c2ecf20Sopenharmony_ci		break;
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	case CS_DATA_UNDERRUN:
27588c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b2,
27598c2ecf20Sopenharmony_ci		    "Command completed with data underrun thread_id=%d\n",
27608c2ecf20Sopenharmony_ci		    thread_id);
27618c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
27628c2ecf20Sopenharmony_ci		break;
27638c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_OVERRUN:
27648c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b3,
27658c2ecf20Sopenharmony_ci		    "Command completed with read data overrun thread_id=%d\n",
27668c2ecf20Sopenharmony_ci		    thread_id);
27678c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
27688c2ecf20Sopenharmony_ci		break;
27698c2ecf20Sopenharmony_ci
27708c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_WR_OVERRUN:
27718c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b4,
27728c2ecf20Sopenharmony_ci		    "Command completed with read and write data overrun "
27738c2ecf20Sopenharmony_ci		    "thread_id=%d\n", thread_id);
27748c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
27758c2ecf20Sopenharmony_ci		break;
27768c2ecf20Sopenharmony_ci
27778c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN:
27788c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b5,
27798c2ecf20Sopenharmony_ci		    "Command completed with read data over and write data "
27808c2ecf20Sopenharmony_ci		    "underrun thread_id=%d\n", thread_id);
27818c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
27828c2ecf20Sopenharmony_ci		break;
27838c2ecf20Sopenharmony_ci
27848c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_UNDERRUN:
27858c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b6,
27868c2ecf20Sopenharmony_ci		    "Command completed with read data underrun "
27878c2ecf20Sopenharmony_ci		    "thread_id=%d\n", thread_id);
27888c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
27898c2ecf20Sopenharmony_ci		break;
27908c2ecf20Sopenharmony_ci
27918c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN:
27928c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b7,
27938c2ecf20Sopenharmony_ci		    "Command completed with read data under and write data "
27948c2ecf20Sopenharmony_ci		    "overrun thread_id=%d\n", thread_id);
27958c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
27968c2ecf20Sopenharmony_ci		break;
27978c2ecf20Sopenharmony_ci
27988c2ecf20Sopenharmony_ci	case CS_BIDIR_RD_WR_UNDERRUN:
27998c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b8,
28008c2ecf20Sopenharmony_ci		    "Command completed with read and write data underrun "
28018c2ecf20Sopenharmony_ci		    "thread_id=%d\n", thread_id);
28028c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
28038c2ecf20Sopenharmony_ci		break;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	case CS_BIDIR_DMA:
28068c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b9,
28078c2ecf20Sopenharmony_ci		    "Command completed with data DMA error thread_id=%d\n",
28088c2ecf20Sopenharmony_ci		    thread_id);
28098c2ecf20Sopenharmony_ci		rval = EXT_STATUS_DMA_ERR;
28108c2ecf20Sopenharmony_ci		break;
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci	case CS_TIMEOUT:
28138c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70ba,
28148c2ecf20Sopenharmony_ci		    "Command completed with timeout thread_id=%d\n",
28158c2ecf20Sopenharmony_ci		    thread_id);
28168c2ecf20Sopenharmony_ci		rval = EXT_STATUS_TIMEOUT;
28178c2ecf20Sopenharmony_ci		break;
28188c2ecf20Sopenharmony_ci	default:
28198c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70bb,
28208c2ecf20Sopenharmony_ci		    "Command completed with completion status=0x%x "
28218c2ecf20Sopenharmony_ci		    "thread_id=%d\n", comp_status, thread_id);
28228c2ecf20Sopenharmony_ci		rval = EXT_STATUS_ERR;
28238c2ecf20Sopenharmony_ci		break;
28248c2ecf20Sopenharmony_ci	}
28258c2ecf20Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
28268c2ecf20Sopenharmony_ci
28278c2ecf20Sopenharmony_cidone:
28288c2ecf20Sopenharmony_ci	/* Return the vendor specific reply to API */
28298c2ecf20Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
28308c2ecf20Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
28318c2ecf20Sopenharmony_ci	/* Always return DID_OK, bsg will send the vendor specific response
28328c2ecf20Sopenharmony_ci	 * in this case only */
28338c2ecf20Sopenharmony_ci	sp->done(sp, DID_OK << 16);
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_ci}
28368c2ecf20Sopenharmony_ci
28378c2ecf20Sopenharmony_ci/**
28388c2ecf20Sopenharmony_ci * qla2x00_status_entry() - Process a Status IOCB entry.
28398c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
28408c2ecf20Sopenharmony_ci * @rsp: response queue
28418c2ecf20Sopenharmony_ci * @pkt: Entry pointer
28428c2ecf20Sopenharmony_ci */
28438c2ecf20Sopenharmony_cistatic void
28448c2ecf20Sopenharmony_ciqla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
28458c2ecf20Sopenharmony_ci{
28468c2ecf20Sopenharmony_ci	srb_t		*sp;
28478c2ecf20Sopenharmony_ci	fc_port_t	*fcport;
28488c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp;
28498c2ecf20Sopenharmony_ci	sts_entry_t *sts = pkt;
28508c2ecf20Sopenharmony_ci	struct sts_entry_24xx *sts24 = pkt;
28518c2ecf20Sopenharmony_ci	uint16_t	comp_status;
28528c2ecf20Sopenharmony_ci	uint16_t	scsi_status;
28538c2ecf20Sopenharmony_ci	uint16_t	ox_id;
28548c2ecf20Sopenharmony_ci	uint8_t		lscsi_status;
28558c2ecf20Sopenharmony_ci	int32_t		resid;
28568c2ecf20Sopenharmony_ci	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
28578c2ecf20Sopenharmony_ci	    fw_resid_len;
28588c2ecf20Sopenharmony_ci	uint8_t		*rsp_info, *sense_data;
28598c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
28608c2ecf20Sopenharmony_ci	uint32_t handle;
28618c2ecf20Sopenharmony_ci	uint16_t que;
28628c2ecf20Sopenharmony_ci	struct req_que *req;
28638c2ecf20Sopenharmony_ci	int logit = 1;
28648c2ecf20Sopenharmony_ci	int res = 0;
28658c2ecf20Sopenharmony_ci	uint16_t state_flags = 0;
28668c2ecf20Sopenharmony_ci	uint16_t sts_qual = 0;
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
28698c2ecf20Sopenharmony_ci		comp_status = le16_to_cpu(sts24->comp_status);
28708c2ecf20Sopenharmony_ci		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
28718c2ecf20Sopenharmony_ci		state_flags = le16_to_cpu(sts24->state_flags);
28728c2ecf20Sopenharmony_ci	} else {
28738c2ecf20Sopenharmony_ci		comp_status = le16_to_cpu(sts->comp_status);
28748c2ecf20Sopenharmony_ci		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
28758c2ecf20Sopenharmony_ci	}
28768c2ecf20Sopenharmony_ci	handle = (uint32_t) LSW(sts->handle);
28778c2ecf20Sopenharmony_ci	que = MSW(sts->handle);
28788c2ecf20Sopenharmony_ci	req = ha->req_q_map[que];
28798c2ecf20Sopenharmony_ci
28808c2ecf20Sopenharmony_ci	/* Check for invalid queue pointer */
28818c2ecf20Sopenharmony_ci	if (req == NULL ||
28828c2ecf20Sopenharmony_ci	    que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
28838c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3059,
28848c2ecf20Sopenharmony_ci		    "Invalid status handle (0x%x): Bad req pointer. req=%p, "
28858c2ecf20Sopenharmony_ci		    "que=%u.\n", sts->handle, req, que);
28868c2ecf20Sopenharmony_ci		return;
28878c2ecf20Sopenharmony_ci	}
28888c2ecf20Sopenharmony_ci
28898c2ecf20Sopenharmony_ci	/* Validate handle. */
28908c2ecf20Sopenharmony_ci	if (handle < req->num_outstanding_cmds) {
28918c2ecf20Sopenharmony_ci		sp = req->outstanding_cmds[handle];
28928c2ecf20Sopenharmony_ci		if (!sp) {
28938c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, vha, 0x3075,
28948c2ecf20Sopenharmony_ci			    "%s(%ld): Already returned command for status handle (0x%x).\n",
28958c2ecf20Sopenharmony_ci			    __func__, vha->host_no, sts->handle);
28968c2ecf20Sopenharmony_ci			return;
28978c2ecf20Sopenharmony_ci		}
28988c2ecf20Sopenharmony_ci	} else {
28998c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3017,
29008c2ecf20Sopenharmony_ci		    "Invalid status handle, out of range (0x%x).\n",
29018c2ecf20Sopenharmony_ci		    sts->handle);
29028c2ecf20Sopenharmony_ci
29038c2ecf20Sopenharmony_ci		if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
29048c2ecf20Sopenharmony_ci			if (IS_P3P_TYPE(ha))
29058c2ecf20Sopenharmony_ci				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
29068c2ecf20Sopenharmony_ci			else
29078c2ecf20Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
29088c2ecf20Sopenharmony_ci			qla2xxx_wake_dpc(vha);
29098c2ecf20Sopenharmony_ci		}
29108c2ecf20Sopenharmony_ci		return;
29118c2ecf20Sopenharmony_ci	}
29128c2ecf20Sopenharmony_ci	qla_put_iocbs(sp->qpair, &sp->iores);
29138c2ecf20Sopenharmony_ci
29148c2ecf20Sopenharmony_ci	if (sp->cmd_type != TYPE_SRB) {
29158c2ecf20Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
29168c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3015,
29178c2ecf20Sopenharmony_ci		    "Unknown sp->cmd_type %x %p).\n",
29188c2ecf20Sopenharmony_ci		    sp->cmd_type, sp);
29198c2ecf20Sopenharmony_ci		return;
29208c2ecf20Sopenharmony_ci	}
29218c2ecf20Sopenharmony_ci
29228c2ecf20Sopenharmony_ci	/* NVME completion. */
29238c2ecf20Sopenharmony_ci	if (sp->type == SRB_NVME_CMD) {
29248c2ecf20Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
29258c2ecf20Sopenharmony_ci		qla24xx_nvme_iocb_entry(vha, req, pkt, sp);
29268c2ecf20Sopenharmony_ci		return;
29278c2ecf20Sopenharmony_ci	}
29288c2ecf20Sopenharmony_ci
29298c2ecf20Sopenharmony_ci	if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) {
29308c2ecf20Sopenharmony_ci		qla25xx_process_bidir_status_iocb(vha, pkt, req, handle);
29318c2ecf20Sopenharmony_ci		return;
29328c2ecf20Sopenharmony_ci	}
29338c2ecf20Sopenharmony_ci
29348c2ecf20Sopenharmony_ci	/* Task Management completion. */
29358c2ecf20Sopenharmony_ci	if (sp->type == SRB_TM_CMD) {
29368c2ecf20Sopenharmony_ci		qla24xx_tm_iocb_entry(vha, req, pkt);
29378c2ecf20Sopenharmony_ci		return;
29388c2ecf20Sopenharmony_ci	}
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_ci	/* Fast path completion. */
29418c2ecf20Sopenharmony_ci	if (comp_status == CS_COMPLETE && scsi_status == 0) {
29428c2ecf20Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
29438c2ecf20Sopenharmony_ci
29448c2ecf20Sopenharmony_ci		return;
29458c2ecf20Sopenharmony_ci	}
29468c2ecf20Sopenharmony_ci
29478c2ecf20Sopenharmony_ci	req->outstanding_cmds[handle] = NULL;
29488c2ecf20Sopenharmony_ci	cp = GET_CMD_SP(sp);
29498c2ecf20Sopenharmony_ci	if (cp == NULL) {
29508c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3018,
29518c2ecf20Sopenharmony_ci		    "Command already returned (0x%x/%p).\n",
29528c2ecf20Sopenharmony_ci		    sts->handle, sp);
29538c2ecf20Sopenharmony_ci
29548c2ecf20Sopenharmony_ci		return;
29558c2ecf20Sopenharmony_ci	}
29568c2ecf20Sopenharmony_ci
29578c2ecf20Sopenharmony_ci	lscsi_status = scsi_status & STATUS_MASK;
29588c2ecf20Sopenharmony_ci
29598c2ecf20Sopenharmony_ci	fcport = sp->fcport;
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	ox_id = 0;
29628c2ecf20Sopenharmony_ci	sense_len = par_sense_len = rsp_info_len = resid_len =
29638c2ecf20Sopenharmony_ci	    fw_resid_len = 0;
29648c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
29658c2ecf20Sopenharmony_ci		if (scsi_status & SS_SENSE_LEN_VALID)
29668c2ecf20Sopenharmony_ci			sense_len = le32_to_cpu(sts24->sense_len);
29678c2ecf20Sopenharmony_ci		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
29688c2ecf20Sopenharmony_ci			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
29698c2ecf20Sopenharmony_ci		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
29708c2ecf20Sopenharmony_ci			resid_len = le32_to_cpu(sts24->rsp_residual_count);
29718c2ecf20Sopenharmony_ci		if (comp_status == CS_DATA_UNDERRUN)
29728c2ecf20Sopenharmony_ci			fw_resid_len = le32_to_cpu(sts24->residual_len);
29738c2ecf20Sopenharmony_ci		rsp_info = sts24->data;
29748c2ecf20Sopenharmony_ci		sense_data = sts24->data;
29758c2ecf20Sopenharmony_ci		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
29768c2ecf20Sopenharmony_ci		ox_id = le16_to_cpu(sts24->ox_id);
29778c2ecf20Sopenharmony_ci		par_sense_len = sizeof(sts24->data);
29788c2ecf20Sopenharmony_ci		sts_qual = le16_to_cpu(sts24->status_qualifier);
29798c2ecf20Sopenharmony_ci	} else {
29808c2ecf20Sopenharmony_ci		if (scsi_status & SS_SENSE_LEN_VALID)
29818c2ecf20Sopenharmony_ci			sense_len = le16_to_cpu(sts->req_sense_length);
29828c2ecf20Sopenharmony_ci		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
29838c2ecf20Sopenharmony_ci			rsp_info_len = le16_to_cpu(sts->rsp_info_len);
29848c2ecf20Sopenharmony_ci		resid_len = le32_to_cpu(sts->residual_length);
29858c2ecf20Sopenharmony_ci		rsp_info = sts->rsp_info;
29868c2ecf20Sopenharmony_ci		sense_data = sts->req_sense_data;
29878c2ecf20Sopenharmony_ci		par_sense_len = sizeof(sts->req_sense_data);
29888c2ecf20Sopenharmony_ci	}
29898c2ecf20Sopenharmony_ci
29908c2ecf20Sopenharmony_ci	/* Check for any FCP transport errors. */
29918c2ecf20Sopenharmony_ci	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
29928c2ecf20Sopenharmony_ci		/* Sense data lies beyond any FCP RESPONSE data. */
29938c2ecf20Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha)) {
29948c2ecf20Sopenharmony_ci			sense_data += rsp_info_len;
29958c2ecf20Sopenharmony_ci			par_sense_len -= rsp_info_len;
29968c2ecf20Sopenharmony_ci		}
29978c2ecf20Sopenharmony_ci		if (rsp_info_len > 3 && rsp_info[3]) {
29988c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
29998c2ecf20Sopenharmony_ci			    "FCP I/O protocol failure (0x%x/0x%x).\n",
30008c2ecf20Sopenharmony_ci			    rsp_info_len, rsp_info[3]);
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci			res = DID_BUS_BUSY << 16;
30038c2ecf20Sopenharmony_ci			goto out;
30048c2ecf20Sopenharmony_ci		}
30058c2ecf20Sopenharmony_ci	}
30068c2ecf20Sopenharmony_ci
30078c2ecf20Sopenharmony_ci	/* Check for overrun. */
30088c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
30098c2ecf20Sopenharmony_ci	    scsi_status & SS_RESIDUAL_OVER)
30108c2ecf20Sopenharmony_ci		comp_status = CS_DATA_OVERRUN;
30118c2ecf20Sopenharmony_ci
30128c2ecf20Sopenharmony_ci	/*
30138c2ecf20Sopenharmony_ci	 * Check retry_delay_timer value if we receive a busy or
30148c2ecf20Sopenharmony_ci	 * queue full.
30158c2ecf20Sopenharmony_ci	 */
30168c2ecf20Sopenharmony_ci	if (unlikely(lscsi_status == SAM_STAT_TASK_SET_FULL ||
30178c2ecf20Sopenharmony_ci		     lscsi_status == SAM_STAT_BUSY))
30188c2ecf20Sopenharmony_ci		qla2x00_set_retry_delay_timestamp(fcport, sts_qual);
30198c2ecf20Sopenharmony_ci
30208c2ecf20Sopenharmony_ci	/*
30218c2ecf20Sopenharmony_ci	 * Based on Host and scsi status generate status code for Linux
30228c2ecf20Sopenharmony_ci	 */
30238c2ecf20Sopenharmony_ci	switch (comp_status) {
30248c2ecf20Sopenharmony_ci	case CS_COMPLETE:
30258c2ecf20Sopenharmony_ci	case CS_QUEUE_FULL:
30268c2ecf20Sopenharmony_ci		if (scsi_status == 0) {
30278c2ecf20Sopenharmony_ci			res = DID_OK << 16;
30288c2ecf20Sopenharmony_ci			break;
30298c2ecf20Sopenharmony_ci		}
30308c2ecf20Sopenharmony_ci		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
30318c2ecf20Sopenharmony_ci			resid = resid_len;
30328c2ecf20Sopenharmony_ci			scsi_set_resid(cp, resid);
30338c2ecf20Sopenharmony_ci
30348c2ecf20Sopenharmony_ci			if (!lscsi_status &&
30358c2ecf20Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
30368c2ecf20Sopenharmony_ci			     cp->underflow)) {
30378c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
30388c2ecf20Sopenharmony_ci				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
30398c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp));
30408c2ecf20Sopenharmony_ci
30418c2ecf20Sopenharmony_ci				res = DID_ERROR << 16;
30428c2ecf20Sopenharmony_ci				break;
30438c2ecf20Sopenharmony_ci			}
30448c2ecf20Sopenharmony_ci		}
30458c2ecf20Sopenharmony_ci		res = DID_OK << 16 | lscsi_status;
30468c2ecf20Sopenharmony_ci
30478c2ecf20Sopenharmony_ci		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
30488c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
30498c2ecf20Sopenharmony_ci			    "QUEUE FULL detected.\n");
30508c2ecf20Sopenharmony_ci			break;
30518c2ecf20Sopenharmony_ci		}
30528c2ecf20Sopenharmony_ci		logit = 0;
30538c2ecf20Sopenharmony_ci		if (lscsi_status != SS_CHECK_CONDITION)
30548c2ecf20Sopenharmony_ci			break;
30558c2ecf20Sopenharmony_ci
30568c2ecf20Sopenharmony_ci		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
30578c2ecf20Sopenharmony_ci		if (!(scsi_status & SS_SENSE_LEN_VALID))
30588c2ecf20Sopenharmony_ci			break;
30598c2ecf20Sopenharmony_ci
30608c2ecf20Sopenharmony_ci		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
30618c2ecf20Sopenharmony_ci		    rsp, res);
30628c2ecf20Sopenharmony_ci		break;
30638c2ecf20Sopenharmony_ci
30648c2ecf20Sopenharmony_ci	case CS_DATA_UNDERRUN:
30658c2ecf20Sopenharmony_ci		/* Use F/W calculated residual length. */
30668c2ecf20Sopenharmony_ci		resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
30678c2ecf20Sopenharmony_ci		scsi_set_resid(cp, resid);
30688c2ecf20Sopenharmony_ci		if (scsi_status & SS_RESIDUAL_UNDER) {
30698c2ecf20Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
30708c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
30718c2ecf20Sopenharmony_ci				    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
30728c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp));
30738c2ecf20Sopenharmony_ci
30748c2ecf20Sopenharmony_ci				res = DID_ERROR << 16 | lscsi_status;
30758c2ecf20Sopenharmony_ci				goto check_scsi_status;
30768c2ecf20Sopenharmony_ci			}
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci			if (!lscsi_status &&
30798c2ecf20Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
30808c2ecf20Sopenharmony_ci			    cp->underflow)) {
30818c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
30828c2ecf20Sopenharmony_ci				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
30838c2ecf20Sopenharmony_ci				    resid, scsi_bufflen(cp));
30848c2ecf20Sopenharmony_ci
30858c2ecf20Sopenharmony_ci				res = DID_ERROR << 16;
30868c2ecf20Sopenharmony_ci				break;
30878c2ecf20Sopenharmony_ci			}
30888c2ecf20Sopenharmony_ci		} else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
30898c2ecf20Sopenharmony_ci			    lscsi_status != SAM_STAT_BUSY) {
30908c2ecf20Sopenharmony_ci			/*
30918c2ecf20Sopenharmony_ci			 * scsi status of task set and busy are considered to be
30928c2ecf20Sopenharmony_ci			 * task not completed.
30938c2ecf20Sopenharmony_ci			 */
30948c2ecf20Sopenharmony_ci
30958c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
30968c2ecf20Sopenharmony_ci			    "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
30978c2ecf20Sopenharmony_ci			    resid, scsi_bufflen(cp));
30988c2ecf20Sopenharmony_ci
30998c2ecf20Sopenharmony_ci			res = DID_ERROR << 16 | lscsi_status;
31008c2ecf20Sopenharmony_ci			goto check_scsi_status;
31018c2ecf20Sopenharmony_ci		} else {
31028c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3030,
31038c2ecf20Sopenharmony_ci			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
31048c2ecf20Sopenharmony_ci			    scsi_status, lscsi_status);
31058c2ecf20Sopenharmony_ci		}
31068c2ecf20Sopenharmony_ci
31078c2ecf20Sopenharmony_ci		res = DID_OK << 16 | lscsi_status;
31088c2ecf20Sopenharmony_ci		logit = 0;
31098c2ecf20Sopenharmony_ci
31108c2ecf20Sopenharmony_cicheck_scsi_status:
31118c2ecf20Sopenharmony_ci		/*
31128c2ecf20Sopenharmony_ci		 * Check to see if SCSI Status is non zero. If so report SCSI
31138c2ecf20Sopenharmony_ci		 * Status.
31148c2ecf20Sopenharmony_ci		 */
31158c2ecf20Sopenharmony_ci		if (lscsi_status != 0) {
31168c2ecf20Sopenharmony_ci			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
31178c2ecf20Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
31188c2ecf20Sopenharmony_ci				    "QUEUE FULL detected.\n");
31198c2ecf20Sopenharmony_ci				logit = 1;
31208c2ecf20Sopenharmony_ci				break;
31218c2ecf20Sopenharmony_ci			}
31228c2ecf20Sopenharmony_ci			if (lscsi_status != SS_CHECK_CONDITION)
31238c2ecf20Sopenharmony_ci				break;
31248c2ecf20Sopenharmony_ci
31258c2ecf20Sopenharmony_ci			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
31268c2ecf20Sopenharmony_ci			if (!(scsi_status & SS_SENSE_LEN_VALID))
31278c2ecf20Sopenharmony_ci				break;
31288c2ecf20Sopenharmony_ci
31298c2ecf20Sopenharmony_ci			qla2x00_handle_sense(sp, sense_data, par_sense_len,
31308c2ecf20Sopenharmony_ci			    sense_len, rsp, res);
31318c2ecf20Sopenharmony_ci		}
31328c2ecf20Sopenharmony_ci		break;
31338c2ecf20Sopenharmony_ci
31348c2ecf20Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
31358c2ecf20Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
31368c2ecf20Sopenharmony_ci	case CS_PORT_BUSY:
31378c2ecf20Sopenharmony_ci	case CS_INCOMPLETE:
31388c2ecf20Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
31398c2ecf20Sopenharmony_ci	case CS_RESET:
31408c2ecf20Sopenharmony_ci
31418c2ecf20Sopenharmony_ci		/*
31428c2ecf20Sopenharmony_ci		 * We are going to have the fc class block the rport
31438c2ecf20Sopenharmony_ci		 * while we try to recover so instruct the mid layer
31448c2ecf20Sopenharmony_ci		 * to requeue until the class decides how to handle this.
31458c2ecf20Sopenharmony_ci		 */
31468c2ecf20Sopenharmony_ci		res = DID_TRANSPORT_DISRUPTED << 16;
31478c2ecf20Sopenharmony_ci
31488c2ecf20Sopenharmony_ci		if (comp_status == CS_TIMEOUT) {
31498c2ecf20Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha))
31508c2ecf20Sopenharmony_ci				break;
31518c2ecf20Sopenharmony_ci			else if ((le16_to_cpu(sts->status_flags) &
31528c2ecf20Sopenharmony_ci			    SF_LOGOUT_SENT) == 0)
31538c2ecf20Sopenharmony_ci				break;
31548c2ecf20Sopenharmony_ci		}
31558c2ecf20Sopenharmony_ci
31568c2ecf20Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE) {
31578c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
31588c2ecf20Sopenharmony_ci				"Port to be marked lost on fcport=%02x%02x%02x, current "
31598c2ecf20Sopenharmony_ci				"port state= %s comp_status %x.\n", fcport->d_id.b.domain,
31608c2ecf20Sopenharmony_ci				fcport->d_id.b.area, fcport->d_id.b.al_pa,
31618c2ecf20Sopenharmony_ci				port_state_str[FCS_ONLINE],
31628c2ecf20Sopenharmony_ci				comp_status);
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
31658c2ecf20Sopenharmony_ci		}
31668c2ecf20Sopenharmony_ci
31678c2ecf20Sopenharmony_ci		break;
31688c2ecf20Sopenharmony_ci
31698c2ecf20Sopenharmony_ci	case CS_ABORTED:
31708c2ecf20Sopenharmony_ci		res = DID_RESET << 16;
31718c2ecf20Sopenharmony_ci		break;
31728c2ecf20Sopenharmony_ci
31738c2ecf20Sopenharmony_ci	case CS_DIF_ERROR:
31748c2ecf20Sopenharmony_ci		logit = qla2x00_handle_dif_error(sp, sts24);
31758c2ecf20Sopenharmony_ci		res = cp->result;
31768c2ecf20Sopenharmony_ci		break;
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ci	case CS_TRANSPORT:
31798c2ecf20Sopenharmony_ci		res = DID_ERROR << 16;
31808c2ecf20Sopenharmony_ci
31818c2ecf20Sopenharmony_ci		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
31828c2ecf20Sopenharmony_ci			break;
31838c2ecf20Sopenharmony_ci
31848c2ecf20Sopenharmony_ci		if (state_flags & BIT_4)
31858c2ecf20Sopenharmony_ci			scmd_printk(KERN_WARNING, cp,
31868c2ecf20Sopenharmony_ci			    "Unsupported device '%s' found.\n",
31878c2ecf20Sopenharmony_ci			    cp->device->vendor);
31888c2ecf20Sopenharmony_ci		break;
31898c2ecf20Sopenharmony_ci
31908c2ecf20Sopenharmony_ci	case CS_DMA:
31918c2ecf20Sopenharmony_ci		ql_log(ql_log_info, fcport->vha, 0x3022,
31928c2ecf20Sopenharmony_ci		    "CS_DMA error: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%06x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
31938c2ecf20Sopenharmony_ci		    comp_status, scsi_status, res, vha->host_no,
31948c2ecf20Sopenharmony_ci		    cp->device->id, cp->device->lun, fcport->d_id.b24,
31958c2ecf20Sopenharmony_ci		    ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len,
31968c2ecf20Sopenharmony_ci		    resid_len, fw_resid_len, sp, cp);
31978c2ecf20Sopenharmony_ci		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
31988c2ecf20Sopenharmony_ci		    pkt, sizeof(*sts24));
31998c2ecf20Sopenharmony_ci		res = DID_ERROR << 16;
32008c2ecf20Sopenharmony_ci		break;
32018c2ecf20Sopenharmony_ci	default:
32028c2ecf20Sopenharmony_ci		res = DID_ERROR << 16;
32038c2ecf20Sopenharmony_ci		break;
32048c2ecf20Sopenharmony_ci	}
32058c2ecf20Sopenharmony_ci
32068c2ecf20Sopenharmony_ciout:
32078c2ecf20Sopenharmony_ci	if (logit)
32088c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
32098c2ecf20Sopenharmony_ci		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
32108c2ecf20Sopenharmony_ci		    "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
32118c2ecf20Sopenharmony_ci		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
32128c2ecf20Sopenharmony_ci		    comp_status, scsi_status, res, vha->host_no,
32138c2ecf20Sopenharmony_ci		    cp->device->id, cp->device->lun, fcport->d_id.b.domain,
32148c2ecf20Sopenharmony_ci		    fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
32158c2ecf20Sopenharmony_ci		    cp->cmnd, scsi_bufflen(cp), rsp_info_len,
32168c2ecf20Sopenharmony_ci		    resid_len, fw_resid_len, sp, cp);
32178c2ecf20Sopenharmony_ci
32188c2ecf20Sopenharmony_ci	if (rsp->status_srb == NULL)
32198c2ecf20Sopenharmony_ci		sp->done(sp, res);
32208c2ecf20Sopenharmony_ci}
32218c2ecf20Sopenharmony_ci
32228c2ecf20Sopenharmony_ci/**
32238c2ecf20Sopenharmony_ci * qla2x00_status_cont_entry() - Process a Status Continuations entry.
32248c2ecf20Sopenharmony_ci * @rsp: response queue
32258c2ecf20Sopenharmony_ci * @pkt: Entry pointer
32268c2ecf20Sopenharmony_ci *
32278c2ecf20Sopenharmony_ci * Extended sense data.
32288c2ecf20Sopenharmony_ci */
32298c2ecf20Sopenharmony_cistatic void
32308c2ecf20Sopenharmony_ciqla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
32318c2ecf20Sopenharmony_ci{
32328c2ecf20Sopenharmony_ci	uint8_t	sense_sz = 0;
32338c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
32348c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
32358c2ecf20Sopenharmony_ci	srb_t *sp = rsp->status_srb;
32368c2ecf20Sopenharmony_ci	struct scsi_cmnd *cp;
32378c2ecf20Sopenharmony_ci	uint32_t sense_len;
32388c2ecf20Sopenharmony_ci	uint8_t *sense_ptr;
32398c2ecf20Sopenharmony_ci
32408c2ecf20Sopenharmony_ci	if (!sp || !GET_CMD_SENSE_LEN(sp))
32418c2ecf20Sopenharmony_ci		return;
32428c2ecf20Sopenharmony_ci
32438c2ecf20Sopenharmony_ci	sense_len = GET_CMD_SENSE_LEN(sp);
32448c2ecf20Sopenharmony_ci	sense_ptr = GET_CMD_SENSE_PTR(sp);
32458c2ecf20Sopenharmony_ci
32468c2ecf20Sopenharmony_ci	cp = GET_CMD_SP(sp);
32478c2ecf20Sopenharmony_ci	if (cp == NULL) {
32488c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3025,
32498c2ecf20Sopenharmony_ci		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
32508c2ecf20Sopenharmony_ci
32518c2ecf20Sopenharmony_ci		rsp->status_srb = NULL;
32528c2ecf20Sopenharmony_ci		return;
32538c2ecf20Sopenharmony_ci	}
32548c2ecf20Sopenharmony_ci
32558c2ecf20Sopenharmony_ci	if (sense_len > sizeof(pkt->data))
32568c2ecf20Sopenharmony_ci		sense_sz = sizeof(pkt->data);
32578c2ecf20Sopenharmony_ci	else
32588c2ecf20Sopenharmony_ci		sense_sz = sense_len;
32598c2ecf20Sopenharmony_ci
32608c2ecf20Sopenharmony_ci	/* Move sense data. */
32618c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha))
32628c2ecf20Sopenharmony_ci		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
32638c2ecf20Sopenharmony_ci	memcpy(sense_ptr, pkt->data, sense_sz);
32648c2ecf20Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
32658c2ecf20Sopenharmony_ci		sense_ptr, sense_sz);
32668c2ecf20Sopenharmony_ci
32678c2ecf20Sopenharmony_ci	sense_len -= sense_sz;
32688c2ecf20Sopenharmony_ci	sense_ptr += sense_sz;
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, sense_ptr);
32718c2ecf20Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
32728c2ecf20Sopenharmony_ci
32738c2ecf20Sopenharmony_ci	/* Place command on done queue. */
32748c2ecf20Sopenharmony_ci	if (sense_len == 0) {
32758c2ecf20Sopenharmony_ci		rsp->status_srb = NULL;
32768c2ecf20Sopenharmony_ci		sp->done(sp, cp->result);
32778c2ecf20Sopenharmony_ci	}
32788c2ecf20Sopenharmony_ci}
32798c2ecf20Sopenharmony_ci
32808c2ecf20Sopenharmony_ci/**
32818c2ecf20Sopenharmony_ci * qla2x00_error_entry() - Process an error entry.
32828c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
32838c2ecf20Sopenharmony_ci * @rsp: response queue
32848c2ecf20Sopenharmony_ci * @pkt: Entry pointer
32858c2ecf20Sopenharmony_ci * return : 1=allow further error analysis. 0=no additional error analysis.
32868c2ecf20Sopenharmony_ci */
32878c2ecf20Sopenharmony_cistatic int
32888c2ecf20Sopenharmony_ciqla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
32898c2ecf20Sopenharmony_ci{
32908c2ecf20Sopenharmony_ci	srb_t *sp;
32918c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
32928c2ecf20Sopenharmony_ci	const char func[] = "ERROR-IOCB";
32938c2ecf20Sopenharmony_ci	uint16_t que = MSW(pkt->handle);
32948c2ecf20Sopenharmony_ci	struct req_que *req = NULL;
32958c2ecf20Sopenharmony_ci	int res = DID_ERROR << 16;
32968c2ecf20Sopenharmony_ci
32978c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x502a,
32988c2ecf20Sopenharmony_ci	    "iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
32998c2ecf20Sopenharmony_ci	    pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id);
33008c2ecf20Sopenharmony_ci
33018c2ecf20Sopenharmony_ci	if (que >= ha->max_req_queues || !ha->req_q_map[que])
33028c2ecf20Sopenharmony_ci		goto fatal;
33038c2ecf20Sopenharmony_ci
33048c2ecf20Sopenharmony_ci	req = ha->req_q_map[que];
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	if (pkt->entry_status & RF_BUSY)
33078c2ecf20Sopenharmony_ci		res = DID_BUS_BUSY << 16;
33088c2ecf20Sopenharmony_ci
33098c2ecf20Sopenharmony_ci	if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE)
33108c2ecf20Sopenharmony_ci		return 0;
33118c2ecf20Sopenharmony_ci
33128c2ecf20Sopenharmony_ci	switch (pkt->entry_type) {
33138c2ecf20Sopenharmony_ci	case NOTIFY_ACK_TYPE:
33148c2ecf20Sopenharmony_ci	case STATUS_TYPE:
33158c2ecf20Sopenharmony_ci	case STATUS_CONT_TYPE:
33168c2ecf20Sopenharmony_ci	case LOGINOUT_PORT_IOCB_TYPE:
33178c2ecf20Sopenharmony_ci	case CT_IOCB_TYPE:
33188c2ecf20Sopenharmony_ci	case ELS_IOCB_TYPE:
33198c2ecf20Sopenharmony_ci	case ABORT_IOCB_TYPE:
33208c2ecf20Sopenharmony_ci	case MBX_IOCB_TYPE:
33218c2ecf20Sopenharmony_ci	default:
33228c2ecf20Sopenharmony_ci		sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
33238c2ecf20Sopenharmony_ci		if (sp) {
33248c2ecf20Sopenharmony_ci			qla_put_iocbs(sp->qpair, &sp->iores);
33258c2ecf20Sopenharmony_ci			sp->done(sp, res);
33268c2ecf20Sopenharmony_ci			return 0;
33278c2ecf20Sopenharmony_ci		}
33288c2ecf20Sopenharmony_ci		break;
33298c2ecf20Sopenharmony_ci
33308c2ecf20Sopenharmony_ci	case ABTS_RESP_24XX:
33318c2ecf20Sopenharmony_ci	case CTIO_TYPE7:
33328c2ecf20Sopenharmony_ci	case CTIO_CRC2:
33338c2ecf20Sopenharmony_ci		return 1;
33348c2ecf20Sopenharmony_ci	}
33358c2ecf20Sopenharmony_cifatal:
33368c2ecf20Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x5030,
33378c2ecf20Sopenharmony_ci	    "Error entry - invalid handle/queue (%04x).\n", que);
33388c2ecf20Sopenharmony_ci	return 0;
33398c2ecf20Sopenharmony_ci}
33408c2ecf20Sopenharmony_ci
33418c2ecf20Sopenharmony_ci/**
33428c2ecf20Sopenharmony_ci * qla24xx_mbx_completion() - Process mailbox command completions.
33438c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
33448c2ecf20Sopenharmony_ci * @mb0: Mailbox0 register
33458c2ecf20Sopenharmony_ci */
33468c2ecf20Sopenharmony_cistatic void
33478c2ecf20Sopenharmony_ciqla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
33488c2ecf20Sopenharmony_ci{
33498c2ecf20Sopenharmony_ci	uint16_t	cnt;
33508c2ecf20Sopenharmony_ci	uint32_t	mboxes;
33518c2ecf20Sopenharmony_ci	__le16 __iomem *wptr;
33528c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
33538c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
33548c2ecf20Sopenharmony_ci
33558c2ecf20Sopenharmony_ci	/* Read all mbox registers? */
33568c2ecf20Sopenharmony_ci	WARN_ON_ONCE(ha->mbx_count > 32);
33578c2ecf20Sopenharmony_ci	mboxes = (1ULL << ha->mbx_count) - 1;
33588c2ecf20Sopenharmony_ci	if (!ha->mcp)
33598c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
33608c2ecf20Sopenharmony_ci	else
33618c2ecf20Sopenharmony_ci		mboxes = ha->mcp->in_mb;
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci	/* Load return mailbox registers. */
33648c2ecf20Sopenharmony_ci	ha->flags.mbox_int = 1;
33658c2ecf20Sopenharmony_ci	ha->mailbox_out[0] = mb0;
33668c2ecf20Sopenharmony_ci	mboxes >>= 1;
33678c2ecf20Sopenharmony_ci	wptr = &reg->mailbox1;
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
33708c2ecf20Sopenharmony_ci		if (mboxes & BIT_0)
33718c2ecf20Sopenharmony_ci			ha->mailbox_out[cnt] = rd_reg_word(wptr);
33728c2ecf20Sopenharmony_ci
33738c2ecf20Sopenharmony_ci		mboxes >>= 1;
33748c2ecf20Sopenharmony_ci		wptr++;
33758c2ecf20Sopenharmony_ci	}
33768c2ecf20Sopenharmony_ci}
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_cistatic void
33798c2ecf20Sopenharmony_ciqla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
33808c2ecf20Sopenharmony_ci	struct abort_entry_24xx *pkt)
33818c2ecf20Sopenharmony_ci{
33828c2ecf20Sopenharmony_ci	const char func[] = "ABT_IOCB";
33838c2ecf20Sopenharmony_ci	srb_t *sp;
33848c2ecf20Sopenharmony_ci	struct srb_iocb *abt;
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
33878c2ecf20Sopenharmony_ci	if (!sp)
33888c2ecf20Sopenharmony_ci		return;
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci	abt = &sp->u.iocb_cmd;
33918c2ecf20Sopenharmony_ci	abt->u.abt.comp_status = pkt->nport_handle;
33928c2ecf20Sopenharmony_ci	sp->done(sp, 0);
33938c2ecf20Sopenharmony_ci}
33948c2ecf20Sopenharmony_ci
33958c2ecf20Sopenharmony_civoid qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
33968c2ecf20Sopenharmony_ci    struct pt_ls4_request *pkt, struct req_que *req)
33978c2ecf20Sopenharmony_ci{
33988c2ecf20Sopenharmony_ci	srb_t *sp;
33998c2ecf20Sopenharmony_ci	const char func[] = "LS4_IOCB";
34008c2ecf20Sopenharmony_ci	uint16_t comp_status;
34018c2ecf20Sopenharmony_ci
34028c2ecf20Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
34038c2ecf20Sopenharmony_ci	if (!sp)
34048c2ecf20Sopenharmony_ci		return;
34058c2ecf20Sopenharmony_ci
34068c2ecf20Sopenharmony_ci	comp_status = le16_to_cpu(pkt->status);
34078c2ecf20Sopenharmony_ci	sp->done(sp, comp_status);
34088c2ecf20Sopenharmony_ci}
34098c2ecf20Sopenharmony_ci
34108c2ecf20Sopenharmony_ci/**
34118c2ecf20Sopenharmony_ci * qla24xx_process_response_queue() - Process response queue entries.
34128c2ecf20Sopenharmony_ci * @vha: SCSI driver HA context
34138c2ecf20Sopenharmony_ci * @rsp: response queue
34148c2ecf20Sopenharmony_ci */
34158c2ecf20Sopenharmony_civoid qla24xx_process_response_queue(struct scsi_qla_host *vha,
34168c2ecf20Sopenharmony_ci	struct rsp_que *rsp)
34178c2ecf20Sopenharmony_ci{
34188c2ecf20Sopenharmony_ci	struct sts_entry_24xx *pkt;
34198c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
34208c2ecf20Sopenharmony_ci	struct purex_entry_24xx *purex_entry;
34218c2ecf20Sopenharmony_ci	struct purex_item *pure_item;
34228c2ecf20Sopenharmony_ci
34238c2ecf20Sopenharmony_ci	if (!ha->flags.fw_started)
34248c2ecf20Sopenharmony_ci		return;
34258c2ecf20Sopenharmony_ci
34268c2ecf20Sopenharmony_ci	if (rsp->qpair->cpuid != smp_processor_id() || !rsp->qpair->rcv_intr) {
34278c2ecf20Sopenharmony_ci		rsp->qpair->rcv_intr = 1;
34288c2ecf20Sopenharmony_ci		qla_cpu_update(rsp->qpair, smp_processor_id());
34298c2ecf20Sopenharmony_ci	}
34308c2ecf20Sopenharmony_ci
34318c2ecf20Sopenharmony_ci	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
34328c2ecf20Sopenharmony_ci		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
34338c2ecf20Sopenharmony_ci
34348c2ecf20Sopenharmony_ci		rsp->ring_index++;
34358c2ecf20Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
34368c2ecf20Sopenharmony_ci			rsp->ring_index = 0;
34378c2ecf20Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
34388c2ecf20Sopenharmony_ci		} else {
34398c2ecf20Sopenharmony_ci			rsp->ring_ptr++;
34408c2ecf20Sopenharmony_ci		}
34418c2ecf20Sopenharmony_ci
34428c2ecf20Sopenharmony_ci		if (pkt->entry_status != 0) {
34438c2ecf20Sopenharmony_ci			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
34448c2ecf20Sopenharmony_ci				goto process_err;
34458c2ecf20Sopenharmony_ci
34468c2ecf20Sopenharmony_ci			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
34478c2ecf20Sopenharmony_ci			wmb();
34488c2ecf20Sopenharmony_ci			continue;
34498c2ecf20Sopenharmony_ci		}
34508c2ecf20Sopenharmony_ciprocess_err:
34518c2ecf20Sopenharmony_ci
34528c2ecf20Sopenharmony_ci		switch (pkt->entry_type) {
34538c2ecf20Sopenharmony_ci		case STATUS_TYPE:
34548c2ecf20Sopenharmony_ci			qla2x00_status_entry(vha, rsp, pkt);
34558c2ecf20Sopenharmony_ci			break;
34568c2ecf20Sopenharmony_ci		case STATUS_CONT_TYPE:
34578c2ecf20Sopenharmony_ci			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
34588c2ecf20Sopenharmony_ci			break;
34598c2ecf20Sopenharmony_ci		case VP_RPT_ID_IOCB_TYPE:
34608c2ecf20Sopenharmony_ci			qla24xx_report_id_acquisition(vha,
34618c2ecf20Sopenharmony_ci			    (struct vp_rpt_id_entry_24xx *)pkt);
34628c2ecf20Sopenharmony_ci			break;
34638c2ecf20Sopenharmony_ci		case LOGINOUT_PORT_IOCB_TYPE:
34648c2ecf20Sopenharmony_ci			qla24xx_logio_entry(vha, rsp->req,
34658c2ecf20Sopenharmony_ci			    (struct logio_entry_24xx *)pkt);
34668c2ecf20Sopenharmony_ci			break;
34678c2ecf20Sopenharmony_ci		case CT_IOCB_TYPE:
34688c2ecf20Sopenharmony_ci			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
34698c2ecf20Sopenharmony_ci			break;
34708c2ecf20Sopenharmony_ci		case ELS_IOCB_TYPE:
34718c2ecf20Sopenharmony_ci			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
34728c2ecf20Sopenharmony_ci			break;
34738c2ecf20Sopenharmony_ci		case ABTS_RECV_24XX:
34748c2ecf20Sopenharmony_ci			if (qla_ini_mode_enabled(vha)) {
34758c2ecf20Sopenharmony_ci				pure_item = qla24xx_copy_std_pkt(vha, pkt);
34768c2ecf20Sopenharmony_ci				if (!pure_item)
34778c2ecf20Sopenharmony_ci					break;
34788c2ecf20Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
34798c2ecf20Sopenharmony_ci							 qla24xx_process_abts);
34808c2ecf20Sopenharmony_ci				break;
34818c2ecf20Sopenharmony_ci			}
34828c2ecf20Sopenharmony_ci			if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
34838c2ecf20Sopenharmony_ci			    IS_QLA28XX(ha)) {
34848c2ecf20Sopenharmony_ci				/* ensure that the ATIO queue is empty */
34858c2ecf20Sopenharmony_ci				qlt_handle_abts_recv(vha, rsp,
34868c2ecf20Sopenharmony_ci				    (response_t *)pkt);
34878c2ecf20Sopenharmony_ci				break;
34888c2ecf20Sopenharmony_ci			} else {
34898c2ecf20Sopenharmony_ci				qlt_24xx_process_atio_queue(vha, 1);
34908c2ecf20Sopenharmony_ci			}
34918c2ecf20Sopenharmony_ci			fallthrough;
34928c2ecf20Sopenharmony_ci		case ABTS_RESP_24XX:
34938c2ecf20Sopenharmony_ci		case CTIO_TYPE7:
34948c2ecf20Sopenharmony_ci		case CTIO_CRC2:
34958c2ecf20Sopenharmony_ci			qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt);
34968c2ecf20Sopenharmony_ci			break;
34978c2ecf20Sopenharmony_ci		case PT_LS4_REQUEST:
34988c2ecf20Sopenharmony_ci			qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt,
34998c2ecf20Sopenharmony_ci			    rsp->req);
35008c2ecf20Sopenharmony_ci			break;
35018c2ecf20Sopenharmony_ci		case NOTIFY_ACK_TYPE:
35028c2ecf20Sopenharmony_ci			if (pkt->handle == QLA_TGT_SKIP_HANDLE)
35038c2ecf20Sopenharmony_ci				qlt_response_pkt_all_vps(vha, rsp,
35048c2ecf20Sopenharmony_ci				    (response_t *)pkt);
35058c2ecf20Sopenharmony_ci			else
35068c2ecf20Sopenharmony_ci				qla24xxx_nack_iocb_entry(vha, rsp->req,
35078c2ecf20Sopenharmony_ci					(struct nack_to_isp *)pkt);
35088c2ecf20Sopenharmony_ci			break;
35098c2ecf20Sopenharmony_ci		case MARKER_TYPE:
35108c2ecf20Sopenharmony_ci			/* Do nothing in this case, this check is to prevent it
35118c2ecf20Sopenharmony_ci			 * from falling into default case
35128c2ecf20Sopenharmony_ci			 */
35138c2ecf20Sopenharmony_ci			break;
35148c2ecf20Sopenharmony_ci		case ABORT_IOCB_TYPE:
35158c2ecf20Sopenharmony_ci			qla24xx_abort_iocb_entry(vha, rsp->req,
35168c2ecf20Sopenharmony_ci			    (struct abort_entry_24xx *)pkt);
35178c2ecf20Sopenharmony_ci			break;
35188c2ecf20Sopenharmony_ci		case MBX_IOCB_TYPE:
35198c2ecf20Sopenharmony_ci			qla24xx_mbx_iocb_entry(vha, rsp->req,
35208c2ecf20Sopenharmony_ci			    (struct mbx_24xx_entry *)pkt);
35218c2ecf20Sopenharmony_ci			break;
35228c2ecf20Sopenharmony_ci		case VP_CTRL_IOCB_TYPE:
35238c2ecf20Sopenharmony_ci			qla_ctrlvp_completed(vha, rsp->req,
35248c2ecf20Sopenharmony_ci			    (struct vp_ctrl_entry_24xx *)pkt);
35258c2ecf20Sopenharmony_ci			break;
35268c2ecf20Sopenharmony_ci		case PUREX_IOCB_TYPE:
35278c2ecf20Sopenharmony_ci			purex_entry = (void *)pkt;
35288c2ecf20Sopenharmony_ci			switch (purex_entry->els_frame_payload[3]) {
35298c2ecf20Sopenharmony_ci			case ELS_RDP:
35308c2ecf20Sopenharmony_ci				pure_item = qla24xx_copy_std_pkt(vha, pkt);
35318c2ecf20Sopenharmony_ci				if (!pure_item)
35328c2ecf20Sopenharmony_ci					break;
35338c2ecf20Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
35348c2ecf20Sopenharmony_ci						 qla24xx_process_purex_rdp);
35358c2ecf20Sopenharmony_ci				break;
35368c2ecf20Sopenharmony_ci			case ELS_FPIN:
35378c2ecf20Sopenharmony_ci				if (!vha->hw->flags.scm_enabled) {
35388c2ecf20Sopenharmony_ci					ql_log(ql_log_warn, vha, 0x5094,
35398c2ecf20Sopenharmony_ci					       "SCM not active for this port\n");
35408c2ecf20Sopenharmony_ci					break;
35418c2ecf20Sopenharmony_ci				}
35428c2ecf20Sopenharmony_ci				pure_item = qla27xx_copy_fpin_pkt(vha,
35438c2ecf20Sopenharmony_ci							  (void **)&pkt, &rsp);
35448c2ecf20Sopenharmony_ci				if (!pure_item)
35458c2ecf20Sopenharmony_ci					break;
35468c2ecf20Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
35478c2ecf20Sopenharmony_ci						 qla27xx_process_purex_fpin);
35488c2ecf20Sopenharmony_ci				break;
35498c2ecf20Sopenharmony_ci
35508c2ecf20Sopenharmony_ci			default:
35518c2ecf20Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x509c,
35528c2ecf20Sopenharmony_ci				       "Discarding ELS Request opcode 0x%x\n",
35538c2ecf20Sopenharmony_ci				       purex_entry->els_frame_payload[3]);
35548c2ecf20Sopenharmony_ci			}
35558c2ecf20Sopenharmony_ci			break;
35568c2ecf20Sopenharmony_ci		default:
35578c2ecf20Sopenharmony_ci			/* Type Not Supported. */
35588c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5042,
35598c2ecf20Sopenharmony_ci			       "Received unknown response pkt type 0x%x entry status=%x.\n",
35608c2ecf20Sopenharmony_ci			       pkt->entry_type, pkt->entry_status);
35618c2ecf20Sopenharmony_ci			break;
35628c2ecf20Sopenharmony_ci		}
35638c2ecf20Sopenharmony_ci		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
35648c2ecf20Sopenharmony_ci		wmb();
35658c2ecf20Sopenharmony_ci	}
35668c2ecf20Sopenharmony_ci
35678c2ecf20Sopenharmony_ci	/* Adjust ring index */
35688c2ecf20Sopenharmony_ci	if (IS_P3P_TYPE(ha)) {
35698c2ecf20Sopenharmony_ci		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
35708c2ecf20Sopenharmony_ci
35718c2ecf20Sopenharmony_ci		wrt_reg_dword(&reg->rsp_q_out[0], rsp->ring_index);
35728c2ecf20Sopenharmony_ci	} else {
35738c2ecf20Sopenharmony_ci		wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index);
35748c2ecf20Sopenharmony_ci	}
35758c2ecf20Sopenharmony_ci}
35768c2ecf20Sopenharmony_ci
35778c2ecf20Sopenharmony_cistatic void
35788c2ecf20Sopenharmony_ciqla2xxx_check_risc_status(scsi_qla_host_t *vha)
35798c2ecf20Sopenharmony_ci{
35808c2ecf20Sopenharmony_ci	int rval;
35818c2ecf20Sopenharmony_ci	uint32_t cnt;
35828c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
35838c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
35848c2ecf20Sopenharmony_ci
35858c2ecf20Sopenharmony_ci	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
35868c2ecf20Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
35878c2ecf20Sopenharmony_ci		return;
35888c2ecf20Sopenharmony_ci
35898c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
35908c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->iobase_addr, 0x7C00);
35918c2ecf20Sopenharmony_ci	rd_reg_dword(&reg->iobase_addr);
35928c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0001);
35938c2ecf20Sopenharmony_ci	for (cnt = 10000; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
35948c2ecf20Sopenharmony_ci	    rval == QLA_SUCCESS; cnt--) {
35958c2ecf20Sopenharmony_ci		if (cnt) {
35968c2ecf20Sopenharmony_ci			wrt_reg_dword(&reg->iobase_window, 0x0001);
35978c2ecf20Sopenharmony_ci			udelay(10);
35988c2ecf20Sopenharmony_ci		} else
35998c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_TIMEOUT;
36008c2ecf20Sopenharmony_ci	}
36018c2ecf20Sopenharmony_ci	if (rval == QLA_SUCCESS)
36028c2ecf20Sopenharmony_ci		goto next_test;
36038c2ecf20Sopenharmony_ci
36048c2ecf20Sopenharmony_ci	rval = QLA_SUCCESS;
36058c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0003);
36068c2ecf20Sopenharmony_ci	for (cnt = 100; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
36078c2ecf20Sopenharmony_ci	    rval == QLA_SUCCESS; cnt--) {
36088c2ecf20Sopenharmony_ci		if (cnt) {
36098c2ecf20Sopenharmony_ci			wrt_reg_dword(&reg->iobase_window, 0x0003);
36108c2ecf20Sopenharmony_ci			udelay(10);
36118c2ecf20Sopenharmony_ci		} else
36128c2ecf20Sopenharmony_ci			rval = QLA_FUNCTION_TIMEOUT;
36138c2ecf20Sopenharmony_ci	}
36148c2ecf20Sopenharmony_ci	if (rval != QLA_SUCCESS)
36158c2ecf20Sopenharmony_ci		goto done;
36168c2ecf20Sopenharmony_ci
36178c2ecf20Sopenharmony_cinext_test:
36188c2ecf20Sopenharmony_ci	if (rd_reg_dword(&reg->iobase_c8) & BIT_3)
36198c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x504c,
36208c2ecf20Sopenharmony_ci		    "Additional code -- 0x55AA.\n");
36218c2ecf20Sopenharmony_ci
36228c2ecf20Sopenharmony_cidone:
36238c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0000);
36248c2ecf20Sopenharmony_ci	rd_reg_dword(&reg->iobase_window);
36258c2ecf20Sopenharmony_ci}
36268c2ecf20Sopenharmony_ci
36278c2ecf20Sopenharmony_ci/**
36288c2ecf20Sopenharmony_ci * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
36298c2ecf20Sopenharmony_ci * @irq: interrupt number
36308c2ecf20Sopenharmony_ci * @dev_id: SCSI driver HA context
36318c2ecf20Sopenharmony_ci *
36328c2ecf20Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
36338c2ecf20Sopenharmony_ci *
36348c2ecf20Sopenharmony_ci * Returns handled flag.
36358c2ecf20Sopenharmony_ci */
36368c2ecf20Sopenharmony_ciirqreturn_t
36378c2ecf20Sopenharmony_ciqla24xx_intr_handler(int irq, void *dev_id)
36388c2ecf20Sopenharmony_ci{
36398c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
36408c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
36418c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
36428c2ecf20Sopenharmony_ci	int		status;
36438c2ecf20Sopenharmony_ci	unsigned long	iter;
36448c2ecf20Sopenharmony_ci	uint32_t	stat;
36458c2ecf20Sopenharmony_ci	uint32_t	hccr;
36468c2ecf20Sopenharmony_ci	uint16_t	mb[8];
36478c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
36488c2ecf20Sopenharmony_ci	unsigned long	flags;
36498c2ecf20Sopenharmony_ci	bool process_atio = false;
36508c2ecf20Sopenharmony_ci
36518c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
36528c2ecf20Sopenharmony_ci	if (!rsp) {
36538c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x5059,
36548c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
36558c2ecf20Sopenharmony_ci		return IRQ_NONE;
36568c2ecf20Sopenharmony_ci	}
36578c2ecf20Sopenharmony_ci
36588c2ecf20Sopenharmony_ci	ha = rsp->hw;
36598c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp24;
36608c2ecf20Sopenharmony_ci	status = 0;
36618c2ecf20Sopenharmony_ci
36628c2ecf20Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
36638c2ecf20Sopenharmony_ci		return IRQ_HANDLED;
36648c2ecf20Sopenharmony_ci
36658c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
36668c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
36678c2ecf20Sopenharmony_ci	for (iter = 50; iter--; ) {
36688c2ecf20Sopenharmony_ci		stat = rd_reg_dword(&reg->host_status);
36698c2ecf20Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
36708c2ecf20Sopenharmony_ci			break;
36718c2ecf20Sopenharmony_ci		if (stat & HSRX_RISC_PAUSED) {
36728c2ecf20Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
36738c2ecf20Sopenharmony_ci				break;
36748c2ecf20Sopenharmony_ci
36758c2ecf20Sopenharmony_ci			hccr = rd_reg_dword(&reg->hccr);
36768c2ecf20Sopenharmony_ci
36778c2ecf20Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x504b,
36788c2ecf20Sopenharmony_ci			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
36798c2ecf20Sopenharmony_ci			    hccr);
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci			qla2xxx_check_risc_status(vha);
36828c2ecf20Sopenharmony_ci
36838c2ecf20Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
36848c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
36858c2ecf20Sopenharmony_ci			break;
36868c2ecf20Sopenharmony_ci		} else if ((stat & HSRX_RISC_INT) == 0)
36878c2ecf20Sopenharmony_ci			break;
36888c2ecf20Sopenharmony_ci
36898c2ecf20Sopenharmony_ci		switch (stat & 0xff) {
36908c2ecf20Sopenharmony_ci		case INTR_ROM_MB_SUCCESS:
36918c2ecf20Sopenharmony_ci		case INTR_ROM_MB_FAILED:
36928c2ecf20Sopenharmony_ci		case INTR_MB_SUCCESS:
36938c2ecf20Sopenharmony_ci		case INTR_MB_FAILED:
36948c2ecf20Sopenharmony_ci			qla24xx_mbx_completion(vha, MSW(stat));
36958c2ecf20Sopenharmony_ci			status |= MBX_INTERRUPT;
36968c2ecf20Sopenharmony_ci
36978c2ecf20Sopenharmony_ci			break;
36988c2ecf20Sopenharmony_ci		case INTR_ASYNC_EVENT:
36998c2ecf20Sopenharmony_ci			mb[0] = MSW(stat);
37008c2ecf20Sopenharmony_ci			mb[1] = rd_reg_word(&reg->mailbox1);
37018c2ecf20Sopenharmony_ci			mb[2] = rd_reg_word(&reg->mailbox2);
37028c2ecf20Sopenharmony_ci			mb[3] = rd_reg_word(&reg->mailbox3);
37038c2ecf20Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
37048c2ecf20Sopenharmony_ci			break;
37058c2ecf20Sopenharmony_ci		case INTR_RSP_QUE_UPDATE:
37068c2ecf20Sopenharmony_ci		case INTR_RSP_QUE_UPDATE_83XX:
37078c2ecf20Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
37088c2ecf20Sopenharmony_ci			break;
37098c2ecf20Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE_27XX:
37108c2ecf20Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE:
37118c2ecf20Sopenharmony_ci			process_atio = true;
37128c2ecf20Sopenharmony_ci			break;
37138c2ecf20Sopenharmony_ci		case INTR_ATIO_RSP_QUE_UPDATE:
37148c2ecf20Sopenharmony_ci			process_atio = true;
37158c2ecf20Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
37168c2ecf20Sopenharmony_ci			break;
37178c2ecf20Sopenharmony_ci		default:
37188c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x504f,
37198c2ecf20Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
37208c2ecf20Sopenharmony_ci			break;
37218c2ecf20Sopenharmony_ci		}
37228c2ecf20Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
37238c2ecf20Sopenharmony_ci		rd_reg_dword_relaxed(&reg->hccr);
37248c2ecf20Sopenharmony_ci		if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
37258c2ecf20Sopenharmony_ci			ndelay(3500);
37268c2ecf20Sopenharmony_ci	}
37278c2ecf20Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
37288c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_ci	if (process_atio) {
37318c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
37328c2ecf20Sopenharmony_ci		qlt_24xx_process_atio_queue(vha, 0);
37338c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
37348c2ecf20Sopenharmony_ci	}
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
37378c2ecf20Sopenharmony_ci}
37388c2ecf20Sopenharmony_ci
37398c2ecf20Sopenharmony_cistatic irqreturn_t
37408c2ecf20Sopenharmony_ciqla24xx_msix_rsp_q(int irq, void *dev_id)
37418c2ecf20Sopenharmony_ci{
37428c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
37438c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
37448c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
37458c2ecf20Sopenharmony_ci	struct scsi_qla_host *vha;
37468c2ecf20Sopenharmony_ci	unsigned long flags;
37478c2ecf20Sopenharmony_ci
37488c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
37498c2ecf20Sopenharmony_ci	if (!rsp) {
37508c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505a,
37518c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
37528c2ecf20Sopenharmony_ci		return IRQ_NONE;
37538c2ecf20Sopenharmony_ci	}
37548c2ecf20Sopenharmony_ci	ha = rsp->hw;
37558c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp24;
37568c2ecf20Sopenharmony_ci
37578c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
37588c2ecf20Sopenharmony_ci
37598c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
37608c2ecf20Sopenharmony_ci	qla24xx_process_response_queue(vha, rsp);
37618c2ecf20Sopenharmony_ci	if (!ha->flags.disable_msix_handshake) {
37628c2ecf20Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
37638c2ecf20Sopenharmony_ci		rd_reg_dword_relaxed(&reg->hccr);
37648c2ecf20Sopenharmony_ci	}
37658c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
37668c2ecf20Sopenharmony_ci
37678c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
37688c2ecf20Sopenharmony_ci}
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_cistatic irqreturn_t
37718c2ecf20Sopenharmony_ciqla24xx_msix_default(int irq, void *dev_id)
37728c2ecf20Sopenharmony_ci{
37738c2ecf20Sopenharmony_ci	scsi_qla_host_t	*vha;
37748c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
37758c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
37768c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
37778c2ecf20Sopenharmony_ci	int		status;
37788c2ecf20Sopenharmony_ci	uint32_t	stat;
37798c2ecf20Sopenharmony_ci	uint32_t	hccr;
37808c2ecf20Sopenharmony_ci	uint16_t	mb[8];
37818c2ecf20Sopenharmony_ci	unsigned long flags;
37828c2ecf20Sopenharmony_ci	bool process_atio = false;
37838c2ecf20Sopenharmony_ci
37848c2ecf20Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
37858c2ecf20Sopenharmony_ci	if (!rsp) {
37868c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505c,
37878c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
37888c2ecf20Sopenharmony_ci		return IRQ_NONE;
37898c2ecf20Sopenharmony_ci	}
37908c2ecf20Sopenharmony_ci	ha = rsp->hw;
37918c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp24;
37928c2ecf20Sopenharmony_ci	status = 0;
37938c2ecf20Sopenharmony_ci
37948c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
37958c2ecf20Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
37968c2ecf20Sopenharmony_ci	do {
37978c2ecf20Sopenharmony_ci		stat = rd_reg_dword(&reg->host_status);
37988c2ecf20Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
37998c2ecf20Sopenharmony_ci			break;
38008c2ecf20Sopenharmony_ci		if (stat & HSRX_RISC_PAUSED) {
38018c2ecf20Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
38028c2ecf20Sopenharmony_ci				break;
38038c2ecf20Sopenharmony_ci
38048c2ecf20Sopenharmony_ci			hccr = rd_reg_dword(&reg->hccr);
38058c2ecf20Sopenharmony_ci
38068c2ecf20Sopenharmony_ci			ql_log(ql_log_info, vha, 0x5050,
38078c2ecf20Sopenharmony_ci			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
38088c2ecf20Sopenharmony_ci			    hccr);
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci			qla2xxx_check_risc_status(vha);
38118c2ecf20Sopenharmony_ci
38128c2ecf20Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
38138c2ecf20Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
38148c2ecf20Sopenharmony_ci			break;
38158c2ecf20Sopenharmony_ci		} else if ((stat & HSRX_RISC_INT) == 0)
38168c2ecf20Sopenharmony_ci			break;
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci		switch (stat & 0xff) {
38198c2ecf20Sopenharmony_ci		case INTR_ROM_MB_SUCCESS:
38208c2ecf20Sopenharmony_ci		case INTR_ROM_MB_FAILED:
38218c2ecf20Sopenharmony_ci		case INTR_MB_SUCCESS:
38228c2ecf20Sopenharmony_ci		case INTR_MB_FAILED:
38238c2ecf20Sopenharmony_ci			qla24xx_mbx_completion(vha, MSW(stat));
38248c2ecf20Sopenharmony_ci			status |= MBX_INTERRUPT;
38258c2ecf20Sopenharmony_ci
38268c2ecf20Sopenharmony_ci			break;
38278c2ecf20Sopenharmony_ci		case INTR_ASYNC_EVENT:
38288c2ecf20Sopenharmony_ci			mb[0] = MSW(stat);
38298c2ecf20Sopenharmony_ci			mb[1] = rd_reg_word(&reg->mailbox1);
38308c2ecf20Sopenharmony_ci			mb[2] = rd_reg_word(&reg->mailbox2);
38318c2ecf20Sopenharmony_ci			mb[3] = rd_reg_word(&reg->mailbox3);
38328c2ecf20Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
38338c2ecf20Sopenharmony_ci			break;
38348c2ecf20Sopenharmony_ci		case INTR_RSP_QUE_UPDATE:
38358c2ecf20Sopenharmony_ci		case INTR_RSP_QUE_UPDATE_83XX:
38368c2ecf20Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
38378c2ecf20Sopenharmony_ci			break;
38388c2ecf20Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE_27XX:
38398c2ecf20Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE:
38408c2ecf20Sopenharmony_ci			process_atio = true;
38418c2ecf20Sopenharmony_ci			break;
38428c2ecf20Sopenharmony_ci		case INTR_ATIO_RSP_QUE_UPDATE:
38438c2ecf20Sopenharmony_ci			process_atio = true;
38448c2ecf20Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
38458c2ecf20Sopenharmony_ci			break;
38468c2ecf20Sopenharmony_ci		default:
38478c2ecf20Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5051,
38488c2ecf20Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
38498c2ecf20Sopenharmony_ci			break;
38508c2ecf20Sopenharmony_ci		}
38518c2ecf20Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
38528c2ecf20Sopenharmony_ci	} while (0);
38538c2ecf20Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
38548c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
38558c2ecf20Sopenharmony_ci
38568c2ecf20Sopenharmony_ci	if (process_atio) {
38578c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
38588c2ecf20Sopenharmony_ci		qlt_24xx_process_atio_queue(vha, 0);
38598c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
38608c2ecf20Sopenharmony_ci	}
38618c2ecf20Sopenharmony_ci
38628c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
38638c2ecf20Sopenharmony_ci}
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ciirqreturn_t
38668c2ecf20Sopenharmony_ciqla2xxx_msix_rsp_q(int irq, void *dev_id)
38678c2ecf20Sopenharmony_ci{
38688c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
38698c2ecf20Sopenharmony_ci	struct qla_qpair *qpair;
38708c2ecf20Sopenharmony_ci
38718c2ecf20Sopenharmony_ci	qpair = dev_id;
38728c2ecf20Sopenharmony_ci	if (!qpair) {
38738c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505b,
38748c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
38758c2ecf20Sopenharmony_ci		return IRQ_NONE;
38768c2ecf20Sopenharmony_ci	}
38778c2ecf20Sopenharmony_ci	ha = qpair->hw;
38788c2ecf20Sopenharmony_ci
38798c2ecf20Sopenharmony_ci	queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work);
38808c2ecf20Sopenharmony_ci
38818c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
38828c2ecf20Sopenharmony_ci}
38838c2ecf20Sopenharmony_ci
38848c2ecf20Sopenharmony_ciirqreturn_t
38858c2ecf20Sopenharmony_ciqla2xxx_msix_rsp_q_hs(int irq, void *dev_id)
38868c2ecf20Sopenharmony_ci{
38878c2ecf20Sopenharmony_ci	struct qla_hw_data *ha;
38888c2ecf20Sopenharmony_ci	struct qla_qpair *qpair;
38898c2ecf20Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
38908c2ecf20Sopenharmony_ci	unsigned long flags;
38918c2ecf20Sopenharmony_ci
38928c2ecf20Sopenharmony_ci	qpair = dev_id;
38938c2ecf20Sopenharmony_ci	if (!qpair) {
38948c2ecf20Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505b,
38958c2ecf20Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
38968c2ecf20Sopenharmony_ci		return IRQ_NONE;
38978c2ecf20Sopenharmony_ci	}
38988c2ecf20Sopenharmony_ci	ha = qpair->hw;
38998c2ecf20Sopenharmony_ci
39008c2ecf20Sopenharmony_ci	reg = &ha->iobase->isp24;
39018c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
39028c2ecf20Sopenharmony_ci	wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
39038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	queue_work_on(smp_processor_id(), ha->wq, &qpair->q_work);
39068c2ecf20Sopenharmony_ci
39078c2ecf20Sopenharmony_ci	return IRQ_HANDLED;
39088c2ecf20Sopenharmony_ci}
39098c2ecf20Sopenharmony_ci
39108c2ecf20Sopenharmony_ci/* Interrupt handling helpers. */
39118c2ecf20Sopenharmony_ci
39128c2ecf20Sopenharmony_cistruct qla_init_msix_entry {
39138c2ecf20Sopenharmony_ci	const char *name;
39148c2ecf20Sopenharmony_ci	irq_handler_t handler;
39158c2ecf20Sopenharmony_ci};
39168c2ecf20Sopenharmony_ci
39178c2ecf20Sopenharmony_cistatic const struct qla_init_msix_entry msix_entries[] = {
39188c2ecf20Sopenharmony_ci	{ "default", qla24xx_msix_default },
39198c2ecf20Sopenharmony_ci	{ "rsp_q", qla24xx_msix_rsp_q },
39208c2ecf20Sopenharmony_ci	{ "atio_q", qla83xx_msix_atio_q },
39218c2ecf20Sopenharmony_ci	{ "qpair_multiq", qla2xxx_msix_rsp_q },
39228c2ecf20Sopenharmony_ci	{ "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs },
39238c2ecf20Sopenharmony_ci};
39248c2ecf20Sopenharmony_ci
39258c2ecf20Sopenharmony_cistatic const struct qla_init_msix_entry qla82xx_msix_entries[] = {
39268c2ecf20Sopenharmony_ci	{ "qla2xxx (default)", qla82xx_msix_default },
39278c2ecf20Sopenharmony_ci	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
39288c2ecf20Sopenharmony_ci};
39298c2ecf20Sopenharmony_ci
39308c2ecf20Sopenharmony_cistatic int
39318c2ecf20Sopenharmony_ciqla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
39328c2ecf20Sopenharmony_ci{
39338c2ecf20Sopenharmony_ci	int i, ret;
39348c2ecf20Sopenharmony_ci	struct qla_msix_entry *qentry;
39358c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
39368c2ecf20Sopenharmony_ci	int min_vecs = QLA_BASE_VECTORS;
39378c2ecf20Sopenharmony_ci	struct irq_affinity desc = {
39388c2ecf20Sopenharmony_ci		.pre_vectors = QLA_BASE_VECTORS,
39398c2ecf20Sopenharmony_ci	};
39408c2ecf20Sopenharmony_ci
39418c2ecf20Sopenharmony_ci	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
39428c2ecf20Sopenharmony_ci	    IS_ATIO_MSIX_CAPABLE(ha)) {
39438c2ecf20Sopenharmony_ci		desc.pre_vectors++;
39448c2ecf20Sopenharmony_ci		min_vecs++;
39458c2ecf20Sopenharmony_ci	}
39468c2ecf20Sopenharmony_ci
39478c2ecf20Sopenharmony_ci	if (USER_CTRL_IRQ(ha) || !ha->mqiobase) {
39488c2ecf20Sopenharmony_ci		/* user wants to control IRQ setting for target mode */
39498c2ecf20Sopenharmony_ci		ret = pci_alloc_irq_vectors(ha->pdev, min_vecs,
39508c2ecf20Sopenharmony_ci		    ha->msix_count, PCI_IRQ_MSIX);
39518c2ecf20Sopenharmony_ci	} else
39528c2ecf20Sopenharmony_ci		ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs,
39538c2ecf20Sopenharmony_ci		    ha->msix_count, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
39548c2ecf20Sopenharmony_ci		    &desc);
39558c2ecf20Sopenharmony_ci
39568c2ecf20Sopenharmony_ci	if (ret < 0) {
39578c2ecf20Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00c7,
39588c2ecf20Sopenharmony_ci		    "MSI-X: Failed to enable support, "
39598c2ecf20Sopenharmony_ci		    "giving   up -- %d/%d.\n",
39608c2ecf20Sopenharmony_ci		    ha->msix_count, ret);
39618c2ecf20Sopenharmony_ci		goto msix_out;
39628c2ecf20Sopenharmony_ci	} else if (ret < ha->msix_count) {
39638c2ecf20Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00c6,
39648c2ecf20Sopenharmony_ci		    "MSI-X: Using %d vectors\n", ret);
39658c2ecf20Sopenharmony_ci		ha->msix_count = ret;
39668c2ecf20Sopenharmony_ci		/* Recalculate queue values */
39678c2ecf20Sopenharmony_ci		if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) {
39688c2ecf20Sopenharmony_ci			ha->max_req_queues = ha->msix_count - 1;
39698c2ecf20Sopenharmony_ci
39708c2ecf20Sopenharmony_ci			/* ATIOQ needs 1 vector. That's 1 less QPair */
39718c2ecf20Sopenharmony_ci			if (QLA_TGT_MODE_ENABLED())
39728c2ecf20Sopenharmony_ci				ha->max_req_queues--;
39738c2ecf20Sopenharmony_ci
39748c2ecf20Sopenharmony_ci			ha->max_rsp_queues = ha->max_req_queues;
39758c2ecf20Sopenharmony_ci
39768c2ecf20Sopenharmony_ci			ha->max_qpairs = ha->max_req_queues - 1;
39778c2ecf20Sopenharmony_ci			ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190,
39788c2ecf20Sopenharmony_ci			    "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs);
39798c2ecf20Sopenharmony_ci		}
39808c2ecf20Sopenharmony_ci	}
39818c2ecf20Sopenharmony_ci	vha->irq_offset = desc.pre_vectors;
39828c2ecf20Sopenharmony_ci	ha->msix_entries = kcalloc(ha->msix_count,
39838c2ecf20Sopenharmony_ci				   sizeof(struct qla_msix_entry),
39848c2ecf20Sopenharmony_ci				   GFP_KERNEL);
39858c2ecf20Sopenharmony_ci	if (!ha->msix_entries) {
39868c2ecf20Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00c8,
39878c2ecf20Sopenharmony_ci		    "Failed to allocate memory for ha->msix_entries.\n");
39888c2ecf20Sopenharmony_ci		ret = -ENOMEM;
39898c2ecf20Sopenharmony_ci		goto free_irqs;
39908c2ecf20Sopenharmony_ci	}
39918c2ecf20Sopenharmony_ci	ha->flags.msix_enabled = 1;
39928c2ecf20Sopenharmony_ci
39938c2ecf20Sopenharmony_ci	for (i = 0; i < ha->msix_count; i++) {
39948c2ecf20Sopenharmony_ci		qentry = &ha->msix_entries[i];
39958c2ecf20Sopenharmony_ci		qentry->vector = pci_irq_vector(ha->pdev, i);
39968c2ecf20Sopenharmony_ci		qentry->entry = i;
39978c2ecf20Sopenharmony_ci		qentry->have_irq = 0;
39988c2ecf20Sopenharmony_ci		qentry->in_use = 0;
39998c2ecf20Sopenharmony_ci		qentry->handle = NULL;
40008c2ecf20Sopenharmony_ci	}
40018c2ecf20Sopenharmony_ci
40028c2ecf20Sopenharmony_ci	/* Enable MSI-X vectors for the base queue */
40038c2ecf20Sopenharmony_ci	for (i = 0; i < QLA_BASE_VECTORS; i++) {
40048c2ecf20Sopenharmony_ci		qentry = &ha->msix_entries[i];
40058c2ecf20Sopenharmony_ci		qentry->handle = rsp;
40068c2ecf20Sopenharmony_ci		rsp->msix = qentry;
40078c2ecf20Sopenharmony_ci		scnprintf(qentry->name, sizeof(qentry->name),
40088c2ecf20Sopenharmony_ci		    "qla2xxx%lu_%s", vha->host_no, msix_entries[i].name);
40098c2ecf20Sopenharmony_ci		if (IS_P3P_TYPE(ha))
40108c2ecf20Sopenharmony_ci			ret = request_irq(qentry->vector,
40118c2ecf20Sopenharmony_ci				qla82xx_msix_entries[i].handler,
40128c2ecf20Sopenharmony_ci				0, qla82xx_msix_entries[i].name, rsp);
40138c2ecf20Sopenharmony_ci		else
40148c2ecf20Sopenharmony_ci			ret = request_irq(qentry->vector,
40158c2ecf20Sopenharmony_ci				msix_entries[i].handler,
40168c2ecf20Sopenharmony_ci				0, qentry->name, rsp);
40178c2ecf20Sopenharmony_ci		if (ret)
40188c2ecf20Sopenharmony_ci			goto msix_register_fail;
40198c2ecf20Sopenharmony_ci		qentry->have_irq = 1;
40208c2ecf20Sopenharmony_ci		qentry->in_use = 1;
40218c2ecf20Sopenharmony_ci	}
40228c2ecf20Sopenharmony_ci
40238c2ecf20Sopenharmony_ci	/*
40248c2ecf20Sopenharmony_ci	 * If target mode is enable, also request the vector for the ATIO
40258c2ecf20Sopenharmony_ci	 * queue.
40268c2ecf20Sopenharmony_ci	 */
40278c2ecf20Sopenharmony_ci	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
40288c2ecf20Sopenharmony_ci	    IS_ATIO_MSIX_CAPABLE(ha)) {
40298c2ecf20Sopenharmony_ci		qentry = &ha->msix_entries[QLA_ATIO_VECTOR];
40308c2ecf20Sopenharmony_ci		rsp->msix = qentry;
40318c2ecf20Sopenharmony_ci		qentry->handle = rsp;
40328c2ecf20Sopenharmony_ci		scnprintf(qentry->name, sizeof(qentry->name),
40338c2ecf20Sopenharmony_ci		    "qla2xxx%lu_%s", vha->host_no,
40348c2ecf20Sopenharmony_ci		    msix_entries[QLA_ATIO_VECTOR].name);
40358c2ecf20Sopenharmony_ci		qentry->in_use = 1;
40368c2ecf20Sopenharmony_ci		ret = request_irq(qentry->vector,
40378c2ecf20Sopenharmony_ci			msix_entries[QLA_ATIO_VECTOR].handler,
40388c2ecf20Sopenharmony_ci			0, qentry->name, rsp);
40398c2ecf20Sopenharmony_ci		qentry->have_irq = 1;
40408c2ecf20Sopenharmony_ci	}
40418c2ecf20Sopenharmony_ci
40428c2ecf20Sopenharmony_cimsix_register_fail:
40438c2ecf20Sopenharmony_ci	if (ret) {
40448c2ecf20Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00cb,
40458c2ecf20Sopenharmony_ci		    "MSI-X: unable to register handler -- %x/%d.\n",
40468c2ecf20Sopenharmony_ci		    qentry->vector, ret);
40478c2ecf20Sopenharmony_ci		qla2x00_free_irqs(vha);
40488c2ecf20Sopenharmony_ci		ha->mqenable = 0;
40498c2ecf20Sopenharmony_ci		goto msix_out;
40508c2ecf20Sopenharmony_ci	}
40518c2ecf20Sopenharmony_ci
40528c2ecf20Sopenharmony_ci	/* Enable MSI-X vector for response queue update for queue 0 */
40538c2ecf20Sopenharmony_ci	if (IS_MQUE_CAPABLE(ha) &&
40548c2ecf20Sopenharmony_ci	    (ha->msixbase && ha->mqiobase && ha->max_qpairs))
40558c2ecf20Sopenharmony_ci		ha->mqenable = 1;
40568c2ecf20Sopenharmony_ci	else
40578c2ecf20Sopenharmony_ci		ha->mqenable = 0;
40588c2ecf20Sopenharmony_ci
40598c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_multiq, vha, 0xc005,
40608c2ecf20Sopenharmony_ci	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
40618c2ecf20Sopenharmony_ci	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
40628c2ecf20Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0055,
40638c2ecf20Sopenharmony_ci	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
40648c2ecf20Sopenharmony_ci	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
40658c2ecf20Sopenharmony_ci
40668c2ecf20Sopenharmony_cimsix_out:
40678c2ecf20Sopenharmony_ci	return ret;
40688c2ecf20Sopenharmony_ci
40698c2ecf20Sopenharmony_cifree_irqs:
40708c2ecf20Sopenharmony_ci	pci_free_irq_vectors(ha->pdev);
40718c2ecf20Sopenharmony_ci	goto msix_out;
40728c2ecf20Sopenharmony_ci}
40738c2ecf20Sopenharmony_ci
40748c2ecf20Sopenharmony_ciint
40758c2ecf20Sopenharmony_ciqla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
40768c2ecf20Sopenharmony_ci{
40778c2ecf20Sopenharmony_ci	int ret = QLA_FUNCTION_FAILED;
40788c2ecf20Sopenharmony_ci	device_reg_t *reg = ha->iobase;
40798c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
40808c2ecf20Sopenharmony_ci
40818c2ecf20Sopenharmony_ci	/* If possible, enable MSI-X. */
40828c2ecf20Sopenharmony_ci	if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
40838c2ecf20Sopenharmony_ci	    !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
40848c2ecf20Sopenharmony_ci	    !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
40858c2ecf20Sopenharmony_ci		goto skip_msi;
40868c2ecf20Sopenharmony_ci
40878c2ecf20Sopenharmony_ci	if (ql2xenablemsix == 2)
40888c2ecf20Sopenharmony_ci		goto skip_msix;
40898c2ecf20Sopenharmony_ci
40908c2ecf20Sopenharmony_ci	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
40918c2ecf20Sopenharmony_ci		(ha->pdev->subsystem_device == 0x7040 ||
40928c2ecf20Sopenharmony_ci		ha->pdev->subsystem_device == 0x7041 ||
40938c2ecf20Sopenharmony_ci		ha->pdev->subsystem_device == 0x1705)) {
40948c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0034,
40958c2ecf20Sopenharmony_ci		    "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
40968c2ecf20Sopenharmony_ci			ha->pdev->subsystem_vendor,
40978c2ecf20Sopenharmony_ci			ha->pdev->subsystem_device);
40988c2ecf20Sopenharmony_ci		goto skip_msi;
40998c2ecf20Sopenharmony_ci	}
41008c2ecf20Sopenharmony_ci
41018c2ecf20Sopenharmony_ci	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
41028c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0035,
41038c2ecf20Sopenharmony_ci		    "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
41048c2ecf20Sopenharmony_ci		    ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
41058c2ecf20Sopenharmony_ci		goto skip_msix;
41068c2ecf20Sopenharmony_ci	}
41078c2ecf20Sopenharmony_ci
41088c2ecf20Sopenharmony_ci	ret = qla24xx_enable_msix(ha, rsp);
41098c2ecf20Sopenharmony_ci	if (!ret) {
41108c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0036,
41118c2ecf20Sopenharmony_ci		    "MSI-X: Enabled (0x%X, 0x%X).\n",
41128c2ecf20Sopenharmony_ci		    ha->chip_revision, ha->fw_attributes);
41138c2ecf20Sopenharmony_ci		goto clear_risc_ints;
41148c2ecf20Sopenharmony_ci	}
41158c2ecf20Sopenharmony_ci
41168c2ecf20Sopenharmony_ciskip_msix:
41178c2ecf20Sopenharmony_ci
41188c2ecf20Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0037,
41198c2ecf20Sopenharmony_ci	    "Falling back-to MSI mode -- ret=%d.\n", ret);
41208c2ecf20Sopenharmony_ci
41218c2ecf20Sopenharmony_ci	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
41228c2ecf20Sopenharmony_ci	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
41238c2ecf20Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
41248c2ecf20Sopenharmony_ci		goto skip_msi;
41258c2ecf20Sopenharmony_ci
41268c2ecf20Sopenharmony_ci	ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
41278c2ecf20Sopenharmony_ci	if (ret > 0) {
41288c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0038,
41298c2ecf20Sopenharmony_ci		    "MSI: Enabled.\n");
41308c2ecf20Sopenharmony_ci		ha->flags.msi_enabled = 1;
41318c2ecf20Sopenharmony_ci	} else
41328c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0039,
41338c2ecf20Sopenharmony_ci		    "Falling back-to INTa mode -- ret=%d.\n", ret);
41348c2ecf20Sopenharmony_ciskip_msi:
41358c2ecf20Sopenharmony_ci
41368c2ecf20Sopenharmony_ci	/* Skip INTx on ISP82xx. */
41378c2ecf20Sopenharmony_ci	if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
41388c2ecf20Sopenharmony_ci		return QLA_FUNCTION_FAILED;
41398c2ecf20Sopenharmony_ci
41408c2ecf20Sopenharmony_ci	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
41418c2ecf20Sopenharmony_ci	    ha->flags.msi_enabled ? 0 : IRQF_SHARED,
41428c2ecf20Sopenharmony_ci	    QLA2XXX_DRIVER_NAME, rsp);
41438c2ecf20Sopenharmony_ci	if (ret) {
41448c2ecf20Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x003a,
41458c2ecf20Sopenharmony_ci		    "Failed to reserve interrupt %d already in use.\n",
41468c2ecf20Sopenharmony_ci		    ha->pdev->irq);
41478c2ecf20Sopenharmony_ci		goto fail;
41488c2ecf20Sopenharmony_ci	} else if (!ha->flags.msi_enabled) {
41498c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0125,
41508c2ecf20Sopenharmony_ci		    "INTa mode: Enabled.\n");
41518c2ecf20Sopenharmony_ci		ha->flags.mr_intr_valid = 1;
41528c2ecf20Sopenharmony_ci		/* Set max_qpair to 0, as MSI-X and MSI in not enabled */
41538c2ecf20Sopenharmony_ci		ha->max_qpairs = 0;
41548c2ecf20Sopenharmony_ci	}
41558c2ecf20Sopenharmony_ci
41568c2ecf20Sopenharmony_ciclear_risc_ints:
41578c2ecf20Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
41588c2ecf20Sopenharmony_ci		goto fail;
41598c2ecf20Sopenharmony_ci
41608c2ecf20Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
41618c2ecf20Sopenharmony_ci	wrt_reg_word(&reg->isp.semaphore, 0);
41628c2ecf20Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
41638c2ecf20Sopenharmony_ci
41648c2ecf20Sopenharmony_cifail:
41658c2ecf20Sopenharmony_ci	return ret;
41668c2ecf20Sopenharmony_ci}
41678c2ecf20Sopenharmony_ci
41688c2ecf20Sopenharmony_civoid
41698c2ecf20Sopenharmony_ciqla2x00_free_irqs(scsi_qla_host_t *vha)
41708c2ecf20Sopenharmony_ci{
41718c2ecf20Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
41728c2ecf20Sopenharmony_ci	struct rsp_que *rsp;
41738c2ecf20Sopenharmony_ci	struct qla_msix_entry *qentry;
41748c2ecf20Sopenharmony_ci	int i;
41758c2ecf20Sopenharmony_ci
41768c2ecf20Sopenharmony_ci	/*
41778c2ecf20Sopenharmony_ci	 * We need to check that ha->rsp_q_map is valid in case we are called
41788c2ecf20Sopenharmony_ci	 * from a probe failure context.
41798c2ecf20Sopenharmony_ci	 */
41808c2ecf20Sopenharmony_ci	if (!ha->rsp_q_map || !ha->rsp_q_map[0])
41818c2ecf20Sopenharmony_ci		goto free_irqs;
41828c2ecf20Sopenharmony_ci	rsp = ha->rsp_q_map[0];
41838c2ecf20Sopenharmony_ci
41848c2ecf20Sopenharmony_ci	if (ha->flags.msix_enabled) {
41858c2ecf20Sopenharmony_ci		for (i = 0; i < ha->msix_count; i++) {
41868c2ecf20Sopenharmony_ci			qentry = &ha->msix_entries[i];
41878c2ecf20Sopenharmony_ci			if (qentry->have_irq) {
41888c2ecf20Sopenharmony_ci				irq_set_affinity_notifier(qentry->vector, NULL);
41898c2ecf20Sopenharmony_ci				free_irq(pci_irq_vector(ha->pdev, i), qentry->handle);
41908c2ecf20Sopenharmony_ci			}
41918c2ecf20Sopenharmony_ci		}
41928c2ecf20Sopenharmony_ci		kfree(ha->msix_entries);
41938c2ecf20Sopenharmony_ci		ha->msix_entries = NULL;
41948c2ecf20Sopenharmony_ci		ha->flags.msix_enabled = 0;
41958c2ecf20Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0042,
41968c2ecf20Sopenharmony_ci			"Disabled MSI-X.\n");
41978c2ecf20Sopenharmony_ci	} else {
41988c2ecf20Sopenharmony_ci		free_irq(pci_irq_vector(ha->pdev, 0), rsp);
41998c2ecf20Sopenharmony_ci	}
42008c2ecf20Sopenharmony_ci
42018c2ecf20Sopenharmony_cifree_irqs:
42028c2ecf20Sopenharmony_ci	pci_free_irq_vectors(ha->pdev);
42038c2ecf20Sopenharmony_ci}
42048c2ecf20Sopenharmony_ci
42058c2ecf20Sopenharmony_ciint qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
42068c2ecf20Sopenharmony_ci	struct qla_msix_entry *msix, int vector_type)
42078c2ecf20Sopenharmony_ci{
42088c2ecf20Sopenharmony_ci	const struct qla_init_msix_entry *intr = &msix_entries[vector_type];
42098c2ecf20Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
42108c2ecf20Sopenharmony_ci	int ret;
42118c2ecf20Sopenharmony_ci
42128c2ecf20Sopenharmony_ci	scnprintf(msix->name, sizeof(msix->name),
42138c2ecf20Sopenharmony_ci	    "qla2xxx%lu_qpair%d", vha->host_no, qpair->id);
42148c2ecf20Sopenharmony_ci	ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair);
42158c2ecf20Sopenharmony_ci	if (ret) {
42168c2ecf20Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00e6,
42178c2ecf20Sopenharmony_ci		    "MSI-X: Unable to register handler -- %x/%d.\n",
42188c2ecf20Sopenharmony_ci		    msix->vector, ret);
42198c2ecf20Sopenharmony_ci		return ret;
42208c2ecf20Sopenharmony_ci	}
42218c2ecf20Sopenharmony_ci	msix->have_irq = 1;
42228c2ecf20Sopenharmony_ci	msix->handle = qpair;
42238c2ecf20Sopenharmony_ci	return ret;
42248c2ecf20Sopenharmony_ci}
4225