From 96ad846445ae33dcae1805b68752e3d5c840e3ed Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 28 Jan 2011 16:04:02 -0800 Subject: [SCSI] 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 Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 65 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 9 deletions(-) (limited to 'drivers/scsi/libfc/fc_lport.c') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index c5a10f94f845..e2cd087e71b2 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -849,7 +849,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 * @fp: The request frame * @@ -859,9 +859,9 @@ 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_frame *fp) +static void fc_lport_recv_els_req(struct fc_lport *lport, + struct fc_frame *fp) { - struct fc_frame_header *fh = fc_frame_header_get(fp); void (*recv)(struct fc_lport *, struct fc_frame *); mutex_lock(&lport->lp_mutex); @@ -873,8 +873,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) */ 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. */ @@ -903,14 +902,62 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) } recv(lport, fp); - } else { - FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n", - fr_eof(fp)); - fc_frame_free(fp); } mutex_unlock(&lport->lp_mutex); } +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 + * @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_frame *fp) +{ + struct fc_frame_header *fh = fc_frame_header_get(fp); + struct fc_seq *sp = fr_seq(fp); + struct fc4_prov *prov; + + /* + * 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, 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); +} + /** * fc_lport_reset() - Reset a local port * @lport: The local port which should be reset -- cgit v1.2.1 From 70d53b046a6221e3ceb3bd8eaa807ef6a1c53762 Mon Sep 17 00:00:00 2001 From: Joe Eykholt Date: Fri, 28 Jan 2011 16:04:18 -0800 Subject: [SCSI] 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 Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/scsi/libfc/fc_lport.c') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e2cd087e71b2..e0ef81426c33 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -633,6 +633,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); @@ -1633,6 +1634,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; } -- cgit v1.2.1 From acc1a921659561c4ea97eca6e3c2633adecbcd81 Mon Sep 17 00:00:00 2001 From: Kiran Patil Date: Fri, 28 Jan 2011 16:05:22 -0800 Subject: [SCSI] libfc: Extending lport's roles for target if there is a registered target. Problem: From initaitor machine, when queried role of target (other end of connection), it is "initiator", hence SCSI-ml doesn't send any LUN Inquiry commands. Fix: If there is a registered target for FC_TYPE_FCP, extend lport's params (capability) to be target as well, By default lport params are INITIATOR only. Having this fix, caused initiator to send SCSI LUN inquiry command to target. Signed-off-by: Kiran Patil Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi/libfc/fc_lport.c') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index e0ef81426c33..735f1f82ccfd 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1597,6 +1597,7 @@ int fc_lport_config(struct fc_lport *lport) fc_lport_add_fc4_type(lport, FC_TYPE_FCP); fc_lport_add_fc4_type(lport, FC_TYPE_CT); + fc_fc4_conf_lport_params(lport, FC_TYPE_FCP); return 0; } -- cgit v1.2.1 From 72fa396bf57b31e8e2a401a21a3a088c0cc6b043 Mon Sep 17 00:00:00 2001 From: Vasu Dev Date: Fri, 25 Feb 2011 15:03:01 -0800 Subject: [SCSI] fcoe, libfc: initialize EM anchors list and then update npiv EMs EM anchors list initialization for only master port was not enough to keep npiv working as described here:- https://lists.open-fcoe.org/pipermail/devel/2011-January/011063.html So this patch moves fc_exch_mgr_list_clone to update npiv ports EMs once EM anchors list initialized. Also some cleanup, no need to set lport = NULL as that always get initialized later. Signed-off-by: Vasu Dev Signed-off-by: Robert Love Signed-off-by: James Bottomley --- drivers/scsi/libfc/fc_lport.c | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers/scsi/libfc/fc_lport.c') diff --git a/drivers/scsi/libfc/fc_lport.c b/drivers/scsi/libfc/fc_lport.c index 735f1f82ccfd..8c08b210001d 100644 --- a/drivers/scsi/libfc/fc_lport.c +++ b/drivers/scsi/libfc/fc_lport.c @@ -1590,6 +1590,7 @@ void fc_lport_enter_flogi(struct fc_lport *lport) */ int fc_lport_config(struct fc_lport *lport) { + INIT_LIST_HEAD(&lport->ema_list); INIT_DELAYED_WORK(&lport->retry_work, fc_lport_timeout); mutex_init(&lport->lp_mutex); -- cgit v1.2.1