qla_isr.c 55.5 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 *);
L
Linus Torvalds 已提交
16
static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
17 18
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
	sts_entry_t *);
19
static struct scsi_qla_host *qla2x00_get_rsp_host(struct rsp_que *);
20

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

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

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

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

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

			/*
			 * 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);
172

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

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

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

	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);
225
		complete(&ha->mbx_intr_comp);
L
Linus Torvalds 已提交
226 227 228 229 230 231 232 233 234 235 236
	}

	return (IRQ_HANDLED);
}

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

	/* 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 已提交
250
		if (IS_QLA2200(ha) && cnt == 8)
L
Linus Torvalds 已提交
251 252 253 254 255
			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 已提交
256

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

	if (ha->mcp) {
		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
262
		    __func__, vha->host_no, ha->mcp->mb[0]));
L
Linus Torvalds 已提交
263 264
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
265
		    __func__, vha->host_no));
L
Linus Torvalds 已提交
266 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
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 已提交
303 304 305
/**
 * qla2x00_async_event() - Process aynchronous events.
 * @ha: SCSI driver HA context
306
 * @mb: Mailbox registers (0 - 3)
L
Linus Torvalds 已提交
307
 */
308
void
309
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
L
Linus Torvalds 已提交
310
{
311
#define LS_UNKNOWN	2
312
	static char	*link_speeds[] = { "1", "2", "?", "4", "8", "10" };
L
Linus Torvalds 已提交
313 314 315 316
	char		*link_speed;
	uint16_t	handle_cnt;
	uint16_t	cnt;
	uint32_t	handles[5];
317
	struct qla_hw_data *ha = vha->hw;
318
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
319 320
	uint32_t	rscn_entry, host_pid;
	uint8_t		rscn_queue_index;
321
	unsigned long	flags;
L
Linus Torvalds 已提交
322 323 324

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

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

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

393
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
394 395 396 397 398 399 400
		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]);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

492 493 494 495 496
		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 已提交
497 498
		}

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

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

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

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

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

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

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

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

538 539 540 541 542 543
		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 已提交
544 545 546 547 548

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

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

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

		ha->flags.gpsc_supported = 1;
569
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
570 571 572 573 574 575 576 577
		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",
578
		    vha->host_no));
L
Linus Torvalds 已提交
579 580 581
		qla_printk(KERN_INFO, ha,
		    "Configuration change detected: value=%x.\n", mb[1]);

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

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

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

	case MBA_PORT_UPDATE:		/* Port database update */
600 601 602 603
		/* Only handle SCNs for our Vport index. */
		if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
			break;

L
Linus Torvalds 已提交
604
		/*
605
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
L
Linus Torvalds 已提交
606 607 608
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
609 610 611
		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 已提交
612
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
613
			    "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
614
			    mb[2], mb[3]));
L
Linus Torvalds 已提交
615 616 617 618
			break;
		}

		DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
619
		    vha->host_no));
L
Linus Torvalds 已提交
620
		DEBUG(printk(KERN_INFO
621
		    "scsi(%ld): Port database changed %04x %04x %04x.\n",
622
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
623 624 625 626

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

629
		qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
630

631
		vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
632

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

	case MBA_RSCN_UPDATE:		/* State Change Registration */
638
		/* Check if the Vport has issued a SCR */
639
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
640 641
			break;
		/* Only handle SCNs for our Vport index. */
642
		if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
643
			break;
L
Linus Torvalds 已提交
644
		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
645
		    vha->host_no));
L
Linus Torvalds 已提交
646
		DEBUG(printk(KERN_INFO
647
		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
648
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
649

650
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
651 652
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
L
Linus Torvalds 已提交
653 654 655 656
		if (rscn_entry == host_pid) {
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Ignoring RSCN update to local host "
			    "port ID (%06x)\n",
657
			    vha->host_no, host_pid));
L
Linus Torvalds 已提交
658 659 660
			break;
		}

661 662
		/* Ignore reserved bits from RSCN-payload. */
		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
663
		rscn_queue_index = vha->rscn_in_ptr + 1;
L
Linus Torvalds 已提交
664 665
		if (rscn_queue_index == MAX_RSCN_COUNT)
			rscn_queue_index = 0;
666 667 668
		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 已提交
669
		} else {
670
			vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
671 672
		}

673 674 675
		atomic_set(&vha->loop_state, LOOP_UPDATE);
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
676

677 678 679
		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 已提交
680 681 682 683
		break;

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

687
		if (IS_FWI2_CAPABLE(ha))
688
			qla24xx_process_response_queue(rsp);
689
		else
690
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
691
		break;
692 693 694

	case MBA_DISCARD_RND_FRAME:
		DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
695
		    "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
696
		break;
697 698 699

	case MBA_TRACE_NOTIFICATION:
		DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
700
		vha->host_no, mb[1], mb[2]));
701
		break;
702 703 704

	case MBA_ISP84XX_ALERT:
		DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
705
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737

		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;
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
	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:
753
		qla81xx_idc_event(vha, mb[0], mb[1]);
754
		break;
L
Linus Torvalds 已提交
755
	}
756

757
	if (!vha->vp_idx && ha->num_vhosts)
758
		qla2x00_alert_all_vps(rsp, mb);
L
Linus Torvalds 已提交
759 760
}

761 762 763 764
static void
qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
{
	fc_port_t *fcport = data;
765 766 767 768 769 770 771 772
	struct scsi_qla_host *vha = fcport->vha;
	struct qla_hw_data *ha = vha->hw;
	struct req_que *req = NULL;

	req = ha->req_q_map[vha->req_ques[0]];
	if (!req)
		return;
	if (req->max_q_depth <= sdev->queue_depth)
773 774 775 776 777 778 779 780 781 782 783
		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;

784
	DEBUG2(qla_printk(KERN_INFO, ha,
785
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
786
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
787 788 789 790 791 792 793 794 795 796 797
	    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;

798
	DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
799
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
800
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
801 802 803 804
	    sdev->queue_depth));
}

static inline void
805 806
qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
								srb_t *sp)
807 808 809 810 811
{
	fc_port_t *fcport;
	struct scsi_device *sdev;

	sdev = sp->cmd->device;
812
	if (sdev->queue_depth >= req->max_q_depth)
813 814 815 816 817 818 819 820 821 822 823 824 825 826
		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 已提交
827 828 829 830 831 832
/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
static void
833 834
qla2x00_process_completed_request(struct scsi_qla_host *vha,
				struct req_que *req, uint32_t index)
L
Linus Torvalds 已提交
835 836
{
	srb_t *sp;
837
	struct qla_hw_data *ha = vha->hw;
L
Linus Torvalds 已提交
838 839 840 841

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

846
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
847 848 849
		return;
	}

850
	sp = req->outstanding_cmds[index];
L
Linus Torvalds 已提交
851 852
	if (sp) {
		/* Free outstanding command slot. */
853
		req->outstanding_cmds[index] = NULL;
L
Linus Torvalds 已提交
854 855 856 857 858 859

		CMD_COMPL_STATUS(sp->cmd) = 0L;
		CMD_SCSI_STATUS(sp->cmd) = 0L;

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

861 862
		qla2x00_ramp_up_queue_depth(vha, req, sp);
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
863 864
	} else {
		DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
865
		    vha->host_no));
L
Linus Torvalds 已提交
866 867 868
		qla_printk(KERN_WARNING, ha,
		    "Invalid ISP SCSI completion handle\n");

869
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
870 871 872 873 874 875 876 877
	}
}

/**
 * qla2x00_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
878
qla2x00_process_response_queue(struct rsp_que *rsp)
L
Linus Torvalds 已提交
879
{
880 881
	struct scsi_qla_host *vha;
	struct qla_hw_data *ha = rsp->hw;
882
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
883 884 885
	sts_entry_t	*pkt;
	uint16_t        handle_cnt;
	uint16_t        cnt;
886 887

	vha = qla2x00_get_rsp_host(rsp);
L
Linus Torvalds 已提交
888

889
	if (!vha->flags.online)
L
Linus Torvalds 已提交
890 891
		return;

892 893
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (sts_entry_t *)rsp->ring_ptr;
L
Linus Torvalds 已提交
894

895 896 897 898
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
L
Linus Torvalds 已提交
899
		} else {
900
			rsp->ring_ptr++;
L
Linus Torvalds 已提交
901 902 903 904
		}

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

907
			qla2x00_error_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
908 909 910 911 912 913 914
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
915
			qla2x00_status_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
916 917 918 919
			break;
		case STATUS_TYPE_21:
			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
920
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
921 922 923 924 925 926
				    ((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++) {
927
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
928 929 930 931
				    ((sts22_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_CONT_TYPE:
932
			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
L
Linus Torvalds 已提交
933 934 935 936 937 938
			break;
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
939
			    vha->host_no, pkt->entry_type, pkt->entry_status));
L
Linus Torvalds 已提交
940 941 942 943 944 945 946
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

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

950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968
static inline void
qla2x00_handle_sense(srb_t *sp, uint8_t *sense_data, uint32_t sense_len)
{
	struct scsi_cmnd *cp = sp->cmd;

	if (sense_len >= SCSI_SENSE_BUFFERSIZE)
		sense_len = SCSI_SENSE_BUFFERSIZE;

	CMD_ACTUAL_SNSLEN(cp) = sense_len;
	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)
969
		sp->fcport->vha->status_srb = sp;
970 971

	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
972
	    "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
973 974
	    cp->device->channel, cp->device->id, cp->device->lun, cp,
	    cp->serial_number));
975 976 977 978 979
	if (sense_len)
		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
		    CMD_ACTUAL_SNSLEN(cp)));
}

L
Linus Torvalds 已提交
980 981 982 983 984 985
/**
 * qla2x00_status_entry() - Process a Status IOCB entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
986
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
L
Linus Torvalds 已提交
987 988 989 990
{
	srb_t		*sp;
	fc_port_t	*fcport;
	struct scsi_cmnd *cp;
991 992
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
L
Linus Torvalds 已提交
993 994 995 996
	uint16_t	comp_status;
	uint16_t	scsi_status;
	uint8_t		lscsi_status;
	int32_t		resid;
997
	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len;
998
	uint8_t		*rsp_info, *sense_data;
999
	struct qla_hw_data *ha = vha->hw;
1000
	struct req_que *req = rsp->req;
1001 1002 1003

	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;
1004
	if (IS_FWI2_CAPABLE(ha)) {
1005 1006 1007 1008 1009 1010
		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;
	}
L
Linus Torvalds 已提交
1011 1012

	/* Fast path completion. */
1013
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
1014
		qla2x00_process_completed_request(vha, req, sts->handle);
L
Linus Torvalds 已提交
1015 1016 1017 1018 1019

		return;
	}

	/* Validate handle. */
1020
	if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
1021 1022
		sp = req->outstanding_cmds[sts->handle];
		req->outstanding_cmds[sts->handle] = NULL;
L
Linus Torvalds 已提交
1023 1024 1025 1026 1027
	} else
		sp = NULL;

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

1031 1032
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1033 1034 1035 1036 1037
		return;
	}
	cp = sp->cmd;
	if (cp == NULL) {
		DEBUG2(printk("scsi(%ld): Command already returned back to OS "
1038
		    "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp));
L
Linus Torvalds 已提交
1039 1040 1041 1042 1043 1044
		qla_printk(KERN_WARNING, ha,
		    "Command is NULL: already returned to OS (sp=%p)\n", sp);

		return;
	}

1045 1046
  	lscsi_status = scsi_status & STATUS_MASK;
	CMD_ENTRY_STATUS(cp) = sts->entry_status;
L
Linus Torvalds 已提交
1047 1048 1049
	CMD_COMPL_STATUS(cp) = comp_status;
	CMD_SCSI_STATUS(cp) = scsi_status;

1050
	fcport = sp->fcport;
L
Linus Torvalds 已提交
1051

1052
	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
1053
	if (IS_FWI2_CAPABLE(ha)) {
1054 1055 1056
		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);
1057
		fw_resid_len = le32_to_cpu(sts24->residual_len);
1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
		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 已提交
1069 1070
	/* Check for any FCP transport errors. */
	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
1071
		/* Sense data lies beyond any FCP RESPONSE data. */
1072
		if (IS_FWI2_CAPABLE(ha))
1073 1074
			sense_data += rsp_info_len;
		if (rsp_info_len > 3 && rsp_info[3]) {
L
Linus Torvalds 已提交
1075 1076
			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
1077
			    "retrying command\n", vha->host_no,
1078 1079 1080 1081
			    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 已提交
1082 1083

			cp->result = DID_BUS_BUSY << 16;
1084
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1085 1086 1087 1088
			return;
		}
	}

1089 1090 1091 1092 1093
	/* 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 已提交
1094 1095 1096 1097 1098
	/*
	 * Based on Host and scsi status generate status code for Linux
	 */
	switch (comp_status) {
	case CS_COMPLETE:
1099
	case CS_QUEUE_FULL:
L
Linus Torvalds 已提交
1100 1101 1102 1103 1104
		if (scsi_status == 0) {
			cp->result = DID_OK << 16;
			break;
		}
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
1105
			resid = resid_len;
1106
			scsi_set_resid(cp, resid);
L
Linus Torvalds 已提交
1107
			CMD_RESID_LEN(cp) = resid;
1108 1109

			if (!lscsi_status &&
1110
			    ((unsigned)(scsi_bufflen(cp) - resid) <
1111 1112
			     cp->underflow)) {
				qla_printk(KERN_INFO, ha,
1113 1114
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1115
					   "error status.\n", vha->host_no,
1116 1117 1118
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
1119 1120 1121 1122

				cp->result = DID_ERROR << 16;
				break;
			}
L
Linus Torvalds 已提交
1123 1124 1125
		}
		cp->result = DID_OK << 16 | lscsi_status;

1126 1127 1128
		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld): QUEUE FULL status detected "
1129
			    "0x%x-0x%x.\n", vha->host_no, comp_status,
1130 1131 1132 1133 1134 1135 1136 1137
			    scsi_status));

			/* Adjust queue depth for all luns on the port. */
			fcport->last_queue_full = jiffies;
			starget_for_each_device(cp->device->sdev_target,
			    fcport, qla2x00_adjust_sdev_qdepth_down);
			break;
		}
L
Linus Torvalds 已提交
1138 1139 1140
		if (lscsi_status != SS_CHECK_CONDITION)
			break;

1141
		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
1142 1143 1144
		if (!(scsi_status & SS_SENSE_LEN_VALID))
			break;

1145
		qla2x00_handle_sense(sp, sense_data, sense_len);
L
Linus Torvalds 已提交
1146 1147 1148
		break;

	case CS_DATA_UNDERRUN:
1149
		resid = resid_len;
1150
		/* Use F/W calculated residual length. */
1151
		if (IS_FWI2_CAPABLE(ha)) {
1152 1153 1154
			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
				lscsi_status = 0;
			} else if (resid != fw_resid_len) {
1155 1156 1157
				scsi_status &= ~SS_RESIDUAL_UNDER;
				lscsi_status = 0;
			}
1158
			resid = fw_resid_len;
1159
		}
1160

L
Linus Torvalds 已提交
1161
		if (scsi_status & SS_RESIDUAL_UNDER) {
1162
			scsi_set_resid(cp, resid);
L
Linus Torvalds 已提交
1163
			CMD_RESID_LEN(cp) = resid;
1164 1165 1166
		} else {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d) UNDERRUN status detected "
1167
			    "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
1168
			    "os_underflow=0x%x\n", vha->host_no,
1169 1170 1171
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status, resid_len, resid, cp->cmnd[0],
			    cp->underflow));
1172

L
Linus Torvalds 已提交
1173 1174 1175
		}

		/*
A
Andrew Vasquez 已提交
1176
		 * Check to see if SCSI Status is non zero. If so report SCSI
L
Linus Torvalds 已提交
1177 1178 1179 1180 1181
		 * Status.
		 */
		if (lscsi_status != 0) {
			cp->result = DID_OK << 16 | lscsi_status;

1182 1183 1184
			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
				DEBUG2(printk(KERN_INFO
				    "scsi(%ld): QUEUE FULL status detected "
1185
				    "0x%x-0x%x.\n", vha->host_no, comp_status,
1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
				    scsi_status));

				/*
				 * Adjust queue depth for all luns on the
				 * port.
				 */
				fcport->last_queue_full = jiffies;
				starget_for_each_device(
				    cp->device->sdev_target, fcport,
				    qla2x00_adjust_sdev_qdepth_down);
				break;
			}
L
Linus Torvalds 已提交
1198 1199 1200
			if (lscsi_status != SS_CHECK_CONDITION)
				break;

1201
			memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
1202 1203 1204
			if (!(scsi_status & SS_SENSE_LEN_VALID))
				break;

1205
			qla2x00_handle_sense(sp, sense_data, sense_len);
L
Linus Torvalds 已提交
1206 1207 1208 1209 1210 1211 1212 1213
		} else {
			/*
			 * If RISC reports underrun and target does not report
			 * it then we must have a lost frame, so tell upper
			 * layer to retry it by reporting a bus busy.
			 */
			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
				DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
1214
					      "frame(s) detected (%x of %x bytes)..."
1215 1216 1217 1218
					      "retrying command.\n",
					vha->host_no, cp->device->channel,
					cp->device->id, cp->device->lun, resid,
					scsi_bufflen(cp)));
L
Linus Torvalds 已提交
1219 1220 1221 1222 1223 1224

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

			/* Handle mid-layer underflow */
1225
			if ((unsigned)(scsi_bufflen(cp) - resid) <
L
Linus Torvalds 已提交
1226 1227
			    cp->underflow) {
				qla_printk(KERN_INFO, ha,
1228 1229
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1230
					   "error status.\n", vha->host_no,
1231 1232 1233
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
L
Linus Torvalds 已提交
1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246

				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",
1247
		    vha->host_no, cp->device->id, cp->device->lun, comp_status,
1248
		    scsi_status));
L
Linus Torvalds 已提交
1249 1250 1251 1252 1253 1254 1255
		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",
1256
		    cp->serial_number, scsi_bufflen(cp), resid_len));
L
Linus Torvalds 已提交
1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272

		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",
1273
		    vha->host_no, cp->device->id, cp->device->lun,
1274
		    cp->serial_number, comp_status,
L
Linus Torvalds 已提交
1275 1276
		    atomic_read(&fcport->state)));

1277 1278 1279 1280 1281 1282
		/*
		 * 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;
1283
		if (atomic_read(&fcport->state) == FCS_ONLINE)
1284
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1285 1286 1287 1288 1289
		break;

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

已提交
1292
		cp->result = DID_RESET << 16;
L
Linus Torvalds 已提交
1293 1294 1295
		break;

	case CS_ABORTED:
A
Andrew Vasquez 已提交
1296
		/*
L
Linus Torvalds 已提交
1297 1298 1299 1300 1301 1302
		 * 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",
1303
		    vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1304 1305 1306 1307 1308

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

	case CS_TIMEOUT:
1309 1310 1311 1312 1313 1314
		/*
		 * 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;
1315

1316
		if (IS_FWI2_CAPABLE(ha)) {
1317 1318
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
1319
			    "0x%x-0x%x\n", vha->host_no, cp->device->channel,
1320 1321 1322 1323
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status));
			break;
		}
L
Linus Torvalds 已提交
1324 1325
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
1326
		    "sflags=%x.\n", vha->host_no, cp->device->channel,
1327 1328
		    cp->device->id, cp->device->lun, comp_status, scsi_status,
		    le16_to_cpu(sts->status_flags)));
L
Linus Torvalds 已提交
1329

1330 1331
		/* Check to see if logout occurred. */
		if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
1332
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1333 1334 1335 1336
		break;

	default:
		DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
1337
		    "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1338 1339 1340 1341 1342 1343 1344 1345 1346
		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. */
1347
	if (vha->status_srb == NULL)
1348
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1349 1350 1351 1352 1353 1354 1355 1356 1357 1358
}

/**
 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 *
 * Extended sense data.
 */
static void
1359
qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
L
Linus Torvalds 已提交
1360 1361
{
	uint8_t		sense_sz = 0;
1362 1363
	struct qla_hw_data *ha = vha->hw;
	srb_t		*sp = vha->status_srb;
L
Linus Torvalds 已提交
1364 1365 1366 1367 1368 1369
	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 "
1370
			    "sp=%p.\n", __func__, sp));
L
Linus Torvalds 已提交
1371 1372
			qla_printk(KERN_INFO, ha,
			    "cmd is NULL: already returned to OS (sp=%p)\n",
A
Andrew Vasquez 已提交
1373
			    sp);
L
Linus Torvalds 已提交
1374

1375
			vha->status_srb = NULL;
L
Linus Torvalds 已提交
1376 1377 1378 1379 1380 1381 1382 1383 1384 1385
			return;
		}

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

		/* Move sense data. */
1386
		if (IS_FWI2_CAPABLE(ha))
1387
			host_to_fcp_swap(pkt->data, sizeof(pkt->data));
L
Linus Torvalds 已提交
1388 1389 1390 1391 1392 1393 1394 1395
		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) {
1396
			vha->status_srb = NULL;
1397
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1398 1399 1400 1401 1402 1403 1404 1405 1406 1407
		}
	}
}

/**
 * qla2x00_error_entry() - Process an error entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
1408
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
L
Linus Torvalds 已提交
1409 1410
{
	srb_t *sp;
1411
	struct qla_hw_data *ha = vha->hw;
1412
	struct req_que *req = rsp->req;
L
Linus Torvalds 已提交
1413 1414 1415 1416 1417 1418
#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 已提交
1419
		qla_printk(KERN_ERR, ha,
L
Linus Torvalds 已提交
1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430
		    "%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. */
	if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
1431
		sp = req->outstanding_cmds[pkt->handle];
L
Linus Torvalds 已提交
1432 1433 1434 1435 1436
	else
		sp = NULL;

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

L
Linus Torvalds 已提交
1439 1440 1441 1442 1443 1444 1445 1446 1447 1448
		/* 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;
		}
1449
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1450

1451 1452
	} else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
	    COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
L
Linus Torvalds 已提交
1453
		DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
1454
		    vha->host_no));
L
Linus Torvalds 已提交
1455 1456 1457
		qla_printk(KERN_WARNING, ha,
		    "Error entry - invalid handle\n");

1458 1459
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1460 1461 1462
	}
}

1463 1464 1465 1466 1467 1468
/**
 * qla24xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
1469
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
1470 1471 1472
{
	uint16_t	cnt;
	uint16_t __iomem *wptr;
1473
	struct qla_hw_data *ha = vha->hw;
1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
	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",
1488
		    __func__, vha->host_no, ha->mcp->mb[0]));
1489 1490
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
1491
		    __func__, vha->host_no));
1492 1493 1494 1495 1496 1497 1498 1499
	}
}

/**
 * qla24xx_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
1500
qla24xx_process_response_queue(struct rsp_que *rsp)
1501
{
1502
	struct qla_hw_data *ha = rsp->hw;
1503
	struct sts_entry_24xx *pkt;
1504 1505 1506
	struct scsi_qla_host *vha;

	vha = qla2x00_get_rsp_host(rsp);
1507

1508
	if (!vha->flags.online)
1509 1510
		return;

1511 1512
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
1513

1514 1515 1516 1517
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
1518
		} else {
1519
			rsp->ring_ptr++;
1520 1521 1522 1523
		}

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

1526
			qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
1527 1528 1529 1530 1531 1532 1533
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
1534
			qla2x00_status_entry(vha, rsp, pkt);
1535 1536
			break;
		case STATUS_CONT_TYPE:
1537
			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
1538
			break;
1539
		case VP_RPT_ID_IOCB_TYPE:
1540
			qla24xx_report_id_acquisition(vha,
1541 1542
			    (struct vp_rpt_id_entry_24xx *)pkt);
			break;
1543 1544 1545 1546 1547
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
1548
			    vha->host_no, pkt->entry_type, pkt->entry_status));
1549 1550 1551 1552 1553 1554 1555
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
1556
	ha->isp_ops->wrt_rsp_reg(ha, rsp->id, rsp->ring_index);
1557 1558
}

1559
static void
1560
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
1561 1562 1563
{
	int rval;
	uint32_t cnt;
1564
	struct qla_hw_data *ha = vha->hw;
1565 1566
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

1567
	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha))
1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605
		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);
}

1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
/**
 * 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
1616
qla24xx_intr_handler(int irq, void *dev_id)
1617
{
1618 1619
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
1620 1621 1622 1623 1624 1625
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];
1626
	struct rsp_que *rsp;
1627

1628 1629
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
1630
		printk(KERN_INFO
1631
		    "%s(): NULL response queue pointer\n", __func__);
1632 1633 1634
		return IRQ_NONE;
	}

1635
	ha = rsp->hw;
1636 1637 1638
	reg = &ha->iobase->isp24;
	status = 0;

1639
	spin_lock(&ha->hardware_lock);
1640
	vha = qla2x00_get_rsp_host(rsp);
1641 1642 1643
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1644 1645 1646
			if (pci_channel_offline(ha->pdev))
				break;

1647 1648 1649 1650
			hccr = RD_REG_DWORD(&reg->hccr);

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

1652
			qla2xxx_check_risc_status(vha);
1653

1654 1655
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1656 1657 1658 1659 1660 1661 1662 1663 1664
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1665
			qla24xx_mbx_completion(vha, MSW(stat));
1666 1667 1668 1669 1670 1671 1672 1673
			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);
1674
			qla2x00_async_event(vha, rsp, mb);
1675 1676
			break;
		case 0x13:
1677 1678
		case 0x14:
			qla24xx_process_response_queue(rsp);
1679 1680 1681 1682
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1683
			    vha->host_no, stat & 0xff));
1684 1685 1686 1687 1688
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
1689
	spin_unlock(&ha->hardware_lock);
1690 1691 1692 1693

	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);
1694
		complete(&ha->mbx_intr_comp);
1695 1696 1697 1698 1699
	}

	return IRQ_HANDLED;
}

1700 1701 1702
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
1703 1704
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1705 1706
	struct device_reg_24xx __iomem *reg;

1707 1708 1709 1710 1711 1712 1713
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		printk(KERN_INFO
		"%s(): NULL response queue pointer\n", __func__);
		return IRQ_NONE;
	}
	ha = rsp->hw;
1714 1715
	reg = &ha->iobase->isp24;

1716
	spin_lock_irq(&ha->hardware_lock);
1717

1718
	qla24xx_process_response_queue(rsp);
1719 1720
	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);

1721
	spin_unlock_irq(&ha->hardware_lock);
1722 1723 1724 1725

	return IRQ_HANDLED;
}

1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750
static irqreturn_t
qla25xx_msix_rsp_q(int irq, void *dev_id)
{
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
	struct device_reg_24xx __iomem *reg;

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

	spin_lock_irq(&ha->hardware_lock);

	qla24xx_process_response_queue(rsp);

	spin_unlock_irq(&ha->hardware_lock);

	return IRQ_HANDLED;
}

1751 1752 1753
static irqreturn_t
qla24xx_msix_default(int irq, void *dev_id)
{
1754 1755 1756
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1757 1758 1759 1760 1761 1762
	struct device_reg_24xx __iomem *reg;
	int		status;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];

1763 1764 1765 1766 1767 1768 1769
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		DEBUG(printk(
		"%s(): NULL response queue pointer\n", __func__));
		return IRQ_NONE;
	}
	ha = rsp->hw;
1770 1771 1772
	reg = &ha->iobase->isp24;
	status = 0;

1773
	spin_lock_irq(&ha->hardware_lock);
1774
	vha = qla2x00_get_rsp_host(rsp);
1775
	do {
1776 1777
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1778 1779 1780
			if (pci_channel_offline(ha->pdev))
				break;

1781 1782 1783 1784
			hccr = RD_REG_DWORD(&reg->hccr);

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

1786
			qla2xxx_check_risc_status(vha);
1787

1788 1789
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1790 1791 1792 1793 1794 1795 1796 1797 1798
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1799
			qla24xx_mbx_completion(vha, MSW(stat));
1800 1801 1802 1803 1804 1805 1806 1807
			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);
1808
			qla2x00_async_event(vha, rsp, mb);
1809 1810
			break;
		case 0x13:
1811 1812
		case 0x14:
			qla24xx_process_response_queue(rsp);
1813 1814 1815 1816
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1817
			    vha->host_no, stat & 0xff));
1818 1819 1820
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1821
	} while (0);
1822
	spin_unlock_irq(&ha->hardware_lock);
1823 1824 1825 1826

	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);
1827
		complete(&ha->mbx_intr_comp);
1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838
	}

	return IRQ_HANDLED;
}

/* Interrupt handling helpers. */

struct qla_init_msix_entry {
	uint16_t entry;
	uint16_t index;
	const char *name;
1839
	irq_handler_t handler;
1840 1841
};

1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854
static struct qla_init_msix_entry base_queue = {
	.entry = 0,
	.index = 0,
	.name = "qla2xxx (default)",
	.handler = qla24xx_msix_default,
};

static struct qla_init_msix_entry base_rsp_queue = {
	.entry = 1,
	.index = 1,
	.name = "qla2xxx (rsp_q)",
	.handler = qla24xx_msix_rsp_q,
};
1855

1856 1857 1858 1859 1860
static struct qla_init_msix_entry multi_rsp_queue = {
	.entry = 1,
	.index = 1,
	.name = "qla2xxx (multi_q)",
	.handler = qla25xx_msix_rsp_q,
1861 1862 1863
};

static void
1864
qla24xx_disable_msix(struct qla_hw_data *ha)
1865 1866 1867 1868
{
	int i;
	struct qla_msix_entry *qentry;

1869 1870
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
1871
		if (qentry->have_irq)
1872
			free_irq(qentry->vector, qentry->rsp);
1873 1874
	}
	pci_disable_msix(ha->pdev);
1875 1876 1877
	kfree(ha->msix_entries);
	ha->msix_entries = NULL;
	ha->flags.msix_enabled = 0;
1878 1879 1880
}

static int
1881
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
1882
{
1883
#define MIN_MSIX_COUNT	2
1884
	int i, ret;
1885
	struct msix_entry *entries;
1886
	struct qla_msix_entry *qentry;
1887 1888 1889 1890 1891 1892
	struct qla_init_msix_entry *msix_queue;

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

1894 1895
	for (i = 0; i < ha->msix_count; i++)
		entries[i].entry = i;
1896

1897
	ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
1898
	if (ret) {
1899 1900 1901
		if (ret < MIN_MSIX_COUNT)
			goto msix_failed;

1902
		qla_printk(KERN_WARNING, ha,
1903 1904 1905 1906 1907
			"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) {
1908
msix_failed:
1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919
			qla_printk(KERN_WARNING, ha, "MSI-X: Failed to enable"
				" support, giving up -- %d/%d\n",
				ha->msix_count, ret);
			goto msix_out;
		}
		ha->max_queues = ha->msix_count - 1;
	}
	ha->msix_entries = kzalloc(sizeof(struct qla_msix_entry) *
				ha->msix_count, GFP_KERNEL);
	if (!ha->msix_entries) {
		ret = -ENOMEM;
1920 1921 1922 1923
		goto msix_out;
	}
	ha->flags.msix_enabled = 1;

1924 1925 1926 1927
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
		qentry->vector = entries[i].vector;
		qentry->entry = entries[i].entry;
1928
		qentry->have_irq = 0;
1929
		qentry->rsp = NULL;
1930 1931
	}

1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971
	/* Enable MSI-X for AENs for queue 0 */
	qentry = &ha->msix_entries[0];
	ret = request_irq(qentry->vector, base_queue.handler, 0,
					base_queue.name, rsp);
	if (ret) {
		qla_printk(KERN_WARNING, ha,
			"MSI-X: Unable to register handler -- %x/%d.\n",
			qentry->vector, ret);
		qla24xx_disable_msix(ha);
		goto msix_out;
	}
	qentry->have_irq = 1;
	qentry->rsp = rsp;

	/* Enable MSI-X vector for response queue update for queue 0 */
	if (ha->max_queues > 1 && ha->mqiobase) {
		ha->mqenable = 1;
		msix_queue = &multi_rsp_queue;
		qla_printk(KERN_INFO, ha,
				"MQ enabled, Number of Queue Resources: %d \n",
				ha->max_queues);
	} else {
		ha->mqenable = 0;
		msix_queue = &base_rsp_queue;
	}

	qentry = &ha->msix_entries[1];
	ret = request_irq(qentry->vector, msix_queue->handler, 0,
						msix_queue->name, rsp);
	if (ret) {
		qla_printk(KERN_WARNING, ha,
			"MSI-X: Unable to register handler -- %x/%d.\n",
			qentry->vector, ret);
		qla24xx_disable_msix(ha);
		ha->mqenable = 0;
		goto msix_out;
	}
	qentry->have_irq = 1;
	qentry->rsp = rsp;

1972
msix_out:
1973
	kfree(entries);
1974 1975 1976 1977
	return ret;
}

int
1978
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
1979 1980
{
	int ret;
1981
	device_reg_t __iomem *reg = ha->iobase;
1982 1983

	/* If possible, enable MSI-X. */
1984 1985
	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) &&
	    !IS_QLA8432(ha) && !IS_QLA8001(ha))
1986 1987
		goto skip_msix;

1988 1989
	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
		!QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
1990
		DEBUG2(qla_printk(KERN_WARNING, ha,
1991 1992
		"MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
			ha->pdev->revision, ha->fw_attributes));
1993 1994 1995 1996

		goto skip_msix;
	}

1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008
	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;
	}

2009
	ret = qla24xx_enable_msix(ha, rsp);
2010 2011 2012 2013
	if (!ret) {
		DEBUG2(qla_printk(KERN_INFO, ha,
		    "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
		    ha->fw_attributes));
2014
		goto clear_risc_ints;
2015 2016 2017 2018
	}
	qla_printk(KERN_WARNING, ha,
	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
2019

2020 2021
	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha) &&
	    !IS_QLA8001(ha))
2022 2023 2024 2025 2026 2027 2028 2029 2030
		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:

2031
	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
2032
	    IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
2033
	if (ret) {
2034 2035 2036
		qla_printk(KERN_WARNING, ha,
		    "Failed to reserve interrupt %d already in use.\n",
		    ha->pdev->irq);
2037 2038 2039 2040 2041
		goto fail;
	}
	ha->flags.inta_enabled = 1;
clear_risc_ints:

2042 2043 2044 2045 2046 2047
	/*
	 * FIXME: Noted that 8014s were being dropped during NK testing.
	 * Timing deltas during MSI-X/INTa transitions?
	 */
	if (IS_QLA81XX(ha))
		goto fail;
2048
	spin_lock_irq(&ha->hardware_lock);
2049 2050 2051 2052 2053 2054 2055
	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);
2056
	}
2057
	spin_unlock_irq(&ha->hardware_lock);
2058

2059
fail:
2060 2061 2062 2063
	return ret;
}

void
2064
qla2x00_free_irqs(scsi_qla_host_t *vha)
2065
{
2066
	struct qla_hw_data *ha = vha->hw;
2067
	struct rsp_que *rsp = ha->rsp_q_map[0];
2068 2069 2070

	if (ha->flags.msix_enabled)
		qla24xx_disable_msix(ha);
2071
	else if (ha->flags.inta_enabled) {
2072
		free_irq(ha->pdev->irq, rsp);
2073 2074
		pci_disable_msi(ha->pdev);
	}
2075
}
2076 2077 2078 2079 2080 2081 2082

static struct scsi_qla_host *
qla2x00_get_rsp_host(struct rsp_que *rsp)
{
	srb_t *sp;
	struct qla_hw_data *ha = rsp->hw;
	struct scsi_qla_host *vha = NULL;
2083 2084 2085 2086 2087 2088 2089 2090 2091
	struct sts_entry_24xx *pkt;
	struct req_que *req;

	if (rsp->id) {
		pkt = (struct sts_entry_24xx *) rsp->ring_ptr;
		req = rsp->req;
		if (pkt && pkt->handle < MAX_OUTSTANDING_COMMANDS) {
			sp = req->outstanding_cmds[pkt->handle];
			if (sp)
2092
				vha = sp->fcport->vha;
2093
		}
2094 2095
	}
	if (!vha)
2096
	/* handle it in base queue */
2097 2098 2099 2100
		vha = pci_get_drvdata(ha->pdev);

	return vha;
}
2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120

int qla25xx_request_irq(struct rsp_que *rsp)
{
	struct qla_hw_data *ha = rsp->hw;
	struct qla_init_msix_entry *intr = &multi_rsp_queue;
	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;
}

2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134
void
qla25xx_wrt_rsp_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index)
{
	device_reg_t __iomem *reg = (void *) ha->mqiobase + QLA_QUE_PAGE * id;
	WRT_REG_DWORD(&reg->isp25mq.rsp_q_out, index);
}

void
qla24xx_wrt_rsp_reg(struct qla_hw_data *ha, uint16_t id, uint16_t index)
{
	device_reg_t __iomem *reg = (void *) ha->iobase;
	WRT_REG_DWORD(&reg->isp24.rsp_q_out, index);
}