Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[linux-2.6-microblaze.git] / drivers / scsi / qla2xxx / qla_os.c
index 8fe2d73..8794e54 100644 (file)
@@ -14,6 +14,8 @@
 #include <linux/kobject.h>
 #include <linux/slab.h>
 #include <linux/blk-mq-pci.h>
+#include <linux/refcount.h>
+
 #include <scsi/scsi_tcq.h>
 #include <scsi/scsicam.h>
 #include <scsi/scsi_transport.h>
@@ -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);
@@ -391,12 +393,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. */
@@ -1012,7 +1016,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 +1216,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 +1281,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 +1341,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) {
@@ -1721,7 +1757,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 +1766,68 @@ __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) {
+                       switch (sp->cmd_type) {
+                       case 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);
+                                       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
+                                        * 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').
+                                        * 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').
                                         */
-                                       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);
+                                       if (!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);
+                                       }
                                }
                                sp->done(sp, res);
-                       } else {
+                               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 +2747,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))
@@ -2819,6 +2858,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
        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)) {
@@ -4249,29 +4290,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)
@@ -4309,6 +4355,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,
@@ -4341,6 +4393,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 */
@@ -4356,7 +4417,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;
@@ -4564,6 +4625,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);
@@ -4579,7 +4644,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);
 
@@ -4710,7 +4774,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);
 
@@ -4761,16 +4824,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
@@ -4808,10 +4880,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;
                        }
@@ -4990,19 +5062,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;
@@ -5025,9 +5090,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;
@@ -6041,12 +6103,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;
+
+                       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;
+                       }
 
-                       ql_dbg(ql_dbg_dpc, base_vha, 0x4007,
-                           "ISP abort scheduled.\n");
-                       if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
+                       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,
@@ -6054,10 +6133,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,
@@ -6183,17 +6261,28 @@ 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);
 
@@ -6406,13 +6495,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++;
        }
@@ -6944,6 +7044,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) {