162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include "qla_target.h"
862306a36Sopenharmony_ci#include "qla_gbl.h"
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/delay.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/cpu.h>
1362306a36Sopenharmony_ci#include <linux/t10-pi.h>
1462306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1562306a36Sopenharmony_ci#include <scsi/scsi_bsg_fc.h>
1662306a36Sopenharmony_ci#include <scsi/scsi_eh.h>
1762306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h>
1862306a36Sopenharmony_ci#include <linux/nvme-fc-driver.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistatic void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
2162306a36Sopenharmony_cistatic void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
2262306a36Sopenharmony_cistatic void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
2362306a36Sopenharmony_cistatic int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
2462306a36Sopenharmony_ci	sts_entry_t *);
2562306a36Sopenharmony_cistatic void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
2662306a36Sopenharmony_ci	struct purex_item *item);
2762306a36Sopenharmony_cistatic struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha,
2862306a36Sopenharmony_ci	uint16_t size);
2962306a36Sopenharmony_cistatic struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha,
3062306a36Sopenharmony_ci	void *pkt);
3162306a36Sopenharmony_cistatic struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha,
3262306a36Sopenharmony_ci	void **pkt, struct rsp_que **rsp);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_cistatic void
3562306a36Sopenharmony_ciqla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	void *pkt = &item->iocb;
3862306a36Sopenharmony_ci	uint16_t pkt_size = item->size;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d,
4162306a36Sopenharmony_ci	       "%s: Enter\n", __func__);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e,
4462306a36Sopenharmony_ci	       "-------- ELS REQ -------\n");
4562306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f,
4662306a36Sopenharmony_ci		       pkt, pkt_size);
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt, 0);
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciconst char *const port_state_str[] = {
5262306a36Sopenharmony_ci	[FCS_UNKNOWN]		= "Unknown",
5362306a36Sopenharmony_ci	[FCS_UNCONFIGURED]	= "UNCONFIGURED",
5462306a36Sopenharmony_ci	[FCS_DEVICE_DEAD]	= "DEAD",
5562306a36Sopenharmony_ci	[FCS_DEVICE_LOST]	= "LOST",
5662306a36Sopenharmony_ci	[FCS_ONLINE]		= "ONLINE"
5762306a36Sopenharmony_ci};
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci#define SFP_DISABLE_LASER_INITIATED    0x15  /* Sub code of 8070 AEN */
6062306a36Sopenharmony_ci#define SFP_ENABLE_LASER_INITIATED     0x16  /* Sub code of 8070 AEN */
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic inline void display_Laser_info(scsi_qla_host_t *vha,
6362306a36Sopenharmony_ci				      u16 mb1, u16 mb2, u16 mb3) {
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	if (mb1 == SFP_DISABLE_LASER_INITIATED)
6662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xf0a2,
6762306a36Sopenharmony_ci		       "SFP temperature (%d C) reached/exceeded the threshold (%d C). Laser is disabled.\n",
6862306a36Sopenharmony_ci		       mb3, mb2);
6962306a36Sopenharmony_ci	if (mb1 == SFP_ENABLE_LASER_INITIATED)
7062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xf0a3,
7162306a36Sopenharmony_ci		       "SFP temperature (%d C) reached normal operating level. Laser is enabled.\n",
7262306a36Sopenharmony_ci		       mb3);
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic void
7662306a36Sopenharmony_ciqla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct abts_entry_24xx *abts =
7962306a36Sopenharmony_ci	    (struct abts_entry_24xx *)&pkt->iocb;
8062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
8162306a36Sopenharmony_ci	struct els_entry_24xx *rsp_els;
8262306a36Sopenharmony_ci	struct abts_entry_24xx *abts_rsp;
8362306a36Sopenharmony_ci	dma_addr_t dma;
8462306a36Sopenharmony_ci	uint32_t fctl;
8562306a36Sopenharmony_ci	int rval;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x0287,
9062306a36Sopenharmony_ci	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n",
9162306a36Sopenharmony_ci	    abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id,
9262306a36Sopenharmony_ci	    abts->seq_id, abts->seq_cnt);
9362306a36Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
9462306a36Sopenharmony_ci	    "-------- ABTS RCV -------\n");
9562306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
9662306a36Sopenharmony_ci	    (uint8_t *)abts, sizeof(*abts));
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma,
9962306a36Sopenharmony_ci	    GFP_KERNEL);
10062306a36Sopenharmony_ci	if (!rsp_els) {
10162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0287,
10262306a36Sopenharmony_ci		    "Failed allocate dma buffer ABTS/ELS RSP.\n");
10362306a36Sopenharmony_ci		return;
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	/* terminate exchange */
10762306a36Sopenharmony_ci	rsp_els->entry_type = ELS_IOCB_TYPE;
10862306a36Sopenharmony_ci	rsp_els->entry_count = 1;
10962306a36Sopenharmony_ci	rsp_els->nport_handle = cpu_to_le16(~0);
11062306a36Sopenharmony_ci	rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort;
11162306a36Sopenharmony_ci	rsp_els->control_flags = cpu_to_le16(EPD_RX_XCHG);
11262306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0283,
11362306a36Sopenharmony_ci	    "Sending ELS Response to terminate exchange %#x...\n",
11462306a36Sopenharmony_ci	    abts->rx_xch_addr_to_abort);
11562306a36Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
11662306a36Sopenharmony_ci	    "-------- ELS RSP -------\n");
11762306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
11862306a36Sopenharmony_ci	    (uint8_t *)rsp_els, sizeof(*rsp_els));
11962306a36Sopenharmony_ci	rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0);
12062306a36Sopenharmony_ci	if (rval) {
12162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0288,
12262306a36Sopenharmony_ci		    "%s: iocb failed to execute -> %x\n", __func__, rval);
12362306a36Sopenharmony_ci	} else if (rsp_els->comp_status) {
12462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0289,
12562306a36Sopenharmony_ci		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
12662306a36Sopenharmony_ci		    __func__, rsp_els->comp_status,
12762306a36Sopenharmony_ci		    rsp_els->error_subcode_1, rsp_els->error_subcode_2);
12862306a36Sopenharmony_ci	} else {
12962306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x028a,
13062306a36Sopenharmony_ci		    "%s: abort exchange done.\n", __func__);
13162306a36Sopenharmony_ci	}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/* send ABTS response */
13462306a36Sopenharmony_ci	abts_rsp = (void *)rsp_els;
13562306a36Sopenharmony_ci	memset(abts_rsp, 0, sizeof(*abts_rsp));
13662306a36Sopenharmony_ci	abts_rsp->entry_type = ABTS_RSP_TYPE;
13762306a36Sopenharmony_ci	abts_rsp->entry_count = 1;
13862306a36Sopenharmony_ci	abts_rsp->nport_handle = abts->nport_handle;
13962306a36Sopenharmony_ci	abts_rsp->vp_idx = abts->vp_idx;
14062306a36Sopenharmony_ci	abts_rsp->sof_type = abts->sof_type & 0xf0;
14162306a36Sopenharmony_ci	abts_rsp->rx_xch_addr = abts->rx_xch_addr;
14262306a36Sopenharmony_ci	abts_rsp->d_id[0] = abts->s_id[0];
14362306a36Sopenharmony_ci	abts_rsp->d_id[1] = abts->s_id[1];
14462306a36Sopenharmony_ci	abts_rsp->d_id[2] = abts->s_id[2];
14562306a36Sopenharmony_ci	abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;
14662306a36Sopenharmony_ci	abts_rsp->s_id[0] = abts->d_id[0];
14762306a36Sopenharmony_ci	abts_rsp->s_id[1] = abts->d_id[1];
14862306a36Sopenharmony_ci	abts_rsp->s_id[2] = abts->d_id[2];
14962306a36Sopenharmony_ci	abts_rsp->cs_ctl = abts->cs_ctl;
15062306a36Sopenharmony_ci	/* include flipping bit23 in fctl */
15162306a36Sopenharmony_ci	fctl = ~(abts->f_ctl[2] | 0x7F) << 16 |
15262306a36Sopenharmony_ci	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;
15362306a36Sopenharmony_ci	abts_rsp->f_ctl[0] = fctl >> 0 & 0xff;
15462306a36Sopenharmony_ci	abts_rsp->f_ctl[1] = fctl >> 8 & 0xff;
15562306a36Sopenharmony_ci	abts_rsp->f_ctl[2] = fctl >> 16 & 0xff;
15662306a36Sopenharmony_ci	abts_rsp->type = FC_TYPE_BLD;
15762306a36Sopenharmony_ci	abts_rsp->rx_id = abts->rx_id;
15862306a36Sopenharmony_ci	abts_rsp->ox_id = abts->ox_id;
15962306a36Sopenharmony_ci	abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id;
16062306a36Sopenharmony_ci	abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id;
16162306a36Sopenharmony_ci	abts_rsp->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0);
16262306a36Sopenharmony_ci	abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
16362306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x028b,
16462306a36Sopenharmony_ci	    "Sending BA ACC response to ABTS %#x...\n",
16562306a36Sopenharmony_ci	    abts->rx_xch_addr_to_abort);
16662306a36Sopenharmony_ci	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
16762306a36Sopenharmony_ci	    "-------- ELS RSP -------\n");
16862306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
16962306a36Sopenharmony_ci	    (uint8_t *)abts_rsp, sizeof(*abts_rsp));
17062306a36Sopenharmony_ci	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
17162306a36Sopenharmony_ci	if (rval) {
17262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x028c,
17362306a36Sopenharmony_ci		    "%s: iocb failed to execute -> %x\n", __func__, rval);
17462306a36Sopenharmony_ci	} else if (abts_rsp->comp_status) {
17562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x028d,
17662306a36Sopenharmony_ci		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
17762306a36Sopenharmony_ci		    __func__, abts_rsp->comp_status,
17862306a36Sopenharmony_ci		    abts_rsp->payload.error.subcode1,
17962306a36Sopenharmony_ci		    abts_rsp->payload.error.subcode2);
18062306a36Sopenharmony_ci	} else {
18162306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x028ea,
18262306a36Sopenharmony_ci		    "%s: done.\n", __func__);
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma);
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci/**
18962306a36Sopenharmony_ci * __qla_consume_iocb - this routine is used to tell fw driver has processed
19062306a36Sopenharmony_ci *   or consumed the head IOCB along with the continuation IOCB's from the
19162306a36Sopenharmony_ci *   provided respond queue.
19262306a36Sopenharmony_ci * @vha: host adapter pointer
19362306a36Sopenharmony_ci * @pkt: pointer to current packet.  On return, this pointer shall move
19462306a36Sopenharmony_ci *       to the next packet.
19562306a36Sopenharmony_ci * @rsp: respond queue pointer.
19662306a36Sopenharmony_ci *
19762306a36Sopenharmony_ci * it is assumed pkt is the head iocb, not the continuation iocbk
19862306a36Sopenharmony_ci */
19962306a36Sopenharmony_civoid __qla_consume_iocb(struct scsi_qla_host *vha,
20062306a36Sopenharmony_ci	void **pkt, struct rsp_que **rsp)
20162306a36Sopenharmony_ci{
20262306a36Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
20362306a36Sopenharmony_ci	response_t *new_pkt;
20462306a36Sopenharmony_ci	uint16_t entry_count_remaining;
20562306a36Sopenharmony_ci	struct purex_entry_24xx *purex = *pkt;
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	entry_count_remaining = purex->entry_count;
20862306a36Sopenharmony_ci	while (entry_count_remaining > 0) {
20962306a36Sopenharmony_ci		new_pkt = rsp_q->ring_ptr;
21062306a36Sopenharmony_ci		*pkt = new_pkt;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci		rsp_q->ring_index++;
21362306a36Sopenharmony_ci		if (rsp_q->ring_index == rsp_q->length) {
21462306a36Sopenharmony_ci			rsp_q->ring_index = 0;
21562306a36Sopenharmony_ci			rsp_q->ring_ptr = rsp_q->ring;
21662306a36Sopenharmony_ci		} else {
21762306a36Sopenharmony_ci			rsp_q->ring_ptr++;
21862306a36Sopenharmony_ci		}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci		new_pkt->signature = RESPONSE_PROCESSED;
22162306a36Sopenharmony_ci		/* flush signature */
22262306a36Sopenharmony_ci		wmb();
22362306a36Sopenharmony_ci		--entry_count_remaining;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci/**
22862306a36Sopenharmony_ci * __qla_copy_purex_to_buffer - extract ELS payload from Purex IOCB
22962306a36Sopenharmony_ci *    and save to provided buffer
23062306a36Sopenharmony_ci * @vha: host adapter pointer
23162306a36Sopenharmony_ci * @pkt: pointer Purex IOCB
23262306a36Sopenharmony_ci * @rsp: respond queue
23362306a36Sopenharmony_ci * @buf: extracted ELS payload copy here
23462306a36Sopenharmony_ci * @buf_len: buffer length
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_ciint __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
23762306a36Sopenharmony_ci	void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
23862306a36Sopenharmony_ci{
23962306a36Sopenharmony_ci	struct purex_entry_24xx *purex = *pkt;
24062306a36Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
24162306a36Sopenharmony_ci	sts_cont_entry_t *new_pkt;
24262306a36Sopenharmony_ci	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
24362306a36Sopenharmony_ci	uint16_t buffer_copy_offset = 0;
24462306a36Sopenharmony_ci	uint16_t entry_count_remaining;
24562306a36Sopenharmony_ci	u16 tpad;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	entry_count_remaining = purex->entry_count;
24862306a36Sopenharmony_ci	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
24962306a36Sopenharmony_ci		- PURX_ELS_HEADER_SIZE;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * end of payload may not end in 4bytes boundary.  Need to
25362306a36Sopenharmony_ci	 * round up / pad for room to swap, before saving data
25462306a36Sopenharmony_ci	 */
25562306a36Sopenharmony_ci	tpad = roundup(total_bytes, 4);
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (buf_len < tpad) {
25862306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5084,
25962306a36Sopenharmony_ci		    "%s buffer is too small %d < %d\n",
26062306a36Sopenharmony_ci		    __func__, buf_len, tpad);
26162306a36Sopenharmony_ci		__qla_consume_iocb(vha, pkt, rsp);
26262306a36Sopenharmony_ci		return -EIO;
26362306a36Sopenharmony_ci	}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	pending_bytes = total_bytes = tpad;
26662306a36Sopenharmony_ci	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
26762306a36Sopenharmony_ci	    sizeof(purex->els_frame_payload) : pending_bytes;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	memcpy(buf, &purex->els_frame_payload[0], no_bytes);
27062306a36Sopenharmony_ci	buffer_copy_offset += no_bytes;
27162306a36Sopenharmony_ci	pending_bytes -= no_bytes;
27262306a36Sopenharmony_ci	--entry_count_remaining;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	((response_t *)purex)->signature = RESPONSE_PROCESSED;
27562306a36Sopenharmony_ci	/* flush signature */
27662306a36Sopenharmony_ci	wmb();
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	do {
27962306a36Sopenharmony_ci		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
28062306a36Sopenharmony_ci			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
28162306a36Sopenharmony_ci			*pkt = new_pkt;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
28462306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x507a,
28562306a36Sopenharmony_ci				    "Unexpected IOCB type, partial data 0x%x\n",
28662306a36Sopenharmony_ci				    buffer_copy_offset);
28762306a36Sopenharmony_ci				break;
28862306a36Sopenharmony_ci			}
28962306a36Sopenharmony_ci
29062306a36Sopenharmony_ci			rsp_q->ring_index++;
29162306a36Sopenharmony_ci			if (rsp_q->ring_index == rsp_q->length) {
29262306a36Sopenharmony_ci				rsp_q->ring_index = 0;
29362306a36Sopenharmony_ci				rsp_q->ring_ptr = rsp_q->ring;
29462306a36Sopenharmony_ci			} else {
29562306a36Sopenharmony_ci				rsp_q->ring_ptr++;
29662306a36Sopenharmony_ci			}
29762306a36Sopenharmony_ci			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
29862306a36Sopenharmony_ci			    sizeof(new_pkt->data) : pending_bytes;
29962306a36Sopenharmony_ci			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
30062306a36Sopenharmony_ci				memcpy((buf + buffer_copy_offset), new_pkt->data,
30162306a36Sopenharmony_ci				    no_bytes);
30262306a36Sopenharmony_ci				buffer_copy_offset += no_bytes;
30362306a36Sopenharmony_ci				pending_bytes -= no_bytes;
30462306a36Sopenharmony_ci				--entry_count_remaining;
30562306a36Sopenharmony_ci			} else {
30662306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5044,
30762306a36Sopenharmony_ci				    "Attempt to copy more that we got, optimizing..%x\n",
30862306a36Sopenharmony_ci				    buffer_copy_offset);
30962306a36Sopenharmony_ci				memcpy((buf + buffer_copy_offset), new_pkt->data,
31062306a36Sopenharmony_ci				    total_bytes - buffer_copy_offset);
31162306a36Sopenharmony_ci			}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
31462306a36Sopenharmony_ci			/* flush signature */
31562306a36Sopenharmony_ci			wmb();
31662306a36Sopenharmony_ci		}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci		if (pending_bytes != 0 || entry_count_remaining != 0) {
31962306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x508b,
32062306a36Sopenharmony_ci			    "Dropping partial Data, underrun bytes = 0x%x, entry cnts 0x%x\n",
32162306a36Sopenharmony_ci			    total_bytes, entry_count_remaining);
32262306a36Sopenharmony_ci			return -EIO;
32362306a36Sopenharmony_ci		}
32462306a36Sopenharmony_ci	} while (entry_count_remaining > 0);
32562306a36Sopenharmony_ci
32662306a36Sopenharmony_ci	be32_to_cpu_array((u32 *)buf, (__be32 *)buf, total_bytes >> 2);
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	return 0;
32962306a36Sopenharmony_ci}
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci/**
33262306a36Sopenharmony_ci * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
33362306a36Sopenharmony_ci * @irq: interrupt number
33462306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
33562306a36Sopenharmony_ci *
33662306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
33762306a36Sopenharmony_ci *
33862306a36Sopenharmony_ci * Returns handled flag.
33962306a36Sopenharmony_ci */
34062306a36Sopenharmony_ciirqreturn_t
34162306a36Sopenharmony_ciqla2100_intr_handler(int irq, void *dev_id)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
34462306a36Sopenharmony_ci	struct qla_hw_data *ha;
34562306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg;
34662306a36Sopenharmony_ci	int		status;
34762306a36Sopenharmony_ci	unsigned long	iter;
34862306a36Sopenharmony_ci	uint16_t	hccr;
34962306a36Sopenharmony_ci	uint16_t	mb[8];
35062306a36Sopenharmony_ci	struct rsp_que *rsp;
35162306a36Sopenharmony_ci	unsigned long	flags;
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
35462306a36Sopenharmony_ci	if (!rsp) {
35562306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505d,
35662306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
35762306a36Sopenharmony_ci		return (IRQ_NONE);
35862306a36Sopenharmony_ci	}
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	ha = rsp->hw;
36162306a36Sopenharmony_ci	reg = &ha->iobase->isp;
36262306a36Sopenharmony_ci	status = 0;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
36562306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
36662306a36Sopenharmony_ci	for (iter = 50; iter--; ) {
36762306a36Sopenharmony_ci		hccr = rd_reg_word(&reg->hccr);
36862306a36Sopenharmony_ci		if (qla2x00_check_reg16_for_disconnect(vha, hccr))
36962306a36Sopenharmony_ci			break;
37062306a36Sopenharmony_ci		if (hccr & HCCR_RISC_PAUSE) {
37162306a36Sopenharmony_ci			if (pci_channel_offline(ha->pdev))
37262306a36Sopenharmony_ci				break;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci			/*
37562306a36Sopenharmony_ci			 * Issue a "HARD" reset in order for the RISC interrupt
37662306a36Sopenharmony_ci			 * bit to be cleared.  Schedule a big hammer to get
37762306a36Sopenharmony_ci			 * out of the RISC PAUSED state.
37862306a36Sopenharmony_ci			 */
37962306a36Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
38062306a36Sopenharmony_ci			rd_reg_word(&reg->hccr);
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
38362306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
38462306a36Sopenharmony_ci			break;
38562306a36Sopenharmony_ci		} else if ((rd_reg_word(&reg->istatus) & ISR_RISC_INT) == 0)
38662306a36Sopenharmony_ci			break;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		if (rd_reg_word(&reg->semaphore) & BIT_0) {
38962306a36Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
39062306a36Sopenharmony_ci			rd_reg_word(&reg->hccr);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci			/* Get mailbox data. */
39362306a36Sopenharmony_ci			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
39462306a36Sopenharmony_ci			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
39562306a36Sopenharmony_ci				qla2x00_mbx_completion(vha, mb[0]);
39662306a36Sopenharmony_ci				status |= MBX_INTERRUPT;
39762306a36Sopenharmony_ci			} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
39862306a36Sopenharmony_ci				mb[1] = RD_MAILBOX_REG(ha, reg, 1);
39962306a36Sopenharmony_ci				mb[2] = RD_MAILBOX_REG(ha, reg, 2);
40062306a36Sopenharmony_ci				mb[3] = RD_MAILBOX_REG(ha, reg, 3);
40162306a36Sopenharmony_ci				qla2x00_async_event(vha, rsp, mb);
40262306a36Sopenharmony_ci			} else {
40362306a36Sopenharmony_ci				/*EMPTY*/
40462306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5025,
40562306a36Sopenharmony_ci				    "Unrecognized interrupt type (%d).\n",
40662306a36Sopenharmony_ci				    mb[0]);
40762306a36Sopenharmony_ci			}
40862306a36Sopenharmony_ci			/* Release mailbox registers. */
40962306a36Sopenharmony_ci			wrt_reg_word(&reg->semaphore, 0);
41062306a36Sopenharmony_ci			rd_reg_word(&reg->semaphore);
41162306a36Sopenharmony_ci		} else {
41262306a36Sopenharmony_ci			qla2x00_process_response_queue(rsp);
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
41562306a36Sopenharmony_ci			rd_reg_word(&reg->hccr);
41662306a36Sopenharmony_ci		}
41762306a36Sopenharmony_ci	}
41862306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
41962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	return (IRQ_HANDLED);
42262306a36Sopenharmony_ci}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_cibool
42562306a36Sopenharmony_ciqla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
42662306a36Sopenharmony_ci{
42762306a36Sopenharmony_ci	/* Check for PCI disconnection */
42862306a36Sopenharmony_ci	if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) {
42962306a36Sopenharmony_ci		if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
43062306a36Sopenharmony_ci		    !test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
43162306a36Sopenharmony_ci		    !test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
43262306a36Sopenharmony_ci			qla_schedule_eeh_work(vha);
43362306a36Sopenharmony_ci		}
43462306a36Sopenharmony_ci		return true;
43562306a36Sopenharmony_ci	} else
43662306a36Sopenharmony_ci		return false;
43762306a36Sopenharmony_ci}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_cibool
44062306a36Sopenharmony_ciqla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci/**
44662306a36Sopenharmony_ci * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
44762306a36Sopenharmony_ci * @irq: interrupt number
44862306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
44962306a36Sopenharmony_ci *
45062306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
45162306a36Sopenharmony_ci *
45262306a36Sopenharmony_ci * Returns handled flag.
45362306a36Sopenharmony_ci */
45462306a36Sopenharmony_ciirqreturn_t
45562306a36Sopenharmony_ciqla2300_intr_handler(int irq, void *dev_id)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
45862306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg;
45962306a36Sopenharmony_ci	int		status;
46062306a36Sopenharmony_ci	unsigned long	iter;
46162306a36Sopenharmony_ci	uint32_t	stat;
46262306a36Sopenharmony_ci	uint16_t	hccr;
46362306a36Sopenharmony_ci	uint16_t	mb[8];
46462306a36Sopenharmony_ci	struct rsp_que *rsp;
46562306a36Sopenharmony_ci	struct qla_hw_data *ha;
46662306a36Sopenharmony_ci	unsigned long	flags;
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
46962306a36Sopenharmony_ci	if (!rsp) {
47062306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x5058,
47162306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
47262306a36Sopenharmony_ci		return (IRQ_NONE);
47362306a36Sopenharmony_ci	}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ha = rsp->hw;
47662306a36Sopenharmony_ci	reg = &ha->iobase->isp;
47762306a36Sopenharmony_ci	status = 0;
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
48062306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
48162306a36Sopenharmony_ci	for (iter = 50; iter--; ) {
48262306a36Sopenharmony_ci		stat = rd_reg_dword(&reg->u.isp2300.host_status);
48362306a36Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
48462306a36Sopenharmony_ci			break;
48562306a36Sopenharmony_ci		if (stat & HSR_RISC_PAUSED) {
48662306a36Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
48762306a36Sopenharmony_ci				break;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci			hccr = rd_reg_word(&reg->hccr);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
49262306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5026,
49362306a36Sopenharmony_ci				    "Parity error -- HCCR=%x, Dumping "
49462306a36Sopenharmony_ci				    "firmware.\n", hccr);
49562306a36Sopenharmony_ci			else
49662306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5027,
49762306a36Sopenharmony_ci				    "RISC paused -- HCCR=%x, Dumping "
49862306a36Sopenharmony_ci				    "firmware.\n", hccr);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci			/*
50162306a36Sopenharmony_ci			 * Issue a "HARD" reset in order for the RISC
50262306a36Sopenharmony_ci			 * interrupt bit to be cleared.  Schedule a big
50362306a36Sopenharmony_ci			 * hammer to get out of the RISC PAUSED state.
50462306a36Sopenharmony_ci			 */
50562306a36Sopenharmony_ci			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
50662306a36Sopenharmony_ci			rd_reg_word(&reg->hccr);
50762306a36Sopenharmony_ci
50862306a36Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
50962306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
51062306a36Sopenharmony_ci			break;
51162306a36Sopenharmony_ci		} else if ((stat & HSR_RISC_INT) == 0)
51262306a36Sopenharmony_ci			break;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		switch (stat & 0xff) {
51562306a36Sopenharmony_ci		case 0x1:
51662306a36Sopenharmony_ci		case 0x2:
51762306a36Sopenharmony_ci		case 0x10:
51862306a36Sopenharmony_ci		case 0x11:
51962306a36Sopenharmony_ci			qla2x00_mbx_completion(vha, MSW(stat));
52062306a36Sopenharmony_ci			status |= MBX_INTERRUPT;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci			/* Release mailbox registers. */
52362306a36Sopenharmony_ci			wrt_reg_word(&reg->semaphore, 0);
52462306a36Sopenharmony_ci			break;
52562306a36Sopenharmony_ci		case 0x12:
52662306a36Sopenharmony_ci			mb[0] = MSW(stat);
52762306a36Sopenharmony_ci			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
52862306a36Sopenharmony_ci			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
52962306a36Sopenharmony_ci			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
53062306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
53162306a36Sopenharmony_ci			break;
53262306a36Sopenharmony_ci		case 0x13:
53362306a36Sopenharmony_ci			qla2x00_process_response_queue(rsp);
53462306a36Sopenharmony_ci			break;
53562306a36Sopenharmony_ci		case 0x15:
53662306a36Sopenharmony_ci			mb[0] = MBA_CMPLT_1_16BIT;
53762306a36Sopenharmony_ci			mb[1] = MSW(stat);
53862306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
53962306a36Sopenharmony_ci			break;
54062306a36Sopenharmony_ci		case 0x16:
54162306a36Sopenharmony_ci			mb[0] = MBA_SCSI_COMPLETION;
54262306a36Sopenharmony_ci			mb[1] = MSW(stat);
54362306a36Sopenharmony_ci			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
54462306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
54562306a36Sopenharmony_ci			break;
54662306a36Sopenharmony_ci		default:
54762306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5028,
54862306a36Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
54962306a36Sopenharmony_ci			break;
55062306a36Sopenharmony_ci		}
55162306a36Sopenharmony_ci		wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
55262306a36Sopenharmony_ci		rd_reg_word_relaxed(&reg->hccr);
55362306a36Sopenharmony_ci	}
55462306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
55562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	return (IRQ_HANDLED);
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci/**
56162306a36Sopenharmony_ci * qla2x00_mbx_completion() - Process mailbox command completions.
56262306a36Sopenharmony_ci * @vha: SCSI driver HA context
56362306a36Sopenharmony_ci * @mb0: Mailbox0 register
56462306a36Sopenharmony_ci */
56562306a36Sopenharmony_cistatic void
56662306a36Sopenharmony_ciqla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
56762306a36Sopenharmony_ci{
56862306a36Sopenharmony_ci	uint16_t	cnt;
56962306a36Sopenharmony_ci	uint32_t	mboxes;
57062306a36Sopenharmony_ci	__le16 __iomem *wptr;
57162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
57262306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	/* Read all mbox registers? */
57562306a36Sopenharmony_ci	WARN_ON_ONCE(ha->mbx_count > 32);
57662306a36Sopenharmony_ci	mboxes = (1ULL << ha->mbx_count) - 1;
57762306a36Sopenharmony_ci	if (!ha->mcp)
57862306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
57962306a36Sopenharmony_ci	else
58062306a36Sopenharmony_ci		mboxes = ha->mcp->in_mb;
58162306a36Sopenharmony_ci
58262306a36Sopenharmony_ci	/* Load return mailbox registers. */
58362306a36Sopenharmony_ci	ha->flags.mbox_int = 1;
58462306a36Sopenharmony_ci	ha->mailbox_out[0] = mb0;
58562306a36Sopenharmony_ci	mboxes >>= 1;
58662306a36Sopenharmony_ci	wptr = MAILBOX_REG(ha, reg, 1);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
58962306a36Sopenharmony_ci		if (IS_QLA2200(ha) && cnt == 8)
59062306a36Sopenharmony_ci			wptr = MAILBOX_REG(ha, reg, 8);
59162306a36Sopenharmony_ci		if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
59262306a36Sopenharmony_ci			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
59362306a36Sopenharmony_ci		else if (mboxes & BIT_0)
59462306a36Sopenharmony_ci			ha->mailbox_out[cnt] = rd_reg_word(wptr);
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci		wptr++;
59762306a36Sopenharmony_ci		mboxes >>= 1;
59862306a36Sopenharmony_ci	}
59962306a36Sopenharmony_ci}
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_cistatic void
60262306a36Sopenharmony_ciqla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
60362306a36Sopenharmony_ci{
60462306a36Sopenharmony_ci	static char *event[] =
60562306a36Sopenharmony_ci		{ "Complete", "Request Notification", "Time Extension" };
60662306a36Sopenharmony_ci	int rval;
60762306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
60862306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
60962306a36Sopenharmony_ci	__le16 __iomem *wptr;
61062306a36Sopenharmony_ci	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/* Seed data -- mailbox1 -> mailbox7. */
61362306a36Sopenharmony_ci	if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
61462306a36Sopenharmony_ci		wptr = &reg24->mailbox1;
61562306a36Sopenharmony_ci	else if (IS_QLA8044(vha->hw))
61662306a36Sopenharmony_ci		wptr = &reg82->mailbox_out[1];
61762306a36Sopenharmony_ci	else
61862306a36Sopenharmony_ci		return;
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
62162306a36Sopenharmony_ci		mb[cnt] = rd_reg_word(wptr);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x5021,
62462306a36Sopenharmony_ci	    "Inter-Driver Communication %s -- "
62562306a36Sopenharmony_ci	    "%04x %04x %04x %04x %04x %04x %04x.\n",
62662306a36Sopenharmony_ci	    event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
62762306a36Sopenharmony_ci	    mb[4], mb[5], mb[6]);
62862306a36Sopenharmony_ci	switch (aen) {
62962306a36Sopenharmony_ci	/* Handle IDC Error completion case. */
63062306a36Sopenharmony_ci	case MBA_IDC_COMPLETE:
63162306a36Sopenharmony_ci		if (mb[1] >> 15) {
63262306a36Sopenharmony_ci			vha->hw->flags.idc_compl_status = 1;
63362306a36Sopenharmony_ci			if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
63462306a36Sopenharmony_ci				complete(&vha->hw->dcbx_comp);
63562306a36Sopenharmony_ci		}
63662306a36Sopenharmony_ci		break;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	case MBA_IDC_NOTIFY:
63962306a36Sopenharmony_ci		/* Acknowledgement needed? [Notify && non-zero timeout]. */
64062306a36Sopenharmony_ci		timeout = (descr >> 8) & 0xf;
64162306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5022,
64262306a36Sopenharmony_ci		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
64362306a36Sopenharmony_ci		    vha->host_no, event[aen & 0xff], timeout);
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_ci		if (!timeout)
64662306a36Sopenharmony_ci			return;
64762306a36Sopenharmony_ci		rval = qla2x00_post_idc_ack_work(vha, mb);
64862306a36Sopenharmony_ci		if (rval != QLA_SUCCESS)
64962306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5023,
65062306a36Sopenharmony_ci			    "IDC failed to post ACK.\n");
65162306a36Sopenharmony_ci		break;
65262306a36Sopenharmony_ci	case MBA_IDC_TIME_EXT:
65362306a36Sopenharmony_ci		vha->hw->idc_extend_tmo = descr;
65462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5087,
65562306a36Sopenharmony_ci		    "%lu Inter-Driver Communication %s -- "
65662306a36Sopenharmony_ci		    "Extend timeout by=%d.\n",
65762306a36Sopenharmony_ci		    vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
65862306a36Sopenharmony_ci		break;
65962306a36Sopenharmony_ci	}
66062306a36Sopenharmony_ci}
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci#define LS_UNKNOWN	2
66362306a36Sopenharmony_ciconst char *
66462306a36Sopenharmony_ciqla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
66562306a36Sopenharmony_ci{
66662306a36Sopenharmony_ci	static const char *const link_speeds[] = {
66762306a36Sopenharmony_ci		"1", "2", "?", "4", "8", "16", "32", "64", "10"
66862306a36Sopenharmony_ci	};
66962306a36Sopenharmony_ci#define	QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
67062306a36Sopenharmony_ci
67162306a36Sopenharmony_ci	if (IS_QLA2100(ha) || IS_QLA2200(ha))
67262306a36Sopenharmony_ci		return link_speeds[0];
67362306a36Sopenharmony_ci	else if (speed == 0x13)
67462306a36Sopenharmony_ci		return link_speeds[QLA_LAST_SPEED];
67562306a36Sopenharmony_ci	else if (speed < QLA_LAST_SPEED)
67662306a36Sopenharmony_ci		return link_speeds[speed];
67762306a36Sopenharmony_ci	else
67862306a36Sopenharmony_ci		return link_speeds[LS_UNKNOWN];
67962306a36Sopenharmony_ci}
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_cistatic void
68262306a36Sopenharmony_ciqla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
68362306a36Sopenharmony_ci{
68462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
68562306a36Sopenharmony_ci
68662306a36Sopenharmony_ci	/*
68762306a36Sopenharmony_ci	 * 8200 AEN Interpretation:
68862306a36Sopenharmony_ci	 * mb[0] = AEN code
68962306a36Sopenharmony_ci	 * mb[1] = AEN Reason code
69062306a36Sopenharmony_ci	 * mb[2] = LSW of Peg-Halt Status-1 Register
69162306a36Sopenharmony_ci	 * mb[6] = MSW of Peg-Halt Status-1 Register
69262306a36Sopenharmony_ci	 * mb[3] = LSW of Peg-Halt Status-2 register
69362306a36Sopenharmony_ci	 * mb[7] = MSW of Peg-Halt Status-2 register
69462306a36Sopenharmony_ci	 * mb[4] = IDC Device-State Register value
69562306a36Sopenharmony_ci	 * mb[5] = IDC Driver-Presence Register value
69662306a36Sopenharmony_ci	 */
69762306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
69862306a36Sopenharmony_ci	    "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
69962306a36Sopenharmony_ci	    mb[0], mb[1], mb[2], mb[6]);
70062306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
70162306a36Sopenharmony_ci	    "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
70262306a36Sopenharmony_ci	    "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
70562306a36Sopenharmony_ci				IDC_HEARTBEAT_FAILURE)) {
70662306a36Sopenharmony_ci		ha->flags.nic_core_hung = 1;
70762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5060,
70862306a36Sopenharmony_ci		    "83XX: F/W Error Reported: Check if reset required.\n");
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci		if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
71162306a36Sopenharmony_ci			uint32_t protocol_engine_id, fw_err_code, err_level;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci			/*
71462306a36Sopenharmony_ci			 * IDC_PEG_HALT_STATUS_CHANGE interpretation:
71562306a36Sopenharmony_ci			 *  - PEG-Halt Status-1 Register:
71662306a36Sopenharmony_ci			 *	(LSW = mb[2], MSW = mb[6])
71762306a36Sopenharmony_ci			 *	Bits 0-7   = protocol-engine ID
71862306a36Sopenharmony_ci			 *	Bits 8-28  = f/w error code
71962306a36Sopenharmony_ci			 *	Bits 29-31 = Error-level
72062306a36Sopenharmony_ci			 *	    Error-level 0x1 = Non-Fatal error
72162306a36Sopenharmony_ci			 *	    Error-level 0x2 = Recoverable Fatal error
72262306a36Sopenharmony_ci			 *	    Error-level 0x4 = UnRecoverable Fatal error
72362306a36Sopenharmony_ci			 *  - PEG-Halt Status-2 Register:
72462306a36Sopenharmony_ci			 *	(LSW = mb[3], MSW = mb[7])
72562306a36Sopenharmony_ci			 */
72662306a36Sopenharmony_ci			protocol_engine_id = (mb[2] & 0xff);
72762306a36Sopenharmony_ci			fw_err_code = (((mb[2] & 0xff00) >> 8) |
72862306a36Sopenharmony_ci			    ((mb[6] & 0x1fff) << 8));
72962306a36Sopenharmony_ci			err_level = ((mb[6] & 0xe000) >> 13);
73062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
73162306a36Sopenharmony_ci			    "Register: protocol_engine_id=0x%x "
73262306a36Sopenharmony_ci			    "fw_err_code=0x%x err_level=0x%x.\n",
73362306a36Sopenharmony_ci			    protocol_engine_id, fw_err_code, err_level);
73462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
73562306a36Sopenharmony_ci			    "Register: 0x%x%x.\n", mb[7], mb[3]);
73662306a36Sopenharmony_ci			if (err_level == ERR_LEVEL_NON_FATAL) {
73762306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5063,
73862306a36Sopenharmony_ci				    "Not a fatal error, f/w has recovered itself.\n");
73962306a36Sopenharmony_ci			} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
74062306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5064,
74162306a36Sopenharmony_ci				    "Recoverable Fatal error: Chip reset "
74262306a36Sopenharmony_ci				    "required.\n");
74362306a36Sopenharmony_ci				qla83xx_schedule_work(vha,
74462306a36Sopenharmony_ci				    QLA83XX_NIC_CORE_RESET);
74562306a36Sopenharmony_ci			} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
74662306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5065,
74762306a36Sopenharmony_ci				    "Unrecoverable Fatal error: Set FAILED "
74862306a36Sopenharmony_ci				    "state, reboot required.\n");
74962306a36Sopenharmony_ci				qla83xx_schedule_work(vha,
75062306a36Sopenharmony_ci				    QLA83XX_NIC_CORE_UNRECOVERABLE);
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci
75462306a36Sopenharmony_ci		if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
75562306a36Sopenharmony_ci			uint16_t peg_fw_state, nw_interface_link_up;
75662306a36Sopenharmony_ci			uint16_t nw_interface_signal_detect, sfp_status;
75762306a36Sopenharmony_ci			uint16_t htbt_counter, htbt_monitor_enable;
75862306a36Sopenharmony_ci			uint16_t sfp_additional_info, sfp_multirate;
75962306a36Sopenharmony_ci			uint16_t sfp_tx_fault, link_speed, dcbx_status;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci			/*
76262306a36Sopenharmony_ci			 * IDC_NIC_FW_REPORTED_FAILURE interpretation:
76362306a36Sopenharmony_ci			 *  - PEG-to-FC Status Register:
76462306a36Sopenharmony_ci			 *	(LSW = mb[2], MSW = mb[6])
76562306a36Sopenharmony_ci			 *	Bits 0-7   = Peg-Firmware state
76662306a36Sopenharmony_ci			 *	Bit 8      = N/W Interface Link-up
76762306a36Sopenharmony_ci			 *	Bit 9      = N/W Interface signal detected
76862306a36Sopenharmony_ci			 *	Bits 10-11 = SFP Status
76962306a36Sopenharmony_ci			 *	  SFP Status 0x0 = SFP+ transceiver not expected
77062306a36Sopenharmony_ci			 *	  SFP Status 0x1 = SFP+ transceiver not present
77162306a36Sopenharmony_ci			 *	  SFP Status 0x2 = SFP+ transceiver invalid
77262306a36Sopenharmony_ci			 *	  SFP Status 0x3 = SFP+ transceiver present and
77362306a36Sopenharmony_ci			 *	  valid
77462306a36Sopenharmony_ci			 *	Bits 12-14 = Heartbeat Counter
77562306a36Sopenharmony_ci			 *	Bit 15     = Heartbeat Monitor Enable
77662306a36Sopenharmony_ci			 *	Bits 16-17 = SFP Additional Info
77762306a36Sopenharmony_ci			 *	  SFP info 0x0 = Unregocnized transceiver for
77862306a36Sopenharmony_ci			 *	  Ethernet
77962306a36Sopenharmony_ci			 *	  SFP info 0x1 = SFP+ brand validation failed
78062306a36Sopenharmony_ci			 *	  SFP info 0x2 = SFP+ speed validation failed
78162306a36Sopenharmony_ci			 *	  SFP info 0x3 = SFP+ access error
78262306a36Sopenharmony_ci			 *	Bit 18     = SFP Multirate
78362306a36Sopenharmony_ci			 *	Bit 19     = SFP Tx Fault
78462306a36Sopenharmony_ci			 *	Bits 20-22 = Link Speed
78562306a36Sopenharmony_ci			 *	Bits 23-27 = Reserved
78662306a36Sopenharmony_ci			 *	Bits 28-30 = DCBX Status
78762306a36Sopenharmony_ci			 *	  DCBX Status 0x0 = DCBX Disabled
78862306a36Sopenharmony_ci			 *	  DCBX Status 0x1 = DCBX Enabled
78962306a36Sopenharmony_ci			 *	  DCBX Status 0x2 = DCBX Exchange error
79062306a36Sopenharmony_ci			 *	Bit 31     = Reserved
79162306a36Sopenharmony_ci			 */
79262306a36Sopenharmony_ci			peg_fw_state = (mb[2] & 0x00ff);
79362306a36Sopenharmony_ci			nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
79462306a36Sopenharmony_ci			nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
79562306a36Sopenharmony_ci			sfp_status = ((mb[2] & 0x0c00) >> 10);
79662306a36Sopenharmony_ci			htbt_counter = ((mb[2] & 0x7000) >> 12);
79762306a36Sopenharmony_ci			htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
79862306a36Sopenharmony_ci			sfp_additional_info = (mb[6] & 0x0003);
79962306a36Sopenharmony_ci			sfp_multirate = ((mb[6] & 0x0004) >> 2);
80062306a36Sopenharmony_ci			sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
80162306a36Sopenharmony_ci			link_speed = ((mb[6] & 0x0070) >> 4);
80262306a36Sopenharmony_ci			dcbx_status = ((mb[6] & 0x7000) >> 12);
80362306a36Sopenharmony_ci
80462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5066,
80562306a36Sopenharmony_ci			    "Peg-to-Fc Status Register:\n"
80662306a36Sopenharmony_ci			    "peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
80762306a36Sopenharmony_ci			    "nw_interface_signal_detect=0x%x"
80862306a36Sopenharmony_ci			    "\nsfp_statis=0x%x.\n ", peg_fw_state,
80962306a36Sopenharmony_ci			    nw_interface_link_up, nw_interface_signal_detect,
81062306a36Sopenharmony_ci			    sfp_status);
81162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5067,
81262306a36Sopenharmony_ci			    "htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
81362306a36Sopenharmony_ci			    "sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ",
81462306a36Sopenharmony_ci			    htbt_counter, htbt_monitor_enable,
81562306a36Sopenharmony_ci			    sfp_additional_info, sfp_multirate);
81662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5068,
81762306a36Sopenharmony_ci			    "sfp_tx_fault=0x%x, link_state=0x%x, "
81862306a36Sopenharmony_ci			    "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
81962306a36Sopenharmony_ci			    dcbx_status);
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		if (mb[1] & IDC_HEARTBEAT_FAILURE) {
82562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5069,
82662306a36Sopenharmony_ci			    "Heartbeat Failure encountered, chip reset "
82762306a36Sopenharmony_ci			    "required.\n");
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci	}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_ci	if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
83462306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x506a,
83562306a36Sopenharmony_ci		    "IDC Device-State changed = 0x%x.\n", mb[4]);
83662306a36Sopenharmony_ci		if (ha->flags.nic_core_reset_owner)
83762306a36Sopenharmony_ci			return;
83862306a36Sopenharmony_ci		qla83xx_schedule_work(vha, MBA_IDC_AEN);
83962306a36Sopenharmony_ci	}
84062306a36Sopenharmony_ci}
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_ci/**
84362306a36Sopenharmony_ci * qla27xx_copy_multiple_pkt() - Copy over purex/purls packets that can
84462306a36Sopenharmony_ci * span over multiple IOCBs.
84562306a36Sopenharmony_ci * @vha: SCSI driver HA context
84662306a36Sopenharmony_ci * @pkt: ELS packet
84762306a36Sopenharmony_ci * @rsp: Response queue
84862306a36Sopenharmony_ci * @is_purls: True, for Unsolicited Received FC-NVMe LS rsp IOCB
84962306a36Sopenharmony_ci *            false, for Unsolicited Received ELS IOCB
85062306a36Sopenharmony_ci * @byte_order: True, to change the byte ordering of iocb payload
85162306a36Sopenharmony_ci */
85262306a36Sopenharmony_cistruct purex_item *
85362306a36Sopenharmony_ciqla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
85462306a36Sopenharmony_ci			  struct rsp_que **rsp, bool is_purls,
85562306a36Sopenharmony_ci			  bool byte_order)
85662306a36Sopenharmony_ci{
85762306a36Sopenharmony_ci	struct purex_entry_24xx *purex = NULL;
85862306a36Sopenharmony_ci	struct pt_ls4_rx_unsol *purls = NULL;
85962306a36Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
86062306a36Sopenharmony_ci	sts_cont_entry_t *new_pkt;
86162306a36Sopenharmony_ci	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
86262306a36Sopenharmony_ci	uint16_t buffer_copy_offset = 0, payload_size = 0;
86362306a36Sopenharmony_ci	uint16_t entry_count, entry_count_remaining;
86462306a36Sopenharmony_ci	struct purex_item *item;
86562306a36Sopenharmony_ci	void *iocb_pkt = NULL;
86662306a36Sopenharmony_ci
86762306a36Sopenharmony_ci	if (is_purls) {
86862306a36Sopenharmony_ci		purls = *pkt;
86962306a36Sopenharmony_ci		total_bytes = (le16_to_cpu(purls->frame_size) & 0x0FFF) -
87062306a36Sopenharmony_ci			      PURX_ELS_HEADER_SIZE;
87162306a36Sopenharmony_ci		entry_count = entry_count_remaining = purls->entry_count;
87262306a36Sopenharmony_ci		payload_size = sizeof(purls->payload);
87362306a36Sopenharmony_ci	} else {
87462306a36Sopenharmony_ci		purex = *pkt;
87562306a36Sopenharmony_ci		total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
87662306a36Sopenharmony_ci			      PURX_ELS_HEADER_SIZE;
87762306a36Sopenharmony_ci		entry_count = entry_count_remaining = purex->entry_count;
87862306a36Sopenharmony_ci		payload_size = sizeof(purex->els_frame_payload);
87962306a36Sopenharmony_ci	}
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	pending_bytes = total_bytes;
88262306a36Sopenharmony_ci	no_bytes = (pending_bytes > payload_size) ? payload_size :
88362306a36Sopenharmony_ci		   pending_bytes;
88462306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x509a,
88562306a36Sopenharmony_ci	       "%s LS, frame_size 0x%x, entry count %d\n",
88662306a36Sopenharmony_ci	       (is_purls ? "PURLS" : "FPIN"), total_bytes, entry_count);
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_ci	item = qla24xx_alloc_purex_item(vha, total_bytes);
88962306a36Sopenharmony_ci	if (!item)
89062306a36Sopenharmony_ci		return item;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	iocb_pkt = &item->iocb;
89362306a36Sopenharmony_ci
89462306a36Sopenharmony_ci	if (is_purls)
89562306a36Sopenharmony_ci		memcpy(iocb_pkt, &purls->payload[0], no_bytes);
89662306a36Sopenharmony_ci	else
89762306a36Sopenharmony_ci		memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
89862306a36Sopenharmony_ci	buffer_copy_offset += no_bytes;
89962306a36Sopenharmony_ci	pending_bytes -= no_bytes;
90062306a36Sopenharmony_ci	--entry_count_remaining;
90162306a36Sopenharmony_ci
90262306a36Sopenharmony_ci	if (is_purls)
90362306a36Sopenharmony_ci		((response_t *)purls)->signature = RESPONSE_PROCESSED;
90462306a36Sopenharmony_ci	else
90562306a36Sopenharmony_ci		((response_t *)purex)->signature = RESPONSE_PROCESSED;
90662306a36Sopenharmony_ci	wmb();
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	do {
90962306a36Sopenharmony_ci		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
91062306a36Sopenharmony_ci			if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
91162306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5084,
91262306a36Sopenharmony_ci				       "Ran out of IOCBs, partial data 0x%x\n",
91362306a36Sopenharmony_ci				       buffer_copy_offset);
91462306a36Sopenharmony_ci				cpu_relax();
91562306a36Sopenharmony_ci				continue;
91662306a36Sopenharmony_ci			}
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
91962306a36Sopenharmony_ci			*pkt = new_pkt;
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_ci			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
92262306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x507a,
92362306a36Sopenharmony_ci				       "Unexpected IOCB type, partial data 0x%x\n",
92462306a36Sopenharmony_ci				       buffer_copy_offset);
92562306a36Sopenharmony_ci				break;
92662306a36Sopenharmony_ci			}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci			rsp_q->ring_index++;
92962306a36Sopenharmony_ci			if (rsp_q->ring_index == rsp_q->length) {
93062306a36Sopenharmony_ci				rsp_q->ring_index = 0;
93162306a36Sopenharmony_ci				rsp_q->ring_ptr = rsp_q->ring;
93262306a36Sopenharmony_ci			} else {
93362306a36Sopenharmony_ci				rsp_q->ring_ptr++;
93462306a36Sopenharmony_ci			}
93562306a36Sopenharmony_ci			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
93662306a36Sopenharmony_ci				sizeof(new_pkt->data) : pending_bytes;
93762306a36Sopenharmony_ci			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
93862306a36Sopenharmony_ci				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
93962306a36Sopenharmony_ci				       new_pkt->data, no_bytes);
94062306a36Sopenharmony_ci				buffer_copy_offset += no_bytes;
94162306a36Sopenharmony_ci				pending_bytes -= no_bytes;
94262306a36Sopenharmony_ci				--entry_count_remaining;
94362306a36Sopenharmony_ci			} else {
94462306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5044,
94562306a36Sopenharmony_ci				       "Attempt to copy more that we got, optimizing..%x\n",
94662306a36Sopenharmony_ci				       buffer_copy_offset);
94762306a36Sopenharmony_ci				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
94862306a36Sopenharmony_ci				       new_pkt->data,
94962306a36Sopenharmony_ci				       total_bytes - buffer_copy_offset);
95062306a36Sopenharmony_ci			}
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
95362306a36Sopenharmony_ci			wmb();
95462306a36Sopenharmony_ci		}
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci		if (pending_bytes != 0 || entry_count_remaining != 0) {
95762306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x508b,
95862306a36Sopenharmony_ci			       "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
95962306a36Sopenharmony_ci			       total_bytes, entry_count_remaining);
96062306a36Sopenharmony_ci			qla24xx_free_purex_item(item);
96162306a36Sopenharmony_ci			return NULL;
96262306a36Sopenharmony_ci		}
96362306a36Sopenharmony_ci	} while (entry_count_remaining > 0);
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	if (byte_order)
96662306a36Sopenharmony_ci		host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	return item;
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_ciint
97262306a36Sopenharmony_ciqla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
97562306a36Sopenharmony_ci	scsi_qla_host_t *vp;
97662306a36Sopenharmony_ci	uint32_t vp_did;
97762306a36Sopenharmony_ci	unsigned long flags;
97862306a36Sopenharmony_ci	int ret = 0;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (!ha->num_vhosts)
98162306a36Sopenharmony_ci		return ret;
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->vport_slock, flags);
98462306a36Sopenharmony_ci	list_for_each_entry(vp, &ha->vp_list, list) {
98562306a36Sopenharmony_ci		vp_did = vp->d_id.b24;
98662306a36Sopenharmony_ci		if (vp_did == rscn_entry) {
98762306a36Sopenharmony_ci			ret = 1;
98862306a36Sopenharmony_ci			break;
98962306a36Sopenharmony_ci		}
99062306a36Sopenharmony_ci	}
99162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->vport_slock, flags);
99262306a36Sopenharmony_ci
99362306a36Sopenharmony_ci	return ret;
99462306a36Sopenharmony_ci}
99562306a36Sopenharmony_ci
99662306a36Sopenharmony_cifc_port_t *
99762306a36Sopenharmony_ciqla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id)
99862306a36Sopenharmony_ci{
99962306a36Sopenharmony_ci	fc_port_t *f, *tf;
100062306a36Sopenharmony_ci
100162306a36Sopenharmony_ci	f = tf = NULL;
100262306a36Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list)
100362306a36Sopenharmony_ci		if (f->loop_id == loop_id)
100462306a36Sopenharmony_ci			return f;
100562306a36Sopenharmony_ci	return NULL;
100662306a36Sopenharmony_ci}
100762306a36Sopenharmony_ci
100862306a36Sopenharmony_cifc_port_t *
100962306a36Sopenharmony_ciqla2x00_find_fcport_by_wwpn(scsi_qla_host_t *vha, u8 *wwpn, u8 incl_deleted)
101062306a36Sopenharmony_ci{
101162306a36Sopenharmony_ci	fc_port_t *f, *tf;
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_ci	f = tf = NULL;
101462306a36Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
101562306a36Sopenharmony_ci		if (memcmp(f->port_name, wwpn, WWN_SIZE) == 0) {
101662306a36Sopenharmony_ci			if (incl_deleted)
101762306a36Sopenharmony_ci				return f;
101862306a36Sopenharmony_ci			else if (f->deleted == 0)
101962306a36Sopenharmony_ci				return f;
102062306a36Sopenharmony_ci		}
102162306a36Sopenharmony_ci	}
102262306a36Sopenharmony_ci	return NULL;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_cifc_port_t *
102662306a36Sopenharmony_ciqla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id,
102762306a36Sopenharmony_ci	u8 incl_deleted)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	fc_port_t *f, *tf;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	f = tf = NULL;
103262306a36Sopenharmony_ci	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
103362306a36Sopenharmony_ci		if (f->d_id.b24 == id->b24) {
103462306a36Sopenharmony_ci			if (incl_deleted)
103562306a36Sopenharmony_ci				return f;
103662306a36Sopenharmony_ci			else if (f->deleted == 0)
103762306a36Sopenharmony_ci				return f;
103862306a36Sopenharmony_ci		}
103962306a36Sopenharmony_ci	}
104062306a36Sopenharmony_ci	return NULL;
104162306a36Sopenharmony_ci}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci/* Shall be called only on supported adapters. */
104462306a36Sopenharmony_cistatic void
104562306a36Sopenharmony_ciqla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
104662306a36Sopenharmony_ci{
104762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
104862306a36Sopenharmony_ci	bool reset_isp_needed = false;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x02f0,
105162306a36Sopenharmony_ci	       "MPI Heartbeat stop. MPI reset is%s needed. "
105262306a36Sopenharmony_ci	       "MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n",
105362306a36Sopenharmony_ci	       mb[1] & BIT_8 ? "" : " not",
105462306a36Sopenharmony_ci	       mb[0], mb[1], mb[2], mb[3]);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	if ((mb[1] & BIT_8) == 0)
105762306a36Sopenharmony_ci		return;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x02f1,
106062306a36Sopenharmony_ci	       "MPI Heartbeat stop. FW dump needed\n");
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci	if (ql2xfulldump_on_mpifail) {
106362306a36Sopenharmony_ci		ha->isp_ops->fw_dump(vha);
106462306a36Sopenharmony_ci		reset_isp_needed = true;
106562306a36Sopenharmony_ci	}
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	ha->isp_ops->mpi_fw_dump(vha, 1);
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ci	if (reset_isp_needed) {
107062306a36Sopenharmony_ci		vha->hw->flags.fw_init_done = 0;
107162306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
107262306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
107362306a36Sopenharmony_ci	}
107462306a36Sopenharmony_ci}
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_cistatic struct purex_item *
107762306a36Sopenharmony_ciqla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
107862306a36Sopenharmony_ci{
107962306a36Sopenharmony_ci	struct purex_item *item = NULL;
108062306a36Sopenharmony_ci	uint8_t item_hdr_size = sizeof(*item);
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
108362306a36Sopenharmony_ci		item = kzalloc(item_hdr_size +
108462306a36Sopenharmony_ci		    (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
108562306a36Sopenharmony_ci	} else {
108662306a36Sopenharmony_ci		if (atomic_inc_return(&vha->default_item.in_use) == 1) {
108762306a36Sopenharmony_ci			item = &vha->default_item;
108862306a36Sopenharmony_ci			goto initialize_purex_header;
108962306a36Sopenharmony_ci		} else {
109062306a36Sopenharmony_ci			item = kzalloc(item_hdr_size, GFP_ATOMIC);
109162306a36Sopenharmony_ci		}
109262306a36Sopenharmony_ci	}
109362306a36Sopenharmony_ci	if (!item) {
109462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5092,
109562306a36Sopenharmony_ci		       ">> Failed allocate purex list item.\n");
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci		return NULL;
109862306a36Sopenharmony_ci	}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_ciinitialize_purex_header:
110162306a36Sopenharmony_ci	item->vha = vha;
110262306a36Sopenharmony_ci	item->size = size;
110362306a36Sopenharmony_ci	return item;
110462306a36Sopenharmony_ci}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_civoid
110762306a36Sopenharmony_ciqla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
110862306a36Sopenharmony_ci			 void (*process_item)(struct scsi_qla_host *vha,
110962306a36Sopenharmony_ci					      struct purex_item *pkt))
111062306a36Sopenharmony_ci{
111162306a36Sopenharmony_ci	struct purex_list *list = &vha->purex_list;
111262306a36Sopenharmony_ci	ulong flags;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci	pkt->process_item = process_item;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	spin_lock_irqsave(&list->lock, flags);
111762306a36Sopenharmony_ci	list_add_tail(&pkt->list, &list->head);
111862306a36Sopenharmony_ci	spin_unlock_irqrestore(&list->lock, flags);
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
112162306a36Sopenharmony_ci}
112262306a36Sopenharmony_ci
112362306a36Sopenharmony_ci/**
112462306a36Sopenharmony_ci * qla24xx_copy_std_pkt() - Copy over purex ELS which is
112562306a36Sopenharmony_ci * contained in a single IOCB.
112662306a36Sopenharmony_ci * purex packet.
112762306a36Sopenharmony_ci * @vha: SCSI driver HA context
112862306a36Sopenharmony_ci * @pkt: ELS packet
112962306a36Sopenharmony_ci */
113062306a36Sopenharmony_cistatic struct purex_item
113162306a36Sopenharmony_ci*qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
113262306a36Sopenharmony_ci{
113362306a36Sopenharmony_ci	struct purex_item *item;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	item = qla24xx_alloc_purex_item(vha,
113662306a36Sopenharmony_ci					QLA_DEFAULT_PAYLOAD_SIZE);
113762306a36Sopenharmony_ci	if (!item)
113862306a36Sopenharmony_ci		return item;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	memcpy(&item->iocb, pkt, sizeof(item->iocb));
114162306a36Sopenharmony_ci	return item;
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci/**
114562306a36Sopenharmony_ci * qla27xx_copy_fpin_pkt() - Copy over fpin packets that can
114662306a36Sopenharmony_ci * span over multiple IOCBs.
114762306a36Sopenharmony_ci * @vha: SCSI driver HA context
114862306a36Sopenharmony_ci * @pkt: ELS packet
114962306a36Sopenharmony_ci * @rsp: Response queue
115062306a36Sopenharmony_ci */
115162306a36Sopenharmony_cistatic struct purex_item *
115262306a36Sopenharmony_ciqla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
115362306a36Sopenharmony_ci		      struct rsp_que **rsp)
115462306a36Sopenharmony_ci{
115562306a36Sopenharmony_ci	struct purex_entry_24xx *purex = *pkt;
115662306a36Sopenharmony_ci	struct rsp_que *rsp_q = *rsp;
115762306a36Sopenharmony_ci	sts_cont_entry_t *new_pkt;
115862306a36Sopenharmony_ci	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
115962306a36Sopenharmony_ci	uint16_t buffer_copy_offset = 0;
116062306a36Sopenharmony_ci	uint16_t entry_count, entry_count_remaining;
116162306a36Sopenharmony_ci	struct purex_item *item;
116262306a36Sopenharmony_ci	void *fpin_pkt = NULL;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
116562306a36Sopenharmony_ci	    - PURX_ELS_HEADER_SIZE;
116662306a36Sopenharmony_ci	pending_bytes = total_bytes;
116762306a36Sopenharmony_ci	entry_count = entry_count_remaining = purex->entry_count;
116862306a36Sopenharmony_ci	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
116962306a36Sopenharmony_ci		   sizeof(purex->els_frame_payload) : pending_bytes;
117062306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x509a,
117162306a36Sopenharmony_ci	       "FPIN ELS, frame_size 0x%x, entry count %d\n",
117262306a36Sopenharmony_ci	       total_bytes, entry_count);
117362306a36Sopenharmony_ci
117462306a36Sopenharmony_ci	item = qla24xx_alloc_purex_item(vha, total_bytes);
117562306a36Sopenharmony_ci	if (!item)
117662306a36Sopenharmony_ci		return item;
117762306a36Sopenharmony_ci
117862306a36Sopenharmony_ci	fpin_pkt = &item->iocb;
117962306a36Sopenharmony_ci
118062306a36Sopenharmony_ci	memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
118162306a36Sopenharmony_ci	buffer_copy_offset += no_bytes;
118262306a36Sopenharmony_ci	pending_bytes -= no_bytes;
118362306a36Sopenharmony_ci	--entry_count_remaining;
118462306a36Sopenharmony_ci
118562306a36Sopenharmony_ci	((response_t *)purex)->signature = RESPONSE_PROCESSED;
118662306a36Sopenharmony_ci	wmb();
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	do {
118962306a36Sopenharmony_ci		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
119062306a36Sopenharmony_ci			if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
119162306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5084,
119262306a36Sopenharmony_ci				       "Ran out of IOCBs, partial data 0x%x\n",
119362306a36Sopenharmony_ci				       buffer_copy_offset);
119462306a36Sopenharmony_ci				cpu_relax();
119562306a36Sopenharmony_ci				continue;
119662306a36Sopenharmony_ci			}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
119962306a36Sopenharmony_ci			*pkt = new_pkt;
120062306a36Sopenharmony_ci
120162306a36Sopenharmony_ci			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
120262306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x507a,
120362306a36Sopenharmony_ci				       "Unexpected IOCB type, partial data 0x%x\n",
120462306a36Sopenharmony_ci				       buffer_copy_offset);
120562306a36Sopenharmony_ci				break;
120662306a36Sopenharmony_ci			}
120762306a36Sopenharmony_ci
120862306a36Sopenharmony_ci			rsp_q->ring_index++;
120962306a36Sopenharmony_ci			if (rsp_q->ring_index == rsp_q->length) {
121062306a36Sopenharmony_ci				rsp_q->ring_index = 0;
121162306a36Sopenharmony_ci				rsp_q->ring_ptr = rsp_q->ring;
121262306a36Sopenharmony_ci			} else {
121362306a36Sopenharmony_ci				rsp_q->ring_ptr++;
121462306a36Sopenharmony_ci			}
121562306a36Sopenharmony_ci			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
121662306a36Sopenharmony_ci			    sizeof(new_pkt->data) : pending_bytes;
121762306a36Sopenharmony_ci			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
121862306a36Sopenharmony_ci				memcpy(((uint8_t *)fpin_pkt +
121962306a36Sopenharmony_ci				    buffer_copy_offset), new_pkt->data,
122062306a36Sopenharmony_ci				    no_bytes);
122162306a36Sopenharmony_ci				buffer_copy_offset += no_bytes;
122262306a36Sopenharmony_ci				pending_bytes -= no_bytes;
122362306a36Sopenharmony_ci				--entry_count_remaining;
122462306a36Sopenharmony_ci			} else {
122562306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x5044,
122662306a36Sopenharmony_ci				       "Attempt to copy more that we got, optimizing..%x\n",
122762306a36Sopenharmony_ci				       buffer_copy_offset);
122862306a36Sopenharmony_ci				memcpy(((uint8_t *)fpin_pkt +
122962306a36Sopenharmony_ci				    buffer_copy_offset), new_pkt->data,
123062306a36Sopenharmony_ci				    total_bytes - buffer_copy_offset);
123162306a36Sopenharmony_ci			}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
123462306a36Sopenharmony_ci			wmb();
123562306a36Sopenharmony_ci		}
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci		if (pending_bytes != 0 || entry_count_remaining != 0) {
123862306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x508b,
123962306a36Sopenharmony_ci			       "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
124062306a36Sopenharmony_ci			       total_bytes, entry_count_remaining);
124162306a36Sopenharmony_ci			qla24xx_free_purex_item(item);
124262306a36Sopenharmony_ci			return NULL;
124362306a36Sopenharmony_ci		}
124462306a36Sopenharmony_ci	} while (entry_count_remaining > 0);
124562306a36Sopenharmony_ci	host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
124662306a36Sopenharmony_ci	return item;
124762306a36Sopenharmony_ci}
124862306a36Sopenharmony_ci
124962306a36Sopenharmony_ci/**
125062306a36Sopenharmony_ci * qla2x00_async_event() - Process aynchronous events.
125162306a36Sopenharmony_ci * @vha: SCSI driver HA context
125262306a36Sopenharmony_ci * @rsp: response queue
125362306a36Sopenharmony_ci * @mb: Mailbox registers (0 - 3)
125462306a36Sopenharmony_ci */
125562306a36Sopenharmony_civoid
125662306a36Sopenharmony_ciqla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
125762306a36Sopenharmony_ci{
125862306a36Sopenharmony_ci	uint16_t	handle_cnt;
125962306a36Sopenharmony_ci	uint16_t	cnt, mbx;
126062306a36Sopenharmony_ci	uint32_t	handles[5];
126162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
126262306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
126362306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
126462306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
126562306a36Sopenharmony_ci	uint32_t	rscn_entry, host_pid;
126662306a36Sopenharmony_ci	unsigned long	flags;
126762306a36Sopenharmony_ci	fc_port_t	*fcport = NULL;
126862306a36Sopenharmony_ci
126962306a36Sopenharmony_ci	if (!vha->hw->flags.fw_started) {
127062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x50ff,
127162306a36Sopenharmony_ci		    "Dropping AEN - %04x %04x %04x %04x.\n",
127262306a36Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
127362306a36Sopenharmony_ci		return;
127462306a36Sopenharmony_ci	}
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	/* Setup to process RIO completion. */
127762306a36Sopenharmony_ci	handle_cnt = 0;
127862306a36Sopenharmony_ci	if (IS_CNA_CAPABLE(ha))
127962306a36Sopenharmony_ci		goto skip_rio;
128062306a36Sopenharmony_ci	switch (mb[0]) {
128162306a36Sopenharmony_ci	case MBA_SCSI_COMPLETION:
128262306a36Sopenharmony_ci		handles[0] = make_handle(mb[2], mb[1]);
128362306a36Sopenharmony_ci		handle_cnt = 1;
128462306a36Sopenharmony_ci		break;
128562306a36Sopenharmony_ci	case MBA_CMPLT_1_16BIT:
128662306a36Sopenharmony_ci		handles[0] = mb[1];
128762306a36Sopenharmony_ci		handle_cnt = 1;
128862306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
128962306a36Sopenharmony_ci		break;
129062306a36Sopenharmony_ci	case MBA_CMPLT_2_16BIT:
129162306a36Sopenharmony_ci		handles[0] = mb[1];
129262306a36Sopenharmony_ci		handles[1] = mb[2];
129362306a36Sopenharmony_ci		handle_cnt = 2;
129462306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
129562306a36Sopenharmony_ci		break;
129662306a36Sopenharmony_ci	case MBA_CMPLT_3_16BIT:
129762306a36Sopenharmony_ci		handles[0] = mb[1];
129862306a36Sopenharmony_ci		handles[1] = mb[2];
129962306a36Sopenharmony_ci		handles[2] = mb[3];
130062306a36Sopenharmony_ci		handle_cnt = 3;
130162306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
130262306a36Sopenharmony_ci		break;
130362306a36Sopenharmony_ci	case MBA_CMPLT_4_16BIT:
130462306a36Sopenharmony_ci		handles[0] = mb[1];
130562306a36Sopenharmony_ci		handles[1] = mb[2];
130662306a36Sopenharmony_ci		handles[2] = mb[3];
130762306a36Sopenharmony_ci		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
130862306a36Sopenharmony_ci		handle_cnt = 4;
130962306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
131062306a36Sopenharmony_ci		break;
131162306a36Sopenharmony_ci	case MBA_CMPLT_5_16BIT:
131262306a36Sopenharmony_ci		handles[0] = mb[1];
131362306a36Sopenharmony_ci		handles[1] = mb[2];
131462306a36Sopenharmony_ci		handles[2] = mb[3];
131562306a36Sopenharmony_ci		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
131662306a36Sopenharmony_ci		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
131762306a36Sopenharmony_ci		handle_cnt = 5;
131862306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
131962306a36Sopenharmony_ci		break;
132062306a36Sopenharmony_ci	case MBA_CMPLT_2_32BIT:
132162306a36Sopenharmony_ci		handles[0] = make_handle(mb[2], mb[1]);
132262306a36Sopenharmony_ci		handles[1] = make_handle(RD_MAILBOX_REG(ha, reg, 7),
132362306a36Sopenharmony_ci					 RD_MAILBOX_REG(ha, reg, 6));
132462306a36Sopenharmony_ci		handle_cnt = 2;
132562306a36Sopenharmony_ci		mb[0] = MBA_SCSI_COMPLETION;
132662306a36Sopenharmony_ci		break;
132762306a36Sopenharmony_ci	default:
132862306a36Sopenharmony_ci		break;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ciskip_rio:
133162306a36Sopenharmony_ci	switch (mb[0]) {
133262306a36Sopenharmony_ci	case MBA_SCSI_COMPLETION:	/* Fast Post */
133362306a36Sopenharmony_ci		if (!vha->flags.online)
133462306a36Sopenharmony_ci			break;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
133762306a36Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
133862306a36Sopenharmony_ci				handles[cnt]);
133962306a36Sopenharmony_ci		break;
134062306a36Sopenharmony_ci
134162306a36Sopenharmony_ci	case MBA_RESET:			/* Reset */
134262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5002,
134362306a36Sopenharmony_ci		    "Asynchronous RESET.\n");
134462306a36Sopenharmony_ci
134562306a36Sopenharmony_ci		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
134662306a36Sopenharmony_ci		break;
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	case MBA_SYSTEM_ERR:		/* System Error */
134962306a36Sopenharmony_ci		mbx = 0;
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ci		vha->hw_err_cnt++;
135262306a36Sopenharmony_ci
135362306a36Sopenharmony_ci		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
135462306a36Sopenharmony_ci		    IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
135562306a36Sopenharmony_ci			u16 m[4];
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci			m[0] = rd_reg_word(&reg24->mailbox4);
135862306a36Sopenharmony_ci			m[1] = rd_reg_word(&reg24->mailbox5);
135962306a36Sopenharmony_ci			m[2] = rd_reg_word(&reg24->mailbox6);
136062306a36Sopenharmony_ci			mbx = m[3] = rd_reg_word(&reg24->mailbox7);
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5003,
136362306a36Sopenharmony_ci			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n",
136462306a36Sopenharmony_ci			    mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]);
136562306a36Sopenharmony_ci		} else
136662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x5003,
136762306a36Sopenharmony_ci			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ",
136862306a36Sopenharmony_ci			    mb[1], mb[2], mb[3]);
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci		if ((IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
137162306a36Sopenharmony_ci		    rd_reg_word(&reg24->mailbox7) & BIT_8)
137262306a36Sopenharmony_ci			ha->isp_ops->mpi_fw_dump(vha, 1);
137362306a36Sopenharmony_ci		ha->isp_ops->fw_dump(vha);
137462306a36Sopenharmony_ci		ha->flags.fw_init_done = 0;
137562306a36Sopenharmony_ci		QLA_FW_STOPPED(ha);
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha)) {
137862306a36Sopenharmony_ci			if (mb[1] == 0 && mb[2] == 0) {
137962306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0x5004,
138062306a36Sopenharmony_ci				    "Unrecoverable Hardware Error: adapter "
138162306a36Sopenharmony_ci				    "marked OFFLINE!\n");
138262306a36Sopenharmony_ci				vha->flags.online = 0;
138362306a36Sopenharmony_ci				vha->device_flags |= DFLG_DEV_FAILED;
138462306a36Sopenharmony_ci			} else {
138562306a36Sopenharmony_ci				/* Check to see if MPI timeout occurred */
138662306a36Sopenharmony_ci				if ((mbx & MBX_3) && (ha->port_no == 0))
138762306a36Sopenharmony_ci					set_bit(MPI_RESET_NEEDED,
138862306a36Sopenharmony_ci					    &vha->dpc_flags);
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
139162306a36Sopenharmony_ci			}
139262306a36Sopenharmony_ci		} else if (mb[1] == 0) {
139362306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x5005,
139462306a36Sopenharmony_ci			    "Unrecoverable Hardware Error: adapter marked "
139562306a36Sopenharmony_ci			    "OFFLINE!\n");
139662306a36Sopenharmony_ci			vha->flags.online = 0;
139762306a36Sopenharmony_ci			vha->device_flags |= DFLG_DEV_FAILED;
139862306a36Sopenharmony_ci		} else
139962306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
140062306a36Sopenharmony_ci		break;
140162306a36Sopenharmony_ci
140262306a36Sopenharmony_ci	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
140362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5006,
140462306a36Sopenharmony_ci		    "ISP Request Transfer Error (%x).\n",  mb[1]);
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci		vha->hw_err_cnt++;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
140962306a36Sopenharmony_ci		break;
141062306a36Sopenharmony_ci
141162306a36Sopenharmony_ci	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
141262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5007,
141362306a36Sopenharmony_ci		    "ISP Response Transfer Error (%x).\n", mb[1]);
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		vha->hw_err_cnt++;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
141862306a36Sopenharmony_ci		break;
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ci	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
142162306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5008,
142262306a36Sopenharmony_ci		    "Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
142362306a36Sopenharmony_ci		break;
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	case MBA_LOOP_INIT_ERR:
142662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5090,
142762306a36Sopenharmony_ci		    "LOOP INIT ERROR (%x).\n", mb[1]);
142862306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
142962306a36Sopenharmony_ci		break;
143062306a36Sopenharmony_ci
143162306a36Sopenharmony_ci	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
143262306a36Sopenharmony_ci		ha->flags.lip_ae = 1;
143362306a36Sopenharmony_ci
143462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5009,
143562306a36Sopenharmony_ci		    "LIP occurred (%x).\n", mb[1]);
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
143862306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
143962306a36Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
144062306a36Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
144162306a36Sopenharmony_ci		}
144262306a36Sopenharmony_ci
144362306a36Sopenharmony_ci		if (vha->vp_idx) {
144462306a36Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
144562306a36Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
144662306a36Sopenharmony_ci		}
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
144962306a36Sopenharmony_ci		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
145262306a36Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
145362306a36Sopenharmony_ci		break;
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	case MBA_LOOP_UP:		/* Loop Up Event */
145662306a36Sopenharmony_ci		if (IS_QLA2100(ha) || IS_QLA2200(ha))
145762306a36Sopenharmony_ci			ha->link_data_rate = PORT_SPEED_1GB;
145862306a36Sopenharmony_ci		else
145962306a36Sopenharmony_ci			ha->link_data_rate = mb[1];
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x500a,
146262306a36Sopenharmony_ci		    "LOOP UP detected (%s Gbps).\n",
146362306a36Sopenharmony_ci		    qla2x00_get_link_speed_str(ha, ha->link_data_rate));
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
146662306a36Sopenharmony_ci			if (mb[2] & BIT_0)
146762306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x11a0,
146862306a36Sopenharmony_ci				    "FEC=enabled (link up).\n");
146962306a36Sopenharmony_ci		}
147062306a36Sopenharmony_ci
147162306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
147262306a36Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
147362306a36Sopenharmony_ci
147462306a36Sopenharmony_ci		if (vha->link_down_time < vha->hw->port_down_retry_count) {
147562306a36Sopenharmony_ci			vha->short_link_down_cnt++;
147662306a36Sopenharmony_ci			vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
147762306a36Sopenharmony_ci		}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci		break;
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci	case MBA_LOOP_DOWN:		/* Loop Down Event */
148262306a36Sopenharmony_ci		SAVE_TOPO(ha);
148362306a36Sopenharmony_ci		ha->flags.lip_ae = 0;
148462306a36Sopenharmony_ci		ha->current_topology = 0;
148562306a36Sopenharmony_ci		vha->link_down_time = 0;
148662306a36Sopenharmony_ci
148762306a36Sopenharmony_ci		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
148862306a36Sopenharmony_ci			? rd_reg_word(&reg24->mailbox4) : 0;
148962306a36Sopenharmony_ci		mbx = (IS_P3P_TYPE(ha)) ? rd_reg_word(&reg82->mailbox_out[4])
149062306a36Sopenharmony_ci			: mbx;
149162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x500b,
149262306a36Sopenharmony_ci		    "LOOP DOWN detected (%x %x %x %x).\n",
149362306a36Sopenharmony_ci		    mb[1], mb[2], mb[3], mbx);
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
149662306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
149762306a36Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
149862306a36Sopenharmony_ci			/*
149962306a36Sopenharmony_ci			 * In case of loop down, restore WWPN from
150062306a36Sopenharmony_ci			 * NVRAM in case of FA-WWPN capable ISP
150162306a36Sopenharmony_ci			 * Restore for Physical Port only
150262306a36Sopenharmony_ci			 */
150362306a36Sopenharmony_ci			if (!vha->vp_idx) {
150462306a36Sopenharmony_ci				if (ha->flags.fawwpn_enabled &&
150562306a36Sopenharmony_ci				    (ha->current_topology == ISP_CFG_F)) {
150662306a36Sopenharmony_ci					memcpy(vha->port_name, ha->port_name, WWN_SIZE);
150762306a36Sopenharmony_ci					fc_host_port_name(vha->host) =
150862306a36Sopenharmony_ci					    wwn_to_u64(vha->port_name);
150962306a36Sopenharmony_ci					ql_dbg(ql_dbg_init + ql_dbg_verbose,
151062306a36Sopenharmony_ci					    vha, 0x00d8, "LOOP DOWN detected,"
151162306a36Sopenharmony_ci					    "restore WWPN %016llx\n",
151262306a36Sopenharmony_ci					    wwn_to_u64(vha->port_name));
151362306a36Sopenharmony_ci				}
151462306a36Sopenharmony_ci
151562306a36Sopenharmony_ci				clear_bit(VP_CONFIG_OK, &vha->vp_flags);
151662306a36Sopenharmony_ci			}
151762306a36Sopenharmony_ci
151862306a36Sopenharmony_ci			vha->device_flags |= DFLG_NO_CABLE;
151962306a36Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
152062306a36Sopenharmony_ci		}
152162306a36Sopenharmony_ci
152262306a36Sopenharmony_ci		if (vha->vp_idx) {
152362306a36Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
152462306a36Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
152562306a36Sopenharmony_ci		}
152662306a36Sopenharmony_ci
152762306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
152862306a36Sopenharmony_ci		ha->link_data_rate = PORT_SPEED_UNKNOWN;
152962306a36Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
153062306a36Sopenharmony_ci		break;
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_ci	case MBA_LIP_RESET:		/* LIP reset occurred */
153362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x500c,
153462306a36Sopenharmony_ci		    "LIP reset occurred (%x).\n", mb[1]);
153562306a36Sopenharmony_ci
153662306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
153762306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
153862306a36Sopenharmony_ci			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
153962306a36Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
154062306a36Sopenharmony_ci		}
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci		if (vha->vp_idx) {
154362306a36Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
154462306a36Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
154562306a36Sopenharmony_ci		}
154662306a36Sopenharmony_ci
154762306a36Sopenharmony_ci		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci		ha->operating_mode = LOOP;
155062306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
155162306a36Sopenharmony_ci		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
155262306a36Sopenharmony_ci		break;
155362306a36Sopenharmony_ci
155462306a36Sopenharmony_ci	/* case MBA_DCBX_COMPLETE: */
155562306a36Sopenharmony_ci	case MBA_POINT_TO_POINT:	/* Point-to-Point */
155662306a36Sopenharmony_ci		ha->flags.lip_ae = 0;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci		if (IS_QLA2100(ha))
155962306a36Sopenharmony_ci			break;
156062306a36Sopenharmony_ci
156162306a36Sopenharmony_ci		if (IS_CNA_CAPABLE(ha)) {
156262306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x500d,
156362306a36Sopenharmony_ci			    "DCBX Completed -- %04x %04x %04x.\n",
156462306a36Sopenharmony_ci			    mb[1], mb[2], mb[3]);
156562306a36Sopenharmony_ci			if (ha->notify_dcbx_comp && !vha->vp_idx)
156662306a36Sopenharmony_ci				complete(&ha->dcbx_comp);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci		} else
156962306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x500e,
157062306a36Sopenharmony_ci			    "Asynchronous P2P MODE received.\n");
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		/*
157362306a36Sopenharmony_ci		 * Until there's a transition from loop down to loop up, treat
157462306a36Sopenharmony_ci		 * this as loop down only.
157562306a36Sopenharmony_ci		 */
157662306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
157762306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
157862306a36Sopenharmony_ci			if (!atomic_read(&vha->loop_down_timer))
157962306a36Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
158062306a36Sopenharmony_ci				    LOOP_DOWN_TIME);
158162306a36Sopenharmony_ci			if (!N2N_TOPO(ha))
158262306a36Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
158362306a36Sopenharmony_ci		}
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci		if (vha->vp_idx) {
158662306a36Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
158762306a36Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
158862306a36Sopenharmony_ci		}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
159162306a36Sopenharmony_ci			set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
159462306a36Sopenharmony_ci		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
159762306a36Sopenharmony_ci		break;
159862306a36Sopenharmony_ci
159962306a36Sopenharmony_ci	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
160062306a36Sopenharmony_ci		if (IS_QLA2100(ha))
160162306a36Sopenharmony_ci			break;
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x500f,
160462306a36Sopenharmony_ci		    "Configuration change detected: value=%x.\n", mb[1]);
160562306a36Sopenharmony_ci
160662306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
160762306a36Sopenharmony_ci			atomic_set(&vha->loop_state, LOOP_DOWN);
160862306a36Sopenharmony_ci			if (!atomic_read(&vha->loop_down_timer))
160962306a36Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
161062306a36Sopenharmony_ci				    LOOP_DOWN_TIME);
161162306a36Sopenharmony_ci			qla2x00_mark_all_devices_lost(vha);
161262306a36Sopenharmony_ci		}
161362306a36Sopenharmony_ci
161462306a36Sopenharmony_ci		if (vha->vp_idx) {
161562306a36Sopenharmony_ci			atomic_set(&vha->vp_state, VP_FAILED);
161662306a36Sopenharmony_ci			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
161762306a36Sopenharmony_ci		}
161862306a36Sopenharmony_ci
161962306a36Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
162062306a36Sopenharmony_ci		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
162162306a36Sopenharmony_ci		break;
162262306a36Sopenharmony_ci
162362306a36Sopenharmony_ci	case MBA_PORT_UPDATE:		/* Port database update */
162462306a36Sopenharmony_ci		/*
162562306a36Sopenharmony_ci		 * Handle only global and vn-port update events
162662306a36Sopenharmony_ci		 *
162762306a36Sopenharmony_ci		 * Relevant inputs:
162862306a36Sopenharmony_ci		 * mb[1] = N_Port handle of changed port
162962306a36Sopenharmony_ci		 * OR 0xffff for global event
163062306a36Sopenharmony_ci		 * mb[2] = New login state
163162306a36Sopenharmony_ci		 * 7 = Port logged out
163262306a36Sopenharmony_ci		 * mb[3] = LSB is vp_idx, 0xff = all vps
163362306a36Sopenharmony_ci		 *
163462306a36Sopenharmony_ci		 * Skip processing if:
163562306a36Sopenharmony_ci		 *       Event is global, vp_idx is NOT all vps,
163662306a36Sopenharmony_ci		 *           vp_idx does not match
163762306a36Sopenharmony_ci		 *       Event is not global, vp_idx does not match
163862306a36Sopenharmony_ci		 */
163962306a36Sopenharmony_ci		if (IS_QLA2XXX_MIDTYPE(ha) &&
164062306a36Sopenharmony_ci		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
164162306a36Sopenharmony_ci			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
164262306a36Sopenharmony_ci			break;
164362306a36Sopenharmony_ci
164462306a36Sopenharmony_ci		if (mb[2] == 0x7) {
164562306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5010,
164662306a36Sopenharmony_ci			    "Port %s %04x %04x %04x.\n",
164762306a36Sopenharmony_ci			    mb[1] == 0xffff ? "unavailable" : "logout",
164862306a36Sopenharmony_ci			    mb[1], mb[2], mb[3]);
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci			if (mb[1] == 0xffff)
165162306a36Sopenharmony_ci				goto global_port_update;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci			if (mb[1] == NPH_SNS_LID(ha)) {
165462306a36Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
165562306a36Sopenharmony_ci				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
165662306a36Sopenharmony_ci				break;
165762306a36Sopenharmony_ci			}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci			/* use handle_cnt for loop id/nport handle */
166062306a36Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha))
166162306a36Sopenharmony_ci				handle_cnt = NPH_SNS;
166262306a36Sopenharmony_ci			else
166362306a36Sopenharmony_ci				handle_cnt = SIMPLE_NAME_SERVER;
166462306a36Sopenharmony_ci			if (mb[1] == handle_cnt) {
166562306a36Sopenharmony_ci				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
166662306a36Sopenharmony_ci				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
166762306a36Sopenharmony_ci				break;
166862306a36Sopenharmony_ci			}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci			/* Port logout */
167162306a36Sopenharmony_ci			fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
167262306a36Sopenharmony_ci			if (!fcport)
167362306a36Sopenharmony_ci				break;
167462306a36Sopenharmony_ci			if (atomic_read(&fcport->state) != FCS_ONLINE)
167562306a36Sopenharmony_ci				break;
167662306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x508a,
167762306a36Sopenharmony_ci			    "Marking port lost loopid=%04x portid=%06x.\n",
167862306a36Sopenharmony_ci			    fcport->loop_id, fcport->d_id.b24);
167962306a36Sopenharmony_ci			if (qla_ini_mode_enabled(vha)) {
168062306a36Sopenharmony_ci				fcport->logout_on_delete = 0;
168162306a36Sopenharmony_ci				qlt_schedule_sess_for_deletion(fcport);
168262306a36Sopenharmony_ci			}
168362306a36Sopenharmony_ci			break;
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ciglobal_port_update:
168662306a36Sopenharmony_ci			if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
168762306a36Sopenharmony_ci				atomic_set(&vha->loop_state, LOOP_DOWN);
168862306a36Sopenharmony_ci				atomic_set(&vha->loop_down_timer,
168962306a36Sopenharmony_ci				    LOOP_DOWN_TIME);
169062306a36Sopenharmony_ci				vha->device_flags |= DFLG_NO_CABLE;
169162306a36Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
169262306a36Sopenharmony_ci			}
169362306a36Sopenharmony_ci
169462306a36Sopenharmony_ci			if (vha->vp_idx) {
169562306a36Sopenharmony_ci				atomic_set(&vha->vp_state, VP_FAILED);
169662306a36Sopenharmony_ci				fc_vport_set_state(vha->fc_vport,
169762306a36Sopenharmony_ci				    FC_VPORT_FAILED);
169862306a36Sopenharmony_ci				qla2x00_mark_all_devices_lost(vha);
169962306a36Sopenharmony_ci			}
170062306a36Sopenharmony_ci
170162306a36Sopenharmony_ci			vha->flags.management_server_logged_in = 0;
170262306a36Sopenharmony_ci			ha->link_data_rate = PORT_SPEED_UNKNOWN;
170362306a36Sopenharmony_ci			break;
170462306a36Sopenharmony_ci		}
170562306a36Sopenharmony_ci
170662306a36Sopenharmony_ci		/*
170762306a36Sopenharmony_ci		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
170862306a36Sopenharmony_ci		 * event etc. earlier indicating loop is down) then process
170962306a36Sopenharmony_ci		 * it.  Otherwise ignore it and Wait for RSCN to come in.
171062306a36Sopenharmony_ci		 */
171162306a36Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
171262306a36Sopenharmony_ci		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
171362306a36Sopenharmony_ci			!ha->flags.n2n_ae  &&
171462306a36Sopenharmony_ci		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
171562306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5011,
171662306a36Sopenharmony_ci			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
171762306a36Sopenharmony_ci			    mb[1], mb[2], mb[3]);
171862306a36Sopenharmony_ci			break;
171962306a36Sopenharmony_ci		}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5012,
172262306a36Sopenharmony_ci		    "Port database changed %04x %04x %04x.\n",
172362306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
172462306a36Sopenharmony_ci
172562306a36Sopenharmony_ci		/*
172662306a36Sopenharmony_ci		 * Mark all devices as missing so we will login again.
172762306a36Sopenharmony_ci		 */
172862306a36Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_UP);
172962306a36Sopenharmony_ci		vha->scan.scan_retry = 0;
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
173262306a36Sopenharmony_ci		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
173362306a36Sopenharmony_ci		set_bit(VP_CONFIG_OK, &vha->vp_flags);
173462306a36Sopenharmony_ci		break;
173562306a36Sopenharmony_ci
173662306a36Sopenharmony_ci	case MBA_RSCN_UPDATE:		/* State Change Registration */
173762306a36Sopenharmony_ci		/* Check if the Vport has issued a SCR */
173862306a36Sopenharmony_ci		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
173962306a36Sopenharmony_ci			break;
174062306a36Sopenharmony_ci		/* Only handle SCNs for our Vport index. */
174162306a36Sopenharmony_ci		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
174262306a36Sopenharmony_ci			break;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5013,
174562306a36Sopenharmony_ci		       "RSCN database changed -- %04x %04x %04x.\n",
174662306a36Sopenharmony_ci		       mb[1], mb[2], mb[3]);
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
174962306a36Sopenharmony_ci		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
175062306a36Sopenharmony_ci				| vha->d_id.b.al_pa;
175162306a36Sopenharmony_ci		if (rscn_entry == host_pid) {
175262306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5014,
175362306a36Sopenharmony_ci			    "Ignoring RSCN update to local host "
175462306a36Sopenharmony_ci			    "port ID (%06x).\n", host_pid);
175562306a36Sopenharmony_ci			break;
175662306a36Sopenharmony_ci		}
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci		/* Ignore reserved bits from RSCN-payload. */
175962306a36Sopenharmony_ci		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
176062306a36Sopenharmony_ci
176162306a36Sopenharmony_ci		/* Skip RSCNs for virtual ports on the same physical port */
176262306a36Sopenharmony_ci		if (qla2x00_is_a_vp_did(vha, rscn_entry))
176362306a36Sopenharmony_ci			break;
176462306a36Sopenharmony_ci
176562306a36Sopenharmony_ci		atomic_set(&vha->loop_down_timer, 0);
176662306a36Sopenharmony_ci		vha->flags.management_server_logged_in = 0;
176762306a36Sopenharmony_ci		{
176862306a36Sopenharmony_ci			struct event_arg ea;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci			memset(&ea, 0, sizeof(ea));
177162306a36Sopenharmony_ci			ea.id.b24 = rscn_entry;
177262306a36Sopenharmony_ci			ea.id.b.rsvd_1 = rscn_entry >> 24;
177362306a36Sopenharmony_ci			qla2x00_handle_rscn(vha, &ea);
177462306a36Sopenharmony_ci			qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
177562306a36Sopenharmony_ci		}
177662306a36Sopenharmony_ci		break;
177762306a36Sopenharmony_ci	case MBA_CONGN_NOTI_RECV:
177862306a36Sopenharmony_ci		if (!ha->flags.scm_enabled ||
177962306a36Sopenharmony_ci		    mb[1] != QLA_CON_PRIMITIVE_RECEIVED)
178062306a36Sopenharmony_ci			break;
178162306a36Sopenharmony_ci
178262306a36Sopenharmony_ci		if (mb[2] == QLA_CONGESTION_ARB_WARNING) {
178362306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x509b,
178462306a36Sopenharmony_ci			       "Congestion Warning %04x %04x.\n", mb[1], mb[2]);
178562306a36Sopenharmony_ci		} else if (mb[2] == QLA_CONGESTION_ARB_ALARM) {
178662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x509b,
178762306a36Sopenharmony_ci			       "Congestion Alarm %04x %04x.\n", mb[1], mb[2]);
178862306a36Sopenharmony_ci		}
178962306a36Sopenharmony_ci		break;
179062306a36Sopenharmony_ci	/* case MBA_RIO_RESPONSE: */
179162306a36Sopenharmony_ci	case MBA_ZIO_RESPONSE:
179262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5015,
179362306a36Sopenharmony_ci		    "[R|Z]IO update completion.\n");
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha))
179662306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
179762306a36Sopenharmony_ci		else
179862306a36Sopenharmony_ci			qla2x00_process_response_queue(rsp);
179962306a36Sopenharmony_ci		break;
180062306a36Sopenharmony_ci
180162306a36Sopenharmony_ci	case MBA_DISCARD_RND_FRAME:
180262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5016,
180362306a36Sopenharmony_ci		    "Discard RND Frame -- %04x %04x %04x.\n",
180462306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
180562306a36Sopenharmony_ci		vha->interface_err_cnt++;
180662306a36Sopenharmony_ci		break;
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_ci	case MBA_TRACE_NOTIFICATION:
180962306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5017,
181062306a36Sopenharmony_ci		    "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
181162306a36Sopenharmony_ci		break;
181262306a36Sopenharmony_ci
181362306a36Sopenharmony_ci	case MBA_ISP84XX_ALERT:
181462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5018,
181562306a36Sopenharmony_ci		    "ISP84XX Alert Notification -- %04x %04x %04x.\n",
181662306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
181962306a36Sopenharmony_ci		switch (mb[1]) {
182062306a36Sopenharmony_ci		case A84_PANIC_RECOVERY:
182162306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x5019,
182262306a36Sopenharmony_ci			    "Alert 84XX: panic recovery %04x %04x.\n",
182362306a36Sopenharmony_ci			    mb[2], mb[3]);
182462306a36Sopenharmony_ci			break;
182562306a36Sopenharmony_ci		case A84_OP_LOGIN_COMPLETE:
182662306a36Sopenharmony_ci			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
182762306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501a,
182862306a36Sopenharmony_ci			    "Alert 84XX: firmware version %x.\n",
182962306a36Sopenharmony_ci			    ha->cs84xx->op_fw_version);
183062306a36Sopenharmony_ci			break;
183162306a36Sopenharmony_ci		case A84_DIAG_LOGIN_COMPLETE:
183262306a36Sopenharmony_ci			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
183362306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501b,
183462306a36Sopenharmony_ci			    "Alert 84XX: diagnostic firmware version %x.\n",
183562306a36Sopenharmony_ci			    ha->cs84xx->diag_fw_version);
183662306a36Sopenharmony_ci			break;
183762306a36Sopenharmony_ci		case A84_GOLD_LOGIN_COMPLETE:
183862306a36Sopenharmony_ci			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
183962306a36Sopenharmony_ci			ha->cs84xx->fw_update = 1;
184062306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x501c,
184162306a36Sopenharmony_ci			    "Alert 84XX: gold firmware version %x.\n",
184262306a36Sopenharmony_ci			    ha->cs84xx->gold_fw_version);
184362306a36Sopenharmony_ci			break;
184462306a36Sopenharmony_ci		default:
184562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x501d,
184662306a36Sopenharmony_ci			    "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
184762306a36Sopenharmony_ci			    mb[1], mb[2], mb[3]);
184862306a36Sopenharmony_ci		}
184962306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
185062306a36Sopenharmony_ci		break;
185162306a36Sopenharmony_ci	case MBA_DCBX_START:
185262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x501e,
185362306a36Sopenharmony_ci		    "DCBX Started -- %04x %04x %04x.\n",
185462306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
185562306a36Sopenharmony_ci		break;
185662306a36Sopenharmony_ci	case MBA_DCBX_PARAM_UPDATE:
185762306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x501f,
185862306a36Sopenharmony_ci		    "DCBX Parameters Updated -- %04x %04x %04x.\n",
185962306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
186062306a36Sopenharmony_ci		break;
186162306a36Sopenharmony_ci	case MBA_FCF_CONF_ERR:
186262306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5020,
186362306a36Sopenharmony_ci		    "FCF Configuration Error -- %04x %04x %04x.\n",
186462306a36Sopenharmony_ci		    mb[1], mb[2], mb[3]);
186562306a36Sopenharmony_ci		break;
186662306a36Sopenharmony_ci	case MBA_IDC_NOTIFY:
186762306a36Sopenharmony_ci		if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
186862306a36Sopenharmony_ci			mb[4] = rd_reg_word(&reg24->mailbox4);
186962306a36Sopenharmony_ci			if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
187062306a36Sopenharmony_ci			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
187162306a36Sopenharmony_ci			    (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
187262306a36Sopenharmony_ci				set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
187362306a36Sopenharmony_ci				/*
187462306a36Sopenharmony_ci				 * Extend loop down timer since port is active.
187562306a36Sopenharmony_ci				 */
187662306a36Sopenharmony_ci				if (atomic_read(&vha->loop_state) == LOOP_DOWN)
187762306a36Sopenharmony_ci					atomic_set(&vha->loop_down_timer,
187862306a36Sopenharmony_ci					    LOOP_DOWN_TIME);
187962306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
188062306a36Sopenharmony_ci			}
188162306a36Sopenharmony_ci		}
188262306a36Sopenharmony_ci		fallthrough;
188362306a36Sopenharmony_ci	case MBA_IDC_COMPLETE:
188462306a36Sopenharmony_ci		if (ha->notify_lb_portup_comp && !vha->vp_idx)
188562306a36Sopenharmony_ci			complete(&ha->lb_portup_comp);
188662306a36Sopenharmony_ci		fallthrough;
188762306a36Sopenharmony_ci	case MBA_IDC_TIME_EXT:
188862306a36Sopenharmony_ci		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
188962306a36Sopenharmony_ci		    IS_QLA8044(ha))
189062306a36Sopenharmony_ci			qla81xx_idc_event(vha, mb[0], mb[1]);
189162306a36Sopenharmony_ci		break;
189262306a36Sopenharmony_ci
189362306a36Sopenharmony_ci	case MBA_IDC_AEN:
189462306a36Sopenharmony_ci		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
189562306a36Sopenharmony_ci			vha->hw_err_cnt++;
189662306a36Sopenharmony_ci			qla27xx_handle_8200_aen(vha, mb);
189762306a36Sopenharmony_ci		} else if (IS_QLA83XX(ha)) {
189862306a36Sopenharmony_ci			mb[4] = rd_reg_word(&reg24->mailbox4);
189962306a36Sopenharmony_ci			mb[5] = rd_reg_word(&reg24->mailbox5);
190062306a36Sopenharmony_ci			mb[6] = rd_reg_word(&reg24->mailbox6);
190162306a36Sopenharmony_ci			mb[7] = rd_reg_word(&reg24->mailbox7);
190262306a36Sopenharmony_ci			qla83xx_handle_8200_aen(vha, mb);
190362306a36Sopenharmony_ci		} else {
190462306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5052,
190562306a36Sopenharmony_ci			    "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n",
190662306a36Sopenharmony_ci			    mb[0], mb[1], mb[2], mb[3]);
190762306a36Sopenharmony_ci		}
190862306a36Sopenharmony_ci		break;
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci	case MBA_DPORT_DIAGNOSTICS:
191162306a36Sopenharmony_ci		if ((mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_NOERR ||
191262306a36Sopenharmony_ci		    (mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_ERR)
191362306a36Sopenharmony_ci			vha->dport_status &= ~DPORT_DIAG_IN_PROGRESS;
191462306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5052,
191562306a36Sopenharmony_ci		    "D-Port Diagnostics: %04x %04x %04x %04x\n",
191662306a36Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
191762306a36Sopenharmony_ci		memcpy(vha->dport_data, mb, sizeof(vha->dport_data));
191862306a36Sopenharmony_ci		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
191962306a36Sopenharmony_ci			static char *results[] = {
192062306a36Sopenharmony_ci			    "start", "done(pass)", "done(error)", "undefined" };
192162306a36Sopenharmony_ci			static char *types[] = {
192262306a36Sopenharmony_ci			    "none", "dynamic", "static", "other" };
192362306a36Sopenharmony_ci			uint result = mb[1] >> 0 & 0x3;
192462306a36Sopenharmony_ci			uint type = mb[1] >> 6 & 0x3;
192562306a36Sopenharmony_ci			uint sw = mb[1] >> 15 & 0x1;
192662306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5052,
192762306a36Sopenharmony_ci			    "D-Port Diagnostics: result=%s type=%s [sw=%u]\n",
192862306a36Sopenharmony_ci			    results[result], types[type], sw);
192962306a36Sopenharmony_ci			if (result == 2) {
193062306a36Sopenharmony_ci				static char *reasons[] = {
193162306a36Sopenharmony_ci				    "reserved", "unexpected reject",
193262306a36Sopenharmony_ci				    "unexpected phase", "retry exceeded",
193362306a36Sopenharmony_ci				    "timed out", "not supported",
193462306a36Sopenharmony_ci				    "user stopped" };
193562306a36Sopenharmony_ci				uint reason = mb[2] >> 0 & 0xf;
193662306a36Sopenharmony_ci				uint phase = mb[2] >> 12 & 0xf;
193762306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5052,
193862306a36Sopenharmony_ci				    "D-Port Diagnostics: reason=%s phase=%u \n",
193962306a36Sopenharmony_ci				    reason < 7 ? reasons[reason] : "other",
194062306a36Sopenharmony_ci				    phase >> 1);
194162306a36Sopenharmony_ci			}
194262306a36Sopenharmony_ci		}
194362306a36Sopenharmony_ci		break;
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	case MBA_TEMPERATURE_ALERT:
194662306a36Sopenharmony_ci		if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
194762306a36Sopenharmony_ci			display_Laser_info(vha, mb[1], mb[2], mb[3]);
194862306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x505e,
194962306a36Sopenharmony_ci		    "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
195062306a36Sopenharmony_ci		break;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	case MBA_TRANS_INSERT:
195362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5091,
195462306a36Sopenharmony_ci		    "Transceiver Insertion: %04x\n", mb[1]);
195562306a36Sopenharmony_ci		set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
195662306a36Sopenharmony_ci		break;
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	case MBA_TRANS_REMOVE:
195962306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n");
196062306a36Sopenharmony_ci		break;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	default:
196362306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5057,
196462306a36Sopenharmony_ci		    "Unknown AEN:%04x %04x %04x %04x\n",
196562306a36Sopenharmony_ci		    mb[0], mb[1], mb[2], mb[3]);
196662306a36Sopenharmony_ci	}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_ci	qlt_async_event(mb[0], vha, mb);
196962306a36Sopenharmony_ci
197062306a36Sopenharmony_ci	if (!vha->vp_idx && ha->num_vhosts)
197162306a36Sopenharmony_ci		qla2x00_alert_all_vps(rsp, mb);
197262306a36Sopenharmony_ci}
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci/**
197562306a36Sopenharmony_ci * qla2x00_process_completed_request() - Process a Fast Post response.
197662306a36Sopenharmony_ci * @vha: SCSI driver HA context
197762306a36Sopenharmony_ci * @req: request queue
197862306a36Sopenharmony_ci * @index: SRB index
197962306a36Sopenharmony_ci */
198062306a36Sopenharmony_civoid
198162306a36Sopenharmony_ciqla2x00_process_completed_request(struct scsi_qla_host *vha,
198262306a36Sopenharmony_ci				  struct req_que *req, uint32_t index)
198362306a36Sopenharmony_ci{
198462306a36Sopenharmony_ci	srb_t *sp;
198562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
198662306a36Sopenharmony_ci
198762306a36Sopenharmony_ci	/* Validate handle. */
198862306a36Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
198962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3014,
199062306a36Sopenharmony_ci		    "Invalid SCSI command index (%x).\n", index);
199162306a36Sopenharmony_ci
199262306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
199362306a36Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
199462306a36Sopenharmony_ci		else
199562306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
199662306a36Sopenharmony_ci		return;
199762306a36Sopenharmony_ci	}
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci	sp = req->outstanding_cmds[index];
200062306a36Sopenharmony_ci	if (sp) {
200162306a36Sopenharmony_ci		/* Free outstanding command slot. */
200262306a36Sopenharmony_ci		req->outstanding_cmds[index] = NULL;
200362306a36Sopenharmony_ci
200462306a36Sopenharmony_ci		/* Save ISP completion status */
200562306a36Sopenharmony_ci		sp->done(sp, DID_OK << 16);
200662306a36Sopenharmony_ci	} else {
200762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
200862306a36Sopenharmony_ci
200962306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
201062306a36Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
201162306a36Sopenharmony_ci		else
201262306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
201362306a36Sopenharmony_ci	}
201462306a36Sopenharmony_ci}
201562306a36Sopenharmony_ci
201662306a36Sopenharmony_cistatic srb_t *
201762306a36Sopenharmony_ciqla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
201862306a36Sopenharmony_ci		       struct req_que *req, void *iocb, u16 *ret_index)
201962306a36Sopenharmony_ci{
202062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
202162306a36Sopenharmony_ci	sts_entry_t *pkt = iocb;
202262306a36Sopenharmony_ci	srb_t *sp;
202362306a36Sopenharmony_ci	uint16_t index;
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci	if (pkt->handle == QLA_SKIP_HANDLE)
202662306a36Sopenharmony_ci		return NULL;
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci	index = LSW(pkt->handle);
202962306a36Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
203062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5031,
203162306a36Sopenharmony_ci			   "%s: Invalid command index (%x) type %8ph.\n",
203262306a36Sopenharmony_ci			   func, index, iocb);
203362306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
203462306a36Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
203562306a36Sopenharmony_ci		else
203662306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
203762306a36Sopenharmony_ci		return NULL;
203862306a36Sopenharmony_ci	}
203962306a36Sopenharmony_ci	sp = req->outstanding_cmds[index];
204062306a36Sopenharmony_ci	if (!sp) {
204162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5032,
204262306a36Sopenharmony_ci			"%s: Invalid completion handle (%x) -- timed-out.\n",
204362306a36Sopenharmony_ci			func, index);
204462306a36Sopenharmony_ci		return NULL;
204562306a36Sopenharmony_ci	}
204662306a36Sopenharmony_ci	if (sp->handle != index) {
204762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x5033,
204862306a36Sopenharmony_ci			"%s: SRB handle (%x) mismatch %x.\n", func,
204962306a36Sopenharmony_ci			sp->handle, index);
205062306a36Sopenharmony_ci		return NULL;
205162306a36Sopenharmony_ci	}
205262306a36Sopenharmony_ci
205362306a36Sopenharmony_ci	*ret_index = index;
205462306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
205562306a36Sopenharmony_ci	return sp;
205662306a36Sopenharmony_ci}
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_cisrb_t *
205962306a36Sopenharmony_ciqla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
206062306a36Sopenharmony_ci			   struct req_que *req, void *iocb)
206162306a36Sopenharmony_ci{
206262306a36Sopenharmony_ci	uint16_t index;
206362306a36Sopenharmony_ci	srb_t *sp;
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ci	sp = qla_get_sp_from_handle(vha, func, req, iocb, &index);
206662306a36Sopenharmony_ci	if (sp)
206762306a36Sopenharmony_ci		req->outstanding_cmds[index] = NULL;
206862306a36Sopenharmony_ci
206962306a36Sopenharmony_ci	return sp;
207062306a36Sopenharmony_ci}
207162306a36Sopenharmony_ci
207262306a36Sopenharmony_cistatic void
207362306a36Sopenharmony_ciqla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
207462306a36Sopenharmony_ci    struct mbx_entry *mbx)
207562306a36Sopenharmony_ci{
207662306a36Sopenharmony_ci	const char func[] = "MBX-IOCB";
207762306a36Sopenharmony_ci	const char *type;
207862306a36Sopenharmony_ci	fc_port_t *fcport;
207962306a36Sopenharmony_ci	srb_t *sp;
208062306a36Sopenharmony_ci	struct srb_iocb *lio;
208162306a36Sopenharmony_ci	uint16_t *data;
208262306a36Sopenharmony_ci	uint16_t status;
208362306a36Sopenharmony_ci
208462306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
208562306a36Sopenharmony_ci	if (!sp)
208662306a36Sopenharmony_ci		return;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	lio = &sp->u.iocb_cmd;
208962306a36Sopenharmony_ci	type = sp->name;
209062306a36Sopenharmony_ci	fcport = sp->fcport;
209162306a36Sopenharmony_ci	data = lio->u.logio.data;
209262306a36Sopenharmony_ci
209362306a36Sopenharmony_ci	data[0] = MBS_COMMAND_ERROR;
209462306a36Sopenharmony_ci	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
209562306a36Sopenharmony_ci	    QLA_LOGIO_LOGIN_RETRIED : 0;
209662306a36Sopenharmony_ci	if (mbx->entry_status) {
209762306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5043,
209862306a36Sopenharmony_ci		    "Async-%s error entry - hdl=%x portid=%02x%02x%02x "
209962306a36Sopenharmony_ci		    "entry-status=%x status=%x state-flag=%x "
210062306a36Sopenharmony_ci		    "status-flags=%x.\n", type, sp->handle,
210162306a36Sopenharmony_ci		    fcport->d_id.b.domain, fcport->d_id.b.area,
210262306a36Sopenharmony_ci		    fcport->d_id.b.al_pa, mbx->entry_status,
210362306a36Sopenharmony_ci		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
210462306a36Sopenharmony_ci		    le16_to_cpu(mbx->status_flags));
210562306a36Sopenharmony_ci
210662306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
210762306a36Sopenharmony_ci		    mbx, sizeof(*mbx));
210862306a36Sopenharmony_ci
210962306a36Sopenharmony_ci		goto logio_done;
211062306a36Sopenharmony_ci	}
211162306a36Sopenharmony_ci
211262306a36Sopenharmony_ci	status = le16_to_cpu(mbx->status);
211362306a36Sopenharmony_ci	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
211462306a36Sopenharmony_ci	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
211562306a36Sopenharmony_ci		status = 0;
211662306a36Sopenharmony_ci	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
211762306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5045,
211862306a36Sopenharmony_ci		    "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n",
211962306a36Sopenharmony_ci		    type, sp->handle, fcport->d_id.b.domain,
212062306a36Sopenharmony_ci		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
212162306a36Sopenharmony_ci		    le16_to_cpu(mbx->mb1));
212262306a36Sopenharmony_ci
212362306a36Sopenharmony_ci		data[0] = MBS_COMMAND_COMPLETE;
212462306a36Sopenharmony_ci		if (sp->type == SRB_LOGIN_CMD) {
212562306a36Sopenharmony_ci			fcport->port_type = FCT_TARGET;
212662306a36Sopenharmony_ci			if (le16_to_cpu(mbx->mb1) & BIT_0)
212762306a36Sopenharmony_ci				fcport->port_type = FCT_INITIATOR;
212862306a36Sopenharmony_ci			else if (le16_to_cpu(mbx->mb1) & BIT_1)
212962306a36Sopenharmony_ci				fcport->flags |= FCF_FCP2_DEVICE;
213062306a36Sopenharmony_ci		}
213162306a36Sopenharmony_ci		goto logio_done;
213262306a36Sopenharmony_ci	}
213362306a36Sopenharmony_ci
213462306a36Sopenharmony_ci	data[0] = le16_to_cpu(mbx->mb0);
213562306a36Sopenharmony_ci	switch (data[0]) {
213662306a36Sopenharmony_ci	case MBS_PORT_ID_USED:
213762306a36Sopenharmony_ci		data[1] = le16_to_cpu(mbx->mb1);
213862306a36Sopenharmony_ci		break;
213962306a36Sopenharmony_ci	case MBS_LOOP_ID_USED:
214062306a36Sopenharmony_ci		break;
214162306a36Sopenharmony_ci	default:
214262306a36Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
214362306a36Sopenharmony_ci		break;
214462306a36Sopenharmony_ci	}
214562306a36Sopenharmony_ci
214662306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x5046,
214762306a36Sopenharmony_ci	    "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x "
214862306a36Sopenharmony_ci	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle,
214962306a36Sopenharmony_ci	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
215062306a36Sopenharmony_ci	    status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
215162306a36Sopenharmony_ci	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
215262306a36Sopenharmony_ci	    le16_to_cpu(mbx->mb7));
215362306a36Sopenharmony_ci
215462306a36Sopenharmony_cilogio_done:
215562306a36Sopenharmony_ci	sp->done(sp, 0);
215662306a36Sopenharmony_ci}
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_cistatic void
215962306a36Sopenharmony_ciqla24xx_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
216062306a36Sopenharmony_ci    struct mbx_24xx_entry *pkt)
216162306a36Sopenharmony_ci{
216262306a36Sopenharmony_ci	const char func[] = "MBX-IOCB2";
216362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
216462306a36Sopenharmony_ci	srb_t *sp;
216562306a36Sopenharmony_ci	struct srb_iocb *si;
216662306a36Sopenharmony_ci	u16 sz, i;
216762306a36Sopenharmony_ci	int res;
216862306a36Sopenharmony_ci
216962306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
217062306a36Sopenharmony_ci	if (!sp)
217162306a36Sopenharmony_ci		return;
217262306a36Sopenharmony_ci
217362306a36Sopenharmony_ci	if (sp->type == SRB_SCSI_CMD ||
217462306a36Sopenharmony_ci	    sp->type == SRB_NVME_CMD ||
217562306a36Sopenharmony_ci	    sp->type == SRB_TM_CMD) {
217662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x509d,
217762306a36Sopenharmony_ci			"Inconsistent event entry type %d\n", sp->type);
217862306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
217962306a36Sopenharmony_ci			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
218062306a36Sopenharmony_ci		else
218162306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
218262306a36Sopenharmony_ci		return;
218362306a36Sopenharmony_ci	}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci	si = &sp->u.iocb_cmd;
218662306a36Sopenharmony_ci	sz = min(ARRAY_SIZE(pkt->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.in_mb));
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci	for (i = 0; i < sz; i++)
218962306a36Sopenharmony_ci		si->u.mbx.in_mb[i] = pkt->mb[i];
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_ci	res = (si->u.mbx.in_mb[0] & MBS_MASK);
219262306a36Sopenharmony_ci
219362306a36Sopenharmony_ci	sp->done(sp, res);
219462306a36Sopenharmony_ci}
219562306a36Sopenharmony_ci
219662306a36Sopenharmony_cistatic void
219762306a36Sopenharmony_ciqla24xxx_nack_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
219862306a36Sopenharmony_ci    struct nack_to_isp *pkt)
219962306a36Sopenharmony_ci{
220062306a36Sopenharmony_ci	const char func[] = "nack";
220162306a36Sopenharmony_ci	srb_t *sp;
220262306a36Sopenharmony_ci	int res = 0;
220362306a36Sopenharmony_ci
220462306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
220562306a36Sopenharmony_ci	if (!sp)
220662306a36Sopenharmony_ci		return;
220762306a36Sopenharmony_ci
220862306a36Sopenharmony_ci	if (pkt->u.isp2x.status != cpu_to_le16(NOTIFY_ACK_SUCCESS))
220962306a36Sopenharmony_ci		res = QLA_FUNCTION_FAILED;
221062306a36Sopenharmony_ci
221162306a36Sopenharmony_ci	sp->done(sp, res);
221262306a36Sopenharmony_ci}
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_cistatic void
221562306a36Sopenharmony_ciqla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
221662306a36Sopenharmony_ci    sts_entry_t *pkt, int iocb_type)
221762306a36Sopenharmony_ci{
221862306a36Sopenharmony_ci	const char func[] = "CT_IOCB";
221962306a36Sopenharmony_ci	const char *type;
222062306a36Sopenharmony_ci	srb_t *sp;
222162306a36Sopenharmony_ci	struct bsg_job *bsg_job;
222262306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
222362306a36Sopenharmony_ci	uint16_t comp_status;
222462306a36Sopenharmony_ci	int res = 0;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
222762306a36Sopenharmony_ci	if (!sp)
222862306a36Sopenharmony_ci		return;
222962306a36Sopenharmony_ci
223062306a36Sopenharmony_ci	switch (sp->type) {
223162306a36Sopenharmony_ci	case SRB_CT_CMD:
223262306a36Sopenharmony_ci	    bsg_job = sp->u.bsg_job;
223362306a36Sopenharmony_ci	    bsg_reply = bsg_job->reply;
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_ci	    type = "ct pass-through";
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	    comp_status = le16_to_cpu(pkt->comp_status);
223862306a36Sopenharmony_ci
223962306a36Sopenharmony_ci	    /*
224062306a36Sopenharmony_ci	     * return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
224162306a36Sopenharmony_ci	     * fc payload  to the caller
224262306a36Sopenharmony_ci	     */
224362306a36Sopenharmony_ci	    bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
224462306a36Sopenharmony_ci	    bsg_job->reply_len = sizeof(struct fc_bsg_reply);
224562306a36Sopenharmony_ci
224662306a36Sopenharmony_ci	    if (comp_status != CS_COMPLETE) {
224762306a36Sopenharmony_ci		    if (comp_status == CS_DATA_UNDERRUN) {
224862306a36Sopenharmony_ci			    res = DID_OK << 16;
224962306a36Sopenharmony_ci			    bsg_reply->reply_payload_rcv_len =
225062306a36Sopenharmony_ci				le16_to_cpu(pkt->rsp_info_len);
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci			    ql_log(ql_log_warn, vha, 0x5048,
225362306a36Sopenharmony_ci				"CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n",
225462306a36Sopenharmony_ci				type, comp_status,
225562306a36Sopenharmony_ci				bsg_reply->reply_payload_rcv_len);
225662306a36Sopenharmony_ci		    } else {
225762306a36Sopenharmony_ci			    ql_log(ql_log_warn, vha, 0x5049,
225862306a36Sopenharmony_ci				"CT pass-through-%s error comp_status=0x%x.\n",
225962306a36Sopenharmony_ci				type, comp_status);
226062306a36Sopenharmony_ci			    res = DID_ERROR << 16;
226162306a36Sopenharmony_ci			    bsg_reply->reply_payload_rcv_len = 0;
226262306a36Sopenharmony_ci		    }
226362306a36Sopenharmony_ci		    ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
226462306a36Sopenharmony_ci			pkt, sizeof(*pkt));
226562306a36Sopenharmony_ci	    } else {
226662306a36Sopenharmony_ci		    res = DID_OK << 16;
226762306a36Sopenharmony_ci		    bsg_reply->reply_payload_rcv_len =
226862306a36Sopenharmony_ci			bsg_job->reply_payload.payload_len;
226962306a36Sopenharmony_ci		    bsg_job->reply_len = 0;
227062306a36Sopenharmony_ci	    }
227162306a36Sopenharmony_ci	    break;
227262306a36Sopenharmony_ci	case SRB_CT_PTHRU_CMD:
227362306a36Sopenharmony_ci	    /*
227462306a36Sopenharmony_ci	     * borrowing sts_entry_24xx.comp_status.
227562306a36Sopenharmony_ci	     * same location as ct_entry_24xx.comp_status
227662306a36Sopenharmony_ci	     */
227762306a36Sopenharmony_ci	     res = qla2x00_chk_ms_status(vha, (ms_iocb_entry_t *)pkt,
227862306a36Sopenharmony_ci		 (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
227962306a36Sopenharmony_ci		 sp->name);
228062306a36Sopenharmony_ci	     break;
228162306a36Sopenharmony_ci	}
228262306a36Sopenharmony_ci
228362306a36Sopenharmony_ci	sp->done(sp, res);
228462306a36Sopenharmony_ci}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_cistatic void
228762306a36Sopenharmony_ciqla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
228862306a36Sopenharmony_ci    struct sts_entry_24xx *pkt, int iocb_type)
228962306a36Sopenharmony_ci{
229062306a36Sopenharmony_ci	struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt;
229162306a36Sopenharmony_ci	const char func[] = "ELS_CT_IOCB";
229262306a36Sopenharmony_ci	const char *type;
229362306a36Sopenharmony_ci	srb_t *sp;
229462306a36Sopenharmony_ci	struct bsg_job *bsg_job;
229562306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
229662306a36Sopenharmony_ci	uint16_t comp_status;
229762306a36Sopenharmony_ci	uint32_t fw_status[3];
229862306a36Sopenharmony_ci	int res, logit = 1;
229962306a36Sopenharmony_ci	struct srb_iocb *els;
230062306a36Sopenharmony_ci	uint n;
230162306a36Sopenharmony_ci	scsi_qla_host_t *vha;
230262306a36Sopenharmony_ci	struct els_sts_entry_24xx *e = (struct els_sts_entry_24xx *)pkt;
230362306a36Sopenharmony_ci
230462306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(v, func, req, pkt);
230562306a36Sopenharmony_ci	if (!sp)
230662306a36Sopenharmony_ci		return;
230762306a36Sopenharmony_ci	bsg_job = sp->u.bsg_job;
230862306a36Sopenharmony_ci	vha = sp->vha;
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ci	type = NULL;
231162306a36Sopenharmony_ci
231262306a36Sopenharmony_ci	comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
231362306a36Sopenharmony_ci	fw_status[1] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1);
231462306a36Sopenharmony_ci	fw_status[2] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2);
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	switch (sp->type) {
231762306a36Sopenharmony_ci	case SRB_ELS_CMD_RPT:
231862306a36Sopenharmony_ci	case SRB_ELS_CMD_HST:
231962306a36Sopenharmony_ci		type = "rpt hst";
232062306a36Sopenharmony_ci		break;
232162306a36Sopenharmony_ci	case SRB_ELS_CMD_HST_NOLOGIN:
232262306a36Sopenharmony_ci		type = "els";
232362306a36Sopenharmony_ci		{
232462306a36Sopenharmony_ci			struct els_entry_24xx *els = (void *)pkt;
232562306a36Sopenharmony_ci			struct qla_bsg_auth_els_request *p =
232662306a36Sopenharmony_ci				(struct qla_bsg_auth_els_request *)bsg_job->request;
232762306a36Sopenharmony_ci
232862306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x700f,
232962306a36Sopenharmony_ci			     "%s %s. portid=%02x%02x%02x status %x xchg %x bsg ptr %p\n",
233062306a36Sopenharmony_ci			     __func__, sc_to_str(p->e.sub_cmd),
233162306a36Sopenharmony_ci			     e->d_id[2], e->d_id[1], e->d_id[0],
233262306a36Sopenharmony_ci			     comp_status, p->e.extra_rx_xchg_address, bsg_job);
233362306a36Sopenharmony_ci
233462306a36Sopenharmony_ci			if (!(le16_to_cpu(els->control_flags) & ECF_PAYLOAD_DESCR_MASK)) {
233562306a36Sopenharmony_ci				if (sp->remap.remapped) {
233662306a36Sopenharmony_ci					n = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
233762306a36Sopenharmony_ci						bsg_job->reply_payload.sg_cnt,
233862306a36Sopenharmony_ci						sp->remap.rsp.buf,
233962306a36Sopenharmony_ci						sp->remap.rsp.len);
234062306a36Sopenharmony_ci					ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x700e,
234162306a36Sopenharmony_ci					   "%s: SG copied %x of %x\n",
234262306a36Sopenharmony_ci					   __func__, n, sp->remap.rsp.len);
234362306a36Sopenharmony_ci				} else {
234462306a36Sopenharmony_ci					ql_dbg(ql_dbg_user, vha, 0x700f,
234562306a36Sopenharmony_ci					   "%s: NOT REMAPPED (error)...!!!\n",
234662306a36Sopenharmony_ci					   __func__);
234762306a36Sopenharmony_ci				}
234862306a36Sopenharmony_ci			}
234962306a36Sopenharmony_ci		}
235062306a36Sopenharmony_ci		break;
235162306a36Sopenharmony_ci	case SRB_CT_CMD:
235262306a36Sopenharmony_ci		type = "ct pass-through";
235362306a36Sopenharmony_ci		break;
235462306a36Sopenharmony_ci	case SRB_ELS_DCMD:
235562306a36Sopenharmony_ci		type = "Driver ELS logo";
235662306a36Sopenharmony_ci		if (iocb_type != ELS_IOCB_TYPE) {
235762306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x5047,
235862306a36Sopenharmony_ci			    "Completing %s: (%p) type=%d.\n",
235962306a36Sopenharmony_ci			    type, sp, sp->type);
236062306a36Sopenharmony_ci			sp->done(sp, 0);
236162306a36Sopenharmony_ci			return;
236262306a36Sopenharmony_ci		}
236362306a36Sopenharmony_ci		break;
236462306a36Sopenharmony_ci	case SRB_CT_PTHRU_CMD:
236562306a36Sopenharmony_ci		/* borrowing sts_entry_24xx.comp_status.
236662306a36Sopenharmony_ci		   same location as ct_entry_24xx.comp_status
236762306a36Sopenharmony_ci		 */
236862306a36Sopenharmony_ci		res = qla2x00_chk_ms_status(sp->vha, (ms_iocb_entry_t *)pkt,
236962306a36Sopenharmony_ci			(struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
237062306a36Sopenharmony_ci			sp->name);
237162306a36Sopenharmony_ci		sp->done(sp, res);
237262306a36Sopenharmony_ci		return;
237362306a36Sopenharmony_ci	default:
237462306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x503e,
237562306a36Sopenharmony_ci		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
237662306a36Sopenharmony_ci		return;
237762306a36Sopenharmony_ci	}
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	if (iocb_type == ELS_IOCB_TYPE) {
238062306a36Sopenharmony_ci		els = &sp->u.iocb_cmd;
238162306a36Sopenharmony_ci		els->u.els_plogi.fw_status[0] = cpu_to_le32(fw_status[0]);
238262306a36Sopenharmony_ci		els->u.els_plogi.fw_status[1] = cpu_to_le32(fw_status[1]);
238362306a36Sopenharmony_ci		els->u.els_plogi.fw_status[2] = cpu_to_le32(fw_status[2]);
238462306a36Sopenharmony_ci		els->u.els_plogi.comp_status = cpu_to_le16(fw_status[0]);
238562306a36Sopenharmony_ci		if (comp_status == CS_COMPLETE) {
238662306a36Sopenharmony_ci			res =  DID_OK << 16;
238762306a36Sopenharmony_ci		} else {
238862306a36Sopenharmony_ci			if (comp_status == CS_DATA_UNDERRUN) {
238962306a36Sopenharmony_ci				res =  DID_OK << 16;
239062306a36Sopenharmony_ci				els->u.els_plogi.len = cpu_to_le16(le32_to_cpu(
239162306a36Sopenharmony_ci					ese->total_byte_count));
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci				if (sp->remap.remapped &&
239462306a36Sopenharmony_ci				    ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_ACC) {
239562306a36Sopenharmony_ci					ql_dbg(ql_dbg_user, vha, 0x503f,
239662306a36Sopenharmony_ci					    "%s IOCB Done LS_ACC %02x%02x%02x -> %02x%02x%02x",
239762306a36Sopenharmony_ci					    __func__, e->s_id[0], e->s_id[2], e->s_id[1],
239862306a36Sopenharmony_ci					    e->d_id[2], e->d_id[1], e->d_id[0]);
239962306a36Sopenharmony_ci					logit = 0;
240062306a36Sopenharmony_ci				}
240162306a36Sopenharmony_ci
240262306a36Sopenharmony_ci			} else if (comp_status == CS_PORT_LOGGED_OUT) {
240362306a36Sopenharmony_ci				ql_dbg(ql_dbg_disc, vha, 0x911e,
240462306a36Sopenharmony_ci				       "%s %d schedule session deletion\n",
240562306a36Sopenharmony_ci				       __func__, __LINE__);
240662306a36Sopenharmony_ci
240762306a36Sopenharmony_ci				els->u.els_plogi.len = 0;
240862306a36Sopenharmony_ci				res = DID_IMM_RETRY << 16;
240962306a36Sopenharmony_ci				qlt_schedule_sess_for_deletion(sp->fcport);
241062306a36Sopenharmony_ci			} else {
241162306a36Sopenharmony_ci				els->u.els_plogi.len = 0;
241262306a36Sopenharmony_ci				res = DID_ERROR << 16;
241362306a36Sopenharmony_ci			}
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci			if (sp->remap.remapped &&
241662306a36Sopenharmony_ci			    ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_RJT) {
241762306a36Sopenharmony_ci				if (logit) {
241862306a36Sopenharmony_ci					ql_dbg(ql_dbg_user, vha, 0x503f,
241962306a36Sopenharmony_ci					    "%s IOCB Done LS_RJT hdl=%x comp_status=0x%x\n",
242062306a36Sopenharmony_ci					    type, sp->handle, comp_status);
242162306a36Sopenharmony_ci
242262306a36Sopenharmony_ci					ql_dbg(ql_dbg_user, vha, 0x503f,
242362306a36Sopenharmony_ci					    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
242462306a36Sopenharmony_ci					    fw_status[1], fw_status[2],
242562306a36Sopenharmony_ci					    le32_to_cpu(((struct els_sts_entry_24xx *)
242662306a36Sopenharmony_ci						pkt)->total_byte_count),
242762306a36Sopenharmony_ci					    e->s_id[0], e->s_id[2], e->s_id[1],
242862306a36Sopenharmony_ci					    e->d_id[2], e->d_id[1], e->d_id[0]);
242962306a36Sopenharmony_ci				}
243062306a36Sopenharmony_ci				if (sp->fcport && sp->fcport->flags & FCF_FCSP_DEVICE &&
243162306a36Sopenharmony_ci				    sp->type == SRB_ELS_CMD_HST_NOLOGIN) {
243262306a36Sopenharmony_ci					ql_dbg(ql_dbg_edif, vha, 0x911e,
243362306a36Sopenharmony_ci					    "%s rcv reject. Sched delete\n", __func__);
243462306a36Sopenharmony_ci					qlt_schedule_sess_for_deletion(sp->fcport);
243562306a36Sopenharmony_ci				}
243662306a36Sopenharmony_ci			} else if (logit) {
243762306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x503f,
243862306a36Sopenharmony_ci				    "%s IOCB Done hdl=%x comp_status=0x%x\n",
243962306a36Sopenharmony_ci				    type, sp->handle, comp_status);
244062306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x503f,
244162306a36Sopenharmony_ci				    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
244262306a36Sopenharmony_ci				    fw_status[1], fw_status[2],
244362306a36Sopenharmony_ci				    le32_to_cpu(((struct els_sts_entry_24xx *)
244462306a36Sopenharmony_ci				    pkt)->total_byte_count),
244562306a36Sopenharmony_ci				    e->s_id[0], e->s_id[2], e->s_id[1],
244662306a36Sopenharmony_ci				    e->d_id[2], e->d_id[1], e->d_id[0]);
244762306a36Sopenharmony_ci			}
244862306a36Sopenharmony_ci		}
244962306a36Sopenharmony_ci		goto els_ct_done;
245062306a36Sopenharmony_ci	}
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
245362306a36Sopenharmony_ci	 * fc payload  to the caller
245462306a36Sopenharmony_ci	 */
245562306a36Sopenharmony_ci	bsg_job = sp->u.bsg_job;
245662306a36Sopenharmony_ci	bsg_reply = bsg_job->reply;
245762306a36Sopenharmony_ci	bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
245862306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
245962306a36Sopenharmony_ci
246062306a36Sopenharmony_ci	if (comp_status != CS_COMPLETE) {
246162306a36Sopenharmony_ci		if (comp_status == CS_DATA_UNDERRUN) {
246262306a36Sopenharmony_ci			res = DID_OK << 16;
246362306a36Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
246462306a36Sopenharmony_ci				le32_to_cpu(ese->total_byte_count);
246562306a36Sopenharmony_ci
246662306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x503f,
246762306a36Sopenharmony_ci			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
246862306a36Sopenharmony_ci			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
246962306a36Sopenharmony_ci			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
247062306a36Sopenharmony_ci			    le32_to_cpu(ese->total_byte_count));
247162306a36Sopenharmony_ci		} else {
247262306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x5040,
247362306a36Sopenharmony_ci			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
247462306a36Sopenharmony_ci			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
247562306a36Sopenharmony_ci			    type, sp->handle, comp_status,
247662306a36Sopenharmony_ci			    le32_to_cpu(ese->error_subcode_1),
247762306a36Sopenharmony_ci			    le32_to_cpu(ese->error_subcode_2));
247862306a36Sopenharmony_ci			res = DID_ERROR << 16;
247962306a36Sopenharmony_ci			bsg_reply->reply_payload_rcv_len = 0;
248062306a36Sopenharmony_ci		}
248162306a36Sopenharmony_ci		memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply),
248262306a36Sopenharmony_ci		       fw_status, sizeof(fw_status));
248362306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
248462306a36Sopenharmony_ci		    pkt, sizeof(*pkt));
248562306a36Sopenharmony_ci	}
248662306a36Sopenharmony_ci	else {
248762306a36Sopenharmony_ci		res =  DID_OK << 16;
248862306a36Sopenharmony_ci		bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
248962306a36Sopenharmony_ci		bsg_job->reply_len = 0;
249062306a36Sopenharmony_ci	}
249162306a36Sopenharmony_ciels_ct_done:
249262306a36Sopenharmony_ci
249362306a36Sopenharmony_ci	sp->done(sp, res);
249462306a36Sopenharmony_ci}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_cistatic void
249762306a36Sopenharmony_ciqla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
249862306a36Sopenharmony_ci    struct logio_entry_24xx *logio)
249962306a36Sopenharmony_ci{
250062306a36Sopenharmony_ci	const char func[] = "LOGIO-IOCB";
250162306a36Sopenharmony_ci	const char *type;
250262306a36Sopenharmony_ci	fc_port_t *fcport;
250362306a36Sopenharmony_ci	srb_t *sp;
250462306a36Sopenharmony_ci	struct srb_iocb *lio;
250562306a36Sopenharmony_ci	uint16_t *data;
250662306a36Sopenharmony_ci	uint32_t iop[2];
250762306a36Sopenharmony_ci	int logit = 1;
250862306a36Sopenharmony_ci
250962306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
251062306a36Sopenharmony_ci	if (!sp)
251162306a36Sopenharmony_ci		return;
251262306a36Sopenharmony_ci
251362306a36Sopenharmony_ci	lio = &sp->u.iocb_cmd;
251462306a36Sopenharmony_ci	type = sp->name;
251562306a36Sopenharmony_ci	fcport = sp->fcport;
251662306a36Sopenharmony_ci	data = lio->u.logio.data;
251762306a36Sopenharmony_ci
251862306a36Sopenharmony_ci	data[0] = MBS_COMMAND_ERROR;
251962306a36Sopenharmony_ci	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
252062306a36Sopenharmony_ci		QLA_LOGIO_LOGIN_RETRIED : 0;
252162306a36Sopenharmony_ci	if (logio->entry_status) {
252262306a36Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5034,
252362306a36Sopenharmony_ci		    "Async-%s error entry - %8phC hdl=%x"
252462306a36Sopenharmony_ci		    "portid=%02x%02x%02x entry-status=%x.\n",
252562306a36Sopenharmony_ci		    type, fcport->port_name, sp->handle, fcport->d_id.b.domain,
252662306a36Sopenharmony_ci		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
252762306a36Sopenharmony_ci		    logio->entry_status);
252862306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
252962306a36Sopenharmony_ci		    logio, sizeof(*logio));
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci		goto logio_done;
253262306a36Sopenharmony_ci	}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
253562306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, sp->vha, 0x5036,
253662306a36Sopenharmony_ci		    "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n",
253762306a36Sopenharmony_ci		    type, sp->handle, fcport->d_id.b24, fcport->port_name,
253862306a36Sopenharmony_ci		    le32_to_cpu(logio->io_parameter[0]));
253962306a36Sopenharmony_ci
254062306a36Sopenharmony_ci		vha->hw->exch_starvation = 0;
254162306a36Sopenharmony_ci		data[0] = MBS_COMMAND_COMPLETE;
254262306a36Sopenharmony_ci
254362306a36Sopenharmony_ci		if (sp->type == SRB_PRLI_CMD) {
254462306a36Sopenharmony_ci			lio->u.logio.iop[0] =
254562306a36Sopenharmony_ci			    le32_to_cpu(logio->io_parameter[0]);
254662306a36Sopenharmony_ci			lio->u.logio.iop[1] =
254762306a36Sopenharmony_ci			    le32_to_cpu(logio->io_parameter[1]);
254862306a36Sopenharmony_ci			goto logio_done;
254962306a36Sopenharmony_ci		}
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci		if (sp->type != SRB_LOGIN_CMD)
255262306a36Sopenharmony_ci			goto logio_done;
255362306a36Sopenharmony_ci
255462306a36Sopenharmony_ci		lio->u.logio.iop[1] = le32_to_cpu(logio->io_parameter[5]);
255562306a36Sopenharmony_ci		if (le32_to_cpu(logio->io_parameter[5]) & LIO_COMM_FEAT_FCSP)
255662306a36Sopenharmony_ci			fcport->flags |= FCF_FCSP_DEVICE;
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci		iop[0] = le32_to_cpu(logio->io_parameter[0]);
255962306a36Sopenharmony_ci		if (iop[0] & BIT_4) {
256062306a36Sopenharmony_ci			fcport->port_type = FCT_TARGET;
256162306a36Sopenharmony_ci			if (iop[0] & BIT_8)
256262306a36Sopenharmony_ci				fcport->flags |= FCF_FCP2_DEVICE;
256362306a36Sopenharmony_ci		} else if (iop[0] & BIT_5)
256462306a36Sopenharmony_ci			fcport->port_type = FCT_INITIATOR;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci		if (iop[0] & BIT_7)
256762306a36Sopenharmony_ci			fcport->flags |= FCF_CONF_COMP_SUPPORTED;
256862306a36Sopenharmony_ci
256962306a36Sopenharmony_ci		if (logio->io_parameter[7] || logio->io_parameter[8])
257062306a36Sopenharmony_ci			fcport->supported_classes |= FC_COS_CLASS2;
257162306a36Sopenharmony_ci		if (logio->io_parameter[9] || logio->io_parameter[10])
257262306a36Sopenharmony_ci			fcport->supported_classes |= FC_COS_CLASS3;
257362306a36Sopenharmony_ci
257462306a36Sopenharmony_ci		goto logio_done;
257562306a36Sopenharmony_ci	}
257662306a36Sopenharmony_ci
257762306a36Sopenharmony_ci	iop[0] = le32_to_cpu(logio->io_parameter[0]);
257862306a36Sopenharmony_ci	iop[1] = le32_to_cpu(logio->io_parameter[1]);
257962306a36Sopenharmony_ci	lio->u.logio.iop[0] = iop[0];
258062306a36Sopenharmony_ci	lio->u.logio.iop[1] = iop[1];
258162306a36Sopenharmony_ci	switch (iop[0]) {
258262306a36Sopenharmony_ci	case LSC_SCODE_PORTID_USED:
258362306a36Sopenharmony_ci		data[0] = MBS_PORT_ID_USED;
258462306a36Sopenharmony_ci		data[1] = LSW(iop[1]);
258562306a36Sopenharmony_ci		logit = 0;
258662306a36Sopenharmony_ci		break;
258762306a36Sopenharmony_ci	case LSC_SCODE_NPORT_USED:
258862306a36Sopenharmony_ci		data[0] = MBS_LOOP_ID_USED;
258962306a36Sopenharmony_ci		logit = 0;
259062306a36Sopenharmony_ci		break;
259162306a36Sopenharmony_ci	case LSC_SCODE_CMD_FAILED:
259262306a36Sopenharmony_ci		if (iop[1] == 0x0606) {
259362306a36Sopenharmony_ci			/*
259462306a36Sopenharmony_ci			 * PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI,
259562306a36Sopenharmony_ci			 * Target side acked.
259662306a36Sopenharmony_ci			 */
259762306a36Sopenharmony_ci			data[0] = MBS_COMMAND_COMPLETE;
259862306a36Sopenharmony_ci			goto logio_done;
259962306a36Sopenharmony_ci		}
260062306a36Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
260162306a36Sopenharmony_ci		break;
260262306a36Sopenharmony_ci	case LSC_SCODE_NOXCB:
260362306a36Sopenharmony_ci		vha->hw->exch_starvation++;
260462306a36Sopenharmony_ci		if (vha->hw->exch_starvation > 5) {
260562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xd046,
260662306a36Sopenharmony_ci			    "Exchange starvation. Resetting RISC\n");
260762306a36Sopenharmony_ci
260862306a36Sopenharmony_ci			vha->hw->exch_starvation = 0;
260962306a36Sopenharmony_ci
261062306a36Sopenharmony_ci			if (IS_P3P_TYPE(vha->hw))
261162306a36Sopenharmony_ci				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
261262306a36Sopenharmony_ci			else
261362306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
261462306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
261562306a36Sopenharmony_ci		}
261662306a36Sopenharmony_ci		fallthrough;
261762306a36Sopenharmony_ci	default:
261862306a36Sopenharmony_ci		data[0] = MBS_COMMAND_ERROR;
261962306a36Sopenharmony_ci		break;
262062306a36Sopenharmony_ci	}
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ci	if (logit)
262362306a36Sopenharmony_ci		ql_log(ql_log_warn, sp->vha, 0x5037, "Async-%s failed: "
262462306a36Sopenharmony_ci		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
262562306a36Sopenharmony_ci		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
262662306a36Sopenharmony_ci		       le16_to_cpu(logio->comp_status),
262762306a36Sopenharmony_ci		       le32_to_cpu(logio->io_parameter[0]),
262862306a36Sopenharmony_ci		       le32_to_cpu(logio->io_parameter[1]));
262962306a36Sopenharmony_ci	else
263062306a36Sopenharmony_ci		ql_dbg(ql_dbg_disc, sp->vha, 0x5037, "Async-%s failed: "
263162306a36Sopenharmony_ci		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
263262306a36Sopenharmony_ci		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
263362306a36Sopenharmony_ci		       le16_to_cpu(logio->comp_status),
263462306a36Sopenharmony_ci		       le32_to_cpu(logio->io_parameter[0]),
263562306a36Sopenharmony_ci		       le32_to_cpu(logio->io_parameter[1]));
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_cilogio_done:
263862306a36Sopenharmony_ci	sp->done(sp, 0);
263962306a36Sopenharmony_ci}
264062306a36Sopenharmony_ci
264162306a36Sopenharmony_cistatic void
264262306a36Sopenharmony_ciqla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
264362306a36Sopenharmony_ci{
264462306a36Sopenharmony_ci	const char func[] = "TMF-IOCB";
264562306a36Sopenharmony_ci	const char *type;
264662306a36Sopenharmony_ci	fc_port_t *fcport;
264762306a36Sopenharmony_ci	srb_t *sp;
264862306a36Sopenharmony_ci	struct srb_iocb *iocb;
264962306a36Sopenharmony_ci	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
265062306a36Sopenharmony_ci	u16 comp_status;
265162306a36Sopenharmony_ci
265262306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
265362306a36Sopenharmony_ci	if (!sp)
265462306a36Sopenharmony_ci		return;
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci	comp_status = le16_to_cpu(sts->comp_status);
265762306a36Sopenharmony_ci	iocb = &sp->u.iocb_cmd;
265862306a36Sopenharmony_ci	type = sp->name;
265962306a36Sopenharmony_ci	fcport = sp->fcport;
266062306a36Sopenharmony_ci	iocb->u.tmf.data = QLA_SUCCESS;
266162306a36Sopenharmony_ci
266262306a36Sopenharmony_ci	if (sts->entry_status) {
266362306a36Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5038,
266462306a36Sopenharmony_ci		    "Async-%s error - hdl=%x entry-status(%x).\n",
266562306a36Sopenharmony_ci		    type, sp->handle, sts->entry_status);
266662306a36Sopenharmony_ci		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
266762306a36Sopenharmony_ci	} else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
266862306a36Sopenharmony_ci		ql_log(ql_log_warn, fcport->vha, 0x5039,
266962306a36Sopenharmony_ci		    "Async-%s error - hdl=%x completion status(%x).\n",
267062306a36Sopenharmony_ci		    type, sp->handle, comp_status);
267162306a36Sopenharmony_ci		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
267262306a36Sopenharmony_ci	} else if ((le16_to_cpu(sts->scsi_status) &
267362306a36Sopenharmony_ci	    SS_RESPONSE_INFO_LEN_VALID)) {
267462306a36Sopenharmony_ci		host_to_fcp_swap(sts->data, sizeof(sts->data));
267562306a36Sopenharmony_ci		if (le32_to_cpu(sts->rsp_data_len) < 4) {
267662306a36Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x503b,
267762306a36Sopenharmony_ci			    "Async-%s error - hdl=%x not enough response(%d).\n",
267862306a36Sopenharmony_ci			    type, sp->handle, sts->rsp_data_len);
267962306a36Sopenharmony_ci		} else if (sts->data[3]) {
268062306a36Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x503c,
268162306a36Sopenharmony_ci			    "Async-%s error - hdl=%x response(%x).\n",
268262306a36Sopenharmony_ci			    type, sp->handle, sts->data[3]);
268362306a36Sopenharmony_ci			iocb->u.tmf.data = QLA_FUNCTION_FAILED;
268462306a36Sopenharmony_ci		}
268562306a36Sopenharmony_ci	}
268662306a36Sopenharmony_ci
268762306a36Sopenharmony_ci	switch (comp_status) {
268862306a36Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
268962306a36Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
269062306a36Sopenharmony_ci	case CS_PORT_BUSY:
269162306a36Sopenharmony_ci	case CS_INCOMPLETE:
269262306a36Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
269362306a36Sopenharmony_ci	case CS_RESET:
269462306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE) {
269562306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
269662306a36Sopenharmony_ci			       "-Port to be marked lost on fcport=%02x%02x%02x, current port state= %s comp_status %x.\n",
269762306a36Sopenharmony_ci			       fcport->d_id.b.domain, fcport->d_id.b.area,
269862306a36Sopenharmony_ci			       fcport->d_id.b.al_pa,
269962306a36Sopenharmony_ci			       port_state_str[FCS_ONLINE],
270062306a36Sopenharmony_ci			       comp_status);
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
270362306a36Sopenharmony_ci		}
270462306a36Sopenharmony_ci		break;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	default:
270762306a36Sopenharmony_ci		break;
270862306a36Sopenharmony_ci	}
270962306a36Sopenharmony_ci
271062306a36Sopenharmony_ci	if (iocb->u.tmf.data != QLA_SUCCESS)
271162306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
271262306a36Sopenharmony_ci		    sts, sizeof(*sts));
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	sp->done(sp, 0);
271562306a36Sopenharmony_ci}
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_cistatic void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
271862306a36Sopenharmony_ci    void *tsk, srb_t *sp)
271962306a36Sopenharmony_ci{
272062306a36Sopenharmony_ci	fc_port_t *fcport;
272162306a36Sopenharmony_ci	struct srb_iocb *iocb;
272262306a36Sopenharmony_ci	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
272362306a36Sopenharmony_ci	uint16_t        state_flags;
272462306a36Sopenharmony_ci	struct nvmefc_fcp_req *fd;
272562306a36Sopenharmony_ci	uint16_t        ret = QLA_SUCCESS;
272662306a36Sopenharmony_ci	__le16		comp_status = sts->comp_status;
272762306a36Sopenharmony_ci	int		logit = 0;
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	iocb = &sp->u.iocb_cmd;
273062306a36Sopenharmony_ci	fcport = sp->fcport;
273162306a36Sopenharmony_ci	iocb->u.nvme.comp_status = comp_status;
273262306a36Sopenharmony_ci	state_flags  = le16_to_cpu(sts->state_flags);
273362306a36Sopenharmony_ci	fd = iocb->u.nvme.desc;
273462306a36Sopenharmony_ci
273562306a36Sopenharmony_ci	if (unlikely(iocb->u.nvme.aen_op))
273662306a36Sopenharmony_ci		atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
273762306a36Sopenharmony_ci	else
273862306a36Sopenharmony_ci		sp->qpair->cmd_completion_cnt++;
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	if (unlikely(comp_status != CS_COMPLETE))
274162306a36Sopenharmony_ci		logit = 1;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	fd->transferred_length = fd->payload_length -
274462306a36Sopenharmony_ci	    le32_to_cpu(sts->residual_len);
274562306a36Sopenharmony_ci
274662306a36Sopenharmony_ci	/*
274762306a36Sopenharmony_ci	 * State flags: Bit 6 and 0.
274862306a36Sopenharmony_ci	 * If 0 is set, we don't care about 6.
274962306a36Sopenharmony_ci	 * both cases resp was dma'd to host buffer
275062306a36Sopenharmony_ci	 * if both are 0, that is good path case.
275162306a36Sopenharmony_ci	 * if six is set and 0 is clear, we need to
275262306a36Sopenharmony_ci	 * copy resp data from status iocb to resp buffer.
275362306a36Sopenharmony_ci	 */
275462306a36Sopenharmony_ci	if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) {
275562306a36Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
275662306a36Sopenharmony_ci	} else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) ==
275762306a36Sopenharmony_ci			(SF_FCP_RSP_DMA | SF_NVME_ERSP)) {
275862306a36Sopenharmony_ci		/* Response already DMA'd to fd->rspaddr. */
275962306a36Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
276062306a36Sopenharmony_ci	} else if ((state_flags & SF_FCP_RSP_DMA)) {
276162306a36Sopenharmony_ci		/*
276262306a36Sopenharmony_ci		 * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this
276362306a36Sopenharmony_ci		 * as an error.
276462306a36Sopenharmony_ci		 */
276562306a36Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
276662306a36Sopenharmony_ci		fd->transferred_length = 0;
276762306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x307a,
276862306a36Sopenharmony_ci			"Unexpected values in NVMe_RSP IU.\n");
276962306a36Sopenharmony_ci		logit = 1;
277062306a36Sopenharmony_ci	} else if (state_flags & SF_NVME_ERSP) {
277162306a36Sopenharmony_ci		uint32_t *inbuf, *outbuf;
277262306a36Sopenharmony_ci		uint16_t iter;
277362306a36Sopenharmony_ci
277462306a36Sopenharmony_ci		inbuf = (uint32_t *)&sts->nvme_ersp_data;
277562306a36Sopenharmony_ci		outbuf = (uint32_t *)fd->rspaddr;
277662306a36Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
277762306a36Sopenharmony_ci		if (unlikely(le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >
277862306a36Sopenharmony_ci		    sizeof(struct nvme_fc_ersp_iu))) {
277962306a36Sopenharmony_ci			if (ql_mask_match(ql_dbg_io)) {
278062306a36Sopenharmony_ci				WARN_ONCE(1, "Unexpected response payload length %u.\n",
278162306a36Sopenharmony_ci				    iocb->u.nvme.rsp_pyld_len);
278262306a36Sopenharmony_ci				ql_log(ql_log_warn, fcport->vha, 0x5100,
278362306a36Sopenharmony_ci				    "Unexpected response payload length %u.\n",
278462306a36Sopenharmony_ci				    iocb->u.nvme.rsp_pyld_len);
278562306a36Sopenharmony_ci			}
278662306a36Sopenharmony_ci			iocb->u.nvme.rsp_pyld_len =
278762306a36Sopenharmony_ci				cpu_to_le16(sizeof(struct nvme_fc_ersp_iu));
278862306a36Sopenharmony_ci		}
278962306a36Sopenharmony_ci		iter = le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >> 2;
279062306a36Sopenharmony_ci		for (; iter; iter--)
279162306a36Sopenharmony_ci			*outbuf++ = swab32(*inbuf++);
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	if (state_flags & SF_NVME_ERSP) {
279562306a36Sopenharmony_ci		struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr;
279662306a36Sopenharmony_ci		u32 tgt_xfer_len;
279762306a36Sopenharmony_ci
279862306a36Sopenharmony_ci		tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len);
279962306a36Sopenharmony_ci		if (fd->transferred_length != tgt_xfer_len) {
280062306a36Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x3079,
280162306a36Sopenharmony_ci			       "Dropped frame(s) detected (sent/rcvd=%u/%u).\n",
280262306a36Sopenharmony_ci			       tgt_xfer_len, fd->transferred_length);
280362306a36Sopenharmony_ci			logit = 1;
280462306a36Sopenharmony_ci		} else if (le16_to_cpu(comp_status) == CS_DATA_UNDERRUN) {
280562306a36Sopenharmony_ci			/*
280662306a36Sopenharmony_ci			 * Do not log if this is just an underflow and there
280762306a36Sopenharmony_ci			 * is no data loss.
280862306a36Sopenharmony_ci			 */
280962306a36Sopenharmony_ci			logit = 0;
281062306a36Sopenharmony_ci		}
281162306a36Sopenharmony_ci	}
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	if (unlikely(logit))
281462306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x5060,
281562306a36Sopenharmony_ci		   "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x  ox_id=%x\n",
281662306a36Sopenharmony_ci		   sp->name, sp->handle, comp_status,
281762306a36Sopenharmony_ci		   fd->transferred_length, le32_to_cpu(sts->residual_len),
281862306a36Sopenharmony_ci		   sts->ox_id);
281962306a36Sopenharmony_ci
282062306a36Sopenharmony_ci	/*
282162306a36Sopenharmony_ci	 * If transport error then Failure (HBA rejects request)
282262306a36Sopenharmony_ci	 * otherwise transport will handle.
282362306a36Sopenharmony_ci	 */
282462306a36Sopenharmony_ci	switch (le16_to_cpu(comp_status)) {
282562306a36Sopenharmony_ci	case CS_COMPLETE:
282662306a36Sopenharmony_ci		break;
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	case CS_RESET:
282962306a36Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
283062306a36Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
283162306a36Sopenharmony_ci		fcport->nvme_flag |= NVME_FLAG_RESETTING;
283262306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE) {
283362306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
283462306a36Sopenharmony_ci			       "Port to be marked lost on fcport=%06x, current "
283562306a36Sopenharmony_ci			       "port state= %s comp_status %x.\n",
283662306a36Sopenharmony_ci			       fcport->d_id.b24, port_state_str[FCS_ONLINE],
283762306a36Sopenharmony_ci			       comp_status);
283862306a36Sopenharmony_ci
283962306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
284062306a36Sopenharmony_ci		}
284162306a36Sopenharmony_ci		fallthrough;
284262306a36Sopenharmony_ci	case CS_ABORTED:
284362306a36Sopenharmony_ci	case CS_PORT_BUSY:
284462306a36Sopenharmony_ci		fd->transferred_length = 0;
284562306a36Sopenharmony_ci		iocb->u.nvme.rsp_pyld_len = 0;
284662306a36Sopenharmony_ci		ret = QLA_ABORTED;
284762306a36Sopenharmony_ci		break;
284862306a36Sopenharmony_ci	case CS_DATA_UNDERRUN:
284962306a36Sopenharmony_ci		break;
285062306a36Sopenharmony_ci	default:
285162306a36Sopenharmony_ci		ret = QLA_FUNCTION_FAILED;
285262306a36Sopenharmony_ci		break;
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci	sp->done(sp, ret);
285562306a36Sopenharmony_ci}
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_cistatic void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
285862306a36Sopenharmony_ci    struct vp_ctrl_entry_24xx *vce)
285962306a36Sopenharmony_ci{
286062306a36Sopenharmony_ci	const char func[] = "CTRLVP-IOCB";
286162306a36Sopenharmony_ci	srb_t *sp;
286262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
286362306a36Sopenharmony_ci
286462306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, vce);
286562306a36Sopenharmony_ci	if (!sp)
286662306a36Sopenharmony_ci		return;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	if (vce->entry_status != 0) {
286962306a36Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c4,
287062306a36Sopenharmony_ci		    "%s: Failed to complete IOCB -- error status (%x)\n",
287162306a36Sopenharmony_ci		    sp->name, vce->entry_status);
287262306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
287362306a36Sopenharmony_ci	} else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) {
287462306a36Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c5,
287562306a36Sopenharmony_ci		    "%s: Failed to complete IOCB -- completion status (%x) vpidx %x\n",
287662306a36Sopenharmony_ci		    sp->name, le16_to_cpu(vce->comp_status),
287762306a36Sopenharmony_ci		    le16_to_cpu(vce->vp_idx_failed));
287862306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
287962306a36Sopenharmony_ci	} else {
288062306a36Sopenharmony_ci		ql_dbg(ql_dbg_vport, vha, 0x10c6,
288162306a36Sopenharmony_ci		    "Done %s.\n", __func__);
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	sp->rc = rval;
288562306a36Sopenharmony_ci	sp->done(sp, rval);
288662306a36Sopenharmony_ci}
288762306a36Sopenharmony_ci
288862306a36Sopenharmony_ci/* Process a single response queue entry. */
288962306a36Sopenharmony_cistatic void qla2x00_process_response_entry(struct scsi_qla_host *vha,
289062306a36Sopenharmony_ci					   struct rsp_que *rsp,
289162306a36Sopenharmony_ci					   sts_entry_t *pkt)
289262306a36Sopenharmony_ci{
289362306a36Sopenharmony_ci	sts21_entry_t *sts21_entry;
289462306a36Sopenharmony_ci	sts22_entry_t *sts22_entry;
289562306a36Sopenharmony_ci	uint16_t handle_cnt;
289662306a36Sopenharmony_ci	uint16_t cnt;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	switch (pkt->entry_type) {
289962306a36Sopenharmony_ci	case STATUS_TYPE:
290062306a36Sopenharmony_ci		qla2x00_status_entry(vha, rsp, pkt);
290162306a36Sopenharmony_ci		break;
290262306a36Sopenharmony_ci	case STATUS_TYPE_21:
290362306a36Sopenharmony_ci		sts21_entry = (sts21_entry_t *)pkt;
290462306a36Sopenharmony_ci		handle_cnt = sts21_entry->handle_count;
290562306a36Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
290662306a36Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
290762306a36Sopenharmony_ci						sts21_entry->handle[cnt]);
290862306a36Sopenharmony_ci		break;
290962306a36Sopenharmony_ci	case STATUS_TYPE_22:
291062306a36Sopenharmony_ci		sts22_entry = (sts22_entry_t *)pkt;
291162306a36Sopenharmony_ci		handle_cnt = sts22_entry->handle_count;
291262306a36Sopenharmony_ci		for (cnt = 0; cnt < handle_cnt; cnt++)
291362306a36Sopenharmony_ci			qla2x00_process_completed_request(vha, rsp->req,
291462306a36Sopenharmony_ci						sts22_entry->handle[cnt]);
291562306a36Sopenharmony_ci		break;
291662306a36Sopenharmony_ci	case STATUS_CONT_TYPE:
291762306a36Sopenharmony_ci		qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
291862306a36Sopenharmony_ci		break;
291962306a36Sopenharmony_ci	case MBX_IOCB_TYPE:
292062306a36Sopenharmony_ci		qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
292162306a36Sopenharmony_ci		break;
292262306a36Sopenharmony_ci	case CT_IOCB_TYPE:
292362306a36Sopenharmony_ci		qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
292462306a36Sopenharmony_ci		break;
292562306a36Sopenharmony_ci	default:
292662306a36Sopenharmony_ci		/* Type Not Supported. */
292762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x504a,
292862306a36Sopenharmony_ci		       "Received unknown response pkt type %x entry status=%x.\n",
292962306a36Sopenharmony_ci		       pkt->entry_type, pkt->entry_status);
293062306a36Sopenharmony_ci		break;
293162306a36Sopenharmony_ci	}
293262306a36Sopenharmony_ci}
293362306a36Sopenharmony_ci
293462306a36Sopenharmony_ci/**
293562306a36Sopenharmony_ci * qla2x00_process_response_queue() - Process response queue entries.
293662306a36Sopenharmony_ci * @rsp: response queue
293762306a36Sopenharmony_ci */
293862306a36Sopenharmony_civoid
293962306a36Sopenharmony_ciqla2x00_process_response_queue(struct rsp_que *rsp)
294062306a36Sopenharmony_ci{
294162306a36Sopenharmony_ci	struct scsi_qla_host *vha;
294262306a36Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
294362306a36Sopenharmony_ci	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
294462306a36Sopenharmony_ci	sts_entry_t	*pkt;
294562306a36Sopenharmony_ci
294662306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
294762306a36Sopenharmony_ci
294862306a36Sopenharmony_ci	if (!vha->flags.online)
294962306a36Sopenharmony_ci		return;
295062306a36Sopenharmony_ci
295162306a36Sopenharmony_ci	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
295262306a36Sopenharmony_ci		pkt = (sts_entry_t *)rsp->ring_ptr;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci		rsp->ring_index++;
295562306a36Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
295662306a36Sopenharmony_ci			rsp->ring_index = 0;
295762306a36Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
295862306a36Sopenharmony_ci		} else {
295962306a36Sopenharmony_ci			rsp->ring_ptr++;
296062306a36Sopenharmony_ci		}
296162306a36Sopenharmony_ci
296262306a36Sopenharmony_ci		if (pkt->entry_status != 0) {
296362306a36Sopenharmony_ci			qla2x00_error_entry(vha, rsp, pkt);
296462306a36Sopenharmony_ci			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
296562306a36Sopenharmony_ci			wmb();
296662306a36Sopenharmony_ci			continue;
296762306a36Sopenharmony_ci		}
296862306a36Sopenharmony_ci
296962306a36Sopenharmony_ci		qla2x00_process_response_entry(vha, rsp, pkt);
297062306a36Sopenharmony_ci		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
297162306a36Sopenharmony_ci		wmb();
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci
297462306a36Sopenharmony_ci	/* Adjust ring index */
297562306a36Sopenharmony_ci	wrt_reg_word(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
297662306a36Sopenharmony_ci}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_cistatic inline void
297962306a36Sopenharmony_ciqla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
298062306a36Sopenharmony_ci		     uint32_t sense_len, struct rsp_que *rsp, int res)
298162306a36Sopenharmony_ci{
298262306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
298362306a36Sopenharmony_ci	struct scsi_cmnd *cp = GET_CMD_SP(sp);
298462306a36Sopenharmony_ci	uint32_t track_sense_len;
298562306a36Sopenharmony_ci
298662306a36Sopenharmony_ci	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
298762306a36Sopenharmony_ci		sense_len = SCSI_SENSE_BUFFERSIZE;
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
299062306a36Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
299162306a36Sopenharmony_ci	track_sense_len = sense_len;
299262306a36Sopenharmony_ci
299362306a36Sopenharmony_ci	if (sense_len > par_sense_len)
299462306a36Sopenharmony_ci		sense_len = par_sense_len;
299562306a36Sopenharmony_ci
299662306a36Sopenharmony_ci	memcpy(cp->sense_buffer, sense_data, sense_len);
299762306a36Sopenharmony_ci
299862306a36Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
299962306a36Sopenharmony_ci	track_sense_len -= sense_len;
300062306a36Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, track_sense_len);
300162306a36Sopenharmony_ci
300262306a36Sopenharmony_ci	if (track_sense_len != 0) {
300362306a36Sopenharmony_ci		rsp->status_srb = sp;
300462306a36Sopenharmony_ci		cp->result = res;
300562306a36Sopenharmony_ci	}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_ci	if (sense_len) {
300862306a36Sopenharmony_ci		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
300962306a36Sopenharmony_ci		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
301062306a36Sopenharmony_ci		    sp->vha->host_no, cp->device->id, cp->device->lun,
301162306a36Sopenharmony_ci		    cp);
301262306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
301362306a36Sopenharmony_ci		    cp->sense_buffer, sense_len);
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci}
301662306a36Sopenharmony_ci
301762306a36Sopenharmony_cistruct scsi_dif_tuple {
301862306a36Sopenharmony_ci	__be16 guard;       /* Checksum */
301962306a36Sopenharmony_ci	__be16 app_tag;         /* APPL identifier */
302062306a36Sopenharmony_ci	__be32 ref_tag;         /* Target LBA or indirect LBA */
302162306a36Sopenharmony_ci};
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci/*
302462306a36Sopenharmony_ci * Checks the guard or meta-data for the type of error
302562306a36Sopenharmony_ci * detected by the HBA. In case of errors, we set the
302662306a36Sopenharmony_ci * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
302762306a36Sopenharmony_ci * to indicate to the kernel that the HBA detected error.
302862306a36Sopenharmony_ci */
302962306a36Sopenharmony_cistatic inline int
303062306a36Sopenharmony_ciqla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
303162306a36Sopenharmony_ci{
303262306a36Sopenharmony_ci	struct scsi_qla_host *vha = sp->vha;
303362306a36Sopenharmony_ci	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
303462306a36Sopenharmony_ci	uint8_t		*ap = &sts24->data[12];
303562306a36Sopenharmony_ci	uint8_t		*ep = &sts24->data[20];
303662306a36Sopenharmony_ci	uint32_t	e_ref_tag, a_ref_tag;
303762306a36Sopenharmony_ci	uint16_t	e_app_tag, a_app_tag;
303862306a36Sopenharmony_ci	uint16_t	e_guard, a_guard;
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	/*
304162306a36Sopenharmony_ci	 * swab32 of the "data" field in the beginning of qla2x00_status_entry()
304262306a36Sopenharmony_ci	 * would make guard field appear at offset 2
304362306a36Sopenharmony_ci	 */
304462306a36Sopenharmony_ci	a_guard   = get_unaligned_le16(ap + 2);
304562306a36Sopenharmony_ci	a_app_tag = get_unaligned_le16(ap + 0);
304662306a36Sopenharmony_ci	a_ref_tag = get_unaligned_le32(ap + 4);
304762306a36Sopenharmony_ci	e_guard   = get_unaligned_le16(ep + 2);
304862306a36Sopenharmony_ci	e_app_tag = get_unaligned_le16(ep + 0);
304962306a36Sopenharmony_ci	e_ref_tag = get_unaligned_le32(ep + 4);
305062306a36Sopenharmony_ci
305162306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3023,
305262306a36Sopenharmony_ci	    "iocb(s) %p Returned STATUS.\n", sts24);
305362306a36Sopenharmony_ci
305462306a36Sopenharmony_ci	ql_dbg(ql_dbg_io, vha, 0x3024,
305562306a36Sopenharmony_ci	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
305662306a36Sopenharmony_ci	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
305762306a36Sopenharmony_ci	    " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
305862306a36Sopenharmony_ci	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
305962306a36Sopenharmony_ci	    a_app_tag, e_app_tag, a_guard, e_guard);
306062306a36Sopenharmony_ci
306162306a36Sopenharmony_ci	/*
306262306a36Sopenharmony_ci	 * Ignore sector if:
306362306a36Sopenharmony_ci	 * For type     3: ref & app tag is all 'f's
306462306a36Sopenharmony_ci	 * For type 0,1,2: app tag is all 'f's
306562306a36Sopenharmony_ci	 */
306662306a36Sopenharmony_ci	if (a_app_tag == be16_to_cpu(T10_PI_APP_ESCAPE) &&
306762306a36Sopenharmony_ci	    (scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3 ||
306862306a36Sopenharmony_ci	     a_ref_tag == be32_to_cpu(T10_PI_REF_ESCAPE))) {
306962306a36Sopenharmony_ci		uint32_t blocks_done, resid;
307062306a36Sopenharmony_ci		sector_t lba_s = scsi_get_lba(cmd);
307162306a36Sopenharmony_ci
307262306a36Sopenharmony_ci		/* 2TB boundary case covered automatically with this */
307362306a36Sopenharmony_ci		blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
307462306a36Sopenharmony_ci
307562306a36Sopenharmony_ci		resid = scsi_bufflen(cmd) - (blocks_done *
307662306a36Sopenharmony_ci		    cmd->device->sector_size);
307762306a36Sopenharmony_ci
307862306a36Sopenharmony_ci		scsi_set_resid(cmd, resid);
307962306a36Sopenharmony_ci		cmd->result = DID_OK << 16;
308062306a36Sopenharmony_ci
308162306a36Sopenharmony_ci		/* Update protection tag */
308262306a36Sopenharmony_ci		if (scsi_prot_sg_count(cmd)) {
308362306a36Sopenharmony_ci			uint32_t i, j = 0, k = 0, num_ent;
308462306a36Sopenharmony_ci			struct scatterlist *sg;
308562306a36Sopenharmony_ci			struct t10_pi_tuple *spt;
308662306a36Sopenharmony_ci
308762306a36Sopenharmony_ci			/* Patch the corresponding protection tags */
308862306a36Sopenharmony_ci			scsi_for_each_prot_sg(cmd, sg,
308962306a36Sopenharmony_ci			    scsi_prot_sg_count(cmd), i) {
309062306a36Sopenharmony_ci				num_ent = sg_dma_len(sg) / 8;
309162306a36Sopenharmony_ci				if (k + num_ent < blocks_done) {
309262306a36Sopenharmony_ci					k += num_ent;
309362306a36Sopenharmony_ci					continue;
309462306a36Sopenharmony_ci				}
309562306a36Sopenharmony_ci				j = blocks_done - k - 1;
309662306a36Sopenharmony_ci				k = blocks_done;
309762306a36Sopenharmony_ci				break;
309862306a36Sopenharmony_ci			}
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci			if (k != blocks_done) {
310162306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x302f,
310262306a36Sopenharmony_ci				    "unexpected tag values tag:lba=%x:%llx)\n",
310362306a36Sopenharmony_ci				    e_ref_tag, (unsigned long long)lba_s);
310462306a36Sopenharmony_ci				return 1;
310562306a36Sopenharmony_ci			}
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci			spt = page_address(sg_page(sg)) + sg->offset;
310862306a36Sopenharmony_ci			spt += j;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci			spt->app_tag = T10_PI_APP_ESCAPE;
311162306a36Sopenharmony_ci			if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
311262306a36Sopenharmony_ci				spt->ref_tag = T10_PI_REF_ESCAPE;
311362306a36Sopenharmony_ci		}
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci		return 0;
311662306a36Sopenharmony_ci	}
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci	/* check guard */
311962306a36Sopenharmony_ci	if (e_guard != a_guard) {
312062306a36Sopenharmony_ci		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
312162306a36Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
312262306a36Sopenharmony_ci		return 1;
312362306a36Sopenharmony_ci	}
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_ci	/* check ref tag */
312662306a36Sopenharmony_ci	if (e_ref_tag != a_ref_tag) {
312762306a36Sopenharmony_ci		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
312862306a36Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
312962306a36Sopenharmony_ci		return 1;
313062306a36Sopenharmony_ci	}
313162306a36Sopenharmony_ci
313262306a36Sopenharmony_ci	/* check appl tag */
313362306a36Sopenharmony_ci	if (e_app_tag != a_app_tag) {
313462306a36Sopenharmony_ci		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
313562306a36Sopenharmony_ci		set_host_byte(cmd, DID_ABORT);
313662306a36Sopenharmony_ci		return 1;
313762306a36Sopenharmony_ci	}
313862306a36Sopenharmony_ci
313962306a36Sopenharmony_ci	return 1;
314062306a36Sopenharmony_ci}
314162306a36Sopenharmony_ci
314262306a36Sopenharmony_cistatic void
314362306a36Sopenharmony_ciqla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
314462306a36Sopenharmony_ci				  struct req_que *req, uint32_t index)
314562306a36Sopenharmony_ci{
314662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
314762306a36Sopenharmony_ci	srb_t *sp;
314862306a36Sopenharmony_ci	uint16_t	comp_status;
314962306a36Sopenharmony_ci	uint16_t	scsi_status;
315062306a36Sopenharmony_ci	uint16_t thread_id;
315162306a36Sopenharmony_ci	uint32_t rval = EXT_STATUS_OK;
315262306a36Sopenharmony_ci	struct bsg_job *bsg_job = NULL;
315362306a36Sopenharmony_ci	struct fc_bsg_request *bsg_request;
315462306a36Sopenharmony_ci	struct fc_bsg_reply *bsg_reply;
315562306a36Sopenharmony_ci	sts_entry_t *sts = pkt;
315662306a36Sopenharmony_ci	struct sts_entry_24xx *sts24 = pkt;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_ci	/* Validate handle. */
315962306a36Sopenharmony_ci	if (index >= req->num_outstanding_cmds) {
316062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70af,
316162306a36Sopenharmony_ci		    "Invalid SCSI completion handle 0x%x.\n", index);
316262306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
316362306a36Sopenharmony_ci		return;
316462306a36Sopenharmony_ci	}
316562306a36Sopenharmony_ci
316662306a36Sopenharmony_ci	sp = req->outstanding_cmds[index];
316762306a36Sopenharmony_ci	if (!sp) {
316862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70b0,
316962306a36Sopenharmony_ci		    "Req:%d: Invalid ISP SCSI completion handle(0x%x)\n",
317062306a36Sopenharmony_ci		    req->id, index);
317162306a36Sopenharmony_ci
317262306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
317362306a36Sopenharmony_ci		return;
317462306a36Sopenharmony_ci	}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_ci	/* Free outstanding command slot. */
317762306a36Sopenharmony_ci	req->outstanding_cmds[index] = NULL;
317862306a36Sopenharmony_ci	bsg_job = sp->u.bsg_job;
317962306a36Sopenharmony_ci	bsg_request = bsg_job->request;
318062306a36Sopenharmony_ci	bsg_reply = bsg_job->reply;
318162306a36Sopenharmony_ci
318262306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
318362306a36Sopenharmony_ci		comp_status = le16_to_cpu(sts24->comp_status);
318462306a36Sopenharmony_ci		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
318562306a36Sopenharmony_ci	} else {
318662306a36Sopenharmony_ci		comp_status = le16_to_cpu(sts->comp_status);
318762306a36Sopenharmony_ci		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
318862306a36Sopenharmony_ci	}
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci	thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
319162306a36Sopenharmony_ci	switch (comp_status) {
319262306a36Sopenharmony_ci	case CS_COMPLETE:
319362306a36Sopenharmony_ci		if (scsi_status == 0) {
319462306a36Sopenharmony_ci			bsg_reply->reply_payload_rcv_len =
319562306a36Sopenharmony_ci					bsg_job->reply_payload.payload_len;
319662306a36Sopenharmony_ci			vha->qla_stats.input_bytes +=
319762306a36Sopenharmony_ci				bsg_reply->reply_payload_rcv_len;
319862306a36Sopenharmony_ci			vha->qla_stats.input_requests++;
319962306a36Sopenharmony_ci			rval = EXT_STATUS_OK;
320062306a36Sopenharmony_ci		}
320162306a36Sopenharmony_ci		goto done;
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci	case CS_DATA_OVERRUN:
320462306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b1,
320562306a36Sopenharmony_ci		    "Command completed with data overrun thread_id=%d\n",
320662306a36Sopenharmony_ci		    thread_id);
320762306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
320862306a36Sopenharmony_ci		break;
320962306a36Sopenharmony_ci
321062306a36Sopenharmony_ci	case CS_DATA_UNDERRUN:
321162306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b2,
321262306a36Sopenharmony_ci		    "Command completed with data underrun thread_id=%d\n",
321362306a36Sopenharmony_ci		    thread_id);
321462306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
321562306a36Sopenharmony_ci		break;
321662306a36Sopenharmony_ci	case CS_BIDIR_RD_OVERRUN:
321762306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b3,
321862306a36Sopenharmony_ci		    "Command completed with read data overrun thread_id=%d\n",
321962306a36Sopenharmony_ci		    thread_id);
322062306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
322162306a36Sopenharmony_ci		break;
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	case CS_BIDIR_RD_WR_OVERRUN:
322462306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b4,
322562306a36Sopenharmony_ci		    "Command completed with read and write data overrun "
322662306a36Sopenharmony_ci		    "thread_id=%d\n", thread_id);
322762306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
322862306a36Sopenharmony_ci		break;
322962306a36Sopenharmony_ci
323062306a36Sopenharmony_ci	case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN:
323162306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b5,
323262306a36Sopenharmony_ci		    "Command completed with read data over and write data "
323362306a36Sopenharmony_ci		    "underrun thread_id=%d\n", thread_id);
323462306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_OVERRUN;
323562306a36Sopenharmony_ci		break;
323662306a36Sopenharmony_ci
323762306a36Sopenharmony_ci	case CS_BIDIR_RD_UNDERRUN:
323862306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b6,
323962306a36Sopenharmony_ci		    "Command completed with read data underrun "
324062306a36Sopenharmony_ci		    "thread_id=%d\n", thread_id);
324162306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
324262306a36Sopenharmony_ci		break;
324362306a36Sopenharmony_ci
324462306a36Sopenharmony_ci	case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN:
324562306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b7,
324662306a36Sopenharmony_ci		    "Command completed with read data under and write data "
324762306a36Sopenharmony_ci		    "overrun thread_id=%d\n", thread_id);
324862306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
324962306a36Sopenharmony_ci		break;
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci	case CS_BIDIR_RD_WR_UNDERRUN:
325262306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b8,
325362306a36Sopenharmony_ci		    "Command completed with read and write data underrun "
325462306a36Sopenharmony_ci		    "thread_id=%d\n", thread_id);
325562306a36Sopenharmony_ci		rval = EXT_STATUS_DATA_UNDERRUN;
325662306a36Sopenharmony_ci		break;
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci	case CS_BIDIR_DMA:
325962306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70b9,
326062306a36Sopenharmony_ci		    "Command completed with data DMA error thread_id=%d\n",
326162306a36Sopenharmony_ci		    thread_id);
326262306a36Sopenharmony_ci		rval = EXT_STATUS_DMA_ERR;
326362306a36Sopenharmony_ci		break;
326462306a36Sopenharmony_ci
326562306a36Sopenharmony_ci	case CS_TIMEOUT:
326662306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70ba,
326762306a36Sopenharmony_ci		    "Command completed with timeout thread_id=%d\n",
326862306a36Sopenharmony_ci		    thread_id);
326962306a36Sopenharmony_ci		rval = EXT_STATUS_TIMEOUT;
327062306a36Sopenharmony_ci		break;
327162306a36Sopenharmony_ci	default:
327262306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70bb,
327362306a36Sopenharmony_ci		    "Command completed with completion status=0x%x "
327462306a36Sopenharmony_ci		    "thread_id=%d\n", comp_status, thread_id);
327562306a36Sopenharmony_ci		rval = EXT_STATUS_ERR;
327662306a36Sopenharmony_ci		break;
327762306a36Sopenharmony_ci	}
327862306a36Sopenharmony_ci	bsg_reply->reply_payload_rcv_len = 0;
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_cidone:
328162306a36Sopenharmony_ci	/* Return the vendor specific reply to API */
328262306a36Sopenharmony_ci	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
328362306a36Sopenharmony_ci	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
328462306a36Sopenharmony_ci	/* Always return DID_OK, bsg will send the vendor specific response
328562306a36Sopenharmony_ci	 * in this case only */
328662306a36Sopenharmony_ci	sp->done(sp, DID_OK << 16);
328762306a36Sopenharmony_ci
328862306a36Sopenharmony_ci}
328962306a36Sopenharmony_ci
329062306a36Sopenharmony_ci/**
329162306a36Sopenharmony_ci * qla2x00_status_entry() - Process a Status IOCB entry.
329262306a36Sopenharmony_ci * @vha: SCSI driver HA context
329362306a36Sopenharmony_ci * @rsp: response queue
329462306a36Sopenharmony_ci * @pkt: Entry pointer
329562306a36Sopenharmony_ci */
329662306a36Sopenharmony_cistatic void
329762306a36Sopenharmony_ciqla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
329862306a36Sopenharmony_ci{
329962306a36Sopenharmony_ci	srb_t		*sp;
330062306a36Sopenharmony_ci	fc_port_t	*fcport;
330162306a36Sopenharmony_ci	struct scsi_cmnd *cp;
330262306a36Sopenharmony_ci	sts_entry_t *sts = pkt;
330362306a36Sopenharmony_ci	struct sts_entry_24xx *sts24 = pkt;
330462306a36Sopenharmony_ci	uint16_t	comp_status;
330562306a36Sopenharmony_ci	uint16_t	scsi_status;
330662306a36Sopenharmony_ci	uint16_t	ox_id;
330762306a36Sopenharmony_ci	uint8_t		lscsi_status;
330862306a36Sopenharmony_ci	int32_t		resid;
330962306a36Sopenharmony_ci	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
331062306a36Sopenharmony_ci	    fw_resid_len;
331162306a36Sopenharmony_ci	uint8_t		*rsp_info, *sense_data;
331262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
331362306a36Sopenharmony_ci	uint32_t handle;
331462306a36Sopenharmony_ci	uint16_t que;
331562306a36Sopenharmony_ci	struct req_que *req;
331662306a36Sopenharmony_ci	int logit = 1;
331762306a36Sopenharmony_ci	int res = 0;
331862306a36Sopenharmony_ci	uint16_t state_flags = 0;
331962306a36Sopenharmony_ci	uint16_t sts_qual = 0;
332062306a36Sopenharmony_ci
332162306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
332262306a36Sopenharmony_ci		comp_status = le16_to_cpu(sts24->comp_status);
332362306a36Sopenharmony_ci		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
332462306a36Sopenharmony_ci		state_flags = le16_to_cpu(sts24->state_flags);
332562306a36Sopenharmony_ci	} else {
332662306a36Sopenharmony_ci		comp_status = le16_to_cpu(sts->comp_status);
332762306a36Sopenharmony_ci		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
332862306a36Sopenharmony_ci	}
332962306a36Sopenharmony_ci	handle = (uint32_t) LSW(sts->handle);
333062306a36Sopenharmony_ci	que = MSW(sts->handle);
333162306a36Sopenharmony_ci	req = ha->req_q_map[que];
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	/* Check for invalid queue pointer */
333462306a36Sopenharmony_ci	if (req == NULL ||
333562306a36Sopenharmony_ci	    que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
333662306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3059,
333762306a36Sopenharmony_ci		    "Invalid status handle (0x%x): Bad req pointer. req=%p, "
333862306a36Sopenharmony_ci		    "que=%u.\n", sts->handle, req, que);
333962306a36Sopenharmony_ci		return;
334062306a36Sopenharmony_ci	}
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	/* Validate handle. */
334362306a36Sopenharmony_ci	if (handle < req->num_outstanding_cmds) {
334462306a36Sopenharmony_ci		sp = req->outstanding_cmds[handle];
334562306a36Sopenharmony_ci		if (!sp) {
334662306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, vha, 0x3075,
334762306a36Sopenharmony_ci			    "%s(%ld): Already returned command for status handle (0x%x).\n",
334862306a36Sopenharmony_ci			    __func__, vha->host_no, sts->handle);
334962306a36Sopenharmony_ci			return;
335062306a36Sopenharmony_ci		}
335162306a36Sopenharmony_ci	} else {
335262306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3017,
335362306a36Sopenharmony_ci		    "Invalid status handle, out of range (0x%x).\n",
335462306a36Sopenharmony_ci		    sts->handle);
335562306a36Sopenharmony_ci
335662306a36Sopenharmony_ci		if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
335762306a36Sopenharmony_ci			if (IS_P3P_TYPE(ha))
335862306a36Sopenharmony_ci				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
335962306a36Sopenharmony_ci			else
336062306a36Sopenharmony_ci				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
336162306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
336262306a36Sopenharmony_ci		}
336362306a36Sopenharmony_ci		return;
336462306a36Sopenharmony_ci	}
336562306a36Sopenharmony_ci	qla_put_fw_resources(sp->qpair, &sp->iores);
336662306a36Sopenharmony_ci
336762306a36Sopenharmony_ci	if (sp->cmd_type != TYPE_SRB) {
336862306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
336962306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3015,
337062306a36Sopenharmony_ci		    "Unknown sp->cmd_type %x %p).\n",
337162306a36Sopenharmony_ci		    sp->cmd_type, sp);
337262306a36Sopenharmony_ci		return;
337362306a36Sopenharmony_ci	}
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	/* NVME completion. */
337662306a36Sopenharmony_ci	if (sp->type == SRB_NVME_CMD) {
337762306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
337862306a36Sopenharmony_ci		qla24xx_nvme_iocb_entry(vha, req, pkt, sp);
337962306a36Sopenharmony_ci		return;
338062306a36Sopenharmony_ci	}
338162306a36Sopenharmony_ci
338262306a36Sopenharmony_ci	if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) {
338362306a36Sopenharmony_ci		qla25xx_process_bidir_status_iocb(vha, pkt, req, handle);
338462306a36Sopenharmony_ci		return;
338562306a36Sopenharmony_ci	}
338662306a36Sopenharmony_ci
338762306a36Sopenharmony_ci	/* Task Management completion. */
338862306a36Sopenharmony_ci	if (sp->type == SRB_TM_CMD) {
338962306a36Sopenharmony_ci		qla24xx_tm_iocb_entry(vha, req, pkt);
339062306a36Sopenharmony_ci		return;
339162306a36Sopenharmony_ci	}
339262306a36Sopenharmony_ci
339362306a36Sopenharmony_ci	/* Fast path completion. */
339462306a36Sopenharmony_ci	qla_chk_edif_rx_sa_delete_pending(vha, sp, sts24);
339562306a36Sopenharmony_ci	sp->qpair->cmd_completion_cnt++;
339662306a36Sopenharmony_ci
339762306a36Sopenharmony_ci	if (comp_status == CS_COMPLETE && scsi_status == 0) {
339862306a36Sopenharmony_ci		qla2x00_process_completed_request(vha, req, handle);
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci		return;
340162306a36Sopenharmony_ci	}
340262306a36Sopenharmony_ci
340362306a36Sopenharmony_ci	cp = GET_CMD_SP(sp);
340462306a36Sopenharmony_ci	if (cp == NULL) {
340562306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, vha, 0x3018,
340662306a36Sopenharmony_ci		    "Command already returned (0x%x/%p).\n",
340762306a36Sopenharmony_ci		    sts->handle, sp);
340862306a36Sopenharmony_ci
340962306a36Sopenharmony_ci		req->outstanding_cmds[handle] = NULL;
341062306a36Sopenharmony_ci		return;
341162306a36Sopenharmony_ci	}
341262306a36Sopenharmony_ci
341362306a36Sopenharmony_ci	lscsi_status = scsi_status & STATUS_MASK;
341462306a36Sopenharmony_ci
341562306a36Sopenharmony_ci	fcport = sp->fcport;
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_ci	ox_id = 0;
341862306a36Sopenharmony_ci	sense_len = par_sense_len = rsp_info_len = resid_len =
341962306a36Sopenharmony_ci	    fw_resid_len = 0;
342062306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
342162306a36Sopenharmony_ci		if (scsi_status & SS_SENSE_LEN_VALID)
342262306a36Sopenharmony_ci			sense_len = le32_to_cpu(sts24->sense_len);
342362306a36Sopenharmony_ci		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
342462306a36Sopenharmony_ci			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
342562306a36Sopenharmony_ci		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
342662306a36Sopenharmony_ci			resid_len = le32_to_cpu(sts24->rsp_residual_count);
342762306a36Sopenharmony_ci		if (comp_status == CS_DATA_UNDERRUN)
342862306a36Sopenharmony_ci			fw_resid_len = le32_to_cpu(sts24->residual_len);
342962306a36Sopenharmony_ci		rsp_info = sts24->data;
343062306a36Sopenharmony_ci		sense_data = sts24->data;
343162306a36Sopenharmony_ci		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
343262306a36Sopenharmony_ci		ox_id = le16_to_cpu(sts24->ox_id);
343362306a36Sopenharmony_ci		par_sense_len = sizeof(sts24->data);
343462306a36Sopenharmony_ci		sts_qual = le16_to_cpu(sts24->status_qualifier);
343562306a36Sopenharmony_ci	} else {
343662306a36Sopenharmony_ci		if (scsi_status & SS_SENSE_LEN_VALID)
343762306a36Sopenharmony_ci			sense_len = le16_to_cpu(sts->req_sense_length);
343862306a36Sopenharmony_ci		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
343962306a36Sopenharmony_ci			rsp_info_len = le16_to_cpu(sts->rsp_info_len);
344062306a36Sopenharmony_ci		resid_len = le32_to_cpu(sts->residual_length);
344162306a36Sopenharmony_ci		rsp_info = sts->rsp_info;
344262306a36Sopenharmony_ci		sense_data = sts->req_sense_data;
344362306a36Sopenharmony_ci		par_sense_len = sizeof(sts->req_sense_data);
344462306a36Sopenharmony_ci	}
344562306a36Sopenharmony_ci
344662306a36Sopenharmony_ci	/* Check for any FCP transport errors. */
344762306a36Sopenharmony_ci	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
344862306a36Sopenharmony_ci		/* Sense data lies beyond any FCP RESPONSE data. */
344962306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(ha)) {
345062306a36Sopenharmony_ci			sense_data += rsp_info_len;
345162306a36Sopenharmony_ci			par_sense_len -= rsp_info_len;
345262306a36Sopenharmony_ci		}
345362306a36Sopenharmony_ci		if (rsp_info_len > 3 && rsp_info[3]) {
345462306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
345562306a36Sopenharmony_ci			    "FCP I/O protocol failure (0x%x/0x%x).\n",
345662306a36Sopenharmony_ci			    rsp_info_len, rsp_info[3]);
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci			res = DID_BUS_BUSY << 16;
345962306a36Sopenharmony_ci			goto out;
346062306a36Sopenharmony_ci		}
346162306a36Sopenharmony_ci	}
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	/* Check for overrun. */
346462306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
346562306a36Sopenharmony_ci	    scsi_status & SS_RESIDUAL_OVER)
346662306a36Sopenharmony_ci		comp_status = CS_DATA_OVERRUN;
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	/*
346962306a36Sopenharmony_ci	 * Check retry_delay_timer value if we receive a busy or
347062306a36Sopenharmony_ci	 * queue full.
347162306a36Sopenharmony_ci	 */
347262306a36Sopenharmony_ci	if (unlikely(lscsi_status == SAM_STAT_TASK_SET_FULL ||
347362306a36Sopenharmony_ci		     lscsi_status == SAM_STAT_BUSY))
347462306a36Sopenharmony_ci		qla2x00_set_retry_delay_timestamp(fcport, sts_qual);
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	/*
347762306a36Sopenharmony_ci	 * Based on Host and scsi status generate status code for Linux
347862306a36Sopenharmony_ci	 */
347962306a36Sopenharmony_ci	switch (comp_status) {
348062306a36Sopenharmony_ci	case CS_COMPLETE:
348162306a36Sopenharmony_ci	case CS_QUEUE_FULL:
348262306a36Sopenharmony_ci		if (scsi_status == 0) {
348362306a36Sopenharmony_ci			res = DID_OK << 16;
348462306a36Sopenharmony_ci			break;
348562306a36Sopenharmony_ci		}
348662306a36Sopenharmony_ci		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
348762306a36Sopenharmony_ci			resid = resid_len;
348862306a36Sopenharmony_ci			scsi_set_resid(cp, resid);
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci			if (!lscsi_status &&
349162306a36Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
349262306a36Sopenharmony_ci			     cp->underflow)) {
349362306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
349462306a36Sopenharmony_ci				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
349562306a36Sopenharmony_ci				    resid, scsi_bufflen(cp));
349662306a36Sopenharmony_ci
349762306a36Sopenharmony_ci				res = DID_ERROR << 16;
349862306a36Sopenharmony_ci				break;
349962306a36Sopenharmony_ci			}
350062306a36Sopenharmony_ci		}
350162306a36Sopenharmony_ci		res = DID_OK << 16 | lscsi_status;
350262306a36Sopenharmony_ci
350362306a36Sopenharmony_ci		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
350462306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
350562306a36Sopenharmony_ci			    "QUEUE FULL detected.\n");
350662306a36Sopenharmony_ci			break;
350762306a36Sopenharmony_ci		}
350862306a36Sopenharmony_ci		logit = 0;
350962306a36Sopenharmony_ci		if (lscsi_status != SS_CHECK_CONDITION)
351062306a36Sopenharmony_ci			break;
351162306a36Sopenharmony_ci
351262306a36Sopenharmony_ci		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
351362306a36Sopenharmony_ci		if (!(scsi_status & SS_SENSE_LEN_VALID))
351462306a36Sopenharmony_ci			break;
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_ci		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
351762306a36Sopenharmony_ci		    rsp, res);
351862306a36Sopenharmony_ci		break;
351962306a36Sopenharmony_ci
352062306a36Sopenharmony_ci	case CS_DATA_UNDERRUN:
352162306a36Sopenharmony_ci		/* Use F/W calculated residual length. */
352262306a36Sopenharmony_ci		resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
352362306a36Sopenharmony_ci		scsi_set_resid(cp, resid);
352462306a36Sopenharmony_ci		if (scsi_status & SS_RESIDUAL_UNDER) {
352562306a36Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
352662306a36Sopenharmony_ci				ql_log(ql_log_warn, fcport->vha, 0x301d,
352762306a36Sopenharmony_ci				       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
352862306a36Sopenharmony_ci				       resid, scsi_bufflen(cp));
352962306a36Sopenharmony_ci
353062306a36Sopenharmony_ci				res = DID_ERROR << 16 | lscsi_status;
353162306a36Sopenharmony_ci				goto check_scsi_status;
353262306a36Sopenharmony_ci			}
353362306a36Sopenharmony_ci
353462306a36Sopenharmony_ci			if (!lscsi_status &&
353562306a36Sopenharmony_ci			    ((unsigned)(scsi_bufflen(cp) - resid) <
353662306a36Sopenharmony_ci			    cp->underflow)) {
353762306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
353862306a36Sopenharmony_ci				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
353962306a36Sopenharmony_ci				    resid, scsi_bufflen(cp));
354062306a36Sopenharmony_ci
354162306a36Sopenharmony_ci				res = DID_ERROR << 16;
354262306a36Sopenharmony_ci				break;
354362306a36Sopenharmony_ci			}
354462306a36Sopenharmony_ci		} else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
354562306a36Sopenharmony_ci			    lscsi_status != SAM_STAT_BUSY) {
354662306a36Sopenharmony_ci			/*
354762306a36Sopenharmony_ci			 * scsi status of task set and busy are considered to be
354862306a36Sopenharmony_ci			 * task not completed.
354962306a36Sopenharmony_ci			 */
355062306a36Sopenharmony_ci
355162306a36Sopenharmony_ci			ql_log(ql_log_warn, fcport->vha, 0x301f,
355262306a36Sopenharmony_ci			       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
355362306a36Sopenharmony_ci			       resid, scsi_bufflen(cp));
355462306a36Sopenharmony_ci
355562306a36Sopenharmony_ci			vha->interface_err_cnt++;
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci			res = DID_ERROR << 16 | lscsi_status;
355862306a36Sopenharmony_ci			goto check_scsi_status;
355962306a36Sopenharmony_ci		} else {
356062306a36Sopenharmony_ci			ql_dbg(ql_dbg_io, fcport->vha, 0x3030,
356162306a36Sopenharmony_ci			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
356262306a36Sopenharmony_ci			    scsi_status, lscsi_status);
356362306a36Sopenharmony_ci		}
356462306a36Sopenharmony_ci
356562306a36Sopenharmony_ci		res = DID_OK << 16 | lscsi_status;
356662306a36Sopenharmony_ci		logit = 0;
356762306a36Sopenharmony_ci
356862306a36Sopenharmony_cicheck_scsi_status:
356962306a36Sopenharmony_ci		/*
357062306a36Sopenharmony_ci		 * Check to see if SCSI Status is non zero. If so report SCSI
357162306a36Sopenharmony_ci		 * Status.
357262306a36Sopenharmony_ci		 */
357362306a36Sopenharmony_ci		if (lscsi_status != 0) {
357462306a36Sopenharmony_ci			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
357562306a36Sopenharmony_ci				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
357662306a36Sopenharmony_ci				    "QUEUE FULL detected.\n");
357762306a36Sopenharmony_ci				logit = 1;
357862306a36Sopenharmony_ci				break;
357962306a36Sopenharmony_ci			}
358062306a36Sopenharmony_ci			if (lscsi_status != SS_CHECK_CONDITION)
358162306a36Sopenharmony_ci				break;
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
358462306a36Sopenharmony_ci			if (!(scsi_status & SS_SENSE_LEN_VALID))
358562306a36Sopenharmony_ci				break;
358662306a36Sopenharmony_ci
358762306a36Sopenharmony_ci			qla2x00_handle_sense(sp, sense_data, par_sense_len,
358862306a36Sopenharmony_ci			    sense_len, rsp, res);
358962306a36Sopenharmony_ci		}
359062306a36Sopenharmony_ci		break;
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_ci	case CS_PORT_LOGGED_OUT:
359362306a36Sopenharmony_ci	case CS_PORT_CONFIG_CHG:
359462306a36Sopenharmony_ci	case CS_PORT_BUSY:
359562306a36Sopenharmony_ci	case CS_INCOMPLETE:
359662306a36Sopenharmony_ci	case CS_PORT_UNAVAILABLE:
359762306a36Sopenharmony_ci	case CS_TIMEOUT:
359862306a36Sopenharmony_ci	case CS_RESET:
359962306a36Sopenharmony_ci	case CS_EDIF_INV_REQ:
360062306a36Sopenharmony_ci
360162306a36Sopenharmony_ci		/*
360262306a36Sopenharmony_ci		 * We are going to have the fc class block the rport
360362306a36Sopenharmony_ci		 * while we try to recover so instruct the mid layer
360462306a36Sopenharmony_ci		 * to requeue until the class decides how to handle this.
360562306a36Sopenharmony_ci		 */
360662306a36Sopenharmony_ci		res = DID_TRANSPORT_DISRUPTED << 16;
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci		if (comp_status == CS_TIMEOUT) {
360962306a36Sopenharmony_ci			if (IS_FWI2_CAPABLE(ha))
361062306a36Sopenharmony_ci				break;
361162306a36Sopenharmony_ci			else if ((le16_to_cpu(sts->status_flags) &
361262306a36Sopenharmony_ci			    SF_LOGOUT_SENT) == 0)
361362306a36Sopenharmony_ci				break;
361462306a36Sopenharmony_ci		}
361562306a36Sopenharmony_ci
361662306a36Sopenharmony_ci		if (atomic_read(&fcport->state) == FCS_ONLINE) {
361762306a36Sopenharmony_ci			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
361862306a36Sopenharmony_ci				"Port to be marked lost on fcport=%02x%02x%02x, current "
361962306a36Sopenharmony_ci				"port state= %s comp_status %x.\n", fcport->d_id.b.domain,
362062306a36Sopenharmony_ci				fcport->d_id.b.area, fcport->d_id.b.al_pa,
362162306a36Sopenharmony_ci				port_state_str[FCS_ONLINE],
362262306a36Sopenharmony_ci				comp_status);
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci			qlt_schedule_sess_for_deletion(fcport);
362562306a36Sopenharmony_ci		}
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci		break;
362862306a36Sopenharmony_ci
362962306a36Sopenharmony_ci	case CS_ABORTED:
363062306a36Sopenharmony_ci		res = DID_RESET << 16;
363162306a36Sopenharmony_ci		break;
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci	case CS_DIF_ERROR:
363462306a36Sopenharmony_ci		logit = qla2x00_handle_dif_error(sp, sts24);
363562306a36Sopenharmony_ci		res = cp->result;
363662306a36Sopenharmony_ci		break;
363762306a36Sopenharmony_ci
363862306a36Sopenharmony_ci	case CS_TRANSPORT:
363962306a36Sopenharmony_ci		res = DID_ERROR << 16;
364062306a36Sopenharmony_ci		vha->hw_err_cnt++;
364162306a36Sopenharmony_ci
364262306a36Sopenharmony_ci		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
364362306a36Sopenharmony_ci			break;
364462306a36Sopenharmony_ci
364562306a36Sopenharmony_ci		if (state_flags & BIT_4)
364662306a36Sopenharmony_ci			scmd_printk(KERN_WARNING, cp,
364762306a36Sopenharmony_ci			    "Unsupported device '%s' found.\n",
364862306a36Sopenharmony_ci			    cp->device->vendor);
364962306a36Sopenharmony_ci		break;
365062306a36Sopenharmony_ci
365162306a36Sopenharmony_ci	case CS_DMA:
365262306a36Sopenharmony_ci		ql_log(ql_log_info, fcport->vha, 0x3022,
365362306a36Sopenharmony_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",
365462306a36Sopenharmony_ci		    comp_status, scsi_status, res, vha->host_no,
365562306a36Sopenharmony_ci		    cp->device->id, cp->device->lun, fcport->d_id.b24,
365662306a36Sopenharmony_ci		    ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len,
365762306a36Sopenharmony_ci		    resid_len, fw_resid_len, sp, cp);
365862306a36Sopenharmony_ci		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
365962306a36Sopenharmony_ci		    pkt, sizeof(*sts24));
366062306a36Sopenharmony_ci		res = DID_ERROR << 16;
366162306a36Sopenharmony_ci		vha->hw_err_cnt++;
366262306a36Sopenharmony_ci		break;
366362306a36Sopenharmony_ci	default:
366462306a36Sopenharmony_ci		res = DID_ERROR << 16;
366562306a36Sopenharmony_ci		break;
366662306a36Sopenharmony_ci	}
366762306a36Sopenharmony_ci
366862306a36Sopenharmony_ciout:
366962306a36Sopenharmony_ci	if (logit)
367062306a36Sopenharmony_ci		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
367162306a36Sopenharmony_ci		       "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
367262306a36Sopenharmony_ci		       comp_status, scsi_status, res, vha->host_no,
367362306a36Sopenharmony_ci		       cp->device->id, cp->device->lun, fcport->d_id.b.domain,
367462306a36Sopenharmony_ci		       fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
367562306a36Sopenharmony_ci		       cp->cmnd, scsi_bufflen(cp), rsp_info_len,
367662306a36Sopenharmony_ci		       resid_len, fw_resid_len, sp, cp);
367762306a36Sopenharmony_ci
367862306a36Sopenharmony_ci	if (rsp->status_srb == NULL)
367962306a36Sopenharmony_ci		sp->done(sp, res);
368062306a36Sopenharmony_ci
368162306a36Sopenharmony_ci	/* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */
368262306a36Sopenharmony_ci	req->outstanding_cmds[handle] = NULL;
368362306a36Sopenharmony_ci}
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci/**
368662306a36Sopenharmony_ci * qla2x00_status_cont_entry() - Process a Status Continuations entry.
368762306a36Sopenharmony_ci * @rsp: response queue
368862306a36Sopenharmony_ci * @pkt: Entry pointer
368962306a36Sopenharmony_ci *
369062306a36Sopenharmony_ci * Extended sense data.
369162306a36Sopenharmony_ci */
369262306a36Sopenharmony_cistatic void
369362306a36Sopenharmony_ciqla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
369462306a36Sopenharmony_ci{
369562306a36Sopenharmony_ci	uint8_t	sense_sz = 0;
369662306a36Sopenharmony_ci	struct qla_hw_data *ha = rsp->hw;
369762306a36Sopenharmony_ci	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
369862306a36Sopenharmony_ci	srb_t *sp = rsp->status_srb;
369962306a36Sopenharmony_ci	struct scsi_cmnd *cp;
370062306a36Sopenharmony_ci	uint32_t sense_len;
370162306a36Sopenharmony_ci	uint8_t *sense_ptr;
370262306a36Sopenharmony_ci
370362306a36Sopenharmony_ci	if (!sp || !GET_CMD_SENSE_LEN(sp))
370462306a36Sopenharmony_ci		return;
370562306a36Sopenharmony_ci
370662306a36Sopenharmony_ci	sense_len = GET_CMD_SENSE_LEN(sp);
370762306a36Sopenharmony_ci	sense_ptr = GET_CMD_SENSE_PTR(sp);
370862306a36Sopenharmony_ci
370962306a36Sopenharmony_ci	cp = GET_CMD_SP(sp);
371062306a36Sopenharmony_ci	if (cp == NULL) {
371162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x3025,
371262306a36Sopenharmony_ci		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
371362306a36Sopenharmony_ci
371462306a36Sopenharmony_ci		rsp->status_srb = NULL;
371562306a36Sopenharmony_ci		return;
371662306a36Sopenharmony_ci	}
371762306a36Sopenharmony_ci
371862306a36Sopenharmony_ci	if (sense_len > sizeof(pkt->data))
371962306a36Sopenharmony_ci		sense_sz = sizeof(pkt->data);
372062306a36Sopenharmony_ci	else
372162306a36Sopenharmony_ci		sense_sz = sense_len;
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	/* Move sense data. */
372462306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha))
372562306a36Sopenharmony_ci		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
372662306a36Sopenharmony_ci	memcpy(sense_ptr, pkt->data, sense_sz);
372762306a36Sopenharmony_ci	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
372862306a36Sopenharmony_ci		sense_ptr, sense_sz);
372962306a36Sopenharmony_ci
373062306a36Sopenharmony_ci	sense_len -= sense_sz;
373162306a36Sopenharmony_ci	sense_ptr += sense_sz;
373262306a36Sopenharmony_ci
373362306a36Sopenharmony_ci	SET_CMD_SENSE_PTR(sp, sense_ptr);
373462306a36Sopenharmony_ci	SET_CMD_SENSE_LEN(sp, sense_len);
373562306a36Sopenharmony_ci
373662306a36Sopenharmony_ci	/* Place command on done queue. */
373762306a36Sopenharmony_ci	if (sense_len == 0) {
373862306a36Sopenharmony_ci		rsp->status_srb = NULL;
373962306a36Sopenharmony_ci		sp->done(sp, cp->result);
374062306a36Sopenharmony_ci	}
374162306a36Sopenharmony_ci}
374262306a36Sopenharmony_ci
374362306a36Sopenharmony_ci/**
374462306a36Sopenharmony_ci * qla2x00_error_entry() - Process an error entry.
374562306a36Sopenharmony_ci * @vha: SCSI driver HA context
374662306a36Sopenharmony_ci * @rsp: response queue
374762306a36Sopenharmony_ci * @pkt: Entry pointer
374862306a36Sopenharmony_ci * return : 1=allow further error analysis. 0=no additional error analysis.
374962306a36Sopenharmony_ci */
375062306a36Sopenharmony_cistatic int
375162306a36Sopenharmony_ciqla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
375262306a36Sopenharmony_ci{
375362306a36Sopenharmony_ci	srb_t *sp;
375462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
375562306a36Sopenharmony_ci	const char func[] = "ERROR-IOCB";
375662306a36Sopenharmony_ci	uint16_t que = MSW(pkt->handle);
375762306a36Sopenharmony_ci	struct req_que *req = NULL;
375862306a36Sopenharmony_ci	int res = DID_ERROR << 16;
375962306a36Sopenharmony_ci	u16 index;
376062306a36Sopenharmony_ci
376162306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, vha, 0x502a,
376262306a36Sopenharmony_ci	    "iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
376362306a36Sopenharmony_ci	    pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id);
376462306a36Sopenharmony_ci
376562306a36Sopenharmony_ci	if (que >= ha->max_req_queues || !ha->req_q_map[que])
376662306a36Sopenharmony_ci		goto fatal;
376762306a36Sopenharmony_ci
376862306a36Sopenharmony_ci	req = ha->req_q_map[que];
376962306a36Sopenharmony_ci
377062306a36Sopenharmony_ci	if (pkt->entry_status & RF_BUSY)
377162306a36Sopenharmony_ci		res = DID_BUS_BUSY << 16;
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE)
377462306a36Sopenharmony_ci		return 0;
377562306a36Sopenharmony_ci
377662306a36Sopenharmony_ci	switch (pkt->entry_type) {
377762306a36Sopenharmony_ci	case NOTIFY_ACK_TYPE:
377862306a36Sopenharmony_ci	case STATUS_CONT_TYPE:
377962306a36Sopenharmony_ci	case LOGINOUT_PORT_IOCB_TYPE:
378062306a36Sopenharmony_ci	case CT_IOCB_TYPE:
378162306a36Sopenharmony_ci	case ELS_IOCB_TYPE:
378262306a36Sopenharmony_ci	case ABORT_IOCB_TYPE:
378362306a36Sopenharmony_ci	case MBX_IOCB_TYPE:
378462306a36Sopenharmony_ci	default:
378562306a36Sopenharmony_ci		sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
378662306a36Sopenharmony_ci		if (sp) {
378762306a36Sopenharmony_ci			sp->done(sp, res);
378862306a36Sopenharmony_ci			return 0;
378962306a36Sopenharmony_ci		}
379062306a36Sopenharmony_ci		break;
379162306a36Sopenharmony_ci
379262306a36Sopenharmony_ci	case SA_UPDATE_IOCB_TYPE:
379362306a36Sopenharmony_ci	case ABTS_RESP_24XX:
379462306a36Sopenharmony_ci	case CTIO_TYPE7:
379562306a36Sopenharmony_ci	case CTIO_CRC2:
379662306a36Sopenharmony_ci		return 1;
379762306a36Sopenharmony_ci	case STATUS_TYPE:
379862306a36Sopenharmony_ci		sp = qla_get_sp_from_handle(vha, func, req, pkt, &index);
379962306a36Sopenharmony_ci		if (sp) {
380062306a36Sopenharmony_ci			sp->done(sp, res);
380162306a36Sopenharmony_ci			req->outstanding_cmds[index] = NULL;
380262306a36Sopenharmony_ci			return 0;
380362306a36Sopenharmony_ci		}
380462306a36Sopenharmony_ci		break;
380562306a36Sopenharmony_ci	}
380662306a36Sopenharmony_cifatal:
380762306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x5030,
380862306a36Sopenharmony_ci	    "Error entry - invalid handle/queue (%04x).\n", que);
380962306a36Sopenharmony_ci	return 0;
381062306a36Sopenharmony_ci}
381162306a36Sopenharmony_ci
381262306a36Sopenharmony_ci/**
381362306a36Sopenharmony_ci * qla24xx_mbx_completion() - Process mailbox command completions.
381462306a36Sopenharmony_ci * @vha: SCSI driver HA context
381562306a36Sopenharmony_ci * @mb0: Mailbox0 register
381662306a36Sopenharmony_ci */
381762306a36Sopenharmony_cistatic void
381862306a36Sopenharmony_ciqla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
381962306a36Sopenharmony_ci{
382062306a36Sopenharmony_ci	uint16_t	cnt;
382162306a36Sopenharmony_ci	uint32_t	mboxes;
382262306a36Sopenharmony_ci	__le16 __iomem *wptr;
382362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
382462306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci	/* Read all mbox registers? */
382762306a36Sopenharmony_ci	WARN_ON_ONCE(ha->mbx_count > 32);
382862306a36Sopenharmony_ci	mboxes = (1ULL << ha->mbx_count) - 1;
382962306a36Sopenharmony_ci	if (!ha->mcp)
383062306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
383162306a36Sopenharmony_ci	else
383262306a36Sopenharmony_ci		mboxes = ha->mcp->in_mb;
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	/* Load return mailbox registers. */
383562306a36Sopenharmony_ci	ha->flags.mbox_int = 1;
383662306a36Sopenharmony_ci	ha->mailbox_out[0] = mb0;
383762306a36Sopenharmony_ci	mboxes >>= 1;
383862306a36Sopenharmony_ci	wptr = &reg->mailbox1;
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
384162306a36Sopenharmony_ci		if (mboxes & BIT_0)
384262306a36Sopenharmony_ci			ha->mailbox_out[cnt] = rd_reg_word(wptr);
384362306a36Sopenharmony_ci
384462306a36Sopenharmony_ci		mboxes >>= 1;
384562306a36Sopenharmony_ci		wptr++;
384662306a36Sopenharmony_ci	}
384762306a36Sopenharmony_ci}
384862306a36Sopenharmony_ci
384962306a36Sopenharmony_cistatic void
385062306a36Sopenharmony_ciqla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
385162306a36Sopenharmony_ci	struct abort_entry_24xx *pkt)
385262306a36Sopenharmony_ci{
385362306a36Sopenharmony_ci	const char func[] = "ABT_IOCB";
385462306a36Sopenharmony_ci	srb_t *sp;
385562306a36Sopenharmony_ci	srb_t *orig_sp = NULL;
385662306a36Sopenharmony_ci	struct srb_iocb *abt;
385762306a36Sopenharmony_ci
385862306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
385962306a36Sopenharmony_ci	if (!sp)
386062306a36Sopenharmony_ci		return;
386162306a36Sopenharmony_ci
386262306a36Sopenharmony_ci	abt = &sp->u.iocb_cmd;
386362306a36Sopenharmony_ci	abt->u.abt.comp_status = pkt->comp_status;
386462306a36Sopenharmony_ci	orig_sp = sp->cmd_sp;
386562306a36Sopenharmony_ci	/* Need to pass original sp */
386662306a36Sopenharmony_ci	if (orig_sp)
386762306a36Sopenharmony_ci		qla_nvme_abort_process_comp_status(pkt, orig_sp);
386862306a36Sopenharmony_ci
386962306a36Sopenharmony_ci	sp->done(sp, 0);
387062306a36Sopenharmony_ci}
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_civoid qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
387362306a36Sopenharmony_ci    struct pt_ls4_request *pkt, struct req_que *req)
387462306a36Sopenharmony_ci{
387562306a36Sopenharmony_ci	srb_t *sp;
387662306a36Sopenharmony_ci	const char func[] = "LS4_IOCB";
387762306a36Sopenharmony_ci	uint16_t comp_status;
387862306a36Sopenharmony_ci
387962306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
388062306a36Sopenharmony_ci	if (!sp)
388162306a36Sopenharmony_ci		return;
388262306a36Sopenharmony_ci
388362306a36Sopenharmony_ci	comp_status = le16_to_cpu(pkt->status);
388462306a36Sopenharmony_ci	sp->done(sp, comp_status);
388562306a36Sopenharmony_ci}
388662306a36Sopenharmony_ci
388762306a36Sopenharmony_ci/**
388862306a36Sopenharmony_ci * qla_chk_cont_iocb_avail - check for all continuation iocbs are available
388962306a36Sopenharmony_ci *   before iocb processing can start.
389062306a36Sopenharmony_ci * @vha: host adapter pointer
389162306a36Sopenharmony_ci * @rsp: respond queue
389262306a36Sopenharmony_ci * @pkt: head iocb describing how many continuation iocb
389362306a36Sopenharmony_ci * Return: 0 all iocbs has arrived, xx- all iocbs have not arrived.
389462306a36Sopenharmony_ci */
389562306a36Sopenharmony_cistatic int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
389662306a36Sopenharmony_ci	struct rsp_que *rsp, response_t *pkt, u32 rsp_q_in)
389762306a36Sopenharmony_ci{
389862306a36Sopenharmony_ci	int start_pkt_ring_index;
389962306a36Sopenharmony_ci	u32 iocb_cnt = 0;
390062306a36Sopenharmony_ci	int rc = 0;
390162306a36Sopenharmony_ci
390262306a36Sopenharmony_ci	if (pkt->entry_count == 1)
390362306a36Sopenharmony_ci		return rc;
390462306a36Sopenharmony_ci
390562306a36Sopenharmony_ci	/* ring_index was pre-increment. set it back to current pkt */
390662306a36Sopenharmony_ci	if (rsp->ring_index == 0)
390762306a36Sopenharmony_ci		start_pkt_ring_index = rsp->length - 1;
390862306a36Sopenharmony_ci	else
390962306a36Sopenharmony_ci		start_pkt_ring_index = rsp->ring_index - 1;
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	if (rsp_q_in < start_pkt_ring_index)
391262306a36Sopenharmony_ci		/* q in ptr is wrapped */
391362306a36Sopenharmony_ci		iocb_cnt = rsp->length - start_pkt_ring_index + rsp_q_in;
391462306a36Sopenharmony_ci	else
391562306a36Sopenharmony_ci		iocb_cnt = rsp_q_in - start_pkt_ring_index;
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_ci	if (iocb_cnt < pkt->entry_count)
391862306a36Sopenharmony_ci		rc = -EIO;
391962306a36Sopenharmony_ci
392062306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x5091,
392162306a36Sopenharmony_ci	       "%s - ring %p pkt %p entry count %d iocb_cnt %d rsp_q_in %d rc %d\n",
392262306a36Sopenharmony_ci	       __func__, rsp->ring, pkt, pkt->entry_count, iocb_cnt, rsp_q_in, rc);
392362306a36Sopenharmony_ci
392462306a36Sopenharmony_ci	return rc;
392562306a36Sopenharmony_ci}
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_cistatic void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
392862306a36Sopenharmony_ci	struct mrk_entry_24xx *pkt)
392962306a36Sopenharmony_ci{
393062306a36Sopenharmony_ci	const char func[] = "MRK-IOCB";
393162306a36Sopenharmony_ci	srb_t *sp;
393262306a36Sopenharmony_ci	int res = QLA_SUCCESS;
393362306a36Sopenharmony_ci
393462306a36Sopenharmony_ci	if (!IS_FWI2_CAPABLE(vha->hw))
393562306a36Sopenharmony_ci		return;
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
393862306a36Sopenharmony_ci	if (!sp)
393962306a36Sopenharmony_ci		return;
394062306a36Sopenharmony_ci
394162306a36Sopenharmony_ci	if (pkt->entry_status) {
394262306a36Sopenharmony_ci		ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
394362306a36Sopenharmony_ci		res = QLA_COMMAND_ERROR;
394462306a36Sopenharmony_ci	}
394562306a36Sopenharmony_ci	sp->u.iocb_cmd.u.tmf.data = res;
394662306a36Sopenharmony_ci	sp->done(sp, res);
394762306a36Sopenharmony_ci}
394862306a36Sopenharmony_ci
394962306a36Sopenharmony_ci/**
395062306a36Sopenharmony_ci * qla24xx_process_response_queue() - Process response queue entries.
395162306a36Sopenharmony_ci * @vha: SCSI driver HA context
395262306a36Sopenharmony_ci * @rsp: response queue
395362306a36Sopenharmony_ci */
395462306a36Sopenharmony_civoid qla24xx_process_response_queue(struct scsi_qla_host *vha,
395562306a36Sopenharmony_ci	struct rsp_que *rsp)
395662306a36Sopenharmony_ci{
395762306a36Sopenharmony_ci	struct sts_entry_24xx *pkt;
395862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
395962306a36Sopenharmony_ci	struct purex_entry_24xx *purex_entry;
396062306a36Sopenharmony_ci	struct purex_item *pure_item;
396162306a36Sopenharmony_ci	struct pt_ls4_rx_unsol *p;
396262306a36Sopenharmony_ci	u16 rsp_in = 0, cur_ring_index;
396362306a36Sopenharmony_ci	int is_shadow_hba;
396462306a36Sopenharmony_ci
396562306a36Sopenharmony_ci	if (!ha->flags.fw_started)
396662306a36Sopenharmony_ci		return;
396762306a36Sopenharmony_ci
396862306a36Sopenharmony_ci	if (rsp->qpair->cpuid != raw_smp_processor_id() || !rsp->qpair->rcv_intr) {
396962306a36Sopenharmony_ci		rsp->qpair->rcv_intr = 1;
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci		if (!rsp->qpair->cpu_mapped)
397262306a36Sopenharmony_ci			qla_cpu_update(rsp->qpair, raw_smp_processor_id());
397362306a36Sopenharmony_ci	}
397462306a36Sopenharmony_ci
397562306a36Sopenharmony_ci#define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in)			\
397662306a36Sopenharmony_ci	do {								\
397762306a36Sopenharmony_ci		_rsp_in = _is_shadow_hba ? *(_rsp)->in_ptr :		\
397862306a36Sopenharmony_ci				rd_reg_dword_relaxed((_rsp)->rsp_q_in);	\
397962306a36Sopenharmony_ci	} while (0)
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	is_shadow_hba = IS_SHADOW_REG_CAPABLE(ha);
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci	__update_rsp_in(is_shadow_hba, rsp, rsp_in);
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_ci	while (rsp->ring_index != rsp_in &&
398662306a36Sopenharmony_ci		       rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
398762306a36Sopenharmony_ci		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
398862306a36Sopenharmony_ci		cur_ring_index = rsp->ring_index;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci		rsp->ring_index++;
399162306a36Sopenharmony_ci		if (rsp->ring_index == rsp->length) {
399262306a36Sopenharmony_ci			rsp->ring_index = 0;
399362306a36Sopenharmony_ci			rsp->ring_ptr = rsp->ring;
399462306a36Sopenharmony_ci		} else {
399562306a36Sopenharmony_ci			rsp->ring_ptr++;
399662306a36Sopenharmony_ci		}
399762306a36Sopenharmony_ci
399862306a36Sopenharmony_ci		if (pkt->entry_status != 0) {
399962306a36Sopenharmony_ci			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
400062306a36Sopenharmony_ci				goto process_err;
400162306a36Sopenharmony_ci
400262306a36Sopenharmony_ci			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
400362306a36Sopenharmony_ci			wmb();
400462306a36Sopenharmony_ci			continue;
400562306a36Sopenharmony_ci		}
400662306a36Sopenharmony_ciprocess_err:
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_ci		switch (pkt->entry_type) {
400962306a36Sopenharmony_ci		case STATUS_TYPE:
401062306a36Sopenharmony_ci			qla2x00_status_entry(vha, rsp, pkt);
401162306a36Sopenharmony_ci			break;
401262306a36Sopenharmony_ci		case STATUS_CONT_TYPE:
401362306a36Sopenharmony_ci			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
401462306a36Sopenharmony_ci			break;
401562306a36Sopenharmony_ci		case VP_RPT_ID_IOCB_TYPE:
401662306a36Sopenharmony_ci			qla24xx_report_id_acquisition(vha,
401762306a36Sopenharmony_ci			    (struct vp_rpt_id_entry_24xx *)pkt);
401862306a36Sopenharmony_ci			break;
401962306a36Sopenharmony_ci		case LOGINOUT_PORT_IOCB_TYPE:
402062306a36Sopenharmony_ci			qla24xx_logio_entry(vha, rsp->req,
402162306a36Sopenharmony_ci			    (struct logio_entry_24xx *)pkt);
402262306a36Sopenharmony_ci			break;
402362306a36Sopenharmony_ci		case CT_IOCB_TYPE:
402462306a36Sopenharmony_ci			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
402562306a36Sopenharmony_ci			break;
402662306a36Sopenharmony_ci		case ELS_IOCB_TYPE:
402762306a36Sopenharmony_ci			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
402862306a36Sopenharmony_ci			break;
402962306a36Sopenharmony_ci		case ABTS_RECV_24XX:
403062306a36Sopenharmony_ci			if (qla_ini_mode_enabled(vha)) {
403162306a36Sopenharmony_ci				pure_item = qla24xx_copy_std_pkt(vha, pkt);
403262306a36Sopenharmony_ci				if (!pure_item)
403362306a36Sopenharmony_ci					break;
403462306a36Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
403562306a36Sopenharmony_ci							 qla24xx_process_abts);
403662306a36Sopenharmony_ci				break;
403762306a36Sopenharmony_ci			}
403862306a36Sopenharmony_ci			if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
403962306a36Sopenharmony_ci			    IS_QLA28XX(ha)) {
404062306a36Sopenharmony_ci				/* ensure that the ATIO queue is empty */
404162306a36Sopenharmony_ci				qlt_handle_abts_recv(vha, rsp,
404262306a36Sopenharmony_ci				    (response_t *)pkt);
404362306a36Sopenharmony_ci				break;
404462306a36Sopenharmony_ci			} else {
404562306a36Sopenharmony_ci				qlt_24xx_process_atio_queue(vha, 1);
404662306a36Sopenharmony_ci			}
404762306a36Sopenharmony_ci			fallthrough;
404862306a36Sopenharmony_ci		case ABTS_RESP_24XX:
404962306a36Sopenharmony_ci		case CTIO_TYPE7:
405062306a36Sopenharmony_ci		case CTIO_CRC2:
405162306a36Sopenharmony_ci			qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt);
405262306a36Sopenharmony_ci			break;
405362306a36Sopenharmony_ci		case PT_LS4_REQUEST:
405462306a36Sopenharmony_ci			qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt,
405562306a36Sopenharmony_ci			    rsp->req);
405662306a36Sopenharmony_ci			break;
405762306a36Sopenharmony_ci		case NOTIFY_ACK_TYPE:
405862306a36Sopenharmony_ci			if (pkt->handle == QLA_TGT_SKIP_HANDLE)
405962306a36Sopenharmony_ci				qlt_response_pkt_all_vps(vha, rsp,
406062306a36Sopenharmony_ci				    (response_t *)pkt);
406162306a36Sopenharmony_ci			else
406262306a36Sopenharmony_ci				qla24xxx_nack_iocb_entry(vha, rsp->req,
406362306a36Sopenharmony_ci					(struct nack_to_isp *)pkt);
406462306a36Sopenharmony_ci			break;
406562306a36Sopenharmony_ci		case MARKER_TYPE:
406662306a36Sopenharmony_ci			qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
406762306a36Sopenharmony_ci			break;
406862306a36Sopenharmony_ci		case ABORT_IOCB_TYPE:
406962306a36Sopenharmony_ci			qla24xx_abort_iocb_entry(vha, rsp->req,
407062306a36Sopenharmony_ci			    (struct abort_entry_24xx *)pkt);
407162306a36Sopenharmony_ci			break;
407262306a36Sopenharmony_ci		case MBX_IOCB_TYPE:
407362306a36Sopenharmony_ci			qla24xx_mbx_iocb_entry(vha, rsp->req,
407462306a36Sopenharmony_ci			    (struct mbx_24xx_entry *)pkt);
407562306a36Sopenharmony_ci			break;
407662306a36Sopenharmony_ci		case VP_CTRL_IOCB_TYPE:
407762306a36Sopenharmony_ci			qla_ctrlvp_completed(vha, rsp->req,
407862306a36Sopenharmony_ci			    (struct vp_ctrl_entry_24xx *)pkt);
407962306a36Sopenharmony_ci			break;
408062306a36Sopenharmony_ci		case PUREX_IOCB_TYPE:
408162306a36Sopenharmony_ci			purex_entry = (void *)pkt;
408262306a36Sopenharmony_ci			switch (purex_entry->els_frame_payload[3]) {
408362306a36Sopenharmony_ci			case ELS_RDP:
408462306a36Sopenharmony_ci				pure_item = qla24xx_copy_std_pkt(vha, pkt);
408562306a36Sopenharmony_ci				if (!pure_item)
408662306a36Sopenharmony_ci					break;
408762306a36Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
408862306a36Sopenharmony_ci						 qla24xx_process_purex_rdp);
408962306a36Sopenharmony_ci				break;
409062306a36Sopenharmony_ci			case ELS_FPIN:
409162306a36Sopenharmony_ci				if (!vha->hw->flags.scm_enabled) {
409262306a36Sopenharmony_ci					ql_log(ql_log_warn, vha, 0x5094,
409362306a36Sopenharmony_ci					       "SCM not active for this port\n");
409462306a36Sopenharmony_ci					break;
409562306a36Sopenharmony_ci				}
409662306a36Sopenharmony_ci				pure_item = qla27xx_copy_fpin_pkt(vha,
409762306a36Sopenharmony_ci							  (void **)&pkt, &rsp);
409862306a36Sopenharmony_ci				__update_rsp_in(is_shadow_hba, rsp, rsp_in);
409962306a36Sopenharmony_ci				if (!pure_item)
410062306a36Sopenharmony_ci					break;
410162306a36Sopenharmony_ci				qla24xx_queue_purex_item(vha, pure_item,
410262306a36Sopenharmony_ci						 qla27xx_process_purex_fpin);
410362306a36Sopenharmony_ci				break;
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ci			case ELS_AUTH_ELS:
410662306a36Sopenharmony_ci				if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
410762306a36Sopenharmony_ci					/*
410862306a36Sopenharmony_ci					 * ring_ptr and ring_index were
410962306a36Sopenharmony_ci					 * pre-incremented above. Reset them
411062306a36Sopenharmony_ci					 * back to current. Wait for next
411162306a36Sopenharmony_ci					 * interrupt with all IOCBs to arrive
411262306a36Sopenharmony_ci					 * and re-process.
411362306a36Sopenharmony_ci					 */
411462306a36Sopenharmony_ci					rsp->ring_ptr = (response_t *)pkt;
411562306a36Sopenharmony_ci					rsp->ring_index = cur_ring_index;
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ci					ql_dbg(ql_dbg_init, vha, 0x5091,
411862306a36Sopenharmony_ci					    "Defer processing ELS opcode %#x...\n",
411962306a36Sopenharmony_ci					    purex_entry->els_frame_payload[3]);
412062306a36Sopenharmony_ci					return;
412162306a36Sopenharmony_ci				}
412262306a36Sopenharmony_ci				qla24xx_auth_els(vha, (void **)&pkt, &rsp);
412362306a36Sopenharmony_ci				break;
412462306a36Sopenharmony_ci			default:
412562306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x509c,
412662306a36Sopenharmony_ci				       "Discarding ELS Request opcode 0x%x\n",
412762306a36Sopenharmony_ci				       purex_entry->els_frame_payload[3]);
412862306a36Sopenharmony_ci			}
412962306a36Sopenharmony_ci			break;
413062306a36Sopenharmony_ci		case SA_UPDATE_IOCB_TYPE:
413162306a36Sopenharmony_ci			qla28xx_sa_update_iocb_entry(vha, rsp->req,
413262306a36Sopenharmony_ci				(struct sa_update_28xx *)pkt);
413362306a36Sopenharmony_ci			break;
413462306a36Sopenharmony_ci		case PT_LS4_UNSOL:
413562306a36Sopenharmony_ci			p = (void *)pkt;
413662306a36Sopenharmony_ci			if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
413762306a36Sopenharmony_ci				rsp->ring_ptr = (response_t *)pkt;
413862306a36Sopenharmony_ci				rsp->ring_index = cur_ring_index;
413962306a36Sopenharmony_ci
414062306a36Sopenharmony_ci				ql_dbg(ql_dbg_init, vha, 0x2124,
414162306a36Sopenharmony_ci				       "Defer processing UNSOL LS req opcode %#x...\n",
414262306a36Sopenharmony_ci				       p->payload[0]);
414362306a36Sopenharmony_ci				return;
414462306a36Sopenharmony_ci			}
414562306a36Sopenharmony_ci			qla2xxx_process_purls_iocb((void **)&pkt, &rsp);
414662306a36Sopenharmony_ci			break;
414762306a36Sopenharmony_ci		default:
414862306a36Sopenharmony_ci			/* Type Not Supported. */
414962306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5042,
415062306a36Sopenharmony_ci			       "Received unknown response pkt type 0x%x entry status=%x.\n",
415162306a36Sopenharmony_ci			       pkt->entry_type, pkt->entry_status);
415262306a36Sopenharmony_ci			break;
415362306a36Sopenharmony_ci		}
415462306a36Sopenharmony_ci		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
415562306a36Sopenharmony_ci		wmb();
415662306a36Sopenharmony_ci	}
415762306a36Sopenharmony_ci
415862306a36Sopenharmony_ci	/* Adjust ring index */
415962306a36Sopenharmony_ci	if (IS_P3P_TYPE(ha)) {
416062306a36Sopenharmony_ci		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
416162306a36Sopenharmony_ci
416262306a36Sopenharmony_ci		wrt_reg_dword(&reg->rsp_q_out[0], rsp->ring_index);
416362306a36Sopenharmony_ci	} else {
416462306a36Sopenharmony_ci		wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index);
416562306a36Sopenharmony_ci	}
416662306a36Sopenharmony_ci}
416762306a36Sopenharmony_ci
416862306a36Sopenharmony_cistatic void
416962306a36Sopenharmony_ciqla2xxx_check_risc_status(scsi_qla_host_t *vha)
417062306a36Sopenharmony_ci{
417162306a36Sopenharmony_ci	int rval;
417262306a36Sopenharmony_ci	uint32_t cnt;
417362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
417462306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
417762306a36Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
417862306a36Sopenharmony_ci		return;
417962306a36Sopenharmony_ci
418062306a36Sopenharmony_ci	rval = QLA_SUCCESS;
418162306a36Sopenharmony_ci	wrt_reg_dword(&reg->iobase_addr, 0x7C00);
418262306a36Sopenharmony_ci	rd_reg_dword(&reg->iobase_addr);
418362306a36Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0001);
418462306a36Sopenharmony_ci	for (cnt = 10000; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
418562306a36Sopenharmony_ci	    rval == QLA_SUCCESS; cnt--) {
418662306a36Sopenharmony_ci		if (cnt) {
418762306a36Sopenharmony_ci			wrt_reg_dword(&reg->iobase_window, 0x0001);
418862306a36Sopenharmony_ci			udelay(10);
418962306a36Sopenharmony_ci		} else
419062306a36Sopenharmony_ci			rval = QLA_FUNCTION_TIMEOUT;
419162306a36Sopenharmony_ci	}
419262306a36Sopenharmony_ci	if (rval == QLA_SUCCESS)
419362306a36Sopenharmony_ci		goto next_test;
419462306a36Sopenharmony_ci
419562306a36Sopenharmony_ci	rval = QLA_SUCCESS;
419662306a36Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0003);
419762306a36Sopenharmony_ci	for (cnt = 100; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
419862306a36Sopenharmony_ci	    rval == QLA_SUCCESS; cnt--) {
419962306a36Sopenharmony_ci		if (cnt) {
420062306a36Sopenharmony_ci			wrt_reg_dword(&reg->iobase_window, 0x0003);
420162306a36Sopenharmony_ci			udelay(10);
420262306a36Sopenharmony_ci		} else
420362306a36Sopenharmony_ci			rval = QLA_FUNCTION_TIMEOUT;
420462306a36Sopenharmony_ci	}
420562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
420662306a36Sopenharmony_ci		goto done;
420762306a36Sopenharmony_ci
420862306a36Sopenharmony_cinext_test:
420962306a36Sopenharmony_ci	if (rd_reg_dword(&reg->iobase_c8) & BIT_3)
421062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x504c,
421162306a36Sopenharmony_ci		    "Additional code -- 0x55AA.\n");
421262306a36Sopenharmony_ci
421362306a36Sopenharmony_cidone:
421462306a36Sopenharmony_ci	wrt_reg_dword(&reg->iobase_window, 0x0000);
421562306a36Sopenharmony_ci	rd_reg_dword(&reg->iobase_window);
421662306a36Sopenharmony_ci}
421762306a36Sopenharmony_ci
421862306a36Sopenharmony_ci/**
421962306a36Sopenharmony_ci * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
422062306a36Sopenharmony_ci * @irq: interrupt number
422162306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
422262306a36Sopenharmony_ci *
422362306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
422462306a36Sopenharmony_ci *
422562306a36Sopenharmony_ci * Returns handled flag.
422662306a36Sopenharmony_ci */
422762306a36Sopenharmony_ciirqreturn_t
422862306a36Sopenharmony_ciqla24xx_intr_handler(int irq, void *dev_id)
422962306a36Sopenharmony_ci{
423062306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
423162306a36Sopenharmony_ci	struct qla_hw_data *ha;
423262306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
423362306a36Sopenharmony_ci	int		status;
423462306a36Sopenharmony_ci	unsigned long	iter;
423562306a36Sopenharmony_ci	uint32_t	stat;
423662306a36Sopenharmony_ci	uint32_t	hccr;
423762306a36Sopenharmony_ci	uint16_t	mb[8];
423862306a36Sopenharmony_ci	struct rsp_que *rsp;
423962306a36Sopenharmony_ci	unsigned long	flags;
424062306a36Sopenharmony_ci	bool process_atio = false;
424162306a36Sopenharmony_ci
424262306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
424362306a36Sopenharmony_ci	if (!rsp) {
424462306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x5059,
424562306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
424662306a36Sopenharmony_ci		return IRQ_NONE;
424762306a36Sopenharmony_ci	}
424862306a36Sopenharmony_ci
424962306a36Sopenharmony_ci	ha = rsp->hw;
425062306a36Sopenharmony_ci	reg = &ha->iobase->isp24;
425162306a36Sopenharmony_ci	status = 0;
425262306a36Sopenharmony_ci
425362306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
425462306a36Sopenharmony_ci		return IRQ_HANDLED;
425562306a36Sopenharmony_ci
425662306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
425762306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
425862306a36Sopenharmony_ci	for (iter = 50; iter--; ) {
425962306a36Sopenharmony_ci		stat = rd_reg_dword(&reg->host_status);
426062306a36Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
426162306a36Sopenharmony_ci			break;
426262306a36Sopenharmony_ci		if (stat & HSRX_RISC_PAUSED) {
426362306a36Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
426462306a36Sopenharmony_ci				break;
426562306a36Sopenharmony_ci
426662306a36Sopenharmony_ci			hccr = rd_reg_dword(&reg->hccr);
426762306a36Sopenharmony_ci
426862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x504b,
426962306a36Sopenharmony_ci			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
427062306a36Sopenharmony_ci			    hccr);
427162306a36Sopenharmony_ci
427262306a36Sopenharmony_ci			qla2xxx_check_risc_status(vha);
427362306a36Sopenharmony_ci
427462306a36Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
427562306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
427662306a36Sopenharmony_ci			break;
427762306a36Sopenharmony_ci		} else if ((stat & HSRX_RISC_INT) == 0)
427862306a36Sopenharmony_ci			break;
427962306a36Sopenharmony_ci
428062306a36Sopenharmony_ci		switch (stat & 0xff) {
428162306a36Sopenharmony_ci		case INTR_ROM_MB_SUCCESS:
428262306a36Sopenharmony_ci		case INTR_ROM_MB_FAILED:
428362306a36Sopenharmony_ci		case INTR_MB_SUCCESS:
428462306a36Sopenharmony_ci		case INTR_MB_FAILED:
428562306a36Sopenharmony_ci			qla24xx_mbx_completion(vha, MSW(stat));
428662306a36Sopenharmony_ci			status |= MBX_INTERRUPT;
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci			break;
428962306a36Sopenharmony_ci		case INTR_ASYNC_EVENT:
429062306a36Sopenharmony_ci			mb[0] = MSW(stat);
429162306a36Sopenharmony_ci			mb[1] = rd_reg_word(&reg->mailbox1);
429262306a36Sopenharmony_ci			mb[2] = rd_reg_word(&reg->mailbox2);
429362306a36Sopenharmony_ci			mb[3] = rd_reg_word(&reg->mailbox3);
429462306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
429562306a36Sopenharmony_ci			break;
429662306a36Sopenharmony_ci		case INTR_RSP_QUE_UPDATE:
429762306a36Sopenharmony_ci		case INTR_RSP_QUE_UPDATE_83XX:
429862306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
429962306a36Sopenharmony_ci			break;
430062306a36Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE_27XX:
430162306a36Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE:
430262306a36Sopenharmony_ci			process_atio = true;
430362306a36Sopenharmony_ci			break;
430462306a36Sopenharmony_ci		case INTR_ATIO_RSP_QUE_UPDATE:
430562306a36Sopenharmony_ci			process_atio = true;
430662306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
430762306a36Sopenharmony_ci			break;
430862306a36Sopenharmony_ci		default:
430962306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x504f,
431062306a36Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
431162306a36Sopenharmony_ci			break;
431262306a36Sopenharmony_ci		}
431362306a36Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
431462306a36Sopenharmony_ci		rd_reg_dword_relaxed(&reg->hccr);
431562306a36Sopenharmony_ci		if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
431662306a36Sopenharmony_ci			ndelay(3500);
431762306a36Sopenharmony_ci	}
431862306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
431962306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
432062306a36Sopenharmony_ci
432162306a36Sopenharmony_ci	if (process_atio) {
432262306a36Sopenharmony_ci		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
432362306a36Sopenharmony_ci		qlt_24xx_process_atio_queue(vha, 0);
432462306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
432562306a36Sopenharmony_ci	}
432662306a36Sopenharmony_ci
432762306a36Sopenharmony_ci	return IRQ_HANDLED;
432862306a36Sopenharmony_ci}
432962306a36Sopenharmony_ci
433062306a36Sopenharmony_cistatic irqreturn_t
433162306a36Sopenharmony_ciqla24xx_msix_rsp_q(int irq, void *dev_id)
433262306a36Sopenharmony_ci{
433362306a36Sopenharmony_ci	struct qla_hw_data *ha;
433462306a36Sopenharmony_ci	struct rsp_que *rsp;
433562306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
433662306a36Sopenharmony_ci	struct scsi_qla_host *vha;
433762306a36Sopenharmony_ci	unsigned long flags;
433862306a36Sopenharmony_ci
433962306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
434062306a36Sopenharmony_ci	if (!rsp) {
434162306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505a,
434262306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
434362306a36Sopenharmony_ci		return IRQ_NONE;
434462306a36Sopenharmony_ci	}
434562306a36Sopenharmony_ci	ha = rsp->hw;
434662306a36Sopenharmony_ci	reg = &ha->iobase->isp24;
434762306a36Sopenharmony_ci
434862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
435162306a36Sopenharmony_ci	qla24xx_process_response_queue(vha, rsp);
435262306a36Sopenharmony_ci	if (!ha->flags.disable_msix_handshake) {
435362306a36Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
435462306a36Sopenharmony_ci		rd_reg_dword_relaxed(&reg->hccr);
435562306a36Sopenharmony_ci	}
435662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
435762306a36Sopenharmony_ci
435862306a36Sopenharmony_ci	return IRQ_HANDLED;
435962306a36Sopenharmony_ci}
436062306a36Sopenharmony_ci
436162306a36Sopenharmony_cistatic irqreturn_t
436262306a36Sopenharmony_ciqla24xx_msix_default(int irq, void *dev_id)
436362306a36Sopenharmony_ci{
436462306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
436562306a36Sopenharmony_ci	struct qla_hw_data *ha;
436662306a36Sopenharmony_ci	struct rsp_que *rsp;
436762306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
436862306a36Sopenharmony_ci	int		status;
436962306a36Sopenharmony_ci	uint32_t	stat;
437062306a36Sopenharmony_ci	uint32_t	hccr;
437162306a36Sopenharmony_ci	uint16_t	mb[8];
437262306a36Sopenharmony_ci	unsigned long flags;
437362306a36Sopenharmony_ci	bool process_atio = false;
437462306a36Sopenharmony_ci
437562306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
437662306a36Sopenharmony_ci	if (!rsp) {
437762306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505c,
437862306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
437962306a36Sopenharmony_ci		return IRQ_NONE;
438062306a36Sopenharmony_ci	}
438162306a36Sopenharmony_ci	ha = rsp->hw;
438262306a36Sopenharmony_ci	reg = &ha->iobase->isp24;
438362306a36Sopenharmony_ci	status = 0;
438462306a36Sopenharmony_ci
438562306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
438662306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
438762306a36Sopenharmony_ci	do {
438862306a36Sopenharmony_ci		stat = rd_reg_dword(&reg->host_status);
438962306a36Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, stat))
439062306a36Sopenharmony_ci			break;
439162306a36Sopenharmony_ci		if (stat & HSRX_RISC_PAUSED) {
439262306a36Sopenharmony_ci			if (unlikely(pci_channel_offline(ha->pdev)))
439362306a36Sopenharmony_ci				break;
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ci			hccr = rd_reg_dword(&reg->hccr);
439662306a36Sopenharmony_ci
439762306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x5050,
439862306a36Sopenharmony_ci			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
439962306a36Sopenharmony_ci			    hccr);
440062306a36Sopenharmony_ci
440162306a36Sopenharmony_ci			qla2xxx_check_risc_status(vha);
440262306a36Sopenharmony_ci			vha->hw_err_cnt++;
440362306a36Sopenharmony_ci
440462306a36Sopenharmony_ci			ha->isp_ops->fw_dump(vha);
440562306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
440662306a36Sopenharmony_ci			break;
440762306a36Sopenharmony_ci		} else if ((stat & HSRX_RISC_INT) == 0)
440862306a36Sopenharmony_ci			break;
440962306a36Sopenharmony_ci
441062306a36Sopenharmony_ci		switch (stat & 0xff) {
441162306a36Sopenharmony_ci		case INTR_ROM_MB_SUCCESS:
441262306a36Sopenharmony_ci		case INTR_ROM_MB_FAILED:
441362306a36Sopenharmony_ci		case INTR_MB_SUCCESS:
441462306a36Sopenharmony_ci		case INTR_MB_FAILED:
441562306a36Sopenharmony_ci			qla24xx_mbx_completion(vha, MSW(stat));
441662306a36Sopenharmony_ci			status |= MBX_INTERRUPT;
441762306a36Sopenharmony_ci
441862306a36Sopenharmony_ci			break;
441962306a36Sopenharmony_ci		case INTR_ASYNC_EVENT:
442062306a36Sopenharmony_ci			mb[0] = MSW(stat);
442162306a36Sopenharmony_ci			mb[1] = rd_reg_word(&reg->mailbox1);
442262306a36Sopenharmony_ci			mb[2] = rd_reg_word(&reg->mailbox2);
442362306a36Sopenharmony_ci			mb[3] = rd_reg_word(&reg->mailbox3);
442462306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
442562306a36Sopenharmony_ci			break;
442662306a36Sopenharmony_ci		case INTR_RSP_QUE_UPDATE:
442762306a36Sopenharmony_ci		case INTR_RSP_QUE_UPDATE_83XX:
442862306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
442962306a36Sopenharmony_ci			break;
443062306a36Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE_27XX:
443162306a36Sopenharmony_ci		case INTR_ATIO_QUE_UPDATE:
443262306a36Sopenharmony_ci			process_atio = true;
443362306a36Sopenharmony_ci			break;
443462306a36Sopenharmony_ci		case INTR_ATIO_RSP_QUE_UPDATE:
443562306a36Sopenharmony_ci			process_atio = true;
443662306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
443762306a36Sopenharmony_ci			break;
443862306a36Sopenharmony_ci		default:
443962306a36Sopenharmony_ci			ql_dbg(ql_dbg_async, vha, 0x5051,
444062306a36Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
444162306a36Sopenharmony_ci			break;
444262306a36Sopenharmony_ci		}
444362306a36Sopenharmony_ci		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
444462306a36Sopenharmony_ci	} while (0);
444562306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
444662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci	if (process_atio) {
444962306a36Sopenharmony_ci		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
445062306a36Sopenharmony_ci		qlt_24xx_process_atio_queue(vha, 0);
445162306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
445262306a36Sopenharmony_ci	}
445362306a36Sopenharmony_ci
445462306a36Sopenharmony_ci	return IRQ_HANDLED;
445562306a36Sopenharmony_ci}
445662306a36Sopenharmony_ci
445762306a36Sopenharmony_ciirqreturn_t
445862306a36Sopenharmony_ciqla2xxx_msix_rsp_q(int irq, void *dev_id)
445962306a36Sopenharmony_ci{
446062306a36Sopenharmony_ci	struct qla_hw_data *ha;
446162306a36Sopenharmony_ci	struct qla_qpair *qpair;
446262306a36Sopenharmony_ci
446362306a36Sopenharmony_ci	qpair = dev_id;
446462306a36Sopenharmony_ci	if (!qpair) {
446562306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505b,
446662306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
446762306a36Sopenharmony_ci		return IRQ_NONE;
446862306a36Sopenharmony_ci	}
446962306a36Sopenharmony_ci	ha = qpair->hw;
447062306a36Sopenharmony_ci
447162306a36Sopenharmony_ci	queue_work(ha->wq, &qpair->q_work);
447262306a36Sopenharmony_ci
447362306a36Sopenharmony_ci	return IRQ_HANDLED;
447462306a36Sopenharmony_ci}
447562306a36Sopenharmony_ci
447662306a36Sopenharmony_ciirqreturn_t
447762306a36Sopenharmony_ciqla2xxx_msix_rsp_q_hs(int irq, void *dev_id)
447862306a36Sopenharmony_ci{
447962306a36Sopenharmony_ci	struct qla_hw_data *ha;
448062306a36Sopenharmony_ci	struct qla_qpair *qpair;
448162306a36Sopenharmony_ci	struct device_reg_24xx __iomem *reg;
448262306a36Sopenharmony_ci	unsigned long flags;
448362306a36Sopenharmony_ci
448462306a36Sopenharmony_ci	qpair = dev_id;
448562306a36Sopenharmony_ci	if (!qpair) {
448662306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0x505b,
448762306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
448862306a36Sopenharmony_ci		return IRQ_NONE;
448962306a36Sopenharmony_ci	}
449062306a36Sopenharmony_ci	ha = qpair->hw;
449162306a36Sopenharmony_ci
449262306a36Sopenharmony_ci	reg = &ha->iobase->isp24;
449362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
449462306a36Sopenharmony_ci	wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
449562306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
449662306a36Sopenharmony_ci
449762306a36Sopenharmony_ci	queue_work(ha->wq, &qpair->q_work);
449862306a36Sopenharmony_ci
449962306a36Sopenharmony_ci	return IRQ_HANDLED;
450062306a36Sopenharmony_ci}
450162306a36Sopenharmony_ci
450262306a36Sopenharmony_ci/* Interrupt handling helpers. */
450362306a36Sopenharmony_ci
450462306a36Sopenharmony_cistruct qla_init_msix_entry {
450562306a36Sopenharmony_ci	const char *name;
450662306a36Sopenharmony_ci	irq_handler_t handler;
450762306a36Sopenharmony_ci};
450862306a36Sopenharmony_ci
450962306a36Sopenharmony_cistatic const struct qla_init_msix_entry msix_entries[] = {
451062306a36Sopenharmony_ci	{ "default", qla24xx_msix_default },
451162306a36Sopenharmony_ci	{ "rsp_q", qla24xx_msix_rsp_q },
451262306a36Sopenharmony_ci	{ "atio_q", qla83xx_msix_atio_q },
451362306a36Sopenharmony_ci	{ "qpair_multiq", qla2xxx_msix_rsp_q },
451462306a36Sopenharmony_ci	{ "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs },
451562306a36Sopenharmony_ci};
451662306a36Sopenharmony_ci
451762306a36Sopenharmony_cistatic const struct qla_init_msix_entry qla82xx_msix_entries[] = {
451862306a36Sopenharmony_ci	{ "qla2xxx (default)", qla82xx_msix_default },
451962306a36Sopenharmony_ci	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
452062306a36Sopenharmony_ci};
452162306a36Sopenharmony_ci
452262306a36Sopenharmony_cistatic int
452362306a36Sopenharmony_ciqla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
452462306a36Sopenharmony_ci{
452562306a36Sopenharmony_ci	int i, ret;
452662306a36Sopenharmony_ci	struct qla_msix_entry *qentry;
452762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
452862306a36Sopenharmony_ci	int min_vecs = QLA_BASE_VECTORS;
452962306a36Sopenharmony_ci	struct irq_affinity desc = {
453062306a36Sopenharmony_ci		.pre_vectors = QLA_BASE_VECTORS,
453162306a36Sopenharmony_ci	};
453262306a36Sopenharmony_ci
453362306a36Sopenharmony_ci	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
453462306a36Sopenharmony_ci	    IS_ATIO_MSIX_CAPABLE(ha)) {
453562306a36Sopenharmony_ci		desc.pre_vectors++;
453662306a36Sopenharmony_ci		min_vecs++;
453762306a36Sopenharmony_ci	}
453862306a36Sopenharmony_ci
453962306a36Sopenharmony_ci	if (USER_CTRL_IRQ(ha) || !ha->mqiobase) {
454062306a36Sopenharmony_ci		/* user wants to control IRQ setting for target mode */
454162306a36Sopenharmony_ci		ret = pci_alloc_irq_vectors(ha->pdev, min_vecs,
454262306a36Sopenharmony_ci		    min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)),
454362306a36Sopenharmony_ci		    PCI_IRQ_MSIX);
454462306a36Sopenharmony_ci	} else
454562306a36Sopenharmony_ci		ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs,
454662306a36Sopenharmony_ci		    min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)),
454762306a36Sopenharmony_ci		    PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
454862306a36Sopenharmony_ci		    &desc);
454962306a36Sopenharmony_ci
455062306a36Sopenharmony_ci	if (ret < 0) {
455162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00c7,
455262306a36Sopenharmony_ci		    "MSI-X: Failed to enable support, "
455362306a36Sopenharmony_ci		    "giving   up -- %d/%d.\n",
455462306a36Sopenharmony_ci		    ha->msix_count, ret);
455562306a36Sopenharmony_ci		goto msix_out;
455662306a36Sopenharmony_ci	} else if (ret < ha->msix_count) {
455762306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00c6,
455862306a36Sopenharmony_ci		    "MSI-X: Using %d vectors\n", ret);
455962306a36Sopenharmony_ci		ha->msix_count = ret;
456062306a36Sopenharmony_ci		/* Recalculate queue values */
456162306a36Sopenharmony_ci		if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) {
456262306a36Sopenharmony_ci			ha->max_req_queues = ha->msix_count - 1;
456362306a36Sopenharmony_ci
456462306a36Sopenharmony_ci			/* ATIOQ needs 1 vector. That's 1 less QPair */
456562306a36Sopenharmony_ci			if (QLA_TGT_MODE_ENABLED())
456662306a36Sopenharmony_ci				ha->max_req_queues--;
456762306a36Sopenharmony_ci
456862306a36Sopenharmony_ci			ha->max_rsp_queues = ha->max_req_queues;
456962306a36Sopenharmony_ci
457062306a36Sopenharmony_ci			ha->max_qpairs = ha->max_req_queues - 1;
457162306a36Sopenharmony_ci			ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190,
457262306a36Sopenharmony_ci			    "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs);
457362306a36Sopenharmony_ci		}
457462306a36Sopenharmony_ci	}
457562306a36Sopenharmony_ci	vha->irq_offset = desc.pre_vectors;
457662306a36Sopenharmony_ci	ha->msix_entries = kcalloc(ha->msix_count,
457762306a36Sopenharmony_ci				   sizeof(struct qla_msix_entry),
457862306a36Sopenharmony_ci				   GFP_KERNEL);
457962306a36Sopenharmony_ci	if (!ha->msix_entries) {
458062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00c8,
458162306a36Sopenharmony_ci		    "Failed to allocate memory for ha->msix_entries.\n");
458262306a36Sopenharmony_ci		ret = -ENOMEM;
458362306a36Sopenharmony_ci		goto free_irqs;
458462306a36Sopenharmony_ci	}
458562306a36Sopenharmony_ci	ha->flags.msix_enabled = 1;
458662306a36Sopenharmony_ci
458762306a36Sopenharmony_ci	for (i = 0; i < ha->msix_count; i++) {
458862306a36Sopenharmony_ci		qentry = &ha->msix_entries[i];
458962306a36Sopenharmony_ci		qentry->vector = pci_irq_vector(ha->pdev, i);
459062306a36Sopenharmony_ci		qentry->vector_base0 = i;
459162306a36Sopenharmony_ci		qentry->entry = i;
459262306a36Sopenharmony_ci		qentry->have_irq = 0;
459362306a36Sopenharmony_ci		qentry->in_use = 0;
459462306a36Sopenharmony_ci		qentry->handle = NULL;
459562306a36Sopenharmony_ci	}
459662306a36Sopenharmony_ci
459762306a36Sopenharmony_ci	/* Enable MSI-X vectors for the base queue */
459862306a36Sopenharmony_ci	for (i = 0; i < QLA_BASE_VECTORS; i++) {
459962306a36Sopenharmony_ci		qentry = &ha->msix_entries[i];
460062306a36Sopenharmony_ci		qentry->handle = rsp;
460162306a36Sopenharmony_ci		rsp->msix = qentry;
460262306a36Sopenharmony_ci		scnprintf(qentry->name, sizeof(qentry->name),
460362306a36Sopenharmony_ci		    "qla2xxx%lu_%s", vha->host_no, msix_entries[i].name);
460462306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
460562306a36Sopenharmony_ci			ret = request_irq(qentry->vector,
460662306a36Sopenharmony_ci				qla82xx_msix_entries[i].handler,
460762306a36Sopenharmony_ci				0, qla82xx_msix_entries[i].name, rsp);
460862306a36Sopenharmony_ci		else
460962306a36Sopenharmony_ci			ret = request_irq(qentry->vector,
461062306a36Sopenharmony_ci				msix_entries[i].handler,
461162306a36Sopenharmony_ci				0, qentry->name, rsp);
461262306a36Sopenharmony_ci		if (ret)
461362306a36Sopenharmony_ci			goto msix_register_fail;
461462306a36Sopenharmony_ci		qentry->have_irq = 1;
461562306a36Sopenharmony_ci		qentry->in_use = 1;
461662306a36Sopenharmony_ci	}
461762306a36Sopenharmony_ci
461862306a36Sopenharmony_ci	/*
461962306a36Sopenharmony_ci	 * If target mode is enable, also request the vector for the ATIO
462062306a36Sopenharmony_ci	 * queue.
462162306a36Sopenharmony_ci	 */
462262306a36Sopenharmony_ci	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
462362306a36Sopenharmony_ci	    IS_ATIO_MSIX_CAPABLE(ha)) {
462462306a36Sopenharmony_ci		qentry = &ha->msix_entries[QLA_ATIO_VECTOR];
462562306a36Sopenharmony_ci		rsp->msix = qentry;
462662306a36Sopenharmony_ci		qentry->handle = rsp;
462762306a36Sopenharmony_ci		scnprintf(qentry->name, sizeof(qentry->name),
462862306a36Sopenharmony_ci		    "qla2xxx%lu_%s", vha->host_no,
462962306a36Sopenharmony_ci		    msix_entries[QLA_ATIO_VECTOR].name);
463062306a36Sopenharmony_ci		qentry->in_use = 1;
463162306a36Sopenharmony_ci		ret = request_irq(qentry->vector,
463262306a36Sopenharmony_ci			msix_entries[QLA_ATIO_VECTOR].handler,
463362306a36Sopenharmony_ci			0, qentry->name, rsp);
463462306a36Sopenharmony_ci		qentry->have_irq = 1;
463562306a36Sopenharmony_ci	}
463662306a36Sopenharmony_ci
463762306a36Sopenharmony_cimsix_register_fail:
463862306a36Sopenharmony_ci	if (ret) {
463962306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00cb,
464062306a36Sopenharmony_ci		    "MSI-X: unable to register handler -- %x/%d.\n",
464162306a36Sopenharmony_ci		    qentry->vector, ret);
464262306a36Sopenharmony_ci		qla2x00_free_irqs(vha);
464362306a36Sopenharmony_ci		ha->mqenable = 0;
464462306a36Sopenharmony_ci		goto msix_out;
464562306a36Sopenharmony_ci	}
464662306a36Sopenharmony_ci
464762306a36Sopenharmony_ci	/* Enable MSI-X vector for response queue update for queue 0 */
464862306a36Sopenharmony_ci	if (IS_MQUE_CAPABLE(ha) &&
464962306a36Sopenharmony_ci	    (ha->msixbase && ha->mqiobase && ha->max_qpairs))
465062306a36Sopenharmony_ci		ha->mqenable = 1;
465162306a36Sopenharmony_ci	else
465262306a36Sopenharmony_ci		ha->mqenable = 0;
465362306a36Sopenharmony_ci
465462306a36Sopenharmony_ci	ql_dbg(ql_dbg_multiq, vha, 0xc005,
465562306a36Sopenharmony_ci	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
465662306a36Sopenharmony_ci	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
465762306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0055,
465862306a36Sopenharmony_ci	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
465962306a36Sopenharmony_ci	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
466062306a36Sopenharmony_ci
466162306a36Sopenharmony_cimsix_out:
466262306a36Sopenharmony_ci	return ret;
466362306a36Sopenharmony_ci
466462306a36Sopenharmony_cifree_irqs:
466562306a36Sopenharmony_ci	pci_free_irq_vectors(ha->pdev);
466662306a36Sopenharmony_ci	goto msix_out;
466762306a36Sopenharmony_ci}
466862306a36Sopenharmony_ci
466962306a36Sopenharmony_ciint
467062306a36Sopenharmony_ciqla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
467162306a36Sopenharmony_ci{
467262306a36Sopenharmony_ci	int ret = QLA_FUNCTION_FAILED;
467362306a36Sopenharmony_ci	device_reg_t *reg = ha->iobase;
467462306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
467562306a36Sopenharmony_ci
467662306a36Sopenharmony_ci	/* If possible, enable MSI-X. */
467762306a36Sopenharmony_ci	if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
467862306a36Sopenharmony_ci	    !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
467962306a36Sopenharmony_ci	    !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
468062306a36Sopenharmony_ci		goto skip_msi;
468162306a36Sopenharmony_ci
468262306a36Sopenharmony_ci	if (ql2xenablemsix == 2)
468362306a36Sopenharmony_ci		goto skip_msix;
468462306a36Sopenharmony_ci
468562306a36Sopenharmony_ci	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
468662306a36Sopenharmony_ci		(ha->pdev->subsystem_device == 0x7040 ||
468762306a36Sopenharmony_ci		ha->pdev->subsystem_device == 0x7041 ||
468862306a36Sopenharmony_ci		ha->pdev->subsystem_device == 0x1705)) {
468962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0034,
469062306a36Sopenharmony_ci		    "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
469162306a36Sopenharmony_ci			ha->pdev->subsystem_vendor,
469262306a36Sopenharmony_ci			ha->pdev->subsystem_device);
469362306a36Sopenharmony_ci		goto skip_msi;
469462306a36Sopenharmony_ci	}
469562306a36Sopenharmony_ci
469662306a36Sopenharmony_ci	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
469762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0035,
469862306a36Sopenharmony_ci		    "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
469962306a36Sopenharmony_ci		    ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
470062306a36Sopenharmony_ci		goto skip_msix;
470162306a36Sopenharmony_ci	}
470262306a36Sopenharmony_ci
470362306a36Sopenharmony_ci	ret = qla24xx_enable_msix(ha, rsp);
470462306a36Sopenharmony_ci	if (!ret) {
470562306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0036,
470662306a36Sopenharmony_ci		    "MSI-X: Enabled (0x%X, 0x%X).\n",
470762306a36Sopenharmony_ci		    ha->chip_revision, ha->fw_attributes);
470862306a36Sopenharmony_ci		goto clear_risc_ints;
470962306a36Sopenharmony_ci	}
471062306a36Sopenharmony_ci
471162306a36Sopenharmony_ciskip_msix:
471262306a36Sopenharmony_ci
471362306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0037,
471462306a36Sopenharmony_ci	    "Falling back-to MSI mode -- ret=%d.\n", ret);
471562306a36Sopenharmony_ci
471662306a36Sopenharmony_ci	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
471762306a36Sopenharmony_ci	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
471862306a36Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
471962306a36Sopenharmony_ci		goto skip_msi;
472062306a36Sopenharmony_ci
472162306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
472262306a36Sopenharmony_ci	if (ret > 0) {
472362306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0038,
472462306a36Sopenharmony_ci		    "MSI: Enabled.\n");
472562306a36Sopenharmony_ci		ha->flags.msi_enabled = 1;
472662306a36Sopenharmony_ci	} else
472762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0039,
472862306a36Sopenharmony_ci		    "Falling back-to INTa mode -- ret=%d.\n", ret);
472962306a36Sopenharmony_ciskip_msi:
473062306a36Sopenharmony_ci
473162306a36Sopenharmony_ci	/* Skip INTx on ISP82xx. */
473262306a36Sopenharmony_ci	if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
473362306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
473462306a36Sopenharmony_ci
473562306a36Sopenharmony_ci	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
473662306a36Sopenharmony_ci	    ha->flags.msi_enabled ? 0 : IRQF_SHARED,
473762306a36Sopenharmony_ci	    QLA2XXX_DRIVER_NAME, rsp);
473862306a36Sopenharmony_ci	if (ret) {
473962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x003a,
474062306a36Sopenharmony_ci		    "Failed to reserve interrupt %d already in use.\n",
474162306a36Sopenharmony_ci		    ha->pdev->irq);
474262306a36Sopenharmony_ci		goto fail;
474362306a36Sopenharmony_ci	} else if (!ha->flags.msi_enabled) {
474462306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0125,
474562306a36Sopenharmony_ci		    "INTa mode: Enabled.\n");
474662306a36Sopenharmony_ci		ha->flags.mr_intr_valid = 1;
474762306a36Sopenharmony_ci		/* Set max_qpair to 0, as MSI-X and MSI in not enabled */
474862306a36Sopenharmony_ci		ha->max_qpairs = 0;
474962306a36Sopenharmony_ci	}
475062306a36Sopenharmony_ci
475162306a36Sopenharmony_ciclear_risc_ints:
475262306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
475362306a36Sopenharmony_ci		goto fail;
475462306a36Sopenharmony_ci
475562306a36Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
475662306a36Sopenharmony_ci	wrt_reg_word(&reg->isp.semaphore, 0);
475762306a36Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
475862306a36Sopenharmony_ci
475962306a36Sopenharmony_cifail:
476062306a36Sopenharmony_ci	return ret;
476162306a36Sopenharmony_ci}
476262306a36Sopenharmony_ci
476362306a36Sopenharmony_civoid
476462306a36Sopenharmony_ciqla2x00_free_irqs(scsi_qla_host_t *vha)
476562306a36Sopenharmony_ci{
476662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
476762306a36Sopenharmony_ci	struct rsp_que *rsp;
476862306a36Sopenharmony_ci	struct qla_msix_entry *qentry;
476962306a36Sopenharmony_ci	int i;
477062306a36Sopenharmony_ci
477162306a36Sopenharmony_ci	/*
477262306a36Sopenharmony_ci	 * We need to check that ha->rsp_q_map is valid in case we are called
477362306a36Sopenharmony_ci	 * from a probe failure context.
477462306a36Sopenharmony_ci	 */
477562306a36Sopenharmony_ci	if (!ha->rsp_q_map || !ha->rsp_q_map[0])
477662306a36Sopenharmony_ci		goto free_irqs;
477762306a36Sopenharmony_ci	rsp = ha->rsp_q_map[0];
477862306a36Sopenharmony_ci
477962306a36Sopenharmony_ci	if (ha->flags.msix_enabled) {
478062306a36Sopenharmony_ci		for (i = 0; i < ha->msix_count; i++) {
478162306a36Sopenharmony_ci			qentry = &ha->msix_entries[i];
478262306a36Sopenharmony_ci			if (qentry->have_irq) {
478362306a36Sopenharmony_ci				irq_set_affinity_notifier(qentry->vector, NULL);
478462306a36Sopenharmony_ci				free_irq(pci_irq_vector(ha->pdev, i), qentry->handle);
478562306a36Sopenharmony_ci			}
478662306a36Sopenharmony_ci		}
478762306a36Sopenharmony_ci		kfree(ha->msix_entries);
478862306a36Sopenharmony_ci		ha->msix_entries = NULL;
478962306a36Sopenharmony_ci		ha->flags.msix_enabled = 0;
479062306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x0042,
479162306a36Sopenharmony_ci			"Disabled MSI-X.\n");
479262306a36Sopenharmony_ci	} else {
479362306a36Sopenharmony_ci		free_irq(pci_irq_vector(ha->pdev, 0), rsp);
479462306a36Sopenharmony_ci	}
479562306a36Sopenharmony_ci
479662306a36Sopenharmony_cifree_irqs:
479762306a36Sopenharmony_ci	pci_free_irq_vectors(ha->pdev);
479862306a36Sopenharmony_ci}
479962306a36Sopenharmony_ci
480062306a36Sopenharmony_ciint qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
480162306a36Sopenharmony_ci	struct qla_msix_entry *msix, int vector_type)
480262306a36Sopenharmony_ci{
480362306a36Sopenharmony_ci	const struct qla_init_msix_entry *intr = &msix_entries[vector_type];
480462306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
480562306a36Sopenharmony_ci	int ret;
480662306a36Sopenharmony_ci
480762306a36Sopenharmony_ci	scnprintf(msix->name, sizeof(msix->name),
480862306a36Sopenharmony_ci	    "qla2xxx%lu_qpair%d", vha->host_no, qpair->id);
480962306a36Sopenharmony_ci	ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair);
481062306a36Sopenharmony_ci	if (ret) {
481162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00e6,
481262306a36Sopenharmony_ci		    "MSI-X: Unable to register handler -- %x/%d.\n",
481362306a36Sopenharmony_ci		    msix->vector, ret);
481462306a36Sopenharmony_ci		return ret;
481562306a36Sopenharmony_ci	}
481662306a36Sopenharmony_ci	msix->have_irq = 1;
481762306a36Sopenharmony_ci	msix->handle = qpair;
481862306a36Sopenharmony_ci	qla_mapq_init_qp_cpu_map(ha, msix, qpair);
481962306a36Sopenharmony_ci	return ret;
482062306a36Sopenharmony_ci}
4821