* [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset
@ 2009-01-21 20:44 Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 2/6] libfc: when rport goes away (re-plogi), clean up exchanges to/from rport Robert Love
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:44 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Abhijeet Joglekar <abjoglek@cisco.com>
fc_exch_mgr structure is private to fc_exch.c. To export exch_mgr_reset to
transport, transport needs access to the exch manager. Change
exch_mgr_reset to use lport param which is the shared structure between
libFC and transport.
Alternatively, fc_exch_mgr definition can be moved to libfc.h so that lport
can be accessed from mp*.
Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/libfc/fc_exch.c | 3 ++-
drivers/scsi/libfc/fc_lport.c | 4 ++--
drivers/scsi/libfc/fc_rport.c | 4 ++--
include/scsi/libfc.h | 4 ++--
4 files changed, 8 insertions(+), 7 deletions(-)
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index 66db08a..a09416f 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1480,10 +1480,11 @@ static void fc_exch_reset(struct fc_exch *ep)
* If sid is non-zero, reset only exchanges we source from that FID.
* If did is non-zero, reset only exchanges destined to that FID.
*/
-void fc_exch_mgr_reset(struct fc_exch_mgr *mp, u32 sid, u32 did)
+void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did)
{
struct fc_exch *ep;
struct fc_exch *next;
+ struct fc_exch_mgr *mp = lp->emp;
spin_lock_bh(&mp->em_lock);
restart:
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 0b9bdb1..5db223c 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -663,7 +663,7 @@ int fc_lport_destroy(struct fc_lport *lport)
{
lport->tt.frame_send = fc_frame_drop;
lport->tt.fcp_abort_io(lport);
- lport->tt.exch_mgr_reset(lport->emp, 0, 0);
+ lport->tt.exch_mgr_reset(lport, 0, 0);
return 0;
}
EXPORT_SYMBOL(fc_lport_destroy);
@@ -973,7 +973,7 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
lport->tt.disc_stop(lport);
- lport->tt.exch_mgr_reset(lport->emp, 0, 0);
+ lport->tt.exch_mgr_reset(lport, 0, 0);
fc_host_fabric_name(lport->host) = 0;
fc_host_port_id(lport->host) = 0;
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index e780d8c..dec7bae 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -1285,7 +1285,7 @@ void fc_rport_terminate_io(struct fc_rport *rport)
struct fc_rport_libfc_priv *rdata = rport->dd_data;
struct fc_lport *lport = rdata->local_port;
- lport->tt.exch_mgr_reset(lport->emp, 0, rport->port_id);
- lport->tt.exch_mgr_reset(lport->emp, rport->port_id, 0);
+ lport->tt.exch_mgr_reset(lport, 0, rport->port_id);
+ lport->tt.exch_mgr_reset(lport, rport->port_id, 0);
}
EXPORT_SYMBOL(fc_rport_terminate_io);
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 9f28763..042f4ad 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -472,7 +472,7 @@ struct libfc_function_template {
* If s_id is non-zero, reset only exchanges originating from that FID.
* If d_id is non-zero, reset only exchanges sending to that FID.
*/
- void (*exch_mgr_reset)(struct fc_exch_mgr *,
+ void (*exch_mgr_reset)(struct fc_lport *,
u32 s_id, u32 d_id);
void (*rport_flush_queue)(void);
@@ -916,7 +916,7 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp);
* If s_id is non-zero, reset only exchanges originating from that FID.
* If d_id is non-zero, reset only exchanges sending to that FID.
*/
-void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id);
+void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);
/*
* Functions for fc_functions_template
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Open-FCoE PATCH 2/6] libfc: when rport goes away (re-plogi), clean up exchanges to/from rport
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
@ 2009-01-21 20:44 ` Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 3/6] libfc: handle RRQ exch timeout Robert Love
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:44 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Abhijeet Joglekar <abjoglek@cisco.com>
When a rport goes away, libFC does a plogi which will reset exchanges
at the rport. Clean exchanges at our end, both in transport and libFC.
If transport hooks into exch_mgr_reset, it will call back into
fc_exch_mgr_reset() to clean up libFC exchanges.
Signed-off-by: Abhijeet Joglekar <abjoglek@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/libfc/fc_rport.c | 7 ++++++-
1 files changed, 6 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index dec7bae..7175759 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -214,6 +214,7 @@ static void fc_rport_state_enter(struct fc_rport *rport,
static void fc_rport_work(struct work_struct *work)
{
+ u32 port_id;
struct fc_rport_libfc_priv *rdata =
container_of(work, struct fc_rport_libfc_priv, event_work);
enum fc_rport_event event;
@@ -279,8 +280,12 @@ static void fc_rport_work(struct work_struct *work)
rport_ops->event_callback(lport, rport, event);
if (trans_state == FC_PORTSTATE_ROGUE)
put_device(&rport->dev);
- else
+ else {
+ port_id = rport->port_id;
fc_remote_port_delete(rport);
+ lport->tt.exch_mgr_reset(lport, 0, port_id);
+ lport->tt.exch_mgr_reset(lport, port_id, 0);
+ }
} else
mutex_unlock(&rdata->rp_mutex);
}
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Open-FCoE PATCH 3/6] libfc: handle RRQ exch timeout
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 2/6] libfc: when rport goes away (re-plogi), clean up exchanges to/from rport Robert Love
@ 2009-01-21 20:44 ` Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 4/6] libfc: fixed a soft lockup issue in fc_exch_recv_abts Robert Love
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:44 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Vasu Dev <vasu.dev@intel.com>
Cleanup exchange held due to RRQ when RRQ exch times out, in this case the
ABTS is already done causing RRQ req therefore proceeding with cleanup in
fc_exch_rrq_resp should be okay to restore exch resource.
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/libfc/fc_exch.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index a09416f..e874e77 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1608,7 +1608,7 @@ static void fc_exch_rrq_resp(struct fc_seq *sp, struct fc_frame *fp, void *arg)
if (IS_ERR(fp)) {
int err = PTR_ERR(fp);
- if (err == -FC_EX_CLOSED)
+ if (err == -FC_EX_CLOSED || err == -FC_EX_TIMEOUT)
goto cleanup;
FC_DBG("Cannot process RRQ, because of frame error %d\n", err);
return;
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Open-FCoE PATCH 4/6] libfc: fixed a soft lockup issue in fc_exch_recv_abts
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 2/6] libfc: when rport goes away (re-plogi), clean up exchanges to/from rport Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 3/6] libfc: handle RRQ exch timeout Robert Love
@ 2009-01-21 20:45 ` Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 5/6] libfc, fcoe: fixed locking issues with lport->lp_mutex around lport->link_status Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 6/6] libfc: rport retry on LS_RJT from certain ELS Robert Love
4 siblings, 0 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:45 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Vasu Dev <vasu.dev@intel.com>
The fc_seq_start_next grabs ep->ex_lock but this lock was already held here,
so instead called fc_seq_start_next_locked to avoid soft lockup.
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/libfc/fc_exch.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index e874e77..dd269e5 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -1096,7 +1096,7 @@ static void fc_exch_recv_abts(struct fc_exch *ep, struct fc_frame *rx_fp)
ap->ba_high_seq_cnt = fh->fh_seq_cnt;
ap->ba_low_seq_cnt = htons(sp->cnt);
}
- sp = fc_seq_start_next(sp);
+ sp = fc_seq_start_next_locked(sp);
spin_unlock_bh(&ep->ex_lock);
fc_seq_send_last(sp, fp, FC_RCTL_BA_ACC, FC_TYPE_BLS);
fc_frame_free(rx_fp);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Open-FCoE PATCH 5/6] libfc, fcoe: fixed locking issues with lport->lp_mutex around lport->link_status
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
` (2 preceding siblings ...)
2009-01-21 20:45 ` [Open-FCoE PATCH 4/6] libfc: fixed a soft lockup issue in fc_exch_recv_abts Robert Love
@ 2009-01-21 20:45 ` Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 6/6] libfc: rport retry on LS_RJT from certain ELS Robert Love
4 siblings, 0 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:45 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Vasu Dev <vasu.dev@intel.com>
The fcoe_xmit could call fc_pause in case the pending skb queue len is larger
than FCOE_MAX_QUEUE_DEPTH, the fc_pause was trying to grab lport->lp_muex to
change lport->link_status and that had these issues :-
1. The fcoe_xmit was getting called with bh disabled, thus causing
"BUG: scheduling while atomic" when grabbing lport->lp_muex with bh disabled.
2. fc_linkup and fc_linkdown function calls lport_enter function with
lport->lp_mutex held and these enter function in turn calls fcoe_xmit to send
lport related FC frame, e.g. fc_linkup => fc_lport_enter_flogi to send flogi
req. In this case grabbing the same lport->lp_mutex again in fc_puase from
fcoe_xmit would cause deadlock.
The lport->lp_mutex was used for setting FC_PAUSE in fcoe_xmit path but
FC_PAUSE bit was not used anywhere beside just setting and clear this
bit in lport->link_status, instead used a separate field qfull in fc_lport
to eliminate need for lport->lp_mutex to track pending queue full condition
and in turn avoid above described two locking issues.
Also added check for lp->qfull in fc_fcp_lport_queue_ready to trigger
SCSI_MLQUEUE_HOST_BUSY when lp->qfull is set to prevent more scsi-ml cmds
while lp->qfull is set.
This patch eliminated FC_LINK_UP and FC_PAUSE and instead used dedicated
fields in fc_lport for this, this simplified all related conditional
code.
Also removed fc_pause and fc_unpause functions and instead used newly added
lport->qfull directly in fcoe.
Signed-off-by: Vasu Dev <vasu.dev@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/fcoe/fcoe_sw.c | 6 +++---
drivers/scsi/fcoe/libfcoe.c | 41 +++++++++++++++++------------------------
drivers/scsi/libfc/fc_fcp.c | 4 ++--
drivers/scsi/libfc/fc_lport.c | 36 ++++++------------------------------
include/scsi/libfc.h | 12 ++----------
5 files changed, 30 insertions(+), 69 deletions(-)
diff --git a/drivers/scsi/fcoe/fcoe_sw.c b/drivers/scsi/fcoe/fcoe_sw.c
index dc4cd5e..cf83675 100644
--- a/drivers/scsi/fcoe/fcoe_sw.c
+++ b/drivers/scsi/fcoe/fcoe_sw.c
@@ -116,7 +116,8 @@ static int fcoe_sw_lport_config(struct fc_lport *lp)
{
int i = 0;
- lp->link_status = 0;
+ lp->link_up = 0;
+ lp->qfull = 0;
lp->max_retry_count = 3;
lp->e_d_tov = 2 * 1000; /* FC-FS default */
lp->r_a_tov = 2 * 2 * 1000;
@@ -181,9 +182,8 @@ static int fcoe_sw_netdev_config(struct fc_lport *lp, struct net_device *netdev)
if (fc_set_mfs(lp, mfs))
return -EINVAL;
- lp->link_status = ~FC_PAUSE & ~FC_LINK_UP;
if (!fcoe_link_ok(lp))
- lp->link_status |= FC_LINK_UP;
+ lp->link_up = 1;
/* offload features support */
if (fc->real_dev->features & NETIF_F_SG)
diff --git a/drivers/scsi/fcoe/libfcoe.c b/drivers/scsi/fcoe/libfcoe.c
index e419f48..2960710 100644
--- a/drivers/scsi/fcoe/libfcoe.c
+++ b/drivers/scsi/fcoe/libfcoe.c
@@ -504,7 +504,7 @@ int fcoe_xmit(struct fc_lport *lp, struct fc_frame *fp)
if (rc) {
fcoe_insert_wait_queue(lp, skb);
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
- fc_pause(lp);
+ lp->qfull = 1;
}
return 0;
@@ -718,7 +718,7 @@ static void fcoe_recv_flogi(struct fcoe_softc *fc, struct fc_frame *fp, u8 *sa)
* fcoe_watchdog - fcoe timer callback
* @vp:
*
- * This checks the pending queue length for fcoe and put fcoe to be paused state
+ * This checks the pending queue length for fcoe and set lport qfull
* if the FCOE_MAX_QUEUE_DEPTH is reached. This is done for all fc_lport on the
* fcoe_hostlist.
*
@@ -728,17 +728,17 @@ void fcoe_watchdog(ulong vp)
{
struct fc_lport *lp;
struct fcoe_softc *fc;
- int paused = 0;
+ int qfilled = 0;
read_lock(&fcoe_hostlist_lock);
list_for_each_entry(fc, &fcoe_hostlist, list) {
lp = fc->lp;
if (lp) {
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
- paused = 1;
+ qfilled = 1;
if (fcoe_check_wait_queue(lp) < FCOE_MAX_QUEUE_DEPTH) {
- if (paused)
- fc_unpause(lp);
+ if (qfilled)
+ lp->qfull = 0;
}
}
}
@@ -767,8 +767,7 @@ void fcoe_watchdog(ulong vp)
**/
static int fcoe_check_wait_queue(struct fc_lport *lp)
{
- int rc, unpause = 0;
- int paused = 0;
+ int rc;
struct sk_buff *skb;
struct fcoe_softc *fc;
@@ -776,10 +775,10 @@ static int fcoe_check_wait_queue(struct fc_lport *lp)
spin_lock_bh(&fc->fcoe_pending_queue.lock);
/*
- * is this interface paused?
+ * if interface pending queue full then set qfull in lport.
*/
if (fc->fcoe_pending_queue.qlen > FCOE_MAX_QUEUE_DEPTH)
- paused = 1;
+ lp->qfull = 1;
if (fc->fcoe_pending_queue.qlen) {
while ((skb = __skb_dequeue(&fc->fcoe_pending_queue)) != NULL) {
spin_unlock_bh(&fc->fcoe_pending_queue.lock);
@@ -791,11 +790,9 @@ static int fcoe_check_wait_queue(struct fc_lport *lp)
spin_lock_bh(&fc->fcoe_pending_queue.lock);
}
if (fc->fcoe_pending_queue.qlen < FCOE_MAX_QUEUE_DEPTH)
- unpause = 1;
+ lp->qfull = 0;
}
spin_unlock_bh(&fc->fcoe_pending_queue.lock);
- if ((unpause) && (paused))
- fc_unpause(lp);
return fc->fcoe_pending_queue.qlen;
}
@@ -873,7 +870,7 @@ static int fcoe_device_notification(struct notifier_block *notifier,
struct net_device *real_dev = ptr;
struct fcoe_softc *fc;
struct fcoe_dev_stats *stats;
- u16 new_status;
+ u32 new_link_up;
u32 mfs;
int rc = NOTIFY_OK;
@@ -890,17 +887,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
goto out;
}
- new_status = lp->link_status;
+ new_link_up = lp->link_up;
switch (event) {
case NETDEV_DOWN:
case NETDEV_GOING_DOWN:
- new_status &= ~FC_LINK_UP;
+ new_link_up = 0;
break;
case NETDEV_UP:
case NETDEV_CHANGE:
- new_status &= ~FC_LINK_UP;
- if (!fcoe_link_ok(lp))
- new_status |= FC_LINK_UP;
+ new_link_up = !fcoe_link_ok(lp);
break;
case NETDEV_CHANGEMTU:
mfs = fc->real_dev->mtu -
@@ -908,17 +903,15 @@ static int fcoe_device_notification(struct notifier_block *notifier,
sizeof(struct fcoe_crc_eof));
if (mfs >= FC_MIN_MAX_FRAME)
fc_set_mfs(lp, mfs);
- new_status &= ~FC_LINK_UP;
- if (!fcoe_link_ok(lp))
- new_status |= FC_LINK_UP;
+ new_link_up = !fcoe_link_ok(lp);
break;
case NETDEV_REGISTER:
break;
default:
FC_DBG("unknown event %ld call", event);
}
- if (lp->link_status != new_status) {
- if ((new_status & FC_LINK_UP) == FC_LINK_UP)
+ if (lp->link_up != new_link_up) {
+ if (new_link_up)
fc_linkup(lp);
else {
stats = lp->dev_stats[smp_processor_id()];
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 404e63f..f440aac 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -1621,7 +1621,7 @@ out:
static inline int fc_fcp_lport_queue_ready(struct fc_lport *lp)
{
/* lock ? */
- return (lp->state == LPORT_ST_READY) && (lp->link_status & FC_LINK_UP);
+ return (lp->state == LPORT_ST_READY) && lp->link_up && !lp->qfull;
}
/**
@@ -1890,7 +1890,7 @@ int fc_eh_abort(struct scsi_cmnd *sc_cmd)
lp = shost_priv(sc_cmd->device->host);
if (lp->state != LPORT_ST_READY)
return rc;
- else if (!(lp->link_status & FC_LINK_UP))
+ else if (!lp->link_up)
return rc;
spin_lock_irqsave(lp->host->host_lock, flags);
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
index 5db223c..a6ab692 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -250,7 +250,7 @@ void fc_get_host_port_state(struct Scsi_Host *shost)
{
struct fc_lport *lp = shost_priv(shost);
- if ((lp->link_status & FC_LINK_UP) == FC_LINK_UP)
+ if (lp->link_up)
fc_host_port_state(shost) = FC_PORTSTATE_ONLINE;
else
fc_host_port_state(shost) = FC_PORTSTATE_OFFLINE;
@@ -577,8 +577,8 @@ void fc_linkup(struct fc_lport *lport)
fc_host_port_id(lport->host));
mutex_lock(&lport->lp_mutex);
- if ((lport->link_status & FC_LINK_UP) != FC_LINK_UP) {
- lport->link_status |= FC_LINK_UP;
+ if (!lport->link_up) {
+ lport->link_up = 1;
if (lport->state == LPORT_ST_RESET)
fc_lport_enter_flogi(lport);
@@ -597,8 +597,8 @@ void fc_linkdown(struct fc_lport *lport)
FC_DEBUG_LPORT("Link is down for port (%6x)\n",
fc_host_port_id(lport->host));
- if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP) {
- lport->link_status &= ~(FC_LINK_UP);
+ if (lport->link_up) {
+ lport->link_up = 0;
fc_lport_enter_reset(lport);
lport->tt.fcp_cleanup(lport);
}
@@ -607,30 +607,6 @@ void fc_linkdown(struct fc_lport *lport)
EXPORT_SYMBOL(fc_linkdown);
/**
- * fc_pause - Pause the flow of frames
- * @lport: The lport to be paused
- */
-void fc_pause(struct fc_lport *lport)
-{
- mutex_lock(&lport->lp_mutex);
- lport->link_status |= FC_PAUSE;
- mutex_unlock(&lport->lp_mutex);
-}
-EXPORT_SYMBOL(fc_pause);
-
-/**
- * fc_unpause - Unpause the flow of frames
- * @lport: The lport to be unpaused
- */
-void fc_unpause(struct fc_lport *lport)
-{
- mutex_lock(&lport->lp_mutex);
- lport->link_status &= ~(FC_PAUSE);
- mutex_unlock(&lport->lp_mutex);
-}
-EXPORT_SYMBOL(fc_unpause);
-
-/**
* fc_fabric_logoff - Logout of the fabric
* @lport: fc_lport pointer to logoff the fabric
*
@@ -977,7 +953,7 @@ static void fc_lport_enter_reset(struct fc_lport *lport)
fc_host_fabric_name(lport->host) = 0;
fc_host_port_id(lport->host) = 0;
- if ((lport->link_status & FC_LINK_UP) == FC_LINK_UP)
+ if (lport->link_up)
fc_lport_enter_flogi(lport);
}
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 042f4ad..b9e6c1c 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -68,9 +68,6 @@
/*
* FC HBA status
*/
-#define FC_PAUSE (1 << 1)
-#define FC_LINK_UP (1 << 0)
-
enum fc_lport_state {
LPORT_ST_NONE = 0,
LPORT_ST_FLOGI,
@@ -603,7 +600,8 @@ struct fc_lport {
/* Operational Information */
struct libfc_function_template tt;
- u16 link_status;
+ u8 link_up;
+ u8 qfull;
enum fc_lport_state state;
unsigned long boot_time;
@@ -704,12 +702,6 @@ void fc_linkup(struct fc_lport *);
void fc_linkdown(struct fc_lport *);
/*
- * Pause and unpause traffic.
- */
-void fc_pause(struct fc_lport *);
-void fc_unpause(struct fc_lport *);
-
-/*
* Configure the local port.
*/
int fc_lport_config(struct fc_lport *);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [Open-FCoE PATCH 6/6] libfc: rport retry on LS_RJT from certain ELS
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
` (3 preceding siblings ...)
2009-01-21 20:45 ` [Open-FCoE PATCH 5/6] libfc, fcoe: fixed locking issues with lport->lp_mutex around lport->link_status Robert Love
@ 2009-01-21 20:45 ` Robert Love
4 siblings, 0 replies; 6+ messages in thread
From: Robert Love @ 2009-01-21 20:45 UTC (permalink / raw)
To: james.bottomley; +Cc: linux-scsi
From: Chris Leech <christopher.leech@intel.com>
This allows any rport ELS to retry on LS_RJT.
The rport error handling would only retry on resource allocation failures
and exchange timeouts. I have a target that will occasionally reject PLOGI
when we do a quick LOGO/PLOGI. When a critical ELS was rejected, libfc would
fail silently leaving the rport in a dead state.
The retry count and delay are managed by fc_rport_error_retry. If the retry
count is exceeded fc_rport_error will be called. When retrying is not the
correct course of action, fc_rport_error can be called directly.
Signed-off-by: Chris Leech <christopher.leech@intel.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
---
drivers/scsi/libfc/fc_exch.c | 2 -
drivers/scsi/libfc/fc_rport.c | 111 ++++++++++++++++++++++++-----------------
include/scsi/fc/fc_fs.h | 5 ++
3 files changed, 69 insertions(+), 49 deletions(-)
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
index dd269e5..8c40189 100644
--- a/drivers/scsi/libfc/fc_exch.c
+++ b/drivers/scsi/libfc/fc_exch.c
@@ -32,8 +32,6 @@
#include <scsi/libfc.h>
#include <scsi/fc_encode.h>
-#define FC_DEF_R_A_TOV (10 * 1000) /* resource allocation timeout */
-
/*
* fc_exch_debug can be set in debugger or at compile time to get more logs.
*/
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 7175759..600a8ff 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -81,6 +81,7 @@ static void fc_rport_recv_logo_req(struct fc_rport *,
struct fc_seq *, struct fc_frame *);
static void fc_rport_timeout(struct work_struct *);
static void fc_rport_error(struct fc_rport *, struct fc_frame *);
+static void fc_rport_error_retry(struct fc_rport *, struct fc_frame *);
static void fc_rport_work(struct work_struct *);
static const char *fc_rport_state_names[] = {
@@ -410,58 +411,74 @@ static void fc_rport_timeout(struct work_struct *work)
}
/**
- * fc_rport_error - Handler for any errors
+ * fc_rport_error - Error handler, called once retries have been exhausted
* @rport: The fc_rport object
* @fp: The frame pointer
*
- * If the error was caused by a resource allocation failure
- * then wait for half a second and retry, otherwise retry
- * immediately.
- *
* Locking Note: The rport lock is expected to be held before
* calling this routine
*/
static void fc_rport_error(struct fc_rport *rport, struct fc_frame *fp)
{
struct fc_rport_libfc_priv *rdata = rport->dd_data;
- unsigned long delay = 0;
FC_DEBUG_RPORT("Error %ld in state %s, retries %d\n",
PTR_ERR(fp), fc_rport_state(rport), rdata->retries);
- if (!fp || PTR_ERR(fp) == -FC_EX_TIMEOUT) {
- /*
- * Memory allocation failure, or the exchange timed out.
- * Retry after delay
- */
- if (rdata->retries < rdata->local_port->max_retry_count) {
- rdata->retries++;
- if (!fp)
- delay = msecs_to_jiffies(500);
- get_device(&rport->dev);
- schedule_delayed_work(&rdata->retry_work, delay);
- } else {
- switch (rdata->rp_state) {
- case RPORT_ST_PLOGI:
- case RPORT_ST_PRLI:
- case RPORT_ST_LOGO:
- rdata->event = RPORT_EV_FAILED;
- queue_work(rport_event_queue,
- &rdata->event_work);
- break;
- case RPORT_ST_RTV:
- fc_rport_enter_ready(rport);
- break;
- case RPORT_ST_NONE:
- case RPORT_ST_READY:
- case RPORT_ST_INIT:
- break;
- }
- }
+ switch (rdata->rp_state) {
+ case RPORT_ST_PLOGI:
+ case RPORT_ST_PRLI:
+ case RPORT_ST_LOGO:
+ rdata->event = RPORT_EV_FAILED;
+ queue_work(rport_event_queue,
+ &rdata->event_work);
+ break;
+ case RPORT_ST_RTV:
+ fc_rport_enter_ready(rport);
+ break;
+ case RPORT_ST_NONE:
+ case RPORT_ST_READY:
+ case RPORT_ST_INIT:
+ break;
}
}
/**
+ * fc_rport_error_retry - Error handler when retries are desired
+ * @rport: The fc_rport object
+ * @fp: The frame pointer
+ *
+ * If the error was an exchange timeout retry immediately,
+ * otherwise wait for E_D_TOV.
+ *
+ * Locking Note: The rport lock is expected to be held before
+ * calling this routine
+ */
+static void fc_rport_error_retry(struct fc_rport *rport, struct fc_frame *fp)
+{
+ struct fc_rport_libfc_priv *rdata = rport->dd_data;
+ unsigned long delay = FC_DEF_E_D_TOV;
+
+ /* make sure this isn't an FC_EX_CLOSED error, never retry those */
+ if (PTR_ERR(fp) == -FC_EX_CLOSED)
+ return fc_rport_error(rport, fp);
+
+ if (rdata->retries < rdata->local_port->max_retry_count) {
+ FC_DEBUG_RPORT("Error %ld in state %s, retrying\n",
+ PTR_ERR(fp), fc_rport_state(rport));
+ rdata->retries++;
+ /* no additional delay on exchange timeouts */
+ if (PTR_ERR(fp) == -FC_EX_TIMEOUT)
+ delay = 0;
+ get_device(&rport->dev);
+ schedule_delayed_work(&rdata->retry_work, delay);
+ return;
+ }
+
+ return fc_rport_error(rport, fp);
+}
+
+/**
* fc_rport_plogi_recv_resp - Handle incoming ELS PLOGI response
* @sp: current sequence in the PLOGI exchange
* @fp: response frame
@@ -495,7 +512,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
}
if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
goto err;
}
@@ -527,7 +544,7 @@ static void fc_rport_plogi_resp(struct fc_seq *sp, struct fc_frame *fp,
else
fc_rport_enter_prli(rport);
} else
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
out:
fc_frame_free(fp);
@@ -557,14 +574,14 @@ static void fc_rport_enter_plogi(struct fc_rport *rport)
rport->maxframe_size = FC_MIN_MAX_PAYLOAD;
fp = fc_frame_alloc(lport, sizeof(struct fc_els_flogi));
if (!fp) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
return;
}
rdata->e_d_tov = lport->e_d_tov;
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PLOGI,
fc_rport_plogi_resp, rport, lport->e_d_tov))
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
else
get_device(&rport->dev);
}
@@ -604,7 +621,7 @@ static void fc_rport_prli_resp(struct fc_seq *sp, struct fc_frame *fp,
}
if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
goto err;
}
@@ -662,7 +679,7 @@ static void fc_rport_logo_resp(struct fc_seq *sp, struct fc_frame *fp,
rport->port_id);
if (IS_ERR(fp)) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
goto err;
}
@@ -712,13 +729,13 @@ static void fc_rport_enter_prli(struct fc_rport *rport)
fp = fc_frame_alloc(lport, sizeof(*pp));
if (!fp) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
return;
}
if (!lport->tt.elsct_send(lport, rport, fp, ELS_PRLI,
fc_rport_prli_resp, rport, lport->e_d_tov))
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
else
get_device(&rport->dev);
}
@@ -809,13 +826,13 @@ static void fc_rport_enter_rtv(struct fc_rport *rport)
fp = fc_frame_alloc(lport, sizeof(struct fc_els_rtv));
if (!fp) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
return;
}
if (!lport->tt.elsct_send(lport, rport, fp, ELS_RTV,
fc_rport_rtv_resp, rport, lport->e_d_tov))
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
else
get_device(&rport->dev);
}
@@ -840,13 +857,13 @@ static void fc_rport_enter_logo(struct fc_rport *rport)
fp = fc_frame_alloc(lport, sizeof(struct fc_els_logo));
if (!fp) {
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
return;
}
if (!lport->tt.elsct_send(lport, rport, fp, ELS_LOGO,
fc_rport_logo_resp, rport, lport->e_d_tov))
- fc_rport_error(rport, fp);
+ fc_rport_error_retry(rport, fp);
else
get_device(&rport->dev);
}
diff --git a/include/scsi/fc/fc_fs.h b/include/scsi/fc/fc_fs.h
index 3e4801d..1b7af3a 100644
--- a/include/scsi/fc/fc_fs.h
+++ b/include/scsi/fc/fc_fs.h
@@ -337,4 +337,9 @@ enum fc_pf_rjt_reason {
FC_RJT_VENDOR = 0xff, /* vendor specific reject */
};
+/* default timeout values */
+
+#define FC_DEF_E_D_TOV 2000UL
+#define FC_DEF_R_A_TOV 10000UL
+
#endif /* _FC_FS_H_ */
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-01-21 20:45 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-01-21 20:44 [Open-FCoE PATCH 1/6] libfc: Pass lport in exch_mgr_reset Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 2/6] libfc: when rport goes away (re-plogi), clean up exchanges to/from rport Robert Love
2009-01-21 20:44 ` [Open-FCoE PATCH 3/6] libfc: handle RRQ exch timeout Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 4/6] libfc: fixed a soft lockup issue in fc_exch_recv_abts Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 5/6] libfc, fcoe: fixed locking issues with lport->lp_mutex around lport->link_status Robert Love
2009-01-21 20:45 ` [Open-FCoE PATCH 6/6] libfc: rport retry on LS_RJT from certain ELS Robert Love
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.