qla_init.c 141 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
 */
#include "qla_def.h"
8
#include "qla_gbl.h"
Linus Torvalds's avatar
Linus Torvalds committed
9
10

#include <linux/delay.h>
11
#include <linux/slab.h>
12
#include <linux/vmalloc.h>
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15

#include "qla_devtbl.h"

16
17
18
19
#ifdef CONFIG_SPARC
#include <asm/prom.h>
#endif

Linus Torvalds's avatar
Linus Torvalds committed
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
*  QLogic ISP2x00 Hardware Support Function Prototypes.
*/
static int qla2x00_isp_firmware(scsi_qla_host_t *);
static int qla2x00_setup_chip(scsi_qla_host_t *);
static int qla2x00_init_rings(scsi_qla_host_t *);
static int qla2x00_fw_ready(scsi_qla_host_t *);
static int qla2x00_configure_hba(scsi_qla_host_t *);
static int qla2x00_configure_loop(scsi_qla_host_t *);
static int qla2x00_configure_local_loop(scsi_qla_host_t *);
static int qla2x00_configure_fabric(scsi_qla_host_t *);
static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
static int qla2x00_device_resync(scsi_qla_host_t *);
static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
    uint16_t *);

static int qla2x00_restart_isp(scsi_qla_host_t *);

38
static int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
39

40
41
static struct qla_chip_state_84xx *qla84xx_get_chip(struct scsi_qla_host *);
static int qla84xx_init_chip(scsi_qla_host_t *);
42
static int qla25xx_init_queues(struct qla_hw_data *);
43

44
45
46
47
48
49
50
/* SRB Extensions ---------------------------------------------------------- */

static void
qla2x00_ctx_sp_timeout(unsigned long __data)
{
	srb_t *sp = (srb_t *)__data;
	struct srb_ctx *ctx;
51
	struct srb_iocb *iocb;
52
53
54
55
56
57
58
59
60
	fc_port_t *fcport = sp->fcport;
	struct qla_hw_data *ha = fcport->vha->hw;
	struct req_que *req;
	unsigned long flags;

	spin_lock_irqsave(&ha->hardware_lock, flags);
	req = ha->req_q_map[0];
	req->outstanding_cmds[sp->handle] = NULL;
	ctx = sp->ctx;
61
62
	iocb = ctx->u.iocb_cmd;
	iocb->timeout(sp);
63
64
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

65
	iocb->free(sp);
66
67
}

68
void
69
70
71
qla2x00_ctx_sp_free(srb_t *sp)
{
	struct srb_ctx *ctx = sp->ctx;
72
	struct srb_iocb *iocb = ctx->u.iocb_cmd;
73

74
75
	del_timer_sync(&iocb->timer);
	kfree(iocb);
76
77
78
79
80
81
82
83
84
85
86
	kfree(ctx);
	mempool_free(sp, sp->fcport->vha->hw->srb_mempool);
}

inline srb_t *
qla2x00_get_ctx_sp(scsi_qla_host_t *vha, fc_port_t *fcport, size_t size,
    unsigned long tmo)
{
	srb_t *sp;
	struct qla_hw_data *ha = vha->hw;
	struct srb_ctx *ctx;
87
	struct srb_iocb *iocb;
88
89
90
91
92
93
94

	sp = mempool_alloc(ha->srb_mempool, GFP_KERNEL);
	if (!sp)
		goto done;
	ctx = kzalloc(size, GFP_KERNEL);
	if (!ctx) {
		mempool_free(sp, ha->srb_mempool);
95
96
97
98
99
100
101
102
		sp = NULL;
		goto done;
	}
	iocb = kzalloc(sizeof(struct srb_iocb), GFP_KERNEL);
	if (!iocb) {
		mempool_free(sp, ha->srb_mempool);
		sp = NULL;
		kfree(ctx);
103
104
105
106
107
108
		goto done;
	}

	memset(sp, 0, sizeof(*sp));
	sp->fcport = fcport;
	sp->ctx = ctx;
109
110
	ctx->u.iocb_cmd = iocb;
	iocb->free = qla2x00_ctx_sp_free;
111

112
	init_timer(&iocb->timer);
113
114
	if (!tmo)
		goto done;
115
116
117
118
	iocb->timer.expires = jiffies + tmo * HZ;
	iocb->timer.data = (unsigned long)sp;
	iocb->timer.function = qla2x00_ctx_sp_timeout;
	add_timer(&iocb->timer);
119
120
121
122
123
124
125
126
127
done:
	return sp;
}

/* Asynchronous Login/Logout Routines -------------------------------------- */

#define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)

static void
128
qla2x00_async_iocb_timeout(srb_t *sp)
129
130
{
	fc_port_t *fcport = sp->fcport;
131
	struct srb_ctx *ctx = sp->ctx;
132
133
134

	DEBUG2(printk(KERN_WARNING
	    "scsi(%ld:%x): Async-%s timeout.\n",
135
	    fcport->vha->host_no, sp->handle, ctx->name));
136

137
	fcport->flags &= ~FCF_ASYNC_SENT;
138
	if (ctx->type == SRB_LOGIN_CMD)
139
140
141
		qla2x00_post_async_logout_work(fcport->vha, fcport, NULL);
}

142
143
144
static void
qla2x00_async_login_ctx_done(srb_t *sp)
{
145
146
	struct srb_ctx *ctx = sp->ctx;
	struct srb_iocb *lio = ctx->u.iocb_cmd;
147
148

	qla2x00_post_async_login_done_work(sp->fcport->vha, sp->fcport,
149
150
		lio->u.logio.data);
	lio->free(sp);
151
152
}

153
154
155
156
157
158
int
qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
{
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
159
160
	struct srb_ctx *ctx;
	struct srb_iocb *lio;
161
162
163
	int rval;

	rval = QLA_FUNCTION_FAILED;
164
	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
165
166
167
168
	    ELS_TMO_2_RATOV(ha) + 2);
	if (!sp)
		goto done;

169
170
171
172
	ctx = sp->ctx;
	ctx->type = SRB_LOGIN_CMD;
	ctx->name = "login";
	lio = ctx->u.iocb_cmd;
173
	lio->timeout = qla2x00_async_iocb_timeout;
174
175
	lio->done = qla2x00_async_login_ctx_done;
	lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
176
	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
177
		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
178
179
180
181
182
183
184
185
186
187
188
189
	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	DEBUG2(printk(KERN_DEBUG
	    "scsi(%ld:%x): Async-login - loop-id=%x portid=%02x%02x%02x "
	    "retries=%d.\n", fcport->vha->host_no, sp->handle, fcport->loop_id,
	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa,
	    fcport->login_retry));
	return rval;

done_free_sp:
190
	lio->free(sp);
191
192
193
194
done:
	return rval;
}

195
196
197
static void
qla2x00_async_logout_ctx_done(srb_t *sp)
{
198
199
	struct srb_ctx *ctx = sp->ctx;
	struct srb_iocb *lio = ctx->u.iocb_cmd;
200
201

	qla2x00_post_async_logout_done_work(sp->fcport->vha, sp->fcport,
202
203
	    lio->u.logio.data);
	lio->free(sp);
204
205
}

206
207
208
209
210
int
qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
{
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
211
212
	struct srb_ctx *ctx;
	struct srb_iocb *lio;
213
214
215
	int rval;

	rval = QLA_FUNCTION_FAILED;
216
	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
217
218
219
220
	    ELS_TMO_2_RATOV(ha) + 2);
	if (!sp)
		goto done;

221
222
223
224
	ctx = sp->ctx;
	ctx->type = SRB_LOGOUT_CMD;
	ctx->name = "logout";
	lio = ctx->u.iocb_cmd;
225
	lio->timeout = qla2x00_async_iocb_timeout;
226
	lio->done = qla2x00_async_logout_ctx_done;
227
228
229
230
231
232
233
234
235
236
237
	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	DEBUG2(printk(KERN_DEBUG
	    "scsi(%ld:%x): Async-logout - loop-id=%x portid=%02x%02x%02x.\n",
	    fcport->vha->host_no, sp->handle, fcport->loop_id,
	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));
	return rval;

done_free_sp:
238
	lio->free(sp);
239
240
241
242
done:
	return rval;
}

243
244
245
static void
qla2x00_async_adisc_ctx_done(srb_t *sp)
{
246
247
	struct srb_ctx *ctx = sp->ctx;
	struct srb_iocb *lio = ctx->u.iocb_cmd;
248
249

	qla2x00_post_async_adisc_done_work(sp->fcport->vha, sp->fcport,
250
251
	    lio->u.logio.data);
	lio->free(sp);
252
253
254
255
256
257
258
259
}

int
qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
{
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
260
261
	struct srb_ctx *ctx;
	struct srb_iocb *lio;
262
263
264
	int rval;

	rval = QLA_FUNCTION_FAILED;
265
	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
266
267
268
269
	    ELS_TMO_2_RATOV(ha) + 2);
	if (!sp)
		goto done;

270
271
272
273
	ctx = sp->ctx;
	ctx->type = SRB_ADISC_CMD;
	ctx->name = "adisc";
	lio = ctx->u.iocb_cmd;
274
	lio->timeout = qla2x00_async_iocb_timeout;
275
	lio->done = qla2x00_async_adisc_ctx_done;
276
	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
277
		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
278
279
280
281
282
283
284
285
286
287
288
289
	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	DEBUG2(printk(KERN_DEBUG
	    "scsi(%ld:%x): Async-adisc - loop-id=%x portid=%02x%02x%02x.\n",
	    fcport->vha->host_no, sp->handle, fcport->loop_id,
	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));

	return rval;

done_free_sp:
290
	lio->free(sp);
291
292
293
294
done:
	return rval;
}

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
static void
qla2x00_async_tm_cmd_ctx_done(srb_t *sp)
{
	struct srb_ctx *ctx = sp->ctx;
	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;

	qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb);
	iocb->free(sp);
}

int
qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
	uint32_t tag)
{
	struct scsi_qla_host *vha = fcport->vha;
	struct qla_hw_data *ha = vha->hw;
	srb_t *sp;
	struct srb_ctx *ctx;
	struct srb_iocb *tcf;
	int rval;

	rval = QLA_FUNCTION_FAILED;
	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
	    ELS_TMO_2_RATOV(ha) + 2);
	if (!sp)
		goto done;

	ctx = sp->ctx;
	ctx->type = SRB_TM_CMD;
	ctx->name = "tmf";
	tcf = ctx->u.iocb_cmd;
	tcf->u.tmf.flags = flags;
	tcf->u.tmf.lun = lun;
	tcf->u.tmf.data = tag;
	tcf->timeout = qla2x00_async_iocb_timeout;
	tcf->done = qla2x00_async_tm_cmd_ctx_done;

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	DEBUG2(printk(KERN_DEBUG
	    "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n",
	    fcport->vha->host_no, sp->handle, fcport->loop_id,
	    fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa));

	return rval;

done_free_sp:
	tcf->free(sp);
done:
	return rval;
}

static void
qla2x00_async_marker_ctx_done(srb_t *sp)
{
	struct srb_ctx *ctx = sp->ctx;
	struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;

	qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
	iocb->free(sp);
}

int
qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
{
	struct scsi_qla_host *vha = fcport->vha;
	srb_t *sp;
	struct srb_ctx *ctx;
	struct srb_iocb *mrk;
	int rval;

	rval = QLA_FUNCTION_FAILED;
	sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
	if (!sp)
		goto done;

	ctx = sp->ctx;
	ctx->type = SRB_MARKER_CMD;
	ctx->name = "marker";
	mrk = ctx->u.iocb_cmd;
	mrk->u.marker.lun = lun;
	mrk->u.marker.modif = modif;
	mrk->timeout = qla2x00_async_iocb_timeout;
	mrk->done = qla2x00_async_marker_ctx_done;

	rval = qla2x00_start_sp(sp);
	if (rval != QLA_SUCCESS)
		goto done_free_sp;

	DEBUG2(printk(KERN_DEBUG
	    "scsi(%ld:%x): Async-marker - loop-id=%x "
	    "portid=%02x%02x%02x.\n",
	    fcport->vha->host_no, sp->handle, fcport->loop_id,
	    fcport->d_id.b.domain, fcport->d_id.b.area,
	    fcport->d_id.b.al_pa));

	return rval;

done_free_sp:
	mrk->free(sp);
done:
	return rval;
}

401
void
402
403
404
405
406
407
408
qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
{
	int rval;

	switch (data[0]) {
	case MBS_COMMAND_COMPLETE:
409
		if (fcport->flags & FCF_FCP2_DEVICE) {
410
411
412
			fcport->flags |= FCF_ASYNC_SENT;
			qla2x00_post_async_adisc_work(vha, fcport, data);
			break;
413
414
		}
		qla2x00_update_fcport(vha, fcport);
415
416
		break;
	case MBS_COMMAND_ERROR:
417
		fcport->flags &= ~FCF_ASYNC_SENT;
418
419
420
421
422
423
424
425
426
427
428
429
430
		if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
			set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
		else
			qla2x00_mark_device_lost(vha, fcport, 1, 0);
		break;
	case MBS_PORT_ID_USED:
		fcport->loop_id = data[1];
		qla2x00_post_async_login_work(vha, fcport, NULL);
		break;
	case MBS_LOOP_ID_USED:
		fcport->loop_id++;
		rval = qla2x00_find_new_loop_id(vha, fcport);
		if (rval != QLA_SUCCESS) {
431
			fcport->flags &= ~FCF_ASYNC_SENT;
432
433
434
435
436
437
			qla2x00_mark_device_lost(vha, fcport, 1, 0);
			break;
		}
		qla2x00_post_async_login_work(vha, fcport, NULL);
		break;
	}
438
	return;
439
440
}

441
void
442
443
444
445
qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
{
	qla2x00_mark_device_lost(vha, fcport, 1, 0);
446
	return;
447
448
}

449
void
450
451
452
453
454
455
qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
    uint16_t *data)
{
	if (data[0] == MBS_COMMAND_COMPLETE) {
		qla2x00_update_fcport(vha, fcport);

456
		return;
457
458
459
460
461
462
463
464
465
	}

	/* Retry login. */
	fcport->flags &= ~FCF_ASYNC_SENT;
	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
		set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
	else
		qla2x00_mark_device_lost(vha, fcport, 1, 0);

466
	return;
467
468
}

469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
void
qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
    struct srb_iocb *iocb)
{
	int rval;
	uint32_t flags;
	uint16_t lun;

	flags = iocb->u.tmf.flags;
	lun = (uint16_t)iocb->u.tmf.lun;

	/* Issue Marker IOCB */
	rval = qla2x00_async_marker(fcport, lun,
		flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);

	if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
		DEBUG2_3_11(printk(KERN_WARNING
			"%s(%ld): TM IOCB failed (%x).\n",
			__func__, vha->host_no, rval));
	}

	return;
}

void
qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
    struct srb_iocb *iocb)
{
	/*
	 * Currently we dont have any specific post response processing
	 * for this IOCB. We'll just return success or failed
	 * depending on whether the IOCB command succeeded or failed.
	 */
	if (iocb->u.tmf.data) {
		DEBUG2_3_11(printk(KERN_WARNING
		    "%s(%ld): Marker IOCB failed (%x).\n",
		    __func__, vha->host_no, iocb->u.tmf.data));
	}

	return;
}

Linus Torvalds's avatar
Linus Torvalds committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
/****************************************************************************/
/*                QLogic ISP2x00 Hardware Support Functions.                */
/****************************************************************************/

/*
* qla2x00_initialize_adapter
*      Initialize board.
*
* Input:
*      ha = adapter block pointer.
*
* Returns:
*      0 = success
*/
int
526
qla2x00_initialize_adapter(scsi_qla_host_t *vha)
Linus Torvalds's avatar
Linus Torvalds committed
527
528
{
	int	rval;
529
	struct qla_hw_data *ha = vha->hw;
530
	struct req_que *req = ha->req_q_map[0];
531

Linus Torvalds's avatar
Linus Torvalds committed
532
	/* Clear adapter flags. */
533
	vha->flags.online = 0;
534
	ha->flags.chip_reset_done = 0;
535
	vha->flags.reset_active = 0;
536
537
	ha->flags.pci_channel_io_perm_failure = 0;
	ha->flags.eeh_busy = 0;
538
539
540
541
542
543
	atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME);
	atomic_set(&vha->loop_state, LOOP_DOWN);
	vha->device_flags = DFLG_NO_CABLE;
	vha->dpc_flags = 0;
	vha->flags.management_server_logged_in = 0;
	vha->marker_needed = 0;
Linus Torvalds's avatar
Linus Torvalds committed
544
545
546
	ha->isp_abort_cnt = 0;
	ha->beacon_blink_led = 0;

547
548
549
	set_bit(0, ha->req_qid_map);
	set_bit(0, ha->rsp_qid_map);

550
	qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
551
	rval = ha->isp_ops->pci_config(vha);
Linus Torvalds's avatar
Linus Torvalds committed
552
	if (rval) {
553
		DEBUG2(printk("scsi(%ld): Unable to configure PCI space.\n",
554
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
555
556
557
		return (rval);
	}

558
	ha->isp_ops->reset_chip(vha);
Linus Torvalds's avatar
Linus Torvalds committed
559

560
	rval = qla2xxx_get_flash_info(vha);
561
562
	if (rval) {
		DEBUG2(printk("scsi(%ld): Unable to validate FLASH data.\n",
563
		    vha->host_no));
564
565
566
		return (rval);
	}

567
	ha->isp_ops->get_flash_version(vha, req->ring);
568

Linus Torvalds's avatar
Linus Torvalds committed
569
	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
570

571
	ha->isp_ops->nvram_config(vha);
Linus Torvalds's avatar
Linus Torvalds committed
572

573
574
575
576
	if (ha->flags.disable_serdes) {
		/* Mask HBA via NVRAM settings? */
		qla_printk(KERN_INFO, ha, "Masking HBA WWPN "
		    "%02x%02x%02x%02x%02x%02x%02x%02x (via NVRAM).\n",
577
578
579
580
		    vha->port_name[0], vha->port_name[1],
		    vha->port_name[2], vha->port_name[3],
		    vha->port_name[4], vha->port_name[5],
		    vha->port_name[6], vha->port_name[7]);
581
582
583
		return QLA_FUNCTION_FAILED;
	}

Linus Torvalds's avatar
Linus Torvalds committed
584
585
	qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");

586
587
	if (qla2x00_isp_firmware(vha) != QLA_SUCCESS) {
		rval = ha->isp_ops->chip_diag(vha);
588
589
		if (rval)
			return (rval);
590
		rval = qla2x00_setup_chip(vha);
591
592
		if (rval)
			return (rval);
Linus Torvalds's avatar
Linus Torvalds committed
593
	}
594

595
	if (IS_QLA84XX(ha)) {
596
		ha->cs84xx = qla84xx_get_chip(vha);
597
598
599
600
601
602
		if (!ha->cs84xx) {
			qla_printk(KERN_ERR, ha,
			    "Unable to configure ISP84XX.\n");
			return QLA_FUNCTION_FAILED;
		}
	}
603
	rval = qla2x00_init_rings(vha);
604
	ha->flags.chip_reset_done = 1;
Linus Torvalds's avatar
Linus Torvalds committed
605

606
	if (rval == QLA_SUCCESS && IS_QLA84XX(ha)) {
607
		/* Issue verify 84xx FW IOCB to complete 84xx initialization */
608
609
610
611
612
613
614
615
		rval = qla84xx_init_chip(vha);
		if (rval != QLA_SUCCESS) {
			qla_printk(KERN_ERR, ha,
				"Unable to initialize ISP84XX.\n");
		qla84xx_put_chip(vha);
		}
	}

616
617
618
619
620
621
	if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha)) {
		if (qla24xx_read_fcp_prio_cfg(vha))
			qla_printk(KERN_ERR, ha,
			"Unable to read FCP priority data.\n");
	}

Linus Torvalds's avatar
Linus Torvalds committed
622
623
624
625
	return (rval);
}

/**
626
 * qla2100_pci_config() - Setup ISP21xx PCI configuration registers.
Linus Torvalds's avatar
Linus Torvalds committed
627
628
629
630
 * @ha: HA context
 *
 * Returns 0 on success.
 */
631
int
632
qla2100_pci_config(scsi_qla_host_t *vha)
Linus Torvalds's avatar
Linus Torvalds committed
633
{
634
	uint16_t w;
635
	unsigned long flags;
636
	struct qla_hw_data *ha = vha->hw;
637
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
638
639

	pci_set_master(ha->pdev);
640
	pci_try_set_mwi(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
641
642

	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
643
	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
644
645
	pci_write_config_word(ha->pdev, PCI_COMMAND, w);

646
	pci_disable_rom(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
647
648
649

	/* Get PCI bus information. */
	spin_lock_irqsave(&ha->hardware_lock, flags);
650
	ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
Linus Torvalds's avatar
Linus Torvalds committed
651
652
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

653
654
	return QLA_SUCCESS;
}
Linus Torvalds's avatar
Linus Torvalds committed
655

656
657
658
659
660
661
662
/**
 * qla2300_pci_config() - Setup ISP23xx PCI configuration registers.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
int
663
qla2300_pci_config(scsi_qla_host_t *vha)
664
{
665
	uint16_t	w;
666
667
	unsigned long   flags = 0;
	uint32_t	cnt;
668
	struct qla_hw_data *ha = vha->hw;
669
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
670

671
	pci_set_master(ha->pdev);
672
	pci_try_set_mwi(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
673

674
	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
675
	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
Linus Torvalds's avatar
Linus Torvalds committed
676

677
678
	if (IS_QLA2322(ha) || IS_QLA6322(ha))
		w &= ~PCI_COMMAND_INTX_DISABLE;
679
	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
Linus Torvalds's avatar
Linus Torvalds committed
680

681
682
683
684
685
686
687
688
689
	/*
	 * If this is a 2300 card and not 2312, reset the
	 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
	 * the 2310 also reports itself as a 2300 so we need to get the
	 * fb revision level -- a 6 indicates it really is a 2300 and
	 * not a 2310.
	 */
	if (IS_QLA2300(ha)) {
		spin_lock_irqsave(&ha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
690

691
		/* Pause RISC. */
692
		WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
693
		for (cnt = 0; cnt < 30000; cnt++) {
694
			if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
695
				break;
Linus Torvalds's avatar
Linus Torvalds committed
696

697
698
			udelay(10);
		}
Linus Torvalds's avatar
Linus Torvalds committed
699

700
		/* Select FPM registers. */
701
702
		WRT_REG_WORD(&reg->ctrl_status, 0x20);
		RD_REG_WORD(&reg->ctrl_status);
703
704

		/* Get the fb rev level */
705
		ha->fb_rev = RD_FB_CMD_REG(ha, reg);
706
707

		if (ha->fb_rev == FPM_2300)
708
			pci_clear_mwi(ha->pdev);
709
710

		/* Deselect FPM registers. */
711
712
		WRT_REG_WORD(&reg->ctrl_status, 0x0);
		RD_REG_WORD(&reg->ctrl_status);
713
714

		/* Release RISC module. */
715
		WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
716
		for (cnt = 0; cnt < 30000; cnt++) {
717
			if ((RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0)
718
719
720
				break;

			udelay(10);
Linus Torvalds's avatar
Linus Torvalds committed
721
722
		}

723
724
		spin_unlock_irqrestore(&ha->hardware_lock, flags);
	}
Linus Torvalds's avatar
Linus Torvalds committed
725

726
727
	pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);

728
	pci_disable_rom(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
729

730
731
	/* Get PCI bus information. */
	spin_lock_irqsave(&ha->hardware_lock, flags);
732
	ha->pci_attr = RD_REG_WORD(&reg->ctrl_status);
733
734
735
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return QLA_SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
736
737
}

738
739
740
741
742
743
744
/**
 * qla24xx_pci_config() - Setup ISP24xx PCI configuration registers.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
int
745
qla24xx_pci_config(scsi_qla_host_t *vha)
746
{
747
	uint16_t w;
748
	unsigned long flags = 0;
749
	struct qla_hw_data *ha = vha->hw;
750
751
752
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;

	pci_set_master(ha->pdev);
753
	pci_try_set_mwi(ha->pdev);
754
755

	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
756
	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
757
758
759
760
761
762
	w &= ~PCI_COMMAND_INTX_DISABLE;
	pci_write_config_word(ha->pdev, PCI_COMMAND, w);

	pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);

	/* PCI-X -- adjust Maximum Memory Read Byte Count (2048). */
763
764
	if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
		pcix_set_mmrbc(ha->pdev, 2048);
765
766

	/* PCIe -- adjust Maximum Read Request Size (2048). */
767
768
	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
		pcie_set_readrq(ha->pdev, 2048);
769

770
	pci_disable_rom(ha->pdev);
771

772
	ha->chip_revision = ha->pdev->revision;
773

774
775
776
777
778
779
780
781
	/* Get PCI bus information. */
	spin_lock_irqsave(&ha->hardware_lock, flags);
	ha->pci_attr = RD_REG_DWORD(&reg->ctrl_status);
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return QLA_SUCCESS;
}

782
783
784
785
786
787
788
/**
 * qla25xx_pci_config() - Setup ISP25xx PCI configuration registers.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
int
789
qla25xx_pci_config(scsi_qla_host_t *vha)
790
791
{
	uint16_t w;
792
	struct qla_hw_data *ha = vha->hw;
793
794
795
796
797
798
799
800
801
802
803
804
805

	pci_set_master(ha->pdev);
	pci_try_set_mwi(ha->pdev);

	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
	w &= ~PCI_COMMAND_INTX_DISABLE;
	pci_write_config_word(ha->pdev, PCI_COMMAND, w);

	/* PCIe -- adjust Maximum Read Request Size (2048). */
	if (pci_find_capability(ha->pdev, PCI_CAP_ID_EXP))
		pcie_set_readrq(ha->pdev, 2048);

806
	pci_disable_rom(ha->pdev);
807
808
809
810
811
812

	ha->chip_revision = ha->pdev->revision;

	return QLA_SUCCESS;
}

Linus Torvalds's avatar
Linus Torvalds committed
813
814
815
816
817
818
819
/**
 * qla2x00_isp_firmware() - Choose firmware image.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
static int
820
qla2x00_isp_firmware(scsi_qla_host_t *vha)
Linus Torvalds's avatar
Linus Torvalds committed
821
822
{
	int  rval;
823
824
	uint16_t loop_id, topo, sw_cap;
	uint8_t domain, area, al_pa;
825
	struct qla_hw_data *ha = vha->hw;
Linus Torvalds's avatar
Linus Torvalds committed
826
827

	/* Assume loading risc code */
828
	rval = QLA_FUNCTION_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
829
830
831

	if (ha->flags.disable_risc_code_load) {
		DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
832
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
833
834
835
		qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");

		/* Verify checksum of loaded RISC code. */
836
		rval = qla2x00_verify_checksum(vha, ha->fw_srisc_address);
837
838
		if (rval == QLA_SUCCESS) {
			/* And, verify we are not in ROM code. */
839
			rval = qla2x00_get_adapter_id(vha, &loop_id, &al_pa,
840
841
			    &area, &domain, &topo, &sw_cap);
		}
Linus Torvalds's avatar
Linus Torvalds committed
842
843
844
845
	}

	if (rval) {
		DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
846
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
847
848
849
850
851
852
853
854
855
856
857
	}

	return (rval);
}

/**
 * qla2x00_reset_chip() - Reset ISP chip.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
858
void
859
qla2x00_reset_chip(scsi_qla_host_t *vha)
Linus Torvalds's avatar
Linus Torvalds committed
860
861
{
	unsigned long   flags = 0;
862
	struct qla_hw_data *ha = vha->hw;
863
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
864
865
866
	uint32_t	cnt;
	uint16_t	cmd;

867
868
869
	if (unlikely(pci_channel_offline(ha->pdev)))
		return;

870
	ha->isp_ops->disable_intrs(ha);
Linus Torvalds's avatar
Linus Torvalds committed
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974

	spin_lock_irqsave(&ha->hardware_lock, flags);

	/* Turn off master enable */
	cmd = 0;
	pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
	cmd &= ~PCI_COMMAND_MASTER;
	pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);

	if (!IS_QLA2100(ha)) {
		/* Pause RISC. */
		WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
		if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
			for (cnt = 0; cnt < 30000; cnt++) {
				if ((RD_REG_WORD(&reg->hccr) &
				    HCCR_RISC_PAUSE) != 0)
					break;
				udelay(100);
			}
		} else {
			RD_REG_WORD(&reg->hccr);	/* PCI Posting. */
			udelay(10);
		}

		/* Select FPM registers. */
		WRT_REG_WORD(&reg->ctrl_status, 0x20);
		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */

		/* FPM Soft Reset. */
		WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
		RD_REG_WORD(&reg->fpm_diag_config);	/* PCI Posting. */

		/* Toggle Fpm Reset. */
		if (!IS_QLA2200(ha)) {
			WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
			RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
		}

		/* Select frame buffer registers. */
		WRT_REG_WORD(&reg->ctrl_status, 0x10);
		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */

		/* Reset frame buffer FIFOs. */
		if (IS_QLA2200(ha)) {
			WRT_FB_CMD_REG(ha, reg, 0xa000);
			RD_FB_CMD_REG(ha, reg);		/* PCI Posting. */
		} else {
			WRT_FB_CMD_REG(ha, reg, 0x00fc);

			/* Read back fb_cmd until zero or 3 seconds max */
			for (cnt = 0; cnt < 3000; cnt++) {
				if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
					break;
				udelay(100);
			}
		}

		/* Select RISC module registers. */
		WRT_REG_WORD(&reg->ctrl_status, 0);
		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */

		/* Reset RISC processor. */
		WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */

		/* Release RISC processor. */
		WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
	}

	WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
	WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);

	/* Reset ISP chip. */
	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);

	/* Wait for RISC to recover from reset. */
	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
		/*
		 * It is necessary to for a delay here since the card doesn't
		 * respond to PCI reads during a reset. On some architectures
		 * this will result in an MCA.
		 */
		udelay(20);
		for (cnt = 30000; cnt; cnt--) {
			if ((RD_REG_WORD(&reg->ctrl_status) &
			    CSR_ISP_SOFT_RESET) == 0)
				break;
			udelay(100);
		}
	} else
		udelay(10);

	/* Reset RISC processor. */
	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);

	WRT_REG_WORD(&reg->semaphore, 0);

	/* Release RISC processor. */
	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */

	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
		for (cnt = 0; cnt < 30000; cnt++) {
975
			if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds's avatar
Linus Torvalds committed
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
				break;

			udelay(100);
		}
	} else
		udelay(100);

	/* Turn on master enable */
	cmd |= PCI_COMMAND_MASTER;
	pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);

	/* Disable RISC pause on FPM parity error. */
	if (!IS_QLA2100(ha)) {
		WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
	}

	spin_unlock_irqrestore(&ha->hardware_lock, flags);
}

996
/**
997
 * qla24xx_reset_risc() - Perform full reset of ISP24xx RISC.
998
999
1000
1001
 * @ha: HA context
 *
 * Returns 0 on success.
 */
1002
static inline void
1003
qla24xx_reset_risc(scsi_qla_host_t *vha)
1004
1005
{
	unsigned long flags = 0;
1006
	struct qla_hw_data *ha = vha->hw;
1007
1008
	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
	uint32_t cnt, d2;
1009
	uint16_t wd;
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023

	spin_lock_irqsave(&ha->hardware_lock, flags);

	/* Reset RISC. */
	WRT_REG_DWORD(&reg->ctrl_status, CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
	for (cnt = 0; cnt < 30000; cnt++) {
		if ((RD_REG_DWORD(&reg->ctrl_status) & CSRX_DMA_ACTIVE) == 0)
			break;

		udelay(10);
	}

	WRT_REG_DWORD(&reg->ctrl_status,
	    CSRX_ISP_SOFT_RESET|CSRX_DMA_SHUTDOWN|MWB_4096_BYTES);
1024
	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
1025

1026
	udelay(100);
1027
1028
1029
1030
1031
1032
1033
1034
	/* Wait for firmware to complete NVRAM accesses. */
	d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
	for (cnt = 10000 ; cnt && d2; cnt--) {
		udelay(5);
		d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
		barrier();
	}

1035
	/* Wait for soft-reset to complete. */
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
	d2 = RD_REG_DWORD(&reg->ctrl_status);
	for (cnt = 6000000 ; cnt && (d2 & CSRX_ISP_SOFT_RESET); cnt--) {
		udelay(5);
		d2 = RD_REG_DWORD(&reg->ctrl_status);
		barrier();
	}

	WRT_REG_DWORD(&reg->hccr, HCCRX_SET_RISC_RESET);
	RD_REG_DWORD(&reg->hccr);

	WRT_REG_DWORD(&reg->hccr, HCCRX_REL_RISC_PAUSE);
	RD_REG_DWORD(&reg->hccr);

	WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_RESET);
	RD_REG_DWORD(&reg->hccr);

	d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
	for (cnt = 6000000 ; cnt && d2; cnt--) {
		udelay(5);
		d2 = (uint32_t) RD_REG_WORD(&reg->mailbox0);
		barrier();
	}

	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1060
1061
1062

	if (IS_NOPOLLING_TYPE(ha))
		ha->isp_ops->enable_intrs(ha);
1063
1064
}

1065
1066
1067
1068
1069
1070
1071
/**
 * qla24xx_reset_chip() - Reset ISP24xx chip.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
void
1072
qla24xx_reset_chip(scsi_qla_host_t *vha)
1073
{
1074
	struct qla_hw_data *ha = vha->hw;
1075
1076
1077
1078
1079
1080

	if (pci_channel_offline(ha->pdev) &&
	    ha->flags.pci_channel_io_perm_failure) {
		return;
	}

1081
	ha->isp_ops->disable_intrs(ha);
1082
1083

	/* Perform RISC reset. */
1084
	qla24xx_reset_risc(vha);
1085
1086
}

Linus Torvalds's avatar
Linus Torvalds committed
1087
1088
1089
1090
1091
1092
/**
 * qla2x00_chip_diag() - Test chip for proper operation.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
1093
int
1094
qla2x00_chip_diag(scsi_qla_host_t *vha)
Linus Torvalds's avatar
Linus Torvalds committed
1095
1096
{
	int		rval;
1097
	struct qla_hw_data *ha = vha->hw;
1098
	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
Linus Torvalds's avatar
Linus Torvalds committed
1099
1100
1101
1102
	unsigned long	flags = 0;
	uint16_t	data;
	uint32_t	cnt;
	uint16_t	mb[5];
1103
	struct req_que *req = ha->req_q_map[0];
Linus Torvalds's avatar
Linus Torvalds committed
1104
1105
1106
1107
1108

	/* Assume a failed state */
	rval = QLA_FUNCTION_FAILED;

	DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
1109
	    vha->host_no, (u_long)&reg->flash_address));
Linus Torvalds's avatar
Linus Torvalds committed
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131

	spin_lock_irqsave(&ha->hardware_lock, flags);

	/* Reset ISP chip. */
	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);

	/*
	 * We need to have a delay here since the card will not respond while
	 * in reset causing an MCA on some architectures.
	 */
	udelay(20);
	data = qla2x00_debounce_register(&reg->ctrl_status);
	for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
		udelay(5);
		data = RD_REG_WORD(&reg->ctrl_status);
		barrier();
	}

	if (!cnt)
		goto chip_diag_failed;

	DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
1132
	    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143

	/* Reset RISC processor. */
	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);

	/* Workaround for QLA2312 PCI parity error */
	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
		data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
		for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
			udelay(5);
			data = RD_MAILBOX_REG(ha, reg, 0);
1144
			barrier();
Linus Torvalds's avatar
Linus Torvalds committed
1145
1146
1147
1148
1149
1150
1151
1152
		}
	} else
		udelay(10);

	if (!cnt)
		goto chip_diag_failed;

	/* Check product ID of chip */
1153
	DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171

	mb[1] = RD_MAILBOX_REG(ha, reg, 1);
	mb[2] = RD_MAILBOX_REG(ha, reg, 2);
	mb[3] = RD_MAILBOX_REG(ha, reg, 3);
	mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
	if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
	    mb[3] != PROD_ID_3) {
		qla_printk(KERN_WARNING, ha,
		    "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);

		goto chip_diag_failed;
	}
	ha->product_id[0] = mb[1];
	ha->product_id[1] = mb[2];
	ha->product_id[2] = mb[3];
	ha->product_id[3] = mb[4];

	/* Adjust fw RISC transfer size */
1172
	if (req->length > 1024)
Linus Torvalds's avatar
Linus Torvalds committed
1173
1174
1175
		ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
	else
		ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
1176
		    req->length;
Linus Torvalds's avatar
Linus Torvalds committed
1177
1178
1179
1180
1181

	if (IS_QLA2200(ha) &&
	    RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
		/* Limit firmware transfer size with a 2200A */
		DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
1182
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1183

1184
		ha->device_type |= DT_ISP2200A;
Linus Torvalds's avatar
Linus Torvalds committed
1185
1186
1187
1188
1189
1190
		ha->fw_transfer_size = 128;
	}

	/* Wrap Incoming Mailboxes Test. */
	spin_unlock_irqrestore(&ha->hardware_lock, flags);

1191
1192
	DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
	rval = qla2x00_mbx_reg_test(vha);
Linus Torvalds's avatar
Linus Torvalds committed
1193
1194
	if (rval) {
		DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
1195
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
		qla_printk(KERN_WARNING, ha,
		    "Failed mailbox send register test\n");
	}
	else {
		/* Flag a successful rval */
		rval = QLA_SUCCESS;
	}
	spin_lock_irqsave(&ha->hardware_lock, flags);

chip_diag_failed:
	if (rval)
		DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
1208
		    "****\n", vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1209
1210
1211
1212
1213
1214

	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return (rval);
}

1215
1216
1217
1218
1219
1220
1221
/**
 * qla24xx_chip_diag() - Test ISP24xx for proper operation.
 * @ha: HA context
 *
 * Returns 0 on success.
 */
int
1222
qla24xx_chip_diag(scsi_qla_host_t *vha)
1223
1224
{
	int rval;
1225
	struct qla_hw_data *ha = vha->hw;
1226
	struct req_que *req = ha->req_q_map[0];
1227

1228
1229
1230
	if (IS_QLA82XX(ha))
		return QLA_SUCCESS;

1231
	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
1232

1233
	rval = qla2x00_mbx_reg_test(vha);
1234
1235
	if (rval) {
		DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
Anirban Chakraborty's avatar