qla_attr.c 34.1 KB
Newer Older
已提交
1
/*
A
Andrew Vasquez 已提交
2
 * QLogic Fibre Channel HBA Driver
3
 * Copyright (c)  2003-2008 QLogic Corporation
已提交
4
 *
A
Andrew Vasquez 已提交
5
 * See LICENSE.qla2xxx for copyright and licensing details.
已提交
6 7 8
 */
#include "qla_def.h"

9
#include <linux/kthread.h>
已提交
10
#include <linux/vmalloc.h>
11
#include <linux/delay.h>
已提交
12

A
Adrian Bunk 已提交
13
static int qla24xx_vport_disable(struct fc_vport *, bool);
14

已提交
15 16 17
/* SYSFS attributes --------------------------------------------------------- */

static ssize_t
18 19 20
qla2x00_sysfs_read_fw_dump(struct kobject *kobj,
			   struct bin_attribute *bin_attr,
			   char *buf, loff_t off, size_t count)
已提交
21
{
A
Andrew Vasquez 已提交
22
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
已提交
23 24 25 26 27
	    struct device, kobj)));

	if (ha->fw_dump_reading == 0)
		return 0;

28 29
	return memory_read_from_buffer(buf, count, &off, ha->fw_dump,
					ha->fw_dump_len);
已提交
30 31 32
}

static ssize_t
33 34 35
qla2x00_sysfs_write_fw_dump(struct kobject *kobj,
			    struct bin_attribute *bin_attr,
			    char *buf, loff_t off, size_t count)
已提交
36
{
A
Andrew Vasquez 已提交
37
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
已提交
38 39 40 41 42 43 44 45 46
	    struct device, kobj)));
	int reading;

	if (off != 0)
		return (0);

	reading = simple_strtol(buf, NULL, 10);
	switch (reading) {
	case 0:
47 48
		if (!ha->fw_dump_reading)
			break;
已提交
49

50 51 52 53 54
		qla_printk(KERN_INFO, ha,
		    "Firmware dump cleared on (%ld).\n", ha->host_no);

		ha->fw_dump_reading = 0;
		ha->fw_dumped = 0;
已提交
55 56
		break;
	case 1:
57
		if (ha->fw_dumped && !ha->fw_dump_reading) {
已提交
58 59 60
			ha->fw_dump_reading = 1;

			qla_printk(KERN_INFO, ha,
61
			    "Raw firmware dump ready for read on (%ld).\n",
已提交
62 63 64
			    ha->host_no);
		}
		break;
65 66 67
	case 2:
		qla2x00_alloc_fw_dump(ha);
		break;
68 69 70
	case 3:
		qla2x00_system_error(ha);
		break;
已提交
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	}
	return (count);
}

static struct bin_attribute sysfs_fw_dump_attr = {
	.attr = {
		.name = "fw_dump",
		.mode = S_IRUSR | S_IWUSR,
	},
	.size = 0,
	.read = qla2x00_sysfs_read_fw_dump,
	.write = qla2x00_sysfs_write_fw_dump,
};

static ssize_t
86 87 88
qla2x00_sysfs_read_nvram(struct kobject *kobj,
			 struct bin_attribute *bin_attr,
			 char *buf, loff_t off, size_t count)
已提交
89
{
A
Andrew Vasquez 已提交
90
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
已提交
91 92
	    struct device, kobj)));

93
	if (!capable(CAP_SYS_ADMIN))
已提交
94 95
		return 0;

96
	/* Read NVRAM data from cache. */
97 98
	return memory_read_from_buffer(buf, count, &off, ha->nvram,
					ha->nvram_size);
已提交
99 100 101
}

static ssize_t
102 103 104
qla2x00_sysfs_write_nvram(struct kobject *kobj,
			  struct bin_attribute *bin_attr,
			  char *buf, loff_t off, size_t count)
已提交
105
{
A
Andrew Vasquez 已提交
106
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
已提交
107 108 109
	    struct device, kobj)));
	uint16_t	cnt;

110
	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size)
已提交
111 112 113
		return 0;

	/* Checksum NVRAM. */
114
	if (IS_FWI2_CAPABLE(ha)) {
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
		uint32_t *iter;
		uint32_t chksum;

		iter = (uint32_t *)buf;
		chksum = 0;
		for (cnt = 0; cnt < ((count >> 2) - 1); cnt++)
			chksum += le32_to_cpu(*iter++);
		chksum = ~chksum + 1;
		*iter = cpu_to_le32(chksum);
	} else {
		uint8_t *iter;
		uint8_t chksum;

		iter = (uint8_t *)buf;
		chksum = 0;
		for (cnt = 0; cnt < count - 1; cnt++)
			chksum += *iter++;
		chksum = ~chksum + 1;
		*iter = chksum;
	}
已提交
135 136

	/* Write NVRAM. */
137
	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->nvram_base, count);
138
	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->nvram, ha->nvram_base,
139
	    count);
已提交
140

141 142
	set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);

已提交
143 144 145 146 147 148 149 150
	return (count);
}

static struct bin_attribute sysfs_nvram_attr = {
	.attr = {
		.name = "nvram",
		.mode = S_IRUSR | S_IWUSR,
	},
151
	.size = 512,
已提交
152 153 154 155
	.read = qla2x00_sysfs_read_nvram,
	.write = qla2x00_sysfs_write_nvram,
};

156
static ssize_t
157 158 159
qla2x00_sysfs_read_optrom(struct kobject *kobj,
			  struct bin_attribute *bin_attr,
			  char *buf, loff_t off, size_t count)
160
{
A
Andrew Vasquez 已提交
161
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
162 163 164 165 166
	    struct device, kobj)));

	if (ha->optrom_state != QLA_SREADING)
		return 0;

167 168
	return memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
					ha->optrom_region_size);
169 170 171
}

static ssize_t
172 173 174
qla2x00_sysfs_write_optrom(struct kobject *kobj,
			   struct bin_attribute *bin_attr,
			   char *buf, loff_t off, size_t count)
175
{
A
Andrew Vasquez 已提交
176
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
177 178 179 180
	    struct device, kobj)));

	if (ha->optrom_state != QLA_SWRITING)
		return -EINVAL;
181
	if (off > ha->optrom_region_size)
182
		return -ERANGE;
183 184
	if (off + count > ha->optrom_region_size)
		count = ha->optrom_region_size - off;
185 186 187 188 189 190 191 192 193 194 195

	memcpy(&ha->optrom_buffer[off], buf, count);

	return count;
}

static struct bin_attribute sysfs_optrom_attr = {
	.attr = {
		.name = "optrom",
		.mode = S_IRUSR | S_IWUSR,
	},
196
	.size = 0,
197 198 199 200 201
	.read = qla2x00_sysfs_read_optrom,
	.write = qla2x00_sysfs_write_optrom,
};

static ssize_t
202 203 204
qla2x00_sysfs_write_optrom_ctl(struct kobject *kobj,
			       struct bin_attribute *bin_attr,
			       char *buf, loff_t off, size_t count)
205
{
A
Andrew Vasquez 已提交
206
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
207
	    struct device, kobj)));
208 209 210
	uint32_t start = 0;
	uint32_t size = ha->optrom_size;
	int val, valid;
211 212 213 214

	if (off)
		return 0;

215 216 217
	if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
		return -EINVAL;
	if (start > ha->optrom_size)
218 219 220 221 222 223 224 225 226
		return -EINVAL;

	switch (val) {
	case 0:
		if (ha->optrom_state != QLA_SREADING &&
		    ha->optrom_state != QLA_SWRITING)
			break;

		ha->optrom_state = QLA_SWAITING;
227 228 229 230 231

		DEBUG2(qla_printk(KERN_INFO, ha,
		    "Freeing flash region allocation -- 0x%x bytes.\n",
		    ha->optrom_region_size));

232 233 234 235 236 237 238
		vfree(ha->optrom_buffer);
		ha->optrom_buffer = NULL;
		break;
	case 1:
		if (ha->optrom_state != QLA_SWAITING)
			break;

239 240 241 242 243 244 245 246 247 248
		if (start & 0xfff) {
			qla_printk(KERN_WARNING, ha,
			    "Invalid start region 0x%x/0x%x.\n", start, size);
			return -EINVAL;
		}

		ha->optrom_region_start = start;
		ha->optrom_region_size = start + size > ha->optrom_size ?
		    ha->optrom_size - start : size;

249
		ha->optrom_state = QLA_SREADING;
250
		ha->optrom_buffer = vmalloc(ha->optrom_region_size);
251 252 253
		if (ha->optrom_buffer == NULL) {
			qla_printk(KERN_WARNING, ha,
			    "Unable to allocate memory for optrom retrieval "
254
			    "(%x).\n", ha->optrom_region_size);
255 256 257 258 259

			ha->optrom_state = QLA_SWAITING;
			return count;
		}

260 261 262 263 264 265 266
		DEBUG2(qla_printk(KERN_INFO, ha,
		    "Reading flash region -- 0x%x/0x%x.\n",
		    ha->optrom_region_start, ha->optrom_region_size));

		memset(ha->optrom_buffer, 0, ha->optrom_region_size);
		ha->isp_ops->read_optrom(ha, ha->optrom_buffer,
		    ha->optrom_region_start, ha->optrom_region_size);
267 268 269 270 271
		break;
	case 2:
		if (ha->optrom_state != QLA_SWAITING)
			break;

272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
		/*
		 * We need to be more restrictive on which FLASH regions are
		 * allowed to be updated via user-space.  Regions accessible
		 * via this method include:
		 *
		 * ISP21xx/ISP22xx/ISP23xx type boards:
		 *
		 * 	0x000000 -> 0x020000 -- Boot code.
		 *
		 * ISP2322/ISP24xx type boards:
		 *
		 * 	0x000000 -> 0x07ffff -- Boot code.
		 * 	0x080000 -> 0x0fffff -- Firmware.
		 *
		 * ISP25xx type boards:
		 *
		 * 	0x000000 -> 0x07ffff -- Boot code.
		 * 	0x080000 -> 0x0fffff -- Firmware.
		 * 	0x120000 -> 0x12ffff -- VPD and HBA parameters.
		 */
		valid = 0;
		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
			valid = 1;
295 296
		else if (start == (ha->flt_region_boot * 4) ||
		    start == (ha->flt_region_fw * 4))
297
			valid = 1;
298 299
		else if (IS_QLA25XX(ha) &&
		    start == (ha->flt_region_vpd_nvram * 4))
300 301 302 303 304 305 306 307 308 309 310
		    valid = 1;
		if (!valid) {
			qla_printk(KERN_WARNING, ha,
			    "Invalid start region 0x%x/0x%x.\n", start, size);
			return -EINVAL;
		}

		ha->optrom_region_start = start;
		ha->optrom_region_size = start + size > ha->optrom_size ?
		    ha->optrom_size - start : size;

311
		ha->optrom_state = QLA_SWRITING;
312
		ha->optrom_buffer = vmalloc(ha->optrom_region_size);
313 314 315
		if (ha->optrom_buffer == NULL) {
			qla_printk(KERN_WARNING, ha,
			    "Unable to allocate memory for optrom update "
316
			    "(%x).\n", ha->optrom_region_size);
317 318 319 320

			ha->optrom_state = QLA_SWAITING;
			return count;
		}
321 322 323 324 325 326

		DEBUG2(qla_printk(KERN_INFO, ha,
		    "Staging flash region write -- 0x%x/0x%x.\n",
		    ha->optrom_region_start, ha->optrom_region_size));

		memset(ha->optrom_buffer, 0, ha->optrom_region_size);
327 328 329 330 331
		break;
	case 3:
		if (ha->optrom_state != QLA_SWRITING)
			break;

332 333 334 335 336 337
		DEBUG2(qla_printk(KERN_INFO, ha,
		    "Writing flash region -- 0x%x/0x%x.\n",
		    ha->optrom_region_start, ha->optrom_region_size));

		ha->isp_ops->write_optrom(ha, ha->optrom_buffer,
		    ha->optrom_region_start, ha->optrom_region_size);
338
		break;
339 340
	default:
		count = -EINVAL;
341 342 343 344 345 346 347 348 349 350 351 352 353
	}
	return count;
}

static struct bin_attribute sysfs_optrom_ctl_attr = {
	.attr = {
		.name = "optrom_ctl",
		.mode = S_IWUSR,
	},
	.size = 0,
	.write = qla2x00_sysfs_write_optrom_ctl,
};

354
static ssize_t
355 356 357
qla2x00_sysfs_read_vpd(struct kobject *kobj,
		       struct bin_attribute *bin_attr,
		       char *buf, loff_t off, size_t count)
358
{
A
Andrew Vasquez 已提交
359
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
360 361
	    struct device, kobj)));

362
	if (!capable(CAP_SYS_ADMIN))
363 364
		return 0;

365
	/* Read NVRAM data from cache. */
366
	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
367 368 369
}

static ssize_t
370 371 372
qla2x00_sysfs_write_vpd(struct kobject *kobj,
			struct bin_attribute *bin_attr,
			char *buf, loff_t off, size_t count)
373
{
A
Andrew Vasquez 已提交
374
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
375 376 377 378 379 380
	    struct device, kobj)));

	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size)
		return 0;

	/* Write NVRAM. */
381
	ha->isp_ops->write_nvram(ha, (uint8_t *)buf, ha->vpd_base, count);
382
	ha->isp_ops->read_nvram(ha, (uint8_t *)ha->vpd, ha->vpd_base, count);
383 384 385 386 387 388 389 390 391 392 393 394 395 396

	return count;
}

static struct bin_attribute sysfs_vpd_attr = {
	.attr = {
		.name = "vpd",
		.mode = S_IRUSR | S_IWUSR,
	},
	.size = 0,
	.read = qla2x00_sysfs_read_vpd,
	.write = qla2x00_sysfs_write_vpd,
};

397
static ssize_t
398 399 400
qla2x00_sysfs_read_sfp(struct kobject *kobj,
		       struct bin_attribute *bin_attr,
		       char *buf, loff_t off, size_t count)
401
{
A
Andrew Vasquez 已提交
402
	struct scsi_qla_host *ha = shost_priv(dev_to_shost(container_of(kobj,
403 404 405 406 407 408 409
	    struct device, kobj)));
	uint16_t iter, addr, offset;
	int rval;

	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != SFP_DEV_SIZE * 2)
		return 0;

410 411 412 413 414 415 416 417 418 419 420 421 422
	if (ha->sfp_data)
		goto do_read;

	ha->sfp_data = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
	    &ha->sfp_data_dma);
	if (!ha->sfp_data) {
		qla_printk(KERN_WARNING, ha,
		    "Unable to allocate memory for SFP read-data.\n");
		return 0;
	}

do_read:
	memset(ha->sfp_data, 0, SFP_BLOCK_SIZE);
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
	addr = 0xa0;
	for (iter = 0, offset = 0; iter < (SFP_DEV_SIZE * 2) / SFP_BLOCK_SIZE;
	    iter++, offset += SFP_BLOCK_SIZE) {
		if (iter == 4) {
			/* Skip to next device address. */
			addr = 0xa2;
			offset = 0;
		}

		rval = qla2x00_read_sfp(ha, ha->sfp_data_dma, addr, offset,
		    SFP_BLOCK_SIZE);
		if (rval != QLA_SUCCESS) {
			qla_printk(KERN_WARNING, ha,
			    "Unable to read SFP data (%x/%x/%x).\n", rval,
			    addr, offset);
			count = 0;
			break;
		}
		memcpy(buf, ha->sfp_data, SFP_BLOCK_SIZE);
		buf += SFP_BLOCK_SIZE;
	}

	return count;
}

static struct bin_attribute sysfs_sfp_attr = {
	.attr = {
		.name = "sfp",
		.mode = S_IRUSR | S_IWUSR,
	},
	.size = SFP_DEV_SIZE * 2,
	.read = qla2x00_sysfs_read_sfp,
};

457 458 459 460 461 462 463 464 465 466 467
static struct sysfs_entry {
	char *name;
	struct bin_attribute *attr;
	int is4GBp_only;
} bin_file_entries[] = {
	{ "fw_dump", &sysfs_fw_dump_attr, },
	{ "nvram", &sysfs_nvram_attr, },
	{ "optrom", &sysfs_optrom_attr, },
	{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
	{ "vpd", &sysfs_vpd_attr, 1 },
	{ "sfp", &sysfs_sfp_attr, 1 },
468
	{ NULL },
469 470
};

已提交
471 472 473 474
void
qla2x00_alloc_sysfs_attr(scsi_qla_host_t *ha)
{
	struct Scsi_Host *host = ha->host;
475 476
	struct sysfs_entry *iter;
	int ret;
已提交
477

478
	for (iter = bin_file_entries; iter->name; iter++) {
479
		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
480 481 482 483 484 485 486 487
			continue;

		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
		    iter->attr);
		if (ret)
			qla_printk(KERN_INFO, ha,
			    "Unable to create sysfs %s binary attribute "
			    "(%d).\n", iter->name, ret);
488
	}
已提交
489 490 491 492 493 494
}

void
qla2x00_free_sysfs_attr(scsi_qla_host_t *ha)
{
	struct Scsi_Host *host = ha->host;
495 496 497
	struct sysfs_entry *iter;

	for (iter = bin_file_entries; iter->name; iter++) {
498
		if (iter->is4GBp_only && !IS_FWI2_CAPABLE(ha))
499
			continue;
已提交
500

501
		sysfs_remove_bin_file(&host->shost_gendev.kobj,
502
		    iter->attr);
503
	}
504 505

	if (ha->beacon_blink_led == 1)
506
		ha->isp_ops->beacon_off(ha);
已提交
507 508
}

509 510 511
/* Scsi_Host attributes. */

static ssize_t
512 513
qla2x00_drvr_version_show(struct device *dev,
			  struct device_attribute *attr, char *buf)
514 515 516 517 518
{
	return snprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
}

static ssize_t
519 520
qla2x00_fw_version_show(struct device *dev,
			struct device_attribute *attr, char *buf)
521
{
522
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
523 524 525
	char fw_str[30];

	return snprintf(buf, PAGE_SIZE, "%s\n",
526
	    ha->isp_ops->fw_version_str(ha, fw_str));
527 528 529
}

static ssize_t
530 531
qla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
			char *buf)
532
{
533
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
534 535
	uint32_t sn;

536 537 538 539
	if (IS_FWI2_CAPABLE(ha)) {
		qla2xxx_get_vpd_field(ha, "SN", buf, PAGE_SIZE);
		return snprintf(buf, PAGE_SIZE, "%s\n", buf);
	}
540

541 542 543 544 545 546
	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
	return snprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
	    sn % 100000);
}

static ssize_t
547 548
qla2x00_isp_name_show(struct device *dev, struct device_attribute *attr,
		      char *buf)
549
{
550
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
551
	return snprintf(buf, PAGE_SIZE, "ISP%04X\n", ha->pdev->device);
552 553 554
}

static ssize_t
555 556
qla2x00_isp_id_show(struct device *dev, struct device_attribute *attr,
		    char *buf)
557
{
558
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
559 560 561 562 563 564
	return snprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
	    ha->product_id[0], ha->product_id[1], ha->product_id[2],
	    ha->product_id[3]);
}

static ssize_t
565 566
qla2x00_model_name_show(struct device *dev, struct device_attribute *attr,
			char *buf)
567
{
568
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
569 570 571 572
	return snprintf(buf, PAGE_SIZE, "%s\n", ha->model_number);
}

static ssize_t
573 574
qla2x00_model_desc_show(struct device *dev, struct device_attribute *attr,
			char *buf)
575
{
576
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
577 578 579 580 581
	return snprintf(buf, PAGE_SIZE, "%s\n",
	    ha->model_desc ? ha->model_desc: "");
}

static ssize_t
582 583
qla2x00_pci_info_show(struct device *dev, struct device_attribute *attr,
		      char *buf)
584
{
585
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
586 587 588
	char pci_info[30];

	return snprintf(buf, PAGE_SIZE, "%s\n",
589
	    ha->isp_ops->pci_info_str(ha, pci_info));
590 591 592
}

static ssize_t
593 594
qla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
			char *buf)
595
{
596
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
	int len = 0;

	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
	    atomic_read(&ha->loop_state) == LOOP_DEAD)
		len = snprintf(buf, PAGE_SIZE, "Link Down\n");
	else if (atomic_read(&ha->loop_state) != LOOP_READY ||
	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
	    test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags))
		len = snprintf(buf, PAGE_SIZE, "Unknown Link State\n");
	else {
		len = snprintf(buf, PAGE_SIZE, "Link Up - ");

		switch (ha->current_topology) {
		case ISP_CFG_NL:
			len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
			break;
		case ISP_CFG_FL:
			len += snprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
			break;
		case ISP_CFG_N:
			len += snprintf(buf + len, PAGE_SIZE-len,
			    "N_Port to N_Port\n");
			break;
		case ISP_CFG_F:
			len += snprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
			break;
		default:
			len += snprintf(buf + len, PAGE_SIZE-len, "Loop\n");
			break;
		}
	}
	return len;
}

631
static ssize_t
632 633
qla2x00_zio_show(struct device *dev, struct device_attribute *attr,
		 char *buf)
634
{
635
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
636 637 638 639 640 641 642 643 644 645 646 647 648 649
	int len = 0;

	switch (ha->zio_mode) {
	case QLA_ZIO_MODE_6:
		len += snprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
		break;
	case QLA_ZIO_DISABLED:
		len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
		break;
	}
	return len;
}

static ssize_t
650 651
qla2x00_zio_store(struct device *dev, struct device_attribute *attr,
		  const char *buf, size_t count)
652
{
653
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
654 655 656
	int val = 0;
	uint16_t zio_mode;

657 658 659
	if (!IS_ZIO_SUPPORTED(ha))
		return -ENOTSUPP;

660 661 662
	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;

663
	if (val)
664
		zio_mode = QLA_ZIO_MODE_6;
665
	else
666 667 668 669 670 671 672 673 674 675 676
		zio_mode = QLA_ZIO_DISABLED;

	/* Update per-hba values and queue a reset. */
	if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) {
		ha->zio_mode = zio_mode;
		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
	}
	return strlen(buf);
}

static ssize_t
677 678
qla2x00_zio_timer_show(struct device *dev, struct device_attribute *attr,
		       char *buf)
679
{
680
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
681 682 683 684 685

	return snprintf(buf, PAGE_SIZE, "%d us\n", ha->zio_timer * 100);
}

static ssize_t
686 687
qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr,
			const char *buf, size_t count)
688
{
689
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
690 691 692 693 694 695 696 697 698 699 700 701 702 703
	int val = 0;
	uint16_t zio_timer;

	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;
	if (val > 25500 || val < 100)
		return -ERANGE;

	zio_timer = (uint16_t)(val / 100);
	ha->zio_timer = zio_timer;

	return strlen(buf);
}

704
static ssize_t
705 706
qla2x00_beacon_show(struct device *dev, struct device_attribute *attr,
		    char *buf)
707
{
708
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
709 710 711 712 713 714 715 716 717 718
	int len = 0;

	if (ha->beacon_blink_led)
		len += snprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
	else
		len += snprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
	return len;
}

static ssize_t
719 720
qla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
		     const char *buf, size_t count)
721
{
722
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738
	int val = 0;
	int rval;

	if (IS_QLA2100(ha) || IS_QLA2200(ha))
		return -EPERM;

	if (test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) {
		qla_printk(KERN_WARNING, ha,
		    "Abort ISP active -- ignoring beacon request.\n");
		return -EBUSY;
	}

	if (sscanf(buf, "%d", &val) != 1)
		return -EINVAL;

	if (val)
739
		rval = ha->isp_ops->beacon_on(ha);
740
	else
741
		rval = ha->isp_ops->beacon_off(ha);
742 743 744 745 746 747 748

	if (rval != QLA_SUCCESS)
		count = 0;

	return count;
}

749
static ssize_t
750 751
qla2x00_optrom_bios_version_show(struct device *dev,
				 struct device_attribute *attr, char *buf)
752
{
753
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
754 755 756 757 758 759

	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
	    ha->bios_revision[0]);
}

static ssize_t
760 761
qla2x00_optrom_efi_version_show(struct device *dev,
				struct device_attribute *attr, char *buf)
762
{
763
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
764 765 766 767 768 769

	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
	    ha->efi_revision[0]);
}

static ssize_t
770 771
qla2x00_optrom_fcode_version_show(struct device *dev,
				  struct device_attribute *attr, char *buf)
772
{
773
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
774 775 776 777 778 779

	return snprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
	    ha->fcode_revision[0]);
}

static ssize_t
780 781
qla2x00_optrom_fw_version_show(struct device *dev,
			       struct device_attribute *attr, char *buf)
782
{
783
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));
784 785 786 787 788 789

	return snprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
	    ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
	    ha->fw_revision[3]);
}

790 791 792 793 794 795 796 797 798 799
static ssize_t
qla2x00_total_isp_aborts_show(struct device *dev,
			      struct device_attribute *attr, char *buf)
{
	scsi_qla_host_t *ha = shost_priv(class_to_shost(dev));

	return snprintf(buf, PAGE_SIZE, "%d\n",
	    ha->qla_stats.total_isp_aborts);
}

800 801 802 803 804 805 806 807
static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL);
static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
static DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
static DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
static DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
static DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
static DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
808
static DEVICE_ATTR(link_state, S_IRUGO, qla2x00_link_state_show, NULL);
809 810 811 812 813 814 815 816 817 818 819 820 821
static DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, qla2x00_zio_store);
static DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
		   qla2x00_zio_timer_store);
static DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
		   qla2x00_beacon_store);
static DEVICE_ATTR(optrom_bios_version, S_IRUGO,
		   qla2x00_optrom_bios_version_show, NULL);
static DEVICE_ATTR(optrom_efi_version, S_IRUGO,
		   qla2x00_optrom_efi_version_show, NULL);
static DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
		   qla2x00_optrom_fcode_version_show, NULL);
static DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
		   NULL);
822 823
static DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
		   NULL);
824 825 826 827 828 829 830 831 832 833

struct device_attribute *qla2x00_host_attrs[] = {
	&dev_attr_driver_version,
	&dev_attr_fw_version,
	&dev_attr_serial_num,
	&dev_attr_isp_name,
	&dev_attr_isp_id,
	&dev_attr_model_name,
	&dev_attr_model_desc,
	&dev_attr_pci_info,
834
	&dev_attr_link_state,
835 836 837 838 839 840 841
	&dev_attr_zio,
	&dev_attr_zio_timer,
	&dev_attr_beacon,
	&dev_attr_optrom_bios_version,
	&dev_attr_optrom_efi_version,
	&dev_attr_optrom_fcode_version,
	&dev_attr_optrom_fw_version,
842
	&dev_attr_total_isp_aborts,
843 844 845
	NULL,
};

已提交
846 847 848 849 850
/* Host attributes. */

static void
qla2x00_get_host_port_id(struct Scsi_Host *shost)
{
A
Andrew Vasquez 已提交
851
	scsi_qla_host_t *ha = shost_priv(shost);
已提交
852 853 854 855 856

	fc_host_port_id(shost) = ha->d_id.b.domain << 16 |
	    ha->d_id.b.area << 8 | ha->d_id.b.al_pa;
}

857 858 859
static void
qla2x00_get_host_speed(struct Scsi_Host *shost)
{
860
	scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
861
	u32 speed = FC_PORTSPEED_UNKNOWN;
862 863

	switch (ha->link_data_rate) {
864
	case PORT_SPEED_1GB:
865
		speed = FC_PORTSPEED_1GBIT;
866
		break;
867
	case PORT_SPEED_2GB:
868
		speed = FC_PORTSPEED_2GBIT;
869
		break;
870
	case PORT_SPEED_4GB:
871
		speed = FC_PORTSPEED_4GBIT;
872
		break;
873
	case PORT_SPEED_8GB:
874
		speed = FC_PORTSPEED_8GBIT;
875
		break;
876 877 878 879
	}
	fc_host_speed(shost) = speed;
}

880 881 882
static void
qla2x00_get_host_port_type(struct Scsi_Host *shost)
{
883
	scsi_qla_host_t *ha = shost_priv(shost);
884 885
	uint32_t port_type = FC_PORTTYPE_UNKNOWN;

886 887 888 889
	if (ha->parent) {
		fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
		return;
	}
890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906
	switch (ha->current_topology) {
	case ISP_CFG_NL:
		port_type = FC_PORTTYPE_LPORT;
		break;
	case ISP_CFG_FL:
		port_type = FC_PORTTYPE_NLPORT;
		break;
	case ISP_CFG_N:
		port_type = FC_PORTTYPE_PTP;
		break;
	case ISP_CFG_F:
		port_type = FC_PORTTYPE_NPORT;
		break;
	}
	fc_host_port_type(shost) = port_type;
}

已提交
907 908 909 910
static void
qla2x00_get_starget_node_name(struct scsi_target *starget)
{
	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
A
Andrew Vasquez 已提交
911
	scsi_qla_host_t *ha = shost_priv(host);
912
	fc_port_t *fcport;
913
	u64 node_name = 0;
已提交
914

915
	list_for_each_entry(fcport, &ha->fcports, list) {
916 917
		if (fcport->rport &&
		    starget->id == fcport->rport->scsi_target_id) {
918
			node_name = wwn_to_u64(fcport->node_name);
919 920 921 922
			break;
		}
	}

923
	fc_starget_node_name(starget) = node_name;
已提交
924 925 926 927 928 929
}

static void
qla2x00_get_starget_port_name(struct scsi_target *starget)
{
	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
A
Andrew Vasquez 已提交
930
	scsi_qla_host_t *ha = shost_priv(host);
931
	fc_port_t *fcport;
932
	u64 port_name = 0;
已提交
933

934
	list_for_each_entry(fcport, &ha->fcports, list) {
935 936
		if (fcport->rport &&
		    starget->id == fcport->rport->scsi_target_id) {
937
			port_name = wwn_to_u64(fcport->port_name);
938 939 940 941
			break;
		}
	}

942
	fc_starget_port_name(starget) = port_name;
已提交
943 944 945 946 947 948
}

static void
qla2x00_get_starget_port_id(struct scsi_target *starget)
{
	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
A
Andrew Vasquez 已提交
949
	scsi_qla_host_t *ha = shost_priv(host);
950 951 952 953
	fc_port_t *fcport;
	uint32_t port_id = ~0U;

	list_for_each_entry(fcport, &ha->fcports, list) {
954 955
		if (fcport->rport &&
		    starget->id == fcport->rport->scsi_target_id) {
956 957 958 959 960
			port_id = fcport->d_id.b.domain << 16 |
			    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
			break;
		}
	}
已提交
961 962 963 964 965 966 967 968

	fc_starget_port_id(starget) = port_id;
}

static void
qla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
{
	if (timeout)
969
		rport->dev_loss_tmo = timeout;
已提交
970
	else
971
		rport->dev_loss_tmo = 1;
已提交
972 973
}

974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
static void
qla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
{
	struct Scsi_Host *host = rport_to_shost(rport);
	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;

	qla2x00_abort_fcport_cmds(fcport);

	/*
	 * Transport has effectively 'deleted' the rport, clear
	 * all local references.
	 */
	spin_lock_irq(host->host_lock);
	fcport->rport = NULL;
	*((fc_port_t **)rport->dd_data) = NULL;
	spin_unlock_irq(host->host_lock);
}

static void
qla2x00_terminate_rport_io(struct fc_rport *rport)
{
	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;

997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
	/*
	 * At this point all fcport's software-states are cleared.  Perform any
	 * final cleanup of firmware resources (PCBs and XCBs).
	 */
	if (fcport->loop_id != FC_NO_LOOP_ID) {
		fcport->ha->isp_ops->fabric_logout(fcport->ha, fcport->loop_id,
		    fcport->d_id.b.domain, fcport->d_id.b.area,
		    fcport->d_id.b.al_pa);
		fcport->loop_id = FC_NO_LOOP_ID;
	}

1008 1009 1010
	qla2x00_abort_fcport_cmds(fcport);
}

1011 1012 1013
static int
qla2x00_issue_lip(struct Scsi_Host *shost)
{
A
Andrew Vasquez 已提交
1014
	scsi_qla_host_t *ha = shost_priv(shost);
1015

1016
	qla2x00_loop_reset(ha);
1017 1018 1019
	return 0;
}

1020 1021 1022
static struct fc_host_statistics *
qla2x00_get_fc_host_stats(struct Scsi_Host *shost)
{
1023
	scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
1024
	int rval;
1025 1026
	struct link_statistics *stats;
	dma_addr_t stats_dma;
1027 1028 1029 1030 1031
	struct fc_host_statistics *pfc_host_stat;

	pfc_host_stat = &ha->fc_host_stat;
	memset(pfc_host_stat, -1, sizeof(struct fc_host_statistics));

1032 1033 1034 1035 1036 1037 1038 1039 1040
	stats = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &stats_dma);
	if (stats == NULL) {
		DEBUG2_3_11(printk("%s(%ld): Failed to allocate memory.\n",
		    __func__, ha->host_no));
		goto done;
	}
	memset(stats, 0, DMA_POOL_SIZE);

	rval = QLA_FUNCTION_FAILED;
1041
	if (IS_FWI2_CAPABLE(ha)) {
1042
		rval = qla24xx_get_isp_stats(ha, stats, stats_dma);
1043 1044 1045 1046 1047
	} else if (atomic_read(&ha->loop_state) == LOOP_READY &&
		    !test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) &&
		    !test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) &&
		    !ha->dpc_active) {
		/* Must be in a 'READY' state for statistics retrieval. */
1048 1049
		rval = qla2x00_get_link_status(ha, ha->loop_id, stats,
		    stats_dma);
1050
	}
1051 1052

	if (rval != QLA_SUCCESS)
1053 1054 1055 1056 1057 1058 1059 1060 1061
		goto done_free;

	pfc_host_stat->link_failure_count = stats->link_fail_cnt;
	pfc_host_stat->loss_of_sync_count = stats->loss_sync_cnt;
	pfc_host_stat->loss_of_signal_count = stats->loss_sig_cnt;
	pfc_host_stat->prim_seq_protocol_err_count = stats->prim_seq_err_cnt;
	pfc_host_stat->invalid_tx_word_count = stats->inval_xmit_word_cnt;
	pfc_host_stat->invalid_crc_count = stats->inval_crc_cnt;
	if (IS_FWI2_CAPABLE(ha)) {
1062
		pfc_host_stat->lip_count = stats->lip_cnt;
1063 1064 1065 1066 1067
		pfc_host_stat->tx_frames = stats->tx_frames;
		pfc_host_stat->rx_frames = stats->rx_frames;
		pfc_host_stat->dumped_frames = stats->dumped_frames;
		pfc_host_stat->nos_count = stats->nos_rcvd;
	}
1068 1069
	pfc_host_stat->fcp_input_megabytes = ha->qla_stats.input_bytes >> 20;
	pfc_host_stat->fcp_output_megabytes = ha->qla_stats.output_bytes >> 20;
1070

1071 1072
done_free:
        dma_pool_free(ha->s_dma_pool, stats, stats_dma);
1073
done:
1074 1075 1076
	return pfc_host_stat;
}

1077 1078 1079
static void
qla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
{
A
Andrew Vasquez 已提交
1080
	scsi_qla_host_t *ha = shost_priv(shost);
1081 1082 1083 1084

	qla2x00_get_sym_node_name(ha, fc_host_symbolic_name(shost));
}

1085 1086 1087
static void
qla2x00_set_host_system_hostname(struct Scsi_Host *shost)
{
A
Andrew Vasquez 已提交
1088
	scsi_qla_host_t *ha = shost_priv(shost);
1089 1090 1091 1092

	set_bit(REGISTER_FDMI_NEEDED, &ha->dpc_flags);
}

1093 1094 1095
static void
qla2x00_get_host_fabric_name(struct Scsi_Host *shost)
{
A
Andrew Vasquez 已提交
1096
	scsi_qla_host_t *ha = shost_priv(shost);
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106
	u64 node_name;

	if (ha->device_flags & SWITCH_FOUND)
		node_name = wwn_to_u64(ha->fabric_node_name);
	else
		node_name = wwn_to_u64(ha->node_name);

	fc_host_fabric_name(shost) = node_name;
}

1107 1108 1109
static void
qla2x00_get_host_port_state(struct Scsi_Host *shost)
{
1110
	scsi_qla_host_t *ha = to_qla_parent(shost_priv(shost));
1111 1112 1113 1114 1115 1116 1117 1118 1119

	if (!ha->flags.online)
		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
	else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT)
		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
	else
		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
}

1120 1121 1122 1123
static int
qla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
{
	int	ret = 0;
A
Andrew Vasquez 已提交
1124
	scsi_qla_host_t *ha = shost_priv(fc_vport->shost);
1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189
	scsi_qla_host_t *vha;

	ret = qla24xx_vport_create_req_sanity_check(fc_vport);
	if (ret) {
		DEBUG15(printk("qla24xx_vport_create_req_sanity_check failed, "
		    "status %x\n", ret));
		return (ret);
	}

	vha = qla24xx_create_vhost(fc_vport);
	if (vha == NULL) {
		DEBUG15(printk ("qla24xx_create_vhost failed, vha = %p\n",
		    vha));
		return FC_VPORT_FAILED;
	}
	if (disable) {
		atomic_set(&vha->vp_state, VP_OFFLINE);
		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
	} else
		atomic_set(&vha->vp_state, VP_FAILED);

	/* ready to create vport */
	qla_printk(KERN_INFO, vha, "VP entry id %d assigned.\n", vha->vp_idx);

	/* initialized vport states */
	atomic_set(&vha->loop_state, LOOP_DOWN);
	vha->vp_err_state=  VP_ERR_PORTDWN;
	vha->vp_prev_err_state=  VP_ERR_UNKWN;
	/* Check if physical ha port is Up */
	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
	    atomic_read(&ha->loop_state) == LOOP_DEAD) {
		/* Don't retry or attempt login of this virtual port */
		DEBUG15(printk ("scsi(%ld): pport loop_state is not UP.\n",
		    vha->host_no));
		atomic_set(&vha->loop_state, LOOP_DEAD);
		if (!disable)
			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
	}

	if (scsi_add_host(vha->host, &fc_vport->dev)) {
		DEBUG15(printk("scsi(%ld): scsi_add_host failure for VP[%d].\n",
			vha->host_no, vha->vp_idx));
		goto vport_create_failed_2;
	}

	/* initialize attributes */
	fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
	fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
	fc_host_supported_classes(vha->host) =
		fc_host_supported_classes(ha->host);
	fc_host_supported_speeds(vha->host) =
		fc_host_supported_speeds(ha->host);

	qla24xx_vport_disable(fc_vport, disable);

	return 0;
vport_create_failed_2:
	qla24xx_disable_vp(vha);
	qla24xx_deallocate_vp_id(vha);
	kfree(vha->port_name);
	kfree(vha->node_name);
	scsi_host_put(vha->host);
	return FC_VPORT_FAILED;
}

A
Adrian Bunk 已提交
1190
static int
1191 1192 1193
qla24xx_vport_delete(struct fc_vport *fc_vport)
{
	scsi_qla_host_t *vha = fc_vport->dd_data;
1194 1195 1196 1197 1198
	scsi_qla_host_t *pha = to_qla_parent(vha);

	while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags) ||
	    test_bit(FCPORT_UPDATE_NEEDED, &pha->dpc_flags))
		msleep(1000);
1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221

	qla24xx_disable_vp(vha);
	qla24xx_deallocate_vp_id(vha);

	kfree(vha->node_name);
	kfree(vha->port_name);

	if (vha->timer_active) {
		qla2x00_vp_stop_timer(vha);
		DEBUG15(printk ("scsi(%ld): timer for the vport[%d] = %p "
		    "has stopped\n",
		    vha->host_no, vha->vp_idx, vha));
        }

	fc_remove_host(vha->host);

	scsi_remove_host(vha->host);

	scsi_host_put(vha->host);

	return 0;
}

A
Adrian Bunk 已提交
1222
static int
1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234
qla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
{
	scsi_qla_host_t *vha = fc_vport->dd_data;

	if (disable)
		qla24xx_disable_vp(vha);
	else
		qla24xx_enable_vp(vha);

	return 0;
}

1235
struct fc_function_template qla2xxx_transport_functions = {
已提交
1236 1237 1238

	.show_host_node_name = 1,
	.show_host_port_name = 1,
1239
	.show_host_supported_classes = 1,
1240
	.show_host_supported_speeds = 1,
1241

已提交
1242 1243
	.get_host_port_id = qla2x00_get_host_port_id,
	.show_host_port_id = 1,
1244 1245
	.get_host_speed = qla2x00_get_host_speed,
	.show_host_speed = 1,
1246 1247
	.get_host_port_type = qla2x00_get_host_port_type,
	.show_host_port_type = 1,
1248 1249
	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
	.show_host_symbolic_name = 1,
1250 1251
	.set_host_system_hostname = qla2x00_set_host_system_hostname,
	.show_host_system_hostname = 1,
1252 1253
	.get_host_fabric_name = qla2x00_get_host_fabric_name,
	.show_host_fabric_name = 1,
1254 1255
	.get_host_port_state = qla2x00_get_host_port_state,
	.show_host_port_state = 1,
已提交
1256

1257
	.dd_fcrport_size = sizeof(struct fc_port *),
1258
	.show_rport_supported_classes = 1,
已提交
1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269

	.get_starget_node_name = qla2x00_get_starget_node_name,
	.show_starget_node_name = 1,
	.get_starget_port_name = qla2x00_get_starget_port_name,
	.show_starget_port_name = 1,
	.get_starget_port_id  = qla2x00_get_starget_port_id,
	.show_starget_port_id = 1,

	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
	.show_rport_dev_loss_tmo = 1,

1270
	.issue_fc_host_lip = qla2x00_issue_lip,
1271 1272
	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
	.terminate_rport_io = qla2x00_terminate_rport_io,
1273
	.get_fc_host_stats = qla2x00_get_fc_host_stats,
1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314

	.vport_create = qla24xx_vport_create,
	.vport_disable = qla24xx_vport_disable,
	.vport_delete = qla24xx_vport_delete,
};

struct fc_function_template qla2xxx_transport_vport_functions = {

	.show_host_node_name = 1,
	.show_host_port_name = 1,
	.show_host_supported_classes = 1,

	.get_host_port_id = qla2x00_get_host_port_id,
	.show_host_port_id = 1,
	.get_host_speed = qla2x00_get_host_speed,
	.show_host_speed = 1,
	.get_host_port_type = qla2x00_get_host_port_type,
	.show_host_port_type = 1,
	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
	.show_host_symbolic_name = 1,
	.set_host_system_hostname = qla2x00_set_host_system_hostname,
	.show_host_system_hostname = 1,
	.get_host_fabric_name = qla2x00_get_host_fabric_name,
	.show_host_fabric_name = 1,
	.get_host_port_state = qla2x00_get_host_port_state,
	.show_host_port_state = 1,

	.dd_fcrport_size = sizeof(struct fc_port *),
	.show_rport_supported_classes = 1,

	.get_starget_node_name = qla2x00_get_starget_node_name,
	.show_starget_node_name = 1,
	.get_starget_port_name = qla2x00_get_starget_port_name,
	.show_starget_port_name = 1,
	.get_starget_port_id  = qla2x00_get_starget_port_id,
	.show_starget_port_id = 1,

	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
	.show_rport_dev_loss_tmo = 1,

	.issue_fc_host_lip = qla2x00_issue_lip,
1315 1316
	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
	.terminate_rport_io = qla2x00_terminate_rport_io,
1317
	.get_fc_host_stats = qla2x00_get_fc_host_stats,
已提交
1318 1319 1320 1321 1322
};

void
qla2x00_init_host_attr(scsi_qla_host_t *ha)
{
1323 1324
	u32 speed = FC_PORTSPEED_UNKNOWN;

1325 1326
	fc_host_node_name(ha->host) = wwn_to_u64(ha->node_name);
	fc_host_port_name(ha->host) = wwn_to_u64(ha->port_name);
1327
	fc_host_supported_classes(ha->host) = FC_COS_CLASS3;
1328
	fc_host_max_npiv_vports(ha->host) = ha->max_npiv_vports;;
1329
	fc_host_npiv_vports_inuse(ha->host) = ha->cur_vport_count;
1330 1331 1332 1333

	if (IS_QLA25XX(ha))
		speed = FC_PORTSPEED_8GBIT | FC_PORTSPEED_4GBIT |
		    FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
1334
	else if (IS_QLA24XX_TYPE(ha))
1335 1336 1337 1338 1339 1340 1341
		speed = FC_PORTSPEED_4GBIT | FC_PORTSPEED_2GBIT |
		    FC_PORTSPEED_1GBIT;
	else if (IS_QLA23XX(ha))
		speed = FC_PORTSPEED_2GBIT | FC_PORTSPEED_1GBIT;
	else
		speed = FC_PORTSPEED_1GBIT;
	fc_host_supported_speeds(ha->host) = speed;
已提交
1342
}