Open-FCoE Features for 2.6.32
Subsystems (3)
cover Open-FCoE Features for 2.6.32
The following series contains the first set of features for libfc, libfcoe and fcoe.
The largest change is to share an Exchange Manager amongst virtual interfaces (VLANs) on a physical interface. This will change will also help with NPIV support which should come in a later patch set.
Other than that, there are a lot of miscellaneous fixes and improvements to all three modules.
---
Joe Eykholt (10):
libfc: fix: cancel rport retry timer
libfc: fc_rport_logoff should not drop the lock
libfc: rename rport state "NONE" to "DELETE".
libfc: fix WARNING from fc_seq_start_next on closed exchanges
libfc: in fc_lport_destroy, flush rports after turning off link
libfc: stop login after fabric logoff
libfc: rename lport NONE state to DISABLED
fcoe: stop delivery of received frames before doing lport_destroy()
libfc: change debug messages to give host number.
libfc: remove extra semicolons from debug macros
Robert Love (1):
libfc: Remove the FC_EM_DBG macro
Vasu Dev (5):
fcoe: removes phys_dev and renames real_dev to netdev.
fcoe, libfc: adds offload EM per eth device with only single xid range per EM
fcoe: modifies fcoe_hostlist_lock uses as prep work to add shared offload EM fcoe, fnic, libfc: modifies current code paths to use EM anchor list fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs
Yi Zou (6):
libfc: Remove page flags check for sglist
libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data
fcoe: Remove ifdef for NETIF_F_FCOE_CRC and NETIF_F_FSO
fcoe: Call dev_ethtool_get_settings() in fcoe_link_ok
libfcoe: Set fip_flags according to fcf and lport's capability of SPMA support
fcoe: Fix validation of mac address when checking for spma support
drivers/scsi/fcoe/fcoe.c | 250 +++++++++++++++++++----------- drivers/scsi/fcoe/fcoe.h | 8 - drivers/scsi/fcoe/libfcoe.c | 14 +- drivers/scsi/fnic/fnic_fcs.c | 2 drivers/scsi/fnic/fnic_main.c | 20 +- drivers/scsi/libfc/fc_exch.c | 337 ++++++++++++++++++++++------------------- drivers/scsi/libfc/fc_fcp.c | 29 ---- drivers/scsi/libfc/fc_lport.c | 61 ++++++- drivers/scsi/libfc/fc_rport.c | 83 ++++++---- include/scsi/fc_frame.h | 7 - include/scsi/libfc.h | 126 +++++++-------- 11 files changed, 518 insertions(+), 419 deletions(-)
Signature · 1 line
//Rob
PATCH 1/22 fcoe: Fix validation of mac address when checking for spma support
From: Yi Zou <[email protected]>
Fix this bug of validating the wrong mac address while checking for SAN MAC address support from LLD as we should check ha->addr not ctlr.ctl_src_addr.
---
drivers/scsi/fcoe/fcoe.c | 2 +- 1 files changed, 1 insertions(+), 1 deletions(-)
drivers/scsi/fcoe/fcoe.c +1 -1
@@ -329,7 +329,7 @@ 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 (fc->ctlr.ctl_src_addr))) { + (is_valid_ether_addr (ha->addr))) {memcpy (fc->ctlr.ctl_src_addr, ha->addr,ETH_ALEN ); fc->ctlr.spma =1 ;break ;
PATCH 2/22 libfcoe: Set fip_flags according to fcf and lport's capability of SPMA support
In reply to Robert LoveFrom: Yi Zou <[email protected]>
When encap the els for FIP, set the fip_flags according to the FCF and lport's capability of supporting SPMA or FPMA or both.
---
drivers/scsi/fcoe/libfcoe.c | 12 +++++++++--- 1 files changed, 9 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/libfcoe.c +9 -3
@@ -413,10 +413,18 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip,struct fip_mac_desc *mac;struct fcoe_fcf *fcf;size_t dlen; +u16 fip_flags; fcf = fip->sel_fcf;if (!fcf)return -ENODEV ; + +/* set flags according to both FCF and lport's capability on SPMA */ + fip_flags = fcf->flags; + fip_flags &= fip->spma ?FIP_FL_SPMA |FIP_FL_FPMA :FIP_FL_FPMA ; +if (!fip_flags) +return -ENODEV ; + dlen =sizeof (struct fip_encaps ) + skb->len;/* len before push */ cap = (struct fip_encaps_head *)skb_push (skb,sizeof (*cap));
@@ -429,9 +437,7 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, cap->fip.fip_op =htons (FIP_OP_LS ); cap->fip.fip_subcode =FIP_SC_REQ ; cap->fip.fip_dl_len =htons ((dlen +sizeof (*mac)) /FIP_BPW ); - cap->fip.fip_flags =htons (FIP_FL_FPMA ); -if (fip->spma) - cap->fip.fip_flags |=htons (FIP_FL_SPMA ); + cap->fip.fip_flags =htons (fip_flags); cap->encaps.fd_desc.fip_dtype = dtype; cap->encaps.fd_desc.fip_dlen = dlen /FIP_BPW ;
PATCH 3/22 fcoe: Call dev_ethtool_get_settings() in fcoe_link_ok
In reply to Robert LoveFrom: Yi Zou <[email protected]>
No need to check phys_dev here, just call dev_ethtool_get_settings() directly will take care of this.
---
drivers/scsi/fcoe/fcoe.c | 38 +++++++++++++++++--------------------- 1 files changed, 17 insertions(+), 21 deletions(-)
drivers/scsi/fcoe/fcoe.c +17 -21
@@ -1635,29 +1635,25 @@ int fcoe_link_ok(struct fc_lport *lp)struct fcoe_softc *fc =lport_priv (lp);struct net_device *dev = fc->real_dev;struct ethtool_cmd ecmd = {ETHTOOL_GSET }; -int rc =0 ; -if ((dev->flags &IFF_UP ) &&netif_carrier_ok (dev)) { - dev = fc->phys_dev; -if (dev->ethtool_ops->get_settings) { - dev->ethtool_ops->get_settings (dev, &ecmd); - lp->link_supported_speeds &= - ~(FC_PORTSPEED_1GBIT |FC_PORTSPEED_10GBIT ); -if (ecmd.supported & (SUPPORTED_1000baseT_Half | - SUPPORTED_1000baseT_Full)) - lp->link_supported_speeds |=FC_PORTSPEED_1GBIT ; -if (ecmd.supported & SUPPORTED_10000baseT_Full) - lp->link_supported_speeds |= -FC_PORTSPEED_10GBIT ; -if (ecmd.speed ==SPEED_1000 ) - lp->link_speed =FC_PORTSPEED_1GBIT ; -if (ecmd.speed ==SPEED_10000 ) - lp->link_speed =FC_PORTSPEED_10GBIT ; - } - }else - rc =-1 ; +if ((dev->flags &IFF_UP ) &&netif_carrier_ok (dev) && + (!dev_ethtool_get_settings (dev, &ecmd))) { + lp->link_supported_speeds &= + ~(FC_PORTSPEED_1GBIT |FC_PORTSPEED_10GBIT ); +if (ecmd.supported & (SUPPORTED_1000baseT_Half | + SUPPORTED_1000baseT_Full)) + lp->link_supported_speeds |=FC_PORTSPEED_1GBIT ; +if (ecmd.supported & SUPPORTED_10000baseT_Full) + lp->link_supported_speeds |= +FC_PORTSPEED_10GBIT ; +if (ecmd.speed ==SPEED_1000 ) + lp->link_speed =FC_PORTSPEED_1GBIT ; +if (ecmd.speed ==SPEED_10000 ) + lp->link_speed =FC_PORTSPEED_10GBIT ; -return rc; +return 0 ; + } +return -1 ; }/**
PATCH 4/22 libfc: remove extra semicolons from debug macros
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
This is unlikely to cause any problems, but the libfc debug macros introduce extra undesirable semicolons.
---
include/scsi/libfc.h | 20 ++++++++++---------- 1 files changed, 10 insertions(+), 10 deletions(-)
include/scsi/libfc.h +10 -10
@@ -51,22 +51,22 @@ do { \do { \CMD ; \ }while (0 ); \ -}while (0 ); +}while (0 ) #define FC_LIBFC_DBG(fmt, args...) \ FC_CHECK_LOGGING(FC_LIBFC_LOGGING, \ - printk(KERN_INFO "libfc: " fmt, ##args);) + printk(KERN_INFO "libfc: " fmt, ##args)) #define FC_LPORT_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ printk(KERN_INFO "lport: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args);) + fc_host_port_id(lport->host), ##args)) #define FC_DISC_DBG(disc, fmt, args...) \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \ printk(KERN_INFO "disc: %6x: " fmt, \ fc_host_port_id(disc->lport->host), \ - ##args);) + ##args)) #define FC_RPORT_DBG(rport, fmt, args...) \ do { \
@@ -75,31 +75,31 @@ do { \FC_CHECK_LOGGING (FC_RPORT_LOGGING , \printk (KERN_INFO "rport: %6x: %6x: " fmt, \fc_host_port_id (lport->host), \ - rport->port_id, ##args);) \ -} while (0); + rport->port_id, ##args)); \ +}while (0 ) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \ printk(KERN_INFO "fcp: %6x: %6x: " fmt, \ fc_host_port_id(pkt->lp->host), \ - pkt->rport->port_id, ##args);) + pkt->rport->port_id, ##args)) #define FC_EM_DBG(em, fmt, args...) \ FC_CHECK_LOGGING(FC_EM_LOGGING, \ printk(KERN_INFO "em: %6x: " fmt, \ fc_host_port_id(em->lp->host), \ - ##args);) + ##args)) #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ printk(KERN_INFO "exch: %6x: %4x: " fmt, \ fc_host_port_id(exch->lp->host), \ - exch->xid, ##args);) + exch->xid, ##args)) #define FC_SCSI_DBG(lport, fmt, args...) \FC_CHECK_LOGGING (FC_SCSI_LOGGING , \printk (KERN_INFO "scsi: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args);) + fc_host_port_id(lport->host), ##args))/* * libfc error codes
PATCH 5/22 libfc: change debug messages to give host number.
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
libfc debug messages currently show 'lport: <fc-id>:' wher <fc-id> is the hex assigned port-id. When the lport is logged off, that will be zero, so its hard to distinguish which instance is involved. The FC-ID can change if the port is re-patched or changes VSANs.
Two lports may even have the same FC-ID if connected to isolated SANs.
Change the debug messages to print the SCSI host number "hostN:", which will not change for the life of the lport.
Still show the FC_ID on lport messages.
Also, add a macro to FC_RPORT_ID_DBG for rport debugging where there's no rdata structure involved. It takes the lport and port_id as parameters. Use this in fc_rport_recv_plogi_req() and fc_rport_recv_logo_req().
---
include/scsi/libfc.h | 36 ++++++++++++++++++++---------------- 1 files changed, 20 insertions(+), 16 deletions(-)
include/scsi/libfc.h +20 -16
@@ -59,47 +59,51 @@ do { \ #define FC_LPORT_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_LPORT_LOGGING, \ - printk(KERN_INFO "lport: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args)) + printk(KERN_INFO "host%u: lport %6x: " fmt, \ + (lport)->host->host_no, \ + fc_host_port_id((lport)->host), ##args)) #define FC_DISC_DBG(disc, fmt, args...) \ FC_CHECK_LOGGING(FC_DISC_LOGGING, \ - printk(KERN_INFO "disc: %6x: " fmt, \ - fc_host_port_id(disc->lport->host), \ + printk(KERN_INFO "host%u: disc: " fmt, \ + (disc)->lport->host->host_no, \ ##args)) +#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...) \ + FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ + printk(KERN_INFO "host%u: rport %6x: " fmt, \ + (lport)->host->host_no, \ + (port_id), ##args)) + #define FC_RPORT_DBG(rport, fmt, args...) \ do { \ struct fc_rport_libfc_priv *rdata = rport->dd_data; \ struct fc_lport *lport = rdata->local_port; \ - FC_CHECK_LOGGING(FC_RPORT_LOGGING, \ - printk(KERN_INFO "rport: %6x: %6x: " fmt, \ - fc_host_port_id(lport->host), \ - rport->port_id, ##args)); \ + FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \ } while (0) #define FC_FCP_DBG(pkt, fmt, args...) \ FC_CHECK_LOGGING(FC_FCP_LOGGING, \ - printk(KERN_INFO "fcp: %6x: %6x: " fmt, \ - fc_host_port_id(pkt->lp->host), \ + printk(KERN_INFO "host%u: fcp: %6x: " fmt, \ + (pkt)->lp->host->host_no, \ pkt->rport->port_id, ##args)) #define FC_EM_DBG(em, fmt, args...) \ FC_CHECK_LOGGING(FC_EM_LOGGING, \ - printk(KERN_INFO "em: %6x: " fmt, \ - fc_host_port_id(em->lp->host), \ + printk(KERN_INFO "host%u: em: " fmt, \ + (em)->lp->host->host_no, \ ##args)) #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ - printk(KERN_INFO "exch: %6x: %4x: " fmt, \ - fc_host_port_id(exch->lp->host), \ + printk(KERN_INFO "host%u: xid %4x: " fmt, \ + (exch)->lp->host->host_no, \ exch->xid, ##args)) #define FC_SCSI_DBG(lport, fmt, args...) \ FC_CHECK_LOGGING(FC_SCSI_LOGGING, \ - printk(KERN_INFO "scsi: %6x: " fmt, \ - fc_host_port_id(lport->host), ##args)) + printk(KERN_INFO "host%u: scsi: " fmt, \ + (lport)->host->host_no, ##args))/* * libfc error codes
PATCH 6/22 fcoe: stop delivery of received frames before doing lport_destroy()
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
To be more sure that no more input arrives at the local port as it is being destroyed, clean the queues in the per-cpu receive threads.
---
drivers/scsi/fcoe/fcoe.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-)
drivers/scsi/fcoe/fcoe.c +3 -3
@@ -466,6 +466,9 @@ static int fcoe_if_destroy(struct net_device *netdev)/* tear-down the FCoE controller */ fcoe_ctlr_destroy (&fc->ctlr); +/* Free queued packets for the per-CPU receive threads */ +fcoe_percpu_clean (lp); +/* Cleanup the fc_lport */ fc_lport_destroy (lp);fc_fcp_destroy (lp);
@@ -478,9 +481,6 @@ static int fcoe_if_destroy(struct net_device *netdev)if (lp->emp)fc_exch_mgr_free (lp->emp); -/* Free the per-CPU receive threads */ -fcoe_percpu_clean (lp); -/* Free existing skbs */ fcoe_clean_pending_queue (lp);
PATCH 7/22 libfc: rename lport NONE state to DISABLED
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The state NONE was meant to be invalid, but has been used as the initial state. Rename it to be DISABLED, as more descriptive. Further patches will make it the like the RESET state, except it won't transition to FLOGI until fc_lport_fabric_login() is called.
---
drivers/scsi/libfc/fc_exch.c | 2 +- drivers/scsi/libfc/fc_lport.c | 12 ++++++------ include/scsi/libfc.h | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-)
drivers/scsi/libfc/fc_exch.c +1 -1
@@ -1875,7 +1875,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,u32 f_ctl;/* lport lock ? */ -if (!lp || !mp || (lp->state ==LPORT_ST_NONE )) { +if (!lp || !mp || lp->state ==LPORT_ST_DISABLED ) {FC_LPORT_DBG (lp,"Receiving frames for an lport that " "has not been initialized correctly\n" );fc_frame_free (fp);
drivers/scsi/libfc/fc_lport.c +6 -6
@@ -113,7 +113,7 @@ static void fc_lport_enter_ready(struct fc_lport *);static void fc_lport_enter_logo (struct fc_lport *);static const char *fc_lport_state_names[] = { - [LPORT_ST_NONE ] ="none" , + [LPORT_ST_DISABLED ] ="disabled" , [LPORT_ST_FLOGI ] ="FLOGI" , [LPORT_ST_DNS ] ="dNS" , [LPORT_ST_RPN_ID ] ="RPN_ID" ,
@@ -550,7 +550,7 @@ int fc_fabric_login(struct fc_lport *lport)int rc =-1 ;mutex_lock (&lport->lp_mutex); -if (lport->state ==LPORT_ST_NONE ) { +if (lport->state ==LPORT_ST_DISABLED ) {fc_lport_enter_reset (lport); rc =0 ; }
@@ -637,7 +637,7 @@ EXPORT_SYMBOL(fc_fabric_logoff);int fc_lport_destroy (struct fc_lport *lport) {mutex_lock (&lport->lp_mutex); - lport->state =LPORT_ST_NONE ; + lport->state =LPORT_ST_DISABLED ; lport->link_up =0 ; lport->tt.frame_send = fc_frame_drop;mutex_unlock (&lport->lp_mutex);
@@ -992,7 +992,7 @@ static void fc_lport_error(struct fc_lport *lport, struct fc_frame *fp)schedule_delayed_work (&lport->retry_work, delay); }else {switch (lport->state) { -case LPORT_ST_NONE : +case LPORT_ST_DISABLED :case LPORT_ST_READY :case LPORT_ST_RESET :case LPORT_ST_RPN_ID :
@@ -1316,7 +1316,7 @@ static void fc_lport_timeout(struct work_struct *work)mutex_lock (&lport->lp_mutex);switch (lport->state) { -case LPORT_ST_NONE : +case LPORT_ST_DISABLED :case LPORT_ST_READY :case LPORT_ST_RESET :WARN_ON (1 );
@@ -1550,7 +1550,7 @@ int fc_lport_config(struct fc_lport *lport)INIT_DELAYED_WORK (&lport->retry_work, fc_lport_timeout);mutex_init (&lport->lp_mutex); -fc_lport_state_enter (lport,LPORT_ST_NONE ); +fc_lport_state_enter (lport,LPORT_ST_DISABLED );fc_lport_add_fc4_type (lport,FC_TYPE_FCP );fc_lport_add_fc4_type (lport,FC_TYPE_CT );
include/scsi/libfc.h +1 -1
@@ -129,7 +129,7 @@ do { \* FC HBA status */ enum fc_lport_state { -LPORT_ST_NONE =0 , +LPORT_ST_DISABLED =0 ,LPORT_ST_FLOGI ,LPORT_ST_DNS ,LPORT_ST_RPN_ID ,
PATCH 8/22 libfc: stop login after fabric logoff
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
When removing the fcoe module, several lports were being shut down through fc_lport_fabric_logoff().
Occasionally, one would enter reset state before fc_lport_destroy() was called, and since link_up was still true, it would log back in.
If we just clear link_up earlier, then we wouldn't be accepting LOGO requests from other initiators while we are shutting down.
Fix by changing the LOGO response handler to enter DISABLED instead of RESET. Add an fc_lport_enter_disabled() function which does what fc_lport_enter_reset() did, except it doesn't proceed to FLOGI state.
Move the code that was common between fc_lport_enter_reset() and fc_lport_enter_disabled() into a new fc_lport_reset_locked() function.
---
drivers/scsi/libfc/fc_lport.c | 42 +++++++++++++++++++++++++++++++++-------- 1 files changed, 34 insertions(+), 8 deletions(-)
drivers/scsi/libfc/fc_lport.c +34 -8
@@ -930,19 +930,14 @@ int fc_lport_reset(struct fc_lport *lport)EXPORT_SYMBOL (fc_lport_reset);/** -* fc_rport_enter_reset() - Reset the local port +* fc_lport_reset_locked() - Reset the local port * @lport: Fibre Channel local port to be reset * * Locking Note: The lport lock is expected to be held before calling * this routine. */ -static void fc_lport_enter_reset (struct fc_lport *lport) +static void fc_lport_reset_locked (struct fc_lport *lport) { -FC_LPORT_DBG (lport,"Entered RESET state from %s state\n" , -fc_lport_state (lport)); - -fc_lport_state_enter (lport,LPORT_ST_RESET ); -if (lport->dns_rp) lport->tt.rport_logoff (lport->dns_rp);
@@ -956,12 +951,43 @@ static void fc_lport_enter_reset(struct fc_lport *lport) lport->tt.exch_mgr_reset (lport,0 ,0 );fc_host_fabric_name (lport->host) =0 ;fc_host_port_id (lport->host) =0 ; +} + +/** +* fc_lport_enter_reset() - Reset the local port +* @lport: Fibre Channel local port to be reset +* +* Locking Note: The lport lock is expected to be held before calling +* this routine. +*/ +static void fc_lport_enter_reset (struct fc_lport *lport) +{ +FC_LPORT_DBG (lport,"Entered RESET state from %s state\n" , +fc_lport_state (lport)); +fc_lport_state_enter (lport,LPORT_ST_RESET ); +fc_lport_reset_locked (lport);if (lport->link_up)fc_lport_enter_flogi (lport); }/** +* fc_lport_enter_disabled() - disable the local port +* @lport: Fibre Channel local port to be reset +* +* Locking Note: The lport lock is expected to be held before calling +* this routine. +*/ +static void fc_lport_enter_disabled (struct fc_lport *lport) +{ +FC_LPORT_DBG (lport,"Entered disabled state from %s state\n" , +fc_lport_state (lport)); + +fc_lport_state_enter (lport,LPORT_ST_DISABLED ); +fc_lport_reset_locked (lport); +} + +/** * fc_lport_error() - Handler for any errors * @lport: The fc_lport object * @fp: The frame pointer
@@ -1382,7 +1408,7 @@ static void fc_lport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, op =fc_frame_payload_op (fp);if (op ==ELS_LS_ACC ) -fc_lport_enter_reset (lport); +fc_lport_enter_disabled (lport);else fc_lport_error (lport, fp);
PATCH 9/22 libfc: in fc_lport_destroy, flush rports after turning off link
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
During an fcoe module unload, we saw a problem where fc_rport_work() finds the lport has been freed. The rdata points to an area containing 0x6b6b6b6b... the pool poison value from kmem_free().
In fcoe_if_destroy() we call fc_fabric_logoff() then fc_lport_destroy(). fc_fabric_logoff() flushes the remote port work, but we're still receiving requests, and an RSCN or PLOGI arrives which creates more rports.
Note that although the LLD also checks link_up, it doesn't do it under the lport mutex, so it can deliver frames to fc_lport_recv_req() even after link_up is cleared.
So, re-check link_up there.
We need to flush the rports by calling disc_stop_final() after we clear link_up.
---
drivers/scsi/libfc/fc_lport.c | 6 +++++- 1 files changed, 5 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_lport.c +5 -1
@@ -643,6 +643,7 @@ int fc_lport_destroy(struct fc_lport *lport)mutex_unlock (&lport->lp_mutex); lport->tt.fcp_abort_io (lport); + lport->tt.disc_stop_final (lport); lport->tt.exch_mgr_reset (lport,0 ,0 );return 0 ; }
@@ -844,7 +845,10 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,* RSCN here. These don't require a session. * Even if we had a session, it might not be ready. */ -if (fh->fh_type ==FC_TYPE_ELS && fh->fh_r_ctl ==FC_RCTL_ELS_REQ ) { +if (!lport->link_up) +fc_frame_free (fp); +else if (fh->fh_type ==FC_TYPE_ELS && + fh->fh_r_ctl ==FC_RCTL_ELS_REQ ) {/* * Check opcode. */
PATCH 10/22 libfc: fix WARNING from fc_seq_start_next on closed exchanges
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
We saw periodic messages like:
WARNING: at drivers/scsi/libfc/fc_exch.c:825 fc_seq_start_next+0x30/0x4b
This was due to trying to allocate a sequence in a request handler when the exchange had been reset.
Delete the WARN_ON.
---
drivers/scsi/libfc/fc_exch.c | 1 - 1 files changed, 0 insertions(+), 1 deletions(-)
drivers/scsi/libfc/fc_exch.c +0 -1
@@ -822,7 +822,6 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp)struct fc_exch *ep =fc_seq_exch (sp);spin_lock_bh (&ep->ex_lock); -WARN_ON ((ep->esb_stat &ESB_ST_COMPLETE ) !=0 ); sp =fc_seq_start_next_locked (sp);spin_unlock_bh (&ep->ex_lock);
PATCH 11/22 libfc: rename rport state "NONE" to "DELETE".
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
State RPORT_ST_NONE was intented to be an invalid state (0), never used. This was a misguided attempt to be sure it was always initialized. Having an extra state meaning nothing requires switch statements to have a case covering that state.
State NONE has been used instead to mean the remote port is being deleted. Changing the name to RPORT_ST_DELETE.
---
drivers/scsi/libfc/fc_rport.c | 28 ++++++++++++++-------------- include/scsi/libfc.h | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-)
drivers/scsi/libfc/fc_rport.c +14 -14
@@ -77,13 +77,13 @@ static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);static void fc_rport_work (struct work_struct *);static const char *fc_rport_state_names[] = { - [RPORT_ST_NONE ] ="None" , [RPORT_ST_INIT ] ="Init" , [RPORT_ST_PLOGI ] ="PLOGI" , [RPORT_ST_PRLI ] ="PRLI" , [RPORT_ST_RTV ] ="RTV" , [RPORT_ST_READY ] ="Ready" , [RPORT_ST_LOGO ] ="LOGO" , + [RPORT_ST_DELETE ] ="Delete" , };static void fc_rport_rogue_destroy (struct device *dev)
@@ -326,8 +326,8 @@ int fc_rport_logoff(struct fc_rport *rport)FC_RPORT_DBG (rport,"Remove port\n" ); -if (rdata->rp_state ==RPORT_ST_NONE ) { -FC_RPORT_DBG (rport,"Port in NONE state, not removing\n" ); +if (rdata->rp_state ==RPORT_ST_DELETE ) { +FC_RPORT_DBG (rport,"Port in Delete state, not removing\n" );mutex_unlock (&rdata->rp_mutex); goto out; }
@@ -335,10 +335,10 @@ int fc_rport_logoff(struct fc_rport *rport)fc_rport_enter_logo (rport);/* -* Change the state to NONE so that we discard +* Change the state to Delete so that we discard * the response. */ -fc_rport_state_enter (rport,RPORT_ST_NONE ); +fc_rport_state_enter (rport,RPORT_ST_DELETE );mutex_unlock (&rdata->rp_mutex);
@@ -405,7 +405,7 @@ static void fc_rport_timeout(struct work_struct *work)break ;case RPORT_ST_READY :case RPORT_ST_INIT : -case RPORT_ST_NONE : +case RPORT_ST_DELETE :break ; }
@@ -433,14 +433,14 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)case RPORT_ST_PRLI :case RPORT_ST_LOGO : rdata->event =RPORT_EV_FAILED ; -fc_rport_state_enter (rport,RPORT_ST_NONE ); +fc_rport_state_enter (rport,RPORT_ST_DELETE );queue_work (rport_event_queue, &rdata->event_work);break ;case RPORT_ST_RTV :fc_rport_enter_ready (rport);break ; -case RPORT_ST_NONE : +case RPORT_ST_DELETE :case RPORT_ST_READY :case RPORT_ST_INIT :break ;
@@ -652,7 +652,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, }else {FC_RPORT_DBG (rport,"Bad ELS response for PRLI command\n" ); rdata->event =RPORT_EV_FAILED ; -fc_rport_state_enter (rport,RPORT_ST_NONE ); +fc_rport_state_enter (rport,RPORT_ST_DELETE );queue_work (rport_event_queue, &rdata->event_work); }
@@ -703,7 +703,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp, }else {FC_RPORT_DBG (rport,"Bad ELS response for LOGO command\n" ); rdata->event =RPORT_EV_LOGO ; -fc_rport_state_enter (rport,RPORT_ST_NONE ); +fc_rport_state_enter (rport,RPORT_ST_DELETE );queue_work (rport_event_queue, &rdata->event_work); }
@@ -1012,7 +1012,7 @@ static void fc_rport_recv_plogi_req(struct fc_rport *rport, "- ignored for now\n", rdata->rp_state);/* XXX TBD - should reset */ break ; -case RPORT_ST_NONE : +case RPORT_ST_DELETE :default :FC_RPORT_DBG (rport,"Received PLOGI in unexpected " "state %d\n" , rdata->rp_state);
@@ -1238,7 +1238,7 @@ static void fc_rport_recv_prlo_req(struct fc_rport *rport, struct fc_seq *sp,FC_RPORT_DBG (rport,"Received PRLO request while in state %s\n" ,fc_rport_state (rport)); -if (rdata->rp_state ==RPORT_ST_NONE ) { +if (rdata->rp_state ==RPORT_ST_DELETE ) {fc_frame_free (fp);return ; }
@@ -1271,13 +1271,13 @@ static void fc_rport_recv_logo_req(struct fc_rport *rport, struct fc_seq *sp,FC_RPORT_DBG (rport,"Received LOGO request while in state %s\n" ,fc_rport_state (rport)); -if (rdata->rp_state ==RPORT_ST_NONE ) { +if (rdata->rp_state ==RPORT_ST_DELETE ) {fc_frame_free (fp);return ; } rdata->event =RPORT_EV_LOGO ; -fc_rport_state_enter (rport,RPORT_ST_NONE ); +fc_rport_state_enter (rport,RPORT_ST_DELETE );queue_work (rport_event_queue, &rdata->event_work); lport->tt.seq_els_rsp_send (sp,ELS_LS_ACC ,NULL );
include/scsi/libfc.h +1 -1
@@ -147,13 +147,13 @@ enum fc_disc_event { };enum fc_rport_state { -RPORT_ST_NONE =0 ,RPORT_ST_INIT ,/* initialized */ RPORT_ST_PLOGI ,/* waiting for PLOGI completion */ RPORT_ST_PRLI ,/* waiting for PRLI completion */ RPORT_ST_RTV ,/* waiting for RTV completion */ RPORT_ST_READY ,/* ready for use */ RPORT_ST_LOGO ,/* port logout sent */ +RPORT_ST_DELETE ,/* port being deleted */ };enum fc_rport_trans_state {
PATCH 12/22 libfc: fc_rport_logoff should not drop the lock
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
fc_rport_logoff drops the rport lock in order to cancel work that may be pending. This is undesirable as the state can completely change, and the caller may not expect that the lock could've been dropped.
If there is work pending, it will acquire the rdata mutex and so we're protected and can change the event from READY to DELETE. Queue the work only if there is no event already pending.
There were a couple other cases where the state was set to DELETE and work queued, even though the state may have already been DELETE. Fix these using a common function fc_rport_enter_delete().
---
drivers/scsi/libfc/fc_rport.c | 60 ++++++++++++++++++++++++++--------------- 1 files changed, 38 insertions(+), 22 deletions(-)
drivers/scsi/libfc/fc_rport.c +38 -22
@@ -230,6 +230,7 @@ static void fc_rport_work(struct work_struct *work) ids.port_name = rport->port_name; ids.node_name = rport->node_name; + rdata->event =RPORT_EV_NONE ;mutex_unlock (&rdata->rp_mutex); new_rport =fc_remote_port_add (lport->host,0 , &ids);
@@ -311,6 +312,37 @@ int fc_rport_login(struct fc_rport *rport) }/** +* fc_rport_enter_delete() - schedule a remote port to be deleted. +* @rport: Fibre Channel remote port +* @event: event to report as the reason for deletion +* +* Locking Note: Called with the rport lock held. +* +* Allow state change into DELETE only once. +* +* Call queue_work only if there's no event already pending. +* Set the new event so that the old pending event will not occur. +* Since we have the mutex, even if fc_rport_work() is already started, +* it'll see the new event. +*/ +static void fc_rport_enter_delete (struct fc_rport *rport, +enum fc_rport_event event) +{ +struct fc_rport_libfc_priv *rdata = rport->dd_data; + +if (rdata->rp_state ==RPORT_ST_DELETE ) +return ; + +FC_RPORT_DBG (rport,"Delete port\n" ); + +fc_rport_state_enter (rport,RPORT_ST_DELETE ); + +if (rdata->event ==RPORT_EV_NONE ) +queue_work (rport_event_queue, &rdata->event_work); + rdata->event = event; +} + +/** * fc_rport_logoff() - Logoff and remove an rport * @rport: Fibre Channel remote port to be removed *
@@ -338,17 +370,7 @@ int fc_rport_logoff(struct fc_rport *rport)* Change the state to Delete so that we discard * the response. */ -fc_rport_state_enter (rport,RPORT_ST_DELETE ); - -mutex_unlock (&rdata->rp_mutex); - -cancel_delayed_work_sync (&rdata->retry_work); - -mutex_lock (&rdata->rp_mutex); - - rdata->event =RPORT_EV_STOP ; -queue_work (rport_event_queue, &rdata->event_work); - +fc_rport_enter_delete (rport,RPORT_EV_STOP );mutex_unlock (&rdata->rp_mutex); out:
@@ -370,8 +392,9 @@ static void fc_rport_enter_ready(struct fc_rport *rport)FC_RPORT_DBG (rport,"Port is Ready\n" ); +if (rdata->event ==RPORT_EV_NONE ) +queue_work (rport_event_queue, &rdata->event_work); rdata->event =RPORT_EV_CREATED ; -queue_work (rport_event_queue, &rdata->event_work); }/**
@@ -432,10 +455,7 @@ static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)case RPORT_ST_PLOGI :case RPORT_ST_PRLI :case RPORT_ST_LOGO : - rdata->event =RPORT_EV_FAILED ; -fc_rport_state_enter (rport,RPORT_ST_DELETE ); -queue_work (rport_event_queue, - &rdata->event_work); +fc_rport_enter_delete (rport,RPORT_EV_FAILED );break ;case RPORT_ST_RTV :fc_rport_enter_ready (rport);
@@ -651,9 +671,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp, }else {FC_RPORT_DBG (rport,"Bad ELS response for PRLI command\n" ); - rdata->event =RPORT_EV_FAILED ; -fc_rport_state_enter (rport,RPORT_ST_DELETE ); -queue_work (rport_event_queue, &rdata->event_work); +fc_rport_enter_delete (rport,RPORT_EV_FAILED ); } out:
@@ -702,9 +720,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,fc_rport_enter_rtv (rport); }else {FC_RPORT_DBG (rport,"Bad ELS response for LOGO command\n" ); - rdata->event =RPORT_EV_LOGO ; -fc_rport_state_enter (rport,RPORT_ST_DELETE ); -queue_work (rport_event_queue, &rdata->event_work); +fc_rport_enter_delete (rport,RPORT_EV_LOGO ); } out:
PATCH 13/22 libfc: fix: cancel rport retry timer
In reply to Robert LoveFrom: Joe Eykholt <[email protected]>
The timer for rport retries wasn't getting canceled, and would occasionally go off after the module was unloaded.
Add logic to cancel the timer in fc_rport_work().
Since we cancel the timer before deleting the rdata,
it is no longer necessary to do a get_device() for the pending timer.
---
drivers/scsi/libfc/fc_rport.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-)
drivers/scsi/libfc/fc_rport.c +1 -2
@@ -276,6 +276,7 @@ static void fc_rport_work(struct work_struct *work)mutex_unlock (&rdata->rp_mutex);if (rport_ops->event_callback) rport_ops->event_callback (lport, rport, event); +cancel_delayed_work_sync (&rdata->retry_work);if (trans_state ==FC_PORTSTATE_ROGUE )put_device (&rport->dev);else {
@@ -433,7 +434,6 @@ static void fc_rport_timeout(struct work_struct *work) }mutex_unlock (&rdata->rp_mutex); -put_device (&rport->dev); }/**
@@ -494,7 +494,6 @@ static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)/* no additional delay on exchange timeouts */ if (PTR_ERR (fp) == -FC_EX_TIMEOUT ) delay =0 ; -get_device (&rport->dev);schedule_delayed_work (&rdata->retry_work, delay);return ; }
PATCH 14/22 fcoe, libfc: adds exchange manager(EM) anchor list per lport and related APIs
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
Adds EM list using a anchor struct fc_exch_mgr_anchor, anchor is used to allow same EM instance sharing across more than one lport on a eth device, this implementation is per discussed design posted at
http://www.open-fcoe.org/pipermail/devel/2009-June/002566.html.
The shared EM is required for multiple lports on eth device when using multiple VLANs or NPIV.
Adds fc_exch_mgr_add API to add a EM to the lport and fc_exch_mgr_del API to delete previously added EM.
Also adds function fc_exch_mgr_destroy() to destroy allocated EM. The kref is added to the EM to keep track of EM usage count, the EM is destroyed when no longer in use upon kref reaching to zero.
The caller can specify match function to fc_exch_mgr_add, this will be used in determining exchange allocation from its EM or not.
Moved calling of fcoe_em_config below fcoe_libfc_config calling, so that list head lp->ema_list is initialized before configuring EM.
---
drivers/scsi/fcoe/fcoe.c | 14 ++++++------ drivers/scsi/libfc/fc_exch.c | 48 +++++++++++++++++++++++++++++++++++++++++ drivers/scsi/libfc/fc_lport.c | 1 + include/scsi/libfc.h | 24 +++++++++++++++++++++ 4 files changed, 80 insertions(+), 7 deletions(-)
drivers/scsi/fcoe/fcoe.c +7 -7
@@ -603,18 +603,18 @@ static int fcoe_if_create(struct net_device *netdev) goto out_netdev_cleanup; } -/* lport exch manager allocation */ - rc =fcoe_em_config (lp); +/* Initialize the library */ + rc =fcoe_libfc_config (lp, &fcoe_libfc_fcn_templ);if (rc) { -FCOE_NETDEV_DBG (netdev,"Could not configure the EM for the " +FCOE_NETDEV_DBG (netdev,"Could not configure libfc for the " "interface\n" ); - goto out_netdev_cleanup; + goto out_lp_destroy; } -/* Initialize the library */ - rc =fcoe_libfc_config (lp, &fcoe_libfc_fcn_templ); +/* lport exch manager allocation */ + rc =fcoe_em_config (lp);if (rc) { -FCOE_NETDEV_DBG (netdev,"Could not configure libfc for the " +FCOE_NETDEV_DBG (netdev,"Could not configure the EM for the " "interface\n" ); goto out_lp_destroy; }
drivers/scsi/libfc/fc_exch.c +48 -0
66 lines not on this page · raw message
drivers/scsi/libfc/fc_lport.c +1 -0
@@ -1618,6 +1618,7 @@ int fc_lport_init(struct fc_lport *lport)if (lport->link_supported_speeds &FC_PORTSPEED_10GBIT )fc_host_supported_speeds (lport->host) |=FC_PORTSPEED_10GBIT ; +INIT_LIST_HEAD (&lport->ema_list);return 0 ; }EXPORT_SYMBOL (fc_lport_init);
include/scsi/libfc.h +24 -0
@@ -348,6 +348,7 @@ static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)*/ struct fc_exch_mgr ; +struct fc_exch_mgr_anchor ;/* * Sequence.
@@ -709,6 +710,7 @@ struct fc_lport {/* Associations */ struct Scsi_Host *host;struct fc_exch_mgr *emp; +struct list_head ema_list;struct fc_rport *dns_rp;struct fc_rport *ptp_rp;void *scsi_priv;
@@ -964,6 +966,28 @@ int fc_elsct_init(struct fc_lport *lp);int fc_exch_init (struct fc_lport *lp);/* +* Adds Exchange Manager (EM) mp to lport. +* +* Adds specified mp to lport using struct fc_exch_mgr_anchor, +* the struct fc_exch_mgr_anchor allows same EM sharing by +* more than one lport with their specified match function, +* the match function is used in allocating exchange from +* added mp. +*/ +struct fc_exch_mgr_anchor *fc_exch_mgr_add (struct fc_lport *lport, +struct fc_exch_mgr *mp, +bool (*match)(struct fc_frame *)); + +/* +* Deletes Exchange Manager (EM) from lport by removing +* its anchor ema from lport. +* +* If removed anchor ema was the last user of its associated EM +* then also destroys associated EM. +*/ +void fc_exch_mgr_del (struct fc_exch_mgr_anchor *ema); + +/* * Allocates an Exchange Manager (EM). * * The EM manages exchanges for their allocation and
PATCH 15/22 libfc: Remove the FC_EM_DBG macro
In reply to Robert LoveCurrently there is a 1:1 relationship between the lport and exchange manager. This macro takes an EM as an argument and determines the lport from it. However, later patches will use an EM list per lport, so we will no longer have this 1:1 relationship- this macro must change.
The FC_EM_DBG macro is rarely used. There are four callers, two can use FC_LPORT_DBG instead and two can be removed since they're not necessary. This patch makes those changes and removes the macro.
---
drivers/scsi/libfc/fc_exch.c | 13 ++++++------- include/scsi/libfc.h | 6 ------ 2 files changed, 6 insertions(+), 13 deletions(-)
drivers/scsi/libfc/fc_exch.c +6 -7
@@ -1129,7 +1129,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, lp->tt.lport_recv (lp, sp, fp);fc_exch_release (ep);/* release from lookup */ }else { -FC_EM_DBG (mp,"exch/seq lookup failed: reject %x\n" , reject); +FC_LPORT_DBG (lp,"exch/seq lookup failed: reject %x\n" , reject);fc_frame_free (fp); } }
@@ -1235,13 +1235,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp)struct fc_seq *sp; sp =fc_seq_lookup_orig (mp, fp);/* doesn't hold sequence */ -if (!sp) { + +if (!sp)atomic_inc (&mp->stats.xid_not_found); -FC_EM_DBG (mp,"seq lookup failed\n" ); - }else { +else atomic_inc (&mp->stats.non_bls_resp); -FC_EM_DBG (mp,"non-BLS response to sequence" ); - } +fc_frame_free (fp); }
@@ -1950,7 +1949,7 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,fc_exch_recv_req (lp, mp, fp);break ;default : -FC_EM_DBG (mp,"dropping invalid frame (eof %x)" ,fr_eof (fp)); +FC_LPORT_DBG (lp,"dropping invalid frame (eof %x)" ,fr_eof (fp));fc_frame_free (fp);break ; }
include/scsi/libfc.h +0 -6
@@ -88,12 +88,6 @@ do { \ (pkt)->lp->host->host_no, \ pkt->rport->port_id, ##args)) -#define FC_EM_DBG(em, fmt, args...) \ - FC_CHECK_LOGGING(FC_EM_LOGGING, \ - printk(KERN_INFO "host%u: em: " fmt, \ - (em)->lp->host->host_no, \ - ##args)) - #define FC_EXCH_DBG(exch, fmt, args...) \ FC_CHECK_LOGGING(FC_EXCH_LOGGING, \ printk(KERN_INFO "host%u: xid %4x: " fmt, \
PATCH 16/22 fcoe, fnic, libfc: modifies current code paths to use EM anchor list
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
Modifies current code to use EM anchor list in EM allocation, EM free, EM reset, exch allocation and exch lookup code paths.
1. Modifies fc_exch_mgr_alloc to accept EM match function and then have allocated EM added to the lport using fc_exch_mgr_add API while also updating EM kref for newly added EM.
2. Updates fc_exch_mgr_free API to accept only lport pointer instead EM and then have this API free all EMs of the lport from EM anchor list.
3. Removes single lport pointer link from the EM, which was used in associating lport pointer in newly allocated exchange. Instead have lport pointer passed along new exchange allocation call path and then store passed lport pointer in newly allocated exchange, this will allow a single EM instance to be used across more than one lport and used in EM reset to reset only lport specific exchanges.
4. Modifies fc_exch_mgr_reset to reset all EMs from the EM anchor list of the lport, adds additional exch lport pointer (ep->lp) check for shared EM case to reset exchange specific to a lport requested reset.
5. Updates exch allocation API fc_exch_alloc to use EM anchor list and its anchor match func pointer. The fc_exch_alloc will walk the list of EMs until it finds a match, a match will be either null match func pointer or call to match function returning true value.
6. Updates fc_exch_recv to accept incoming frame on local port using only lport pointer and frame pointer without specifying EM instance of incoming frame. Instead modified fc_exch_recv to locate EM for the incoming frame by matching xid of incoming frame against a EM xid range. This change was required to use EM list in libfc Rx path and after this change the lport fc_exch_mgr pointer emp is not needed anymore, so removed emp pointer.
7. Updates fnic for removed lport emp pointer and above modified libfc APIs fc_exch_recv, fc_exch_mgr_alloc and fc_exch_mgr_free.
8. Removes exch_get and exch_put from libfc_function_template as these are no longer needed with EM anchor list and its match function use. Also removes its default function fc_exch_get.
A defect this patch introduced regarding the libfc initialization order in the fnic driver was fixed by Joe Eykholt <[email protected]>.
---
drivers/scsi/fcoe/fcoe.c | 16 +-- drivers/scsi/fcoe/libfcoe.c | 2 drivers/scsi/fnic/fnic_fcs.c | 2 drivers/scsi/fnic/fnic_main.c | 20 ++-- drivers/scsi/libfc/fc_exch.c | 191 +++++++++++++++++++++++++---------------- include/scsi/libfc.h | 48 ++-------- 6 files changed, 142 insertions(+), 137 deletions(-)
drivers/scsi/fcoe/fcoe.c +6 -10
@@ -423,11 +423,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,*/ static inline int fcoe_em_config (struct fc_lport *lp) { -BUG_ON (lp->emp); - - lp->emp =fc_exch_mgr_alloc (lp,FC_CLASS_3 , -FCOE_MIN_XID ,FCOE_MAX_XID ); -if (!lp->emp) +if (!fc_exch_mgr_alloc (lp,FC_CLASS_3 ,FCOE_MIN_XID , +FCOE_MAX_XID ,NULL ))return -ENOMEM ;return 0 ;
@@ -478,8 +475,7 @@ static int fcoe_if_destroy(struct net_device *netdev)scsi_remove_host (lp->host);/* There are no more rports or I/O, free the EM */ -if (lp->emp) -fc_exch_mgr_free (lp->emp); +fc_exch_mgr_free (lp);/* Free existing skbs */ fcoe_clean_pending_queue (lp);
@@ -634,7 +630,7 @@ static int fcoe_if_create(struct net_device *netdev)return rc; out_lp_destroy: -fc_exch_mgr_free (lp->emp);/* Free the EM */ +fc_exch_mgr_free (lp); out_netdev_cleanup:fcoe_netdev_cleanup (fc); out_host_put:
@@ -1277,7 +1273,7 @@ int fcoe_percpu_receive_thread(void *arg) fh =fc_frame_header_get (fp);if (fh->fh_r_ctl ==FC_RCTL_DD_SOL_DATA && fh->fh_type ==FC_TYPE_FCP ) { -fc_exch_recv (lp, lp->emp, fp); +fc_exch_recv (lp, fp);continue ; }if (fr_flags (fp) &FCPHF_CRC_UNCHECKED ) {
@@ -1298,7 +1294,7 @@ int fcoe_percpu_receive_thread(void *arg)fc_frame_free (fp);continue ; } -fc_exch_recv (lp, lp->emp, fp); +fc_exch_recv (lp, fp); }return 0 ; }
drivers/scsi/fcoe/libfcoe.c +1 -1
@@ -885,7 +885,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb) stats->RxFrames++; stats->RxWords += skb->len /FIP_BPW ; -fc_exch_recv (lp, lp->emp, fp); +fc_exch_recv (lp, fp);return ; len_err:
drivers/scsi/fnic/fnic_fcs.c +1 -1
@@ -115,7 +115,7 @@ void fnic_handle_frame(struct work_struct *work) }spin_unlock_irqrestore (&fnic->fnic_lock, flags); -fc_exch_recv (lp, lp->emp, fp); +fc_exch_recv (lp, fp); } }
drivers/scsi/fnic/fnic_main.c +9 -11
@@ -671,14 +671,6 @@ static int __devinit fnic_probe(struct pci_dev *pdev, lp->link_up =0 ; lp->tt = fnic_transport_template; - lp->emp =fc_exch_mgr_alloc (lp,FC_CLASS_3 , -FCPIO_HOST_EXCH_RANGE_START , -FCPIO_HOST_EXCH_RANGE_END ); -if (!lp->emp) { - err = -ENOMEM ; - goto err_out_remove_scsi_host; - } - lp->max_retry_count = fnic->config.flogi_retries; lp->max_rport_retry_count = fnic->config.plogi_retries; lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
@@ -693,12 +685,18 @@ static int __devinit fnic_probe(struct pci_dev *pdev,fc_set_wwnn (lp, fnic->config.node_wwn);fc_set_wwpn (lp, fnic->config.port_wwn); -fc_exch_init (lp);fc_lport_init (lp); +fc_exch_init (lp);fc_elsct_init (lp);fc_rport_init (lp);fc_disc_init (lp); +if (!fc_exch_mgr_alloc (lp,FC_CLASS_3 ,FCPIO_HOST_EXCH_RANGE_START , +FCPIO_HOST_EXCH_RANGE_END ,NULL )) { + err = -ENOMEM ; + goto err_out_remove_scsi_host; + } +fc_lport_config (lp); if (fc_set_mfs(lp, fnic->config.maxdatafieldsize +
@@ -738,7 +736,7 @@ static int __devinit fnic_probe(struct pci_dev *pdev,return 0 ; err_out_free_exch_mgr: -fc_exch_mgr_free (lp->emp); +fc_exch_mgr_free (lp); err_out_remove_scsi_host:fc_remove_host (fnic->lport->host);scsi_remove_host (fnic->lport->host);
@@ -827,7 +825,7 @@ static void __devexit fnic_remove(struct pci_dev *pdev)fc_remove_host (fnic->lport->host);scsi_remove_host (fnic->lport->host); -fc_exch_mgr_free (fnic->lport->emp); +fc_exch_mgr_free (fnic->lport);vnic_dev_notify_unset (fnic->vdev);fnic_free_vnic_resources (fnic);fnic_free_intr (fnic);
drivers/scsi/libfc/fc_exch.c +117 -74
343 lines not on this page · raw message
include/scsi/libfc.h +8 -40
86 lines not on this page · raw message
PATCH 17/22 fcoe: modifies fcoe_hostlist_lock uses as prep work to add shared offload EM
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
Modifies fcoe_hostlist_lock uses such that a new EM allocation in fcoe_em_config and adding new fcoe_softc using fcoe_hostlist_add are atomic, this is to ensure that a shared offload EM gets allocated only once per eth device for its all lports.
---
drivers/scsi/fcoe/fcoe.c | 26 ++++++++++++++++++-------- 1 files changed, 18 insertions(+), 8 deletions(-)
drivers/scsi/fcoe/fcoe.c +18 -8
@@ -419,6 +419,8 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,* fcoe_em_config() - allocates em for this lport * @lp: the port 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)
@@ -607,6 +609,13 @@ static int fcoe_if_create(struct net_device *netdev) goto out_lp_destroy; } +/* +* fcoe_em_alloc() and fcoe_hostlist_add() both +* need to be atomic under fcoe_hostlist_lock +* since fcoe_em_alloc() looks for an existing EM +* instance on host list updated by fcoe_hostlist_add(). +*/ +write_lock (&fcoe_hostlist_lock);/* lport exch manager allocation */ rc =fcoe_em_config (lp);if (rc) {
@@ -617,6 +626,7 @@ static int fcoe_if_create(struct net_device *netdev)/* add to lports list */ fcoe_hostlist_add (lp); +write_unlock (&fcoe_hostlist_lock); lp->boot_time = jiffies;
@@ -1720,6 +1730,8 @@ int fcoe_reset(struct Scsi_Host *shost)* fcoe_hostlist_lookup_softc() - 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 */ static struct fcoe_softc *
@@ -1727,14 +1739,10 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev) {struct fcoe_softc *fc; -read_lock (&fcoe_hostlist_lock);list_for_each_entry (fc, &fcoe_hostlist, list) { -if (fc->real_dev == dev) { -read_unlock (&fcoe_hostlist_lock); +if (fc->real_dev == dev)return fc; - } } -read_unlock (&fcoe_hostlist_lock);return NULL ; }
@@ -1748,7 +1756,9 @@ struct fc_lport *fcoe_hostlist_lookup(const struct net_device *netdev) {struct fcoe_softc *fc; +read_lock (&fcoe_hostlist_lock); fc =fcoe_hostlist_lookup_softc (netdev); +read_unlock (&fcoe_hostlist_lock);return (fc) ? fc->ctlr.lp :NULL ; }
@@ -1757,6 +1767,8 @@ 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 *lp)
@@ -1766,9 +1778,7 @@ int fcoe_hostlist_add(const struct fc_lport *lp) fc =fcoe_hostlist_lookup_softc (fcoe_netdev (lp));if (!fc) { fc =lport_priv (lp); -write_lock_bh (&fcoe_hostlist_lock);list_add_tail (&fc->list, &fcoe_hostlist); -write_unlock_bh (&fcoe_hostlist_lock); }return 0 ; }
@@ -1783,9 +1793,9 @@ int fcoe_hostlist_remove(const struct fc_lport *lp) {struct fcoe_softc *fc; +write_lock_bh (&fcoe_hostlist_lock); fc =fcoe_hostlist_lookup_softc (fcoe_netdev (lp));BUG_ON (!fc); -write_lock_bh (&fcoe_hostlist_lock);list_del (&fc->list);write_unlock_bh (&fcoe_hostlist_lock);
PATCH 18/22 fcoe, libfc: adds offload EM per eth device with only single xid range per EM
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
Updates fcoe_em_config to allocate a single instance of sharable offload EM for supported lp->lro_xid per eth device, and then share this EM for subsequently more lports creation on same eth device (e.g when using VLAN).
Adds tiny fcoe_oem_match function for offload EM to return true for read types IO to have read IO exchanges allocated from offload shared EM.
Removes fc_em_alloc_xid function completely which was needed to manage two xid ranges within a EM, this is not needed any more with allocation of separate sharable offload EM per eth device. Instead this patch adds simple xid allocation logic to manage single xid range.
Adds fc_exch_em_alloc with mp->next_xid as cursor to allocate new xid from single xid range of EM, uses mp->next_xid instead removed mp->last_xid which slightly increase probability of finding empty xid on exch allocation.
Removes restriction of not allowing use of xid zero along with changing two xid range change to single xid range.
Makes fc_fcp_ddp_setup calling conditional to only xid allocated from shared offload EM.
---
drivers/scsi/fcoe/fcoe.c | 67 +++++++++++++++++++++++++++++- drivers/scsi/fcoe/fcoe.h | 3 + drivers/scsi/libfc/fc_exch.c | 94 ++++++++---------------------------------- 3 files changed, 85 insertions(+), 79 deletions(-)
drivers/scsi/fcoe/fcoe.c +65 -2
@@ -415,6 +415,17 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,return 0 ; } +/* +* fcoe_oem_match() - match for read types IO +* @fp: the fc_frame for new IO. +* +* Returns : true for read types IO, otherwise returns false. +*/ +bool fcoe_oem_match (struct fc_frame *fp) +{ +return fc_fcp_is_read (fr_fsp (fp)); +} +/** * fcoe_em_config() - allocates em for this lport * @lp: the port that em is to allocated for
@@ -425,9 +436,61 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost,*/ static inline int fcoe_em_config (struct fc_lport *lp) { -if (!fc_exch_mgr_alloc (lp,FC_CLASS_3 ,FCOE_MIN_XID , -FCOE_MAX_XID ,NULL )) +struct fcoe_softc *fc =lport_priv (lp); +struct fcoe_softc *oldfc =NULL ; +u16 min_xid =FCOE_MIN_XID ; +u16 max_xid =FCOE_MAX_XID ; + +/* +* Check if need to allocate an em instance for +* offload exchange ids to be shared across all VN_PORTs/lport. +*/ +if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) { + lp->lro_xid =0 ; + goto skip_oem; + } + +/* +* Reuse existing offload em instance in case +* it is already allocated on phys_dev. +*/ +list_for_each_entry (oldfc, &fcoe_hostlist, list) { +if (oldfc->phys_dev == fc->phys_dev) { + fc->oem = oldfc->oem; +break ; + } + } + +if (fc->oem) { +if (!fc_exch_mgr_add (lp, fc->oem, fcoe_oem_match)) { +printk (KERN_ERR "fcoe_em_config: failed to add " +"offload em:%p on interface:%s\n" , + fc->oem, fc->real_dev->name); +return -ENOMEM ; + } + }else { + fc->oem =fc_exch_mgr_alloc (lp,FC_CLASS_3 , +FCOE_MIN_XID , lp->lro_xid, + fcoe_oem_match); +if (!fc->oem) { +printk (KERN_ERR "fcoe_em_config: failed to allocate " +"em for offload exches on interface:%s\n" , + fc->real_dev->name); +return -ENOMEM ; + } + } + +/* +* Exclude offload EM xid range from next EM xid range. +*/ + min_xid += lp->lro_xid +1 ; + +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->real_dev->name);return -ENOMEM ; + }return 0 ; }
drivers/scsi/fcoe/fcoe.h +2 -1
@@ -37,7 +37,7 @@#define FCOE_MAX_OUTSTANDING_COMMANDS 1024 -#define FCOE_MIN_XID 0x0001/* the min xid supported by fcoe_sw */ +#define FCOE_MIN_XID 0x0000/* the min xid supported by fcoe_sw */ #define FCOE_MAX_XID 0x07ef/* the max xid supported by fcoe_sw */ unsigned int fcoe_debug_logging;
@@ -81,6 +81,7 @@ struct fcoe_softc {struct list_head list;struct net_device *real_dev;struct net_device *phys_dev;/* device with ethtool_ops */ +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;
drivers/scsi/libfc/fc_exch.c +18 -76
153 lines not on this page · raw message
PATCH 19/22 fcoe: Remove ifdef for NETIF_F_FCOE_CRC and NETIF_F_FSO
In reply to Robert LoveFrom: Yi Zou <[email protected]>
Remove the extra ifdef for NETIF_F_FSO and NETIF_F_FCOE_CRC since they are already defined in the current kernel as in include/linux/netdevice.h.
---
drivers/scsi/fcoe/fcoe.c | 6 ------ 1 files changed, 0 insertions(+), 6 deletions(-)
drivers/scsi/fcoe/fcoe.c +0 -6
@@ -300,20 +300,16 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)if (fc->real_dev->features &NETIF_F_SG ) lp->sg_supp =1 ; -#ifdef NETIF_F_FCOE_CRC if (netdev->features &NETIF_F_FCOE_CRC ) { lp->crc_offload =1 ;FCOE_NETDEV_DBG (netdev,"Supports FCCRC offload\n" ); } -#endif -#ifdef NETIF_F_FSO if (netdev->features &NETIF_F_FSO ) { lp->seq_offload =1 ; lp->lso_max = netdev->gso_max_size;FCOE_NETDEV_DBG (netdev,"Supports LSO for max len 0x%x\n" , lp->lso_max); } -#endif if (netdev->fcoe_ddp_xid) { lp->lro_enabled =1 ; lp->lro_xid = netdev->fcoe_ddp_xid;
@@ -1205,7 +1201,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)FC_FCOE_ENCAPS_VER (hp,FC_FCOE_VER ); hp->fcoe_sof = sof; -#ifdef NETIF_F_FSO /* fcoe lso, mss is in max_payload which is non-zero for FCP data */ if (lp->seq_offload &&fr_max_payload (fp)) {skb_shinfo (skb)->gso_type =SKB_GSO_FCOE ;
@@ -1214,7 +1209,6 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)skb_shinfo (skb)->gso_type =0 ;skb_shinfo (skb)->gso_size =0 ; } -#endif /* update tx stats: regardless if LLD fails */ stats =fc_lport_get_stats (lp); stats->TxFrames++;
PATCH 20/22 libfc: Remove FC_FRAME_SG_LEN in fc_fcp_send_data
In reply to Robert LoveFrom: Yi Zou <[email protected]>
FC_FRAME_SG_LEN is 4 which is too small when offload is enabled. Actually, the WARN_ON() in fc_fcp_send_data() should be:
WARN_ON(skb_shinfo(fp_skb(fp))->nr_frags > MAX_SKB_FRAGS);
But since we will not get anything more than 64K anyway, so there is no need to do this anyway here. Therefore, I am getting rid of FC_FRAME_SG_LEN here and the WARN_ON here.
---
drivers/scsi/libfc/fc_fcp.c | 2 -- include/scsi/fc_frame.h | 7 ------- 2 files changed, 0 insertions(+), 9 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -2
@@ -569,8 +569,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, } sg_bytes =min (tlen, sg->length - offset);if (using_sg) { -WARN_ON (skb_shinfo (fp_skb (fp))->nr_frags > -FC_FRAME_SG_LEN );get_page (sg_page (sg)); skb_fill_page_desc(fp_skb(fp), skb_shinfo(fp_skb(fp))->nr_frags,
include/scsi/fc_frame.h +0 -7
@@ -37,13 +37,6 @@#define FC_FRAME_HEADROOM 32/* headroom for VLAN + FCoE headers */ #define FC_FRAME_TAILROOM 8/* trailer space for FCoE */ -/* -* Information about an individual fibre channel frame received or to be sent. -* The buffer may be in up to 4 additional non-contiguous sections, -* but the linear section must hold the frame header. -*/ -#define FC_FRAME_SG_LEN 4/* scatter/gather list maximum length */ -#define fp_skb (fp) (&((fp)->skb))#define fr_hdr (fp) ((fp)->skb.data)#define fr_len (fp) ((fp)->skb.len)
PATCH 21/22 libfc: Remove page flags check for sglist
In reply to Robert LoveFrom: Yi Zou <[email protected]>
I don't believe this check is needed any more in the current kernel, which, if I understand correctly, is for compound page where only the first page is supposed to get ref-counted.
---
drivers/scsi/libfc/fc_fcp.c | 27 --------------------------- 1 files changed, 0 insertions(+), 27 deletions(-)
drivers/scsi/libfc/fc_fcp.c +0 -27
@@ -507,33 +507,6 @@ static int fc_fcp_send_data(struct fc_fcp_pkt *fsp, struct fc_seq *seq, f_ctl =FC_FC_REL_OFF ;WARN_ON (!seq); -/* -* If a get_page()/put_page() will fail, don't use sg lists -* in the fc_frame structure. -* -* The put_page() may be long after the I/O has completed -* in the case of FCoE, since the network driver does it -* via free_skb(). See the test in free_pages_check(). -* -* Test this case with 'dd </dev/zero >/dev/st0 bs=64k'. -*/ -if (using_sg) { -for (sg =scsi_sglist (sc); sg; sg =sg_next (sg)) { -if (page_count (sg_page (sg)) ==0 || - (sg_page (sg)->flags & (1 << PG_lru | -1 << PG_private | -1 << PG_locked | -1 << PG_active | -1 << PG_slab | -1 << PG_swapcache | -1 << PG_writeback | -1 << PG_reserved | -1 << PG_buddy))) { - using_sg =0 ; -break ; - } - } - } sg =scsi_sglist (sc);while (remaining >0 && sg) {
PATCH 22/22 fcoe: removes phys_dev and renames real_dev to netdev.
In reply to Robert LoveFrom: Vasu Dev <[email protected]>
The phys_dev was used only to locate common offload EM instance for all FCoE instances on a eth devices in function fcoe_em_config, so just updated fcoe_em_config to look for actual real eth device in locating common offload EM instance and then no need to store phys_dev in fcoe_softc, so removes phys_dev from fcoe_softc also.
Renames fcoe_softc real_dev to netdev and updates all its uses to use netdev.
So effectively no functional change, use of single netdev instead phys_dev and real_dev saves one pointer memory in fcoe_softc, also real_dev used here was confusing with vlan driver terminology since real_dev in vlan driver is referred to physical eth device.
---
drivers/scsi/fcoe/fcoe.c | 93 ++++++++++++++++++++++++---------------------- drivers/scsi/fcoe/fcoe.h | 5 +- 2 files changed, 51 insertions(+), 47 deletions(-)
drivers/scsi/fcoe/fcoe.c +49 -44
@@ -159,7 +159,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)->real_dev; + skb->dev =fcoe_from_ctlr (fip)->netdev;dev_queue_xmit (skb); }
@@ -179,8 +179,8 @@ static void fcoe_update_src_mac(struct fcoe_ctlr *fip, u8 *old, u8 *new) fc =fcoe_from_ctlr (fip);rtnl_lock ();if (!is_zero_ether_addr (old)) -dev_unicast_delete (fc->real_dev, old); -dev_unicast_add (fc->real_dev, new); +dev_unicast_delete (fc->netdev, old); +dev_unicast_add (fc->netdev, new);rtnl_unlock (); }
@@ -231,12 +231,12 @@ void fcoe_netdev_cleanup(struct fcoe_softc *fc)/* Delete secondary MAC addresses */ rtnl_lock ();memcpy (flogi_maddr, (u8 [6 ])FC_FCOE_FLOGI_MAC ,ETH_ALEN ); -dev_unicast_delete (fc->real_dev, flogi_maddr); +dev_unicast_delete (fc->netdev, flogi_maddr);if (!is_zero_ether_addr (fc->ctlr.data_src_addr)) -dev_unicast_delete (fc->real_dev, fc->ctlr.data_src_addr); +dev_unicast_delete (fc->netdev, fc->ctlr.data_src_addr);if (fc->ctlr.spma) -dev_unicast_delete (fc->real_dev, fc->ctlr.ctl_src_addr); -dev_mc_delete (fc->real_dev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +dev_unicast_delete (fc->netdev, fc->ctlr.ctl_src_addr); +dev_mc_delete (fc->netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock (); }
@@ -272,17 +272,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)/* Setup lport private data to point to fcoe softc */ fc =lport_priv (lp); fc->ctlr.lp = lp; - fc->real_dev = netdev; - fc->phys_dev = netdev; - -/* Require support for get_pauseparam ethtool op. */ -if (netdev->priv_flags &IFF_802_1Q_VLAN ) - fc->phys_dev =vlan_dev_real_dev (netdev); + fc->netdev = netdev;/* Do not support for bonding device */ -if ((fc->real_dev->priv_flags &IFF_MASTER_ALB ) || - (fc->real_dev->priv_flags &IFF_SLAVE_INACTIVE ) || - (fc->real_dev->priv_flags &IFF_MASTER_8023AD )) { +if ((netdev->priv_flags &IFF_MASTER_ALB ) || + (netdev->priv_flags &IFF_SLAVE_INACTIVE ) || + (netdev->priv_flags &IFF_MASTER_8023AD )) {return -EOPNOTSUPP ; }
@@ -291,13 +286,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)* user-configured limit. If the MFS is too low, fcoe_link_ok() * will return 0, so do this first. */ - mfs = fc->real_dev->mtu - (sizeof (struct fcoe_hdr ) + -sizeof (struct fcoe_crc_eof )); + mfs = netdev->mtu - (sizeof (struct fcoe_hdr ) + +sizeof (struct fcoe_crc_eof ));if (fc_set_mfs (lp, mfs))return -EINVAL ;/* offload features support */ -if (fc->real_dev->features &NETIF_F_SG ) +if (netdev->features &NETIF_F_SG ) lp->sg_supp =1 ;if (netdev->features &NETIF_F_FCOE_CRC ) {
@@ -335,13 +330,13 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)/* setup Source Mac Address */ if (!fc->ctlr.spma) -memcpy (fc->ctlr.ctl_src_addr, fc->real_dev->dev_addr, - fc->real_dev->addr_len); +memcpy (fc->ctlr.ctl_src_addr, netdev->dev_addr, + fc->netdev->addr_len); - wwnn =fcoe_wwn_from_mac (fc->real_dev->dev_addr,1 ,0 ); + 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 (fc->real_dev->dev_addr,2 ,0 ); + wwpn =fcoe_wwn_from_mac (netdev->dev_addr,2 ,0 );fc_set_wwpn (lp, wwpn);/*
@@ -351,10 +346,10 @@ 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 (fc->real_dev, flogi_maddr); +dev_unicast_add (netdev, flogi_maddr);if (fc->ctlr.spma) -dev_unicast_add (fc->real_dev, fc->ctlr.ctl_src_addr); -dev_mc_add (fc->real_dev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 ); +dev_unicast_add (netdev, fc->ctlr.ctl_src_addr); +dev_mc_add (netdev,FIP_ALL_ENODE_MACS ,ETH_ALEN ,0 );rtnl_unlock ();/*
@@ -363,12 +358,12 @@ static int fcoe_netdev_config(struct fc_lport *lp, struct net_device *netdev)*/ fc->fcoe_packet_type.func = fcoe_rcv; fc->fcoe_packet_type.type =__constant_htons (ETH_P_FCOE ); - fc->fcoe_packet_type.dev = fc->real_dev; + fc->fcoe_packet_type.dev = netdev;dev_add_pack (&fc->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 = fc->real_dev; + fc->fip_packet_type.dev = netdev;dev_add_pack (&fc->fip_packet_type);return 0 ;
@@ -434,6 +429,7 @@ static inline int fcoe_em_config(struct fc_lport *lp) {struct fcoe_softc *fc =lport_priv (lp);struct fcoe_softc *oldfc =NULL ; +struct net_device *old_real_dev, *cur_real_dev;u16 min_xid =FCOE_MIN_XID ;u16 max_xid =FCOE_MAX_XID ;
@@ -448,10 +444,20 @@ static inline int fcoe_em_config(struct fc_lport *lp)/* * Reuse existing offload em instance in case -* it is already allocated on phys_dev. +* 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); +else + cur_real_dev = fc->netdev; +list_for_each_entry (oldfc, &fcoe_hostlist, list) { -if (oldfc->phys_dev == fc->phys_dev) { +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;break ; }
@@ -461,7 +467,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)if (!fc_exch_mgr_add (lp, fc->oem, fcoe_oem_match)) {printk (KERN_ERR "fcoe_em_config: failed to add " "offload em:%p on interface:%s\n" , - fc->oem, fc->real_dev->name); + fc->oem, fc->netdev->name);return -ENOMEM ; } }else {
@@ -471,7 +477,7 @@ static inline int fcoe_em_config(struct fc_lport *lp)if (!fc->oem) {printk (KERN_ERR "fcoe_em_config: failed to allocate " "em for offload exches on interface:%s\n" , - fc->real_dev->name); + fc->netdev->name);return -ENOMEM ; } }
@@ -484,7 +490,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->real_dev->name); +"allocate em on interface %s\n" , fc->netdev->name);return -ENOMEM ; }
@@ -548,7 +554,7 @@ static int fcoe_if_destroy(struct net_device *netdev)fc_lport_free_stats (lp);/* Release the net_device and Scsi_Host */ -dev_put (fc->real_dev); +dev_put (netdev);scsi_host_put (lp->host);return 0 ;
@@ -1179,7 +1185,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 = fc->real_dev; + skb->dev = fc->netdev;/* fill up mac and fcoe headers */ eh =eth_hdr (skb);
@@ -1454,7 +1460,7 @@ static int fcoe_device_notification(struct notifier_block *notifier, ulong event, void *ptr) { struct fc_lport *lp = NULL; -struct net_device *real_dev = ptr; +struct net_device *netdev = ptr;struct fcoe_softc *fc;struct fcoe_dev_stats *stats;u32 link_possible =1 ;
@@ -1463,7 +1469,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,read_lock (&fcoe_hostlist_lock);list_for_each_entry (fc, &fcoe_hostlist, list) { -if (fc->real_dev == real_dev) { +if (fc->netdev == netdev) { lp = fc->ctlr.lp;break ; }
@@ -1483,16 +1489,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,case NETDEV_CHANGE :break ;case NETDEV_CHANGEMTU : - mfs = fc->real_dev->mtu - - (sizeof (struct fcoe_hdr ) + -sizeof (struct fcoe_crc_eof )); + mfs = netdev->mtu - (sizeof (struct fcoe_hdr ) + +sizeof (struct fcoe_crc_eof ));if (mfs >=FC_MIN_MAX_FRAME )fc_set_mfs (lp, mfs);break ;case NETDEV_REGISTER :break ;default : -FCOE_NETDEV_DBG (real_dev,"Unknown event %ld " +FCOE_NETDEV_DBG (netdev,"Unknown event %ld " "from netdev netlink\n" , event); }if (link_possible && !fcoe_link_ok (lp))
@@ -1696,7 +1701,7 @@ 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->real_dev; +struct net_device *dev = fc->netdev;struct ethtool_cmd ecmd = {ETHTOOL_GSET }; if ((dev->flags & IFF_UP) && netif_carrier_ok(dev) &&
@@ -1797,7 +1802,7 @@ fcoe_hostlist_lookup_softc(const struct net_device *dev)struct fcoe_softc *fc;list_for_each_entry (fc, &fcoe_hostlist, list) { -if (fc->real_dev == dev) +if (fc->netdev == dev)return fc; }return NULL ;
@@ -1916,7 +1921,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->real_dev); +fcoe_if_destroy (fc->netdev);unregister_hotcpu_notifier (&fcoe_cpu_notifier);
drivers/scsi/fcoe/fcoe.h +2 -3
@@ -79,8 +79,7 @@ struct fcoe_percpu_s {*/ struct fcoe_softc {struct list_head list; -struct net_device *real_dev; -struct net_device *phys_dev;/* device with ethtool_ops */ +struct net_device *netdev;struct fc_exch_mgr *oem;/* offload exchange manger */ struct packet_type fcoe_packet_type;struct packet_type fip_packet_type;
@@ -95,7 +94,7 @@ struct fcoe_softc {static inline struct net_device *fcoe_netdev (const struct fc_lport *lp) { -return ((struct fcoe_softc *)lport_priv (lp))->real_dev; +return ((struct fcoe_softc *)lport_priv (lp))->netdev; }#endif /* _FCOE_H_ */