Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 226806
b: refs/heads/master
c: 794d98e
h: refs/heads/master
v: v3
  • Loading branch information
Joe Eykholt authored and James Bottomley committed Dec 21, 2010
1 parent 0a4d8a5 commit eb66d12
Show file tree
Hide file tree
Showing 3 changed files with 186 additions and 31 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b69ae0ae3f322d9a6bc4e209049b5b6e193ad652
refs/heads/master: 794d98e77f5901ceded697f1633463e88f078038
207 changes: 177 additions & 30 deletions trunk/drivers/scsi/fcoe/libfcoe.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ MODULE_LICENSE("GPL v2");
static void fcoe_ctlr_timeout(unsigned long);
static void fcoe_ctlr_timer_work(struct work_struct *);
static void fcoe_ctlr_recv_work(struct work_struct *);
static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *);
static void fcoe_ctlr_select(struct fcoe_ctlr *);

static void fcoe_ctlr_vn_start(struct fcoe_ctlr *);
static int fcoe_ctlr_vn_recv(struct fcoe_ctlr *, struct sk_buff *);
Expand Down Expand Up @@ -176,6 +178,7 @@ void fcoe_ctlr_init(struct fcoe_ctlr *fip, enum fip_state mode)
fip->mode = mode;
INIT_LIST_HEAD(&fip->fcfs);
mutex_init(&fip->ctlr_mutex);
spin_lock_init(&fip->ctlr_lock);
fip->flogi_oxid = FC_XID_UNKNOWN;
setup_timer(&fip->timer, fcoe_ctlr_timeout, (unsigned long)fip);
INIT_WORK(&fip->timer_work, fcoe_ctlr_timer_work);
Expand Down Expand Up @@ -231,17 +234,31 @@ void fcoe_ctlr_destroy(struct fcoe_ctlr *fip)
EXPORT_SYMBOL(fcoe_ctlr_destroy);

/**
* fcoe_ctlr_announce() - announce new selection
* fcoe_ctlr_announce() - announce new FCF selection
* @fip: The FCoE controller
*
* Also sets the destination MAC for FCoE and control packets
*
* Called with neither ctlr_mutex nor ctlr_lock held.
*/
static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *sel = fip->sel_fcf;
struct fcoe_fcf *sel;
struct fcoe_fcf *fcf;

mutex_lock(&fip->ctlr_mutex);
spin_lock_bh(&fip->ctlr_lock);

kfree_skb(fip->flogi_req);
fip->flogi_req = NULL;
list_for_each_entry(fcf, &fip->fcfs, list)
fcf->flogi_sent = 0;

spin_unlock_bh(&fip->ctlr_lock);
sel = fip->sel_fcf;

if (sel && !compare_ether_addr(sel->fcf_mac, fip->dest_addr))
return;
goto unlock;
if (!is_zero_ether_addr(fip->dest_addr)) {
printk(KERN_NOTICE "libfcoe: host%d: "
"FIP Fibre-Channel Forwarder MAC %pM deselected\n",
Expand All @@ -255,6 +272,8 @@ static void fcoe_ctlr_announce(struct fcoe_ctlr *fip)
memcpy(fip->dest_addr, sel->fcf_mac, ETH_ALEN);
fip->map_dest = 0;
}
unlock:
mutex_unlock(&fip->ctlr_mutex);
}

/**
Expand Down Expand Up @@ -591,6 +610,9 @@ static int fcoe_ctlr_encaps(struct fcoe_ctlr *fip, struct fc_lport *lport,
* The caller must check that the length is a multiple of 4.
* The SKB must have enough headroom (28 bytes) and tailroom (8 bytes).
* The the skb must also be an fc_frame.
*
* This is called from the lower-level driver with spinlocks held,
* so we must not take a mutex here.
*/
int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
struct sk_buff *skb)
Expand Down Expand Up @@ -628,7 +650,15 @@ int fcoe_ctlr_els_send(struct fcoe_ctlr *fip, struct fc_lport *lport,
switch (op) {
case ELS_FLOGI:
op = FIP_DT_FLOGI;
break;
if (fip->mode == FIP_MODE_VN2VN)
break;
spin_lock_bh(&fip->ctlr_lock);
kfree_skb(fip->flogi_req);
fip->flogi_req = skb;
fip->flogi_req_send = 1;
spin_unlock_bh(&fip->ctlr_lock);
schedule_work(&fip->timer_work);
return -EINPROGRESS;
case ELS_FDISC:
if (ntoh24(fh->fh_s_id))
return 0;
Expand Down Expand Up @@ -1088,18 +1118,24 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
els_op = *(u8 *)(fh + 1);

if ((els_dtype == FIP_DT_FLOGI || els_dtype == FIP_DT_FDISC) &&
sub == FIP_SC_REP && els_op == ELS_LS_ACC &&
fip->mode != FIP_MODE_VN2VN) {
if (!is_valid_ether_addr(granted_mac)) {
LIBFCOE_FIP_DBG(fip,
"Invalid MAC address %pM in FIP ELS\n",
granted_mac);
goto drop;
}
memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);
sub == FIP_SC_REP && fip->mode != FIP_MODE_VN2VN) {
if (els_op == ELS_LS_ACC) {
if (!is_valid_ether_addr(granted_mac)) {
LIBFCOE_FIP_DBG(fip,
"Invalid MAC address %pM in FIP ELS\n",
granted_mac);
goto drop;
}
memcpy(fr_cb(fp)->granted_mac, granted_mac, ETH_ALEN);

if (fip->flogi_oxid == ntohs(fh->fh_ox_id))
fip->flogi_oxid = FC_XID_UNKNOWN;
if (fip->flogi_oxid == ntohs(fh->fh_ox_id)) {
fip->flogi_oxid = FC_XID_UNKNOWN;
if (els_dtype == FIP_DT_FLOGI)
fcoe_ctlr_announce(fip);
}
} else if (els_dtype == FIP_DT_FLOGI &&
!fcoe_ctlr_flogi_retry(fip))
goto drop; /* retrying FLOGI so drop reject */
}

if ((desc_cnt == 0) || ((els_op != ELS_LS_RJT) &&
Expand Down Expand Up @@ -1355,12 +1391,15 @@ static int fcoe_ctlr_recv_handler(struct fcoe_ctlr *fip, struct sk_buff *skb)
*
* If there are conflicting advertisements, no FCF can be chosen.
*
* If there is already a selected FCF, this will choose a better one or
* an equivalent one that hasn't already been sent a FLOGI.
*
* Called with lock held.
*/
static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
struct fcoe_fcf *best = NULL;
struct fcoe_fcf *best = fip->sel_fcf;
struct fcoe_fcf *first;

first = list_first_entry(&fip->fcfs, struct fcoe_fcf, list);
Expand All @@ -1377,6 +1416,8 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
"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",
Expand All @@ -1386,11 +1427,7 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
"" : "un");
continue;
}
if (!best) {
best = fcf;
continue;
}
if (fcf->pri < best->pri)
if (!best || fcf->pri < best->pri || best->flogi_sent)
best = fcf;
}
fip->sel_fcf = best;
Expand All @@ -1403,6 +1440,121 @@ static void fcoe_ctlr_select(struct fcoe_ctlr *fip)
}
}

/**
* fcoe_ctlr_flogi_send_locked() - send FIP-encapsulated FLOGI to current FCF
* @fip: The FCoE controller
*
* Returns non-zero error if it could not be sent.
*
* Called with ctlr_mutex and ctlr_lock held.
* Caller must verify that fip->sel_fcf is not NULL.
*/
static int fcoe_ctlr_flogi_send_locked(struct fcoe_ctlr *fip)
{
struct sk_buff *skb;
struct sk_buff *skb_orig;
struct fc_frame_header *fh;
int error;

skb_orig = fip->flogi_req;
if (!skb_orig)
return -EINVAL;

/*
* Clone and send the FLOGI request. If clone fails, use original.
*/
skb = skb_clone(skb_orig, GFP_ATOMIC);
if (!skb) {
skb = skb_orig;
fip->flogi_req = NULL;
}
fh = (struct fc_frame_header *)skb->data;
error = fcoe_ctlr_encaps(fip, fip->lp, FIP_DT_FLOGI, skb,
ntoh24(fh->fh_d_id));
if (error) {
kfree_skb(skb);
return error;
}
fip->send(fip, skb);
fip->sel_fcf->flogi_sent = 1;
return 0;
}

/**
* fcoe_ctlr_flogi_retry() - resend FLOGI request to a new FCF if possible
* @fip: The FCoE controller
*
* Returns non-zero error code if there's no FLOGI request to retry or
* no alternate FCF available.
*/
static int fcoe_ctlr_flogi_retry(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;
int error;

mutex_lock(&fip->ctlr_mutex);
spin_lock_bh(&fip->ctlr_lock);
LIBFCOE_FIP_DBG(fip, "re-sending FLOGI - reselect\n");
fcoe_ctlr_select(fip);
fcf = fip->sel_fcf;
if (!fcf || fcf->flogi_sent) {
kfree_skb(fip->flogi_req);
fip->flogi_req = NULL;
error = -ENOENT;
} else {
fcoe_ctlr_solicit(fip, NULL);
error = fcoe_ctlr_flogi_send_locked(fip);
}
spin_unlock_bh(&fip->ctlr_lock);
mutex_unlock(&fip->ctlr_mutex);
return error;
}


/**
* fcoe_ctlr_flogi_send() - Handle sending of FIP FLOGI.
* @fip: The FCoE controller that timed out
*
* Done here because fcoe_ctlr_els_send() can't get mutex.
*
* Called with ctlr_mutex held. The caller must not hold ctlr_lock.
*/
static void fcoe_ctlr_flogi_send(struct fcoe_ctlr *fip)
{
struct fcoe_fcf *fcf;

spin_lock_bh(&fip->ctlr_lock);
fcf = fip->sel_fcf;
if (!fcf || !fip->flogi_req_send)
goto unlock;

LIBFCOE_FIP_DBG(fip, "sending FLOGI\n");

/*
* If this FLOGI is being sent due to a timeout retry
* to the same FCF as before, select a different FCF if possible.
*/
if (fcf->flogi_sent) {
LIBFCOE_FIP_DBG(fip, "sending FLOGI - reselect\n");
fcoe_ctlr_select(fip);
fcf = fip->sel_fcf;
if (!fcf || fcf->flogi_sent) {
LIBFCOE_FIP_DBG(fip, "sending FLOGI - clearing\n");
list_for_each_entry(fcf, &fip->fcfs, list)
fcf->flogi_sent = 0;
fcoe_ctlr_select(fip);
fcf = fip->sel_fcf;
}
}
if (fcf) {
fcoe_ctlr_flogi_send_locked(fip);
fip->flogi_req_send = 0;
} else /* XXX */
LIBFCOE_FIP_DBG(fip, "No FCF selected - defer send\n");
unlock:
spin_unlock_bh(&fip->ctlr_lock);
}

/**
* fcoe_ctlr_timeout() - FIP timeout handler
* @arg: The FCoE controller that timed out
Expand Down Expand Up @@ -1455,15 +1607,10 @@ static void fcoe_ctlr_timer_work(struct work_struct *work)
next_timer = fip->sel_time;
}

if (sel != fcf) {
fcf = sel; /* the old FCF may have been freed */
fcoe_ctlr_announce(fip);
if (sel) {
if (time_after(next_timer, fip->ctlr_ka_time))
next_timer = fip->ctlr_ka_time;
} else
reset = 1;
}
if (sel && fip->flogi_req_send)
fcoe_ctlr_flogi_send(fip);
else if (!sel && fcf)
reset = 1;

if (sel && !sel->fd_flags) {
if (time_after_eq(jiffies, fip->ctlr_ka_time)) {
Expand Down
8 changes: 8 additions & 0 deletions trunk/include/scsi/libfcoe.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,12 @@ enum fip_state {
* @timer_work: &work_struct for doing keep-alives and resets.
* @recv_work: &work_struct for receiving FIP frames.
* @fip_recv_list: list of received FIP frames.
* @flogi_req: clone of FLOGI request sent
* @rnd_state: state for pseudo-random number generator.
* @port_id: proposed or selected local-port ID.
* @user_mfs: configured maximum FC frame size, including FC header.
* @flogi_oxid: exchange ID of most recent fabric login.
* @flogi_req_send: send of FLOGI requested
* @flogi_count: number of FLOGI attempts in AUTO mode.
* @map_dest: use the FC_MAP mode for destination MAC addresses.
* @spma: supports SPMA server-provided MACs mode
Expand All @@ -106,6 +108,7 @@ enum fip_state {
* @update_mac: LLD-supplied function to handle changes to MAC addresses.
* @get_src_addr: LLD-supplied function to supply a source MAC address.
* @ctlr_mutex: lock protecting this structure.
* @ctlr_lock: spinlock covering flogi_req
*
* This structure is used by all FCoE drivers. It contains information
* needed by all FCoE low-level drivers (LLDs) as well as internal state
Expand All @@ -126,12 +129,14 @@ struct fcoe_ctlr {
struct work_struct timer_work;
struct work_struct recv_work;
struct sk_buff_head fip_recv_list;
struct sk_buff *flogi_req;

struct rnd_state rnd_state;
u32 port_id;

u16 user_mfs;
u16 flogi_oxid;
u8 flogi_req_send;
u8 flogi_count;
u8 map_dest;
u8 spma;
Expand All @@ -143,6 +148,7 @@ struct fcoe_ctlr {
void (*update_mac)(struct fc_lport *, u8 *addr);
u8 * (*get_src_addr)(struct fc_lport *);
struct mutex ctlr_mutex;
spinlock_t ctlr_lock;
};

/**
Expand All @@ -155,6 +161,7 @@ struct fcoe_ctlr {
* @fcf_mac: Ethernet address of the FCF
* @vfid: virtual fabric ID
* @pri: selection priority, smaller values are better
* @flogi_sent: current FLOGI sent to this FCF
* @flags: flags received from advertisement
* @fka_period: keep-alive period, in jiffies
*
Expand All @@ -176,6 +183,7 @@ struct fcoe_fcf {
u8 fcf_mac[ETH_ALEN];

u8 pri;
u8 flogi_sent;
u16 flags;
u32 fka_period;
u8 fd_flags:1;
Expand Down

0 comments on commit eb66d12

Please sign in to comment.