0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/kernel.h>
0009 #include <linux/types.h>
0010 #include <linux/scatterlist.h>
0011 #include <linux/crc32.h>
0012 #include <linux/module.h>
0013
0014 #include <scsi/libfc.h>
0015
0016 #include "fc_encode.h"
0017 #include "fc_libfc.h"
0018
0019 MODULE_AUTHOR("Open-FCoE.org");
0020 MODULE_DESCRIPTION("libfc");
0021 MODULE_LICENSE("GPL v2");
0022
0023 unsigned int fc_debug_logging;
0024 module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
0025 MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
0026
0027 DEFINE_MUTEX(fc_prov_mutex);
0028 static LIST_HEAD(fc_local_ports);
0029 struct blocking_notifier_head fc_lport_notifier_head =
0030 BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
0031 EXPORT_SYMBOL(fc_lport_notifier_head);
0032
0033
0034
0035
0036 struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
0037 [0] = &fc_rport_t0_prov,
0038 [FC_TYPE_FCP] = &fc_rport_fcp_init,
0039 };
0040
0041
0042
0043
0044 struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
0045 [FC_TYPE_ELS] = &fc_lport_els_prov,
0046 };
0047
0048
0049
0050
0051 static int __init libfc_init(void)
0052 {
0053 int rc = 0;
0054
0055 rc = fc_setup_fcp();
0056 if (rc)
0057 return rc;
0058
0059 rc = fc_setup_exch_mgr();
0060 if (rc)
0061 goto destroy_pkt_cache;
0062
0063 rc = fc_setup_rport();
0064 if (rc)
0065 goto destroy_em;
0066
0067 return rc;
0068 destroy_em:
0069 fc_destroy_exch_mgr();
0070 destroy_pkt_cache:
0071 fc_destroy_fcp();
0072 return rc;
0073 }
0074 module_init(libfc_init);
0075
0076
0077
0078
0079 static void __exit libfc_exit(void)
0080 {
0081 fc_destroy_fcp();
0082 fc_destroy_exch_mgr();
0083 fc_destroy_rport();
0084 }
0085 module_exit(libfc_exit);
0086
0087
0088
0089
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099 u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
0100 struct scatterlist *sg,
0101 u32 *nents, size_t *offset,
0102 u32 *crc)
0103 {
0104 size_t remaining = len;
0105 u32 copy_len = 0;
0106
0107 while (remaining > 0 && sg) {
0108 size_t off, sg_bytes;
0109 void *page_addr;
0110
0111 if (*offset >= sg->length) {
0112
0113
0114
0115
0116 if (!(*nents))
0117 break;
0118 --(*nents);
0119 *offset -= sg->length;
0120 sg = sg_next(sg);
0121 continue;
0122 }
0123 sg_bytes = min(remaining, sg->length - *offset);
0124
0125
0126
0127
0128
0129 off = *offset + sg->offset;
0130 sg_bytes = min(sg_bytes,
0131 (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
0132 page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT));
0133 if (crc)
0134 *crc = crc32(*crc, buf, sg_bytes);
0135 memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
0136 kunmap_atomic(page_addr);
0137 buf += sg_bytes;
0138 *offset += sg_bytes;
0139 remaining -= sg_bytes;
0140 copy_len += sg_bytes;
0141 }
0142 return copy_len;
0143 }
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
0155 enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
0156 {
0157 struct fc_frame_header *fh;
0158 struct fc_frame_header *in_fh;
0159 struct fc_seq *sp;
0160 u32 fill;
0161
0162 fh = __fc_frame_header_get(fp);
0163 in_fh = __fc_frame_header_get(in_fp);
0164
0165 if (f_ctl & FC_FC_END_SEQ) {
0166 fill = -fr_len(fp) & 3;
0167 if (fill) {
0168
0169 skb_put_zero(fp_skb(fp), fill);
0170 f_ctl |= fill;
0171 }
0172 fr_eof(fp) = FC_EOF_T;
0173 } else {
0174 WARN_ON(fr_len(fp) % 4 != 0);
0175 fr_eof(fp) = FC_EOF_N;
0176 }
0177
0178 fh->fh_r_ctl = r_ctl;
0179 memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
0180 memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
0181 fh->fh_type = in_fh->fh_type;
0182 hton24(fh->fh_f_ctl, f_ctl);
0183 fh->fh_ox_id = in_fh->fh_ox_id;
0184 fh->fh_rx_id = in_fh->fh_rx_id;
0185 fh->fh_cs_ctl = 0;
0186 fh->fh_df_ctl = 0;
0187 fh->fh_parm_offset = htonl(parm_offset);
0188
0189 sp = fr_seq(in_fp);
0190 if (sp) {
0191 fr_seq(fp) = sp;
0192 fh->fh_seq_id = sp->id;
0193 seq_cnt = sp->cnt;
0194 } else {
0195 fh->fh_seq_id = 0;
0196 }
0197 fh->fh_seq_cnt = ntohs(seq_cnt);
0198 fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
0199 fr_encaps(fp) = fr_encaps(in_fp);
0200 }
0201 EXPORT_SYMBOL(fc_fill_hdr);
0202
0203
0204
0205
0206
0207
0208
0209
0210 void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
0211 enum fc_rctl r_ctl, u32 parm_offset)
0212 {
0213 struct fc_seq *sp;
0214
0215 sp = fr_seq(in_fp);
0216 if (sp)
0217 fr_seq(fp) = fc_seq_start_next(sp);
0218 fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
0219 }
0220 EXPORT_SYMBOL(fc_fill_reply_hdr);
0221
0222
0223
0224
0225
0226
0227
0228
0229 void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type)
0230 {
0231 struct fc4_prov *prov_entry;
0232 BUG_ON(type >= FC_FC4_PROV_SIZE);
0233 BUG_ON(!lport);
0234 prov_entry = fc_passive_prov[type];
0235 if (type == FC_TYPE_FCP) {
0236 if (prov_entry && prov_entry->recv)
0237 lport->service_params |= FCP_SPPF_TARG_FCN;
0238 }
0239 }
0240
0241 void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
0242 {
0243 struct fc_lport *lport;
0244
0245 mutex_lock(&fc_prov_mutex);
0246 list_for_each_entry(lport, &fc_local_ports, lport_list)
0247 notify(lport, arg);
0248 mutex_unlock(&fc_prov_mutex);
0249 }
0250 EXPORT_SYMBOL(fc_lport_iterate);
0251
0252
0253
0254
0255
0256
0257
0258
0259 int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
0260 {
0261 struct fc4_prov **prov_entry;
0262 int ret = 0;
0263
0264 if (type >= FC_FC4_PROV_SIZE)
0265 return -EINVAL;
0266 mutex_lock(&fc_prov_mutex);
0267 prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
0268 if (*prov_entry)
0269 ret = -EBUSY;
0270 else
0271 *prov_entry = prov;
0272 mutex_unlock(&fc_prov_mutex);
0273 return ret;
0274 }
0275 EXPORT_SYMBOL(fc_fc4_register_provider);
0276
0277
0278
0279
0280
0281
0282 void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
0283 {
0284 BUG_ON(type >= FC_FC4_PROV_SIZE);
0285 mutex_lock(&fc_prov_mutex);
0286 if (prov->recv)
0287 RCU_INIT_POINTER(fc_passive_prov[type], NULL);
0288 else
0289 RCU_INIT_POINTER(fc_active_prov[type], NULL);
0290 mutex_unlock(&fc_prov_mutex);
0291 synchronize_rcu();
0292 }
0293 EXPORT_SYMBOL(fc_fc4_deregister_provider);
0294
0295
0296
0297
0298
0299 void fc_fc4_add_lport(struct fc_lport *lport)
0300 {
0301 mutex_lock(&fc_prov_mutex);
0302 list_add_tail(&lport->lport_list, &fc_local_ports);
0303 blocking_notifier_call_chain(&fc_lport_notifier_head,
0304 FC_LPORT_EV_ADD, lport);
0305 mutex_unlock(&fc_prov_mutex);
0306 }
0307
0308
0309
0310
0311
0312 void fc_fc4_del_lport(struct fc_lport *lport)
0313 {
0314 mutex_lock(&fc_prov_mutex);
0315 list_del(&lport->lport_list);
0316 blocking_notifier_call_chain(&fc_lport_notifier_head,
0317 FC_LPORT_EV_DEL, lport);
0318 mutex_unlock(&fc_prov_mutex);
0319 }