[SCSI] libfc: rename rport event CREATED to READY
[linux-2.6.git] / include / scsi / libfc.h
index 9f28763..d324df8 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <linux/timer.h>
 #include <linux/if.h>
+#include <linux/percpu.h>
 
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_fc.h>
 
 #include <scsi/fc_frame.h>
 
-#define LIBFC_DEBUG
-
-#ifdef LIBFC_DEBUG
-/* Log messages */
-#define FC_DBG(fmt, args...)                                           \
-       do {                                                            \
-               printk(KERN_INFO "%s " fmt, __func__, ##args);          \
-       } while (0)
-#else
-#define FC_DBG(fmt, args...)
-#endif
+#define FC_LIBFC_LOGGING 0x01 /* General logging, not categorized */
+#define FC_LPORT_LOGGING 0x02 /* lport layer logging */
+#define FC_DISC_LOGGING  0x04 /* discovery layer logging */
+#define FC_RPORT_LOGGING 0x08 /* rport layer logging */
+#define FC_FCP_LOGGING   0x10 /* I/O path logging */
+#define FC_EM_LOGGING    0x20 /* Exchange Manager logging */
+#define FC_EXCH_LOGGING  0x40 /* Exchange/Sequence logging */
+#define FC_SCSI_LOGGING  0x80 /* SCSI logging (mostly error handling) */
+
+extern unsigned int fc_debug_logging;
+
+#define FC_CHECK_LOGGING(LEVEL, CMD)                           \
+do {                                                           \
+       if (unlikely(fc_debug_logging & LEVEL))                 \
+               do {                                            \
+                       CMD;                                    \
+               } while (0);                                    \
+} while (0)
+
+#define FC_LIBFC_DBG(fmt, args...)                                     \
+       FC_CHECK_LOGGING(FC_LIBFC_LOGGING,                              \
+                        printk(KERN_INFO "libfc: " fmt, ##args))
+
+#define FC_LPORT_DBG(lport, fmt, args...)                              \
+       FC_CHECK_LOGGING(FC_LPORT_LOGGING,                              \
+                        printk(KERN_INFO "host%u: lport %6x: " fmt,    \
+                               (lport)->host->host_no,                 \
+                               fc_host_port_id((lport)->host), ##args))
+
+#define FC_DISC_DBG(disc, fmt, args...)                                        \
+       FC_CHECK_LOGGING(FC_DISC_LOGGING,                               \
+                        printk(KERN_INFO "host%u: disc: " fmt,         \
+                               (disc)->lport->host->host_no,           \
+                               ##args))
+
+#define FC_RPORT_ID_DBG(lport, port_id, fmt, args...)                  \
+       FC_CHECK_LOGGING(FC_RPORT_LOGGING,                              \
+                        printk(KERN_INFO "host%u: rport %6x: " fmt,    \
+                               (lport)->host->host_no,                 \
+                               (port_id), ##args))
+
+#define FC_RPORT_DBG(rdata, fmt, args...)                              \
+       FC_RPORT_ID_DBG((rdata)->local_port, (rdata)->ids.port_id, fmt, ##args)
+
+#define FC_FCP_DBG(pkt, fmt, args...)                                  \
+       FC_CHECK_LOGGING(FC_FCP_LOGGING,                                \
+                        printk(KERN_INFO "host%u: fcp: %6x: " fmt,     \
+                               (pkt)->lp->host->host_no,               \
+                               pkt->rport->port_id, ##args))
+
+#define FC_EXCH_DBG(exch, fmt, args...)                                        \
+       FC_CHECK_LOGGING(FC_EXCH_LOGGING,                               \
+                        printk(KERN_INFO "host%u: xid %4x: " fmt,      \
+                               (exch)->lp->host->host_no,              \
+                               exch->xid, ##args))
+
+#define FC_SCSI_DBG(lport, fmt, args...)                               \
+       FC_CHECK_LOGGING(FC_SCSI_LOGGING,                               \
+                        printk(KERN_INFO "host%u: scsi: " fmt,         \
+                               (lport)->host->host_no, ##args))
 
 /*
  * libfc error codes
 /*
  * FC HBA status
  */
-#define FC_PAUSE                   (1 << 1)
-#define FC_LINK_UP                 (1 << 0)
-
 enum fc_lport_state {
-       LPORT_ST_NONE = 0,
+       LPORT_ST_DISABLED = 0,
        LPORT_ST_FLOGI,
        LPORT_ST_DNS,
        LPORT_ST_RPN_ID,
@@ -90,13 +137,13 @@ enum fc_disc_event {
 };
 
 enum fc_rport_state {
-       RPORT_ST_NONE = 0,
        RPORT_ST_INIT,          /* initialized */
        RPORT_ST_PLOGI,         /* waiting for PLOGI completion */
        RPORT_ST_PRLI,          /* waiting for PRLI completion */
        RPORT_ST_RTV,           /* waiting for RTV completion */
        RPORT_ST_READY,         /* ready for use */
        RPORT_ST_LOGO,          /* port logout sent */
+       RPORT_ST_DELETE,        /* port being deleted */
 };
 
 enum fc_rport_trans_state {
@@ -120,23 +167,37 @@ struct fc_disc_port {
 
 enum fc_rport_event {
        RPORT_EV_NONE = 0,
-       RPORT_EV_CREATED,
+       RPORT_EV_READY,
        RPORT_EV_FAILED,
        RPORT_EV_STOP,
        RPORT_EV_LOGO
 };
 
+/*
+ * Temporary definition to prepare for split off from fc_rport_libfc_priv
+ * of a separately-allocated structure called fc_rport_priv.  This will
+ * be the primary object for the discovery and rport state machines.
+ * This definition is just to make this patch series easier to review.
+ */
+#define fc_rport_priv fc_rport_libfc_priv
+
+struct fc_rport_priv;
+
 struct fc_rport_operations {
-       void (*event_callback)(struct fc_lport *, struct fc_rport *,
+       void (*event_callback)(struct fc_lport *, struct fc_rport_priv *,
                               enum fc_rport_event);
 };
 
 /**
  * struct fc_rport_libfc_priv - libfc internal information about a remote port
  * @local_port: Fibre Channel host port instance
+ * @rport: transport remote port
+ * @kref: reference counter
  * @rp_state: state tracks progress of PLOGI, PRLI, and RTV exchanges
+ * @ids: remote port identifiers and roles
  * @flags: REC and RETRY supported flags
  * @max_seq: maximum number of concurrent sequences
+ * @maxframe_size: maximum frame size
  * @retries: retry count in current state
  * @e_d_tov: error detect timeout value (in msec)
  * @r_a_tov: resource allocation timeout value (in msec)
@@ -146,11 +207,15 @@ struct fc_rport_operations {
  */
 struct fc_rport_libfc_priv {
        struct fc_lport            *local_port;
+       struct fc_rport            *rport;
+       struct kref                kref;
        enum fc_rport_state        rp_state;
+       struct fc_rport_identifiers ids;
        u16                        flags;
        #define FC_RP_FLAGS_REC_SUPPORTED       (1 << 0)
        #define FC_RP_FLAGS_RETRY               (1 << 1)
        u16                        max_seq;
+       u16                        maxframe_size;
        unsigned int               retries;
        unsigned int               e_d_tov;
        unsigned int               r_a_tov;
@@ -161,20 +226,11 @@ struct fc_rport_libfc_priv {
        struct fc_rport_operations *ops;
        struct list_head           peers;
        struct work_struct         event_work;
+       u32                        supported_classes;
 };
 
-#define PRIV_TO_RPORT(x)                                               \
-       (struct fc_rport *)((void *)x - sizeof(struct fc_rport));
 #define RPORT_TO_PRIV(x)                                               \
-       (struct fc_rport_libfc_priv *)((void *)x + sizeof(struct fc_rport));
-
-struct fc_rport *fc_rport_rogue_create(struct fc_disc_port *);
-
-static inline void fc_rport_set_name(struct fc_rport *rport, u64 wwpn, u64 wwnn)
-{
-       rport->node_name = wwnn;
-       rport->port_name = wwpn;
-}
+       ((struct fc_rport_libfc_priv *)((void *)(x) + sizeof(struct fc_rport)))
 
 /*
  * fcoe stats structure
@@ -248,6 +304,7 @@ struct fc_fcp_pkt {
         */
        struct fcp_cmnd cdb_cmd;
        size_t          xfer_len;
+       u16             xfer_ddp;       /* this xfer is ddped */
        u32             xfer_contig_end; /* offset of end of contiguous xfer */
        u16             max_payload;    /* max payload size in bytes */
 
@@ -270,6 +327,15 @@ struct fc_fcp_pkt {
        u8              recov_retry;    /* count of recovery retries */
        struct fc_seq   *recov_seq;     /* sequence for REC or SRR */
 };
+/*
+ * FC_FCP HELPER FUNCTIONS
+ *****************************/
+static inline bool fc_fcp_is_read(const struct fc_fcp_pkt *fsp)
+{
+       if (fsp && fsp->cmd)
+               return fsp->cmd->sc_data_direction == DMA_FROM_DEVICE;
+       return false;
+}
 
 /*
  * Structure and function definitions for managing Fibre Channel Exchanges
@@ -281,6 +347,8 @@ struct fc_fcp_pkt {
  */
 
 struct fc_exch_mgr;
+struct fc_exch_mgr_anchor;
+extern u16     fc_cpu_mask;    /* cpu mask for possible cpus */
 
 /*
  * Sequence.
@@ -305,6 +373,7 @@ struct fc_seq {
  */
 struct fc_exch {
        struct fc_exch_mgr *em;         /* exchange manager */
+       struct fc_exch_pool *pool;      /* per cpu exches pool */
        u32             state;          /* internal driver state */
        u16             xid;            /* our exchange ID */
        struct list_head        ex_list;        /* free or busy list linkage */
@@ -339,43 +408,26 @@ struct fc_exch {
 
 struct libfc_function_template {
 
-       /**
-        * Mandatory Fields
-        *
-        * These handlers must be implemented by the LLD.
-        */
-
        /*
         * Interface to send a FC frame
-        */
-       int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp);
-
-       /**
-        * Optional Fields
         *
-        * The LLD may choose to implement any of the following handlers.
-        * If LLD doesn't specify hander and leaves its pointer NULL then
-        * the default libfc function will be used for that handler.
-        */
-
-       /**
-        * ELS/CT interfaces
+        * STATUS: REQUIRED
         */
+       int (*frame_send)(struct fc_lport *lp, struct fc_frame *fp);
 
        /*
-        * elsct_send - sends ELS/CT frame
+        * Interface to send ELS/CT frames
+        *
+        * STATUS: OPTIONAL
         */
        struct fc_seq *(*elsct_send)(struct fc_lport *lport,
-                                    struct fc_rport *rport,
+                                    u32 did,
                                     struct fc_frame *fp,
                                     unsigned int op,
                                     void (*resp)(struct fc_seq *,
                                             struct fc_frame *fp,
                                             void *arg),
                                     void *arg, u32 timer_msec);
-       /**
-        * Exhance Manager interfaces
-        */
 
        /*
         * Send the FC frame payload using a new exchange and sequence.
@@ -407,6 +459,8 @@ struct libfc_function_template {
         * timer_msec argument is specified. The timer is canceled when
         * it fires or when the exchange is done. The exchange timeout handler
         * is registered by EM layer.
+        *
+        * STATUS: OPTIONAL
         */
        struct fc_seq *(*exch_seq_send)(struct fc_lport *lp,
                                        struct fc_frame *fp,
@@ -418,14 +472,33 @@ struct libfc_function_template {
                                        void *arg, unsigned int timer_msec);
 
        /*
-        * send a frame using existing sequence and exchange.
+        * Sets up the DDP context for a given exchange id on the given
+        * scatterlist if LLD supports DDP for large receive.
+        *
+        * STATUS: OPTIONAL
+        */
+       int (*ddp_setup)(struct fc_lport *lp, u16 xid,
+                        struct scatterlist *sgl, unsigned int sgc);
+       /*
+        * Completes the DDP transfer and returns the length of data DDPed
+        * for the given exchange id.
+        *
+        * STATUS: OPTIONAL
+        */
+       int (*ddp_done)(struct fc_lport *lp, u16 xid);
+       /*
+        * Send a frame using an existing sequence and exchange.
+        *
+        * STATUS: OPTIONAL
         */
        int (*seq_send)(struct fc_lport *lp, struct fc_seq *sp,
                        struct fc_frame *fp);
 
        /*
-        * Send ELS response using mainly infomation
-        * in exchange and sequence in EM layer.
+        * Send an ELS response using infomation from a previous
+        * exchange and sequence.
+        *
+        * STATUS: OPTIONAL
         */
        void (*seq_els_rsp_send)(struct fc_seq *sp, enum fc_els_cmd els_cmd,
                                 struct fc_seq_els_data *els_data);
@@ -437,6 +510,8 @@ struct libfc_function_template {
         * A timer_msec can be specified for abort timeout, if non-zero
         * timer_msec value is specified then exchange resp handler
         * will be called with timeout error if no response to abort.
+        *
+        * STATUS: OPTIONAL
         */
        int (*seq_exch_abort)(const struct fc_seq *req_sp,
                              unsigned int timer_msec);
@@ -444,26 +519,15 @@ struct libfc_function_template {
        /*
         * Indicate that an exchange/sequence tuple is complete and the memory
         * allocated for the related objects may be freed.
+        *
+        * STATUS: OPTIONAL
         */
        void (*exch_done)(struct fc_seq *sp);
 
        /*
-        * Assigns a EM and a free XID for an new exchange and then
-        * allocates a new exchange and sequence pair.
-        * The fp can be used to determine free XID.
-        */
-       struct fc_exch *(*exch_get)(struct fc_lport *lp, struct fc_frame *fp);
-
-       /*
-        * Release previously assigned XID by exch_get API.
-        * The LLD may implement this if XID is assigned by LLD
-        * in exch_get().
-        */
-       void (*exch_put)(struct fc_lport *lp, struct fc_exch_mgr *mp,
-                        u16 ex_id);
-
-       /*
         * Start a new sequence on the same exchange/sequence tuple.
+        *
+        * STATUS: OPTIONAL
         */
        struct fc_seq *(*seq_start_next)(struct fc_seq *sp);
 
@@ -471,26 +535,39 @@ struct libfc_function_template {
         * Reset an exchange manager, completing all sequences and exchanges.
         * If s_id is non-zero, reset only exchanges originating from that FID.
         * If d_id is non-zero, reset only exchanges sending to that FID.
+        *
+        * STATUS: OPTIONAL
         */
-       void (*exch_mgr_reset)(struct fc_exch_mgr *,
+       void (*exch_mgr_reset)(struct fc_lport *,
                               u32 s_id, u32 d_id);
 
-       void (*rport_flush_queue)(void);
-       /**
-        * Local Port interfaces
+       /*
+        * Flush the rport work queue. Generally used before shutdown.
+        *
+        * STATUS: OPTIONAL
         */
+       void (*rport_flush_queue)(void);
 
        /*
-        * Receive a frame to a local port.
+        * Receive a frame for a local port.
+        *
+        * STATUS: OPTIONAL
         */
        void (*lport_recv)(struct fc_lport *lp, struct fc_seq *sp,
                           struct fc_frame *fp);
 
+       /*
+        * Reset the local port.
+        *
+        * STATUS: OPTIONAL
+        */
        int (*lport_reset)(struct fc_lport *);
 
-       /**
-        * Remote Port interfaces
+       /*
+        * Create a remote port
         */
+       struct fc_rport_priv *(*rport_create)(struct fc_lport *,
+                                             struct fc_rport_identifiers *);
 
        /*
         * Initiates the RP state machine. It is called from the LP module.
@@ -500,26 +577,39 @@ struct libfc_function_template {
         * - PLOGI
         * - PRLI
         * - RTV
+        *
+        * STATUS: OPTIONAL
         */
-       int (*rport_login)(struct fc_rport *rport);
+       int (*rport_login)(struct fc_rport_priv *);
 
        /*
         * Logoff, and remove the rport from the transport if
         * it had been added. This will send a LOGO to the target.
+        *
+        * STATUS: OPTIONAL
         */
-       int (*rport_logoff)(struct fc_rport *rport);
+       int (*rport_logoff)(struct fc_rport_priv *);
 
        /*
         * Recieve a request from a remote port.
+        *
+        * STATUS: OPTIONAL
         */
        void (*rport_recv_req)(struct fc_seq *, struct fc_frame *,
-                              struct fc_rport *);
+                              struct fc_rport_priv *);
 
-       struct fc_rport *(*rport_lookup)(const struct fc_lport *, u32);
+       /*
+        * lookup an rport by it's port ID.
+        *
+        * STATUS: OPTIONAL
+        */
+       struct fc_rport_priv *(*rport_lookup)(const struct fc_lport *, u32);
 
-       /**
-        * FCP interfaces
+       /*
+        * Destroy an rport after final kref_put().
+        * The argument is a pointer to the kref inside the fc_rport_priv.
         */
+       void (*rport_destroy)(struct kref *);
 
        /*
         * Send a fcp cmd from fsp pkt.
@@ -527,30 +617,38 @@ struct libfc_function_template {
         *
         * The resp handler is called when FCP_RSP received.
         *
+        * STATUS: OPTIONAL
         */
        int (*fcp_cmd_send)(struct fc_lport *lp, struct fc_fcp_pkt *fsp,
                            void (*resp)(struct fc_seq *, struct fc_frame *fp,
                                         void *arg));
 
        /*
-        * Used at least durring linkdown and reset
+        * Cleanup the FCP layer, used durring link down and reset
+        *
+        * STATUS: OPTIONAL
         */
        void (*fcp_cleanup)(struct fc_lport *lp);
 
        /*
         * Abort all I/O on a local port
+        *
+        * STATUS: OPTIONAL
         */
        void (*fcp_abort_io)(struct fc_lport *lp);
 
-       /**
-        * Discovery interfaces
+       /*
+        * Receive a request for the discovery layer.
+        *
+        * STATUS: OPTIONAL
         */
-
        void (*disc_recv_req)(struct fc_seq *,
                              struct fc_frame *, struct fc_lport *);
 
        /*
         * Start discovery for a local port.
+        *
+        * STATUS: OPTIONAL
         */
        void (*disc_start)(void (*disc_callback)(struct fc_lport *,
                                                 enum fc_disc_event),
@@ -559,6 +657,8 @@ struct libfc_function_template {
        /*
         * Stop discovery for a given lport. This will remove
         * all discovered rports
+        *
+        * STATUS: OPTIONAL
         */
        void (*disc_stop) (struct fc_lport *);
 
@@ -566,6 +666,8 @@ struct libfc_function_template {
         * Stop discovery for a given lport. This will block
         * until all discovered rports are deleted from the
         * FC transport class
+        *
+        * STATUS: OPTIONAL
         */
        void (*disc_stop_final) (struct fc_lport *);
 };
@@ -584,6 +686,7 @@ struct fc_disc {
                              enum fc_disc_event);
 
        struct list_head         rports;
+       struct list_head         rogue_rports;
        struct fc_lport         *lport;
        struct mutex            disc_mutex;
        struct fc_gpn_ft_resp   partial_buf;    /* partial name buffer */
@@ -595,20 +698,22 @@ struct fc_lport {
 
        /* Associations */
        struct Scsi_Host        *host;
-       struct fc_exch_mgr      *emp;
-       struct fc_rport         *dns_rp;
-       struct fc_rport         *ptp_rp;
+       struct list_head        ema_list;
+       struct fc_rport_priv    *dns_rp;
+       struct fc_rport_priv    *ptp_rp;
        void                    *scsi_priv;
        struct fc_disc          disc;
 
        /* Operational Information */
        struct libfc_function_template tt;
-       u16                     link_status;
+       u8                      link_up;
+       u8                      qfull;
        enum fc_lport_state     state;
        unsigned long           boot_time;
 
        struct fc_host_statistics host_stats;
-       struct fcoe_dev_stats   *dev_stats[NR_CPUS];
+       struct fcoe_dev_stats   *dev_stats;
+
        u64                     wwpn;
        u64                     wwnn;
        u8                      retry_count;
@@ -623,9 +728,11 @@ struct fc_lport {
        unsigned int            e_d_tov;
        unsigned int            r_a_tov;
        u8                      max_retry_count;
+       u8                      max_rport_retry_count;
        u16                     link_speed;
        u16                     link_supported_speeds;
        u16                     lro_xid;        /* max xid for fcoe lro */
+       unsigned int            lso_max;        /* max large send size */
        struct fc_ns_fts        fcts;           /* FC-4 type masks */
        struct fc_els_rnid_gen  rnid_gen;       /* RNID information */
 
@@ -637,14 +744,9 @@ struct fc_lport {
        struct delayed_work     disc_work;
 };
 
-/**
+/*
  * FC_LPORT HELPER FUNCTIONS
  *****************************/
-static inline void *lport_priv(const struct fc_lport *lp)
-{
-       return (void *)(lp + 1);
-}
-
 static inline int fc_lport_test_ready(struct fc_lport *lp)
 {
        return lp->state == LPORT_ST_READY;
@@ -668,8 +770,44 @@ static inline void fc_lport_state_enter(struct fc_lport *lp,
        lp->state = state;
 }
 
+static inline int fc_lport_init_stats(struct fc_lport *lp)
+{
+       /* allocate per cpu stats block */
+       lp->dev_stats = alloc_percpu(struct fcoe_dev_stats);
+       if (!lp->dev_stats)
+               return -ENOMEM;
+       return 0;
+}
+
+static inline void fc_lport_free_stats(struct fc_lport *lp)
+{
+       free_percpu(lp->dev_stats);
+}
+
+static inline struct fcoe_dev_stats *fc_lport_get_stats(struct fc_lport *lp)
+{
+       return per_cpu_ptr(lp->dev_stats, smp_processor_id());
+}
+
+static inline void *lport_priv(const struct fc_lport *lp)
+{
+       return (void *)(lp + 1);
+}
 
 /**
+ * libfc_host_alloc() - Allocate a Scsi_Host with room for the fc_lport
+ * @sht: ptr to the scsi host templ
+ * @priv_size: size of private data after fc_lport
+ *
+ * Returns: ptr to Scsi_Host
+ */
+static inline struct Scsi_Host *
+libfc_host_alloc(struct scsi_host_template *sht, int priv_size)
+{
+       return scsi_host_alloc(sht, sizeof(struct fc_lport) + priv_size);
+}
+
+/*
  * LOCAL PORT LAYER
  *****************************/
 int fc_lport_init(struct fc_lport *lp);
@@ -704,12 +842,6 @@ void fc_linkup(struct fc_lport *);
 void fc_linkdown(struct fc_lport *);
 
 /*
- * Pause and unpause traffic.
- */
-void fc_pause(struct fc_lport *);
-void fc_unpause(struct fc_lport *);
-
-/*
  * Configure the local port.
  */
 int fc_lport_config(struct fc_lport *);
@@ -725,19 +857,19 @@ int fc_lport_reset(struct fc_lport *);
 int fc_set_mfs(struct fc_lport *lp, u32 mfs);
 
 
-/**
+/*
  * REMOTE PORT LAYER
  *****************************/
 int fc_rport_init(struct fc_lport *lp);
 void fc_rport_terminate_io(struct fc_rport *rp);
 
-/**
+/*
  * DISCOVERY LAYER
  *****************************/
 int fc_disc_init(struct fc_lport *lp);
 
 
-/**
+/*
  * SCSI LAYER
  *****************************/
 /*
@@ -798,7 +930,12 @@ int fc_change_queue_type(struct scsi_device *sdev, int tag_type);
  */
 void fc_fcp_destroy(struct fc_lport *);
 
-/**
+/*
+ * Set up direct-data placement for this I/O request
+ */
+void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
+
+/*
  * ELS/CT interface
  *****************************/
 /*
@@ -807,7 +944,7 @@ void fc_fcp_destroy(struct fc_lport *);
 int fc_elsct_init(struct fc_lport *lp);
 
 
-/**
+/*
  * EXCHANGE MANAGER LAYER
  *****************************/
 /*
@@ -817,6 +954,28 @@ int fc_elsct_init(struct fc_lport *lp);
 int fc_exch_init(struct fc_lport *lp);
 
 /*
+ * Adds Exchange Manager (EM) mp to lport.
+ *
+ * Adds specified mp to lport using struct fc_exch_mgr_anchor,
+ * the struct fc_exch_mgr_anchor allows same EM sharing by
+ * more than one lport with their specified match function,
+ * the match function is used in allocating exchange from
+ * added mp.
+ */
+struct fc_exch_mgr_anchor *fc_exch_mgr_add(struct fc_lport *lport,
+                                          struct fc_exch_mgr *mp,
+                                          bool (*match)(struct fc_frame *));
+
+/*
+ * Deletes Exchange Manager (EM) from lport by removing
+ * its anchor ema from lport.
+ *
+ * If removed anchor ema was the last user of its associated EM
+ * then also destroys associated EM.
+ */
+void fc_exch_mgr_del(struct fc_exch_mgr_anchor *ema);
+
+/*
  * Allocates an Exchange Manager (EM).
  *
  * The EM manages exchanges for their allocation and
@@ -831,27 +990,25 @@ int fc_exch_init(struct fc_lport *lp);
  * a new exchange.
  * The LLD may choose to have multiple EMs,
  * e.g. one EM instance per CPU receive thread in LLD.
- * The LLD can use exch_get() of struct libfc_function_template
- * to specify XID for a new exchange within
- * a specified EM instance.
  *
- * The em_idx to uniquely identify an EM instance.
+ * Specified match function is used in allocating exchanges
+ * from newly allocated EM.
  */
 struct fc_exch_mgr *fc_exch_mgr_alloc(struct fc_lport *lp,
                                      enum fc_class class,
                                      u16 min_xid,
-                                     u16 max_xid);
+                                     u16 max_xid,
+                                     bool (*match)(struct fc_frame *));
 
 /*
- * Free an exchange manager.
+ * Free all exchange managers of a lport.
  */
-void fc_exch_mgr_free(struct fc_exch_mgr *mp);
+void fc_exch_mgr_free(struct fc_lport *lport);
 
 /*
  * Receive a frame on specified local port and exchange manager.
  */
-void fc_exch_recv(struct fc_lport *lp, struct fc_exch_mgr *mp,
-                 struct fc_frame *fp);
+void fc_exch_recv(struct fc_lport *lp, struct fc_frame *fp);
 
 /*
  * This function is for exch_seq_send function pointer in
@@ -893,30 +1050,22 @@ int fc_seq_exch_abort(const struct fc_seq *req_sp, unsigned int timer_msec);
 void fc_exch_done(struct fc_seq *sp);
 
 /*
- * Assigns a EM and XID for a frame and then allocates
- * a new exchange and sequence pair.
- * The fp can be used to determine free XID.
- */
-struct fc_exch *fc_exch_get(struct fc_lport *lp, struct fc_frame *fp);
-
-/*
  * Allocate a new exchange and sequence pair.
- * if ex_id is zero then next free exchange id
- * from specified exchange manger mp will be assigned.
  */
-struct fc_exch *fc_exch_alloc(struct fc_exch_mgr *mp,
-                             struct fc_frame *fp, u16 ex_id);
+struct fc_exch *fc_exch_alloc(struct fc_lport *lport, struct fc_frame *fp);
 /*
  * Start a new sequence on the same exchange as the supplied sequence.
  */
 struct fc_seq *fc_seq_start_next(struct fc_seq *sp);
 
+
 /*
- * Reset an exchange manager, completing all sequences and exchanges.
- * If s_id is non-zero, reset only exchanges originating from that FID.
- * If d_id is non-zero, reset only exchanges sending to that FID.
+ * Reset all EMs of a lport, releasing its all sequences and
+ * exchanges. If sid is non-zero, then reset only exchanges
+ * we sourced from that FID. If did is non-zero, reset only
+ * exchanges destined to that FID.
  */
-void fc_exch_mgr_reset(struct fc_exch_mgr *, u32 s_id, u32 d_id);
+void fc_exch_mgr_reset(struct fc_lport *, u32 s_id, u32 d_id);
 
 /*
  * Functions for fc_functions_template