libfc, libfcoe and fcoe updates for scsi-misc
Subsystems (2)
cover libfc, libfcoe and fcoe updates for scsi-misc
These patches are targeting the 2.6.32 merge window.
There are three main focuses in this patch series. First, there are contributions that modify the stack for VLANs and prepare for NPIV. For both of those technologies resources need to be shared between VLANs on a physical port or VN_Ports on an N_Port. Second, there are improvements to the discovery and remote port layers. Discovery is now much more graceful (ADISC) and there is a cleaner division between fc_rports that are used by the FC transport and libfc's internal remote port tracking structures. Third, there is a performance optomization for the exchange manager where per-CPU exchange ID (XID) pools are created so that each CPU is not contending for a shared lock when trying to acquire a new XID.
Other than these primary changes there are other smaller contributions. A user-tunable DDP limit has been added. There are various improvements to the debug logging macros and uses of them. FC headers are exported for user space tools. The fcoe create/destroy path has been improved.
---
Chris Leech (15):
fcoe: use rtnl mutex in place of hostlist lock
fcoe: Fix module ref count bug by adding NETDEV UNREGISTER handling
fcoe: move the host-list add/remove to keep out VN_Ports
fcoe: add mutex to protect create and destroy
fcoe: split out per interface setup
fcoe: fcoe_interface create, destroy and refcounting
fcoe: remove fcoe_interface->priv pointer
fcoe: move offload exchange manager pointer from fcoe_port to fcoe_interface
fcoe: move FIP controller from fcoe_port to fcoe_interface
fcoe: move packet handlers from fcoe_port to fcoe_interface
fcoe: move netdev to fcoe_interface
fcoe: Introduce and allocate fcoe_interface structure, 1:1 with net_device
fcoe: interface changes to fcoe_if_create and fcoe_if_destroy
fcoe: fix missing error check in call to fcoe_if_init
libfcoe: fcoe_ctlr_destroy use cancel_work_sync instead of flush_work
Joe Eykholt (41):
fcoe: flush per-cpu thread work when destroying interface
libfc: don't swap OX_ID and RX_ID when sending BA_RJT
libfc: send GPN_ID in reaction to single-port RSCNs.
libfc: fix handling of incoming Discover Address (ADISC) requests
libfc: use ADISC to verify rport login state
libfc: LOGO response code had extraeous enter_rtv
libfc: re-login to remote ports that send us LOGO
libfc: fix rport error handling for login-required and invalid ops
libfc: correctly handle incoming PLOGI request.
libfc: improve debug messages for ELS response handlers
libfc: fix: rport_recv_req needs disc_mutex when calling rport_lookup
libfc: move remote port lookup for ELS requests into fc_rport.c.
libfc: don't do discovery before callback is set
libfc: clean up point-to-point discovery code.
libfc: discovery gpn_ft parse bug
libfc: discovery retry should clear pending first.
libfc: fix: empty zone causes endless discovery retries.
libfc: handle discovery failure more correctly.
libfc: rearrange code in fc_disc_gpn_ft_resp()
libfc: discovery restart sequence error fix
libfc: do not log off rports before or after discovery
libfc: move rport_lookup into fc_rport.c
libfc: change to make remote port callback optional
libfc: have rport_create do a lookup for pre-existing rports first
libfc: make rport module maintain the rport list
libfc: simplify fc_lport_rport_callback
libfc: rport debug messages were printing pointer values
libfc: remove unused disc->delay element
libfc: eliminate disc->event
libfc: fix rport event race between READY and LOGO
libfc: don't create dummy (rogue) remote ports
libfc: rename rport event CREATED to READY
libfc: rearrange code in fc_rport_work
libfc: make rport structure optional
libfc: change elsct to use FC_ID instead of rdata
libfc: make fc_rport_priv the primary rport interface.
libfc: fix RPORT_TO_PRIV and PRIV_TO_RPORT() macros.
libfc: change interface for rport_create
libfc: prepare to split off struct fc_rport_priv from fc_rport_libfc_priv
fcoe: remove unnecessary list and lock initializations.
fcoe: libfcoe: extra semicolon in CHECK_LOGGING macros causes compile error
Robert Love (5):
libfc: Always reset remote port roles when receiving PRLI
libfc: Initialize fc_rport_identifiers inside fc_rport_create
libfc: Export FC headers
libfc: Fix misleading debug statement
fcoe: Add format spacing to FCOE_NETDEV_DBG debug macro
Vasu Dev (2):
fcoe, libfc: fully makes use of per cpu exch pool and then removes em_lock fcoe, libfc: adds per cpu exch pool within exchange manager(EM)
Yi Zou (1):
fcoe: Add sysfs parameter to fcoe for minimum DDP read I/O size
drivers/scsi/fcoe/fcoe.c | 948 ++++++++++++++++++++---------------- drivers/scsi/fcoe/fcoe.h | 32 + drivers/scsi/fcoe/libfcoe.c | 10 drivers/scsi/libfc/fc_disc.c | 523 ++++++++------------ drivers/scsi/libfc/fc_elsct.c | 49 ++ drivers/scsi/libfc/fc_exch.c | 286 +++++++---- drivers/scsi/libfc/fc_fcp.c | 2 drivers/scsi/libfc/fc_lport.c | 222 ++------ drivers/scsi/libfc/fc_rport.c | 1091 +++++++++++++++++++++++++---------------- include/scsi/Kbuild | 1 include/scsi/fc/Kbuild | 4 include/scsi/fc/fc_gs.h | 1 include/scsi/fc_encode.h | 60 ++ include/scsi/libfc.h | 122 +++-- 14 files changed, 1824 insertions(+), 1527 deletions(-) create mode 100644 include/scsi/fc/Kbuild
Signature · 1 line
//Rob
PATCH 1/64 fcoe: Add format spacing to FCOE_NETDEV_DBG debug macro
There's currently no space between the interface name and the user specified format/string. This patch adds a space and a colon to the output to separate the interface name and the user specified string.
So, instead of "ethXfoo" it will read "ethX: foo".
---
drivers/scsi/fcoe/fcoe.h | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.h +1 -1
@@ -61,7 +61,7 @@ do { \ #define FCOE_NETDEV_DBG(netdev, fmt, args...) \ FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \ - printk(KERN_INFO "fcoe: %s" fmt, \ + printk(KERN_INFO "fcoe: %s: " fmt, \ netdev->name, ##args);)/*
PATCH 2/64 libfc: Fix misleading debug statement
In reply to Robert LoveThe statement reads, "Exchange timed out, notifying the upper layer", however, this statement is printed whenever the timer is armed. This is confusing to someone debugging the code because every time an exchange is initialized, there is an incorrect statement stating that the timer has already timed out. This patch changes the statement to read, "Exchange timer armed" which is more accurate.
This patch also adds a debug statement in the timeout handler to properly indicate that the exchange has timed out.
---
drivers/scsi/libfc/fc_exch.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_exch.c +3 -1
@@ -326,7 +326,7 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep,if (ep->state & (FC_EX_RST_CLEANUP |FC_EX_DONE ))return ; -FC_EXCH_DBG (ep,"Exchange timed out, notifying the upper layer\n" ); +FC_EXCH_DBG (ep,"Exchange timer armed\n" );if (schedule_delayed_work (&ep->timeout_work,msecs_to_jiffies (timer_msec)))
@@ -412,6 +412,8 @@ static void fc_exch_timeout(struct work_struct *work)u32 e_stat;int rc =1 ; +FC_EXCH_DBG (ep,"Exchange timed out\n" ); +spin_lock_bh (&ep->ex_lock);if (ep->state & (FC_EX_RST_CLEANUP |FC_EX_DONE )) goto unlock;
PATCH 3/64 fcoe: libfcoe: extra semicolon in CHECK_LOGGING macros causes compile error
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
If using code like this:
if (foo)
FCOE_DBG("foo\n);
else
FCOE_DBG("bar\n");one gets compile errors because FCOE_DBG expands with its own semicolon, making one too many for the if-statement.
Remove the offending semicolon in fcoe.h and also a similar case in libfcoe.c.
---
drivers/scsi/fcoe/fcoe.h | 2 +- drivers/scsi/fcoe/libfcoe.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/fcoe/fcoe.h +1 -1
@@ -53,7 +53,7 @@ do { \do { \CMD ; \ }while (0 ); \ -}while (0 ); +}while (0 ) #define FCOE_DBG(fmt, args...) \ FCOE_CHECK_LOGGING(FCOE_LOGGING, \
drivers/scsi/fcoe/libfcoe.c +1 -1
@@ -69,7 +69,7 @@ do { \do { \CMD ; \ }while (0 ); \ -}while (0 ); +}while (0 ) #define LIBFCOE_DBG(fmt, args...) \ LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
PATCH 4/64 fcoe, libfc: adds per cpu exch pool within exchange manager(EM)
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
Adds per cpu exch pool for these reasons:-
1. Currently an EM instance is shared across all cpus to manage all exches for all cpus. This required em_lock across all cpus for an exch alloc, free, lookup and reset each frame and that made em_lock expensive, so instead having per cpu exch pool with their own per cpu pool lock will likely reduce locking contention in fast path for an exch alloc, free and lookup.
2. Per cpu exch pool will likely improve cache hit ratio since all frames of an exch will be processed on the same cpu on which exch originated.
This patch is only prep work to help in keeping complexity of next patch low, so this patch only sets up per cpu exch pool and related helper funcs to be used by next patch. The next patch fully makes use of per cpu exch pool in all code paths ie. tx, rx and reset.
Divides per EM exch id range equally across all cpus to setup per cpu exch pool. This division is such that lower bits of exch id carries cpu number info on which exch originated, later a simple bitwise AND operation on exch id of incoming frame with fc_cpu_mask retrieves cpu number info to direct all frames to same cpu on which exch originated. This required a global fc_cpu_mask and fc_cpu_order initialized to max possible cpus number nr_cpu_ids rounded up to 2's power, this will be used in mapping exch id and exch ptr array index in pool during exch allocation, find or reset code paths.
Adds a check in fc_exch_mgr_alloc() to ensure specified min_xid lower bits are zero since these bits are used to carry cpu info.
Adds and initializes struct fc_exch_pool with all required fields to manage exches in pool.
Allocates per cpu struct fc_exch_pool with memory for exches array for range of exches per pool. The exches array memory is followed by struct fc_exch_pool.
Adds fc_exch_ptr_get/set() helper functions to get/set exch ptr in pool exches array at specified array index.
Increases default FCOE_MAX_XID to 0x0FFF from 0x07EF, so that more exches are available per cpu after above described exch id range division across all cpus to each pool.
---
drivers/scsi/fcoe/fcoe.h | 2 - drivers/scsi/libfc/fc_exch.c | 89 +++++++++++++++++++++++++++++++++++++++++- include/scsi/libfc.h | 1 3 files changed, 88 insertions(+), 4 deletions(-)
drivers/scsi/fcoe/fcoe.h +1 -1
@@ -38,7 +38,7 @@#define FCOE_MAX_OUTSTANDING_COMMANDS 1024#define FCOE_MIN_XID 0x0000/* the min xid supported by fcoe_sw */ -#define FCOE_MAX_XID 0x07ef/* the max xid supported by fcoe_sw */ +#define FCOE_MAX_XID 0x0FFF/* the max xid supported by fcoe_sw */ unsigned int fcoe_debug_logging;module_param_named (debug_logging, fcoe_debug_logging, int,S_IRUGO |S_IWUSR );
drivers/scsi/libfc/fc_exch.c +86 -3
146 lines not on this page · raw message
include/scsi/libfc.h +1 -0
@@ -343,6 +343,7 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)struct fc_exch_mgr ;struct fc_exch_mgr_anchor ; +extern u16 fc_cpu_mask;/* cpu mask for possible cpus */ /* * Sequence.
PATCH 5/64 fcoe, libfc: fully makes use of per cpu exch pool and then removes em_lock
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
1. Updates fcoe_rcv() to queue incoming frames to the fcoe per cpu thread on which this frame's exch was originated and simply use current cpu for request exch not originated by initiator. It is redundant to add this code under CONFIG_SMP, so removes CONFIG_SMP uses around this code.
2. Updates fc_exch_em_alloc, fc_exch_delete, fc_exch_find to use per cpu exch pools, here fc_exch_delete is rename of older fc_exch_mgr_delete_ep since ep/exch are now deleted in pools of EM and so brief new name is sufficient and better name.
Updates these functions to map exch id to their index into exch pool using fc_cpu_mask, fc_cpu_order and EM min_xid. This mapping is as per detailed explanation about this in last patch and basically this is just as lower fc_cpu_mask bits of exch id as cpu number and upper bit sum of EM min_xid and exch index in pool.
Uses pool next_index to keep track of exch allocation from pool along with pool_max_index as upper bound of exches array in pool.
3. Adds exch pool ptr to fc_exch to free exch to its pool in fc_exch_delete.
4. Updates fc_exch_mgr_reset to reset all exch pools of an EM, this required adding fc_exch_pool_reset func to reset exches in pool and then have fc_exch_mgr_reset call fc_exch_pool_reset for each pool within each EM for a lport.
5. Removes no longer needed exches array, em_lock, next_xid, and total_exches from struct fc_exch_mgr, these are not needed after use of per cpu exch pool, also removes not used max_read, last_read from struct fc_exch_mgr.
6. Updates locking notes for exch pool lock with fc_exch lock and uses pool lock in exch allocation, lookup and reset.
---
drivers/scsi/fcoe/fcoe.c | 19 ++-- drivers/scsi/libfc/fc_exch.c | 189 ++++++++++++++++++++++-------------------- include/scsi/libfc.h | 9 +- 3 files changed, 115 insertions(+), 102 deletions(-)
drivers/scsi/fcoe/fcoe.c +9 -10
@@ -912,8 +912,7 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,struct fcoe_softc *fc;struct fc_frame_header *fh;struct fcoe_percpu_s *fps; -unsigned short oxid; -unsigned int cpu =0 ; +unsigned int cpu; fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); lp = fc->ctlr.lp;
@@ -947,20 +946,20 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,skb_set_transport_header (skb,sizeof (struct fcoe_hdr )); fh = (struct fc_frame_header *)skb_transport_header (skb); - oxid =ntohs (fh->fh_ox_id); - fr =fcoe_dev_from_skb (skb); fr->fr_dev = lp; fr->ptype = ptype; -#ifdef CONFIG_SMP /* -* The incoming frame exchange id(oxid) is ANDed with num of online -* cpu bits to get cpu and then this cpu is used for selecting -* a per cpu kernel thread from fcoe_percpu. +* In case the incoming frame's exchange is originated from +* the initiator, then received frame's exchange id is ANDed +* with fc_cpu_mask bits to get the same cpu on which exchange +* was originated, otherwise just use the current cpu. */ - cpu = oxid & (num_online_cpus () -1 ); -#endif +if (ntoh24 (fh->fh_f_ctl) &FC_FC_EX_CTX ) + cpu =ntohs (fh->fh_ox_id) & fc_cpu_mask; +else + cpu =smp_processor_id (); fps = &per_cpu (fcoe_percpu, cpu);spin_lock_bh (&fps->fcoe_rx_list.lock);
drivers/scsi/libfc/fc_exch.c +100 -89
337 lines not on this page · raw message
include/scsi/libfc.h +6 -3
@@ -368,6 +368,7 @@ struct fc_seq {*/ struct fc_exch {struct fc_exch_mgr *em;/* exchange manager */ +struct fc_exch_pool *pool;/* per cpu exches pool */ u32 state;/* internal driver state */ u16 xid;/* our exchange ID */ struct list_head ex_list;/* free or busy list linkage */
@@ -1045,10 +1046,12 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp);*/ struct fc_seq *fc_seq_start_next (struct fc_seq *sp); +/* -* Reset an exchange manager, completing all sequences and exchanges. -* If s_id is non-zero, reset only exchanges originating from that FID. -* If d_id is non-zero, reset only exchanges sending to that FID. +* Reset all EMs of a lport, releasing its all sequences and +* exchanges. If sid is non-zero, then reset only exchanges +* we sourced from that FID. If did is non-zero, reset only +* exchanges destined to that FID. */ void fc_exch_mgr_reset (struct fc_lport *,u32 s_id,u32 d_id);
PATCH 6/64 libfc: Export FC headers
In reply to Robert LoveExport fc_els.h, fc_fs.h, fc_gs.h and fc_ns.h so that they may be used by applications.
This will be needed for FC Passthrough applications like fcping, but could be used by other applications.
---
include/scsi/Kbuild | 1 + include/scsi/fc/Kbuild | 4 ++++ 2 files changed, 5 insertions(+), 0 deletions(-) create mode 100644 include/scsi/fc/Kbuild
include/scsi/Kbuild +1 -0
@@ -2,3 +2,4 @@ header-y += scsi.h header-y += scsi_netlink.h header-y += scsi_netlink_fc.h header-y += scsi_bsg_fc.h +header-y += fc/
include/scsi/fc/Kbuild new file +4 -0
@@ -0,0 +1,4 @@ +header-y += fc_els.h +header-y += fc_fs.h +header-y += fc_gs.h +header-y += fc_ns.h
Re: [PATCH 06/64] libfc: Export FC headers
Quoted 5 lines · Robert Love
Export
fc_els.h,fc_fs.h,fc_gs.handfc_ns.hso that they may be used by applications.This will be needed for FC Passthrough applications like fcping, but could be used by other applications.
Are there already plans to implement tools like fcping? I have heard people thinking about the idea, but i am not aware of a project working on this.
--
Christof Schmitt
Re: [PATCH 06/64] libfc: Export FC headers
Quoted 11 lines · Christof Schmitt
Quoted 5 lines · Robert Love
Export
fc_els.h,fc_fs.h,fc_gs.handfc_ns.hso that they may be used by applications.This will be needed for FC Passthrough applications like fcping, but could be used by other applications.
Are there already plans to implement tools like fcping? I have heard people thinking about the idea, but i am not aware of a project working on this.
Yeah, we have an implementation in our fcoe-utils package. You can download that package here- git://open-fcoe.org/openfc/fcoe-utils.git.
//Rob
Re: [PATCH 06/64] libfc: Export FC headers
Quoted 15 lines · Robert Love
Quoted 11 lines · Christof Schmitt
Quoted 5 lines · Robert Love
Export
fc_els.h,fc_fs.h,fc_gs.handfc_ns.hso that they may be used by applications.This will be needed for FC Passthrough applications like fcping, but could be used by other applications.
Are there already plans to implement tools like fcping? I have heard people thinking about the idea, but i am not aware of a project working on this.
Yeah, we have an implementation in our fcoe-utils package. You can download that package here-
git://open-fcoe.org/openfc/fcoe-utils.git.
Quoted 6 lines
//Rob
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Rob
Are there any plans to extend your fcoe-utils package with some more tools or functionality ?
Maybe something like fctrace, ...
If so, would you be interested in code contributions in this area ? Not sure about legal so far, but will see.
Cheers Swen
Re: [PATCH 06/64] libfc: Export FC headers
Quoted 23 lines · Swen Schillig
Quoted 15 lines · Robert Love
Quoted 11 lines · Christof Schmitt
Quoted 5 lines · Robert Love
Export
fc_els.h,fc_fs.h,fc_gs.handfc_ns.hso that they may be used by applications.This will be needed for FC Passthrough applications like fcping, but could be used by other applications.
Are there already plans to implement tools like fcping? I have heard people thinking about the idea, but i am not aware of a project working on this.
Yeah, we have an implementation in our fcoe-utils package. You can download that package here-
git://open-fcoe.org/openfc/fcoe-utils.git.Quoted 6 lines
//Rob
--
To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Quoted 6 lines
Hi Rob
Are there any plans to extend your fcoe-utils package with some more tools or functionality ?
Maybe something like fctrace, ...
There aren't any specific plans for new user space tools at the moment. Most of our time is being spent on adding functionality to libfc, libfcoe and fcoe. We're also making some improvements to the other tools in fcoe-utils that you might not care about as much. fcoeadm (interacts with fcoe.ko) and fcoemon (DCB monitoring ans fcoe system service daemon) are the primary applications in that package.
Regarding other applications- Chris Leech is working on patches to add more registration commands (to the directory server) to libfc and to test those changes he has a modified fcping to do directory server queries, using FC passthrough. We'll probably check that tool in too.
Quoted 3 lines
If so, would you be interested in code contributions in this area ? Not sure about legal so far, but will see.
I would definitely be interested contributions. fctrace would be great. Also, if you want to patch fcping or another application so that it works with ZFCP I'd be glad to accept those patches too.
//Rob
PATCH 7/64 fcoe: Add sysfs parameter to fcoe for minimum DDP read I/O size
In reply to Robert LoveFrom: Yi Zou <[email protected]>
This adds fcoe_ddp_min as a module parameter for fcoe module to:/sys/module/fcoe/parameters/ddp_min
It is observed that for some hardware, particularly Intel 82599, there is too much overhead in setting up context for direct data placement (DDP) read when the requested read I/O size is small. This is added as a module parameter for performance tuning and is set as 0 by default and user can change this based on their own hardware.
---
drivers/scsi/fcoe/fcoe.c | 9 ++++++++- 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.c +8 -1
@@ -49,6 +49,12 @@ MODULE_AUTHOR("Open-FCoE.org");MODULE_DESCRIPTION ("FCoE" );MODULE_LICENSE ("GPL v2" ); +/* Performance tuning parameters for fcoe */ +static unsigned int fcoe_ddp_min; +module_param_named (ddp_min, fcoe_ddp_min, uint,S_IRUGO |S_IWUSR ); +MODULE_PARM_DESC (ddp_min,"Minimum I/O size in bytes for " \ +"Direct Data Placement (DDP)." ); +/* fcoe host list */ LIST_HEAD (fcoe_hostlist);DEFINE_RWLOCK (fcoe_hostlist_lock);
@@ -414,7 +420,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,*/ bool fcoe_oem_match (struct fc_frame *fp) { -return fc_fcp_is_read (fr_fsp (fp)); +return fc_fcp_is_read (fr_fsp (fp)) && + (fr_fsp (fp)->data_len > fcoe_ddp_min); }/**
PATCH 8/64 libfcoe: fcoe_ctlr_destroy use cancel_work_sync instead of flush_work
In reply to Robert LoveFrom: Chris Leech <[email protected]>
Use cancel_work_sync() in place of flush_work(), so that fcoe_ctlr_destroy() can be called from a workqueue.
Also, purge the receive queue after the recv_work has been cancled because if recv_work isn't run it's not guaranteed to be empty now.
---
drivers/scsi/fcoe/libfcoe.c | 8 ++++++-- 1 files changed, 6 insertions(+), 2 deletions(-)
drivers/scsi/fcoe/libfcoe.c +6 -2
@@ -148,13 +148,17 @@ static void fcoe_ctlr_reset_fcfs(struct fcoe_ctlr *fip)*/ void fcoe_ctlr_destroy (struct fcoe_ctlr *fip) { -flush_work (&fip->recv_work); +cancel_work_sync (&fip->recv_work); +spin_lock_bh (&fip->fip_recv_list.lock); +__skb_queue_purge (&fip->fip_recv_list); +spin_unlock_bh (&fip->fip_recv_list.lock); +spin_lock_bh (&fip->lock); fip->state =FIP_ST_DISABLED ;fcoe_ctlr_reset_fcfs (fip);spin_unlock_bh (&fip->lock);del_timer_sync (&fip->timer); -flush_work (&fip->link_work); +cancel_work_sync (&fip->link_work); }EXPORT_SYMBOL (fcoe_ctlr_destroy);
PATCH 9/64 fcoe: fix missing error check in call to fcoe_if_init
In reply to Robert LoveFrom: Chris Leech <[email protected]>
fcoe_if_init() can fail, but it's return value wasn't checked
---
drivers/scsi/fcoe/fcoe.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.c +3 -1
@@ -1900,7 +1900,9 @@ static int __init fcoe_init(void)/* Setup link change notification */ fcoe_dev_setup (); -fcoe_if_init (); + rc =fcoe_if_init (); +if (rc) + goto out_free;return 0 ;
PATCH 10/64 fcoe: remove unnecessary list and lock initializations.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The hostlist and the hostlist_lock were initialized both in the delcaration and in fcoe_init(). Remove the unneeded code.
---
drivers/scsi/fcoe/fcoe.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/fcoe.c +0 -3
@@ -1881,9 +1881,6 @@ static int __init fcoe_init(void)int rc =0 ;struct fcoe_percpu_s *p; -INIT_LIST_HEAD (&fcoe_hostlist); -rwlock_init (&fcoe_hostlist_lock); -for_each_possible_cpu (cpu) { p = &per_cpu (fcoe_percpu, cpu);skb_queue_head_init (&p->fcoe_rx_list);
PATCH 11/64 fcoe: interface changes to fcoe_if_create and fcoe_if_destroy
In reply to Robert LoveFrom: Chris Leech <[email protected]>
By passing in the parent device instead of assuming the netdev is what should be used, fcoe_if_create becomes usable for NPIV vports as well. You still need a netdev, because that's how FCoE works. Also removed some duplicate checks from fcoe_if_create that are already in fcoe_create.
fcoe_if_destroy needs to take an lport as it's only argument, not a netdev. That removes the 1:1 netdev:lport assumption from the destroy path.
---
drivers/scsi/fcoe/fcoe.c | 113 ++++++++++++++++++++-------------------------- 1 files changed, 48 insertions(+), 65 deletions(-)
drivers/scsi/fcoe/fcoe.c +48 -65
@@ -1,5 +1,5 @@/* -* Copyright(c) 2007 - 2008 Intel Corporation. All rights reserved. +* Copyright(c) 2007 - 2009 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,
@@ -506,30 +506,20 @@ skip_oem:/** * fcoe_if_destroy() - FCoE software HBA tear-down function -* @netdev: ptr to the associated net_device -* -* Returns: 0 if link is OK for use by FCoE. +* @lport: fc_lport to destroy */ -static int fcoe_if_destroy (struct net_device *netdev) +static void fcoe_if_destroy (struct fc_lport *lport) { -struct fc_lport *lp =NULL ; -struct fcoe_softc *fc; - -BUG_ON (!netdev); +struct fcoe_softc *fc =lport_priv (lport); +struct net_device *netdev = fc->netdev;FCOE_NETDEV_DBG (netdev,"Destroying interface\n" ); - lp =fcoe_hostlist_lookup (netdev); -if (!lp) -return -ENODEV ; - - fc =lport_priv (lp); -/* Logout of the fabric */ -fc_fabric_logoff (lp); +fc_fabric_logoff (lport);/* Remove the instance from fcoe's list */ -fcoe_hostlist_remove (lp); +fcoe_hostlist_remove (lport);/* clean up netdev configurations */ fcoe_netdev_cleanup (fc);
@@ -538,33 +528,31 @@ static int fcoe_if_destroy(struct net_device *netdev)fcoe_ctlr_destroy (&fc->ctlr);/* Free queued packets for the per-CPU receive threads */ -fcoe_percpu_clean (lp); +fcoe_percpu_clean (lport);/* Cleanup the fc_lport */ -fc_lport_destroy (lp); -fc_fcp_destroy (lp); +fc_lport_destroy (lport); +fc_fcp_destroy (lport);/* Detach from the scsi-ml */ -fc_remove_host (lp->host); -scsi_remove_host (lp->host); +fc_remove_host (lport->host); +scsi_remove_host (lport->host);/* There are no more rports or I/O, free the EM */ -fc_exch_mgr_free (lp); +fc_exch_mgr_free (lport);/* Free existing skbs */ -fcoe_clean_pending_queue (lp); +fcoe_clean_pending_queue (lport);/* Stop the timer */ del_timer_sync (&fc->timer);/* Free memory used by statistical counters */ -fc_lport_free_stats (lp); +fc_lport_free_stats (lport);/* Release the net_device and Scsi_Host */ dev_put (netdev); -scsi_host_put (lp->host); - -return 0 ; +scsi_host_put (lport->host); }/*
@@ -612,38 +600,35 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {/** * fcoe_if_create() - this function creates the fcoe interface * @netdev: pointer the associated netdevice +* @parent: device pointer to be the parent in sysfs for the SCSI host * * Creates fc_lport struct and scsi_host for lport, configures lport * and starts fabric login. * -* Returns : 0 on success +* Returns : The allocated fc_lport or an error pointer */ -static int fcoe_if_create (struct net_device *netdev) +static struct fc_lport *fcoe_if_create (struct net_device *netdev, +struct device *parent) {int rc; -struct fc_lport *lp =NULL ; +struct fc_lport *lport =NULL ;struct fcoe_softc *fc;struct Scsi_Host *shost; -BUG_ON (!netdev); -FCOE_NETDEV_DBG (netdev,"Create Interface\n" ); - lp =fcoe_hostlist_lookup (netdev); -if (lp) -return -EEXIST ; - shost =libfc_host_alloc (&fcoe_shost_template,sizeof (struct fcoe_softc ));if (!shost) {FCOE_NETDEV_DBG (netdev,"Could not allocate host structure\n" ); -return -ENOMEM ; + rc = -ENOMEM ; + goto out; } - lp =shost_priv (shost); - fc =lport_priv (lp); + lport =shost_priv (shost); + fc =lport_priv (lport);/* configure fc_lport, e.g., em */ - rc =fcoe_lport_config (lp); + rc =fcoe_lport_config (lport);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure lport for the " "interface\n" );
@@ -658,7 +643,7 @@ static int fcoe_if_create(struct net_device *netdev) fc->ctlr.update_mac = fcoe_update_src_mac;/* configure lport network properties */ - rc =fcoe_netdev_config (lp, netdev); + rc =fcoe_netdev_config (lport, netdev);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure netdev for the " "interface\n" );
@@ -666,7 +651,7 @@ static int fcoe_if_create(struct net_device *netdev) }/* configure lport scsi host properties */ - rc =fcoe_shost_config (lp, shost, &netdev->dev); + rc =fcoe_shost_config (lport, shost, parent);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure shost for the " "interface\n" );
@@ -674,7 +659,7 @@ static int fcoe_if_create(struct net_device *netdev) }/* Initialize the library */ - rc =fcoe_libfc_config (lp, &fcoe_libfc_fcn_templ); + rc =fcoe_libfc_config (lport, &fcoe_libfc_fcn_templ);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure libfc for the " "interface\n" );
@@ -689,7 +674,7 @@ static int fcoe_if_create(struct net_device *netdev)*/ write_lock (&fcoe_hostlist_lock);/* lport exch manager allocation */ - rc =fcoe_em_config (lp); + rc =fcoe_em_config (lport);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure the EM for the " "interface\n" );
@@ -697,27 +682,28 @@ static int fcoe_if_create(struct net_device *netdev) }/* add to lports list */ -fcoe_hostlist_add (lp); +fcoe_hostlist_add (lport);write_unlock (&fcoe_hostlist_lock); - lp->boot_time = jiffies; + lport->boot_time = jiffies; -fc_fabric_login (lp); +fc_fabric_login (lport); -if (!fcoe_link_ok (lp)) +if (!fcoe_link_ok (lport))fcoe_ctlr_link_up (&fc->ctlr);dev_hold (netdev); -return rc; +return lport; out_lp_destroy: -fc_exch_mgr_free (lp); +fc_exch_mgr_free (lport); out_netdev_cleanup:fcoe_netdev_cleanup (fc); out_host_put: -scsi_host_put (lp->host); -return rc; +scsi_host_put (lport->host); +out: +return ERR_PTR (rc); }/**
@@ -1616,8 +1602,9 @@ static int fcoe_ethdrv_put(const struct net_device *netdev)*/ static int fcoe_destroy (const char *buffer,struct kernel_param *kp) { -int rc;struct net_device *netdev; +struct fc_lport *lport; +int rc; netdev =fcoe_if_to_netdev (buffer);if (!netdev) {
@@ -1625,17 +1612,12 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; }/* look for existing lport */ -if (!fcoe_hostlist_lookup (netdev)) { + lport =fcoe_hostlist_lookup (netdev); +if (!lport) { rc = -ENODEV ; goto out_putdev; } - rc =fcoe_if_destroy (netdev); -if (rc) { -printk (KERN_ERR "fcoe: Failed to destroy interface (%s)\n" , - netdev->name); - rc = -EIO ; - goto out_putdev; - } +fcoe_if_destroy (lport);fcoe_ethdrv_put (netdev); rc =0 ; out_putdev:
@@ -1654,6 +1636,7 @@ out_nodev:static int fcoe_create (const char *buffer,struct kernel_param *kp) {int rc; +struct fc_lport *lport;struct net_device *netdev; netdev =fcoe_if_to_netdev (buffer);
@@ -1668,8 +1651,8 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) }fcoe_ethdrv_get (netdev); - rc =fcoe_if_create (netdev); -if (rc) { + lport =fcoe_if_create (netdev, &netdev->dev); +if (IS_ERR (lport)) {printk (KERN_ERR "fcoe: Failed to create interface (%s)\n" , netdev->name);fcoe_ethdrv_put (netdev);
@@ -1926,7 +1909,7 @@ static void __exit fcoe_exit(void)/* releases the associated fcoe hosts */ list_for_each_entry_safe (fc, tmp, &fcoe_hostlist, list) -fcoe_if_destroy (fc->netdev); +fcoe_if_destroy (fc->ctlr.lp);unregister_hotcpu_notifier (&fcoe_cpu_notifier);
PATCH 12/64 fcoe: Introduce and allocate fcoe_interface structure, 1:1 with net_device
In reply to Robert LoveFrom: Chris Leech <[email protected]>
In preparation for NPIV support, I'm splitting the fcoe instance structure into two to remove the assumptions about it being 1:1 with the net_device. There will now be two structures, one which is 1:1 with the underlying net_device and one which is allocated per virtual SCSI/FC host.
fcoe_softc is renamed to fcoe_port for the per Scsi_Host FCoE private data.
Later patches with start moving shared stuff from fcoe_port to fcoe_interface
---
drivers/scsi/fcoe/fcoe.c | 326 ++++++++++++++++++++++++---------------------- drivers/scsi/fcoe/fcoe.h | 19 ++- 2 files changed, 188 insertions(+), 157 deletions(-)
drivers/scsi/fcoe/fcoe.c +173 -153
@@ -151,10 +151,10 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,struct packet_type *ptype, struct net_device *orig_dev) { - struct fcoe_softc *fc; + struct fcoe_port *port; - fc = container_of(ptype, struct fcoe_softc, fip_packet_type); -fcoe_ctlr_recv (&fc->ctlr, skb); + port = container_of(ptype, struct fcoe_port, fip_packet_type); +fcoe_ctlr_recv (&port->ctlr, skb);return 0 ; }
@@ -180,13 +180,13 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)*/ static void fcoe_update_src_mac (struct fcoe_ctlr *fip,u8 *old,u8 *new) { -struct fcoe_softc *fc; +struct fcoe_port *port; - fc =fcoe_from_ctlr (fip); + port =fcoe_from_ctlr (fip);rtnl_lock ();if (!is_zero_ether_addr (old)) -dev_unicast_delete (fc->netdev, old); -dev_unicast_add (fc->netdev, new); +dev_unicast_delete (port->netdev, old); +dev_unicast_add (port->netdev, new);rtnl_unlock (); }
@@ -224,25 +224,25 @@ static int fcoe_lport_config(struct fc_lport *lp)/** * fcoe_netdev_cleanup() - clean up netdev configurations -* @fc: ptr to the fcoe_softc +* @port: ptr to the fcoe_port */ -void fcoe_netdev_cleanup (struct fcoe_softc *fc) +void fcoe_netdev_cleanup (struct fcoe_port *port) {u8 flogi_maddr[ETH_ALEN ];/* Don't listen for Ethernet packets anymore */ -dev_remove_pack (&fc->fcoe_packet_type); -dev_remove_pack (&fc->fip_packet_type); +dev_remove_pack (&port->fcoe_packet_type); +dev_remove_pack (&port->fip_packet_type);/* Delete secondary MAC addresses */ rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); -dev_unicast_delete (fc->netdev, flogi_maddr); -if (!is_zero_ether_addr (fc->ctlr.data_src_addr)) -dev_unicast_delete (fc->netdev, fc->ctlr.data_src_addr); -if (fc->ctlr.spma) -dev_unicast_delete (fc->netdev, fc->ctlr.ctl_src_addr); -dev_mc_delete (fc->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +dev_unicast_delete (port->netdev, flogi_maddr); +if (!is_zero_ether_addr (port->ctlr.data_src_addr)) +dev_unicast_delete (port->netdev, port->ctlr.data_src_addr); +if (port->ctlr.spma) +dev_unicast_delete (port->netdev, port->ctlr.ctl_src_addr); +dev_mc_delete (port->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock (); }
@@ -271,14 +271,14 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) {u32 mfs;u64 wwnn, wwpn; -struct fcoe_softc *fc; +struct fcoe_port *port;u8 flogi_maddr[ETH_ALEN ];struct netdev_hw_addr *ha;/* Setup lport private data to point to fcoe softc */ - fc =lport_priv (lp); - fc->ctlr.lp = lp; - fc->netdev = netdev; + port =lport_priv (lp); + port->ctlr.lp = lp; + port->netdev = netdev;/* Do not support for bonding device */ if ((netdev->priv_flags & IFF_MASTER_ALB) ||
@@ -317,27 +317,27 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)FCOE_NETDEV_DBG (netdev,"Supports LRO for max xid 0x%x\n" , lp->lro_xid); } -skb_queue_head_init (&fc->fcoe_pending_queue); - fc->fcoe_pending_queue_active =0 ; -setup_timer (&fc->timer, fcoe_queue_timer, (unsigned long )lp); +skb_queue_head_init (&port->fcoe_pending_queue); + port->fcoe_pending_queue_active =0 ; +setup_timer (&port->timer, fcoe_queue_timer, (unsigned long )lp);/* look for SAN MAC address, if multiple SAN MACs exist, only * use the first one for SPMA */ rcu_read_lock ();for_each_dev_addr (netdev, ha) {if ((ha->type ==NETDEV_HW_ADDR_T_SAN ) && - (is_valid_ether_addr (ha->addr))) { -memcpy (fc->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); - fc->ctlr.spma =1 ; + (is_valid_ether_addr (port->ctlr.ctl_src_addr))) { +memcpy (port->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); + port->ctlr.spma =1 ;break ; } }rcu_read_unlock ();/* setup Source Mac Address */ -if (!fc->ctlr.spma) -memcpy (fc->ctlr.ctl_src_addr, netdev->dev_addr, - fc->netdev->addr_len); +if (!port->ctlr.spma) +memcpy (port->ctlr.ctl_src_addr, netdev->dev_addr, + netdev->addr_len); wwnn =fcoe_wwn_from_mac (netdev->dev_addr,1 ,0 );fc_set_wwnn (lp, wwnn);
@@ -353,8 +353,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN );dev_unicast_add (netdev, flogi_maddr); -if (fc->ctlr.spma) -dev_unicast_add (netdev, fc->ctlr.ctl_src_addr); +if (port->ctlr.spma) +dev_unicast_add (netdev, port->ctlr.ctl_src_addr);dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock ();
@@ -362,15 +362,15 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)* setup the receive function from ethernet driver * on the ethertype for the given device */ - fc->fcoe_packet_type.func = fcoe_rcv; - fc->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); - fc->fcoe_packet_type.dev = netdev; -dev_add_pack (&fc->fcoe_packet_type); + port->fcoe_packet_type.func = fcoe_rcv; + port->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); + port->fcoe_packet_type.dev = netdev; +dev_add_pack (&port->fcoe_packet_type); - fc->fip_packet_type.func = fcoe_fip_recv; - fc->fip_packet_type.type =htons (ETH_P_FIP ); - fc->fip_packet_type.dev = netdev; -dev_add_pack (&fc->fip_packet_type); + port->fip_packet_type.func = fcoe_fip_recv; + port->fip_packet_type.type =htons (ETH_P_FIP ); + port->fip_packet_type.dev = netdev; +dev_add_pack (&port->fip_packet_type);return 0 ; }
@@ -426,7 +426,7 @@ bool fcoe_oem_match(struct fc_frame *fp)/** * fcoe_em_config() - allocates em for this lport -* @lp: the port that em is to allocated for +* @lp: the fcoe that em is to allocated for * * Called with write fcoe_hostlist_lock held. *
@@ -434,8 +434,9 @@ bool fcoe_oem_match(struct fc_frame *fp)*/ static inline int fcoe_em_config (struct fc_lport *lp) { -struct fcoe_softc *fc =lport_priv (lp); -struct fcoe_softc *oldfc =NULL ; +struct fcoe_interface *fcoe; +struct fcoe_port *port =lport_priv (lp); +struct fcoe_port *oldfc =NULL ;struct net_device *old_real_dev, *cur_real_dev;u16 min_xid =FCOE_MIN_XID ;u16 max_xid =FCOE_MAX_XID ;
@@ -453,38 +454,39 @@ static inline int fcoe_em_config(struct fc_lport *lp)* Reuse existing offload em instance in case * it is already allocated on real eth device */ -if (fc->netdev->priv_flags &IFF_802_1Q_VLAN ) - cur_real_dev =vlan_dev_real_dev (fc->netdev); +if (port->netdev->priv_flags &IFF_802_1Q_VLAN ) + cur_real_dev =vlan_dev_real_dev (port->netdev);else - cur_real_dev = fc->netdev; + cur_real_dev = port->netdev; -list_for_each_entry (oldfc, &fcoe_hostlist, list) { +list_for_each_entry (fcoe, &fcoe_hostlist, list) { + oldfc = fcoe->priv;if (oldfc->netdev->priv_flags &IFF_802_1Q_VLAN ) old_real_dev =vlan_dev_real_dev (oldfc->netdev);else old_real_dev = oldfc->netdev;if (cur_real_dev == old_real_dev) { - fc->oem = oldfc->oem; + port->oem = oldfc->oem;break ; } } -if (fc->oem) { -if (!fc_exch_mgr_add (lp, fc->oem, fcoe_oem_match)) { +if (port->oem) { +if (!fc_exch_mgr_add (lp, port->oem, fcoe_oem_match)) {printk (KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n" , - fc->oem, fc->netdev->name); + port->oem, port->netdev->name);return -ENOMEM ; } }else { - fc->oem =fc_exch_mgr_alloc (lp,FC_CLASS_3 , + port->oem =fc_exch_mgr_alloc (lp,FC_CLASS_3 ,FCOE_MIN_XID , lp->lro_xid, fcoe_oem_match); -if (!fc->oem) { +if (!port->oem) {printk (KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n" , - fc->netdev->name); + port->netdev->name);return -ENOMEM ; } }
@@ -497,7 +499,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) skip_oem:if (!fc_exch_mgr_alloc (lp,FC_CLASS_3 , min_xid, max_xid,NULL )) {printk (KERN_ERR "fcoe_em_config: failed to " -"allocate em on interface %s\n" , fc->netdev->name); +"allocate em on interface %s\n" , port->netdev->name);return -ENOMEM ; }
@@ -510,8 +512,9 @@ skip_oem:*/ static void fcoe_if_destroy (struct fc_lport *lport) { -struct fcoe_softc *fc =lport_priv (lport); -struct net_device *netdev = fc->netdev; +struct fcoe_port *port =lport_priv (lport); +struct fcoe_interface *fcoe = port->fcoe; +struct net_device *netdev = port->netdev;FCOE_NETDEV_DBG (netdev,"Destroying interface\n" );
@@ -522,10 +525,10 @@ static void fcoe_if_destroy(struct fc_lport *lport)fcoe_hostlist_remove (lport);/* clean up netdev configurations */ -fcoe_netdev_cleanup (fc); +fcoe_netdev_cleanup (port);/* tear-down the FCoE controller */ -fcoe_ctlr_destroy (&fc->ctlr); +fcoe_ctlr_destroy (&port->ctlr);/* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean (lport);
@@ -545,7 +548,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)fcoe_clean_pending_queue (lport);/* Stop the timer */ -del_timer_sync (&fc->timer); +del_timer_sync (&port->timer);/* Free memory used by statistical counters */ fc_lport_free_stats (lport);
@@ -553,6 +556,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* Release the net_device and Scsi_Host */ dev_put (netdev);scsi_host_put (lport->host); +kfree (fcoe);/* TODO, should be refcounted */ }/*
@@ -612,20 +616,31 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, {int rc;struct fc_lport *lport =NULL ; -struct fcoe_softc *fc; +struct fcoe_port *port; +struct fcoe_interface *fcoe;struct Scsi_Host *shost;FCOE_NETDEV_DBG (netdev,"Create Interface\n" ); + fcoe =kzalloc (sizeof (*fcoe),GFP_KERNEL ); +if (!fcoe) { +FCOE_NETDEV_DBG (netdev,"Could not allocate fcoe structure\n" ); + rc = -ENOMEM ; + goto out; + } + shost =libfc_host_alloc (&fcoe_shost_template, -sizeof (struct fcoe_softc )); +sizeof (struct fcoe_port ));if (!shost) {FCOE_NETDEV_DBG (netdev,"Could not allocate host structure\n" ); rc = -ENOMEM ; - goto out; + goto out_kfree_port; } lport =shost_priv (shost); - fc =lport_priv (lport); + port =lport_priv (lport); + + port->fcoe = fcoe; + fcoe->priv = port;/* configure fc_lport, e.g., em */ rc =fcoe_lport_config (lport);
@@ -638,9 +653,9 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev,/* * Initialize FIP. */ -fcoe_ctlr_init (&fc->ctlr); - fc->ctlr.send = fcoe_fip_send; - fc->ctlr.update_mac = fcoe_update_src_mac; +fcoe_ctlr_init (&port->ctlr); + port->ctlr.send = fcoe_fip_send; + port->ctlr.update_mac = fcoe_update_src_mac;/* configure lport network properties */ rc =fcoe_netdev_config (lport, netdev);
@@ -690,7 +705,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev,fc_fabric_login (lport);if (!fcoe_link_ok (lport)) -fcoe_ctlr_link_up (&fc->ctlr); +fcoe_ctlr_link_up (&port->ctlr);dev_hold (netdev);
@@ -699,9 +714,11 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, out_lp_destroy:fc_exch_mgr_free (lport); out_netdev_cleanup: -fcoe_netdev_cleanup (fc); +fcoe_netdev_cleanup (port); out_host_put:scsi_host_put (lport->host); +out_kfree_port: +kfree (fcoe); out:return ERR_PTR (rc); }
@@ -902,13 +919,13 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, {struct fc_lport *lp;struct fcoe_rcv_info *fr; -struct fcoe_softc *fc; +struct fcoe_port *port;struct fc_frame_header *fh;struct fcoe_percpu_s *fps;unsigned int cpu; - fc = container_of(ptype, struct fcoe_softc, fcoe_packet_type); - lp = fc->ctlr.lp; + port = container_of(ptype, struct fcoe_port, fcoe_packet_type); + lp = port->ctlr.lp;if (unlikely (lp ==NULL )) {FCOE_NETDEV_DBG (dev,"Cannot find hba structure" ); goto err2;
@@ -1059,7 +1076,7 @@ static int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen)* fcoe_fc_crc() - calculates FC CRC in this fcoe skb * @fp: the fc_frame containing data to be checksummed * -* This uses crc32() to calculate the crc for fc frame +* This uses crc32() to calculate the crc for port frame * Return : 32 bit crc */ u32 fcoe_fc_crc (struct fc_frame *fp)
@@ -1092,7 +1109,7 @@ u32 fcoe_fc_crc(struct fc_frame *fp)/** * fcoe_xmit() - FCoE frame transmit function -* @lp: the associated local port +* @lp: the associated local fcoe * @fp: the fc_frame to be transmitted * * Return : 0 for success
@@ -1109,13 +1126,13 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)unsigned int hlen;/* header length implies the version */ unsigned int tlen;/* trailer length */ unsigned int elen;/* eth header, may include vlan */ -struct fcoe_softc *fc; +struct fcoe_port *port;u8 sof, eof;struct fcoe_hdr *hp;WARN_ON ((fr_len (fp) %sizeof (u32)) !=0 ); - fc =lport_priv (lp); + port =lport_priv (lp); fh =fc_frame_header_get (fp); skb =fp_skb (fp); wlen = skb->len /FCOE_WORD_TO_BYTE ;
@@ -1126,7 +1143,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) }if (unlikely (fh->fh_r_ctl ==FC_RCTL_ELS_REQ ) && -fcoe_ctlr_els_send (&fc->ctlr, skb)) +fcoe_ctlr_els_send (&port->ctlr, skb))return 0 ; sof =fr_sof (fp);
@@ -1148,7 +1165,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) crc =fcoe_fc_crc (fp); } -/* copy fc crc and eof to the skb buff */ +/* copy port crc and eof to the skb buff */ if (skb_is_nonlinear (skb)) {skb_frag_t *frag;if (fcoe_get_paged_crc_eof (skb, tlen)) {
@@ -1171,27 +1188,27 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) cp =NULL ; } -/* adjust skb network/transport offsets to match mac/fcoe/fc */ +/* adjust skb network/transport offsets to match mac/fcoe/port */ skb_push (skb, elen + hlen);skb_reset_mac_header (skb);skb_reset_network_header (skb); skb->mac_len = elen; skb->protocol =htons (ETH_P_FCOE ); - skb->dev = fc->netdev; + skb->dev = port->netdev;/* fill up mac and fcoe headers */ eh =eth_hdr (skb); eh->h_proto =htons (ETH_P_FCOE ); -if (fc->ctlr.map_dest) +if (port->ctlr.map_dest)fc_fcoe_set_mac (eh->h_dest, fh->fh_d_id);else /* insert GW address */ -memcpy (eh->h_dest, fc->ctlr.dest_addr,ETH_ALEN ); +memcpy (eh->h_dest, port->ctlr.dest_addr,ETH_ALEN ); -if (unlikely (fc->ctlr.flogi_oxid !=FC_XID_UNKNOWN )) -memcpy (eh->h_source, fc->ctlr.ctl_src_addr,ETH_ALEN ); +if (unlikely (port->ctlr.flogi_oxid !=FC_XID_UNKNOWN )) +memcpy (eh->h_source, port->ctlr.ctl_src_addr,ETH_ALEN );else -memcpy (eh->h_source, fc->ctlr.data_src_addr,ETH_ALEN ); +memcpy (eh->h_source, port->ctlr.data_src_addr,ETH_ALEN ); hp = (struct fcoe_hdr *)(eh +1 );memset (hp,0 ,sizeof (*hp));
@@ -1214,7 +1231,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)/* send down to lld */ fr_dev (fp) = lp; -if (fc->fcoe_pending_queue.qlen) +if (port->fcoe_pending_queue.qlen)fcoe_check_wait_queue (lp, skb);else if (fcoe_start_io (skb))fcoe_check_wait_queue (lp, skb);
@@ -1240,7 +1257,7 @@ int fcoe_percpu_receive_thread(void *arg)struct fcoe_crc_eof crc_eof;struct fc_frame *fp;u8 *mac =NULL ; -struct fcoe_softc *fc; +struct fcoe_port *port;struct fcoe_hdr *hp;set_user_nice (current,-20 );
@@ -1276,7 +1293,7 @@ int fcoe_percpu_receive_thread(void *arg)/* * Save source MAC address before discarding header. */ - fc =lport_priv (lp); + port =lport_priv (lp);if (skb_is_nonlinear (skb))skb_linearize (skb);/* not ideal */ mac =eth_hdr (skb)->h_source;
@@ -1354,8 +1371,8 @@ int fcoe_percpu_receive_thread(void *arg) }fr_flags (fp) &= ~FCPHF_CRC_UNCHECKED ; } -if (unlikely (fc->ctlr.flogi_oxid !=FC_XID_UNKNOWN ) && -fcoe_ctlr_recv_flogi (&fc->ctlr, fp, mac)) { +if (unlikely (port->ctlr.flogi_oxid !=FC_XID_UNKNOWN ) && +fcoe_ctlr_recv_flogi (&port->ctlr, fp, mac)) {fc_frame_free (fp);continue ; }
@@ -1379,46 +1396,46 @@ int fcoe_percpu_receive_thread(void *arg)*/ static void fcoe_check_wait_queue (struct fc_lport *lp,struct sk_buff *skb) { -struct fcoe_softc *fc =lport_priv (lp); +struct fcoe_port *port =lport_priv (lp);int rc; -spin_lock_bh (&fc->fcoe_pending_queue.lock); +spin_lock_bh (&port->fcoe_pending_queue.lock);if (skb) -__skb_queue_tail (&fc->fcoe_pending_queue, skb); +__skb_queue_tail (&port->fcoe_pending_queue, skb); -if (fc->fcoe_pending_queue_active) +if (port->fcoe_pending_queue_active) goto out; - fc->fcoe_pending_queue_active =1 ; + port->fcoe_pending_queue_active =1 ; -while (fc->fcoe_pending_queue.qlen) { +while (port->fcoe_pending_queue.qlen) {/* keep qlen > 0 until fcoe_start_io succeeds */ - fc->fcoe_pending_queue.qlen++; - skb =__skb_dequeue (&fc->fcoe_pending_queue); + port->fcoe_pending_queue.qlen++; + skb =__skb_dequeue (&port->fcoe_pending_queue); -spin_unlock_bh (&fc->fcoe_pending_queue.lock); +spin_unlock_bh (&port->fcoe_pending_queue.lock); rc =fcoe_start_io (skb); -spin_lock_bh (&fc->fcoe_pending_queue.lock); +spin_lock_bh (&port->fcoe_pending_queue.lock);if (rc) { -__skb_queue_head (&fc->fcoe_pending_queue, skb); +__skb_queue_head (&port->fcoe_pending_queue, skb);/* undo temporary increment above */ - fc->fcoe_pending_queue.qlen--; + port->fcoe_pending_queue.qlen--;break ; }/* undo temporary increment above */ - fc->fcoe_pending_queue.qlen--; + port->fcoe_pending_queue.qlen--; } -if (fc->fcoe_pending_queue.qlen <FCOE_LOW_QUEUE_DEPTH ) +if (port->fcoe_pending_queue.qlen <FCOE_LOW_QUEUE_DEPTH ) lp->qfull =0 ; -if (fc->fcoe_pending_queue.qlen && !timer_pending (&fc->timer)) -mod_timer (&fc->timer, jiffies +2 ); - fc->fcoe_pending_queue_active =0 ; +if (port->fcoe_pending_queue.qlen && !timer_pending (&port->timer)) +mod_timer (&port->timer, jiffies +2 ); + port->fcoe_pending_queue_active =0 ; out: -if (fc->fcoe_pending_queue.qlen >FCOE_MAX_QUEUE_DEPTH ) +if (port->fcoe_pending_queue.qlen >FCOE_MAX_QUEUE_DEPTH ) lp->qfull =1 ; -spin_unlock_bh (&fc->fcoe_pending_queue.lock); +spin_unlock_bh (&port->fcoe_pending_queue.lock);return ; }
@@ -1453,16 +1470,18 @@ static int fcoe_device_notification(struct notifier_block *notifier, {struct fc_lport *lp =NULL ;struct net_device *netdev = ptr; -struct fcoe_softc *fc; +struct fcoe_interface *fcoe; +struct fcoe_port *port =NULL ;struct fcoe_dev_stats *stats;u32 link_possible =1 ;u32 mfs;int rc =NOTIFY_OK ;read_lock (&fcoe_hostlist_lock); -list_for_each_entry (fc, &fcoe_hostlist, list) { -if (fc->netdev == netdev) { - lp = fc->ctlr.lp; +list_for_each_entry (fcoe, &fcoe_hostlist, list) { + port = fcoe->priv; +if (port->netdev == netdev) { + lp = port->ctlr.lp;break ; } }
@@ -1493,8 +1512,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, "from netdev netlink\n", event); }if (link_possible && !fcoe_link_ok (lp)) -fcoe_ctlr_link_up (&fc->ctlr); -else if (fcoe_ctlr_link_down (&fc->ctlr)) { +fcoe_ctlr_link_up (&port->ctlr); +else if (fcoe_ctlr_link_down (&port->ctlr)) { stats =fc_lport_get_stats (lp); stats->LinkFailureCount++;fcoe_clean_pending_queue (lp);
@@ -1668,10 +1687,10 @@ out_nodev:module_param_call (create, fcoe_create,NULL ,NULL ,S_IWUSR );__MODULE_PARM_TYPE (create,"string" ); -MODULE_PARM_DESC (create,"Create fcoe port using net device passed in." ); +MODULE_PARM_DESC (create,"Create fcoe fcoe using net device passed in." );module_param_call (destroy, fcoe_destroy,NULL ,NULL ,S_IWUSR );__MODULE_PARM_TYPE (destroy,"string" ); -MODULE_PARM_DESC (destroy,"Destroy fcoe port" ); +MODULE_PARM_DESC (destroy,"Destroy fcoe fcoe" );/** * fcoe_link_ok() - Check if link is ok for the fc_lport
@@ -1689,8 +1708,8 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe port");*/ int fcoe_link_ok (struct fc_lport *lp) { -struct fcoe_softc *fc =lport_priv (lp); -struct net_device *dev = fc->netdev; +struct fcoe_port *port =lport_priv (lp); +struct net_device *dev = port->netdev;struct ethtool_cmd ecmd = {ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
@@ -1752,16 +1771,16 @@ void fcoe_percpu_clean(struct fc_lport *lp)*/ void fcoe_clean_pending_queue (struct fc_lport *lp) { -struct fcoe_softc *fc =lport_priv (lp); +struct fcoe_port *port =lport_priv (lp);struct sk_buff *skb; -spin_lock_bh (&fc->fcoe_pending_queue.lock); -while ((skb =__skb_dequeue (&fc->fcoe_pending_queue)) !=NULL ) { -spin_unlock_bh (&fc->fcoe_pending_queue.lock); +spin_lock_bh (&port->fcoe_pending_queue.lock); +while ((skb =__skb_dequeue (&port->fcoe_pending_queue)) !=NULL ) { +spin_unlock_bh (&port->fcoe_pending_queue.lock);kfree_skb (skb); -spin_lock_bh (&fc->fcoe_pending_queue.lock); +spin_lock_bh (&port->fcoe_pending_queue.lock); } -spin_unlock_bh (&fc->fcoe_pending_queue.lock); +spin_unlock_bh (&port->fcoe_pending_queue.lock); }/**
@@ -1778,21 +1797,21 @@ int fcoe_reset(struct Scsi_Host *shost) }/** -* fcoe_hostlist_lookup_softc() - find the corresponding lport by a given device +* fcoe_hostlist_lookup_port() - find the corresponding lport by a given device * @dev: this is currently ptr to net_device * * Called with fcoe_hostlist_lock held. * -* Returns: NULL or the located fcoe_softc +* Returns: NULL or the located fcoe_port */ -static struct fcoe_softc * -fcoe_hostlist_lookup_softc (const struct net_device *dev) +static struct fcoe_interface * +fcoe_hostlist_lookup_port (const struct net_device *dev) { -struct fcoe_softc *fc; +struct fcoe_interface *fcoe; -list_for_each_entry (fc, &fcoe_hostlist, list) { -if (fc->netdev == dev) -return fc; +list_for_each_entry (fcoe, &fcoe_hostlist, list) { +if (fcoe->priv->netdev == dev) +return fcoe; }return NULL ; }
@@ -1805,13 +1824,13 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev)*/ struct fc_lport *fcoe_hostlist_lookup (const struct net_device *netdev) { -struct fcoe_softc *fc; +struct fcoe_interface *fcoe;read_lock (&fcoe_hostlist_lock); - fc =fcoe_hostlist_lookup_softc (netdev); + fcoe =fcoe_hostlist_lookup_port (netdev);read_unlock (&fcoe_hostlist_lock); -return (fc) ? fc->ctlr.lp :NULL ; +return (fcoe) ? fcoe->priv->ctlr.lp :NULL ; }/**
@@ -1822,14 +1841,16 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)* * Returns: 0 for success */ -int fcoe_hostlist_add (const struct fc_lport *lp) +int fcoe_hostlist_add (const struct fc_lport *lport) { -struct fcoe_softc *fc; - - fc =fcoe_hostlist_lookup_softc (fcoe_netdev (lp)); -if (!fc) { - fc =lport_priv (lp); -list_add_tail (&fc->list, &fcoe_hostlist); +struct fcoe_interface *fcoe; +struct fcoe_port *port; + + fcoe =fcoe_hostlist_lookup_port (fcoe_netdev (lport)); +if (!fcoe) { + port =lport_priv (lport); + fcoe = port->fcoe; +list_add_tail (&fcoe->list, &fcoe_hostlist); }return 0 ; }
@@ -1840,14 +1861,14 @@ int fcoe_hostlist_add(const struct fc_lport *lp)* * Returns: 0 for success */ -int fcoe_hostlist_remove (const struct fc_lport *lp) +int fcoe_hostlist_remove (const struct fc_lport *lport) { -struct fcoe_softc *fc; +struct fcoe_interface *fcoe;write_lock_bh (&fcoe_hostlist_lock); - fc =fcoe_hostlist_lookup_softc (fcoe_netdev (lp)); -BUG_ON (!fc); -list_del (&fc->list); + fcoe =fcoe_hostlist_lookup_port (fcoe_netdev (lport)); +BUG_ON (!fcoe); +list_del (&fcoe->list);write_unlock_bh (&fcoe_hostlist_lock);return 0 ;
@@ -1903,19 +1924,18 @@ module_init(fcoe_init); static void __exit fcoe_exit(void) {unsigned int cpu; -struct fcoe_softc *fc, *tmp; +struct fcoe_interface *fcoe, *tmp;fcoe_dev_cleanup ();/* releases the associated fcoe hosts */ -list_for_each_entry_safe (fc, tmp, &fcoe_hostlist, list) -fcoe_if_destroy (fc->ctlr.lp); +list_for_each_entry_safe (fcoe, tmp, &fcoe_hostlist, list) +fcoe_if_destroy (fcoe->priv->ctlr.lp);unregister_hotcpu_notifier (&fcoe_cpu_notifier); -for_each_online_cpu (cpu) { +for_each_online_cpu (cpu)fcoe_percpu_thread_destroy (cpu); - }/* detach from scsi transport */ fcoe_if_exit ();
drivers/scsi/fcoe/fcoe.h +15 -4
@@ -75,10 +75,21 @@ struct fcoe_percpu_s { };/* -* the fcoe sw transport private data +* an FCoE interface, 1:1 with netdev */ -struct fcoe_softc { +struct fcoe_interface {struct list_head list; +/* This will be removed once all the shared values are +* moved out of fcoe_port */ +struct fcoe_port *priv; +}; + +/* +* the FCoE private structure that's allocated along with the +* Scsi_Host and libfc fc_lport structures +*/ +struct fcoe_port { +struct fcoe_interface *fcoe;struct net_device *netdev;struct fc_exch_mgr *oem;/* offload exchange manger */ struct packet_type fcoe_packet_type;
@@ -89,12 +100,12 @@ struct fcoe_softc { struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr (fc) container_of(fc, struct fcoe_softc, ctlr) +#define fcoe_from_ctlr (port) container_of(port, struct fcoe_port, ctlr)static inline struct net_device *fcoe_netdev (const struct fc_lport *lp) { -return ((struct fcoe_softc *)lport_priv (lp))->netdev; +return ((struct fcoe_port *)lport_priv (lp))->netdev; }#endif /* _FCOE_H_ */
PATCH 13/64 fcoe: move netdev to fcoe_interface
In reply to Robert LoveFrom: Chris Leech <[email protected]>
The network interface needs to be shared between all NPIV VN_Ports, therefor it should be tracked in the fcoe_interface and not for each SCSI host in fcoe_port.
---
drivers/scsi/fcoe/fcoe.c | 61 ++++++++++++++++++++++++++-------------------- drivers/scsi/fcoe/fcoe.h | 9 +++---- 2 files changed, 38 insertions(+), 32 deletions(-)
drivers/scsi/fcoe/fcoe.c +34 -27
@@ -165,7 +165,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,*/ static void fcoe_fip_send (struct fcoe_ctlr *fip,struct sk_buff *skb) { - skb->dev =fcoe_from_ctlr (fip)->netdev; + skb->dev =fcoe_from_ctlr (fip)->fcoe->netdev;dev_queue_xmit (skb); }
@@ -180,13 +180,16 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)*/ static void fcoe_update_src_mac (struct fcoe_ctlr *fip,u8 *old,u8 *new) { +struct fcoe_interface *fcoe;struct fcoe_port *port; port =fcoe_from_ctlr (fip); + fcoe = port->fcoe; +rtnl_lock ();if (!is_zero_ether_addr (old)) -dev_unicast_delete (port->netdev, old); -dev_unicast_add (port->netdev, new); +dev_unicast_delete (fcoe->netdev, old); +dev_unicast_add (fcoe->netdev, new);rtnl_unlock (); }
@@ -229,6 +232,7 @@ static int fcoe_lport_config(struct fc_lport *lp)void fcoe_netdev_cleanup (struct fcoe_port *port) {u8 flogi_maddr[ETH_ALEN ]; +struct fcoe_interface *fcoe = port->fcoe;/* Don't listen for Ethernet packets anymore */ dev_remove_pack (&port->fcoe_packet_type);
@@ -237,12 +241,12 @@ void fcoe_netdev_cleanup(struct fcoe_port *port)/* Delete secondary MAC addresses */ rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); -dev_unicast_delete (port->netdev, flogi_maddr); +dev_unicast_delete (fcoe->netdev, flogi_maddr);if (!is_zero_ether_addr (port->ctlr.data_src_addr)) -dev_unicast_delete (port->netdev, port->ctlr.data_src_addr); +dev_unicast_delete (fcoe->netdev, port->ctlr.data_src_addr);if (port->ctlr.spma) -dev_unicast_delete (port->netdev, port->ctlr.ctl_src_addr); -dev_mc_delete (port->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +dev_unicast_delete (fcoe->netdev, port->ctlr.ctl_src_addr); +dev_mc_delete (fcoe->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock (); }
@@ -271,14 +275,16 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) {u32 mfs;u64 wwnn, wwpn; +struct fcoe_interface *fcoe;struct fcoe_port *port;u8 flogi_maddr[ETH_ALEN ];struct netdev_hw_addr *ha;/* Setup lport private data to point to fcoe softc */ port =lport_priv (lp); + fcoe = port->fcoe; port->ctlr.lp = lp; - port->netdev = netdev; + fcoe->netdev = netdev;/* Do not support for bonding device */ if ((netdev->priv_flags & IFF_MASTER_ALB) ||
@@ -434,9 +440,10 @@ bool fcoe_oem_match(struct fc_frame *fp)*/ static inline int fcoe_em_config (struct fc_lport *lp) { -struct fcoe_interface *fcoe;struct fcoe_port *port =lport_priv (lp); -struct fcoe_port *oldfc =NULL ; +struct fcoe_port *oldport =NULL ; +struct fcoe_interface *fcoe = port->fcoe; +struct fcoe_interface *oldfcoe =NULL ;struct net_device *old_real_dev, *cur_real_dev;u16 min_xid =FCOE_MIN_XID ;u16 max_xid =FCOE_MAX_XID ;
@@ -454,20 +461,20 @@ static inline int fcoe_em_config(struct fc_lport *lp)* Reuse existing offload em instance in case * it is already allocated on real eth device */ -if (port->netdev->priv_flags &IFF_802_1Q_VLAN ) - cur_real_dev =vlan_dev_real_dev (port->netdev); +if (fcoe->netdev->priv_flags &IFF_802_1Q_VLAN ) + cur_real_dev =vlan_dev_real_dev (fcoe->netdev);else - cur_real_dev = port->netdev; + cur_real_dev = fcoe->netdev; -list_for_each_entry (fcoe, &fcoe_hostlist, list) { - oldfc = fcoe->priv; -if (oldfc->netdev->priv_flags &IFF_802_1Q_VLAN ) - old_real_dev =vlan_dev_real_dev (oldfc->netdev); +list_for_each_entry (oldfcoe, &fcoe_hostlist, list) { + oldport = oldfcoe->priv; +if (oldfcoe->netdev->priv_flags &IFF_802_1Q_VLAN ) + old_real_dev =vlan_dev_real_dev (oldfcoe->netdev);else - old_real_dev = oldfc->netdev; + old_real_dev = oldfcoe->netdev;if (cur_real_dev == old_real_dev) { - port->oem = oldfc->oem; + port->oem = oldport->oem;break ; } }
@@ -476,7 +483,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)if (!fc_exch_mgr_add (lp, port->oem, fcoe_oem_match)) {printk (KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n" , - port->oem, port->netdev->name); + port->oem, fcoe->netdev->name);return -ENOMEM ; } }else {
@@ -486,7 +493,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)if (!port->oem) {printk (KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n" , - port->netdev->name); + fcoe->netdev->name);return -ENOMEM ; } }
@@ -499,7 +506,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) skip_oem:if (!fc_exch_mgr_alloc (lp,FC_CLASS_3 , min_xid, max_xid,NULL )) {printk (KERN_ERR "fcoe_em_config: failed to " -"allocate em on interface %s\n" , port->netdev->name); +"allocate em on interface %s\n" , fcoe->netdev->name);return -ENOMEM ; }
@@ -514,7 +521,7 @@ static void fcoe_if_destroy(struct fc_lport *lport) {struct fcoe_port *port =lport_priv (lport);struct fcoe_interface *fcoe = port->fcoe; -struct net_device *netdev = port->netdev; +struct net_device *netdev = fcoe->netdev;FCOE_NETDEV_DBG (netdev,"Destroying interface\n" );
@@ -1194,7 +1201,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)skb_reset_network_header (skb); skb->mac_len = elen; skb->protocol =htons (ETH_P_FCOE ); - skb->dev = port->netdev; + skb->dev = port->fcoe->netdev;/* fill up mac and fcoe headers */ eh =eth_hdr (skb);
@@ -1480,7 +1487,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,read_lock (&fcoe_hostlist_lock);list_for_each_entry (fcoe, &fcoe_hostlist, list) { port = fcoe->priv; -if (port->netdev == netdev) { +if (fcoe->netdev == netdev) { lp = port->ctlr.lp;break ; }
@@ -1709,7 +1716,7 @@ MODULE_PARM_DESC(destroy, "Destroy fcoe fcoe");int fcoe_link_ok (struct fc_lport *lp) {struct fcoe_port *port =lport_priv (lp); -struct net_device *dev = port->netdev; +struct net_device *dev = port->fcoe->netdev;struct ethtool_cmd ecmd = {ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
@@ -1810,7 +1817,7 @@ fcoe_hostlist_lookup_port(const struct net_device *dev)struct fcoe_interface *fcoe;list_for_each_entry (fcoe, &fcoe_hostlist, list) { -if (fcoe->priv->netdev == dev) +if (fcoe->netdev == dev)return fcoe; }return NULL ;
drivers/scsi/fcoe/fcoe.h +4 -5
@@ -82,6 +82,7 @@ struct fcoe_interface {/* This will be removed once all the shared values are * moved out of fcoe_port */ struct fcoe_port *priv; +struct net_device *netdev; };/*
@@ -90,7 +91,6 @@ struct fcoe_interface {*/ struct fcoe_port {struct fcoe_interface *fcoe; -struct net_device *netdev;struct fc_exch_mgr *oem;/* offload exchange manger */ struct packet_type fcoe_packet_type;struct packet_type fip_packet_type;
@@ -100,12 +100,11 @@ struct fcoe_port { struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr (port) container_of(port, struct fcoe_port, ctlr) +#define fcoe_from_ctlr (fip) container_of(fip, struct fcoe_port, ctlr) -static inline struct net_device *fcoe_netdev ( -const struct fc_lport *lp) +static inline struct net_device *fcoe_netdev (const struct fc_lport *lp) { -return ((struct fcoe_port *)lport_priv (lp))->netdev; +return ((struct fcoe_port *)lport_priv (lp))->fcoe->netdev; }#endif /* _FCOE_H_ */
PATCH 14/64 fcoe: move packet handlers from fcoe_port to fcoe_interface
In reply to Robert LoveFrom: Chris Leech <[email protected]>
The packet handlers need to be tracked in fcoe_interface so there is only one set per net_device. When NPIV is enabled there will be multiple SCSI hosts and multiple fcoe_port structures on a single net_device.
The packet handlers match by ethertype and netdev. If the same handler gets registered on a single netdev multiple times, the receive function will be called multiple times for each frame.
---
drivers/scsi/fcoe/fcoe.c | 28 ++++++++++++++++------------ drivers/scsi/fcoe/fcoe.h | 4 ++-- 2 files changed, 18 insertions(+), 14 deletions(-)
drivers/scsi/fcoe/fcoe.c +16 -12
@@ -151,9 +151,11 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,struct packet_type *ptype, struct net_device *orig_dev) { + struct fcoe_interface *fcoe;struct fcoe_port *port; - port = container_of(ptype, struct fcoe_port, fip_packet_type); + fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); + port = fcoe->priv;fcoe_ctlr_recv (&port->ctlr, skb);return 0 ; }
@@ -235,8 +237,8 @@ void fcoe_netdev_cleanup(struct fcoe_port *port)struct fcoe_interface *fcoe = port->fcoe;/* Don't listen for Ethernet packets anymore */ -dev_remove_pack (&port->fcoe_packet_type); -dev_remove_pack (&port->fip_packet_type); +dev_remove_pack (&fcoe->fcoe_packet_type); +dev_remove_pack (&fcoe->fip_packet_type);/* Delete secondary MAC addresses */ rtnl_lock ();
@@ -368,15 +370,15 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)* setup the receive function from ethernet driver * on the ethertype for the given device */ - port->fcoe_packet_type.func = fcoe_rcv; - port->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); - port->fcoe_packet_type.dev = netdev; -dev_add_pack (&port->fcoe_packet_type); + fcoe->fcoe_packet_type.func = fcoe_rcv; + fcoe->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); + fcoe->fcoe_packet_type.dev = netdev; +dev_add_pack (&fcoe->fcoe_packet_type); - port->fip_packet_type.func = fcoe_fip_recv; - port->fip_packet_type.type =htons (ETH_P_FIP ); - port->fip_packet_type.dev = netdev; -dev_add_pack (&port->fip_packet_type); + fcoe->fip_packet_type.func = fcoe_fip_recv; + fcoe->fip_packet_type.type =htons (ETH_P_FIP ); + fcoe->fip_packet_type.dev = netdev; +dev_add_pack (&fcoe->fip_packet_type);return 0 ; }
@@ -926,12 +928,14 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev, {struct fc_lport *lp;struct fcoe_rcv_info *fr; +struct fcoe_interface *fcoe;struct fcoe_port *port;struct fc_frame_header *fh;struct fcoe_percpu_s *fps;unsigned int cpu; - port = container_of(ptype, struct fcoe_port, fcoe_packet_type); + fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); + port = fcoe->priv; lp = port->ctlr.lp;if (unlikely (lp ==NULL )) {FCOE_NETDEV_DBG (dev,"Cannot find hba structure" );
drivers/scsi/fcoe/fcoe.h +2 -2
@@ -83,6 +83,8 @@ struct fcoe_interface {* moved out of fcoe_port */ struct fcoe_port *priv;struct net_device *netdev; +struct packet_type fcoe_packet_type; +struct packet_type fip_packet_type; };/*
@@ -92,8 +94,6 @@ struct fcoe_interface {struct fcoe_port {struct fcoe_interface *fcoe;struct fc_exch_mgr *oem;/* offload exchange manger */ -struct packet_type fcoe_packet_type; -struct packet_type fip_packet_type;struct sk_buff_head fcoe_pending_queue;u8 fcoe_pending_queue_active;struct timer_list timer;/* queue timer */
PATCH 15/64 fcoe: move FIP controller from fcoe_port to fcoe_interface
In reply to Robert LoveFrom: Chris Leech <[email protected]>
There is only one FIP state per net_device, so the FIP controller needs to be moved from the per-SCSI-host fcoe_port to the per-net_device fcoe_interface structure.
---
drivers/scsi/fcoe/fcoe.c | 83 +++++++++++++++++++++------------------------- drivers/scsi/fcoe/fcoe.h | 4 +- 2 files changed, 39 insertions(+), 48 deletions(-)
drivers/scsi/fcoe/fcoe.c +37 -46
@@ -152,11 +152,9 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev, struct net_device *orig_dev) {struct fcoe_interface *fcoe; -struct fcoe_port *port; fcoe = container_of(ptype, struct fcoe_interface, fip_packet_type); - port = fcoe->priv; -fcoe_ctlr_recv (&port->ctlr, skb); +fcoe_ctlr_recv (&fcoe->ctlr, skb);return 0 ; }
@@ -167,7 +165,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,*/ static void fcoe_fip_send (struct fcoe_ctlr *fip,struct sk_buff *skb) { - skb->dev =fcoe_from_ctlr (fip)->fcoe->netdev; + skb->dev =fcoe_from_ctlr (fip)->netdev;dev_queue_xmit (skb); }
@@ -183,11 +181,8 @@ static void fcoe_fip_send(struct fcoe_ctlr *fip, struct sk_buff *skb)static void fcoe_update_src_mac (struct fcoe_ctlr *fip,u8 *old,u8 *new) {struct fcoe_interface *fcoe; -struct fcoe_port *port; - - port =fcoe_from_ctlr (fip); - fcoe = port->fcoe; + fcoe =fcoe_from_ctlr (fip);rtnl_lock ();if (!is_zero_ether_addr (old))dev_unicast_delete (fcoe->netdev, old);
@@ -244,10 +239,10 @@ void fcoe_netdev_cleanup(struct fcoe_port *port)rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN );dev_unicast_delete (fcoe->netdev, flogi_maddr); -if (!is_zero_ether_addr (port->ctlr.data_src_addr)) -dev_unicast_delete (fcoe->netdev, port->ctlr.data_src_addr); -if (port->ctlr.spma) -dev_unicast_delete (fcoe->netdev, port->ctlr.ctl_src_addr); +if (!is_zero_ether_addr (fcoe->ctlr.data_src_addr)) +dev_unicast_delete (fcoe->netdev, fcoe->ctlr.data_src_addr); +if (fcoe->ctlr.spma) +dev_unicast_delete (fcoe->netdev, fcoe->ctlr.ctl_src_addr);dev_mc_delete (fcoe->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock (); }
@@ -285,7 +280,7 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)/* Setup lport private data to point to fcoe softc */ port =lport_priv (lp); fcoe = port->fcoe; - port->ctlr.lp = lp; + fcoe->ctlr.lp = lp; fcoe->netdev = netdev;/* Do not support for bonding device */
@@ -334,17 +329,17 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)rcu_read_lock ();for_each_dev_addr (netdev, ha) {if ((ha->type ==NETDEV_HW_ADDR_T_SAN ) && - (is_valid_ether_addr (port->ctlr.ctl_src_addr))) { -memcpy (port->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); - port->ctlr.spma =1 ; + (is_valid_ether_addr (fcoe->ctlr.ctl_src_addr))) { +memcpy (fcoe->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); + fcoe->ctlr.spma =1 ;break ; } }rcu_read_unlock ();/* setup Source Mac Address */ -if (!port->ctlr.spma) -memcpy (port->ctlr.ctl_src_addr, netdev->dev_addr, +if (!fcoe->ctlr.spma) +memcpy (fcoe->ctlr.ctl_src_addr, netdev->dev_addr, netdev->addr_len); wwnn =fcoe_wwn_from_mac (netdev->dev_addr,1 ,0 );
@@ -361,8 +356,8 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN );dev_unicast_add (netdev, flogi_maddr); -if (port->ctlr.spma) -dev_unicast_add (netdev, port->ctlr.ctl_src_addr); +if (fcoe->ctlr.spma) +dev_unicast_add (netdev, fcoe->ctlr.ctl_src_addr);dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock ();
@@ -537,7 +532,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)fcoe_netdev_cleanup (port);/* tear-down the FCoE controller */ -fcoe_ctlr_destroy (&port->ctlr); +fcoe_ctlr_destroy (&fcoe->ctlr);/* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean (lport);
@@ -662,9 +657,9 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev,/* * Initialize FIP. */ -fcoe_ctlr_init (&port->ctlr); - port->ctlr.send = fcoe_fip_send; - port->ctlr.update_mac = fcoe_update_src_mac; +fcoe_ctlr_init (&fcoe->ctlr); + fcoe->ctlr.send = fcoe_fip_send; + fcoe->ctlr.update_mac = fcoe_update_src_mac;/* configure lport network properties */ rc =fcoe_netdev_config (lport, netdev);
@@ -714,7 +709,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev,fc_fabric_login (lport);if (!fcoe_link_ok (lport)) -fcoe_ctlr_link_up (&port->ctlr); +fcoe_ctlr_link_up (&fcoe->ctlr);dev_hold (netdev);
@@ -929,14 +924,12 @@ int fcoe_rcv(struct sk_buff *skb, struct net_device *dev,struct fc_lport *lp;struct fcoe_rcv_info *fr;struct fcoe_interface *fcoe; -struct fcoe_port *port;struct fc_frame_header *fh;struct fcoe_percpu_s *fps;unsigned int cpu; fcoe = container_of(ptype, struct fcoe_interface, fcoe_packet_type); - port = fcoe->priv; - lp = port->ctlr.lp; + lp = fcoe->ctlr.lp;if (unlikely (lp ==NULL )) {FCOE_NETDEV_DBG (dev,"Cannot find hba structure" ); goto err2;
@@ -1137,13 +1130,13 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)unsigned int hlen;/* header length implies the version */ unsigned int tlen;/* trailer length */ unsigned int elen;/* eth header, may include vlan */ -struct fcoe_port *port; +struct fcoe_port *port =lport_priv (lp); +struct fcoe_interface *fcoe = port->fcoe;u8 sof, eof;struct fcoe_hdr *hp;WARN_ON ((fr_len (fp) %sizeof (u32)) !=0 ); - port =lport_priv (lp); fh =fc_frame_header_get (fp); skb =fp_skb (fp); wlen = skb->len /FCOE_WORD_TO_BYTE ;
@@ -1154,7 +1147,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) }if (unlikely (fh->fh_r_ctl ==FC_RCTL_ELS_REQ ) && -fcoe_ctlr_els_send (&port->ctlr, skb)) +fcoe_ctlr_els_send (&fcoe->ctlr, skb))return 0 ; sof =fr_sof (fp);
@@ -1205,21 +1198,21 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)skb_reset_network_header (skb); skb->mac_len = elen; skb->protocol =htons (ETH_P_FCOE ); - skb->dev = port->fcoe->netdev; + skb->dev = fcoe->netdev;/* fill up mac and fcoe headers */ eh =eth_hdr (skb); eh->h_proto =htons (ETH_P_FCOE ); -if (port->ctlr.map_dest) +if (fcoe->ctlr.map_dest)fc_fcoe_set_mac (eh->h_dest, fh->fh_d_id);else /* insert GW address */ -memcpy (eh->h_dest, port->ctlr.dest_addr,ETH_ALEN ); +memcpy (eh->h_dest, fcoe->ctlr.dest_addr,ETH_ALEN ); -if (unlikely (port->ctlr.flogi_oxid !=FC_XID_UNKNOWN )) -memcpy (eh->h_source, port->ctlr.ctl_src_addr,ETH_ALEN ); +if (unlikely (fcoe->ctlr.flogi_oxid !=FC_XID_UNKNOWN )) +memcpy (eh->h_source, fcoe->ctlr.ctl_src_addr,ETH_ALEN );else -memcpy (eh->h_source, port->ctlr.data_src_addr,ETH_ALEN ); +memcpy (eh->h_source, fcoe->ctlr.data_src_addr,ETH_ALEN ); hp = (struct fcoe_hdr *)(eh +1 );memset (hp,0 ,sizeof (*hp));
@@ -1382,8 +1375,8 @@ int fcoe_percpu_receive_thread(void *arg) }fr_flags (fp) &= ~FCPHF_CRC_UNCHECKED ; } -if (unlikely (port->ctlr.flogi_oxid !=FC_XID_UNKNOWN ) && -fcoe_ctlr_recv_flogi (&port->ctlr, fp, mac)) { +if (unlikely (port->fcoe->ctlr.flogi_oxid !=FC_XID_UNKNOWN ) && +fcoe_ctlr_recv_flogi (&port->fcoe->ctlr, fp, mac)) {fc_frame_free (fp);continue ; }
@@ -1482,7 +1475,6 @@ static int fcoe_device_notification(struct notifier_block *notifier,struct fc_lport *lp =NULL ;struct net_device *netdev = ptr;struct fcoe_interface *fcoe; -struct fcoe_port *port =NULL ;struct fcoe_dev_stats *stats;u32 link_possible =1 ;u32 mfs;
@@ -1490,9 +1482,8 @@ static int fcoe_device_notification(struct notifier_block *notifier,read_lock (&fcoe_hostlist_lock);list_for_each_entry (fcoe, &fcoe_hostlist, list) { - port = fcoe->priv;if (fcoe->netdev == netdev) { - lp = port->ctlr.lp; + lp = fcoe->ctlr.lp;break ; } }
@@ -1523,8 +1514,8 @@ static int fcoe_device_notification(struct notifier_block *notifier, "from netdev netlink\n", event); }if (link_possible && !fcoe_link_ok (lp)) -fcoe_ctlr_link_up (&port->ctlr); -else if (fcoe_ctlr_link_down (&port->ctlr)) { +fcoe_ctlr_link_up (&fcoe->ctlr); +else if (fcoe_ctlr_link_down (&fcoe->ctlr)) { stats =fc_lport_get_stats (lp); stats->LinkFailureCount++;fcoe_clean_pending_queue (lp);
@@ -1841,7 +1832,7 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) fcoe =fcoe_hostlist_lookup_port (netdev);read_unlock (&fcoe_hostlist_lock); -return (fcoe) ? fcoe->priv->ctlr.lp :NULL ; +return (fcoe) ? fcoe->ctlr.lp :NULL ; }/**
@@ -1941,7 +1932,7 @@ static void __exit fcoe_exit(void)/* releases the associated fcoe hosts */ list_for_each_entry_safe (fcoe, tmp, &fcoe_hostlist, list) -fcoe_if_destroy (fcoe->priv->ctlr.lp); +fcoe_if_destroy (fcoe->ctlr.lp);unregister_hotcpu_notifier (&fcoe_cpu_notifier);
drivers/scsi/fcoe/fcoe.h +2 -2
@@ -85,6 +85,7 @@ struct fcoe_interface {struct net_device *netdev;struct packet_type fcoe_packet_type;struct packet_type fip_packet_type; +struct fcoe_ctlr ctlr; };/*
@@ -97,10 +98,9 @@ struct fcoe_port {struct sk_buff_head fcoe_pending_queue;u8 fcoe_pending_queue_active;struct timer_list timer;/* queue timer */ -struct fcoe_ctlr ctlr; }; -#define fcoe_from_ctlr (fip) container_of(fip, struct fcoe_port, ctlr) +#define fcoe_from_ctlr (fip) container_of(fip, struct fcoe_interface, ctlr)static inline struct net_device *fcoe_netdev (const struct fc_lport *lp) {
PATCH 16/64 fcoe: move offload exchange manager pointer from fcoe_port to fcoe_interface
In reply to Robert LoveFrom: Chris Leech <[email protected]>
The offload EM pointer is only used when setting up a new libfc instance, but as it's designed to be shared among NPIV VN_Ports it should be tracked in fcoe_interface.
With the host-list changed to track fcoe_interfaces as well, this is needed before we can remove the priv pointer from that structure (which is only there to help in the transition, and stops making sense once NPIV is enabled).
---
drivers/scsi/fcoe/fcoe.c | 14 ++++++-------- drivers/scsi/fcoe/fcoe.h | 2 +- 2 files changed, 7 insertions(+), 9 deletions(-)
drivers/scsi/fcoe/fcoe.c +6 -8
@@ -438,7 +438,6 @@ bool fcoe_oem_match(struct fc_frame *fp)static inline int fcoe_em_config (struct fc_lport *lp) {struct fcoe_port *port =lport_priv (lp); -struct fcoe_port *oldport =NULL ;struct fcoe_interface *fcoe = port->fcoe;struct fcoe_interface *oldfcoe =NULL ;struct net_device *old_real_dev, *cur_real_dev;
@@ -464,30 +463,29 @@ static inline int fcoe_em_config(struct fc_lport *lp) cur_real_dev = fcoe->netdev;list_for_each_entry (oldfcoe, &fcoe_hostlist, list) { - oldport = oldfcoe->priv;if (oldfcoe->netdev->priv_flags &IFF_802_1Q_VLAN ) old_real_dev =vlan_dev_real_dev (oldfcoe->netdev);else old_real_dev = oldfcoe->netdev;if (cur_real_dev == old_real_dev) { - port->oem = oldport->oem; + fcoe->oem = oldfcoe->oem;break ; } } -if (port->oem) { -if (!fc_exch_mgr_add (lp, port->oem, fcoe_oem_match)) { +if (fcoe->oem) { +if (!fc_exch_mgr_add (lp, fcoe->oem, fcoe_oem_match)) {printk (KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n" , - port->oem, fcoe->netdev->name); + fcoe->oem, fcoe->netdev->name);return -ENOMEM ; } }else { - port->oem =fc_exch_mgr_alloc (lp,FC_CLASS_3 , + fcoe->oem =fc_exch_mgr_alloc (lp,FC_CLASS_3 ,FCOE_MIN_XID , lp->lro_xid, fcoe_oem_match); -if (!port->oem) { +if (!fcoe->oem) {printk (KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n" , fcoe->netdev->name);
drivers/scsi/fcoe/fcoe.h +1 -1
@@ -86,6 +86,7 @@ struct fcoe_interface {struct packet_type fcoe_packet_type;struct packet_type fip_packet_type;struct fcoe_ctlr ctlr; +struct fc_exch_mgr *oem;/* offload exchange manager */ };/*
@@ -94,7 +95,6 @@ struct fcoe_interface {*/ struct fcoe_port {struct fcoe_interface *fcoe; -struct fc_exch_mgr *oem;/* offload exchange manger */ struct sk_buff_head fcoe_pending_queue;u8 fcoe_pending_queue_active;struct timer_list timer;/* queue timer */
PATCH 17/64 fcoe: remove fcoe_interface->priv pointer
In reply to Robert LoveFrom: Chris Leech <[email protected]>
The priv pointer is no longer needed, and once NPIV is enabled fcoe_interface:fc_lport becomes a one-to-many relationship.
Remove the single pointer.
---
drivers/scsi/fcoe/fcoe.c | 2 -- drivers/scsi/fcoe/fcoe.h | 3 --- 2 files changed, 0 insertions(+), 5 deletions(-)
drivers/scsi/fcoe/fcoe.c +0 -2
@@ -640,9 +640,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev, } lport =shost_priv (shost); port =lport_priv (lport); - port->fcoe = fcoe; - fcoe->priv = port;/* configure fc_lport, e.g., em */ rc =fcoe_lport_config (lport);
drivers/scsi/fcoe/fcoe.h +0 -3
@@ -79,9 +79,6 @@ struct fcoe_percpu_s {*/ struct fcoe_interface {struct list_head list; -/* This will be removed once all the shared values are -* moved out of fcoe_port */ -struct fcoe_port *priv;struct net_device *netdev;struct packet_type fcoe_packet_type;struct packet_type fip_packet_type;
PATCH 18/64 fcoe: fcoe_interface create, destroy and refcounting
In reply to Robert LoveFrom: Chris Leech <[email protected]>
Up to this point the fcoe_instance structure was simply kzalloc/kfreed. This patch introduces create and destroy functions as well as kref based reference counting. The create function will grow as the initialization code is moved there.
---
drivers/scsi/fcoe/fcoe.c | 97 +++++++++++++++++++++++++++++++++++++--------- drivers/scsi/fcoe/fcoe.h | 1 2 files changed, 79 insertions(+), 19 deletions(-)
drivers/scsi/fcoe/fcoe.c +78 -19
@@ -139,6 +139,58 @@ static struct scsi_host_template fcoe_shost_template = { };/** +* fcoe_interface_create() +* @netdev: network interface +* +* Returns: pointer to a struct fcoe_interface or NULL on error +*/ +static struct fcoe_interface *fcoe_interface_create (struct net_device *netdev) +{ +struct fcoe_interface *fcoe; + + fcoe =kzalloc (sizeof (*fcoe),GFP_KERNEL ); +if (!fcoe) { +FCOE_NETDEV_DBG (netdev,"Could not allocate fcoe structure\n" ); +return NULL ; + } + +kref_init (&fcoe->kref); + fcoe->netdev = netdev; + +return fcoe; +} + +/** +* fcoe_interface_release() - fcoe_port kref release function +* @kref: embedded reference count in an fcoe_interface struct +*/ +static void fcoe_interface_release (struct kref *kref) +{ +struct fcoe_interface *fcoe; + + fcoe = container_of(kref, struct fcoe_interface, kref); +kfree (fcoe); +} + +/** +* fcoe_interface_get() +* @fcoe: +*/ +static inline void fcoe_interface_get (struct fcoe_interface *fcoe) +{ +kref_get (&fcoe->kref); +} + +/** +* fcoe_interface_put() +* @fcoe: +*/ +static inline void fcoe_interface_put (struct fcoe_interface *fcoe) +{ +kref_put (&fcoe->kref, fcoe_interface_release); +} + +/** * fcoe_fip_recv - handle a received FIP frame. * @skb: the receive skb * @dev: associated &net_device
@@ -558,7 +610,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* Release the net_device and Scsi_Host */ dev_put (netdev);scsi_host_put (lport->host); -kfree (fcoe);/* TODO, should be refcounted */ +fcoe_interface_put (fcoe); }/*
@@ -604,8 +656,8 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = { };/** -* fcoe_if_create() - this function creates the fcoe interface -* @netdev: pointer the associated netdevice +* fcoe_if_create() - this function creates the fcoe port +* @fcoe: fcoe_interface structure to create an fc_lport instance on * @parent: device pointer to be the parent in sysfs for the SCSI host * * Creates fc_lport struct and scsi_host for lport, configures lport
@@ -613,30 +665,23 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {* * Returns : The allocated fc_lport or an error pointer */ -static struct fc_lport *fcoe_if_create (struct net_device *netdev, +static struct fc_lport *fcoe_if_create (struct fcoe_interface *fcoe,struct device *parent) {int rc;struct fc_lport *lport =NULL ;struct fcoe_port *port; -struct fcoe_interface *fcoe;struct Scsi_Host *shost; +struct net_device *netdev = fcoe->netdev;FCOE_NETDEV_DBG (netdev,"Create Interface\n" ); - fcoe =kzalloc (sizeof (*fcoe),GFP_KERNEL ); -if (!fcoe) { -FCOE_NETDEV_DBG (netdev,"Could not allocate fcoe structure\n" ); - rc = -ENOMEM ; - goto out; - } - shost =libfc_host_alloc (&fcoe_shost_template,sizeof (struct fcoe_port ));if (!shost) {FCOE_NETDEV_DBG (netdev,"Could not allocate host structure\n" ); rc = -ENOMEM ; - goto out_kfree_port; + goto out; } lport =shost_priv (shost); port =lport_priv (lport);
@@ -708,7 +753,7 @@ static struct fc_lport *fcoe_if_create(struct net_device *netdev,fcoe_ctlr_link_up (&fcoe->ctlr);dev_hold (netdev); - +fcoe_interface_get (fcoe);return lport; out_lp_destroy:
@@ -717,8 +762,6 @@ out_netdev_cleanup:fcoe_netdev_cleanup (port); out_host_put:scsi_host_put (lport->host); -out_kfree_port: -kfree (fcoe); out:return ERR_PTR (rc); }
@@ -1620,6 +1663,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev)static int fcoe_destroy (const char *buffer,struct kernel_param *kp) {struct net_device *netdev; +struct fcoe_interface *fcoe; +struct fcoe_port *port;struct fc_lport *lport;int rc;
@@ -1634,6 +1679,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV ; goto out_putdev; } + port =lport_priv (lport); + fcoe = port->fcoe;fcoe_if_destroy (lport);fcoe_ethdrv_put (netdev); rc =0 ;
@@ -1653,6 +1700,7 @@ out_nodev:static int fcoe_create (const char *buffer,struct kernel_param *kp) {int rc; +struct fcoe_interface *fcoe;struct fc_lport *lport;struct net_device *netdev;
@@ -1668,15 +1716,26 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) }fcoe_ethdrv_get (netdev); - lport =fcoe_if_create (netdev, &netdev->dev); + fcoe =fcoe_interface_create (netdev); +if (!fcoe) { + rc = -ENOMEM ; + goto out_putdev; + } + + lport =fcoe_if_create (fcoe, &netdev->dev);if (IS_ERR (lport)) {printk (KERN_ERR "fcoe: Failed to create interface (%s)\n" , netdev->name);fcoe_ethdrv_put (netdev); rc = -EIO ; - goto out_putdev; + goto out_free; } - rc =0 ; + +dev_put (netdev); +return 0 ; + +out_free: +fcoe_interface_put (fcoe); out_putdev:dev_put (netdev); out_nodev:
drivers/scsi/fcoe/fcoe.h +1 -0
@@ -84,6 +84,7 @@ struct fcoe_interface {struct packet_type fip_packet_type;struct fcoe_ctlr ctlr;struct fc_exch_mgr *oem;/* offload exchange manager */ +struct kref kref; };/*
PATCH 19/64 fcoe: split out per interface setup
In reply to Robert LoveFrom: Chris Leech <[email protected]>
fcoe_netdev_config() is called during initialization of a libfc instance. Much of what was there only needs to be done once for each net_device. The same goes for the corresponding cleanup.
The FIP controller initialization is moved to interface creation time. Otherwise it will keep getting re-initialized for every VN_Port once NPIV is enabled.
fcoe_if_destroy() has some reordering to deal with the changes. Receives are not stopped until after fcoe_interface_put() is called, but transmits must be stopped before. So there is some care to stop libfc transmits and the transmit backlog timer, then call fcoe_interface_put which will stop receives and cleanup the FIP controller, then the receive queues can be cleaned and the port freed.
---
drivers/scsi/fcoe/fcoe.c | 267 +++++++++++++++++++++++++--------------------- 1 files changed, 148 insertions(+), 119 deletions(-)
drivers/scsi/fcoe/fcoe.c +148 -119
@@ -138,6 +138,82 @@ static struct scsi_host_template fcoe_shost_template = { .max_sectors = 0xffff, }; +static int fcoe_fip_recv (struct sk_buff *skb,struct net_device *dev, +struct packet_type *ptype, +struct net_device *orig_dev); +/** +* fcoe_interface_setup() +* @fcoe: new fcoe_interface +* @netdev : ptr to the associated netdevice struct +* +* Returns : 0 for success +*/ +static int fcoe_interface_setup (struct fcoe_interface *fcoe, +struct net_device *netdev) +{ +struct fcoe_ctlr *fip = &fcoe->ctlr; +struct netdev_hw_addr *ha; +u8 flogi_maddr[ETH_ALEN ]; + + fcoe->netdev = netdev; + +/* Do not support for bonding device */ +if ((netdev->priv_flags &IFF_MASTER_ALB ) || + (netdev->priv_flags &IFF_SLAVE_INACTIVE ) || + (netdev->priv_flags &IFF_MASTER_8023AD )) { +return -EOPNOTSUPP ; + } + +/* look for SAN MAC address, if multiple SAN MACs exist, only +* use the first one for SPMA */ +rcu_read_lock (); +for_each_dev_addr (netdev, ha) { +if ((ha->type ==NETDEV_HW_ADDR_T_SAN ) && + (is_valid_ether_addr (fip->ctl_src_addr))) { +memcpy (fip->ctl_src_addr, ha->addr,ETH_ALEN ); + fip->spma =1 ; +break ; + } + } +rcu_read_unlock (); + +/* setup Source Mac Address */ +if (!fip->spma) +memcpy (fip->ctl_src_addr, netdev->dev_addr, netdev->addr_len); + +/* +* Add FCoE MAC address as second unicast MAC address +* or enter promiscuous mode if not capable of listening +* for multiple unicast MACs. +*/ +rtnl_lock (); +memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); +dev_unicast_add (netdev, flogi_maddr); +if (fip->spma) +dev_unicast_add (netdev, fip->ctl_src_addr); +dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +rtnl_unlock (); + +/* +* setup the receive function from ethernet driver +* on the ethertype for the given device +*/ + fcoe->fcoe_packet_type.func = fcoe_rcv; + fcoe->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); + fcoe->fcoe_packet_type.dev = netdev; +dev_add_pack (&fcoe->fcoe_packet_type); + + fcoe->fip_packet_type.func = fcoe_fip_recv; + fcoe->fip_packet_type.type =htons (ETH_P_FIP ); + fcoe->fip_packet_type.dev = netdev; +dev_add_pack (&fcoe->fip_packet_type); + +return 0 ; +} + +static void fcoe_fip_send (struct fcoe_ctlr *fip,struct sk_buff *skb); +static void fcoe_update_src_mac (struct fcoe_ctlr *fip,u8 *old,u8 *new); +/** * fcoe_interface_create() * @netdev: network interface
@@ -155,12 +231,55 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev) }kref_init (&fcoe->kref); - fcoe->netdev = netdev; + +/* +* Initialize FIP. +*/ +fcoe_ctlr_init (&fcoe->ctlr); + fcoe->ctlr.send = fcoe_fip_send; + fcoe->ctlr.update_mac = fcoe_update_src_mac; + +fcoe_interface_setup (fcoe, netdev);return fcoe; }/** +* fcoe_interface_cleanup() - clean up netdev configurations +* @fcoe: +*/ +void fcoe_interface_cleanup (struct fcoe_interface *fcoe) +{ +struct net_device *netdev = fcoe->netdev; +struct fcoe_ctlr *fip = &fcoe->ctlr; +u8 flogi_maddr[ETH_ALEN ]; + +/* +* Don't listen for Ethernet packets anymore. +* synchronize_net() ensures that the packet handlers are not running +* on another CPU. dev_remove_pack() would do that, this calls the +* unsyncronized version __dev_remove_pack() to avoid multiple delays. +*/ +__dev_remove_pack (&fcoe->fcoe_packet_type); +__dev_remove_pack (&fcoe->fip_packet_type); +synchronize_net (); + +/* tear-down the FCoE controller */ +fcoe_ctlr_destroy (&fcoe->ctlr); + +/* Delete secondary MAC addresses */ +rtnl_lock (); +memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); +dev_unicast_delete (netdev, flogi_maddr); +if (!is_zero_ether_addr (fip->data_src_addr)) +dev_unicast_delete (netdev, fip->data_src_addr); +if (fip->spma) +dev_unicast_delete (netdev, fip->ctl_src_addr); +dev_mc_delete (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +rtnl_unlock (); +} + +/** * fcoe_interface_release() - fcoe_port kref release function * @kref: embedded reference count in an fcoe_interface struct */
@@ -169,6 +288,7 @@ static void fcoe_interface_release(struct kref *kref)struct fcoe_interface *fcoe; fcoe = container_of(kref, struct fcoe_interface, kref); +fcoe_interface_cleanup (fcoe);kfree (fcoe); }
@@ -275,31 +395,6 @@ static int fcoe_lport_config(struct fc_lport *lp) }/** -* fcoe_netdev_cleanup() - clean up netdev configurations -* @port: ptr to the fcoe_port -*/ -void fcoe_netdev_cleanup (struct fcoe_port *port) -{ -u8 flogi_maddr[ETH_ALEN ]; -struct fcoe_interface *fcoe = port->fcoe; - -/* Don't listen for Ethernet packets anymore */ -dev_remove_pack (&fcoe->fcoe_packet_type); -dev_remove_pack (&fcoe->fip_packet_type); - -/* Delete secondary MAC addresses */ -rtnl_lock (); -memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); -dev_unicast_delete (fcoe->netdev, flogi_maddr); -if (!is_zero_ether_addr (fcoe->ctlr.data_src_addr)) -dev_unicast_delete (fcoe->netdev, fcoe->ctlr.data_src_addr); -if (fcoe->ctlr.spma) -dev_unicast_delete (fcoe->netdev, fcoe->ctlr.ctl_src_addr); -dev_mc_delete (fcoe->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); -rtnl_unlock (); -} - -/** * fcoe_queue_timer() - fcoe queue timer * @lp: the fc_lport pointer *
@@ -326,21 +421,10 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)u64 wwnn, wwpn;struct fcoe_interface *fcoe;struct fcoe_port *port; -u8 flogi_maddr[ETH_ALEN ]; -struct netdev_hw_addr *ha;/* Setup lport private data to point to fcoe softc */ port =lport_priv (lp); fcoe = port->fcoe; - fcoe->ctlr.lp = lp; - fcoe->netdev = netdev; - -/* Do not support for bonding device */ -if ((netdev->priv_flags &IFF_MASTER_ALB ) || - (netdev->priv_flags &IFF_SLAVE_INACTIVE ) || - (netdev->priv_flags &IFF_MASTER_8023AD )) { -return -EOPNOTSUPP ; - }/* * Determine max frame size based on underlying device and optional
@@ -376,57 +460,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev) port->fcoe_pending_queue_active =0 ;setup_timer (&port->timer, fcoe_queue_timer, (unsigned long )lp); -/* look for SAN MAC address, if multiple SAN MACs exist, only -* use the first one for SPMA */ -rcu_read_lock (); -for_each_dev_addr (netdev, ha) { -if ((ha->type ==NETDEV_HW_ADDR_T_SAN ) && - (is_valid_ether_addr (fcoe->ctlr.ctl_src_addr))) { -memcpy (fcoe->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); - fcoe->ctlr.spma =1 ; -break ; - } - } -rcu_read_unlock (); - -/* setup Source Mac Address */ -if (!fcoe->ctlr.spma) -memcpy (fcoe->ctlr.ctl_src_addr, netdev->dev_addr, - netdev->addr_len); - wwnn =fcoe_wwn_from_mac (netdev->dev_addr,1 ,0 );fc_set_wwnn (lp, wwnn);/* XXX - 3rd arg needs to be vlan id */ wwpn =fcoe_wwn_from_mac (netdev->dev_addr,2 ,0 );fc_set_wwpn (lp, wwpn); -/* -* Add FCoE MAC address as second unicast MAC address -* or enter promiscuous mode if not capable of listening -* for multiple unicast MACs. -*/ -rtnl_lock (); -memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); -dev_unicast_add (netdev, flogi_maddr); -if (fcoe->ctlr.spma) -dev_unicast_add (netdev, fcoe->ctlr.ctl_src_addr); -dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); -rtnl_unlock (); - -/* -* setup the receive function from ethernet driver -* on the ethertype for the given device -*/ - fcoe->fcoe_packet_type.func = fcoe_rcv; - fcoe->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); - fcoe->fcoe_packet_type.dev = netdev; -dev_add_pack (&fcoe->fcoe_packet_type); - - fcoe->fip_packet_type.func = fcoe_fip_recv; - fcoe->fip_packet_type.type =htons (ETH_P_FIP ); - fcoe->fip_packet_type.dev = netdev; -dev_add_pack (&fcoe->fip_packet_type); -return 0 ; }
@@ -578,19 +617,22 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* Remove the instance from fcoe's list */ fcoe_hostlist_remove (lport); -/* clean up netdev configurations */ -fcoe_netdev_cleanup (port); +/* Cleanup the fc_lport */ +fc_lport_destroy (lport); +fc_fcp_destroy (lport); + +/* Stop the transmit retry timer */ +del_timer_sync (&port->timer); -/* tear-down the FCoE controller */ -fcoe_ctlr_destroy (&fcoe->ctlr); +/* Free existing transmit skbs */ +fcoe_clean_pending_queue (lport); + +/* receives may not be stopped until after this */ +fcoe_interface_put (fcoe);/* Free queued packets for the per-CPU receive threads */ fcoe_percpu_clean (lport); -/* Cleanup the fc_lport */ -fc_lport_destroy (lport); -fc_fcp_destroy (lport); -/* Detach from the scsi-ml */ fc_remove_host (lport->host);scsi_remove_host (lport->host);
@@ -598,19 +640,12 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* There are no more rports or I/O, free the EM */ fc_exch_mgr_free (lport); -/* Free existing skbs */ -fcoe_clean_pending_queue (lport); - -/* Stop the timer */ -del_timer_sync (&port->timer); -/* Free memory used by statistical counters */ fc_lport_free_stats (lport);/* Release the net_device and Scsi_Host */ dev_put (netdev);scsi_host_put (lport->host); -fcoe_interface_put (fcoe); }/*
@@ -660,8 +695,7 @@ static struct libfc_function_template fcoe_libfc_fcn_templ = {* @fcoe: fcoe_interface structure to create an fc_lport instance on * @parent: device pointer to be the parent in sysfs for the SCSI host * -* Creates fc_lport struct and scsi_host for lport, configures lport -* and starts fabric login. +* Creates fc_lport struct and scsi_host for lport, configures lport. * * Returns : The allocated fc_lport or an error pointer */
@@ -695,19 +729,12 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_host_put; } -/* -* Initialize FIP. -*/ -fcoe_ctlr_init (&fcoe->ctlr); - fcoe->ctlr.send = fcoe_fip_send; - fcoe->ctlr.update_mac = fcoe_update_src_mac; -/* configure lport network properties */ rc =fcoe_netdev_config (lport, netdev);if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure netdev for the " "interface\n" ); - goto out_netdev_cleanup; + goto out_lp_destroy; }/* configure lport scsi host properties */
@@ -715,7 +742,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,if (rc) {FCOE_NETDEV_DBG (netdev,"Could not configure shost for the " "interface\n" ); - goto out_netdev_cleanup; + goto out_lp_destroy; }/* Initialize the library */
@@ -745,21 +772,12 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,fcoe_hostlist_add (lport);write_unlock (&fcoe_hostlist_lock); - lport->boot_time = jiffies; - -fc_fabric_login (lport); - -if (!fcoe_link_ok (lport)) -fcoe_ctlr_link_up (&fcoe->ctlr); -dev_hold (netdev);fcoe_interface_get (fcoe);return lport; out_lp_destroy:fc_exch_mgr_free (lport); -out_netdev_cleanup: -fcoe_netdev_cleanup (port); out_host_put:scsi_host_put (lport->host); out:
@@ -1731,10 +1749,21 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) goto out_free; } -dev_put (netdev); -return 0 ; +/* Make this the "master" N_Port */ + fcoe->ctlr.lp = lport; + +/* start FIP Discovery and FLOGI */ + lport->boot_time = jiffies; +fc_fabric_login (lport); +if (!fcoe_link_ok (lport)) +fcoe_ctlr_link_up (&fcoe->ctlr); + rc =0 ; out_free: +/* +* Release from init in fcoe_interface_create(), on success lport +* should be holding a reference taken in fcoe_if_create(). +*/ fcoe_interface_put (fcoe); out_putdev:dev_put (netdev);
PATCH 20/64 fcoe: add mutex to protect create and destroy
In reply to Robert LoveFrom: Chris Leech <[email protected]>
Rather than rely on the hostlist_lock to be held while creating exchange managers, serialize fcoe instance creation and destruction with a mutex. This will allow the hostlist addition to be moved out of fcoe_if_create(), which will simplify NPIV support.
---
drivers/scsi/fcoe/fcoe.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 files changed, 39 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.c +39 -1
@@ -55,6 +55,8 @@ module_param_named(ddp_min, fcoe_ddp_min, uint, S_IRUGO | S_IWUSR);MODULE_PARM_DESC (ddp_min,"Minimum I/O size in bytes for " \"Direct Data Placement (DDP)." ); +DEFINE_MUTEX (fcoe_config_mutex); +/* fcoe host list */ LIST_HEAD (fcoe_hostlist);DEFINE_RWLOCK (fcoe_hostlist_lock);
@@ -811,6 +813,7 @@ static int __init fcoe_if_init(void) int __exit fcoe_if_exit(void) {fc_release_transport (scsi_transport_fcoe_sw); + scsi_transport_fcoe_sw =NULL ;return 0 ; }
@@ -1686,6 +1689,19 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp)struct fc_lport *lport;int rc; +mutex_lock (&fcoe_config_mutex); +#ifdef CONFIG_FCOE_MODULE +/* +* Make sure the module has been initialized, and is not about to be +* removed. Module paramter sysfs files are writable before the +* module_init function is called and after module_exit. +*/ +if (THIS_MODULE ->state !=MODULE_STATE_LIVE ) { + rc = -ENODEV ; + goto out_nodev; + } +#endif + netdev =fcoe_if_to_netdev (buffer);if (!netdev) { rc = -ENODEV ;
@@ -1705,6 +1721,7 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) out_putdev:dev_put (netdev); out_nodev: +mutex_unlock (&fcoe_config_mutex);return rc; }
@@ -1722,6 +1739,19 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)struct fc_lport *lport;struct net_device *netdev; +mutex_lock (&fcoe_config_mutex); +#ifdef CONFIG_FCOE_MODULE +/* +* Make sure the module has been initialized, and is not about to be +* removed. Module paramter sysfs files are writable before the +* module_init function is called and after module_exit. +*/ +if (THIS_MODULE ->state !=MODULE_STATE_LIVE ) { + rc = -ENODEV ; + goto out_nodev; + } +#endif + netdev =fcoe_if_to_netdev (buffer);if (!netdev) { rc = -ENODEV ;
@@ -1768,6 +1798,7 @@ out_free: out_putdev:dev_put (netdev); out_nodev: +mutex_unlock (&fcoe_config_mutex);return rc; }
@@ -1971,6 +2002,8 @@ static int __init fcoe_init(void)int rc =0 ;struct fcoe_percpu_s *p; +mutex_lock (&fcoe_config_mutex); +for_each_possible_cpu (cpu) { p = &per_cpu (fcoe_percpu, cpu);skb_queue_head_init (&p->fcoe_rx_list);
@@ -1991,13 +2024,14 @@ static int __init fcoe_init(void)if (rc) goto out_free; +mutex_unlock (&fcoe_config_mutex);return 0 ; out_free:for_each_online_cpu (cpu) {fcoe_percpu_thread_destroy (cpu); } - +mutex_unlock (&fcoe_config_mutex);return rc; }module_init (fcoe_init);
@@ -2012,6 +2046,8 @@ static void __exit fcoe_exit(void)unsigned int cpu;struct fcoe_interface *fcoe, *tmp; +mutex_lock (&fcoe_config_mutex); +fcoe_dev_cleanup ();/* releases the associated fcoe hosts */
@@ -2025,5 +2061,7 @@ static void __exit fcoe_exit(void)/* detach from scsi transport */ fcoe_if_exit (); + +mutex_unlock (&fcoe_config_mutex); }module_exit (fcoe_exit);
PATCH 21/64 fcoe: move the host-list add/remove to keep out VN_Ports
In reply to Robert LoveFrom: Chris Leech <[email protected]>
We only want the FCoE create and destroy routines to deal with top level N_Ports, the VN_Ports are tracked on the vport list (see scsi_transport_fc).
---
drivers/scsi/fcoe/fcoe.c | 31 +++++++++++++++++++------------ 1 files changed, 19 insertions(+), 12 deletions(-)
drivers/scsi/fcoe/fcoe.c +19 -12
@@ -616,9 +616,6 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* Logout of the fabric */ fc_fabric_logoff (lport); -/* Remove the instance from fcoe's list */ -fcoe_hostlist_remove (lport); -/* Cleanup the fc_lport */ fc_lport_destroy (lport);fc_fcp_destroy (lport);
@@ -757,11 +754,13 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,/* * fcoe_em_alloc() and fcoe_hostlist_add() both -* need to be atomic under fcoe_hostlist_lock +* need to be atomic with respect to other changes to the hostlist * since fcoe_em_alloc() looks for an existing EM * instance on host list updated by fcoe_hostlist_add(). +* +* This is currently handled through the fcoe_config_mutex begin held. */ -write_lock (&fcoe_hostlist_lock); +/* lport exch manager allocation */ rc =fcoe_em_config (lport);if (rc) {
@@ -770,10 +769,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_lp_destroy; } -/* add to lports list */ -fcoe_hostlist_add (lport); -write_unlock (&fcoe_hostlist_lock); -dev_hold (netdev);fcoe_interface_get (fcoe);return lport;
@@ -1713,6 +1708,8 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV ; goto out_putdev; } +/* Remove the instance from fcoe's list */ +fcoe_hostlist_remove (lport); port =lport_priv (lport); fcoe = port->fcoe;fcoe_if_destroy (lport);
@@ -1782,6 +1779,9 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)/* Make this the "master" N_Port */ fcoe->ctlr.lp = lport; +/* add to lports list */ +fcoe_hostlist_add (lport); +/* start FIP Discovery and FLOGI */ lport->boot_time = jiffies;fc_fabric_login (lport);
@@ -1954,8 +1954,6 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)* fcoe_hostlist_add() - Add a lport to lports list * @lp: ptr to the fc_lport to be added * -* Called with write fcoe_hostlist_lock held. -* * Returns: 0 for success */ int fcoe_hostlist_add (const struct fc_lport *lport)
@@ -1963,12 +1961,14 @@ int fcoe_hostlist_add(const struct fc_lport *lport)struct fcoe_interface *fcoe;struct fcoe_port *port; +write_lock_bh (&fcoe_hostlist_lock); fcoe =fcoe_hostlist_lookup_port (fcoe_netdev (lport));if (!fcoe) { port =lport_priv (lport); fcoe = port->fcoe;list_add_tail (&fcoe->list, &fcoe_hostlist); } +write_unlock_bh (&fcoe_hostlist_lock);return 0 ; }
@@ -2045,14 +2045,21 @@ static void __exit fcoe_exit(void) {unsigned int cpu;struct fcoe_interface *fcoe, *tmp; +LIST_HEAD (local_list);mutex_lock (&fcoe_config_mutex);fcoe_dev_cleanup ();/* releases the associated fcoe hosts */ -list_for_each_entry_safe (fcoe, tmp, &fcoe_hostlist, list) +write_lock_bh (&fcoe_hostlist_lock); +list_splice_init (&fcoe_hostlist, &local_list); +write_unlock_bh (&fcoe_hostlist_lock); + +list_for_each_entry_safe (fcoe, tmp, &local_list, list) { +list_del (&fcoe->list);fcoe_if_destroy (fcoe->ctlr.lp); + }unregister_hotcpu_notifier (&fcoe_cpu_notifier);
PATCH 22/64 fcoe: Fix module ref count bug by adding NETDEV UNREGISTER handling
In reply to Robert LoveFrom: Chris Leech <[email protected]>
Fixes reference counting on fcoe_instance and net_device, and adds NETDEV_UNREGISTER notifier handling so that you can unload network drivers. FCoE no longer increments the module use count for the network driver.
On an NETDEV_UNREGISTER event, destroying the FCoE instance is deferred to a workqueue context to avoid RTNL deadlocks.
Based in part by an earlier patch from John Fastabend
John's patch description:
Currently, the netdev module ref count is not decremented with module_put() when the module is unloaded while fcoe instances are present. To fix this removed reference count on netdev module completely and added functionality to netdev event handling for NETDEV_UNREGISTER events.
This allows fcoe to remove devices cleanly when the netdev module is unloaded so we no longer need to hold a reference count for the netdev module.
---
drivers/scsi/fcoe/fcoe.c | 186 ++++++++++++++++------------------------------ drivers/scsi/fcoe/fcoe.h | 2 2 files changed, 67 insertions(+), 121 deletions(-)
drivers/scsi/fcoe/fcoe.c +65 -121
@@ -74,12 +74,13 @@ static int fcoe_link_ok(struct fc_lport *lp);static struct fc_lport *fcoe_hostlist_lookup (const struct net_device *);static int fcoe_hostlist_add (const struct fc_lport *); -static int fcoe_hostlist_remove (const struct fc_lport *);static void fcoe_check_wait_queue (struct fc_lport *,struct sk_buff *);static int fcoe_device_notification (struct notifier_block *,ulong ,void *);static void fcoe_dev_setup (void );static void fcoe_dev_cleanup (void ); +static struct fcoe_interface * +fcoe_hostlist_lookup_port (const struct net_device *dev);/* notification function from net device */ static struct notifier_block fcoe_notifier = {
@@ -149,6 +150,7 @@ static int fcoe_fip_recv(struct sk_buff *skb, struct net_device *dev,* @netdev : ptr to the associated netdevice struct * * Returns : 0 for success +* Locking: must be called with the RTNL mutex held */ static int fcoe_interface_setup (struct fcoe_interface *fcoe,struct net_device *netdev)
@@ -188,13 +190,11 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,* or enter promiscuous mode if not capable of listening * for multiple unicast MACs. */ -rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN );dev_unicast_add (netdev, flogi_maddr);if (fip->spma)dev_unicast_add (netdev, fip->ctl_src_addr);dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); -rtnl_unlock ();/* * setup the receive function from ethernet driver
@@ -215,6 +215,7 @@ static int fcoe_interface_setup(struct fcoe_interface *fcoe,static void fcoe_fip_send (struct fcoe_ctlr *fip,struct sk_buff *skb);static void fcoe_update_src_mac (struct fcoe_ctlr *fip,u8 *old,u8 *new); +static void fcoe_destroy_work (struct work_struct *work);/** * fcoe_interface_create()
@@ -232,6 +233,7 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)return NULL ; } +dev_hold (netdev);kref_init (&fcoe->kref);/*
@@ -249,6 +251,8 @@ static struct fcoe_interface *fcoe_interface_create(struct net_device *netdev)/** * fcoe_interface_cleanup() - clean up netdev configurations * @fcoe: +* +* Caller must be holding the RTNL mutex */ void fcoe_interface_cleanup (struct fcoe_interface *fcoe) {
@@ -266,11 +270,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)__dev_remove_pack (&fcoe->fip_packet_type);synchronize_net (); -/* tear-down the FCoE controller */ -fcoe_ctlr_destroy (&fcoe->ctlr); -/* Delete secondary MAC addresses */ -rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN );dev_unicast_delete (netdev, flogi_maddr);if (!is_zero_ether_addr (fip->data_src_addr))
@@ -278,7 +278,6 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)if (fip->spma)dev_unicast_delete (netdev, fip->ctl_src_addr);dev_mc_delete (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); -rtnl_unlock (); }/**
@@ -288,10 +287,14 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)static void fcoe_interface_release (struct kref *kref) {struct fcoe_interface *fcoe; +struct net_device *netdev; fcoe = container_of(kref, struct fcoe_interface, kref); -fcoe_interface_cleanup (fcoe); + netdev = fcoe->netdev; +/* tear-down the FCoE controller */ +fcoe_ctlr_destroy (&fcoe->ctlr);kfree (fcoe); +dev_put (netdev); }/**
@@ -642,8 +645,7 @@ static void fcoe_if_destroy(struct fc_lport *lport)/* Free memory used by statistical counters */ fc_lport_free_stats (lport); -/* Release the net_device and Scsi_Host */ -dev_put (netdev); +/* Release the Scsi_Host */ scsi_host_put (lport->host); }
@@ -718,7 +720,9 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, } lport =shost_priv (shost); port =lport_priv (lport); + port->lport = lport; port->fcoe = fcoe; +INIT_WORK (&port->destroy_work, fcoe_destroy_work);/* configure fc_lport, e.g., em */ rc =fcoe_lport_config (lport);
@@ -769,7 +773,6 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe, goto out_lp_destroy; } -dev_hold (netdev);fcoe_interface_get (fcoe);return lport;
@@ -1530,19 +1533,19 @@ static int fcoe_device_notification(struct notifier_block *notifier,struct fc_lport *lp =NULL ;struct net_device *netdev = ptr;struct fcoe_interface *fcoe; +struct fcoe_port *port;struct fcoe_dev_stats *stats;u32 link_possible =1 ;u32 mfs;int rc =NOTIFY_OK ; -read_lock (&fcoe_hostlist_lock); +write_lock (&fcoe_hostlist_lock);list_for_each_entry (fcoe, &fcoe_hostlist, list) {if (fcoe->netdev == netdev) { lp = fcoe->ctlr.lp;break ; } } -read_unlock (&fcoe_hostlist_lock);if (lp ==NULL ) { rc =NOTIFY_DONE ; goto out;
@@ -1564,6 +1567,13 @@ static int fcoe_device_notification(struct notifier_block *notifier,break ;case NETDEV_REGISTER :break ; +case NETDEV_UNREGISTER : +list_del (&fcoe->list); + port =lport_priv (fcoe->ctlr.lp); +fcoe_interface_cleanup (fcoe); +schedule_work (&port->destroy_work); + goto out; +break ;default :FCOE_NETDEV_DBG (netdev,"Unknown event %ld " "from netdev netlink\n" , event);
@@ -1576,6 +1586,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,fcoe_clean_pending_queue (lp); } out: +write_unlock (&fcoe_hostlist_lock);return rc; }
@@ -1601,75 +1612,6 @@ static struct net_device *fcoe_if_to_netdev(const char *buffer) }/** -* fcoe_netdev_to_module_owner() - finds out the driver module of the netdev -* @netdev: the target netdev -* -* Returns: ptr to the struct module, NULL for failure -*/ -static struct module * -fcoe_netdev_to_module_owner (const struct net_device *netdev) -{ -struct device *dev; - -if (!netdev) -return NULL ; - - dev = netdev->dev.parent; -if (!dev) -return NULL ; - -if (!dev->driver) -return NULL ; - -return dev->driver->owner; -} - -/** -* fcoe_ethdrv_get() - Hold the Ethernet driver -* @netdev: the target netdev -* -* Holds the Ethernet driver module by try_module_get() for -* the corresponding netdev. -* -* Returns: 0 for success -*/ -static int fcoe_ethdrv_get (const struct net_device *netdev) -{ -struct module *owner; - - owner =fcoe_netdev_to_module_owner (netdev); -if (owner) { -FCOE_NETDEV_DBG (netdev,"Hold driver module %s\n" , -module_name (owner)); -return try_module_get (owner); - } -return -ENODEV ; -} - -/** -* fcoe_ethdrv_put() - Release the Ethernet driver -* @netdev: the target netdev -* -* Releases the Ethernet driver module by module_put for -* the corresponding netdev. -* -* Returns: 0 for success -*/ -static int fcoe_ethdrv_put (const struct net_device *netdev) -{ -struct module *owner; - - owner =fcoe_netdev_to_module_owner (netdev); -if (owner) { -FCOE_NETDEV_DBG (netdev,"Release driver module %s\n" , -module_name (owner)); -module_put (owner); -return 0 ; - } -return -ENODEV ; -} - -/** * fcoe_destroy() - handles the destroy from sysfs * @buffer: expected to be an eth if name * @kp: associated kernel param
@@ -1678,10 +1620,8 @@ static int fcoe_ethdrv_put(const struct net_device *netdev)*/ static int fcoe_destroy (const char *buffer,struct kernel_param *kp) { -struct net_device *netdev;struct fcoe_interface *fcoe; -struct fcoe_port *port; -struct fc_lport *lport; +struct net_device *netdev;int rc;mutex_lock (&fcoe_config_mutex);
@@ -1702,19 +1642,20 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) rc = -ENODEV ; goto out_nodev; } -/* look for existing lport */ - lport =fcoe_hostlist_lookup (netdev); -if (!lport) { + +write_lock (&fcoe_hostlist_lock); + fcoe =fcoe_hostlist_lookup_port (netdev); +if (!fcoe) { +write_unlock (&fcoe_hostlist_lock); rc = -ENODEV ; goto out_putdev; } -/* Remove the instance from fcoe's list */ -fcoe_hostlist_remove (lport); - port =lport_priv (lport); - fcoe = port->fcoe; -fcoe_if_destroy (lport); -fcoe_ethdrv_put (netdev); - rc =0 ; +list_del (&fcoe->list); +write_unlock (&fcoe_hostlist_lock); +rtnl_lock (); +fcoe_interface_cleanup (fcoe); +rtnl_unlock (); +fcoe_if_destroy (fcoe->ctlr.lp); out_putdev:dev_put (netdev); out_nodev:
@@ -1722,6 +1663,16 @@ out_nodev:return rc; } +static void fcoe_destroy_work (struct work_struct *work) +{ +struct fcoe_port *port; + + port = container_of(work, struct fcoe_port, destroy_work); +mutex_lock (&fcoe_config_mutex); +fcoe_if_destroy (port->lport); +mutex_unlock (&fcoe_config_mutex); +} +/** * fcoe_create() - Handles the create call from sysfs * @buffer: expected to be an eth if name
@@ -1749,17 +1700,18 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp) }#endif +rtnl_lock (); netdev =fcoe_if_to_netdev (buffer);if (!netdev) { rc = -ENODEV ; goto out_nodev; } +/* look for existing lport */ if (fcoe_hostlist_lookup (netdev)) { rc = -EEXIST ; goto out_putdev; } -fcoe_ethdrv_get (netdev); fcoe =fcoe_interface_create (netdev);if (!fcoe) {
@@ -1771,8 +1723,8 @@ static int fcoe_create(const char *buffer, struct kernel_param *kp)if (IS_ERR (lport)) {printk (KERN_ERR "fcoe: Failed to create interface (%s)\n" , netdev->name); -fcoe_ethdrv_put (netdev); rc = -EIO ; +fcoe_interface_cleanup (fcoe); goto out_free; }
@@ -1798,6 +1750,7 @@ out_free: out_putdev:dev_put (netdev); out_nodev: +rtnl_unlock ();mutex_unlock (&fcoe_config_mutex);return rc; }
@@ -1973,25 +1926,6 @@ int fcoe_hostlist_add(const struct fc_lport *lport) }/** -* fcoe_hostlist_remove() - remove a lport from lports list -* @lp: ptr to the fc_lport to be removed -* -* Returns: 0 for success -*/ -int fcoe_hostlist_remove (const struct fc_lport *lport) -{ -struct fcoe_interface *fcoe; - -write_lock_bh (&fcoe_hostlist_lock); - fcoe =fcoe_hostlist_lookup_port (fcoe_netdev (lport)); -BUG_ON (!fcoe); -list_del (&fcoe->list); -write_unlock_bh (&fcoe_hostlist_lock); - -return 0 ; -} - -/** * fcoe_init() - fcoe module loading initialization * * Returns 0 on success, negative on failure
@@ -2046,6 +1980,7 @@ static void __exit fcoe_exit(void)unsigned int cpu;struct fcoe_interface *fcoe, *tmp;LIST_HEAD (local_list); +struct fcoe_port *port;mutex_lock (&fcoe_config_mutex);
@@ -2058,7 +1993,11 @@ static void __exit fcoe_exit(void)list_for_each_entry_safe (fcoe, tmp, &local_list, list) {list_del (&fcoe->list); -fcoe_if_destroy (fcoe->ctlr.lp); + port =lport_priv (fcoe->ctlr.lp); +rtnl_lock (); +fcoe_interface_cleanup (fcoe); +rtnl_unlock (); +schedule_work (&port->destroy_work); }unregister_hotcpu_notifier (&fcoe_cpu_notifier);
@@ -2066,9 +2005,14 @@ static void __exit fcoe_exit(void)for_each_online_cpu (cpu)fcoe_percpu_thread_destroy (cpu); -/* detach from scsi transport */ -fcoe_if_exit (); -mutex_unlock (&fcoe_config_mutex); + +/* flush any asyncronous interface destroys, +* this should happen after the netdev notifier is unregistered */ +flush_scheduled_work (); + +/* detach from scsi transport +* must happen after all destroys are done, therefor after the flush */ +fcoe_if_exit (); }module_exit (fcoe_exit);
drivers/scsi/fcoe/fcoe.h +2 -0
@@ -93,9 +93,11 @@ struct fcoe_interface {*/ struct fcoe_port {struct fcoe_interface *fcoe; +struct fc_lport *lport;struct sk_buff_head fcoe_pending_queue;u8 fcoe_pending_queue_active;struct timer_list timer;/* queue timer */ +struct work_struct destroy_work;/* to prevent rtnl deadlocks */ };#define fcoe_from_ctlr (fip) container_of(fip, struct fcoe_interface, ctlr)
PATCH 23/64 fcoe: use rtnl mutex in place of hostlist lock
In reply to Robert LoveFrom: Chris Leech <[email protected]>
This just cuts down on the number of locks we're dealing with, and eliminates the need to take another lock in the netdev notifier.
---
drivers/scsi/fcoe/fcoe.c | 37 +++++++++++-------------------------- 1 files changed, 11 insertions(+), 26 deletions(-)
drivers/scsi/fcoe/fcoe.c +11 -26
@@ -58,8 +58,8 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \DEFINE_MUTEX (fcoe_config_mutex);/* fcoe host list */ +/* must only by accessed under the RTNL mutex */ LIST_HEAD (fcoe_hostlist); -DEFINE_RWLOCK (fcoe_hostlist_lock); DEFINE_PER_CPU(struct fcoe_percpu_s, fcoe_percpu);/* Function Prototypes */
@@ -527,8 +527,6 @@ bool fcoe_oem_match(struct fc_frame *fp)* fcoe_em_config() - allocates em for this lport * @lp: the fcoe that em is to allocated for * -* Called with write fcoe_hostlist_lock held. -* * Returns : 0 on success */ static inline int fcoe_em_config (struct fc_lport *lp)
@@ -1539,7 +1537,6 @@ static int fcoe_device_notification(struct notifier_block *notifier,u32 mfs;int rc =NOTIFY_OK ; -write_lock (&fcoe_hostlist_lock);list_for_each_entry (fcoe, &fcoe_hostlist, list) {if (fcoe->netdev == netdev) { lp = fcoe->ctlr.lp;
@@ -1586,7 +1583,6 @@ static int fcoe_device_notification(struct notifier_block *notifier,fcoe_clean_pending_queue (lp); } out: -write_unlock (&fcoe_hostlist_lock);return rc; }
@@ -1643,16 +1639,14 @@ static int fcoe_destroy(const char *buffer, struct kernel_param *kp) goto out_nodev; } -write_lock (&fcoe_hostlist_lock); +rtnl_lock (); fcoe =fcoe_hostlist_lookup_port (netdev);if (!fcoe) { -write_unlock (&fcoe_hostlist_lock); +rtnl_unlock (); rc = -ENODEV ; goto out_putdev; }list_del (&fcoe->list); -write_unlock (&fcoe_hostlist_lock); -rtnl_lock ();fcoe_interface_cleanup (fcoe);rtnl_unlock ();fcoe_if_destroy (fcoe->ctlr.lp);
@@ -1870,9 +1864,8 @@ int fcoe_reset(struct Scsi_Host *shost)* fcoe_hostlist_lookup_port() - find the corresponding lport by a given device * @dev: this is currently ptr to net_device * -* Called with fcoe_hostlist_lock held. -* * Returns: NULL or the located fcoe_port +* Locking: must be called with the RNL mutex held */ static struct fcoe_interface *fcoe_hostlist_lookup_port (const struct net_device *dev)
@@ -1891,15 +1884,13 @@ fcoe_hostlist_lookup_port(const struct net_device *dev)* @netdev: ptr to net_device * * Returns: 0 for success +* Locking: must be called with the RTNL mutex held */ -struct fc_lport *fcoe_hostlist_lookup (const struct net_device *netdev) +static struct fc_lport *fcoe_hostlist_lookup (const struct net_device *netdev) {struct fcoe_interface *fcoe; -read_lock (&fcoe_hostlist_lock); fcoe =fcoe_hostlist_lookup_port (netdev); -read_unlock (&fcoe_hostlist_lock); -return (fcoe) ? fcoe->ctlr.lp :NULL ; }
@@ -1908,20 +1899,19 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev)* @lp: ptr to the fc_lport to be added * * Returns: 0 for success +* Locking: must be called with the RTNL mutex held */ -int fcoe_hostlist_add (const struct fc_lport *lport) +static int fcoe_hostlist_add (const struct fc_lport *lport) {struct fcoe_interface *fcoe;struct fcoe_port *port; -write_lock_bh (&fcoe_hostlist_lock); fcoe =fcoe_hostlist_lookup_port (fcoe_netdev (lport));if (!fcoe) { port =lport_priv (lport); fcoe = port->fcoe;list_add_tail (&fcoe->list, &fcoe_hostlist); } -write_unlock_bh (&fcoe_hostlist_lock);return 0 ; }
@@ -1979,7 +1969,6 @@ static void __exit fcoe_exit(void) {unsigned int cpu;struct fcoe_interface *fcoe, *tmp; -LIST_HEAD (local_list);struct fcoe_port *port;mutex_lock (&fcoe_config_mutex);
@@ -1987,18 +1976,14 @@ static void __exit fcoe_exit(void)fcoe_dev_cleanup ();/* releases the associated fcoe hosts */ -write_lock_bh (&fcoe_hostlist_lock); -list_splice_init (&fcoe_hostlist, &local_list); -write_unlock_bh (&fcoe_hostlist_lock); - -list_for_each_entry_safe (fcoe, tmp, &local_list, list) { +rtnl_lock (); +list_for_each_entry_safe (fcoe, tmp, &fcoe_hostlist, list) {list_del (&fcoe->list); port =lport_priv (fcoe->ctlr.lp); -rtnl_lock ();fcoe_interface_cleanup (fcoe); -rtnl_unlock ();schedule_work (&port->destroy_work); } +rtnl_unlock ();unregister_hotcpu_notifier (&fcoe_cpu_notifier);
PATCH 24/64 libfc: prepare to split off struct fc_rport_priv from fc_rport_libfc_priv
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
While the I/O and LLD interfaces use fc_rport_libfc_priv, the disc and rport interfaces will use fc_rport_priv, which will be separately allocated.
Change the disc and rport usage of fc_rport_libfc_priv to fc_rport_priv.
Use #define temporarily to make both names equivalent until a subsequent patch splits them.
---
drivers/scsi/libfc/fc_disc.c | 18 ++++++------ drivers/scsi/libfc/fc_lport.c | 2 + drivers/scsi/libfc/fc_rport.c | 60 +++++++++++++++++++++-------------------- include/scsi/libfc.h | 10 ++++++- 4 files changed, 49 insertions(+), 41 deletions(-)
drivers/scsi/libfc/fc_disc.c +9 -9
@@ -65,7 +65,7 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport, {const struct fc_disc *disc = &lport->disc;struct fc_rport *rport, *found =NULL ; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata;int disc_found =0 ;list_for_each_entry (rdata, &disc->rports, peers) {
@@ -94,7 +94,7 @@ void fc_disc_stop_rports(struct fc_disc *disc) {struct fc_lport *lport;struct fc_rport *rport; -struct fc_rport_libfc_priv *rdata, *next; +struct fc_rport_priv *rdata, *next; lport = disc->lport;
@@ -126,7 +126,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport,struct fc_rport *rport, enum fc_rport_event event) { - struct fc_rport_libfc_priv *rdata = rport->dd_data; + struct fc_rport_priv *rdata = rport->dd_data;struct fc_disc *disc = &lport->disc; FC_DISC_DBG(disc, "Received a %d event for port (%6x)\n", event,
@@ -170,7 +170,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, {struct fc_lport *lport;struct fc_rport *rport; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata;struct fc_els_rscn *rp;struct fc_els_rscn_page *pp;struct fc_seq_els_data rjt_data;
@@ -309,7 +309,7 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,static void fc_disc_restart (struct fc_disc *disc) {struct fc_rport *rport; -struct fc_rport_libfc_priv *rdata, *next; +struct fc_rport_priv *rdata, *next;struct fc_lport *lport = disc->lport;FC_DISC_DBG (disc,"Restarting discovery\n" );
@@ -400,7 +400,7 @@ static int fc_disc_new_target(struct fc_disc *disc, struct fc_rport_identifiers *ids) {struct fc_lport *lport = disc->lport; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata;int error =0 ;if (rport && ids->port_name) {
@@ -458,7 +458,7 @@ static int fc_disc_new_target(struct fc_disc *disc,static void fc_disc_del_target (struct fc_disc *disc,struct fc_rport *rport) {struct fc_lport *lport = disc->lport; -struct fc_rport_libfc_priv *rdata = rport->dd_data; +struct fc_rport_priv *rdata = rport->dd_data;list_del (&rdata->peers); lport->tt.rport_logoff (rport); }
@@ -580,7 +580,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)int error =0 ;struct fc_disc_port dp;struct fc_rport *rport; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata; lport = disc->lport;
@@ -774,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) {struct fc_lport *lport;struct fc_rport *new_rport; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata; lport = disc->lport;
drivers/scsi/libfc/fc_lport.c +1 -1
@@ -1306,7 +1306,7 @@ static struct fc_rport_operations fc_lport_rport_ops = {static void fc_lport_enter_dns (struct fc_lport *lport) {struct fc_rport *rport; -struct fc_rport_libfc_priv *rdata; +struct fc_rport_priv *rdata;struct fc_disc_port dp; dp.ids.port_id =FC_FID_DIR_SERV ;
drivers/scsi/libfc/fc_rport.c +30 -30
222 lines not on this page · raw message
include/scsi/libfc.h +9 -1
@@ -77,7 +77,7 @@ do { \ #define FC_RPORT_DBG(rport, fmt, args...) \ do { \ - struct fc_rport_libfc_priv *rdata = rport->dd_data; \ + struct fc_rport_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0)
@@ -177,6 +177,14 @@ enum fc_rport_event {RPORT_EV_LOGO }; +/* +* Temporary definition to prepare for split off from fc_rport_libfc_priv +* of a separately-allocated structure called fc_rport_priv. This will +* be the primary object for the discovery and rport state machines. +* This definition is just to make this patch series easier to review. +*/ +#define fc_rport_priv fc_rport_libfc_priv +struct fc_rport_operations {void (*event_callback)(struct fc_lport *,struct fc_rport *,enum fc_rport_event );
PATCH 25/64 libfc: change interface for rport_create
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The interface for lport->tt.rport_create() takes a fc_disc_port arg,
which is unnatural for most calls. The only reason for this was
to avoid passing in the local port as an argument, but otherwise added to complexity.
Simplify by just using lport and fc_rport_identifiers.
---
drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- drivers/scsi/libfc/fc_lport.c | 26 ++++++++++++-------------- drivers/scsi/libfc/fc_rport.c | 17 +++++++++-------- include/scsi/libfc.h | 5 ++--- 4 files changed, 35 insertions(+), 44 deletions(-)
drivers/scsi/libfc/fc_disc.c +12 -19
@@ -428,13 +428,7 @@ static int fc_disc_new_target(struct fc_disc *disc,if (!rport) { rport = lport->tt.rport_lookup (lport, ids->port_id);if (!rport) { -struct fc_disc_port dp; - dp.lp = lport; - dp.ids.port_id = ids->port_id; - dp.ids.port_name = ids->port_name; - dp.ids.node_name = ids->node_name; - dp.ids.roles = ids->roles; - rport = lport->tt.rport_create (&dp); + rport = lport->tt.rport_create (lport, ids); }if (!rport) error = -ENOMEM ;
@@ -578,7 +572,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)size_t plen;size_t tlen;int error =0 ; -struct fc_disc_port dp; +struct fc_rport_identifiers ids;struct fc_rport *rport;struct fc_rport_priv *rdata;
@@ -621,15 +615,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)* After the first time through the loop, things return to "normal". */ while (plen >=sizeof (*np)) { - dp.lp = lport; - dp.ids.port_id =ntoh24 (np->fp_fid); - dp.ids.port_name =ntohll (np->fp_wwpn); - dp.ids.node_name =-1 ; - dp.ids.roles =FC_RPORT_ROLE_UNKNOWN ; - -if ((dp.ids.port_id !=fc_host_port_id (lport->host)) && - (dp.ids.port_name != lport->wwpn)) { - rport = lport->tt.rport_create (&dp); + ids.port_id =ntoh24 (np->fp_fid); + ids.port_name =ntohll (np->fp_wwpn); + ids.node_name =-1 ; + ids.roles =FC_RPORT_ROLE_UNKNOWN ; + +if (ids.port_id !=fc_host_port_id (lport->host) && + ids.port_name != lport->wwpn) { + rport = lport->tt.rport_create (lport, &ids);if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops;
@@ -640,7 +633,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) }else printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " -"(%6x)\n" , dp.ids.port_id); +"(%6x)\n" , ids.port_id); }if (np->fp_flags &FC_NS_FID_LAST ) {
@@ -781,7 +774,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)if (dp->ids.port_id ==fc_host_port_id (lport->host)) goto out; - new_rport = lport->tt.rport_create (dp); + new_rport = lport->tt.rport_create (lport, &dp->ids);if (new_rport) { rdata = new_rport->dd_data; rdata->ops = &fc_disc_rport_ops;
drivers/scsi/libfc/fc_lport.c +12 -14
@@ -211,20 +211,19 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_disc_port dp; + struct fc_rport_identifiers ids; - dp.lp = lport; - dp.ids.port_id = remote_fid; - dp.ids.port_name = remote_wwpn; - dp.ids.node_name = remote_wwnn; - dp.ids.roles =FC_RPORT_ROLE_UNKNOWN ; + ids.port_id = remote_fid; + ids.port_name = remote_wwpn; + ids.node_name = remote_wwnn; + ids.roles =FC_RPORT_ROLE_UNKNOWN ;if (lport->ptp_rp) { lport->tt.rport_logoff (lport->ptp_rp); lport->ptp_rp =NULL ; } - lport->ptp_rp = lport->tt.rport_create (&dp); + lport->ptp_rp = lport->tt.rport_create (lport, &ids); lport->tt.rport_login (lport->ptp_rp);
@@ -1307,20 +1306,19 @@ static void fc_lport_enter_dns(struct fc_lport *lport) {struct fc_rport *rport;struct fc_rport_priv *rdata; -struct fc_disc_port dp; +struct fc_rport_identifiers ids; - dp.ids.port_id =FC_FID_DIR_SERV ; - dp.ids.port_name =-1 ; - dp.ids.node_name =-1 ; - dp.ids.roles =FC_RPORT_ROLE_UNKNOWN ; - dp.lp = lport; + ids.port_id =FC_FID_DIR_SERV ; + ids.port_name =-1 ; + ids.node_name =-1 ; + ids.roles =FC_RPORT_ROLE_UNKNOWN ;FC_LPORT_DBG (lport,"Entered DNS state from %s state\n" ,fc_lport_state (lport));fc_lport_state_enter (lport,LPORT_ST_DNS ); - rport = lport->tt.rport_create (&dp); + rport = lport->tt.rport_create (lport, &ids);if (!rport) goto err;
drivers/scsi/libfc/fc_rport.c +9 -8
@@ -93,7 +93,8 @@ static void fc_rport_rogue_destroy(struct device *dev)kfree (rport); } -struct fc_rport *fc_rport_rogue_create (struct fc_disc_port *dp) +struct fc_rport *fc_rport_rogue_create (struct fc_lport *lport, +struct fc_rport_identifiers *ids) {struct fc_rport *rport;struct fc_rport_priv *rdata;
@@ -105,10 +106,10 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rdata =RPORT_TO_PRIV (rport); rport->dd_data = rdata; - rport->port_id = dp->ids.port_id; - rport->port_name = dp->ids.port_name; - rport->node_name = dp->ids.node_name; - rport->roles = dp->ids.roles; + rport->port_id = ids->port_id; + rport->port_name = ids->port_name; + rport->node_name = ids->node_name; + rport->roles = ids->roles; rport->maxframe_size =FC_MIN_MAX_PAYLOAD ;/* * Note: all this libfc rogue rport code will be removed for
@@ -118,14 +119,14 @@ struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *dp) rport->dev.release = fc_rport_rogue_destroy;mutex_init (&rdata->rp_mutex); - rdata->local_port = dp->lp; + rdata->local_port = lport; rdata->trans_state =FC_PORTSTATE_ROGUE ; rdata->rp_state =RPORT_ST_INIT ; rdata->event =RPORT_EV_NONE ; rdata->flags =FC_RP_FLAGS_REC_SUPPORTED ; rdata->ops =NULL ; - rdata->e_d_tov = dp->lp->e_d_tov; - rdata->r_a_tov = dp->lp->r_a_tov; + rdata->e_d_tov = lport->e_d_tov; + rdata->r_a_tov = lport->r_a_tov;INIT_DELAYED_WORK (&rdata->retry_work, fc_rport_timeout);INIT_WORK (&rdata->event_work, fc_rport_work);/*
include/scsi/libfc.h +2 -3
@@ -227,8 +227,6 @@ struct fc_rport_libfc_priv {#define RPORT_TO_PRIV (x) \ (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); -struct fc_rport *fc_rport_rogue_create (struct fc_disc_port *); -static inline void fc_rport_set_name (struct fc_rport *rport,u64 wwpn,u64 wwnn) { rport->node_name = wwnn;
@@ -569,7 +567,8 @@ struct libfc_function_template {/* * Create a remote port */ -struct fc_rport *(*rport_create)(struct fc_disc_port *); +struct fc_rport *(*rport_create)(struct fc_lport *, +struct fc_rport_identifiers *);/* * Initiates the RP state machine. It is called from the LP module.
PATCH 26/64 libfc: fix RPORT_TO_PRIV and PRIV_TO_RPORT() macros.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
These macros introduce extra undesirable semicolons that keep them from being used in expressions, and they don't protect against being passed an expression.
Add parens and remove the semicolons.
---
include/scsi/libfc.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
include/scsi/libfc.h +2 -2
@@ -223,9 +223,9 @@ struct fc_rport_libfc_priv { };#define PRIV_TO_RPORT (x) \ - (struct fc_rport *)((void *)x - sizeof(struct fc_rport)); + ((struct fc_rport *)((void *)(x) - sizeof(struct fc_rport)))#define RPORT_TO_PRIV (x) \ - (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport)); + ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport)))static inline void fc_rport_set_name (struct fc_rport *rport,u64 wwpn,u64 wwnn) {
PATCH 27/64 libfc: make fc_rport_priv the primary rport interface.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The rport and discovery modules deal with remote ports before fc_remote_port_add() can be done, because the full set of rport identifiers is not known at early stages.
In preparation for splitting the fc_rport/fc_rport_priv allocation, make fc_rport_priv the primary interface for the remote port and discovery engines.
The FCP / SCSI layers still deal with fc_rport and fc_rport_libfc_priv, however.
---
drivers/scsi/libfc/fc_disc.c | 95 ++++------- drivers/scsi/libfc/fc_elsct.c | 4 drivers/scsi/libfc/fc_fcp.c | 2 drivers/scsi/libfc/fc_lport.c | 26 +-- drivers/scsi/libfc/fc_rport.c | 364 ++++++++++++++++++++--------------------- include/scsi/fc_encode.h | 7 + include/scsi/libfc.h | 26 ++- 7 files changed, 245 insertions(+), 279 deletions(-)
drivers/scsi/libfc/fc_disc.c +34 -61
@@ -49,7 +49,6 @@ static void fc_disc_gpn_ft_req(struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *);static int fc_disc_new_target (struct fc_disc *,struct fc_rport *,struct fc_rport_identifiers *); -static void fc_disc_del_target (struct fc_disc *,struct fc_rport *);static void fc_disc_done (struct fc_disc *);static void fc_disc_timeout (struct work_struct *);static void fc_disc_single (struct fc_disc *,struct fc_disc_port *);
@@ -60,27 +59,19 @@ static void fc_disc_restart(struct fc_disc *);* @lport: Fibre Channel host port instance * @port_id: remote port port_id to match */ -struct fc_rport *fc_disc_lookup_rport (const struct fc_lport *lport, -u32 port_id) +struct fc_rport_priv *fc_disc_lookup_rport (const struct fc_lport *lport, +u32 port_id) {const struct fc_disc *disc = &lport->disc; -struct fc_rport *rport, *found =NULL ; +struct fc_rport *rport;struct fc_rport_priv *rdata; -int disc_found =0 ;list_for_each_entry (rdata, &disc->rports, peers) { rport =PRIV_TO_RPORT (rdata); -if (rport->port_id == port_id) { - disc_found =1 ; - found = rport; -break ; - } +if (rport->port_id == port_id) +return rdata; } - -if (!disc_found) - found =NULL ; - -return found; +return NULL ; }/**
@@ -93,21 +84,18 @@ struct fc_rport *fc_disc_lookup_rport(const struct fc_lport *lport,void fc_disc_stop_rports (struct fc_disc *disc) {struct fc_lport *lport; -struct fc_rport *rport;struct fc_rport_priv *rdata, *next; lport = disc->lport;mutex_lock (&disc->disc_mutex);list_for_each_entry_safe (rdata, next, &disc->rports, peers) { - rport =PRIV_TO_RPORT (rdata);list_del (&rdata->peers); - lport->tt.rport_logoff (rport); + lport->tt.rport_logoff (rdata); }list_for_each_entry_safe (rdata, next, &disc->rogue_rports, peers) { - rport =PRIV_TO_RPORT (rdata); - lport->tt.rport_logoff (rport); + lport->tt.rport_logoff (rdata); }mutex_unlock (&disc->disc_mutex);
@@ -116,18 +104,18 @@ void fc_disc_stop_rports(struct fc_disc *disc)/** * fc_disc_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event -* @rport: The rport which the event has occured on +* @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_disc_rport_callback (struct fc_lport *lport, -struct fc_rport *rport, +struct fc_rport_priv *rdata,enum fc_rport_event event) { -struct fc_rport_priv *rdata = rport->dd_data;struct fc_disc *disc = &lport->disc; +struct fc_rport *rport =PRIV_TO_RPORT (rdata);FC_DISC_DBG (disc,"Received a %d event for port (%6x)\n" , event, rport->port_id);
@@ -169,7 +157,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) {struct fc_lport *lport; -struct fc_rport *rport;struct fc_rport_priv *rdata;struct fc_els_rscn *rp;struct fc_els_rscn_page *pp;
@@ -249,11 +236,10 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending);list_for_each_entry_safe (dp, next, &disc_ports, peers) {list_del (&dp->peers); - rport = lport->tt.rport_lookup (lport, dp->ids.port_id); -if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_lookup (lport, dp->ids.port_id); +if (rdata) {list_del (&rdata->peers); - lport->tt.rport_logoff (rport); + lport->tt.rport_logoff (rdata); }fc_disc_single (disc, dp); }
@@ -308,16 +294,14 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,*/ static void fc_disc_restart (struct fc_disc *disc) { -struct fc_rport *rport;struct fc_rport_priv *rdata, *next;struct fc_lport *lport = disc->lport;FC_DISC_DBG (disc,"Restarting discovery\n" );list_for_each_entry_safe (rdata, next, &disc->rports, peers) { - rport =PRIV_TO_RPORT (rdata);list_del (&rdata->peers); - lport->tt.rport_logoff (rport); + lport->tt.rport_logoff (rdata); } disc->requested =1 ;
@@ -335,6 +319,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, enum fc_disc_event), struct fc_lport *lport) { +struct fc_rport_priv *rdata;struct fc_rport *rport;struct fc_rport_identifiers ids;struct fc_disc *disc = &lport->disc;
@@ -362,8 +347,9 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,* Handle point-to-point mode as a simple discovery * of the remote port. Yucky, yucky, yuck, yuck! */ - rport = disc->lport->ptp_rp; -if (rport) { + rdata = disc->lport->ptp_rp; +if (rdata) { + rport =PRIV_TO_RPORT (rdata); ids.port_id = rport->port_id; ids.port_name = rport->port_name; ids.node_name = rport->node_name;
@@ -418,7 +404,9 @@ static int fc_disc_new_target(struct fc_disc *disc,* assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ -fc_disc_del_target (disc, rport); + rdata = rport->dd_data; +list_del (&rdata->peers); + lport->tt.rport_logoff (rdata); rport =NULL ; } }
@@ -426,38 +414,27 @@ static int fc_disc_new_target(struct fc_disc *disc, ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) {if (!rport) { - rport = lport->tt.rport_lookup (lport, ids->port_id); + rdata = lport->tt.rport_lookup (lport, ids->port_id);if (!rport) { - rport = lport->tt.rport_create (lport, ids); + rdata = lport->tt.rport_create (lport, ids); } -if (!rport) +if (!rdata) error = -ENOMEM ; +else + rport =PRIV_TO_RPORT (rdata); }if (rport) { rdata = rport->dd_data; rdata->ops = &fc_disc_rport_ops; rdata->rp_state =RPORT_ST_INIT ;list_add_tail (&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login (rport); + lport->tt.rport_login (rdata); } }return error; }/** -* fc_disc_del_target() - Delete a target -* @disc: FC discovery context -* @rport: The remote port to be removed -*/ -static void fc_disc_del_target (struct fc_disc *disc,struct fc_rport *rport) -{ -struct fc_lport *lport = disc->lport; -struct fc_rport_priv *rdata = rport->dd_data; -list_del (&rdata->peers); - lport->tt.rport_logoff (rport); -} - -/** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context * Locking Note: This function expects that the disc mutex is locked before
@@ -573,7 +550,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)size_t tlen;int error =0 ;struct fc_rport_identifiers ids; -struct fc_rport *rport;struct fc_rport_priv *rdata; lport = disc->lport;
@@ -622,14 +598,13 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)if (ids.port_id !=fc_host_port_id (lport->host) && ids.port_name != lport->wwpn) { - rport = lport->tt.rport_create (lport, &ids); -if (rport) { - rdata = rport->dd_data; + rdata = lport->tt.rport_create (lport, &ids); +if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->local_port = lport;list_add_tail (&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login (rport); + lport->tt.rport_login (rdata); }else printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port "
@@ -766,7 +741,6 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,static void fc_disc_single (struct fc_disc *disc,struct fc_disc_port *dp) {struct fc_lport *lport; -struct fc_rport *new_rport;struct fc_rport_priv *rdata; lport = disc->lport;
@@ -774,13 +748,12 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)if (dp->ids.port_id ==fc_host_port_id (lport->host)) goto out; - new_rport = lport->tt.rport_create (lport, &dp->ids); -if (new_rport) { - rdata = new_rport->dd_data; + rdata = lport->tt.rport_create (lport, &dp->ids); +if (rdata) { rdata->ops = &fc_disc_rport_ops;kfree (dp);list_add_tail (&rdata->peers, &disc->rogue_rports); - lport->tt.rport_login (new_rport); + lport->tt.rport_login (rdata); }return ; out:
drivers/scsi/libfc/fc_elsct.c +2 -2
@@ -32,7 +32,7 @@* fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *rdata, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *,
@@ -47,7 +47,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport,/* ELS requests */ if ((op >=ELS_LS_RJT ) && (op <=ELS_AUTH_ELS )) - rc =fc_els_fill (lport, rport, fp, op, &r_ctl, &did, &fh_type); + rc =fc_els_fill (lport, rdata, fp, op, &r_ctl, &did, &fh_type);else /* CT requests */ rc =fc_ct_fill (lport, fp, op, &r_ctl, &did, &fh_type);
drivers/scsi/libfc/fc_fcp.c +1 -1
@@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)fc_fill_fc_hdr (fp,FC_RCTL_ELS_REQ , rport->port_id,fc_host_port_id (rp->local_port->host),FC_TYPE_ELS ,FC_FC_FIRST_SEQ |FC_FC_END_SEQ |FC_FC_SEQ_INIT ,0 ); -if (lp->tt.elsct_send (lp, rport, fp,ELS_REC , fc_fcp_rec_resp, +if (lp->tt.elsct_send (lp, rport->dd_data, fp,ELS_REC , fc_fcp_rec_resp, fsp,jiffies_to_msecs (FC_SCSI_REC_TOV ))) {fc_fcp_pkt_hold (fsp);/* hold while REC outstanding */ return ;
drivers/scsi/libfc/fc_lport.c +13 -13
@@ -133,16 +133,18 @@ static int fc_frame_drop(struct fc_lport *lport, struct fc_frame *fp)/** * fc_lport_rport_callback() - Event handler for rport events * @lport: The lport which is receiving the event -* @rport: The rport which the event has occured on +* @rdata: private remote port data * @event: The event that occured * * Locking Note: The rport lock should not be held when calling * this function. */ static void fc_lport_rport_callback (struct fc_lport *lport, -struct fc_rport *rport, +struct fc_rport_priv *rdata,enum fc_rport_event event) { +struct fc_rport *rport =PRIV_TO_RPORT (rdata); +FC_LPORT_DBG (lport,"Received a %d event for port (%6x)\n" , event, rport->port_id);
@@ -151,7 +153,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,if (rport->port_id ==FC_FID_DIR_SERV ) {mutex_lock (&lport->lp_mutex);if (lport->state ==LPORT_ST_DNS ) { - lport->dns_rp = rport; + lport->dns_rp = rdata;fc_lport_enter_rpn_id (lport); }else { FC_LPORT_DBG(lport, "Received an CREATED event "
@@ -160,7 +162,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,"in the DNS state, it's in the " "%d state" , rport->port_id, lport->state); - lport->tt.rport_logoff (rport); + lport->tt.rport_logoff (rdata); }mutex_unlock (&lport->lp_mutex); }else
@@ -832,7 +834,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, {struct fc_frame_header *fh =fc_frame_header_get (fp);void (*recv) (struct fc_seq *,struct fc_frame *,struct fc_lport *); -struct fc_rport *rport; +struct fc_rport_priv *rdata;u32 s_id;u32 d_id;struct fc_seq_els_data rjt_data;
@@ -888,9 +890,9 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, s_id =ntoh24 (fh->fh_s_id); d_id =ntoh24 (fh->fh_d_id); - rport = lport->tt.rport_lookup (lport, s_id); -if (rport) - lport->tt.rport_recv_req (sp, fp, rport); + rdata = lport->tt.rport_lookup (lport, s_id); +if (rdata) + lport->tt.rport_recv_req (sp, fp, rdata);else { rjt_data.fp =NULL ; rjt_data.reason =ELS_RJT_UNAB ;
@@ -1304,7 +1306,6 @@ static struct fc_rport_operations fc_lport_rport_ops = {*/ static void fc_lport_enter_dns (struct fc_lport *lport) { -struct fc_rport *rport;struct fc_rport_priv *rdata;struct fc_rport_identifiers ids;
@@ -1318,13 +1319,12 @@ static void fc_lport_enter_dns(struct fc_lport *lport)fc_lport_state_enter (lport,LPORT_ST_DNS ); - rport = lport->tt.rport_create (lport, &ids); -if (!rport) + rdata = lport->tt.rport_create (lport, &ids); +if (!rdata) goto err; - rdata = rport->dd_data; rdata->ops = &fc_lport_rport_ops; - lport->tt.rport_login (rport); + lport->tt.rport_login (rdata);return ; err:
drivers/scsi/libfc/fc_rport.c +176 -188
932 lines not on this page · raw message
include/scsi/fc_encode.h +5 -2
@@ -249,10 +249,13 @@ static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp)/** * fc_els_fill - Fill in an ELS request frame */ -static inline int fc_els_fill (struct fc_lport *lport,struct fc_rport *rport, +static inline int fc_els_fill (struct fc_lport *lport, +struct fc_rport_priv *rdata,struct fc_frame *fp,unsigned int op,enum fc_rctl *r_ctl,u32 *did,enum fc_fh_type *fh_type) { +struct fc_rport *rport =PRIV_TO_RPORT (rdata); +switch (op) {case ELS_PLOGI :fc_plogi_fill (lport, fp,ELS_PLOGI );
@@ -272,7 +275,7 @@ static inline int fc_els_fill(struct fc_lport *lport, struct fc_rport *rport,* is port logo, therefore * set did to rport id. */ -if (rport) +if (rdata) *did = rport->port_id;break ;
include/scsi/libfc.h +14 -12
@@ -75,10 +75,10 @@ do { \ (lport)->host->host_no, \ (port_id), ##args)) -#define FC_RPORT_DBG(rport, fmt, args...) \ +#define FC_RPORT_DBG(rdata, fmt, args...) \ do { \ - struct fc_rport_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ + struct fc_rport *rport = PRIV_TO_RPORT(rdata); \ FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0)
@@ -185,8 +185,10 @@ enum fc_rport_event {*/ #define fc_rport_priv fc_rport_libfc_priv +struct fc_rport_priv ; +struct fc_rport_operations { -void (*event_callback)(struct fc_lport *,struct fc_rport *, +void (*event_callback)(struct fc_lport *,struct fc_rport_priv *,enum fc_rport_event ); };
@@ -422,7 +424,7 @@ struct libfc_function_template {* STATUS: OPTIONAL */ struct fc_seq *(*elsct_send)(struct fc_lport *lport, - struct fc_rport *rport, + struct fc_rport_priv *, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *,
@@ -567,8 +569,8 @@ struct libfc_function_template {/* * Create a remote port */ -struct fc_rport *(*rport_create)(struct fc_lport *, -struct fc_rport_identifiers *); +struct fc_rport_priv *(*rport_create)(struct fc_lport *, +struct fc_rport_identifiers *);/* * Initiates the RP state machine. It is called from the LP module.
@@ -581,7 +583,7 @@ struct libfc_function_template {* * STATUS: OPTIONAL */ -int (*rport_login)(struct fc_rport *rport); +int (*rport_login)(struct fc_rport_priv *);/* * Logoff, and remove the rport from the transport if
@@ -589,7 +591,7 @@ struct libfc_function_template {* * STATUS: OPTIONAL */ -int (*rport_logoff)(struct fc_rport *rport); +int (*rport_logoff)(struct fc_rport_priv *);/* * Recieve a request from a remote port.
@@ -597,14 +599,14 @@ struct libfc_function_template {* STATUS: OPTIONAL */ void (*rport_recv_req)(struct fc_seq *,struct fc_frame *, -struct fc_rport *); +struct fc_rport_priv *);/* * lookup an rport by it's port ID. * * STATUS: OPTIONAL */ -struct fc_rport *(*rport_lookup)(const struct fc_lport *,u32 ); +struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *,u32 );/* * Send a fcp cmd from fsp pkt.
@@ -694,8 +696,8 @@ struct fc_lport {/* Associations */ struct Scsi_Host *host;struct list_head ema_list; -struct fc_rport *dns_rp; -struct fc_rport *ptp_rp; +struct fc_rport_priv *dns_rp; +struct fc_rport_priv *ptp_rp;void *scsi_priv;struct fc_disc disc;
PATCH 28/64 libfc: change elsct to use FC_ID instead of rdata
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
tt.elsct_send is used by both FCP and by the rport state machine. After further patches, these two modules will use different structures for the remote port.
So, change elsct_send to use the FC_ID instead of the fc_rport_priv as its argument. It currently only uses the FC_ID anyway.
For CT requests the destination FC_ID is still implicitly 0xfffffc. After further patches the did arg on CT requests will be used to specify the FC_ID being inquired about for GPN_ID or other queries.
---
drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_elsct.c | 11 ++++++----- drivers/scsi/libfc/fc_fcp.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ drivers/scsi/libfc/fc_rport.c | 8 ++++---- include/scsi/fc_encode.h | 26 +++++--------------------- include/scsi/libfc.h | 2 +- 7 files changed, 24 insertions(+), 39 deletions(-)
drivers/scsi/libfc/fc_disc.c +1 -1
@@ -526,7 +526,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *disc)if (!fp) goto err; -if (lport->tt.elsct_send (lport,NULL , fp, +if (lport->tt.elsct_send (lport,0 , fp,FC_NS_GPN_FT , fc_disc_gpn_ft_resp, disc, lport->e_d_tov))
drivers/scsi/libfc/fc_elsct.c +6 -5
@@ -32,7 +32,7 @@* fc_elsct_send - sends ELS/CT frame */ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, - struct fc_rport_priv *rdata, + u32 did, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *,
@@ -41,16 +41,17 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, void *arg, u32 timer_msec) {enum fc_rctl r_ctl; -u32 did =FC_FID_NONE ;enum fc_fh_type fh_type;int rc;/* ELS requests */ if ((op >=ELS_LS_RJT ) && (op <=ELS_AUTH_ELS )) - rc =fc_els_fill (lport, rdata, fp, op, &r_ctl, &did, &fh_type); -else + rc =fc_els_fill (lport, did, fp, op, &r_ctl, &fh_type); +else {/* CT requests */ - rc =fc_ct_fill (lport, fp, op, &r_ctl, &did, &fh_type); + rc =fc_ct_fill (lport, fp, op, &r_ctl, &fh_type); + did =FC_FID_DIR_SERV ; + }if (rc)return NULL ;
drivers/scsi/libfc/fc_fcp.c +1 -1
@@ -1308,7 +1308,7 @@ static void fc_fcp_rec(struct fc_fcp_pkt *fsp)fc_fill_fc_hdr (fp,FC_RCTL_ELS_REQ , rport->port_id,fc_host_port_id (rp->local_port->host),FC_TYPE_ELS ,FC_FC_FIRST_SEQ |FC_FC_END_SEQ |FC_FC_SEQ_INIT ,0 ); -if (lp->tt.elsct_send (lp, rport->dd_data, fp,ELS_REC , fc_fcp_rec_resp, +if (lp->tt.elsct_send (lp, rport->port_id, fp,ELS_REC , fc_fcp_rec_resp, fsp,jiffies_to_msecs (FC_SCSI_REC_TOV ))) {fc_fcp_pkt_hold (fsp);/* hold while REC outstanding */ return ;
drivers/scsi/libfc/fc_lport.c +6 -6
@@ -1217,7 +1217,7 @@ static void fc_lport_enter_scr(struct fc_lport *lport)return ; } -if (!lport->tt.elsct_send (lport,NULL , fp,ELS_SCR , +if (!lport->tt.elsct_send (lport,FC_FID_FCTRL , fp,ELS_SCR , fc_lport_scr_resp, lport, lport->e_d_tov))fc_lport_error (lport, fp); }
@@ -1258,7 +1258,7 @@ static void fc_lport_enter_rft_id(struct fc_lport *lport)return ; } -if (!lport->tt.elsct_send (lport,NULL , fp,FC_NS_RFT_ID , +if (!lport->tt.elsct_send (lport,FC_FID_DIR_SERV , fp,FC_NS_RFT_ID , fc_lport_rft_id_resp, lport, lport->e_d_tov))fc_lport_error (lport, fp);
@@ -1287,7 +1287,7 @@ static void fc_lport_enter_rpn_id(struct fc_lport *lport)return ; } -if (!lport->tt.elsct_send (lport,NULL , fp,FC_NS_RPN_ID , +if (!lport->tt.elsct_send (lport,FC_FID_DIR_SERV , fp,FC_NS_RPN_ID , fc_lport_rpn_id_resp, lport, lport->e_d_tov))fc_lport_error (lport, fp);
@@ -1443,8 +1443,8 @@ static void fc_lport_enter_logo(struct fc_lport *lport)return ; } -if (!lport->tt.elsct_send (lport,NULL , fp,ELS_LOGO , fc_lport_logo_resp, - lport, lport->e_d_tov)) +if (!lport->tt.elsct_send (lport,FC_FID_FLOGI , fp,ELS_LOGO , + fc_lport_logo_resp, lport, lport->e_d_tov))fc_lport_error (lport, fp); }
@@ -1567,7 +1567,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport)if (!fp)return fc_lport_error (lport, fp); -if (!lport->tt.elsct_send (lport,NULL , fp,ELS_FLOGI , +if (!lport->tt.elsct_send (lport,FC_FID_FLOGI , fp,ELS_FLOGI , fc_lport_flogi_resp, lport, lport->e_d_tov))fc_lport_error (lport, fp); }
drivers/scsi/libfc/fc_rport.c +4 -4
@@ -593,7 +593,7 @@ static void fc_rport_enter_plogi(struct fc_rport_priv *rdata) } rdata->e_d_tov = lport->e_d_tov; -if (!lport->tt.elsct_send (lport, rdata, fp,ELS_PLOGI , +if (!lport->tt.elsct_send (lport, rport->port_id, fp,ELS_PLOGI , fc_rport_plogi_resp, rdata, lport->e_d_tov))fc_rport_error_retry (rdata, fp);else
@@ -747,7 +747,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata)return ; } -if (!lport->tt.elsct_send (lport, rdata, fp,ELS_PRLI , +if (!lport->tt.elsct_send (lport, rport->port_id, fp,ELS_PRLI , fc_rport_prli_resp, rdata, lport->e_d_tov))fc_rport_error_retry (rdata, fp);else
@@ -845,7 +845,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *rdata)return ; } -if (!lport->tt.elsct_send (lport, rdata, fp,ELS_RTV , +if (!lport->tt.elsct_send (lport, rport->port_id, fp,ELS_RTV , fc_rport_rtv_resp, rdata, lport->e_d_tov))fc_rport_error_retry (rdata, fp);else
@@ -876,7 +876,7 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)return ; } -if (!lport->tt.elsct_send (lport, rdata, fp,ELS_LOGO , +if (!lport->tt.elsct_send (lport, rport->port_id, fp,ELS_LOGO , fc_rport_logo_resp, rdata, lport->e_d_tov))fc_rport_error_retry (rdata, fp);else
include/scsi/fc_encode.h +5 -21
@@ -79,8 +79,9 @@ static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp,/** * fc_ct_fill - Fill in a name service request frame */ -static inline int fc_ct_fill (struct fc_lport *lport,struct fc_frame *fp, -unsigned int op,enum fc_rctl *r_ctl,u32 *did, +static inline int fc_ct_fill (struct fc_lport *lport, +struct fc_frame *fp, +unsigned int op,enum fc_rctl *r_ctl,enum fc_fh_type *fh_type) {struct fc_ct_req *ct;
@@ -110,7 +111,6 @@ static inline int fc_ct_fill(struct fc_lport *lport, struct fc_frame *fp,return -EINVAL ; } *r_ctl =FC_RCTL_DD_UNSOL_CTL ; - *did =FC_FID_DIR_SERV ; *fh_type =FC_TYPE_CT ;return 0 ; }
@@ -250,53 +250,37 @@ static inline void fc_scr_fill(struct fc_lport *lport, struct fc_frame *fp)* fc_els_fill - Fill in an ELS request frame */ static inline int fc_els_fill (struct fc_lport *lport, -struct fc_rport_priv *rdata, +u32 did,struct fc_frame *fp,unsigned int op, -enum fc_rctl *r_ctl,u32 *did,enum fc_fh_type *fh_type) +enum fc_rctl *r_ctl,enum fc_fh_type *fh_type) { -struct fc_rport *rport =PRIV_TO_RPORT (rdata); -switch (op) {case ELS_PLOGI :fc_plogi_fill (lport, fp,ELS_PLOGI ); - *did = rport->port_id;break ;case ELS_FLOGI :fc_flogi_fill (lport, fp); - *did =FC_FID_FLOGI ;break ;case ELS_LOGO :fc_logo_fill (lport, fp); - *did =FC_FID_FLOGI ; -/* -* if rport is valid then it -* is port logo, therefore -* set did to rport id. -*/ -if (rdata) - *did = rport->port_id;break ;case ELS_RTV :fc_rtv_fill (lport, fp); - *did = rport->port_id;break ;case ELS_REC :fc_rec_fill (lport, fp); - *did = rport->port_id;break ;case ELS_PRLI :fc_prli_fill (lport, fp); - *did = rport->port_id;break ;case ELS_SCR :fc_scr_fill (lport, fp); - *did =FC_FID_FCTRL ;break ;default :
include/scsi/libfc.h +1 -1
@@ -424,7 +424,7 @@ struct libfc_function_template {* STATUS: OPTIONAL */ struct fc_seq *(*elsct_send)(struct fc_lport *lport, - struct fc_rport_priv *, + u32 did, struct fc_frame *fp, unsigned int op, void (*resp)(struct fc_seq *,
PATCH 29/64 libfc: make rport structure optional
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Allow a struct fc_rport_priv to have no fc_rport associated with it. This sets up to remove the need for "rogue" rports.
Add a few fields to fc_rport_priv that are needed before the fc_rport is created. These are the ids, maxframe_size, classes, and rport pointer.
Remove the macro PRIV_TO_RPORT(). Just use rdata->rport where appropriate.
To take the place of the get_device()/put_device ops that were used to hold both the rport and rdata, add a reference count to rdata structures using kref. When kref_get decrements the refcount to zero, a new template function releasing the rdata should be called. This will take care of freeing the rdata and releasing the hold on the rport (for now). After subsequent patches make the rport truly optional, this release function will simply free the rdata.
Remove the simple inline function fc_rport_set_name(), which becomes semanticly ambiguous otherwise. The caller will set the port_name and node_name in the rdata->Ids, which will later be copied to the rport when it its created.
---
drivers/scsi/libfc/fc_disc.c | 54 ++++++++-------------- drivers/scsi/libfc/fc_lport.c | 14 ++---- drivers/scsi/libfc/fc_rport.c | 102 +++++++++++++++++++++++------------------ include/scsi/libfc.h | 29 ++++++------ 4 files changed, 98 insertions(+), 101 deletions(-)
drivers/scsi/libfc/fc_disc.c +19 -35
@@ -47,7 +47,7 @@static void fc_disc_gpn_ft_req (struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *); -static int fc_disc_new_target (struct fc_disc *,struct fc_rport *, +static int fc_disc_new_target (struct fc_disc *,struct fc_rport_priv *,struct fc_rport_identifiers *);static void fc_disc_done (struct fc_disc *);static void fc_disc_timeout (struct work_struct *);
@@ -63,12 +63,10 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport, u32 port_id) {const struct fc_disc *disc = &lport->disc; -struct fc_rport *rport;struct fc_rport_priv *rdata;list_for_each_entry (rdata, &disc->rports, peers) { - rport =PRIV_TO_RPORT (rdata); -if (rport->port_id == port_id) +if (rdata->ids.port_id == port_id)return rdata; }return NULL ;
@@ -115,10 +113,9 @@ static void fc_disc_rport_callback(struct fc_lport *lport, enum fc_rport_event event) {struct fc_disc *disc = &lport->disc; -struct fc_rport *rport =PRIV_TO_RPORT (rdata);FC_DISC_DBG (disc,"Received a %d event for port (%6x)\n" , event, - rport->port_id); + rdata->ids.port_id);switch (event) {case RPORT_EV_CREATED :
@@ -320,8 +317,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, struct fc_lport *lport) {struct fc_rport_priv *rdata; -struct fc_rport *rport; -struct fc_rport_identifiers ids;struct fc_disc *disc = &lport->disc;/*
@@ -349,18 +344,12 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,*/ rdata = disc->lport->ptp_rp;if (rdata) { - rport =PRIV_TO_RPORT (rdata); - ids.port_id = rport->port_id; - ids.port_name = rport->port_name; - ids.node_name = rport->node_name; - ids.roles =FC_RPORT_ROLE_UNKNOWN ; -get_device (&rport->dev); - -if (!fc_disc_new_target (disc, rport, &ids)) { +kref_get (&rdata->kref); +if (!fc_disc_new_target (disc, rdata, &rdata->ids)) { disc->event =DISC_EV_SUCCESS ;fc_disc_done (disc); } -put_device (&rport->dev); +kref_put (&rdata->kref, rdata->local_port->tt.rport_destroy); }else {fc_disc_gpn_ft_req (disc);/* get ports by FC-4 type */ }
@@ -375,28 +364,27 @@ static struct fc_rport_operations fc_disc_rport_ops = {/** * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port -* @rport: The previous FC remote port (NULL if new remote port) +* @rdata: The previous FC remote port priv (NULL if new remote port) * @ids: Identifiers for the new FC remote port * * Locking Note: This function expects that the disc_mutex is locked * before it is called. */ static int fc_disc_new_target (struct fc_disc *disc, -struct fc_rport *rport, +struct fc_rport_priv *rdata,struct fc_rport_identifiers *ids) {struct fc_lport *lport = disc->lport; -struct fc_rport_priv *rdata;int error =0 ; -if (rport && ids->port_name) { -if (rport->port_name ==-1 ) { +if (rdata && ids->port_name) { +if (rdata->ids.port_name ==-1 ) {/* * Set WWN and fall through to notify of create. */ -fc_rport_set_name (rport, ids->port_name, - rport->node_name); - }else if (rport->port_name != ids->port_name) { + rdata->ids.port_name = ids->port_name; + rdata->ids.node_name = ids->node_name; + }else if (rdata->ids.port_name != ids->port_name) {/* * This is a new port with the same FCID as * a previously-discovered port. Presumably the old
@@ -404,27 +392,23 @@ static int fc_disc_new_target(struct fc_disc *disc,* assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ - rdata = rport->dd_data;list_del (&rdata->peers); lport->tt.rport_logoff (rdata); - rport =NULL ; + rdata =NULL ; } }if (((ids->port_name !=-1 ) || (ids->port_id !=-1 )) && ids->port_id !=fc_host_port_id (lport->host) && ids->port_name != lport->wwpn) { -if (!rport) { +if (!rdata) { rdata = lport->tt.rport_lookup (lport, ids->port_id); -if (!rport) { +if (!rdata) { rdata = lport->tt.rport_create (lport, ids); +if (!rdata) + error = -ENOMEM ; } -if (!rdata) - error = -ENOMEM ; -else - rport =PRIV_TO_RPORT (rdata); } -if (rport) { - rdata = rport->dd_data; +if (rdata) { rdata->ops = &fc_disc_rport_ops; rdata->rp_state =RPORT_ST_INIT ;list_add_tail (&rdata->peers, &disc->rogue_rports);
drivers/scsi/libfc/fc_lport.c +6 -8
@@ -143,14 +143,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, struct fc_rport_priv *rdata, enum fc_rport_event event) { - struct fc_rport *rport = PRIV_TO_RPORT(rdata); - FC_LPORT_DBG(lport, "Received a %d event for port (%6x)\n", event, - rport->port_id); + rdata->ids.port_id);switch (event) {case RPORT_EV_CREATED : -if (rport->port_id ==FC_FID_DIR_SERV ) { +if (rdata->ids.port_id ==FC_FID_DIR_SERV ) {mutex_lock (&lport->lp_mutex);if (lport->state ==LPORT_ST_DNS ) { lport->dns_rp = rdata;
@@ -160,7 +158,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport,"on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the " -"%d state" , rport->port_id, +"%d state" , rdata->ids.port_id, lport->state); lport->tt.rport_logoff (rdata); }
@@ -168,12 +166,12 @@ static void fc_lport_rport_callback(struct fc_lport *lport, }else FC_LPORT_DBG (lport,"Received an event for port (%6x) " "which is not the directory server\n" , - rport->port_id); + rdata->ids.port_id);break ;case RPORT_EV_LOGO :case RPORT_EV_FAILED :case RPORT_EV_STOP : -if (rport->port_id ==FC_FID_DIR_SERV ) { +if (rdata->ids.port_id ==FC_FID_DIR_SERV ) {mutex_lock (&lport->lp_mutex); lport->dns_rp =NULL ;mutex_unlock (&lport->lp_mutex);
@@ -181,7 +179,7 @@ static void fc_lport_rport_callback(struct fc_lport *lport, }else FC_LPORT_DBG (lport,"Received an event for port (%6x) " "which is not the directory server\n" , - rport->port_id); + rdata->ids.port_id);break ;case RPORT_EV_NONE :break ;
drivers/scsi/libfc/fc_rport.c +57 -45
346 lines not on this page · raw message
include/scsi/libfc.h +16 -13
@@ -76,11 +76,7 @@ do { \ (port_id), ##args)) #define FC_RPORT_DBG(rdata, fmt, args...) \ -do { \ - struct fc_lport *lport = rdata->local_port; \ - struct fc_rport *rport = PRIV_TO_RPORT(rdata); \ - FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ -} while (0) + FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \
@@ -195,9 +191,13 @@ struct fc_rport_operations {/** * struct fc_rport_libfc_priv - libfc internal information about a remote port * @local_port: Fibre Channel host port instance +* @rport: transport remote port +* @kref: reference counter * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges +* @ids: remote port identifiers and roles * @flags: REC and RETRY supported flags * @max_seq: maximum number of concurrent sequences +* @maxframe_size: maximum frame size * @retries: retry count in current state * @e_d_tov: error detect timeout value (in msec) * @r_a_tov: resource allocation timeout value (in msec)
@@ -207,11 +207,15 @@ struct fc_rport_operations {*/ struct fc_rport_libfc_priv {struct fc_lport *local_port; +struct fc_rport *rport; +struct kref kref;enum fc_rport_state rp_state; +struct fc_rport_identifiers ids;u16 flags;#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0)#define FC_RP_FLAGS_RETRY (1 << 1)u16 max_seq; +u16 maxframe_size;unsigned int retries;unsigned int e_d_tov;unsigned int r_a_tov;
@@ -222,19 +226,12 @@ struct fc_rport_libfc_priv {struct fc_rport_operations *ops;struct list_head peers;struct work_struct event_work; +u32 supported_classes; }; -#define PRIV_TO_RPORT (x) \ - ((struct fc_rport *)((void *)(x) - sizeof(struct fc_rport)))#define RPORT_TO_PRIV (x) \ ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) -static inline void fc_rport_set_name (struct fc_rport *rport,u64 wwpn,u64 wwnn) -{ - rport->node_name = wwnn; - rport->port_name = wwpn; -} -/* * fcoe stats structure */
@@ -609,6 +606,12 @@ struct libfc_function_template {struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *,u32 );/* +* Destroy an rport after final kref_put(). +* The argument is a pointer to the kref inside the fc_rport_priv. +*/ +void (*rport_destroy)(struct kref *); + +/* * Send a fcp cmd from fsp pkt. * Called with the SCSI host lock unlocked and irqs disabled. *
PATCH 30/64 libfc: rearrange code in fc_rport_work
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
This is a cleanup without semantic changes to use a switch statement instead of a series of if-statements in fc_rport_work(), and to move some declarations up to the top.
---
drivers/scsi/libfc/fc_rport.c | 24 +++++++++++++++--------- 1 files changed, 15 insertions(+), 9 deletions(-)
drivers/scsi/libfc/fc_rport.c +15 -9
@@ -233,6 +233,9 @@ static void fc_rport_work(struct work_struct *work)enum fc_rport_trans_state trans_state;struct fc_lport *lport = rdata->local_port;struct fc_rport_operations *rport_ops; +struct fc_rport *new_rport; +struct fc_rport_priv *new_rdata; +struct fc_rport_identifiers ids;struct fc_rport *rport;mutex_lock (&rdata->rp_mutex);
@@ -240,11 +243,8 @@ static void fc_rport_work(struct work_struct *work) rport_ops = rdata->ops; rport = rdata->rport; -if (event ==RPORT_EV_CREATED ) { -struct fc_rport *new_rport; -struct fc_rport_priv *new_rdata; -struct fc_rport_identifiers ids; - +switch (event) { +case RPORT_EV_CREATED : ids = rdata->ids; rdata->event =RPORT_EV_NONE ;mutex_unlock (&rdata->rp_mutex);
@@ -289,9 +289,11 @@ static void fc_rport_work(struct work_struct *work) rdata = new_rport->dd_data;if (rport_ops->event_callback) rport_ops->event_callback (lport, rdata, event); - }else if ((event ==RPORT_EV_FAILED ) || - (event ==RPORT_EV_LOGO ) || - (event ==RPORT_EV_STOP )) { +break ; + +case RPORT_EV_FAILED : +case RPORT_EV_LOGO : +case RPORT_EV_STOP : trans_state = rdata->trans_state;mutex_unlock (&rdata->rp_mutex);if (rport_ops->event_callback)
@@ -305,8 +307,12 @@ static void fc_rport_work(struct work_struct *work) lport->tt.exch_mgr_reset (lport,0 , port_id); lport->tt.exch_mgr_reset (lport, port_id,0 ); } - }else +break ; + +default :mutex_unlock (&rdata->rp_mutex); +break ; + } }/**
PATCH 31/64 libfc: rename rport event CREATED to READY
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Remote ports will become READY more than once after ADISC is implemented in a later patch.
The event callback that has been called "CREATED" will mean "READY". Rename it now in preparation for those changes.
---
drivers/scsi/libfc/fc_disc.c | 2 +- drivers/scsi/libfc/fc_lport.c | 4 ++-- drivers/scsi/libfc/fc_rport.c | 4 ++-- include/scsi/libfc.h | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-)
drivers/scsi/libfc/fc_disc.c +1 -1
@@ -118,7 +118,7 @@ static void fc_disc_rport_callback(struct fc_lport *lport, rdata->ids.port_id);switch (event) { -case RPORT_EV_CREATED : +case RPORT_EV_READY :if (disc) {mutex_lock (&disc->disc_mutex);list_add_tail (&rdata->peers, &disc->rports);
drivers/scsi/libfc/fc_lport.c +2 -2
@@ -147,14 +147,14 @@ static void fc_lport_rport_callback(struct fc_lport *lport, rdata->ids.port_id);switch (event) { -case RPORT_EV_CREATED : +case RPORT_EV_READY :if (rdata->ids.port_id ==FC_FID_DIR_SERV ) {mutex_lock (&lport->lp_mutex);if (lport->state ==LPORT_ST_DNS ) { lport->dns_rp = rdata;fc_lport_enter_rpn_id (lport); }else { -FC_LPORT_DBG (lport,"Received an CREATED event " +FC_LPORT_DBG (lport,"Received an READY event " "on port (%6x) for the directory " "server, but the lport is not " "in the DNS state, it's in the "
drivers/scsi/libfc/fc_rport.c +2 -2
@@ -244,7 +244,7 @@ static void fc_rport_work(struct work_struct *work) rport = rdata->rport;switch (event) { -case RPORT_EV_CREATED : +case RPORT_EV_READY : ids = rdata->ids; rdata->event =RPORT_EV_NONE ;mutex_unlock (&rdata->rp_mutex);
@@ -413,7 +413,7 @@ static void fc_rport_enter_ready(struct fc_rport_priv *rdata)if (rdata->event ==RPORT_EV_NONE )queue_work (rport_event_queue, &rdata->event_work); - rdata->event =RPORT_EV_CREATED ; + rdata->event =RPORT_EV_READY ; }/**
include/scsi/libfc.h +1 -1
@@ -167,7 +167,7 @@ struct fc_disc_port {enum fc_rport_event {RPORT_EV_NONE =0 , -RPORT_EV_CREATED , +RPORT_EV_READY ,RPORT_EV_FAILED ,RPORT_EV_STOP ,RPORT_EV_LOGO
PATCH 32/64 libfc: don't create dummy (rogue) remote ports
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Don't create a "dummy" remote port to go with fc_rport_priv.
Make the rport truly optional by allocating fc_rport_priv separately and not requiring a dummy rport to be there if we haven't yet done fc_remote_port_add().
The fc_rport_libfc_priv remains as a structure attached to the rport for I/O purposes.
Be sure to hold references on rdata when the lock is dropped in fc_rport_work().
---
drivers/scsi/libfc/fc_disc.c | 40 +++-------- drivers/scsi/libfc/fc_rport.c | 154 +++++++++++++++++------------------------ include/scsi/libfc.h | 40 +++++------ 3 files changed, 92 insertions(+), 142 deletions(-)
drivers/scsi/libfc/fc_disc.c +10 -30
@@ -66,7 +66,8 @@ struct fc_rport_priv *fc_disc_lookup_rport(const struct fc_lport *lport,struct fc_rport_priv *rdata;list_for_each_entry (rdata, &disc->rports, peers) { -if (rdata->ids.port_id == port_id) +if (rdata->ids.port_id == port_id && + rdata->rp_state !=RPORT_ST_DELETE )return rdata; }return NULL ;
@@ -87,15 +88,8 @@ void fc_disc_stop_rports(struct fc_disc *disc) lport = disc->lport;mutex_lock (&disc->disc_mutex); -list_for_each_entry_safe (rdata, next, &disc->rports, peers) { -list_del (&rdata->peers); +list_for_each_entry_safe (rdata, next, &disc->rports, peers) lport->tt.rport_logoff (rdata); - } - -list_for_each_entry_safe (rdata, next, &disc->rogue_rports, peers) { - lport->tt.rport_logoff (rdata); - } -mutex_unlock (&disc->disc_mutex); }
@@ -119,20 +113,12 @@ static void fc_disc_rport_callback(struct fc_lport *lport,switch (event) {case RPORT_EV_READY : -if (disc) { -mutex_lock (&disc->disc_mutex); -list_add_tail (&rdata->peers, &disc->rports); -mutex_unlock (&disc->disc_mutex); - }break ;case RPORT_EV_LOGO :case RPORT_EV_FAILED :case RPORT_EV_STOP :mutex_lock (&disc->disc_mutex); -mutex_lock (&rdata->rp_mutex); -if (rdata->trans_state ==FC_PORTSTATE_ROGUE ) -list_del (&rdata->peers); -mutex_unlock (&rdata->rp_mutex); +list_del (&rdata->peers);mutex_unlock (&disc->disc_mutex);break ;default :
@@ -235,7 +221,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,list_del (&dp->peers); rdata = lport->tt.rport_lookup (lport, dp->ids.port_id);if (rdata) { -list_del (&rdata->peers); lport->tt.rport_logoff (rdata); }fc_disc_single (disc, dp);
@@ -296,10 +281,8 @@ static void fc_disc_restart(struct fc_disc *disc)FC_DISC_DBG (disc,"Restarting discovery\n" ); -list_for_each_entry_safe (rdata, next, &disc->rports, peers) { -list_del (&rdata->peers); +list_for_each_entry_safe (rdata, next, &disc->rports, peers) lport->tt.rport_logoff (rdata); - } disc->requested =1 ;if (!disc->pending)
@@ -392,7 +375,6 @@ static int fc_disc_new_target(struct fc_disc *disc,* assigned the same FCID. This should be rare. * Delete the old one and fall thru to re-create. */ -list_del (&rdata->peers); lport->tt.rport_logoff (rdata); rdata =NULL ; }
@@ -406,12 +388,13 @@ static int fc_disc_new_target(struct fc_disc *disc, rdata = lport->tt.rport_create (lport, ids);if (!rdata) error = -ENOMEM ; +else +list_add_tail (&rdata->peers, + &disc->rports); } }if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->rp_state =RPORT_ST_INIT ; -list_add_tail (&rdata->peers, &disc->rogue_rports); lport->tt.rport_login (rdata); } }
@@ -585,9 +568,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create (lport, &ids);if (rdata) { rdata->ops = &fc_disc_rport_ops; - rdata->local_port = lport; -list_add_tail (&rdata->peers, - &disc->rogue_rports); +list_add_tail (&rdata->peers, &disc->rports); lport->tt.rport_login (rdata); }else printk(KERN_WARNING "libfc: Failed to allocate "
@@ -736,7 +717,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)if (rdata) { rdata->ops = &fc_disc_rport_ops;kfree (dp); -list_add_tail (&rdata->peers, &disc->rogue_rports); +list_add_tail (&rdata->peers, &disc->rports); lport->tt.rport_login (rdata); }return ;
@@ -798,7 +779,6 @@ int fc_disc_init(struct fc_lport *lport)INIT_DELAYED_WORK (&disc->disc_work, fc_disc_timeout);mutex_init (&disc->disc_mutex);INIT_LIST_HEAD (&disc->rports); -INIT_LIST_HEAD (&disc->rogue_rports); disc->lport = lport; disc->delay =FC_DISC_DELAY ;
drivers/scsi/libfc/fc_rport.c +63 -91
224 lines not on this page · raw message
include/scsi/libfc.h +19 -21
@@ -146,11 +146,6 @@ enum fc_rport_state { RPORT_ST_DELETE, /* port being deleted */ }; -enum fc_rport_trans_state { -FC_PORTSTATE_ROGUE , -FC_PORTSTATE_REAL , -}; -/** * struct fc_disc_port - temporary discovery port to hold rport identifiers * @lp: Fibre Channel host port instance
@@ -173,14 +168,6 @@ enum fc_rport_event {RPORT_EV_LOGO }; -/* -* Temporary definition to prepare for split off from fc_rport_libfc_priv -* of a separately-allocated structure called fc_rport_priv. This will -* be the primary object for the discovery and rport state machines. -* This definition is just to make this patch series easier to review. -*/ -#define fc_rport_priv fc_rport_libfc_priv -struct fc_rport_priv ;struct fc_rport_operations {
@@ -191,6 +178,24 @@ struct fc_rport_operations {/** * struct fc_rport_libfc_priv - libfc internal information about a remote port * @local_port: Fibre Channel host port instance +* @rp_state: indicates READY for I/O or DELETE when blocked. +* @flags: REC and RETRY supported flags +* @e_d_tov: error detect timeout value (in msec) +* @r_a_tov: resource allocation timeout value (in msec) +*/ +struct fc_rport_libfc_priv { +struct fc_lport *local_port; +enum fc_rport_state rp_state; +u16 flags; +#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) +#define FC_RP_FLAGS_RETRY (1 << 1) +unsigned int e_d_tov; +unsigned int r_a_tov; +}; + +/** +* struct fc_rport_priv - libfc rport and discovery info about a remote port +* @local_port: Fibre Channel host port instance * @rport: transport remote port * @kref: reference counter * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges
@@ -205,21 +210,18 @@ struct fc_rport_operations {* @retry_work: * @event_callback: Callback for rport READY, FAILED or LOGO */ -struct fc_rport_libfc_priv { +struct fc_rport_priv {struct fc_lport *local_port;struct fc_rport *rport;struct kref kref;enum fc_rport_state rp_state;struct fc_rport_identifiers ids;u16 flags; -#define FC_RP_FLAGS_REC_SUPPORTED (1 << 0) -#define FC_RP_FLAGS_RETRY (1 << 1)u16 max_seq;u16 maxframe_size;unsigned int retries;unsigned int e_d_tov;unsigned int r_a_tov; -enum fc_rport_trans_state trans_state;struct mutex rp_mutex;struct delayed_work retry_work;enum fc_rport_event event;
@@ -229,9 +231,6 @@ struct fc_rport_libfc_priv {u32 supported_classes; }; -#define RPORT_TO_PRIV (x) \ - ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport))) -/* * fcoe stats structure */
@@ -686,7 +685,6 @@ struct fc_disc { enum fc_disc_event);struct list_head rports; -struct list_head rogue_rports;struct fc_lport *lport;struct mutex disc_mutex;struct fc_gpn_ft_resp partial_buf;/* partial name buffer */
PATCH 33/64 libfc: fix rport event race between READY and LOGO
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When a remote port becomes ready and a LOGO is received before the READY event is in rport_work waiting on the mutex, the event is changed to LOGO and the work queued, so both the calls to rport_work see the LOGO event, and both try to do the list_del(), causing a crash.
Don't change the event if it is already set.
---
drivers/scsi/libfc/fc_rport.c | 4 +--- 1 files changed, 1 insertions(+), 3 deletions(-)
drivers/scsi/libfc/fc_rport.c +1 -3
@@ -1267,9 +1267,7 @@ static void fc_rport_recv_logo_req(struct fc_rport_priv *rdata,return ; } - rdata->event =RPORT_EV_LOGO ; -fc_rport_state_enter (rdata,RPORT_ST_DELETE ); -queue_work (rport_event_queue, &rdata->event_work); +fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL );fc_frame_free (fp);
PATCH 34/64 libfc: eliminate disc->event
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
There was no need to have the discovery status stored in struct fc_disc.
Change fc_disc_done() to take the discovery status as an argument and just pass it on to the discovery callback.
---
drivers/scsi/libfc/fc_disc.c | 31 ++++++++++++------------------- include/scsi/libfc.h | 1 - 2 files changed, 12 insertions(+), 20 deletions(-)
drivers/scsi/libfc/fc_disc.c +12 -19
@@ -49,7 +49,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *);static int fc_disc_new_target (struct fc_disc *,struct fc_rport_priv *,struct fc_rport_identifiers *); -static void fc_disc_done (struct fc_disc *); +static void fc_disc_done (struct fc_disc *,enum fc_disc_event );static void fc_disc_timeout (struct work_struct *);static void fc_disc_single (struct fc_disc *,struct fc_disc_port *);static void fc_disc_restart (struct fc_disc *);
@@ -329,8 +329,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,if (rdata) {kref_get (&rdata->kref);if (!fc_disc_new_target (disc, rdata, &rdata->ids)) { - disc->event =DISC_EV_SUCCESS ; -fc_disc_done (disc); +fc_disc_done (disc,DISC_EV_SUCCESS ); }kref_put (&rdata->kref, rdata->local_port->tt.rport_destroy); }else {
@@ -404,20 +403,18 @@ static int fc_disc_new_target(struct fc_disc *disc,/** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context +* @event: discovery completion status +* * Locking Note: This function expects that the disc mutex is locked before * it is called. The discovery callback is then made with the lock released, * and the lock is re-taken before returning from this function */ -static void fc_disc_done (struct fc_disc *disc) +static void fc_disc_done (struct fc_disc *disc,enum fc_disc_event event) {struct fc_lport *lport = disc->lport; -enum fc_disc_event event;FC_DISC_DBG (disc,"Discovery complete\n" ); - event = disc->event; - disc->event =DISC_EV_NONE ; -if (disc->requested)fc_disc_gpn_ft_req (disc);else
@@ -460,11 +457,8 @@ static void fc_disc_error(struct fc_disc *disc, struct fc_frame *fp) } disc->retry_count++;schedule_delayed_work (&disc->disc_work, delay); - }else { -/* exceeded retries */ - disc->event =DISC_EV_FAILED ; -fc_disc_done (disc); - } + }else +fc_disc_done (disc,DISC_EV_FAILED ); } }
@@ -503,10 +497,12 @@ err: }/** -* fc_disc_gpn_ft_parse() - Parse the list of IDs and names resulting from a request +* fc_disc_gpn_ft_parse() - Parse the body of the dNS GPN_FT response. * @lport: Fibre Channel host port instance * @buf: GPN_FT response buffer * @len: size of response buffer +* +* Goes through the list of IDs and names resulting from a request. */ static int fc_disc_gpn_ft_parse (struct fc_disc *disc,void *buf,size_t len) {
@@ -577,8 +573,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) }if (np->fp_flags &FC_NS_FID_LAST ) { - disc->event =DISC_EV_SUCCESS ; -fc_disc_done (disc); +fc_disc_done (disc,DISC_EV_SUCCESS ); len =0 ;break ; }
@@ -669,8 +664,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,FC_DISC_DBG (disc,"GPN_FT rejected reason %x exp %x " "(check zoning)\n" , cp->ct_reason, cp->ct_explan); - disc->event =DISC_EV_FAILED ; -fc_disc_done (disc); +fc_disc_done (disc,DISC_EV_FAILED ); }else {FC_DISC_DBG (disc,"GPN_FT unexpected response code " "%x\n" ,ntohs (cp->ct_cmd));
@@ -782,7 +776,6 @@ int fc_disc_init(struct fc_lport *lport) disc->lport = lport; disc->delay =FC_DISC_DELAY ; - disc->event =DISC_EV_NONE ;return 0 ; }
include/scsi/libfc.h +0 -1
@@ -679,7 +679,6 @@ struct fc_disc {unsigned char requested;unsigned short seq_count;unsigned char buf_len; -enum fc_disc_event event;void (*disc_callback)(struct fc_lport *,enum fc_disc_event );
PATCH 35/64 libfc: remove unused disc->delay element
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Delete unused disc->delay element.
---
drivers/scsi/libfc/fc_disc.c | 3 --- include/scsi/libfc.h | 1 - 2 files changed, 0 insertions(+), 4 deletions(-)
drivers/scsi/libfc/fc_disc.c +0 -3
@@ -43,8 +43,6 @@#define FC_DISC_RETRY_LIMIT 3/* max retries */ #define FC_DISC_RETRY_DELAY 500UL/* (msecs) delay */ -#define FC_DISC_DELAY 3 -static void fc_disc_gpn_ft_req (struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *); static int fc_disc_new_target(struct fc_disc *, struct fc_rport_priv *,
@@ -775,7 +773,6 @@ int fc_disc_init(struct fc_lport *lport)INIT_LIST_HEAD (&disc->rports); disc->lport = lport; - disc->delay =FC_DISC_DELAY ;return 0 ; }
include/scsi/libfc.h +0 -1
@@ -674,7 +674,6 @@ struct libfc_function_template {/* information used by the discovery layer */ struct fc_disc {unsigned char retry_count; -unsigned char delay;unsigned char pending;unsigned char requested;unsigned short seq_count;
PATCH 36/64 libfc: rport debug messages were printing pointer values
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Don't print large negative decimal numbers for frame pointers in the debug messages from fc_rport_error(). Just print 0 if its a frame pointer, and print the error numbers as positive.
---
drivers/scsi/libfc/fc_rport.c | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_rport.c +2 -1
@@ -436,7 +436,8 @@ static void fc_rport_timeout(struct work_struct *work)static void fc_rport_error (struct fc_rport_priv *rdata,struct fc_frame *fp) {FC_RPORT_DBG (rdata,"Error %ld in state %s, retries %d\n" , -PTR_ERR (fp),fc_rport_state (rdata), rdata->retries); +IS_ERR (fp) ? -PTR_ERR (fp) :0 , +fc_rport_state (rdata), rdata->retries);switch (rdata->rp_state) {case RPORT_ST_PLOGI :
PATCH 37/64 libfc: simplify fc_lport_rport_callback
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The lport rport callback can only be called for the dNS rport, since its the only rport who's ops point to that function.
Remove unnecessary checking and debug messages.
Put the locking outside the switch statement as a simplification.
---
drivers/scsi/libfc/fc_lport.c | 43 ++++++++++++++--------------------------- 1 files changed, 15 insertions(+), 28 deletions(-)
drivers/scsi/libfc/fc_lport.c +15 -28
@@ -146,44 +146,31 @@ static void fc_lport_rport_callback(struct fc_lport *lport,FC_LPORT_DBG (lport,"Received a %d event for port (%6x)\n" , event, rdata->ids.port_id); +mutex_lock (&lport->lp_mutex);switch (event) {case RPORT_EV_READY : -if (rdata->ids.port_id ==FC_FID_DIR_SERV ) { -mutex_lock (&lport->lp_mutex); -if (lport->state ==LPORT_ST_DNS ) { - lport->dns_rp = rdata; -fc_lport_enter_rpn_id (lport); - }else { -FC_LPORT_DBG (lport,"Received an READY event " -"on port (%6x) for the directory " -"server, but the lport is not " -"in the DNS state, it's in the " -"%d state" , rdata->ids.port_id, - lport->state); - lport->tt.rport_logoff (rdata); - } -mutex_unlock (&lport->lp_mutex); - }else -FC_LPORT_DBG (lport,"Received an event for port (%6x) " -"which is not the directory server\n" , - rdata->ids.port_id); +if (lport->state ==LPORT_ST_DNS ) { + lport->dns_rp = rdata; +fc_lport_enter_rpn_id (lport); + }else { +FC_LPORT_DBG (lport,"Received an READY event " +"on port (%6x) for the directory " +"server, but the lport is not " +"in the DNS state, it's in the " +"%d state" , rdata->ids.port_id, + lport->state); + lport->tt.rport_logoff (rdata); + }break ;case RPORT_EV_LOGO :case RPORT_EV_FAILED :case RPORT_EV_STOP : -if (rdata->ids.port_id ==FC_FID_DIR_SERV ) { -mutex_lock (&lport->lp_mutex); - lport->dns_rp =NULL ; -mutex_unlock (&lport->lp_mutex); - - }else -FC_LPORT_DBG (lport,"Received an event for port (%6x) " -"which is not the directory server\n" , - rdata->ids.port_id); + lport->dns_rp =NULL ;break ;case RPORT_EV_NONE :break ; } +mutex_unlock (&lport->lp_mutex); }/**
PATCH 38/64 libfc: make rport module maintain the rport list
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The list of remote ports (struct fc_rport_priv) has been maintained by the discovery module. In preparation for having lport->tt.rport_create() do a lookup first, maintain the rports list in the rport module. It will still be protected by the disc_mutex.
The DNS rport is an exception for until after further patches. For now, do not add it to the list.
The point-to-point rport will be in the discovery list. So at shutdown, it doesn't need to be separately logged out.
---
drivers/scsi/libfc/fc_disc.c | 8 -------- drivers/scsi/libfc/fc_lport.c | 14 ++++++-------- drivers/scsi/libfc/fc_rport.c | 11 +++++++++-- 3 files changed, 15 insertions(+), 18 deletions(-)
drivers/scsi/libfc/fc_disc.c +0 -8
@@ -115,9 +115,6 @@ static void fc_disc_rport_callback(struct fc_lport *lport,case RPORT_EV_LOGO :case RPORT_EV_FAILED :case RPORT_EV_STOP : -mutex_lock (&disc->disc_mutex); -list_del (&rdata->peers); -mutex_unlock (&disc->disc_mutex);break ;default :break ;
@@ -385,9 +382,6 @@ static int fc_disc_new_target(struct fc_disc *disc, rdata = lport->tt.rport_create (lport, ids);if (!rdata) error = -ENOMEM ; -else -list_add_tail (&rdata->peers, - &disc->rports); } }if (rdata) {
@@ -562,7 +556,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create (lport, &ids);if (rdata) { rdata->ops = &fc_disc_rport_ops; -list_add_tail (&rdata->peers, &disc->rports); lport->tt.rport_login (rdata); }else printk(KERN_WARNING "libfc: Failed to allocate "
@@ -709,7 +702,6 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp)if (rdata) { rdata->ops = &fc_disc_rport_ops;kfree (dp); -list_add_tail (&rdata->peers, &disc->rports); lport->tt.rport_login (rdata); }return ;
drivers/scsi/libfc/fc_lport.c +6 -8
@@ -205,12 +205,11 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, ids.node_name = remote_wwnn; ids.roles =FC_RPORT_ROLE_UNKNOWN ; -if (lport->ptp_rp) { +mutex_lock (&lport->disc.disc_mutex); +if (lport->ptp_rp) lport->tt.rport_logoff (lport->ptp_rp); - lport->ptp_rp =NULL ; - } - lport->ptp_rp = lport->tt.rport_create (lport, &ids); +mutex_unlock (&lport->disc.disc_mutex); lport->tt.rport_login (lport->ptp_rp);
@@ -931,10 +930,7 @@ static void fc_lport_reset_locked(struct fc_lport *lport)if (lport->dns_rp) lport->tt.rport_logoff (lport->dns_rp); -if (lport->ptp_rp) { - lport->tt.rport_logoff (lport->ptp_rp); - lport->ptp_rp =NULL ; - } + lport->ptp_rp =NULL ; lport->tt.disc_stop (lport);
@@ -1304,7 +1300,9 @@ static void fc_lport_enter_dns(struct fc_lport *lport)fc_lport_state_enter (lport,LPORT_ST_DNS ); +mutex_lock (&lport->disc.disc_mutex); rdata = lport->tt.rport_create (lport, &ids); +mutex_unlock (&lport->disc.disc_mutex);if (!rdata) goto err;
drivers/scsi/libfc/fc_rport.c +9 -2
@@ -91,8 +91,7 @@ static const char *fc_rport_state_names[] = {* @lport: local port. * @ids: remote port identifiers. * -* Locking note: this may be called without locks held, but -* is usually called from discovery with the disc_mutex held. +* Locking note: must be called with the disc_mutex held. */ static struct fc_rport_priv *fc_rport_create (struct fc_lport *lport,struct fc_rport_identifiers *ids)
@@ -115,6 +114,8 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, rdata->maxframe_size =FC_MIN_MAX_PAYLOAD ;INIT_DELAYED_WORK (&rdata->retry_work, fc_rport_timeout);INIT_WORK (&rdata->event_work, fc_rport_work); +if (ids->port_id !=FC_FID_DIR_SERV ) +list_add (&rdata->peers, &lport->disc.rports);return rdata; }
@@ -258,6 +259,12 @@ static void fc_rport_work(struct work_struct *work) port_id = rdata->ids.port_id;mutex_unlock (&rdata->rp_mutex); +if (port_id !=FC_FID_DIR_SERV ) { +mutex_lock (&lport->disc.disc_mutex); +list_del (&rdata->peers); +mutex_unlock (&lport->disc.disc_mutex); + } +if (rport_ops->event_callback) {FC_RPORT_DBG (rdata,"callback ev %d\n" , event); rport_ops->event_callback (lport, rdata, event);
PATCH 39/64 libfc: have rport_create do a lookup for pre-existing rports first
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
For future discovery patches, change rport_create to return a previously created rport_priv that has the FC_ID as long as it isn't in deleted state.
---
drivers/scsi/libfc/fc_disc.c | 9 +++------ drivers/scsi/libfc/fc_rport.c | 4 ++++ 2 files changed, 7 insertions(+), 6 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -6
@@ -377,12 +377,9 @@ static int fc_disc_new_target(struct fc_disc *disc, ids->port_id != fc_host_port_id(lport->host) && ids->port_name != lport->wwpn) {if (!rdata) { - rdata = lport->tt.rport_lookup (lport, ids->port_id); -if (!rdata) { - rdata = lport->tt.rport_create (lport, ids); -if (!rdata) - error = -ENOMEM ; - } + rdata = lport->tt.rport_create (lport, ids); +if (!rdata) + error = -ENOMEM ; }if (rdata) { rdata->ops = &fc_disc_rport_ops;
drivers/scsi/libfc/fc_rport.c +4 -0
@@ -98,6 +98,10 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, {struct fc_rport_priv *rdata; + rdata = lport->tt.rport_lookup (lport, ids->port_id); +if (rdata) +return rdata; + rdata =kzalloc (sizeof (*rdata),GFP_KERNEL );if (!rdata)return NULL ;
PATCH 40/64 libfc: change to make remote port callback optional
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Since the rport list maintenance is now done in the rport module, the callback (and ops) are usually not necessary.
Allow rdata->ops to be left NULL if nothing needs
to be done in an event callback.
---
drivers/scsi/libfc/fc_disc.c | 45 +++-------------------------------------- drivers/scsi/libfc/fc_rport.c | 4 ++-- 2 files changed, 5 insertions(+), 44 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -42
@@ -92,37 +92,6 @@ void fc_disc_stop_rports(struct fc_disc *disc) }/** -* fc_disc_rport_callback() - Event handler for rport events -* @lport: The lport which is receiving the event -* @rdata: private remote port data -* @event: The event that occured -* -* Locking Note: The rport lock should not be held when calling -* this function. -*/ -static void fc_disc_rport_callback (struct fc_lport *lport, -struct fc_rport_priv *rdata, -enum fc_rport_event event) -{ -struct fc_disc *disc = &lport->disc; - -FC_DISC_DBG (disc,"Received a %d event for port (%6x)\n" , event, - rdata->ids.port_id); - -switch (event) { -case RPORT_EV_READY : -break ; -case RPORT_EV_LOGO : -case RPORT_EV_FAILED : -case RPORT_EV_STOP : -break ; -default : -break ; - } - -} - -/** * fc_disc_recv_rscn_req() - Handle Registered State Change Notification (RSCN) * @sp: Current sequence of the RSCN exchange * @fp: RSCN Frame
@@ -334,10 +303,6 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,mutex_unlock (&disc->disc_mutex); } -static struct fc_rport_operations fc_disc_rport_ops = { - .event_callback = fc_disc_rport_callback, -}; -/** * fc_disc_new_target() - Handle new target found by discovery * @lport: FC local port
@@ -381,10 +346,8 @@ static int fc_disc_new_target(struct fc_disc *disc,if (!rdata) error = -ENOMEM ; } -if (rdata) { - rdata->ops = &fc_disc_rport_ops; +if (rdata) lport->tt.rport_login (rdata); - } }return error; }
@@ -551,10 +514,9 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)if (ids.port_id !=fc_host_port_id (lport->host) && ids.port_name != lport->wwpn) { rdata = lport->tt.rport_create (lport, &ids); -if (rdata) { - rdata->ops = &fc_disc_rport_ops; +if (rdata) lport->tt.rport_login (rdata); - }else +else printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n" , ids.port_id);
@@ -697,7 +659,6 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) rdata = lport->tt.rport_create (lport, &dp->ids);if (rdata) { - rdata->ops = &fc_disc_rport_ops;kfree (dp); lport->tt.rport_login (rdata); }
drivers/scsi/libfc/fc_rport.c +2 -2
@@ -250,7 +250,7 @@ static void fc_rport_work(struct work_struct *work) rp->r_a_tov = rdata->r_a_tov;mutex_unlock (&rdata->rp_mutex); -if (rport_ops->event_callback) { +if (rport_ops && rport_ops->event_callback) {FC_RPORT_DBG (rdata,"callback ev %d\n" , event); rport_ops->event_callback (lport, rdata, event); }
@@ -269,7 +269,7 @@ static void fc_rport_work(struct work_struct *work)mutex_unlock (&lport->disc.disc_mutex); } -if (rport_ops->event_callback) { +if (rport_ops && rport_ops->event_callback) {FC_RPORT_DBG (rdata,"callback ev %d\n" , event); rport_ops->event_callback (lport, rdata, event); }
PATCH 41/64 libfc: move rport_lookup into fc_rport.c
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Move the libfc remote port lookup function into fc_rport.c. This seems like the best place for it.
---
drivers/scsi/libfc/fc_disc.c | 22 ---------------------- drivers/scsi/libfc/fc_rport.c | 20 ++++++++++++++++++++ 2 files changed, 20 insertions(+), 22 deletions(-)
drivers/scsi/libfc/fc_disc.c +0 -22
@@ -53,25 +53,6 @@ static void fc_disc_single(struct fc_disc *, struct fc_disc_port *);static void fc_disc_restart (struct fc_disc *);/** -* fc_disc_lookup_rport() - lookup a remote port by port_id -* @lport: Fibre Channel host port instance -* @port_id: remote port port_id to match -*/ -struct fc_rport_priv *fc_disc_lookup_rport (const struct fc_lport *lport, -u32 port_id) -{ -const struct fc_disc *disc = &lport->disc; -struct fc_rport_priv *rdata; - -list_for_each_entry (rdata, &disc->rports, peers) { -if (rdata->ids.port_id == port_id && - rdata->rp_state !=RPORT_ST_DELETE ) -return rdata; - } -return NULL ; -} - -/** * fc_disc_stop_rports() - delete all the remote ports associated with the lport * @disc: The discovery job to stop rports on *
@@ -714,9 +695,6 @@ int fc_disc_init(struct fc_lport *lport)if (!lport->tt.disc_recv_req) lport->tt.disc_recv_req = fc_disc_recv_req; -if (!lport->tt.rport_lookup) - lport->tt.rport_lookup = fc_disc_lookup_rport; - disc = &lport->disc;INIT_DELAYED_WORK (&disc->disc_work, fc_disc_timeout);mutex_init (&disc->disc_mutex);
drivers/scsi/libfc/fc_rport.c +20 -0
@@ -87,6 +87,23 @@ static const char *fc_rport_state_names[] = { };/** +* fc_rport_lookup() - lookup a remote port by port_id +* @lport: Fibre Channel host port instance +* @port_id: remote port port_id to match +*/ +static struct fc_rport_priv *fc_rport_lookup (const struct fc_lport *lport, +u32 port_id) +{ +struct fc_rport_priv *rdata; + +list_for_each_entry (rdata, &lport->disc.rports, peers) +if (rdata->ids.port_id == port_id && + rdata->rp_state !=RPORT_ST_DELETE ) +return rdata; +return NULL ; +} + +/** * fc_rport_create() - create remote port in INIT state. * @lport: local port. * @ids: remote port identifiers.
@@ -1292,6 +1309,9 @@ static void fc_rport_flush_queue(void)int fc_rport_init (struct fc_lport *lport) { +if (!lport->tt.rport_lookup) + lport->tt.rport_lookup = fc_rport_lookup; +if (!lport->tt.rport_create) lport->tt.rport_create = fc_rport_create;
PATCH 42/64 libfc: do not log off rports before or after discovery
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When receiving an RSCN, do not log off all rports. This is extremely disruptive. If, after the GPN_FT response, some rports haven't been listed, delete them.
Add field disc_id to structs fc_rport_priv and fc_disc. disc_id is an arbitrary serial number used to identify the rports found by the latest discovery. This eliminates the need to go through the rport list when restarting discovery.
---
drivers/scsi/libfc/fc_disc.c | 47 ++++++++++++++++++++++++++++++------------ include/scsi/libfc.h | 3 +++ 2 files changed, 37 insertions(+), 13 deletions(-)
drivers/scsi/libfc/fc_disc.c +34 -13
@@ -221,17 +221,19 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,*/ static void fc_disc_restart (struct fc_disc *disc) { -struct fc_rport_priv *rdata, *next; -struct fc_lport *lport = disc->lport; -FC_DISC_DBG (disc,"Restarting discovery\n" ); -list_for_each_entry_safe (rdata, next, &disc->rports, peers) - lport->tt.rport_logoff (rdata); - disc->requested =1 ; -if (!disc->pending) -fc_disc_gpn_ft_req (disc); +if (disc->pending) +return ; + +/* +* Advance disc_id. This is an arbitrary non-zero number that will +* match the value in the fc_rport_priv after discovery for all +* freshly-discovered remote ports. Avoid wrapping to zero. +*/ + disc->disc_id = (disc->disc_id +2 ) |1 ; +fc_disc_gpn_ft_req (disc); }/**
@@ -278,6 +280,7 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *, }kref_put (&rdata->kref, rdata->local_port->tt.rport_destroy); }else { + disc->disc_id = (disc->disc_id +2 ) |1 ;fc_disc_gpn_ft_req (disc);/* get ports by FC-4 type */ }
@@ -345,13 +348,30 @@ static int fc_disc_new_target(struct fc_disc *disc,static void fc_disc_done (struct fc_disc *disc,enum fc_disc_event event) {struct fc_lport *lport = disc->lport; +struct fc_rport_priv *rdata;FC_DISC_DBG (disc,"Discovery complete\n" ); -if (disc->requested) -fc_disc_gpn_ft_req (disc); -else - disc->pending =0 ; + disc->pending =0 ; +if (disc->requested) { +fc_disc_restart (disc); +return ; + } + +/* +* Go through all remote ports. If they were found in the latest +* discovery, reverify or log them in. Otherwise, log them out. +* Skip ports which were never discovered. These are the dNS port +* and ports which were created by PLOGI. +*/ +list_for_each_entry (rdata, &disc->rports, peers) { +if (!rdata->disc_id) +continue ; +if (rdata->disc_id == disc->disc_id) + lport->tt.rport_login (rdata); +else + lport->tt.rport_logoff (rdata); + }mutex_unlock (&disc->disc_mutex); disc->disc_callback (lport, event);
@@ -496,7 +516,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) ids.port_name != lport->wwpn) { rdata = lport->tt.rport_create (lport, &ids);if (rdata) - lport->tt.rport_login (rdata); + rdata->disc_id = disc->disc_id;else printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port "
@@ -640,6 +660,7 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) rdata = lport->tt.rport_create (lport, &dp->ids);if (rdata) { + rdata->disc_id = disc->disc_id;kfree (dp); lport->tt.rport_login (rdata); }
include/scsi/libfc.h +3 -0
@@ -202,6 +202,7 @@ struct fc_rport_libfc_priv {* @ids: remote port identifiers and roles * @flags: REC and RETRY supported flags * @max_seq: maximum number of concurrent sequences +* @disc_id: discovery identifier * @maxframe_size: maximum frame size * @retries: retry count in current state * @e_d_tov: error detect timeout value (in msec)
@@ -218,6 +219,7 @@ struct fc_rport_priv {struct fc_rport_identifiers ids;u16 flags;u16 max_seq; +u16 disc_id;u16 maxframe_size;unsigned int retries;unsigned int e_d_tov;
@@ -678,6 +680,7 @@ struct fc_disc {unsigned char requested;unsigned short seq_count;unsigned char buf_len; +u16 disc_id;void (*disc_callback)(struct fc_lport *,enum fc_disc_event );
PATCH 43/64 libfc: discovery restart sequence error fix
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When an RSCN is received during fabric discovery, it restarts. After the restart, disc->seq_count was incremented, so when the first frame was received, it was considered "out of sequence". That left the state disc->active, preventing further discoveries.
Change to advance the sequence count before parsing, so that it won't be changed after a potential restart.
---
drivers/scsi/libfc/fc_disc.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_disc.c +1 -2
@@ -629,11 +629,10 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, seq_cnt, disc->seq_count, fr_sof(fp), fr_eof(fp)); }if (buf) { + disc->seq_count++; error =fc_disc_gpn_ft_parse (disc, buf, len);if (error)fc_disc_error (disc, fp); -else - disc->seq_count++; }fc_frame_free (fp);
PATCH 44/64 libfc: rearrange code in fc_disc_gpn_ft_resp()
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Code cleanup for fc_disc_gpn_ft_resp().
Some of the fc_disc.c code was poorly formatted. For example, some lines in fc_disc.c were unnecessarily truncated and the buf variable could be eliminated.
Also moved the increment of seq_count into fc_disc_gpn_ft_parse(), to avoid doing it separately before each call.
---
drivers/scsi/libfc/fc_disc.c | 28 ++++++++++++---------------- 1 files changed, 12 insertions(+), 16 deletions(-)
drivers/scsi/libfc/fc_disc.c +12 -16
@@ -469,6 +469,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)struct fc_rport_priv *rdata; lport = disc->lport; + disc->seq_count++;/* * Handle partial name record left over from previous call.
@@ -582,10 +583,10 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,struct fc_disc *disc = disc_arg;struct fc_ct_hdr *cp;struct fc_frame_header *fh; +enum fc_disc_event event =DISC_EV_NONE ;unsigned int seq_cnt; -void *buf =NULL ;unsigned int len; -int error; +int error =0 ;mutex_lock (&disc->disc_mutex);FC_DISC_DBG (disc,"Received a GPN_FT response\n" );
@@ -600,8 +601,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, fh =fc_frame_header_get (fp); len =fr_len (fp) -sizeof (*fh); seq_cnt =ntohs (fh->fh_seq_cnt); -if (fr_sof (fp) ==FC_SOF_I3 && seq_cnt ==0 && - disc->seq_count ==0 ) { +if (fr_sof (fp) ==FC_SOF_I3 && seq_cnt ==0 && disc->seq_count ==0 ) { cp =fc_frame_payload_get (fp,sizeof (*cp));if (!cp) { FC_DISC_DBG(disc, "GPN_FT response too short, len %d\n",
@@ -609,33 +609,29 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, }else if (ntohs (cp->ct_cmd) ==FC_FS_ACC ) {/* Accepted, parse the response. */ - buf = cp +1 ; len -=sizeof (*cp); + error =fc_disc_gpn_ft_parse (disc, cp +1 , len); }else if (ntohs (cp->ct_cmd) ==FC_FS_RJT ) {FC_DISC_DBG (disc,"GPN_FT rejected reason %x exp %x " "(check zoning)\n" , cp->ct_reason, cp->ct_explan); -fc_disc_done (disc,DISC_EV_FAILED ); + event =DISC_EV_FAILED ; }else {FC_DISC_DBG (disc,"GPN_FT unexpected response code " "%x\n" ,ntohs (cp->ct_cmd)); } - }else if (fr_sof (fp) ==FC_SOF_N3 && - seq_cnt == disc->seq_count) { - buf = fh +1 ; + }else if (fr_sof (fp) ==FC_SOF_N3 && seq_cnt == disc->seq_count) { + error =fc_disc_gpn_ft_parse (disc, fh +1 , len); }else {FC_DISC_DBG (disc,"GPN_FT unexpected frame - out of sequence? " "seq_cnt %x expected %x sof %x eof %x\n" , seq_cnt, disc->seq_count,fr_sof (fp),fr_eof (fp)); } -if (buf) { - disc->seq_count++; - error =fc_disc_gpn_ft_parse (disc, buf, len); -if (error) -fc_disc_error (disc, fp); - } +if (error) +fc_disc_error (disc, fp); +else if (event !=DISC_EV_NONE ) +fc_disc_done (disc, event);fc_frame_free (fp); -mutex_unlock (&disc->disc_mutex); }
PATCH 45/64 libfc: handle discovery failure more correctly.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Abhijeet Joglekar wrote: "In gpn_ft_resp, if the payload is short, or unexpected response or out of sequence frame, then we just return and do nothing. We should either enter fc_disc_done() with DISC_EV_FAIL which will then restart any queued discovery requests or call lport module which will reset local port, or we should call fc_disc_error() so that the gpn_ft is retried.
The situation as is causes discovery to remain pending and never get restarted, in these rare cases. We saw this due to a coding bug in fc_disc before. The only ways it could happen would be bugs, packet corruption or an FC fabric problem.
Change it to fail discovery. The local port will restart discovery, although it probably should just give up until the next link flap.
---
drivers/scsi/libfc/fc_disc.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -0
@@ -606,6 +606,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,if (!cp) {FC_DISC_DBG (disc,"GPN_FT response too short, len %d\n" ,fr_len (fp)); + event =DISC_EV_FAILED ; }else if (ntohs (cp->ct_cmd) ==FC_FS_ACC ) {/* Accepted, parse the response. */
@@ -619,6 +620,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, }else {FC_DISC_DBG (disc,"GPN_FT unexpected response code " "%x\n" ,ntohs (cp->ct_cmd)); + event =DISC_EV_FAILED ; } }else if (fr_sof (fp) ==FC_SOF_N3 && seq_cnt == disc->seq_count) { error =fc_disc_gpn_ft_parse (disc, fh +1 , len);
@@ -626,6 +628,7 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,FC_DISC_DBG (disc,"GPN_FT unexpected frame - out of sequence? " "seq_cnt %x expected %x sof %x eof %x\n" , seq_cnt, disc->seq_count,fr_sof (fp),fr_eof (fp)); + event =DISC_EV_FAILED ; }if (error)fc_disc_error (disc, fp);
PATCH 46/64 libfc: fix: empty zone causes endless discovery retries.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
On some switches, an empty zone causes GPN_FT to be rejected with reason 9 (unable) explanation 7 (FC-4 types not registered), which causes discovery to be retried endlessly. Treat this as just an empty response and consider discovery complete.
---
drivers/scsi/libfc/fc_disc.c | 3 +++ include/scsi/fc/fc_gs.h | 1 + 2 files changed, 4 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -0
@@ -617,6 +617,9 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp,"(check zoning)\n" , cp->ct_reason, cp->ct_explan); event =DISC_EV_FAILED ; +if (cp->ct_reason ==FC_FS_RJT_UNABL && + cp->ct_explan ==FC_FS_EXP_FTNR ) + event =DISC_EV_SUCCESS ; }else {FC_DISC_DBG (disc,"GPN_FT unexpected response code " "%x\n" ,ntohs (cp->ct_cmd));
include/scsi/fc/fc_gs.h +1 -0
@@ -87,6 +87,7 @@ enum fc_ct_explan {FC_FS_EXP_PNAM =0x02 ,/* port name not registered */ FC_FS_EXP_NNAM =0x03 ,/* node name not registered */ FC_FS_EXP_COS =0x04 ,/* class of service not registered */ + FC_FS_EXP_FTNR = 0x07, /* FC-4 types not registered */ /* definitions not complete */ };
PATCH 47/64 libfc: discovery retry should clear pending first.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Currently fc_disc_timeout() restarts discovery only if it is not pending. When the timer is scheduled, the discovery is left pending, so the timeout never restarts it.
Fix by not checking for pending in the timeout handler.
If discovery is stopped and restarted in the meantime, the timeout will be canceled.
Also, when a new discovery is started, the retry count wasn't cleared.
---
drivers/scsi/libfc/fc_disc.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_disc.c +2 -2
@@ -233,6 +233,7 @@ static void fc_disc_restart(struct fc_disc *disc)* freshly-discovered remote ports. Avoid wrapping to zero. */ disc->disc_id = (disc->disc_id +2 ) |1 ; + disc->retry_count =0 ;fc_disc_gpn_ft_req (disc); }
@@ -563,8 +564,7 @@ static void fc_disc_timeout(struct work_struct *work) struct fc_disc, disc_work.work);mutex_lock (&disc->disc_mutex); -if (disc->requested && !disc->pending) -fc_disc_gpn_ft_req (disc); +fc_disc_gpn_ft_req (disc);mutex_unlock (&disc->disc_mutex); }
PATCH 48/64 libfc: discovery gpn_ft parse bug
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
In fc_disc_gpn_ft_parse(), after fc_disc_done() is called, the disc state is changed by setting buf_len = 0. This is wrong
since the discovery may have restarted. Instead, return
after calling fc_disc_done.
Also, return an error on memory allocation failure.
---
drivers/scsi/libfc/fc_disc.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-)
drivers/scsi/libfc/fc_disc.c +4 -3
@@ -479,6 +479,7 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) plen = len; np = (struct fc_gpn_ft_resp *)bp; tlen = disc->buf_len; + disc->buf_len =0 ;if (tlen) {WARN_ON (tlen >=sizeof (*np)); plen =sizeof (*np) - tlen;
@@ -519,10 +520,12 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len) rdata = lport->tt.rport_create (lport, &ids);if (rdata) rdata->disc_id = disc->disc_id; -else +else {printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n" , ids.port_id); + error = -ENOMEM ; + } }if (np->fp_flags &FC_NS_FID_LAST ) {
@@ -546,8 +549,6 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)memcpy (&disc->partial_buf, np, len); } disc->buf_len = (unsigned char ) len; - }else { - disc->buf_len =0 ; }return error; }
PATCH 49/64 libfc: clean up point-to-point discovery code.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The discovery code had a special-case for the point-to-point mode, which used a bunch of code that wasn't really needed.
Now that rport_create adds the rport to the discovery list, completely skip discovery for the point-to-point case.
---
drivers/scsi/libfc/fc_disc.c | 84 +---------------------------------------- drivers/scsi/libfc/fc_lport.c | 13 +----- 2 files changed, 4 insertions(+), 93 deletions(-)
drivers/scsi/libfc/fc_disc.c +2 -82
@@ -45,8 +45,6 @@static void fc_disc_gpn_ft_req (struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *); -static int fc_disc_new_target (struct fc_disc *,struct fc_rport_priv *, -struct fc_rport_identifiers *);static void fc_disc_done (struct fc_disc *,enum fc_disc_event );static void fc_disc_timeout (struct work_struct *);static void fc_disc_single (struct fc_disc *,struct fc_disc_port *);
@@ -240,14 +238,12 @@ static void fc_disc_restart(struct fc_disc *disc)/** * fc_disc_start() - Fibre Channel Target discovery * @lport: FC local port -* -* Returns non-zero if discovery cannot be started. +* @disc_callback: function to be called when discovery is complete */ static void fc_disc_start (void (*disc_callback)(struct fc_lport *,enum fc_disc_event ),struct fc_lport *lport) { -struct fc_rport_priv *rdata;struct fc_disc *disc = &lport->disc;/*
@@ -256,88 +252,12 @@ static void fc_disc_start(void (*disc_callback)(struct fc_lport *,* and send the GPN_FT request. */ mutex_lock (&disc->disc_mutex); - disc->disc_callback = disc_callback; - -/* -* If not ready, or already running discovery, just set request flag. -*/ - disc->requested =1 ; - -if (disc->pending) { -mutex_unlock (&disc->disc_mutex); -return ; - } - -/* -* Handle point-to-point mode as a simple discovery -* of the remote port. Yucky, yucky, yuck, yuck! -*/ - rdata = disc->lport->ptp_rp; -if (rdata) { -kref_get (&rdata->kref); -if (!fc_disc_new_target (disc, rdata, &rdata->ids)) { -fc_disc_done (disc,DISC_EV_SUCCESS ); - } -kref_put (&rdata->kref, rdata->local_port->tt.rport_destroy); - }else { - disc->disc_id = (disc->disc_id +2 ) |1 ; -fc_disc_gpn_ft_req (disc);/* get ports by FC-4 type */ - } - +fc_disc_restart (disc);mutex_unlock (&disc->disc_mutex); }/** -* fc_disc_new_target() - Handle new target found by discovery -* @lport: FC local port -* @rdata: The previous FC remote port priv (NULL if new remote port) -* @ids: Identifiers for the new FC remote port -* -* Locking Note: This function expects that the disc_mutex is locked -* before it is called. -*/ -static int fc_disc_new_target (struct fc_disc *disc, -struct fc_rport_priv *rdata, -struct fc_rport_identifiers *ids) -{ -struct fc_lport *lport = disc->lport; -int error =0 ; - -if (rdata && ids->port_name) { -if (rdata->ids.port_name ==-1 ) { -/* -* Set WWN and fall through to notify of create. -*/ - rdata->ids.port_name = ids->port_name; - rdata->ids.node_name = ids->node_name; - }else if (rdata->ids.port_name != ids->port_name) { -/* -* This is a new port with the same FCID as -* a previously-discovered port. Presumably the old -* port logged out and a new port logged in and was -* assigned the same FCID. This should be rare. -* Delete the old one and fall thru to re-create. -*/ - lport->tt.rport_logoff (rdata); - rdata =NULL ; - } - } -if (((ids->port_name !=-1 ) || (ids->port_id !=-1 )) && - ids->port_id !=fc_host_port_id (lport->host) && - ids->port_name != lport->wwpn) { -if (!rdata) { - rdata = lport->tt.rport_create (lport, ids); -if (!rdata) - error = -ENOMEM ; - } -if (rdata) - lport->tt.rport_login (rdata); - } -return error; -} - -/** * fc_disc_done() - Discovery has been completed * @disc: FC discovery context * @event: discovery completion status
drivers/scsi/libfc/fc_lport.c +2 -11
@@ -708,7 +708,8 @@ static void fc_lport_enter_ready(struct fc_lport *lport)fc_lport_state_enter (lport,LPORT_ST_READY ); - lport->tt.disc_start (fc_lport_disc_callback, lport); +if (!lport->ptp_rp) + lport->tt.disc_start (fc_lport_disc_callback, lport); }/**
@@ -794,8 +795,6 @@ static void fc_lport_recv_flogi_req(struct fc_seq *sp_in,fc_lport_ptp_setup (lport, remote_fid, remote_wwpn,get_unaligned_be64 (&flp->fl_wwnn)); - lport->tt.disc_start (fc_lport_disc_callback, lport); - out: sp =fr_seq (rx_fp);fc_frame_free (rx_fp);
@@ -1512,14 +1511,6 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,fc_lport_enter_dns (lport); } } - -if (flp) { - csp_flags =ntohs (flp->fl_csp.sp_features); -if ((csp_flags &FC_SP_FT_FPORT ) ==0 ) { - lport->tt.disc_start (fc_lport_disc_callback, - lport); - } - } }else {FC_LPORT_DBG (lport,"Bad FLOGI response\n" ); }
PATCH 50/64 libfc: don't do discovery before callback is set
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
It's possible to "restart" discovery before it was started if an RSCN is received early enough. We were jumping to 0 due to the disc_callback function pointer not getting set.
Don't restart discovery if disc_callback is NULL.
---
drivers/scsi/libfc/fc_disc.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_disc.c +3 -0
@@ -219,6 +219,9 @@ static void fc_disc_recv_req(struct fc_seq *sp, struct fc_frame *fp,*/ static void fc_disc_restart (struct fc_disc *disc) { +if (!disc->disc_callback) +return ; +FC_DISC_DBG (disc,"Restarting discovery\n" ); disc->requested =1 ;
PATCH 51/64 libfc: Initialize fc_rport_identifiers inside fc_rport_create
In reply to Robert LoveCurrently these values are initialized by the callers. This was exposed by a later patch that adds PLOGI request support. The patch failed to initialize the new remote port's roles and it caused problems. This patch has the rport_create routine initialize the identifiers and then the callers can override them with real values.
---
drivers/scsi/libfc/fc_disc.c | 20 ++++++++------------ drivers/scsi/libfc/fc_lport.c | 19 ++++--------------- drivers/scsi/libfc/fc_rport.c | 18 +++++++++++------- include/scsi/libfc.h | 17 +++++++++-------- 4 files changed, 32 insertions(+), 42 deletions(-)
drivers/scsi/libfc/fc_disc.c +8 -12
@@ -137,10 +137,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,break ; } dp->lp = lport; - dp->ids.port_id =ntoh24 (pp->rscn_fid); - dp->ids.port_name =-1 ; - dp->ids.node_name =-1 ; - dp->ids.roles =FC_RPORT_ROLE_UNKNOWN ; + dp->port_id =ntoh24 (pp->rscn_fid);list_add_tail (&dp->peers, &disc_ports);break ;case ELS_ADDR_FMT_AREA :
@@ -162,7 +159,7 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, redisc, lport->state, disc->pending);list_for_each_entry_safe (dp, next, &disc_ports, peers) {list_del (&dp->peers); - rdata = lport->tt.rport_lookup (lport, dp->ids.port_id); + rdata = lport->tt.rport_lookup (lport, dp->port_id);if (rdata) { lport->tt.rport_logoff (rdata); }
@@ -435,15 +432,14 @@ static int fc_disc_gpn_ft_parse(struct fc_disc *disc, void *buf, size_t len)while (plen >=sizeof (*np)) { ids.port_id =ntoh24 (np->fp_fid); ids.port_name =ntohll (np->fp_wwpn); - ids.node_name =-1 ; - ids.roles =FC_RPORT_ROLE_UNKNOWN ;if (ids.port_id !=fc_host_port_id (lport->host) && ids.port_name != lport->wwpn) { - rdata = lport->tt.rport_create (lport, &ids); -if (rdata) + rdata = lport->tt.rport_create (lport, ids.port_id); +if (rdata) { + rdata->ids.port_name = ids.port_name; rdata->disc_id = disc->disc_id; -else { + }else {printk (KERN_WARNING "libfc: Failed to allocate " "memory for the newly discovered port " "(%6x)\n" , ids.port_id);
@@ -580,10 +576,10 @@ static void fc_disc_single(struct fc_disc *disc, struct fc_disc_port *dp) lport = disc->lport; -if (dp->ids.port_id ==fc_host_port_id (lport->host)) +if (dp->port_id ==fc_host_port_id (lport->host)) goto out; - rdata = lport->tt.rport_create (lport, &dp->ids); + rdata = lport->tt.rport_create (lport, dp->port_id);if (rdata) { rdata->disc_id = disc->disc_id;kfree (dp);
drivers/scsi/libfc/fc_lport.c +4 -15
@@ -198,17 +198,12 @@ static void fc_lport_ptp_setup(struct fc_lport *lport, u32 remote_fid, u64 remote_wwpn, u64 remote_wwnn) { - struct fc_rport_identifiers ids; - - ids.port_id = remote_fid; - ids.port_name = remote_wwpn; - ids.node_name = remote_wwnn; - ids.roles =FC_RPORT_ROLE_UNKNOWN ; - mutex_lock(&lport->disc.disc_mutex);if (lport->ptp_rp) lport->tt.rport_logoff (lport->ptp_rp); - lport->ptp_rp = lport->tt.rport_create (lport, &ids); + lport->ptp_rp = lport->tt.rport_create (lport, remote_fid); + lport->ptp_rp->ids.port_name = remote_wwpn; + lport->ptp_rp->ids.node_name = remote_wwnn;mutex_unlock (&lport->disc.disc_mutex); lport->tt.rport_login (lport->ptp_rp);
@@ -1287,12 +1282,6 @@ static struct fc_rport_operations fc_lport_rport_ops = {static void fc_lport_enter_dns (struct fc_lport *lport) {struct fc_rport_priv *rdata; -struct fc_rport_identifiers ids; - - ids.port_id =FC_FID_DIR_SERV ; - ids.port_name =-1 ; - ids.node_name =-1 ; - ids.roles =FC_RPORT_ROLE_UNKNOWN ;FC_LPORT_DBG (lport,"Entered DNS state from %s state\n" ,fc_lport_state (lport));
@@ -1300,7 +1289,7 @@ static void fc_lport_enter_dns(struct fc_lport *lport)fc_lport_state_enter (lport,LPORT_ST_DNS );mutex_lock (&lport->disc.disc_mutex); - rdata = lport->tt.rport_create (lport, &ids); + rdata = lport->tt.rport_create (lport,FC_FID_DIR_SERV );mutex_unlock (&lport->disc.disc_mutex);if (!rdata) goto err;
drivers/scsi/libfc/fc_rport.c +11 -7
@@ -104,18 +104,18 @@ static struct fc_rport_priv *fc_rport_lookup(const struct fc_lport *lport, }/** -* fc_rport_create() - create remote port in INIT state. -* @lport: local port. -* @ids: remote port identifiers. +* fc_rport_create() - Create a new remote port +* @lport: The local port that the new remote port is for +* @port_id: The port ID for the new remote port * * Locking note: must be called with the disc_mutex held. */ static struct fc_rport_priv *fc_rport_create (struct fc_lport *lport, -struct fc_rport_identifiers *ids) +u32 port_id) {struct fc_rport_priv *rdata; - rdata = lport->tt.rport_lookup (lport, ids->port_id); + rdata = lport->tt.rport_lookup (lport, port_id);if (rdata)return rdata;
@@ -123,7 +123,11 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport,if (!rdata)return NULL ; - rdata->ids = *ids; + rdata->ids.node_name =-1 ; + rdata->ids.port_name =-1 ; + rdata->ids.port_id = port_id; + rdata->ids.roles =FC_RPORT_ROLE_UNKNOWN ; +kref_init (&rdata->kref);mutex_init (&rdata->rp_mutex); rdata->local_port = lport;
@@ -135,7 +139,7 @@ static struct fc_rport_priv *fc_rport_create(struct fc_lport *lport, rdata->maxframe_size =FC_MIN_MAX_PAYLOAD ;INIT_DELAYED_WORK (&rdata->retry_work, fc_rport_timeout);INIT_WORK (&rdata->event_work, fc_rport_work); -if (ids->port_id !=FC_FID_DIR_SERV ) +if (port_id !=FC_FID_DIR_SERV )list_add (&rdata->peers, &lport->disc.rports);return rdata; }
include/scsi/libfc.h +9 -8
@@ -148,16 +148,16 @@ enum fc_rport_state {/** * struct fc_disc_port - temporary discovery port to hold rport identifiers -* @lp: Fibre Channel host port instance -* @peers: node for list management during discovery and RSCN processing -* @ids: identifiers structure to pass to fc_remote_port_add() -* @rport_work: work struct for starting the rport state machine +* @lp: Fibre Channel host port instance +* @peers: Node for list management during discovery and RSCN processing +* @rport_work: Work struct for starting the rport state machine +* @port_id: Port ID of the discovered port */ struct fc_disc_port {struct fc_lport *lp;struct list_head peers; -struct fc_rport_identifiers ids;struct work_struct rport_work; +u32 port_id; };enum fc_rport_event {
@@ -565,10 +565,11 @@ struct libfc_function_template {int (*lport_reset)(struct fc_lport *);/* -* Create a remote port +* Create a remote port with a given port ID +* +* STATUS: OPTIONAL */ -struct fc_rport_priv *(*rport_create)(struct fc_lport *, -struct fc_rport_identifiers *); +struct fc_rport_priv *(*rport_create)(struct fc_lport *,u32 );/* * Initiates the RP state machine. It is called from the LP module.
PATCH 52/64 libfc: Always reset remote port roles when receiving PRLI
In reply to Robert LoveDon't trust previous roles, reset them when we receive a PRLI.
---
drivers/scsi/libfc/fc_rport.c | 6 ++++++ 1 files changed, 6 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_rport.c +6 -0
@@ -666,6 +666,9 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, goto err; } +/* reinitialize remote port roles */ + rdata->ids.roles =FC_RPORT_ROLE_UNKNOWN ; + op =fc_frame_payload_op (fp);if (op ==ELS_LS_ACC ) { pp =fc_frame_payload_get (fp,sizeof (*pp));
@@ -1173,6 +1176,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata, pp->prli.prli_len =htons (len); len -=sizeof (struct fc_els_prli ); +/* reinitialize remote port roles */ + rdata->ids.roles =FC_RPORT_ROLE_UNKNOWN ; +/* * Go through all the service parameter pages and build * response. If plen indicates longer SPP than standard,
PATCH 53/64 libfc: move remote port lookup for ELS requests into fc_rport.c.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
This moves the remote port lookup for incoming ELS requests into fc_rport.c, in preparation for handing PLOGI and LOGO from unknown rports.
This changes the arg to rport_recv_req from an rdata to an lport.
---
drivers/scsi/libfc/fc_lport.c | 30 +--------------- drivers/scsi/libfc/fc_rport.c | 78 ++++++++++++++++++++++------------------- include/scsi/libfc.h | 2 + 3 files changed, 44 insertions(+), 66 deletions(-)
drivers/scsi/libfc/fc_lport.c +2 -28
@@ -812,10 +812,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp, {struct fc_frame_header *fh =fc_frame_header_get (fp);void (*recv) (struct fc_seq *,struct fc_frame *,struct fc_lport *); -struct fc_rport_priv *rdata; -u32 s_id; -u32 d_id; -struct fc_seq_els_data rjt_data;mutex_lock (&lport->lp_mutex);
@@ -831,7 +827,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,/* * Check opcode. */ - recv =NULL ; + recv = lport->tt.rport_recv_req;switch (fc_frame_payload_op (fp)) {case ELS_FLOGI : recv = fc_lport_recv_flogi_req;
@@ -858,29 +854,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,break ; } -if (recv) -recv (sp, fp, lport); -else { -/* -* Find session. -* If this is a new incoming PLOGI, we won't find it. -*/ - s_id =ntoh24 (fh->fh_s_id); - d_id =ntoh24 (fh->fh_d_id); - - rdata = lport->tt.rport_lookup (lport, s_id); -if (rdata) - lport->tt.rport_recv_req (sp, fp, rdata); -else { - rjt_data.fp =NULL ; - rjt_data.reason =ELS_RJT_UNAB ; - rjt_data.explan =ELS_EXPL_NONE ; - lport->tt.seq_els_rsp_send (sp, -ELS_LS_RJT , - &rjt_data); -fc_frame_free (fp); - } - } +recv (sp, fp, lport); }else {FC_LPORT_DBG (lport,"dropping invalid frame (eof %x)\n" ,fr_eof (fp));
drivers/scsi/libfc/fc_rport.c +41 -37
98 lines not on this page · raw message
include/scsi/libfc.h +1 -1
@@ -598,7 +598,7 @@ struct libfc_function_template {* STATUS: OPTIONAL */ void (*rport_recv_req)(struct fc_seq *,struct fc_frame *, -struct fc_rport_priv *); +struct fc_lport *);/* * lookup an rport by it's port ID.
PATCH 54/64 libfc: fix: rport_recv_req needs disc_mutex when calling rport_lookup
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The rport_lookup function must be called while holding the disc_mutex. Otherwise, the rdata could be deleted just after that by another thread.
All callers now check the state after grabbing the rdata rp_mutex. Even though rport_lookup skips ports in DELETE state, it does that without holding the rdata rp_mutex, so that the state may change.
---
drivers/scsi/libfc/fc_rport.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
drivers/scsi/libfc/fc_rport.c +3 -0
@@ -932,14 +932,17 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, fh =fc_frame_header_get (fp); s_id =ntoh24 (fh->fh_s_id); +mutex_lock (&lport->disc.disc_mutex); rdata = lport->tt.rport_lookup (lport, s_id);if (!rdata) { +mutex_unlock (&lport->disc.disc_mutex); els_data.reason =ELS_RJT_UNAB ; lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &els_data);fc_frame_free (fp);return ; }mutex_lock (&rdata->rp_mutex); +mutex_unlock (&lport->disc.disc_mutex); op =fc_frame_payload_op (fp);switch (op) {
PATCH 55/64 libfc: improve debug messages for ELS response handlers
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
Improve lport and rport debug messages to indicate whether the response is LS_ACC, LS_RJT, closed, or timeout.
---
drivers/scsi/libfc/fc_elsct.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 20 ++++++++++---------- drivers/scsi/libfc/fc_rport.c | 8 ++++---- include/scsi/libfc.h | 5 +++++ 4 files changed, 57 insertions(+), 14 deletions(-)
drivers/scsi/libfc/fc_elsct.c +38 -0
@@ -70,3 +70,41 @@ int fc_elsct_init(struct fc_lport *lport)return 0 ; }EXPORT_SYMBOL (fc_elsct_init); + +/** +* fc_els_resp_type() - return string describing ELS response for debug. +* @fp: frame pointer with possible error code. +*/ +const char *fc_els_resp_type (struct fc_frame *fp) +{ +const char *msg; +if (IS_ERR (fp)) { +switch (-PTR_ERR (fp)) { +case FC_NO_ERR : + msg ="response no error" ; +break ; +case FC_EX_TIMEOUT : + msg ="response timeout" ; +break ; +case FC_EX_CLOSED : + msg ="response closed" ; +break ; +default : + msg ="response unknown error" ; +break ; + } + }else { +switch (fc_frame_payload_op (fp)) { +case ELS_LS_ACC : + msg ="accept" ; +break ; +case ELS_LS_RJT : + msg ="reject" ; +break ; +default : + msg ="response unknown ELS" ; +break ; + } + } +return msg; +}
drivers/scsi/libfc/fc_lport.c +10 -10
@@ -1006,13 +1006,13 @@ static void fc_lport_rft_id_resp(struct fc_seq *sp, struct fc_frame *fp,struct fc_frame_header *fh;struct fc_ct_hdr *ct; +FC_LPORT_DBG (lport,"Received a RFT_ID %s\n" ,fc_els_resp_type (fp)); +if (fp ==ERR_PTR (-FC_EX_CLOSED ))return ;mutex_lock (&lport->lp_mutex); -FC_LPORT_DBG (lport,"Received a RFT_ID response\n" ); -if (lport->state !=LPORT_ST_RFT_ID ) {FC_LPORT_DBG (lport,"Received a RFT_ID response, but in state " "%s\n" ,fc_lport_state (lport));
@@ -1060,13 +1060,13 @@ static void fc_lport_rpn_id_resp(struct fc_seq *sp, struct fc_frame *fp,struct fc_frame_header *fh;struct fc_ct_hdr *ct; +FC_LPORT_DBG (lport,"Received a RPN_ID %s\n" ,fc_els_resp_type (fp)); +if (fp ==ERR_PTR (-FC_EX_CLOSED ))return ;mutex_lock (&lport->lp_mutex); -FC_LPORT_DBG (lport,"Received a RPN_ID response\n" ); -if (lport->state !=LPORT_ST_RPN_ID ) {FC_LPORT_DBG (lport,"Received a RPN_ID response, but in state " "%s\n" ,fc_lport_state (lport));
@@ -1112,13 +1112,13 @@ static void fc_lport_scr_resp(struct fc_seq *sp, struct fc_frame *fp,struct fc_lport *lport = lp_arg;u8 op; +FC_LPORT_DBG (lport,"Received a SCR %s\n" ,fc_els_resp_type (fp)); +if (fp ==ERR_PTR (-FC_EX_CLOSED ))return ;mutex_lock (&lport->lp_mutex); -FC_LPORT_DBG (lport,"Received a SCR response\n" ); -if (lport->state !=LPORT_ST_SCR ) {FC_LPORT_DBG (lport,"Received a SCR response, but in state " "%s\n" ,fc_lport_state (lport));
@@ -1333,13 +1333,13 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,struct fc_lport *lport = lp_arg;u8 op; +FC_LPORT_DBG (lport,"Received a LOGO %s\n" ,fc_els_resp_type (fp)); +if (fp ==ERR_PTR (-FC_EX_CLOSED ))return ;mutex_lock (&lport->lp_mutex); -FC_LPORT_DBG (lport,"Received a LOGO response\n" ); -if (lport->state !=LPORT_ST_LOGO ) {FC_LPORT_DBG (lport,"Received a LOGO response, but in state " "%s\n" ,fc_lport_state (lport));
@@ -1415,13 +1415,13 @@ static void fc_lport_flogi_resp(struct fc_seq *sp, struct fc_frame *fp,unsigned int e_d_tov;u16 mfs; +FC_LPORT_DBG (lport,"Received a FLOGI %s\n" ,fc_els_resp_type (fp)); +if (fp ==ERR_PTR (-FC_EX_CLOSED ))return ;mutex_lock (&lport->lp_mutex); -FC_LPORT_DBG (lport,"Received a FLOGI response\n" ); -if (lport->state !=LPORT_ST_FLOGI ) {FC_LPORT_DBG (lport,"Received a FLOGI response, but in state " "%s\n" ,fc_lport_state (lport));
drivers/scsi/libfc/fc_rport.c +4 -4
@@ -544,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,mutex_lock (&rdata->rp_mutex); -FC_RPORT_DBG (rdata,"Received a PLOGI response\n" ); +FC_RPORT_DBG (rdata,"Received a PLOGI %s\n" ,fc_els_resp_type (fp));if (rdata->rp_state !=RPORT_ST_PLOGI ) { FC_RPORT_DBG(rdata, "Received a PLOGI response, but in state "
@@ -651,7 +651,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,mutex_lock (&rdata->rp_mutex); -FC_RPORT_DBG (rdata,"Received a PRLI response\n" ); +FC_RPORT_DBG (rdata,"Received a PRLI %s\n" ,fc_els_resp_type (fp));if (rdata->rp_state !=RPORT_ST_PRLI ) { FC_RPORT_DBG(rdata, "Received a PRLI response, but in state "
@@ -717,7 +717,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,mutex_lock (&rdata->rp_mutex); -FC_RPORT_DBG (rdata,"Received a LOGO response\n" ); +FC_RPORT_DBG (rdata,"Received a LOGO %s\n" ,fc_els_resp_type (fp));if (rdata->rp_state !=RPORT_ST_LOGO ) { FC_RPORT_DBG(rdata, "Received a LOGO response, but in state "
@@ -801,7 +801,7 @@ static void fc_rport_rtv_resp(struct fc_seq *sp, struct fc_frame *fp,mutex_lock (&rdata->rp_mutex); -FC_RPORT_DBG (rdata,"Received a RTV response\n" ); +FC_RPORT_DBG (rdata,"Received a RTV %s\n" ,fc_els_resp_type (fp));if (rdata->rp_state !=RPORT_ST_RTV ) { FC_RPORT_DBG(rdata, "Received a RTV response, but in state "
include/scsi/libfc.h +5 -0
@@ -1084,4 +1084,9 @@ void fc_destroy_exch_mgr(void);int fc_setup_rport (void );void fc_destroy_rport (void ); +/* +* Internal libfc functions. +*/ +const char *fc_els_resp_type (struct fc_frame *); +#endif /* _LIBFC_H_ */
PATCH 56/64 libfc: correctly handle incoming PLOGI request.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
libfc receives PLOGIs from switches which are trying to discover what kind of devices are present, and from other initiators to find out if we're a target.
As an initiator, some argue we don't need to handle incoming PLOGI requests, and we currently reject them from unknown remote ports, but accept them is we're in the middle of a PLOGI to the remote port.
For eventual target implementations, we want to handle them always.
For incoming PLOGI, don't fail if the rport_priv doesn't exist. Just create it and go become READY without going through PRLI. If PRLI occurs, then our roles will be set and we'll become READY again.
Also, allow incoming PRLI in RTV state.
---
drivers/scsi/libfc/fc_rport.c | 185 +++++++++++++++++++++-------------------- 1 files changed, 93 insertions(+), 92 deletions(-)
drivers/scsi/libfc/fc_rport.c +93 -92
@@ -63,7 +63,7 @@ static void fc_rport_enter_rtv(struct fc_rport_priv *);static void fc_rport_enter_ready (struct fc_rport_priv *);static void fc_rport_enter_logo (struct fc_rport_priv *); -static void fc_rport_recv_plogi_req (struct fc_rport_priv *, +static void fc_rport_recv_plogi_req (struct fc_lport *,struct fc_seq *,struct fc_frame *);static void fc_rport_recv_prli_req (struct fc_rport_priv *,struct fc_seq *,struct fc_frame *);
@@ -576,15 +576,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp, csp_seq = cssp_seq; rdata->max_seq = csp_seq; rdata->maxframe_size =fc_plogi_get_maxframe (plp, lport->mfs); - -/* -* If the rport is one of the well known addresses -* we skip PRLI and RTV and go straight to READY. -*/ -if (rdata->ids.port_id >=FC_FID_DOM_MGR ) -fc_rport_enter_ready (rdata); -else -fc_rport_enter_prli (rdata); +fc_rport_enter_prli (rdata); }else fc_rport_error_retry (rdata, fp);
@@ -763,6 +755,15 @@ static void fc_rport_enter_prli(struct fc_rport_priv *rdata) } *pp;struct fc_frame *fp; +/* +* If the rport is one of the well known addresses +* we skip PRLI and RTV and go straight to READY. +*/ +if (rdata->ids.port_id >=FC_FID_DOM_MGR ) { +fc_rport_enter_ready (rdata); +return ; + } +FC_RPORT_DBG (rdata,"Port entered PRLI state from %s state\n" ,fc_rport_state (rdata));
@@ -929,6 +930,15 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, els_data.explan =ELS_EXPL_NONE ; els_data.reason =ELS_RJT_NONE ; + op =fc_frame_payload_op (fp); +switch (op) { +case ELS_PLOGI : +fc_rport_recv_plogi_req (lport, sp, fp); +return ; +default : +break ; + } + fh =fc_frame_header_get (fp); s_id =ntoh24 (fh->fh_s_id);
@@ -944,11 +954,7 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,mutex_lock (&rdata->rp_mutex);mutex_unlock (&lport->disc.disc_mutex); - op =fc_frame_payload_op (fp);switch (op) { -case ELS_PLOGI : -fc_rport_recv_plogi_req (rdata, sp, fp); -break ;case ELS_PRLI :fc_rport_recv_prli_req (rdata, sp, fp);break ;
@@ -977,48 +983,56 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp,/** * fc_rport_recv_plogi_req() - Handle incoming Port Login (PLOGI) request -* @rdata: private remote port data +* @lport: local port * @sp: current sequence in the PLOGI exchange * @fp: PLOGI request frame * -* Locking Note: The rport lock is exected to be held before calling -* this function. +* Locking Note: The rport lock is held before calling this function. */ -static void fc_rport_recv_plogi_req (struct fc_rport_priv *rdata, +static void fc_rport_recv_plogi_req (struct fc_lport *lport,struct fc_seq *sp,struct fc_frame *rx_fp) { -struct fc_lport *lport = rdata->local_port; +struct fc_disc *disc; +struct fc_rport_priv *rdata;struct fc_frame *fp = rx_fp;struct fc_exch *ep;struct fc_frame_header *fh;struct fc_els_flogi *pl;struct fc_seq_els_data rjt_data; -u32 sid; -u64 wwpn; -u64 wwnn; -enum fc_els_rjt_reason reject =0 ; -u32 f_ctl; - rjt_data.fp =NULL ; +u32 sid, f_ctl; + rjt_data.fp =NULL ; fh =fc_frame_header_get (fp); + sid =ntoh24 (fh->fh_s_id); -FC_RPORT_DBG (rdata,"Received PLOGI request while in state %s\n" , -fc_rport_state (rdata)); +FC_RPORT_ID_DBG (lport, sid,"Received PLOGI request\n" ); - sid =ntoh24 (fh->fh_s_id); pl =fc_frame_payload_get (fp,sizeof (*pl));if (!pl) { -FC_RPORT_DBG (rdata,"Received PLOGI too short\n" ); -WARN_ON (1 ); -/* XXX TBD: send reject? */ -fc_frame_free (fp); -return ; +FC_RPORT_ID_DBG (lport, sid,"Received PLOGI too short\n" ); + rjt_data.reason =ELS_RJT_PROT ; + rjt_data.explan =ELS_EXPL_INV_LEN ; + goto reject; + } + + disc = &lport->disc; +mutex_lock (&disc->disc_mutex); + rdata = lport->tt.rport_create (lport, sid); +if (!rdata) { +mutex_unlock (&disc->disc_mutex); + rjt_data.reason =ELS_RJT_UNAB ; + rjt_data.explan =ELS_EXPL_INSUF_RES ; + goto reject; } - wwpn =get_unaligned_be64 (&pl->fl_wwpn); - wwnn =get_unaligned_be64 (&pl->fl_wwnn); + +mutex_lock (&rdata->rp_mutex); +mutex_unlock (&disc->disc_mutex); + + rdata->ids.port_name =get_unaligned_be64 (&pl->fl_wwpn); + rdata->ids.node_name =get_unaligned_be64 (&pl->fl_wwnn);/* -* If the session was just created, possibly due to the incoming PLOGI, +* If the rport was just created, possibly due to the incoming PLOGI, * set the state appropriately and accept the PLOGI. * * If we had also sent a PLOGI, and if the received PLOGI is from a
@@ -1030,72 +1044,58 @@ static void fc_rport_recv_plogi_req(struct fc_rport_priv *rdata,*/ switch (rdata->rp_state) {case RPORT_ST_INIT : -FC_RPORT_DBG (rdata,"Received PLOGI, wwpn %llx state INIT " -"- reject\n" , (unsigned long long )wwpn); - reject =ELS_RJT_UNSUP ; +FC_RPORT_DBG (rdata,"Received PLOGI in INIT state\n" );break ;case RPORT_ST_PLOGI : -FC_RPORT_DBG (rdata,"Received PLOGI in PLOGI state %d\n" , - rdata->rp_state); -if (wwpn < lport->wwpn) - reject =ELS_RJT_INPROG ; +FC_RPORT_DBG (rdata,"Received PLOGI in PLOGI state\n" ); +if (rdata->ids.port_name < lport->wwpn) { +mutex_unlock (&rdata->rp_mutex); + rjt_data.reason =ELS_RJT_INPROG ; + rjt_data.explan =ELS_EXPL_NONE ; + goto reject; + }break ;case RPORT_ST_PRLI :case RPORT_ST_READY : -FC_RPORT_DBG (rdata,"Received PLOGI in logged-in state %d " -"- ignored for now\n" , rdata->rp_state); -/* XXX TBD - should reset */ break ;case RPORT_ST_DELETE :default : -FC_RPORT_DBG (rdata,"Received PLOGI in unexpected " -"state %d\n" , rdata->rp_state); -fc_frame_free (fp); -return ; -break ; +FC_RPORT_DBG (rdata,"Received PLOGI in unexpected state %d\n" , + rdata->rp_state); +fc_frame_free (rx_fp); + goto out; } -if (reject) { - rjt_data.reason = reject; - rjt_data.explan =ELS_EXPL_NONE ; - lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &rjt_data); -fc_frame_free (fp); - }else { - fp =fc_frame_alloc (lport,sizeof (*pl)); -if (fp ==NULL ) { - fp = rx_fp; - rjt_data.reason =ELS_RJT_UNAB ; - rjt_data.explan =ELS_EXPL_NONE ; - lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &rjt_data); -fc_frame_free (fp); - }else { - sp = lport->tt.seq_start_next (sp); -WARN_ON (!sp); - rdata->ids.port_name = wwpn; - rdata->ids.node_name = wwnn; - -/* -* Get session payload size from incoming PLOGI. -*/ - rdata->maxframe_size = -fc_plogi_get_maxframe (pl, lport->mfs); -fc_frame_free (rx_fp); -fc_plogi_fill (lport, fp,ELS_LS_ACC ); - -/* -* Send LS_ACC. If this fails, -* the originator should retry. -*/ - f_ctl =FC_FC_EX_CTX |FC_FC_LAST_SEQ ; - f_ctl |=FC_FC_END_SEQ |FC_FC_SEQ_INIT ; - ep =fc_seq_exch (sp); -fc_fill_fc_hdr (fp,FC_RCTL_ELS_REP , ep->did, ep->sid, -FC_TYPE_ELS , f_ctl,0 ); - lport->tt.seq_send (lport, sp, fp); -if (rdata->rp_state ==RPORT_ST_PLOGI ) -fc_rport_enter_prli (rdata); - } - } +/* +* Get session payload size from incoming PLOGI. +*/ + rdata->maxframe_size =fc_plogi_get_maxframe (pl, lport->mfs); +fc_frame_free (rx_fp); + +/* +* Send LS_ACC. If this fails, the originator should retry. +*/ + sp = lport->tt.seq_start_next (sp); +if (!sp) + goto out; + fp =fc_frame_alloc (lport,sizeof (*pl)); +if (!fp) + goto out; + +fc_plogi_fill (lport, fp,ELS_LS_ACC ); + f_ctl =FC_FC_EX_CTX |FC_FC_LAST_SEQ |FC_FC_END_SEQ |FC_FC_SEQ_INIT ; + ep =fc_seq_exch (sp); +fc_fill_fc_hdr (fp,FC_RCTL_ELS_REP , ep->did, ep->sid, +FC_TYPE_ELS , f_ctl,0 ); + lport->tt.seq_send (lport, sp, fp); +fc_rport_enter_prli (rdata); +out: +mutex_unlock (&rdata->rp_mutex); +return ; + +reject: + lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &rjt_data); +fc_frame_free (fp); }/**
@@ -1138,6 +1138,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,switch (rdata->rp_state) {case RPORT_ST_PRLI : +case RPORT_ST_RTV :case RPORT_ST_READY : reason =ELS_RJT_NONE ;break ;
PATCH 57/64 libfc: fix rport error handling for login-required and invalid ops
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When receiving an ELS request, if the request isn't recognized, the unsupported operation error should be given even if the port is not found or not logged in.
Also, the LOGO request shouldn't give the login-required explanation.
---
drivers/scsi/libfc/fc_rport.c | 137 ++++++++++++++++++++++++++--------------- 1 files changed, 88 insertions(+), 49 deletions(-)
drivers/scsi/libfc/fc_rport.c +88 -49
@@ -69,7 +69,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *, struct fc_seq *, struct fc_frame *);static void fc_rport_recv_prlo_req (struct fc_rport_priv *,struct fc_seq *,struct fc_frame *); -static void fc_rport_recv_logo_req (struct fc_rport_priv *, +static void fc_rport_recv_logo_req (struct fc_lport *,struct fc_seq *,struct fc_frame *);static void fc_rport_timeout (struct work_struct *);static void fc_rport_error (struct fc_rport_priv *,struct fc_frame *);
@@ -908,62 +908,56 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata)kref_get (&rdata->kref); } -/** -* fc_rport_recv_req() - Receive a request from a rport +* fc_rport_recv_els_req() - handle a validated ELS request. +* @lport: Fibre Channel local port * @sp: current sequence in the PLOGI exchange * @fp: response frame -* @lport: Fibre Channel local port +* +* Handle incoming ELS requests that require port login. +* The ELS opcode has already been validated by the caller. * * Locking Note: Called with the lport lock held. */ -void fc_rport_recv_req (struct fc_seq *sp,struct fc_frame *fp, -struct fc_lport *lport) +static void fc_rport_recv_els_req (struct fc_lport *lport, +struct fc_seq *sp,struct fc_frame *fp) {struct fc_rport_priv *rdata;struct fc_frame_header *fh;struct fc_seq_els_data els_data; -u32 s_id; -u8 op; els_data.fp =NULL ; - els_data.explan =ELS_EXPL_NONE ; - els_data.reason =ELS_RJT_NONE ; - - op =fc_frame_payload_op (fp); -switch (op) { -case ELS_PLOGI : -fc_rport_recv_plogi_req (lport, sp, fp); -return ; -default : -break ; - } + els_data.reason =ELS_RJT_UNAB ; + els_data.explan =ELS_EXPL_PLOGI_REQD ; fh =fc_frame_header_get (fp); - s_id =ntoh24 (fh->fh_s_id);mutex_lock (&lport->disc.disc_mutex); - rdata = lport->tt.rport_lookup (lport, s_id); + rdata = lport->tt.rport_lookup (lport,ntoh24 (fh->fh_s_id));if (!rdata) {mutex_unlock (&lport->disc.disc_mutex); - els_data.reason =ELS_RJT_UNAB ; - lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &els_data); -fc_frame_free (fp); -return ; + goto reject; }mutex_lock (&rdata->rp_mutex);mutex_unlock (&lport->disc.disc_mutex); -switch (op) { +switch (rdata->rp_state) { +case RPORT_ST_PRLI : +case RPORT_ST_RTV : +case RPORT_ST_READY : +break ; +default : +mutex_unlock (&rdata->rp_mutex); + goto reject; + } + +switch (fc_frame_payload_op (fp)) {case ELS_PRLI :fc_rport_recv_prli_req (rdata, sp, fp);break ;case ELS_PRLO :fc_rport_recv_prlo_req (rdata, sp, fp);break ; -case ELS_LOGO : -fc_rport_recv_logo_req (rdata, sp, fp); -break ;case ELS_RRQ : els_data.fp = fp; lport->tt.seq_els_rsp_send (sp,ELS_RRQ , &els_data);
@@ -973,12 +967,58 @@ void fc_rport_recv_req(struct fc_seq *sp, struct fc_frame *fp, lport->tt.seq_els_rsp_send (sp,ELS_REC , &els_data);break ;default : - els_data.reason =ELS_RJT_UNSUP ; - lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &els_data); +fc_frame_free (fp);/* can't happen */ break ; }mutex_unlock (&rdata->rp_mutex); +return ; + +reject: + lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &els_data); +fc_frame_free (fp); +} + +/** +* fc_rport_recv_req() - Handle a received ELS request from a rport +* @sp: current sequence in the PLOGI exchange +* @fp: response frame +* @lport: Fibre Channel local port +* +* Locking Note: Called with the lport lock held. +*/ +void fc_rport_recv_req (struct fc_seq *sp,struct fc_frame *fp, +struct fc_lport *lport) +{ +struct fc_seq_els_data els_data; + +/* +* Handle PLOGI and LOGO requests separately, since they +* don't require prior login. +* Check for unsupported opcodes first and reject them. +* For some ops, it would be incorrect to reject with "PLOGI required". +*/ +switch (fc_frame_payload_op (fp)) { +case ELS_PLOGI : +fc_rport_recv_plogi_req (lport, sp, fp); +break ; +case ELS_LOGO : +fc_rport_recv_logo_req (lport, sp, fp); +break ; +case ELS_PRLI : +case ELS_PRLO : +case ELS_RRQ : +case ELS_REC : +fc_rport_recv_els_req (lport, sp, fp); +break ; +default : +fc_frame_free (fp); + els_data.fp =NULL ; + els_data.reason =ELS_RJT_UNSUP ; + els_data.explan =ELS_EXPL_NONE ; + lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &els_data); +break ; + } }/**
@@ -1276,11 +1316,6 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,FC_RPORT_DBG (rdata,"Received PRLO request while in state %s\n" ,fc_rport_state (rdata)); -if (rdata->rp_state ==RPORT_ST_DELETE ) { -fc_frame_free (fp); -return ; - } - rjt_data.fp =NULL ; rjt_data.reason =ELS_RJT_UNAB ; rjt_data.explan =ELS_EXPL_NONE ;
@@ -1290,32 +1325,36 @@ static void fc_rport_recv_prlo_req(struct fc_rport_priv *rdata,/** * fc_rport_recv_logo_req() - Handle incoming Logout (LOGO) request -* @rdata: private remote port data +* @lport: local port. * @sp: current sequence in the LOGO exchange * @fp: LOGO request frame * * Locking Note: The rport lock is exected to be held before calling * this function. */ -static void fc_rport_recv_logo_req (struct fc_rport_priv *rdata, +static void fc_rport_recv_logo_req (struct fc_lport *lport,struct fc_seq *sp,struct fc_frame *fp) {struct fc_frame_header *fh; -struct fc_lport *lport = rdata->local_port; +struct fc_rport_priv *rdata; +u32 sid; fh =fc_frame_header_get (fp); + sid =ntoh24 (fh->fh_s_id); -FC_RPORT_DBG (rdata,"Received LOGO request while in state %s\n" , -fc_rport_state (rdata)); - -if (rdata->rp_state ==RPORT_ST_DELETE ) { -fc_frame_free (fp); -return ; - } - -fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); - +mutex_lock (&lport->disc.disc_mutex); + rdata = lport->tt.rport_lookup (lport, sid); +if (rdata) { +mutex_lock (&rdata->rp_mutex); +FC_RPORT_DBG (rdata,"Received LOGO request while in state %s\n" , +fc_rport_state (rdata)); +fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); +mutex_unlock (&rdata->rp_mutex); + }else +FC_RPORT_ID_DBG (lport, sid, +"Received LOGO from non-logged-in port\n" ); +mutex_unlock (&lport->disc.disc_mutex); lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL );fc_frame_free (fp); }
PATCH 58/64 libfc: re-login to remote ports that send us LOGO
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
After a quick link flap, a target was seen to send us a LOGO. Apparently, it saw an RSCN reporting that we had dropped out of the fabric after we had logged back into it.
This is likely in larger fabrics (more than 2 FC switches) after a quick link flap at the initiator. Each link transition causes an port-specific RSCN to the target. After the link comes back up, the initiator successfully discovers and does a PLOGI to the target before the target sees the first RSCN reporting the initiator is gone, and it sends a LOGO. The target may see a subsequent RSCN saying the port is back, but probably wouldn't send a PLOGI and leaves it up to the initiator to re-login.
An RSCN can be delayed by the switches due to software layers but a PLOGI is forwarded in hardware causing the PLOGI to beat the RSCN.
If a remote port is in the discovered set and sends a LOGO, re-login to it.
---
drivers/scsi/libfc/fc_rport.c | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_rport.c +11 -2
@@ -1340,6 +1340,8 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,struct fc_rport_priv *rdata;u32 sid; + lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL ); + fh =fc_frame_header_get (fp); sid =ntoh24 (fh->fh_s_id);
@@ -1349,13 +1351,20 @@ static void fc_rport_recv_logo_req(struct fc_lport *lport,mutex_lock (&rdata->rp_mutex);FC_RPORT_DBG (rdata,"Received LOGO request while in state %s\n" ,fc_rport_state (rdata)); -fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); + +/* +* If the remote port was created due to discovery, +* log back in. It may have seen a stale RSCN about us. +*/ +if (rdata->rp_state !=RPORT_ST_DELETE && rdata->disc_id) +fc_rport_enter_plogi (rdata); +else +fc_rport_enter_delete (rdata,RPORT_EV_LOGO );mutex_unlock (&rdata->rp_mutex); }else FC_RPORT_ID_DBG (lport, sid,"Received LOGO from non-logged-in port\n" );mutex_unlock (&lport->disc.disc_mutex); - lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL );fc_frame_free (fp); }
PATCH 59/64 libfc: LOGO response code had extraeous enter_rtv
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
fc_rport_logo_resp() had a call to fc_rport_enter_rtv() if the LOGO was accepted. This must've been a copy/paste mistake, but it didn't matter since we don't stay in the LOGO state long enough to hit this code.
Change fc_rport_logo_resp() to just enter the delete state no matter what.
---
drivers/scsi/libfc/fc_rport.c | 10 ++++------ 1 files changed, 4 insertions(+), 6 deletions(-)
drivers/scsi/libfc/fc_rport.c +4 -6
@@ -725,12 +725,10 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, } op =fc_frame_payload_op (fp); -if (op ==ELS_LS_ACC ) { -fc_rport_enter_rtv (rdata); - }else { -FC_RPORT_DBG (rdata,"Bad ELS response for LOGO command\n" ); -fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); - } +if (op !=ELS_LS_ACC ) +FC_RPORT_DBG (rdata,"Bad ELS response op %x for LOGO command\n" , + op); +fc_rport_enter_delete (rdata,RPORT_EV_LOGO ); out:fc_frame_free (fp);
PATCH 60/64 libfc: use ADISC to verify rport login state
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When rport_login is called on an rport that is already thought to be logged in, use ADISC. If that fails, redo PLOGI. This is less disruptive after fabric changes that don't affect the state of the target.
Implement the sending of ADISC via fc_els_fill.
Add ADISC state to the rport state machine. This is entered from READY and returns to READY after successful completion. If it fails, the rport is either logged off and deleted or re-does PLOGI.
---
drivers/scsi/libfc/fc_rport.c | 122 +++++++++++++++++++++++++++++++++++++++-- include/scsi/fc_encode.h | 21 +++++++ include/scsi/libfc.h | 1 3 files changed, 139 insertions(+), 5 deletions(-)
drivers/scsi/libfc/fc_rport.c +117 -5
@@ -62,6 +62,7 @@ static void fc_rport_enter_prli(struct fc_rport_priv *);static void fc_rport_enter_rtv (struct fc_rport_priv *);static void fc_rport_enter_ready (struct fc_rport_priv *);static void fc_rport_enter_logo (struct fc_rport_priv *); +static void fc_rport_enter_adisc (struct fc_rport_priv *);static void fc_rport_recv_plogi_req (struct fc_lport *,struct fc_seq *,struct fc_frame *);
@@ -83,6 +84,7 @@ static const char *fc_rport_state_names[] = { [RPORT_ST_RTV] = "RTV", [RPORT_ST_READY] = "Ready", [RPORT_ST_LOGO] = "LOGO", + [RPORT_ST_ADISC] = "ADISC", [RPORT_ST_DELETE] = "Delete", };
@@ -326,15 +328,25 @@ static void fc_rport_work(struct work_struct *work)* Locking Note: Called without the rport lock held. This * function will hold the rport lock, call an _enter_* * function and then unlock the rport. +* +* This indicates the intent to be logged into the remote port. +* If it appears we are already logged in, ADISC is used to verify +* the setup. */ int fc_rport_login (struct fc_rport_priv *rdata) {mutex_lock (&rdata->rp_mutex); -FC_RPORT_DBG (rdata,"Login to port\n" ); - -fc_rport_enter_plogi (rdata); - +switch (rdata->rp_state) { +case RPORT_ST_READY : +FC_RPORT_DBG (rdata,"ADISC port\n" ); +fc_rport_enter_adisc (rdata); +break ; +default : +FC_RPORT_DBG (rdata,"Login to port\n" ); +fc_rport_enter_plogi (rdata); +break ; + }mutex_unlock (&rdata->rp_mutex);return 0 ;
@@ -448,6 +460,9 @@ static void fc_rport_timeout(struct work_struct *work)case RPORT_ST_LOGO :fc_rport_enter_logo (rdata);break ; +case RPORT_ST_ADISC : +fc_rport_enter_adisc (rdata); +break ;case RPORT_ST_READY :case RPORT_ST_INIT :case RPORT_ST_DELETE :
@@ -473,13 +488,16 @@ static void fc_rport_error(struct fc_rport_priv *rdata, struct fc_frame *fp)switch (rdata->rp_state) {case RPORT_ST_PLOGI : -case RPORT_ST_PRLI :case RPORT_ST_LOGO :fc_rport_enter_delete (rdata,RPORT_EV_FAILED );break ;case RPORT_ST_RTV :fc_rport_enter_ready (rdata);break ; +case RPORT_ST_PRLI : +case RPORT_ST_ADISC : +fc_rport_enter_logo (rdata); +break ;case RPORT_ST_DELETE :case RPORT_ST_READY :case RPORT_ST_INIT :
@@ -907,6 +925,93 @@ static void fc_rport_enter_logo(struct fc_rport_priv *rdata) }/** +* fc_rport_els_adisc_resp() - Address Discovery response handler +* @sp: current sequence in the ADISC exchange +* @fp: response frame +* @rdata_arg: remote port private. +* +* Locking Note: This function will be called without the rport lock +* held, but it will lock, call an _enter_* function or fc_rport_error +* and then unlock the rport. +*/ +static void fc_rport_adisc_resp (struct fc_seq *sp,struct fc_frame *fp, +void *rdata_arg) +{ +struct fc_rport_priv *rdata = rdata_arg; +struct fc_els_adisc *adisc; +u8 op; + +mutex_lock (&rdata->rp_mutex); + +FC_RPORT_DBG (rdata,"Received a ADISC response\n" ); + +if (rdata->rp_state !=RPORT_ST_ADISC ) { +FC_RPORT_DBG (rdata,"Received a ADISC resp but in state %s\n" , +fc_rport_state (rdata)); +if (IS_ERR (fp)) + goto err; + goto out; + } + +if (IS_ERR (fp)) { +fc_rport_error (rdata, fp); + goto err; + } + +/* +* If address verification failed. Consider us logged out of the rport. +* Since the rport is still in discovery, we want to be +* logged in, so go to PLOGI state. Otherwise, go back to READY. +*/ + op =fc_frame_payload_op (fp); + adisc =fc_frame_payload_get (fp,sizeof (*adisc)); +if (op !=ELS_LS_ACC || !adisc || +ntoh24 (adisc->adisc_port_id) != rdata->ids.port_id || +get_unaligned_be64 (&adisc->adisc_wwpn) != rdata->ids.port_name || +get_unaligned_be64 (&adisc->adisc_wwnn) != rdata->ids.node_name) { +FC_RPORT_DBG (rdata,"ADISC error or mismatch\n" ); +fc_rport_enter_plogi (rdata); + }else { +FC_RPORT_DBG (rdata,"ADISC OK\n" ); +fc_rport_enter_ready (rdata); + } +out: +fc_frame_free (fp); +err: +mutex_unlock (&rdata->rp_mutex); +kref_put (&rdata->kref, rdata->local_port->tt.rport_destroy); +} + +/** +* fc_rport_enter_adisc() - Send Address Discover (ADISC) request to peer +* @rdata: remote port private data +* +* Locking Note: The rport lock is expected to be held before calling +* this routine. +*/ +static void fc_rport_enter_adisc (struct fc_rport_priv *rdata) +{ +struct fc_lport *lport = rdata->local_port; +struct fc_frame *fp; + +FC_RPORT_DBG (rdata,"sending ADISC from %s state\n" , +fc_rport_state (rdata)); + +fc_rport_state_enter (rdata,RPORT_ST_ADISC ); + + fp =fc_frame_alloc (lport,sizeof (struct fc_els_adisc )); +if (!fp) { +fc_rport_error_retry (rdata, fp); +return ; + } +if (!lport->tt.elsct_send (lport, rdata->ids.port_id, fp,ELS_ADISC , + fc_rport_adisc_resp, rdata, lport->e_d_tov)) +fc_rport_error_retry (rdata, fp); +else +kref_get (&rdata->kref); +} + +/** * fc_rport_recv_els_req() - handle a validated ELS request. * @lport: Fibre Channel local port * @sp: current sequence in the PLOGI exchange
@@ -943,6 +1048,7 @@ static void fc_rport_recv_els_req(struct fc_lport *lport,case RPORT_ST_PRLI :case RPORT_ST_RTV :case RPORT_ST_READY : +case RPORT_ST_ADISC :break ;default :mutex_unlock (&rdata->rp_mutex);
@@ -1095,6 +1201,10 @@ static void fc_rport_recv_plogi_req(struct fc_lport *lport,break ;case RPORT_ST_PRLI :case RPORT_ST_READY : +case RPORT_ST_ADISC : +FC_RPORT_DBG (rdata,"Received PLOGI in logged-in state %d " +"- ignored for now\n" , rdata->rp_state); +/* XXX TBD - should reset */ break ;case RPORT_ST_DELETE :default :
@@ -1178,6 +1288,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,case RPORT_ST_PRLI :case RPORT_ST_RTV :case RPORT_ST_READY : +case RPORT_ST_ADISC : reason =ELS_RJT_NONE ;break ;default :
@@ -1283,6 +1394,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,fc_rport_enter_ready (rdata);break ;case RPORT_ST_READY : +case RPORT_ST_ADISC :break ;default :break ;
include/scsi/fc_encode.h +21 -0
@@ -57,6 +57,23 @@ static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl, }/** +* fc_adisc_fill() - Fill in adisc request frame +* @lport: local port. +* @fp: fc frame where payload will be placed. +*/ +static inline void fc_adisc_fill (struct fc_lport *lport,struct fc_frame *fp) +{ +struct fc_els_adisc *adisc; + + adisc =fc_frame_payload_get (fp,sizeof (*adisc)); +memset (adisc,0 ,sizeof (*adisc)); + adisc->adisc_cmd =ELS_ADISC ; +put_unaligned_be64 (lport->wwpn, &adisc->adisc_wwpn); +put_unaligned_be64 (lport->wwnn, &adisc->adisc_wwnn); +hton24 (adisc->adisc_port_id,fc_host_port_id (lport->host)); +} + +/** * fc_ct_hdr_fill- fills ct header and reset ct payload * returns pointer to ct request. */
@@ -255,6 +272,10 @@ static inline int fc_els_fill(struct fc_lport *lport, enum fc_rctl *r_ctl, enum fc_fh_type *fh_type) {switch (op) { +case ELS_ADISC : +fc_adisc_fill (lport, fp); +break ; +case ELS_PLOGI :fc_plogi_fill (lport, fp,ELS_PLOGI );break ;
include/scsi/libfc.h +1 -0
@@ -143,6 +143,7 @@ enum fc_rport_state {RPORT_ST_RTV ,/* waiting for RTV completion */ RPORT_ST_READY ,/* ready for use */ RPORT_ST_LOGO ,/* port logout sent */ +RPORT_ST_ADISC ,/* Discover Address sent */ RPORT_ST_DELETE, /* port being deleted */ };
PATCH 61/64 libfc: fix handling of incoming Discover Address (ADISC) requests
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The local port facility has been replying to ADISC requests without looking to see if the remote port is logged in. This is incorrect. An ADISC request requires PLOGI first. It should be rejected if the sending remote port is not logged in.
This is like other incoming requests that require login, all of which should be handled in the remote port module.
Move the ADISC request handling from fc_lport.c to fc_rport.c.
---
drivers/scsi/libfc/fc_lport.c | 53 ----------------------------------------- drivers/scsi/libfc/fc_rport.c | 48 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 53 deletions(-)
drivers/scsi/libfc/fc_lport.c +0 -53
@@ -452,56 +452,6 @@ static void fc_lport_recv_rnid_req(struct fc_seq *sp, struct fc_frame *in_fp, }/** -* fc_lport_recv_adisc_req() - Handle received Address Discovery Request -* @lport: Fibre Channel local port recieving the ADISC -* @sp: current sequence in the ADISC exchange -* @fp: ADISC request frame -* -* Locking Note: The lport lock is expected to be held before calling -* this function. -*/ -static void fc_lport_recv_adisc_req (struct fc_seq *sp,struct fc_frame *in_fp, -struct fc_lport *lport) -{ -struct fc_frame *fp; -struct fc_exch *ep =fc_seq_exch (sp); -struct fc_els_adisc *req, *rp; -struct fc_seq_els_data rjt_data; -size_t len; -u32 f_ctl; - -FC_LPORT_DBG (lport,"Received ADISC request while in state %s\n" , -fc_lport_state (lport)); - - req =fc_frame_payload_get (in_fp,sizeof (*req)); -if (!req) { - rjt_data.fp =NULL ; - rjt_data.reason =ELS_RJT_LOGIC ; - rjt_data.explan =ELS_EXPL_NONE ; - lport->tt.seq_els_rsp_send (sp,ELS_LS_RJT , &rjt_data); - }else { - len =sizeof (*rp); - fp =fc_frame_alloc (lport, len); -if (fp) { - rp =fc_frame_payload_get (fp, len); -memset (rp,0 , len); - rp->adisc_cmd =ELS_LS_ACC ; - rp->adisc_wwpn =htonll (lport->wwpn); - rp->adisc_wwnn =htonll (lport->wwnn); -hton24 (rp->adisc_port_id, -fc_host_port_id (lport->host)); - sp = lport->tt.seq_start_next (sp); - f_ctl =FC_FC_EX_CTX |FC_FC_LAST_SEQ ; - f_ctl |=FC_FC_END_SEQ |FC_FC_SEQ_INIT ; -fc_fill_fc_hdr (fp,FC_RCTL_ELS_REP , ep->did, ep->sid, -FC_TYPE_ELS , f_ctl,0 ); - lport->tt.seq_send (lport, sp, fp); - } - } -fc_frame_free (in_fp); -} - -/** * fc_lport_recv_logo_req() - Handle received fabric LOGO request * @lport: Fibre Channel local port recieving the LOGO * @sp: current sequence in the LOGO exchange
@@ -849,9 +799,6 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,case ELS_RNID : recv = fc_lport_recv_rnid_req;break ; -case ELS_ADISC : - recv = fc_lport_recv_adisc_req; -break ; }recv (sp, fp, lport);
drivers/scsi/libfc/fc_rport.c +48 -0
66 lines not on this page · raw message
PATCH 62/64 libfc: send GPN_ID in reaction to single-port RSCNs.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When an RSCN indicates changes to individual remote ports, don't blindly log them out and then back in. Instead, determine whether they're still in the directory, by doing GPN_ID.
If that is successful, call login, which will send ADISC and reverify, otherwise, call logoff. Perhaps we should just delete the rport, not send LOGO, but it seems safer.
Also, fix a possible issue where if a mix of records in the RSCN cause us to queue disc_ports for disc_single and then we decide to do full rediscovery, we leak memory for those disc_ports queued.
So, go through the list of disc_ports even if doing full discovery. Free the disc_ports in any case. If any of the disc_single() calls return error, do a full discovery.
The ability to fill in GPN_ID requests was added to fc_ct_fill(). For this, it needs the FC_ID to be passed in as an arg. The did parameter for fc_elsct_send() is used for that, since the actual D_DID will always be 0xfffffc for all CT requests so far.
---
drivers/scsi/libfc/fc_disc.c | 137 ++++++++++++++++++++++++++++++++++------- drivers/scsi/libfc/fc_elsct.c | 2 - include/scsi/fc_encode.h | 16 ++++- 3 files changed, 128 insertions(+), 27 deletions(-)
drivers/scsi/libfc/fc_disc.c +113 -24
@@ -47,7 +47,7 @@ static void fc_disc_gpn_ft_req(struct fc_disc *);static void fc_disc_gpn_ft_resp (struct fc_seq *,struct fc_frame *,void *);static void fc_disc_done (struct fc_disc *,enum fc_disc_event );static void fc_disc_timeout (struct work_struct *); -static void fc_disc_single (struct fc_disc *,struct fc_disc_port *); +static int fc_disc_single (struct fc_lport *,struct fc_disc_port *);static void fc_disc_restart (struct fc_disc *);/**
@@ -83,7 +83,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, struct fc_disc *disc) {struct fc_lport *lport; -struct fc_rport_priv *rdata;struct fc_els_rscn *rp;struct fc_els_rscn_page *pp;struct fc_seq_els_data rjt_data;
@@ -150,6 +149,19 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp, } } lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL ); + +/* +* If not doing a complete rediscovery, do GPN_ID on +* the individual ports mentioned in the list. +* If any of these get an error, do a full rediscovery. +* In any case, go through the list and free the entries. +*/ +list_for_each_entry_safe (dp, next, &disc_ports, peers) { +list_del (&dp->peers); +if (!redisc) + redisc =fc_disc_single (lport, dp); +kfree (dp); + }if (redisc) {FC_DISC_DBG (disc,"RSCN received: rediscovering\n" );fc_disc_restart (disc);
@@ -157,14 +169,6 @@ static void fc_disc_recv_rscn_req(struct fc_seq *sp, struct fc_frame *fp,FC_DISC_DBG (disc,"RSCN received: not rediscovering. " "redisc %d state %d in_prog %d\n" , redisc, lport->state, disc->pending); -list_for_each_entry_safe (dp, next, &disc_ports, peers) { -list_del (&dp->peers); - rdata = lport->tt.rport_lookup (lport, dp->port_id); -if (rdata) { - lport->tt.rport_logoff (rdata); - } -fc_disc_single (disc, dp); - } }fc_frame_free (fp);return ;
@@ -562,32 +566,117 @@ static void fc_disc_gpn_ft_resp(struct fc_seq *sp, struct fc_frame *fp, }/** -* fc_disc_single() - Discover the directory information for a single target -* @lport: FC local port -* @dp: The port to rediscover +* fc_disc_gpn_id_resp() - Handle a response frame from Get Port Names (GPN_ID) +* @sp: exchange sequence +* @fp: response frame +* @rdata_arg: remote port private data * -* Locking Note: This function expects that the disc_mutex is locked -* before it is called. +* Locking Note: This function is called without disc mutex held. */ -static void fc_disc_single (struct fc_disc *disc,struct fc_disc_port *dp) +static void fc_disc_gpn_id_resp (struct fc_seq *sp,struct fc_frame *fp, +void *rdata_arg) { +struct fc_rport_priv *rdata = rdata_arg; +struct fc_rport_priv *new_rdata;struct fc_lport *lport; -struct fc_rport_priv *rdata; +struct fc_disc *disc; +struct fc_ct_hdr *cp; +struct fc_ns_gid_pn *pn; +u64 port_name; - lport = disc->lport; + lport = rdata->local_port; + disc = &lport->disc; -if (dp->port_id ==fc_host_port_id (lport->host)) +mutex_lock (&disc->disc_mutex); +if (PTR_ERR (fp) == -FC_EX_CLOSED ) goto out; +if (IS_ERR (fp)) + goto redisc; + + cp =fc_frame_payload_get (fp,sizeof (*cp)); +if (!cp) + goto redisc; +if (ntohs (cp->ct_cmd) ==FC_FS_ACC ) { +if (fr_len (fp) <sizeof (struct fc_frame_header ) + +sizeof (*cp) +sizeof (*pn)) + goto redisc; + pn = (struct fc_ns_gid_pn *)(cp +1 ); + port_name =get_unaligned_be64 (&pn->fn_wwpn); +if (rdata->ids.port_name ==-1 ) + rdata->ids.port_name = port_name; +else if (rdata->ids.port_name != port_name) { +FC_DISC_DBG (disc,"GPN_ID accepted. WWPN changed. " +"Port-id %x wwpn %llx\n" , + rdata->ids.port_id, port_name); + lport->tt.rport_logoff (rdata); - rdata = lport->tt.rport_create (lport, dp->port_id); -if (rdata) { + new_rdata = lport->tt.rport_create (lport, + rdata->ids.port_id); +if (new_rdata) { + new_rdata->disc_id = disc->disc_id; + lport->tt.rport_login (new_rdata); + } + goto out; + } rdata->disc_id = disc->disc_id; -kfree (dp); lport->tt.rport_login (rdata); + }else if (ntohs (cp->ct_cmd) ==FC_FS_RJT ) { +FC_DISC_DBG (disc,"GPN_ID rejected reason %x exp %x\n" , + cp->ct_reason, cp->ct_explan); + lport->tt.rport_logoff (rdata); + }else { +FC_DISC_DBG (disc,"GPN_ID unexpected response code %x\n" , +ntohs (cp->ct_cmd)); +redisc: +fc_disc_restart (disc); } -return ; out: -kfree (dp); +mutex_unlock (&disc->disc_mutex); +kref_put (&rdata->kref, lport->tt.rport_destroy); +} + +/** +* fc_disc_gpn_id_req() - Send Get Port Names by ID (GPN_ID) request +* @lport: local port +* @rdata: remote port private data +* +* Locking Note: This function expects that the disc_mutex is locked +* before it is called. +* On failure, an error code is returned. +*/ +static int fc_disc_gpn_id_req (struct fc_lport *lport, +struct fc_rport_priv *rdata) +{ +struct fc_frame *fp; + + fp =fc_frame_alloc (lport,sizeof (struct fc_ct_hdr ) + +sizeof (struct fc_ns_fid )); +if (!fp) +return -ENOMEM ; +if (!lport->tt.elsct_send (lport, rdata->ids.port_id, fp,FC_NS_GPN_ID , + fc_disc_gpn_id_resp, rdata, lport->e_d_tov)) +return -ENOMEM ; +kref_get (&rdata->kref); +return 0 ; +} + +/** +* fc_disc_single() - Discover the directory information for a single target +* @lport: local port +* @dp: The port to rediscover +* +* Locking Note: This function expects that the disc_mutex is locked +* before it is called. +*/ +static int fc_disc_single (struct fc_lport *lport,struct fc_disc_port *dp) +{ +struct fc_rport_priv *rdata; + + rdata = lport->tt.rport_create (lport, dp->port_id); +if (!rdata) +return -ENOMEM ; + rdata->disc_id =0 ; +return fc_disc_gpn_id_req (lport, rdata); }/**
drivers/scsi/libfc/fc_elsct.c +1 -1
@@ -49,7 +49,7 @@ static struct fc_seq *fc_elsct_send(struct fc_lport *lport, rc =fc_els_fill (lport, did, fp, op, &r_ctl, &fh_type); else {/* CT requests */ - rc =fc_ct_fill (lport, fp, op, &r_ctl, &fh_type); + rc =fc_ct_fill (lport, did, fp, op, &r_ctl, &fh_type); did =FC_FID_DIR_SERV ; }
include/scsi/fc_encode.h +14 -2
@@ -32,6 +32,7 @@ struct fc_ct_req {struct fc_ns_gid_ft gid;struct fc_ns_rn_id rn;struct fc_ns_rft rft; +struct fc_ns_fid fid; } payload; };
@@ -94,10 +95,16 @@ static inline struct fc_ct_req *fc_ct_hdr_fill(const struct fc_frame *fp, }/** -* fc_ct_fill - Fill in a name service request frame +* fc_ct_fill() - Fill in a name service request frame +* @lport: local port. +* @fc_id: FC_ID of non-destination rport for GPN_ID and similar inquiries. +* @fp: frame to contain payload. +* @op: CT opcode. +* @r_ctl: pointer to FC header R_CTL. +* @fh_type: pointer to FC-4 type. */ static inline int fc_ct_fill (struct fc_lport *lport, -struct fc_frame *fp, +u32 fc_id,struct fc_frame *fp,unsigned int op,enum fc_rctl *r_ctl,enum fc_fh_type *fh_type) {
@@ -109,6 +116,11 @@ static inline int fc_ct_fill(struct fc_lport *lport, ct->payload.gid.fn_fc4_type =FC_TYPE_FCP ;break ; +case FC_NS_GPN_ID : + ct =fc_ct_hdr_fill (fp, op,sizeof (struct fc_ns_fid )); +hton24 (ct->payload.fid.fp_fid, fc_id); +break ; +case FC_NS_RFT_ID : ct =fc_ct_hdr_fill (fp, op,sizeof (struct fc_ns_rft )); hton24(ct->payload.rft.fid.fp_fid,
PATCH 63/64 libfc: don't swap OX_ID and RX_ID when sending BA_RJT
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
I saw an lport debug message from the exchange manager saying:
"lport 70500: Received response for out of range oxid:ffff"
A trace showed this was a BA_RJT sent due to an incoming ABTS which arrived on an unknown exchange. So, the sender of the BA_RJT was in error, but in this case, both the initiator and responder were the same machine.
The OX_ID and RX_ID should not have been reversed in this case.
---
drivers/scsi/libfc/fc_exch.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_exch.c +2 -2
@@ -1017,8 +1017,8 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp,*/ memcpy (fh->fh_s_id, rx_fh->fh_d_id,3 );memcpy (fh->fh_d_id, rx_fh->fh_s_id,3 ); - fh->fh_ox_id = rx_fh->fh_rx_id; - fh->fh_rx_id = rx_fh->fh_ox_id; + fh->fh_ox_id = rx_fh->fh_ox_id; + fh->fh_rx_id = rx_fh->fh_rx_id; fh->fh_seq_cnt = rx_fh->fh_seq_cnt; fh->fh_r_ctl =FC_RCTL_BA_RJT ; fh->fh_type =FC_TYPE_BLS ;
PATCH 64/64 fcoe: flush per-cpu thread work when destroying interface
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
This fixes one cause of an occational problem when unloading libfc where the exchange manager pool doesn't have all items freed.
The existing WARN_ON(mp->total_exches <= 0) isn't hit. However, note that total_exches is decremented when the exchange is completed, and it can be held with a refcnt for a while after that.
I'm not sure what the offending exchange is, but I suspect it is an incoming request, because outgoing state machines should be all stopped at this point.
Note that although receive is stopped before the exchange manager is freed, there could still be active threads handling received frames.
This patch flushes the queues by allocating a new skb and sending it through, and have the thread handle this new skb specially. This is similar to the way the work queues are flushed now by putting work items in them and waiting until they make it through the queue.
An skb->destructor function is used to inform us of the completion of the flush, and the fr_dev() is left NULL to indicate to fcoe_percpu_receive_thread() that the skb should be just freed. There's already a check for the lp being NULL which prints a message.
We skip printing the message if the destructor is for flushing.
---
drivers/scsi/fcoe/fcoe.c | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 files changed, 40 insertions(+), 2 deletions(-)
drivers/scsi/fcoe/fcoe.c +40 -2
@@ -57,6 +57,9 @@ MODULE_PARM_DESC(ddp_min, "Minimum I/O size in bytes for " \DEFINE_MUTEX (fcoe_config_mutex); +/* fcoe_percpu_clean completion. Waiter protected by fcoe_create_mutex */ +static DECLARE_COMPLETION (fcoe_flush_completion); +/* fcoe host list */ /* must only by accessed under the RTNL mutex */ LIST_HEAD (fcoe_hostlist);
@@ -827,7 +830,7 @@ static void fcoe_percpu_thread_create(unsigned int cpu) thread =kthread_create (fcoe_percpu_receive_thread, (void *)p,"fcoethread/%d" , cpu); -if (likely (!IS_ERR (p->thread))) { +if (likely (!IS_ERR (thread))) {kthread_bind (thread, cpu);wake_up_process (thread);
@@ -1300,6 +1303,15 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp) }/** +* fcoe_percpu_flush_done() - Indicate percpu queue flush completion. +* @skb: the skb being completed. +*/ +static void fcoe_percpu_flush_done (struct sk_buff *skb) +{ +complete (&fcoe_flush_completion); +} + +/** * fcoe_percpu_receive_thread() - recv thread per cpu * @arg: ptr to the fcoe per cpu struct *
@@ -1338,7 +1350,8 @@ int fcoe_percpu_receive_thread(void *arg) fr =fcoe_dev_from_skb (skb); lp = fr->fr_dev;if (unlikely (lp ==NULL )) { -FCOE_NETDEV_DBG (skb->dev,"Invalid HBA Structure" ); +if (skb->destructor != fcoe_percpu_flush_done) +FCOE_NETDEV_DBG (skb->dev,"NULL lport in skb" );kfree_skb (skb);continue ; }
@@ -1799,6 +1812,13 @@ int fcoe_link_ok(struct fc_lport *lp)/** * fcoe_percpu_clean() - Clear the pending skbs for an lport * @lp: the fc_lport +* +* Must be called with fcoe_create_mutex held to single-thread completion. +* +* This flushes the pending skbs by adding a new skb to each queue and +* waiting until they are all freed. This assures us that not only are +* there no packets that will be handled by the lport, but also that any +* threads already handling packet have returned. */ void fcoe_percpu_clean (struct fc_lport *lp) {
@@ -1823,7 +1843,25 @@ void fcoe_percpu_clean(struct fc_lport *lp)kfree_skb (skb); } } + +if (!pp->thread || !cpu_online (cpu)) { +spin_unlock_bh (&pp->fcoe_rx_list.lock); +continue ; + } + + skb =dev_alloc_skb (0 ); +if (!skb) { +spin_unlock_bh (&pp->fcoe_rx_list.lock); +continue ; + } + skb->destructor = fcoe_percpu_flush_done; + +__skb_queue_tail (&pp->fcoe_rx_list, skb); +if (pp->fcoe_rx_list.qlen ==1 ) +wake_up_process (pp->thread);spin_unlock_bh (&pp->fcoe_rx_list.lock); + +wait_for_completion (&fcoe_flush_completion); } }