diff options
Diffstat (limited to 'drivers/scsi/libfc/fc_exch.c')
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 515 |
1 files changed, 321 insertions, 194 deletions
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c index 145ab9ba55ea..c1c15748220c 100644 --- a/drivers/scsi/libfc/fc_exch.c +++ b/drivers/scsi/libfc/fc_exch.c | |||
@@ -32,6 +32,9 @@ | |||
32 | #include <scsi/libfc.h> | 32 | #include <scsi/libfc.h> |
33 | #include <scsi/fc_encode.h> | 33 | #include <scsi/fc_encode.h> |
34 | 34 | ||
35 | u16 fc_cpu_mask; /* cpu mask for possible cpus */ | ||
36 | EXPORT_SYMBOL(fc_cpu_mask); | ||
37 | static u16 fc_cpu_order; /* 2's power to represent total possible cpus */ | ||
35 | static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ | 38 | static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ |
36 | 39 | ||
37 | /* | 40 | /* |
@@ -48,6 +51,20 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ | |||
48 | */ | 51 | */ |
49 | 52 | ||
50 | /* | 53 | /* |
54 | * Per cpu exchange pool | ||
55 | * | ||
56 | * This structure manages per cpu exchanges in array of exchange pointers. | ||
57 | * This array is allocated followed by struct fc_exch_pool memory for | ||
58 | * assigned range of exchanges to per cpu pool. | ||
59 | */ | ||
60 | struct fc_exch_pool { | ||
61 | u16 next_index; /* next possible free exchange index */ | ||
62 | u16 total_exches; /* total allocated exchanges */ | ||
63 | spinlock_t lock; /* exch pool lock */ | ||
64 | struct list_head ex_list; /* allocated exchanges list */ | ||
65 | }; | ||
66 | |||
67 | /* | ||
51 | * Exchange manager. | 68 | * Exchange manager. |
52 | * | 69 | * |
53 | * This structure is the center for creating exchanges and sequences. | 70 | * This structure is the center for creating exchanges and sequences. |
@@ -55,17 +72,13 @@ static struct kmem_cache *fc_em_cachep; /* cache for exchanges */ | |||
55 | */ | 72 | */ |
56 | struct fc_exch_mgr { | 73 | struct fc_exch_mgr { |
57 | enum fc_class class; /* default class for sequences */ | 74 | enum fc_class class; /* default class for sequences */ |
58 | spinlock_t em_lock; /* exchange manager lock, | 75 | struct kref kref; /* exchange mgr reference count */ |
59 | must be taken before ex_lock */ | ||
60 | u16 last_xid; /* last allocated exchange ID */ | ||
61 | u16 min_xid; /* min exchange ID */ | 76 | u16 min_xid; /* min exchange ID */ |
62 | u16 max_xid; /* max exchange ID */ | 77 | u16 max_xid; /* max exchange ID */ |
63 | u16 max_read; /* max exchange ID for read */ | ||
64 | u16 last_read; /* last xid allocated for read */ | ||
65 | u32 total_exches; /* total allocated exchanges */ | ||
66 | struct list_head ex_list; /* allocated exchanges list */ | 78 | struct list_head ex_list; /* allocated exchanges list */ |
67 | struct fc_lport *lp; /* fc device instance */ | ||
68 | mempool_t *ep_pool; /* reserve ep's */ | 79 | mempool_t *ep_pool; /* reserve ep's */ |
80 | u16 pool_max_index; /* max exch array index in exch pool */ | ||
81 | struct fc_exch_pool *pool; /* per cpu exch pool */ | ||
69 | 82 | ||
70 | /* | 83 | /* |
71 | * currently exchange mgr stats are updated but not used. | 84 | * currently exchange mgr stats are updated but not used. |
@@ -80,10 +93,15 @@ struct fc_exch_mgr { | |||
80 | atomic_t seq_not_found; | 93 | atomic_t seq_not_found; |
81 | atomic_t non_bls_resp; | 94 | atomic_t non_bls_resp; |
82 | } stats; | 95 | } stats; |
83 | struct fc_exch **exches; /* for exch pointers indexed by xid */ | ||
84 | }; | 96 | }; |
85 | #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) | 97 | #define fc_seq_exch(sp) container_of(sp, struct fc_exch, seq) |
86 | 98 | ||
99 | struct fc_exch_mgr_anchor { | ||
100 | struct list_head ema_list; | ||
101 | struct fc_exch_mgr *mp; | ||
102 | bool (*match)(struct fc_frame *); | ||
103 | }; | ||
104 | |||
87 | static void fc_exch_rrq(struct fc_exch *); | 105 | static void fc_exch_rrq(struct fc_exch *); |
88 | static void fc_seq_ls_acc(struct fc_seq *); | 106 | static void fc_seq_ls_acc(struct fc_seq *); |
89 | static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, | 107 | static void fc_seq_ls_rjt(struct fc_seq *, enum fc_els_rjt_reason, |
@@ -167,8 +185,8 @@ static struct fc_seq *fc_seq_start_next_locked(struct fc_seq *sp); | |||
167 | * sequence allocation and deallocation must be locked. | 185 | * sequence allocation and deallocation must be locked. |
168 | * - exchange refcnt can be done atomicly without locks. | 186 | * - exchange refcnt can be done atomicly without locks. |
169 | * - sequence allocation must be locked by exch lock. | 187 | * - sequence allocation must be locked by exch lock. |
170 | * - If the em_lock and ex_lock must be taken at the same time, then the | 188 | * - If the EM pool lock and ex_lock must be taken at the same time, then the |
171 | * em_lock must be taken before the ex_lock. | 189 | * EM pool lock must be taken before the ex_lock. |
172 | */ | 190 | */ |
173 | 191 | ||
174 | /* | 192 | /* |
@@ -268,8 +286,6 @@ static void fc_exch_release(struct fc_exch *ep) | |||
268 | mp = ep->em; | 286 | mp = ep->em; |
269 | if (ep->destructor) | 287 | if (ep->destructor) |
270 | ep->destructor(&ep->seq, ep->arg); | 288 | ep->destructor(&ep->seq, ep->arg); |
271 | if (ep->lp->tt.exch_put) | ||
272 | ep->lp->tt.exch_put(ep->lp, mp, ep->xid); | ||
273 | WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); | 289 | WARN_ON(!(ep->esb_stat & ESB_ST_COMPLETE)); |
274 | mempool_free(ep, mp->ep_pool); | 290 | mempool_free(ep, mp->ep_pool); |
275 | } | 291 | } |
@@ -299,17 +315,31 @@ static int fc_exch_done_locked(struct fc_exch *ep) | |||
299 | return rc; | 315 | return rc; |
300 | } | 316 | } |
301 | 317 | ||
302 | static void fc_exch_mgr_delete_ep(struct fc_exch *ep) | 318 | static inline struct fc_exch *fc_exch_ptr_get(struct fc_exch_pool *pool, |
319 | u16 index) | ||
303 | { | 320 | { |
304 | struct fc_exch_mgr *mp; | 321 | struct fc_exch **exches = (struct fc_exch **)(pool + 1); |
322 | return exches[index]; | ||
323 | } | ||
305 | 324 | ||
306 | mp = ep->em; | 325 | static inline void fc_exch_ptr_set(struct fc_exch_pool *pool, u16 index, |
307 | spin_lock_bh(&mp->em_lock); | 326 | struct fc_exch *ep) |
308 | WARN_ON(mp->total_exches <= 0); | 327 | { |
309 | mp->total_exches--; | 328 | ((struct fc_exch **)(pool + 1))[index] = ep; |
310 | mp->exches[ep->xid - mp->min_xid] = NULL; | 329 | } |
330 | |||
331 | static void fc_exch_delete(struct fc_exch *ep) | ||
332 | { | ||
333 | struct fc_exch_pool *pool; | ||
334 | |||
335 | pool = ep->pool; | ||
336 | spin_lock_bh(&pool->lock); | ||
337 | WARN_ON(pool->total_exches <= 0); | ||
338 | pool->total_exches--; | ||
339 | fc_exch_ptr_set(pool, (ep->xid - ep->em->min_xid) >> fc_cpu_order, | ||
340 | NULL); | ||
311 | list_del(&ep->ex_list); | 341 | list_del(&ep->ex_list); |
312 | spin_unlock_bh(&mp->em_lock); | 342 | spin_unlock_bh(&pool->lock); |
313 | fc_exch_release(ep); /* drop hold for exch in mp */ | 343 | fc_exch_release(ep); /* drop hold for exch in mp */ |
314 | } | 344 | } |
315 | 345 | ||
@@ -322,7 +352,7 @@ static inline void fc_exch_timer_set_locked(struct fc_exch *ep, | |||
322 | if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) | 352 | if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) |
323 | return; | 353 | return; |
324 | 354 | ||
325 | FC_EXCH_DBG(ep, "Exchange timed out, notifying the upper layer\n"); | 355 | FC_EXCH_DBG(ep, "Exchange timer armed\n"); |
326 | 356 | ||
327 | if (schedule_delayed_work(&ep->timeout_work, | 357 | if (schedule_delayed_work(&ep->timeout_work, |
328 | msecs_to_jiffies(timer_msec))) | 358 | msecs_to_jiffies(timer_msec))) |
@@ -408,6 +438,8 @@ static void fc_exch_timeout(struct work_struct *work) | |||
408 | u32 e_stat; | 438 | u32 e_stat; |
409 | int rc = 1; | 439 | int rc = 1; |
410 | 440 | ||
441 | FC_EXCH_DBG(ep, "Exchange timed out\n"); | ||
442 | |||
411 | spin_lock_bh(&ep->ex_lock); | 443 | spin_lock_bh(&ep->ex_lock); |
412 | if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) | 444 | if (ep->state & (FC_EX_RST_CLEANUP | FC_EX_DONE)) |
413 | goto unlock; | 445 | goto unlock; |
@@ -427,7 +459,7 @@ static void fc_exch_timeout(struct work_struct *work) | |||
427 | rc = fc_exch_done_locked(ep); | 459 | rc = fc_exch_done_locked(ep); |
428 | spin_unlock_bh(&ep->ex_lock); | 460 | spin_unlock_bh(&ep->ex_lock); |
429 | if (!rc) | 461 | if (!rc) |
430 | fc_exch_mgr_delete_ep(ep); | 462 | fc_exch_delete(ep); |
431 | if (resp) | 463 | if (resp) |
432 | resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); | 464 | resp(sp, ERR_PTR(-FC_EX_TIMEOUT), arg); |
433 | fc_seq_exch_abort(sp, 2 * ep->r_a_tov); | 465 | fc_seq_exch_abort(sp, 2 * ep->r_a_tov); |
@@ -460,65 +492,20 @@ static struct fc_seq *fc_seq_alloc(struct fc_exch *ep, u8 seq_id) | |||
460 | return sp; | 492 | return sp; |
461 | } | 493 | } |
462 | 494 | ||
463 | /* | 495 | /** |
464 | * fc_em_alloc_xid - returns an xid based on request type | 496 | * fc_exch_em_alloc() - allocate an exchange from a specified EM. |
465 | * @lp : ptr to associated lport | 497 | * @lport: ptr to the local port |
466 | * @fp : ptr to the assocated frame | 498 | * @mp: ptr to the exchange manager |
467 | * | 499 | * |
468 | * check the associated fc_fsp_pkt to get scsi command type and | 500 | * Returns pointer to allocated fc_exch with exch lock held. |
469 | * command direction to decide from which range this exch id | ||
470 | * will be allocated from. | ||
471 | * | ||
472 | * Returns : 0 or an valid xid | ||
473 | */ | 501 | */ |
474 | static u16 fc_em_alloc_xid(struct fc_exch_mgr *mp, const struct fc_frame *fp) | 502 | static struct fc_exch *fc_exch_em_alloc(struct fc_lport *lport, |
475 | { | 503 | struct fc_exch_mgr *mp) |
476 | u16 xid, min, max; | ||
477 | u16 *plast; | ||
478 | struct fc_exch *ep = NULL; | ||
479 | |||
480 | if (mp->max_read) { | ||
481 | if (fc_fcp_is_read(fr_fsp(fp))) { | ||
482 | min = mp->min_xid; | ||
483 | max = mp->max_read; | ||
484 | plast = &mp->last_read; | ||
485 | } else { | ||
486 | min = mp->max_read + 1; | ||
487 | max = mp->max_xid; | ||
488 | plast = &mp->last_xid; | ||
489 | } | ||
490 | } else { | ||
491 | min = mp->min_xid; | ||
492 | max = mp->max_xid; | ||
493 | plast = &mp->last_xid; | ||
494 | } | ||
495 | xid = *plast; | ||
496 | do { | ||
497 | xid = (xid == max) ? min : xid + 1; | ||
498 | ep = mp->exches[xid - mp->min_xid]; | ||
499 | } while ((ep != NULL) && (xid != *plast)); | ||
500 | |||
501 | if (unlikely(ep)) | ||
502 | xid = 0; | ||
503 | else | ||
504 | *plast = xid; | ||
505 | |||
506 | return xid; | ||
507 | } | ||
508 | |||
509 | /* | ||
510 | * fc_exch_alloc - allocate an exchange. | ||
511 | * @mp : ptr to the exchange manager | ||
512 | * @xid: input xid | ||
513 | * | ||
514 | * if xid is supplied zero then assign next free exchange ID | ||
515 | * from exchange manager, otherwise use supplied xid. | ||
516 | * Returns with exch lock held. | ||
517 | */ | ||
518 | struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | ||
519 | struct fc_frame *fp, u16 xid) | ||
520 | { | 504 | { |
521 | struct fc_exch *ep; | 505 | struct fc_exch *ep; |
506 | unsigned int cpu; | ||
507 | u16 index; | ||
508 | struct fc_exch_pool *pool; | ||
522 | 509 | ||
523 | /* allocate memory for exchange */ | 510 | /* allocate memory for exchange */ |
524 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); | 511 | ep = mempool_alloc(mp->ep_pool, GFP_ATOMIC); |
@@ -528,16 +515,17 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | |||
528 | } | 515 | } |
529 | memset(ep, 0, sizeof(*ep)); | 516 | memset(ep, 0, sizeof(*ep)); |
530 | 517 | ||
531 | spin_lock_bh(&mp->em_lock); | 518 | cpu = smp_processor_id(); |
532 | /* alloc xid if input xid 0 */ | 519 | pool = per_cpu_ptr(mp->pool, cpu); |
533 | if (!xid) { | 520 | spin_lock_bh(&pool->lock); |
534 | /* alloc a new xid */ | 521 | index = pool->next_index; |
535 | xid = fc_em_alloc_xid(mp, fp); | 522 | /* allocate new exch from pool */ |
536 | if (!xid) { | 523 | while (fc_exch_ptr_get(pool, index)) { |
537 | printk(KERN_WARNING "libfc: Failed to allocate an exhange\n"); | 524 | index = index == mp->pool_max_index ? 0 : index + 1; |
525 | if (index == pool->next_index) | ||
538 | goto err; | 526 | goto err; |
539 | } | ||
540 | } | 527 | } |
528 | pool->next_index = index == mp->pool_max_index ? 0 : index + 1; | ||
541 | 529 | ||
542 | fc_exch_hold(ep); /* hold for exch in mp */ | 530 | fc_exch_hold(ep); /* hold for exch in mp */ |
543 | spin_lock_init(&ep->ex_lock); | 531 | spin_lock_init(&ep->ex_lock); |
@@ -548,18 +536,19 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | |||
548 | */ | 536 | */ |
549 | spin_lock_bh(&ep->ex_lock); | 537 | spin_lock_bh(&ep->ex_lock); |
550 | 538 | ||
551 | mp->exches[xid - mp->min_xid] = ep; | 539 | fc_exch_ptr_set(pool, index, ep); |
552 | list_add_tail(&ep->ex_list, &mp->ex_list); | 540 | list_add_tail(&ep->ex_list, &pool->ex_list); |
553 | fc_seq_alloc(ep, ep->seq_id++); | 541 | fc_seq_alloc(ep, ep->seq_id++); |
554 | mp->total_exches++; | 542 | pool->total_exches++; |
555 | spin_unlock_bh(&mp->em_lock); | 543 | spin_unlock_bh(&pool->lock); |
556 | 544 | ||
557 | /* | 545 | /* |
558 | * update exchange | 546 | * update exchange |
559 | */ | 547 | */ |
560 | ep->oxid = ep->xid = xid; | 548 | ep->oxid = ep->xid = (index << fc_cpu_order | cpu) + mp->min_xid; |
561 | ep->em = mp; | 549 | ep->em = mp; |
562 | ep->lp = mp->lp; | 550 | ep->pool = pool; |
551 | ep->lp = lport; | ||
563 | ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ | 552 | ep->f_ctl = FC_FC_FIRST_SEQ; /* next seq is first seq */ |
564 | ep->rxid = FC_XID_UNKNOWN; | 553 | ep->rxid = FC_XID_UNKNOWN; |
565 | ep->class = mp->class; | 554 | ep->class = mp->class; |
@@ -567,11 +556,36 @@ struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp, | |||
567 | out: | 556 | out: |
568 | return ep; | 557 | return ep; |
569 | err: | 558 | err: |
570 | spin_unlock_bh(&mp->em_lock); | 559 | spin_unlock_bh(&pool->lock); |
571 | atomic_inc(&mp->stats.no_free_exch_xid); | 560 | atomic_inc(&mp->stats.no_free_exch_xid); |
572 | mempool_free(ep, mp->ep_pool); | 561 | mempool_free(ep, mp->ep_pool); |
573 | return NULL; | 562 | return NULL; |
574 | } | 563 | } |
564 | |||
565 | /** | ||
566 | * fc_exch_alloc() - allocate an exchange. | ||
567 | * @lport: ptr to the local port | ||
568 | * @fp: ptr to the FC frame | ||
569 | * | ||
570 | * This function walks the list of the exchange manager(EM) | ||
571 | * anchors to select a EM for new exchange allocation. The | ||
572 | * EM is selected having either a NULL match function pointer | ||
573 | * or call to match function returning true. | ||
574 | */ | ||
575 | struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp) | ||
576 | { | ||
577 | struct fc_exch_mgr_anchor *ema; | ||
578 | struct fc_exch *ep; | ||
579 | |||
580 | list_for_each_entry(ema, &lport->ema_list, ema_list) { | ||
581 | if (!ema->match || ema->match(fp)) { | ||
582 | ep = fc_exch_em_alloc(lport, ema->mp); | ||
583 | if (ep) | ||
584 | return ep; | ||
585 | } | ||
586 | } | ||
587 | return NULL; | ||
588 | } | ||
575 | EXPORT_SYMBOL(fc_exch_alloc); | 589 | EXPORT_SYMBOL(fc_exch_alloc); |
576 | 590 | ||
577 | /* | 591 | /* |
@@ -579,16 +593,18 @@ EXPORT_SYMBOL(fc_exch_alloc); | |||
579 | */ | 593 | */ |
580 | static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) | 594 | static struct fc_exch *fc_exch_find(struct fc_exch_mgr *mp, u16 xid) |
581 | { | 595 | { |
596 | struct fc_exch_pool *pool; | ||
582 | struct fc_exch *ep = NULL; | 597 | struct fc_exch *ep = NULL; |
583 | 598 | ||
584 | if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { | 599 | if ((xid >= mp->min_xid) && (xid <= mp->max_xid)) { |
585 | spin_lock_bh(&mp->em_lock); | 600 | pool = per_cpu_ptr(mp->pool, xid & fc_cpu_mask); |
586 | ep = mp->exches[xid - mp->min_xid]; | 601 | spin_lock_bh(&pool->lock); |
602 | ep = fc_exch_ptr_get(pool, (xid - mp->min_xid) >> fc_cpu_order); | ||
587 | if (ep) { | 603 | if (ep) { |
588 | fc_exch_hold(ep); | 604 | fc_exch_hold(ep); |
589 | WARN_ON(ep->xid != xid); | 605 | WARN_ON(ep->xid != xid); |
590 | } | 606 | } |
591 | spin_unlock_bh(&mp->em_lock); | 607 | spin_unlock_bh(&pool->lock); |
592 | } | 608 | } |
593 | return ep; | 609 | return ep; |
594 | } | 610 | } |
@@ -602,7 +618,7 @@ void fc_exch_done(struct fc_seq *sp) | |||
602 | rc = fc_exch_done_locked(ep); | 618 | rc = fc_exch_done_locked(ep); |
603 | spin_unlock_bh(&ep->ex_lock); | 619 | spin_unlock_bh(&ep->ex_lock); |
604 | if (!rc) | 620 | if (!rc) |
605 | fc_exch_mgr_delete_ep(ep); | 621 | fc_exch_delete(ep); |
606 | } | 622 | } |
607 | EXPORT_SYMBOL(fc_exch_done); | 623 | EXPORT_SYMBOL(fc_exch_done); |
608 | 624 | ||
@@ -610,12 +626,14 @@ EXPORT_SYMBOL(fc_exch_done); | |||
610 | * Allocate a new exchange as responder. | 626 | * Allocate a new exchange as responder. |
611 | * Sets the responder ID in the frame header. | 627 | * Sets the responder ID in the frame header. |
612 | */ | 628 | */ |
613 | static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | 629 | static struct fc_exch *fc_exch_resp(struct fc_lport *lport, |
630 | struct fc_exch_mgr *mp, | ||
631 | struct fc_frame *fp) | ||
614 | { | 632 | { |
615 | struct fc_exch *ep; | 633 | struct fc_exch *ep; |
616 | struct fc_frame_header *fh; | 634 | struct fc_frame_header *fh; |
617 | 635 | ||
618 | ep = mp->lp->tt.exch_get(mp->lp, fp); | 636 | ep = fc_exch_alloc(lport, fp); |
619 | if (ep) { | 637 | if (ep) { |
620 | ep->class = fc_frame_class(fp); | 638 | ep->class = fc_frame_class(fp); |
621 | 639 | ||
@@ -641,7 +659,7 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
641 | ep->esb_stat &= ~ESB_ST_SEQ_INIT; | 659 | ep->esb_stat &= ~ESB_ST_SEQ_INIT; |
642 | 660 | ||
643 | fc_exch_hold(ep); /* hold for caller */ | 661 | fc_exch_hold(ep); /* hold for caller */ |
644 | spin_unlock_bh(&ep->ex_lock); /* lock from exch_get */ | 662 | spin_unlock_bh(&ep->ex_lock); /* lock from fc_exch_alloc */ |
645 | } | 663 | } |
646 | return ep; | 664 | return ep; |
647 | } | 665 | } |
@@ -651,7 +669,8 @@ static struct fc_exch *fc_exch_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
651 | * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold | 669 | * If fc_pf_rjt_reason is FC_RJT_NONE then this function will have a hold |
652 | * on the ep that should be released by the caller. | 670 | * on the ep that should be released by the caller. |
653 | */ | 671 | */ |
654 | static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, | 672 | static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_lport *lport, |
673 | struct fc_exch_mgr *mp, | ||
655 | struct fc_frame *fp) | 674 | struct fc_frame *fp) |
656 | { | 675 | { |
657 | struct fc_frame_header *fh = fc_frame_header_get(fp); | 676 | struct fc_frame_header *fh = fc_frame_header_get(fp); |
@@ -705,7 +724,7 @@ static enum fc_pf_rjt_reason fc_seq_lookup_recip(struct fc_exch_mgr *mp, | |||
705 | reject = FC_RJT_RX_ID; | 724 | reject = FC_RJT_RX_ID; |
706 | goto rel; | 725 | goto rel; |
707 | } | 726 | } |
708 | ep = fc_exch_resp(mp, fp); | 727 | ep = fc_exch_resp(lport, mp, fp); |
709 | if (!ep) { | 728 | if (!ep) { |
710 | reject = FC_RJT_EXCH_EST; /* XXX */ | 729 | reject = FC_RJT_EXCH_EST; /* XXX */ |
711 | goto out; | 730 | goto out; |
@@ -822,7 +841,6 @@ struct fc_seq *fc_seq_start_next(struct fc_seq *sp) | |||
822 | struct fc_exch *ep = fc_seq_exch(sp); | 841 | struct fc_exch *ep = fc_seq_exch(sp); |
823 | 842 | ||
824 | spin_lock_bh(&ep->ex_lock); | 843 | spin_lock_bh(&ep->ex_lock); |
825 | WARN_ON((ep->esb_stat & ESB_ST_COMPLETE) != 0); | ||
826 | sp = fc_seq_start_next_locked(sp); | 844 | sp = fc_seq_start_next_locked(sp); |
827 | spin_unlock_bh(&ep->ex_lock); | 845 | spin_unlock_bh(&ep->ex_lock); |
828 | 846 | ||
@@ -999,8 +1017,8 @@ static void fc_exch_send_ba_rjt(struct fc_frame *rx_fp, | |||
999 | */ | 1017 | */ |
1000 | memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3); | 1018 | memcpy(fh->fh_s_id, rx_fh->fh_d_id, 3); |
1001 | memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3); | 1019 | memcpy(fh->fh_d_id, rx_fh->fh_s_id, 3); |
1002 | fh->fh_ox_id = rx_fh->fh_rx_id; | 1020 | fh->fh_ox_id = rx_fh->fh_ox_id; |
1003 | fh->fh_rx_id = rx_fh->fh_ox_id; | 1021 | fh->fh_rx_id = rx_fh->fh_rx_id; |
1004 | fh->fh_seq_cnt = rx_fh->fh_seq_cnt; | 1022 | fh->fh_seq_cnt = rx_fh->fh_seq_cnt; |
1005 | fh->fh_r_ctl = FC_RCTL_BA_RJT; | 1023 | fh->fh_r_ctl = FC_RCTL_BA_RJT; |
1006 | fh->fh_type = FC_TYPE_BLS; | 1024 | fh->fh_type = FC_TYPE_BLS; |
@@ -1097,7 +1115,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, | |||
1097 | enum fc_pf_rjt_reason reject; | 1115 | enum fc_pf_rjt_reason reject; |
1098 | 1116 | ||
1099 | fr_seq(fp) = NULL; | 1117 | fr_seq(fp) = NULL; |
1100 | reject = fc_seq_lookup_recip(mp, fp); | 1118 | reject = fc_seq_lookup_recip(lp, mp, fp); |
1101 | if (reject == FC_RJT_NONE) { | 1119 | if (reject == FC_RJT_NONE) { |
1102 | sp = fr_seq(fp); /* sequence will be held */ | 1120 | sp = fr_seq(fp); /* sequence will be held */ |
1103 | ep = fc_seq_exch(sp); | 1121 | ep = fc_seq_exch(sp); |
@@ -1123,7 +1141,7 @@ static void fc_exch_recv_req(struct fc_lport *lp, struct fc_exch_mgr *mp, | |||
1123 | lp->tt.lport_recv(lp, sp, fp); | 1141 | lp->tt.lport_recv(lp, sp, fp); |
1124 | fc_exch_release(ep); /* release from lookup */ | 1142 | fc_exch_release(ep); /* release from lookup */ |
1125 | } else { | 1143 | } else { |
1126 | FC_EM_DBG(mp, "exch/seq lookup failed: reject %x\n", reject); | 1144 | FC_LPORT_DBG(lp, "exch/seq lookup failed: reject %x\n", reject); |
1127 | fc_frame_free(fp); | 1145 | fc_frame_free(fp); |
1128 | } | 1146 | } |
1129 | } | 1147 | } |
@@ -1193,7 +1211,7 @@ static void fc_exch_recv_seq_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
1193 | WARN_ON(fc_seq_exch(sp) != ep); | 1211 | WARN_ON(fc_seq_exch(sp) != ep); |
1194 | spin_unlock_bh(&ep->ex_lock); | 1212 | spin_unlock_bh(&ep->ex_lock); |
1195 | if (!rc) | 1213 | if (!rc) |
1196 | fc_exch_mgr_delete_ep(ep); | 1214 | fc_exch_delete(ep); |
1197 | } | 1215 | } |
1198 | 1216 | ||
1199 | /* | 1217 | /* |
@@ -1229,13 +1247,12 @@ static void fc_exch_recv_resp(struct fc_exch_mgr *mp, struct fc_frame *fp) | |||
1229 | struct fc_seq *sp; | 1247 | struct fc_seq *sp; |
1230 | 1248 | ||
1231 | sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ | 1249 | sp = fc_seq_lookup_orig(mp, fp); /* doesn't hold sequence */ |
1232 | if (!sp) { | 1250 | |
1251 | if (!sp) | ||
1233 | atomic_inc(&mp->stats.xid_not_found); | 1252 | atomic_inc(&mp->stats.xid_not_found); |
1234 | FC_EM_DBG(mp, "seq lookup failed\n"); | 1253 | else |
1235 | } else { | ||
1236 | atomic_inc(&mp->stats.non_bls_resp); | 1254 | atomic_inc(&mp->stats.non_bls_resp); |
1237 | FC_EM_DBG(mp, "non-BLS response to sequence"); | 1255 | |
1238 | } | ||
1239 | fc_frame_free(fp); | 1256 | fc_frame_free(fp); |
1240 | } | 1257 | } |
1241 | 1258 | ||
@@ -1304,7 +1321,7 @@ static void fc_exch_abts_resp(struct fc_exch *ep, struct fc_frame *fp) | |||
1304 | rc = fc_exch_done_locked(ep); | 1321 | rc = fc_exch_done_locked(ep); |
1305 | spin_unlock_bh(&ep->ex_lock); | 1322 | spin_unlock_bh(&ep->ex_lock); |
1306 | if (!rc) | 1323 | if (!rc) |
1307 | fc_exch_mgr_delete_ep(ep); | 1324 | fc_exch_delete(ep); |
1308 | 1325 | ||
1309 | if (resp) | 1326 | if (resp) |
1310 | resp(sp, fp, ex_resp_arg); | 1327 | resp(sp, fp, ex_resp_arg); |
@@ -1447,44 +1464,77 @@ static void fc_exch_reset(struct fc_exch *ep) | |||
1447 | rc = fc_exch_done_locked(ep); | 1464 | rc = fc_exch_done_locked(ep); |
1448 | spin_unlock_bh(&ep->ex_lock); | 1465 | spin_unlock_bh(&ep->ex_lock); |
1449 | if (!rc) | 1466 | if (!rc) |
1450 | fc_exch_mgr_delete_ep(ep); | 1467 | fc_exch_delete(ep); |
1451 | 1468 | ||
1452 | if (resp) | 1469 | if (resp) |
1453 | resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); | 1470 | resp(sp, ERR_PTR(-FC_EX_CLOSED), arg); |
1454 | } | 1471 | } |
1455 | 1472 | ||
1456 | /* | 1473 | /** |
1457 | * Reset an exchange manager, releasing all sequences and exchanges. | 1474 | * fc_exch_pool_reset() - Resets an per cpu exches pool. |
1458 | * If sid is non-zero, reset only exchanges we source from that FID. | 1475 | * @lport: ptr to the local port |
1459 | * If did is non-zero, reset only exchanges destined to that FID. | 1476 | * @pool: ptr to the per cpu exches pool |
1477 | * @sid: source FC ID | ||
1478 | * @did: destination FC ID | ||
1479 | * | ||
1480 | * Resets an per cpu exches pool, releasing its all sequences | ||
1481 | * and exchanges. If sid is non-zero, then reset only exchanges | ||
1482 | * we sourced from that FID. If did is non-zero, reset only | ||
1483 | * exchanges destined to that FID. | ||
1460 | */ | 1484 | */ |
1461 | void fc_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) | 1485 | static void fc_exch_pool_reset(struct fc_lport *lport, |
1486 | struct fc_exch_pool *pool, | ||
1487 | u32 sid, u32 did) | ||
1462 | { | 1488 | { |
1463 | struct fc_exch *ep; | 1489 | struct fc_exch *ep; |
1464 | struct fc_exch *next; | 1490 | struct fc_exch *next; |
1465 | struct fc_exch_mgr *mp = lp->emp; | ||
1466 | 1491 | ||
1467 | spin_lock_bh(&mp->em_lock); | 1492 | spin_lock_bh(&pool->lock); |
1468 | restart: | 1493 | restart: |
1469 | list_for_each_entry_safe(ep, next, &mp->ex_list, ex_list) { | 1494 | list_for_each_entry_safe(ep, next, &pool->ex_list, ex_list) { |
1470 | if ((sid == 0 || sid == ep->sid) && | 1495 | if ((lport == ep->lp) && |
1496 | (sid == 0 || sid == ep->sid) && | ||
1471 | (did == 0 || did == ep->did)) { | 1497 | (did == 0 || did == ep->did)) { |
1472 | fc_exch_hold(ep); | 1498 | fc_exch_hold(ep); |
1473 | spin_unlock_bh(&mp->em_lock); | 1499 | spin_unlock_bh(&pool->lock); |
1474 | 1500 | ||
1475 | fc_exch_reset(ep); | 1501 | fc_exch_reset(ep); |
1476 | 1502 | ||
1477 | fc_exch_release(ep); | 1503 | fc_exch_release(ep); |
1478 | spin_lock_bh(&mp->em_lock); | 1504 | spin_lock_bh(&pool->lock); |
1479 | 1505 | ||
1480 | /* | 1506 | /* |
1481 | * must restart loop incase while lock was down | 1507 | * must restart loop incase while lock |
1482 | * multiple eps were released. | 1508 | * was down multiple eps were released. |
1483 | */ | 1509 | */ |
1484 | goto restart; | 1510 | goto restart; |
1485 | } | 1511 | } |
1486 | } | 1512 | } |
1487 | spin_unlock_bh(&mp->em_lock); | 1513 | spin_unlock_bh(&pool->lock); |
1514 | } | ||
1515 | |||
1516 | /** | ||
1517 | * fc_exch_mgr_reset() - Resets all EMs of a lport | ||
1518 | * @lport: ptr to the local port | ||
1519 | * @sid: source FC ID | ||
1520 | * @did: destination FC ID | ||
1521 | * | ||
1522 | * Reset all EMs of a lport, releasing its all sequences and | ||
1523 | * exchanges. If sid is non-zero, then reset only exchanges | ||
1524 | * we sourced from that FID. If did is non-zero, reset only | ||
1525 | * exchanges destined to that FID. | ||
1526 | */ | ||
1527 | void fc_exch_mgr_reset(struct fc_lport *lport, u32 sid, u32 did) | ||
1528 | { | ||
1529 | struct fc_exch_mgr_anchor *ema; | ||
1530 | unsigned int cpu; | ||
1531 | |||
1532 | list_for_each_entry(ema, &lport->ema_list, ema_list) { | ||
1533 | for_each_possible_cpu(cpu) | ||
1534 | fc_exch_pool_reset(lport, | ||
1535 | per_cpu_ptr(ema->mp->pool, cpu), | ||
1536 | sid, did); | ||
1537 | } | ||
1488 | } | 1538 | } |
1489 | EXPORT_SYMBOL(fc_exch_mgr_reset); | 1539 | EXPORT_SYMBOL(fc_exch_mgr_reset); |
1490 | 1540 | ||
@@ -1730,85 +1780,129 @@ reject: | |||
1730 | fc_frame_free(fp); | 1780 | fc_frame_free(fp); |
1731 | } | 1781 | } |
1732 | 1782 | ||
1783 | struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport, | ||
1784 | struct fc_exch_mgr *mp, | ||
1785 | bool (*match)(struct fc_frame *)) | ||
1786 | { | ||
1787 | struct fc_exch_mgr_anchor *ema; | ||
1788 | |||
1789 | ema = kmalloc(sizeof(*ema), GFP_ATOMIC); | ||
1790 | if (!ema) | ||
1791 | return ema; | ||
1792 | |||
1793 | ema->mp = mp; | ||
1794 | ema->match = match; | ||
1795 | /* add EM anchor to EM anchors list */ | ||
1796 | list_add_tail(&ema->ema_list, &lport->ema_list); | ||
1797 | kref_get(&mp->kref); | ||
1798 | return ema; | ||
1799 | } | ||
1800 | EXPORT_SYMBOL(fc_exch_mgr_add); | ||
1801 | |||
1802 | static void fc_exch_mgr_destroy(struct kref *kref) | ||
1803 | { | ||
1804 | struct fc_exch_mgr *mp = container_of(kref, struct fc_exch_mgr, kref); | ||
1805 | |||
1806 | mempool_destroy(mp->ep_pool); | ||
1807 | free_percpu(mp->pool); | ||
1808 | kfree(mp); | ||
1809 | } | ||
1810 | |||
1811 | void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema) | ||
1812 | { | ||
1813 | /* remove EM anchor from EM anchors list */ | ||
1814 | list_del(&ema->ema_list); | ||
1815 | kref_put(&ema->mp->kref, fc_exch_mgr_destroy); | ||
1816 | kfree(ema); | ||
1817 | } | ||
1818 | EXPORT_SYMBOL(fc_exch_mgr_del); | ||
1819 | |||
1733 | struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, | 1820 | struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp, |
1734 | enum fc_class class, | 1821 | enum fc_class class, |
1735 | u16 min_xid, u16 max_xid) | 1822 | u16 min_xid, u16 max_xid, |
1823 | bool (*match)(struct fc_frame *)) | ||
1736 | { | 1824 | { |
1737 | struct fc_exch_mgr *mp; | 1825 | struct fc_exch_mgr *mp; |
1738 | size_t len; | 1826 | u16 pool_exch_range; |
1827 | size_t pool_size; | ||
1828 | unsigned int cpu; | ||
1829 | struct fc_exch_pool *pool; | ||
1739 | 1830 | ||
1740 | if (max_xid <= min_xid || min_xid == 0 || max_xid == FC_XID_UNKNOWN) { | 1831 | if (max_xid <= min_xid || max_xid == FC_XID_UNKNOWN || |
1832 | (min_xid & fc_cpu_mask) != 0) { | ||
1741 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", | 1833 | FC_LPORT_DBG(lp, "Invalid min_xid 0x:%x and max_xid 0x:%x\n", |
1742 | min_xid, max_xid); | 1834 | min_xid, max_xid); |
1743 | return NULL; | 1835 | return NULL; |
1744 | } | 1836 | } |
1745 | 1837 | ||
1746 | /* | 1838 | /* |
1747 | * Memory need for EM | 1839 | * allocate memory for EM |
1748 | */ | 1840 | */ |
1749 | #define xid_ok(i, m1, m2) (((i) >= (m1)) && ((i) <= (m2))) | 1841 | mp = kzalloc(sizeof(struct fc_exch_mgr), GFP_ATOMIC); |
1750 | len = (max_xid - min_xid + 1) * (sizeof(struct fc_exch *)); | ||
1751 | len += sizeof(struct fc_exch_mgr); | ||
1752 | |||
1753 | mp = kzalloc(len, GFP_ATOMIC); | ||
1754 | if (!mp) | 1842 | if (!mp) |
1755 | return NULL; | 1843 | return NULL; |
1756 | 1844 | ||
1757 | mp->class = class; | 1845 | mp->class = class; |
1758 | mp->total_exches = 0; | ||
1759 | mp->exches = (struct fc_exch **)(mp + 1); | ||
1760 | mp->lp = lp; | ||
1761 | /* adjust em exch xid range for offload */ | 1846 | /* adjust em exch xid range for offload */ |
1762 | mp->min_xid = min_xid; | 1847 | mp->min_xid = min_xid; |
1763 | mp->max_xid = max_xid; | 1848 | mp->max_xid = max_xid; |
1764 | mp->last_xid = min_xid - 1; | ||
1765 | mp->max_read = 0; | ||
1766 | mp->last_read = 0; | ||
1767 | if (lp->lro_enabled && xid_ok(lp->lro_xid, min_xid, max_xid)) { | ||
1768 | mp->max_read = lp->lro_xid; | ||
1769 | mp->last_read = min_xid - 1; | ||
1770 | mp->last_xid = mp->max_read; | ||
1771 | } else { | ||
1772 | /* disable lro if no xid control over read */ | ||
1773 | lp->lro_enabled = 0; | ||
1774 | } | ||
1775 | |||
1776 | INIT_LIST_HEAD(&mp->ex_list); | ||
1777 | spin_lock_init(&mp->em_lock); | ||
1778 | 1849 | ||
1779 | mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); | 1850 | mp->ep_pool = mempool_create_slab_pool(2, fc_em_cachep); |
1780 | if (!mp->ep_pool) | 1851 | if (!mp->ep_pool) |
1781 | goto free_mp; | 1852 | goto free_mp; |
1782 | 1853 | ||
1854 | /* | ||
1855 | * Setup per cpu exch pool with entire exchange id range equally | ||
1856 | * divided across all cpus. The exch pointers array memory is | ||
1857 | * allocated for exch range per pool. | ||
1858 | */ | ||
1859 | pool_exch_range = (mp->max_xid - mp->min_xid + 1) / (fc_cpu_mask + 1); | ||
1860 | mp->pool_max_index = pool_exch_range - 1; | ||
1861 | |||
1862 | /* | ||
1863 | * Allocate and initialize per cpu exch pool | ||
1864 | */ | ||
1865 | pool_size = sizeof(*pool) + pool_exch_range * sizeof(struct fc_exch *); | ||
1866 | mp->pool = __alloc_percpu(pool_size, __alignof__(struct fc_exch_pool)); | ||
1867 | if (!mp->pool) | ||
1868 | goto free_mempool; | ||
1869 | for_each_possible_cpu(cpu) { | ||
1870 | pool = per_cpu_ptr(mp->pool, cpu); | ||
1871 | spin_lock_init(&pool->lock); | ||
1872 | INIT_LIST_HEAD(&pool->ex_list); | ||
1873 | } | ||
1874 | |||
1875 | kref_init(&mp->kref); | ||
1876 | if (!fc_exch_mgr_add(lp, mp, match)) { | ||
1877 | free_percpu(mp->pool); | ||
1878 | goto free_mempool; | ||
1879 | } | ||
1880 | |||
1881 | /* | ||
1882 | * Above kref_init() sets mp->kref to 1 and then | ||
1883 | * call to fc_exch_mgr_add incremented mp->kref again, | ||
1884 | * so adjust that extra increment. | ||
1885 | */ | ||
1886 | kref_put(&mp->kref, fc_exch_mgr_destroy); | ||
1783 | return mp; | 1887 | return mp; |
1784 | 1888 | ||
1889 | free_mempool: | ||
1890 | mempool_destroy(mp->ep_pool); | ||
1785 | free_mp: | 1891 | free_mp: |
1786 | kfree(mp); | 1892 | kfree(mp); |
1787 | return NULL; | 1893 | return NULL; |
1788 | } | 1894 | } |
1789 | EXPORT_SYMBOL(fc_exch_mgr_alloc); | 1895 | EXPORT_SYMBOL(fc_exch_mgr_alloc); |
1790 | 1896 | ||
1791 | void fc_exch_mgr_free(struct fc_exch_mgr *mp) | 1897 | void fc_exch_mgr_free(struct fc_lport *lport) |
1792 | { | 1898 | { |
1793 | WARN_ON(!mp); | 1899 | struct fc_exch_mgr_anchor *ema, *next; |
1794 | /* | 1900 | |
1795 | * The total exch count must be zero | 1901 | list_for_each_entry_safe(ema, next, &lport->ema_list, ema_list) |
1796 | * before freeing exchange manager. | 1902 | fc_exch_mgr_del(ema); |
1797 | */ | ||
1798 | WARN_ON(mp->total_exches != 0); | ||
1799 | mempool_destroy(mp->ep_pool); | ||
1800 | kfree(mp); | ||
1801 | } | 1903 | } |
1802 | EXPORT_SYMBOL(fc_exch_mgr_free); | 1904 | EXPORT_SYMBOL(fc_exch_mgr_free); |
1803 | 1905 | ||
1804 | struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp) | ||
1805 | { | ||
1806 | if (!lp || !lp->emp) | ||
1807 | return NULL; | ||
1808 | |||
1809 | return fc_exch_alloc(lp->emp, fp, 0); | ||
1810 | } | ||
1811 | EXPORT_SYMBOL(fc_exch_get); | ||
1812 | 1906 | ||
1813 | struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | 1907 | struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, |
1814 | struct fc_frame *fp, | 1908 | struct fc_frame *fp, |
@@ -1823,7 +1917,7 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | |||
1823 | struct fc_frame_header *fh; | 1917 | struct fc_frame_header *fh; |
1824 | int rc = 1; | 1918 | int rc = 1; |
1825 | 1919 | ||
1826 | ep = lp->tt.exch_get(lp, fp); | 1920 | ep = fc_exch_alloc(lp, fp); |
1827 | if (!ep) { | 1921 | if (!ep) { |
1828 | fc_frame_free(fp); | 1922 | fc_frame_free(fp); |
1829 | return NULL; | 1923 | return NULL; |
@@ -1843,7 +1937,8 @@ struct fc_seq *fc_exch_seq_send(struct fc_lport *lp, | |||
1843 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); | 1937 | fc_exch_setup_hdr(ep, fp, ep->f_ctl); |
1844 | sp->cnt++; | 1938 | sp->cnt++; |
1845 | 1939 | ||
1846 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | 1940 | if (ep->xid <= lp->lro_xid) |
1941 | fc_fcp_ddp_setup(fr_fsp(fp), ep->xid); | ||
1847 | 1942 | ||
1848 | if (unlikely(lp->tt.frame_send(lp, fp))) | 1943 | if (unlikely(lp->tt.frame_send(lp, fp))) |
1849 | goto err; | 1944 | goto err; |
@@ -1860,7 +1955,7 @@ err: | |||
1860 | rc = fc_exch_done_locked(ep); | 1955 | rc = fc_exch_done_locked(ep); |
1861 | spin_unlock_bh(&ep->ex_lock); | 1956 | spin_unlock_bh(&ep->ex_lock); |
1862 | if (!rc) | 1957 | if (!rc) |
1863 | fc_exch_mgr_delete_ep(ep); | 1958 | fc_exch_delete(ep); |
1864 | return NULL; | 1959 | return NULL; |
1865 | } | 1960 | } |
1866 | EXPORT_SYMBOL(fc_exch_seq_send); | 1961 | EXPORT_SYMBOL(fc_exch_seq_send); |
@@ -1868,24 +1963,44 @@ EXPORT_SYMBOL(fc_exch_seq_send); | |||
1868 | /* | 1963 | /* |
1869 | * Receive a frame | 1964 | * Receive a frame |
1870 | */ | 1965 | */ |
1871 | void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, | 1966 | void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp) |
1872 | struct fc_frame *fp) | ||
1873 | { | 1967 | { |
1874 | struct fc_frame_header *fh = fc_frame_header_get(fp); | 1968 | struct fc_frame_header *fh = fc_frame_header_get(fp); |
1875 | u32 f_ctl; | 1969 | struct fc_exch_mgr_anchor *ema; |
1970 | u32 f_ctl, found = 0; | ||
1971 | u16 oxid; | ||
1876 | 1972 | ||
1877 | /* lport lock ? */ | 1973 | /* lport lock ? */ |
1878 | if (!lp || !mp || (lp->state == LPORT_ST_NONE)) { | 1974 | if (!lp || lp->state == LPORT_ST_DISABLED) { |
1879 | FC_LPORT_DBG(lp, "Receiving frames for an lport that " | 1975 | FC_LPORT_DBG(lp, "Receiving frames for an lport that " |
1880 | "has not been initialized correctly\n"); | 1976 | "has not been initialized correctly\n"); |
1881 | fc_frame_free(fp); | 1977 | fc_frame_free(fp); |
1882 | return; | 1978 | return; |
1883 | } | 1979 | } |
1884 | 1980 | ||
1981 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
1982 | oxid = ntohs(fh->fh_ox_id); | ||
1983 | if (f_ctl & FC_FC_EX_CTX) { | ||
1984 | list_for_each_entry(ema, &lp->ema_list, ema_list) { | ||
1985 | if ((oxid >= ema->mp->min_xid) && | ||
1986 | (oxid <= ema->mp->max_xid)) { | ||
1987 | found = 1; | ||
1988 | break; | ||
1989 | } | ||
1990 | } | ||
1991 | |||
1992 | if (!found) { | ||
1993 | FC_LPORT_DBG(lp, "Received response for out " | ||
1994 | "of range oxid:%hx\n", oxid); | ||
1995 | fc_frame_free(fp); | ||
1996 | return; | ||
1997 | } | ||
1998 | } else | ||
1999 | ema = list_entry(lp->ema_list.prev, typeof(*ema), ema_list); | ||
2000 | |||
1885 | /* | 2001 | /* |
1886 | * If frame is marked invalid, just drop it. | 2002 | * If frame is marked invalid, just drop it. |
1887 | */ | 2003 | */ |
1888 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
1889 | switch (fr_eof(fp)) { | 2004 | switch (fr_eof(fp)) { |
1890 | case FC_EOF_T: | 2005 | case FC_EOF_T: |
1891 | if (f_ctl & FC_FC_END_SEQ) | 2006 | if (f_ctl & FC_FC_END_SEQ) |
@@ -1893,34 +2008,24 @@ void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp, | |||
1893 | /* fall through */ | 2008 | /* fall through */ |
1894 | case FC_EOF_N: | 2009 | case FC_EOF_N: |
1895 | if (fh->fh_type == FC_TYPE_BLS) | 2010 | if (fh->fh_type == FC_TYPE_BLS) |
1896 | fc_exch_recv_bls(mp, fp); | 2011 | fc_exch_recv_bls(ema->mp, fp); |
1897 | else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == | 2012 | else if ((f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == |
1898 | FC_FC_EX_CTX) | 2013 | FC_FC_EX_CTX) |
1899 | fc_exch_recv_seq_resp(mp, fp); | 2014 | fc_exch_recv_seq_resp(ema->mp, fp); |
1900 | else if (f_ctl & FC_FC_SEQ_CTX) | 2015 | else if (f_ctl & FC_FC_SEQ_CTX) |
1901 | fc_exch_recv_resp(mp, fp); | 2016 | fc_exch_recv_resp(ema->mp, fp); |
1902 | else | 2017 | else |
1903 | fc_exch_recv_req(lp, mp, fp); | 2018 | fc_exch_recv_req(lp, ema->mp, fp); |
1904 | break; | 2019 | break; |
1905 | default: | 2020 | default: |
1906 | FC_EM_DBG(mp, "dropping invalid frame (eof %x)", fr_eof(fp)); | 2021 | FC_LPORT_DBG(lp, "dropping invalid frame (eof %x)", fr_eof(fp)); |
1907 | fc_frame_free(fp); | 2022 | fc_frame_free(fp); |
1908 | break; | ||
1909 | } | 2023 | } |
1910 | } | 2024 | } |
1911 | EXPORT_SYMBOL(fc_exch_recv); | 2025 | EXPORT_SYMBOL(fc_exch_recv); |
1912 | 2026 | ||
1913 | int fc_exch_init(struct fc_lport *lp) | 2027 | int fc_exch_init(struct fc_lport *lp) |
1914 | { | 2028 | { |
1915 | if (!lp->tt.exch_get) { | ||
1916 | /* | ||
1917 | * exch_put() should be NULL if | ||
1918 | * exch_get() is NULL | ||
1919 | */ | ||
1920 | WARN_ON(lp->tt.exch_put); | ||
1921 | lp->tt.exch_get = fc_exch_get; | ||
1922 | } | ||
1923 | |||
1924 | if (!lp->tt.seq_start_next) | 2029 | if (!lp->tt.seq_start_next) |
1925 | lp->tt.seq_start_next = fc_seq_start_next; | 2030 | lp->tt.seq_start_next = fc_seq_start_next; |
1926 | 2031 | ||
@@ -1942,6 +2047,28 @@ int fc_exch_init(struct fc_lport *lp) | |||
1942 | if (!lp->tt.seq_exch_abort) | 2047 | if (!lp->tt.seq_exch_abort) |
1943 | lp->tt.seq_exch_abort = fc_seq_exch_abort; | 2048 | lp->tt.seq_exch_abort = fc_seq_exch_abort; |
1944 | 2049 | ||
2050 | /* | ||
2051 | * Initialize fc_cpu_mask and fc_cpu_order. The | ||
2052 | * fc_cpu_mask is set for nr_cpu_ids rounded up | ||
2053 | * to order of 2's * power and order is stored | ||
2054 | * in fc_cpu_order as this is later required in | ||
2055 | * mapping between an exch id and exch array index | ||
2056 | * in per cpu exch pool. | ||
2057 | * | ||
2058 | * This round up is required to align fc_cpu_mask | ||
2059 | * to exchange id's lower bits such that all incoming | ||
2060 | * frames of an exchange gets delivered to the same | ||
2061 | * cpu on which exchange originated by simple bitwise | ||
2062 | * AND operation between fc_cpu_mask and exchange id. | ||
2063 | */ | ||
2064 | fc_cpu_mask = 1; | ||
2065 | fc_cpu_order = 0; | ||
2066 | while (fc_cpu_mask < nr_cpu_ids) { | ||
2067 | fc_cpu_mask <<= 1; | ||
2068 | fc_cpu_order++; | ||
2069 | } | ||
2070 | fc_cpu_mask--; | ||
2071 | |||
1945 | return 0; | 2072 | return 0; |
1946 | } | 2073 | } |
1947 | EXPORT_SYMBOL(fc_exch_init); | 2074 | EXPORT_SYMBOL(fc_exch_init); |