[PATCH 03/18] nvme: split command submission helpers out of pci.c

J Freyensee james_p_freyensee at linux.intel.com
Wed Oct 21 11:48:54 PDT 2015


On Fri, 2015-10-16 at 07:58 +0200, Christoph Hellwig wrote:
> Create a new core.c and start by adding the command submission 
> helpers
> to it, which are already abstracted away from the actual hardware 
> queues
> by the block layer.
> 
> Signed-off-by: Christoph Hellwig <hch at lst.de>
> Acked-by: Keith Busch <keith.busch at intel.com>
> ---
>  drivers/nvme/host/Makefile |   2 +-
>  drivers/nvme/host/core.c   | 172 
> +++++++++++++++++++++++++++++++++++++++++++++
>  drivers/nvme/host/nvme.h   |   3 +
>  drivers/nvme/host/pci.c    | 153 +----------------------------------
> -----
>  4 files changed, 177 insertions(+), 153 deletions(-)
>  create mode 100644 drivers/nvme/host/core.c
> 
> diff --git a/drivers/nvme/host/Makefile b/drivers/nvme/host/Makefile
> index cfb6679..336b4ea 100644
> --- a/drivers/nvme/host/Makefile
> +++ b/drivers/nvme/host/Makefile
> @@ -1,4 +1,4 @@
>  
>  obj-$(CONFIG_BLK_DEV_NVME)     += nvme.o
>  
> -nvme-y		+= pci.o scsi.o
> +nvme-y		+= core.o pci.o scsi.o
> diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c
> new file mode 100644
> index 0000000..dfb528d
> --- /dev/null
> +++ b/drivers/nvme/host/core.c
> @@ -0,0 +1,172 @@
> +/*
> + * NVM Express device driver
> + * Copyright (c) 2011-2014, Intel Corporation.
> + *
> + * This program is free software; you can redistribute it and/or 
> modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but 
> WITHOUT
> + * ANY WARRANTY; without even the implied warranty of 
> MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public 
> License for
> + * more details.
> + */
> +
> +#include <linux/blkdev.h>
> +#include <linux/blk-mq.h>
> +#include <linux/errno.h>
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/types.h>
> +
> +#include "nvme.h"
> +
> +/*
> + * 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
> + */
> +int __nvme_submit_sync_cmd(struct request_queue *q, struct 
> nvme_command *cmd,
> +		void *buffer, void __user *ubuffer, unsigned 
> bufflen,
> +		u32 *result, unsigned timeout)
> +{
> +	bool write = cmd->common.opcode & 1;
> +	struct bio *bio = NULL;
> +	struct request *req;
> +	int ret;
> +
> +	req = blk_mq_alloc_request(q, write, GFP_KERNEL, false);
> +	if (IS_ERR(req))
> +		return PTR_ERR(req);
> +
> +	req->cmd_type = REQ_TYPE_DRV_PRIV;
> +	req->cmd_flags |= REQ_FAILFAST_DRIVER;
> +	req->__data_len = 0;
> +	req->__sector = (sector_t) -1;
> +	req->bio = req->biotail = NULL;
> +
> +	req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
> +
> +	req->cmd = (unsigned char *)cmd;
> +	req->cmd_len = sizeof(struct nvme_command);
> +	req->special = (void *)0;
> +
> +	if (buffer && bufflen) {
> +		ret = blk_rq_map_kern(q, req, buffer, bufflen, 
> __GFP_WAIT);
> +		if (ret)
> +			goto out;
> +	} else if (ubuffer && bufflen) {
> +		ret = blk_rq_map_user(q, req, NULL, ubuffer, 
> bufflen, __GFP_WAIT);
> +		if (ret)
> +			goto out;
> +		bio = req->bio;
> +	}
> +
> +	blk_execute_rq(req->q, NULL, req, 0);
> +	if (bio)
> +		blk_rq_unmap_user(bio);
> +	if (result)
> +		*result = (u32)(uintptr_t)req->special;
> +	ret = req->errors;
> + out:
> +	blk_mq_free_request(req);
> +	return ret;
> +}
> +
> +int nvme_submit_sync_cmd(struct request_queue *q, struct 
> nvme_command *cmd,
> +		void *buffer, unsigned bufflen)
> +{
> +	return __nvme_submit_sync_cmd(q, cmd, buffer, NULL, bufflen, 
> NULL, 0);
> +}
> +
> +int nvme_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl 
> **id)
> +{
> +	struct nvme_command c = { };
> +	int error;
> +
> +	/* gcc-4.4.4 (at least) has issues with initializers and 
> anon unions */
> +	c.identify.opcode = nvme_admin_identify;
> +	c.identify.cns = cpu_to_le32(1);
> +
> +	*id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
> +	if (!*id)
> +		return -ENOMEM;
> +
> +	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
> +			sizeof(struct nvme_id_ctrl));
> +	if (error)
> +		kfree(*id);
> +	return error;
> +}
> +
> +int nvme_identify_ns(struct nvme_dev *dev, unsigned nsid,
> +		struct nvme_id_ns **id)
> +{
> +	struct nvme_command c = { };
> +	int error;
> +
> +	/* gcc-4.4.4 (at least) has issues with initializers and 
> anon unions */
> +	c.identify.opcode = nvme_admin_identify,
> +	c.identify.nsid = cpu_to_le32(nsid),
> +
> +	*id = kmalloc(sizeof(struct nvme_id_ns), GFP_KERNEL);
> +	if (!*id)
> +		return -ENOMEM;
> +
> +	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
> +			sizeof(struct nvme_id_ns));
> +	if (error)
> +		kfree(*id);
> +	return error;
> +}
> +
> +int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned 
> nsid,
> +					dma_addr_t dma_addr, u32 
> *result)
> +{
> +	struct nvme_command c;
> +
> +	memset(&c, 0, sizeof(c));
> +	c.features.opcode = nvme_admin_get_features;
> +	c.features.nsid = cpu_to_le32(nsid);
> +	c.features.prp1 = cpu_to_le64(dma_addr);
> +	c.features.fid = cpu_to_le32(fid);
> +
> +	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 
> 0,
> +			result, 0);
> +}
> +
> +int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned 
> dword11,
> +					dma_addr_t dma_addr, u32 
> *result)
> +{
> +	struct nvme_command c;
> +
> +	memset(&c, 0, sizeof(c));
> +	c.features.opcode = nvme_admin_set_features;
> +	c.features.prp1 = cpu_to_le64(dma_addr);
> +	c.features.fid = cpu_to_le32(fid);
> +	c.features.dword11 = cpu_to_le32(dword11);
> +
> +	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 
> 0,
> +			result, 0);
> +}
> +
> +int nvme_get_log_page(struct nvme_dev *dev, struct nvme_smart_log 
> **log)
> +{
> +	struct nvme_command c = { };
> +	int error;
> +
> +	c.common.opcode = nvme_admin_get_log_page,
> +	c.common.nsid = cpu_to_le32(0xFFFFFFFF),
> +	c.common.cdw10[0] = cpu_to_le32(
> +			(((sizeof(struct nvme_smart_log) / 4) - 1) 
> << 16) |
> +			 NVME_LOG_SMART),
> +
> +	*log = kmalloc(sizeof(struct nvme_smart_log), GFP_KERNEL);
> +	if (!*log)
> +		return -ENOMEM;
> +
> +	error = nvme_submit_sync_cmd(dev->admin_q, &c, *log,
> +			sizeof(struct nvme_smart_log));
> +	if (error)
> +		kfree(*log);
> +	return error;
> +}
> diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h
> index 835941b..0633a7b 100644
> --- a/drivers/nvme/host/nvme.h
> +++ b/drivers/nvme/host/nvme.h
> @@ -22,6 +22,9 @@
>  extern unsigned char nvme_io_timeout;
>  #define NVME_IO_TIMEOUT	(nvme_io_timeout * HZ)
>  
> +extern unsigned char admin_timeout;
> +#define ADMIN_TIMEOUT	(admin_timeout * HZ)
> +
>  /*
>   * Represents an NVM Express device.  Each nvme_dev is a PCI 
> function.
>   */
> diff --git a/drivers/nvme/host/pci.c b/drivers/nvme/host/pci.c
> index 7e1b438..628c572 100644
> --- a/drivers/nvme/host/pci.c
> +++ b/drivers/nvme/host/pci.c
> @@ -50,10 +50,9 @@
>  #define NVME_AQ_DEPTH		256
>  #define SQ_SIZE(depth)		(depth * sizeof(struct 
> nvme_command))
>  #define CQ_SIZE(depth)		(depth * sizeof(struct 
> nvme_completion))
> -#define ADMIN_TIMEOUT		(admin_timeout * HZ)
>  #define SHUTDOWN_TIMEOUT	(shutdown_timeout * HZ)

I think some or all of these #defines should be moved out of the .c
file and stuck into a .h file as well?  Why would any of the queue
depths or the shutdown timeout be PCIe specific?

>  
> -static unsigned char admin_timeout = 60;
> +unsigned char admin_timeout = 60;
>  module_param(admin_timeout, byte, 0644);
>  MODULE_PARM_DESC(admin_timeout, "timeout in seconds for admin 
> commands");
>  


> @@ -1031,63 +1030,6 @@ static irqreturn_t nvme_irq_check(int irq, 
> void *data)
>  	return IRQ_WAKE_THREAD;
>  }
>  
> -/*
> - * 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
> - */
> -int __nvme_submit_sync_cmd(struct request_queue *q, struct 
> nvme_command *cmd,
> -		void *buffer, void __user *ubuffer, unsigned 
> bufflen,
> -		u32 *result, unsigned timeout)
> -{
> -	bool write = cmd->common.opcode & 1;
> -	struct bio *bio = NULL;
> -	struct request *req;
> -	int ret;
> -
> -	req = blk_mq_alloc_request(q, write, GFP_KERNEL, false);
> -	if (IS_ERR(req))
> -		return PTR_ERR(req);
> -
> -	req->cmd_type = REQ_TYPE_DRV_PRIV;
> -	req->cmd_flags |= REQ_FAILFAST_DRIVER;
> -	req->__data_len = 0;
> -	req->__sector = (sector_t) -1;
> -	req->bio = req->biotail = NULL;
> -
> -	req->timeout = timeout ? timeout : ADMIN_TIMEOUT;
> -
> -	req->cmd = (unsigned char *)cmd;
> -	req->cmd_len = sizeof(struct nvme_command);
> -	req->special = (void *)0;
> -
> -	if (buffer && bufflen) {
> -		ret = blk_rq_map_kern(q, req, buffer, bufflen, 
> __GFP_WAIT);
> -		if (ret)
> -			goto out;
> -	} else if (ubuffer && bufflen) {
> -		ret = blk_rq_map_user(q, req, NULL, ubuffer, 
> bufflen, __GFP_WAIT);
> -		if (ret)
> -			goto out;
> -		bio = req->bio;
> -	}
> -
> -	blk_execute_rq(req->q, NULL, req, 0);
> -	if (bio)
> -		blk_rq_unmap_user(bio);
> -	if (result)
> -		*result = (u32)(uintptr_t)req->special;
> -	ret = req->errors;
> - out:
> -	blk_mq_free_request(req);
> -	return ret;
> -}
> -
> -int nvme_submit_sync_cmd(struct request_queue *q, struct 
> nvme_command *cmd,
> -		void *buffer, unsigned bufflen)
> -{
> -	return __nvme_submit_sync_cmd(q, cmd, buffer, NULL, bufflen, 
> NULL, 0);
> -}
> -
>  static int nvme_submit_async_admin_req(struct nvme_dev *dev)
>  {
>  	struct nvme_queue *nvmeq = dev->queues[0];
> @@ -1199,99 +1141,6 @@ static int adapter_delete_sq(struct nvme_dev 
> *dev, u16 sqid)
>  	return adapter_delete_queue(dev, nvme_admin_delete_sq, 
> sqid);
>  }
>  
> -int nvme_identify_ctrl(struct nvme_dev *dev, struct nvme_id_ctrl 
> **id)
> -{
> -	struct nvme_command c = { };
> -	int error;
> -
> -	/* gcc-4.4.4 (at least) has issues with initializers and 
> anon unions */
> -	c.identify.opcode = nvme_admin_identify;
> -	c.identify.cns = cpu_to_le32(1);
> -
> -	*id = kmalloc(sizeof(struct nvme_id_ctrl), GFP_KERNEL);
> -	if (!*id)
> -		return -ENOMEM;
> -
> -	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
> -			sizeof(struct nvme_id_ctrl));
> -	if (error)
> -		kfree(*id);
> -	return error;
> -}
> -
> -int nvme_identify_ns(struct nvme_dev *dev, unsigned nsid,
> -		struct nvme_id_ns **id)
> -{
> -	struct nvme_command c = { };
> -	int error;
> -
> -	/* gcc-4.4.4 (at least) has issues with initializers and 
> anon unions */
> -	c.identify.opcode = nvme_admin_identify,
> -	c.identify.nsid = cpu_to_le32(nsid),
> -
> -	*id = kmalloc(sizeof(struct nvme_id_ns), GFP_KERNEL);
> -	if (!*id)
> -		return -ENOMEM;
> -
> -	error = nvme_submit_sync_cmd(dev->admin_q, &c, *id,
> -			sizeof(struct nvme_id_ns));
> -	if (error)
> -		kfree(*id);
> -	return error;
> -}
> -
> -int nvme_get_features(struct nvme_dev *dev, unsigned fid, unsigned 
> nsid,
> -					dma_addr_t dma_addr, u32 
> *result)
> -{
> -	struct nvme_command c;
> -
> -	memset(&c, 0, sizeof(c));
> -	c.features.opcode = nvme_admin_get_features;
> -	c.features.nsid = cpu_to_le32(nsid);
> -	c.features.prp1 = cpu_to_le64(dma_addr);
> -	c.features.fid = cpu_to_le32(fid);
> -
> -	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 
> 0,
> -			result, 0);
> -}
> -
> -int nvme_set_features(struct nvme_dev *dev, unsigned fid, unsigned 
> dword11,
> -					dma_addr_t dma_addr, u32 
> *result)
> -{
> -	struct nvme_command c;
> -
> -	memset(&c, 0, sizeof(c));
> -	c.features.opcode = nvme_admin_set_features;
> -	c.features.prp1 = cpu_to_le64(dma_addr);
> -	c.features.fid = cpu_to_le32(fid);
> -	c.features.dword11 = cpu_to_le32(dword11);
> -
> -	return __nvme_submit_sync_cmd(dev->admin_q, &c, NULL, NULL, 
> 0,
> -			result, 0);
> -}
> -
> -int nvme_get_log_page(struct nvme_dev *dev, struct nvme_smart_log 
> **log)
> -{
> -	struct nvme_command c = { };
> -	int error;
> -
> -	c.common.opcode = nvme_admin_get_log_page,
> -	c.common.nsid = cpu_to_le32(0xFFFFFFFF),
> -	c.common.cdw10[0] = cpu_to_le32(
> -			(((sizeof(struct nvme_smart_log) / 4) - 1) 
> << 16) |
> -			 NVME_LOG_SMART),
> -
> -	*log = kmalloc(sizeof(struct nvme_smart_log), GFP_KERNEL);
> -	if (!*log)
> -		return -ENOMEM;
> -
> -	error = nvme_submit_sync_cmd(dev->admin_q, &c, *log,
> -			sizeof(struct nvme_smart_log));
> -	if (error)
> -		kfree(*log);
> -	return error;
> -}
> -
>  /**
>   * nvme_abort_req - Attempt aborting a request
>   *



More information about the Linux-nvme mailing list