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 and full and
extended FPIN messages.

Signed-off-by: Dave Marquardt <[email protected]>
---
 drivers/scsi/ibmvscsi/ibmvfc.c | 96 ++++++++++++++++++++++++++++++++++++++++--
 drivers/scsi/ibmvscsi/ibmvfc.h | 17 ++++++++
 2 files changed, 109 insertions(+), 4 deletions(-)

diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 110d77b9aac3..6dd1e726d9b9 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -5261,6 +5261,88 @@ 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;
+       int level = IBMVFC_DEFAULT_LOG_LEVEL;
+
+       if (vhost->scsi_scrqs.protocol != IBMVFC_PROTO_SCSI) {
+               ibmvfc_log(vhost, level, "Fabric Login failed: unknown 
protocol\n");
+               ibmvfc_hard_reset_host(vhost);
+               return;
+       }
+
+       evt = ibmvfc_get_reserved_event(&vhost->crq);
+       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));
+       mad->common.opcode = cpu_to_be32(IBMVFC_FABRIC_LOGIN);
+       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;
@@ -5307,8 +5389,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)
@@ -5499,9 +5585,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 526632cb7237..adfd67e85af8 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 {
@@ -180,6 +181,7 @@ struct ibmvfc_npiv_login {
 #define IBMVFC_CAN_HANDLE_FPIN         0x004
 #define IBMVFC_CAN_USE_MAD_VERSION     0x008
 #define IBMVFC_CAN_SEND_VF_WWPN                0x010
+#define IBMVFC_YES_SCSI                        0x040
 #define IBMVFC_CAN_USE_NOOP_CMD                0x200
        __be64 node_name;
        struct srp_direct_buf async;
@@ -227,6 +229,7 @@ struct ibmvfc_npiv_login_resp {
 #define IBMVFC_MAD_VERSION_CAP         0x0020
 #define IBMVFC_HANDLE_VF_WWPN          0x0040
 #define IBMVFC_CAN_SUPPORT_CHANNELS    0x0080
+#define IBMVFC_SUPPORT_SCSI            0x0200
 #define IBMVFC_SUPPORT_NOOP_CMD                0x1000
        __be32 max_cmds;
        __be32 scsi_id_sz;
@@ -590,6 +593,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 +731,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