aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/target/target_core_sbc.c
diff options
context:
space:
mode:
authorAsias He <asias@redhat.com>2013-02-25 01:03:46 -0500
committerNicholas Bellinger <nab@linux-iscsi.org>2013-04-25 04:05:24 -0400
commit86d7182985d25900929adce14fffd729cc8c6fb8 (patch)
tree8e5e755c5badf3a09b5b0c4e6c2f76c72c080dcf /drivers/target/target_core_sbc.c
parentdbc21c5abbeb4419da5a54157c4b7a0ec0dee185 (diff)
target: Add sbc_execute_unmap() helper
iblock_execute_unmap() and fd_execute_unmap share a lot of code. Add sbc_execute_unmap() helper to remove duplicated code for iblock_execute_unmap() and fd_execute_unmap(). Cc: Christoph Hellwig <hch@lst.de> Cc: Martin K. Petersen <martin.petersen@oracle.com> Cc: Nicholas Bellinger <nab@linux-iscsi.org> Signed-off-by: Asias He <asias@redhat.com> Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers/target/target_core_sbc.c')
-rw-r--r--drivers/target/target_core_sbc.c85
1 files changed, 85 insertions, 0 deletions
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index 60d4b5185f32..bbc5b0ee2bdc 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -596,3 +596,88 @@ u32 sbc_get_device_type(struct se_device *dev)
596 return TYPE_DISK; 596 return TYPE_DISK;
597} 597}
598EXPORT_SYMBOL(sbc_get_device_type); 598EXPORT_SYMBOL(sbc_get_device_type);
599
600sense_reason_t
601sbc_execute_unmap(struct se_cmd *cmd,
602 sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *,
603 sector_t, sector_t),
604 void *priv)
605{
606 struct se_device *dev = cmd->se_dev;
607 unsigned char *buf, *ptr = NULL;
608 sector_t lba;
609 int size;
610 u32 range;
611 sense_reason_t ret = 0;
612 int dl, bd_dl;
613
614 /* We never set ANC_SUP */
615 if (cmd->t_task_cdb[1])
616 return TCM_INVALID_CDB_FIELD;
617
618 if (cmd->data_length == 0) {
619 target_complete_cmd(cmd, SAM_STAT_GOOD);
620 return 0;
621 }
622
623 if (cmd->data_length < 8) {
624 pr_warn("UNMAP parameter list length %u too small\n",
625 cmd->data_length);
626 return TCM_PARAMETER_LIST_LENGTH_ERROR;
627 }
628
629 buf = transport_kmap_data_sg(cmd);
630 if (!buf)
631 return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
632
633 dl = get_unaligned_be16(&buf[0]);
634 bd_dl = get_unaligned_be16(&buf[2]);
635
636 size = cmd->data_length - 8;
637 if (bd_dl > size)
638 pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n",
639 cmd->data_length, bd_dl);
640 else
641 size = bd_dl;
642
643 if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) {
644 ret = TCM_INVALID_PARAMETER_LIST;
645 goto err;
646 }
647
648 /* First UNMAP block descriptor starts at 8 byte offset */
649 ptr = &buf[8];
650 pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u"
651 " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr);
652
653 while (size >= 16) {
654 lba = get_unaligned_be64(&ptr[0]);
655 range = get_unaligned_be32(&ptr[8]);
656 pr_debug("UNMAP: Using lba: %llu and range: %u\n",
657 (unsigned long long)lba, range);
658
659 if (range > dev->dev_attrib.max_unmap_lba_count) {
660 ret = TCM_INVALID_PARAMETER_LIST;
661 goto err;
662 }
663
664 if (lba + range > dev->transport->get_blocks(dev) + 1) {
665 ret = TCM_ADDRESS_OUT_OF_RANGE;
666 goto err;
667 }
668
669 ret = do_unmap_fn(cmd, priv, lba, range);
670 if (ret)
671 goto err;
672
673 ptr += 16;
674 size -= 16;
675 }
676
677err:
678 transport_kunmap_data_sg(cmd);
679 if (!ret)
680 target_complete_cmd(cmd, GOOD);
681 return ret;
682}
683EXPORT_SYMBOL(sbc_execute_unmap);