18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright(c) 2007 Intel Corporation. All rights reserved.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Maintained at www.Open-FCoE.org
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#ifndef _FC_FRAME_H_
98c2ecf20Sopenharmony_ci#define _FC_FRAME_H_
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <linux/scatterlist.h>
128c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
138c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h>
168c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fcp.h>
178c2ecf20Sopenharmony_ci#include <scsi/fc/fc_encaps.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/* some helpful macros */
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define ntohll(x) be64_to_cpu(x)
248c2ecf20Sopenharmony_ci#define htonll(x) cpu_to_be64(x)
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic inline u32 ntoh24(const u8 *p)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	return (p[0] << 16) | (p[1] << 8) | p[2];
298c2ecf20Sopenharmony_ci}
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistatic inline void hton24(u8 *p, u32 v)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	p[0] = (v >> 16) & 0xff;
348c2ecf20Sopenharmony_ci	p[1] = (v >> 8) & 0xff;
358c2ecf20Sopenharmony_ci	p[2] = v & 0xff;
368c2ecf20Sopenharmony_ci}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * The fc_frame interface is used to pass frame data between functions.
408c2ecf20Sopenharmony_ci * The frame includes the data buffer, length, and SOF / EOF delimiter types.
418c2ecf20Sopenharmony_ci * A pointer to the port structure of the receiving port is also includeded.
428c2ecf20Sopenharmony_ci */
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci#define	FC_FRAME_HEADROOM	32	/* headroom for VLAN + FCoE headers */
458c2ecf20Sopenharmony_ci#define	FC_FRAME_TAILROOM	8	/* trailer space for FCoE */
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci/* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */
488c2ecf20Sopenharmony_ci#define FC_FRAME_SG_LEN		(MAX_SKB_FRAGS - 1)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define fp_skb(fp)	(&((fp)->skb))
518c2ecf20Sopenharmony_ci#define fr_hdr(fp)	((fp)->skb.data)
528c2ecf20Sopenharmony_ci#define fr_len(fp)	((fp)->skb.len)
538c2ecf20Sopenharmony_ci#define fr_cb(fp)	((struct fcoe_rcv_info *)&((fp)->skb.cb[0]))
548c2ecf20Sopenharmony_ci#define fr_dev(fp)	(fr_cb(fp)->fr_dev)
558c2ecf20Sopenharmony_ci#define fr_seq(fp)	(fr_cb(fp)->fr_seq)
568c2ecf20Sopenharmony_ci#define fr_sof(fp)	(fr_cb(fp)->fr_sof)
578c2ecf20Sopenharmony_ci#define fr_eof(fp)	(fr_cb(fp)->fr_eof)
588c2ecf20Sopenharmony_ci#define fr_flags(fp)	(fr_cb(fp)->fr_flags)
598c2ecf20Sopenharmony_ci#define fr_encaps(fp)	(fr_cb(fp)->fr_encaps)
608c2ecf20Sopenharmony_ci#define fr_max_payload(fp)	(fr_cb(fp)->fr_max_payload)
618c2ecf20Sopenharmony_ci#define fr_fsp(fp)	(fr_cb(fp)->fr_fsp)
628c2ecf20Sopenharmony_ci#define fr_crc(fp)	(fr_cb(fp)->fr_crc)
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_cistruct fc_frame {
658c2ecf20Sopenharmony_ci	struct sk_buff skb;
668c2ecf20Sopenharmony_ci};
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cistruct fcoe_rcv_info {
698c2ecf20Sopenharmony_ci	struct fc_lport	*fr_dev;	/* transport layer private pointer */
708c2ecf20Sopenharmony_ci	struct fc_seq	*fr_seq;	/* for use with exchange manager */
718c2ecf20Sopenharmony_ci	struct fc_fcp_pkt *fr_fsp;	/* for the corresponding fcp I/O */
728c2ecf20Sopenharmony_ci	u32		fr_crc;
738c2ecf20Sopenharmony_ci	u16		fr_max_payload;	/* max FC payload */
748c2ecf20Sopenharmony_ci	u8		fr_sof;		/* start of frame delimiter */
758c2ecf20Sopenharmony_ci	u8		fr_eof;		/* end of frame delimiter */
768c2ecf20Sopenharmony_ci	u8		fr_flags;	/* flags - see below */
778c2ecf20Sopenharmony_ci	u8		fr_encaps;	/* LLD encapsulation info (e.g. FIP) */
788c2ecf20Sopenharmony_ci	u8		granted_mac[ETH_ALEN]; /* FCoE MAC address */
798c2ecf20Sopenharmony_ci};
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci/*
838c2ecf20Sopenharmony_ci * Get fc_frame pointer for an skb that's already been imported.
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_cistatic inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb)
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb));
888c2ecf20Sopenharmony_ci	return (struct fcoe_rcv_info *) skb->cb;
898c2ecf20Sopenharmony_ci}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci/*
928c2ecf20Sopenharmony_ci * fr_flags.
938c2ecf20Sopenharmony_ci */
948c2ecf20Sopenharmony_ci#define	FCPHF_CRC_UNCHECKED	0x01	/* CRC not computed, still appended */
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/*
978c2ecf20Sopenharmony_ci * Initialize a frame.
988c2ecf20Sopenharmony_ci * We don't do a complete memset here for performance reasons.
998c2ecf20Sopenharmony_ci * The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually.
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic inline void fc_frame_init(struct fc_frame *fp)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	fr_dev(fp) = NULL;
1048c2ecf20Sopenharmony_ci	fr_seq(fp) = NULL;
1058c2ecf20Sopenharmony_ci	fr_flags(fp) = 0;
1068c2ecf20Sopenharmony_ci	fr_encaps(fp) = 0;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistruct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
1108c2ecf20Sopenharmony_cistruct fc_frame *_fc_frame_alloc(size_t payload_len);
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci/*
1138c2ecf20Sopenharmony_ci * Allocate fc_frame structure and buffer.  Set the initial length to
1148c2ecf20Sopenharmony_ci * payload_size + sizeof (struct fc_frame_header).
1158c2ecf20Sopenharmony_ci */
1168c2ecf20Sopenharmony_cistatic inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len)
1178c2ecf20Sopenharmony_ci{
1188c2ecf20Sopenharmony_ci	struct fc_frame *fp;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	/*
1218c2ecf20Sopenharmony_ci	 * Note: Since len will often be a constant multiple of 4,
1228c2ecf20Sopenharmony_ci	 * this check will usually be evaluated and eliminated at compile time.
1238c2ecf20Sopenharmony_ci	 */
1248c2ecf20Sopenharmony_ci	if (len && len % 4)
1258c2ecf20Sopenharmony_ci		fp = fc_frame_alloc_fill(dev, len);
1268c2ecf20Sopenharmony_ci	else
1278c2ecf20Sopenharmony_ci		fp = _fc_frame_alloc(len);
1288c2ecf20Sopenharmony_ci	return fp;
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/*
1328c2ecf20Sopenharmony_ci * Free the fc_frame structure and buffer.
1338c2ecf20Sopenharmony_ci */
1348c2ecf20Sopenharmony_cistatic inline void fc_frame_free(struct fc_frame *fp)
1358c2ecf20Sopenharmony_ci{
1368c2ecf20Sopenharmony_ci	kfree_skb(fp_skb(fp));
1378c2ecf20Sopenharmony_ci}
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic inline int fc_frame_is_linear(struct fc_frame *fp)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	return !skb_is_nonlinear(fp_skb(fp));
1428c2ecf20Sopenharmony_ci}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci/*
1458c2ecf20Sopenharmony_ci * Get frame header from message in fc_frame structure.
1468c2ecf20Sopenharmony_ci * This version doesn't do a length check.
1478c2ecf20Sopenharmony_ci */
1488c2ecf20Sopenharmony_cistatic inline
1498c2ecf20Sopenharmony_cistruct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	return (struct fc_frame_header *)fr_hdr(fp);
1528c2ecf20Sopenharmony_ci}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci/*
1558c2ecf20Sopenharmony_ci * Get frame header from message in fc_frame structure.
1568c2ecf20Sopenharmony_ci * This hides a cast and provides a place to add some checking.
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_cistatic inline
1598c2ecf20Sopenharmony_cistruct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header));
1628c2ecf20Sopenharmony_ci	return __fc_frame_header_get(fp);
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci/*
1668c2ecf20Sopenharmony_ci * Get source FC_ID (S_ID) from frame header in message.
1678c2ecf20Sopenharmony_ci */
1688c2ecf20Sopenharmony_cistatic inline u32 fc_frame_sid(const struct fc_frame *fp)
1698c2ecf20Sopenharmony_ci{
1708c2ecf20Sopenharmony_ci	return ntoh24(__fc_frame_header_get(fp)->fh_s_id);
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_ci/*
1748c2ecf20Sopenharmony_ci * Get destination FC_ID (D_ID) from frame header in message.
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cistatic inline u32 fc_frame_did(const struct fc_frame *fp)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	return ntoh24(__fc_frame_header_get(fp)->fh_d_id);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci/*
1828c2ecf20Sopenharmony_ci * Get frame payload from message in fc_frame structure.
1838c2ecf20Sopenharmony_ci * This hides a cast and provides a place to add some checking.
1848c2ecf20Sopenharmony_ci * The len parameter is the minimum length for the payload portion.
1858c2ecf20Sopenharmony_ci * Returns NULL if the frame is too short.
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * This assumes the interesting part of the payload is in the first part
1888c2ecf20Sopenharmony_ci * of the buffer for received data.  This may not be appropriate to use for
1898c2ecf20Sopenharmony_ci * buffers being transmitted.
1908c2ecf20Sopenharmony_ci */
1918c2ecf20Sopenharmony_cistatic inline void *fc_frame_payload_get(const struct fc_frame *fp,
1928c2ecf20Sopenharmony_ci					 size_t len)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	void *pp = NULL;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	if (fr_len(fp) >= sizeof(struct fc_frame_header) + len)
1978c2ecf20Sopenharmony_ci		pp = fc_frame_header_get(fp) + 1;
1988c2ecf20Sopenharmony_ci	return pp;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci/*
2028c2ecf20Sopenharmony_ci * Get frame payload opcode (first byte) from message in fc_frame structure.
2038c2ecf20Sopenharmony_ci * This hides a cast and provides a place to add some checking. Return 0
2048c2ecf20Sopenharmony_ci * if the frame has no payload.
2058c2ecf20Sopenharmony_ci */
2068c2ecf20Sopenharmony_cistatic inline u8 fc_frame_payload_op(const struct fc_frame *fp)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	u8 *cp;
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci	cp = fc_frame_payload_get(fp, sizeof(u8));
2118c2ecf20Sopenharmony_ci	if (!cp)
2128c2ecf20Sopenharmony_ci		return 0;
2138c2ecf20Sopenharmony_ci	return *cp;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci}
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci/*
2188c2ecf20Sopenharmony_ci * Get FC class from frame.
2198c2ecf20Sopenharmony_ci */
2208c2ecf20Sopenharmony_cistatic inline enum fc_class fc_frame_class(const struct fc_frame *fp)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	return fc_sof_class(fr_sof(fp));
2238c2ecf20Sopenharmony_ci}
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci/*
2268c2ecf20Sopenharmony_ci * Check the CRC in a frame.
2278c2ecf20Sopenharmony_ci * The CRC immediately follows the last data item *AFTER* the length.
2288c2ecf20Sopenharmony_ci * The return value is zero if the CRC matches.
2298c2ecf20Sopenharmony_ci */
2308c2ecf20Sopenharmony_ciu32 fc_frame_crc_check(struct fc_frame *);
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_cistatic inline u8 fc_frame_rctl(const struct fc_frame *fp)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	return fc_frame_header_get(fp)->fh_r_ctl;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic inline bool fc_frame_is_cmd(const struct fc_frame *fp)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci/*
2438c2ecf20Sopenharmony_ci * Check for leaks.
2448c2ecf20Sopenharmony_ci * Print the frame header of any currently allocated frame, assuming there
2458c2ecf20Sopenharmony_ci * should be none at this point.
2468c2ecf20Sopenharmony_ci */
2478c2ecf20Sopenharmony_civoid fc_frame_leak_check(void);
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci#endif /* _FC_FRAME_H_ */
250