From: Dave Marquardt <[email protected]>

Add support for fabric login in order to support the asynchronous
event queue with its own interrupt as required by NPIV specification
to support the asynchronous sub-queue and interrupt in order to
support full and extended FPIN messages.
---
 drivers/scsi/ibmvscsi/ibmvfc.c | 94 ++++++++++++++++++++++++++++++++++++++++--
 drivers/scsi/ibmvscsi/ibmvfc.h | 16 +++++++
 2 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 88386d7c9106..a18861808325 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -5244,6 +5244,86 @@ static void ibmvfc_discover_targets(struct ibmvfc_host 
*vhost)
                ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
 }
 
+static void ibmvfc_fabric_login_done(struct ibmvfc_event *evt)
+{
+       struct ibmvfc_fabric_login *rsp = &evt->xfer_iu->fabric_login;
+       u32 mad_status = be16_to_cpu(rsp->common.status);
+       struct ibmvfc_host *vhost = evt->vhost;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
+
+       ENTER;
+
+       switch (mad_status) {
+       case IBMVFC_MAD_SUCCESS:
+               fc_host_port_id(vhost->host) = be64_to_cpu(rsp->nport_id);
+               ibmvfc_free_event(evt);
+               break;
+
+       case IBMVFC_MAD_FAILED:
+               if (ibmvfc_retry_cmd(be16_to_cpu(rsp->status), 
be16_to_cpu(rsp->error)))
+                       level += ibmvfc_retry_host_init(vhost);
+               else
+                       ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+               ibmvfc_log(vhost, level, "Fabric Login failed: %s (%x:%x)\n",
+                          ibmvfc_get_cmd_error(be16_to_cpu(rsp->status), 
be16_to_cpu(rsp->error)),
+                                               be16_to_cpu(rsp->status), 
be16_to_cpu(rsp->error));
+               ibmvfc_free_event(evt);
+               LEAVE;
+               return;
+
+       case IBMVFC_MAD_CRQ_ERROR:
+               ibmvfc_retry_host_init(vhost);
+               fallthrough;
+
+       case IBMVFC_MAD_DRIVER_FAILED:
+               ibmvfc_free_event(evt);
+               LEAVE;
+               return;
+
+       default:
+               dev_err(vhost->dev, "Invalid fabric Login response: 0x%x\n", 
mad_status);
+               ibmvfc_link_down(vhost, IBMVFC_LINK_DEAD);
+               ibmvfc_free_event(evt);
+               LEAVE;
+               return;
+       }
+
+       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+       wake_up(&vhost->work_wait_q);
+
+       LEAVE;
+}
+
+static void ibmvfc_fabric_login(struct ibmvfc_host *vhost)
+{
+       struct ibmvfc_fabric_login *mad;
+       struct ibmvfc_event *evt = ibmvfc_get_reserved_event(&vhost->crq);
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
+
+       if (!evt) {
+               ibmvfc_log(vhost, level, "Fabric Login failed: no available 
events\n");
+               ibmvfc_hard_reset_host(vhost);
+               return;
+       }
+
+       ibmvfc_init_event(evt, ibmvfc_fabric_login_done, IBMVFC_MAD_FORMAT);
+       mad = &evt->iu.fabric_login;
+       memset(mad, 0, sizeof(*mad));
+       if (vhost->scsi_scrqs.protocol == IBMVFC_PROTO_SCSI)
+               mad->common.opcode = cpu_to_be32(IBMVFC_FABRIC_LOGIN);
+       else {
+               ibmvfc_log(vhost, level, "Fabric Login failed: unknown 
protocol\n");
+               return;
+       }
+       mad->common.version = cpu_to_be32(1);
+       mad->common.length = cpu_to_be16(sizeof(*mad));
+
+       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_INIT_WAIT);
+
+       if (ibmvfc_send_event(evt, vhost, default_timeout))
+               ibmvfc_link_down(vhost, IBMVFC_LINK_DOWN);
+}
+
 static void ibmvfc_channel_setup_done(struct ibmvfc_event *evt)
 {
        struct ibmvfc_host *vhost = evt->vhost;
@@ -5290,8 +5370,12 @@ static void ibmvfc_channel_setup_done(struct 
ibmvfc_event *evt)
                return;
        }
 
-       ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
-       wake_up(&vhost->work_wait_q);
+       if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI)) {
+               ibmvfc_fabric_login(vhost);
+       } else {
+               ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
+               wake_up(&vhost->work_wait_q);
+       }
 }
 
 static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
@@ -5482,9 +5566,11 @@ static void ibmvfc_npiv_login_done(struct ibmvfc_event 
*evt)
        vhost->host->can_queue = be32_to_cpu(rsp->max_cmds) - 
IBMVFC_NUM_INTERNAL_REQ;
        vhost->host->max_sectors = npiv_max_sectors;
 
-       if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS) && 
vhost->do_enquiry) {
+       if (ibmvfc_check_caps(vhost, IBMVFC_CAN_SUPPORT_CHANNELS) && 
vhost->do_enquiry)
                ibmvfc_channel_enquiry(vhost);
-       } else {
+       else if (ibmvfc_check_caps(vhost, IBMVFC_SUPPORT_SCSI))
+               ibmvfc_fabric_login(vhost);
+       else {
                vhost->do_enquiry = 0;
                ibmvfc_set_host_action(vhost, IBMVFC_HOST_ACTION_QUERY);
                wake_up(&vhost->work_wait_q);
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.h b/drivers/scsi/ibmvscsi/ibmvfc.h
index dd26248cac3e..c996b36d335d 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.h
+++ b/drivers/scsi/ibmvscsi/ibmvfc.h
@@ -138,6 +138,7 @@ enum ibmvfc_mad_types {
        IBMVFC_CHANNEL_ENQUIRY  = 0x1000,
        IBMVFC_CHANNEL_SETUP    = 0x2000,
        IBMVFC_CONNECTION_INFO  = 0x4000,
+       IBMVFC_FABRIC_LOGIN     = 0x8000,
 };
 
 struct ibmvfc_mad_common {
@@ -227,6 +228,7 @@ struct ibmvfc_npiv_login_resp {
 #define IBMVFC_MAD_VERSION_CAP         0x20
 #define IBMVFC_HANDLE_VF_WWPN          0x40
 #define IBMVFC_CAN_SUPPORT_CHANNELS    0x80
+#define IBMVFC_SUPPORT_SCSI            0x200
 #define IBMVFC_SUPPORT_NOOP_CMD                0x1000
        __be32 max_cmds;
        __be32 scsi_id_sz;
@@ -590,6 +592,19 @@ struct ibmvfc_connection_info {
        __be64 reserved[16];
 } __packed __aligned(8);
 
+struct ibmvfc_fabric_login {
+       struct ibmvfc_mad_common common;
+       __be64 flags;
+#define IBMVFC_STRIP_MERGE     0x1
+#define IBMVFC_LINK_COMMANDS   0x2
+       __be64 capabilities;
+       __be64 nport_id;
+       __be16 status;
+       __be16 error;
+       __be32 pad;
+       __be64 reserved[16];
+} __packed __aligned(8);
+
 struct ibmvfc_trace_start_entry {
        u32 xfer_len;
 } __packed;
@@ -715,6 +730,7 @@ union ibmvfc_iu {
        struct ibmvfc_channel_enquiry channel_enquiry;
        struct ibmvfc_channel_setup_mad channel_setup;
        struct ibmvfc_connection_info connection_info;
+       struct ibmvfc_fabric_login fabric_login;
 } __packed __aligned(8);
 
 enum ibmvfc_target_action {

-- 
2.54.0



Reply via email to