root/drivers/scsi/libfc/fc_libfc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. libfc_init
  2. libfc_exit
  3. fc_copy_buffer_to_sglist
  4. fc_fill_hdr
  5. fc_fill_reply_hdr
  6. fc_fc4_conf_lport_params
  7. fc_lport_iterate
  8. fc_fc4_register_provider
  9. fc_fc4_deregister_provider
  10. fc_fc4_add_lport
  11. fc_fc4_del_lport

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Copyright(c) 2009 Intel Corporation. All rights reserved.
   4  *
   5  * Maintained at www.Open-FCoE.org
   6  */
   7 
   8 #include <linux/kernel.h>
   9 #include <linux/types.h>
  10 #include <linux/scatterlist.h>
  11 #include <linux/crc32.h>
  12 #include <linux/module.h>
  13 
  14 #include <scsi/libfc.h>
  15 #include <scsi/fc_encode.h>
  16 
  17 #include "fc_libfc.h"
  18 
  19 MODULE_AUTHOR("Open-FCoE.org");
  20 MODULE_DESCRIPTION("libfc");
  21 MODULE_LICENSE("GPL v2");
  22 
  23 unsigned int fc_debug_logging;
  24 module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
  25 MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
  26 
  27 DEFINE_MUTEX(fc_prov_mutex);
  28 static LIST_HEAD(fc_local_ports);
  29 struct blocking_notifier_head fc_lport_notifier_head =
  30                 BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
  31 EXPORT_SYMBOL(fc_lport_notifier_head);
  32 
  33 /*
  34  * Providers which primarily send requests and PRLIs.
  35  */
  36 struct fc4_prov *fc_active_prov[FC_FC4_PROV_SIZE] = {
  37         [0] = &fc_rport_t0_prov,
  38         [FC_TYPE_FCP] = &fc_rport_fcp_init,
  39 };
  40 
  41 /*
  42  * Providers which receive requests.
  43  */
  44 struct fc4_prov *fc_passive_prov[FC_FC4_PROV_SIZE] = {
  45         [FC_TYPE_ELS] = &fc_lport_els_prov,
  46 };
  47 
  48 /**
  49  * libfc_init() - Initialize libfc.ko
  50  */
  51 static int __init libfc_init(void)
  52 {
  53         int rc = 0;
  54 
  55         rc = fc_setup_fcp();
  56         if (rc)
  57                 return rc;
  58 
  59         rc = fc_setup_exch_mgr();
  60         if (rc)
  61                 goto destroy_pkt_cache;
  62 
  63         rc = fc_setup_rport();
  64         if (rc)
  65                 goto destroy_em;
  66 
  67         return rc;
  68 destroy_em:
  69         fc_destroy_exch_mgr();
  70 destroy_pkt_cache:
  71         fc_destroy_fcp();
  72         return rc;
  73 }
  74 module_init(libfc_init);
  75 
  76 /**
  77  * libfc_exit() - Tear down libfc.ko
  78  */
  79 static void __exit libfc_exit(void)
  80 {
  81         fc_destroy_fcp();
  82         fc_destroy_exch_mgr();
  83         fc_destroy_rport();
  84 }
  85 module_exit(libfc_exit);
  86 
  87 /**
  88  * fc_copy_buffer_to_sglist() - This routine copies the data of a buffer
  89  *                              into a scatter-gather list (SG list).
  90  *
  91  * @buf: pointer to the data buffer.
  92  * @len: the byte-length of the data buffer.
  93  * @sg: pointer to the pointer of the SG list.
  94  * @nents: pointer to the remaining number of entries in the SG list.
  95  * @offset: pointer to the current offset in the SG list.
  96  * @crc: pointer to the 32-bit crc value.
  97  *       If crc is NULL, CRC is not calculated.
  98  */
  99 u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
 100                              struct scatterlist *sg,
 101                              u32 *nents, size_t *offset,
 102                              u32 *crc)
 103 {
 104         size_t remaining = len;
 105         u32 copy_len = 0;
 106 
 107         while (remaining > 0 && sg) {
 108                 size_t off, sg_bytes;
 109                 void *page_addr;
 110 
 111                 if (*offset >= sg->length) {
 112                         /*
 113                          * Check for end and drop resources
 114                          * from the last iteration.
 115                          */
 116                         if (!(*nents))
 117                                 break;
 118                         --(*nents);
 119                         *offset -= sg->length;
 120                         sg = sg_next(sg);
 121                         continue;
 122                 }
 123                 sg_bytes = min(remaining, sg->length - *offset);
 124 
 125                 /*
 126                  * The scatterlist item may be bigger than PAGE_SIZE,
 127                  * but we are limited to mapping PAGE_SIZE at a time.
 128                  */
 129                 off = *offset + sg->offset;
 130                 sg_bytes = min(sg_bytes,
 131                                (size_t)(PAGE_SIZE - (off & ~PAGE_MASK)));
 132                 page_addr = kmap_atomic(sg_page(sg) + (off >> PAGE_SHIFT));
 133                 if (crc)
 134                         *crc = crc32(*crc, buf, sg_bytes);
 135                 memcpy((char *)page_addr + (off & ~PAGE_MASK), buf, sg_bytes);
 136                 kunmap_atomic(page_addr);
 137                 buf += sg_bytes;
 138                 *offset += sg_bytes;
 139                 remaining -= sg_bytes;
 140                 copy_len += sg_bytes;
 141         }
 142         return copy_len;
 143 }
 144 
 145 /**
 146  * fc_fill_hdr() -  fill FC header fields based on request
 147  * @fp: reply frame containing header to be filled in
 148  * @in_fp: request frame containing header to use in filling in reply
 149  * @r_ctl: R_CTL value for header
 150  * @f_ctl: F_CTL value for header, with 0 pad
 151  * @seq_cnt: sequence count for the header, ignored if frame has a sequence
 152  * @parm_offset: parameter / offset value
 153  */
 154 void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
 155                  enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
 156 {
 157         struct fc_frame_header *fh;
 158         struct fc_frame_header *in_fh;
 159         struct fc_seq *sp;
 160         u32 fill;
 161 
 162         fh = __fc_frame_header_get(fp);
 163         in_fh = __fc_frame_header_get(in_fp);
 164 
 165         if (f_ctl & FC_FC_END_SEQ) {
 166                 fill = -fr_len(fp) & 3;
 167                 if (fill) {
 168                         /* TODO, this may be a problem with fragmented skb */
 169                         skb_put_zero(fp_skb(fp), fill);
 170                         f_ctl |= fill;
 171                 }
 172                 fr_eof(fp) = FC_EOF_T;
 173         } else {
 174                 WARN_ON(fr_len(fp) % 4 != 0);   /* no pad to non last frame */
 175                 fr_eof(fp) = FC_EOF_N;
 176         }
 177 
 178         fh->fh_r_ctl = r_ctl;
 179         memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
 180         memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
 181         fh->fh_type = in_fh->fh_type;
 182         hton24(fh->fh_f_ctl, f_ctl);
 183         fh->fh_ox_id = in_fh->fh_ox_id;
 184         fh->fh_rx_id = in_fh->fh_rx_id;
 185         fh->fh_cs_ctl = 0;
 186         fh->fh_df_ctl = 0;
 187         fh->fh_parm_offset = htonl(parm_offset);
 188 
 189         sp = fr_seq(in_fp);
 190         if (sp) {
 191                 fr_seq(fp) = sp;
 192                 fh->fh_seq_id = sp->id;
 193                 seq_cnt = sp->cnt;
 194         } else {
 195                 fh->fh_seq_id = 0;
 196         }
 197         fh->fh_seq_cnt = ntohs(seq_cnt);
 198         fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
 199         fr_encaps(fp) = fr_encaps(in_fp);
 200 }
 201 EXPORT_SYMBOL(fc_fill_hdr);
 202 
 203 /**
 204  * fc_fill_reply_hdr() -  fill FC reply header fields based on request
 205  * @fp: reply frame containing header to be filled in
 206  * @in_fp: request frame containing header to use in filling in reply
 207  * @r_ctl: R_CTL value for reply
 208  * @parm_offset: parameter / offset value
 209  */
 210 void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
 211                        enum fc_rctl r_ctl, u32 parm_offset)
 212 {
 213         struct fc_seq *sp;
 214 
 215         sp = fr_seq(in_fp);
 216         if (sp)
 217                 fr_seq(fp) = fc_seq_start_next(sp);
 218         fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
 219 }
 220 EXPORT_SYMBOL(fc_fill_reply_hdr);
 221 
 222 /**
 223  * fc_fc4_conf_lport_params() - Modify "service_params" of specified lport
 224  * if there is service provider (target provider) registered with libfc
 225  * for specified "fc_ft_type"
 226  * @lport: Local port which service_params needs to be modified
 227  * @type: FC-4 type, such as FC_TYPE_FCP
 228  */
 229 void fc_fc4_conf_lport_params(struct fc_lport *lport, enum fc_fh_type type)
 230 {
 231         struct fc4_prov *prov_entry;
 232         BUG_ON(type >= FC_FC4_PROV_SIZE);
 233         BUG_ON(!lport);
 234         prov_entry = fc_passive_prov[type];
 235         if (type == FC_TYPE_FCP) {
 236                 if (prov_entry && prov_entry->recv)
 237                         lport->service_params |= FCP_SPPF_TARG_FCN;
 238         }
 239 }
 240 
 241 void fc_lport_iterate(void (*notify)(struct fc_lport *, void *), void *arg)
 242 {
 243         struct fc_lport *lport;
 244 
 245         mutex_lock(&fc_prov_mutex);
 246         list_for_each_entry(lport, &fc_local_ports, lport_list)
 247                 notify(lport, arg);
 248         mutex_unlock(&fc_prov_mutex);
 249 }
 250 EXPORT_SYMBOL(fc_lport_iterate);
 251 
 252 /**
 253  * fc_fc4_register_provider() - register FC-4 upper-level provider.
 254  * @type: FC-4 type, such as FC_TYPE_FCP
 255  * @prov: structure describing provider including ops vector.
 256  *
 257  * Returns 0 on success, negative error otherwise.
 258  */
 259 int fc_fc4_register_provider(enum fc_fh_type type, struct fc4_prov *prov)
 260 {
 261         struct fc4_prov **prov_entry;
 262         int ret = 0;
 263 
 264         if (type >= FC_FC4_PROV_SIZE)
 265                 return -EINVAL;
 266         mutex_lock(&fc_prov_mutex);
 267         prov_entry = (prov->recv ? fc_passive_prov : fc_active_prov) + type;
 268         if (*prov_entry)
 269                 ret = -EBUSY;
 270         else
 271                 *prov_entry = prov;
 272         mutex_unlock(&fc_prov_mutex);
 273         return ret;
 274 }
 275 EXPORT_SYMBOL(fc_fc4_register_provider);
 276 
 277 /**
 278  * fc_fc4_deregister_provider() - deregister FC-4 upper-level provider.
 279  * @type: FC-4 type, such as FC_TYPE_FCP
 280  * @prov: structure describing provider including ops vector.
 281  */
 282 void fc_fc4_deregister_provider(enum fc_fh_type type, struct fc4_prov *prov)
 283 {
 284         BUG_ON(type >= FC_FC4_PROV_SIZE);
 285         mutex_lock(&fc_prov_mutex);
 286         if (prov->recv)
 287                 RCU_INIT_POINTER(fc_passive_prov[type], NULL);
 288         else
 289                 RCU_INIT_POINTER(fc_active_prov[type], NULL);
 290         mutex_unlock(&fc_prov_mutex);
 291         synchronize_rcu();
 292 }
 293 EXPORT_SYMBOL(fc_fc4_deregister_provider);
 294 
 295 /**
 296  * fc_fc4_add_lport() - add new local port to list and run notifiers.
 297  * @lport:  The new local port.
 298  */
 299 void fc_fc4_add_lport(struct fc_lport *lport)
 300 {
 301         mutex_lock(&fc_prov_mutex);
 302         list_add_tail(&lport->lport_list, &fc_local_ports);
 303         blocking_notifier_call_chain(&fc_lport_notifier_head,
 304                                      FC_LPORT_EV_ADD, lport);
 305         mutex_unlock(&fc_prov_mutex);
 306 }
 307 
 308 /**
 309  * fc_fc4_del_lport() - remove local port from list and run notifiers.
 310  * @lport:  The new local port.
 311  */
 312 void fc_fc4_del_lport(struct fc_lport *lport)
 313 {
 314         mutex_lock(&fc_prov_mutex);
 315         list_del(&lport->lport_list);
 316         blocking_notifier_call_chain(&fc_lport_notifier_head,
 317                                      FC_LPORT_EV_DEL, lport);
 318         mutex_unlock(&fc_prov_mutex);
 319 }

/* [<][>][^][v][top][bottom][index][help] */