qla_isr.c 90.0 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
A
Andrew Vasquez 已提交
2
 * QLogic Fibre Channel HBA Driver
3
 * Copyright (c)  2003-2014 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
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
18
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
19 20
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
	sts_entry_t *);
21 22 23 24
static void qla_irq_affinity_notify(struct irq_affinity_notify *,
    const cpumask_t *);
static void qla_irq_affinity_release(struct kref *);

25

L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35
/**
 * 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
36
qla2100_intr_handler(int irq, void *dev_id)
L
Linus Torvalds 已提交
37
{
38 39
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
40
	struct device_reg_2xxx __iomem *reg;
L
Linus Torvalds 已提交
41 42
	int		status;
	unsigned long	iter;
43
	uint16_t	hccr;
44
	uint16_t	mb[4];
45
	struct rsp_que *rsp;
46
	unsigned long	flags;
L
Linus Torvalds 已提交
47

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

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

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

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

77 78
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
79 80
			break;
		} else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
L
Linus Torvalds 已提交
81 82 83 84 85 86 87
			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. */
88 89
			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
90
				qla2x00_mbx_completion(vha, mb[0]);
L
Linus Torvalds 已提交
91
				status |= MBX_INTERRUPT;
92 93 94 95
			} 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);
96
				qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
97 98
			} else {
				/*EMPTY*/
99 100 101
				ql_dbg(ql_dbg_async, vha, 0x5025,
				    "Unrecognized interrupt type (%d).\n",
				    mb[0]);
L
Linus Torvalds 已提交
102 103 104 105 106
			}
			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			RD_REG_WORD(&reg->semaphore);
		} else {
107
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
108 109 110 111 112

			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
			RD_REG_WORD(&reg->hccr);
		}
	}
113
	qla2x00_handle_mbx_completion(ha, status);
114
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
115 116 117 118

	return (IRQ_HANDLED);
}

119
bool
120
qla2x00_check_reg32_for_disconnect(scsi_qla_host_t *vha, uint32_t reg)
121 122
{
	/* Check for PCI disconnection */
123
	if (reg == 0xffffffff && !pci_channel_offline(vha->hw->pdev)) {
124
		if (!test_and_set_bit(PFLG_DISCONNECTED, &vha->pci_flags) &&
125 126
		    !test_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags) &&
		    !test_bit(PFLG_DRIVER_PROBING, &vha->pci_flags)) {
127 128 129 130 131 132 133
			/*
			 * Schedule this (only once) on the default system
			 * workqueue so that all the adapter workqueues and the
			 * DPC thread can be shutdown cleanly.
			 */
			schedule_work(&vha->hw->board_disable);
		}
134 135 136 137 138
		return true;
	} else
		return false;
}

139 140 141 142 143 144
bool
qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg)
{
	return qla2x00_check_reg32_for_disconnect(vha, 0xffff0000 | reg);
}

L
Linus Torvalds 已提交
145 146 147 148 149 150 151 152 153 154
/**
 * 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
155
qla2300_intr_handler(int irq, void *dev_id)
L
Linus Torvalds 已提交
156
{
157
	scsi_qla_host_t	*vha;
158
	struct device_reg_2xxx __iomem *reg;
L
Linus Torvalds 已提交
159 160 161 162
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint16_t	hccr;
163
	uint16_t	mb[4];
164 165
	struct rsp_que *rsp;
	struct qla_hw_data *ha;
166
	unsigned long	flags;
L
Linus Torvalds 已提交
167

168 169
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
170 171
		ql_log(ql_log_info, NULL, 0x5058,
		    "%s: NULL response queue pointer.\n", __func__);
L
Linus Torvalds 已提交
172 173 174
		return (IRQ_NONE);
	}

175
	ha = rsp->hw;
176
	reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
177 178
	status = 0;

179
	spin_lock_irqsave(&ha->hardware_lock, flags);
180
	vha = pci_get_drvdata(ha->pdev);
L
Linus Torvalds 已提交
181 182
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
183
		if (qla2x00_check_reg32_for_disconnect(vha, stat))
184
			break;
L
Linus Torvalds 已提交
185
		if (stat & HSR_RISC_PAUSED) {
186
			if (unlikely(pci_channel_offline(ha->pdev)))
187 188
				break;

L
Linus Torvalds 已提交
189
			hccr = RD_REG_WORD(&reg->hccr);
190

L
Linus Torvalds 已提交
191
			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
192 193 194
				ql_log(ql_log_warn, vha, 0x5026,
				    "Parity error -- HCCR=%x, Dumping "
				    "firmware.\n", hccr);
L
Linus Torvalds 已提交
195
			else
196 197 198
				ql_log(ql_log_warn, vha, 0x5027,
				    "RISC paused -- HCCR=%x, Dumping "
				    "firmware.\n", hccr);
L
Linus Torvalds 已提交
199 200 201 202

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

208 209
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218
			break;
		} else if ((stat & HSR_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
219
			qla2x00_mbx_completion(vha, MSW(stat));
L
Linus Torvalds 已提交
220 221 222 223 224 225
			status |= MBX_INTERRUPT;

			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			break;
		case 0x12:
226 227 228 229
			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);
230
			qla2x00_async_event(vha, rsp, mb);
231 232
			break;
		case 0x13:
233
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
234 235
			break;
		case 0x15:
236 237
			mb[0] = MBA_CMPLT_1_16BIT;
			mb[1] = MSW(stat);
238
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
239 240
			break;
		case 0x16:
241 242 243
			mb[0] = MBA_SCSI_COMPLETION;
			mb[1] = MSW(stat);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
244
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
245 246
			break;
		default:
247 248
			ql_dbg(ql_dbg_async, vha, 0x5028,
			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
L
Linus Torvalds 已提交
249 250 251 252 253
			break;
		}
		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
		RD_REG_WORD_RELAXED(&reg->hccr);
	}
254
	qla2x00_handle_mbx_completion(ha, status);
255
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
256 257 258 259 260 261 262 263 264 265

	return (IRQ_HANDLED);
}

/**
 * qla2x00_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
266
qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
L
Linus Torvalds 已提交
267 268
{
	uint16_t	cnt;
269
	uint32_t	mboxes;
L
Linus Torvalds 已提交
270
	uint16_t __iomem *wptr;
271
	struct qla_hw_data *ha = vha->hw;
272
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
273

274 275 276
	/* Read all mbox registers? */
	mboxes = (1 << ha->mbx_count) - 1;
	if (!ha->mcp)
277
		ql_dbg(ql_dbg_async, vha, 0x5001, "MBX pointer ERROR.\n");
278 279 280
	else
		mboxes = ha->mcp->in_mb;

L
Linus Torvalds 已提交
281 282 283
	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
284
	mboxes >>= 1;
L
Linus Torvalds 已提交
285 286 287
	wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
A
Andrew Vasquez 已提交
288
		if (IS_QLA2200(ha) && cnt == 8)
L
Linus Torvalds 已提交
289
			wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
290
		if ((cnt == 4 || cnt == 5) && (mboxes & BIT_0))
L
Linus Torvalds 已提交
291
			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
292
		else if (mboxes & BIT_0)
L
Linus Torvalds 已提交
293
			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
A
Andrew Vasquez 已提交
294

L
Linus Torvalds 已提交
295
		wptr++;
296
		mboxes >>= 1;
L
Linus Torvalds 已提交
297 298 299
	}
}

300 301 302 303 304 305 306
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;
307
	struct device_reg_82xx __iomem *reg82 = &vha->hw->iobase->isp82;
308 309 310 311
	uint16_t __iomem *wptr;
	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];

	/* Seed data -- mailbox1 -> mailbox7. */
312 313 314 315 316 317 318
	if (IS_QLA81XX(vha->hw) || IS_QLA83XX(vha->hw))
		wptr = (uint16_t __iomem *)&reg24->mailbox1;
	else if (IS_QLA8044(vha->hw))
		wptr = (uint16_t __iomem *)&reg82->mailbox_out[1];
	else
		return;

319 320 321
	for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
		mb[cnt] = RD_REG_WORD(wptr);

322
	ql_dbg(ql_dbg_async, vha, 0x5021,
323
	    "Inter-Driver Communication %s -- "
324 325 326
	    "%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]);
327 328 329 330 331
	switch (aen) {
	/* Handle IDC Error completion case. */
	case MBA_IDC_COMPLETE:
		if (mb[1] >> 15) {
			vha->hw->flags.idc_compl_status = 1;
332
			if (vha->hw->notify_dcbx_comp && !vha->vp_idx)
333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
				complete(&vha->hw->dcbx_comp);
		}
		break;

	case MBA_IDC_NOTIFY:
		/* Acknowledgement needed? [Notify && non-zero timeout]. */
		timeout = (descr >> 8) & 0xf;
		ql_dbg(ql_dbg_async, vha, 0x5022,
		    "%lu Inter-Driver Communication %s -- ACK timeout=%d.\n",
		    vha->host_no, event[aen & 0xff], timeout);

		if (!timeout)
			return;
		rval = qla2x00_post_idc_ack_work(vha, mb);
		if (rval != QLA_SUCCESS)
			ql_log(ql_log_warn, vha, 0x5023,
			    "IDC failed to post ACK.\n");
		break;
	case MBA_IDC_TIME_EXT:
		vha->hw->idc_extend_tmo = descr;
		ql_dbg(ql_dbg_async, vha, 0x5087,
		    "%lu Inter-Driver Communication %s -- "
		    "Extend timeout by=%d.\n",
		    vha->host_no, event[aen & 0xff], vha->hw->idc_extend_tmo);
		break;
358
	}
359 360
}

361
#define LS_UNKNOWN	2
362 363
const char *
qla2x00_get_link_speed_str(struct qla_hw_data *ha, uint16_t speed)
364
{
365 366
	static const char *const link_speeds[] = {
		"1", "2", "?", "4", "8", "16", "32", "10"
367
	};
368
#define	QLA_LAST_SPEED	7
369 370

	if (IS_QLA2100(ha) || IS_QLA2200(ha))
371 372
		return link_speeds[0];
	else if (speed == 0x13)
373 374
		return link_speeds[QLA_LAST_SPEED];
	else if (speed < QLA_LAST_SPEED)
375 376 377
		return link_speeds[speed];
	else
		return link_speeds[LS_UNKNOWN];
378 379
}

380
static void
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 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
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]);
536 537
		if (ha->flags.nic_core_reset_owner)
			return;
538 539 540 541
		qla83xx_schedule_work(vha, MBA_IDC_AEN);
	}
}

542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
int
qla2x00_is_a_vp_did(scsi_qla_host_t *vha, uint32_t rscn_entry)
{
	struct qla_hw_data *ha = vha->hw;
	scsi_qla_host_t *vp;
	uint32_t vp_did;
	unsigned long flags;
	int ret = 0;

	if (!ha->num_vhosts)
		return ret;

	spin_lock_irqsave(&ha->vport_slock, flags);
	list_for_each_entry(vp, &ha->vp_list, list) {
		vp_did = vp->d_id.b24;
		if (vp_did == rscn_entry) {
			ret = 1;
			break;
		}
	}
	spin_unlock_irqrestore(&ha->vport_slock, flags);

	return ret;
}

567 568 569 570 571 572 573 574 575 576 577
static inline fc_port_t *
qla2x00_find_fcport_by_loopid(scsi_qla_host_t *vha, uint16_t loop_id)
{
	fc_port_t *fcport;

	list_for_each_entry(fcport, &vha->vp_fcports, list)
		if (fcport->loop_id == loop_id)
			return fcport;
	return NULL;
}

L
Linus Torvalds 已提交
578 579 580
/**
 * qla2x00_async_event() - Process aynchronous events.
 * @ha: SCSI driver HA context
581
 * @mb: Mailbox registers (0 - 3)
L
Linus Torvalds 已提交
582
 */
583
void
584
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
L
Linus Torvalds 已提交
585 586
{
	uint16_t	handle_cnt;
587
	uint16_t	cnt, mbx;
L
Linus Torvalds 已提交
588
	uint32_t	handles[5];
589
	struct qla_hw_data *ha = vha->hw;
590
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
591
	struct device_reg_24xx __iomem *reg24 = &ha->iobase->isp24;
592
	struct device_reg_82xx __iomem *reg82 = &ha->iobase->isp82;
593
	uint32_t	rscn_entry, host_pid;
594
	unsigned long	flags;
595
	fc_port_t	*fcport = NULL;
L
Linus Torvalds 已提交
596 597 598

	/* Setup to process RIO completion. */
	handle_cnt = 0;
599
	if (IS_CNA_CAPABLE(ha))
600
		goto skip_rio;
L
Linus Torvalds 已提交
601 602
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:
603
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
604 605 606
		handle_cnt = 1;
		break;
	case MBA_CMPLT_1_16BIT:
607
		handles[0] = mb[1];
L
Linus Torvalds 已提交
608 609 610 611
		handle_cnt = 1;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_2_16BIT:
612 613
		handles[0] = mb[1];
		handles[1] = mb[2];
L
Linus Torvalds 已提交
614 615 616 617
		handle_cnt = 2;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_3_16BIT:
618 619 620
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
621 622 623 624
		handle_cnt = 3;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_4_16BIT:
625 626 627
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
628 629 630 631 632
		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
		handle_cnt = 4;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_5_16BIT:
633 634 635
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
636 637 638 639 640 641
		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:
642
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
643 644 645 646 647 648 649 650 651
		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;
	}
652
skip_rio:
L
Linus Torvalds 已提交
653 654
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:	/* Fast Post */
655
		if (!vha->flags.online)
L
Linus Torvalds 已提交
656 657 658
			break;

		for (cnt = 0; cnt < handle_cnt; cnt++)
659 660
			qla2x00_process_completed_request(vha, rsp->req,
				handles[cnt]);
L
Linus Torvalds 已提交
661 662 663
		break;

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

667
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
668 669 670
		break;

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

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

679
		if (IS_FWI2_CAPABLE(ha)) {
680
			if (mb[1] == 0 && mb[2] == 0) {
681
				ql_log(ql_log_fatal, vha, 0x5004,
682 683
				    "Unrecoverable Hardware Error: adapter "
				    "marked OFFLINE!\n");
684
				vha->flags.online = 0;
685
				vha->device_flags |= DFLG_DEV_FAILED;
686
			} else {
L
Lucas De Marchi 已提交
687
				/* Check to see if MPI timeout occurred */
688
				if ((mbx & MBX_3) && (ha->port_no == 0))
689 690 691
					set_bit(MPI_RESET_NEEDED,
					    &vha->dpc_flags);

692
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
693
			}
694
		} else if (mb[1] == 0) {
695
			ql_log(ql_log_fatal, vha, 0x5005,
L
Linus Torvalds 已提交
696 697
			    "Unrecoverable Hardware Error: adapter marked "
			    "OFFLINE!\n");
698
			vha->flags.online = 0;
699
			vha->device_flags |= DFLG_DEV_FAILED;
L
Linus Torvalds 已提交
700
		} else
701
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
702 703 704
		break;

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

708
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
709 710 711
		break;

	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
712
		ql_log(ql_log_warn, vha, 0x5007,
713
		    "ISP Response Transfer Error (%x).\n", mb[1]);
L
Linus Torvalds 已提交
714

715
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
716 717 718
		break;

	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
719
		ql_dbg(ql_dbg_async, vha, 0x5008,
720 721
		    "Asynchronous WAKEUP_THRES (%x).\n", mb[1]);
		break;
L
Linus Torvalds 已提交
722

723
	case MBA_LOOP_INIT_ERR:
724
		ql_log(ql_log_warn, vha, 0x5090,
725 726 727
		    "LOOP INIT ERROR (%x).\n", mb[1]);
		ha->isp_ops->fw_dump(vha, 1);
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
728
		break;
729

L
Linus Torvalds 已提交
730
	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
731
		ql_dbg(ql_dbg_async, vha, 0x5009,
732
		    "LIP occurred (%x).\n", mb[1]);
L
Linus Torvalds 已提交
733

734 735 736 737
		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 已提交
738 739
		}

740 741 742
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
743 744
		}

745 746
		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
747

748 749
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
L
Linus Torvalds 已提交
750 751 752
		break;

	case MBA_LOOP_UP:		/* Loop Up Event */
753
		if (IS_QLA2100(ha) || IS_QLA2200(ha))
754
			ha->link_data_rate = PORT_SPEED_1GB;
755
		else
L
Linus Torvalds 已提交
756 757
			ha->link_data_rate = mb[1];

758
		ql_log(ql_log_info, vha, 0x500a,
759
		    "LOOP UP detected (%s Gbps).\n",
760
		    qla2x00_get_link_speed_str(ha, ha->link_data_rate));
L
Linus Torvalds 已提交
761

762 763
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
L
Linus Torvalds 已提交
764 765 766
		break;

	case MBA_LOOP_DOWN:		/* Loop Down Event */
767 768
		mbx = (IS_QLA81XX(ha) || IS_QLA8031(ha))
			? RD_REG_WORD(&reg24->mailbox4) : 0;
769 770
		mbx = (IS_P3P_TYPE(ha)) ? RD_REG_WORD(&reg82->mailbox_out[4])
			: mbx;
771
		ql_log(ql_log_info, vha, 0x500b,
772 773
		    "LOOP DOWN detected (%x %x %x %x).\n",
		    mb[1], mb[2], mb[3], mbx);
L
Linus Torvalds 已提交
774

775 776 777
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
778 779 780
			/*
			 * In case of loop down, restore WWPN from
			 * NVRAM in case of FA-WWPN capable ISP
781
			 * Restore for Physical Port only
782
			 */
783 784 785 786 787 788 789 790 791 792 793 794 795
			if (!vha->vp_idx) {
				if (ha->flags.fawwpn_enabled) {
					void *wwpn = ha->init_cb->port_name;
					memcpy(vha->port_name, wwpn, WWN_SIZE);
					fc_host_port_name(vha->host) =
					    wwn_to_u64(vha->port_name);
					ql_dbg(ql_dbg_init + ql_dbg_verbose,
					    vha, 0x0144, "LOOP DOWN detected,"
					    "restore WWPN %016llx\n",
					    wwn_to_u64(vha->port_name));
				}

				clear_bit(VP_CONFIG_OK, &vha->vp_flags);
796 797
			}

798 799
			vha->device_flags |= DFLG_NO_CABLE;
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
800 801
		}

802 803 804
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
805 806
		}

807
		vha->flags.management_server_logged_in = 0;
808
		ha->link_data_rate = PORT_SPEED_UNKNOWN;
809
		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
L
Linus Torvalds 已提交
810 811 812
		break;

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

816 817 818 819
		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 已提交
820 821
		}

822 823 824
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
825 826
		}

827
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
828 829

		ha->operating_mode = LOOP;
830 831
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
L
Linus Torvalds 已提交
832 833
		break;

834
	/* case MBA_DCBX_COMPLETE: */
L
Linus Torvalds 已提交
835 836 837 838
	case MBA_POINT_TO_POINT:	/* Point-to-Point */
		if (IS_QLA2100(ha))
			break;

839
		if (IS_CNA_CAPABLE(ha)) {
840 841 842
			ql_dbg(ql_dbg_async, vha, 0x500d,
			    "DCBX Completed -- %04x %04x %04x.\n",
			    mb[1], mb[2], mb[3]);
843
			if (ha->notify_dcbx_comp && !vha->vp_idx)
844 845 846
				complete(&ha->dcbx_comp);

		} else
847 848
			ql_dbg(ql_dbg_async, vha, 0x500e,
			    "Asynchronous P2P MODE received.\n");
L
Linus Torvalds 已提交
849 850 851 852 853

		/*
		 * Until there's a transition from loop down to loop up, treat
		 * this as loop down only.
		 */
854 855 856 857
		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 已提交
858
				    LOOP_DOWN_TIME);
859
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
860 861
		}

862 863 864
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
865 866
		}

867 868 869 870 871
		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);
872 873

		ha->flags.gpsc_supported = 1;
874
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
875 876 877 878 879 880
		break;

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

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

884 885 886 887
		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 已提交
888
				    LOOP_DOWN_TIME);
889
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
890 891
		}

892 893 894
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
895 896
		}

897 898
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
899 900 901
		break;

	case MBA_PORT_UPDATE:		/* Port database update */
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916
		/*
		 * 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
		 */
917 918 919 920
		if (IS_QLA2XXX_MIDTYPE(ha) &&
		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
			break;
921

922
		if (mb[2] == 0x7) {
923
			ql_dbg(ql_dbg_async, vha, 0x5010,
924 925
			    "Port %s %04x %04x %04x.\n",
			    mb[1] == 0xffff ? "unavailable" : "logout",
926
			    mb[1], mb[2], mb[3]);
927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943

			if (mb[1] == 0xffff)
				goto global_port_update;

			/* Port logout */
			fcport = qla2x00_find_fcport_by_loopid(vha, mb[1]);
			if (!fcport)
				break;
			if (atomic_read(&fcport->state) != FCS_ONLINE)
				break;
			ql_dbg(ql_dbg_async, vha, 0x508a,
			    "Marking port lost loopid=%04x portid=%06x.\n",
			    fcport->loop_id, fcport->d_id.b24);
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
			break;

global_port_update:
944 945 946 947 948 949 950 951 952 953 954 955
			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);
956
				qla2x00_mark_all_devices_lost(vha, 1);
957 958 959 960 961 962 963
			}

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

L
Linus Torvalds 已提交
964
		/*
965
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
L
Linus Torvalds 已提交
966 967 968
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
969
		atomic_set(&vha->loop_down_timer, 0);
970 971
		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
972 973 974
			ql_dbg(ql_dbg_async, vha, 0x5011,
			    "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n",
			    mb[1], mb[2], mb[3]);
975 976

			qlt_async_event(mb[0], vha, mb);
L
Linus Torvalds 已提交
977 978 979
			break;
		}

980 981 982
		ql_dbg(ql_dbg_async, vha, 0x5012,
		    "Port database changed %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
L
Linus Torvalds 已提交
983 984 985 986

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

989
		qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
990

991 992 993
		if (vha->vp_idx == 0 && !qla_ini_mode_enabled(vha))
			set_bit(SCR_PENDING, &vha->dpc_flags);

994 995
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
996
		set_bit(VP_CONFIG_OK, &vha->vp_flags);
997 998

		qlt_async_event(mb[0], vha, mb);
L
Linus Torvalds 已提交
999 1000 1001
		break;

	case MBA_RSCN_UPDATE:		/* State Change Registration */
1002
		/* Check if the Vport has issued a SCR */
1003
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
1004 1005
			break;
		/* Only handle SCNs for our Vport index. */
1006
		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
1007
			break;
1008

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

1013
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
1014 1015
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
L
Linus Torvalds 已提交
1016
		if (rscn_entry == host_pid) {
1017 1018 1019
			ql_dbg(ql_dbg_async, vha, 0x5014,
			    "Ignoring RSCN update to local host "
			    "port ID (%06x).\n", host_pid);
L
Linus Torvalds 已提交
1020 1021 1022
			break;
		}

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

1026 1027 1028 1029
		/* Skip RSCNs for virtual ports on the same physical port */
		if (qla2x00_is_a_vp_did(vha, rscn_entry))
			break;

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
		/*
		 * Search for the rport related to this RSCN entry and mark it
		 * as lost.
		 */
		list_for_each_entry(fcport, &vha->vp_fcports, list) {
			if (atomic_read(&fcport->state) != FCS_ONLINE)
				continue;
			if (fcport->d_id.b24 == rscn_entry) {
				qla2x00_mark_device_lost(vha, fcport, 0, 0);
				break;
			}
		}

1043 1044
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
1045

1046 1047 1048
		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 已提交
1049 1050 1051 1052
		break;

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

1056
		if (IS_FWI2_CAPABLE(ha))
1057
			qla24xx_process_response_queue(vha, rsp);
1058
		else
1059
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
1060
		break;
1061 1062

	case MBA_DISCARD_RND_FRAME:
1063 1064 1065
		ql_dbg(ql_dbg_async, vha, 0x5016,
		    "Discard RND Frame -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
1066
		break;
1067 1068

	case MBA_TRACE_NOTIFICATION:
1069 1070
		ql_dbg(ql_dbg_async, vha, 0x5017,
		    "Trace Notification -- %04x %04x.\n", mb[1], mb[2]);
1071
		break;
1072 1073

	case MBA_ISP84XX_ALERT:
1074 1075 1076
		ql_dbg(ql_dbg_async, vha, 0x5018,
		    "ISP84XX Alert Notification -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
1077 1078 1079 1080

		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
		switch (mb[1]) {
		case A84_PANIC_RECOVERY:
1081 1082 1083
			ql_log(ql_log_info, vha, 0x5019,
			    "Alert 84XX: panic recovery %04x %04x.\n",
			    mb[2], mb[3]);
1084 1085 1086
			break;
		case A84_OP_LOGIN_COMPLETE:
			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
1087 1088 1089
			ql_log(ql_log_info, vha, 0x501a,
			    "Alert 84XX: firmware version %x.\n",
			    ha->cs84xx->op_fw_version);
1090 1091 1092
			break;
		case A84_DIAG_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
1093 1094 1095
			ql_log(ql_log_info, vha, 0x501b,
			    "Alert 84XX: diagnostic firmware version %x.\n",
			    ha->cs84xx->diag_fw_version);
1096 1097 1098 1099
			break;
		case A84_GOLD_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
			ha->cs84xx->fw_update = 1;
1100 1101 1102
			ql_log(ql_log_info, vha, 0x501c,
			    "Alert 84XX: gold firmware version %x.\n",
			    ha->cs84xx->gold_fw_version);
1103 1104
			break;
		default:
1105 1106
			ql_log(ql_log_warn, vha, 0x501d,
			    "Alert 84xx: Invalid Alert %04x %04x %04x.\n",
1107 1108 1109 1110
			    mb[1], mb[2], mb[3]);
		}
		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
		break;
1111
	case MBA_DCBX_START:
1112 1113 1114
		ql_dbg(ql_dbg_async, vha, 0x501e,
		    "DCBX Started -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
1115 1116
		break;
	case MBA_DCBX_PARAM_UPDATE:
1117 1118 1119
		ql_dbg(ql_dbg_async, vha, 0x501f,
		    "DCBX Parameters Updated -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
1120 1121
		break;
	case MBA_FCF_CONF_ERR:
1122 1123 1124
		ql_dbg(ql_dbg_async, vha, 0x5020,
		    "FCF Configuration Error -- %04x %04x %04x.\n",
		    mb[1], mb[2], mb[3]);
1125 1126
		break;
	case MBA_IDC_NOTIFY:
1127
		if (IS_QLA8031(vha->hw) || IS_QLA8044(ha)) {
1128 1129 1130 1131
			mb[4] = RD_REG_WORD(&reg24->mailbox4);
			if (((mb[2] & 0x7fff) == MBC_PORT_RESET ||
			    (mb[2] & 0x7fff) == MBC_SET_PORT_CONFIG) &&
			    (mb[4] & INTERNAL_LOOPBACK_MASK) != 0) {
1132
				set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
1133 1134 1135 1136 1137 1138
				/*
				 * Extend loop down timer since port is active.
				 */
				if (atomic_read(&vha->loop_state) == LOOP_DOWN)
					atomic_set(&vha->loop_down_timer,
					    LOOP_DOWN_TIME);
1139 1140
				qla2xxx_wake_dpc(vha);
			}
1141
		}
1142
	case MBA_IDC_COMPLETE:
1143
		if (ha->notify_lb_portup_comp && !vha->vp_idx)
1144 1145
			complete(&ha->lb_portup_comp);
		/* Fallthru */
1146
	case MBA_IDC_TIME_EXT:
1147 1148
		if (IS_QLA81XX(vha->hw) || IS_QLA8031(vha->hw) ||
		    IS_QLA8044(ha))
1149 1150 1151 1152 1153 1154 1155 1156 1157
			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);
1158
		break;
1159

1160 1161
	case MBA_DPORT_DIAGNOSTICS:
		ql_dbg(ql_dbg_async, vha, 0x5052,
1162
		    "D-Port Diagnostics: %04x result=%s\n",
1163
		    mb[0],
1164
		    mb[1] == 0 ? "start" :
1165 1166
		    mb[1] == 1 ? "done (pass)" :
		    mb[1] == 2 ? "done (error)" : "other");
1167 1168
		break;

1169 1170 1171 1172 1173 1174 1175
	case MBA_TEMPERATURE_ALERT:
		ql_dbg(ql_dbg_async, vha, 0x505e,
		    "TEMPERATURE ALERT: %04x %04x %04x\n", mb[1], mb[2], mb[3]);
		if (mb[1] == 0x12)
			schedule_work(&ha->board_disable);
		break;

1176 1177 1178 1179
	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 已提交
1180
	}
1181

1182 1183
	qlt_async_event(mb[0], vha, mb);

1184
	if (!vha->vp_idx && ha->num_vhosts)
1185
		qla2x00_alert_all_vps(rsp, mb);
L
Linus Torvalds 已提交
1186 1187 1188 1189 1190 1191 1192
}

/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
1193
void
1194
qla2x00_process_completed_request(struct scsi_qla_host *vha,
1195
				  struct req_que *req, uint32_t index)
L
Linus Torvalds 已提交
1196 1197
{
	srb_t *sp;
1198
	struct qla_hw_data *ha = vha->hw;
L
Linus Torvalds 已提交
1199 1200

	/* Validate handle. */
1201
	if (index >= req->num_outstanding_cmds) {
1202 1203
		ql_log(ql_log_warn, vha, 0x3014,
		    "Invalid SCSI command index (%x).\n", index);
L
Linus Torvalds 已提交
1204

1205
		if (IS_P3P_TYPE(ha))
1206 1207 1208
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
1209 1210 1211
		return;
	}

1212
	sp = req->outstanding_cmds[index];
L
Linus Torvalds 已提交
1213 1214
	if (sp) {
		/* Free outstanding command slot. */
1215
		req->outstanding_cmds[index] = NULL;
L
Linus Torvalds 已提交
1216 1217

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

1222
		if (IS_P3P_TYPE(ha))
1223 1224 1225
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
1226 1227 1228
	}
}

1229
srb_t *
1230 1231 1232 1233 1234 1235 1236 1237 1238
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);
1239
	if (index >= req->num_outstanding_cmds) {
1240 1241
		ql_log(ql_log_warn, vha, 0x5031,
		    "Invalid command index (%x).\n", index);
1242
		if (IS_P3P_TYPE(ha))
1243 1244 1245
			set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
		else
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1246 1247 1248 1249
		goto done;
	}
	sp = req->outstanding_cmds[index];
	if (!sp) {
1250 1251
		ql_log(ql_log_warn, vha, 0x5032,
		    "Invalid completion handle (%x) -- timed-out.\n", index);
1252 1253 1254
		return sp;
	}
	if (sp->handle != index) {
1255 1256
		ql_log(ql_log_warn, vha, 0x5033,
		    "SRB handle (%x) mismatch %x.\n", sp->handle, index);
1257 1258
		return NULL;
	}
1259

1260
	req->outstanding_cmds[index] = NULL;
1261

1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
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;
1274
	struct srb_iocb *lio;
1275
	uint16_t *data;
1276
	uint16_t status;
1277 1278 1279 1280 1281

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

1282 1283
	lio = &sp->u.iocb_cmd;
	type = sp->name;
1284
	fcport = sp->fcport;
1285
	data = lio->u.logio.data;
1286

1287
	data[0] = MBS_COMMAND_ERROR;
1288
	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
1289
	    QLA_LOGIO_LOGIN_RETRIED : 0;
1290
	if (mbx->entry_status) {
1291
		ql_dbg(ql_dbg_async, vha, 0x5043,
1292
		    "Async-%s error entry - hdl=%x portid=%02x%02x%02x "
1293
		    "entry-status=%x status=%x state-flag=%x "
1294 1295
		    "status-flags=%x.\n", type, sp->handle,
		    fcport->d_id.b.domain, fcport->d_id.b.area,
1296 1297
		    fcport->d_id.b.al_pa, mbx->entry_status,
		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
1298
		    le16_to_cpu(mbx->status_flags));
1299

1300
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5029,
1301
		    (uint8_t *)mbx, sizeof(*mbx));
1302

1303
		goto logio_done;
1304 1305
	}

1306
	status = le16_to_cpu(mbx->status);
1307
	if (status == 0x30 && sp->type == SRB_LOGIN_CMD &&
1308 1309 1310
	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
		status = 0;
	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
1311
		ql_dbg(ql_dbg_async, vha, 0x5045,
1312 1313 1314 1315
		    "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));
1316 1317

		data[0] = MBS_COMMAND_COMPLETE;
1318
		if (sp->type == SRB_LOGIN_CMD) {
1319 1320 1321
			fcport->port_type = FCT_TARGET;
			if (le16_to_cpu(mbx->mb1) & BIT_0)
				fcport->port_type = FCT_INITIATOR;
1322
			else if (le16_to_cpu(mbx->mb1) & BIT_1)
1323
				fcport->flags |= FCF_FCP2_DEVICE;
1324
		}
1325
		goto logio_done;
1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339
	}

	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;
	}

1340
	ql_log(ql_log_warn, vha, 0x5046,
1341 1342 1343 1344
	    "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),
1345
	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
1346
	    le16_to_cpu(mbx->mb7));
1347

1348
logio_done:
1349
	sp->done(vha, sp, 0);
1350 1351
}

1352 1353 1354 1355 1356 1357 1358 1359
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;
1360
	struct fc_bsg_reply *bsg_reply;
1361
	uint16_t comp_status;
1362
	int res;
1363 1364 1365 1366 1367

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

1368
	bsg_job = sp->u.bsg_job;
1369
	bsg_reply = bsg_job->reply;
1370

1371
	type = "ct pass-through";
1372 1373 1374 1375 1376 1377

	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
	 */
1378
	bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
1379 1380 1381 1382
	bsg_job->reply_len = sizeof(struct fc_bsg_reply);

	if (comp_status != CS_COMPLETE) {
		if (comp_status == CS_DATA_UNDERRUN) {
1383
			res = DID_OK << 16;
1384
			bsg_reply->reply_payload_rcv_len =
1385 1386
			    le16_to_cpu(((sts_entry_t *)pkt)->rsp_info_len);

1387 1388
			ql_log(ql_log_warn, vha, 0x5048,
			    "CT pass-through-%s error "
1389
			    "comp_status-status=0x%x total_byte = 0x%x.\n",
1390
			    type, comp_status,
1391
			    bsg_reply->reply_payload_rcv_len);
1392
		} else {
1393 1394 1395
			ql_log(ql_log_warn, vha, 0x5049,
			    "CT pass-through-%s error "
			    "comp_status-status=0x%x.\n", type, comp_status);
1396
			res = DID_ERROR << 16;
1397
			bsg_reply->reply_payload_rcv_len = 0;
1398
		}
1399
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5035,
1400
		    (uint8_t *)pkt, sizeof(*pkt));
1401
	} else {
1402
		res = DID_OK << 16;
1403
		bsg_reply->reply_payload_rcv_len =
1404 1405 1406 1407
		    bsg_job->reply_payload.payload_len;
		bsg_job->reply_len = 0;
	}

1408
	sp->done(vha, sp, res);
1409 1410
}

1411 1412 1413 1414 1415 1416 1417 1418
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;
1419
	struct fc_bsg_reply *bsg_reply;
1420 1421 1422
	uint16_t comp_status;
	uint32_t fw_status[3];
	uint8_t* fw_sts_ptr;
1423
	int res;
1424 1425 1426 1427

	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
	if (!sp)
		return;
1428
	bsg_job = sp->u.bsg_job;
1429
	bsg_reply = bsg_job->reply;
1430 1431

	type = NULL;
1432
	switch (sp->type) {
1433 1434 1435 1436 1437 1438 1439
	case SRB_ELS_CMD_RPT:
	case SRB_ELS_CMD_HST:
		type = "els";
		break;
	case SRB_CT_CMD:
		type = "ct pass-through";
		break;
1440 1441 1442 1443 1444 1445
	case SRB_ELS_DCMD:
		type = "Driver ELS logo";
		ql_dbg(ql_dbg_user, vha, 0x5047,
		    "Completing %s: (%p) type=%d.\n", type, sp, sp->type);
		sp->done(vha, sp, 0);
		return;
1446
	default:
1447
		ql_dbg(ql_dbg_user, vha, 0x503e,
1448
		    "Unrecognized SRB: (%p) type=%d.\n", sp, sp->type);
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458
		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
	 */
1459
	bsg_reply->reply_data.ctels_reply.status = FC_CTELS_STATUS_OK;
1460 1461 1462 1463
	bsg_job->reply_len = sizeof(struct fc_bsg_reply) + sizeof(fw_status);

	if (comp_status != CS_COMPLETE) {
		if (comp_status == CS_DATA_UNDERRUN) {
1464
			res = DID_OK << 16;
1465
			bsg_reply->reply_payload_rcv_len =
1466
			    le16_to_cpu(((struct els_sts_entry_24xx *)pkt)->total_byte_count);
1467

1468
			ql_dbg(ql_dbg_user, vha, 0x503f,
1469
			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
1470
			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
1471
			    type, sp->handle, comp_status, fw_status[1], fw_status[2],
1472 1473
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				pkt)->total_byte_count));
1474 1475 1476 1477
			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
		}
		else {
1478
			ql_dbg(ql_dbg_user, vha, 0x5040,
1479
			    "ELS-CT pass-through-%s error hdl=%x comp_status-status=0x%x "
1480
			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
1481
			    type, sp->handle, comp_status,
1482 1483 1484 1485
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				pkt)->error_subcode_1),
			    le16_to_cpu(((struct els_sts_entry_24xx *)
				    pkt)->error_subcode_2));
1486
			res = DID_ERROR << 16;
1487
			bsg_reply->reply_payload_rcv_len = 0;
1488 1489 1490
			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
		}
1491
		ql_dump_buffer(ql_dbg_user + ql_dbg_buffer, vha, 0x5056,
1492
				(uint8_t *)pkt, sizeof(*pkt));
1493 1494
	}
	else {
1495
		res =  DID_OK << 16;
1496
		bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len;
1497 1498 1499
		bsg_job->reply_len = 0;
	}

1500
	sp->done(vha, sp, res);
1501 1502
}

1503 1504 1505 1506 1507 1508 1509 1510
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;
1511
	struct srb_iocb *lio;
1512
	uint16_t *data;
1513 1514 1515 1516 1517 1518
	uint32_t iop[2];

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

1519 1520
	lio = &sp->u.iocb_cmd;
	type = sp->name;
1521
	fcport = sp->fcport;
1522
	data = lio->u.logio.data;
1523

1524
	data[0] = MBS_COMMAND_ERROR;
1525
	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
1526
		QLA_LOGIO_LOGIN_RETRIED : 0;
1527
	if (logio->entry_status) {
1528
		ql_log(ql_log_warn, fcport->vha, 0x5034,
1529
		    "Async-%s error entry - hdl=%x"
1530
		    "portid=%02x%02x%02x entry-status=%x.\n",
1531 1532 1533 1534
		    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,
1535
		    (uint8_t *)logio, sizeof(*logio));
1536

1537
		goto logio_done;
1538 1539 1540
	}

	if (le16_to_cpu(logio->comp_status) == CS_COMPLETE) {
1541
		ql_dbg(ql_dbg_async, fcport->vha, 0x5036,
1542 1543 1544
		    "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,
1545
		    le32_to_cpu(logio->io_parameter[0]));
1546 1547

		data[0] = MBS_COMMAND_COMPLETE;
1548
		if (sp->type != SRB_LOGIN_CMD)
1549
			goto logio_done;
1550 1551 1552 1553 1554

		iop[0] = le32_to_cpu(logio->io_parameter[0]);
		if (iop[0] & BIT_4) {
			fcport->port_type = FCT_TARGET;
			if (iop[0] & BIT_8)
1555
				fcport->flags |= FCF_FCP2_DEVICE;
1556
		} else if (iop[0] & BIT_5)
1557
			fcport->port_type = FCT_INITIATOR;
1558

1559 1560 1561
		if (iop[0] & BIT_7)
			fcport->flags |= FCF_CONF_COMP_SUPPORTED;

1562 1563 1564 1565 1566
		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;

1567
		goto logio_done;
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584
	}

	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;
	}

1585
	ql_dbg(ql_dbg_async, fcport->vha, 0x5037,
1586 1587
	    "Async-%s failed - hdl=%x portid=%02x%02x%02x comp=%x "
	    "iop0=%x iop1=%x.\n", type, sp->handle, fcport->d_id.b.domain,
1588
	    fcport->d_id.b.area, fcport->d_id.b.al_pa,
1589 1590
	    le16_to_cpu(logio->comp_status),
	    le32_to_cpu(logio->io_parameter[0]),
1591
	    le32_to_cpu(logio->io_parameter[1]));
1592

1593
logio_done:
1594
	sp->done(vha, sp, 0);
1595 1596
}

1597
static void
1598
qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, void *tsk)
1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
{
	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;

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

1611 1612
	iocb = &sp->u.iocb_cmd;
	type = sp->name;
1613
	fcport = sp->fcport;
1614
	iocb->u.tmf.data = QLA_SUCCESS;
1615 1616

	if (sts->entry_status) {
1617
		ql_log(ql_log_warn, fcport->vha, 0x5038,
1618 1619
		    "Async-%s error - hdl=%x entry-status(%x).\n",
		    type, sp->handle, sts->entry_status);
1620
		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
1621
	} else if (sts->comp_status != cpu_to_le16(CS_COMPLETE)) {
1622
		ql_log(ql_log_warn, fcport->vha, 0x5039,
1623 1624
		    "Async-%s error - hdl=%x completion status(%x).\n",
		    type, sp->handle, sts->comp_status);
1625 1626
		iocb->u.tmf.data = QLA_FUNCTION_FAILED;
	} else if ((le16_to_cpu(sts->scsi_status) &
1627
	    SS_RESPONSE_INFO_LEN_VALID)) {
1628 1629 1630 1631 1632 1633 1634 1635
		if (le32_to_cpu(sts->rsp_data_len) < 4) {
			ql_log(ql_log_warn, fcport->vha, 0x503b,
			    "Async-%s error - hdl=%x not enough response(%d).\n",
			    type, sp->handle, sts->rsp_data_len);
		} else if (sts->data[3]) {
			ql_log(ql_log_warn, fcport->vha, 0x503c,
			    "Async-%s error - hdl=%x response(%x).\n",
			    type, sp->handle, sts->data[3]);
B
Bart Van Assche 已提交
1636
			iocb->u.tmf.data = QLA_FUNCTION_FAILED;
1637
		}
1638 1639
	}

1640
	if (iocb->u.tmf.data != QLA_SUCCESS)
1641 1642
		ql_dump_buffer(ql_dbg_async + ql_dbg_buffer, vha, 0x5055,
		    (uint8_t *)sts, sizeof(*sts));
1643

1644
	sp->done(vha, sp, 0);
1645 1646
}

L
Linus Torvalds 已提交
1647 1648 1649 1650 1651
/**
 * qla2x00_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
1652
qla2x00_process_response_queue(struct rsp_que *rsp)
L
Linus Torvalds 已提交
1653
{
1654 1655
	struct scsi_qla_host *vha;
	struct qla_hw_data *ha = rsp->hw;
1656
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
1657 1658 1659
	sts_entry_t	*pkt;
	uint16_t        handle_cnt;
	uint16_t        cnt;
1660

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

1663
	if (!vha->flags.online)
L
Linus Torvalds 已提交
1664 1665
		return;

1666 1667
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (sts_entry_t *)rsp->ring_ptr;
L
Linus Torvalds 已提交
1668

1669 1670 1671 1672
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
L
Linus Torvalds 已提交
1673
		} else {
1674
			rsp->ring_ptr++;
L
Linus Torvalds 已提交
1675 1676 1677
		}

		if (pkt->entry_status != 0) {
1678
			qla2x00_error_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
1679 1680 1681 1682 1683 1684 1685
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
1686
			qla2x00_status_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
1687 1688 1689 1690
			break;
		case STATUS_TYPE_21:
			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
1691
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
1692 1693 1694 1695 1696 1697
				    ((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++) {
1698
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
1699 1700 1701 1702
				    ((sts22_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_CONT_TYPE:
1703
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
L
Linus Torvalds 已提交
1704
			break;
1705 1706 1707
		case MBX_IOCB_TYPE:
			qla2x00_mbx_iocb_entry(vha, rsp->req,
			    (struct mbx_entry *)pkt);
1708
			break;
1709 1710 1711
		case CT_IOCB_TYPE:
			qla2x00_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			break;
L
Linus Torvalds 已提交
1712 1713
		default:
			/* Type Not Supported. */
1714 1715
			ql_log(ql_log_warn, vha, 0x504a,
			    "Received unknown response pkt type %x "
L
Linus Torvalds 已提交
1716
			    "entry status=%x.\n",
1717
			    pkt->entry_type, pkt->entry_status);
L
Linus Torvalds 已提交
1718 1719 1720 1721 1722 1723 1724
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

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

1728
static inline void
1729
qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t par_sense_len,
1730
		     uint32_t sense_len, struct rsp_que *rsp, int res)
1731
{
1732
	struct scsi_qla_host *vha = sp->fcport->vha;
1733 1734
	struct scsi_cmnd *cp = GET_CMD_SP(sp);
	uint32_t track_sense_len;
1735 1736 1737 1738

	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
		sense_len = SCSI_SENSE_BUFFERSIZE;

1739 1740 1741 1742 1743
	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)
1744
		sense_len = par_sense_len;
1745 1746 1747

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

1748 1749 1750 1751 1752
	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) {
1753
		rsp->status_srb = sp;
1754 1755
		cp->result = res;
	}
1756

1757 1758
	if (sense_len) {
		ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x301c,
H
Hannes Reinecke 已提交
1759
		    "Check condition Sense data, nexus%ld:%d:%llu cmd=%p.\n",
1760 1761
		    sp->fcport->vha->host_no, cp->device->id, cp->device->lun,
		    cp);
1762 1763
		ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x302b,
		    cp->sense_buffer, sense_len);
1764
	}
1765 1766
}

1767 1768
struct scsi_dif_tuple {
	__be16 guard;       /* Checksum */
1769
	__be16 app_tag;         /* APPL identifier */
1770 1771 1772 1773 1774 1775 1776 1777 1778
	__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.
 */
1779
static inline int
1780 1781
qla2x00_handle_dif_error(srb_t *sp, struct sts_entry_24xx *sts24)
{
1782
	struct scsi_qla_host *vha = sp->fcport->vha;
1783
	struct scsi_cmnd *cmd = GET_CMD_SP(sp);
1784 1785
	uint8_t		*ap = &sts24->data[12];
	uint8_t		*ep = &sts24->data[20];
1786 1787 1788 1789
	uint32_t	e_ref_tag, a_ref_tag;
	uint16_t	e_app_tag, a_app_tag;
	uint16_t	e_guard, a_guard;

1790 1791 1792 1793 1794 1795 1796 1797 1798 1799
	/*
	 * 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));
1800

1801 1802
	ql_dbg(ql_dbg_io, vha, 0x3023,
	    "iocb(s) %p Returned STATUS.\n", sts24);
1803

1804 1805
	ql_dbg(ql_dbg_io, vha, 0x3024,
	    "DIF ERROR in cmd 0x%x lba 0x%llx act ref"
1806
	    " tag=0x%x, exp ref_tag=0x%x, act app tag=0x%x, exp app"
1807
	    " tag=0x%x, act guard=0x%x, exp guard=0x%x.\n",
1808
	    cmd->cmnd[0], (u64)scsi_get_lba(cmd), a_ref_tag, e_ref_tag,
1809
	    a_app_tag, e_app_tag, a_guard, e_guard);
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
	/*
	 * 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;
1835
			struct t10_pi_tuple *spt;
1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850

			/* 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) {
1851
				ql_log(ql_log_warn, vha, 0x302f,
1852 1853
				    "unexpected tag values tag:lba=%x:%llx)\n",
				    e_ref_tag, (unsigned long long)lba_s);
1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867
				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;
	}

1868 1869 1870 1871 1872 1873 1874
	/* 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;
1875
		return 1;
1876 1877
	}

1878 1879
	/* check ref tag */
	if (e_ref_tag != a_ref_tag) {
1880
		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
1881
		    0x10, 0x3);
1882 1883 1884
		set_driver_byte(cmd, DRIVER_SENSE);
		set_host_byte(cmd, DID_ABORT);
		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
1885
		return 1;
1886 1887
	}

1888 1889
	/* check appl tag */
	if (e_app_tag != a_app_tag) {
1890
		scsi_build_sense_buffer(1, cmd->sense_buffer, ILLEGAL_REQUEST,
1891
		    0x10, 0x2);
1892 1893 1894
		set_driver_byte(cmd, DRIVER_SENSE);
		set_host_byte(cmd, DID_ABORT);
		cmd->result |= SAM_STAT_CHECK_CONDITION << 1;
1895
		return 1;
1896
	}
1897

1898
	return 1;
1899 1900
}

1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911
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;
1912 1913
	struct fc_bsg_request *bsg_request;
	struct fc_bsg_reply *bsg_reply;
1914 1915 1916 1917 1918 1919
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;

	/* Validate handle. */
1920
	if (index >= req->num_outstanding_cmds) {
1921 1922 1923 1924 1925 1926 1927
		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];
1928
	if (!sp) {
1929 1930 1931 1932 1933 1934 1935 1936
		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;
	}

1937 1938 1939 1940 1941 1942
	/* Free outstanding command slot. */
	req->outstanding_cmds[index] = NULL;
	bsg_job = sp->u.bsg_job;
	bsg_request = bsg_job->request;
	bsg_reply = bsg_job->reply;

1943 1944 1945 1946 1947 1948 1949 1950
	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;
	}

1951
	thread_id = bsg_request->rqst_data.h_vendor.vendor_cmd[1];
1952 1953 1954
	switch (comp_status) {
	case CS_COMPLETE:
		if (scsi_status == 0) {
1955
			bsg_reply->reply_payload_rcv_len =
1956
					bsg_job->reply_payload.payload_len;
1957
			vha->qla_stats.input_bytes +=
1958
				bsg_reply->reply_payload_rcv_len;
1959
			vha->qla_stats.input_requests++;
1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038
			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;
	}
2039
	bsg_reply->reply_payload_rcv_len = 0;
2040 2041 2042

done:
	/* Return the vendor specific reply to API */
2043
	bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval;
2044 2045 2046 2047 2048 2049 2050
	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 已提交
2051 2052 2053 2054 2055 2056
/**
 * qla2x00_status_entry() - Process a Status IOCB entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
2057
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
L
Linus Torvalds 已提交
2058 2059 2060 2061
{
	srb_t		*sp;
	fc_port_t	*fcport;
	struct scsi_cmnd *cp;
2062 2063
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
L
Linus Torvalds 已提交
2064 2065
	uint16_t	comp_status;
	uint16_t	scsi_status;
2066
	uint16_t	ox_id;
L
Linus Torvalds 已提交
2067 2068
	uint8_t		lscsi_status;
	int32_t		resid;
2069 2070
	uint32_t sense_len, par_sense_len, rsp_info_len, resid_len,
	    fw_resid_len;
2071
	uint8_t		*rsp_info, *sense_data;
2072
	struct qla_hw_data *ha = vha->hw;
2073 2074 2075
	uint32_t handle;
	uint16_t que;
	struct req_que *req;
2076
	int logit = 1;
2077
	int res = 0;
2078
	uint16_t state_flags = 0;
2079
	uint16_t retry_delay = 0;
2080 2081 2082

	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;
2083
	if (IS_FWI2_CAPABLE(ha)) {
2084 2085
		comp_status = le16_to_cpu(sts24->comp_status);
		scsi_status = le16_to_cpu(sts24->scsi_status) & SS_MASK;
2086
		state_flags = le16_to_cpu(sts24->state_flags);
2087 2088 2089 2090
	} else {
		comp_status = le16_to_cpu(sts->comp_status);
		scsi_status = le16_to_cpu(sts->scsi_status) & SS_MASK;
	}
2091 2092 2093
	handle = (uint32_t) LSW(sts->handle);
	que = MSW(sts->handle);
	req = ha->req_q_map[que];
2094

2095 2096 2097 2098 2099 2100 2101 2102 2103
	/* Check for invalid queue pointer */
	if (req == NULL ||
	    que >= find_first_zero_bit(ha->req_qid_map, ha->max_req_queues)) {
		ql_dbg(ql_dbg_io, vha, 0x3059,
		    "Invalid status handle (0x%x): Bad req pointer. req=%p, "
		    "que=%u.\n", sts->handle, req, que);
		return;
	}

L
Linus Torvalds 已提交
2104
	/* Validate handle. */
2105
	if (handle < req->num_outstanding_cmds) {
2106
		sp = req->outstanding_cmds[handle];
2107 2108 2109 2110 2111 2112 2113
		if (!sp) {
			ql_dbg(ql_dbg_io, vha, 0x3075,
			    "%s(%ld): Already returned command for status handle (0x%x).\n",
			    __func__, vha->host_no, sts->handle);
			return;
		}
	} else {
2114
		ql_dbg(ql_dbg_io, vha, 0x3017,
2115 2116
		    "Invalid status handle, out of range (0x%x).\n",
		    sts->handle);
L
Linus Torvalds 已提交
2117

2118 2119 2120 2121 2122 2123 2124
		if (!test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
			if (IS_P3P_TYPE(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 已提交
2125 2126
		return;
	}
2127 2128 2129 2130 2131 2132

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

2133 2134 2135 2136 2137 2138
	/* Task Management completion. */
	if (sp->type == SRB_TM_CMD) {
		qla24xx_tm_iocb_entry(vha, req, pkt);
		return;
	}

2139 2140 2141 2142 2143 2144 2145 2146
	/* Fast path completion. */
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
		qla2x00_process_completed_request(vha, req, handle);

		return;
	}

	req->outstanding_cmds[handle] = NULL;
2147
	cp = GET_CMD_SP(sp);
L
Linus Torvalds 已提交
2148
	if (cp == NULL) {
2149
		ql_dbg(ql_dbg_io, vha, 0x3018,
2150 2151
		    "Command already returned (0x%x/%p).\n",
		    sts->handle, sp);
L
Linus Torvalds 已提交
2152 2153 2154 2155

		return;
	}

2156
	lscsi_status = scsi_status & STATUS_MASK;
L
Linus Torvalds 已提交
2157

2158
	fcport = sp->fcport;
L
Linus Torvalds 已提交
2159

2160
	ox_id = 0;
2161 2162
	sense_len = par_sense_len = rsp_info_len = resid_len =
	    fw_resid_len = 0;
2163
	if (IS_FWI2_CAPABLE(ha)) {
2164 2165 2166 2167 2168 2169 2170 2171
		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);
2172 2173 2174
		rsp_info = sts24->data;
		sense_data = sts24->data;
		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
2175
		ox_id = le16_to_cpu(sts24->ox_id);
2176
		par_sense_len = sizeof(sts24->data);
2177 2178 2179
		/* Valid values of the retry delay timer are 0x1-0xffef */
		if (sts24->retry_delay > 0 && sts24->retry_delay < 0xfff1)
			retry_delay = sts24->retry_delay;
2180
	} else {
2181 2182 2183 2184
		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);
2185 2186 2187
		resid_len = le32_to_cpu(sts->residual_length);
		rsp_info = sts->rsp_info;
		sense_data = sts->req_sense_data;
2188
		par_sense_len = sizeof(sts->req_sense_data);
2189 2190
	}

L
Linus Torvalds 已提交
2191 2192
	/* Check for any FCP transport errors. */
	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
2193
		/* Sense data lies beyond any FCP RESPONSE data. */
2194
		if (IS_FWI2_CAPABLE(ha)) {
2195
			sense_data += rsp_info_len;
2196 2197
			par_sense_len -= rsp_info_len;
		}
2198
		if (rsp_info_len > 3 && rsp_info[3]) {
2199
			ql_dbg(ql_dbg_io, fcport->vha, 0x3019,
2200 2201
			    "FCP I/O protocol failure (0x%x/0x%x).\n",
			    rsp_info_len, rsp_info[3]);
L
Linus Torvalds 已提交
2202

2203
			res = DID_BUS_BUSY << 16;
2204
			goto out;
L
Linus Torvalds 已提交
2205 2206 2207
		}
	}

2208 2209 2210 2211 2212
	/* Check for overrun. */
	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
	    scsi_status & SS_RESIDUAL_OVER)
		comp_status = CS_DATA_OVERRUN;

2213 2214 2215 2216 2217 2218 2219 2220
	/*
	 * Check retry_delay_timer value if we receive a busy or
	 * queue full.
	 */
	if (lscsi_status == SAM_STAT_TASK_SET_FULL ||
	    lscsi_status == SAM_STAT_BUSY)
		qla2x00_set_retry_delay_timestamp(fcport, retry_delay);

L
Linus Torvalds 已提交
2221 2222 2223 2224 2225
	/*
	 * Based on Host and scsi status generate status code for Linux
	 */
	switch (comp_status) {
	case CS_COMPLETE:
2226
	case CS_QUEUE_FULL:
L
Linus Torvalds 已提交
2227
		if (scsi_status == 0) {
2228
			res = DID_OK << 16;
L
Linus Torvalds 已提交
2229 2230 2231
			break;
		}
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
2232
			resid = resid_len;
2233
			scsi_set_resid(cp, resid);
2234 2235

			if (!lscsi_status &&
2236
			    ((unsigned)(scsi_bufflen(cp) - resid) <
2237
			     cp->underflow)) {
2238
				ql_dbg(ql_dbg_io, fcport->vha, 0x301a,
2239
				    "Mid-layer underflow "
2240
				    "detected (0x%x of 0x%x bytes).\n",
2241
				    resid, scsi_bufflen(cp));
2242

2243
				res = DID_ERROR << 16;
2244 2245
				break;
			}
L
Linus Torvalds 已提交
2246
		}
2247
		res = DID_OK << 16 | lscsi_status;
L
Linus Torvalds 已提交
2248

2249
		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
2250
			ql_dbg(ql_dbg_io, fcport->vha, 0x301b,
2251
			    "QUEUE FULL detected.\n");
2252 2253
			break;
		}
2254
		logit = 0;
L
Linus Torvalds 已提交
2255 2256 2257
		if (lscsi_status != SS_CHECK_CONDITION)
			break;

2258
		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
2259 2260 2261
		if (!(scsi_status & SS_SENSE_LEN_VALID))
			break;

2262
		qla2x00_handle_sense(sp, sense_data, par_sense_len, sense_len,
2263
		    rsp, res);
L
Linus Torvalds 已提交
2264 2265 2266
		break;

	case CS_DATA_UNDERRUN:
2267
		/* Use F/W calculated residual length. */
2268 2269 2270 2271
		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) {
2272
				ql_dbg(ql_dbg_io, fcport->vha, 0x301d,
2273 2274 2275
				    "Dropped frame(s) detected "
				    "(0x%x of 0x%x bytes).\n",
				    resid, scsi_bufflen(cp));
2276

2277
				res = DID_ERROR << 16 | lscsi_status;
2278
				goto check_scsi_status;
2279
			}
2280

2281 2282 2283
			if (!lscsi_status &&
			    ((unsigned)(scsi_bufflen(cp) - resid) <
			    cp->underflow)) {
2284
				ql_dbg(ql_dbg_io, fcport->vha, 0x301e,
2285
				    "Mid-layer underflow "
2286
				    "detected (0x%x of 0x%x bytes).\n",
2287
				    resid, scsi_bufflen(cp));
2288

2289
				res = DID_ERROR << 16;
2290 2291
				break;
			}
2292 2293 2294 2295 2296 2297 2298
		} 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.
			 */

2299
			ql_dbg(ql_dbg_io, fcport->vha, 0x301f,
2300
			    "Dropped frame(s) detected (0x%x "
2301 2302
			    "of 0x%x bytes).\n", resid,
			    scsi_bufflen(cp));
2303

2304
			res = DID_ERROR << 16 | lscsi_status;
2305
			goto check_scsi_status;
2306 2307 2308 2309
		} 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 已提交
2310 2311
		}

2312
		res = DID_OK << 16 | lscsi_status;
2313
		logit = 0;
2314

2315
check_scsi_status:
L
Linus Torvalds 已提交
2316
		/*
A
Andrew Vasquez 已提交
2317
		 * Check to see if SCSI Status is non zero. If so report SCSI
L
Linus Torvalds 已提交
2318 2319 2320
		 * Status.
		 */
		if (lscsi_status != 0) {
2321
			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
2322
				ql_dbg(ql_dbg_io, fcport->vha, 0x3020,
2323
				    "QUEUE FULL detected.\n");
2324
				logit = 1;
2325 2326
				break;
			}
L
Linus Torvalds 已提交
2327 2328 2329
			if (lscsi_status != SS_CHECK_CONDITION)
				break;

2330
			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
2331 2332 2333
			if (!(scsi_status & SS_SENSE_LEN_VALID))
				break;

2334
			qla2x00_handle_sense(sp, sense_data, par_sense_len,
2335
			    sense_len, rsp, res);
L
Linus Torvalds 已提交
2336 2337 2338 2339 2340 2341 2342 2343
		}
		break;

	case CS_PORT_LOGGED_OUT:
	case CS_PORT_CONFIG_CHG:
	case CS_PORT_BUSY:
	case CS_INCOMPLETE:
	case CS_PORT_UNAVAILABLE:
2344
	case CS_TIMEOUT:
2345 2346
	case CS_RESET:

2347 2348 2349 2350 2351
		/*
		 * 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.
		 */
2352
		res = DID_TRANSPORT_DISRUPTED << 16;
2353 2354 2355 2356 2357 2358 2359 2360 2361

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

2362
		ql_dbg(ql_dbg_io, fcport->vha, 0x3021,
2363 2364 2365 2366
		    "Port to be marked lost on fcport=%02x%02x%02x, current "
		    "port state= %s.\n", fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa,
		    port_state_str[atomic_read(&fcport->state)]);
2367

2368
		if (atomic_read(&fcport->state) == FCS_ONLINE)
2369
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
2370 2371 2372
		break;

	case CS_ABORTED:
2373
		res = DID_RESET << 16;
L
Linus Torvalds 已提交
2374
		break;
2375 2376

	case CS_DIF_ERROR:
2377
		logit = qla2x00_handle_dif_error(sp, sts24);
2378
		res = cp->result;
2379
		break;
2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392

	case CS_TRANSPORT:
		res = DID_ERROR << 16;

		if (!IS_PI_SPLIT_DET_CAPABLE(ha))
			break;

		if (state_flags & BIT_4)
			scmd_printk(KERN_WARNING, cp,
			    "Unsupported device '%s' found.\n",
			    cp->device->vendor);
		break;

L
Linus Torvalds 已提交
2393
	default:
2394
		res = DID_ERROR << 16;
L
Linus Torvalds 已提交
2395 2396 2397
		break;
	}

2398 2399
out:
	if (logit)
2400
		ql_dbg(ql_dbg_io, fcport->vha, 0x3022,
H
Hannes Reinecke 已提交
2401
		    "FCP command status: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu "
2402
		    "portid=%02x%02x%02x oxid=0x%x cdb=%10phN len=0x%x "
2403
		    "rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n",
2404
		    comp_status, scsi_status, res, vha->host_no,
2405 2406
		    cp->device->id, cp->device->lun, fcport->d_id.b.domain,
		    fcport->d_id.b.area, fcport->d_id.b.al_pa, ox_id,
2407
		    cp->cmnd, scsi_bufflen(cp), rsp_info_len,
2408
		    resid_len, fw_resid_len, sp, cp);
2409

2410
	if (rsp->status_srb == NULL)
2411
		sp->done(ha, sp, res);
L
Linus Torvalds 已提交
2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
}

/**
 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 *
 * Extended sense data.
 */
static void
2422
qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
L
Linus Torvalds 已提交
2423
{
2424
	uint8_t	sense_sz = 0;
2425
	struct qla_hw_data *ha = rsp->hw;
2426
	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
2427
	srb_t *sp = rsp->status_srb;
L
Linus Torvalds 已提交
2428
	struct scsi_cmnd *cp;
2429 2430
	uint32_t sense_len;
	uint8_t *sense_ptr;
L
Linus Torvalds 已提交
2431

2432 2433
	if (!sp || !GET_CMD_SENSE_LEN(sp))
		return;
L
Linus Torvalds 已提交
2434

2435 2436
	sense_len = GET_CMD_SENSE_LEN(sp);
	sense_ptr = GET_CMD_SENSE_PTR(sp);
L
Linus Torvalds 已提交
2437

2438 2439 2440 2441
	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 已提交
2442

2443 2444
		rsp->status_srb = NULL;
		return;
L
Linus Torvalds 已提交
2445 2446
	}

2447 2448 2449 2450
	if (sense_len > sizeof(pkt->data))
		sense_sz = sizeof(pkt->data);
	else
		sense_sz = sense_len;
2451

2452 2453 2454 2455 2456 2457
	/* 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);
2458

2459 2460
	sense_len -= sense_sz;
	sense_ptr += sense_sz;
2461

2462 2463 2464 2465 2466 2467 2468
	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);
2469 2470 2471
	}
}

L
Linus Torvalds 已提交
2472 2473 2474 2475 2476 2477
/**
 * qla2x00_error_entry() - Process an error entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
2478
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
L
Linus Torvalds 已提交
2479 2480
{
	srb_t *sp;
2481
	struct qla_hw_data *ha = vha->hw;
2482
	const char func[] = "ERROR-IOCB";
2483
	uint16_t que = MSW(pkt->handle);
2484
	struct req_que *req = NULL;
2485
	int res = DID_ERROR << 16;
2486

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

2490 2491 2492 2493 2494
	if (que >= ha->max_req_queues || !ha->req_q_map[que])
		goto fatal;

	req = ha->req_q_map[que];

2495 2496
	if (pkt->entry_status & RF_BUSY)
		res = DID_BUS_BUSY << 16;
L
Linus Torvalds 已提交
2497

2498
	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
2499
	if (sp) {
2500
		sp->done(ha, sp, res);
2501
		return;
L
Linus Torvalds 已提交
2502
	}
2503 2504
fatal:
	ql_log(ql_log_warn, vha, 0x5030,
2505
	    "Error entry - invalid handle/queue (%04x).\n", que);
L
Linus Torvalds 已提交
2506 2507
}

2508 2509 2510 2511 2512 2513
/**
 * qla24xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
2514
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
2515 2516
{
	uint16_t	cnt;
2517
	uint32_t	mboxes;
2518
	uint16_t __iomem *wptr;
2519
	struct qla_hw_data *ha = vha->hw;
2520 2521
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

2522 2523 2524
	/* Read all mbox registers? */
	mboxes = (1 << ha->mbx_count) - 1;
	if (!ha->mcp)
2525
		ql_dbg(ql_dbg_async, vha, 0x504e, "MBX pointer ERROR.\n");
2526 2527 2528
	else
		mboxes = ha->mcp->in_mb;

2529 2530 2531
	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
2532
	mboxes >>= 1;
2533 2534 2535
	wptr = (uint16_t __iomem *)&reg->mailbox1;

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
2536 2537 2538 2539
		if (mboxes & BIT_0)
			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);

		mboxes >>= 1;
2540 2541 2542 2543
		wptr++;
	}
}

2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560
static void
qla24xx_abort_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
	struct abort_entry_24xx *pkt)
{
	const char func[] = "ABT_IOCB";
	srb_t *sp;
	struct srb_iocb *abt;

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

	abt = &sp->u.iocb_cmd;
	abt->u.abt.comp_status = le32_to_cpu(pkt->nport_handle);
	sp->done(vha, sp, 0);
}

2561 2562 2563 2564
/**
 * qla24xx_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
2565 2566
void qla24xx_process_response_queue(struct scsi_qla_host *vha,
	struct rsp_que *rsp)
2567 2568
{
	struct sts_entry_24xx *pkt;
2569
	struct qla_hw_data *ha = vha->hw;
2570

2571
	if (!vha->flags.online)
2572 2573
		return;

2574
	if (rsp->msix && rsp->msix->cpuid != smp_processor_id()) {
2575 2576 2577 2578 2579 2580 2581
		/* if kernel does not notify qla of IRQ's CPU change,
		 * then set it here.
		 */
		rsp->msix->cpuid = smp_processor_id();
		ha->tgt.rspq_vector_cpuid = rsp->msix->cpuid;
	}

2582 2583
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
2584

2585 2586 2587 2588
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
2589
		} else {
2590
			rsp->ring_ptr++;
2591 2592 2593
		}

		if (pkt->entry_status != 0) {
2594
			qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
2595

2596 2597
			if (qlt_24xx_process_response_error(vha, pkt))
				goto process_err;
2598

2599 2600 2601 2602
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}
2603
process_err:
2604 2605 2606

		switch (pkt->entry_type) {
		case STATUS_TYPE:
2607
			qla2x00_status_entry(vha, rsp, pkt);
2608 2609
			break;
		case STATUS_CONT_TYPE:
2610
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
2611
			break;
2612
		case VP_RPT_ID_IOCB_TYPE:
2613
			qla24xx_report_id_acquisition(vha,
2614 2615
			    (struct vp_rpt_id_entry_24xx *)pkt);
			break;
2616 2617 2618 2619
		case LOGINOUT_PORT_IOCB_TYPE:
			qla24xx_logio_entry(vha, rsp->req,
			    (struct logio_entry_24xx *)pkt);
			break;
2620
		case CT_IOCB_TYPE:
2621 2622
			qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
			break;
2623
		case ELS_IOCB_TYPE:
2624 2625
			qla24xx_els_ct_entry(vha, rsp->req, pkt, ELS_IOCB_TYPE);
			break;
2626
		case ABTS_RECV_24XX:
2627 2628 2629 2630 2631 2632 2633 2634
			if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
				/* ensure that the ATIO queue is empty */
				qlt_handle_abts_recv(vha, (response_t *)pkt);
				break;
			} else {
				/* drop through */
				qlt_24xx_process_atio_queue(vha, 1);
			}
2635 2636 2637
		case ABTS_RESP_24XX:
		case CTIO_TYPE7:
		case NOTIFY_ACK_TYPE:
2638
		case CTIO_CRC2:
2639 2640
			qlt_response_pkt_all_vps(vha, (response_t *)pkt);
			break;
2641 2642 2643 2644 2645
		case MARKER_TYPE:
			/* Do nothing in this case, this check is to prevent it
			 * from falling into default case
			 */
			break;
2646 2647 2648 2649
		case ABORT_IOCB_TYPE:
			qla24xx_abort_iocb_entry(vha, rsp->req,
			    (struct abort_entry_24xx *)pkt);
			break;
2650 2651
		default:
			/* Type Not Supported. */
2652 2653
			ql_dbg(ql_dbg_async, vha, 0x5042,
			    "Received unknown response pkt type %x "
2654
			    "entry status=%x.\n",
2655
			    pkt->entry_type, pkt->entry_status);
2656 2657 2658 2659 2660 2661 2662
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
2663
	if (IS_P3P_TYPE(ha)) {
2664 2665 2666 2667
		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);
2668 2669
}

2670
static void
2671
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
2672 2673 2674
{
	int rval;
	uint32_t cnt;
2675
	struct qla_hw_data *ha = vha->hw;
2676 2677
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

2678 2679
	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
	    !IS_QLA27XX(ha))
2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
		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;

2697
	rval = QLA_SUCCESS;
2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711
	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)
2712 2713
		ql_log(ql_log_info, vha, 0x504c,
		    "Additional code -- 0x55AA.\n");
2714 2715 2716 2717 2718 2719

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

2720
/**
2721
 * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx.
2722 2723 2724 2725 2726 2727 2728 2729
 * @irq:
 * @dev_id: SCSI driver HA context
 *
 * Called by system whenever the host adapter generates an interrupt.
 *
 * Returns handled flag.
 */
irqreturn_t
2730
qla24xx_intr_handler(int irq, void *dev_id)
2731
{
2732 2733
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
2734 2735 2736 2737 2738
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
2739
	uint16_t	mb[8];
2740
	struct rsp_que *rsp;
2741
	unsigned long	flags;
2742

2743 2744
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2745 2746
		ql_log(ql_log_info, NULL, 0x5059,
		    "%s: NULL response queue pointer.\n", __func__);
2747 2748 2749
		return IRQ_NONE;
	}

2750
	ha = rsp->hw;
2751 2752 2753
	reg = &ha->iobase->isp24;
	status = 0;

2754 2755 2756
	if (unlikely(pci_channel_offline(ha->pdev)))
		return IRQ_HANDLED;

2757
	spin_lock_irqsave(&ha->hardware_lock, flags);
2758
	vha = pci_get_drvdata(ha->pdev);
2759 2760
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
2761
		if (qla2x00_check_reg32_for_disconnect(vha, stat))
2762
			break;
2763
		if (stat & HSRX_RISC_PAUSED) {
2764
			if (unlikely(pci_channel_offline(ha->pdev)))
2765 2766
				break;

2767 2768
			hccr = RD_REG_DWORD(&reg->hccr);

2769 2770 2771
			ql_log(ql_log_warn, vha, 0x504b,
			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
			    hccr);
2772

2773
			qla2xxx_check_risc_status(vha);
2774

2775 2776
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2777 2778 2779 2780 2781
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
2782 2783 2784 2785
		case INTR_ROM_MB_SUCCESS:
		case INTR_ROM_MB_FAILED:
		case INTR_MB_SUCCESS:
		case INTR_MB_FAILED:
2786
			qla24xx_mbx_completion(vha, MSW(stat));
2787 2788 2789
			status |= MBX_INTERRUPT;

			break;
2790
		case INTR_ASYNC_EVENT:
2791 2792 2793 2794
			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);
2795
			qla2x00_async_event(vha, rsp, mb);
2796
			break;
2797 2798
		case INTR_RSP_QUE_UPDATE:
		case INTR_RSP_QUE_UPDATE_83XX:
2799
			qla24xx_process_response_queue(vha, rsp);
2800
			break;
2801 2802 2803 2804 2805
		case INTR_ATIO_QUE_UPDATE:{
			unsigned long flags2;
			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
			qlt_24xx_process_atio_queue(vha, 1);
			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
2806
			break;
2807 2808 2809 2810 2811 2812 2813
		}
		case INTR_ATIO_RSP_QUE_UPDATE: {
			unsigned long flags2;
			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
			qlt_24xx_process_atio_queue(vha, 1);
			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);

2814 2815
			qla24xx_process_response_queue(vha, rsp);
			break;
2816
		}
2817
		default:
2818 2819
			ql_dbg(ql_dbg_async, vha, 0x504f,
			    "Unrecognized interrupt type (%d).\n", stat * 0xff);
2820 2821 2822 2823
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
2824 2825
		if (unlikely(IS_QLA83XX(ha) && (ha->pdev->revision == 1)))
			ndelay(3500);
2826
	}
2827
	qla2x00_handle_mbx_completion(ha, status);
2828
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2829 2830 2831 2832

	return IRQ_HANDLED;
}

2833 2834 2835
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
2836 2837
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
2838
	struct device_reg_24xx __iomem *reg;
2839
	struct scsi_qla_host *vha;
2840
	unsigned long flags;
2841
	uint32_t stat = 0;
2842

2843 2844
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2845 2846
		ql_log(ql_log_info, NULL, 0x505a,
		    "%s: NULL response queue pointer.\n", __func__);
2847 2848 2849
		return IRQ_NONE;
	}
	ha = rsp->hw;
2850 2851
	reg = &ha->iobase->isp24;

2852
	spin_lock_irqsave(&ha->hardware_lock, flags);
2853

2854
	vha = pci_get_drvdata(ha->pdev);
2855 2856 2857 2858 2859
	/*
	 * Use host_status register to check to PCI disconnection before we
	 * we process the response queue.
	 */
	stat = RD_REG_DWORD(&reg->host_status);
2860
	if (qla2x00_check_reg32_for_disconnect(vha, stat))
2861
		goto out;
2862
	qla24xx_process_response_queue(vha, rsp);
2863
	if (!ha->flags.disable_msix_handshake) {
2864 2865 2866
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
2867
out:
2868
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2869 2870 2871 2872

	return IRQ_HANDLED;
}

2873 2874 2875 2876
static irqreturn_t
qla25xx_msix_rsp_q(int irq, void *dev_id)
{
	struct qla_hw_data *ha;
2877
	scsi_qla_host_t *vha;
2878
	struct rsp_que *rsp;
2879
	struct device_reg_24xx __iomem *reg;
2880
	unsigned long flags;
2881
	uint32_t hccr = 0;
2882 2883 2884

	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2885 2886
		ql_log(ql_log_info, NULL, 0x505b,
		    "%s: NULL response queue pointer.\n", __func__);
2887 2888 2889
		return IRQ_NONE;
	}
	ha = rsp->hw;
2890
	vha = pci_get_drvdata(ha->pdev);
2891

2892
	/* Clear the interrupt, if enabled, for this response queue */
2893
	if (!ha->flags.disable_msix_handshake) {
2894
		reg = &ha->iobase->isp24;
2895
		spin_lock_irqsave(&ha->hardware_lock, flags);
2896
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2897
		hccr = RD_REG_DWORD_RELAXED(&reg->hccr);
2898
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
2899
	}
2900
	if (qla2x00_check_reg32_for_disconnect(vha, hccr))
2901
		goto out;
2902 2903
	queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);

2904
out:
2905 2906 2907
	return IRQ_HANDLED;
}

2908 2909 2910
static irqreturn_t
qla24xx_msix_default(int irq, void *dev_id)
{
2911 2912 2913
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
2914 2915 2916 2917
	struct device_reg_24xx __iomem *reg;
	int		status;
	uint32_t	stat;
	uint32_t	hccr;
2918
	uint16_t	mb[8];
2919
	unsigned long flags;
2920

2921 2922
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
2923 2924
		ql_log(ql_log_info, NULL, 0x505c,
		    "%s: NULL response queue pointer.\n", __func__);
2925 2926 2927
		return IRQ_NONE;
	}
	ha = rsp->hw;
2928 2929 2930
	reg = &ha->iobase->isp24;
	status = 0;

2931
	spin_lock_irqsave(&ha->hardware_lock, flags);
2932
	vha = pci_get_drvdata(ha->pdev);
2933
	do {
2934
		stat = RD_REG_DWORD(&reg->host_status);
2935
		if (qla2x00_check_reg32_for_disconnect(vha, stat))
2936
			break;
2937
		if (stat & HSRX_RISC_PAUSED) {
2938
			if (unlikely(pci_channel_offline(ha->pdev)))
2939 2940
				break;

2941 2942
			hccr = RD_REG_DWORD(&reg->hccr);

2943 2944 2945
			ql_log(ql_log_info, vha, 0x5050,
			    "RISC paused -- HCCR=%x, Dumping firmware.\n",
			    hccr);
2946

2947
			qla2xxx_check_risc_status(vha);
2948

2949 2950
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
2951 2952 2953 2954 2955
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
2956 2957 2958 2959
		case INTR_ROM_MB_SUCCESS:
		case INTR_ROM_MB_FAILED:
		case INTR_MB_SUCCESS:
		case INTR_MB_FAILED:
2960
			qla24xx_mbx_completion(vha, MSW(stat));
2961 2962 2963
			status |= MBX_INTERRUPT;

			break;
2964
		case INTR_ASYNC_EVENT:
2965 2966 2967 2968
			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);
2969
			qla2x00_async_event(vha, rsp, mb);
2970
			break;
2971 2972
		case INTR_RSP_QUE_UPDATE:
		case INTR_RSP_QUE_UPDATE_83XX:
2973
			qla24xx_process_response_queue(vha, rsp);
2974
			break;
2975 2976 2977 2978 2979
		case INTR_ATIO_QUE_UPDATE:{
			unsigned long flags2;
			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
			qlt_24xx_process_atio_queue(vha, 1);
			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);
2980
			break;
2981 2982 2983 2984 2985 2986 2987
		}
		case INTR_ATIO_RSP_QUE_UPDATE: {
			unsigned long flags2;
			spin_lock_irqsave(&ha->tgt.atio_lock, flags2);
			qlt_24xx_process_atio_queue(vha, 1);
			spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2);

2988 2989
			qla24xx_process_response_queue(vha, rsp);
			break;
2990
		}
2991
		default:
2992 2993
			ql_dbg(ql_dbg_async, vha, 0x5051,
			    "Unrecognized interrupt type (%d).\n", stat & 0xff);
2994 2995 2996
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
2997
	} while (0);
2998
	qla2x00_handle_mbx_completion(ha, status);
2999
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
3000 3001 3002 3003 3004 3005 3006 3007

	return IRQ_HANDLED;
}

/* Interrupt handling helpers. */

struct qla_init_msix_entry {
	const char *name;
3008
	irq_handler_t handler;
3009 3010
};

3011
static struct qla_init_msix_entry msix_entries[3] = {
3012 3013
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
3014
	{ "qla2xxx (multiq)", qla25xx_msix_rsp_q },
3015 3016
};

3017 3018 3019 3020 3021
static struct qla_init_msix_entry qla82xx_msix_entries[2] = {
	{ "qla2xxx (default)", qla82xx_msix_default },
	{ "qla2xxx (rsp_q)", qla82xx_msix_rsp_q },
};

3022 3023 3024 3025 3026 3027
static struct qla_init_msix_entry qla83xx_msix_entries[3] = {
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
	{ "qla2xxx (atio_q)", qla83xx_msix_atio_q },
};

3028
static void
3029
qla24xx_disable_msix(struct qla_hw_data *ha)
3030 3031 3032
{
	int i;
	struct qla_msix_entry *qentry;
3033
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
3034

3035 3036
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
3037 3038 3039
		if (qentry->have_irq) {
			/* un-register irq cpu affinity notification */
			irq_set_affinity_notifier(qentry->vector, NULL);
3040
			free_irq(qentry->vector, qentry->rsp);
3041
		}
3042 3043
	}
	pci_disable_msix(ha->pdev);
3044 3045 3046
	kfree(ha->msix_entries);
	ha->msix_entries = NULL;
	ha->flags.msix_enabled = 0;
3047 3048
	ql_dbg(ql_dbg_init, vha, 0x0042,
	    "Disabled the MSI.\n");
3049 3050 3051
}

static int
3052
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
3053
{
3054
#define MIN_MSIX_COUNT	2
3055
#define ATIO_VECTOR	2
3056
	int i, ret;
3057
	struct msix_entry *entries;
3058
	struct qla_msix_entry *qentry;
3059
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
3060 3061

	entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
3062
			GFP_KERNEL);
3063 3064 3065
	if (!entries) {
		ql_log(ql_log_warn, vha, 0x00bc,
		    "Failed to allocate memory for msix_entry.\n");
3066
		return -ENOMEM;
3067
	}
3068

3069 3070
	for (i = 0; i < ha->msix_count; i++)
		entries[i].entry = i;
3071

3072 3073 3074 3075 3076 3077 3078 3079 3080
	ret = pci_enable_msix_range(ha->pdev,
				    entries, MIN_MSIX_COUNT, ha->msix_count);
	if (ret < 0) {
		ql_log(ql_log_fatal, vha, 0x00c7,
		    "MSI-X: Failed to enable support, "
		    "giving   up -- %d/%d.\n",
		    ha->msix_count, ret);
		goto msix_out;
	} else if (ret < ha->msix_count) {
3081 3082 3083 3084
		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);
Q
Quinn Tran 已提交
3085 3086
		ha->msix_count = ret;
		ha->max_rsp_queues = ha->msix_count - 1;
3087 3088 3089 3090
	}
	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
				ha->msix_count, GFP_KERNEL);
	if (!ha->msix_entries) {
3091 3092
		ql_log(ql_log_fatal, vha, 0x00c8,
		    "Failed to allocate memory for ha->msix_entries.\n");
3093
		ret = -ENOMEM;
3094 3095 3096 3097
		goto msix_out;
	}
	ha->flags.msix_enabled = 1;

3098 3099 3100 3101
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
		qentry->vector = entries[i].vector;
		qentry->entry = entries[i].entry;
3102
		qentry->have_irq = 0;
3103
		qentry->rsp = NULL;
3104 3105 3106
		qentry->irq_notify.notify  = qla_irq_affinity_notify;
		qentry->irq_notify.release = qla_irq_affinity_release;
		qentry->cpuid = -1;
3107 3108
	}

3109
	/* Enable MSI-X vectors for the base queue */
3110
	for (i = 0; i < 2; i++) {
3111
		qentry = &ha->msix_entries[i];
3112 3113
		qentry->rsp = rsp;
		rsp->msix = qentry;
3114
		if (IS_P3P_TYPE(ha))
3115 3116 3117
			ret = request_irq(qentry->vector,
				qla82xx_msix_entries[i].handler,
				0, qla82xx_msix_entries[i].name, rsp);
3118
		else
3119 3120 3121
			ret = request_irq(qentry->vector,
				msix_entries[i].handler,
				0, msix_entries[i].name, rsp);
3122 3123 3124
		if (ret)
			goto msix_register_fail;
		qentry->have_irq = 1;
3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136

		/* Register for CPU affinity notification. */
		irq_set_affinity_notifier(qentry->vector, &qentry->irq_notify);

		/* Schedule work (ie. trigger a notification) to read cpu
		 * mask for this specific irq.
		 * kref_get is required because
		* irq_affinity_notify() will do
		* kref_put().
		*/
		kref_get(&qentry->irq_notify.kref);
		schedule_work(&qentry->irq_notify.work);
3137 3138 3139 3140 3141 3142 3143 3144
	}

	/*
	 * If target mode is enable, also request the vector for the ATIO
	 * queue.
	 */
	if (QLA_TGT_MODE_ENABLED() && IS_ATIO_MSIX_CAPABLE(ha)) {
		qentry = &ha->msix_entries[ATIO_VECTOR];
3145 3146
		qentry->rsp = rsp;
		rsp->msix = qentry;
3147 3148 3149
		ret = request_irq(qentry->vector,
			qla83xx_msix_entries[ATIO_VECTOR].handler,
			0, qla83xx_msix_entries[ATIO_VECTOR].name, rsp);
3150
		qentry->have_irq = 1;
3151 3152
	}

3153 3154 3155 3156 3157 3158 3159 3160 3161 3162
msix_register_fail:
	if (ret) {
		ql_log(ql_log_fatal, vha, 0x00cb,
		    "MSI-X: unable to register handler -- %x/%d.\n",
		    qentry->vector, ret);
		qla24xx_disable_msix(ha);
		ha->mqenable = 0;
		goto msix_out;
	}

3163
	/* Enable MSI-X vector for response queue update for queue 0 */
3164
	if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
3165 3166 3167 3168 3169 3170 3171
		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;
3172 3173 3174 3175 3176 3177
	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);
3178

3179
msix_out:
3180
	kfree(entries);
3181 3182 3183 3184
	return ret;
}

int
3185
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
3186
{
3187
	int ret = QLA_FUNCTION_FAILED;
3188
	device_reg_t *reg = ha->iobase;
3189
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
3190 3191

	/* If possible, enable MSI-X. */
3192
	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
3193 3194
	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) && !IS_QLAFX00(ha) &&
	    !IS_QLA27XX(ha))
3195 3196 3197 3198 3199 3200
		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)) {
3201 3202
		ql_log(ql_log_warn, vha, 0x0034,
		    "MSI-X: Unsupported ISP 2432 SSVID/SSDID (0x%X,0x%X).\n",
3203
			ha->pdev->subsystem_vendor,
3204
			ha->pdev->subsystem_device);
3205 3206
		goto skip_msi;
	}
3207

3208
	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX)) {
3209 3210
		ql_log(ql_log_warn, vha, 0x0035,
		    "MSI-X; Unsupported ISP2432 (0x%X, 0x%X).\n",
3211
		    ha->pdev->revision, QLA_MSIX_CHIP_REV_24XX);
3212 3213 3214
		goto skip_msix;
	}

3215
	ret = qla24xx_enable_msix(ha, rsp);
3216
	if (!ret) {
3217 3218 3219
		ql_dbg(ql_dbg_init, vha, 0x0036,
		    "MSI-X: Enabled (0x%X, 0x%X).\n",
		    ha->chip_revision, ha->fw_attributes);
3220
		goto clear_risc_ints;
3221
	}
3222

3223
skip_msix:
3224

3225 3226 3227
	ql_log(ql_log_info, vha, 0x0037,
	    "Falling back-to MSI mode -%d.\n", ret);

3228
	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
3229 3230
	    !IS_QLA8001(ha) && !IS_P3P_TYPE(ha) && !IS_QLAFX00(ha) &&
	    !IS_QLA27XX(ha))
3231 3232 3233 3234
		goto skip_msi;

	ret = pci_enable_msi(ha->pdev);
	if (!ret) {
3235 3236
		ql_dbg(ql_dbg_init, vha, 0x0038,
		    "MSI: Enabled.\n");
3237
		ha->flags.msi_enabled = 1;
3238
	} else
3239
		ql_log(ql_log_warn, vha, 0x0039,
3240 3241
		    "Falling back-to INTa mode -- %d.\n", ret);
skip_msi:
3242 3243 3244 3245 3246

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

3247
	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
3248 3249
	    ha->flags.msi_enabled ? 0 : IRQF_SHARED,
	    QLA2XXX_DRIVER_NAME, rsp);
3250
	if (ret) {
3251
		ql_log(ql_log_warn, vha, 0x003a,
3252 3253
		    "Failed to reserve interrupt %d already in use.\n",
		    ha->pdev->irq);
3254
		goto fail;
3255
	} else if (!ha->flags.msi_enabled) {
3256 3257
		ql_dbg(ql_dbg_init, vha, 0x0125,
		    "INTa mode: Enabled.\n");
3258 3259
		ha->flags.mr_intr_valid = 1;
	}
3260

3261
clear_risc_ints:
3262 3263
	if (IS_FWI2_CAPABLE(ha) || IS_QLAFX00(ha))
		goto fail;
3264

3265
	spin_lock_irq(&ha->hardware_lock);
3266
	WRT_REG_WORD(&reg->isp.semaphore, 0);
3267
	spin_unlock_irq(&ha->hardware_lock);
3268

3269
fail:
3270 3271 3272 3273
	return ret;
}

void
3274
qla2x00_free_irqs(scsi_qla_host_t *vha)
3275
{
3276
	struct qla_hw_data *ha = vha->hw;
3277 3278 3279 3280 3281 3282 3283 3284 3285
	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];
3286 3287 3288

	if (ha->flags.msix_enabled)
		qla24xx_disable_msix(ha);
3289
	else if (ha->flags.msi_enabled) {
3290
		free_irq(ha->pdev->irq, rsp);
3291
		pci_disable_msi(ha->pdev);
3292 3293
	} else
		free_irq(ha->pdev->irq, rsp);
3294
}
3295

3296 3297 3298 3299

int qla25xx_request_irq(struct rsp_que *rsp)
{
	struct qla_hw_data *ha = rsp->hw;
3300
	struct qla_init_msix_entry *intr = &msix_entries[2];
3301
	struct qla_msix_entry *msix = rsp->msix;
3302
	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
3303 3304 3305 3306
	int ret;

	ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
	if (ret) {
3307 3308 3309
		ql_log(ql_log_fatal, vha, 0x00e6,
		    "MSI-X: Unable to register handler -- %x/%d.\n",
		    msix->vector, ret);
3310 3311 3312 3313 3314 3315
		return ret;
	}
	msix->have_irq = 1;
	msix->rsp = rsp;
	return ret;
}
3316 3317 3318 3319 3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 3344 3345 3346 3347


/* irq_set_affinity/irqbalance will trigger notification of cpu mask update */
static void qla_irq_affinity_notify(struct irq_affinity_notify *notify,
	const cpumask_t *mask)
{
	struct qla_msix_entry *e =
		container_of(notify, struct qla_msix_entry, irq_notify);
	struct qla_hw_data *ha;
	struct scsi_qla_host *base_vha;

	/* user is recommended to set mask to just 1 cpu */
	e->cpuid = cpumask_first(mask);

	ha = e->rsp->hw;
	base_vha = pci_get_drvdata(ha->pdev);

	ql_dbg(ql_dbg_init, base_vha, 0xffff,
	    "%s: host %ld : vector %d cpu %d \n", __func__,
	    base_vha->host_no, e->vector, e->cpuid);

	if (e->have_irq) {
		if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) &&
		    (e->entry == QLA83XX_RSPQ_MSIX_ENTRY_NUMBER)) {
			ha->tgt.rspq_vector_cpuid = e->cpuid;
			ql_dbg(ql_dbg_init, base_vha, 0xffff,
			    "%s: host%ld: rspq vector %d cpu %d  runtime change\n",
			    __func__, base_vha->host_no, e->vector, e->cpuid);
		}
	}
}

3348
static void qla_irq_affinity_release(struct kref *ref)
3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359
{
	struct irq_affinity_notify *notify =
		container_of(ref, struct irq_affinity_notify, kref);
	struct qla_msix_entry *e =
		container_of(notify, struct qla_msix_entry, irq_notify);
	struct scsi_qla_host *base_vha = pci_get_drvdata(e->rsp->hw->pdev);

	ql_dbg(ql_dbg_init, base_vha, 0xffff,
	    "%s: host%ld: vector %d cpu %d \n", __func__,
	    base_vha->host_no, e->vector, e->cpuid);
}