xref: /openbmc/linux/include/scsi/fc_frame.h (revision e31ac898)
1a61127c2SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
242e9a92fSRobert Love /*
342e9a92fSRobert Love  * Copyright(c) 2007 Intel Corporation. All rights reserved.
442e9a92fSRobert Love  *
542e9a92fSRobert Love  * Maintained at www.Open-FCoE.org
642e9a92fSRobert Love  */
742e9a92fSRobert Love 
842e9a92fSRobert Love #ifndef _FC_FRAME_H_
942e9a92fSRobert Love #define _FC_FRAME_H_
1042e9a92fSRobert Love 
1142e9a92fSRobert Love #include <linux/scatterlist.h>
1242e9a92fSRobert Love #include <linux/skbuff.h>
1342e9a92fSRobert Love #include <scsi/scsi_cmnd.h>
1442e9a92fSRobert Love 
1542e9a92fSRobert Love #include <scsi/fc/fc_fs.h>
1642e9a92fSRobert Love #include <scsi/fc/fc_fcp.h>
1742e9a92fSRobert Love #include <scsi/fc/fc_encaps.h>
1842e9a92fSRobert Love 
1911b56188SChris Leech #include <linux/if_ether.h>
2011b56188SChris Leech 
21251748a9SJoe Eykholt /* some helpful macros */
22251748a9SJoe Eykholt 
23251748a9SJoe Eykholt #define ntohll(x) be64_to_cpu(x)
24251748a9SJoe Eykholt #define htonll(x) cpu_to_be64(x)
25251748a9SJoe Eykholt 
ntoh24(const u8 * p)26251748a9SJoe Eykholt static inline u32 ntoh24(const u8 *p)
27251748a9SJoe Eykholt {
28251748a9SJoe Eykholt 	return (p[0] << 16) | (p[1] << 8) | p[2];
29251748a9SJoe Eykholt }
30251748a9SJoe Eykholt 
hton24(u8 * p,u32 v)31251748a9SJoe Eykholt static inline void hton24(u8 *p, u32 v)
32251748a9SJoe Eykholt {
33251748a9SJoe Eykholt 	p[0] = (v >> 16) & 0xff;
34251748a9SJoe Eykholt 	p[1] = (v >> 8) & 0xff;
35251748a9SJoe Eykholt 	p[2] = v & 0xff;
36251748a9SJoe Eykholt }
37251748a9SJoe Eykholt 
3842e9a92fSRobert Love /*
3942e9a92fSRobert Love  * The fc_frame interface is used to pass frame data between functions.
4042e9a92fSRobert Love  * The frame includes the data buffer, length, and SOF / EOF delimiter types.
4142e9a92fSRobert Love  * A pointer to the port structure of the receiving port is also includeded.
4242e9a92fSRobert Love  */
4342e9a92fSRobert Love 
4442e9a92fSRobert Love #define	FC_FRAME_HEADROOM	32	/* headroom for VLAN + FCoE headers */
4542e9a92fSRobert Love #define	FC_FRAME_TAILROOM	8	/* trailer space for FCoE */
4642e9a92fSRobert Love 
47d37322a4SYi Zou /* Max number of skb frags allowed, reserving one for fcoe_crc_eof page */
48d37322a4SYi Zou #define FC_FRAME_SG_LEN		(MAX_SKB_FRAGS - 1)
49d37322a4SYi Zou 
5042e9a92fSRobert Love #define fp_skb(fp)	(&((fp)->skb))
5142e9a92fSRobert Love #define fr_hdr(fp)	((fp)->skb.data)
5242e9a92fSRobert Love #define fr_len(fp)	((fp)->skb.len)
5342e9a92fSRobert Love #define fr_cb(fp)	((struct fcoe_rcv_info *)&((fp)->skb.cb[0]))
5442e9a92fSRobert Love #define fr_dev(fp)	(fr_cb(fp)->fr_dev)
5542e9a92fSRobert Love #define fr_seq(fp)	(fr_cb(fp)->fr_seq)
5642e9a92fSRobert Love #define fr_sof(fp)	(fr_cb(fp)->fr_sof)
5742e9a92fSRobert Love #define fr_eof(fp)	(fr_cb(fp)->fr_eof)
5842e9a92fSRobert Love #define fr_flags(fp)	(fr_cb(fp)->fr_flags)
59f60e12e9SJoe Eykholt #define fr_encaps(fp)	(fr_cb(fp)->fr_encaps)
6042e9a92fSRobert Love #define fr_max_payload(fp)	(fr_cb(fp)->fr_max_payload)
61b277d2aaSYi Zou #define fr_fsp(fp)	(fr_cb(fp)->fr_fsp)
6242e9a92fSRobert Love #define fr_crc(fp)	(fr_cb(fp)->fr_crc)
6342e9a92fSRobert Love 
6442e9a92fSRobert Love struct fc_frame {
6542e9a92fSRobert Love 	struct sk_buff skb;
6642e9a92fSRobert Love };
6742e9a92fSRobert Love 
6842e9a92fSRobert Love struct fcoe_rcv_info {
6942e9a92fSRobert Love 	struct fc_lport	*fr_dev;	/* transport layer private pointer */
7042e9a92fSRobert Love 	struct fc_seq	*fr_seq;	/* for use with exchange manager */
71b277d2aaSYi Zou 	struct fc_fcp_pkt *fr_fsp;	/* for the corresponding fcp I/O */
7242e9a92fSRobert Love 	u32		fr_crc;
7342e9a92fSRobert Love 	u16		fr_max_payload;	/* max FC payload */
74d058fd31SBart Van Assche 	u8		fr_sof;		/* start of frame delimiter */
75d058fd31SBart Van Assche 	u8		fr_eof;		/* end of frame delimiter */
7642e9a92fSRobert Love 	u8		fr_flags;	/* flags - see below */
77f60e12e9SJoe Eykholt 	u8		fr_encaps;	/* LLD encapsulation info (e.g. FIP) */
7811b56188SChris Leech 	u8		granted_mac[ETH_ALEN]; /* FCoE MAC address */
7942e9a92fSRobert Love };
8042e9a92fSRobert Love 
8142e9a92fSRobert Love 
8242e9a92fSRobert Love /*
8342e9a92fSRobert Love  * Get fc_frame pointer for an skb that's already been imported.
8442e9a92fSRobert Love  */
fcoe_dev_from_skb(const struct sk_buff * skb)8542e9a92fSRobert Love static inline struct fcoe_rcv_info *fcoe_dev_from_skb(const struct sk_buff *skb)
8642e9a92fSRobert Love {
8742e9a92fSRobert Love 	BUILD_BUG_ON(sizeof(struct fcoe_rcv_info) > sizeof(skb->cb));
8842e9a92fSRobert Love 	return (struct fcoe_rcv_info *) skb->cb;
8942e9a92fSRobert Love }
9042e9a92fSRobert Love 
9142e9a92fSRobert Love /*
9242e9a92fSRobert Love  * fr_flags.
9342e9a92fSRobert Love  */
9442e9a92fSRobert Love #define	FCPHF_CRC_UNCHECKED	0x01	/* CRC not computed, still appended */
9542e9a92fSRobert Love 
9642e9a92fSRobert Love /*
9742e9a92fSRobert Love  * Initialize a frame.
9842e9a92fSRobert Love  * We don't do a complete memset here for performance reasons.
9942e9a92fSRobert Love  * The caller must set fr_free, fr_hdr, fr_len, fr_sof, and fr_eof eventually.
10042e9a92fSRobert Love  */
fc_frame_init(struct fc_frame * fp)10142e9a92fSRobert Love static inline void fc_frame_init(struct fc_frame *fp)
10242e9a92fSRobert Love {
10342e9a92fSRobert Love 	fr_dev(fp) = NULL;
10442e9a92fSRobert Love 	fr_seq(fp) = NULL;
10542e9a92fSRobert Love 	fr_flags(fp) = 0;
106f60e12e9SJoe Eykholt 	fr_encaps(fp) = 0;
10742e9a92fSRobert Love }
10842e9a92fSRobert Love 
10942e9a92fSRobert Love struct fc_frame *fc_frame_alloc_fill(struct fc_lport *, size_t payload_len);
110a7bbc7f4SVasu Dev struct fc_frame *_fc_frame_alloc(size_t payload_len);
11142e9a92fSRobert Love 
11242e9a92fSRobert Love /*
11342e9a92fSRobert Love  * Allocate fc_frame structure and buffer.  Set the initial length to
11442e9a92fSRobert Love  * payload_size + sizeof (struct fc_frame_header).
11542e9a92fSRobert Love  */
fc_frame_alloc(struct fc_lport * dev,size_t len)11642e9a92fSRobert Love static inline struct fc_frame *fc_frame_alloc(struct fc_lport *dev, size_t len)
11742e9a92fSRobert Love {
11842e9a92fSRobert Love 	struct fc_frame *fp;
11942e9a92fSRobert Love 
12042e9a92fSRobert Love 	/*
12142e9a92fSRobert Love 	 * Note: Since len will often be a constant multiple of 4,
12242e9a92fSRobert Love 	 * this check will usually be evaluated and eliminated at compile time.
12342e9a92fSRobert Love 	 */
124a7bbc7f4SVasu Dev 	if (len && len % 4)
12542e9a92fSRobert Love 		fp = fc_frame_alloc_fill(dev, len);
12642e9a92fSRobert Love 	else
127a7bbc7f4SVasu Dev 		fp = _fc_frame_alloc(len);
12842e9a92fSRobert Love 	return fp;
12942e9a92fSRobert Love }
13042e9a92fSRobert Love 
13142e9a92fSRobert Love /*
13242e9a92fSRobert Love  * Free the fc_frame structure and buffer.
13342e9a92fSRobert Love  */
fc_frame_free(struct fc_frame * fp)13442e9a92fSRobert Love static inline void fc_frame_free(struct fc_frame *fp)
13542e9a92fSRobert Love {
13642e9a92fSRobert Love 	kfree_skb(fp_skb(fp));
13742e9a92fSRobert Love }
13842e9a92fSRobert Love 
fc_frame_is_linear(struct fc_frame * fp)13942e9a92fSRobert Love static inline int fc_frame_is_linear(struct fc_frame *fp)
14042e9a92fSRobert Love {
14142e9a92fSRobert Love 	return !skb_is_nonlinear(fp_skb(fp));
14242e9a92fSRobert Love }
14342e9a92fSRobert Love 
14442e9a92fSRobert Love /*
14542e9a92fSRobert Love  * Get frame header from message in fc_frame structure.
146251748a9SJoe Eykholt  * This version doesn't do a length check.
147251748a9SJoe Eykholt  */
148251748a9SJoe Eykholt static inline
__fc_frame_header_get(const struct fc_frame * fp)149251748a9SJoe Eykholt struct fc_frame_header *__fc_frame_header_get(const struct fc_frame *fp)
150251748a9SJoe Eykholt {
151251748a9SJoe Eykholt 	return (struct fc_frame_header *)fr_hdr(fp);
152251748a9SJoe Eykholt }
153251748a9SJoe Eykholt 
154251748a9SJoe Eykholt /*
155251748a9SJoe Eykholt  * Get frame header from message in fc_frame structure.
15642e9a92fSRobert Love  * This hides a cast and provides a place to add some checking.
15742e9a92fSRobert Love  */
15842e9a92fSRobert Love static inline
fc_frame_header_get(const struct fc_frame * fp)15942e9a92fSRobert Love struct fc_frame_header *fc_frame_header_get(const struct fc_frame *fp)
16042e9a92fSRobert Love {
16142e9a92fSRobert Love 	WARN_ON(fr_len(fp) < sizeof(struct fc_frame_header));
162251748a9SJoe Eykholt 	return __fc_frame_header_get(fp);
163251748a9SJoe Eykholt }
164251748a9SJoe Eykholt 
165251748a9SJoe Eykholt /*
166251748a9SJoe Eykholt  * Get source FC_ID (S_ID) from frame header in message.
167251748a9SJoe Eykholt  */
fc_frame_sid(const struct fc_frame * fp)168251748a9SJoe Eykholt static inline u32 fc_frame_sid(const struct fc_frame *fp)
169251748a9SJoe Eykholt {
170251748a9SJoe Eykholt 	return ntoh24(__fc_frame_header_get(fp)->fh_s_id);
171251748a9SJoe Eykholt }
172251748a9SJoe Eykholt 
173251748a9SJoe Eykholt /*
174251748a9SJoe Eykholt  * Get destination FC_ID (D_ID) from frame header in message.
175251748a9SJoe Eykholt  */
fc_frame_did(const struct fc_frame * fp)176251748a9SJoe Eykholt static inline u32 fc_frame_did(const struct fc_frame *fp)
177251748a9SJoe Eykholt {
178251748a9SJoe Eykholt 	return ntoh24(__fc_frame_header_get(fp)->fh_d_id);
17942e9a92fSRobert Love }
18042e9a92fSRobert Love 
18142e9a92fSRobert Love /*
18242e9a92fSRobert Love  * Get frame payload from message in fc_frame structure.
18342e9a92fSRobert Love  * This hides a cast and provides a place to add some checking.
18442e9a92fSRobert Love  * The len parameter is the minimum length for the payload portion.
18542e9a92fSRobert Love  * Returns NULL if the frame is too short.
18642e9a92fSRobert Love  *
18742e9a92fSRobert Love  * This assumes the interesting part of the payload is in the first part
18842e9a92fSRobert Love  * of the buffer for received data.  This may not be appropriate to use for
18942e9a92fSRobert Love  * buffers being transmitted.
19042e9a92fSRobert Love  */
fc_frame_payload_get(const struct fc_frame * fp,size_t len)19142e9a92fSRobert Love static inline void *fc_frame_payload_get(const struct fc_frame *fp,
19242e9a92fSRobert Love 					 size_t len)
19342e9a92fSRobert Love {
19442e9a92fSRobert Love 	void *pp = NULL;
19542e9a92fSRobert Love 
19642e9a92fSRobert Love 	if (fr_len(fp) >= sizeof(struct fc_frame_header) + len)
19742e9a92fSRobert Love 		pp = fc_frame_header_get(fp) + 1;
19842e9a92fSRobert Love 	return pp;
19942e9a92fSRobert Love }
20042e9a92fSRobert Love 
20142e9a92fSRobert Love /*
20242e9a92fSRobert Love  * Get frame payload opcode (first byte) from message in fc_frame structure.
20342e9a92fSRobert Love  * This hides a cast and provides a place to add some checking. Return 0
20442e9a92fSRobert Love  * if the frame has no payload.
20542e9a92fSRobert Love  */
fc_frame_payload_op(const struct fc_frame * fp)20642e9a92fSRobert Love static inline u8 fc_frame_payload_op(const struct fc_frame *fp)
20742e9a92fSRobert Love {
20842e9a92fSRobert Love 	u8 *cp;
20942e9a92fSRobert Love 
21042e9a92fSRobert Love 	cp = fc_frame_payload_get(fp, sizeof(u8));
21142e9a92fSRobert Love 	if (!cp)
21242e9a92fSRobert Love 		return 0;
21342e9a92fSRobert Love 	return *cp;
21442e9a92fSRobert Love 
21542e9a92fSRobert Love }
21642e9a92fSRobert Love 
21742e9a92fSRobert Love /*
21842e9a92fSRobert Love  * Get FC class from frame.
21942e9a92fSRobert Love  */
fc_frame_class(const struct fc_frame * fp)22042e9a92fSRobert Love static inline enum fc_class fc_frame_class(const struct fc_frame *fp)
22142e9a92fSRobert Love {
22242e9a92fSRobert Love 	return fc_sof_class(fr_sof(fp));
22342e9a92fSRobert Love }
22442e9a92fSRobert Love 
22542e9a92fSRobert Love /*
22642e9a92fSRobert Love  * Check the CRC in a frame.
22742e9a92fSRobert Love  * The CRC immediately follows the last data item *AFTER* the length.
22842e9a92fSRobert Love  * The return value is zero if the CRC matches.
22942e9a92fSRobert Love  */
23042e9a92fSRobert Love u32 fc_frame_crc_check(struct fc_frame *);
23142e9a92fSRobert Love 
fc_frame_rctl(const struct fc_frame * fp)23242e9a92fSRobert Love static inline u8 fc_frame_rctl(const struct fc_frame *fp)
23342e9a92fSRobert Love {
23442e9a92fSRobert Love 	return fc_frame_header_get(fp)->fh_r_ctl;
23542e9a92fSRobert Love }
23642e9a92fSRobert Love 
fc_frame_is_cmd(const struct fc_frame * fp)23742e9a92fSRobert Love static inline bool fc_frame_is_cmd(const struct fc_frame *fp)
23842e9a92fSRobert Love {
23942e9a92fSRobert Love 	return fc_frame_rctl(fp) == FC_RCTL_DD_UNSOL_CMD;
24042e9a92fSRobert Love }
24142e9a92fSRobert Love 
24242e9a92fSRobert Love /*
24342e9a92fSRobert Love  * Check for leaks.
24442e9a92fSRobert Love  * Print the frame header of any currently allocated frame, assuming there
24542e9a92fSRobert Love  * should be none at this point.
24642e9a92fSRobert Love  */
24742e9a92fSRobert Love void fc_frame_leak_check(void);
24842e9a92fSRobert Love 
__fc_fill_fc_hdr(struct fc_frame_header * fh,enum fc_rctl r_ctl,u32 did,u32 sid,enum fc_fh_type type,u32 f_ctl,u32 parm_offset)249*e31ac898SArnd Bergmann static inline void __fc_fill_fc_hdr(struct fc_frame_header *fh,
250*e31ac898SArnd Bergmann 				    enum fc_rctl r_ctl,
251*e31ac898SArnd Bergmann 				    u32 did, u32 sid, enum fc_fh_type type,
252*e31ac898SArnd Bergmann 				    u32 f_ctl, u32 parm_offset)
253*e31ac898SArnd Bergmann {
254*e31ac898SArnd Bergmann 	WARN_ON(r_ctl == 0);
255*e31ac898SArnd Bergmann 	fh->fh_r_ctl = r_ctl;
256*e31ac898SArnd Bergmann 	hton24(fh->fh_d_id, did);
257*e31ac898SArnd Bergmann 	hton24(fh->fh_s_id, sid);
258*e31ac898SArnd Bergmann 	fh->fh_type = type;
259*e31ac898SArnd Bergmann 	hton24(fh->fh_f_ctl, f_ctl);
260*e31ac898SArnd Bergmann 	fh->fh_cs_ctl = 0;
261*e31ac898SArnd Bergmann 	fh->fh_df_ctl = 0;
262*e31ac898SArnd Bergmann 	fh->fh_parm_offset = htonl(parm_offset);
263*e31ac898SArnd Bergmann }
264*e31ac898SArnd Bergmann 
265*e31ac898SArnd Bergmann /**
266*e31ac898SArnd Bergmann  * fill FC header fields in specified fc_frame
267*e31ac898SArnd Bergmann  */
fc_fill_fc_hdr(struct fc_frame * fp,enum fc_rctl r_ctl,u32 did,u32 sid,enum fc_fh_type type,u32 f_ctl,u32 parm_offset)268*e31ac898SArnd Bergmann static inline void fc_fill_fc_hdr(struct fc_frame *fp, enum fc_rctl r_ctl,
269*e31ac898SArnd Bergmann 				  u32 did, u32 sid, enum fc_fh_type type,
270*e31ac898SArnd Bergmann 				  u32 f_ctl, u32 parm_offset)
271*e31ac898SArnd Bergmann {
272*e31ac898SArnd Bergmann 	struct fc_frame_header *fh;
273*e31ac898SArnd Bergmann 
274*e31ac898SArnd Bergmann 	fh = fc_frame_header_get(fp);
275*e31ac898SArnd Bergmann 	__fc_fill_fc_hdr(fh, r_ctl, did, sid, type, f_ctl, parm_offset);
276*e31ac898SArnd Bergmann }
277*e31ac898SArnd Bergmann 
278*e31ac898SArnd Bergmann 
27942e9a92fSRobert Love #endif /* _FC_FRAME_H_ */
280