From 5d84242673d67afb10b6ab2dbe5e87a1c669f09e Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Tue, 3 Aug 2010 18:04:36 +0000 Subject: [PATCH] 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 --- fcst/linux-patches/15-fc4 | 487 +++++++++++++++++++++++++++++ fcst/linux-patches/16-seq-set-resp | 84 +++++ fcst/linux-patches/17-lport-hook | 36 +++ fcst/linux-patches/18-lport-notify | 167 ++++++++++ fcst/linux-patches/series-2.6.35 | 6 + 5 files changed, 780 insertions(+) create mode 100644 fcst/linux-patches/15-fc4 create mode 100644 fcst/linux-patches/16-seq-set-resp create mode 100644 fcst/linux-patches/17-lport-hook create mode 100644 fcst/linux-patches/18-lport-notify create mode 100644 fcst/linux-patches/series-2.6.35 diff --git a/fcst/linux-patches/15-fc4 b/fcst/linux-patches/15-fc4 new file mode 100644 index 000000000..64c7a7723 --- /dev/null +++ b/fcst/linux-patches/15-fc4 @@ -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 + +--- + 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 + ++#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 + *****************************/ diff --git a/fcst/linux-patches/16-seq-set-resp b/fcst/linux-patches/16-seq-set-resp new file mode 100644 index 000000000..00abbb863 --- /dev/null +++ b/fcst/linux-patches/16-seq-set-resp @@ -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 + +--- + 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 + *****************************/ diff --git a/fcst/linux-patches/17-lport-hook b/fcst/linux-patches/17-lport-hook new file mode 100644 index 000000000..303ada0d7 --- /dev/null +++ b/fcst/linux-patches/17-lport-hook @@ -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 + +--- + 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]; + }; + + /** diff --git a/fcst/linux-patches/18-lport-notify b/fcst/linux-patches/18-lport-notify new file mode 100644 index 000000000..23c9dd1c0 --- /dev/null +++ b/fcst/linux-patches/18-lport-notify @@ -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 + +--- + 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 diff --git a/fcst/linux-patches/series-2.6.35 b/fcst/linux-patches/series-2.6.35 new file mode 100644 index 000000000..64a91b5e2 --- /dev/null +++ b/fcst/linux-patches/series-2.6.35 @@ -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