Commit | Line | Data |
---|---|---|
3699d92a KP |
1 | /* |
2 | * Copyright (c) 2010 Cisco Systems, Inc. | |
3 | * | |
4 | * Portions based on tcm_loop_fabric_scsi.c and libfc/fc_fcp.c | |
5 | * | |
6 | * Copyright (c) 2007 Intel Corporation. All rights reserved. | |
7 | * Copyright (c) 2008 Red Hat, Inc. All rights reserved. | |
8 | * Copyright (c) 2008 Mike Christie | |
9 | * Copyright (c) 2009 Rising Tide, Inc. | |
10 | * Copyright (c) 2009 Linux-iSCSI.org | |
11 | * Copyright (c) 2009 Nicholas A. Bellinger <nab@linux-iscsi.org> | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify it | |
14 | * under the terms and conditions of the GNU General Public License, | |
15 | * version 2, as published by the Free Software Foundation. | |
16 | * | |
17 | * This program is distributed in the hope it will be useful, but WITHOUT | |
18 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
19 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
20 | * more details. | |
21 | * | |
22 | * You should have received a copy of the GNU General Public License along with | |
23 | * this program; if not, write to the Free Software Foundation, Inc., | |
24 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | |
25 | */ | |
26 | ||
27 | /* XXX TBD some includes may be extraneous */ | |
28 | ||
29 | #include <linux/module.h> | |
30 | #include <linux/moduleparam.h> | |
31 | #include <linux/version.h> | |
32 | #include <generated/utsrelease.h> | |
33 | #include <linux/utsname.h> | |
34 | #include <linux/init.h> | |
35 | #include <linux/slab.h> | |
36 | #include <linux/kthread.h> | |
37 | #include <linux/types.h> | |
38 | #include <linux/string.h> | |
39 | #include <linux/configfs.h> | |
40 | #include <linux/ctype.h> | |
41 | #include <linux/hash.h> | |
42 | #include <asm/unaligned.h> | |
43 | #include <scsi/scsi.h> | |
44 | #include <scsi/scsi_host.h> | |
45 | #include <scsi/scsi_device.h> | |
46 | #include <scsi/scsi_cmnd.h> | |
47 | #include <scsi/libfc.h> | |
48 | #include <scsi/fc_encode.h> | |
49 | ||
50 | #include <target/target_core_base.h> | |
51 | #include <target/target_core_transport.h> | |
52 | #include <target/target_core_fabric_ops.h> | |
53 | #include <target/target_core_device.h> | |
54 | #include <target/target_core_tpg.h> | |
55 | #include <target/target_core_configfs.h> | |
56 | #include <target/target_core_base.h> | |
57 | #include <target/configfs_macros.h> | |
58 | ||
59 | #include "tcm_fc.h" | |
60 | ||
61 | /* | |
62 | * Deliver read data back to initiator. | |
63 | * XXX TBD handle resource problems later. | |
64 | */ | |
65 | int ft_queue_data_in(struct se_cmd *se_cmd) | |
66 | { | |
67 | struct ft_cmd *cmd = container_of(se_cmd, struct ft_cmd, se_cmd); | |
3699d92a KP |
68 | struct fc_frame *fp = NULL; |
69 | struct fc_exch *ep; | |
70 | struct fc_lport *lport; | |
71 | struct se_mem *mem; | |
72 | size_t remaining; | |
73 | u32 f_ctl = FC_FC_EX_CTX | FC_FC_REL_OFF; | |
74 | u32 mem_off; | |
75 | u32 fh_off = 0; | |
76 | u32 frame_off = 0; | |
77 | size_t frame_len = 0; | |
78 | size_t mem_len; | |
79 | size_t tlen; | |
80 | size_t off_in_page; | |
81 | struct page *page; | |
82 | int use_sg; | |
83 | int error; | |
84 | void *page_addr; | |
85 | void *from; | |
86 | void *to = NULL; | |
87 | ||
88 | ep = fc_seq_exch(cmd->seq); | |
89 | lport = ep->lp; | |
90 | cmd->seq = lport->tt.seq_start_next(cmd->seq); | |
91 | ||
3699d92a KP |
92 | remaining = se_cmd->data_length; |
93 | ||
94 | /* | |
95 | * Setup to use first mem list entry if any. | |
96 | */ | |
a1d8b49a AG |
97 | if (se_cmd->t_tasks_se_num) { |
98 | mem = list_first_entry(&se_cmd->t_mem_list, | |
3699d92a KP |
99 | struct se_mem, se_list); |
100 | mem_len = mem->se_len; | |
101 | mem_off = mem->se_off; | |
102 | page = mem->se_page; | |
103 | } else { | |
104 | mem = NULL; | |
105 | mem_len = remaining; | |
106 | mem_off = 0; | |
107 | page = NULL; | |
108 | } | |
109 | ||
110 | /* no scatter/gather in skb for odd word length due to fc_seq_send() */ | |
111 | use_sg = !(remaining % 4); | |
112 | ||
113 | while (remaining) { | |
114 | if (!mem_len) { | |
115 | BUG_ON(!mem); | |
116 | mem = list_entry(mem->se_list.next, | |
117 | struct se_mem, se_list); | |
118 | mem_len = min((size_t)mem->se_len, remaining); | |
119 | mem_off = mem->se_off; | |
120 | page = mem->se_page; | |
121 | } | |
122 | if (!frame_len) { | |
123 | /* | |
124 | * If lport's has capability of Large Send Offload LSO) | |
125 | * , then allow 'frame_len' to be as big as 'lso_max' | |
126 | * if indicated transfer length is >= lport->lso_max | |
127 | */ | |
128 | frame_len = (lport->seq_offload) ? lport->lso_max : | |
129 | cmd->sess->max_frame; | |
130 | frame_len = min(frame_len, remaining); | |
131 | fp = fc_frame_alloc(lport, use_sg ? 0 : frame_len); | |
132 | if (!fp) | |
133 | return -ENOMEM; | |
134 | to = fc_frame_payload_get(fp, 0); | |
135 | fh_off = frame_off; | |
136 | frame_off += frame_len; | |
137 | /* | |
138 | * Setup the frame's max payload which is used by base | |
139 | * driver to indicate HW about max frame size, so that | |
140 | * HW can do fragmentation appropriately based on | |
141 | * "gso_max_size" of underline netdev. | |
142 | */ | |
143 | fr_max_payload(fp) = cmd->sess->max_frame; | |
144 | } | |
145 | tlen = min(mem_len, frame_len); | |
146 | ||
147 | if (use_sg) { | |
148 | if (!mem) { | |
a1d8b49a AG |
149 | BUG_ON(!se_cmd->t_task_buf); |
150 | page_addr = se_cmd->t_task_buf + mem_off; | |
3699d92a KP |
151 | /* |
152 | * In this case, offset is 'offset_in_page' of | |
153 | * (t_task_buf + mem_off) instead of 'mem_off'. | |
154 | */ | |
155 | off_in_page = offset_in_page(page_addr); | |
156 | page = virt_to_page(page_addr); | |
157 | tlen = min(tlen, PAGE_SIZE - off_in_page); | |
158 | } else | |
159 | off_in_page = mem_off; | |
160 | BUG_ON(!page); | |
161 | get_page(page); | |
162 | skb_fill_page_desc(fp_skb(fp), | |
163 | skb_shinfo(fp_skb(fp))->nr_frags, | |
164 | page, off_in_page, tlen); | |
165 | fr_len(fp) += tlen; | |
166 | fp_skb(fp)->data_len += tlen; | |
167 | fp_skb(fp)->truesize += | |
168 | PAGE_SIZE << compound_order(page); | |
169 | } else if (mem) { | |
170 | BUG_ON(!page); | |
171 | from = kmap_atomic(page + (mem_off >> PAGE_SHIFT), | |
172 | KM_SOFTIRQ0); | |
173 | page_addr = from; | |
174 | from += mem_off & ~PAGE_MASK; | |
175 | tlen = min(tlen, (size_t)(PAGE_SIZE - | |
176 | (mem_off & ~PAGE_MASK))); | |
177 | memcpy(to, from, tlen); | |
178 | kunmap_atomic(page_addr, KM_SOFTIRQ0); | |
179 | to += tlen; | |
180 | } else { | |
a1d8b49a | 181 | from = se_cmd->t_task_buf + mem_off; |
3699d92a KP |
182 | memcpy(to, from, tlen); |
183 | to += tlen; | |
184 | } | |
185 | ||
186 | mem_off += tlen; | |
187 | mem_len -= tlen; | |
188 | frame_len -= tlen; | |
189 | remaining -= tlen; | |
190 | ||
191 | if (frame_len && | |
192 | (skb_shinfo(fp_skb(fp))->nr_frags < FC_FRAME_SG_LEN)) | |
193 | continue; | |
194 | if (!remaining) | |
195 | f_ctl |= FC_FC_END_SEQ; | |
196 | fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, | |
197 | FC_TYPE_FCP, f_ctl, fh_off); | |
198 | error = lport->tt.seq_send(lport, cmd->seq, fp); | |
199 | if (error) { | |
200 | /* XXX For now, initiator will retry */ | |
201 | if (printk_ratelimit()) | |
202 | printk(KERN_ERR "%s: Failed to send frame %p, " | |
95efa286 | 203 | "xid <0x%x>, remaining %zu, " |
3699d92a KP |
204 | "lso_max <0x%x>\n", |
205 | __func__, fp, ep->xid, | |
206 | remaining, lport->lso_max); | |
207 | } | |
208 | } | |
209 | return ft_queue_status(se_cmd); | |
210 | } | |
211 | ||
212 | /* | |
213 | * Receive write data frame. | |
214 | */ | |
215 | void ft_recv_write_data(struct ft_cmd *cmd, struct fc_frame *fp) | |
216 | { | |
217 | struct se_cmd *se_cmd = &cmd->se_cmd; | |
218 | struct fc_seq *seq = cmd->seq; | |
219 | struct fc_exch *ep; | |
220 | struct fc_lport *lport; | |
3699d92a KP |
221 | struct fc_frame_header *fh; |
222 | struct se_mem *mem; | |
223 | u32 mem_off; | |
224 | u32 rel_off; | |
225 | size_t frame_len; | |
226 | size_t mem_len; | |
227 | size_t tlen; | |
228 | struct page *page; | |
229 | void *page_addr; | |
230 | void *from; | |
231 | void *to; | |
232 | u32 f_ctl; | |
233 | void *buf; | |
234 | ||
3699d92a KP |
235 | fh = fc_frame_header_get(fp); |
236 | if (!(ntoh24(fh->fh_f_ctl) & FC_FC_REL_OFF)) | |
237 | goto drop; | |
238 | ||
239 | /* | |
240 | * Doesn't expect even single byte of payload. Payload | |
241 | * is expected to be copied directly to user buffers | |
242 | * due to DDP (Large Rx offload) feature, hence | |
243 | * BUG_ON if BUF is non-NULL | |
244 | */ | |
245 | buf = fc_frame_payload_get(fp, 1); | |
246 | if (cmd->was_ddp_setup && buf) { | |
247 | printk(KERN_INFO "%s: When DDP was setup, not expected to" | |
248 | "receive frame with payload, Payload shall be" | |
249 | "copied directly to buffer instead of coming " | |
250 | "via. legacy receive queues\n", __func__); | |
251 | BUG_ON(buf); | |
252 | } | |
253 | ||
254 | /* | |
255 | * If ft_cmd indicated 'ddp_setup', in that case only the last frame | |
256 | * should come with 'TSI bit being set'. If 'TSI bit is not set and if | |
257 | * data frame appears here, means error condition. In both the cases | |
258 | * release the DDP context (ddp_put) and in error case, as well | |
259 | * initiate error recovery mechanism. | |
260 | */ | |
261 | ep = fc_seq_exch(seq); | |
262 | if (cmd->was_ddp_setup) { | |
263 | BUG_ON(!ep); | |
264 | lport = ep->lp; | |
265 | BUG_ON(!lport); | |
266 | } | |
267 | if (cmd->was_ddp_setup && ep->xid != FC_XID_UNKNOWN) { | |
268 | f_ctl = ntoh24(fh->fh_f_ctl); | |
269 | /* | |
270 | * If TSI bit set in f_ctl, means last write data frame is | |
271 | * received successfully where payload is posted directly | |
272 | * to user buffer and only the last frame's header is posted | |
273 | * in legacy receive queue | |
274 | */ | |
275 | if (f_ctl & FC_FC_SEQ_INIT) { /* TSI bit set in FC frame */ | |
276 | cmd->write_data_len = lport->tt.ddp_done(lport, | |
277 | ep->xid); | |
278 | goto last_frame; | |
279 | } else { | |
280 | /* | |
281 | * Updating the write_data_len may be meaningless at | |
282 | * this point, but just in case if required in future | |
283 | * for debugging or any other purpose | |
284 | */ | |
285 | printk(KERN_ERR "%s: Received frame with TSI bit not" | |
286 | " being SET, dropping the frame, " | |
287 | "cmd->sg <%p>, cmd->sg_cnt <0x%x>\n", | |
288 | __func__, cmd->sg, cmd->sg_cnt); | |
289 | cmd->write_data_len = lport->tt.ddp_done(lport, | |
290 | ep->xid); | |
291 | lport->tt.seq_exch_abort(cmd->seq, 0); | |
292 | goto drop; | |
293 | } | |
294 | } | |
295 | ||
296 | rel_off = ntohl(fh->fh_parm_offset); | |
297 | frame_len = fr_len(fp); | |
298 | if (frame_len <= sizeof(*fh)) | |
299 | goto drop; | |
300 | frame_len -= sizeof(*fh); | |
301 | from = fc_frame_payload_get(fp, 0); | |
302 | if (rel_off >= se_cmd->data_length) | |
303 | goto drop; | |
304 | if (frame_len + rel_off > se_cmd->data_length) | |
305 | frame_len = se_cmd->data_length - rel_off; | |
306 | ||
307 | /* | |
308 | * Setup to use first mem list entry if any. | |
309 | */ | |
a1d8b49a AG |
310 | if (se_cmd->t_tasks_se_num) { |
311 | mem = list_first_entry(&se_cmd->t_mem_list, | |
3699d92a KP |
312 | struct se_mem, se_list); |
313 | mem_len = mem->se_len; | |
314 | mem_off = mem->se_off; | |
315 | page = mem->se_page; | |
316 | } else { | |
317 | mem = NULL; | |
318 | page = NULL; | |
319 | mem_off = 0; | |
320 | mem_len = frame_len; | |
321 | } | |
322 | ||
323 | while (frame_len) { | |
324 | if (!mem_len) { | |
325 | BUG_ON(!mem); | |
326 | mem = list_entry(mem->se_list.next, | |
327 | struct se_mem, se_list); | |
328 | mem_len = mem->se_len; | |
329 | mem_off = mem->se_off; | |
330 | page = mem->se_page; | |
331 | } | |
332 | if (rel_off >= mem_len) { | |
333 | rel_off -= mem_len; | |
334 | mem_len = 0; | |
335 | continue; | |
336 | } | |
337 | mem_off += rel_off; | |
338 | mem_len -= rel_off; | |
339 | rel_off = 0; | |
340 | ||
341 | tlen = min(mem_len, frame_len); | |
342 | ||
343 | if (mem) { | |
344 | to = kmap_atomic(page + (mem_off >> PAGE_SHIFT), | |
345 | KM_SOFTIRQ0); | |
346 | page_addr = to; | |
347 | to += mem_off & ~PAGE_MASK; | |
348 | tlen = min(tlen, (size_t)(PAGE_SIZE - | |
349 | (mem_off & ~PAGE_MASK))); | |
350 | memcpy(to, from, tlen); | |
351 | kunmap_atomic(page_addr, KM_SOFTIRQ0); | |
352 | } else { | |
a1d8b49a | 353 | to = se_cmd->t_task_buf + mem_off; |
3699d92a KP |
354 | memcpy(to, from, tlen); |
355 | } | |
356 | from += tlen; | |
357 | frame_len -= tlen; | |
358 | mem_off += tlen; | |
359 | mem_len -= tlen; | |
360 | cmd->write_data_len += tlen; | |
361 | } | |
362 | last_frame: | |
363 | if (cmd->write_data_len == se_cmd->data_length) | |
364 | transport_generic_handle_data(se_cmd); | |
365 | drop: | |
366 | fc_frame_free(fp); | |
367 | } |