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

9
#include <linux/delay.h>
10 11
#include <scsi/scsi_tcq.h>

L
Linus Torvalds 已提交
12
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
13 14 15
static void qla2x00_process_completed_request(struct scsi_qla_host *,
	struct req_que *, uint32_t);
static void qla2x00_status_entry(scsi_qla_host_t *, struct rsp_que *, void *);
16
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
17 18
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
	sts_entry_t *);
19

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

42 43
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
L
Linus Torvalds 已提交
44
		printk(KERN_INFO
45
		    "%s(): NULL response queue pointer\n", __func__);
L
Linus Torvalds 已提交
46 47 48
		return (IRQ_NONE);
	}

49
	ha = rsp->hw;
50
	reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
51 52
	status = 0;

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

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

69 70
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
71 72
			break;
		} else if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
L
Linus Torvalds 已提交
73 74 75 76 77 78 79
			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. */
80 81
			mb[0] = RD_MAILBOX_REG(ha, reg, 0);
			if (mb[0] > 0x3fff && mb[0] < 0x8000) {
82
				qla2x00_mbx_completion(vha, mb[0]);
L
Linus Torvalds 已提交
83
				status |= MBX_INTERRUPT;
84 85 86 87
			} 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);
88
				qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
89 90 91
			} else {
				/*EMPTY*/
				DEBUG2(printk("scsi(%ld): Unrecognized "
92
				    "interrupt type (%d).\n",
93
				    vha->host_no, mb[0]));
L
Linus Torvalds 已提交
94 95 96 97 98
			}
			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			RD_REG_WORD(&reg->semaphore);
		} else {
99
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
100 101 102 103 104

			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
			RD_REG_WORD(&reg->hccr);
		}
	}
105
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
106 107 108 109

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

	return (IRQ_HANDLED);
}

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

139 140
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
L
Linus Torvalds 已提交
141
		printk(KERN_INFO
142
		    "%s(): NULL response queue pointer\n", __func__);
L
Linus Torvalds 已提交
143 144 145
		return (IRQ_NONE);
	}

146
	ha = rsp->hw;
147
	reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
148 149
	status = 0;

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

L
Linus Torvalds 已提交
158 159
			hccr = RD_REG_WORD(&reg->hccr);
			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
160 161
				qla_printk(KERN_INFO, ha, "Parity error -- "
				    "HCCR=%x, Dumping firmware!\n", hccr);
L
Linus Torvalds 已提交
162
			else
163 164
				qla_printk(KERN_INFO, ha, "RISC paused -- "
				    "HCCR=%x, Dumping firmware!\n", hccr);
L
Linus Torvalds 已提交
165 166 167 168 169 170 171 172

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

174 175
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
176 177 178 179 180 181 182 183 184
			break;
		} else if ((stat & HSR_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
185
			qla2x00_mbx_completion(vha, MSW(stat));
L
Linus Torvalds 已提交
186 187 188 189 190 191
			status |= MBX_INTERRUPT;

			/* Release mailbox registers. */
			WRT_REG_WORD(&reg->semaphore, 0);
			break;
		case 0x12:
192 193 194 195
			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);
196
			qla2x00_async_event(vha, rsp, mb);
197 198
			break;
		case 0x13:
199
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
200 201
			break;
		case 0x15:
202 203
			mb[0] = MBA_CMPLT_1_16BIT;
			mb[1] = MSW(stat);
204
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
205 206
			break;
		case 0x16:
207 208 209
			mb[0] = MBA_SCSI_COMPLETION;
			mb[1] = MSW(stat);
			mb[2] = RD_MAILBOX_REG(ha, reg, 2);
210
			qla2x00_async_event(vha, rsp, mb);
L
Linus Torvalds 已提交
211 212 213
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
214
			    "(%d).\n",
215
			    vha->host_no, stat & 0xff));
L
Linus Torvalds 已提交
216 217 218 219 220
			break;
		}
		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
		RD_REG_WORD_RELAXED(&reg->hccr);
	}
221
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
L
Linus Torvalds 已提交
222 223 224 225

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
226
		complete(&ha->mbx_intr_comp);
L
Linus Torvalds 已提交
227 228 229 230 231 232 233 234 235 236 237
	}

	return (IRQ_HANDLED);
}

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

	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
	wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
A
Andrew Vasquez 已提交
251
		if (IS_QLA2200(ha) && cnt == 8)
L
Linus Torvalds 已提交
252 253 254 255 256
			wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
		if (cnt == 4 || cnt == 5)
			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
		else
			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
A
Andrew Vasquez 已提交
257

L
Linus Torvalds 已提交
258 259 260 261 262
		wptr++;
	}

	if (ha->mcp) {
		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
263
		    __func__, vha->host_no, ha->mcp->mb[0]));
L
Linus Torvalds 已提交
264 265
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
266
		    __func__, vha->host_no));
L
Linus Torvalds 已提交
267 268 269
	}
}

270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
static void
qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
{
	static char *event[] =
		{ "Complete", "Request Notification", "Time Extension" };
	int rval;
	struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
	uint16_t __iomem *wptr;
	uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];

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

	DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
	    "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
	    event[aen & 0xff],
	    mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));

	/* Acknowledgement needed? [Notify && non-zero timeout]. */
	timeout = (descr >> 8) & 0xf;
	if (aen != MBA_IDC_NOTIFY || !timeout)
		return;

	DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
	    "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));

	rval = qla2x00_post_idc_ack_work(vha, mb);
	if (rval != QLA_SUCCESS)
		qla_printk(KERN_WARNING, vha->hw,
		    "IDC failed to post ACK.\n");
}

L
Linus Torvalds 已提交
304 305 306
/**
 * qla2x00_async_event() - Process aynchronous events.
 * @ha: SCSI driver HA context
307
 * @mb: Mailbox registers (0 - 3)
L
Linus Torvalds 已提交
308
 */
309
void
310
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
L
Linus Torvalds 已提交
311
{
312
#define LS_UNKNOWN	2
313
	static char	*link_speeds[] = { "1", "2", "?", "4", "8", "10" };
L
Linus Torvalds 已提交
314 315 316 317
	char		*link_speed;
	uint16_t	handle_cnt;
	uint16_t	cnt;
	uint32_t	handles[5];
318
	struct qla_hw_data *ha = vha->hw;
319
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
320 321
	uint32_t	rscn_entry, host_pid;
	uint8_t		rscn_queue_index;
322
	unsigned long	flags;
L
Linus Torvalds 已提交
323 324 325

	/* Setup to process RIO completion. */
	handle_cnt = 0;
326 327
	if (IS_QLA81XX(ha))
		goto skip_rio;
L
Linus Torvalds 已提交
328 329
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:
330
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
331 332 333
		handle_cnt = 1;
		break;
	case MBA_CMPLT_1_16BIT:
334
		handles[0] = mb[1];
L
Linus Torvalds 已提交
335 336 337 338
		handle_cnt = 1;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_2_16BIT:
339 340
		handles[0] = mb[1];
		handles[1] = mb[2];
L
Linus Torvalds 已提交
341 342 343 344
		handle_cnt = 2;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_3_16BIT:
345 346 347
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
348 349 350 351
		handle_cnt = 3;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_4_16BIT:
352 353 354
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
355 356 357 358 359
		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
		handle_cnt = 4;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_5_16BIT:
360 361 362
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
363 364 365 366 367 368
		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:
369
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
370 371 372 373 374 375 376 377 378
		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;
	}
379
skip_rio:
L
Linus Torvalds 已提交
380 381
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:	/* Fast Post */
382
		if (!vha->flags.online)
L
Linus Torvalds 已提交
383 384 385
			break;

		for (cnt = 0; cnt < handle_cnt; cnt++)
386 387
			qla2x00_process_completed_request(vha, rsp->req,
				handles[cnt]);
L
Linus Torvalds 已提交
388 389 390
		break;

	case MBA_RESET:			/* Reset */
391 392
		DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
			vha->host_no));
L
Linus Torvalds 已提交
393

394
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
395 396 397 398 399 400 401
		break;

	case MBA_SYSTEM_ERR:		/* System Error */
		qla_printk(KERN_INFO, ha,
		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
		    mb[1], mb[2], mb[3]);

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

404
		if (IS_FWI2_CAPABLE(ha)) {
405 406 407 408
			if (mb[1] == 0 && mb[2] == 0) {
				qla_printk(KERN_ERR, ha,
				    "Unrecoverable Hardware Error: adapter "
				    "marked OFFLINE!\n");
409
				vha->flags.online = 0;
410
			} else
411
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
412
		} else if (mb[1] == 0) {
L
Linus Torvalds 已提交
413 414 415
			qla_printk(KERN_INFO, ha,
			    "Unrecoverable Hardware Error: adapter marked "
			    "OFFLINE!\n");
416
			vha->flags.online = 0;
L
Linus Torvalds 已提交
417
		} else
418
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
419 420 421 422
		break;

	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
		DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",
423
		    vha->host_no));
L
Linus Torvalds 已提交
424 425
		qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");

426
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
427 428 429 430
		break;

	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
		DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
431
		    vha->host_no));
L
Linus Torvalds 已提交
432 433
		qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");

434
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
435 436 437 438
		break;

	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
		DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
439
		    vha->host_no));
L
Linus Torvalds 已提交
440 441 442
		break;

	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
443
		DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
L
Linus Torvalds 已提交
444
		    mb[1]));
445
		qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
L
Linus Torvalds 已提交
446

447 448 449 450
		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 已提交
451 452
		}

453 454 455
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
456 457
		}

458 459
		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
460

461 462
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
L
Linus Torvalds 已提交
463 464 465 466 467
		break;

	case MBA_LOOP_UP:		/* Loop Up Event */
		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
			link_speed = link_speeds[0];
468
			ha->link_data_rate = PORT_SPEED_1GB;
L
Linus Torvalds 已提交
469
		} else {
470
			link_speed = link_speeds[LS_UNKNOWN];
L
Linus Torvalds 已提交
471 472
			if (mb[1] < 5)
				link_speed = link_speeds[mb[1]];
473 474
			else if (mb[1] == 0x13)
				link_speed = link_speeds[5];
L
Linus Torvalds 已提交
475 476 477 478
			ha->link_data_rate = mb[1];
		}

		DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
479
		    vha->host_no, link_speed));
L
Linus Torvalds 已提交
480 481 482
		qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
		    link_speed);

483 484
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
L
Linus Torvalds 已提交
485 486 487
		break;

	case MBA_LOOP_DOWN:		/* Loop Down Event */
488
		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
489
		    "(%x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3]));
490 491
		qla_printk(KERN_INFO, ha, "LOOP DOWN detected (%x %x %x).\n",
		    mb[1], mb[2], mb[3]);
L
Linus Torvalds 已提交
492

493 494 495 496 497
		if (atomic_read(&vha->loop_state) != LOOP_DOWN) {
			atomic_set(&vha->loop_state, LOOP_DOWN);
			atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
			vha->device_flags |= DFLG_NO_CABLE;
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
498 499
		}

500 501 502
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
503 504
		}

505
		vha->flags.management_server_logged_in = 0;
506
		ha->link_data_rate = PORT_SPEED_UNKNOWN;
507
		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
L
Linus Torvalds 已提交
508 509 510 511
		break;

	case MBA_LIP_RESET:		/* LIP reset occurred */
		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
512
		    vha->host_no, mb[1]));
L
Linus Torvalds 已提交
513
		qla_printk(KERN_INFO, ha,
514
		    "LIP reset occurred (%x).\n", mb[1]);
L
Linus Torvalds 已提交
515

516 517 518 519
		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 已提交
520 521
		}

522 523 524
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
525 526
		}

527
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
528 529

		ha->operating_mode = LOOP;
530 531
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
L
Linus Torvalds 已提交
532 533
		break;

534
	/* case MBA_DCBX_COMPLETE: */
L
Linus Torvalds 已提交
535 536 537 538
	case MBA_POINT_TO_POINT:	/* Point-to-Point */
		if (IS_QLA2100(ha))
			break;

539 540 541 542 543 544
		if (IS_QLA81XX(ha))
			DEBUG2(printk("scsi(%ld): DCBX Completed -- %04x %04x "
			    "%04x\n", vha->host_no, mb[1], mb[2], mb[3]));
		else
			DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE "
			    "received.\n", vha->host_no));
L
Linus Torvalds 已提交
545 546 547 548 549

		/*
		 * Until there's a transition from loop down to loop up, treat
		 * this as loop down only.
		 */
550 551 552 553
		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 已提交
554
				    LOOP_DOWN_TIME);
555
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
556 557
		}

558 559 560
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
561 562
		}

563 564 565 566 567
		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);
568 569

		ha->flags.gpsc_supported = 1;
570
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
571 572 573 574 575 576 577 578
		break;

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

		DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
		    "received.\n",
579
		    vha->host_no));
L
Linus Torvalds 已提交
580 581 582
		qla_printk(KERN_INFO, ha,
		    "Configuration change detected: value=%x.\n", mb[1]);

583 584 585 586
		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 已提交
587
				    LOOP_DOWN_TIME);
588
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
589 590
		}

591 592 593
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
594 595
		}

596 597
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
598 599 600
		break;

	case MBA_PORT_UPDATE:		/* Port database update */
601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620
		/*
		 * 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
		 */
		if ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff)
			|| (mb[1] != 0xffff)) {
			if (vha->vp_idx != (mb[3] & 0xff))
				break;
		}
621

622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641
		/* Global event -- port logout or port unavailable. */
		if (mb[1] == 0xffff && mb[2] == 0x7) {
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
			    vha->host_no));
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Port unavailable %04x %04x %04x.\n",
			    vha->host_no, mb[1], mb[2], mb[3]));

			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);
642
				qla2x00_mark_all_devices_lost(vha, 1);
643 644 645 646 647 648 649
			}

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

L
Linus Torvalds 已提交
650
		/*
651
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
L
Linus Torvalds 已提交
652 653 654
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
655 656 657
		atomic_set(&vha->loop_down_timer, 0);
		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
L
Linus Torvalds 已提交
658
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
659
			    "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
660
			    mb[2], mb[3]));
L
Linus Torvalds 已提交
661 662 663 664
			break;
		}

		DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
665
		    vha->host_no));
L
Linus Torvalds 已提交
666
		DEBUG(printk(KERN_INFO
667
		    "scsi(%ld): Port database changed %04x %04x %04x.\n",
668
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
669 670 671 672

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

675
		qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
676

677
		vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
678

679 680
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
681 682 683
		break;

	case MBA_RSCN_UPDATE:		/* State Change Registration */
684
		/* Check if the Vport has issued a SCR */
685
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
686 687
			break;
		/* Only handle SCNs for our Vport index. */
688
		if (vha->vp_idx != (mb[3] & 0xff))
689
			break;
L
Linus Torvalds 已提交
690
		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
691
		    vha->host_no));
L
Linus Torvalds 已提交
692
		DEBUG(printk(KERN_INFO
693
		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
694
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
695

696
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
697 698
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
L
Linus Torvalds 已提交
699 700 701 702
		if (rscn_entry == host_pid) {
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Ignoring RSCN update to local host "
			    "port ID (%06x)\n",
703
			    vha->host_no, host_pid));
L
Linus Torvalds 已提交
704 705 706
			break;
		}

707 708
		/* Ignore reserved bits from RSCN-payload. */
		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
709
		rscn_queue_index = vha->rscn_in_ptr + 1;
L
Linus Torvalds 已提交
710 711
		if (rscn_queue_index == MAX_RSCN_COUNT)
			rscn_queue_index = 0;
712 713 714
		if (rscn_queue_index != vha->rscn_out_ptr) {
			vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
			vha->rscn_in_ptr = rscn_queue_index;
L
Linus Torvalds 已提交
715
		} else {
716
			vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
717 718
		}

719 720 721
		atomic_set(&vha->loop_state, LOOP_UPDATE);
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
722

723 724 725
		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 已提交
726 727 728 729
		break;

	/* case MBA_RIO_RESPONSE: */
	case MBA_ZIO_RESPONSE:
730
		DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
731
		    vha->host_no));
L
Linus Torvalds 已提交
732

733
		if (IS_FWI2_CAPABLE(ha))
734
			qla24xx_process_response_queue(vha, rsp);
735
		else
736
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
737
		break;
738 739 740

	case MBA_DISCARD_RND_FRAME:
		DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
741
		    "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
742
		break;
743 744 745

	case MBA_TRACE_NOTIFICATION:
		DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
746
		vha->host_no, mb[1], mb[2]));
747
		break;
748 749 750

	case MBA_ISP84XX_ALERT:
		DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
751
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783

		spin_lock_irqsave(&ha->cs84xx->access_lock, flags);
		switch (mb[1]) {
		case A84_PANIC_RECOVERY:
			qla_printk(KERN_INFO, ha, "Alert 84XX: panic recovery "
			    "%04x %04x\n", mb[2], mb[3]);
			break;
		case A84_OP_LOGIN_COMPLETE:
			ha->cs84xx->op_fw_version = mb[3] << 16 | mb[2];
			DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
			    "firmware version %x\n", ha->cs84xx->op_fw_version));
			break;
		case A84_DIAG_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
			DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX:"
			    "diagnostic firmware version %x\n",
			    ha->cs84xx->diag_fw_version));
			break;
		case A84_GOLD_LOGIN_COMPLETE:
			ha->cs84xx->diag_fw_version = mb[3] << 16 | mb[2];
			ha->cs84xx->fw_update = 1;
			DEBUG2(qla_printk(KERN_INFO, ha, "Alert 84XX: gold "
			    "firmware version %x\n",
			    ha->cs84xx->gold_fw_version));
			break;
		default:
			qla_printk(KERN_ERR, ha,
			    "Alert 84xx: Invalid Alert %04x %04x %04x\n",
			    mb[1], mb[2], mb[3]);
		}
		spin_unlock_irqrestore(&ha->cs84xx->access_lock, flags);
		break;
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
	case MBA_DCBX_START:
		DEBUG2(printk("scsi(%ld): DCBX Started -- %04x %04x %04x\n",
		    vha->host_no, mb[1], mb[2], mb[3]));
		break;
	case MBA_DCBX_PARAM_UPDATE:
		DEBUG2(printk("scsi(%ld): DCBX Parameters Updated -- "
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
		break;
	case MBA_FCF_CONF_ERR:
		DEBUG2(printk("scsi(%ld): FCF Configuration Error -- "
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
		break;
	case MBA_IDC_COMPLETE:
	case MBA_IDC_NOTIFY:
	case MBA_IDC_TIME_EXT:
799
		qla81xx_idc_event(vha, mb[0], mb[1]);
800
		break;
L
Linus Torvalds 已提交
801
	}
802

803
	if (!vha->vp_idx && ha->num_vhosts)
804
		qla2x00_alert_all_vps(rsp, mb);
L
Linus Torvalds 已提交
805 806
}

807 808 809 810
static void
qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
{
	fc_port_t *fcport = data;
811 812 813 814
	struct scsi_qla_host *vha = fcport->vha;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req = NULL;

815 816 817
	if (!ql2xqfulltracking)
		return;

818
	req = vha->req;
819 820 821
	if (!req)
		return;
	if (req->max_q_depth <= sdev->queue_depth)
822 823 824 825 826 827 828 829 830 831 832
		return;

	if (sdev->ordered_tags)
		scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
		    sdev->queue_depth + 1);
	else
		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG,
		    sdev->queue_depth + 1);

	fcport->last_ramp_up = jiffies;

833
	DEBUG2(qla_printk(KERN_INFO, ha,
834
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
835
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
836 837 838 839 840 841 842 843 844 845 846
	    sdev->queue_depth));
}

static void
qla2x00_adjust_sdev_qdepth_down(struct scsi_device *sdev, void *data)
{
	fc_port_t *fcport = data;

	if (!scsi_track_queue_full(sdev, sdev->queue_depth - 1))
		return;

847
	DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
848
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
849
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
850 851 852 853
	    sdev->queue_depth));
}

static inline void
854 855
qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
								srb_t *sp)
856 857 858 859
{
	fc_port_t *fcport;
	struct scsi_device *sdev;

860 861 862
	if (!ql2xqfulltracking)
		return;

863
	sdev = sp->cmd->device;
864
	if (sdev->queue_depth >= req->max_q_depth)
865 866 867 868 869 870 871 872 873 874 875 876 877 878
		return;

	fcport = sp->fcport;
	if (time_before(jiffies,
	    fcport->last_ramp_up + ql2xqfullrampup * HZ))
		return;
	if (time_before(jiffies,
	    fcport->last_queue_full + ql2xqfullrampup * HZ))
		return;

	starget_for_each_device(sdev->sdev_target, fcport,
	    qla2x00_adjust_sdev_qdepth_up);
}

L
Linus Torvalds 已提交
879 880 881 882 883 884
/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
static void
885 886
qla2x00_process_completed_request(struct scsi_qla_host *vha,
				struct req_que *req, uint32_t index)
L
Linus Torvalds 已提交
887 888
{
	srb_t *sp;
889
	struct qla_hw_data *ha = vha->hw;
L
Linus Torvalds 已提交
890 891 892 893

	/* Validate handle. */
	if (index >= MAX_OUTSTANDING_COMMANDS) {
		DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
894
		    vha->host_no, index));
L
Linus Torvalds 已提交
895 896 897
		qla_printk(KERN_WARNING, ha,
		    "Invalid SCSI completion handle %d.\n", index);

898
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
899 900 901
		return;
	}

902
	sp = req->outstanding_cmds[index];
L
Linus Torvalds 已提交
903 904
	if (sp) {
		/* Free outstanding command slot. */
905
		req->outstanding_cmds[index] = NULL;
L
Linus Torvalds 已提交
906 907 908

		/* Save ISP completion status */
		sp->cmd->result = DID_OK << 16;
909

910 911
		qla2x00_ramp_up_queue_depth(vha, req, sp);
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
912
	} else {
913 914
		DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
			" handle(%d)\n", vha->host_no, req->id, index));
L
Linus Torvalds 已提交
915 916 917
		qla_printk(KERN_WARNING, ha,
		    "Invalid ISP SCSI completion handle\n");

918
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
919 920 921 922 923 924 925 926
	}
}

/**
 * qla2x00_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
927
qla2x00_process_response_queue(struct rsp_que *rsp)
L
Linus Torvalds 已提交
928
{
929 930
	struct scsi_qla_host *vha;
	struct qla_hw_data *ha = rsp->hw;
931
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
932 933 934
	sts_entry_t	*pkt;
	uint16_t        handle_cnt;
	uint16_t        cnt;
935

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

938
	if (!vha->flags.online)
L
Linus Torvalds 已提交
939 940
		return;

941 942
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (sts_entry_t *)rsp->ring_ptr;
L
Linus Torvalds 已提交
943

944 945 946 947
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
L
Linus Torvalds 已提交
948
		} else {
949
			rsp->ring_ptr++;
L
Linus Torvalds 已提交
950 951 952 953
		}

		if (pkt->entry_status != 0) {
			DEBUG3(printk(KERN_INFO
954
			    "scsi(%ld): Process error entry.\n", vha->host_no));
L
Linus Torvalds 已提交
955

956
			qla2x00_error_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
957 958 959 960 961 962 963
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
964
			qla2x00_status_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
965 966 967 968
			break;
		case STATUS_TYPE_21:
			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
969
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
970 971 972 973 974 975
				    ((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++) {
976
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
977 978 979 980
				    ((sts22_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_CONT_TYPE:
981
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
L
Linus Torvalds 已提交
982 983 984 985 986 987
			break;
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
988
			    vha->host_no, pkt->entry_type, pkt->entry_status));
L
Linus Torvalds 已提交
989 990 991 992 993 994 995
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

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

999
static inline void
1000 1001
qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len,
	struct rsp_que *rsp)
1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017
{
	struct scsi_cmnd *cp = sp->cmd;

	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
		sense_len = SCSI_SENSE_BUFFERSIZE;

	sp->request_sense_length = sense_len;
	sp->request_sense_ptr = cp->sense_buffer;
	if (sp->request_sense_length > 32)
		sense_len = 32;

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

	sp->request_sense_ptr += sense_len;
	sp->request_sense_length -= sense_len;
	if (sp->request_sense_length != 0)
1018
		rsp->status_srb = sp;
1019 1020

	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
1021
	    "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
1022 1023
	    cp->device->channel, cp->device->id, cp->device->lun, cp,
	    cp->serial_number));
1024
	if (sense_len)
1025
		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer, sense_len));
1026 1027
}

L
Linus Torvalds 已提交
1028 1029 1030 1031 1032 1033
/**
 * qla2x00_status_entry() - Process a Status IOCB entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
1034
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
L
Linus Torvalds 已提交
1035 1036 1037 1038
{
	srb_t		*sp;
	fc_port_t	*fcport;
	struct scsi_cmnd *cp;
1039 1040
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
L
Linus Torvalds 已提交
1041 1042 1043 1044
	uint16_t	comp_status;
	uint16_t	scsi_status;
	uint8_t		lscsi_status;
	int32_t		resid;
1045
	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len;
1046
	uint8_t		*rsp_info, *sense_data;
1047
	struct qla_hw_data *ha = vha->hw;
1048 1049 1050
	uint32_t handle;
	uint16_t que;
	struct req_que *req;
1051 1052 1053

	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;
1054
	if (IS_FWI2_CAPABLE(ha)) {
1055 1056 1057 1058 1059 1060
		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;
	}
1061 1062 1063
	handle = (uint32_t) LSW(sts->handle);
	que = MSW(sts->handle);
	req = ha->req_q_map[que];
L
Linus Torvalds 已提交
1064
	/* Fast path completion. */
1065
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
1066
		qla2x00_process_completed_request(vha, req, handle);
L
Linus Torvalds 已提交
1067 1068 1069 1070 1071

		return;
	}

	/* Validate handle. */
1072 1073 1074
	if (handle < MAX_OUTSTANDING_COMMANDS) {
		sp = req->outstanding_cmds[handle];
		req->outstanding_cmds[handle] = NULL;
L
Linus Torvalds 已提交
1075 1076 1077 1078 1079
	} else
		sp = NULL;

	if (sp == NULL) {
		DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
1080
		    vha->host_no));
L
Linus Torvalds 已提交
1081 1082
		qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");

1083 1084
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1085 1086 1087 1088 1089
		return;
	}
	cp = sp->cmd;
	if (cp == NULL) {
		DEBUG2(printk("scsi(%ld): Command already returned back to OS "
1090
		    "pkt->handle=%d sp=%p.\n", vha->host_no, handle, sp));
L
Linus Torvalds 已提交
1091 1092 1093 1094 1095 1096
		qla_printk(KERN_WARNING, ha,
		    "Command is NULL: already returned to OS (sp=%p)\n", sp);

		return;
	}

1097
  	lscsi_status = scsi_status & STATUS_MASK;
L
Linus Torvalds 已提交
1098

1099
	fcport = sp->fcport;
L
Linus Torvalds 已提交
1100

1101
	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
1102
	if (IS_FWI2_CAPABLE(ha)) {
1103 1104 1105
		sense_len = le32_to_cpu(sts24->sense_len);
		rsp_info_len = le32_to_cpu(sts24->rsp_data_len);
		resid_len = le32_to_cpu(sts24->rsp_residual_count);
1106
		fw_resid_len = le32_to_cpu(sts24->residual_len);
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117
		rsp_info = sts24->data;
		sense_data = sts24->data;
		host_to_fcp_swap(sts24->data, sizeof(sts24->data));
	} else {
		sense_len = le16_to_cpu(sts->req_sense_length);
		rsp_info_len = le16_to_cpu(sts->rsp_info_len);
		resid_len = le32_to_cpu(sts->residual_length);
		rsp_info = sts->rsp_info;
		sense_data = sts->req_sense_data;
	}

L
Linus Torvalds 已提交
1118 1119
	/* Check for any FCP transport errors. */
	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
1120
		/* Sense data lies beyond any FCP RESPONSE data. */
1121
		if (IS_FWI2_CAPABLE(ha))
1122 1123
			sense_data += rsp_info_len;
		if (rsp_info_len > 3 && rsp_info[3]) {
L
Linus Torvalds 已提交
1124 1125
			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
1126
			    "retrying command\n", vha->host_no,
1127 1128 1129 1130
			    cp->device->channel, cp->device->id,
			    cp->device->lun, rsp_info_len, rsp_info[0],
			    rsp_info[1], rsp_info[2], rsp_info[3], rsp_info[4],
			    rsp_info[5], rsp_info[6], rsp_info[7]));
L
Linus Torvalds 已提交
1131 1132

			cp->result = DID_BUS_BUSY << 16;
1133
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1134 1135 1136 1137
			return;
		}
	}

1138 1139 1140 1141 1142
	/* Check for overrun. */
	if (IS_FWI2_CAPABLE(ha) && comp_status == CS_COMPLETE &&
	    scsi_status & SS_RESIDUAL_OVER)
		comp_status = CS_DATA_OVERRUN;

L
Linus Torvalds 已提交
1143 1144 1145 1146 1147
	/*
	 * Based on Host and scsi status generate status code for Linux
	 */
	switch (comp_status) {
	case CS_COMPLETE:
1148
	case CS_QUEUE_FULL:
L
Linus Torvalds 已提交
1149 1150 1151 1152 1153
		if (scsi_status == 0) {
			cp->result = DID_OK << 16;
			break;
		}
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
1154
			resid = resid_len;
1155
			scsi_set_resid(cp, resid);
1156 1157

			if (!lscsi_status &&
1158
			    ((unsigned)(scsi_bufflen(cp) - resid) <
1159 1160
			     cp->underflow)) {
				qla_printk(KERN_INFO, ha,
1161 1162
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1163
					   "error status.\n", vha->host_no,
1164 1165 1166
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
1167 1168 1169 1170

				cp->result = DID_ERROR << 16;
				break;
			}
L
Linus Torvalds 已提交
1171 1172 1173
		}
		cp->result = DID_OK << 16 | lscsi_status;

1174 1175 1176
		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld): QUEUE FULL status detected "
1177
			    "0x%x-0x%x.\n", vha->host_no, comp_status,
1178 1179 1180
			    scsi_status));

			/* Adjust queue depth for all luns on the port. */
1181 1182
			if (!ql2xqfulltracking)
				break;
1183 1184 1185 1186 1187
			fcport->last_queue_full = jiffies;
			starget_for_each_device(cp->device->sdev_target,
			    fcport, qla2x00_adjust_sdev_qdepth_down);
			break;
		}
L
Linus Torvalds 已提交
1188 1189 1190
		if (lscsi_status != SS_CHECK_CONDITION)
			break;

1191
		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
1192 1193 1194
		if (!(scsi_status & SS_SENSE_LEN_VALID))
			break;

1195
		qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
L
Linus Torvalds 已提交
1196 1197 1198
		break;

	case CS_DATA_UNDERRUN:
1199
		resid = resid_len;
1200
		/* Use F/W calculated residual length. */
1201
		if (IS_FWI2_CAPABLE(ha)) {
1202 1203 1204
			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
				lscsi_status = 0;
			} else if (resid != fw_resid_len) {
1205 1206 1207
				scsi_status &= ~SS_RESIDUAL_UNDER;
				lscsi_status = 0;
			}
1208
			resid = fw_resid_len;
1209
		}
1210

L
Linus Torvalds 已提交
1211
		if (scsi_status & SS_RESIDUAL_UNDER) {
1212
			scsi_set_resid(cp, resid);
1213 1214 1215
		} else {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d) UNDERRUN status detected "
1216
			    "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
1217
			    "os_underflow=0x%x\n", vha->host_no,
1218 1219 1220
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status, resid_len, resid, cp->cmnd[0],
			    cp->underflow));
1221

L
Linus Torvalds 已提交
1222 1223 1224
		}

		/*
A
Andrew Vasquez 已提交
1225
		 * Check to see if SCSI Status is non zero. If so report SCSI
L
Linus Torvalds 已提交
1226 1227 1228 1229 1230
		 * Status.
		 */
		if (lscsi_status != 0) {
			cp->result = DID_OK << 16 | lscsi_status;

1231 1232 1233
			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
				DEBUG2(printk(KERN_INFO
				    "scsi(%ld): QUEUE FULL status detected "
1234
				    "0x%x-0x%x.\n", vha->host_no, comp_status,
1235 1236 1237 1238 1239 1240
				    scsi_status));

				/*
				 * Adjust queue depth for all luns on the
				 * port.
				 */
1241 1242
				if (!ql2xqfulltracking)
					break;
1243 1244 1245 1246 1247 1248
				fcport->last_queue_full = jiffies;
				starget_for_each_device(
				    cp->device->sdev_target, fcport,
				    qla2x00_adjust_sdev_qdepth_down);
				break;
			}
L
Linus Torvalds 已提交
1249 1250 1251
			if (lscsi_status != SS_CHECK_CONDITION)
				break;

1252
			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
1253 1254 1255
			if (!(scsi_status & SS_SENSE_LEN_VALID))
				break;

1256
			qla2x00_handle_sense(sp, sense_data, sense_len, rsp);
L
Linus Torvalds 已提交
1257 1258 1259 1260
		} else {
			/*
			 * If RISC reports underrun and target does not report
			 * it then we must have a lost frame, so tell upper
1261
			 * layer to retry it by reporting an error.
L
Linus Torvalds 已提交
1262 1263 1264
			 */
			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
				DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
1265
					      "frame(s) detected (%x of %x bytes)..."
1266 1267 1268 1269
					      "retrying command.\n",
					vha->host_no, cp->device->channel,
					cp->device->id, cp->device->lun, resid,
					scsi_bufflen(cp)));
L
Linus Torvalds 已提交
1270

1271
				scsi_set_resid(cp, resid);
1272
				cp->result = DID_ERROR << 16;
L
Linus Torvalds 已提交
1273 1274 1275 1276
				break;
			}

			/* Handle mid-layer underflow */
1277
			if ((unsigned)(scsi_bufflen(cp) - resid) <
L
Linus Torvalds 已提交
1278 1279
			    cp->underflow) {
				qla_printk(KERN_INFO, ha,
1280 1281
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1282
					   "error status.\n", vha->host_no,
1283 1284 1285
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
L
Linus Torvalds 已提交
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298

				cp->result = DID_ERROR << 16;
				break;
			}

			/* Everybody online, looking good... */
			cp->result = DID_OK << 16;
		}
		break;

	case CS_DATA_OVERRUN:
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
1299
		    vha->host_no, cp->device->id, cp->device->lun, comp_status,
1300
		    scsi_status));
L
Linus Torvalds 已提交
1301 1302 1303 1304 1305 1306 1307
		DEBUG2(printk(KERN_INFO
		    "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
		    cp->cmnd[4], cp->cmnd[5]));
		DEBUG2(printk(KERN_INFO
		    "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
		    "status!\n",
1308
		    cp->serial_number, scsi_bufflen(cp), resid_len));
L
Linus Torvalds 已提交
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324

		cp->result = DID_ERROR << 16;
		break;

	case CS_PORT_LOGGED_OUT:
	case CS_PORT_CONFIG_CHG:
	case CS_PORT_BUSY:
	case CS_INCOMPLETE:
	case CS_PORT_UNAVAILABLE:
		/*
		 * If the port is in Target Down state, return all IOs for this
		 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
		 * retry_queue.
		 */
		DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
		    "pid=%ld, compl status=0x%x, port state=0x%x\n",
1325
		    vha->host_no, cp->device->id, cp->device->lun,
1326
		    cp->serial_number, comp_status,
L
Linus Torvalds 已提交
1327 1328
		    atomic_read(&fcport->state)));

1329 1330 1331 1332 1333 1334
		/*
		 * 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.
		 */
		cp->result = DID_TRANSPORT_DISRUPTED << 16;
1335
		if (atomic_read(&fcport->state) == FCS_ONLINE)
1336
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1337 1338 1339 1340 1341
		break;

	case CS_RESET:
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
1342
		    vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1343

已提交
1344
		cp->result = DID_RESET << 16;
L
Linus Torvalds 已提交
1345 1346 1347
		break;

	case CS_ABORTED:
A
Andrew Vasquez 已提交
1348
		/*
L
Linus Torvalds 已提交
1349 1350 1351 1352 1353 1354
		 * hv2.19.12 - DID_ABORT does not retry the request if we
		 * aborted this request then abort otherwise it must be a
		 * reset.
		 */
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
1355
		    vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1356 1357 1358 1359 1360

		cp->result = DID_RESET << 16;
		break;

	case CS_TIMEOUT:
1361 1362 1363 1364 1365 1366
		/*
		 * 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.
		 */
		cp->result = DID_TRANSPORT_DISRUPTED << 16;
1367

1368
		if (IS_FWI2_CAPABLE(ha)) {
1369 1370
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
1371
			    "0x%x-0x%x\n", vha->host_no, cp->device->channel,
1372 1373 1374 1375
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status));
			break;
		}
L
Linus Torvalds 已提交
1376 1377
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
1378
		    "sflags=%x.\n", vha->host_no, cp->device->channel,
1379 1380
		    cp->device->id, cp->device->lun, comp_status, scsi_status,
		    le16_to_cpu(sts->status_flags)));
L
Linus Torvalds 已提交
1381

1382 1383
		/* Check to see if logout occurred. */
		if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
1384
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1385 1386 1387 1388
		break;

	default:
		DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
1389
		    "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1390 1391 1392 1393 1394 1395 1396 1397 1398
		qla_printk(KERN_INFO, ha,
		    "Unknown status detected 0x%x-0x%x.\n",
		    comp_status, scsi_status);

		cp->result = DID_ERROR << 16;
		break;
	}

	/* Place command on done queue. */
1399
	if (rsp->status_srb == NULL)
1400
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410
}

/**
 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 *
 * Extended sense data.
 */
static void
1411
qla2x00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt)
L
Linus Torvalds 已提交
1412 1413
{
	uint8_t		sense_sz = 0;
1414 1415
	struct qla_hw_data *ha = rsp->hw;
	srb_t		*sp = rsp->status_srb;
L
Linus Torvalds 已提交
1416 1417 1418 1419 1420 1421
	struct scsi_cmnd *cp;

	if (sp != NULL && sp->request_sense_length != 0) {
		cp = sp->cmd;
		if (cp == NULL) {
			DEBUG2(printk("%s(): Cmd already returned back to OS "
1422
			    "sp=%p.\n", __func__, sp));
L
Linus Torvalds 已提交
1423 1424
			qla_printk(KERN_INFO, ha,
			    "cmd is NULL: already returned to OS (sp=%p)\n",
A
Andrew Vasquez 已提交
1425
			    sp);
L
Linus Torvalds 已提交
1426

1427
			rsp->status_srb = NULL;
L
Linus Torvalds 已提交
1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
			return;
		}

		if (sp->request_sense_length > sizeof(pkt->data)) {
			sense_sz = sizeof(pkt->data);
		} else {
			sense_sz = sp->request_sense_length;
		}

		/* Move sense data. */
1438
		if (IS_FWI2_CAPABLE(ha))
1439
			host_to_fcp_swap(pkt->data, sizeof(pkt->data));
L
Linus Torvalds 已提交
1440 1441 1442 1443 1444 1445 1446 1447
		memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
		DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));

		sp->request_sense_ptr += sense_sz;
		sp->request_sense_length -= sense_sz;

		/* Place command on done queue. */
		if (sp->request_sense_length == 0) {
1448
			rsp->status_srb = NULL;
1449
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1450 1451 1452 1453 1454 1455 1456 1457 1458 1459
		}
	}
}

/**
 * qla2x00_error_entry() - Process an error entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
1460
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
L
Linus Torvalds 已提交
1461 1462
{
	srb_t *sp;
1463
	struct qla_hw_data *ha = vha->hw;
1464 1465 1466
	uint32_t handle = LSW(pkt->handle);
	uint16_t que = MSW(pkt->handle);
	struct req_que *req = ha->req_q_map[que];
L
Linus Torvalds 已提交
1467 1468 1469 1470 1471 1472
#if defined(QL_DEBUG_LEVEL_2)
	if (pkt->entry_status & RF_INV_E_ORDER)
		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
	else if (pkt->entry_status & RF_INV_E_COUNT)
		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
	else if (pkt->entry_status & RF_INV_E_PARAM)
A
Andrew Vasquez 已提交
1473
		qla_printk(KERN_ERR, ha,
L
Linus Torvalds 已提交
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483
		    "%s: Invalid Entry Parameter\n", __func__);
	else if (pkt->entry_status & RF_INV_E_TYPE)
		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
	else if (pkt->entry_status & RF_BUSY)
		qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
	else
		qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
#endif

	/* Validate handle. */
1484 1485
	if (handle < MAX_OUTSTANDING_COMMANDS)
		sp = req->outstanding_cmds[handle];
L
Linus Torvalds 已提交
1486 1487 1488 1489 1490
	else
		sp = NULL;

	if (sp) {
		/* Free outstanding command slot. */
1491
		req->outstanding_cmds[handle] = NULL;
1492

L
Linus Torvalds 已提交
1493 1494 1495 1496 1497 1498 1499 1500 1501 1502
		/* Bad payload or header */
		if (pkt->entry_status &
		    (RF_INV_E_ORDER | RF_INV_E_COUNT |
		     RF_INV_E_PARAM | RF_INV_E_TYPE)) {
			sp->cmd->result = DID_ERROR << 16;
		} else if (pkt->entry_status & RF_BUSY) {
			sp->cmd->result = DID_BUS_BUSY << 16;
		} else {
			sp->cmd->result = DID_ERROR << 16;
		}
1503
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1504

1505 1506
	} else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
	    COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
L
Linus Torvalds 已提交
1507
		DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
1508
		    vha->host_no));
L
Linus Torvalds 已提交
1509 1510 1511
		qla_printk(KERN_WARNING, ha,
		    "Error entry - invalid handle\n");

1512 1513
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1514 1515 1516
	}
}

1517 1518 1519 1520 1521 1522
/**
 * qla24xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
1523
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
1524 1525 1526
{
	uint16_t	cnt;
	uint16_t __iomem *wptr;
1527
	struct qla_hw_data *ha = vha->hw;
1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

	/* Load return mailbox registers. */
	ha->flags.mbox_int = 1;
	ha->mailbox_out[0] = mb0;
	wptr = (uint16_t __iomem *)&reg->mailbox1;

	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
		ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
		wptr++;
	}

	if (ha->mcp) {
		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
1542
		    __func__, vha->host_no, ha->mcp->mb[0]));
1543 1544
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
1545
		    __func__, vha->host_no));
1546 1547 1548 1549 1550 1551 1552
	}
}

/**
 * qla24xx_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
1553 1554
void qla24xx_process_response_queue(struct scsi_qla_host *vha,
	struct rsp_que *rsp)
1555 1556 1557
{
	struct sts_entry_24xx *pkt;

1558
	if (!vha->flags.online)
1559 1560
		return;

1561 1562
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
1563

1564 1565 1566 1567
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
1568
		} else {
1569
			rsp->ring_ptr++;
1570 1571 1572 1573
		}

		if (pkt->entry_status != 0) {
			DEBUG3(printk(KERN_INFO
1574
			    "scsi(%ld): Process error entry.\n", vha->host_no));
1575

1576
			qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
1577 1578 1579 1580 1581 1582 1583
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
1584
			qla2x00_status_entry(vha, rsp, pkt);
1585 1586
			break;
		case STATUS_CONT_TYPE:
1587
			qla2x00_status_cont_entry(rsp, (sts_cont_entry_t *)pkt);
1588
			break;
1589
		case VP_RPT_ID_IOCB_TYPE:
1590
			qla24xx_report_id_acquisition(vha,
1591 1592
			    (struct vp_rpt_id_entry_24xx *)pkt);
			break;
1593 1594 1595 1596 1597
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
1598
			    vha->host_no, pkt->entry_type, pkt->entry_status));
1599 1600 1601 1602 1603 1604 1605
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
1606
	WRT_REG_DWORD(rsp->rsp_q_out, rsp->ring_index);
1607 1608
}

1609
static void
1610
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
1611 1612 1613
{
	int rval;
	uint32_t cnt;
1614
	struct qla_hw_data *ha = vha->hw;
1615 1616
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

1617
	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655
		return;

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

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

next_test:
	if (RD_REG_DWORD(&reg->iobase_c8) & BIT_3)
		qla_printk(KERN_INFO, ha, "Additional code -- 0x55AA.\n");

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

1656 1657 1658 1659 1660 1661 1662 1663 1664 1665
/**
 * qla24xx_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
1666
qla24xx_intr_handler(int irq, void *dev_id)
1667
{
1668 1669
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
1670 1671 1672 1673 1674 1675
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];
1676
	struct rsp_que *rsp;
1677
	unsigned long	flags;
1678

1679 1680
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
1681
		printk(KERN_INFO
1682
		    "%s(): NULL response queue pointer\n", __func__);
1683 1684 1685
		return IRQ_NONE;
	}

1686
	ha = rsp->hw;
1687 1688 1689
	reg = &ha->iobase->isp24;
	status = 0;

1690
	spin_lock_irqsave(&ha->hardware_lock, flags);
1691
	vha = pci_get_drvdata(ha->pdev);
1692 1693 1694
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1695 1696 1697
			if (pci_channel_offline(ha->pdev))
				break;

1698 1699 1700 1701
			hccr = RD_REG_DWORD(&reg->hccr);

			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
			    "Dumping firmware!\n", hccr);
1702

1703
			qla2xxx_check_risc_status(vha);
1704

1705 1706
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1707 1708 1709 1710 1711 1712 1713 1714 1715
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1716
			qla24xx_mbx_completion(vha, MSW(stat));
1717 1718 1719 1720 1721 1722 1723 1724
			status |= MBX_INTERRUPT;

			break;
		case 0x12:
			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);
1725
			qla2x00_async_event(vha, rsp, mb);
1726 1727
			break;
		case 0x13:
1728
		case 0x14:
1729
			qla24xx_process_response_queue(vha, rsp);
1730 1731 1732 1733
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1734
			    vha->host_no, stat & 0xff));
1735 1736 1737 1738 1739
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
1740
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1741 1742 1743 1744

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
1745
		complete(&ha->mbx_intr_comp);
1746 1747 1748 1749 1750
	}

	return IRQ_HANDLED;
}

1751 1752 1753
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
1754 1755
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1756
	struct device_reg_24xx __iomem *reg;
1757
	struct scsi_qla_host *vha;
1758

1759 1760 1761 1762 1763 1764 1765
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		printk(KERN_INFO
		"%s(): NULL response queue pointer\n", __func__);
		return IRQ_NONE;
	}
	ha = rsp->hw;
1766 1767
	reg = &ha->iobase->isp24;

1768
	spin_lock_irq(&ha->hardware_lock);
1769

1770 1771
	vha = qla25xx_get_host(rsp);
	qla24xx_process_response_queue(vha, rsp);
1772 1773
	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);

1774
	spin_unlock_irq(&ha->hardware_lock);
1775 1776 1777 1778

	return IRQ_HANDLED;
}

1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797
static irqreturn_t
qla25xx_msix_rsp_q(int irq, void *dev_id)
{
	struct qla_hw_data *ha;
	struct rsp_que *rsp;

	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		printk(KERN_INFO
			"%s(): NULL response queue pointer\n", __func__);
		return IRQ_NONE;
	}
	ha = rsp->hw;

	queue_work_on((int) (rsp->id - 1), ha->wq, &rsp->q_work);

	return IRQ_HANDLED;
}

1798 1799 1800
static irqreturn_t
qla24xx_msix_default(int irq, void *dev_id)
{
1801 1802 1803
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1804 1805 1806 1807 1808 1809
	struct device_reg_24xx __iomem *reg;
	int		status;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];

1810 1811 1812 1813 1814 1815 1816
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		DEBUG(printk(
		"%s(): NULL response queue pointer\n", __func__));
		return IRQ_NONE;
	}
	ha = rsp->hw;
1817 1818 1819
	reg = &ha->iobase->isp24;
	status = 0;

1820
	spin_lock_irq(&ha->hardware_lock);
1821
	vha = pci_get_drvdata(ha->pdev);
1822
	do {
1823 1824
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1825 1826 1827
			if (pci_channel_offline(ha->pdev))
				break;

1828 1829 1830 1831
			hccr = RD_REG_DWORD(&reg->hccr);

			qla_printk(KERN_INFO, ha, "RISC paused -- HCCR=%x, "
			    "Dumping firmware!\n", hccr);
1832

1833
			qla2xxx_check_risc_status(vha);
1834

1835 1836
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1837 1838 1839 1840 1841 1842 1843 1844 1845
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1846
			qla24xx_mbx_completion(vha, MSW(stat));
1847 1848 1849 1850 1851 1852 1853 1854
			status |= MBX_INTERRUPT;

			break;
		case 0x12:
			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);
1855
			qla2x00_async_event(vha, rsp, mb);
1856 1857
			break;
		case 0x13:
1858
		case 0x14:
1859
			qla24xx_process_response_queue(vha, rsp);
1860 1861 1862 1863
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1864
			    vha->host_no, stat & 0xff));
1865 1866 1867
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1868
	} while (0);
1869
	spin_unlock_irq(&ha->hardware_lock);
1870 1871 1872 1873

	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
1874
		complete(&ha->mbx_intr_comp);
1875 1876 1877 1878 1879 1880 1881 1882 1883
	}

	return IRQ_HANDLED;
}

/* Interrupt handling helpers. */

struct qla_init_msix_entry {
	const char *name;
1884
	irq_handler_t handler;
1885 1886
};

1887
static struct qla_init_msix_entry msix_entries[3] = {
1888 1889
	{ "qla2xxx (default)", qla24xx_msix_default },
	{ "qla2xxx (rsp_q)", qla24xx_msix_rsp_q },
1890
	{ "qla2xxx (multiq)", qla25xx_msix_rsp_q },
1891 1892 1893
};

static void
1894
qla24xx_disable_msix(struct qla_hw_data *ha)
1895 1896 1897 1898
{
	int i;
	struct qla_msix_entry *qentry;

1899 1900
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
1901
		if (qentry->have_irq)
1902
			free_irq(qentry->vector, qentry->rsp);
1903 1904
	}
	pci_disable_msix(ha->pdev);
1905 1906 1907
	kfree(ha->msix_entries);
	ha->msix_entries = NULL;
	ha->flags.msix_enabled = 0;
1908 1909 1910
}

static int
1911
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
1912
{
1913
#define MIN_MSIX_COUNT	2
1914
	int i, ret;
1915
	struct msix_entry *entries;
1916
	struct qla_msix_entry *qentry;
1917 1918 1919 1920 1921

	entries = kzalloc(sizeof(struct msix_entry) * ha->msix_count,
					GFP_KERNEL);
	if (!entries)
		return -ENOMEM;
1922

1923 1924
	for (i = 0; i < ha->msix_count; i++)
		entries[i].entry = i;
1925

1926
	ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
1927
	if (ret) {
1928 1929 1930
		if (ret < MIN_MSIX_COUNT)
			goto msix_failed;

1931
		qla_printk(KERN_WARNING, ha,
1932 1933 1934 1935 1936
			"MSI-X: Failed to enable support -- %d/%d\n"
			" Retry with %d vectors\n", ha->msix_count, ret, ret);
		ha->msix_count = ret;
		ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
		if (ret) {
1937
msix_failed:
1938 1939 1940 1941 1942
			qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
				" support, giving up -- %d/%d\n",
				ha->msix_count, ret);
			goto msix_out;
		}
1943
		ha->max_rsp_queues = ha->msix_count - 1;
1944 1945 1946 1947 1948
	}
	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
				ha->msix_count, GFP_KERNEL);
	if (!ha->msix_entries) {
		ret = -ENOMEM;
1949 1950 1951 1952
		goto msix_out;
	}
	ha->flags.msix_enabled = 1;

1953 1954 1955 1956
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
		qentry->vector = entries[i].vector;
		qentry->entry = entries[i].entry;
1957
		qentry->have_irq = 0;
1958
		qentry->rsp = NULL;
1959 1960
	}

1961 1962 1963 1964 1965 1966 1967
	/* Enable MSI-X vectors for the base queue */
	for (i = 0; i < 2; i++) {
		qentry = &ha->msix_entries[i];
		ret = request_irq(qentry->vector, msix_entries[i].handler,
					0, msix_entries[i].name, rsp);
		if (ret) {
			qla_printk(KERN_WARNING, ha,
1968 1969
			"MSI-X: Unable to register handler -- %x/%d.\n",
			qentry->vector, ret);
1970 1971 1972 1973 1974 1975 1976
			qla24xx_disable_msix(ha);
			ha->mqenable = 0;
			goto msix_out;
		}
		qentry->have_irq = 1;
		qentry->rsp = rsp;
		rsp->msix = qentry;
1977 1978 1979
	}

	/* Enable MSI-X vector for response queue update for queue 0 */
1980
	if (ha->mqiobase &&  (ha->max_rsp_queues > 1 || ha->max_req_queues > 1))
1981 1982
		ha->mqenable = 1;

1983
msix_out:
1984
	kfree(entries);
1985 1986 1987 1988
	return ret;
}

int
1989
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
1990 1991
{
	int ret;
1992
	device_reg_t __iomem *reg = ha->iobase;
1993 1994

	/* If possible, enable MSI-X. */
1995 1996
	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
	    !IS_QLA8432(ha) && !IS_QLA8001(ha))
1997 1998
		goto skip_msix;

1999 2000
	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
		!QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
2001
		DEBUG2(qla_printk(KERN_WARNING, ha,
2002 2003
		"MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
			ha->pdev->revision, ha->fw_attributes));
2004 2005 2006 2007

		goto skip_msix;
	}

2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019
	if (ha->pdev->subsystem_vendor == PCI_VENDOR_ID_HP &&
	    (ha->pdev->subsystem_device == 0x7040 ||
		ha->pdev->subsystem_device == 0x7041 ||
		ha->pdev->subsystem_device == 0x1705)) {
		DEBUG2(qla_printk(KERN_WARNING, ha,
		    "MSI-X: Unsupported ISP2432 SSVID/SSDID (0x%X, 0x%X).\n",
		    ha->pdev->subsystem_vendor,
		    ha->pdev->subsystem_device));

		goto skip_msi;
	}

2020
	ret = qla24xx_enable_msix(ha, rsp);
2021 2022 2023 2024
	if (!ret) {
		DEBUG2(qla_printk(KERN_INFO, ha,
		    "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
		    ha->fw_attributes));
2025
		goto clear_risc_ints;
2026 2027 2028 2029
	}
	qla_printk(KERN_WARNING, ha,
	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
2030

2031 2032
	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
	    !IS_QLA8001(ha))
2033 2034 2035 2036 2037 2038 2039 2040 2041
		goto skip_msi;

	ret = pci_enable_msi(ha->pdev);
	if (!ret) {
		DEBUG2(qla_printk(KERN_INFO, ha, "MSI: Enabled.\n"));
		ha->flags.msi_enabled = 1;
	}
skip_msi:

2042
	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
2043
	    IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
2044
	if (ret) {
2045 2046 2047
		qla_printk(KERN_WARNING, ha,
		    "Failed to reserve interrupt %d already in use.\n",
		    ha->pdev->irq);
2048 2049 2050 2051 2052
		goto fail;
	}
	ha->flags.inta_enabled = 1;
clear_risc_ints:

2053 2054 2055 2056 2057 2058
	/*
	 * FIXME: Noted that 8014s were being dropped during NK testing.
	 * Timing deltas during MSI-X/INTa transitions?
	 */
	if (IS_QLA81XX(ha))
		goto fail;
2059
	spin_lock_irq(&ha->hardware_lock);
2060 2061 2062 2063 2064 2065 2066
	if (IS_FWI2_CAPABLE(ha)) {
		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_HOST_INT);
		WRT_REG_DWORD(&reg->isp24.hccr, HCCRX_CLR_RISC_INT);
	} else {
		WRT_REG_WORD(&reg->isp.semaphore, 0);
		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_RISC_INT);
		WRT_REG_WORD(&reg->isp.hccr, HCCR_CLR_HOST_INT);
2067
	}
2068
	spin_unlock_irq(&ha->hardware_lock);
2069

2070
fail:
2071 2072 2073 2074
	return ret;
}

void
2075
qla2x00_free_irqs(scsi_qla_host_t *vha)
2076
{
2077
	struct qla_hw_data *ha = vha->hw;
2078
	struct rsp_que *rsp = ha->rsp_q_map[0];
2079 2080 2081

	if (ha->flags.msix_enabled)
		qla24xx_disable_msix(ha);
2082
	else if (ha->flags.inta_enabled) {
2083
		free_irq(ha->pdev->irq, rsp);
2084 2085
		pci_disable_msi(ha->pdev);
	}
2086
}
2087

2088 2089 2090 2091

int qla25xx_request_irq(struct rsp_que *rsp)
{
	struct qla_hw_data *ha = rsp->hw;
2092
	struct qla_init_msix_entry *intr = &msix_entries[2];
2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106
	struct qla_msix_entry *msix = rsp->msix;
	int ret;

	ret = request_irq(msix->vector, intr->handler, 0, intr->name, rsp);
	if (ret) {
		qla_printk(KERN_WARNING, ha,
			"MSI-X: Unable to register handler -- %x/%d.\n",
			msix->vector, ret);
		return ret;
	}
	msix->have_irq = 1;
	msix->rsp = rsp;
	return ret;
}
2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133

struct scsi_qla_host *
qla25xx_get_host(struct rsp_que *rsp)
{
	srb_t *sp;
	struct qla_hw_data *ha = rsp->hw;
	struct scsi_qla_host *vha = NULL;
	struct sts_entry_24xx *pkt;
	struct req_que *req;
	uint16_t que;
	uint32_t handle;

	pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
	que = MSW(pkt->handle);
	handle = (uint32_t) LSW(pkt->handle);
	req = ha->req_q_map[que];
	if (handle < MAX_OUTSTANDING_COMMANDS) {
		sp = req->outstanding_cmds[handle];
		if (sp)
			return  sp->fcport->vha;
		else
			goto base_que;
	}
base_que:
	vha = pci_get_drvdata(ha->pdev);
	return vha;
}