162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include "qla_target.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/kthread.h>
1062306a36Sopenharmony_ci#include <linux/vmalloc.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci#include <linux/delay.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_cistatic int qla24xx_vport_disable(struct fc_vport *, bool);
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci/* SYSFS attributes --------------------------------------------------------- */
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic ssize_t
1962306a36Sopenharmony_ciqla2x00_sysfs_read_fw_dump(struct file *filp, struct kobject *kobj,
2062306a36Sopenharmony_ci			   struct bin_attribute *bin_attr,
2162306a36Sopenharmony_ci			   char *buf, loff_t off, size_t count)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
2462306a36Sopenharmony_ci	    struct device, kobj)));
2562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
2662306a36Sopenharmony_ci	int rval = 0;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	if (!(ha->fw_dump_reading || ha->mctp_dump_reading ||
2962306a36Sopenharmony_ci	      ha->mpi_fw_dump_reading))
3062306a36Sopenharmony_ci		return 0;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
3362306a36Sopenharmony_ci	if (IS_P3P_TYPE(ha)) {
3462306a36Sopenharmony_ci		if (off < ha->md_template_size) {
3562306a36Sopenharmony_ci			rval = memory_read_from_buffer(buf, count,
3662306a36Sopenharmony_ci			    &off, ha->md_tmplt_hdr, ha->md_template_size);
3762306a36Sopenharmony_ci		} else {
3862306a36Sopenharmony_ci			off -= ha->md_template_size;
3962306a36Sopenharmony_ci			rval = memory_read_from_buffer(buf, count,
4062306a36Sopenharmony_ci			    &off, ha->md_dump, ha->md_dump_size);
4162306a36Sopenharmony_ci		}
4262306a36Sopenharmony_ci	} else if (ha->mctp_dumped && ha->mctp_dump_reading) {
4362306a36Sopenharmony_ci		rval = memory_read_from_buffer(buf, count, &off, ha->mctp_dump,
4462306a36Sopenharmony_ci		    MCTP_DUMP_SIZE);
4562306a36Sopenharmony_ci	} else if (ha->mpi_fw_dumped && ha->mpi_fw_dump_reading) {
4662306a36Sopenharmony_ci		rval = memory_read_from_buffer(buf, count, &off,
4762306a36Sopenharmony_ci					       ha->mpi_fw_dump,
4862306a36Sopenharmony_ci					       ha->mpi_fw_dump_len);
4962306a36Sopenharmony_ci	} else if (ha->fw_dump_reading) {
5062306a36Sopenharmony_ci		rval = memory_read_from_buffer(buf, count, &off, ha->fw_dump,
5162306a36Sopenharmony_ci					ha->fw_dump_len);
5262306a36Sopenharmony_ci	} else {
5362306a36Sopenharmony_ci		rval = 0;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
5662306a36Sopenharmony_ci	return rval;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cistatic ssize_t
6062306a36Sopenharmony_ciqla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj,
6162306a36Sopenharmony_ci			    struct bin_attribute *bin_attr,
6262306a36Sopenharmony_ci			    char *buf, loff_t off, size_t count)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
6562306a36Sopenharmony_ci	    struct device, kobj)));
6662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6762306a36Sopenharmony_ci	int reading;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (off != 0)
7062306a36Sopenharmony_ci		return (0);
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	reading = simple_strtol(buf, NULL, 10);
7362306a36Sopenharmony_ci	switch (reading) {
7462306a36Sopenharmony_ci	case 0:
7562306a36Sopenharmony_ci		if (!ha->fw_dump_reading)
7662306a36Sopenharmony_ci			break;
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x705d,
7962306a36Sopenharmony_ci		    "Firmware dump cleared on (%ld).\n", vha->host_no);
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha)) {
8262306a36Sopenharmony_ci			qla82xx_md_free(vha);
8362306a36Sopenharmony_ci			qla82xx_md_prep(vha);
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci		ha->fw_dump_reading = 0;
8662306a36Sopenharmony_ci		ha->fw_dumped = false;
8762306a36Sopenharmony_ci		break;
8862306a36Sopenharmony_ci	case 1:
8962306a36Sopenharmony_ci		if (ha->fw_dumped && !ha->fw_dump_reading) {
9062306a36Sopenharmony_ci			ha->fw_dump_reading = 1;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x705e,
9362306a36Sopenharmony_ci			    "Raw firmware dump ready for read on (%ld).\n",
9462306a36Sopenharmony_ci			    vha->host_no);
9562306a36Sopenharmony_ci		}
9662306a36Sopenharmony_ci		break;
9762306a36Sopenharmony_ci	case 2:
9862306a36Sopenharmony_ci		qla2x00_alloc_fw_dump(vha);
9962306a36Sopenharmony_ci		break;
10062306a36Sopenharmony_ci	case 3:
10162306a36Sopenharmony_ci		if (IS_QLA82XX(ha)) {
10262306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
10362306a36Sopenharmony_ci			qla82xx_set_reset_owner(vha);
10462306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
10562306a36Sopenharmony_ci		} else if (IS_QLA8044(ha)) {
10662306a36Sopenharmony_ci			qla8044_idc_lock(ha);
10762306a36Sopenharmony_ci			qla82xx_set_reset_owner(vha);
10862306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
10962306a36Sopenharmony_ci		} else {
11062306a36Sopenharmony_ci			qla2x00_system_error(vha);
11162306a36Sopenharmony_ci		}
11262306a36Sopenharmony_ci		break;
11362306a36Sopenharmony_ci	case 4:
11462306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha)) {
11562306a36Sopenharmony_ci			if (ha->md_tmplt_hdr)
11662306a36Sopenharmony_ci				ql_dbg(ql_dbg_user, vha, 0x705b,
11762306a36Sopenharmony_ci				    "MiniDump supported with this firmware.\n");
11862306a36Sopenharmony_ci			else
11962306a36Sopenharmony_ci				ql_dbg(ql_dbg_user, vha, 0x709d,
12062306a36Sopenharmony_ci				    "MiniDump not supported with this firmware.\n");
12162306a36Sopenharmony_ci		}
12262306a36Sopenharmony_ci		break;
12362306a36Sopenharmony_ci	case 5:
12462306a36Sopenharmony_ci		if (IS_P3P_TYPE(ha))
12562306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
12662306a36Sopenharmony_ci		break;
12762306a36Sopenharmony_ci	case 6:
12862306a36Sopenharmony_ci		if (!ha->mctp_dump_reading)
12962306a36Sopenharmony_ci			break;
13062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70c1,
13162306a36Sopenharmony_ci		    "MCTP dump cleared on (%ld).\n", vha->host_no);
13262306a36Sopenharmony_ci		ha->mctp_dump_reading = 0;
13362306a36Sopenharmony_ci		ha->mctp_dumped = 0;
13462306a36Sopenharmony_ci		break;
13562306a36Sopenharmony_ci	case 7:
13662306a36Sopenharmony_ci		if (ha->mctp_dumped && !ha->mctp_dump_reading) {
13762306a36Sopenharmony_ci			ha->mctp_dump_reading = 1;
13862306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x70c2,
13962306a36Sopenharmony_ci			    "Raw mctp dump ready for read on (%ld).\n",
14062306a36Sopenharmony_ci			    vha->host_no);
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci		break;
14362306a36Sopenharmony_ci	case 8:
14462306a36Sopenharmony_ci		if (!ha->mpi_fw_dump_reading)
14562306a36Sopenharmony_ci			break;
14662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70e7,
14762306a36Sopenharmony_ci		       "MPI firmware dump cleared on (%ld).\n", vha->host_no);
14862306a36Sopenharmony_ci		ha->mpi_fw_dump_reading = 0;
14962306a36Sopenharmony_ci		ha->mpi_fw_dumped = 0;
15062306a36Sopenharmony_ci		break;
15162306a36Sopenharmony_ci	case 9:
15262306a36Sopenharmony_ci		if (ha->mpi_fw_dumped && !ha->mpi_fw_dump_reading) {
15362306a36Sopenharmony_ci			ha->mpi_fw_dump_reading = 1;
15462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x70e8,
15562306a36Sopenharmony_ci			       "Raw MPI firmware dump ready for read on (%ld).\n",
15662306a36Sopenharmony_ci			       vha->host_no);
15762306a36Sopenharmony_ci		}
15862306a36Sopenharmony_ci		break;
15962306a36Sopenharmony_ci	case 10:
16062306a36Sopenharmony_ci		if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
16162306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x70e9,
16262306a36Sopenharmony_ci			       "Issuing MPI firmware dump on host#%ld.\n",
16362306a36Sopenharmony_ci			       vha->host_no);
16462306a36Sopenharmony_ci			ha->isp_ops->mpi_fw_dump(vha, 0);
16562306a36Sopenharmony_ci		}
16662306a36Sopenharmony_ci		break;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci	return count;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic struct bin_attribute sysfs_fw_dump_attr = {
17262306a36Sopenharmony_ci	.attr = {
17362306a36Sopenharmony_ci		.name = "fw_dump",
17462306a36Sopenharmony_ci		.mode = S_IRUSR | S_IWUSR,
17562306a36Sopenharmony_ci	},
17662306a36Sopenharmony_ci	.size = 0,
17762306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_fw_dump,
17862306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_fw_dump,
17962306a36Sopenharmony_ci};
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_cistatic ssize_t
18262306a36Sopenharmony_ciqla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj,
18362306a36Sopenharmony_ci			 struct bin_attribute *bin_attr,
18462306a36Sopenharmony_ci			 char *buf, loff_t off, size_t count)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
18762306a36Sopenharmony_ci	    struct device, kobj)));
18862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
18962306a36Sopenharmony_ci	uint32_t faddr;
19062306a36Sopenharmony_ci	struct active_regions active_regions = { };
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
19362306a36Sopenharmony_ci		return 0;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
19662306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
19762306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
19862306a36Sopenharmony_ci		return -EAGAIN;
19962306a36Sopenharmony_ci	}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (!IS_NOCACHE_VPD_TYPE(ha)) {
20262306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
20362306a36Sopenharmony_ci		goto skip;
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	faddr = ha->flt_region_nvram;
20762306a36Sopenharmony_ci	if (IS_QLA28XX(ha)) {
20862306a36Sopenharmony_ci		qla28xx_get_aux_images(vha, &active_regions);
20962306a36Sopenharmony_ci		if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
21062306a36Sopenharmony_ci			faddr = ha->flt_region_nvram_sec;
21162306a36Sopenharmony_ci	}
21262306a36Sopenharmony_ci	ha->isp_ops->read_optrom(vha, ha->nvram, faddr << 2, ha->nvram_size);
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ciskip:
21762306a36Sopenharmony_ci	return memory_read_from_buffer(buf, count, &off, ha->nvram,
21862306a36Sopenharmony_ci					ha->nvram_size);
21962306a36Sopenharmony_ci}
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_cistatic ssize_t
22262306a36Sopenharmony_ciqla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj,
22362306a36Sopenharmony_ci			  struct bin_attribute *bin_attr,
22462306a36Sopenharmony_ci			  char *buf, loff_t off, size_t count)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
22762306a36Sopenharmony_ci	    struct device, kobj)));
22862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
22962306a36Sopenharmony_ci	uint16_t	cnt;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->nvram_size ||
23262306a36Sopenharmony_ci	    !ha->isp_ops->write_nvram)
23362306a36Sopenharmony_ci		return -EINVAL;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	/* Checksum NVRAM. */
23662306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
23762306a36Sopenharmony_ci		__le32 *iter = (__force __le32 *)buf;
23862306a36Sopenharmony_ci		uint32_t chksum;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci		chksum = 0;
24162306a36Sopenharmony_ci		for (cnt = 0; cnt < ((count >> 2) - 1); cnt++, iter++)
24262306a36Sopenharmony_ci			chksum += le32_to_cpu(*iter);
24362306a36Sopenharmony_ci		chksum = ~chksum + 1;
24462306a36Sopenharmony_ci		*iter = cpu_to_le32(chksum);
24562306a36Sopenharmony_ci	} else {
24662306a36Sopenharmony_ci		uint8_t *iter;
24762306a36Sopenharmony_ci		uint8_t chksum;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci		iter = (uint8_t *)buf;
25062306a36Sopenharmony_ci		chksum = 0;
25162306a36Sopenharmony_ci		for (cnt = 0; cnt < count - 1; cnt++)
25262306a36Sopenharmony_ci			chksum += *iter++;
25362306a36Sopenharmony_ci		chksum = ~chksum + 1;
25462306a36Sopenharmony_ci		*iter = chksum;
25562306a36Sopenharmony_ci	}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_ci	if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
25862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x705f,
25962306a36Sopenharmony_ci		    "HBA not online, failing NVRAM update.\n");
26062306a36Sopenharmony_ci		return -EAGAIN;
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci
26362306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
26462306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
26562306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
26662306a36Sopenharmony_ci		return -EAGAIN;
26762306a36Sopenharmony_ci	}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	/* Write NVRAM. */
27062306a36Sopenharmony_ci	ha->isp_ops->write_nvram(vha, buf, ha->nvram_base, count);
27162306a36Sopenharmony_ci	ha->isp_ops->read_nvram(vha, ha->nvram, ha->nvram_base,
27262306a36Sopenharmony_ci	    count);
27362306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0x7060,
27662306a36Sopenharmony_ci	    "Setting ISP_ABORT_NEEDED\n");
27762306a36Sopenharmony_ci	/* NVRAM settings take effect immediately. */
27862306a36Sopenharmony_ci	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
27962306a36Sopenharmony_ci	qla2xxx_wake_dpc(vha);
28062306a36Sopenharmony_ci	qla2x00_wait_for_chip_reset(vha);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	return count;
28362306a36Sopenharmony_ci}
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_cistatic struct bin_attribute sysfs_nvram_attr = {
28662306a36Sopenharmony_ci	.attr = {
28762306a36Sopenharmony_ci		.name = "nvram",
28862306a36Sopenharmony_ci		.mode = S_IRUSR | S_IWUSR,
28962306a36Sopenharmony_ci	},
29062306a36Sopenharmony_ci	.size = 512,
29162306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_nvram,
29262306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_nvram,
29362306a36Sopenharmony_ci};
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_cistatic ssize_t
29662306a36Sopenharmony_ciqla2x00_sysfs_read_optrom(struct file *filp, struct kobject *kobj,
29762306a36Sopenharmony_ci			  struct bin_attribute *bin_attr,
29862306a36Sopenharmony_ci			  char *buf, loff_t off, size_t count)
29962306a36Sopenharmony_ci{
30062306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
30162306a36Sopenharmony_ci	    struct device, kobj)));
30262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
30362306a36Sopenharmony_ci	ssize_t rval = 0;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	if (ha->optrom_state != QLA_SREADING)
30862306a36Sopenharmony_ci		goto out;
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	rval = memory_read_from_buffer(buf, count, &off, ha->optrom_buffer,
31162306a36Sopenharmony_ci	    ha->optrom_region_size);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ciout:
31462306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	return rval;
31762306a36Sopenharmony_ci}
31862306a36Sopenharmony_ci
31962306a36Sopenharmony_cistatic ssize_t
32062306a36Sopenharmony_ciqla2x00_sysfs_write_optrom(struct file *filp, struct kobject *kobj,
32162306a36Sopenharmony_ci			   struct bin_attribute *bin_attr,
32262306a36Sopenharmony_ci			   char *buf, loff_t off, size_t count)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
32562306a36Sopenharmony_ci	    struct device, kobj)));
32662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (ha->optrom_state != QLA_SWRITING) {
33162306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
33262306a36Sopenharmony_ci		return -EINVAL;
33362306a36Sopenharmony_ci	}
33462306a36Sopenharmony_ci	if (off > ha->optrom_region_size) {
33562306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
33662306a36Sopenharmony_ci		return -ERANGE;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci	if (off + count > ha->optrom_region_size)
33962306a36Sopenharmony_ci		count = ha->optrom_region_size - off;
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci	memcpy(&ha->optrom_buffer[off], buf, count);
34262306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	return count;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic struct bin_attribute sysfs_optrom_attr = {
34862306a36Sopenharmony_ci	.attr = {
34962306a36Sopenharmony_ci		.name = "optrom",
35062306a36Sopenharmony_ci		.mode = S_IRUSR | S_IWUSR,
35162306a36Sopenharmony_ci	},
35262306a36Sopenharmony_ci	.size = 0,
35362306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_optrom,
35462306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_optrom,
35562306a36Sopenharmony_ci};
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic ssize_t
35862306a36Sopenharmony_ciqla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj,
35962306a36Sopenharmony_ci			       struct bin_attribute *bin_attr,
36062306a36Sopenharmony_ci			       char *buf, loff_t off, size_t count)
36162306a36Sopenharmony_ci{
36262306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
36362306a36Sopenharmony_ci	    struct device, kobj)));
36462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
36562306a36Sopenharmony_ci	uint32_t start = 0;
36662306a36Sopenharmony_ci	uint32_t size = ha->optrom_size;
36762306a36Sopenharmony_ci	int val, valid;
36862306a36Sopenharmony_ci	ssize_t rval = count;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	if (off)
37162306a36Sopenharmony_ci		return -EINVAL;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
37462306a36Sopenharmony_ci		return -EAGAIN;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (sscanf(buf, "%d:%x:%x", &val, &start, &size) < 1)
37762306a36Sopenharmony_ci		return -EINVAL;
37862306a36Sopenharmony_ci	if (start > ha->optrom_size)
37962306a36Sopenharmony_ci		return -EINVAL;
38062306a36Sopenharmony_ci	if (size > ha->optrom_size - start)
38162306a36Sopenharmony_ci		size = ha->optrom_size - start;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
38462306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
38562306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
38662306a36Sopenharmony_ci		return -EAGAIN;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci	switch (val) {
38962306a36Sopenharmony_ci	case 0:
39062306a36Sopenharmony_ci		if (ha->optrom_state != QLA_SREADING &&
39162306a36Sopenharmony_ci		    ha->optrom_state != QLA_SWRITING) {
39262306a36Sopenharmony_ci			rval =  -EINVAL;
39362306a36Sopenharmony_ci			goto out;
39462306a36Sopenharmony_ci		}
39562306a36Sopenharmony_ci		ha->optrom_state = QLA_SWAITING;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7061,
39862306a36Sopenharmony_ci		    "Freeing flash region allocation -- 0x%x bytes.\n",
39962306a36Sopenharmony_ci		    ha->optrom_region_size);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci		vfree(ha->optrom_buffer);
40262306a36Sopenharmony_ci		ha->optrom_buffer = NULL;
40362306a36Sopenharmony_ci		break;
40462306a36Sopenharmony_ci	case 1:
40562306a36Sopenharmony_ci		if (ha->optrom_state != QLA_SWAITING) {
40662306a36Sopenharmony_ci			rval = -EINVAL;
40762306a36Sopenharmony_ci			goto out;
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		ha->optrom_region_start = start;
41162306a36Sopenharmony_ci		ha->optrom_region_size = size;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci		ha->optrom_state = QLA_SREADING;
41462306a36Sopenharmony_ci		ha->optrom_buffer = vzalloc(ha->optrom_region_size);
41562306a36Sopenharmony_ci		if (ha->optrom_buffer == NULL) {
41662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7062,
41762306a36Sopenharmony_ci			    "Unable to allocate memory for optrom retrieval "
41862306a36Sopenharmony_ci			    "(%x).\n", ha->optrom_region_size);
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_ci			ha->optrom_state = QLA_SWAITING;
42162306a36Sopenharmony_ci			rval = -ENOMEM;
42262306a36Sopenharmony_ci			goto out;
42362306a36Sopenharmony_ci		}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
42662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7063,
42762306a36Sopenharmony_ci			    "HBA not online, failing NVRAM update.\n");
42862306a36Sopenharmony_ci			rval = -EAGAIN;
42962306a36Sopenharmony_ci			goto out;
43062306a36Sopenharmony_ci		}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7064,
43362306a36Sopenharmony_ci		    "Reading flash region -- 0x%x/0x%x.\n",
43462306a36Sopenharmony_ci		    ha->optrom_region_start, ha->optrom_region_size);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci		ha->isp_ops->read_optrom(vha, ha->optrom_buffer,
43762306a36Sopenharmony_ci		    ha->optrom_region_start, ha->optrom_region_size);
43862306a36Sopenharmony_ci		break;
43962306a36Sopenharmony_ci	case 2:
44062306a36Sopenharmony_ci		if (ha->optrom_state != QLA_SWAITING) {
44162306a36Sopenharmony_ci			rval = -EINVAL;
44262306a36Sopenharmony_ci			goto out;
44362306a36Sopenharmony_ci		}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci		/*
44662306a36Sopenharmony_ci		 * We need to be more restrictive on which FLASH regions are
44762306a36Sopenharmony_ci		 * allowed to be updated via user-space.  Regions accessible
44862306a36Sopenharmony_ci		 * via this method include:
44962306a36Sopenharmony_ci		 *
45062306a36Sopenharmony_ci		 * ISP21xx/ISP22xx/ISP23xx type boards:
45162306a36Sopenharmony_ci		 *
45262306a36Sopenharmony_ci		 * 	0x000000 -> 0x020000 -- Boot code.
45362306a36Sopenharmony_ci		 *
45462306a36Sopenharmony_ci		 * ISP2322/ISP24xx type boards:
45562306a36Sopenharmony_ci		 *
45662306a36Sopenharmony_ci		 * 	0x000000 -> 0x07ffff -- Boot code.
45762306a36Sopenharmony_ci		 * 	0x080000 -> 0x0fffff -- Firmware.
45862306a36Sopenharmony_ci		 *
45962306a36Sopenharmony_ci		 * ISP25xx type boards:
46062306a36Sopenharmony_ci		 *
46162306a36Sopenharmony_ci		 * 	0x000000 -> 0x07ffff -- Boot code.
46262306a36Sopenharmony_ci		 * 	0x080000 -> 0x0fffff -- Firmware.
46362306a36Sopenharmony_ci		 * 	0x120000 -> 0x12ffff -- VPD and HBA parameters.
46462306a36Sopenharmony_ci		 *
46562306a36Sopenharmony_ci		 * > ISP25xx type boards:
46662306a36Sopenharmony_ci		 *
46762306a36Sopenharmony_ci		 *      None -- should go through BSG.
46862306a36Sopenharmony_ci		 */
46962306a36Sopenharmony_ci		valid = 0;
47062306a36Sopenharmony_ci		if (ha->optrom_size == OPTROM_SIZE_2300 && start == 0)
47162306a36Sopenharmony_ci			valid = 1;
47262306a36Sopenharmony_ci		else if (IS_QLA24XX_TYPE(ha) || IS_QLA25XX(ha))
47362306a36Sopenharmony_ci			valid = 1;
47462306a36Sopenharmony_ci		if (!valid) {
47562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7065,
47662306a36Sopenharmony_ci			    "Invalid start region 0x%x/0x%x.\n", start, size);
47762306a36Sopenharmony_ci			rval = -EINVAL;
47862306a36Sopenharmony_ci			goto out;
47962306a36Sopenharmony_ci		}
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci		ha->optrom_region_start = start;
48262306a36Sopenharmony_ci		ha->optrom_region_size = size;
48362306a36Sopenharmony_ci
48462306a36Sopenharmony_ci		ha->optrom_state = QLA_SWRITING;
48562306a36Sopenharmony_ci		ha->optrom_buffer = vzalloc(ha->optrom_region_size);
48662306a36Sopenharmony_ci		if (ha->optrom_buffer == NULL) {
48762306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7066,
48862306a36Sopenharmony_ci			    "Unable to allocate memory for optrom update "
48962306a36Sopenharmony_ci			    "(%x)\n", ha->optrom_region_size);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci			ha->optrom_state = QLA_SWAITING;
49262306a36Sopenharmony_ci			rval = -ENOMEM;
49362306a36Sopenharmony_ci			goto out;
49462306a36Sopenharmony_ci		}
49562306a36Sopenharmony_ci
49662306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7067,
49762306a36Sopenharmony_ci		    "Staging flash region write -- 0x%x/0x%x.\n",
49862306a36Sopenharmony_ci		    ha->optrom_region_start, ha->optrom_region_size);
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci		break;
50162306a36Sopenharmony_ci	case 3:
50262306a36Sopenharmony_ci		if (ha->optrom_state != QLA_SWRITING) {
50362306a36Sopenharmony_ci			rval = -EINVAL;
50462306a36Sopenharmony_ci			goto out;
50562306a36Sopenharmony_ci		}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci		if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
50862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7068,
50962306a36Sopenharmony_ci			    "HBA not online, failing flash update.\n");
51062306a36Sopenharmony_ci			rval = -EAGAIN;
51162306a36Sopenharmony_ci			goto out;
51262306a36Sopenharmony_ci		}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7069,
51562306a36Sopenharmony_ci		    "Writing flash region -- 0x%x/0x%x.\n",
51662306a36Sopenharmony_ci		    ha->optrom_region_start, ha->optrom_region_size);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci		rval = ha->isp_ops->write_optrom(vha, ha->optrom_buffer,
51962306a36Sopenharmony_ci		    ha->optrom_region_start, ha->optrom_region_size);
52062306a36Sopenharmony_ci		if (rval)
52162306a36Sopenharmony_ci			rval = -EIO;
52262306a36Sopenharmony_ci		break;
52362306a36Sopenharmony_ci	default:
52462306a36Sopenharmony_ci		rval = -EINVAL;
52562306a36Sopenharmony_ci	}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ciout:
52862306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
52962306a36Sopenharmony_ci	return rval;
53062306a36Sopenharmony_ci}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_cistatic struct bin_attribute sysfs_optrom_ctl_attr = {
53362306a36Sopenharmony_ci	.attr = {
53462306a36Sopenharmony_ci		.name = "optrom_ctl",
53562306a36Sopenharmony_ci		.mode = S_IWUSR,
53662306a36Sopenharmony_ci	},
53762306a36Sopenharmony_ci	.size = 0,
53862306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_optrom_ctl,
53962306a36Sopenharmony_ci};
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_cistatic ssize_t
54262306a36Sopenharmony_ciqla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj,
54362306a36Sopenharmony_ci		       struct bin_attribute *bin_attr,
54462306a36Sopenharmony_ci		       char *buf, loff_t off, size_t count)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
54762306a36Sopenharmony_ci	    struct device, kobj)));
54862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
54962306a36Sopenharmony_ci	uint32_t faddr;
55062306a36Sopenharmony_ci	struct active_regions active_regions = { };
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
55362306a36Sopenharmony_ci		return -EAGAIN;
55462306a36Sopenharmony_ci
55562306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
55662306a36Sopenharmony_ci		return -EINVAL;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	if (!IS_NOCACHE_VPD_TYPE(ha))
55962306a36Sopenharmony_ci		goto skip;
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	faddr = ha->flt_region_vpd << 2;
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	if (IS_QLA28XX(ha)) {
56462306a36Sopenharmony_ci		qla28xx_get_aux_images(vha, &active_regions);
56562306a36Sopenharmony_ci		if (active_regions.aux.vpd_nvram == QLA27XX_SECONDARY_IMAGE)
56662306a36Sopenharmony_ci			faddr = ha->flt_region_vpd_sec << 2;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		ql_dbg(ql_dbg_init, vha, 0x7070,
56962306a36Sopenharmony_ci		    "Loading %s nvram image.\n",
57062306a36Sopenharmony_ci		    active_regions.aux.vpd_nvram == QLA27XX_PRIMARY_IMAGE ?
57162306a36Sopenharmony_ci		    "primary" : "secondary");
57262306a36Sopenharmony_ci	}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
57562306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
57662306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
57762306a36Sopenharmony_ci		return -EAGAIN;
57862306a36Sopenharmony_ci	}
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
58162306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size);
58462306a36Sopenharmony_ciskip:
58562306a36Sopenharmony_ci	return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size);
58662306a36Sopenharmony_ci}
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_cistatic ssize_t
58962306a36Sopenharmony_ciqla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj,
59062306a36Sopenharmony_ci			struct bin_attribute *bin_attr,
59162306a36Sopenharmony_ci			char *buf, loff_t off, size_t count)
59262306a36Sopenharmony_ci{
59362306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
59462306a36Sopenharmony_ci	    struct device, kobj)));
59562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
59662306a36Sopenharmony_ci	uint8_t *tmp_data;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
59962306a36Sopenharmony_ci		return 0;
60062306a36Sopenharmony_ci
60162306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha))
60262306a36Sopenharmony_ci		return 0;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size ||
60562306a36Sopenharmony_ci	    !ha->isp_ops->write_nvram)
60662306a36Sopenharmony_ci		return 0;
60762306a36Sopenharmony_ci
60862306a36Sopenharmony_ci	if (qla2x00_wait_for_hba_online(vha) != QLA_SUCCESS) {
60962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x706a,
61062306a36Sopenharmony_ci		    "HBA not online, failing VPD update.\n");
61162306a36Sopenharmony_ci		return -EAGAIN;
61262306a36Sopenharmony_ci	}
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	mutex_lock(&ha->optrom_mutex);
61562306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
61662306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
61762306a36Sopenharmony_ci		return -EAGAIN;
61862306a36Sopenharmony_ci	}
61962306a36Sopenharmony_ci
62062306a36Sopenharmony_ci	/* Write NVRAM. */
62162306a36Sopenharmony_ci	ha->isp_ops->write_nvram(vha, buf, ha->vpd_base, count);
62262306a36Sopenharmony_ci	ha->isp_ops->read_nvram(vha, ha->vpd, ha->vpd_base, count);
62362306a36Sopenharmony_ci
62462306a36Sopenharmony_ci	/* Update flash version information for 4Gb & above. */
62562306a36Sopenharmony_ci	if (!IS_FWI2_CAPABLE(ha)) {
62662306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
62762306a36Sopenharmony_ci		return -EINVAL;
62862306a36Sopenharmony_ci	}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_ci	tmp_data = vmalloc(256);
63162306a36Sopenharmony_ci	if (!tmp_data) {
63262306a36Sopenharmony_ci		mutex_unlock(&ha->optrom_mutex);
63362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x706b,
63462306a36Sopenharmony_ci		    "Unable to allocate memory for VPD information update.\n");
63562306a36Sopenharmony_ci		return -ENOMEM;
63662306a36Sopenharmony_ci	}
63762306a36Sopenharmony_ci	ha->isp_ops->get_flash_version(vha, tmp_data);
63862306a36Sopenharmony_ci	vfree(tmp_data);
63962306a36Sopenharmony_ci
64062306a36Sopenharmony_ci	mutex_unlock(&ha->optrom_mutex);
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	return count;
64362306a36Sopenharmony_ci}
64462306a36Sopenharmony_ci
64562306a36Sopenharmony_cistatic struct bin_attribute sysfs_vpd_attr = {
64662306a36Sopenharmony_ci	.attr = {
64762306a36Sopenharmony_ci		.name = "vpd",
64862306a36Sopenharmony_ci		.mode = S_IRUSR | S_IWUSR,
64962306a36Sopenharmony_ci	},
65062306a36Sopenharmony_ci	.size = 0,
65162306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_vpd,
65262306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_vpd,
65362306a36Sopenharmony_ci};
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_cistatic ssize_t
65662306a36Sopenharmony_ciqla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj,
65762306a36Sopenharmony_ci		       struct bin_attribute *bin_attr,
65862306a36Sopenharmony_ci		       char *buf, loff_t off, size_t count)
65962306a36Sopenharmony_ci{
66062306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
66162306a36Sopenharmony_ci	    struct device, kobj)));
66262306a36Sopenharmony_ci	int rval;
66362306a36Sopenharmony_ci
66462306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE)
66562306a36Sopenharmony_ci		return 0;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
66862306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
66962306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
67062306a36Sopenharmony_ci		return 0;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	rval = qla2x00_read_sfp_dev(vha, buf, count);
67462306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	if (rval)
67762306a36Sopenharmony_ci		return -EIO;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	return count;
68062306a36Sopenharmony_ci}
68162306a36Sopenharmony_ci
68262306a36Sopenharmony_cistatic struct bin_attribute sysfs_sfp_attr = {
68362306a36Sopenharmony_ci	.attr = {
68462306a36Sopenharmony_ci		.name = "sfp",
68562306a36Sopenharmony_ci		.mode = S_IRUSR | S_IWUSR,
68662306a36Sopenharmony_ci	},
68762306a36Sopenharmony_ci	.size = SFP_DEV_SIZE,
68862306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_sfp,
68962306a36Sopenharmony_ci};
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_cistatic ssize_t
69262306a36Sopenharmony_ciqla2x00_sysfs_write_reset(struct file *filp, struct kobject *kobj,
69362306a36Sopenharmony_ci			struct bin_attribute *bin_attr,
69462306a36Sopenharmony_ci			char *buf, loff_t off, size_t count)
69562306a36Sopenharmony_ci{
69662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
69762306a36Sopenharmony_ci	    struct device, kobj)));
69862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
69962306a36Sopenharmony_ci	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
70062306a36Sopenharmony_ci	int type;
70162306a36Sopenharmony_ci	uint32_t idc_control;
70262306a36Sopenharmony_ci	uint8_t *tmp_data = NULL;
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	if (off != 0)
70562306a36Sopenharmony_ci		return -EINVAL;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	type = simple_strtol(buf, NULL, 10);
70862306a36Sopenharmony_ci	switch (type) {
70962306a36Sopenharmony_ci	case 0x2025c:
71062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x706e,
71162306a36Sopenharmony_ci		    "Issuing ISP reset.\n");
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci		if (vha->hw->flags.port_isolated) {
71462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x706e,
71562306a36Sopenharmony_ci			       "Port is isolated, returning.\n");
71662306a36Sopenharmony_ci			return -EINVAL;
71762306a36Sopenharmony_ci		}
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci		scsi_block_requests(vha->host);
72062306a36Sopenharmony_ci		if (IS_QLA82XX(ha)) {
72162306a36Sopenharmony_ci			ha->flags.isp82xx_no_md_cap = 1;
72262306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
72362306a36Sopenharmony_ci			qla82xx_set_reset_owner(vha);
72462306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
72562306a36Sopenharmony_ci		} else if (IS_QLA8044(ha)) {
72662306a36Sopenharmony_ci			qla8044_idc_lock(ha);
72762306a36Sopenharmony_ci			idc_control = qla8044_rd_reg(ha,
72862306a36Sopenharmony_ci			    QLA8044_IDC_DRV_CTRL);
72962306a36Sopenharmony_ci			qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
73062306a36Sopenharmony_ci			    (idc_control | GRACEFUL_RESET_BIT1));
73162306a36Sopenharmony_ci			qla82xx_set_reset_owner(vha);
73262306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
73362306a36Sopenharmony_ci		} else {
73462306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
73562306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
73662306a36Sopenharmony_ci		}
73762306a36Sopenharmony_ci		qla2x00_wait_for_chip_reset(vha);
73862306a36Sopenharmony_ci		scsi_unblock_requests(vha->host);
73962306a36Sopenharmony_ci		break;
74062306a36Sopenharmony_ci	case 0x2025d:
74162306a36Sopenharmony_ci		if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
74262306a36Sopenharmony_ci		    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
74362306a36Sopenharmony_ci			return -EPERM;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x706f,
74662306a36Sopenharmony_ci		    "Issuing MPI reset.\n");
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci		if (IS_QLA83XX(ha)) {
74962306a36Sopenharmony_ci			uint32_t idc_control;
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci			qla83xx_idc_lock(vha, 0);
75262306a36Sopenharmony_ci			__qla83xx_get_idc_control(vha, &idc_control);
75362306a36Sopenharmony_ci			idc_control |= QLA83XX_IDC_GRACEFUL_RESET;
75462306a36Sopenharmony_ci			__qla83xx_set_idc_control(vha, idc_control);
75562306a36Sopenharmony_ci			qla83xx_wr_reg(vha, QLA83XX_IDC_DEV_STATE,
75662306a36Sopenharmony_ci			    QLA8XXX_DEV_NEED_RESET);
75762306a36Sopenharmony_ci			qla83xx_idc_audit(vha, IDC_AUDIT_TIMESTAMP);
75862306a36Sopenharmony_ci			qla83xx_idc_unlock(vha, 0);
75962306a36Sopenharmony_ci			break;
76062306a36Sopenharmony_ci		} else {
76162306a36Sopenharmony_ci			/* Make sure FC side is not in reset */
76262306a36Sopenharmony_ci			WARN_ON_ONCE(qla2x00_wait_for_hba_online(vha) !=
76362306a36Sopenharmony_ci				     QLA_SUCCESS);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci			/* Issue MPI reset */
76662306a36Sopenharmony_ci			scsi_block_requests(vha->host);
76762306a36Sopenharmony_ci			if (qla81xx_restart_mpi_firmware(vha) != QLA_SUCCESS)
76862306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x7070,
76962306a36Sopenharmony_ci				    "MPI reset failed.\n");
77062306a36Sopenharmony_ci			scsi_unblock_requests(vha->host);
77162306a36Sopenharmony_ci			break;
77262306a36Sopenharmony_ci		}
77362306a36Sopenharmony_ci		break;
77462306a36Sopenharmony_ci	case 0x2025e:
77562306a36Sopenharmony_ci		if (!IS_P3P_TYPE(ha) || vha != base_vha) {
77662306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x7071,
77762306a36Sopenharmony_ci			    "FCoE ctx reset not supported.\n");
77862306a36Sopenharmony_ci			return -EPERM;
77962306a36Sopenharmony_ci		}
78062306a36Sopenharmony_ci
78162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x7072,
78262306a36Sopenharmony_ci		    "Issuing FCoE ctx reset.\n");
78362306a36Sopenharmony_ci		set_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags);
78462306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
78562306a36Sopenharmony_ci		qla2x00_wait_for_fcoe_ctx_reset(vha);
78662306a36Sopenharmony_ci		break;
78762306a36Sopenharmony_ci	case 0x2025f:
78862306a36Sopenharmony_ci		if (!IS_QLA8031(ha))
78962306a36Sopenharmony_ci			return -EPERM;
79062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70bc,
79162306a36Sopenharmony_ci		    "Disabling Reset by IDC control\n");
79262306a36Sopenharmony_ci		qla83xx_idc_lock(vha, 0);
79362306a36Sopenharmony_ci		__qla83xx_get_idc_control(vha, &idc_control);
79462306a36Sopenharmony_ci		idc_control |= QLA83XX_IDC_RESET_DISABLED;
79562306a36Sopenharmony_ci		__qla83xx_set_idc_control(vha, idc_control);
79662306a36Sopenharmony_ci		qla83xx_idc_unlock(vha, 0);
79762306a36Sopenharmony_ci		break;
79862306a36Sopenharmony_ci	case 0x20260:
79962306a36Sopenharmony_ci		if (!IS_QLA8031(ha))
80062306a36Sopenharmony_ci			return -EPERM;
80162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x70bd,
80262306a36Sopenharmony_ci		    "Enabling Reset by IDC control\n");
80362306a36Sopenharmony_ci		qla83xx_idc_lock(vha, 0);
80462306a36Sopenharmony_ci		__qla83xx_get_idc_control(vha, &idc_control);
80562306a36Sopenharmony_ci		idc_control &= ~QLA83XX_IDC_RESET_DISABLED;
80662306a36Sopenharmony_ci		__qla83xx_set_idc_control(vha, idc_control);
80762306a36Sopenharmony_ci		qla83xx_idc_unlock(vha, 0);
80862306a36Sopenharmony_ci		break;
80962306a36Sopenharmony_ci	case 0x20261:
81062306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70e0,
81162306a36Sopenharmony_ci		    "Updating cache versions without reset ");
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_ci		tmp_data = vmalloc(256);
81462306a36Sopenharmony_ci		if (!tmp_data) {
81562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70e1,
81662306a36Sopenharmony_ci			    "Unable to allocate memory for VPD information update.\n");
81762306a36Sopenharmony_ci			return -ENOMEM;
81862306a36Sopenharmony_ci		}
81962306a36Sopenharmony_ci		ha->isp_ops->get_flash_version(vha, tmp_data);
82062306a36Sopenharmony_ci		vfree(tmp_data);
82162306a36Sopenharmony_ci		break;
82262306a36Sopenharmony_ci	}
82362306a36Sopenharmony_ci	return count;
82462306a36Sopenharmony_ci}
82562306a36Sopenharmony_ci
82662306a36Sopenharmony_cistatic struct bin_attribute sysfs_reset_attr = {
82762306a36Sopenharmony_ci	.attr = {
82862306a36Sopenharmony_ci		.name = "reset",
82962306a36Sopenharmony_ci		.mode = S_IWUSR,
83062306a36Sopenharmony_ci	},
83162306a36Sopenharmony_ci	.size = 0,
83262306a36Sopenharmony_ci	.write = qla2x00_sysfs_write_reset,
83362306a36Sopenharmony_ci};
83462306a36Sopenharmony_ci
83562306a36Sopenharmony_cistatic ssize_t
83662306a36Sopenharmony_ciqla2x00_issue_logo(struct file *filp, struct kobject *kobj,
83762306a36Sopenharmony_ci			struct bin_attribute *bin_attr,
83862306a36Sopenharmony_ci			char *buf, loff_t off, size_t count)
83962306a36Sopenharmony_ci{
84062306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
84162306a36Sopenharmony_ci	    struct device, kobj)));
84262306a36Sopenharmony_ci	int type;
84362306a36Sopenharmony_ci	port_id_t did;
84462306a36Sopenharmony_ci
84562306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
84662306a36Sopenharmony_ci		return 0;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(vha->hw->pdev)))
84962306a36Sopenharmony_ci		return 0;
85062306a36Sopenharmony_ci
85162306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha))
85262306a36Sopenharmony_ci		return 0;
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	type = simple_strtol(buf, NULL, 10);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	did.b.domain = (type & 0x00ff0000) >> 16;
85762306a36Sopenharmony_ci	did.b.area = (type & 0x0000ff00) >> 8;
85862306a36Sopenharmony_ci	did.b.al_pa = (type & 0x000000ff);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xd04d, "portid=%02x%02x%02x done\n",
86162306a36Sopenharmony_ci	    did.b.domain, did.b.area, did.b.al_pa);
86262306a36Sopenharmony_ci
86362306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x70e4, "%s: %d\n", __func__, type);
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	qla24xx_els_dcmd_iocb(vha, ELS_DCMD_LOGO, did);
86662306a36Sopenharmony_ci	return count;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic struct bin_attribute sysfs_issue_logo_attr = {
87062306a36Sopenharmony_ci	.attr = {
87162306a36Sopenharmony_ci		.name = "issue_logo",
87262306a36Sopenharmony_ci		.mode = S_IWUSR,
87362306a36Sopenharmony_ci	},
87462306a36Sopenharmony_ci	.size = 0,
87562306a36Sopenharmony_ci	.write = qla2x00_issue_logo,
87662306a36Sopenharmony_ci};
87762306a36Sopenharmony_ci
87862306a36Sopenharmony_cistatic ssize_t
87962306a36Sopenharmony_ciqla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj,
88062306a36Sopenharmony_ci		       struct bin_attribute *bin_attr,
88162306a36Sopenharmony_ci		       char *buf, loff_t off, size_t count)
88262306a36Sopenharmony_ci{
88362306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
88462306a36Sopenharmony_ci	    struct device, kobj)));
88562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
88662306a36Sopenharmony_ci	int rval;
88762306a36Sopenharmony_ci	uint16_t actual_size;
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE)
89062306a36Sopenharmony_ci		return 0;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
89362306a36Sopenharmony_ci		return 0;
89462306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
89562306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
89662306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
89762306a36Sopenharmony_ci		return 0;
89862306a36Sopenharmony_ci	}
89962306a36Sopenharmony_ci
90062306a36Sopenharmony_ci	if (ha->xgmac_data)
90162306a36Sopenharmony_ci		goto do_read;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE,
90462306a36Sopenharmony_ci	    &ha->xgmac_data_dma, GFP_KERNEL);
90562306a36Sopenharmony_ci	if (!ha->xgmac_data) {
90662306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
90762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7076,
90862306a36Sopenharmony_ci		    "Unable to allocate memory for XGMAC read-data.\n");
90962306a36Sopenharmony_ci		return 0;
91062306a36Sopenharmony_ci	}
91162306a36Sopenharmony_ci
91262306a36Sopenharmony_cido_read:
91362306a36Sopenharmony_ci	actual_size = 0;
91462306a36Sopenharmony_ci	memset(ha->xgmac_data, 0, XGMAC_DATA_SIZE);
91562306a36Sopenharmony_ci
91662306a36Sopenharmony_ci	rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma,
91762306a36Sopenharmony_ci	    XGMAC_DATA_SIZE, &actual_size);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
92062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
92162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7077,
92262306a36Sopenharmony_ci		    "Unable to read XGMAC data (%x).\n", rval);
92362306a36Sopenharmony_ci		count = 0;
92462306a36Sopenharmony_ci	}
92562306a36Sopenharmony_ci
92662306a36Sopenharmony_ci	count = actual_size > count ? count : actual_size;
92762306a36Sopenharmony_ci	memcpy(buf, ha->xgmac_data, count);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	return count;
93062306a36Sopenharmony_ci}
93162306a36Sopenharmony_ci
93262306a36Sopenharmony_cistatic struct bin_attribute sysfs_xgmac_stats_attr = {
93362306a36Sopenharmony_ci	.attr = {
93462306a36Sopenharmony_ci		.name = "xgmac_stats",
93562306a36Sopenharmony_ci		.mode = S_IRUSR,
93662306a36Sopenharmony_ci	},
93762306a36Sopenharmony_ci	.size = 0,
93862306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_xgmac_stats,
93962306a36Sopenharmony_ci};
94062306a36Sopenharmony_ci
94162306a36Sopenharmony_cistatic ssize_t
94262306a36Sopenharmony_ciqla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj,
94362306a36Sopenharmony_ci		       struct bin_attribute *bin_attr,
94462306a36Sopenharmony_ci		       char *buf, loff_t off, size_t count)
94562306a36Sopenharmony_ci{
94662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(container_of(kobj,
94762306a36Sopenharmony_ci	    struct device, kobj)));
94862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
94962306a36Sopenharmony_ci	int rval;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN) || off != 0 || count > DCBX_TLV_DATA_SIZE)
95262306a36Sopenharmony_ci		return 0;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
95562306a36Sopenharmony_ci	if (ha->dcbx_tlv)
95662306a36Sopenharmony_ci		goto do_read;
95762306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
95862306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
95962306a36Sopenharmony_ci		return 0;
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE,
96362306a36Sopenharmony_ci	    &ha->dcbx_tlv_dma, GFP_KERNEL);
96462306a36Sopenharmony_ci	if (!ha->dcbx_tlv) {
96562306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
96662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7078,
96762306a36Sopenharmony_ci		    "Unable to allocate memory for DCBX TLV read-data.\n");
96862306a36Sopenharmony_ci		return -ENOMEM;
96962306a36Sopenharmony_ci	}
97062306a36Sopenharmony_ci
97162306a36Sopenharmony_cido_read:
97262306a36Sopenharmony_ci	memset(ha->dcbx_tlv, 0, DCBX_TLV_DATA_SIZE);
97362306a36Sopenharmony_ci
97462306a36Sopenharmony_ci	rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma,
97562306a36Sopenharmony_ci	    DCBX_TLV_DATA_SIZE);
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
97862306a36Sopenharmony_ci
97962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
98062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x7079,
98162306a36Sopenharmony_ci		    "Unable to read DCBX TLV (%x).\n", rval);
98262306a36Sopenharmony_ci		return -EIO;
98362306a36Sopenharmony_ci	}
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	memcpy(buf, ha->dcbx_tlv, count);
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	return count;
98862306a36Sopenharmony_ci}
98962306a36Sopenharmony_ci
99062306a36Sopenharmony_cistatic struct bin_attribute sysfs_dcbx_tlv_attr = {
99162306a36Sopenharmony_ci	.attr = {
99262306a36Sopenharmony_ci		.name = "dcbx_tlv",
99362306a36Sopenharmony_ci		.mode = S_IRUSR,
99462306a36Sopenharmony_ci	},
99562306a36Sopenharmony_ci	.size = 0,
99662306a36Sopenharmony_ci	.read = qla2x00_sysfs_read_dcbx_tlv,
99762306a36Sopenharmony_ci};
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic struct sysfs_entry {
100062306a36Sopenharmony_ci	char *name;
100162306a36Sopenharmony_ci	struct bin_attribute *attr;
100262306a36Sopenharmony_ci	int type;
100362306a36Sopenharmony_ci} bin_file_entries[] = {
100462306a36Sopenharmony_ci	{ "fw_dump", &sysfs_fw_dump_attr, },
100562306a36Sopenharmony_ci	{ "nvram", &sysfs_nvram_attr, },
100662306a36Sopenharmony_ci	{ "optrom", &sysfs_optrom_attr, },
100762306a36Sopenharmony_ci	{ "optrom_ctl", &sysfs_optrom_ctl_attr, },
100862306a36Sopenharmony_ci	{ "vpd", &sysfs_vpd_attr, 1 },
100962306a36Sopenharmony_ci	{ "sfp", &sysfs_sfp_attr, 1 },
101062306a36Sopenharmony_ci	{ "reset", &sysfs_reset_attr, },
101162306a36Sopenharmony_ci	{ "issue_logo", &sysfs_issue_logo_attr, },
101262306a36Sopenharmony_ci	{ "xgmac_stats", &sysfs_xgmac_stats_attr, 3 },
101362306a36Sopenharmony_ci	{ "dcbx_tlv", &sysfs_dcbx_tlv_attr, 3 },
101462306a36Sopenharmony_ci	{ NULL },
101562306a36Sopenharmony_ci};
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_civoid
101862306a36Sopenharmony_ciqla2x00_alloc_sysfs_attr(scsi_qla_host_t *vha)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	struct Scsi_Host *host = vha->host;
102162306a36Sopenharmony_ci	struct sysfs_entry *iter;
102262306a36Sopenharmony_ci	int ret;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	for (iter = bin_file_entries; iter->name; iter++) {
102562306a36Sopenharmony_ci		if (iter->type && !IS_FWI2_CAPABLE(vha->hw))
102662306a36Sopenharmony_ci			continue;
102762306a36Sopenharmony_ci		if (iter->type == 2 && !IS_QLA25XX(vha->hw))
102862306a36Sopenharmony_ci			continue;
102962306a36Sopenharmony_ci		if (iter->type == 3 && !(IS_CNA_CAPABLE(vha->hw)))
103062306a36Sopenharmony_ci			continue;
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_ci		ret = sysfs_create_bin_file(&host->shost_gendev.kobj,
103362306a36Sopenharmony_ci		    iter->attr);
103462306a36Sopenharmony_ci		if (ret)
103562306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x00f3,
103662306a36Sopenharmony_ci			    "Unable to create sysfs %s binary attribute (%d).\n",
103762306a36Sopenharmony_ci			    iter->name, ret);
103862306a36Sopenharmony_ci		else
103962306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x00f4,
104062306a36Sopenharmony_ci			    "Successfully created sysfs %s binary attribute.\n",
104162306a36Sopenharmony_ci			    iter->name);
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci}
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_civoid
104662306a36Sopenharmony_ciqla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon)
104762306a36Sopenharmony_ci{
104862306a36Sopenharmony_ci	struct Scsi_Host *host = vha->host;
104962306a36Sopenharmony_ci	struct sysfs_entry *iter;
105062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	for (iter = bin_file_entries; iter->name; iter++) {
105362306a36Sopenharmony_ci		if (iter->type && !IS_FWI2_CAPABLE(ha))
105462306a36Sopenharmony_ci			continue;
105562306a36Sopenharmony_ci		if (iter->type == 2 && !IS_QLA25XX(ha))
105662306a36Sopenharmony_ci			continue;
105762306a36Sopenharmony_ci		if (iter->type == 3 && !(IS_CNA_CAPABLE(ha)))
105862306a36Sopenharmony_ci			continue;
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci		sysfs_remove_bin_file(&host->shost_gendev.kobj,
106162306a36Sopenharmony_ci		    iter->attr);
106262306a36Sopenharmony_ci	}
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	if (stop_beacon && ha->beacon_blink_led == 1)
106562306a36Sopenharmony_ci		ha->isp_ops->beacon_off(vha);
106662306a36Sopenharmony_ci}
106762306a36Sopenharmony_ci
106862306a36Sopenharmony_ci/* Scsi_Host attributes. */
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_cistatic ssize_t
107162306a36Sopenharmony_ciqla2x00_driver_version_show(struct device *dev,
107262306a36Sopenharmony_ci			  struct device_attribute *attr, char *buf)
107362306a36Sopenharmony_ci{
107462306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str);
107562306a36Sopenharmony_ci}
107662306a36Sopenharmony_ci
107762306a36Sopenharmony_cistatic ssize_t
107862306a36Sopenharmony_ciqla2x00_fw_version_show(struct device *dev,
107962306a36Sopenharmony_ci			struct device_attribute *attr, char *buf)
108062306a36Sopenharmony_ci{
108162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
108262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
108362306a36Sopenharmony_ci	char fw_str[128];
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n",
108662306a36Sopenharmony_ci	    ha->isp_ops->fw_version_str(vha, fw_str, sizeof(fw_str)));
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_cistatic ssize_t
109062306a36Sopenharmony_ciqla2x00_serial_num_show(struct device *dev, struct device_attribute *attr,
109162306a36Sopenharmony_ci			char *buf)
109262306a36Sopenharmony_ci{
109362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
109462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
109562306a36Sopenharmony_ci	uint32_t sn;
109662306a36Sopenharmony_ci
109762306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw)) {
109862306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "%s\n",
109962306a36Sopenharmony_ci		    vha->hw->mr.serial_num);
110062306a36Sopenharmony_ci	} else if (IS_FWI2_CAPABLE(ha)) {
110162306a36Sopenharmony_ci		qla2xxx_get_vpd_field(vha, "SN", buf, PAGE_SIZE - 1);
110262306a36Sopenharmony_ci		return strlen(strcat(buf, "\n"));
110362306a36Sopenharmony_ci	}
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ci	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
110662306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%c%05d\n", 'A' + sn / 100000,
110762306a36Sopenharmony_ci	    sn % 100000);
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_cistatic ssize_t
111162306a36Sopenharmony_ciqla2x00_isp_name_show(struct device *dev, struct device_attribute *attr,
111262306a36Sopenharmony_ci		      char *buf)
111362306a36Sopenharmony_ci{
111462306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "ISP%04X\n", vha->hw->pdev->device);
111762306a36Sopenharmony_ci}
111862306a36Sopenharmony_ci
111962306a36Sopenharmony_cistatic ssize_t
112062306a36Sopenharmony_ciqla2x00_isp_id_show(struct device *dev, struct device_attribute *attr,
112162306a36Sopenharmony_ci		    char *buf)
112262306a36Sopenharmony_ci{
112362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
112462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw))
112762306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "%s\n",
112862306a36Sopenharmony_ci		    vha->hw->mr.hw_version);
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
113162306a36Sopenharmony_ci	    ha->product_id[0], ha->product_id[1], ha->product_id[2],
113262306a36Sopenharmony_ci	    ha->product_id[3]);
113362306a36Sopenharmony_ci}
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_cistatic ssize_t
113662306a36Sopenharmony_ciqla2x00_model_name_show(struct device *dev, struct device_attribute *attr,
113762306a36Sopenharmony_ci			char *buf)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_number);
114262306a36Sopenharmony_ci}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_cistatic ssize_t
114562306a36Sopenharmony_ciqla2x00_model_desc_show(struct device *dev, struct device_attribute *attr,
114662306a36Sopenharmony_ci			char *buf)
114762306a36Sopenharmony_ci{
114862306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", vha->hw->model_desc);
115162306a36Sopenharmony_ci}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_cistatic ssize_t
115462306a36Sopenharmony_ciqla2x00_pci_info_show(struct device *dev, struct device_attribute *attr,
115562306a36Sopenharmony_ci		      char *buf)
115662306a36Sopenharmony_ci{
115762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
115862306a36Sopenharmony_ci	char pci_info[30];
115962306a36Sopenharmony_ci
116062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n",
116162306a36Sopenharmony_ci			 vha->hw->isp_ops->pci_info_str(vha, pci_info,
116262306a36Sopenharmony_ci							sizeof(pci_info)));
116362306a36Sopenharmony_ci}
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_cistatic ssize_t
116662306a36Sopenharmony_ciqla2x00_link_state_show(struct device *dev, struct device_attribute *attr,
116762306a36Sopenharmony_ci			char *buf)
116862306a36Sopenharmony_ci{
116962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
117062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
117162306a36Sopenharmony_ci	int len = 0;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	if (atomic_read(&vha->loop_state) == LOOP_DOWN ||
117462306a36Sopenharmony_ci	    atomic_read(&vha->loop_state) == LOOP_DEAD ||
117562306a36Sopenharmony_ci	    vha->device_flags & DFLG_NO_CABLE)
117662306a36Sopenharmony_ci		len = scnprintf(buf, PAGE_SIZE, "Link Down\n");
117762306a36Sopenharmony_ci	else if (atomic_read(&vha->loop_state) != LOOP_READY ||
117862306a36Sopenharmony_ci	    qla2x00_chip_is_down(vha))
117962306a36Sopenharmony_ci		len = scnprintf(buf, PAGE_SIZE, "Unknown Link State\n");
118062306a36Sopenharmony_ci	else {
118162306a36Sopenharmony_ci		len = scnprintf(buf, PAGE_SIZE, "Link Up - ");
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		switch (ha->current_topology) {
118462306a36Sopenharmony_ci		case ISP_CFG_NL:
118562306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE-len, "Loop\n");
118662306a36Sopenharmony_ci			break;
118762306a36Sopenharmony_ci		case ISP_CFG_FL:
118862306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE-len, "FL_Port\n");
118962306a36Sopenharmony_ci			break;
119062306a36Sopenharmony_ci		case ISP_CFG_N:
119162306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE-len,
119262306a36Sopenharmony_ci			    "N_Port to N_Port\n");
119362306a36Sopenharmony_ci			break;
119462306a36Sopenharmony_ci		case ISP_CFG_F:
119562306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE-len, "F_Port\n");
119662306a36Sopenharmony_ci			break;
119762306a36Sopenharmony_ci		default:
119862306a36Sopenharmony_ci			len += scnprintf(buf + len, PAGE_SIZE-len, "Loop\n");
119962306a36Sopenharmony_ci			break;
120062306a36Sopenharmony_ci		}
120162306a36Sopenharmony_ci	}
120262306a36Sopenharmony_ci	return len;
120362306a36Sopenharmony_ci}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_cistatic ssize_t
120662306a36Sopenharmony_ciqla2x00_zio_show(struct device *dev, struct device_attribute *attr,
120762306a36Sopenharmony_ci		 char *buf)
120862306a36Sopenharmony_ci{
120962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
121062306a36Sopenharmony_ci	int len = 0;
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	switch (vha->hw->zio_mode) {
121362306a36Sopenharmony_ci	case QLA_ZIO_MODE_6:
121462306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len, "Mode 6\n");
121562306a36Sopenharmony_ci		break;
121662306a36Sopenharmony_ci	case QLA_ZIO_DISABLED:
121762306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
121862306a36Sopenharmony_ci		break;
121962306a36Sopenharmony_ci	}
122062306a36Sopenharmony_ci	return len;
122162306a36Sopenharmony_ci}
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_cistatic ssize_t
122462306a36Sopenharmony_ciqla2x00_zio_store(struct device *dev, struct device_attribute *attr,
122562306a36Sopenharmony_ci		  const char *buf, size_t count)
122662306a36Sopenharmony_ci{
122762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
122862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
122962306a36Sopenharmony_ci	int val = 0;
123062306a36Sopenharmony_ci	uint16_t zio_mode;
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (!IS_ZIO_SUPPORTED(ha))
123362306a36Sopenharmony_ci		return -ENOTSUPP;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
123662306a36Sopenharmony_ci		return -EINVAL;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	if (val)
123962306a36Sopenharmony_ci		zio_mode = QLA_ZIO_MODE_6;
124062306a36Sopenharmony_ci	else
124162306a36Sopenharmony_ci		zio_mode = QLA_ZIO_DISABLED;
124262306a36Sopenharmony_ci
124362306a36Sopenharmony_ci	/* Update per-hba values and queue a reset. */
124462306a36Sopenharmony_ci	if (zio_mode != QLA_ZIO_DISABLED || ha->zio_mode != QLA_ZIO_DISABLED) {
124562306a36Sopenharmony_ci		ha->zio_mode = zio_mode;
124662306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
124762306a36Sopenharmony_ci	}
124862306a36Sopenharmony_ci	return strlen(buf);
124962306a36Sopenharmony_ci}
125062306a36Sopenharmony_ci
125162306a36Sopenharmony_cistatic ssize_t
125262306a36Sopenharmony_ciqla2x00_zio_timer_show(struct device *dev, struct device_attribute *attr,
125362306a36Sopenharmony_ci		       char *buf)
125462306a36Sopenharmony_ci{
125562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
125662306a36Sopenharmony_ci
125762306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d us\n", vha->hw->zio_timer * 100);
125862306a36Sopenharmony_ci}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_cistatic ssize_t
126162306a36Sopenharmony_ciqla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr,
126262306a36Sopenharmony_ci			const char *buf, size_t count)
126362306a36Sopenharmony_ci{
126462306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
126562306a36Sopenharmony_ci	int val = 0;
126662306a36Sopenharmony_ci	uint16_t zio_timer;
126762306a36Sopenharmony_ci
126862306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
126962306a36Sopenharmony_ci		return -EINVAL;
127062306a36Sopenharmony_ci	if (val > 25500 || val < 100)
127162306a36Sopenharmony_ci		return -ERANGE;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	zio_timer = (uint16_t)(val / 100);
127462306a36Sopenharmony_ci	vha->hw->zio_timer = zio_timer;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	return strlen(buf);
127762306a36Sopenharmony_ci}
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_cistatic ssize_t
128062306a36Sopenharmony_ciqla_zio_threshold_show(struct device *dev, struct device_attribute *attr,
128162306a36Sopenharmony_ci		       char *buf)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d exchanges\n",
128662306a36Sopenharmony_ci	    vha->hw->last_zio_threshold);
128762306a36Sopenharmony_ci}
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_cistatic ssize_t
129062306a36Sopenharmony_ciqla_zio_threshold_store(struct device *dev, struct device_attribute *attr,
129162306a36Sopenharmony_ci    const char *buf, size_t count)
129262306a36Sopenharmony_ci{
129362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
129462306a36Sopenharmony_ci	int val = 0;
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	if (vha->hw->zio_mode != QLA_ZIO_MODE_6)
129762306a36Sopenharmony_ci		return -EINVAL;
129862306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
129962306a36Sopenharmony_ci		return -EINVAL;
130062306a36Sopenharmony_ci	if (val < 0 || val > 256)
130162306a36Sopenharmony_ci		return -ERANGE;
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ci	atomic_set(&vha->hw->zio_threshold, val);
130462306a36Sopenharmony_ci	return strlen(buf);
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_cistatic ssize_t
130862306a36Sopenharmony_ciqla2x00_beacon_show(struct device *dev, struct device_attribute *attr,
130962306a36Sopenharmony_ci		    char *buf)
131062306a36Sopenharmony_ci{
131162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
131262306a36Sopenharmony_ci	int len = 0;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	if (vha->hw->beacon_blink_led)
131562306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len, "Enabled\n");
131662306a36Sopenharmony_ci	else
131762306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len, "Disabled\n");
131862306a36Sopenharmony_ci	return len;
131962306a36Sopenharmony_ci}
132062306a36Sopenharmony_ci
132162306a36Sopenharmony_cistatic ssize_t
132262306a36Sopenharmony_ciqla2x00_beacon_store(struct device *dev, struct device_attribute *attr,
132362306a36Sopenharmony_ci		     const char *buf, size_t count)
132462306a36Sopenharmony_ci{
132562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
132662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
132762306a36Sopenharmony_ci	int val = 0;
132862306a36Sopenharmony_ci	int rval;
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	if (IS_QLA2100(ha) || IS_QLA2200(ha))
133162306a36Sopenharmony_ci		return -EPERM;
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
133462306a36Sopenharmony_ci		return -EINVAL;
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
133762306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
133862306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
133962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x707a,
134062306a36Sopenharmony_ci		    "Abort ISP active -- ignoring beacon request.\n");
134162306a36Sopenharmony_ci		return -EBUSY;
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci	if (val)
134562306a36Sopenharmony_ci		rval = ha->isp_ops->beacon_on(vha);
134662306a36Sopenharmony_ci	else
134762306a36Sopenharmony_ci		rval = ha->isp_ops->beacon_off(vha);
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
135062306a36Sopenharmony_ci		count = 0;
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
135362306a36Sopenharmony_ci
135462306a36Sopenharmony_ci	return count;
135562306a36Sopenharmony_ci}
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_cistatic ssize_t
135862306a36Sopenharmony_ciqla2x00_beacon_config_show(struct device *dev, struct device_attribute *attr,
135962306a36Sopenharmony_ci	char *buf)
136062306a36Sopenharmony_ci{
136162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
136262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
136362306a36Sopenharmony_ci	uint16_t led[3] = { 0 };
136462306a36Sopenharmony_ci
136562306a36Sopenharmony_ci	if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
136662306a36Sopenharmony_ci		return -EPERM;
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	if (ql26xx_led_config(vha, 0, led))
136962306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
137062306a36Sopenharmony_ci
137162306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%#04hx %#04hx %#04hx\n",
137262306a36Sopenharmony_ci	    led[0], led[1], led[2]);
137362306a36Sopenharmony_ci}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_cistatic ssize_t
137662306a36Sopenharmony_ciqla2x00_beacon_config_store(struct device *dev, struct device_attribute *attr,
137762306a36Sopenharmony_ci	const char *buf, size_t count)
137862306a36Sopenharmony_ci{
137962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
138062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
138162306a36Sopenharmony_ci	uint16_t options = BIT_0;
138262306a36Sopenharmony_ci	uint16_t led[3] = { 0 };
138362306a36Sopenharmony_ci	uint16_t word[4];
138462306a36Sopenharmony_ci	int n;
138562306a36Sopenharmony_ci
138662306a36Sopenharmony_ci	if (!IS_QLA2031(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
138762306a36Sopenharmony_ci		return -EPERM;
138862306a36Sopenharmony_ci
138962306a36Sopenharmony_ci	n = sscanf(buf, "%hx %hx %hx %hx", word+0, word+1, word+2, word+3);
139062306a36Sopenharmony_ci	if (n == 4) {
139162306a36Sopenharmony_ci		if (word[0] == 3) {
139262306a36Sopenharmony_ci			options |= BIT_3|BIT_2|BIT_1;
139362306a36Sopenharmony_ci			led[0] = word[1];
139462306a36Sopenharmony_ci			led[1] = word[2];
139562306a36Sopenharmony_ci			led[2] = word[3];
139662306a36Sopenharmony_ci			goto write;
139762306a36Sopenharmony_ci		}
139862306a36Sopenharmony_ci		return -EINVAL;
139962306a36Sopenharmony_ci	}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	if (n == 2) {
140262306a36Sopenharmony_ci		/* check led index */
140362306a36Sopenharmony_ci		if (word[0] == 0) {
140462306a36Sopenharmony_ci			options |= BIT_2;
140562306a36Sopenharmony_ci			led[0] = word[1];
140662306a36Sopenharmony_ci			goto write;
140762306a36Sopenharmony_ci		}
140862306a36Sopenharmony_ci		if (word[0] == 1) {
140962306a36Sopenharmony_ci			options |= BIT_3;
141062306a36Sopenharmony_ci			led[1] = word[1];
141162306a36Sopenharmony_ci			goto write;
141262306a36Sopenharmony_ci		}
141362306a36Sopenharmony_ci		if (word[0] == 2) {
141462306a36Sopenharmony_ci			options |= BIT_1;
141562306a36Sopenharmony_ci			led[2] = word[1];
141662306a36Sopenharmony_ci			goto write;
141762306a36Sopenharmony_ci		}
141862306a36Sopenharmony_ci		return -EINVAL;
141962306a36Sopenharmony_ci	}
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	return -EINVAL;
142262306a36Sopenharmony_ci
142362306a36Sopenharmony_ciwrite:
142462306a36Sopenharmony_ci	if (ql26xx_led_config(vha, options, led))
142562306a36Sopenharmony_ci		return -EFAULT;
142662306a36Sopenharmony_ci
142762306a36Sopenharmony_ci	return count;
142862306a36Sopenharmony_ci}
142962306a36Sopenharmony_ci
143062306a36Sopenharmony_cistatic ssize_t
143162306a36Sopenharmony_ciqla2x00_optrom_bios_version_show(struct device *dev,
143262306a36Sopenharmony_ci				 struct device_attribute *attr, char *buf)
143362306a36Sopenharmony_ci{
143462306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
143562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->bios_revision[1],
143862306a36Sopenharmony_ci	    ha->bios_revision[0]);
143962306a36Sopenharmony_ci}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_cistatic ssize_t
144262306a36Sopenharmony_ciqla2x00_optrom_efi_version_show(struct device *dev,
144362306a36Sopenharmony_ci				struct device_attribute *attr, char *buf)
144462306a36Sopenharmony_ci{
144562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
144662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
144762306a36Sopenharmony_ci
144862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->efi_revision[1],
144962306a36Sopenharmony_ci	    ha->efi_revision[0]);
145062306a36Sopenharmony_ci}
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_cistatic ssize_t
145362306a36Sopenharmony_ciqla2x00_optrom_fcode_version_show(struct device *dev,
145462306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
145562306a36Sopenharmony_ci{
145662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
145762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d\n", ha->fcode_revision[1],
146062306a36Sopenharmony_ci	    ha->fcode_revision[0]);
146162306a36Sopenharmony_ci}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_cistatic ssize_t
146462306a36Sopenharmony_ciqla2x00_optrom_fw_version_show(struct device *dev,
146562306a36Sopenharmony_ci			       struct device_attribute *attr, char *buf)
146662306a36Sopenharmony_ci{
146762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
146862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d %d\n",
147162306a36Sopenharmony_ci	    ha->fw_revision[0], ha->fw_revision[1], ha->fw_revision[2],
147262306a36Sopenharmony_ci	    ha->fw_revision[3]);
147362306a36Sopenharmony_ci}
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_cistatic ssize_t
147662306a36Sopenharmony_ciqla2x00_optrom_gold_fw_version_show(struct device *dev,
147762306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
147862306a36Sopenharmony_ci{
147962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
148062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (!IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
148362306a36Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
148462306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
148562306a36Sopenharmony_ci
148662306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%d)\n",
148762306a36Sopenharmony_ci	    ha->gold_fw_version[0], ha->gold_fw_version[1],
148862306a36Sopenharmony_ci	    ha->gold_fw_version[2], ha->gold_fw_version[3]);
148962306a36Sopenharmony_ci}
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_cistatic ssize_t
149262306a36Sopenharmony_ciqla2x00_total_isp_aborts_show(struct device *dev,
149362306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf)
149462306a36Sopenharmony_ci{
149562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n",
149862306a36Sopenharmony_ci	    vha->qla_stats.total_isp_aborts);
149962306a36Sopenharmony_ci}
150062306a36Sopenharmony_ci
150162306a36Sopenharmony_cistatic ssize_t
150262306a36Sopenharmony_ciqla24xx_84xx_fw_version_show(struct device *dev,
150362306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
150462306a36Sopenharmony_ci{
150562306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
150662306a36Sopenharmony_ci	uint16_t status[2] = { 0 };
150762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
150862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci	if (!IS_QLA84XX(ha))
151162306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	if (!ha->cs84xx->op_fw_version) {
151462306a36Sopenharmony_ci		rval = qla84xx_verify_chip(vha, status);
151562306a36Sopenharmony_ci
151662306a36Sopenharmony_ci		if (!rval && !status[0])
151762306a36Sopenharmony_ci			return scnprintf(buf, PAGE_SIZE, "%u\n",
151862306a36Sopenharmony_ci			    (uint32_t)ha->cs84xx->op_fw_version);
151962306a36Sopenharmony_ci	}
152062306a36Sopenharmony_ci
152162306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "\n");
152262306a36Sopenharmony_ci}
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_cistatic ssize_t
152562306a36Sopenharmony_ciqla2x00_serdes_version_show(struct device *dev, struct device_attribute *attr,
152662306a36Sopenharmony_ci    char *buf)
152762306a36Sopenharmony_ci{
152862306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
152962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
153262306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
153562306a36Sopenharmony_ci	    ha->serdes_version[0], ha->serdes_version[1],
153662306a36Sopenharmony_ci	    ha->serdes_version[2]);
153762306a36Sopenharmony_ci}
153862306a36Sopenharmony_ci
153962306a36Sopenharmony_cistatic ssize_t
154062306a36Sopenharmony_ciqla2x00_mpi_version_show(struct device *dev, struct device_attribute *attr,
154162306a36Sopenharmony_ci    char *buf)
154262306a36Sopenharmony_ci{
154362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
154462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha) && !IS_QLA8044(ha) &&
154762306a36Sopenharmony_ci	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
154862306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
154962306a36Sopenharmony_ci
155062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d (%x)\n",
155162306a36Sopenharmony_ci	    ha->mpi_version[0], ha->mpi_version[1], ha->mpi_version[2],
155262306a36Sopenharmony_ci	    ha->mpi_capabilities);
155362306a36Sopenharmony_ci}
155462306a36Sopenharmony_ci
155562306a36Sopenharmony_cistatic ssize_t
155662306a36Sopenharmony_ciqla2x00_phy_version_show(struct device *dev, struct device_attribute *attr,
155762306a36Sopenharmony_ci    char *buf)
155862306a36Sopenharmony_ci{
155962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
156062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci	if (!IS_QLA81XX(ha) && !IS_QLA8031(ha))
156362306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
156662306a36Sopenharmony_ci	    ha->phy_version[0], ha->phy_version[1], ha->phy_version[2]);
156762306a36Sopenharmony_ci}
156862306a36Sopenharmony_ci
156962306a36Sopenharmony_cistatic ssize_t
157062306a36Sopenharmony_ciqla2x00_flash_block_size_show(struct device *dev,
157162306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf)
157262306a36Sopenharmony_ci{
157362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
157462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "0x%x\n", ha->fdt_block_size);
157762306a36Sopenharmony_ci}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_cistatic ssize_t
158062306a36Sopenharmony_ciqla2x00_vlan_id_show(struct device *dev, struct device_attribute *attr,
158162306a36Sopenharmony_ci    char *buf)
158262306a36Sopenharmony_ci{
158362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	if (!IS_CNA_CAPABLE(vha->hw))
158662306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", vha->fcoe_vlan_id);
158962306a36Sopenharmony_ci}
159062306a36Sopenharmony_ci
159162306a36Sopenharmony_cistatic ssize_t
159262306a36Sopenharmony_ciqla2x00_vn_port_mac_address_show(struct device *dev,
159362306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
159462306a36Sopenharmony_ci{
159562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
159662306a36Sopenharmony_ci
159762306a36Sopenharmony_ci	if (!IS_CNA_CAPABLE(vha->hw))
159862306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%pMR\n", vha->fcoe_vn_port_mac);
160162306a36Sopenharmony_ci}
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_cistatic ssize_t
160462306a36Sopenharmony_ciqla2x00_fabric_param_show(struct device *dev, struct device_attribute *attr,
160562306a36Sopenharmony_ci    char *buf)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", vha->hw->switch_cap);
161062306a36Sopenharmony_ci}
161162306a36Sopenharmony_ci
161262306a36Sopenharmony_cistatic ssize_t
161362306a36Sopenharmony_ciqla2x00_thermal_temp_show(struct device *dev,
161462306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
161562306a36Sopenharmony_ci{
161662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
161762306a36Sopenharmony_ci	uint16_t temp = 0;
161862306a36Sopenharmony_ci	int rc;
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
162162306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
162262306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
162362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n");
162462306a36Sopenharmony_ci		goto done;
162562306a36Sopenharmony_ci	}
162662306a36Sopenharmony_ci
162762306a36Sopenharmony_ci	if (vha->hw->flags.eeh_busy) {
162862306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
162962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70dd, "PCI EEH busy.\n");
163062306a36Sopenharmony_ci		goto done;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	rc = qla2x00_get_thermal_temp(vha, &temp);
163462306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
163562306a36Sopenharmony_ci	if (rc == QLA_SUCCESS)
163662306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "%d\n", temp);
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_cidone:
163962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "\n");
164062306a36Sopenharmony_ci}
164162306a36Sopenharmony_ci
164262306a36Sopenharmony_cistatic ssize_t
164362306a36Sopenharmony_ciqla2x00_fw_state_show(struct device *dev, struct device_attribute *attr,
164462306a36Sopenharmony_ci    char *buf)
164562306a36Sopenharmony_ci{
164662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
164762306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
164862306a36Sopenharmony_ci	uint16_t state[6];
164962306a36Sopenharmony_ci	uint32_t pstate;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw)) {
165262306a36Sopenharmony_ci		pstate = qlafx00_fw_state_show(dev, attr, buf);
165362306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate);
165462306a36Sopenharmony_ci	}
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	mutex_lock(&vha->hw->optrom_mutex);
165762306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha)) {
165862306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
165962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x707c,
166062306a36Sopenharmony_ci		    "ISP reset active.\n");
166162306a36Sopenharmony_ci		goto out;
166262306a36Sopenharmony_ci	} else if (vha->hw->flags.eeh_busy) {
166362306a36Sopenharmony_ci		mutex_unlock(&vha->hw->optrom_mutex);
166462306a36Sopenharmony_ci		goto out;
166562306a36Sopenharmony_ci	}
166662306a36Sopenharmony_ci
166762306a36Sopenharmony_ci	rval = qla2x00_get_firmware_state(vha, state);
166862306a36Sopenharmony_ci	mutex_unlock(&vha->hw->optrom_mutex);
166962306a36Sopenharmony_ciout:
167062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
167162306a36Sopenharmony_ci		memset(state, -1, sizeof(state));
167262306a36Sopenharmony_ci		rval = qla2x00_get_firmware_state(vha, state);
167362306a36Sopenharmony_ci	}
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
167662306a36Sopenharmony_ci	    state[0], state[1], state[2], state[3], state[4], state[5]);
167762306a36Sopenharmony_ci}
167862306a36Sopenharmony_ci
167962306a36Sopenharmony_cistatic ssize_t
168062306a36Sopenharmony_ciqla2x00_diag_requests_show(struct device *dev,
168162306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
168262306a36Sopenharmony_ci{
168362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ci	if (!IS_BIDI_CAPABLE(vha->hw))
168662306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%llu\n", vha->bidi_stats.io_count);
168962306a36Sopenharmony_ci}
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_cistatic ssize_t
169262306a36Sopenharmony_ciqla2x00_diag_megabytes_show(struct device *dev,
169362306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
169462306a36Sopenharmony_ci{
169562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	if (!IS_BIDI_CAPABLE(vha->hw))
169862306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
169962306a36Sopenharmony_ci
170062306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%llu\n",
170162306a36Sopenharmony_ci	    vha->bidi_stats.transfer_bytes >> 20);
170262306a36Sopenharmony_ci}
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_cistatic ssize_t
170562306a36Sopenharmony_ciqla2x00_fw_dump_size_show(struct device *dev, struct device_attribute *attr,
170662306a36Sopenharmony_ci	char *buf)
170762306a36Sopenharmony_ci{
170862306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
170962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
171062306a36Sopenharmony_ci	uint32_t size;
171162306a36Sopenharmony_ci
171262306a36Sopenharmony_ci	if (!ha->fw_dumped)
171362306a36Sopenharmony_ci		size = 0;
171462306a36Sopenharmony_ci	else if (IS_P3P_TYPE(ha))
171562306a36Sopenharmony_ci		size = ha->md_template_size + ha->md_dump_size;
171662306a36Sopenharmony_ci	else
171762306a36Sopenharmony_ci		size = ha->fw_dump_len;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d\n", size);
172062306a36Sopenharmony_ci}
172162306a36Sopenharmony_ci
172262306a36Sopenharmony_cistatic ssize_t
172362306a36Sopenharmony_ciqla2x00_allow_cna_fw_dump_show(struct device *dev,
172462306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
172762306a36Sopenharmony_ci
172862306a36Sopenharmony_ci	if (!IS_P3P_TYPE(vha->hw))
172962306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
173062306a36Sopenharmony_ci	else
173162306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "%s\n",
173262306a36Sopenharmony_ci		    vha->hw->allow_cna_fw_dump ? "true" : "false");
173362306a36Sopenharmony_ci}
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic ssize_t
173662306a36Sopenharmony_ciqla2x00_allow_cna_fw_dump_store(struct device *dev,
173762306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
173862306a36Sopenharmony_ci{
173962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
174062306a36Sopenharmony_ci	int val = 0;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	if (!IS_P3P_TYPE(vha->hw))
174362306a36Sopenharmony_ci		return -EINVAL;
174462306a36Sopenharmony_ci
174562306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
174662306a36Sopenharmony_ci		return -EINVAL;
174762306a36Sopenharmony_ci
174862306a36Sopenharmony_ci	vha->hw->allow_cna_fw_dump = val != 0;
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	return strlen(buf);
175162306a36Sopenharmony_ci}
175262306a36Sopenharmony_ci
175362306a36Sopenharmony_cistatic ssize_t
175462306a36Sopenharmony_ciqla2x00_pep_version_show(struct device *dev, struct device_attribute *attr,
175562306a36Sopenharmony_ci	char *buf)
175662306a36Sopenharmony_ci{
175762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
175862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
176162306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%02d.%02d\n",
176462306a36Sopenharmony_ci	    ha->pep_version[0], ha->pep_version[1], ha->pep_version[2]);
176562306a36Sopenharmony_ci}
176662306a36Sopenharmony_ci
176762306a36Sopenharmony_cistatic ssize_t
176862306a36Sopenharmony_ciqla2x00_min_supported_speed_show(struct device *dev,
176962306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
177062306a36Sopenharmony_ci{
177162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
177262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
177562306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n",
177862306a36Sopenharmony_ci	    ha->min_supported_speed == 6 ? "64Gps" :
177962306a36Sopenharmony_ci	    ha->min_supported_speed == 5 ? "32Gps" :
178062306a36Sopenharmony_ci	    ha->min_supported_speed == 4 ? "16Gps" :
178162306a36Sopenharmony_ci	    ha->min_supported_speed == 3 ? "8Gps" :
178262306a36Sopenharmony_ci	    ha->min_supported_speed == 2 ? "4Gps" :
178362306a36Sopenharmony_ci	    ha->min_supported_speed != 0 ? "unknown" : "");
178462306a36Sopenharmony_ci}
178562306a36Sopenharmony_ci
178662306a36Sopenharmony_cistatic ssize_t
178762306a36Sopenharmony_ciqla2x00_max_supported_speed_show(struct device *dev,
178862306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
178962306a36Sopenharmony_ci{
179062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
179162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
179262306a36Sopenharmony_ci
179362306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
179462306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
179562306a36Sopenharmony_ci
179662306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n",
179762306a36Sopenharmony_ci	    ha->max_supported_speed  == 2 ? "64Gps" :
179862306a36Sopenharmony_ci	    ha->max_supported_speed  == 1 ? "32Gps" :
179962306a36Sopenharmony_ci	    ha->max_supported_speed  == 0 ? "16Gps" : "unknown");
180062306a36Sopenharmony_ci}
180162306a36Sopenharmony_ci
180262306a36Sopenharmony_cistatic ssize_t
180362306a36Sopenharmony_ciqla2x00_port_speed_store(struct device *dev, struct device_attribute *attr,
180462306a36Sopenharmony_ci    const char *buf, size_t count)
180562306a36Sopenharmony_ci{
180662306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
180762306a36Sopenharmony_ci	ulong type, speed;
180862306a36Sopenharmony_ci	int oldspeed, rval;
180962306a36Sopenharmony_ci	int mode = QLA_SET_DATA_RATE_LR;
181062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha)) {
181362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70d8,
181462306a36Sopenharmony_ci		    "Speed setting not supported \n");
181562306a36Sopenharmony_ci		return -EINVAL;
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	rval = kstrtol(buf, 10, &type);
181962306a36Sopenharmony_ci	if (rval)
182062306a36Sopenharmony_ci		return rval;
182162306a36Sopenharmony_ci	speed = type;
182262306a36Sopenharmony_ci	if (type == 40 || type == 80 || type == 160 ||
182362306a36Sopenharmony_ci	    type == 320) {
182462306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x70d9,
182562306a36Sopenharmony_ci		    "Setting will be affected after a loss of sync\n");
182662306a36Sopenharmony_ci		type = type/10;
182762306a36Sopenharmony_ci		mode = QLA_SET_DATA_RATE_NOLR;
182862306a36Sopenharmony_ci	}
182962306a36Sopenharmony_ci
183062306a36Sopenharmony_ci	oldspeed = ha->set_data_rate;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	switch (type) {
183362306a36Sopenharmony_ci	case 0:
183462306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_AUTO;
183562306a36Sopenharmony_ci		break;
183662306a36Sopenharmony_ci	case 4:
183762306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_4GB;
183862306a36Sopenharmony_ci		break;
183962306a36Sopenharmony_ci	case 8:
184062306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_8GB;
184162306a36Sopenharmony_ci		break;
184262306a36Sopenharmony_ci	case 16:
184362306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_16GB;
184462306a36Sopenharmony_ci		break;
184562306a36Sopenharmony_ci	case 32:
184662306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_32GB;
184762306a36Sopenharmony_ci		break;
184862306a36Sopenharmony_ci	default:
184962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x1199,
185062306a36Sopenharmony_ci		    "Unrecognized speed setting:%lx. Setting Autoneg\n",
185162306a36Sopenharmony_ci		    speed);
185262306a36Sopenharmony_ci		ha->set_data_rate = PORT_SPEED_AUTO;
185362306a36Sopenharmony_ci	}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha) || (oldspeed == ha->set_data_rate))
185662306a36Sopenharmony_ci		return -EINVAL;
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x70da,
185962306a36Sopenharmony_ci	    "Setting speed to %lx Gbps \n", type);
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_ci	rval = qla2x00_set_data_rate(vha, mode);
186262306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
186362306a36Sopenharmony_ci		return -EIO;
186462306a36Sopenharmony_ci
186562306a36Sopenharmony_ci	return strlen(buf);
186662306a36Sopenharmony_ci}
186762306a36Sopenharmony_ci
186862306a36Sopenharmony_cistatic const struct {
186962306a36Sopenharmony_ci	u16 rate;
187062306a36Sopenharmony_ci	char *str;
187162306a36Sopenharmony_ci} port_speed_str[] = {
187262306a36Sopenharmony_ci	{ PORT_SPEED_4GB, "4" },
187362306a36Sopenharmony_ci	{ PORT_SPEED_8GB, "8" },
187462306a36Sopenharmony_ci	{ PORT_SPEED_16GB, "16" },
187562306a36Sopenharmony_ci	{ PORT_SPEED_32GB, "32" },
187662306a36Sopenharmony_ci	{ PORT_SPEED_64GB, "64" },
187762306a36Sopenharmony_ci	{ PORT_SPEED_10GB, "10" },
187862306a36Sopenharmony_ci};
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_cistatic ssize_t
188162306a36Sopenharmony_ciqla2x00_port_speed_show(struct device *dev, struct device_attribute *attr,
188262306a36Sopenharmony_ci    char *buf)
188362306a36Sopenharmony_ci{
188462306a36Sopenharmony_ci	struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev));
188562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
188662306a36Sopenharmony_ci	ssize_t rval;
188762306a36Sopenharmony_ci	u16 i;
188862306a36Sopenharmony_ci	char *speed = "Unknown";
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	rval = qla2x00_get_data_rate(vha);
189162306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
189262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x70db,
189362306a36Sopenharmony_ci		    "Unable to get port speed rval:%zd\n", rval);
189462306a36Sopenharmony_ci		return -EINVAL;
189562306a36Sopenharmony_ci	}
189662306a36Sopenharmony_ci
189762306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(port_speed_str); i++) {
189862306a36Sopenharmony_ci		if (port_speed_str[i].rate != ha->link_data_rate)
189962306a36Sopenharmony_ci			continue;
190062306a36Sopenharmony_ci		speed = port_speed_str[i].str;
190162306a36Sopenharmony_ci		break;
190262306a36Sopenharmony_ci	}
190362306a36Sopenharmony_ci
190462306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", speed);
190562306a36Sopenharmony_ci}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_cistatic ssize_t
190862306a36Sopenharmony_ciqla2x00_mpi_pause_store(struct device *dev,
190962306a36Sopenharmony_ci	struct device_attribute *attr, const char *buf, size_t count)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
191262306a36Sopenharmony_ci	int rval = 0;
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci	if (sscanf(buf, "%d", &rval) != 1)
191562306a36Sopenharmony_ci		return -EINVAL;
191662306a36Sopenharmony_ci
191762306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0x7089, "Pausing MPI...\n");
191862306a36Sopenharmony_ci
191962306a36Sopenharmony_ci	rval = qla83xx_wr_reg(vha, 0x002012d4, 0x30000001);
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
192262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x708a, "Unable to pause MPI.\n");
192362306a36Sopenharmony_ci		count = 0;
192462306a36Sopenharmony_ci	}
192562306a36Sopenharmony_ci
192662306a36Sopenharmony_ci	return count;
192762306a36Sopenharmony_ci}
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_cistatic DEVICE_ATTR(mpi_pause, S_IWUSR, NULL, qla2x00_mpi_pause_store);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci/* ----- */
193262306a36Sopenharmony_ci
193362306a36Sopenharmony_cistatic ssize_t
193462306a36Sopenharmony_ciqlini_mode_show(struct device *dev, struct device_attribute *attr, char *buf)
193562306a36Sopenharmony_ci{
193662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
193762306a36Sopenharmony_ci	int len = 0;
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len,
194062306a36Sopenharmony_ci	    "Supported options: enabled | disabled | dual | exclusive\n");
194162306a36Sopenharmony_ci
194262306a36Sopenharmony_ci	/* --- */
194362306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len, "Current selection: ");
194462306a36Sopenharmony_ci
194562306a36Sopenharmony_ci	switch (vha->qlini_mode) {
194662306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_EXCLUSIVE:
194762306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len,
194862306a36Sopenharmony_ci		    QLA2XXX_INI_MODE_STR_EXCLUSIVE);
194962306a36Sopenharmony_ci		break;
195062306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_DISABLED:
195162306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len,
195262306a36Sopenharmony_ci		    QLA2XXX_INI_MODE_STR_DISABLED);
195362306a36Sopenharmony_ci		break;
195462306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_ENABLED:
195562306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len,
195662306a36Sopenharmony_ci		    QLA2XXX_INI_MODE_STR_ENABLED);
195762306a36Sopenharmony_ci		break;
195862306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_DUAL:
195962306a36Sopenharmony_ci		len += scnprintf(buf + len, PAGE_SIZE-len,
196062306a36Sopenharmony_ci		    QLA2XXX_INI_MODE_STR_DUAL);
196162306a36Sopenharmony_ci		break;
196262306a36Sopenharmony_ci	}
196362306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len, "\n");
196462306a36Sopenharmony_ci
196562306a36Sopenharmony_ci	return len;
196662306a36Sopenharmony_ci}
196762306a36Sopenharmony_ci
196862306a36Sopenharmony_cistatic char *mode_to_str[] = {
196962306a36Sopenharmony_ci	"exclusive",
197062306a36Sopenharmony_ci	"disabled",
197162306a36Sopenharmony_ci	"enabled",
197262306a36Sopenharmony_ci	"dual",
197362306a36Sopenharmony_ci};
197462306a36Sopenharmony_ci
197562306a36Sopenharmony_ci#define NEED_EXCH_OFFLOAD(_exchg) ((_exchg) > FW_DEF_EXCHANGES_CNT)
197662306a36Sopenharmony_cistatic void qla_set_ini_mode(scsi_qla_host_t *vha, int op)
197762306a36Sopenharmony_ci{
197862306a36Sopenharmony_ci	enum {
197962306a36Sopenharmony_ci		NO_ACTION,
198062306a36Sopenharmony_ci		MODE_CHANGE_ACCEPT,
198162306a36Sopenharmony_ci		MODE_CHANGE_NO_ACTION,
198262306a36Sopenharmony_ci		TARGET_STILL_ACTIVE,
198362306a36Sopenharmony_ci	};
198462306a36Sopenharmony_ci	int action = NO_ACTION;
198562306a36Sopenharmony_ci	int set_mode = 0;
198662306a36Sopenharmony_ci	u8  eo_toggle = 0;	/* exchange offload flipped */
198762306a36Sopenharmony_ci
198862306a36Sopenharmony_ci	switch (vha->qlini_mode) {
198962306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_DISABLED:
199062306a36Sopenharmony_ci		switch (op) {
199162306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DISABLED:
199262306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
199362306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
199462306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
199562306a36Sopenharmony_ci					eo_toggle = 1;
199662306a36Sopenharmony_ci				if (((vha->ql2xexchoffld !=
199762306a36Sopenharmony_ci				    vha->u_ql2xexchoffld) &&
199862306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
199962306a36Sopenharmony_ci				    eo_toggle) {
200062306a36Sopenharmony_ci					/*
200162306a36Sopenharmony_ci					 * The number of exchange to be offload
200262306a36Sopenharmony_ci					 * was tweaked or offload option was
200362306a36Sopenharmony_ci					 * flipped
200462306a36Sopenharmony_ci					 */
200562306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
200662306a36Sopenharmony_ci				} else {
200762306a36Sopenharmony_ci					action = MODE_CHANGE_NO_ACTION;
200862306a36Sopenharmony_ci				}
200962306a36Sopenharmony_ci			} else {
201062306a36Sopenharmony_ci				action = MODE_CHANGE_NO_ACTION;
201162306a36Sopenharmony_ci			}
201262306a36Sopenharmony_ci			break;
201362306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_EXCLUSIVE:
201462306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
201562306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
201662306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
201762306a36Sopenharmony_ci					eo_toggle = 1;
201862306a36Sopenharmony_ci				if (((vha->ql2xexchoffld !=
201962306a36Sopenharmony_ci				    vha->u_ql2xexchoffld) &&
202062306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
202162306a36Sopenharmony_ci				    eo_toggle) {
202262306a36Sopenharmony_ci					/*
202362306a36Sopenharmony_ci					 * The number of exchange to be offload
202462306a36Sopenharmony_ci					 * was tweaked or offload option was
202562306a36Sopenharmony_ci					 * flipped
202662306a36Sopenharmony_ci					 */
202762306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
202862306a36Sopenharmony_ci				} else {
202962306a36Sopenharmony_ci					action = MODE_CHANGE_NO_ACTION;
203062306a36Sopenharmony_ci				}
203162306a36Sopenharmony_ci			} else {
203262306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
203362306a36Sopenharmony_ci			}
203462306a36Sopenharmony_ci			break;
203562306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DUAL:
203662306a36Sopenharmony_ci			action = MODE_CHANGE_ACCEPT;
203762306a36Sopenharmony_ci			/* active_mode is target only, reset it to dual */
203862306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
203962306a36Sopenharmony_ci				set_mode = 1;
204062306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
204162306a36Sopenharmony_ci			} else {
204262306a36Sopenharmony_ci				action = MODE_CHANGE_NO_ACTION;
204362306a36Sopenharmony_ci			}
204462306a36Sopenharmony_ci			break;
204562306a36Sopenharmony_ci
204662306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_ENABLED:
204762306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha))
204862306a36Sopenharmony_ci				action = TARGET_STILL_ACTIVE;
204962306a36Sopenharmony_ci			else {
205062306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
205162306a36Sopenharmony_ci				set_mode = 1;
205262306a36Sopenharmony_ci			}
205362306a36Sopenharmony_ci			break;
205462306a36Sopenharmony_ci		}
205562306a36Sopenharmony_ci		break;
205662306a36Sopenharmony_ci
205762306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_EXCLUSIVE:
205862306a36Sopenharmony_ci		switch (op) {
205962306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_EXCLUSIVE:
206062306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
206162306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
206262306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
206362306a36Sopenharmony_ci					eo_toggle = 1;
206462306a36Sopenharmony_ci				if (((vha->ql2xexchoffld !=
206562306a36Sopenharmony_ci				    vha->u_ql2xexchoffld) &&
206662306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
206762306a36Sopenharmony_ci				    eo_toggle)
206862306a36Sopenharmony_ci					/*
206962306a36Sopenharmony_ci					 * The number of exchange to be offload
207062306a36Sopenharmony_ci					 * was tweaked or offload option was
207162306a36Sopenharmony_ci					 * flipped
207262306a36Sopenharmony_ci					 */
207362306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
207462306a36Sopenharmony_ci				else
207562306a36Sopenharmony_ci					action = NO_ACTION;
207662306a36Sopenharmony_ci			} else
207762306a36Sopenharmony_ci				action = NO_ACTION;
207862306a36Sopenharmony_ci
207962306a36Sopenharmony_ci			break;
208062306a36Sopenharmony_ci
208162306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DISABLED:
208262306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
208362306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) !=
208462306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
208562306a36Sopenharmony_ci					eo_toggle = 1;
208662306a36Sopenharmony_ci				if (((vha->ql2xexchoffld !=
208762306a36Sopenharmony_ci				      vha->u_ql2xexchoffld) &&
208862306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) ||
208962306a36Sopenharmony_ci				    eo_toggle)
209062306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
209162306a36Sopenharmony_ci				else
209262306a36Sopenharmony_ci					action = MODE_CHANGE_NO_ACTION;
209362306a36Sopenharmony_ci			} else
209462306a36Sopenharmony_ci				action = MODE_CHANGE_NO_ACTION;
209562306a36Sopenharmony_ci			break;
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DUAL: /* exclusive -> dual */
209862306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha)) {
209962306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
210062306a36Sopenharmony_ci				set_mode = 1;
210162306a36Sopenharmony_ci			} else
210262306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
210362306a36Sopenharmony_ci			break;
210462306a36Sopenharmony_ci
210562306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_ENABLED:
210662306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha))
210762306a36Sopenharmony_ci				action = TARGET_STILL_ACTIVE;
210862306a36Sopenharmony_ci			else {
210962306a36Sopenharmony_ci				if (vha->hw->flags.fw_started)
211062306a36Sopenharmony_ci					action = MODE_CHANGE_NO_ACTION;
211162306a36Sopenharmony_ci				else
211262306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
211362306a36Sopenharmony_ci			}
211462306a36Sopenharmony_ci			break;
211562306a36Sopenharmony_ci		}
211662306a36Sopenharmony_ci		break;
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_ENABLED:
211962306a36Sopenharmony_ci		switch (op) {
212062306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_ENABLED:
212162306a36Sopenharmony_ci			if (NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg) !=
212262306a36Sopenharmony_ci			    vha->hw->flags.exchoffld_enabled)
212362306a36Sopenharmony_ci				eo_toggle = 1;
212462306a36Sopenharmony_ci			if (((vha->ql2xiniexchg != vha->u_ql2xiniexchg) &&
212562306a36Sopenharmony_ci				NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg)) ||
212662306a36Sopenharmony_ci			    eo_toggle)
212762306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
212862306a36Sopenharmony_ci			else
212962306a36Sopenharmony_ci				action = NO_ACTION;
213062306a36Sopenharmony_ci			break;
213162306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DUAL:
213262306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DISABLED:
213362306a36Sopenharmony_ci			action = MODE_CHANGE_ACCEPT;
213462306a36Sopenharmony_ci			break;
213562306a36Sopenharmony_ci		default:
213662306a36Sopenharmony_ci			action = MODE_CHANGE_NO_ACTION;
213762306a36Sopenharmony_ci			break;
213862306a36Sopenharmony_ci		}
213962306a36Sopenharmony_ci		break;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	case QLA2XXX_INI_MODE_DUAL:
214262306a36Sopenharmony_ci		switch (op) {
214362306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DUAL:
214462306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha) ||
214562306a36Sopenharmony_ci			    qla_dual_mode_enabled(vha)) {
214662306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
214762306a36Sopenharmony_ci					vha->u_ql2xiniexchg) !=
214862306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
214962306a36Sopenharmony_ci					eo_toggle = 1;
215062306a36Sopenharmony_ci
215162306a36Sopenharmony_ci				if ((((vha->ql2xexchoffld +
215262306a36Sopenharmony_ci				       vha->ql2xiniexchg) !=
215362306a36Sopenharmony_ci				    (vha->u_ql2xiniexchg +
215462306a36Sopenharmony_ci				     vha->u_ql2xexchoffld)) &&
215562306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
215662306a36Sopenharmony_ci					vha->u_ql2xexchoffld)) || eo_toggle)
215762306a36Sopenharmony_ci					action = MODE_CHANGE_ACCEPT;
215862306a36Sopenharmony_ci				else
215962306a36Sopenharmony_ci					action = NO_ACTION;
216062306a36Sopenharmony_ci			} else {
216162306a36Sopenharmony_ci				if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld +
216262306a36Sopenharmony_ci					vha->u_ql2xiniexchg) !=
216362306a36Sopenharmony_ci				    vha->hw->flags.exchoffld_enabled)
216462306a36Sopenharmony_ci					eo_toggle = 1;
216562306a36Sopenharmony_ci
216662306a36Sopenharmony_ci				if ((((vha->ql2xexchoffld + vha->ql2xiniexchg)
216762306a36Sopenharmony_ci				    != (vha->u_ql2xiniexchg +
216862306a36Sopenharmony_ci					vha->u_ql2xexchoffld)) &&
216962306a36Sopenharmony_ci				    NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg +
217062306a36Sopenharmony_ci					vha->u_ql2xexchoffld)) || eo_toggle)
217162306a36Sopenharmony_ci					action = MODE_CHANGE_NO_ACTION;
217262306a36Sopenharmony_ci				else
217362306a36Sopenharmony_ci					action = NO_ACTION;
217462306a36Sopenharmony_ci			}
217562306a36Sopenharmony_ci			break;
217662306a36Sopenharmony_ci
217762306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_DISABLED:
217862306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha) ||
217962306a36Sopenharmony_ci			    qla_dual_mode_enabled(vha)) {
218062306a36Sopenharmony_ci				/* turning off initiator mode */
218162306a36Sopenharmony_ci				set_mode = 1;
218262306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
218362306a36Sopenharmony_ci			} else {
218462306a36Sopenharmony_ci				action = MODE_CHANGE_NO_ACTION;
218562306a36Sopenharmony_ci			}
218662306a36Sopenharmony_ci			break;
218762306a36Sopenharmony_ci
218862306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_EXCLUSIVE:
218962306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha) ||
219062306a36Sopenharmony_ci			    qla_dual_mode_enabled(vha)) {
219162306a36Sopenharmony_ci				set_mode = 1;
219262306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
219362306a36Sopenharmony_ci			} else {
219462306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
219562306a36Sopenharmony_ci			}
219662306a36Sopenharmony_ci			break;
219762306a36Sopenharmony_ci
219862306a36Sopenharmony_ci		case QLA2XXX_INI_MODE_ENABLED:
219962306a36Sopenharmony_ci			if (qla_tgt_mode_enabled(vha) ||
220062306a36Sopenharmony_ci			    qla_dual_mode_enabled(vha)) {
220162306a36Sopenharmony_ci				action = TARGET_STILL_ACTIVE;
220262306a36Sopenharmony_ci			} else {
220362306a36Sopenharmony_ci				action = MODE_CHANGE_ACCEPT;
220462306a36Sopenharmony_ci			}
220562306a36Sopenharmony_ci		}
220662306a36Sopenharmony_ci		break;
220762306a36Sopenharmony_ci	}
220862306a36Sopenharmony_ci
220962306a36Sopenharmony_ci	switch (action) {
221062306a36Sopenharmony_ci	case MODE_CHANGE_ACCEPT:
221162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xffff,
221262306a36Sopenharmony_ci		    "Mode change accepted. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
221362306a36Sopenharmony_ci		    mode_to_str[vha->qlini_mode], mode_to_str[op],
221462306a36Sopenharmony_ci		    vha->ql2xexchoffld, vha->u_ql2xexchoffld,
221562306a36Sopenharmony_ci		    vha->ql2xiniexchg, vha->u_ql2xiniexchg);
221662306a36Sopenharmony_ci
221762306a36Sopenharmony_ci		vha->qlini_mode = op;
221862306a36Sopenharmony_ci		vha->ql2xexchoffld = vha->u_ql2xexchoffld;
221962306a36Sopenharmony_ci		vha->ql2xiniexchg = vha->u_ql2xiniexchg;
222062306a36Sopenharmony_ci		if (set_mode)
222162306a36Sopenharmony_ci			qlt_set_mode(vha);
222262306a36Sopenharmony_ci		vha->flags.online = 1;
222362306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
222462306a36Sopenharmony_ci		break;
222562306a36Sopenharmony_ci
222662306a36Sopenharmony_ci	case MODE_CHANGE_NO_ACTION:
222762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xffff,
222862306a36Sopenharmony_ci		    "Mode is set. No action taken. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n",
222962306a36Sopenharmony_ci		    mode_to_str[vha->qlini_mode], mode_to_str[op],
223062306a36Sopenharmony_ci		    vha->ql2xexchoffld, vha->u_ql2xexchoffld,
223162306a36Sopenharmony_ci		    vha->ql2xiniexchg, vha->u_ql2xiniexchg);
223262306a36Sopenharmony_ci		vha->qlini_mode = op;
223362306a36Sopenharmony_ci		vha->ql2xexchoffld = vha->u_ql2xexchoffld;
223462306a36Sopenharmony_ci		vha->ql2xiniexchg = vha->u_ql2xiniexchg;
223562306a36Sopenharmony_ci		break;
223662306a36Sopenharmony_ci
223762306a36Sopenharmony_ci	case TARGET_STILL_ACTIVE:
223862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xffff,
223962306a36Sopenharmony_ci		    "Target Mode is active. Unable to change Mode.\n");
224062306a36Sopenharmony_ci		break;
224162306a36Sopenharmony_ci
224262306a36Sopenharmony_ci	case NO_ACTION:
224362306a36Sopenharmony_ci	default:
224462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xffff,
224562306a36Sopenharmony_ci		    "Mode unchange. No action taken. %d|%d pct %d|%d.\n",
224662306a36Sopenharmony_ci		    vha->qlini_mode, op,
224762306a36Sopenharmony_ci		    vha->ql2xexchoffld, vha->u_ql2xexchoffld);
224862306a36Sopenharmony_ci		break;
224962306a36Sopenharmony_ci	}
225062306a36Sopenharmony_ci}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_cistatic ssize_t
225362306a36Sopenharmony_ciqlini_mode_store(struct device *dev, struct device_attribute *attr,
225462306a36Sopenharmony_ci    const char *buf, size_t count)
225562306a36Sopenharmony_ci{
225662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
225762306a36Sopenharmony_ci	int ini;
225862306a36Sopenharmony_ci
225962306a36Sopenharmony_ci	if (!buf)
226062306a36Sopenharmony_ci		return -EINVAL;
226162306a36Sopenharmony_ci
226262306a36Sopenharmony_ci	if (strncasecmp(QLA2XXX_INI_MODE_STR_EXCLUSIVE, buf,
226362306a36Sopenharmony_ci		strlen(QLA2XXX_INI_MODE_STR_EXCLUSIVE)) == 0)
226462306a36Sopenharmony_ci		ini = QLA2XXX_INI_MODE_EXCLUSIVE;
226562306a36Sopenharmony_ci	else if (strncasecmp(QLA2XXX_INI_MODE_STR_DISABLED, buf,
226662306a36Sopenharmony_ci		strlen(QLA2XXX_INI_MODE_STR_DISABLED)) == 0)
226762306a36Sopenharmony_ci		ini = QLA2XXX_INI_MODE_DISABLED;
226862306a36Sopenharmony_ci	else if (strncasecmp(QLA2XXX_INI_MODE_STR_ENABLED, buf,
226962306a36Sopenharmony_ci		  strlen(QLA2XXX_INI_MODE_STR_ENABLED)) == 0)
227062306a36Sopenharmony_ci		ini = QLA2XXX_INI_MODE_ENABLED;
227162306a36Sopenharmony_ci	else if (strncasecmp(QLA2XXX_INI_MODE_STR_DUAL, buf,
227262306a36Sopenharmony_ci		strlen(QLA2XXX_INI_MODE_STR_DUAL)) == 0)
227362306a36Sopenharmony_ci		ini = QLA2XXX_INI_MODE_DUAL;
227462306a36Sopenharmony_ci	else
227562306a36Sopenharmony_ci		return -EINVAL;
227662306a36Sopenharmony_ci
227762306a36Sopenharmony_ci	qla_set_ini_mode(vha, ini);
227862306a36Sopenharmony_ci	return strlen(buf);
227962306a36Sopenharmony_ci}
228062306a36Sopenharmony_ci
228162306a36Sopenharmony_cistatic ssize_t
228262306a36Sopenharmony_ciql2xexchoffld_show(struct device *dev, struct device_attribute *attr,
228362306a36Sopenharmony_ci    char *buf)
228462306a36Sopenharmony_ci{
228562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
228662306a36Sopenharmony_ci	int len = 0;
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len,
228962306a36Sopenharmony_ci		"target exchange: new %d : current: %d\n\n",
229062306a36Sopenharmony_ci		vha->u_ql2xexchoffld, vha->ql2xexchoffld);
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len,
229362306a36Sopenharmony_ci	    "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
229462306a36Sopenharmony_ci	    vha->host_no);
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci	return len;
229762306a36Sopenharmony_ci}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_cistatic ssize_t
230062306a36Sopenharmony_ciql2xexchoffld_store(struct device *dev, struct device_attribute *attr,
230162306a36Sopenharmony_ci    const char *buf, size_t count)
230262306a36Sopenharmony_ci{
230362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
230462306a36Sopenharmony_ci	int val = 0;
230562306a36Sopenharmony_ci
230662306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
230762306a36Sopenharmony_ci		return -EINVAL;
230862306a36Sopenharmony_ci
230962306a36Sopenharmony_ci	if (val > FW_MAX_EXCHANGES_CNT)
231062306a36Sopenharmony_ci		val = FW_MAX_EXCHANGES_CNT;
231162306a36Sopenharmony_ci	else if (val < 0)
231262306a36Sopenharmony_ci		val = 0;
231362306a36Sopenharmony_ci
231462306a36Sopenharmony_ci	vha->u_ql2xexchoffld = val;
231562306a36Sopenharmony_ci	return strlen(buf);
231662306a36Sopenharmony_ci}
231762306a36Sopenharmony_ci
231862306a36Sopenharmony_cistatic ssize_t
231962306a36Sopenharmony_ciql2xiniexchg_show(struct device *dev, struct device_attribute *attr,
232062306a36Sopenharmony_ci    char *buf)
232162306a36Sopenharmony_ci{
232262306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
232362306a36Sopenharmony_ci	int len = 0;
232462306a36Sopenharmony_ci
232562306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len,
232662306a36Sopenharmony_ci		"target exchange: new %d : current: %d\n\n",
232762306a36Sopenharmony_ci		vha->u_ql2xiniexchg, vha->ql2xiniexchg);
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	len += scnprintf(buf + len, PAGE_SIZE-len,
233062306a36Sopenharmony_ci	    "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n",
233162306a36Sopenharmony_ci	    vha->host_no);
233262306a36Sopenharmony_ci
233362306a36Sopenharmony_ci	return len;
233462306a36Sopenharmony_ci}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_cistatic ssize_t
233762306a36Sopenharmony_ciql2xiniexchg_store(struct device *dev, struct device_attribute *attr,
233862306a36Sopenharmony_ci    const char *buf, size_t count)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
234162306a36Sopenharmony_ci	int val = 0;
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	if (sscanf(buf, "%d", &val) != 1)
234462306a36Sopenharmony_ci		return -EINVAL;
234562306a36Sopenharmony_ci
234662306a36Sopenharmony_ci	if (val > FW_MAX_EXCHANGES_CNT)
234762306a36Sopenharmony_ci		val = FW_MAX_EXCHANGES_CNT;
234862306a36Sopenharmony_ci	else if (val < 0)
234962306a36Sopenharmony_ci		val = 0;
235062306a36Sopenharmony_ci
235162306a36Sopenharmony_ci	vha->u_ql2xiniexchg = val;
235262306a36Sopenharmony_ci	return strlen(buf);
235362306a36Sopenharmony_ci}
235462306a36Sopenharmony_ci
235562306a36Sopenharmony_cistatic ssize_t
235662306a36Sopenharmony_ciqla2x00_dif_bundle_statistics_show(struct device *dev,
235762306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
235862306a36Sopenharmony_ci{
235962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
236062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE,
236362306a36Sopenharmony_ci	    "cross=%llu read=%llu write=%llu kalloc=%llu dma_alloc=%llu unusable=%u\n",
236462306a36Sopenharmony_ci	    ha->dif_bundle_crossed_pages, ha->dif_bundle_reads,
236562306a36Sopenharmony_ci	    ha->dif_bundle_writes, ha->dif_bundle_kallocs,
236662306a36Sopenharmony_ci	    ha->dif_bundle_dma_allocs, ha->pool.unusable.count);
236762306a36Sopenharmony_ci}
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_cistatic ssize_t
237062306a36Sopenharmony_ciqla2x00_fw_attr_show(struct device *dev,
237162306a36Sopenharmony_ci    struct device_attribute *attr, char *buf)
237262306a36Sopenharmony_ci{
237362306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
237462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
237762306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
237862306a36Sopenharmony_ci
237962306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%llx\n",
238062306a36Sopenharmony_ci	    (uint64_t)ha->fw_attributes_ext[1] << 48 |
238162306a36Sopenharmony_ci	    (uint64_t)ha->fw_attributes_ext[0] << 32 |
238262306a36Sopenharmony_ci	    (uint64_t)ha->fw_attributes_h << 16 |
238362306a36Sopenharmony_ci	    (uint64_t)ha->fw_attributes);
238462306a36Sopenharmony_ci}
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_cistatic ssize_t
238762306a36Sopenharmony_ciqla2x00_port_no_show(struct device *dev, struct device_attribute *attr,
238862306a36Sopenharmony_ci    char *buf)
238962306a36Sopenharmony_ci{
239062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%u\n", vha->hw->port_no);
239362306a36Sopenharmony_ci}
239462306a36Sopenharmony_ci
239562306a36Sopenharmony_cistatic ssize_t
239662306a36Sopenharmony_ciqla2x00_dport_diagnostics_show(struct device *dev,
239762306a36Sopenharmony_ci	struct device_attribute *attr, char *buf)
239862306a36Sopenharmony_ci{
239962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(class_to_shost(dev));
240062306a36Sopenharmony_ci
240162306a36Sopenharmony_ci	if (!IS_QLA83XX(vha->hw) && !IS_QLA27XX(vha->hw) &&
240262306a36Sopenharmony_ci	    !IS_QLA28XX(vha->hw))
240362306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
240462306a36Sopenharmony_ci
240562306a36Sopenharmony_ci	if (!*vha->dport_data)
240662306a36Sopenharmony_ci		return scnprintf(buf, PAGE_SIZE, "\n");
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%04x %04x %04x %04x\n",
240962306a36Sopenharmony_ci	    vha->dport_data[0], vha->dport_data[1],
241062306a36Sopenharmony_ci	    vha->dport_data[2], vha->dport_data[3]);
241162306a36Sopenharmony_ci}
241262306a36Sopenharmony_cistatic DEVICE_ATTR(dport_diagnostics, 0444,
241362306a36Sopenharmony_ci	   qla2x00_dport_diagnostics_show, NULL);
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_cistatic DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL);
241662306a36Sopenharmony_cistatic DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL);
241762306a36Sopenharmony_cistatic DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL);
241862306a36Sopenharmony_cistatic DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL);
241962306a36Sopenharmony_cistatic DEVICE_ATTR(isp_id, S_IRUGO, qla2x00_isp_id_show, NULL);
242062306a36Sopenharmony_cistatic DEVICE_ATTR(model_name, S_IRUGO, qla2x00_model_name_show, NULL);
242162306a36Sopenharmony_cistatic DEVICE_ATTR(model_desc, S_IRUGO, qla2x00_model_desc_show, NULL);
242262306a36Sopenharmony_cistatic DEVICE_ATTR(pci_info, S_IRUGO, qla2x00_pci_info_show, NULL);
242362306a36Sopenharmony_cistatic DEVICE_ATTR(link_state, S_IRUGO, qla2x00_link_state_show, NULL);
242462306a36Sopenharmony_cistatic DEVICE_ATTR(zio, S_IRUGO | S_IWUSR, qla2x00_zio_show, qla2x00_zio_store);
242562306a36Sopenharmony_cistatic DEVICE_ATTR(zio_timer, S_IRUGO | S_IWUSR, qla2x00_zio_timer_show,
242662306a36Sopenharmony_ci		   qla2x00_zio_timer_store);
242762306a36Sopenharmony_cistatic DEVICE_ATTR(beacon, S_IRUGO | S_IWUSR, qla2x00_beacon_show,
242862306a36Sopenharmony_ci		   qla2x00_beacon_store);
242962306a36Sopenharmony_cistatic DEVICE_ATTR(beacon_config, 0644, qla2x00_beacon_config_show,
243062306a36Sopenharmony_ci		   qla2x00_beacon_config_store);
243162306a36Sopenharmony_cistatic DEVICE_ATTR(optrom_bios_version, S_IRUGO,
243262306a36Sopenharmony_ci		   qla2x00_optrom_bios_version_show, NULL);
243362306a36Sopenharmony_cistatic DEVICE_ATTR(optrom_efi_version, S_IRUGO,
243462306a36Sopenharmony_ci		   qla2x00_optrom_efi_version_show, NULL);
243562306a36Sopenharmony_cistatic DEVICE_ATTR(optrom_fcode_version, S_IRUGO,
243662306a36Sopenharmony_ci		   qla2x00_optrom_fcode_version_show, NULL);
243762306a36Sopenharmony_cistatic DEVICE_ATTR(optrom_fw_version, S_IRUGO, qla2x00_optrom_fw_version_show,
243862306a36Sopenharmony_ci		   NULL);
243962306a36Sopenharmony_cistatic DEVICE_ATTR(optrom_gold_fw_version, S_IRUGO,
244062306a36Sopenharmony_ci    qla2x00_optrom_gold_fw_version_show, NULL);
244162306a36Sopenharmony_cistatic DEVICE_ATTR(84xx_fw_version, S_IRUGO, qla24xx_84xx_fw_version_show,
244262306a36Sopenharmony_ci		   NULL);
244362306a36Sopenharmony_cistatic DEVICE_ATTR(total_isp_aborts, S_IRUGO, qla2x00_total_isp_aborts_show,
244462306a36Sopenharmony_ci		   NULL);
244562306a36Sopenharmony_cistatic DEVICE_ATTR(serdes_version, 0444, qla2x00_serdes_version_show, NULL);
244662306a36Sopenharmony_cistatic DEVICE_ATTR(mpi_version, S_IRUGO, qla2x00_mpi_version_show, NULL);
244762306a36Sopenharmony_cistatic DEVICE_ATTR(phy_version, S_IRUGO, qla2x00_phy_version_show, NULL);
244862306a36Sopenharmony_cistatic DEVICE_ATTR(flash_block_size, S_IRUGO, qla2x00_flash_block_size_show,
244962306a36Sopenharmony_ci		   NULL);
245062306a36Sopenharmony_cistatic DEVICE_ATTR(vlan_id, S_IRUGO, qla2x00_vlan_id_show, NULL);
245162306a36Sopenharmony_cistatic DEVICE_ATTR(vn_port_mac_address, S_IRUGO,
245262306a36Sopenharmony_ci		   qla2x00_vn_port_mac_address_show, NULL);
245362306a36Sopenharmony_cistatic DEVICE_ATTR(fabric_param, S_IRUGO, qla2x00_fabric_param_show, NULL);
245462306a36Sopenharmony_cistatic DEVICE_ATTR(fw_state, S_IRUGO, qla2x00_fw_state_show, NULL);
245562306a36Sopenharmony_cistatic DEVICE_ATTR(thermal_temp, S_IRUGO, qla2x00_thermal_temp_show, NULL);
245662306a36Sopenharmony_cistatic DEVICE_ATTR(diag_requests, S_IRUGO, qla2x00_diag_requests_show, NULL);
245762306a36Sopenharmony_cistatic DEVICE_ATTR(diag_megabytes, S_IRUGO, qla2x00_diag_megabytes_show, NULL);
245862306a36Sopenharmony_cistatic DEVICE_ATTR(fw_dump_size, S_IRUGO, qla2x00_fw_dump_size_show, NULL);
245962306a36Sopenharmony_cistatic DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR,
246062306a36Sopenharmony_ci		   qla2x00_allow_cna_fw_dump_show,
246162306a36Sopenharmony_ci		   qla2x00_allow_cna_fw_dump_store);
246262306a36Sopenharmony_cistatic DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL);
246362306a36Sopenharmony_cistatic DEVICE_ATTR(min_supported_speed, 0444,
246462306a36Sopenharmony_ci		   qla2x00_min_supported_speed_show, NULL);
246562306a36Sopenharmony_cistatic DEVICE_ATTR(max_supported_speed, 0444,
246662306a36Sopenharmony_ci		   qla2x00_max_supported_speed_show, NULL);
246762306a36Sopenharmony_cistatic DEVICE_ATTR(zio_threshold, 0644,
246862306a36Sopenharmony_ci    qla_zio_threshold_show,
246962306a36Sopenharmony_ci    qla_zio_threshold_store);
247062306a36Sopenharmony_cistatic DEVICE_ATTR_RW(qlini_mode);
247162306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ql2xexchoffld);
247262306a36Sopenharmony_cistatic DEVICE_ATTR_RW(ql2xiniexchg);
247362306a36Sopenharmony_cistatic DEVICE_ATTR(dif_bundle_statistics, 0444,
247462306a36Sopenharmony_ci    qla2x00_dif_bundle_statistics_show, NULL);
247562306a36Sopenharmony_cistatic DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show,
247662306a36Sopenharmony_ci    qla2x00_port_speed_store);
247762306a36Sopenharmony_cistatic DEVICE_ATTR(port_no, 0444, qla2x00_port_no_show, NULL);
247862306a36Sopenharmony_cistatic DEVICE_ATTR(fw_attr, 0444, qla2x00_fw_attr_show, NULL);
247962306a36Sopenharmony_ci
248062306a36Sopenharmony_cistatic struct attribute *qla2x00_host_attrs[] = {
248162306a36Sopenharmony_ci	&dev_attr_driver_version.attr,
248262306a36Sopenharmony_ci	&dev_attr_fw_version.attr,
248362306a36Sopenharmony_ci	&dev_attr_serial_num.attr,
248462306a36Sopenharmony_ci	&dev_attr_isp_name.attr,
248562306a36Sopenharmony_ci	&dev_attr_isp_id.attr,
248662306a36Sopenharmony_ci	&dev_attr_model_name.attr,
248762306a36Sopenharmony_ci	&dev_attr_model_desc.attr,
248862306a36Sopenharmony_ci	&dev_attr_pci_info.attr,
248962306a36Sopenharmony_ci	&dev_attr_link_state.attr,
249062306a36Sopenharmony_ci	&dev_attr_zio.attr,
249162306a36Sopenharmony_ci	&dev_attr_zio_timer.attr,
249262306a36Sopenharmony_ci	&dev_attr_beacon.attr,
249362306a36Sopenharmony_ci	&dev_attr_beacon_config.attr,
249462306a36Sopenharmony_ci	&dev_attr_optrom_bios_version.attr,
249562306a36Sopenharmony_ci	&dev_attr_optrom_efi_version.attr,
249662306a36Sopenharmony_ci	&dev_attr_optrom_fcode_version.attr,
249762306a36Sopenharmony_ci	&dev_attr_optrom_fw_version.attr,
249862306a36Sopenharmony_ci	&dev_attr_84xx_fw_version.attr,
249962306a36Sopenharmony_ci	&dev_attr_total_isp_aborts.attr,
250062306a36Sopenharmony_ci	&dev_attr_serdes_version.attr,
250162306a36Sopenharmony_ci	&dev_attr_mpi_version.attr,
250262306a36Sopenharmony_ci	&dev_attr_phy_version.attr,
250362306a36Sopenharmony_ci	&dev_attr_flash_block_size.attr,
250462306a36Sopenharmony_ci	&dev_attr_vlan_id.attr,
250562306a36Sopenharmony_ci	&dev_attr_vn_port_mac_address.attr,
250662306a36Sopenharmony_ci	&dev_attr_fabric_param.attr,
250762306a36Sopenharmony_ci	&dev_attr_fw_state.attr,
250862306a36Sopenharmony_ci	&dev_attr_optrom_gold_fw_version.attr,
250962306a36Sopenharmony_ci	&dev_attr_thermal_temp.attr,
251062306a36Sopenharmony_ci	&dev_attr_diag_requests.attr,
251162306a36Sopenharmony_ci	&dev_attr_diag_megabytes.attr,
251262306a36Sopenharmony_ci	&dev_attr_fw_dump_size.attr,
251362306a36Sopenharmony_ci	&dev_attr_allow_cna_fw_dump.attr,
251462306a36Sopenharmony_ci	&dev_attr_pep_version.attr,
251562306a36Sopenharmony_ci	&dev_attr_min_supported_speed.attr,
251662306a36Sopenharmony_ci	&dev_attr_max_supported_speed.attr,
251762306a36Sopenharmony_ci	&dev_attr_zio_threshold.attr,
251862306a36Sopenharmony_ci	&dev_attr_dif_bundle_statistics.attr,
251962306a36Sopenharmony_ci	&dev_attr_port_speed.attr,
252062306a36Sopenharmony_ci	&dev_attr_port_no.attr,
252162306a36Sopenharmony_ci	&dev_attr_fw_attr.attr,
252262306a36Sopenharmony_ci	&dev_attr_dport_diagnostics.attr,
252362306a36Sopenharmony_ci	&dev_attr_mpi_pause.attr,
252462306a36Sopenharmony_ci	&dev_attr_qlini_mode.attr,
252562306a36Sopenharmony_ci	&dev_attr_ql2xiniexchg.attr,
252662306a36Sopenharmony_ci	&dev_attr_ql2xexchoffld.attr,
252762306a36Sopenharmony_ci	NULL,
252862306a36Sopenharmony_ci};
252962306a36Sopenharmony_ci
253062306a36Sopenharmony_cistatic umode_t qla_host_attr_is_visible(struct kobject *kobj,
253162306a36Sopenharmony_ci					struct attribute *attr, int i)
253262306a36Sopenharmony_ci{
253362306a36Sopenharmony_ci	if (ql2x_ini_mode != QLA2XXX_INI_MODE_DUAL &&
253462306a36Sopenharmony_ci	    (attr == &dev_attr_qlini_mode.attr ||
253562306a36Sopenharmony_ci	     attr == &dev_attr_ql2xiniexchg.attr ||
253662306a36Sopenharmony_ci	     attr == &dev_attr_ql2xexchoffld.attr))
253762306a36Sopenharmony_ci		return 0;
253862306a36Sopenharmony_ci	return attr->mode;
253962306a36Sopenharmony_ci}
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_cistatic const struct attribute_group qla2x00_host_attr_group = {
254262306a36Sopenharmony_ci	.is_visible = qla_host_attr_is_visible,
254362306a36Sopenharmony_ci	.attrs = qla2x00_host_attrs
254462306a36Sopenharmony_ci};
254562306a36Sopenharmony_ci
254662306a36Sopenharmony_ciconst struct attribute_group *qla2x00_host_groups[] = {
254762306a36Sopenharmony_ci	&qla2x00_host_attr_group,
254862306a36Sopenharmony_ci	NULL
254962306a36Sopenharmony_ci};
255062306a36Sopenharmony_ci
255162306a36Sopenharmony_ci/* Host attributes. */
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_cistatic void
255462306a36Sopenharmony_ciqla2x00_get_host_port_id(struct Scsi_Host *shost)
255562306a36Sopenharmony_ci{
255662306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_ci	fc_host_port_id(shost) = vha->d_id.b.domain << 16 |
255962306a36Sopenharmony_ci	    vha->d_id.b.area << 8 | vha->d_id.b.al_pa;
256062306a36Sopenharmony_ci}
256162306a36Sopenharmony_ci
256262306a36Sopenharmony_cistatic void
256362306a36Sopenharmony_ciqla2x00_get_host_speed(struct Scsi_Host *shost)
256462306a36Sopenharmony_ci{
256562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
256662306a36Sopenharmony_ci	u32 speed;
256762306a36Sopenharmony_ci
256862306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw)) {
256962306a36Sopenharmony_ci		qlafx00_get_host_speed(shost);
257062306a36Sopenharmony_ci		return;
257162306a36Sopenharmony_ci	}
257262306a36Sopenharmony_ci
257362306a36Sopenharmony_ci	switch (vha->hw->link_data_rate) {
257462306a36Sopenharmony_ci	case PORT_SPEED_1GB:
257562306a36Sopenharmony_ci		speed = FC_PORTSPEED_1GBIT;
257662306a36Sopenharmony_ci		break;
257762306a36Sopenharmony_ci	case PORT_SPEED_2GB:
257862306a36Sopenharmony_ci		speed = FC_PORTSPEED_2GBIT;
257962306a36Sopenharmony_ci		break;
258062306a36Sopenharmony_ci	case PORT_SPEED_4GB:
258162306a36Sopenharmony_ci		speed = FC_PORTSPEED_4GBIT;
258262306a36Sopenharmony_ci		break;
258362306a36Sopenharmony_ci	case PORT_SPEED_8GB:
258462306a36Sopenharmony_ci		speed = FC_PORTSPEED_8GBIT;
258562306a36Sopenharmony_ci		break;
258662306a36Sopenharmony_ci	case PORT_SPEED_10GB:
258762306a36Sopenharmony_ci		speed = FC_PORTSPEED_10GBIT;
258862306a36Sopenharmony_ci		break;
258962306a36Sopenharmony_ci	case PORT_SPEED_16GB:
259062306a36Sopenharmony_ci		speed = FC_PORTSPEED_16GBIT;
259162306a36Sopenharmony_ci		break;
259262306a36Sopenharmony_ci	case PORT_SPEED_32GB:
259362306a36Sopenharmony_ci		speed = FC_PORTSPEED_32GBIT;
259462306a36Sopenharmony_ci		break;
259562306a36Sopenharmony_ci	case PORT_SPEED_64GB:
259662306a36Sopenharmony_ci		speed = FC_PORTSPEED_64GBIT;
259762306a36Sopenharmony_ci		break;
259862306a36Sopenharmony_ci	default:
259962306a36Sopenharmony_ci		speed = FC_PORTSPEED_UNKNOWN;
260062306a36Sopenharmony_ci		break;
260162306a36Sopenharmony_ci	}
260262306a36Sopenharmony_ci
260362306a36Sopenharmony_ci	fc_host_speed(shost) = speed;
260462306a36Sopenharmony_ci}
260562306a36Sopenharmony_ci
260662306a36Sopenharmony_cistatic void
260762306a36Sopenharmony_ciqla2x00_get_host_port_type(struct Scsi_Host *shost)
260862306a36Sopenharmony_ci{
260962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
261062306a36Sopenharmony_ci	uint32_t port_type;
261162306a36Sopenharmony_ci
261262306a36Sopenharmony_ci	if (vha->vp_idx) {
261362306a36Sopenharmony_ci		fc_host_port_type(shost) = FC_PORTTYPE_NPIV;
261462306a36Sopenharmony_ci		return;
261562306a36Sopenharmony_ci	}
261662306a36Sopenharmony_ci	switch (vha->hw->current_topology) {
261762306a36Sopenharmony_ci	case ISP_CFG_NL:
261862306a36Sopenharmony_ci		port_type = FC_PORTTYPE_LPORT;
261962306a36Sopenharmony_ci		break;
262062306a36Sopenharmony_ci	case ISP_CFG_FL:
262162306a36Sopenharmony_ci		port_type = FC_PORTTYPE_NLPORT;
262262306a36Sopenharmony_ci		break;
262362306a36Sopenharmony_ci	case ISP_CFG_N:
262462306a36Sopenharmony_ci		port_type = FC_PORTTYPE_PTP;
262562306a36Sopenharmony_ci		break;
262662306a36Sopenharmony_ci	case ISP_CFG_F:
262762306a36Sopenharmony_ci		port_type = FC_PORTTYPE_NPORT;
262862306a36Sopenharmony_ci		break;
262962306a36Sopenharmony_ci	default:
263062306a36Sopenharmony_ci		port_type = FC_PORTTYPE_UNKNOWN;
263162306a36Sopenharmony_ci		break;
263262306a36Sopenharmony_ci	}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_ci	fc_host_port_type(shost) = port_type;
263562306a36Sopenharmony_ci}
263662306a36Sopenharmony_ci
263762306a36Sopenharmony_cistatic void
263862306a36Sopenharmony_ciqla2x00_get_starget_node_name(struct scsi_target *starget)
263962306a36Sopenharmony_ci{
264062306a36Sopenharmony_ci	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
264162306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
264262306a36Sopenharmony_ci	fc_port_t *fcport;
264362306a36Sopenharmony_ci	u64 node_name = 0;
264462306a36Sopenharmony_ci
264562306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
264662306a36Sopenharmony_ci		if (fcport->rport &&
264762306a36Sopenharmony_ci		    starget->id == fcport->rport->scsi_target_id) {
264862306a36Sopenharmony_ci			node_name = wwn_to_u64(fcport->node_name);
264962306a36Sopenharmony_ci			break;
265062306a36Sopenharmony_ci		}
265162306a36Sopenharmony_ci	}
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	fc_starget_node_name(starget) = node_name;
265462306a36Sopenharmony_ci}
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_cistatic void
265762306a36Sopenharmony_ciqla2x00_get_starget_port_name(struct scsi_target *starget)
265862306a36Sopenharmony_ci{
265962306a36Sopenharmony_ci	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
266062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
266162306a36Sopenharmony_ci	fc_port_t *fcport;
266262306a36Sopenharmony_ci	u64 port_name = 0;
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
266562306a36Sopenharmony_ci		if (fcport->rport &&
266662306a36Sopenharmony_ci		    starget->id == fcport->rport->scsi_target_id) {
266762306a36Sopenharmony_ci			port_name = wwn_to_u64(fcport->port_name);
266862306a36Sopenharmony_ci			break;
266962306a36Sopenharmony_ci		}
267062306a36Sopenharmony_ci	}
267162306a36Sopenharmony_ci
267262306a36Sopenharmony_ci	fc_starget_port_name(starget) = port_name;
267362306a36Sopenharmony_ci}
267462306a36Sopenharmony_ci
267562306a36Sopenharmony_cistatic void
267662306a36Sopenharmony_ciqla2x00_get_starget_port_id(struct scsi_target *starget)
267762306a36Sopenharmony_ci{
267862306a36Sopenharmony_ci	struct Scsi_Host *host = dev_to_shost(starget->dev.parent);
267962306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(host);
268062306a36Sopenharmony_ci	fc_port_t *fcport;
268162306a36Sopenharmony_ci	uint32_t port_id = ~0U;
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci	list_for_each_entry(fcport, &vha->vp_fcports, list) {
268462306a36Sopenharmony_ci		if (fcport->rport &&
268562306a36Sopenharmony_ci		    starget->id == fcport->rport->scsi_target_id) {
268662306a36Sopenharmony_ci			port_id = fcport->d_id.b.domain << 16 |
268762306a36Sopenharmony_ci			    fcport->d_id.b.area << 8 | fcport->d_id.b.al_pa;
268862306a36Sopenharmony_ci			break;
268962306a36Sopenharmony_ci		}
269062306a36Sopenharmony_ci	}
269162306a36Sopenharmony_ci
269262306a36Sopenharmony_ci	fc_starget_port_id(starget) = port_id;
269362306a36Sopenharmony_ci}
269462306a36Sopenharmony_ci
269562306a36Sopenharmony_cistatic inline void
269662306a36Sopenharmony_ciqla2x00_set_rport_loss_tmo(struct fc_rport *rport, uint32_t timeout)
269762306a36Sopenharmony_ci{
269862306a36Sopenharmony_ci	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci	rport->dev_loss_tmo = timeout ? timeout : 1;
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci	if (IS_ENABLED(CONFIG_NVME_FC) && fcport && fcport->nvme_remote_port)
270362306a36Sopenharmony_ci		nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port,
270462306a36Sopenharmony_ci					       rport->dev_loss_tmo);
270562306a36Sopenharmony_ci}
270662306a36Sopenharmony_ci
270762306a36Sopenharmony_cistatic void
270862306a36Sopenharmony_ciqla2x00_dev_loss_tmo_callbk(struct fc_rport *rport)
270962306a36Sopenharmony_ci{
271062306a36Sopenharmony_ci	struct Scsi_Host *host = rport_to_shost(rport);
271162306a36Sopenharmony_ci	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
271262306a36Sopenharmony_ci	unsigned long flags;
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci	if (!fcport)
271562306a36Sopenharmony_ci		return;
271662306a36Sopenharmony_ci
271762306a36Sopenharmony_ci	ql_dbg(ql_dbg_async, fcport->vha, 0x5101,
271862306a36Sopenharmony_ci	       DBG_FCPORT_PRFMT(fcport, "dev_loss_tmo expiry, rport_state=%d",
271962306a36Sopenharmony_ci				rport->port_state));
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	/*
272262306a36Sopenharmony_ci	 * Now that the rport has been deleted, set the fcport state to
272362306a36Sopenharmony_ci	 * FCS_DEVICE_DEAD, if the fcport is still lost.
272462306a36Sopenharmony_ci	 */
272562306a36Sopenharmony_ci	if (fcport->scan_state != QLA_FCPORT_FOUND)
272662306a36Sopenharmony_ci		qla2x00_set_fcport_state(fcport, FCS_DEVICE_DEAD);
272762306a36Sopenharmony_ci
272862306a36Sopenharmony_ci	/*
272962306a36Sopenharmony_ci	 * Transport has effectively 'deleted' the rport, clear
273062306a36Sopenharmony_ci	 * all local references.
273162306a36Sopenharmony_ci	 */
273262306a36Sopenharmony_ci	spin_lock_irqsave(host->host_lock, flags);
273362306a36Sopenharmony_ci	/* Confirm port has not reappeared before clearing pointers. */
273462306a36Sopenharmony_ci	if (rport->port_state != FC_PORTSTATE_ONLINE) {
273562306a36Sopenharmony_ci		fcport->rport = NULL;
273662306a36Sopenharmony_ci		*((fc_port_t **)rport->dd_data) = NULL;
273762306a36Sopenharmony_ci	}
273862306a36Sopenharmony_ci	spin_unlock_irqrestore(host->host_lock, flags);
273962306a36Sopenharmony_ci
274062306a36Sopenharmony_ci	if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
274162306a36Sopenharmony_ci		return;
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
274462306a36Sopenharmony_ci		qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
274562306a36Sopenharmony_ci		return;
274662306a36Sopenharmony_ci	}
274762306a36Sopenharmony_ci}
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_cistatic void
275062306a36Sopenharmony_ciqla2x00_terminate_rport_io(struct fc_rport *rport)
275162306a36Sopenharmony_ci{
275262306a36Sopenharmony_ci	fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
275362306a36Sopenharmony_ci	scsi_qla_host_t *vha;
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci	if (!fcport)
275662306a36Sopenharmony_ci		return;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	if (test_bit(UNLOADING, &fcport->vha->dpc_flags))
275962306a36Sopenharmony_ci		return;
276062306a36Sopenharmony_ci
276162306a36Sopenharmony_ci	if (test_bit(ABORT_ISP_ACTIVE, &fcport->vha->dpc_flags))
276262306a36Sopenharmony_ci		return;
276362306a36Sopenharmony_ci	vha = fcport->vha;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(fcport->vha->hw->pdev))) {
276662306a36Sopenharmony_ci		qla2x00_abort_all_cmds(fcport->vha, DID_NO_CONNECT << 16);
276762306a36Sopenharmony_ci		qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24,
276862306a36Sopenharmony_ci			0, WAIT_TARGET);
276962306a36Sopenharmony_ci		return;
277062306a36Sopenharmony_ci	}
277162306a36Sopenharmony_ci	/*
277262306a36Sopenharmony_ci	 * At this point all fcport's software-states are cleared.  Perform any
277362306a36Sopenharmony_ci	 * final cleanup of firmware resources (PCBs and XCBs).
277462306a36Sopenharmony_ci	 *
277562306a36Sopenharmony_ci	 * Attempt to cleanup only lost devices.
277662306a36Sopenharmony_ci	 */
277762306a36Sopenharmony_ci	if (fcport->loop_id != FC_NO_LOOP_ID) {
277862306a36Sopenharmony_ci		if (IS_FWI2_CAPABLE(fcport->vha->hw) &&
277962306a36Sopenharmony_ci		    fcport->scan_state != QLA_FCPORT_FOUND) {
278062306a36Sopenharmony_ci			if (fcport->loop_id != FC_NO_LOOP_ID)
278162306a36Sopenharmony_ci				fcport->logout_on_delete = 1;
278262306a36Sopenharmony_ci
278362306a36Sopenharmony_ci			if (!EDIF_NEGOTIATION_PENDING(fcport)) {
278462306a36Sopenharmony_ci				ql_dbg(ql_dbg_disc, fcport->vha, 0x911e,
278562306a36Sopenharmony_ci				       "%s %d schedule session deletion\n", __func__,
278662306a36Sopenharmony_ci				       __LINE__);
278762306a36Sopenharmony_ci				qlt_schedule_sess_for_deletion(fcport);
278862306a36Sopenharmony_ci			}
278962306a36Sopenharmony_ci		} else if (!IS_FWI2_CAPABLE(fcport->vha->hw)) {
279062306a36Sopenharmony_ci			qla2x00_port_logout(fcport->vha, fcport);
279162306a36Sopenharmony_ci		}
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci
279462306a36Sopenharmony_ci	/* check for any straggling io left behind */
279562306a36Sopenharmony_ci	if (qla2x00_eh_wait_for_pending_commands(fcport->vha, fcport->d_id.b24, 0, WAIT_TARGET)) {
279662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x300b,
279762306a36Sopenharmony_ci		       "IO not return.  Resetting. \n");
279862306a36Sopenharmony_ci		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
279962306a36Sopenharmony_ci		qla2xxx_wake_dpc(vha);
280062306a36Sopenharmony_ci		qla2x00_wait_for_chip_reset(vha);
280162306a36Sopenharmony_ci	}
280262306a36Sopenharmony_ci}
280362306a36Sopenharmony_ci
280462306a36Sopenharmony_cistatic int
280562306a36Sopenharmony_ciqla2x00_issue_lip(struct Scsi_Host *shost)
280662306a36Sopenharmony_ci{
280762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw))
281062306a36Sopenharmony_ci		return 0;
281162306a36Sopenharmony_ci
281262306a36Sopenharmony_ci	if (vha->hw->flags.port_isolated)
281362306a36Sopenharmony_ci		return 0;
281462306a36Sopenharmony_ci
281562306a36Sopenharmony_ci	qla2x00_loop_reset(vha);
281662306a36Sopenharmony_ci	return 0;
281762306a36Sopenharmony_ci}
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_cistatic struct fc_host_statistics *
282062306a36Sopenharmony_ciqla2x00_get_fc_host_stats(struct Scsi_Host *shost)
282162306a36Sopenharmony_ci{
282262306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
282362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
282462306a36Sopenharmony_ci	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
282562306a36Sopenharmony_ci	int rval;
282662306a36Sopenharmony_ci	struct link_statistics *stats;
282762306a36Sopenharmony_ci	dma_addr_t stats_dma;
282862306a36Sopenharmony_ci	struct fc_host_statistics *p = &vha->fc_host_stat;
282962306a36Sopenharmony_ci	struct qla_qpair *qpair;
283062306a36Sopenharmony_ci	int i;
283162306a36Sopenharmony_ci	u64 ib = 0, ob = 0, ir = 0, or = 0;
283262306a36Sopenharmony_ci
283362306a36Sopenharmony_ci	memset(p, -1, sizeof(*p));
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	if (IS_QLAFX00(vha->hw))
283662306a36Sopenharmony_ci		goto done;
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_ci	if (test_bit(UNLOADING, &vha->dpc_flags))
283962306a36Sopenharmony_ci		goto done;
284062306a36Sopenharmony_ci
284162306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
284262306a36Sopenharmony_ci		goto done;
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_ci	if (qla2x00_chip_is_down(vha))
284562306a36Sopenharmony_ci		goto done;
284662306a36Sopenharmony_ci
284762306a36Sopenharmony_ci	stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma,
284862306a36Sopenharmony_ci				   GFP_KERNEL);
284962306a36Sopenharmony_ci	if (!stats) {
285062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x707d,
285162306a36Sopenharmony_ci		    "Failed to allocate memory for stats.\n");
285262306a36Sopenharmony_ci		goto done;
285362306a36Sopenharmony_ci	}
285462306a36Sopenharmony_ci
285562306a36Sopenharmony_ci	rval = QLA_FUNCTION_FAILED;
285662306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
285762306a36Sopenharmony_ci		rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, 0);
285862306a36Sopenharmony_ci	} else if (atomic_read(&base_vha->loop_state) == LOOP_READY &&
285962306a36Sopenharmony_ci	    !ha->dpc_active) {
286062306a36Sopenharmony_ci		/* Must be in a 'READY' state for statistics retrieval. */
286162306a36Sopenharmony_ci		rval = qla2x00_get_link_status(base_vha, base_vha->loop_id,
286262306a36Sopenharmony_ci						stats, stats_dma);
286362306a36Sopenharmony_ci	}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
286662306a36Sopenharmony_ci		goto done_free;
286762306a36Sopenharmony_ci
286862306a36Sopenharmony_ci	/* --- */
286962306a36Sopenharmony_ci	for (i = 0; i < vha->hw->max_qpairs; i++) {
287062306a36Sopenharmony_ci		qpair = vha->hw->queue_pair_map[i];
287162306a36Sopenharmony_ci		if (!qpair)
287262306a36Sopenharmony_ci			continue;
287362306a36Sopenharmony_ci		ir += qpair->counters.input_requests;
287462306a36Sopenharmony_ci		or += qpair->counters.output_requests;
287562306a36Sopenharmony_ci		ib += qpair->counters.input_bytes;
287662306a36Sopenharmony_ci		ob += qpair->counters.output_bytes;
287762306a36Sopenharmony_ci	}
287862306a36Sopenharmony_ci	ir += ha->base_qpair->counters.input_requests;
287962306a36Sopenharmony_ci	or += ha->base_qpair->counters.output_requests;
288062306a36Sopenharmony_ci	ib += ha->base_qpair->counters.input_bytes;
288162306a36Sopenharmony_ci	ob += ha->base_qpair->counters.output_bytes;
288262306a36Sopenharmony_ci
288362306a36Sopenharmony_ci	ir += vha->qla_stats.input_requests;
288462306a36Sopenharmony_ci	or += vha->qla_stats.output_requests;
288562306a36Sopenharmony_ci	ib += vha->qla_stats.input_bytes;
288662306a36Sopenharmony_ci	ob += vha->qla_stats.output_bytes;
288762306a36Sopenharmony_ci	/* --- */
288862306a36Sopenharmony_ci
288962306a36Sopenharmony_ci	p->link_failure_count = le32_to_cpu(stats->link_fail_cnt);
289062306a36Sopenharmony_ci	p->loss_of_sync_count = le32_to_cpu(stats->loss_sync_cnt);
289162306a36Sopenharmony_ci	p->loss_of_signal_count = le32_to_cpu(stats->loss_sig_cnt);
289262306a36Sopenharmony_ci	p->prim_seq_protocol_err_count = le32_to_cpu(stats->prim_seq_err_cnt);
289362306a36Sopenharmony_ci	p->invalid_tx_word_count = le32_to_cpu(stats->inval_xmit_word_cnt);
289462306a36Sopenharmony_ci	p->invalid_crc_count = le32_to_cpu(stats->inval_crc_cnt);
289562306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
289662306a36Sopenharmony_ci		p->lip_count = le32_to_cpu(stats->lip_cnt);
289762306a36Sopenharmony_ci		p->tx_frames = le32_to_cpu(stats->tx_frames);
289862306a36Sopenharmony_ci		p->rx_frames = le32_to_cpu(stats->rx_frames);
289962306a36Sopenharmony_ci		p->dumped_frames = le32_to_cpu(stats->discarded_frames);
290062306a36Sopenharmony_ci		p->nos_count = le32_to_cpu(stats->nos_rcvd);
290162306a36Sopenharmony_ci		p->error_frames =
290262306a36Sopenharmony_ci		    le32_to_cpu(stats->dropped_frames) +
290362306a36Sopenharmony_ci		    le32_to_cpu(stats->discarded_frames);
290462306a36Sopenharmony_ci		if (IS_QLA83XX(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
290562306a36Sopenharmony_ci			p->rx_words = le64_to_cpu(stats->fpm_recv_word_cnt);
290662306a36Sopenharmony_ci			p->tx_words = le64_to_cpu(stats->fpm_xmit_word_cnt);
290762306a36Sopenharmony_ci		} else {
290862306a36Sopenharmony_ci			p->rx_words = ib >> 2;
290962306a36Sopenharmony_ci			p->tx_words = ob >> 2;
291062306a36Sopenharmony_ci		}
291162306a36Sopenharmony_ci	}
291262306a36Sopenharmony_ci
291362306a36Sopenharmony_ci	p->fcp_control_requests = vha->qla_stats.control_requests;
291462306a36Sopenharmony_ci	p->fcp_input_requests = ir;
291562306a36Sopenharmony_ci	p->fcp_output_requests = or;
291662306a36Sopenharmony_ci	p->fcp_input_megabytes  = ib >> 20;
291762306a36Sopenharmony_ci	p->fcp_output_megabytes = ob >> 20;
291862306a36Sopenharmony_ci	p->seconds_since_last_reset =
291962306a36Sopenharmony_ci	    get_jiffies_64() - vha->qla_stats.jiffies_at_last_reset;
292062306a36Sopenharmony_ci	do_div(p->seconds_since_last_reset, HZ);
292162306a36Sopenharmony_ci
292262306a36Sopenharmony_cidone_free:
292362306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(struct link_statistics),
292462306a36Sopenharmony_ci	    stats, stats_dma);
292562306a36Sopenharmony_cidone:
292662306a36Sopenharmony_ci	return p;
292762306a36Sopenharmony_ci}
292862306a36Sopenharmony_ci
292962306a36Sopenharmony_cistatic void
293062306a36Sopenharmony_ciqla2x00_reset_host_stats(struct Scsi_Host *shost)
293162306a36Sopenharmony_ci{
293262306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
293362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
293462306a36Sopenharmony_ci	struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
293562306a36Sopenharmony_ci	struct link_statistics *stats;
293662306a36Sopenharmony_ci	dma_addr_t stats_dma;
293762306a36Sopenharmony_ci	int i;
293862306a36Sopenharmony_ci	struct qla_qpair *qpair;
293962306a36Sopenharmony_ci
294062306a36Sopenharmony_ci	memset(&vha->qla_stats, 0, sizeof(vha->qla_stats));
294162306a36Sopenharmony_ci	memset(&vha->fc_host_stat, 0, sizeof(vha->fc_host_stat));
294262306a36Sopenharmony_ci	for (i = 0; i < vha->hw->max_qpairs; i++) {
294362306a36Sopenharmony_ci		qpair = vha->hw->queue_pair_map[i];
294462306a36Sopenharmony_ci		if (!qpair)
294562306a36Sopenharmony_ci			continue;
294662306a36Sopenharmony_ci		memset(&qpair->counters, 0, sizeof(qpair->counters));
294762306a36Sopenharmony_ci	}
294862306a36Sopenharmony_ci	memset(&ha->base_qpair->counters, 0, sizeof(qpair->counters));
294962306a36Sopenharmony_ci
295062306a36Sopenharmony_ci	vha->qla_stats.jiffies_at_last_reset = get_jiffies_64();
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci	if (IS_FWI2_CAPABLE(ha)) {
295362306a36Sopenharmony_ci		int rval;
295462306a36Sopenharmony_ci
295562306a36Sopenharmony_ci		stats = dma_alloc_coherent(&ha->pdev->dev,
295662306a36Sopenharmony_ci		    sizeof(*stats), &stats_dma, GFP_KERNEL);
295762306a36Sopenharmony_ci		if (!stats) {
295862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70d7,
295962306a36Sopenharmony_ci			    "Failed to allocate memory for stats.\n");
296062306a36Sopenharmony_ci			return;
296162306a36Sopenharmony_ci		}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_ci		/* reset firmware statistics */
296462306a36Sopenharmony_ci		rval = qla24xx_get_isp_stats(base_vha, stats, stats_dma, BIT_0);
296562306a36Sopenharmony_ci		if (rval != QLA_SUCCESS)
296662306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x70de,
296762306a36Sopenharmony_ci			       "Resetting ISP statistics failed: rval = %d\n",
296862306a36Sopenharmony_ci			       rval);
296962306a36Sopenharmony_ci
297062306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, sizeof(*stats),
297162306a36Sopenharmony_ci		    stats, stats_dma);
297262306a36Sopenharmony_ci	}
297362306a36Sopenharmony_ci}
297462306a36Sopenharmony_ci
297562306a36Sopenharmony_cistatic void
297662306a36Sopenharmony_ciqla2x00_get_host_symbolic_name(struct Scsi_Host *shost)
297762306a36Sopenharmony_ci{
297862306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	qla2x00_get_sym_node_name(vha, fc_host_symbolic_name(shost),
298162306a36Sopenharmony_ci	    sizeof(fc_host_symbolic_name(shost)));
298262306a36Sopenharmony_ci}
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_cistatic void
298562306a36Sopenharmony_ciqla2x00_set_host_system_hostname(struct Scsi_Host *shost)
298662306a36Sopenharmony_ci{
298762306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
298862306a36Sopenharmony_ci
298962306a36Sopenharmony_ci	set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags);
299062306a36Sopenharmony_ci}
299162306a36Sopenharmony_ci
299262306a36Sopenharmony_cistatic void
299362306a36Sopenharmony_ciqla2x00_get_host_fabric_name(struct Scsi_Host *shost)
299462306a36Sopenharmony_ci{
299562306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
299662306a36Sopenharmony_ci	static const uint8_t node_name[WWN_SIZE] = {
299762306a36Sopenharmony_ci		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
299862306a36Sopenharmony_ci	};
299962306a36Sopenharmony_ci	u64 fabric_name = wwn_to_u64(node_name);
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	if (vha->device_flags & SWITCH_FOUND)
300262306a36Sopenharmony_ci		fabric_name = wwn_to_u64(vha->fabric_node_name);
300362306a36Sopenharmony_ci
300462306a36Sopenharmony_ci	fc_host_fabric_name(shost) = fabric_name;
300562306a36Sopenharmony_ci}
300662306a36Sopenharmony_ci
300762306a36Sopenharmony_cistatic void
300862306a36Sopenharmony_ciqla2x00_get_host_port_state(struct Scsi_Host *shost)
300962306a36Sopenharmony_ci{
301062306a36Sopenharmony_ci	scsi_qla_host_t *vha = shost_priv(shost);
301162306a36Sopenharmony_ci	struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev);
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	if (!base_vha->flags.online) {
301462306a36Sopenharmony_ci		fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
301562306a36Sopenharmony_ci		return;
301662306a36Sopenharmony_ci	}
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci	switch (atomic_read(&base_vha->loop_state)) {
301962306a36Sopenharmony_ci	case LOOP_UPDATE:
302062306a36Sopenharmony_ci		fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS;
302162306a36Sopenharmony_ci		break;
302262306a36Sopenharmony_ci	case LOOP_DOWN:
302362306a36Sopenharmony_ci		if (test_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags))
302462306a36Sopenharmony_ci			fc_host_port_state(shost) = FC_PORTSTATE_DIAGNOSTICS;
302562306a36Sopenharmony_ci		else
302662306a36Sopenharmony_ci			fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
302762306a36Sopenharmony_ci		break;
302862306a36Sopenharmony_ci	case LOOP_DEAD:
302962306a36Sopenharmony_ci		fc_host_port_state(shost) = FC_PORTSTATE_LINKDOWN;
303062306a36Sopenharmony_ci		break;
303162306a36Sopenharmony_ci	case LOOP_READY:
303262306a36Sopenharmony_ci		fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
303362306a36Sopenharmony_ci		break;
303462306a36Sopenharmony_ci	default:
303562306a36Sopenharmony_ci		fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
303662306a36Sopenharmony_ci		break;
303762306a36Sopenharmony_ci	}
303862306a36Sopenharmony_ci}
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_cistatic int
304162306a36Sopenharmony_ciqla24xx_vport_create(struct fc_vport *fc_vport, bool disable)
304262306a36Sopenharmony_ci{
304362306a36Sopenharmony_ci	int	ret = 0;
304462306a36Sopenharmony_ci	uint8_t	qos = 0;
304562306a36Sopenharmony_ci	scsi_qla_host_t *base_vha = shost_priv(fc_vport->shost);
304662306a36Sopenharmony_ci	scsi_qla_host_t *vha = NULL;
304762306a36Sopenharmony_ci	struct qla_hw_data *ha = base_vha->hw;
304862306a36Sopenharmony_ci	int	cnt;
304962306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
305062306a36Sopenharmony_ci	struct qla_qpair *qpair;
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci	ret = qla24xx_vport_create_req_sanity_check(fc_vport);
305362306a36Sopenharmony_ci	if (ret) {
305462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x707e,
305562306a36Sopenharmony_ci		    "Vport sanity check failed, status %x\n", ret);
305662306a36Sopenharmony_ci		return (ret);
305762306a36Sopenharmony_ci	}
305862306a36Sopenharmony_ci
305962306a36Sopenharmony_ci	vha = qla24xx_create_vhost(fc_vport);
306062306a36Sopenharmony_ci	if (vha == NULL) {
306162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x707f, "Vport create host failed.\n");
306262306a36Sopenharmony_ci		return FC_VPORT_FAILED;
306362306a36Sopenharmony_ci	}
306462306a36Sopenharmony_ci	if (disable) {
306562306a36Sopenharmony_ci		atomic_set(&vha->vp_state, VP_OFFLINE);
306662306a36Sopenharmony_ci		fc_vport_set_state(fc_vport, FC_VPORT_DISABLED);
306762306a36Sopenharmony_ci	} else
306862306a36Sopenharmony_ci		atomic_set(&vha->vp_state, VP_FAILED);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci	/* ready to create vport */
307162306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x7080,
307262306a36Sopenharmony_ci	    "VP entry id %d assigned.\n", vha->vp_idx);
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	/* initialized vport states */
307562306a36Sopenharmony_ci	atomic_set(&vha->loop_state, LOOP_DOWN);
307662306a36Sopenharmony_ci	vha->vp_err_state = VP_ERR_PORTDWN;
307762306a36Sopenharmony_ci	vha->vp_prev_err_state = VP_ERR_UNKWN;
307862306a36Sopenharmony_ci	/* Check if physical ha port is Up */
307962306a36Sopenharmony_ci	if (atomic_read(&base_vha->loop_state) == LOOP_DOWN ||
308062306a36Sopenharmony_ci	    atomic_read(&base_vha->loop_state) == LOOP_DEAD) {
308162306a36Sopenharmony_ci		/* Don't retry or attempt login of this virtual port */
308262306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7081,
308362306a36Sopenharmony_ci		    "Vport loop state is not UP.\n");
308462306a36Sopenharmony_ci		atomic_set(&vha->loop_state, LOOP_DEAD);
308562306a36Sopenharmony_ci		if (!disable)
308662306a36Sopenharmony_ci			fc_vport_set_state(fc_vport, FC_VPORT_LINKDOWN);
308762306a36Sopenharmony_ci	}
308862306a36Sopenharmony_ci
308962306a36Sopenharmony_ci	if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) {
309062306a36Sopenharmony_ci		if (ha->fw_attributes & BIT_4) {
309162306a36Sopenharmony_ci			int prot = 0, guard;
309262306a36Sopenharmony_ci
309362306a36Sopenharmony_ci			vha->flags.difdix_supported = 1;
309462306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7082,
309562306a36Sopenharmony_ci			    "Registered for DIF/DIX type 1 and 3 protection.\n");
309662306a36Sopenharmony_ci			scsi_host_set_prot(vha->host,
309762306a36Sopenharmony_ci			    prot | SHOST_DIF_TYPE1_PROTECTION
309862306a36Sopenharmony_ci			    | SHOST_DIF_TYPE2_PROTECTION
309962306a36Sopenharmony_ci			    | SHOST_DIF_TYPE3_PROTECTION
310062306a36Sopenharmony_ci			    | SHOST_DIX_TYPE1_PROTECTION
310162306a36Sopenharmony_ci			    | SHOST_DIX_TYPE2_PROTECTION
310262306a36Sopenharmony_ci			    | SHOST_DIX_TYPE3_PROTECTION);
310362306a36Sopenharmony_ci
310462306a36Sopenharmony_ci			guard = SHOST_DIX_GUARD_CRC;
310562306a36Sopenharmony_ci
310662306a36Sopenharmony_ci			if (IS_PI_IPGUARD_CAPABLE(ha) &&
310762306a36Sopenharmony_ci			    (ql2xenabledif > 1 || IS_PI_DIFB_DIX0_CAPABLE(ha)))
310862306a36Sopenharmony_ci				guard |= SHOST_DIX_GUARD_IP;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci			scsi_host_set_guard(vha->host, guard);
311162306a36Sopenharmony_ci		} else
311262306a36Sopenharmony_ci			vha->flags.difdix_supported = 0;
311362306a36Sopenharmony_ci	}
311462306a36Sopenharmony_ci
311562306a36Sopenharmony_ci	if (scsi_add_host_with_dma(vha->host, &fc_vport->dev,
311662306a36Sopenharmony_ci				   &ha->pdev->dev)) {
311762306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7083,
311862306a36Sopenharmony_ci		    "scsi_add_host failure for VP[%d].\n", vha->vp_idx);
311962306a36Sopenharmony_ci		goto vport_create_failed_2;
312062306a36Sopenharmony_ci	}
312162306a36Sopenharmony_ci
312262306a36Sopenharmony_ci	/* initialize attributes */
312362306a36Sopenharmony_ci	fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
312462306a36Sopenharmony_ci	fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
312562306a36Sopenharmony_ci	fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
312662306a36Sopenharmony_ci	fc_host_supported_classes(vha->host) =
312762306a36Sopenharmony_ci		fc_host_supported_classes(base_vha->host);
312862306a36Sopenharmony_ci	fc_host_supported_speeds(vha->host) =
312962306a36Sopenharmony_ci		fc_host_supported_speeds(base_vha->host);
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	qlt_vport_create(vha, ha);
313262306a36Sopenharmony_ci	qla24xx_vport_disable(fc_vport, disable);
313362306a36Sopenharmony_ci
313462306a36Sopenharmony_ci	if (!ql2xmqsupport || !ha->npiv_info)
313562306a36Sopenharmony_ci		goto vport_queue;
313662306a36Sopenharmony_ci
313762306a36Sopenharmony_ci	/* Create a request queue in QoS mode for the vport */
313862306a36Sopenharmony_ci	for (cnt = 0; cnt < ha->nvram_npiv_size; cnt++) {
313962306a36Sopenharmony_ci		if (memcmp(ha->npiv_info[cnt].port_name, vha->port_name, 8) == 0
314062306a36Sopenharmony_ci			&& memcmp(ha->npiv_info[cnt].node_name, vha->node_name,
314162306a36Sopenharmony_ci					8) == 0) {
314262306a36Sopenharmony_ci			qos = ha->npiv_info[cnt].q_qos;
314362306a36Sopenharmony_ci			break;
314462306a36Sopenharmony_ci		}
314562306a36Sopenharmony_ci	}
314662306a36Sopenharmony_ci
314762306a36Sopenharmony_ci	if (qos) {
314862306a36Sopenharmony_ci		qpair = qla2xxx_create_qpair(vha, qos, vha->vp_idx, true);
314962306a36Sopenharmony_ci		if (!qpair)
315062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7084,
315162306a36Sopenharmony_ci			    "Can't create qpair for VP[%d]\n",
315262306a36Sopenharmony_ci			    vha->vp_idx);
315362306a36Sopenharmony_ci		else {
315462306a36Sopenharmony_ci			ql_dbg(ql_dbg_multiq, vha, 0xc001,
315562306a36Sopenharmony_ci			    "Queue pair: %d Qos: %d) created for VP[%d]\n",
315662306a36Sopenharmony_ci			    qpair->id, qos, vha->vp_idx);
315762306a36Sopenharmony_ci			ql_dbg(ql_dbg_user, vha, 0x7085,
315862306a36Sopenharmony_ci			    "Queue Pair: %d Qos: %d) created for VP[%d]\n",
315962306a36Sopenharmony_ci			    qpair->id, qos, vha->vp_idx);
316062306a36Sopenharmony_ci			req = qpair->req;
316162306a36Sopenharmony_ci			vha->qpair = qpair;
316262306a36Sopenharmony_ci		}
316362306a36Sopenharmony_ci	}
316462306a36Sopenharmony_ci
316562306a36Sopenharmony_civport_queue:
316662306a36Sopenharmony_ci	vha->req = req;
316762306a36Sopenharmony_ci	return 0;
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_civport_create_failed_2:
317062306a36Sopenharmony_ci	qla24xx_disable_vp(vha);
317162306a36Sopenharmony_ci	qla24xx_deallocate_vp_id(vha);
317262306a36Sopenharmony_ci	scsi_host_put(vha->host);
317362306a36Sopenharmony_ci	return FC_VPORT_FAILED;
317462306a36Sopenharmony_ci}
317562306a36Sopenharmony_ci
317662306a36Sopenharmony_cistatic int
317762306a36Sopenharmony_ciqla24xx_vport_delete(struct fc_vport *fc_vport)
317862306a36Sopenharmony_ci{
317962306a36Sopenharmony_ci	scsi_qla_host_t *vha = fc_vport->dd_data;
318062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
318162306a36Sopenharmony_ci	uint16_t id = vha->vp_idx;
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	set_bit(VPORT_DELETE, &vha->dpc_flags);
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	while (test_bit(LOOP_RESYNC_ACTIVE, &vha->dpc_flags))
318662306a36Sopenharmony_ci		msleep(1000);
318762306a36Sopenharmony_ci
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	qla24xx_disable_vp(vha);
319062306a36Sopenharmony_ci	qla2x00_wait_for_sess_deletion(vha);
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	qla_nvme_delete(vha);
319362306a36Sopenharmony_ci	qla_enode_stop(vha);
319462306a36Sopenharmony_ci	qla_edb_stop(vha);
319562306a36Sopenharmony_ci
319662306a36Sopenharmony_ci	vha->flags.delete_progress = 1;
319762306a36Sopenharmony_ci
319862306a36Sopenharmony_ci	qlt_remove_target(ha, vha);
319962306a36Sopenharmony_ci
320062306a36Sopenharmony_ci	fc_remove_host(vha->host);
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci	scsi_remove_host(vha->host);
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_ci	/* Allow timer to run to drain queued items, when removing vp */
320562306a36Sopenharmony_ci	qla24xx_deallocate_vp_id(vha);
320662306a36Sopenharmony_ci
320762306a36Sopenharmony_ci	if (vha->timer_active) {
320862306a36Sopenharmony_ci		qla2x00_vp_stop_timer(vha);
320962306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0x7086,
321062306a36Sopenharmony_ci		    "Timer for the VP[%d] has stopped\n", vha->vp_idx);
321162306a36Sopenharmony_ci	}
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	qla2x00_free_fcports(vha);
321462306a36Sopenharmony_ci
321562306a36Sopenharmony_ci	mutex_lock(&ha->vport_lock);
321662306a36Sopenharmony_ci	ha->cur_vport_count--;
321762306a36Sopenharmony_ci	clear_bit(vha->vp_idx, ha->vp_idx_map);
321862306a36Sopenharmony_ci	mutex_unlock(&ha->vport_lock);
321962306a36Sopenharmony_ci
322062306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, vha->gnl.size, vha->gnl.l,
322162306a36Sopenharmony_ci	    vha->gnl.ldma);
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	vha->gnl.l = NULL;
322462306a36Sopenharmony_ci
322562306a36Sopenharmony_ci	vfree(vha->scan.l);
322662306a36Sopenharmony_ci
322762306a36Sopenharmony_ci	if (vha->qpair && vha->qpair->vp_idx == vha->vp_idx) {
322862306a36Sopenharmony_ci		if (qla2xxx_delete_qpair(vha, vha->qpair) != QLA_SUCCESS)
322962306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x7087,
323062306a36Sopenharmony_ci			    "Queue Pair delete failed.\n");
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x7088, "VP[%d] deleted.\n", id);
323462306a36Sopenharmony_ci	scsi_host_put(vha->host);
323562306a36Sopenharmony_ci	return 0;
323662306a36Sopenharmony_ci}
323762306a36Sopenharmony_ci
323862306a36Sopenharmony_cistatic int
323962306a36Sopenharmony_ciqla24xx_vport_disable(struct fc_vport *fc_vport, bool disable)
324062306a36Sopenharmony_ci{
324162306a36Sopenharmony_ci	scsi_qla_host_t *vha = fc_vport->dd_data;
324262306a36Sopenharmony_ci
324362306a36Sopenharmony_ci	if (disable)
324462306a36Sopenharmony_ci		qla24xx_disable_vp(vha);
324562306a36Sopenharmony_ci	else
324662306a36Sopenharmony_ci		qla24xx_enable_vp(vha);
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	return 0;
324962306a36Sopenharmony_ci}
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_cistruct fc_function_template qla2xxx_transport_functions = {
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	.show_host_node_name = 1,
325462306a36Sopenharmony_ci	.show_host_port_name = 1,
325562306a36Sopenharmony_ci	.show_host_supported_classes = 1,
325662306a36Sopenharmony_ci	.show_host_supported_speeds = 1,
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci	.get_host_port_id = qla2x00_get_host_port_id,
325962306a36Sopenharmony_ci	.show_host_port_id = 1,
326062306a36Sopenharmony_ci	.get_host_speed = qla2x00_get_host_speed,
326162306a36Sopenharmony_ci	.show_host_speed = 1,
326262306a36Sopenharmony_ci	.get_host_port_type = qla2x00_get_host_port_type,
326362306a36Sopenharmony_ci	.show_host_port_type = 1,
326462306a36Sopenharmony_ci	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
326562306a36Sopenharmony_ci	.show_host_symbolic_name = 1,
326662306a36Sopenharmony_ci	.set_host_system_hostname = qla2x00_set_host_system_hostname,
326762306a36Sopenharmony_ci	.show_host_system_hostname = 1,
326862306a36Sopenharmony_ci	.get_host_fabric_name = qla2x00_get_host_fabric_name,
326962306a36Sopenharmony_ci	.show_host_fabric_name = 1,
327062306a36Sopenharmony_ci	.get_host_port_state = qla2x00_get_host_port_state,
327162306a36Sopenharmony_ci	.show_host_port_state = 1,
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	.dd_fcrport_size = sizeof(struct fc_port *),
327462306a36Sopenharmony_ci	.show_rport_supported_classes = 1,
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	.get_starget_node_name = qla2x00_get_starget_node_name,
327762306a36Sopenharmony_ci	.show_starget_node_name = 1,
327862306a36Sopenharmony_ci	.get_starget_port_name = qla2x00_get_starget_port_name,
327962306a36Sopenharmony_ci	.show_starget_port_name = 1,
328062306a36Sopenharmony_ci	.get_starget_port_id  = qla2x00_get_starget_port_id,
328162306a36Sopenharmony_ci	.show_starget_port_id = 1,
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
328462306a36Sopenharmony_ci	.show_rport_dev_loss_tmo = 1,
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	.issue_fc_host_lip = qla2x00_issue_lip,
328762306a36Sopenharmony_ci	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
328862306a36Sopenharmony_ci	.terminate_rport_io = qla2x00_terminate_rport_io,
328962306a36Sopenharmony_ci	.get_fc_host_stats = qla2x00_get_fc_host_stats,
329062306a36Sopenharmony_ci	.reset_fc_host_stats = qla2x00_reset_host_stats,
329162306a36Sopenharmony_ci
329262306a36Sopenharmony_ci	.vport_create = qla24xx_vport_create,
329362306a36Sopenharmony_ci	.vport_disable = qla24xx_vport_disable,
329462306a36Sopenharmony_ci	.vport_delete = qla24xx_vport_delete,
329562306a36Sopenharmony_ci	.bsg_request = qla24xx_bsg_request,
329662306a36Sopenharmony_ci	.bsg_timeout = qla24xx_bsg_timeout,
329762306a36Sopenharmony_ci};
329862306a36Sopenharmony_ci
329962306a36Sopenharmony_cistruct fc_function_template qla2xxx_transport_vport_functions = {
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	.show_host_node_name = 1,
330262306a36Sopenharmony_ci	.show_host_port_name = 1,
330362306a36Sopenharmony_ci	.show_host_supported_classes = 1,
330462306a36Sopenharmony_ci
330562306a36Sopenharmony_ci	.get_host_port_id = qla2x00_get_host_port_id,
330662306a36Sopenharmony_ci	.show_host_port_id = 1,
330762306a36Sopenharmony_ci	.get_host_speed = qla2x00_get_host_speed,
330862306a36Sopenharmony_ci	.show_host_speed = 1,
330962306a36Sopenharmony_ci	.get_host_port_type = qla2x00_get_host_port_type,
331062306a36Sopenharmony_ci	.show_host_port_type = 1,
331162306a36Sopenharmony_ci	.get_host_symbolic_name = qla2x00_get_host_symbolic_name,
331262306a36Sopenharmony_ci	.show_host_symbolic_name = 1,
331362306a36Sopenharmony_ci	.set_host_system_hostname = qla2x00_set_host_system_hostname,
331462306a36Sopenharmony_ci	.show_host_system_hostname = 1,
331562306a36Sopenharmony_ci	.get_host_fabric_name = qla2x00_get_host_fabric_name,
331662306a36Sopenharmony_ci	.show_host_fabric_name = 1,
331762306a36Sopenharmony_ci	.get_host_port_state = qla2x00_get_host_port_state,
331862306a36Sopenharmony_ci	.show_host_port_state = 1,
331962306a36Sopenharmony_ci
332062306a36Sopenharmony_ci	.dd_fcrport_size = sizeof(struct fc_port *),
332162306a36Sopenharmony_ci	.show_rport_supported_classes = 1,
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	.get_starget_node_name = qla2x00_get_starget_node_name,
332462306a36Sopenharmony_ci	.show_starget_node_name = 1,
332562306a36Sopenharmony_ci	.get_starget_port_name = qla2x00_get_starget_port_name,
332662306a36Sopenharmony_ci	.show_starget_port_name = 1,
332762306a36Sopenharmony_ci	.get_starget_port_id  = qla2x00_get_starget_port_id,
332862306a36Sopenharmony_ci	.show_starget_port_id = 1,
332962306a36Sopenharmony_ci
333062306a36Sopenharmony_ci	.set_rport_dev_loss_tmo = qla2x00_set_rport_loss_tmo,
333162306a36Sopenharmony_ci	.show_rport_dev_loss_tmo = 1,
333262306a36Sopenharmony_ci
333362306a36Sopenharmony_ci	.issue_fc_host_lip = qla2x00_issue_lip,
333462306a36Sopenharmony_ci	.dev_loss_tmo_callbk = qla2x00_dev_loss_tmo_callbk,
333562306a36Sopenharmony_ci	.terminate_rport_io = qla2x00_terminate_rport_io,
333662306a36Sopenharmony_ci	.get_fc_host_stats = qla2x00_get_fc_host_stats,
333762306a36Sopenharmony_ci	.reset_fc_host_stats = qla2x00_reset_host_stats,
333862306a36Sopenharmony_ci
333962306a36Sopenharmony_ci	.bsg_request = qla24xx_bsg_request,
334062306a36Sopenharmony_ci	.bsg_timeout = qla24xx_bsg_timeout,
334162306a36Sopenharmony_ci};
334262306a36Sopenharmony_ci
334362306a36Sopenharmony_cistatic uint
334462306a36Sopenharmony_ciqla2x00_get_host_supported_speeds(scsi_qla_host_t *vha, uint speeds)
334562306a36Sopenharmony_ci{
334662306a36Sopenharmony_ci	uint supported_speeds = FC_PORTSPEED_UNKNOWN;
334762306a36Sopenharmony_ci
334862306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_64GB)
334962306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_64GBIT;
335062306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_32GB)
335162306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_32GBIT;
335262306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_16GB)
335362306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_16GBIT;
335462306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_8GB)
335562306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_8GBIT;
335662306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_4GB)
335762306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_4GBIT;
335862306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_2GB)
335962306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_2GBIT;
336062306a36Sopenharmony_ci	if (speeds & FDMI_PORT_SPEED_1GB)
336162306a36Sopenharmony_ci		supported_speeds |= FC_PORTSPEED_1GBIT;
336262306a36Sopenharmony_ci
336362306a36Sopenharmony_ci	return supported_speeds;
336462306a36Sopenharmony_ci}
336562306a36Sopenharmony_ci
336662306a36Sopenharmony_civoid
336762306a36Sopenharmony_ciqla2x00_init_host_attr(scsi_qla_host_t *vha)
336862306a36Sopenharmony_ci{
336962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
337062306a36Sopenharmony_ci	u32 speeds = 0, fdmi_speed = 0;
337162306a36Sopenharmony_ci
337262306a36Sopenharmony_ci	fc_host_dev_loss_tmo(vha->host) = ha->port_down_retry_count;
337362306a36Sopenharmony_ci	fc_host_node_name(vha->host) = wwn_to_u64(vha->node_name);
337462306a36Sopenharmony_ci	fc_host_port_name(vha->host) = wwn_to_u64(vha->port_name);
337562306a36Sopenharmony_ci	fc_host_supported_classes(vha->host) = ha->base_qpair->enable_class_2 ?
337662306a36Sopenharmony_ci			(FC_COS_CLASS2|FC_COS_CLASS3) : FC_COS_CLASS3;
337762306a36Sopenharmony_ci	fc_host_max_npiv_vports(vha->host) = ha->max_npiv_vports;
337862306a36Sopenharmony_ci	fc_host_npiv_vports_inuse(vha->host) = ha->cur_vport_count;
337962306a36Sopenharmony_ci
338062306a36Sopenharmony_ci	fdmi_speed = qla25xx_fdmi_port_speed_capability(ha);
338162306a36Sopenharmony_ci	speeds = qla2x00_get_host_supported_speeds(vha, fdmi_speed);
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci	fc_host_supported_speeds(vha->host) = speeds;
338462306a36Sopenharmony_ci}
3385