diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:49:45 +0000 |
commit | 2c3c1048746a4622d8c89a29670120dc8fab93c4 (patch) | |
tree | 848558de17fb3008cdf4d861b01ac7781903ce39 /drivers/scsi/libfc/fc_frame.c | |
parent | Initial commit. (diff) | |
download | linux-upstream.tar.xz linux-upstream.zip |
Adding upstream version 6.1.76.upstream/6.1.76upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'drivers/scsi/libfc/fc_frame.c')
-rw-r--r-- | drivers/scsi/libfc/fc_frame.c | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/drivers/scsi/libfc/fc_frame.c b/drivers/scsi/libfc/fc_frame.c new file mode 100644 index 000000000..f3aefb2de --- /dev/null +++ b/drivers/scsi/libfc/fc_frame.c @@ -0,0 +1,79 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright(c) 2007 Intel Corporation. All rights reserved. + * + * Maintained at www.Open-FCoE.org + */ + +/* + * Frame allocation. + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/skbuff.h> +#include <linux/crc32.h> +#include <linux/gfp.h> + +#include <scsi/fc_frame.h> + +/* + * Check the CRC in a frame. + */ +u32 fc_frame_crc_check(struct fc_frame *fp) +{ + u32 crc; + u32 error; + const u8 *bp; + unsigned int len; + + WARN_ON(!fc_frame_is_linear(fp)); + fr_flags(fp) &= ~FCPHF_CRC_UNCHECKED; + len = (fr_len(fp) + 3) & ~3; /* round up length to include fill */ + bp = (const u8 *) fr_hdr(fp); + crc = ~crc32(~0, bp, len); + error = crc ^ fr_crc(fp); + return error; +} +EXPORT_SYMBOL(fc_frame_crc_check); + +/* + * Allocate a frame intended to be sent. + * Get an sk_buff for the frame and set the length. + */ +struct fc_frame *_fc_frame_alloc(size_t len) +{ + struct fc_frame *fp; + struct sk_buff *skb; + + WARN_ON((len % sizeof(u32)) != 0); + len += sizeof(struct fc_frame_header); + skb = alloc_skb_fclone(len + FC_FRAME_HEADROOM + FC_FRAME_TAILROOM + + NET_SKB_PAD, GFP_ATOMIC); + if (!skb) + return NULL; + skb_reserve(skb, NET_SKB_PAD + FC_FRAME_HEADROOM); + fp = (struct fc_frame *) skb; + fc_frame_init(fp); + skb_put(skb, len); + return fp; +} +EXPORT_SYMBOL(_fc_frame_alloc); + +struct fc_frame *fc_frame_alloc_fill(struct fc_lport *lp, size_t payload_len) +{ + struct fc_frame *fp; + size_t fill; + + fill = payload_len % 4; + if (fill != 0) + fill = 4 - fill; + fp = _fc_frame_alloc(payload_len + fill); + if (fp) { + memset((char *) fr_hdr(fp) + payload_len, 0, fill); + /* trim is OK, we just allocated it so there are no fragments */ + skb_trim(fp_skb(fp), + payload_len + sizeof(struct fc_frame_header)); + } + return fp; +} +EXPORT_SYMBOL(fc_frame_alloc_fill); |