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