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

	DEBUG2(printk(KERN_WARNING
134
135
136
137
		"scsi(%ld:%x): Async-%s timeout - portid=%02x%02x%02x.\n",
		fcport->vha->host_no, sp->handle,
		ctx->name, fcport->d_id.b.domain,
		fcport->d_id.b.area, fcport->d_id.b.al_pa));
138

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

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

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

155
156
157
158
159
160
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;
161
162
	struct srb_ctx *ctx;
	struct srb_iocb *lio;
163
164
165
	int rval;

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

171
172
173
174
	ctx = sp->ctx;
	ctx->type = SRB_LOGIN_CMD;
	ctx->name = "login";
	lio = ctx->u.iocb_cmd;
175
	lio->timeout = qla2x00_async_iocb_timeout;
176
177
	lio->done = qla2x00_async_login_ctx_done;
	lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
178
	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
179
		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
180
181
182
183
184
185
186
187
188
189
190
191
	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:
192
	lio->free(sp);
193
194
195
196
done:
	return rval;
}

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

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

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

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

223
224
225
226
	ctx = sp->ctx;
	ctx->type = SRB_LOGOUT_CMD;
	ctx->name = "logout";
	lio = ctx->u.iocb_cmd;
227
	lio->timeout = qla2x00_async_iocb_timeout;
228
	lio->done = qla2x00_async_logout_ctx_done;
229
230
231
232
233
234
235
236
237
238
239
	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:
240
	lio->free(sp);
241
242
243
244
done:
	return rval;
}

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

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

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;
262
263
	struct srb_ctx *ctx;
	struct srb_iocb *lio;
264
265
266
	int rval;

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

272
273
274
275
	ctx = sp->ctx;
	ctx->type = SRB_ADISC_CMD;
	ctx->name = "adisc";
	lio = ctx->u.iocb_cmd;
276
	lio->timeout = qla2x00_async_iocb_timeout;
277
	lio->done = qla2x00_async_adisc_ctx_done;
278
	if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
279
		lio->u.logio.flags |= SRB_LOGIN_RETRIED;
280
281
282
283
284
285
286
287
288
289
290
291
	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:
292
	lio->free(sp);
293
294
295
296
done:
	return rval;
}

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

403
void
404
405
406
407
408
409
410
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:
411
		if (fcport->flags & FCF_FCP2_DEVICE) {
412
413
414
			fcport->flags |= FCF_ASYNC_SENT;
			qla2x00_post_async_adisc_work(vha, fcport, data);
			break;
415
416
		}
		qla2x00_update_fcport(vha, fcport);
417
418
		break;
	case MBS_COMMAND_ERROR:
419
		fcport->flags &= ~FCF_ASYNC_SENT;
420
421
422
423
424
425
426
427
428
429
430
431
432
		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) {
433
			fcport->flags &= ~FCF_ASYNC_SENT;
434
435
436
437
438
439
			qla2x00_mark_device_lost(vha, fcport, 1, 0);
			break;
		}
		qla2x00_post_async_login_work(vha, fcport, NULL);
		break;
	}
440
	return;
441
442
}

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

451
void
452
453
454
455
456
457
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);

458
		return;
459
460
461
462
463
464
465
466
467
	}

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

468
	return;
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
511
512
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
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
/****************************************************************************/
/*                QLogic ISP2x00 Hardware Support Functions.                */
/****************************************************************************/

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

Linus Torvalds's avatar
Linus Torvalds committed
534
	/* Clear adapter flags. */
535
	vha->flags.online = 0;
536
	ha->flags.chip_reset_done = 0;
537
	vha->flags.reset_active = 0;
538
539
	ha->flags.pci_channel_io_perm_failure = 0;
	ha->flags.eeh_busy = 0;
540
541
542
543
544
545
	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
546
547
548
	ha->isp_abort_cnt = 0;
	ha->beacon_blink_led = 0;

549
550
551
	set_bit(0, ha->req_qid_map);
	set_bit(0, ha->rsp_qid_map);

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

560
	ha->isp_ops->reset_chip(vha);
Linus Torvalds's avatar
Linus Torvalds committed
561

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

569
	ha->isp_ops->get_flash_version(vha, req->ring);
570

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

573
	ha->isp_ops->nvram_config(vha);
Linus Torvalds's avatar
Linus Torvalds committed
574

575
576
577
578
	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",
579
580
581
582
		    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]);
583
584
585
		return QLA_FUNCTION_FAILED;
	}

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

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

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

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

618
619
620
621
622
623
	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
624
625
626
627
	return (rval);
}

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

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

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

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

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

655
656
	return QLA_SUCCESS;
}
Linus Torvalds's avatar
Linus Torvalds committed
657

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

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

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

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

683
684
685
686
687
688
689
690
691
	/*
	 * 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
692

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

699
700
			udelay(10);
		}
Linus Torvalds's avatar
Linus Torvalds committed
701

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

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

		if (ha->fb_rev == FPM_2300)
710
			pci_clear_mwi(ha->pdev);
711
712

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

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

			udelay(10);
Linus Torvalds's avatar
Linus Torvalds committed
723
724
		}

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

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

730
	pci_disable_rom(ha->pdev);
Linus Torvalds's avatar
Linus Torvalds committed
731

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

	return QLA_SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
738
739
}

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

	pci_set_master(ha->pdev);
755
	pci_try_set_mwi(ha->pdev);
756
757

	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
758
	w |= (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
759
760
761
762
763
764
	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). */
765
766
	if (pci_find_capability(ha->pdev, PCI_CAP_ID_PCIX))
		pcix_set_mmrbc(ha->pdev, 2048);
767
768

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

772
	pci_disable_rom(ha->pdev);
773

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

776
777
778
779
780
781
782
783
	/* 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;
}

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

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

808
	pci_disable_rom(ha->pdev);
809
810
811
812
813
814

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

	return QLA_SUCCESS;
}

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

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

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

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

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

	return (rval);
}

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

869
870
871
	if (unlikely(pci_channel_offline(ha->pdev)))
		return;

872
	ha->isp_ops->disable_intrs(ha);
Linus Torvalds's avatar
Linus Torvalds committed
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
975
976

	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++) {
977
			if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY)
Linus Torvalds's avatar
Linus Torvalds committed
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
				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);
}

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

	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);
1026
	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
1027

1028
	udelay(100);
1029
1030
1031
1032
1033
1034
1035
1036
	/* 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();
	}

1037
	/* Wait for soft-reset to complete. */
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
	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);
1062
1063
1064

	if (IS_NOPOLLING_TYPE(ha))
		ha->isp_ops->enable_intrs(ha);
1065
1066
}

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

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

1083
	ha->isp_ops->disable_intrs(ha);
1084
1085

	/* Perform RISC reset. */
1086
	qla24xx_reset_risc(vha);
1087
1088
}

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

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

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

	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",
1134
	    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145

	/* 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);
1146
			barrier();
Linus Torvalds's avatar
Linus Torvalds committed
1147
1148
1149
1150
1151
1152
1153
1154
		}
	} else
		udelay(10);

	if (!cnt)
		goto chip_diag_failed;

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

	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 */
1174
	if (req->length > 1024)
Linus Torvalds's avatar
Linus Torvalds committed
1175
1176
1177
		ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
	else
		ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
1178
		    req->length;
Linus Torvalds's avatar
Linus Torvalds committed
1179
1180
1181
1182
1183

	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",
1184
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1185

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

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

1193
1194
	DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", vha->host_no));
	rval = qla2x00_mbx_reg_test(vha);
Linus Torvalds's avatar
Linus Torvalds committed
1195
1196
	if (rval) {
		DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
1197
		    vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
		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 "
1210
		    "****\n", vha->host_no));
Linus Torvalds's avatar
Linus Torvalds committed
1211
1212
1213
1214
1215
1216

	spin_unlock_irqrestore(&ha->hardware_lock, flags);

	return (rval);
}

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

1230
1231
1232
	if (IS_QLA82XX(ha))
		return QLA_SUCCESS;

1233
	ha->fw_transfer_size = REQUEST_ENTRY_SIZE * req->length;
1234

1235
	rval = qla2x00_mbx_reg_test(vha);
1236
1237
	if (rval)