summaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_init.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_init.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_init.c245
1 files changed, 230 insertions, 15 deletions
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index dcc0f0d823db..f01f07116bd3 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -136,6 +136,10 @@ static void qla24xx_abort_iocb_timeout(void *data)
static void qla24xx_abort_sp_done(srb_t *sp, int res)
{
struct srb_iocb *abt = &sp->u.iocb_cmd;
+ srb_t *orig_sp = sp->cmd_sp;
+
+ if (orig_sp)
+ qla_wait_nvme_release_cmd_kref(orig_sp);
del_timer(&sp->u.iocb_cmd.timer);
if (sp->flags & SRB_WAKEUP_ON_COMP)
@@ -347,11 +351,11 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
if (NVME_TARGET(vha->hw, fcport))
lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI;
- 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);
+ ql_log(ql_log_warn, 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) {
@@ -3371,8 +3375,7 @@ qla2x00_alloc_fw_dump(scsi_qla_host_t *vha)
"Re-Allocated (%d KB) and save firmware dump.\n",
dump_size / 1024);
} else {
- if (ha->fw_dump)
- vfree(ha->fw_dump);
+ vfree(ha->fw_dump);
ha->fw_dump = fw_dump;
ha->fw_dump_len = ha->fw_dump_alloc_len =
@@ -4993,6 +4996,9 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
fcport->login_retry = vha->hw->login_retry_count;
fcport->chip_reset = vha->hw->base_qpair->chip_reset;
fcport->logout_on_delete = 1;
+ fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+ fcport->tgt_short_link_down_cnt = 0;
+ fcport->dev_loss_tmo = 0;
if (!fcport->ct_desc.ct_sns) {
ql_log(ql_log_warn, vha, 0xd049,
@@ -5490,6 +5496,7 @@ qla2x00_reg_remote_port(scsi_qla_host_t *vha, fc_port_t *fcport)
spin_lock_irqsave(fcport->vha->host->host_lock, flags);
*((fc_port_t **)rport->dd_data) = fcport;
spin_unlock_irqrestore(fcport->vha->host->host_lock, flags);
+ fcport->dev_loss_tmo = rport->dev_loss_tmo;
rport->supported_classes = fcport->supported_classes;
@@ -5548,6 +5555,11 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
fcport->logout_on_delete = 1;
fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0;
+ if (fcport->tgt_link_down_time < fcport->dev_loss_tmo) {
+ fcport->tgt_short_link_down_cnt++;
+ fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+ }
+
switch (vha->hw->current_topology) {
case ISP_CFG_N:
case ISP_CFG_NL:
@@ -6908,6 +6920,9 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
if (vha->flags.online) {
qla2x00_abort_isp_cleanup(vha);
+ if (vha->hw->flags.port_isolated)
+ return status;
+
if (test_and_clear_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags)) {
ha->flags.chip_reset_done = 1;
vha->flags.online = 1;
@@ -7029,6 +7044,11 @@ qla2x00_abort_isp(scsi_qla_host_t *vha)
}
+ if (vha->hw->flags.port_isolated) {
+ qla2x00_abort_isp_cleanup(vha);
+ return status;
+ }
+
if (!status) {
ql_dbg(ql_dbg_taskm, vha, 0x8022, "%s succeeded.\n", __func__);
qla2x00_configure_hba(vha);
@@ -7855,8 +7875,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
templates = (risc_attr & BIT_9) ? 2 : 1;
ql_dbg(ql_dbg_init, vha, 0x0160, "-> templates = %u\n", templates);
for (j = 0; j < templates; j++, fwdt++) {
- if (fwdt->template)
- vfree(fwdt->template);
+ vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
@@ -7916,8 +7935,7 @@ qla24xx_load_risc_flash(scsi_qla_host_t *vha, uint32_t *srisc_addr,
return QLA_SUCCESS;
failed:
- if (fwdt->template)
- vfree(fwdt->template);
+ vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
@@ -8113,8 +8131,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
templates = (risc_attr & BIT_9) ? 2 : 1;
ql_dbg(ql_dbg_init, vha, 0x0170, "-> templates = %u\n", templates);
for (j = 0; j < templates; j++, fwdt++) {
- if (fwdt->template)
- vfree(fwdt->template);
+ vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
@@ -8174,8 +8191,7 @@ qla24xx_load_risc_blob(scsi_qla_host_t *vha, uint32_t *srisc_addr)
return QLA_SUCCESS;
failed:
- if (fwdt->template)
- vfree(fwdt->template);
+ vfree(fwdt->template);
fwdt->template = NULL;
fwdt->length = 0;
@@ -9171,3 +9187,202 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair)
fail:
return ret;
}
+
+uint64_t
+qla2x00_count_set_bits(uint32_t num)
+{
+ /* Brian Kernighan's Algorithm */
+ u64 count = 0;
+
+ while (num) {
+ num &= (num - 1);
+ count++;
+ }
+ return count;
+}
+
+uint64_t
+qla2x00_get_num_tgts(scsi_qla_host_t *vha)
+{
+ fc_port_t *f, *tf;
+ u64 count = 0;
+
+ f = NULL;
+ tf = NULL;
+
+ list_for_each_entry_safe(f, tf, &vha->vp_fcports, list) {
+ if (f->port_type != FCT_TARGET)
+ continue;
+ count++;
+ }
+ return count;
+}
+
+int qla2xxx_reset_stats(struct Scsi_Host *host, u32 flags)
+{
+ scsi_qla_host_t *vha = shost_priv(host);
+ fc_port_t *fcport = NULL;
+ unsigned long int_flags;
+
+ if (flags & QLA2XX_HW_ERROR)
+ vha->hw_err_cnt = 0;
+ if (flags & QLA2XX_SHT_LNK_DWN)
+ vha->short_link_down_cnt = 0;
+ if (flags & QLA2XX_INT_ERR)
+ vha->interface_err_cnt = 0;
+ if (flags & QLA2XX_CMD_TIMEOUT)
+ vha->cmd_timeout_cnt = 0;
+ if (flags & QLA2XX_RESET_CMD_ERR)
+ vha->reset_cmd_err_cnt = 0;
+ if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ fcport->tgt_short_link_down_cnt = 0;
+ fcport->tgt_link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+ }
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
+ }
+ vha->link_down_time = QLA2XX_MAX_LINK_DOWN_TIME;
+ return 0;
+}
+
+int qla2xxx_start_stats(struct Scsi_Host *host, u32 flags)
+{
+ return qla2xxx_reset_stats(host, flags);
+}
+
+int qla2xxx_stop_stats(struct Scsi_Host *host, u32 flags)
+{
+ return qla2xxx_reset_stats(host, flags);
+}
+
+int qla2xxx_get_ini_stats(struct Scsi_Host *host, u32 flags,
+ void *data, u64 size)
+{
+ scsi_qla_host_t *vha = shost_priv(host);
+ struct ql_vnd_host_stats_resp *resp = (struct ql_vnd_host_stats_resp *)data;
+ struct ql_vnd_stats *rsp_data = &resp->stats;
+ u64 ini_entry_count = 0;
+ u64 i = 0;
+ u64 entry_count = 0;
+ u64 num_tgt = 0;
+ u32 tmp_stat_type = 0;
+ fc_port_t *fcport = NULL;
+ unsigned long int_flags;
+
+ /* Copy stat type to work on it */
+ tmp_stat_type = flags;
+
+ if (tmp_stat_type & BIT_17) {
+ num_tgt = qla2x00_get_num_tgts(vha);
+ /* unset BIT_17 */
+ tmp_stat_type &= ~(1 << 17);
+ }
+ ini_entry_count = qla2x00_count_set_bits(tmp_stat_type);
+
+ entry_count = ini_entry_count + num_tgt;
+
+ rsp_data->entry_count = entry_count;
+
+ i = 0;
+ if (flags & QLA2XX_HW_ERROR) {
+ rsp_data->entry[i].stat_type = QLA2XX_HW_ERROR;
+ rsp_data->entry[i].tgt_num = 0x0;
+ rsp_data->entry[i].cnt = vha->hw_err_cnt;
+ i++;
+ }
+
+ if (flags & QLA2XX_SHT_LNK_DWN) {
+ rsp_data->entry[i].stat_type = QLA2XX_SHT_LNK_DWN;
+ rsp_data->entry[i].tgt_num = 0x0;
+ rsp_data->entry[i].cnt = vha->short_link_down_cnt;
+ i++;
+ }
+
+ if (flags & QLA2XX_INT_ERR) {
+ rsp_data->entry[i].stat_type = QLA2XX_INT_ERR;
+ rsp_data->entry[i].tgt_num = 0x0;
+ rsp_data->entry[i].cnt = vha->interface_err_cnt;
+ i++;
+ }
+
+ if (flags & QLA2XX_CMD_TIMEOUT) {
+ rsp_data->entry[i].stat_type = QLA2XX_CMD_TIMEOUT;
+ rsp_data->entry[i].tgt_num = 0x0;
+ rsp_data->entry[i].cnt = vha->cmd_timeout_cnt;
+ i++;
+ }
+
+ if (flags & QLA2XX_RESET_CMD_ERR) {
+ rsp_data->entry[i].stat_type = QLA2XX_RESET_CMD_ERR;
+ rsp_data->entry[i].tgt_num = 0x0;
+ rsp_data->entry[i].cnt = vha->reset_cmd_err_cnt;
+ i++;
+ }
+
+ /* i will continue from previous loop, as target
+ * entries are after initiator
+ */
+ if (flags & QLA2XX_TGT_SHT_LNK_DOWN) {
+ spin_lock_irqsave(&vha->hw->tgt.sess_lock, int_flags);
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (fcport->port_type != FCT_TARGET)
+ continue;
+ if (!fcport->rport)
+ continue;
+ rsp_data->entry[i].stat_type = QLA2XX_TGT_SHT_LNK_DOWN;
+ rsp_data->entry[i].tgt_num = fcport->rport->number;
+ rsp_data->entry[i].cnt = fcport->tgt_short_link_down_cnt;
+ i++;
+ }
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, int_flags);
+ }
+ resp->status = EXT_STATUS_OK;
+
+ return 0;
+}
+
+int qla2xxx_get_tgt_stats(struct Scsi_Host *host, u32 flags,
+ struct fc_rport *rport, void *data, u64 size)
+{
+ struct ql_vnd_tgt_stats_resp *tgt_data = data;
+ fc_port_t *fcport = *(fc_port_t **)rport->dd_data;
+
+ tgt_data->status = 0;
+ tgt_data->stats.entry_count = 1;
+ tgt_data->stats.entry[0].stat_type = flags;
+ tgt_data->stats.entry[0].tgt_num = rport->number;
+ tgt_data->stats.entry[0].cnt = fcport->tgt_short_link_down_cnt;
+
+ return 0;
+}
+
+int qla2xxx_disable_port(struct Scsi_Host *host)
+{
+ scsi_qla_host_t *vha = shost_priv(host);
+
+ vha->hw->flags.port_isolated = 1;
+
+ if (qla2x00_chip_is_down(vha))
+ return 0;
+
+ if (vha->flags.online) {
+ qla2x00_abort_isp_cleanup(vha);
+ qla2x00_wait_for_sess_deletion(vha);
+ }
+
+ return 0;
+}
+
+int qla2xxx_enable_port(struct Scsi_Host *host)
+{
+ scsi_qla_host_t *vha = shost_priv(host);
+
+ vha->hw->flags.port_isolated = 0;
+ /* Set the flag to 1, so that isp_abort can proceed */
+ vha->flags.online = 1;
+ set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
+ qla2xxx_wake_dpc(vha);
+
+ return 0;
+}