diff options
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 67 | ||||
-rw-r--r-- | drivers/scsi/fcoe/fcoe.h | 3 | ||||
-rw-r--r-- | drivers/scsi/libfc/fc_exch.c | 94 |
3 files changed, 85 insertions, 79 deletions
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c index 86410b9a30c3..0306aa95eb34 100644 --- a/drivers/scsi/fcoe/fcoe.c +++ b/drivers/scsi/fcoe/fcoe.c | |||
@@ -415,6 +415,17 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, | |||
415 | return 0; | 415 | return 0; |
416 | } | 416 | } |
417 | 417 | ||
418 | /* | ||
419 | * fcoe_oem_match() - match for read types IO | ||
420 | * @fp: the fc_frame for new IO. | ||
421 | * | ||
422 | * Returns : true for read types IO, otherwise returns false. | ||
423 | */ | ||
424 | bool fcoe_oem_match(struct fc_frame *fp) | ||
425 | { | ||
426 | return fc_fcp_is_read(fr_fsp(fp)); | ||
427 | } | ||
428 | |||
418 | /** | 429 | /** |
419 | * fcoe_em_config() - allocates em for this lport | 430 | * fcoe_em_config() - allocates em for this lport |
420 | * @lp: the port that em is to allocated for | 431 | * @lp: the port that em is to allocated for |
@@ -425,9 +436,61 @@ static int fcoe_shost_config(struct fc_lport *lp, struct Scsi_Host *shost, | |||
425 | */ | 436 | */ |
426 | static inline int fcoe_em_config(struct fc_lport *lp) | 437 | static inline int fcoe_em_config(struct fc_lport *lp) |
427 | { | 438 | { |
428 | if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCOE_MIN_XID, | 439 | struct fcoe_softc *fc = lport_priv(lp); |
429 | FCOE_MAX_XID, NULL)) | 440 | struct fcoe_softc *oldfc = NULL; |
441 | u16 min_xid = FCOE_MIN_XID; | ||
442 | u16 max_xid = FCOE_MAX_XID; | ||
443 | |||
444 | /* | ||
445 | * Check if need to allocate an em instance for | ||
446 | * offload exchange ids to be shared across all VN_PORTs/lport. | ||
447 | */ | ||
448 | if (!lp->lro_enabled || !lp->lro_xid || (lp->lro_xid >= max_xid)) { | ||
449 | lp->lro_xid = 0; | ||
450 | goto skip_oem; | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Reuse existing offload em instance in case | ||
455 | * it is already allocated on phys_dev. | ||
456 | */ | ||
457 | list_for_each_entry(oldfc, &fcoe_hostlist, list) { | ||
458 | if (oldfc->phys_dev == fc->phys_dev) { | ||
459 | fc->oem = oldfc->oem; | ||
460 | break; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | if (fc->oem) { | ||
465 | if (!fc_exch_mgr_add(lp, fc->oem, fcoe_oem_match)) { | ||
466 | printk(KERN_ERR "fcoe_em_config: failed to add " | ||
467 | "offload em:%p on interface:%s\n", | ||
468 | fc->oem, fc->real_dev->name); | ||
469 | return -ENOMEM; | ||
470 | } | ||
471 | } else { | ||
472 | fc->oem = fc_exch_mgr_alloc(lp, FC_CLASS_3, | ||
473 | FCOE_MIN_XID, lp->lro_xid, | ||
474 | fcoe_oem_match); | ||
475 | if (!fc->oem) { | ||
476 | printk(KERN_ERR "fcoe_em_config: failed to allocate " | ||
477 | "em for offload exches on interface:%s\n", | ||
478 | fc->real_dev->name); | ||
479 | return -ENOMEM; | ||
480 | } | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * Exclude offload EM xid range from next EM xid range. | ||
485 | */ | ||
486 | min_xid += lp->lro_xid + 1; | ||
487 | |||
488 | skip_oem: | ||
489 | if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, min_xid, max_xid, NULL)) { | ||
490 | printk(KERN_ERR "fcoe_em_config: failed to " | ||
491 | "allocate em on interface %s\n", fc->real_dev->name); | ||
430 | return -ENOMEM; | 492 | return -ENOMEM; |
493 | } | ||
431 | 494 | ||
432 | return 0; | 495 | return 0; |
433 | } | 496 | } |
diff --git a/drivers/scsi/fcoe/fcoe.h b/drivers/scsi/fcoe/fcoe.h index 0d724fa0898f..6905efc166bf 100644 --- a/drivers/scsi/fcoe/fcoe.h +++ b/drivers/scsi/fcoe/fcoe.h | |||
@@ -37,7 +37,7 @@ | |||
37 | 37 | ||
38 | #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 | 38 | #define FCOE_MAX_OUTSTANDING_COMMANDS 1024 |
39 | 39 | ||
40 | #define FCOE_MIN_XID 0x0001 /* the min xid supported by fcoe_sw */ | 40 | #define FCOE_MIN_XID 0x0000 /* the min xid supported by fcoe_sw */ |
41 | #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ | 41 | #define FCOE_MAX_XID 0x07ef /* the max xid supported by fcoe_sw */ |
42 | 42 | ||
43 | unsigned int fcoe_debug_logging; | 43 | unsigned int fcoe_debug_logging; |
@@ -81,6 +81,7 @@ struct fcoe_softc { | |||
81 | struct list_head list; | 81 | struct list_head list; |
82 | struct net_device *real_dev; | 82 | struct net_device *real_dev; |
83 | struct net_device *phys_dev; /* device with ethtool_ops */ | 83 | struct net_device *phys_dev; /* device with ethtool_ops */ |
84 | struct fc_exch_mgr *oem; /* offload exchange manger */ | ||
84 | struct packet_type fcoe_packet_type; | 85 | struct packet_type fcoe_packet_type; |
85 | struct packet_type fip_packet_type; | 86 | struct packet_type fip_packet_type; |
86 | struct sk_buff_head fcoe_pending_queue; | 87 | struct sk_buff_head fcoe_pending_queue; |
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; |