diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 94 |
1 files changed, 18 insertions, 76 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 324589a5cc03..11ddd115efb6 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -58,7 +58,7 @@ struct fc_exch_mgr { | |||
58 | struct kref kref; /* exchange mgr reference count */ | 58 | struct kref kref; /* exchange mgr reference count */ |
59 | spinlock_t em_lock; /* exchange manager lock, | 59 | spinlock_t em_lock; /* exchange manager lock, |
60 | must be taken before ex_lock */ | 60 | must be taken before ex_lock */ |
61 | u16 last_xid; /* last allocated exchange ID */ | 61 | u16 next_xid; /* next possible free exchange ID */ |
62 | u16 min_xid; /* min exchange ID */ | 62 | u16 min_xid; /* min exchange ID */ |
63 | u16 max_xid; /* max exchange ID */ | 63 | u16 max_xid; /* max exchange ID */ |
64 | u16 max_read; /* max exchange ID for read */ | 64 | u16 max_read; /* max exchange ID for read */ |
@@ -464,68 +464,21 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) | |||
464 | return sp; | 464 | return sp; |
465 | } | 465 | } |
466 | 466 | ||
467 | /* | ||
468 | * fc_em_alloc_xid - returns an xid based on request type | ||
469 | * @lp : ptr to associated lport | ||
470 | * @fp : ptr to the assocated frame | ||
471 | * | ||
472 | * check the associated fc_fsp_pkt to get scsi command type and | ||
473 | * command direction to decide from which range this exch id | ||
474 | * will be allocated from. | ||
475 | * | ||
476 | * Returns : 0 or an valid xid | ||
477 | */ | ||
478 | static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) | ||
479 | { | ||
480 | u16 xid, min, max; | ||
481 | u16 *plast; | ||
482 | struct fc_exch *ep = NULL; | ||
483 | |||
484 | if (mp->max_read) { | ||
485 | if (fc_fcp_is_read(fr_fsp(fp))) { | ||
486 | min = mp->min_xid; | ||
487 | max = mp->max_read; | ||
488 | plast = &mp->last_read; | ||
489 | } else { | ||
490 | min = mp->max_read + 1; | ||
491 | max = mp->max_xid; | ||
492 | plast = &mp->last_xid; | ||
493 | } | ||
494 | } else { | ||
495 | min = mp->min_xid; | ||
496 | max = mp->max_xid; | ||
497 | plast = &mp->last_xid; | ||
498 | } | ||
499 | xid = *plast; | ||
500 | do { | ||
501 | xid = (xid == max) ? min : xid + 1; | ||
502 | ep = mp->exches[xid - mp->min_xid]; | ||
503 | } while ((ep != NULL) && (xid != *plast)); | ||
504 | |||
505 | if (unlikely(ep)) | ||
506 | xid = 0; | ||
507 | else | ||
508 | *plast = xid; | ||
509 | |||
510 | return xid; | ||
511 | } | ||
512 | |||
513 | /** | 467 | /** |
514 | * fc_exch_em_alloc() - allocate an exchange from a specified EM. | 468 | * fc_exch_em_alloc() - allocate an exchange from a specified EM. |
515 | * @lport: ptr to the local port | 469 | * @lport: ptr to the local port |
516 | * @mp: ptr to the exchange manager | 470 | * @mp: ptr to the exchange manager |
517 | * @fp: ptr to the FC frame | ||
518 | * @xid: input xid | ||
519 | * | 471 | * |
520 | * if xid is supplied zero then assign next free exchange ID | 472 | * Returns pointer to allocated fc_exch with exch lock held. |
521 | * from exchange manager, otherwise use supplied xid. | ||
522 | * Returns with exch lock held. | ||
523 | */ | 473 | */ |
524 | static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, | 474 | static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, |
525 | struct fc_exch_mgr *mp, | 475 | struct fc_exch_mgr *mp) |
526 | struct fc_frame *fp, u16 xid) | ||
527 | { | 476 | { |
528 | struct fc_exch *ep; | 477 | struct fc_exch *ep; |
478 | u16 min, max, xid; | ||
479 | |||
480 | min = mp->min_xid; | ||
481 | max = mp->max_xid; | ||
529 | 482 | ||
530 | /* allocate memory for exchange */ | 483 | /* allocate memory for exchange */ |
531 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); | 484 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); |
@@ -536,15 +489,14 @@ static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, | |||
536 | memset(ep, 0, sizeof(*ep)); | 489 | memset(ep, 0, sizeof(*ep)); |
537 | 490 | ||
538 | spin_lock_bh(&mp->em_lock); | 491 | spin_lock_bh(&mp->em_lock); |
539 | /* alloc xid if input xid 0 */ | 492 | xid = mp->next_xid; |
540 | if (!xid) { | 493 | /* alloc a new xid */ |
541 | /* alloc a new xid */ | 494 | while (mp->exches[xid - min]) { |
542 | xid = fc_em_alloc_xid(mp, fp); | 495 | xid = (xid == max) ? min : xid + 1; |
543 | if (!xid) { | 496 | if (xid == mp->next_xid) |
544 | printk(KERN_WARNING "libfc: Failed to allocate an exhange\n"); | ||
545 | goto err; | 497 | goto err; |
546 | } | ||
547 | } | 498 | } |
499 | mp->next_xid = (xid == max) ? min : xid + 1; | ||
548 | 500 | ||
549 | fc_exch_hold(ep); /* hold for exch in mp */ | 501 | fc_exch_hold(ep); /* hold for exch in mp */ |
550 | spin_lock_init(&ep->ex_lock); | 502 | spin_lock_init(&ep->ex_lock); |
@@ -597,7 +549,7 @@ struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) | |||
597 | 549 | ||
598 | list_for_each_entry(ema, &lport->ema_list, ema_list) { | 550 | list_for_each_entry(ema, &lport->ema_list, ema_list) { |
599 | if (!ema->match || ema->match(fp)) { | 551 | if (!ema->match || ema->match(fp)) { |
600 | ep = fc_exch_em_alloc(lport, ema->mp, fp, 0); | 552 | ep = fc_exch_em_alloc(lport, ema->mp); |
601 | if (ep) | 553 | if (ep) |
602 | return ep; | 554 | return ep; |
603 | } | 555 | } |
@@ -1817,7 +1769,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1817 | struct fc_exch_mgr *mp; | 1769 | struct fc_exch_mgr *mp; |
1818 | size_t len; | 1770 | size_t len; |
1819 | 1771 | ||
1820 | if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { | 1772 | if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN) { |
1821 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", | 1773 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", |
1822 | min_xid, max_xid); | 1774 | min_xid, max_xid); |
1823 | return NULL; | 1775 | return NULL; |
@@ -1826,7 +1778,6 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1826 | /* | 1778 | /* |
1827 | * Memory need for EM | 1779 | * Memory need for EM |
1828 | */ | 1780 | */ |
1829 | #define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2))) | ||
1830 | len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); | 1781 | len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); |
1831 | len += sizeof(struct fc_exch_mgr); | 1782 | len += sizeof(struct fc_exch_mgr); |
1832 | 1783 | ||
@@ -1840,17 +1791,7 @@ struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | |||
1840 | /* adjust em exch xid range for offload */ | 1791 | /* adjust em exch xid range for offload */ |
1841 | mp->min_xid = min_xid; | 1792 | mp->min_xid = min_xid; |
1842 | mp->max_xid = max_xid; | 1793 | mp->max_xid = max_xid; |
1843 | mp->last_xid = min_xid - 1; | 1794 | mp->next_xid = min_xid; |
1844 | mp->max_read = 0; | ||
1845 | mp->last_read = 0; | ||
1846 | if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) { | ||
1847 | mp->max_read = lp->lro_xid; | ||
1848 | mp->last_read = min_xid - 1; | ||
1849 | mp->last_xid = mp->max_read; | ||
1850 | } else { | ||
1851 | /* disable lro if no xid control over read */ | ||
1852 | lp->lro_enabled = 0; | ||
1853 | } | ||
1854 | 1795 | ||
1855 | INIT_LIST_HEAD(&mp->ex_list); | 1796 | INIT_LIST_HEAD(&mp->ex_list); |
1856 | spin_lock_init(&mp->em_lock); | 1797 | spin_lock_init(&mp->em_lock); |
@@ -1922,7 +1863,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | |||
1922 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); | 1863 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); |
1923 | sp->cnt++; | 1864 | sp->cnt++; |
1924 | 1865 | ||
1925 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | 1866 | if (ep->xid <= lp->lro_xid) |
1867 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | ||
1926 | 1868 | ||
1927 | if (unlikely(lp->tt.frame_send(lp, fp))) | 1869 | if (unlikely(lp->tt.frame_send(lp, fp))) |
1928 | goto err; | 1870 | goto err; |