scsi: qla2xxx: Add ability to send PRLO
authorQuinn Tran <quinn.tran@cavium.com>
Thu, 28 Dec 2017 20:33:20 +0000 (12:33 -0800)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 4 Jan 2018 04:41:05 +0000 (23:41 -0500)
Add ability to send Implicit PRLO to flush IOs
from FW back to driver.

Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
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_os.c

index 92dbba47d3cfa2a3ce671186a27aaa90a8671046..7a42aad55ec37972e4eeae1550fa77e4843a5e8e 100644 (file)
@@ -507,6 +507,7 @@ struct srb_iocb {
 #define SRB_NVME_LS    20
 #define SRB_PRLI_CMD   21
 #define SRB_CTRL_VP    22
+#define SRB_PRLO_CMD   23
 
 enum {
        TYPE_SRB,
@@ -3140,6 +3141,8 @@ enum qla_work_type {
        QLA_EVT_GNL,
        QLA_EVT_NACK,
        QLA_EVT_RELOGIN,
+       QLA_EVT_ASYNC_PRLO,
+       QLA_EVT_ASYNC_PRLO_DONE,
 };
 
 
index aabd49ef95a3a63fa4be99086ef67dcb522ad07f..7b61c96502e4195c857e4df4a283f97dcd139763 100644 (file)
@@ -66,6 +66,7 @@ extern void qla84xx_put_chip(struct scsi_qla_host *);
 extern int qla2x00_async_login(struct scsi_qla_host *, fc_port_t *,
     uint16_t *);
 extern int qla2x00_async_logout(struct scsi_qla_host *, fc_port_t *);
+extern int qla2x00_async_prlo(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);
@@ -109,6 +110,13 @@ int qla24xx_post_newsess_work(struct scsi_qla_host *, port_id_t *, u8 *,
 int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
 int qla24xx_detect_sfp(scsi_qla_host_t *vha);
 int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
+void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *,
+    uint16_t *);
+extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *,
+    uint16_t *);
+extern int qla2x00_post_async_prlo_done_work(struct scsi_qla_host *,
+    fc_port_t *, uint16_t *);
+
 /*
  * Global Data in qla_os.c source file.
  */
index 39d1edc6c2b19937eb7fc3abf74d09ec0df51fb1..56bff7856cf8f1e47b21b17166b4490c552c5cfb 100644 (file)
@@ -278,6 +278,65 @@ done:
        fcport->flags &= ~FCF_ASYNC_SENT;
        return rval;
 }
+
+void
+qla2x00_async_prlo_done(struct scsi_qla_host *vha, fc_port_t *fcport,
+    uint16_t *data)
+{
+       /* Don't re-login in target mode */
+       if (!fcport->tgt_session)
+               qla2x00_mark_device_lost(vha, fcport, 1, 0);
+       qlt_logo_completion_handler(fcport, data[0]);
+}
+
+static void
+qla2x00_async_prlo_sp_done(void *s, int res)
+{
+       srb_t *sp = (srb_t *)s;
+       struct srb_iocb *lio = &sp->u.iocb_cmd;
+       struct scsi_qla_host *vha = sp->vha;
+
+       if (!test_bit(UNLOADING, &vha->dpc_flags))
+               qla2x00_post_async_prlo_done_work(sp->fcport->vha, sp->fcport,
+                   lio->u.logio.data);
+       sp->free(sp);
+}
+
+int
+qla2x00_async_prlo(struct scsi_qla_host *vha, fc_port_t *fcport)
+{
+       srb_t *sp;
+       struct srb_iocb *lio;
+       int rval;
+
+       rval = QLA_FUNCTION_FAILED;
+       sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+       if (!sp)
+               goto done;
+
+       sp->type = SRB_PRLO_CMD;
+       sp->name = "prlo";
+       qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2);
+
+       lio = &sp->u.iocb_cmd;
+       lio->timeout = qla2x00_async_iocb_timeout;
+       sp->done = qla2x00_async_prlo_sp_done;
+       rval = qla2x00_start_sp(sp);
+       if (rval != QLA_SUCCESS)
+               goto done_free_sp;
+
+       ql_dbg(ql_dbg_disc, vha, 0x2070,
+           "Async-prlo - 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);
+       return rval;
+
+done_free_sp:
+       sp->free(sp);
+done:
+       return rval;
+}
+
 static
 void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea)
 {
index d1dfa784d89540ea14b413a3795e79d0b51a7681..14a3f6932c9cafe523db2b2703f2b1eb32cd2611 100644 (file)
@@ -3390,6 +3390,20 @@ qla25xx_ctrlvp_iocb(srb_t *sp, struct vp_ctrl_entry_24xx *vce)
        vce->vp_idx_map[map] |= 1 << pos;
 }
 
+static void
+qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio)
+{
+       logio->entry_type = LOGINOUT_PORT_IOCB_TYPE;
+       logio->control_flags =
+           cpu_to_le16(LCF_COMMAND_PRLO|LCF_IMPL_PRLO);
+
+       logio->nport_handle = cpu_to_le16(sp->fcport->loop_id);
+       logio->port_id[0] = sp->fcport->d_id.b.al_pa;
+       logio->port_id[1] = sp->fcport->d_id.b.area;
+       logio->port_id[2] = sp->fcport->d_id.b.domain;
+       logio->vp_index = sp->fcport->vha->vp_idx;
+}
+
 int
 qla2x00_start_sp(srb_t *sp)
 {
@@ -3471,6 +3485,9 @@ qla2x00_start_sp(srb_t *sp)
        case SRB_CTRL_VP:
                qla25xx_ctrlvp_iocb(sp, pkt);
                break;
+       case SRB_PRLO_CMD:
+               qla24xx_prlo_iocb(sp, pkt);
+               break;
        default:
                break;
        }
index 487e1affacf4543ed1cd3c1a05561ec3fc8e690c..aca7afc139ea46cbae510163f955317e950c9b60 100644 (file)
@@ -4690,6 +4690,8 @@ 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);
 
 int
 qla2x00_post_uevent_work(struct scsi_qla_host *vha, u32 code)
@@ -4943,6 +4945,13 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                case QLA_EVT_NACK:
                        qla24xx_do_nack_work(vha, e);
                        break;
+               case QLA_EVT_ASYNC_PRLO:
+                       qla2x00_async_prlo(vha, e->u.logio.fcport);
+                       break;
+               case QLA_EVT_ASYNC_PRLO_DONE:
+                       qla2x00_async_prlo_done(vha, e->u.logio.fcport,
+                           e->u.logio.data);
+                       break;
                }
                if (e->flags & QLA_EVT_FLAG_FREE)
                        kfree(e);