xref: /linux/drivers/scsi/qla2xxx/qla_isr.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
177adf3f0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
3fa90c54fSAndrew Vasquez  * QLogic Fibre Channel HBA Driver
4bd21eaf9SArmen Baloyan  * Copyright (c)  2003-2014 QLogic Corporation
51da177e4SLinus Torvalds  */
61da177e4SLinus Torvalds #include "qla_def.h"
72d70c103SNicholas Bellinger #include "qla_target.h"
8a0465859SBikash Hazarika #include "qla_gbl.h"
91da177e4SLinus Torvalds 
1005236a05SAndrew Vasquez #include <linux/delay.h>
115a0e3ad6STejun Heo #include <linux/slab.h>
12e326d22aSQuinn Tran #include <linux/cpu.h>
1309ce66aeSBart Van Assche #include <linux/t10-pi.h>
14df7baa50SAndrew Vasquez #include <scsi/scsi_tcq.h>
159a069e19SGiridhar Malavali #include <scsi/scsi_bsg_fc.h>
16bad75002SArun Easi #include <scsi/scsi_eh.h>
17d32041ecSJohannes Thumshirn #include <scsi/fc/fc_fs.h>
18d32041ecSJohannes Thumshirn #include <linux/nvme-fc-driver.h>
19df7baa50SAndrew Vasquez 
201da177e4SLinus Torvalds static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
2173208dfdSAnirban Chakraborty static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
222afa19a9SAnirban Chakraborty static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
23c5419e26SQuinn Tran static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
2473208dfdSAnirban Chakraborty 	sts_entry_t *);
259f2475feSShyam Sundar static void qla27xx_process_purex_fpin(struct scsi_qla_host *vha,
269f2475feSShyam Sundar 	struct purex_item *item);
279f2475feSShyam Sundar static struct purex_item *qla24xx_alloc_purex_item(scsi_qla_host_t *vha,
289f2475feSShyam Sundar 	uint16_t size);
299f2475feSShyam Sundar static struct purex_item *qla24xx_copy_std_pkt(struct scsi_qla_host *vha,
309f2475feSShyam Sundar 	void *pkt);
319f2475feSShyam Sundar static struct purex_item *qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha,
329f2475feSShyam Sundar 	void **pkt, struct rsp_que **rsp);
339f2475feSShyam Sundar 
349f2475feSShyam Sundar static void
qla27xx_process_purex_fpin(struct scsi_qla_host * vha,struct purex_item * item)359f2475feSShyam Sundar qla27xx_process_purex_fpin(struct scsi_qla_host *vha, struct purex_item *item)
369f2475feSShyam Sundar {
379f2475feSShyam Sundar 	void *pkt = &item->iocb;
389f2475feSShyam Sundar 	uint16_t pkt_size = item->size;
399f2475feSShyam Sundar 
409f2475feSShyam Sundar 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508d,
419f2475feSShyam Sundar 	       "%s: Enter\n", __func__);
429f2475feSShyam Sundar 
439f2475feSShyam Sundar 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x508e,
449f2475feSShyam Sundar 	       "-------- ELS REQ -------\n");
459f2475feSShyam Sundar 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x508f,
469f2475feSShyam Sundar 		       pkt, pkt_size);
479f2475feSShyam Sundar 
4864fd2ba9SMuneendra 	fc_host_fpin_rcv(vha->host, pkt_size, (char *)pkt, 0);
499f2475feSShyam Sundar }
509a853f71SAndrew Vasquez 
51c4dc7cd3SBart Van Assche const char *const port_state_str[] = {
526e0e85d3SGleb Chesnokov 	[FCS_UNKNOWN]		= "Unknown",
536e0e85d3SGleb Chesnokov 	[FCS_UNCONFIGURED]	= "UNCONFIGURED",
546e0e85d3SGleb Chesnokov 	[FCS_DEVICE_DEAD]	= "DEAD",
556e0e85d3SGleb Chesnokov 	[FCS_DEVICE_LOST]	= "LOST",
566e0e85d3SGleb Chesnokov 	[FCS_ONLINE]		= "ONLINE"
57c4dc7cd3SBart Van Assche };
58c4dc7cd3SBart Van Assche 
59cd248a95SBikash Hazarika #define SFP_DISABLE_LASER_INITIATED    0x15  /* Sub code of 8070 AEN */
60cd248a95SBikash Hazarika #define SFP_ENABLE_LASER_INITIATED     0x16  /* Sub code of 8070 AEN */
61cd248a95SBikash Hazarika 
display_Laser_info(scsi_qla_host_t * vha,u16 mb1,u16 mb2,u16 mb3)62cd248a95SBikash Hazarika static inline void display_Laser_info(scsi_qla_host_t *vha,
63cd248a95SBikash Hazarika 				      u16 mb1, u16 mb2, u16 mb3) {
64cd248a95SBikash Hazarika 
65cd248a95SBikash Hazarika 	if (mb1 == SFP_DISABLE_LASER_INITIATED)
66cd248a95SBikash Hazarika 		ql_log(ql_log_warn, vha, 0xf0a2,
67cd248a95SBikash Hazarika 		       "SFP temperature (%d C) reached/exceeded the threshold (%d C). Laser is disabled.\n",
68cd248a95SBikash Hazarika 		       mb3, mb2);
69cd248a95SBikash Hazarika 	if (mb1 == SFP_ENABLE_LASER_INITIATED)
70cd248a95SBikash Hazarika 		ql_log(ql_log_warn, vha, 0xf0a3,
71cd248a95SBikash Hazarika 		       "SFP temperature (%d C) reached normal operating level. Laser is enabled.\n",
72cd248a95SBikash Hazarika 		       mb3);
73cd248a95SBikash Hazarika }
74cd248a95SBikash Hazarika 
75576bfde8SJoe Carnuccio static void
qla24xx_process_abts(struct scsi_qla_host * vha,struct purex_item * pkt)7662e9dd17SShyam Sundar qla24xx_process_abts(struct scsi_qla_host *vha, struct purex_item *pkt)
77576bfde8SJoe Carnuccio {
7862e9dd17SShyam Sundar 	struct abts_entry_24xx *abts =
7962e9dd17SShyam Sundar 	    (struct abts_entry_24xx *)&pkt->iocb;
80576bfde8SJoe Carnuccio 	struct qla_hw_data *ha = vha->hw;
81576bfde8SJoe Carnuccio 	struct els_entry_24xx *rsp_els;
82576bfde8SJoe Carnuccio 	struct abts_entry_24xx *abts_rsp;
83576bfde8SJoe Carnuccio 	dma_addr_t dma;
84576bfde8SJoe Carnuccio 	uint32_t fctl;
85576bfde8SJoe Carnuccio 	int rval;
86576bfde8SJoe Carnuccio 
87576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init, vha, 0x0286, "%s: entered.\n", __func__);
88576bfde8SJoe Carnuccio 
89576bfde8SJoe Carnuccio 	ql_log(ql_log_warn, vha, 0x0287,
90576bfde8SJoe Carnuccio 	    "Processing ABTS xchg=%#x oxid=%#x rxid=%#x seqid=%#x seqcnt=%#x\n",
91576bfde8SJoe Carnuccio 	    abts->rx_xch_addr_to_abort, abts->ox_id, abts->rx_id,
92576bfde8SJoe Carnuccio 	    abts->seq_id, abts->seq_cnt);
93576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
94576bfde8SJoe Carnuccio 	    "-------- ABTS RCV -------\n");
95576bfde8SJoe Carnuccio 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0287,
96576bfde8SJoe Carnuccio 	    (uint8_t *)abts, sizeof(*abts));
97576bfde8SJoe Carnuccio 
98576bfde8SJoe Carnuccio 	rsp_els = dma_alloc_coherent(&ha->pdev->dev, sizeof(*rsp_els), &dma,
99576bfde8SJoe Carnuccio 	    GFP_KERNEL);
100576bfde8SJoe Carnuccio 	if (!rsp_els) {
101576bfde8SJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x0287,
102576bfde8SJoe Carnuccio 		    "Failed allocate dma buffer ABTS/ELS RSP.\n");
103576bfde8SJoe Carnuccio 		return;
104576bfde8SJoe Carnuccio 	}
105576bfde8SJoe Carnuccio 
106576bfde8SJoe Carnuccio 	/* terminate exchange */
107576bfde8SJoe Carnuccio 	rsp_els->entry_type = ELS_IOCB_TYPE;
108576bfde8SJoe Carnuccio 	rsp_els->entry_count = 1;
1097ffa5b93SBart Van Assche 	rsp_els->nport_handle = cpu_to_le16(~0);
110576bfde8SJoe Carnuccio 	rsp_els->rx_xchg_address = abts->rx_xch_addr_to_abort;
1117ffa5b93SBart Van Assche 	rsp_els->control_flags = cpu_to_le16(EPD_RX_XCHG);
112576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init, vha, 0x0283,
113576bfde8SJoe Carnuccio 	    "Sending ELS Response to terminate exchange %#x...\n",
114576bfde8SJoe Carnuccio 	    abts->rx_xch_addr_to_abort);
115576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
116576bfde8SJoe Carnuccio 	    "-------- ELS RSP -------\n");
117576bfde8SJoe Carnuccio 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x0283,
118576bfde8SJoe Carnuccio 	    (uint8_t *)rsp_els, sizeof(*rsp_els));
119576bfde8SJoe Carnuccio 	rval = qla2x00_issue_iocb(vha, rsp_els, dma, 0);
120576bfde8SJoe Carnuccio 	if (rval) {
121576bfde8SJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x0288,
122576bfde8SJoe Carnuccio 		    "%s: iocb failed to execute -> %x\n", __func__, rval);
123576bfde8SJoe Carnuccio 	} else if (rsp_els->comp_status) {
124576bfde8SJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x0289,
125576bfde8SJoe Carnuccio 		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
126576bfde8SJoe Carnuccio 		    __func__, rsp_els->comp_status,
127576bfde8SJoe Carnuccio 		    rsp_els->error_subcode_1, rsp_els->error_subcode_2);
128576bfde8SJoe Carnuccio 	} else {
129576bfde8SJoe Carnuccio 		ql_dbg(ql_dbg_init, vha, 0x028a,
130576bfde8SJoe Carnuccio 		    "%s: abort exchange done.\n", __func__);
131576bfde8SJoe Carnuccio 	}
132576bfde8SJoe Carnuccio 
133576bfde8SJoe Carnuccio 	/* send ABTS response */
134576bfde8SJoe Carnuccio 	abts_rsp = (void *)rsp_els;
135576bfde8SJoe Carnuccio 	memset(abts_rsp, 0, sizeof(*abts_rsp));
136576bfde8SJoe Carnuccio 	abts_rsp->entry_type = ABTS_RSP_TYPE;
137576bfde8SJoe Carnuccio 	abts_rsp->entry_count = 1;
138576bfde8SJoe Carnuccio 	abts_rsp->nport_handle = abts->nport_handle;
139576bfde8SJoe Carnuccio 	abts_rsp->vp_idx = abts->vp_idx;
140576bfde8SJoe Carnuccio 	abts_rsp->sof_type = abts->sof_type & 0xf0;
141576bfde8SJoe Carnuccio 	abts_rsp->rx_xch_addr = abts->rx_xch_addr;
142576bfde8SJoe Carnuccio 	abts_rsp->d_id[0] = abts->s_id[0];
143576bfde8SJoe Carnuccio 	abts_rsp->d_id[1] = abts->s_id[1];
144576bfde8SJoe Carnuccio 	abts_rsp->d_id[2] = abts->s_id[2];
145576bfde8SJoe Carnuccio 	abts_rsp->r_ctl = FC_ROUTING_BLD | FC_R_CTL_BLD_BA_ACC;
146576bfde8SJoe Carnuccio 	abts_rsp->s_id[0] = abts->d_id[0];
147576bfde8SJoe Carnuccio 	abts_rsp->s_id[1] = abts->d_id[1];
148576bfde8SJoe Carnuccio 	abts_rsp->s_id[2] = abts->d_id[2];
149576bfde8SJoe Carnuccio 	abts_rsp->cs_ctl = abts->cs_ctl;
150576bfde8SJoe Carnuccio 	/* include flipping bit23 in fctl */
151576bfde8SJoe Carnuccio 	fctl = ~(abts->f_ctl[2] | 0x7F) << 16 |
152576bfde8SJoe Carnuccio 	    FC_F_CTL_LAST_SEQ | FC_F_CTL_END_SEQ | FC_F_CTL_SEQ_INIT;
153576bfde8SJoe Carnuccio 	abts_rsp->f_ctl[0] = fctl >> 0 & 0xff;
154576bfde8SJoe Carnuccio 	abts_rsp->f_ctl[1] = fctl >> 8 & 0xff;
155576bfde8SJoe Carnuccio 	abts_rsp->f_ctl[2] = fctl >> 16 & 0xff;
156576bfde8SJoe Carnuccio 	abts_rsp->type = FC_TYPE_BLD;
157576bfde8SJoe Carnuccio 	abts_rsp->rx_id = abts->rx_id;
158576bfde8SJoe Carnuccio 	abts_rsp->ox_id = abts->ox_id;
159576bfde8SJoe Carnuccio 	abts_rsp->payload.ba_acc.aborted_rx_id = abts->rx_id;
160576bfde8SJoe Carnuccio 	abts_rsp->payload.ba_acc.aborted_ox_id = abts->ox_id;
1617ffa5b93SBart Van Assche 	abts_rsp->payload.ba_acc.high_seq_cnt = cpu_to_le16(~0);
162576bfde8SJoe Carnuccio 	abts_rsp->rx_xch_addr_to_abort = abts->rx_xch_addr_to_abort;
163576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init, vha, 0x028b,
164576bfde8SJoe Carnuccio 	    "Sending BA ACC response to ABTS %#x...\n",
165576bfde8SJoe Carnuccio 	    abts->rx_xch_addr_to_abort);
166576bfde8SJoe Carnuccio 	ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
167576bfde8SJoe Carnuccio 	    "-------- ELS RSP -------\n");
168576bfde8SJoe Carnuccio 	ql_dump_buffer(ql_dbg_init + ql_dbg_verbose, vha, 0x028b,
169576bfde8SJoe Carnuccio 	    (uint8_t *)abts_rsp, sizeof(*abts_rsp));
170576bfde8SJoe Carnuccio 	rval = qla2x00_issue_iocb(vha, abts_rsp, dma, 0);
171576bfde8SJoe Carnuccio 	if (rval) {
172576bfde8SJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x028c,
173576bfde8SJoe Carnuccio 		    "%s: iocb failed to execute -> %x\n", __func__, rval);
174576bfde8SJoe Carnuccio 	} else if (abts_rsp->comp_status) {
175576bfde8SJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x028d,
176576bfde8SJoe Carnuccio 		    "%s: iocb failed to complete -> completion=%#x subcode=(%#x,%#x)\n",
177576bfde8SJoe Carnuccio 		    __func__, abts_rsp->comp_status,
178576bfde8SJoe Carnuccio 		    abts_rsp->payload.error.subcode1,
179576bfde8SJoe Carnuccio 		    abts_rsp->payload.error.subcode2);
180576bfde8SJoe Carnuccio 	} else {
181576bfde8SJoe Carnuccio 		ql_dbg(ql_dbg_init, vha, 0x028ea,
182576bfde8SJoe Carnuccio 		    "%s: done.\n", __func__);
183576bfde8SJoe Carnuccio 	}
184576bfde8SJoe Carnuccio 
185576bfde8SJoe Carnuccio 	dma_free_coherent(&ha->pdev->dev, sizeof(*rsp_els), rsp_els, dma);
186576bfde8SJoe Carnuccio }
187576bfde8SJoe Carnuccio 
1881da177e4SLinus Torvalds /**
189fac28079SQuinn Tran  * __qla_consume_iocb - this routine is used to tell fw driver has processed
190fac28079SQuinn Tran  *   or consumed the head IOCB along with the continuation IOCB's from the
191fac28079SQuinn Tran  *   provided respond queue.
192fac28079SQuinn Tran  * @vha: host adapter pointer
193fac28079SQuinn Tran  * @pkt: pointer to current packet.  On return, this pointer shall move
194fac28079SQuinn Tran  *       to the next packet.
195fac28079SQuinn Tran  * @rsp: respond queue pointer.
196fac28079SQuinn Tran  *
197fac28079SQuinn Tran  * it is assumed pkt is the head iocb, not the continuation iocbk
198fac28079SQuinn Tran  */
__qla_consume_iocb(struct scsi_qla_host * vha,void ** pkt,struct rsp_que ** rsp)199fac28079SQuinn Tran void __qla_consume_iocb(struct scsi_qla_host *vha,
200fac28079SQuinn Tran 	void **pkt, struct rsp_que **rsp)
201fac28079SQuinn Tran {
202fac28079SQuinn Tran 	struct rsp_que *rsp_q = *rsp;
203fac28079SQuinn Tran 	response_t *new_pkt;
204fac28079SQuinn Tran 	uint16_t entry_count_remaining;
205fac28079SQuinn Tran 	struct purex_entry_24xx *purex = *pkt;
206fac28079SQuinn Tran 
207fac28079SQuinn Tran 	entry_count_remaining = purex->entry_count;
208fac28079SQuinn Tran 	while (entry_count_remaining > 0) {
209fac28079SQuinn Tran 		new_pkt = rsp_q->ring_ptr;
210fac28079SQuinn Tran 		*pkt = new_pkt;
211fac28079SQuinn Tran 
212fac28079SQuinn Tran 		rsp_q->ring_index++;
213fac28079SQuinn Tran 		if (rsp_q->ring_index == rsp_q->length) {
214fac28079SQuinn Tran 			rsp_q->ring_index = 0;
215fac28079SQuinn Tran 			rsp_q->ring_ptr = rsp_q->ring;
216fac28079SQuinn Tran 		} else {
217fac28079SQuinn Tran 			rsp_q->ring_ptr++;
218fac28079SQuinn Tran 		}
219fac28079SQuinn Tran 
220fac28079SQuinn Tran 		new_pkt->signature = RESPONSE_PROCESSED;
221fac28079SQuinn Tran 		/* flush signature */
222fac28079SQuinn Tran 		wmb();
223fac28079SQuinn Tran 		--entry_count_remaining;
224fac28079SQuinn Tran 	}
225fac28079SQuinn Tran }
226fac28079SQuinn Tran 
227fac28079SQuinn Tran /**
228fac28079SQuinn Tran  * __qla_copy_purex_to_buffer - extract ELS payload from Purex IOCB
229fac28079SQuinn Tran  *    and save to provided buffer
230fac28079SQuinn Tran  * @vha: host adapter pointer
231fac28079SQuinn Tran  * @pkt: pointer Purex IOCB
232fac28079SQuinn Tran  * @rsp: respond queue
233fac28079SQuinn Tran  * @buf: extracted ELS payload copy here
234fac28079SQuinn Tran  * @buf_len: buffer length
235fac28079SQuinn Tran  */
__qla_copy_purex_to_buffer(struct scsi_qla_host * vha,void ** pkt,struct rsp_que ** rsp,u8 * buf,u32 buf_len)236fac28079SQuinn Tran int __qla_copy_purex_to_buffer(struct scsi_qla_host *vha,
237fac28079SQuinn Tran 	void **pkt, struct rsp_que **rsp, u8 *buf, u32 buf_len)
238fac28079SQuinn Tran {
239fac28079SQuinn Tran 	struct purex_entry_24xx *purex = *pkt;
240fac28079SQuinn Tran 	struct rsp_que *rsp_q = *rsp;
241fac28079SQuinn Tran 	sts_cont_entry_t *new_pkt;
242fac28079SQuinn Tran 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
243fac28079SQuinn Tran 	uint16_t buffer_copy_offset = 0;
244fac28079SQuinn Tran 	uint16_t entry_count_remaining;
245fac28079SQuinn Tran 	u16 tpad;
246fac28079SQuinn Tran 
247fac28079SQuinn Tran 	entry_count_remaining = purex->entry_count;
248fac28079SQuinn Tran 	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
249fac28079SQuinn Tran 		- PURX_ELS_HEADER_SIZE;
250fac28079SQuinn Tran 
251fac28079SQuinn Tran 	/*
252fac28079SQuinn Tran 	 * end of payload may not end in 4bytes boundary.  Need to
253fac28079SQuinn Tran 	 * round up / pad for room to swap, before saving data
254fac28079SQuinn Tran 	 */
255fac28079SQuinn Tran 	tpad = roundup(total_bytes, 4);
256fac28079SQuinn Tran 
257fac28079SQuinn Tran 	if (buf_len < tpad) {
258fac28079SQuinn Tran 		ql_dbg(ql_dbg_async, vha, 0x5084,
259fac28079SQuinn Tran 		    "%s buffer is too small %d < %d\n",
260fac28079SQuinn Tran 		    __func__, buf_len, tpad);
261fac28079SQuinn Tran 		__qla_consume_iocb(vha, pkt, rsp);
262fac28079SQuinn Tran 		return -EIO;
263fac28079SQuinn Tran 	}
264fac28079SQuinn Tran 
265fac28079SQuinn Tran 	pending_bytes = total_bytes = tpad;
266fac28079SQuinn Tran 	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
267fac28079SQuinn Tran 	    sizeof(purex->els_frame_payload) : pending_bytes;
268fac28079SQuinn Tran 
269fac28079SQuinn Tran 	memcpy(buf, &purex->els_frame_payload[0], no_bytes);
270fac28079SQuinn Tran 	buffer_copy_offset += no_bytes;
271fac28079SQuinn Tran 	pending_bytes -= no_bytes;
272fac28079SQuinn Tran 	--entry_count_remaining;
273fac28079SQuinn Tran 
274fac28079SQuinn Tran 	((response_t *)purex)->signature = RESPONSE_PROCESSED;
275fac28079SQuinn Tran 	/* flush signature */
276fac28079SQuinn Tran 	wmb();
277fac28079SQuinn Tran 
278fac28079SQuinn Tran 	do {
279fac28079SQuinn Tran 		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
280fac28079SQuinn Tran 			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
281fac28079SQuinn Tran 			*pkt = new_pkt;
282fac28079SQuinn Tran 
283fac28079SQuinn Tran 			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
284fac28079SQuinn Tran 				ql_log(ql_log_warn, vha, 0x507a,
285fac28079SQuinn Tran 				    "Unexpected IOCB type, partial data 0x%x\n",
286fac28079SQuinn Tran 				    buffer_copy_offset);
287fac28079SQuinn Tran 				break;
288fac28079SQuinn Tran 			}
289fac28079SQuinn Tran 
290fac28079SQuinn Tran 			rsp_q->ring_index++;
291fac28079SQuinn Tran 			if (rsp_q->ring_index == rsp_q->length) {
292fac28079SQuinn Tran 				rsp_q->ring_index = 0;
293fac28079SQuinn Tran 				rsp_q->ring_ptr = rsp_q->ring;
294fac28079SQuinn Tran 			} else {
295fac28079SQuinn Tran 				rsp_q->ring_ptr++;
296fac28079SQuinn Tran 			}
297fac28079SQuinn Tran 			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
298fac28079SQuinn Tran 			    sizeof(new_pkt->data) : pending_bytes;
299fac28079SQuinn Tran 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
300fac28079SQuinn Tran 				memcpy((buf + buffer_copy_offset), new_pkt->data,
301fac28079SQuinn Tran 				    no_bytes);
302fac28079SQuinn Tran 				buffer_copy_offset += no_bytes;
303fac28079SQuinn Tran 				pending_bytes -= no_bytes;
304fac28079SQuinn Tran 				--entry_count_remaining;
305fac28079SQuinn Tran 			} else {
306fac28079SQuinn Tran 				ql_log(ql_log_warn, vha, 0x5044,
307fac28079SQuinn Tran 				    "Attempt to copy more that we got, optimizing..%x\n",
308fac28079SQuinn Tran 				    buffer_copy_offset);
309fac28079SQuinn Tran 				memcpy((buf + buffer_copy_offset), new_pkt->data,
310fac28079SQuinn Tran 				    total_bytes - buffer_copy_offset);
311fac28079SQuinn Tran 			}
312fac28079SQuinn Tran 
313fac28079SQuinn Tran 			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
314fac28079SQuinn Tran 			/* flush signature */
315fac28079SQuinn Tran 			wmb();
316fac28079SQuinn Tran 		}
317fac28079SQuinn Tran 
318fac28079SQuinn Tran 		if (pending_bytes != 0 || entry_count_remaining != 0) {
319fac28079SQuinn Tran 			ql_log(ql_log_fatal, vha, 0x508b,
320fac28079SQuinn Tran 			    "Dropping partial Data, underrun bytes = 0x%x, entry cnts 0x%x\n",
321fac28079SQuinn Tran 			    total_bytes, entry_count_remaining);
322fac28079SQuinn Tran 			return -EIO;
323fac28079SQuinn Tran 		}
324fac28079SQuinn Tran 	} while (entry_count_remaining > 0);
325fac28079SQuinn Tran 
326fac28079SQuinn Tran 	be32_to_cpu_array((u32 *)buf, (__be32 *)buf, total_bytes >> 2);
327fac28079SQuinn Tran 
328fac28079SQuinn Tran 	return 0;
329fac28079SQuinn Tran }
330fac28079SQuinn Tran 
331fac28079SQuinn Tran /**
3321da177e4SLinus Torvalds  * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
333807eb907SBart Van Assche  * @irq: interrupt number
3341da177e4SLinus Torvalds  * @dev_id: SCSI driver HA context
3351da177e4SLinus Torvalds  *
3361da177e4SLinus Torvalds  * Called by system whenever the host adapter generates an interrupt.
3371da177e4SLinus Torvalds  *
3381da177e4SLinus Torvalds  * Returns handled flag.
3391da177e4SLinus Torvalds  */
3401da177e4SLinus Torvalds irqreturn_t
qla2100_intr_handler(int irq,void * dev_id)3417d12e780SDavid Howells qla2100_intr_handler(int irq, void *dev_id)
3421da177e4SLinus Torvalds {
343e315cd28SAnirban Chakraborty 	scsi_qla_host_t	*vha;
344e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha;
3453d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg;
3461da177e4SLinus Torvalds 	int		status;
3471da177e4SLinus Torvalds 	unsigned long	iter;
34814e660e6SSeokmann Ju 	uint16_t	hccr;
3490a59cea4SBart Van Assche 	uint16_t	mb[8];
350e315cd28SAnirban Chakraborty 	struct rsp_que *rsp;
35143fac4d9SAnirban Chakraborty 	unsigned long	flags;
3521da177e4SLinus Torvalds 
353e315cd28SAnirban Chakraborty 	rsp = (struct rsp_que *) dev_id;
354e315cd28SAnirban Chakraborty 	if (!rsp) {
3553256b435SChad Dupuis 		ql_log(ql_log_info, NULL, 0x505d,
3563256b435SChad Dupuis 		    "%s: NULL response queue pointer.\n", __func__);
3571da177e4SLinus Torvalds 		return (IRQ_NONE);
3581da177e4SLinus Torvalds 	}
3591da177e4SLinus Torvalds 
360e315cd28SAnirban Chakraborty 	ha = rsp->hw;
3613d71644cSAndrew Vasquez 	reg = &ha->iobase->isp;
3621da177e4SLinus Torvalds 	status = 0;
3631da177e4SLinus Torvalds 
36443fac4d9SAnirban Chakraborty 	spin_lock_irqsave(&ha->hardware_lock, flags);
3652afa19a9SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
3661da177e4SLinus Torvalds 	for (iter = 50; iter--; ) {
36704474d3aSBart Van Assche 		hccr = rd_reg_word(&reg->hccr);
368c821e0d5SJoe Lawrence 		if (qla2x00_check_reg16_for_disconnect(vha, hccr))
369f3ddac19SChad Dupuis 			break;
37014e660e6SSeokmann Ju 		if (hccr & HCCR_RISC_PAUSE) {
37114e660e6SSeokmann Ju 			if (pci_channel_offline(ha->pdev))
37214e660e6SSeokmann Ju 				break;
37314e660e6SSeokmann Ju 
37414e660e6SSeokmann Ju 			/*
37514e660e6SSeokmann Ju 			 * Issue a "HARD" reset in order for the RISC interrupt
376a06a0f8eSJustin P. Mattock 			 * bit to be cleared.  Schedule a big hammer to get
37714e660e6SSeokmann Ju 			 * out of the RISC PAUSED state.
37814e660e6SSeokmann Ju 			 */
37904474d3aSBart Van Assche 			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
38004474d3aSBart Van Assche 			rd_reg_word(&reg->hccr);
38114e660e6SSeokmann Ju 
3828ae17876SBart Van Assche 			ha->isp_ops->fw_dump(vha);
383e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
38414e660e6SSeokmann Ju 			break;
38504474d3aSBart Van Assche 		} else if ((rd_reg_word(&reg->istatus) & ISR_RISC_INT) == 0)
3861da177e4SLinus Torvalds 			break;
3871da177e4SLinus Torvalds 
38804474d3aSBart Van Assche 		if (rd_reg_word(&reg->semaphore) & BIT_0) {
38904474d3aSBart Van Assche 			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
39004474d3aSBart Van Assche 			rd_reg_word(&reg->hccr);
3911da177e4SLinus Torvalds 
3921da177e4SLinus Torvalds 			/* Get mailbox data. */
3939a853f71SAndrew Vasquez 			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
3949a853f71SAndrew Vasquez 			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
395e315cd28SAnirban Chakraborty 				qla2x00_mbx_completion(vha, mb[0]);
3961da177e4SLinus Torvalds 				status |= MBX_INTERRUPT;
3979a853f71SAndrew Vasquez 			} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
3989a853f71SAndrew Vasquez 				mb[1] = RD_MAILBOX_REG(ha, reg, 1);
3999a853f71SAndrew Vasquez 				mb[2] = RD_MAILBOX_REG(ha, reg, 2);
4009a853f71SAndrew Vasquez 				mb[3] = RD_MAILBOX_REG(ha, reg, 3);
40173208dfdSAnirban Chakraborty 				qla2x00_async_event(vha, rsp, mb);
4021da177e4SLinus Torvalds 			} else {
4031da177e4SLinus Torvalds 				/*EMPTY*/
4047c3df132SSaurav Kashyap 				ql_dbg(ql_dbg_async, vha, 0x5025,
4057c3df132SSaurav Kashyap 				    "Unrecognized interrupt type (%d).\n",
4067c3df132SSaurav Kashyap 				    mb[0]);
4071da177e4SLinus Torvalds 			}
4081da177e4SLinus Torvalds 			/* Release mailbox registers. */
40904474d3aSBart Van Assche 			wrt_reg_word(&reg->semaphore, 0);
41004474d3aSBart Van Assche 			rd_reg_word(&reg->semaphore);
4111da177e4SLinus Torvalds 		} else {
41273208dfdSAnirban Chakraborty 			qla2x00_process_response_queue(rsp);
4131da177e4SLinus Torvalds 
41404474d3aSBart Van Assche 			wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
41504474d3aSBart Van Assche 			rd_reg_word(&reg->hccr);
4161da177e4SLinus Torvalds 		}
4171da177e4SLinus Torvalds 	}
41836439832Sgurinder.shergill@hp.com 	qla2x00_handle_mbx_completion(ha, status);
41943fac4d9SAnirban Chakraborty 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4201da177e4SLinus Torvalds 
4211da177e4SLinus Torvalds 	return (IRQ_HANDLED);
4221da177e4SLinus Torvalds }
4231da177e4SLinus Torvalds 
424f3ddac19SChad Dupuis bool
qla2x00_check_reg32_for_disconnect(scsi_qla_host_t * vha,uint32_t reg)425c821e0d5SJoe Lawrence qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
426f3ddac19SChad Dupuis {
427f3ddac19SChad Dupuis 	/* Check for PCI disconnection */
428a30c2a3bSThadeu Lima de Souza Cascardo 	if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) {
429beb9e315SJoe Lawrence 		if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
4306b383979SJoe Lawrence 		    !test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
4316b383979SJoe Lawrence 		    !test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
432f7a0ed47SQuinn Tran 			qla_schedule_eeh_work(vha);
433232792b6SJoe Lawrence 		}
434f3ddac19SChad Dupuis 		return true;
435f3ddac19SChad Dupuis 	} else
436f3ddac19SChad Dupuis 		return false;
437f3ddac19SChad Dupuis }
438f3ddac19SChad Dupuis 
439c821e0d5SJoe Lawrence bool
qla2x00_check_reg16_for_disconnect(scsi_qla_host_t * vha,uint16_t reg)440c821e0d5SJoe Lawrence qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
441c821e0d5SJoe Lawrence {
442c821e0d5SJoe Lawrence 	return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg);
443c821e0d5SJoe Lawrence }
444c821e0d5SJoe Lawrence 
4451da177e4SLinus Torvalds /**
4461da177e4SLinus Torvalds  * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
447807eb907SBart Van Assche  * @irq: interrupt number
4481da177e4SLinus Torvalds  * @dev_id: SCSI driver HA context
4491da177e4SLinus Torvalds  *
4501da177e4SLinus Torvalds  * Called by system whenever the host adapter generates an interrupt.
4511da177e4SLinus Torvalds  *
4521da177e4SLinus Torvalds  * Returns handled flag.
4531da177e4SLinus Torvalds  */
4541da177e4SLinus Torvalds irqreturn_t
qla2300_intr_handler(int irq,void * dev_id)4557d12e780SDavid Howells qla2300_intr_handler(int irq, void *dev_id)
4561da177e4SLinus Torvalds {
457e315cd28SAnirban Chakraborty 	scsi_qla_host_t	*vha;
4583d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg;
4591da177e4SLinus Torvalds 	int		status;
4601da177e4SLinus Torvalds 	unsigned long	iter;
4611da177e4SLinus Torvalds 	uint32_t	stat;
4621da177e4SLinus Torvalds 	uint16_t	hccr;
4630a59cea4SBart Van Assche 	uint16_t	mb[8];
464e315cd28SAnirban Chakraborty 	struct rsp_que *rsp;
465e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha;
46643fac4d9SAnirban Chakraborty 	unsigned long	flags;
4671da177e4SLinus Torvalds 
468e315cd28SAnirban Chakraborty 	rsp = (struct rsp_que *) dev_id;
469e315cd28SAnirban Chakraborty 	if (!rsp) {
4703256b435SChad Dupuis 		ql_log(ql_log_info, NULL, 0x5058,
4713256b435SChad Dupuis 		    "%s: NULL response queue pointer.\n", __func__);
4721da177e4SLinus Torvalds 		return (IRQ_NONE);
4731da177e4SLinus Torvalds 	}
4741da177e4SLinus Torvalds 
475e315cd28SAnirban Chakraborty 	ha = rsp->hw;
4763d71644cSAndrew Vasquez 	reg = &ha->iobase->isp;
4771da177e4SLinus Torvalds 	status = 0;
4781da177e4SLinus Torvalds 
47943fac4d9SAnirban Chakraborty 	spin_lock_irqsave(&ha->hardware_lock, flags);
4802afa19a9SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
4811da177e4SLinus Torvalds 	for (iter = 50; iter--; ) {
48204474d3aSBart Van Assche 		stat = rd_reg_dword(&reg->u.isp2300.host_status);
483c821e0d5SJoe Lawrence 		if (qla2x00_check_reg32_for_disconnect(vha, stat))
484f3ddac19SChad Dupuis 			break;
4851da177e4SLinus Torvalds 		if (stat & HSR_RISC_PAUSED) {
48685880801SAndrew Vasquez 			if (unlikely(pci_channel_offline(ha->pdev)))
48714e660e6SSeokmann Ju 				break;
48814e660e6SSeokmann Ju 
48904474d3aSBart Van Assche 			hccr = rd_reg_word(&reg->hccr);
490f3ddac19SChad Dupuis 
4911da177e4SLinus Torvalds 			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
4927c3df132SSaurav Kashyap 				ql_log(ql_log_warn, vha, 0x5026,
4937c3df132SSaurav Kashyap 				    "Parity error -- HCCR=%x, Dumping "
4947c3df132SSaurav Kashyap 				    "firmware.\n", hccr);
4951da177e4SLinus Torvalds 			else
4967c3df132SSaurav Kashyap 				ql_log(ql_log_warn, vha, 0x5027,
4977c3df132SSaurav Kashyap 				    "RISC paused -- HCCR=%x, Dumping "
4987c3df132SSaurav Kashyap 				    "firmware.\n", hccr);
4991da177e4SLinus Torvalds 
5001da177e4SLinus Torvalds 			/*
5011da177e4SLinus Torvalds 			 * Issue a "HARD" reset in order for the RISC
5021da177e4SLinus Torvalds 			 * interrupt bit to be cleared.  Schedule a big
503a06a0f8eSJustin P. Mattock 			 * hammer to get out of the RISC PAUSED state.
5041da177e4SLinus Torvalds 			 */
50504474d3aSBart Van Assche 			wrt_reg_word(&reg->hccr, HCCR_RESET_RISC);
50604474d3aSBart Van Assche 			rd_reg_word(&reg->hccr);
50707f31805SAndrew Vasquez 
5088ae17876SBart Van Assche 			ha->isp_ops->fw_dump(vha);
509e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
5101da177e4SLinus Torvalds 			break;
5111da177e4SLinus Torvalds 		} else if ((stat & HSR_RISC_INT) == 0)
5121da177e4SLinus Torvalds 			break;
5131da177e4SLinus Torvalds 
5141da177e4SLinus Torvalds 		switch (stat & 0xff) {
5151da177e4SLinus Torvalds 		case 0x1:
5161da177e4SLinus Torvalds 		case 0x2:
5171da177e4SLinus Torvalds 		case 0x10:
5181da177e4SLinus Torvalds 		case 0x11:
519e315cd28SAnirban Chakraborty 			qla2x00_mbx_completion(vha, MSW(stat));
5201da177e4SLinus Torvalds 			status |= MBX_INTERRUPT;
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds 			/* Release mailbox registers. */
52304474d3aSBart Van Assche 			wrt_reg_word(&reg->semaphore, 0);
5241da177e4SLinus Torvalds 			break;
5251da177e4SLinus Torvalds 		case 0x12:
5269a853f71SAndrew Vasquez 			mb[0] = MSW(stat);
5279a853f71SAndrew Vasquez 			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
5289a853f71SAndrew Vasquez 			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
5299a853f71SAndrew Vasquez 			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
53073208dfdSAnirban Chakraborty 			qla2x00_async_event(vha, rsp, mb);
5319a853f71SAndrew Vasquez 			break;
5329a853f71SAndrew Vasquez 		case 0x13:
53373208dfdSAnirban Chakraborty 			qla2x00_process_response_queue(rsp);
5341da177e4SLinus Torvalds 			break;
5351da177e4SLinus Torvalds 		case 0x15:
5369a853f71SAndrew Vasquez 			mb[0] = MBA_CMPLT_1_16BIT;
5379a853f71SAndrew Vasquez 			mb[1] = MSW(stat);
53873208dfdSAnirban Chakraborty 			qla2x00_async_event(vha, rsp, mb);
5391da177e4SLinus Torvalds 			break;
5401da177e4SLinus Torvalds 		case 0x16:
5419a853f71SAndrew Vasquez 			mb[0] = MBA_SCSI_COMPLETION;
5429a853f71SAndrew Vasquez 			mb[1] = MSW(stat);
5439a853f71SAndrew Vasquez 			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
54473208dfdSAnirban Chakraborty 			qla2x00_async_event(vha, rsp, mb);
5451da177e4SLinus Torvalds 			break;
5461da177e4SLinus Torvalds 		default:
5477c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5028,
5487c3df132SSaurav Kashyap 			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
5491da177e4SLinus Torvalds 			break;
5501da177e4SLinus Torvalds 		}
55104474d3aSBart Van Assche 		wrt_reg_word(&reg->hccr, HCCR_CLR_RISC_INT);
55204474d3aSBart Van Assche 		rd_reg_word_relaxed(&reg->hccr);
5531da177e4SLinus Torvalds 	}
55436439832Sgurinder.shergill@hp.com 	qla2x00_handle_mbx_completion(ha, status);
55543fac4d9SAnirban Chakraborty 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
5561da177e4SLinus Torvalds 
5571da177e4SLinus Torvalds 	return (IRQ_HANDLED);
5581da177e4SLinus Torvalds }
5591da177e4SLinus Torvalds 
5601da177e4SLinus Torvalds /**
5611da177e4SLinus Torvalds  * qla2x00_mbx_completion() - Process mailbox command completions.
5622db6228dSBart Van Assche  * @vha: SCSI driver HA context
5631da177e4SLinus Torvalds  * @mb0: Mailbox0 register
5641da177e4SLinus Torvalds  */
5651da177e4SLinus Torvalds static void
qla2x00_mbx_completion(scsi_qla_host_t * vha,uint16_t mb0)566e315cd28SAnirban Chakraborty qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds 	uint16_t	cnt;
5694fa94f83SAndrew Vasquez 	uint32_t	mboxes;
5707ffa5b93SBart Van Assche 	__le16 __iomem *wptr;
571e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
5723d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
5731da177e4SLinus Torvalds 
5744fa94f83SAndrew Vasquez 	/* Read all mbox registers? */
575c02189e1SBart Van Assche 	WARN_ON_ONCE(ha->mbx_count > 32);
576c02189e1SBart Van Assche 	mboxes = (1ULL << ha->mbx_count) - 1;
5774fa94f83SAndrew Vasquez 	if (!ha->mcp)
578a720101dSMasanari Iida 		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
5794fa94f83SAndrew Vasquez 	else
5804fa94f83SAndrew Vasquez 		mboxes = ha->mcp->in_mb;
5814fa94f83SAndrew Vasquez 
5821da177e4SLinus Torvalds 	/* Load return mailbox registers. */
5831da177e4SLinus Torvalds 	ha->flags.mbox_int = 1;
5841da177e4SLinus Torvalds 	ha->mailbox_out[0] = mb0;
5854fa94f83SAndrew Vasquez 	mboxes >>= 1;
5867ffa5b93SBart Van Assche 	wptr = MAILBOX_REG(ha, reg, 1);
5871da177e4SLinus Torvalds 
5881da177e4SLinus Torvalds 	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
5891da177e4SLinus Torvalds 		if (IS_QLA2200(ha) && cnt == 8)
5907ffa5b93SBart Van Assche 			wptr = MAILBOX_REG(ha, reg, 8);
5914fa94f83SAndrew Vasquez 		if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
5921da177e4SLinus Torvalds 			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
5934fa94f83SAndrew Vasquez 		else if (mboxes & BIT_0)
59404474d3aSBart Van Assche 			ha->mailbox_out[cnt] = rd_reg_word(wptr);
5951da177e4SLinus Torvalds 
5961da177e4SLinus Torvalds 		wptr++;
5974fa94f83SAndrew Vasquez 		mboxes >>= 1;
5981da177e4SLinus Torvalds 	}
5991da177e4SLinus Torvalds }
6001da177e4SLinus Torvalds 
6018a659571SAndrew Vasquez static void
qla81xx_idc_event(scsi_qla_host_t * vha,uint16_t aen,uint16_t descr)6028a659571SAndrew Vasquez qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
6038a659571SAndrew Vasquez {
6048a659571SAndrew Vasquez 	static char *event[] =
6058a659571SAndrew Vasquez 		{ "Complete", "Request Notification", "Time Extension" };
6068a659571SAndrew Vasquez 	int rval;
6078a659571SAndrew Vasquez 	struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
6089e5054ecSChad Dupuis 	struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
60937139da1SBart Van Assche 	__le16 __iomem *wptr;
6108a659571SAndrew Vasquez 	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
6118a659571SAndrew Vasquez 
6128a659571SAndrew Vasquez 	/* Seed data -- mailbox1 -> mailbox7. */
6139e5054ecSChad Dupuis 	if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
6147ffa5b93SBart Van Assche 		wptr = &reg24->mailbox1;
6159e5054ecSChad Dupuis 	else if (IS_QLA8044(vha->hw))
6167ffa5b93SBart Van Assche 		wptr = &reg82->mailbox_out[1];
6179e5054ecSChad Dupuis 	else
6189e5054ecSChad Dupuis 		return;
6199e5054ecSChad Dupuis 
6208a659571SAndrew Vasquez 	for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
62104474d3aSBart Van Assche 		mb[cnt] = rd_reg_word(wptr);
6228a659571SAndrew Vasquez 
6237c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_async, vha, 0x5021,
6246246b8a1SGiridhar Malavali 	    "Inter-Driver Communication %s -- "
6257c3df132SSaurav Kashyap 	    "%04x %04x %04x %04x %04x %04x %04x.\n",
6267c3df132SSaurav Kashyap 	    event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
6277c3df132SSaurav Kashyap 	    mb[4], mb[5], mb[6]);
628454073c9SSantosh Vernekar 	switch (aen) {
629454073c9SSantosh Vernekar 	/* Handle IDC Error completion case. */
630454073c9SSantosh Vernekar 	case MBA_IDC_COMPLETE:
631454073c9SSantosh Vernekar 		if (mb[1] >> 15) {
632bf5b8ad7SChad Dupuis 			vha->hw->flags.idc_compl_status = 1;
6339aaf2ceaSChad Dupuis 			if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
634bf5b8ad7SChad Dupuis 				complete(&vha->hw->dcbx_comp);
635bf5b8ad7SChad Dupuis 		}
636454073c9SSantosh Vernekar 		break;
6378a659571SAndrew Vasquez 
638454073c9SSantosh Vernekar 	case MBA_IDC_NOTIFY:
6398a659571SAndrew Vasquez 		/* Acknowledgement needed? [Notify && non-zero timeout]. */
6408a659571SAndrew Vasquez 		timeout = (descr >> 8) & 0xf;
6417c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5022,
642d8424f68SJoe Perches 		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
6437c3df132SSaurav Kashyap 		    vha->host_no, event[aen & 0xff], timeout);
6448a659571SAndrew Vasquez 
645454073c9SSantosh Vernekar 		if (!timeout)
646454073c9SSantosh Vernekar 			return;
6478a659571SAndrew Vasquez 		rval = qla2x00_post_idc_ack_work(vha, mb);
6488a659571SAndrew Vasquez 		if (rval != QLA_SUCCESS)
6497c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x5023,
6508a659571SAndrew Vasquez 			    "IDC failed to post ACK.\n");
651454073c9SSantosh Vernekar 		break;
652454073c9SSantosh Vernekar 	case MBA_IDC_TIME_EXT:
653454073c9SSantosh Vernekar 		vha->hw->idc_extend_tmo = descr;
654454073c9SSantosh Vernekar 		ql_dbg(ql_dbg_async, vha, 0x5087,
655454073c9SSantosh Vernekar 		    "%lu Inter-Driver Communication %s -- "
656454073c9SSantosh Vernekar 		    "Extend timeout by=%d.\n",
657454073c9SSantosh Vernekar 		    vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
658454073c9SSantosh Vernekar 		break;
659454073c9SSantosh Vernekar 	}
6608a659571SAndrew Vasquez }
6618a659571SAndrew Vasquez 
662daae62a3SChad Dupuis #define LS_UNKNOWN	2
663d0297c9aSJoe Carnuccio const char *
qla2x00_get_link_speed_str(struct qla_hw_data * ha,uint16_t speed)664d0297c9aSJoe Carnuccio qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
665daae62a3SChad Dupuis {
666d0297c9aSJoe Carnuccio 	static const char *const link_speeds[] = {
66785818882SQuinn Tran 		"1", "2", "?", "4", "8", "16", "32", "64", "10"
668d0297c9aSJoe Carnuccio 	};
669b0a1c5b5SBart Van Assche #define	QLA_LAST_SPEED (ARRAY_SIZE(link_speeds) - 1)
670daae62a3SChad Dupuis 
671daae62a3SChad Dupuis 	if (IS_QLA2100(ha) || IS_QLA2200(ha))
672d0297c9aSJoe Carnuccio 		return link_speeds[0];
673d0297c9aSJoe Carnuccio 	else if (speed == 0x13)
674f73cb695SChad Dupuis 		return link_speeds[QLA_LAST_SPEED];
675f73cb695SChad Dupuis 	else if (speed < QLA_LAST_SPEED)
676d0297c9aSJoe Carnuccio 		return link_speeds[speed];
677d0297c9aSJoe Carnuccio 	else
678d0297c9aSJoe Carnuccio 		return link_speeds[LS_UNKNOWN];
679daae62a3SChad Dupuis }
680daae62a3SChad Dupuis 
681fa492630SSaurav Kashyap static void
qla83xx_handle_8200_aen(scsi_qla_host_t * vha,uint16_t * mb)6827d613ac6SSantosh Vernekar qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
6837d613ac6SSantosh Vernekar {
6847d613ac6SSantosh Vernekar 	struct qla_hw_data *ha = vha->hw;
6857d613ac6SSantosh Vernekar 
6867d613ac6SSantosh Vernekar 	/*
6877d613ac6SSantosh Vernekar 	 * 8200 AEN Interpretation:
6887d613ac6SSantosh Vernekar 	 * mb[0] = AEN code
6897d613ac6SSantosh Vernekar 	 * mb[1] = AEN Reason code
6907d613ac6SSantosh Vernekar 	 * mb[2] = LSW of Peg-Halt Status-1 Register
6917d613ac6SSantosh Vernekar 	 * mb[6] = MSW of Peg-Halt Status-1 Register
6927d613ac6SSantosh Vernekar 	 * mb[3] = LSW of Peg-Halt Status-2 register
6937d613ac6SSantosh Vernekar 	 * mb[7] = MSW of Peg-Halt Status-2 register
6947d613ac6SSantosh Vernekar 	 * mb[4] = IDC Device-State Register value
6957d613ac6SSantosh Vernekar 	 * mb[5] = IDC Driver-Presence Register value
6967d613ac6SSantosh Vernekar 	 */
6977d613ac6SSantosh Vernekar 	ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
6987d613ac6SSantosh Vernekar 	    "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
6997d613ac6SSantosh Vernekar 	    mb[0], mb[1], mb[2], mb[6]);
7007d613ac6SSantosh Vernekar 	ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
7017d613ac6SSantosh Vernekar 	    "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
7027d613ac6SSantosh Vernekar 	    "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);
7037d613ac6SSantosh Vernekar 
7047d613ac6SSantosh Vernekar 	if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
7057d613ac6SSantosh Vernekar 				IDC_HEARTBEAT_FAILURE)) {
7067d613ac6SSantosh Vernekar 		ha->flags.nic_core_hung = 1;
7077d613ac6SSantosh Vernekar 		ql_log(ql_log_warn, vha, 0x5060,
7087d613ac6SSantosh Vernekar 		    "83XX: F/W Error Reported: Check if reset required.\n");
7097d613ac6SSantosh Vernekar 
7107d613ac6SSantosh Vernekar 		if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
7117d613ac6SSantosh Vernekar 			uint32_t protocol_engine_id, fw_err_code, err_level;
7127d613ac6SSantosh Vernekar 
7137d613ac6SSantosh Vernekar 			/*
7147d613ac6SSantosh Vernekar 			 * IDC_PEG_HALT_STATUS_CHANGE interpretation:
7157d613ac6SSantosh Vernekar 			 *  - PEG-Halt Status-1 Register:
7167d613ac6SSantosh Vernekar 			 *	(LSW = mb[2], MSW = mb[6])
7177d613ac6SSantosh Vernekar 			 *	Bits 0-7   = protocol-engine ID
7187d613ac6SSantosh Vernekar 			 *	Bits 8-28  = f/w error code
7197d613ac6SSantosh Vernekar 			 *	Bits 29-31 = Error-level
7207d613ac6SSantosh Vernekar 			 *	    Error-level 0x1 = Non-Fatal error
7217d613ac6SSantosh Vernekar 			 *	    Error-level 0x2 = Recoverable Fatal error
7227d613ac6SSantosh Vernekar 			 *	    Error-level 0x4 = UnRecoverable Fatal error
7237d613ac6SSantosh Vernekar 			 *  - PEG-Halt Status-2 Register:
7247d613ac6SSantosh Vernekar 			 *	(LSW = mb[3], MSW = mb[7])
7257d613ac6SSantosh Vernekar 			 */
7267d613ac6SSantosh Vernekar 			protocol_engine_id = (mb[2] & 0xff);
7277d613ac6SSantosh Vernekar 			fw_err_code = (((mb[2] & 0xff00) >> 8) |
7287d613ac6SSantosh Vernekar 			    ((mb[6] & 0x1fff) << 8));
7297d613ac6SSantosh Vernekar 			err_level = ((mb[6] & 0xe000) >> 13);
7307d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
7317d613ac6SSantosh Vernekar 			    "Register: protocol_engine_id=0x%x "
7327d613ac6SSantosh Vernekar 			    "fw_err_code=0x%x err_level=0x%x.\n",
7337d613ac6SSantosh Vernekar 			    protocol_engine_id, fw_err_code, err_level);
7347d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
7357d613ac6SSantosh Vernekar 			    "Register: 0x%x%x.\n", mb[7], mb[3]);
7367d613ac6SSantosh Vernekar 			if (err_level == ERR_LEVEL_NON_FATAL) {
7377d613ac6SSantosh Vernekar 				ql_log(ql_log_warn, vha, 0x5063,
7380bf0efa1SColin Ian King 				    "Not a fatal error, f/w has recovered itself.\n");
7397d613ac6SSantosh Vernekar 			} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
7407d613ac6SSantosh Vernekar 				ql_log(ql_log_fatal, vha, 0x5064,
7417d613ac6SSantosh Vernekar 				    "Recoverable Fatal error: Chip reset "
7427d613ac6SSantosh Vernekar 				    "required.\n");
7437d613ac6SSantosh Vernekar 				qla83xx_schedule_work(vha,
7447d613ac6SSantosh Vernekar 				    QLA83XX_NIC_CORE_RESET);
7457d613ac6SSantosh Vernekar 			} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
7467d613ac6SSantosh Vernekar 				ql_log(ql_log_fatal, vha, 0x5065,
7477d613ac6SSantosh Vernekar 				    "Unrecoverable Fatal error: Set FAILED "
7487d613ac6SSantosh Vernekar 				    "state, reboot required.\n");
7497d613ac6SSantosh Vernekar 				qla83xx_schedule_work(vha,
7507d613ac6SSantosh Vernekar 				    QLA83XX_NIC_CORE_UNRECOVERABLE);
7517d613ac6SSantosh Vernekar 			}
7527d613ac6SSantosh Vernekar 		}
7537d613ac6SSantosh Vernekar 
7547d613ac6SSantosh Vernekar 		if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
7557d613ac6SSantosh Vernekar 			uint16_t peg_fw_state, nw_interface_link_up;
7567d613ac6SSantosh Vernekar 			uint16_t nw_interface_signal_detect, sfp_status;
7577d613ac6SSantosh Vernekar 			uint16_t htbt_counter, htbt_monitor_enable;
758b4a028a5SColin Ian King 			uint16_t sfp_additional_info, sfp_multirate;
7597d613ac6SSantosh Vernekar 			uint16_t sfp_tx_fault, link_speed, dcbx_status;
7607d613ac6SSantosh Vernekar 
7617d613ac6SSantosh Vernekar 			/*
7627d613ac6SSantosh Vernekar 			 * IDC_NIC_FW_REPORTED_FAILURE interpretation:
7637d613ac6SSantosh Vernekar 			 *  - PEG-to-FC Status Register:
7647d613ac6SSantosh Vernekar 			 *	(LSW = mb[2], MSW = mb[6])
7657d613ac6SSantosh Vernekar 			 *	Bits 0-7   = Peg-Firmware state
7667d613ac6SSantosh Vernekar 			 *	Bit 8      = N/W Interface Link-up
7677d613ac6SSantosh Vernekar 			 *	Bit 9      = N/W Interface signal detected
7687d613ac6SSantosh Vernekar 			 *	Bits 10-11 = SFP Status
7697d613ac6SSantosh Vernekar 			 *	  SFP Status 0x0 = SFP+ transceiver not expected
7707d613ac6SSantosh Vernekar 			 *	  SFP Status 0x1 = SFP+ transceiver not present
7717d613ac6SSantosh Vernekar 			 *	  SFP Status 0x2 = SFP+ transceiver invalid
7727d613ac6SSantosh Vernekar 			 *	  SFP Status 0x3 = SFP+ transceiver present and
7737d613ac6SSantosh Vernekar 			 *	  valid
7747d613ac6SSantosh Vernekar 			 *	Bits 12-14 = Heartbeat Counter
7757d613ac6SSantosh Vernekar 			 *	Bit 15     = Heartbeat Monitor Enable
7767d613ac6SSantosh Vernekar 			 *	Bits 16-17 = SFP Additional Info
7777d613ac6SSantosh Vernekar 			 *	  SFP info 0x0 = Unregocnized transceiver for
7787d613ac6SSantosh Vernekar 			 *	  Ethernet
7797d613ac6SSantosh Vernekar 			 *	  SFP info 0x1 = SFP+ brand validation failed
7807d613ac6SSantosh Vernekar 			 *	  SFP info 0x2 = SFP+ speed validation failed
7817d613ac6SSantosh Vernekar 			 *	  SFP info 0x3 = SFP+ access error
7827d613ac6SSantosh Vernekar 			 *	Bit 18     = SFP Multirate
7837d613ac6SSantosh Vernekar 			 *	Bit 19     = SFP Tx Fault
7847d613ac6SSantosh Vernekar 			 *	Bits 20-22 = Link Speed
7857d613ac6SSantosh Vernekar 			 *	Bits 23-27 = Reserved
7867d613ac6SSantosh Vernekar 			 *	Bits 28-30 = DCBX Status
7877d613ac6SSantosh Vernekar 			 *	  DCBX Status 0x0 = DCBX Disabled
7887d613ac6SSantosh Vernekar 			 *	  DCBX Status 0x1 = DCBX Enabled
7897d613ac6SSantosh Vernekar 			 *	  DCBX Status 0x2 = DCBX Exchange error
7907d613ac6SSantosh Vernekar 			 *	Bit 31     = Reserved
7917d613ac6SSantosh Vernekar 			 */
7927d613ac6SSantosh Vernekar 			peg_fw_state = (mb[2] & 0x00ff);
7937d613ac6SSantosh Vernekar 			nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
7947d613ac6SSantosh Vernekar 			nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
7957d613ac6SSantosh Vernekar 			sfp_status = ((mb[2] & 0x0c00) >> 10);
7967d613ac6SSantosh Vernekar 			htbt_counter = ((mb[2] & 0x7000) >> 12);
7977d613ac6SSantosh Vernekar 			htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
798b4a028a5SColin Ian King 			sfp_additional_info = (mb[6] & 0x0003);
7997d613ac6SSantosh Vernekar 			sfp_multirate = ((mb[6] & 0x0004) >> 2);
8007d613ac6SSantosh Vernekar 			sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
8017d613ac6SSantosh Vernekar 			link_speed = ((mb[6] & 0x0070) >> 4);
8027d613ac6SSantosh Vernekar 			dcbx_status = ((mb[6] & 0x7000) >> 12);
8037d613ac6SSantosh Vernekar 
8047d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5066,
8057d613ac6SSantosh Vernekar 			    "Peg-to-Fc Status Register:\n"
8067d613ac6SSantosh Vernekar 			    "peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
8077d613ac6SSantosh Vernekar 			    "nw_interface_signal_detect=0x%x"
8087d613ac6SSantosh Vernekar 			    "\nsfp_statis=0x%x.\n ", peg_fw_state,
8097d613ac6SSantosh Vernekar 			    nw_interface_link_up, nw_interface_signal_detect,
8107d613ac6SSantosh Vernekar 			    sfp_status);
8117d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5067,
8127d613ac6SSantosh Vernekar 			    "htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
813b4a028a5SColin Ian King 			    "sfp_additional_info=0x%x, sfp_multirate=0x%x.\n ",
8147d613ac6SSantosh Vernekar 			    htbt_counter, htbt_monitor_enable,
815b4a028a5SColin Ian King 			    sfp_additional_info, sfp_multirate);
8167d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5068,
8177d613ac6SSantosh Vernekar 			    "sfp_tx_fault=0x%x, link_state=0x%x, "
8187d613ac6SSantosh Vernekar 			    "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
8197d613ac6SSantosh Vernekar 			    dcbx_status);
8207d613ac6SSantosh Vernekar 
8217d613ac6SSantosh Vernekar 			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
8227d613ac6SSantosh Vernekar 		}
8237d613ac6SSantosh Vernekar 
8247d613ac6SSantosh Vernekar 		if (mb[1] & IDC_HEARTBEAT_FAILURE) {
8257d613ac6SSantosh Vernekar 			ql_log(ql_log_warn, vha, 0x5069,
8267d613ac6SSantosh Vernekar 			    "Heartbeat Failure encountered, chip reset "
8277d613ac6SSantosh Vernekar 			    "required.\n");
8287d613ac6SSantosh Vernekar 
8297d613ac6SSantosh Vernekar 			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
8307d613ac6SSantosh Vernekar 		}
8317d613ac6SSantosh Vernekar 	}
8327d613ac6SSantosh Vernekar 
8337d613ac6SSantosh Vernekar 	if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
8347d613ac6SSantosh Vernekar 		ql_log(ql_log_info, vha, 0x506a,
8357d613ac6SSantosh Vernekar 		    "IDC Device-State changed = 0x%x.\n", mb[4]);
8366c3943cdSSaurav Kashyap 		if (ha->flags.nic_core_reset_owner)
8376c3943cdSSaurav Kashyap 			return;
8387d613ac6SSantosh Vernekar 		qla83xx_schedule_work(vha, MBA_IDC_AEN);
8397d613ac6SSantosh Vernekar 	}
8407d613ac6SSantosh Vernekar }
8417d613ac6SSantosh Vernekar 
842875386b9SManish Rangankar /**
843875386b9SManish Rangankar  * qla27xx_copy_multiple_pkt() - Copy over purex/purls packets that can
844875386b9SManish Rangankar  * span over multiple IOCBs.
845875386b9SManish Rangankar  * @vha: SCSI driver HA context
846875386b9SManish Rangankar  * @pkt: ELS packet
847875386b9SManish Rangankar  * @rsp: Response queue
848875386b9SManish Rangankar  * @is_purls: True, for Unsolicited Received FC-NVMe LS rsp IOCB
849875386b9SManish Rangankar  *            false, for Unsolicited Received ELS IOCB
850875386b9SManish Rangankar  * @byte_order: True, to change the byte ordering of iocb payload
851875386b9SManish Rangankar  */
852875386b9SManish Rangankar struct purex_item *
qla27xx_copy_multiple_pkt(struct scsi_qla_host * vha,void ** pkt,struct rsp_que ** rsp,bool is_purls,bool byte_order)853875386b9SManish Rangankar qla27xx_copy_multiple_pkt(struct scsi_qla_host *vha, void **pkt,
854875386b9SManish Rangankar 			  struct rsp_que **rsp, bool is_purls,
855875386b9SManish Rangankar 			  bool byte_order)
856875386b9SManish Rangankar {
857875386b9SManish Rangankar 	struct purex_entry_24xx *purex = NULL;
858875386b9SManish Rangankar 	struct pt_ls4_rx_unsol *purls = NULL;
859875386b9SManish Rangankar 	struct rsp_que *rsp_q = *rsp;
860875386b9SManish Rangankar 	sts_cont_entry_t *new_pkt;
861875386b9SManish Rangankar 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
862875386b9SManish Rangankar 	uint16_t buffer_copy_offset = 0, payload_size = 0;
863875386b9SManish Rangankar 	uint16_t entry_count, entry_count_remaining;
864875386b9SManish Rangankar 	struct purex_item *item;
865875386b9SManish Rangankar 	void *iocb_pkt = NULL;
866875386b9SManish Rangankar 
867875386b9SManish Rangankar 	if (is_purls) {
868875386b9SManish Rangankar 		purls = *pkt;
869875386b9SManish Rangankar 		total_bytes = (le16_to_cpu(purls->frame_size) & 0x0FFF) -
870875386b9SManish Rangankar 			      PURX_ELS_HEADER_SIZE;
871875386b9SManish Rangankar 		entry_count = entry_count_remaining = purls->entry_count;
872875386b9SManish Rangankar 		payload_size = sizeof(purls->payload);
873875386b9SManish Rangankar 	} else {
874875386b9SManish Rangankar 		purex = *pkt;
875875386b9SManish Rangankar 		total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF) -
876875386b9SManish Rangankar 			      PURX_ELS_HEADER_SIZE;
877875386b9SManish Rangankar 		entry_count = entry_count_remaining = purex->entry_count;
878875386b9SManish Rangankar 		payload_size = sizeof(purex->els_frame_payload);
879875386b9SManish Rangankar 	}
880875386b9SManish Rangankar 
881875386b9SManish Rangankar 	pending_bytes = total_bytes;
882875386b9SManish Rangankar 	no_bytes = (pending_bytes > payload_size) ? payload_size :
883875386b9SManish Rangankar 		   pending_bytes;
884875386b9SManish Rangankar 	ql_dbg(ql_dbg_async, vha, 0x509a,
885875386b9SManish Rangankar 	       "%s LS, frame_size 0x%x, entry count %d\n",
886875386b9SManish Rangankar 	       (is_purls ? "PURLS" : "FPIN"), total_bytes, entry_count);
887875386b9SManish Rangankar 
888875386b9SManish Rangankar 	item = qla24xx_alloc_purex_item(vha, total_bytes);
889875386b9SManish Rangankar 	if (!item)
890875386b9SManish Rangankar 		return item;
891875386b9SManish Rangankar 
892875386b9SManish Rangankar 	iocb_pkt = &item->iocb;
893875386b9SManish Rangankar 
894875386b9SManish Rangankar 	if (is_purls)
895875386b9SManish Rangankar 		memcpy(iocb_pkt, &purls->payload[0], no_bytes);
896875386b9SManish Rangankar 	else
897875386b9SManish Rangankar 		memcpy(iocb_pkt, &purex->els_frame_payload[0], no_bytes);
898875386b9SManish Rangankar 	buffer_copy_offset += no_bytes;
899875386b9SManish Rangankar 	pending_bytes -= no_bytes;
900875386b9SManish Rangankar 	--entry_count_remaining;
901875386b9SManish Rangankar 
902875386b9SManish Rangankar 	if (is_purls)
903875386b9SManish Rangankar 		((response_t *)purls)->signature = RESPONSE_PROCESSED;
904875386b9SManish Rangankar 	else
905875386b9SManish Rangankar 		((response_t *)purex)->signature = RESPONSE_PROCESSED;
906875386b9SManish Rangankar 	wmb();
907875386b9SManish Rangankar 
908875386b9SManish Rangankar 	do {
909875386b9SManish Rangankar 		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
910875386b9SManish Rangankar 			if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
911875386b9SManish Rangankar 				ql_dbg(ql_dbg_async, vha, 0x5084,
912875386b9SManish Rangankar 				       "Ran out of IOCBs, partial data 0x%x\n",
913875386b9SManish Rangankar 				       buffer_copy_offset);
914875386b9SManish Rangankar 				cpu_relax();
915875386b9SManish Rangankar 				continue;
916875386b9SManish Rangankar 			}
917875386b9SManish Rangankar 
918875386b9SManish Rangankar 			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
919875386b9SManish Rangankar 			*pkt = new_pkt;
920875386b9SManish Rangankar 
921875386b9SManish Rangankar 			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
922875386b9SManish Rangankar 				ql_log(ql_log_warn, vha, 0x507a,
923875386b9SManish Rangankar 				       "Unexpected IOCB type, partial data 0x%x\n",
924875386b9SManish Rangankar 				       buffer_copy_offset);
925875386b9SManish Rangankar 				break;
926875386b9SManish Rangankar 			}
927875386b9SManish Rangankar 
928875386b9SManish Rangankar 			rsp_q->ring_index++;
929875386b9SManish Rangankar 			if (rsp_q->ring_index == rsp_q->length) {
930875386b9SManish Rangankar 				rsp_q->ring_index = 0;
931875386b9SManish Rangankar 				rsp_q->ring_ptr = rsp_q->ring;
932875386b9SManish Rangankar 			} else {
933875386b9SManish Rangankar 				rsp_q->ring_ptr++;
934875386b9SManish Rangankar 			}
935875386b9SManish Rangankar 			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
936875386b9SManish Rangankar 				sizeof(new_pkt->data) : pending_bytes;
937875386b9SManish Rangankar 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
938875386b9SManish Rangankar 				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
939875386b9SManish Rangankar 				       new_pkt->data, no_bytes);
940875386b9SManish Rangankar 				buffer_copy_offset += no_bytes;
941875386b9SManish Rangankar 				pending_bytes -= no_bytes;
942875386b9SManish Rangankar 				--entry_count_remaining;
943875386b9SManish Rangankar 			} else {
944875386b9SManish Rangankar 				ql_log(ql_log_warn, vha, 0x5044,
945875386b9SManish Rangankar 				       "Attempt to copy more that we got, optimizing..%x\n",
946875386b9SManish Rangankar 				       buffer_copy_offset);
947875386b9SManish Rangankar 				memcpy(((uint8_t *)iocb_pkt + buffer_copy_offset),
948875386b9SManish Rangankar 				       new_pkt->data,
949875386b9SManish Rangankar 				       total_bytes - buffer_copy_offset);
950875386b9SManish Rangankar 			}
951875386b9SManish Rangankar 
952875386b9SManish Rangankar 			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
953875386b9SManish Rangankar 			wmb();
954875386b9SManish Rangankar 		}
955875386b9SManish Rangankar 
956875386b9SManish Rangankar 		if (pending_bytes != 0 || entry_count_remaining != 0) {
957875386b9SManish Rangankar 			ql_log(ql_log_fatal, vha, 0x508b,
958875386b9SManish Rangankar 			       "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
959875386b9SManish Rangankar 			       total_bytes, entry_count_remaining);
960875386b9SManish Rangankar 			qla24xx_free_purex_item(item);
961875386b9SManish Rangankar 			return NULL;
962875386b9SManish Rangankar 		}
963875386b9SManish Rangankar 	} while (entry_count_remaining > 0);
964875386b9SManish Rangankar 
965875386b9SManish Rangankar 	if (byte_order)
966875386b9SManish Rangankar 		host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
967875386b9SManish Rangankar 
968875386b9SManish Rangankar 	return item;
969875386b9SManish Rangankar }
970875386b9SManish Rangankar 
971bb4cf5b7SChad Dupuis int
qla2x00_is_a_vp_did(scsi_qla_host_t * vha,uint32_t rscn_entry)972bb4cf5b7SChad Dupuis qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
973bb4cf5b7SChad Dupuis {
974bb4cf5b7SChad Dupuis 	struct qla_hw_data *ha = vha->hw;
975bb4cf5b7SChad Dupuis 	scsi_qla_host_t *vp;
976bb4cf5b7SChad Dupuis 	uint32_t vp_did;
977bb4cf5b7SChad Dupuis 	unsigned long flags;
978bb4cf5b7SChad Dupuis 	int ret = 0;
979bb4cf5b7SChad Dupuis 
980bb4cf5b7SChad Dupuis 	if (!ha->num_vhosts)
981bb4cf5b7SChad Dupuis 		return ret;
982bb4cf5b7SChad Dupuis 
983bb4cf5b7SChad Dupuis 	spin_lock_irqsave(&ha->vport_slock, flags);
984bb4cf5b7SChad Dupuis 	list_for_each_entry(vp, &ha->vp_list, list) {
985bb4cf5b7SChad Dupuis 		vp_did = vp->d_id.b24;
986bb4cf5b7SChad Dupuis 		if (vp_did == rscn_entry) {
987bb4cf5b7SChad Dupuis 			ret = 1;
988bb4cf5b7SChad Dupuis 			break;
989bb4cf5b7SChad Dupuis 		}
990bb4cf5b7SChad Dupuis 	}
991bb4cf5b7SChad Dupuis 	spin_unlock_irqrestore(&ha->vport_slock, flags);
992bb4cf5b7SChad Dupuis 
993bb4cf5b7SChad Dupuis 	return ret;
994bb4cf5b7SChad Dupuis }
995bb4cf5b7SChad Dupuis 
996726b8548SQuinn Tran fc_port_t *
qla2x00_find_fcport_by_loopid(scsi_qla_host_t * vha,uint16_t loop_id)99717cac3a1SJoe Carnuccio qla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id)
99817cac3a1SJoe Carnuccio {
999726b8548SQuinn Tran 	fc_port_t *f, *tf;
100017cac3a1SJoe Carnuccio 
1001726b8548SQuinn Tran 	f = tf = NULL;
1002726b8548SQuinn Tran 	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list)
1003726b8548SQuinn Tran 		if (f->loop_id == loop_id)
1004726b8548SQuinn Tran 			return f;
1005726b8548SQuinn Tran 	return NULL;
1006726b8548SQuinn Tran }
1007726b8548SQuinn Tran 
1008726b8548SQuinn Tran fc_port_t *
qla2x00_find_fcport_by_wwpn(scsi_qla_host_t * vha,u8 * wwpn,u8 incl_deleted)1009726b8548SQuinn Tran qla2x00_find_fcport_by_wwpn(scsi_qla_host_t *vha, u8 *wwpn, u8 incl_deleted)
1010726b8548SQuinn Tran {
1011726b8548SQuinn Tran 	fc_port_t *f, *tf;
1012726b8548SQuinn Tran 
1013726b8548SQuinn Tran 	f = tf = NULL;
1014726b8548SQuinn Tran 	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
1015726b8548SQuinn Tran 		if (memcmp(f->port_name, wwpn, WWN_SIZE) == 0) {
1016726b8548SQuinn Tran 			if (incl_deleted)
1017726b8548SQuinn Tran 				return f;
1018726b8548SQuinn Tran 			else if (f->deleted == 0)
1019726b8548SQuinn Tran 				return f;
1020726b8548SQuinn Tran 		}
1021726b8548SQuinn Tran 	}
1022726b8548SQuinn Tran 	return NULL;
1023726b8548SQuinn Tran }
1024726b8548SQuinn Tran 
1025726b8548SQuinn Tran fc_port_t *
qla2x00_find_fcport_by_nportid(scsi_qla_host_t * vha,port_id_t * id,u8 incl_deleted)1026726b8548SQuinn Tran qla2x00_find_fcport_by_nportid(scsi_qla_host_t *vha, port_id_t *id,
1027726b8548SQuinn Tran 	u8 incl_deleted)
1028726b8548SQuinn Tran {
1029726b8548SQuinn Tran 	fc_port_t *f, *tf;
1030726b8548SQuinn Tran 
1031726b8548SQuinn Tran 	f = tf = NULL;
1032726b8548SQuinn Tran 	list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
1033726b8548SQuinn Tran 		if (f->d_id.b24 == id->b24) {
1034726b8548SQuinn Tran 			if (incl_deleted)
1035726b8548SQuinn Tran 				return f;
1036726b8548SQuinn Tran 			else if (f->deleted == 0)
1037726b8548SQuinn Tran 				return f;
1038726b8548SQuinn Tran 		}
1039726b8548SQuinn Tran 	}
104017cac3a1SJoe Carnuccio 	return NULL;
104117cac3a1SJoe Carnuccio }
104217cac3a1SJoe Carnuccio 
1043cbb01c2fSArun Easi /* Shall be called only on supported adapters. */
1044cbb01c2fSArun Easi static void
qla27xx_handle_8200_aen(scsi_qla_host_t * vha,uint16_t * mb)1045cbb01c2fSArun Easi qla27xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
1046cbb01c2fSArun Easi {
1047cbb01c2fSArun Easi 	struct qla_hw_data *ha = vha->hw;
104871311be1SJiapeng Zhong 	bool reset_isp_needed = false;
1049cbb01c2fSArun Easi 
1050cbb01c2fSArun Easi 	ql_log(ql_log_warn, vha, 0x02f0,
1051cbb01c2fSArun Easi 	       "MPI Heartbeat stop. MPI reset is%s needed. "
1052cbb01c2fSArun Easi 	       "MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n",
10537a6cdbd5SArun Easi 	       mb[1] & BIT_8 ? "" : " not",
1054cbb01c2fSArun Easi 	       mb[0], mb[1], mb[2], mb[3]);
1055cbb01c2fSArun Easi 
1056cbb01c2fSArun Easi 	if ((mb[1] & BIT_8) == 0)
1057cbb01c2fSArun Easi 		return;
1058cbb01c2fSArun Easi 
1059cbb01c2fSArun Easi 	ql_log(ql_log_warn, vha, 0x02f1,
1060cbb01c2fSArun Easi 	       "MPI Heartbeat stop. FW dump needed\n");
1061cbb01c2fSArun Easi 
1062cbb01c2fSArun Easi 	if (ql2xfulldump_on_mpifail) {
10638ae17876SBart Van Assche 		ha->isp_ops->fw_dump(vha);
106471311be1SJiapeng Zhong 		reset_isp_needed = true;
1065cbb01c2fSArun Easi 	}
1066cbb01c2fSArun Easi 
1067cbb01c2fSArun Easi 	ha->isp_ops->mpi_fw_dump(vha, 1);
1068cbb01c2fSArun Easi 
1069cbb01c2fSArun Easi 	if (reset_isp_needed) {
1070cbb01c2fSArun Easi 		vha->hw->flags.fw_init_done = 0;
1071cbb01c2fSArun Easi 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1072cbb01c2fSArun Easi 		qla2xxx_wake_dpc(vha);
1073cbb01c2fSArun Easi 	}
1074cbb01c2fSArun Easi }
1075cbb01c2fSArun Easi 
107658101f15SShyam Sundar static struct purex_item *
qla24xx_alloc_purex_item(scsi_qla_host_t * vha,uint16_t size)107762e9dd17SShyam Sundar qla24xx_alloc_purex_item(scsi_qla_host_t *vha, uint16_t size)
107862e9dd17SShyam Sundar {
107962e9dd17SShyam Sundar 	struct purex_item *item = NULL;
108062e9dd17SShyam Sundar 	uint8_t item_hdr_size = sizeof(*item);
108162e9dd17SShyam Sundar 
108262e9dd17SShyam Sundar 	if (size > QLA_DEFAULT_PAYLOAD_SIZE) {
108362e9dd17SShyam Sundar 		item = kzalloc(item_hdr_size +
108462e9dd17SShyam Sundar 		    (size - QLA_DEFAULT_PAYLOAD_SIZE), GFP_ATOMIC);
108562e9dd17SShyam Sundar 	} else {
108662e9dd17SShyam Sundar 		if (atomic_inc_return(&vha->default_item.in_use) == 1) {
108762e9dd17SShyam Sundar 			item = &vha->default_item;
108862e9dd17SShyam Sundar 			goto initialize_purex_header;
108962e9dd17SShyam Sundar 		} else {
109062e9dd17SShyam Sundar 			item = kzalloc(item_hdr_size, GFP_ATOMIC);
109162e9dd17SShyam Sundar 		}
109262e9dd17SShyam Sundar 	}
109362e9dd17SShyam Sundar 	if (!item) {
109462e9dd17SShyam Sundar 		ql_log(ql_log_warn, vha, 0x5092,
109562e9dd17SShyam Sundar 		       ">> Failed allocate purex list item.\n");
109662e9dd17SShyam Sundar 
109762e9dd17SShyam Sundar 		return NULL;
109862e9dd17SShyam Sundar 	}
109962e9dd17SShyam Sundar 
110062e9dd17SShyam Sundar initialize_purex_header:
110162e9dd17SShyam Sundar 	item->vha = vha;
110262e9dd17SShyam Sundar 	item->size = size;
110362e9dd17SShyam Sundar 	return item;
110462e9dd17SShyam Sundar }
110562e9dd17SShyam Sundar 
1106875386b9SManish Rangankar void
qla24xx_queue_purex_item(scsi_qla_host_t * vha,struct purex_item * pkt,void (* process_item)(struct scsi_qla_host * vha,struct purex_item * pkt))110762e9dd17SShyam Sundar qla24xx_queue_purex_item(scsi_qla_host_t *vha, struct purex_item *pkt,
110862e9dd17SShyam Sundar 			 void (*process_item)(struct scsi_qla_host *vha,
110962e9dd17SShyam Sundar 					      struct purex_item *pkt))
111062e9dd17SShyam Sundar {
111162e9dd17SShyam Sundar 	struct purex_list *list = &vha->purex_list;
111262e9dd17SShyam Sundar 	ulong flags;
111362e9dd17SShyam Sundar 
111462e9dd17SShyam Sundar 	pkt->process_item = process_item;
111562e9dd17SShyam Sundar 
111662e9dd17SShyam Sundar 	spin_lock_irqsave(&list->lock, flags);
111762e9dd17SShyam Sundar 	list_add_tail(&pkt->list, &list->head);
111862e9dd17SShyam Sundar 	spin_unlock_irqrestore(&list->lock, flags);
111962e9dd17SShyam Sundar 
112062e9dd17SShyam Sundar 	set_bit(PROCESS_PUREX_IOCB, &vha->dpc_flags);
112162e9dd17SShyam Sundar }
112262e9dd17SShyam Sundar 
112362e9dd17SShyam Sundar /**
112462e9dd17SShyam Sundar  * qla24xx_copy_std_pkt() - Copy over purex ELS which is
112562e9dd17SShyam Sundar  * contained in a single IOCB.
112662e9dd17SShyam Sundar  * purex packet.
112762e9dd17SShyam Sundar  * @vha: SCSI driver HA context
112862e9dd17SShyam Sundar  * @pkt: ELS packet
112962e9dd17SShyam Sundar  */
11309f2475feSShyam Sundar static struct purex_item
qla24xx_copy_std_pkt(struct scsi_qla_host * vha,void * pkt)113162e9dd17SShyam Sundar *qla24xx_copy_std_pkt(struct scsi_qla_host *vha, void *pkt)
113262e9dd17SShyam Sundar {
113362e9dd17SShyam Sundar 	struct purex_item *item;
113462e9dd17SShyam Sundar 
113562e9dd17SShyam Sundar 	item = qla24xx_alloc_purex_item(vha,
113662e9dd17SShyam Sundar 					QLA_DEFAULT_PAYLOAD_SIZE);
113762e9dd17SShyam Sundar 	if (!item)
113862e9dd17SShyam Sundar 		return item;
113962e9dd17SShyam Sundar 
114062e9dd17SShyam Sundar 	memcpy(&item->iocb, pkt, sizeof(item->iocb));
114162e9dd17SShyam Sundar 	return item;
114262e9dd17SShyam Sundar }
114362e9dd17SShyam Sundar 
11441da177e4SLinus Torvalds /**
11459f2475feSShyam Sundar  * qla27xx_copy_fpin_pkt() - Copy over fpin packets that can
11469f2475feSShyam Sundar  * span over multiple IOCBs.
11479f2475feSShyam Sundar  * @vha: SCSI driver HA context
11489f2475feSShyam Sundar  * @pkt: ELS packet
11499f2475feSShyam Sundar  * @rsp: Response queue
11509f2475feSShyam Sundar  */
11519f2475feSShyam Sundar static struct purex_item *
qla27xx_copy_fpin_pkt(struct scsi_qla_host * vha,void ** pkt,struct rsp_que ** rsp)11529f2475feSShyam Sundar qla27xx_copy_fpin_pkt(struct scsi_qla_host *vha, void **pkt,
11539f2475feSShyam Sundar 		      struct rsp_que **rsp)
11549f2475feSShyam Sundar {
11559f2475feSShyam Sundar 	struct purex_entry_24xx *purex = *pkt;
11569f2475feSShyam Sundar 	struct rsp_que *rsp_q = *rsp;
11579f2475feSShyam Sundar 	sts_cont_entry_t *new_pkt;
11589f2475feSShyam Sundar 	uint16_t no_bytes = 0, total_bytes = 0, pending_bytes = 0;
11599f2475feSShyam Sundar 	uint16_t buffer_copy_offset = 0;
11609f2475feSShyam Sundar 	uint16_t entry_count, entry_count_remaining;
11619f2475feSShyam Sundar 	struct purex_item *item;
11629f2475feSShyam Sundar 	void *fpin_pkt = NULL;
11639f2475feSShyam Sundar 
116458101f15SShyam Sundar 	total_bytes = (le16_to_cpu(purex->frame_size) & 0x0FFF)
11659f2475feSShyam Sundar 	    - PURX_ELS_HEADER_SIZE;
11669f2475feSShyam Sundar 	pending_bytes = total_bytes;
11679f2475feSShyam Sundar 	entry_count = entry_count_remaining = purex->entry_count;
11689f2475feSShyam Sundar 	no_bytes = (pending_bytes > sizeof(purex->els_frame_payload))  ?
11699f2475feSShyam Sundar 		   sizeof(purex->els_frame_payload) : pending_bytes;
11709f2475feSShyam Sundar 	ql_log(ql_log_info, vha, 0x509a,
11719f2475feSShyam Sundar 	       "FPIN ELS, frame_size 0x%x, entry count %d\n",
11729f2475feSShyam Sundar 	       total_bytes, entry_count);
11739f2475feSShyam Sundar 
11749f2475feSShyam Sundar 	item = qla24xx_alloc_purex_item(vha, total_bytes);
11759f2475feSShyam Sundar 	if (!item)
11769f2475feSShyam Sundar 		return item;
11779f2475feSShyam Sundar 
11789f2475feSShyam Sundar 	fpin_pkt = &item->iocb;
11799f2475feSShyam Sundar 
11809f2475feSShyam Sundar 	memcpy(fpin_pkt, &purex->els_frame_payload[0], no_bytes);
11819f2475feSShyam Sundar 	buffer_copy_offset += no_bytes;
11829f2475feSShyam Sundar 	pending_bytes -= no_bytes;
11839f2475feSShyam Sundar 	--entry_count_remaining;
11849f2475feSShyam Sundar 
11859f2475feSShyam Sundar 	((response_t *)purex)->signature = RESPONSE_PROCESSED;
11869f2475feSShyam Sundar 	wmb();
11879f2475feSShyam Sundar 
11889f2475feSShyam Sundar 	do {
11899f2475feSShyam Sundar 		while ((total_bytes > 0) && (entry_count_remaining > 0)) {
11909f2475feSShyam Sundar 			if (rsp_q->ring_ptr->signature == RESPONSE_PROCESSED) {
11919f2475feSShyam Sundar 				ql_dbg(ql_dbg_async, vha, 0x5084,
11929f2475feSShyam Sundar 				       "Ran out of IOCBs, partial data 0x%x\n",
11939f2475feSShyam Sundar 				       buffer_copy_offset);
11949f2475feSShyam Sundar 				cpu_relax();
11959f2475feSShyam Sundar 				continue;
11969f2475feSShyam Sundar 			}
11979f2475feSShyam Sundar 
11989f2475feSShyam Sundar 			new_pkt = (sts_cont_entry_t *)rsp_q->ring_ptr;
11999f2475feSShyam Sundar 			*pkt = new_pkt;
12009f2475feSShyam Sundar 
12019f2475feSShyam Sundar 			if (new_pkt->entry_type != STATUS_CONT_TYPE) {
12029f2475feSShyam Sundar 				ql_log(ql_log_warn, vha, 0x507a,
12039f2475feSShyam Sundar 				       "Unexpected IOCB type, partial data 0x%x\n",
12049f2475feSShyam Sundar 				       buffer_copy_offset);
12059f2475feSShyam Sundar 				break;
12069f2475feSShyam Sundar 			}
12079f2475feSShyam Sundar 
12089f2475feSShyam Sundar 			rsp_q->ring_index++;
12099f2475feSShyam Sundar 			if (rsp_q->ring_index == rsp_q->length) {
12109f2475feSShyam Sundar 				rsp_q->ring_index = 0;
12119f2475feSShyam Sundar 				rsp_q->ring_ptr = rsp_q->ring;
12129f2475feSShyam Sundar 			} else {
12139f2475feSShyam Sundar 				rsp_q->ring_ptr++;
12149f2475feSShyam Sundar 			}
12159f2475feSShyam Sundar 			no_bytes = (pending_bytes > sizeof(new_pkt->data)) ?
12169f2475feSShyam Sundar 			    sizeof(new_pkt->data) : pending_bytes;
12179f2475feSShyam Sundar 			if ((buffer_copy_offset + no_bytes) <= total_bytes) {
12189f2475feSShyam Sundar 				memcpy(((uint8_t *)fpin_pkt +
12199f2475feSShyam Sundar 				    buffer_copy_offset), new_pkt->data,
12209f2475feSShyam Sundar 				    no_bytes);
12219f2475feSShyam Sundar 				buffer_copy_offset += no_bytes;
12229f2475feSShyam Sundar 				pending_bytes -= no_bytes;
12239f2475feSShyam Sundar 				--entry_count_remaining;
12249f2475feSShyam Sundar 			} else {
12259f2475feSShyam Sundar 				ql_log(ql_log_warn, vha, 0x5044,
12269f2475feSShyam Sundar 				       "Attempt to copy more that we got, optimizing..%x\n",
12279f2475feSShyam Sundar 				       buffer_copy_offset);
12289f2475feSShyam Sundar 				memcpy(((uint8_t *)fpin_pkt +
12299f2475feSShyam Sundar 				    buffer_copy_offset), new_pkt->data,
12309f2475feSShyam Sundar 				    total_bytes - buffer_copy_offset);
12319f2475feSShyam Sundar 			}
12329f2475feSShyam Sundar 
12339f2475feSShyam Sundar 			((response_t *)new_pkt)->signature = RESPONSE_PROCESSED;
12349f2475feSShyam Sundar 			wmb();
12359f2475feSShyam Sundar 		}
12369f2475feSShyam Sundar 
12379f2475feSShyam Sundar 		if (pending_bytes != 0 || entry_count_remaining != 0) {
12389f2475feSShyam Sundar 			ql_log(ql_log_fatal, vha, 0x508b,
12399f2475feSShyam Sundar 			       "Dropping partial FPIN, underrun bytes = 0x%x, entry cnts 0x%x\n",
12409f2475feSShyam Sundar 			       total_bytes, entry_count_remaining);
12419f2475feSShyam Sundar 			qla24xx_free_purex_item(item);
12429f2475feSShyam Sundar 			return NULL;
12439f2475feSShyam Sundar 		}
12449f2475feSShyam Sundar 	} while (entry_count_remaining > 0);
12459f2475feSShyam Sundar 	host_to_fcp_swap((uint8_t *)&item->iocb, total_bytes);
12469f2475feSShyam Sundar 	return item;
12479f2475feSShyam Sundar }
12489f2475feSShyam Sundar 
12499f2475feSShyam Sundar /**
12501da177e4SLinus Torvalds  * qla2x00_async_event() - Process aynchronous events.
12512db6228dSBart Van Assche  * @vha: SCSI driver HA context
12522db6228dSBart Van Assche  * @rsp: response queue
12539a853f71SAndrew Vasquez  * @mb: Mailbox registers (0 - 3)
12541da177e4SLinus Torvalds  */
12552c3dfe3fSSeokmann Ju void
qla2x00_async_event(scsi_qla_host_t * vha,struct rsp_que * rsp,uint16_t * mb)125673208dfdSAnirban Chakraborty qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
12571da177e4SLinus Torvalds {
12581da177e4SLinus Torvalds 	uint16_t	handle_cnt;
1259bdab23daSAndrew Vasquez 	uint16_t	cnt, mbx;
12601da177e4SLinus Torvalds 	uint32_t	handles[5];
1261e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
12623d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1263bdab23daSAndrew Vasquez 	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
1264bc5c2aadSAndrew Vasquez 	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
126552c82823SBart Van Assche 	uint32_t	rscn_entry, host_pid;
12664d4df193SHarihara Kadayam 	unsigned long	flags;
1267ef86cb20SChad Dupuis 	fc_port_t	*fcport = NULL;
12681da177e4SLinus Torvalds 
12695b51f35dSQuinn Tran 	if (!vha->hw->flags.fw_started) {
12705b51f35dSQuinn Tran 		ql_log(ql_log_warn, vha, 0x50ff,
12715b51f35dSQuinn Tran 		    "Dropping AEN - %04x %04x %04x %04x.\n",
12725b51f35dSQuinn Tran 		    mb[0], mb[1], mb[2], mb[3]);
127345235022SQuinn Tran 		return;
12745b51f35dSQuinn Tran 	}
127545235022SQuinn Tran 
12761da177e4SLinus Torvalds 	/* Setup to process RIO completion. */
12771da177e4SLinus Torvalds 	handle_cnt = 0;
12786246b8a1SGiridhar Malavali 	if (IS_CNA_CAPABLE(ha))
12793a03eb79SAndrew Vasquez 		goto skip_rio;
12801da177e4SLinus Torvalds 	switch (mb[0]) {
12811da177e4SLinus Torvalds 	case MBA_SCSI_COMPLETION:
12827ffa5b93SBart Van Assche 		handles[0] = make_handle(mb[2], mb[1]);
12831da177e4SLinus Torvalds 		handle_cnt = 1;
12841da177e4SLinus Torvalds 		break;
12851da177e4SLinus Torvalds 	case MBA_CMPLT_1_16BIT:
12869a853f71SAndrew Vasquez 		handles[0] = mb[1];
12871da177e4SLinus Torvalds 		handle_cnt = 1;
12881da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
12891da177e4SLinus Torvalds 		break;
12901da177e4SLinus Torvalds 	case MBA_CMPLT_2_16BIT:
12919a853f71SAndrew Vasquez 		handles[0] = mb[1];
12929a853f71SAndrew Vasquez 		handles[1] = mb[2];
12931da177e4SLinus Torvalds 		handle_cnt = 2;
12941da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
12951da177e4SLinus Torvalds 		break;
12961da177e4SLinus Torvalds 	case MBA_CMPLT_3_16BIT:
12979a853f71SAndrew Vasquez 		handles[0] = mb[1];
12989a853f71SAndrew Vasquez 		handles[1] = mb[2];
12999a853f71SAndrew Vasquez 		handles[2] = mb[3];
13001da177e4SLinus Torvalds 		handle_cnt = 3;
13011da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
13021da177e4SLinus Torvalds 		break;
13031da177e4SLinus Torvalds 	case MBA_CMPLT_4_16BIT:
13049a853f71SAndrew Vasquez 		handles[0] = mb[1];
13059a853f71SAndrew Vasquez 		handles[1] = mb[2];
13069a853f71SAndrew Vasquez 		handles[2] = mb[3];
13071da177e4SLinus Torvalds 		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
13081da177e4SLinus Torvalds 		handle_cnt = 4;
13091da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
13101da177e4SLinus Torvalds 		break;
13111da177e4SLinus Torvalds 	case MBA_CMPLT_5_16BIT:
13129a853f71SAndrew Vasquez 		handles[0] = mb[1];
13139a853f71SAndrew Vasquez 		handles[1] = mb[2];
13149a853f71SAndrew Vasquez 		handles[2] = mb[3];
13151da177e4SLinus Torvalds 		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
13161da177e4SLinus Torvalds 		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
13171da177e4SLinus Torvalds 		handle_cnt = 5;
13181da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
13191da177e4SLinus Torvalds 		break;
13201da177e4SLinus Torvalds 	case MBA_CMPLT_2_32BIT:
13217ffa5b93SBart Van Assche 		handles[0] = make_handle(mb[2], mb[1]);
13227ffa5b93SBart Van Assche 		handles[1] = make_handle(RD_MAILBOX_REG(ha, reg, 7),
13231da177e4SLinus Torvalds 					 RD_MAILBOX_REG(ha, reg, 6));
13241da177e4SLinus Torvalds 		handle_cnt = 2;
13251da177e4SLinus Torvalds 		mb[0] = MBA_SCSI_COMPLETION;
13261da177e4SLinus Torvalds 		break;
13271da177e4SLinus Torvalds 	default:
13281da177e4SLinus Torvalds 		break;
13291da177e4SLinus Torvalds 	}
13303a03eb79SAndrew Vasquez skip_rio:
13311da177e4SLinus Torvalds 	switch (mb[0]) {
13321da177e4SLinus Torvalds 	case MBA_SCSI_COMPLETION:	/* Fast Post */
1333e315cd28SAnirban Chakraborty 		if (!vha->flags.online)
13341da177e4SLinus Torvalds 			break;
13351da177e4SLinus Torvalds 
13361da177e4SLinus Torvalds 		for (cnt = 0; cnt < handle_cnt; cnt++)
133773208dfdSAnirban Chakraborty 			qla2x00_process_completed_request(vha, rsp->req,
133873208dfdSAnirban Chakraborty 				handles[cnt]);
13391da177e4SLinus Torvalds 		break;
13401da177e4SLinus Torvalds 
13411da177e4SLinus Torvalds 	case MBA_RESET:			/* Reset */
13427c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5002,
13437c3df132SSaurav Kashyap 		    "Asynchronous RESET.\n");
13441da177e4SLinus Torvalds 
1345e315cd28SAnirban Chakraborty 		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
13461da177e4SLinus Torvalds 		break;
13471da177e4SLinus Torvalds 
13481da177e4SLinus Torvalds 	case MBA_SYSTEM_ERR:		/* System Error */
1349a82c307eSQuinn Tran 		mbx = 0;
1350dbf1f53cSSaurav Kashyap 
1351dbf1f53cSSaurav Kashyap 		vha->hw_err_cnt++;
1352dbf1f53cSSaurav Kashyap 
1353a82c307eSQuinn Tran 		if (IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
1354a82c307eSQuinn Tran 		    IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
1355a82c307eSQuinn Tran 			u16 m[4];
1356a82c307eSQuinn Tran 
135704474d3aSBart Van Assche 			m[0] = rd_reg_word(&reg24->mailbox4);
135804474d3aSBart Van Assche 			m[1] = rd_reg_word(&reg24->mailbox5);
135904474d3aSBart Van Assche 			m[2] = rd_reg_word(&reg24->mailbox6);
136004474d3aSBart Van Assche 			mbx = m[3] = rd_reg_word(&reg24->mailbox7);
1361a82c307eSQuinn Tran 
13627c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x5003,
1363a82c307eSQuinn Tran 			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh mbx4=%xh mbx5=%xh mbx6=%xh mbx7=%xh.\n",
1364a82c307eSQuinn Tran 			    mb[1], mb[2], mb[3], m[0], m[1], m[2], m[3]);
1365a82c307eSQuinn Tran 		} else
1366a82c307eSQuinn Tran 			ql_log(ql_log_warn, vha, 0x5003,
1367a82c307eSQuinn Tran 			    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n ",
1368a82c307eSQuinn Tran 			    mb[1], mb[2], mb[3]);
1369a82c307eSQuinn Tran 
1370cbb01c2fSArun Easi 		if ((IS_QLA27XX(ha) || IS_QLA28XX(ha)) &&
137104474d3aSBart Van Assche 		    rd_reg_word(&reg24->mailbox7) & BIT_8)
1372cbb01c2fSArun Easi 			ha->isp_ops->mpi_fw_dump(vha, 1);
13738ae17876SBart Van Assche 		ha->isp_ops->fw_dump(vha);
1374ec7193e2SQuinn Tran 		ha->flags.fw_init_done = 0;
13754b60c827SQuinn Tran 		QLA_FW_STOPPED(ha);
13761da177e4SLinus Torvalds 
1377e428924cSAndrew Vasquez 		if (IS_FWI2_CAPABLE(ha)) {
13789a853f71SAndrew Vasquez 			if (mb[1] == 0 && mb[2] == 0) {
13797c3df132SSaurav Kashyap 				ql_log(ql_log_fatal, vha, 0x5004,
13809a853f71SAndrew Vasquez 				    "Unrecoverable Hardware Error: adapter "
13819a853f71SAndrew Vasquez 				    "marked OFFLINE!\n");
1382e315cd28SAnirban Chakraborty 				vha->flags.online = 0;
13836246b8a1SGiridhar Malavali 				vha->device_flags |= DFLG_DEV_FAILED;
1384b1d46989SMadhuranath Iyengar 			} else {
138525985edcSLucas De Marchi 				/* Check to see if MPI timeout occurred */
1386f73cb695SChad Dupuis 				if ((mbx & MBX_3) && (ha->port_no == 0))
1387b1d46989SMadhuranath Iyengar 					set_bit(MPI_RESET_NEEDED,
1388b1d46989SMadhuranath Iyengar 					    &vha->dpc_flags);
1389b1d46989SMadhuranath Iyengar 
1390e315cd28SAnirban Chakraborty 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1391b1d46989SMadhuranath Iyengar 			}
13929a853f71SAndrew Vasquez 		} else if (mb[1] == 0) {
13937c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, vha, 0x5005,
13941da177e4SLinus Torvalds 			    "Unrecoverable Hardware Error: adapter marked "
13951da177e4SLinus Torvalds 			    "OFFLINE!\n");
1396e315cd28SAnirban Chakraborty 			vha->flags.online = 0;
13976246b8a1SGiridhar Malavali 			vha->device_flags |= DFLG_DEV_FAILED;
13981da177e4SLinus Torvalds 		} else
1399e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
14001da177e4SLinus Torvalds 		break;
14011da177e4SLinus Torvalds 
14021da177e4SLinus Torvalds 	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
14037c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5006,
1404bdab23daSAndrew Vasquez 		    "ISP Request Transfer Error (%x).\n",  mb[1]);
14051da177e4SLinus Torvalds 
1406dbf1f53cSSaurav Kashyap 		vha->hw_err_cnt++;
1407dbf1f53cSSaurav Kashyap 
1408e315cd28SAnirban Chakraborty 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
14091da177e4SLinus Torvalds 		break;
14101da177e4SLinus Torvalds 
14111da177e4SLinus Torvalds 	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
14127c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5007,
141341233cd3SJoe Carnuccio 		    "ISP Response Transfer Error (%x).\n", mb[1]);
14141da177e4SLinus Torvalds 
1415dbf1f53cSSaurav Kashyap 		vha->hw_err_cnt++;
1416dbf1f53cSSaurav Kashyap 
1417e315cd28SAnirban Chakraborty 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
14181da177e4SLinus Torvalds 		break;
14191da177e4SLinus Torvalds 
14201da177e4SLinus Torvalds 	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
14217c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5008,
142241233cd3SJoe Carnuccio 		    "Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
14232d70c103SNicholas Bellinger 		break;
142441233cd3SJoe Carnuccio 
142541233cd3SJoe Carnuccio 	case MBA_LOOP_INIT_ERR:
142675d560e0SSawan Chandak 		ql_log(ql_log_warn, vha, 0x5090,
142741233cd3SJoe Carnuccio 		    "LOOP INIT ERROR (%x).\n", mb[1]);
142841233cd3SJoe Carnuccio 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
142941233cd3SJoe Carnuccio 		break;
143041233cd3SJoe Carnuccio 
14311da177e4SLinus Torvalds 	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
1432ec7193e2SQuinn Tran 		ha->flags.lip_ae = 1;
1433ec7193e2SQuinn Tran 
1434cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_async, vha, 0x5009,
14357c3df132SSaurav Kashyap 		    "LIP occurred (%x).\n", mb[1]);
14361da177e4SLinus Torvalds 
1437e315cd28SAnirban Chakraborty 		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
1438e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_state, LOOP_DOWN);
1439e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
14403c75ad1dSHimanshu Madhani 			qla2x00_mark_all_devices_lost(vha);
14411da177e4SLinus Torvalds 		}
14421da177e4SLinus Torvalds 
1443e315cd28SAnirban Chakraborty 		if (vha->vp_idx) {
1444e315cd28SAnirban Chakraborty 			atomic_set(&vha->vp_state, VP_FAILED);
1445e315cd28SAnirban Chakraborty 			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
14462c3dfe3fSSeokmann Ju 		}
14472c3dfe3fSSeokmann Ju 
1448e315cd28SAnirban Chakraborty 		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
1449e315cd28SAnirban Chakraborty 		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
14501da177e4SLinus Torvalds 
1451e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
1452e315cd28SAnirban Chakraborty 		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
14531da177e4SLinus Torvalds 		break;
14541da177e4SLinus Torvalds 
14551da177e4SLinus Torvalds 	case MBA_LOOP_UP:		/* Loop Up Event */
1456daae62a3SChad Dupuis 		if (IS_QLA2100(ha) || IS_QLA2200(ha))
1457d8b45213SAndrew Vasquez 			ha->link_data_rate = PORT_SPEED_1GB;
1458daae62a3SChad Dupuis 		else
14591da177e4SLinus Torvalds 			ha->link_data_rate = mb[1];
14601da177e4SLinus Torvalds 
14618e5a9484SChad Dupuis 		ql_log(ql_log_info, vha, 0x500a,
1462daae62a3SChad Dupuis 		    "LOOP UP detected (%s Gbps).\n",
1463d0297c9aSJoe Carnuccio 		    qla2x00_get_link_speed_str(ha, ha->link_data_rate));
14641da177e4SLinus Torvalds 
146575666f4aSHimanshu Madhani 		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
146675666f4aSHimanshu Madhani 			if (mb[2] & BIT_0)
146775666f4aSHimanshu Madhani 				ql_log(ql_log_info, vha, 0x11a0,
146875666f4aSHimanshu Madhani 				    "FEC=enabled (link up).\n");
146975666f4aSHimanshu Madhani 		}
147075666f4aSHimanshu Madhani 
1471e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
1472e315cd28SAnirban Chakraborty 		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
1473e4e3a2ceSQuinn Tran 
1474dbf1f53cSSaurav Kashyap 		if (vha->link_down_time < vha->hw->port_down_retry_count) {
1475dbf1f53cSSaurav Kashyap 			vha->short_link_down_cnt++;
1476dbf1f53cSSaurav Kashyap 			vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
1477dbf1f53cSSaurav Kashyap 		}
1478dbf1f53cSSaurav Kashyap 
14791da177e4SLinus Torvalds 		break;
14801da177e4SLinus Torvalds 
14811da177e4SLinus Torvalds 	case MBA_LOOP_DOWN:		/* Loop Down Event */
14829cd883f0SQuinn Tran 		SAVE_TOPO(ha);
1483ec7193e2SQuinn Tran 		ha->flags.lip_ae = 0;
1484ec7193e2SQuinn Tran 		ha->current_topology = 0;
1485dbf1f53cSSaurav Kashyap 		vha->link_down_time = 0;
1486ec7193e2SQuinn Tran 
14876246b8a1SGiridhar Malavali 		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
148804474d3aSBart Van Assche 			? rd_reg_word(&reg24->mailbox4) : 0;
148904474d3aSBart Van Assche 		mbx = (IS_P3P_TYPE(ha)) ? rd_reg_word(&reg82->mailbox_out[4])
14907ec0effdSAtul Deshmukh 			: mbx;
14918e5a9484SChad Dupuis 		ql_log(ql_log_info, vha, 0x500b,
14927c3df132SSaurav Kashyap 		    "LOOP DOWN detected (%x %x %x %x).\n",
14937c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3], mbx);
14941da177e4SLinus Torvalds 
1495e315cd28SAnirban Chakraborty 		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
1496e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_state, LOOP_DOWN);
1497e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
14982486c627SHimanshu Madhani 			/*
14992486c627SHimanshu Madhani 			 * In case of loop down, restore WWPN from
15002486c627SHimanshu Madhani 			 * NVRAM in case of FA-WWPN capable ISP
1501718abbdcSSawan Chandak 			 * Restore for Physical Port only
15022486c627SHimanshu Madhani 			 */
1503718abbdcSSawan Chandak 			if (!vha->vp_idx) {
1504dcbf8f80SSawan Chandak 				if (ha->flags.fawwpn_enabled &&
1505dcbf8f80SSawan Chandak 				    (ha->current_topology == ISP_CFG_F)) {
1506cf3b4fb6SBikash Hazarika 					memcpy(vha->port_name, ha->port_name, WWN_SIZE);
1507718abbdcSSawan Chandak 					fc_host_port_name(vha->host) =
1508718abbdcSSawan Chandak 					    wwn_to_u64(vha->port_name);
1509718abbdcSSawan Chandak 					ql_dbg(ql_dbg_init + ql_dbg_verbose,
151083548fe2SQuinn Tran 					    vha, 0x00d8, "LOOP DOWN detected,"
1511718abbdcSSawan Chandak 					    "restore WWPN %016llx\n",
1512718abbdcSSawan Chandak 					    wwn_to_u64(vha->port_name));
15132486c627SHimanshu Madhani 				}
15142486c627SHimanshu Madhani 
1515ded6411fSSawan Chandak 				clear_bit(VP_CONFIG_OK, &vha->vp_flags);
1516718abbdcSSawan Chandak 			}
1517718abbdcSSawan Chandak 
1518e315cd28SAnirban Chakraborty 			vha->device_flags |= DFLG_NO_CABLE;
15193c75ad1dSHimanshu Madhani 			qla2x00_mark_all_devices_lost(vha);
15201da177e4SLinus Torvalds 		}
15211da177e4SLinus Torvalds 
1522e315cd28SAnirban Chakraborty 		if (vha->vp_idx) {
1523e315cd28SAnirban Chakraborty 			atomic_set(&vha->vp_state, VP_FAILED);
1524e315cd28SAnirban Chakraborty 			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
15252c3dfe3fSSeokmann Ju 		}
15262c3dfe3fSSeokmann Ju 
1527e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
1528d8b45213SAndrew Vasquez 		ha->link_data_rate = PORT_SPEED_UNKNOWN;
1529e315cd28SAnirban Chakraborty 		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
15301da177e4SLinus Torvalds 		break;
15311da177e4SLinus Torvalds 
15321da177e4SLinus Torvalds 	case MBA_LIP_RESET:		/* LIP reset occurred */
1533cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_async, vha, 0x500c,
1534cc3ef7bcSBjorn Helgaas 		    "LIP reset occurred (%x).\n", mb[1]);
15351da177e4SLinus Torvalds 
1536e315cd28SAnirban Chakraborty 		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
1537e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_state, LOOP_DOWN);
1538e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
15393c75ad1dSHimanshu Madhani 			qla2x00_mark_all_devices_lost(vha);
15401da177e4SLinus Torvalds 		}
15411da177e4SLinus Torvalds 
1542e315cd28SAnirban Chakraborty 		if (vha->vp_idx) {
1543e315cd28SAnirban Chakraborty 			atomic_set(&vha->vp_state, VP_FAILED);
1544e315cd28SAnirban Chakraborty 			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
15452c3dfe3fSSeokmann Ju 		}
15462c3dfe3fSSeokmann Ju 
1547e315cd28SAnirban Chakraborty 		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
15481da177e4SLinus Torvalds 
15491da177e4SLinus Torvalds 		ha->operating_mode = LOOP;
1550e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
1551e315cd28SAnirban Chakraborty 		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
15521da177e4SLinus Torvalds 		break;
15531da177e4SLinus Torvalds 
15543a03eb79SAndrew Vasquez 	/* case MBA_DCBX_COMPLETE: */
15551da177e4SLinus Torvalds 	case MBA_POINT_TO_POINT:	/* Point-to-Point */
1556ec7193e2SQuinn Tran 		ha->flags.lip_ae = 0;
1557ec7193e2SQuinn Tran 
15581da177e4SLinus Torvalds 		if (IS_QLA2100(ha))
15591da177e4SLinus Torvalds 			break;
15601da177e4SLinus Torvalds 
15617ec0effdSAtul Deshmukh 		if (IS_CNA_CAPABLE(ha)) {
15627c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x500d,
15637c3df132SSaurav Kashyap 			    "DCBX Completed -- %04x %04x %04x.\n",
15647c3df132SSaurav Kashyap 			    mb[1], mb[2], mb[3]);
15659aaf2ceaSChad Dupuis 			if (ha->notify_dcbx_comp && !vha->vp_idx)
156623f2ebd1SSarang Radke 				complete(&ha->dcbx_comp);
156723f2ebd1SSarang Radke 
156823f2ebd1SSarang Radke 		} else
15697c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x500e,
15707c3df132SSaurav Kashyap 			    "Asynchronous P2P MODE received.\n");
15711da177e4SLinus Torvalds 
15721da177e4SLinus Torvalds 		/*
15731da177e4SLinus Torvalds 		 * Until there's a transition from loop down to loop up, treat
15741da177e4SLinus Torvalds 		 * this as loop down only.
15751da177e4SLinus Torvalds 		 */
1576e315cd28SAnirban Chakraborty 		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
1577e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_state, LOOP_DOWN);
1578e315cd28SAnirban Chakraborty 			if (!atomic_read(&vha->loop_down_timer))
1579e315cd28SAnirban Chakraborty 				atomic_set(&vha->loop_down_timer,
15801da177e4SLinus Torvalds 				    LOOP_DOWN_TIME);
158148acad09SQuinn Tran 			if (!N2N_TOPO(ha))
15823c75ad1dSHimanshu Madhani 				qla2x00_mark_all_devices_lost(vha);
15831da177e4SLinus Torvalds 		}
15841da177e4SLinus Torvalds 
1585e315cd28SAnirban Chakraborty 		if (vha->vp_idx) {
1586e315cd28SAnirban Chakraborty 			atomic_set(&vha->vp_state, VP_FAILED);
1587e315cd28SAnirban Chakraborty 			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
15882c3dfe3fSSeokmann Ju 		}
15892c3dfe3fSSeokmann Ju 
1590e315cd28SAnirban Chakraborty 		if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
1591e315cd28SAnirban Chakraborty 			set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
1592e315cd28SAnirban Chakraborty 
1593e315cd28SAnirban Chakraborty 		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
1594e315cd28SAnirban Chakraborty 		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
15954346b149SAndrew Vasquez 
1596e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
15971da177e4SLinus Torvalds 		break;
15981da177e4SLinus Torvalds 
15991da177e4SLinus Torvalds 	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
16001da177e4SLinus Torvalds 		if (IS_QLA2100(ha))
16011da177e4SLinus Torvalds 			break;
16021da177e4SLinus Torvalds 
1603cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_async, vha, 0x500f,
16041da177e4SLinus Torvalds 		    "Configuration change detected: value=%x.\n", mb[1]);
16051da177e4SLinus Torvalds 
1606e315cd28SAnirban Chakraborty 		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
1607e315cd28SAnirban Chakraborty 			atomic_set(&vha->loop_state, LOOP_DOWN);
1608e315cd28SAnirban Chakraborty 			if (!atomic_read(&vha->loop_down_timer))
1609e315cd28SAnirban Chakraborty 				atomic_set(&vha->loop_down_timer,
16101da177e4SLinus Torvalds 				    LOOP_DOWN_TIME);
16113c75ad1dSHimanshu Madhani 			qla2x00_mark_all_devices_lost(vha);
16121da177e4SLinus Torvalds 		}
16131da177e4SLinus Torvalds 
1614e315cd28SAnirban Chakraborty 		if (vha->vp_idx) {
1615e315cd28SAnirban Chakraborty 			atomic_set(&vha->vp_state, VP_FAILED);
1616e315cd28SAnirban Chakraborty 			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
16172c3dfe3fSSeokmann Ju 		}
16182c3dfe3fSSeokmann Ju 
1619e315cd28SAnirban Chakraborty 		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
1620e315cd28SAnirban Chakraborty 		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
16211da177e4SLinus Torvalds 		break;
16221da177e4SLinus Torvalds 
16231da177e4SLinus Torvalds 	case MBA_PORT_UPDATE:		/* Port database update */
162455903b9dSSantosh Vernekar 		/*
162555903b9dSSantosh Vernekar 		 * Handle only global and vn-port update events
162655903b9dSSantosh Vernekar 		 *
162755903b9dSSantosh Vernekar 		 * Relevant inputs:
162855903b9dSSantosh Vernekar 		 * mb[1] = N_Port handle of changed port
162955903b9dSSantosh Vernekar 		 * OR 0xffff for global event
163055903b9dSSantosh Vernekar 		 * mb[2] = New login state
163155903b9dSSantosh Vernekar 		 * 7 = Port logged out
163255903b9dSSantosh Vernekar 		 * mb[3] = LSB is vp_idx, 0xff = all vps
163355903b9dSSantosh Vernekar 		 *
163455903b9dSSantosh Vernekar 		 * Skip processing if:
163555903b9dSSantosh Vernekar 		 *       Event is global, vp_idx is NOT all vps,
163655903b9dSSantosh Vernekar 		 *           vp_idx does not match
163755903b9dSSantosh Vernekar 		 *       Event is not global, vp_idx does not match
163855903b9dSSantosh Vernekar 		 */
163912cec63eSAndrew Vasquez 		if (IS_QLA2XXX_MIDTYPE(ha) &&
164012cec63eSAndrew Vasquez 		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
164112cec63eSAndrew Vasquez 			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
164273208dfdSAnirban Chakraborty 			break;
164373208dfdSAnirban Chakraborty 
164417cac3a1SJoe Carnuccio 		if (mb[2] == 0x7) {
16457c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5010,
164617cac3a1SJoe Carnuccio 			    "Port %s %04x %04x %04x.\n",
164717cac3a1SJoe Carnuccio 			    mb[1] == 0xffff ? "unavailable" : "logout",
16487c3df132SSaurav Kashyap 			    mb[1], mb[2], mb[3]);
164917cac3a1SJoe Carnuccio 
165017cac3a1SJoe Carnuccio 			if (mb[1] == 0xffff)
165117cac3a1SJoe Carnuccio 				goto global_port_update;
165217cac3a1SJoe Carnuccio 
1653b98ae0d7SQuinn Tran 			if (mb[1] == NPH_SNS_LID(ha)) {
1654b98ae0d7SQuinn Tran 				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
1655b98ae0d7SQuinn Tran 				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
1656b98ae0d7SQuinn Tran 				break;
1657b98ae0d7SQuinn Tran 			}
1658b98ae0d7SQuinn Tran 
1659b98ae0d7SQuinn Tran 			/* use handle_cnt for loop id/nport handle */
1660b98ae0d7SQuinn Tran 			if (IS_FWI2_CAPABLE(ha))
1661b98ae0d7SQuinn Tran 				handle_cnt = NPH_SNS;
1662b98ae0d7SQuinn Tran 			else
1663b98ae0d7SQuinn Tran 				handle_cnt = SIMPLE_NAME_SERVER;
1664b98ae0d7SQuinn Tran 			if (mb[1] == handle_cnt) {
1665b98ae0d7SQuinn Tran 				set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
1666b98ae0d7SQuinn Tran 				set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
1667b98ae0d7SQuinn Tran 				break;
1668b98ae0d7SQuinn Tran 			}
1669b98ae0d7SQuinn Tran 
167017cac3a1SJoe Carnuccio 			/* Port logout */
167117cac3a1SJoe Carnuccio 			fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
167217cac3a1SJoe Carnuccio 			if (!fcport)
167317cac3a1SJoe Carnuccio 				break;
167417cac3a1SJoe Carnuccio 			if (atomic_read(&fcport->state) != FCS_ONLINE)
167517cac3a1SJoe Carnuccio 				break;
167617cac3a1SJoe Carnuccio 			ql_dbg(ql_dbg_async, vha, 0x508a,
167717cac3a1SJoe Carnuccio 			    "Marking port lost loopid=%04x portid=%06x.\n",
167817cac3a1SJoe Carnuccio 			    fcport->loop_id, fcport->d_id.b24);
1679726b8548SQuinn Tran 			if (qla_ini_mode_enabled(vha)) {
1680726b8548SQuinn Tran 				fcport->logout_on_delete = 0;
1681d8630bb9SQuinn Tran 				qlt_schedule_sess_for_deletion(fcport);
1682726b8548SQuinn Tran 			}
168317cac3a1SJoe Carnuccio 			break;
168417cac3a1SJoe Carnuccio 
168517cac3a1SJoe Carnuccio global_port_update:
16869764ff88SAndrew Vasquez 			if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
16879764ff88SAndrew Vasquez 				atomic_set(&vha->loop_state, LOOP_DOWN);
16889764ff88SAndrew Vasquez 				atomic_set(&vha->loop_down_timer,
16899764ff88SAndrew Vasquez 				    LOOP_DOWN_TIME);
16909764ff88SAndrew Vasquez 				vha->device_flags |= DFLG_NO_CABLE;
16913c75ad1dSHimanshu Madhani 				qla2x00_mark_all_devices_lost(vha);
16929764ff88SAndrew Vasquez 			}
16939764ff88SAndrew Vasquez 
16949764ff88SAndrew Vasquez 			if (vha->vp_idx) {
16959764ff88SAndrew Vasquez 				atomic_set(&vha->vp_state, VP_FAILED);
16969764ff88SAndrew Vasquez 				fc_vport_set_state(vha->fc_vport,
16979764ff88SAndrew Vasquez 				    FC_VPORT_FAILED);
16983c75ad1dSHimanshu Madhani 				qla2x00_mark_all_devices_lost(vha);
16999764ff88SAndrew Vasquez 			}
17009764ff88SAndrew Vasquez 
17019764ff88SAndrew Vasquez 			vha->flags.management_server_logged_in = 0;
17029764ff88SAndrew Vasquez 			ha->link_data_rate = PORT_SPEED_UNKNOWN;
17039764ff88SAndrew Vasquez 			break;
17049764ff88SAndrew Vasquez 		}
17059764ff88SAndrew Vasquez 
17061da177e4SLinus Torvalds 		/*
1707cc3ef7bcSBjorn Helgaas 		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
17081da177e4SLinus Torvalds 		 * event etc. earlier indicating loop is down) then process
17091da177e4SLinus Torvalds 		 * it.  Otherwise ignore it and Wait for RSCN to come in.
17101da177e4SLinus Torvalds 		 */
1711e315cd28SAnirban Chakraborty 		atomic_set(&vha->loop_down_timer, 0);
17128e5a9484SChad Dupuis 		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
1713edd05de1SDuane Grigsby 			!ha->flags.n2n_ae  &&
17148e5a9484SChad Dupuis 		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
17157c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5011,
17167c3df132SSaurav Kashyap 			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
17177c3df132SSaurav Kashyap 			    mb[1], mb[2], mb[3]);
17181da177e4SLinus Torvalds 			break;
17191da177e4SLinus Torvalds 		}
17201da177e4SLinus Torvalds 
17217c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5012,
17227c3df132SSaurav Kashyap 		    "Port database changed %04x %04x %04x.\n",
17237c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
17241da177e4SLinus Torvalds 
17251da177e4SLinus Torvalds 		/*
17261da177e4SLinus Torvalds 		 * Mark all devices as missing so we will login again.
17271da177e4SLinus Torvalds 		 */
1728e315cd28SAnirban Chakraborty 		atomic_set(&vha->loop_state, LOOP_UP);
17296944dccbSQuinn Tran 		vha->scan.scan_retry = 0;
17301da177e4SLinus Torvalds 
1731e315cd28SAnirban Chakraborty 		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
1732e315cd28SAnirban Chakraborty 		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
1733ded6411fSSawan Chandak 		set_bit(VP_CONFIG_OK, &vha->vp_flags);
17341da177e4SLinus Torvalds 		break;
17351da177e4SLinus Torvalds 
17361da177e4SLinus Torvalds 	case MBA_RSCN_UPDATE:		/* State Change Registration */
17373c397400SSeokmann Ju 		/* Check if the Vport has issued a SCR */
1738e315cd28SAnirban Chakraborty 		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
17392c3dfe3fSSeokmann Ju 			break;
17403c397400SSeokmann Ju 		/* Only handle SCNs for our Vport index. */
17410d6e61bcSAndrew Vasquez 		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
17423c397400SSeokmann Ju 			break;
17430d6e61bcSAndrew Vasquez 
1744daaecb41SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5013,
17457c3df132SSaurav Kashyap 		       "RSCN database changed -- %04x %04x %04x.\n",
17467c3df132SSaurav Kashyap 		       mb[1], mb[2], mb[3]);
17471da177e4SLinus Torvalds 
174859d72d87SRavi Anand 		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
1749e315cd28SAnirban Chakraborty 		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
1750e315cd28SAnirban Chakraborty 				| vha->d_id.b.al_pa;
17511da177e4SLinus Torvalds 		if (rscn_entry == host_pid) {
17527c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5014,
17537c3df132SSaurav Kashyap 			    "Ignoring RSCN update to local host "
17547c3df132SSaurav Kashyap 			    "port ID (%06x).\n", host_pid);
17551da177e4SLinus Torvalds 			break;
17561da177e4SLinus Torvalds 		}
17571da177e4SLinus Torvalds 
175859d72d87SRavi Anand 		/* Ignore reserved bits from RSCN-payload. */
175959d72d87SRavi Anand 		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
17601da177e4SLinus Torvalds 
1761bb4cf5b7SChad Dupuis 		/* Skip RSCNs for virtual ports on the same physical port */
1762bb4cf5b7SChad Dupuis 		if (qla2x00_is_a_vp_did(vha, rscn_entry))
1763bb4cf5b7SChad Dupuis 			break;
1764bb4cf5b7SChad Dupuis 
1765e315cd28SAnirban Chakraborty 		atomic_set(&vha->loop_down_timer, 0);
1766e315cd28SAnirban Chakraborty 		vha->flags.management_server_logged_in = 0;
1767726b8548SQuinn Tran 		{
1768726b8548SQuinn Tran 			struct event_arg ea;
17691da177e4SLinus Torvalds 
1770726b8548SQuinn Tran 			memset(&ea, 0, sizeof(ea));
1771726b8548SQuinn Tran 			ea.id.b24 = rscn_entry;
177241dc529aSQuinn Tran 			ea.id.b.rsvd_1 = rscn_entry >> 24;
1773897def20SBart Van Assche 			qla2x00_handle_rscn(vha, &ea);
1774e315cd28SAnirban Chakraborty 			qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
1775726b8548SQuinn Tran 		}
17761da177e4SLinus Torvalds 		break;
17779f2475feSShyam Sundar 	case MBA_CONGN_NOTI_RECV:
17789f2475feSShyam Sundar 		if (!ha->flags.scm_enabled ||
17799f2475feSShyam Sundar 		    mb[1] != QLA_CON_PRIMITIVE_RECEIVED)
17809f2475feSShyam Sundar 			break;
17819f2475feSShyam Sundar 
17829f2475feSShyam Sundar 		if (mb[2] == QLA_CONGESTION_ARB_WARNING) {
17839f2475feSShyam Sundar 			ql_dbg(ql_dbg_async, vha, 0x509b,
17849f2475feSShyam Sundar 			       "Congestion Warning %04x %04x.\n", mb[1], mb[2]);
17859f2475feSShyam Sundar 		} else if (mb[2] == QLA_CONGESTION_ARB_ALARM) {
17869f2475feSShyam Sundar 			ql_log(ql_log_warn, vha, 0x509b,
17879f2475feSShyam Sundar 			       "Congestion Alarm %04x %04x.\n", mb[1], mb[2]);
17889f2475feSShyam Sundar 		}
17899f2475feSShyam Sundar 		break;
17901da177e4SLinus Torvalds 	/* case MBA_RIO_RESPONSE: */
17911da177e4SLinus Torvalds 	case MBA_ZIO_RESPONSE:
17927c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5015,
17937c3df132SSaurav Kashyap 		    "[R|Z]IO update completion.\n");
17941da177e4SLinus Torvalds 
1795e428924cSAndrew Vasquez 		if (IS_FWI2_CAPABLE(ha))
17962afa19a9SAnirban Chakraborty 			qla24xx_process_response_queue(vha, rsp);
17974fdfefe5SAndrew Vasquez 		else
179873208dfdSAnirban Chakraborty 			qla2x00_process_response_queue(rsp);
17991da177e4SLinus Torvalds 		break;
18009a853f71SAndrew Vasquez 
18019a853f71SAndrew Vasquez 	case MBA_DISCARD_RND_FRAME:
18027c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5016,
18037c3df132SSaurav Kashyap 		    "Discard RND Frame -- %04x %04x %04x.\n",
18047c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
1805dbf1f53cSSaurav Kashyap 		vha->interface_err_cnt++;
18069a853f71SAndrew Vasquez 		break;
180745ebeb56SAndrew Vasquez 
180845ebeb56SAndrew Vasquez 	case MBA_TRACE_NOTIFICATION:
18097c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5017,
18107c3df132SSaurav Kashyap 		    "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
181145ebeb56SAndrew Vasquez 		break;
18124d4df193SHarihara Kadayam 
18134d4df193SHarihara Kadayam 	case MBA_ISP84XX_ALERT:
18147c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5018,
18157c3df132SSaurav Kashyap 		    "ISP84XX Alert Notification -- %04x %04x %04x.\n",
18167c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
18174d4df193SHarihara Kadayam 
18184d4df193SHarihara Kadayam 		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
18194d4df193SHarihara Kadayam 		switch (mb[1]) {
18204d4df193SHarihara Kadayam 		case A84_PANIC_RECOVERY:
18217c3df132SSaurav Kashyap 			ql_log(ql_log_info, vha, 0x5019,
18227c3df132SSaurav Kashyap 			    "Alert 84XX: panic recovery %04x %04x.\n",
18237c3df132SSaurav Kashyap 			    mb[2], mb[3]);
18244d4df193SHarihara Kadayam 			break;
18254d4df193SHarihara Kadayam 		case A84_OP_LOGIN_COMPLETE:
18264d4df193SHarihara Kadayam 			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
18277c3df132SSaurav Kashyap 			ql_log(ql_log_info, vha, 0x501a,
18287c3df132SSaurav Kashyap 			    "Alert 84XX: firmware version %x.\n",
18297c3df132SSaurav Kashyap 			    ha->cs84xx->op_fw_version);
18304d4df193SHarihara Kadayam 			break;
18314d4df193SHarihara Kadayam 		case A84_DIAG_LOGIN_COMPLETE:
18324d4df193SHarihara Kadayam 			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
18337c3df132SSaurav Kashyap 			ql_log(ql_log_info, vha, 0x501b,
18347c3df132SSaurav Kashyap 			    "Alert 84XX: diagnostic firmware version %x.\n",
18357c3df132SSaurav Kashyap 			    ha->cs84xx->diag_fw_version);
18364d4df193SHarihara Kadayam 			break;
18374d4df193SHarihara Kadayam 		case A84_GOLD_LOGIN_COMPLETE:
18384d4df193SHarihara Kadayam 			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
18394d4df193SHarihara Kadayam 			ha->cs84xx->fw_update = 1;
18407c3df132SSaurav Kashyap 			ql_log(ql_log_info, vha, 0x501c,
18417c3df132SSaurav Kashyap 			    "Alert 84XX: gold firmware version %x.\n",
18427c3df132SSaurav Kashyap 			    ha->cs84xx->gold_fw_version);
18434d4df193SHarihara Kadayam 			break;
18444d4df193SHarihara Kadayam 		default:
18457c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x501d,
18467c3df132SSaurav Kashyap 			    "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
18474d4df193SHarihara Kadayam 			    mb[1], mb[2], mb[3]);
18484d4df193SHarihara Kadayam 		}
18494d4df193SHarihara Kadayam 		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
18504d4df193SHarihara Kadayam 		break;
18513a03eb79SAndrew Vasquez 	case MBA_DCBX_START:
18527c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x501e,
18537c3df132SSaurav Kashyap 		    "DCBX Started -- %04x %04x %04x.\n",
18547c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
18553a03eb79SAndrew Vasquez 		break;
18563a03eb79SAndrew Vasquez 	case MBA_DCBX_PARAM_UPDATE:
18577c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x501f,
18587c3df132SSaurav Kashyap 		    "DCBX Parameters Updated -- %04x %04x %04x.\n",
18597c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
18603a03eb79SAndrew Vasquez 		break;
18613a03eb79SAndrew Vasquez 	case MBA_FCF_CONF_ERR:
18627c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5020,
18637c3df132SSaurav Kashyap 		    "FCF Configuration Error -- %04x %04x %04x.\n",
18647c3df132SSaurav Kashyap 		    mb[1], mb[2], mb[3]);
18653a03eb79SAndrew Vasquez 		break;
18663a03eb79SAndrew Vasquez 	case MBA_IDC_NOTIFY:
18677ec0effdSAtul Deshmukh 		if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
186804474d3aSBart Van Assche 			mb[4] = rd_reg_word(&reg24->mailbox4);
186967b2a31fSChad Dupuis 			if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
187067b2a31fSChad Dupuis 			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
187167b2a31fSChad Dupuis 			    (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
18728fcd6b8bSChad Dupuis 				set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
187367b2a31fSChad Dupuis 				/*
187467b2a31fSChad Dupuis 				 * Extend loop down timer since port is active.
187567b2a31fSChad Dupuis 				 */
187667b2a31fSChad Dupuis 				if (atomic_read(&vha->loop_state) == LOOP_DOWN)
187767b2a31fSChad Dupuis 					atomic_set(&vha->loop_down_timer,
187867b2a31fSChad Dupuis 					    LOOP_DOWN_TIME);
18798fcd6b8bSChad Dupuis 				qla2xxx_wake_dpc(vha);
18808fcd6b8bSChad Dupuis 			}
188167b2a31fSChad Dupuis 		}
1882df561f66SGustavo A. R. Silva 		fallthrough;
18838fcd6b8bSChad Dupuis 	case MBA_IDC_COMPLETE:
18849aaf2ceaSChad Dupuis 		if (ha->notify_lb_portup_comp && !vha->vp_idx)
1885f356bef1SChad Dupuis 			complete(&ha->lb_portup_comp);
1886df561f66SGustavo A. R. Silva 		fallthrough;
18873a03eb79SAndrew Vasquez 	case MBA_IDC_TIME_EXT:
18887ec0effdSAtul Deshmukh 		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
18897ec0effdSAtul Deshmukh 		    IS_QLA8044(ha))
18908a659571SAndrew Vasquez 			qla81xx_idc_event(vha, mb[0], mb[1]);
18913a03eb79SAndrew Vasquez 		break;
18927d613ac6SSantosh Vernekar 
18937d613ac6SSantosh Vernekar 	case MBA_IDC_AEN:
1894d52cd774SQuinn Tran 		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
1895dbf1f53cSSaurav Kashyap 			vha->hw_err_cnt++;
1896cbb01c2fSArun Easi 			qla27xx_handle_8200_aen(vha, mb);
1897d52cd774SQuinn Tran 		} else if (IS_QLA83XX(ha)) {
189804474d3aSBart Van Assche 			mb[4] = rd_reg_word(&reg24->mailbox4);
189904474d3aSBart Van Assche 			mb[5] = rd_reg_word(&reg24->mailbox5);
190004474d3aSBart Van Assche 			mb[6] = rd_reg_word(&reg24->mailbox6);
190104474d3aSBart Van Assche 			mb[7] = rd_reg_word(&reg24->mailbox7);
19027d613ac6SSantosh Vernekar 			qla83xx_handle_8200_aen(vha, mb);
1903d52cd774SQuinn Tran 		} else {
1904d52cd774SQuinn Tran 			ql_dbg(ql_dbg_async, vha, 0x5052,
1905d52cd774SQuinn Tran 			    "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n",
1906d52cd774SQuinn Tran 			    mb[0], mb[1], mb[2], mb[3]);
1907d52cd774SQuinn Tran 		}
19087d613ac6SSantosh Vernekar 		break;
19097d613ac6SSantosh Vernekar 
1910b5a340ddSJoe Carnuccio 	case MBA_DPORT_DIAGNOSTICS:
1911476da8faSBikash Hazarika 		if ((mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_NOERR ||
1912476da8faSBikash Hazarika 		    (mb[1] & 0xF) == AEN_DONE_DIAG_TEST_WITH_ERR)
1913476da8faSBikash Hazarika 			vha->dport_status &= ~DPORT_DIAG_IN_PROGRESS;
1914b5a340ddSJoe Carnuccio 		ql_dbg(ql_dbg_async, vha, 0x5052,
191542521564SJoe Carnuccio 		    "D-Port Diagnostics: %04x %04x %04x %04x\n",
191642521564SJoe Carnuccio 		    mb[0], mb[1], mb[2], mb[3]);
1917e6ad2b79SJoe Carnuccio 		memcpy(vha->dport_data, mb, sizeof(vha->dport_data));
191842521564SJoe Carnuccio 		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
191942521564SJoe Carnuccio 			static char *results[] = {
192042521564SJoe Carnuccio 			    "start", "done(pass)", "done(error)", "undefined" };
192142521564SJoe Carnuccio 			static char *types[] = {
192242521564SJoe Carnuccio 			    "none", "dynamic", "static", "other" };
192342521564SJoe Carnuccio 			uint result = mb[1] >> 0 & 0x3;
192442521564SJoe Carnuccio 			uint type = mb[1] >> 6 & 0x3;
192542521564SJoe Carnuccio 			uint sw = mb[1] >> 15 & 0x1;
192642521564SJoe Carnuccio 			ql_dbg(ql_dbg_async, vha, 0x5052,
192742521564SJoe Carnuccio 			    "D-Port Diagnostics: result=%s type=%s [sw=%u]\n",
192842521564SJoe Carnuccio 			    results[result], types[type], sw);
192942521564SJoe Carnuccio 			if (result == 2) {
193042521564SJoe Carnuccio 				static char *reasons[] = {
193142521564SJoe Carnuccio 				    "reserved", "unexpected reject",
193242521564SJoe Carnuccio 				    "unexpected phase", "retry exceeded",
193342521564SJoe Carnuccio 				    "timed out", "not supported",
193442521564SJoe Carnuccio 				    "user stopped" };
193542521564SJoe Carnuccio 				uint reason = mb[2] >> 0 & 0xf;
193642521564SJoe Carnuccio 				uint phase = mb[2] >> 12 & 0xf;
193742521564SJoe Carnuccio 				ql_dbg(ql_dbg_async, vha, 0x5052,
193842521564SJoe Carnuccio 				    "D-Port Diagnostics: reason=%s phase=%u \n",
193942521564SJoe Carnuccio 				    reason < 7 ? reasons[reason] : "other",
194042521564SJoe Carnuccio 				    phase >> 1);
194142521564SJoe Carnuccio 			}
194242521564SJoe Carnuccio 		}
1943b5a340ddSJoe Carnuccio 		break;
1944b5a340ddSJoe Carnuccio 
1945a29b3dd7SJoe Carnuccio 	case MBA_TEMPERATURE_ALERT:
1946cd248a95SBikash Hazarika 		if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
1947cd248a95SBikash Hazarika 			display_Laser_info(vha, mb[1], mb[2], mb[3]);
1948a29b3dd7SJoe Carnuccio 		ql_dbg(ql_dbg_async, vha, 0x505e,
1949a29b3dd7SJoe Carnuccio 		    "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
1950a29b3dd7SJoe Carnuccio 		break;
1951a29b3dd7SJoe Carnuccio 
195292d4408eSSawan Chandak 	case MBA_TRANS_INSERT:
195392d4408eSSawan Chandak 		ql_dbg(ql_dbg_async, vha, 0x5091,
195492d4408eSSawan Chandak 		    "Transceiver Insertion: %04x\n", mb[1]);
1955b0f18eeeSAndrew Vasquez 		set_bit(DETECT_SFP_CHANGE, &vha->dpc_flags);
1956b0f18eeeSAndrew Vasquez 		break;
1957b0f18eeeSAndrew Vasquez 
1958b0f18eeeSAndrew Vasquez 	case MBA_TRANS_REMOVE:
1959b0f18eeeSAndrew Vasquez 		ql_dbg(ql_dbg_async, vha, 0x5091, "Transceiver Removal\n");
196092d4408eSSawan Chandak 		break;
196192d4408eSSawan Chandak 
19626246b8a1SGiridhar Malavali 	default:
19636246b8a1SGiridhar Malavali 		ql_dbg(ql_dbg_async, vha, 0x5057,
19646246b8a1SGiridhar Malavali 		    "Unknown AEN:%04x %04x %04x %04x\n",
19656246b8a1SGiridhar Malavali 		    mb[0], mb[1], mb[2], mb[3]);
19661da177e4SLinus Torvalds 	}
19672c3dfe3fSSeokmann Ju 
19682d70c103SNicholas Bellinger 	qlt_async_event(mb[0], vha, mb);
19692d70c103SNicholas Bellinger 
1970e315cd28SAnirban Chakraborty 	if (!vha->vp_idx && ha->num_vhosts)
197173208dfdSAnirban Chakraborty 		qla2x00_alert_all_vps(rsp, mb);
19721da177e4SLinus Torvalds }
19731da177e4SLinus Torvalds 
19741da177e4SLinus Torvalds /**
19751da177e4SLinus Torvalds  * qla2x00_process_completed_request() - Process a Fast Post response.
19762db6228dSBart Van Assche  * @vha: SCSI driver HA context
19772db6228dSBart Van Assche  * @req: request queue
19781da177e4SLinus Torvalds  * @index: SRB index
19791da177e4SLinus Torvalds  */
19808ae6d9c7SGiridhar Malavali void
qla2x00_process_completed_request(struct scsi_qla_host * vha,struct req_que * req,uint32_t index)198173208dfdSAnirban Chakraborty qla2x00_process_completed_request(struct scsi_qla_host *vha,
198273208dfdSAnirban Chakraborty 				  struct req_que *req, uint32_t index)
19831da177e4SLinus Torvalds {
19841da177e4SLinus Torvalds 	srb_t *sp;
1985e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
19861da177e4SLinus Torvalds 
19871da177e4SLinus Torvalds 	/* Validate handle. */
19888d93f550SChad Dupuis 	if (index >= req->num_outstanding_cmds) {
19897c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x3014,
19907c3df132SSaurav Kashyap 		    "Invalid SCSI command index (%x).\n", index);
19911da177e4SLinus Torvalds 
19927ec0effdSAtul Deshmukh 		if (IS_P3P_TYPE(ha))
19938f7daeadSGiridhar Malavali 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
19948f7daeadSGiridhar Malavali 		else
1995e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
19961da177e4SLinus Torvalds 		return;
19971da177e4SLinus Torvalds 	}
19981da177e4SLinus Torvalds 
1999e315cd28SAnirban Chakraborty 	sp = req->outstanding_cmds[index];
20001da177e4SLinus Torvalds 	if (sp) {
20011da177e4SLinus Torvalds 		/* Free outstanding command slot. */
2002e315cd28SAnirban Chakraborty 		req->outstanding_cmds[index] = NULL;
20031da177e4SLinus Torvalds 
20041da177e4SLinus Torvalds 		/* Save ISP completion status */
200525ff6af1SJoe Carnuccio 		sp->done(sp, DID_OK << 16);
20061da177e4SLinus Torvalds 	} else {
20077c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
20081da177e4SLinus Torvalds 
20097ec0effdSAtul Deshmukh 		if (IS_P3P_TYPE(ha))
20108f7daeadSGiridhar Malavali 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
20118f7daeadSGiridhar Malavali 		else
2012e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
20131da177e4SLinus Torvalds 	}
20141da177e4SLinus Torvalds }
20151da177e4SLinus Torvalds 
2016b843addeSQuinn Tran static srb_t *
qla_get_sp_from_handle(scsi_qla_host_t * vha,const char * func,struct req_que * req,void * iocb,u16 * ret_index)2017b843addeSQuinn Tran qla_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
2018b843addeSQuinn Tran 		       struct req_que *req, void *iocb, u16 *ret_index)
2019ac280b67SAndrew Vasquez {
2020ac280b67SAndrew Vasquez 	struct qla_hw_data *ha = vha->hw;
2021ac280b67SAndrew Vasquez 	sts_entry_t *pkt = iocb;
2022622299f1SDaniel Wagner 	srb_t *sp;
2023ac280b67SAndrew Vasquez 	uint16_t index;
2024ac280b67SAndrew Vasquez 
2025fac28079SQuinn Tran 	if (pkt->handle == QLA_SKIP_HANDLE)
2026fac28079SQuinn Tran 		return NULL;
2027fac28079SQuinn Tran 
2028ac280b67SAndrew Vasquez 	index = LSW(pkt->handle);
20298d93f550SChad Dupuis 	if (index >= req->num_outstanding_cmds) {
20307c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5031,
20317d88d5dfSDaniel Wagner 			   "%s: Invalid command index (%x) type %8ph.\n",
20327d88d5dfSDaniel Wagner 			   func, index, iocb);
20337ec0effdSAtul Deshmukh 		if (IS_P3P_TYPE(ha))
20348f7daeadSGiridhar Malavali 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
20358f7daeadSGiridhar Malavali 		else
2036ac280b67SAndrew Vasquez 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2037622299f1SDaniel Wagner 		return NULL;
2038ac280b67SAndrew Vasquez 	}
2039ac280b67SAndrew Vasquez 	sp = req->outstanding_cmds[index];
2040ac280b67SAndrew Vasquez 	if (!sp) {
20417c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5032,
20427d88d5dfSDaniel Wagner 			"%s: Invalid completion handle (%x) -- timed-out.\n",
20437d88d5dfSDaniel Wagner 			func, index);
2044622299f1SDaniel Wagner 		return NULL;
2045ac280b67SAndrew Vasquez 	}
2046ac280b67SAndrew Vasquez 	if (sp->handle != index) {
20477c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x5033,
20487d88d5dfSDaniel Wagner 			"%s: SRB handle (%x) mismatch %x.\n", func,
20497d88d5dfSDaniel Wagner 			sp->handle, index);
2050ac280b67SAndrew Vasquez 		return NULL;
2051ac280b67SAndrew Vasquez 	}
20529a069e19SGiridhar Malavali 
2053b843addeSQuinn Tran 	*ret_index = index;
2054b843addeSQuinn Tran 	qla_put_fw_resources(sp->qpair, &sp->iores);
2055b843addeSQuinn Tran 	return sp;
2056b843addeSQuinn Tran }
2057b843addeSQuinn Tran 
2058b843addeSQuinn Tran srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t * vha,const char * func,struct req_que * req,void * iocb)2059b843addeSQuinn Tran qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
2060b843addeSQuinn Tran 			   struct req_que *req, void *iocb)
2061b843addeSQuinn Tran {
2062b843addeSQuinn Tran 	uint16_t index;
2063b843addeSQuinn Tran 	srb_t *sp;
2064b843addeSQuinn Tran 
2065b843addeSQuinn Tran 	sp = qla_get_sp_from_handle(vha, func, req, iocb, &index);
2066b843addeSQuinn Tran 	if (sp)
2067ac280b67SAndrew Vasquez 		req->outstanding_cmds[index] = NULL;
2068d3affdebSQuinn Tran 
2069ac280b67SAndrew Vasquez 	return sp;
2070ac280b67SAndrew Vasquez }
2071ac280b67SAndrew Vasquez 
2072ac280b67SAndrew Vasquez static void
qla2x00_mbx_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,struct mbx_entry * mbx)2073ac280b67SAndrew Vasquez qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
2074ac280b67SAndrew Vasquez     struct mbx_entry *mbx)
2075ac280b67SAndrew Vasquez {
2076ac280b67SAndrew Vasquez 	const char func[] = "MBX-IOCB";
2077ac280b67SAndrew Vasquez 	const char *type;
2078ac280b67SAndrew Vasquez 	fc_port_t *fcport;
2079ac280b67SAndrew Vasquez 	srb_t *sp;
20804916392bSMadhuranath Iyengar 	struct srb_iocb *lio;
208199b0bec7SAndrew Vasquez 	uint16_t *data;
20825ff1d584SAndrew Vasquez 	uint16_t status;
2083ac280b67SAndrew Vasquez 
2084ac280b67SAndrew Vasquez 	sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
2085ac280b67SAndrew Vasquez 	if (!sp)
2086ac280b67SAndrew Vasquez 		return;
2087ac280b67SAndrew Vasquez 
20889ba56b95SGiridhar Malavali 	lio = &sp->u.iocb_cmd;
20899ba56b95SGiridhar Malavali 	type = sp->name;
2090ac280b67SAndrew Vasquez 	fcport = sp->fcport;
20914916392bSMadhuranath Iyengar 	data = lio->u.logio.data;
2092ac280b67SAndrew Vasquez 
20935ff1d584SAndrew Vasquez 	data[0] = MBS_COMMAND_ERROR;
20944916392bSMadhuranath Iyengar 	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
20955ff1d584SAndrew Vasquez 	    QLA_LOGIO_LOGIN_RETRIED : 0;
2096ac280b67SAndrew Vasquez 	if (mbx->entry_status) {
20977c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5043,
2098cfb0919cSChad Dupuis 		    "Async-%s error entry - hdl=%x portid=%02x%02x%02x "
2099d3fa9e7dSAndrew Vasquez 		    "entry-status=%x status=%x state-flag=%x "
2100cfb0919cSChad Dupuis 		    "status-flags=%x.\n", type, sp->handle,
2101cfb0919cSChad Dupuis 		    fcport->d_id.b.domain, fcport->d_id.b.area,
2102d3fa9e7dSAndrew Vasquez 		    fcport->d_id.b.al_pa, mbx->entry_status,
2103d3fa9e7dSAndrew Vasquez 		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
21047c3df132SSaurav Kashyap 		    le16_to_cpu(mbx->status_flags));
2105d3fa9e7dSAndrew Vasquez 
2106cfb0919cSChad Dupuis 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
2107f8f97b0cSJoe Carnuccio 		    mbx, sizeof(*mbx));
2108ac280b67SAndrew Vasquez 
210999b0bec7SAndrew Vasquez 		goto logio_done;
2110ac280b67SAndrew Vasquez 	}
2111ac280b67SAndrew Vasquez 
21125ff1d584SAndrew Vasquez 	status = le16_to_cpu(mbx->status);
21139ba56b95SGiridhar Malavali 	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
21145ff1d584SAndrew Vasquez 	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
21155ff1d584SAndrew Vasquez 		status = 0;
21165ff1d584SAndrew Vasquez 	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
21177c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_async, vha, 0x5045,
2118cfb0919cSChad Dupuis 		    "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n",
2119cfb0919cSChad Dupuis 		    type, sp->handle, fcport->d_id.b.domain,
2120cfb0919cSChad Dupuis 		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
2121cfb0919cSChad Dupuis 		    le16_to_cpu(mbx->mb1));
2122ac280b67SAndrew Vasquez 
2123ac280b67SAndrew Vasquez 		data[0] = MBS_COMMAND_COMPLETE;
21249ba56b95SGiridhar Malavali 		if (sp->type == SRB_LOGIN_CMD) {
212599b0bec7SAndrew Vasquez 			fcport->port_type = FCT_TARGET;
212699b0bec7SAndrew Vasquez 			if (le16_to_cpu(mbx->mb1) & BIT_0)
212799b0bec7SAndrew Vasquez 				fcport->port_type = FCT_INITIATOR;
21286ac52608SAndrew Vasquez 			else if (le16_to_cpu(mbx->mb1) & BIT_1)
21298474f3a0SSantosh Vernekar 				fcport->flags |= FCF_FCP2_DEVICE;
21305ff1d584SAndrew Vasquez 		}
213199b0bec7SAndrew Vasquez 		goto logio_done;
2132ac280b67SAndrew Vasquez 	}
2133ac280b67SAndrew Vasquez 
2134ac280b67SAndrew Vasquez 	data[0] = le16_to_cpu(mbx->mb0);
2135ac280b67SAndrew Vasquez 	switch (data[0]) {
2136ac280b67SAndrew Vasquez 	case MBS_PORT_ID_USED:
2137ac280b67SAndrew Vasquez 		data[1] = le16_to_cpu(mbx->mb1);
2138ac280b67SAndrew Vasquez 		break;
2139ac280b67SAndrew Vasquez 	case MBS_LOOP_ID_USED:
2140ac280b67SAndrew Vasquez 		break;
2141ac280b67SAndrew Vasquez 	default:
2142ac280b67SAndrew Vasquez 		data[0] = MBS_COMMAND_ERROR;
2143ac280b67SAndrew Vasquez 		break;
2144ac280b67SAndrew Vasquez 	}
2145ac280b67SAndrew Vasquez 
21467c3df132SSaurav Kashyap 	ql_log(ql_log_warn, vha, 0x5046,
2147cfb0919cSChad Dupuis 	    "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x "
2148cfb0919cSChad Dupuis 	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle,
2149cfb0919cSChad Dupuis 	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
2150cfb0919cSChad Dupuis 	    status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
2151ac280b67SAndrew Vasquez 	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
21527c3df132SSaurav Kashyap 	    le16_to_cpu(mbx->mb7));
2153ac280b67SAndrew Vasquez 
215499b0bec7SAndrew Vasquez logio_done:
215525ff6af1SJoe Carnuccio 	sp->done(sp, 0);
2156ac280b67SAndrew Vasquez }
2157ac280b67SAndrew Vasquez 
2158ac280b67SAndrew Vasquez static void
qla24xx_mbx_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,struct mbx_24xx_entry * pkt)2159726b8548SQuinn Tran qla24xx_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
2160726b8548SQuinn Tran     struct mbx_24xx_entry *pkt)
2161726b8548SQuinn Tran {
2162726b8548SQuinn Tran 	const char func[] = "MBX-IOCB2";
2163657ed8a8SDaniel Wagner 	struct qla_hw_data *ha = vha->hw;
2164726b8548SQuinn Tran 	srb_t *sp;
2165726b8548SQuinn Tran 	struct srb_iocb *si;
2166726b8548SQuinn Tran 	u16 sz, i;
2167726b8548SQuinn Tran 	int res;
2168726b8548SQuinn Tran 
2169726b8548SQuinn Tran 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
2170726b8548SQuinn Tran 	if (!sp)
2171726b8548SQuinn Tran 		return;
2172726b8548SQuinn Tran 
2173657ed8a8SDaniel Wagner 	if (sp->type == SRB_SCSI_CMD ||
2174657ed8a8SDaniel Wagner 	    sp->type == SRB_NVME_CMD ||
2175657ed8a8SDaniel Wagner 	    sp->type == SRB_TM_CMD) {
2176657ed8a8SDaniel Wagner 		ql_log(ql_log_warn, vha, 0x509d,
2177657ed8a8SDaniel Wagner 			"Inconsistent event entry type %d\n", sp->type);
2178657ed8a8SDaniel Wagner 		if (IS_P3P_TYPE(ha))
2179657ed8a8SDaniel Wagner 			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
2180657ed8a8SDaniel Wagner 		else
2181657ed8a8SDaniel Wagner 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2182657ed8a8SDaniel Wagner 		return;
2183657ed8a8SDaniel Wagner 	}
2184657ed8a8SDaniel Wagner 
2185726b8548SQuinn Tran 	si = &sp->u.iocb_cmd;
2186726b8548SQuinn Tran 	sz = min(ARRAY_SIZE(pkt->mb), ARRAY_SIZE(sp->u.iocb_cmd.u.mbx.in_mb));
2187726b8548SQuinn Tran 
2188726b8548SQuinn Tran 	for (i = 0; i < sz; i++)
21897ffa5b93SBart Van Assche 		si->u.mbx.in_mb[i] = pkt->mb[i];
2190726b8548SQuinn Tran 
2191726b8548SQuinn Tran 	res = (si->u.mbx.in_mb[0] & MBS_MASK);
2192726b8548SQuinn Tran 
219325ff6af1SJoe Carnuccio 	sp->done(sp, res);
2194726b8548SQuinn Tran }
2195726b8548SQuinn Tran 
2196726b8548SQuinn Tran static void
qla24xxx_nack_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,struct nack_to_isp * pkt)2197726b8548SQuinn Tran qla24xxx_nack_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
2198726b8548SQuinn Tran     struct nack_to_isp *pkt)
2199726b8548SQuinn Tran {
2200726b8548SQuinn Tran 	const char func[] = "nack";
2201726b8548SQuinn Tran 	srb_t *sp;
2202726b8548SQuinn Tran 	int res = 0;
2203726b8548SQuinn Tran 
2204726b8548SQuinn Tran 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
2205726b8548SQuinn Tran 	if (!sp)
2206726b8548SQuinn Tran 		return;
2207726b8548SQuinn Tran 
2208726b8548SQuinn Tran 	if (pkt->u.isp2x.status != cpu_to_le16(NOTIFY_ACK_SUCCESS))
2209726b8548SQuinn Tran 		res = QLA_FUNCTION_FAILED;
2210726b8548SQuinn Tran 
221125ff6af1SJoe Carnuccio 	sp->done(sp, res);
2212ac280b67SAndrew Vasquez }
2213ac280b67SAndrew Vasquez 
2214ac280b67SAndrew Vasquez static void
qla2x00_ct_entry(scsi_qla_host_t * vha,struct req_que * req,sts_entry_t * pkt,int iocb_type)22159bc4f4fbSHarish Zunjarrao qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
22169bc4f4fbSHarish Zunjarrao     sts_entry_t *pkt, int iocb_type)
22179bc4f4fbSHarish Zunjarrao {
22189bc4f4fbSHarish Zunjarrao 	const char func[] = "CT_IOCB";
22199bc4f4fbSHarish Zunjarrao 	const char *type;
22209bc4f4fbSHarish Zunjarrao 	srb_t *sp;
222175cc8cfcSJohannes Thumshirn 	struct bsg_job *bsg_job;
222201e0e15cSJohannes Thumshirn 	struct fc_bsg_reply *bsg_reply;
22239bc4f4fbSHarish Zunjarrao 	uint16_t comp_status;
2224726b8548SQuinn Tran 	int res = 0;
22259bc4f4fbSHarish Zunjarrao 
22269bc4f4fbSHarish Zunjarrao 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
22279bc4f4fbSHarish Zunjarrao 	if (!sp)
22289bc4f4fbSHarish Zunjarrao 		return;
22299bc4f4fbSHarish Zunjarrao 
2230726b8548SQuinn Tran 	switch (sp->type) {
2231726b8548SQuinn Tran 	case SRB_CT_CMD:
22329ba56b95SGiridhar Malavali 	    bsg_job = sp->u.bsg_job;
223301e0e15cSJohannes Thumshirn 	    bsg_reply = bsg_job->reply;
22349bc4f4fbSHarish Zunjarrao 
22359bc4f4fbSHarish Zunjarrao 	    type = "ct pass-through";
22369bc4f4fbSHarish Zunjarrao 
22379bc4f4fbSHarish Zunjarrao 	    comp_status = le16_to_cpu(pkt->comp_status);
22389bc4f4fbSHarish Zunjarrao 
2239726b8548SQuinn Tran 	    /*
2240726b8548SQuinn Tran 	     * return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
22419bc4f4fbSHarish Zunjarrao 	     * fc payload  to the caller
22429bc4f4fbSHarish Zunjarrao 	     */
224301e0e15cSJohannes Thumshirn 	    bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
22449bc4f4fbSHarish Zunjarrao 	    bsg_job->reply_len = sizeof(struct fc_bsg_reply);
22459bc4f4fbSHarish Zunjarrao 
22469bc4f4fbSHarish Zunjarrao 	    if (comp_status != CS_COMPLETE) {
22479bc4f4fbSHarish Zunjarrao 		    if (comp_status == CS_DATA_UNDERRUN) {
22489ba56b95SGiridhar Malavali 			    res = DID_OK << 16;
224901e0e15cSJohannes Thumshirn 			    bsg_reply->reply_payload_rcv_len =
22501a20719eSBart Van Assche 				le16_to_cpu(pkt->rsp_info_len);
22519bc4f4fbSHarish Zunjarrao 
22527c3df132SSaurav Kashyap 			    ql_log(ql_log_warn, vha, 0x5048,
2253726b8548SQuinn Tran 				"CT pass-through-%s error comp_status=0x%x total_byte=0x%x.\n",
22547c3df132SSaurav Kashyap 				type, comp_status,
225501e0e15cSJohannes Thumshirn 				bsg_reply->reply_payload_rcv_len);
22569bc4f4fbSHarish Zunjarrao 		    } else {
22577c3df132SSaurav Kashyap 			    ql_log(ql_log_warn, vha, 0x5049,
2258726b8548SQuinn Tran 				"CT pass-through-%s error comp_status=0x%x.\n",
2259726b8548SQuinn Tran 				type, comp_status);
22609ba56b95SGiridhar Malavali 			    res = DID_ERROR << 16;
226101e0e15cSJohannes Thumshirn 			    bsg_reply->reply_payload_rcv_len = 0;
22629bc4f4fbSHarish Zunjarrao 		    }
2263cfb0919cSChad Dupuis 		    ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
2264f8f97b0cSJoe Carnuccio 			pkt, sizeof(*pkt));
22659bc4f4fbSHarish Zunjarrao 	    } else {
22669ba56b95SGiridhar Malavali 		    res = DID_OK << 16;
226701e0e15cSJohannes Thumshirn 		    bsg_reply->reply_payload_rcv_len =
22689bc4f4fbSHarish Zunjarrao 			bsg_job->reply_payload.payload_len;
22699bc4f4fbSHarish Zunjarrao 		    bsg_job->reply_len = 0;
22709bc4f4fbSHarish Zunjarrao 	    }
2271726b8548SQuinn Tran 	    break;
2272726b8548SQuinn Tran 	case SRB_CT_PTHRU_CMD:
2273726b8548SQuinn Tran 	    /*
2274726b8548SQuinn Tran 	     * borrowing sts_entry_24xx.comp_status.
2275726b8548SQuinn Tran 	     * same location as ct_entry_24xx.comp_status
2276726b8548SQuinn Tran 	     */
2277726b8548SQuinn Tran 	     res = qla2x00_chk_ms_status(vha, (ms_iocb_entry_t *)pkt,
2278726b8548SQuinn Tran 		 (struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
2279726b8548SQuinn Tran 		 sp->name);
2280726b8548SQuinn Tran 	     break;
2281726b8548SQuinn Tran 	}
22829bc4f4fbSHarish Zunjarrao 
228325ff6af1SJoe Carnuccio 	sp->done(sp, res);
22849bc4f4fbSHarish Zunjarrao }
22859bc4f4fbSHarish Zunjarrao 
22869bc4f4fbSHarish Zunjarrao static void
qla24xx_els_ct_entry(scsi_qla_host_t * v,struct req_que * req,struct sts_entry_24xx * pkt,int iocb_type)228784318a9fSQuinn Tran qla24xx_els_ct_entry(scsi_qla_host_t *v, struct req_que *req,
22889a069e19SGiridhar Malavali     struct sts_entry_24xx *pkt, int iocb_type)
22899a069e19SGiridhar Malavali {
22907ffa5b93SBart Van Assche 	struct els_sts_entry_24xx *ese = (struct els_sts_entry_24xx *)pkt;
22919a069e19SGiridhar Malavali 	const char func[] = "ELS_CT_IOCB";
22929a069e19SGiridhar Malavali 	const char *type;
22939a069e19SGiridhar Malavali 	srb_t *sp;
229475cc8cfcSJohannes Thumshirn 	struct bsg_job *bsg_job;
229501e0e15cSJohannes Thumshirn 	struct fc_bsg_reply *bsg_reply;
22969a069e19SGiridhar Malavali 	uint16_t comp_status;
22979a069e19SGiridhar Malavali 	uint32_t fw_status[3];
229884318a9fSQuinn Tran 	int res, logit = 1;
2299edd05de1SDuane Grigsby 	struct srb_iocb *els;
230084318a9fSQuinn Tran 	uint n;
230184318a9fSQuinn Tran 	scsi_qla_host_t *vha;
230284318a9fSQuinn Tran 	struct els_sts_entry_24xx *e = (struct els_sts_entry_24xx *)pkt;
23039a069e19SGiridhar Malavali 
230484318a9fSQuinn Tran 	sp = qla2x00_get_sp_from_handle(v, func, req, pkt);
23059a069e19SGiridhar Malavali 	if (!sp)
23069a069e19SGiridhar Malavali 		return;
230784318a9fSQuinn Tran 	bsg_job = sp->u.bsg_job;
230884318a9fSQuinn Tran 	vha = sp->vha;
23099a069e19SGiridhar Malavali 
23109a069e19SGiridhar Malavali 	type = NULL;
231184318a9fSQuinn Tran 
231284318a9fSQuinn Tran 	comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
231384318a9fSQuinn Tran 	fw_status[1] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_1);
231484318a9fSQuinn Tran 	fw_status[2] = le32_to_cpu(((struct els_sts_entry_24xx *)pkt)->error_subcode_2);
231584318a9fSQuinn Tran 
23169ba56b95SGiridhar Malavali 	switch (sp->type) {
23179a069e19SGiridhar Malavali 	case SRB_ELS_CMD_RPT:
23189a069e19SGiridhar Malavali 	case SRB_ELS_CMD_HST:
231984318a9fSQuinn Tran 		type = "rpt hst";
232084318a9fSQuinn Tran 		break;
232184318a9fSQuinn Tran 	case SRB_ELS_CMD_HST_NOLOGIN:
23229a069e19SGiridhar Malavali 		type = "els";
232384318a9fSQuinn Tran 		{
232484318a9fSQuinn Tran 			struct els_entry_24xx *els = (void *)pkt;
232584318a9fSQuinn Tran 			struct qla_bsg_auth_els_request *p =
232684318a9fSQuinn Tran 				(struct qla_bsg_auth_els_request *)bsg_job->request;
232784318a9fSQuinn Tran 
232884318a9fSQuinn Tran 			ql_dbg(ql_dbg_user, vha, 0x700f,
232984318a9fSQuinn Tran 			     "%s %s. portid=%02x%02x%02x status %x xchg %x bsg ptr %p\n",
233084318a9fSQuinn Tran 			     __func__, sc_to_str(p->e.sub_cmd),
233184318a9fSQuinn Tran 			     e->d_id[2], e->d_id[1], e->d_id[0],
233284318a9fSQuinn Tran 			     comp_status, p->e.extra_rx_xchg_address, bsg_job);
233384318a9fSQuinn Tran 
233484318a9fSQuinn Tran 			if (!(le16_to_cpu(els->control_flags) & ECF_PAYLOAD_DESCR_MASK)) {
233584318a9fSQuinn Tran 				if (sp->remap.remapped) {
233684318a9fSQuinn Tran 					n = sg_copy_from_buffer(bsg_job->reply_payload.sg_list,
233784318a9fSQuinn Tran 						bsg_job->reply_payload.sg_cnt,
233884318a9fSQuinn Tran 						sp->remap.rsp.buf,
233984318a9fSQuinn Tran 						sp->remap.rsp.len);
234084318a9fSQuinn Tran 					ql_dbg(ql_dbg_user + ql_dbg_verbose, vha, 0x700e,
234184318a9fSQuinn Tran 					   "%s: SG copied %x of %x\n",
234284318a9fSQuinn Tran 					   __func__, n, sp->remap.rsp.len);
234384318a9fSQuinn Tran 				} else {
234484318a9fSQuinn Tran 					ql_dbg(ql_dbg_user, vha, 0x700f,
234584318a9fSQuinn Tran 					   "%s: NOT REMAPPED (error)...!!!\n",
234684318a9fSQuinn Tran 					   __func__);
234784318a9fSQuinn Tran 				}
234884318a9fSQuinn Tran 			}
234984318a9fSQuinn Tran 		}
23509a069e19SGiridhar Malavali 		break;
23519a069e19SGiridhar Malavali 	case SRB_CT_CMD:
23529a069e19SGiridhar Malavali 		type = "ct pass-through";
23539a069e19SGiridhar Malavali 		break;
23546eb54715SHimanshu Madhani 	case SRB_ELS_DCMD:
23556eb54715SHimanshu Madhani 		type = "Driver ELS logo";
2356edd05de1SDuane Grigsby 		if (iocb_type != ELS_IOCB_TYPE) {
23576eb54715SHimanshu Madhani 			ql_dbg(ql_dbg_user, vha, 0x5047,
2358edd05de1SDuane Grigsby 			    "Completing %s: (%p) type=%d.\n",
2359edd05de1SDuane Grigsby 			    type, sp, sp->type);
236025ff6af1SJoe Carnuccio 			sp->done(sp, 0);
23616eb54715SHimanshu Madhani 			return;
2362edd05de1SDuane Grigsby 		}
2363edd05de1SDuane Grigsby 		break;
2364726b8548SQuinn Tran 	case SRB_CT_PTHRU_CMD:
2365726b8548SQuinn Tran 		/* borrowing sts_entry_24xx.comp_status.
2366726b8548SQuinn Tran 		   same location as ct_entry_24xx.comp_status
2367726b8548SQuinn Tran 		 */
23682d73ac61SQuinn Tran 		res = qla2x00_chk_ms_status(sp->vha, (ms_iocb_entry_t *)pkt,
2369726b8548SQuinn Tran 			(struct ct_sns_rsp *)sp->u.iocb_cmd.u.ctarg.rsp,
2370726b8548SQuinn Tran 			sp->name);
237125ff6af1SJoe Carnuccio 		sp->done(sp, res);
23729a069e19SGiridhar Malavali 		return;
23739a069e19SGiridhar Malavali 	default:
23749a069e19SGiridhar Malavali 		ql_dbg(ql_dbg_user, vha, 0x503e,
23759a069e19SGiridhar Malavali 		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
23769a069e19SGiridhar Malavali 		return;
23779a069e19SGiridhar Malavali 	}
23789a069e19SGiridhar Malavali 
2379edd05de1SDuane Grigsby 	if (iocb_type == ELS_IOCB_TYPE) {
2380edd05de1SDuane Grigsby 		els = &sp->u.iocb_cmd;
23817ffa5b93SBart Van Assche 		els->u.els_plogi.fw_status[0] = cpu_to_le32(fw_status[0]);
23827ffa5b93SBart Van Assche 		els->u.els_plogi.fw_status[1] = cpu_to_le32(fw_status[1]);
23837ffa5b93SBart Van Assche 		els->u.els_plogi.fw_status[2] = cpu_to_le32(fw_status[2]);
23847ffa5b93SBart Van Assche 		els->u.els_plogi.comp_status = cpu_to_le16(fw_status[0]);
2385edd05de1SDuane Grigsby 		if (comp_status == CS_COMPLETE) {
2386edd05de1SDuane Grigsby 			res =  DID_OK << 16;
2387edd05de1SDuane Grigsby 		} else {
2388edd05de1SDuane Grigsby 			if (comp_status == CS_DATA_UNDERRUN) {
2389edd05de1SDuane Grigsby 				res =  DID_OK << 16;
23907ffa5b93SBart Van Assche 				els->u.els_plogi.len = cpu_to_le16(le32_to_cpu(
23917ffa5b93SBart Van Assche 					ese->total_byte_count));
239284318a9fSQuinn Tran 
239384318a9fSQuinn Tran 				if (sp->remap.remapped &&
239484318a9fSQuinn Tran 				    ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_ACC) {
239584318a9fSQuinn Tran 					ql_dbg(ql_dbg_user, vha, 0x503f,
239684318a9fSQuinn Tran 					    "%s IOCB Done LS_ACC %02x%02x%02x -> %02x%02x%02x",
239784318a9fSQuinn Tran 					    __func__, e->s_id[0], e->s_id[2], e->s_id[1],
239884318a9fSQuinn Tran 					    e->d_id[2], e->d_id[1], e->d_id[0]);
239984318a9fSQuinn Tran 					logit = 0;
240084318a9fSQuinn Tran 				}
240184318a9fSQuinn Tran 
240284318a9fSQuinn Tran 			} else if (comp_status == CS_PORT_LOGGED_OUT) {
24036c9998ceSQuinn Tran 				ql_dbg(ql_dbg_disc, vha, 0x911e,
24046c9998ceSQuinn Tran 				       "%s %d schedule session deletion\n",
24056c9998ceSQuinn Tran 				       __func__, __LINE__);
24066c9998ceSQuinn Tran 
240784318a9fSQuinn Tran 				els->u.els_plogi.len = 0;
240884318a9fSQuinn Tran 				res = DID_IMM_RETRY << 16;
2409b15ce2f3SQuinn Tran 				qlt_schedule_sess_for_deletion(sp->fcport);
2410edd05de1SDuane Grigsby 			} else {
2411edd05de1SDuane Grigsby 				els->u.els_plogi.len = 0;
2412edd05de1SDuane Grigsby 				res = DID_ERROR << 16;
2413edd05de1SDuane Grigsby 			}
241484318a9fSQuinn Tran 
241584318a9fSQuinn Tran 			if (sp->remap.remapped &&
241684318a9fSQuinn Tran 			    ((u8 *)sp->remap.rsp.buf)[0] == ELS_LS_RJT) {
2417bcf53607SQuinn Tran 				if (logit) {
241884318a9fSQuinn Tran 					ql_dbg(ql_dbg_user, vha, 0x503f,
241984318a9fSQuinn Tran 					    "%s IOCB Done LS_RJT hdl=%x comp_status=0x%x\n",
242084318a9fSQuinn Tran 					    type, sp->handle, comp_status);
242184318a9fSQuinn Tran 
242284318a9fSQuinn Tran 					ql_dbg(ql_dbg_user, vha, 0x503f,
242384318a9fSQuinn Tran 					    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
242484318a9fSQuinn Tran 					    fw_status[1], fw_status[2],
242584318a9fSQuinn Tran 					    le32_to_cpu(((struct els_sts_entry_24xx *)
242684318a9fSQuinn Tran 						pkt)->total_byte_count),
242784318a9fSQuinn Tran 					    e->s_id[0], e->s_id[2], e->s_id[1],
242884318a9fSQuinn Tran 					    e->d_id[2], e->d_id[1], e->d_id[0]);
2429bcf53607SQuinn Tran 				}
2430bcf53607SQuinn Tran 				if (sp->fcport && sp->fcport->flags & FCF_FCSP_DEVICE &&
2431bcf53607SQuinn Tran 				    sp->type == SRB_ELS_CMD_HST_NOLOGIN) {
2432bcf53607SQuinn Tran 					ql_dbg(ql_dbg_edif, vha, 0x911e,
2433bcf53607SQuinn Tran 					    "%s rcv reject. Sched delete\n", __func__);
2434bcf53607SQuinn Tran 					qlt_schedule_sess_for_deletion(sp->fcport);
2435bcf53607SQuinn Tran 				}
2436bcf53607SQuinn Tran 			} else if (logit) {
243784318a9fSQuinn Tran 				ql_log(ql_log_info, vha, 0x503f,
243884318a9fSQuinn Tran 				    "%s IOCB Done hdl=%x comp_status=0x%x\n",
243984318a9fSQuinn Tran 				    type, sp->handle, comp_status);
244084318a9fSQuinn Tran 				ql_log(ql_log_info, vha, 0x503f,
244184318a9fSQuinn Tran 				    "subcode 1=0x%x subcode 2=0x%x bytes=0x%x %02x%02x%02x -> %02x%02x%02x\n",
244284318a9fSQuinn Tran 				    fw_status[1], fw_status[2],
244384318a9fSQuinn Tran 				    le32_to_cpu(((struct els_sts_entry_24xx *)
244484318a9fSQuinn Tran 				    pkt)->total_byte_count),
244584318a9fSQuinn Tran 				    e->s_id[0], e->s_id[2], e->s_id[1],
244684318a9fSQuinn Tran 				    e->d_id[2], e->d_id[1], e->d_id[0]);
2447edd05de1SDuane Grigsby 			}
244884318a9fSQuinn Tran 		}
2449edd05de1SDuane Grigsby 		goto els_ct_done;
2450edd05de1SDuane Grigsby 	}
2451edd05de1SDuane Grigsby 
24529a069e19SGiridhar Malavali 	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
24539a069e19SGiridhar Malavali 	 * fc payload  to the caller
24549a069e19SGiridhar Malavali 	 */
2455a1730595SDuane Grigsby 	bsg_job = sp->u.bsg_job;
2456a1730595SDuane Grigsby 	bsg_reply = bsg_job->reply;
245701e0e15cSJohannes Thumshirn 	bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
24589a069e19SGiridhar Malavali 	bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);
24599a069e19SGiridhar Malavali 
24609a069e19SGiridhar Malavali 	if (comp_status != CS_COMPLETE) {
24619a069e19SGiridhar Malavali 		if (comp_status == CS_DATA_UNDERRUN) {
24629ba56b95SGiridhar Malavali 			res = DID_OK << 16;
246301e0e15cSJohannes Thumshirn 			bsg_reply->reply_payload_rcv_len =
24647ffa5b93SBart Van Assche 				le32_to_cpu(ese->total_byte_count);
24659a069e19SGiridhar Malavali 
246637fed3eeSAndrew Vasquez 			ql_dbg(ql_dbg_user, vha, 0x503f,
2467cfb0919cSChad Dupuis 			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
24689a069e19SGiridhar Malavali 			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
2469cfb0919cSChad Dupuis 			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
24707ffa5b93SBart Van Assche 			    le32_to_cpu(ese->total_byte_count));
247105231a3bSChristoph Hellwig 		} else {
247237fed3eeSAndrew Vasquez 			ql_dbg(ql_dbg_user, vha, 0x5040,
2473cfb0919cSChad Dupuis 			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
24749a069e19SGiridhar Malavali 			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
2475cfb0919cSChad Dupuis 			    type, sp->handle, comp_status,
24767ffa5b93SBart Van Assche 			    le32_to_cpu(ese->error_subcode_1),
24777ffa5b93SBart Van Assche 			    le32_to_cpu(ese->error_subcode_2));
24789ba56b95SGiridhar Malavali 			res = DID_ERROR << 16;
247901e0e15cSJohannes Thumshirn 			bsg_reply->reply_payload_rcv_len = 0;
24809a069e19SGiridhar Malavali 		}
248105231a3bSChristoph Hellwig 		memcpy(bsg_job->reply + sizeof(struct fc_bsg_reply),
248205231a3bSChristoph Hellwig 		       fw_status, sizeof(fw_status));
248337fed3eeSAndrew Vasquez 		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
2484f8f97b0cSJoe Carnuccio 		    pkt, sizeof(*pkt));
24859a069e19SGiridhar Malavali 	}
24869a069e19SGiridhar Malavali 	else {
24879ba56b95SGiridhar Malavali 		res =  DID_OK << 16;
248801e0e15cSJohannes Thumshirn 		bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
24899a069e19SGiridhar Malavali 		bsg_job->reply_len = 0;
24909a069e19SGiridhar Malavali 	}
2491edd05de1SDuane Grigsby els_ct_done:
24929a069e19SGiridhar Malavali 
249325ff6af1SJoe Carnuccio 	sp->done(sp, res);
24949a069e19SGiridhar Malavali }
24959a069e19SGiridhar Malavali 
24969a069e19SGiridhar Malavali static void
qla24xx_logio_entry(scsi_qla_host_t * vha,struct req_que * req,struct logio_entry_24xx * logio)2497ac280b67SAndrew Vasquez qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
2498ac280b67SAndrew Vasquez     struct logio_entry_24xx *logio)
2499ac280b67SAndrew Vasquez {
2500ac280b67SAndrew Vasquez 	const char func[] = "LOGIO-IOCB";
2501ac280b67SAndrew Vasquez 	const char *type;
2502ac280b67SAndrew Vasquez 	fc_port_t *fcport;
2503ac280b67SAndrew Vasquez 	srb_t *sp;
25044916392bSMadhuranath Iyengar 	struct srb_iocb *lio;
250599b0bec7SAndrew Vasquez 	uint16_t *data;
2506ac280b67SAndrew Vasquez 	uint32_t iop[2];
2507a5741427SArun Easi 	int logit = 1;
2508ac280b67SAndrew Vasquez 
2509ac280b67SAndrew Vasquez 	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
2510ac280b67SAndrew Vasquez 	if (!sp)
2511ac280b67SAndrew Vasquez 		return;
2512ac280b67SAndrew Vasquez 
25139ba56b95SGiridhar Malavali 	lio = &sp->u.iocb_cmd;
25149ba56b95SGiridhar Malavali 	type = sp->name;
2515ac280b67SAndrew Vasquez 	fcport = sp->fcport;
25164916392bSMadhuranath Iyengar 	data = lio->u.logio.data;
2517ac280b67SAndrew Vasquez 
25185ff1d584SAndrew Vasquez 	data[0] = MBS_COMMAND_ERROR;
25194916392bSMadhuranath Iyengar 	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
25205ff1d584SAndrew Vasquez 		QLA_LOGIO_LOGIN_RETRIED : 0;
2521ac280b67SAndrew Vasquez 	if (logio->entry_status) {
25225e19ed90SArun Easi 		ql_log(ql_log_warn, fcport->vha, 0x5034,
25235b33469aSQuinn Tran 		    "Async-%s error entry - %8phC hdl=%x"
2524d3fa9e7dSAndrew Vasquez 		    "portid=%02x%02x%02x entry-status=%x.\n",
25255b33469aSQuinn Tran 		    type, fcport->port_name, sp->handle, fcport->d_id.b.domain,
2526cfb0919cSChad Dupuis 		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
2527cfb0919cSChad Dupuis 		    logio->entry_status);
2528cfb0919cSChad Dupuis 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
2529f8f97b0cSJoe Carnuccio 		    logio, sizeof(*logio));
2530ac280b67SAndrew Vasquez 
253199b0bec7SAndrew Vasquez 		goto logio_done;
2532ac280b67SAndrew Vasquez 	}
2533ac280b67SAndrew Vasquez 
2534ac280b67SAndrew Vasquez 	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
2535cbe729a6SJoe Carnuccio 		ql_dbg(ql_dbg_async, sp->vha, 0x5036,
2536cbe729a6SJoe Carnuccio 		    "Async-%s complete: handle=%x pid=%06x wwpn=%8phC iop0=%x\n",
2537cbe729a6SJoe Carnuccio 		    type, sp->handle, fcport->d_id.b24, fcport->port_name,
25387c3df132SSaurav Kashyap 		    le32_to_cpu(logio->io_parameter[0]));
2539ac280b67SAndrew Vasquez 
2540ead03855SQuinn Tran 		vha->hw->exch_starvation = 0;
2541ac280b67SAndrew Vasquez 		data[0] = MBS_COMMAND_COMPLETE;
254203aaa89fSDarren Trapp 
254303aaa89fSDarren Trapp 		if (sp->type == SRB_PRLI_CMD) {
254403aaa89fSDarren Trapp 			lio->u.logio.iop[0] =
254503aaa89fSDarren Trapp 			    le32_to_cpu(logio->io_parameter[0]);
254603aaa89fSDarren Trapp 			lio->u.logio.iop[1] =
254703aaa89fSDarren Trapp 			    le32_to_cpu(logio->io_parameter[1]);
254803aaa89fSDarren Trapp 			goto logio_done;
254903aaa89fSDarren Trapp 		}
255003aaa89fSDarren Trapp 
25519ba56b95SGiridhar Malavali 		if (sp->type != SRB_LOGIN_CMD)
255299b0bec7SAndrew Vasquez 			goto logio_done;
2553ac280b67SAndrew Vasquez 
25549efea843SQuinn Tran 		lio->u.logio.iop[1] = le32_to_cpu(logio->io_parameter[5]);
25559efea843SQuinn Tran 		if (le32_to_cpu(logio->io_parameter[5]) & LIO_COMM_FEAT_FCSP)
25569efea843SQuinn Tran 			fcport->flags |= FCF_FCSP_DEVICE;
25579efea843SQuinn Tran 
2558ac280b67SAndrew Vasquez 		iop[0] = le32_to_cpu(logio->io_parameter[0]);
2559ac280b67SAndrew Vasquez 		if (iop[0] & BIT_4) {
2560ac280b67SAndrew Vasquez 			fcport->port_type = FCT_TARGET;
2561ac280b67SAndrew Vasquez 			if (iop[0] & BIT_8)
25628474f3a0SSantosh Vernekar 				fcport->flags |= FCF_FCP2_DEVICE;
2563b0cd579cSAndrew Vasquez 		} else if (iop[0] & BIT_5)
2564ac280b67SAndrew Vasquez 			fcport->port_type = FCT_INITIATOR;
2565b0cd579cSAndrew Vasquez 
25662d70c103SNicholas Bellinger 		if (iop[0] & BIT_7)
25672d70c103SNicholas Bellinger 			fcport->flags |= FCF_CONF_COMP_SUPPORTED;
25682d70c103SNicholas Bellinger 
2569ac280b67SAndrew Vasquez 		if (logio->io_parameter[7] || logio->io_parameter[8])
2570ac280b67SAndrew Vasquez 			fcport->supported_classes |= FC_COS_CLASS2;
2571ac280b67SAndrew Vasquez 		if (logio->io_parameter[9] || logio->io_parameter[10])
2572ac280b67SAndrew Vasquez 			fcport->supported_classes |= FC_COS_CLASS3;
2573ac280b67SAndrew Vasquez 
257499b0bec7SAndrew Vasquez 		goto logio_done;
2575ac280b67SAndrew Vasquez 	}
2576ac280b67SAndrew Vasquez 
2577ac280b67SAndrew Vasquez 	iop[0] = le32_to_cpu(logio->io_parameter[0]);
2578ac280b67SAndrew Vasquez 	iop[1] = le32_to_cpu(logio->io_parameter[1]);
2579726b8548SQuinn Tran 	lio->u.logio.iop[0] = iop[0];
2580726b8548SQuinn Tran 	lio->u.logio.iop[1] = iop[1];
2581ac280b67SAndrew Vasquez 	switch (iop[0]) {
2582ac280b67SAndrew Vasquez 	case LSC_SCODE_PORTID_USED:
2583ac280b67SAndrew Vasquez 		data[0] = MBS_PORT_ID_USED;
2584ac280b67SAndrew Vasquez 		data[1] = LSW(iop[1]);
2585a5741427SArun Easi 		logit = 0;
2586ac280b67SAndrew Vasquez 		break;
2587ac280b67SAndrew Vasquez 	case LSC_SCODE_NPORT_USED:
2588ac280b67SAndrew Vasquez 		data[0] = MBS_LOOP_ID_USED;
2589a5741427SArun Easi 		logit = 0;
2590ac280b67SAndrew Vasquez 		break;
25915b33469aSQuinn Tran 	case LSC_SCODE_CMD_FAILED:
25925b33469aSQuinn Tran 		if (iop[1] == 0x0606) {
25935b33469aSQuinn Tran 			/*
25945b33469aSQuinn Tran 			 * PLOGI/PRLI Completed. We must have Recv PLOGI/PRLI,
25955b33469aSQuinn Tran 			 * Target side acked.
25965b33469aSQuinn Tran 			 */
25975b33469aSQuinn Tran 			data[0] = MBS_COMMAND_COMPLETE;
25985b33469aSQuinn Tran 			goto logio_done;
25995b33469aSQuinn Tran 		}
26005b33469aSQuinn Tran 		data[0] = MBS_COMMAND_ERROR;
26015b33469aSQuinn Tran 		break;
2602ead03855SQuinn Tran 	case LSC_SCODE_NOXCB:
2603ead03855SQuinn Tran 		vha->hw->exch_starvation++;
2604ead03855SQuinn Tran 		if (vha->hw->exch_starvation > 5) {
260583548fe2SQuinn Tran 			ql_log(ql_log_warn, vha, 0xd046,
2606ead03855SQuinn Tran 			    "Exchange starvation. Resetting RISC\n");
2607ead03855SQuinn Tran 
2608ead03855SQuinn Tran 			vha->hw->exch_starvation = 0;
2609ead03855SQuinn Tran 
2610ead03855SQuinn Tran 			if (IS_P3P_TYPE(vha->hw))
2611ead03855SQuinn Tran 				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
2612ead03855SQuinn Tran 			else
2613ead03855SQuinn Tran 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2614ead03855SQuinn Tran 			qla2xxx_wake_dpc(vha);
2615ead03855SQuinn Tran 		}
2616df561f66SGustavo A. R. Silva 		fallthrough;
2617ac280b67SAndrew Vasquez 	default:
2618ac280b67SAndrew Vasquez 		data[0] = MBS_COMMAND_ERROR;
2619ac280b67SAndrew Vasquez 		break;
2620ac280b67SAndrew Vasquez 	}
2621ac280b67SAndrew Vasquez 
2622a5741427SArun Easi 	if (logit)
2623a5741427SArun Easi 		ql_log(ql_log_warn, sp->vha, 0x5037, "Async-%s failed: "
2624a5741427SArun Easi 		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
2625a5741427SArun Easi 		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
2626a5741427SArun Easi 		       le16_to_cpu(logio->comp_status),
2627a5741427SArun Easi 		       le32_to_cpu(logio->io_parameter[0]),
2628a5741427SArun Easi 		       le32_to_cpu(logio->io_parameter[1]));
2629a5741427SArun Easi 	else
2630a5741427SArun Easi 		ql_dbg(ql_dbg_disc, sp->vha, 0x5037, "Async-%s failed: "
2631a5741427SArun Easi 		       "handle=%x pid=%06x wwpn=%8phC comp_status=%x iop0=%x iop1=%x\n",
2632cbe729a6SJoe Carnuccio 		       type, sp->handle, fcport->d_id.b24, fcport->port_name,
2633ac280b67SAndrew Vasquez 		       le16_to_cpu(logio->comp_status),
2634ac280b67SAndrew Vasquez 		       le32_to_cpu(logio->io_parameter[0]),
26357c3df132SSaurav Kashyap 		       le32_to_cpu(logio->io_parameter[1]));
2636ac280b67SAndrew Vasquez 
263799b0bec7SAndrew Vasquez logio_done:
263825ff6af1SJoe Carnuccio 	sp->done(sp, 0);
2639ac280b67SAndrew Vasquez }
2640ac280b67SAndrew Vasquez 
26413822263eSMadhuranath Iyengar static void
qla24xx_tm_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,void * tsk)2642faef62d1SArmen Baloyan qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
26433822263eSMadhuranath Iyengar {
26443822263eSMadhuranath Iyengar 	const char func[] = "TMF-IOCB";
26453822263eSMadhuranath Iyengar 	const char *type;
26463822263eSMadhuranath Iyengar 	fc_port_t *fcport;
26473822263eSMadhuranath Iyengar 	srb_t *sp;
26483822263eSMadhuranath Iyengar 	struct srb_iocb *iocb;
26493822263eSMadhuranath Iyengar 	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
2650e4fc78f4SQuinn Tran 	u16 comp_status;
26513822263eSMadhuranath Iyengar 
26523822263eSMadhuranath Iyengar 	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
26533822263eSMadhuranath Iyengar 	if (!sp)
26543822263eSMadhuranath Iyengar 		return;
26553822263eSMadhuranath Iyengar 
2656e4fc78f4SQuinn Tran 	comp_status = le16_to_cpu(sts->comp_status);
26579ba56b95SGiridhar Malavali 	iocb = &sp->u.iocb_cmd;
26589ba56b95SGiridhar Malavali 	type = sp->name;
26593822263eSMadhuranath Iyengar 	fcport = sp->fcport;
2660faef62d1SArmen Baloyan 	iocb->u.tmf.data = QLA_SUCCESS;
26613822263eSMadhuranath Iyengar 
26623822263eSMadhuranath Iyengar 	if (sts->entry_status) {
26635e19ed90SArun Easi 		ql_log(ql_log_warn, fcport->vha, 0x5038,
2664cfb0919cSChad Dupuis 		    "Async-%s error - hdl=%x entry-status(%x).\n",
2665cfb0919cSChad Dupuis 		    type, sp->handle, sts->entry_status);
2666faef62d1SArmen Baloyan 		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
2667ad950360SBart Van Assche 	} else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
26685e19ed90SArun Easi 		ql_log(ql_log_warn, fcport->vha, 0x5039,
2669cfb0919cSChad Dupuis 		    "Async-%s error - hdl=%x completion status(%x).\n",
2670e4fc78f4SQuinn Tran 		    type, sp->handle, comp_status);
2671faef62d1SArmen Baloyan 		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
2672faef62d1SArmen Baloyan 	} else if ((le16_to_cpu(sts->scsi_status) &
26733822263eSMadhuranath Iyengar 	    SS_RESPONSE_INFO_LEN_VALID)) {
267458ca5999SQuinn Tran 		host_to_fcp_swap(sts->data, sizeof(sts->data));
2675faef62d1SArmen Baloyan 		if (le32_to_cpu(sts->rsp_data_len) < 4) {
26765e19ed90SArun Easi 			ql_log(ql_log_warn, fcport->vha, 0x503b,
2677cfb0919cSChad Dupuis 			    "Async-%s error - hdl=%x not enough response(%d).\n",
2678cfb0919cSChad Dupuis 			    type, sp->handle, sts->rsp_data_len);
26793822263eSMadhuranath Iyengar 		} else if (sts->data[3]) {
26805e19ed90SArun Easi 			ql_log(ql_log_warn, fcport->vha, 0x503c,
2681cfb0919cSChad Dupuis 			    "Async-%s error - hdl=%x response(%x).\n",
2682cfb0919cSChad Dupuis 			    type, sp->handle, sts->data[3]);
2683faef62d1SArmen Baloyan 			iocb->u.tmf.data = QLA_FUNCTION_FAILED;
2684faef62d1SArmen Baloyan 		}
26853822263eSMadhuranath Iyengar 	}
26863822263eSMadhuranath Iyengar 
2687e4fc78f4SQuinn Tran 	switch (comp_status) {
2688e4fc78f4SQuinn Tran 	case CS_PORT_LOGGED_OUT:
2689e4fc78f4SQuinn Tran 	case CS_PORT_CONFIG_CHG:
2690e4fc78f4SQuinn Tran 	case CS_PORT_BUSY:
2691e4fc78f4SQuinn Tran 	case CS_INCOMPLETE:
2692e4fc78f4SQuinn Tran 	case CS_PORT_UNAVAILABLE:
2693e4fc78f4SQuinn Tran 	case CS_RESET:
2694e4fc78f4SQuinn Tran 		if (atomic_read(&fcport->state) == FCS_ONLINE) {
2695e4fc78f4SQuinn Tran 			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
2696e4fc78f4SQuinn Tran 			       "-Port to be marked lost on fcport=%02x%02x%02x, current port state= %s comp_status %x.\n",
2697e4fc78f4SQuinn Tran 			       fcport->d_id.b.domain, fcport->d_id.b.area,
2698e4fc78f4SQuinn Tran 			       fcport->d_id.b.al_pa,
2699e4fc78f4SQuinn Tran 			       port_state_str[FCS_ONLINE],
2700e4fc78f4SQuinn Tran 			       comp_status);
2701e4fc78f4SQuinn Tran 
2702e4fc78f4SQuinn Tran 			qlt_schedule_sess_for_deletion(fcport);
2703e4fc78f4SQuinn Tran 		}
2704e4fc78f4SQuinn Tran 		break;
2705e4fc78f4SQuinn Tran 
2706e4fc78f4SQuinn Tran 	default:
2707e4fc78f4SQuinn Tran 		break;
2708e4fc78f4SQuinn Tran 	}
2709e4fc78f4SQuinn Tran 
2710faef62d1SArmen Baloyan 	if (iocb->u.tmf.data != QLA_SUCCESS)
2711f8f97b0cSJoe Carnuccio 		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, sp->vha, 0x5055,
2712f8f97b0cSJoe Carnuccio 		    sts, sizeof(*sts));
27133822263eSMadhuranath Iyengar 
271425ff6af1SJoe Carnuccio 	sp->done(sp, 0);
27153822263eSMadhuranath Iyengar }
27163822263eSMadhuranath Iyengar 
qla24xx_nvme_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,void * tsk,srb_t * sp)271760dd6e8eSDarren Trapp static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
271860dd6e8eSDarren Trapp     void *tsk, srb_t *sp)
27197401bc18SDuane Grigsby {
27207401bc18SDuane Grigsby 	fc_port_t *fcport;
27217401bc18SDuane Grigsby 	struct srb_iocb *iocb;
27227401bc18SDuane Grigsby 	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
27237401bc18SDuane Grigsby 	uint16_t        state_flags;
27247401bc18SDuane Grigsby 	struct nvmefc_fcp_req *fd;
27254072e1dcSDarren Trapp 	uint16_t        ret = QLA_SUCCESS;
27267ffa5b93SBart Van Assche 	__le16		comp_status = sts->comp_status;
27273d582b34SArun Easi 	int		logit = 0;
27287401bc18SDuane Grigsby 
27297401bc18SDuane Grigsby 	iocb = &sp->u.iocb_cmd;
27307401bc18SDuane Grigsby 	fcport = sp->fcport;
27314072e1dcSDarren Trapp 	iocb->u.nvme.comp_status = comp_status;
27327401bc18SDuane Grigsby 	state_flags  = le16_to_cpu(sts->state_flags);
27337401bc18SDuane Grigsby 	fd = iocb->u.nvme.desc;
27347401bc18SDuane Grigsby 
273560dd6e8eSDarren Trapp 	if (unlikely(iocb->u.nvme.aen_op))
2736deeae7a6SDuane Grigsby 		atomic_dec(&sp->vha->hw->nvme_active_aen_cnt);
2737d94d8158SQuinn Tran 	else
2738d94d8158SQuinn Tran 		sp->qpair->cmd_completion_cnt++;
27397401bc18SDuane Grigsby 
27403d582b34SArun Easi 	if (unlikely(comp_status != CS_COMPLETE))
27413d582b34SArun Easi 		logit = 1;
27423d582b34SArun Easi 
27433d582b34SArun Easi 	fd->transferred_length = fd->payload_length -
27443d582b34SArun Easi 	    le32_to_cpu(sts->residual_len);
27453d582b34SArun Easi 
27467401bc18SDuane Grigsby 	/*
27477401bc18SDuane Grigsby 	 * State flags: Bit 6 and 0.
27487401bc18SDuane Grigsby 	 * If 0 is set, we don't care about 6.
27497401bc18SDuane Grigsby 	 * both cases resp was dma'd to host buffer
27507401bc18SDuane Grigsby 	 * if both are 0, that is good path case.
27517401bc18SDuane Grigsby 	 * if six is set and 0 is clear, we need to
27527401bc18SDuane Grigsby 	 * copy resp data from status iocb to resp buffer.
27537401bc18SDuane Grigsby 	 */
27547401bc18SDuane Grigsby 	if (!(state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP))) {
27557401bc18SDuane Grigsby 		iocb->u.nvme.rsp_pyld_len = 0;
27563d582b34SArun Easi 	} else if ((state_flags & (SF_FCP_RSP_DMA | SF_NVME_ERSP)) ==
27573d582b34SArun Easi 			(SF_FCP_RSP_DMA | SF_NVME_ERSP)) {
27583d582b34SArun Easi 		/* Response already DMA'd to fd->rspaddr. */
27597ffa5b93SBart Van Assche 		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
27603d582b34SArun Easi 	} else if ((state_flags & SF_FCP_RSP_DMA)) {
27613d582b34SArun Easi 		/*
27623d582b34SArun Easi 		 * Non-zero value in first 12 bytes of NVMe_RSP IU, treat this
27633d582b34SArun Easi 		 * as an error.
27643d582b34SArun Easi 		 */
27653d582b34SArun Easi 		iocb->u.nvme.rsp_pyld_len = 0;
27663d582b34SArun Easi 		fd->transferred_length = 0;
27673d582b34SArun Easi 		ql_dbg(ql_dbg_io, fcport->vha, 0x307a,
27683d582b34SArun Easi 			"Unexpected values in NVMe_RSP IU.\n");
27693d582b34SArun Easi 		logit = 1;
27707401bc18SDuane Grigsby 	} else if (state_flags & SF_NVME_ERSP) {
27717401bc18SDuane Grigsby 		uint32_t *inbuf, *outbuf;
27727401bc18SDuane Grigsby 		uint16_t iter;
27737401bc18SDuane Grigsby 
27747401bc18SDuane Grigsby 		inbuf = (uint32_t *)&sts->nvme_ersp_data;
27757401bc18SDuane Grigsby 		outbuf = (uint32_t *)fd->rspaddr;
27767ffa5b93SBart Van Assche 		iocb->u.nvme.rsp_pyld_len = sts->nvme_rsp_pyld_len;
27777ffa5b93SBart Van Assche 		if (unlikely(le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >
277800fe717eSArun Easi 		    sizeof(struct nvme_fc_ersp_iu))) {
277900fe717eSArun Easi 			if (ql_mask_match(ql_dbg_io)) {
278000fe717eSArun Easi 				WARN_ONCE(1, "Unexpected response payload length %u.\n",
278100fe717eSArun Easi 				    iocb->u.nvme.rsp_pyld_len);
278200fe717eSArun Easi 				ql_log(ql_log_warn, fcport->vha, 0x5100,
278300fe717eSArun Easi 				    "Unexpected response payload length %u.\n",
278400fe717eSArun Easi 				    iocb->u.nvme.rsp_pyld_len);
278500fe717eSArun Easi 			}
278600fe717eSArun Easi 			iocb->u.nvme.rsp_pyld_len =
27877ffa5b93SBart Van Assche 				cpu_to_le16(sizeof(struct nvme_fc_ersp_iu));
278800fe717eSArun Easi 		}
27897ffa5b93SBart Van Assche 		iter = le16_to_cpu(iocb->u.nvme.rsp_pyld_len) >> 2;
27907401bc18SDuane Grigsby 		for (; iter; iter--)
27917401bc18SDuane Grigsby 			*outbuf++ = swab32(*inbuf++);
27927401bc18SDuane Grigsby 	}
27937401bc18SDuane Grigsby 
27943d582b34SArun Easi 	if (state_flags & SF_NVME_ERSP) {
27953d582b34SArun Easi 		struct nvme_fc_ersp_iu *rsp_iu = fd->rspaddr;
27963d582b34SArun Easi 		u32 tgt_xfer_len;
27977401bc18SDuane Grigsby 
27983d582b34SArun Easi 		tgt_xfer_len = be32_to_cpu(rsp_iu->xfrd_len);
27993d582b34SArun Easi 		if (fd->transferred_length != tgt_xfer_len) {
2800daaecb41SSaurav Kashyap 			ql_log(ql_log_warn, fcport->vha, 0x3079,
28013d582b34SArun Easi 			       "Dropped frame(s) detected (sent/rcvd=%u/%u).\n",
28023d582b34SArun Easi 			       tgt_xfer_len, fd->transferred_length);
28033d582b34SArun Easi 			logit = 1;
28047ffa5b93SBart Van Assche 		} else if (le16_to_cpu(comp_status) == CS_DATA_UNDERRUN) {
28053d582b34SArun Easi 			/*
28063d582b34SArun Easi 			 * Do not log if this is just an underflow and there
28073d582b34SArun Easi 			 * is no data loss.
28083d582b34SArun Easi 			 */
28093d582b34SArun Easi 			logit = 0;
28103d582b34SArun Easi 		}
28113d582b34SArun Easi 	}
28123d582b34SArun Easi 
28133d582b34SArun Easi 	if (unlikely(logit))
2814bff4873cSArun Easi 		ql_dbg(ql_dbg_io, fcport->vha, 0x5060,
28154072e1dcSDarren Trapp 		   "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x  ox_id=%x\n",
28164072e1dcSDarren Trapp 		   sp->name, sp->handle, comp_status,
28174072e1dcSDarren Trapp 		   fd->transferred_length, le32_to_cpu(sts->residual_len),
28184072e1dcSDarren Trapp 		   sts->ox_id);
28194072e1dcSDarren Trapp 
28204072e1dcSDarren Trapp 	/*
28214072e1dcSDarren Trapp 	 * If transport error then Failure (HBA rejects request)
28224072e1dcSDarren Trapp 	 * otherwise transport will handle.
28234072e1dcSDarren Trapp 	 */
28247ffa5b93SBart Van Assche 	switch (le16_to_cpu(comp_status)) {
282549b3d5f6Shimanshu.madhani@cavium.com 	case CS_COMPLETE:
282649b3d5f6Shimanshu.madhani@cavium.com 		break;
28274072e1dcSDarren Trapp 
282849b3d5f6Shimanshu.madhani@cavium.com 	case CS_RESET:
282949b3d5f6Shimanshu.madhani@cavium.com 	case CS_PORT_UNAVAILABLE:
283049b3d5f6Shimanshu.madhani@cavium.com 	case CS_PORT_LOGGED_OUT:
28314072e1dcSDarren Trapp 		fcport->nvme_flag |= NVME_FLAG_RESETTING;
28327a8ff7d9SQuinn Tran 		if (atomic_read(&fcport->state) == FCS_ONLINE) {
28337a8ff7d9SQuinn Tran 			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
28347a8ff7d9SQuinn Tran 			       "Port to be marked lost on fcport=%06x, current "
28357a8ff7d9SQuinn Tran 			       "port state= %s comp_status %x.\n",
28367a8ff7d9SQuinn Tran 			       fcport->d_id.b24, port_state_str[FCS_ONLINE],
28377a8ff7d9SQuinn Tran 			       comp_status);
28387a8ff7d9SQuinn Tran 
28397a8ff7d9SQuinn Tran 			qlt_schedule_sess_for_deletion(fcport);
28407a8ff7d9SQuinn Tran 		}
2841df561f66SGustavo A. R. Silva 		fallthrough;
28424072e1dcSDarren Trapp 	case CS_ABORTED:
284349b3d5f6Shimanshu.madhani@cavium.com 	case CS_PORT_BUSY:
28449dd9686bSDarren Trapp 		fd->transferred_length = 0;
28459dd9686bSDarren Trapp 		iocb->u.nvme.rsp_pyld_len = 0;
284649b3d5f6Shimanshu.madhani@cavium.com 		ret = QLA_ABORTED;
284749b3d5f6Shimanshu.madhani@cavium.com 		break;
28484072e1dcSDarren Trapp 	case CS_DATA_UNDERRUN:
28494072e1dcSDarren Trapp 		break;
285049b3d5f6Shimanshu.madhani@cavium.com 	default:
28517401bc18SDuane Grigsby 		ret = QLA_FUNCTION_FAILED;
285249b3d5f6Shimanshu.madhani@cavium.com 		break;
285349b3d5f6Shimanshu.madhani@cavium.com 	}
28547401bc18SDuane Grigsby 	sp->done(sp, ret);
28557401bc18SDuane Grigsby }
28567401bc18SDuane Grigsby 
qla_ctrlvp_completed(scsi_qla_host_t * vha,struct req_que * req,struct vp_ctrl_entry_24xx * vce)28572853192eSQuinn Tran static void qla_ctrlvp_completed(scsi_qla_host_t *vha, struct req_que *req,
28582853192eSQuinn Tran     struct vp_ctrl_entry_24xx *vce)
28592853192eSQuinn Tran {
28602853192eSQuinn Tran 	const char func[] = "CTRLVP-IOCB";
28612853192eSQuinn Tran 	srb_t *sp;
28622853192eSQuinn Tran 	int rval = QLA_SUCCESS;
28632853192eSQuinn Tran 
28642853192eSQuinn Tran 	sp = qla2x00_get_sp_from_handle(vha, func, req, vce);
28652853192eSQuinn Tran 	if (!sp)
28662853192eSQuinn Tran 		return;
28672853192eSQuinn Tran 
28682853192eSQuinn Tran 	if (vce->entry_status != 0) {
28692853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0x10c4,
28702853192eSQuinn Tran 		    "%s: Failed to complete IOCB -- error status (%x)\n",
28712853192eSQuinn Tran 		    sp->name, vce->entry_status);
28722853192eSQuinn Tran 		rval = QLA_FUNCTION_FAILED;
28732853192eSQuinn Tran 	} else if (vce->comp_status != cpu_to_le16(CS_COMPLETE)) {
28742853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0x10c5,
28752853192eSQuinn Tran 		    "%s: Failed to complete IOCB -- completion status (%x) vpidx %x\n",
28762853192eSQuinn Tran 		    sp->name, le16_to_cpu(vce->comp_status),
28772853192eSQuinn Tran 		    le16_to_cpu(vce->vp_idx_failed));
28782853192eSQuinn Tran 		rval = QLA_FUNCTION_FAILED;
28792853192eSQuinn Tran 	} else {
28802853192eSQuinn Tran 		ql_dbg(ql_dbg_vport, vha, 0x10c6,
28812853192eSQuinn Tran 		    "Done %s.\n", __func__);
28822853192eSQuinn Tran 	}
28832853192eSQuinn Tran 
28842853192eSQuinn Tran 	sp->rc = rval;
28852853192eSQuinn Tran 	sp->done(sp, rval);
28862853192eSQuinn Tran }
28872853192eSQuinn Tran 
28887b006b97SBart Van Assche /* Process a single response queue entry. */
qla2x00_process_response_entry(struct scsi_qla_host * vha,struct rsp_que * rsp,sts_entry_t * pkt)28897b006b97SBart Van Assche static void qla2x00_process_response_entry(struct scsi_qla_host *vha,
28907b006b97SBart Van Assche 					   struct rsp_que *rsp,
28917b006b97SBart Van Assche 					   sts_entry_t *pkt)
28927b006b97SBart Van Assche {
28937b006b97SBart Van Assche 	sts21_entry_t *sts21_entry;
28947b006b97SBart Van Assche 	sts22_entry_t *sts22_entry;
28957b006b97SBart Van Assche 	uint16_t handle_cnt;
28967b006b97SBart Van Assche 	uint16_t cnt;
28977b006b97SBart Van Assche 
28987b006b97SBart Van Assche 	switch (pkt->entry_type) {
28997b006b97SBart Van Assche 	case STATUS_TYPE:
29007b006b97SBart Van Assche 		qla2x00_status_entry(vha, rsp, pkt);
29017b006b97SBart Van Assche 		break;
29027b006b97SBart Van Assche 	case STATUS_TYPE_21:
29037b006b97SBart Van Assche 		sts21_entry = (sts21_entry_t *)pkt;
29047b006b97SBart Van Assche 		handle_cnt = sts21_entry->handle_count;
29057b006b97SBart Van Assche 		for (cnt = 0; cnt < handle_cnt; cnt++)
29067b006b97SBart Van Assche 			qla2x00_process_completed_request(vha, rsp->req,
29077b006b97SBart Van Assche 						sts21_entry->handle[cnt]);
29087b006b97SBart Van Assche 		break;
29097b006b97SBart Van Assche 	case STATUS_TYPE_22:
29107b006b97SBart Van Assche 		sts22_entry = (sts22_entry_t *)pkt;
29117b006b97SBart Van Assche 		handle_cnt = sts22_entry->handle_count;
29127b006b97SBart Van Assche 		for (cnt = 0; cnt < handle_cnt; cnt++)
29137b006b97SBart Van Assche 			qla2x00_process_completed_request(vha, rsp->req,
29147b006b97SBart Van Assche 						sts22_entry->handle[cnt]);
29157b006b97SBart Van Assche 		break;
29167b006b97SBart Van Assche 	case STATUS_CONT_TYPE:
29177b006b97SBart Van Assche 		qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
29187b006b97SBart Van Assche 		break;
29197b006b97SBart Van Assche 	case MBX_IOCB_TYPE:
29207b006b97SBart Van Assche 		qla2x00_mbx_iocb_entry(vha, rsp->req, (struct mbx_entry *)pkt);
29217b006b97SBart Van Assche 		break;
29227b006b97SBart Van Assche 	case CT_IOCB_TYPE:
29237b006b97SBart Van Assche 		qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
29247b006b97SBart Van Assche 		break;
29257b006b97SBart Van Assche 	default:
29267b006b97SBart Van Assche 		/* Type Not Supported. */
29277b006b97SBart Van Assche 		ql_log(ql_log_warn, vha, 0x504a,
29287b006b97SBart Van Assche 		       "Received unknown response pkt type %x entry status=%x.\n",
29297b006b97SBart Van Assche 		       pkt->entry_type, pkt->entry_status);
29307b006b97SBart Van Assche 		break;
29317b006b97SBart Van Assche 	}
29327b006b97SBart Van Assche }
29337b006b97SBart Van Assche 
29341da177e4SLinus Torvalds /**
29351da177e4SLinus Torvalds  * qla2x00_process_response_queue() - Process response queue entries.
29362db6228dSBart Van Assche  * @rsp: response queue
29371da177e4SLinus Torvalds  */
29381da177e4SLinus Torvalds void
qla2x00_process_response_queue(struct rsp_que * rsp)293973208dfdSAnirban Chakraborty qla2x00_process_response_queue(struct rsp_que *rsp)
29401da177e4SLinus Torvalds {
294173208dfdSAnirban Chakraborty 	struct scsi_qla_host *vha;
294273208dfdSAnirban Chakraborty 	struct qla_hw_data *ha = rsp->hw;
29433d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
29441da177e4SLinus Torvalds 	sts_entry_t	*pkt;
294573208dfdSAnirban Chakraborty 
29462afa19a9SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
29471da177e4SLinus Torvalds 
2948e315cd28SAnirban Chakraborty 	if (!vha->flags.online)
29491da177e4SLinus Torvalds 		return;
29501da177e4SLinus Torvalds 
2951e315cd28SAnirban Chakraborty 	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
2952e315cd28SAnirban Chakraborty 		pkt = (sts_entry_t *)rsp->ring_ptr;
29531da177e4SLinus Torvalds 
2954e315cd28SAnirban Chakraborty 		rsp->ring_index++;
2955e315cd28SAnirban Chakraborty 		if (rsp->ring_index == rsp->length) {
2956e315cd28SAnirban Chakraborty 			rsp->ring_index = 0;
2957e315cd28SAnirban Chakraborty 			rsp->ring_ptr = rsp->ring;
29581da177e4SLinus Torvalds 		} else {
2959e315cd28SAnirban Chakraborty 			rsp->ring_ptr++;
29601da177e4SLinus Torvalds 		}
29611da177e4SLinus Torvalds 
29621da177e4SLinus Torvalds 		if (pkt->entry_status != 0) {
296373208dfdSAnirban Chakraborty 			qla2x00_error_entry(vha, rsp, pkt);
29641da177e4SLinus Torvalds 			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
29651da177e4SLinus Torvalds 			wmb();
29661da177e4SLinus Torvalds 			continue;
29671da177e4SLinus Torvalds 		}
29681da177e4SLinus Torvalds 
29697b006b97SBart Van Assche 		qla2x00_process_response_entry(vha, rsp, pkt);
29701da177e4SLinus Torvalds 		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
29711da177e4SLinus Torvalds 		wmb();
29721da177e4SLinus Torvalds 	}
29731da177e4SLinus Torvalds 
29741da177e4SLinus Torvalds 	/* Adjust ring index */
297504474d3aSBart Van Assche 	wrt_reg_word(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
29761da177e4SLinus Torvalds }
29771da177e4SLinus Torvalds 
29784733fcb1SAndrew Vasquez static inline void
qla2x00_handle_sense(srb_t * sp,uint8_t * sense_data,uint32_t par_sense_len,uint32_t sense_len,struct rsp_que * rsp,int res)29795544213bSAndrew Vasquez qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
29809ba56b95SGiridhar Malavali 		     uint32_t sense_len, struct rsp_que *rsp, int res)
29814733fcb1SAndrew Vasquez {
298225ff6af1SJoe Carnuccio 	struct scsi_qla_host *vha = sp->vha;
29839ba56b95SGiridhar Malavali 	struct scsi_cmnd *cp = GET_CMD_SP(sp);
29849ba56b95SGiridhar Malavali 	uint32_t track_sense_len;
29854733fcb1SAndrew Vasquez 
29864733fcb1SAndrew Vasquez 	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
29874733fcb1SAndrew Vasquez 		sense_len = SCSI_SENSE_BUFFERSIZE;
29884733fcb1SAndrew Vasquez 
29899ba56b95SGiridhar Malavali 	SET_CMD_SENSE_LEN(sp, sense_len);
29909ba56b95SGiridhar Malavali 	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
29919ba56b95SGiridhar Malavali 	track_sense_len = sense_len;
29929ba56b95SGiridhar Malavali 
29939ba56b95SGiridhar Malavali 	if (sense_len > par_sense_len)
29945544213bSAndrew Vasquez 		sense_len = par_sense_len;
29954733fcb1SAndrew Vasquez 
29964733fcb1SAndrew Vasquez 	memcpy(cp->sense_buffer, sense_data, sense_len);
29974733fcb1SAndrew Vasquez 
29989ba56b95SGiridhar Malavali 	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
29999ba56b95SGiridhar Malavali 	track_sense_len -= sense_len;
30009ba56b95SGiridhar Malavali 	SET_CMD_SENSE_LEN(sp, track_sense_len);
30019ba56b95SGiridhar Malavali 
30029ba56b95SGiridhar Malavali 	if (track_sense_len != 0) {
30032afa19a9SAnirban Chakraborty 		rsp->status_srb = sp;
30049ba56b95SGiridhar Malavali 		cp->result = res;
30059ba56b95SGiridhar Malavali 	}
30064733fcb1SAndrew Vasquez 
3007cfb0919cSChad Dupuis 	if (sense_len) {
3008cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
30099cb78c16SHannes Reinecke 		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
301025ff6af1SJoe Carnuccio 		    sp->vha->host_no, cp->device->id, cp->device->lun,
3011cfb0919cSChad Dupuis 		    cp);
30127c3df132SSaurav Kashyap 		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
30137c3df132SSaurav Kashyap 		    cp->sense_buffer, sense_len);
30144733fcb1SAndrew Vasquez 	}
3015cfb0919cSChad Dupuis }
30164733fcb1SAndrew Vasquez 
3017bad75002SArun Easi /*
3018bad75002SArun Easi  * Checks the guard or meta-data for the type of error
3019bad75002SArun Easi  * detected by the HBA. In case of errors, we set the
3020bad75002SArun Easi  * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
3021bad75002SArun Easi  * to indicate to the kernel that the HBA detected error.
3022bad75002SArun Easi  */
30238cb2049cSArun Easi static inline int
qla2x00_handle_dif_error(srb_t * sp,struct sts_entry_24xx * sts24)3024bad75002SArun Easi qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
3025bad75002SArun Easi {
302625ff6af1SJoe Carnuccio 	struct scsi_qla_host *vha = sp->vha;
30279ba56b95SGiridhar Malavali 	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
30288cb2049cSArun Easi 	uint8_t		*ap = &sts24->data[12];
30298cb2049cSArun Easi 	uint8_t		*ep = &sts24->data[20];
3030bad75002SArun Easi 	uint32_t	e_ref_tag, a_ref_tag;
3031bad75002SArun Easi 	uint16_t	e_app_tag, a_app_tag;
3032bad75002SArun Easi 	uint16_t	e_guard, a_guard;
3033bad75002SArun Easi 
30348cb2049cSArun Easi 	/*
30358cb2049cSArun Easi 	 * swab32 of the "data" field in the beginning of qla2x00_status_entry()
30368cb2049cSArun Easi 	 * would make guard field appear at offset 2
30378cb2049cSArun Easi 	 */
3038a9c4ae10SBart Van Assche 	a_guard   = get_unaligned_le16(ap + 2);
3039a9c4ae10SBart Van Assche 	a_app_tag = get_unaligned_le16(ap + 0);
3040a9c4ae10SBart Van Assche 	a_ref_tag = get_unaligned_le32(ap + 4);
3041a9c4ae10SBart Van Assche 	e_guard   = get_unaligned_le16(ep + 2);
3042a9c4ae10SBart Van Assche 	e_app_tag = get_unaligned_le16(ep + 0);
3043a9c4ae10SBart Van Assche 	e_ref_tag = get_unaligned_le32(ep + 4);
3044bad75002SArun Easi 
30457c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_io, vha, 0x3023,
30467c3df132SSaurav Kashyap 	    "iocb(s) %p Returned STATUS.\n", sts24);
3047bad75002SArun Easi 
30487c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_io, vha, 0x3024,
30497c3df132SSaurav Kashyap 	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
3050bad75002SArun Easi 	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
30517c3df132SSaurav Kashyap 	    " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
3052bad75002SArun Easi 	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
30537c3df132SSaurav Kashyap 	    a_app_tag, e_app_tag, a_guard, e_guard);
3054bad75002SArun Easi 
30558cb2049cSArun Easi 	/*
30568cb2049cSArun Easi 	 * Ignore sector if:
30578cb2049cSArun Easi 	 * For type     3: ref & app tag is all 'f's
30588cb2049cSArun Easi 	 * For type 0,1,2: app tag is all 'f's
30598cb2049cSArun Easi 	 */
30607ffa5b93SBart Van Assche 	if (a_app_tag == be16_to_cpu(T10_PI_APP_ESCAPE) &&
30617ffa5b93SBart Van Assche 	    (scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3 ||
30627ffa5b93SBart Van Assche 	     a_ref_tag == be32_to_cpu(T10_PI_REF_ESCAPE))) {
30638cb2049cSArun Easi 		uint32_t blocks_done, resid;
30648cb2049cSArun Easi 		sector_t lba_s = scsi_get_lba(cmd);
30658cb2049cSArun Easi 
30668cb2049cSArun Easi 		/* 2TB boundary case covered automatically with this */
30678cb2049cSArun Easi 		blocks_done = e_ref_tag - (uint32_t)lba_s + 1;
30688cb2049cSArun Easi 
30698cb2049cSArun Easi 		resid = scsi_bufflen(cmd) - (blocks_done *
30708cb2049cSArun Easi 		    cmd->device->sector_size);
30718cb2049cSArun Easi 
30728cb2049cSArun Easi 		scsi_set_resid(cmd, resid);
30738cb2049cSArun Easi 		cmd->result = DID_OK << 16;
30748cb2049cSArun Easi 
30758cb2049cSArun Easi 		/* Update protection tag */
30768cb2049cSArun Easi 		if (scsi_prot_sg_count(cmd)) {
30778cb2049cSArun Easi 			uint32_t i, j = 0, k = 0, num_ent;
30788cb2049cSArun Easi 			struct scatterlist *sg;
307927c0e83bSChristoph Hellwig 			struct t10_pi_tuple *spt;
30808cb2049cSArun Easi 
30818cb2049cSArun Easi 			/* Patch the corresponding protection tags */
30828cb2049cSArun Easi 			scsi_for_each_prot_sg(cmd, sg,
30838cb2049cSArun Easi 			    scsi_prot_sg_count(cmd), i) {
30848cb2049cSArun Easi 				num_ent = sg_dma_len(sg) / 8;
30858cb2049cSArun Easi 				if (k + num_ent < blocks_done) {
30868cb2049cSArun Easi 					k += num_ent;
30878cb2049cSArun Easi 					continue;
30888cb2049cSArun Easi 				}
30898cb2049cSArun Easi 				j = blocks_done - k - 1;
30908cb2049cSArun Easi 				k = blocks_done;
30918cb2049cSArun Easi 				break;
30928cb2049cSArun Easi 			}
30938cb2049cSArun Easi 
30948cb2049cSArun Easi 			if (k != blocks_done) {
3095cfb0919cSChad Dupuis 				ql_log(ql_log_warn, vha, 0x302f,
30968ec9c7fbSRandy Dunlap 				    "unexpected tag values tag:lba=%x:%llx)\n",
30978ec9c7fbSRandy Dunlap 				    e_ref_tag, (unsigned long long)lba_s);
30988cb2049cSArun Easi 				return 1;
30998cb2049cSArun Easi 			}
31008cb2049cSArun Easi 
31018cb2049cSArun Easi 			spt = page_address(sg_page(sg)) + sg->offset;
31028cb2049cSArun Easi 			spt += j;
31038cb2049cSArun Easi 
3104128b6f9fSDmitry Monakhov 			spt->app_tag = T10_PI_APP_ESCAPE;
31058cb2049cSArun Easi 			if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
3106128b6f9fSDmitry Monakhov 				spt->ref_tag = T10_PI_REF_ESCAPE;
31078cb2049cSArun Easi 		}
31088cb2049cSArun Easi 
31098cb2049cSArun Easi 		return 0;
31108cb2049cSArun Easi 	}
31118cb2049cSArun Easi 
3112bad75002SArun Easi 	/* check guard */
3113bad75002SArun Easi 	if (e_guard != a_guard) {
3114f2b1e9c6SHannes Reinecke 		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x1);
3115bad75002SArun Easi 		set_host_byte(cmd, DID_ABORT);
31168cb2049cSArun Easi 		return 1;
3117bad75002SArun Easi 	}
3118bad75002SArun Easi 
3119e02587d7SArun Easi 	/* check ref tag */
3120e02587d7SArun Easi 	if (e_ref_tag != a_ref_tag) {
3121f2b1e9c6SHannes Reinecke 		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x3);
3122e02587d7SArun Easi 		set_host_byte(cmd, DID_ABORT);
3123e02587d7SArun Easi 		return 1;
3124e02587d7SArun Easi 	}
3125e02587d7SArun Easi 
3126bad75002SArun Easi 	/* check appl tag */
3127bad75002SArun Easi 	if (e_app_tag != a_app_tag) {
3128f2b1e9c6SHannes Reinecke 		scsi_build_sense(cmd, 1, ILLEGAL_REQUEST, 0x10, 0x2);
3129bad75002SArun Easi 		set_host_byte(cmd, DID_ABORT);
31308cb2049cSArun Easi 		return 1;
3131bad75002SArun Easi 	}
3132bad75002SArun Easi 
31338cb2049cSArun Easi 	return 1;
3134bad75002SArun Easi }
3135bad75002SArun Easi 
3136a9b6f722SSaurav Kashyap static void
qla25xx_process_bidir_status_iocb(scsi_qla_host_t * vha,void * pkt,struct req_que * req,uint32_t index)3137a9b6f722SSaurav Kashyap qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
3138a9b6f722SSaurav Kashyap 				  struct req_que *req, uint32_t index)
3139a9b6f722SSaurav Kashyap {
3140a9b6f722SSaurav Kashyap 	struct qla_hw_data *ha = vha->hw;
3141a9b6f722SSaurav Kashyap 	srb_t *sp;
3142a9b6f722SSaurav Kashyap 	uint16_t	comp_status;
3143a9b6f722SSaurav Kashyap 	uint16_t	scsi_status;
3144a9b6f722SSaurav Kashyap 	uint16_t thread_id;
3145a9b6f722SSaurav Kashyap 	uint32_t rval = EXT_STATUS_OK;
314675cc8cfcSJohannes Thumshirn 	struct bsg_job *bsg_job = NULL;
314701e0e15cSJohannes Thumshirn 	struct fc_bsg_request *bsg_request;
314801e0e15cSJohannes Thumshirn 	struct fc_bsg_reply *bsg_reply;
31491a20719eSBart Van Assche 	sts_entry_t *sts = pkt;
31501a20719eSBart Van Assche 	struct sts_entry_24xx *sts24 = pkt;
3151a9b6f722SSaurav Kashyap 
3152a9b6f722SSaurav Kashyap 	/* Validate handle. */
31538d93f550SChad Dupuis 	if (index >= req->num_outstanding_cmds) {
3154a9b6f722SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x70af,
3155a9b6f722SSaurav Kashyap 		    "Invalid SCSI completion handle 0x%x.\n", index);
3156a9b6f722SSaurav Kashyap 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3157a9b6f722SSaurav Kashyap 		return;
3158a9b6f722SSaurav Kashyap 	}
3159a9b6f722SSaurav Kashyap 
3160a9b6f722SSaurav Kashyap 	sp = req->outstanding_cmds[index];
316101e0e15cSJohannes Thumshirn 	if (!sp) {
3162a9b6f722SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x70b0,
3163a9b6f722SSaurav Kashyap 		    "Req:%d: Invalid ISP SCSI completion handle(0x%x)\n",
3164a9b6f722SSaurav Kashyap 		    req->id, index);
3165a9b6f722SSaurav Kashyap 
3166a9b6f722SSaurav Kashyap 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3167a9b6f722SSaurav Kashyap 		return;
3168a9b6f722SSaurav Kashyap 	}
3169a9b6f722SSaurav Kashyap 
317001e0e15cSJohannes Thumshirn 	/* Free outstanding command slot. */
317101e0e15cSJohannes Thumshirn 	req->outstanding_cmds[index] = NULL;
317201e0e15cSJohannes Thumshirn 	bsg_job = sp->u.bsg_job;
317301e0e15cSJohannes Thumshirn 	bsg_request = bsg_job->request;
317401e0e15cSJohannes Thumshirn 	bsg_reply = bsg_job->reply;
317501e0e15cSJohannes Thumshirn 
3176a9b6f722SSaurav Kashyap 	if (IS_FWI2_CAPABLE(ha)) {
3177a9b6f722SSaurav Kashyap 		comp_status = le16_to_cpu(sts24->comp_status);
3178a9b6f722SSaurav Kashyap 		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
3179a9b6f722SSaurav Kashyap 	} else {
3180a9b6f722SSaurav Kashyap 		comp_status = le16_to_cpu(sts->comp_status);
3181a9b6f722SSaurav Kashyap 		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
3182a9b6f722SSaurav Kashyap 	}
3183a9b6f722SSaurav Kashyap 
318401e0e15cSJohannes Thumshirn 	thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
3185a9b6f722SSaurav Kashyap 	switch (comp_status) {
3186a9b6f722SSaurav Kashyap 	case CS_COMPLETE:
3187a9b6f722SSaurav Kashyap 		if (scsi_status == 0) {
318801e0e15cSJohannes Thumshirn 			bsg_reply->reply_payload_rcv_len =
3189a9b6f722SSaurav Kashyap 					bsg_job->reply_payload.payload_len;
3190fabbb8dfSJoe Carnuccio 			vha->qla_stats.input_bytes +=
319101e0e15cSJohannes Thumshirn 				bsg_reply->reply_payload_rcv_len;
3192fabbb8dfSJoe Carnuccio 			vha->qla_stats.input_requests++;
3193a9b6f722SSaurav Kashyap 			rval = EXT_STATUS_OK;
3194a9b6f722SSaurav Kashyap 		}
3195a9b6f722SSaurav Kashyap 		goto done;
3196a9b6f722SSaurav Kashyap 
3197a9b6f722SSaurav Kashyap 	case CS_DATA_OVERRUN:
3198a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b1,
31995a68a1c2SMilan P Gandhi 		    "Command completed with data overrun thread_id=%d\n",
3200a9b6f722SSaurav Kashyap 		    thread_id);
3201a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_OVERRUN;
3202a9b6f722SSaurav Kashyap 		break;
3203a9b6f722SSaurav Kashyap 
3204a9b6f722SSaurav Kashyap 	case CS_DATA_UNDERRUN:
3205a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b2,
32065a68a1c2SMilan P Gandhi 		    "Command completed with data underrun thread_id=%d\n",
3207a9b6f722SSaurav Kashyap 		    thread_id);
3208a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_UNDERRUN;
3209a9b6f722SSaurav Kashyap 		break;
3210a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_OVERRUN:
3211a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b3,
3212a9b6f722SSaurav Kashyap 		    "Command completed with read data overrun thread_id=%d\n",
3213a9b6f722SSaurav Kashyap 		    thread_id);
3214a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_OVERRUN;
3215a9b6f722SSaurav Kashyap 		break;
3216a9b6f722SSaurav Kashyap 
3217a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_WR_OVERRUN:
3218a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b4,
3219a9b6f722SSaurav Kashyap 		    "Command completed with read and write data overrun "
3220a9b6f722SSaurav Kashyap 		    "thread_id=%d\n", thread_id);
3221a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_OVERRUN;
3222a9b6f722SSaurav Kashyap 		break;
3223a9b6f722SSaurav Kashyap 
3224a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN:
3225a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b5,
3226a9b6f722SSaurav Kashyap 		    "Command completed with read data over and write data "
3227a9b6f722SSaurav Kashyap 		    "underrun thread_id=%d\n", thread_id);
3228a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_OVERRUN;
3229a9b6f722SSaurav Kashyap 		break;
3230a9b6f722SSaurav Kashyap 
3231a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_UNDERRUN:
3232a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b6,
32335a68a1c2SMilan P Gandhi 		    "Command completed with read data underrun "
3234a9b6f722SSaurav Kashyap 		    "thread_id=%d\n", thread_id);
3235a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_UNDERRUN;
3236a9b6f722SSaurav Kashyap 		break;
3237a9b6f722SSaurav Kashyap 
3238a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN:
3239a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b7,
3240a9b6f722SSaurav Kashyap 		    "Command completed with read data under and write data "
3241a9b6f722SSaurav Kashyap 		    "overrun thread_id=%d\n", thread_id);
3242a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_UNDERRUN;
3243a9b6f722SSaurav Kashyap 		break;
3244a9b6f722SSaurav Kashyap 
3245a9b6f722SSaurav Kashyap 	case CS_BIDIR_RD_WR_UNDERRUN:
3246a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b8,
3247a9b6f722SSaurav Kashyap 		    "Command completed with read and write data underrun "
3248a9b6f722SSaurav Kashyap 		    "thread_id=%d\n", thread_id);
3249a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DATA_UNDERRUN;
3250a9b6f722SSaurav Kashyap 		break;
3251a9b6f722SSaurav Kashyap 
3252a9b6f722SSaurav Kashyap 	case CS_BIDIR_DMA:
3253a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70b9,
3254a9b6f722SSaurav Kashyap 		    "Command completed with data DMA error thread_id=%d\n",
3255a9b6f722SSaurav Kashyap 		    thread_id);
3256a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_DMA_ERR;
3257a9b6f722SSaurav Kashyap 		break;
3258a9b6f722SSaurav Kashyap 
3259a9b6f722SSaurav Kashyap 	case CS_TIMEOUT:
3260a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70ba,
3261a9b6f722SSaurav Kashyap 		    "Command completed with timeout thread_id=%d\n",
3262a9b6f722SSaurav Kashyap 		    thread_id);
3263a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_TIMEOUT;
3264a9b6f722SSaurav Kashyap 		break;
3265a9b6f722SSaurav Kashyap 	default:
3266a9b6f722SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x70bb,
3267a9b6f722SSaurav Kashyap 		    "Command completed with completion status=0x%x "
3268a9b6f722SSaurav Kashyap 		    "thread_id=%d\n", comp_status, thread_id);
3269a9b6f722SSaurav Kashyap 		rval = EXT_STATUS_ERR;
3270a9b6f722SSaurav Kashyap 		break;
3271a9b6f722SSaurav Kashyap 	}
327201e0e15cSJohannes Thumshirn 	bsg_reply->reply_payload_rcv_len = 0;
3273a9b6f722SSaurav Kashyap 
3274a9b6f722SSaurav Kashyap done:
3275a9b6f722SSaurav Kashyap 	/* Return the vendor specific reply to API */
327601e0e15cSJohannes Thumshirn 	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
3277a9b6f722SSaurav Kashyap 	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
3278a9b6f722SSaurav Kashyap 	/* Always return DID_OK, bsg will send the vendor specific response
3279a9b6f722SSaurav Kashyap 	 * in this case only */
3280f7d5182cSJohannes Thumshirn 	sp->done(sp, DID_OK << 16);
3281a9b6f722SSaurav Kashyap 
3282a9b6f722SSaurav Kashyap }
3283a9b6f722SSaurav Kashyap 
32841da177e4SLinus Torvalds /**
32851da177e4SLinus Torvalds  * qla2x00_status_entry() - Process a Status IOCB entry.
32862db6228dSBart Van Assche  * @vha: SCSI driver HA context
32872db6228dSBart Van Assche  * @rsp: response queue
32881da177e4SLinus Torvalds  * @pkt: Entry pointer
32891da177e4SLinus Torvalds  */
32901da177e4SLinus Torvalds static void
qla2x00_status_entry(scsi_qla_host_t * vha,struct rsp_que * rsp,void * pkt)329173208dfdSAnirban Chakraborty qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
32921da177e4SLinus Torvalds {
32931da177e4SLinus Torvalds 	srb_t		*sp;
32941da177e4SLinus Torvalds 	fc_port_t	*fcport;
32951da177e4SLinus Torvalds 	struct scsi_cmnd *cp;
32961a20719eSBart Van Assche 	sts_entry_t *sts = pkt;
32971a20719eSBart Van Assche 	struct sts_entry_24xx *sts24 = pkt;
32981da177e4SLinus Torvalds 	uint16_t	comp_status;
32991da177e4SLinus Torvalds 	uint16_t	scsi_status;
3300b7d2280cSAndrew Vasquez 	uint16_t	ox_id;
33011da177e4SLinus Torvalds 	uint8_t		lscsi_status;
33021da177e4SLinus Torvalds 	int32_t		resid;
33035544213bSAndrew Vasquez 	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
33045544213bSAndrew Vasquez 	    fw_resid_len;
33059a853f71SAndrew Vasquez 	uint8_t		*rsp_info, *sense_data;
3306e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
33072afa19a9SAnirban Chakraborty 	uint32_t handle;
33082afa19a9SAnirban Chakraborty 	uint16_t que;
33092afa19a9SAnirban Chakraborty 	struct req_que *req;
3310b7d2280cSAndrew Vasquez 	int logit = 1;
33119ba56b95SGiridhar Malavali 	int res = 0;
3312a9b6f722SSaurav Kashyap 	uint16_t state_flags = 0;
33133aac0c0fSArun Easi 	uint16_t sts_qual = 0;
33149a853f71SAndrew Vasquez 
3315e428924cSAndrew Vasquez 	if (IS_FWI2_CAPABLE(ha)) {
33169a853f71SAndrew Vasquez 		comp_status = le16_to_cpu(sts24->comp_status);
33179a853f71SAndrew Vasquez 		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
3318a9b6f722SSaurav Kashyap 		state_flags = le16_to_cpu(sts24->state_flags);
33199a853f71SAndrew Vasquez 	} else {
33209a853f71SAndrew Vasquez 		comp_status = le16_to_cpu(sts->comp_status);
33219a853f71SAndrew Vasquez 		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
33229a853f71SAndrew Vasquez 	}
33232afa19a9SAnirban Chakraborty 	handle = (uint32_t) LSW(sts->handle);
33242afa19a9SAnirban Chakraborty 	que = MSW(sts->handle);
33252afa19a9SAnirban Chakraborty 	req = ha->req_q_map[que];
3326a9083016SGiridhar Malavali 
332736008cf1SChad Dupuis 	/* Check for invalid queue pointer */
332836008cf1SChad Dupuis 	if (req == NULL ||
332936008cf1SChad Dupuis 	    que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
333036008cf1SChad Dupuis 		ql_dbg(ql_dbg_io, vha, 0x3059,
333136008cf1SChad Dupuis 		    "Invalid status handle (0x%x): Bad req pointer. req=%p, "
333236008cf1SChad Dupuis 		    "que=%u.\n", sts->handle, req, que);
333336008cf1SChad Dupuis 		return;
333436008cf1SChad Dupuis 	}
333536008cf1SChad Dupuis 
33361da177e4SLinus Torvalds 	/* Validate handle. */
3337c7bc4caeSChad Dupuis 	if (handle < req->num_outstanding_cmds) {
33382afa19a9SAnirban Chakraborty 		sp = req->outstanding_cmds[handle];
3339c7bc4caeSChad Dupuis 		if (!sp) {
3340c7bc4caeSChad Dupuis 			ql_dbg(ql_dbg_io, vha, 0x3075,
3341c7bc4caeSChad Dupuis 			    "%s(%ld): Already returned command for status handle (0x%x).\n",
3342c7bc4caeSChad Dupuis 			    __func__, vha->host_no, sts->handle);
3343c7bc4caeSChad Dupuis 			return;
3344c7bc4caeSChad Dupuis 		}
3345c7bc4caeSChad Dupuis 	} else {
3346cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_io, vha, 0x3017,
3347c7bc4caeSChad Dupuis 		    "Invalid status handle, out of range (0x%x).\n",
3348c7bc4caeSChad Dupuis 		    sts->handle);
33491da177e4SLinus Torvalds 
3350acd3ce88SChad Dupuis 		if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
33517ec0effdSAtul Deshmukh 			if (IS_P3P_TYPE(ha))
33528f7daeadSGiridhar Malavali 				set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
33538f7daeadSGiridhar Malavali 			else
3354e315cd28SAnirban Chakraborty 				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
3355e315cd28SAnirban Chakraborty 			qla2xxx_wake_dpc(vha);
3356acd3ce88SChad Dupuis 		}
33571da177e4SLinus Torvalds 		return;
33581da177e4SLinus Torvalds 	}
335941e5afe5SQuinn Tran 	qla_put_fw_resources(sp->qpair, &sp->iores);
3360a9b6f722SSaurav Kashyap 
3361c5419e26SQuinn Tran 	if (sp->cmd_type != TYPE_SRB) {
3362c5419e26SQuinn Tran 		req->outstanding_cmds[handle] = NULL;
3363c5419e26SQuinn Tran 		ql_dbg(ql_dbg_io, vha, 0x3015,
3364c5419e26SQuinn Tran 		    "Unknown sp->cmd_type %x %p).\n",
3365c5419e26SQuinn Tran 		    sp->cmd_type, sp);
3366c5419e26SQuinn Tran 		return;
3367c5419e26SQuinn Tran 	}
3368c5419e26SQuinn Tran 
33697401bc18SDuane Grigsby 	/* NVME completion. */
33707401bc18SDuane Grigsby 	if (sp->type == SRB_NVME_CMD) {
337160dd6e8eSDarren Trapp 		req->outstanding_cmds[handle] = NULL;
337260dd6e8eSDarren Trapp 		qla24xx_nvme_iocb_entry(vha, req, pkt, sp);
33737401bc18SDuane Grigsby 		return;
33747401bc18SDuane Grigsby 	}
33757401bc18SDuane Grigsby 
3376a9b6f722SSaurav Kashyap 	if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) {
3377a9b6f722SSaurav Kashyap 		qla25xx_process_bidir_status_iocb(vha, pkt, req, handle);
3378a9b6f722SSaurav Kashyap 		return;
3379a9b6f722SSaurav Kashyap 	}
3380a9b6f722SSaurav Kashyap 
3381faef62d1SArmen Baloyan 	/* Task Management completion. */
3382faef62d1SArmen Baloyan 	if (sp->type == SRB_TM_CMD) {
3383faef62d1SArmen Baloyan 		qla24xx_tm_iocb_entry(vha, req, pkt);
3384faef62d1SArmen Baloyan 		return;
3385faef62d1SArmen Baloyan 	}
3386faef62d1SArmen Baloyan 
3387a9b6f722SSaurav Kashyap 	/* Fast path completion. */
3388dd30706eSQuinn Tran 	qla_chk_edif_rx_sa_delete_pending(vha, sp, sts24);
338971bef502SQuinn Tran 	sp->qpair->cmd_completion_cnt++;
3390dd30706eSQuinn Tran 
3391a9b6f722SSaurav Kashyap 	if (comp_status == CS_COMPLETE && scsi_status == 0) {
3392a9b6f722SSaurav Kashyap 		qla2x00_process_completed_request(vha, req, handle);
3393a9b6f722SSaurav Kashyap 
3394a9b6f722SSaurav Kashyap 		return;
3395a9b6f722SSaurav Kashyap 	}
3396a9b6f722SSaurav Kashyap 
33979ba56b95SGiridhar Malavali 	cp = GET_CMD_SP(sp);
33981da177e4SLinus Torvalds 	if (cp == NULL) {
3399cfb0919cSChad Dupuis 		ql_dbg(ql_dbg_io, vha, 0x3018,
34007c3df132SSaurav Kashyap 		    "Command already returned (0x%x/%p).\n",
34017c3df132SSaurav Kashyap 		    sts->handle, sp);
34021da177e4SLinus Torvalds 
3403b843addeSQuinn Tran 		req->outstanding_cmds[handle] = NULL;
34041da177e4SLinus Torvalds 		return;
34051da177e4SLinus Torvalds 	}
34061da177e4SLinus Torvalds 
34071da177e4SLinus Torvalds 	lscsi_status = scsi_status & STATUS_MASK;
34081da177e4SLinus Torvalds 
3409bdf79621S 	fcport = sp->fcport;
34101da177e4SLinus Torvalds 
3411b7d2280cSAndrew Vasquez 	ox_id = 0;
34125544213bSAndrew Vasquez 	sense_len = par_sense_len = rsp_info_len = resid_len =
34135544213bSAndrew Vasquez 	    fw_resid_len = 0;
3414e428924cSAndrew Vasquez 	if (IS_FWI2_CAPABLE(ha)) {
34150f00a206SLalit Chandivade 		if (scsi_status & SS_SENSE_LEN_VALID)
34169a853f71SAndrew Vasquez 			sense_len = le32_to_cpu(sts24->sense_len);
34170f00a206SLalit Chandivade 		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
34189a853f71SAndrew Vasquez 			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
34190f00a206SLalit Chandivade 		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
34209a853f71SAndrew Vasquez 			resid_len = le32_to_cpu(sts24->rsp_residual_count);
34210f00a206SLalit Chandivade 		if (comp_status == CS_DATA_UNDERRUN)
3422ed17c71bSRavi Anand 			fw_resid_len = le32_to_cpu(sts24->residual_len);
34239a853f71SAndrew Vasquez 		rsp_info = sts24->data;
34249a853f71SAndrew Vasquez 		sense_data = sts24->data;
34259a853f71SAndrew Vasquez 		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
3426b7d2280cSAndrew Vasquez 		ox_id = le16_to_cpu(sts24->ox_id);
34275544213bSAndrew Vasquez 		par_sense_len = sizeof(sts24->data);
34283aac0c0fSArun Easi 		sts_qual = le16_to_cpu(sts24->status_qualifier);
34299a853f71SAndrew Vasquez 	} else {
34300f00a206SLalit Chandivade 		if (scsi_status & SS_SENSE_LEN_VALID)
34319a853f71SAndrew Vasquez 			sense_len = le16_to_cpu(sts->req_sense_length);
34320f00a206SLalit Chandivade 		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
34339a853f71SAndrew Vasquez 			rsp_info_len = le16_to_cpu(sts->rsp_info_len);
34349a853f71SAndrew Vasquez 		resid_len = le32_to_cpu(sts->residual_length);
34359a853f71SAndrew Vasquez 		rsp_info = sts->rsp_info;
34369a853f71SAndrew Vasquez 		sense_data = sts->req_sense_data;
34375544213bSAndrew Vasquez 		par_sense_len = sizeof(sts->req_sense_data);
34389a853f71SAndrew Vasquez 	}
34399a853f71SAndrew Vasquez 
34401da177e4SLinus Torvalds 	/* Check for any FCP transport errors. */
34411da177e4SLinus Torvalds 	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
34429a853f71SAndrew Vasquez 		/* Sense data lies beyond any FCP RESPONSE data. */
34435544213bSAndrew Vasquez 		if (IS_FWI2_CAPABLE(ha)) {
34449a853f71SAndrew Vasquez 			sense_data += rsp_info_len;
34455544213bSAndrew Vasquez 			par_sense_len -= rsp_info_len;
34465544213bSAndrew Vasquez 		}
34479a853f71SAndrew Vasquez 		if (rsp_info_len > 3 && rsp_info[3]) {
34485e19ed90SArun Easi 			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
34497c3df132SSaurav Kashyap 			    "FCP I/O protocol failure (0x%x/0x%x).\n",
34507c3df132SSaurav Kashyap 			    rsp_info_len, rsp_info[3]);
34511da177e4SLinus Torvalds 
34529ba56b95SGiridhar Malavali 			res = DID_BUS_BUSY << 16;
3453b7d2280cSAndrew Vasquez 			goto out;
34541da177e4SLinus Torvalds 		}
34551da177e4SLinus Torvalds 	}
34561da177e4SLinus Torvalds 
34573e8ce320SAndrew Vasquez 	/* Check for overrun. */
34583e8ce320SAndrew Vasquez 	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
34593e8ce320SAndrew Vasquez 	    scsi_status & SS_RESIDUAL_OVER)
34603e8ce320SAndrew Vasquez 		comp_status = CS_DATA_OVERRUN;
34613e8ce320SAndrew Vasquez 
34621da177e4SLinus Torvalds 	/*
3463e05fe292SChad Dupuis 	 * Check retry_delay_timer value if we receive a busy or
3464e05fe292SChad Dupuis 	 * queue full.
3465e05fe292SChad Dupuis 	 */
34663aac0c0fSArun Easi 	if (unlikely(lscsi_status == SAM_STAT_TASK_SET_FULL ||
34673aac0c0fSArun Easi 		     lscsi_status == SAM_STAT_BUSY))
34683aac0c0fSArun Easi 		qla2x00_set_retry_delay_timestamp(fcport, sts_qual);
3469e05fe292SChad Dupuis 
3470e05fe292SChad Dupuis 	/*
34711da177e4SLinus Torvalds 	 * Based on Host and scsi status generate status code for Linux
34721da177e4SLinus Torvalds 	 */
34731da177e4SLinus Torvalds 	switch (comp_status) {
34741da177e4SLinus Torvalds 	case CS_COMPLETE:
3475df7baa50SAndrew Vasquez 	case CS_QUEUE_FULL:
34761da177e4SLinus Torvalds 		if (scsi_status == 0) {
34779ba56b95SGiridhar Malavali 			res = DID_OK << 16;
34781da177e4SLinus Torvalds 			break;
34791da177e4SLinus Torvalds 		}
34801da177e4SLinus Torvalds 		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
34819a853f71SAndrew Vasquez 			resid = resid_len;
3482385d70b4SFUJITA Tomonori 			scsi_set_resid(cp, resid);
34830da69df1SAndrew Vasquez 
34840da69df1SAndrew Vasquez 			if (!lscsi_status &&
3485385d70b4SFUJITA Tomonori 			    ((unsigned)(scsi_bufflen(cp) - resid) <
34860da69df1SAndrew Vasquez 			     cp->underflow)) {
34875e19ed90SArun Easi 				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
348883548fe2SQuinn Tran 				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
34897c3df132SSaurav Kashyap 				    resid, scsi_bufflen(cp));
34900da69df1SAndrew Vasquez 
34919ba56b95SGiridhar Malavali 				res = DID_ERROR << 16;
34920da69df1SAndrew Vasquez 				break;
34930da69df1SAndrew Vasquez 			}
34941da177e4SLinus Torvalds 		}
34959ba56b95SGiridhar Malavali 		res = DID_OK << 16 | lscsi_status;
34961da177e4SLinus Torvalds 
3497df7baa50SAndrew Vasquez 		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
34985e19ed90SArun Easi 			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
34997c3df132SSaurav Kashyap 			    "QUEUE FULL detected.\n");
3500df7baa50SAndrew Vasquez 			break;
3501df7baa50SAndrew Vasquez 		}
3502b7d2280cSAndrew Vasquez 		logit = 0;
35031da177e4SLinus Torvalds 		if (lscsi_status != SS_CHECK_CONDITION)
35041da177e4SLinus Torvalds 			break;
35051da177e4SLinus Torvalds 
3506b80ca4f7SFUJITA Tomonori 		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
35071da177e4SLinus Torvalds 		if (!(scsi_status & SS_SENSE_LEN_VALID))
35081da177e4SLinus Torvalds 			break;
35091da177e4SLinus Torvalds 
35105544213bSAndrew Vasquez 		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
35119ba56b95SGiridhar Malavali 		    rsp, res);
35121da177e4SLinus Torvalds 		break;
35131da177e4SLinus Torvalds 
35141da177e4SLinus Torvalds 	case CS_DATA_UNDERRUN:
35150f00a206SLalit Chandivade 		/* Use F/W calculated residual length. */
35160f00a206SLalit Chandivade 		resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
35170f00a206SLalit Chandivade 		scsi_set_resid(cp, resid);
35180f00a206SLalit Chandivade 		if (scsi_status & SS_RESIDUAL_UNDER) {
35190f00a206SLalit Chandivade 			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
3520daaecb41SSaurav Kashyap 				ql_log(ql_log_warn, fcport->vha, 0x301d,
352183548fe2SQuinn Tran 				       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
35227c3df132SSaurav Kashyap 				       resid, scsi_bufflen(cp));
35230f00a206SLalit Chandivade 
35249ba56b95SGiridhar Malavali 				res = DID_ERROR << 16 | lscsi_status;
35254e85e3d9SArun Easi 				goto check_scsi_status;
35261da177e4SLinus Torvalds 			}
35271da177e4SLinus Torvalds 
35280f00a206SLalit Chandivade 			if (!lscsi_status &&
35290f00a206SLalit Chandivade 			    ((unsigned)(scsi_bufflen(cp) - resid) <
35300f00a206SLalit Chandivade 			    cp->underflow)) {
35315e19ed90SArun Easi 				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
353283548fe2SQuinn Tran 				    "Mid-layer underflow detected (0x%x of 0x%x bytes).\n",
35337c3df132SSaurav Kashyap 				    resid, scsi_bufflen(cp));
35340f00a206SLalit Chandivade 
35359ba56b95SGiridhar Malavali 				res = DID_ERROR << 16;
35360f00a206SLalit Chandivade 				break;
35370f00a206SLalit Chandivade 			}
35384aee5766SGiridhar Malavali 		} else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
35394aee5766SGiridhar Malavali 			    lscsi_status != SAM_STAT_BUSY) {
35404aee5766SGiridhar Malavali 			/*
35414aee5766SGiridhar Malavali 			 * scsi status of task set and busy are considered to be
35424aee5766SGiridhar Malavali 			 * task not completed.
35434aee5766SGiridhar Malavali 			 */
35444aee5766SGiridhar Malavali 
3545daaecb41SSaurav Kashyap 			ql_log(ql_log_warn, fcport->vha, 0x301f,
354683548fe2SQuinn Tran 			       "Dropped frame(s) detected (0x%x of 0x%x bytes).\n",
354783548fe2SQuinn Tran 			       resid, scsi_bufflen(cp));
35480f00a206SLalit Chandivade 
3549dbf1f53cSSaurav Kashyap 			vha->interface_err_cnt++;
3550dbf1f53cSSaurav Kashyap 
35519ba56b95SGiridhar Malavali 			res = DID_ERROR << 16 | lscsi_status;
35520374f55eSLalit Chandivade 			goto check_scsi_status;
35534aee5766SGiridhar Malavali 		} else {
35544aee5766SGiridhar Malavali 			ql_dbg(ql_dbg_io, fcport->vha, 0x3030,
35554aee5766SGiridhar Malavali 			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
35564aee5766SGiridhar Malavali 			    scsi_status, lscsi_status);
35570f00a206SLalit Chandivade 		}
35580f00a206SLalit Chandivade 
35599ba56b95SGiridhar Malavali 		res = DID_OK << 16 | lscsi_status;
3560b7d2280cSAndrew Vasquez 		logit = 0;
35610f00a206SLalit Chandivade 
35620374f55eSLalit Chandivade check_scsi_status:
35631da177e4SLinus Torvalds 		/*
35641da177e4SLinus Torvalds 		 * Check to see if SCSI Status is non zero. If so report SCSI
35651da177e4SLinus Torvalds 		 * Status.
35661da177e4SLinus Torvalds 		 */
35671da177e4SLinus Torvalds 		if (lscsi_status != 0) {
3568ffec28a3SAndrew Vasquez 			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
35695e19ed90SArun Easi 				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
35707c3df132SSaurav Kashyap 				    "QUEUE FULL detected.\n");
3571b7d2280cSAndrew Vasquez 				logit = 1;
3572ffec28a3SAndrew Vasquez 				break;
3573ffec28a3SAndrew Vasquez 			}
35741da177e4SLinus Torvalds 			if (lscsi_status != SS_CHECK_CONDITION)
35751da177e4SLinus Torvalds 				break;
35761da177e4SLinus Torvalds 
3577b80ca4f7SFUJITA Tomonori 			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
35781da177e4SLinus Torvalds 			if (!(scsi_status & SS_SENSE_LEN_VALID))
35791da177e4SLinus Torvalds 				break;
35801da177e4SLinus Torvalds 
35815544213bSAndrew Vasquez 			qla2x00_handle_sense(sp, sense_data, par_sense_len,
35829ba56b95SGiridhar Malavali 			    sense_len, rsp, res);
35831da177e4SLinus Torvalds 		}
35841da177e4SLinus Torvalds 		break;
35851da177e4SLinus Torvalds 
35861da177e4SLinus Torvalds 	case CS_PORT_LOGGED_OUT:
35871da177e4SLinus Torvalds 	case CS_PORT_CONFIG_CHG:
35881da177e4SLinus Torvalds 	case CS_PORT_BUSY:
35891da177e4SLinus Torvalds 	case CS_INCOMPLETE:
35901da177e4SLinus Torvalds 	case CS_PORT_UNAVAILABLE:
35911da177e4SLinus Torvalds 	case CS_TIMEOUT:
3592ff454b01SChad Dupuis 	case CS_RESET:
3593d7e2e4a6SQuinn Tran 	case CS_EDIF_INV_REQ:
3594ff454b01SChad Dupuis 
3595056a4483SMike Christie 		/*
3596056a4483SMike Christie 		 * We are going to have the fc class block the rport
3597056a4483SMike Christie 		 * while we try to recover so instruct the mid layer
3598056a4483SMike Christie 		 * to requeue until the class decides how to handle this.
3599056a4483SMike Christie 		 */
36009ba56b95SGiridhar Malavali 		res = DID_TRANSPORT_DISRUPTED << 16;
36011da177e4SLinus Torvalds 
3602b7d2280cSAndrew Vasquez 		if (comp_status == CS_TIMEOUT) {
3603b7d2280cSAndrew Vasquez 			if (IS_FWI2_CAPABLE(ha))
3604b7d2280cSAndrew Vasquez 				break;
3605b7d2280cSAndrew Vasquez 			else if ((le16_to_cpu(sts->status_flags) &
3606b7d2280cSAndrew Vasquez 			    SF_LOGOUT_SENT) == 0)
36079a853f71SAndrew Vasquez 				break;
36081da177e4SLinus Torvalds 		}
36099a853f71SAndrew Vasquez 
3610726b8548SQuinn Tran 		if (atomic_read(&fcport->state) == FCS_ONLINE) {
3611726b8548SQuinn Tran 			ql_dbg(ql_dbg_disc, fcport->vha, 0x3021,
36120e948975SChad Dupuis 				"Port to be marked lost on fcport=%02x%02x%02x, current "
3613726b8548SQuinn Tran 				"port state= %s comp_status %x.\n", fcport->d_id.b.domain,
36140e948975SChad Dupuis 				fcport->d_id.b.area, fcport->d_id.b.al_pa,
3615282d1056SBart Van Assche 				port_state_str[FCS_ONLINE],
3616726b8548SQuinn Tran 				comp_status);
3617b7d2280cSAndrew Vasquez 
3618d8630bb9SQuinn Tran 			qlt_schedule_sess_for_deletion(fcport);
3619726b8548SQuinn Tran 		}
3620726b8548SQuinn Tran 
36211da177e4SLinus Torvalds 		break;
36221da177e4SLinus Torvalds 
3623b7d2280cSAndrew Vasquez 	case CS_ABORTED:
36249ba56b95SGiridhar Malavali 		res = DID_RESET << 16;
3625b7d2280cSAndrew Vasquez 		break;
3626bad75002SArun Easi 
3627bad75002SArun Easi 	case CS_DIF_ERROR:
36288cb2049cSArun Easi 		logit = qla2x00_handle_dif_error(sp, sts24);
3629fb6e4668SArun Easi 		res = cp->result;
3630bad75002SArun Easi 		break;
36319e522cd8SArun Easi 
36329e522cd8SArun Easi 	case CS_TRANSPORT:
36339e522cd8SArun Easi 		res = DID_ERROR << 16;
3634dbf1f53cSSaurav Kashyap 		vha->hw_err_cnt++;
36359e522cd8SArun Easi 
36369e522cd8SArun Easi 		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
36379e522cd8SArun Easi 			break;
36389e522cd8SArun Easi 
36399e522cd8SArun Easi 		if (state_flags & BIT_4)
36409e522cd8SArun Easi 			scmd_printk(KERN_WARNING, cp,
36419e522cd8SArun Easi 			    "Unsupported device '%s' found.\n",
36429e522cd8SArun Easi 			    cp->device->vendor);
36439e522cd8SArun Easi 		break;
36449e522cd8SArun Easi 
364550b81275SGiridhar Malavali 	case CS_DMA:
364650b81275SGiridhar Malavali 		ql_log(ql_log_info, fcport->vha, 0x3022,
364750b81275SGiridhar Malavali 		    "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",
364850b81275SGiridhar Malavali 		    comp_status, scsi_status, res, vha->host_no,
364950b81275SGiridhar Malavali 		    cp->device->id, cp->device->lun, fcport->d_id.b24,
365050b81275SGiridhar Malavali 		    ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len,
365150b81275SGiridhar Malavali 		    resid_len, fw_resid_len, sp, cp);
365250b81275SGiridhar Malavali 		ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee,
365350b81275SGiridhar Malavali 		    pkt, sizeof(*sts24));
365450b81275SGiridhar Malavali 		res = DID_ERROR << 16;
3655dbf1f53cSSaurav Kashyap 		vha->hw_err_cnt++;
365650b81275SGiridhar Malavali 		break;
36571da177e4SLinus Torvalds 	default:
36589ba56b95SGiridhar Malavali 		res = DID_ERROR << 16;
36591da177e4SLinus Torvalds 		break;
36601da177e4SLinus Torvalds 	}
36611da177e4SLinus Torvalds 
3662b7d2280cSAndrew Vasquez out:
3663b7d2280cSAndrew Vasquez 	if (logit)
3664bff4873cSArun Easi 		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
3665daaecb41SSaurav Kashyap 		       "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",
36669ba56b95SGiridhar Malavali 		       comp_status, scsi_status, res, vha->host_no,
3667cfb0919cSChad Dupuis 		       cp->device->id, cp->device->lun, fcport->d_id.b.domain,
3668cfb0919cSChad Dupuis 		       fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
36697b833558SOleksandr Khoshaba 		       cp->cmnd, scsi_bufflen(cp), rsp_info_len,
3670c7bc4caeSChad Dupuis 		       resid_len, fw_resid_len, sp, cp);
3671b7d2280cSAndrew Vasquez 
36722afa19a9SAnirban Chakraborty 	if (rsp->status_srb == NULL)
367325ff6af1SJoe Carnuccio 		sp->done(sp, res);
3674b843addeSQuinn Tran 
3675b843addeSQuinn Tran 	/* for io's, clearing of outstanding_cmds[handle] means scsi_done was called */
3676b843addeSQuinn Tran 	req->outstanding_cmds[handle] = NULL;
36771da177e4SLinus Torvalds }
36781da177e4SLinus Torvalds 
36791da177e4SLinus Torvalds /**
36801da177e4SLinus Torvalds  * qla2x00_status_cont_entry() - Process a Status Continuations entry.
36812db6228dSBart Van Assche  * @rsp: response queue
36821da177e4SLinus Torvalds  * @pkt: Entry pointer
36831da177e4SLinus Torvalds  *
36841da177e4SLinus Torvalds  * Extended sense data.
36851da177e4SLinus Torvalds  */
36861da177e4SLinus Torvalds static void
qla2x00_status_cont_entry(struct rsp_que * rsp,sts_cont_entry_t * pkt)36872afa19a9SAnirban Chakraborty qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
36881da177e4SLinus Torvalds {
36891da177e4SLinus Torvalds 	uint8_t	sense_sz = 0;
36902afa19a9SAnirban Chakraborty 	struct qla_hw_data *ha = rsp->hw;
36917c3df132SSaurav Kashyap 	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
36922afa19a9SAnirban Chakraborty 	srb_t *sp = rsp->status_srb;
36931da177e4SLinus Torvalds 	struct scsi_cmnd *cp;
36949ba56b95SGiridhar Malavali 	uint32_t sense_len;
36959ba56b95SGiridhar Malavali 	uint8_t *sense_ptr;
36961da177e4SLinus Torvalds 
36979ba56b95SGiridhar Malavali 	if (!sp || !GET_CMD_SENSE_LEN(sp))
36989ba56b95SGiridhar Malavali 		return;
36999ba56b95SGiridhar Malavali 
37009ba56b95SGiridhar Malavali 	sense_len = GET_CMD_SENSE_LEN(sp);
37019ba56b95SGiridhar Malavali 	sense_ptr = GET_CMD_SENSE_PTR(sp);
37029ba56b95SGiridhar Malavali 
37039ba56b95SGiridhar Malavali 	cp = GET_CMD_SP(sp);
37041da177e4SLinus Torvalds 	if (cp == NULL) {
37057c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x3025,
37069ba56b95SGiridhar Malavali 		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
37071da177e4SLinus Torvalds 
37082afa19a9SAnirban Chakraborty 		rsp->status_srb = NULL;
37091da177e4SLinus Torvalds 		return;
37101da177e4SLinus Torvalds 	}
37111da177e4SLinus Torvalds 
37129ba56b95SGiridhar Malavali 	if (sense_len > sizeof(pkt->data))
37131da177e4SLinus Torvalds 		sense_sz = sizeof(pkt->data);
37149ba56b95SGiridhar Malavali 	else
37159ba56b95SGiridhar Malavali 		sense_sz = sense_len;
37161da177e4SLinus Torvalds 
37171da177e4SLinus Torvalds 	/* Move sense data. */
3718e428924cSAndrew Vasquez 	if (IS_FWI2_CAPABLE(ha))
37199a853f71SAndrew Vasquez 		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
37209ba56b95SGiridhar Malavali 	memcpy(sense_ptr, pkt->data, sense_sz);
37217c3df132SSaurav Kashyap 	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
37229ba56b95SGiridhar Malavali 		sense_ptr, sense_sz);
37231da177e4SLinus Torvalds 
37249ba56b95SGiridhar Malavali 	sense_len -= sense_sz;
37259ba56b95SGiridhar Malavali 	sense_ptr += sense_sz;
37269ba56b95SGiridhar Malavali 
37279ba56b95SGiridhar Malavali 	SET_CMD_SENSE_PTR(sp, sense_ptr);
37289ba56b95SGiridhar Malavali 	SET_CMD_SENSE_LEN(sp, sense_len);
37291da177e4SLinus Torvalds 
37301da177e4SLinus Torvalds 	/* Place command on done queue. */
37319ba56b95SGiridhar Malavali 	if (sense_len == 0) {
37322afa19a9SAnirban Chakraborty 		rsp->status_srb = NULL;
373325ff6af1SJoe Carnuccio 		sp->done(sp, cp->result);
37341da177e4SLinus Torvalds 	}
37351da177e4SLinus Torvalds }
3736c4631191SGiridhar Malavali 
37371da177e4SLinus Torvalds /**
37381da177e4SLinus Torvalds  * qla2x00_error_entry() - Process an error entry.
37392db6228dSBart Van Assche  * @vha: SCSI driver HA context
37402db6228dSBart Van Assche  * @rsp: response queue
37411da177e4SLinus Torvalds  * @pkt: Entry pointer
3742c5419e26SQuinn Tran  * return : 1=allow further error analysis. 0=no additional error analysis.
37431da177e4SLinus Torvalds  */
3744c5419e26SQuinn Tran static int
qla2x00_error_entry(scsi_qla_host_t * vha,struct rsp_que * rsp,sts_entry_t * pkt)374573208dfdSAnirban Chakraborty qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
37461da177e4SLinus Torvalds {
37471da177e4SLinus Torvalds 	srb_t *sp;
3748e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
3749c4631191SGiridhar Malavali 	const char func[] = "ERROR-IOCB";
37502afa19a9SAnirban Chakraborty 	uint16_t que = MSW(pkt->handle);
3751a6fe35c0SArun Easi 	struct req_que *req = NULL;
37529ba56b95SGiridhar Malavali 	int res = DID_ERROR << 16;
3753b843addeSQuinn Tran 	u16 index;
37547c3df132SSaurav Kashyap 
37557c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_async, vha, 0x502a,
375682de802aSQuinn Tran 	    "iocb type %xh with error status %xh, handle %xh, rspq id %d\n",
375782de802aSQuinn Tran 	    pkt->entry_type, pkt->entry_status, pkt->handle, rsp->id);
37589ba56b95SGiridhar Malavali 
3759a6fe35c0SArun Easi 	if (que >= ha->max_req_queues || !ha->req_q_map[que])
3760a6fe35c0SArun Easi 		goto fatal;
3761a6fe35c0SArun Easi 
3762a6fe35c0SArun Easi 	req = ha->req_q_map[que];
3763a6fe35c0SArun Easi 
37649ba56b95SGiridhar Malavali 	if (pkt->entry_status & RF_BUSY)
37659ba56b95SGiridhar Malavali 		res = DID_BUS_BUSY << 16;
37661da177e4SLinus Torvalds 
3767c5419e26SQuinn Tran 	if ((pkt->handle & ~QLA_TGT_HANDLE_MASK) == QLA_TGT_SKIP_HANDLE)
3768c5419e26SQuinn Tran 		return 0;
37694f060736SQuinn Tran 
3770c5419e26SQuinn Tran 	switch (pkt->entry_type) {
3771c5419e26SQuinn Tran 	case NOTIFY_ACK_TYPE:
3772c5419e26SQuinn Tran 	case STATUS_CONT_TYPE:
3773c5419e26SQuinn Tran 	case LOGINOUT_PORT_IOCB_TYPE:
3774c5419e26SQuinn Tran 	case CT_IOCB_TYPE:
3775c5419e26SQuinn Tran 	case ELS_IOCB_TYPE:
3776c5419e26SQuinn Tran 	case ABORT_IOCB_TYPE:
3777c5419e26SQuinn Tran 	case MBX_IOCB_TYPE:
3778527b8ae3SQuinn Tran 	default:
3779c4631191SGiridhar Malavali 		sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
3780a6fe35c0SArun Easi 		if (sp) {
378125ff6af1SJoe Carnuccio 			sp->done(sp, res);
3782c5419e26SQuinn Tran 			return 0;
3783c5419e26SQuinn Tran 		}
3784c5419e26SQuinn Tran 		break;
3785c5419e26SQuinn Tran 
3786dd30706eSQuinn Tran 	case SA_UPDATE_IOCB_TYPE:
3787c5419e26SQuinn Tran 	case ABTS_RESP_24XX:
3788c5419e26SQuinn Tran 	case CTIO_TYPE7:
3789c5419e26SQuinn Tran 	case CTIO_CRC2:
3790c5419e26SQuinn Tran 		return 1;
3791b843addeSQuinn Tran 	case STATUS_TYPE:
3792b843addeSQuinn Tran 		sp = qla_get_sp_from_handle(vha, func, req, pkt, &index);
3793b843addeSQuinn Tran 		if (sp) {
3794b843addeSQuinn Tran 			sp->done(sp, res);
3795b843addeSQuinn Tran 			req->outstanding_cmds[index] = NULL;
3796b843addeSQuinn Tran 			return 0;
3797b843addeSQuinn Tran 		}
3798b843addeSQuinn Tran 		break;
3799a6fe35c0SArun Easi 	}
3800a6fe35c0SArun Easi fatal:
38017c3df132SSaurav Kashyap 	ql_log(ql_log_warn, vha, 0x5030,
3802fd49a540SChad Dupuis 	    "Error entry - invalid handle/queue (%04x).\n", que);
3803c5419e26SQuinn Tran 	return 0;
38041da177e4SLinus Torvalds }
38051da177e4SLinus Torvalds 
38061da177e4SLinus Torvalds /**
38079a853f71SAndrew Vasquez  * qla24xx_mbx_completion() - Process mailbox command completions.
38082db6228dSBart Van Assche  * @vha: SCSI driver HA context
38099a853f71SAndrew Vasquez  * @mb0: Mailbox0 register
38109a853f71SAndrew Vasquez  */
38119a853f71SAndrew Vasquez static void
qla24xx_mbx_completion(scsi_qla_host_t * vha,uint16_t mb0)3812e315cd28SAnirban Chakraborty qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
38139a853f71SAndrew Vasquez {
38149a853f71SAndrew Vasquez 	uint16_t	cnt;
38154fa94f83SAndrew Vasquez 	uint32_t	mboxes;
381637139da1SBart Van Assche 	__le16 __iomem *wptr;
3817e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
38189a853f71SAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
38199a853f71SAndrew Vasquez 
38204fa94f83SAndrew Vasquez 	/* Read all mbox registers? */
3821c02189e1SBart Van Assche 	WARN_ON_ONCE(ha->mbx_count > 32);
3822c02189e1SBart Van Assche 	mboxes = (1ULL << ha->mbx_count) - 1;
38234fa94f83SAndrew Vasquez 	if (!ha->mcp)
3824a720101dSMasanari Iida 		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
38254fa94f83SAndrew Vasquez 	else
38264fa94f83SAndrew Vasquez 		mboxes = ha->mcp->in_mb;
38274fa94f83SAndrew Vasquez 
38289a853f71SAndrew Vasquez 	/* Load return mailbox registers. */
38299a853f71SAndrew Vasquez 	ha->flags.mbox_int = 1;
38309a853f71SAndrew Vasquez 	ha->mailbox_out[0] = mb0;
38314fa94f83SAndrew Vasquez 	mboxes >>= 1;
38327ffa5b93SBart Van Assche 	wptr = &reg->mailbox1;
38339a853f71SAndrew Vasquez 
38349a853f71SAndrew Vasquez 	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
38354fa94f83SAndrew Vasquez 		if (mboxes & BIT_0)
383604474d3aSBart Van Assche 			ha->mailbox_out[cnt] = rd_reg_word(wptr);
38374fa94f83SAndrew Vasquez 
38384fa94f83SAndrew Vasquez 		mboxes >>= 1;
38399a853f71SAndrew Vasquez 		wptr++;
38409a853f71SAndrew Vasquez 	}
38419a853f71SAndrew Vasquez }
38429a853f71SAndrew Vasquez 
38434440e46dSArmen Baloyan static void
qla24xx_abort_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,struct abort_entry_24xx * pkt)38444440e46dSArmen Baloyan qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
38454440e46dSArmen Baloyan 	struct abort_entry_24xx *pkt)
38464440e46dSArmen Baloyan {
38474440e46dSArmen Baloyan 	const char func[] = "ABT_IOCB";
38484440e46dSArmen Baloyan 	srb_t *sp;
3849a0465859SBikash Hazarika 	srb_t *orig_sp = NULL;
38504440e46dSArmen Baloyan 	struct srb_iocb *abt;
38514440e46dSArmen Baloyan 
38524440e46dSArmen Baloyan 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
38534440e46dSArmen Baloyan 	if (!sp)
38544440e46dSArmen Baloyan 		return;
38554440e46dSArmen Baloyan 
38564440e46dSArmen Baloyan 	abt = &sp->u.iocb_cmd;
385737ce4f35SBart Van Assche 	abt->u.abt.comp_status = pkt->comp_status;
3858a0465859SBikash Hazarika 	orig_sp = sp->cmd_sp;
3859a0465859SBikash Hazarika 	/* Need to pass original sp */
3860a0465859SBikash Hazarika 	if (orig_sp)
3861a0465859SBikash Hazarika 		qla_nvme_abort_process_comp_status(pkt, orig_sp);
3862a0465859SBikash Hazarika 
386325ff6af1SJoe Carnuccio 	sp->done(sp, 0);
38644440e46dSArmen Baloyan }
38654440e46dSArmen Baloyan 
qla24xx_nvme_ls4_iocb(struct scsi_qla_host * vha,struct pt_ls4_request * pkt,struct req_que * req)38660f7e51f6Shimanshu.madhani@cavium.com void qla24xx_nvme_ls4_iocb(struct scsi_qla_host *vha,
38670f7e51f6Shimanshu.madhani@cavium.com     struct pt_ls4_request *pkt, struct req_que *req)
3868e84067d7SDuane Grigsby {
3869e84067d7SDuane Grigsby 	srb_t *sp;
3870e84067d7SDuane Grigsby 	const char func[] = "LS4_IOCB";
3871e84067d7SDuane Grigsby 	uint16_t comp_status;
3872e84067d7SDuane Grigsby 
3873e84067d7SDuane Grigsby 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
3874e84067d7SDuane Grigsby 	if (!sp)
3875e84067d7SDuane Grigsby 		return;
3876e84067d7SDuane Grigsby 
3877e84067d7SDuane Grigsby 	comp_status = le16_to_cpu(pkt->status);
3878e84067d7SDuane Grigsby 	sp->done(sp, comp_status);
3879e84067d7SDuane Grigsby }
3880e84067d7SDuane Grigsby 
38819a853f71SAndrew Vasquez /**
3882fac28079SQuinn Tran  * qla_chk_cont_iocb_avail - check for all continuation iocbs are available
3883fac28079SQuinn Tran  *   before iocb processing can start.
3884fac28079SQuinn Tran  * @vha: host adapter pointer
3885fac28079SQuinn Tran  * @rsp: respond queue
3886fac28079SQuinn Tran  * @pkt: head iocb describing how many continuation iocb
3887fac28079SQuinn Tran  * Return: 0 all iocbs has arrived, xx- all iocbs have not arrived.
3888fac28079SQuinn Tran  */
qla_chk_cont_iocb_avail(struct scsi_qla_host * vha,struct rsp_que * rsp,response_t * pkt,u32 rsp_q_in)3889fac28079SQuinn Tran static int qla_chk_cont_iocb_avail(struct scsi_qla_host *vha,
3890c019cd65SQuinn Tran 	struct rsp_que *rsp, response_t *pkt, u32 rsp_q_in)
3891fac28079SQuinn Tran {
3892c019cd65SQuinn Tran 	int start_pkt_ring_index;
3893c019cd65SQuinn Tran 	u32 iocb_cnt = 0;
3894fac28079SQuinn Tran 	int rc = 0;
3895fac28079SQuinn Tran 
3896fac28079SQuinn Tran 	if (pkt->entry_count == 1)
3897fac28079SQuinn Tran 		return rc;
3898fac28079SQuinn Tran 
3899fac28079SQuinn Tran 	/* ring_index was pre-increment. set it back to current pkt */
3900fac28079SQuinn Tran 	if (rsp->ring_index == 0)
3901fac28079SQuinn Tran 		start_pkt_ring_index = rsp->length - 1;
3902fac28079SQuinn Tran 	else
3903fac28079SQuinn Tran 		start_pkt_ring_index = rsp->ring_index - 1;
3904fac28079SQuinn Tran 
3905c019cd65SQuinn Tran 	if (rsp_q_in < start_pkt_ring_index)
3906c019cd65SQuinn Tran 		/* q in ptr is wrapped */
3907c019cd65SQuinn Tran 		iocb_cnt = rsp->length - start_pkt_ring_index + rsp_q_in;
3908fac28079SQuinn Tran 	else
3909c019cd65SQuinn Tran 		iocb_cnt = rsp_q_in - start_pkt_ring_index;
3910fac28079SQuinn Tran 
3911c019cd65SQuinn Tran 	if (iocb_cnt < pkt->entry_count)
3912fac28079SQuinn Tran 		rc = -EIO;
3913fac28079SQuinn Tran 
3914c019cd65SQuinn Tran 	ql_dbg(ql_dbg_init, vha, 0x5091,
3915c019cd65SQuinn Tran 	       "%s - ring %p pkt %p entry count %d iocb_cnt %d rsp_q_in %d rc %d\n",
3916c019cd65SQuinn Tran 	       __func__, rsp->ring, pkt, pkt->entry_count, iocb_cnt, rsp_q_in, rc);
3917fac28079SQuinn Tran 
3918fac28079SQuinn Tran 	return rc;
3919fac28079SQuinn Tran }
3920fac28079SQuinn Tran 
qla_marker_iocb_entry(scsi_qla_host_t * vha,struct req_que * req,struct mrk_entry_24xx * pkt)39219803fb5dSQuinn Tran static void qla_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
39229803fb5dSQuinn Tran 	struct mrk_entry_24xx *pkt)
39239803fb5dSQuinn Tran {
39249803fb5dSQuinn Tran 	const char func[] = "MRK-IOCB";
39259803fb5dSQuinn Tran 	srb_t *sp;
39269803fb5dSQuinn Tran 	int res = QLA_SUCCESS;
39279803fb5dSQuinn Tran 
39289803fb5dSQuinn Tran 	if (!IS_FWI2_CAPABLE(vha->hw))
39299803fb5dSQuinn Tran 		return;
39309803fb5dSQuinn Tran 
39319803fb5dSQuinn Tran 	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
39329803fb5dSQuinn Tran 	if (!sp)
39339803fb5dSQuinn Tran 		return;
39349803fb5dSQuinn Tran 
39359803fb5dSQuinn Tran 	if (pkt->entry_status) {
39369803fb5dSQuinn Tran 		ql_dbg(ql_dbg_taskm, vha, 0x8025, "marker failure.\n");
39379803fb5dSQuinn Tran 		res = QLA_COMMAND_ERROR;
39389803fb5dSQuinn Tran 	}
39399803fb5dSQuinn Tran 	sp->u.iocb_cmd.u.tmf.data = res;
39409803fb5dSQuinn Tran 	sp->done(sp, res);
39419803fb5dSQuinn Tran }
39429803fb5dSQuinn Tran 
3943fac28079SQuinn Tran /**
39449a853f71SAndrew Vasquez  * qla24xx_process_response_queue() - Process response queue entries.
39452db6228dSBart Van Assche  * @vha: SCSI driver HA context
39462db6228dSBart Van Assche  * @rsp: response queue
39479a853f71SAndrew Vasquez  */
qla24xx_process_response_queue(struct scsi_qla_host * vha,struct rsp_que * rsp)39482afa19a9SAnirban Chakraborty void qla24xx_process_response_queue(struct scsi_qla_host *vha,
39492afa19a9SAnirban Chakraborty 	struct rsp_que *rsp)
39509a853f71SAndrew Vasquez {
39519a853f71SAndrew Vasquez 	struct sts_entry_24xx *pkt;
3952a9083016SGiridhar Malavali 	struct qla_hw_data *ha = vha->hw;
39539f2475feSShyam Sundar 	struct purex_entry_24xx *purex_entry;
395462e9dd17SShyam Sundar 	struct purex_item *pure_item;
3955875386b9SManish Rangankar 	struct pt_ls4_rx_unsol *p;
3956e4f8a29dSArun Easi 	u16 rsp_in = 0, cur_ring_index;
3957e4f8a29dSArun Easi 	int is_shadow_hba;
39589a853f71SAndrew Vasquez 
3959ec7193e2SQuinn Tran 	if (!ha->flags.fw_started)
39609a853f71SAndrew Vasquez 		return;
39619a853f71SAndrew Vasquez 
3962*59f10a05SNilesh Javali 	if (rsp->qpair->cpuid != raw_smp_processor_id() || !rsp->qpair->rcv_intr) {
396349db4d4eSQuinn Tran 		rsp->qpair->rcv_intr = 1;
3964d54820b2SGleb Chesnokov 
3965d54820b2SGleb Chesnokov 		if (!rsp->qpair->cpu_mapped)
3966d54820b2SGleb Chesnokov 			qla_cpu_update(rsp->qpair, raw_smp_processor_id());
396749db4d4eSQuinn Tran 	}
3968e326d22aSQuinn Tran 
3969e4f8a29dSArun Easi #define __update_rsp_in(_is_shadow_hba, _rsp, _rsp_in)			\
3970e4f8a29dSArun Easi 	do {								\
3971e4f8a29dSArun Easi 		_rsp_in = _is_shadow_hba ? *(_rsp)->in_ptr :		\
3972e4f8a29dSArun Easi 				rd_reg_dword_relaxed((_rsp)->rsp_q_in);	\
3973e4f8a29dSArun Easi 	} while (0)
3974e4f8a29dSArun Easi 
3975e4f8a29dSArun Easi 	is_shadow_hba = IS_SHADOW_REG_CAPABLE(ha);
3976e4f8a29dSArun Easi 
3977e4f8a29dSArun Easi 	__update_rsp_in(is_shadow_hba, rsp, rsp_in);
3978e4f8a29dSArun Easi 
3979e4f8a29dSArun Easi 	while (rsp->ring_index != rsp_in &&
3980e4f8a29dSArun Easi 		       rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
3981e315cd28SAnirban Chakraborty 		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
3982c019cd65SQuinn Tran 		cur_ring_index = rsp->ring_index;
39839a853f71SAndrew Vasquez 
3984e315cd28SAnirban Chakraborty 		rsp->ring_index++;
3985e315cd28SAnirban Chakraborty 		if (rsp->ring_index == rsp->length) {
3986e315cd28SAnirban Chakraborty 			rsp->ring_index = 0;
3987e315cd28SAnirban Chakraborty 			rsp->ring_ptr = rsp->ring;
39889a853f71SAndrew Vasquez 		} else {
3989e315cd28SAnirban Chakraborty 			rsp->ring_ptr++;
39909a853f71SAndrew Vasquez 		}
39919a853f71SAndrew Vasquez 
39929a853f71SAndrew Vasquez 		if (pkt->entry_status != 0) {
3993c5419e26SQuinn Tran 			if (qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt))
3994f83adb61SQuinn Tran 				goto process_err;
39952d70c103SNicholas Bellinger 
39969a853f71SAndrew Vasquez 			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
39979a853f71SAndrew Vasquez 			wmb();
39989a853f71SAndrew Vasquez 			continue;
39999a853f71SAndrew Vasquez 		}
4000f83adb61SQuinn Tran process_err:
40019a853f71SAndrew Vasquez 
40029a853f71SAndrew Vasquez 		switch (pkt->entry_type) {
40039a853f71SAndrew Vasquez 		case STATUS_TYPE:
400473208dfdSAnirban Chakraborty 			qla2x00_status_entry(vha, rsp, pkt);
40059a853f71SAndrew Vasquez 			break;
40069a853f71SAndrew Vasquez 		case STATUS_CONT_TYPE:
40072afa19a9SAnirban Chakraborty 			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
40089a853f71SAndrew Vasquez 			break;
40092c3dfe3fSSeokmann Ju 		case VP_RPT_ID_IOCB_TYPE:
4010e315cd28SAnirban Chakraborty 			qla24xx_report_id_acquisition(vha,
40112c3dfe3fSSeokmann Ju 			    (struct vp_rpt_id_entry_24xx *)pkt);
40122c3dfe3fSSeokmann Ju 			break;
4013ac280b67SAndrew Vasquez 		case LOGINOUT_PORT_IOCB_TYPE:
4014ac280b67SAndrew Vasquez 			qla24xx_logio_entry(vha, rsp->req,
4015ac280b67SAndrew Vasquez 			    (struct logio_entry_24xx *)pkt);
4016ac280b67SAndrew Vasquez 			break;
40179a069e19SGiridhar Malavali 		case CT_IOCB_TYPE:
40189a069e19SGiridhar Malavali 			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
40199a069e19SGiridhar Malavali 			break;
40209a069e19SGiridhar Malavali 		case ELS_IOCB_TYPE:
40219a069e19SGiridhar Malavali 			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
40229a069e19SGiridhar Malavali 			break;
40232d70c103SNicholas Bellinger 		case ABTS_RECV_24XX:
4024576bfde8SJoe Carnuccio 			if (qla_ini_mode_enabled(vha)) {
402562e9dd17SShyam Sundar 				pure_item = qla24xx_copy_std_pkt(vha, pkt);
402662e9dd17SShyam Sundar 				if (!pure_item)
402762e9dd17SShyam Sundar 					break;
402862e9dd17SShyam Sundar 				qla24xx_queue_purex_item(vha, pure_item,
4029576bfde8SJoe Carnuccio 							 qla24xx_process_abts);
4030576bfde8SJoe Carnuccio 				break;
4031576bfde8SJoe Carnuccio 			}
4032ecc89f25SJoe Carnuccio 			if (IS_QLA83XX(ha) || IS_QLA27XX(ha) ||
4033ecc89f25SJoe Carnuccio 			    IS_QLA28XX(ha)) {
40342d70c103SNicholas Bellinger 				/* ensure that the ATIO queue is empty */
403582de802aSQuinn Tran 				qlt_handle_abts_recv(vha, rsp,
403682de802aSQuinn Tran 				    (response_t *)pkt);
40372f424b9bSQuinn Tran 				break;
40382f424b9bSQuinn Tran 			} else {
40392f424b9bSQuinn Tran 				qlt_24xx_process_atio_queue(vha, 1);
40402f424b9bSQuinn Tran 			}
4041df561f66SGustavo A. R. Silva 			fallthrough;
40422d70c103SNicholas Bellinger 		case ABTS_RESP_24XX:
40432d70c103SNicholas Bellinger 		case CTIO_TYPE7:
4044f83adb61SQuinn Tran 		case CTIO_CRC2:
404582de802aSQuinn Tran 			qlt_response_pkt_all_vps(vha, rsp, (response_t *)pkt);
40462d70c103SNicholas Bellinger 			break;
4047e84067d7SDuane Grigsby 		case PT_LS4_REQUEST:
4048e84067d7SDuane Grigsby 			qla24xx_nvme_ls4_iocb(vha, (struct pt_ls4_request *)pkt,
4049e84067d7SDuane Grigsby 			    rsp->req);
4050e84067d7SDuane Grigsby 			break;
4051726b8548SQuinn Tran 		case NOTIFY_ACK_TYPE:
4052726b8548SQuinn Tran 			if (pkt->handle == QLA_TGT_SKIP_HANDLE)
405382de802aSQuinn Tran 				qlt_response_pkt_all_vps(vha, rsp,
405482de802aSQuinn Tran 				    (response_t *)pkt);
4055726b8548SQuinn Tran 			else
4056726b8548SQuinn Tran 				qla24xxx_nack_iocb_entry(vha, rsp->req,
4057726b8548SQuinn Tran 					(struct nack_to_isp *)pkt);
4058726b8548SQuinn Tran 			break;
405954883291SSaurav Kashyap 		case MARKER_TYPE:
40609803fb5dSQuinn Tran 			qla_marker_iocb_entry(vha, rsp->req, (struct mrk_entry_24xx *)pkt);
406154883291SSaurav Kashyap 			break;
40624440e46dSArmen Baloyan 		case ABORT_IOCB_TYPE:
40634440e46dSArmen Baloyan 			qla24xx_abort_iocb_entry(vha, rsp->req,
40644440e46dSArmen Baloyan 			    (struct abort_entry_24xx *)pkt);
40654440e46dSArmen Baloyan 			break;
4066726b8548SQuinn Tran 		case MBX_IOCB_TYPE:
4067657ed8a8SDaniel Wagner 			qla24xx_mbx_iocb_entry(vha, rsp->req,
4068657ed8a8SDaniel Wagner 			    (struct mbx_24xx_entry *)pkt);
4069726b8548SQuinn Tran 			break;
40702853192eSQuinn Tran 		case VP_CTRL_IOCB_TYPE:
40712853192eSQuinn Tran 			qla_ctrlvp_completed(vha, rsp->req,
40722853192eSQuinn Tran 			    (struct vp_ctrl_entry_24xx *)pkt);
40732853192eSQuinn Tran 			break;
4074d83a80eeSJoe Carnuccio 		case PUREX_IOCB_TYPE:
40759f2475feSShyam Sundar 			purex_entry = (void *)pkt;
40769f2475feSShyam Sundar 			switch (purex_entry->els_frame_payload[3]) {
40779f2475feSShyam Sundar 			case ELS_RDP:
407862e9dd17SShyam Sundar 				pure_item = qla24xx_copy_std_pkt(vha, pkt);
407962e9dd17SShyam Sundar 				if (!pure_item)
408062e9dd17SShyam Sundar 					break;
408162e9dd17SShyam Sundar 				qla24xx_queue_purex_item(vha, pure_item,
408262e9dd17SShyam Sundar 						 qla24xx_process_purex_rdp);
4083576bfde8SJoe Carnuccio 				break;
40849f2475feSShyam Sundar 			case ELS_FPIN:
40859f2475feSShyam Sundar 				if (!vha->hw->flags.scm_enabled) {
40869f2475feSShyam Sundar 					ql_log(ql_log_warn, vha, 0x5094,
40879f2475feSShyam Sundar 					       "SCM not active for this port\n");
40889f2475feSShyam Sundar 					break;
4089576bfde8SJoe Carnuccio 				}
40909f2475feSShyam Sundar 				pure_item = qla27xx_copy_fpin_pkt(vha,
40919f2475feSShyam Sundar 							  (void **)&pkt, &rsp);
4092e4f8a29dSArun Easi 				__update_rsp_in(is_shadow_hba, rsp, rsp_in);
40939f2475feSShyam Sundar 				if (!pure_item)
40949f2475feSShyam Sundar 					break;
40959f2475feSShyam Sundar 				qla24xx_queue_purex_item(vha, pure_item,
40969f2475feSShyam Sundar 						 qla27xx_process_purex_fpin);
40979f2475feSShyam Sundar 				break;
40989f2475feSShyam Sundar 
4099fac28079SQuinn Tran 			case ELS_AUTH_ELS:
4100c019cd65SQuinn Tran 				if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
4101c019cd65SQuinn Tran 					/*
4102c019cd65SQuinn Tran 					 * ring_ptr and ring_index were
4103c019cd65SQuinn Tran 					 * pre-incremented above. Reset them
4104c019cd65SQuinn Tran 					 * back to current. Wait for next
4105c019cd65SQuinn Tran 					 * interrupt with all IOCBs to arrive
4106c019cd65SQuinn Tran 					 * and re-process.
4107c019cd65SQuinn Tran 					 */
4108c019cd65SQuinn Tran 					rsp->ring_ptr = (response_t *)pkt;
4109c019cd65SQuinn Tran 					rsp->ring_index = cur_ring_index;
4110c019cd65SQuinn Tran 
4111fac28079SQuinn Tran 					ql_dbg(ql_dbg_init, vha, 0x5091,
4112fac28079SQuinn Tran 					    "Defer processing ELS opcode %#x...\n",
4113fac28079SQuinn Tran 					    purex_entry->els_frame_payload[3]);
4114fac28079SQuinn Tran 					return;
4115fac28079SQuinn Tran 				}
4116fac28079SQuinn Tran 				qla24xx_auth_els(vha, (void **)&pkt, &rsp);
4117fac28079SQuinn Tran 				break;
41189f2475feSShyam Sundar 			default:
41199f2475feSShyam Sundar 				ql_log(ql_log_warn, vha, 0x509c,
41209f2475feSShyam Sundar 				       "Discarding ELS Request opcode 0x%x\n",
41219f2475feSShyam Sundar 				       purex_entry->els_frame_payload[3]);
41229f2475feSShyam Sundar 			}
41239f2475feSShyam Sundar 			break;
4124dd30706eSQuinn Tran 		case SA_UPDATE_IOCB_TYPE:
4125dd30706eSQuinn Tran 			qla28xx_sa_update_iocb_entry(vha, rsp->req,
4126dd30706eSQuinn Tran 				(struct sa_update_28xx *)pkt);
4127dd30706eSQuinn Tran 			break;
4128875386b9SManish Rangankar 		case PT_LS4_UNSOL:
4129875386b9SManish Rangankar 			p = (void *)pkt;
4130875386b9SManish Rangankar 			if (qla_chk_cont_iocb_avail(vha, rsp, (response_t *)pkt, rsp_in)) {
4131875386b9SManish Rangankar 				rsp->ring_ptr = (response_t *)pkt;
4132875386b9SManish Rangankar 				rsp->ring_index = cur_ring_index;
4133dd30706eSQuinn Tran 
4134875386b9SManish Rangankar 				ql_dbg(ql_dbg_init, vha, 0x2124,
4135875386b9SManish Rangankar 				       "Defer processing UNSOL LS req opcode %#x...\n",
4136875386b9SManish Rangankar 				       p->payload[0]);
4137875386b9SManish Rangankar 				return;
4138875386b9SManish Rangankar 			}
4139875386b9SManish Rangankar 			qla2xxx_process_purls_iocb((void **)&pkt, &rsp);
4140875386b9SManish Rangankar 			break;
41419a853f71SAndrew Vasquez 		default:
41429a853f71SAndrew Vasquez 			/* Type Not Supported. */
41437c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5042,
41449f2475feSShyam Sundar 			       "Received unknown response pkt type 0x%x entry status=%x.\n",
41457c3df132SSaurav Kashyap 			       pkt->entry_type, pkt->entry_status);
41469a853f71SAndrew Vasquez 			break;
41479a853f71SAndrew Vasquez 		}
41489a853f71SAndrew Vasquez 		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
41499a853f71SAndrew Vasquez 		wmb();
41509a853f71SAndrew Vasquez 	}
41519a853f71SAndrew Vasquez 
41529a853f71SAndrew Vasquez 	/* Adjust ring index */
41537ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha)) {
4154a9083016SGiridhar Malavali 		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
4155bd432bb5SBart Van Assche 
415604474d3aSBart Van Assche 		wrt_reg_dword(&reg->rsp_q_out[0], rsp->ring_index);
4157726b8548SQuinn Tran 	} else {
415804474d3aSBart Van Assche 		wrt_reg_dword(rsp->rsp_q_out, rsp->ring_index);
41599a853f71SAndrew Vasquez 	}
4160726b8548SQuinn Tran }
41619a853f71SAndrew Vasquez 
416205236a05SAndrew Vasquez static void
qla2xxx_check_risc_status(scsi_qla_host_t * vha)4163e315cd28SAnirban Chakraborty qla2xxx_check_risc_status(scsi_qla_host_t *vha)
416405236a05SAndrew Vasquez {
416505236a05SAndrew Vasquez 	int rval;
416605236a05SAndrew Vasquez 	uint32_t cnt;
4167e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
416805236a05SAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
416905236a05SAndrew Vasquez 
4170f73cb695SChad Dupuis 	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
4171ecc89f25SJoe Carnuccio 	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
417205236a05SAndrew Vasquez 		return;
417305236a05SAndrew Vasquez 
417405236a05SAndrew Vasquez 	rval = QLA_SUCCESS;
417504474d3aSBart Van Assche 	wrt_reg_dword(&reg->iobase_addr, 0x7C00);
417604474d3aSBart Van Assche 	rd_reg_dword(&reg->iobase_addr);
417704474d3aSBart Van Assche 	wrt_reg_dword(&reg->iobase_window, 0x0001);
417804474d3aSBart Van Assche 	for (cnt = 10000; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
417905236a05SAndrew Vasquez 	    rval == QLA_SUCCESS; cnt--) {
418005236a05SAndrew Vasquez 		if (cnt) {
418104474d3aSBart Van Assche 			wrt_reg_dword(&reg->iobase_window, 0x0001);
418205236a05SAndrew Vasquez 			udelay(10);
418305236a05SAndrew Vasquez 		} else
418405236a05SAndrew Vasquez 			rval = QLA_FUNCTION_TIMEOUT;
418505236a05SAndrew Vasquez 	}
418605236a05SAndrew Vasquez 	if (rval == QLA_SUCCESS)
418705236a05SAndrew Vasquez 		goto next_test;
418805236a05SAndrew Vasquez 
4189b2ec76c5SBart Van Assche 	rval = QLA_SUCCESS;
419004474d3aSBart Van Assche 	wrt_reg_dword(&reg->iobase_window, 0x0003);
419104474d3aSBart Van Assche 	for (cnt = 100; (rd_reg_dword(&reg->iobase_window) & BIT_0) == 0 &&
419205236a05SAndrew Vasquez 	    rval == QLA_SUCCESS; cnt--) {
419305236a05SAndrew Vasquez 		if (cnt) {
419404474d3aSBart Van Assche 			wrt_reg_dword(&reg->iobase_window, 0x0003);
419505236a05SAndrew Vasquez 			udelay(10);
419605236a05SAndrew Vasquez 		} else
419705236a05SAndrew Vasquez 			rval = QLA_FUNCTION_TIMEOUT;
419805236a05SAndrew Vasquez 	}
419905236a05SAndrew Vasquez 	if (rval != QLA_SUCCESS)
420005236a05SAndrew Vasquez 		goto done;
420105236a05SAndrew Vasquez 
420205236a05SAndrew Vasquez next_test:
420304474d3aSBart Van Assche 	if (rd_reg_dword(&reg->iobase_c8) & BIT_3)
42047c3df132SSaurav Kashyap 		ql_log(ql_log_info, vha, 0x504c,
42057c3df132SSaurav Kashyap 		    "Additional code -- 0x55AA.\n");
420605236a05SAndrew Vasquez 
420705236a05SAndrew Vasquez done:
420804474d3aSBart Van Assche 	wrt_reg_dword(&reg->iobase_window, 0x0000);
420904474d3aSBart Van Assche 	rd_reg_dword(&reg->iobase_window);
421005236a05SAndrew Vasquez }
421105236a05SAndrew Vasquez 
42129a853f71SAndrew Vasquez /**
42136246b8a1SGiridhar Malavali  * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
4214807eb907SBart Van Assche  * @irq: interrupt number
42159a853f71SAndrew Vasquez  * @dev_id: SCSI driver HA context
42169a853f71SAndrew Vasquez  *
42179a853f71SAndrew Vasquez  * Called by system whenever the host adapter generates an interrupt.
42189a853f71SAndrew Vasquez  *
42199a853f71SAndrew Vasquez  * Returns handled flag.
42209a853f71SAndrew Vasquez  */
42219a853f71SAndrew Vasquez irqreturn_t
qla24xx_intr_handler(int irq,void * dev_id)42227d12e780SDavid Howells qla24xx_intr_handler(int irq, void *dev_id)
42239a853f71SAndrew Vasquez {
4224e315cd28SAnirban Chakraborty 	scsi_qla_host_t	*vha;
4225e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha;
42269a853f71SAndrew Vasquez 	struct device_reg_24xx __iomem *reg;
42279a853f71SAndrew Vasquez 	int		status;
42289a853f71SAndrew Vasquez 	unsigned long	iter;
42299a853f71SAndrew Vasquez 	uint32_t	stat;
42309a853f71SAndrew Vasquez 	uint32_t	hccr;
42317d613ac6SSantosh Vernekar 	uint16_t	mb[8];
4232e315cd28SAnirban Chakraborty 	struct rsp_que *rsp;
423343fac4d9SAnirban Chakraborty 	unsigned long	flags;
42341073daa4SQuinn Tran 	bool process_atio = false;
42359a853f71SAndrew Vasquez 
4236e315cd28SAnirban Chakraborty 	rsp = (struct rsp_que *) dev_id;
4237e315cd28SAnirban Chakraborty 	if (!rsp) {
42383256b435SChad Dupuis 		ql_log(ql_log_info, NULL, 0x5059,
42393256b435SChad Dupuis 		    "%s: NULL response queue pointer.\n", __func__);
42409a853f71SAndrew Vasquez 		return IRQ_NONE;
42419a853f71SAndrew Vasquez 	}
42429a853f71SAndrew Vasquez 
4243e315cd28SAnirban Chakraborty 	ha = rsp->hw;
42449a853f71SAndrew Vasquez 	reg = &ha->iobase->isp24;
42459a853f71SAndrew Vasquez 	status = 0;
42469a853f71SAndrew Vasquez 
424785880801SAndrew Vasquez 	if (unlikely(pci_channel_offline(ha->pdev)))
424885880801SAndrew Vasquez 		return IRQ_HANDLED;
424985880801SAndrew Vasquez 
425043fac4d9SAnirban Chakraborty 	spin_lock_irqsave(&ha->hardware_lock, flags);
42512afa19a9SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
42529a853f71SAndrew Vasquez 	for (iter = 50; iter--; ) {
425304474d3aSBart Van Assche 		stat = rd_reg_dword(&reg->host_status);
4254c821e0d5SJoe Lawrence 		if (qla2x00_check_reg32_for_disconnect(vha, stat))
4255f3ddac19SChad Dupuis 			break;
42569a853f71SAndrew Vasquez 		if (stat & HSRX_RISC_PAUSED) {
425785880801SAndrew Vasquez 			if (unlikely(pci_channel_offline(ha->pdev)))
425814e660e6SSeokmann Ju 				break;
425914e660e6SSeokmann Ju 
426004474d3aSBart Van Assche 			hccr = rd_reg_dword(&reg->hccr);
42619a853f71SAndrew Vasquez 
42627c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x504b,
42637c3df132SSaurav Kashyap 			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
42647c3df132SSaurav Kashyap 			    hccr);
426505236a05SAndrew Vasquez 
4266e315cd28SAnirban Chakraborty 			qla2xxx_check_risc_status(vha);
426705236a05SAndrew Vasquez 
42688ae17876SBart Van Assche 			ha->isp_ops->fw_dump(vha);
4269e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
42709a853f71SAndrew Vasquez 			break;
42719a853f71SAndrew Vasquez 		} else if ((stat & HSRX_RISC_INT) == 0)
42729a853f71SAndrew Vasquez 			break;
42739a853f71SAndrew Vasquez 
42749a853f71SAndrew Vasquez 		switch (stat & 0xff) {
4275fafbda9fSArun Easi 		case INTR_ROM_MB_SUCCESS:
4276fafbda9fSArun Easi 		case INTR_ROM_MB_FAILED:
4277fafbda9fSArun Easi 		case INTR_MB_SUCCESS:
4278fafbda9fSArun Easi 		case INTR_MB_FAILED:
4279e315cd28SAnirban Chakraborty 			qla24xx_mbx_completion(vha, MSW(stat));
42809a853f71SAndrew Vasquez 			status |= MBX_INTERRUPT;
42819a853f71SAndrew Vasquez 
42829a853f71SAndrew Vasquez 			break;
4283fafbda9fSArun Easi 		case INTR_ASYNC_EVENT:
42849a853f71SAndrew Vasquez 			mb[0] = MSW(stat);
428504474d3aSBart Van Assche 			mb[1] = rd_reg_word(&reg->mailbox1);
428604474d3aSBart Van Assche 			mb[2] = rd_reg_word(&reg->mailbox2);
428704474d3aSBart Van Assche 			mb[3] = rd_reg_word(&reg->mailbox3);
428873208dfdSAnirban Chakraborty 			qla2x00_async_event(vha, rsp, mb);
42899a853f71SAndrew Vasquez 			break;
4290fafbda9fSArun Easi 		case INTR_RSP_QUE_UPDATE:
4291fafbda9fSArun Easi 		case INTR_RSP_QUE_UPDATE_83XX:
42922afa19a9SAnirban Chakraborty 			qla24xx_process_response_queue(vha, rsp);
42939a853f71SAndrew Vasquez 			break;
4294c9558869SHimanshu Madhani 		case INTR_ATIO_QUE_UPDATE_27XX:
42951073daa4SQuinn Tran 		case INTR_ATIO_QUE_UPDATE:
42961073daa4SQuinn Tran 			process_atio = true;
42972d70c103SNicholas Bellinger 			break;
42981073daa4SQuinn Tran 		case INTR_ATIO_RSP_QUE_UPDATE:
42991073daa4SQuinn Tran 			process_atio = true;
43002d70c103SNicholas Bellinger 			qla24xx_process_response_queue(vha, rsp);
43012d70c103SNicholas Bellinger 			break;
43029a853f71SAndrew Vasquez 		default:
43037c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x504f,
43047c3df132SSaurav Kashyap 			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
43059a853f71SAndrew Vasquez 			break;
43069a853f71SAndrew Vasquez 		}
430704474d3aSBart Van Assche 		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
430804474d3aSBart Van Assche 		rd_reg_dword_relaxed(&reg->hccr);
4309cb860bbdSGiridhar Malavali 		if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
4310cb860bbdSGiridhar Malavali 			ndelay(3500);
43119a853f71SAndrew Vasquez 	}
431236439832Sgurinder.shergill@hp.com 	qla2x00_handle_mbx_completion(ha, status);
431343fac4d9SAnirban Chakraborty 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
43149a853f71SAndrew Vasquez 
43151073daa4SQuinn Tran 	if (process_atio) {
43161073daa4SQuinn Tran 		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
43171073daa4SQuinn Tran 		qlt_24xx_process_atio_queue(vha, 0);
43181073daa4SQuinn Tran 		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
43191073daa4SQuinn Tran 	}
43201073daa4SQuinn Tran 
43219a853f71SAndrew Vasquez 	return IRQ_HANDLED;
43229a853f71SAndrew Vasquez }
43239a853f71SAndrew Vasquez 
4324a8488abeSAndrew Vasquez static irqreturn_t
qla24xx_msix_rsp_q(int irq,void * dev_id)4325a8488abeSAndrew Vasquez qla24xx_msix_rsp_q(int irq, void *dev_id)
4326a8488abeSAndrew Vasquez {
4327e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha;
4328e315cd28SAnirban Chakraborty 	struct rsp_que *rsp;
4329a8488abeSAndrew Vasquez 	struct device_reg_24xx __iomem *reg;
43302afa19a9SAnirban Chakraborty 	struct scsi_qla_host *vha;
43310f19bc68SXiaotian Feng 	unsigned long flags;
4332a8488abeSAndrew Vasquez 
4333e315cd28SAnirban Chakraborty 	rsp = (struct rsp_que *) dev_id;
4334e315cd28SAnirban Chakraborty 	if (!rsp) {
43353256b435SChad Dupuis 		ql_log(ql_log_info, NULL, 0x505a,
43363256b435SChad Dupuis 		    "%s: NULL response queue pointer.\n", __func__);
4337e315cd28SAnirban Chakraborty 		return IRQ_NONE;
4338e315cd28SAnirban Chakraborty 	}
4339e315cd28SAnirban Chakraborty 	ha = rsp->hw;
4340a8488abeSAndrew Vasquez 	reg = &ha->iobase->isp24;
4341a8488abeSAndrew Vasquez 
43420f19bc68SXiaotian Feng 	spin_lock_irqsave(&ha->hardware_lock, flags);
4343a8488abeSAndrew Vasquez 
4344a67093d4SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
43452afa19a9SAnirban Chakraborty 	qla24xx_process_response_queue(vha, rsp);
43463155754aSAnirban Chakraborty 	if (!ha->flags.disable_msix_handshake) {
434704474d3aSBart Van Assche 		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
434804474d3aSBart Van Assche 		rd_reg_dword_relaxed(&reg->hccr);
4349eb94114bSAnirban Chakraborty 	}
43500f19bc68SXiaotian Feng 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
435173208dfdSAnirban Chakraborty 
435273208dfdSAnirban Chakraborty 	return IRQ_HANDLED;
435373208dfdSAnirban Chakraborty }
435473208dfdSAnirban Chakraborty 
435573208dfdSAnirban Chakraborty static irqreturn_t
qla24xx_msix_default(int irq,void * dev_id)4356a8488abeSAndrew Vasquez qla24xx_msix_default(int irq, void *dev_id)
4357a8488abeSAndrew Vasquez {
4358e315cd28SAnirban Chakraborty 	scsi_qla_host_t	*vha;
4359e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha;
4360e315cd28SAnirban Chakraborty 	struct rsp_que *rsp;
4361a8488abeSAndrew Vasquez 	struct device_reg_24xx __iomem *reg;
4362a8488abeSAndrew Vasquez 	int		status;
4363a8488abeSAndrew Vasquez 	uint32_t	stat;
4364a8488abeSAndrew Vasquez 	uint32_t	hccr;
43657d613ac6SSantosh Vernekar 	uint16_t	mb[8];
43660f19bc68SXiaotian Feng 	unsigned long flags;
43671073daa4SQuinn Tran 	bool process_atio = false;
4368a8488abeSAndrew Vasquez 
4369e315cd28SAnirban Chakraborty 	rsp = (struct rsp_que *) dev_id;
4370e315cd28SAnirban Chakraborty 	if (!rsp) {
43713256b435SChad Dupuis 		ql_log(ql_log_info, NULL, 0x505c,
43723256b435SChad Dupuis 		    "%s: NULL response queue pointer.\n", __func__);
4373e315cd28SAnirban Chakraborty 		return IRQ_NONE;
4374e315cd28SAnirban Chakraborty 	}
4375e315cd28SAnirban Chakraborty 	ha = rsp->hw;
4376a8488abeSAndrew Vasquez 	reg = &ha->iobase->isp24;
4377a8488abeSAndrew Vasquez 	status = 0;
4378a8488abeSAndrew Vasquez 
43790f19bc68SXiaotian Feng 	spin_lock_irqsave(&ha->hardware_lock, flags);
43802afa19a9SAnirban Chakraborty 	vha = pci_get_drvdata(ha->pdev);
438187f27015SAndrew Vasquez 	do {
438204474d3aSBart Van Assche 		stat = rd_reg_dword(&reg->host_status);
4383c821e0d5SJoe Lawrence 		if (qla2x00_check_reg32_for_disconnect(vha, stat))
4384f3ddac19SChad Dupuis 			break;
4385a8488abeSAndrew Vasquez 		if (stat & HSRX_RISC_PAUSED) {
438685880801SAndrew Vasquez 			if (unlikely(pci_channel_offline(ha->pdev)))
438714e660e6SSeokmann Ju 				break;
438814e660e6SSeokmann Ju 
438904474d3aSBart Van Assche 			hccr = rd_reg_dword(&reg->hccr);
4390a8488abeSAndrew Vasquez 
43917c3df132SSaurav Kashyap 			ql_log(ql_log_info, vha, 0x5050,
43927c3df132SSaurav Kashyap 			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
43937c3df132SSaurav Kashyap 			    hccr);
439405236a05SAndrew Vasquez 
4395e315cd28SAnirban Chakraborty 			qla2xxx_check_risc_status(vha);
4396dbf1f53cSSaurav Kashyap 			vha->hw_err_cnt++;
439705236a05SAndrew Vasquez 
43988ae17876SBart Van Assche 			ha->isp_ops->fw_dump(vha);
4399e315cd28SAnirban Chakraborty 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
4400a8488abeSAndrew Vasquez 			break;
4401a8488abeSAndrew Vasquez 		} else if ((stat & HSRX_RISC_INT) == 0)
4402a8488abeSAndrew Vasquez 			break;
4403a8488abeSAndrew Vasquez 
4404a8488abeSAndrew Vasquez 		switch (stat & 0xff) {
4405fafbda9fSArun Easi 		case INTR_ROM_MB_SUCCESS:
4406fafbda9fSArun Easi 		case INTR_ROM_MB_FAILED:
4407fafbda9fSArun Easi 		case INTR_MB_SUCCESS:
4408fafbda9fSArun Easi 		case INTR_MB_FAILED:
4409e315cd28SAnirban Chakraborty 			qla24xx_mbx_completion(vha, MSW(stat));
4410a8488abeSAndrew Vasquez 			status |= MBX_INTERRUPT;
4411a8488abeSAndrew Vasquez 
4412a8488abeSAndrew Vasquez 			break;
4413fafbda9fSArun Easi 		case INTR_ASYNC_EVENT:
4414a8488abeSAndrew Vasquez 			mb[0] = MSW(stat);
441504474d3aSBart Van Assche 			mb[1] = rd_reg_word(&reg->mailbox1);
441604474d3aSBart Van Assche 			mb[2] = rd_reg_word(&reg->mailbox2);
441704474d3aSBart Van Assche 			mb[3] = rd_reg_word(&reg->mailbox3);
441873208dfdSAnirban Chakraborty 			qla2x00_async_event(vha, rsp, mb);
4419a8488abeSAndrew Vasquez 			break;
4420fafbda9fSArun Easi 		case INTR_RSP_QUE_UPDATE:
4421fafbda9fSArun Easi 		case INTR_RSP_QUE_UPDATE_83XX:
44222afa19a9SAnirban Chakraborty 			qla24xx_process_response_queue(vha, rsp);
4423a8488abeSAndrew Vasquez 			break;
4424c9558869SHimanshu Madhani 		case INTR_ATIO_QUE_UPDATE_27XX:
44251073daa4SQuinn Tran 		case INTR_ATIO_QUE_UPDATE:
44261073daa4SQuinn Tran 			process_atio = true;
44272d70c103SNicholas Bellinger 			break;
44281073daa4SQuinn Tran 		case INTR_ATIO_RSP_QUE_UPDATE:
44291073daa4SQuinn Tran 			process_atio = true;
44302d70c103SNicholas Bellinger 			qla24xx_process_response_queue(vha, rsp);
44312d70c103SNicholas Bellinger 			break;
4432a8488abeSAndrew Vasquez 		default:
44337c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_async, vha, 0x5051,
44347c3df132SSaurav Kashyap 			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
4435a8488abeSAndrew Vasquez 			break;
4436a8488abeSAndrew Vasquez 		}
443704474d3aSBart Van Assche 		wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
443887f27015SAndrew Vasquez 	} while (0);
443936439832Sgurinder.shergill@hp.com 	qla2x00_handle_mbx_completion(ha, status);
44400f19bc68SXiaotian Feng 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4441a8488abeSAndrew Vasquez 
44421073daa4SQuinn Tran 	if (process_atio) {
44431073daa4SQuinn Tran 		spin_lock_irqsave(&ha->tgt.atio_lock, flags);
44441073daa4SQuinn Tran 		qlt_24xx_process_atio_queue(vha, 0);
44451073daa4SQuinn Tran 		spin_unlock_irqrestore(&ha->tgt.atio_lock, flags);
44461073daa4SQuinn Tran 	}
44471073daa4SQuinn Tran 
4448a8488abeSAndrew Vasquez 	return IRQ_HANDLED;
4449a8488abeSAndrew Vasquez }
4450a8488abeSAndrew Vasquez 
4451d7459527SMichael Hernandez irqreturn_t
qla2xxx_msix_rsp_q(int irq,void * dev_id)4452d7459527SMichael Hernandez qla2xxx_msix_rsp_q(int irq, void *dev_id)
4453d7459527SMichael Hernandez {
4454d7459527SMichael Hernandez 	struct qla_hw_data *ha;
4455d7459527SMichael Hernandez 	struct qla_qpair *qpair;
44567b2a7396SAndrew Vasquez 
44577b2a7396SAndrew Vasquez 	qpair = dev_id;
44587b2a7396SAndrew Vasquez 	if (!qpair) {
44597b2a7396SAndrew Vasquez 		ql_log(ql_log_info, NULL, 0x505b,
44607b2a7396SAndrew Vasquez 		    "%s: NULL response queue pointer.\n", __func__);
44617b2a7396SAndrew Vasquez 		return IRQ_NONE;
44627b2a7396SAndrew Vasquez 	}
44637b2a7396SAndrew Vasquez 	ha = qpair->hw;
44647b2a7396SAndrew Vasquez 
4465*59f10a05SNilesh Javali 	queue_work(ha->wq, &qpair->q_work);
44667b2a7396SAndrew Vasquez 
44677b2a7396SAndrew Vasquez 	return IRQ_HANDLED;
44687b2a7396SAndrew Vasquez }
44697b2a7396SAndrew Vasquez 
44707b2a7396SAndrew Vasquez irqreturn_t
qla2xxx_msix_rsp_q_hs(int irq,void * dev_id)44717b2a7396SAndrew Vasquez qla2xxx_msix_rsp_q_hs(int irq, void *dev_id)
44727b2a7396SAndrew Vasquez {
44737b2a7396SAndrew Vasquez 	struct qla_hw_data *ha;
44747b2a7396SAndrew Vasquez 	struct qla_qpair *qpair;
4475d7459527SMichael Hernandez 	struct device_reg_24xx __iomem *reg;
4476d7459527SMichael Hernandez 	unsigned long flags;
4477d7459527SMichael Hernandez 
4478d7459527SMichael Hernandez 	qpair = dev_id;
4479d7459527SMichael Hernandez 	if (!qpair) {
4480d7459527SMichael Hernandez 		ql_log(ql_log_info, NULL, 0x505b,
4481d7459527SMichael Hernandez 		    "%s: NULL response queue pointer.\n", __func__);
4482d7459527SMichael Hernandez 		return IRQ_NONE;
4483d7459527SMichael Hernandez 	}
4484d7459527SMichael Hernandez 	ha = qpair->hw;
4485d7459527SMichael Hernandez 
4486d7459527SMichael Hernandez 	reg = &ha->iobase->isp24;
4487d7459527SMichael Hernandez 	spin_lock_irqsave(&ha->hardware_lock, flags);
448804474d3aSBart Van Assche 	wrt_reg_dword(&reg->hccr, HCCRX_CLR_RISC_INT);
4489d7459527SMichael Hernandez 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
4490d7459527SMichael Hernandez 
4491*59f10a05SNilesh Javali 	queue_work(ha->wq, &qpair->q_work);
4492d7459527SMichael Hernandez 
4493d7459527SMichael Hernandez 	return IRQ_HANDLED;
4494d7459527SMichael Hernandez }
4495d7459527SMichael Hernandez 
4496a8488abeSAndrew Vasquez /* Interrupt handling helpers. */
4497a8488abeSAndrew Vasquez 
4498a8488abeSAndrew Vasquez struct qla_init_msix_entry {
4499a8488abeSAndrew Vasquez 	const char *name;
4500476834c2SJeff Garzik 	irq_handler_t handler;
4501a8488abeSAndrew Vasquez };
4502a8488abeSAndrew Vasquez 
450344a8f954SNicolas Iooss static const struct qla_init_msix_entry msix_entries[] = {
4504e326d22aSQuinn Tran 	{ "default", qla24xx_msix_default },
4505e326d22aSQuinn Tran 	{ "rsp_q", qla24xx_msix_rsp_q },
4506e326d22aSQuinn Tran 	{ "atio_q", qla83xx_msix_atio_q },
4507e326d22aSQuinn Tran 	{ "qpair_multiq", qla2xxx_msix_rsp_q },
45087b2a7396SAndrew Vasquez 	{ "qpair_multiq_hs", qla2xxx_msix_rsp_q_hs },
4509aa230bc5SArun Easi };
4510aa230bc5SArun Easi 
451144a8f954SNicolas Iooss static const struct qla_init_msix_entry qla82xx_msix_entries[] = {
45122afa19a9SAnirban Chakraborty 	{ "qla2xxx (default)", qla82xx_msix_default },
45132afa19a9SAnirban Chakraborty 	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
451468ca949cSAnirban Chakraborty };
4515a8488abeSAndrew Vasquez 
4516a8488abeSAndrew Vasquez static int
qla24xx_enable_msix(struct qla_hw_data * ha,struct rsp_que * rsp)451773208dfdSAnirban Chakraborty qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
4518a8488abeSAndrew Vasquez {
4519a8488abeSAndrew Vasquez 	int i, ret;
4520a8488abeSAndrew Vasquez 	struct qla_msix_entry *qentry;
45217c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
452267f2db87SMichael Hernandez 	int min_vecs = QLA_BASE_VECTORS;
452317e5fc58SChristoph Hellwig 	struct irq_affinity desc = {
452417e5fc58SChristoph Hellwig 		.pre_vectors = QLA_BASE_VECTORS,
452517e5fc58SChristoph Hellwig 	};
4526a8488abeSAndrew Vasquez 
4527c9558869SHimanshu Madhani 	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
4528c9558869SHimanshu Madhani 	    IS_ATIO_MSIX_CAPABLE(ha)) {
452917e5fc58SChristoph Hellwig 		desc.pre_vectors++;
453067f2db87SMichael Hernandez 		min_vecs++;
453167f2db87SMichael Hernandez 	}
453217e5fc58SChristoph Hellwig 
4533f3e02695SGiridhar Malavali 	if (USER_CTRL_IRQ(ha) || !ha->mqiobase) {
453409620eebSQuinn Tran 		/* user wants to control IRQ setting for target mode */
453509620eebSQuinn Tran 		ret = pci_alloc_irq_vectors(ha->pdev, min_vecs,
4536f02d4086SRoman Bolshakov 		    min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)),
4537a6dcfe08SQuinn Tran 		    PCI_IRQ_MSIX);
453809620eebSQuinn Tran 	} else
453967f2db87SMichael Hernandez 		ret = pci_alloc_irq_vectors_affinity(ha->pdev, min_vecs,
4540f02d4086SRoman Bolshakov 		    min((u16)ha->msix_count, (u16)(num_online_cpus() + min_vecs)),
4541a6dcfe08SQuinn Tran 		    PCI_IRQ_MSIX | PCI_IRQ_AFFINITY,
454217e5fc58SChristoph Hellwig 		    &desc);
454317e5fc58SChristoph Hellwig 
454484e32a06SAlexander Gordeev 	if (ret < 0) {
45457c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x00c7,
45467c3df132SSaurav Kashyap 		    "MSI-X: Failed to enable support, "
45477c3df132SSaurav Kashyap 		    "giving   up -- %d/%d.\n",
454873208dfdSAnirban Chakraborty 		    ha->msix_count, ret);
454973208dfdSAnirban Chakraborty 		goto msix_out;
455084e32a06SAlexander Gordeev 	} else if (ret < ha->msix_count) {
4551da48b824SHimanshu Madhani 		ql_log(ql_log_info, vha, 0x00c6,
4552da48b824SHimanshu Madhani 		    "MSI-X: Using %d vectors\n", ret);
455384e32a06SAlexander Gordeev 		ha->msix_count = ret;
4554d7459527SMichael Hernandez 		/* Recalculate queue values */
4555c38d1bafSHimanshu Madhani 		if (ha->mqiobase && (ql2xmqsupport || ql2xnvmeenable)) {
4556d7459527SMichael Hernandez 			ha->max_req_queues = ha->msix_count - 1;
4557d7459527SMichael Hernandez 
4558d7459527SMichael Hernandez 			/* ATIOQ needs 1 vector. That's 1 less QPair */
4559d7459527SMichael Hernandez 			if (QLA_TGT_MODE_ENABLED())
4560d7459527SMichael Hernandez 				ha->max_req_queues--;
4561d7459527SMichael Hernandez 
4562d7459527SMichael Hernandez 			ha->max_rsp_queues = ha->max_req_queues;
4563d7459527SMichael Hernandez 
4564d7459527SMichael Hernandez 			ha->max_qpairs = ha->max_req_queues - 1;
4565d7459527SMichael Hernandez 			ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0190,
4566d7459527SMichael Hernandez 			    "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs);
4567d7459527SMichael Hernandez 		}
4568cb43285fSQuinn Tran 	}
4569f0783d43SMing Lei 	vha->irq_offset = desc.pre_vectors;
45706396bb22SKees Cook 	ha->msix_entries = kcalloc(ha->msix_count,
45716396bb22SKees Cook 				   sizeof(struct qla_msix_entry),
45726396bb22SKees Cook 				   GFP_KERNEL);
457373208dfdSAnirban Chakraborty 	if (!ha->msix_entries) {
45747c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x00c8,
45757c3df132SSaurav Kashyap 		    "Failed to allocate memory for ha->msix_entries.\n");
457673208dfdSAnirban Chakraborty 		ret = -ENOMEM;
457724afabdbSBart Van Assche 		goto free_irqs;
4578a8488abeSAndrew Vasquez 	}
4579a8488abeSAndrew Vasquez 	ha->flags.msix_enabled = 1;
4580a8488abeSAndrew Vasquez 
458173208dfdSAnirban Chakraborty 	for (i = 0; i < ha->msix_count; i++) {
458273208dfdSAnirban Chakraborty 		qentry = &ha->msix_entries[i];
45834fa18345SMichael Hernandez 		qentry->vector = pci_irq_vector(ha->pdev, i);
45841d201c81SShreyas Deodhar 		qentry->vector_base0 = i;
45854fa18345SMichael Hernandez 		qentry->entry = i;
4586a8488abeSAndrew Vasquez 		qentry->have_irq = 0;
4587d7459527SMichael Hernandez 		qentry->in_use = 0;
45884fa18345SMichael Hernandez 		qentry->handle = NULL;
458973208dfdSAnirban Chakraborty 	}
459073208dfdSAnirban Chakraborty 
45912afa19a9SAnirban Chakraborty 	/* Enable MSI-X vectors for the base queue */
459217e5fc58SChristoph Hellwig 	for (i = 0; i < QLA_BASE_VECTORS; i++) {
45932afa19a9SAnirban Chakraborty 		qentry = &ha->msix_entries[i];
45944fa18345SMichael Hernandez 		qentry->handle = rsp;
4595ef8d1d51SJohannes Thumshirn 		rsp->msix = qentry;
4596d7459527SMichael Hernandez 		scnprintf(qentry->name, sizeof(qentry->name),
4597e326d22aSQuinn Tran 		    "qla2xxx%lu_%s", vha->host_no, msix_entries[i].name);
4598f324777eSChad Dupuis 		if (IS_P3P_TYPE(ha))
4599a9083016SGiridhar Malavali 			ret = request_irq(qentry->vector,
4600a9083016SGiridhar Malavali 				qla82xx_msix_entries[i].handler,
4601a9083016SGiridhar Malavali 				0, qla82xx_msix_entries[i].name, rsp);
4602f324777eSChad Dupuis 		else
4603a9083016SGiridhar Malavali 			ret = request_irq(qentry->vector,
4604a9083016SGiridhar Malavali 				msix_entries[i].handler,
4605e326d22aSQuinn Tran 				0, qentry->name, rsp);
4606f324777eSChad Dupuis 		if (ret)
4607f324777eSChad Dupuis 			goto msix_register_fail;
4608f324777eSChad Dupuis 		qentry->have_irq = 1;
4609093df737SQuinn Tran 		qentry->in_use = 1;
4610a9083016SGiridhar Malavali 	}
4611f324777eSChad Dupuis 
4612f324777eSChad Dupuis 	/*
4613f324777eSChad Dupuis 	 * If target mode is enable, also request the vector for the ATIO
4614f324777eSChad Dupuis 	 * queue.
4615f324777eSChad Dupuis 	 */
4616c9558869SHimanshu Madhani 	if (QLA_TGT_MODE_ENABLED() && (ql2xenablemsix != 0) &&
4617c9558869SHimanshu Madhani 	    IS_ATIO_MSIX_CAPABLE(ha)) {
4618093df737SQuinn Tran 		qentry = &ha->msix_entries[QLA_ATIO_VECTOR];
4619ef8d1d51SJohannes Thumshirn 		rsp->msix = qentry;
4620d7459527SMichael Hernandez 		qentry->handle = rsp;
4621d7459527SMichael Hernandez 		scnprintf(qentry->name, sizeof(qentry->name),
4622e326d22aSQuinn Tran 		    "qla2xxx%lu_%s", vha->host_no,
4623e326d22aSQuinn Tran 		    msix_entries[QLA_ATIO_VECTOR].name);
4624093df737SQuinn Tran 		qentry->in_use = 1;
4625f324777eSChad Dupuis 		ret = request_irq(qentry->vector,
4626093df737SQuinn Tran 			msix_entries[QLA_ATIO_VECTOR].handler,
4627e326d22aSQuinn Tran 			0, qentry->name, rsp);
4628f324777eSChad Dupuis 		qentry->have_irq = 1;
4629f324777eSChad Dupuis 	}
4630f324777eSChad Dupuis 
4631f324777eSChad Dupuis msix_register_fail:
4632a8488abeSAndrew Vasquez 	if (ret) {
46337c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x00cb,
46347c3df132SSaurav Kashyap 		    "MSI-X: unable to register handler -- %x/%d.\n",
463573208dfdSAnirban Chakraborty 		    qentry->vector, ret);
46364fa18345SMichael Hernandez 		qla2x00_free_irqs(vha);
46372afa19a9SAnirban Chakraborty 		ha->mqenable = 0;
4638a8488abeSAndrew Vasquez 		goto msix_out;
4639a8488abeSAndrew Vasquez 	}
464073208dfdSAnirban Chakraborty 
464173208dfdSAnirban Chakraborty 	/* Enable MSI-X vector for response queue update for queue 0 */
46425304673bSQuinn Tran 	if (IS_MQUE_CAPABLE(ha) &&
46435304673bSQuinn Tran 	    (ha->msixbase && ha->mqiobase && ha->max_qpairs))
46446246b8a1SGiridhar Malavali 		ha->mqenable = 1;
46455304673bSQuinn Tran 	else
46465304673bSQuinn Tran 		ha->mqenable = 0;
46475304673bSQuinn Tran 
46487c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_multiq, vha, 0xc005,
46497c3df132SSaurav Kashyap 	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
46507c3df132SSaurav Kashyap 	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
46517c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, vha, 0x0055,
46527c3df132SSaurav Kashyap 	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
46537c3df132SSaurav Kashyap 	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
465473208dfdSAnirban Chakraborty 
4655a8488abeSAndrew Vasquez msix_out:
4656a8488abeSAndrew Vasquez 	return ret;
465724afabdbSBart Van Assche 
465824afabdbSBart Van Assche free_irqs:
465924afabdbSBart Van Assche 	pci_free_irq_vectors(ha->pdev);
466024afabdbSBart Van Assche 	goto msix_out;
4661a8488abeSAndrew Vasquez }
4662a8488abeSAndrew Vasquez 
4663a8488abeSAndrew Vasquez int
qla2x00_request_irqs(struct qla_hw_data * ha,struct rsp_que * rsp)466473208dfdSAnirban Chakraborty qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
4665a8488abeSAndrew Vasquez {
46667fa3e239SSawan Chandak 	int ret = QLA_FUNCTION_FAILED;
4667f73cb695SChad Dupuis 	device_reg_t *reg = ha->iobase;
46687c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
4669a8488abeSAndrew Vasquez 
4670a8488abeSAndrew Vasquez 	/* If possible, enable MSI-X. */
4671e7240af5SHimanshu Madhani 	if (ql2xenablemsix == 0 || (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
4672e7240af5SHimanshu Madhani 	    !IS_QLA8432(ha) && !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
4673ecc89f25SJoe Carnuccio 	    !IS_QLAFX00(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha)))
46746377a7aeSBen Hutchings 		goto skip_msi;
4675a8488abeSAndrew Vasquez 
4676e7240af5SHimanshu Madhani 	if (ql2xenablemsix == 2)
4677e7240af5SHimanshu Madhani 		goto skip_msix;
4678e7240af5SHimanshu Madhani 
4679da7429f9SAndrew Vasquez 	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
4680da7429f9SAndrew Vasquez 		(ha->pdev->subsystem_device == 0x7040 ||
4681da7429f9SAndrew Vasquez 		ha->pdev->subsystem_device == 0x7041 ||
4682da7429f9SAndrew Vasquez 		ha->pdev->subsystem_device == 0x1705)) {
46837c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x0034,
4684da7429f9SAndrew Vasquez 		    "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
4685da7429f9SAndrew Vasquez 			ha->pdev->subsystem_vendor,
46867c3df132SSaurav Kashyap 			ha->pdev->subsystem_device);
4687da7429f9SAndrew Vasquez 		goto skip_msi;
4688da7429f9SAndrew Vasquez 	}
4689da7429f9SAndrew Vasquez 
469042cd4f5dSChad Dupuis 	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
46917c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x0035,
46927c3df132SSaurav Kashyap 		    "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
469342cd4f5dSChad Dupuis 		    ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
46946377a7aeSBen Hutchings 		goto skip_msix;
46956377a7aeSBen Hutchings 	}
46966377a7aeSBen Hutchings 
469773208dfdSAnirban Chakraborty 	ret = qla24xx_enable_msix(ha, rsp);
4698a8488abeSAndrew Vasquez 	if (!ret) {
46997c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x0036,
47007c3df132SSaurav Kashyap 		    "MSI-X: Enabled (0x%X, 0x%X).\n",
47017c3df132SSaurav Kashyap 		    ha->chip_revision, ha->fw_attributes);
4702963b0fddSAndrew Vasquez 		goto clear_risc_ints;
4703a8488abeSAndrew Vasquez 	}
47047fa3e239SSawan Chandak 
4705a8488abeSAndrew Vasquez skip_msix:
4706cbedb601SAndrew Vasquez 
47077fa3e239SSawan Chandak 	ql_log(ql_log_info, vha, 0x0037,
470845dc8f2dSHuacai Chen 	    "Falling back-to MSI mode -- ret=%d.\n", ret);
47097fa3e239SSawan Chandak 
47103a03eb79SAndrew Vasquez 	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
4711f73cb695SChad Dupuis 	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
4712ecc89f25SJoe Carnuccio 	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
4713cbedb601SAndrew Vasquez 		goto skip_msi;
4714cbedb601SAndrew Vasquez 
47154fa18345SMichael Hernandez 	ret = pci_alloc_irq_vectors(ha->pdev, 1, 1, PCI_IRQ_MSI);
471645dc8f2dSHuacai Chen 	if (ret > 0) {
47177c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x0038,
47187c3df132SSaurav Kashyap 		    "MSI: Enabled.\n");
4719cbedb601SAndrew Vasquez 		ha->flags.msi_enabled = 1;
4720a9083016SGiridhar Malavali 	} else
47217c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x0039,
472245dc8f2dSHuacai Chen 		    "Falling back-to INTa mode -- ret=%d.\n", ret);
47237fa3e239SSawan Chandak skip_msi:
4724a033b655SGiridhar Malavali 
4725a033b655SGiridhar Malavali 	/* Skip INTx on ISP82xx. */
4726a033b655SGiridhar Malavali 	if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
4727a033b655SGiridhar Malavali 		return QLA_FUNCTION_FAILED;
4728a033b655SGiridhar Malavali 
4729fd34f556SAndrew Vasquez 	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
47307992abfcSMike Hernandez 	    ha->flags.msi_enabled ? 0 : IRQF_SHARED,
47317992abfcSMike Hernandez 	    QLA2XXX_DRIVER_NAME, rsp);
4732963b0fddSAndrew Vasquez 	if (ret) {
47337c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x003a,
4734a8488abeSAndrew Vasquez 		    "Failed to reserve interrupt %d already in use.\n",
4735a8488abeSAndrew Vasquez 		    ha->pdev->irq);
4736963b0fddSAndrew Vasquez 		goto fail;
47378ae6d9c7SGiridhar Malavali 	} else if (!ha->flags.msi_enabled) {
473868d91cbdSSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x0125,
473968d91cbdSSaurav Kashyap 		    "INTa mode: Enabled.\n");
47408ae6d9c7SGiridhar Malavali 		ha->flags.mr_intr_valid = 1;
47414a0a542fSSaurav Kashyap 		/* Set max_qpair to 0, as MSI-X and MSI in not enabled */
47424a0a542fSSaurav Kashyap 		ha->max_qpairs = 0;
47438ae6d9c7SGiridhar Malavali 	}
47447992abfcSMike Hernandez 
4745963b0fddSAndrew Vasquez clear_risc_ints:
47464bb2efc4SJoe Carnuccio 	if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
47474bb2efc4SJoe Carnuccio 		goto fail;
4748a8488abeSAndrew Vasquez 
4749c6952483SAndrew Vasquez 	spin_lock_irq(&ha->hardware_lock);
475004474d3aSBart Van Assche 	wrt_reg_word(&reg->isp.semaphore, 0);
4751c6952483SAndrew Vasquez 	spin_unlock_irq(&ha->hardware_lock);
4752963b0fddSAndrew Vasquez 
4753963b0fddSAndrew Vasquez fail:
4754a8488abeSAndrew Vasquez 	return ret;
4755a8488abeSAndrew Vasquez }
4756a8488abeSAndrew Vasquez 
4757a8488abeSAndrew Vasquez void
qla2x00_free_irqs(scsi_qla_host_t * vha)4758e315cd28SAnirban Chakraborty qla2x00_free_irqs(scsi_qla_host_t *vha)
4759a8488abeSAndrew Vasquez {
4760e315cd28SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
47619a347ff4SChad Dupuis 	struct rsp_que *rsp;
47624fa18345SMichael Hernandez 	struct qla_msix_entry *qentry;
47634fa18345SMichael Hernandez 	int i;
47649a347ff4SChad Dupuis 
47659a347ff4SChad Dupuis 	/*
47669a347ff4SChad Dupuis 	 * We need to check that ha->rsp_q_map is valid in case we are called
47679a347ff4SChad Dupuis 	 * from a probe failure context.
47689a347ff4SChad Dupuis 	 */
47699a347ff4SChad Dupuis 	if (!ha->rsp_q_map || !ha->rsp_q_map[0])
477027873de9SBart Van Assche 		goto free_irqs;
47719a347ff4SChad Dupuis 	rsp = ha->rsp_q_map[0];
4772a8488abeSAndrew Vasquez 
47734fa18345SMichael Hernandez 	if (ha->flags.msix_enabled) {
47744fa18345SMichael Hernandez 		for (i = 0; i < ha->msix_count; i++) {
47754fa18345SMichael Hernandez 			qentry = &ha->msix_entries[i];
47764fa18345SMichael Hernandez 			if (qentry->have_irq) {
47774fa18345SMichael Hernandez 				irq_set_affinity_notifier(qentry->vector, NULL);
47784fa18345SMichael Hernandez 				free_irq(pci_irq_vector(ha->pdev, i), qentry->handle);
47794fa18345SMichael Hernandez 			}
47804fa18345SMichael Hernandez 		}
47814fa18345SMichael Hernandez 		kfree(ha->msix_entries);
47824fa18345SMichael Hernandez 		ha->msix_entries = NULL;
47834fa18345SMichael Hernandez 		ha->flags.msix_enabled = 0;
47844fa18345SMichael Hernandez 		ql_dbg(ql_dbg_init, vha, 0x0042,
47854fa18345SMichael Hernandez 			"Disabled MSI-X.\n");
47864fa18345SMichael Hernandez 	} else {
47874fa18345SMichael Hernandez 		free_irq(pci_irq_vector(ha->pdev, 0), rsp);
4788a8488abeSAndrew Vasquez 	}
4789e315cd28SAnirban Chakraborty 
479027873de9SBart Van Assche free_irqs:
47914fa18345SMichael Hernandez 	pci_free_irq_vectors(ha->pdev);
47921da177e4SLinus Torvalds }
479373208dfdSAnirban Chakraborty 
qla25xx_request_irq(struct qla_hw_data * ha,struct qla_qpair * qpair,struct qla_msix_entry * msix,int vector_type)4794d7459527SMichael Hernandez int qla25xx_request_irq(struct qla_hw_data *ha, struct qla_qpair *qpair,
4795d7459527SMichael Hernandez 	struct qla_msix_entry *msix, int vector_type)
479673208dfdSAnirban Chakraborty {
479744a8f954SNicolas Iooss 	const struct qla_init_msix_entry *intr = &msix_entries[vector_type];
47987c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
479973208dfdSAnirban Chakraborty 	int ret;
480073208dfdSAnirban Chakraborty 
4801d7459527SMichael Hernandez 	scnprintf(msix->name, sizeof(msix->name),
4802d7459527SMichael Hernandez 	    "qla2xxx%lu_qpair%d", vha->host_no, qpair->id);
4803d7459527SMichael Hernandez 	ret = request_irq(msix->vector, intr->handler, 0, msix->name, qpair);
480473208dfdSAnirban Chakraborty 	if (ret) {
48057c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x00e6,
480673208dfdSAnirban Chakraborty 		    "MSI-X: Unable to register handler -- %x/%d.\n",
480773208dfdSAnirban Chakraborty 		    msix->vector, ret);
480873208dfdSAnirban Chakraborty 		return ret;
480973208dfdSAnirban Chakraborty 	}
481073208dfdSAnirban Chakraborty 	msix->have_irq = 1;
4811d7459527SMichael Hernandez 	msix->handle = qpair;
48121d201c81SShreyas Deodhar 	qla_mapq_init_qp_cpu_map(ha, msix, qpair);
481373208dfdSAnirban Chakraborty 	return ret;
481473208dfdSAnirban Chakraborty }
4815