[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 <jeykholt@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
Joe Eykholt
2011-01-28 16:04:02 -08:00
zatwierdzone przez James Bottomley
rodzic 55204909bb
commit 96ad846445
5 zmienionych plików z 258 dodań i 35 usunięć

Wyświetl plik

@@ -35,6 +35,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
*/
@@ -210,3 +227,46 @@ void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
}
EXPORT_SYMBOL(fc_fill_reply_hdr);
/**
* 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);