/* * 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"
/* * fcoe_fcf_dev_loss_tmo: the default number of seconds that fcoe sysfs * should insulate the loss of a fcf.
*/ staticunsignedint fcoe_fcf_dev_loss_tmo = 1800; /* seconds */
module_param_named(fcf_dev_loss_tmo, fcoe_fcf_dev_loss_tmo,
uint, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(fcf_dev_loss_tmo, "Maximum number of seconds that libfcoe should" " insulate the loss of a fcf. Once this value is" " exceeded, the fcf is removed.");
/* * These are used by the fcoe_*_show_function routines, they * are intentionally placed in the .c file as they're not intended * for use throughout the code.
*/ #define fcoe_ctlr_id(x) \
((x)->id) #define fcoe_ctlr_work_q(x) \
((x)->work_q) #define fcoe_ctlr_devloss_work_q(x) \
((x)->devloss_work_q) #define fcoe_ctlr_mode(x) \
((x)->mode) #define fcoe_ctlr_fcf_dev_loss_tmo(x) \
((x)->fcf_dev_loss_tmo) #define fcoe_ctlr_link_fail(x) \
((x)->lesb.lesb_link_fail) #define fcoe_ctlr_vlink_fail(x) \
((x)->lesb.lesb_vlink_fail) #define fcoe_ctlr_miss_fka(x) \
((x)->lesb.lesb_miss_fka) #define fcoe_ctlr_symb_err(x) \
((x)->lesb.lesb_symb_err) #define fcoe_ctlr_err_block(x) \
((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) \
((x)->fabric_name) #define fcoe_fcf_switch_name(x) \
((x)->switch_name) #define fcoe_fcf_fc_map(x) \
((x)->fc_map) #define fcoe_fcf_vfid(x) \
((x)->vfid) #define fcoe_fcf_mac(x) \
((x)->mac) #define fcoe_fcf_priority(x) \
((x)->priority) #define fcoe_fcf_fka_period(x) \
((x)->fka_period) #define fcoe_fcf_dev_loss_tmo(x) \
((x)->dev_loss_tmo) #define fcoe_fcf_selected(x) \
((x)->selected) #define fcoe_fcf_vlan_id(x) \
((x)->vlan_id)
if (count > FCOE_MAX_MODENAME_LEN) return -EINVAL;
switch (ctlr->enabled) { case FCOE_CTLR_ENABLED:
LIBFCOE_SYSFS_DBG(ctlr, "Cannot change mode when enabled.\n"); return -EBUSY; case FCOE_CTLR_DISABLED: if (!ctlr->f->set_fcoe_ctlr_mode) {
LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported by LLD.\n"); return -ENOTSUPP;
}
res = sysfs_match_string(fip_conn_type_names, buf); if (res < 0 || res == FIP_CONN_TYPE_UNKNOWN) {
LIBFCOE_SYSFS_DBG(ctlr, "Unknown mode %s provided.\n",
buf); return -EINVAL;
}
ctlr->mode = res;
ctlr->f->set_fcoe_ctlr_mode(ctlr);
LIBFCOE_SYSFS_DBG(ctlr, "Mode changed to %s.\n", buf);
return count; case FCOE_CTLR_UNUSED: default:
LIBFCOE_SYSFS_DBG(ctlr, "Mode change not supported.\n"); return -ENOTSUPP;
}
}
/** * fcoe_ctlr_device_flush_work() - Flush a FIP ctlr's workqueue * @ctlr: Pointer to the FIP ctlr whose workqueue is to be flushed
*/ staticvoid fcoe_ctlr_device_flush_work(struct fcoe_ctlr_device *ctlr)
{ if (!fcoe_ctlr_work_q(ctlr)) {
printk(KERN_ERR "ERROR: FIP Ctlr '%d' attempted to flush work, " "when no workqueue created.\n", ctlr->id);
dump_stack(); return;
}
flush_workqueue(fcoe_ctlr_work_q(ctlr));
}
/** * fcoe_ctlr_device_queue_work() - Schedule work for a FIP ctlr's workqueue * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue * @work: Work to queue for execution * * Return value: * 1 on success / 0 already queued / < 0 for error
*/ staticint fcoe_ctlr_device_queue_work(struct fcoe_ctlr_device *ctlr, struct work_struct *work)
{ if (unlikely(!fcoe_ctlr_work_q(ctlr))) {
printk(KERN_ERR "ERROR: FIP Ctlr '%d' attempted to queue work, " "when no workqueue created.\n", ctlr->id);
dump_stack();
/** * fcoe_ctlr_device_queue_devloss_work() - Schedule work for a FIP ctlr's devloss workqueue * @ctlr: Pointer to the FIP ctlr who owns the devloss workqueue * @work: Work to queue for execution * @delay: jiffies to delay the work queuing * * Return value: * 1 on success / 0 already queued / < 0 for error
*/ staticint fcoe_ctlr_device_queue_devloss_work(struct fcoe_ctlr_device *ctlr, struct delayed_work *work, unsignedlong delay)
{ if (unlikely(!fcoe_ctlr_devloss_work_q(ctlr))) {
printk(KERN_ERR "ERROR: FIP Ctlr '%d' attempted to queue work, " "when no workqueue created.\n", ctlr->id);
dump_stack();
/** * fcoe_ctlr_device_add() - Add a FIP ctlr to sysfs * @parent: The parent device to which the fcoe_ctlr instance * should be attached * @f: The LLD's FCoE sysfs function template pointer * @priv_size: Size to be allocated with the fcoe_ctlr_device for the LLD * * This routine allocates a FIP ctlr object with some additional memory * for the LLD. The FIP ctlr is initialized, added to sysfs and then * attributes are added to it.
*/ struct fcoe_ctlr_device *fcoe_ctlr_device_add(struct device *parent, struct fcoe_sysfs_function_template *f, int priv_size)
{ struct fcoe_ctlr_device *ctlr; int error = 0;
/** * fcoe_ctlr_device_delete() - Delete a FIP ctlr and its subtree from sysfs * @ctlr: A pointer to the ctlr to be deleted * * Deletes a FIP ctlr and any fcfs attached * to it. Deleting fcfs will cause their childen * to be deleted as well. * * The ctlr is detached from sysfs and it's resources * are freed (work q), but the memory is not freed * until its last reference is released. * * This routine expects no locks to be held before * calling. * * TODO: Currently there are no callbacks to clean up LLD data * for a fcoe_fcf_device. LLDs must keep this in mind as they need * to clean up each of their LLD data for all fcoe_fcf_device before * calling fcoe_ctlr_device_delete.
*/ void fcoe_ctlr_device_delete(struct fcoe_ctlr_device *ctlr)
{ struct fcoe_fcf_device *fcf, *next; /* Remove any attached fcfs */
mutex_lock(&ctlr->lock);
list_for_each_entry_safe(fcf, next,
&ctlr->fcfs, peers) {
list_del(&fcf->peers);
fcf->state = FCOE_FCF_STATE_DELETED;
fcoe_ctlr_device_queue_work(ctlr, &fcf->delete_work);
}
mutex_unlock(&ctlr->lock);
/** * fcoe_fcf_device_final_delete() - Final delete routine * @work: The FIP fcf's embedded work struct * * It is expected that the fcf has been removed from * the FIP ctlr's list before calling this routine.
*/ staticvoid fcoe_fcf_device_final_delete(struct work_struct *work)
{ struct fcoe_fcf_device *fcf =
container_of(work, struct fcoe_fcf_device, delete_work); struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
/* * Cancel any outstanding timers. These should really exist * only when rmmod'ing the LLDD and we're asking for * immediate termination of the rports
*/ if (!cancel_delayed_work(&fcf->dev_loss_work))
fcoe_ctlr_device_flush_devloss(ctlr);
device_unregister(&fcf->dev);
}
/** * fip_timeout_deleted_fcf() - Delete a fcf when the devloss timer fires * @work: The FIP fcf's embedded work struct * * Removes the fcf from the FIP ctlr's list of fcfs and * queues the final deletion.
*/ staticvoid fip_timeout_deleted_fcf(struct work_struct *work)
{ struct fcoe_fcf_device *fcf =
container_of(work, struct fcoe_fcf_device, dev_loss_work.work); struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf);
mutex_lock(&ctlr->lock);
/* * If the fcf is deleted or reconnected before the timer * fires the devloss queue will be flushed, but the state will * either be CONNECTED or DELETED. If that is the case we * cancel deleting the fcf.
*/ if (fcf->state != FCOE_FCF_STATE_DISCONNECTED) goto out;
dev_printk(KERN_ERR, &fcf->dev, "FIP fcf connection time out: removing fcf\n");
/** * fcoe_fcf_device_delete() - Delete a FIP fcf * @fcf: Pointer to the fcf which is to be deleted * * Queues the FIP fcf on the devloss workqueue * * Expects the ctlr_attrs mutex to be held for fcf * state change.
*/ void fcoe_fcf_device_delete(struct fcoe_fcf_device *fcf)
{ struct fcoe_ctlr_device *ctlr = fcoe_fcf_dev_to_ctlr_dev(fcf); int timeout = fcf->dev_loss_tmo;
if (fcf->state != FCOE_FCF_STATE_CONNECTED) return;
fcf->state = FCOE_FCF_STATE_DISCONNECTED;
/* * FCF will only be re-connected by the LLD calling * fcoe_fcf_device_add, and it should be setting up * priv then.
*/
fcf->priv = NULL;
/** * fcoe_fcf_device_add() - Add a FCoE sysfs fcoe_fcf_device to the system * @ctlr: The fcoe_ctlr_device that will be the fcoe_fcf_device parent * @new_fcf: A temporary FCF used for lookups on the current list of fcfs * * Expects to be called with the ctlr->lock held
*/ struct fcoe_fcf_device *fcoe_fcf_device_add(struct fcoe_ctlr_device *ctlr, struct fcoe_fcf_device *new_fcf)
{ struct fcoe_fcf_device *fcf; int error = 0;
list_for_each_entry(fcf, &ctlr->fcfs, peers) { if (fcoe_fcf_device_match(new_fcf, fcf)) { if (fcf->state == FCOE_FCF_STATE_CONNECTED) return fcf;
fcf->state = FCOE_FCF_STATE_CONNECTED;
if (!cancel_delayed_work(&fcf->dev_loss_work))
fcoe_ctlr_device_flush_devloss(ctlr);
return fcf;
}
}
fcf = kzalloc(sizeof(struct fcoe_fcf_device), GFP_ATOMIC); if (unlikely(!fcf)) goto out;
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.