1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/kernel.h>
21#include <linux/types.h>
22#include <linux/scatterlist.h>
23#include <linux/crc32.h>
24
25#include <scsi/libfc.h>
26#include <scsi/fc_encode.h>
27
28#include "fc_libfc.h"
29
30MODULE_AUTHOR("Open-FCoE.org");
31MODULE_DESCRIPTION("libfc");
32MODULE_LICENSE("GPL v2");
33
34unsigned int fc_debug_logging;
35module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
36MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
37
38DEFINE_MUTEX(fc_prov_mutex);
39static LIST_HEAD(fc_local_ports);
40struct blocking_notifier_head fc_lport_notifier_head =
41 BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
42EXPORT_SYMBOL(fc_lport_notifier_head);
43
44
45
46
47struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
48 [0] = &fc_rport_t0_prov,
49 [FC_TYPE_FCP] = &fc_rport_fcp_init,
50};
51
52
53
54
55struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
56 [FC_TYPE_ELS] = &fc_lport_els_prov,
57};
58
59
60
61
62static int __init libfc_init(void)
63{
64 int rc = 0;
65
66 rc = fc_setup_fcp();
67 if (rc)
68 return rc;
69
70 rc = fc_setup_exch_mgr();
71 if (rc)
72 goto destroy_pkt_cache;
73
74 rc = fc_setup_rport();
75 if (rc)
76 goto destroy_em;
77
78 return rc;
79destroy_em:
80 fc_destroy_exch_mgr();
81destroy_pkt_cache:
82 fc_destroy_fcp();
83 return rc;
84}
85module_init(libfc_init);
86
87
88
89
90static void __exit libfc_exit(void)
91{
92 fc_destroy_fcp();
93 fc_destroy_exch_mgr();
94 fc_destroy_rport();
95}
96module_exit(libfc_exit);
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
112 struct scatterlist *sg,
113 u32 *nents, size_t *offset,
114 enum km_type km_type, u32 *crc)
115{
116 size_t remaining = len;
117 u32 copy_len = 0;
118
119 while (remaining > 0 && sg) {
120 size_t off, sg_bytes;
121 void *page_addr;
122
123 if (*offset >= sg->length) {
124
125
126
127
128 if (!(*nents))
129 break;
130 --(*nents);
131 *offset -= sg->length;
132 sg = sg_next(sg);
133 continue;
134 }
135 sg_bytes = min(remaining, sg->length - *offset);
136
137
138
139
140
141 off = *offset + sg->offset;
142 sg_bytes = min(sg_bytes,
143 (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
144 page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT),
145 km_type);
146 if (crc)
147 *crc = crc32(*crc, buf, sg_bytes);
148 memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
149 kunmap_atomic(page_addr, km_type);
150 buf += sg_bytes;
151 *offset += sg_bytes;
152 remaining -= sg_bytes;
153 copy_len += sg_bytes;
154 }
155 return copy_len;
156}
157
158
159
160
161
162
163
164
165
166
167void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
168 enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
169{
170 struct fc_frame_header *fh;
171 struct fc_frame_header *in_fh;
172 struct fc_seq *sp;
173 u32 fill;
174
175 fh = __fc_frame_header_get(fp);
176 in_fh = __fc_frame_header_get(in_fp);
177
178 if (f_ctl & FC_FC_END_SEQ) {
179 fill = -fr_len(fp) & 3;
180 if (fill) {
181
182 memset(skb_put(fp_skb(fp), fill), 0, fill);
183 f_ctl |= fill;
184 }
185 fr_eof(fp) = FC_EOF_T;
186 } else {
187 WARN_ON(fr_len(fp) % 4 != 0);
188 fr_eof(fp) = FC_EOF_N;
189 }
190
191 fh->fh_r_ctl = r_ctl;
192 memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
193 memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
194 fh->fh_type = in_fh->fh_type;
195 hton24(fh->fh_f_ctl, f_ctl);
196 fh->fh_ox_id = in_fh->fh_ox_id;
197 fh->fh_rx_id = in_fh->fh_rx_id;
198 fh->fh_cs_ctl = 0;
199 fh->fh_df_ctl = 0;
200 fh->fh_parm_offset = htonl(parm_offset);
201
202 sp = fr_seq(in_fp);
203 if (sp) {
204 fr_seq(fp) = sp;
205 fh->fh_seq_id = sp->id;
206 seq_cnt = sp->cnt;
207 } else {
208 fh->fh_seq_id = 0;
209 }
210 fh->fh_seq_cnt = ntohs(seq_cnt);
211 fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
212 fr_encaps(fp) = fr_encaps(in_fp);
213}
214EXPORT_SYMBOL(fc_fill_hdr);
215
216
217
218
219
220
221
222
223void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
224 enum fc_rctl r_ctl, u32 parm_offset)
225{
226 struct fc_seq *sp;
227
228 sp = fr_seq(in_fp);
229 if (sp)
230 fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp);
231 fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
232}
233EXPORT_SYMBOL(fc_fill_reply_hdr);
234
235
236
237
238
239
240
241
242void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type)
243{
244 struct fc4_prov *prov_entry;
245 BUG_ON(type >= FC_FC4_PROV_SIZE);
246 BUG_ON(!lport);
247 prov_entry = fc_passive_prov[type];
248 if (type == FC_TYPE_FCP) {
249 if (prov_entry && prov_entry->recv)
250 lport->service_params |= FCP_SPPF_TARG_FCN;
251 }
252}
253
254void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
255{
256 struct fc_lport *lport;
257
258 mutex_lock(&fc_prov_mutex);
259 list_for_each_entry(lport, &fc_local_ports, lport_list)
260 notify(lport, arg);
261 mutex_unlock(&fc_prov_mutex);
262}
263EXPORT_SYMBOL(fc_lport_iterate);
264
265
266
267
268
269
270
271
272int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
273{
274 struct fc4_prov **prov_entry;
275 int ret = 0;
276
277 if (type >= FC_FC4_PROV_SIZE)
278 return -EINVAL;
279 mutex_lock(&fc_prov_mutex);
280 prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
281 if (*prov_entry)
282 ret = -EBUSY;
283 else
284 *prov_entry = prov;
285 mutex_unlock(&fc_prov_mutex);
286 return ret;
287}
288EXPORT_SYMBOL(fc_fc4_register_provider);
289
290
291
292
293
294
295void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
296{
297 BUG_ON(type >= FC_FC4_PROV_SIZE);
298 mutex_lock(&fc_prov_mutex);
299 if (prov->recv)
300 rcu_assign_pointer(fc_passive_prov[type], NULL);
301 else
302 rcu_assign_pointer(fc_active_prov[type], NULL);
303 mutex_unlock(&fc_prov_mutex);
304 synchronize_rcu();
305}
306EXPORT_SYMBOL(fc_fc4_deregister_provider);
307
308
309
310
311
312void fc_fc4_add_lport(struct fc_lport *lport)
313{
314 mutex_lock(&fc_prov_mutex);
315 list_add_tail(&lport->lport_list, &fc_local_ports);
316 blocking_notifier_call_chain(&fc_lport_notifier_head,
317 FC_LPORT_EV_ADD, lport);
318 mutex_unlock(&fc_prov_mutex);
319}
320
321
322
323
324
325void fc_fc4_del_lport(struct fc_lport *lport)
326{
327 mutex_lock(&fc_prov_mutex);
328 list_del(&lport->lport_list);
329 blocking_notifier_call_chain(&fc_lport_notifier_head,
330 FC_LPORT_EV_DEL, lport);
331 mutex_unlock(&fc_prov_mutex);
332}
333