diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_lport.c')
| -rw-r--r-- | drivers/scsi/libfc/fc_lport.c | 442 |
1 files changed, 249 insertions, 193 deletions
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index f04d15c67df3..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 *); @@ -149,7 +140,7 @@ static const char *fc_lport_state_names[] = { * @offset: The offset into the response data */ struct fc_bsg_info { - struct fc_bsg_job *job; + struct bsg_job *job; struct fc_lport *lport; u16 rsp_code; struct scatterlist *sg; @@ -200,7 +191,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, "in the DNS or FDMI state, it's in the " "%d state", rdata->ids.port_id, lport->state); - lport->tt.rport_logoff(rdata); + fc_rport_logoff(rdata); } break; case RPORT_EV_LOGO: @@ -242,18 +233,26 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - mutex_lock(&lport->disc.disc_mutex); + lockdep_assert_held(&lport->lp_mutex); + if (lport->ptp_rdata) { - lport->tt.rport_logoff(lport->ptp_rdata); - kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); + fc_rport_logoff(lport->ptp_rdata); + kref_put(&lport->ptp_rdata->kref, fc_rport_destroy); + } + 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; } - lport->ptp_rdata = lport->tt.rport_create(lport, remote_fid); kref_get(&lport->ptp_rdata->kref); lport->ptp_rdata->ids.port_name = remote_wwpn; lport->ptp_rdata->ids.node_name = remote_wwnn; mutex_unlock(&lport->disc.disc_mutex); - lport->tt.rport_login(lport->ptp_rdata); + fc_rport_login(lport->ptp_rdata); fc_lport_enter_ready(lport); } @@ -301,7 +300,6 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) { struct fc_host_statistics *fc_stats; struct fc_lport *lport = shost_priv(shost); - struct timespec v0, v1; unsigned int cpu; u64 fcp_in_bytes = 0; u64 fcp_out_bytes = 0; @@ -309,30 +307,28 @@ struct fc_host_statistics *fc_get_host_stats(struct Scsi_Host *shost) fc_stats = &lport->host_stats; memset(fc_stats, 0, sizeof(struct fc_host_statistics)); - jiffies_to_timespec(jiffies, &v0); - jiffies_to_timespec(lport->boot_time, &v1); - fc_stats->seconds_since_last_reset = (v0.tv_sec - v1.tv_sec); + fc_stats->seconds_since_last_reset = (jiffies - lport->boot_time) / HZ; for_each_possible_cpu(cpu) { struct fc_stats *stats; 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); @@ -403,26 +399,22 @@ static void fc_lport_add_fc4_type(struct fc_lport *lport, enum fc_fh_type type) * fc_lport_recv_rlir_req() - Handle received Registered Link Incident Report. * @lport: Fibre Channel local port receiving the RLIR * @fp: The RLIR request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. */ static void fc_lport_recv_rlir_req(struct fc_lport *lport, struct fc_frame *fp) { + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Received RLIR request while in state %s\n", fc_lport_state(lport)); - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); + fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_frame_free(fp); } /** * fc_lport_recv_echo_req() - Handle received ECHO request * @lport: The local port receiving the ECHO - * @fp: ECHO request frame - * - * Locking Note: The lport lock is expected to be held before calling - * this function. + * @in_fp: ECHO request frame */ static void fc_lport_recv_echo_req(struct fc_lport *lport, struct fc_frame *in_fp) @@ -432,6 +424,8 @@ static void fc_lport_recv_echo_req(struct fc_lport *lport, void *pp; void *dp; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Received ECHO request while in state %s\n", fc_lport_state(lport)); @@ -455,10 +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 - * - * Locking Note: The lport lock is expected to be held before calling - * this function. + * @in_fp: The RNID request frame */ static void fc_lport_recv_rnid_req(struct fc_lport *lport, struct fc_frame *in_fp) @@ -474,6 +465,8 @@ static void fc_lport_recv_rnid_req(struct fc_lport *lport, u8 fmt; size_t len; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Received RNID request while in state %s\n", fc_lport_state(lport)); @@ -481,7 +474,7 @@ static void fc_lport_recv_rnid_req(struct fc_lport *lport, if (!req) { rjt_data.reason = ELS_RJT_LOGIC; rjt_data.explan = ELS_EXPL_NONE; - lport->tt.seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); + fc_seq_els_rsp_send(in_fp, ELS_LS_RJT, &rjt_data); } else { fmt = req->rnid_fmt; len = sizeof(*rp); @@ -515,13 +508,12 @@ static void fc_lport_recv_rnid_req(struct fc_lport *lport, * fc_lport_recv_logo_req() - Handle received fabric LOGO request * @lport: The local port receiving the LOGO * @fp: The LOGO request frame - * - * Locking Note: The lport lock is exected to be held before calling - * this function. */ static void fc_lport_recv_logo_req(struct fc_lport *lport, struct fc_frame *fp) { - lport->tt.seq_els_rsp_send(fp, ELS_LS_ACC, NULL); + lockdep_assert_held(&lport->lp_mutex); + + fc_seq_els_rsp_send(fp, ELS_LS_ACC, NULL); fc_lport_enter_reset(lport); fc_frame_free(fp); } @@ -553,11 +545,11 @@ EXPORT_SYMBOL(fc_fabric_login); /** * __fc_linkup() - Handler for transport linkup events * @lport: The lport whose link is up - * - * Locking: must be called with the lp_mutex held */ void __fc_linkup(struct fc_lport *lport) { + lockdep_assert_held(&lport->lp_mutex); + if (!lport->link_up) { lport->link_up = 1; @@ -584,11 +576,11 @@ EXPORT_SYMBOL(fc_linkup); /** * __fc_linkdown() - Handler for transport linkdown events * @lport: The lport whose link is down - * - * Locking: must be called with the lp_mutex held */ void __fc_linkdown(struct fc_lport *lport) { + lockdep_assert_held(&lport->lp_mutex); + if (lport->link_up) { lport->link_up = 0; fc_lport_enter_reset(lport); @@ -623,9 +615,9 @@ int fc_fabric_logoff(struct fc_lport *lport) lport->tt.disc_stop_final(lport); mutex_lock(&lport->lp_mutex); if (lport->dns_rdata) - lport->tt.rport_logoff(lport->dns_rdata); + fc_rport_logoff(lport->dns_rdata); mutex_unlock(&lport->lp_mutex); - lport->tt.rport_flush_queue(); + fc_rport_flush_queue(); mutex_lock(&lport->lp_mutex); fc_lport_enter_logo(lport); mutex_unlock(&lport->lp_mutex); @@ -720,14 +712,13 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_ready(struct fc_lport *lport) { + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered READY from state %s\n", fc_lport_state(lport)); @@ -745,13 +736,12 @@ static void fc_lport_enter_ready(struct fc_lport *lport) * @lport: The local port which will have its Port ID set. * @port_id: The new port ID. * @fp: The frame containing the incoming request, or NULL. - * - * Locking Note: The lport lock is expected to be held before calling - * this function. */ static void fc_lport_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp) { + lockdep_assert_held(&lport->lp_mutex); + if (port_id) printk(KERN_INFO "host%d: Assigned Port ID %6.6x\n", lport->host->host_no, port_id); @@ -766,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. * @@ -801,9 +791,6 @@ EXPORT_SYMBOL(fc_lport_set_local_id); * A received FLOGI request indicates a point-to-point connection. * Accept it with the common service parameters indicating our N port. * Set up to do a PLOGI if we have the higher-number WWPN. - * - * Locking Note: The lport lock is expected to be held before calling - * this function. */ static void fc_lport_recv_flogi_req(struct fc_lport *lport, struct fc_frame *rx_fp) @@ -816,6 +803,8 @@ static void fc_lport_recv_flogi_req(struct fc_lport *lport, u32 remote_fid; u32 local_fid; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Received FLOGI request while in state %s\n", fc_lport_state(lport)); @@ -887,8 +876,6 @@ out: static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_frame *fp) { - void (*recv)(struct fc_lport *, struct fc_frame *); - mutex_lock(&lport->lp_mutex); /* @@ -902,31 +889,35 @@ static void fc_lport_recv_els_req(struct fc_lport *lport, /* * Check opcode. */ - recv = lport->tt.rport_recv_req; switch (fc_frame_payload_op(fp)) { case ELS_FLOGI: if (!lport->point_to_multipoint) - recv = fc_lport_recv_flogi_req; + fc_lport_recv_flogi_req(lport, fp); + else + fc_rport_recv_req(lport, fp); break; case ELS_LOGO: if (fc_frame_sid(fp) == FC_FID_FLOGI) - recv = fc_lport_recv_logo_req; + fc_lport_recv_logo_req(lport, fp); + else + fc_rport_recv_req(lport, fp); break; case ELS_RSCN: - recv = lport->tt.disc_recv_req; + lport->tt.disc_recv_req(lport, fp); break; case ELS_ECHO: - recv = fc_lport_recv_echo_req; + fc_lport_recv_echo_req(lport, fp); break; case ELS_RLIR: - recv = fc_lport_recv_rlir_req; + fc_lport_recv_rlir_req(lport, fp); break; case ELS_RNID: - recv = fc_lport_recv_rnid_req; + fc_lport_recv_rnid_req(lport, fp); + break; + default: + fc_rport_recv_req(lport, fp); break; } - - recv(lport, fp); } mutex_unlock(&lport->lp_mutex); } @@ -944,15 +935,14 @@ struct fc4_prov fc_lport_els_prov = { }; /** - * fc_lport_recv_req() - The generic lport request handler + * fc_lport_recv() - The generic lport request handler * @lport: The lport that received the request * @fp: The frame the request is in * * Locking Note: This function should not be called with the lport * lock held because it may grab the lock. */ -static void fc_lport_recv_req(struct fc_lport *lport, - struct fc_frame *fp) +void fc_lport_recv(struct fc_lport *lport, struct fc_frame *fp) { struct fc_frame_header *fh = fc_frame_header_get(fp); struct fc_seq *sp = fr_seq(fp); @@ -981,8 +971,9 @@ drop: FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type); fc_frame_free(fp); if (sp) - lport->tt.exch_done(sp); + fc_exch_done(sp); } +EXPORT_SYMBOL(fc_lport_recv); /** * fc_lport_reset() - Reset a local port @@ -1004,18 +995,19 @@ EXPORT_SYMBOL(fc_lport_reset); /** * fc_lport_reset_locked() - Reset the local port w/ the lport lock held * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_reset_locked(struct fc_lport *lport) { - if (lport->dns_rdata) - lport->tt.rport_logoff(lport->dns_rdata); + lockdep_assert_held(&lport->lp_mutex); + + if (lport->dns_rdata) { + fc_rport_logoff(lport->dns_rdata); + lport->dns_rdata = NULL; + } if (lport->ptp_rdata) { - lport->tt.rport_logoff(lport->ptp_rdata); - kref_put(&lport->ptp_rdata->kref, lport->tt.rport_destroy); + fc_rport_logoff(lport->ptp_rdata); + kref_put(&lport->ptp_rdata->kref, fc_rport_destroy); lport->ptp_rdata = NULL; } @@ -1031,12 +1023,11 @@ static void fc_lport_reset_locked(struct fc_lport *lport) /** * fc_lport_enter_reset() - Reset the local port * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_reset(struct fc_lport *lport) { + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered RESET state from %s state\n", fc_lport_state(lport)); @@ -1061,12 +1052,11 @@ static void fc_lport_enter_reset(struct fc_lport *lport) /** * fc_lport_enter_disabled() - Disable the local port * @lport: The local port to be reset - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_disabled(struct fc_lport *lport) { + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered disabled state from %s state\n", fc_lport_state(lport)); @@ -1088,7 +1078,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp) { unsigned long delay = 0; FC_LPORT_DBG(lport, "Error %ld in state %s, retries %d\n", - PTR_ERR(fp), fc_lport_state(lport), + IS_ERR(fp) ? -PTR_ERR(fp) : 0, fc_lport_state(lport), lport->retry_count); if (PTR_ERR(fp) == -FC_EX_CLOSED) @@ -1204,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)) @@ -1238,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); @@ -1317,14 +1313,13 @@ err: /** * fc_lport_enter_scr() - Send a SCR (State Change Register) request * @lport: The local port to register for state changes - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_scr(struct fc_lport *lport) { struct fc_frame *fp; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered SCR state from %s state\n", fc_lport_state(lport)); @@ -1345,9 +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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. + * @state: Local port state */ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) { @@ -1356,6 +1349,8 @@ static void fc_lport_enter_ns(struct fc_lport *lport, enum fc_lport_state state) int size = sizeof(struct fc_ct_hdr); size_t len; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered %s state from %s state\n", fc_lport_state_names[state], fc_lport_state(lport)); @@ -1413,29 +1408,28 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_dns(struct fc_lport *lport) { struct fc_rport_priv *rdata; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered DNS state from %s state\n", fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_DNS); mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, FC_FID_DIR_SERV); + rdata = fc_rport_create(lport, FC_FID_DIR_SERV); mutex_unlock(&lport->disc.disc_mutex); if (!rdata) goto err; rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rdata); + fc_rport_login(rdata); return; err: @@ -1445,9 +1439,7 @@ err: /** * fc_lport_enter_ms() - management server commands * @lport: Fibre Channel local port to register - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. + * @state: Local port state */ static void fc_lport_enter_ms(struct fc_lport *lport, enum fc_lport_state state) { @@ -1456,6 +1448,8 @@ 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", fc_lport_state_names[state], @@ -1467,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; @@ -1481,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; @@ -1490,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; @@ -1498,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: @@ -1530,29 +1554,28 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_fdmi(struct fc_lport *lport) { struct fc_rport_priv *rdata; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered FDMI state from %s state\n", fc_lport_state(lport)); fc_lport_state_enter(lport, LPORT_ST_FDMI); mutex_lock(&lport->disc.disc_mutex); - rdata = lport->tt.rport_create(lport, FC_FID_MGMT_SERV); + rdata = fc_rport_create(lport, FC_FID_MGMT_SERV); mutex_unlock(&lport->disc.disc_mutex); if (!rdata) goto err; rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login(rdata); + fc_rport_login(rdata); return; err: @@ -1568,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); @@ -1595,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; @@ -1662,17 +1693,16 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_logo(struct fc_lport *lport) { struct fc_frame *fp; struct fc_els_logo *logo; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered LOGO state from %s state\n", fc_lport_state(lport)); @@ -1739,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) & @@ -1754,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) { @@ -1775,7 +1805,7 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, if ((csp_flags & FC_SP_FT_FPORT) == 0) { if (e_d_tov > lport->e_d_tov) lport->e_d_tov = e_d_tov; - lport->r_a_tov = 2 * e_d_tov; + lport->r_a_tov = 2 * lport->e_d_tov; fc_lport_set_port_id(lport, did, fp); printk(KERN_INFO "host%d: libfc: " "Port (%6.6x) entered " @@ -1787,8 +1817,10 @@ void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp, get_unaligned_be64( &flp->fl_wwnn)); } else { - lport->e_d_tov = e_d_tov; - lport->r_a_tov = r_a_tov; + if (e_d_tov > lport->e_d_tov) + lport->e_d_tov = e_d_tov; + if (r_a_tov > lport->r_a_tov) + lport->r_a_tov = r_a_tov; fc_host_fabric_name(lport->host) = get_unaligned_be64(&flp->fl_wwnn); fc_lport_set_port_id(lport, did, fp); @@ -1803,16 +1835,15 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ static void fc_lport_enter_flogi(struct fc_lport *lport) { struct fc_frame *fp; + lockdep_assert_held(&lport->lp_mutex); + FC_LPORT_DBG(lport, "Entered FLOGI state from %s state\n", fc_lport_state(lport)); @@ -1861,11 +1892,12 @@ EXPORT_SYMBOL(fc_lport_config); */ int fc_lport_init(struct fc_lport *lport) { - if (!lport->tt.lport_recv) - lport->tt.lport_recv = fc_lport_recv_req; + struct fc_host_attrs *fc_host; - if (!lport->tt.lport_reset) - lport->tt.lport_reset = fc_lport_reset; + 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; @@ -1875,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, @@ -1887,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); @@ -1903,18 +1955,19 @@ static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, void *info_arg) { struct fc_bsg_info *info = info_arg; - struct fc_bsg_job *job = info->job; + struct bsg_job *job = info->job; + struct fc_bsg_reply *bsg_reply = job->reply; struct fc_lport *lport = info->lport; struct fc_frame_header *fh; size_t len; void *buf; if (IS_ERR(fp)) { - job->reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ? + bsg_reply->result = (PTR_ERR(fp) == -FC_EX_CLOSED) ? -ECONNABORTED : -ETIMEDOUT; job->reply_len = sizeof(uint32_t); - job->state_flags |= FC_RQST_STATE_DONE; - job->job_done(job); + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); kfree(info); return; } @@ -1931,25 +1984,25 @@ static void fc_lport_bsg_resp(struct fc_seq *sp, struct fc_frame *fp, (unsigned short)fc_frame_payload_op(fp); /* Save the reply status of the job */ - job->reply->reply_data.ctels_reply.status = + bsg_reply->reply_data.ctels_reply.status = (cmd == info->rsp_code) ? FC_CTELS_STATUS_OK : FC_CTELS_STATUS_REJECT; } - job->reply->reply_payload_rcv_len += + bsg_reply->reply_payload_rcv_len += fc_copy_buffer_to_sglist(buf, len, info->sg, &info->nents, &info->offset, NULL); if (fr_eof(fp) == FC_EOF_T && (ntoh24(fh->fh_f_ctl) & (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) == (FC_FC_LAST_SEQ | FC_FC_END_SEQ)) { - if (job->reply->reply_payload_rcv_len > + if (bsg_reply->reply_payload_rcv_len > job->reply_payload.payload_len) - job->reply->reply_payload_rcv_len = + bsg_reply->reply_payload_rcv_len = job->reply_payload.payload_len; - job->reply->result = 0; - job->state_flags |= FC_RQST_STATE_DONE; - job->job_done(job); + bsg_reply->result = 0; + bsg_job_done(job, bsg_reply->result, + bsg_reply->reply_payload_rcv_len); kfree(info); } fc_frame_free(fp); @@ -1961,11 +2014,9 @@ 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 - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. + * @tov: The timeout period (in ms) */ -static int fc_lport_els_request(struct fc_bsg_job *job, +static int fc_lport_els_request(struct bsg_job *job, struct fc_lport *lport, u32 did, u32 tov) { @@ -1975,6 +2026,8 @@ static int fc_lport_els_request(struct fc_bsg_job *job, char *pp; int len; + lockdep_assert_held(&lport->lp_mutex); + fp = fc_frame_alloc(lport, job->request_payload.payload_len); if (!fp) return -ENOMEM; @@ -2008,8 +2061,8 @@ static int fc_lport_els_request(struct fc_bsg_job *job, info->nents = job->reply_payload.sg_cnt; info->sg = job->reply_payload.sg_list; - if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, - NULL, info, tov)) { + if (!fc_exch_seq_send(lport, fp, fc_lport_bsg_resp, + NULL, info, tov)) { kfree(info); return -ECOMM; } @@ -2022,11 +2075,8 @@ static int fc_lport_els_request(struct fc_bsg_job *job, * @lport: The local port sending the request * @did: The destination FC-ID * @tov: The timeout period to wait for the response - * - * Locking Note: The lport lock is expected to be held before calling - * this routine. */ -static int fc_lport_ct_request(struct fc_bsg_job *job, +static int fc_lport_ct_request(struct bsg_job *job, struct fc_lport *lport, u32 did, u32 tov) { struct fc_bsg_info *info; @@ -2035,6 +2085,8 @@ static int fc_lport_ct_request(struct fc_bsg_job *job, struct fc_ct_req *ct; size_t len; + lockdep_assert_held(&lport->lp_mutex); + fp = fc_frame_alloc(lport, sizeof(struct fc_ct_hdr) + job->request_payload.payload_len); if (!fp) @@ -2069,8 +2121,8 @@ static int fc_lport_ct_request(struct fc_bsg_job *job, info->nents = job->reply_payload.sg_cnt; info->sg = job->reply_payload.sg_list; - if (!lport->tt.exch_seq_send(lport, fp, fc_lport_bsg_resp, - NULL, info, tov)) { + if (!fc_exch_seq_send(lport, fp, fc_lport_bsg_resp, + NULL, info, tov)) { kfree(info); return -ECOMM; } @@ -2082,25 +2134,24 @@ static int fc_lport_ct_request(struct fc_bsg_job *job, * FC Passthrough requests * @job: The BSG passthrough job */ -int fc_lport_bsg_request(struct fc_bsg_job *job) +int fc_lport_bsg_request(struct bsg_job *job) { - struct request *rsp = job->req->next_rq; - struct Scsi_Host *shost = job->shost; + struct fc_bsg_request *bsg_request = job->request; + struct fc_bsg_reply *bsg_reply = job->reply; + struct Scsi_Host *shost = fc_bsg_to_shost(job); struct fc_lport *lport = shost_priv(shost); struct fc_rport *rport; struct fc_rport_priv *rdata; int rc = -EINVAL; - u32 did; + u32 did, tov; - job->reply->reply_payload_rcv_len = 0; - if (rsp) - rsp->resid_len = job->reply_payload.payload_len; + bsg_reply->reply_payload_rcv_len = 0; mutex_lock(&lport->lp_mutex); - switch (job->request->msgcode) { + switch (bsg_request->msgcode) { case FC_BSG_RPT_ELS: - rport = job->rport; + rport = fc_bsg_to_rport(job); if (!rport) break; @@ -2110,7 +2161,7 @@ int fc_lport_bsg_request(struct fc_bsg_job *job) break; case FC_BSG_RPT_CT: - rport = job->rport; + rport = fc_bsg_to_rport(job); if (!rport) break; @@ -2120,20 +2171,25 @@ int fc_lport_bsg_request(struct fc_bsg_job *job) break; case FC_BSG_HST_CT: - did = ntoh24(job->request->rqst_data.h_ct.port_id); - if (did == FC_FID_DIR_SERV) + did = ntoh24(bsg_request->rqst_data.h_ct.port_id); + if (did == FC_FID_DIR_SERV) { rdata = lport->dns_rdata; - else - rdata = lport->tt.rport_lookup(lport, did); - - if (!rdata) - break; + if (!rdata) + break; + tov = rdata->e_d_tov; + } else { + rdata = fc_rport_lookup(lport, did); + if (!rdata) + break; + tov = rdata->e_d_tov; + kref_put(&rdata->kref, fc_rport_destroy); + } - rc = fc_lport_ct_request(job, lport, did, rdata->e_d_tov); + rc = fc_lport_ct_request(job, lport, did, tov); break; case FC_BSG_HST_ELS_NOLOGIN: - did = ntoh24(job->request->rqst_data.h_els.port_id); + did = ntoh24(bsg_request->rqst_data.h_els.port_id); rc = fc_lport_els_request(job, lport, did, lport->e_d_tov); break; } |
