diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_lport.c')
| -rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 171 |
1 files changed, 121 insertions, 50 deletions
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index be83590ed955..310fa5add5f0 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1,19 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * Copyright(c) 2007 Intel Corporation. All rights reserved. * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * * Maintained at www.Open-FCoE.org */ @@ -91,21 +79,24 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <scsi/fc/fc_gs.h> #include <scsi/libfc.h> -#include <scsi/fc_encode.h> #include <linux/scatterlist.h> +#include "fc_encode.h" #include "fc_libfc.h" /* Fabric IDs to use for point-to-point mode, chosen on whims. */ #define FC_LOCAL_PTP_FID_LO 0x010101 #define FC_LOCAL_PTP_FID_HI 0x010102 -#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/ +#define DNS_DELAY 3 /* Discovery delay after RSCN (in seconds)*/ +#define MAX_CT_PAYLOAD 2048 +#define DISCOVERED_PORTS 4 +#define NUMBER_OF_PORTS 1 static void fc_lport_error(struct fc_lport *, struct fc_frame *); @@ -250,6 +241,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, } mutex_lock(&lport->disc.disc_mutex); lport->ptp_rdata = fc_rport_create(lport, remote_fid); + if (!lport->ptp_rdata) { + printk(KERN_WARNING "libfc: Failed to setup lport 0x%x\n", + lport->port_id); + mutex_unlock(&lport->disc.disc_mutex); + return; + } kref_get(&lport->ptp_rdata->kref); lport->ptp_rdata->ids.port_name = remote_wwpn; lport->ptp_rdata->ids.node_name = remote_wwnn; @@ -317,21 +314,21 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) stats = per_cpu_ptr(lport->stats, cpu); - fc_stats->tx_frames += stats->TxFrames; - fc_stats->tx_words += stats->TxWords; - fc_stats->rx_frames += stats->RxFrames; - fc_stats->rx_words += stats->RxWords; - fc_stats->error_frames += stats->ErrorFrames; - fc_stats->invalid_crc_count += stats->InvalidCRCCount; - fc_stats->fcp_input_requests += stats->InputRequests; - fc_stats->fcp_output_requests += stats->OutputRequests; - fc_stats->fcp_control_requests += stats->ControlRequests; - fcp_in_bytes += stats->InputBytes; - fcp_out_bytes += stats->OutputBytes; - fc_stats->fcp_packet_alloc_failures += stats->FcpPktAllocFails; - fc_stats->fcp_packet_aborts += stats->FcpPktAborts; - fc_stats->fcp_frame_alloc_failures += stats->FcpFrameAllocFails; - fc_stats->link_failure_count += stats->LinkFailureCount; + fc_stats->tx_frames += READ_ONCE(stats->TxFrames); + fc_stats->tx_words += READ_ONCE(stats->TxWords); + fc_stats->rx_frames += READ_ONCE(stats->RxFrames); + fc_stats->rx_words += READ_ONCE(stats->RxWords); + fc_stats->error_frames += READ_ONCE(stats->ErrorFrames); + fc_stats->invalid_crc_count += READ_ONCE(stats->InvalidCRCCount); + fc_stats->fcp_input_requests += READ_ONCE(stats->InputRequests); + fc_stats->fcp_output_requests += READ_ONCE(stats->OutputRequests); + fc_stats->fcp_control_requests += READ_ONCE(stats->ControlRequests); + fcp_in_bytes += READ_ONCE(stats->InputBytes); + fcp_out_bytes += READ_ONCE(stats->OutputBytes); + fc_stats->fcp_packet_alloc_failures += READ_ONCE(stats->FcpPktAllocFails); + fc_stats->fcp_packet_aborts += READ_ONCE(stats->FcpPktAborts); + fc_stats->fcp_frame_alloc_failures += READ_ONCE(stats->FcpFrameAllocFails); + fc_stats->link_failure_count += READ_ONCE(stats->LinkFailureCount); } fc_stats->fcp_input_megabytes = div_u64(fcp_in_bytes, 1000000); fc_stats->fcp_output_megabytes = div_u64(fcp_out_bytes, 1000000); @@ -417,7 +414,7 @@ static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) /** * fc_lport_recv_echo_req() - Handle received ECHO request * @lport: The local port receiving the ECHO - * @fp: ECHO request frame + * @in_fp: ECHO request frame */ static void fc_lport_recv_echo_req(struct fc_lport *lport, struct fc_frame *in_fp) @@ -452,7 +449,7 @@ static void fc_lport_recv_echo_req(struct fc_lport *lport, /** * fc_lport_recv_rnid_req() - Handle received Request Node ID data request * @lport: The local port receiving the RNID - * @fp: The RNID request frame + * @in_fp: The RNID request frame */ static void fc_lport_recv_rnid_req(struct fc_lport *lport, struct fc_frame *in_fp) @@ -715,7 +712,7 @@ static void fc_lport_disc_callback(struct fc_lport *lport, } /** - * fc_rport_enter_ready() - Enter the ready state and start discovery + * fc_lport_enter_ready() - Enter the ready state and start discovery * @lport: The local port that is ready */ static void fc_lport_enter_ready(struct fc_lport *lport) @@ -759,7 +756,7 @@ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, } /** - * fc_lport_set_port_id() - set the local port Port ID for point-to-multipoint + * fc_lport_set_local_id() - set the local port Port ID for point-to-multipoint * @lport: The local port which will have its Port ID set. * @port_id: The new port ID. * @@ -1197,7 +1194,7 @@ static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp, struct fc_lport *lport = lp_arg; struct fc_frame_header *fh; struct fc_ct_hdr *ct; - + struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host); FC_LPORT_DBG(lport, "Received a ms %s\n", fc_els_resp_type(fp)); if (fp == ERR_PTR(-FC_EX_CLOSED)) @@ -1231,7 +1228,13 @@ static void fc_lport_ms_resp(struct fc_seq *sp, struct fc_frame *fp, switch (lport->state) { case LPORT_ST_RHBA: - if (ntohs(ct->ct_cmd) == FC_FS_ACC) + if ((ntohs(ct->ct_cmd) == FC_FS_RJT) && fc_host->fdmi_version == FDMI_V2) { + FC_LPORT_DBG(lport, "Error for FDMI-V2, fall back to FDMI-V1\n"); + fc_host->fdmi_version = FDMI_V1; + + fc_lport_enter_ms(lport, LPORT_ST_RHBA); + + } else if (ntohs(ct->ct_cmd) == FC_FS_ACC) fc_lport_enter_ms(lport, LPORT_ST_RPA); else /* Error Skip RPA */ fc_lport_enter_scr(lport); @@ -1337,6 +1340,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport) /** * fc_lport_enter_ns() - register some object with the name server * @lport: Fibre Channel local port to register + * @state: Local port state */ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) { @@ -1404,7 +1408,7 @@ static struct fc_rport_operations fc_lport_rport_ops = { }; /** - * fc_rport_enter_dns() - Create a fc_rport for the name server + * fc_lport_enter_dns() - Create a fc_rport for the name server * @lport: The local port requesting a remote port for the name server */ static void fc_lport_enter_dns(struct fc_lport *lport) @@ -1435,6 +1439,7 @@ err: /** * fc_lport_enter_ms() - management server commands * @lport: Fibre Channel local port to register + * @state: Local port state */ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) { @@ -1443,7 +1448,7 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) int size = sizeof(struct fc_ct_hdr); size_t len; int numattrs; - + struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host); lockdep_assert_held(&lport->lp_mutex); FC_LPORT_DBG(lport, "Entered %s state from %s state\n", @@ -1456,10 +1461,10 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) case LPORT_ST_RHBA: cmd = FC_FDMI_RHBA; /* Number of HBA Attributes */ - numattrs = 10; + numattrs = 11; len = sizeof(struct fc_fdmi_rhba); len -= sizeof(struct fc_fdmi_attr_entry); - len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + len += FC_FDMI_HBA_ATTR_NODENAME_LEN; len += FC_FDMI_HBA_ATTR_MANUFACTURER_LEN; len += FC_FDMI_HBA_ATTR_SERIALNUMBER_LEN; @@ -1470,6 +1475,21 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) len += FC_FDMI_HBA_ATTR_OPTIONROMVERSION_LEN; len += FC_FDMI_HBA_ATTR_FIRMWAREVERSION_LEN; len += FC_FDMI_HBA_ATTR_OSNAMEVERSION_LEN; + len += FC_FDMI_HBA_ATTR_MAXCTPAYLOAD_LEN; + + + if (fc_host->fdmi_version == FDMI_V2) { + numattrs += 7; + len += FC_FDMI_HBA_ATTR_NODESYMBLNAME_LEN; + len += FC_FDMI_HBA_ATTR_VENDORSPECIFICINFO_LEN; + len += FC_FDMI_HBA_ATTR_NUMBEROFPORTS_LEN; + len += FC_FDMI_HBA_ATTR_FABRICNAME_LEN; + len += FC_FDMI_HBA_ATTR_BIOSVERSION_LEN; + len += FC_FDMI_HBA_ATTR_BIOSSTATE_LEN; + len += FC_FDMI_HBA_ATTR_VENDORIDENTIFIER_LEN; + } + + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); size += len; break; @@ -1479,7 +1499,6 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) numattrs = 6; len = sizeof(struct fc_fdmi_rpa); len -= sizeof(struct fc_fdmi_attr_entry); - len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); len += FC_FDMI_PORT_ATTR_FC4TYPES_LEN; len += FC_FDMI_PORT_ATTR_SUPPORTEDSPEED_LEN; len += FC_FDMI_PORT_ATTR_CURRENTPORTSPEED_LEN; @@ -1487,6 +1506,22 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) len += FC_FDMI_PORT_ATTR_OSDEVICENAME_LEN; len += FC_FDMI_PORT_ATTR_HOSTNAME_LEN; + if (fc_host->fdmi_version == FDMI_V2) { + numattrs += 10; + len += FC_FDMI_PORT_ATTR_NODENAME_LEN; + len += FC_FDMI_PORT_ATTR_PORTNAME_LEN; + len += FC_FDMI_PORT_ATTR_SYMBOLICNAME_LEN; + len += FC_FDMI_PORT_ATTR_PORTTYPE_LEN; + len += FC_FDMI_PORT_ATTR_SUPPORTEDCLASSSRVC_LEN; + len += FC_FDMI_PORT_ATTR_FABRICNAME_LEN; + len += FC_FDMI_PORT_ATTR_CURRENTFC4TYPE_LEN; + len += FC_FDMI_PORT_ATTR_PORTSTATE_LEN; + len += FC_FDMI_PORT_ATTR_DISCOVEREDPORTS_LEN; + len += FC_FDMI_PORT_ATTR_PORTID_LEN; + } + + len += (numattrs * FC_FDMI_ATTR_ENTRY_HEADER_LEN); + size += len; break; case LPORT_ST_DPRT: @@ -1519,7 +1554,7 @@ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) } /** - * fc_rport_enter_fdmi() - Create a fc_rport for the management server + * fc_lport_enter_fdmi() - Create a fc_rport for the management server * @lport: The local port requesting a remote port for the management server */ static void fc_lport_enter_fdmi(struct fc_lport *lport) @@ -1556,6 +1591,7 @@ static void fc_lport_timeout(struct work_struct *work) struct fc_lport *lport = container_of(work, struct fc_lport, retry_work.work); + struct fc_host_attrs *fc_host = shost_to_fc_host(lport->host); mutex_lock(&lport->lp_mutex); @@ -1583,12 +1619,19 @@ static void fc_lport_timeout(struct work_struct *work) fc_lport_enter_fdmi(lport); break; case LPORT_ST_RHBA: + if (fc_host->fdmi_version == FDMI_V2) { + FC_LPORT_DBG(lport, "timeout for FDMI-V2 RHBA,fall back to FDMI-V1\n"); + fc_host->fdmi_version = FDMI_V1; + fc_lport_enter_ms(lport, LPORT_ST_RHBA); + break; + } + fallthrough; case LPORT_ST_RPA: case LPORT_ST_DHBA: case LPORT_ST_DPRT: FC_LPORT_DBG(lport, "Skipping lport state %s to SCR\n", fc_lport_state(lport)); - /* fall thru */ + fallthrough; case LPORT_ST_SCR: fc_lport_enter_scr(lport); break; @@ -1650,7 +1693,7 @@ err: EXPORT_SYMBOL(fc_lport_logo_resp); /** - * fc_rport_enter_logo() - Logout of the fabric + * fc_lport_enter_logo() - Logout of the fabric * @lport: The local port to be logged out */ static void fc_lport_enter_logo(struct fc_lport *lport) @@ -1726,14 +1769,14 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, fc_frame_payload_op(fp) != ELS_LS_ACC) { FC_LPORT_DBG(lport, "FLOGI not accepted or bad response\n"); fc_lport_error(lport, fp); - goto err; + goto out; } flp = fc_frame_payload_get(fp, sizeof(*flp)); if (!flp) { FC_LPORT_DBG(lport, "FLOGI bad response\n"); fc_lport_error(lport, fp); - goto err; + goto out; } mfs = ntohs(flp->fl_csp.sp_bb_data) & @@ -1741,9 +1784,9 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, if (mfs < FC_SP_MIN_MAX_PAYLOAD || mfs > FC_SP_MAX_MAX_PAYLOAD) { FC_LPORT_DBG(lport, "FLOGI bad mfs:%hu response, " - "lport->mfs:%hu\n", mfs, lport->mfs); + "lport->mfs:%u\n", mfs, lport->mfs); fc_lport_error(lport, fp); - goto err; + goto out; } if (mfs <= lport->mfs) { @@ -1792,7 +1835,7 @@ err: EXPORT_SYMBOL(fc_lport_flogi_resp); /** - * fc_rport_enter_flogi() - Send a FLOGI request to the fabric manager + * fc_lport_enter_flogi() - Send a FLOGI request to the fabric manager * @lport: Fibre Channel local port to be logged in to the fabric */ static void fc_lport_enter_flogi(struct fc_lport *lport) @@ -1849,6 +1892,13 @@ EXPORT_SYMBOL(fc_lport_config); */ int fc_lport_init(struct fc_lport *lport) { + struct fc_host_attrs *fc_host; + + fc_host = shost_to_fc_host(lport->host); + + /* Set FDMI version to FDMI-2 specification*/ + fc_host->fdmi_version = FDMI_V2; + fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT; fc_host_node_name(lport->host) = lport->wwnn; fc_host_port_name(lport->host) = lport->wwpn; @@ -1857,6 +1907,7 @@ int fc_lport_init(struct fc_lport *lport) sizeof(fc_host_supported_fc4s(lport->host))); fc_host_supported_fc4s(lport->host)[2] = 1; fc_host_supported_fc4s(lport->host)[7] = 1; + fc_host_num_discovered_ports(lport->host) = 4; /* This value is also unchanging */ memset(fc_host_active_fc4s(lport->host), 0, @@ -1869,8 +1920,27 @@ int fc_lport_init(struct fc_lport *lport) fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT; if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT) fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT; + if (lport->link_supported_speeds & FC_PORTSPEED_40GBIT) + fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_40GBIT; + if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT) + fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT; + if (lport->link_supported_speeds & FC_PORTSPEED_25GBIT) + fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_25GBIT; + if (lport->link_supported_speeds & FC_PORTSPEED_50GBIT) + fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_50GBIT; + if (lport->link_supported_speeds & FC_PORTSPEED_100GBIT) + fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_100GBIT; + fc_fc4_add_lport(lport); + fc_host_num_discovered_ports(lport->host) = DISCOVERED_PORTS; + fc_host_port_state(lport->host) = FC_PORTSTATE_ONLINE; + fc_host_max_ct_payload(lport->host) = MAX_CT_PAYLOAD; + fc_host_num_ports(lport->host) = NUMBER_OF_PORTS; + fc_host_bootbios_state(lport->host) = 0X00000000; + snprintf(fc_host_bootbios_version(lport->host), + FC_SYMBOLIC_NAME_SIZE, "%s", "Unknown"); + return 0; } EXPORT_SYMBOL(fc_lport_init); @@ -1944,6 +2014,7 @@ static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, * @job: The BSG Passthrough job * @lport: The local port sending the request * @did: The destination port id + * @tov: The timeout period (in ms) */ static int fc_lport_els_request(struct bsg_job *job, struct fc_lport *lport, |
