diff options
| -rw-r--r-- | drivers/target/target_core_file.c | 119 | ||||
| -rw-r--r-- | drivers/target/target_core_file.h | 5 |
2 files changed, 123 insertions, 1 deletions
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 119d51909762..aaba7c588c4d 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
| @@ -257,6 +257,72 @@ static void fd_free_device(struct se_device *dev) | |||
| 257 | kfree(fd_dev); | 257 | kfree(fd_dev); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot, | ||
| 261 | int is_write) | ||
| 262 | { | ||
| 263 | struct se_device *se_dev = cmd->se_dev; | ||
| 264 | struct fd_dev *dev = FD_DEV(se_dev); | ||
| 265 | struct file *prot_fd = dev->fd_prot_file; | ||
| 266 | struct scatterlist *sg; | ||
| 267 | loff_t pos = (cmd->t_task_lba * se_dev->prot_length); | ||
| 268 | unsigned char *buf; | ||
| 269 | u32 prot_size, len, size; | ||
| 270 | int rc, ret = 1, i; | ||
| 271 | |||
| 272 | prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) * | ||
| 273 | se_dev->prot_length; | ||
| 274 | |||
| 275 | if (!is_write) { | ||
| 276 | fd_prot->prot_buf = vzalloc(prot_size); | ||
| 277 | if (!fd_prot->prot_buf) { | ||
| 278 | pr_err("Unable to allocate fd_prot->prot_buf\n"); | ||
| 279 | return -ENOMEM; | ||
| 280 | } | ||
| 281 | buf = fd_prot->prot_buf; | ||
| 282 | |||
| 283 | fd_prot->prot_sg_nents = cmd->t_prot_nents; | ||
| 284 | fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) * | ||
| 285 | fd_prot->prot_sg_nents, GFP_KERNEL); | ||
| 286 | if (!fd_prot->prot_sg) { | ||
| 287 | pr_err("Unable to allocate fd_prot->prot_sg\n"); | ||
| 288 | vfree(fd_prot->prot_buf); | ||
| 289 | return -ENOMEM; | ||
| 290 | } | ||
| 291 | size = prot_size; | ||
| 292 | |||
| 293 | for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) { | ||
| 294 | |||
| 295 | len = min_t(u32, PAGE_SIZE, size); | ||
| 296 | sg_set_buf(sg, buf, len); | ||
| 297 | size -= len; | ||
| 298 | buf += len; | ||
| 299 | } | ||
| 300 | } | ||
| 301 | |||
| 302 | if (is_write) { | ||
| 303 | rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos); | ||
| 304 | if (rc < 0 || prot_size != rc) { | ||
| 305 | pr_err("kernel_write() for fd_do_prot_rw failed:" | ||
| 306 | " %d\n", rc); | ||
| 307 | ret = -EINVAL; | ||
| 308 | } | ||
| 309 | } else { | ||
| 310 | rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size); | ||
| 311 | if (rc < 0) { | ||
| 312 | pr_err("kernel_read() for fd_do_prot_rw failed:" | ||
| 313 | " %d\n", rc); | ||
| 314 | ret = -EINVAL; | ||
| 315 | } | ||
| 316 | } | ||
| 317 | |||
| 318 | if (is_write || ret < 0) { | ||
| 319 | kfree(fd_prot->prot_sg); | ||
| 320 | vfree(fd_prot->prot_buf); | ||
| 321 | } | ||
| 322 | |||
| 323 | return ret; | ||
| 324 | } | ||
| 325 | |||
| 260 | static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, | 326 | static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl, |
| 261 | u32 sgl_nents, int is_write) | 327 | u32 sgl_nents, int is_write) |
| 262 | { | 328 | { |
| @@ -551,6 +617,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 551 | enum dma_data_direction data_direction) | 617 | enum dma_data_direction data_direction) |
| 552 | { | 618 | { |
| 553 | struct se_device *dev = cmd->se_dev; | 619 | struct se_device *dev = cmd->se_dev; |
| 620 | struct fd_prot fd_prot; | ||
| 621 | sense_reason_t rc; | ||
| 554 | int ret = 0; | 622 | int ret = 0; |
| 555 | 623 | ||
| 556 | /* | 624 | /* |
| @@ -558,8 +626,48 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 558 | * physical memory addresses to struct iovec virtual memory. | 626 | * physical memory addresses to struct iovec virtual memory. |
| 559 | */ | 627 | */ |
| 560 | if (data_direction == DMA_FROM_DEVICE) { | 628 | if (data_direction == DMA_FROM_DEVICE) { |
| 629 | memset(&fd_prot, 0, sizeof(struct fd_prot)); | ||
| 630 | |||
| 631 | if (cmd->prot_type) { | ||
| 632 | ret = fd_do_prot_rw(cmd, &fd_prot, false); | ||
| 633 | if (ret < 0) | ||
| 634 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
| 635 | } | ||
| 636 | |||
| 561 | ret = fd_do_rw(cmd, sgl, sgl_nents, 0); | 637 | ret = fd_do_rw(cmd, sgl, sgl_nents, 0); |
| 638 | |||
| 639 | if (ret > 0 && cmd->prot_type) { | ||
| 640 | u32 sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
| 641 | |||
| 642 | rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, | ||
| 643 | 0, fd_prot.prot_sg, 0); | ||
| 644 | if (rc) { | ||
| 645 | kfree(fd_prot.prot_sg); | ||
| 646 | vfree(fd_prot.prot_buf); | ||
| 647 | return rc; | ||
| 648 | } | ||
| 649 | kfree(fd_prot.prot_sg); | ||
| 650 | vfree(fd_prot.prot_buf); | ||
| 651 | } | ||
| 562 | } else { | 652 | } else { |
| 653 | memset(&fd_prot, 0, sizeof(struct fd_prot)); | ||
| 654 | |||
| 655 | if (cmd->prot_type) { | ||
| 656 | u32 sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
| 657 | |||
| 658 | ret = fd_do_prot_rw(cmd, &fd_prot, false); | ||
| 659 | if (ret < 0) | ||
| 660 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
| 661 | |||
| 662 | rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, | ||
| 663 | 0, fd_prot.prot_sg, 0); | ||
| 664 | if (rc) { | ||
| 665 | kfree(fd_prot.prot_sg); | ||
| 666 | vfree(fd_prot.prot_buf); | ||
| 667 | return rc; | ||
| 668 | } | ||
| 669 | } | ||
| 670 | |||
| 563 | ret = fd_do_rw(cmd, sgl, sgl_nents, 1); | 671 | ret = fd_do_rw(cmd, sgl, sgl_nents, 1); |
| 564 | /* | 672 | /* |
| 565 | * Perform implicit vfs_fsync_range() for fd_do_writev() ops | 673 | * Perform implicit vfs_fsync_range() for fd_do_writev() ops |
| @@ -576,10 +684,19 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, | |||
| 576 | 684 | ||
| 577 | vfs_fsync_range(fd_dev->fd_file, start, end, 1); | 685 | vfs_fsync_range(fd_dev->fd_file, start, end, 1); |
| 578 | } | 686 | } |
| 687 | |||
| 688 | if (ret > 0 && cmd->prot_type) { | ||
| 689 | ret = fd_do_prot_rw(cmd, &fd_prot, true); | ||
| 690 | if (ret < 0) | ||
| 691 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
| 692 | } | ||
| 579 | } | 693 | } |
| 580 | 694 | ||
| 581 | if (ret < 0) | 695 | if (ret < 0) { |
| 696 | kfree(fd_prot.prot_sg); | ||
| 697 | vfree(fd_prot.prot_buf); | ||
| 582 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 698 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
| 699 | } | ||
| 583 | 700 | ||
| 584 | if (ret) | 701 | if (ret) |
| 585 | target_complete_cmd(cmd, SAM_STAT_GOOD); | 702 | target_complete_cmd(cmd, SAM_STAT_GOOD); |
diff --git a/drivers/target/target_core_file.h b/drivers/target/target_core_file.h index 583691ebcbe0..97e5e7dd4259 100644 --- a/drivers/target/target_core_file.h +++ b/drivers/target/target_core_file.h | |||
| @@ -18,6 +18,11 @@ | |||
| 18 | #define FDBD_HAS_BUFFERED_IO_WCE 0x04 | 18 | #define FDBD_HAS_BUFFERED_IO_WCE 0x04 |
| 19 | #define FDBD_FORMAT_UNIT_SIZE 2048 | 19 | #define FDBD_FORMAT_UNIT_SIZE 2048 |
| 20 | 20 | ||
| 21 | struct fd_prot { | ||
| 22 | unsigned char *prot_buf; | ||
| 23 | struct scatterlist *prot_sg; | ||
| 24 | u32 prot_sg_nents; | ||
| 25 | }; | ||
| 21 | 26 | ||
| 22 | struct fd_dev { | 27 | struct fd_dev { |
| 23 | struct se_device dev; | 28 | struct se_device dev; |
