diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 12:47:02 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-07 12:47:02 -0800 |
commit | da40d036fd716f0efb2917076220814b1e927ae1 (patch) | |
tree | 567893573a48e2954d82421e77606034d3b32f84 /drivers/scsi/libfc/fc_exch.c | |
parent | aa58abc20fa85328a9f048e2626c0893691ff284 (diff) | |
parent | c32e061fa19893ce4acf95d97d5613a161f0f1b7 (diff) | |
download | linux-stable-da40d036fd716f0efb2917076220814b1e927ae1.tar.gz linux-stable-da40d036fd716f0efb2917076220814b1e927ae1.tar.bz2 linux-stable-da40d036fd716f0efb2917076220814b1e927ae1.zip |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi-misc-2.6: (147 commits)
[SCSI] arcmsr: fix write to device check
[SCSI] lpfc: lower stack use in lpfc_fc_frame_check
[SCSI] eliminate an unnecessary local variable from scsi_remove_target()
[SCSI] libiscsi: use bh locking instead of irq with session lock
[SCSI] libiscsi: do not take host lock in queuecommand
[SCSI] be2iscsi: fix null ptr when accessing task hdr
[SCSI] be2iscsi: fix gfp use in alloc_pdu
[SCSI] libiscsi: add more informative failure message during iscsi scsi eh
[SCSI] gdth: Add missing call to gdth_ioctl_free
[SCSI] bfa: remove unused defintions and misc cleanups
[SCSI] bfa: remove inactive functions
[SCSI] bfa: replace bfa_assert with WARN_ON
[SCSI] qla2xxx: Use sg_next to fetch next sg element while walking sg list.
[SCSI] qla2xxx: Fix to avoid recursive lock failure during BSG timeout.
[SCSI] qla2xxx: Remove code to not reset ISP82xx on failure.
[SCSI] qla2xxx: Display mailbox register 4 during 8012 AEN for ISP82XX parts.
[SCSI] qla2xxx: Don't perform a BIG_HAMMER if Get-ID (0x20) mailbox command fails on CNAs.
[SCSI] qla2xxx: Remove redundant module parameter permission bits
[SCSI] qla2xxx: Add sysfs node for displaying board temperature.
[SCSI] qla2xxx: Code cleanup to remove unwanted comments and code.
...
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 48 |
1 files changed, 40 insertions, 8 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index ec2a1aec2350..d21367d3305f 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c @@ -67,6 +67,11 @@ struct workqueue_struct *fc_exch_workqueue; struct fc_exch_pool { u16 next_index; u16 total_exches; + + /* two cache of free slot in exch array */ + u16 left; + u16 right; + spinlock_t lock; struct list_head ex_list; }; @@ -108,7 +113,6 @@ struct fc_exch_mgr { atomic_t non_bls_resp; } stats; }; -#define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) /** * struct fc_exch_mgr_anchor - primary structure for list of EMs @@ -397,13 +401,23 @@ static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, static void fc_exch_delete(struct fc_exch *ep) { struct fc_exch_pool *pool; + u16 index; pool = ep->pool; spin_lock_bh(&pool->lock); WARN_ON(pool->total_exches <= 0); pool->total_exches--; - fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order, - NULL); + + /* update cache of free slot */ + index = (ep->xid - ep->em->min_xid) >> fc_cpu_order; + if (pool->left == FC_XID_UNKNOWN) + pool->left = index; + else if (pool->right == FC_XID_UNKNOWN) + pool->right = index; + else + pool->next_index = index; + + fc_exch_ptr_set(pool, index, NULL); list_del(&ep->ex_list); spin_unlock_bh(&pool->lock); fc_exch_release(ep); /* drop hold for exch in mp */ @@ -636,10 +650,13 @@ static void fc_exch_timeout(struct work_struct *work) if (e_stat & ESB_ST_ABNORMAL) rc = fc_exch_done_locked(ep); spin_unlock_bh(&ep->ex_lock); - if (!rc) - fc_exch_delete(ep); if (resp) resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); + if (!rc) { + /* delete the exchange if it's already being aborted */ + fc_exch_delete(ep); + return; + } fc_seq_exch_abort(sp, 2 * ep->r_a_tov); goto done; } @@ -679,6 +696,19 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, pool = per_cpu_ptr(mp->pool, cpu); spin_lock_bh(&pool->lock); put_cpu(); + + /* peek cache of free slot */ + if (pool->left != FC_XID_UNKNOWN) { + index = pool->left; + pool->left = FC_XID_UNKNOWN; + goto hit; + } + if (pool->right != FC_XID_UNKNOWN) { + index = pool->right; + pool->right = FC_XID_UNKNOWN; + goto hit; + } + index = pool->next_index; /* allocate new exch from pool */ while (fc_exch_ptr_get(pool, index)) { @@ -687,7 +717,7 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, goto err; } pool->next_index = index == mp->pool_max_index ? 0 : index + 1; - +hit: fc_exch_hold(ep); /* hold for exch in mp */ spin_lock_init(&ep->ex_lock); /* @@ -1247,7 +1277,7 @@ static struct fc_seq *fc_seq_assign(struct fc_lport *lport, struct fc_frame *fp) list_for_each_entry(ema, &lport->ema_list, ema_list) if ((!ema->match || ema->match(fp)) && - fc_seq_lookup_recip(lport, ema->mp, fp) != FC_RJT_NONE) + fc_seq_lookup_recip(lport, ema->mp, fp) == FC_RJT_NONE) break; return fr_seq(fp); } @@ -1343,7 +1373,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) } if (ep->esb_stat & ESB_ST_COMPLETE) { atomic_inc(&mp->stats.xid_not_found); - goto out; + goto rel; } if (ep->rxid == FC_XID_UNKNOWN) ep->rxid = ntohs(fh->fh_rx_id); @@ -2181,6 +2211,8 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lport, goto free_mempool; for_each_possible_cpu(cpu) { pool = per_cpu_ptr(mp->pool, cpu); + pool->left = FC_XID_UNKNOWN; + pool->right = FC_XID_UNKNOWN; spin_lock_init(&pool->lock); INIT_LIST_HEAD(&pool->ex_list); } |