qla_isr.c 53.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
	}
}

/**
 * qla2x00_async_event() - Process aynchronous events.
 * @ha: SCSI driver HA context
272
 * @mb: Mailbox registers (0 - 3)
L
Linus Torvalds 已提交
273
 */
274
void
275
qla2x00_async_event(scsi_qla_host_t *vha, struct rsp_que *rsp, uint16_t *mb)
L
Linus Torvalds 已提交
276
{
277
#define LS_UNKNOWN	2
278
	static char	*link_speeds[5] = { "1", "2", "?", "4", "8" };
L
Linus Torvalds 已提交
279 280 281 282
	char		*link_speed;
	uint16_t	handle_cnt;
	uint16_t	cnt;
	uint32_t	handles[5];
283
	struct qla_hw_data *ha = vha->hw;
284
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
285 286
	uint32_t	rscn_entry, host_pid;
	uint8_t		rscn_queue_index;
287
	unsigned long	flags;
L
Linus Torvalds 已提交
288 289 290 291 292

	/* Setup to process RIO completion. */
	handle_cnt = 0;
	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:
293
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
294 295 296
		handle_cnt = 1;
		break;
	case MBA_CMPLT_1_16BIT:
297
		handles[0] = mb[1];
L
Linus Torvalds 已提交
298 299 300 301
		handle_cnt = 1;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_2_16BIT:
302 303
		handles[0] = mb[1];
		handles[1] = mb[2];
L
Linus Torvalds 已提交
304 305 306 307
		handle_cnt = 2;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_3_16BIT:
308 309 310
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
311 312 313 314
		handle_cnt = 3;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_4_16BIT:
315 316 317
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
318 319 320 321 322
		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
		handle_cnt = 4;
		mb[0] = MBA_SCSI_COMPLETION;
		break;
	case MBA_CMPLT_5_16BIT:
323 324 325
		handles[0] = mb[1];
		handles[1] = mb[2];
		handles[2] = mb[3];
L
Linus Torvalds 已提交
326 327 328 329 330 331
		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:
332
		handles[0] = le32_to_cpu((uint32_t)((mb[2] << 16) | mb[1]));
L
Linus Torvalds 已提交
333 334 335 336 337 338 339 340 341 342 343 344
		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;
	}

	switch (mb[0]) {
	case MBA_SCSI_COMPLETION:	/* Fast Post */
345
		if (!vha->flags.online)
L
Linus Torvalds 已提交
346 347 348
			break;

		for (cnt = 0; cnt < handle_cnt; cnt++)
349 350
			qla2x00_process_completed_request(vha, rsp->req,
				handles[cnt]);
L
Linus Torvalds 已提交
351 352 353
		break;

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

357
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
358 359 360 361 362 363 364
		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]);

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

367
		if (IS_FWI2_CAPABLE(ha)) {
368 369 370 371
			if (mb[1] == 0 && mb[2] == 0) {
				qla_printk(KERN_ERR, ha,
				    "Unrecoverable Hardware Error: adapter "
				    "marked OFFLINE!\n");
372
				vha->flags.online = 0;
373
			} else
374
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
375
		} else if (mb[1] == 0) {
L
Linus Torvalds 已提交
376 377 378
			qla_printk(KERN_INFO, ha,
			    "Unrecoverable Hardware Error: adapter marked "
			    "OFFLINE!\n");
379
			vha->flags.online = 0;
L
Linus Torvalds 已提交
380
		} else
381
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
382 383 384 385
		break;

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

389
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
390 391 392 393
		break;

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

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

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

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

410 411 412 413
		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 已提交
414 415
		}

416 417 418
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
419 420
		}

421 422
		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
423

424 425
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
L
Linus Torvalds 已提交
426 427 428 429 430
		break;

	case MBA_LOOP_UP:		/* Loop Up Event */
		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
			link_speed = link_speeds[0];
431
			ha->link_data_rate = PORT_SPEED_1GB;
L
Linus Torvalds 已提交
432
		} else {
433
			link_speed = link_speeds[LS_UNKNOWN];
L
Linus Torvalds 已提交
434 435 436 437 438 439
			if (mb[1] < 5)
				link_speed = link_speeds[mb[1]];
			ha->link_data_rate = mb[1];
		}

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

444 445
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
L
Linus Torvalds 已提交
446 447 448
		break;

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

454 455 456 457 458
		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 已提交
459 460
		}

461 462 463
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
464 465
		}

466
		vha->flags.management_server_logged_in = 0;
467
		ha->link_data_rate = PORT_SPEED_UNKNOWN;
468
		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
L
Linus Torvalds 已提交
469 470 471 472
		break;

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

477 478 479 480
		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 已提交
481 482
		}

483 484 485
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
486 487
		}

488
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
489 490

		ha->operating_mode = LOOP;
491 492
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
L
Linus Torvalds 已提交
493 494 495 496 497 498 499
		break;

	case MBA_POINT_TO_POINT:	/* Point-to-Point */
		if (IS_QLA2100(ha))
			break;

		DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n",
500
		    vha->host_no));
L
Linus Torvalds 已提交
501 502 503 504 505

		/*
		 * Until there's a transition from loop down to loop up, treat
		 * this as loop down only.
		 */
506 507 508 509
		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 已提交
510
				    LOOP_DOWN_TIME);
511
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
512 513
		}

514 515 516
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
517 518
		}

519 520 521 522 523
		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);
524 525

		ha->flags.gpsc_supported = 1;
526
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
527 528 529 530 531 532 533 534
		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",
535
		    vha->host_no));
L
Linus Torvalds 已提交
536 537 538
		qla_printk(KERN_INFO, ha,
		    "Configuration change detected: value=%x.\n", mb[1]);

539 540 541 542
		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 已提交
543
				    LOOP_DOWN_TIME);
544
			qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
545 546
		}

547 548 549
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
550 551
		}

552 553
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
554 555 556
		break;

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

L
Linus Torvalds 已提交
561
		/*
562
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
L
Linus Torvalds 已提交
563 564 565
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
566 567 568
		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 已提交
569
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
570
			    "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
571
			    mb[2], mb[3]));
L
Linus Torvalds 已提交
572 573 574 575
			break;
		}

		DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
576
		    vha->host_no));
L
Linus Torvalds 已提交
577
		DEBUG(printk(KERN_INFO
578
		    "scsi(%ld): Port database changed %04x %04x %04x.\n",
579
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
580 581 582 583

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

586
		qla2x00_mark_all_devices_lost(vha, 1);
L
Linus Torvalds 已提交
587

588
		vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
589

590 591
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
L
Linus Torvalds 已提交
592 593 594
		break;

	case MBA_RSCN_UPDATE:		/* State Change Registration */
595
		/* Check if the Vport has issued a SCR */
596
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
597 598
			break;
		/* Only handle SCNs for our Vport index. */
599
		if (vha->vp_idx && vha->vp_idx != (mb[3] & 0xff))
600
			break;
L
Linus Torvalds 已提交
601
		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
602
		    vha->host_no));
L
Linus Torvalds 已提交
603
		DEBUG(printk(KERN_INFO
604
		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
605
		    vha->host_no, mb[1], mb[2], mb[3]));
L
Linus Torvalds 已提交
606

607
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
608 609
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
L
Linus Torvalds 已提交
610 611 612 613
		if (rscn_entry == host_pid) {
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Ignoring RSCN update to local host "
			    "port ID (%06x)\n",
614
			    vha->host_no, host_pid));
L
Linus Torvalds 已提交
615 616 617
			break;
		}

618 619
		/* Ignore reserved bits from RSCN-payload. */
		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
620
		rscn_queue_index = vha->rscn_in_ptr + 1;
L
Linus Torvalds 已提交
621 622
		if (rscn_queue_index == MAX_RSCN_COUNT)
			rscn_queue_index = 0;
623 624 625
		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 已提交
626
		} else {
627
			vha->flags.rscn_queue_overflow = 1;
L
Linus Torvalds 已提交
628 629
		}

630 631 632
		atomic_set(&vha->loop_state, LOOP_UPDATE);
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
L
Linus Torvalds 已提交
633

634 635 636
		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 已提交
637 638 639 640
		break;

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

644
		if (IS_FWI2_CAPABLE(ha))
645
			qla24xx_process_response_queue(rsp);
646
		else
647
			qla2x00_process_response_queue(rsp);
L
Linus Torvalds 已提交
648
		break;
649 650 651

	case MBA_DISCARD_RND_FRAME:
		DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
652
		    "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
653
		break;
654 655 656

	case MBA_TRACE_NOTIFICATION:
		DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
657
		vha->host_no, mb[1], mb[2]));
658
		break;
659 660 661

	case MBA_ISP84XX_ALERT:
		DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
662
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694

		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;
L
Linus Torvalds 已提交
695
	}
696

697
	if (!vha->vp_idx && ha->num_vhosts)
698
		qla2x00_alert_all_vps(rsp, mb);
L
Linus Torvalds 已提交
699 700
}

701 702 703 704
static void
qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, void *data)
{
	fc_port_t *fcport = data;
705 706 707 708 709 710 711 712
	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)
713 714 715 716 717 718 719 720 721 722 723
		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;

724
	DEBUG2(qla_printk(KERN_INFO, ha,
725
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-up to %d.\n",
726
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
727 728 729 730 731 732 733 734 735 736 737
	    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;

738
	DEBUG2(qla_printk(KERN_INFO, fcport->vha->hw,
739
	    "scsi(%ld:%d:%d:%d): Queue depth adjusted-down to %d.\n",
740
	    fcport->vha->host_no, sdev->channel, sdev->id, sdev->lun,
741 742 743 744
	    sdev->queue_depth));
}

static inline void
745 746
qla2x00_ramp_up_queue_depth(scsi_qla_host_t *vha, struct req_que *req,
								srb_t *sp)
747 748 749 750 751
{
	fc_port_t *fcport;
	struct scsi_device *sdev;

	sdev = sp->cmd->device;
752
	if (sdev->queue_depth >= req->max_q_depth)
753 754 755 756 757 758 759 760 761 762 763 764 765 766
		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 已提交
767 768 769 770 771 772
/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
static void
773 774
qla2x00_process_completed_request(struct scsi_qla_host *vha,
				struct req_que *req, uint32_t index)
L
Linus Torvalds 已提交
775 776
{
	srb_t *sp;
777
	struct qla_hw_data *ha = vha->hw;
L
Linus Torvalds 已提交
778 779 780 781

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

786
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
787 788 789
		return;
	}

790
	sp = req->outstanding_cmds[index];
L
Linus Torvalds 已提交
791 792
	if (sp) {
		/* Free outstanding command slot. */
793
		req->outstanding_cmds[index] = NULL;
L
Linus Torvalds 已提交
794 795 796 797 798 799

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

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

801 802
		qla2x00_ramp_up_queue_depth(vha, req, sp);
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
803 804
	} else {
		DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
805
		    vha->host_no));
L
Linus Torvalds 已提交
806 807 808
		qla_printk(KERN_WARNING, ha,
		    "Invalid ISP SCSI completion handle\n");

809
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
L
Linus Torvalds 已提交
810 811 812 813 814 815 816 817
	}
}

/**
 * qla2x00_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
818
qla2x00_process_response_queue(struct rsp_que *rsp)
L
Linus Torvalds 已提交
819
{
820 821
	struct scsi_qla_host *vha;
	struct qla_hw_data *ha = rsp->hw;
822
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
L
Linus Torvalds 已提交
823 824 825
	sts_entry_t	*pkt;
	uint16_t        handle_cnt;
	uint16_t        cnt;
826 827

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

829
	if (!vha->flags.online)
L
Linus Torvalds 已提交
830 831
		return;

832 833
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (sts_entry_t *)rsp->ring_ptr;
L
Linus Torvalds 已提交
834

835 836 837 838
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
L
Linus Torvalds 已提交
839
		} else {
840
			rsp->ring_ptr++;
L
Linus Torvalds 已提交
841 842 843 844
		}

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

847
			qla2x00_error_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
848 849 850 851 852 853 854
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
855
			qla2x00_status_entry(vha, rsp, pkt);
L
Linus Torvalds 已提交
856 857 858 859
			break;
		case STATUS_TYPE_21:
			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
			for (cnt = 0; cnt < handle_cnt; cnt++) {
860
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
861 862 863 864 865 866
				    ((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++) {
867
				qla2x00_process_completed_request(vha, rsp->req,
L
Linus Torvalds 已提交
868 869 870 871
				    ((sts22_entry_t *)pkt)->handle[cnt]);
			}
			break;
		case STATUS_CONT_TYPE:
872
			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
L
Linus Torvalds 已提交
873 874 875 876 877 878
			break;
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
879
			    vha->host_no, pkt->entry_type, pkt->entry_status));
L
Linus Torvalds 已提交
880 881 882 883 884 885 886
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

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

890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
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)
909
		sp->fcport->vha->status_srb = sp;
910 911

	DEBUG5(printk("%s(): Check condition Sense data, scsi(%ld:%d:%d:%d) "
912
	    "cmd=%p pid=%ld\n", __func__, sp->fcport->vha->host_no,
913 914
	    cp->device->channel, cp->device->id, cp->device->lun, cp,
	    cp->serial_number));
915 916 917 918 919
	if (sense_len)
		DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
		    CMD_ACTUAL_SNSLEN(cp)));
}

L
Linus Torvalds 已提交
920 921 922 923 924 925
/**
 * qla2x00_status_entry() - Process a Status IOCB entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
926
qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt)
L
Linus Torvalds 已提交
927 928 929 930
{
	srb_t		*sp;
	fc_port_t	*fcport;
	struct scsi_cmnd *cp;
931 932
	sts_entry_t *sts;
	struct sts_entry_24xx *sts24;
L
Linus Torvalds 已提交
933 934 935 936
	uint16_t	comp_status;
	uint16_t	scsi_status;
	uint8_t		lscsi_status;
	int32_t		resid;
937
	uint32_t	sense_len, rsp_info_len, resid_len, fw_resid_len;
938
	uint8_t		*rsp_info, *sense_data;
939
	struct qla_hw_data *ha = vha->hw;
940
	struct req_que *req = rsp->req;
941 942 943

	sts = (sts_entry_t *) pkt;
	sts24 = (struct sts_entry_24xx *) pkt;
944
	if (IS_FWI2_CAPABLE(ha)) {
945 946 947 948 949 950
		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 已提交
951 952

	/* Fast path completion. */
953
	if (comp_status == CS_COMPLETE && scsi_status == 0) {
954
		qla2x00_process_completed_request(vha, req, sts->handle);
L
Linus Torvalds 已提交
955 956 957 958 959

		return;
	}

	/* Validate handle. */
960
	if (sts->handle < MAX_OUTSTANDING_COMMANDS) {
961 962
		sp = req->outstanding_cmds[sts->handle];
		req->outstanding_cmds[sts->handle] = NULL;
L
Linus Torvalds 已提交
963 964 965 966 967
	} else
		sp = NULL;

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

971 972
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
973 974 975 976 977
		return;
	}
	cp = sp->cmd;
	if (cp == NULL) {
		DEBUG2(printk("scsi(%ld): Command already returned back to OS "
978
		    "pkt->handle=%d sp=%p.\n", vha->host_no, sts->handle, sp));
L
Linus Torvalds 已提交
979 980 981 982 983 984
		qla_printk(KERN_WARNING, ha,
		    "Command is NULL: already returned to OS (sp=%p)\n", sp);

		return;
	}

985 986
  	lscsi_status = scsi_status & STATUS_MASK;
	CMD_ENTRY_STATUS(cp) = sts->entry_status;
L
Linus Torvalds 已提交
987 988 989
	CMD_COMPL_STATUS(cp) = comp_status;
	CMD_SCSI_STATUS(cp) = scsi_status;

990
	fcport = sp->fcport;
L
Linus Torvalds 已提交
991

992
	sense_len = rsp_info_len = resid_len = fw_resid_len = 0;
993
	if (IS_FWI2_CAPABLE(ha)) {
994 995 996
		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);
997
		fw_resid_len = le32_to_cpu(sts24->residual_len);
998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
		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 已提交
1009 1010
	/* Check for any FCP transport errors. */
	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
1011
		/* Sense data lies beyond any FCP RESPONSE data. */
1012
		if (IS_FWI2_CAPABLE(ha))
1013 1014
			sense_data += rsp_info_len;
		if (rsp_info_len > 3 && rsp_info[3]) {
L
Linus Torvalds 已提交
1015 1016
			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
1017
			    "retrying command\n", vha->host_no,
1018 1019 1020 1021
			    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 已提交
1022 1023

			cp->result = DID_BUS_BUSY << 16;
1024
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1025 1026 1027 1028
			return;
		}
	}

1029 1030 1031 1032 1033
	/* 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 已提交
1034 1035 1036 1037 1038
	/*
	 * Based on Host and scsi status generate status code for Linux
	 */
	switch (comp_status) {
	case CS_COMPLETE:
1039
	case CS_QUEUE_FULL:
L
Linus Torvalds 已提交
1040 1041 1042 1043 1044
		if (scsi_status == 0) {
			cp->result = DID_OK << 16;
			break;
		}
		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
1045
			resid = resid_len;
1046
			scsi_set_resid(cp, resid);
L
Linus Torvalds 已提交
1047
			CMD_RESID_LEN(cp) = resid;
1048 1049

			if (!lscsi_status &&
1050
			    ((unsigned)(scsi_bufflen(cp) - resid) <
1051 1052
			     cp->underflow)) {
				qla_printk(KERN_INFO, ha,
1053 1054
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1055
					   "error status.\n", vha->host_no,
1056 1057 1058
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
1059 1060 1061 1062

				cp->result = DID_ERROR << 16;
				break;
			}
L
Linus Torvalds 已提交
1063 1064 1065
		}
		cp->result = DID_OK << 16 | lscsi_status;

1066 1067 1068
		if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld): QUEUE FULL status detected "
1069
			    "0x%x-0x%x.\n", vha->host_no, comp_status,
1070 1071 1072 1073 1074 1075 1076 1077
			    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 已提交
1078 1079 1080
		if (lscsi_status != SS_CHECK_CONDITION)
			break;

1081
		memset(cp->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
L
Linus Torvalds 已提交
1082 1083 1084
		if (!(scsi_status & SS_SENSE_LEN_VALID))
			break;

1085
		qla2x00_handle_sense(sp, sense_data, sense_len);
L
Linus Torvalds 已提交
1086 1087 1088
		break;

	case CS_DATA_UNDERRUN:
1089
		resid = resid_len;
1090
		/* Use F/W calculated residual length. */
1091
		if (IS_FWI2_CAPABLE(ha)) {
1092 1093 1094
			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
				lscsi_status = 0;
			} else if (resid != fw_resid_len) {
1095 1096 1097
				scsi_status &= ~SS_RESIDUAL_UNDER;
				lscsi_status = 0;
			}
1098
			resid = fw_resid_len;
1099
		}
1100

L
Linus Torvalds 已提交
1101
		if (scsi_status & SS_RESIDUAL_UNDER) {
1102
			scsi_set_resid(cp, resid);
L
Linus Torvalds 已提交
1103
			CMD_RESID_LEN(cp) = resid;
1104 1105 1106
		} else {
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d) UNDERRUN status detected "
1107
			    "0x%x-0x%x. resid=0x%x fw_resid=0x%x cdb=0x%x "
1108
			    "os_underflow=0x%x\n", vha->host_no,
1109 1110 1111
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status, resid_len, resid, cp->cmnd[0],
			    cp->underflow));
1112

L
Linus Torvalds 已提交
1113 1114 1115
		}

		/*
A
Andrew Vasquez 已提交
1116
		 * Check to see if SCSI Status is non zero. If so report SCSI
L
Linus Torvalds 已提交
1117 1118 1119 1120 1121
		 * Status.
		 */
		if (lscsi_status != 0) {
			cp->result = DID_OK << 16 | lscsi_status;

1122 1123 1124
			if (lscsi_status == SAM_STAT_TASK_SET_FULL) {
				DEBUG2(printk(KERN_INFO
				    "scsi(%ld): QUEUE FULL status detected "
1125
				    "0x%x-0x%x.\n", vha->host_no, comp_status,
1126 1127 1128 1129 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 1149 1150 1151 1152 1153
		} 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 "
1154
					      "frame(s) detected (%x of %x bytes)..."
1155 1156 1157 1158
					      "retrying command.\n",
					vha->host_no, cp->device->channel,
					cp->device->id, cp->device->lun, resid,
					scsi_bufflen(cp)));
L
Linus Torvalds 已提交
1159 1160 1161 1162 1163 1164

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

			/* Handle mid-layer underflow */
1165
			if ((unsigned)(scsi_bufflen(cp) - resid) <
L
Linus Torvalds 已提交
1166 1167
			    cp->underflow) {
				qla_printk(KERN_INFO, ha,
1168 1169
					   "scsi(%ld:%d:%d:%d): Mid-layer underflow "
					   "detected (%x of %x bytes)...returning "
1170
					   "error status.\n", vha->host_no,
1171 1172 1173
					   cp->device->channel, cp->device->id,
					   cp->device->lun, resid,
					   scsi_bufflen(cp));
L
Linus Torvalds 已提交
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186

				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",
1187
		    vha->host_no, cp->device->id, cp->device->lun, comp_status,
1188
		    scsi_status));
L
Linus Torvalds 已提交
1189 1190 1191 1192 1193 1194 1195
		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",
1196
		    cp->serial_number, scsi_bufflen(cp), resid_len));
L
Linus Torvalds 已提交
1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212

		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",
1213
		    vha->host_no, cp->device->id, cp->device->lun,
1214
		    cp->serial_number, comp_status,
L
Linus Torvalds 已提交
1215 1216
		    atomic_read(&fcport->state)));

1217 1218 1219 1220 1221 1222
		/*
		 * 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;
1223
		if (atomic_read(&fcport->state) == FCS_ONLINE)
1224
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1225 1226 1227 1228 1229
		break;

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

已提交
1232
		cp->result = DID_RESET << 16;
L
Linus Torvalds 已提交
1233 1234 1235
		break;

	case CS_ABORTED:
A
Andrew Vasquez 已提交
1236
		/*
L
Linus Torvalds 已提交
1237 1238 1239 1240 1241 1242
		 * 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",
1243
		    vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1244 1245 1246 1247 1248

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

	case CS_TIMEOUT:
1249 1250 1251 1252 1253 1254
		/*
		 * 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;
1255

1256
		if (IS_FWI2_CAPABLE(ha)) {
1257 1258
			DEBUG2(printk(KERN_INFO
			    "scsi(%ld:%d:%d:%d): TIMEOUT status detected "
1259
			    "0x%x-0x%x\n", vha->host_no, cp->device->channel,
1260 1261 1262 1263
			    cp->device->id, cp->device->lun, comp_status,
			    scsi_status));
			break;
		}
L
Linus Torvalds 已提交
1264 1265
		DEBUG2(printk(KERN_INFO
		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
1266
		    "sflags=%x.\n", vha->host_no, cp->device->channel,
1267 1268
		    cp->device->id, cp->device->lun, comp_status, scsi_status,
		    le16_to_cpu(sts->status_flags)));
L
Linus Torvalds 已提交
1269

1270 1271
		/* Check to see if logout occurred. */
		if ((le16_to_cpu(sts->status_flags) & SF_LOGOUT_SENT))
1272
			qla2x00_mark_device_lost(fcport->vha, fcport, 1, 1);
L
Linus Torvalds 已提交
1273 1274 1275 1276
		break;

	default:
		DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
1277
		    "0x%x-0x%x.\n", vha->host_no, comp_status, scsi_status));
L
Linus Torvalds 已提交
1278 1279 1280 1281 1282 1283 1284 1285 1286
		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. */
1287
	if (vha->status_srb == NULL)
1288
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
}

/**
 * qla2x00_status_cont_entry() - Process a Status Continuations entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 *
 * Extended sense data.
 */
static void
1299
qla2x00_status_cont_entry(scsi_qla_host_t *vha, sts_cont_entry_t *pkt)
L
Linus Torvalds 已提交
1300 1301
{
	uint8_t		sense_sz = 0;
1302 1303
	struct qla_hw_data *ha = vha->hw;
	srb_t		*sp = vha->status_srb;
L
Linus Torvalds 已提交
1304 1305 1306 1307 1308 1309
	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 "
1310
			    "sp=%p.\n", __func__, sp));
L
Linus Torvalds 已提交
1311 1312
			qla_printk(KERN_INFO, ha,
			    "cmd is NULL: already returned to OS (sp=%p)\n",
A
Andrew Vasquez 已提交
1313
			    sp);
L
Linus Torvalds 已提交
1314

1315
			vha->status_srb = NULL;
L
Linus Torvalds 已提交
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
			return;
		}

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

		/* Move sense data. */
1326
		if (IS_FWI2_CAPABLE(ha))
1327
			host_to_fcp_swap(pkt->data, sizeof(pkt->data));
L
Linus Torvalds 已提交
1328 1329 1330 1331 1332 1333 1334 1335
		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) {
1336
			vha->status_srb = NULL;
1337
			qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1338 1339 1340 1341 1342 1343 1344 1345 1346 1347
		}
	}
}

/**
 * qla2x00_error_entry() - Process an error entry.
 * @ha: SCSI driver HA context
 * @pkt: Entry pointer
 */
static void
1348
qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt)
L
Linus Torvalds 已提交
1349 1350
{
	srb_t *sp;
1351
	struct qla_hw_data *ha = vha->hw;
1352
	struct req_que *req = rsp->req;
L
Linus Torvalds 已提交
1353 1354 1355 1356 1357 1358
#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 已提交
1359
		qla_printk(KERN_ERR, ha,
L
Linus Torvalds 已提交
1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370
		    "%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)
1371
		sp = req->outstanding_cmds[pkt->handle];
L
Linus Torvalds 已提交
1372 1373 1374 1375 1376
	else
		sp = NULL;

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

L
Linus Torvalds 已提交
1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
		/* 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;
		}
1389
		qla2x00_sp_compl(ha, sp);
L
Linus Torvalds 已提交
1390

1391 1392
	} else if (pkt->entry_type == COMMAND_A64_TYPE || pkt->entry_type ==
	    COMMAND_TYPE || pkt->entry_type == COMMAND_TYPE_7) {
L
Linus Torvalds 已提交
1393
		DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
1394
		    vha->host_no));
L
Linus Torvalds 已提交
1395 1396 1397
		qla_printk(KERN_WARNING, ha,
		    "Error entry - invalid handle\n");

1398 1399
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		qla2xxx_wake_dpc(vha);
L
Linus Torvalds 已提交
1400 1401 1402
	}
}

1403 1404 1405 1406 1407 1408
/**
 * qla24xx_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
1409
qla24xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
1410 1411 1412
{
	uint16_t	cnt;
	uint16_t __iomem *wptr;
1413
	struct qla_hw_data *ha = vha->hw;
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427
	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",
1428
		    __func__, vha->host_no, ha->mcp->mb[0]));
1429 1430
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
1431
		    __func__, vha->host_no));
1432 1433 1434 1435 1436 1437 1438 1439
	}
}

/**
 * qla24xx_process_response_queue() - Process response queue entries.
 * @ha: SCSI driver HA context
 */
void
1440
qla24xx_process_response_queue(struct rsp_que *rsp)
1441
{
1442
	struct qla_hw_data *ha = rsp->hw;
1443
	struct sts_entry_24xx *pkt;
1444 1445 1446
	struct scsi_qla_host *vha;

	vha = qla2x00_get_rsp_host(rsp);
1447

1448
	if (!vha->flags.online)
1449 1450
		return;

1451 1452
	while (rsp->ring_ptr->signature != RESPONSE_PROCESSED) {
		pkt = (struct sts_entry_24xx *)rsp->ring_ptr;
1453

1454 1455 1456 1457
		rsp->ring_index++;
		if (rsp->ring_index == rsp->length) {
			rsp->ring_index = 0;
			rsp->ring_ptr = rsp->ring;
1458
		} else {
1459
			rsp->ring_ptr++;
1460 1461 1462 1463
		}

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

1466
			qla2x00_error_entry(vha, rsp, (sts_entry_t *) pkt);
1467 1468 1469 1470 1471 1472 1473
			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
			wmb();
			continue;
		}

		switch (pkt->entry_type) {
		case STATUS_TYPE:
1474
			qla2x00_status_entry(vha, rsp, pkt);
1475 1476
			break;
		case STATUS_CONT_TYPE:
1477
			qla2x00_status_cont_entry(vha, (sts_cont_entry_t *)pkt);
1478
			break;
1479
		case VP_RPT_ID_IOCB_TYPE:
1480
			qla24xx_report_id_acquisition(vha,
1481 1482
			    (struct vp_rpt_id_entry_24xx *)pkt);
			break;
1483 1484 1485 1486 1487
		default:
			/* Type Not Supported. */
			DEBUG4(printk(KERN_WARNING
			    "scsi(%ld): Received unknown response pkt type %x "
			    "entry status=%x.\n",
1488
			    vha->host_no, pkt->entry_type, pkt->entry_status));
1489 1490 1491 1492 1493 1494 1495
			break;
		}
		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
		wmb();
	}

	/* Adjust ring index */
1496
	ha->isp_ops->wrt_rsp_reg(ha, rsp->id, rsp->ring_index);
1497 1498
}

1499
static void
1500
qla2xxx_check_risc_status(scsi_qla_host_t *vha)
1501 1502 1503
{
	int rval;
	uint32_t cnt;
1504
	struct qla_hw_data *ha = vha->hw;
1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

	if (!IS_QLA25XX(ha))
		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);
}

1546 1547 1548 1549 1550 1551 1552 1553 1554 1555
/**
 * 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
1556
qla24xx_intr_handler(int irq, void *dev_id)
1557
{
1558 1559
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
1560 1561 1562 1563 1564 1565
	struct device_reg_24xx __iomem *reg;
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];
1566
	struct rsp_que *rsp;
1567

1568 1569
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
1570
		printk(KERN_INFO
1571
		    "%s(): NULL response queue pointer\n", __func__);
1572 1573 1574
		return IRQ_NONE;
	}

1575
	ha = rsp->hw;
1576 1577 1578
	reg = &ha->iobase->isp24;
	status = 0;

1579
	spin_lock(&ha->hardware_lock);
1580
	vha = qla2x00_get_rsp_host(rsp);
1581 1582 1583
	for (iter = 50; iter--; ) {
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1584 1585 1586
			if (pci_channel_offline(ha->pdev))
				break;

1587 1588 1589 1590
			hccr = RD_REG_DWORD(&reg->hccr);

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

1592
			qla2xxx_check_risc_status(vha);
1593

1594 1595
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1596 1597 1598 1599 1600 1601 1602 1603 1604
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1605
			qla24xx_mbx_completion(vha, MSW(stat));
1606 1607 1608 1609 1610 1611 1612 1613
			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);
1614
			qla2x00_async_event(vha, rsp, mb);
1615 1616
			break;
		case 0x13:
1617 1618
		case 0x14:
			qla24xx_process_response_queue(rsp);
1619 1620 1621 1622
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1623
			    vha->host_no, stat & 0xff));
1624 1625 1626 1627 1628
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
		RD_REG_DWORD_RELAXED(&reg->hccr);
	}
1629
	spin_unlock(&ha->hardware_lock);
1630 1631 1632 1633

	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);
1634
		complete(&ha->mbx_intr_comp);
1635 1636 1637 1638 1639
	}

	return IRQ_HANDLED;
}

1640 1641 1642
static irqreturn_t
qla24xx_msix_rsp_q(int irq, void *dev_id)
{
1643 1644
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1645 1646
	struct device_reg_24xx __iomem *reg;

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

1656
	spin_lock_irq(&ha->hardware_lock);
1657

1658
	qla24xx_process_response_queue(rsp);
1659 1660
	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);

1661
	spin_unlock_irq(&ha->hardware_lock);
1662 1663 1664 1665

	return IRQ_HANDLED;
}

1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
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;
	uint16_t msix_disabled_hccr = 0;

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

	msix_disabled_hccr = rsp->options;
	if (!rsp->id)
		msix_disabled_hccr &= __constant_cpu_to_le32(BIT_22);
	else
1689
		msix_disabled_hccr &= __constant_cpu_to_le32(BIT_6);
1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700

	qla24xx_process_response_queue(rsp);

	if (!msix_disabled_hccr)
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);

	spin_unlock_irq(&ha->hardware_lock);

	return IRQ_HANDLED;
}

1701 1702 1703
static irqreturn_t
qla24xx_msix_default(int irq, void *dev_id)
{
1704 1705 1706
	scsi_qla_host_t	*vha;
	struct qla_hw_data *ha;
	struct rsp_que *rsp;
1707 1708 1709 1710 1711 1712
	struct device_reg_24xx __iomem *reg;
	int		status;
	uint32_t	stat;
	uint32_t	hccr;
	uint16_t	mb[4];

1713 1714 1715 1716 1717 1718 1719
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
		DEBUG(printk(
		"%s(): NULL response queue pointer\n", __func__));
		return IRQ_NONE;
	}
	ha = rsp->hw;
1720 1721 1722
	reg = &ha->iobase->isp24;
	status = 0;

1723
	spin_lock_irq(&ha->hardware_lock);
1724
	vha = qla2x00_get_rsp_host(rsp);
1725
	do {
1726 1727
		stat = RD_REG_DWORD(&reg->host_status);
		if (stat & HSRX_RISC_PAUSED) {
1728 1729 1730
			if (pci_channel_offline(ha->pdev))
				break;

1731 1732 1733 1734
			hccr = RD_REG_DWORD(&reg->hccr);

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

1736
			qla2xxx_check_risc_status(vha);
1737

1738 1739
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
1740 1741 1742 1743 1744 1745 1746 1747 1748
			break;
		} else if ((stat & HSRX_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
1749
			qla24xx_mbx_completion(vha, MSW(stat));
1750 1751 1752 1753 1754 1755 1756 1757
			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);
1758
			qla2x00_async_event(vha, rsp, mb);
1759 1760
			break;
		case 0x13:
1761 1762
		case 0x14:
			qla24xx_process_response_queue(rsp);
1763 1764 1765 1766
			break;
		default:
			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
			    "(%d).\n",
1767
			    vha->host_no, stat & 0xff));
1768 1769 1770
			break;
		}
		WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
1771
	} while (0);
1772
	spin_unlock_irq(&ha->hardware_lock);
1773 1774 1775 1776

	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);
1777
		complete(&ha->mbx_intr_comp);
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788
	}

	return IRQ_HANDLED;
}

/* Interrupt handling helpers. */

struct qla_init_msix_entry {
	uint16_t entry;
	uint16_t index;
	const char *name;
1789
	irq_handler_t handler;
1790 1791
};

1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804
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,
};
1805

1806 1807 1808 1809 1810
static struct qla_init_msix_entry multi_rsp_queue = {
	.entry = 1,
	.index = 1,
	.name = "qla2xxx (multi_q)",
	.handler = qla25xx_msix_rsp_q,
1811 1812 1813
};

static void
1814
qla24xx_disable_msix(struct qla_hw_data *ha)
1815 1816 1817 1818
{
	int i;
	struct qla_msix_entry *qentry;

1819 1820
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
1821
		if (qentry->have_irq)
1822
			free_irq(qentry->vector, qentry->rsp);
1823 1824
	}
	pci_disable_msix(ha->pdev);
1825 1826 1827
	kfree(ha->msix_entries);
	ha->msix_entries = NULL;
	ha->flags.msix_enabled = 0;
1828 1829 1830
}

static int
1831
qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp)
1832 1833
{
	int i, ret;
1834
	struct msix_entry *entries;
1835
	struct qla_msix_entry *qentry;
1836 1837 1838 1839 1840 1841
	struct qla_init_msix_entry *msix_queue;

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

1843 1844
	for (i = 0; i < ha->msix_count; i++)
		entries[i].entry = i;
1845

1846
	ret = pci_enable_msix(ha->pdev, entries, ha->msix_count);
1847 1848
	if (ret) {
		qla_printk(KERN_WARNING, ha,
1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864
			"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) {
			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;
1865 1866 1867 1868
		goto msix_out;
	}
	ha->flags.msix_enabled = 1;

1869 1870 1871 1872
	for (i = 0; i < ha->msix_count; i++) {
		qentry = &ha->msix_entries[i];
		qentry->vector = entries[i].vector;
		qentry->entry = entries[i].entry;
1873
		qentry->have_irq = 0;
1874
		qentry->rsp = NULL;
1875 1876
	}

1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916
	/* 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;

1917
msix_out:
1918
	kfree(entries);
1919 1920 1921 1922
	return ret;
}

int
1923
qla2x00_request_irqs(struct qla_hw_data *ha, struct rsp_que *rsp)
1924 1925
{
	int ret;
1926
	device_reg_t __iomem *reg = ha->iobase;
1927 1928

	/* If possible, enable MSI-X. */
1929
	if (!IS_QLA2432(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
1930 1931
		goto skip_msix;

1932 1933
	if (IS_QLA2432(ha) && (ha->pdev->revision < QLA_MSIX_CHIP_REV_24XX ||
		!QLA_MSIX_FW_MODE_1(ha->fw_attributes))) {
1934
		DEBUG2(qla_printk(KERN_WARNING, ha,
1935 1936
		"MSI-X: Unsupported ISP2432 (0x%X, 0x%X).\n",
			ha->pdev->revision, ha->fw_attributes));
1937 1938 1939 1940

		goto skip_msix;
	}

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

1953
	ret = qla24xx_enable_msix(ha, rsp);
1954 1955 1956 1957
	if (!ret) {
		DEBUG2(qla_printk(KERN_INFO, ha,
		    "MSI-X: Enabled (0x%X, 0x%X).\n", ha->chip_revision,
		    ha->fw_attributes));
1958
		goto clear_risc_ints;
1959 1960 1961 1962
	}
	qla_printk(KERN_WARNING, ha,
	    "MSI-X: Falling back-to INTa mode -- %d.\n", ret);
skip_msix:
1963

1964
	if (!IS_QLA24XX(ha) && !IS_QLA2532(ha) && !IS_QLA8432(ha))
1965 1966 1967 1968 1969 1970 1971 1972 1973
		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:

1974
	ret = request_irq(ha->pdev->irq, ha->isp_ops->intr_handler,
1975
	    IRQF_DISABLED|IRQF_SHARED, QLA2XXX_DRIVER_NAME, rsp);
1976
	if (ret) {
1977 1978 1979
		qla_printk(KERN_WARNING, ha,
		    "Failed to reserve interrupt %d already in use.\n",
		    ha->pdev->irq);
1980 1981 1982 1983 1984
		goto fail;
	}
	ha->flags.inta_enabled = 1;
clear_risc_ints:

1985
	spin_lock_irq(&ha->hardware_lock);
1986 1987 1988 1989 1990 1991 1992
	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);
1993
	}
1994
	spin_unlock_irq(&ha->hardware_lock);
1995

1996
fail:
1997 1998 1999 2000
	return ret;
}

void
2001
qla2x00_free_irqs(scsi_qla_host_t *vha)
2002
{
2003
	struct qla_hw_data *ha = vha->hw;
2004
	struct rsp_que *rsp = ha->rsp_q_map[0];
2005 2006 2007

	if (ha->flags.msix_enabled)
		qla24xx_disable_msix(ha);
2008
	else if (ha->flags.inta_enabled) {
2009
		free_irq(ha->pdev->irq, rsp);
2010 2011
		pci_disable_msi(ha->pdev);
	}
2012
}
2013 2014 2015 2016 2017 2018 2019

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;
2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030
	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)
				vha = sp->vha;
		}
2031 2032
	}
	if (!vha)
2033
	/* handle it in base queue */
2034 2035 2036 2037
		vha = pci_get_drvdata(ha->pdev);

	return vha;
}
2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057

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

2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
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);
}