qla_isr.c 66.7 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
 * QLogic Fibre Channel HBA Driver
3
 * Copyright (c)  2003-2008 QLogic Corporation
Linus Torvalds's avatar
Linus Torvalds committed
4
 *
5
 * See LICENSE.qla2xxx for copyright and licensing details.
Linus Torvalds's avatar
Linus Torvalds committed
6
7
8
 */
#include "qla_def.h"

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

Linus Torvalds's avatar
Linus Torvalds committed
15
static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
16
17
18
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 *);
19
static void qla2x00_status_cont_entry(struct rsp_que *, sts_cont_entry_t *);
20
21
static void qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *,
	sts_entry_t *);
22

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

45
46
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
Linus Torvalds's avatar
Linus Torvalds committed
47
		printk(KERN_INFO
48
		    "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
49
50
51
		return (IRQ_NONE);
	}

52
	ha = rsp->hw;
53
	reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
54
55
	status = 0;

56
	spin_lock_irqsave(&ha->hardware_lock, flags);
57
	vha = pci_get_drvdata(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
58
	for (iter = 50; iter--; ) {
59
60
61
62
63
64
65
66
67
68
69
70
71
		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);

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

			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
			RD_REG_WORD(&reg->hccr);
		}
	}
108
	spin_unlock_irqrestore(&ha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
109
110
111
112

	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);
113
		complete(&ha->mbx_intr_comp);
Linus Torvalds's avatar
Linus Torvalds committed
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
	}

	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
129
qla2300_intr_handler(int irq, void *dev_id)
Linus Torvalds's avatar
Linus Torvalds committed
130
{
131
	scsi_qla_host_t	*vha;
132
	struct device_reg_2xxx __iomem *reg;
Linus Torvalds's avatar
Linus Torvalds committed
133
134
135
136
	int		status;
	unsigned long	iter;
	uint32_t	stat;
	uint16_t	hccr;
137
	uint16_t	mb[4];
138
139
	struct rsp_que *rsp;
	struct qla_hw_data *ha;
140
	unsigned long	flags;
Linus Torvalds's avatar
Linus Torvalds committed
141

142
143
	rsp = (struct rsp_que *) dev_id;
	if (!rsp) {
Linus Torvalds's avatar
Linus Torvalds committed
144
		printk(KERN_INFO
145
		    "%s(): NULL response queue pointer\n", __func__);
Linus Torvalds's avatar
Linus Torvalds committed
146
147
148
		return (IRQ_NONE);
	}

149
	ha = rsp->hw;
150
	reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
151
152
	status = 0;

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

Linus Torvalds's avatar
Linus Torvalds committed
161
162
			hccr = RD_REG_WORD(&reg->hccr);
			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
163
164
				qla_printk(KERN_INFO, ha, "Parity error -- "
				    "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds's avatar
Linus Torvalds committed
165
			else
166
167
				qla_printk(KERN_INFO, ha, "RISC paused -- "
				    "HCCR=%x, Dumping firmware!\n", hccr);
Linus Torvalds's avatar
Linus Torvalds committed
168
169
170
171
172
173
174
175

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

177
178
			ha->isp_ops->fw_dump(vha, 1);
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
179
180
181
182
183
184
185
186
187
			break;
		} else if ((stat & HSR_RISC_INT) == 0)
			break;

		switch (stat & 0xff) {
		case 0x1:
		case 0x2:
		case 0x10:
		case 0x11:
188
			qla2x00_mbx_completion(vha, MSW(stat));
Linus Torvalds's avatar
Linus Torvalds committed
189
190
191
192
193
194
			status |= MBX_INTERRUPT;

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

	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);
229
		complete(&ha->mbx_intr_comp);
Linus Torvalds's avatar
Linus Torvalds committed
230
231
232
233
234
235
236
237
238
239
240
	}

	return (IRQ_HANDLED);
}

/**
 * qla2x00_mbx_completion() - Process mailbox command completions.
 * @ha: SCSI driver HA context
 * @mb0: Mailbox0 register
 */
static void
241
qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
Linus Torvalds's avatar
Linus Torvalds committed
242
243
244
{
	uint16_t	cnt;
	uint16_t __iomem *wptr;
245
	struct qla_hw_data *ha = vha->hw;
246
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
247
248
249
250
251
252
253

	/* 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++) {
254
		if (IS_QLA2200(ha) && cnt == 8)
Linus Torvalds's avatar
Linus Torvalds committed
255
256
257
258
259
			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);
260

Linus Torvalds's avatar
Linus Torvalds committed
261
262
263
264
265
		wptr++;
	}

	if (ha->mcp) {
		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
266
		    __func__, vha->host_no, ha->mcp->mb[0]));
Linus Torvalds's avatar
Linus Torvalds committed
267
268
	} else {
		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
269
		    __func__, vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
270
271
272
	}
}

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

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

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

		for (cnt = 0; cnt < handle_cnt; cnt++)
390
391
			qla2x00_process_completed_request(vha, rsp->req,
				handles[cnt]);
Linus Torvalds's avatar
Linus Torvalds committed
392
393
394
		break;

	case MBA_RESET:			/* Reset */
395
396
		DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n",
			vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
397

398
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
399
400
401
		break;

	case MBA_SYSTEM_ERR:		/* System Error */
402
		mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox7) : 0;
Linus Torvalds's avatar
Linus Torvalds committed
403
		qla_printk(KERN_INFO, ha,
404
405
		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh "
		    "mbx7=%xh.\n", mb[1], mb[2], mb[3], mbx);
Linus Torvalds's avatar
Linus Torvalds committed
406

407
		ha->isp_ops->fw_dump(vha, 1);
Linus Torvalds's avatar
Linus Torvalds committed
408

409
		if (IS_FWI2_CAPABLE(ha)) {
410
411
412
413
			if (mb[1] == 0 && mb[2] == 0) {
				qla_printk(KERN_ERR, ha,
				    "Unrecoverable Hardware Error: adapter "
				    "marked OFFLINE!\n");
414
				vha->flags.online = 0;
415
			} else
416
				set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
417
		} else if (mb[1] == 0) {
Linus Torvalds's avatar
Linus Torvalds committed
418
419
420
			qla_printk(KERN_INFO, ha,
			    "Unrecoverable Hardware Error: adapter marked "
			    "OFFLINE!\n");
421
			vha->flags.online = 0;
Linus Torvalds's avatar
Linus Torvalds committed
422
		} else
423
			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
424
425
426
		break;

	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
427
428
429
430
		DEBUG2(printk("scsi(%ld): ISP Request Transfer Error (%x).\n",
		    vha->host_no, mb[1]));
		qla_printk(KERN_WARNING, ha,
		    "ISP Request Transfer Error (%x).\n", mb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
431

432
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
433
434
435
436
		break;

	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
		DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
437
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
438
439
		qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");

440
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
441
442
443
444
		break;

	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
		DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
445
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
446
447
448
		break;

	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
449
		DEBUG2(printk("scsi(%ld): LIP occurred (%x).\n", vha->host_no,
Linus Torvalds's avatar
Linus Torvalds committed
450
		    mb[1]));
451
		qla_printk(KERN_INFO, ha, "LIP occurred (%x).\n", mb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
452

453
454
455
456
		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);
Linus Torvalds's avatar
Linus Torvalds committed
457
458
		}

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

464
465
		set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags);
		set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
466

467
468
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIP, mb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
469
470
471
472
473
		break;

	case MBA_LOOP_UP:		/* Loop Up Event */
		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
			link_speed = link_speeds[0];
474
			ha->link_data_rate = PORT_SPEED_1GB;
Linus Torvalds's avatar
Linus Torvalds committed
475
		} else {
476
			link_speed = link_speeds[LS_UNKNOWN];
Linus Torvalds's avatar
Linus Torvalds committed
477
478
			if (mb[1] < 5)
				link_speed = link_speeds[mb[1]];
479
480
			else if (mb[1] == 0x13)
				link_speed = link_speeds[5];
Linus Torvalds's avatar
Linus Torvalds committed
481
482
483
484
			ha->link_data_rate = mb[1];
		}

		DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
485
		    vha->host_no, link_speed));
Linus Torvalds's avatar
Linus Torvalds committed
486
487
488
		qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
		    link_speed);

489
490
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LINKUP, ha->link_data_rate);
Linus Torvalds's avatar
Linus Torvalds committed
491
492
493
		break;

	case MBA_LOOP_DOWN:		/* Loop Down Event */
494
		mbx = IS_QLA81XX(ha) ? RD_REG_WORD(&reg24->mailbox4) : 0;
495
		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN "
496
497
498
499
500
		    "(%x %x %x %x).\n", vha->host_no, mb[1], mb[2], mb[3],
		    mbx));
		qla_printk(KERN_INFO, ha,
		    "LOOP DOWN detected (%x %x %x %x).\n", mb[1], mb[2], mb[3],
		    mbx);
Linus Torvalds's avatar
Linus Torvalds committed
501

502
503
504
505
506
		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);
Linus Torvalds's avatar
Linus Torvalds committed
507
508
		}

509
510
511
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
512
513
		}

514
		vha->flags.management_server_logged_in = 0;
515
		ha->link_data_rate = PORT_SPEED_UNKNOWN;
516
		qla2x00_post_aen_work(vha, FCH_EVT_LINKDOWN, 0);
Linus Torvalds's avatar
Linus Torvalds committed
517
518
519
520
		break;

	case MBA_LIP_RESET:		/* LIP reset occurred */
		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
521
		    vha->host_no, mb[1]));
Linus Torvalds's avatar
Linus Torvalds committed
522
		qla_printk(KERN_INFO, ha,
523
		    "LIP reset occurred (%x).\n", mb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
524

525
526
527
528
		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);
Linus Torvalds's avatar
Linus Torvalds committed
529
530
		}

531
532
533
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
534
535
		}

536
		set_bit(RESET_MARKER_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
537
538

		ha->operating_mode = LOOP;
539
540
		vha->flags.management_server_logged_in = 0;
		qla2x00_post_aen_work(vha, FCH_EVT_LIPRESET, mb[1]);
Linus Torvalds's avatar
Linus Torvalds committed
541
542
		break;

543
	/* case MBA_DCBX_COMPLETE: */
Linus Torvalds's avatar
Linus Torvalds committed
544
545
546
547
	case MBA_POINT_TO_POINT:	/* Point-to-Point */
		if (IS_QLA2100(ha))
			break;

548
		if (IS_QLA8XXX_TYPE(ha))
549
550
551
552
553
			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));
Linus Torvalds's avatar
Linus Torvalds committed
554
555
556
557
558

		/*
		 * Until there's a transition from loop down to loop up, treat
		 * this as loop down only.
		 */
559
560
561
562
		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,
Linus Torvalds's avatar
Linus Torvalds committed
563
				    LOOP_DOWN_TIME);
564
			qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds's avatar
Linus Torvalds committed
565
566
		}

567
568
569
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
570
571
		}

572
573
574
575
576
		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);
577
578

		ha->flags.gpsc_supported = 1;
579
		vha->flags.management_server_logged_in = 0;
Linus Torvalds's avatar
Linus Torvalds committed
580
581
582
583
584
585
586
587
		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",
588
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
589
590
591
		qla_printk(KERN_INFO, ha,
		    "Configuration change detected: value=%x.\n", mb[1]);

592
593
594
595
		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,
Linus Torvalds's avatar
Linus Torvalds committed
596
				    LOOP_DOWN_TIME);
597
			qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds's avatar
Linus Torvalds committed
598
599
		}

600
601
602
		if (vha->vp_idx) {
			atomic_set(&vha->vp_state, VP_FAILED);
			fc_vport_set_state(vha->fc_vport, FC_VPORT_FAILED);
603
604
		}

605
606
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
607
608
609
		break;

	case MBA_PORT_UPDATE:		/* Port database update */
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
		/*
		 * Handle only global and vn-port update events
		 *
		 * Relevant inputs:
		 * mb[1] = N_Port handle of changed port
		 * OR 0xffff for global event
		 * mb[2] = New login state
		 * 7 = Port logged out
		 * mb[3] = LSB is vp_idx, 0xff = all vps
		 *
		 * Skip processing if:
		 *       Event is global, vp_idx is NOT all vps,
		 *           vp_idx does not match
		 *       Event is not global, vp_idx does not match
		 */
625
626
627
628
		if (IS_QLA2XXX_MIDTYPE(ha) &&
		    ((mb[1] == 0xffff && (mb[3] & 0xff) != 0xff) ||
			(mb[1] != 0xffff)) && vha->vp_idx != (mb[3] & 0xff))
			break;
629

630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
		/* Global event -- port logout or port unavailable. */
		if (mb[1] == 0xffff && mb[2] == 0x7) {
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
			    vha->host_no));
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Port unavailable %04x %04x %04x.\n",
			    vha->host_no, mb[1], mb[2], mb[3]));

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

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

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

Linus Torvalds's avatar
Linus Torvalds committed
658
		/*
659
		 * If PORT UPDATE is global (received LIP_OCCURRED/LIP_RESET
Linus Torvalds's avatar
Linus Torvalds committed
660
661
662
		 * event etc. earlier indicating loop is down) then process
		 * it.  Otherwise ignore it and Wait for RSCN to come in.
		 */
663
664
665
		atomic_set(&vha->loop_down_timer, 0);
		if (atomic_read(&vha->loop_state) != LOOP_DOWN &&
		    atomic_read(&vha->loop_state) != LOOP_DEAD) {
Linus Torvalds's avatar
Linus Torvalds committed
666
			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
667
			    "ignored %04x/%04x/%04x.\n", vha->host_no, mb[1],
668
			    mb[2], mb[3]));
Linus Torvalds's avatar
Linus Torvalds committed
669
670
671
672
			break;
		}

		DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
673
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
674
		DEBUG(printk(KERN_INFO
675
		    "scsi(%ld): Port database changed %04x %04x %04x.\n",
676
		    vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds's avatar
Linus Torvalds committed
677
678
679
680

		/*
		 * Mark all devices as missing so we will login again.
		 */
681
		atomic_set(&vha->loop_state, LOOP_UP);
Linus Torvalds's avatar
Linus Torvalds committed
682

683
		qla2x00_mark_all_devices_lost(vha, 1);
Linus Torvalds's avatar
Linus Torvalds committed
684

685
		vha->flags.rscn_queue_overflow = 1;
Linus Torvalds's avatar
Linus Torvalds committed
686

687
688
		set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
		set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
689
690
691
		break;

	case MBA_RSCN_UPDATE:		/* State Change Registration */
692
		/* Check if the Vport has issued a SCR */
693
		if (vha->vp_idx && test_bit(VP_SCR_NEEDED, &vha->vp_flags))
694
695
			break;
		/* Only handle SCNs for our Vport index. */
696
		if (ha->flags.npiv_supported && vha->vp_idx != (mb[3] & 0xff))
697
			break;
698

Linus Torvalds's avatar
Linus Torvalds committed
699
		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
700
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
701
		DEBUG(printk(KERN_INFO
702
		    "scsi(%ld): RSCN database changed -- %04x %04x %04x.\n",
703
		    vha->host_no, mb[1], mb[2], mb[3]));
Linus Torvalds's avatar
Linus Torvalds committed
704

705
		rscn_entry = ((mb[1] & 0xff) << 16) | mb[2];
706
707
		host_pid = (vha->d_id.b.domain << 16) | (vha->d_id.b.area << 8)
				| vha->d_id.b.al_pa;
Linus Torvalds's avatar
Linus Torvalds committed
708
709
710
711
		if (rscn_entry == host_pid) {
			DEBUG(printk(KERN_INFO
			    "scsi(%ld): Ignoring RSCN update to local host "
			    "port ID (%06x)\n",
712
			    vha->host_no, host_pid));
Linus Torvalds's avatar
Linus Torvalds committed
713
714
715
			break;
		}

716
717
		/* Ignore reserved bits from RSCN-payload. */
		rscn_entry = ((mb[1] & 0x3ff) << 16) | mb[2];
718
		rscn_queue_index = vha->rscn_in_ptr + 1;
Linus Torvalds's avatar
Linus Torvalds committed
719
720
		if (rscn_queue_index == MAX_RSCN_COUNT)
			rscn_queue_index = 0;
721
722
723
		if (rscn_queue_index != vha->rscn_out_ptr) {
			vha->rscn_queue[vha->rscn_in_ptr] = rscn_entry;
			vha->rscn_in_ptr = rscn_queue_index;
Linus Torvalds's avatar
Linus Torvalds committed
724
		} else {
725
			vha->flags.rscn_queue_overflow = 1;
Linus Torvalds's avatar
Linus Torvalds committed
726
727
		}

728
729
730
		atomic_set(&vha->loop_state, LOOP_UPDATE);
		atomic_set(&vha->loop_down_timer, 0);
		vha->flags.management_server_logged_in = 0;
Linus Torvalds's avatar
Linus Torvalds committed
731

732
733
734
		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);
Linus Torvalds's avatar
Linus Torvalds committed
735
736
737
738
		break;

	/* case MBA_RIO_RESPONSE: */
	case MBA_ZIO_RESPONSE:
739
		DEBUG3(printk("scsi(%ld): [R|Z]IO update completion.\n",
740
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
741

742
		if (IS_FWI2_CAPABLE(ha))
743
			qla24xx_process_response_queue(vha, rsp);
744
		else
745
			qla2x00_process_response_queue(rsp);
Linus Torvalds's avatar
Linus Torvalds committed
746
		break;
747
748
749

	case MBA_DISCARD_RND_FRAME:
		DEBUG2(printk("scsi(%ld): Discard RND Frame -- %04x %04x "
750
		    "%04x.\n", vha->host_no, mb[1], mb[2], mb[3]));
751
		break;
752
753
754

	case MBA_TRACE_NOTIFICATION:
		DEBUG2(printk("scsi(%ld): Trace Notification -- %04x %04x.\n",
755
		vha->host_no, mb[1], mb[2]));
756
		break;
757
758
759

	case MBA_ISP84XX_ALERT:
		DEBUG2(printk("scsi(%ld): ISP84XX Alert Notification -- "
760
		    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792

		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;
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
	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:
808
		qla81xx_idc_event(vha, mb[0], mb[1]);
809
		break;
Linus Torvalds's avatar
Linus Torvalds committed
810
	}
811

812
	if (!vha->vp_idx && ha->num_vhosts)
813
		qla2x00_alert_all_vps(rsp, mb);
Linus Torvalds's avatar
Linus Torvalds committed
814
815
816
817
818
819
820
821
}

/**
 * qla2x00_process_completed_request() - Process a Fast Post response.
 * @ha: SCSI driver HA context
 * @index: SRB index
 */
static void
822
823
qla2x00_process_completed_request(struct scsi_qla_host *vha,
				struct req_que *req, uint32_t index)
Linus Torvalds's avatar
Linus Torvalds committed
824
825
{
	srb_t *sp;
826
	struct qla_hw_data *ha = vha->hw;
Linus Torvalds's avatar
Linus Torvalds committed
827
828
829
830

	/* Validate handle. */
	if (index >= MAX_OUTSTANDING_COMMANDS) {
		DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
831
		    vha->host_no, index));
Linus Torvalds's avatar
Linus Torvalds committed
832
833
834
		qla_printk(KERN_WARNING, ha,
		    "Invalid SCSI completion handle %d.\n", index);

835
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
836
837
838
		return;
	}

839
	sp = req->outstanding_cmds[index];
Linus Torvalds's avatar
Linus Torvalds committed
840
841
	if (sp) {
		/* Free outstanding command slot. */
842
		req->outstanding_cmds[index] = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
843
844
845

		/* Save ISP completion status */
		sp->cmd->result = DID_OK << 16;
846
		qla2x00_sp_compl(ha, sp);
Linus Torvalds's avatar
Linus Torvalds committed
847
	} else {
848
		DEBUG2(printk("scsi(%ld) Req:%d: Invalid ISP SCSI completion"
849
			" handle(0x%x)\n", vha->host_no, req->id, index));
Linus Torvalds's avatar
Linus Torvalds committed
850
851
852
		qla_printk(KERN_WARNING, ha,
		    "Invalid ISP SCSI completion handle\n");

853
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
854
855
856
	}
}

857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
static srb_t *
qla2x00_get_sp_from_handle(scsi_qla_host_t *vha, const char *func,
    struct req_que *req, void *iocb)
{
	struct qla_hw_data *ha = vha->hw;
	sts_entry_t *pkt = iocb;
	srb_t *sp = NULL;
	uint16_t index;

	index = LSW(pkt->handle);
	if (index >= MAX_OUTSTANDING_COMMANDS) {
		qla_printk(KERN_WARNING, ha,
		    "%s: Invalid completion handle (%x).\n", func, index);
		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
		goto done;
	}
	sp = req->outstanding_cmds[index];
	if (!sp) {
		qla_printk(KERN_WARNING, ha,
		    "%s: Invalid completion handle (%x) -- timed-out.\n", func,
		    index);
		return sp;
	}
	if (sp->handle != index) {
		qla_printk(KERN_WARNING, ha,
		    "%s: SRB handle (%x) mismatch %x.\n", func, sp->handle,
		    index);
		return NULL;
	}
886

887
	req->outstanding_cmds[index] = NULL;
888

889
890
891
892
893
894
895
896
897
898
899
900
done:
	return sp;
}

static void
qla2x00_mbx_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct mbx_entry *mbx)
{
	const char func[] = "MBX-IOCB";
	const char *type;
	fc_port_t *fcport;
	srb_t *sp;
901
902
	struct srb_iocb *lio;
	struct srb_ctx *ctx;
903
	uint16_t *data;
904
	uint16_t status;
905
906
907
908
909

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

910
911
912
	ctx = sp->ctx;
	lio = ctx->u.iocb_cmd;
	type = ctx->name;
913
	fcport = sp->fcport;
914
	data = lio->u.logio.data;
915

916
	data[0] = MBS_COMMAND_ERROR;
917
	data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ?
918
	    QLA_LOGIO_LOGIN_RETRIED : 0;
919
920
	if (mbx->entry_status) {
		DEBUG2(printk(KERN_WARNING
921
922
923
		    "scsi(%ld:%x): Async-%s error entry - portid=%02x%02x%02x "
		    "entry-status=%x status=%x state-flag=%x "
		    "status-flags=%x.\n",
924
		    fcport->vha->host_no, sp->handle, type,
925
926
927
		    fcport->d_id.b.domain, fcport->d_id.b.area,
		    fcport->d_id.b.al_pa, mbx->entry_status,
		    le16_to_cpu(mbx->status), le16_to_cpu(mbx->state_flags),
928
		    le16_to_cpu(mbx->status_flags)));
929

930
931
		DEBUG2(qla2x00_dump_buffer((uint8_t *)mbx, sizeof(*mbx)));

932
		goto logio_done;
933
934
	}

935
	status = le16_to_cpu(mbx->status);
936
	if (status == 0x30 && ctx->type == SRB_LOGIN_CMD &&
937
938
939
	    le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE)
		status = 0;
	if (!status && le16_to_cpu(mbx->mb0) == MBS_COMMAND_COMPLETE) {
940
		DEBUG2(printk(KERN_DEBUG
941
942
		    "scsi(%ld:%x): Async-%s complete - portid=%02x%02x%02x "
		    "mbx1=%x.\n",
943
		    fcport->vha->host_no, sp->handle, type,
944
945
		    fcport->d_id.b.domain, fcport->d_id.b.area,
		    fcport->d_id.b.al_pa, le16_to_cpu(mbx->mb1)));
946
947

		data[0] = MBS_COMMAND_COMPLETE;
948
		if (ctx->type == SRB_LOGIN_CMD) {
949
950
951
			fcport->port_type = FCT_TARGET;
			if (le16_to_cpu(mbx->mb1) & BIT_0)
				fcport->port_type = FCT_INITIATOR;
952
			else if (le16_to_cpu(mbx->mb1) & BIT_1)
953
				fcport->flags |= FCF_FCP2_DEVICE;
954
		}
955
		goto logio_done;
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
	}

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

	DEBUG2(printk(KERN_WARNING
971
972
973
974
	    "scsi(%ld:%x): Async-%s failed - portid=%02x%02x%02x status=%x "
	    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
	    fcport->vha->host_no, sp->handle, type, fcport->d_id.b.domain,
	    fcport->d_id.b.area, fcport->d_id.b.al_pa, status,
975
976
977
978
	    le16_to_cpu(mbx->mb0), le16_to_cpu(mbx->mb1),
	    le16_to_cpu(mbx->mb2), le16_to_cpu(mbx->mb6),
	    le16_to_cpu(mbx->mb7)));

979
logio_done:
980
	lio->done(sp);
981
982
}

983
984
985
986
987
988
989
990
static void
qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req,
    struct sts_entry_24xx *pkt, int iocb_type)
{
	const char func[] = "ELS_CT_IOCB";
	const char *type;
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
991
	struct srb_ctx *sp_bsg;
992
993
994
995
996
997
998
999
	struct fc_bsg_job *bsg_job;
	uint16_t comp_status;
	uint32_t fw_status[3];
	uint8_t* fw_sts_ptr;

	sp = qla2x00_get_sp_from_handle(vha, func, req, pkt);
	if (!sp)
		return;
1000
1001
	sp_bsg = sp->ctx;
	bsg_job = sp_bsg->u.bsg_job;
1002
1003

	type = NULL;
1004
	switch (sp_bsg->type) {
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
	case SRB_ELS_CMD_RPT:
	case SRB_ELS_CMD_HST:
		type = "els";
		break;
	case SRB_CT_CMD:
		type = "ct pass-through";
		break;
	default:
		qla_printk(KERN_WARNING, ha,
		    "%s: Unrecognized SRB: (%p) type=%d.\n", func, sp,
1015
		    sp_bsg->type);
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
		return;
	}

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

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

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

			DEBUG2(qla_printk(KERN_WARNING, ha,
			    "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
			    "error subcode 1=0x%x error subcode 2=0x%x total_byte = 0x%x.\n",
				vha->host_no, sp->handle, type, comp_status, fw_status[1], fw_status[2],
				le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->total_byte_count)));
			fw_sts_ptr = ((uint8_t*)bsg_job->req->sense) + sizeof(struct fc_bsg_reply);
			memcpy( fw_sts_ptr, fw_status, sizeof(fw_status));
		}
		else {
			DEBUG2(qla_printk(KERN_WARNING, ha,
			    "scsi(%ld:0x%x): ELS-CT pass-through-%s error comp_status-status=0x%x "
			    "error subcode 1=0x%x error subcode 2=0x%x.\n",
				vha->host_no, sp->handle, type, comp_status,
				le16_to_cpu(((