summaryrefslogtreecommitdiff
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.c264
1 files changed, 240 insertions, 24 deletions
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
index ec0423ec6681..a2d48d6b1dfc 100644
--- a/drivers/scsi/qla2xxx/qla_init.c
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -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);