[SCSI] qla2xxx: Support for asynchronous TM and Marker IOCBs.
authorMadhuranath Iyengar <madhuranath.iyengar@qlogic.com>
Tue, 4 May 2010 22:01:29 +0000 (15:01 -0700)
committerJames Bottomley <James.Bottomley@suse.de>
Sun, 16 May 2010 22:21:57 +0000 (18:21 -0400)
Currently we can only issue the task management (TM)
commands via the mailbox mechanism. This is a limitation,
since only one mailbox command can be issued at a time.
The purpose of this effort is to provide support for
issuing and processing the respose to TM and Marker
IOCBs asynchronously. Towards achieving this, the
consolidated srb architecture that is currently used for
BSG and IOCB/Logio commands has been enhanced and used.

Signed-off-by: Giridhar Malavali <giridhar.malavali@qlogic.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/qla2xxx/qla_bsg.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_iocb.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_os.c

index 951db816ee454ab9be1d3539f1a74ac11cedb8da..b905dfe5ea61339577b3c9dffb9bae1f3439399d 100644 (file)
@@ -317,6 +317,9 @@ qla2x00_process_els(struct fc_bsg_job *bsg_job)
        els->type =
                (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
                SRB_ELS_CMD_RPT : SRB_ELS_CMD_HST);
+       els->name =
+               (bsg_job->request->msgcode == FC_BSG_RPT_ELS ?
+               "bsg_els_rpt" : "bsg_els_hst");
        els->u.bsg_job = bsg_job;
 
        DEBUG2(qla_printk(KERN_INFO, ha,
@@ -450,6 +453,7 @@ qla2x00_process_ct(struct fc_bsg_job *bsg_job)
 
        ct = sp->ctx;
        ct->type = SRB_CT_CMD;
+       ct->name = "bsg_ct";
        ct->u.bsg_job = bsg_job;
 
        DEBUG2(qla_printk(KERN_INFO, ha,
index 08f5fd5359ddeaed1e3c84d089bc81bb1ffbb672..0d2cecbb8f47655af778b6f1e4f1aeb4bcc8e024 100644 (file)
@@ -223,6 +223,26 @@ struct srb_iocb {
 #define SRB_LOGIN_SKIP_PRLI    BIT_2
                        uint16_t data[2];
                } logio;
+               struct {
+                       /*
+                        * Values for flags field below are as
+                        * defined in tsk_mgmt_entry struct
+                        * for control_flags field in qla_fw.h.
+                        */
+                       uint32_t flags;
+                       uint32_t lun;
+                       uint32_t data;
+               } tmf;
+               struct {
+                       /*
+                        * values for modif field below are as
+                        * defined in mrk_entry_24xx struct
+                        * for the modifier field in qla_fw.h.
+                        */
+                       uint8_t modif;
+                       uint16_t lun;
+                       uint32_t data;
+               } marker;
        } u;
 
        struct timer_list timer;
@@ -239,6 +259,8 @@ struct srb_iocb {
 #define SRB_ELS_CMD_HST 4
 #define SRB_CT_CMD     5
 #define SRB_ADISC_CMD  6
+#define SRB_TM_CMD     7
+#define SRB_MARKER_CMD 8
 
 struct srb_ctx {
        uint16_t type;
index 408e5f0a53c15d9452f3dd35ba720a5eba0e30fd..3dbefe1a6b5fbb34ca5a5f45530bd423f40c03d0 100644 (file)
@@ -58,12 +58,18 @@ extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
 extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
 extern int qla2x00_async_adisc(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
+extern int qla2x00_async_tm_cmd(fc_port_t *, uint32_t, uint32_t, uint32_t);
+extern int qla2x00_async_marker(fc_port_t *, uint16_t, uint8_t);
 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 *);
+extern void qla2x00_async_tm_cmd_done(struct scsi_qla_host *, fc_port_t *,
+       struct srb_iocb *);
+extern void qla2x00_async_marker_done(struct scsi_qla_host *, fc_port_t *,
+       struct srb_iocb *);
 
 extern fc_port_t *
 qla2x00_alloc_fcport(scsi_qla_host_t *, gfp_t );
@@ -87,6 +93,7 @@ extern int ql2xetsenable;
 extern int ql2xshiftctondsd;
 extern int ql2xdbwr;
 extern int ql2xdontresethba;
+extern int ql2xasynctmfenable;
 
 extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
index 72b4ef2701584b111a4e6f5d28a35851a0c4bccc..e78089ded5176ef4a6e080aff4928af6f80d1787 100644 (file)
@@ -125,7 +125,7 @@ done:
 #define ELS_TMO_2_RATOV(ha) ((ha)->r_a_tov / 10 * 2)
 
 static void
-qla2x00_async_logio_timeout(srb_t *sp)
+qla2x00_async_iocb_timeout(srb_t *sp)
 {
        fc_port_t *fcport = sp->fcport;
        struct srb_ctx *ctx = sp->ctx;
@@ -170,7 +170,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport,
        ctx->type = SRB_LOGIN_CMD;
        ctx->name = "login";
        lio = ctx->u.iocb_cmd;
-       lio->timeout = qla2x00_async_logio_timeout;
+       lio->timeout = qla2x00_async_iocb_timeout;
        lio->done = qla2x00_async_login_ctx_done;
        lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI;
        if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
@@ -222,7 +222,7 @@ qla2x00_async_logout(struct scsi_qla_host *vha, fc_port_t *fcport)
        ctx->type = SRB_LOGOUT_CMD;
        ctx->name = "logout";
        lio = ctx->u.iocb_cmd;
-       lio->timeout = qla2x00_async_logio_timeout;
+       lio->timeout = qla2x00_async_iocb_timeout;
        lio->done = qla2x00_async_logout_ctx_done;
        rval = qla2x00_start_sp(sp);
        if (rval != QLA_SUCCESS)
@@ -271,7 +271,7 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport,
        ctx->type = SRB_ADISC_CMD;
        ctx->name = "adisc";
        lio = ctx->u.iocb_cmd;
-       lio->timeout = qla2x00_async_logio_timeout;
+       lio->timeout = qla2x00_async_iocb_timeout;
        lio->done = qla2x00_async_adisc_ctx_done;
        if (data[1] & QLA_LOGIO_LOGIN_RETRIED)
                lio->u.logio.flags |= SRB_LOGIN_RETRIED;
@@ -292,6 +292,112 @@ done:
        return rval;
 }
 
+static void
+qla2x00_async_tm_cmd_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
+
+       qla2x00_async_tm_cmd_done(sp->fcport->vha, sp->fcport, iocb);
+       iocb->free(sp);
+}
+
+int
+qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun,
+       uint32_t tag)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       srb_t *sp;
+       struct srb_ctx *ctx;
+       struct srb_iocb *tcf;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx),
+           ELS_TMO_2_RATOV(ha) + 2);
+       if (!sp)
+               goto done;
+
+       ctx = sp->ctx;
+       ctx->type = SRB_TM_CMD;
+       ctx->name = "tmf";
+       tcf = ctx->u.iocb_cmd;
+       tcf->u.tmf.flags = flags;
+       tcf->u.tmf.lun = lun;
+       tcf->u.tmf.data = tag;
+       tcf->timeout = qla2x00_async_iocb_timeout;
+       tcf->done = qla2x00_async_tm_cmd_ctx_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       DEBUG2(printk(KERN_DEBUG
+           "scsi(%ld:%x): Async-tmf - loop-id=%x portid=%02x%02x%02x.\n",
+           fcport->vha->host_no, 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:
+       tcf->free(sp);
+done:
+       return rval;
+}
+
+static void
+qla2x00_async_marker_ctx_done(srb_t *sp)
+{
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = (struct srb_iocb *)ctx->u.iocb_cmd;
+
+       qla2x00_async_marker_done(sp->fcport->vha, sp->fcport, iocb);
+       iocb->free(sp);
+}
+
+int
+qla2x00_async_marker(fc_port_t *fcport, uint16_t lun, uint8_t modif)
+{
+       struct scsi_qla_host *vha = fcport->vha;
+       srb_t *sp;
+       struct srb_ctx *ctx;
+       struct srb_iocb *mrk;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_ctx_sp(vha, fcport, sizeof(struct srb_ctx), 0);
+       if (!sp)
+               goto done;
+
+       ctx = sp->ctx;
+       ctx->type = SRB_MARKER_CMD;
+       ctx->name = "marker";
+       mrk = ctx->u.iocb_cmd;
+       mrk->u.marker.lun = lun;
+       mrk->u.marker.modif = modif;
+       mrk->timeout = qla2x00_async_iocb_timeout;
+       mrk->done = qla2x00_async_marker_ctx_done;
+
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       DEBUG2(printk(KERN_DEBUG
+           "scsi(%ld:%x): Async-marker - loop-id=%x "
+           "portid=%02x%02x%02x.\n",
+           fcport->vha->host_no, 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:
+       mrk->free(sp);
+done:
+       return rval;
+}
+
 void
 qla2x00_async_login_done(struct scsi_qla_host *vha, fc_port_t *fcport,
     uint16_t *data)
@@ -360,6 +466,48 @@ qla2x00_async_adisc_done(struct scsi_qla_host *vha, fc_port_t *fcport,
        return;
 }
 
+void
+qla2x00_async_tm_cmd_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    struct srb_iocb *iocb)
+{
+       int rval;
+       uint32_t flags;
+       uint16_t lun;
+
+       flags = iocb->u.tmf.flags;
+       lun = (uint16_t)iocb->u.tmf.lun;
+
+       /* Issue Marker IOCB */
+       rval = qla2x00_async_marker(fcport, lun,
+               flags == TCF_LUN_RESET ? MK_SYNC_ID_LUN : MK_SYNC_ID);
+
+       if ((rval != QLA_SUCCESS) || iocb->u.tmf.data) {
+               DEBUG2_3_11(printk(KERN_WARNING
+                       "%s(%ld): TM IOCB failed (%x).\n",
+                       __func__, vha->host_no, rval));
+       }
+
+       return;
+}
+
+void
+qla2x00_async_marker_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    struct srb_iocb *iocb)
+{
+       /*
+        * Currently we dont have any specific post response processing
+        * for this IOCB. We'll just return success or failed
+        * depending on whether the IOCB command succeeded or failed.
+        */
+       if (iocb->u.tmf.data) {
+               DEBUG2_3_11(printk(KERN_WARNING
+                   "%s(%ld): Marker IOCB failed (%x).\n",
+                   __func__, vha->host_no, iocb->u.tmf.data));
+       }
+
+       return;
+}
+
 /****************************************************************************/
 /*                QLogic ISP2x00 Hardware Support Functions.                */
 /****************************************************************************/
index 8861b88319fbcfea94fcef009bd4d6e1a4074cc1..d7a9fff15ad545f16b53aab9adb5072303610527 100644 (file)
@@ -1085,6 +1085,64 @@ qla2x00_adisc_iocb(srb_t *sp, struct mbx_entry *mbx)
        mbx->mb9 = cpu_to_le16(sp->fcport->vp_idx);
 }
 
+static void
+qla24xx_tm_iocb(srb_t *sp, struct tsk_mgmt_entry *tsk)
+{
+       uint32_t flags;
+       unsigned int lun;
+       struct fc_port *fcport = sp->fcport;
+       scsi_qla_host_t *vha = fcport->vha;
+       struct qla_hw_data *ha = vha->hw;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = ctx->u.iocb_cmd;
+       struct req_que *req = vha->req;
+
+       flags = iocb->u.tmf.flags;
+       lun = iocb->u.tmf.lun;
+
+       tsk->entry_type = TSK_MGMT_IOCB_TYPE;
+       tsk->entry_count = 1;
+       tsk->handle = MAKE_HANDLE(req->id, tsk->handle);
+       tsk->nport_handle = cpu_to_le16(fcport->loop_id);
+       tsk->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
+       tsk->control_flags = cpu_to_le32(flags);
+       tsk->port_id[0] = fcport->d_id.b.al_pa;
+       tsk->port_id[1] = fcport->d_id.b.area;
+       tsk->port_id[2] = fcport->d_id.b.domain;
+       tsk->vp_index = fcport->vp_idx;
+
+       if (flags == TCF_LUN_RESET) {
+               int_to_scsilun(lun, &tsk->lun);
+               host_to_fcp_swap((uint8_t *)&tsk->lun,
+                       sizeof(tsk->lun));
+       }
+}
+
+static void
+qla24xx_marker_iocb(srb_t *sp, struct mrk_entry_24xx *mrk)
+{
+       uint16_t lun;
+       uint8_t modif;
+       struct fc_port *fcport = sp->fcport;
+       scsi_qla_host_t *vha = fcport->vha;
+       struct srb_ctx *ctx = sp->ctx;
+       struct srb_iocb *iocb = ctx->u.iocb_cmd;
+       struct req_que *req = vha->req;
+
+       lun = iocb->u.marker.lun;
+       modif = iocb->u.marker.modif;
+       mrk->entry_type = MARKER_TYPE;
+       mrk->modifier = modif;
+       if (modif !=  MK_SYNC_ALL) {
+               mrk->nport_handle = cpu_to_le16(fcport->loop_id);
+               mrk->lun[1] = LSB(lun);
+               mrk->lun[2] = MSB(lun);
+               host_to_fcp_swap(mrk->lun, sizeof(mrk->lun));
+               mrk->vp_index = vha->vp_idx;
+               mrk->handle = MAKE_HANDLE(req->id, mrk->handle);
+       }
+}
+
 static void
 qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
 {
@@ -1239,6 +1297,12 @@ qla2x00_start_sp(srb_t *sp)
                    qla24xx_adisc_iocb(sp, pkt) :
                    qla2x00_adisc_iocb(sp, pkt);
                break;
+       case SRB_TM_CMD:
+               qla24xx_tm_iocb(sp, pkt);
+               break;
+       case SRB_MARKER_CMD:
+               qla24xx_marker_iocb(sp, pkt);
+               break;
        default:
                break;
        }
index 166bb2045fd4497cb96db0128c47ea5b5e2837c2..eed71ea1d9473fcd3c0837a195943c8cf935c749 100644 (file)
@@ -1161,6 +1161,99 @@ logio_done:
        lio->done(sp);
 }
 
+static void
+qla24xx_tm_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct tsk_mgmt_entry *tsk)
+{
+       const char func[] = "TMF-IOCB";
+       const char *type;
+       fc_port_t *fcport;
+       srb_t *sp;
+       struct srb_iocb *iocb;
+       struct srb_ctx *ctx;
+       struct sts_entry_24xx *sts = (struct sts_entry_24xx *)tsk;
+       int error = 1;
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, tsk);
+       if (!sp)
+               return;
+
+       ctx = sp->ctx;
+       iocb = ctx->u.iocb_cmd;
+       type = ctx->name;
+       fcport = sp->fcport;
+
+       if (sts->entry_status) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - entry-status(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->entry_status));
+       } else if (sts->comp_status != __constant_cpu_to_le16(CS_COMPLETE)) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - completion status(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->comp_status));
+       } else if (!(le16_to_cpu(sts->scsi_status) &
+           SS_RESPONSE_INFO_LEN_VALID)) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - no response info(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->scsi_status));
+       } else if (le32_to_cpu(sts->rsp_data_len) < 4) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - not enough response(%d).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->rsp_data_len));
+       } else if (sts->data[3]) {
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error - response(%x).\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->data[3]));
+       } else {
+               error = 0;
+       }
+
+       if (error) {
+               iocb->u.tmf.data = error;
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)sts, sizeof(*sts)));
+       }
+
+       iocb->done(sp);
+}
+
+static void
+qla24xx_marker_iocb_entry(scsi_qla_host_t *vha, struct req_que *req,
+    struct mrk_entry_24xx *mrk)
+{
+       const char func[] = "MRK-IOCB";
+       const char *type;
+       fc_port_t *fcport;
+       srb_t *sp;
+       struct srb_iocb *iocb;
+       struct srb_ctx *ctx;
+       struct sts_entry_24xx *sts = (struct sts_entry_24xx *)mrk;
+
+       sp = qla2x00_get_sp_from_handle(vha, func, req, mrk);
+       if (!sp)
+               return;
+
+       ctx = sp->ctx;
+       iocb = ctx->u.iocb_cmd;
+       type = ctx->name;
+       fcport = sp->fcport;
+
+       if (sts->entry_status) {
+               iocb->u.marker.data = 1;
+               DEBUG2(printk(KERN_WARNING
+                   "scsi(%ld:%x): Async-%s error entry - entry-status=%x.\n",
+                   fcport->vha->host_no, sp->handle, type,
+                   sts->entry_status));
+               DEBUG2(qla2x00_dump_buffer((uint8_t *)mrk, sizeof(*sts)));
+       }
+
+       iocb->done(sp);
+}
+
 /**
  * qla2x00_process_response_queue() - Process response queue entries.
  * @ha: SCSI driver HA context
@@ -1225,6 +1318,7 @@ qla2x00_process_response_queue(struct rsp_que *rsp)
                case MBX_IOCB_TYPE:
                        qla2x00_mbx_iocb_entry(vha, rsp->req,
                            (struct mbx_entry *)pkt);
+                       break;
                default:
                        /* Type Not Supported. */
                        DEBUG4(printk(KERN_WARNING
@@ -1751,6 +1845,14 @@ void qla24xx_process_response_queue(struct scsi_qla_host *vha,
                        qla24xx_logio_entry(vha, rsp->req,
                            (struct logio_entry_24xx *)pkt);
                        break;
+               case TSK_MGMT_IOCB_TYPE:
+                       qla24xx_tm_iocb_entry(vha, rsp->req,
+                           (struct tsk_mgmt_entry *)pkt);
+                       break;
+               case MARKER_TYPE:
+                       qla24xx_marker_iocb_entry(vha, rsp->req,
+                           (struct mrk_entry_24xx *)pkt);
+                       break;
                 case CT_IOCB_TYPE:
                        qla24xx_els_ct_entry(vha, rsp->req, pkt, CT_IOCB_TYPE);
                        clear_bit(MBX_INTERRUPT, &vha->hw->mbx_cmd_flags);
index 2f303322806150d9eb58f1b2815d7f70e97ca371..f3650d0434cadf7b1d00bb63694f48fefaa7f26f 100644 (file)
@@ -2464,12 +2464,22 @@ __qla24xx_issue_tmf(char *name, uint32_t type, struct fc_port *fcport,
 int
 qla24xx_abort_target(struct fc_port *fcport, unsigned int l, int tag)
 {
+       struct qla_hw_data *ha = fcport->vha->hw;
+
+       if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha))
+               return qla2x00_async_tm_cmd(fcport, TCF_TARGET_RESET, l, tag);
+
        return __qla24xx_issue_tmf("Target", TCF_TARGET_RESET, fcport, l, tag);
 }
 
 int
 qla24xx_lun_reset(struct fc_port *fcport, unsigned int l, int tag)
 {
+       struct qla_hw_data *ha = fcport->vha->hw;
+
+       if ((ql2xasynctmfenable) && IS_FWI2_CAPABLE(ha))
+               return qla2x00_async_tm_cmd(fcport, TCF_LUN_RESET, l, tag);
+
        return __qla24xx_issue_tmf("Lun", TCF_LUN_RESET, fcport, l, tag);
 }
 
index 70651f9fa6532c7256cfe66a2bbe55ef74ffd71c..523d414b59afb2148021cfd30698cbf2e7292662 100644 (file)
@@ -142,6 +142,11 @@ MODULE_PARM_DESC(ql2xdontresethba,
        " 1 -- Do not reset on failure.\n");
 
 
+int ql2xasynctmfenable;
+module_param(ql2xasynctmfenable, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xasynctmfenable,
+               "Enables issue of TM IOCBs asynchronously via IOCB mechanism"
+               "Default is 0 - Issue TM IOCBs via mailbox mechanism.");
 /*
  * SCSI host template entry points
  */