diff options
Diffstat (limited to 'drivers/scsi/fcoe/fcoe.c')
| -rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 213 | 
1 files changed, 71 insertions, 142 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index bde6ee5333e..cc23bd9480b 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c @@ -381,6 +381,42 @@ out:  }  /** + * 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; +	struct net_device *netdev; + +	fcoe = container_of(kref, struct fcoe_interface, kref); +	netdev = fcoe->netdev; +	/* tear-down the FCoE controller */ +	fcoe_ctlr_destroy(&fcoe->ctlr); +	kfree(fcoe); +	dev_put(netdev); +	module_put(THIS_MODULE); +} + +/** + * fcoe_interface_get() - Get a reference to a FCoE interface + * @fcoe: The FCoE interface to be held + */ +static inline void fcoe_interface_get(struct fcoe_interface *fcoe) +{ +	kref_get(&fcoe->kref); +} + +/** + * fcoe_interface_put() - Put a reference to a FCoE interface + * @fcoe: The FCoE interface to be released + */ +static inline void fcoe_interface_put(struct fcoe_interface *fcoe) +{ +	kref_put(&fcoe->kref, fcoe_interface_release); +} + +/**   * fcoe_interface_cleanup() - Clean up a FCoE interface   * @fcoe: The FCoE interface to be cleaned up   * @@ -392,6 +428,21 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)  	struct fcoe_ctlr *fip = &fcoe->ctlr;  	u8 flogi_maddr[ETH_ALEN];  	const struct net_device_ops *ops; +	struct fcoe_port *port = lport_priv(fcoe->ctlr.lp); + +	FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); + +	/* Logout of the fabric */ +	fc_fabric_logoff(fcoe->ctlr.lp); + +	/* Cleanup the fc_lport */ +	fc_lport_destroy(fcoe->ctlr.lp); + +	/* Stop the transmit retry timer */ +	del_timer_sync(&port->timer); + +	/* Free existing transmit skbs */ +	fcoe_clean_pending_queue(fcoe->ctlr.lp);  	/*  	 * Don't listen for Ethernet packets anymore. @@ -414,6 +465,9 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)  	} else  		dev_mc_del(netdev, FIP_ALL_ENODE_MACS); +	if (!is_zero_ether_addr(port->data_src_addr)) +		dev_uc_del(netdev, port->data_src_addr); +  	/* Tell the LLD we are done w/ FCoE */  	ops = netdev->netdev_ops;  	if (ops->ndo_fcoe_disable) { @@ -421,42 +475,7 @@ void fcoe_interface_cleanup(struct fcoe_interface *fcoe)  			FCOE_NETDEV_DBG(netdev, "Failed to disable FCoE"  					" specific feature for LLD.\n");  	} -} - -/** - * 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; -	struct net_device *netdev; - -	fcoe = container_of(kref, struct fcoe_interface, kref); -	netdev = fcoe->netdev; -	/* tear-down the FCoE controller */ -	fcoe_ctlr_destroy(&fcoe->ctlr); -	kfree(fcoe); -	dev_put(netdev); -	module_put(THIS_MODULE); -} - -/** - * fcoe_interface_get() - Get a reference to a FCoE interface - * @fcoe: The FCoE interface to be held - */ -static inline void fcoe_interface_get(struct fcoe_interface *fcoe) -{ -	kref_get(&fcoe->kref); -} - -/** - * fcoe_interface_put() - Put a reference to a FCoE interface - * @fcoe: The FCoE interface to be released - */ -static inline void fcoe_interface_put(struct fcoe_interface *fcoe) -{ -	kref_put(&fcoe->kref, fcoe_interface_release); +	fcoe_interface_put(fcoe);  }  /** @@ -821,39 +840,9 @@ skip_oem:   * fcoe_if_destroy() - Tear down a SW FCoE instance   * @lport: The local port to be destroyed   * - * Locking: must be called with the RTNL mutex held and RTNL mutex - * needed to be dropped by this function since not dropping RTNL - * would cause circular locking warning on synchronous fip worker - * cancelling thru fcoe_interface_put invoked by this function. - *   */  static void fcoe_if_destroy(struct fc_lport *lport)  { -	struct fcoe_port *port = lport_priv(lport); -	struct fcoe_interface *fcoe = port->priv; -	struct net_device *netdev = fcoe->netdev; - -	FCOE_NETDEV_DBG(netdev, "Destroying interface\n"); - -	/* Logout of the fabric */ -	fc_fabric_logoff(lport); - -	/* Cleanup the fc_lport */ -	fc_lport_destroy(lport); - -	/* Stop the transmit retry timer */ -	del_timer_sync(&port->timer); - -	/* Free existing transmit skbs */ -	fcoe_clean_pending_queue(lport); - -	if (!is_zero_ether_addr(port->data_src_addr)) -		dev_uc_del(netdev, port->data_src_addr); -	rtnl_unlock(); - -	/* 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); @@ -1783,23 +1772,8 @@ static int fcoe_disable(struct net_device *netdev)  	int rc = 0;  	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 - -	if (!rtnl_trylock()) { -		mutex_unlock(&fcoe_config_mutex); -		return -ERESTARTSYS; -	} +	rtnl_lock();  	fcoe = fcoe_hostlist_lookup_port(netdev);  	rtnl_unlock(); @@ -1809,7 +1783,6 @@ static int fcoe_disable(struct net_device *netdev)  	} else  		rc = -ENODEV; -out_nodev:  	mutex_unlock(&fcoe_config_mutex);  	return rc;  } @@ -1828,22 +1801,7 @@ static int fcoe_enable(struct net_device *netdev)  	int rc = 0;  	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 -	if (!rtnl_trylock()) { -		mutex_unlock(&fcoe_config_mutex); -		return -ERESTARTSYS; -	} - +	rtnl_lock();  	fcoe = fcoe_hostlist_lookup_port(netdev);  	rtnl_unlock(); @@ -1852,7 +1810,6 @@ static int fcoe_enable(struct net_device *netdev)  	else if (!fcoe_link_ok(fcoe->ctlr.lp))  		fcoe_ctlr_link_up(&fcoe->ctlr); -out_nodev:  	mutex_unlock(&fcoe_config_mutex);  	return rc;  } @@ -1868,35 +1825,22 @@ out_nodev:  static int fcoe_destroy(struct net_device *netdev)  {  	struct fcoe_interface *fcoe; +	struct fc_lport *lport;  	int rc = 0;  	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 -	if (!rtnl_trylock()) { -		mutex_unlock(&fcoe_config_mutex); -		return -ERESTARTSYS; -	} - +	rtnl_lock();  	fcoe = fcoe_hostlist_lookup_port(netdev);  	if (!fcoe) {  		rtnl_unlock();  		rc = -ENODEV;  		goto out_nodev;  	} -	fcoe_interface_cleanup(fcoe); +	lport = fcoe->ctlr.lp;  	list_del(&fcoe->list); -	/* RTNL mutex is dropped by fcoe_if_destroy */ -	fcoe_if_destroy(fcoe->ctlr.lp); +	fcoe_interface_cleanup(fcoe); +	rtnl_unlock(); +	fcoe_if_destroy(lport);  out_nodev:  	mutex_unlock(&fcoe_config_mutex);  	return rc; @@ -1912,8 +1856,6 @@ static void fcoe_destroy_work(struct work_struct *work)  	port = container_of(work, struct fcoe_port, destroy_work);  	mutex_lock(&fcoe_config_mutex); -	rtnl_lock(); -	/* RTNL mutex is dropped by fcoe_if_destroy */  	fcoe_if_destroy(port->lport);  	mutex_unlock(&fcoe_config_mutex);  } @@ -1948,23 +1890,7 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)  	struct fc_lport *lport;  	mutex_lock(&fcoe_config_mutex); - -	if (!rtnl_trylock()) { -		mutex_unlock(&fcoe_config_mutex); -		return -ERESTARTSYS; -	} - -#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 +	rtnl_lock();  	/* look for existing lport */  	if (fcoe_hostlist_lookup(netdev)) { @@ -2026,7 +1952,7 @@ out_nodev:  int fcoe_link_speed_update(struct fc_lport *lport)  {  	struct net_device *netdev = fcoe_netdev(lport); -	struct ethtool_cmd ecmd = { ETHTOOL_GSET }; +	struct ethtool_cmd ecmd;  	if (!dev_ethtool_get_settings(netdev, &ecmd)) {  		lport->link_supported_speeds &= @@ -2037,11 +1963,14 @@ int fcoe_link_speed_update(struct fc_lport *lport)  		if (ecmd.supported & SUPPORTED_10000baseT_Full)  			lport->link_supported_speeds |=  				FC_PORTSPEED_10GBIT; -		if (ecmd.speed == SPEED_1000) +		switch (ethtool_cmd_speed(&ecmd)) { +		case SPEED_1000:  			lport->link_speed = FC_PORTSPEED_1GBIT; -		if (ecmd.speed == SPEED_10000) +			break; +		case SPEED_10000:  			lport->link_speed = FC_PORTSPEED_10GBIT; - +			break; +		}  		return 0;  	}  	return -1;  |