mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'for-4.13/block' of git://git.kernel.dk/linux-block
Pull core block/IO updates from Jens Axboe:
"This is the main pull request for the block layer for 4.13. Not a huge
round in terms of features, but there's a lot of churn related to some
core cleanups.
Note this depends on the UUID tree pull request, that Christoph
already sent out.
This pull request contains:
- A series from Christoph, unifying the error/stats codes in the
block layer. We now use blk_status_t everywhere, instead of using
different schemes for different places.
- Also from Christoph, some cleanups around request allocation and IO
scheduler interactions in blk-mq.
- And yet another series from Christoph, cleaning up how we handle
and do bounce buffering in the block layer.
- A blk-mq debugfs series from Bart, further improving on the support
we have for exporting internal information to aid debugging IO
hangs or stalls.
- Also from Bart, a series that cleans up the request initialization
differences across types of devices.
- A series from Goldwyn Rodrigues, allowing the block layer to return
failure if we will block and the user asked for non-blocking.
- Patch from Hannes for supporting setting loop devices block size to
that of the underlying device.
- Two series of patches from Javier, fixing various issues with
lightnvm, particular around pblk.
- A series from me, adding support for write hints. This comes with
NVMe support as well, so applications can help guide data placement
on flash to improve performance, latencies, and write
amplification.
- A series from Ming, improving and hardening blk-mq support for
stopping/starting and quiescing hardware queues.
- Two pull requests for NVMe updates. Nothing major on the feature
side, but lots of cleanups and bug fixes. From the usual crew.
- A series from Neil Brown, greatly improving the bio rescue set
support. Most notably, this kills the bio rescue work queues, if we
don't really need them.
- Lots of other little bug fixes that are all over the place"
* 'for-4.13/block' of git://git.kernel.dk/linux-block: (217 commits)
lightnvm: pblk: set line bitmap check under debug
lightnvm: pblk: verify that cache read is still valid
lightnvm: pblk: add initialization check
lightnvm: pblk: remove target using async. I/Os
lightnvm: pblk: use vmalloc for GC data buffer
lightnvm: pblk: use right metadata buffer for recovery
lightnvm: pblk: schedule if data is not ready
lightnvm: pblk: remove unused return variable
lightnvm: pblk: fix double-free on pblk init
lightnvm: pblk: fix bad le64 assignations
nvme: Makefile: remove dead build rule
blk-mq: map all HWQ also in hyperthreaded system
nvmet-rdma: register ib_client to not deadlock in device removal
nvme_fc: fix error recovery on link down.
nvmet_fc: fix crashes on bad opcodes
nvme_fc: Fix crash when nvme controller connection fails.
nvme_fc: replace ioabort msleep loop with completion
nvme_fc: fix double calls to nvme_cleanup_cmd()
nvme-fabrics: verify that a controller returns the correct NQN
nvme: simplify nvme_dev_attrs_are_visible
...
This commit is contained in:
commit
c6b1e36c8f
265 changed files with 5912 additions and 6237 deletions
|
|
@ -13,18 +13,6 @@ config BLK_DEV_NVME
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called nvme.
|
||||
|
||||
config BLK_DEV_NVME_SCSI
|
||||
bool "SCSI emulation for NVMe device nodes"
|
||||
depends on NVME_CORE
|
||||
---help---
|
||||
This adds support for the SG_IO ioctl on the NVMe character
|
||||
and block devices nodes, as well as a translation for a small
|
||||
number of selected SCSI commands to NVMe commands to the NVMe
|
||||
driver. If you don't know what this means you probably want
|
||||
to say N here, unless you run a distro that abuses the SCSI
|
||||
emulation to provide stable device names for mount by id, like
|
||||
some OpenSuSE and SLES versions.
|
||||
|
||||
config NVME_FABRICS
|
||||
tristate
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ obj-$(CONFIG_NVME_RDMA) += nvme-rdma.o
|
|||
obj-$(CONFIG_NVME_FC) += nvme-fc.o
|
||||
|
||||
nvme-core-y := core.o
|
||||
nvme-core-$(CONFIG_BLK_DEV_NVME_SCSI) += scsi.o
|
||||
nvme-core-$(CONFIG_NVM) += lightnvm.o
|
||||
|
||||
nvme-y += pci.o
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@
|
|||
#include <linux/nvme_ioctl.h>
|
||||
#include <linux/t10-pi.h>
|
||||
#include <linux/pm_qos.h>
|
||||
#include <scsi/sg.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "nvme.h"
|
||||
|
|
@ -45,7 +44,7 @@ module_param_named(io_timeout, nvme_io_timeout, byte, 0644);
|
|||
MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O");
|
||||
EXPORT_SYMBOL_GPL(nvme_io_timeout);
|
||||
|
||||
unsigned char shutdown_timeout = 5;
|
||||
static unsigned char shutdown_timeout = 5;
|
||||
module_param(shutdown_timeout, byte, 0644);
|
||||
MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
|
||||
|
||||
|
|
@ -65,34 +64,53 @@ static bool force_apst;
|
|||
module_param(force_apst, bool, 0644);
|
||||
MODULE_PARM_DESC(force_apst, "allow APST for newly enumerated devices even if quirked off");
|
||||
|
||||
static bool streams;
|
||||
module_param(streams, bool, 0644);
|
||||
MODULE_PARM_DESC(streams, "turn on support for Streams write directives");
|
||||
|
||||
struct workqueue_struct *nvme_wq;
|
||||
EXPORT_SYMBOL_GPL(nvme_wq);
|
||||
|
||||
static LIST_HEAD(nvme_ctrl_list);
|
||||
static DEFINE_SPINLOCK(dev_list_lock);
|
||||
|
||||
static struct class *nvme_class;
|
||||
|
||||
static int nvme_error_status(struct request *req)
|
||||
int nvme_reset_ctrl(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
if (!nvme_change_ctrl_state(ctrl, NVME_CTRL_RESETTING))
|
||||
return -EBUSY;
|
||||
if (!queue_work(nvme_wq, &ctrl->reset_work))
|
||||
return -EBUSY;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_reset_ctrl);
|
||||
|
||||
static int nvme_reset_ctrl_sync(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = nvme_reset_ctrl(ctrl);
|
||||
if (!ret)
|
||||
flush_work(&ctrl->reset_work);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static blk_status_t nvme_error_status(struct request *req)
|
||||
{
|
||||
switch (nvme_req(req)->status & 0x7ff) {
|
||||
case NVME_SC_SUCCESS:
|
||||
return 0;
|
||||
return BLK_STS_OK;
|
||||
case NVME_SC_CAP_EXCEEDED:
|
||||
return -ENOSPC;
|
||||
default:
|
||||
return -EIO;
|
||||
|
||||
/*
|
||||
* XXX: these errors are a nasty side-band protocol to
|
||||
* drivers/md/dm-mpath.c:noretry_error() that aren't documented
|
||||
* anywhere..
|
||||
*/
|
||||
case NVME_SC_CMD_SEQ_ERROR:
|
||||
return -EILSEQ;
|
||||
return BLK_STS_NOSPC;
|
||||
case NVME_SC_ONCS_NOT_SUPPORTED:
|
||||
return -EOPNOTSUPP;
|
||||
return BLK_STS_NOTSUPP;
|
||||
case NVME_SC_WRITE_FAULT:
|
||||
case NVME_SC_READ_ERROR:
|
||||
case NVME_SC_UNWRITTEN_BLOCK:
|
||||
return -ENODATA;
|
||||
return BLK_STS_MEDIUM;
|
||||
default:
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -165,7 +183,6 @@ bool nvme_change_ctrl_state(struct nvme_ctrl *ctrl,
|
|||
switch (old_state) {
|
||||
case NVME_CTRL_NEW:
|
||||
case NVME_CTRL_LIVE:
|
||||
case NVME_CTRL_RECONNECTING:
|
||||
changed = true;
|
||||
/* FALLTHRU */
|
||||
default:
|
||||
|
|
@ -283,6 +300,105 @@ struct request *nvme_alloc_request(struct request_queue *q,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_alloc_request);
|
||||
|
||||
static int nvme_toggle_streams(struct nvme_ctrl *ctrl, bool enable)
|
||||
{
|
||||
struct nvme_command c;
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
|
||||
c.directive.opcode = nvme_admin_directive_send;
|
||||
c.directive.nsid = cpu_to_le32(0xffffffff);
|
||||
c.directive.doper = NVME_DIR_SND_ID_OP_ENABLE;
|
||||
c.directive.dtype = NVME_DIR_IDENTIFY;
|
||||
c.directive.tdtype = NVME_DIR_STREAMS;
|
||||
c.directive.endir = enable ? NVME_DIR_ENDIR : 0;
|
||||
|
||||
return nvme_submit_sync_cmd(ctrl->admin_q, &c, NULL, 0);
|
||||
}
|
||||
|
||||
static int nvme_disable_streams(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
return nvme_toggle_streams(ctrl, false);
|
||||
}
|
||||
|
||||
static int nvme_enable_streams(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
return nvme_toggle_streams(ctrl, true);
|
||||
}
|
||||
|
||||
static int nvme_get_stream_params(struct nvme_ctrl *ctrl,
|
||||
struct streams_directive_params *s, u32 nsid)
|
||||
{
|
||||
struct nvme_command c;
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
memset(s, 0, sizeof(*s));
|
||||
|
||||
c.directive.opcode = nvme_admin_directive_recv;
|
||||
c.directive.nsid = cpu_to_le32(nsid);
|
||||
c.directive.numd = sizeof(*s);
|
||||
c.directive.doper = NVME_DIR_RCV_ST_OP_PARAM;
|
||||
c.directive.dtype = NVME_DIR_STREAMS;
|
||||
|
||||
return nvme_submit_sync_cmd(ctrl->admin_q, &c, s, sizeof(*s));
|
||||
}
|
||||
|
||||
static int nvme_configure_directives(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
struct streams_directive_params s;
|
||||
int ret;
|
||||
|
||||
if (!(ctrl->oacs & NVME_CTRL_OACS_DIRECTIVES))
|
||||
return 0;
|
||||
if (!streams)
|
||||
return 0;
|
||||
|
||||
ret = nvme_enable_streams(ctrl);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nvme_get_stream_params(ctrl, &s, 0xffffffff);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctrl->nssa = le16_to_cpu(s.nssa);
|
||||
if (ctrl->nssa < BLK_MAX_WRITE_HINTS - 1) {
|
||||
dev_info(ctrl->device, "too few streams (%u) available\n",
|
||||
ctrl->nssa);
|
||||
nvme_disable_streams(ctrl);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ctrl->nr_streams = min_t(unsigned, ctrl->nssa, BLK_MAX_WRITE_HINTS - 1);
|
||||
dev_info(ctrl->device, "Using %u streams\n", ctrl->nr_streams);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if 'req' has a write hint associated with it. If it does, assign
|
||||
* a valid namespace stream to the write.
|
||||
*/
|
||||
static void nvme_assign_write_stream(struct nvme_ctrl *ctrl,
|
||||
struct request *req, u16 *control,
|
||||
u32 *dsmgmt)
|
||||
{
|
||||
enum rw_hint streamid = req->write_hint;
|
||||
|
||||
if (streamid == WRITE_LIFE_NOT_SET || streamid == WRITE_LIFE_NONE)
|
||||
streamid = 0;
|
||||
else {
|
||||
streamid--;
|
||||
if (WARN_ON_ONCE(streamid > ctrl->nr_streams))
|
||||
return;
|
||||
|
||||
*control |= NVME_RW_DTYPE_STREAMS;
|
||||
*dsmgmt |= streamid << 16;
|
||||
}
|
||||
|
||||
if (streamid < ARRAY_SIZE(req->q->write_hints))
|
||||
req->q->write_hints[streamid] += blk_rq_bytes(req) >> 9;
|
||||
}
|
||||
|
||||
static inline void nvme_setup_flush(struct nvme_ns *ns,
|
||||
struct nvme_command *cmnd)
|
||||
{
|
||||
|
|
@ -291,7 +407,7 @@ static inline void nvme_setup_flush(struct nvme_ns *ns,
|
|||
cmnd->common.nsid = cpu_to_le32(ns->ns_id);
|
||||
}
|
||||
|
||||
static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
|
||||
static blk_status_t nvme_setup_discard(struct nvme_ns *ns, struct request *req,
|
||||
struct nvme_command *cmnd)
|
||||
{
|
||||
unsigned short segments = blk_rq_nr_discard_segments(req), n = 0;
|
||||
|
|
@ -300,7 +416,7 @@ static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
|
|||
|
||||
range = kmalloc_array(segments, sizeof(*range), GFP_ATOMIC);
|
||||
if (!range)
|
||||
return BLK_MQ_RQ_QUEUE_BUSY;
|
||||
return BLK_STS_RESOURCE;
|
||||
|
||||
__rq_for_each_bio(bio, req) {
|
||||
u64 slba = nvme_block_nr(ns, bio->bi_iter.bi_sector);
|
||||
|
|
@ -314,7 +430,7 @@ static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
|
|||
|
||||
if (WARN_ON_ONCE(n != segments)) {
|
||||
kfree(range);
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
|
||||
memset(cmnd, 0, sizeof(*cmnd));
|
||||
|
|
@ -328,15 +444,26 @@ static inline int nvme_setup_discard(struct nvme_ns *ns, struct request *req,
|
|||
req->special_vec.bv_len = sizeof(*range) * segments;
|
||||
req->rq_flags |= RQF_SPECIAL_PAYLOAD;
|
||||
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
|
||||
struct nvme_command *cmnd)
|
||||
static inline blk_status_t nvme_setup_rw(struct nvme_ns *ns,
|
||||
struct request *req, struct nvme_command *cmnd)
|
||||
{
|
||||
struct nvme_ctrl *ctrl = ns->ctrl;
|
||||
u16 control = 0;
|
||||
u32 dsmgmt = 0;
|
||||
|
||||
/*
|
||||
* If formated with metadata, require the block layer provide a buffer
|
||||
* unless this namespace is formated such that the metadata can be
|
||||
* stripped/generated by the controller with PRACT=1.
|
||||
*/
|
||||
if (ns && ns->ms &&
|
||||
(!ns->pi_type || ns->ms != sizeof(struct t10_pi_tuple)) &&
|
||||
!blk_integrity_rq(req) && !blk_rq_is_passthrough(req))
|
||||
return BLK_STS_NOTSUPP;
|
||||
|
||||
if (req->cmd_flags & REQ_FUA)
|
||||
control |= NVME_RW_FUA;
|
||||
if (req->cmd_flags & (REQ_FAILFAST_DEV | REQ_RAHEAD))
|
||||
|
|
@ -351,6 +478,9 @@ static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
|
|||
cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
|
||||
cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
|
||||
|
||||
if (req_op(req) == REQ_OP_WRITE && ctrl->nr_streams)
|
||||
nvme_assign_write_stream(ctrl, req, &control, &dsmgmt);
|
||||
|
||||
if (ns->ms) {
|
||||
switch (ns->pi_type) {
|
||||
case NVME_NS_DPS_PI_TYPE3:
|
||||
|
|
@ -370,12 +500,13 @@ static inline void nvme_setup_rw(struct nvme_ns *ns, struct request *req,
|
|||
|
||||
cmnd->rw.control = cpu_to_le16(control);
|
||||
cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
|
||||
blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
|
||||
struct nvme_command *cmd)
|
||||
{
|
||||
int ret = BLK_MQ_RQ_QUEUE_OK;
|
||||
blk_status_t ret = BLK_STS_OK;
|
||||
|
||||
if (!(req->rq_flags & RQF_DONTPREP)) {
|
||||
nvme_req(req)->retries = 0;
|
||||
|
|
@ -398,11 +529,11 @@ int nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
|
|||
break;
|
||||
case REQ_OP_READ:
|
||||
case REQ_OP_WRITE:
|
||||
nvme_setup_rw(ns, req, cmd);
|
||||
ret = nvme_setup_rw(ns, req, cmd);
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
|
||||
cmd->common.command_id = req->tag;
|
||||
|
|
@ -555,15 +686,16 @@ int nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
|
|||
result, timeout);
|
||||
}
|
||||
|
||||
static void nvme_keep_alive_end_io(struct request *rq, int error)
|
||||
static void nvme_keep_alive_end_io(struct request *rq, blk_status_t status)
|
||||
{
|
||||
struct nvme_ctrl *ctrl = rq->end_io_data;
|
||||
|
||||
blk_mq_free_request(rq);
|
||||
|
||||
if (error) {
|
||||
if (status) {
|
||||
dev_err(ctrl->device,
|
||||
"failed nvme_keep_alive_end_io error=%d\n", error);
|
||||
"failed nvme_keep_alive_end_io error=%d\n",
|
||||
status);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -599,7 +731,7 @@ static void nvme_keep_alive_work(struct work_struct *work)
|
|||
if (nvme_keep_alive(ctrl)) {
|
||||
/* allocation failure, reset the controller */
|
||||
dev_err(ctrl->device, "keep-alive failed\n");
|
||||
ctrl->ops->reset_ctrl(ctrl);
|
||||
nvme_reset_ctrl(ctrl);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -623,7 +755,7 @@ void nvme_stop_keep_alive(struct nvme_ctrl *ctrl)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_stop_keep_alive);
|
||||
|
||||
int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
|
||||
static int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
|
||||
{
|
||||
struct nvme_command c = { };
|
||||
int error;
|
||||
|
|
@ -643,6 +775,77 @@ int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id)
|
|||
return error;
|
||||
}
|
||||
|
||||
static int nvme_identify_ns_descs(struct nvme_ns *ns, unsigned nsid)
|
||||
{
|
||||
struct nvme_command c = { };
|
||||
int status;
|
||||
void *data;
|
||||
int pos;
|
||||
int len;
|
||||
|
||||
c.identify.opcode = nvme_admin_identify;
|
||||
c.identify.nsid = cpu_to_le32(nsid);
|
||||
c.identify.cns = NVME_ID_CNS_NS_DESC_LIST;
|
||||
|
||||
data = kzalloc(NVME_IDENTIFY_DATA_SIZE, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
status = nvme_submit_sync_cmd(ns->ctrl->admin_q, &c, data,
|
||||
NVME_IDENTIFY_DATA_SIZE);
|
||||
if (status)
|
||||
goto free_data;
|
||||
|
||||
for (pos = 0; pos < NVME_IDENTIFY_DATA_SIZE; pos += len) {
|
||||
struct nvme_ns_id_desc *cur = data + pos;
|
||||
|
||||
if (cur->nidl == 0)
|
||||
break;
|
||||
|
||||
switch (cur->nidt) {
|
||||
case NVME_NIDT_EUI64:
|
||||
if (cur->nidl != NVME_NIDT_EUI64_LEN) {
|
||||
dev_warn(ns->ctrl->device,
|
||||
"ctrl returned bogus length: %d for NVME_NIDT_EUI64\n",
|
||||
cur->nidl);
|
||||
goto free_data;
|
||||
}
|
||||
len = NVME_NIDT_EUI64_LEN;
|
||||
memcpy(ns->eui, data + pos + sizeof(*cur), len);
|
||||
break;
|
||||
case NVME_NIDT_NGUID:
|
||||
if (cur->nidl != NVME_NIDT_NGUID_LEN) {
|
||||
dev_warn(ns->ctrl->device,
|
||||
"ctrl returned bogus length: %d for NVME_NIDT_NGUID\n",
|
||||
cur->nidl);
|
||||
goto free_data;
|
||||
}
|
||||
len = NVME_NIDT_NGUID_LEN;
|
||||
memcpy(ns->nguid, data + pos + sizeof(*cur), len);
|
||||
break;
|
||||
case NVME_NIDT_UUID:
|
||||
if (cur->nidl != NVME_NIDT_UUID_LEN) {
|
||||
dev_warn(ns->ctrl->device,
|
||||
"ctrl returned bogus length: %d for NVME_NIDT_UUID\n",
|
||||
cur->nidl);
|
||||
goto free_data;
|
||||
}
|
||||
len = NVME_NIDT_UUID_LEN;
|
||||
uuid_copy(&ns->uuid, data + pos + sizeof(*cur));
|
||||
break;
|
||||
default:
|
||||
/* Skip unnkown types */
|
||||
len = cur->nidl;
|
||||
break;
|
||||
}
|
||||
|
||||
len += sizeof(*cur);
|
||||
}
|
||||
free_data:
|
||||
kfree(data);
|
||||
return status;
|
||||
}
|
||||
|
||||
static int nvme_identify_ns_list(struct nvme_ctrl *dev, unsigned nsid, __le32 *ns_list)
|
||||
{
|
||||
struct nvme_command c = { };
|
||||
|
|
@ -653,7 +856,7 @@ static int nvme_identify_ns_list(struct nvme_ctrl *dev, unsigned nsid, __le32 *n
|
|||
return nvme_submit_sync_cmd(dev->admin_q, &c, ns_list, 0x1000);
|
||||
}
|
||||
|
||||
int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
|
||||
static int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
|
||||
struct nvme_id_ns **id)
|
||||
{
|
||||
struct nvme_command c = { };
|
||||
|
|
@ -675,26 +878,7 @@ int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
|
|||
return error;
|
||||
}
|
||||
|
||||
int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
|
||||
void *buffer, size_t buflen, u32 *result)
|
||||
{
|
||||
struct nvme_command c;
|
||||
union nvme_result res;
|
||||
int ret;
|
||||
|
||||
memset(&c, 0, sizeof(c));
|
||||
c.features.opcode = nvme_admin_get_features;
|
||||
c.features.nsid = cpu_to_le32(nsid);
|
||||
c.features.fid = cpu_to_le32(fid);
|
||||
|
||||
ret = __nvme_submit_sync_cmd(dev->admin_q, &c, &res, buffer, buflen, 0,
|
||||
NVME_QID_ANY, 0, 0);
|
||||
if (ret >= 0 && result)
|
||||
*result = le32_to_cpu(res.u32);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
|
||||
static int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
|
||||
void *buffer, size_t buflen, u32 *result)
|
||||
{
|
||||
struct nvme_command c;
|
||||
|
|
@ -713,28 +897,6 @@ int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int nvme_get_log_page(struct nvme_ctrl *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;
|
||||
}
|
||||
|
||||
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
|
||||
{
|
||||
u32 q_count = (*count - 1) | ((*count - 1) << 16);
|
||||
|
|
@ -752,7 +914,7 @@ int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count)
|
|||
* access to the admin queue, as that might be only way to fix them up.
|
||||
*/
|
||||
if (status > 0) {
|
||||
dev_err(ctrl->dev, "Could not set queue count (%d)\n", status);
|
||||
dev_err(ctrl->device, "Could not set queue count (%d)\n", status);
|
||||
*count = 0;
|
||||
} else {
|
||||
nr_io_queues = min(result & 0xffff, result >> 16) + 1;
|
||||
|
|
@ -870,12 +1032,6 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
return nvme_user_cmd(ns->ctrl, ns, (void __user *)arg);
|
||||
case NVME_IOCTL_SUBMIT_IO:
|
||||
return nvme_submit_io(ns, (void __user *)arg);
|
||||
#ifdef CONFIG_BLK_DEV_NVME_SCSI
|
||||
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);
|
||||
#endif
|
||||
default:
|
||||
#ifdef CONFIG_NVM
|
||||
if (ns->ndev)
|
||||
|
|
@ -892,10 +1048,6 @@ static int nvme_ioctl(struct block_device *bdev, fmode_t mode,
|
|||
static int nvme_compat_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
switch (cmd) {
|
||||
case SG_IO:
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
return nvme_ioctl(bdev, mode, cmd, arg);
|
||||
}
|
||||
#else
|
||||
|
|
@ -983,6 +1135,12 @@ static void nvme_init_integrity(struct nvme_ns *ns)
|
|||
}
|
||||
#endif /* CONFIG_BLK_DEV_INTEGRITY */
|
||||
|
||||
static void nvme_set_chunk_size(struct nvme_ns *ns)
|
||||
{
|
||||
u32 chunk_size = (((u32)ns->noiob) << (ns->lba_shift - 9));
|
||||
blk_queue_chunk_sectors(ns->queue, rounddown_pow_of_two(chunk_size));
|
||||
}
|
||||
|
||||
static void nvme_config_discard(struct nvme_ns *ns)
|
||||
{
|
||||
struct nvme_ctrl *ctrl = ns->ctrl;
|
||||
|
|
@ -991,8 +1149,15 @@ static void nvme_config_discard(struct nvme_ns *ns)
|
|||
BUILD_BUG_ON(PAGE_SIZE / sizeof(struct nvme_dsm_range) <
|
||||
NVME_DSM_MAX_RANGES);
|
||||
|
||||
ns->queue->limits.discard_alignment = logical_block_size;
|
||||
ns->queue->limits.discard_granularity = logical_block_size;
|
||||
if (ctrl->nr_streams && ns->sws && ns->sgs) {
|
||||
unsigned int sz = logical_block_size * ns->sws * ns->sgs;
|
||||
|
||||
ns->queue->limits.discard_alignment = sz;
|
||||
ns->queue->limits.discard_granularity = sz;
|
||||
} else {
|
||||
ns->queue->limits.discard_alignment = logical_block_size;
|
||||
ns->queue->limits.discard_granularity = logical_block_size;
|
||||
}
|
||||
blk_queue_max_discard_sectors(ns->queue, UINT_MAX);
|
||||
blk_queue_max_discard_segments(ns->queue, NVME_DSM_MAX_RANGES);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
|
||||
|
|
@ -1016,7 +1181,15 @@ static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
|
|||
if (ns->ctrl->vs >= NVME_VS(1, 1, 0))
|
||||
memcpy(ns->eui, (*id)->eui64, sizeof(ns->eui));
|
||||
if (ns->ctrl->vs >= NVME_VS(1, 2, 0))
|
||||
memcpy(ns->uuid, (*id)->nguid, sizeof(ns->uuid));
|
||||
memcpy(ns->nguid, (*id)->nguid, sizeof(ns->nguid));
|
||||
if (ns->ctrl->vs >= NVME_VS(1, 3, 0)) {
|
||||
/* Don't treat error as fatal we potentially
|
||||
* already have a NGUID or EUI-64
|
||||
*/
|
||||
if (nvme_identify_ns_descs(ns, ns->ns_id))
|
||||
dev_warn(ns->ctrl->device,
|
||||
"%s: Identify Descriptors failed\n", __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1024,6 +1197,7 @@ static int nvme_revalidate_ns(struct nvme_ns *ns, struct nvme_id_ns **id)
|
|||
static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
|
||||
{
|
||||
struct nvme_ns *ns = disk->private_data;
|
||||
struct nvme_ctrl *ctrl = ns->ctrl;
|
||||
u16 bs;
|
||||
|
||||
/*
|
||||
|
|
@ -1034,12 +1208,15 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
|
|||
if (ns->lba_shift == 0)
|
||||
ns->lba_shift = 9;
|
||||
bs = 1 << ns->lba_shift;
|
||||
ns->noiob = le16_to_cpu(id->noiob);
|
||||
|
||||
blk_mq_freeze_queue(disk->queue);
|
||||
|
||||
if (ns->ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)
|
||||
if (ctrl->ops->flags & NVME_F_METADATA_SUPPORTED)
|
||||
nvme_prep_integrity(disk, id, bs);
|
||||
blk_queue_logical_block_size(ns->queue, bs);
|
||||
if (ns->noiob)
|
||||
nvme_set_chunk_size(ns);
|
||||
if (ns->ms && !blk_get_integrity(disk) && !ns->ext)
|
||||
nvme_init_integrity(ns);
|
||||
if (ns->ms && !(ns->ms == 8 && ns->pi_type) && !blk_get_integrity(disk))
|
||||
|
|
@ -1047,7 +1224,7 @@ static void __nvme_revalidate_disk(struct gendisk *disk, struct nvme_id_ns *id)
|
|||
else
|
||||
set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
|
||||
|
||||
if (ns->ctrl->oncs & NVME_CTRL_ONCS_DSM)
|
||||
if (ctrl->oncs & NVME_CTRL_ONCS_DSM)
|
||||
nvme_config_discard(ns);
|
||||
blk_mq_unfreeze_queue(disk->queue);
|
||||
}
|
||||
|
|
@ -1283,7 +1460,7 @@ EXPORT_SYMBOL_GPL(nvme_enable_ctrl);
|
|||
|
||||
int nvme_shutdown_ctrl(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
unsigned long timeout = SHUTDOWN_TIMEOUT + jiffies;
|
||||
unsigned long timeout = jiffies + (shutdown_timeout * HZ);
|
||||
u32 csts;
|
||||
int ret;
|
||||
|
||||
|
|
@ -1372,7 +1549,7 @@ static void nvme_configure_apst(struct nvme_ctrl *ctrl)
|
|||
if (!table)
|
||||
return;
|
||||
|
||||
if (ctrl->ps_max_latency_us == 0) {
|
||||
if (!ctrl->apst_enabled || ctrl->ps_max_latency_us == 0) {
|
||||
/* Turn off APST. */
|
||||
apste = 0;
|
||||
dev_dbg(ctrl->device, "APST disabled\n");
|
||||
|
|
@ -1528,6 +1705,31 @@ static bool quirk_matches(const struct nvme_id_ctrl *id,
|
|||
string_matches(id->fr, q->fr, sizeof(id->fr));
|
||||
}
|
||||
|
||||
static void nvme_init_subnqn(struct nvme_ctrl *ctrl, struct nvme_id_ctrl *id)
|
||||
{
|
||||
size_t nqnlen;
|
||||
int off;
|
||||
|
||||
nqnlen = strnlen(id->subnqn, NVMF_NQN_SIZE);
|
||||
if (nqnlen > 0 && nqnlen < NVMF_NQN_SIZE) {
|
||||
strcpy(ctrl->subnqn, id->subnqn);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctrl->vs >= NVME_VS(1, 2, 1))
|
||||
dev_warn(ctrl->device, "missing or invalid SUBNQN field.\n");
|
||||
|
||||
/* Generate a "fake" NQN per Figure 254 in NVMe 1.3 + ECN 001 */
|
||||
off = snprintf(ctrl->subnqn, NVMF_NQN_SIZE,
|
||||
"nqn.2014.08.org.nvmexpress:%4x%4x",
|
||||
le16_to_cpu(id->vid), le16_to_cpu(id->ssvid));
|
||||
memcpy(ctrl->subnqn + off, id->sn, sizeof(id->sn));
|
||||
off += sizeof(id->sn);
|
||||
memcpy(ctrl->subnqn + off, id->mn, sizeof(id->mn));
|
||||
off += sizeof(id->mn);
|
||||
memset(ctrl->subnqn + off, 0, sizeof(ctrl->subnqn) - off);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the cached copies of the Identify data and various controller
|
||||
* register in our nvme_ctrl structure. This should be called as soon as
|
||||
|
|
@ -1539,7 +1741,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
u64 cap;
|
||||
int ret, page_shift;
|
||||
u32 max_hw_sectors;
|
||||
u8 prev_apsta;
|
||||
bool prev_apst_enabled;
|
||||
|
||||
ret = ctrl->ops->reg_read32(ctrl, NVME_REG_VS, &ctrl->vs);
|
||||
if (ret) {
|
||||
|
|
@ -1563,6 +1765,8 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
nvme_init_subnqn(ctrl, id);
|
||||
|
||||
if (!ctrl->identified) {
|
||||
/*
|
||||
* Check for quirks. Quirk can depend on firmware version,
|
||||
|
|
@ -1582,7 +1786,7 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
}
|
||||
|
||||
if (force_apst && (ctrl->quirks & NVME_QUIRK_NO_DEEPEST_PS)) {
|
||||
dev_warn(ctrl->dev, "forcibly allowing all power states due to nvme_core.force_apst -- use at your own risk\n");
|
||||
dev_warn(ctrl->device, "forcibly allowing all power states due to nvme_core.force_apst -- use at your own risk\n");
|
||||
ctrl->quirks &= ~NVME_QUIRK_NO_DEEPEST_PS;
|
||||
}
|
||||
|
||||
|
|
@ -1607,16 +1811,17 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
ctrl->kas = le16_to_cpu(id->kas);
|
||||
|
||||
ctrl->npss = id->npss;
|
||||
prev_apsta = ctrl->apsta;
|
||||
ctrl->apsta = id->apsta;
|
||||
prev_apst_enabled = ctrl->apst_enabled;
|
||||
if (ctrl->quirks & NVME_QUIRK_NO_APST) {
|
||||
if (force_apst && id->apsta) {
|
||||
dev_warn(ctrl->dev, "forcibly allowing APST due to nvme_core.force_apst -- use at your own risk\n");
|
||||
ctrl->apsta = 1;
|
||||
dev_warn(ctrl->device, "forcibly allowing APST due to nvme_core.force_apst -- use at your own risk\n");
|
||||
ctrl->apst_enabled = true;
|
||||
} else {
|
||||
ctrl->apsta = 0;
|
||||
ctrl->apst_enabled = false;
|
||||
}
|
||||
} else {
|
||||
ctrl->apsta = id->apsta;
|
||||
ctrl->apst_enabled = id->apsta;
|
||||
}
|
||||
memcpy(ctrl->psd, id->psd, sizeof(ctrl->psd));
|
||||
|
||||
|
|
@ -1634,22 +1839,25 @@ int nvme_init_identify(struct nvme_ctrl *ctrl)
|
|||
ret = -EINVAL;
|
||||
|
||||
if (!ctrl->opts->discovery_nqn && !ctrl->kas) {
|
||||
dev_err(ctrl->dev,
|
||||
dev_err(ctrl->device,
|
||||
"keep-alive support is mandatory for fabrics\n");
|
||||
ret = -EINVAL;
|
||||
}
|
||||
} else {
|
||||
ctrl->cntlid = le16_to_cpu(id->cntlid);
|
||||
ctrl->hmpre = le32_to_cpu(id->hmpre);
|
||||
ctrl->hmmin = le32_to_cpu(id->hmmin);
|
||||
}
|
||||
|
||||
kfree(id);
|
||||
|
||||
if (ctrl->apsta && !prev_apsta)
|
||||
if (ctrl->apst_enabled && !prev_apst_enabled)
|
||||
dev_pm_qos_expose_latency_tolerance(ctrl->device);
|
||||
else if (!ctrl->apsta && prev_apsta)
|
||||
else if (!ctrl->apst_enabled && prev_apst_enabled)
|
||||
dev_pm_qos_hide_latency_tolerance(ctrl->device);
|
||||
|
||||
nvme_configure_apst(ctrl);
|
||||
nvme_configure_directives(ctrl);
|
||||
|
||||
ctrl->identified = true;
|
||||
|
||||
|
|
@ -1735,7 +1943,7 @@ static long nvme_dev_ioctl(struct file *file, unsigned int cmd,
|
|||
return nvme_dev_user_cmd(ctrl, argp);
|
||||
case NVME_IOCTL_RESET:
|
||||
dev_warn(ctrl->device, "resetting controller\n");
|
||||
return ctrl->ops->reset_ctrl(ctrl);
|
||||
return nvme_reset_ctrl_sync(ctrl);
|
||||
case NVME_IOCTL_SUBSYS_RESET:
|
||||
return nvme_reset_subsystem(ctrl);
|
||||
case NVME_IOCTL_RESCAN:
|
||||
|
|
@ -1761,7 +1969,7 @@ static ssize_t nvme_sysfs_reset(struct device *dev,
|
|||
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = ctrl->ops->reset_ctrl(ctrl);
|
||||
ret = nvme_reset_ctrl_sync(ctrl);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
return count;
|
||||
|
|
@ -1787,8 +1995,8 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
|
|||
int serial_len = sizeof(ctrl->serial);
|
||||
int model_len = sizeof(ctrl->model);
|
||||
|
||||
if (memchr_inv(ns->uuid, 0, sizeof(ns->uuid)))
|
||||
return sprintf(buf, "eui.%16phN\n", ns->uuid);
|
||||
if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid)))
|
||||
return sprintf(buf, "eui.%16phN\n", ns->nguid);
|
||||
|
||||
if (memchr_inv(ns->eui, 0, sizeof(ns->eui)))
|
||||
return sprintf(buf, "eui.%8phN\n", ns->eui);
|
||||
|
|
@ -1803,11 +2011,28 @@ static ssize_t wwid_show(struct device *dev, struct device_attribute *attr,
|
|||
}
|
||||
static DEVICE_ATTR(wwid, S_IRUGO, wwid_show, NULL);
|
||||
|
||||
static ssize_t nguid_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
|
||||
return sprintf(buf, "%pU\n", ns->nguid);
|
||||
}
|
||||
static DEVICE_ATTR(nguid, S_IRUGO, nguid_show, NULL);
|
||||
|
||||
static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
|
||||
return sprintf(buf, "%pU\n", ns->uuid);
|
||||
|
||||
/* For backward compatibility expose the NGUID to userspace if
|
||||
* we have no UUID set
|
||||
*/
|
||||
if (uuid_is_null(&ns->uuid)) {
|
||||
printk_ratelimited(KERN_WARNING
|
||||
"No UUID available providing old NGUID\n");
|
||||
return sprintf(buf, "%pU\n", ns->nguid);
|
||||
}
|
||||
return sprintf(buf, "%pU\n", &ns->uuid);
|
||||
}
|
||||
static DEVICE_ATTR(uuid, S_IRUGO, uuid_show, NULL);
|
||||
|
||||
|
|
@ -1830,6 +2055,7 @@ static DEVICE_ATTR(nsid, S_IRUGO, nsid_show, NULL);
|
|||
static struct attribute *nvme_ns_attrs[] = {
|
||||
&dev_attr_wwid.attr,
|
||||
&dev_attr_uuid.attr,
|
||||
&dev_attr_nguid.attr,
|
||||
&dev_attr_eui.attr,
|
||||
&dev_attr_nsid.attr,
|
||||
NULL,
|
||||
|
|
@ -1842,7 +2068,12 @@ static umode_t nvme_ns_attrs_are_visible(struct kobject *kobj,
|
|||
struct nvme_ns *ns = nvme_get_ns_from_dev(dev);
|
||||
|
||||
if (a == &dev_attr_uuid.attr) {
|
||||
if (!memchr_inv(ns->uuid, 0, sizeof(ns->uuid)))
|
||||
if (uuid_is_null(&ns->uuid) ||
|
||||
!memchr_inv(ns->nguid, 0, sizeof(ns->nguid)))
|
||||
return 0;
|
||||
}
|
||||
if (a == &dev_attr_nguid.attr) {
|
||||
if (!memchr_inv(ns->nguid, 0, sizeof(ns->nguid)))
|
||||
return 0;
|
||||
}
|
||||
if (a == &dev_attr_eui.attr) {
|
||||
|
|
@ -1931,8 +2162,7 @@ static ssize_t nvme_sysfs_show_subsysnqn(struct device *dev,
|
|||
{
|
||||
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
ctrl->ops->get_subsysnqn(ctrl));
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n", ctrl->subnqn);
|
||||
}
|
||||
static DEVICE_ATTR(subsysnqn, S_IRUGO, nvme_sysfs_show_subsysnqn, NULL);
|
||||
|
||||
|
|
@ -1961,24 +2191,16 @@ static struct attribute *nvme_dev_attrs[] = {
|
|||
NULL
|
||||
};
|
||||
|
||||
#define CHECK_ATTR(ctrl, a, name) \
|
||||
if ((a) == &dev_attr_##name.attr && \
|
||||
!(ctrl)->ops->get_##name) \
|
||||
return 0
|
||||
|
||||
static umode_t nvme_dev_attrs_are_visible(struct kobject *kobj,
|
||||
struct attribute *a, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
|
||||
|
||||
if (a == &dev_attr_delete_controller.attr) {
|
||||
if (!ctrl->ops->delete_ctrl)
|
||||
return 0;
|
||||
}
|
||||
|
||||
CHECK_ATTR(ctrl, a, subsysnqn);
|
||||
CHECK_ATTR(ctrl, a, address);
|
||||
if (a == &dev_attr_delete_controller.attr && !ctrl->ops->delete_ctrl)
|
||||
return 0;
|
||||
if (a == &dev_attr_address.attr && !ctrl->ops->get_address)
|
||||
return 0;
|
||||
|
||||
return a->mode;
|
||||
}
|
||||
|
|
@ -2019,6 +2241,32 @@ static struct nvme_ns *nvme_find_get_ns(struct nvme_ctrl *ctrl, unsigned nsid)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int nvme_setup_streams_ns(struct nvme_ctrl *ctrl, struct nvme_ns *ns)
|
||||
{
|
||||
struct streams_directive_params s;
|
||||
int ret;
|
||||
|
||||
if (!ctrl->nr_streams)
|
||||
return 0;
|
||||
|
||||
ret = nvme_get_stream_params(ctrl, &s, ns->ns_id);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ns->sws = le32_to_cpu(s.sws);
|
||||
ns->sgs = le16_to_cpu(s.sgs);
|
||||
|
||||
if (ns->sws) {
|
||||
unsigned int bs = 1 << ns->lba_shift;
|
||||
|
||||
blk_queue_io_min(ns->queue, bs * ns->sws);
|
||||
if (ns->sgs)
|
||||
blk_queue_io_opt(ns->queue, bs * ns->sws * ns->sgs);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
|
||||
{
|
||||
struct nvme_ns *ns;
|
||||
|
|
@ -2048,6 +2296,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
|
|||
|
||||
blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
|
||||
nvme_set_queue_limits(ctrl, ns->queue);
|
||||
nvme_setup_streams_ns(ctrl, ns);
|
||||
|
||||
sprintf(disk_name, "nvme%dn%d", ctrl->instance, ns->instance);
|
||||
|
||||
|
|
@ -2056,7 +2305,7 @@ static void nvme_alloc_ns(struct nvme_ctrl *ctrl, unsigned nsid)
|
|||
|
||||
if (nvme_nvm_ns_supported(ns, id) &&
|
||||
nvme_nvm_register(ns, disk_name, node)) {
|
||||
dev_warn(ctrl->dev, "%s: LightNVM init failure\n", __func__);
|
||||
dev_warn(ctrl->device, "%s: LightNVM init failure\n", __func__);
|
||||
goto out_free_id;
|
||||
}
|
||||
|
||||
|
|
@ -2231,7 +2480,7 @@ void nvme_queue_scan(struct nvme_ctrl *ctrl)
|
|||
* removal.
|
||||
*/
|
||||
if (ctrl->state == NVME_CTRL_LIVE)
|
||||
schedule_work(&ctrl->scan_work);
|
||||
queue_work(nvme_wq, &ctrl->scan_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_queue_scan);
|
||||
|
||||
|
|
@ -2286,7 +2535,7 @@ void nvme_complete_async_event(struct nvme_ctrl *ctrl, __le16 status,
|
|||
/*FALLTHRU*/
|
||||
case NVME_SC_ABORT_REQ:
|
||||
++ctrl->event_limit;
|
||||
schedule_work(&ctrl->async_event_work);
|
||||
queue_work(nvme_wq, &ctrl->async_event_work);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -2309,7 +2558,7 @@ EXPORT_SYMBOL_GPL(nvme_complete_async_event);
|
|||
void nvme_queue_async_events(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
ctrl->event_limit = NVME_NR_AERS;
|
||||
schedule_work(&ctrl->async_event_work);
|
||||
queue_work(nvme_wq, &ctrl->async_event_work);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvme_queue_async_events);
|
||||
|
||||
|
|
@ -2442,6 +2691,9 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
|
|||
|
||||
mutex_lock(&ctrl->namespaces_mutex);
|
||||
|
||||
/* Forcibly unquiesce queues to avoid blocking dispatch */
|
||||
blk_mq_unquiesce_queue(ctrl->admin_q);
|
||||
|
||||
/* Forcibly start all queues to avoid having stuck requests */
|
||||
blk_mq_start_hw_queues(ctrl->admin_q);
|
||||
|
||||
|
|
@ -2455,6 +2707,9 @@ void nvme_kill_queues(struct nvme_ctrl *ctrl)
|
|||
revalidate_disk(ns->disk);
|
||||
blk_set_queue_dying(ns->queue);
|
||||
|
||||
/* Forcibly unquiesce queues to avoid blocking dispatch */
|
||||
blk_mq_unquiesce_queue(ns->queue);
|
||||
|
||||
/*
|
||||
* Forcibly start all queues to avoid having stuck requests.
|
||||
* Note that we must ensure the queues are not stopped
|
||||
|
|
@ -2533,7 +2788,7 @@ void nvme_start_queues(struct nvme_ctrl *ctrl)
|
|||
|
||||
mutex_lock(&ctrl->namespaces_mutex);
|
||||
list_for_each_entry(ns, &ctrl->namespaces, list) {
|
||||
blk_mq_start_stopped_hw_queues(ns->queue, true);
|
||||
blk_mq_unquiesce_queue(ns->queue);
|
||||
blk_mq_kick_requeue_list(ns->queue);
|
||||
}
|
||||
mutex_unlock(&ctrl->namespaces_mutex);
|
||||
|
|
@ -2544,10 +2799,15 @@ int __init nvme_core_init(void)
|
|||
{
|
||||
int result;
|
||||
|
||||
nvme_wq = alloc_workqueue("nvme-wq",
|
||||
WQ_UNBOUND | WQ_MEM_RECLAIM | WQ_SYSFS, 0);
|
||||
if (!nvme_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
|
||||
&nvme_dev_fops);
|
||||
if (result < 0)
|
||||
return result;
|
||||
goto destroy_wq;
|
||||
else if (result > 0)
|
||||
nvme_char_major = result;
|
||||
|
||||
|
|
@ -2559,8 +2819,10 @@ int __init nvme_core_init(void)
|
|||
|
||||
return 0;
|
||||
|
||||
unregister_chrdev:
|
||||
unregister_chrdev:
|
||||
__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
|
||||
destroy_wq:
|
||||
destroy_workqueue(nvme_wq);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -2568,6 +2830,7 @@ void nvme_core_exit(void)
|
|||
{
|
||||
class_destroy(nvme_class);
|
||||
__unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
|
||||
destroy_workqueue(nvme_wq);
|
||||
}
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
|||
|
|
@ -58,7 +58,6 @@ static struct nvmf_host *nvmf_host_add(const char *hostnqn)
|
|||
|
||||
kref_init(&host->ref);
|
||||
memcpy(host->nqn, hostnqn, NVMF_NQN_SIZE);
|
||||
uuid_gen(&host->id);
|
||||
|
||||
list_add_tail(&host->list, &nvmf_hosts);
|
||||
out_unlock:
|
||||
|
|
@ -75,7 +74,6 @@ static struct nvmf_host *nvmf_host_default(void)
|
|||
return NULL;
|
||||
|
||||
kref_init(&host->ref);
|
||||
uuid_gen(&host->id);
|
||||
snprintf(host->nqn, NVMF_NQN_SIZE,
|
||||
"nqn.2014-08.org.nvmexpress:NVMf:uuid:%pUb", &host->id);
|
||||
|
||||
|
|
@ -127,16 +125,6 @@ int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nvmf_get_address);
|
||||
|
||||
/**
|
||||
* nvmf_get_subsysnqn() - Get subsystem NQN
|
||||
* @ctrl: Host NVMe controller instance which we got the NQN
|
||||
*/
|
||||
const char *nvmf_get_subsysnqn(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
return ctrl->opts->subsysnqn;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nvmf_get_subsysnqn);
|
||||
|
||||
/**
|
||||
* nvmf_reg_read32() - NVMe Fabrics "Property Get" API function.
|
||||
* @ctrl: Host NVMe controller instance maintaining the admin
|
||||
|
|
@ -337,6 +325,24 @@ static void nvmf_log_connect_error(struct nvme_ctrl *ctrl,
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NVME_SC_CONNECT_INVALID_HOST:
|
||||
dev_err(ctrl->device,
|
||||
"Connect for subsystem %s is not allowed, hostnqn: %s\n",
|
||||
data->subsysnqn, data->hostnqn);
|
||||
break;
|
||||
|
||||
case NVME_SC_CONNECT_CTRL_BUSY:
|
||||
dev_err(ctrl->device,
|
||||
"Connect command failed: controller is busy or not available\n");
|
||||
break;
|
||||
|
||||
case NVME_SC_CONNECT_FORMAT:
|
||||
dev_err(ctrl->device,
|
||||
"Connect incompatible format: %d",
|
||||
cmd->connect.recfmt);
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_err(ctrl->device,
|
||||
"Connect command failed, error wo/DNR bit: %d\n",
|
||||
|
|
@ -376,13 +382,7 @@ int nvmf_connect_admin_queue(struct nvme_ctrl *ctrl)
|
|||
cmd.connect.opcode = nvme_fabrics_command;
|
||||
cmd.connect.fctype = nvme_fabrics_type_connect;
|
||||
cmd.connect.qid = 0;
|
||||
|
||||
/*
|
||||
* fabrics spec sets a minimum of depth 32 for admin queue,
|
||||
* so set the queue with this depth always until
|
||||
* justification otherwise.
|
||||
*/
|
||||
cmd.connect.sqsize = cpu_to_le16(NVMF_AQ_DEPTH - 1);
|
||||
cmd.connect.sqsize = cpu_to_le16(NVME_AQ_DEPTH - 1);
|
||||
|
||||
/*
|
||||
* Set keep-alive timeout in seconds granularity (ms * 1000)
|
||||
|
|
@ -474,7 +474,7 @@ EXPORT_SYMBOL_GPL(nvmf_connect_io_queue);
|
|||
bool nvmf_should_reconnect(struct nvme_ctrl *ctrl)
|
||||
{
|
||||
if (ctrl->opts->max_reconnects != -1 &&
|
||||
ctrl->opts->nr_reconnects < ctrl->opts->max_reconnects)
|
||||
ctrl->nr_reconnects < ctrl->opts->max_reconnects)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -547,6 +547,7 @@ static const match_table_t opt_tokens = {
|
|||
{ NVMF_OPT_KATO, "keep_alive_tmo=%d" },
|
||||
{ NVMF_OPT_HOSTNQN, "hostnqn=%s" },
|
||||
{ NVMF_OPT_HOST_TRADDR, "host_traddr=%s" },
|
||||
{ NVMF_OPT_HOST_ID, "hostid=%s" },
|
||||
{ NVMF_OPT_ERR, NULL }
|
||||
};
|
||||
|
||||
|
|
@ -558,6 +559,7 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
|
|||
int token, ret = 0;
|
||||
size_t nqnlen = 0;
|
||||
int ctrl_loss_tmo = NVMF_DEF_CTRL_LOSS_TMO;
|
||||
uuid_t hostid;
|
||||
|
||||
/* Set defaults */
|
||||
opts->queue_size = NVMF_DEF_QUEUE_SIZE;
|
||||
|
|
@ -568,6 +570,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
|
|||
if (!options)
|
||||
return -ENOMEM;
|
||||
|
||||
uuid_gen(&hostid);
|
||||
|
||||
while ((p = strsep(&o, ",\n")) != NULL) {
|
||||
if (!*p)
|
||||
continue;
|
||||
|
|
@ -724,6 +728,17 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
|
|||
}
|
||||
opts->host_traddr = p;
|
||||
break;
|
||||
case NVMF_OPT_HOST_ID:
|
||||
p = match_strdup(args);
|
||||
if (!p) {
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
if (uuid_parse(p, &hostid)) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pr_warn("unknown parameter or missing value '%s' in ctrl creation request\n",
|
||||
p);
|
||||
|
|
@ -743,6 +758,8 @@ static int nvmf_parse_options(struct nvmf_ctrl_options *opts,
|
|||
opts->host = nvmf_default_host;
|
||||
}
|
||||
|
||||
uuid_copy(&opts->host->id, &hostid);
|
||||
|
||||
out:
|
||||
if (!opts->discovery_nqn && !opts->kato)
|
||||
opts->kato = NVME_DEFAULT_KATO;
|
||||
|
|
@ -803,7 +820,8 @@ EXPORT_SYMBOL_GPL(nvmf_free_options);
|
|||
|
||||
#define NVMF_REQUIRED_OPTS (NVMF_OPT_TRANSPORT | NVMF_OPT_NQN)
|
||||
#define NVMF_ALLOWED_OPTS (NVMF_OPT_QUEUE_SIZE | NVMF_OPT_NR_IO_QUEUES | \
|
||||
NVMF_OPT_KATO | NVMF_OPT_HOSTNQN)
|
||||
NVMF_OPT_KATO | NVMF_OPT_HOSTNQN | \
|
||||
NVMF_OPT_HOST_ID)
|
||||
|
||||
static struct nvme_ctrl *
|
||||
nvmf_create_ctrl(struct device *dev, const char *buf, size_t count)
|
||||
|
|
@ -854,6 +872,15 @@ nvmf_create_ctrl(struct device *dev, const char *buf, size_t count)
|
|||
goto out_unlock;
|
||||
}
|
||||
|
||||
if (strcmp(ctrl->subnqn, opts->subsysnqn)) {
|
||||
dev_warn(ctrl->device,
|
||||
"controller returned incorrect NQN: \"%s\".\n",
|
||||
ctrl->subnqn);
|
||||
mutex_unlock(&nvmf_transports_mutex);
|
||||
ctrl->ops->delete_ctrl(ctrl);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
|
||||
mutex_unlock(&nvmf_transports_mutex);
|
||||
return ctrl;
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ enum {
|
|||
NVMF_OPT_RECONNECT_DELAY = 1 << 9,
|
||||
NVMF_OPT_HOST_TRADDR = 1 << 10,
|
||||
NVMF_OPT_CTRL_LOSS_TMO = 1 << 11,
|
||||
NVMF_OPT_HOST_ID = 1 << 12,
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -80,7 +81,6 @@ enum {
|
|||
* @discovery_nqn: indicates if the subsysnqn is the well-known discovery NQN.
|
||||
* @kato: Keep-alive timeout.
|
||||
* @host: Virtual NVMe host, contains the NQN and Host ID.
|
||||
* @nr_reconnects: number of reconnect attempted since the last ctrl failure
|
||||
* @max_reconnects: maximum number of allowed reconnect attempts before removing
|
||||
* the controller, (-1) means reconnect forever, zero means remove
|
||||
* immediately;
|
||||
|
|
@ -98,7 +98,6 @@ struct nvmf_ctrl_options {
|
|||
bool discovery_nqn;
|
||||
unsigned int kato;
|
||||
struct nvmf_host *host;
|
||||
int nr_reconnects;
|
||||
int max_reconnects;
|
||||
};
|
||||
|
||||
|
|
@ -140,7 +139,6 @@ int nvmf_connect_io_queue(struct nvme_ctrl *ctrl, u16 qid);
|
|||
int nvmf_register_transport(struct nvmf_transport_ops *ops);
|
||||
void nvmf_unregister_transport(struct nvmf_transport_ops *ops);
|
||||
void nvmf_free_options(struct nvmf_ctrl_options *opts);
|
||||
const char *nvmf_get_subsysnqn(struct nvme_ctrl *ctrl);
|
||||
int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size);
|
||||
bool nvmf_should_reconnect(struct nvme_ctrl *ctrl);
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
*/
|
||||
#define NVME_FC_NR_AEN_COMMANDS 1
|
||||
#define NVME_FC_AQ_BLKMQ_DEPTH \
|
||||
(NVMF_AQ_DEPTH - NVME_FC_NR_AEN_COMMANDS)
|
||||
(NVME_AQ_DEPTH - NVME_FC_NR_AEN_COMMANDS)
|
||||
#define AEN_CMDID_BASE (NVME_FC_AQ_BLKMQ_DEPTH + 1)
|
||||
|
||||
enum nvme_fc_queue_flags {
|
||||
|
|
@ -161,12 +161,12 @@ struct nvme_fc_ctrl {
|
|||
struct blk_mq_tag_set tag_set;
|
||||
|
||||
struct work_struct delete_work;
|
||||
struct work_struct reset_work;
|
||||
struct delayed_work connect_work;
|
||||
|
||||
struct kref ref;
|
||||
u32 flags;
|
||||
u32 iocnt;
|
||||
wait_queue_head_t ioabort_wait;
|
||||
|
||||
struct nvme_fc_fcp_op aen_ops[NVME_FC_NR_AEN_COMMANDS];
|
||||
|
||||
|
|
@ -214,7 +214,6 @@ static LIST_HEAD(nvme_fc_lport_list);
|
|||
static DEFINE_IDA(nvme_fc_local_port_cnt);
|
||||
static DEFINE_IDA(nvme_fc_ctrl_cnt);
|
||||
|
||||
static struct workqueue_struct *nvme_fc_wq;
|
||||
|
||||
|
||||
|
||||
|
|
@ -1241,8 +1240,10 @@ __nvme_fc_fcpop_chk_teardowns(struct nvme_fc_ctrl *ctrl,
|
|||
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
if (unlikely(op->flags & FCOP_FLAGS_TERMIO)) {
|
||||
if (ctrl->flags & FCCTRL_TERMIO)
|
||||
ctrl->iocnt--;
|
||||
if (ctrl->flags & FCCTRL_TERMIO) {
|
||||
if (!--ctrl->iocnt)
|
||||
wake_up(&ctrl->ioabort_wait);
|
||||
}
|
||||
}
|
||||
if (op->flags & FCOP_FLAGS_RELEASED)
|
||||
complete_rq = true;
|
||||
|
|
@ -1449,18 +1450,8 @@ nvme_fc_init_request(struct blk_mq_tag_set *set, struct request *rq,
|
|||
{
|
||||
struct nvme_fc_ctrl *ctrl = set->driver_data;
|
||||
struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
|
||||
struct nvme_fc_queue *queue = &ctrl->queues[hctx_idx+1];
|
||||
|
||||
return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
|
||||
}
|
||||
|
||||
static int
|
||||
nvme_fc_init_admin_request(struct blk_mq_tag_set *set, struct request *rq,
|
||||
unsigned int hctx_idx, unsigned int numa_node)
|
||||
{
|
||||
struct nvme_fc_ctrl *ctrl = set->driver_data;
|
||||
struct nvme_fc_fcp_op *op = blk_mq_rq_to_pdu(rq);
|
||||
struct nvme_fc_queue *queue = &ctrl->queues[0];
|
||||
int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
|
||||
struct nvme_fc_queue *queue = &ctrl->queues[queue_idx];
|
||||
|
||||
return __nvme_fc_init_request(ctrl, queue, op, rq, queue->rqcnt++);
|
||||
}
|
||||
|
|
@ -1758,16 +1749,16 @@ nvme_fc_nvme_ctrl_freed(struct nvme_ctrl *nctrl)
|
|||
static void
|
||||
nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg)
|
||||
{
|
||||
/* only proceed if in LIVE state - e.g. on first error */
|
||||
if (ctrl->ctrl.state != NVME_CTRL_LIVE)
|
||||
return;
|
||||
|
||||
dev_warn(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: transport association error detected: %s\n",
|
||||
ctrl->cnum, errmsg);
|
||||
dev_warn(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: resetting controller\n", ctrl->cnum);
|
||||
|
||||
/* stop the queues on error, cleanup is in reset thread */
|
||||
if (ctrl->queue_count > 1)
|
||||
nvme_stop_queues(&ctrl->ctrl);
|
||||
|
||||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING)) {
|
||||
dev_err(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: error_recovery: Couldn't change state "
|
||||
|
|
@ -1775,10 +1766,7 @@ nvme_fc_error_recovery(struct nvme_fc_ctrl *ctrl, char *errmsg)
|
|||
return;
|
||||
}
|
||||
|
||||
if (!queue_work(nvme_fc_wq, &ctrl->reset_work))
|
||||
dev_err(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: error_recovery: Failed to schedule "
|
||||
"reset work\n", ctrl->cnum);
|
||||
nvme_reset_ctrl(&ctrl->ctrl);
|
||||
}
|
||||
|
||||
static enum blk_eh_timer_return
|
||||
|
|
@ -1887,7 +1875,7 @@ nvme_fc_unmap_data(struct nvme_fc_ctrl *ctrl, struct request *rq,
|
|||
* level FC exchange resource that is also outstanding. This must be
|
||||
* considered in all cleanup operations.
|
||||
*/
|
||||
static int
|
||||
static blk_status_t
|
||||
nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
||||
struct nvme_fc_fcp_op *op, u32 data_len,
|
||||
enum nvmefc_fcp_datadir io_dir)
|
||||
|
|
@ -1902,10 +1890,10 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
|||
* the target device is present
|
||||
*/
|
||||
if (ctrl->rport->remoteport.port_state != FC_OBJSTATE_ONLINE)
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
if (!nvme_fc_ctrl_get(ctrl))
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
/* format the FC-NVME CMD IU and fcp_req */
|
||||
cmdiu->connection_id = cpu_to_be64(queue->connection_id);
|
||||
|
|
@ -1953,8 +1941,9 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
|||
if (ret < 0) {
|
||||
nvme_cleanup_cmd(op->rq);
|
||||
nvme_fc_ctrl_put(ctrl);
|
||||
return (ret == -ENOMEM || ret == -EAGAIN) ?
|
||||
BLK_MQ_RQ_QUEUE_BUSY : BLK_MQ_RQ_QUEUE_ERROR;
|
||||
if (ret == -ENOMEM || ret == -EAGAIN)
|
||||
return BLK_STS_RESOURCE;
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1971,28 +1960,26 @@ nvme_fc_start_fcp_op(struct nvme_fc_ctrl *ctrl, struct nvme_fc_queue *queue,
|
|||
queue->lldd_handle, &op->fcp_req);
|
||||
|
||||
if (ret) {
|
||||
if (op->rq) { /* normal request */
|
||||
if (op->rq) /* normal request */
|
||||
nvme_fc_unmap_data(ctrl, op->rq, op);
|
||||
nvme_cleanup_cmd(op->rq);
|
||||
}
|
||||
/* else - aen. no cleanup needed */
|
||||
|
||||
nvme_fc_ctrl_put(ctrl);
|
||||
|
||||
if (ret != -EBUSY)
|
||||
return BLK_MQ_RQ_QUEUE_ERROR;
|
||||
return BLK_STS_IOERR;
|
||||
|
||||
if (op->rq) {
|
||||
blk_mq_stop_hw_queues(op->rq->q);
|
||||
blk_mq_delay_queue(queue->hctx, NVMEFC_QUEUE_DELAY);
|
||||
}
|
||||
return BLK_MQ_RQ_QUEUE_BUSY;
|
||||
return BLK_STS_RESOURCE;
|
||||
}
|
||||
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
static blk_status_t
|
||||
nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
const struct blk_mq_queue_data *bd)
|
||||
{
|
||||
|
|
@ -2005,7 +1992,7 @@ nvme_fc_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
struct nvme_command *sqe = &cmdiu->sqe;
|
||||
enum nvmefc_fcp_datadir io_dir;
|
||||
u32 data_len;
|
||||
int ret;
|
||||
blk_status_t ret;
|
||||
|
||||
ret = nvme_setup_cmd(ns, rq, sqe);
|
||||
if (ret)
|
||||
|
|
@ -2060,7 +2047,7 @@ nvme_fc_submit_async_event(struct nvme_ctrl *arg, int aer_idx)
|
|||
struct nvme_fc_fcp_op *aen_op;
|
||||
unsigned long flags;
|
||||
bool terminating = false;
|
||||
int ret;
|
||||
blk_status_t ret;
|
||||
|
||||
if (aer_idx > NVME_FC_NR_AEN_COMMANDS)
|
||||
return;
|
||||
|
|
@ -2092,7 +2079,6 @@ __nvme_fc_final_op_cleanup(struct request *rq)
|
|||
op->flags &= ~(FCOP_FLAGS_TERMIO | FCOP_FLAGS_RELEASED |
|
||||
FCOP_FLAGS_COMPLETE);
|
||||
|
||||
nvme_cleanup_cmd(rq);
|
||||
nvme_fc_unmap_data(ctrl, rq, op);
|
||||
nvme_complete_rq(rq);
|
||||
nvme_fc_ctrl_put(ctrl);
|
||||
|
|
@ -2310,7 +2296,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
|
|||
int ret;
|
||||
bool changed;
|
||||
|
||||
++ctrl->ctrl.opts->nr_reconnects;
|
||||
++ctrl->ctrl.nr_reconnects;
|
||||
|
||||
/*
|
||||
* Create the admin queue
|
||||
|
|
@ -2407,7 +2393,7 @@ nvme_fc_create_association(struct nvme_fc_ctrl *ctrl)
|
|||
changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
|
||||
WARN_ON_ONCE(!changed);
|
||||
|
||||
ctrl->ctrl.opts->nr_reconnects = 0;
|
||||
ctrl->ctrl.nr_reconnects = 0;
|
||||
|
||||
if (ctrl->queue_count > 1) {
|
||||
nvme_start_queues(&ctrl->ctrl);
|
||||
|
|
@ -2493,11 +2479,7 @@ nvme_fc_delete_association(struct nvme_fc_ctrl *ctrl)
|
|||
|
||||
/* wait for all io that had to be aborted */
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
while (ctrl->iocnt) {
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
msleep(1000);
|
||||
spin_lock_irqsave(&ctrl->lock, flags);
|
||||
}
|
||||
wait_event_lock_irq(ctrl->ioabort_wait, ctrl->iocnt == 0, ctrl->lock);
|
||||
ctrl->flags &= ~FCCTRL_TERMIO;
|
||||
spin_unlock_irqrestore(&ctrl->lock, flags);
|
||||
|
||||
|
|
@ -2527,7 +2509,7 @@ nvme_fc_delete_ctrl_work(struct work_struct *work)
|
|||
struct nvme_fc_ctrl *ctrl =
|
||||
container_of(work, struct nvme_fc_ctrl, delete_work);
|
||||
|
||||
cancel_work_sync(&ctrl->reset_work);
|
||||
cancel_work_sync(&ctrl->ctrl.reset_work);
|
||||
cancel_delayed_work_sync(&ctrl->connect_work);
|
||||
|
||||
/*
|
||||
|
|
@ -2554,7 +2536,7 @@ __nvme_fc_schedule_delete_work(struct nvme_fc_ctrl *ctrl)
|
|||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING))
|
||||
return true;
|
||||
|
||||
if (!queue_work(nvme_fc_wq, &ctrl->delete_work))
|
||||
if (!queue_work(nvme_wq, &ctrl->delete_work))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
|
@ -2581,7 +2563,7 @@ nvme_fc_del_nvme_ctrl(struct nvme_ctrl *nctrl)
|
|||
ret = __nvme_fc_del_ctrl(ctrl);
|
||||
|
||||
if (!ret)
|
||||
flush_workqueue(nvme_fc_wq);
|
||||
flush_workqueue(nvme_wq);
|
||||
|
||||
nvme_put_ctrl(&ctrl->ctrl);
|
||||
|
||||
|
|
@ -2606,13 +2588,13 @@ nvme_fc_reconnect_or_delete(struct nvme_fc_ctrl *ctrl, int status)
|
|||
dev_info(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: Reconnect attempt in %d seconds.\n",
|
||||
ctrl->cnum, ctrl->ctrl.opts->reconnect_delay);
|
||||
queue_delayed_work(nvme_fc_wq, &ctrl->connect_work,
|
||||
queue_delayed_work(nvme_wq, &ctrl->connect_work,
|
||||
ctrl->ctrl.opts->reconnect_delay * HZ);
|
||||
} else {
|
||||
dev_warn(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: Max reconnect attempts (%d) "
|
||||
"reached. Removing controller\n",
|
||||
ctrl->cnum, ctrl->ctrl.opts->nr_reconnects);
|
||||
ctrl->cnum, ctrl->ctrl.nr_reconnects);
|
||||
WARN_ON(__nvme_fc_schedule_delete_work(ctrl));
|
||||
}
|
||||
}
|
||||
|
|
@ -2621,7 +2603,7 @@ static void
|
|||
nvme_fc_reset_ctrl_work(struct work_struct *work)
|
||||
{
|
||||
struct nvme_fc_ctrl *ctrl =
|
||||
container_of(work, struct nvme_fc_ctrl, reset_work);
|
||||
container_of(work, struct nvme_fc_ctrl, ctrl.reset_work);
|
||||
int ret;
|
||||
|
||||
/* will block will waiting for io to terminate */
|
||||
|
|
@ -2635,29 +2617,6 @@ nvme_fc_reset_ctrl_work(struct work_struct *work)
|
|||
"NVME-FC{%d}: controller reset complete\n", ctrl->cnum);
|
||||
}
|
||||
|
||||
/*
|
||||
* called by the nvme core layer, for sysfs interface that requests
|
||||
* a reset of the nvme controller
|
||||
*/
|
||||
static int
|
||||
nvme_fc_reset_nvme_ctrl(struct nvme_ctrl *nctrl)
|
||||
{
|
||||
struct nvme_fc_ctrl *ctrl = to_fc_ctrl(nctrl);
|
||||
|
||||
dev_info(ctrl->ctrl.device,
|
||||
"NVME-FC{%d}: admin requested controller reset\n", ctrl->cnum);
|
||||
|
||||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING))
|
||||
return -EBUSY;
|
||||
|
||||
if (!queue_work(nvme_fc_wq, &ctrl->reset_work))
|
||||
return -EBUSY;
|
||||
|
||||
flush_work(&ctrl->reset_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
|
||||
.name = "fc",
|
||||
.module = THIS_MODULE,
|
||||
|
|
@ -2665,11 +2624,9 @@ static const struct nvme_ctrl_ops nvme_fc_ctrl_ops = {
|
|||
.reg_read32 = nvmf_reg_read32,
|
||||
.reg_read64 = nvmf_reg_read64,
|
||||
.reg_write32 = nvmf_reg_write32,
|
||||
.reset_ctrl = nvme_fc_reset_nvme_ctrl,
|
||||
.free_ctrl = nvme_fc_nvme_ctrl_freed,
|
||||
.submit_async_event = nvme_fc_submit_async_event,
|
||||
.delete_ctrl = nvme_fc_del_nvme_ctrl,
|
||||
.get_subsysnqn = nvmf_get_subsysnqn,
|
||||
.get_address = nvmf_get_address,
|
||||
};
|
||||
|
||||
|
|
@ -2695,7 +2652,7 @@ nvme_fc_connect_ctrl_work(struct work_struct *work)
|
|||
static const struct blk_mq_ops nvme_fc_admin_mq_ops = {
|
||||
.queue_rq = nvme_fc_queue_rq,
|
||||
.complete = nvme_fc_complete_rq,
|
||||
.init_request = nvme_fc_init_admin_request,
|
||||
.init_request = nvme_fc_init_request,
|
||||
.exit_request = nvme_fc_exit_request,
|
||||
.reinit_request = nvme_fc_reinit_request,
|
||||
.init_hctx = nvme_fc_init_admin_hctx,
|
||||
|
|
@ -2740,7 +2697,7 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
|
|||
kref_init(&ctrl->ref);
|
||||
|
||||
INIT_WORK(&ctrl->delete_work, nvme_fc_delete_ctrl_work);
|
||||
INIT_WORK(&ctrl->reset_work, nvme_fc_reset_ctrl_work);
|
||||
INIT_WORK(&ctrl->ctrl.reset_work, nvme_fc_reset_ctrl_work);
|
||||
INIT_DELAYED_WORK(&ctrl->connect_work, nvme_fc_connect_ctrl_work);
|
||||
spin_lock_init(&ctrl->lock);
|
||||
|
||||
|
|
@ -2807,6 +2764,9 @@ nvme_fc_init_ctrl(struct device *dev, struct nvmf_ctrl_options *opts,
|
|||
nvme_uninit_ctrl(&ctrl->ctrl);
|
||||
nvme_put_ctrl(&ctrl->ctrl);
|
||||
|
||||
/* Remove core ctrl ref. */
|
||||
nvme_put_ctrl(&ctrl->ctrl);
|
||||
|
||||
/* as we're past the point where we transition to the ref
|
||||
* counting teardown path, if we return a bad pointer here,
|
||||
* the calling routine, thinking it's prior to the
|
||||
|
|
@ -2965,20 +2925,7 @@ static struct nvmf_transport_ops nvme_fc_transport = {
|
|||
|
||||
static int __init nvme_fc_init_module(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
nvme_fc_wq = create_workqueue("nvme_fc_wq");
|
||||
if (!nvme_fc_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nvmf_register_transport(&nvme_fc_transport);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
return 0;
|
||||
err:
|
||||
destroy_workqueue(nvme_fc_wq);
|
||||
return ret;
|
||||
return nvmf_register_transport(&nvme_fc_transport);
|
||||
}
|
||||
|
||||
static void __exit nvme_fc_exit_module(void)
|
||||
|
|
@ -2989,8 +2936,6 @@ static void __exit nvme_fc_exit_module(void)
|
|||
|
||||
nvmf_unregister_transport(&nvme_fc_transport);
|
||||
|
||||
destroy_workqueue(nvme_fc_wq);
|
||||
|
||||
ida_destroy(&nvme_fc_local_port_cnt);
|
||||
ida_destroy(&nvme_fc_ctrl_cnt);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -242,7 +242,7 @@ static inline void _nvme_nvm_check_size(void)
|
|||
BUILD_BUG_ON(sizeof(struct nvme_nvm_erase_blk) != 64);
|
||||
BUILD_BUG_ON(sizeof(struct nvme_nvm_id_group) != 960);
|
||||
BUILD_BUG_ON(sizeof(struct nvme_nvm_addr_format) != 16);
|
||||
BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != 4096);
|
||||
BUILD_BUG_ON(sizeof(struct nvme_nvm_id) != NVME_IDENTIFY_DATA_SIZE);
|
||||
BUILD_BUG_ON(sizeof(struct nvme_nvm_bb_tbl) != 64);
|
||||
}
|
||||
|
||||
|
|
@ -480,7 +480,7 @@ static inline void nvme_nvm_rqtocmd(struct nvm_rq *rqd, struct nvme_ns *ns,
|
|||
rqd->bio->bi_iter.bi_sector));
|
||||
}
|
||||
|
||||
static void nvme_nvm_end_io(struct request *rq, int error)
|
||||
static void nvme_nvm_end_io(struct request *rq, blk_status_t status)
|
||||
{
|
||||
struct nvm_rq *rqd = rq->end_io_data;
|
||||
|
||||
|
|
@ -509,7 +509,7 @@ static int nvme_nvm_submit_io(struct nvm_dev *dev, struct nvm_rq *rqd)
|
|||
rq = nvme_alloc_request(q, (struct nvme_command *)cmd, 0, NVME_QID_ANY);
|
||||
if (IS_ERR(rq)) {
|
||||
kfree(cmd);
|
||||
return -ENOMEM;
|
||||
return PTR_ERR(rq);
|
||||
}
|
||||
rq->cmd_flags &= ~REQ_FAILFAST_DRIVER;
|
||||
|
||||
|
|
@ -571,13 +571,6 @@ static struct nvm_dev_ops nvme_nvm_dev_ops = {
|
|||
.max_phys_sect = 64,
|
||||
};
|
||||
|
||||
static void nvme_nvm_end_user_vio(struct request *rq, int error)
|
||||
{
|
||||
struct completion *waiting = rq->end_io_data;
|
||||
|
||||
complete(waiting);
|
||||
}
|
||||
|
||||
static int nvme_nvm_submit_user_cmd(struct request_queue *q,
|
||||
struct nvme_ns *ns,
|
||||
struct nvme_nvm_command *vcmd,
|
||||
|
|
@ -608,7 +601,6 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
|
|||
rq->timeout = timeout ? timeout : ADMIN_TIMEOUT;
|
||||
|
||||
rq->cmd_flags &= ~REQ_FAILFAST_DRIVER;
|
||||
rq->end_io_data = &wait;
|
||||
|
||||
if (ppa_buf && ppa_len) {
|
||||
ppa_list = dma_pool_alloc(dev->dma_pool, GFP_KERNEL, &ppa_dma);
|
||||
|
|
@ -662,9 +654,7 @@ static int nvme_nvm_submit_user_cmd(struct request_queue *q,
|
|||
}
|
||||
|
||||
submit:
|
||||
blk_execute_rq_nowait(q, NULL, rq, 0, nvme_nvm_end_user_vio);
|
||||
|
||||
wait_for_completion_io(&wait);
|
||||
blk_execute_rq(q, NULL, rq, 0);
|
||||
|
||||
if (nvme_req(rq)->flags & NVME_REQ_CANCELLED)
|
||||
ret = -EINTR;
|
||||
|
|
|
|||
|
|
@ -27,12 +27,11 @@ extern unsigned char nvme_io_timeout;
|
|||
extern unsigned char admin_timeout;
|
||||
#define ADMIN_TIMEOUT (admin_timeout * HZ)
|
||||
|
||||
extern unsigned char shutdown_timeout;
|
||||
#define SHUTDOWN_TIMEOUT (shutdown_timeout * HZ)
|
||||
|
||||
#define NVME_DEFAULT_KATO 5
|
||||
#define NVME_KATO_GRACE 10
|
||||
|
||||
extern struct workqueue_struct *nvme_wq;
|
||||
|
||||
enum {
|
||||
NVME_NS_LBA = 0,
|
||||
NVME_NS_LIGHTNVM = 1,
|
||||
|
|
@ -131,6 +130,7 @@ struct nvme_ctrl {
|
|||
struct device *device; /* char device */
|
||||
struct list_head node;
|
||||
struct ida ns_ida;
|
||||
struct work_struct reset_work;
|
||||
|
||||
struct opal_dev *opal_dev;
|
||||
|
||||
|
|
@ -138,6 +138,7 @@ struct nvme_ctrl {
|
|||
char serial[20];
|
||||
char model[40];
|
||||
char firmware_rev[8];
|
||||
char subnqn[NVMF_NQN_SIZE];
|
||||
u16 cntlid;
|
||||
|
||||
u32 ctrl_config;
|
||||
|
|
@ -147,6 +148,8 @@ struct nvme_ctrl {
|
|||
u16 oncs;
|
||||
u16 vid;
|
||||
u16 oacs;
|
||||
u16 nssa;
|
||||
u16 nr_streams;
|
||||
atomic_t abort_limit;
|
||||
u8 event_limit;
|
||||
u8 vwc;
|
||||
|
|
@ -165,6 +168,10 @@ struct nvme_ctrl {
|
|||
|
||||
/* Power saving configuration */
|
||||
u64 ps_max_latency_us;
|
||||
bool apst_enabled;
|
||||
|
||||
u32 hmpre;
|
||||
u32 hmmin;
|
||||
|
||||
/* Fabrics only */
|
||||
u16 sqsize;
|
||||
|
|
@ -172,12 +179,10 @@ struct nvme_ctrl {
|
|||
u32 iorcsz;
|
||||
u16 icdoff;
|
||||
u16 maxcmd;
|
||||
int nr_reconnects;
|
||||
struct nvmf_ctrl_options *opts;
|
||||
};
|
||||
|
||||
/*
|
||||
* An NVM Express namespace is equivalent to a SCSI LUN
|
||||
*/
|
||||
struct nvme_ns {
|
||||
struct list_head list;
|
||||
|
||||
|
|
@ -189,14 +194,18 @@ struct nvme_ns {
|
|||
int instance;
|
||||
|
||||
u8 eui[8];
|
||||
u8 uuid[16];
|
||||
u8 nguid[16];
|
||||
uuid_t uuid;
|
||||
|
||||
unsigned ns_id;
|
||||
int lba_shift;
|
||||
u16 ms;
|
||||
u16 sgs;
|
||||
u32 sws;
|
||||
bool ext;
|
||||
u8 pi_type;
|
||||
unsigned long flags;
|
||||
u16 noiob;
|
||||
|
||||
#define NVME_NS_REMOVING 0
|
||||
#define NVME_NS_DEAD 1
|
||||
|
|
@ -214,11 +223,9 @@ struct nvme_ctrl_ops {
|
|||
int (*reg_read32)(struct nvme_ctrl *ctrl, u32 off, u32 *val);
|
||||
int (*reg_write32)(struct nvme_ctrl *ctrl, u32 off, u32 val);
|
||||
int (*reg_read64)(struct nvme_ctrl *ctrl, u32 off, u64 *val);
|
||||
int (*reset_ctrl)(struct nvme_ctrl *ctrl);
|
||||
void (*free_ctrl)(struct nvme_ctrl *ctrl);
|
||||
void (*submit_async_event)(struct nvme_ctrl *ctrl, int aer_idx);
|
||||
int (*delete_ctrl)(struct nvme_ctrl *ctrl);
|
||||
const char *(*get_subsysnqn)(struct nvme_ctrl *ctrl);
|
||||
int (*get_address)(struct nvme_ctrl *ctrl, char *buf, int size);
|
||||
};
|
||||
|
||||
|
|
@ -296,7 +303,7 @@ void nvme_start_freeze(struct nvme_ctrl *ctrl);
|
|||
#define NVME_QID_ANY -1
|
||||
struct request *nvme_alloc_request(struct request_queue *q,
|
||||
struct nvme_command *cmd, unsigned int flags, int qid);
|
||||
int nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
|
||||
blk_status_t nvme_setup_cmd(struct nvme_ns *ns, struct request *req,
|
||||
struct nvme_command *cmd);
|
||||
int nvme_submit_sync_cmd(struct request_queue *q, struct nvme_command *cmd,
|
||||
void *buf, unsigned bufflen);
|
||||
|
|
@ -310,23 +317,10 @@ int __nvme_submit_user_cmd(struct request_queue *q, struct nvme_command *cmd,
|
|||
void __user *ubuffer, unsigned bufflen,
|
||||
void __user *meta_buffer, unsigned meta_len, u32 meta_seed,
|
||||
u32 *result, unsigned timeout);
|
||||
int nvme_identify_ctrl(struct nvme_ctrl *dev, struct nvme_id_ctrl **id);
|
||||
int nvme_identify_ns(struct nvme_ctrl *dev, unsigned nsid,
|
||||
struct nvme_id_ns **id);
|
||||
int nvme_get_log_page(struct nvme_ctrl *dev, struct nvme_smart_log **log);
|
||||
int nvme_get_features(struct nvme_ctrl *dev, unsigned fid, unsigned nsid,
|
||||
void *buffer, size_t buflen, u32 *result);
|
||||
int nvme_set_features(struct nvme_ctrl *dev, unsigned fid, unsigned dword11,
|
||||
void *buffer, size_t buflen, u32 *result);
|
||||
int nvme_set_queue_count(struct nvme_ctrl *ctrl, int *count);
|
||||
void nvme_start_keep_alive(struct nvme_ctrl *ctrl);
|
||||
void nvme_stop_keep_alive(struct nvme_ctrl *ctrl);
|
||||
|
||||
struct sg_io_hdr;
|
||||
|
||||
int nvme_sg_io(struct nvme_ns *ns, struct sg_io_hdr __user *u_hdr);
|
||||
int nvme_sg_io32(struct nvme_ns *ns, unsigned long arg);
|
||||
int nvme_sg_get_version_num(int __user *ip);
|
||||
int nvme_reset_ctrl(struct nvme_ctrl *ctrl);
|
||||
|
||||
#ifdef CONFIG_NVM
|
||||
int nvme_nvm_ns_supported(struct nvme_ns *ns, struct nvme_id_ns *id);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -48,7 +48,7 @@
|
|||
*/
|
||||
#define NVME_RDMA_NR_AEN_COMMANDS 1
|
||||
#define NVME_RDMA_AQ_BLKMQ_DEPTH \
|
||||
(NVMF_AQ_DEPTH - NVME_RDMA_NR_AEN_COMMANDS)
|
||||
(NVME_AQ_DEPTH - NVME_RDMA_NR_AEN_COMMANDS)
|
||||
|
||||
struct nvme_rdma_device {
|
||||
struct ib_device *dev;
|
||||
|
|
@ -80,10 +80,8 @@ struct nvme_rdma_request {
|
|||
};
|
||||
|
||||
enum nvme_rdma_queue_flags {
|
||||
NVME_RDMA_Q_CONNECTED = (1 << 0),
|
||||
NVME_RDMA_IB_QUEUE_ALLOCATED = (1 << 1),
|
||||
NVME_RDMA_Q_DELETING = (1 << 2),
|
||||
NVME_RDMA_Q_LIVE = (1 << 3),
|
||||
NVME_RDMA_Q_LIVE = 0,
|
||||
NVME_RDMA_Q_DELETING = 1,
|
||||
};
|
||||
|
||||
struct nvme_rdma_queue {
|
||||
|
|
@ -103,9 +101,6 @@ struct nvme_rdma_queue {
|
|||
};
|
||||
|
||||
struct nvme_rdma_ctrl {
|
||||
/* read and written in the hot path */
|
||||
spinlock_t lock;
|
||||
|
||||
/* read only in the hot path */
|
||||
struct nvme_rdma_queue *queues;
|
||||
u32 queue_count;
|
||||
|
|
@ -113,7 +108,6 @@ struct nvme_rdma_ctrl {
|
|||
/* other member variables */
|
||||
struct blk_mq_tag_set tag_set;
|
||||
struct work_struct delete_work;
|
||||
struct work_struct reset_work;
|
||||
struct work_struct err_work;
|
||||
|
||||
struct nvme_rdma_qe async_event_sqe;
|
||||
|
|
@ -145,8 +139,6 @@ static DEFINE_MUTEX(device_list_mutex);
|
|||
static LIST_HEAD(nvme_rdma_ctrl_list);
|
||||
static DEFINE_MUTEX(nvme_rdma_ctrl_mutex);
|
||||
|
||||
static struct workqueue_struct *nvme_rdma_wq;
|
||||
|
||||
/*
|
||||
* Disabling this option makes small I/O goes faster, but is fundamentally
|
||||
* unsafe. With it turned off we will have to register a global rkey that
|
||||
|
|
@ -301,10 +293,12 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void __nvme_rdma_exit_request(struct nvme_rdma_ctrl *ctrl,
|
||||
struct request *rq, unsigned int queue_idx)
|
||||
static void nvme_rdma_exit_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx)
|
||||
{
|
||||
struct nvme_rdma_ctrl *ctrl = set->driver_data;
|
||||
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
|
||||
int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
|
||||
struct nvme_rdma_queue *queue = &ctrl->queues[queue_idx];
|
||||
struct nvme_rdma_device *dev = queue->device;
|
||||
|
||||
|
|
@ -315,22 +309,13 @@ static void __nvme_rdma_exit_request(struct nvme_rdma_ctrl *ctrl,
|
|||
DMA_TO_DEVICE);
|
||||
}
|
||||
|
||||
static void nvme_rdma_exit_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx)
|
||||
{
|
||||
return __nvme_rdma_exit_request(set->driver_data, rq, hctx_idx + 1);
|
||||
}
|
||||
|
||||
static void nvme_rdma_exit_admin_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx)
|
||||
{
|
||||
return __nvme_rdma_exit_request(set->driver_data, rq, 0);
|
||||
}
|
||||
|
||||
static int __nvme_rdma_init_request(struct nvme_rdma_ctrl *ctrl,
|
||||
struct request *rq, unsigned int queue_idx)
|
||||
static int nvme_rdma_init_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx,
|
||||
unsigned int numa_node)
|
||||
{
|
||||
struct nvme_rdma_ctrl *ctrl = set->driver_data;
|
||||
struct nvme_rdma_request *req = blk_mq_rq_to_pdu(rq);
|
||||
int queue_idx = (set == &ctrl->tag_set) ? hctx_idx + 1 : 0;
|
||||
struct nvme_rdma_queue *queue = &ctrl->queues[queue_idx];
|
||||
struct nvme_rdma_device *dev = queue->device;
|
||||
struct ib_device *ibdev = dev->dev;
|
||||
|
|
@ -358,20 +343,6 @@ out_free_qe:
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int nvme_rdma_init_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx,
|
||||
unsigned int numa_node)
|
||||
{
|
||||
return __nvme_rdma_init_request(set->driver_data, rq, hctx_idx + 1);
|
||||
}
|
||||
|
||||
static int nvme_rdma_init_admin_request(struct blk_mq_tag_set *set,
|
||||
struct request *rq, unsigned int hctx_idx,
|
||||
unsigned int numa_node)
|
||||
{
|
||||
return __nvme_rdma_init_request(set->driver_data, rq, 0);
|
||||
}
|
||||
|
||||
static int nvme_rdma_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
|
||||
unsigned int hctx_idx)
|
||||
{
|
||||
|
|
@ -469,9 +440,6 @@ static void nvme_rdma_destroy_queue_ib(struct nvme_rdma_queue *queue)
|
|||
struct nvme_rdma_device *dev;
|
||||
struct ib_device *ibdev;
|
||||
|
||||
if (!test_and_clear_bit(NVME_RDMA_IB_QUEUE_ALLOCATED, &queue->flags))
|
||||
return;
|
||||
|
||||
dev = queue->device;
|
||||
ibdev = dev->dev;
|
||||
rdma_destroy_qp(queue->cm_id);
|
||||
|
|
@ -483,17 +451,21 @@ static void nvme_rdma_destroy_queue_ib(struct nvme_rdma_queue *queue)
|
|||
nvme_rdma_dev_put(dev);
|
||||
}
|
||||
|
||||
static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue,
|
||||
struct nvme_rdma_device *dev)
|
||||
static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue)
|
||||
{
|
||||
struct ib_device *ibdev = dev->dev;
|
||||
struct ib_device *ibdev;
|
||||
const int send_wr_factor = 3; /* MR, SEND, INV */
|
||||
const int cq_factor = send_wr_factor + 1; /* + RECV */
|
||||
int comp_vector, idx = nvme_rdma_queue_idx(queue);
|
||||
|
||||
int ret;
|
||||
|
||||
queue->device = dev;
|
||||
queue->device = nvme_rdma_find_get_device(queue->cm_id);
|
||||
if (!queue->device) {
|
||||
dev_err(queue->cm_id->device->dev.parent,
|
||||
"no client data found!\n");
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
ibdev = queue->device->dev;
|
||||
|
||||
/*
|
||||
* The admin queue is barely used once the controller is live, so don't
|
||||
|
|
@ -506,12 +478,12 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue,
|
|||
|
||||
|
||||
/* +1 for ib_stop_cq */
|
||||
queue->ib_cq = ib_alloc_cq(dev->dev, queue,
|
||||
cq_factor * queue->queue_size + 1, comp_vector,
|
||||
IB_POLL_SOFTIRQ);
|
||||
queue->ib_cq = ib_alloc_cq(ibdev, queue,
|
||||
cq_factor * queue->queue_size + 1,
|
||||
comp_vector, IB_POLL_SOFTIRQ);
|
||||
if (IS_ERR(queue->ib_cq)) {
|
||||
ret = PTR_ERR(queue->ib_cq);
|
||||
goto out;
|
||||
goto out_put_dev;
|
||||
}
|
||||
|
||||
ret = nvme_rdma_create_qp(queue, send_wr_factor);
|
||||
|
|
@ -524,7 +496,6 @@ static int nvme_rdma_create_queue_ib(struct nvme_rdma_queue *queue,
|
|||
ret = -ENOMEM;
|
||||
goto out_destroy_qp;
|
||||
}
|
||||
set_bit(NVME_RDMA_IB_QUEUE_ALLOCATED, &queue->flags);
|
||||
|
||||
return 0;
|
||||
|
||||
|
|
@ -532,7 +503,8 @@ out_destroy_qp:
|
|||
ib_destroy_qp(queue->qp);
|
||||
out_destroy_ib_cq:
|
||||
ib_free_cq(queue->ib_cq);
|
||||
out:
|
||||
out_put_dev:
|
||||
nvme_rdma_dev_put(queue->device);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -583,12 +555,10 @@ static int nvme_rdma_init_queue(struct nvme_rdma_ctrl *ctrl,
|
|||
}
|
||||
|
||||
clear_bit(NVME_RDMA_Q_DELETING, &queue->flags);
|
||||
set_bit(NVME_RDMA_Q_CONNECTED, &queue->flags);
|
||||
|
||||
return 0;
|
||||
|
||||
out_destroy_cm_id:
|
||||
nvme_rdma_destroy_queue_ib(queue);
|
||||
rdma_destroy_id(queue->cm_id);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -718,11 +688,11 @@ static void nvme_rdma_reconnect_or_remove(struct nvme_rdma_ctrl *ctrl)
|
|||
if (nvmf_should_reconnect(&ctrl->ctrl)) {
|
||||
dev_info(ctrl->ctrl.device, "Reconnecting in %d seconds...\n",
|
||||
ctrl->ctrl.opts->reconnect_delay);
|
||||
queue_delayed_work(nvme_rdma_wq, &ctrl->reconnect_work,
|
||||
queue_delayed_work(nvme_wq, &ctrl->reconnect_work,
|
||||
ctrl->ctrl.opts->reconnect_delay * HZ);
|
||||
} else {
|
||||
dev_info(ctrl->ctrl.device, "Removing controller...\n");
|
||||
queue_work(nvme_rdma_wq, &ctrl->delete_work);
|
||||
queue_work(nvme_wq, &ctrl->delete_work);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -733,7 +703,7 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
|
|||
bool changed;
|
||||
int ret;
|
||||
|
||||
++ctrl->ctrl.opts->nr_reconnects;
|
||||
++ctrl->ctrl.nr_reconnects;
|
||||
|
||||
if (ctrl->queue_count > 1) {
|
||||
nvme_rdma_free_io_queues(ctrl);
|
||||
|
|
@ -749,7 +719,7 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
|
|||
if (ret)
|
||||
goto requeue;
|
||||
|
||||
ret = nvme_rdma_init_queue(ctrl, 0, NVMF_AQ_DEPTH);
|
||||
ret = nvme_rdma_init_queue(ctrl, 0, NVME_AQ_DEPTH);
|
||||
if (ret)
|
||||
goto requeue;
|
||||
|
||||
|
|
@ -777,7 +747,7 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
|
|||
|
||||
changed = nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_LIVE);
|
||||
WARN_ON_ONCE(!changed);
|
||||
ctrl->ctrl.opts->nr_reconnects = 0;
|
||||
ctrl->ctrl.nr_reconnects = 0;
|
||||
|
||||
if (ctrl->queue_count > 1) {
|
||||
nvme_queue_scan(&ctrl->ctrl);
|
||||
|
|
@ -790,7 +760,7 @@ static void nvme_rdma_reconnect_ctrl_work(struct work_struct *work)
|
|||
|
||||
requeue:
|
||||
dev_info(ctrl->ctrl.device, "Failed reconnect attempt %d\n",
|
||||
ctrl->ctrl.opts->nr_reconnects);
|
||||
ctrl->ctrl.nr_reconnects);
|
||||
nvme_rdma_reconnect_or_remove(ctrl);
|
||||
}
|
||||
|
||||
|
|
@ -802,10 +772,8 @@ static void nvme_rdma_error_recovery_work(struct work_struct *work)
|
|||
|
||||
nvme_stop_keep_alive(&ctrl->ctrl);
|
||||
|
||||
for (i = 0; i < ctrl->queue_count; i++) {
|
||||
clear_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[i].flags);
|
||||
for (i = 0; i < ctrl->queue_count; i++)
|
||||
clear_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[i].flags);
|
||||
}
|
||||
|
||||
if (ctrl->queue_count > 1)
|
||||
nvme_stop_queues(&ctrl->ctrl);
|
||||
|
|
@ -833,7 +801,7 @@ static void nvme_rdma_error_recovery(struct nvme_rdma_ctrl *ctrl)
|
|||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RECONNECTING))
|
||||
return;
|
||||
|
||||
queue_work(nvme_rdma_wq, &ctrl->err_work);
|
||||
queue_work(nvme_wq, &ctrl->err_work);
|
||||
}
|
||||
|
||||
static void nvme_rdma_wr_error(struct ib_cq *cq, struct ib_wc *wc,
|
||||
|
|
@ -1278,21 +1246,11 @@ static int nvme_rdma_conn_rejected(struct nvme_rdma_queue *queue,
|
|||
|
||||
static int nvme_rdma_addr_resolved(struct nvme_rdma_queue *queue)
|
||||
{
|
||||
struct nvme_rdma_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = nvme_rdma_find_get_device(queue->cm_id);
|
||||
if (!dev) {
|
||||
dev_err(queue->cm_id->device->dev.parent,
|
||||
"no client data found!\n");
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
ret = nvme_rdma_create_queue_ib(queue, dev);
|
||||
if (ret) {
|
||||
nvme_rdma_dev_put(dev);
|
||||
goto out;
|
||||
}
|
||||
ret = nvme_rdma_create_queue_ib(queue);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = rdma_resolve_route(queue->cm_id, NVME_RDMA_CONNECT_TIMEOUT_MS);
|
||||
if (ret) {
|
||||
|
|
@ -1306,7 +1264,6 @@ static int nvme_rdma_addr_resolved(struct nvme_rdma_queue *queue)
|
|||
|
||||
out_destroy_queue:
|
||||
nvme_rdma_destroy_queue_ib(queue);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -1334,8 +1291,8 @@ static int nvme_rdma_route_resolved(struct nvme_rdma_queue *queue)
|
|||
* specified by the Fabrics standard.
|
||||
*/
|
||||
if (priv.qid == 0) {
|
||||
priv.hrqsize = cpu_to_le16(NVMF_AQ_DEPTH);
|
||||
priv.hsqsize = cpu_to_le16(NVMF_AQ_DEPTH - 1);
|
||||
priv.hrqsize = cpu_to_le16(NVME_AQ_DEPTH);
|
||||
priv.hsqsize = cpu_to_le16(NVME_AQ_DEPTH - 1);
|
||||
} else {
|
||||
/*
|
||||
* current interpretation of the fabrics spec
|
||||
|
|
@ -1383,12 +1340,14 @@ static int nvme_rdma_cm_handler(struct rdma_cm_id *cm_id,
|
|||
complete(&queue->cm_done);
|
||||
return 0;
|
||||
case RDMA_CM_EVENT_REJECTED:
|
||||
nvme_rdma_destroy_queue_ib(queue);
|
||||
cm_error = nvme_rdma_conn_rejected(queue, ev);
|
||||
break;
|
||||
case RDMA_CM_EVENT_ADDR_ERROR:
|
||||
case RDMA_CM_EVENT_ROUTE_ERROR:
|
||||
case RDMA_CM_EVENT_CONNECT_ERROR:
|
||||
case RDMA_CM_EVENT_UNREACHABLE:
|
||||
nvme_rdma_destroy_queue_ib(queue);
|
||||
case RDMA_CM_EVENT_ADDR_ERROR:
|
||||
dev_dbg(queue->ctrl->ctrl.device,
|
||||
"CM error event %d\n", ev->event);
|
||||
cm_error = -ECONNRESET;
|
||||
|
|
@ -1435,8 +1394,8 @@ nvme_rdma_timeout(struct request *rq, bool reserved)
|
|||
/*
|
||||
* We cannot accept any other command until the Connect command has completed.
|
||||
*/
|
||||
static inline int nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
|
||||
struct request *rq)
|
||||
static inline blk_status_t
|
||||
nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue, struct request *rq)
|
||||
{
|
||||
if (unlikely(!test_bit(NVME_RDMA_Q_LIVE, &queue->flags))) {
|
||||
struct nvme_command *cmd = nvme_req(rq)->cmd;
|
||||
|
|
@ -1452,16 +1411,15 @@ static inline int nvme_rdma_queue_is_ready(struct nvme_rdma_queue *queue,
|
|||
* failover.
|
||||
*/
|
||||
if (queue->ctrl->ctrl.state == NVME_CTRL_RECONNECTING)
|
||||
return -EIO;
|
||||
else
|
||||
return -EAGAIN;
|
||||
return BLK_STS_IOERR;
|
||||
return BLK_STS_RESOURCE; /* try again later */
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
static blk_status_t nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
const struct blk_mq_queue_data *bd)
|
||||
{
|
||||
struct nvme_ns *ns = hctx->queue->queuedata;
|
||||
|
|
@ -1472,28 +1430,29 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
struct nvme_command *c = sqe->data;
|
||||
bool flush = false;
|
||||
struct ib_device *dev;
|
||||
int ret;
|
||||
blk_status_t ret;
|
||||
int err;
|
||||
|
||||
WARN_ON_ONCE(rq->tag < 0);
|
||||
|
||||
ret = nvme_rdma_queue_is_ready(queue, rq);
|
||||
if (unlikely(ret))
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
dev = queue->device->dev;
|
||||
ib_dma_sync_single_for_cpu(dev, sqe->dma,
|
||||
sizeof(struct nvme_command), DMA_TO_DEVICE);
|
||||
|
||||
ret = nvme_setup_cmd(ns, rq, c);
|
||||
if (ret != BLK_MQ_RQ_QUEUE_OK)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
blk_mq_start_request(rq);
|
||||
|
||||
ret = nvme_rdma_map_data(queue, rq, c);
|
||||
if (ret < 0) {
|
||||
err = nvme_rdma_map_data(queue, rq, c);
|
||||
if (err < 0) {
|
||||
dev_err(queue->ctrl->ctrl.device,
|
||||
"Failed to map data (%d)\n", ret);
|
||||
"Failed to map data (%d)\n", err);
|
||||
nvme_cleanup_cmd(rq);
|
||||
goto err;
|
||||
}
|
||||
|
|
@ -1503,17 +1462,18 @@ static int nvme_rdma_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
|
||||
if (req_op(rq) == REQ_OP_FLUSH)
|
||||
flush = true;
|
||||
ret = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
|
||||
err = nvme_rdma_post_send(queue, sqe, req->sge, req->num_sge,
|
||||
req->mr->need_inval ? &req->reg_wr.wr : NULL, flush);
|
||||
if (ret) {
|
||||
if (err) {
|
||||
nvme_rdma_unmap_data(queue, rq);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
return BLK_STS_OK;
|
||||
err:
|
||||
return (ret == -ENOMEM || ret == -EAGAIN) ?
|
||||
BLK_MQ_RQ_QUEUE_BUSY : BLK_MQ_RQ_QUEUE_ERROR;
|
||||
if (err == -ENOMEM || err == -EAGAIN)
|
||||
return BLK_STS_RESOURCE;
|
||||
return BLK_STS_IOERR;
|
||||
}
|
||||
|
||||
static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
|
||||
|
|
@ -1523,7 +1483,6 @@ static int nvme_rdma_poll(struct blk_mq_hw_ctx *hctx, unsigned int tag)
|
|||
struct ib_wc wc;
|
||||
int found = 0;
|
||||
|
||||
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
|
||||
while (ib_poll_cq(cq, 1, &wc) > 0) {
|
||||
struct ib_cqe *cqe = wc.wr_cqe;
|
||||
|
||||
|
|
@ -1560,8 +1519,8 @@ static const struct blk_mq_ops nvme_rdma_mq_ops = {
|
|||
static const struct blk_mq_ops nvme_rdma_admin_mq_ops = {
|
||||
.queue_rq = nvme_rdma_queue_rq,
|
||||
.complete = nvme_rdma_complete_rq,
|
||||
.init_request = nvme_rdma_init_admin_request,
|
||||
.exit_request = nvme_rdma_exit_admin_request,
|
||||
.init_request = nvme_rdma_init_request,
|
||||
.exit_request = nvme_rdma_exit_request,
|
||||
.reinit_request = nvme_rdma_reinit_request,
|
||||
.init_hctx = nvme_rdma_init_admin_hctx,
|
||||
.timeout = nvme_rdma_timeout,
|
||||
|
|
@ -1571,7 +1530,7 @@ static int nvme_rdma_configure_admin_queue(struct nvme_rdma_ctrl *ctrl)
|
|||
{
|
||||
int error;
|
||||
|
||||
error = nvme_rdma_init_queue(ctrl, 0, NVMF_AQ_DEPTH);
|
||||
error = nvme_rdma_init_queue(ctrl, 0, NVME_AQ_DEPTH);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
|
|
@ -1672,7 +1631,7 @@ static void nvme_rdma_shutdown_ctrl(struct nvme_rdma_ctrl *ctrl)
|
|||
nvme_rdma_free_io_queues(ctrl);
|
||||
}
|
||||
|
||||
if (test_bit(NVME_RDMA_Q_CONNECTED, &ctrl->queues[0].flags))
|
||||
if (test_bit(NVME_RDMA_Q_LIVE, &ctrl->queues[0].flags))
|
||||
nvme_shutdown_ctrl(&ctrl->ctrl);
|
||||
|
||||
blk_mq_stop_hw_queues(ctrl->ctrl.admin_q);
|
||||
|
|
@ -1709,7 +1668,7 @@ static int __nvme_rdma_del_ctrl(struct nvme_rdma_ctrl *ctrl)
|
|||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING))
|
||||
return -EBUSY;
|
||||
|
||||
if (!queue_work(nvme_rdma_wq, &ctrl->delete_work))
|
||||
if (!queue_work(nvme_wq, &ctrl->delete_work))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
|
|
@ -1743,8 +1702,8 @@ static void nvme_rdma_remove_ctrl_work(struct work_struct *work)
|
|||
|
||||
static void nvme_rdma_reset_ctrl_work(struct work_struct *work)
|
||||
{
|
||||
struct nvme_rdma_ctrl *ctrl = container_of(work,
|
||||
struct nvme_rdma_ctrl, reset_work);
|
||||
struct nvme_rdma_ctrl *ctrl =
|
||||
container_of(work, struct nvme_rdma_ctrl, ctrl.reset_work);
|
||||
int ret;
|
||||
bool changed;
|
||||
|
||||
|
|
@ -1785,22 +1744,7 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work)
|
|||
del_dead_ctrl:
|
||||
/* Deleting this dead controller... */
|
||||
dev_warn(ctrl->ctrl.device, "Removing after reset failure\n");
|
||||
WARN_ON(!queue_work(nvme_rdma_wq, &ctrl->delete_work));
|
||||
}
|
||||
|
||||
static int nvme_rdma_reset_ctrl(struct nvme_ctrl *nctrl)
|
||||
{
|
||||
struct nvme_rdma_ctrl *ctrl = to_rdma_ctrl(nctrl);
|
||||
|
||||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING))
|
||||
return -EBUSY;
|
||||
|
||||
if (!queue_work(nvme_rdma_wq, &ctrl->reset_work))
|
||||
return -EBUSY;
|
||||
|
||||
flush_work(&ctrl->reset_work);
|
||||
|
||||
return 0;
|
||||
WARN_ON(!queue_work(nvme_wq, &ctrl->delete_work));
|
||||
}
|
||||
|
||||
static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
|
||||
|
|
@ -1810,11 +1754,9 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
|
|||
.reg_read32 = nvmf_reg_read32,
|
||||
.reg_read64 = nvmf_reg_read64,
|
||||
.reg_write32 = nvmf_reg_write32,
|
||||
.reset_ctrl = nvme_rdma_reset_ctrl,
|
||||
.free_ctrl = nvme_rdma_free_ctrl,
|
||||
.submit_async_event = nvme_rdma_submit_async_event,
|
||||
.delete_ctrl = nvme_rdma_del_ctrl,
|
||||
.get_subsysnqn = nvmf_get_subsysnqn,
|
||||
.get_address = nvmf_get_address,
|
||||
};
|
||||
|
||||
|
|
@ -1919,8 +1861,7 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
|
|||
nvme_rdma_reconnect_ctrl_work);
|
||||
INIT_WORK(&ctrl->err_work, nvme_rdma_error_recovery_work);
|
||||
INIT_WORK(&ctrl->delete_work, nvme_rdma_del_ctrl_work);
|
||||
INIT_WORK(&ctrl->reset_work, nvme_rdma_reset_ctrl_work);
|
||||
spin_lock_init(&ctrl->lock);
|
||||
INIT_WORK(&ctrl->ctrl.reset_work, nvme_rdma_reset_ctrl_work);
|
||||
|
||||
ctrl->queue_count = opts->nr_io_queues + 1; /* +1 for admin queue */
|
||||
ctrl->ctrl.sqsize = opts->queue_size - 1;
|
||||
|
|
@ -1939,12 +1880,14 @@ static struct nvme_ctrl *nvme_rdma_create_ctrl(struct device *dev,
|
|||
/* sanity check icdoff */
|
||||
if (ctrl->ctrl.icdoff) {
|
||||
dev_err(ctrl->ctrl.device, "icdoff is not supported!\n");
|
||||
ret = -EINVAL;
|
||||
goto out_remove_admin_queue;
|
||||
}
|
||||
|
||||
/* sanity check keyed sgls */
|
||||
if (!(ctrl->ctrl.sgls & (1 << 20))) {
|
||||
dev_err(ctrl->ctrl.device, "Mandatory keyed sgls are not support\n");
|
||||
ret = -EINVAL;
|
||||
goto out_remove_admin_queue;
|
||||
}
|
||||
|
||||
|
|
@ -2033,7 +1976,7 @@ static void nvme_rdma_remove_one(struct ib_device *ib_device, void *client_data)
|
|||
}
|
||||
mutex_unlock(&nvme_rdma_ctrl_mutex);
|
||||
|
||||
flush_workqueue(nvme_rdma_wq);
|
||||
flush_workqueue(nvme_wq);
|
||||
}
|
||||
|
||||
static struct ib_client nvme_rdma_ib_client = {
|
||||
|
|
@ -2046,13 +1989,9 @@ static int __init nvme_rdma_init_module(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
nvme_rdma_wq = create_workqueue("nvme_rdma_wq");
|
||||
if (!nvme_rdma_wq)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = ib_register_client(&nvme_rdma_ib_client);
|
||||
if (ret)
|
||||
goto err_destroy_wq;
|
||||
return ret;
|
||||
|
||||
ret = nvmf_register_transport(&nvme_rdma_transport);
|
||||
if (ret)
|
||||
|
|
@ -2062,8 +2001,6 @@ static int __init nvme_rdma_init_module(void)
|
|||
|
||||
err_unreg_client:
|
||||
ib_unregister_client(&nvme_rdma_ib_client);
|
||||
err_destroy_wq:
|
||||
destroy_workqueue(nvme_rdma_wq);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -2071,7 +2008,6 @@ static void __exit nvme_rdma_cleanup_module(void)
|
|||
{
|
||||
nvmf_unregister_transport(&nvme_rdma_transport);
|
||||
ib_unregister_client(&nvme_rdma_ib_client);
|
||||
destroy_workqueue(nvme_rdma_wq);
|
||||
}
|
||||
|
||||
module_init(nvme_rdma_init_module);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -336,7 +336,7 @@ out:
|
|||
|
||||
static void nvmet_execute_identify_nslist(struct nvmet_req *req)
|
||||
{
|
||||
static const int buf_size = 4096;
|
||||
static const int buf_size = NVME_IDENTIFY_DATA_SIZE;
|
||||
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
||||
struct nvmet_ns *ns;
|
||||
u32 min_nsid = le32_to_cpu(req->cmd->identify.nsid);
|
||||
|
|
@ -367,6 +367,64 @@ out:
|
|||
nvmet_req_complete(req, status);
|
||||
}
|
||||
|
||||
static u16 nvmet_copy_ns_identifier(struct nvmet_req *req, u8 type, u8 len,
|
||||
void *id, off_t *off)
|
||||
{
|
||||
struct nvme_ns_id_desc desc = {
|
||||
.nidt = type,
|
||||
.nidl = len,
|
||||
};
|
||||
u16 status;
|
||||
|
||||
status = nvmet_copy_to_sgl(req, *off, &desc, sizeof(desc));
|
||||
if (status)
|
||||
return status;
|
||||
*off += sizeof(desc);
|
||||
|
||||
status = nvmet_copy_to_sgl(req, *off, id, len);
|
||||
if (status)
|
||||
return status;
|
||||
*off += len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nvmet_execute_identify_desclist(struct nvmet_req *req)
|
||||
{
|
||||
struct nvmet_ns *ns;
|
||||
u16 status = 0;
|
||||
off_t off = 0;
|
||||
|
||||
ns = nvmet_find_namespace(req->sq->ctrl, req->cmd->identify.nsid);
|
||||
if (!ns) {
|
||||
status = NVME_SC_INVALID_NS | NVME_SC_DNR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (memchr_inv(&ns->uuid, 0, sizeof(ns->uuid))) {
|
||||
status = nvmet_copy_ns_identifier(req, NVME_NIDT_UUID,
|
||||
NVME_NIDT_UUID_LEN,
|
||||
&ns->uuid, &off);
|
||||
if (status)
|
||||
goto out_put_ns;
|
||||
}
|
||||
if (memchr_inv(ns->nguid, 0, sizeof(ns->nguid))) {
|
||||
status = nvmet_copy_ns_identifier(req, NVME_NIDT_NGUID,
|
||||
NVME_NIDT_NGUID_LEN,
|
||||
&ns->nguid, &off);
|
||||
if (status)
|
||||
goto out_put_ns;
|
||||
}
|
||||
|
||||
if (sg_zero_buffer(req->sg, req->sg_cnt, NVME_IDENTIFY_DATA_SIZE - off,
|
||||
off) != NVME_IDENTIFY_DATA_SIZE - off)
|
||||
status = NVME_SC_INTERNAL | NVME_SC_DNR;
|
||||
out_put_ns:
|
||||
nvmet_put_namespace(ns);
|
||||
out:
|
||||
nvmet_req_complete(req, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* A "mimimum viable" abort implementation: the command is mandatory in the
|
||||
* spec, but we are not required to do any useful work. We couldn't really
|
||||
|
|
@ -504,7 +562,7 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
|
|||
}
|
||||
break;
|
||||
case nvme_admin_identify:
|
||||
req->data_len = 4096;
|
||||
req->data_len = NVME_IDENTIFY_DATA_SIZE;
|
||||
switch (cmd->identify.cns) {
|
||||
case NVME_ID_CNS_NS:
|
||||
req->execute = nvmet_execute_identify_ns;
|
||||
|
|
@ -515,6 +573,9 @@ u16 nvmet_parse_admin_cmd(struct nvmet_req *req)
|
|||
case NVME_ID_CNS_NS_ACTIVE_LIST:
|
||||
req->execute = nvmet_execute_identify_nslist;
|
||||
return 0;
|
||||
case NVME_ID_CNS_NS_DESC_LIST:
|
||||
req->execute = nvmet_execute_identify_desclist;
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case nvme_admin_abort_cmd:
|
||||
|
|
|
|||
|
|
@ -305,11 +305,41 @@ out_unlock:
|
|||
|
||||
CONFIGFS_ATTR(nvmet_ns_, device_path);
|
||||
|
||||
static ssize_t nvmet_ns_device_uuid_show(struct config_item *item, char *page)
|
||||
{
|
||||
return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->uuid);
|
||||
}
|
||||
|
||||
static ssize_t nvmet_ns_device_uuid_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
struct nvmet_ns *ns = to_nvmet_ns(item);
|
||||
struct nvmet_subsys *subsys = ns->subsys;
|
||||
int ret = 0;
|
||||
|
||||
|
||||
mutex_lock(&subsys->lock);
|
||||
if (ns->enabled) {
|
||||
ret = -EBUSY;
|
||||
goto out_unlock;
|
||||
}
|
||||
|
||||
|
||||
if (uuid_parse(page, &ns->uuid))
|
||||
ret = -EINVAL;
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&subsys->lock);
|
||||
return ret ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t nvmet_ns_device_nguid_show(struct config_item *item, char *page)
|
||||
{
|
||||
return sprintf(page, "%pUb\n", &to_nvmet_ns(item)->nguid);
|
||||
}
|
||||
|
||||
CONFIGFS_ATTR(nvmet_ns_, device_uuid);
|
||||
|
||||
static ssize_t nvmet_ns_device_nguid_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
|
|
@ -379,6 +409,7 @@ CONFIGFS_ATTR(nvmet_ns_, enable);
|
|||
static struct configfs_attribute *nvmet_ns_attrs[] = {
|
||||
&nvmet_ns_attr_device_path,
|
||||
&nvmet_ns_attr_device_nguid,
|
||||
&nvmet_ns_attr_device_uuid,
|
||||
&nvmet_ns_attr_enable,
|
||||
NULL,
|
||||
};
|
||||
|
|
@ -619,8 +650,45 @@ out_unlock:
|
|||
|
||||
CONFIGFS_ATTR(nvmet_subsys_, attr_allow_any_host);
|
||||
|
||||
static ssize_t nvmet_subsys_version_show(struct config_item *item,
|
||||
char *page)
|
||||
{
|
||||
struct nvmet_subsys *subsys = to_subsys(item);
|
||||
|
||||
if (NVME_TERTIARY(subsys->ver))
|
||||
return snprintf(page, PAGE_SIZE, "%d.%d.%d\n",
|
||||
(int)NVME_MAJOR(subsys->ver),
|
||||
(int)NVME_MINOR(subsys->ver),
|
||||
(int)NVME_TERTIARY(subsys->ver));
|
||||
else
|
||||
return snprintf(page, PAGE_SIZE, "%d.%d\n",
|
||||
(int)NVME_MAJOR(subsys->ver),
|
||||
(int)NVME_MINOR(subsys->ver));
|
||||
}
|
||||
|
||||
static ssize_t nvmet_subsys_version_store(struct config_item *item,
|
||||
const char *page, size_t count)
|
||||
{
|
||||
struct nvmet_subsys *subsys = to_subsys(item);
|
||||
int major, minor, tertiary = 0;
|
||||
int ret;
|
||||
|
||||
|
||||
ret = sscanf(page, "%d.%d.%d\n", &major, &minor, &tertiary);
|
||||
if (ret != 2 && ret != 3)
|
||||
return -EINVAL;
|
||||
|
||||
down_write(&nvmet_config_sem);
|
||||
subsys->ver = NVME_VS(major, minor, tertiary);
|
||||
up_write(&nvmet_config_sem);
|
||||
|
||||
return count;
|
||||
}
|
||||
CONFIGFS_ATTR(nvmet_subsys_, version);
|
||||
|
||||
static struct configfs_attribute *nvmet_subsys_attrs[] = {
|
||||
&nvmet_subsys_attr_attr_allow_any_host,
|
||||
&nvmet_subsys_attr_version,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -380,6 +380,7 @@ struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid)
|
|||
|
||||
ns->nsid = nsid;
|
||||
ns->subsys = subsys;
|
||||
uuid_gen(&ns->uuid);
|
||||
|
||||
return ns;
|
||||
}
|
||||
|
|
@ -926,7 +927,7 @@ struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
|
|||
if (!subsys)
|
||||
return NULL;
|
||||
|
||||
subsys->ver = NVME_VS(1, 2, 1); /* NVMe 1.2.1 */
|
||||
subsys->ver = NVME_VS(1, 3, 0); /* NVMe 1.3.0 */
|
||||
|
||||
switch (type) {
|
||||
case NVME_NQN_NVME:
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ static void nvmet_format_discovery_entry(struct nvmf_disc_rsp_page_hdr *hdr,
|
|||
e->portid = port->disc_addr.portid;
|
||||
/* we support only dynamic controllers */
|
||||
e->cntlid = cpu_to_le16(NVME_CNTLID_DYNAMIC);
|
||||
e->asqsz = cpu_to_le16(NVMF_AQ_DEPTH);
|
||||
e->asqsz = cpu_to_le16(NVME_AQ_DEPTH);
|
||||
e->subtype = type;
|
||||
memcpy(e->trsvcid, port->disc_addr.trsvcid, NVMF_TRSVCID_SIZE);
|
||||
memcpy(e->traddr, port->disc_addr.traddr, NVMF_TRADDR_SIZE);
|
||||
|
|
@ -185,7 +185,7 @@ u16 nvmet_parse_discovery_cmd(struct nvmet_req *req)
|
|||
return NVME_SC_INVALID_OPCODE | NVME_SC_DNR;
|
||||
}
|
||||
case nvme_admin_identify:
|
||||
req->data_len = 4096;
|
||||
req->data_len = NVME_IDENTIFY_DATA_SIZE;
|
||||
switch (cmd->identify.cns) {
|
||||
case NVME_ID_CNS_CTRL:
|
||||
req->execute =
|
||||
|
|
|
|||
|
|
@ -2096,20 +2096,22 @@ nvmet_fc_handle_fcp_rqst(struct nvmet_fc_tgtport *tgtport,
|
|||
/* clear any response payload */
|
||||
memset(&fod->rspiubuf, 0, sizeof(fod->rspiubuf));
|
||||
|
||||
fod->data_sg = NULL;
|
||||
fod->data_sg_cnt = 0;
|
||||
|
||||
ret = nvmet_req_init(&fod->req,
|
||||
&fod->queue->nvme_cq,
|
||||
&fod->queue->nvme_sq,
|
||||
&nvmet_fc_tgt_fcp_ops);
|
||||
if (!ret) { /* bad SQE content or invalid ctrl state */
|
||||
nvmet_fc_abort_op(tgtport, fod);
|
||||
if (!ret) {
|
||||
/* bad SQE content or invalid ctrl state */
|
||||
/* nvmet layer has already called op done to send rsp. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* keep a running counter of tail position */
|
||||
atomic_inc(&fod->queue->sqtail);
|
||||
|
||||
fod->data_sg = NULL;
|
||||
fod->data_sg_cnt = 0;
|
||||
if (fod->total_length) {
|
||||
ret = nvmet_fc_alloc_tgt_pgs(fod);
|
||||
if (ret) {
|
||||
|
|
|
|||
|
|
@ -569,7 +569,6 @@ fcloop_tgt_fcp_abort(struct nvmet_fc_target_port *tgtport,
|
|||
struct nvmefc_tgt_fcp_req *tgt_fcpreq)
|
||||
{
|
||||
struct fcloop_fcpreq *tfcp_req = tgt_fcp_req_to_fcpreq(tgt_fcpreq);
|
||||
int active;
|
||||
|
||||
/*
|
||||
* mark aborted only in case there were 2 threads in transport
|
||||
|
|
@ -577,7 +576,6 @@ fcloop_tgt_fcp_abort(struct nvmet_fc_target_port *tgtport,
|
|||
* after the abort request
|
||||
*/
|
||||
spin_lock(&tfcp_req->reqlock);
|
||||
active = tfcp_req->active;
|
||||
tfcp_req->aborted = true;
|
||||
spin_unlock(&tfcp_req->reqlock);
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ static void nvmet_bio_done(struct bio *bio)
|
|||
struct nvmet_req *req = bio->bi_private;
|
||||
|
||||
nvmet_req_complete(req,
|
||||
bio->bi_error ? NVME_SC_INTERNAL | NVME_SC_DNR : 0);
|
||||
bio->bi_status ? NVME_SC_INTERNAL | NVME_SC_DNR : 0);
|
||||
|
||||
if (bio != &req->inline_bio)
|
||||
bio_put(bio);
|
||||
|
|
@ -145,7 +145,7 @@ static void nvmet_execute_discard(struct nvmet_req *req)
|
|||
bio->bi_private = req;
|
||||
bio->bi_end_io = nvmet_bio_done;
|
||||
if (status) {
|
||||
bio->bi_error = -EIO;
|
||||
bio->bi_status = BLK_STS_IOERR;
|
||||
bio_endio(bio);
|
||||
} else {
|
||||
submit_bio(bio);
|
||||
|
|
|
|||
|
|
@ -21,8 +21,6 @@
|
|||
#include "../host/nvme.h"
|
||||
#include "../host/fabrics.h"
|
||||
|
||||
#define NVME_LOOP_AQ_DEPTH 256
|
||||
|
||||
#define NVME_LOOP_MAX_SEGMENTS 256
|
||||
|
||||
/*
|
||||
|
|
@ -31,7 +29,7 @@
|
|||
*/
|
||||
#define NVME_LOOP_NR_AEN_COMMANDS 1
|
||||
#define NVME_LOOP_AQ_BLKMQ_DEPTH \
|
||||
(NVME_LOOP_AQ_DEPTH - NVME_LOOP_NR_AEN_COMMANDS)
|
||||
(NVME_AQ_DEPTH - NVME_LOOP_NR_AEN_COMMANDS)
|
||||
|
||||
struct nvme_loop_iod {
|
||||
struct nvme_request nvme_req;
|
||||
|
|
@ -45,7 +43,6 @@ struct nvme_loop_iod {
|
|||
};
|
||||
|
||||
struct nvme_loop_ctrl {
|
||||
spinlock_t lock;
|
||||
struct nvme_loop_queue *queues;
|
||||
u32 queue_count;
|
||||
|
||||
|
|
@ -59,7 +56,6 @@ struct nvme_loop_ctrl {
|
|||
|
||||
struct nvmet_ctrl *target_ctrl;
|
||||
struct work_struct delete_work;
|
||||
struct work_struct reset_work;
|
||||
};
|
||||
|
||||
static inline struct nvme_loop_ctrl *to_loop_ctrl(struct nvme_ctrl *ctrl)
|
||||
|
|
@ -151,7 +147,7 @@ nvme_loop_timeout(struct request *rq, bool reserved)
|
|||
struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(rq);
|
||||
|
||||
/* queue error recovery */
|
||||
schedule_work(&iod->queue->ctrl->reset_work);
|
||||
nvme_reset_ctrl(&iod->queue->ctrl->ctrl);
|
||||
|
||||
/* fail with DNR on admin cmd timeout */
|
||||
nvme_req(rq)->status = NVME_SC_ABORT_REQ | NVME_SC_DNR;
|
||||
|
|
@ -159,17 +155,17 @@ nvme_loop_timeout(struct request *rq, bool reserved)
|
|||
return BLK_EH_HANDLED;
|
||||
}
|
||||
|
||||
static int nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
static blk_status_t nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
||||
const struct blk_mq_queue_data *bd)
|
||||
{
|
||||
struct nvme_ns *ns = hctx->queue->queuedata;
|
||||
struct nvme_loop_queue *queue = hctx->driver_data;
|
||||
struct request *req = bd->rq;
|
||||
struct nvme_loop_iod *iod = blk_mq_rq_to_pdu(req);
|
||||
int ret;
|
||||
blk_status_t ret;
|
||||
|
||||
ret = nvme_setup_cmd(ns, req, &iod->cmd);
|
||||
if (ret != BLK_MQ_RQ_QUEUE_OK)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
iod->cmd.common.flags |= NVME_CMD_SGL_METABUF;
|
||||
|
|
@ -179,16 +175,15 @@ static int nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
nvme_cleanup_cmd(req);
|
||||
blk_mq_start_request(req);
|
||||
nvme_loop_queue_response(&iod->req);
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
if (blk_rq_bytes(req)) {
|
||||
iod->sg_table.sgl = iod->first_sgl;
|
||||
ret = sg_alloc_table_chained(&iod->sg_table,
|
||||
if (sg_alloc_table_chained(&iod->sg_table,
|
||||
blk_rq_nr_phys_segments(req),
|
||||
iod->sg_table.sgl);
|
||||
if (ret)
|
||||
return BLK_MQ_RQ_QUEUE_BUSY;
|
||||
iod->sg_table.sgl))
|
||||
return BLK_STS_RESOURCE;
|
||||
|
||||
iod->req.sg = iod->sg_table.sgl;
|
||||
iod->req.sg_cnt = blk_rq_map_sg(req->q, req, iod->sg_table.sgl);
|
||||
|
|
@ -197,7 +192,7 @@ static int nvme_loop_queue_rq(struct blk_mq_hw_ctx *hctx,
|
|||
blk_mq_start_request(req);
|
||||
|
||||
schedule_work(&iod->work);
|
||||
return BLK_MQ_RQ_QUEUE_OK;
|
||||
return BLK_STS_OK;
|
||||
}
|
||||
|
||||
static void nvme_loop_submit_async_event(struct nvme_ctrl *arg, int aer_idx)
|
||||
|
|
@ -234,15 +229,10 @@ static int nvme_loop_init_request(struct blk_mq_tag_set *set,
|
|||
struct request *req, unsigned int hctx_idx,
|
||||
unsigned int numa_node)
|
||||
{
|
||||
return nvme_loop_init_iod(set->driver_data, blk_mq_rq_to_pdu(req),
|
||||
hctx_idx + 1);
|
||||
}
|
||||
struct nvme_loop_ctrl *ctrl = set->driver_data;
|
||||
|
||||
static int nvme_loop_init_admin_request(struct blk_mq_tag_set *set,
|
||||
struct request *req, unsigned int hctx_idx,
|
||||
unsigned int numa_node)
|
||||
{
|
||||
return nvme_loop_init_iod(set->driver_data, blk_mq_rq_to_pdu(req), 0);
|
||||
return nvme_loop_init_iod(ctrl, blk_mq_rq_to_pdu(req),
|
||||
(set == &ctrl->tag_set) ? hctx_idx + 1 : 0);
|
||||
}
|
||||
|
||||
static int nvme_loop_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
|
||||
|
|
@ -280,7 +270,7 @@ static const struct blk_mq_ops nvme_loop_mq_ops = {
|
|||
static const struct blk_mq_ops nvme_loop_admin_mq_ops = {
|
||||
.queue_rq = nvme_loop_queue_rq,
|
||||
.complete = nvme_loop_complete_rq,
|
||||
.init_request = nvme_loop_init_admin_request,
|
||||
.init_request = nvme_loop_init_request,
|
||||
.init_hctx = nvme_loop_init_admin_hctx,
|
||||
.timeout = nvme_loop_timeout,
|
||||
};
|
||||
|
|
@ -467,7 +457,7 @@ static int __nvme_loop_del_ctrl(struct nvme_loop_ctrl *ctrl)
|
|||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_DELETING))
|
||||
return -EBUSY;
|
||||
|
||||
if (!schedule_work(&ctrl->delete_work))
|
||||
if (!queue_work(nvme_wq, &ctrl->delete_work))
|
||||
return -EBUSY;
|
||||
|
||||
return 0;
|
||||
|
|
@ -501,8 +491,8 @@ static void nvme_loop_delete_ctrl(struct nvmet_ctrl *nctrl)
|
|||
|
||||
static void nvme_loop_reset_ctrl_work(struct work_struct *work)
|
||||
{
|
||||
struct nvme_loop_ctrl *ctrl = container_of(work,
|
||||
struct nvme_loop_ctrl, reset_work);
|
||||
struct nvme_loop_ctrl *ctrl =
|
||||
container_of(work, struct nvme_loop_ctrl, ctrl.reset_work);
|
||||
bool changed;
|
||||
int ret;
|
||||
|
||||
|
|
@ -540,21 +530,6 @@ out_disable:
|
|||
nvme_put_ctrl(&ctrl->ctrl);
|
||||
}
|
||||
|
||||
static int nvme_loop_reset_ctrl(struct nvme_ctrl *nctrl)
|
||||
{
|
||||
struct nvme_loop_ctrl *ctrl = to_loop_ctrl(nctrl);
|
||||
|
||||
if (!nvme_change_ctrl_state(&ctrl->ctrl, NVME_CTRL_RESETTING))
|
||||
return -EBUSY;
|
||||
|
||||
if (!schedule_work(&ctrl->reset_work))
|
||||
return -EBUSY;
|
||||
|
||||
flush_work(&ctrl->reset_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
|
||||
.name = "loop",
|
||||
.module = THIS_MODULE,
|
||||
|
|
@ -562,11 +537,9 @@ static const struct nvme_ctrl_ops nvme_loop_ctrl_ops = {
|
|||
.reg_read32 = nvmf_reg_read32,
|
||||
.reg_read64 = nvmf_reg_read64,
|
||||
.reg_write32 = nvmf_reg_write32,
|
||||
.reset_ctrl = nvme_loop_reset_ctrl,
|
||||
.free_ctrl = nvme_loop_free_ctrl,
|
||||
.submit_async_event = nvme_loop_submit_async_event,
|
||||
.delete_ctrl = nvme_loop_del_ctrl,
|
||||
.get_subsysnqn = nvmf_get_subsysnqn,
|
||||
};
|
||||
|
||||
static int nvme_loop_create_io_queues(struct nvme_loop_ctrl *ctrl)
|
||||
|
|
@ -629,15 +602,13 @@ static struct nvme_ctrl *nvme_loop_create_ctrl(struct device *dev,
|
|||
INIT_LIST_HEAD(&ctrl->list);
|
||||
|
||||
INIT_WORK(&ctrl->delete_work, nvme_loop_del_ctrl_work);
|
||||
INIT_WORK(&ctrl->reset_work, nvme_loop_reset_ctrl_work);
|
||||
INIT_WORK(&ctrl->ctrl.reset_work, nvme_loop_reset_ctrl_work);
|
||||
|
||||
ret = nvme_init_ctrl(&ctrl->ctrl, dev, &nvme_loop_ctrl_ops,
|
||||
0 /* no quirks, we're perfect! */);
|
||||
if (ret)
|
||||
goto out_put_ctrl;
|
||||
|
||||
spin_lock_init(&ctrl->lock);
|
||||
|
||||
ret = -ENOMEM;
|
||||
|
||||
ctrl->ctrl.sqsize = opts->queue_size - 1;
|
||||
|
|
@ -766,7 +737,7 @@ static void __exit nvme_loop_cleanup_module(void)
|
|||
__nvme_loop_del_ctrl(ctrl);
|
||||
mutex_unlock(&nvme_loop_ctrl_mutex);
|
||||
|
||||
flush_scheduled_work();
|
||||
flush_workqueue(nvme_wq);
|
||||
}
|
||||
|
||||
module_init(nvme_loop_init_module);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ struct nvmet_ns {
|
|||
u32 blksize_shift;
|
||||
loff_t size;
|
||||
u8 nguid[16];
|
||||
uuid_t uuid;
|
||||
|
||||
bool enabled;
|
||||
struct nvmet_subsys *subsys;
|
||||
|
|
|
|||
|
|
@ -1027,7 +1027,7 @@ nvmet_rdma_parse_cm_connect_req(struct rdma_conn_param *conn,
|
|||
queue->recv_queue_size = le16_to_cpu(req->hsqsize) + 1;
|
||||
queue->send_queue_size = le16_to_cpu(req->hrqsize);
|
||||
|
||||
if (!queue->host_qid && queue->recv_queue_size > NVMF_AQ_DEPTH)
|
||||
if (!queue->host_qid && queue->recv_queue_size > NVME_AQ_DEPTH)
|
||||
return NVME_RDMA_CM_INVALID_HSQSIZE;
|
||||
|
||||
/* XXX: Should we enforce some kind of max for IO queues? */
|
||||
|
|
@ -1307,53 +1307,44 @@ static void nvmet_rdma_queue_connect_fail(struct rdma_cm_id *cm_id,
|
|||
|
||||
/**
|
||||
* nvme_rdma_device_removal() - Handle RDMA device removal
|
||||
* @cm_id: rdma_cm id, used for nvmet port
|
||||
* @queue: nvmet rdma queue (cm id qp_context)
|
||||
* @addr: nvmet address (cm_id context)
|
||||
*
|
||||
* DEVICE_REMOVAL event notifies us that the RDMA device is about
|
||||
* to unplug so we should take care of destroying our RDMA resources.
|
||||
* This event will be generated for each allocated cm_id.
|
||||
* to unplug. Note that this event can be generated on a normal
|
||||
* queue cm_id and/or a device bound listener cm_id (where in this
|
||||
* case queue will be null).
|
||||
*
|
||||
* Note that this event can be generated on a normal queue cm_id
|
||||
* and/or a device bound listener cm_id (where in this case
|
||||
* queue will be null).
|
||||
*
|
||||
* we claim ownership on destroying the cm_id. For queues we move
|
||||
* the queue state to NVMET_RDMA_IN_DEVICE_REMOVAL and for port
|
||||
* We registered an ib_client to handle device removal for queues,
|
||||
* so we only need to handle the listening port cm_ids. In this case
|
||||
* we nullify the priv to prevent double cm_id destruction and destroying
|
||||
* the cm_id implicitely by returning a non-zero rc to the callout.
|
||||
*/
|
||||
static int nvmet_rdma_device_removal(struct rdma_cm_id *cm_id,
|
||||
struct nvmet_rdma_queue *queue)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (!queue) {
|
||||
struct nvmet_port *port = cm_id->context;
|
||||
struct nvmet_port *port;
|
||||
|
||||
if (queue) {
|
||||
/*
|
||||
* This is a listener cm_id. Make sure that
|
||||
* future remove_port won't invoke a double
|
||||
* cm_id destroy. use atomic xchg to make sure
|
||||
* we don't compete with remove_port.
|
||||
* This is a queue cm_id. we have registered
|
||||
* an ib_client to handle queues removal
|
||||
* so don't interfear and just return.
|
||||
*/
|
||||
if (xchg(&port->priv, NULL) != cm_id)
|
||||
return 0;
|
||||
} else {
|
||||
/*
|
||||
* This is a queue cm_id. Make sure that
|
||||
* release queue will not destroy the cm_id
|
||||
* and schedule all ctrl queues removal (only
|
||||
* if the queue is not disconnecting already).
|
||||
*/
|
||||
spin_lock_irqsave(&queue->state_lock, flags);
|
||||
if (queue->state != NVMET_RDMA_Q_DISCONNECTING)
|
||||
queue->state = NVMET_RDMA_IN_DEVICE_REMOVAL;
|
||||
spin_unlock_irqrestore(&queue->state_lock, flags);
|
||||
nvmet_rdma_queue_disconnect(queue);
|
||||
flush_scheduled_work();
|
||||
return 0;
|
||||
}
|
||||
|
||||
port = cm_id->context;
|
||||
|
||||
/*
|
||||
* This is a listener cm_id. Make sure that
|
||||
* future remove_port won't invoke a double
|
||||
* cm_id destroy. use atomic xchg to make sure
|
||||
* we don't compete with remove_port.
|
||||
*/
|
||||
if (xchg(&port->priv, NULL) != cm_id)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* We need to return 1 so that the core will destroy
|
||||
* it's own ID. What a great API design..
|
||||
|
|
@ -1519,9 +1510,51 @@ static struct nvmet_fabrics_ops nvmet_rdma_ops = {
|
|||
.delete_ctrl = nvmet_rdma_delete_ctrl,
|
||||
};
|
||||
|
||||
static void nvmet_rdma_add_one(struct ib_device *ib_device)
|
||||
{
|
||||
}
|
||||
|
||||
static void nvmet_rdma_remove_one(struct ib_device *ib_device, void *client_data)
|
||||
{
|
||||
struct nvmet_rdma_queue *queue;
|
||||
|
||||
/* Device is being removed, delete all queues using this device */
|
||||
mutex_lock(&nvmet_rdma_queue_mutex);
|
||||
list_for_each_entry(queue, &nvmet_rdma_queue_list, queue_list) {
|
||||
if (queue->dev->device != ib_device)
|
||||
continue;
|
||||
|
||||
pr_info("Removing queue %d\n", queue->idx);
|
||||
__nvmet_rdma_queue_disconnect(queue);
|
||||
}
|
||||
mutex_unlock(&nvmet_rdma_queue_mutex);
|
||||
|
||||
flush_scheduled_work();
|
||||
}
|
||||
|
||||
static struct ib_client nvmet_rdma_ib_client = {
|
||||
.name = "nvmet_rdma",
|
||||
.add = nvmet_rdma_add_one,
|
||||
.remove = nvmet_rdma_remove_one
|
||||
};
|
||||
|
||||
static int __init nvmet_rdma_init(void)
|
||||
{
|
||||
return nvmet_register_transport(&nvmet_rdma_ops);
|
||||
int ret;
|
||||
|
||||
ret = ib_register_client(&nvmet_rdma_ib_client);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = nvmet_register_transport(&nvmet_rdma_ops);
|
||||
if (ret)
|
||||
goto err_ib_client;
|
||||
|
||||
return 0;
|
||||
|
||||
err_ib_client:
|
||||
ib_unregister_client(&nvmet_rdma_ib_client);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit nvmet_rdma_exit(void)
|
||||
|
|
@ -1544,6 +1577,7 @@ static void __exit nvmet_rdma_exit(void)
|
|||
mutex_unlock(&nvmet_rdma_queue_mutex);
|
||||
|
||||
flush_scheduled_work();
|
||||
ib_unregister_client(&nvmet_rdma_ib_client);
|
||||
ida_destroy(&nvmet_rdma_queue_ida);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue