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