aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-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
4 files changed, 233 insertions, 36 deletions
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c
index 6a48c28e4420..ae3abef6523e 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 eea0c3541b71..205de285e456 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 c5a10f94f845..e2cd087e71b2 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 309e3e713ea1..a92954c1f42f 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)