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
