aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoe Eykholt <jeykholt@cisco.com>2011-01-28 19:04:02 -0500
committerJames Bottomley <James.Bottomley@suse.de>2011-02-12 12:00:40 -0500
commit96ad846445ae33dcae1805b68752e3d5c840e3ed (patch)
treee73ea227c24d90654d58f0cfbec00f689bdac081
parent55204909bb687c997d5601e9f24a25cf9e915d78 (diff)
[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>
-rw-r--r--drivers/scsi/libfc/fc_libfc.c60
-rw-r--r--drivers/scsi/libfc/fc_libfc.h11
-rw-r--r--drivers/scsi/libfc/fc_lport.c65
-rw-r--r--drivers/scsi/libfc/fc_rport.c133
-rw-r--r--include/scsi/libfc.h26
5 files changed, 259 insertions, 36 deletions
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index 6a48c28e442..ae3abef6523 100644
--- a/drivers/scsi/libfc/fc_libfc.c
+++ b/drivers/scsi/libfc/fc_libfc.c
@@ -35,6 +35,23 @@ unsigned int fc_debug_logging;
35module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR); 35module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
36MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels"); 36MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
37 37
38DEFINE_MUTEX(fc_prov_mutex);
39
40/*
41 * Providers which primarily send requests and PRLIs.
42 */
43struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
44 [0] = &fc_rport_t0_prov,
45 [FC_TYPE_FCP] = &fc_rport_fcp_init,
46};
47
48/*
49 * Providers which receive requests.
50 */
51struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
52 [FC_TYPE_ELS] = &fc_lport_els_prov,
53};
54
38/** 55/**
39 * libfc_init() - Initialize libfc.ko 56 * libfc_init() - Initialize libfc.ko
40 */ 57 */
@@ -210,3 +227,46 @@ void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
210 fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset); 227 fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
211} 228}
212EXPORT_SYMBOL(fc_fill_reply_hdr); 229EXPORT_SYMBOL(fc_fill_reply_hdr);
230
231/**
232 * fc_fc4_register_provider() - register FC-4 upper-level provider.
233 * @type: FC-4 type, such as FC_TYPE_FCP
234 * @prov: structure describing provider including ops vector.
235 *
236 * Returns 0 on success, negative error otherwise.
237 */
238int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
239{
240 struct fc4_prov **prov_entry;
241 int ret = 0;
242
243 if (type >= FC_FC4_PROV_SIZE)
244 return -EINVAL;
245 mutex_lock(&fc_prov_mutex);
246 prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
247 if (*prov_entry)
248 ret = -EBUSY;
249 else
250 *prov_entry = prov;
251 mutex_unlock(&fc_prov_mutex);
252 return ret;
253}
254EXPORT_SYMBOL(fc_fc4_register_provider);
255
256/**
257 * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
258 * @type: FC-4 type, such as FC_TYPE_FCP
259 * @prov: structure describing provider including ops vector.
260 */
261void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
262{
263 BUG_ON(type >= FC_FC4_PROV_SIZE);
264 mutex_lock(&fc_prov_mutex);
265 if (prov->recv)
266 rcu_assign_pointer(fc_passive_prov[type], NULL);
267 else
268 rcu_assign_pointer(fc_active_prov[type], NULL);
269 mutex_unlock(&fc_prov_mutex);
270 synchronize_rcu();
271}
272EXPORT_SYMBOL(fc_fc4_deregister_provider);
diff --git a/drivers/scsi/libfc/fc_libfc.h b/drivers/scsi/libfc/fc_libfc.h
index eea0c3541b7..205de285e45 100644
--- a/drivers/scsi/libfc/fc_libfc.h
+++ b/drivers/scsi/libfc/fc_libfc.h
@@ -94,6 +94,17 @@ extern unsigned int fc_debug_logging;
94 (lport)->host->host_no, ##args)) 94 (lport)->host->host_no, ##args))
95 95
96/* 96/*
97 * FC-4 Providers.
98 */
99extern struct fc4_prov *fc_active_prov[]; /* providers without recv */
100extern struct fc4_prov *fc_passive_prov[]; /* providers with recv */
101extern struct mutex fc_prov_mutex; /* lock over table changes */
102
103extern struct fc4_prov fc_rport_t0_prov; /* type 0 provider */
104extern struct fc4_prov fc_lport_els_prov; /* ELS provider */
105extern struct fc4_prov fc_rport_fcp_init; /* FCP initiator provider */
106
107/*
97 * Set up direct-data placement for this I/O request 108 * Set up direct-data placement for this I/O request
98 */ 109 */
99void fc_fcp_ddp_setup(struct fc_fcp_pkt *fsp, u16 xid); 110void 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 c5a10f94f84..e2cd087e71b 100644
--- a/drivers/scsi/libfc/fc_lport.c
+++ b/drivers/scsi/libfc/fc_lport.c
@@ -849,7 +849,7 @@ out:
849} 849}
850 850
851/** 851/**
852 * fc_lport_recv_req() - The generic lport request handler 852 * fc_lport_recv_els_req() - The generic lport ELS request handler
853 * @lport: The local port that received the request 853 * @lport: The local port that received the request
854 * @fp: The request frame 854 * @fp: The request frame
855 * 855 *
@@ -859,9 +859,9 @@ out:
859 * Locking Note: This function should not be called with the lport 859 * Locking Note: This function should not be called with the lport
860 * lock held becuase it will grab the lock. 860 * lock held becuase it will grab the lock.
861 */ 861 */
862static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp) 862static void fc_lport_recv_els_req(struct fc_lport *lport,
863 struct fc_frame *fp)
863{ 864{
864 struct fc_frame_header *fh = fc_frame_header_get(fp);
865 void (*recv)(struct fc_lport *, struct fc_frame *); 865 void (*recv)(struct fc_lport *, struct fc_frame *);
866 866
867 mutex_lock(&lport->lp_mutex); 867 mutex_lock(&lport->lp_mutex);
@@ -873,8 +873,7 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
873 */ 873 */
874 if (!lport->link_up) 874 if (!lport->link_up)
875 fc_frame_free(fp); 875 fc_frame_free(fp);
876 else if (fh->fh_type == FC_TYPE_ELS && 876 else {
877 fh->fh_r_ctl == FC_RCTL_ELS_REQ) {
878 /* 877 /*
879 * Check opcode. 878 * Check opcode.
880 */ 879 */
@@ -903,14 +902,62 @@ static void fc_lport_recv_req(struct fc_lport *lport, struct fc_frame *fp)
903 } 902 }
904 903
905 recv(lport, fp); 904 recv(lport, fp);
906 } else {
907 FC_LPORT_DBG(lport, "dropping invalid frame (eof %x)\n",
908 fr_eof(fp));
909 fc_frame_free(fp);
910 } 905 }
911 mutex_unlock(&lport->lp_mutex); 906 mutex_unlock(&lport->lp_mutex);
912} 907}
913 908
909static int fc_lport_els_prli(struct fc_rport_priv *rdata, u32 spp_len,
910 const struct fc_els_spp *spp_in,
911 struct fc_els_spp *spp_out)
912{
913 return FC_SPP_RESP_INVL;
914}
915
916struct fc4_prov fc_lport_els_prov = {
917 .prli = fc_lport_els_prli,
918 .recv = fc_lport_recv_els_req,
919};
920
921/**
922 * fc_lport_recv_req() - The generic lport request handler
923 * @lport: The lport that received the request
924 * @fp: The frame the request is in
925 *
926 * Locking Note: This function should not be called with the lport
927 * lock held becuase it may grab the lock.
928 */
929static void fc_lport_recv_req(struct fc_lport *lport,
930 struct fc_frame *fp)
931{
932 struct fc_frame_header *fh = fc_frame_header_get(fp);
933 struct fc_seq *sp = fr_seq(fp);
934 struct fc4_prov *prov;
935
936 /*
937 * Use RCU read lock and module_lock to be sure module doesn't
938 * deregister and get unloaded while we're calling it.
939 * try_module_get() is inlined and accepts a NULL parameter.
940 * Only ELSes and FCP target ops should come through here.
941 * The locking is unfortunate, and a better scheme is being sought.
942 */
943
944 rcu_read_lock();
945 if (fh->fh_type >= FC_FC4_PROV_SIZE)
946 goto drop;
947 prov = rcu_dereference(fc_passive_prov[fh->fh_type]);
948 if (!prov || !try_module_get(prov->module))
949 goto drop;
950 rcu_read_unlock();
951 prov->recv(lport, fp);
952 module_put(prov->module);
953 return;
954drop:
955 rcu_read_unlock();
956 FC_LPORT_DBG(lport, "dropping unexpected frame type %x\n", fh->fh_type);
957 fc_frame_free(fp);
958 lport->tt.exch_done(sp);
959}
960
914/** 961/**
915 * fc_lport_reset() - Reset a local port 962 * fc_lport_reset() - Reset a local port
916 * @lport: The local port which should be reset 963 * @lport: The local port which should be reset
diff --git a/drivers/scsi/libfc/fc_rport.c b/drivers/scsi/libfc/fc_rport.c
index 309e3e713ea..a92954c1f42 100644
--- a/drivers/scsi/libfc/fc_rport.c
+++ b/drivers/scsi/libfc/fc_rport.c
@@ -257,6 +257,8 @@ static void fc_rport_work(struct work_struct *work)
257 struct fc_rport_operations *rport_ops; 257 struct fc_rport_operations *rport_ops;
258 struct fc_rport_identifiers ids; 258 struct fc_rport_identifiers ids;
259 struct fc_rport *rport; 259 struct fc_rport *rport;
260 struct fc4_prov *prov;
261 u8 type;
260 262
261 mutex_lock(&rdata->rp_mutex); 263 mutex_lock(&rdata->rp_mutex);
262 event = rdata->event; 264 event = rdata->event;
@@ -306,6 +308,15 @@ static void fc_rport_work(struct work_struct *work)
306 case RPORT_EV_FAILED: 308 case RPORT_EV_FAILED:
307 case RPORT_EV_LOGO: 309 case RPORT_EV_LOGO:
308 case RPORT_EV_STOP: 310 case RPORT_EV_STOP:
311 if (rdata->prli_count) {
312 mutex_lock(&fc_prov_mutex);
313 for (type = 1; type < FC_FC4_PROV_SIZE; type++) {
314 prov = fc_passive_prov[type];
315 if (prov && prov->prlo)
316 prov->prlo(rdata);
317 }
318 mutex_unlock(&fc_prov_mutex);
319 }
309 port_id = rdata->ids.port_id; 320 port_id = rdata->ids.port_id;
310 mutex_unlock(&rdata->rp_mutex); 321 mutex_unlock(&rdata->rp_mutex);
311 322
@@ -1643,9 +1654,9 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
1643 unsigned int len; 1654 unsigned int len;
1644 unsigned int plen; 1655 unsigned int plen;
1645 enum fc_els_spp_resp resp; 1656 enum fc_els_spp_resp resp;
1657 enum fc_els_spp_resp passive;
1646 struct fc_seq_els_data rjt_data; 1658 struct fc_seq_els_data rjt_data;
1647 u32 fcp_parm; 1659 struct fc4_prov *prov;
1648 u32 roles = FC_RPORT_ROLE_UNKNOWN;
1649 1660
1650 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n", 1661 FC_RPORT_DBG(rdata, "Received PRLI request while in state %s\n",
1651 fc_rport_state(rdata)); 1662 fc_rport_state(rdata));
@@ -1679,46 +1690,41 @@ static void fc_rport_recv_prli_req(struct fc_rport_priv *rdata,
1679 pp->prli.prli_len = htons(len); 1690 pp->prli.prli_len = htons(len);
1680 len -= sizeof(struct fc_els_prli); 1691 len -= sizeof(struct fc_els_prli);
1681 1692
1682 /* reinitialize remote port roles */
1683 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1684
1685 /* 1693 /*
1686 * Go through all the service parameter pages and build 1694 * Go through all the service parameter pages and build
1687 * response. If plen indicates longer SPP than standard, 1695 * response. If plen indicates longer SPP than standard,
1688 * use that. The entire response has been pre-cleared above. 1696 * use that. The entire response has been pre-cleared above.
1689 */ 1697 */
1690 spp = &pp->spp; 1698 spp = &pp->spp;
1699 mutex_lock(&fc_prov_mutex);
1691 while (len >= plen) { 1700 while (len >= plen) {
1692 spp->spp_type = rspp->spp_type; 1701 spp->spp_type = rspp->spp_type;
1693 spp->spp_type_ext = rspp->spp_type_ext; 1702 spp->spp_type_ext = rspp->spp_type_ext;
1694 spp->spp_flags = rspp->spp_flags & FC_SPP_EST_IMG_PAIR; 1703 resp = 0;
1695 resp = FC_SPP_RESP_ACK; 1704
1696 1705 if (rspp->spp_type < FC_FC4_PROV_SIZE) {
1697 switch (rspp->spp_type) { 1706 prov = fc_active_prov[rspp->spp_type];
1698 case 0: /* common to all FC-4 types */ 1707 if (prov)
1699 break; 1708 resp = prov->prli(rdata, plen, rspp, spp);
1700 case FC_TYPE_FCP: 1709 prov = fc_passive_prov[rspp->spp_type];
1701 fcp_parm = ntohl(rspp->spp_params); 1710 if (prov) {
1702 if (fcp_parm & FCP_SPPF_RETRY) 1711 passive = prov->prli(rdata, plen, rspp, spp);
1703 rdata->flags |= FC_RP_FLAGS_RETRY; 1712 if (!resp || passive == FC_SPP_RESP_ACK)
1704 rdata->supported_classes = FC_COS_CLASS3; 1713 resp = passive;
1705 if (fcp_parm & FCP_SPPF_INIT_FCN) 1714 }
1706 roles |= FC_RPORT_ROLE_FCP_INITIATOR; 1715 }
1707 if (fcp_parm & FCP_SPPF_TARG_FCN) 1716 if (!resp) {
1708 roles |= FC_RPORT_ROLE_FCP_TARGET; 1717 if (spp->spp_flags & FC_SPP_EST_IMG_PAIR)
1709 rdata->ids.roles = roles; 1718 resp |= FC_SPP_RESP_CONF;
1710 1719 else
1711 spp->spp_params = htonl(lport->service_params); 1720 resp |= FC_SPP_RESP_INVL;
1712 break;
1713 default:
1714 resp = FC_SPP_RESP_INVL;
1715 break;
1716 } 1721 }
1717 spp->spp_flags |= resp; 1722 spp->spp_flags |= resp;
1718 len -= plen; 1723 len -= plen;
1719 rspp = (struct fc_els_spp *)((char *)rspp + plen); 1724 rspp = (struct fc_els_spp *)((char *)rspp + plen);
1720 spp = (struct fc_els_spp *)((char *)spp + plen); 1725 spp = (struct fc_els_spp *)((char *)spp + plen);
1721 } 1726 }
1727 mutex_unlock(&fc_prov_mutex);
1722 1728
1723 /* 1729 /*
1724 * Send LS_ACC. If this fails, the originator should retry. 1730 * Send LS_ACC. If this fails, the originator should retry.
@@ -1888,6 +1894,79 @@ int fc_rport_init(struct fc_lport *lport)
1888EXPORT_SYMBOL(fc_rport_init); 1894EXPORT_SYMBOL(fc_rport_init);
1889 1895
1890/** 1896/**
1897 * fc_rport_fcp_prli() - Handle incoming PRLI for the FCP initiator.
1898 * @rdata: remote port private
1899 * @spp_len: service parameter page length
1900 * @rspp: received service parameter page
1901 * @spp: response service parameter page
1902 *
1903 * Returns the value for the response code to be placed in spp_flags;
1904 * Returns 0 if not an initiator.
1905 */
1906static int fc_rport_fcp_prli(struct fc_rport_priv *rdata, u32 spp_len,
1907 const struct fc_els_spp *rspp,
1908 struct fc_els_spp *spp)
1909{
1910 struct fc_lport *lport = rdata->local_port;
1911 u32 fcp_parm;
1912
1913 fcp_parm = ntohl(rspp->spp_params);
1914 rdata->ids.roles = FC_RPORT_ROLE_UNKNOWN;
1915 if (fcp_parm & FCP_SPPF_INIT_FCN)
1916 rdata->ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR;
1917 if (fcp_parm & FCP_SPPF_TARG_FCN)
1918 rdata->ids.roles |= FC_RPORT_ROLE_FCP_TARGET;
1919 if (fcp_parm & FCP_SPPF_RETRY)
1920 rdata->flags |= FC_RP_FLAGS_RETRY;
1921 rdata->supported_classes = FC_COS_CLASS3;
1922
1923 if (!(lport->service_params & FC_RPORT_ROLE_FCP_INITIATOR))
1924 return 0;
1925
1926 spp->spp_flags |= rspp->spp_flags & FC_SPP_EST_IMG_PAIR;
1927
1928 /*
1929 * OR in our service parameters with other providers (target), if any.
1930 */
1931 fcp_parm = ntohl(spp->spp_params);
1932 spp->spp_params = htonl(fcp_parm | lport->service_params);
1933 return FC_SPP_RESP_ACK;
1934}
1935
1936/*
1937 * FC-4 provider ops for FCP initiator.
1938 */
1939struct fc4_prov fc_rport_fcp_init = {
1940 .prli = fc_rport_fcp_prli,
1941};
1942
1943/**
1944 * fc_rport_t0_prli() - Handle incoming PRLI parameters for type 0
1945 * @rdata: remote port private
1946 * @spp_len: service parameter page length
1947 * @rspp: received service parameter page
1948 * @spp: response service parameter page
1949 */
1950static int fc_rport_t0_prli(struct fc_rport_priv *rdata, u32 spp_len,
1951 const struct fc_els_spp *rspp,
1952 struct fc_els_spp *spp)
1953{
1954 if (rspp->spp_flags & FC_SPP_EST_IMG_PAIR)
1955 return FC_SPP_RESP_INVL;
1956 return FC_SPP_RESP_ACK;
1957}
1958
1959/*
1960 * FC-4 provider ops for type 0 service parameters.
1961 *
1962 * This handles the special case of type 0 which is always successful
1963 * but doesn't do anything otherwise.
1964 */
1965struct fc4_prov fc_rport_t0_prov = {
1966 .prli = fc_rport_t0_prli,
1967};
1968
1969/**
1891 * fc_setup_rport() - Initialize the rport_event_queue 1970 * fc_setup_rport() - Initialize the rport_event_queue
1892 */ 1971 */
1893int fc_setup_rport(void) 1972int fc_setup_rport(void)
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index f53c8e31d5f..3ae2a760b4f 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -35,6 +35,8 @@
35 35
36#include <scsi/fc_frame.h> 36#include <scsi/fc_frame.h>
37 37
38#define FC_FC4_PROV_SIZE (FC_TYPE_FCP + 1) /* size of tables */
39
38/* 40/*
39 * libfc error codes 41 * libfc error codes
40 */ 42 */
@@ -179,6 +181,7 @@ struct fc_rport_libfc_priv {
179 * @rp_mutex: The mutex that protects the remote port 181 * @rp_mutex: The mutex that protects the remote port
180 * @retry_work: Handle for retries 182 * @retry_work: Handle for retries
181 * @event_callback: Callback when READY, FAILED or LOGO states complete 183 * @event_callback: Callback when READY, FAILED or LOGO states complete
184 * @prli_count: Count of open PRLI sessions in providers
182 * @rcu: Structure used for freeing in an RCU-safe manner 185 * @rcu: Structure used for freeing in an RCU-safe manner
183 */ 186 */
184struct fc_rport_priv { 187struct fc_rport_priv {
@@ -202,6 +205,7 @@ struct fc_rport_priv {
202 struct list_head peers; 205 struct list_head peers;
203 struct work_struct event_work; 206 struct work_struct event_work;
204 u32 supported_classes; 207 u32 supported_classes;
208 u16 prli_count;
205 struct rcu_head rcu; 209 struct rcu_head rcu;
206}; 210};
207 211
@@ -848,6 +852,28 @@ struct fc_lport {
848 struct delayed_work retry_work; 852 struct delayed_work retry_work;
849}; 853};
850 854
855/**
856 * struct fc4_prov - FC-4 provider registration
857 * @prli: Handler for incoming PRLI
858 * @prlo: Handler for session reset
859 * @recv: Handler for incoming request
860 * @module: Pointer to module. May be NULL.
861 */
862struct fc4_prov {
863 int (*prli)(struct fc_rport_priv *, u32 spp_len,
864 const struct fc_els_spp *spp_in,
865 struct fc_els_spp *spp_out);
866 void (*prlo)(struct fc_rport_priv *);
867 void (*recv)(struct fc_lport *, struct fc_frame *);
868 struct module *module;
869};
870
871/*
872 * Register FC-4 provider with libfc.
873 */
874int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *);
875void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *);
876
851/* 877/*
852 * FC_LPORT HELPER FUNCTIONS 878 * FC_LPORT HELPER FUNCTIONS
853 *****************************/ 879 *****************************/