aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/qla2xxx/qla_iocb.c
diff options
context:
space:
mode:
authorDuane Grigsby <duane.grigsby@cavium.com>2017-10-13 09:34:06 -0700
committerMartin K. Petersen <martin.petersen@oracle.com>2017-10-16 23:02:20 -0400
commitedd05de1975927b51b4e8e1135ef4d6130dfd17c (patch)
tree0fa6ea86e07b6cab87f4bd7e39cdd5dd23b28bad /drivers/scsi/qla2xxx/qla_iocb.c
parentscsi: qla2xxx: Allow MBC_GET_PORT_DATABASE to query and save the port states (diff)
downloadlinux-dev-edd05de1975927b51b4e8e1135ef4d6130dfd17c.tar.xz
linux-dev-edd05de1975927b51b4e8e1135ef4d6130dfd17c.zip
scsi: qla2xxx: Changes to support N2N logins
If we discovered a topology that is N2N then we will issue a login to the target. If our WWPN is bigger than the target's WWPN then we will initiate login, otherwise we will just wait for the target to initiate login. [mkp: many whitespace errors] Signed-off-by: Duane Grigsby <duane.grigsby@cavium.com> Signed-off-by: Michael Hernandez <michael.hernandez@cavium.com> Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com> Reviewed-by: Johannes Thumshirn <jthumshirn@suse.de> Tested-by: Ewan D. Milne <emilne@redhat.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'drivers/scsi/qla2xxx/qla_iocb.c')
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c195
1 files changed, 185 insertions, 10 deletions
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index 2f94159186d7..d810a447cb4a 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -2518,6 +2518,7 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
scsi_qla_host_t *vha = sp->vha;
struct srb_iocb *elsio = &sp->u.iocb_cmd;
+ uint32_t dsd_len = 24;
els_iocb->entry_type = ELS_IOCB_TYPE;
els_iocb->entry_count = 1;
@@ -2534,24 +2535,198 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa;
els_iocb->port_id[1] = sp->fcport->d_id.b.area;
els_iocb->port_id[2] = sp->fcport->d_id.b.domain;
+ els_iocb->s_id[0] = vha->d_id.b.al_pa;
+ els_iocb->s_id[1] = vha->d_id.b.area;
+ els_iocb->s_id[2] = vha->d_id.b.domain;
els_iocb->control_flags = 0;
- els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
- els_iocb->tx_address[0] =
- cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
- els_iocb->tx_address[1] =
- cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
- els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
+ if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) {
+ els_iocb->tx_byte_count = sizeof(struct els_plogi_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma));
+ els_iocb->tx_len = dsd_len;
+
+ els_iocb->rx_dsd_count = 1;
+ els_iocb->rx_byte_count = sizeof(struct els_plogi_payload);
+ els_iocb->rx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma));
+ els_iocb->rx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma));
+ els_iocb->rx_len = dsd_len;
+ ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073,
+ "PLOGI ELS IOCB:\n");
+ ql_dump_buffer(ql_log_info, vha, 0x0109,
+ (uint8_t *)els_iocb, 0x70);
+ } else {
+ els_iocb->tx_byte_count = sizeof(struct els_logo_payload);
+ els_iocb->tx_address[0] =
+ cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_address[1] =
+ cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma));
+ els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload));
- els_iocb->rx_byte_count = 0;
- els_iocb->rx_address[0] = 0;
- els_iocb->rx_address[1] = 0;
- els_iocb->rx_len = 0;
+ els_iocb->rx_byte_count = 0;
+ els_iocb->rx_address[0] = 0;
+ els_iocb->rx_address[1] = 0;
+ els_iocb->rx_len = 0;
+ }
sp->vha->qla_stats.control_requests++;
}
static void
+qla2x00_els_dcmd2_sp_free(void *data)
+{
+ srb_t *sp = data;
+ struct srb_iocb *elsio = &sp->u.iocb_cmd;
+
+ if (elsio->u.els_plogi.els_plogi_pyld)
+ dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_plogi.els_plogi_pyld,
+ elsio->u.els_plogi.els_plogi_pyld_dma);
+
+ if (elsio->u.els_plogi.els_resp_pyld)
+ dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_SIZE,
+ elsio->u.els_plogi.els_resp_pyld,
+ elsio->u.els_plogi.els_resp_pyld_dma);
+
+ del_timer(&elsio->timer);
+ qla2x00_rel_sp(sp);
+}
+
+static void
+qla2x00_els_dcmd2_iocb_timeout(void *data)
+{
+ srb_t *sp = data;
+ fc_port_t *fcport = sp->fcport;
+ struct scsi_qla_host *vha = sp->vha;
+ struct qla_hw_data *ha = vha->hw;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ unsigned long flags = 0;
+ int res;
+
+ ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069,
+ "%s hdl=%x ELS Timeout, %8phC portid=%06x\n",
+ sp->name, sp->handle, fcport->port_name, fcport->d_id.b24);
+
+ /* Abort the exchange */
+ spin_lock_irqsave(&ha->hardware_lock, flags);
+ res = ha->isp_ops->abort_command(sp);
+ ql_dbg(ql_dbg_io, vha, 0x3070,
+ "mbx abort_command %s\n",
+ (res == QLA_SUCCESS) ? "successful" : "failed");
+ spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+ complete(&lio->u.els_plogi.comp);
+}
+
+static void
+qla2x00_els_dcmd2_sp_done(void *ptr, int res)
+{
+ srb_t *sp = ptr;
+ fc_port_t *fcport = sp->fcport;
+ struct srb_iocb *lio = &sp->u.iocb_cmd;
+ struct scsi_qla_host *vha = sp->vha;
+
+ ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3072,
+ "%s ELS hdl=%x, portid=%06x done %8pC\n",
+ sp->name, sp->handle, fcport->d_id.b24, fcport->port_name);
+
+ complete(&lio->u.els_plogi.comp);
+}
+
+int
+qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode,
+ fc_port_t *fcport, port_id_t remote_did)
+{
+ srb_t *sp;
+ struct srb_iocb *elsio = NULL;
+ struct qla_hw_data *ha = vha->hw;
+ int rval = QLA_SUCCESS;
+ void *ptr, *resp_ptr;
+ dma_addr_t ptr_dma;
+
+ /* Alloc SRB structure */
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp) {
+ ql_log(ql_log_info, vha, 0x70e6,
+ "SRB allocation failed\n");
+ return -ENOMEM;
+ }
+
+ elsio = &sp->u.iocb_cmd;
+ fcport->d_id.b.domain = remote_did.b.domain;
+ fcport->d_id.b.area = remote_did.b.area;
+ fcport->d_id.b.al_pa = remote_did.b.al_pa;
+
+ ql_dbg(ql_dbg_io, vha, 0x3073,
+ "Enter: PLOGI portid=%06x\n", fcport->d_id.b24);
+
+ sp->type = SRB_ELS_DCMD;
+ sp->name = "ELS_DCMD";
+ sp->fcport = fcport;
+ qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT);
+ elsio->timeout = qla2x00_els_dcmd2_iocb_timeout;
+ sp->done = qla2x00_els_dcmd2_sp_done;
+ sp->free = qla2x00_els_dcmd2_sp_free;
+
+ ptr = elsio->u.els_plogi.els_plogi_pyld =
+ dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL);
+ ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma;
+
+ if (!elsio->u.els_plogi.els_plogi_pyld) {
+ rval = QLA_FUNCTION_FAILED;
+ goto out;
+ }
+
+ resp_ptr = elsio->u.els_plogi.els_resp_pyld =
+ dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE,
+ &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL);
+
+ if (!elsio->u.els_plogi.els_resp_pyld) {
+ rval = QLA_FUNCTION_FAILED;
+ goto out;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr);
+
+ memset(ptr, 0, sizeof(struct els_plogi_payload));
+ memset(resp_ptr, 0, sizeof(struct els_plogi_payload));
+ elsio->u.els_plogi.els_cmd = els_opcode;
+ elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode;
+ qla24xx_get_port_login_templ(vha, ptr_dma + 4,
+ &elsio->u.els_plogi.els_plogi_pyld->data[0],
+ sizeof(struct els_plogi_payload));
+
+ ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n");
+ ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x0109,
+ (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70);
+
+ init_completion(&elsio->u.els_plogi.comp);
+ rval = qla2x00_start_sp(sp);
+ if (rval != QLA_SUCCESS) {
+ rval = QLA_FUNCTION_FAILED;
+ goto out;
+ }
+
+ ql_dbg(ql_dbg_io, vha, 0x3074,
+ "%s PLOGI sent, hdl=%x, loopid=%x, portid=%06x\n",
+ sp->name, sp->handle, fcport->loop_id, fcport->d_id.b24);
+
+ wait_for_completion(&elsio->u.els_plogi.comp);
+
+ if (elsio->u.els_plogi.comp_status != CS_COMPLETE)
+ rval = QLA_FUNCTION_FAILED;
+
+out:
+ sp->free(sp);
+ return rval;
+}
+
+static void
qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb)
{
struct bsg_job *bsg_job = sp->u.bsg_job;