diff options
Diffstat (limited to 'drivers/scsi/fcoe/fcoe.c')
-rw-r--r-- | drivers/scsi/fcoe/fcoe.c | 67 |
1 files changed, 65 insertions, 2 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 | } |