qla_os.c 76.9 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1
/*
2
3
 * QLogic Fibre Channel HBA Driver
 * Copyright (c)  2003-2005 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
9
10
11
 */
#include "qla_def.h"

#include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
12
#include <linux/kthread.h>
Linus Torvalds's avatar
Linus Torvalds committed
13
14
15
16
17
18
19
20
21
22
23
24
25
26

#include <scsi/scsi_tcq.h>
#include <scsi/scsicam.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_fc.h>

/*
 * Driver version
 */
char qla2x00_version_str[40];

/*
 * SRB allocation cache
 */
27
static struct kmem_cache *srb_cachep;
Linus Torvalds's avatar
Linus Torvalds committed
28
29
30
31

/*
 * Ioctl related information.
 */
32
int num_hosts;
Linus Torvalds's avatar
Linus Torvalds committed
33
34
35
36
37
int ql2xlogintimeout = 20;
module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xlogintimeout,
		"Login timeout value in seconds.");

38
int qlport_down_retry;
Linus Torvalds's avatar
Linus Torvalds committed
39
40
module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(qlport_down_retry,
41
		"Maximum number of command retries to a port that returns "
Linus Torvalds's avatar
Linus Torvalds committed
42
43
44
45
46
47
		"a PORT-DOWN status.");

int ql2xplogiabsentdevice;
module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xplogiabsentdevice,
		"Option to enable PLOGI to devices that are not present after "
48
		"a Fabric scan.  This is needed for several broken switches. "
Linus Torvalds's avatar
Linus Torvalds committed
49
50
51
52
53
54
55
		"Default is 0 - no PLOGI. 1 - perfom PLOGI.");

int ql2xloginretrycount = 0;
module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xloginretrycount,
		"Specify an alternate value for the NVRAM login retry count.");

56
57
58
59
60
61
62
int ql2xallocfwdump = 1;
module_param(ql2xallocfwdump, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xallocfwdump,
		"Option to enable allocation of memory for a firmware dump "
		"during HBA initialization.  Memory allocation requirements "
		"vary by ISP type.  Default is 1 - allocate memory.");

63
int ql2xextended_error_logging;
64
module_param(ql2xextended_error_logging, int, S_IRUGO|S_IWUSR);
65
MODULE_PARM_DESC(ql2xextended_error_logging,
66
67
68
		"Option to enable extended error logging, "
		"Default is 0 - no logging. 1 - log errors.");

Linus Torvalds's avatar
Linus Torvalds committed
69
70
71
72
static void qla2x00_free_device(scsi_qla_host_t *);

static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);

73
74
75
76
77
78
int ql2xfdmienable;
module_param(ql2xfdmienable, int, S_IRUGO|S_IRUSR);
MODULE_PARM_DESC(ql2xfdmienable,
		"Enables FDMI registratons "
		"Default is 0 - no FDMI. 1 - perfom FDMI.");

79
80
81
82
83
84
85
86
87
88
89
90
91
#define MAX_Q_DEPTH    32
static int ql2xmaxqdepth = MAX_Q_DEPTH;
module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xmaxqdepth,
		"Maximum queue depth to report for target devices.");

int ql2xqfullrampup = 120;
module_param(ql2xqfullrampup, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ql2xqfullrampup,
		"Number of seconds to wait to begin to ramp-up the queue "
		"depth for a device after a queue-full condition has been "
		"detected.  Default is 120 seconds.");

Linus Torvalds's avatar
Linus Torvalds committed
92
/*
93
 * SCSI host template entry points
Linus Torvalds's avatar
Linus Torvalds committed
94
95
 */
static int qla2xxx_slave_configure(struct scsi_device * device);
96
static int qla2xxx_slave_alloc(struct scsi_device *);
97
98
static int qla2xxx_scan_finished(struct Scsi_Host *, unsigned long time);
static void qla2xxx_scan_start(struct Scsi_Host *);
99
static void qla2xxx_slave_destroy(struct scsi_device *);
Linus Torvalds's avatar
Linus Torvalds committed
100
101
static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
		void (*fn)(struct scsi_cmnd *));
102
103
static int qla24xx_queuecommand(struct scsi_cmnd *cmd,
		void (*fn)(struct scsi_cmnd *));
Linus Torvalds's avatar
Linus Torvalds committed
104
105
106
107
108
109
static int qla2xxx_eh_abort(struct scsi_cmnd *);
static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);

110
111
112
static int qla2x00_change_queue_depth(struct scsi_device *, int);
static int qla2x00_change_queue_type(struct scsi_device *, int);

113
struct scsi_host_template qla2x00_driver_template = {
Linus Torvalds's avatar
Linus Torvalds committed
114
	.module			= THIS_MODULE,
115
	.name			= QLA2XXX_DRIVER_NAME,
Linus Torvalds's avatar
Linus Torvalds committed
116
117
118
119
120
121
122
123
124
	.queuecommand		= qla2x00_queuecommand,

	.eh_abort_handler	= qla2xxx_eh_abort,
	.eh_device_reset_handler = qla2xxx_eh_device_reset,
	.eh_bus_reset_handler	= qla2xxx_eh_bus_reset,
	.eh_host_reset_handler	= qla2xxx_eh_host_reset,

	.slave_configure	= qla2xxx_slave_configure,

125
126
	.slave_alloc		= qla2xxx_slave_alloc,
	.slave_destroy		= qla2xxx_slave_destroy,
127
128
	.scan_finished		= qla2xxx_scan_finished,
	.scan_start		= qla2xxx_scan_start,
129
130
	.change_queue_depth	= qla2x00_change_queue_depth,
	.change_queue_type	= qla2x00_change_queue_type,
Linus Torvalds's avatar
Linus Torvalds committed
131
132
133
	.this_id		= -1,
	.cmd_per_lun		= 3,
	.use_clustering		= ENABLE_CLUSTERING,
134
	.use_sg_chaining	= ENABLE_SG_CHAINING,
Linus Torvalds's avatar
Linus Torvalds committed
135
136
137
138
139
140
141
	.sg_tablesize		= SG_ALL,

	/*
	 * The RISC allows for each command to transfer (2^32-1) bytes of data,
	 * which equates to 0x800000 sectors.
	 */
	.max_sectors		= 0xFFFF,
142
	.shost_attrs		= qla2x00_host_attrs,
Linus Torvalds's avatar
Linus Torvalds committed
143
144
};

145
struct scsi_host_template qla24xx_driver_template = {
146
	.module			= THIS_MODULE,
147
	.name			= QLA2XXX_DRIVER_NAME,
148
149
150
151
152
153
154
155
156
157
158
	.queuecommand		= qla24xx_queuecommand,

	.eh_abort_handler	= qla2xxx_eh_abort,
	.eh_device_reset_handler = qla2xxx_eh_device_reset,
	.eh_bus_reset_handler	= qla2xxx_eh_bus_reset,
	.eh_host_reset_handler	= qla2xxx_eh_host_reset,

	.slave_configure	= qla2xxx_slave_configure,

	.slave_alloc		= qla2xxx_slave_alloc,
	.slave_destroy		= qla2xxx_slave_destroy,
159
160
	.scan_finished		= qla2xxx_scan_finished,
	.scan_start		= qla2xxx_scan_start,
161
162
	.change_queue_depth	= qla2x00_change_queue_depth,
	.change_queue_type	= qla2x00_change_queue_type,
163
164
165
	.this_id		= -1,
	.cmd_per_lun		= 3,
	.use_clustering		= ENABLE_CLUSTERING,
166
	.use_sg_chaining	= ENABLE_SG_CHAINING,
167
168
169
	.sg_tablesize		= SG_ALL,

	.max_sectors		= 0xFFFF,
170
	.shost_attrs		= qla2x00_host_attrs,
171
172
};

Linus Torvalds's avatar
Linus Torvalds committed
173
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
174
struct scsi_transport_template *qla2xxx_transport_vport_template = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
175
176
177
178
179
180

/* TODO Convert to inlines
 *
 * Timer routines
 */

181
void qla2x00_timer(scsi_qla_host_t *);
Linus Torvalds's avatar
Linus Torvalds committed
182

183
__inline__ void qla2x00_start_timer(scsi_qla_host_t *,
Linus Torvalds's avatar
Linus Torvalds committed
184
185
    void *, unsigned long);
static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
186
__inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
Linus Torvalds's avatar
Linus Torvalds committed
187

188
__inline__ void
Linus Torvalds's avatar
Linus Torvalds committed
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
{
	init_timer(&ha->timer);
	ha->timer.expires = jiffies + interval * HZ;
	ha->timer.data = (unsigned long)ha;
	ha->timer.function = (void (*)(unsigned long))func;
	add_timer(&ha->timer);
	ha->timer_active = 1;
}

static inline void
qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
{
	mod_timer(&ha->timer, jiffies + interval * HZ);
}

205
__inline__ void
Linus Torvalds's avatar
Linus Torvalds committed
206
207
208
209
210
211
212
213
214
215
qla2x00_stop_timer(scsi_qla_host_t *ha)
{
	del_timer_sync(&ha->timer);
	ha->timer_active = 0;
}

static int qla2x00_do_dpc(void *data);

static void qla2x00_rst_aen(scsi_qla_host_t *);

216
217
uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
void qla2x00_mem_free(scsi_qla_host_t *ha);
Linus Torvalds's avatar
Linus Torvalds committed
218
219
static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
220
221
static void qla2x00_sp_free_dma(scsi_qla_host_t *, srb_t *);
void qla2x00_sp_compl(scsi_qla_host_t *ha, srb_t *);
Linus Torvalds's avatar
Linus Torvalds committed
222
223
224
225

/* -------------------------------------------------------------------------- */

static char *
226
qla2x00_pci_info_str(struct scsi_qla_host *ha, char *str)
Linus Torvalds's avatar
Linus Torvalds committed
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
{
	static char *pci_bus_modes[] = {
		"33", "66", "100", "133",
	};
	uint16_t pci_bus;

	strcpy(str, "PCI");
	pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;
	if (pci_bus) {
		strcat(str, "-X (");
		strcat(str, pci_bus_modes[pci_bus]);
	} else {
		pci_bus = (ha->pci_attr & BIT_8) >> 8;
		strcat(str, " (");
		strcat(str, pci_bus_modes[pci_bus]);
	}
	strcat(str, " MHz)");

	return (str);
}

248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
static char *
qla24xx_pci_info_str(struct scsi_qla_host *ha, char *str)
{
	static char *pci_bus_modes[] = { "33", "66", "100", "133", };
	uint32_t pci_bus;
	int pcie_reg;

	pcie_reg = pci_find_capability(ha->pdev, PCI_CAP_ID_EXP);
	if (pcie_reg) {
		char lwstr[6];
		uint16_t pcie_lstat, lspeed, lwidth;

		pcie_reg += 0x12;
		pci_read_config_word(ha->pdev, pcie_reg, &pcie_lstat);
		lspeed = pcie_lstat & (BIT_0 | BIT_1 | BIT_2 | BIT_3);
		lwidth = (pcie_lstat &
		    (BIT_4 | BIT_5 | BIT_6 | BIT_7 | BIT_8 | BIT_9)) >> 4;

		strcpy(str, "PCIe (");
		if (lspeed == 1)
			strcat(str, "2.5Gb/s ");
269
270
		else if (lspeed == 2)
			strcat(str, "5.0Gb/s ");
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
		else
			strcat(str, "<unknown> ");
		snprintf(lwstr, sizeof(lwstr), "x%d)", lwidth);
		strcat(str, lwstr);

		return str;
	}

	strcpy(str, "PCI");
	pci_bus = (ha->pci_attr & CSRX_PCIX_BUS_MODE_MASK) >> 8;
	if (pci_bus == 0 || pci_bus == 8) {
		strcat(str, " (");
		strcat(str, pci_bus_modes[pci_bus >> 3]);
	} else {
		strcat(str, "-X ");
		if (pci_bus & BIT_2)
			strcat(str, "Mode 2");
		else
			strcat(str, "Mode 1");
		strcat(str, " (");
		strcat(str, pci_bus_modes[pci_bus & ~BIT_2]);
	}
	strcat(str, " MHz)");

	return str;
}

298
static char *
299
qla2x00_fw_version_str(struct scsi_qla_host *ha, char *str)
Linus Torvalds's avatar
Linus Torvalds committed
300
301
{
	char un_str[10];
302

Linus Torvalds's avatar
Linus Torvalds committed
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
	sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
	    ha->fw_minor_version,
	    ha->fw_subminor_version);

	if (ha->fw_attributes & BIT_9) {
		strcat(str, "FLX");
		return (str);
	}

	switch (ha->fw_attributes & 0xFF) {
	case 0x7:
		strcat(str, "EF");
		break;
	case 0x17:
		strcat(str, "TP");
		break;
	case 0x37:
		strcat(str, "IP");
		break;
	case 0x77:
		strcat(str, "VI");
		break;
	default:
		sprintf(un_str, "(%x)", ha->fw_attributes);
		strcat(str, un_str);
		break;
	}
	if (ha->fw_attributes & 0x100)
		strcat(str, "X");

	return (str);
}

336
static char *
337
338
qla24xx_fw_version_str(struct scsi_qla_host *ha, char *str)
{
339
340
341
342
	sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
	    ha->fw_minor_version,
	    ha->fw_subminor_version);

343
344
345
346
347
348
	if (ha->fw_attributes & BIT_0)
		strcat(str, "[Class 2] ");
	if (ha->fw_attributes & BIT_1)
		strcat(str, "[IP] ");
	if (ha->fw_attributes & BIT_2)
		strcat(str, "[Multi-ID] ");
349
350
351
352
353
354
	if (ha->fw_attributes & BIT_3)
		strcat(str, "[SB-2] ");
	if (ha->fw_attributes & BIT_4)
		strcat(str, "[T10 CRC] ");
	if (ha->fw_attributes & BIT_5)
		strcat(str, "[VI] ");
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
	if (ha->fw_attributes & BIT_13)
		strcat(str, "[Experimental]");
	return str;
}

static inline srb_t *
qla2x00_get_new_sp(scsi_qla_host_t *ha, fc_port_t *fcport,
    struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
	srb_t *sp;

	sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
	if (!sp)
		return sp;

	sp->ha = ha;
	sp->fcport = fcport;
	sp->cmd = cmd;
	sp->flags = 0;
	CMD_SP(cmd) = (void *)sp;
	cmd->scsi_done = done;

	return sp;
}

Linus Torvalds's avatar
Linus Torvalds committed
380
static int
381
qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
Linus Torvalds's avatar
Linus Torvalds committed
382
{
383
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
384
	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
385
	struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
386
387
	srb_t *sp;
	int rval;
Linus Torvalds's avatar
Linus Torvalds committed
388

389
390
391
392
393
	if (unlikely(pci_channel_offline(ha->pdev))) {
		cmd->result = DID_REQUEUE << 16;
		goto qc_fail_command;
	}

394
395
396
	rval = fc_remote_port_chkready(rport);
	if (rval) {
		cmd->result = rval;
397
398
		goto qc_fail_command;
	}
Linus Torvalds's avatar
Linus Torvalds committed
399

400
401
402
403
404
405
	/* Close window on fcport/rport state-transitioning. */
	if (!*(fc_port_t **)rport->dd_data) {
		cmd->result = DID_IMM_RETRY << 16;
		goto qc_fail_command;
	}

406
407
408
409
410
411
412
413
	if (atomic_read(&fcport->state) != FCS_ONLINE) {
		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
		    atomic_read(&ha->loop_state) == LOOP_DEAD) {
			cmd->result = DID_NO_CONNECT << 16;
			goto qc_fail_command;
		}
		goto qc_host_busy;
	}
Linus Torvalds's avatar
Linus Torvalds committed
414
415
416

	spin_unlock_irq(ha->host->host_lock);

417
418
	sp = qla2x00_get_new_sp(ha, fcport, cmd, done);
	if (!sp)
419
		goto qc_host_busy_lock;
Linus Torvalds's avatar
Linus Torvalds committed
420

421
422
423
	rval = qla2x00_start_scsi(sp);
	if (rval != QLA_SUCCESS)
		goto qc_host_busy_free_sp;
Linus Torvalds's avatar
Linus Torvalds committed
424

425
	spin_lock_irq(ha->host->host_lock);
Linus Torvalds's avatar
Linus Torvalds committed
426

427
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
428

429
430
431
qc_host_busy_free_sp:
	qla2x00_sp_free_dma(ha, sp);
	mempool_free(sp, ha->srb_mempool);
Linus Torvalds's avatar
Linus Torvalds committed
432

433
434
qc_host_busy_lock:
	spin_lock_irq(ha->host->host_lock);
Linus Torvalds's avatar
Linus Torvalds committed
435

436
437
qc_host_busy:
	return SCSI_MLQUEUE_HOST_BUSY;
Linus Torvalds's avatar
Linus Torvalds committed
438

439
440
qc_fail_command:
	done(cmd);
Linus Torvalds's avatar
Linus Torvalds committed
441

442
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
443
444
}

445
446
447
448

static int
qla24xx_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
449
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
450
	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
451
	struct fc_rport *rport = starget_to_rport(scsi_target(cmd->device));
452
453
	srb_t *sp;
	int rval;
454
	scsi_qla_host_t *pha = to_qla_parent(ha);
455

456
457
458
459
460
	if (unlikely(pci_channel_offline(ha->pdev))) {
		cmd->result = DID_REQUEUE << 16;
		goto qc24_fail_command;
	}

461
462
463
	rval = fc_remote_port_chkready(rport);
	if (rval) {
		cmd->result = rval;
464
465
466
		goto qc24_fail_command;
	}

467
468
469
470
471
472
	/* Close window on fcport/rport state-transitioning. */
	if (!*(fc_port_t **)rport->dd_data) {
		cmd->result = DID_IMM_RETRY << 16;
		goto qc24_fail_command;
	}

473
474
	if (atomic_read(&fcport->state) != FCS_ONLINE) {
		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
475
		    atomic_read(&pha->loop_state) == LOOP_DEAD) {
476
477
478
479
480
481
482
483
			cmd->result = DID_NO_CONNECT << 16;
			goto qc24_fail_command;
		}
		goto qc24_host_busy;
	}

	spin_unlock_irq(ha->host->host_lock);

484
	sp = qla2x00_get_new_sp(pha, fcport, cmd, done);
485
486
487
488
489
490
491
492
493
494
495
496
	if (!sp)
		goto qc24_host_busy_lock;

	rval = qla24xx_start_scsi(sp);
	if (rval != QLA_SUCCESS)
		goto qc24_host_busy_free_sp;

	spin_lock_irq(ha->host->host_lock);

	return 0;

qc24_host_busy_free_sp:
497
498
	qla2x00_sp_free_dma(pha, sp);
	mempool_free(sp, pha->srb_mempool);
499
500
501
502
503
504
505
506
507
508
509
510
511
512

qc24_host_busy_lock:
	spin_lock_irq(ha->host->host_lock);

qc24_host_busy:
	return SCSI_MLQUEUE_HOST_BUSY;

qc24_fail_command:
	done(cmd);

	return 0;
}


Linus Torvalds's avatar
Linus Torvalds committed
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
/*
 * qla2x00_eh_wait_on_command
 *    Waits for the command to be returned by the Firmware for some
 *    max time.
 *
 * Input:
 *    ha = actual ha whose done queue will contain the command
 *	      returned by firmware.
 *    cmd = Scsi Command to wait on.
 *    flag = Abort/Reset(Bus or Device Reset)
 *
 * Return:
 *    Not Found : 0
 *    Found : 1
 */
static int
qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
{
531
532
#define ABORT_POLLING_PERIOD	1000
#define ABORT_WAIT_ITER		((10 * 1000) / (ABORT_POLLING_PERIOD))
533
534
	unsigned long wait_iter = ABORT_WAIT_ITER;
	int ret = QLA_SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
535

536
	while (CMD_SP(cmd)) {
537
		msleep(ABORT_POLLING_PERIOD);
Linus Torvalds's avatar
Linus Torvalds committed
538

539
540
541
542
543
		if (--wait_iter)
			break;
	}
	if (CMD_SP(cmd))
		ret = QLA_FUNCTION_FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
544

545
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
546
547
548
549
}

/*
 * qla2x00_wait_for_hba_online
550
 *    Wait till the HBA is online after going through
Linus Torvalds's avatar
Linus Torvalds committed
551
552
553
554
555
 *    <= MAX_RETRIES_OF_ISP_ABORT  or
 *    finally HBA is disabled ie marked offline
 *
 * Input:
 *     ha - pointer to host adapter structure
556
557
 *
 * Note:
Linus Torvalds's avatar
Linus Torvalds committed
558
559
560
561
562
563
564
 *    Does context switching-Release SPIN_LOCK
 *    (if any) before calling this routine.
 *
 * Return:
 *    Success (Adapter is online) : 0
 *    Failed  (Adapter is offline/disabled) : 1
 */
565
int
Linus Torvalds's avatar
Linus Torvalds committed
566
567
qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
{
568
569
	int		return_status;
	unsigned long	wait_online;
570
	scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds's avatar
Linus Torvalds committed
571

572
	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ);
573
574
575
576
	while (((test_bit(ISP_ABORT_NEEDED, &pha->dpc_flags)) ||
	    test_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags) ||
	    test_bit(ISP_ABORT_RETRY, &pha->dpc_flags) ||
	    pha->dpc_active) && time_before(jiffies, wait_online)) {
Linus Torvalds's avatar
Linus Torvalds committed
577
578
579

		msleep(1000);
	}
580
	if (pha->flags.online)
581
		return_status = QLA_SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
582
583
584
585
586
587
588
589
590
591
592
	else
		return_status = QLA_FUNCTION_FAILED;

	DEBUG2(printk("%s return_status=%d\n",__func__,return_status));

	return (return_status);
}

/*
 * qla2x00_wait_for_loop_ready
 *    Wait for MAX_LOOP_TIMEOUT(5 min) value for loop
593
 *    to be in LOOP_READY state.
Linus Torvalds's avatar
Linus Torvalds committed
594
595
 * Input:
 *     ha - pointer to host adapter structure
596
597
 *
 * Note:
Linus Torvalds's avatar
Linus Torvalds committed
598
599
 *    Does context switching-Release SPIN_LOCK
 *    (if any) before calling this routine.
600
 *
Linus Torvalds's avatar
Linus Torvalds committed
601
602
603
604
605
 *
 * Return:
 *    Success (LOOP_READY) : 0
 *    Failed  (LOOP_NOT_READY) : 1
 */
606
static inline int
Linus Torvalds's avatar
Linus Torvalds committed
607
608
609
610
qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
{
	int 	 return_status = QLA_SUCCESS;
	unsigned long loop_timeout ;
611
	scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds's avatar
Linus Torvalds committed
612
613

	/* wait for 5 min at the max for loop to be ready */
614
	loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ);
Linus Torvalds's avatar
Linus Torvalds committed
615

616
617
618
619
	while ((!atomic_read(&pha->loop_down_timer) &&
	    atomic_read(&pha->loop_state) == LOOP_DOWN) ||
	    atomic_read(&pha->loop_state) != LOOP_READY) {
		if (atomic_read(&pha->loop_state) == LOOP_DEAD) {
620
621
622
			return_status = QLA_FUNCTION_FAILED;
			break;
		}
Linus Torvalds's avatar
Linus Torvalds committed
623
624
625
626
627
628
		msleep(1000);
		if (time_after_eq(jiffies, loop_timeout)) {
			return_status = QLA_FUNCTION_FAILED;
			break;
		}
	}
629
	return (return_status);
Linus Torvalds's avatar
Linus Torvalds committed
630
631
}

632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
static void
qla2x00_block_error_handler(struct scsi_cmnd *cmnd)
{
	struct Scsi_Host *shost = cmnd->device->host;
	struct fc_rport *rport = starget_to_rport(scsi_target(cmnd->device));
	unsigned long flags;

	spin_lock_irqsave(shost->host_lock, flags);
	while (rport->port_state == FC_PORTSTATE_BLOCKED) {
		spin_unlock_irqrestore(shost->host_lock, flags);
		msleep(1000);
		spin_lock_irqsave(shost->host_lock, flags);
	}
	spin_unlock_irqrestore(shost->host_lock, flags);
	return;
}

Linus Torvalds's avatar
Linus Torvalds committed
649
650
651
652
653
654
655
656
657
658
659
660
661
/**************************************************************************
* qla2xxx_eh_abort
*
* Description:
*    The abort function will abort the specified command.
*
* Input:
*    cmd = Linux SCSI command packet to be aborted.
*
* Returns:
*    Either SUCCESS or FAILED.
*
* Note:
662
*    Only return FAILED if command not returned by firmware.
Linus Torvalds's avatar
Linus Torvalds committed
663
**************************************************************************/
664
static int
Linus Torvalds's avatar
Linus Torvalds committed
665
666
qla2xxx_eh_abort(struct scsi_cmnd *cmd)
{
667
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
668
669
670
671
	srb_t *sp;
	int ret, i;
	unsigned int id, lun;
	unsigned long serial;
672
	unsigned long flags;
673
	int wait = 0;
674
	scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds's avatar
Linus Torvalds committed
675

676
677
	qla2x00_block_error_handler(cmd);

678
	if (!CMD_SP(cmd))
679
		return SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
680

681
	ret = SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
682

683
684
685
	id = cmd->device->id;
	lun = cmd->device->lun;
	serial = cmd->serial_number;
Linus Torvalds's avatar
Linus Torvalds committed
686

687
	/* Check active list for command command. */
688
	spin_lock_irqsave(&pha->hardware_lock, flags);
689
	for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
690
		sp = pha->outstanding_cmds[i];
Linus Torvalds's avatar
Linus Torvalds committed
691

692
693
		if (sp == NULL)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
694

695
696
		if (sp->cmd != cmd)
			continue;
Linus Torvalds's avatar
Linus Torvalds committed
697

698
699
		DEBUG2(printk("%s(%ld): aborting sp %p from RISC. pid=%ld.\n",
		    __func__, ha->host_no, sp, serial));
700
		DEBUG3(qla2x00_print_scsi_cmd(cmd));
Linus Torvalds's avatar
Linus Torvalds committed
701

702
		spin_unlock_irqrestore(&pha->hardware_lock, flags);
703
		if (ha->isp_ops->abort_command(ha, sp)) {
704
705
706
707
708
			DEBUG2(printk("%s(%ld): abort_command "
			    "mbx failed.\n", __func__, ha->host_no));
		} else {
			DEBUG3(printk("%s(%ld): abort_command "
			    "mbx success.\n", __func__, ha->host_no));
709
			wait = 1;
710
		}
711
		spin_lock_irqsave(&pha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
712

713
714
		break;
	}
715
	spin_unlock_irqrestore(&pha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
716

717
	/* Wait for the command to be returned. */
718
	if (wait) {
719
		if (qla2x00_eh_wait_on_command(ha, cmd) != QLA_SUCCESS) {
720
			qla_printk(KERN_ERR, ha,
721
722
			    "scsi(%ld:%d:%d): Abort handler timed out -- %lx "
			    "%x.\n", ha->host_no, id, lun, serial, ret);
723
			ret = FAILED;
724
		}
Linus Torvalds's avatar
Linus Torvalds committed
725
726
	}

727
	qla_printk(KERN_INFO, ha,
728
729
	    "scsi(%ld:%d:%d): Abort command issued -- %d %lx %x.\n",
	    ha->host_no, id, lun, wait, serial, ret);
Linus Torvalds's avatar
Linus Torvalds committed
730

731
732
	return ret;
}
Linus Torvalds's avatar
Linus Torvalds committed
733

734
735
736
737
738
739
740
741
/**************************************************************************
* qla2x00_eh_wait_for_pending_target_commands
*
* Description:
*    Waits for all the commands to come back from the specified target.
*
* Input:
*    ha - pointer to scsi_qla_host structure.
742
*    t  - target
743
744
745
746
747
748
749
750
751
752
753
754
* Returns:
*    Either SUCCESS or FAILED.
*
* Note:
**************************************************************************/
static int
qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
{
	int	cnt;
	int	status;
	srb_t		*sp;
	struct scsi_cmnd *cmd;
755
	unsigned long flags;
756
	scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds's avatar
Linus Torvalds committed
757

758
	status = 0;
Linus Torvalds's avatar
Linus Torvalds committed
759
760

	/*
761
762
	 * Waiting for all commands for the designated target in the active
	 * array
Linus Torvalds's avatar
Linus Torvalds committed
763
764
	 */
	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
765
766
		spin_lock_irqsave(&pha->hardware_lock, flags);
		sp = pha->outstanding_cmds[cnt];
Linus Torvalds's avatar
Linus Torvalds committed
767
768
		if (sp) {
			cmd = sp->cmd;
769
770
771
			spin_unlock_irqrestore(&pha->hardware_lock, flags);
			if (cmd->device->id == t &&
			    ha->vp_idx == sp->ha->vp_idx) {
Linus Torvalds's avatar
Linus Torvalds committed
772
773
774
775
776
				if (!qla2x00_eh_wait_on_command(ha, cmd)) {
					status = 1;
					break;
				}
			}
777
		} else {
778
			spin_unlock_irqrestore(&pha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
779
780
781
782
783
784
785
786
787
788
789
790
791
792
		}
	}
	return (status);
}


/**************************************************************************
* qla2xxx_eh_device_reset
*
* Description:
*    The device reset function will reset the target and abort any
*    executing commands.
*
*    NOTE: The use of SP is undefined within this context.  Do *NOT*
793
*          attempt to use this value, even if you determine it is
Linus Torvalds's avatar
Linus Torvalds committed
794
795
796
797
798
799
800
801
802
803
*          non-null.
*
* Input:
*    cmd = Linux SCSI command packet of the command that cause the
*          bus device reset.
*
* Returns:
*    SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
804
static int
Linus Torvalds's avatar
Linus Torvalds committed
805
806
qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
{
807
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
808
	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
809
	int ret = FAILED;
810
811
	unsigned int id, lun;
	unsigned long serial;
Linus Torvalds's avatar
Linus Torvalds committed
812

813
814
	qla2x00_block_error_handler(cmd);

815
816
817
	id = cmd->device->id;
	lun = cmd->device->lun;
	serial = cmd->serial_number;
Linus Torvalds's avatar
Linus Torvalds committed
818

819
	if (!fcport)
820
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
821
822

	qla_printk(KERN_INFO, ha,
823
	    "scsi(%ld:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, id, lun);
Linus Torvalds's avatar
Linus Torvalds committed
824

825
	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
Linus Torvalds's avatar
Linus Torvalds committed
826
827
828
		goto eh_dev_reset_done;

	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
829
830
		if (qla2x00_device_reset(ha, fcport) == 0)
			ret = SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
831
832

#if defined(LOGOUT_AFTER_DEVICE_RESET)
833
834
		if (ret == SUCCESS) {
			if (fcport->flags & FC_FABRIC_DEVICE) {
835
				ha->isp_ops->fabric_logout(ha, fcport->loop_id);
836
				qla2x00_mark_device_lost(ha, fcport, 0, 0);
Linus Torvalds's avatar
Linus Torvalds committed
837
838
839
840
841
			}
		}
#endif
	} else {
		DEBUG2(printk(KERN_INFO
842
		    "%s failed: loop not ready\n",__func__));
Linus Torvalds's avatar
Linus Torvalds committed
843
844
	}

845
	if (ret == FAILED) {
Linus Torvalds's avatar
Linus Torvalds committed
846
847
848
849
850
851
852
853
		DEBUG3(printk("%s(%ld): device reset failed\n",
		    __func__, ha->host_no));
		qla_printk(KERN_INFO, ha, "%s: device reset failed\n",
		    __func__);

		goto eh_dev_reset_done;
	}

854
855
856
857
858
859
860
861
862
863
864
865
	/* Flush outstanding commands. */
	if (qla2x00_eh_wait_for_pending_target_commands(ha, id))
		ret = FAILED;
	if (ret == FAILED) {
		DEBUG3(printk("%s(%ld): failed while waiting for commands\n",
		    __func__, ha->host_no));
		qla_printk(KERN_INFO, ha,
		    "%s: failed while waiting for commands\n", __func__);
	} else
		qla_printk(KERN_INFO, ha,
		    "scsi(%ld:%d:%d): DEVICE RESET SUCCEEDED.\n", ha->host_no,
		    id, lun);
866
 eh_dev_reset_done:
867
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
}

/**************************************************************************
* qla2x00_eh_wait_for_pending_commands
*
* Description:
*    Waits for all the commands to come back from the specified host.
*
* Input:
*    ha - pointer to scsi_qla_host structure.
*
* Returns:
*    1 : SUCCESS
*    0 : FAILED
*
* Note:
**************************************************************************/
static int
qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
{
	int	cnt;
	int	status;
	srb_t		*sp;
	struct scsi_cmnd *cmd;
892
	unsigned long flags;
Linus Torvalds's avatar
Linus Torvalds committed
893
894
895
896
897
898
899
900

	status = 1;

	/*
	 * Waiting for all commands for the designated target in the active
	 * array
	 */
	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
901
		spin_lock_irqsave(&ha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
902
903
904
		sp = ha->outstanding_cmds[cnt];
		if (sp) {
			cmd = sp->cmd;
905
			spin_unlock_irqrestore(&ha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
906
907
908
909
910
			status = qla2x00_eh_wait_on_command(ha, cmd);
			if (status == 0)
				break;
		}
		else {
911
			spin_unlock_irqrestore(&ha->hardware_lock, flags);
Linus Torvalds's avatar
Linus Torvalds committed
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
		}
	}
	return (status);
}


/**************************************************************************
* qla2xxx_eh_bus_reset
*
* Description:
*    The bus reset function will reset the bus and abort any executing
*    commands.
*
* Input:
*    cmd = Linux SCSI command packet of the command that cause the
*          bus reset.
*
* Returns:
*    SUCCESS/FAILURE (defined as macro in scsi.h).
*
**************************************************************************/
933
static int
Linus Torvalds's avatar
Linus Torvalds committed
934
935
qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
{
936
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
937
	scsi_qla_host_t *pha = to_qla_parent(ha);
938
	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
939
	int ret = FAILED;
940
941
942
	unsigned int id, lun;
	unsigned long serial;

943
944
	qla2x00_block_error_handler(cmd);

945
946
947
	id = cmd->device->id;
	lun = cmd->device->lun;
	serial = cmd->serial_number;
Linus Torvalds's avatar
Linus Torvalds committed
948

949
	if (!fcport)
950
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
951
952

	qla_printk(KERN_INFO, ha,
953
	    "scsi(%ld:%d:%d): LOOP RESET ISSUED.\n", ha->host_no, id, lun);
Linus Torvalds's avatar
Linus Torvalds committed
954
955
956

	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
		DEBUG2(printk("%s failed:board disabled\n",__func__));
957
		goto eh_bus_reset_done;
Linus Torvalds's avatar
Linus Torvalds committed
958
959
960
	}

	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
961
962
		if (qla2x00_loop_reset(ha) == QLA_SUCCESS)
			ret = SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
963
	}
964
965
	if (ret == FAILED)
		goto eh_bus_reset_done;
Linus Torvalds's avatar
Linus Torvalds committed
966

967
	/* Flush outstanding commands. */
968
	if (!qla2x00_eh_wait_for_pending_commands(pha))
969
		ret = FAILED;
Linus Torvalds's avatar
Linus Torvalds committed
970

971
eh_bus_reset_done:
Linus Torvalds's avatar
Linus Torvalds committed
972
	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
973
	    (ret == FAILED) ? "failed" : "succeded");
Linus Torvalds's avatar
Linus Torvalds committed
974

975
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
}

/**************************************************************************
* qla2xxx_eh_host_reset
*
* Description:
*    The reset function will reset the Adapter.
*
* Input:
*      cmd = Linux SCSI command packet of the command that cause the
*            adapter reset.
*
* Returns:
*      Either SUCCESS or FAILED.
*
* Note:
**************************************************************************/
993
static int
Linus Torvalds's avatar
Linus Torvalds committed
994
995
qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
{
996
	scsi_qla_host_t *ha = shost_priv(cmd->device->host);
997
	fc_port_t *fcport = (struct fc_port *) cmd->device->hostdata;
998
	int ret = FAILED;
999
1000
	unsigned int id, lun;
	unsigned long serial;
1001
	scsi_qla_host_t *pha = to_qla_parent(ha);
Linus Torvalds's avatar
Linus Torvalds committed
1002

1003
1004
	qla2x00_block_error_handler(cmd);

1005
1006
1007
1008
	id = cmd->device->id;
	lun = cmd->device->lun;
	serial = cmd->serial_number;

1009
	if (!fcport)
1010
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
1011
1012

	qla_printk(KERN_INFO, ha,
1013
	    "scsi(%ld:%d:%d): ADAPTER RESET ISSUED.\n", ha->host_no, id, lun);
Linus Torvalds's avatar
Linus Torvalds committed
1014
1015

	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
1016
		goto eh_host_reset_lock;
Linus Torvalds's avatar
Linus Torvalds committed
1017
1018
1019

	/*
	 * Fixme-may be dpc thread is active and processing
1020
	 * loop_resync,so wait a while for it to
Linus Torvalds's avatar
Linus Torvalds committed
1021
1022
1023
1024
1025
1026
	 * be completed and then issue big hammer.Otherwise
	 * it may cause I/O failure as big hammer marks the
	 * devices as lost kicking of the port_down_timer
	 * while dpc is stuck for the mailbox to complete.
	 */
	qla2x00_wait_for_loop_ready(ha);
1027
1028
1029
	set_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
	if (qla2x00_abort_isp(pha)) {
		clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
1030
		/* failed. schedule dpc to try */
1031
		set_bit(ISP_ABORT_NEEDED, &pha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
1032
1033

		if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
1034
			goto eh_host_reset_lock;
1035
	}
1036
	clear_bit(ABORT_ISP_ACTIVE, &pha->dpc_flags);
Linus Torvalds's avatar
Linus Torvalds committed
1037
1038

	/* Waiting for our command in done_queue to be returned to OS.*/
1039
	if (qla2x00_eh_wait_for_pending_commands(pha))
1040
		ret = SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
1041

1042
1043
1044
	if (ha->parent)
		qla2x00_vp_abort_isp(ha);

1045
1046
1047
eh_host_reset_lock:
	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
	    (ret == FAILED) ? "failed" : "succeded");
Linus Torvalds's avatar
Linus Torvalds committed
1048

1049
1050
	return ret;
}
Linus Torvalds's avatar
Linus Torvalds committed
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061

/*
* qla2x00_loop_reset
*      Issue loop reset.
*
* Input:
*      ha = adapter block pointer.
*
* Returns:
*      0 = success
*/
1062
int
Linus Torvalds's avatar
Linus Torvalds committed
1063
1064
qla2x00_loop_reset(scsi_qla_host_t *ha)
{
1065
	int ret;
1066
	struct fc_port *fcport;
Linus Torvalds's avatar
Linus Torvalds committed
1067

1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
	if (ha->flags.enable_lip_full_login) {
		ret = qla2x00_full_login_lip(ha);
		if (ret != QLA_SUCCESS) {
			DEBUG2_3(printk("%s(%ld): bus_reset failed: "
			    "full_login_lip=%d.\n", __func__, ha->host_no,
			    ret));
		}
		atomic_set(&ha->loop_state, LOOP_DOWN);
		atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
		qla2x00_mark_all_devices_lost(ha, 0);
		qla2x00_wait_for_loop_ready(ha);
	}

Linus Torvalds's avatar
Linus Torvalds committed
1081
	if (ha->flags.enable_lip_reset) {
1082
1083
1084
1085
1086
1087
		ret = qla2x00_lip_reset(ha);
		if (ret != QLA_SUCCESS) {
			DEBUG2_3(printk("%s(%ld): bus_reset failed: "
			    "lip_reset=%d.\n", __func__, ha->host_no, ret));
		}
		qla2x00_wait_for_loop_ready(ha);
Linus Torvalds's avatar
Linus Torvalds committed
1088
1089
	}

1090
	if (ha->flags.enable_target_reset) {
1091
1092
		list_for_each_entry(fcport, &ha->fcports, list) {
			if (fcport->port_type != FCT_TARGET)
Linus Torvalds's avatar
Linus Torvalds committed
1093
1094
				continue;

1095
1096
1097
1098
1099
1100
			ret = qla2x00_device_reset(ha, fcport);
			if (ret != QLA_SUCCESS) {
				DEBUG2_3(printk("%s(%ld): bus_reset failed: "
				    "target_reset=%d d_id=%x.\n", __func__,
				    ha->host_no, ret, fcport->d_id.b24));
			}
Linus Torvalds's avatar
Linus Torvalds committed
1101
1102
1103
1104
1105
1106
		}
	}

	/* Issue marker command only when we are going to start the I/O */
	ha->marker_needed = 1;

1107
	return QLA_SUCCESS;
Linus Torvalds's avatar
Linus Torvalds committed
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
}

/*
 * qla2x00_device_reset
 *	Issue bus device reset message to the target.
 *
 * Input:
 *	ha = adapter block pointer.
 *	t = SCSI ID.
 *	TARGET_QUEUE_LOCK must be released.
 *	ADAPTER_STATE_LOCK must be released.
 *
 * Context:
 *	Kernel context.
 */
static int
qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
{
	/* Abort Target command will clear Reservation */
1127
	return ha->isp_ops->abort_target(reset_fcport);
Linus Torvalds's avatar
Linus Torvalds committed
1128
1129
}

1130
1131
static int
qla2xxx_slave_alloc(struct scsi_device *sdev)
Linus Torvalds's avatar
Linus Torvalds committed
1132
{
1133
	struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
Linus Torvalds's avatar
Linus Torvalds committed
1134

1135
	if (!rport || fc_remote_port_chkready(rport))
1136
		return -ENXIO;
1137

1138
	sdev->hostdata = *(fc_port_t **)rport->dd_data;
Linus Torvalds's avatar
Linus Torvalds committed
1139

1140
1141
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
1142

1143
1144
1145
static int
qla2xxx_slave_configure(struct scsi_device *sdev)
{
1146
	scsi_qla_host_t *ha = shost_priv(sdev->host);
's avatar
committed
1147
1148
	struct fc_rport *rport = starget_to_rport(sdev->sdev_target);

1149
	if (sdev->tagged_supported)
1150
		scsi_activate_tcq(sdev, ha->max_q_depth);
1151
	else
1152
		scsi_deactivate_tcq(sdev, ha->max_q_depth);
Linus Torvalds's avatar
Linus Torvalds committed
1153

's avatar
committed
1154
1155
	rport->dev_loss_tmo = ha->port_down_retry_count + 5;

1156
1157
	return 0;
}
Linus Torvalds's avatar
Linus Torvalds committed
1158

1159
1160
1161
1162
static void
qla2xxx_slave_destroy(struct scsi_device *sdev)
{
	sdev->hostdata = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
1163
1164
}

1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
static int
qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
	return sdev->queue_depth;
}

static int
qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
{
	if (sdev->tagged_supported) {
		scsi_set_tag_type(sdev, tag_type);
		if (tag_type)
			scsi_activate_tcq(sdev, sdev->queue_depth);
		else
			scsi_deactivate_tcq(sdev, sdev->queue_depth);
	} else
		tag_type = 0;

	return tag_type;
}

Linus Torvalds's avatar
Linus Torvalds committed
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
/**
 * qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
 * @ha: HA context
 *
 * At exit, the @ha's flags.enable_64bit_addressing set to indicated
 * supported addressing method.
 */
static void
qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
{
1197
	/* Assume a 32bit DMA mask. */
Linus Torvalds's avatar
Linus Torvalds committed
1198
1199
	ha->flags.enable_64bit_addressing = 0;

1200
1201
1202
1203
1204
	if (!dma_set_mask(&ha->pdev->dev, DMA_64BIT_MASK)) {
		/* Any upper-dword bits set? */
		if (MSD(dma_get_required_mask(&ha->pdev->dev)) &&
		    !pci_set_consistent_dma_mask(ha->pdev, DMA_64BIT_MASK)) {
			/* Ok, a 64bit DMA mask is applicable. */
Linus Torvalds's avatar
Linus Torvalds committed
1205
			ha->flags.enable_64bit_addressing = 1;
1206
1207
			ha->isp_ops->calc_req_entries = qla2x00_calc_iocbs_64;
			ha->isp_ops->build_iocbs = qla2x00_build_scsi_iocbs_64;
1208
			return;
Linus Torvalds's avatar
Linus Torvalds committed
1209
1210
		}
	}
1211
1212
1213

	dma_set_mask(&ha->pdev->dev, DMA_32BIT_MASK);
	pci_set_consistent_dma_mask(ha->pdev, DMA_32BIT_MASK);
Linus Torvalds's avatar
Linus Torvalds committed
1214
1215
}