Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright(c) 2009 Intel Corporation. All rights reserved.
0004  *
0005  * Maintained at www.Open-FCoE.org
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  * Providers which primarily send requests and PRLIs.
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  * Providers which receive requests.
0043  */
0044 struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
0045     [FC_TYPE_ELS] = &fc_lport_els_prov,
0046 };
0047 
0048 /**
0049  * libfc_init() - Initialize libfc.ko
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  * libfc_exit() - Tear down libfc.ko
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  * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer
0089  *              into a scatter-gather list (SG list).
0090  *
0091  * @buf: pointer to the data buffer.
0092  * @len: the byte-length of the data buffer.
0093  * @sg: pointer to the pointer of the SG list.
0094  * @nents: pointer to the remaining number of entries in the SG list.
0095  * @offset: pointer to the current offset in the SG list.
0096  * @crc: pointer to the 32-bit crc value.
0097  *   If crc is NULL, CRC is not calculated.
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              * Check for end and drop resources
0114              * from the last iteration.
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          * The scatterlist item may be bigger than PAGE_SIZE,
0127          * but we are limited to mapping PAGE_SIZE at a time.
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  * fc_fill_hdr() -  fill FC header fields based on request
0147  * @fp: reply frame containing header to be filled in
0148  * @in_fp: request frame containing header to use in filling in reply
0149  * @r_ctl: R_CTL value for header
0150  * @f_ctl: F_CTL value for header, with 0 pad
0151  * @seq_cnt: sequence count for the header, ignored if frame has a sequence
0152  * @parm_offset: parameter / offset value
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             /* TODO, this may be a problem with fragmented skb */
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);   /* no pad to non last frame */
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  * fc_fill_reply_hdr() -  fill FC reply header fields based on request
0205  * @fp: reply frame containing header to be filled in
0206  * @in_fp: request frame containing header to use in filling in reply
0207  * @r_ctl: R_CTL value for reply
0208  * @parm_offset: parameter / offset value
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  * fc_fc4_conf_lport_params() - Modify "service_params" of specified lport
0224  * if there is service provider (target provider) registered with libfc
0225  * for specified "fc_ft_type"
0226  * @lport: Local port which service_params needs to be modified
0227  * @type: FC-4 type, such as FC_TYPE_FCP
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  * fc_fc4_register_provider() - register FC-4 upper-level provider.
0254  * @type: FC-4 type, such as FC_TYPE_FCP
0255  * @prov: structure describing provider including ops vector.
0256  *
0257  * Returns 0 on success, negative error otherwise.
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  * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
0279  * @type: FC-4 type, such as FC_TYPE_FCP
0280  * @prov: structure describing provider including ops vector.
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  * fc_fc4_add_lport() - add new local port to list and run notifiers.
0297  * @lport:  The new local port.
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  * fc_fc4_del_lport() - remove local port from list and run notifiers.
0310  * @lport:  The new local port.
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 }