cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fc_libfc.c (8261B)


      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
     16#include "fc_encode.h"
     17#include "fc_libfc.h"
     18
     19MODULE_AUTHOR("Open-FCoE.org");
     20MODULE_DESCRIPTION("libfc");
     21MODULE_LICENSE("GPL v2");
     22
     23unsigned int fc_debug_logging;
     24module_param_named(debug_logging, fc_debug_logging, int, S_IRUGO|S_IWUSR);
     25MODULE_PARM_DESC(debug_logging, "a bit mask of logging levels");
     26
     27DEFINE_MUTEX(fc_prov_mutex);
     28static LIST_HEAD(fc_local_ports);
     29struct blocking_notifier_head fc_lport_notifier_head =
     30		BLOCKING_NOTIFIER_INIT(fc_lport_notifier_head);
     31EXPORT_SYMBOL(fc_lport_notifier_head);
     32
     33/*
     34 * Providers which primarily send requests and PRLIs.
     35 */
     36struct 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 */
     44struct 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 */
     51static 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;
     68destroy_em:
     69	fc_destroy_exch_mgr();
     70destroy_pkt_cache:
     71	fc_destroy_fcp();
     72	return rc;
     73}
     74module_init(libfc_init);
     75
     76/**
     77 * libfc_exit() - Tear down libfc.ko
     78 */
     79static void __exit libfc_exit(void)
     80{
     81	fc_destroy_fcp();
     82	fc_destroy_exch_mgr();
     83	fc_destroy_rport();
     84}
     85module_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 */
     99u32 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 */
    154void 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}
    201EXPORT_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 */
    210void 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}
    220EXPORT_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 */
    229void 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
    241void 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}
    250EXPORT_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 */
    259int 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}
    275EXPORT_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 */
    282void 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}
    293EXPORT_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 */
    299void 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 */
    312void 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}