NVMe: Add nvme-scsi.c
Translates SCSI commands in SG_IO ioctl to NVMe commands. Uses the scsi-nvme translation spec from nvmexpress.org as reference. Signed-off-by: Vishal Verma <vishal.l.verma@intel.com> Signed-off-by: Matthew Wilcox <matthew.r.wilcox@intel.com>
This commit is contained in:
parent
f8ebf8409a
commit
5d0f6131a7
@ -42,5 +42,5 @@ obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX) += mtip32xx/
|
|||||||
|
|
||||||
obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/
|
obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/
|
||||||
|
|
||||||
nvme-y := nvme-core.o
|
nvme-y := nvme-core.o nvme-scsi.o
|
||||||
swim_mod-y := swim.o swim_asm.o
|
swim_mod-y := swim.o swim_asm.o
|
||||||
|
@ -39,7 +39,7 @@
|
|||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
#include <scsi/sg.h>
|
||||||
#include <asm-generic/io-64-nonatomic-lo-hi.h>
|
#include <asm-generic/io-64-nonatomic-lo-hi.h>
|
||||||
|
|
||||||
#define NVME_Q_DEPTH 1024
|
#define NVME_Q_DEPTH 1024
|
||||||
@ -224,12 +224,12 @@ static void *cancel_cmdid(struct nvme_queue *nvmeq, int cmdid,
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nvme_queue *get_nvmeq(struct nvme_dev *dev)
|
struct nvme_queue *get_nvmeq(struct nvme_dev *dev)
|
||||||
{
|
{
|
||||||
return dev->queues[get_cpu() + 1];
|
return dev->queues[get_cpu() + 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
static void put_nvmeq(struct nvme_queue *nvmeq)
|
void put_nvmeq(struct nvme_queue *nvmeq)
|
||||||
{
|
{
|
||||||
put_cpu();
|
put_cpu();
|
||||||
}
|
}
|
||||||
@ -290,7 +290,7 @@ nvme_alloc_iod(unsigned nseg, unsigned nbytes, gfp_t gfp)
|
|||||||
return iod;
|
return iod;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
|
void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
|
||||||
{
|
{
|
||||||
const int last_prp = PAGE_SIZE / 8 - 1;
|
const int last_prp = PAGE_SIZE / 8 - 1;
|
||||||
int i;
|
int i;
|
||||||
@ -339,9 +339,8 @@ static void bio_completion(struct nvme_dev *dev, void *ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* length is in bytes. gfp flags indicates whether we may sleep. */
|
/* length is in bytes. gfp flags indicates whether we may sleep. */
|
||||||
static int nvme_setup_prps(struct nvme_dev *dev,
|
int nvme_setup_prps(struct nvme_dev *dev, struct nvme_common_command *cmd,
|
||||||
struct nvme_common_command *cmd, struct nvme_iod *iod,
|
struct nvme_iod *iod, int total_len, gfp_t gfp)
|
||||||
int total_len, gfp_t gfp)
|
|
||||||
{
|
{
|
||||||
struct dma_pool *pool;
|
struct dma_pool *pool;
|
||||||
int length = total_len;
|
int length = total_len;
|
||||||
@ -512,7 +511,7 @@ static int nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns)
|
int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns)
|
||||||
{
|
{
|
||||||
int cmdid = alloc_cmdid(nvmeq, (void *)CMD_CTX_FLUSH,
|
int cmdid = alloc_cmdid(nvmeq, (void *)CMD_CTX_FLUSH,
|
||||||
special_completion, NVME_IO_TIMEOUT);
|
special_completion, NVME_IO_TIMEOUT);
|
||||||
@ -715,8 +714,8 @@ static void sync_completion(struct nvme_dev *dev, void *ctx,
|
|||||||
* Returns 0 on success. If the result is negative, it's a Linux error code;
|
* Returns 0 on success. If the result is negative, it's a Linux error code;
|
||||||
* if the result is positive, it's an NVM Express status code
|
* if the result is positive, it's an NVM Express status code
|
||||||
*/
|
*/
|
||||||
static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq,
|
int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd,
|
||||||
struct nvme_command *cmd, u32 *result, unsigned timeout)
|
u32 *result, unsigned timeout)
|
||||||
{
|
{
|
||||||
int cmdid;
|
int cmdid;
|
||||||
struct sync_cmd_info cmdinfo;
|
struct sync_cmd_info cmdinfo;
|
||||||
@ -745,7 +744,7 @@ static int nvme_submit_sync_cmd(struct nvme_queue *nvmeq,
|
|||||||
return cmdinfo.status;
|
return cmdinfo.status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd,
|
int nvme_submit_admin_cmd(struct nvme_dev *dev, struct nvme_command *cmd,
|
||||||
u32 *result)
|
u32 *result)
|
||||||
{
|
{
|
||||||
return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT);
|
return nvme_submit_sync_cmd(dev->queues[0], cmd, result, ADMIN_TIMEOUT);
|
||||||
@ -818,7 +817,7 @@ static int adapter_delete_sq(struct nvme_dev *dev, u16 sqid)
|
|||||||
return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid);
|
return adapter_delete_queue(dev, nvme_admin_delete_sq, sqid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
|
int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
|
||||||
dma_addr_t dma_addr)
|
dma_addr_t dma_addr)
|
||||||
{
|
{
|
||||||
struct nvme_command c;
|
struct nvme_command c;
|
||||||
@ -832,7 +831,7 @@ static int nvme_identify(struct nvme_dev *dev, unsigned nsid, unsigned cns,
|
|||||||
return nvme_submit_admin_cmd(dev, &c, NULL);
|
return nvme_submit_admin_cmd(dev, &c, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
|
int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
|
||||||
dma_addr_t dma_addr, u32 *result)
|
dma_addr_t dma_addr, u32 *result)
|
||||||
{
|
{
|
||||||
struct nvme_command c;
|
struct nvme_command c;
|
||||||
@ -846,8 +845,8 @@ static int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
|
|||||||
return nvme_submit_admin_cmd(dev, &c, result);
|
return nvme_submit_admin_cmd(dev, &c, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nvme_set_features(struct nvme_dev *dev, unsigned fid,
|
int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
|
||||||
unsigned dword11, dma_addr_t dma_addr, u32 *result)
|
dma_addr_t dma_addr, u32 *result)
|
||||||
{
|
{
|
||||||
struct nvme_command c;
|
struct nvme_command c;
|
||||||
|
|
||||||
@ -1065,7 +1064,7 @@ static int nvme_configure_admin_queue(struct nvme_dev *dev)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
|
struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
|
||||||
unsigned long addr, unsigned length)
|
unsigned long addr, unsigned length)
|
||||||
{
|
{
|
||||||
int i, err, count, nents, offset;
|
int i, err, count, nents, offset;
|
||||||
@ -1121,7 +1120,7 @@ static struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
|
|||||||
return ERR_PTR(err);
|
return ERR_PTR(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
|
void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
|
||||||
struct nvme_iod *iod)
|
struct nvme_iod *iod)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1257,6 +1256,10 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode, unsigned int cmd,
|
|||||||
return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
|
return nvme_user_admin_cmd(ns->dev, (void __user *)arg);
|
||||||
case NVME_IOCTL_SUBMIT_IO:
|
case NVME_IOCTL_SUBMIT_IO:
|
||||||
return nvme_submit_io(ns, (void __user *)arg);
|
return nvme_submit_io(ns, (void __user *)arg);
|
||||||
|
case SG_GET_VERSION_NUM:
|
||||||
|
return nvme_sg_get_version_num((void __user *)arg);
|
||||||
|
case SG_IO:
|
||||||
|
return nvme_sg_io(ns, (void __user *)arg);
|
||||||
default:
|
default:
|
||||||
return -ENOTTY;
|
return -ENOTTY;
|
||||||
}
|
}
|
||||||
|
2941
drivers/block/nvme-scsi.c
Normal file
2941
drivers/block/nvme-scsi.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -546,6 +546,8 @@ struct nvme_ns {
|
|||||||
|
|
||||||
int ns_id;
|
int ns_id;
|
||||||
int lba_shift;
|
int lba_shift;
|
||||||
|
u64 mode_select_num_blocks;
|
||||||
|
u32 mode_select_block_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -563,6 +565,39 @@ struct nvme_iod {
|
|||||||
dma_addr_t first_dma;
|
dma_addr_t first_dma;
|
||||||
struct scatterlist sg[0];
|
struct scatterlist sg[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nvme_free_iod - frees an nvme_iod
|
||||||
|
* @dev: The device that the I/O was submitted to
|
||||||
|
* @iod: The memory to free
|
||||||
|
*/
|
||||||
|
void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod);
|
||||||
|
|
||||||
|
int nvme_setup_prps(struct nvme_dev *dev, struct nvme_common_command *cmd,
|
||||||
|
struct nvme_iod *iod, int total_len, gfp_t gfp);
|
||||||
|
struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
|
||||||
|
unsigned long addr, unsigned length);
|
||||||
|
void nvme_unmap_user_pages(struct nvme_dev *dev, int write,
|
||||||
|
struct nvme_iod *iod);
|
||||||
|
struct nvme_queue *get_nvmeq(struct nvme_dev *dev);
|
||||||
|
void put_nvmeq(struct nvme_queue *nvmeq);
|
||||||
|
int nvme_submit_sync_cmd(struct nvme_queue *nvmeq, struct nvme_command *cmd,
|
||||||
|
u32 *result, unsigned timeout);
|
||||||
|
int nvme_submit_flush_data(struct nvme_queue *nvmeq, struct nvme_ns *ns);
|
||||||
|
int nvme_submit_admin_cmd(struct nvme_dev *, struct nvme_command *,
|
||||||
|
u32 *result);
|
||||||
|
int nvme_identify(struct nvme_dev *, unsigned nsid, unsigned cns,
|
||||||
|
dma_addr_t dma_addr);
|
||||||
|
int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned nsid,
|
||||||
|
dma_addr_t dma_addr, u32 *result);
|
||||||
|
int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned dword11,
|
||||||
|
dma_addr_t dma_addr, u32 *result);
|
||||||
|
|
||||||
|
struct sg_io_hdr;
|
||||||
|
|
||||||
|
int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
|
||||||
|
int nvme_sg_get_version_num(int __user *ip);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* _LINUX_NVME_H */
|
#endif /* _LINUX_NVME_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user