#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(rport, fmt, args...) \
+do { \
+ struct fc_rport_priv *rdata = rport->dd_data; \
+ struct fc_lport *lport = rdata->local_port; \
+ FC_RPORT_ID_DBG(lport, rport->port_id, fmt, ##args); \
+} while (0)
+
+#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
*/
enum fc_lport_state {
- LPORT_ST_NONE = 0,
+ LPORT_ST_DISABLED = 0,
LPORT_ST_FLOGI,
LPORT_ST_DNS,
LPORT_ST_RPN_ID,
};
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 {
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_operations {
void (*event_callback)(struct fc_lport *, struct fc_rport *,
enum fc_rport_event);
#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;
*/
struct fc_exch_mgr;
+struct fc_exch_mgr_anchor;
+extern u16 fc_cpu_mask; /* cpu mask for possible cpus */
/*
* Sequence.
*/
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 */
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.
- *
- * STATUS: OPTIONAL
- */
- 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().
- *
- * STATUS: OPTIONAL
- */
- 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
/*
* Create a remote port
*/
- struct fc_rport *(*rport_create)(struct fc_disc_port *);
+ struct fc_rport *(*rport_create)(struct fc_lport *,
+ struct fc_rport_identifiers *);
/*
* Initiates the RP state machine. It is called from the LP module.
/* Associations */
struct Scsi_Host *host;
- struct fc_exch_mgr *emp;
+ struct list_head ema_list;
struct fc_rport *dns_rp;
struct fc_rport *ptp_rp;
void *scsi_priv;
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
* 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
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_lport *, u32 s_id, u32 d_id);