mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 12:46:27 +00:00
Add patch series for 2.6.35.
The individual patches are a subset of the earlier ones, with only line number changes to apply cleanly. git-svn-id: http://svn.code.sf.net/p/scst/svn/trunk@1922 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -0,0 +1,487 @@
|
||||
libfc: add hook for FC-4 provider registration
|
||||
|
||||
Allow FC-4 provider modules to hook into libfc, mostly for targets.
|
||||
This should allow any FC-4 module to handle PRLI requests and maintain
|
||||
process-association states.
|
||||
|
||||
Each provider registers its ops with libfc and then will be called for
|
||||
any incoming PRLI for that FC-4 type on any instance. The provider
|
||||
can decide whether to handle that particular instance using any method
|
||||
it likes, such as ACLs or other configuration information.
|
||||
|
||||
A count is kept of the number of successful PRLIs from the remote port.
|
||||
Providers are called back with an implicit PRLO when the remote port
|
||||
is about to be deleted or has been reset.
|
||||
|
||||
fc_lport_recv_req() now sends incoming FC-4 requests to FC-4 providers,
|
||||
and there is a built-in provider always registered for handling
|
||||
incoming ELS requests.
|
||||
|
||||
The call to provider recv() routines uses rcu_read_lock()
|
||||
so that providers aren't removed during the call. That lock is very
|
||||
cheap and shouldn't affect any performance on ELS requests.
|
||||
Providers can rely on the RCU lock to protect a session lookup as well.
|
||||
|
||||
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
|
||||
|
||||
---
|
||||
drivers/scsi/libfc/fc_libfc.c | 60 ++++++++++++++++++
|
||||
drivers/scsi/libfc/fc_libfc.h | 11 +++
|
||||
drivers/scsi/libfc/fc_lport.c | 63 ++++++++++++++++---
|
||||
drivers/scsi/libfc/fc_rport.c | 133 +++++++++++++++++++++++++++++++++--------
|
||||
include/scsi/libfc.h | 26 ++++++++
|
||||
5 files changed, 255 insertions(+), 38 deletions(-)
|
||||
|
||||
|
||||
---
|
||||
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
|
||||
index 39f4b6a..ce0de44 100644
|
||||
--- a/drivers/scsi/libfc/fc_libfc.c
|
||||
+++ b/drivers/scsi/libfc/fc_libfc.c
|
||||
@@ -34,6 +34,23 @@ unsigned int fc_debug_logging;
|
||||
module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
|
||||
|
||||
+DEFINE_MUTEX(fc_prov_mutex);
|
||||
+
|
||||
+/*
|
||||
+ * Providers which primarily send requests and PRLIs.
|
||||
+ */
|
||||
+struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
|
||||
+ [0] = &fc_rport_t0_prov,
|
||||
+ [FC_TYPE_FCP] = &fc_rport_fcp_init,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Providers which receive requests.
|
||||
+ */
|
||||
+struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
|
||||
+ [FC_TYPE_ELS] = &fc_lport_els_prov,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* libfc_init() - Initialize libfc.ko
|
||||
*/
|
||||
@@ -132,3 +149,46 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
|
||||
}
|
||||
return copy_len;
|
||||
}
|
||||
+
|
||||
+/**
|
||||
+ * fc_fc4_register_provider() - register FC-4 upper-level provider.
|
||||
+ * @type: FC-4 type, such as FC_TYPE_FCP
|
||||
+ * @prov: structure describing provider including ops vector.
|
||||
+ *
|
||||
+ * Returns 0 on success, negative error otherwise.
|
||||
+ */
|
||||
+int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
|
||||
+{
|
||||
+ struct fc4_prov **prov_entry;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (type >= FC_FC4_PROV_SIZE)
|
||||
+ return -EINVAL;
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
|
||||
+ if (*prov_entry)
|
||||
+ ret = -EBUSY;
|
||||
+ else
|
||||
+ *prov_entry = prov;
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL(fc_fc4_register_provider);
|
||||
+
|
||||
+/**
|
||||
+ * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
|
||||
+ * @type: FC-4 type, such as FC_TYPE_FCP
|
||||
+ * @prov: structure describing provider including ops vector.
|
||||
+ */
|
||||
+void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
|
||||
+{
|
||||
+ BUG_ON(type >= FC_FC4_PROV_SIZE);
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ if (prov->recv)
|
||||
+ rcu_assign_pointer(fc_passive_prov[type], NULL);
|
||||
+ else
|
||||
+ rcu_assign_pointer(fc_active_prov[type], NULL);
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+ synchronize_rcu();
|
||||
+}
|
||||
+EXPORT_SYMBOL(fc_fc4_deregister_provider);
|
||||
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
|
||||
index f5c0ca4..2323c80 100644
|
||||
--- a/drivers/scsi/libfc/fc_libfc.h
|
||||
+++ b/drivers/scsi/libfc/fc_libfc.h
|
||||
@@ -82,6 +82,17 @@ extern unsigned int fc_debug_logging;
|
||||
(lport)->host->host_no, ##args))
|
||||
|
||||
/*
|
||||
+ * FC-4 Providers.
|
||||
+ */
|
||||
+extern struct fc4_prov *fc_active_prov[]; /* providers without recv */
|
||||
+extern struct fc4_prov *fc_passive_prov[]; /* providers with recv */
|
||||
+extern struct mutex fc_prov_mutex; /* lock over table changes */
|
||||
+
|
||||
+extern struct fc4_prov fc_rport_t0_prov; /* type 0 provider */
|
||||
+extern struct fc4_prov fc_lport_els_prov; /* ELS provider */
|
||||
+extern struct fc4_prov fc_rport_fcp_init; /* FCP initiator provider */
|
||||
+
|
||||
+/*
|
||||
* Set up direct-data placement for this I/O request
|
||||
*/
|
||||
void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid);
|
||||
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
|
||||
index 79c9e3c..b05329c 100644
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -844,7 +844,7 @@ out:
|
||||
}
|
||||
|
||||
/**
|
||||
- * fc_lport_recv_req() - The generic lport request handler
|
||||
+ * fc_lport_recv_els_req() - The generic lport ELS request handler
|
||||
* @lport: The local port that received the request
|
||||
* @sp: The sequence the request is on
|
||||
* @fp: The request frame
|
||||
@@ -855,8 +855,8 @@ out:
|
||||
* Locking Note: This function should not be called with the lport
|
||||
* lock held becuase it will grab the lock.
|
||||
*/
|
||||
-static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
|
||||
- struct fc_frame *fp)
|
||||
+static void fc_lport_recv_els_req(struct fc_lport *lport, struct fc_seq *sp,
|
||||
+ struct fc_frame *fp)
|
||||
{
|
||||
struct fc_frame_header *fh = fc_frame_header_get(fp);
|
||||
void (*recv) (struct fc_seq *, struct fc_frame *, struct fc_lport *);
|
||||
@@ -870,8 +870,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
|
||||
*/
|
||||
if (!lport->link_up)
|
||||
fc_frame_free(fp);
|
||||
- else if (fh->fh_type == FC_TYPE_ELS &&
|
||||
- fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
|
||||
+ else {
|
||||
/*
|
||||
* Check opcode.
|
||||
*/
|
||||
@@ -900,17 +899,59 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
|
||||
}
|
||||
|
||||
recv(sp, fp, lport);
|
||||
- } else {
|
||||
- FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
|
||||
- fr_eof(fp));
|
||||
- fc_frame_free(fp);
|
||||
}
|
||||
mutex_unlock(&lport->lp_mutex);
|
||||
+ lport->tt.exch_done(sp);
|
||||
+}
|
||||
+
|
||||
+static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len,
|
||||
+ const struct fc_els_spp *spp_in,
|
||||
+ struct fc_els_spp *spp_out)
|
||||
+{
|
||||
+ return FC_SPP_RESP_INVL;
|
||||
+}
|
||||
+
|
||||
+struct fc4_prov fc_lport_els_prov = {
|
||||
+ .prli = fc_lport_els_prli,
|
||||
+ .recv = fc_lport_recv_els_req,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * fc_lport_recv_req() - The generic lport request handler
|
||||
+ * @lport: The lport that received the request
|
||||
+ * @sp: The sequence the request is on
|
||||
+ * @fp: The frame the request is in
|
||||
+ *
|
||||
+ * Locking Note: This function should not be called with the lport
|
||||
+ * lock held becuase it may grab the lock.
|
||||
+ */
|
||||
+static void fc_lport_recv_req(struct fc_lport *lport, struct fc_seq *sp,
|
||||
+ struct fc_frame *fp)
|
||||
+{
|
||||
+ struct fc_frame_header *fh = fc_frame_header_get(fp);
|
||||
+ struct fc4_prov *prov;
|
||||
|
||||
/*
|
||||
- * The common exch_done for all request may not be good
|
||||
- * if any request requires longer hold on exhange. XXX
|
||||
+ * Use RCU read lock and module_lock to be sure module doesn't
|
||||
+ * deregister and get unloaded while we're calling it.
|
||||
+ * try_module_get() is inlined and accepts a NULL parameter.
|
||||
+ * Only ELSes and FCP target ops should come through here.
|
||||
+ * The locking is unfortunate, and a better scheme is being sought.
|
||||
*/
|
||||
+ rcu_read_lock();
|
||||
+ if (fh->fh_type >= FC_FC4_PROV_SIZE)
|
||||
+ goto drop;
|
||||
+ prov = rcu_dereference(fc_passive_prov[fh->fh_type]);
|
||||
+ if (!prov || !try_module_get(prov->module))
|
||||
+ goto drop;
|
||||
+ rcu_read_unlock();
|
||||
+ prov->recv(lport, sp, fp);
|
||||
+ module_put(prov->module);
|
||||
+ return;
|
||||
+drop:
|
||||
+ rcu_read_unlock();
|
||||
+ FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type);
|
||||
+ fc_frame_free(fp);
|
||||
lport->tt.exch_done(sp);
|
||||
}
|
||||
|
||||
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
|
||||
index 39e440f..3ec4aa5 100644
|
||||
--- a/drivers/scsi/libfc/fc_rport.c
|
||||
+++ b/drivers/scsi/libfc/fc_rport.c
|
||||
@@ -246,6 +246,8 @@ static void fc_rport_work(struct work_struct *work)
|
||||
struct fc_rport_operations *rport_ops;
|
||||
struct fc_rport_identifiers ids;
|
||||
struct fc_rport *rport;
|
||||
+ struct fc4_prov *prov;
|
||||
+ u8 type;
|
||||
int restart = 0;
|
||||
|
||||
mutex_lock(&rdata->rp_mutex);
|
||||
@@ -295,6 +297,15 @@ static void fc_rport_work(struct work_struct *work)
|
||||
case RPORT_EV_FAILED:
|
||||
case RPORT_EV_LOGO:
|
||||
case RPORT_EV_STOP:
|
||||
+ if (rdata->prli_count) {
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ for (type = 1; type < FC_FC4_PROV_SIZE; type++) {
|
||||
+ prov = fc_passive_prov[type];
|
||||
+ if (prov && prov->prlo)
|
||||
+ prov->prlo(rdata);
|
||||
+ }
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+ }
|
||||
port_id = rdata->ids.port_id;
|
||||
mutex_unlock(&rdata->rp_mutex);
|
||||
|
||||
@@ -1434,6 +1445,7 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
|
||||
struct fc_exch *ep;
|
||||
struct fc_frame *fp;
|
||||
struct fc_frame_header *fh;
|
||||
+ struct fc4_prov *prov;
|
||||
struct {
|
||||
struct fc_els_prli prli;
|
||||
struct fc_els_spp spp;
|
||||
@@ -1443,10 +1455,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
|
||||
unsigned int len;
|
||||
unsigned int plen;
|
||||
enum fc_els_spp_resp resp;
|
||||
+ enum fc_els_spp_resp passive;
|
||||
struct fc_seq_els_data rjt_data;
|
||||
u32 f_ctl;
|
||||
- u32 fcp_parm;
|
||||
- u32 roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
|
||||
rjt_data.fp = NULL;
|
||||
fh = fc_frame_header_get(rx_fp);
|
||||
@@ -1485,46 +1496,41 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
|
||||
pp->prli.prli_len = htons(len);
|
||||
len -= sizeof(struct fc_els_prli);
|
||||
|
||||
- /* reinitialize remote port roles */
|
||||
- rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
-
|
||||
/*
|
||||
* Go through all the service parameter pages and build
|
||||
* response. If plen indicates longer SPP than standard,
|
||||
* use that. The entire response has been pre-cleared above.
|
||||
*/
|
||||
spp = &pp->spp;
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
while (len >= plen) {
|
||||
spp->spp_type = rspp->spp_type;
|
||||
spp->spp_type_ext = rspp->spp_type_ext;
|
||||
- spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
||||
- resp = FC_SPP_RESP_ACK;
|
||||
-
|
||||
- switch (rspp->spp_type) {
|
||||
- case 0: /* common to all FC-4 types */
|
||||
- break;
|
||||
- case FC_TYPE_FCP:
|
||||
- fcp_parm = ntohl(rspp->spp_params);
|
||||
- if (fcp_parm & FCP_SPPF_RETRY)
|
||||
- rdata->flags |= FC_RP_FLAGS_RETRY;
|
||||
- rdata->supported_classes = FC_COS_CLASS3;
|
||||
- if (fcp_parm & FCP_SPPF_INIT_FCN)
|
||||
- roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
- if (fcp_parm & FCP_SPPF_TARG_FCN)
|
||||
- roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
- rdata->ids.roles = roles;
|
||||
-
|
||||
- spp->spp_params = htonl(lport->service_params);
|
||||
- break;
|
||||
- default:
|
||||
- resp = FC_SPP_RESP_INVL;
|
||||
- break;
|
||||
+ resp = 0;
|
||||
+
|
||||
+ if (rspp->spp_type < FC_FC4_PROV_SIZE) {
|
||||
+ prov = fc_active_prov[rspp->spp_type];
|
||||
+ if (prov)
|
||||
+ resp = prov->prli(rdata, plen, rspp, spp);
|
||||
+ prov = fc_passive_prov[rspp->spp_type];
|
||||
+ if (prov) {
|
||||
+ passive = prov->prli(rdata, plen, rspp, spp);
|
||||
+ if (!resp || passive == FC_SPP_RESP_ACK)
|
||||
+ resp = passive;
|
||||
+ }
|
||||
+ }
|
||||
+ if (!resp) {
|
||||
+ if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
|
||||
+ resp |= FC_SPP_RESP_CONF;
|
||||
+ else
|
||||
+ resp |= FC_SPP_RESP_INVL;
|
||||
}
|
||||
spp->spp_flags |= resp;
|
||||
len -= plen;
|
||||
rspp = (struct fc_els_spp *)((char *)rspp + plen);
|
||||
spp = (struct fc_els_spp *)((char *)spp + plen);
|
||||
}
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
|
||||
/*
|
||||
* Send LS_ACC. If this fails, the originator should retry.
|
||||
@@ -1669,6 +1675,79 @@ int fc_rport_init(struct fc_lport *lport)
|
||||
EXPORT_SYMBOL(fc_rport_init);
|
||||
|
||||
/**
|
||||
+ * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
|
||||
+ * @rdata: remote port private
|
||||
+ * @spp_len: service parameter page length
|
||||
+ * @rspp: received service parameter page
|
||||
+ * @spp: response service parameter page
|
||||
+ *
|
||||
+ * Returns the value for the response code to be placed in spp_flags;
|
||||
+ * Returns 0 if not an initiator.
|
||||
+ */
|
||||
+static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
|
||||
+ const struct fc_els_spp *rspp,
|
||||
+ struct fc_els_spp *spp)
|
||||
+{
|
||||
+ struct fc_lport *lport = rdata->local_port;
|
||||
+ u32 fcp_parm;
|
||||
+
|
||||
+ fcp_parm = ntohl(rspp->spp_params);
|
||||
+ rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
|
||||
+ if (fcp_parm & FCP_SPPF_INIT_FCN)
|
||||
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
|
||||
+ if (fcp_parm & FCP_SPPF_TARG_FCN)
|
||||
+ rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
|
||||
+ if (fcp_parm & FCP_SPPF_RETRY)
|
||||
+ rdata->flags |= FC_RP_FLAGS_RETRY;
|
||||
+ rdata->supported_classes = FC_COS_CLASS3;
|
||||
+
|
||||
+ if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR))
|
||||
+ return 0;
|
||||
+
|
||||
+ spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
|
||||
+
|
||||
+ /*
|
||||
+ * OR in our service parameters with other providers (target), if any.
|
||||
+ */
|
||||
+ fcp_parm = ntohl(spp->spp_params);
|
||||
+ spp->spp_params = htonl(fcp_parm | lport->service_params);
|
||||
+ return FC_SPP_RESP_ACK;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * FC-4 provider ops for FCP initiator.
|
||||
+ */
|
||||
+struct fc4_prov fc_rport_fcp_init = {
|
||||
+ .prli = fc_rport_fcp_prli,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
+ * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
|
||||
+ * @rdata: remote port private
|
||||
+ * @spp_len: service parameter page length
|
||||
+ * @rspp: received service parameter page
|
||||
+ * @spp: response service parameter page
|
||||
+ */
|
||||
+static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
|
||||
+ const struct fc_els_spp *rspp,
|
||||
+ struct fc_els_spp *spp)
|
||||
+{
|
||||
+ if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR)
|
||||
+ return FC_SPP_RESP_INVL;
|
||||
+ return FC_SPP_RESP_ACK;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * FC-4 provider ops for type 0 service parameters.
|
||||
+ *
|
||||
+ * This handles the special case of type 0 which is always successful
|
||||
+ * but doesn't do anything otherwise.
|
||||
+ */
|
||||
+struct fc4_prov fc_rport_t0_prov = {
|
||||
+ .prli = fc_rport_t0_prli,
|
||||
+};
|
||||
+
|
||||
+/**
|
||||
* fc_setup_rport() - Initialize the rport_event_queue
|
||||
*/
|
||||
int fc_setup_rport()
|
||||
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
|
||||
index 7495c0b..4ac290f 100644
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
#include <scsi/fc_frame.h>
|
||||
|
||||
+#define FC_FC4_PROV_SIZE (FC_TYPE_FCP + 1) /* size of tables */
|
||||
+
|
||||
/*
|
||||
* libfc error codes
|
||||
*/
|
||||
@@ -195,6 +197,7 @@ struct fc_rport_libfc_priv {
|
||||
* @rp_mutex: The mutex that protects the remote port
|
||||
* @retry_work: Handle for retries
|
||||
* @event_callback: Callback when READY, FAILED or LOGO states complete
|
||||
+ * @prli_count: Count of open PRLI sessions in providers
|
||||
*/
|
||||
struct fc_rport_priv {
|
||||
struct fc_lport *local_port;
|
||||
@@ -216,6 +219,7 @@ struct fc_rport_priv {
|
||||
struct list_head peers;
|
||||
struct work_struct event_work;
|
||||
u32 supported_classes;
|
||||
+ u16 prli_count;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -857,6 +861,28 @@ struct fc_lport {
|
||||
struct delayed_work retry_work;
|
||||
};
|
||||
|
||||
+/**
|
||||
+ * struct fc4_prov - FC-4 provider registration
|
||||
+ * @prli: Handler for incoming PRLI
|
||||
+ * @prlo: Handler for session reset
|
||||
+ * @recv: Handler for incoming request
|
||||
+ * @module: Pointer to module. May be NULL.
|
||||
+ */
|
||||
+struct fc4_prov {
|
||||
+ int (*prli)(struct fc_rport_priv *, u32 spp_len,
|
||||
+ const struct fc_els_spp *spp_in,
|
||||
+ struct fc_els_spp *spp_out);
|
||||
+ void (*prlo)(struct fc_rport_priv *);
|
||||
+ void (*recv)(struct fc_lport *, struct fc_seq *, struct fc_frame *);
|
||||
+ struct module *module;
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Register FC-4 provider with libfc.
|
||||
+ */
|
||||
+int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *);
|
||||
+void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *);
|
||||
+
|
||||
/*
|
||||
* FC_LPORT HELPER FUNCTIONS
|
||||
*****************************/
|
||||
@@ -0,0 +1,84 @@
|
||||
libfc: add method for setting handler for incoming exchange
|
||||
|
||||
Add a method for setting handler for incoming exchange.
|
||||
For multi-sequence exchanges, this allows the target driver
|
||||
to add a response handler for handling subsequent sequences,
|
||||
and exchange manager resets.
|
||||
|
||||
The new function is called fc_seq_set_resp().
|
||||
|
||||
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
|
||||
|
||||
---
|
||||
drivers/scsi/libfc/fc_exch.c | 19 +++++++++++++++++++
|
||||
include/scsi/libfc.h | 11 ++++++++++-
|
||||
2 files changed, 29 insertions(+), 1 deletions(-)
|
||||
|
||||
|
||||
---
|
||||
diff --git a/drivers/scsi/libfc/fc_exch.c b/drivers/scsi/libfc/fc_exch.c
|
||||
index 104e0fb..1828d1d 100644
|
||||
--- a/drivers/scsi/libfc/fc_exch.c
|
||||
+++ b/drivers/scsi/libfc/fc_exch.c
|
||||
@@ -545,6 +545,22 @@ static struct fc_seq *fc_seq_start_next(struct fc_seq *sp)
|
||||
return sp;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * Set the response handler for the exchange associated with a sequence.
|
||||
+ */
|
||||
+static void fc_seq_set_resp(struct fc_seq *sp,
|
||||
+ void (*resp)(struct fc_seq *, struct fc_frame *,
|
||||
+ void *),
|
||||
+ void *arg)
|
||||
+{
|
||||
+ struct fc_exch *ep = fc_seq_exch(sp);
|
||||
+
|
||||
+ spin_lock_bh(&ep->ex_lock);
|
||||
+ ep->resp = resp;
|
||||
+ ep->arg = arg;
|
||||
+ spin_unlock_bh(&ep->ex_lock);
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* fc_seq_exch_abort() - Abort an exchange and sequence
|
||||
* @req_sp: The sequence to be aborted
|
||||
@@ -2263,6 +2279,9 @@ int fc_exch_init(struct fc_lport *lport)
|
||||
if (!lport->tt.seq_start_next)
|
||||
lport->tt.seq_start_next = fc_seq_start_next;
|
||||
|
||||
+ if (!lport->tt.seq_set_resp)
|
||||
+ lport->tt.seq_set_resp = fc_seq_set_resp;
|
||||
+
|
||||
if (!lport->tt.exch_seq_send)
|
||||
lport->tt.exch_seq_send = fc_exch_seq_send;
|
||||
|
||||
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
|
||||
index 4ac290f..64a4756 100644
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -571,6 +571,16 @@ struct libfc_function_template {
|
||||
struct fc_seq *(*seq_start_next)(struct fc_seq *);
|
||||
|
||||
/*
|
||||
+ * Set a response handler for the exchange of the sequence.
|
||||
+ *
|
||||
+ * STATUS: OPTIONAL
|
||||
+ */
|
||||
+ void (*seq_set_resp)(struct fc_seq *sp,
|
||||
+ void (*resp)(struct fc_seq *, struct fc_frame *,
|
||||
+ void *),
|
||||
+ void *arg);
|
||||
+
|
||||
+ /*
|
||||
* 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.
|
||||
@@ -1056,7 +1066,6 @@ struct fc_seq *fc_elsct_send(struct fc_lport *, u32 did,
|
||||
void fc_lport_flogi_resp(struct fc_seq *, struct fc_frame *, void *);
|
||||
void fc_lport_logo_resp(struct fc_seq *, struct fc_frame *, void *);
|
||||
|
||||
-
|
||||
/*
|
||||
* EXCHANGE MANAGER LAYER
|
||||
*****************************/
|
||||
@@ -0,0 +1,36 @@
|
||||
libfc: add local port hook for provider session lookup
|
||||
|
||||
The target provider needs a per-instance lookup table
|
||||
or other way to lookup sessions quickly without going through
|
||||
a linear list or serializing too much.
|
||||
|
||||
Add a simple void * array indexed by FC-4 type to the fc_lport.
|
||||
|
||||
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
|
||||
|
||||
---
|
||||
include/scsi/libfc.h | 2 ++
|
||||
1 files changed, 2 insertions(+), 0 deletions(-)
|
||||
|
||||
|
||||
---
|
||||
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
|
||||
index 64a4756..9d7c8e3 100644
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -816,6 +816,7 @@ struct fc_disc {
|
||||
* @lp_mutex: Mutex to protect the local port
|
||||
* @list: Handle for list of local ports
|
||||
* @retry_work: Handle to local port for delayed retry context
|
||||
+ * @prov: Pointers available for use by passive FC-4 providers
|
||||
*/
|
||||
struct fc_lport {
|
||||
/* Associations */
|
||||
@@ -869,6 +870,7 @@ struct fc_lport {
|
||||
struct mutex lp_mutex;
|
||||
struct list_head list;
|
||||
struct delayed_work retry_work;
|
||||
+ void *prov[FC_FC4_PROV_SIZE];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -0,0 +1,167 @@
|
||||
libfc: add hook to notify providers of local port changes
|
||||
|
||||
When an SCST provider is registered, it needs to know what
|
||||
local ports are available for configuration as targets.
|
||||
|
||||
Add a notifier chain that is invoked when any local port
|
||||
that is added or deleted.
|
||||
|
||||
Maintain a global list of local ports and add an
|
||||
interator function that calls a given function for
|
||||
every existing local port. This is used when first
|
||||
loading a provider.
|
||||
|
||||
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
|
||||
|
||||
---
|
||||
drivers/scsi/libfc/fc_libfc.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/scsi/libfc/fc_libfc.h | 2 ++
|
||||
drivers/scsi/libfc/fc_lport.c | 2 ++
|
||||
include/scsi/libfc.h | 14 +++++++++++++-
|
||||
4 files changed, 58 insertions(+), 1 deletions(-)
|
||||
|
||||
|
||||
---
|
||||
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
|
||||
index ce0de44..abd108a 100644
|
||||
--- a/drivers/scsi/libfc/fc_libfc.c
|
||||
+++ b/drivers/scsi/libfc/fc_libfc.c
|
||||
@@ -35,6 +35,10 @@ module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
|
||||
MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
|
||||
|
||||
DEFINE_MUTEX(fc_prov_mutex);
|
||||
+static LIST_HEAD(fc_local_ports);
|
||||
+struct blocking_notifier_head fc_lport_notifier_head =
|
||||
+ BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
|
||||
+EXPORT_SYMBOL(fc_lport_notifier_head);
|
||||
|
||||
/*
|
||||
* Providers which primarily send requests and PRLIs.
|
||||
@@ -150,6 +154,17 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
|
||||
return copy_len;
|
||||
}
|
||||
|
||||
+void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
|
||||
+{
|
||||
+ struct fc_lport *lport;
|
||||
+
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ list_for_each_entry(lport, &fc_local_ports, lport_list)
|
||||
+ notify(lport, arg);
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+}
|
||||
+EXPORT_SYMBOL(fc_lport_iterate);
|
||||
+
|
||||
/**
|
||||
* fc_fc4_register_provider() - register FC-4 upper-level provider.
|
||||
* @type: FC-4 type, such as FC_TYPE_FCP
|
||||
@@ -192,3 +207,29 @@ void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL(fc_fc4_deregister_provider);
|
||||
+
|
||||
+/**
|
||||
+ * fc_fc4_add_lport() - add new local port to list and run notifiers.
|
||||
+ * @lport: The new local port.
|
||||
+ */
|
||||
+void fc_fc4_add_lport(struct fc_lport *lport)
|
||||
+{
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ list_add_tail(&lport->lport_list, &fc_local_ports);
|
||||
+ blocking_notifier_call_chain(&fc_lport_notifier_head,
|
||||
+ FC_LPORT_EV_ADD, lport);
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * fc_fc4_del_lport() - remove local port from list and run notifiers.
|
||||
+ * @lport: The new local port.
|
||||
+ */
|
||||
+void fc_fc4_del_lport(struct fc_lport *lport)
|
||||
+{
|
||||
+ mutex_lock(&fc_prov_mutex);
|
||||
+ list_del(&lport->lport_list);
|
||||
+ blocking_notifier_call_chain(&fc_lport_notifier_head,
|
||||
+ FC_LPORT_EV_DEL, lport);
|
||||
+ mutex_unlock(&fc_prov_mutex);
|
||||
+}
|
||||
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
|
||||
index 2323c80..85ce01e 100644
|
||||
--- a/drivers/scsi/libfc/fc_libfc.h
|
||||
+++ b/drivers/scsi/libfc/fc_libfc.h
|
||||
@@ -111,6 +111,8 @@ void fc_destroy_fcp(void);
|
||||
* Internal libfc functions
|
||||
*/
|
||||
const char *fc_els_resp_type(struct fc_frame *);
|
||||
+extern void fc_fc4_add_lport(struct fc_lport *);
|
||||
+extern void fc_fc4_del_lport(struct fc_lport *);
|
||||
|
||||
/*
|
||||
* Copies a buffer into an sg list
|
||||
diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c
|
||||
index b05329c..375a2a7 100644
|
||||
--- a/drivers/scsi/libfc/fc_lport.c
|
||||
+++ b/drivers/scsi/libfc/fc_lport.c
|
||||
@@ -647,6 +647,7 @@ int fc_lport_destroy(struct fc_lport *lport)
|
||||
lport->tt.fcp_abort_io(lport);
|
||||
lport->tt.disc_stop_final(lport);
|
||||
lport->tt.exch_mgr_reset(lport, 0, 0);
|
||||
+ fc_fc4_del_lport(lport);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(fc_lport_destroy);
|
||||
@@ -1639,6 +1640,7 @@ int fc_lport_init(struct fc_lport *lport)
|
||||
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_1GBIT;
|
||||
if (lport->link_supported_speeds & FC_PORTSPEED_10GBIT)
|
||||
fc_host_supported_speeds(lport->host) |= FC_PORTSPEED_10GBIT;
|
||||
+ fc_fc4_add_lport(lport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
|
||||
index 9d7c8e3..2fa3538 100644
|
||||
--- a/include/scsi/libfc.h
|
||||
+++ b/include/scsi/libfc.h
|
||||
@@ -775,6 +775,15 @@ struct fc_disc {
|
||||
enum fc_disc_event);
|
||||
};
|
||||
|
||||
+/*
|
||||
+ * Local port notifier and events.
|
||||
+ */
|
||||
+extern struct blocking_notifier_head fc_lport_notifier_head;
|
||||
+enum fc_lport_event {
|
||||
+ FC_LPORT_EV_ADD,
|
||||
+ FC_LPORT_EV_DEL,
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct fc_lport - Local port
|
||||
* @host: The SCSI host associated with a local port
|
||||
@@ -814,8 +823,9 @@ struct fc_disc {
|
||||
* @lso_max: The maximum large offload send size
|
||||
* @fcts: FC-4 type mask
|
||||
* @lp_mutex: Mutex to protect the local port
|
||||
- * @list: Handle for list of local ports
|
||||
+ * @list: Linkage on list of vport peers
|
||||
* @retry_work: Handle to local port for delayed retry context
|
||||
+ * @lport_list: Linkage on module-wide list of local ports
|
||||
* @prov: Pointers available for use by passive FC-4 providers
|
||||
*/
|
||||
struct fc_lport {
|
||||
@@ -870,6 +880,7 @@ struct fc_lport {
|
||||
struct mutex lp_mutex;
|
||||
struct list_head list;
|
||||
struct delayed_work retry_work;
|
||||
+ struct list_head lport_list;
|
||||
void *prov[FC_FC4_PROV_SIZE];
|
||||
};
|
||||
|
||||
@@ -1024,6 +1035,7 @@ int fc_set_mfs(struct fc_lport *, u32 mfs);
|
||||
struct fc_lport *libfc_vport_create(struct fc_vport *, int privsize);
|
||||
struct fc_lport *fc_vport_id_lookup(struct fc_lport *, u32 port_id);
|
||||
int fc_lport_bsg_request(struct fc_bsg_job *);
|
||||
+void fc_lport_iterate(void (*func)(struct fc_lport *, void *), void *);
|
||||
|
||||
/*
|
||||
* REMOTE PORT LAYER
|
||||
@@ -0,0 +1,6 @@
|
||||
# applies to 2.6.35
|
||||
15-fc4
|
||||
16-seq-set-resp
|
||||
17-lport-hook
|
||||
18-lport-notify
|
||||
14-fc-frame-sparse-workaround
|
||||
Reference in New Issue
Block a user