aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libfc/fc_libfc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/libfc/fc_libfc.c')
-rw-r--r--drivers/scsi/libfc/fc_libfc.c78
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 @@
23#include <linux/crc32.h> 23#include <linux/crc32.h>
24 24
25#include <scsi/libfc.h> 25#include <scsi/libfc.h>
26#include <scsi/fc_encode.h>
26 27
27#include "fc_libfc.h" 28#include "fc_libfc.h"
28 29
@@ -132,3 +133,80 @@ u32 fc_copy_buffer_to_sglist(void *buf, size_t len,
132 } 133 }
133 return copy_len; 134 return copy_len;
134} 135}
136
137/**
138 * fc_fill_hdr() - fill FC header fields based on request
139 * @fp: reply frame containing header to be filled in
140 * @in_fp: request frame containing header to use in filling in reply
141 * @r_ctl: R_CTL value for header
142 * @f_ctl: F_CTL value for header, with 0 pad
143 * @seq_cnt: sequence count for the header, ignored if frame has a sequence
144 * @parm_offset: parameter / offset value
145 */
146void fc_fill_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
147 enum fc_rctl r_ctl, u32 f_ctl, u16 seq_cnt, u32 parm_offset)
148{
149 struct fc_frame_header *fh;
150 struct fc_frame_header *in_fh;
151 struct fc_seq *sp;
152 u32 fill;
153
154 fh = __fc_frame_header_get(fp);
155 in_fh = __fc_frame_header_get(in_fp);
156
157 if (f_ctl & FC_FC_END_SEQ) {
158 fill = -fr_len(fp) & 3;
159 if (fill) {
160 /* TODO, this may be a problem with fragmented skb */
161 memset(skb_put(fp_skb(fp), fill), 0, fill);
162 f_ctl |= fill;
163 }
164 fr_eof(fp) = FC_EOF_T;
165 } else {
166 WARN_ON(fr_len(fp) % 4 != 0); /* no pad to non last frame */
167 fr_eof(fp) = FC_EOF_N;
168 }
169
170 fh->fh_r_ctl = r_ctl;
171 memcpy(fh->fh_d_id, in_fh->fh_s_id, sizeof(fh->fh_d_id));
172 memcpy(fh->fh_s_id, in_fh->fh_d_id, sizeof(fh->fh_s_id));
173 fh->fh_type = in_fh->fh_type;
174 hton24(fh->fh_f_ctl, f_ctl);
175 fh->fh_ox_id = in_fh->fh_ox_id;
176 fh->fh_rx_id = in_fh->fh_rx_id;
177 fh->fh_cs_ctl = 0;
178 fh->fh_df_ctl = 0;
179 fh->fh_parm_offset = htonl(parm_offset);
180
181 sp = fr_seq(in_fp);
182 if (sp) {
183 fr_seq(fp) = sp;
184 fh->fh_seq_id = sp->id;
185 seq_cnt = sp->cnt;
186 } else {
187 fh->fh_seq_id = 0;
188 }
189 fh->fh_seq_cnt = ntohs(seq_cnt);
190 fr_sof(fp) = seq_cnt ? FC_SOF_N3 : FC_SOF_I3;
191 fr_encaps(fp) = fr_encaps(in_fp);
192}
193EXPORT_SYMBOL(fc_fill_hdr);
194
195/**
196 * fc_fill_reply_hdr() - fill FC reply header fields based on request
197 * @fp: reply frame containing header to be filled in
198 * @in_fp: request frame containing header to use in filling in reply
199 * @r_ctl: R_CTL value for reply
200 * @parm_offset: parameter / offset value
201 */
202void fc_fill_reply_hdr(struct fc_frame *fp, const struct fc_frame *in_fp,
203 enum fc_rctl r_ctl, u32 parm_offset)
204{
205 struct fc_seq *sp;
206
207 sp = fr_seq(in_fp);
208 if (sp)
209 fr_seq(fp) = fr_dev(in_fp)->tt.seq_start_next(sp);
210 fc_fill_hdr(fp, in_fp, r_ctl, FC_FCTL_RESP, 0, parm_offset);
211}
212EXPORT_SYMBOL(fc_fill_reply_hdr);