summaryrefslogtreecommitdiff
path: root/drivers/scsi/fcoe/fcoe_ctlr.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/fcoe/fcoe_ctlr.c')
-rw-r--r--drivers/scsi/fcoe/fcoe_ctlr.c94
1 files changed, 63 insertions, 31 deletions
diff --git a/drivers/scsi/fcoe/fcoe_ctlr.c b/drivers/scsi/fcoe/fcoe_ctlr.c
index 692c6535fe75..75efdbc54ef8 100644
--- a/drivers/scsi/fcoe/fcoe_ctlr.c
+++ b/drivers/scsi/fcoe/fcoe_ctlr.c
@@ -160,10 +160,16 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
}
EXPORT_SYMBOL(fcoe_ctlr_init);
+/**
+ * fcoe_sysfs_fcf_add() - Add a fcoe_fcf{,_device} to a fcoe_ctlr{,_device}
+ * @new: The newly discovered FCF
+ *
+ * Called with fip->ctlr_mutex held
+ */
static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new)
{
struct fcoe_ctlr *fip = new->fip;
- struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+ struct fcoe_ctlr_device *ctlr_dev;
struct fcoe_fcf_device *temp, *fcf_dev;
int rc = -ENOMEM;
@@ -174,8 +180,6 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new)
if (!temp)
goto out;
- mutex_lock(&ctlr_dev->lock);
-
temp->fabric_name = new->fabric_name;
temp->switch_name = new->switch_name;
temp->fc_map = new->fc_map;
@@ -185,55 +189,83 @@ static int fcoe_sysfs_fcf_add(struct fcoe_fcf *new)
temp->fka_period = new->fka_period;
temp->selected = 0; /* default to unselected */
- fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp);
- if (unlikely(!fcf_dev))
- goto unlock;
-
/*
- * The fcoe_sysfs layer can return a CONNECTED fcf that
- * has a priv (fcf was never deleted) or a CONNECTED fcf
- * that doesn't have a priv (fcf was deleted). However,
- * libfcoe will always delete FCFs before trying to add
- * them. This is ensured because both recv_adv and
- * age_fcfs are protected by the the fcoe_ctlr's mutex.
- * This means that we should never get a FCF with a
- * non-NULL priv pointer.
+ * If ctlr_dev doesn't exist then it means we're a libfcoe user
+ * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device.
+ * fnic would be an example of a driver with this behavior. In this
+ * case we want to add the fcoe_fcf to the fcoe_ctlr list, but we
+ * don't want to make sysfs changes.
*/
- BUG_ON(fcf_dev->priv);
- fcf_dev->priv = new;
- new->fcf_dev = fcf_dev;
+ ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+ if (ctlr_dev) {
+ mutex_lock(&ctlr_dev->lock);
+ fcf_dev = fcoe_fcf_device_add(ctlr_dev, temp);
+ if (unlikely(!fcf_dev)) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ /*
+ * The fcoe_sysfs layer can return a CONNECTED fcf that
+ * has a priv (fcf was never deleted) or a CONNECTED fcf
+ * that doesn't have a priv (fcf was deleted). However,
+ * libfcoe will always delete FCFs before trying to add
+ * them. This is ensured because both recv_adv and
+ * age_fcfs are protected by the the fcoe_ctlr's mutex.
+ * This means that we should never get a FCF with a
+ * non-NULL priv pointer.
+ */
+ BUG_ON(fcf_dev->priv);
+
+ fcf_dev->priv = new;
+ new->fcf_dev = fcf_dev;
+ mutex_unlock(&ctlr_dev->lock);
+ }
list_add(&new->list, &fip->fcfs);
fip->fcf_count++;
rc = 0;
-unlock:
- mutex_unlock(&ctlr_dev->lock);
-
out:
kfree(temp);
return rc;
}
+/**
+ * fcoe_sysfs_fcf_del() - Remove a fcoe_fcf{,_device} to a fcoe_ctlr{,_device}
+ * @new: The FCF to be removed
+ *
+ * Called with fip->ctlr_mutex held
+ */
static void fcoe_sysfs_fcf_del(struct fcoe_fcf *new)
{
struct fcoe_ctlr *fip = new->fip;
- struct fcoe_ctlr_device *ctlr_dev = fcoe_ctlr_to_ctlr_dev(fip);
+ struct fcoe_ctlr_device *cdev;
struct fcoe_fcf_device *fcf_dev;
list_del(&new->list);
fip->fcf_count--;
- mutex_lock(&ctlr_dev->lock);
-
- fcf_dev = fcoe_fcf_to_fcf_dev(new);
- WARN_ON(!fcf_dev);
- new->fcf_dev = NULL;
- fcoe_fcf_device_delete(fcf_dev);
- kfree(new);
-
- mutex_unlock(&ctlr_dev->lock);
+ /*
+ * If ctlr_dev doesn't exist then it means we're a libfcoe user
+ * who doesn't use fcoe_syfs and didn't allocate a fcoe_ctlr_device
+ * or a fcoe_fcf_device.
+ *
+ * fnic would be an example of a driver with this behavior. In this
+ * case we want to remove the fcoe_fcf from the fcoe_ctlr list (above),
+ * but we don't want to make sysfs changes.
+ */
+ cdev = fcoe_ctlr_to_ctlr_dev(fip);
+ if (cdev) {
+ mutex_lock(&cdev->lock);
+ fcf_dev = fcoe_fcf_to_fcf_dev(new);
+ WARN_ON(!fcf_dev);
+ new->fcf_dev = NULL;
+ fcoe_fcf_device_delete(fcf_dev);
+ kfree(new);
+ mutex_unlock(&cdev->lock);
+ }
}
/**