qla_isr.c 80.1 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
A
Andrew Vasquez 已提交
2
 * QLogic Fibre Channel HBA Driver
3
 * Copyright (c)  2003-2012 QLogic Corporation
L
Linus Torvalds 已提交
4
 *
A
Andrew Vasquez 已提交
5
 * See LICENSE.qla2xxx for copyright and licensing details.
L
Linus Torvalds 已提交
6 7
 */
#include "qla_def.h"
8
#include "qla_target.h"
L
Linus Torvalds 已提交
9

10
#include <linux/delay.h>
11
#include <linux/slab.h>
12
#include <scsi/scsi_tcq.h>
13
#include <scsi/scsi_bsg_fc.h>
14
#include <scsi/scsi_eh.h>
15

L
Linus Torvalds 已提交
16
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
17 18 19
static void qla2x00_process_completed_request(struct scsi_qla_host *,
	struct req_que *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
20
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
21 22
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
	sts_entry_t *);
23

L
Linus Torvalds 已提交
24 25 26 27 28 29 30 31 32 33
/**
 * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
 * @irq:
 * @dev_id: SCSI driver HA context
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
34
qla2100_intr_handler(int irq, void *dev_id)
L
Linus Torvalds 已提交
35
{
36 37
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
38
	struct device_reg_2xxx __iomem *reg;
L
Linus Torvalds 已提交
39 40
	int		status;
	unsigned long	iter;
41
	uint16_t	hccr;
42
	uint16_t	mb[4];
43
	struct rsp_que *rsp;
44
	unsigned long	flags;
L
Linus Torvalds 已提交
45

46 47
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
48 49
		ql_log(ql_log_info, NULL, 0x505d,
		    "%s: NULL response queue pointer.\n", __func__);
L
Linus Torvalds 已提交
50 51 52
		return (IRQ_NONE);
	}

53
	ha = rsp->hw;
54
	reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
55 56
	status = 0;

57
	spin_lock_irqsave(&ha->hardware_lock, flags);
58
	vha = pci_get_drvdata(ha->pdev);
L
Linus Torvalds 已提交
59
	for (iter = 50; iter--; ) {
60 61 62 63 64 65 66
		hccr = RD_REG_WORD(&reg->hccr);
		if (hccr & HCCR_RISC_PAUSE) {
			if (pci_channel_offline(ha->pdev))
				break;

			/*
			 * Issue a "HARD" reset in order for the RISC interrupt
67
			 * bit to be cleared.  Schedule a big hammer to get
68 69 70 71 72
			 * out of the RISC PAUSED state.
			 */
			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
			RD_REG_WORD(&reg->hccr);

73 74
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
75 76
			break;
		} else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
L
Linus Torvalds 已提交
77 78 79 80 81 82 83
			break;

		if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
			RD_REG_WORD(&reg->hccr);

			/* Get mailbox data. */
84 85
			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
86
				qla2x00_mbx_completion(vha, mb[0]);
L
Linus Torvalds 已提交
87
				status |= MBX_INTERRUPT;
88 89 90 91
			} else if (mb[0] > 0x7fff && mb[0] < 0xc000) {
				mb[1] = RD_MAILBOX_REG(ha, reg, 1);
				mb[2] = RD_MAILBOX_REG(ha, reg, 2);
				mb[3] = RD_MAILBOX_REG(ha, reg, 3);
92
				qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
93 94
			} else {
				/*EMPTY*/
95 96 97
				ql_dbg(ql_dbg_async, vha, 0x5025,
				    "Unrecognized interrupt type (%d).\n",
				    mb[0]);
L
Linus Torvalds 已提交
98 99 100 101 102
			}
			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			RD_REG_WORD(&reg->semaphore);
		} else {
103
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
104 105 106 107 108

			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
			RD_REG_WORD(&reg->hccr);
		}
	}
109
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
110 111 112 113

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
114
		complete(&ha->mbx_intr_comp);
L
Linus Torvalds 已提交
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
	}

	return (IRQ_HANDLED);
}

/**
 * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
 * @irq:
 * @dev_id: SCSI driver HA context
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
130
qla2300_intr_handler(int irq, void *dev_id)
L
Linus Torvalds 已提交
131
{
132
	scsi_qla_host_t	*vha;
133
	struct device_reg_2xxx __iomem *reg;
L
Linus Torvalds 已提交
134 135 136 137
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint16_t	hccr;
138
	uint16_t	mb[4];
139 140
	struct rsp_que *rsp;
	struct qla_hw_data *ha;
141
	unsigned long	flags;
L
Linus Torvalds 已提交
142

143 144
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
145 146
		ql_log(ql_log_info, NULL, 0x5058,
		    "%s: NULL response queue pointer.\n", __func__);
L
Linus Torvalds 已提交
147 148 149
		return (IRQ_NONE);
	}

150
	ha = rsp->hw;
151
	reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
152 153
	status = 0;

154
	spin_lock_irqsave(&ha->hardware_lock, flags);
155
	vha = pci_get_drvdata(ha->pdev);
L
Linus Torvalds 已提交
156 157 158
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
		if (stat & HSR_RISC_PAUSED) {
159
			if (unlikely(pci_channel_offline(ha->pdev)))
160 161
				break;

L
Linus Torvalds 已提交
162 163
			hccr = RD_REG_WORD(&reg->hccr);
			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
164 165 166
				ql_log(ql_log_warn, vha, 0x5026,
				    "Parity error -- HCCR=%x, Dumping "
				    "firmware.\n", hccr);
L
Linus Torvalds 已提交
167
			else
168 169 170
				ql_log(ql_log_warn, vha, 0x5027,
				    "RISC paused -- HCCR=%x, Dumping "
				    "firmware.\n", hccr);
L
Linus Torvalds 已提交
171 172 173 174

			/*
			 * Issue a "HARD" reset in order for the RISC
			 * interrupt bit to be cleared.  Schedule a big
175
			 * hammer to get out of the RISC PAUSED state.
L
Linus Torvalds 已提交
176 177 178
			 */
			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
			RD_REG_WORD(&reg->hccr);
179

180 181
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
182 183 184 185 186 187 188 189 190
			break;
		} else if ((stat & HSR_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
191
			qla2x00_mbx_completion(vha, MSW(stat));
L
Linus Torvalds 已提交
192 193 194 195 196 197
			status |= MBX_INTERRUPT;

			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			break;
		case 0x12:
198 199 200 201
			mb[0] = MSW(stat);
			mb[1] = RD_MAILBOX_REG(ha, reg, 1);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
			mb[3] = RD_MAILBOX_REG(ha, reg, 3);
202
			qla2x00_async_event(vha, rsp, mb);
203 204
			break;
		case 0x13:
205
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
206 207
			break;
		case 0x15:
208 209
			mb[0] = MBA_CMPLT_1_16BIT;
			mb[1] = MSW(stat);
210
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
211 212
			break;
		case 0x16:
213 214 215
			mb[0] = MBA_SCSI_COMPLETION;
			mb[1] = MSW(stat);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
216
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
217 218
			break;
		default:
219 220
			ql_dbg(ql_dbg_async, vha, 0x5028,
			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
L
Linus Torvalds 已提交
221 222 223 224 225
			break;
		}
		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
		RD_REG_WORD_RELAXED(&reg->hccr);
	}
226
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
227 228 229 230

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
231
		complete(&ha->mbx_intr_comp);
L
Linus Torvalds 已提交
232 233 234 235 236 237 238 239 240 241 242
	}

	return (IRQ_HANDLED);
}

/**
 * qla2x00_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
243
qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
L
Linus Torvalds 已提交
244 245
{
	uint16_t	cnt;
246
	uint32_t	mboxes;
L
Linus Torvalds 已提交
247
	uint16_t __iomem *wptr;
248
	struct qla_hw_data *ha = vha->hw;
249
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
250

251 252 253 254 255 256 257
	/* Read all mbox registers? */
	mboxes = (1 << ha->mbx_count) - 1;
	if (!ha->mcp)
		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERRROR.\n");
	else
		mboxes = ha->mcp->in_mb;

L
Linus Torvalds 已提交
258 259 260
	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
261
	mboxes >>= 1;
L
Linus Torvalds 已提交
262 263 264
	wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
A
Andrew Vasquez 已提交
265
		if (IS_QLA2200(ha) && cnt == 8)
L
Linus Torvalds 已提交
266
			wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
267
		if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
L
Linus Torvalds 已提交
268
			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
269
		else if (mboxes & BIT_0)
L
Linus Torvalds 已提交
270
			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
A
Andrew Vasquez 已提交
271

L
Linus Torvalds 已提交
272
		wptr++;
273
		mboxes >>= 1;
L
Linus Torvalds 已提交
274 275 276
	}
}

277 278 279 280 281 282 283 284 285 286 287 288 289 290 291
static void
qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
{
	static char *event[] =
		{ "Complete", "Request Notification", "Time Extension" };
	int rval;
	struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
	uint16_t __iomem *wptr;
	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];

	/* Seed data -- mailbox1 -> mailbox7. */
	wptr = (uint16_t __iomem *)&reg24->mailbox1;
	for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
		mb[cnt] = RD_REG_WORD(wptr);

292
	ql_dbg(ql_dbg_async, vha, 0x5021,
293
	    "Inter-Driver Communication %s -- "
294 295 296
	    "%04x %04x %04x %04x %04x %04x %04x.\n",
	    event[aen & 0xff], mb[0], mb[1], mb[2], mb[3],
	    mb[4], mb[5], mb[6]);
297

298 299 300 301 302 303 304 305 306 307
	if (IS_QLA81XX(vha->hw)) {
		/* Acknowledgement needed? [Notify && non-zero timeout]. */
		timeout = (descr >> 8) & 0xf;
		if (aen != MBA_IDC_NOTIFY || !timeout)
			return;

		ql_dbg(ql_dbg_async, vha, 0x5022,
		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
		    vha->host_no, event[aen & 0xff], timeout);
	}
308 309 310

	rval = qla2x00_post_idc_ack_work(vha, mb);
	if (rval != QLA_SUCCESS)
311
		ql_log(ql_log_warn, vha, 0x5023,
312 313 314
		    "IDC failed to post ACK.\n");
}

315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336
#define LS_UNKNOWN	2
char *
qla2x00_get_link_speed_str(struct qla_hw_data *ha)
{
	static char *link_speeds[] = {"1", "2", "?", "4", "8", "16", "10"};
	char *link_speed;
	int fw_speed = ha->link_data_rate;

	if (IS_QLA2100(ha) || IS_QLA2200(ha))
		link_speed = link_speeds[0];
	else if (fw_speed == 0x13)
		link_speed = link_speeds[6];
	else {
		link_speed = link_speeds[LS_UNKNOWN];
		if (fw_speed < 6)
			link_speed =
			    link_speeds[fw_speed];
	}

	return link_speed;
}

337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
void
qla83xx_handle_8200_aen(scsi_qla_host_t *vha, uint16_t *mb)
{
	struct qla_hw_data *ha = vha->hw;

	/*
	 * 8200 AEN Interpretation:
	 * mb[0] = AEN code
	 * mb[1] = AEN Reason code
	 * mb[2] = LSW of Peg-Halt Status-1 Register
	 * mb[6] = MSW of Peg-Halt Status-1 Register
	 * mb[3] = LSW of Peg-Halt Status-2 register
	 * mb[7] = MSW of Peg-Halt Status-2 register
	 * mb[4] = IDC Device-State Register value
	 * mb[5] = IDC Driver-Presence Register value
	 */
	ql_dbg(ql_dbg_async, vha, 0x506b, "AEN Code: mb[0] = 0x%x AEN reason: "
	    "mb[1] = 0x%x PH-status1: mb[2] = 0x%x PH-status1: mb[6] = 0x%x.\n",
	    mb[0], mb[1], mb[2], mb[6]);
	ql_dbg(ql_dbg_async, vha, 0x506c, "PH-status2: mb[3] = 0x%x "
	    "PH-status2: mb[7] = 0x%x Device-State: mb[4] = 0x%x "
	    "Drv-Presence: mb[5] = 0x%x.\n", mb[3], mb[7], mb[4], mb[5]);

	if (mb[1] & (IDC_PEG_HALT_STATUS_CHANGE | IDC_NIC_FW_REPORTED_FAILURE |
				IDC_HEARTBEAT_FAILURE)) {
		ha->flags.nic_core_hung = 1;
		ql_log(ql_log_warn, vha, 0x5060,
		    "83XX: F/W Error Reported: Check if reset required.\n");

		if (mb[1] & IDC_PEG_HALT_STATUS_CHANGE) {
			uint32_t protocol_engine_id, fw_err_code, err_level;

			/*
			 * IDC_PEG_HALT_STATUS_CHANGE interpretation:
			 *  - PEG-Halt Status-1 Register:
			 *	(LSW = mb[2], MSW = mb[6])
			 *	Bits 0-7   = protocol-engine ID
			 *	Bits 8-28  = f/w error code
			 *	Bits 29-31 = Error-level
			 *	    Error-level 0x1 = Non-Fatal error
			 *	    Error-level 0x2 = Recoverable Fatal error
			 *	    Error-level 0x4 = UnRecoverable Fatal error
			 *  - PEG-Halt Status-2 Register:
			 *	(LSW = mb[3], MSW = mb[7])
			 */
			protocol_engine_id = (mb[2] & 0xff);
			fw_err_code = (((mb[2] & 0xff00) >> 8) |
			    ((mb[6] & 0x1fff) << 8));
			err_level = ((mb[6] & 0xe000) >> 13);
			ql_log(ql_log_warn, vha, 0x5061, "PegHalt Status-1 "
			    "Register: protocol_engine_id=0x%x "
			    "fw_err_code=0x%x err_level=0x%x.\n",
			    protocol_engine_id, fw_err_code, err_level);
			ql_log(ql_log_warn, vha, 0x5062, "PegHalt Status-2 "
			    "Register: 0x%x%x.\n", mb[7], mb[3]);
			if (err_level == ERR_LEVEL_NON_FATAL) {
				ql_log(ql_log_warn, vha, 0x5063,
				    "Not a fatal error, f/w has recovered "
				    "iteself.\n");
			} else if (err_level == ERR_LEVEL_RECOVERABLE_FATAL) {
				ql_log(ql_log_fatal, vha, 0x5064,
				    "Recoverable Fatal error: Chip reset "
				    "required.\n");
				qla83xx_schedule_work(vha,
				    QLA83XX_NIC_CORE_RESET);
			} else if (err_level == ERR_LEVEL_UNRECOVERABLE_FATAL) {
				ql_log(ql_log_fatal, vha, 0x5065,
				    "Unrecoverable Fatal error: Set FAILED "
				    "state, reboot required.\n");
				qla83xx_schedule_work(vha,
				    QLA83XX_NIC_CORE_UNRECOVERABLE);
			}
		}

		if (mb[1] & IDC_NIC_FW_REPORTED_FAILURE) {
			uint16_t peg_fw_state, nw_interface_link_up;
			uint16_t nw_interface_signal_detect, sfp_status;
			uint16_t htbt_counter, htbt_monitor_enable;
			uint16_t sfp_additonal_info, sfp_multirate;
			uint16_t sfp_tx_fault, link_speed, dcbx_status;

			/*
			 * IDC_NIC_FW_REPORTED_FAILURE interpretation:
			 *  - PEG-to-FC Status Register:
			 *	(LSW = mb[2], MSW = mb[6])
			 *	Bits 0-7   = Peg-Firmware state
			 *	Bit 8      = N/W Interface Link-up
			 *	Bit 9      = N/W Interface signal detected
			 *	Bits 10-11 = SFP Status
			 *	  SFP Status 0x0 = SFP+ transceiver not expected
			 *	  SFP Status 0x1 = SFP+ transceiver not present
			 *	  SFP Status 0x2 = SFP+ transceiver invalid
			 *	  SFP Status 0x3 = SFP+ transceiver present and
			 *	  valid
			 *	Bits 12-14 = Heartbeat Counter
			 *	Bit 15     = Heartbeat Monitor Enable
			 *	Bits 16-17 = SFP Additional Info
			 *	  SFP info 0x0 = Unregocnized transceiver for
			 *	  Ethernet
			 *	  SFP info 0x1 = SFP+ brand validation failed
			 *	  SFP info 0x2 = SFP+ speed validation failed
			 *	  SFP info 0x3 = SFP+ access error
			 *	Bit 18     = SFP Multirate
			 *	Bit 19     = SFP Tx Fault
			 *	Bits 20-22 = Link Speed
			 *	Bits 23-27 = Reserved
			 *	Bits 28-30 = DCBX Status
			 *	  DCBX Status 0x0 = DCBX Disabled
			 *	  DCBX Status 0x1 = DCBX Enabled
			 *	  DCBX Status 0x2 = DCBX Exchange error
			 *	Bit 31     = Reserved
			 */
			peg_fw_state = (mb[2] & 0x00ff);
			nw_interface_link_up = ((mb[2] & 0x0100) >> 8);
			nw_interface_signal_detect = ((mb[2] & 0x0200) >> 9);
			sfp_status = ((mb[2] & 0x0c00) >> 10);
			htbt_counter = ((mb[2] & 0x7000) >> 12);
			htbt_monitor_enable = ((mb[2] & 0x8000) >> 15);
			sfp_additonal_info = (mb[6] & 0x0003);
			sfp_multirate = ((mb[6] & 0x0004) >> 2);
			sfp_tx_fault = ((mb[6] & 0x0008) >> 3);
			link_speed = ((mb[6] & 0x0070) >> 4);
			dcbx_status = ((mb[6] & 0x7000) >> 12);

			ql_log(ql_log_warn, vha, 0x5066,
			    "Peg-to-Fc Status Register:\n"
			    "peg_fw_state=0x%x, nw_interface_link_up=0x%x, "
			    "nw_interface_signal_detect=0x%x"
			    "\nsfp_statis=0x%x.\n ", peg_fw_state,
			    nw_interface_link_up, nw_interface_signal_detect,
			    sfp_status);
			ql_log(ql_log_warn, vha, 0x5067,
			    "htbt_counter=0x%x, htbt_monitor_enable=0x%x, "
			    "sfp_additonal_info=0x%x, sfp_multirate=0x%x.\n ",
			    htbt_counter, htbt_monitor_enable,
			    sfp_additonal_info, sfp_multirate);
			ql_log(ql_log_warn, vha, 0x5068,
			    "sfp_tx_fault=0x%x, link_state=0x%x, "
			    "dcbx_status=0x%x.\n", sfp_tx_fault, link_speed,
			    dcbx_status);

			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
		}

		if (mb[1] & IDC_HEARTBEAT_FAILURE) {
			ql_log(ql_log_warn, vha, 0x5069,
			    "Heartbeat Failure encountered, chip reset "
			    "required.\n");

			qla83xx_schedule_work(vha, QLA83XX_NIC_CORE_RESET);
		}
	}

	if (mb[1] & IDC_DEVICE_STATE_CHANGE) {
		ql_log(ql_log_info, vha, 0x506a,
		    "IDC Device-State changed = 0x%x.\n", mb[4]);
		qla83xx_schedule_work(vha, MBA_IDC_AEN);
	}
}

L
Linus Torvalds 已提交
497 498 499
/**
 * qla2x00_async_event() - Process aynchronous events.
 * @ha: SCSI driver HA context
500
 * @mb: Mailbox registers (0 - 3)
L
Linus Torvalds 已提交
501
 */
502
void
503
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
L
Linus Torvalds 已提交
504 505
{
	uint16_t	handle_cnt;
506
	uint16_t	cnt, mbx;
L
Linus Torvalds 已提交
507
	uint32_t	handles[5];
508
	struct qla_hw_data *ha = vha->hw;
509
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
510
	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
511
	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
L
Linus Torvalds 已提交
512
	uint32_t	rscn_entry, host_pid;
513
	unsigned long	flags;
L
Linus Torvalds 已提交
514 515 516

	/* Setup to process RIO completion. */
	handle_cnt = 0;
517
	if (IS_CNA_CAPABLE(ha))
518
		goto skip_rio;
L
Linus Torvalds 已提交
519 520
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:
521
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
522 523 524
		handle_cnt = 1;
		break;
	case MBA_CMPLT_1_16BIT:
525
		handles[0] = mb[1];
L
Linus Torvalds 已提交
526 527 528 529
		handle_cnt = 1;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_2_16BIT:
530 531
		handles[0] = mb[1];
		handles[1] = mb[2];
L
Linus Torvalds 已提交
532 533 534 535
		handle_cnt = 2;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_3_16BIT:
536 537 538
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
539 540 541 542
		handle_cnt = 3;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_4_16BIT:
543 544 545
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
546 547 548 549 550
		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
		handle_cnt = 4;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_5_16BIT:
551 552 553
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
554 555 556 557 558 559
		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
		handle_cnt = 5;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_2_32BIT:
560
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
561 562 563 564 565 566 567 568 569
		handles[1] = le32_to_cpu(
		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
		    RD_MAILBOX_REG(ha, reg, 6));
		handle_cnt = 2;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	default:
		break;
	}
570
skip_rio:
L
Linus Torvalds 已提交
571 572
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:	/* Fast Post */
573
		if (!vha->flags.online)
L
Linus Torvalds 已提交
574 575 576
			break;

		for (cnt = 0; cnt < handle_cnt; cnt++)
577 578
			qla2x00_process_completed_request(vha, rsp->req,
				handles[cnt]);
L
Linus Torvalds 已提交
579 580 581
		break;

	case MBA_RESET:			/* Reset */
582 583
		ql_dbg(ql_dbg_async, vha, 0x5002,
		    "Asynchronous RESET.\n");
L
Linus Torvalds 已提交
584

585
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
586 587 588
		break;

	case MBA_SYSTEM_ERR:		/* System Error */
589 590
		mbx = (IS_QLA81XX(ha) || IS_QLA83XX(ha)) ?
			RD_REG_WORD(&reg24->mailbox7) : 0;
591
		ql_log(ql_log_warn, vha, 0x5003,
592 593
		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
		    "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
L
Linus Torvalds 已提交
594

595
		ha->isp_ops->fw_dump(vha, 1);
L
Linus Torvalds 已提交
596

597
		if (IS_FWI2_CAPABLE(ha)) {
598
			if (mb[1] == 0 && mb[2] == 0) {
599
				ql_log(ql_log_fatal, vha, 0x5004,
600 601
				    "Unrecoverable Hardware Error: adapter "
				    "marked OFFLINE!\n");
602
				vha->flags.online = 0;
603
				vha->device_flags |= DFLG_DEV_FAILED;
604
			} else {
L
Lucas De Marchi 已提交
605
				/* Check to see if MPI timeout occurred */
606 607 608 609
				if ((mbx & MBX_3) && (ha->flags.port0))
					set_bit(MPI_RESET_NEEDED,
					    &vha->dpc_flags);

610
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
611
			}
612
		} else if (mb[1] == 0) {
613
			ql_log(ql_log_fatal, vha, 0x5005,
L
Linus Torvalds 已提交
614 615
			    "Unrecoverable Hardware Error: adapter marked "
			    "OFFLINE!\n");
616
			vha->flags.online = 0;
617
			vha->device_flags |= DFLG_DEV_FAILED;
L
Linus Torvalds 已提交
618
		} else
619
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
620 621 622
		break;

	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
623 624
		ql_log(ql_log_warn, vha, 0x5006,
		    "ISP Request Transfer Error (%x).\n",  mb[1]);
L
Linus Torvalds 已提交
625

626
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
627 628 629
		break;

	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
630 631
		ql_log(ql_log_warn, vha, 0x5007,
		    "ISP Response Transfer Error.\n");
L
Linus Torvalds 已提交
632

633
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
634 635 636
		break;

	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
637 638
		ql_dbg(ql_dbg_async, vha, 0x5008,
		    "Asynchronous WAKEUP_THRES.\n");
L
Linus Torvalds 已提交
639

640
		break;
L
Linus Torvalds 已提交
641
	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
642
		ql_dbg(ql_dbg_async, vha, 0x5009,
643
		    "LIP occurred (%x).\n", mb[1]);
L
Linus Torvalds 已提交
644

645 646 647 648
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
649 650
		}

651 652 653
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
654 655
		}

656 657
		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
658

659 660
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
L
Linus Torvalds 已提交
661 662 663
		break;

	case MBA_LOOP_UP:		/* Loop Up Event */
664
		if (IS_QLA2100(ha) || IS_QLA2200(ha))
665
			ha->link_data_rate = PORT_SPEED_1GB;
666
		else
L
Linus Torvalds 已提交
667 668
			ha->link_data_rate = mb[1];

669
		ql_dbg(ql_dbg_async, vha, 0x500a,
670 671
		    "LOOP UP detected (%s Gbps).\n",
		    qla2x00_get_link_speed_str(ha));
L
Linus Torvalds 已提交
672

673 674
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
L
Linus Torvalds 已提交
675 676 677
		break;

	case MBA_LOOP_DOWN:		/* Loop Down Event */
678 679
		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
			? RD_REG_WORD(&reg24->mailbox4) : 0;
680
		mbx = IS_QLA82XX(ha) ? RD_REG_WORD(&reg82->mailbox_out[4]) : mbx;
681
		ql_dbg(ql_dbg_async, vha, 0x500b,
682 683
		    "LOOP DOWN detected (%x %x %x %x).\n",
		    mb[1], mb[2], mb[3], mbx);
L
Linus Torvalds 已提交
684

685 686 687 688 689
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
			vha->device_flags |= DFLG_NO_CABLE;
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
690 691
		}

692 693 694
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
695 696
		}

697
		vha->flags.management_server_logged_in = 0;
698
		ha->link_data_rate = PORT_SPEED_UNKNOWN;
699
		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
L
Linus Torvalds 已提交
700 701 702
		break;

	case MBA_LIP_RESET:		/* LIP reset occurred */
703
		ql_dbg(ql_dbg_async, vha, 0x500c,
704
		    "LIP reset occurred (%x).\n", mb[1]);
L
Linus Torvalds 已提交
705

706 707 708 709
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
710 711
		}

712 713 714
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
715 716
		}

717
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
718 719

		ha->operating_mode = LOOP;
720 721
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
L
Linus Torvalds 已提交
722 723
		break;

724
	/* case MBA_DCBX_COMPLETE: */
L
Linus Torvalds 已提交
725 726 727 728
	case MBA_POINT_TO_POINT:	/* Point-to-Point */
		if (IS_QLA2100(ha))
			break;

729
		if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA8031(ha)) {
730 731 732
			ql_dbg(ql_dbg_async, vha, 0x500d,
			    "DCBX Completed -- %04x %04x %04x.\n",
			    mb[1], mb[2], mb[3]);
733 734 735 736
			if (ha->notify_dcbx_comp)
				complete(&ha->dcbx_comp);

		} else
737 738
			ql_dbg(ql_dbg_async, vha, 0x500e,
			    "Asynchronous P2P MODE received.\n");
L
Linus Torvalds 已提交
739 740 741 742 743

		/*
		 * Until there's a transition from loop down to loop up, treat
		 * this as loop down only.
		 */
744 745 746 747
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			if (!atomic_read(&vha->loop_down_timer))
				atomic_set(&vha->loop_down_timer,
L
Linus Torvalds 已提交
748
				    LOOP_DOWN_TIME);
749
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
750 751
		}

752 753 754
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
755 756
		}

757 758 759 760 761
		if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)))
			set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);

		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
762 763

		ha->flags.gpsc_supported = 1;
764
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
765 766 767 768 769 770
		break;

	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
		if (IS_QLA2100(ha))
			break;

771
		ql_dbg(ql_dbg_async, vha, 0x500f,
L
Linus Torvalds 已提交
772 773
		    "Configuration change detected: value=%x.\n", mb[1]);

774 775 776 777
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			if (!atomic_read(&vha->loop_down_timer))
				atomic_set(&vha->loop_down_timer,
L
Linus Torvalds 已提交
778
				    LOOP_DOWN_TIME);
779
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
780 781
		}

782 783 784
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
785 786
		}

787 788
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
789 790 791
		break;

	case MBA_PORT_UPDATE:		/* Port database update */
792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
		/*
		 * Handle only global and vn-port update events
		 *
		 * Relevant inputs:
		 * mb[1] = N_Port handle of changed port
		 * OR 0xffff for global event
		 * mb[2] = New login state
		 * 7 = Port logged out
		 * mb[3] = LSB is vp_idx, 0xff = all vps
		 *
		 * Skip processing if:
		 *       Event is global, vp_idx is NOT all vps,
		 *           vp_idx does not match
		 *       Event is not global, vp_idx does not match
		 */
807 808 809 810
		if (IS_QLA2XXX_MIDTYPE(ha) &&
		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
			break;
811

812 813
		/* Global event -- port logout or port unavailable. */
		if (mb[1] == 0xffff && mb[2] == 0x7) {
814 815 816
			ql_dbg(ql_dbg_async, vha, 0x5010,
			    "Port unavailable %04x %04x %04x.\n",
			    mb[1], mb[2], mb[3]);
817 818
			ql_log(ql_log_warn, vha, 0x505e,
			    "Link is offline.\n");
819 820 821 822 823 824 825 826 827 828 829 830 831

			if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
				atomic_set(&vha->loop_state, LOOP_DOWN);
				atomic_set(&vha->loop_down_timer,
				    LOOP_DOWN_TIME);
				vha->device_flags |= DFLG_NO_CABLE;
				qla2x00_mark_all_devices_lost(vha, 1);
			}

			if (vha->vp_idx) {
				atomic_set(&vha->vp_state, VP_FAILED);
				fc_vport_set_state(vha->fc_vport,
				    FC_VPORT_FAILED);
832
				qla2x00_mark_all_devices_lost(vha, 1);
833 834 835 836 837 838 839
			}

			vha->flags.management_server_logged_in = 0;
			ha->link_data_rate = PORT_SPEED_UNKNOWN;
			break;
		}

L
Linus Torvalds 已提交
840
		/*
841
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
L
Linus Torvalds 已提交
842 843 844
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
845
		atomic_set(&vha->loop_down_timer, 0);
846
		if (mb[1] != 0xffff || (mb[2] != 0x6 && mb[2] != 0x4)) {
847 848 849
			ql_dbg(ql_dbg_async, vha, 0x5011,
			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
			    mb[1], mb[2], mb[3]);
850 851

			qlt_async_event(mb[0], vha, mb);
L
Linus Torvalds 已提交
852 853 854
			break;
		}

855 856 857
		ql_dbg(ql_dbg_async, vha, 0x5012,
		    "Port database changed %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
858 859 860
		ql_log(ql_log_warn, vha, 0x505f,
		    "Link is operational (%s Gbps).\n",
		    qla2x00_get_link_speed_str(ha));
L
Linus Torvalds 已提交
861 862 863 864

		/*
		 * Mark all devices as missing so we will login again.
		 */
865
		atomic_set(&vha->loop_state, LOOP_UP);
L
Linus Torvalds 已提交
866

867
		qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
868

869 870 871
		if (vha->vp_idx == 0 && !qla_ini_mode_enabled(vha))
			set_bit(SCR_PENDING, &vha->dpc_flags);

872 873
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
874 875

		qlt_async_event(mb[0], vha, mb);
L
Linus Torvalds 已提交
876 877 878
		break;

	case MBA_RSCN_UPDATE:		/* State Change Registration */
879
		/* Check if the Vport has issued a SCR */
880
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
881 882
			break;
		/* Only handle SCNs for our Vport index. */
883
		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
884
			break;
885

886 887 888
		ql_dbg(ql_dbg_async, vha, 0x5013,
		    "RSCN database changed -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
L
Linus Torvalds 已提交
889

890
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
891 892
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
L
Linus Torvalds 已提交
893
		if (rscn_entry == host_pid) {
894 895 896
			ql_dbg(ql_dbg_async, vha, 0x5014,
			    "Ignoring RSCN update to local host "
			    "port ID (%06x).\n", host_pid);
L
Linus Torvalds 已提交
897 898 899
			break;
		}

900 901
		/* Ignore reserved bits from RSCN-payload. */
		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
L
Linus Torvalds 已提交
902

903 904
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
905

906 907 908
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(RSCN_UPDATE, &vha->dpc_flags);
		qla2x00_post_aen_work(vha, FCH_EVT_RSCN, rscn_entry);
L
Linus Torvalds 已提交
909 910 911 912
		break;

	/* case MBA_RIO_RESPONSE: */
	case MBA_ZIO_RESPONSE:
913 914
		ql_dbg(ql_dbg_async, vha, 0x5015,
		    "[R|Z]IO update completion.\n");
L
Linus Torvalds 已提交
915

916
		if (IS_FWI2_CAPABLE(ha))
917
			qla24xx_process_response_queue(vha, rsp);
918
		else
919
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
920
		break;
921 922

	case MBA_DISCARD_RND_FRAME:
923 924 925
		ql_dbg(ql_dbg_async, vha, 0x5016,
		    "Discard RND Frame -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
926
		break;
927 928

	case MBA_TRACE_NOTIFICATION:
929 930
		ql_dbg(ql_dbg_async, vha, 0x5017,
		    "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
931
		break;
932 933

	case MBA_ISP84XX_ALERT:
934 935 936
		ql_dbg(ql_dbg_async, vha, 0x5018,
		    "ISP84XX Alert Notification -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
937 938 939 940

		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
		switch (mb[1]) {
		case A84_PANIC_RECOVERY:
941 942 943
			ql_log(ql_log_info, vha, 0x5019,
			    "Alert 84XX: panic recovery %04x %04x.\n",
			    mb[2], mb[3]);
944 945 946
			break;
		case A84_OP_LOGIN_COMPLETE:
			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
947 948 949
			ql_log(ql_log_info, vha, 0x501a,
			    "Alert 84XX: firmware version %x.\n",
			    ha->cs84xx->op_fw_version);
950 951 952
			break;
		case A84_DIAG_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
953 954 955
			ql_log(ql_log_info, vha, 0x501b,
			    "Alert 84XX: diagnostic firmware version %x.\n",
			    ha->cs84xx->diag_fw_version);
956 957 958 959
			break;
		case A84_GOLD_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
			ha->cs84xx->fw_update = 1;
960 961 962
			ql_log(ql_log_info, vha, 0x501c,
			    "Alert 84XX: gold firmware version %x.\n",
			    ha->cs84xx->gold_fw_version);
963 964
			break;
		default:
965 966
			ql_log(ql_log_warn, vha, 0x501d,
			    "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
967 968 969 970
			    mb[1], mb[2], mb[3]);
		}
		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
		break;
971
	case MBA_DCBX_START:
972 973 974
		ql_dbg(ql_dbg_async, vha, 0x501e,
		    "DCBX Started -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
975 976
		break;
	case MBA_DCBX_PARAM_UPDATE:
977 978 979
		ql_dbg(ql_dbg_async, vha, 0x501f,
		    "DCBX Parameters Updated -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
980 981
		break;
	case MBA_FCF_CONF_ERR:
982 983 984
		ql_dbg(ql_dbg_async, vha, 0x5020,
		    "FCF Configuration Error -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
985 986
		break;
	case MBA_IDC_NOTIFY:
987 988 989 990 991 992 993 994 995 996
		/* See if we need to quiesce any I/O */
		if (IS_QLA8031(vha->hw))
			if ((mb[2] & 0x7fff) == MBC_PORT_RESET ||
			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) {
				set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
				/* Ack that we have quiesced I/O */
				qla81xx_idc_event(vha, mb[0], mb[1]);
				qla2xxx_wake_dpc(vha);
			}
	case MBA_IDC_COMPLETE:
997
	case MBA_IDC_TIME_EXT:
998 999 1000 1001 1002 1003 1004 1005 1006 1007
		if (IS_QLA81XX(vha->hw))
			qla81xx_idc_event(vha, mb[0], mb[1]);
		break;

	case MBA_IDC_AEN:
		mb[4] = RD_REG_WORD(&reg24->mailbox4);
		mb[5] = RD_REG_WORD(&reg24->mailbox5);
		mb[6] = RD_REG_WORD(&reg24->mailbox6);
		mb[7] = RD_REG_WORD(&reg24->mailbox7);
		qla83xx_handle_8200_aen(vha, mb);
1008
		break;
1009

1010 1011 1012 1013
	default:
		ql_dbg(ql_dbg_async, vha, 0x5057,
		    "Unknown AEN:%04x %04x %04x %04x\n",
		    mb[0], mb[1], mb[2], mb[3]);
L
Linus Torvalds 已提交
1014
	}
1015

1016 1017
	qlt_async_event(mb[0], vha, mb);

1018
	if (!vha->vp_idx && ha->num_vhosts)
1019
		qla2x00_alert_all_vps(rsp, mb);
L
Linus Torvalds 已提交
1020 1021 1022 1023 1024 1025 1026 1027
}

/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
static void
1028 1029
qla2x00_process_completed_request(struct scsi_qla_host *vha,
				struct req_que *req, uint32_t index)
L
Linus Torvalds 已提交
1030 1031
{
	srb_t *sp;
1032
	struct qla_hw_data *ha = vha->hw;
L
Linus Torvalds 已提交
1033 1034 1035

	/* Validate handle. */
	if (index >= MAX_OUTSTANDING_COMMANDS) {
1036 1037
		ql_log(ql_log_warn, vha, 0x3014,
		    "Invalid SCSI command index (%x).\n", index);
L
Linus Torvalds 已提交
1038

1039 1040 1041 1042
		if (IS_QLA82XX(ha))
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
1043 1044 1045
		return;
	}

1046
	sp = req->outstanding_cmds[index];
L
Linus Torvalds 已提交
1047 1048
	if (sp) {
		/* Free outstanding command slot. */
1049
		req->outstanding_cmds[index] = NULL;
L
Linus Torvalds 已提交
1050 1051

		/* Save ISP completion status */
1052
		sp->done(ha, sp, DID_OK << 16);
L
Linus Torvalds 已提交
1053
	} else {
1054
		ql_log(ql_log_warn, vha, 0x3016, "Invalid SCSI SRB.\n");
L
Linus Torvalds 已提交
1055

1056 1057 1058 1059
		if (IS_QLA82XX(ha))
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
1060 1061 1062
	}
}

1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073
static srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
    struct req_que *req, void *iocb)
{
	struct qla_hw_data *ha = vha->hw;
	sts_entry_t *pkt = iocb;
	srb_t *sp = NULL;
	uint16_t index;

	index = LSW(pkt->handle);
	if (index >= MAX_OUTSTANDING_COMMANDS) {
1074 1075
		ql_log(ql_log_warn, vha, 0x5031,
		    "Invalid command index (%x).\n", index);
1076 1077 1078 1079
		if (IS_QLA82XX(ha))
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1080 1081 1082 1083
		goto done;
	}
	sp = req->outstanding_cmds[index];
	if (!sp) {
1084 1085
		ql_log(ql_log_warn, vha, 0x5032,
		    "Invalid completion handle (%x) -- timed-out.\n", index);
1086 1087 1088
		return sp;
	}
	if (sp->handle != index) {
1089 1090
		ql_log(ql_log_warn, vha, 0x5033,
		    "SRB handle (%x) mismatch %x.\n", sp->handle, index);
1091 1092
		return NULL;
	}
1093

1094
	req->outstanding_cmds[index] = NULL;
1095

1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
done:
	return sp;
}

static void
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct mbx_entry *mbx)
{
	const char func[] = "MBX-IOCB";
	const char *type;
	fc_port_t *fcport;
	srb_t *sp;
1108
	struct srb_iocb *lio;
1109
	uint16_t *data;
1110
	uint16_t status;
1111 1112 1113 1114 1115

	sp = qla2x00_get_sp_from_handle(vha, func, req, mbx);
	if (!sp)
		return;

1116 1117
	lio = &sp->u.iocb_cmd;
	type = sp->name;
1118
	fcport = sp->fcport;
1119
	data = lio->u.logio.data;
1120

1121
	data[0] = MBS_COMMAND_ERROR;
1122
	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
1123
	    QLA_LOGIO_LOGIN_RETRIED : 0;
1124
	if (mbx->entry_status) {
1125
		ql_dbg(ql_dbg_async, vha, 0x5043,
1126
		    "Async-%s error entry - hdl=%x portid=%02x%02x%02x "
1127
		    "entry-status=%x status=%x state-flag=%x "
1128 1129
		    "status-flags=%x.\n", type, sp->handle,
		    fcport->d_id.b.domain, fcport->d_id.b.area,
1130 1131
		    fcport->d_id.b.al_pa, mbx->entry_status,
		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
1132
		    le16_to_cpu(mbx->status_flags));
1133

1134
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
1135
		    (uint8_t *)mbx, sizeof(*mbx));
1136

1137
		goto logio_done;
1138 1139
	}

1140
	status = le16_to_cpu(mbx->status);
1141
	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
1142 1143 1144
	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
		status = 0;
	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
1145
		ql_dbg(ql_dbg_async, vha, 0x5045,
1146 1147 1148 1149
		    "Async-%s complete - hdl=%x portid=%02x%02x%02x mbx1=%x.\n",
		    type, sp->handle, fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
		    le16_to_cpu(mbx->mb1));
1150 1151

		data[0] = MBS_COMMAND_COMPLETE;
1152
		if (sp->type == SRB_LOGIN_CMD) {
1153 1154 1155
			fcport->port_type = FCT_TARGET;
			if (le16_to_cpu(mbx->mb1) & BIT_0)
				fcport->port_type = FCT_INITIATOR;
1156
			else if (le16_to_cpu(mbx->mb1) & BIT_1)
1157
				fcport->flags |= FCF_FCP2_DEVICE;
1158
		}
1159
		goto logio_done;
1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
	}

	data[0] = le16_to_cpu(mbx->mb0);
	switch (data[0]) {
	case MBS_PORT_ID_USED:
		data[1] = le16_to_cpu(mbx->mb1);
		break;
	case MBS_LOOP_ID_USED:
		break;
	default:
		data[0] = MBS_COMMAND_ERROR;
		break;
	}

1174
	ql_log(ql_log_warn, vha, 0x5046,
1175 1176 1177 1178
	    "Async-%s failed - hdl=%x portid=%02x%02x%02x status=%x "
	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n", type, sp->handle,
	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
	    status, le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
1179
	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
1180
	    le16_to_cpu(mbx->mb7));
1181

1182
logio_done:
1183
	sp->done(vha, sp, 0);
1184 1185
}

1186 1187 1188 1189 1190 1191 1192 1193 1194
static void
qla2x00_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
    sts_entry_t *pkt, int iocb_type)
{
	const char func[] = "CT_IOCB";
	const char *type;
	srb_t *sp;
	struct fc_bsg_job *bsg_job;
	uint16_t comp_status;
1195
	int res;
1196 1197 1198 1199 1200

	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
	if (!sp)
		return;

1201
	bsg_job = sp->u.bsg_job;
1202

1203
	type = "ct pass-through";
1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214

	comp_status = le16_to_cpu(pkt->comp_status);

	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
	 * fc payload  to the caller
	 */
	bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
	bsg_job->reply_len = sizeof(struct fc_bsg_reply);

	if (comp_status != CS_COMPLETE) {
		if (comp_status == CS_DATA_UNDERRUN) {
1215
			res = DID_OK << 16;
1216 1217 1218
			bsg_job->reply->reply_payload_rcv_len =
			    le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);

1219 1220
			ql_log(ql_log_warn, vha, 0x5048,
			    "CT pass-through-%s error "
1221
			    "comp_status-status=0x%x total_byte = 0x%x.\n",
1222 1223
			    type, comp_status,
			    bsg_job->reply->reply_payload_rcv_len);
1224
		} else {
1225 1226 1227
			ql_log(ql_log_warn, vha, 0x5049,
			    "CT pass-through-%s error "
			    "comp_status-status=0x%x.\n", type, comp_status);
1228
			res = DID_ERROR << 16;
1229 1230
			bsg_job->reply->reply_payload_rcv_len = 0;
		}
1231
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
1232
		    (uint8_t *)pkt, sizeof(*pkt));
1233
	} else {
1234
		res = DID_OK << 16;
1235 1236 1237 1238 1239
		bsg_job->reply->reply_payload_rcv_len =
		    bsg_job->reply_payload.payload_len;
		bsg_job->reply_len = 0;
	}

1240
	sp->done(vha, sp, res);
1241 1242
}

1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
static void
qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct sts_entry_24xx *pkt, int iocb_type)
{
	const char func[] = "ELS_CT_IOCB";
	const char *type;
	srb_t *sp;
	struct fc_bsg_job *bsg_job;
	uint16_t comp_status;
	uint32_t fw_status[3];
	uint8_t* fw_sts_ptr;
1254
	int res;
1255 1256 1257 1258

	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
	if (!sp)
		return;
1259
	bsg_job = sp->u.bsg_job;
1260 1261

	type = NULL;
1262
	switch (sp->type) {
1263 1264 1265 1266 1267 1268 1269 1270
	case SRB_ELS_CMD_RPT:
	case SRB_ELS_CMD_HST:
		type = "els";
		break;
	case SRB_CT_CMD:
		type = "ct pass-through";
		break;
	default:
1271
		ql_dbg(ql_dbg_user, vha, 0x503e,
1272
		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287
		return;
	}

	comp_status = fw_status[0] = le16_to_cpu(pkt->comp_status);
	fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1);
	fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2);

	/* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT
	 * fc payload  to the caller
	 */
	bsg_job->reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
	bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);

	if (comp_status != CS_COMPLETE) {
		if (comp_status == CS_DATA_UNDERRUN) {
1288
			res = DID_OK << 16;
1289
			bsg_job->reply->reply_payload_rcv_len =
1290
			    le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->total_byte_count);
1291

1292
			ql_dbg(ql_dbg_user, vha, 0x503f,
1293
			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
1294
			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
1295
			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
1296 1297
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				pkt)->total_byte_count));
1298 1299 1300 1301
			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
		}
		else {
1302
			ql_dbg(ql_dbg_user, vha, 0x5040,
1303
			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
1304
			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
1305
			    type, sp->handle, comp_status,
1306 1307 1308 1309
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				pkt)->error_subcode_1),
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				    pkt)->error_subcode_2));
1310
			res = DID_ERROR << 16;
1311 1312 1313 1314
			bsg_job->reply->reply_payload_rcv_len = 0;
			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
		}
1315
		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
1316
				(uint8_t *)pkt, sizeof(*pkt));
1317 1318
	}
	else {
1319
		res =  DID_OK << 16;
1320 1321 1322 1323
		bsg_job->reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
		bsg_job->reply_len = 0;
	}

1324
	sp->done(vha, sp, res);
1325 1326
}

1327 1328 1329 1330 1331 1332 1333 1334
static void
qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct logio_entry_24xx *logio)
{
	const char func[] = "LOGIO-IOCB";
	const char *type;
	fc_port_t *fcport;
	srb_t *sp;
1335
	struct srb_iocb *lio;
1336
	uint16_t *data;
1337 1338 1339 1340 1341 1342
	uint32_t iop[2];

	sp = qla2x00_get_sp_from_handle(vha, func, req, logio);
	if (!sp)
		return;

1343 1344
	lio = &sp->u.iocb_cmd;
	type = sp->name;
1345
	fcport = sp->fcport;
1346
	data = lio->u.logio.data;
1347

1348
	data[0] = MBS_COMMAND_ERROR;
1349
	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
1350
		QLA_LOGIO_LOGIN_RETRIED : 0;
1351
	if (logio->entry_status) {
1352
		ql_log(ql_log_warn, fcport->vha, 0x5034,
1353
		    "Async-%s error entry - hdl=%x"
1354
		    "portid=%02x%02x%02x entry-status=%x.\n",
1355 1356 1357 1358
		    type, sp->handle, fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
		    logio->entry_status);
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x504d,
1359
		    (uint8_t *)logio, sizeof(*logio));
1360

1361
		goto logio_done;
1362 1363 1364
	}

	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
1365
		ql_dbg(ql_dbg_async, fcport->vha, 0x5036,
1366 1367 1368
		    "Async-%s complete - hdl=%x portid=%02x%02x%02x "
		    "iop0=%x.\n", type, sp->handle, fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
1369
		    le32_to_cpu(logio->io_parameter[0]));
1370 1371

		data[0] = MBS_COMMAND_COMPLETE;
1372
		if (sp->type != SRB_LOGIN_CMD)
1373
			goto logio_done;
1374 1375 1376 1377 1378

		iop[0] = le32_to_cpu(logio->io_parameter[0]);
		if (iop[0] & BIT_4) {
			fcport->port_type = FCT_TARGET;
			if (iop[0] & BIT_8)
1379
				fcport->flags |= FCF_FCP2_DEVICE;
1380
		} else if (iop[0] & BIT_5)
1381
			fcport->port_type = FCT_INITIATOR;
1382

1383 1384 1385
		if (iop[0] & BIT_7)
			fcport->flags |= FCF_CONF_COMP_SUPPORTED;

1386 1387 1388 1389 1390
		if (logio->io_parameter[7] || logio->io_parameter[8])
			fcport->supported_classes |= FC_COS_CLASS2;
		if (logio->io_parameter[9] || logio->io_parameter[10])
			fcport->supported_classes |= FC_COS_CLASS3;

1391
		goto logio_done;
1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408
	}

	iop[0] = le32_to_cpu(logio->io_parameter[0]);
	iop[1] = le32_to_cpu(logio->io_parameter[1]);
	switch (iop[0]) {
	case LSC_SCODE_PORTID_USED:
		data[0] = MBS_PORT_ID_USED;
		data[1] = LSW(iop[1]);
		break;
	case LSC_SCODE_NPORT_USED:
		data[0] = MBS_LOOP_ID_USED;
		break;
	default:
		data[0] = MBS_COMMAND_ERROR;
		break;
	}

1409
	ql_dbg(ql_dbg_async, fcport->vha, 0x5037,
1410 1411
	    "Async-%s failed - hdl=%x portid=%02x%02x%02x comp=%x "
	    "iop0=%x iop1=%x.\n", type, sp->handle, fcport->d_id.b.domain,
1412
	    fcport->d_id.b.area, fcport->d_id.b.al_pa,
1413 1414
	    le16_to_cpu(logio->comp_status),
	    le32_to_cpu(logio->io_parameter[0]),
1415
	    le32_to_cpu(logio->io_parameter[1]));
1416

1417
logio_done:
1418
	sp->done(vha, sp, 0);
1419 1420
}

1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436
static void
qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct tsk_mgmt_entry *tsk)
{
	const char func[] = "TMF-IOCB";
	const char *type;
	fc_port_t *fcport;
	srb_t *sp;
	struct srb_iocb *iocb;
	struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
	int error = 1;

	sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
	if (!sp)
		return;

1437 1438
	iocb = &sp->u.iocb_cmd;
	type = sp->name;
1439 1440 1441
	fcport = sp->fcport;

	if (sts->entry_status) {
1442
		ql_log(ql_log_warn, fcport->vha, 0x5038,
1443 1444
		    "Async-%s error - hdl=%x entry-status(%x).\n",
		    type, sp->handle, sts->entry_status);
1445
	} else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
1446
		ql_log(ql_log_warn, fcport->vha, 0x5039,
1447 1448
		    "Async-%s error - hdl=%x completion status(%x).\n",
		    type, sp->handle, sts->comp_status);
1449 1450
	} else if (!(le16_to_cpu(sts->scsi_status) &
	    SS_RESPONSE_INFO_LEN_VALID)) {
1451
		ql_log(ql_log_warn, fcport->vha, 0x503a,
1452 1453
		    "Async-%s error - hdl=%x no response info(%x).\n",
		    type, sp->handle, sts->scsi_status);
1454
	} else if (le32_to_cpu(sts->rsp_data_len) < 4) {
1455
		ql_log(ql_log_warn, fcport->vha, 0x503b,
1456 1457
		    "Async-%s error - hdl=%x not enough response(%d).\n",
		    type, sp->handle, sts->rsp_data_len);
1458
	} else if (sts->data[3]) {
1459
		ql_log(ql_log_warn, fcport->vha, 0x503c,
1460 1461
		    "Async-%s error - hdl=%x response(%x).\n",
		    type, sp->handle, sts->data[3]);
1462 1463 1464 1465 1466 1467
	} else {
		error = 0;
	}

	if (error) {
		iocb->u.tmf.data = error;
1468 1469
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
		    (uint8_t *)sts, sizeof(*sts));
1470 1471
	}

1472
	sp->done(vha, sp, 0);
1473 1474
}

L
Linus Torvalds 已提交
1475 1476 1477 1478 1479
/**
 * qla2x00_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
1480
qla2x00_process_response_queue(struct rsp_que *rsp)
L
Linus Torvalds 已提交
1481
{
1482 1483
	struct scsi_qla_host *vha;
	struct qla_hw_data *ha = rsp->hw;
1484
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
1485 1486 1487
	sts_entry_t	*pkt;
	uint16_t        handle_cnt;
	uint16_t        cnt;
1488

1489
	vha = pci_get_drvdata(ha->pdev);
L
Linus Torvalds 已提交
1490

1491
	if (!vha->flags.online)
L
Linus Torvalds 已提交
1492 1493
		return;

1494 1495
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (sts_entry_t *)rsp->ring_ptr;
L
Linus Torvalds 已提交
1496

1497 1498 1499 1500
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
L
Linus Torvalds 已提交
1501
		} else {
1502
			rsp->ring_ptr++;
L
Linus Torvalds 已提交
1503 1504 1505
		}

		if (pkt->entry_status != 0) {
1506
			qla2x00_error_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
1507 1508 1509 1510 1511 1512 1513
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
1514
			qla2x00_status_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
1515 1516 1517 1518
			break;
		case STATUS_TYPE_21:
			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
1519
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
1520 1521 1522 1523 1524 1525
				    ((sts21_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_TYPE_22:
			handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
1526
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
1527 1528 1529 1530
				    ((sts22_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_CONT_TYPE:
1531
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
L
Linus Torvalds 已提交
1532
			break;
1533 1534 1535
		case MBX_IOCB_TYPE:
			qla2x00_mbx_iocb_entry(vha, rsp->req,
			    (struct mbx_entry *)pkt);
1536
			break;
1537 1538 1539
		case CT_IOCB_TYPE:
			qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			break;
L
Linus Torvalds 已提交
1540 1541
		default:
			/* Type Not Supported. */
1542 1543
			ql_log(ql_log_warn, vha, 0x504a,
			    "Received unknown response pkt type %x "
L
Linus Torvalds 已提交
1544
			    "entry status=%x.\n",
1545
			    pkt->entry_type, pkt->entry_status);
L
Linus Torvalds 已提交
1546 1547 1548 1549 1550 1551 1552
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
1553
	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), rsp->ring_index);
L
Linus Torvalds 已提交
1554 1555
}

1556
static inline void
1557
qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
1558
		     uint32_t sense_len, struct rsp_que *rsp, int res)
1559
{
1560
	struct scsi_qla_host *vha = sp->fcport->vha;
1561 1562
	struct scsi_cmnd *cp = GET_CMD_SP(sp);
	uint32_t track_sense_len;
1563 1564 1565 1566

	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
		sense_len = SCSI_SENSE_BUFFERSIZE;

1567 1568 1569 1570 1571
	SET_CMD_SENSE_LEN(sp, sense_len);
	SET_CMD_SENSE_PTR(sp, cp->sense_buffer);
	track_sense_len = sense_len;

	if (sense_len > par_sense_len)
1572
		sense_len = par_sense_len;
1573 1574 1575

	memcpy(cp->sense_buffer, sense_data, sense_len);

1576 1577 1578 1579 1580
	SET_CMD_SENSE_PTR(sp, cp->sense_buffer + sense_len);
	track_sense_len -= sense_len;
	SET_CMD_SENSE_LEN(sp, track_sense_len);

	if (track_sense_len != 0) {
1581
		rsp->status_srb = sp;
1582 1583
		cp->result = res;
	}
1584

1585 1586 1587 1588 1589
	if (sense_len) {
		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
		    "Check condition Sense data, nexus%ld:%d:%d cmd=%p.\n",
		    sp->fcport->vha->host_no, cp->device->id, cp->device->lun,
		    cp);
1590 1591
		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
		    cp->sense_buffer, sense_len);
1592
	}
1593 1594
}

1595 1596
struct scsi_dif_tuple {
	__be16 guard;       /* Checksum */
1597
	__be16 app_tag;         /* APPL identifier */
1598 1599 1600 1601 1602 1603 1604 1605 1606
	__be32 ref_tag;         /* Target LBA or indirect LBA */
};

/*
 * Checks the guard or meta-data for the type of error
 * detected by the HBA. In case of errors, we set the
 * ASC/ASCQ fields in the sense buffer with ILLEGAL_REQUEST
 * to indicate to the kernel that the HBA detected error.
 */
1607
static inline int
1608 1609
qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
{
1610
	struct scsi_qla_host *vha = sp->fcport->vha;
1611
	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
1612 1613
	uint8_t		*ap = &sts24->data[12];
	uint8_t		*ep = &sts24->data[20];
1614 1615 1616 1617
	uint32_t	e_ref_tag, a_ref_tag;
	uint16_t	e_app_tag, a_app_tag;
	uint16_t	e_guard, a_guard;

1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
	/*
	 * swab32 of the "data" field in the beginning of qla2x00_status_entry()
	 * would make guard field appear at offset 2
	 */
	a_guard   = le16_to_cpu(*(uint16_t *)(ap + 2));
	a_app_tag = le16_to_cpu(*(uint16_t *)(ap + 0));
	a_ref_tag = le32_to_cpu(*(uint32_t *)(ap + 4));
	e_guard   = le16_to_cpu(*(uint16_t *)(ep + 2));
	e_app_tag = le16_to_cpu(*(uint16_t *)(ep + 0));
	e_ref_tag = le32_to_cpu(*(uint32_t *)(ep + 4));
1628

1629 1630
	ql_dbg(ql_dbg_io, vha, 0x3023,
	    "iocb(s) %p Returned STATUS.\n", sts24);
1631

1632 1633
	ql_dbg(ql_dbg_io, vha, 0x3024,
	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
1634
	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
1635
	    " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
1636
	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
1637
	    a_app_tag, e_app_tag, a_guard, e_guard);
1638

1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678
	/*
	 * Ignore sector if:
	 * For type     3: ref & app tag is all 'f's
	 * For type 0,1,2: app tag is all 'f's
	 */
	if ((a_app_tag == 0xffff) &&
	    ((scsi_get_prot_type(cmd) != SCSI_PROT_DIF_TYPE3) ||
	     (a_ref_tag == 0xffffffff))) {
		uint32_t blocks_done, resid;
		sector_t lba_s = scsi_get_lba(cmd);

		/* 2TB boundary case covered automatically with this */
		blocks_done = e_ref_tag - (uint32_t)lba_s + 1;

		resid = scsi_bufflen(cmd) - (blocks_done *
		    cmd->device->sector_size);

		scsi_set_resid(cmd, resid);
		cmd->result = DID_OK << 16;

		/* Update protection tag */
		if (scsi_prot_sg_count(cmd)) {
			uint32_t i, j = 0, k = 0, num_ent;
			struct scatterlist *sg;
			struct sd_dif_tuple *spt;

			/* Patch the corresponding protection tags */
			scsi_for_each_prot_sg(cmd, sg,
			    scsi_prot_sg_count(cmd), i) {
				num_ent = sg_dma_len(sg) / 8;
				if (k + num_ent < blocks_done) {
					k += num_ent;
					continue;
				}
				j = blocks_done - k - 1;
				k = blocks_done;
				break;
			}

			if (k != blocks_done) {
1679
				ql_log(ql_log_warn, vha, 0x302f,
1680 1681
				    "unexpected tag values tag:lba=%x:%llx)\n",
				    e_ref_tag, (unsigned long long)lba_s);
1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695
				return 1;
			}

			spt = page_address(sg_page(sg)) + sg->offset;
			spt += j;

			spt->app_tag = 0xffff;
			if (scsi_get_prot_type(cmd) == SCSI_PROT_DIF_TYPE3)
				spt->ref_tag = 0xffffffff;
		}

		return 0;
	}

1696 1697 1698 1699 1700 1701 1702
	/* check guard */
	if (e_guard != a_guard) {
		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
		    0x10, 0x1);
		set_driver_byte(cmd, DRIVER_SENSE);
		set_host_byte(cmd, DID_ABORT);
		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
1703
		return 1;
1704 1705
	}

1706 1707
	/* check ref tag */
	if (e_ref_tag != a_ref_tag) {
1708
		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
1709
		    0x10, 0x3);
1710 1711 1712
		set_driver_byte(cmd, DRIVER_SENSE);
		set_host_byte(cmd, DID_ABORT);
		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
1713
		return 1;
1714 1715
	}

1716 1717
	/* check appl tag */
	if (e_app_tag != a_app_tag) {
1718
		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
1719
		    0x10, 0x2);
1720 1721 1722
		set_driver_byte(cmd, DRIVER_SENSE);
		set_host_byte(cmd, DID_ABORT);
		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
1723
		return 1;
1724
	}
1725

1726
	return 1;
1727 1728
}

1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871
static void
qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt,
				  struct req_que *req, uint32_t index)
{
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
	uint16_t	comp_status;
	uint16_t	scsi_status;
	uint16_t thread_id;
	uint32_t rval = EXT_STATUS_OK;
	struct fc_bsg_job *bsg_job = NULL;
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;

	/* Validate handle. */
	if (index >= MAX_OUTSTANDING_COMMANDS) {
		ql_log(ql_log_warn, vha, 0x70af,
		    "Invalid SCSI completion handle 0x%x.\n", index);
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		return;
	}

	sp = req->outstanding_cmds[index];
	if (sp) {
		/* Free outstanding command slot. */
		req->outstanding_cmds[index] = NULL;
		bsg_job = sp->u.bsg_job;
	} else {
		ql_log(ql_log_warn, vha, 0x70b0,
		    "Req:%d: Invalid ISP SCSI completion handle(0x%x)\n",
		    req->id, index);

		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		return;
	}

	if (IS_FWI2_CAPABLE(ha)) {
		comp_status = le16_to_cpu(sts24->comp_status);
		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
	} else {
		comp_status = le16_to_cpu(sts->comp_status);
		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
	}

	thread_id = bsg_job->request->rqst_data.h_vendor.vendor_cmd[1];
	switch (comp_status) {
	case CS_COMPLETE:
		if (scsi_status == 0) {
			bsg_job->reply->reply_payload_rcv_len =
					bsg_job->reply_payload.payload_len;
			rval = EXT_STATUS_OK;
		}
		goto done;

	case CS_DATA_OVERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b1,
		    "Command completed with date overrun thread_id=%d\n",
		    thread_id);
		rval = EXT_STATUS_DATA_OVERRUN;
		break;

	case CS_DATA_UNDERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b2,
		    "Command completed with date underrun thread_id=%d\n",
		    thread_id);
		rval = EXT_STATUS_DATA_UNDERRUN;
		break;
	case CS_BIDIR_RD_OVERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b3,
		    "Command completed with read data overrun thread_id=%d\n",
		    thread_id);
		rval = EXT_STATUS_DATA_OVERRUN;
		break;

	case CS_BIDIR_RD_WR_OVERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b4,
		    "Command completed with read and write data overrun "
		    "thread_id=%d\n", thread_id);
		rval = EXT_STATUS_DATA_OVERRUN;
		break;

	case CS_BIDIR_RD_OVERRUN_WR_UNDERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b5,
		    "Command completed with read data over and write data "
		    "underrun thread_id=%d\n", thread_id);
		rval = EXT_STATUS_DATA_OVERRUN;
		break;

	case CS_BIDIR_RD_UNDERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b6,
		    "Command completed with read data data underrun "
		    "thread_id=%d\n", thread_id);
		rval = EXT_STATUS_DATA_UNDERRUN;
		break;

	case CS_BIDIR_RD_UNDERRUN_WR_OVERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b7,
		    "Command completed with read data under and write data "
		    "overrun thread_id=%d\n", thread_id);
		rval = EXT_STATUS_DATA_UNDERRUN;
		break;

	case CS_BIDIR_RD_WR_UNDERRUN:
		ql_dbg(ql_dbg_user, vha, 0x70b8,
		    "Command completed with read and write data underrun "
		    "thread_id=%d\n", thread_id);
		rval = EXT_STATUS_DATA_UNDERRUN;
		break;

	case CS_BIDIR_DMA:
		ql_dbg(ql_dbg_user, vha, 0x70b9,
		    "Command completed with data DMA error thread_id=%d\n",
		    thread_id);
		rval = EXT_STATUS_DMA_ERR;
		break;

	case CS_TIMEOUT:
		ql_dbg(ql_dbg_user, vha, 0x70ba,
		    "Command completed with timeout thread_id=%d\n",
		    thread_id);
		rval = EXT_STATUS_TIMEOUT;
		break;
	default:
		ql_dbg(ql_dbg_user, vha, 0x70bb,
		    "Command completed with completion status=0x%x "
		    "thread_id=%d\n", comp_status, thread_id);
		rval = EXT_STATUS_ERR;
		break;
	}
		bsg_job->reply->reply_payload_rcv_len = 0;

done:
	/* Return the vendor specific reply to API */
	bsg_job->reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
	bsg_job->reply_len = sizeof(struct fc_bsg_reply);
	/* Always return DID_OK, bsg will send the vendor specific response
	 * in this case only */
	sp->done(vha, sp, (DID_OK << 6));

}

L
Linus Torvalds 已提交
1872 1873 1874 1875 1876 1877
/**
 * qla2x00_status_entry() - Process a Status IOCB entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
1878
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
L
Linus Torvalds 已提交
1879 1880 1881 1882
{
	srb_t		*sp;
	fc_port_t	*fcport;
	struct scsi_cmnd *cp;
1883 1884
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
L
Linus Torvalds 已提交
1885 1886
	uint16_t	comp_status;
	uint16_t	scsi_status;
1887
	uint16_t	ox_id;
L
Linus Torvalds 已提交
1888 1889
	uint8_t		lscsi_status;
	int32_t		resid;
1890 1891
	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
	    fw_resid_len;
1892
	uint8_t		*rsp_info, *sense_data;
1893
	struct qla_hw_data *ha = vha->hw;
1894 1895 1896
	uint32_t handle;
	uint16_t que;
	struct req_que *req;
1897
	int logit = 1;
1898
	int res = 0;
1899
	uint16_t state_flags = 0;
1900 1901 1902

	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;
1903
	if (IS_FWI2_CAPABLE(ha)) {
1904 1905
		comp_status = le16_to_cpu(sts24->comp_status);
		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
1906
		state_flags = le16_to_cpu(sts24->state_flags);
1907 1908 1909 1910
	} else {
		comp_status = le16_to_cpu(sts->comp_status);
		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
	}
1911 1912 1913
	handle = (uint32_t) LSW(sts->handle);
	que = MSW(sts->handle);
	req = ha->req_q_map[que];
1914

L
Linus Torvalds 已提交
1915
	/* Validate handle. */
1916 1917
	if (handle < MAX_OUTSTANDING_COMMANDS) {
		sp = req->outstanding_cmds[handle];
L
Linus Torvalds 已提交
1918 1919 1920 1921
	} else
		sp = NULL;

	if (sp == NULL) {
1922
		ql_dbg(ql_dbg_io, vha, 0x3017,
1923
		    "Invalid status handle (0x%x).\n", sts->handle);
L
Linus Torvalds 已提交
1924

1925 1926 1927 1928
		if (IS_QLA82XX(ha))
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1929
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1930 1931
		return;
	}
1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945

	if (unlikely((state_flags & BIT_1) && (sp->type == SRB_BIDI_CMD))) {
		qla25xx_process_bidir_status_iocb(vha, pkt, req, handle);
		return;
	}

	/* Fast path completion. */
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
		qla2x00_process_completed_request(vha, req, handle);

		return;
	}

	req->outstanding_cmds[handle] = NULL;
1946
	cp = GET_CMD_SP(sp);
L
Linus Torvalds 已提交
1947
	if (cp == NULL) {
1948
		ql_dbg(ql_dbg_io, vha, 0x3018,
1949 1950
		    "Command already returned (0x%x/%p).\n",
		    sts->handle, sp);
L
Linus Torvalds 已提交
1951 1952 1953 1954

		return;
	}

1955
  	lscsi_status = scsi_status & STATUS_MASK;
L
Linus Torvalds 已提交
1956

1957
	fcport = sp->fcport;
L
Linus Torvalds 已提交
1958

1959
	ox_id = 0;
1960 1961
	sense_len = par_sense_len = rsp_info_len = resid_len =
	    fw_resid_len = 0;
1962
	if (IS_FWI2_CAPABLE(ha)) {
1963 1964 1965 1966 1967 1968 1969 1970
		if (scsi_status & SS_SENSE_LEN_VALID)
			sense_len = le32_to_cpu(sts24->sense_len);
		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
			rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER))
			resid_len = le32_to_cpu(sts24->rsp_residual_count);
		if (comp_status == CS_DATA_UNDERRUN)
			fw_resid_len = le32_to_cpu(sts24->residual_len);
1971 1972 1973
		rsp_info = sts24->data;
		sense_data = sts24->data;
		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
1974
		ox_id = le16_to_cpu(sts24->ox_id);
1975
		par_sense_len = sizeof(sts24->data);
1976
	} else {
1977 1978 1979 1980
		if (scsi_status & SS_SENSE_LEN_VALID)
			sense_len = le16_to_cpu(sts->req_sense_length);
		if (scsi_status & SS_RESPONSE_INFO_LEN_VALID)
			rsp_info_len = le16_to_cpu(sts->rsp_info_len);
1981 1982 1983
		resid_len = le32_to_cpu(sts->residual_length);
		rsp_info = sts->rsp_info;
		sense_data = sts->req_sense_data;
1984
		par_sense_len = sizeof(sts->req_sense_data);
1985 1986
	}

L
Linus Torvalds 已提交
1987 1988
	/* Check for any FCP transport errors. */
	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
1989
		/* Sense data lies beyond any FCP RESPONSE data. */
1990
		if (IS_FWI2_CAPABLE(ha)) {
1991
			sense_data += rsp_info_len;
1992 1993
			par_sense_len -= rsp_info_len;
		}
1994
		if (rsp_info_len > 3 && rsp_info[3]) {
1995
			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
1996 1997
			    "FCP I/O protocol failure (0x%x/0x%x).\n",
			    rsp_info_len, rsp_info[3]);
L
Linus Torvalds 已提交
1998

1999
			res = DID_BUS_BUSY << 16;
2000
			goto out;
L
Linus Torvalds 已提交
2001 2002 2003
		}
	}

2004 2005 2006 2007 2008
	/* Check for overrun. */
	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
	    scsi_status & SS_RESIDUAL_OVER)
		comp_status = CS_DATA_OVERRUN;

L
Linus Torvalds 已提交
2009 2010 2011 2012 2013
	/*
	 * Based on Host and scsi status generate status code for Linux
	 */
	switch (comp_status) {
	case CS_COMPLETE:
2014
	case CS_QUEUE_FULL:
L
Linus Torvalds 已提交
2015
		if (scsi_status == 0) {
2016
			res = DID_OK << 16;
L
Linus Torvalds 已提交
2017 2018 2019
			break;
		}
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
2020
			resid = resid_len;
2021
			scsi_set_resid(cp, resid);
2022 2023

			if (!lscsi_status &&
2024
			    ((unsigned)(scsi_bufflen(cp) - resid) <
2025
			     cp->underflow)) {
2026
				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
2027
				    "Mid-layer underflow "
2028
				    "detected (0x%x of 0x%x bytes).\n",
2029
				    resid, scsi_bufflen(cp));
2030

2031
				res = DID_ERROR << 16;
2032 2033
				break;
			}
L
Linus Torvalds 已提交
2034
		}
2035
		res = DID_OK << 16 | lscsi_status;
L
Linus Torvalds 已提交
2036

2037
		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
2038
			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
2039
			    "QUEUE FULL detected.\n");
2040 2041
			break;
		}
2042
		logit = 0;
L
Linus Torvalds 已提交
2043 2044 2045
		if (lscsi_status != SS_CHECK_CONDITION)
			break;

2046
		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
2047 2048 2049
		if (!(scsi_status & SS_SENSE_LEN_VALID))
			break;

2050
		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
2051
		    rsp, res);
L
Linus Torvalds 已提交
2052 2053 2054
		break;

	case CS_DATA_UNDERRUN:
2055
		/* Use F/W calculated residual length. */
2056 2057 2058 2059
		resid = IS_FWI2_CAPABLE(ha) ? fw_resid_len : resid_len;
		scsi_set_resid(cp, resid);
		if (scsi_status & SS_RESIDUAL_UNDER) {
			if (IS_FWI2_CAPABLE(ha) && fw_resid_len != resid_len) {
2060
				ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
2061 2062 2063
				    "Dropped frame(s) detected "
				    "(0x%x of 0x%x bytes).\n",
				    resid, scsi_bufflen(cp));
2064

2065
				res = DID_ERROR << 16 | lscsi_status;
2066
				goto check_scsi_status;
2067
			}
2068

2069 2070 2071
			if (!lscsi_status &&
			    ((unsigned)(scsi_bufflen(cp) - resid) <
			    cp->underflow)) {
2072
				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
2073
				    "Mid-layer underflow "
2074
				    "detected (0x%x of 0x%x bytes).\n",
2075
				    resid, scsi_bufflen(cp));
2076

2077
				res = DID_ERROR << 16;
2078 2079
				break;
			}
2080 2081 2082 2083 2084 2085 2086
		} else if (lscsi_status != SAM_STAT_TASK_SET_FULL &&
			    lscsi_status != SAM_STAT_BUSY) {
			/*
			 * scsi status of task set and busy are considered to be
			 * task not completed.
			 */

2087
			ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
2088
			    "Dropped frame(s) detected (0x%x "
2089 2090
			    "of 0x%x bytes).\n", resid,
			    scsi_bufflen(cp));
2091

2092
			res = DID_ERROR << 16 | lscsi_status;
2093
			goto check_scsi_status;
2094 2095 2096 2097
		} else {
			ql_dbg(ql_dbg_io, fcport->vha, 0x3030,
			    "scsi_status: 0x%x, lscsi_status: 0x%x\n",
			    scsi_status, lscsi_status);
L
Linus Torvalds 已提交
2098 2099
		}

2100
		res = DID_OK << 16 | lscsi_status;
2101
		logit = 0;
2102

2103
check_scsi_status:
L
Linus Torvalds 已提交
2104
		/*
A
Andrew Vasquez 已提交
2105
		 * Check to see if SCSI Status is non zero. If so report SCSI
L
Linus Torvalds 已提交
2106 2107 2108
		 * Status.
		 */
		if (lscsi_status != 0) {
2109
			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
2110
				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
2111
				    "QUEUE FULL detected.\n");
2112
				logit = 1;
2113 2114
				break;
			}
L
Linus Torvalds 已提交
2115 2116 2117
			if (lscsi_status != SS_CHECK_CONDITION)
				break;

2118
			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
2119 2120 2121
			if (!(scsi_status & SS_SENSE_LEN_VALID))
				break;

2122
			qla2x00_handle_sense(sp, sense_data, par_sense_len,
2123
			    sense_len, rsp, res);
L
Linus Torvalds 已提交
2124 2125 2126 2127 2128 2129 2130 2131
		}
		break;

	case CS_PORT_LOGGED_OUT:
	case CS_PORT_CONFIG_CHG:
	case CS_PORT_BUSY:
	case CS_INCOMPLETE:
	case CS_PORT_UNAVAILABLE:
2132
	case CS_TIMEOUT:
2133 2134
	case CS_RESET:

2135 2136 2137 2138 2139
		/*
		 * We are going to have the fc class block the rport
		 * while we try to recover so instruct the mid layer
		 * to requeue until the class decides how to handle this.
		 */
2140
		res = DID_TRANSPORT_DISRUPTED << 16;
2141 2142 2143 2144 2145 2146 2147 2148 2149

		if (comp_status == CS_TIMEOUT) {
			if (IS_FWI2_CAPABLE(ha))
				break;
			else if ((le16_to_cpu(sts->status_flags) &
			    SF_LOGOUT_SENT) == 0)
				break;
		}

2150
		ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
2151 2152
		    "Port down status: port-state=0x%x.\n",
		    atomic_read(&fcport->state));
2153

2154
		if (atomic_read(&fcport->state) == FCS_ONLINE)
2155
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
2156 2157 2158
		break;

	case CS_ABORTED:
2159
		res = DID_RESET << 16;
L
Linus Torvalds 已提交
2160
		break;
2161 2162

	case CS_DIF_ERROR:
2163
		logit = qla2x00_handle_dif_error(sp, sts24);
2164
		break;
L
Linus Torvalds 已提交
2165
	default:
2166
		res = DID_ERROR << 16;
L
Linus Torvalds 已提交
2167 2168 2169
		break;
	}

2170 2171
out:
	if (logit)
2172
		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
2173
		    "FCP command status: 0x%x-0x%x (0x%x) "
2174 2175
		    "nexus=%ld:%d:%d portid=%02x%02x%02x oxid=0x%x "
		    "cdb=%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x len=0x%x "
2176
		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x.\n",
2177
		    comp_status, scsi_status, res, vha->host_no,
2178 2179 2180 2181 2182
		    cp->device->id, cp->device->lun, fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
		    cp->cmnd[4], cp->cmnd[5], cp->cmnd[6], cp->cmnd[7],
		    cp->cmnd[8], cp->cmnd[9], scsi_bufflen(cp), rsp_info_len,
2183
		    resid_len, fw_resid_len);
2184

2185
	if (rsp->status_srb == NULL)
2186
		sp->done(ha, sp, res);
L
Linus Torvalds 已提交
2187 2188 2189 2190 2191 2192 2193 2194 2195 2196
}

/**
 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 *
 * Extended sense data.
 */
static void
2197
qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
L
Linus Torvalds 已提交
2198
{
2199
	uint8_t	sense_sz = 0;
2200
	struct qla_hw_data *ha = rsp->hw;
2201
	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
2202
	srb_t *sp = rsp->status_srb;
L
Linus Torvalds 已提交
2203
	struct scsi_cmnd *cp;
2204 2205
	uint32_t sense_len;
	uint8_t *sense_ptr;
L
Linus Torvalds 已提交
2206

2207 2208
	if (!sp || !GET_CMD_SENSE_LEN(sp))
		return;
L
Linus Torvalds 已提交
2209

2210 2211
	sense_len = GET_CMD_SENSE_LEN(sp);
	sense_ptr = GET_CMD_SENSE_PTR(sp);
L
Linus Torvalds 已提交
2212

2213 2214 2215 2216
	cp = GET_CMD_SP(sp);
	if (cp == NULL) {
		ql_log(ql_log_warn, vha, 0x3025,
		    "cmd is NULL: already returned to OS (sp=%p).\n", sp);
L
Linus Torvalds 已提交
2217

2218 2219
		rsp->status_srb = NULL;
		return;
L
Linus Torvalds 已提交
2220 2221
	}

2222 2223 2224 2225
	if (sense_len > sizeof(pkt->data))
		sense_sz = sizeof(pkt->data);
	else
		sense_sz = sense_len;
2226

2227 2228 2229 2230 2231 2232
	/* Move sense data. */
	if (IS_FWI2_CAPABLE(ha))
		host_to_fcp_swap(pkt->data, sizeof(pkt->data));
	memcpy(sense_ptr, pkt->data, sense_sz);
	ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302c,
		sense_ptr, sense_sz);
2233

2234 2235
	sense_len -= sense_sz;
	sense_ptr += sense_sz;
2236

2237 2238 2239 2240 2241 2242 2243
	SET_CMD_SENSE_PTR(sp, sense_ptr);
	SET_CMD_SENSE_LEN(sp, sense_len);

	/* Place command on done queue. */
	if (sense_len == 0) {
		rsp->status_srb = NULL;
		sp->done(ha, sp, cp->result);
2244 2245 2246
	}
}

L
Linus Torvalds 已提交
2247 2248 2249 2250 2251 2252
/**
 * qla2x00_error_entry() - Process an error entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
2253
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
L
Linus Torvalds 已提交
2254 2255
{
	srb_t *sp;
2256
	struct qla_hw_data *ha = vha->hw;
2257
	const char func[] = "ERROR-IOCB";
2258
	uint16_t que = MSW(pkt->handle);
2259
	struct req_que *req = NULL;
2260
	int res = DID_ERROR << 16;
2261

2262 2263 2264
	ql_dbg(ql_dbg_async, vha, 0x502a,
	    "type of error status in response: 0x%x\n", pkt->entry_status);

2265 2266 2267 2268 2269
	if (que >= ha->max_req_queues || !ha->req_q_map[que])
		goto fatal;

	req = ha->req_q_map[que];

2270 2271
	if (pkt->entry_status & RF_BUSY)
		res = DID_BUS_BUSY << 16;
L
Linus Torvalds 已提交
2272

2273
	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
2274
	if (sp) {
2275
		sp->done(ha, sp, res);
2276
		return;
L
Linus Torvalds 已提交
2277
	}
2278 2279 2280 2281 2282 2283 2284 2285 2286
fatal:
	ql_log(ql_log_warn, vha, 0x5030,
	    "Error entry - invalid handle/queue.\n");

	if (IS_QLA82XX(ha))
		set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
	else
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
	qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
2287 2288
}

2289 2290 2291 2292 2293 2294
/**
 * qla24xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
2295
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
2296 2297
{
	uint16_t	cnt;
2298
	uint32_t	mboxes;
2299
	uint16_t __iomem *wptr;
2300
	struct qla_hw_data *ha = vha->hw;
2301 2302
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

2303 2304 2305 2306 2307 2308 2309
	/* Read all mbox registers? */
	mboxes = (1 << ha->mbx_count) - 1;
	if (!ha->mcp)
		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERRROR.\n");
	else
		mboxes = ha->mcp->in_mb;

2310 2311 2312
	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
2313
	mboxes >>= 1;
2314 2315 2316
	wptr = (uint16_t __iomem *)&reg->mailbox1;

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
2317 2318 2319 2320
		if (mboxes & BIT_0)
			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);

		mboxes >>= 1;
2321 2322 2323 2324 2325 2326 2327 2328
		wptr++;
	}
}

/**
 * qla24xx_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
2329 2330
void qla24xx_process_response_queue(struct scsi_qla_host *vha,
	struct rsp_que *rsp)
2331 2332
{
	struct sts_entry_24xx *pkt;
2333
	struct qla_hw_data *ha = vha->hw;
2334

2335
	if (!vha->flags.online)
2336 2337
		return;

2338 2339
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
2340

2341 2342 2343 2344
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
2345
		} else {
2346
			rsp->ring_ptr++;
2347 2348 2349
		}

		if (pkt->entry_status != 0) {
2350
			qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
2351 2352 2353

			(void)qlt_24xx_process_response_error(vha, pkt);

2354 2355 2356 2357 2358 2359 2360
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
2361
			qla2x00_status_entry(vha, rsp, pkt);
2362 2363
			break;
		case STATUS_CONT_TYPE:
2364
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
2365
			break;
2366
		case VP_RPT_ID_IOCB_TYPE:
2367
			qla24xx_report_id_acquisition(vha,
2368 2369
			    (struct vp_rpt_id_entry_24xx *)pkt);
			break;
2370 2371 2372 2373
		case LOGINOUT_PORT_IOCB_TYPE:
			qla24xx_logio_entry(vha, rsp->req,
			    (struct logio_entry_24xx *)pkt);
			break;
2374 2375 2376 2377
		case TSK_MGMT_IOCB_TYPE:
			qla24xx_tm_iocb_entry(vha, rsp->req,
			    (struct tsk_mgmt_entry *)pkt);
			break;
2378 2379 2380 2381 2382 2383
                case CT_IOCB_TYPE:
			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			break;
                case ELS_IOCB_TYPE:
			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
			break;
2384 2385 2386 2387 2388 2389 2390 2391
		case ABTS_RECV_24XX:
			/* ensure that the ATIO queue is empty */
			qlt_24xx_process_atio_queue(vha);
		case ABTS_RESP_24XX:
		case CTIO_TYPE7:
		case NOTIFY_ACK_TYPE:
			qlt_response_pkt_all_vps(vha, (response_t *)pkt);
			break;
2392 2393 2394 2395 2396
		case MARKER_TYPE:
			/* Do nothing in this case, this check is to prevent it
			 * from falling into default case
			 */
			break;
2397 2398
		default:
			/* Type Not Supported. */
2399 2400
			ql_dbg(ql_dbg_async, vha, 0x5042,
			    "Received unknown response pkt type %x "
2401
			    "entry status=%x.\n",
2402
			    pkt->entry_type, pkt->entry_status);
2403 2404 2405 2406 2407 2408 2409
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
2410 2411 2412 2413 2414
	if (IS_QLA82XX(ha)) {
		struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
		WRT_REG_DWORD(&reg->rsp_q_out[0], rsp->ring_index);
	} else
		WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
2415 2416
}

2417
static void
2418
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
2419 2420 2421
{
	int rval;
	uint32_t cnt;
2422
	struct qla_hw_data *ha = vha->hw;
2423 2424
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

2425
	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha))
2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456
		return;

	rval = QLA_SUCCESS;
	WRT_REG_DWORD(&reg->iobase_addr, 0x7C00);
	RD_REG_DWORD(&reg->iobase_addr);
	WRT_REG_DWORD(&reg->iobase_window, 0x0001);
	for (cnt = 10000; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt) {
			WRT_REG_DWORD(&reg->iobase_window, 0x0001);
			udelay(10);
		} else
			rval = QLA_FUNCTION_TIMEOUT;
	}
	if (rval == QLA_SUCCESS)
		goto next_test;

	WRT_REG_DWORD(&reg->iobase_window, 0x0003);
	for (cnt = 100; (RD_REG_DWORD(&reg->iobase_window) & BIT_0) == 0 &&
	    rval == QLA_SUCCESS; cnt--) {
		if (cnt) {
			WRT_REG_DWORD(&reg->iobase_window, 0x0003);
			udelay(10);
		} else
			rval = QLA_FUNCTION_TIMEOUT;
	}
	if (rval != QLA_SUCCESS)
		goto done;

next_test:
	if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
2457 2458
		ql_log(ql_log_info, vha, 0x504c,
		    "Additional code -- 0x55AA.\n");
2459 2460 2461 2462 2463 2464

done:
	WRT_REG_DWORD(&reg->iobase_window, 0x0000);
	RD_REG_DWORD(&reg->iobase_window);
}

2465
/**
2466
 * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
2467 2468 2469 2470 2471 2472 2473 2474
 * @irq:
 * @dev_id: SCSI driver HA context
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
2475
qla24xx_intr_handler(int irq, void *dev_id)
2476
{
2477 2478
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
2479 2480 2481 2482 2483
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
2484
	uint16_t	mb[8];
2485
	struct rsp_que *rsp;
2486
	unsigned long	flags;
2487

2488 2489
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2490 2491
		ql_log(ql_log_info, NULL, 0x5059,
		    "%s: NULL response queue pointer.\n", __func__);
2492 2493 2494
		return IRQ_NONE;
	}

2495
	ha = rsp->hw;
2496 2497 2498
	reg = &ha->iobase->isp24;
	status = 0;

2499 2500 2501
	if (unlikely(pci_channel_offline(ha->pdev)))
		return IRQ_HANDLED;

2502
	spin_lock_irqsave(&ha->hardware_lock, flags);
2503
	vha = pci_get_drvdata(ha->pdev);
2504 2505 2506
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
2507
			if (unlikely(pci_channel_offline(ha->pdev)))
2508 2509
				break;

2510 2511
			hccr = RD_REG_DWORD(&reg->hccr);

2512 2513 2514
			ql_log(ql_log_warn, vha, 0x504b,
			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
			    hccr);
2515

2516
			qla2xxx_check_risc_status(vha);
2517

2518 2519
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2520 2521 2522 2523 2524
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
2525 2526 2527 2528
		case INTR_ROM_MB_SUCCESS:
		case INTR_ROM_MB_FAILED:
		case INTR_MB_SUCCESS:
		case INTR_MB_FAILED:
2529
			qla24xx_mbx_completion(vha, MSW(stat));
2530 2531 2532
			status |= MBX_INTERRUPT;

			break;
2533
		case INTR_ASYNC_EVENT:
2534 2535 2536 2537
			mb[0] = MSW(stat);
			mb[1] = RD_REG_WORD(&reg->mailbox1);
			mb[2] = RD_REG_WORD(&reg->mailbox2);
			mb[3] = RD_REG_WORD(&reg->mailbox3);
2538
			qla2x00_async_event(vha, rsp, mb);
2539
			break;
2540 2541
		case INTR_RSP_QUE_UPDATE:
		case INTR_RSP_QUE_UPDATE_83XX:
2542
			qla24xx_process_response_queue(vha, rsp);
2543
			break;
2544
		case INTR_ATIO_QUE_UPDATE:
2545 2546
			qlt_24xx_process_atio_queue(vha);
			break;
2547
		case INTR_ATIO_RSP_QUE_UPDATE:
2548 2549 2550
			qlt_24xx_process_atio_queue(vha);
			qla24xx_process_response_queue(vha, rsp);
			break;
2551
		default:
2552 2553
			ql_dbg(ql_dbg_async, vha, 0x504f,
			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
2554 2555 2556 2557 2558
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
2559
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2560 2561 2562 2563

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
2564
		complete(&ha->mbx_intr_comp);
2565 2566 2567 2568 2569
	}

	return IRQ_HANDLED;
}

2570 2571 2572
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
2573 2574
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
2575
	struct device_reg_24xx __iomem *reg;
2576
	struct scsi_qla_host *vha;
2577
	unsigned long flags;
2578

2579 2580
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2581 2582
		ql_log(ql_log_info, NULL, 0x505a,
		    "%s: NULL response queue pointer.\n", __func__);
2583 2584 2585
		return IRQ_NONE;
	}
	ha = rsp->hw;
2586 2587
	reg = &ha->iobase->isp24;

2588
	spin_lock_irqsave(&ha->hardware_lock, flags);
2589

2590
	vha = pci_get_drvdata(ha->pdev);
2591
	qla24xx_process_response_queue(vha, rsp);
2592
	if (!ha->flags.disable_msix_handshake) {
2593 2594 2595
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
2596
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2597 2598 2599 2600

	return IRQ_HANDLED;
}

2601 2602 2603 2604 2605
static irqreturn_t
qla25xx_msix_rsp_q(int irq, void *dev_id)
{
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
2606
	struct device_reg_24xx __iomem *reg;
2607
	unsigned long flags;
2608 2609 2610

	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2611 2612
		ql_log(ql_log_info, NULL, 0x505b,
		    "%s: NULL response queue pointer.\n", __func__);
2613 2614 2615 2616
		return IRQ_NONE;
	}
	ha = rsp->hw;

2617
	/* Clear the interrupt, if enabled, for this response queue */
2618
	if (!ha->flags.disable_msix_handshake) {
2619
		reg = &ha->iobase->isp24;
2620
		spin_lock_irqsave(&ha->hardware_lock, flags);
2621 2622
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
2623
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
2624
	}
2625 2626 2627 2628 2629
	queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);

	return IRQ_HANDLED;
}

2630 2631 2632
static irqreturn_t
qla24xx_msix_default(int irq, void *dev_id)
{
2633 2634 2635
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
2636 2637 2638 2639
	struct device_reg_24xx __iomem *reg;
	int		status;
	uint32_t	stat;
	uint32_t	hccr;
2640
	uint16_t	mb[8];
2641
	unsigned long flags;
2642

2643 2644
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2645 2646
		ql_log(ql_log_info, NULL, 0x505c,
		    "%s: NULL response queue pointer.\n", __func__);
2647 2648 2649
		return IRQ_NONE;
	}
	ha = rsp->hw;
2650 2651 2652
	reg = &ha->iobase->isp24;
	status = 0;

2653
	spin_lock_irqsave(&ha->hardware_lock, flags);
2654
	vha = pci_get_drvdata(ha->pdev);
2655
	do {
2656 2657
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
2658
			if (unlikely(pci_channel_offline(ha->pdev)))
2659 2660
				break;

2661 2662
			hccr = RD_REG_DWORD(&reg->hccr);

2663 2664 2665
			ql_log(ql_log_info, vha, 0x5050,
			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
			    hccr);
2666

2667
			qla2xxx_check_risc_status(vha);
2668

2669 2670
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2671 2672 2673 2674 2675
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
2676 2677 2678 2679
		case INTR_ROM_MB_SUCCESS:
		case INTR_ROM_MB_FAILED:
		case INTR_MB_SUCCESS:
		case INTR_MB_FAILED:
2680
			qla24xx_mbx_completion(vha, MSW(stat));
2681 2682 2683
			status |= MBX_INTERRUPT;

			break;
2684
		case INTR_ASYNC_EVENT:
2685 2686 2687 2688
			mb[0] = MSW(stat);
			mb[1] = RD_REG_WORD(&reg->mailbox1);
			mb[2] = RD_REG_WORD(&reg->mailbox2);
			mb[3] = RD_REG_WORD(&reg->mailbox3);
2689
			qla2x00_async_event(vha, rsp, mb);
2690
			break;
2691 2692
		case INTR_RSP_QUE_UPDATE:
		case INTR_RSP_QUE_UPDATE_83XX:
2693
			qla24xx_process_response_queue(vha, rsp);
2694
			break;
2695
		case INTR_ATIO_QUE_UPDATE:
2696 2697
			qlt_24xx_process_atio_queue(vha);
			break;
2698
		case INTR_ATIO_RSP_QUE_UPDATE:
2699 2700 2701
			qlt_24xx_process_atio_queue(vha);
			qla24xx_process_response_queue(vha, rsp);
			break;
2702
		default:
2703 2704
			ql_dbg(ql_dbg_async, vha, 0x5051,
			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
2705 2706 2707
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2708
	} while (0);
2709
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2710 2711 2712 2713

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
2714
		complete(&ha->mbx_intr_comp);
2715 2716 2717 2718 2719 2720 2721 2722
	}
	return IRQ_HANDLED;
}

/* Interrupt handling helpers. */

struct qla_init_msix_entry {
	const char *name;
2723
	irq_handler_t handler;
2724 2725
};

2726
static struct qla_init_msix_entry msix_entries[3] = {
2727 2728
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
2729
	{ "qla2xxx (multiq)", qla25xx_msix_rsp_q },
2730 2731
};

2732 2733 2734 2735 2736
static struct qla_init_msix_entry qla82xx_msix_entries[2] = {
	{ "qla2xxx (default)", qla82xx_msix_default },
	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
};

2737
static void
2738
qla24xx_disable_msix(struct qla_hw_data *ha)
2739 2740 2741
{
	int i;
	struct qla_msix_entry *qentry;
2742
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
2743

2744 2745
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
2746
		if (qentry->have_irq)
2747
			free_irq(qentry->vector, qentry->rsp);
2748 2749
	}
	pci_disable_msix(ha->pdev);
2750 2751 2752
	kfree(ha->msix_entries);
	ha->msix_entries = NULL;
	ha->flags.msix_enabled = 0;
2753 2754
	ql_dbg(ql_dbg_init, vha, 0x0042,
	    "Disabled the MSI.\n");
2755 2756 2757
}

static int
2758
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
2759
{
2760
#define MIN_MSIX_COUNT	2
2761
	int i, ret;
2762
	struct msix_entry *entries;
2763
	struct qla_msix_entry *qentry;
2764
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
2765 2766

	entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
2767
			GFP_KERNEL);
2768 2769 2770
	if (!entries) {
		ql_log(ql_log_warn, vha, 0x00bc,
		    "Failed to allocate memory for msix_entry.\n");
2771
		return -ENOMEM;
2772
	}
2773

2774 2775
	for (i = 0; i < ha->msix_count; i++)
		entries[i].entry = i;
2776

2777
	ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
2778
	if (ret) {
2779 2780 2781
		if (ret < MIN_MSIX_COUNT)
			goto msix_failed;

2782 2783 2784 2785
		ql_log(ql_log_warn, vha, 0x00c6,
		    "MSI-X: Failed to enable support "
		    "-- %d/%d\n Retry with %d vectors.\n",
		    ha->msix_count, ret, ret);
2786 2787 2788
		ha->msix_count = ret;
		ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
		if (ret) {
2789
msix_failed:
2790 2791 2792 2793
			ql_log(ql_log_fatal, vha, 0x00c7,
			    "MSI-X: Failed to enable support, "
			    "giving   up -- %d/%d.\n",
			    ha->msix_count, ret);
2794 2795
			goto msix_out;
		}
2796
		ha->max_rsp_queues = ha->msix_count - 1;
2797 2798 2799 2800
	}
	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
				ha->msix_count, GFP_KERNEL);
	if (!ha->msix_entries) {
2801 2802
		ql_log(ql_log_fatal, vha, 0x00c8,
		    "Failed to allocate memory for ha->msix_entries.\n");
2803
		ret = -ENOMEM;
2804 2805 2806 2807
		goto msix_out;
	}
	ha->flags.msix_enabled = 1;

2808 2809 2810 2811
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
		qentry->vector = entries[i].vector;
		qentry->entry = entries[i].entry;
2812
		qentry->have_irq = 0;
2813
		qentry->rsp = NULL;
2814 2815
	}

2816 2817 2818
	/* Enable MSI-X vectors for the base queue */
	for (i = 0; i < 2; i++) {
		qentry = &ha->msix_entries[i];
2819 2820 2821 2822 2823 2824 2825 2826 2827
		if (IS_QLA82XX(ha)) {
			ret = request_irq(qentry->vector,
				qla82xx_msix_entries[i].handler,
				0, qla82xx_msix_entries[i].name, rsp);
		} else {
			ret = request_irq(qentry->vector,
				msix_entries[i].handler,
				0, msix_entries[i].name, rsp);
		}
2828
		if (ret) {
2829 2830 2831
			ql_log(ql_log_fatal, vha, 0x00cb,
			    "MSI-X: unable to register handler -- %x/%d.\n",
			    qentry->vector, ret);
2832 2833 2834 2835 2836 2837 2838
			qla24xx_disable_msix(ha);
			ha->mqenable = 0;
			goto msix_out;
		}
		qentry->have_irq = 1;
		qentry->rsp = rsp;
		rsp->msix = qentry;
2839 2840 2841
	}

	/* Enable MSI-X vector for response queue update for queue 0 */
2842 2843 2844 2845 2846 2847 2848 2849
	if (IS_QLA83XX(ha)) {
		if (ha->msixbase && ha->mqiobase &&
		    (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
			ha->mqenable = 1;
	} else
		if (ha->mqiobase
		    && (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
			ha->mqenable = 1;
2850 2851 2852 2853 2854 2855
	ql_dbg(ql_dbg_multiq, vha, 0xc005,
	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
	ql_dbg(ql_dbg_init, vha, 0x0055,
	    "mqiobase=%p, max_rsp_queues=%d, max_req_queues=%d.\n",
	    ha->mqiobase, ha->max_rsp_queues, ha->max_req_queues);
2856

2857
msix_out:
2858
	kfree(entries);
2859 2860 2861 2862
	return ret;
}

int
2863
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
2864 2865
{
	int ret;
2866
	device_reg_t __iomem *reg = ha->iobase;
2867
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
2868 2869

	/* If possible, enable MSI-X. */
2870 2871
	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
		!IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
2872 2873 2874 2875 2876 2877
		goto skip_msi;

	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
		(ha->pdev->subsystem_device == 0x7040 ||
		ha->pdev->subsystem_device == 0x7041 ||
		ha->pdev->subsystem_device == 0x1705)) {
2878 2879
		ql_log(ql_log_warn, vha, 0x0034,
		    "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
2880
			ha->pdev->subsystem_vendor,
2881
			ha->pdev->subsystem_device);
2882 2883
		goto skip_msi;
	}
2884

2885
	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
2886 2887
		ql_log(ql_log_warn, vha, 0x0035,
		    "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
2888
		    ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
2889 2890 2891
		goto skip_msix;
	}

2892
	ret = qla24xx_enable_msix(ha, rsp);
2893
	if (!ret) {
2894 2895 2896
		ql_dbg(ql_dbg_init, vha, 0x0036,
		    "MSI-X: Enabled (0x%X, 0x%X).\n",
		    ha->chip_revision, ha->fw_attributes);
2897
		goto clear_risc_ints;
2898
	}
2899 2900
	ql_log(ql_log_info, vha, 0x0037,
	    "MSI-X Falling back-to MSI mode -%d.\n", ret);
2901
skip_msix:
2902

2903 2904
	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
	    !IS_QLA8001(ha))
2905 2906 2907 2908
		goto skip_msi;

	ret = pci_enable_msi(ha->pdev);
	if (!ret) {
2909 2910
		ql_dbg(ql_dbg_init, vha, 0x0038,
		    "MSI: Enabled.\n");
2911
		ha->flags.msi_enabled = 1;
2912
	} else
2913 2914
		ql_log(ql_log_warn, vha, 0x0039,
		    "MSI-X; Falling back-to INTa mode -- %d.\n", ret);
2915 2916 2917 2918 2919

	/* Skip INTx on ISP82xx. */
	if (!ha->flags.msi_enabled && IS_QLA82XX(ha))
		return QLA_FUNCTION_FAILED;

2920 2921
skip_msi:

2922
	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
2923 2924
	    ha->flags.msi_enabled ? 0 : IRQF_SHARED,
	    QLA2XXX_DRIVER_NAME, rsp);
2925
	if (ret) {
2926
		ql_log(ql_log_warn, vha, 0x003a,
2927 2928
		    "Failed to reserve interrupt %d already in use.\n",
		    ha->pdev->irq);
2929 2930
		goto fail;
	}
2931

2932 2933
clear_risc_ints:

2934 2935 2936 2937
	/*
	 * FIXME: Noted that 8014s were being dropped during NK testing.
	 * Timing deltas during MSI-X/INTa transitions?
	 */
2938
	if (IS_QLA81XX(ha) || IS_QLA82XX(ha) || IS_QLA83XX(ha))
2939
		goto fail;
2940
	spin_lock_irq(&ha->hardware_lock);
2941 2942 2943 2944 2945 2946 2947
	if (IS_FWI2_CAPABLE(ha)) {
		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
	} else {
		WRT_REG_WORD(&reg->isp.semaphore, 0);
		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
2948
	}
2949
	spin_unlock_irq(&ha->hardware_lock);
2950

2951
fail:
2952 2953 2954 2955
	return ret;
}

void
2956
qla2x00_free_irqs(scsi_qla_host_t *vha)
2957
{
2958
	struct qla_hw_data *ha = vha->hw;
2959 2960 2961 2962 2963 2964 2965 2966 2967
	struct rsp_que *rsp;

	/*
	 * We need to check that ha->rsp_q_map is valid in case we are called
	 * from a probe failure context.
	 */
	if (!ha->rsp_q_map || !ha->rsp_q_map[0])
		return;
	rsp = ha->rsp_q_map[0];
2968 2969 2970

	if (ha->flags.msix_enabled)
		qla24xx_disable_msix(ha);
2971
	else if (ha->flags.msi_enabled) {
2972
		free_irq(ha->pdev->irq, rsp);
2973
		pci_disable_msi(ha->pdev);
2974 2975
	} else
		free_irq(ha->pdev->irq, rsp);
2976
}
2977

2978 2979 2980 2981

int qla25xx_request_irq(struct rsp_que *rsp)
{
	struct qla_hw_data *ha = rsp->hw;
2982
	struct qla_init_msix_entry *intr = &msix_entries[2];
2983
	struct qla_msix_entry *msix = rsp->msix;
2984
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
2985 2986 2987 2988
	int ret;

	ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
	if (ret) {
2989 2990 2991
		ql_log(ql_log_fatal, vha, 0x00e6,
		    "MSI-X: Unable to register handler -- %x/%d.\n",
		    msix->vector, ret);
2992 2993 2994 2995 2996 2997
		return ret;
	}
	msix->have_irq = 1;
	msix->rsp = rsp;
	return ret;
}