diff options
author | Sheng Yang <sheng@yasker.org> | 2016-02-26 17:59:57 -0500 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2016-03-11 00:49:02 -0500 |
commit | 26418649eead52619d8dd6cbc6760a1b144dbcd2 (patch) | |
tree | 89baa8edf0b0f25f1a2c19a113ce064848e1e72b | |
parent | 0c28481ffb4683ef21c6664d15dbd5ae5a6cd027 (diff) |
target/user: Introduce data_bitmap, replace data_length/data_head/data_tail
The data_bitmap was introduced to support asynchornization accessing of
data area.
We divide mailbox data area into blocks, and use data_bitmap to track the
usage of data area. All the new command's data would start with a new block,
and may left unusable space after it end. But it's easy to track using
data_bitmap.
Now we can allocate data area for asynchronization accessing from userspace,
since we can track the allocation using data_bitmap. The userspace part would
be the same as Maxim's previous asynchronized implementation.
Signed-off-by: Sheng Yang <sheng@yasker.org>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_user.c | 221 |
1 files changed, 121 insertions, 100 deletions
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index baa8720ab24f..b1539f357429 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/vmalloc.h> | 26 | #include <linux/vmalloc.h> |
27 | #include <linux/uio_driver.h> | 27 | #include <linux/uio_driver.h> |
28 | #include <linux/stringify.h> | 28 | #include <linux/stringify.h> |
29 | #include <linux/bitops.h> | ||
29 | #include <net/genetlink.h> | 30 | #include <net/genetlink.h> |
30 | #include <scsi/scsi_common.h> | 31 | #include <scsi/scsi_common.h> |
31 | #include <scsi/scsi_proto.h> | 32 | #include <scsi/scsi_proto.h> |
@@ -63,8 +64,11 @@ | |||
63 | 64 | ||
64 | #define TCMU_TIME_OUT (30 * MSEC_PER_SEC) | 65 | #define TCMU_TIME_OUT (30 * MSEC_PER_SEC) |
65 | 66 | ||
67 | #define DATA_BLOCK_BITS 256 | ||
68 | #define DATA_BLOCK_SIZE 4096 | ||
69 | |||
66 | #define CMDR_SIZE (16 * 4096) | 70 | #define CMDR_SIZE (16 * 4096) |
67 | #define DATA_SIZE (257 * 4096) | 71 | #define DATA_SIZE (DATA_BLOCK_BITS * DATA_BLOCK_SIZE) |
68 | 72 | ||
69 | #define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) | 73 | #define TCMU_RING_SIZE (CMDR_SIZE + DATA_SIZE) |
70 | 74 | ||
@@ -93,12 +97,11 @@ struct tcmu_dev { | |||
93 | u32 cmdr_size; | 97 | u32 cmdr_size; |
94 | u32 cmdr_last_cleaned; | 98 | u32 cmdr_last_cleaned; |
95 | /* Offset of data ring from start of mb */ | 99 | /* Offset of data ring from start of mb */ |
100 | /* Must add data_off and mb_addr to get the address */ | ||
96 | size_t data_off; | 101 | size_t data_off; |
97 | size_t data_size; | 102 | size_t data_size; |
98 | /* Ring head + tail values. */ | 103 | |
99 | /* Must add data_off and mb_addr to get the address */ | 104 | DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS); |
100 | size_t data_head; | ||
101 | size_t data_tail; | ||
102 | 105 | ||
103 | wait_queue_head_t wait_cmdr; | 106 | wait_queue_head_t wait_cmdr; |
104 | /* TODO should this be a mutex? */ | 107 | /* TODO should this be a mutex? */ |
@@ -122,9 +125,9 @@ struct tcmu_cmd { | |||
122 | 125 | ||
123 | uint16_t cmd_id; | 126 | uint16_t cmd_id; |
124 | 127 | ||
125 | /* Can't use se_cmd->data_length when cleaning up expired cmds, because if | 128 | /* Can't use se_cmd when cleaning up expired cmds, because if |
126 | cmd has been completed then accessing se_cmd is off limits */ | 129 | cmd has been completed then accessing se_cmd is off limits */ |
127 | size_t data_length; | 130 | DECLARE_BITMAP(data_bitmap, DATA_BLOCK_BITS); |
128 | 131 | ||
129 | unsigned long deadline; | 132 | unsigned long deadline; |
130 | 133 | ||
@@ -168,13 +171,6 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) | |||
168 | 171 | ||
169 | tcmu_cmd->se_cmd = se_cmd; | 172 | tcmu_cmd->se_cmd = se_cmd; |
170 | tcmu_cmd->tcmu_dev = udev; | 173 | tcmu_cmd->tcmu_dev = udev; |
171 | tcmu_cmd->data_length = se_cmd->data_length; | ||
172 | |||
173 | if (se_cmd->se_cmd_flags & SCF_BIDI) { | ||
174 | BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); | ||
175 | tcmu_cmd->data_length += se_cmd->t_bidi_data_sg->length; | ||
176 | } | ||
177 | |||
178 | tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT); | 174 | tcmu_cmd->deadline = jiffies + msecs_to_jiffies(TCMU_TIME_OUT); |
179 | 175 | ||
180 | idr_preload(GFP_KERNEL); | 176 | idr_preload(GFP_KERNEL); |
@@ -242,111 +238,115 @@ static inline void new_iov(struct iovec **iov, int *iov_cnt, | |||
242 | 238 | ||
243 | iovec = *iov; | 239 | iovec = *iov; |
244 | memset(iovec, 0, sizeof(struct iovec)); | 240 | memset(iovec, 0, sizeof(struct iovec)); |
245 | |||
246 | /* Even iov_base is relative to mb_addr */ | ||
247 | iovec->iov_base = (void __user *) udev->data_off + | ||
248 | udev->data_head; | ||
249 | } | 241 | } |
250 | 242 | ||
251 | #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) | 243 | #define UPDATE_HEAD(head, used, size) smp_store_release(&head, ((head % size) + used) % size) |
252 | 244 | ||
245 | /* offset is relative to mb_addr */ | ||
246 | static inline size_t get_block_offset(struct tcmu_dev *dev, | ||
247 | int block, int remaining) | ||
248 | { | ||
249 | return dev->data_off + block * DATA_BLOCK_SIZE + | ||
250 | DATA_BLOCK_SIZE - remaining; | ||
251 | } | ||
252 | |||
253 | static inline size_t iov_tail(struct tcmu_dev *udev, struct iovec *iov) | ||
254 | { | ||
255 | return (size_t)iov->iov_base + iov->iov_len; | ||
256 | } | ||
257 | |||
253 | static void alloc_and_scatter_data_area(struct tcmu_dev *udev, | 258 | static void alloc_and_scatter_data_area(struct tcmu_dev *udev, |
254 | struct scatterlist *data_sg, unsigned int data_nents, | 259 | struct scatterlist *data_sg, unsigned int data_nents, |
255 | struct iovec **iov, int *iov_cnt, bool copy_data) | 260 | struct iovec **iov, int *iov_cnt, bool copy_data) |
256 | { | 261 | { |
257 | int i; | 262 | int i, block; |
263 | int block_remaining = 0; | ||
258 | void *from, *to; | 264 | void *from, *to; |
259 | size_t copy_bytes; | 265 | size_t copy_bytes, to_offset; |
260 | struct scatterlist *sg; | 266 | struct scatterlist *sg; |
261 | 267 | ||
262 | if (data_nents == 0) | ||
263 | return; | ||
264 | |||
265 | new_iov(iov, iov_cnt, udev); | ||
266 | for_each_sg(data_sg, sg, data_nents, i) { | 268 | for_each_sg(data_sg, sg, data_nents, i) { |
267 | copy_bytes = min_t(size_t, sg->length, | 269 | int sg_remaining = sg->length; |
268 | head_to_end(udev->data_head, udev->data_size)); | ||
269 | from = kmap_atomic(sg_page(sg)) + sg->offset; | 270 | from = kmap_atomic(sg_page(sg)) + sg->offset; |
270 | to = (void *) udev->mb_addr + udev->data_off + udev->data_head; | 271 | while (sg_remaining > 0) { |
271 | 272 | if (block_remaining == 0) { | |
272 | if (copy_data) { | 273 | block = find_first_zero_bit(udev->data_bitmap, |
273 | memcpy(to, from, copy_bytes); | 274 | DATA_BLOCK_BITS); |
274 | tcmu_flush_dcache_range(to, copy_bytes); | 275 | block_remaining = DATA_BLOCK_SIZE; |
275 | } | 276 | set_bit(block, udev->data_bitmap); |
276 | 277 | } | |
277 | (*iov)->iov_len += copy_bytes; | 278 | copy_bytes = min_t(size_t, sg_remaining, |
278 | 279 | block_remaining); | |
279 | UPDATE_HEAD(udev->data_head, copy_bytes, udev->data_size); | 280 | to_offset = get_block_offset(udev, block, |
280 | 281 | block_remaining); | |
281 | /* Uh oh, we wrapped the buffer. Must split sg across 2 iovs. */ | 282 | to = (void *)udev->mb_addr + to_offset; |
282 | if (sg->length != copy_bytes) { | 283 | if (*iov_cnt != 0 && |
283 | void *from_skip = from + copy_bytes; | 284 | to_offset == iov_tail(udev, *iov)) { |
284 | 285 | (*iov)->iov_len += copy_bytes; | |
285 | copy_bytes = sg->length - copy_bytes; | 286 | } else { |
286 | 287 | new_iov(iov, iov_cnt, udev); | |
287 | new_iov(iov, iov_cnt, udev); | 288 | (*iov)->iov_base = (void __user *) to_offset; |
288 | (*iov)->iov_len = copy_bytes; | 289 | (*iov)->iov_len = copy_bytes; |
289 | 290 | } | |
290 | if (copy_data) { | 291 | if (copy_data) { |
291 | to = (void *) udev->mb_addr + | 292 | memcpy(to, from + sg->length - sg_remaining, |
292 | udev->data_off + udev->data_head; | 293 | copy_bytes); |
293 | memcpy(to, from_skip, copy_bytes); | ||
294 | tcmu_flush_dcache_range(to, copy_bytes); | 294 | tcmu_flush_dcache_range(to, copy_bytes); |
295 | } | 295 | } |
296 | 296 | sg_remaining -= copy_bytes; | |
297 | 297 | block_remaining -= copy_bytes; | |
298 | UPDATE_HEAD(udev->data_head, | ||
299 | copy_bytes, udev->data_size); | ||
300 | } | 298 | } |
301 | |||
302 | kunmap_atomic(from - sg->offset); | 299 | kunmap_atomic(from - sg->offset); |
303 | } | 300 | } |
304 | } | 301 | } |
305 | 302 | ||
306 | static void free_data_area(struct tcmu_dev *udev, size_t length) | 303 | static void free_data_area(struct tcmu_dev *udev, struct tcmu_cmd *cmd) |
307 | { | 304 | { |
308 | UPDATE_HEAD(udev->data_tail, length, udev->data_size); | 305 | bitmap_xor(udev->data_bitmap, udev->data_bitmap, cmd->data_bitmap, |
306 | DATA_BLOCK_BITS); | ||
309 | } | 307 | } |
310 | 308 | ||
311 | static void gather_and_free_data_area(struct tcmu_dev *udev, | 309 | static void gather_data_area(struct tcmu_dev *udev, unsigned long *cmd_bitmap, |
312 | struct scatterlist *data_sg, unsigned int data_nents) | 310 | struct scatterlist *data_sg, unsigned int data_nents) |
313 | { | 311 | { |
314 | int i; | 312 | int i, block; |
313 | int block_remaining = 0; | ||
315 | void *from, *to; | 314 | void *from, *to; |
316 | size_t copy_bytes; | 315 | size_t copy_bytes, from_offset; |
317 | struct scatterlist *sg; | 316 | struct scatterlist *sg; |
318 | 317 | ||
319 | /* It'd be easier to look at entry's iovec again, but UAM */ | ||
320 | for_each_sg(data_sg, sg, data_nents, i) { | 318 | for_each_sg(data_sg, sg, data_nents, i) { |
321 | copy_bytes = min_t(size_t, sg->length, | 319 | int sg_remaining = sg->length; |
322 | head_to_end(udev->data_tail, udev->data_size)); | ||
323 | |||
324 | to = kmap_atomic(sg_page(sg)) + sg->offset; | 320 | to = kmap_atomic(sg_page(sg)) + sg->offset; |
325 | WARN_ON(sg->length + sg->offset > PAGE_SIZE); | 321 | while (sg_remaining > 0) { |
326 | from = (void *) udev->mb_addr + | 322 | if (block_remaining == 0) { |
327 | udev->data_off + udev->data_tail; | 323 | block = find_first_bit(cmd_bitmap, |
328 | tcmu_flush_dcache_range(from, copy_bytes); | 324 | DATA_BLOCK_BITS); |
329 | memcpy(to, from, copy_bytes); | 325 | block_remaining = DATA_BLOCK_SIZE; |
330 | 326 | clear_bit(block, cmd_bitmap); | |
331 | free_data_area(udev, copy_bytes); | 327 | } |
332 | 328 | copy_bytes = min_t(size_t, sg_remaining, | |
333 | /* Uh oh, wrapped the data buffer for this sg's data */ | 329 | block_remaining); |
334 | if (sg->length != copy_bytes) { | 330 | from_offset = get_block_offset(udev, block, |
335 | void *to_skip = to + copy_bytes; | 331 | block_remaining); |
336 | 332 | from = (void *) udev->mb_addr + from_offset; | |
337 | from = (void *) udev->mb_addr + | ||
338 | udev->data_off + udev->data_tail; | ||
339 | WARN_ON(udev->data_tail); | ||
340 | copy_bytes = sg->length - copy_bytes; | ||
341 | tcmu_flush_dcache_range(from, copy_bytes); | 333 | tcmu_flush_dcache_range(from, copy_bytes); |
342 | memcpy(to_skip, from, copy_bytes); | 334 | memcpy(to + sg->length - sg_remaining, from, |
335 | copy_bytes); | ||
343 | 336 | ||
344 | free_data_area(udev, copy_bytes); | 337 | sg_remaining -= copy_bytes; |
338 | block_remaining -= copy_bytes; | ||
345 | } | 339 | } |
346 | kunmap_atomic(to - sg->offset); | 340 | kunmap_atomic(to - sg->offset); |
347 | } | 341 | } |
348 | } | 342 | } |
349 | 343 | ||
344 | static inline size_t spc_bitmap_free(unsigned long *bitmap) | ||
345 | { | ||
346 | return DATA_BLOCK_SIZE * (DATA_BLOCK_BITS - | ||
347 | bitmap_weight(bitmap, DATA_BLOCK_BITS)); | ||
348 | } | ||
349 | |||
350 | /* | 350 | /* |
351 | * We can't queue a command until we have space available on the cmd ring *and* | 351 | * We can't queue a command until we have space available on the cmd ring *and* |
352 | * space available on the data ring. | 352 | * space available on the data ring. |
@@ -380,10 +380,10 @@ static bool is_ring_space_avail(struct tcmu_dev *udev, size_t cmd_size, size_t d | |||
380 | return false; | 380 | return false; |
381 | } | 381 | } |
382 | 382 | ||
383 | space = spc_free(udev->data_head, udev->data_tail, udev->data_size); | 383 | space = spc_bitmap_free(udev->data_bitmap); |
384 | if (space < data_needed) { | 384 | if (space < data_needed) { |
385 | pr_debug("no data space: %zu %zu %zu\n", udev->data_head, | 385 | pr_debug("no data space: only %lu available, but ask for %lu\n", |
386 | udev->data_tail, udev->data_size); | 386 | space, data_needed); |
387 | return false; | 387 | return false; |
388 | } | 388 | } |
389 | 389 | ||
@@ -402,6 +402,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
402 | uint32_t cmd_head; | 402 | uint32_t cmd_head; |
403 | uint64_t cdb_off; | 403 | uint64_t cdb_off; |
404 | bool copy_to_data_area; | 404 | bool copy_to_data_area; |
405 | size_t data_length; | ||
406 | DECLARE_BITMAP(old_bitmap, DATA_BLOCK_BITS); | ||
405 | 407 | ||
406 | if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) | 408 | if (test_bit(TCMU_DEV_BIT_BROKEN, &udev->flags)) |
407 | return -EINVAL; | 409 | return -EINVAL; |
@@ -410,10 +412,12 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
410 | * Must be a certain minimum size for response sense info, but | 412 | * Must be a certain minimum size for response sense info, but |
411 | * also may be larger if the iov array is large. | 413 | * also may be larger if the iov array is large. |
412 | * | 414 | * |
413 | * 3 iovs since we can describe the whole continuous are using one | 415 | * We prepare way too many iovs for potential uses here, because it's |
414 | * for data, one for bidi and one more in the case of wrap. | 416 | * expensive to tell how many regions are freed in the bitmap |
415 | */ | 417 | */ |
416 | base_command_size = max(offsetof(struct tcmu_cmd_entry, req.iov[3]), | 418 | base_command_size = max(offsetof(struct tcmu_cmd_entry, |
419 | req.iov[se_cmd->t_bidi_data_nents + | ||
420 | se_cmd->t_data_nents]), | ||
417 | sizeof(struct tcmu_cmd_entry)); | 421 | sizeof(struct tcmu_cmd_entry)); |
418 | command_size = base_command_size | 422 | command_size = base_command_size |
419 | + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); | 423 | + round_up(scsi_command_size(se_cmd->t_task_cdb), TCMU_OP_ALIGN_SIZE); |
@@ -424,13 +428,18 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
424 | 428 | ||
425 | mb = udev->mb_addr; | 429 | mb = udev->mb_addr; |
426 | cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ | 430 | cmd_head = mb->cmd_head % udev->cmdr_size; /* UAM */ |
431 | data_length = se_cmd->data_length; | ||
432 | if (se_cmd->se_cmd_flags & SCF_BIDI) { | ||
433 | BUG_ON(!(se_cmd->t_bidi_data_sg && se_cmd->t_bidi_data_nents)); | ||
434 | data_length += se_cmd->t_bidi_data_sg->length; | ||
435 | } | ||
427 | if ((command_size > (udev->cmdr_size / 2)) | 436 | if ((command_size > (udev->cmdr_size / 2)) |
428 | || tcmu_cmd->data_length > (udev->data_size - 1)) | 437 | || data_length > udev->data_size) |
429 | pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " | 438 | pr_warn("TCMU: Request of size %zu/%zu may be too big for %u/%zu " |
430 | "cmd/data ring buffers\n", command_size, tcmu_cmd->data_length, | 439 | "cmd/data ring buffers\n", command_size, data_length, |
431 | udev->cmdr_size, udev->data_size); | 440 | udev->cmdr_size, udev->data_size); |
432 | 441 | ||
433 | while (!is_ring_space_avail(udev, command_size, tcmu_cmd->data_length)) { | 442 | while (!is_ring_space_avail(udev, command_size, data_length)) { |
434 | int ret; | 443 | int ret; |
435 | DEFINE_WAIT(__wait); | 444 | DEFINE_WAIT(__wait); |
436 | 445 | ||
@@ -477,6 +486,8 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
477 | entry->hdr.kflags = 0; | 486 | entry->hdr.kflags = 0; |
478 | entry->hdr.uflags = 0; | 487 | entry->hdr.uflags = 0; |
479 | 488 | ||
489 | bitmap_copy(old_bitmap, udev->data_bitmap, DATA_BLOCK_BITS); | ||
490 | |||
480 | /* | 491 | /* |
481 | * Fix up iovecs, and handle if allocation in data ring wrapped. | 492 | * Fix up iovecs, and handle if allocation in data ring wrapped. |
482 | */ | 493 | */ |
@@ -495,6 +506,10 @@ static int tcmu_queue_cmd_ring(struct tcmu_cmd *tcmu_cmd) | |||
495 | se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false); | 506 | se_cmd->t_bidi_data_nents, &iov, &iov_cnt, false); |
496 | entry->req.iov_bidi_cnt = iov_cnt; | 507 | entry->req.iov_bidi_cnt = iov_cnt; |
497 | 508 | ||
509 | /* cmd's data_bitmap is what changed in process */ | ||
510 | bitmap_xor(tcmu_cmd->data_bitmap, old_bitmap, udev->data_bitmap, | ||
511 | DATA_BLOCK_BITS); | ||
512 | |||
498 | /* All offsets relative to mb_addr, not start of entry! */ | 513 | /* All offsets relative to mb_addr, not start of entry! */ |
499 | cdb_off = CMDR_OFF + cmd_head + base_command_size; | 514 | cdb_off = CMDR_OFF + cmd_head + base_command_size; |
500 | memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb)); | 515 | memcpy((void *) mb + cdb_off, se_cmd->t_task_cdb, scsi_command_size(se_cmd->t_task_cdb)); |
@@ -547,31 +562,36 @@ static void tcmu_handle_completion(struct tcmu_cmd *cmd, struct tcmu_cmd_entry * | |||
547 | if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { | 562 | if (test_bit(TCMU_CMD_BIT_EXPIRED, &cmd->flags)) { |
548 | /* cmd has been completed already from timeout, just reclaim data | 563 | /* cmd has been completed already from timeout, just reclaim data |
549 | ring space */ | 564 | ring space */ |
550 | free_data_area(udev, cmd->data_length); | 565 | free_data_area(udev, cmd); |
551 | return; | 566 | return; |
552 | } | 567 | } |
553 | 568 | ||
554 | if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { | 569 | if (entry->hdr.uflags & TCMU_UFLAG_UNKNOWN_OP) { |
555 | free_data_area(udev, cmd->data_length); | 570 | free_data_area(udev, cmd); |
556 | pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", | 571 | pr_warn("TCMU: Userspace set UNKNOWN_OP flag on se_cmd %p\n", |
557 | cmd->se_cmd); | 572 | cmd->se_cmd); |
558 | entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; | 573 | entry->rsp.scsi_status = SAM_STAT_CHECK_CONDITION; |
559 | } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { | 574 | } else if (entry->rsp.scsi_status == SAM_STAT_CHECK_CONDITION) { |
560 | memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, | 575 | memcpy(se_cmd->sense_buffer, entry->rsp.sense_buffer, |
561 | se_cmd->scsi_sense_length); | 576 | se_cmd->scsi_sense_length); |
562 | free_data_area(udev, cmd->data_length); | 577 | free_data_area(udev, cmd); |
563 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { | 578 | } else if (se_cmd->se_cmd_flags & SCF_BIDI) { |
564 | /* Discard data_out buffer */ | 579 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); |
565 | free_data_area(udev, (size_t)se_cmd->t_data_sg->length); | ||
566 | 580 | ||
567 | /* Get Data-In buffer */ | 581 | /* Get Data-In buffer before clean up */ |
568 | gather_and_free_data_area(udev, | 582 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); |
583 | gather_data_area(udev, bitmap, | ||
569 | se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); | 584 | se_cmd->t_bidi_data_sg, se_cmd->t_bidi_data_nents); |
585 | free_data_area(udev, cmd); | ||
570 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { | 586 | } else if (se_cmd->data_direction == DMA_FROM_DEVICE) { |
571 | gather_and_free_data_area(udev, | 587 | DECLARE_BITMAP(bitmap, DATA_BLOCK_BITS); |
588 | |||
589 | bitmap_copy(bitmap, cmd->data_bitmap, DATA_BLOCK_BITS); | ||
590 | gather_data_area(udev, bitmap, | ||
572 | se_cmd->t_data_sg, se_cmd->t_data_nents); | 591 | se_cmd->t_data_sg, se_cmd->t_data_nents); |
592 | free_data_area(udev, cmd); | ||
573 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { | 593 | } else if (se_cmd->data_direction == DMA_TO_DEVICE) { |
574 | free_data_area(udev, cmd->data_length); | 594 | free_data_area(udev, cmd); |
575 | } else if (se_cmd->data_direction != DMA_NONE) { | 595 | } else if (se_cmd->data_direction != DMA_NONE) { |
576 | pr_warn("TCMU: data direction was %d!\n", | 596 | pr_warn("TCMU: data direction was %d!\n", |
577 | se_cmd->data_direction); | 597 | se_cmd->data_direction); |
@@ -912,6 +932,7 @@ static int tcmu_configure_device(struct se_device *dev) | |||
912 | 932 | ||
913 | WARN_ON(!PAGE_ALIGNED(udev->data_off)); | 933 | WARN_ON(!PAGE_ALIGNED(udev->data_off)); |
914 | WARN_ON(udev->data_size % PAGE_SIZE); | 934 | WARN_ON(udev->data_size % PAGE_SIZE); |
935 | WARN_ON(udev->data_size % DATA_BLOCK_SIZE); | ||
915 | 936 | ||
916 | info->version = __stringify(TCMU_MAILBOX_VERSION); | 937 | info->version = __stringify(TCMU_MAILBOX_VERSION); |
917 | 938 | ||