diff options
author | Joe Eykholt <jeykholt@cisco.com> | 2010-07-20 15:21:01 -0700 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2010-07-28 09:06:00 -0500 |
commit | 24f089e2f2c800f88039e9d536d558ec6e349fad (patch) | |
tree | 59cf263f112e176015a3a37c3928cc3d2a4dfcb5 /drivers/scsi/libfc/fc_libfc.c | |
parent | 251748a99e631a2c46edcf9e519cfc60fae8153d (diff) | |
download | blackbird-op-linux-24f089e2f2c800f88039e9d536d558ec6e349fad.tar.gz blackbird-op-linux-24f089e2f2c800f88039e9d536d558ec6e349fad.zip |
[SCSI] libfc: add fc_fill_reply_hdr() and fc_fill_hdr()
Add functions to fill in an FC header given a request header.
These reduces code lines in fc_lport and fc_rport and works
without an exchange/sequence assigned.
fc_fill_reply_hdr() fills a header for a final reply frame.
fc_fill_hdr() which is similar but allows specifying the
f_ctl parameter.
Add defines for F_CTL values FC_FCTL_REQ and FC_FCTL_RESP.
These can be used for most request and response sequences.
v2 of patch adds a line to copy the frame encapsulation
info from the received frame.
Signed-off-by: Joe Eykholt <jeykholt@cisco.com>
Signed-off-by: Robert Love <robert.w.love@intel.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/libfc/fc_libfc.c')
-rw-r--r-- | drivers/scsi/libfc/fc_libfc.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/scsi/libfc/fc_libfc.c b/drivers/scsi/libfc/fc_libfc.c index 39f4b6ab04b4..6a48c28e4420 100644 --- a/drivers/scsi/libfc/fc_libfc.c +++ b/drivers/scsi/libfc/fc_libfc.c @@ -23,6 +23,7 @@ #include <linux/crc32.h> #include <scsi/libfc.h> +#include <scsi/fc_encode.h> #include "fc_libfc.h" @@ -132,3 +133,80 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len, } return copy_len; } + +/** + * fc_fill_hdr() - fill FC header fields based on request + * @fp: reply frame containing header to be filled in + * @in_fp: request frame containing header to use in filling in reply + * @r_ctl: R_CTL value for header + * @f_ctl: F_CTL value for header, with 0 pad + * @seq_cnt: sequence count for the header, ignored if frame has a sequence + * @parm_offset: parameter / offset value + */ +void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, + enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset) +{ + struct fc_frame_header *fh; + struct fc_frame_header *in_fh; + struct fc_seq *sp; + u32 fill; + + fh = __fc_frame_header_get(fp); + in_fh = __fc_frame_header_get(in_fp); + + if (f_ctl & FC_FC_END_SEQ) { + fill = -fr_len(fp) & 3; + if (fill) { + /* TODO, this may be a problem with fragmented skb */ + memset(skb_put(fp_skb(fp), fill), 0, fill); + f_ctl |= fill; + } + fr_eof(fp) = FC_EOF_T; + } else { + WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */ + fr_eof(fp) = FC_EOF_N; + } + + fh->fh_r_ctl = r_ctl; + memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id)); + memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id)); + fh->fh_type = in_fh->fh_type; + hton24(fh->fh_f_ctl, f_ctl); + fh->fh_ox_id = in_fh->fh_ox_id; + fh->fh_rx_id = in_fh->fh_rx_id; + fh->fh_cs_ctl = 0; + fh->fh_df_ctl = 0; + fh->fh_parm_offset = htonl(parm_offset); + + sp = fr_seq(in_fp); + if (sp) { + fr_seq(fp) = sp; + fh->fh_seq_id = sp->id; + seq_cnt = sp->cnt; + } else { + fh->fh_seq_id = 0; + } + fh->fh_seq_cnt = ntohs(seq_cnt); + fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3; + fr_encaps(fp) = fr_encaps(in_fp); +} +EXPORT_SYMBOL(fc_fill_hdr); + +/** + * fc_fill_reply_hdr() - fill FC reply header fields based on request + * @fp: reply frame containing header to be filled in + * @in_fp: request frame containing header to use in filling in reply + * @r_ctl: R_CTL value for reply + * @parm_offset: parameter / offset value + */ +void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp, + enum fc_rctl r_ctl, u32 parm_offset) +{ + struct fc_seq *sp; + + sp = fr_seq(in_fp); + if (sp) + fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp); + fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset); +} +EXPORT_SYMBOL(fc_fill_reply_hdr); |