diff options
author | Keith Busch <keith.busch@intel.com> | 2013-04-24 17:44:24 -0400 |
---|---|---|
committer | Matthew Wilcox <matthew.r.wilcox@intel.com> | 2013-05-02 14:32:08 -0400 |
commit | ec5037335064dcc52c2fbbf3d505bae0eb27e713 (patch) | |
tree | 6106acdb426250fb2e69e72efde4a86d78ffd1d8 /drivers/block/nvme-scsi.c | |
parent | 14385de117882fa253954063d8b8d8a6bdeae650 (diff) |
NVMe: Add scsi unmap to SG_IO
Translates a scsi unmap request from SG_IO ioctl to NVMe
data-set-management deallocate.
Signed-off-by: Keith Busch <keith.busch@intel.com>
Acked-by: Vishal Verma <vishal.l.verma@linux.intel.com>
Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
Diffstat (limited to 'drivers/block/nvme-scsi.c')
-rw-r--r-- | drivers/block/nvme-scsi.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c index fe2fcfff4c0f..1c0710ca55d6 100644 --- a/drivers/block/nvme-scsi.c +++ b/drivers/block/nvme-scsi.c | |||
@@ -100,6 +100,7 @@ static int sg_version_num = 30534; /* 2 digits for each component */ | |||
100 | #define FORMAT_UNIT_PROT_INT_OFFSET 3 | 100 | #define FORMAT_UNIT_PROT_INT_OFFSET 3 |
101 | #define FORMAT_UNIT_PROT_FIELD_USAGE_OFFSET 0 | 101 | #define FORMAT_UNIT_PROT_FIELD_USAGE_OFFSET 0 |
102 | #define FORMAT_UNIT_PROT_FIELD_USAGE_MASK 0x07 | 102 | #define FORMAT_UNIT_PROT_FIELD_USAGE_MASK 0x07 |
103 | #define UNMAP_CDB_PARAM_LIST_LENGTH_OFFSET 7 | ||
103 | 104 | ||
104 | /* Misc. defines */ | 105 | /* Misc. defines */ |
105 | #define NIBBLE_SHIFT 4 | 106 | #define NIBBLE_SHIFT 4 |
@@ -2862,6 +2863,80 @@ static int nvme_trans_write_buffer(struct nvme_ns *ns, struct sg_io_hdr *hdr, | |||
2862 | return res; | 2863 | return res; |
2863 | } | 2864 | } |
2864 | 2865 | ||
2866 | struct scsi_unmap_blk_desc { | ||
2867 | __be64 slba; | ||
2868 | __be32 nlb; | ||
2869 | u32 resv; | ||
2870 | }; | ||
2871 | |||
2872 | struct scsi_unmap_parm_list { | ||
2873 | __be16 unmap_data_len; | ||
2874 | __be16 unmap_blk_desc_data_len; | ||
2875 | u32 resv; | ||
2876 | struct scsi_unmap_blk_desc desc[0]; | ||
2877 | }; | ||
2878 | |||
2879 | static int nvme_trans_unmap(struct nvme_ns *ns, struct sg_io_hdr *hdr, | ||
2880 | u8 *cmd) | ||
2881 | { | ||
2882 | struct nvme_dev *dev = ns->dev; | ||
2883 | struct scsi_unmap_parm_list *plist; | ||
2884 | struct nvme_dsm_range *range; | ||
2885 | struct nvme_queue *nvmeq; | ||
2886 | struct nvme_command c; | ||
2887 | int i, nvme_sc, res = -ENOMEM; | ||
2888 | u16 ndesc, list_len; | ||
2889 | dma_addr_t dma_addr; | ||
2890 | |||
2891 | list_len = GET_U16_FROM_CDB(cmd, UNMAP_CDB_PARAM_LIST_LENGTH_OFFSET); | ||
2892 | if (!list_len) | ||
2893 | return -EINVAL; | ||
2894 | |||
2895 | plist = kmalloc(list_len, GFP_KERNEL); | ||
2896 | if (!plist) | ||
2897 | return -ENOMEM; | ||
2898 | |||
2899 | res = nvme_trans_copy_from_user(hdr, plist, list_len); | ||
2900 | if (res != SNTI_TRANSLATION_SUCCESS) | ||
2901 | goto out; | ||
2902 | |||
2903 | ndesc = be16_to_cpu(plist->unmap_blk_desc_data_len) >> 4; | ||
2904 | if (!ndesc || ndesc > 256) { | ||
2905 | res = -EINVAL; | ||
2906 | goto out; | ||
2907 | } | ||
2908 | |||
2909 | range = dma_alloc_coherent(&dev->pci_dev->dev, ndesc * sizeof(*range), | ||
2910 | &dma_addr, GFP_KERNEL); | ||
2911 | if (!range) | ||
2912 | goto out; | ||
2913 | |||
2914 | for (i = 0; i < ndesc; i++) { | ||
2915 | range[i].nlb = cpu_to_le32(be32_to_cpu(plist->desc[i].nlb)); | ||
2916 | range[i].slba = cpu_to_le64(be64_to_cpu(plist->desc[i].slba)); | ||
2917 | range[i].cattr = 0; | ||
2918 | } | ||
2919 | |||
2920 | memset(&c, 0, sizeof(c)); | ||
2921 | c.dsm.opcode = nvme_cmd_dsm; | ||
2922 | c.dsm.nsid = cpu_to_le32(ns->ns_id); | ||
2923 | c.dsm.prp1 = cpu_to_le64(dma_addr); | ||
2924 | c.dsm.nr = cpu_to_le32(ndesc - 1); | ||
2925 | c.dsm.attributes = cpu_to_le32(NVME_DSMGMT_AD); | ||
2926 | |||
2927 | nvmeq = get_nvmeq(dev); | ||
2928 | put_nvmeq(nvmeq); | ||
2929 | |||
2930 | nvme_sc = nvme_submit_sync_cmd(nvmeq, &c, NULL, NVME_IO_TIMEOUT); | ||
2931 | res = nvme_trans_status_code(hdr, nvme_sc); | ||
2932 | |||
2933 | dma_free_coherent(&dev->pci_dev->dev, ndesc * sizeof(*range), | ||
2934 | range, dma_addr); | ||
2935 | out: | ||
2936 | kfree(plist); | ||
2937 | return res; | ||
2938 | } | ||
2939 | |||
2865 | static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) | 2940 | static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) |
2866 | { | 2941 | { |
2867 | u8 cmd[BLK_MAX_CDB]; | 2942 | u8 cmd[BLK_MAX_CDB]; |
@@ -2936,6 +3011,9 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr) | |||
2936 | case WRITE_BUFFER: | 3011 | case WRITE_BUFFER: |
2937 | retcode = nvme_trans_write_buffer(ns, hdr, cmd); | 3012 | retcode = nvme_trans_write_buffer(ns, hdr, cmd); |
2938 | break; | 3013 | break; |
3014 | case UNMAP: | ||
3015 | retcode = nvme_trans_unmap(ns, hdr, cmd); | ||
3016 | break; | ||
2939 | default: | 3017 | default: |
2940 | out: | 3018 | out: |
2941 | retcode = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION, | 3019 | retcode = nvme_trans_completion(hdr, SAM_STAT_CHECK_CONDITION, |