Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[sfrench/cifs-2.6.git] / drivers / scsi / qla2xxx / qla_init.c
index 1a955c3ff3d6ce2732e3fd03e65203a5162dbc9a..c3dd8dd4f73409ed7d46c7d340dfefdd67e8d311 100644 (file)
@@ -1996,6 +1996,11 @@ qla2x00_tmf_iocb_timeout(void *data)
        int rc, h;
        unsigned long flags;
 
+       if (sp->type == SRB_MARKER) {
+               complete(&tmf->u.tmf.comp);
+               return;
+       }
+
        rc = qla24xx_async_abort_cmd(sp, false);
        if (rc) {
                spin_lock_irqsave(sp->qpair->qp_lock_ptr, flags);
@@ -2013,24 +2018,131 @@ qla2x00_tmf_iocb_timeout(void *data)
        }
 }
 
+static void qla_marker_sp_done(srb_t *sp, int res)
+{
+       struct srb_iocb *tmf = &sp->u.iocb_cmd;
+
+       if (res != QLA_SUCCESS)
+               ql_dbg(ql_dbg_taskm, sp->vha, 0x8004,
+                   "Async-marker fail hdl=%x portid=%06x ctrl=%x lun=%lld qp=%d.\n",
+                   sp->handle, sp->fcport->d_id.b24, sp->u.iocb_cmd.u.tmf.flags,
+                   sp->u.iocb_cmd.u.tmf.lun, sp->qpair->id);
+
+       sp->u.iocb_cmd.u.tmf.data = res;
+       complete(&tmf->u.tmf.comp);
+}
+
+#define  START_SP_W_RETRIES(_sp, _rval) \
+{\
+       int cnt = 5; \
+       do { \
+               _rval = qla2x00_start_sp(_sp); \
+               if (_rval == EAGAIN) \
+                       msleep(1); \
+               else \
+                       break; \
+               cnt--; \
+       } while (cnt); \
+}
+
+/**
+ * qla26xx_marker: send marker IOCB and wait for the completion of it.
+ * @arg: pointer to argument list.
+ *    It is assume caller will provide an fcport pointer and modifier
+ */
+static int
+qla26xx_marker(struct tmf_arg *arg)
+{
+       struct scsi_qla_host *vha = arg->vha;
+       struct srb_iocb *tm_iocb;
+       srb_t *sp;
+       int rval = QLA_FUNCTION_FAILED;
+       fc_port_t *fcport = arg->fcport;
+
+       if (TMF_NOT_READY(arg->fcport)) {
+               ql_dbg(ql_dbg_taskm, vha, 0x8039,
+                   "FC port not ready for marker loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
+                   fcport->loop_id, fcport->d_id.b24,
+                   arg->modifier, arg->lun, arg->qpair->id);
+               return QLA_SUSPENDED;
+       }
+
+       /* ref: INIT */
+       sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
+       if (!sp)
+               goto done;
+
+       sp->type = SRB_MARKER;
+       sp->name = "marker";
+       qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha), qla_marker_sp_done);
+       sp->u.iocb_cmd.timeout = qla2x00_tmf_iocb_timeout;
+
+       tm_iocb = &sp->u.iocb_cmd;
+       init_completion(&tm_iocb->u.tmf.comp);
+       tm_iocb->u.tmf.modifier = arg->modifier;
+       tm_iocb->u.tmf.lun = arg->lun;
+       tm_iocb->u.tmf.loop_id = fcport->loop_id;
+       tm_iocb->u.tmf.vp_index = vha->vp_idx;
+
+       START_SP_W_RETRIES(sp, rval);
+
+       ql_dbg(ql_dbg_taskm, vha, 0x8006,
+           "Async-marker hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
+           sp->handle, fcport->loop_id, fcport->d_id.b24,
+           arg->modifier, arg->lun, sp->qpair->id, rval);
+
+       if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x8031,
+                   "Marker IOCB send failure (%x).\n", rval);
+               goto done_free_sp;
+       }
+
+       wait_for_completion(&tm_iocb->u.tmf.comp);
+       rval = tm_iocb->u.tmf.data;
+
+       if (rval != QLA_SUCCESS) {
+               ql_log(ql_log_warn, vha, 0x8019,
+                   "Marker failed hdl=%x loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d rval %d.\n",
+                   sp->handle, fcport->loop_id, fcport->d_id.b24,
+                   arg->modifier, arg->lun, sp->qpair->id, rval);
+       }
+
+done_free_sp:
+       /* ref: INIT */
+       kref_put(&sp->cmd_kref, qla2x00_sp_release);
+done:
+       return rval;
+}
+
 static void qla2x00_tmf_sp_done(srb_t *sp, int res)
 {
        struct srb_iocb *tmf = &sp->u.iocb_cmd;
 
+       if (res)
+               tmf->u.tmf.data = res;
        complete(&tmf->u.tmf.comp);
 }
 
-int
-qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
-       uint32_t tag)
+static int
+__qla2x00_async_tm_cmd(struct tmf_arg *arg)
 {
-       struct scsi_qla_host *vha = fcport->vha;
+       struct scsi_qla_host *vha = arg->vha;
        struct srb_iocb *tm_iocb;
        srb_t *sp;
        int rval = QLA_FUNCTION_FAILED;
 
+       fc_port_t *fcport = arg->fcport;
+
+       if (TMF_NOT_READY(arg->fcport)) {
+               ql_dbg(ql_dbg_taskm, vha, 0x8032,
+                   "FC port not ready for TM command loop-id=%x portid=%06x modifier=%x lun=%lld qp=%d.\n",
+                   fcport->loop_id, fcport->d_id.b24,
+                   arg->modifier, arg->lun, arg->qpair->id);
+               return QLA_SUSPENDED;
+       }
+
        /* ref: INIT */
-       sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+       sp = qla2xxx_get_qpair_sp(vha, arg->qpair, fcport, GFP_KERNEL);
        if (!sp)
                goto done;
 
@@ -2043,15 +2155,16 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
 
        tm_iocb = &sp->u.iocb_cmd;
        init_completion(&tm_iocb->u.tmf.comp);
-       tm_iocb->u.tmf.flags = flags;
-       tm_iocb->u.tmf.lun = lun;
+       tm_iocb->u.tmf.flags = arg->flags;
+       tm_iocb->u.tmf.lun = arg->lun;
+
+       START_SP_W_RETRIES(sp, rval);
 
        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);
+           "Async-tmf hdl=%x loop-id=%x portid=%06x ctrl=%x lun=%lld qp=%d rval=%x.\n",
+           sp->handle, fcport->loop_id, fcport->d_id.b24,
+           arg->flags, arg->lun, sp->qpair->id, rval);
 
-       rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS)
                goto done_free_sp;
        wait_for_completion(&tm_iocb->u.tmf.comp);
@@ -2063,15 +2176,8 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
                    "TM IOCB failed (%x).\n", rval);
        }
 
-       if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw)) {
-               flags = tm_iocb->u.tmf.flags;
-               lun = (uint16_t)tm_iocb->u.tmf.lun;
-
-               /* Issue Marker IOCB */
-               qla2x00_marker(vha, vha->hw->base_qpair,
-                   fcport->loop_id, lun,
-                   flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
-       }
+       if (!test_bit(UNLOADING, &vha->dpc_flags) && !IS_QLAFX00(vha->hw))
+               rval = qla26xx_marker(arg);
 
 done_free_sp:
        /* ref: INIT */
@@ -2080,6 +2186,115 @@ done:
        return rval;
 }
 
+static void qla_put_tmf(fc_port_t *fcport)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+       fcport->active_tmf--;
+       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+}
+
+static
+int qla_get_tmf(fc_port_t *fcport)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       unsigned long flags;
+       int rc = 0;
+       LIST_HEAD(tmf_elem);
+
+       spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+       list_add_tail(&tmf_elem, &fcport->tmf_pending);
+
+       while (fcport->active_tmf >= MAX_ACTIVE_TMF) {
+               spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+               msleep(1);
+
+               spin_lock_irqsave(&ha->tgt.sess_lock, flags);
+               if (TMF_NOT_READY(fcport)) {
+                       ql_log(ql_log_warn, vha, 0x802c,
+                           "Unable to acquire TM resource due to disruption.\n");
+                       rc = EIO;
+                       break;
+               }
+               if (fcport->active_tmf < MAX_ACTIVE_TMF &&
+                   list_is_first(&tmf_elem, &fcport->tmf_pending))
+                       break;
+       }
+
+       list_del(&tmf_elem);
+
+       if (!rc)
+               fcport->active_tmf++;
+
+       spin_unlock_irqrestore(&ha->tgt.sess_lock, flags);
+
+       return rc;
+}
+
+int
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint64_t lun,
+                    uint32_t tag)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_qpair *qpair;
+       struct tmf_arg a;
+       int i, rval = QLA_SUCCESS;
+
+       if (TMF_NOT_READY(fcport))
+               return QLA_SUSPENDED;
+
+       a.vha = fcport->vha;
+       a.fcport = fcport;
+       a.lun = lun;
+       if (flags & (TCF_LUN_RESET|TCF_ABORT_TASK_SET|TCF_CLEAR_TASK_SET|TCF_CLEAR_ACA)) {
+               a.modifier = MK_SYNC_ID_LUN;
+
+               if (qla_get_tmf(fcport))
+                       return QLA_FUNCTION_FAILED;
+       } else {
+               a.modifier = MK_SYNC_ID;
+       }
+
+       if (vha->hw->mqenable) {
+               for (i = 0; i < vha->hw->num_qpairs; i++) {
+                       qpair = vha->hw->queue_pair_map[i];
+                       if (!qpair)
+                               continue;
+
+                       if (TMF_NOT_READY(fcport)) {
+                               ql_log(ql_log_warn, vha, 0x8026,
+                                   "Unable to send TM due to disruption.\n");
+                               rval = QLA_SUSPENDED;
+                               break;
+                       }
+
+                       a.qpair = qpair;
+                       a.flags = flags|TCF_NOTMCMD_TO_TARGET;
+                       rval = __qla2x00_async_tm_cmd(&a);
+                       if (rval)
+                               break;
+               }
+       }
+
+       if (rval)
+               goto bailout;
+
+       a.qpair = vha->hw->base_qpair;
+       a.flags = flags;
+       rval = __qla2x00_async_tm_cmd(&a);
+
+bailout:
+       if (a.modifier == MK_SYNC_ID_LUN)
+               qla_put_tmf(fcport);
+
+       return rval;
+}
+
 int
 qla24xx_async_abort_command(srb_t *sp)
 {
@@ -4861,7 +5076,7 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
                if (use_tbl &&
                    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES)
-                       strlcpy(ha->model_desc,
+                       strscpy(ha->model_desc,
                            qla2x00_model_name[index * 2 + 1],
                            sizeof(ha->model_desc));
        } else {
@@ -4869,14 +5084,14 @@ qla2x00_set_model_info(scsi_qla_host_t *vha, uint8_t *model, size_t len,
                if (use_tbl &&
                    ha->pdev->subsystem_vendor == PCI_VENDOR_ID_QLOGIC &&
                    index < QLA_MODEL_NAMES) {
-                       strlcpy(ha->model_number,
+                       strscpy(ha->model_number,
                                qla2x00_model_name[index * 2],
                                sizeof(ha->model_number));
-                       strlcpy(ha->model_desc,
+                       strscpy(ha->model_desc,
                            qla2x00_model_name[index * 2 + 1],
                            sizeof(ha->model_desc));
                } else {
-                       strlcpy(ha->model_number, def,
+                       strscpy(ha->model_number, def,
                                sizeof(ha->model_number));
                }
        }
@@ -5291,6 +5506,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vha, gfp_t flags)
        INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
        INIT_LIST_HEAD(&fcport->gnl_entry);
        INIT_LIST_HEAD(&fcport->list);
+       INIT_LIST_HEAD(&fcport->tmf_pending);
 
        INIT_LIST_HEAD(&fcport->sess_cmd_list);
        spin_lock_init(&fcport->sess_cmd_lock);
@@ -5333,7 +5549,7 @@ static void qla_get_login_template(scsi_qla_host_t *vha)
        __be32 *q;
 
        memset(ha->init_cb, 0, ha->init_cb_size);
-       sz = min_t(int, sizeof(struct fc_els_flogi), ha->init_cb_size);
+       sz = min_t(int, sizeof(struct fc_els_csp), ha->init_cb_size);
        rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma,
                                            ha->init_cb, sz);
        if (rval != QLA_SUCCESS) {
@@ -6004,7 +6220,6 @@ qla2x00_configure_fabric(scsi_qla_host_t *vha)
        fc_port_t       *fcport;
        uint16_t        mb[MAILBOX_REGISTER_COUNT];
        uint16_t        loop_id;
-       LIST_HEAD(new_fcports);
        struct qla_hw_data *ha = vha->hw;
        int             discovery_gen;