You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley: "This is an assorted set of stragglers into the merge window with driver updates for qla2xxx, megaraid_sas, storvsc and ufs. It also includes pulls of the uapi tree (all the remaining SCSI pieces) and the fcoe tree (updates to fcoe and libfc)" * tag 'scsi-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (81 commits) [SCSI] ufs: Separate PCI code into glue driver [SCSI] ufs: Segregate PCI Specific Code [SCSI] scsi: fix lpfc build when wmb() is defined as mb() [SCSI] storvsc: Handle dynamic resizing of the device [SCSI] storvsc: Restructure error handling code on command completion [SCSI] storvsc: avoid usage of WRITE_SAME [SCSI] aacraid: suppress two GCC warnings [SCSI] hpsa: check for dma_mapping_error in hpsa_passthru ioctls [SCSI] hpsa: reorganize error handling in hpsa_passthru_ioctl [SCSI] hpsa: check for dma_mapping_error in hpsa_map_sg_chain_block [SCSI] hpsa: Check for dma_mapping_error for all code paths using fill_cmd [SCSI] hpsa: Check for dma_mapping_error in hpsa_map_one [SCSI] dc395x: uninitialized variable in device_alloc() [SCSI] Fix range check in scsi_host_dif_capable() [SCSI] storvsc: Initialize the sglist [SCSI] mpt2sas: Add support for OEM specific controller [SCSI] ipr: Fix oops while resetting an ipr adapter [SCSI] fnic: Fnic Trace Utility [SCSI] fnic: New debug flags and debug log messages [SCSI] fnic: fnic driver may hit BUG_ON on device reset ...
This commit is contained in:
@@ -1,14 +1,53 @@
|
||||
What: /sys/bus/fcoe/ctlr_X
|
||||
What: /sys/bus/fcoe/
|
||||
Date: August 2012
|
||||
KernelVersion: TBD
|
||||
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
|
||||
Description: The FCoE bus. Attributes in this directory are control interfaces.
|
||||
Attributes:
|
||||
|
||||
ctlr_create: 'FCoE Controller' instance creation interface. Writing an
|
||||
<ifname> to this file will allocate and populate sysfs with a
|
||||
fcoe_ctlr_device (ctlr_X). The user can then configure any
|
||||
per-port settings and finally write to the fcoe_ctlr_device's
|
||||
'start' attribute to begin the kernel's discovery and login
|
||||
process.
|
||||
|
||||
ctlr_destroy: 'FCoE Controller' instance removal interface. Writing a
|
||||
fcoe_ctlr_device's sysfs name to this file will log the
|
||||
fcoe_ctlr_device out of the fabric or otherwise connected
|
||||
FCoE devices. It will also free all kernel memory allocated
|
||||
for this fcoe_ctlr_device and any structures associated
|
||||
with it, this includes the scsi_host.
|
||||
|
||||
What: /sys/bus/fcoe/devices/ctlr_X
|
||||
Date: March 2012
|
||||
KernelVersion: TBD
|
||||
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
|
||||
Description: 'FCoE Controller' instances on the fcoe bus
|
||||
Description: 'FCoE Controller' instances on the fcoe bus.
|
||||
The FCoE Controller now has a three stage creation process.
|
||||
1) Write interface name to ctlr_create 2) Configure the FCoE
|
||||
Controller (ctlr_X) 3) Enable the FCoE Controller to begin
|
||||
discovery and login. The FCoE Controller is destroyed by
|
||||
writing it's name, i.e. ctlr_X to the ctlr_delete file.
|
||||
|
||||
Attributes:
|
||||
|
||||
fcf_dev_loss_tmo: Device loss timeout peroid (see below). Changing
|
||||
this value will change the dev_loss_tmo for all
|
||||
FCFs discovered by this controller.
|
||||
|
||||
mode: Display or change the FCoE Controller's mode. Possible
|
||||
modes are 'Fabric' and 'VN2VN'. If a FCoE Controller
|
||||
is started in 'Fabric' mode then FIP FCF discovery is
|
||||
initiated and ultimately a fabric login is attempted.
|
||||
If a FCoE Controller is started in 'VN2VN' mode then
|
||||
FIP VN2VN discovery and login is performed. A FCoE
|
||||
Controller only supports one mode at a time.
|
||||
|
||||
enabled: Whether an FCoE controller is enabled or disabled.
|
||||
0 if disabled, 1 if enabled. Writing either 0 or 1
|
||||
to this file will enable or disable the FCoE controller.
|
||||
|
||||
lesb/link_fail: Link Error Status Block (LESB) link failure count.
|
||||
|
||||
lesb/vlink_fail: Link Error Status Block (LESB) virtual link
|
||||
@@ -26,7 +65,7 @@ Attributes:
|
||||
|
||||
Notes: ctlr_X (global increment starting at 0)
|
||||
|
||||
What: /sys/bus/fcoe/fcf_X
|
||||
What: /sys/bus/fcoe/devices/fcf_X
|
||||
Date: March 2012
|
||||
KernelVersion: TBD
|
||||
Contact: Robert Love <robert.w.love@intel.com>, devel@open-fcoe.org
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
Release Date : Sat. Feb 9, 2013 17:00:00 PST 2013 -
|
||||
(emaild-id:megaraidlinux@lsi.com)
|
||||
Adam Radford
|
||||
Current Version : 06.506.00.00-rc1
|
||||
Old Version : 06.504.01.00-rc1
|
||||
1. Add 4k FastPath DIF support.
|
||||
2. Dont load DevHandle unless FastPath enabled.
|
||||
3. Version and Changelog update.
|
||||
-------------------------------------------------------------------------------
|
||||
Release Date : Mon. Oct 1, 2012 17:00:00 PST 2012 -
|
||||
(emaild-id:megaraidlinux@lsi.com)
|
||||
Adam Radford
|
||||
|
||||
@@ -407,7 +407,7 @@ static int aac_src_deliver_message(struct fib *fib)
|
||||
fib->hw_fib_va->header.StructType = FIB_MAGIC2;
|
||||
fib->hw_fib_va->header.SenderFibAddress = (u32)address;
|
||||
fib->hw_fib_va->header.u.TimeStamp = 0;
|
||||
BUG_ON((u32)(address >> 32) != 0L);
|
||||
BUG_ON(upper_32_bits(address) != 0L);
|
||||
address |= fibsize;
|
||||
} else {
|
||||
/* Calculate the amount to the fibsize bits */
|
||||
@@ -431,7 +431,7 @@ static int aac_src_deliver_message(struct fib *fib)
|
||||
address |= fibsize;
|
||||
}
|
||||
|
||||
src_writel(dev, MUnit.IQ_H, (address >> 32) & 0xffffffff);
|
||||
src_writel(dev, MUnit.IQ_H, upper_32_bits(address) & 0xffffffff);
|
||||
src_writel(dev, MUnit.IQ_L, address & 0xffffffff);
|
||||
|
||||
return 0;
|
||||
|
||||
+149
-107
@@ -62,6 +62,10 @@ static int bnx2fc_destroy(struct net_device *net_device);
|
||||
static int bnx2fc_enable(struct net_device *netdev);
|
||||
static int bnx2fc_disable(struct net_device *netdev);
|
||||
|
||||
/* fcoe_syfs control interface handlers */
|
||||
static int bnx2fc_ctlr_alloc(struct net_device *netdev);
|
||||
static int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev);
|
||||
|
||||
static void bnx2fc_recv_frame(struct sk_buff *skb);
|
||||
|
||||
static void bnx2fc_start_disc(struct bnx2fc_interface *interface);
|
||||
@@ -89,7 +93,6 @@ static void bnx2fc_port_shutdown(struct fc_lport *lport);
|
||||
static void bnx2fc_stop(struct bnx2fc_interface *interface);
|
||||
static int __init bnx2fc_mod_init(void);
|
||||
static void __exit bnx2fc_mod_exit(void);
|
||||
static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev);
|
||||
|
||||
unsigned int bnx2fc_debug_level;
|
||||
module_param_named(debug_logging, bnx2fc_debug_level, int, S_IRUGO|S_IWUSR);
|
||||
@@ -107,44 +110,6 @@ static inline struct net_device *bnx2fc_netdev(const struct fc_lport *lport)
|
||||
((struct fcoe_port *)lport_priv(lport))->priv)->netdev;
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2fc_get_lesb() - Fill the FCoE Link Error Status Block
|
||||
* @lport: the local port
|
||||
* @fc_lesb: the link error status block
|
||||
*/
|
||||
static void bnx2fc_get_lesb(struct fc_lport *lport,
|
||||
struct fc_els_lesb *fc_lesb)
|
||||
{
|
||||
struct net_device *netdev = bnx2fc_netdev(lport);
|
||||
|
||||
__fcoe_get_lesb(lport, fc_lesb, netdev);
|
||||
}
|
||||
|
||||
static void bnx2fc_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
|
||||
{
|
||||
struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
|
||||
struct net_device *netdev = bnx2fc_netdev(fip->lp);
|
||||
struct fcoe_fc_els_lesb *fcoe_lesb;
|
||||
struct fc_els_lesb fc_lesb;
|
||||
|
||||
__fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
|
||||
fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
|
||||
|
||||
ctlr_dev->lesb.lesb_link_fail =
|
||||
ntohl(fcoe_lesb->lesb_link_fail);
|
||||
ctlr_dev->lesb.lesb_vlink_fail =
|
||||
ntohl(fcoe_lesb->lesb_vlink_fail);
|
||||
ctlr_dev->lesb.lesb_miss_fka =
|
||||
ntohl(fcoe_lesb->lesb_miss_fka);
|
||||
ctlr_dev->lesb.lesb_symb_err =
|
||||
ntohl(fcoe_lesb->lesb_symb_err);
|
||||
ctlr_dev->lesb.lesb_err_block =
|
||||
ntohl(fcoe_lesb->lesb_err_block);
|
||||
ctlr_dev->lesb.lesb_fcs_error =
|
||||
ntohl(fcoe_lesb->lesb_fcs_error);
|
||||
}
|
||||
EXPORT_SYMBOL(bnx2fc_ctlr_get_lesb);
|
||||
|
||||
static void bnx2fc_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev)
|
||||
{
|
||||
struct fcoe_ctlr_device *ctlr_dev =
|
||||
@@ -741,35 +706,6 @@ static int bnx2fc_shost_config(struct fc_lport *lport, struct device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void bnx2fc_link_speed_update(struct fc_lport *lport)
|
||||
{
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
struct bnx2fc_interface *interface = port->priv;
|
||||
struct net_device *netdev = interface->netdev;
|
||||
struct ethtool_cmd ecmd;
|
||||
|
||||
if (!__ethtool_get_settings(netdev, &ecmd)) {
|
||||
lport->link_supported_speeds &=
|
||||
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
|
||||
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full))
|
||||
lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
|
||||
if (ecmd.supported & SUPPORTED_10000baseT_Full)
|
||||
lport->link_supported_speeds |= FC_PORTSPEED_10GBIT;
|
||||
|
||||
switch (ethtool_cmd_speed(&ecmd)) {
|
||||
case SPEED_1000:
|
||||
lport->link_speed = FC_PORTSPEED_1GBIT;
|
||||
break;
|
||||
case SPEED_2500:
|
||||
lport->link_speed = FC_PORTSPEED_2GBIT;
|
||||
break;
|
||||
case SPEED_10000:
|
||||
lport->link_speed = FC_PORTSPEED_10GBIT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static int bnx2fc_link_ok(struct fc_lport *lport)
|
||||
{
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
@@ -827,7 +763,7 @@ static int bnx2fc_net_config(struct fc_lport *lport, struct net_device *netdev)
|
||||
port->fcoe_pending_queue_active = 0;
|
||||
setup_timer(&port->timer, fcoe_queue_timer, (unsigned long) lport);
|
||||
|
||||
bnx2fc_link_speed_update(lport);
|
||||
fcoe_link_speed_update(lport);
|
||||
|
||||
if (!lport->vport) {
|
||||
if (fcoe_get_wwn(netdev, &wwnn, NETDEV_FCOE_WWNN))
|
||||
@@ -871,6 +807,7 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
|
||||
u16 vlan_id)
|
||||
{
|
||||
struct bnx2fc_hba *hba = (struct bnx2fc_hba *)context;
|
||||
struct fcoe_ctlr_device *cdev;
|
||||
struct fc_lport *lport;
|
||||
struct fc_lport *vport;
|
||||
struct bnx2fc_interface *interface, *tmp;
|
||||
@@ -930,30 +867,47 @@ static void bnx2fc_indicate_netevent(void *context, unsigned long event,
|
||||
BNX2FC_HBA_DBG(lport, "netevent handler - event=%s %ld\n",
|
||||
interface->netdev->name, event);
|
||||
|
||||
bnx2fc_link_speed_update(lport);
|
||||
fcoe_link_speed_update(lport);
|
||||
|
||||
cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
|
||||
|
||||
if (link_possible && !bnx2fc_link_ok(lport)) {
|
||||
/* Reset max recv frame size to default */
|
||||
fc_set_mfs(lport, BNX2FC_MFS);
|
||||
/*
|
||||
* ctlr link up will only be handled during
|
||||
* enable to avoid sending discovery solicitation
|
||||
* on a stale vlan
|
||||
*/
|
||||
if (interface->enabled)
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_DISABLED:
|
||||
pr_info("Link up while interface is disabled.\n");
|
||||
break;
|
||||
case FCOE_CTLR_ENABLED:
|
||||
case FCOE_CTLR_UNUSED:
|
||||
/* Reset max recv frame size to default */
|
||||
fc_set_mfs(lport, BNX2FC_MFS);
|
||||
/*
|
||||
* ctlr link up will only be handled during
|
||||
* enable to avoid sending discovery
|
||||
* solicitation on a stale vlan
|
||||
*/
|
||||
if (interface->enabled)
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
};
|
||||
} else if (fcoe_ctlr_link_down(ctlr)) {
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
list_for_each_entry(vport, &lport->vports, list)
|
||||
fc_host_port_type(vport->host) =
|
||||
FC_PORTTYPE_UNKNOWN;
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
fc_host_port_type(lport->host) = FC_PORTTYPE_UNKNOWN;
|
||||
per_cpu_ptr(lport->stats,
|
||||
get_cpu())->LinkFailureCount++;
|
||||
put_cpu();
|
||||
fcoe_clean_pending_queue(lport);
|
||||
wait_for_upload = 1;
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_DISABLED:
|
||||
pr_info("Link down while interface is disabled.\n");
|
||||
break;
|
||||
case FCOE_CTLR_ENABLED:
|
||||
case FCOE_CTLR_UNUSED:
|
||||
mutex_lock(&lport->lp_mutex);
|
||||
list_for_each_entry(vport, &lport->vports, list)
|
||||
fc_host_port_type(vport->host) =
|
||||
FC_PORTTYPE_UNKNOWN;
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
fc_host_port_type(lport->host) =
|
||||
FC_PORTTYPE_UNKNOWN;
|
||||
per_cpu_ptr(lport->stats,
|
||||
get_cpu())->LinkFailureCount++;
|
||||
put_cpu();
|
||||
fcoe_clean_pending_queue(lport);
|
||||
wait_for_upload = 1;
|
||||
};
|
||||
}
|
||||
}
|
||||
mutex_unlock(&bnx2fc_dev_lock);
|
||||
@@ -1484,6 +1438,7 @@ static struct fc_lport *bnx2fc_if_create(struct bnx2fc_interface *interface,
|
||||
port = lport_priv(lport);
|
||||
port->lport = lport;
|
||||
port->priv = interface;
|
||||
port->get_netdev = bnx2fc_netdev;
|
||||
INIT_WORK(&port->destroy_work, bnx2fc_destroy_work);
|
||||
|
||||
/* Configure fcoe_port */
|
||||
@@ -2003,7 +1958,9 @@ static void bnx2fc_ulp_init(struct cnic_dev *dev)
|
||||
set_bit(BNX2FC_CNIC_REGISTERED, &hba->reg_with_cnic);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deperecated: Use bnx2fc_enabled()
|
||||
*/
|
||||
static int bnx2fc_disable(struct net_device *netdev)
|
||||
{
|
||||
struct bnx2fc_interface *interface;
|
||||
@@ -2029,7 +1986,9 @@ static int bnx2fc_disable(struct net_device *netdev)
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deprecated: Use bnx2fc_enabled()
|
||||
*/
|
||||
static int bnx2fc_enable(struct net_device *netdev)
|
||||
{
|
||||
struct bnx2fc_interface *interface;
|
||||
@@ -2055,17 +2014,57 @@ static int bnx2fc_enable(struct net_device *netdev)
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2fc_create - Create bnx2fc FCoE interface
|
||||
* bnx2fc_ctlr_enabled() - Enable or disable an FCoE Controller
|
||||
* @cdev: The FCoE Controller that is being enabled or disabled
|
||||
*
|
||||
* @buffer: The name of Ethernet interface to create on
|
||||
* @kp: The associated kernel param
|
||||
* fcoe_sysfs will ensure that the state of 'enabled' has
|
||||
* changed, so no checking is necessary here. This routine simply
|
||||
* calls fcoe_enable or fcoe_disable, both of which are deprecated.
|
||||
* When those routines are removed the functionality can be merged
|
||||
* here.
|
||||
*/
|
||||
static int bnx2fc_ctlr_enabled(struct fcoe_ctlr_device *cdev)
|
||||
{
|
||||
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev);
|
||||
struct fc_lport *lport = ctlr->lp;
|
||||
struct net_device *netdev = bnx2fc_netdev(lport);
|
||||
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_ENABLED:
|
||||
return bnx2fc_enable(netdev);
|
||||
case FCOE_CTLR_DISABLED:
|
||||
return bnx2fc_disable(netdev);
|
||||
case FCOE_CTLR_UNUSED:
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
}
|
||||
|
||||
enum bnx2fc_create_link_state {
|
||||
BNX2FC_CREATE_LINK_DOWN,
|
||||
BNX2FC_CREATE_LINK_UP,
|
||||
};
|
||||
|
||||
/**
|
||||
* _bnx2fc_create() - Create bnx2fc FCoE interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
* @fip_mode: The FIP mode for this creation
|
||||
* @link_state: The ctlr link state on creation
|
||||
*
|
||||
* Called from sysfs.
|
||||
* Called from either the libfcoe 'create' module parameter
|
||||
* via fcoe_create or from fcoe_syfs's ctlr_create file.
|
||||
*
|
||||
* libfcoe's 'create' module parameter is deprecated so some
|
||||
* consolidation of code can be done when that interface is
|
||||
* removed.
|
||||
*
|
||||
* Returns: 0 for success
|
||||
*/
|
||||
static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
static int _bnx2fc_create(struct net_device *netdev,
|
||||
enum fip_state fip_mode,
|
||||
enum bnx2fc_create_link_state link_state)
|
||||
{
|
||||
struct fcoe_ctlr_device *cdev;
|
||||
struct fcoe_ctlr *ctlr;
|
||||
struct bnx2fc_interface *interface;
|
||||
struct bnx2fc_hba *hba;
|
||||
@@ -2160,7 +2159,15 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
/* Make this master N_port */
|
||||
ctlr->lp = lport;
|
||||
|
||||
if (!bnx2fc_link_ok(lport)) {
|
||||
cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
|
||||
|
||||
if (link_state == BNX2FC_CREATE_LINK_UP)
|
||||
cdev->enabled = FCOE_CTLR_ENABLED;
|
||||
else
|
||||
cdev->enabled = FCOE_CTLR_DISABLED;
|
||||
|
||||
if (link_state == BNX2FC_CREATE_LINK_UP &&
|
||||
!bnx2fc_link_ok(lport)) {
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
fc_host_port_type(lport->host) = FC_PORTTYPE_NPORT;
|
||||
set_bit(ADAPTER_STATE_READY, &interface->hba->adapter_state);
|
||||
@@ -2168,7 +2175,10 @@ static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
|
||||
BNX2FC_HBA_DBG(lport, "create: START DISC\n");
|
||||
bnx2fc_start_disc(interface);
|
||||
interface->enabled = true;
|
||||
|
||||
if (link_state == BNX2FC_CREATE_LINK_UP)
|
||||
interface->enabled = true;
|
||||
|
||||
/*
|
||||
* Release from kref_init in bnx2fc_interface_setup, on success
|
||||
* lport should be holding a reference taken in bnx2fc_if_create
|
||||
@@ -2193,6 +2203,37 @@ mod_err:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2fc_create() - Create a bnx2fc interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
* @fip_mode: The FIP mode for this creation
|
||||
*
|
||||
* Called from fcoe transport
|
||||
*
|
||||
* Returns: 0 for success
|
||||
*/
|
||||
static int bnx2fc_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
{
|
||||
return _bnx2fc_create(netdev, fip_mode, BNX2FC_CREATE_LINK_UP);
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2fc_ctlr_alloc() - Allocate a bnx2fc interface from fcoe_sysfs
|
||||
* @netdev: The net_device to be used by the allocated FCoE Controller
|
||||
*
|
||||
* This routine is called from fcoe_sysfs. It will start the fcoe_ctlr
|
||||
* in a link_down state. The allows the user an opportunity to configure
|
||||
* the FCoE Controller from sysfs before enabling the FCoE Controller.
|
||||
*
|
||||
* Creating in with this routine starts the FCoE Controller in Fabric
|
||||
* mode. The user can change to VN2VN or another mode before enabling.
|
||||
*/
|
||||
static int bnx2fc_ctlr_alloc(struct net_device *netdev)
|
||||
{
|
||||
return _bnx2fc_create(netdev, FIP_MODE_FABRIC,
|
||||
BNX2FC_CREATE_LINK_DOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
* bnx2fc_find_hba_for_cnic - maps cnic instance to bnx2fc hba instance
|
||||
*
|
||||
@@ -2318,6 +2359,7 @@ static struct fcoe_transport bnx2fc_transport = {
|
||||
.name = {"bnx2fc"},
|
||||
.attached = false,
|
||||
.list = LIST_HEAD_INIT(bnx2fc_transport.list),
|
||||
.alloc = bnx2fc_ctlr_alloc,
|
||||
.match = bnx2fc_match,
|
||||
.create = bnx2fc_create,
|
||||
.destroy = bnx2fc_destroy,
|
||||
@@ -2562,13 +2604,13 @@ module_init(bnx2fc_mod_init);
|
||||
module_exit(bnx2fc_mod_exit);
|
||||
|
||||
static struct fcoe_sysfs_function_template bnx2fc_fcoe_sysfs_templ = {
|
||||
.get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
|
||||
.get_fcoe_ctlr_link_fail = bnx2fc_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_vlink_fail = bnx2fc_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_miss_fka = bnx2fc_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_symb_err = bnx2fc_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_err_block = bnx2fc_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_fcs_error = bnx2fc_ctlr_get_lesb,
|
||||
.set_fcoe_ctlr_enabled = bnx2fc_ctlr_enabled,
|
||||
.get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_symb_err = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_err_block = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_fcs_error = fcoe_ctlr_get_lesb,
|
||||
|
||||
.get_fcoe_fcf_selected = fcoe_fcf_get_selected,
|
||||
.get_fcoe_fcf_vlan_id = bnx2fc_fcf_get_vlan_id,
|
||||
@@ -2675,7 +2717,7 @@ static struct libfc_function_template bnx2fc_libfc_fcn_templ = {
|
||||
.elsct_send = bnx2fc_elsct_send,
|
||||
.fcp_abort_io = bnx2fc_abort_io,
|
||||
.fcp_cleanup = bnx2fc_cleanup,
|
||||
.get_lesb = bnx2fc_get_lesb,
|
||||
.get_lesb = fcoe_get_lesb,
|
||||
.rport_event_callback = bnx2fc_rport_event_handler,
|
||||
};
|
||||
|
||||
|
||||
@@ -3747,13 +3747,13 @@ static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
|
||||
dcb->max_command = 1;
|
||||
dcb->target_id = target;
|
||||
dcb->target_lun = lun;
|
||||
dcb->dev_mode = eeprom->target[target].cfg0;
|
||||
#ifndef DC395x_NO_DISCONNECT
|
||||
dcb->identify_msg =
|
||||
IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun);
|
||||
#else
|
||||
dcb->identify_msg = IDENTIFY(0, lun);
|
||||
#endif
|
||||
dcb->dev_mode = eeprom->target[target].cfg0;
|
||||
dcb->inquiry7 = 0;
|
||||
dcb->sync_mode = 0;
|
||||
dcb->min_nego_period = clock_period[period_index];
|
||||
|
||||
+176
-88
@@ -82,11 +82,11 @@ static int fcoe_rcv(struct sk_buff *, struct net_device *,
|
||||
struct packet_type *, struct net_device *);
|
||||
static int fcoe_percpu_receive_thread(void *);
|
||||
static void fcoe_percpu_clean(struct fc_lport *);
|
||||
static int fcoe_link_speed_update(struct fc_lport *);
|
||||
static int fcoe_link_ok(struct fc_lport *);
|
||||
|
||||
static struct fc_lport *fcoe_hostlist_lookup(const struct net_device *);
|
||||
static int fcoe_hostlist_add(const struct fc_lport *);
|
||||
static void fcoe_hostlist_del(const struct fc_lport *);
|
||||
|
||||
static int fcoe_device_notification(struct notifier_block *, ulong, void *);
|
||||
static void fcoe_dev_setup(void);
|
||||
@@ -117,6 +117,11 @@ static int fcoe_destroy(struct net_device *netdev);
|
||||
static int fcoe_enable(struct net_device *netdev);
|
||||
static int fcoe_disable(struct net_device *netdev);
|
||||
|
||||
/* fcoe_syfs control interface handlers */
|
||||
static int fcoe_ctlr_alloc(struct net_device *netdev);
|
||||
static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev);
|
||||
|
||||
|
||||
static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
|
||||
u32 did, struct fc_frame *,
|
||||
unsigned int op,
|
||||
@@ -126,8 +131,6 @@ static struct fc_seq *fcoe_elsct_send(struct fc_lport *,
|
||||
void *, u32 timeout);
|
||||
static void fcoe_recv_frame(struct sk_buff *skb);
|
||||
|
||||
static void fcoe_get_lesb(struct fc_lport *, struct fc_els_lesb *);
|
||||
|
||||
/* notification function for packets from net device */
|
||||
static struct notifier_block fcoe_notifier = {
|
||||
.notifier_call = fcoe_device_notification,
|
||||
@@ -151,11 +154,11 @@ static int fcoe_vport_create(struct fc_vport *, bool disabled);
|
||||
static int fcoe_vport_disable(struct fc_vport *, bool disable);
|
||||
static void fcoe_set_vport_symbolic_name(struct fc_vport *);
|
||||
static void fcoe_set_port_id(struct fc_lport *, u32, struct fc_frame *);
|
||||
static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *);
|
||||
static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *);
|
||||
|
||||
static struct fcoe_sysfs_function_template fcoe_sysfs_templ = {
|
||||
.get_fcoe_ctlr_mode = fcoe_ctlr_get_fip_mode,
|
||||
.set_fcoe_ctlr_mode = fcoe_ctlr_set_fip_mode,
|
||||
.set_fcoe_ctlr_enabled = fcoe_ctlr_enabled,
|
||||
.get_fcoe_ctlr_link_fail = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_vlink_fail = fcoe_ctlr_get_lesb,
|
||||
.get_fcoe_ctlr_miss_fka = fcoe_ctlr_get_lesb,
|
||||
@@ -1112,10 +1115,17 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
||||
port = lport_priv(lport);
|
||||
port->lport = lport;
|
||||
port->priv = fcoe;
|
||||
port->get_netdev = fcoe_netdev;
|
||||
port->max_queue_depth = FCOE_MAX_QUEUE_DEPTH;
|
||||
port->min_queue_depth = FCOE_MIN_QUEUE_DEPTH;
|
||||
INIT_WORK(&port->destroy_work, fcoe_destroy_work);
|
||||
|
||||
/*
|
||||
* Need to add the lport to the hostlist
|
||||
* so we catch NETDEV_CHANGE events.
|
||||
*/
|
||||
fcoe_hostlist_add(lport);
|
||||
|
||||
/* configure a fc_lport including the exchange manager */
|
||||
rc = fcoe_lport_config(lport);
|
||||
if (rc) {
|
||||
@@ -1187,6 +1197,7 @@ static struct fc_lport *fcoe_if_create(struct fcoe_interface *fcoe,
|
||||
out_lp_destroy:
|
||||
fc_exch_mgr_free(lport);
|
||||
out_host_put:
|
||||
fcoe_hostlist_del(lport);
|
||||
scsi_host_put(lport->host);
|
||||
out:
|
||||
return ERR_PTR(rc);
|
||||
@@ -1964,6 +1975,7 @@ static int fcoe_dcb_app_notification(struct notifier_block *notifier,
|
||||
static int fcoe_device_notification(struct notifier_block *notifier,
|
||||
ulong event, void *ptr)
|
||||
{
|
||||
struct fcoe_ctlr_device *cdev;
|
||||
struct fc_lport *lport = NULL;
|
||||
struct net_device *netdev = ptr;
|
||||
struct fcoe_ctlr *ctlr;
|
||||
@@ -2020,13 +2032,29 @@ static int fcoe_device_notification(struct notifier_block *notifier,
|
||||
|
||||
fcoe_link_speed_update(lport);
|
||||
|
||||
if (link_possible && !fcoe_link_ok(lport))
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
else if (fcoe_ctlr_link_down(ctlr)) {
|
||||
stats = per_cpu_ptr(lport->stats, get_cpu());
|
||||
stats->LinkFailureCount++;
|
||||
put_cpu();
|
||||
fcoe_clean_pending_queue(lport);
|
||||
cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
|
||||
|
||||
if (link_possible && !fcoe_link_ok(lport)) {
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_DISABLED:
|
||||
pr_info("Link up while interface is disabled.\n");
|
||||
break;
|
||||
case FCOE_CTLR_ENABLED:
|
||||
case FCOE_CTLR_UNUSED:
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
};
|
||||
} else if (fcoe_ctlr_link_down(ctlr)) {
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_DISABLED:
|
||||
pr_info("Link down while interface is disabled.\n");
|
||||
break;
|
||||
case FCOE_CTLR_ENABLED:
|
||||
case FCOE_CTLR_UNUSED:
|
||||
stats = per_cpu_ptr(lport->stats, get_cpu());
|
||||
stats->LinkFailureCount++;
|
||||
put_cpu();
|
||||
fcoe_clean_pending_queue(lport);
|
||||
};
|
||||
}
|
||||
out:
|
||||
return rc;
|
||||
@@ -2039,6 +2067,8 @@ out:
|
||||
* Called from fcoe transport.
|
||||
*
|
||||
* Returns: 0 for success
|
||||
*
|
||||
* Deprecated: use fcoe_ctlr_enabled()
|
||||
*/
|
||||
static int fcoe_disable(struct net_device *netdev)
|
||||
{
|
||||
@@ -2097,6 +2127,33 @@ out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_ctlr_enabled() - Enable or disable an FCoE Controller
|
||||
* @cdev: The FCoE Controller that is being enabled or disabled
|
||||
*
|
||||
* fcoe_sysfs will ensure that the state of 'enabled' has
|
||||
* changed, so no checking is necessary here. This routine simply
|
||||
* calls fcoe_enable or fcoe_disable, both of which are deprecated.
|
||||
* When those routines are removed the functionality can be merged
|
||||
* here.
|
||||
*/
|
||||
static int fcoe_ctlr_enabled(struct fcoe_ctlr_device *cdev)
|
||||
{
|
||||
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(cdev);
|
||||
struct fc_lport *lport = ctlr->lp;
|
||||
struct net_device *netdev = fcoe_netdev(lport);
|
||||
|
||||
switch (cdev->enabled) {
|
||||
case FCOE_CTLR_ENABLED:
|
||||
return fcoe_enable(netdev);
|
||||
case FCOE_CTLR_DISABLED:
|
||||
return fcoe_disable(netdev);
|
||||
case FCOE_CTLR_UNUSED:
|
||||
default:
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_destroy() - Destroy a FCoE interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
@@ -2139,8 +2196,31 @@ static void fcoe_destroy_work(struct work_struct *work)
|
||||
{
|
||||
struct fcoe_port *port;
|
||||
struct fcoe_interface *fcoe;
|
||||
struct Scsi_Host *shost;
|
||||
struct fc_host_attrs *fc_host;
|
||||
unsigned long flags;
|
||||
struct fc_vport *vport;
|
||||
struct fc_vport *next_vport;
|
||||
|
||||
port = container_of(work, struct fcoe_port, destroy_work);
|
||||
shost = port->lport->host;
|
||||
fc_host = shost_to_fc_host(shost);
|
||||
|
||||
/* Loop through all the vports and mark them for deletion */
|
||||
spin_lock_irqsave(shost->host_lock, flags);
|
||||
list_for_each_entry_safe(vport, next_vport, &fc_host->vports, peers) {
|
||||
if (vport->flags & (FC_VPORT_DEL | FC_VPORT_CREATING)) {
|
||||
continue;
|
||||
} else {
|
||||
vport->flags |= FC_VPORT_DELETING;
|
||||
queue_work(fc_host_work_q(shost),
|
||||
&vport->vport_delete_work);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(shost->host_lock, flags);
|
||||
|
||||
flush_workqueue(fc_host_work_q(shost));
|
||||
|
||||
mutex_lock(&fcoe_config_mutex);
|
||||
|
||||
fcoe = port->priv;
|
||||
@@ -2204,16 +2284,26 @@ static void fcoe_dcb_create(struct fcoe_interface *fcoe)
|
||||
#endif
|
||||
}
|
||||
|
||||
enum fcoe_create_link_state {
|
||||
FCOE_CREATE_LINK_DOWN,
|
||||
FCOE_CREATE_LINK_UP,
|
||||
};
|
||||
|
||||
/**
|
||||
* fcoe_create() - Create a fcoe interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
* @fip_mode: The FIP mode for this creation
|
||||
* _fcoe_create() - (internal) Create a fcoe interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
* @fip_mode: The FIP mode for this creation
|
||||
* @link_state: The ctlr link state on creation
|
||||
*
|
||||
* Called from fcoe transport
|
||||
* Called from either the libfcoe 'create' module parameter
|
||||
* via fcoe_create or from fcoe_syfs's ctlr_create file.
|
||||
*
|
||||
* Returns: 0 for success
|
||||
* libfcoe's 'create' module parameter is deprecated so some
|
||||
* consolidation of code can be done when that interface is
|
||||
* removed.
|
||||
*/
|
||||
static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
static int _fcoe_create(struct net_device *netdev, enum fip_state fip_mode,
|
||||
enum fcoe_create_link_state link_state)
|
||||
{
|
||||
int rc = 0;
|
||||
struct fcoe_ctlr_device *ctlr_dev;
|
||||
@@ -2254,13 +2344,29 @@ static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
/* setup DCB priority attributes. */
|
||||
fcoe_dcb_create(fcoe);
|
||||
|
||||
/* add to lports list */
|
||||
fcoe_hostlist_add(lport);
|
||||
|
||||
/* start FIP Discovery and FLOGI */
|
||||
lport->boot_time = jiffies;
|
||||
fc_fabric_login(lport);
|
||||
if (!fcoe_link_ok(lport)) {
|
||||
|
||||
/*
|
||||
* If the fcoe_ctlr_device is to be set to DISABLED
|
||||
* it must be done after the lport is added to the
|
||||
* hostlist, but before the rtnl_lock is released.
|
||||
* This is because the rtnl_lock protects the
|
||||
* hostlist that fcoe_device_notification uses. If
|
||||
* the FCoE Controller is intended to be created
|
||||
* DISABLED then 'enabled' needs to be considered
|
||||
* handling link events. 'enabled' must be set
|
||||
* before the lport can be found in the hostlist
|
||||
* when a link up event is received.
|
||||
*/
|
||||
if (link_state == FCOE_CREATE_LINK_UP)
|
||||
ctlr_dev->enabled = FCOE_CTLR_ENABLED;
|
||||
else
|
||||
ctlr_dev->enabled = FCOE_CTLR_DISABLED;
|
||||
|
||||
if (link_state == FCOE_CREATE_LINK_UP &&
|
||||
!fcoe_link_ok(lport)) {
|
||||
rtnl_unlock();
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
mutex_unlock(&fcoe_config_mutex);
|
||||
@@ -2275,37 +2381,34 @@ out_nortnl:
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_link_speed_update() - Update the supported and actual link speeds
|
||||
* @lport: The local port to update speeds for
|
||||
* fcoe_create() - Create a fcoe interface
|
||||
* @netdev : The net_device object the Ethernet interface to create on
|
||||
* @fip_mode: The FIP mode for this creation
|
||||
*
|
||||
* Returns: 0 if the ethtool query was successful
|
||||
* -1 if the ethtool query failed
|
||||
* Called from fcoe transport
|
||||
*
|
||||
* Returns: 0 for success
|
||||
*/
|
||||
static int fcoe_link_speed_update(struct fc_lport *lport)
|
||||
static int fcoe_create(struct net_device *netdev, enum fip_state fip_mode)
|
||||
{
|
||||
struct net_device *netdev = fcoe_netdev(lport);
|
||||
struct ethtool_cmd ecmd;
|
||||
return _fcoe_create(netdev, fip_mode, FCOE_CREATE_LINK_UP);
|
||||
}
|
||||
|
||||
if (!__ethtool_get_settings(netdev, &ecmd)) {
|
||||
lport->link_supported_speeds &=
|
||||
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
|
||||
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full))
|
||||
lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
|
||||
if (ecmd.supported & SUPPORTED_10000baseT_Full)
|
||||
lport->link_supported_speeds |=
|
||||
FC_PORTSPEED_10GBIT;
|
||||
switch (ethtool_cmd_speed(&ecmd)) {
|
||||
case SPEED_1000:
|
||||
lport->link_speed = FC_PORTSPEED_1GBIT;
|
||||
break;
|
||||
case SPEED_10000:
|
||||
lport->link_speed = FC_PORTSPEED_10GBIT;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
/**
|
||||
* fcoe_ctlr_alloc() - Allocate a fcoe interface from fcoe_sysfs
|
||||
* @netdev: The net_device to be used by the allocated FCoE Controller
|
||||
*
|
||||
* This routine is called from fcoe_sysfs. It will start the fcoe_ctlr
|
||||
* in a link_down state. The allows the user an opportunity to configure
|
||||
* the FCoE Controller from sysfs before enabling the FCoE Controller.
|
||||
*
|
||||
* Creating in with this routine starts the FCoE Controller in Fabric
|
||||
* mode. The user can change to VN2VN or another mode before enabling.
|
||||
*/
|
||||
static int fcoe_ctlr_alloc(struct net_device *netdev)
|
||||
{
|
||||
return _fcoe_create(netdev, FIP_MODE_FABRIC,
|
||||
FCOE_CREATE_LINK_DOWN);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2375,10 +2478,13 @@ static int fcoe_reset(struct Scsi_Host *shost)
|
||||
struct fcoe_port *port = lport_priv(lport);
|
||||
struct fcoe_interface *fcoe = port->priv;
|
||||
struct fcoe_ctlr *ctlr = fcoe_to_ctlr(fcoe);
|
||||
struct fcoe_ctlr_device *cdev = fcoe_ctlr_to_ctlr_dev(ctlr);
|
||||
|
||||
fcoe_ctlr_link_down(ctlr);
|
||||
fcoe_clean_pending_queue(ctlr->lp);
|
||||
if (!fcoe_link_ok(ctlr->lp))
|
||||
|
||||
if (cdev->enabled != FCOE_CTLR_DISABLED &&
|
||||
!fcoe_link_ok(ctlr->lp))
|
||||
fcoe_ctlr_link_up(ctlr);
|
||||
return 0;
|
||||
}
|
||||
@@ -2445,12 +2551,31 @@ static int fcoe_hostlist_add(const struct fc_lport *lport)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_hostlist_del() - Remove the FCoE interface identified by a local
|
||||
* port to the hostlist
|
||||
* @lport: The local port that identifies the FCoE interface to be added
|
||||
*
|
||||
* Locking: must be called with the RTNL mutex held
|
||||
*
|
||||
*/
|
||||
static void fcoe_hostlist_del(const struct fc_lport *lport)
|
||||
{
|
||||
struct fcoe_interface *fcoe;
|
||||
struct fcoe_port *port;
|
||||
|
||||
port = lport_priv(lport);
|
||||
fcoe = port->priv;
|
||||
list_del(&fcoe->list);
|
||||
return;
|
||||
}
|
||||
|
||||
static struct fcoe_transport fcoe_sw_transport = {
|
||||
.name = {FCOE_TRANSPORT_DEFAULT},
|
||||
.attached = false,
|
||||
.list = LIST_HEAD_INIT(fcoe_sw_transport.list),
|
||||
.match = fcoe_match,
|
||||
.alloc = fcoe_ctlr_alloc,
|
||||
.create = fcoe_create,
|
||||
.destroy = fcoe_destroy,
|
||||
.enable = fcoe_enable,
|
||||
@@ -2534,9 +2659,9 @@ static void __exit fcoe_exit(void)
|
||||
/* releases the associated fcoe hosts */
|
||||
rtnl_lock();
|
||||
list_for_each_entry_safe(fcoe, tmp, &fcoe_hostlist, list) {
|
||||
list_del(&fcoe->list);
|
||||
ctlr = fcoe_to_ctlr(fcoe);
|
||||
port = lport_priv(ctlr->lp);
|
||||
fcoe_hostlist_del(port->lport);
|
||||
queue_work(fcoe_wq, &port->destroy_work);
|
||||
}
|
||||
rtnl_unlock();
|
||||
@@ -2776,43 +2901,6 @@ static void fcoe_set_vport_symbolic_name(struct fc_vport *vport)
|
||||
NULL, NULL, 3 * lport->r_a_tov);
|
||||
}
|
||||
|
||||
/**
|
||||
* fcoe_get_lesb() - Fill the FCoE Link Error Status Block
|
||||
* @lport: the local port
|
||||
* @fc_lesb: the link error status block
|
||||
*/
|
||||
static void fcoe_get_lesb(struct fc_lport *lport,
|
||||
struct fc_els_lesb *fc_lesb)
|
||||
{
|
||||
struct net_device *netdev = fcoe_netdev(lport);
|
||||
|
||||
__fcoe_get_lesb(lport, fc_lesb, netdev);
|
||||
}
|
||||
|
||||
static void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
|
||||
{
|
||||
struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
|
||||
struct net_device *netdev = fcoe_netdev(fip->lp);
|
||||
struct fcoe_fc_els_lesb *fcoe_lesb;
|
||||
struct fc_els_lesb fc_lesb;
|
||||
|
||||
__fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
|
||||
fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
|
||||
|
||||
ctlr_dev->lesb.lesb_link_fail =
|
||||
ntohl(fcoe_lesb->lesb_link_fail);
|
||||
ctlr_dev->lesb.lesb_vlink_fail =
|
||||
ntohl(fcoe_lesb->lesb_vlink_fail);
|
||||
ctlr_dev->lesb.lesb_miss_fka =
|
||||
ntohl(fcoe_lesb->lesb_miss_fka);
|
||||
ctlr_dev->lesb.lesb_symb_err =
|
||||
ntohl(fcoe_lesb->lesb_symb_err);
|
||||
ctlr_dev->lesb.lesb_err_block =
|
||||
ntohl(fcoe_lesb->lesb_err_block);
|
||||
ctlr_dev->lesb.lesb_fcs_error =
|
||||
ntohl(fcoe_lesb->lesb_fcs_error);
|
||||
}
|
||||
|
||||
static void fcoe_fcf_get_vlan_id(struct fcoe_fcf_device *fcf_dev)
|
||||
{
|
||||
struct fcoe_ctlr_device *ctlr_dev =
|
||||
|
||||
@@ -55,12 +55,12 @@ do { \
|
||||
|
||||
#define FCOE_DBG(fmt, args...) \
|
||||
FCOE_CHECK_LOGGING(FCOE_LOGGING, \
|
||||
printk(KERN_INFO "fcoe: " fmt, ##args);)
|
||||
pr_info("fcoe: " fmt, ##args);)
|
||||
|
||||
#define FCOE_NETDEV_DBG(netdev, fmt, args...) \
|
||||
FCOE_CHECK_LOGGING(FCOE_NETDEV_LOGGING, \
|
||||
printk(KERN_INFO "fcoe: %s: " fmt, \
|
||||
netdev->name, ##args);)
|
||||
pr_info("fcoe: %s: " fmt, \
|
||||
netdev->name, ##args);)
|
||||
|
||||
/**
|
||||
* struct fcoe_interface - A FCoE interface
|
||||
|
||||
@@ -1291,8 +1291,16 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
|
||||
|
||||
LIBFCOE_FIP_DBG(fip, "Clear Virtual Link received\n");
|
||||
|
||||
if (!fcf || !lport->port_id)
|
||||
if (!fcf || !lport->port_id) {
|
||||
/*
|
||||
* We are yet to select best FCF, but we got CVL in the
|
||||
* meantime. reset the ctlr and let it rediscover the FCF
|
||||
*/
|
||||
mutex_lock(&fip->ctlr_mutex);
|
||||
fcoe_ctlr_reset(fip);
|
||||
mutex_unlock(&fip->ctlr_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* mask of required descriptors. Validating each one clears its bit.
|
||||
@@ -1551,15 +1559,6 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
|
||||
fcf->fabric_name, fcf->vfid, fcf->fcf_mac,
|
||||
fcf->fc_map, fcoe_ctlr_mtu_valid(fcf),
|
||||
fcf->flogi_sent, fcf->pri);
|
||||
if (fcf->fabric_name != first->fabric_name ||
|
||||
fcf->vfid != first->vfid ||
|
||||
fcf->fc_map != first->fc_map) {
|
||||
LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
|
||||
"or FC-MAP\n");
|
||||
return NULL;
|
||||
}
|
||||
if (fcf->flogi_sent)
|
||||
continue;
|
||||
if (!fcoe_ctlr_fcf_usable(fcf)) {
|
||||
LIBFCOE_FIP_DBG(fip, "FCF for fab %16.16llx "
|
||||
"map %x %svalid %savailable\n",
|
||||
@@ -1569,6 +1568,15 @@ static struct fcoe_fcf *fcoe_ctlr_select(struct fcoe_ctlr *fip)
|
||||
"" : "un");
|
||||
continue;
|
||||
}
|
||||
if (fcf->fabric_name != first->fabric_name ||
|
||||
fcf->vfid != first->vfid ||
|
||||
fcf->fc_map != first->fc_map) {
|
||||
LIBFCOE_FIP_DBG(fip, "Conflicting fabric, VFID, "
|
||||
"or FC-MAP\n");
|
||||
return NULL;
|
||||
}
|
||||
if (fcf->flogi_sent)
|
||||
continue;
|
||||
if (!best || fcf->pri < best->pri || best->flogi_sent)
|
||||
best = fcf;
|
||||
}
|
||||
@@ -2864,22 +2872,21 @@ void fcoe_fcf_get_selected(struct fcoe_fcf_device *fcf_dev)
|
||||
}
|
||||
EXPORT_SYMBOL(fcoe_fcf_get_selected);
|
||||
|
||||
void fcoe_ctlr_get_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
|
||||
void fcoe_ctlr_set_fip_mode(struct fcoe_ctlr_device *ctlr_dev)
|
||||
{
|
||||
struct fcoe_ctlr *ctlr = fcoe_ctlr_device_priv(ctlr_dev);
|
||||
|
||||
mutex_lock(&ctlr->ctlr_mutex);
|
||||
switch (ctlr->mode) {
|
||||
case FIP_MODE_FABRIC:
|
||||
ctlr_dev->mode = FIP_CONN_TYPE_FABRIC;
|
||||
break;
|
||||
case FIP_MODE_VN2VN:
|
||||
ctlr_dev->mode = FIP_CONN_TYPE_VN2VN;
|
||||
switch (ctlr_dev->mode) {
|
||||
case FIP_CONN_TYPE_VN2VN:
|
||||
ctlr->mode = FIP_MODE_VN2VN;
|
||||
break;
|
||||
case FIP_CONN_TYPE_FABRIC:
|
||||
default:
|
||||
ctlr_dev->mode = FIP_CONN_TYPE_UNKNOWN;
|
||||
ctlr->mode = FIP_MODE_FABRIC;
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_unlock(&ctlr->ctlr_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(fcoe_ctlr_get_fip_mode);
|
||||
EXPORT_SYMBOL(fcoe_ctlr_set_fip_mode);
|
||||
|
||||
+152
-34
@@ -21,8 +21,17 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#include <scsi/fcoe_sysfs.h>
|
||||
#include <scsi/libfcoe.h>
|
||||
|
||||
/*
|
||||
* OK to include local libfcoe.h for debug_logging, but cannot include
|
||||
* <scsi/libfcoe.h> otherwise non-netdev based fcoe solutions would have
|
||||
* have to include more than fcoe_sysfs.h.
|
||||
*/
|
||||
#include "libfcoe.h"
|
||||
|
||||
static atomic_t ctlr_num;
|
||||
static atomic_t fcf_num;
|
||||
@@ -71,6 +80,8 @@ MODULE_PARM_DESC(fcf_dev_loss_tmo,
|
||||
((x)->lesb.lesb_err_block)
|
||||
#define fcoe_ctlr_fcs_error(x) \
|
||||
((x)->lesb.lesb_fcs_error)
|
||||
#define fcoe_ctlr_enabled(x) \
|
||||
((x)->enabled)
|
||||
#define fcoe_fcf_state(x) \
|
||||
((x)->state)
|
||||
#define fcoe_fcf_fabric_name(x) \
|
||||
@@ -210,25 +221,34 @@ static ssize_t show_fcoe_fcf_device_##field(struct device *dev, \
|
||||
#define fcoe_enum_name_search(title, table_type, table) \
|
||||
static const char *get_fcoe_##title##_name(enum table_type table_key) \
|
||||
{ \
|
||||
int i; \
|
||||
char *name = NULL; \
|
||||
\
|
||||
for (i = 0; i < ARRAY_SIZE(table); i++) { \
|
||||
if (table[i].value == table_key) { \
|
||||
name = table[i].name; \
|
||||
break; \
|
||||
} \
|
||||
} \
|
||||
return name; \
|
||||
if (table_key < 0 || table_key >= ARRAY_SIZE(table)) \
|
||||
return NULL; \
|
||||
return table[table_key]; \
|
||||
}
|
||||
|
||||
static struct {
|
||||
enum fcf_state value;
|
||||
char *name;
|
||||
} fcf_state_names[] = {
|
||||
{ FCOE_FCF_STATE_UNKNOWN, "Unknown" },
|
||||
{ FCOE_FCF_STATE_DISCONNECTED, "Disconnected" },
|
||||
{ FCOE_FCF_STATE_CONNECTED, "Connected" },
|
||||
static char *fip_conn_type_names[] = {
|
||||
[ FIP_CONN_TYPE_UNKNOWN ] = "Unknown",
|
||||
[ FIP_CONN_TYPE_FABRIC ] = "Fabric",
|
||||
[ FIP_CONN_TYPE_VN2VN ] = "VN2VN",
|
||||
};
|
||||
fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
|
||||
|
||||
static enum fip_conn_type fcoe_parse_mode(const char *buf)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(fip_conn_type_names); i++) {
|
||||
if (strcasecmp(buf, fip_conn_type_names[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
|
||||
return FIP_CONN_TYPE_UNKNOWN;
|
||||
}
|
||||
|
||||
static char *fcf_state_names[] = {
|
||||
[ FCOE_FCF_STATE_UNKNOWN ] = "Unknown",
|
||||
[ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected",
|
||||
[ FCOE_FCF_STATE_CONNECTED ] = "Connected",
|
||||
};
|
||||
fcoe_enum_name_search(fcf_state, fcf_state, fcf_state_names)
|
||||
#define FCOE_FCF_STATE_MAX_NAMELEN 50
|
||||
@@ -246,17 +266,7 @@ static ssize_t show_fcf_state(struct device *dev,
|
||||
}
|
||||
static FCOE_DEVICE_ATTR(fcf, state, S_IRUGO, show_fcf_state, NULL);
|
||||
|
||||
static struct {
|
||||
enum fip_conn_type value;
|
||||
char *name;
|
||||
} fip_conn_type_names[] = {
|
||||
{ FIP_CONN_TYPE_UNKNOWN, "Unknown" },
|
||||
{ FIP_CONN_TYPE_FABRIC, "Fabric" },
|
||||
{ FIP_CONN_TYPE_VN2VN, "VN2VN" },
|
||||
};
|
||||
fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names)
|
||||
#define FCOE_CTLR_MODE_MAX_NAMELEN 50
|
||||
|
||||
#define FCOE_MAX_MODENAME_LEN 20
|
||||
static ssize_t show_ctlr_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
@@ -264,17 +274,116 @@ static ssize_t show_ctlr_mode(struct device *dev,
|
||||
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
|
||||
const char *name;
|
||||
|
||||
if (ctlr->f->get_fcoe_ctlr_mode)
|
||||
ctlr->f->get_fcoe_ctlr_mode(ctlr);
|
||||
|
||||
name = get_fcoe_ctlr_mode_name(ctlr->mode);
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
return snprintf(buf, FCOE_CTLR_MODE_MAX_NAMELEN,
|
||||
return snprintf(buf, FCOE_MAX_MODENAME_LEN,
|
||||
"%s\n", name);
|
||||
}
|
||||
static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO,
|
||||
show_ctlr_mode, NULL);
|
||||
|
||||
static ssize_t store_ctlr_mode(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
|
||||
char mode[FCOE_MAX_MODENAME_LEN + 1];
|
||||
|
||||
if (count > FCOE_MAX_MODENAME_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
strncpy(mode, buf, count);
|
||||
|
||||
if (mode[count - 1] == '\n')
|
||||
mode[count - 1] = '\0';
|
||||
else
|
||||
mode[count] = '\0';
|
||||
|
||||
switch (ctlr->enabled) {
|
||||
case FCOE_CTLR_ENABLED:
|
||||
LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.");
|
||||
return -EBUSY;
|
||||
case FCOE_CTLR_DISABLED:
|
||||
if (!ctlr->f->set_fcoe_ctlr_mode) {
|
||||
LIBFCOE_SYSFS_DBG(ctlr,
|
||||
"Mode change not supported by LLD.");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
ctlr->mode = fcoe_parse_mode(mode);
|
||||
if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) {
|
||||
LIBFCOE_SYSFS_DBG(ctlr,
|
||||
"Unknown mode %s provided.", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ctlr->f->set_fcoe_ctlr_mode(ctlr);
|
||||
LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.", buf);
|
||||
|
||||
return count;
|
||||
case FCOE_CTLR_UNUSED:
|
||||
default:
|
||||
LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.");
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
}
|
||||
|
||||
static FCOE_DEVICE_ATTR(ctlr, mode, S_IRUGO | S_IWUSR,
|
||||
show_ctlr_mode, store_ctlr_mode);
|
||||
|
||||
static ssize_t store_ctlr_enabled(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
|
||||
int rc;
|
||||
|
||||
switch (ctlr->enabled) {
|
||||
case FCOE_CTLR_ENABLED:
|
||||
if (*buf == '1')
|
||||
return count;
|
||||
ctlr->enabled = FCOE_CTLR_DISABLED;
|
||||
break;
|
||||
case FCOE_CTLR_DISABLED:
|
||||
if (*buf == '0')
|
||||
return count;
|
||||
ctlr->enabled = FCOE_CTLR_ENABLED;
|
||||
break;
|
||||
case FCOE_CTLR_UNUSED:
|
||||
return -ENOTSUPP;
|
||||
};
|
||||
|
||||
rc = ctlr->f->set_fcoe_ctlr_enabled(ctlr);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static char *ctlr_enabled_state_names[] = {
|
||||
[ FCOE_CTLR_ENABLED ] = "1",
|
||||
[ FCOE_CTLR_DISABLED ] = "0",
|
||||
};
|
||||
fcoe_enum_name_search(ctlr_enabled_state, ctlr_enabled_state,
|
||||
ctlr_enabled_state_names)
|
||||
#define FCOE_CTLR_ENABLED_MAX_NAMELEN 50
|
||||
|
||||
static ssize_t show_ctlr_enabled_state(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev);
|
||||
const char *name;
|
||||
|
||||
name = get_fcoe_ctlr_enabled_state_name(ctlr->enabled);
|
||||
if (!name)
|
||||
return -EINVAL;
|
||||
return snprintf(buf, FCOE_CTLR_ENABLED_MAX_NAMELEN,
|
||||
"%s\n", name);
|
||||
}
|
||||
|
||||
static FCOE_DEVICE_ATTR(ctlr, enabled, S_IRUGO | S_IWUSR,
|
||||
show_ctlr_enabled_state,
|
||||
store_ctlr_enabled);
|
||||
|
||||
static ssize_t
|
||||
store_private_fcoe_ctlr_fcf_dev_loss_tmo(struct device *dev,
|
||||
@@ -359,6 +468,7 @@ static struct attribute_group fcoe_ctlr_lesb_attr_group = {
|
||||
|
||||
static struct attribute *fcoe_ctlr_attrs[] = {
|
||||
&device_attr_fcoe_ctlr_fcf_dev_loss_tmo.attr,
|
||||
&device_attr_fcoe_ctlr_enabled.attr,
|
||||
&device_attr_fcoe_ctlr_mode.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -443,9 +553,16 @@ struct device_type fcoe_fcf_device_type = {
|
||||
.release = fcoe_fcf_device_release,
|
||||
};
|
||||
|
||||
struct bus_attribute fcoe_bus_attr_group[] = {
|
||||
__ATTR(ctlr_create, S_IWUSR, NULL, fcoe_ctlr_create_store),
|
||||
__ATTR(ctlr_destroy, S_IWUSR, NULL, fcoe_ctlr_destroy_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
struct bus_type fcoe_bus_type = {
|
||||
.name = "fcoe",
|
||||
.match = &fcoe_bus_match,
|
||||
.bus_attrs = fcoe_bus_attr_group,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -566,6 +683,7 @@ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent,
|
||||
|
||||
ctlr->id = atomic_inc_return(&ctlr_num) - 1;
|
||||
ctlr->f = f;
|
||||
ctlr->mode = FIP_CONN_TYPE_FABRIC;
|
||||
INIT_LIST_HEAD(&ctlr->fcfs);
|
||||
mutex_init(&ctlr->lock);
|
||||
ctlr->dev.parent = parent;
|
||||
|
||||
@@ -83,6 +83,50 @@ static struct notifier_block libfcoe_notifier = {
|
||||
.notifier_call = libfcoe_device_notification,
|
||||
};
|
||||
|
||||
/**
|
||||
* fcoe_link_speed_update() - Update the supported and actual link speeds
|
||||
* @lport: The local port to update speeds for
|
||||
*
|
||||
* Returns: 0 if the ethtool query was successful
|
||||
* -1 if the ethtool query failed
|
||||
*/
|
||||
int fcoe_link_speed_update(struct fc_lport *lport)
|
||||
{
|
||||
struct net_device *netdev = fcoe_get_netdev(lport);
|
||||
struct ethtool_cmd ecmd;
|
||||
|
||||
if (!__ethtool_get_settings(netdev, &ecmd)) {
|
||||
lport->link_supported_speeds &=
|
||||
~(FC_PORTSPEED_1GBIT | FC_PORTSPEED_10GBIT);
|
||||
if (ecmd.supported & (SUPPORTED_1000baseT_Half |
|
||||
SUPPORTED_1000baseT_Full))
|
||||
lport->link_supported_speeds |= FC_PORTSPEED_1GBIT;
|
||||
if (ecmd.supported & SUPPORTED_10000baseT_Full)
|
||||
lport->link_supported_speeds |=
|
||||
FC_PORTSPEED_10GBIT;
|
||||
switch (ethtool_cmd_speed(&ecmd)) {
|
||||
case SPEED_1000:
|
||||
lport->link_speed = FC_PORTSPEED_1GBIT;
|
||||
break;
|
||||
case SPEED_10000:
|
||||
lport->link_speed = FC_PORTSPEED_10GBIT;
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fcoe_link_speed_update);
|
||||
|
||||
/**
|
||||
* __fcoe_get_lesb() - Get the Link Error Status Block (LESB) for a given lport
|
||||
* @lport: The local port to update speeds for
|
||||
* @fc_lesb: Pointer to the LESB to be filled up
|
||||
* @netdev: Pointer to the netdev that is associated with the lport
|
||||
*
|
||||
* Note, the Link Error Status Block (LESB) for FCoE is defined in FC-BB-6
|
||||
* Clause 7.11 in v1.04.
|
||||
*/
|
||||
void __fcoe_get_lesb(struct fc_lport *lport,
|
||||
struct fc_els_lesb *fc_lesb,
|
||||
struct net_device *netdev)
|
||||
@@ -112,6 +156,51 @@ void __fcoe_get_lesb(struct fc_lport *lport,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__fcoe_get_lesb);
|
||||
|
||||
/**
|
||||
* fcoe_get_lesb() - Fill the FCoE Link Error Status Block
|
||||
* @lport: the local port
|
||||
* @fc_lesb: the link error status block
|
||||
*/
|
||||
void fcoe_get_lesb(struct fc_lport *lport,
|
||||
struct fc_els_lesb *fc_lesb)
|
||||
{
|
||||
struct net_device *netdev = fcoe_get_netdev(lport);
|
||||
|
||||
__fcoe_get_lesb(lport, fc_lesb, netdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fcoe_get_lesb);
|
||||
|
||||
/**
|
||||
* fcoe_ctlr_get_lesb() - Get the Link Error Status Block (LESB) for a given
|
||||
* fcoe controller device
|
||||
* @ctlr_dev: The given fcoe controller device
|
||||
*
|
||||
*/
|
||||
void fcoe_ctlr_get_lesb(struct fcoe_ctlr_device *ctlr_dev)
|
||||
{
|
||||
struct fcoe_ctlr *fip = fcoe_ctlr_device_priv(ctlr_dev);
|
||||
struct net_device *netdev = fcoe_get_netdev(fip->lp);
|
||||
struct fcoe_fc_els_lesb *fcoe_lesb;
|
||||
struct fc_els_lesb fc_lesb;
|
||||
|
||||
__fcoe_get_lesb(fip->lp, &fc_lesb, netdev);
|
||||
fcoe_lesb = (struct fcoe_fc_els_lesb *)(&fc_lesb);
|
||||
|
||||
ctlr_dev->lesb.lesb_link_fail =
|
||||
ntohl(fcoe_lesb->lesb_link_fail);
|
||||
ctlr_dev->lesb.lesb_vlink_fail =
|
||||
ntohl(fcoe_lesb->lesb_vlink_fail);
|
||||
ctlr_dev->lesb.lesb_miss_fka =
|
||||
ntohl(fcoe_lesb->lesb_miss_fka);
|
||||
ctlr_dev->lesb.lesb_symb_err =
|
||||
ntohl(fcoe_lesb->lesb_symb_err);
|
||||
ctlr_dev->lesb.lesb_err_block =
|
||||
ntohl(fcoe_lesb->lesb_err_block);
|
||||
ctlr_dev->lesb.lesb_fcs_error =
|
||||
ntohl(fcoe_lesb->lesb_fcs_error);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fcoe_ctlr_get_lesb);
|
||||
|
||||
void fcoe_wwn_to_str(u64 wwn, char *buf, int len)
|
||||
{
|
||||
u8 wwpn[8];
|
||||
@@ -627,6 +716,110 @@ static int libfcoe_device_notification(struct notifier_block *notifier,
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
ssize_t fcoe_ctlr_create_store(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct net_device *netdev = NULL;
|
||||
struct fcoe_transport *ft = NULL;
|
||||
struct fcoe_ctlr_device *ctlr_dev = NULL;
|
||||
int rc = 0;
|
||||
int err;
|
||||
|
||||
mutex_lock(&ft_mutex);
|
||||
|
||||
netdev = fcoe_if_to_netdev(buf);
|
||||
if (!netdev) {
|
||||
LIBFCOE_TRANSPORT_DBG("Invalid device %s.\n", buf);
|
||||
rc = -ENODEV;
|
||||
goto out_nodev;
|
||||
}
|
||||
|
||||
ft = fcoe_netdev_map_lookup(netdev);
|
||||
if (ft) {
|
||||
LIBFCOE_TRANSPORT_DBG("transport %s already has existing "
|
||||
"FCoE instance on %s.\n",
|
||||
ft->name, netdev->name);
|
||||
rc = -EEXIST;
|
||||
goto out_putdev;
|
||||
}
|
||||
|
||||
ft = fcoe_transport_lookup(netdev);
|
||||
if (!ft) {
|
||||
LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
|
||||
netdev->name);
|
||||
rc = -ENODEV;
|
||||
goto out_putdev;
|
||||
}
|
||||
|
||||
/* pass to transport create */
|
||||
err = ft->alloc ? ft->alloc(netdev) : -ENODEV;
|
||||
if (err) {
|
||||
fcoe_del_netdev_mapping(netdev);
|
||||
rc = -ENOMEM;
|
||||
goto out_putdev;
|
||||
}
|
||||
|
||||
err = fcoe_add_netdev_mapping(netdev, ft);
|
||||
if (err) {
|
||||
LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping "
|
||||
"for FCoE transport %s for %s.\n",
|
||||
ft->name, netdev->name);
|
||||
rc = -ENODEV;
|
||||
goto out_putdev;
|
||||
}
|
||||
|
||||
LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
|
||||
ft->name, (ctlr_dev) ? "succeeded" : "failed",
|
||||
netdev->name);
|
||||
|
||||
out_putdev:
|
||||
dev_put(netdev);
|
||||
out_nodev:
|
||||
mutex_unlock(&ft_mutex);
|
||||
if (rc)
|
||||
return rc;
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t fcoe_ctlr_destroy_store(struct bus_type *bus,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int rc = -ENODEV;
|
||||
struct net_device *netdev = NULL;
|
||||
struct fcoe_transport *ft = NULL;
|
||||
|
||||
mutex_lock(&ft_mutex);
|
||||
|
||||
netdev = fcoe_if_to_netdev(buf);
|
||||
if (!netdev) {
|
||||
LIBFCOE_TRANSPORT_DBG("invalid device %s.\n", buf);
|
||||
goto out_nodev;
|
||||
}
|
||||
|
||||
ft = fcoe_netdev_map_lookup(netdev);
|
||||
if (!ft) {
|
||||
LIBFCOE_TRANSPORT_DBG("no FCoE transport found for %s.\n",
|
||||
netdev->name);
|
||||
goto out_putdev;
|
||||
}
|
||||
|
||||
/* pass to transport destroy */
|
||||
rc = ft->destroy(netdev);
|
||||
if (rc)
|
||||
goto out_putdev;
|
||||
|
||||
fcoe_del_netdev_mapping(netdev);
|
||||
LIBFCOE_TRANSPORT_DBG("transport %s %s to destroy fcoe on %s.\n",
|
||||
ft->name, (rc) ? "failed" : "succeeded",
|
||||
netdev->name);
|
||||
rc = count; /* required for successful return */
|
||||
out_putdev:
|
||||
dev_put(netdev);
|
||||
out_nodev:
|
||||
mutex_unlock(&ft_mutex);
|
||||
return rc;
|
||||
}
|
||||
EXPORT_SYMBOL(fcoe_ctlr_destroy_store);
|
||||
|
||||
/**
|
||||
* fcoe_transport_create() - Create a fcoe interface
|
||||
@@ -769,11 +962,7 @@ out_putdev:
|
||||
dev_put(netdev);
|
||||
out_nodev:
|
||||
mutex_unlock(&ft_mutex);
|
||||
|
||||
if (rc == -ERESTARTSYS)
|
||||
return restart_syscall();
|
||||
else
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
#define _FCOE_LIBFCOE_H_
|
||||
|
||||
extern unsigned int libfcoe_debug_logging;
|
||||
#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
|
||||
#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
|
||||
#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */
|
||||
#define LIBFCOE_LOGGING 0x01 /* General logging, not categorized */
|
||||
#define LIBFCOE_FIP_LOGGING 0x02 /* FIP logging */
|
||||
#define LIBFCOE_TRANSPORT_LOGGING 0x04 /* FCoE transport logging */
|
||||
#define LIBFCOE_SYSFS_LOGGING 0x08 /* fcoe_sysfs logging */
|
||||
|
||||
#define LIBFCOE_CHECK_LOGGING(LEVEL, CMD) \
|
||||
do { \
|
||||
@@ -16,16 +17,19 @@ do { \
|
||||
|
||||
#define LIBFCOE_DBG(fmt, args...) \
|
||||
LIBFCOE_CHECK_LOGGING(LIBFCOE_LOGGING, \
|
||||
printk(KERN_INFO "libfcoe: " fmt, ##args);)
|
||||
pr_info("libfcoe: " fmt, ##args);)
|
||||
|
||||
#define LIBFCOE_FIP_DBG(fip, fmt, args...) \
|
||||
LIBFCOE_CHECK_LOGGING(LIBFCOE_FIP_LOGGING, \
|
||||
printk(KERN_INFO "host%d: fip: " fmt, \
|
||||
(fip)->lp->host->host_no, ##args);)
|
||||
pr_info("host%d: fip: " fmt, \
|
||||
(fip)->lp->host->host_no, ##args);)
|
||||
|
||||
#define LIBFCOE_TRANSPORT_DBG(fmt, args...) \
|
||||
LIBFCOE_CHECK_LOGGING(LIBFCOE_TRANSPORT_LOGGING, \
|
||||
printk(KERN_INFO "%s: " fmt, \
|
||||
__func__, ##args);)
|
||||
pr_info("%s: " fmt, __func__, ##args);)
|
||||
|
||||
#define LIBFCOE_SYSFS_DBG(cdev, fmt, args...) \
|
||||
LIBFCOE_CHECK_LOGGING(LIBFCOE_SYSFS_LOGGING, \
|
||||
pr_info("ctlr_%d: " fmt, cdev->id, ##args);)
|
||||
|
||||
#endif /* _FCOE_LIBFCOE_H_ */
|
||||
|
||||
@@ -7,6 +7,8 @@ fnic-y := \
|
||||
fnic_res.o \
|
||||
fnic_fcs.o \
|
||||
fnic_scsi.o \
|
||||
fnic_trace.o \
|
||||
fnic_debugfs.o \
|
||||
vnic_cq.o \
|
||||
vnic_dev.o \
|
||||
vnic_intr.o \
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <scsi/libfcoe.h>
|
||||
#include "fnic_io.h"
|
||||
#include "fnic_res.h"
|
||||
#include "fnic_trace.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_rq.h"
|
||||
@@ -55,6 +56,34 @@
|
||||
#define FNIC_TAG_MASK (BIT(24) - 1) /* mask for lookup */
|
||||
#define FNIC_NO_TAG -1
|
||||
|
||||
/*
|
||||
* Command flags to identify the type of command and for other future
|
||||
* use.
|
||||
*/
|
||||
#define FNIC_NO_FLAGS 0
|
||||
#define FNIC_IO_INITIALIZED BIT(0)
|
||||
#define FNIC_IO_ISSUED BIT(1)
|
||||
#define FNIC_IO_DONE BIT(2)
|
||||
#define FNIC_IO_REQ_NULL BIT(3)
|
||||
#define FNIC_IO_ABTS_PENDING BIT(4)
|
||||
#define FNIC_IO_ABORTED BIT(5)
|
||||
#define FNIC_IO_ABTS_ISSUED BIT(6)
|
||||
#define FNIC_IO_TERM_ISSUED BIT(7)
|
||||
#define FNIC_IO_INTERNAL_TERM_ISSUED BIT(8)
|
||||
#define FNIC_IO_ABT_TERM_DONE BIT(9)
|
||||
#define FNIC_IO_ABT_TERM_REQ_NULL BIT(10)
|
||||
#define FNIC_IO_ABT_TERM_TIMED_OUT BIT(11)
|
||||
#define FNIC_DEVICE_RESET BIT(12) /* Device reset request */
|
||||
#define FNIC_DEV_RST_ISSUED BIT(13)
|
||||
#define FNIC_DEV_RST_TIMED_OUT BIT(14)
|
||||
#define FNIC_DEV_RST_ABTS_ISSUED BIT(15)
|
||||
#define FNIC_DEV_RST_TERM_ISSUED BIT(16)
|
||||
#define FNIC_DEV_RST_DONE BIT(17)
|
||||
#define FNIC_DEV_RST_REQ_NULL BIT(18)
|
||||
#define FNIC_DEV_RST_ABTS_DONE BIT(19)
|
||||
#define FNIC_DEV_RST_TERM_DONE BIT(20)
|
||||
#define FNIC_DEV_RST_ABTS_PENDING BIT(21)
|
||||
|
||||
/*
|
||||
* Usage of the scsi_cmnd scratchpad.
|
||||
* These fields are locked by the hashed io_req_lock.
|
||||
@@ -64,6 +93,7 @@
|
||||
#define CMD_ABTS_STATUS(Cmnd) ((Cmnd)->SCp.Message)
|
||||
#define CMD_LR_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in)
|
||||
#define CMD_TAG(Cmnd) ((Cmnd)->SCp.sent_command)
|
||||
#define CMD_FLAGS(Cmnd) ((Cmnd)->SCp.Status)
|
||||
|
||||
#define FCPIO_INVALID_CODE 0x100 /* hdr_status value unused by firmware */
|
||||
|
||||
@@ -71,9 +101,28 @@
|
||||
#define FNIC_HOST_RESET_TIMEOUT 10000 /* mSec */
|
||||
#define FNIC_RMDEVICE_TIMEOUT 1000 /* mSec */
|
||||
#define FNIC_HOST_RESET_SETTLE_TIME 30 /* Sec */
|
||||
#define FNIC_ABT_TERM_DELAY_TIMEOUT 500 /* mSec */
|
||||
|
||||
#define FNIC_MAX_FCP_TARGET 256
|
||||
|
||||
/**
|
||||
* state_flags to identify host state along along with fnic's state
|
||||
**/
|
||||
#define __FNIC_FLAGS_FWRESET BIT(0) /* fwreset in progress */
|
||||
#define __FNIC_FLAGS_BLOCK_IO BIT(1) /* IOs are blocked */
|
||||
|
||||
#define FNIC_FLAGS_NONE (0)
|
||||
#define FNIC_FLAGS_FWRESET (__FNIC_FLAGS_FWRESET | \
|
||||
__FNIC_FLAGS_BLOCK_IO)
|
||||
|
||||
#define FNIC_FLAGS_IO_BLOCKED (__FNIC_FLAGS_BLOCK_IO)
|
||||
|
||||
#define fnic_set_state_flags(fnicp, st_flags) \
|
||||
__fnic_set_state_flags(fnicp, st_flags, 0)
|
||||
|
||||
#define fnic_clear_state_flags(fnicp, st_flags) \
|
||||
__fnic_set_state_flags(fnicp, st_flags, 1)
|
||||
|
||||
extern unsigned int fnic_log_level;
|
||||
|
||||
#define FNIC_MAIN_LOGGING 0x01
|
||||
@@ -170,6 +219,9 @@ struct fnic {
|
||||
|
||||
struct completion *remove_wait; /* device remove thread blocks */
|
||||
|
||||
atomic_t in_flight; /* io counter */
|
||||
u32 _reserved; /* fill hole */
|
||||
unsigned long state_flags; /* protected by host lock */
|
||||
enum fnic_state state;
|
||||
spinlock_t fnic_lock;
|
||||
|
||||
@@ -267,4 +319,12 @@ const char *fnic_state_to_str(unsigned int state);
|
||||
void fnic_log_q_error(struct fnic *fnic);
|
||||
void fnic_handle_link_event(struct fnic *fnic);
|
||||
|
||||
int fnic_is_abts_pending(struct fnic *, struct scsi_cmnd *);
|
||||
|
||||
static inline int
|
||||
fnic_chk_state_flags_locked(struct fnic *fnic, unsigned long st_flags)
|
||||
{
|
||||
return ((fnic->state_flags & st_flags) == st_flags);
|
||||
}
|
||||
void __fnic_set_state_flags(struct fnic *, unsigned long, unsigned long);
|
||||
#endif /* _FNIC_H_ */
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
* Copyright 2012 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include "fnic.h"
|
||||
|
||||
static struct dentry *fnic_trace_debugfs_root;
|
||||
static struct dentry *fnic_trace_debugfs_file;
|
||||
static struct dentry *fnic_trace_enable;
|
||||
|
||||
/*
|
||||
* fnic_trace_ctrl_open - Open the trace_enable file
|
||||
* @inode: The inode pointer.
|
||||
* @file: The file pointer to attach the trace enable/disable flag.
|
||||
*
|
||||
* Description:
|
||||
* This routine opens a debugsfs file trace_enable.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns zero if successful.
|
||||
*/
|
||||
static int fnic_trace_ctrl_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
filp->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_ctrl_read - Read a trace_enable debugfs file
|
||||
* @filp: The file pointer to read from.
|
||||
* @ubuf: The buffer to copy the data to.
|
||||
* @cnt: The number of bytes to read.
|
||||
* @ppos: The position in the file to start reading from.
|
||||
*
|
||||
* Description:
|
||||
* This routine reads value of variable fnic_tracing_enabled
|
||||
* and stores into local @buf. It will start reading file at @ppos and
|
||||
* copy up to @cnt of data to @ubuf from @buf.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns the amount of data that was read.
|
||||
*/
|
||||
static ssize_t fnic_trace_ctrl_read(struct file *filp,
|
||||
char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char buf[64];
|
||||
int len;
|
||||
len = sprintf(buf, "%u\n", fnic_tracing_enabled);
|
||||
|
||||
return simple_read_from_buffer(ubuf, cnt, ppos, buf, len);
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_ctrl_write - Write to trace_enable debugfs file
|
||||
* @filp: The file pointer to write from.
|
||||
* @ubuf: The buffer to copy the data from.
|
||||
* @cnt: The number of bytes to write.
|
||||
* @ppos: The position in the file to start writing to.
|
||||
*
|
||||
* Description:
|
||||
* This routine writes data from user buffer @ubuf to buffer @buf and
|
||||
* sets fnic_tracing_enabled value as per user input.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns the amount of data that was written.
|
||||
*/
|
||||
static ssize_t fnic_trace_ctrl_write(struct file *filp,
|
||||
const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
char buf[64];
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (cnt >= sizeof(buf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&buf, ubuf, cnt))
|
||||
return -EFAULT;
|
||||
|
||||
buf[cnt] = 0;
|
||||
|
||||
ret = kstrtoul(buf, 10, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
fnic_tracing_enabled = val;
|
||||
(*ppos)++;
|
||||
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_open - Open the fnic trace log
|
||||
* @inode: The inode pointer
|
||||
* @file: The file pointer to attach the log output
|
||||
*
|
||||
* Description:
|
||||
* This routine is the entry point for the debugfs open file operation.
|
||||
* It allocates the necessary buffer for the log, fills the buffer from
|
||||
* the in-memory log and then returns a pointer to that log in
|
||||
* the private_data field in @file.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns zero if successful. On error it will return
|
||||
* a negative error value.
|
||||
*/
|
||||
static int fnic_trace_debugfs_open(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
fnic_dbgfs_t *fnic_dbg_prt;
|
||||
fnic_dbg_prt = kzalloc(sizeof(fnic_dbgfs_t), GFP_KERNEL);
|
||||
if (!fnic_dbg_prt)
|
||||
return -ENOMEM;
|
||||
|
||||
fnic_dbg_prt->buffer = vmalloc((3*(trace_max_pages * PAGE_SIZE)));
|
||||
if (!fnic_dbg_prt->buffer) {
|
||||
kfree(fnic_dbg_prt);
|
||||
return -ENOMEM;
|
||||
}
|
||||
memset((void *)fnic_dbg_prt->buffer, 0,
|
||||
(3*(trace_max_pages * PAGE_SIZE)));
|
||||
fnic_dbg_prt->buffer_len = fnic_get_trace_data(fnic_dbg_prt);
|
||||
file->private_data = fnic_dbg_prt;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_lseek - Seek through a debugfs file
|
||||
* @file: The file pointer to seek through.
|
||||
* @offset: The offset to seek to or the amount to seek by.
|
||||
* @howto: Indicates how to seek.
|
||||
*
|
||||
* Description:
|
||||
* This routine is the entry point for the debugfs lseek file operation.
|
||||
* The @howto parameter indicates whether @offset is the offset to directly
|
||||
* seek to, or if it is a value to seek forward or reverse by. This function
|
||||
* figures out what the new offset of the debugfs file will be and assigns
|
||||
* that value to the f_pos field of @file.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns the new offset if successful and returns a negative
|
||||
* error if unable to process the seek.
|
||||
*/
|
||||
static loff_t fnic_trace_debugfs_lseek(struct file *file,
|
||||
loff_t offset,
|
||||
int howto)
|
||||
{
|
||||
fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
|
||||
loff_t pos = -1;
|
||||
|
||||
switch (howto) {
|
||||
case 0:
|
||||
pos = offset;
|
||||
break;
|
||||
case 1:
|
||||
pos = file->f_pos + offset;
|
||||
break;
|
||||
case 2:
|
||||
pos = fnic_dbg_prt->buffer_len - offset;
|
||||
}
|
||||
return (pos < 0 || pos > fnic_dbg_prt->buffer_len) ?
|
||||
-EINVAL : (file->f_pos = pos);
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_read - Read a debugfs file
|
||||
* @file: The file pointer to read from.
|
||||
* @ubuf: The buffer to copy the data to.
|
||||
* @nbytes: The number of bytes to read.
|
||||
* @pos: The position in the file to start reading from.
|
||||
*
|
||||
* Description:
|
||||
* This routine reads data from the buffer indicated in the private_data
|
||||
* field of @file. It will start reading at @pos and copy up to @nbytes of
|
||||
* data to @ubuf.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns the amount of data that was read (this could be
|
||||
* less than @nbytes if the end of the file was reached).
|
||||
*/
|
||||
static ssize_t fnic_trace_debugfs_read(struct file *file,
|
||||
char __user *ubuf,
|
||||
size_t nbytes,
|
||||
loff_t *pos)
|
||||
{
|
||||
fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
|
||||
int rc = 0;
|
||||
rc = simple_read_from_buffer(ubuf, nbytes, pos,
|
||||
fnic_dbg_prt->buffer,
|
||||
fnic_dbg_prt->buffer_len);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_release - Release the buffer used to store
|
||||
* debugfs file data
|
||||
* @inode: The inode pointer
|
||||
* @file: The file pointer that contains the buffer to release
|
||||
*
|
||||
* Description:
|
||||
* This routine frees the buffer that was allocated when the debugfs
|
||||
* file was opened.
|
||||
*
|
||||
* Returns:
|
||||
* This function returns zero.
|
||||
*/
|
||||
static int fnic_trace_debugfs_release(struct inode *inode,
|
||||
struct file *file)
|
||||
{
|
||||
fnic_dbgfs_t *fnic_dbg_prt = file->private_data;
|
||||
|
||||
vfree(fnic_dbg_prt->buffer);
|
||||
kfree(fnic_dbg_prt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations fnic_trace_ctrl_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fnic_trace_ctrl_open,
|
||||
.read = fnic_trace_ctrl_read,
|
||||
.write = fnic_trace_ctrl_write,
|
||||
};
|
||||
|
||||
static const struct file_operations fnic_trace_debugfs_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = fnic_trace_debugfs_open,
|
||||
.llseek = fnic_trace_debugfs_lseek,
|
||||
.read = fnic_trace_debugfs_read,
|
||||
.release = fnic_trace_debugfs_release,
|
||||
};
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_init - Initialize debugfs for fnic trace logging
|
||||
*
|
||||
* Description:
|
||||
* When Debugfs is configured this routine sets up the fnic debugfs
|
||||
* file system. If not already created, this routine will create the
|
||||
* fnic directory. It will create file trace to log fnic trace buffer
|
||||
* output into debugfs and it will also create file trace_enable to
|
||||
* control enable/disable of trace logging into trace buffer.
|
||||
*/
|
||||
int fnic_trace_debugfs_init(void)
|
||||
{
|
||||
int rc = -1;
|
||||
fnic_trace_debugfs_root = debugfs_create_dir("fnic", NULL);
|
||||
if (!fnic_trace_debugfs_root) {
|
||||
printk(KERN_DEBUG "Cannot create debugfs root\n");
|
||||
return rc;
|
||||
}
|
||||
fnic_trace_enable = debugfs_create_file("tracing_enable",
|
||||
S_IFREG|S_IRUGO|S_IWUSR,
|
||||
fnic_trace_debugfs_root,
|
||||
NULL, &fnic_trace_ctrl_fops);
|
||||
|
||||
if (!fnic_trace_enable) {
|
||||
printk(KERN_DEBUG "Cannot create trace_enable file"
|
||||
" under debugfs");
|
||||
return rc;
|
||||
}
|
||||
|
||||
fnic_trace_debugfs_file = debugfs_create_file("trace",
|
||||
S_IFREG|S_IRUGO|S_IWUSR,
|
||||
fnic_trace_debugfs_root,
|
||||
NULL,
|
||||
&fnic_trace_debugfs_fops);
|
||||
|
||||
if (!fnic_trace_debugfs_file) {
|
||||
printk(KERN_DEBUG "Cannot create trace file under debugfs");
|
||||
return rc;
|
||||
}
|
||||
rc = 0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_debugfs_terminate - Tear down debugfs infrastructure
|
||||
*
|
||||
* Description:
|
||||
* When Debugfs is configured this routine removes debugfs file system
|
||||
* elements that are specific to fnic trace logging.
|
||||
*/
|
||||
void fnic_trace_debugfs_terminate(void)
|
||||
{
|
||||
if (fnic_trace_debugfs_file) {
|
||||
debugfs_remove(fnic_trace_debugfs_file);
|
||||
fnic_trace_debugfs_file = NULL;
|
||||
}
|
||||
if (fnic_trace_enable) {
|
||||
debugfs_remove(fnic_trace_enable);
|
||||
fnic_trace_enable = NULL;
|
||||
}
|
||||
if (fnic_trace_debugfs_root) {
|
||||
debugfs_remove(fnic_trace_debugfs_root);
|
||||
fnic_trace_debugfs_root = NULL;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#include <scsi/fc/fc_fcp.h>
|
||||
|
||||
#define FNIC_DFLT_SG_DESC_CNT 32
|
||||
#define FNIC_MAX_SG_DESC_CNT 1024 /* Maximum descriptors per sgl */
|
||||
#define FNIC_MAX_SG_DESC_CNT 256 /* Maximum descriptors per sgl */
|
||||
#define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */
|
||||
|
||||
struct host_sg_desc {
|
||||
@@ -45,7 +45,8 @@ enum fnic_sgl_list_type {
|
||||
};
|
||||
|
||||
enum fnic_ioreq_state {
|
||||
FNIC_IOREQ_CMD_PENDING = 0,
|
||||
FNIC_IOREQ_NOT_INITED = 0,
|
||||
FNIC_IOREQ_CMD_PENDING,
|
||||
FNIC_IOREQ_ABTS_PENDING,
|
||||
FNIC_IOREQ_ABTS_COMPLETE,
|
||||
FNIC_IOREQ_CMD_COMPLETE,
|
||||
@@ -60,6 +61,7 @@ struct fnic_io_req {
|
||||
u8 sgl_type; /* device DMA descriptor list type */
|
||||
u8 io_completed:1; /* set to 1 when fw completes IO */
|
||||
u32 port_id; /* remote port DID */
|
||||
unsigned long start_time; /* in jiffies */
|
||||
struct completion *abts_done; /* completion for abts */
|
||||
struct completion *dr_done; /* completion for device reset */
|
||||
};
|
||||
|
||||
@@ -68,6 +68,10 @@ unsigned int fnic_log_level;
|
||||
module_param(fnic_log_level, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels");
|
||||
|
||||
unsigned int fnic_trace_max_pages = 16;
|
||||
module_param(fnic_trace_max_pages, uint, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(fnic_trace_max_pages, "Total allocated memory pages "
|
||||
"for fnic trace buffer");
|
||||
|
||||
static struct libfc_function_template fnic_transport_template = {
|
||||
.frame_send = fnic_send,
|
||||
@@ -624,6 +628,9 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
}
|
||||
fnic->state = FNIC_IN_FC_MODE;
|
||||
|
||||
atomic_set(&fnic->in_flight, 0);
|
||||
fnic->state_flags = FNIC_FLAGS_NONE;
|
||||
|
||||
/* Enable hardware stripping of vlan header on ingress */
|
||||
fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1);
|
||||
|
||||
@@ -858,6 +865,14 @@ static int __init fnic_init_module(void)
|
||||
|
||||
printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION);
|
||||
|
||||
/* Allocate memory for trace buffer */
|
||||
err = fnic_trace_buf_init();
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR PFX "Trace buffer initialization Failed "
|
||||
"Fnic Tracing utility is disabled\n");
|
||||
fnic_trace_free();
|
||||
}
|
||||
|
||||
/* Create a cache for allocation of default size sgls */
|
||||
len = sizeof(struct fnic_dflt_sgl_list);
|
||||
fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create
|
||||
@@ -928,6 +943,7 @@ err_create_fnic_ioreq_slab:
|
||||
err_create_fnic_sgl_slab_max:
|
||||
kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
|
||||
err_create_fnic_sgl_slab_dflt:
|
||||
fnic_trace_free();
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -939,6 +955,7 @@ static void __exit fnic_cleanup_module(void)
|
||||
kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]);
|
||||
kmem_cache_destroy(fnic_io_req_cache);
|
||||
fc_release_transport(fnic_fc_transport);
|
||||
fnic_trace_free();
|
||||
}
|
||||
|
||||
module_init(fnic_init_module);
|
||||
|
||||
+670
-51
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
* Copyright 2012 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mempool.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include "fnic_io.h"
|
||||
#include "fnic.h"
|
||||
|
||||
unsigned int trace_max_pages;
|
||||
static int fnic_max_trace_entries;
|
||||
|
||||
static unsigned long fnic_trace_buf_p;
|
||||
static DEFINE_SPINLOCK(fnic_trace_lock);
|
||||
|
||||
static fnic_trace_dbg_t fnic_trace_entries;
|
||||
int fnic_tracing_enabled = 1;
|
||||
|
||||
/*
|
||||
* fnic_trace_get_buf - Give buffer pointer to user to fill up trace information
|
||||
*
|
||||
* Description:
|
||||
* This routine gets next available trace buffer entry location @wr_idx
|
||||
* from allocated trace buffer pages and give that memory location
|
||||
* to user to store the trace information.
|
||||
*
|
||||
* Return Value:
|
||||
* This routine returns pointer to next available trace entry
|
||||
* @fnic_buf_head for user to fill trace information.
|
||||
*/
|
||||
fnic_trace_data_t *fnic_trace_get_buf(void)
|
||||
{
|
||||
unsigned long fnic_buf_head;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&fnic_trace_lock, flags);
|
||||
|
||||
/*
|
||||
* Get next available memory location for writing trace information
|
||||
* at @wr_idx and increment @wr_idx
|
||||
*/
|
||||
fnic_buf_head =
|
||||
fnic_trace_entries.page_offset[fnic_trace_entries.wr_idx];
|
||||
fnic_trace_entries.wr_idx++;
|
||||
|
||||
/*
|
||||
* Verify if trace buffer is full then change wd_idx to
|
||||
* start from zero
|
||||
*/
|
||||
if (fnic_trace_entries.wr_idx >= fnic_max_trace_entries)
|
||||
fnic_trace_entries.wr_idx = 0;
|
||||
|
||||
/*
|
||||
* Verify if write index @wr_idx and read index @rd_idx are same then
|
||||
* increment @rd_idx to move to next entry in trace buffer
|
||||
*/
|
||||
if (fnic_trace_entries.wr_idx == fnic_trace_entries.rd_idx) {
|
||||
fnic_trace_entries.rd_idx++;
|
||||
if (fnic_trace_entries.rd_idx >= fnic_max_trace_entries)
|
||||
fnic_trace_entries.rd_idx = 0;
|
||||
}
|
||||
spin_unlock_irqrestore(&fnic_trace_lock, flags);
|
||||
return (fnic_trace_data_t *)fnic_buf_head;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_get_trace_data - Copy trace buffer to a memory file
|
||||
* @fnic_dbgfs_t: pointer to debugfs trace buffer
|
||||
*
|
||||
* Description:
|
||||
* This routine gathers the fnic trace debugfs data from the fnic_trace_data_t
|
||||
* buffer and dumps it to fnic_dbgfs_t. It will start at the rd_idx entry in
|
||||
* the log and process the log until the end of the buffer. Then it will gather
|
||||
* from the beginning of the log and process until the current entry @wr_idx.
|
||||
*
|
||||
* Return Value:
|
||||
* This routine returns the amount of bytes that were dumped into fnic_dbgfs_t
|
||||
*/
|
||||
int fnic_get_trace_data(fnic_dbgfs_t *fnic_dbgfs_prt)
|
||||
{
|
||||
int rd_idx;
|
||||
int wr_idx;
|
||||
int len = 0;
|
||||
unsigned long flags;
|
||||
char str[KSYM_SYMBOL_LEN];
|
||||
struct timespec val;
|
||||
fnic_trace_data_t *tbp;
|
||||
|
||||
spin_lock_irqsave(&fnic_trace_lock, flags);
|
||||
rd_idx = fnic_trace_entries.rd_idx;
|
||||
wr_idx = fnic_trace_entries.wr_idx;
|
||||
if (wr_idx < rd_idx) {
|
||||
while (1) {
|
||||
/* Start from read index @rd_idx */
|
||||
tbp = (fnic_trace_data_t *)
|
||||
fnic_trace_entries.page_offset[rd_idx];
|
||||
if (!tbp) {
|
||||
spin_unlock_irqrestore(&fnic_trace_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
/* Convert function pointer to function name */
|
||||
if (sizeof(unsigned long) < 8) {
|
||||
sprint_symbol(str, tbp->fnaddr.low);
|
||||
jiffies_to_timespec(tbp->timestamp.low, &val);
|
||||
} else {
|
||||
sprint_symbol(str, tbp->fnaddr.val);
|
||||
jiffies_to_timespec(tbp->timestamp.val, &val);
|
||||
}
|
||||
/*
|
||||
* Dump trace buffer entry to memory file
|
||||
* and increment read index @rd_idx
|
||||
*/
|
||||
len += snprintf(fnic_dbgfs_prt->buffer + len,
|
||||
(trace_max_pages * PAGE_SIZE * 3) - len,
|
||||
"%16lu.%16lu %-50s %8x %8x %16llx %16llx "
|
||||
"%16llx %16llx %16llx\n", val.tv_sec,
|
||||
val.tv_nsec, str, tbp->host_no, tbp->tag,
|
||||
tbp->data[0], tbp->data[1], tbp->data[2],
|
||||
tbp->data[3], tbp->data[4]);
|
||||
rd_idx++;
|
||||
/*
|
||||
* If rd_idx is reached to maximum trace entries
|
||||
* then move rd_idx to zero
|
||||
*/
|
||||
if (rd_idx > (fnic_max_trace_entries-1))
|
||||
rd_idx = 0;
|
||||
/*
|
||||
* Continure dumpping trace buffer entries into
|
||||
* memory file till rd_idx reaches write index
|
||||
*/
|
||||
if (rd_idx == wr_idx)
|
||||
break;
|
||||
}
|
||||
} else if (wr_idx > rd_idx) {
|
||||
while (1) {
|
||||
/* Start from read index @rd_idx */
|
||||
tbp = (fnic_trace_data_t *)
|
||||
fnic_trace_entries.page_offset[rd_idx];
|
||||
if (!tbp) {
|
||||
spin_unlock_irqrestore(&fnic_trace_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
/* Convert function pointer to function name */
|
||||
if (sizeof(unsigned long) < 8) {
|
||||
sprint_symbol(str, tbp->fnaddr.low);
|
||||
jiffies_to_timespec(tbp->timestamp.low, &val);
|
||||
} else {
|
||||
sprint_symbol(str, tbp->fnaddr.val);
|
||||
jiffies_to_timespec(tbp->timestamp.val, &val);
|
||||
}
|
||||
/*
|
||||
* Dump trace buffer entry to memory file
|
||||
* and increment read index @rd_idx
|
||||
*/
|
||||
len += snprintf(fnic_dbgfs_prt->buffer + len,
|
||||
(trace_max_pages * PAGE_SIZE * 3) - len,
|
||||
"%16lu.%16lu %-50s %8x %8x %16llx %16llx "
|
||||
"%16llx %16llx %16llx\n", val.tv_sec,
|
||||
val.tv_nsec, str, tbp->host_no, tbp->tag,
|
||||
tbp->data[0], tbp->data[1], tbp->data[2],
|
||||
tbp->data[3], tbp->data[4]);
|
||||
rd_idx++;
|
||||
/*
|
||||
* Continue dumpping trace buffer entries into
|
||||
* memory file till rd_idx reaches write index
|
||||
*/
|
||||
if (rd_idx == wr_idx)
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&fnic_trace_lock, flags);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_buf_init - Initialize fnic trace buffer logging facility
|
||||
*
|
||||
* Description:
|
||||
* Initialize trace buffer data structure by allocating required memory and
|
||||
* setting page_offset information for every trace entry by adding trace entry
|
||||
* length to previous page_offset value.
|
||||
*/
|
||||
int fnic_trace_buf_init(void)
|
||||
{
|
||||
unsigned long fnic_buf_head;
|
||||
int i;
|
||||
int err = 0;
|
||||
|
||||
trace_max_pages = fnic_trace_max_pages;
|
||||
fnic_max_trace_entries = (trace_max_pages * PAGE_SIZE)/
|
||||
FNIC_ENTRY_SIZE_BYTES;
|
||||
|
||||
fnic_trace_buf_p = (unsigned long)vmalloc((trace_max_pages * PAGE_SIZE));
|
||||
if (!fnic_trace_buf_p) {
|
||||
printk(KERN_ERR PFX "Failed to allocate memory "
|
||||
"for fnic_trace_buf_p\n");
|
||||
err = -ENOMEM;
|
||||
goto err_fnic_trace_buf_init;
|
||||
}
|
||||
memset((void *)fnic_trace_buf_p, 0, (trace_max_pages * PAGE_SIZE));
|
||||
|
||||
fnic_trace_entries.page_offset = vmalloc(fnic_max_trace_entries *
|
||||
sizeof(unsigned long));
|
||||
if (!fnic_trace_entries.page_offset) {
|
||||
printk(KERN_ERR PFX "Failed to allocate memory for"
|
||||
" page_offset\n");
|
||||
if (fnic_trace_buf_p) {
|
||||
vfree((void *)fnic_trace_buf_p);
|
||||
fnic_trace_buf_p = 0;
|
||||
}
|
||||
err = -ENOMEM;
|
||||
goto err_fnic_trace_buf_init;
|
||||
}
|
||||
memset((void *)fnic_trace_entries.page_offset, 0,
|
||||
(fnic_max_trace_entries * sizeof(unsigned long)));
|
||||
fnic_trace_entries.wr_idx = fnic_trace_entries.rd_idx = 0;
|
||||
fnic_buf_head = fnic_trace_buf_p;
|
||||
|
||||
/*
|
||||
* Set page_offset field of fnic_trace_entries struct by
|
||||
* calculating memory location for every trace entry using
|
||||
* length of each trace entry
|
||||
*/
|
||||
for (i = 0; i < fnic_max_trace_entries; i++) {
|
||||
fnic_trace_entries.page_offset[i] = fnic_buf_head;
|
||||
fnic_buf_head += FNIC_ENTRY_SIZE_BYTES;
|
||||
}
|
||||
err = fnic_trace_debugfs_init();
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR PFX "Failed to initialize debugfs for tracing\n");
|
||||
goto err_fnic_trace_debugfs_init;
|
||||
}
|
||||
printk(KERN_INFO PFX "Successfully Initialized Trace Buffer\n");
|
||||
return err;
|
||||
err_fnic_trace_debugfs_init:
|
||||
fnic_trace_free();
|
||||
err_fnic_trace_buf_init:
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* fnic_trace_free - Free memory of fnic trace data structures.
|
||||
*/
|
||||
void fnic_trace_free(void)
|
||||
{
|
||||
fnic_tracing_enabled = 0;
|
||||
fnic_trace_debugfs_terminate();
|
||||
if (fnic_trace_entries.page_offset) {
|
||||
vfree((void *)fnic_trace_entries.page_offset);
|
||||
fnic_trace_entries.page_offset = NULL;
|
||||
}
|
||||
if (fnic_trace_buf_p) {
|
||||
vfree((void *)fnic_trace_buf_p);
|
||||
fnic_trace_buf_p = 0;
|
||||
}
|
||||
printk(KERN_INFO PFX "Successfully Freed Trace Buffer\n");
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2012 Cisco Systems, Inc. All rights reserved.
|
||||
*
|
||||
* This program is free software; you may redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __FNIC_TRACE_H__
|
||||
#define __FNIC_TRACE_H__
|
||||
|
||||
#define FNIC_ENTRY_SIZE_BYTES 64
|
||||
|
||||
extern ssize_t simple_read_from_buffer(void __user *to,
|
||||
size_t count,
|
||||
loff_t *ppos,
|
||||
const void *from,
|
||||
size_t available);
|
||||
|
||||
extern unsigned int fnic_trace_max_pages;
|
||||
extern int fnic_tracing_enabled;
|
||||
extern unsigned int trace_max_pages;
|
||||
|
||||
typedef struct fnic_trace_dbg {
|
||||
int wr_idx;
|
||||
int rd_idx;
|
||||
unsigned long *page_offset;
|
||||
} fnic_trace_dbg_t;
|
||||
|
||||
typedef struct fnic_dbgfs {
|
||||
int buffer_len;
|
||||
char *buffer;
|
||||
} fnic_dbgfs_t;
|
||||
|
||||
struct fnic_trace_data {
|
||||
union {
|
||||
struct {
|
||||
u32 low;
|
||||
u32 high;
|
||||
};
|
||||
u64 val;
|
||||
} timestamp, fnaddr;
|
||||
u32 host_no;
|
||||
u32 tag;
|
||||
u64 data[5];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
typedef struct fnic_trace_data fnic_trace_data_t;
|
||||
|
||||
#define FNIC_TRACE_ENTRY_SIZE \
|
||||
(FNIC_ENTRY_SIZE_BYTES - sizeof(fnic_trace_data_t))
|
||||
|
||||
#define FNIC_TRACE(_fn, _hn, _t, _a, _b, _c, _d, _e) \
|
||||
if (unlikely(fnic_tracing_enabled)) { \
|
||||
fnic_trace_data_t *trace_buf = fnic_trace_get_buf(); \
|
||||
if (trace_buf) { \
|
||||
if (sizeof(unsigned long) < 8) { \
|
||||
trace_buf->timestamp.low = jiffies; \
|
||||
trace_buf->fnaddr.low = (u32)(unsigned long)_fn; \
|
||||
} else { \
|
||||
trace_buf->timestamp.val = jiffies; \
|
||||
trace_buf->fnaddr.val = (u64)(unsigned long)_fn; \
|
||||
} \
|
||||
trace_buf->host_no = _hn; \
|
||||
trace_buf->tag = _t; \
|
||||
trace_buf->data[0] = (u64)(unsigned long)_a; \
|
||||
trace_buf->data[1] = (u64)(unsigned long)_b; \
|
||||
trace_buf->data[2] = (u64)(unsigned long)_c; \
|
||||
trace_buf->data[3] = (u64)(unsigned long)_d; \
|
||||
trace_buf->data[4] = (u64)(unsigned long)_e; \
|
||||
} \
|
||||
}
|
||||
|
||||
fnic_trace_data_t *fnic_trace_get_buf(void);
|
||||
int fnic_get_trace_data(fnic_dbgfs_t *);
|
||||
int fnic_trace_buf_init(void);
|
||||
void fnic_trace_free(void);
|
||||
int fnic_trace_debugfs_init(void);
|
||||
void fnic_trace_debugfs_terminate(void);
|
||||
|
||||
#endif
|
||||
+84
-33
@@ -165,7 +165,7 @@ static void cmd_free(struct ctlr_info *h, struct CommandList *c);
|
||||
static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
|
||||
static struct CommandList *cmd_alloc(struct ctlr_info *h);
|
||||
static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
|
||||
static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
|
||||
int cmd_type);
|
||||
|
||||
@@ -1131,7 +1131,7 @@ clean:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void hpsa_map_sg_chain_block(struct ctlr_info *h,
|
||||
static int hpsa_map_sg_chain_block(struct ctlr_info *h,
|
||||
struct CommandList *c)
|
||||
{
|
||||
struct SGDescriptor *chain_sg, *chain_block;
|
||||
@@ -1144,8 +1144,15 @@ static void hpsa_map_sg_chain_block(struct ctlr_info *h,
|
||||
(c->Header.SGTotal - h->max_cmd_sg_entries);
|
||||
temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len,
|
||||
PCI_DMA_TODEVICE);
|
||||
if (dma_mapping_error(&h->pdev->dev, temp64)) {
|
||||
/* prevent subsequent unmapping */
|
||||
chain_sg->Addr.lower = 0;
|
||||
chain_sg->Addr.upper = 0;
|
||||
return -1;
|
||||
}
|
||||
chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL);
|
||||
chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
|
||||
@@ -1390,7 +1397,7 @@ static void hpsa_pci_unmap(struct pci_dev *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
static void hpsa_map_one(struct pci_dev *pdev,
|
||||
static int hpsa_map_one(struct pci_dev *pdev,
|
||||
struct CommandList *cp,
|
||||
unsigned char *buf,
|
||||
size_t buflen,
|
||||
@@ -1401,10 +1408,16 @@ static void hpsa_map_one(struct pci_dev *pdev,
|
||||
if (buflen == 0 || data_direction == PCI_DMA_NONE) {
|
||||
cp->Header.SGList = 0;
|
||||
cp->Header.SGTotal = 0;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
addr64 = (u64) pci_map_single(pdev, buf, buflen, data_direction);
|
||||
if (dma_mapping_error(&pdev->dev, addr64)) {
|
||||
/* Prevent subsequent unmap of something never mapped */
|
||||
cp->Header.SGList = 0;
|
||||
cp->Header.SGTotal = 0;
|
||||
return -1;
|
||||
}
|
||||
cp->SG[0].Addr.lower =
|
||||
(u32) (addr64 & (u64) 0x00000000FFFFFFFF);
|
||||
cp->SG[0].Addr.upper =
|
||||
@@ -1412,6 +1425,7 @@ static void hpsa_map_one(struct pci_dev *pdev,
|
||||
cp->SG[0].Len = buflen;
|
||||
cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
|
||||
cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void hpsa_scsi_do_simple_cmd_core(struct ctlr_info *h,
|
||||
@@ -1540,13 +1554,18 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize, page, scsi3addr, TYPE_CMD);
|
||||
if (fill_cmd(c, HPSA_INQUIRY, h, buf, bufsize,
|
||||
page, scsi3addr, TYPE_CMD)) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
|
||||
ei = c->err_info;
|
||||
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
|
||||
hpsa_scsi_interpret_error(c);
|
||||
rc = -1;
|
||||
}
|
||||
out:
|
||||
cmd_special_free(h, c);
|
||||
return rc;
|
||||
}
|
||||
@@ -1564,7 +1583,9 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0, scsi3addr, TYPE_MSG);
|
||||
/* fill_cmd can't fail here, no data buffer to map. */
|
||||
(void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h,
|
||||
NULL, 0, 0, scsi3addr, TYPE_MSG);
|
||||
hpsa_scsi_do_simple_cmd_core(h, c);
|
||||
/* no unmap needed here because no data xfer. */
|
||||
|
||||
@@ -1631,8 +1652,11 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
|
||||
}
|
||||
/* address the controller */
|
||||
memset(scsi3addr, 0, sizeof(scsi3addr));
|
||||
fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
|
||||
buf, bufsize, 0, scsi3addr, TYPE_CMD);
|
||||
if (fill_cmd(c, logical ? HPSA_REPORT_LOG : HPSA_REPORT_PHYS, h,
|
||||
buf, bufsize, 0, scsi3addr, TYPE_CMD)) {
|
||||
rc = -1;
|
||||
goto out;
|
||||
}
|
||||
if (extended_response)
|
||||
c->Request.CDB[1] = extended_response;
|
||||
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
|
||||
@@ -1642,6 +1666,7 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
|
||||
hpsa_scsi_interpret_error(c);
|
||||
rc = -1;
|
||||
}
|
||||
out:
|
||||
cmd_special_free(h, c);
|
||||
return rc;
|
||||
}
|
||||
@@ -2105,7 +2130,10 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
|
||||
if (chained) {
|
||||
cp->Header.SGList = h->max_cmd_sg_entries;
|
||||
cp->Header.SGTotal = (u16) (use_sg + 1);
|
||||
hpsa_map_sg_chain_block(h, cp);
|
||||
if (hpsa_map_sg_chain_block(h, cp)) {
|
||||
scsi_dma_unmap(cmd);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2353,8 +2381,9 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
|
||||
if (waittime < HPSA_MAX_WAIT_INTERVAL_SECS)
|
||||
waittime = waittime * 2;
|
||||
|
||||
/* Send the Test Unit Ready */
|
||||
fill_cmd(c, TEST_UNIT_READY, h, NULL, 0, 0, lunaddr, TYPE_CMD);
|
||||
/* Send the Test Unit Ready, fill_cmd can't fail, no mapping */
|
||||
(void) fill_cmd(c, TEST_UNIT_READY, h,
|
||||
NULL, 0, 0, lunaddr, TYPE_CMD);
|
||||
hpsa_scsi_do_simple_cmd_core(h, c);
|
||||
/* no unmap needed here because no data xfer. */
|
||||
|
||||
@@ -2439,7 +2468,9 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
fill_cmd(c, HPSA_ABORT_MSG, h, abort, 0, 0, scsi3addr, TYPE_MSG);
|
||||
/* fill_cmd can't fail here, no buffer to map */
|
||||
(void) fill_cmd(c, HPSA_ABORT_MSG, h, abort,
|
||||
0, 0, scsi3addr, TYPE_MSG);
|
||||
if (swizzle)
|
||||
swizzle_abort_tag(&c->Request.CDB[4]);
|
||||
hpsa_scsi_do_simple_cmd_core(h, c);
|
||||
@@ -2928,6 +2959,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
struct CommandList *c;
|
||||
char *buff = NULL;
|
||||
union u64bit temp64;
|
||||
int rc = 0;
|
||||
|
||||
if (!argp)
|
||||
return -EINVAL;
|
||||
@@ -2947,8 +2979,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
/* Copy the data into the buffer we created */
|
||||
if (copy_from_user(buff, iocommand.buf,
|
||||
iocommand.buf_size)) {
|
||||
kfree(buff);
|
||||
return -EFAULT;
|
||||
rc = -EFAULT;
|
||||
goto out_kfree;
|
||||
}
|
||||
} else {
|
||||
memset(buff, 0, iocommand.buf_size);
|
||||
@@ -2956,8 +2988,8 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
}
|
||||
c = cmd_special_alloc(h);
|
||||
if (c == NULL) {
|
||||
kfree(buff);
|
||||
return -ENOMEM;
|
||||
rc = -ENOMEM;
|
||||
goto out_kfree;
|
||||
}
|
||||
/* Fill in the command type */
|
||||
c->cmd_type = CMD_IOCTL_PEND;
|
||||
@@ -2982,6 +3014,13 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
if (iocommand.buf_size > 0) {
|
||||
temp64.val = pci_map_single(h->pdev, buff,
|
||||
iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(&h->pdev->dev, temp64.val)) {
|
||||
c->SG[0].Addr.lower = 0;
|
||||
c->SG[0].Addr.upper = 0;
|
||||
c->SG[0].Len = 0;
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
c->SG[0].Addr.lower = temp64.val32.lower;
|
||||
c->SG[0].Addr.upper = temp64.val32.upper;
|
||||
c->SG[0].Len = iocommand.buf_size;
|
||||
@@ -2996,22 +3035,22 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
memcpy(&iocommand.error_info, c->err_info,
|
||||
sizeof(iocommand.error_info));
|
||||
if (copy_to_user(argp, &iocommand, sizeof(iocommand))) {
|
||||
kfree(buff);
|
||||
cmd_special_free(h, c);
|
||||
return -EFAULT;
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (iocommand.Request.Type.Direction == XFER_READ &&
|
||||
iocommand.buf_size > 0) {
|
||||
/* Copy the data out of the buffer we created */
|
||||
if (copy_to_user(iocommand.buf, buff, iocommand.buf_size)) {
|
||||
kfree(buff);
|
||||
cmd_special_free(h, c);
|
||||
return -EFAULT;
|
||||
rc = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
kfree(buff);
|
||||
out:
|
||||
cmd_special_free(h, c);
|
||||
return 0;
|
||||
out_kfree:
|
||||
kfree(buff);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
@@ -3103,6 +3142,15 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
|
||||
for (i = 0; i < sg_used; i++) {
|
||||
temp64.val = pci_map_single(h->pdev, buff[i],
|
||||
buff_size[i], PCI_DMA_BIDIRECTIONAL);
|
||||
if (dma_mapping_error(&h->pdev->dev, temp64.val)) {
|
||||
c->SG[i].Addr.lower = 0;
|
||||
c->SG[i].Addr.upper = 0;
|
||||
c->SG[i].Len = 0;
|
||||
hpsa_pci_unmap(h->pdev, c, i,
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
status = -ENOMEM;
|
||||
goto cleanup1;
|
||||
}
|
||||
c->SG[i].Addr.lower = temp64.val32.lower;
|
||||
c->SG[i].Addr.upper = temp64.val32.upper;
|
||||
c->SG[i].Len = buff_size[i];
|
||||
@@ -3190,7 +3238,8 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
|
||||
c = cmd_alloc(h);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
|
||||
/* fill_cmd can't fail here, no data buffer to map */
|
||||
(void) fill_cmd(c, HPSA_DEVICE_RESET_MSG, h, NULL, 0, 0,
|
||||
RAID_CTLR_LUNID, TYPE_MSG);
|
||||
c->Request.CDB[1] = reset_type; /* fill_cmd defaults to target reset */
|
||||
c->waiting = NULL;
|
||||
@@ -3202,7 +3251,7 @@ static int hpsa_send_host_reset(struct ctlr_info *h, unsigned char *scsi3addr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
void *buff, size_t size, u8 page_code, unsigned char *scsi3addr,
|
||||
int cmd_type)
|
||||
{
|
||||
@@ -3271,7 +3320,7 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
default:
|
||||
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
|
||||
BUG();
|
||||
return;
|
||||
return -1;
|
||||
}
|
||||
} else if (cmd_type == TYPE_MSG) {
|
||||
switch (cmd) {
|
||||
@@ -3343,10 +3392,9 @@ static void fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
|
||||
default:
|
||||
pci_dir = PCI_DMA_BIDIRECTIONAL;
|
||||
}
|
||||
|
||||
hpsa_map_one(h->pdev, c, buff, size, pci_dir);
|
||||
|
||||
return;
|
||||
if (hpsa_map_one(h->pdev, c, buff, size, pci_dir))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4882,10 +4930,13 @@ static void hpsa_flush_cache(struct ctlr_info *h)
|
||||
dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
|
||||
goto out_of_memory;
|
||||
}
|
||||
fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
|
||||
RAID_CTLR_LUNID, TYPE_CMD);
|
||||
if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
|
||||
RAID_CTLR_LUNID, TYPE_CMD)) {
|
||||
goto out;
|
||||
}
|
||||
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_TODEVICE);
|
||||
if (c->err_info->CommandStatus != 0)
|
||||
out:
|
||||
dev_warn(&h->pdev->dev,
|
||||
"error flushing cache on controller\n");
|
||||
cmd_special_free(h, c);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user