unsignedint libfcoe_debug_logging;
module_param_named(debug_logging, libfcoe_debug_logging, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
module_param_call(create, fcoe_transport_create, NULL,
(void *)FIP_MODE_FABRIC, S_IWUSR);
__MODULE_PARM_TYPE(create, "string");
MODULE_PARM_DESC(create, " Creates fcoe instance on an ethernet interface");
module_param_call(create_vn2vn, fcoe_transport_create, NULL,
(void *)FIP_MODE_VN2VN, S_IWUSR);
__MODULE_PARM_TYPE(create_vn2vn, "string");
MODULE_PARM_DESC(create_vn2vn, " Creates a VN_node to VN_node FCoE instance " "on an Ethernet interface");
module_param_call(destroy, fcoe_transport_destroy, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(destroy, "string");
MODULE_PARM_DESC(destroy, " Destroys fcoe instance on an ethernet interface");
module_param_call(enable, fcoe_transport_enable, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(enable, "string");
MODULE_PARM_DESC(enable, " Enables fcoe on an ethernet interface.");
module_param_call(disable, fcoe_transport_disable, NULL, NULL, S_IWUSR);
__MODULE_PARM_TYPE(disable, "string");
MODULE_PARM_DESC(disable, " Disables fcoe on an ethernet interface.");
/* notification function for packets from net device */ staticstruct notifier_block libfcoe_notifier = {
.notifier_call = libfcoe_device_notification,
};
staticinline u32 eth2fc_speed(u32 eth_port_speed)
{ int i;
for (i = 0; i < ARRAY_SIZE(fcoe_port_speed_mapping); i++) { if (fcoe_port_speed_mapping[i].eth_port_speed == eth_port_speed) return fcoe_port_speed_mapping[i].fc_port_speed;
}
return FC_PORTSPEED_UNKNOWN;
}
/** * 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_link_ksettings ecmd;
/** * __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)
{ unsignedint cpu;
u32 lfc, vlfc, mdac; struct fc_stats *stats; struct fcoe_fc_els_lesb *lesb; struct rtnl_link_stats64 temp;
/** * 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_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 fc_els_lesb *fc_lesb;
/** * fcoe_validate_vport_create() - Validate a vport before creating it * @vport: NPIV port to be created * * This routine is meant to add validation for a vport before creating it * via fcoe_vport_create(). * Current validations are: * - WWPN supplied is unique for given lport
*/ int fcoe_validate_vport_create(struct fc_vport *vport)
{ struct Scsi_Host *shost = vport_to_shost(vport); struct fc_lport *n_port = shost_priv(shost); struct fc_lport *vn_port; int rc = 0; char buf[32];
mutex_lock(&n_port->lp_mutex);
fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf)); /* Check if the wwpn is not same as that of the lport */ if (!memcmp(&n_port->wwpn, &vport->port_name, sizeof(u64))) {
LIBFCOE_TRANSPORT_DBG("vport WWPN 0x%s is same as that of the " "base port WWPN\n", buf);
rc = -EINVAL; goto out;
}
/* Check if there is any existing vport with same wwpn */
list_for_each_entry(vn_port, &n_port->vports, list) { if (!memcmp(&vn_port->wwpn, &vport->port_name, sizeof(u64))) {
LIBFCOE_TRANSPORT_DBG("vport with given WWPN 0x%s " "already exists\n", buf);
rc = -EINVAL; break;
}
}
out:
mutex_unlock(&n_port->lp_mutex); return rc;
}
EXPORT_SYMBOL_GPL(fcoe_validate_vport_create);
/** * fcoe_get_wwn() - Get the world wide name from LLD if it supports it * @netdev: the associated net device * @wwn: the output WWN * @type: the type of WWN (WWPN or WWNN) * * Returns: 0 for success
*/ int fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type)
{ conststruct net_device_ops *ops = netdev->netdev_ops;
if (ops->ndo_fcoe_get_wwn) return ops->ndo_fcoe_get_wwn(netdev, wwn, type); return -EINVAL;
}
EXPORT_SYMBOL_GPL(fcoe_get_wwn);
/** * fcoe_fc_crc() - Calculates the CRC for a given frame * @fp: The frame to be checksumed * * This uses crc32() routine to calculate the CRC for a frame * * Return: The 32 bit CRC value
*/
u32 fcoe_fc_crc(struct fc_frame *fp)
{ struct sk_buff *skb = fp_skb(fp);
skb_frag_t *frag; unsignedchar *data; unsignedlong off, len, clen;
u32 crc; unsigned i;
crc = crc32(~0, skb->data, skb_headlen(skb));
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
frag = &skb_shinfo(skb)->frags[i];
off = skb_frag_off(frag);
len = skb_frag_size(frag); while (len > 0) {
clen = min(len, PAGE_SIZE - (off & ~PAGE_MASK));
data = kmap_atomic(
skb_frag_page(frag) + (off >> PAGE_SHIFT));
crc = crc32(crc, data + (off & ~PAGE_MASK), clen);
kunmap_atomic(data);
off += clen;
len -= clen;
}
} return crc;
}
EXPORT_SYMBOL_GPL(fcoe_fc_crc);
/** * fcoe_start_io() - Start FCoE I/O * @skb: The packet to be transmitted * * This routine is called from the net device to start transmitting * FCoE packets. * * Returns: 0 for success
*/ int fcoe_start_io(struct sk_buff *skb)
{ struct sk_buff *nskb; int rc;
/** * fcoe_clean_pending_queue() - Dequeue a skb and free it * @lport: The local port to dequeue a skb on
*/ void fcoe_clean_pending_queue(struct fc_lport *lport)
{ struct fcoe_port *port = lport_priv(lport); struct sk_buff *skb;
/** * fcoe_check_wait_queue() - Attempt to clear the transmit backlog * @lport: The local port whose backlog is to be cleared * @skb: The received FIP packet * * This empties the wait_queue, dequeues the head of the wait_queue queue * and calls fcoe_start_io() for each packet. If all skb have been * transmitted it returns the qlen. If an error occurs it restores * wait_queue (to try again later) and returns -1. * * The wait_queue is used when the skb transmit fails. The failed skb * will go in the wait_queue which will be emptied by the timer function or * by the next skb transmit.
*/ void fcoe_check_wait_queue(struct fc_lport *lport, struct sk_buff *skb)
{ struct fcoe_port *port = lport_priv(lport); int rc;
spin_lock_bh(&port->fcoe_pending_queue.lock);
if (skb)
__skb_queue_tail(&port->fcoe_pending_queue, skb);
if (port->fcoe_pending_queue_active) goto out;
port->fcoe_pending_queue_active = 1;
while (port->fcoe_pending_queue.qlen) { /* keep qlen > 0 until fcoe_start_io succeeds */
port->fcoe_pending_queue.qlen++;
skb = __skb_dequeue(&port->fcoe_pending_queue);
/** * fcoe_get_paged_crc_eof() - Allocate a page to be used for the trailer CRC * @skb: The packet to be transmitted * @tlen: The total length of the trailer * @fps: The fcoe context * * This routine allocates a page for frame trailers. The page is re-used if * there is enough room left on it for the current trailer. If there isn't * enough buffer left a new page is allocated for the trailer. Reference to * the page from this function as well as the skbs using the page fragments * ensure that the page is freed at the appropriate time. * * Returns: 0 for success
*/ int fcoe_get_paged_crc_eof(struct sk_buff *skb, int tlen, struct fcoe_percpu_s *fps)
{ struct page *page;
page = fps->crc_eof_page; if (!page) {
page = alloc_page(GFP_ATOMIC); if (!page) return -ENOMEM;
/** * fcoe_transport_lookup - find an fcoe transport that matches a netdev * @netdev: The netdev to look for from all attached transports * * Returns : ptr to the fcoe transport that supports this netdev or NULL * if not found. * * The ft_mutex should be held when this is called
*/ staticstruct fcoe_transport *fcoe_transport_lookup(struct net_device *netdev)
{ struct fcoe_transport *ft = NULL;
/** * fcoe_transport_attach - Attaches an FCoE transport * @ft: The fcoe transport to be attached * * Returns : 0 for success
*/ int fcoe_transport_attach(struct fcoe_transport *ft)
{ int rc = 0;
/* Add default transport to the tail */ if (strcmp(ft->name, FCOE_TRANSPORT_DEFAULT))
list_add(&ft->list, &fcoe_transports); else
list_add_tail(&ft->list, &fcoe_transports);
ft->attached = true;
LIBFCOE_TRANSPORT_DBG("attaching transport %s\n", ft->name);
/** * fcoe_transport_detach - Detaches an FCoE transport * @ft: The fcoe transport to be attached * * Returns : 0 for success
*/ int fcoe_transport_detach(struct fcoe_transport *ft)
{ int rc = 0; struct fcoe_netdev_mapping *nm = NULL, *tmp;
/* remove netdev mapping for this transport as it is going away */
mutex_lock(&fn_mutex);
list_for_each_entry_safe(nm, tmp, &fcoe_netdevs, list) { if (nm->ft == ft) {
LIBFCOE_TRANSPORT_DBG("transport %s going away, " "remove its netdev mapping for %s\n",
ft->name, nm->netdev->name);
list_del(&nm->list);
kfree(nm);
}
}
mutex_unlock(&fn_mutex);
list_del(&ft->list);
ft->attached = false;
LIBFCOE_TRANSPORT_DBG("detaching transport %s\n", ft->name);
out_attach:
mutex_unlock(&ft_mutex); return rc;
}
EXPORT_SYMBOL(fcoe_transport_detach);
staticint fcoe_transport_show(char *buffer, conststruct kernel_param *kp)
{ int i, j; struct fcoe_transport *ft = NULL;
i = j = sprintf(buffer, "Attached FCoE transports:");
mutex_lock(&ft_mutex);
list_for_each_entry(ft, &fcoe_transports, list) { if (i >= PAGE_SIZE - IFNAMSIZ) break;
i += snprintf(&buffer[i], IFNAMSIZ, "%s ", ft->name);
}
mutex_unlock(&ft_mutex); if (i == j)
i += snprintf(&buffer[i], IFNAMSIZ, "none"); return i;
}
/** * fcoe_netdev_map_lookup - find the fcoe transport that matches the netdev on which * it was created * @netdev: The net device that the FCoE interface is on * * Returns : ptr to the fcoe transport that supports this netdev or NULL * if not found. * * The ft_mutex should be held when this is called
*/ staticstruct fcoe_transport *fcoe_netdev_map_lookup(struct net_device *netdev)
{ struct fcoe_transport *ft = NULL; struct fcoe_netdev_mapping *nm;
mutex_lock(&fn_mutex);
list_for_each_entry(nm, &fcoe_netdevs, list) { if (netdev == nm->netdev) {
ft = nm->ft;
mutex_unlock(&fn_mutex); return ft;
}
}
mutex_unlock(&fn_mutex); return NULL;
}
/** * fcoe_if_to_netdev() - Parse a name buffer to get a net device * @buffer: The name of the net device * * Returns: NULL or a ptr to net_device
*/ staticstruct net_device *fcoe_if_to_netdev(constchar *buffer)
{ char *cp; char ifname[IFNAMSIZ + 2];
/** * libfcoe_device_notification() - Handler for net device events * @notifier: The context of the notification * @event: The type of event * @ptr: The net device that the event was on * * This function is called by the Ethernet driver in case of link change event. * * Returns: 0 for success
*/ staticint libfcoe_device_notification(struct notifier_block *notifier,
ulong event, void *ptr)
{ struct net_device *netdev = netdev_notifier_info_to_dev(ptr);
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 succeeded to create fcoe on %s.\n",
ft->name, netdev->name);
/** * fcoe_transport_create() - Create a fcoe interface * @buffer: The name of the Ethernet interface to create on * @kp: The associated kernel param * * Called from sysfs. This holds the ft_mutex while calling the * registered fcoe transport's create function. * * Returns: 0 for success
*/ staticint fcoe_transport_create(constchar *buffer, conststruct kernel_param *kp)
{ int rc = -ENODEV; struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL; enum fip_mode fip_mode = (enum fip_mode)(uintptr_t)kp->arg;
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); goto out_putdev;
}
rc = fcoe_add_netdev_mapping(netdev, ft); if (rc) {
LIBFCOE_TRANSPORT_DBG("failed to add new netdev mapping " "for FCoE transport %s for %s.\n",
ft->name, netdev->name); goto out_putdev;
}
/* pass to transport create */
rc = ft->create ? ft->create(netdev, fip_mode) : -ENODEV; if (rc)
fcoe_del_netdev_mapping(netdev);
LIBFCOE_TRANSPORT_DBG("transport %s %s to create fcoe on %s.\n",
ft->name, (rc) ? "failed" : "succeeded",
netdev->name);
/** * fcoe_transport_destroy() - Destroy a FCoE interface * @buffer: The name of the Ethernet interface to be destroyed * @kp: The associated kernel parameter * * Called from sysfs. This holds the ft_mutex while calling the * registered fcoe transport's destroy function. * * Returns: 0 for success
*/ staticint fcoe_transport_destroy(constchar *buffer, conststruct kernel_param *kp)
{ int rc = -ENODEV; struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL;
/** * fcoe_transport_disable() - Disables a FCoE interface * @buffer: The name of the Ethernet interface to be disabled * @kp: The associated kernel parameter * * Called from sysfs. * * Returns: 0 for success
*/ staticint fcoe_transport_disable(constchar *buffer, conststruct kernel_param *kp)
{ int rc = -ENODEV; struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL;
mutex_lock(&ft_mutex);
netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev;
ft = fcoe_netdev_map_lookup(netdev); if (!ft) goto out_putdev;
/** * fcoe_transport_enable() - Enables a FCoE interface * @buffer: The name of the Ethernet interface to be enabled * @kp: The associated kernel parameter * * Called from sysfs. * * Returns: 0 for success
*/ staticint fcoe_transport_enable(constchar *buffer, conststruct kernel_param *kp)
{ int rc = -ENODEV; struct net_device *netdev = NULL; struct fcoe_transport *ft = NULL;
mutex_lock(&ft_mutex);
netdev = fcoe_if_to_netdev(buffer); if (!netdev) goto out_nodev;
ft = fcoe_netdev_map_lookup(netdev); if (!ft) goto out_putdev;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.