diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 130 |
1 files changed, 80 insertions, 50 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index aceffadb21c7..c772d8d27159 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -99,11 +99,6 @@ struct fc_exch_mgr { u16 max_xid; u16 pool_max_index; - /* - * currently exchange mgr stats are updated but not used. - * either stats can be expose via sysfs or remove them - * all together if not used XXX - */ struct { atomic_t no_free_exch; atomic_t no_free_exch_xid; @@ -124,7 +119,7 @@ struct fc_exch_mgr { * for each anchor to determine if that EM should be used. The last * anchor in the list will always match to handle any exchanges not * handled by other EMs. The non-default EMs would be added to the - * anchor list by HW that provides FCoE offloads. + * anchor list by HW that provides offloads. */ struct fc_exch_mgr_anchor { struct list_head ema_list; @@ -339,6 +334,52 @@ static void fc_exch_release(struct fc_exch *ep) } /** + * fc_exch_timer_cancel() - cancel exch timer + * @ep: The exchange whose timer to be canceled + */ +static inline void fc_exch_timer_cancel(struct fc_exch *ep) +{ + if (cancel_delayed_work(&ep->timeout_work)) { + FC_EXCH_DBG(ep, "Exchange timer canceled\n"); + atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + } +} + +/** + * fc_exch_timer_set_locked() - Start a timer for an exchange w/ the + * the exchange lock held + * @ep: The exchange whose timer will start + * @timer_msec: The timeout period + * + * Used for upper level protocols to time out the exchange. + * The timer is cancelled when it fires or when the exchange completes. + */ +static inline void fc_exch_timer_set_locked(struct fc_exch *ep, + unsigned int timer_msec) +{ + if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) + return; + + FC_EXCH_DBG(ep, "Exchange timer armed : %d msecs\n", timer_msec); + + if (queue_delayed_work(fc_exch_workqueue, &ep->timeout_work, + msecs_to_jiffies(timer_msec))) + fc_exch_hold(ep); /* hold for timer */ +} + +/** + * fc_exch_timer_set() - Lock the exchange and set the timer + * @ep: The exchange whose timer will start + * @timer_msec: The timeout period + */ +static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec) +{ + spin_lock_bh(&ep->ex_lock); + fc_exch_timer_set_locked(ep, timer_msec); + spin_unlock_bh(&ep->ex_lock); +} + +/** * fc_exch_done_locked() - Complete an exchange with the exchange lock held * @ep: The exchange that is complete */ @@ -359,8 +400,7 @@ static int fc_exch_done_locked(struct fc_exch *ep) if (!(ep->esb_stat & ESB_ST_REC_QUAL)) { ep->state |= FC_EX_DONE; - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + fc_exch_timer_cancel(ep); rc = 0; } return rc; @@ -424,40 +464,6 @@ static void fc_exch_delete(struct fc_exch *ep) } /** - * fc_exch_timer_set_locked() - Start a timer for an exchange w/ the - * the exchange lock held - * @ep: The exchange whose timer will start - * @timer_msec: The timeout period - * - * Used for upper level protocols to time out the exchange. - * The timer is cancelled when it fires or when the exchange completes. - */ -static inline void fc_exch_timer_set_locked(struct fc_exch *ep, - unsigned int timer_msec) -{ - if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) - return; - - FC_EXCH_DBG(ep, "Exchange timer armed\n"); - - if (queue_delayed_work(fc_exch_workqueue, &ep->timeout_work, - msecs_to_jiffies(timer_msec))) - fc_exch_hold(ep); /* hold for timer */ -} - -/** - * fc_exch_timer_set() - Lock the exchange and set the timer - * @ep: The exchange whose timer will start - * @timer_msec: The timeout period - */ -static void fc_exch_timer_set(struct fc_exch *ep, unsigned int timer_msec) -{ - spin_lock_bh(&ep->ex_lock); - fc_exch_timer_set_locked(ep, timer_msec); - spin_unlock_bh(&ep->ex_lock); -} - -/** * fc_seq_send() - Send a frame using existing sequence/exchange pair * @lport: The local port that the exchange will be sent on * @sp: The sequence to be sent @@ -986,7 +992,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, /* * Update sequence_id based on incoming last * frame of sequence exchange. This is needed - * for FCoE target where DDP has been used + * for FC target where DDP has been used * on target where, stack is indicated only * about last frame's (payload _header) header. * Whereas "seq_id" which is part of @@ -1549,8 +1555,10 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) FC_EXCH_DBG(ep, "exch: BLS rctl %x - %s\n", fh->fh_r_ctl, fc_exch_rctl_name(fh->fh_r_ctl)); - if (cancel_delayed_work_sync(&ep->timeout_work)) + if (cancel_delayed_work_sync(&ep->timeout_work)) { + FC_EXCH_DBG(ep, "Exchange timer canceled\n"); fc_exch_release(ep); /* release from pending timer hold */ + } spin_lock_bh(&ep->ex_lock); switch (fh->fh_r_ctl) { @@ -1737,8 +1745,7 @@ static void fc_exch_reset(struct fc_exch *ep) spin_lock_bh(&ep->ex_lock); fc_exch_abort_locked(ep, 0); ep->state |= FC_EX_RST_CLEANUP; - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop hold for timer */ + fc_exch_timer_cancel(ep); resp = ep->resp; ep->resp = NULL; if (ep->esb_stat & ESB_ST_REC_QUAL) @@ -2133,10 +2140,8 @@ static void fc_exch_els_rrq(struct fc_frame *fp) ep->esb_stat &= ~ESB_ST_REC_QUAL; atomic_dec(&ep->ex_refcnt); /* drop hold for rec qual */ } - if (ep->esb_stat & ESB_ST_COMPLETE) { - if (cancel_delayed_work(&ep->timeout_work)) - atomic_dec(&ep->ex_refcnt); /* drop timer hold */ - } + if (ep->esb_stat & ESB_ST_COMPLETE) + fc_exch_timer_cancel(ep); spin_unlock_bh(&ep->ex_lock); @@ -2156,6 +2161,31 @@ out: } /** + * fc_exch_update_stats() - update exches stats to lport + * @lport: The local port to update exchange manager stats + */ +void fc_exch_update_stats(struct fc_lport *lport) +{ + struct fc_host_statistics *st; + struct fc_exch_mgr_anchor *ema; + struct fc_exch_mgr *mp; + + st = &lport->host_stats; + + list_for_each_entry(ema, &lport->ema_list, ema_list) { + mp = ema->mp; + st->fc_no_free_exch += atomic_read(&mp->stats.no_free_exch); + st->fc_no_free_exch_xid += + atomic_read(&mp->stats.no_free_exch_xid); + st->fc_xid_not_found += atomic_read(&mp->stats.xid_not_found); + st->fc_xid_busy += atomic_read(&mp->stats.xid_busy); + st->fc_seq_not_found += atomic_read(&mp->stats.seq_not_found); + st->fc_non_bls_resp += atomic_read(&mp->stats.non_bls_resp); + } +} +EXPORT_SYMBOL(fc_exch_update_stats); + +/** * fc_exch_mgr_add() - Add an exchange manager to a local port's list of EMs * @lport: The local port to add the exchange manager to * @mp: The exchange manager to be added to the local port |