From fc4c99dccd6d77f421555add85fba3bffd9fec79 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 29 Mar 2019 01:32:45 +0000 Subject: [PATCH] qla2x00t-32gbit: Upgrade initiator code to the code from kernel v5.1-rc2 This patch is the output of git diff v4.18.20..v5.1-rc2 drivers/scsi/qla2xxx. Only one manual change has been applied, namely the removal of "cmd->se_cmd.map_cpu = cpu;" from qlt_alloc_qfull_cmd(). git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@8094 d57e44dd-8a1f-0410-8b47-8ef2f437770f --- qla2x00t-32gbit/qla_attr.c | 723 ++++++++++++++++++- qla2x00t-32gbit/qla_bsg.c | 6 +- qla2x00t-32gbit/qla_dbg.c | 3 + qla2x00t-32gbit/qla_def.h | 97 ++- qla2x00t-32gbit/qla_dfs.c | 45 +- qla2x00t-32gbit/qla_fw.h | 5 + qla2x00t-32gbit/qla_gbl.h | 31 +- qla2x00t-32gbit/qla_gs.c | 689 +++++++------------ qla2x00t-32gbit/qla_init.c | 1224 +++++++++++++++++++-------------- qla2x00t-32gbit/qla_inline.h | 35 +- qla2x00t-32gbit/qla_iocb.c | 576 +++++++++++----- qla2x00t-32gbit/qla_isr.c | 119 ++-- qla2x00t-32gbit/qla_mbx.c | 292 +++++--- qla2x00t-32gbit/qla_mid.c | 3 +- qla2x00t-32gbit/qla_mr.c | 21 +- qla2x00t-32gbit/qla_nvme.c | 92 ++- qla2x00t-32gbit/qla_nvme.h | 4 +- qla2x00t-32gbit/qla_nx.c | 6 +- qla2x00t-32gbit/qla_nx2.c | 2 +- qla2x00t-32gbit/qla_os.c | 825 +++++++++++++++------- qla2x00t-32gbit/qla_sup.c | 2 +- qla2x00t-32gbit/qla_target.c | 609 ++++++++++------ qla2x00t-32gbit/qla_target.h | 18 +- qla2x00t-32gbit/qla_tmpl.c | 241 ++++--- qla2x00t-32gbit/qla_tmpl.h | 26 +- qla2x00t-32gbit/qla_version.h | 2 +- 26 files changed, 3744 insertions(+), 1952 deletions(-) diff --git a/qla2x00t-32gbit/qla_attr.c b/qla2x00t-32gbit/qla_attr.c index c8731568f..f928c4d3a 100644 --- a/qla2x00t-32gbit/qla_attr.c +++ b/qla2x00t-32gbit/qla_attr.c @@ -158,9 +158,17 @@ qla2x00_sysfs_read_nvram(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN)) return 0; + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } + if (IS_NOCACHE_VPD_TYPE(ha)) ha->isp_ops->read_optrom(vha, ha->nvram, ha->flt_region_nvram << 2, ha->nvram_size); + mutex_unlock(&ha->optrom_mutex); + return memory_read_from_buffer(buf, count, &off, ha->nvram, ha->nvram_size); } @@ -208,10 +216,17 @@ qla2x00_sysfs_write_nvram(struct file *filp, struct kobject *kobj, return -EAGAIN; } + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->nvram_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->nvram, ha->nvram_base, - count); + count); + mutex_unlock(&ha->optrom_mutex); ql_dbg(ql_dbg_user, vha, 0x7060, "Setting ISP_ABORT_NEEDED\n"); @@ -322,6 +337,10 @@ qla2x00_sysfs_write_optrom_ctl(struct file *filp, struct kobject *kobj, size = ha->optrom_size - start; mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } switch (val) { case 0: if (ha->optrom_state != QLA_SREADING && @@ -499,8 +518,14 @@ qla2x00_sysfs_read_vpd(struct file *filp, struct kobject *kobj, qla27xx_find_valid_image(vha) == QLA27XX_SECONDARY_IMAGE) faddr = ha->flt_region_vpd_sec << 2; + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } ha->isp_ops->read_optrom(vha, ha->vpd, faddr, ha->vpd_size); + mutex_unlock(&ha->optrom_mutex); } return memory_read_from_buffer(buf, count, &off, ha->vpd, ha->vpd_size); } @@ -518,6 +543,9 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, if (unlikely(pci_channel_offline(ha->pdev))) return 0; + if (qla2x00_chip_is_down(vha)) + return 0; + if (!capable(CAP_SYS_ADMIN) || off != 0 || count != ha->vpd_size || !ha->isp_ops->write_nvram) return 0; @@ -528,16 +556,25 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, return -EAGAIN; } + mutex_lock(&ha->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&ha->optrom_mutex); + return -EAGAIN; + } + /* Write NVRAM. */ ha->isp_ops->write_nvram(vha, (uint8_t *)buf, ha->vpd_base, count); ha->isp_ops->read_nvram(vha, (uint8_t *)ha->vpd, ha->vpd_base, count); /* Update flash version information for 4Gb & above. */ - if (!IS_FWI2_CAPABLE(ha)) + if (!IS_FWI2_CAPABLE(ha)) { + mutex_unlock(&ha->optrom_mutex); return -EINVAL; + } tmp_data = vmalloc(256); if (!tmp_data) { + mutex_unlock(&ha->optrom_mutex); ql_log(ql_log_warn, vha, 0x706b, "Unable to allocate memory for VPD information update.\n"); return -ENOMEM; @@ -545,6 +582,8 @@ qla2x00_sysfs_write_vpd(struct file *filp, struct kobject *kobj, ha->isp_ops->get_flash_version(vha, tmp_data); vfree(tmp_data); + mutex_unlock(&ha->optrom_mutex); + return count; } @@ -570,10 +609,15 @@ qla2x00_sysfs_read_sfp(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count < SFP_DEV_SIZE) return 0; - if (qla2x00_reset_active(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); return 0; + } rval = qla2x00_read_sfp_dev(vha, buf, count); + mutex_unlock(&vha->hw->optrom_mutex); + if (rval) return -EIO; @@ -733,6 +777,15 @@ qla2x00_issue_logo(struct file *filp, struct kobject *kobj, int type; port_id_t did; + if (!capable(CAP_SYS_ADMIN)) + return 0; + + if (unlikely(pci_channel_offline(vha->hw->pdev))) + return 0; + + if (qla2x00_chip_is_down(vha)) + return 0; + type = simple_strtol(buf, NULL, 10); did.b.domain = (type & 0x00ff0000) >> 16; @@ -771,12 +824,21 @@ qla2x00_sysfs_read_xgmac_stats(struct file *filp, struct kobject *kobj, if (!capable(CAP_SYS_ADMIN) || off != 0 || count > XGMAC_DATA_SIZE) return 0; + if (unlikely(pci_channel_offline(ha->pdev))) + return 0; + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); + return 0; + } + if (ha->xgmac_data) goto do_read; ha->xgmac_data = dma_alloc_coherent(&ha->pdev->dev, XGMAC_DATA_SIZE, &ha->xgmac_data_dma, GFP_KERNEL); if (!ha->xgmac_data) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x7076, "Unable to allocate memory for XGMAC read-data.\n"); return 0; @@ -788,6 +850,8 @@ do_read: rval = qla2x00_get_xgmac_stats(vha, ha->xgmac_data_dma, XGMAC_DATA_SIZE, &actual_size); + + mutex_unlock(&vha->hw->optrom_mutex); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7077, "Unable to read XGMAC data (%x).\n", rval); @@ -824,10 +888,16 @@ qla2x00_sysfs_read_dcbx_tlv(struct file *filp, struct kobject *kobj, if (ha->dcbx_tlv) goto do_read; + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); + return 0; + } ha->dcbx_tlv = dma_alloc_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, &ha->dcbx_tlv_dma, GFP_KERNEL); if (!ha->dcbx_tlv) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x7078, "Unable to allocate memory for DCBX TLV read-data.\n"); return -ENOMEM; @@ -838,6 +908,9 @@ do_read: rval = qla2x00_get_dcbx_params(vha, ha->dcbx_tlv_dma, DCBX_TLV_DATA_SIZE); + + mutex_unlock(&vha->hw->optrom_mutex); + if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x7079, "Unable to read DCBX TLV (%x).\n", rval); @@ -932,7 +1005,7 @@ qla2x00_free_sysfs_attr(scsi_qla_host_t *vha, bool stop_beacon) /* Scsi_Host attributes. */ static ssize_t -qla2x00_drvr_version_show(struct device *dev, +qla2x00_driver_version_show(struct device *dev, struct device_attribute *attr, char *buf) { return scnprintf(buf, PAGE_SIZE, "%s\n", qla2x00_version_str); @@ -1036,7 +1109,7 @@ qla2x00_link_state_show(struct device *dev, struct device_attribute *attr, vha->device_flags & DFLG_NO_CABLE) len = scnprintf(buf, PAGE_SIZE, "Link Down\n"); else if (atomic_read(&vha->loop_state) != LOOP_READY || - qla2x00_reset_active(vha)) + qla2x00_chip_is_down(vha)) len = scnprintf(buf, PAGE_SIZE, "Unknown Link State\n"); else { len = scnprintf(buf, PAGE_SIZE, "Link Up - "); @@ -1137,6 +1210,34 @@ qla2x00_zio_timer_store(struct device *dev, struct device_attribute *attr, return strlen(buf); } +static ssize_t +qla_zio_threshold_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + + return scnprintf(buf, PAGE_SIZE, "%d exchanges\n", + vha->hw->last_zio_threshold); +} + +static ssize_t +qla_zio_threshold_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (vha->hw->zio_mode != QLA_ZIO_MODE_6) + return -EINVAL; + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + if (val < 0 || val > 256) + return -ERANGE; + + atomic_set(&vha->hw->zio_threshold, val); + return strlen(buf); +} + static ssize_t qla2x00_beacon_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -1163,15 +1264,17 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, if (IS_QLA2100(ha) || IS_QLA2200(ha)) return -EPERM; - if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) { + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x707a, "Abort ISP active -- ignoring beacon request.\n"); return -EBUSY; } - if (sscanf(buf, "%d", &val) != 1) - return -EINVAL; - if (val) rval = ha->isp_ops->beacon_on(vha); else @@ -1180,6 +1283,8 @@ qla2x00_beacon_store(struct device *dev, struct device_attribute *attr, if (rval != QLA_SUCCESS) count = 0; + mutex_unlock(&vha->hw->optrom_mutex); + return count; } @@ -1349,18 +1454,24 @@ qla2x00_thermal_temp_show(struct device *dev, { scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); uint16_t temp = 0; + int rc; - if (qla2x00_reset_active(vha)) { + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x70dc, "ISP reset active.\n"); goto done; } if (vha->hw->flags.eeh_busy) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x70dd, "PCI EEH busy.\n"); goto done; } - if (qla2x00_get_thermal_temp(vha, &temp) == QLA_SUCCESS) + rc = qla2x00_get_thermal_temp(vha, &temp); + mutex_unlock(&vha->hw->optrom_mutex); + if (rc == QLA_SUCCESS) return scnprintf(buf, PAGE_SIZE, "%d\n", temp); done: @@ -1381,13 +1492,24 @@ qla2x00_fw_state_show(struct device *dev, struct device_attribute *attr, return scnprintf(buf, PAGE_SIZE, "0x%x\n", pstate); } - if (qla2x00_reset_active(vha)) + mutex_lock(&vha->hw->optrom_mutex); + if (qla2x00_chip_is_down(vha)) { + mutex_unlock(&vha->hw->optrom_mutex); ql_log(ql_log_warn, vha, 0x707c, "ISP reset active.\n"); - else if (!vha->hw->flags.eeh_busy) - rval = qla2x00_get_firmware_state(vha, state); - if (rval != QLA_SUCCESS) + goto out; + } else if (vha->hw->flags.eeh_busy) { + mutex_unlock(&vha->hw->optrom_mutex); + goto out; + } + + rval = qla2x00_get_firmware_state(vha, state); + mutex_unlock(&vha->hw->optrom_mutex); +out: + if (rval != QLA_SUCCESS) { memset(state, -1, sizeof(state)); + rval = qla2x00_get_firmware_state(vha, state); + } return scnprintf(buf, PAGE_SIZE, "0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", state[0], state[1], state[2], state[3], state[4], state[5]); @@ -1513,7 +1635,536 @@ qla2x00_max_speed_sup_show(struct device *dev, struct device_attribute *attr, ha->max_speed_sup ? "32Gps" : "16Gps"); } -static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_drvr_version_show, NULL); +static ssize_t +qla2x00_port_speed_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev)); + ulong type, speed; + int oldspeed, rval; + int mode = QLA_SET_DATA_RATE_LR; + struct qla_hw_data *ha = vha->hw; + + if (!IS_QLA27XX(vha->hw)) { + ql_log(ql_log_warn, vha, 0x70d8, + "Speed setting not supported \n"); + return -EINVAL; + } + + rval = kstrtol(buf, 10, &type); + if (rval) + return rval; + speed = type; + if (type == 40 || type == 80 || type == 160 || + type == 320) { + ql_dbg(ql_dbg_user, vha, 0x70d9, + "Setting will be affected after a loss of sync\n"); + type = type/10; + mode = QLA_SET_DATA_RATE_NOLR; + } + + oldspeed = ha->set_data_rate; + + switch (type) { + case 0: + ha->set_data_rate = PORT_SPEED_AUTO; + break; + case 4: + ha->set_data_rate = PORT_SPEED_4GB; + break; + case 8: + ha->set_data_rate = PORT_SPEED_8GB; + break; + case 16: + ha->set_data_rate = PORT_SPEED_16GB; + break; + case 32: + ha->set_data_rate = PORT_SPEED_32GB; + break; + default: + ql_log(ql_log_warn, vha, 0x1199, + "Unrecognized speed setting:%lx. Setting Autoneg\n", + speed); + ha->set_data_rate = PORT_SPEED_AUTO; + } + + if (qla2x00_chip_is_down(vha) || (oldspeed == ha->set_data_rate)) + return -EINVAL; + + ql_log(ql_log_info, vha, 0x70da, + "Setting speed to %lx Gbps \n", type); + + rval = qla2x00_set_data_rate(vha, mode); + if (rval != QLA_SUCCESS) + return -EIO; + + return strlen(buf); +} + +static ssize_t +qla2x00_port_speed_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct scsi_qla_host *vha = shost_priv(dev_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + ssize_t rval; + char *spd[7] = {"0", "0", "0", "4", "8", "16", "32"}; + + rval = qla2x00_get_data_rate(vha); + if (rval != QLA_SUCCESS) { + ql_log(ql_log_warn, vha, 0x70db, + "Unable to get port speed rval:%zd\n", rval); + return -EINVAL; + } + + ql_log(ql_log_info, vha, 0x70d6, + "port speed:%d\n", ha->link_data_rate); + + return scnprintf(buf, PAGE_SIZE, "%s\n", spd[ha->link_data_rate]); +} + +/* ----- */ + +static ssize_t +qlini_mode_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Supported options: enabled | disabled | dual | exclusive\n"); + + /* --- */ + len += scnprintf(buf + len, PAGE_SIZE-len, "Current selection: "); + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_EXCLUSIVE); + break; + case QLA2XXX_INI_MODE_DISABLED: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_DISABLED); + break; + case QLA2XXX_INI_MODE_ENABLED: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_ENABLED); + break; + case QLA2XXX_INI_MODE_DUAL: + len += scnprintf(buf + len, PAGE_SIZE-len, + QLA2XXX_INI_MODE_STR_DUAL); + break; + } + len += scnprintf(buf + len, PAGE_SIZE-len, "\n"); + + return len; +} + +static char *mode_to_str[] = { + "exclusive", + "disabled", + "enabled", + "dual", +}; + +#define NEED_EXCH_OFFLOAD(_exchg) ((_exchg) > FW_DEF_EXCHANGES_CNT) +static int qla_set_ini_mode(scsi_qla_host_t *vha, int op) +{ + int rc = 0; + enum { + NO_ACTION, + MODE_CHANGE_ACCEPT, + MODE_CHANGE_NO_ACTION, + TARGET_STILL_ACTIVE, + }; + int action = NO_ACTION; + int set_mode = 0; + u8 eo_toggle = 0; /* exchange offload flipped */ + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_DISABLED: + switch (op) { + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) { + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) { + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + } else { + action = MODE_CHANGE_ACCEPT; + } + break; + case QLA2XXX_INI_MODE_DUAL: + action = MODE_CHANGE_ACCEPT; + /* active_mode is target only, reset it to dual */ + if (qla_tgt_mode_enabled(vha)) { + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha)) + action = TARGET_STILL_ACTIVE; + else { + action = MODE_CHANGE_ACCEPT; + set_mode = 1; + } + break; + } + break; + + case QLA2XXX_INI_MODE_EXCLUSIVE: + switch (op) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) + /* + * The number of exchange to be offload + * was tweaked or offload option was + * flipped + */ + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + } else + action = NO_ACTION; + + break; + + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xexchoffld != + vha->u_ql2xexchoffld) && + NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld)) || + eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = MODE_CHANGE_NO_ACTION; + } else + action = MODE_CHANGE_NO_ACTION; + break; + + case QLA2XXX_INI_MODE_DUAL: /* exclusive -> dual */ + if (qla_tgt_mode_enabled(vha)) { + action = MODE_CHANGE_ACCEPT; + set_mode = 1; + } else + action = MODE_CHANGE_ACCEPT; + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha)) + action = TARGET_STILL_ACTIVE; + else { + if (vha->hw->flags.fw_started) + action = MODE_CHANGE_NO_ACTION; + else + action = MODE_CHANGE_ACCEPT; + } + break; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + switch (op) { + case QLA2XXX_INI_MODE_ENABLED: + if (NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + if (((vha->ql2xiniexchg != vha->u_ql2xiniexchg) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg)) || + eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + break; + case QLA2XXX_INI_MODE_DUAL: + case QLA2XXX_INI_MODE_DISABLED: + action = MODE_CHANGE_ACCEPT; + break; + default: + action = MODE_CHANGE_NO_ACTION; + break; + } + break; + + case QLA2XXX_INI_MODE_DUAL: + switch (op) { + case QLA2XXX_INI_MODE_DUAL: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld + + vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + + if ((((vha->ql2xexchoffld + + vha->ql2xiniexchg) != + (vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) || eo_toggle) + action = MODE_CHANGE_ACCEPT; + else + action = NO_ACTION; + } else { + if (NEED_EXCH_OFFLOAD(vha->u_ql2xexchoffld + + vha->u_ql2xiniexchg) != + vha->hw->flags.exchoffld_enabled) + eo_toggle = 1; + + if ((((vha->ql2xexchoffld + vha->ql2xiniexchg) + != (vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) && + NEED_EXCH_OFFLOAD(vha->u_ql2xiniexchg + + vha->u_ql2xexchoffld)) || eo_toggle) + action = MODE_CHANGE_NO_ACTION; + else + action = NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_DISABLED: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + /* turning off initiator mode */ + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_NO_ACTION; + } + break; + + case QLA2XXX_INI_MODE_EXCLUSIVE: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + set_mode = 1; + action = MODE_CHANGE_ACCEPT; + } else { + action = MODE_CHANGE_ACCEPT; + } + break; + + case QLA2XXX_INI_MODE_ENABLED: + if (qla_tgt_mode_enabled(vha) || + qla_dual_mode_enabled(vha)) { + action = TARGET_STILL_ACTIVE; + } else { + action = MODE_CHANGE_ACCEPT; + } + } + break; + } + + switch (action) { + case MODE_CHANGE_ACCEPT: + ql_log(ql_log_warn, vha, 0xffff, + "Mode change accepted. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n", + mode_to_str[vha->qlini_mode], mode_to_str[op], + vha->ql2xexchoffld, vha->u_ql2xexchoffld, + vha->ql2xiniexchg, vha->u_ql2xiniexchg); + + vha->qlini_mode = op; + vha->ql2xexchoffld = vha->u_ql2xexchoffld; + vha->ql2xiniexchg = vha->u_ql2xiniexchg; + if (set_mode) + qlt_set_mode(vha); + vha->flags.online = 1; + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + break; + + case MODE_CHANGE_NO_ACTION: + ql_log(ql_log_warn, vha, 0xffff, + "Mode is set. No action taken. From %s to %s, Tgt exchg %d|%d. ini exchg %d|%d\n", + mode_to_str[vha->qlini_mode], mode_to_str[op], + vha->ql2xexchoffld, vha->u_ql2xexchoffld, + vha->ql2xiniexchg, vha->u_ql2xiniexchg); + vha->qlini_mode = op; + vha->ql2xexchoffld = vha->u_ql2xexchoffld; + vha->ql2xiniexchg = vha->u_ql2xiniexchg; + break; + + case TARGET_STILL_ACTIVE: + ql_log(ql_log_warn, vha, 0xffff, + "Target Mode is active. Unable to change Mode.\n"); + break; + + case NO_ACTION: + default: + ql_log(ql_log_warn, vha, 0xffff, + "Mode unchange. No action taken. %d|%d pct %d|%d.\n", + vha->qlini_mode, op, + vha->ql2xexchoffld, vha->u_ql2xexchoffld); + break; + } + + return rc; +} + +static ssize_t +qlini_mode_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int ini; + + if (!buf) + return -EINVAL; + + if (strncasecmp(QLA2XXX_INI_MODE_STR_EXCLUSIVE, buf, + strlen(QLA2XXX_INI_MODE_STR_EXCLUSIVE)) == 0) + ini = QLA2XXX_INI_MODE_EXCLUSIVE; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_DISABLED, buf, + strlen(QLA2XXX_INI_MODE_STR_DISABLED)) == 0) + ini = QLA2XXX_INI_MODE_DISABLED; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_ENABLED, buf, + strlen(QLA2XXX_INI_MODE_STR_ENABLED)) == 0) + ini = QLA2XXX_INI_MODE_ENABLED; + else if (strncasecmp(QLA2XXX_INI_MODE_STR_DUAL, buf, + strlen(QLA2XXX_INI_MODE_STR_DUAL)) == 0) + ini = QLA2XXX_INI_MODE_DUAL; + else + return -EINVAL; + + qla_set_ini_mode(vha, ini); + return strlen(buf); +} + +static ssize_t +ql2xexchoffld_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "target exchange: new %d : current: %d\n\n", + vha->u_ql2xexchoffld, vha->ql2xexchoffld); + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n", + vha->host_no); + + return len; +} + +static ssize_t +ql2xexchoffld_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + if (val > FW_MAX_EXCHANGES_CNT) + val = FW_MAX_EXCHANGES_CNT; + else if (val < 0) + val = 0; + + vha->u_ql2xexchoffld = val; + return strlen(buf); +} + +static ssize_t +ql2xiniexchg_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int len = 0; + + len += scnprintf(buf + len, PAGE_SIZE-len, + "target exchange: new %d : current: %d\n\n", + vha->u_ql2xiniexchg, vha->ql2xiniexchg); + + len += scnprintf(buf + len, PAGE_SIZE-len, + "Please (re)set operating mode via \"/sys/class/scsi_host/host%ld/qlini_mode\" to load new setting.\n", + vha->host_no); + + return len; +} + +static ssize_t +ql2xiniexchg_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + int val = 0; + + if (sscanf(buf, "%d", &val) != 1) + return -EINVAL; + + if (val > FW_MAX_EXCHANGES_CNT) + val = FW_MAX_EXCHANGES_CNT; + else if (val < 0) + val = 0; + + vha->u_ql2xiniexchg = val; + return strlen(buf); +} + +static ssize_t +qla2x00_dif_bundle_statistics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + scsi_qla_host_t *vha = shost_priv(class_to_shost(dev)); + struct qla_hw_data *ha = vha->hw; + + return scnprintf(buf, PAGE_SIZE, + "cross=%llu read=%llu write=%llu kalloc=%llu dma_alloc=%llu unusable=%u\n", + ha->dif_bundle_crossed_pages, ha->dif_bundle_reads, + ha->dif_bundle_writes, ha->dif_bundle_kallocs, + ha->dif_bundle_dma_allocs, ha->pool.unusable.count); +} + +static DEVICE_ATTR(driver_version, S_IRUGO, qla2x00_driver_version_show, NULL); static DEVICE_ATTR(fw_version, S_IRUGO, qla2x00_fw_version_show, NULL); static DEVICE_ATTR(serial_num, S_IRUGO, qla2x00_serial_num_show, NULL); static DEVICE_ATTR(isp_name, S_IRUGO, qla2x00_isp_name_show, NULL); @@ -1560,6 +2211,17 @@ static DEVICE_ATTR(allow_cna_fw_dump, S_IRUGO | S_IWUSR, static DEVICE_ATTR(pep_version, S_IRUGO, qla2x00_pep_version_show, NULL); static DEVICE_ATTR(min_link_speed, S_IRUGO, qla2x00_min_link_speed_show, NULL); static DEVICE_ATTR(max_speed_sup, S_IRUGO, qla2x00_max_speed_sup_show, NULL); +static DEVICE_ATTR(zio_threshold, 0644, + qla_zio_threshold_show, + qla_zio_threshold_store); +static DEVICE_ATTR_RW(qlini_mode); +static DEVICE_ATTR_RW(ql2xexchoffld); +static DEVICE_ATTR_RW(ql2xiniexchg); +static DEVICE_ATTR(dif_bundle_statistics, 0444, + qla2x00_dif_bundle_statistics_show, NULL); +static DEVICE_ATTR(port_speed, 0644, qla2x00_port_speed_show, + qla2x00_port_speed_store); + struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_driver_version, @@ -1596,9 +2258,30 @@ struct device_attribute *qla2x00_host_attrs[] = { &dev_attr_pep_version, &dev_attr_min_link_speed, &dev_attr_max_speed_sup, + &dev_attr_zio_threshold, + &dev_attr_dif_bundle_statistics, + &dev_attr_port_speed, + NULL, /* reserve for qlini_mode */ + NULL, /* reserve for ql2xiniexchg */ + NULL, /* reserve for ql2xexchoffld */ NULL, }; +void qla_insert_tgt_attrs(void) +{ + struct device_attribute **attr; + + /* advance to empty slot */ + for (attr = &qla2x00_host_attrs[0]; *attr; ++attr) + continue; + + *attr = &dev_attr_qlini_mode; + attr++; + *attr = &dev_attr_ql2xiniexchg; + attr++; + *attr = &dev_attr_ql2xexchoffld; +} + /* Host attributes. */ static void @@ -1840,11 +2523,11 @@ qla2x00_get_fc_host_stats(struct Scsi_Host *shost) if (unlikely(pci_channel_offline(ha->pdev))) goto done; - if (qla2x00_reset_active(vha)) + if (qla2x00_chip_is_down(vha)) goto done; - stats = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*stats), - &stats_dma, GFP_KERNEL); + stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma, + GFP_KERNEL); if (!stats) { ql_log(ql_log_warn, vha, 0x707d, "Failed to allocate memory for stats.\n"); @@ -2140,6 +2823,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport) test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags)) msleep(1000); + qla_nvme_delete(vha); + qla24xx_disable_vp(vha); qla2x00_wait_for_sess_deletion(vha); diff --git a/qla2x00t-32gbit/qla_bsg.c b/qla2x00t-32gbit/qla_bsg.c index c11a89be2..17d42658a 100644 --- a/qla2x00t-32gbit/qla_bsg.c +++ b/qla2x00t-32gbit/qla_bsg.c @@ -2312,8 +2312,8 @@ qla2x00_get_priv_stats(struct bsg_job *bsg_job) if (!IS_FWI2_CAPABLE(ha)) return -EPERM; - stats = dma_zalloc_coherent(&ha->pdev->dev, sizeof(*stats), - &stats_dma, GFP_KERNEL); + stats = dma_alloc_coherent(&ha->pdev->dev, sizeof(*stats), &stats_dma, + GFP_KERNEL); if (!stats) { ql_log(ql_log_warn, vha, 0x70e2, "Failed to allocate memory for stats.\n"); @@ -2487,7 +2487,7 @@ qla24xx_bsg_request(struct bsg_job *bsg_job) vha = shost_priv(host); } - if (qla2x00_reset_active(vha)) { + if (qla2x00_chip_is_down(vha)) { ql_dbg(ql_dbg_user, vha, 0x709f, "BSG: ISP abort active/needed -- cmd=%d.\n", bsg_request->msgcode); diff --git a/qla2x00t-32gbit/qla_dbg.c b/qla2x00t-32gbit/qla_dbg.c index 5fd44c50b..c7533fa7f 100644 --- a/qla2x00t-32gbit/qla_dbg.c +++ b/qla2x00t-32gbit/qla_dbg.c @@ -1130,6 +1130,7 @@ qla24xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) ha->fw_dump); goto qla24xx_fw_dump_failed; } + QLA_FW_STOPPED(ha); fw = &ha->fw_dump->isp.isp24; qla2xxx_prep_dump(ha, ha->fw_dump); @@ -1384,6 +1385,7 @@ qla25xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) ha->fw_dump); goto qla25xx_fw_dump_failed; } + QLA_FW_STOPPED(ha); fw = &ha->fw_dump->isp.isp25; qla2xxx_prep_dump(ha, ha->fw_dump); ha->fw_dump->version = htonl(2); @@ -2036,6 +2038,7 @@ qla83xx_fw_dump(scsi_qla_host_t *vha, int hardware_locked) "request...\n", ha->fw_dump); goto qla83xx_fw_dump_failed; } + QLA_FW_STOPPED(ha); fw = &ha->fw_dump->isp.isp83; qla2xxx_prep_dump(ha, ha->fw_dump); diff --git a/qla2x00t-32gbit/qla_def.h b/qla2x00t-32gbit/qla_def.h index 0f94b1d62..3d46975a5 100644 --- a/qla2x00t-32gbit/qla_def.h +++ b/qla2x00t-32gbit/qla_def.h @@ -262,8 +262,8 @@ struct name_list_extended { struct get_name_list_extended *l; dma_addr_t ldma; struct list_head fcports; - spinlock_t fcports_lock; u32 size; + u8 sent; }; /* * Timeout timer counts in seconds @@ -313,6 +313,8 @@ struct srb_cmd { #define SRB_CRC_CTX_DMA_VALID BIT_2 /* DIF: context DMA valid */ #define SRB_CRC_PROT_DMA_VALID BIT_4 /* DIF: prot DMA valid */ #define SRB_CRC_CTX_DSD_VALID BIT_5 /* DIF: dsd_list valid */ +#define SRB_WAKEUP_ON_COMP BIT_6 +#define SRB_DIF_BUNDL_DMA_VALID BIT_7 /* DIF: DMA list valid */ /* To identify if a srb is of T10-CRC type. @sp => srb_t pointer */ #define IS_PROT_IO(sp) (sp->flags & SRB_CRC_CTX_DSD_VALID) @@ -379,6 +381,7 @@ struct srb_iocb { #define SRB_LOGIN_COND_PLOGI BIT_1 #define SRB_LOGIN_SKIP_PRLI BIT_2 #define SRB_LOGIN_NVME_PRLI BIT_3 +#define SRB_LOGIN_PRLI_ONLY BIT_4 uint16_t data[2]; u32 iop[2]; } logio; @@ -398,6 +401,8 @@ struct srb_iocb { struct completion comp; struct els_plogi_payload *els_plogi_pyld; struct els_plogi_payload *els_resp_pyld; + u32 tx_size; + u32 rx_size; dma_addr_t els_plogi_pyld_dma; dma_addr_t els_resp_pyld_dma; uint32_t fw_status[3]; @@ -515,6 +520,7 @@ struct srb_iocb { enum { TYPE_SRB, TYPE_TGT_CMD, + TYPE_TGT_TMCMD, /* task management */ }; typedef struct srb { @@ -1887,6 +1893,13 @@ struct crc_context { /* List of DMA context transfers */ struct list_head dsd_list; + /* List of DIF Bundling context DMA address */ + struct list_head ldif_dsd_list; + u8 no_ldif_dsd; + + struct list_head ldif_dma_hndl_list; + u32 dif_bundl_len; + u8 no_dif_bundl; /* This structure should not exceed 512 bytes */ }; @@ -2276,7 +2289,6 @@ struct ct_sns_desc { enum discovery_state { DSC_DELETED, DSC_GNN_ID, - DSC_GID_PN, DSC_GNL, DSC_LOGIN_PEND, DSC_LOGIN_FAILED, @@ -2301,7 +2313,6 @@ enum login_state { /* FW control Target side */ enum fcport_mgt_event { FCME_RELOGIN = 1, FCME_RSCN, - FCME_GIDPN_DONE, FCME_PLOGI_DONE, /* Initiator side sent LLIOCB */ FCME_PRLI_DONE, FCME_GNL_DONE, @@ -2312,6 +2323,7 @@ enum fcport_mgt_event { FCME_ADISC_DONE, FCME_GNNID_DONE, FCME_GFPNID_DONE, + FCME_ELS_PLOGI_DONE, }; enum rscn_addr_format { @@ -2346,7 +2358,7 @@ typedef struct fc_port { unsigned int login_succ:1; unsigned int query:1; unsigned int id_changed:1; - unsigned int rscn_rcvd:1; + unsigned int scan_needed:1; struct work_struct nvme_del_work; struct completion nvme_del_done; @@ -2355,7 +2367,9 @@ typedef struct fc_port { #define NVME_PRLI_SP_INITIATOR BIT_5 #define NVME_PRLI_SP_TARGET BIT_4 #define NVME_PRLI_SP_DISCOVERY BIT_3 +#define NVME_PRLI_SP_FIRST_BURST BIT_0 uint8_t nvme_flag; + uint32_t nvme_first_burst_size; #define NVME_FLAG_REGISTERED 4 #define NVME_FLAG_DELETING 2 #define NVME_FLAG_RESETTING 1 @@ -2370,11 +2384,13 @@ typedef struct fc_port { unsigned long expires; struct list_head del_list_entry; struct work_struct free_work; - + struct work_struct reg_work; + uint64_t jiffies_at_registration; struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX]; uint16_t tgt_id; uint16_t old_tgt_id; + uint16_t sec_since_registration; uint8_t fcp_prio; @@ -2407,7 +2423,9 @@ typedef struct fc_port { struct qla_tgt_sess *tgt_session; struct ct_sns_desc ct_desc; enum discovery_state disc_state; + enum discovery_state next_disc_state; enum login_state fw_login_state; + unsigned long dm_login_expire; unsigned long plogi_nack_done_deadline; u32 login_gen, last_login_gen; @@ -2418,7 +2436,8 @@ typedef struct fc_port { u8 iocb[IOCB_SIZE]; u8 current_login_state; u8 last_login_state; - struct completion n2n_done; + u16 n2n_link_reset_cnt; + u16 n2n_chip_reset; } fc_port_t; #define QLA_FCPORT_SCAN 1 @@ -3205,17 +3224,14 @@ enum qla_work_type { QLA_EVT_ASYNC_LOGOUT, QLA_EVT_ASYNC_LOGOUT_DONE, QLA_EVT_ASYNC_ADISC, - QLA_EVT_ASYNC_ADISC_DONE, QLA_EVT_UEVENT, QLA_EVT_AENFX, - QLA_EVT_GIDPN, QLA_EVT_GPNID, QLA_EVT_UNMAP, QLA_EVT_NEW_SESS, QLA_EVT_GPDB, QLA_EVT_PRLI, QLA_EVT_GPSC, - QLA_EVT_UPD_FCPORT, QLA_EVT_GNL, QLA_EVT_NACK, QLA_EVT_RELOGIN, @@ -3228,6 +3244,7 @@ enum qla_work_type { QLA_EVT_GFPNID, QLA_EVT_SP_RETRY, QLA_EVT_IIDMA, + QLA_EVT_ELS_PLOGI, }; @@ -3475,6 +3492,9 @@ struct qla_qpair { struct list_head qp_list_elem; /* vha->qp_list */ struct list_head hints_list; uint16_t cpuid; + uint16_t retry_term_cnt; + uint32_t retry_term_exchg_addr; + uint64_t retry_term_jiff; struct qla_tgt_counters tgt_counters; }; @@ -3599,6 +3619,8 @@ struct qla_hw_data { uint32_t detected_lr_sfp:1; uint32_t using_lr_setting:1; uint32_t rida_fmt2:1; + uint32_t purge_mbox:1; + uint32_t n2n_bigger:1; } flags; uint16_t max_exchg; @@ -3676,12 +3698,14 @@ struct qla_hw_data { #define PORT_SPEED_UNKNOWN 0xFFFF #define PORT_SPEED_1GB 0x00 #define PORT_SPEED_2GB 0x01 +#define PORT_SPEED_AUTO 0x02 #define PORT_SPEED_4GB 0x03 #define PORT_SPEED_8GB 0x04 #define PORT_SPEED_16GB 0x05 #define PORT_SPEED_32GB 0x06 #define PORT_SPEED_10GB 0x13 uint16_t link_data_rate; /* F/W operating speed */ + uint16_t set_data_rate; /* Set by user */ uint8_t current_topology; uint8_t prev_topology; @@ -3844,6 +3868,10 @@ struct qla_hw_data { int port_down_retry_count; uint8_t mbx_count; uint8_t aen_mbx_count; + atomic_t num_pend_mbx_stage1; + atomic_t num_pend_mbx_stage2; + atomic_t num_pend_mbx_stage3; + uint16_t frame_payload_size; uint32_t login_retry_count; /* SNS command interfaces. */ @@ -3903,6 +3931,9 @@ struct qla_hw_data { int exchoffld_size; int exchoffld_count; + /* n2n */ + struct els_plogi_payload plogi_els_payld; + void *swl; /* These are used by mailbox operations. */ @@ -3939,6 +3970,10 @@ struct qla_hw_data { uint16_t fw_subminor_version; uint16_t fw_attributes; uint16_t fw_attributes_h; +#define FW_ATTR_H_NVME_FBURST BIT_1 +#define FW_ATTR_H_NVME BIT_10 +#define FW_ATTR_H_NVME_UPDATED BIT_14 + uint16_t fw_attributes_ext[2]; uint32_t fw_memory_size; uint32_t fw_transfer_size; @@ -4157,6 +4192,7 @@ struct qla_hw_data { struct work_struct board_disable; struct mr_data_fx00 mr; + uint32_t chip_reset; struct qlt_hw_data tgt; int allow_cna_fw_dump; @@ -4164,8 +4200,32 @@ struct qla_hw_data { uint16_t min_link_speed; uint16_t max_speed_sup; + /* DMA pool for the DIF bundling buffers */ + struct dma_pool *dif_bundl_pool; + #define DIF_BUNDLING_DMA_POOL_SIZE 1024 + struct { + struct { + struct list_head head; + uint count; + } good; + struct { + struct list_head head; + uint count; + } unusable; + } pool; + + unsigned long long dif_bundle_crossed_pages; + unsigned long long dif_bundle_reads; + unsigned long long dif_bundle_writes; + unsigned long long dif_bundle_kallocs; + unsigned long long dif_bundle_dma_allocs; + atomic_t nvme_active_aen_cnt; uint16_t nvme_last_rptd_aen; /* Last recorded aen count */ + + atomic_t zio_threshold; + uint16_t last_zio_threshold; +#define DEFAULT_ZIO_THRESHOLD 5 }; #define FW_ABILITY_MAX_SPEED_MASK 0xFUL @@ -4174,6 +4234,10 @@ struct qla_hw_data { #define FW_ABILITY_MAX_SPEED(ha) \ (ha->fw_ability_mask & FW_ABILITY_MAX_SPEED_MASK) +#define QLA_GET_DATA_RATE 0 +#define QLA_SET_DATA_RATE_NOLR 1 +#define QLA_SET_DATA_RATE_LR 2 /* Set speed and initiate LR */ + /* * Qlogic scsi host structure */ @@ -4205,6 +4269,7 @@ typedef struct scsi_qla_host { uint32_t qpairs_req_created:1; uint32_t qpairs_rsp_created:1; uint32_t nvme_enabled:1; + uint32_t nvme_first_burst:1; } flags; atomic_t loop_state; @@ -4238,17 +4303,18 @@ typedef struct scsi_qla_host { #define FCOE_CTX_RESET_NEEDED 18 /* Initiate FCoE context reset */ #define MPI_RESET_NEEDED 19 /* Initiate MPI FW reset */ #define ISP_QUIESCE_NEEDED 20 /* Driver need some quiescence */ -#define FREE_BIT 21 +#define N2N_LINK_RESET 21 #define PORT_UPDATE_NEEDED 22 #define FX00_RESET_RECOVERY 23 #define FX00_TARGET_SCAN 24 #define FX00_CRITEMP_RECOVERY 25 #define FX00_HOST_INFO_RESEND 26 #define QPAIR_ONLINE_CHECK_NEEDED 27 -#define SET_ZIO_THRESHOLD_NEEDED 28 +#define SET_NVME_ZIO_THRESHOLD_NEEDED 28 #define DETECT_SFP_CHANGE 29 #define N2N_LOGIN_NEEDED 30 #define IOCB_WORK_ACTIVE 31 +#define SET_ZIO_THRESHOLD_NEEDED 32 unsigned long pci_flags; #define PFLG_DISCONNECTED 0 /* PCI device removed */ @@ -4351,6 +4417,13 @@ typedef struct scsi_qla_host { atomic_t vref_count; struct qla8044_reset_template reset_tmplt; uint16_t bbcr; + + uint16_t u_ql2xexchoffld; + uint16_t u_ql2xiniexchg; + uint16_t qlini_mode; + uint16_t ql2xexchoffld; + uint16_t ql2xiniexchg; + struct name_list_extended gnl; /* Count of active session/fcport */ int fcport_count; @@ -4362,6 +4435,8 @@ typedef struct scsi_qla_host { uint16_t n2n_id; struct list_head gpnid_list; struct fab_scan scan; + + unsigned int irq_offset; } scsi_qla_host_t; struct qla27xx_image_status { diff --git a/qla2x00t-32gbit/qla_dfs.c b/qla2x00t-32gbit/qla_dfs.c index 0b190082a..5819a45ac 100644 --- a/qla2x00t-32gbit/qla_dfs.c +++ b/qla2x00t-32gbit/qla_dfs.c @@ -193,6 +193,8 @@ qla_dfs_tgt_counters_show(struct seq_file *s, void *unused) for (i = 0; i < vha->hw->max_qpairs; i++) { qpair = vha->hw->queue_pair_map[i]; + if (!qpair) + continue; qla_core_sbt_cmd += qpair->tgt_counters.qla_core_sbt_cmd; core_qla_que_buf += qpair->tgt_counters.core_qla_que_buf; qla_core_ret_ctio += qpair->tgt_counters.qla_core_ret_ctio; @@ -446,11 +448,6 @@ qla2x00_dfs_setup(scsi_qla_host_t *vha) atomic_set(&qla2x00_dfs_root_count, 0); qla2x00_dfs_root = debugfs_create_dir(QLA2XXX_DRIVER_NAME, NULL); - if (!qla2x00_dfs_root) { - ql_log(ql_log_warn, vha, 0x00f7, - "Unable to create debugfs root directory.\n"); - goto out; - } create_dir: if (ha->dfs_dir) @@ -458,64 +455,28 @@ create_dir: mutex_init(&ha->fce_mutex); ha->dfs_dir = debugfs_create_dir(vha->host_str, qla2x00_dfs_root); - if (!ha->dfs_dir) { - ql_log(ql_log_warn, vha, 0x00f8, - "Unable to create debugfs ha directory.\n"); - goto out; - } atomic_inc(&qla2x00_dfs_root_count); create_nodes: ha->dfs_fw_resource_cnt = debugfs_create_file("fw_resource_count", S_IRUSR, ha->dfs_dir, vha, &dfs_fw_resource_cnt_ops); - if (!ha->dfs_fw_resource_cnt) { - ql_log(ql_log_warn, vha, 0x00fd, - "Unable to create debugFS fw_resource_count node.\n"); - goto out; - } ha->dfs_tgt_counters = debugfs_create_file("tgt_counters", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_counters_ops); - if (!ha->dfs_tgt_counters) { - ql_log(ql_log_warn, vha, 0xd301, - "Unable to create debugFS tgt_counters node.\n"); - goto out; - } ha->tgt.dfs_tgt_port_database = debugfs_create_file("tgt_port_database", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_port_database_ops); - if (!ha->tgt.dfs_tgt_port_database) { - ql_log(ql_log_warn, vha, 0xd03f, - "Unable to create debugFS tgt_port_database node.\n"); - goto out; - } ha->dfs_fce = debugfs_create_file("fce", S_IRUSR, ha->dfs_dir, vha, &dfs_fce_ops); - if (!ha->dfs_fce) { - ql_log(ql_log_warn, vha, 0x00f9, - "Unable to create debugfs fce node.\n"); - goto out; - } ha->tgt.dfs_tgt_sess = debugfs_create_file("tgt_sess", S_IRUSR, ha->dfs_dir, vha, &dfs_tgt_sess_ops); - if (!ha->tgt.dfs_tgt_sess) { - ql_log(ql_log_warn, vha, 0xd040, - "Unable to create debugFS tgt_sess node.\n"); - goto out; - } - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) { + if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) ha->tgt.dfs_naqp = debugfs_create_file("naqp", 0400, ha->dfs_dir, vha, &dfs_naqp_ops); - if (!ha->tgt.dfs_naqp) { - ql_log(ql_log_warn, vha, 0xd011, - "Unable to create debugFS naqp node.\n"); - goto out; - } - } out: return 0; } diff --git a/qla2x00t-32gbit/qla_fw.h b/qla2x00t-32gbit/qla_fw.h index 5d8688e5b..50c1e6c62 100644 --- a/qla2x00t-32gbit/qla_fw.h +++ b/qla2x00t-32gbit/qla_fw.h @@ -1366,6 +1366,11 @@ struct vp_rpt_id_entry_24xx { /* format 1 fabric */ uint8_t vpstat1_subcode; /* vp_status=1 subcode */ uint8_t flags; +#define TOPO_MASK 0xE +#define TOPO_FL 0x2 +#define TOPO_N2N 0x4 +#define TOPO_F 0x6 + uint16_t fip_flags; uint8_t rsv2[12]; diff --git a/qla2x00t-32gbit/qla_gbl.h b/qla2x00t-32gbit/qla_gbl.h index 2660a48d9..4eefe69ca 100644 --- a/qla2x00t-32gbit/qla_gbl.h +++ b/qla2x00t-32gbit/qla_gbl.h @@ -45,8 +45,7 @@ extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t); -extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, - port_id_t); +extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, bool); extern void qla2x00_update_fcports(scsi_qla_host_t *); @@ -55,7 +54,7 @@ extern void qla2x00_abort_isp_cleanup(scsi_qla_host_t *); extern void qla2x00_quiesce_io(scsi_qla_host_t *); extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *); - +void qla_register_fcport_fn(struct work_struct *); extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *); extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *); @@ -74,8 +73,6 @@ extern void qla2x00_async_login_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern void qla2x00_async_logout_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); -extern void qla2x00_async_adisc_done(struct scsi_qla_host *, fc_port_t *, - uint16_t *); struct qla_work_evt *qla2x00_alloc_work(struct scsi_qla_host *, enum qla_work_type); extern int qla24xx_async_gnl(struct scsi_qla_host *, fc_port_t *); @@ -110,6 +107,7 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *, u8*, int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *); int qla24xx_detect_sfp(scsi_qla_host_t *vha); int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8); + void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *, uint16_t *); extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *, @@ -118,6 +116,9 @@ extern int qla2x00_post_async_prlo_done_work(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla_post_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); void qla_do_iidma_work(struct scsi_qla_host *vha, fc_port_t *fcport); +int qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *); +void qla_rscn_replay(fc_port_t *fcport); + /* * Global Data in qla_os.c source file. */ @@ -158,6 +159,8 @@ extern int ql2xnvmeenable; extern int ql2xautodetectsfp; extern int ql2xenablemsix; extern int qla2xuseresexchforels; +extern int ql2xexlogins; +extern int ql2xdifbundlinginternalbuffers; extern int qla2x00_loop_reset(scsi_qla_host_t *); extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int); @@ -208,11 +211,11 @@ extern void qla2x00_disable_board_on_pci_error(struct work_struct *); extern void qla2x00_sp_compl(void *, int); extern void qla2xxx_qpair_sp_free_dma(void *); extern void qla2xxx_qpair_sp_compl(void *, int); -extern int qla24xx_post_upd_fcport_work(struct scsi_qla_host *, fc_port_t *); +extern void qla24xx_sched_upd_fcport(fc_port_t *); void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *, uint16_t *); int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *); -int qla24xx_async_abort_cmd(srb_t *); +int qla24xx_async_abort_cmd(srb_t *, bool); int qla24xx_post_relogin_work(struct scsi_qla_host *vha); void qla2x00_wait_for_sess_deletion(scsi_qla_host_t *); @@ -267,8 +270,8 @@ extern void qla24xx_build_scsi_iocbs(srb_t *, struct cmd_type_7 *, uint16_t, struct req_que *); extern int qla2x00_start_scsi(srb_t *sp); extern int qla24xx_start_scsi(srb_t *sp); -int qla2x00_marker(struct scsi_qla_host *, struct req_que *, struct rsp_que *, - uint16_t, uint64_t, uint8_t); +int qla2x00_marker(struct scsi_qla_host *, struct qla_qpair *, + uint16_t, uint64_t, uint8_t); extern int qla2x00_start_sp(srb_t *); extern int qla24xx_dif_start_scsi(srb_t *); extern int qla2x00_start_bidir(srb_t *, struct scsi_qla_host *, uint32_t); @@ -283,7 +286,7 @@ extern int qla24xx_walk_and_build_sglist_no_difb(struct qla_hw_data *, srb_t *, extern int qla24xx_walk_and_build_sglist(struct qla_hw_data *, srb_t *, uint32_t *, uint16_t, struct qla_tc_param *); extern int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *, srb_t *, - uint32_t *, uint16_t, struct qla_tc_param *); + uint32_t *, uint16_t, struct qla_tgt_cmd *); extern int qla24xx_get_one_block_sg(uint32_t, struct qla2_sgx *, uint32_t *); extern int qla24xx_configure_prot_mode(srb_t *, uint16_t *); extern int qla24xx_build_scsi_crc_2_iocbs(srb_t *, @@ -644,9 +647,6 @@ extern void qla2x00_get_sym_node_name(scsi_qla_host_t *, uint8_t *, size_t); extern int qla2x00_chk_ms_status(scsi_qla_host_t *, ms_iocb_entry_t *, struct ct_sns_rsp *, const char *); extern void qla2x00_async_iocb_timeout(void *data); -extern int qla24xx_async_gidpn(scsi_qla_host_t *, fc_port_t *); -int qla24xx_post_gidpn_work(struct scsi_qla_host *, fc_port_t *); -void qla24xx_handle_gidpn_event(scsi_qla_host_t *, struct event_arg *); extern void qla2x00_free_fcport(fc_port_t *); @@ -677,6 +677,7 @@ void qla_scan_work_fn(struct work_struct *); */ struct device_attribute; extern struct device_attribute *qla2x00_host_attrs[]; +extern struct device_attribute *qla2x00_host_attrs_dm[]; struct fc_function_template; extern struct fc_function_template qla2xxx_transport_functions; extern struct fc_function_template qla2xxx_transport_vport_functions; @@ -690,7 +691,7 @@ extern int qla2x00_echo_test(scsi_qla_host_t *, extern int qla24xx_update_all_fcp_prio(scsi_qla_host_t *); extern int qla24xx_fcp_prio_cfg_valid(scsi_qla_host_t *, struct qla_fcp_prio_cfg *, uint8_t); - +void qla_insert_tgt_attrs(void); /* * Global Function Prototypes in qla_dfs.c source file. */ @@ -897,5 +898,7 @@ void qlt_unknown_atio_work_fn(struct work_struct *); void qlt_update_host_map(struct scsi_qla_host *, port_id_t); void qlt_remove_target_resources(struct qla_hw_data *); void qlt_clr_qp_table(struct scsi_qla_host *vha); +void qlt_set_mode(struct scsi_qla_host *); +int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); #endif /* _QLA_GBL_H */ diff --git a/qla2x00t-32gbit/qla_gs.c b/qla2x00t-32gbit/qla_gs.c index c492af5bc..c6fdad124 100644 --- a/qla2x00t-32gbit/qla_gs.c +++ b/qla2x00t-32gbit/qla_gs.c @@ -657,15 +657,16 @@ static int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_sns_sp_done; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - hdl=%x portid %06x.\n", + sp->name, sp->handle, d_id->b24); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_disc, vha, 0x2043, "RFT_ID issue IOCB failed (%d).\n", rval); goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s - hdl=%x portid %06x.\n", - sp->name, sp->handle, d_id->b24); return rval; done_free_sp: sp->free(sp); @@ -752,6 +753,10 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_sns_sp_done; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - hdl=%x portid %06x feature %x type %x.\n", + sp->name, sp->handle, d_id->b24, fc4feature, fc4type); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_disc, vha, 0x2047, @@ -759,9 +764,6 @@ static int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s - hdl=%x portid %06x feature %x type %x.\n", - sp->name, sp->handle, d_id->b24, fc4feature, fc4type); return rval; done_free_sp: @@ -844,15 +846,16 @@ static int qla_async_rnnid(scsi_qla_host_t *vha, port_id_t *d_id, sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_sns_sp_done; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - hdl=%x portid %06x\n", + sp->name, sp->handle, d_id->b24); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_disc, vha, 0x204d, "RNN_ID issue IOCB failed (%d).\n", rval); goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s - hdl=%x portid %06x\n", - sp->name, sp->handle, d_id->b24); return rval; @@ -957,15 +960,16 @@ static int qla_async_rsnn_nn(scsi_qla_host_t *vha) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_sns_sp_done; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s - hdl=%x.\n", + sp->name, sp->handle); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_disc, vha, 0x2043, "RFT_ID issue IOCB failed (%d).\n", rval); goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s - hdl=%x.\n", - sp->name, sp->handle); return rval; @@ -1962,7 +1966,6 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) void *entries; struct ct_fdmiv2_hba_attr *eiter; struct qla_hw_data *ha = vha->hw; - struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb; struct new_utsname *p_sysid = NULL; /* Issue RHBA */ @@ -2142,9 +2145,7 @@ qla2x00_fdmiv2_rhba(scsi_qla_host_t *vha) /* MAX CT Payload Length */ eiter = entries + size; eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); - eiter->a.max_ct_len = IS_FWI2_CAPABLE(ha) ? - le16_to_cpu(icb24->frame_payload_size) : - le16_to_cpu(ha->init_cb->frame_payload_size); + eiter->a.max_ct_len = cpu_to_be32(ha->frame_payload_size); eiter->a.max_ct_len = cpu_to_be32(eiter->a.max_ct_len); eiter->len = cpu_to_be16(4 + 4); size += 4 + 4; @@ -2976,237 +2977,6 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) } } -/* GID_PN completion processing. */ -void qla24xx_handle_gidpn_event(scsi_qla_host_t *vha, struct event_arg *ea) -{ - fc_port_t *fcport = ea->fcport; - - ql_dbg(ql_dbg_disc, vha, 0x201d, - "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2, - fcport->rscn_gen, ea->sp->gen1, fcport->loop_id); - - if (fcport->disc_state == DSC_DELETE_PEND) - return; - - if (ea->sp->gen2 != fcport->login_gen) { - /* PLOGI/PRLI/LOGO came in while cmd was out.*/ - ql_dbg(ql_dbg_disc, vha, 0x201e, - "%s %8phC generation changed rscn %d|%d n", - __func__, fcport->port_name, fcport->last_rscn_gen, - fcport->rscn_gen); - return; - } - - if (!ea->rc) { - if (ea->sp->gen1 == fcport->rscn_gen) { - fcport->scan_state = QLA_FCPORT_FOUND; - fcport->flags |= FCF_FABRIC_DEVICE; - - if (fcport->d_id.b24 == ea->id.b24) { - /* cable plugged into the same place */ - switch (vha->host->active_mode) { - case MODE_TARGET: - if (fcport->fw_login_state == - DSC_LS_PRLI_COMP) { - u16 data[2]; - /* - * Late RSCN was delivered. - * Remote port already login'ed. - */ - ql_dbg(ql_dbg_disc, vha, 0x201f, - "%s %d %8phC post adisc\n", - __func__, __LINE__, - fcport->port_name); - data[0] = data[1] = 0; - qla2x00_post_async_adisc_work( - vha, fcport, data); - } - break; - case MODE_INITIATOR: - case MODE_DUAL: - default: - ql_dbg(ql_dbg_disc, vha, 0x201f, - "%s %d %8phC post %s\n", __func__, - __LINE__, fcport->port_name, - (atomic_read(&fcport->state) == - FCS_ONLINE) ? "adisc" : "gnl"); - - if (atomic_read(&fcport->state) == - FCS_ONLINE) { - u16 data[2]; - - data[0] = data[1] = 0; - qla2x00_post_async_adisc_work( - vha, fcport, data); - } else { - qla24xx_post_gnl_work(vha, - fcport); - } - break; - } - } else { /* fcport->d_id.b24 != ea->id.b24 */ - fcport->d_id.b24 = ea->id.b24; - fcport->id_changed = 1; - if (fcport->deleted != QLA_SESS_DELETED) { - ql_dbg(ql_dbg_disc, vha, 0x2021, - "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - } - } - } else { /* ea->sp->gen1 != fcport->rscn_gen */ - ql_dbg(ql_dbg_disc, vha, 0x2022, - "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - /* rscn came in while cmd was out */ - qla24xx_post_gidpn_work(vha, fcport); - } - } else { /* ea->rc */ - /* cable pulled */ - if (ea->sp->gen1 == fcport->rscn_gen) { - if (ea->sp->gen2 == fcport->login_gen) { - ql_dbg(ql_dbg_disc, vha, 0x2042, - "%s %d %8phC post del sess\n", __func__, - __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - } else { - ql_dbg(ql_dbg_disc, vha, 0x2045, - "%s %d %8phC login\n", __func__, __LINE__, - fcport->port_name); - qla24xx_fcport_handle_login(vha, fcport); - } - } else { - ql_dbg(ql_dbg_disc, vha, 0x2049, - "%s %d %8phC post gidpn\n", __func__, __LINE__, - fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); - } - } -} /* gidpn_event */ - -static void qla2x00_async_gidpn_sp_done(void *s, int res) -{ - struct srb *sp = s; - struct scsi_qla_host *vha = sp->vha; - fc_port_t *fcport = sp->fcport; - u8 *id = fcport->ct_desc.ct_sns->p.rsp.rsp.gid_pn.port_id; - struct event_arg ea; - - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - - memset(&ea, 0, sizeof(ea)); - ea.fcport = fcport; - ea.id.b.domain = id[0]; - ea.id.b.area = id[1]; - ea.id.b.al_pa = id[2]; - ea.sp = sp; - ea.rc = res; - ea.event = FCME_GIDPN_DONE; - - if (res == QLA_FUNCTION_TIMEOUT) { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s WWPN %8phC timed out.\n", - sp->name, fcport->port_name); - qla24xx_post_gidpn_work(sp->vha, fcport); - sp->free(sp); - return; - } else if (res) { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s fail res %x, WWPN %8phC\n", - sp->name, res, fcport->port_name); - } else { - ql_dbg(ql_dbg_disc, vha, 0x204f, - "Async done-%s good WWPN %8phC ID %3phC\n", - sp->name, fcport->port_name, id); - } - - qla2x00_fcport_event_handler(vha, &ea); - - sp->free(sp); -} - -int qla24xx_async_gidpn(scsi_qla_host_t *vha, fc_port_t *fcport) -{ - int rval = QLA_FUNCTION_FAILED; - struct ct_sns_req *ct_req; - srb_t *sp; - - if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) - return rval; - - fcport->disc_state = DSC_GID_PN; - fcport->scan_state = QLA_FCPORT_SCAN; - sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); - if (!sp) - goto done; - - fcport->flags |= FCF_ASYNC_SENT; - sp->type = SRB_CT_PTHRU_CMD; - sp->name = "gidpn"; - sp->gen1 = fcport->rscn_gen; - sp->gen2 = fcport->login_gen; - - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); - - /* CT_IU preamble */ - ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GID_PN_CMD, - GID_PN_RSP_SIZE); - - /* GIDPN req */ - memcpy(ct_req->req.gid_pn.port_name, fcport->port_name, - WWN_SIZE); - - /* req & rsp use the same buffer */ - sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; - sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; - sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; - sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; - sp->u.iocb_cmd.u.ctarg.req_size = GID_PN_REQ_SIZE; - sp->u.iocb_cmd.u.ctarg.rsp_size = GID_PN_RSP_SIZE; - sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; - - sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; - sp->done = qla2x00_async_gidpn_sp_done; - - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - - ql_dbg(ql_dbg_disc, vha, 0x20a4, - "Async-%s - %8phC hdl=%x loopid=%x portid %02x%02x%02x.\n", - sp->name, fcport->port_name, - sp->handle, fcport->loop_id, fcport->d_id.b.domain, - fcport->d_id.b.area, fcport->d_id.b.al_pa); - return rval; - -done_free_sp: - sp->free(sp); -done: - fcport->flags &= ~FCF_ASYNC_ACTIVE; - return rval; -} - -int qla24xx_post_gidpn_work(struct scsi_qla_host *vha, fc_port_t *fcport) -{ - struct qla_work_evt *e; - int ls; - - ls = atomic_read(&vha->loop_state); - if (((ls != LOOP_READY) && (ls != LOOP_UP)) || - test_bit(UNLOADING, &vha->dpc_flags)) - return 0; - - e = qla2x00_alloc_work(vha, QLA_EVT_GIDPN); - if (!e) - return QLA_FUNCTION_FAILED; - - e->u.fcport.fcport = fcport; - fcport->flags |= FCF_ASYNC_ACTIVE; - return qla2x00_post_work(vha, e); -} - int qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport) { struct qla_work_evt *e; @@ -3240,9 +3010,6 @@ void qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, fcport->port_name); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } @@ -3264,6 +3031,9 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) "Async done-%s res %x, WWPN %8phC \n", sp->name, res, fcport->port_name); + if (res == QLA_FUNCTION_TIMEOUT) + return; + if (res == (DID_ERROR << 16)) { /* entry status error */ goto done; @@ -3275,7 +3045,7 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) ql_dbg(ql_dbg_disc, vha, 0x2019, "GPSC command unsupported, disabling query.\n"); ha->flags.gpsc_supported = 0; - res = QLA_SUCCESS; + goto done; } } else { switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) { @@ -3308,7 +3078,6 @@ static void qla24xx_async_gpsc_sp_done(void *s, int res) be16_to_cpu(ct_rsp->rsp.gpsc.speeds), be16_to_cpu(ct_rsp->rsp.gpsc.speed)); } -done: memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPSC_DONE; ea.rc = res; @@ -3316,6 +3085,7 @@ done: ea.sp = sp; qla2x00_fcport_event_handler(vha, &ea); +done: sp->free(sp); } @@ -3358,15 +3128,15 @@ int qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla24xx_async_gpsc_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x205e, "Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n", sp->name, fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -3394,19 +3164,40 @@ int qla24xx_post_gpnid_work(struct scsi_qla_host *vha, port_id_t *id) void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp) { - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; + struct srb_iocb *c = &sp->u.iocb_cmd; + + switch (sp->type) { + case SRB_ELS_DCMD: + if (c->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + c->u.els_plogi.tx_size, + c->u.els_plogi.els_plogi_pyld, + c->u.els_plogi.els_plogi_pyld_dma); + + if (c->u.els_plogi.els_resp_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + c->u.els_plogi.rx_size, + c->u.els_plogi.els_resp_pyld, + c->u.els_plogi.els_resp_pyld_dma); + break; + case SRB_CT_PTHRU_CMD: + default: + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.req_allocated_size, + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + break; } sp->free(sp); @@ -3424,26 +3215,10 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) if (ea->rc) { /* cable is disconnected */ list_for_each_entry_safe(fcport, t, &vha->vp_fcports, list) { - if (fcport->d_id.b24 == ea->id.b24) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC DS %d\n", - __func__, __LINE__, - fcport->port_name, - fcport->disc_state); + if (fcport->d_id.b24 == ea->id.b24) fcport->scan_state = QLA_FCPORT_SCAN; - switch (fcport->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - break; - } - } + + qlt_schedule_sess_for_deletion(fcport); } } else { /* cable is connected */ @@ -3452,37 +3227,30 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) list_for_each_entry_safe(conflict, t, &vha->vp_fcports, list) { if ((conflict->d_id.b24 == ea->id.b24) && - (fcport != conflict)) { - /* 2 fcports with conflict Nport ID or + (fcport != conflict)) + /* + * 2 fcports with conflict Nport ID or * an existing fcport is having nport ID * conflict with new fcport. */ - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC DS %d\n", - __func__, __LINE__, - conflict->port_name, - conflict->disc_state); conflict->scan_state = QLA_FCPORT_SCAN; - switch (conflict->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - conflict->port_name); - qlt_schedule_sess_for_deletion - (conflict); - break; - } - } + + qlt_schedule_sess_for_deletion(conflict); } + fcport->scan_needed = 0; fcport->rscn_gen++; fcport->scan_state = QLA_FCPORT_FOUND; fcport->flags |= FCF_FABRIC_DEVICE; + if (fcport->login_retry == 0) { + fcport->login_retry = + vha->hw->login_retry_count; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Port login retry %8phN, lid 0x%04x cnt=%d.\n", + fcport->port_name, fcport->loop_id, + fcport->login_retry); + } switch (fcport->disc_state) { case DSC_LOGIN_COMPLETE: /* recheck session is still intact. */ @@ -3522,19 +3290,7 @@ void qla24xx_handle_gpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) conflict->disc_state); conflict->scan_state = QLA_FCPORT_SCAN; - switch (conflict->disc_state) { - case DSC_DELETED: - case DSC_DELETE_PEND: - break; - default: - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - conflict->port_name); - qlt_schedule_sess_for_deletion - (conflict); - break; - } + qlt_schedule_sess_for_deletion(conflict); } } @@ -3698,13 +3454,14 @@ int qla24xx_async_gpnid(scsi_qla_host_t *vha, port_id_t *id) sp->u.iocb_cmd.timeout = qla2x00_async_iocb_timeout; sp->done = qla2x00_async_gpnid_sp_done; + ql_dbg(ql_dbg_disc, vha, 0x2067, + "Async-%s hdl=%x ID %3phC.\n", sp->name, + sp->handle, ct_req->req.port_id.port_id); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x2067, - "Async-%s hdl=%x ID %3phC.\n", sp->name, - sp->handle, ct_req->req.port_id.port_id); return rval; done_free_sp: @@ -3825,14 +3582,14 @@ int qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport) sp->done = qla24xx_async_gffid_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x2132, "Async-%s hdl=%x %8phC.\n", sp->name, sp->handle, fcport->port_name); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: sp->free(sp); @@ -3870,9 +3627,10 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) fc_port_t *fcport; u32 i, rc; bool found; - struct fab_scan_rp *rp; + struct fab_scan_rp *rp, *trp; unsigned long flags; u8 recheck = 0; + u16 dup = 0, dup_cnt = 0; ql_dbg(ql_dbg_disc, vha, 0xffff, "%s enter\n", __func__); @@ -3903,6 +3661,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) for (i = 0; i < vha->hw->max_fibre_devices; i++) { u64 wwn; + int k; rp = &vha->scan.l[i]; found = false; @@ -3911,6 +3670,20 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) if (wwn == 0) continue; + /* Remove duplicate NPORT ID entries from switch data base */ + for (k = i + 1; k < vha->hw->max_fibre_devices; k++) { + trp = &vha->scan.l[k]; + if (rp->id.b24 == trp->id.b24) { + dup = 1; + dup_cnt++; + ql_dbg(ql_dbg_disc + ql_dbg_verbose, + vha, 0xffff, + "Detected duplicate NPORT ID from switch data base: ID %06x WWN %8phN WWN %8phN\n", + rp->id.b24, rp->port_name, trp->port_name); + memset(trp, 0, sizeof(*trp)); + } + } + if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE)) continue; @@ -3925,7 +3698,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) list_for_each_entry(fcport, &vha->vp_fcports, list) { if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) continue; - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; fcport->scan_state = QLA_FCPORT_FOUND; found = true; /* @@ -3950,25 +3723,30 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) } } + if (dup) { + ql_log(ql_log_warn, vha, 0xffff, + "Detected %d duplicate NPORT ID(s) from switch data base\n", + dup_cnt); + } + /* * Logout all previous fabric dev marked lost, except FCP2 devices. */ list_for_each_entry(fcport, &vha->vp_fcports, list) { if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; continue; } if (fcport->scan_state != QLA_FCPORT_FOUND) { - fcport->rscn_rcvd = 0; + fcport->scan_needed = 0; if ((qla_dual_mode_enabled(vha) || qla_ini_mode_enabled(vha)) && atomic_read(&fcport->state) == FCS_ONLINE) { - qla2x00_mark_device_lost(vha, fcport, - ql2xplogiabsentdevice, 0); + if (fcport->loop_id != FC_NO_LOOP_ID) { + if (fcport->flags & FCF_FCP2_DEVICE) + fcport->logout_on_delete = 0; - if (fcport->loop_id != FC_NO_LOOP_ID && - (fcport->flags & FCF_FCP2_DEVICE) == 0) { ql_dbg(ql_dbg_disc, vha, 0x20f0, "%s %d %8phC post del sess\n", __func__, __LINE__, @@ -3979,9 +3757,17 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) } } } else { - if (fcport->rscn_rcvd || + if (fcport->scan_needed || fcport->disc_state != DSC_LOGIN_COMPLETE) { - fcport->rscn_rcvd = 0; + if (fcport->login_retry == 0) { + fcport->login_retry = + vha->hw->login_retry_count; + ql_dbg(ql_dbg_disc, vha, 0x20a3, + "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", + fcport->port_name, fcport->loop_id, + fcport->login_retry); + } + fcport->scan_needed = 0; qla24xx_fcport_handle_login(vha, fcport); } } @@ -3996,7 +3782,7 @@ out: if (recheck) { list_for_each_entry(fcport, &vha->vp_fcports, list) { - if (fcport->rscn_rcvd) { + if (fcport->scan_needed) { set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); break; @@ -4005,6 +3791,41 @@ out: } } +static int qla2x00_post_gnnft_gpnft_done_work(struct scsi_qla_host *vha, + srb_t *sp, int cmd) +{ + struct qla_work_evt *e; + + if (cmd != QLA_EVT_GPNFT_DONE && cmd != QLA_EVT_GNNFT_DONE) + return QLA_PARAMETER_ERROR; + + e = qla2x00_alloc_work(vha, cmd); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.iosb.sp = sp; + + return qla2x00_post_work(vha, e); +} + +static int qla2x00_post_nvme_gpnft_work(struct scsi_qla_host *vha, + srb_t *sp, int cmd) +{ + struct qla_work_evt *e; + + if (cmd != QLA_EVT_GPNFT) + return QLA_PARAMETER_ERROR; + + e = qla2x00_alloc_work(vha, cmd); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.gpnft.fc4_type = FC4_TYPE_NVME; + e->u.gpnft.sp = sp; + + return qla2x00_post_work(vha, e); +} + static void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha, struct srb *sp) { @@ -4105,120 +3926,85 @@ static void qla2x00_async_gpnft_gnnft_sp_done(void *s, int res) { struct srb *sp = s; struct scsi_qla_host *vha = sp->vha; - struct qla_work_evt *e; struct ct_sns_req *ct_req = (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; u16 cmd = be16_to_cpu(ct_req->command); u8 fc4_type = sp->gen2; unsigned long flags; + int rc; /* gen2 field is holding the fc4type */ ql_dbg(ql_dbg_disc, vha, 0xffff, "Async done-%s res %x FC4Type %x\n", sp->name, res, sp->gen2); + del_timer(&sp->u.iocb_cmd.timer); + sp->rc = res; if (res) { unsigned long flags; + const char *name = sp->name; - sp->free(sp); - spin_lock_irqsave(&vha->work_lock, flags); - vha->scan.scan_flags &= ~SF_SCANNING; - vha->scan.scan_retry++; - spin_unlock_irqrestore(&vha->work_lock, flags); + /* + * We are in an Interrupt context, queue up this + * sp for GNNFT_DONE work. This will allow all + * the resource to get freed up. + */ + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GNNFT_DONE); + if (rc) { + /* Cleanup here to prevent memory leak */ + qla24xx_sp_unmap(vha, sp); - if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); - } else { - ql_dbg(ql_dbg_disc, sp->vha, 0xffff, - "Async done-%s rescan failed on all retries\n", - sp->name); + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + vha->scan.scan_retry++; + spin_unlock_irqrestore(&vha->work_lock, flags); + + if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } else { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async done-%s rescan failed on all retries.\n", + name); + } } return; } - if (!res) - qla2x00_find_free_fcp_nvme_slot(vha, sp); + qla2x00_find_free_fcp_nvme_slot(vha, sp); if ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled && cmd == GNN_FT_CMD) { - del_timer(&sp->u.iocb_cmd.timer); spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT); - if (!e) { - /* - * please ignore kernel warning. Otherwise, - * we have mem leak. - */ - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } - - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s unable to alloc work element\n", - sp->name); - sp->free(sp); + sp->rc = res; + rc = qla2x00_post_nvme_gpnft_work(vha, sp, QLA_EVT_GPNFT); + if (rc) { + qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - return; } - e->u.gpnft.fc4_type = FC4_TYPE_NVME; - sp->rc = res; - e->u.gpnft.sp = sp; - - qla2x00_post_work(vha, e); return; } - if (cmd == GPN_FT_CMD) - e = qla2x00_alloc_work(vha, QLA_EVT_GPNFT_DONE); - else - e = qla2x00_alloc_work(vha, QLA_EVT_GNNFT_DONE); - if (!e) { - /* please ignore kernel warning. Otherwise, we have mem leak. */ - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.req_allocated_size, - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; - } + if (cmd == GPN_FT_CMD) { + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GPNFT_DONE); + } else { + rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, + QLA_EVT_GNNFT_DONE); + } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async done-%s unable to alloc work element\n", - sp->name); - sp->free(sp); + if (rc) { + qla24xx_sp_unmap(vha, sp); set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); return; } - - sp->rc = res; - e->u.iosb.sp = sp; - - qla2x00_post_work(vha, e); } /* @@ -4251,11 +4037,13 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); WARN_ON(1); + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); goto done_free_sp; } ql_dbg(ql_dbg_disc, vha, 0xfffff, - "%s: FC4Type %x, CT-PASSTRHU %s command ctarg rsp size %d, ctarg req size %d\n", + "%s: FC4Type %x, CT-PASSTHRU %s command ctarg rsp size %d, ctarg req size %d\n", __func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size, sp->u.iocb_cmd.u.ctarg.req_size); @@ -4283,13 +4071,18 @@ static int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, sp->done = qla2x00_async_gpnft_gnnft_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s hdl=%x FC4Type %x.\n", sp->name, sp->handle, ct_req->req.gpn_ft.port_type); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_flags &= ~SF_SCANNING; + spin_unlock_irqrestore(&vha->work_lock, flags); + goto done_free_sp; + } + return rval; done_free_sp: @@ -4317,7 +4110,6 @@ void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) { ql_dbg(ql_dbg_disc, vha, 0xffff, "%s enter\n", __func__); - del_timer(&sp->u.iocb_cmd.timer); qla24xx_async_gnnft(vha, sp, sp->gen2); } @@ -4360,9 +4152,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) return rval; } - sp->u.iocb_cmd.u.ctarg.req = dma_zalloc_coherent( - &vha->hw->pdev->dev, sizeof(struct ct_sns_pkt), - &sp->u.iocb_cmd.u.ctarg.req_dma, GFP_KERNEL); + sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + &sp->u.iocb_cmd.u.ctarg.req_dma, + GFP_KERNEL); sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); if (!sp->u.iocb_cmd.u.ctarg.req) { ql_log(ql_log_warn, vha, 0xffff, @@ -4370,7 +4163,8 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - goto done_free_sp; + qla2x00_rel_sp(sp); + return rval; } sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; @@ -4378,9 +4172,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) ((vha->hw->max_fibre_devices - 1) * sizeof(struct ct_sns_gpn_ft_data)); - sp->u.iocb_cmd.u.ctarg.rsp = dma_zalloc_coherent( - &vha->hw->pdev->dev, rspsz, - &sp->u.iocb_cmd.u.ctarg.rsp_dma, GFP_KERNEL); + sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, + rspsz, + &sp->u.iocb_cmd.u.ctarg.rsp_dma, + GFP_KERNEL); sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); if (!sp->u.iocb_cmd.u.ctarg.rsp) { ql_log(ql_log_warn, vha, 0xffff, @@ -4388,7 +4183,13 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); - goto done_free_sp; + dma_free_coherent(&vha->hw->pdev->dev, + sp->u.iocb_cmd.u.ctarg.req_allocated_size, + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + qla2x00_rel_sp(sp); + return rval; } sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; @@ -4425,6 +4226,10 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) sp->done = qla2x00_async_gpnft_gnnft_sp_done; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "Async-%s hdl=%x FC4Type %x.\n", sp->name, + sp->handle, ct_req->req.gpn_ft.port_type); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { spin_lock_irqsave(&vha->work_lock, flags); @@ -4433,9 +4238,6 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Async-%s hdl=%x FC4Type %x.\n", sp->name, - sp->handle, ct_req->req.gpn_ft.port_type); return rval; done_free_sp: @@ -4556,13 +4358,14 @@ int qla24xx_async_gnnid(scsi_qla_host_t *vha, fc_port_t *fcport) sp->done = qla2x00_async_gnnid_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n", sp->name, fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -4610,9 +4413,6 @@ void qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, fcport->port_name); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } @@ -4689,14 +4489,15 @@ int qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport) sp->done = qla2x00_async_gfpnid_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0xffff, "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n", sp->name, fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: diff --git a/qla2x00t-32gbit/qla_init.c b/qla2x00t-32gbit/qla_init.c index f77e47015..0c700b140 100644 --- a/qla2x00t-32gbit/qla_init.c +++ b/qla2x00t-32gbit/qla_init.c @@ -50,16 +50,17 @@ qla2x00_sp_timeout(struct timer_list *t) { srb_t *sp = from_timer(sp, t, u.iocb_cmd.timer); struct srb_iocb *iocb; - scsi_qla_host_t *vha = sp->vha; struct req_que *req; unsigned long flags; + struct qla_hw_data *ha = sp->vha->hw; - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - req = vha->hw->req_q_map[0]; + WARN_ON_ONCE(irqs_disabled()); + spin_lock_irqsave(&ha->hardware_lock, flags); + req = sp->qpair->req; req->outstanding_cmds[sp->handle] = NULL; iocb = &sp->u.iocb_cmd; + spin_unlock_irqrestore(&ha->hardware_lock, flags); iocb->timeout(sp); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); } void @@ -100,6 +101,8 @@ qla2x00_async_iocb_timeout(void *data) srb_t *sp = data; fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; + int rc, h; + unsigned long flags; if (fcport) { ql_dbg(ql_dbg_disc, fcport->vha, 0x2071, @@ -114,11 +117,26 @@ qla2x00_async_iocb_timeout(void *data) switch (sp->type) { case SRB_LOGIN_CMD: - /* Retry as needed. */ - lio->u.logio.data[0] = MBS_COMMAND_ERROR; - lio->u.logio.data[1] = lio->u.logio.flags & SRB_LOGIN_RETRIED ? - QLA_LOGIO_LOGIN_RETRIED : 0; - sp->done(sp, QLA_FUNCTION_TIMEOUT); + rc = qla24xx_async_abort_cmd(sp, false); + if (rc) { + /* Retry as needed. */ + lio->u.logio.data[0] = MBS_COMMAND_ERROR; + lio->u.logio.data[1] = + lio->u.logio.flags & SRB_LOGIN_RETRIED ? + QLA_LOGIO_LOGIN_RETRIED : 0; + spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); + for (h = 1; h < sp->qpair->req->num_outstanding_cmds; + h++) { + if (sp->qpair->req->outstanding_cmds[h] == + sp) { + sp->qpair->req->outstanding_cmds[h] = + NULL; + break; + } + } + spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); + sp->done(sp, QLA_FUNCTION_TIMEOUT); + } break; case SRB_LOGOUT_CMD: case SRB_CT_PTHRU_CMD: @@ -127,7 +145,21 @@ qla2x00_async_iocb_timeout(void *data) case SRB_NACK_PRLI: case SRB_NACK_LOGO: case SRB_CTRL_VP: - sp->done(sp, QLA_FUNCTION_TIMEOUT); + rc = qla24xx_async_abort_cmd(sp, false); + if (rc) { + spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags); + for (h = 1; h < sp->qpair->req->num_outstanding_cmds; + h++) { + if (sp->qpair->req->outstanding_cmds[h] == + sp) { + sp->qpair->req->outstanding_cmds[h] = + NULL; + break; + } + } + spin_unlock_irqrestore(sp->qpair->qp_lock_ptr, flags); + sp->done(sp, QLA_FUNCTION_TIMEOUT); + } break; } } @@ -160,6 +192,22 @@ qla2x00_async_login_sp_done(void *ptr, int res) sp->free(sp); } +static inline bool +fcport_is_smaller(fc_port_t *fcport) +{ + if (wwn_to_u64(fcport->port_name) < + wwn_to_u64(fcport->vha->port_name)) + return true; + else + return false; +} + +static inline bool +fcport_is_bigger(fc_port_t *fcport) +{ + return !fcport_is_smaller(fcport); +} + int qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) @@ -189,13 +237,20 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_login_sp_done; - lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; + if (N2N_TOPO(fcport->vha->hw) && fcport_is_bigger(fcport)) + lio->u.logio.flags |= SRB_LOGIN_PRLI_ONLY; + else + lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; if (fcport->fc4f_nvme) lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI; - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - lio->u.logio.flags |= SRB_LOGIN_RETRIED; + ql_dbg(ql_dbg_disc, vha, 0x2072, + "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x " + "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id, + fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, + fcport->login_retry); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { fcport->flags |= FCF_LOGIN_NEEDED; @@ -203,11 +258,6 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0x2072, - "Async-login - %8phC hdl=%x, loopid=%x portid=%02x%02x%02x " - "retries=%d.\n", fcport->port_name, sp->handle, fcport->loop_id, - fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, - fcport->login_retry); return rval; done_free_sp: @@ -252,15 +302,16 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport) qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_logout_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x2070, "Async-logout - hdl=%x loop-id=%x portid=%02x%02x%02x %8phC.\n", sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, fcport->port_name); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -315,14 +366,16 @@ qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport) qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_prlo_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x2070, "Async-prlo - hdl=%x loop-id=%x portid=%02x%02x%02x.\n", sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: @@ -347,6 +400,9 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) ql_dbg(ql_dbg_disc, vha, 0x2066, "%s %8phC: adisc fail: post delete\n", __func__, ea->fcport->port_name); + /* deleted = 0 & logout_on_delete = force fw cleanup */ + fcport->deleted = 0; + fcport->logout_on_delete = 1; qlt_schedule_sess_for_deletion(ea->fcport); return; } @@ -361,15 +417,27 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) __func__, ea->fcport->port_name); return; } else if (ea->sp->gen1 != ea->fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, ea->fcport->port_name); - qla24xx_post_gidpn_work(vha, ea->fcport); + qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } __qla24xx_handle_gpdb_event(vha, ea); } +static int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(vha, QLA_EVT_ELS_PLOGI); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + fcport->flags |= FCF_ASYNC_ACTIVE; + return qla2x00_post_work(vha, e); +} + static void qla2x00_async_adisc_sp_done(void *ptr, int res) { @@ -405,9 +473,11 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, { srb_t *sp; struct srb_iocb *lio; - int rval; + int rval = QLA_FUNCTION_FAILED; + + if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) + return rval; - rval = QLA_FUNCTION_FAILED; fcport->flags |= FCF_ASYNC_SENT; sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) @@ -418,18 +488,22 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, lio = &sp->u.iocb_cmd; lio->timeout = qla2x00_async_iocb_timeout; + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_adisc_sp_done; if (data[1] & QLA_LOGIO_LOGIN_RETRIED) lio->u.logio.flags |= SRB_LOGIN_RETRIED; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; ql_dbg(ql_dbg_disc, vha, 0x206f, "Async-adisc - hdl=%x loopid=%x portid=%06x %8phC.\n", sp->handle, fcport->loop_id, fcport->d_id.b24, fcport->port_name); + + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: @@ -464,7 +538,6 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, if (ea->rc) { /* rval */ if (fcport->login_retry == 0) { - fcport->login_retry = vha->hw->login_retry_count; ql_dbg(ql_dbg_disc, vha, 0x20de, "GNL failed Port login retry %8phN, retry cnt=%d.\n", fcport->port_name, fcport->login_retry); @@ -473,11 +546,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, } if (fcport->last_rscn_gen != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20df, - "%s %8phC rscn gen changed rscn %d|%d \n", - __func__, fcport->port_name, - fcport->last_rscn_gen, fcport->rscn_gen); - qla24xx_post_gidpn_work(vha, fcport); + qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } else if (fcport->last_login_gen != fcport->login_gen) { ql_dbg(ql_dbg_disc, vha, 0x20e0, @@ -497,35 +567,51 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, for (i = 0; i < n; i++) { e = &vha->gnl.l[i]; wwn = wwn_to_u64(e->port_name); - - if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE)) - continue; - - found = 1; id.b.domain = e->port_id[2]; id.b.area = e->port_id[1]; id.b.al_pa = e->port_id[0]; id.b.rsvd_1 = 0; + if (memcmp((u8 *)&wwn, fcport->port_name, WWN_SIZE)) + continue; + + if (IS_SW_RESV_ADDR(id)) + continue; + + found = 1; + loop_id = le16_to_cpu(e->nport_handle); loop_id = (loop_id & 0x7fff); + if (fcport->fc4f_nvme) + current_login_state = e->current_login_state >> 4; + else + current_login_state = e->current_login_state & 0xf; + ql_dbg(ql_dbg_disc, vha, 0x20e2, - "%s found %8phC CLS [%d|%d] ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", + "%s found %8phC CLS [%x|%x] nvme %d ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", __func__, fcport->port_name, e->current_login_state, fcport->fw_login_state, - id.b.domain, id.b.area, id.b.al_pa, + fcport->fc4f_nvme, id.b.domain, id.b.area, id.b.al_pa, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa, loop_id, fcport->loop_id); - if ((id.b24 != fcport->d_id.b24) || - ((fcport->loop_id != FC_NO_LOOP_ID) && - (fcport->loop_id != loop_id))) { - ql_dbg(ql_dbg_disc, vha, 0x20e3, - "%s %d %8phC post del sess\n", - __func__, __LINE__, fcport->port_name); - qlt_schedule_sess_for_deletion(fcport); - return; + switch (fcport->disc_state) { + case DSC_DELETE_PEND: + case DSC_DELETED: + break; + default: + if ((id.b24 != fcport->d_id.b24 && + fcport->d_id.b24) || + (fcport->loop_id != FC_NO_LOOP_ID && + fcport->loop_id != loop_id)) { + ql_dbg(ql_dbg_disc, vha, 0x20e3, + "%s %d %8phC post del sess\n", + __func__, __LINE__, fcport->port_name); + qlt_schedule_sess_for_deletion(fcport); + return; + } + break; } fcport->loop_id = loop_id; @@ -544,68 +630,151 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, fcport->login_pause = 1; } - if (fcport->fc4f_nvme) - current_login_state = e->current_login_state >> 4; - else - current_login_state = e->current_login_state & 0xf; - - switch (current_login_state) { - case DSC_LS_PRLI_COMP: - ql_dbg(ql_dbg_disc, vha, 0x20e4, - "%s %d %8phC post gpdb\n", - __func__, __LINE__, fcport->port_name); - - if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) - fcport->port_type = FCT_INITIATOR; - else - fcport->port_type = FCT_TARGET; - - data[0] = data[1] = 0; - qla2x00_post_async_adisc_work(vha, fcport, data); - break; - case DSC_LS_PORT_UNAVAIL: + switch (vha->hw->current_topology) { default: - if (fcport->loop_id == FC_NO_LOOP_ID) { - qla2x00_find_new_loop_id(vha, fcport); - fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; + switch (current_login_state) { + case DSC_LS_PRLI_COMP: + ql_dbg(ql_dbg_disc + ql_dbg_verbose, + vha, 0x20e4, "%s %d %8phC post gpdb\n", + __func__, __LINE__, fcport->port_name); + + if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) + fcport->port_type = FCT_INITIATOR; + else + fcport->port_type = FCT_TARGET; + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work(vha, fcport, + data); + break; + case DSC_LS_PORT_UNAVAIL: + default: + if (fcport->loop_id == FC_NO_LOOP_ID) { + qla2x00_find_new_loop_id(vha, fcport); + fcport->fw_login_state = + DSC_LS_PORT_UNAVAIL; + } + ql_dbg(ql_dbg_disc, vha, 0x20e5, + "%s %d %8phC\n", __func__, __LINE__, + fcport->port_name); + qla24xx_fcport_handle_login(vha, fcport); + break; } - ql_dbg(ql_dbg_disc, vha, 0x20e5, - "%s %d %8phC\n", - __func__, __LINE__, fcport->port_name); - qla24xx_fcport_handle_login(vha, fcport); break; - } + case ISP_CFG_N: + fcport->fw_login_state = current_login_state; + fcport->d_id = id; + switch (current_login_state) { + case DSC_LS_PRLI_COMP: + if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) + fcport->port_type = FCT_INITIATOR; + else + fcport->port_type = FCT_TARGET; + + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work(vha, fcport, + data); + break; + case DSC_LS_PLOGI_COMP: + if (fcport_is_bigger(fcport)) { + /* local adapter is smaller */ + if (fcport->loop_id != FC_NO_LOOP_ID) + qla2x00_clear_loop_id(fcport); + + fcport->loop_id = loop_id; + qla24xx_fcport_handle_login(vha, + fcport); + break; + } + /* fall through */ + default: + if (fcport_is_smaller(fcport)) { + /* local adapter is bigger */ + if (fcport->loop_id != FC_NO_LOOP_ID) + qla2x00_clear_loop_id(fcport); + + fcport->loop_id = loop_id; + qla24xx_fcport_handle_login(vha, + fcport); + } + break; + } + break; + } /* switch (ha->current_topology) */ } if (!found) { - /* fw has no record of this port */ - for (i = 0; i < n; i++) { - e = &vha->gnl.l[i]; - id.b.domain = e->port_id[0]; - id.b.area = e->port_id[1]; - id.b.al_pa = e->port_id[2]; - id.b.rsvd_1 = 0; - loop_id = le16_to_cpu(e->nport_handle); + switch (vha->hw->current_topology) { + case ISP_CFG_F: + case ISP_CFG_FL: + for (i = 0; i < n; i++) { + e = &vha->gnl.l[i]; + id.b.domain = e->port_id[0]; + id.b.area = e->port_id[1]; + id.b.al_pa = e->port_id[2]; + id.b.rsvd_1 = 0; + loop_id = le16_to_cpu(e->nport_handle); - if (fcport->d_id.b24 == id.b24) { - conflict_fcport = - qla2x00_find_fcport_by_wwpn(vha, - e->port_name, 0); - if (conflict_fcport) { - qlt_schedule_sess_for_deletion - (conflict_fcport); - ql_dbg(ql_dbg_disc, vha, 0x20e6, - "%s %d %8phC post del sess\n", - __func__, __LINE__, - conflict_fcport->port_name); + if (fcport->d_id.b24 == id.b24) { + conflict_fcport = + qla2x00_find_fcport_by_wwpn(vha, + e->port_name, 0); + if (conflict_fcport) { + ql_dbg(ql_dbg_disc + ql_dbg_verbose, + vha, 0x20e5, + "%s %d %8phC post del sess\n", + __func__, __LINE__, + conflict_fcport->port_name); + qlt_schedule_sess_for_deletion + (conflict_fcport); + } } + /* + * FW already picked this loop id for + * another fcport + */ + if (fcport->loop_id == loop_id) + fcport->loop_id = FC_NO_LOOP_ID; } - - /* FW already picked this loop id for another fcport */ - if (fcport->loop_id == loop_id) - fcport->loop_id = FC_NO_LOOP_ID; + qla24xx_fcport_handle_login(vha, fcport); + break; + case ISP_CFG_N: + fcport->disc_state = DSC_DELETED; + if (time_after_eq(jiffies, fcport->dm_login_expire)) { + if (fcport->n2n_link_reset_cnt < 2) { + fcport->n2n_link_reset_cnt++; + /* + * remote port is not sending PLOGI. + * Reset link to kick start his state + * machine + */ + set_bit(N2N_LINK_RESET, + &vha->dpc_flags); + } else { + if (fcport->n2n_chip_reset < 1) { + ql_log(ql_log_info, vha, 0x705d, + "Chip reset to bring laser down"); + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + fcport->n2n_chip_reset++; + } else { + ql_log(ql_log_info, vha, 0x705d, + "Remote port %8ph is not coming back\n", + fcport->port_name); + fcport->scan_state = 0; + } + } + qla2xxx_wake_dpc(vha); + } else { + /* + * report port suppose to do PLOGI. Give him + * more time. FW will catch it. + */ + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } + break; + default: + break; } - qla24xx_fcport_handle_login(vha, fcport); } } /* gnl_event */ @@ -628,6 +797,10 @@ qla24xx_async_gnl_sp_done(void *s, int res) sp->name, res, sp->u.iocb_cmd.u.mbx.in_mb[1], sp->u.iocb_cmd.u.mbx.in_mb[2]); + if (res == QLA_FUNCTION_TIMEOUT) + return; + + sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); ea.sp = sp; ea.rc = res; @@ -655,25 +828,24 @@ qla24xx_async_gnl_sp_done(void *s, int res) (loop_id & 0x7fff)); } - spin_lock_irqsave(&vha->gnl.fcports_lock, flags); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); INIT_LIST_HEAD(&h); fcport = tf = NULL; if (!list_empty(&vha->gnl.fcports)) list_splice_init(&vha->gnl.fcports, &h); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); list_for_each_entry_safe(fcport, tf, &h, gnl_entry) { list_del_init(&fcport->gnl_entry); - spin_lock(&vha->hw->tgt.sess_lock); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - spin_unlock(&vha->hw->tgt.sess_lock); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); ea.fcport = fcport; qla2x00_fcport_event_handler(vha, &ea); } - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); - spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); /* create new fcport if fw has knowledge of new sessions */ for (i = 0; i < n; i++) { port_id_t id; @@ -706,6 +878,8 @@ qla24xx_async_gnl_sp_done(void *s, int res) } } + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + vha->gnl.sent = 0; spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); sp->free(sp); @@ -725,27 +899,24 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) ql_dbg(ql_dbg_disc, vha, 0x20d9, "Async-gnlist WWPN %8phC \n", fcport->port_name); - spin_lock_irqsave(&vha->gnl.fcports_lock, flags); - if (!list_empty(&fcport->gnl_entry)) { - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); - rval = QLA_SUCCESS; - goto done; - } - - spin_lock(&vha->hw->tgt.sess_lock); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + fcport->flags |= FCF_ASYNC_SENT; fcport->disc_state = DSC_GNL; fcport->last_rscn_gen = fcport->rscn_gen; fcport->last_login_gen = fcport->login_gen; - spin_unlock(&vha->hw->tgt.sess_lock); list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports); - spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags); + if (vha->gnl.sent) { + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + return QLA_SUCCESS; + } + vha->gnl.sent = 1; + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); if (!sp) goto done; - fcport->flags |= FCF_ASYNC_SENT; sp->type = SRB_MB_IOCB; sp->name = "gnlist"; sp->gen1 = fcport->rscn_gen; @@ -767,14 +938,14 @@ int qla24xx_async_gnl(struct scsi_qla_host *vha, fc_port_t *fcport) sp->done = qla24xx_async_gnl_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x20da, "Async-%s - OUT WWPN %8phC hndl %x\n", sp->name, fcport->port_name, sp->handle); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: @@ -811,8 +982,13 @@ void qla24xx_async_gpdb_sp_done(void *s, int res) "Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n", sp->name, res, fcport->port_name, mb[1], mb[2]); - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + if (res == QLA_FUNCTION_TIMEOUT) { + dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, + sp->u.iocb_cmd.u.mbx.in_dma); + return; + } + fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); memset(&ea, 0, sizeof(ea)); ea.event = FCME_GPDB_DONE; ea.fcport = fcport; @@ -903,6 +1079,11 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) if (fcport->fc4f_nvme) lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI; + ql_dbg(ql_dbg_disc, vha, 0x211b, + "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n", + fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24, + fcport->login_retry, fcport->fc4f_nvme ? "nvme" : "fc"); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { fcport->flags |= FCF_LOGIN_NEEDED; @@ -910,11 +1091,6 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) goto done_free_sp; } - ql_dbg(ql_dbg_disc, vha, 0x211b, - "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n", - fcport->port_name, sp->handle, fcport->loop_id, - fcport->d_id.b24, fcport->login_retry); - return rval; done_free_sp: @@ -988,14 +1164,13 @@ int qla24xx_async_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, u8 opt) sp->done = qla24xx_async_gpdb_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x20dc, "Async-%s %8phC hndl %x opt %x\n", sp->name, fcport->port_name, sp->handle, opt); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; return rval; done_free_sp: @@ -1023,11 +1198,9 @@ void __qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) vha->fcport_count++; ea->fcport->login_succ = 1; - ql_dbg(ql_dbg_disc, vha, 0x20d6, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, ea->fcport->port_name, - vha->fcport_count); - qla24xx_post_upd_fcport_work(vha, ea->fcport); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + qla24xx_sched_upd_fcport(ea->fcport); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); } else if (ea->fcport->login_succ) { /* * We have an existing session. A late RSCN delivery @@ -1055,8 +1228,9 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) fcport->flags &= ~FCF_ASYNC_SENT; ql_dbg(ql_dbg_disc, vha, 0x20d2, - "%s %8phC DS %d LS %d rc %d\n", __func__, fcport->port_name, - fcport->disc_state, pd->current_login_state, ea->rc); + "%s %8phC DS %d LS %d nvme %x rc %d\n", __func__, fcport->port_name, + fcport->disc_state, pd->current_login_state, fcport->fc4f_nvme, + ea->rc); if (fcport->disc_state == DSC_DELETE_PEND) return; @@ -1066,6 +1240,19 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) else ls = pd->current_login_state & 0xf; + if (ea->sp->gen2 != fcport->login_gen) { + /* target side must have changed it. */ + + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC generation changed\n", + __func__, fcport->port_name); + return; + } else if (ea->sp->gen1 != fcport->rscn_gen) { + qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); + return; + } + switch (ls) { case PDS_PRLI_COMPLETE: __qla24xx_parse_gpdb(vha, fcport, pd); @@ -1120,7 +1307,8 @@ static void qla_chk_n2n_b4_login(struct scsi_qla_host *vha, fc_port_t *fcport) login = 1; } - if (login) { + if (login && fcport->login_retry) { + fcport->login_retry--; if (fcport->loop_id == FC_NO_LOOP_ID) { fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; rc = qla2x00_find_new_loop_id(vha, fcport); @@ -1144,14 +1332,14 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) { u16 data[2]; u64 wwn; + u16 sec; - ql_dbg(ql_dbg_disc, vha, 0x20d8, - "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d retry %d lid %d scan %d\n", + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x20d8, + "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d lid %d scan %d\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, fcport->login_pause, fcport->flags, fcport->conflict, fcport->last_rscn_gen, fcport->rscn_gen, - fcport->login_gen, fcport->login_retry, - fcport->loop_id, fcport->scan_state); + fcport->login_gen, fcport->loop_id, fcport->scan_state); if (fcport->scan_state != QLA_FCPORT_FOUND) return 0; @@ -1177,53 +1365,87 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) return 0; } - if (fcport->login_retry > 0) - fcport->login_retry--; - switch (fcport->disc_state) { case DSC_DELETED: wwn = wwn_to_u64(fcport->node_name); - if (wwn == 0) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post GNNID\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gnnid_work(vha, fcport); - } else if (fcport->loop_id == FC_NO_LOOP_ID) { - ql_dbg(ql_dbg_disc, vha, 0x20bd, - "%s %d %8phC post gnl\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gnl_work(vha, fcport); - } else { - qla_chk_n2n_b4_login(vha, fcport); + switch (vha->hw->current_topology) { + case ISP_CFG_N: + if (fcport_is_smaller(fcport)) { + /* this adapter is bigger */ + if (fcport->login_retry) { + if (fcport->loop_id == FC_NO_LOOP_ID) { + qla2x00_find_new_loop_id(vha, + fcport); + fcport->fw_login_state = + DSC_LS_PORT_UNAVAIL; + } + fcport->login_retry--; + qla_post_els_plogi_work(vha, fcport); + } else { + ql_log(ql_log_info, vha, 0x705d, + "Unable to reach remote port %8phC", + fcport->port_name); + } + } else { + qla24xx_post_gnl_work(vha, fcport); + } + break; + default: + if (wwn == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d %8phC post GNNID\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gnnid_work(vha, fcport); + } else if (fcport->loop_id == FC_NO_LOOP_ID) { + ql_dbg(ql_dbg_disc, vha, 0x20bd, + "%s %d %8phC post gnl\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gnl_work(vha, fcport); + } else { + qla_chk_n2n_b4_login(vha, fcport); + } + break; } break; case DSC_GNL: - if (fcport->login_pause) { - fcport->last_rscn_gen = fcport->rscn_gen; - fcport->last_login_gen = fcport->login_gen; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + switch (vha->hw->current_topology) { + case ISP_CFG_N: + if ((fcport->current_login_state & 0xf) == 0x6) { + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post GPDB work\n", + __func__, __LINE__, fcport->port_name); + fcport->chip_reset = + vha->hw->base_qpair->chip_reset; + qla24xx_post_gpdb_work(vha, fcport, 0); + } else { + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post NVMe PRLI\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_prli_work(vha, fcport); + } + break; + default: + if (fcport->login_pause) { + fcport->last_rscn_gen = fcport->rscn_gen; + fcport->last_login_gen = fcport->login_gen; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; + } + qla_chk_n2n_b4_login(vha, fcport); break; } - - qla_chk_n2n_b4_login(vha, fcport); break; case DSC_LOGIN_FAILED: - ql_dbg(ql_dbg_disc, vha, 0x20d0, - "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); if (N2N_TOPO(vha->hw)) qla_chk_n2n_b4_login(vha, fcport); else - qla24xx_post_gidpn_work(vha, fcport); + qlt_schedule_sess_for_deletion(fcport); break; case DSC_LOGIN_COMPLETE: /* recheck login state */ - ql_dbg(ql_dbg_disc, vha, 0x20d1, - "%s %d %8phC post adisc\n", - __func__, __LINE__, fcport->port_name); data[0] = data[1] = 0; qla2x00_post_async_adisc_work(vha, fcport, data); break; @@ -1233,6 +1455,22 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) qla24xx_post_prli_work(vha, fcport); break; + case DSC_UPD_FCPORT: + sec = jiffies_to_msecs(jiffies - + fcport->jiffies_at_registration)/1000; + if (fcport->sec_since_registration < sec && sec && + !(sec % 60)) { + fcport->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, fcport->vha, 0xffff, + "%s %8phC - Slow Rport registration(%d Sec)\n", + __func__, fcport->port_name, sec); + } + + if (fcport->next_disc_state != DSC_DELETE_PEND) + fcport->next_disc_state = DSC_ADISC; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; + default: break; } @@ -1240,29 +1478,6 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) return 0; } -static -void qla24xx_handle_rscn_event(fc_port_t *fcport, struct event_arg *ea) -{ - fcport->rscn_gen++; - - ql_dbg(ql_dbg_disc, fcport->vha, 0x210c, - "%s %8phC DS %d LS %d\n", - __func__, fcport->port_name, fcport->disc_state, - fcport->fw_login_state); - - if (fcport->flags & FCF_ASYNC_SENT) - return; - - switch (fcport->disc_state) { - case DSC_DELETED: - case DSC_LOGIN_COMPLETE: - qla24xx_post_gpnid_work(fcport->vha, &ea->id); - break; - default: - break; - } -} - int qla24xx_post_newsess_work(struct scsi_qla_host *vha, port_id_t *id, u8 *port_name, u8 *node_name, void *pla, u8 fc4_type) { @@ -1307,33 +1522,28 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, } } - if (fcport->flags & FCF_ASYNC_SENT) { - fcport->login_retry++; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - return; - } - - if (fcport->disc_state == DSC_DELETE_PEND) { - fcport->login_retry++; - return; - } - if (fcport->last_rscn_gen != fcport->rscn_gen) { ql_dbg(ql_dbg_disc, vha, 0x20e9, "%s %d %8phC post gidpn\n", __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); return; } qla24xx_fcport_handle_login(vha, fcport); } + +static void qla_handle_els_plogi_done(scsi_qla_host_t *vha, + struct event_arg *ea) +{ + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post PRLI\n", + __func__, __LINE__, ea->fcport->port_name); + qla24xx_post_prli_work(vha, ea->fcport); +} + void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) { - fc_port_t *f, *tf; - uint32_t id = 0, mask, rid; - unsigned long flags; fc_port_t *fcport; switch (ea->event) { @@ -1346,12 +1556,14 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_RSCN: if (test_bit(UNLOADING, &vha->dpc_flags)) return; - switch (ea->id.b.rsvd_1) { - case RSCN_PORT_ADDR: + { + unsigned long flags; fcport = qla2x00_find_fcport_by_nportid (vha, &ea->id, 1); - if (fcport) - fcport->rscn_rcvd = 1; + if (fcport) { + fcport->scan_needed = 1; + fcport->rscn_gen++; + } spin_lock_irqsave(&vha->work_lock, flags); if (vha->scan.scan_flags == 0) { @@ -1361,45 +1573,8 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) schedule_delayed_work(&vha->scan.scan_work, 5); } spin_unlock_irqrestore(&vha->work_lock, flags); - - break; - case RSCN_AREA_ADDR: - case RSCN_DOM_ADDR: - if (ea->id.b.rsvd_1 == RSCN_AREA_ADDR) { - mask = 0xffff00; - ql_dbg(ql_dbg_async, vha, 0x5044, - "RSCN: Area 0x%06x was affected\n", - ea->id.b24); - } else { - mask = 0xff0000; - ql_dbg(ql_dbg_async, vha, 0x507a, - "RSCN: Domain 0x%06x was affected\n", - ea->id.b24); - } - - rid = ea->id.b24 & mask; - list_for_each_entry_safe(f, tf, &vha->vp_fcports, - list) { - id = f->d_id.b24 & mask; - if (rid == id) { - ea->fcport = f; - qla24xx_handle_rscn_event(f, ea); - } - } - break; - case RSCN_FAB_ADDR: - default: - ql_log(ql_log_warn, vha, 0xd045, - "RSCN: Fabric was affected. Addr format %d\n", - ea->id.b.rsvd_1); - qla2x00_mark_all_devices_lost(vha, 1); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); } break; - case FCME_GIDPN_DONE: - qla24xx_handle_gidpn_event(vha, ea); - break; case FCME_GNL_DONE: qla24xx_handle_gnl_done_event(vha, ea); break; @@ -1430,12 +1605,39 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_GFPNID_DONE: qla24xx_handle_gfpnid_event(vha, ea); break; + case FCME_ELS_PLOGI_DONE: + qla_handle_els_plogi_done(vha, ea); + break; default: BUG_ON(1); break; } } +/* + * RSCN(s) came in for this fcport, but the RSCN(s) was not able + * to be consumed by the fcport + */ +void qla_rscn_replay(fc_port_t *fcport) +{ + struct event_arg ea; + + switch (fcport->disc_state) { + case DSC_DELETE_PEND: + return; + default: + break; + } + + if (fcport->scan_needed) { + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_RSCN; + ea.id = fcport->d_id; + ea.id.b.rsvd_1 = RSCN_PORT_ADDR; + qla2x00_fcport_event_handler(fcport->vha, &ea); + } +} + static void qla2x00_tmf_iocb_timeout(void *data) { @@ -1481,15 +1683,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, tm_iocb->u.tmf.data = tag; sp->done = qla2x00_tmf_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_taskm, vha, 0x802f, "Async-tmf hdl=%x loop-id=%x portid=%02x%02x%02x.\n", sp->handle, fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area, fcport->d_id.b.al_pa); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; wait_for_completion(&tm_iocb->u.tmf.comp); rval = tm_iocb->u.tmf.data; @@ -1504,14 +1705,14 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, lun = (uint16_t)tm_iocb->u.tmf.lun; /* Issue Marker IOCB */ - qla2x00_marker(vha, vha->hw->req_q_map[0], - vha->hw->rsp_q_map[0], sp->fcport->loop_id, lun, + qla2x00_marker(vha, vha->hw->base_qpair, + fcport->loop_id, lun, flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID); } done_free_sp: sp->free(sp); - sp->fcport->flags &= ~FCF_ASYNC_SENT; + fcport->flags &= ~FCF_ASYNC_SENT; done: return rval; } @@ -1523,7 +1724,7 @@ qla24xx_abort_iocb_timeout(void *data) struct srb_iocb *abt = &sp->u.iocb_cmd; abt->u.abt.comp_status = CS_TIMEOUT; - complete(&abt->u.abt.comp); + sp->done(sp, QLA_FUNCTION_TIMEOUT); } static void @@ -1532,53 +1733,59 @@ qla24xx_abort_sp_done(void *ptr, int res) srb_t *sp = ptr; struct srb_iocb *abt = &sp->u.iocb_cmd; - if (del_timer(&sp->u.iocb_cmd.timer)) - complete(&abt->u.abt.comp); + if (del_timer(&sp->u.iocb_cmd.timer)) { + if (sp->flags & SRB_WAKEUP_ON_COMP) + complete(&abt->u.abt.comp); + else + sp->free(sp); + } } int -qla24xx_async_abort_cmd(srb_t *cmd_sp) +qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) { scsi_qla_host_t *vha = cmd_sp->vha; - fc_port_t *fcport = cmd_sp->fcport; struct srb_iocb *abt_iocb; srb_t *sp; int rval = QLA_FUNCTION_FAILED; - sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + sp = qla2xxx_get_qpair_sp(cmd_sp->vha, cmd_sp->qpair, cmd_sp->fcport, + GFP_ATOMIC); if (!sp) goto done; abt_iocb = &sp->u.iocb_cmd; sp->type = SRB_ABT_CMD; sp->name = "abort"; + sp->qpair = cmd_sp->qpair; + if (wait) + sp->flags = SRB_WAKEUP_ON_COMP; abt_iocb->timeout = qla24xx_abort_iocb_timeout; init_completion(&abt_iocb->u.abt.comp); - qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha)); + /* FW can send 2 x ABTS's timeout/20s */ + qla2x00_init_timer(sp, 42); abt_iocb->u.abt.cmd_hndl = cmd_sp->handle; - - if (vha->flags.qpairs_available && cmd_sp->qpair) - abt_iocb->u.abt.req_que_no = - cpu_to_le16(cmd_sp->qpair->req->id); - else - abt_iocb->u.abt.req_que_no = cpu_to_le16(vha->req->id); + abt_iocb->u.abt.req_que_no = cpu_to_le16(cmd_sp->qpair->req->id); sp->done = qla24xx_abort_sp_done; + ql_dbg(ql_dbg_async, vha, 0x507c, + "Abort command issued - hdl=%x, type=%x\n", + cmd_sp->handle, cmd_sp->type); + rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) goto done_free_sp; - ql_dbg(ql_dbg_async, vha, 0x507c, - "Abort command issued - hdl=%x, target_id=%x\n", - cmd_sp->handle, fcport->tgt_id); - - wait_for_completion(&abt_iocb->u.abt.comp); - - rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? - QLA_SUCCESS : QLA_FUNCTION_FAILED; + if (wait) { + wait_for_completion(&abt_iocb->u.abt.comp); + rval = abt_iocb->u.abt.comp_status == CS_COMPLETE ? + QLA_SUCCESS : QLA_FUNCTION_FAILED; + } else { + goto done; + } done_free_sp: sp->free(sp); @@ -1593,19 +1800,17 @@ qla24xx_async_abort_command(srb_t *sp) uint32_t handle; fc_port_t *fcport = sp->fcport; + struct qla_qpair *qpair = sp->qpair; struct scsi_qla_host *vha = fcport->vha; - struct qla_hw_data *ha = vha->hw; - struct req_que *req = vha->req; + struct req_que *req = qpair->req; - if (vha->flags.qpairs_available && sp->qpair) - req = sp->qpair->req; - - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); for (handle = 1; handle < req->num_outstanding_cmds; handle++) { if (req->outstanding_cmds[handle] == sp) break; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + if (handle == req->num_outstanding_cmds) { /* Command not found. */ return QLA_FUNCTION_FAILED; @@ -1614,7 +1819,7 @@ qla24xx_async_abort_command(srb_t *sp) return qlafx00_fx_disc(vha, &vha->hw->mr.fcport, FXDISC_ABORT_IOCTL); - return qla24xx_async_abort_cmd(sp); + return qla24xx_async_abort_cmd(sp, true); } static void @@ -1628,6 +1833,12 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) ea->fcport->chip_reset = vha->hw->base_qpair->chip_reset; ea->fcport->logout_on_delete = 1; + ea->fcport->nvme_prli_service_param = ea->iop[0]; + if (ea->iop[0] & NVME_PRLI_SP_FIRST_BURST) + ea->fcport->nvme_first_burst_size = + (ea->iop[1] & 0xffff) * 512; + else + ea->fcport->nvme_first_burst_size = 0; qla24xx_post_gpdb_work(vha, ea->fcport, 0); break; default: @@ -1666,7 +1877,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d data %x|%x iop %x|%x\n", __func__, fcport->port_name, fcport->disc_state, fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen, - ea->sp->gen2, fcport->rscn_gen|ea->sp->gen1, + ea->sp->gen1, fcport->rscn_gen, ea->data[0], ea->data[1], ea->iop[0], ea->iop[1]); if ((fcport->fw_login_state == DSC_LS_PLOGI_PEND) || @@ -1688,9 +1899,11 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) set_bit(RELOGIN_NEEDED, &vha->dpc_flags); return; } else if (ea->sp->gen1 != fcport->rscn_gen) { - ql_dbg(ql_dbg_disc, vha, 0x20d4, "%s %d %8phC post gidpn\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gidpn_work(vha, fcport); + ql_dbg(ql_dbg_disc, vha, 0x20d3, + "%s %8phC RSCN generation changed\n", + __func__, fcport->port_name); + qla_rscn_replay(fcport); + qlt_schedule_sess_for_deletion(fcport); return; } @@ -1769,8 +1982,6 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) "%s %d %8phC NPortId %06x inuse with loopid 0x%x. post gidpn\n", __func__, __LINE__, ea->fcport->port_name, ea->fcport->d_id.b24, lid); - qla2x00_clear_loop_id(ea->fcport); - qla24xx_post_gidpn_work(vha, ea->fcport); } else { ql_dbg(ql_dbg_disc, vha, 0x20ed, "%s %d %8phC NPortId %06x inuse with loopid 0x%x. sched delete\n", @@ -1792,33 +2003,12 @@ void qla2x00_async_logout_done(struct scsi_qla_host *vha, fc_port_t *fcport, uint16_t *data) { - qla2x00_mark_device_lost(vha, fcport, 1, 0); qlt_logo_completion_handler(fcport, data[0]); fcport->login_gen++; fcport->flags &= ~FCF_ASYNC_ACTIVE; return; } -void -qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport, - uint16_t *data) -{ - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); - if (data[0] == MBS_COMMAND_COMPLETE) { - qla2x00_update_fcport(vha, fcport); - - return; - } - - /* Retry login. */ - if (data[1] & QLA_LOGIO_LOGIN_RETRIED) - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - else - qla2x00_mark_device_lost(vha, fcport, 1, 0); - - return; -} - /****************************************************************************/ /* QLogic ISP2x00 Hardware Support Functions. */ /****************************************************************************/ @@ -2836,8 +3026,8 @@ qla2x00_alloc_offload_mem(scsi_qla_host_t *vha) FCE_SIZE, ha->fce, ha->fce_dma); /* Allocate memory for Fibre Channel Event Buffer. */ - tc = dma_zalloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, - GFP_KERNEL); + tc = dma_alloc_coherent(&ha->pdev->dev, FCE_SIZE, &tc_dma, + GFP_KERNEL); if (!tc) { ql_log(ql_log_warn, vha, 0x00be, "Unable to allocate (%d KB) for FCE.\n", @@ -2868,8 +3058,8 @@ try_eft: EFT_SIZE, ha->eft, ha->eft_dma); /* Allocate memory for Extended Trace Buffer. */ - tc = dma_zalloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, - GFP_KERNEL); + tc = dma_alloc_coherent(&ha->pdev->dev, EFT_SIZE, &tc_dma, + GFP_KERNEL); if (!tc) { ql_log(ql_log_warn, vha, 0x00c1, "Unable to allocate (%d KB) for EFT.\n", @@ -3308,6 +3498,11 @@ qla2x00_setup_chip(scsi_qla_host_t *vha) if (rval == QLA_SUCCESS) { qla24xx_detect_sfp(vha); + if ((IS_QLA83XX(ha) || IS_QLA27XX(ha)) && + (ha->zio_mode == QLA_ZIO_MODE_6)) + qla27xx_set_zio_threshold(vha, + ha->last_zio_threshold); + rval = qla2x00_set_exlogins_buffer(vha); if (rval != QLA_SUCCESS) goto failed; @@ -3687,8 +3882,17 @@ qla24xx_config_rings(struct scsi_qla_host *vha) WRT_REG_DWORD(®->isp24.rsp_q_in, 0); WRT_REG_DWORD(®->isp24.rsp_q_out, 0); } + qlt_24xx_config_rings(vha); + /* If the user has configured the speed, set it here */ + if (ha->set_data_rate) { + ql_dbg(ql_dbg_init, vha, 0x00fd, + "Speed set by user : %s Gbps \n", + qla2x00_get_link_speed_str(ha, ha->set_data_rate)); + icb->firmware_options_3 = (ha->set_data_rate << 13); + } + /* PCI posting */ RD_REG_DWORD(&ioreg->hccr); } @@ -3796,6 +4000,7 @@ next_check: ql_dbg(ql_dbg_init, vha, 0x00d3, "Init Firmware -- success.\n"); QLA_FW_STARTED(ha); + vha->u_ql2xexchoffld = vha->u_ql2xiniexchg = 0; } return (rval); @@ -4043,7 +4248,8 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) id.b.al_pa = al_pa; id.b.rsvd_1 = 0; spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_update_host_map(vha, id); + if (!(topo == 2 && ha->flags.n2n_bigger)) + qlt_update_host_map(vha, id); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!vha->flags.init_done) @@ -4301,7 +4507,7 @@ qla2x00_nvram_config(scsi_qla_host_t *vha) cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options; while (cnt--) *dptr1++ = *dptr2++; - + ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size); /* Use alternate WWN? */ if (nv->host_p[1] & BIT_7) { memcpy(icb->node_name, nv->alternate_node_name, WWN_SIZE); @@ -4485,6 +4691,16 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) if (!fcport) return NULL; + fcport->ct_desc.ct_sns = dma_alloc_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), &fcport->ct_desc.ct_sns_dma, + flags); + if (!fcport->ct_desc.ct_sns) { + ql_log(ql_log_warn, vha, 0xd049, + "Failed to allocate ct_sns request.\n"); + kfree(fcport); + return NULL; + } + /* Setup fcport template structure. */ fcport->vha = vha; fcport->port_type = FCT_UNKNOWN; @@ -4493,13 +4709,11 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) fcport->supported_classes = FC_COS_UNSPECIFIED; fcport->fp_speed = PORT_SPEED_UNKNOWN; - fcport->ct_desc.ct_sns = dma_alloc_coherent(&vha->hw->pdev->dev, - sizeof(struct ct_sns_pkt), &fcport->ct_desc.ct_sns_dma, - flags); fcport->disc_state = DSC_DELETED; fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; fcport->deleted = QLA_SESS_DELETED; fcport->login_retry = vha->hw->login_retry_count; + fcport->chip_reset = vha->hw->base_qpair->chip_reset; fcport->logout_on_delete = 1; if (!fcport->ct_desc.ct_sns) { @@ -4508,7 +4722,9 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags) kfree(fcport); fcport = NULL; } + INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn); + INIT_WORK(&fcport->reg_work, qla_register_fcport_fn); INIT_LIST_HEAD(&fcport->gnl_entry); INIT_LIST_HEAD(&fcport->list); @@ -4585,20 +4801,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) } else if (ha->current_topology == ISP_CFG_N) { clear_bit(RSCN_UPDATE, &flags); - if (ha->flags.rida_fmt2) { - /* With Rida Format 2, the login is already triggered. - * We know who is on the other side of the wire. - * No need to login to do login to find out or drop into - * qla2x00_configure_local_loop(). - */ + if (qla_tgt_mode_enabled(vha)) { + /* allow the other side to start the login */ clear_bit(LOCAL_LOOP_UPDATE, &flags); set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - } else { - if (qla_tgt_mode_enabled(vha)) { - /* allow the other side to start the login */ - clear_bit(LOCAL_LOOP_UPDATE, &flags); - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - } } } else if (ha->current_topology == ISP_CFG_NL) { clear_bit(RSCN_UPDATE, &flags); @@ -4644,19 +4850,10 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) */ if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) { - if (IS_QLA27XX(ha) || IS_QLA83XX(ha)) { - spin_lock_irqsave(&ha->tgt.atio_lock, - flags); - qlt_24xx_process_atio_queue(vha, 0); - spin_unlock_irqrestore( - &ha->tgt.atio_lock, flags); - } else { - spin_lock_irqsave(&ha->hardware_lock, - flags); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore( - &ha->hardware_lock, flags); - } + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, + flags); } } } @@ -4681,110 +4878,6 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) return (rval); } -/* - * N2N Login - * Updates Fibre Channel Device Database with local loop devices. - * - * Input: - * ha = adapter block pointer. - * - * Returns: - */ -static int qla24xx_n2n_handle_login(struct scsi_qla_host *vha, - fc_port_t *fcport) -{ - struct qla_hw_data *ha = vha->hw; - int res = QLA_SUCCESS, rval; - int greater_wwpn = 0; - int logged_in = 0; - - if (ha->current_topology != ISP_CFG_N) - return res; - - if (wwn_to_u64(vha->port_name) > - wwn_to_u64(vha->n2n_port_name)) { - ql_dbg(ql_dbg_disc, vha, 0x2002, - "HBA WWPN is greater %llx > target %llx\n", - wwn_to_u64(vha->port_name), - wwn_to_u64(vha->n2n_port_name)); - greater_wwpn = 1; - fcport->d_id.b24 = vha->n2n_id; - } - - fcport->loop_id = vha->loop_id; - fcport->fc4f_nvme = 0; - fcport->query = 1; - - ql_dbg(ql_dbg_disc, vha, 0x4001, - "Initiate N2N login handler: HBA port_id=%06x loopid=%d\n", - fcport->d_id.b24, vha->loop_id); - - /* Fill in member data. */ - if (!greater_wwpn) { - rval = qla2x00_get_port_database(vha, fcport, 0); - ql_dbg(ql_dbg_disc, vha, 0x1051, - "Remote login-state (%x/%x) port_id=%06x loop_id=%x, rval=%d\n", - fcport->current_login_state, fcport->last_login_state, - fcport->d_id.b24, fcport->loop_id, rval); - - if (((fcport->current_login_state & 0xf) == 0x4) || - ((fcport->current_login_state & 0xf) == 0x6)) - logged_in = 1; - } - - if (logged_in || greater_wwpn) { - if (!vha->nvme_local_port && vha->flags.nvme_enabled) - qla_nvme_register_hba(vha); - - /* Set connected N_Port d_id */ - if (vha->flags.nvme_enabled) - fcport->fc4f_nvme = 1; - - fcport->scan_state = QLA_FCPORT_FOUND; - fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; - fcport->disc_state = DSC_GNL; - fcport->n2n_flag = 1; - fcport->flags = 3; - vha->hw->flags.gpsc_supported = 0; - - if (greater_wwpn) { - ql_dbg(ql_dbg_disc, vha, 0x20e5, - "%s %d PLOGI ELS %8phC\n", - __func__, __LINE__, fcport->port_name); - - res = qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI, - fcport, fcport->d_id); - } - - if (res != QLA_SUCCESS) { - ql_log(ql_log_info, vha, 0xd04d, - "PLOGI Failed: portid=%06x - retrying\n", - fcport->d_id.b24); - res = QLA_SUCCESS; - } else { - /* State 0x6 means FCP PRLI complete */ - if ((fcport->current_login_state & 0xf) == 0x6) { - ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post GPDB work\n", - __func__, __LINE__, fcport->port_name); - fcport->chip_reset = - vha->hw->base_qpair->chip_reset; - qla24xx_post_gpdb_work(vha, fcport, 0); - } else { - ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post NVMe PRLI\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_prli_work(vha, fcport); - } - } - } else { - /* Wait for next database change */ - set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); - } - - return res; -} - /* * qla2x00_configure_local_loop * Updates Fibre Channel Device Database with local loop devices. @@ -4811,6 +4904,31 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; unsigned long flags; + /* Inititae N2N login. */ + if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { + /* borrowing */ + u32 *bp, i, sz; + + memset(ha->init_cb, 0, ha->init_cb_size); + sz = min_t(int, sizeof(struct els_plogi_payload), + ha->init_cb_size); + rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, + (void *)ha->init_cb, sz); + if (rval == QLA_SUCCESS) { + bp = (uint32_t *)ha->init_cb; + for (i = 0; i < sz/4 ; i++, bp++) + *bp = cpu_to_be32(*bp); + + memcpy(&ha->plogi_els_payld.data, (void *)ha->init_cb, + sizeof(ha->plogi_els_payld.data)); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } else { + ql_dbg(ql_dbg_init, vha, 0x00d1, + "PLOGI ELS param read fail.\n"); + } + return QLA_SUCCESS; + } + found_devs = 0; new_fcport = NULL; entries = MAX_FIBRE_DEVICES_LOOP; @@ -4828,6 +4946,19 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) (uint8_t *)ha->gid_list, entries * sizeof(struct gid_list_info)); + if (entries == 0) { + spin_lock_irqsave(&vha->work_lock, flags); + vha->scan.scan_retry++; + spin_unlock_irqrestore(&vha->work_lock, flags); + + if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { + set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + } + } else { + vha->scan.scan_retry = 0; + } + list_for_each_entry(fcport, &vha->vp_fcports, list) { fcport->scan_state = QLA_FCPORT_SCAN; } @@ -4842,14 +4973,6 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) } new_fcport->flags &= ~FCF_FABRIC_DEVICE; - /* Inititae N2N login. */ - if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { - rval = qla24xx_n2n_handle_login(vha, new_fcport); - if (rval != QLA_SUCCESS) - goto cleanup_allocation; - return QLA_SUCCESS; - } - /* Add devices to port list. */ id_iter = (char *)ha->gid_list; for (index = 0; index < entries; index++) { @@ -4869,10 +4992,12 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) continue; /* Bypass if not same domain and area of adapter. */ - if (area && domain && - (area != vha->d_id.b.area || domain != vha->d_id.b.domain)) + if (area && domain && ((area != vha->d_id.b.area) || + (domain != vha->d_id.b.domain)) && + (ha->current_topology == ISP_CFG_NL)) continue; + /* Bypass invalid local loop ID. */ if (loop_id > LAST_LOCAL_LOOP_ID) continue; @@ -5048,6 +5173,9 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) struct fc_rport *rport; unsigned long flags; + if (atomic_read(&fcport->state) == FCS_ONLINE) + return; + rport_ids.node_name = wwn_to_u64(fcport->node_name); rport_ids.port_name = wwn_to_u64(fcport->port_name); rport_ids.port_id = fcport->d_id.b.domain << 16 | @@ -5098,30 +5226,35 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport) void qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) { - fcport->vha = vha; - if (IS_SW_RESV_ADDR(fcport->d_id)) return; ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n", __func__, fcport->port_name); - if (IS_QLAFX00(vha->hw)) { - qla2x00_set_fcport_state(fcport, FCS_ONLINE); - } else { - fcport->login_retry = 0; - fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); - fcport->disc_state = DSC_LOGIN_COMPLETE; - fcport->deleted = 0; - fcport->logout_on_delete = 1; - qla2x00_set_fcport_state(fcport, FCS_ONLINE); + fcport->disc_state = DSC_UPD_FCPORT; + fcport->login_retry = vha->hw->login_retry_count; + fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT); + fcport->deleted = 0; + fcport->logout_on_delete = 1; + fcport->login_retry = vha->hw->login_retry_count; + fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0; + + switch (vha->hw->current_topology) { + case ISP_CFG_N: + case ISP_CFG_NL: + fcport->keep_nport_handle = 1; + break; + default: + break; } - qla2x00_set_fcport_state(fcport, FCS_ONLINE); qla2x00_iidma_fcport(vha, fcport); if (fcport->fc4f_nvme) { qla_nvme_register_remote(vha, fcport); + fcport->disc_state = DSC_LOGIN_COMPLETE; + qla2x00_set_fcport_state(fcport, FCS_ONLINE); return; } @@ -5146,6 +5279,8 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) break; } + qla2x00_set_fcport_state(fcport, FCS_ONLINE); + if (IS_IIDMA_CAPABLE(vha->hw) && vha->hw->flags.gpsc_supported) { if (fcport->id_changed) { fcport->id_changed = 0; @@ -5162,6 +5297,36 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla24xx_post_gpsc_work(vha, fcport); } } + + fcport->disc_state = DSC_LOGIN_COMPLETE; +} + +void qla_register_fcport_fn(struct work_struct *work) +{ + fc_port_t *fcport = container_of(work, struct fc_port, reg_work); + u32 rscn_gen = fcport->rscn_gen; + u16 data[2]; + + if (IS_SW_RESV_ADDR(fcport->d_id)) + return; + + qla2x00_update_fcport(fcport->vha, fcport); + + if (rscn_gen != fcport->rscn_gen) { + /* RSCN(s) came in while registration */ + switch (fcport->next_disc_state) { + case DSC_DELETE_PEND: + qlt_schedule_sess_for_deletion(fcport); + break; + case DSC_ADISC: + data[0] = data[1] = 0; + qla2x00_post_async_adisc_work(fcport->vha, fcport, + data); + break; + default: + break; + } + } } /* @@ -5662,6 +5827,34 @@ qla2x00_find_new_loop_id(scsi_qla_host_t *vha, fc_port_t *dev) } +/* FW does not set aside Loop id for MGMT Server/FFFFFAh */ +int +qla2x00_reserve_mgmt_server_loop_id(scsi_qla_host_t *vha) +{ + int loop_id = FC_NO_LOOP_ID; + int lid = NPH_MGMT_SERVER - vha->vp_idx; + unsigned long flags; + struct qla_hw_data *ha = vha->hw; + + if (vha->vp_idx == 0) { + set_bit(NPH_MGMT_SERVER, ha->loop_id_map); + return NPH_MGMT_SERVER; + } + + /* pick id from high and work down to low */ + spin_lock_irqsave(&ha->vport_slock, flags); + for (; lid > 0; lid--) { + if (!test_bit(lid, vha->hw->loop_id_map)) { + set_bit(lid, vha->hw->loop_id_map); + loop_id = lid; + break; + } + } + spin_unlock_irqrestore(&ha->vport_slock, flags); + + return loop_id; +} + /* * qla2x00_fabric_login * Issue fabric login command. @@ -5855,11 +6048,6 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) { int rval = QLA_SUCCESS; uint32_t wait_time; - struct req_que *req; - struct rsp_que *rsp; - - req = vha->req; - rsp = req->rsp; clear_bit(ISP_ABORT_RETRY, &vha->dpc_flags); if (vha->flags.online) { @@ -5872,8 +6060,8 @@ qla2x00_loop_resync(scsi_qla_host_t *vha) * Issue a marker after FW becomes * ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, - MK_SYNC_ALL); + qla2x00_marker(vha, vha->hw->base_qpair, + 0, 0, MK_SYNC_ALL); vha->marker_needed = 0; } @@ -6329,6 +6517,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ql_log(ql_log_info, vha, 0x00af, "Performing ISP error recovery - ha=%p.\n", ha); + ha->flags.purge_mbox = 1; /* For ISP82XX, reset_chip is just disabling interrupts. * Driver waits for the completion of the commands. * the interrupts need to be enabled. @@ -6336,6 +6525,7 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) if (!(IS_P3P_TYPE(ha))) ha->isp_ops->reset_chip(vha); + ha->link_data_rate = PORT_SPEED_UNKNOWN; SAVE_TOPO(ha); ha->flags.rida_fmt2 = 0; ha->flags.n2n_ae = 0; @@ -6343,13 +6533,31 @@ qla2x00_abort_isp_cleanup(scsi_qla_host_t *vha) ha->current_topology = 0; ha->flags.fw_started = 0; ha->flags.fw_init_done = 0; - ha->base_qpair->chip_reset++; + ha->chip_reset++; + ha->base_qpair->chip_reset = ha->chip_reset; for (i = 0; i < ha->max_qpairs; i++) { if (ha->queue_pair_map[i]) ha->queue_pair_map[i]->chip_reset = ha->base_qpair->chip_reset; } + /* purge MBox commands */ + if (atomic_read(&ha->num_pend_mbx_stage3)) { + clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); + complete(&ha->mbx_intr_comp); + } + + i = 0; + while (atomic_read(&ha->num_pend_mbx_stage3) || + atomic_read(&ha->num_pend_mbx_stage2) || + atomic_read(&ha->num_pend_mbx_stage1)) { + msleep(20); + i++; + if (i > 50) + break; + } + ha->flags.purge_mbox = 0; + atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); if (atomic_read(&vha->loop_state) != LOOP_DOWN) { atomic_set(&vha->loop_state, LOOP_DOWN); @@ -6446,6 +6654,20 @@ qla2x00_abort_isp(scsi_qla_host_t *vha) return status; } + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_DISABLED: + if (!qla_tgt_mode_enabled(vha)) + return 0; + break; + case QLA2XXX_INI_MODE_DUAL: + if (!qla_dual_mode_enabled(vha)) + return 0; + break; + case QLA2XXX_INI_MODE_ENABLED: + default: + break; + } + ha->isp_ops->get_flash_version(vha, req->ring); ha->isp_ops->nvram_config(vha); @@ -6577,8 +6799,6 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) { int status = 0; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; /* If firmware needs to be loaded */ if (qla2x00_isp_firmware(vha)) { @@ -6598,7 +6818,7 @@ qla2x00_restart_isp(scsi_qla_host_t *vha) status = qla2x00_fw_ready(vha); if (!status) { /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } @@ -6855,7 +7075,7 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) (uint8_t *)&icb->interrupt_delay_timer; while (cnt--) *dptr1++ = *dptr2++; - + ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size); /* * Setup driver NVRAM options. */ @@ -6954,6 +7174,9 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) if (ql2xloginretrycount) ha->login_retry_count = ql2xloginretrycount; + /* N2N: driver will initiate Login instead of FW */ + icb->firmware_options_3 |= BIT_8; + /* Enable ZIO. */ if (!vha->flags.init_done) { ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & @@ -7061,7 +7284,7 @@ check_valid_image: ha->active_image = QLA27XX_SECONDARY_IMAGE; } - ql_dbg(ql_dbg_init, vha, 0x018f, "%s image\n", + ql_dbg(ql_dbg_init + ql_dbg_verbose, vha, 0x018f, "%s image\n", ha->active_image == 0 ? "default bootld and fw" : ha->active_image == 1 ? "primary" : ha->active_image == 2 ? "secondary" : @@ -7650,22 +7873,15 @@ qla24xx_configure_vhba(scsi_qla_host_t *vha) uint16_t mb[MAILBOX_REGISTER_COUNT]; struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - struct req_que *req; - struct rsp_que *rsp; if (!vha->vp_idx) return -EINVAL; rval = qla2x00_fw_ready(base_vha); - if (vha->qpair) - req = vha->qpair->req; - else - req = ha->req_q_map[0]; - rsp = req->rsp; if (rval == QLA_SUCCESS) { clear_bit(RESET_MARKER_NEEDED, &vha->dpc_flags); - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL); } vha->flags.management_server_logged_in = 0; @@ -7909,7 +8125,7 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* Use extended-initialization control block. */ memcpy(ha->ex_init_cb, &nv->ex_version, sizeof(*ha->ex_init_cb)); - + ha->frame_payload_size = le16_to_cpu(icb->frame_payload_size); /* * Setup driver NVRAM options. */ @@ -8034,8 +8250,10 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) } /* enable RIDA Format2 */ - if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) - icb->firmware_options_3 |= BIT_0; + icb->firmware_options_3 |= BIT_0; + + /* N2N: driver will initiate Login instead of FW */ + icb->firmware_options_3 |= BIT_8; if (IS_QLA27XX(ha)) { icb->firmware_options_3 |= BIT_8; @@ -8055,8 +8273,6 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) { int status, rval; struct qla_hw_data *ha = vha->hw; - struct req_que *req = ha->req_q_map[0]; - struct rsp_que *rsp = ha->rsp_q_map[0]; struct scsi_qla_host *vp; unsigned long flags; @@ -8068,7 +8284,7 @@ qla82xx_restart_isp(scsi_qla_host_t *vha) status = qla2x00_fw_ready(vha); if (!status) { /* Issue a marker after FW becomes ready. */ - qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL); + qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL); vha->flags.online = 1; set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } diff --git a/qla2x00t-32gbit/qla_inline.h b/qla2x00t-32gbit/qla_inline.h index 59fd5a9df..512c3c37b 100644 --- a/qla2x00t-32gbit/qla_inline.h +++ b/qla2x00t-32gbit/qla_inline.h @@ -58,14 +58,12 @@ qla2x00_debounce_register(volatile uint16_t __iomem *addr) static inline void qla2x00_poll(struct rsp_que *rsp) { - unsigned long flags; struct qla_hw_data *ha = rsp->hw; - local_irq_save(flags); + if (IS_P3P_TYPE(ha)) qla82xx_poll(0, rsp); else ha->isp_ops->intr_handler(0, rsp); - local_irq_restore(flags); } static inline uint8_t * @@ -204,8 +202,15 @@ qla2x00_reset_active(scsi_qla_host_t *vha) test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags); } +static inline int +qla2x00_chip_is_down(scsi_qla_host_t *vha) +{ + return (qla2x00_reset_active(vha) || !vha->hw->flags.fw_started); +} + static inline srb_t * -qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) +qla2xxx_get_qpair_sp(scsi_qla_host_t *vha, struct qla_qpair *qpair, + fc_port_t *fcport, gfp_t flag) { srb_t *sp = NULL; uint8_t bail; @@ -221,7 +226,9 @@ qla2xxx_get_qpair_sp(struct qla_qpair *qpair, fc_port_t *fcport, gfp_t flag) memset(sp, 0, sizeof(*sp)); sp->fcport = fcport; sp->iocbs = 1; - sp->vha = qpair->vha; + sp->vha = vha; + sp->qpair = qpair; + sp->cmd_type = TYPE_SRB; INIT_LIST_HEAD(&sp->elem); done: @@ -242,19 +249,17 @@ qla2x00_get_sp(scsi_qla_host_t *vha, fc_port_t *fcport, gfp_t flag) { srb_t *sp = NULL; uint8_t bail; + struct qla_qpair *qpair; QLA_VHA_MARK_BUSY(vha, bail); if (unlikely(bail)) return NULL; - sp = mempool_alloc(vha->hw->srb_mempool, flag); + qpair = vha->hw->base_qpair; + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, flag); if (!sp) goto done; - memset(sp, 0, sizeof(*sp)); - sp->fcport = fcport; - sp->cmd_type = TYPE_SRB; - sp->iocbs = 1; sp->vha = vha; done: if (!sp) @@ -266,7 +271,7 @@ static inline void qla2x00_rel_sp(srb_t *sp) { QLA_VHA_MARK_NOT_BUSY(sp->vha); - mempool_free(sp, sp->vha->hw->srb_mempool); + qla2xxx_rel_qpair_sp(sp->qpair, sp); } static inline void @@ -278,8 +283,6 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo) init_completion(&sp->comp); if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD)) init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); - if (sp->type == SRB_ELS_DCMD) - init_completion(&sp->u.iocb_cmd.u.els_logo.comp); add_timer(&sp->u.iocb_cmd.timer); } @@ -315,13 +318,13 @@ static inline bool qla_is_exch_offld_enabled(struct scsi_qla_host *vha) { if (qla_ini_mode_enabled(vha) && - (ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) + (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT)) return true; else if (qla_tgt_mode_enabled(vha) && - (ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) + (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT)) return true; else if (qla_dual_mode_enabled(vha) && - ((ql2xiniexchg + ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) + ((vha->ql2xiniexchg + vha->ql2xexchoffld) > FW_DEF_EXCHANGES_CNT)) return true; else return false; diff --git a/qla2x00t-32gbit/qla_iocb.c b/qla2x00t-32gbit/qla_iocb.c index 3e94f15ce..456a41d2e 100644 --- a/qla2x00t-32gbit/qla_iocb.c +++ b/qla2x00t-32gbit/qla_iocb.c @@ -336,7 +336,7 @@ qla2x00_start_scsi(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { return (QLA_FUNCTION_FAILED); } @@ -490,8 +490,7 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) /** * qla2x00_marker() - Send a marker IOCB to the firmware. * @vha: HA context - * @req: request queue - * @rsp: response queue + * @qpair: queue pair pointer * @loop_id: loop ID * @lun: LUN * @type: marker modifier @@ -501,18 +500,16 @@ qla2x00_start_iocbs(struct scsi_qla_host *vha, struct req_que *req) * Returns non-zero if a failure occurred, else zero. */ static int -__qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, - struct rsp_que *rsp, uint16_t loop_id, - uint64_t lun, uint8_t type) +__qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, + uint16_t loop_id, uint64_t lun, uint8_t type) { mrk_entry_t *mrk; struct mrk_entry_24xx *mrk24 = NULL; - + struct req_que *req = qpair->req; struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); - req = ha->req_q_map[0]; - mrk = (mrk_entry_t *)qla2x00_alloc_iocbs(vha, NULL); + mrk = (mrk_entry_t *)__qla2x00_alloc_iocbs(qpair, NULL); if (mrk == NULL) { ql_log(ql_log_warn, base_vha, 0x3026, "Failed to allocate Marker IOCB.\n"); @@ -543,16 +540,15 @@ __qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, } int -qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, - struct rsp_que *rsp, uint16_t loop_id, uint64_t lun, - uint8_t type) +qla2x00_marker(struct scsi_qla_host *vha, struct qla_qpair *qpair, + uint16_t loop_id, uint64_t lun, uint8_t type) { int ret; unsigned long flags = 0; - spin_lock_irqsave(&vha->hw->hardware_lock, flags); - ret = __qla2x00_marker(vha, req, rsp, loop_id, lun, type); - spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + ret = __qla2x00_marker(vha, qpair, loop_id, lun, type); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return (ret); } @@ -567,11 +563,11 @@ qla2x00_marker(struct scsi_qla_host *vha, struct req_que *req, int qla2x00_issue_marker(scsi_qla_host_t *vha, int ha_locked) { if (ha_locked) { - if (__qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0, + if (__qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) return QLA_FUNCTION_FAILED; } else { - if (qla2x00_marker(vha, vha->req, vha->req->rsp, 0, 0, + if (qla2x00_marker(vha, vha->hw->base_qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) return QLA_FUNCTION_FAILED; } @@ -1098,88 +1094,300 @@ qla24xx_walk_and_build_sglist(struct qla_hw_data *ha, srb_t *sp, uint32_t *dsd, int qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, - uint32_t *dsd, uint16_t tot_dsds, struct qla_tc_param *tc) + uint32_t *cur_dsd, uint16_t tot_dsds, struct qla_tgt_cmd *tc) { - void *next_dsd; - uint8_t avail_dsds = 0; - uint32_t dsd_list_len; - struct dsd_dma *dsd_ptr; + struct dsd_dma *dsd_ptr = NULL, *dif_dsd, *nxt_dsd; struct scatterlist *sg, *sgl; - int i; - struct scsi_cmnd *cmd; - uint32_t *cur_dsd = dsd; - uint16_t used_dsds = tot_dsds; + struct crc_context *difctx = NULL; struct scsi_qla_host *vha; + uint dsd_list_len; + uint avail_dsds = 0; + uint used_dsds = tot_dsds; + bool dif_local_dma_alloc = false; + bool direction_to_device = false; + int i; if (sp) { - cmd = GET_CMD_SP(sp); + struct scsi_cmnd *cmd = GET_CMD_SP(sp); sgl = scsi_prot_sglist(cmd); vha = sp->vha; + difctx = sp->u.scmd.ctx; + direction_to_device = cmd->sc_data_direction == DMA_TO_DEVICE; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, + "%s: scsi_cmnd: %p, crc_ctx: %p, sp: %p\n", + __func__, cmd, difctx, sp); } else if (tc) { vha = tc->vha; sgl = tc->prot_sg; + difctx = tc->ctx; + direction_to_device = tc->dma_data_direction == DMA_TO_DEVICE; } else { BUG(); return 1; } - ql_dbg(ql_dbg_tgt, vha, 0xe021, - "%s: enter\n", __func__); + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe021, + "%s: enter (write=%u)\n", __func__, direction_to_device); - for_each_sg(sgl, sg, tot_dsds, i) { - dma_addr_t sle_dma; + /* if initiator doing write or target doing read */ + if (direction_to_device) { + for_each_sg(sgl, sg, tot_dsds, i) { + u64 sle_phys = sg_phys(sg); - /* Allocate additional continuation packets? */ - if (avail_dsds == 0) { - avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? - QLA_DSDS_PER_IOCB : used_dsds; - dsd_list_len = (avail_dsds + 1) * 12; - used_dsds -= avail_dsds; + /* If SGE addr + len flips bits in upper 32-bits */ + if (MSD(sle_phys + sg->length) ^ MSD(sle_phys)) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe022, + "%s: page boundary crossing (phys=%llx len=%x)\n", + __func__, sle_phys, sg->length); - /* allocate tracking DS */ - dsd_ptr = kzalloc(sizeof(struct dsd_dma), GFP_ATOMIC); - if (!dsd_ptr) - return 1; - - /* allocate new list */ - dsd_ptr->dsd_addr = next_dsd = - dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, - &dsd_ptr->dsd_list_dma); - - if (!next_dsd) { - /* - * Need to cleanup only this dsd_ptr, rest - * will be done by sp_free_dma() - */ - kfree(dsd_ptr); - return 1; + if (difctx) { + ha->dif_bundle_crossed_pages++; + dif_local_dma_alloc = true; + } else { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, + vha, 0xe022, + "%s: difctx pointer is NULL\n", + __func__); + } + break; } - - if (sp) { - list_add_tail(&dsd_ptr->list, - &((struct crc_context *) - sp->u.scmd.ctx)->dsd_list); - - sp->flags |= SRB_CRC_CTX_DSD_VALID; - } else { - list_add_tail(&dsd_ptr->list, - &(tc->ctx->dsd_list)); - *tc->ctx_dsd_alloced = 1; - } - - /* add new list to cmd iocb or last list */ - *cur_dsd++ = cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); - *cur_dsd++ = dsd_list_len; - cur_dsd = (uint32_t *)next_dsd; } - sle_dma = sg_dma_address(sg); + ha->dif_bundle_writes++; + } else { + ha->dif_bundle_reads++; + } - *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); - *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + if (ql2xdifbundlinginternalbuffers) + dif_local_dma_alloc = direction_to_device; - avail_dsds--; + if (dif_local_dma_alloc) { + u32 track_difbundl_buf = 0; + u32 ldma_sg_len = 0; + u8 ldma_needed = 1; + + difctx->no_dif_bundl = 0; + difctx->dif_bundl_len = 0; + + /* Track DSD buffers */ + INIT_LIST_HEAD(&difctx->ldif_dsd_list); + /* Track local DMA buffers */ + INIT_LIST_HEAD(&difctx->ldif_dma_hndl_list); + + for_each_sg(sgl, sg, tot_dsds, i) { + u32 sglen = sg_dma_len(sg); + + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe023, + "%s: sg[%x] (phys=%llx sglen=%x) ldma_sg_len: %x dif_bundl_len: %x ldma_needed: %x\n", + __func__, i, (u64)sg_phys(sg), sglen, ldma_sg_len, + difctx->dif_bundl_len, ldma_needed); + + while (sglen) { + u32 xfrlen = 0; + + if (ldma_needed) { + /* + * Allocate list item to store + * the DMA buffers + */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), + GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt, vha, 0xe024, + "%s: failed alloc dsd_ptr\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + /* allocate dma buffer */ + dsd_ptr->dsd_addr = dma_pool_alloc + (ha->dif_bundl_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + ql_dbg(ql_dbg_tgt, vha, 0xe024, + "%s: failed alloc ->dsd_ptr\n", + __func__); + /* + * need to cleanup only this + * dsd_ptr rest will be done + * by sp_free_dma() + */ + kfree(dsd_ptr); + ha->dif_bundle_kallocs--; + return 1; + } + ha->dif_bundle_dma_allocs++; + ldma_needed = 0; + difctx->no_dif_bundl++; + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dma_hndl_list); + } + + /* xfrlen is min of dma pool size and sglen */ + xfrlen = (sglen > + (DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len)) ? + DIF_BUNDLING_DMA_POOL_SIZE - ldma_sg_len : + sglen; + + /* replace with local allocated dma buffer */ + sg_pcopy_to_buffer(sgl, sg_nents(sgl), + dsd_ptr->dsd_addr + ldma_sg_len, xfrlen, + difctx->dif_bundl_len); + difctx->dif_bundl_len += xfrlen; + sglen -= xfrlen; + ldma_sg_len += xfrlen; + if (ldma_sg_len == DIF_BUNDLING_DMA_POOL_SIZE || + sg_is_last(sg)) { + ldma_needed = 1; + ldma_sg_len = 0; + } + } + } + + track_difbundl_buf = used_dsds = difctx->no_dif_bundl; + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe025, + "dif_bundl_len=%x, no_dif_bundl=%x track_difbundl_buf: %x\n", + difctx->dif_bundl_len, difctx->no_dif_bundl, + track_difbundl_buf); + + if (sp) + sp->flags |= SRB_DIF_BUNDL_DMA_VALID; + else + tc->prot_flags = DIF_BUNDL_DMA_VALID; + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dma_hndl_list, list) { + u32 sglen = (difctx->dif_bundl_len > + DIF_BUNDLING_DMA_POOL_SIZE) ? + DIF_BUNDLING_DMA_POOL_SIZE : difctx->dif_bundl_len; + + BUG_ON(track_difbundl_buf == 0); + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, + 0xe024, + "%s: adding continuation iocb's\n", + __func__); + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt, vha, 0xe026, + "%s: failed alloc dsd_ptr\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + difctx->no_ldif_dsd++; + /* allocate new list */ + dsd_ptr->dsd_addr = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + ql_dbg(ql_dbg_tgt, vha, 0xe026, + "%s: failed alloc ->dsd_addr\n", + __func__); + /* + * need to cleanup only this dsd_ptr + * rest will be done by sp_free_dma() + */ + kfree(dsd_ptr); + ha->dif_bundle_kallocs--; + return 1; + } + ha->dif_bundle_dma_allocs++; + + if (sp) { + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dsd_list); + sp->flags |= SRB_CRC_CTX_DSD_VALID; + } else { + list_add_tail(&dsd_ptr->list, + &difctx->ldif_dsd_list); + tc->ctx_dsd_alloced = 1; + } + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = + cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = + cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = dsd_ptr->dsd_addr; + } + *cur_dsd++ = cpu_to_le32(LSD(dif_dsd->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(MSD(dif_dsd->dsd_list_dma)); + *cur_dsd++ = cpu_to_le32(sglen); + avail_dsds--; + difctx->dif_bundl_len -= sglen; + track_difbundl_buf--; + } + + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe026, + "%s: no_ldif_dsd:%x, no_dif_bundl:%x\n", __func__, + difctx->no_ldif_dsd, difctx->no_dif_bundl); + } else { + for_each_sg(sgl, sg, tot_dsds, i) { + dma_addr_t sle_dma; + + /* Allocate additional continuation packets? */ + if (avail_dsds == 0) { + avail_dsds = (used_dsds > QLA_DSDS_PER_IOCB) ? + QLA_DSDS_PER_IOCB : used_dsds; + dsd_list_len = (avail_dsds + 1) * 12; + used_dsds -= avail_dsds; + + /* allocate tracking DS */ + dsd_ptr = kzalloc(sizeof(*dsd_ptr), GFP_ATOMIC); + if (!dsd_ptr) { + ql_dbg(ql_dbg_tgt + ql_dbg_verbose, + vha, 0xe027, + "%s: failed alloc dsd_dma...\n", + __func__); + return 1; + } + + /* allocate new list */ + dsd_ptr->dsd_addr = + dma_pool_alloc(ha->dl_dma_pool, GFP_ATOMIC, + &dsd_ptr->dsd_list_dma); + if (!dsd_ptr->dsd_addr) { + /* need to cleanup only this dsd_ptr */ + /* rest will be done by sp_free_dma() */ + kfree(dsd_ptr); + return 1; + } + + if (sp) { + list_add_tail(&dsd_ptr->list, + &difctx->dsd_list); + sp->flags |= SRB_CRC_CTX_DSD_VALID; + } else { + list_add_tail(&dsd_ptr->list, + &difctx->dsd_list); + tc->ctx_dsd_alloced = 1; + } + + /* add new list to cmd iocb or last list */ + *cur_dsd++ = + cpu_to_le32(LSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = + cpu_to_le32(MSD(dsd_ptr->dsd_list_dma)); + *cur_dsd++ = dsd_list_len; + cur_dsd = dsd_ptr->dsd_addr; + } + sle_dma = sg_dma_address(sg); + *cur_dsd++ = cpu_to_le32(LSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(MSD(sle_dma)); + *cur_dsd++ = cpu_to_le32(sg_dma_len(sg)); + avail_dsds--; + } } /* Null termination */ *cur_dsd++ = 0; @@ -1187,7 +1395,6 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, *cur_dsd++ = 0; return 0; } - /** * qla24xx_build_scsi_crc_2_iocbs() - Build IOCB command utilizing Command * Type 6 IOCB types. @@ -1195,8 +1402,8 @@ qla24xx_walk_and_build_prot_sglist(struct qla_hw_data *ha, srb_t *sp, * @sp: SRB command to process * @cmd_pkt: Command type 3 IOCB * @tot_dsds: Total number of segments to transfer - * @tot_prot_dsds: - * @fw_prot_opts: + * @tot_prot_dsds: Total number of segments with protection information + * @fw_prot_opts: Protection options to be passed to firmware */ inline int qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt, @@ -1416,21 +1623,19 @@ qla24xx_start_scsi(srb_t *sp) uint16_t req_cnt; uint16_t tot_dsds; struct req_que *req = NULL; - struct rsp_que *rsp = NULL; struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; /* Setup device pointers. */ req = vha->req; - rsp = req->rsp; /* So we know we haven't pci_map'ed anything yet */ tot_dsds = 0; /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) return QLA_FUNCTION_FAILED; vha->marker_needed = 0; @@ -1583,7 +1788,7 @@ qla24xx_dif_start_scsi(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + if (qla2x00_marker(vha, ha->base_qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) return QLA_FUNCTION_FAILED; vha->marker_needed = 0; @@ -1754,7 +1959,6 @@ qla2xxx_start_scsi_mq(srb_t *sp) uint16_t req_cnt; uint16_t tot_dsds; struct req_que *req = NULL; - struct rsp_que *rsp = NULL; struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct scsi_qla_host *vha = sp->fcport->vha; struct qla_hw_data *ha = vha->hw; @@ -1764,7 +1968,6 @@ qla2xxx_start_scsi_mq(srb_t *sp) spin_lock_irqsave(&qpair->qp_lock, flags); /* Setup qpair pointers */ - rsp = qpair->rsp; req = qpair->req; /* So we know we haven't pci_map'ed anything yet */ @@ -1772,7 +1975,7 @@ qla2xxx_start_scsi_mq(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (__qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; @@ -1940,7 +2143,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (__qla2x00_marker(vha, req, rsp, 0, 0, MK_SYNC_ALL) != + if (__qla2x00_marker(vha, qpair, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; @@ -2208,8 +2411,11 @@ qla24xx_prli_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); - if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) + if (lio->u.logio.flags & SRB_LOGIN_NVME_PRLI) { logio->control_flags |= LCF_NVME_PRLI; + if (sp->vha->flags.nvme_first_burst) + logio->io_parameter[0] = NVME_PRLI_SP_FIRST_BURST; + } logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); logio->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -2224,12 +2430,15 @@ qla24xx_login_iocb(srb_t *sp, struct logio_entry_24xx *logio) struct srb_iocb *lio = &sp->u.iocb_cmd; logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; - logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); - - if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) - logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); - if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) - logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); + if (lio->u.logio.flags & SRB_LOGIN_PRLI_ONLY) { + logio->control_flags = cpu_to_le16(LCF_COMMAND_PRLI); + } else { + logio->control_flags = cpu_to_le16(LCF_COMMAND_PLOGI); + if (lio->u.logio.flags & SRB_LOGIN_COND_PLOGI) + logio->control_flags |= cpu_to_le16(LCF_COND_PLOGI); + if (lio->u.logio.flags & SRB_LOGIN_SKIP_PRLI) + logio->control_flags |= cpu_to_le16(LCF_SKIP_PRLI); + } logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); logio->port_id[0] = sp->fcport->d_id.b.al_pa; logio->port_id[1] = sp->fcport->d_id.b.area; @@ -2267,8 +2476,7 @@ qla24xx_logout_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->entry_type = LOGINOUT_PORT_IOCB_TYPE; logio->control_flags = cpu_to_le16(LCF_COMMAND_LOGO|LCF_IMPL_LOGO); - if (!sp->fcport->se_sess || - !sp->fcport->keep_nport_handle) + if (!sp->fcport->keep_nport_handle) logio->control_flags |= cpu_to_le16(LCF_FREE_NPORT); logio->nport_handle = cpu_to_le16(sp->fcport->loop_id); logio->port_id[0] = sp->fcport->d_id.b.al_pa; @@ -2446,6 +2654,7 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, sp->fcport = fcport; elsio->timeout = qla2x00_els_dcmd_iocb_timeout; qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); + init_completion(&sp->u.iocb_cmd.u.els_logo.comp); sp->done = qla2x00_els_dcmd_sp_done; sp->free = qla2x00_els_dcmd_sp_free; @@ -2493,7 +2702,6 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { scsi_qla_host_t *vha = sp->vha; struct srb_iocb *elsio = &sp->u.iocb_cmd; - uint32_t dsd_len = 24; els_iocb->entry_type = ELS_IOCB_TYPE; els_iocb->entry_count = 1; @@ -2516,20 +2724,21 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->control_flags = 0; if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { - els_iocb->tx_byte_count = sizeof(struct els_plogi_payload); + els_iocb->tx_byte_count = els_iocb->tx_len = + sizeof(struct els_plogi_payload); els_iocb->tx_address[0] = cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma)); els_iocb->tx_address[1] = cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma)); - els_iocb->tx_len = dsd_len; els_iocb->rx_dsd_count = 1; - els_iocb->rx_byte_count = sizeof(struct els_plogi_payload); + els_iocb->rx_byte_count = els_iocb->rx_len = + sizeof(struct els_plogi_payload); els_iocb->rx_address[0] = cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma)); els_iocb->rx_address[1] = cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma)); - els_iocb->rx_len = dsd_len; + ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI ELS IOCB:\n"); ql_dump_buffer(ql_log_info, vha, 0x0109, @@ -2551,26 +2760,6 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) sp->vha->qla_stats.control_requests++; } -static void -qla2x00_els_dcmd2_sp_free(void *data) -{ - srb_t *sp = data; - struct srb_iocb *elsio = &sp->u.iocb_cmd; - - if (elsio->u.els_plogi.els_plogi_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE, - elsio->u.els_plogi.els_plogi_pyld, - elsio->u.els_plogi.els_plogi_pyld_dma); - - if (elsio->u.els_plogi.els_resp_pyld) - dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE, - elsio->u.els_plogi.els_resp_pyld, - elsio->u.els_plogi.els_resp_pyld_dma); - - del_timer(&elsio->timer); - qla2x00_rel_sp(sp); -} - static void qla2x00_els_dcmd2_iocb_timeout(void *data) { @@ -2578,7 +2767,6 @@ qla2x00_els_dcmd2_iocb_timeout(void *data) fc_port_t *fcport = sp->fcport; struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; - struct srb_iocb *lio = &sp->u.iocb_cmd; unsigned long flags = 0; int res; @@ -2594,7 +2782,7 @@ qla2x00_els_dcmd2_iocb_timeout(void *data) (res == QLA_SUCCESS) ? "successful" : "failed"); spin_unlock_irqrestore(&ha->hardware_lock, flags); - complete(&lio->u.els_plogi.comp); + sp->done(sp, QLA_FUNCTION_TIMEOUT); } static void @@ -2604,24 +2792,61 @@ qla2x00_els_dcmd2_sp_done(void *ptr, int res) fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; + struct event_arg ea; + struct qla_work_evt *e; - ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3072, - "%s ELS hdl=%x, portid=%06x done %8phC\n", - sp->name, sp->handle, fcport->d_id.b24, fcport->port_name); + ql_dbg(ql_dbg_disc, vha, 0x3072, + "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n", + sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name); - complete(&lio->u.els_plogi.comp); + fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); + del_timer(&sp->u.iocb_cmd.timer); + + if (sp->flags & SRB_WAKEUP_ON_COMP) + complete(&lio->u.els_plogi.comp); + else { + if (res) { + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } else { + memset(&ea, 0, sizeof(ea)); + ea.fcport = fcport; + ea.rc = res; + ea.event = FCME_ELS_PLOGI_DONE; + qla2x00_fcport_event_handler(vha, &ea); + } + + e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); + if (!e) { + struct srb_iocb *elsio = &sp->u.iocb_cmd; + + if (elsio->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.tx_size, + elsio->u.els_plogi.els_plogi_pyld, + elsio->u.els_plogi.els_plogi_pyld_dma); + + if (elsio->u.els_plogi.els_resp_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.rx_size, + elsio->u.els_plogi.els_resp_pyld, + elsio->u.els_plogi.els_resp_pyld_dma); + sp->free(sp); + return; + } + e->u.iosb.sp = sp; + qla2x00_post_work(vha, e); + } } int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, - fc_port_t *fcport, port_id_t remote_did) + fc_port_t *fcport, bool wait) { srb_t *sp; struct srb_iocb *elsio = NULL; struct qla_hw_data *ha = vha->hw; int rval = QLA_SUCCESS; void *ptr, *resp_ptr; - dma_addr_t ptr_dma; /* Alloc SRB structure */ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); @@ -2632,10 +2857,6 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, } elsio = &sp->u.iocb_cmd; - fcport->d_id.b.domain = remote_did.b.domain; - fcport->d_id.b.area = remote_did.b.area; - fcport->d_id.b.al_pa = remote_did.b.al_pa; - ql_dbg(ql_dbg_io, vha, 0x3073, "Enter: PLOGI portid=%06x\n", fcport->d_id.b24); @@ -2646,15 +2867,17 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; init_completion(&elsio->u.els_plogi.comp); - qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); + if (wait) + sp->flags = SRB_WAKEUP_ON_COMP; + + qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT + 2); sp->done = qla2x00_els_dcmd2_sp_done; - sp->free = qla2x00_els_dcmd2_sp_free; + elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; ptr = elsio->u.els_plogi.els_plogi_pyld = dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); - ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma; if (!elsio->u.els_plogi.els_plogi_pyld) { rval = QLA_FUNCTION_FAILED; @@ -2674,33 +2897,52 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, memset(ptr, 0, sizeof(struct els_plogi_payload)); memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); + memcpy(elsio->u.els_plogi.els_plogi_pyld->data, + &ha->plogi_els_payld.data, + sizeof(elsio->u.els_plogi.els_plogi_pyld->data)); + elsio->u.els_plogi.els_cmd = els_opcode; elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode; - qla24xx_get_port_login_templ(vha, ptr_dma + 4, - &elsio->u.els_plogi.els_plogi_pyld->data[0], - sizeof(struct els_plogi_payload)); - ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); - ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x0109, + ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109, (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { rval = QLA_FUNCTION_FAILED; - goto out; + } else { + ql_dbg(ql_dbg_disc, vha, 0x3074, + "%s PLOGI sent, hdl=%x, loopid=%x, to port_id %06x from port_id %06x\n", + sp->name, sp->handle, fcport->loop_id, + fcport->d_id.b24, vha->d_id.b24); } - ql_dbg(ql_dbg_io, vha, 0x3074, - "%s PLOGI sent, hdl=%x, loopid=%x, portid=%06x\n", - sp->name, sp->handle, fcport->loop_id, fcport->d_id.b24); + if (wait) { + wait_for_completion(&elsio->u.els_plogi.comp); - wait_for_completion(&elsio->u.els_plogi.comp); - - if (elsio->u.els_plogi.comp_status != CS_COMPLETE) - rval = QLA_FUNCTION_FAILED; + if (elsio->u.els_plogi.comp_status != CS_COMPLETE) + rval = QLA_FUNCTION_FAILED; + } else { + goto done; + } out: + fcport->flags &= ~(FCF_ASYNC_SENT); + if (elsio->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.tx_size, + elsio->u.els_plogi.els_plogi_pyld, + elsio->u.els_plogi.els_plogi_pyld_dma); + + if (elsio->u.els_plogi.els_resp_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.rx_size, + elsio->u.els_plogi.els_resp_pyld, + elsio->u.els_plogi.els_resp_pyld_dma); + sp->free(sp); +done: return rval; } @@ -2955,8 +3197,8 @@ qla82xx_start_scsi(srb_t *sp) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, - rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { + if (qla2x00_marker(vha, ha->base_qpair, + 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x300c, "qla2x00_marker failed for cmd=%p.\n", cmd); return QLA_FUNCTION_FAILED; @@ -3258,19 +3500,21 @@ qla24xx_abort_iocb(srb_t *sp, struct abort_entry_24xx *abt_iocb) { struct srb_iocb *aio = &sp->u.iocb_cmd; scsi_qla_host_t *vha = sp->vha; - struct req_que *req = vha->req; + struct req_que *req = sp->qpair->req; memset(abt_iocb, 0, sizeof(struct abort_entry_24xx)); abt_iocb->entry_type = ABORT_IOCB_TYPE; abt_iocb->entry_count = 1; abt_iocb->handle = cpu_to_le32(MAKE_HANDLE(req->id, sp->handle)); - abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + if (sp->fcport) { + abt_iocb->nport_handle = cpu_to_le16(sp->fcport->loop_id); + abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; + abt_iocb->port_id[1] = sp->fcport->d_id.b.area; + abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; + } abt_iocb->handle_to_abort = cpu_to_le32(MAKE_HANDLE(aio->u.abt.req_que_no, aio->u.abt.cmd_hndl)); - abt_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; - abt_iocb->port_id[1] = sp->fcport->d_id.b.area; - abt_iocb->port_id[2] = sp->fcport->d_id.b.domain; abt_iocb->vp_index = vha->vp_idx; abt_iocb->req_que_no = cpu_to_le16(aio->u.abt.req_que_no); /* Send the command to the firmware */ @@ -3396,22 +3640,22 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) int qla2x00_start_sp(srb_t *sp) { - int rval; + int rval = QLA_SUCCESS; scsi_qla_host_t *vha = sp->vha; struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qp = sp->qpair; void *pkt; unsigned long flags; - rval = QLA_FUNCTION_FAILED; - spin_lock_irqsave(&ha->hardware_lock, flags); - pkt = qla2x00_alloc_iocbs(vha, sp); + spin_lock_irqsave(qp->qp_lock_ptr, flags); + pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); if (!pkt) { + rval = EAGAIN; ql_log(ql_log_warn, vha, 0x700c, "qla2x00_alloc_iocbs failed.\n"); goto done; } - rval = QLA_SUCCESS; switch (sp->type) { case SRB_LOGIN_CMD: IS_FWI2_CAPABLE(ha) ? @@ -3482,9 +3726,9 @@ qla2x00_start_sp(srb_t *sp) } wmb(); - qla2x00_start_iocbs(vha, ha->req_q_map[0]); + qla2x00_start_iocbs(vha, qp->req); done: - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qp->qp_lock_ptr, flags); return rval; } @@ -3607,8 +3851,8 @@ qla2x00_start_bidir(srb_t *sp, struct scsi_qla_host *vha, uint32_t tot_dsds) /* Send marker if required */ if (vha->marker_needed != 0) { - if (qla2x00_marker(vha, req, - rsp, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) + if (qla2x00_marker(vha, ha->base_qpair, + 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) return EXT_STATUS_MAILBOX; vha->marker_needed = 0; } diff --git a/qla2x00t-32gbit/qla_isr.c b/qla2x00t-32gbit/qla_isr.c index 7756106d4..69bbea923 100644 --- a/qla2x00t-32gbit/qla_isr.c +++ b/qla2x00t-32gbit/qla_isr.c @@ -25,7 +25,7 @@ static int qla2x00_error_entry(scsi_qla_host_t *, struct rsp_que *, /** * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200. - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. @@ -144,7 +144,7 @@ qla2x00_check_reg16_for_disconnect(scsi_qla_host_t *vha, uint16_t reg) /** * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. @@ -834,7 +834,8 @@ skip_rio: * Restore for Physical Port only */ if (!vha->vp_idx) { - if (ha->flags.fawwpn_enabled) { + if (ha->flags.fawwpn_enabled && + (ha->current_topology == ISP_CFG_F)) { void *wwpn = ha->init_cb->port_name; memcpy(vha->port_name, wwpn, WWN_SIZE); fc_host_port_name(vha->host) = @@ -911,7 +912,8 @@ skip_rio: if (!atomic_read(&vha->loop_down_timer)) atomic_set(&vha->loop_down_timer, LOOP_DOWN_TIME); - qla2x00_mark_all_devices_lost(vha, 1); + if (!N2N_TOPO(ha)) + qla2x00_mark_all_devices_lost(vha, 1); } if (vha->vp_idx) { @@ -1713,6 +1715,15 @@ qla24xx_logio_entry(scsi_qla_host_t *vha, struct req_que *req, vha->hw->exch_starvation = 0; data[0] = MBS_COMMAND_COMPLETE; + + if (sp->type == SRB_PRLI_CMD) { + lio->u.logio.iop[0] = + le32_to_cpu(logio->io_parameter[0]); + lio->u.logio.iop[1] = + le32_to_cpu(logio->io_parameter[1]); + goto logio_done; + } + if (sp->type != SRB_LOGIN_CMD) goto logio_done; @@ -1849,11 +1860,12 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk; uint16_t state_flags; struct nvmefc_fcp_req *fd; - uint16_t ret = 0; + uint16_t ret = QLA_SUCCESS; + uint16_t comp_status = le16_to_cpu(sts->comp_status); iocb = &sp->u.iocb_cmd; fcport = sp->fcport; - iocb->u.nvme.comp_status = le16_to_cpu(sts->comp_status); + iocb->u.nvme.comp_status = comp_status; state_flags = le16_to_cpu(sts->state_flags); fd = iocb->u.nvme.desc; @@ -1891,28 +1903,35 @@ static void qla24xx_nvme_iocb_entry(scsi_qla_host_t *vha, struct req_que *req, fd->transferred_length = fd->payload_length - le32_to_cpu(sts->residual_len); - switch (le16_to_cpu(sts->comp_status)) { + if (unlikely(comp_status != CS_COMPLETE)) + ql_log(ql_log_warn, fcport->vha, 0x5060, + "NVME-%s ERR Handling - hdl=%x status(%x) tr_len:%x resid=%x ox_id=%x\n", + sp->name, sp->handle, comp_status, + fd->transferred_length, le32_to_cpu(sts->residual_len), + sts->ox_id); + + /* + * If transport error then Failure (HBA rejects request) + * otherwise transport will handle. + */ + switch (comp_status) { case CS_COMPLETE: - ret = QLA_SUCCESS; break; - case CS_ABORTED: + case CS_RESET: case CS_PORT_UNAVAILABLE: case CS_PORT_LOGGED_OUT: + fcport->nvme_flag |= NVME_FLAG_RESETTING; + /* fall through */ + case CS_ABORTED: case CS_PORT_BUSY: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s ERR Handling - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); fd->transferred_length = 0; iocb->u.nvme.rsp_pyld_len = 0; ret = QLA_ABORTED; break; + case CS_DATA_UNDERRUN: + break; default: - ql_log(ql_log_warn, fcport->vha, 0x5060, - "NVME-%s error - hdl=%x completion status(%x) resid=%x ox_id=%x\n", - sp->name, sp->handle, sts->comp_status, - le32_to_cpu(sts->residual_len), sts->ox_id); ret = QLA_FUNCTION_FAILED; break; } @@ -2716,6 +2735,17 @@ check_scsi_status: cp->device->vendor); break; + case CS_DMA: + ql_log(ql_log_info, fcport->vha, 0x3022, + "CS_DMA error: 0x%x-0x%x (0x%x) nexus=%ld:%d:%llu portid=%06x oxid=0x%x cdb=%10phN len=0x%x rsp_info=0x%x resid=0x%x fw_resid=0x%x sp=%p cp=%p.\n", + comp_status, scsi_status, res, vha->host_no, + cp->device->id, cp->device->lun, fcport->d_id.b24, + ox_id, cp->cmnd, scsi_bufflen(cp), rsp_info_len, + resid_len, fw_resid_len, sp, cp); + ql_dump_buffer(ql_dbg_tgt + ql_dbg_verbose, vha, 0xe0ee, + pkt, sizeof(*sts24)); + res = DID_ERROR << 16; + break; default: res = DID_ERROR << 16; break; @@ -2836,6 +2866,7 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) case ELS_IOCB_TYPE: case ABORT_IOCB_TYPE: case MBX_IOCB_TYPE: + default: sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { sp->done(sp, res); @@ -2846,7 +2877,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) case ABTS_RESP_24XX: case CTIO_TYPE7: case CTIO_CRC2: - default: return 1; } fatal: @@ -3100,7 +3130,7 @@ done: /** * qla24xx_intr_handler() - Process interrupts for the ISP23xx and ISP24xx. - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. @@ -3120,6 +3150,7 @@ qla24xx_intr_handler(int irq, void *dev_id) uint16_t mb[8]; struct rsp_que *rsp; unsigned long flags; + bool process_atio = false; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -3180,22 +3211,13 @@ qla24xx_intr_handler(int irq, void *dev_id) qla24xx_process_response_queue(vha, rsp); break; case INTR_ATIO_QUE_UPDATE_27XX: - case INTR_ATIO_QUE_UPDATE:{ - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); + case INTR_ATIO_QUE_UPDATE: + process_atio = true; break; - } - case INTR_ATIO_RSP_QUE_UPDATE: { - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); - + case INTR_ATIO_RSP_QUE_UPDATE: + process_atio = true; qla24xx_process_response_queue(vha, rsp); break; - } default: ql_dbg(ql_dbg_async, vha, 0x504f, "Unrecognized interrupt type (%d).\n", stat * 0xff); @@ -3209,6 +3231,12 @@ qla24xx_intr_handler(int irq, void *dev_id) qla2x00_handle_mbx_completion(ha, status); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (process_atio) { + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); + } + return IRQ_HANDLED; } @@ -3255,6 +3283,7 @@ qla24xx_msix_default(int irq, void *dev_id) uint32_t hccr; uint16_t mb[8]; unsigned long flags; + bool process_atio = false; rsp = (struct rsp_que *) dev_id; if (!rsp) { @@ -3311,22 +3340,13 @@ qla24xx_msix_default(int irq, void *dev_id) qla24xx_process_response_queue(vha, rsp); break; case INTR_ATIO_QUE_UPDATE_27XX: - case INTR_ATIO_QUE_UPDATE:{ - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); + case INTR_ATIO_QUE_UPDATE: + process_atio = true; break; - } - case INTR_ATIO_RSP_QUE_UPDATE: { - unsigned long flags2; - spin_lock_irqsave(&ha->tgt.atio_lock, flags2); - qlt_24xx_process_atio_queue(vha, 1); - spin_unlock_irqrestore(&ha->tgt.atio_lock, flags2); - + case INTR_ATIO_RSP_QUE_UPDATE: + process_atio = true; qla24xx_process_response_queue(vha, rsp); break; - } default: ql_dbg(ql_dbg_async, vha, 0x5051, "Unrecognized interrupt type (%d).\n", stat & 0xff); @@ -3337,6 +3357,12 @@ qla24xx_msix_default(int irq, void *dev_id) qla2x00_handle_mbx_completion(ha, status); spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (process_atio) { + spin_lock_irqsave(&ha->tgt.atio_lock, flags); + qlt_24xx_process_atio_queue(vha, 0); + spin_unlock_irqrestore(&ha->tgt.atio_lock, flags); + } + return IRQ_HANDLED; } @@ -3405,7 +3431,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) min_vecs++; } - if (USER_CTRL_IRQ(ha)) { + if (USER_CTRL_IRQ(ha) || !ha->mqiobase) { /* user wants to control IRQ setting for target mode */ ret = pci_alloc_irq_vectors(ha->pdev, min_vecs, ha->msix_count, PCI_IRQ_MSIX); @@ -3441,6 +3467,7 @@ qla24xx_enable_msix(struct qla_hw_data *ha, struct rsp_que *rsp) "Adjusted Max no of queues pairs: %d.\n", ha->max_qpairs); } } + vha->irq_offset = desc.pre_vectors; ha->msix_entries = kcalloc(ha->msix_count, sizeof(struct qla_msix_entry), GFP_KERNEL); diff --git a/qla2x00t-32gbit/qla_mbx.c b/qla2x00t-32gbit/qla_mbx.c index f301621e3..5400696e1 100644 --- a/qla2x00t-32gbit/qla_mbx.c +++ b/qla2x00t-32gbit/qla_mbx.c @@ -59,6 +59,8 @@ static struct rom_cmd { { MBC_IOCB_COMMAND_A64 }, { MBC_GET_ADAPTER_LOOP_ID }, { MBC_READ_SFP }, + { MBC_GET_RNID_PARAMS }, + { MBC_GET_SET_ZIO_THRESHOLD }, }; static int is_rom_cmd(uint16_t cmd) @@ -110,6 +112,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) unsigned long wait_time; struct qla_hw_data *ha = vha->hw; scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev); + u32 chip_reset; ql_dbg(ql_dbg_mbx, vha, 0x1000, "Entered %s.\n", __func__); @@ -140,7 +143,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) rval = QLA_SUCCESS; abort_active = test_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); - + chip_reset = ha->chip_reset; if (ha->flags.pci_channel_io_perm_failure) { ql_log(ql_log_warn, vha, 0x1003, @@ -167,6 +170,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) return QLA_FUNCTION_TIMEOUT; } + atomic_inc(&ha->num_pend_mbx_stage1); /* * Wait for active mailbox commands to finish by waiting at most tov * seconds. This is to serialize actual issuing of mailbox cmds during @@ -177,10 +181,16 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) ql_log(ql_log_warn, vha, 0xd035, "Cmd access timeout, cmd=0x%x, Exiting.\n", mcp->mb[0]); + atomic_dec(&ha->num_pend_mbx_stage1); return QLA_FUNCTION_TIMEOUT; } + atomic_dec(&ha->num_pend_mbx_stage1); + if (ha->flags.purge_mbox || chip_reset != ha->chip_reset) { + rval = QLA_ABORTED; + goto premature_exit; + } + - ha->flags.mbox_busy = 1; /* Save mailbox command for debug */ ha->mcp = mcp; @@ -189,6 +199,14 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) spin_lock_irqsave(&ha->hardware_lock, flags); + if (ha->flags.purge_mbox || chip_reset != ha->chip_reset || + ha->flags.mbox_busy) { + rval = QLA_ABORTED; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + goto premature_exit; + } + ha->flags.mbox_busy = 1; + /* Load mailbox registers. */ if (IS_P3P_TYPE(ha)) optr = (uint16_t __iomem *)®->isp82.mailbox_in[0]; @@ -231,16 +249,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "jiffies=%lx.\n", jiffies); /* Wait for mbx cmd completion until timeout */ - + atomic_inc(&ha->num_pend_mbx_stage2); if ((!abort_active && io_lock_on) || IS_NOPOLLING_TYPE(ha)) { set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); if (IS_P3P_TYPE(ha)) { if (RD_REG_DWORD(®->isp82.hint) & HINT_MBX_INT_PENDING) { + ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->flags.mbox_busy = 0; + + atomic_dec(&ha->num_pend_mbx_stage2); ql_dbg(ql_dbg_mbx, vha, 0x1010, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -254,14 +274,37 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) spin_unlock_irqrestore(&ha->hardware_lock, flags); wait_time = jiffies; + atomic_inc(&ha->num_pend_mbx_stage3); if (!wait_for_completion_timeout(&ha->mbx_intr_comp, mcp->tov * HZ)) { + if (chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); + atomic_dec(&ha->num_pend_mbx_stage2); + atomic_dec(&ha->num_pend_mbx_stage3); + rval = QLA_ABORTED; + goto premature_exit; + } ql_dbg(ql_dbg_mbx, vha, 0x117a, "cmd=%x Timeout.\n", command); spin_lock_irqsave(&ha->hardware_lock, flags); clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags); spin_unlock_irqrestore(&ha->hardware_lock, flags); + + } else if (ha->flags.purge_mbox || + chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + atomic_dec(&ha->num_pend_mbx_stage2); + atomic_dec(&ha->num_pend_mbx_stage3); + rval = QLA_ABORTED; + goto premature_exit; } + atomic_dec(&ha->num_pend_mbx_stage3); + if (time_after(jiffies, wait_time + 5 * HZ)) ql_log(ql_log_warn, vha, 0x1015, "cmd=0x%x, waited %d msecs\n", command, jiffies_to_msecs(jiffies - wait_time)); @@ -272,9 +315,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) if (IS_P3P_TYPE(ha)) { if (RD_REG_DWORD(®->isp82.hint) & HINT_MBX_INT_PENDING) { + ha->flags.mbox_busy = 0; spin_unlock_irqrestore(&ha->hardware_lock, flags); - ha->flags.mbox_busy = 0; + atomic_dec(&ha->num_pend_mbx_stage2); ql_dbg(ql_dbg_mbx, vha, 0x1012, "Pending mailbox timeout, exiting.\n"); rval = QLA_FUNCTION_TIMEOUT; @@ -289,6 +333,17 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */ while (!ha->flags.mbox_int) { + if (ha->flags.purge_mbox || + chip_reset != ha->chip_reset) { + spin_lock_irqsave(&ha->hardware_lock, flags); + ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); + atomic_dec(&ha->num_pend_mbx_stage2); + rval = QLA_ABORTED; + goto premature_exit; + } + if (time_after(jiffies, wait_time)) break; @@ -312,6 +367,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) "Waited %d sec.\n", (uint)((jiffies - (wait_time - (mcp->tov * HZ)))/HZ)); } + atomic_dec(&ha->num_pend_mbx_stage2); /* Check whether we timed out */ if (ha->flags.mbox_int) { @@ -325,7 +381,10 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags); if (IS_P3P_TYPE(ha) && ha->flags.isp82xx_fw_hung) { + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); + /* Setting Link-Down error */ mcp->mb[0] = MBS_LINK_DOWN_ERROR; ha->mcp = NULL; @@ -390,14 +449,18 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) /* Capture FW dump only, if PCI device active */ if (!pci_channel_offline(vha->hw->pdev)) { pci_read_config_word(ha->pdev, PCI_VENDOR_ID, &w); - if (w == 0xffff || ictrl == 0xffffffff) { + if (w == 0xffff || ictrl == 0xffffffff || + (chip_reset != ha->chip_reset)) { /* This is special case if there is unload * of driver happening and if PCI device go * into bad state due to PCI error condition * then only PCI ERR flag would be set. * we will do premature exit for above case. */ + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, + flags); rval = QLA_FUNCTION_TIMEOUT; goto premature_exit; } @@ -412,8 +475,9 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) rval = QLA_FUNCTION_TIMEOUT; } } - + spin_lock_irqsave(&ha->hardware_lock, flags); ha->flags.mbox_busy = 0; + spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Clean up */ ha->mcp = NULL; @@ -454,7 +518,7 @@ qla2x00_mailbox_command(scsi_qla_host_t *vha, mbx_cmd_t *mcp) set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); qla2xxx_wake_dpc(vha); } - } else if (!abort_active) { + } else if (current == ha->dpc_thread) { /* call abort directly since we are in the DPC thread */ ql_dbg(ql_dbg_mbx, vha, 0x101d, "Timeout, calling abort_isp.\n"); @@ -497,7 +561,11 @@ premature_exit: complete(&ha->mbx_cmd_comp); mbx_done: - if (rval) { + if (rval == QLA_ABORTED) { + ql_log(ql_log_info, vha, 0xd035, + "Chip Reset in progress. Purging Mbox cmd=0x%x.\n", + mcp->mb[0]); + } else if (rval) { if (ql2xextended_error_logging & (ql_dbg_disc|ql_dbg_mbx)) { pr_warn("%s [%s]-%04x:%ld: **** Failed", QL_MSGHDR, dev_name(&ha->pdev->dev), 0x1020+0x800, @@ -1041,7 +1109,12 @@ qla2x00_get_fw_version(scsi_qla_host_t *vha) * FW supports nvme and driver load parameter requested nvme. * BIT 26 of fw_attributes indicates NVMe support. */ - if ((ha->fw_attributes_h & 0x400) && ql2xnvmeenable) { + if ((ha->fw_attributes_h & + (FW_ATTR_H_NVME | FW_ATTR_H_NVME_UPDATED)) && + ql2xnvmeenable) { + if (ha->fw_attributes_h & FW_ATTR_H_NVME_FBURST) + vha->flags.nvme_first_burst = 1; + vha->flags.nvme_enabled = 1; ql_log(ql_log_info, vha, 0xd302, "%s: FC-NVMe is Enabled (0x%x)\n", @@ -1440,17 +1513,12 @@ qla2x00_abort_target(struct fc_port *fcport, uint64_t l, int tag) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *vha; - struct req_que *req; - struct rsp_que *rsp; - l = l; vha = fcport->vha; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x103e, "Entered %s.\n", __func__); - req = vha->hw->req_q_map[0]; - rsp = req->rsp; mcp->mb[0] = MBC_ABORT_TARGET; mcp->out_mb = MBX_9|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) { @@ -1473,7 +1541,7 @@ qla2x00_abort_target(struct fc_port *fcport, uint64_t l, int tag) } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, 0, + rval2 = qla2x00_marker(vha, vha->hw->base_qpair, fcport->loop_id, 0, MK_SYNC_ID); if (rval2 != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1040, @@ -1493,16 +1561,12 @@ qla2x00_lun_reset(struct fc_port *fcport, uint64_t l, int tag) mbx_cmd_t mc; mbx_cmd_t *mcp = &mc; scsi_qla_host_t *vha; - struct req_que *req; - struct rsp_que *rsp; vha = fcport->vha; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1042, "Entered %s.\n", __func__); - req = vha->hw->req_q_map[0]; - rsp = req->rsp; mcp->mb[0] = MBC_LUN_RESET; mcp->out_mb = MBX_9|MBX_3|MBX_2|MBX_1|MBX_0; if (HAS_EXTENDED_IDS(vha->hw)) @@ -1522,7 +1586,7 @@ qla2x00_lun_reset(struct fc_port *fcport, uint64_t l, int tag) } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, + rval2 = qla2x00_marker(vha, vha->hw->base_qpair, fcport->loop_id, l, MK_SYNC_ID_LUN); if (rval2 != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1044, @@ -2177,7 +2241,7 @@ qla2x00_lip_reset(scsi_qla_host_t *vha) mcp->out_mb = MBX_2|MBX_1|MBX_0; } else if (IS_FWI2_CAPABLE(vha->hw)) { mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = BIT_6; + mcp->mb[1] = BIT_4; mcp->mb[2] = 0; mcp->mb[3] = vha->hw->loop_reset_delay; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -2687,7 +2751,7 @@ qla2x00_full_login_lip(scsi_qla_host_t *vha) "Entered %s.\n", __func__); mcp->mb[0] = MBC_LIP_FULL_LOGIN; - mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_3 : 0; + mcp->mb[1] = IS_FWI2_CAPABLE(vha->hw) ? BIT_4 : 0; mcp->mb[2] = 0; mcp->mb[3] = 0; mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0; @@ -3026,22 +3090,25 @@ qla24xx_abort_command(srb_t *sp) struct scsi_qla_host *vha = fcport->vha; struct qla_hw_data *ha = vha->hw; struct req_que *req = vha->req; + struct qla_qpair *qpair = sp->qpair; ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x108c, "Entered %s.\n", __func__); if (vha->flags.qpairs_available && sp->qpair) req = sp->qpair->req; + else + return QLA_FUNCTION_FAILED; if (ql2xasynctmfenable) return qla24xx_async_abort_command(sp); - spin_lock_irqsave(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); for (handle = 1; handle < req->num_outstanding_cmds; handle++) { if (req->outstanding_cmds[handle] == sp) break; } - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); if (handle == req->num_outstanding_cmds) { /* Command not found. */ return QLA_FUNCTION_FAILED; @@ -3111,7 +3178,6 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, scsi_qla_host_t *vha; struct qla_hw_data *ha; struct req_que *req; - struct rsp_que *rsp; struct qla_qpair *qpair; vha = fcport->vha; @@ -3124,10 +3190,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, if (vha->vp_idx && vha->qpair) { /* NPIV port */ qpair = vha->qpair; - rsp = qpair->rsp; req = qpair->req; - } else { - rsp = req->rsp; } tsk = dma_pool_zalloc(ha->s_dma_pool, GFP_KERNEL, &tsk_dma); @@ -3184,7 +3247,7 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport, } /* Issue marker IOCB. */ - rval2 = qla2x00_marker(vha, req, rsp, fcport->loop_id, l, + rval2 = qla2x00_marker(vha, ha->base_qpair, fcport->loop_id, l, type == TCF_LUN_RESET ? MK_SYNC_ID_LUN: MK_SYNC_ID); if (rval2 != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1099, @@ -3405,9 +3468,9 @@ qla8044_read_serdes_word(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data) /** * qla2x00_set_serdes_params() - * @vha: HA context - * @sw_em_1g: - * @sw_em_2g: - * @sw_em_4g: + * @sw_em_1g: serial link options + * @sw_em_2g: serial link options + * @sw_em_4g: serial link options * * Returns */ @@ -3794,30 +3857,68 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, "Format 1: WWPN %8phC.\n", vha->port_name); - /* N2N. direct connect */ - if (IS_QLA27XX(ha) && - ((rptid_entry->u.f1.flags>>1) & 0x7) == 2) { - /* if our portname is higher then initiate N2N login */ - if (wwn_to_u64(vha->port_name) > - wwn_to_u64(rptid_entry->u.f1.port_name)) { - // ??? qlt_update_host_map(vha, id); - vha->n2n_id = 0x1; - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Setting n2n_update_needed for id %d\n", - vha->n2n_id); + switch (rptid_entry->u.f1.flags & TOPO_MASK) { + case TOPO_N2N: + ha->current_topology = ISP_CFG_N; + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + fcport = qla2x00_find_fcport_by_wwpn(vha, + rptid_entry->u.f1.port_name, 1); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + + if (fcport) { + fcport->plogi_nack_done_deadline = jiffies + HZ; + fcport->dm_login_expire = jiffies + 3*HZ; + fcport->scan_state = QLA_FCPORT_FOUND; + switch (fcport->disc_state) { + case DSC_DELETED: + set_bit(RELOGIN_NEEDED, + &vha->dpc_flags); + break; + case DSC_DELETE_PEND: + break; + default: + qlt_schedule_sess_for_deletion(fcport); + break; + } } else { - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Remote login - Waiting for WWPN %8phC.\n", - rptid_entry->u.f1.port_name); + id.b24 = 0; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(rptid_entry->u.f1.port_name)) { + vha->d_id.b24 = 0; + vha->d_id.b.al_pa = 1; + ha->flags.n2n_bigger = 1; + + id.b.al_pa = 2; + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: assign local id %x remote id %x\n", + vha->d_id.b24, id.b24); + } else { + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote login - Waiting for WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + ha->flags.n2n_bigger = 0; + } + qla24xx_post_newsess_work(vha, &id, + rptid_entry->u.f1.port_name, + rptid_entry->u.f1.node_name, + NULL, + FC4_TYPE_UNKNOWN); } - memcpy(vha->n2n_port_name, rptid_entry->u.f1.port_name, - WWN_SIZE); + /* if our portname is higher then initiate N2N login */ + set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); ha->flags.n2n_ae = 1; return; + break; + case TOPO_FL: + ha->current_topology = ISP_CFG_FL; + break; + case TOPO_F: + ha->current_topology = ISP_CFG_F; + break; + default: + break; } ha->flags.gpsc_supported = 1; @@ -3906,30 +4007,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, rptid_entry->u.f2.port_name, 1); if (fcport) { + fcport->login_retry = vha->hw->login_retry_count; fcport->plogi_nack_done_deadline = jiffies + HZ; fcport->scan_state = QLA_FCPORT_FOUND; - switch (fcport->disc_state) { - case DSC_DELETED: - ql_dbg(ql_dbg_disc, vha, 0x210d, - "%s %d %8phC login\n", - __func__, __LINE__, fcport->port_name); - qla24xx_fcport_handle_login(vha, fcport); - break; - case DSC_DELETE_PEND: - break; - default: - qlt_schedule_sess_for_deletion(fcport); - break; - } - } else { - id.b.al_pa = rptid_entry->u.f2.remote_nport_id[0]; - id.b.area = rptid_entry->u.f2.remote_nport_id[1]; - id.b.domain = rptid_entry->u.f2.remote_nport_id[2]; - qla24xx_post_newsess_work(vha, &id, - rptid_entry->u.f2.port_name, - rptid_entry->u.f2.node_name, - NULL, - FC4_TYPE_UNKNOWN); } } } @@ -4660,7 +4740,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, "Done %s.\n", __func__); bp = (uint32_t *) buf; for (i = 0; i < (bufsiz-4)/4; i++, bp++) - *bp = cpu_to_be32(*bp); + *bp = le32_to_cpu(*bp); } return rval; @@ -5158,6 +5238,66 @@ qla81xx_write_mpi_register(scsi_qla_host_t *vha, uint16_t *mb) return rval; } +/* Set the specified data rate */ +int +qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode) +{ + int rval; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + struct qla_hw_data *ha = vha->hw; + uint16_t val; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1106, + "Entered %s speed:0x%x mode:0x%x.\n", __func__, ha->set_data_rate, + mode); + + if (!IS_FWI2_CAPABLE(ha)) + return QLA_FUNCTION_FAILED; + + memset(mcp, 0, sizeof(*mcp)); + switch (ha->set_data_rate) { + case PORT_SPEED_AUTO: + case PORT_SPEED_4GB: + case PORT_SPEED_8GB: + case PORT_SPEED_16GB: + case PORT_SPEED_32GB: + val = ha->set_data_rate; + break; + default: + ql_log(ql_log_warn, vha, 0x1199, + "Unrecognized speed setting:%d. Setting Autoneg\n", + ha->set_data_rate); + val = ha->set_data_rate = PORT_SPEED_AUTO; + break; + } + + mcp->mb[0] = MBC_DATA_RATE; + mcp->mb[1] = mode; + mcp->mb[2] = val; + + mcp->out_mb = MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_2|MBX_1|MBX_0; + if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) + mcp->in_mb |= MBX_4|MBX_3; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x1107, + "Failed=%x mb[0]=%x.\n", rval, mcp->mb[0]); + } else { + if (mcp->mb[1] != 0x7) + ql_dbg(ql_dbg_mbx, vha, 0x1179, + "Speed set:0x%x\n", mcp->mb[1]); + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1108, + "Done %s.\n", __func__); + } + + return rval; +} + int qla2x00_get_data_rate(scsi_qla_host_t *vha) { @@ -5173,7 +5313,7 @@ qla2x00_get_data_rate(scsi_qla_host_t *vha) return QLA_FUNCTION_FAILED; mcp->mb[0] = MBC_DATA_RATE; - mcp->mb[1] = 0; + mcp->mb[1] = QLA_GET_DATA_RATE; mcp->out_mb = MBX_1|MBX_0; mcp->in_mb = MBX_2|MBX_1|MBX_0; if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) @@ -6178,8 +6318,6 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->d_id.b.rsvd_1 = 0; if (fcport->fc4f_nvme) { - fcport->nvme_prli_service_param = - pd->prli_nvme_svc_param_word_3; fcport->port_type = FCT_NVME; } else { /* If not target must be initiator or unknown type. */ diff --git a/qla2x00t-32gbit/qla_mid.c b/qla2x00t-32gbit/qla_mid.c index aa727d07b..099d8e985 100644 --- a/qla2x00t-32gbit/qla_mid.c +++ b/qla2x00t-32gbit/qla_mid.c @@ -492,7 +492,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) "Couldn't allocate vp_id.\n"); goto create_vhost_failed; } - vha->mgmt_svr_loop_id = NPH_MGMT_SERVER; + vha->mgmt_svr_loop_id = qla2x00_reserve_mgmt_server_loop_id(vha); vha->dpc_flags = 0L; @@ -507,6 +507,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport) qla2x00_start_timer(vha, WATCH_INTERVAL); vha->req = base_vha->req; + vha->flags.nvme_enabled = base_vha->flags.nvme_enabled; host->can_queue = base_vha->req->length + 128; host->cmd_per_lun = 3; if (IS_T10_PI_CAPABLE(ha) && ql2xenabledif) diff --git a/qla2x00t-32gbit/qla_mr.c b/qla2x00t-32gbit/qla_mr.c index 521a51370..60f964c53 100644 --- a/qla2x00t-32gbit/qla_mr.c +++ b/qla2x00t-32gbit/qla_mr.c @@ -2212,7 +2212,7 @@ qlafx00_ioctl_iosb_entry(scsi_qla_host_t *vha, struct req_que *req, struct bsg_job *bsg_job; struct fc_bsg_reply *bsg_reply; struct srb_iocb *iocb_job; - int res; + int res = 0; struct qla_mt_iocb_rsp_fx00 fstatus; uint8_t *fw_sts_ptr; @@ -2624,7 +2624,7 @@ qlafx00_status_cont_entry(struct rsp_que *rsp, sts_cont_entry_t *pkt) * qlafx00_multistatus_entry() - Process Multi response queue entries. * @vha: SCSI driver HA context * @rsp: response queue - * @pkt: + * @pkt: received packet */ static void qlafx00_multistatus_entry(struct scsi_qla_host *vha, @@ -2681,12 +2681,10 @@ qlafx00_multistatus_entry(struct scsi_qla_host *vha, * @vha: SCSI driver HA context * @rsp: response queue * @pkt: Entry pointer - * @estatus: - * @etype: */ static void qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, - struct sts_entry_fx00 *pkt, uint8_t estatus, uint8_t etype) + struct sts_entry_fx00 *pkt) { srb_t *sp; struct qla_hw_data *ha = vha->hw; @@ -2695,9 +2693,6 @@ qlafx00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, struct req_que *req = NULL; int res = DID_ERROR << 16; - ql_dbg(ql_dbg_async, vha, 0x507f, - "type of error status in response: 0x%x\n", estatus); - req = ha->req_q_map[que]; sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); @@ -2745,9 +2740,11 @@ qlafx00_process_response_queue(struct scsi_qla_host *vha, if (pkt->entry_status != 0 && pkt->entry_type != IOCTL_IOSB_TYPE_FX00) { + ql_dbg(ql_dbg_async, vha, 0x507f, + "type of error status in response: 0x%x\n", + pkt->entry_status); qlafx00_error_entry(vha, rsp, - (struct sts_entry_fx00 *)pkt, pkt->entry_status, - pkt->entry_type); + (struct sts_entry_fx00 *)pkt); continue; } @@ -2867,7 +2864,7 @@ qlafx00_async_event(scsi_qla_host_t *vha) /** * qlafx00x_mbx_completion() - Process mailbox command completions. * @vha: SCSI driver HA context - * @mb0: + * @mb0: value to be written into mailbox register 0 */ static void qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0) @@ -2893,7 +2890,7 @@ qlafx00_mbx_completion(scsi_qla_host_t *vha, uint32_t mb0) /** * qlafx00_intr_handler() - Process interrupts for the ISPFX00. - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. diff --git a/qla2x00t-32gbit/qla_nvme.c b/qla2x00t-32gbit/qla_nvme.c index d0dc425f3..41c85da3a 100644 --- a/qla2x00t-32gbit/qla_nvme.c +++ b/qla2x00t-32gbit/qla_nvme.c @@ -30,6 +30,9 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) return 0; } + if (!vha->nvme_local_port && qla_nvme_register_hba(vha)) + return 0; + if (!(fcport->nvme_prli_service_param & (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) || (fcport->nvme_flag & NVME_FLAG_REGISTERED)) @@ -182,6 +185,14 @@ static void qla_nvme_abort_work(struct work_struct *work) struct qla_hw_data *ha = fcport->vha->hw; int rval; + if (fcport) + ql_dbg(ql_dbg_io, fcport->vha, 0xffff, + "%s called for sp=%p, hndl=%x on fcport=%p deleted=%d\n", + __func__, sp, sp->handle, fcport, fcport->deleted); + + if (!ha->flags.fw_started && (fcport && fcport->deleted)) + return; + rval = ha->isp_ops->abort_command(sp); ql_dbg(ql_dbg_io, fcport->vha, 0x212b, @@ -269,17 +280,6 @@ static void qla_nvme_fcp_abort(struct nvme_fc_local_port *lport, schedule_work(&priv->abort_work); } -static void qla_nvme_poll(struct nvme_fc_local_port *lport, void *hw_queue_handle) -{ - struct qla_qpair *qpair = hw_queue_handle; - unsigned long flags; - struct scsi_qla_host *vha = lport->private; - - spin_lock_irqsave(&qpair->qp_lock, flags); - qla24xx_process_response_queue(vha, qpair->rsp); - spin_unlock_irqrestore(&qpair->qp_lock, flags); -} - static inline int qla2x00_start_nvme_mq(srb_t *sp) { unsigned long flags; @@ -366,17 +366,24 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) /* No data transfer how do we check buffer len == 0?? */ if (fd->io_dir == NVMEFC_FCP_READ) { - cmd_pkt->control_flags = - cpu_to_le16(CF_READ_DATA | CF_NVME_ENABLE); + cmd_pkt->control_flags = CF_READ_DATA; vha->qla_stats.input_bytes += fd->payload_length; vha->qla_stats.input_requests++; } else if (fd->io_dir == NVMEFC_FCP_WRITE) { - cmd_pkt->control_flags = - cpu_to_le16(CF_WRITE_DATA | CF_NVME_ENABLE); + cmd_pkt->control_flags = CF_WRITE_DATA; + if ((vha->flags.nvme_first_burst) && + (sp->fcport->nvme_prli_service_param & + NVME_PRLI_SP_FIRST_BURST)) { + if ((fd->payload_length <= + sp->fcport->nvme_first_burst_size) || + (sp->fcport->nvme_first_burst_size == 0)) + cmd_pkt->control_flags |= + CF_NVME_FIRST_BURST_ENABLE; + } vha->qla_stats.output_bytes += fd->payload_length; vha->qla_stats.output_requests++; } else if (fd->io_dir == 0) { - cmd_pkt->control_flags = cpu_to_le16(CF_NVME_ENABLE); + cmd_pkt->control_flags = 0; } /* Set NPORT-ID */ @@ -471,21 +478,10 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, int rval = -ENODEV; srb_t *sp; struct qla_qpair *qpair = hw_queue_handle; - struct nvme_private *priv; + struct nvme_private *priv = fd->private; struct qla_nvme_rport *qla_rport = rport->private; - if (!fd || !qpair) { - ql_log(ql_log_warn, NULL, 0x2134, - "NO NVMe request or Queue Handle\n"); - return rval; - } - - priv = fd->private; fcport = qla_rport->fcport; - if (!fcport) { - ql_log(ql_log_warn, NULL, 0x210e, "No fcport ptr\n"); - return rval; - } vha = fcport->vha; @@ -503,7 +499,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, return -EBUSY; /* Alloc SRB structure */ - sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); if (!sp) return -EBUSY; @@ -514,6 +510,7 @@ static int qla_nvme_post_cmd(struct nvme_fc_local_port *lport, sp->name = "nvme_cmd"; sp->done = qla_nvme_sp_done; sp->qpair = qpair; + sp->vha = vha; nvme = &sp->u.iocb_cmd; nvme->u.nvme.desc = fd; @@ -561,7 +558,7 @@ static void qla_nvme_remoteport_delete(struct nvme_fc_remote_port *rport) schedule_work(&fcport->free_work); } - fcport->nvme_flag &= ~(NVME_FLAG_REGISTERED | NVME_FLAG_DELETING); + fcport->nvme_flag &= ~NVME_FLAG_DELETING; ql_log(ql_log_info, fcport->vha, 0x2110, "remoteport_delete of %p completed.\n", fcport); } @@ -575,7 +572,6 @@ static struct nvme_fc_port_template qla_nvme_fc_transport = { .ls_abort = qla_nvme_ls_abort, .fcp_io = qla_nvme_post_cmd, .fcp_abort = qla_nvme_fcp_abort, - .poll_queue = qla_nvme_poll, .max_hw_queues = 8, .max_sgl_segments = 128, .max_dif_sgl_segments = 64, @@ -619,6 +615,7 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) struct fc_port *fcport = container_of(work, struct fc_port, nvme_del_work); struct qla_nvme_rport *qla_rport, *trport; + scsi_qla_host_t *base_vha; if (!IS_ENABLED(CONFIG_NVME_FC)) return; @@ -626,6 +623,15 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) ql_log(ql_log_warn, NULL, 0x2112, "%s: unregister remoteport on %p\n",__func__, fcport); + base_vha = pci_get_drvdata(fcport->vha->hw->pdev); + if (test_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags)) { + ql_dbg(ql_dbg_disc, fcport->vha, 0x2114, + "%s: Notify FC-NVMe transport, set devloss=0\n", + __func__); + + nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); + } + list_for_each_entry_safe(qla_rport, trport, &fcport->vha->nvme_rport_list, list) { if (qla_rport->fcport == fcport) { @@ -642,23 +648,11 @@ static void qla_nvme_unregister_remote_port(struct work_struct *work) void qla_nvme_delete(struct scsi_qla_host *vha) { - struct qla_nvme_rport *qla_rport, *trport; - fc_port_t *fcport; int nv_ret; if (!IS_ENABLED(CONFIG_NVME_FC)) return; - list_for_each_entry_safe(qla_rport, trport, - &vha->nvme_rport_list, list) { - fcport = qla_rport->fcport; - - ql_log(ql_log_info, fcport->vha, 0x2114, "%s: fcport=%p\n", - __func__, fcport); - - nvme_fc_set_remoteport_devloss(fcport->nvme_remote_port, 0); - } - if (vha->nvme_local_port) { init_completion(&vha->nvme_del_done); ql_log(ql_log_info, vha, 0x2116, @@ -673,15 +667,15 @@ void qla_nvme_delete(struct scsi_qla_host *vha) } } -void qla_nvme_register_hba(struct scsi_qla_host *vha) +int qla_nvme_register_hba(struct scsi_qla_host *vha) { struct nvme_fc_port_template *tmpl; struct qla_hw_data *ha; struct nvme_fc_port_info pinfo; - int ret; + int ret = EINVAL; if (!IS_ENABLED(CONFIG_NVME_FC)) - return; + return ret; ha = vha->hw; tmpl = &qla_nvme_fc_transport; @@ -708,7 +702,9 @@ void qla_nvme_register_hba(struct scsi_qla_host *vha) if (ret) { ql_log(ql_log_warn, vha, 0xffff, "register_localport failed: ret=%x\n", ret); - return; + } else { + vha->nvme_local_port->private = vha; } - vha->nvme_local_port->private = vha; + + return ret; } diff --git a/qla2x00t-32gbit/qla_nvme.h b/qla2x00t-32gbit/qla_nvme.h index 816854ada..da8dad5ad 100644 --- a/qla2x00t-32gbit/qla_nvme.h +++ b/qla2x00t-32gbit/qla_nvme.h @@ -57,7 +57,7 @@ struct cmd_nvme { uint64_t rsvd; uint16_t control_flags; /* Control Flags */ -#define CF_NVME_ENABLE BIT_9 +#define CF_NVME_FIRST_BURST_ENABLE BIT_11 #define CF_DIF_SEG_DESCR_ENABLE BIT_3 #define CF_DATA_SEG_DESCR_ENABLE BIT_2 #define CF_READ_DATA BIT_1 @@ -142,7 +142,7 @@ struct pt_ls4_rx_unsol { /* * Global functions prototype in qla_nvme.c source file. */ -void qla_nvme_register_hba(struct scsi_qla_host *); +int qla_nvme_register_hba(struct scsi_qla_host *); int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *); void qla_nvme_delete(struct scsi_qla_host *); void qla_nvme_abort(struct qla_hw_data *, struct srb *sp, int res); diff --git a/qla2x00t-32gbit/qla_nx.c b/qla2x00t-32gbit/qla_nx.c index de2bc7844..f2f54806f 100644 --- a/qla2x00t-32gbit/qla_nx.c +++ b/qla2x00t-32gbit/qla_nx.c @@ -2010,7 +2010,7 @@ qla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0) /** * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx. - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. @@ -3699,8 +3699,8 @@ qla82xx_chip_reset_cleanup(scsi_qla_host_t *vha) spin_unlock_irqrestore(&ha->hardware_lock, flags); /* Wait for pending cmds (physical and virtual) to complete */ - if (!qla2x00_eh_wait_for_pending_commands(vha, 0, 0, - WAIT_HOST) == QLA_SUCCESS) { + if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0, + WAIT_HOST)) { ql_dbg(ql_dbg_init, vha, 0x00b3, "Done wait for " "pending commands.\n"); diff --git a/qla2x00t-32gbit/qla_nx2.c b/qla2x00t-32gbit/qla_nx2.c index 3a2b0282d..fe856b602 100644 --- a/qla2x00t-32gbit/qla_nx2.c +++ b/qla2x00t-32gbit/qla_nx2.c @@ -3878,7 +3878,7 @@ out: #define PF_BITS_MASK (0xF << 16) /** * qla8044_intr_handler() - Process interrupts for the ISP8044 - * @irq: + * @irq: interrupt number * @dev_id: SCSI driver HA context * * Called by system whenever the host adapter generates an interrupt. diff --git a/qla2x00t-32gbit/qla_os.c b/qla2x00t-32gbit/qla_os.c index 1fbd16c8c..91f576d74 100644 --- a/qla2x00t-32gbit/qla_os.c +++ b/qla2x00t-32gbit/qla_os.c @@ -14,6 +14,8 @@ #include #include #include +#include + #include #include #include @@ -65,7 +67,7 @@ module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(ql2xplogiabsentdevice, "Option to enable PLOGI to devices that are not present after " "a Fabric scan. This is needed for several broken switches. " - "Default is 0 - no PLOGI. 1 - perfom PLOGI."); + "Default is 0 - no PLOGI. 1 - perform PLOGI."); int ql2xloginretrycount = 0; module_param(ql2xloginretrycount, int, S_IRUGO); @@ -204,7 +206,7 @@ int ql2xasynctmfenable = 1; module_param(ql2xasynctmfenable, int, S_IRUGO); MODULE_PARM_DESC(ql2xasynctmfenable, "Enables issue of TM IOCBs asynchronously via IOCB mechanism" - "Default is 0 - Issue TM IOCBs via mailbox mechanism."); + "Default is 1 - Issue TM IOCBs via mailbox mechanism."); int ql2xdontresethba; module_param(ql2xdontresethba, int, S_IRUGO|S_IWUSR); @@ -283,6 +285,27 @@ MODULE_PARM_DESC(qla2xuseresexchforels, "Reserve 1/2 of emergency exchanges for ELS.\n" " 0 (default): disabled"); +int ql2xprotmask; +module_param(ql2xprotmask, int, 0644); +MODULE_PARM_DESC(ql2xprotmask, + "Override DIF/DIX protection capabilities mask\n" + "Default is 0 which sets protection mask based on " + "capabilities reported by HBA firmware.\n"); + +int ql2xprotguard; +module_param(ql2xprotguard, int, 0644); +MODULE_PARM_DESC(ql2xprotguard, "Override choice of DIX checksum\n" + " 0 -- Let HBA firmware decide\n" + " 1 -- Force T10 CRC\n" + " 2 -- Force IP checksum\n"); + +int ql2xdifbundlinginternalbuffers; +module_param(ql2xdifbundlinginternalbuffers, int, 0644); +MODULE_PARM_DESC(ql2xdifbundlinginternalbuffers, + "Force using internal buffers for DIF information\n" + "0 (Default). Based on check.\n" + "1 Force using internal buffers\n"); + /* * SCSI host template entry points */ @@ -326,7 +349,6 @@ struct scsi_host_template qla2xxx_driver_template = { .map_queues = qla2xxx_map_queues, .this_id = -1, .cmd_per_lun = 3, - .use_clustering = ENABLE_CLUSTERING, .sg_tablesize = SG_ALL, .max_sectors = 0xFFFF, @@ -391,12 +413,14 @@ static void qla_init_base_qpair(struct scsi_qla_host *vha, struct req_que *req, struct qla_hw_data *ha = vha->hw; rsp->qpair = ha->base_qpair; rsp->req = req; + ha->base_qpair->hw = ha; ha->base_qpair->req = req; ha->base_qpair->rsp = rsp; ha->base_qpair->vha = vha; ha->base_qpair->qp_lock_ptr = &ha->hardware_lock; ha->base_qpair->use_shadow_reg = IS_SHADOW_REG_CAPABLE(ha) ? 1 : 0; ha->base_qpair->msix = &ha->msix_entries[QLA_MSIX_RSP_Q]; + ha->base_qpair->srb_mempool = ha->srb_mempool; INIT_LIST_HEAD(&ha->base_qpair->hints_list); ha->base_qpair->enable_class_2 = ql2xenableclass2; /* init qpair to this cpu. Will adjust at run time. */ @@ -801,7 +825,44 @@ qla2xxx_qpair_sp_free_dma(void *ptr) ha->gbl_dsd_inuse -= ctx1->dsd_use_cnt; ha->gbl_dsd_avail += ctx1->dsd_use_cnt; mempool_free(ctx1, ha->ctx_mempool); + sp->flags &= ~SRB_FCP_CMND_DMA_VALID; } + if (sp->flags & SRB_DIF_BUNDL_DMA_VALID) { + struct crc_context *difctx = sp->u.scmd.ctx; + struct dsd_dma *dif_dsd, *nxt_dsd; + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dma_hndl_list, list) { + list_del(&dif_dsd->list); + dma_pool_free(ha->dif_bundl_pool, dif_dsd->dsd_addr, + dif_dsd->dsd_list_dma); + kfree(dif_dsd); + difctx->no_dif_bundl--; + } + + list_for_each_entry_safe(dif_dsd, nxt_dsd, + &difctx->ldif_dsd_list, list) { + list_del(&dif_dsd->list); + dma_pool_free(ha->dl_dma_pool, dif_dsd->dsd_addr, + dif_dsd->dsd_list_dma); + kfree(dif_dsd); + difctx->no_ldif_dsd--; + } + + if (difctx->no_ldif_dsd) { + ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, + "%s: difctx->no_ldif_dsd=%x\n", + __func__, difctx->no_ldif_dsd); + } + + if (difctx->no_dif_bundl) { + ql_dbg(ql_dbg_tgt+ql_dbg_verbose, sp->vha, 0xe022, + "%s: difctx->no_dif_bundl=%x\n", + __func__, difctx->no_dif_bundl); + } + sp->flags &= ~SRB_DIF_BUNDL_DMA_VALID; + } + end: CMD_SP(cmd) = NULL; qla2xxx_rel_qpair_sp(sp->qpair, sp); @@ -853,13 +914,9 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) } if (ha->mqenable) { - if (shost_use_blk_mq(vha->host)) { - tag = blk_mq_unique_tag(cmd->request); - hwq = blk_mq_unique_tag_to_hwq(tag); - qpair = ha->queue_pair_map[hwq]; - } else if (vha->vp_idx && vha->qpair) { - qpair = vha->qpair; - } + tag = blk_mq_unique_tag(cmd->request); + hwq = blk_mq_unique_tag_to_hwq(tag); + qpair = ha->queue_pair_map[hwq]; if (qpair) return qla2xxx_mqueuecommand(host, cmd, qpair); @@ -1012,7 +1069,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, else goto qc24_target_busy; - sp = qla2xxx_get_qpair_sp(qpair, fcport, GFP_ATOMIC); + sp = qla2xxx_get_qpair_sp(vha, qpair, fcport, GFP_ATOMIC); if (!sp) goto qc24_host_busy; @@ -1212,10 +1269,14 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -static void +static int sp_get(struct srb *sp) { - atomic_inc(&sp->ref_count); + if (!refcount_inc_not_zero((refcount_t*)&sp->ref_count)) + /* kref get fail */ + return ENXIO; + else + return 0; } #define ISP_REG_DISCONNECT 0xffffffffU @@ -1273,38 +1334,51 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) unsigned long flags; int rval, wait = 0; struct qla_hw_data *ha = vha->hw; + struct qla_qpair *qpair; if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x8042, "PCI/Register disconnect, exiting.\n"); return FAILED; } - if (!CMD_SP(cmd)) - return SUCCESS; ret = fc_block_scsi_eh(cmd); if (ret != 0) return ret; ret = SUCCESS; - id = cmd->device->id; - lun = cmd->device->lun; - - spin_lock_irqsave(&ha->hardware_lock, flags); sp = (srb_t *) CMD_SP(cmd); - if (!sp) { - spin_unlock_irqrestore(&ha->hardware_lock, flags); + if (!sp) + return SUCCESS; + + qpair = sp->qpair; + if (!qpair) + return SUCCESS; + + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + if (!CMD_SP(cmd)) { + /* there's a chance an interrupt could clear + the ptr as part of done & free */ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return SUCCESS; } + if (sp_get(sp)){ + /* ref_count is already 0 */ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return SUCCESS; + } + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + + id = cmd->device->id; + lun = cmd->device->lun; + ql_dbg(ql_dbg_taskm, vha, 0x8002, "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", vha->host_no, id, lun, sp, cmd, sp->handle); /* Get a reference to the sp and drop the lock.*/ - sp_get(sp); - spin_unlock_irqrestore(&ha->hardware_lock, flags); rval = ha->isp_ops->abort_command(sp); if (rval) { if (rval == QLA_FUNCTION_PARAMETER_ERROR) @@ -1320,14 +1394,29 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) wait = 1; } - spin_lock_irqsave(&ha->hardware_lock, flags); - sp->done(sp, 0); - spin_unlock_irqrestore(&ha->hardware_lock, flags); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + /* + * Clear the slot in the oustanding_cmds array if we can't find the + * command to reclaim the resources. + */ + if (rval == QLA_FUNCTION_PARAMETER_ERROR) + vha->req->outstanding_cmds[sp->handle] = NULL; + + /* + * sp->done will do ref_count-- + * sp_get() took an extra count above + */ + sp->done(sp, DID_RESET << 16); /* Did the command return during mailbox execution? */ if (ret == FAILED && !CMD_SP(cmd)) ret = SUCCESS; + if (!CMD_SP(cmd)) + wait = 0; + + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + /* Wait for the command to be returned. */ if (wait) { if (qla2x00_eh_wait_on_command(cmd) != QLA_SUCCESS) { @@ -1428,7 +1517,7 @@ __qla2xxx_eh_generic_reset(char *name, enum nexus_wait_type type, goto eh_reset_failed; } err = 2; - if (do_reset(fcport, cmd->device->lun, cmd->request->cpu + 1) + if (do_reset(fcport, cmd->device->lun, 1) != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x800c, "do_reset failed for cmd=%p.\n", cmd); @@ -1710,10 +1799,53 @@ qla2x00_loop_reset(scsi_qla_host_t *vha) return QLA_SUCCESS; } +static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, + unsigned long *flags) + __releases(qp->qp_lock_ptr) + __acquires(qp->qp_lock_ptr) +{ + scsi_qla_host_t *vha = qp->vha; + struct qla_hw_data *ha = vha->hw; + + if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS) { + if (!sp_get(sp)) { + /* got sp */ + spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); + qla_nvme_abort(ha, sp, res); + spin_lock_irqsave(qp->qp_lock_ptr, *flags); + } + } else if (GET_CMD_SP(sp) && !ha->flags.eeh_busy && + !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && + !qla2x00_isp_reg_stat(ha) && sp->type == SRB_SCSI_CMD) { + /* + * Don't abort commands in adapter during EEH recovery as it's + * not accessible/responding. + * + * Get a reference to the sp and drop the lock. The reference + * ensures this sp->done() call and not the call in + * qla2xxx_eh_abort() ends the SCSI cmd (with result 'res'). + */ + if (!sp_get(sp)) { + int status; + + spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); + status = qla2xxx_eh_abort(GET_CMD_SP(sp)); + spin_lock_irqsave(qp->qp_lock_ptr, *flags); + /* + * Get rid of extra reference caused + * by early exit from qla2xxx_eh_abort + */ + if (status == FAST_IO_FAIL) + atomic_dec(&sp->ref_count); + } + } + sp->done(sp, res); +} + static void __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) { - int cnt, status; + int cnt; unsigned long flags; srb_t *sp; scsi_qla_host_t *vha = qp->vha; @@ -1721,7 +1853,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) struct req_que *req; struct qla_tgt *tgt = vha->vha_tgt.qla_tgt; struct qla_tgt_cmd *cmd; - uint8_t trace = 0; if (!ha->req_q_map) return; @@ -1731,64 +1862,31 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) sp = req->outstanding_cmds[cnt]; if (sp) { req->outstanding_cmds[cnt] = NULL; - if (sp->cmd_type == TYPE_SRB) { - if (sp->type == SRB_NVME_CMD || - sp->type == SRB_NVME_LS) { - sp_get(sp); - spin_unlock_irqrestore(qp->qp_lock_ptr, - flags); - qla_nvme_abort(ha, sp, res); - spin_lock_irqsave(qp->qp_lock_ptr, - flags); - } else if (GET_CMD_SP(sp) && - !ha->flags.eeh_busy && - (!test_bit(ABORT_ISP_ACTIVE, - &vha->dpc_flags)) && - (sp->type == SRB_SCSI_CMD)) { - /* - * Don't abort commands in - * adapter during EEH - * recovery as it's not - * accessible/responding. - * - * Get a reference to the sp - * and drop the lock. The - * reference ensures this - * sp->done() call and not the - * call in qla2xxx_eh_abort() - * ends the SCSI command (with - * result 'res'). - */ - sp_get(sp); - spin_unlock_irqrestore(qp->qp_lock_ptr, - flags); - status = qla2xxx_eh_abort( - GET_CMD_SP(sp)); - spin_lock_irqsave(qp->qp_lock_ptr, - flags); - /* - * Get rid of extra reference - * if immediate exit from - * ql2xxx_eh_abort - */ - if (status == FAILED && - (qla2x00_isp_reg_stat(ha))) - atomic_dec( - &sp->ref_count); - } - sp->done(sp, res); - } else { + switch (sp->cmd_type) { + case TYPE_SRB: + qla2x00_abort_srb(qp, sp, res, &flags); + break; + case TYPE_TGT_CMD: if (!vha->hw->tgt.tgt_ops || !tgt || qla_ini_mode_enabled(vha)) { - if (!trace) - ql_dbg(ql_dbg_tgt_mgt, - vha, 0xf003, - "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", - vha->dpc_flags); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf003, + "HOST-ABORT-HNDLR: dpc_flags=%lx. Target mode disabled\n", + vha->dpc_flags); continue; } cmd = (struct qla_tgt_cmd *)sp; qlt_abort_cmd_on_host_reset(cmd->vha, cmd); + break; + case TYPE_TGT_TMCMD: + /* + * Currently, only ABTS response gets on the + * outstanding_cmds[] + */ + ha->tgt.tgt_ops->free_mcmd( + (struct qla_tgt_mgmt_cmd *)sp); + break; + default: + break; } } } @@ -2708,7 +2806,7 @@ static void qla2x00_iocb_work_fn(struct work_struct *work) struct scsi_qla_host, iocb_work); struct qla_hw_data *ha = vha->hw; struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev); - int i = 20; + int i = 2; unsigned long flags; if (test_bit(UNLOADING, &base_vha->dpc_flags)) @@ -2816,6 +2914,11 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) ha->link_data_rate = PORT_SPEED_UNKNOWN; ha->optrom_size = OPTROM_SIZE_2300; ha->max_exchg = FW_MAX_EXCHANGES_CNT; + atomic_set(&ha->num_pend_mbx_stage1, 0); + atomic_set(&ha->num_pend_mbx_stage2, 0); + atomic_set(&ha->num_pend_mbx_stage3, 0); + atomic_set(&ha->zio_threshold, DEFAULT_ZIO_THRESHOLD); + ha->last_zio_threshold = DEFAULT_ZIO_THRESHOLD; /* Assign ISP specific operations. */ if (IS_QLA2100(ha)) { @@ -3046,7 +3149,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) host = base_vha->host; base_vha->req = req; if (IS_QLA2XXX_MIDTYPE(ha)) - base_vha->mgmt_svr_loop_id = NPH_MGMT_SERVER; + base_vha->mgmt_svr_loop_id = + qla2x00_reserve_mgmt_server_loop_id(base_vha); else base_vha->mgmt_svr_loop_id = MANAGEMENT_SERVER + base_vha->vp_idx; @@ -3108,7 +3212,7 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) goto probe_failed; } - if (ha->mqenable && shost_use_blk_mq(host)) { + if (ha->mqenable) { /* number of hardware queues supported by blk/scsi-mq*/ host->nr_hw_queues = ha->max_qpairs; @@ -3220,25 +3324,17 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) base_vha->mgmt_svr_loop_id, host->sg_tablesize); if (ha->mqenable) { - bool mq = false; bool startit = false; - if (QLA_TGT_MODE_ENABLED()) { - mq = true; + if (QLA_TGT_MODE_ENABLED()) startit = false; - } - if ((ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) && - shost_use_blk_mq(host)) { - mq = true; + if (ql2x_ini_mode == QLA2XXX_INI_MODE_ENABLED) startit = true; - } - if (mq) { - /* Create start of day qpairs for Block MQ */ - for (i = 0; i < ha->max_qpairs; i++) - qla2xxx_create_qpair(base_vha, 5, 0, startit); - } + /* Create start of day qpairs for Block MQ */ + for (i = 0; i < ha->max_qpairs; i++) + qla2xxx_create_qpair(base_vha, 5, 0, startit); } if (ha->flags.running_gold_fw) @@ -3304,13 +3400,16 @@ skip_dpc: "Registering for DIF/DIX type 1 and 3 protection.\n"); if (ql2xenabledif == 1) prot = SHOST_DIX_TYPE0_PROTECTION; - scsi_host_set_prot(host, - prot | SHOST_DIF_TYPE1_PROTECTION - | SHOST_DIF_TYPE2_PROTECTION - | SHOST_DIF_TYPE3_PROTECTION - | SHOST_DIX_TYPE1_PROTECTION - | SHOST_DIX_TYPE2_PROTECTION - | SHOST_DIX_TYPE3_PROTECTION); + if (ql2xprotmask) + scsi_host_set_prot(host, ql2xprotmask); + else + scsi_host_set_prot(host, + prot | SHOST_DIF_TYPE1_PROTECTION + | SHOST_DIF_TYPE2_PROTECTION + | SHOST_DIF_TYPE3_PROTECTION + | SHOST_DIX_TYPE1_PROTECTION + | SHOST_DIX_TYPE2_PROTECTION + | SHOST_DIX_TYPE3_PROTECTION); guard = SHOST_DIX_GUARD_CRC; @@ -3318,7 +3417,10 @@ skip_dpc: (ql2xenabledif > 1 || IS_PI_DIFB_DIX0_CAPABLE(ha))) guard |= SHOST_DIX_GUARD_IP; - scsi_host_set_guard(host, guard); + if (ql2xprotguard) + scsi_host_set_guard(host, ql2xprotguard); + else + scsi_host_set_guard(host, guard); } else base_vha->flags.difdix_supported = 0; } @@ -3519,6 +3621,8 @@ qla2x00_delete_all_vps(struct qla_hw_data *ha, scsi_qla_host_t *base_vha) spin_unlock_irqrestore(&ha->vport_slock, flags); mutex_unlock(&ha->vport_lock); + qla_nvme_delete(vha); + fc_vport_terminate(vha->fc_vport); scsi_host_put(vha->host); @@ -3830,14 +3934,6 @@ void qla2x00_mark_device_lost(scsi_qla_host_t *vha, fc_port_t *fcport, return; set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - - if (fcport->login_retry == 0) { - fcport->login_retry = vha->hw->login_retry_count; - - ql_dbg(ql_dbg_disc, vha, 0x20a3, - "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", - fcport->port_name, fcport->loop_id, fcport->login_retry); - } } /* @@ -3965,9 +4061,86 @@ qla2x00_mem_alloc(struct qla_hw_data *ha, uint16_t req_len, uint16_t rsp_len, "Failed to allocate memory for fcp_cmnd_dma_pool.\n"); goto fail_dl_dma_pool; } + + if (ql2xenabledif) { + u64 bufsize = DIF_BUNDLING_DMA_POOL_SIZE; + struct dsd_dma *dsd, *nxt; + uint i; + /* Creata a DMA pool of buffers for DIF bundling */ + ha->dif_bundl_pool = dma_pool_create(name, + &ha->pdev->dev, DIF_BUNDLING_DMA_POOL_SIZE, 8, 0); + if (!ha->dif_bundl_pool) { + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, + "%s: failed create dif_bundl_pool\n", + __func__); + goto fail_dif_bundl_dma_pool; + } + + INIT_LIST_HEAD(&ha->pool.good.head); + INIT_LIST_HEAD(&ha->pool.unusable.head); + ha->pool.good.count = 0; + ha->pool.unusable.count = 0; + for (i = 0; i < 128; i++) { + dsd = kzalloc(sizeof(*dsd), GFP_ATOMIC); + if (!dsd) { + ql_dbg_pci(ql_dbg_init, ha->pdev, + 0xe0ee, "%s: failed alloc dsd\n", + __func__); + return 1; + } + ha->dif_bundle_kallocs++; + + dsd->dsd_addr = dma_pool_alloc( + ha->dif_bundl_pool, GFP_ATOMIC, + &dsd->dsd_list_dma); + if (!dsd->dsd_addr) { + ql_dbg_pci(ql_dbg_init, ha->pdev, + 0xe0ee, + "%s: failed alloc ->dsd_addr\n", + __func__); + kfree(dsd); + ha->dif_bundle_kallocs--; + continue; + } + ha->dif_bundle_dma_allocs++; + + /* + * if DMA buffer crosses 4G boundary, + * put it on bad list + */ + if (MSD(dsd->dsd_list_dma) ^ + MSD(dsd->dsd_list_dma + bufsize)) { + list_add_tail(&dsd->list, + &ha->pool.unusable.head); + ha->pool.unusable.count++; + } else { + list_add_tail(&dsd->list, + &ha->pool.good.head); + ha->pool.good.count++; + } + } + + /* return the good ones back to the pool */ + list_for_each_entry_safe(dsd, nxt, + &ha->pool.good.head, list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, + dsd->dsd_addr, dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + } + + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0024, + "%s: dif dma pool (good=%u unusable=%u)\n", + __func__, ha->pool.good.count, + ha->pool.unusable.count); + } + ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0025, - "dl_dma_pool=%p fcp_cmnd_dma_pool=%p.\n", - ha->dl_dma_pool, ha->fcp_cmnd_dma_pool); + "dl_dma_pool=%p fcp_cmnd_dma_pool=%p dif_bundl_pool=%p.\n", + ha->dl_dma_pool, ha->fcp_cmnd_dma_pool, + ha->dif_bundl_pool); } /* Allocate memory for SNS commands */ @@ -4132,6 +4305,24 @@ fail_free_ms_iocb: dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt), ha->sns_cmd, ha->sns_cmd_dma); fail_dma_pool: + if (ql2xenabledif) { + struct dsd_dma *dsd, *nxt; + + list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, + list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + ha->pool.unusable.count--; + } + dma_pool_destroy(ha->dif_bundl_pool); + ha->dif_bundl_pool = NULL; + } + +fail_dif_bundl_dma_pool: if (IS_QLA82XX(ha) || ql2xenabledif) { dma_pool_destroy(ha->fcp_cmnd_dma_pool); ha->fcp_cmnd_dma_pool = NULL; @@ -4148,12 +4339,10 @@ fail_free_nvram: kfree(ha->nvram); ha->nvram = NULL; fail_free_ctx_mempool: - if (ha->ctx_mempool) - mempool_destroy(ha->ctx_mempool); + mempool_destroy(ha->ctx_mempool); ha->ctx_mempool = NULL; fail_free_srb_mempool: - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); + mempool_destroy(ha->srb_mempool); ha->srb_mempool = NULL; fail_free_gid_list: dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), @@ -4253,29 +4442,34 @@ static void qla2x00_number_of_exch(scsi_qla_host_t *vha, u32 *ret_cnt, u16 max_cnt) { u32 temp; + struct init_cb_81xx *icb = (struct init_cb_81xx *)&vha->hw->init_cb; *ret_cnt = FW_DEF_EXCHANGES_CNT; if (max_cnt > vha->hw->max_exchg) max_cnt = vha->hw->max_exchg; if (qla_ini_mode_enabled(vha)) { - if (ql2xiniexchg > max_cnt) - ql2xiniexchg = max_cnt; + if (vha->ql2xiniexchg > max_cnt) + vha->ql2xiniexchg = max_cnt; + + if (vha->ql2xiniexchg > FW_DEF_EXCHANGES_CNT) + *ret_cnt = vha->ql2xiniexchg; - if (ql2xiniexchg > FW_DEF_EXCHANGES_CNT) - *ret_cnt = ql2xiniexchg; } else if (qla_tgt_mode_enabled(vha)) { - if (ql2xexchoffld > max_cnt) - ql2xexchoffld = max_cnt; + if (vha->ql2xexchoffld > max_cnt) { + vha->ql2xexchoffld = max_cnt; + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); + } - if (ql2xexchoffld > FW_DEF_EXCHANGES_CNT) - *ret_cnt = ql2xexchoffld; + if (vha->ql2xexchoffld > FW_DEF_EXCHANGES_CNT) + *ret_cnt = vha->ql2xexchoffld; } else if (qla_dual_mode_enabled(vha)) { - temp = ql2xiniexchg + ql2xexchoffld; + temp = vha->ql2xiniexchg + vha->ql2xexchoffld; if (temp > max_cnt) { - ql2xiniexchg -= (temp - max_cnt)/2; - ql2xexchoffld -= (((temp - max_cnt)/2) + 1); + vha->ql2xiniexchg -= (temp - max_cnt)/2; + vha->ql2xexchoffld -= (((temp - max_cnt)/2) + 1); temp = max_cnt; + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); } if (temp > FW_DEF_EXCHANGES_CNT) @@ -4313,6 +4507,12 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) if (totsz != ha->exchoffld_size) { qla2x00_free_exchoffld_buffer(ha); + if (actual_cnt <= FW_DEF_EXCHANGES_CNT) { + ha->exchoffld_size = 0; + ha->flags.exchoffld_enabled = 0; + return QLA_SUCCESS; + } + ha->exchoffld_size = totsz; ql_log(ql_log_info, vha, 0xd016, @@ -4345,6 +4545,15 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) return -ENOMEM; } + } else if (!ha->exchoffld_buf || (actual_cnt <= FW_DEF_EXCHANGES_CNT)) { + /* pathological case */ + qla2x00_free_exchoffld_buffer(ha); + ha->exchoffld_size = 0; + ha->flags.exchoffld_enabled = 0; + ql_log(ql_log_info, vha, 0xd016, + "Exchange offload not enable: offld size=%d, actual count=%d entry sz=0x%x, total sz=0x%x.\n", + ha->exchoffld_size, actual_cnt, size, totsz); + return 0; } /* Now configure the dma buffer */ @@ -4360,7 +4569,7 @@ qla2x00_set_exchoffld_buffer(scsi_qla_host_t *vha) if (qla_ini_mode_enabled(vha)) icb->exchange_count = 0; else - icb->exchange_count = cpu_to_le16(ql2xexchoffld); + icb->exchange_count = cpu_to_le16(vha->ql2xexchoffld); } return rval; @@ -4435,8 +4644,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) dma_free_coherent(&ha->pdev->dev, MCTP_DUMP_SIZE, ha->mctp_dump, ha->mctp_dump_dma); - if (ha->srb_mempool) - mempool_destroy(ha->srb_mempool); + mempool_destroy(ha->srb_mempool); if (ha->dcbx_tlv) dma_free_coherent(&ha->pdev->dev, DCBX_TLV_DATA_SIZE, @@ -4468,8 +4676,7 @@ qla2x00_mem_free(struct qla_hw_data *ha) if (ha->async_pd) dma_pool_free(ha->s_dma_pool, ha->async_pd, ha->async_pd_dma); - if (ha->s_dma_pool) - dma_pool_destroy(ha->s_dma_pool); + dma_pool_destroy(ha->s_dma_pool); if (ha->gid_list) dma_free_coherent(&ha->pdev->dev, qla2x00_gid_list_size(ha), @@ -4490,14 +4697,37 @@ qla2x00_mem_free(struct qla_hw_data *ha) } } - if (ha->dl_dma_pool) - dma_pool_destroy(ha->dl_dma_pool); + dma_pool_destroy(ha->dl_dma_pool); - if (ha->fcp_cmnd_dma_pool) - dma_pool_destroy(ha->fcp_cmnd_dma_pool); + dma_pool_destroy(ha->fcp_cmnd_dma_pool); - if (ha->ctx_mempool) - mempool_destroy(ha->ctx_mempool); + mempool_destroy(ha->ctx_mempool); + + if (ql2xenabledif) { + struct dsd_dma *dsd, *nxt; + + list_for_each_entry_safe(dsd, nxt, &ha->pool.unusable.head, + list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + ha->pool.unusable.count--; + } + list_for_each_entry_safe(dsd, nxt, &ha->pool.good.head, list) { + list_del(&dsd->list); + dma_pool_free(ha->dif_bundl_pool, dsd->dsd_addr, + dsd->dsd_list_dma); + ha->dif_bundle_dma_allocs--; + kfree(dsd); + ha->dif_bundle_kallocs--; + } + } + + if (ha->dif_bundl_pool) + dma_pool_destroy(ha->dif_bundl_pool); qlt_mem_free(ha); @@ -4568,6 +4798,10 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, vha->host_no = host->host_no; vha->hw = ha; + vha->qlini_mode = ql2x_ini_mode; + vha->ql2xexchoffld = ql2xexchoffld; + vha->ql2xiniexchg = ql2xiniexchg; + INIT_LIST_HEAD(&vha->vp_fcports); INIT_LIST_HEAD(&vha->work_list); INIT_LIST_HEAD(&vha->list); @@ -4583,7 +4817,6 @@ struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *sht, spin_lock_init(&vha->work_lock); spin_lock_init(&vha->cmd_list_lock); - spin_lock_init(&vha->gnl.fcports_lock); init_waitqueue_head(&vha->fcport_waitQ); init_waitqueue_head(&vha->vref_waitq); @@ -4714,7 +4947,6 @@ qla2x00_post_async_work(login, QLA_EVT_ASYNC_LOGIN); qla2x00_post_async_work(logout, QLA_EVT_ASYNC_LOGOUT); qla2x00_post_async_work(logout_done, QLA_EVT_ASYNC_LOGOUT_DONE); qla2x00_post_async_work(adisc, QLA_EVT_ASYNC_ADISC); -qla2x00_post_async_work(adisc_done, QLA_EVT_ASYNC_ADISC_DONE); qla2x00_post_async_work(prlo, QLA_EVT_ASYNC_PRLO); qla2x00_post_async_work(prlo_done, QLA_EVT_ASYNC_PRLO_DONE); @@ -4765,16 +4997,25 @@ qlafx00_post_aenfx_work(struct scsi_qla_host *vha, uint32_t evtcode, return qla2x00_post_work(vha, e); } -int qla24xx_post_upd_fcport_work(struct scsi_qla_host *vha, fc_port_t *fcport) +void qla24xx_sched_upd_fcport(fc_port_t *fcport) { - struct qla_work_evt *e; + unsigned long flags; - e = qla2x00_alloc_work(vha, QLA_EVT_UPD_FCPORT); - if (!e) - return QLA_FUNCTION_FAILED; + if (IS_SW_RESV_ADDR(fcport->d_id)) + return; - e->u.fcport.fcport = fcport; - return qla2x00_post_work(vha, e); + spin_lock_irqsave(&fcport->vha->work_lock, flags); + if (fcport->disc_state == DSC_UPD_FCPORT) { + spin_unlock_irqrestore(&fcport->vha->work_lock, flags); + return; + } + fcport->jiffies_at_registration = jiffies; + fcport->sec_since_registration = 0; + fcport->next_disc_state = DSC_DELETED; + fcport->disc_state = DSC_UPD_FCPORT; + spin_unlock_irqrestore(&fcport->vha->work_lock, flags); + + queue_work(system_unbound_wq, &fcport->reg_work); } static @@ -4785,7 +5026,6 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) struct qlt_plogi_ack_t *pla = (struct qlt_plogi_ack_t *)e->u.new_sess.pla; uint8_t free_fcport = 0; - u64 wwn; ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC enter\n", @@ -4813,10 +5053,10 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->d_id = e->u.new_sess.id; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; - if (e->u.new_sess.fc4_type & FS_FC4TYPE_FCP) + if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP) fcport->fc4_type = FC4_TYPE_FCP_SCSI; - if (e->u.new_sess.fc4_type & FS_FC4TYPE_NVME) { + if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) { fcport->fc4_type = FC4_TYPE_OTHER; fcport->fc4f_nvme = FC4_TYPE_NVME; } @@ -4858,9 +5098,6 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); if (fcport) { - if (N2N_TOPO(vha->hw)) - fcport->flags &= ~FCF_FABRIC_DEVICE; - fcport->id_changed = 1; fcport->scan_state = QLA_FCPORT_FOUND; memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE); @@ -4921,12 +5158,22 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (dfcp) qlt_schedule_sess_for_deletion(tfcp); - wwn = wwn_to_u64(fcport->node_name); - if (!wwn) - qla24xx_async_gnnid(vha, fcport); - else - qla24xx_async_gnl(vha, fcport); + if (N2N_TOPO(vha->hw)) + fcport->flags &= ~FCF_FABRIC_DEVICE; + + if (N2N_TOPO(vha->hw)) { + if (vha->flags.nvme_enabled) { + fcport->fc4f_nvme = 1; + fcport->n2n_flag = 1; + } + fcport->fw_login_state = 0; + /* + * wait link init done before sending login + */ + } else { + qla24xx_fcport_handle_login(vha, fcport); + } } } @@ -4957,14 +5204,14 @@ qla2x00_do_work(struct scsi_qla_host *vha) struct qla_work_evt *e, *tmp; unsigned long flags; LIST_HEAD(work); + int rc; spin_lock_irqsave(&vha->work_lock, flags); list_splice_init(&vha->work_list, &work); spin_unlock_irqrestore(&vha->work_lock, flags); list_for_each_entry_safe(e, tmp, &work, list) { - list_del_init(&e->list); - + rc = QLA_SUCCESS; switch (e->type) { case QLA_EVT_AEN: fc_host_post_event(vha->host, fc_get_event_number(), @@ -4978,7 +5225,7 @@ qla2x00_do_work(struct scsi_qla_host *vha) e->u.logio.data); break; case QLA_EVT_ASYNC_LOGOUT: - qla2x00_async_logout(vha, e->u.logio.fcport); + rc = qla2x00_async_logout(vha, e->u.logio.fcport); break; case QLA_EVT_ASYNC_LOGOUT_DONE: qla2x00_async_logout_done(vha, e->u.logio.fcport, @@ -4988,19 +5235,12 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla2x00_async_adisc(vha, e->u.logio.fcport, e->u.logio.data); break; - case QLA_EVT_ASYNC_ADISC_DONE: - qla2x00_async_adisc_done(vha, e->u.logio.fcport, - e->u.logio.data); - break; case QLA_EVT_UEVENT: qla2x00_uevent_emit(vha, e->u.uevent.code); break; case QLA_EVT_AENFX: qlafx00_process_aen(vha, e); break; - case QLA_EVT_GIDPN: - qla24xx_async_gidpn(vha, e->u.fcport.fcport); - break; case QLA_EVT_GPNID: qla24xx_async_gpnid(vha, &e->u.gpnid.id); break; @@ -5023,9 +5263,6 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_GPSC: qla24xx_async_gpsc(vha, e->u.fcport.fcport); break; - case QLA_EVT_UPD_FCPORT: - qla2x00_update_fcport(vha, e->u.fcport.fcport); - break; case QLA_EVT_GNL: qla24xx_async_gnl(vha, e->u.fcport.fcport); break; @@ -5033,7 +5270,7 @@ qla2x00_do_work(struct scsi_qla_host *vha) qla24xx_do_nack_work(vha, e); break; case QLA_EVT_ASYNC_PRLO: - qla2x00_async_prlo(vha, e->u.logio.fcport); + rc = qla2x00_async_prlo(vha, e->u.logio.fcport); break; case QLA_EVT_ASYNC_PRLO_DONE: qla2x00_async_prlo_done(vha, e->u.logio.fcport, @@ -5061,7 +5298,20 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_IIDMA: qla_do_iidma_work(vha, e->u.fcport.fcport); break; + case QLA_EVT_ELS_PLOGI: + qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI, + e->u.fcport.fcport, false); + break; } + + if (rc == EAGAIN) { + /* put 'work' at head of 'vha->work_list' */ + spin_lock_irqsave(&vha->work_lock, flags); + list_splice(&work, &vha->work_list); + spin_unlock_irqrestore(&vha->work_lock, flags); + break; + } + list_del_init(&e->list); if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); @@ -5090,7 +5340,7 @@ int qla24xx_post_relogin_work(struct scsi_qla_host *vha) void qla2x00_relogin(struct scsi_qla_host *vha) { fc_port_t *fcport; - int status; + int status, relogin_needed = 0; struct event_arg ea; list_for_each_entry(fcport, &vha->vp_fcports, list) { @@ -5099,47 +5349,59 @@ void qla2x00_relogin(struct scsi_qla_host *vha) * to it if we haven't run out of retries. */ if (atomic_read(&fcport->state) != FCS_ONLINE && - fcport->login_retry && - !(fcport->flags & (FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE))) { - if (vha->hw->current_topology != ISP_CFG_NL) { - ql_dbg(ql_dbg_disc, fcport->vha, 0x2108, - "%s %8phC DS %d LS %d\n", __func__, - fcport->port_name, fcport->disc_state, - fcport->fw_login_state); - memset(&ea, 0, sizeof(ea)); - ea.event = FCME_RELOGIN; - ea.fcport = fcport; - qla2x00_fcport_event_handler(vha, &ea); - } else if (vha->hw->current_topology == ISP_CFG_NL) { - fcport->login_retry--; - status = qla2x00_local_device_login(vha, - fcport); - if (status == QLA_SUCCESS) { - fcport->old_loop_id = fcport->loop_id; - ql_dbg(ql_dbg_disc, vha, 0x2003, - "Port login OK: logged in ID 0x%x.\n", - fcport->loop_id); - qla2x00_update_fcport(vha, fcport); - } else if (status == 1) { - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - /* retry the login again */ - ql_dbg(ql_dbg_disc, vha, 0x2007, - "Retrying %d login again loop_id 0x%x.\n", - fcport->login_retry, - fcport->loop_id); - } else { - fcport->login_retry = 0; - } + fcport->login_retry) { + if (fcport->scan_state != QLA_FCPORT_FOUND || + fcport->disc_state == DSC_LOGIN_COMPLETE) + continue; - if (fcport->login_retry == 0 && - status != QLA_SUCCESS) - qla2x00_clear_loop_id(fcport); + if (fcport->flags & (FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE) || + fcport->disc_state == DSC_DELETE_PEND) { + relogin_needed = 1; + } else { + if (vha->hw->current_topology != ISP_CFG_NL) { + memset(&ea, 0, sizeof(ea)); + ea.event = FCME_RELOGIN; + ea.fcport = fcport; + qla2x00_fcport_event_handler(vha, &ea); + } else if (vha->hw->current_topology == + ISP_CFG_NL) { + fcport->login_retry--; + status = + qla2x00_local_device_login(vha, + fcport); + if (status == QLA_SUCCESS) { + fcport->old_loop_id = + fcport->loop_id; + ql_dbg(ql_dbg_disc, vha, 0x2003, + "Port login OK: logged in ID 0x%x.\n", + fcport->loop_id); + qla2x00_update_fcport + (vha, fcport); + } else if (status == 1) { + set_bit(RELOGIN_NEEDED, + &vha->dpc_flags); + /* retry the login again */ + ql_dbg(ql_dbg_disc, vha, 0x2007, + "Retrying %d login again loop_id 0x%x.\n", + fcport->login_retry, + fcport->loop_id); + } else { + fcport->login_retry = 0; + } + + if (fcport->login_retry == 0 && + status != QLA_SUCCESS) + qla2x00_clear_loop_id(fcport); + } } } if (test_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags)) break; } + if (relogin_needed) + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + ql_dbg(ql_dbg_disc, vha, 0x400e, "Relogin end.\n"); } @@ -6023,12 +6285,29 @@ qla2x00_do_dpc(void *data) if (test_and_clear_bit (ISP_ABORT_NEEDED, &base_vha->dpc_flags) && !test_bit(UNLOADING, &base_vha->dpc_flags)) { + bool do_reset = true; - ql_dbg(ql_dbg_dpc, base_vha, 0x4007, - "ISP abort scheduled.\n"); - if (!(test_and_set_bit(ABORT_ISP_ACTIVE, + switch (base_vha->qlini_mode) { + case QLA2XXX_INI_MODE_ENABLED: + break; + case QLA2XXX_INI_MODE_DISABLED: + if (!qla_tgt_mode_enabled(base_vha) && + !ha->flags.fw_started) + do_reset = false; + break; + case QLA2XXX_INI_MODE_DUAL: + if (!qla_dual_mode_enabled(base_vha) && + !ha->flags.fw_started) + do_reset = false; + break; + default: + break; + } + + if (do_reset && !(test_and_set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags))) { - + ql_dbg(ql_dbg_dpc, base_vha, 0x4007, + "ISP abort scheduled.\n"); if (ha->isp_ops->abort_isp(base_vha)) { /* failed. retry later */ set_bit(ISP_ABORT_NEEDED, @@ -6036,10 +6315,9 @@ qla2x00_do_dpc(void *data) } clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + ql_dbg(ql_dbg_dpc, base_vha, 0x4008, + "ISP abort end.\n"); } - - ql_dbg(ql_dbg_dpc, base_vha, 0x4008, - "ISP abort end.\n"); } if (test_and_clear_bit(FCPORT_UPDATE_NEEDED, @@ -6165,20 +6443,36 @@ intr_on_check: mutex_unlock(&ha->mq_lock); } - if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, &base_vha->dpc_flags)) { + if (test_and_clear_bit(SET_NVME_ZIO_THRESHOLD_NEEDED, + &base_vha->dpc_flags)) { ql_log(ql_log_info, base_vha, 0xffffff, "nvme: SET ZIO Activity exchange threshold to %d.\n", ha->nvme_last_rptd_aen); - if (qla27xx_set_zio_threshold(base_vha, ha->nvme_last_rptd_aen)) { + if (qla27xx_set_zio_threshold(base_vha, + ha->nvme_last_rptd_aen)) { ql_log(ql_log_info, base_vha, 0xffffff, - "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n", - ha->nvme_last_rptd_aen); + "nvme: Unable to SET ZIO Activity exchange threshold to %d.\n", + ha->nvme_last_rptd_aen); } } + if (test_and_clear_bit(SET_ZIO_THRESHOLD_NEEDED, + &base_vha->dpc_flags)) { + ql_log(ql_log_info, base_vha, 0xffffff, + "SET ZIO Activity exchange threshold to %d.\n", + ha->last_zio_threshold); + qla27xx_set_zio_threshold(base_vha, + ha->last_zio_threshold); + } + if (!IS_QLAFX00(ha)) qla2x00_do_dpc_all_vps(base_vha); + if (test_and_clear_bit(N2N_LINK_RESET, + &base_vha->dpc_flags)) { + qla2x00_lip_reset(base_vha); + } + ha->dpc_active = 0; end_loop: set_current_state(TASK_INTERRUPTIBLE); @@ -6383,13 +6677,24 @@ qla2x00_timer(struct timer_list *t) * FC-NVME * see if the active AEN count has changed from what was last reported. */ - if (!vha->vp_idx && - atomic_read(&ha->nvme_active_aen_cnt) != ha->nvme_last_rptd_aen && - ha->zio_mode == QLA_ZIO_MODE_6) { + if (!vha->vp_idx && (atomic_read(&ha->nvme_active_aen_cnt) != + ha->nvme_last_rptd_aen) && ha->zio_mode == QLA_ZIO_MODE_6) { ql_log(ql_log_info, vha, 0x3002, - "nvme: Sched: Set ZIO exchange threshold to %d.\n", - ha->nvme_last_rptd_aen); + "nvme: Sched: Set ZIO exchange threshold to %d.\n", + ha->nvme_last_rptd_aen); ha->nvme_last_rptd_aen = atomic_read(&ha->nvme_active_aen_cnt); + set_bit(SET_NVME_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); + start_dpc++; + } + + if (!vha->vp_idx && + (atomic_read(&ha->zio_threshold) != ha->last_zio_threshold) && + (ha->zio_mode == QLA_ZIO_MODE_6) && + (IS_QLA83XX(ha) || IS_QLA27XX(ha))) { + ql_log(ql_log_info, vha, 0x3002, + "Sched: Set ZIO exchange threshold to %d.\n", + ha->last_zio_threshold); + ha->last_zio_threshold = atomic_read(&ha->zio_threshold); set_bit(SET_ZIO_THRESHOLD_NEEDED, &vha->dpc_flags); start_dpc++; } @@ -6816,20 +7121,70 @@ qla2xxx_pci_resume(struct pci_dev *pdev) "The device failed to resume I/O from slot/link_reset.\n"); } - pci_cleanup_aer_uncorrect_error_status(pdev); - ha->flags.eeh_busy = 0; } +static void +qla_pci_reset_prepare(struct pci_dev *pdev) +{ + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + struct qla_hw_data *ha = base_vha->hw; + struct qla_qpair *qpair; + + ql_log(ql_log_warn, base_vha, 0xffff, + "%s.\n", __func__); + + /* + * PCI FLR/function reset is about to reset the + * slot. Stop the chip to stop all DMA access. + * It is assumed that pci_reset_done will be called + * after FLR to resume Chip operation. + */ + ha->flags.eeh_busy = 1; + mutex_lock(&ha->mq_lock); + list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) + qpair->online = 0; + mutex_unlock(&ha->mq_lock); + + set_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); + qla2x00_abort_isp_cleanup(base_vha); + qla2x00_abort_all_cmds(base_vha, DID_RESET << 16); +} + +static void +qla_pci_reset_done(struct pci_dev *pdev) +{ + scsi_qla_host_t *base_vha = pci_get_drvdata(pdev); + struct qla_hw_data *ha = base_vha->hw; + struct qla_qpair *qpair; + + ql_log(ql_log_warn, base_vha, 0xffff, + "%s.\n", __func__); + + /* + * FLR just completed by PCI layer. Resume adapter + */ + ha->flags.eeh_busy = 0; + mutex_lock(&ha->mq_lock); + list_for_each_entry(qpair, &base_vha->qp_list, qp_list_elem) + qpair->online = 1; + mutex_unlock(&ha->mq_lock); + + base_vha->flags.online = 1; + ha->isp_ops->abort_isp(base_vha); + clear_bit(ABORT_ISP_ACTIVE, &base_vha->dpc_flags); +} + static int qla2xxx_map_queues(struct Scsi_Host *shost) { int rc; scsi_qla_host_t *vha = (scsi_qla_host_t *)shost->hostdata; + struct blk_mq_queue_map *qmap = &shost->tag_set.map[0]; - if (USER_CTRL_IRQ(vha->hw)) - rc = blk_mq_map_queues(&shost->tag_set); + if (USER_CTRL_IRQ(vha->hw) || !vha->hw->mqiobase) + rc = blk_mq_map_queues(qmap); else - rc = blk_mq_pci_map_queues(&shost->tag_set, vha->hw->pdev, 0); + rc = blk_mq_pci_map_queues(qmap, vha->hw->pdev, vha->irq_offset); return rc; } @@ -6838,6 +7193,8 @@ static const struct pci_error_handlers qla2xxx_err_handler = { .mmio_enabled = qla2xxx_pci_mmio_enabled, .slot_reset = qla2xxx_pci_slot_reset, .resume = qla2xxx_pci_resume, + .reset_prepare = qla_pci_reset_prepare, + .reset_done = qla_pci_reset_done, }; static struct pci_device_id qla2xxx_pci_tbl[] = { @@ -6923,6 +7280,9 @@ qla2x00_module_init(void) if (ql2xextended_error_logging == 1) ql2xextended_error_logging = QL_DBG_DEFAULT1_MASK; + if (ql2x_ini_mode == QLA2XXX_INI_MODE_DUAL) + qla_insert_tgt_attrs(); + qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions); if (!qla2xxx_transport_template) { @@ -6976,8 +7336,7 @@ qla2x00_module_exit(void) qla2x00_release_firmware(); kmem_cache_destroy(srb_cachep); qlt_exit(); - if (ctx_cachep) - kmem_cache_destroy(ctx_cachep); + kmem_cache_destroy(ctx_cachep); fc_release_transport(qla2xxx_transport_template); fc_release_transport(qla2xxx_transport_vport_template); } diff --git a/qla2x00t-32gbit/qla_sup.c b/qla2x00t-32gbit/qla_sup.c index 4499c7871..2a3055c79 100644 --- a/qla2x00t-32gbit/qla_sup.c +++ b/qla2x00t-32gbit/qla_sup.c @@ -2229,7 +2229,7 @@ qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr, /** * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip. - * @ha: + * @ha: host adapter * @man_id: Flash manufacturer ID * @flash_id: Flash ID */ diff --git a/qla2x00t-32gbit/qla_target.c b/qla2x00t-32gbit/qla_target.c index 776651b07..c23ca849b 100644 --- a/qla2x00t-32gbit/qla_target.c +++ b/qla2x00t-32gbit/qla_target.c @@ -141,6 +141,8 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *, struct abts_recv_from_24xx *); static void qlt_send_busy(struct qla_qpair *, struct atio_from_isp *, uint16_t); +static int qlt_check_reserve_free_req(struct qla_qpair *qpair, uint32_t); +static inline uint32_t qlt_make_handle(struct qla_qpair *); /* * Global Variables @@ -542,7 +544,6 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, qlt_response_pkt(host, rsp, pkt); break; } - default: qlt_response_pkt(vha, rsp, pkt); break; @@ -601,14 +602,9 @@ void qla2x00_async_nack_sp_done(void *s, int res) sp->fcport->login_succ = 1; vha->fcport_count++; - - ql_dbg(ql_dbg_disc, vha, 0x20f3, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, - sp->fcport->port_name, - vha->fcport_count); - sp->fcport->disc_state = DSC_UPD_FCPORT; - qla24xx_post_upd_fcport_work(vha, sp->fcport); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + qla24xx_sched_upd_fcport(sp->fcport); + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); } else { sp->fcport->login_retry = 0; sp->fcport->disc_state = DSC_LOGIN_COMPLETE; @@ -665,14 +661,14 @@ int qla24xx_async_notify_ack(scsi_qla_host_t *vha, fc_port_t *fcport, sp->u.iocb_cmd.u.nack.ntfy = ntfy; sp->done = qla2x00_async_nack_sp_done; - rval = qla2x00_start_sp(sp); - if (rval != QLA_SUCCESS) - goto done_free_sp; - ql_dbg(ql_dbg_disc, vha, 0x20f4, "Async-%s %8phC hndl %x %s\n", sp->name, fcport->port_name, sp->handle, c); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) + goto done_free_sp; + return rval; done_free_sp: @@ -689,6 +685,9 @@ void qla24xx_do_nack_work(struct scsi_qla_host *vha, struct qla_work_evt *e) switch (e->u.nack.type) { case SRB_NACK_PRLI: + t = e->u.nack.fcport; + flush_work(&t->del_work); + flush_work(&t->free_work); mutex_lock(&vha->vha_tgt.tgt_mutex); t = qlt_create_sess(vha, e->u.nack.fcport, 0); mutex_unlock(&vha->vha_tgt.tgt_mutex); @@ -806,6 +805,10 @@ qlt_plogi_ack_find_add(struct scsi_qla_host *vha, port_id_t *id, list_for_each_entry(pla, &vha->plogi_ack_list, list) { if (pla->id.b24 == id->b24) { + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0x210d, + "%s %d %8phC Term INOT due to new INOT", + __func__, __LINE__, + pla->iocb.u.isp24.port_name); qlt_send_term_imm_notif(vha, &pla->iocb, 1); memcpy(&pla->iocb, iocb, sizeof(pla->iocb)); return pla; @@ -1055,7 +1058,6 @@ void qlt_free_session_done(struct work_struct *work) sess->disc_state = DSC_DELETED; sess->fw_login_state = DSC_LS_PORT_UNAVAIL; sess->deleted = QLA_SESS_DELETED; - sess->login_retry = vha->hw->login_retry_count; if (sess->login_succ && !IS_SW_RESV_ADDR(sess->d_id)) { vha->fcport_count--; @@ -1075,6 +1077,7 @@ void qlt_free_session_done(struct work_struct *work) struct qlt_plogi_ack_t *con = sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]; struct imm_ntfy_from_isp *iocb; + own = sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN]; if (con) { iocb = &con->iocb; @@ -1158,7 +1161,7 @@ void qlt_unreg_sess(struct fc_port *sess) if (sess->se_sess) vha->hw->tgt.tgt_ops->clear_nacl_from_fcport_map(sess); - qla2x00_mark_device_lost(vha, sess, 1, 1); + qla2x00_mark_device_lost(vha, sess, 0, 0); sess->deleted = QLA_SESS_DELETION_IN_PROGRESS; sess->disc_state = DSC_DELETE_PEND; @@ -1227,11 +1230,12 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) { struct qla_tgt *tgt = sess->tgt; unsigned long flags; + u16 sec; - if (sess->disc_state == DSC_DELETE_PEND) + switch (sess->disc_state) { + case DSC_DELETE_PEND: return; - - if (sess->disc_state == DSC_DELETED) { + case DSC_DELETED: if (tgt && tgt->tgt_stop && (tgt->sess_count == 0)) wake_up_all(&tgt->waitQ); if (sess->vha->fcport_count == 0) @@ -1240,11 +1244,26 @@ void qlt_schedule_sess_for_deletion(struct fc_port *sess) if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] && !sess->plogi_link[QLT_PLOGI_LINK_CONFLICT]) return; + break; + case DSC_UPD_FCPORT: + /* + * This port is not done reporting to upper layer. + * let it finish + */ + sess->next_disc_state = DSC_DELETE_PEND; + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration)/1000; + if (sess->sec_since_registration < sec && sec && !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, sess->vha, 0xffff, + "%s %8phC : Slow Rport registration(%d Sec)\n", + __func__, sess->port_name, sec); + } + return; + default: + break; } - if (sess->deleted == QLA_SESS_DELETED) - sess->logout_on_delete = 0; - spin_lock_irqsave(&sess->vha->work_lock, flags); if (sess->deleted == QLA_SESS_DELETION_IN_PROGRESS) { spin_unlock_irqrestore(&sess->vha->work_lock, flags); @@ -1477,27 +1496,14 @@ int qlt_stop_phase1(struct qla_tgt *tgt) struct qla_hw_data *ha = tgt->ha; unsigned long flags; + mutex_lock(&ha->optrom_mutex); mutex_lock(&qla_tgt_mutex); - if (!vha->fc_vport) { - struct Scsi_Host *sh = vha->host; - struct fc_host_attrs *fc_host = shost_to_fc_host(sh); - bool npiv_vports; - spin_lock_irqsave(sh->host_lock, flags); - npiv_vports = (fc_host->npiv_vports_inuse); - spin_unlock_irqrestore(sh->host_lock, flags); - - if (npiv_vports) { - mutex_unlock(&qla_tgt_mutex); - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, - "NPIV is in use. Can not stop target\n"); - return -EPERM; - } - } if (tgt->tgt_stop || tgt->tgt_stopped) { ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04e, "Already in tgt->tgt_stop or tgt_stopped state\n"); mutex_unlock(&qla_tgt_mutex); + mutex_unlock(&ha->optrom_mutex); return -EPERM; } @@ -1535,6 +1541,8 @@ int qlt_stop_phase1(struct qla_tgt *tgt) /* Wait for sessions to clear out (just in case) */ wait_event_timeout(tgt->waitQ, test_tgt_sess_count(tgt), 10*HZ); + mutex_unlock(&ha->optrom_mutex); + return 0; } EXPORT_SYMBOL(qlt_stop_phase1); @@ -1564,6 +1572,15 @@ void qlt_stop_phase2(struct qla_tgt *tgt) ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished\n", tgt); + + switch (vha->qlini_mode) { + case QLA2XXX_INI_MODE_EXCLUSIVE: + vha->flags.online = 1; + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + break; + default: + break; + } } EXPORT_SYMBOL(qlt_stop_phase2); @@ -1713,6 +1730,94 @@ static void qlt_send_notify_ack(struct qla_qpair *qpair, qla2x00_start_iocbs(vha, qpair->req); } +static int qlt_build_abts_resp_iocb(struct qla_tgt_mgmt_cmd *mcmd) +{ + struct scsi_qla_host *vha = mcmd->vha; + struct qla_hw_data *ha = vha->hw; + struct abts_resp_to_24xx *resp; + uint32_t f_ctl, h; + uint8_t *p; + int rc; + struct abts_recv_from_24xx *abts = &mcmd->orig_iocb.abts; + struct qla_qpair *qpair = mcmd->qpair; + + ql_dbg(ql_dbg_tgt, vha, 0xe006, + "Sending task mgmt ABTS response (ha=%p, status=%x)\n", + ha, mcmd->fc_tm_rsp); + + rc = qlt_check_reserve_free_req(qpair, 1); + if (rc) { + ql_dbg(ql_dbg_tgt, vha, 0xe04a, + "qla_target(%d): %s failed: unable to allocate request packet\n", + vha->vp_idx, __func__); + return -EAGAIN; + } + + resp = (struct abts_resp_to_24xx *)qpair->req->ring_ptr; + memset(resp, 0, sizeof(*resp)); + + h = qlt_make_handle(qpair); + if (unlikely(h == QLA_TGT_NULL_HANDLE)) { + /* + * CTIO type 7 from the firmware doesn't provide a way to + * know the initiator's LOOP ID, hence we can't find + * the session and, so, the command. + */ + return -EAGAIN; + } else { + qpair->req->outstanding_cmds[h] = (srb_t *)mcmd; + } + + resp->handle = MAKE_HANDLE(qpair->req->id, h); + resp->entry_type = ABTS_RESP_24XX; + resp->entry_count = 1; + resp->nport_handle = abts->nport_handle; + resp->vp_index = vha->vp_idx; + resp->sof_type = abts->sof_type; + resp->exchange_address = abts->exchange_address; + resp->fcp_hdr_le = abts->fcp_hdr_le; + f_ctl = cpu_to_le32(F_CTL_EXCH_CONTEXT_RESP | + F_CTL_LAST_SEQ | F_CTL_END_SEQ | + F_CTL_SEQ_INITIATIVE); + p = (uint8_t *)&f_ctl; + resp->fcp_hdr_le.f_ctl[0] = *p++; + resp->fcp_hdr_le.f_ctl[1] = *p++; + resp->fcp_hdr_le.f_ctl[2] = *p; + + resp->fcp_hdr_le.d_id[0] = abts->fcp_hdr_le.s_id[0]; + resp->fcp_hdr_le.d_id[1] = abts->fcp_hdr_le.s_id[1]; + resp->fcp_hdr_le.d_id[2] = abts->fcp_hdr_le.s_id[2]; + resp->fcp_hdr_le.s_id[0] = abts->fcp_hdr_le.d_id[0]; + resp->fcp_hdr_le.s_id[1] = abts->fcp_hdr_le.d_id[1]; + resp->fcp_hdr_le.s_id[2] = abts->fcp_hdr_le.d_id[2]; + + resp->exchange_addr_to_abort = abts->exchange_addr_to_abort; + if (mcmd->fc_tm_rsp == FCP_TMF_CMPL) { + resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_ACC; + resp->payload.ba_acct.seq_id_valid = SEQ_ID_INVALID; + resp->payload.ba_acct.low_seq_cnt = 0x0000; + resp->payload.ba_acct.high_seq_cnt = 0xFFFF; + resp->payload.ba_acct.ox_id = abts->fcp_hdr_le.ox_id; + resp->payload.ba_acct.rx_id = abts->fcp_hdr_le.rx_id; + } else { + resp->fcp_hdr_le.r_ctl = R_CTL_BASIC_LINK_SERV | R_CTL_B_RJT; + resp->payload.ba_rjt.reason_code = + BA_RJT_REASON_CODE_UNABLE_TO_PERFORM; + /* Other bytes are zero */ + } + + vha->vha_tgt.qla_tgt->abts_resp_expected++; + + /* Memory Barrier */ + wmb(); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); + + return rc; +} + /* * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ @@ -1740,6 +1845,7 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, } resp->entry_type = ABTS_RESP_24XX; + resp->handle = QLA_TGT_SKIP_HANDLE; resp->entry_count = 1; resp->nport_handle = abts->nport_handle; resp->vp_index = vha->vp_idx; @@ -1797,15 +1903,13 @@ static void qlt_24xx_send_abts_resp(struct qla_qpair *qpair, * ha->hardware_lock supposed to be held on entry. Might drop it, then reaquire */ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, - struct abts_resp_from_24xx_fw *entry) + struct qla_qpair *qpair, response_t *pkt, struct qla_tgt_mgmt_cmd *mcmd) { struct ctio7_to_24xx *ctio; + u16 tmp; + struct abts_recv_from_24xx *entry; - ql_dbg(ql_dbg_tgt, vha, 0xe007, - "Sending retry TERM EXCH CTIO7 (ha=%p)\n", vha->hw); - - ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready( - vha->hw->base_qpair, NULL); + ctio = (struct ctio7_to_24xx *)qla2x00_alloc_iocbs_ready(qpair, NULL); if (ctio == NULL) { ql_dbg(ql_dbg_tgt, vha, 0xe04b, "qla_target(%d): %s failed: unable to allocate " @@ -1813,6 +1917,13 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, return; } + if (mcmd) + /* abts from remote port */ + entry = &mcmd->orig_iocb.abts; + else + /* abts from this driver. */ + entry = (struct abts_recv_from_24xx *)pkt; + /* * We've got on entrance firmware's response on by us generated * ABTS response. So, in it ID fields are reversed. @@ -1824,56 +1935,48 @@ static void qlt_24xx_retry_term_exchange(struct scsi_qla_host *vha, ctio->handle = QLA_TGT_SKIP_HANDLE | CTIO_COMPLETION_HANDLE_MARK; ctio->timeout = cpu_to_le16(QLA_TGT_TIMEOUT); ctio->vp_index = vha->vp_idx; - ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; - ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; - ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; ctio->exchange_addr = entry->exchange_addr_to_abort; - ctio->u.status1.flags = cpu_to_le16(CTIO7_FLAGS_STATUS_MODE_1 | - CTIO7_FLAGS_TERMINATE); - ctio->u.status1.ox_id = cpu_to_le16(entry->fcp_hdr_le.ox_id); + tmp = (CTIO7_FLAGS_STATUS_MODE_1 | CTIO7_FLAGS_TERMINATE); + + if (mcmd) { + ctio->initiator_id[0] = entry->fcp_hdr_le.s_id[0]; + ctio->initiator_id[1] = entry->fcp_hdr_le.s_id[1]; + ctio->initiator_id[2] = entry->fcp_hdr_le.s_id[2]; + + if (mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) + tmp |= (mcmd->abort_io_attr << 9); + else if (qpair->retry_term_cnt & 1) + tmp |= (0x4 << 9); + } else { + ctio->initiator_id[0] = entry->fcp_hdr_le.d_id[0]; + ctio->initiator_id[1] = entry->fcp_hdr_le.d_id[1]; + ctio->initiator_id[2] = entry->fcp_hdr_le.d_id[2]; + + if (qpair->retry_term_cnt & 1) + tmp |= (0x4 << 9); + } + ctio->u.status1.flags = cpu_to_le16(tmp); + ctio->u.status1.ox_id = entry->fcp_hdr_le.ox_id; + + ql_dbg(ql_dbg_tgt, vha, 0xe007, + "Sending retry TERM EXCH CTIO7 flags %04xh oxid %04xh attr valid %x\n", + le16_to_cpu(ctio->u.status1.flags), + le16_to_cpu(ctio->u.status1.ox_id), + (mcmd && mcmd->flags & QLA24XX_MGMT_ABORT_IO_ATTR_VALID) ? 1 : 0); /* Memory Barrier */ wmb(); - qla2x00_start_iocbs(vha, vha->req); + if (qpair->reqq_start_iocbs) + qpair->reqq_start_iocbs(qpair); + else + qla2x00_start_iocbs(vha, qpair->req); - qlt_24xx_send_abts_resp(vha->hw->base_qpair, - (struct abts_recv_from_24xx *)entry, - FCP_TMF_CMPL, true); -} + if (mcmd) + qlt_build_abts_resp_iocb(mcmd); + else + qlt_24xx_send_abts_resp(qpair, + (struct abts_recv_from_24xx *)entry, FCP_TMF_CMPL, true); -static int abort_cmd_for_tag(struct scsi_qla_host *vha, uint32_t tag) -{ - struct qla_tgt_sess_op *op; - struct qla_tgt_cmd *cmd; - unsigned long flags; - - spin_lock_irqsave(&vha->cmd_list_lock, flags); - list_for_each_entry(op, &vha->qla_sess_op_cmd_list, cmd_list) { - if (tag == op->atio.u.isp24.exchange_addr) { - op->aborted = true; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - - list_for_each_entry(op, &vha->unknown_atio_list, cmd_list) { - if (tag == op->atio.u.isp24.exchange_addr) { - op->aborted = true; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - - list_for_each_entry(cmd, &vha->qla_cmd_list, cmd_list) { - if (tag == cmd->atio.u.isp24.exchange_addr) { - cmd->aborted = 1; - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - return 1; - } - } - spin_unlock_irqrestore(&vha->cmd_list_lock, flags); - - return 0; } /* drop cmds for the given lun @@ -1968,9 +2071,8 @@ static void qlt_do_tmr_work(struct work_struct *work) spin_lock_irqsave(mcmd->qpair->qp_lock_ptr, flags); switch (mcmd->tmr_func) { case QLA_TGT_ABTS: - qlt_24xx_send_abts_resp(mcmd->qpair, - &mcmd->orig_iocb.abts, - FCP_TMF_REJECTED, false); + mcmd->fc_tm_rsp = FCP_TMF_REJECTED; + qlt_build_abts_resp_iocb(mcmd); break; case QLA_TGT_LUN_RESET: case QLA_TGT_CLEAR_TS: @@ -2005,12 +2107,6 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, struct qla_tgt_mgmt_cmd *mcmd; struct qla_qpair_hint *h = &vha->vha_tgt.qla_tgt->qphints[0]; - if (abort_cmd_for_tag(vha, abts->exchange_addr_to_abort)) { - /* send TASK_ABORT response immediately */ - qlt_24xx_send_abts_resp(ha->base_qpair, abts, FCP_TMF_CMPL, false); - return 0; - } - ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00f, "qla_target(%d): task abort (tag=%d)\n", vha->vp_idx, abts->exchange_addr_to_abort); @@ -2023,7 +2119,7 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, return -ENOMEM; } memset(mcmd, 0, sizeof(*mcmd)); - + mcmd->cmd_type = TYPE_TGT_TMCMD; mcmd->sess = sess; memcpy(&mcmd->orig_iocb.abts, abts, sizeof(mcmd->orig_iocb.abts)); mcmd->reset_count = ha->base_qpair->chip_reset; @@ -2045,6 +2141,8 @@ static int __qlt_24xx_handle_abts(struct scsi_qla_host *vha, if (abort_cmd && abort_cmd->qpair) { mcmd->qpair = abort_cmd->qpair; mcmd->se_cmd.cpuid = abort_cmd->se_cmd.cpuid; + mcmd->abort_io_attr = abort_cmd->atio.u.isp24.attr; + mcmd->flags = QLA24XX_MGMT_ABORT_IO_ATTR_VALID; } } @@ -2262,6 +2360,7 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) struct qla_hw_data *ha = vha->hw; unsigned long flags; struct qla_qpair *qpair = mcmd->qpair; + bool free_mcmd = true; ql_dbg(ql_dbg_tgt_mgt, vha, 0xf013, "TM response mcmd (%p) status %#x state %#x", @@ -2284,26 +2383,26 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) } if (mcmd->flags == QLA24XX_MGMT_SEND_NACK) { - if (mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == - ELS_LOGO || - mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == - ELS_PRLO || - mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode == - ELS_TPRLO) { + switch (mcmd->orig_iocb.imm_ntfy.u.isp24.status_subcode) { + case ELS_LOGO: + case ELS_PRLO: + case ELS_TPRLO: ql_dbg(ql_dbg_disc, vha, 0x2106, "TM response logo %phC status %#x state %#x", mcmd->sess->port_name, mcmd->fc_tm_rsp, mcmd->flags); qlt_schedule_sess_for_deletion(mcmd->sess); - } else { + break; + default: qlt_send_notify_ack(vha->hw->base_qpair, &mcmd->orig_iocb.imm_ntfy, 0, 0, 0, 0, 0, 0); + break; } } else { - if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) - qlt_24xx_send_abts_resp(qpair, &mcmd->orig_iocb.abts, - mcmd->fc_tm_rsp, false); - else + if (mcmd->orig_iocb.atio.u.raw.entry_type == ABTS_RECV_24XX) { + qlt_build_abts_resp_iocb(mcmd); + free_mcmd = false; + } else qlt_24xx_send_task_mgmt_ctio(qpair, mcmd, mcmd->fc_tm_rsp); } @@ -2315,7 +2414,9 @@ void qlt_xmit_tm_rsp(struct qla_tgt_mgmt_cmd *mcmd) * descriptor after TFO->queue_tm_rsp() -> tcm_qla2xxx_queue_tm_rsp() -> * qlt_xmit_tm_rsp() returns here.. */ - ha->tgt.tgt_ops->free_mcmd(mcmd); + if (free_mcmd) + ha->tgt.tgt_ops->free_mcmd(mcmd); + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); } EXPORT_SYMBOL(qlt_xmit_tm_rsp); @@ -2328,7 +2429,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) BUG_ON(cmd->sg_cnt == 0); prm->sg = (struct scatterlist *)cmd->sg; - prm->seg_cnt = pci_map_sg(cmd->qpair->pdev, cmd->sg, + prm->seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); if (unlikely(prm->seg_cnt == 0)) goto out_err; @@ -2355,7 +2456,7 @@ static int qlt_pci_map_calc_cnt(struct qla_tgt_prm *prm) if (cmd->prot_sg_cnt) { prm->prot_sg = cmd->prot_sg; - prm->prot_seg_cnt = pci_map_sg(cmd->qpair->pdev, + prm->prot_seg_cnt = dma_map_sg(&cmd->qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (unlikely(prm->prot_seg_cnt == 0)) @@ -2390,12 +2491,12 @@ static void qlt_unmap_sg(struct scsi_qla_host *vha, struct qla_tgt_cmd *cmd) qpair = cmd->qpair; - pci_unmap_sg(qpair->pdev, cmd->sg, cmd->sg_cnt, + dma_unmap_sg(&qpair->pdev->dev, cmd->sg, cmd->sg_cnt, cmd->dma_data_direction); cmd->sg_mapped = 0; if (cmd->prot_sg_cnt) - pci_unmap_sg(qpair->pdev, cmd->prot_sg, cmd->prot_sg_cnt, + dma_unmap_sg(&qpair->pdev->dev, cmd->prot_sg, cmd->prot_sg_cnt, cmd->dma_data_direction); if (!cmd->ctx) @@ -2563,9 +2664,9 @@ static void qlt_load_cont_data_segments(struct qla_tgt_prm *prm) cnt < QLA_TGT_DATASEGS_PER_CONT_24XX && prm->seg_cnt; cnt++, prm->seg_cnt--) { *dword_ptr++ = - cpu_to_le32(pci_dma_lo32 + cpu_to_le32(lower_32_bits (sg_dma_address(prm->sg))); - *dword_ptr++ = cpu_to_le32(pci_dma_hi32 + *dword_ptr++ = cpu_to_le32(upper_32_bits (sg_dma_address(prm->sg))); *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); @@ -2607,9 +2708,9 @@ static void qlt_load_data_segments(struct qla_tgt_prm *prm) (cnt < QLA_TGT_DATASEGS_PER_CMD_24XX) && prm->seg_cnt; cnt++, prm->seg_cnt--) { *dword_ptr++ = - cpu_to_le32(pci_dma_lo32(sg_dma_address(prm->sg))); + cpu_to_le32(lower_32_bits(sg_dma_address(prm->sg))); - *dword_ptr++ = cpu_to_le32(pci_dma_hi32( + *dword_ptr++ = cpu_to_le32(upper_32_bits( sg_dma_address(prm->sg))); *dword_ptr++ = cpu_to_le32(sg_dma_len(prm->sg)); @@ -3133,7 +3234,7 @@ qlt_build_ctio_crc2_pkt(struct qla_qpair *qpair, struct qla_tgt_prm *prm) cur_dsd = (uint32_t *) &crc_ctx_pkt->u.bundling.dif_address; if (qla24xx_walk_and_build_prot_sglist(ha, NULL, cur_dsd, - prm->prot_seg_cnt, &tc)) + prm->prot_seg_cnt, cmd)) goto crc_queuing_error; } return QLA_SUCCESS; @@ -3160,13 +3261,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, unsigned long flags = 0; int res; - if (cmd->sess && cmd->sess->deleted) { + if (!qpair->fw_started || (cmd->reset_count != qpair->chip_reset) || + (cmd->sess && cmd->sess->deleted)) { cmd->state = QLA_TGT_STATE_PROCESSED; - if (cmd->sess->logout_completed) - /* no need to terminate. FW already freed exchange. */ - qlt_abort_cmd_on_host_reset(cmd->vha, cmd); - else - qlt_send_term_exchange(qpair, cmd, &cmd->atio, 0, 0); + qlt_abort_cmd_on_host_reset(cmd->vha, cmd); return 0; } @@ -3287,7 +3385,10 @@ int qlt_xmit_response(struct qla_tgt_cmd *cmd, int xmit_type, cmd->state = QLA_TGT_STATE_PROCESSED; /* Mid-level is done processing */ + spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; + spin_unlock(&cmd->cmd_lock); + cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ wmb(); @@ -3365,7 +3466,10 @@ int qlt_rdy_to_xfer(struct qla_tgt_cmd *cmd) qlt_load_data_segments(&prm); cmd->state = QLA_TGT_STATE_NEED_DATA; + spin_lock(&cmd->cmd_lock); cmd->cmd_sent_to_fw = 1; + spin_unlock(&cmd->cmd_lock); + cmd->ctio_flags = le16_to_cpu(pkt->u.status0.flags); /* Memory Barrier */ wmb(); @@ -3823,10 +3927,10 @@ static int qlt_term_ctio_exchange(struct qla_qpair *qpair, void *ctio, /* ha->hardware_lock supposed to be held on entry */ -static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, +static void *qlt_ctio_to_cmd(struct scsi_qla_host *vha, struct rsp_que *rsp, uint32_t handle, void *ctio) { - struct qla_tgt_cmd *cmd = NULL; + void *cmd = NULL; struct req_que *req; int qid = GET_QID(handle); uint32_t h = handle & ~QLA_TGT_HANDLE_MASK; @@ -3855,7 +3959,7 @@ static struct qla_tgt_cmd *qlt_ctio_to_cmd(struct scsi_qla_host *vha, return NULL; } - cmd = (struct qla_tgt_cmd *)req->outstanding_cmds[h]; + cmd = (void *) req->outstanding_cmds[h]; if (unlikely(cmd == NULL)) { ql_dbg(ql_dbg_async, vha, 0xe053, "qla_target(%d): Suspicious: unable to find the command with handle %x req->id %d rsp->id %d\n", @@ -3928,7 +4032,7 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, return; } - cmd = qlt_ctio_to_cmd(vha, rsp, handle, ctio); + cmd = (struct qla_tgt_cmd *)qlt_ctio_to_cmd(vha, rsp, handle, ctio); if (cmd == NULL) return; @@ -3939,12 +4043,20 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, if (unlikely(status != CTIO_SUCCESS)) { switch (status & 0xFFFF) { + case CTIO_INVALID_RX_ID: + if (printk_ratelimit()) + dev_info(&vha->hw->pdev->dev, + "qla_target(%d): CTIO with INVALID_RX_ID ATIO attr %x CTIO Flags %x|%x\n", + vha->vp_idx, cmd->atio.u.isp24.attr, + ((cmd->ctio_flags >> 9) & 0xf), + cmd->ctio_flags); + + break; case CTIO_LIP_RESET: case CTIO_TARGET_RESET: case CTIO_ABORTED: /* driver request abort via Terminate exchange */ case CTIO_TIMEOUT: - case CTIO_INVALID_RX_ID: /* They are OK */ ql_dbg(ql_dbg_tgt_mgt, vha, 0xf058, "qla_target(%d): CTIO with " @@ -3971,7 +4083,6 @@ static void qlt_do_ctio_completion(struct scsi_qla_host *vha, * Session is already logged out, but we need * to notify initiator, who's not aware of this */ - cmd->sess->logout_on_delete = 0; cmd->sess->send_els_logo = 1; ql_dbg(ql_dbg_disc, vha, 0x20f8, "%s %d %8phC post del sess\n", @@ -4703,6 +4814,12 @@ static int qlt_handle_login(struct scsi_qla_host *vha, sess = qlt_find_sess_invalidate_other(vha, wwn, port_id, loop_id, &conflict_sess); spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + } else { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d Term INOT due to WWN=0 lid=%d, NportID %06X ", + __func__, __LINE__, loop_id, port_id.b24); + qlt_send_term_imm_notif(vha, iocb, 1); + goto out; } if (IS_SW_RESV_ADDR(port_id)) { @@ -4712,6 +4829,10 @@ static int qlt_handle_login(struct scsi_qla_host *vha, pla = qlt_plogi_ack_find_add(vha, &port_id, iocb); if (!pla) { + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, + "%s %d %8phC Term INOT due to mem alloc fail", + __func__, __LINE__, + iocb->u.isp24.port_name); qlt_send_term_imm_notif(vha, iocb, 1); goto out; } @@ -4740,6 +4861,32 @@ static int qlt_handle_login(struct scsi_qla_host *vha, goto out; } + if (sess->disc_state == DSC_UPD_FCPORT) { + u16 sec; + + /* + * Remote port registration is still going on from + * previous login. Allow it to finish before we + * accept the new login. + */ + sess->next_disc_state = DSC_DELETE_PEND; + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration) / 1000; + if (sess->sec_since_registration < sec && sec && + !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %8phC - Slow Rport registration (%d Sec)\n", + __func__, sess->port_name, sec); + } + + if (!conflict_sess) + kmem_cache_free(qla_tgt_plogi_cachep, pla); + + qlt_send_term_imm_notif(vha, iocb, 1); + goto out; + } + qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN); sess->d_id = port_id; sess->login_gen++; @@ -4898,6 +5045,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, if (sess != NULL) { bool delete = false; + int sec; spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags); switch (sess->fw_login_state) { case DSC_LS_PLOGI_PEND: @@ -4910,9 +5058,24 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha, } switch (sess->disc_state) { + case DSC_UPD_FCPORT: + spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock, + flags); + + sec = jiffies_to_msecs(jiffies - + sess->jiffies_at_registration)/1000; + if (sess->sec_since_registration < sec && sec && + !(sec % 5)) { + sess->sec_since_registration = sec; + ql_dbg(ql_dbg_disc, sess->vha, 0xffff, + "%s %8phC : Slow Rport registration(%d Sec)\n", + __func__, sess->port_name, sec); + } + qlt_send_term_imm_notif(vha, iocb, 1); + return 0; + case DSC_LOGIN_PEND: case DSC_GPDB: - case DSC_UPD_FCPORT: case DSC_LOGIN_COMPLETE: case DSC_ADISC: delete = false; @@ -5590,6 +5753,101 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha, tgt->atio_irq_cmd_count--; } +/* + * qpair lock is assume to be held + * rc = 0 : send terminate & abts respond + * rc != 0: do not send term & abts respond + */ +static int qlt_chk_unresolv_exchg(struct scsi_qla_host *vha, + struct qla_qpair *qpair, struct abts_resp_from_24xx_fw *entry) +{ + struct qla_hw_data *ha = vha->hw; + int rc = 0; + + /* + * Detect unresolved exchange. If the same ABTS is unable + * to terminate an existing command and the same ABTS loops + * between FW & Driver, then force FW dump. Under 1 jiff, + * we should see multiple loops. + */ + if (qpair->retry_term_exchg_addr == entry->exchange_addr_to_abort && + qpair->retry_term_jiff == jiffies) { + /* found existing exchange */ + qpair->retry_term_cnt++; + if (qpair->retry_term_cnt >= 5) { + rc = EIO; + qpair->retry_term_cnt = 0; + ql_log(ql_log_warn, vha, 0xffff, + "Unable to send ABTS Respond. Dumping firmware.\n"); + ql_dump_buffer(ql_dbg_tgt_mgt + ql_dbg_buffer, + vha, 0xffff, (uint8_t *)entry, sizeof(*entry)); + + if (qpair == ha->base_qpair) + ha->isp_ops->fw_dump(vha, 1); + else + ha->isp_ops->fw_dump(vha, 0); + + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + } else if (qpair->retry_term_jiff != jiffies) { + qpair->retry_term_exchg_addr = entry->exchange_addr_to_abort; + qpair->retry_term_cnt = 0; + qpair->retry_term_jiff = jiffies; + } + + return rc; +} + + +static void qlt_handle_abts_completion(struct scsi_qla_host *vha, + struct rsp_que *rsp, response_t *pkt) +{ + struct abts_resp_from_24xx_fw *entry = + (struct abts_resp_from_24xx_fw *)pkt; + u32 h = pkt->handle & ~QLA_TGT_HANDLE_MASK; + struct qla_tgt_mgmt_cmd *mcmd; + struct qla_hw_data *ha = vha->hw; + + mcmd = (struct qla_tgt_mgmt_cmd *)qlt_ctio_to_cmd(vha, rsp, + pkt->handle, pkt); + if (mcmd == NULL && h != QLA_TGT_SKIP_HANDLE) { + ql_dbg(ql_dbg_async, vha, 0xe064, + "qla_target(%d): ABTS Comp without mcmd\n", + vha->vp_idx); + return; + } + + if (mcmd) + vha = mcmd->vha; + vha->vha_tgt.qla_tgt->abts_resp_expected--; + + ql_dbg(ql_dbg_tgt, vha, 0xe038, + "ABTS_RESP_24XX: compl_status %x\n", + entry->compl_status); + + if (le16_to_cpu(entry->compl_status) != ABTS_RESP_COMPL_SUCCESS) { + if ((entry->error_subcode1 == 0x1E) && + (entry->error_subcode2 == 0)) { + if (qlt_chk_unresolv_exchg(vha, rsp->qpair, entry)) { + ha->tgt.tgt_ops->free_mcmd(mcmd); + return; + } + qlt_24xx_retry_term_exchange(vha, rsp->qpair, + pkt, mcmd); + } else { + ql_dbg(ql_dbg_tgt, vha, 0xe063, + "qla_target(%d): ABTS_RESP_24XX failed %x (subcode %x:%x)", + vha->vp_idx, entry->compl_status, + entry->error_subcode1, + entry->error_subcode2); + ha->tgt.tgt_ops->free_mcmd(mcmd); + } + } else { + ha->tgt.tgt_ops->free_mcmd(mcmd); + } +} + /* ha->hardware_lock supposed to be held on entry */ /* called via callback from qla2xxx */ static void qlt_response_pkt(struct scsi_qla_host *vha, @@ -5722,41 +5980,7 @@ static void qlt_response_pkt(struct scsi_qla_host *vha, case ABTS_RESP_24XX: if (tgt->abts_resp_expected > 0) { - struct abts_resp_from_24xx_fw *entry = - (struct abts_resp_from_24xx_fw *)pkt; - ql_dbg(ql_dbg_tgt, vha, 0xe038, - "ABTS_RESP_24XX: compl_status %x\n", - entry->compl_status); - tgt->abts_resp_expected--; - if (le16_to_cpu(entry->compl_status) != - ABTS_RESP_COMPL_SUCCESS) { - if ((entry->error_subcode1 == 0x1E) && - (entry->error_subcode2 == 0)) { - /* - * We've got a race here: aborted - * exchange not terminated, i.e. - * response for the aborted command was - * sent between the abort request was - * received and processed. - * Unfortunately, the firmware has a - * silly requirement that all aborted - * exchanges must be explicitely - * terminated, otherwise it refuses to - * send responses for the abort - * requests. So, we have to - * (re)terminate the exchange and retry - * the abort response. - */ - qlt_24xx_retry_term_exchange(vha, - entry); - } else - ql_dbg(ql_dbg_tgt, vha, 0xe063, - "qla_target(%d): ABTS_RESP_24XX " - "failed %x (subcode %x:%x)", - vha->vp_idx, entry->compl_status, - entry->error_subcode1, - entry->error_subcode2); - } + qlt_handle_abts_completion(vha, rsp, pkt); } else { ql_dbg(ql_dbg_tgt, vha, 0xe064, "qla_target(%d): Unexpected ABTS_RESP_24XX " @@ -5946,10 +6170,7 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha, case MODE_DUAL: if (newfcport) { if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) { - ql_dbg(ql_dbg_disc, vha, 0x20fe, - "%s %d %8phC post upd_fcport fcp_cnt %d\n", - __func__, __LINE__, fcport->port_name, vha->fcport_count); - qla24xx_post_upd_fcport_work(vha, fcport); + qla24xx_sched_upd_fcport(fcport); } else { ql_dbg(ql_dbg_disc, vha, 0x20ff, "%s %d %8phC post gpsc fcp_cnt %d\n", @@ -6111,7 +6332,7 @@ static void qlt_tmr_work(struct qla_tgt *tgt, struct atio_from_isp *a = &prm->tm_iocb2; struct scsi_qla_host *vha = tgt->vha; struct qla_hw_data *ha = vha->hw; - struct fc_port *sess = NULL; + struct fc_port *sess; unsigned long flags; uint8_t *s_id = NULL; /* to hide compiler warnings */ int rc; @@ -6137,7 +6358,6 @@ static void qlt_tmr_work(struct qla_tgt *tgt, goto out_term2; } else { if (sess->deleted) { - sess = NULL; goto out_term2; } @@ -6145,7 +6365,6 @@ static void qlt_tmr_work(struct qla_tgt *tgt, ql_dbg(ql_dbg_tgt_tmr, vha, 0xf020, "%s: kref_get fail %8phC\n", __func__, sess->port_name); - sess = NULL; goto out_term2; } } @@ -6164,8 +6383,6 @@ static void qlt_tmr_work(struct qla_tgt *tgt, return; out_term2: - if (sess) - ha->tgt.tgt_ops->put_sess(sess); spin_unlock_irqrestore(&ha->tgt.sess_lock, flags); out_term: qlt_send_term_exchange(ha->base_qpair, NULL, &prm->tm_iocb2, 1, 0); @@ -6366,9 +6583,9 @@ static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn, * qla_tgt_lport_register - register lport with external module * * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data - * @phys_wwpn: - * @npiv_wwpn: - * @npiv_wwnn: + * @phys_wwpn: physical port WWPN + * @npiv_wwpn: NPIV WWPN + * @npiv_wwnn: NPIV WWNN * @callback: lport initialization callback for tcm_qla2xxx code */ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, @@ -6395,6 +6612,9 @@ int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn, if (!(host->hostt->supported_mode & MODE_TARGET)) continue; + if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) + continue; + spin_lock_irqsave(&ha->hardware_lock, flags); if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) { pr_debug("MODE_TARGET already active on qla2xxx(%d)\n", @@ -6457,15 +6677,15 @@ void qlt_lport_deregister(struct scsi_qla_host *vha) EXPORT_SYMBOL(qlt_lport_deregister); /* Must be called under HW lock */ -static void qlt_set_mode(struct scsi_qla_host *vha) +void qlt_set_mode(struct scsi_qla_host *vha) { - switch (ql2x_ini_mode) { + switch (vha->qlini_mode) { case QLA2XXX_INI_MODE_DISABLED: case QLA2XXX_INI_MODE_EXCLUSIVE: vha->host->active_mode = MODE_TARGET; break; case QLA2XXX_INI_MODE_ENABLED: - vha->host->active_mode = MODE_UNKNOWN; + vha->host->active_mode = MODE_INITIATOR; break; case QLA2XXX_INI_MODE_DUAL: vha->host->active_mode = MODE_DUAL; @@ -6478,7 +6698,7 @@ static void qlt_set_mode(struct scsi_qla_host *vha) /* Must be called under HW lock */ static void qlt_clear_mode(struct scsi_qla_host *vha) { - switch (ql2x_ini_mode) { + switch (vha->qlini_mode) { case QLA2XXX_INI_MODE_DISABLED: vha->host->active_mode = MODE_UNKNOWN; break; @@ -6514,12 +6734,17 @@ qlt_enable_vha(struct scsi_qla_host *vha) dump_stack(); return; } + if (vha->qlini_mode == QLA2XXX_INI_MODE_ENABLED) + return; spin_lock_irqsave(&ha->hardware_lock, flags); tgt->tgt_stopped = 0; qlt_set_mode(vha); spin_unlock_irqrestore(&ha->hardware_lock, flags); + mutex_lock(&ha->optrom_mutex); + ql_dbg(ql_dbg_tgt_mgt, vha, 0xf021, + "%s.\n", __func__); if (vha->vp_idx) { qla24xx_disable_vp(vha); qla24xx_enable_vp(vha); @@ -6528,6 +6753,7 @@ qlt_enable_vha(struct scsi_qla_host *vha) qla2xxx_wake_dpc(base_vha); qla2x00_wait_for_hba_online(base_vha); } + mutex_unlock(&ha->optrom_mutex); } EXPORT_SYMBOL(qlt_enable_vha); @@ -6749,7 +6975,7 @@ qlt_24xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_24xx *nv) if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); else /* dual */ - nv->exchange_count = cpu_to_le16(ql2xexchoffld); + nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); @@ -6828,14 +7054,6 @@ qlt_24xx_config_nvram_stage2(struct scsi_qla_host *vha, memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); icb->firmware_options_1 |= cpu_to_le32(BIT_14); } - - /* disable ZIO at start time. */ - if (!vha->flags.init_done) { - uint32_t tmp; - tmp = le32_to_cpu(icb->firmware_options_2); - tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - icb->firmware_options_2 = cpu_to_le32(tmp); - } } void @@ -6863,7 +7081,7 @@ qlt_81xx_config_nvram_stage1(struct scsi_qla_host *vha, struct nvram_81xx *nv) if (qla_tgt_mode_enabled(vha)) nv->exchange_count = cpu_to_le16(0xFFFF); else /* dual */ - nv->exchange_count = cpu_to_le16(ql2xexchoffld); + nv->exchange_count = cpu_to_le16(vha->ql2xexchoffld); /* Enable target mode */ nv->firmware_options_1 |= cpu_to_le32(BIT_4); @@ -6939,15 +7157,6 @@ qlt_81xx_config_nvram_stage2(struct scsi_qla_host *vha, memcpy(icb->node_name, ha->tgt.tgt_node_name, WWN_SIZE); icb->firmware_options_1 |= cpu_to_le32(BIT_14); } - - /* disable ZIO at start time. */ - if (!vha->flags.init_done) { - uint32_t tmp; - tmp = le32_to_cpu(icb->firmware_options_2); - tmp &= ~(BIT_3 | BIT_2 | BIT_1 | BIT_0); - icb->firmware_options_2 = cpu_to_le32(tmp); - } - } void diff --git a/qla2x00t-32gbit/qla_target.h b/qla2x00t-32gbit/qla_target.h index 655845755..967b5e1c3 100644 --- a/qla2x00t-32gbit/qla_target.h +++ b/qla2x00t-32gbit/qla_target.h @@ -772,14 +772,6 @@ int qla2x00_wait_for_hba_online(struct scsi_qla_host *); #define FC_TM_REJECT 4 #define FC_TM_FAILED 5 -#if (BITS_PER_LONG > 32) || defined(CONFIG_HIGHMEM64G) -#define pci_dma_lo32(a) (a & 0xffffffff) -#define pci_dma_hi32(a) ((((a) >> 16)>>16) & 0xffffffff) -#else -#define pci_dma_lo32(a) (a & 0xffffffff) -#define pci_dma_hi32(a) 0 -#endif - #define QLA_TGT_SENSE_VALID(sense) ((sense != NULL) && \ (((const uint8_t *)(sense))[0] & 0x70) == 0x70) @@ -901,6 +893,7 @@ struct qla_tgt_cmd { unsigned int aborted:1; unsigned int data_work:1; unsigned int data_work_free:1; + unsigned int released:1; struct scatterlist *sg; /* cmd data buffer SG vector */ int sg_cnt; /* SG segments count */ @@ -909,6 +902,7 @@ struct qla_tgt_cmd { u64 unpacked_lun; enum dma_data_direction dma_data_direction; + uint16_t ctio_flags; uint16_t vp_idx; uint16_t loop_id; /* to save extra sess dereferences */ struct qla_tgt *tgt; /* to save extra sess dereferences */ @@ -935,6 +929,8 @@ struct qla_tgt_cmd { uint64_t lba; uint16_t a_guard, e_guard, a_app_tag, e_app_tag; uint32_t a_ref_tag, e_ref_tag; +#define DIF_BUNDL_DMA_VALID 1 + uint16_t prot_flags; uint64_t jiffies_at_alloc; uint64_t jiffies_at_free; @@ -957,16 +953,20 @@ struct qla_tgt_sess_work_param { }; struct qla_tgt_mgmt_cmd { + uint8_t cmd_type; + uint8_t pad[3]; uint16_t tmr_func; uint8_t fc_tm_rsp; + uint8_t abort_io_attr; struct fc_port *sess; struct qla_qpair *qpair; struct scsi_qla_host *vha; struct se_cmd se_cmd; struct work_struct free_work; unsigned int flags; +#define QLA24XX_MGMT_SEND_NACK BIT_0 +#define QLA24XX_MGMT_ABORT_IO_ATTR_VALID BIT_1 uint32_t reset_count; -#define QLA24XX_MGMT_SEND_NACK 1 struct work_struct work; uint64_t unpacked_lun; union { diff --git a/qla2x00t-32gbit/qla_tmpl.c b/qla2x00t-32gbit/qla_tmpl.c index 9f3c26375..9e52500ca 100644 --- a/qla2x00t-32gbit/qla_tmpl.c +++ b/qla2x00t-32gbit/qla_tmpl.c @@ -221,7 +221,13 @@ qla27xx_skip_entry(struct qla27xx_fwdt_entry *ent, void *buf) ent->hdr.driver_flags |= DRIVER_FLAG_SKIP_ENTRY; } -static int +static inline struct qla27xx_fwdt_entry * +qla27xx_next_entry(struct qla27xx_fwdt_entry *ent) +{ + return (void *)ent + ent->hdr.size; +} + +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -229,10 +235,10 @@ qla27xx_fwdt_entry_t0(struct scsi_qla_host *vha, "%s: nop [%lx]\n", __func__, *len); qla27xx_skip_entry(ent, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -241,10 +247,10 @@ qla27xx_fwdt_entry_t255(struct scsi_qla_host *vha, qla27xx_skip_entry(ent, buf); /* terminate */ - return true; + return NULL; } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -255,10 +261,10 @@ qla27xx_fwdt_entry_t256(struct scsi_qla_host *vha, qla27xx_read_window(reg, ent->t256.base_addr, ent->t256.pci_offset, ent->t256.reg_count, ent->t256.reg_width, buf, len); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -269,10 +275,10 @@ qla27xx_fwdt_entry_t257(struct scsi_qla_host *vha, qla27xx_write_reg(reg, IOBASE_ADDR, ent->t257.base_addr, buf); qla27xx_write_reg(reg, ent->t257.pci_offset, ent->t257.write_data, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -284,10 +290,10 @@ qla27xx_fwdt_entry_t258(struct scsi_qla_host *vha, qla27xx_read_window(reg, ent->t258.base_addr, ent->t258.pci_offset, ent->t258.reg_count, ent->t258.reg_width, buf, len); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -299,10 +305,10 @@ qla27xx_fwdt_entry_t259(struct scsi_qla_host *vha, qla27xx_write_reg(reg, ent->t259.banksel_offset, ent->t259.bank, buf); qla27xx_write_reg(reg, ent->t259.pci_offset, ent->t259.write_data, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -313,10 +319,10 @@ qla27xx_fwdt_entry_t260(struct scsi_qla_host *vha, qla27xx_insert32(ent->t260.pci_offset, buf, len); qla27xx_read_reg(reg, ent->t260.pci_offset, buf, len); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -326,10 +332,10 @@ qla27xx_fwdt_entry_t261(struct scsi_qla_host *vha, "%s: wrpci [%lx]\n", __func__, *len); qla27xx_write_reg(reg, ent->t261.pci_offset, ent->t261.write_data, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -362,6 +368,11 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, ent->t262.start_addr = start; ent->t262.end_addr = end; } + } else if (ent->t262.ram_area == T262_RAM_AREA_MISC) { + if (buf) { + ent->t262.start_addr = start; + ent->t262.end_addr = end; + } } else { ql_dbg(ql_dbg_misc, vha, 0xd022, "%s: unknown area %x\n", __func__, ent->t262.ram_area); @@ -384,10 +395,10 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, } *len += dwords * sizeof(uint32_t); done: - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -450,10 +461,10 @@ qla27xx_fwdt_entry_t263(struct scsi_qla_host *vha, qla27xx_skip_entry(ent, buf); } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -478,10 +489,10 @@ qla27xx_fwdt_entry_t264(struct scsi_qla_host *vha, qla27xx_skip_entry(ent, buf); } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -492,10 +503,10 @@ qla27xx_fwdt_entry_t265(struct scsi_qla_host *vha, if (buf) qla24xx_pause_risc(reg, vha->hw); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -504,10 +515,10 @@ qla27xx_fwdt_entry_t266(struct scsi_qla_host *vha, if (buf) qla24xx_soft_reset(vha->hw); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -517,10 +528,10 @@ qla27xx_fwdt_entry_t267(struct scsi_qla_host *vha, "%s: dis intr [%lx]\n", __func__, *len); qla27xx_write_reg(reg, ent->t267.pci_offset, ent->t267.data, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -587,10 +598,10 @@ qla27xx_fwdt_entry_t268(struct scsi_qla_host *vha, break; } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -604,10 +615,10 @@ qla27xx_fwdt_entry_t269(struct scsi_qla_host *vha, if (buf) ent->t269.scratch_size = 5 * sizeof(uint32_t); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -625,10 +636,10 @@ qla27xx_fwdt_entry_t270(struct scsi_qla_host *vha, addr += sizeof(uint32_t); } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -642,10 +653,10 @@ qla27xx_fwdt_entry_t271(struct scsi_qla_host *vha, qla27xx_write_reg(reg, 0xc4, data, buf); qla27xx_write_reg(reg, 0xc0, addr, buf); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -662,10 +673,10 @@ qla27xx_fwdt_entry_t272(struct scsi_qla_host *vha, } *len += dwords * sizeof(uint32_t); - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -685,10 +696,10 @@ qla27xx_fwdt_entry_t273(struct scsi_qla_host *vha, addr += sizeof(uint32_t); } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -746,10 +757,10 @@ qla27xx_fwdt_entry_t274(struct scsi_qla_host *vha, qla27xx_skip_entry(ent, buf); } - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { @@ -763,7 +774,7 @@ qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha, qla27xx_skip_entry(ent, buf); goto done; } - if (offset + ent->t275.length > ent->hdr.entry_size) { + if (offset + ent->t275.length > ent->hdr.size) { ql_dbg(ql_dbg_misc, vha, 0xd030, "%s: buffer overflow\n", __func__); qla27xx_skip_entry(ent, buf); @@ -772,59 +783,103 @@ qla27xx_fwdt_entry_t275(struct scsi_qla_host *vha, qla27xx_insertbuf(ent->t275.buffer, ent->t275.length, buf, len); done: - return false; + return qla27xx_next_entry(ent); } -static int +static struct qla27xx_fwdt_entry * +qla27xx_fwdt_entry_t276(struct scsi_qla_host *vha, + struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) +{ + uint type = vha->hw->pdev->device >> 4 & 0xf; + uint func = vha->hw->port_no & 0x3; + + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd214, + "%s: cond [%lx]\n", __func__, *len); + + if (type != ent->t276.cond1 || func != ent->t276.cond2) { + ent = qla27xx_next_entry(ent); + qla27xx_skip_entry(ent, buf); + } + + return qla27xx_next_entry(ent); +} + +static struct qla27xx_fwdt_entry * +qla27xx_fwdt_entry_t277(struct scsi_qla_host *vha, + struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) +{ + struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd215, + "%s: rdpep [%lx]\n", __func__, *len); + qla27xx_insert32(ent->t277.wr_cmd_data, buf, len); + qla27xx_write_reg(reg, ent->t277.cmd_addr, ent->t277.wr_cmd_data, buf); + qla27xx_read_reg(reg, ent->t277.data_addr, buf, len); + + return qla27xx_next_entry(ent); +} + +static struct qla27xx_fwdt_entry * +qla27xx_fwdt_entry_t278(struct scsi_qla_host *vha, + struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) +{ + struct device_reg_24xx __iomem *reg = qla27xx_isp_reg(vha); + + ql_dbg(ql_dbg_misc + ql_dbg_verbose, vha, 0xd216, + "%s: wrpep [%lx]\n", __func__, *len); + qla27xx_write_reg(reg, ent->t278.data_addr, ent->t278.wr_data, buf); + qla27xx_write_reg(reg, ent->t278.cmd_addr, ent->t278.wr_cmd_data, buf); + + return qla27xx_next_entry(ent); +} + +static struct qla27xx_fwdt_entry * qla27xx_fwdt_entry_other(struct scsi_qla_host *vha, struct qla27xx_fwdt_entry *ent, void *buf, ulong *len) { ql_dbg(ql_dbg_misc, vha, 0xd2ff, - "%s: type %x [%lx]\n", __func__, ent->hdr.entry_type, *len); + "%s: type %x [%lx]\n", __func__, ent->hdr.type, *len); qla27xx_skip_entry(ent, buf); - return false; + return qla27xx_next_entry(ent); } -struct qla27xx_fwdt_entry_call { +static struct { uint type; - int (*call)( - struct scsi_qla_host *, - struct qla27xx_fwdt_entry *, - void *, - ulong *); + typeof(qla27xx_fwdt_entry_other)(*call); +} qla27xx_fwdt_entry_call[] = { + { ENTRY_TYPE_NOP, qla27xx_fwdt_entry_t0 }, + { ENTRY_TYPE_TMP_END, qla27xx_fwdt_entry_t255 }, + { ENTRY_TYPE_RD_IOB_T1, qla27xx_fwdt_entry_t256 }, + { ENTRY_TYPE_WR_IOB_T1, qla27xx_fwdt_entry_t257 }, + { ENTRY_TYPE_RD_IOB_T2, qla27xx_fwdt_entry_t258 }, + { ENTRY_TYPE_WR_IOB_T2, qla27xx_fwdt_entry_t259 }, + { ENTRY_TYPE_RD_PCI, qla27xx_fwdt_entry_t260 }, + { ENTRY_TYPE_WR_PCI, qla27xx_fwdt_entry_t261 }, + { ENTRY_TYPE_RD_RAM, qla27xx_fwdt_entry_t262 }, + { ENTRY_TYPE_GET_QUEUE, qla27xx_fwdt_entry_t263 }, + { ENTRY_TYPE_GET_FCE, qla27xx_fwdt_entry_t264 }, + { ENTRY_TYPE_PSE_RISC, qla27xx_fwdt_entry_t265 }, + { ENTRY_TYPE_RST_RISC, qla27xx_fwdt_entry_t266 }, + { ENTRY_TYPE_DIS_INTR, qla27xx_fwdt_entry_t267 }, + { ENTRY_TYPE_GET_HBUF, qla27xx_fwdt_entry_t268 }, + { ENTRY_TYPE_SCRATCH, qla27xx_fwdt_entry_t269 }, + { ENTRY_TYPE_RDREMREG, qla27xx_fwdt_entry_t270 }, + { ENTRY_TYPE_WRREMREG, qla27xx_fwdt_entry_t271 }, + { ENTRY_TYPE_RDREMRAM, qla27xx_fwdt_entry_t272 }, + { ENTRY_TYPE_PCICFG, qla27xx_fwdt_entry_t273 }, + { ENTRY_TYPE_GET_SHADOW, qla27xx_fwdt_entry_t274 }, + { ENTRY_TYPE_WRITE_BUF, qla27xx_fwdt_entry_t275 }, + { ENTRY_TYPE_CONDITIONAL, qla27xx_fwdt_entry_t276 }, + { ENTRY_TYPE_RDPEPREG, qla27xx_fwdt_entry_t277 }, + { ENTRY_TYPE_WRPEPREG, qla27xx_fwdt_entry_t278 }, + { -1, qla27xx_fwdt_entry_other } }; -static struct qla27xx_fwdt_entry_call ql27xx_fwdt_entry_call_list[] = { - { ENTRY_TYPE_NOP , qla27xx_fwdt_entry_t0 } , - { ENTRY_TYPE_TMP_END , qla27xx_fwdt_entry_t255 } , - { ENTRY_TYPE_RD_IOB_T1 , qla27xx_fwdt_entry_t256 } , - { ENTRY_TYPE_WR_IOB_T1 , qla27xx_fwdt_entry_t257 } , - { ENTRY_TYPE_RD_IOB_T2 , qla27xx_fwdt_entry_t258 } , - { ENTRY_TYPE_WR_IOB_T2 , qla27xx_fwdt_entry_t259 } , - { ENTRY_TYPE_RD_PCI , qla27xx_fwdt_entry_t260 } , - { ENTRY_TYPE_WR_PCI , qla27xx_fwdt_entry_t261 } , - { ENTRY_TYPE_RD_RAM , qla27xx_fwdt_entry_t262 } , - { ENTRY_TYPE_GET_QUEUE , qla27xx_fwdt_entry_t263 } , - { ENTRY_TYPE_GET_FCE , qla27xx_fwdt_entry_t264 } , - { ENTRY_TYPE_PSE_RISC , qla27xx_fwdt_entry_t265 } , - { ENTRY_TYPE_RST_RISC , qla27xx_fwdt_entry_t266 } , - { ENTRY_TYPE_DIS_INTR , qla27xx_fwdt_entry_t267 } , - { ENTRY_TYPE_GET_HBUF , qla27xx_fwdt_entry_t268 } , - { ENTRY_TYPE_SCRATCH , qla27xx_fwdt_entry_t269 } , - { ENTRY_TYPE_RDREMREG , qla27xx_fwdt_entry_t270 } , - { ENTRY_TYPE_WRREMREG , qla27xx_fwdt_entry_t271 } , - { ENTRY_TYPE_RDREMRAM , qla27xx_fwdt_entry_t272 } , - { ENTRY_TYPE_PCICFG , qla27xx_fwdt_entry_t273 } , - { ENTRY_TYPE_GET_SHADOW , qla27xx_fwdt_entry_t274 } , - { ENTRY_TYPE_WRITE_BUF , qla27xx_fwdt_entry_t275 } , - { -1 , qla27xx_fwdt_entry_other } -}; - -static inline int (*qla27xx_find_entry(uint type)) - (struct scsi_qla_host *, struct qla27xx_fwdt_entry *, void *, ulong *) +static inline +typeof(qla27xx_fwdt_entry_call->call)(qla27xx_find_entry(uint type)) { - struct qla27xx_fwdt_entry_call *list = ql27xx_fwdt_entry_call_list; + typeof(*qla27xx_fwdt_entry_call) *list = qla27xx_fwdt_entry_call; while (list->type < type) list++; @@ -834,14 +889,6 @@ static inline int (*qla27xx_find_entry(uint type)) return qla27xx_fwdt_entry_other; } -static inline void * -qla27xx_next_entry(void *p) -{ - struct qla27xx_fwdt_entry *ent = p; - - return p + ent->hdr.entry_size; -} - static void qla27xx_walk_template(struct scsi_qla_host *vha, struct qla27xx_fwdt_template *tmp, void *buf, ulong *len) @@ -852,18 +899,16 @@ qla27xx_walk_template(struct scsi_qla_host *vha, ql_dbg(ql_dbg_misc, vha, 0xd01a, "%s: entry count %lx\n", __func__, count); while (count--) { - if (buf && *len >= vha->hw->fw_dump_len) + ent = qla27xx_find_entry(ent->hdr.type)(vha, ent, buf, len); + if (!ent) break; - if (qla27xx_find_entry(ent->hdr.entry_type)(vha, ent, buf, len)) - break; - ent = qla27xx_next_entry(ent); } if (count) ql_dbg(ql_dbg_misc, vha, 0xd018, "%s: entry residual count (%lx)\n", __func__, count); - if (ent->hdr.entry_type != ENTRY_TYPE_TMP_END) + if (ent) ql_dbg(ql_dbg_misc, vha, 0xd019, "%s: missing end entry (%lx)\n", __func__, count); @@ -1037,8 +1082,10 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) ql_log(ql_log_warn, vha, 0xd300, "Firmware has been previously dumped (%p)," " -- ignoring request\n", vha->hw->fw_dump); - else + else { + QLA_FW_STOPPED(vha->hw); qla27xx_execute_fwdt_template(vha); + } #ifndef __CHECKER__ if (!hardware_locked) diff --git a/qla2x00t-32gbit/qla_tmpl.h b/qla2x00t-32gbit/qla_tmpl.h index 141c1c5e7..5c2c2a8a1 100644 --- a/qla2x00t-32gbit/qla_tmpl.h +++ b/qla2x00t-32gbit/qla_tmpl.h @@ -54,6 +54,9 @@ struct __packed qla27xx_fwdt_template { #define ENTRY_TYPE_PCICFG 273 #define ENTRY_TYPE_GET_SHADOW 274 #define ENTRY_TYPE_WRITE_BUF 275 +#define ENTRY_TYPE_CONDITIONAL 276 +#define ENTRY_TYPE_RDPEPREG 277 +#define ENTRY_TYPE_WRPEPREG 278 #define CAPTURE_FLAG_PHYS_ONLY BIT_0 #define CAPTURE_FLAG_PHYS_VIRT BIT_1 @@ -62,8 +65,8 @@ struct __packed qla27xx_fwdt_template { struct __packed qla27xx_fwdt_entry { struct __packed { - uint32_t entry_type; - uint32_t entry_size; + uint32_t type; + uint32_t size; uint32_t reserved_1; uint8_t capture_flags; @@ -199,6 +202,24 @@ struct __packed qla27xx_fwdt_entry { uint32_t length; uint8_t buffer[]; } t275; + + struct __packed { + uint32_t cond1; + uint32_t cond2; + } t276; + + struct __packed { + uint32_t cmd_addr; + uint32_t wr_cmd_data; + uint32_t data_addr; + } t277; + + struct __packed { + uint32_t cmd_addr; + uint32_t wr_cmd_data; + uint32_t data_addr; + uint32_t wr_data; + } t278; }; }; @@ -206,6 +227,7 @@ struct __packed qla27xx_fwdt_entry { #define T262_RAM_AREA_EXTERNAL_RAM 2 #define T262_RAM_AREA_SHARED_RAM 3 #define T262_RAM_AREA_DDR_RAM 4 +#define T262_RAM_AREA_MISC 5 #define T263_QUEUE_TYPE_REQ 1 #define T263_QUEUE_TYPE_RSP 2 diff --git a/qla2x00t-32gbit/qla_version.h b/qla2x00t-32gbit/qla_version.h index 1ad758222..0690dac24 100644 --- a/qla2x00t-32gbit/qla_version.h +++ b/qla2x00t-32gbit/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.00.00.07-k" +#define QLA2XXX_VERSION "10.00.00.14-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 0