diff options
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 @@ | |||
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 | */ | ||
146 | void 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 | } | ||
193 | EXPORT_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 | */ | ||
202 | void 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 | } | ||
212 | EXPORT_SYMBOL(fc_fill_reply_hdr); | ||