162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common code for the NVMe target. 462306a36Sopenharmony_ci * Copyright (c) 2015-2016 HGST, a Western Digital Company. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/random.h> 962306a36Sopenharmony_ci#include <linux/rculist.h> 1062306a36Sopenharmony_ci#include <linux/pci-p2pdma.h> 1162306a36Sopenharmony_ci#include <linux/scatterlist.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <generated/utsrelease.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#define CREATE_TRACE_POINTS 1662306a36Sopenharmony_ci#include "trace.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "nvmet.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistruct kmem_cache *nvmet_bvec_cache; 2162306a36Sopenharmony_cistruct workqueue_struct *buffered_io_wq; 2262306a36Sopenharmony_cistruct workqueue_struct *zbd_wq; 2362306a36Sopenharmony_cistatic const struct nvmet_fabrics_ops *nvmet_transports[NVMF_TRTYPE_MAX]; 2462306a36Sopenharmony_cistatic DEFINE_IDA(cntlid_ida); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistruct workqueue_struct *nvmet_wq; 2762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_wq); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * This read/write semaphore is used to synchronize access to configuration 3162306a36Sopenharmony_ci * information on a target system that will result in discovery log page 3262306a36Sopenharmony_ci * information change for at least one host. 3362306a36Sopenharmony_ci * The full list of resources to protected by this semaphore is: 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * - subsystems list 3662306a36Sopenharmony_ci * - per-subsystem allowed hosts list 3762306a36Sopenharmony_ci * - allow_any_host subsystem attribute 3862306a36Sopenharmony_ci * - nvmet_genctr 3962306a36Sopenharmony_ci * - the nvmet_transports array 4062306a36Sopenharmony_ci * 4162306a36Sopenharmony_ci * When updating any of those lists/structures write lock should be obtained, 4262306a36Sopenharmony_ci * while when reading (popolating discovery log page or checking host-subsystem 4362306a36Sopenharmony_ci * link) read lock is obtained to allow concurrent reads. 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ciDECLARE_RWSEM(nvmet_config_sem); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ciu32 nvmet_ana_group_enabled[NVMET_MAX_ANAGRPS + 1]; 4862306a36Sopenharmony_ciu64 nvmet_ana_chgcnt; 4962306a36Sopenharmony_ciDECLARE_RWSEM(nvmet_ana_sem); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ciinline u16 errno_to_nvme_status(struct nvmet_req *req, int errno) 5262306a36Sopenharmony_ci{ 5362306a36Sopenharmony_ci switch (errno) { 5462306a36Sopenharmony_ci case 0: 5562306a36Sopenharmony_ci return NVME_SC_SUCCESS; 5662306a36Sopenharmony_ci case -ENOSPC: 5762306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_rw_command, length); 5862306a36Sopenharmony_ci return NVME_SC_CAP_EXCEEDED | NVME_SC_DNR; 5962306a36Sopenharmony_ci case -EREMOTEIO: 6062306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_rw_command, slba); 6162306a36Sopenharmony_ci return NVME_SC_LBA_RANGE | NVME_SC_DNR; 6262306a36Sopenharmony_ci case -EOPNOTSUPP: 6362306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, opcode); 6462306a36Sopenharmony_ci switch (req->cmd->common.opcode) { 6562306a36Sopenharmony_ci case nvme_cmd_dsm: 6662306a36Sopenharmony_ci case nvme_cmd_write_zeroes: 6762306a36Sopenharmony_ci return NVME_SC_ONCS_NOT_SUPPORTED | NVME_SC_DNR; 6862306a36Sopenharmony_ci default: 6962306a36Sopenharmony_ci return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci break; 7262306a36Sopenharmony_ci case -ENODATA: 7362306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_rw_command, nsid); 7462306a36Sopenharmony_ci return NVME_SC_ACCESS_DENIED; 7562306a36Sopenharmony_ci case -EIO: 7662306a36Sopenharmony_ci fallthrough; 7762306a36Sopenharmony_ci default: 7862306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, opcode); 7962306a36Sopenharmony_ci return NVME_SC_INTERNAL | NVME_SC_DNR; 8062306a36Sopenharmony_ci } 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ciu16 nvmet_report_invalid_opcode(struct nvmet_req *req) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci pr_debug("unhandled cmd %d on qid %d\n", req->cmd->common.opcode, 8662306a36Sopenharmony_ci req->sq->qid); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, opcode); 8962306a36Sopenharmony_ci return NVME_SC_INVALID_OPCODE | NVME_SC_DNR; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistatic struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port, 9362306a36Sopenharmony_ci const char *subsysnqn); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ciu16 nvmet_copy_to_sgl(struct nvmet_req *req, off_t off, const void *buf, 9662306a36Sopenharmony_ci size_t len) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci if (sg_pcopy_from_buffer(req->sg, req->sg_cnt, buf, len, off) != len) { 9962306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 10062306a36Sopenharmony_ci return NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR; 10162306a36Sopenharmony_ci } 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ciu16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf, size_t len) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci if (sg_pcopy_to_buffer(req->sg, req->sg_cnt, buf, len, off) != len) { 10862306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 10962306a36Sopenharmony_ci return NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci return 0; 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ciu16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len) 11562306a36Sopenharmony_ci{ 11662306a36Sopenharmony_ci if (sg_zero_buffer(req->sg, req->sg_cnt, len, off) != len) { 11762306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 11862306a36Sopenharmony_ci return NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci return 0; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic u32 nvmet_max_nsid(struct nvmet_subsys *subsys) 12462306a36Sopenharmony_ci{ 12562306a36Sopenharmony_ci struct nvmet_ns *cur; 12662306a36Sopenharmony_ci unsigned long idx; 12762306a36Sopenharmony_ci u32 nsid = 0; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci xa_for_each(&subsys->namespaces, idx, cur) 13062306a36Sopenharmony_ci nsid = cur->nsid; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci return nsid; 13362306a36Sopenharmony_ci} 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic u32 nvmet_async_event_result(struct nvmet_async_event *aen) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci return aen->event_type | (aen->event_info << 8) | (aen->log_page << 16); 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic void nvmet_async_events_failall(struct nvmet_ctrl *ctrl) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct nvmet_req *req; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 14562306a36Sopenharmony_ci while (ctrl->nr_async_event_cmds) { 14662306a36Sopenharmony_ci req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; 14762306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 14862306a36Sopenharmony_ci nvmet_req_complete(req, NVME_SC_INTERNAL | NVME_SC_DNR); 14962306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic void nvmet_async_events_process(struct nvmet_ctrl *ctrl) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct nvmet_async_event *aen; 15762306a36Sopenharmony_ci struct nvmet_req *req; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 16062306a36Sopenharmony_ci while (ctrl->nr_async_event_cmds && !list_empty(&ctrl->async_events)) { 16162306a36Sopenharmony_ci aen = list_first_entry(&ctrl->async_events, 16262306a36Sopenharmony_ci struct nvmet_async_event, entry); 16362306a36Sopenharmony_ci req = ctrl->async_event_cmds[--ctrl->nr_async_event_cmds]; 16462306a36Sopenharmony_ci nvmet_set_result(req, nvmet_async_event_result(aen)); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci list_del(&aen->entry); 16762306a36Sopenharmony_ci kfree(aen); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 17062306a36Sopenharmony_ci trace_nvmet_async_event(ctrl, req->cqe->result.u32); 17162306a36Sopenharmony_ci nvmet_req_complete(req, 0); 17262306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistatic void nvmet_async_events_free(struct nvmet_ctrl *ctrl) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci struct nvmet_async_event *aen, *tmp; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 18262306a36Sopenharmony_ci list_for_each_entry_safe(aen, tmp, &ctrl->async_events, entry) { 18362306a36Sopenharmony_ci list_del(&aen->entry); 18462306a36Sopenharmony_ci kfree(aen); 18562306a36Sopenharmony_ci } 18662306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic void nvmet_async_event_work(struct work_struct *work) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = 19262306a36Sopenharmony_ci container_of(work, struct nvmet_ctrl, async_event_work); 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci nvmet_async_events_process(ctrl); 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_civoid nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type, 19862306a36Sopenharmony_ci u8 event_info, u8 log_page) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci struct nvmet_async_event *aen; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci aen = kmalloc(sizeof(*aen), GFP_KERNEL); 20362306a36Sopenharmony_ci if (!aen) 20462306a36Sopenharmony_ci return; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci aen->event_type = event_type; 20762306a36Sopenharmony_ci aen->event_info = event_info; 20862306a36Sopenharmony_ci aen->log_page = log_page; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 21162306a36Sopenharmony_ci list_add_tail(&aen->entry, &ctrl->async_events); 21262306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci queue_work(nvmet_wq, &ctrl->async_event_work); 21562306a36Sopenharmony_ci} 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void nvmet_add_to_changed_ns_log(struct nvmet_ctrl *ctrl, __le32 nsid) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci u32 i; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 22262306a36Sopenharmony_ci if (ctrl->nr_changed_ns > NVME_MAX_CHANGED_NAMESPACES) 22362306a36Sopenharmony_ci goto out_unlock; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci for (i = 0; i < ctrl->nr_changed_ns; i++) { 22662306a36Sopenharmony_ci if (ctrl->changed_ns_list[i] == nsid) 22762306a36Sopenharmony_ci goto out_unlock; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci if (ctrl->nr_changed_ns == NVME_MAX_CHANGED_NAMESPACES) { 23162306a36Sopenharmony_ci ctrl->changed_ns_list[0] = cpu_to_le32(0xffffffff); 23262306a36Sopenharmony_ci ctrl->nr_changed_ns = U32_MAX; 23362306a36Sopenharmony_ci goto out_unlock; 23462306a36Sopenharmony_ci } 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci ctrl->changed_ns_list[ctrl->nr_changed_ns++] = nsid; 23762306a36Sopenharmony_ciout_unlock: 23862306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_civoid nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci lockdep_assert_held(&subsys->lock); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { 24862306a36Sopenharmony_ci nvmet_add_to_changed_ns_log(ctrl, cpu_to_le32(nsid)); 24962306a36Sopenharmony_ci if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_NS_ATTR)) 25062306a36Sopenharmony_ci continue; 25162306a36Sopenharmony_ci nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 25262306a36Sopenharmony_ci NVME_AER_NOTICE_NS_CHANGED, 25362306a36Sopenharmony_ci NVME_LOG_CHANGED_NS); 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_civoid nvmet_send_ana_event(struct nvmet_subsys *subsys, 25862306a36Sopenharmony_ci struct nvmet_port *port) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci mutex_lock(&subsys->lock); 26362306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { 26462306a36Sopenharmony_ci if (port && ctrl->port != port) 26562306a36Sopenharmony_ci continue; 26662306a36Sopenharmony_ci if (nvmet_aen_bit_disabled(ctrl, NVME_AEN_BIT_ANA_CHANGE)) 26762306a36Sopenharmony_ci continue; 26862306a36Sopenharmony_ci nvmet_add_async_event(ctrl, NVME_AER_TYPE_NOTICE, 26962306a36Sopenharmony_ci NVME_AER_NOTICE_ANA, NVME_LOG_ANA); 27062306a36Sopenharmony_ci } 27162306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 27262306a36Sopenharmony_ci} 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_civoid nvmet_port_send_ana_event(struct nvmet_port *port) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct nvmet_subsys_link *p; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci down_read(&nvmet_config_sem); 27962306a36Sopenharmony_ci list_for_each_entry(p, &port->subsystems, entry) 28062306a36Sopenharmony_ci nvmet_send_ana_event(p->subsys, port); 28162306a36Sopenharmony_ci up_read(&nvmet_config_sem); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciint nvmet_register_transport(const struct nvmet_fabrics_ops *ops) 28562306a36Sopenharmony_ci{ 28662306a36Sopenharmony_ci int ret = 0; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci down_write(&nvmet_config_sem); 28962306a36Sopenharmony_ci if (nvmet_transports[ops->type]) 29062306a36Sopenharmony_ci ret = -EINVAL; 29162306a36Sopenharmony_ci else 29262306a36Sopenharmony_ci nvmet_transports[ops->type] = ops; 29362306a36Sopenharmony_ci up_write(&nvmet_config_sem); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci return ret; 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_register_transport); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_civoid nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci down_write(&nvmet_config_sem); 30262306a36Sopenharmony_ci nvmet_transports[ops->type] = NULL; 30362306a36Sopenharmony_ci up_write(&nvmet_config_sem); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_unregister_transport); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_civoid nvmet_port_del_ctrls(struct nvmet_port *port, struct nvmet_subsys *subsys) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci mutex_lock(&subsys->lock); 31262306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { 31362306a36Sopenharmony_ci if (ctrl->port == port) 31462306a36Sopenharmony_ci ctrl->ops->delete_ctrl(ctrl); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciint nvmet_enable_port(struct nvmet_port *port) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci const struct nvmet_fabrics_ops *ops; 32262306a36Sopenharmony_ci int ret; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci lockdep_assert_held(&nvmet_config_sem); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci ops = nvmet_transports[port->disc_addr.trtype]; 32762306a36Sopenharmony_ci if (!ops) { 32862306a36Sopenharmony_ci up_write(&nvmet_config_sem); 32962306a36Sopenharmony_ci request_module("nvmet-transport-%d", port->disc_addr.trtype); 33062306a36Sopenharmony_ci down_write(&nvmet_config_sem); 33162306a36Sopenharmony_ci ops = nvmet_transports[port->disc_addr.trtype]; 33262306a36Sopenharmony_ci if (!ops) { 33362306a36Sopenharmony_ci pr_err("transport type %d not supported\n", 33462306a36Sopenharmony_ci port->disc_addr.trtype); 33562306a36Sopenharmony_ci return -EINVAL; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci } 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci if (!try_module_get(ops->owner)) 34062306a36Sopenharmony_ci return -EINVAL; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci /* 34362306a36Sopenharmony_ci * If the user requested PI support and the transport isn't pi capable, 34462306a36Sopenharmony_ci * don't enable the port. 34562306a36Sopenharmony_ci */ 34662306a36Sopenharmony_ci if (port->pi_enable && !(ops->flags & NVMF_METADATA_SUPPORTED)) { 34762306a36Sopenharmony_ci pr_err("T10-PI is not supported by transport type %d\n", 34862306a36Sopenharmony_ci port->disc_addr.trtype); 34962306a36Sopenharmony_ci ret = -EINVAL; 35062306a36Sopenharmony_ci goto out_put; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci ret = ops->add_port(port); 35462306a36Sopenharmony_ci if (ret) 35562306a36Sopenharmony_ci goto out_put; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci /* If the transport didn't set inline_data_size, then disable it. */ 35862306a36Sopenharmony_ci if (port->inline_data_size < 0) 35962306a36Sopenharmony_ci port->inline_data_size = 0; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci port->enabled = true; 36262306a36Sopenharmony_ci port->tr_ops = ops; 36362306a36Sopenharmony_ci return 0; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ciout_put: 36662306a36Sopenharmony_ci module_put(ops->owner); 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_civoid nvmet_disable_port(struct nvmet_port *port) 37162306a36Sopenharmony_ci{ 37262306a36Sopenharmony_ci const struct nvmet_fabrics_ops *ops; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci lockdep_assert_held(&nvmet_config_sem); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci port->enabled = false; 37762306a36Sopenharmony_ci port->tr_ops = NULL; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ops = nvmet_transports[port->disc_addr.trtype]; 38062306a36Sopenharmony_ci ops->remove_port(port); 38162306a36Sopenharmony_ci module_put(ops->owner); 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_cistatic void nvmet_keep_alive_timer(struct work_struct *work) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = container_of(to_delayed_work(work), 38762306a36Sopenharmony_ci struct nvmet_ctrl, ka_work); 38862306a36Sopenharmony_ci bool reset_tbkas = ctrl->reset_tbkas; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci ctrl->reset_tbkas = false; 39162306a36Sopenharmony_ci if (reset_tbkas) { 39262306a36Sopenharmony_ci pr_debug("ctrl %d reschedule traffic based keep-alive timer\n", 39362306a36Sopenharmony_ci ctrl->cntlid); 39462306a36Sopenharmony_ci queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ); 39562306a36Sopenharmony_ci return; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci pr_err("ctrl %d keep-alive timer (%d seconds) expired!\n", 39962306a36Sopenharmony_ci ctrl->cntlid, ctrl->kato); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci nvmet_ctrl_fatal_error(ctrl); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_civoid nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci if (unlikely(ctrl->kato == 0)) 40762306a36Sopenharmony_ci return; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci pr_debug("ctrl %d start keep-alive timer for %d secs\n", 41062306a36Sopenharmony_ci ctrl->cntlid, ctrl->kato); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci queue_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_civoid nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci if (unlikely(ctrl->kato == 0)) 41862306a36Sopenharmony_ci return; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci pr_debug("ctrl %d stop keep-alive\n", ctrl->cntlid); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci cancel_delayed_work_sync(&ctrl->ka_work); 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ciu16 nvmet_req_find_ns(struct nvmet_req *req) 42662306a36Sopenharmony_ci{ 42762306a36Sopenharmony_ci u32 nsid = le32_to_cpu(req->cmd->common.nsid); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci req->ns = xa_load(&nvmet_req_subsys(req)->namespaces, nsid); 43062306a36Sopenharmony_ci if (unlikely(!req->ns)) { 43162306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, nsid); 43262306a36Sopenharmony_ci return NVME_SC_INVALID_NS | NVME_SC_DNR; 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci percpu_ref_get(&req->ns->ref); 43662306a36Sopenharmony_ci return NVME_SC_SUCCESS; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic void nvmet_destroy_namespace(struct percpu_ref *ref) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct nvmet_ns *ns = container_of(ref, struct nvmet_ns, ref); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci complete(&ns->disable_done); 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_civoid nvmet_put_namespace(struct nvmet_ns *ns) 44762306a36Sopenharmony_ci{ 44862306a36Sopenharmony_ci percpu_ref_put(&ns->ref); 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic void nvmet_ns_dev_disable(struct nvmet_ns *ns) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci nvmet_bdev_ns_disable(ns); 45462306a36Sopenharmony_ci nvmet_file_ns_disable(ns); 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cistatic int nvmet_p2pmem_ns_enable(struct nvmet_ns *ns) 45862306a36Sopenharmony_ci{ 45962306a36Sopenharmony_ci int ret; 46062306a36Sopenharmony_ci struct pci_dev *p2p_dev; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci if (!ns->use_p2pmem) 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci if (!ns->bdev) { 46662306a36Sopenharmony_ci pr_err("peer-to-peer DMA is not supported by non-block device namespaces\n"); 46762306a36Sopenharmony_ci return -EINVAL; 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci if (!blk_queue_pci_p2pdma(ns->bdev->bd_disk->queue)) { 47162306a36Sopenharmony_ci pr_err("peer-to-peer DMA is not supported by the driver of %s\n", 47262306a36Sopenharmony_ci ns->device_path); 47362306a36Sopenharmony_ci return -EINVAL; 47462306a36Sopenharmony_ci } 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (ns->p2p_dev) { 47762306a36Sopenharmony_ci ret = pci_p2pdma_distance(ns->p2p_dev, nvmet_ns_dev(ns), true); 47862306a36Sopenharmony_ci if (ret < 0) 47962306a36Sopenharmony_ci return -EINVAL; 48062306a36Sopenharmony_ci } else { 48162306a36Sopenharmony_ci /* 48262306a36Sopenharmony_ci * Right now we just check that there is p2pmem available so 48362306a36Sopenharmony_ci * we can report an error to the user right away if there 48462306a36Sopenharmony_ci * is not. We'll find the actual device to use once we 48562306a36Sopenharmony_ci * setup the controller when the port's device is available. 48662306a36Sopenharmony_ci */ 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci p2p_dev = pci_p2pmem_find(nvmet_ns_dev(ns)); 48962306a36Sopenharmony_ci if (!p2p_dev) { 49062306a36Sopenharmony_ci pr_err("no peer-to-peer memory is available for %s\n", 49162306a36Sopenharmony_ci ns->device_path); 49262306a36Sopenharmony_ci return -EINVAL; 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci pci_dev_put(p2p_dev); 49662306a36Sopenharmony_ci } 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return 0; 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * Note: ctrl->subsys->lock should be held when calling this function 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_cistatic void nvmet_p2pmem_ns_add_p2p(struct nvmet_ctrl *ctrl, 50562306a36Sopenharmony_ci struct nvmet_ns *ns) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct device *clients[2]; 50862306a36Sopenharmony_ci struct pci_dev *p2p_dev; 50962306a36Sopenharmony_ci int ret; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!ctrl->p2p_client || !ns->use_p2pmem) 51262306a36Sopenharmony_ci return; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci if (ns->p2p_dev) { 51562306a36Sopenharmony_ci ret = pci_p2pdma_distance(ns->p2p_dev, ctrl->p2p_client, true); 51662306a36Sopenharmony_ci if (ret < 0) 51762306a36Sopenharmony_ci return; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci p2p_dev = pci_dev_get(ns->p2p_dev); 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci clients[0] = ctrl->p2p_client; 52262306a36Sopenharmony_ci clients[1] = nvmet_ns_dev(ns); 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci p2p_dev = pci_p2pmem_find_many(clients, ARRAY_SIZE(clients)); 52562306a36Sopenharmony_ci if (!p2p_dev) { 52662306a36Sopenharmony_ci pr_err("no peer-to-peer memory is available that's supported by %s and %s\n", 52762306a36Sopenharmony_ci dev_name(ctrl->p2p_client), ns->device_path); 52862306a36Sopenharmony_ci return; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci ret = radix_tree_insert(&ctrl->p2p_ns_map, ns->nsid, p2p_dev); 53362306a36Sopenharmony_ci if (ret < 0) 53462306a36Sopenharmony_ci pci_dev_put(p2p_dev); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci pr_info("using p2pmem on %s for nsid %d\n", pci_name(p2p_dev), 53762306a36Sopenharmony_ci ns->nsid); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cibool nvmet_ns_revalidate(struct nvmet_ns *ns) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci loff_t oldsize = ns->size; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci if (ns->bdev) 54562306a36Sopenharmony_ci nvmet_bdev_ns_revalidate(ns); 54662306a36Sopenharmony_ci else 54762306a36Sopenharmony_ci nvmet_file_ns_revalidate(ns); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return oldsize != ns->size; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ciint nvmet_ns_enable(struct nvmet_ns *ns) 55362306a36Sopenharmony_ci{ 55462306a36Sopenharmony_ci struct nvmet_subsys *subsys = ns->subsys; 55562306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 55662306a36Sopenharmony_ci int ret; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci mutex_lock(&subsys->lock); 55962306a36Sopenharmony_ci ret = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (nvmet_is_passthru_subsys(subsys)) { 56262306a36Sopenharmony_ci pr_info("cannot enable both passthru and regular namespaces for a single subsystem"); 56362306a36Sopenharmony_ci goto out_unlock; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (ns->enabled) 56762306a36Sopenharmony_ci goto out_unlock; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci ret = -EMFILE; 57062306a36Sopenharmony_ci if (subsys->nr_namespaces == NVMET_MAX_NAMESPACES) 57162306a36Sopenharmony_ci goto out_unlock; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci ret = nvmet_bdev_ns_enable(ns); 57462306a36Sopenharmony_ci if (ret == -ENOTBLK) 57562306a36Sopenharmony_ci ret = nvmet_file_ns_enable(ns); 57662306a36Sopenharmony_ci if (ret) 57762306a36Sopenharmony_ci goto out_unlock; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci ret = nvmet_p2pmem_ns_enable(ns); 58062306a36Sopenharmony_ci if (ret) 58162306a36Sopenharmony_ci goto out_dev_disable; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) 58462306a36Sopenharmony_ci nvmet_p2pmem_ns_add_p2p(ctrl, ns); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci ret = percpu_ref_init(&ns->ref, nvmet_destroy_namespace, 58762306a36Sopenharmony_ci 0, GFP_KERNEL); 58862306a36Sopenharmony_ci if (ret) 58962306a36Sopenharmony_ci goto out_dev_put; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (ns->nsid > subsys->max_nsid) 59262306a36Sopenharmony_ci subsys->max_nsid = ns->nsid; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci ret = xa_insert(&subsys->namespaces, ns->nsid, ns, GFP_KERNEL); 59562306a36Sopenharmony_ci if (ret) 59662306a36Sopenharmony_ci goto out_restore_subsys_maxnsid; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci subsys->nr_namespaces++; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci nvmet_ns_changed(subsys, ns->nsid); 60162306a36Sopenharmony_ci ns->enabled = true; 60262306a36Sopenharmony_ci ret = 0; 60362306a36Sopenharmony_ciout_unlock: 60462306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 60562306a36Sopenharmony_ci return ret; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ciout_restore_subsys_maxnsid: 60862306a36Sopenharmony_ci subsys->max_nsid = nvmet_max_nsid(subsys); 60962306a36Sopenharmony_ci percpu_ref_exit(&ns->ref); 61062306a36Sopenharmony_ciout_dev_put: 61162306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) 61262306a36Sopenharmony_ci pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid)); 61362306a36Sopenharmony_ciout_dev_disable: 61462306a36Sopenharmony_ci nvmet_ns_dev_disable(ns); 61562306a36Sopenharmony_ci goto out_unlock; 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_civoid nvmet_ns_disable(struct nvmet_ns *ns) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci struct nvmet_subsys *subsys = ns->subsys; 62162306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci mutex_lock(&subsys->lock); 62462306a36Sopenharmony_ci if (!ns->enabled) 62562306a36Sopenharmony_ci goto out_unlock; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci ns->enabled = false; 62862306a36Sopenharmony_ci xa_erase(&ns->subsys->namespaces, ns->nsid); 62962306a36Sopenharmony_ci if (ns->nsid == subsys->max_nsid) 63062306a36Sopenharmony_ci subsys->max_nsid = nvmet_max_nsid(subsys); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) 63362306a36Sopenharmony_ci pci_dev_put(radix_tree_delete(&ctrl->p2p_ns_map, ns->nsid)); 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci /* 63862306a36Sopenharmony_ci * Now that we removed the namespaces from the lookup list, we 63962306a36Sopenharmony_ci * can kill the per_cpu ref and wait for any remaining references 64062306a36Sopenharmony_ci * to be dropped, as well as a RCU grace period for anyone only 64162306a36Sopenharmony_ci * using the namepace under rcu_read_lock(). Note that we can't 64262306a36Sopenharmony_ci * use call_rcu here as we need to ensure the namespaces have 64362306a36Sopenharmony_ci * been fully destroyed before unloading the module. 64462306a36Sopenharmony_ci */ 64562306a36Sopenharmony_ci percpu_ref_kill(&ns->ref); 64662306a36Sopenharmony_ci synchronize_rcu(); 64762306a36Sopenharmony_ci wait_for_completion(&ns->disable_done); 64862306a36Sopenharmony_ci percpu_ref_exit(&ns->ref); 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci mutex_lock(&subsys->lock); 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_ci subsys->nr_namespaces--; 65362306a36Sopenharmony_ci nvmet_ns_changed(subsys, ns->nsid); 65462306a36Sopenharmony_ci nvmet_ns_dev_disable(ns); 65562306a36Sopenharmony_ciout_unlock: 65662306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 65762306a36Sopenharmony_ci} 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_civoid nvmet_ns_free(struct nvmet_ns *ns) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci nvmet_ns_disable(ns); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci down_write(&nvmet_ana_sem); 66462306a36Sopenharmony_ci nvmet_ana_group_enabled[ns->anagrpid]--; 66562306a36Sopenharmony_ci up_write(&nvmet_ana_sem); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci kfree(ns->device_path); 66862306a36Sopenharmony_ci kfree(ns); 66962306a36Sopenharmony_ci} 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_cistruct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid) 67262306a36Sopenharmony_ci{ 67362306a36Sopenharmony_ci struct nvmet_ns *ns; 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci ns = kzalloc(sizeof(*ns), GFP_KERNEL); 67662306a36Sopenharmony_ci if (!ns) 67762306a36Sopenharmony_ci return NULL; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci init_completion(&ns->disable_done); 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_ci ns->nsid = nsid; 68262306a36Sopenharmony_ci ns->subsys = subsys; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci down_write(&nvmet_ana_sem); 68562306a36Sopenharmony_ci ns->anagrpid = NVMET_DEFAULT_ANA_GRPID; 68662306a36Sopenharmony_ci nvmet_ana_group_enabled[ns->anagrpid]++; 68762306a36Sopenharmony_ci up_write(&nvmet_ana_sem); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci uuid_gen(&ns->uuid); 69062306a36Sopenharmony_ci ns->buffered_io = false; 69162306a36Sopenharmony_ci ns->csi = NVME_CSI_NVM; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return ns; 69462306a36Sopenharmony_ci} 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_cistatic void nvmet_update_sq_head(struct nvmet_req *req) 69762306a36Sopenharmony_ci{ 69862306a36Sopenharmony_ci if (req->sq->size) { 69962306a36Sopenharmony_ci u32 old_sqhd, new_sqhd; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci old_sqhd = READ_ONCE(req->sq->sqhd); 70262306a36Sopenharmony_ci do { 70362306a36Sopenharmony_ci new_sqhd = (old_sqhd + 1) % req->sq->size; 70462306a36Sopenharmony_ci } while (!try_cmpxchg(&req->sq->sqhd, &old_sqhd, new_sqhd)); 70562306a36Sopenharmony_ci } 70662306a36Sopenharmony_ci req->cqe->sq_head = cpu_to_le16(req->sq->sqhd & 0x0000FFFF); 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic void nvmet_set_error(struct nvmet_req *req, u16 status) 71062306a36Sopenharmony_ci{ 71162306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = req->sq->ctrl; 71262306a36Sopenharmony_ci struct nvme_error_slot *new_error_slot; 71362306a36Sopenharmony_ci unsigned long flags; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci req->cqe->status = cpu_to_le16(status << 1); 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci if (!ctrl || req->error_loc == NVMET_NO_ERROR_LOC) 71862306a36Sopenharmony_ci return; 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci spin_lock_irqsave(&ctrl->error_lock, flags); 72162306a36Sopenharmony_ci ctrl->err_counter++; 72262306a36Sopenharmony_ci new_error_slot = 72362306a36Sopenharmony_ci &ctrl->slots[ctrl->err_counter % NVMET_ERROR_LOG_SLOTS]; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci new_error_slot->error_count = cpu_to_le64(ctrl->err_counter); 72662306a36Sopenharmony_ci new_error_slot->sqid = cpu_to_le16(req->sq->qid); 72762306a36Sopenharmony_ci new_error_slot->cmdid = cpu_to_le16(req->cmd->common.command_id); 72862306a36Sopenharmony_ci new_error_slot->status_field = cpu_to_le16(status << 1); 72962306a36Sopenharmony_ci new_error_slot->param_error_location = cpu_to_le16(req->error_loc); 73062306a36Sopenharmony_ci new_error_slot->lba = cpu_to_le64(req->error_slba); 73162306a36Sopenharmony_ci new_error_slot->nsid = req->cmd->common.nsid; 73262306a36Sopenharmony_ci spin_unlock_irqrestore(&ctrl->error_lock, flags); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci /* set the more bit for this request */ 73562306a36Sopenharmony_ci req->cqe->status |= cpu_to_le16(1 << 14); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic void __nvmet_req_complete(struct nvmet_req *req, u16 status) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct nvmet_ns *ns = req->ns; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci if (!req->sq->sqhd_disabled) 74362306a36Sopenharmony_ci nvmet_update_sq_head(req); 74462306a36Sopenharmony_ci req->cqe->sq_id = cpu_to_le16(req->sq->qid); 74562306a36Sopenharmony_ci req->cqe->command_id = req->cmd->common.command_id; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (unlikely(status)) 74862306a36Sopenharmony_ci nvmet_set_error(req, status); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci trace_nvmet_req_complete(req); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci req->ops->queue_response(req); 75362306a36Sopenharmony_ci if (ns) 75462306a36Sopenharmony_ci nvmet_put_namespace(ns); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_civoid nvmet_req_complete(struct nvmet_req *req, u16 status) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct nvmet_sq *sq = req->sq; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci __nvmet_req_complete(req, status); 76262306a36Sopenharmony_ci percpu_ref_put(&sq->ref); 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_req_complete); 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_civoid nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, 76762306a36Sopenharmony_ci u16 qid, u16 size) 76862306a36Sopenharmony_ci{ 76962306a36Sopenharmony_ci cq->qid = qid; 77062306a36Sopenharmony_ci cq->size = size; 77162306a36Sopenharmony_ci} 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_civoid nvmet_sq_setup(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, 77462306a36Sopenharmony_ci u16 qid, u16 size) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci sq->sqhd = 0; 77762306a36Sopenharmony_ci sq->qid = qid; 77862306a36Sopenharmony_ci sq->size = size; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci ctrl->sqs[qid] = sq; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void nvmet_confirm_sq(struct percpu_ref *ref) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct nvmet_sq *sq = container_of(ref, struct nvmet_sq, ref); 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci complete(&sq->confirm_done); 78862306a36Sopenharmony_ci} 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_civoid nvmet_sq_destroy(struct nvmet_sq *sq) 79162306a36Sopenharmony_ci{ 79262306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = sq->ctrl; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci /* 79562306a36Sopenharmony_ci * If this is the admin queue, complete all AERs so that our 79662306a36Sopenharmony_ci * queue doesn't have outstanding requests on it. 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci if (ctrl && ctrl->sqs && ctrl->sqs[0] == sq) 79962306a36Sopenharmony_ci nvmet_async_events_failall(ctrl); 80062306a36Sopenharmony_ci percpu_ref_kill_and_confirm(&sq->ref, nvmet_confirm_sq); 80162306a36Sopenharmony_ci wait_for_completion(&sq->confirm_done); 80262306a36Sopenharmony_ci wait_for_completion(&sq->free_done); 80362306a36Sopenharmony_ci percpu_ref_exit(&sq->ref); 80462306a36Sopenharmony_ci nvmet_auth_sq_free(sq); 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci if (ctrl) { 80762306a36Sopenharmony_ci /* 80862306a36Sopenharmony_ci * The teardown flow may take some time, and the host may not 80962306a36Sopenharmony_ci * send us keep-alive during this period, hence reset the 81062306a36Sopenharmony_ci * traffic based keep-alive timer so we don't trigger a 81162306a36Sopenharmony_ci * controller teardown as a result of a keep-alive expiration. 81262306a36Sopenharmony_ci */ 81362306a36Sopenharmony_ci ctrl->reset_tbkas = true; 81462306a36Sopenharmony_ci sq->ctrl->sqs[sq->qid] = NULL; 81562306a36Sopenharmony_ci nvmet_ctrl_put(ctrl); 81662306a36Sopenharmony_ci sq->ctrl = NULL; /* allows reusing the queue later */ 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci} 81962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_sq_destroy); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_cistatic void nvmet_sq_free(struct percpu_ref *ref) 82262306a36Sopenharmony_ci{ 82362306a36Sopenharmony_ci struct nvmet_sq *sq = container_of(ref, struct nvmet_sq, ref); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci complete(&sq->free_done); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ciint nvmet_sq_init(struct nvmet_sq *sq) 82962306a36Sopenharmony_ci{ 83062306a36Sopenharmony_ci int ret; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ret = percpu_ref_init(&sq->ref, nvmet_sq_free, 0, GFP_KERNEL); 83362306a36Sopenharmony_ci if (ret) { 83462306a36Sopenharmony_ci pr_err("percpu_ref init failed!\n"); 83562306a36Sopenharmony_ci return ret; 83662306a36Sopenharmony_ci } 83762306a36Sopenharmony_ci init_completion(&sq->free_done); 83862306a36Sopenharmony_ci init_completion(&sq->confirm_done); 83962306a36Sopenharmony_ci nvmet_auth_sq_init(sq); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci return 0; 84262306a36Sopenharmony_ci} 84362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_sq_init); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_cistatic inline u16 nvmet_check_ana_state(struct nvmet_port *port, 84662306a36Sopenharmony_ci struct nvmet_ns *ns) 84762306a36Sopenharmony_ci{ 84862306a36Sopenharmony_ci enum nvme_ana_state state = port->ana_state[ns->anagrpid]; 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (unlikely(state == NVME_ANA_INACCESSIBLE)) 85162306a36Sopenharmony_ci return NVME_SC_ANA_INACCESSIBLE; 85262306a36Sopenharmony_ci if (unlikely(state == NVME_ANA_PERSISTENT_LOSS)) 85362306a36Sopenharmony_ci return NVME_SC_ANA_PERSISTENT_LOSS; 85462306a36Sopenharmony_ci if (unlikely(state == NVME_ANA_CHANGE)) 85562306a36Sopenharmony_ci return NVME_SC_ANA_TRANSITION; 85662306a36Sopenharmony_ci return 0; 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic inline u16 nvmet_io_cmd_check_access(struct nvmet_req *req) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci if (unlikely(req->ns->readonly)) { 86262306a36Sopenharmony_ci switch (req->cmd->common.opcode) { 86362306a36Sopenharmony_ci case nvme_cmd_read: 86462306a36Sopenharmony_ci case nvme_cmd_flush: 86562306a36Sopenharmony_ci break; 86662306a36Sopenharmony_ci default: 86762306a36Sopenharmony_ci return NVME_SC_NS_WRITE_PROTECTED; 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return 0; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_cistatic u16 nvmet_parse_io_cmd(struct nvmet_req *req) 87562306a36Sopenharmony_ci{ 87662306a36Sopenharmony_ci struct nvme_command *cmd = req->cmd; 87762306a36Sopenharmony_ci u16 ret; 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (nvme_is_fabrics(cmd)) 88062306a36Sopenharmony_ci return nvmet_parse_fabrics_io_cmd(req); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci if (unlikely(!nvmet_check_auth_status(req))) 88362306a36Sopenharmony_ci return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci ret = nvmet_check_ctrl_status(req); 88662306a36Sopenharmony_ci if (unlikely(ret)) 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (nvmet_is_passthru_req(req)) 89062306a36Sopenharmony_ci return nvmet_parse_passthru_io_cmd(req); 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci ret = nvmet_req_find_ns(req); 89362306a36Sopenharmony_ci if (unlikely(ret)) 89462306a36Sopenharmony_ci return ret; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci ret = nvmet_check_ana_state(req->port, req->ns); 89762306a36Sopenharmony_ci if (unlikely(ret)) { 89862306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, nsid); 89962306a36Sopenharmony_ci return ret; 90062306a36Sopenharmony_ci } 90162306a36Sopenharmony_ci ret = nvmet_io_cmd_check_access(req); 90262306a36Sopenharmony_ci if (unlikely(ret)) { 90362306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, nsid); 90462306a36Sopenharmony_ci return ret; 90562306a36Sopenharmony_ci } 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_ci switch (req->ns->csi) { 90862306a36Sopenharmony_ci case NVME_CSI_NVM: 90962306a36Sopenharmony_ci if (req->ns->file) 91062306a36Sopenharmony_ci return nvmet_file_parse_io_cmd(req); 91162306a36Sopenharmony_ci return nvmet_bdev_parse_io_cmd(req); 91262306a36Sopenharmony_ci case NVME_CSI_ZNS: 91362306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_BLK_DEV_ZONED)) 91462306a36Sopenharmony_ci return nvmet_bdev_zns_parse_io_cmd(req); 91562306a36Sopenharmony_ci return NVME_SC_INVALID_IO_CMD_SET; 91662306a36Sopenharmony_ci default: 91762306a36Sopenharmony_ci return NVME_SC_INVALID_IO_CMD_SET; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci} 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_cibool nvmet_req_init(struct nvmet_req *req, struct nvmet_cq *cq, 92262306a36Sopenharmony_ci struct nvmet_sq *sq, const struct nvmet_fabrics_ops *ops) 92362306a36Sopenharmony_ci{ 92462306a36Sopenharmony_ci u8 flags = req->cmd->common.flags; 92562306a36Sopenharmony_ci u16 status; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci req->cq = cq; 92862306a36Sopenharmony_ci req->sq = sq; 92962306a36Sopenharmony_ci req->ops = ops; 93062306a36Sopenharmony_ci req->sg = NULL; 93162306a36Sopenharmony_ci req->metadata_sg = NULL; 93262306a36Sopenharmony_ci req->sg_cnt = 0; 93362306a36Sopenharmony_ci req->metadata_sg_cnt = 0; 93462306a36Sopenharmony_ci req->transfer_len = 0; 93562306a36Sopenharmony_ci req->metadata_len = 0; 93662306a36Sopenharmony_ci req->cqe->status = 0; 93762306a36Sopenharmony_ci req->cqe->sq_head = 0; 93862306a36Sopenharmony_ci req->ns = NULL; 93962306a36Sopenharmony_ci req->error_loc = NVMET_NO_ERROR_LOC; 94062306a36Sopenharmony_ci req->error_slba = 0; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci /* no support for fused commands yet */ 94362306a36Sopenharmony_ci if (unlikely(flags & (NVME_CMD_FUSE_FIRST | NVME_CMD_FUSE_SECOND))) { 94462306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, flags); 94562306a36Sopenharmony_ci status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; 94662306a36Sopenharmony_ci goto fail; 94762306a36Sopenharmony_ci } 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci /* 95062306a36Sopenharmony_ci * For fabrics, PSDT field shall describe metadata pointer (MPTR) that 95162306a36Sopenharmony_ci * contains an address of a single contiguous physical buffer that is 95262306a36Sopenharmony_ci * byte aligned. 95362306a36Sopenharmony_ci */ 95462306a36Sopenharmony_ci if (unlikely((flags & NVME_CMD_SGL_ALL) != NVME_CMD_SGL_METABUF)) { 95562306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, flags); 95662306a36Sopenharmony_ci status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; 95762306a36Sopenharmony_ci goto fail; 95862306a36Sopenharmony_ci } 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci if (unlikely(!req->sq->ctrl)) 96162306a36Sopenharmony_ci /* will return an error for any non-connect command: */ 96262306a36Sopenharmony_ci status = nvmet_parse_connect_cmd(req); 96362306a36Sopenharmony_ci else if (likely(req->sq->qid != 0)) 96462306a36Sopenharmony_ci status = nvmet_parse_io_cmd(req); 96562306a36Sopenharmony_ci else 96662306a36Sopenharmony_ci status = nvmet_parse_admin_cmd(req); 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (status) 96962306a36Sopenharmony_ci goto fail; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci trace_nvmet_req_init(req, req->cmd); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci if (unlikely(!percpu_ref_tryget_live(&sq->ref))) { 97462306a36Sopenharmony_ci status = NVME_SC_INVALID_FIELD | NVME_SC_DNR; 97562306a36Sopenharmony_ci goto fail; 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci if (sq->ctrl) 97962306a36Sopenharmony_ci sq->ctrl->reset_tbkas = true; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci return true; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cifail: 98462306a36Sopenharmony_ci __nvmet_req_complete(req, status); 98562306a36Sopenharmony_ci return false; 98662306a36Sopenharmony_ci} 98762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_req_init); 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_civoid nvmet_req_uninit(struct nvmet_req *req) 99062306a36Sopenharmony_ci{ 99162306a36Sopenharmony_ci percpu_ref_put(&req->sq->ref); 99262306a36Sopenharmony_ci if (req->ns) 99362306a36Sopenharmony_ci nvmet_put_namespace(req->ns); 99462306a36Sopenharmony_ci} 99562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_req_uninit); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_cibool nvmet_check_transfer_len(struct nvmet_req *req, size_t len) 99862306a36Sopenharmony_ci{ 99962306a36Sopenharmony_ci if (unlikely(len != req->transfer_len)) { 100062306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 100162306a36Sopenharmony_ci nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR); 100262306a36Sopenharmony_ci return false; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci return true; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_check_transfer_len); 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cibool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci if (unlikely(data_len > req->transfer_len)) { 101262306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 101362306a36Sopenharmony_ci nvmet_req_complete(req, NVME_SC_SGL_INVALID_DATA | NVME_SC_DNR); 101462306a36Sopenharmony_ci return false; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci return true; 101862306a36Sopenharmony_ci} 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_cistatic unsigned int nvmet_data_transfer_len(struct nvmet_req *req) 102162306a36Sopenharmony_ci{ 102262306a36Sopenharmony_ci return req->transfer_len - req->metadata_len; 102362306a36Sopenharmony_ci} 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_cistatic int nvmet_req_alloc_p2pmem_sgls(struct pci_dev *p2p_dev, 102662306a36Sopenharmony_ci struct nvmet_req *req) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci req->sg = pci_p2pmem_alloc_sgl(p2p_dev, &req->sg_cnt, 102962306a36Sopenharmony_ci nvmet_data_transfer_len(req)); 103062306a36Sopenharmony_ci if (!req->sg) 103162306a36Sopenharmony_ci goto out_err; 103262306a36Sopenharmony_ci 103362306a36Sopenharmony_ci if (req->metadata_len) { 103462306a36Sopenharmony_ci req->metadata_sg = pci_p2pmem_alloc_sgl(p2p_dev, 103562306a36Sopenharmony_ci &req->metadata_sg_cnt, req->metadata_len); 103662306a36Sopenharmony_ci if (!req->metadata_sg) 103762306a36Sopenharmony_ci goto out_free_sg; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci req->p2p_dev = p2p_dev; 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return 0; 104362306a36Sopenharmony_ciout_free_sg: 104462306a36Sopenharmony_ci pci_p2pmem_free_sgl(req->p2p_dev, req->sg); 104562306a36Sopenharmony_ciout_err: 104662306a36Sopenharmony_ci return -ENOMEM; 104762306a36Sopenharmony_ci} 104862306a36Sopenharmony_ci 104962306a36Sopenharmony_cistatic struct pci_dev *nvmet_req_find_p2p_dev(struct nvmet_req *req) 105062306a36Sopenharmony_ci{ 105162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_PCI_P2PDMA) || 105262306a36Sopenharmony_ci !req->sq->ctrl || !req->sq->qid || !req->ns) 105362306a36Sopenharmony_ci return NULL; 105462306a36Sopenharmony_ci return radix_tree_lookup(&req->sq->ctrl->p2p_ns_map, req->ns->nsid); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ciint nvmet_req_alloc_sgls(struct nvmet_req *req) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci struct pci_dev *p2p_dev = nvmet_req_find_p2p_dev(req); 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci if (p2p_dev && !nvmet_req_alloc_p2pmem_sgls(p2p_dev, req)) 106262306a36Sopenharmony_ci return 0; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci req->sg = sgl_alloc(nvmet_data_transfer_len(req), GFP_KERNEL, 106562306a36Sopenharmony_ci &req->sg_cnt); 106662306a36Sopenharmony_ci if (unlikely(!req->sg)) 106762306a36Sopenharmony_ci goto out; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci if (req->metadata_len) { 107062306a36Sopenharmony_ci req->metadata_sg = sgl_alloc(req->metadata_len, GFP_KERNEL, 107162306a36Sopenharmony_ci &req->metadata_sg_cnt); 107262306a36Sopenharmony_ci if (unlikely(!req->metadata_sg)) 107362306a36Sopenharmony_ci goto out_free; 107462306a36Sopenharmony_ci } 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ciout_free: 107862306a36Sopenharmony_ci sgl_free(req->sg); 107962306a36Sopenharmony_ciout: 108062306a36Sopenharmony_ci return -ENOMEM; 108162306a36Sopenharmony_ci} 108262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_req_alloc_sgls); 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_civoid nvmet_req_free_sgls(struct nvmet_req *req) 108562306a36Sopenharmony_ci{ 108662306a36Sopenharmony_ci if (req->p2p_dev) { 108762306a36Sopenharmony_ci pci_p2pmem_free_sgl(req->p2p_dev, req->sg); 108862306a36Sopenharmony_ci if (req->metadata_sg) 108962306a36Sopenharmony_ci pci_p2pmem_free_sgl(req->p2p_dev, req->metadata_sg); 109062306a36Sopenharmony_ci req->p2p_dev = NULL; 109162306a36Sopenharmony_ci } else { 109262306a36Sopenharmony_ci sgl_free(req->sg); 109362306a36Sopenharmony_ci if (req->metadata_sg) 109462306a36Sopenharmony_ci sgl_free(req->metadata_sg); 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci req->sg = NULL; 109862306a36Sopenharmony_ci req->metadata_sg = NULL; 109962306a36Sopenharmony_ci req->sg_cnt = 0; 110062306a36Sopenharmony_ci req->metadata_sg_cnt = 0; 110162306a36Sopenharmony_ci} 110262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_req_free_sgls); 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_cistatic inline bool nvmet_cc_en(u32 cc) 110562306a36Sopenharmony_ci{ 110662306a36Sopenharmony_ci return (cc >> NVME_CC_EN_SHIFT) & 0x1; 110762306a36Sopenharmony_ci} 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_cistatic inline u8 nvmet_cc_css(u32 cc) 111062306a36Sopenharmony_ci{ 111162306a36Sopenharmony_ci return (cc >> NVME_CC_CSS_SHIFT) & 0x7; 111262306a36Sopenharmony_ci} 111362306a36Sopenharmony_ci 111462306a36Sopenharmony_cistatic inline u8 nvmet_cc_mps(u32 cc) 111562306a36Sopenharmony_ci{ 111662306a36Sopenharmony_ci return (cc >> NVME_CC_MPS_SHIFT) & 0xf; 111762306a36Sopenharmony_ci} 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_cistatic inline u8 nvmet_cc_ams(u32 cc) 112062306a36Sopenharmony_ci{ 112162306a36Sopenharmony_ci return (cc >> NVME_CC_AMS_SHIFT) & 0x7; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic inline u8 nvmet_cc_shn(u32 cc) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci return (cc >> NVME_CC_SHN_SHIFT) & 0x3; 112762306a36Sopenharmony_ci} 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_cistatic inline u8 nvmet_cc_iosqes(u32 cc) 113062306a36Sopenharmony_ci{ 113162306a36Sopenharmony_ci return (cc >> NVME_CC_IOSQES_SHIFT) & 0xf; 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_cistatic inline u8 nvmet_cc_iocqes(u32 cc) 113562306a36Sopenharmony_ci{ 113662306a36Sopenharmony_ci return (cc >> NVME_CC_IOCQES_SHIFT) & 0xf; 113762306a36Sopenharmony_ci} 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_cistatic inline bool nvmet_css_supported(u8 cc_css) 114062306a36Sopenharmony_ci{ 114162306a36Sopenharmony_ci switch (cc_css << NVME_CC_CSS_SHIFT) { 114262306a36Sopenharmony_ci case NVME_CC_CSS_NVM: 114362306a36Sopenharmony_ci case NVME_CC_CSS_CSI: 114462306a36Sopenharmony_ci return true; 114562306a36Sopenharmony_ci default: 114662306a36Sopenharmony_ci return false; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci} 114962306a36Sopenharmony_ci 115062306a36Sopenharmony_cistatic void nvmet_start_ctrl(struct nvmet_ctrl *ctrl) 115162306a36Sopenharmony_ci{ 115262306a36Sopenharmony_ci lockdep_assert_held(&ctrl->lock); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci /* 115562306a36Sopenharmony_ci * Only I/O controllers should verify iosqes,iocqes. 115662306a36Sopenharmony_ci * Strictly speaking, the spec says a discovery controller 115762306a36Sopenharmony_ci * should verify iosqes,iocqes are zeroed, however that 115862306a36Sopenharmony_ci * would break backwards compatibility, so don't enforce it. 115962306a36Sopenharmony_ci */ 116062306a36Sopenharmony_ci if (!nvmet_is_disc_subsys(ctrl->subsys) && 116162306a36Sopenharmony_ci (nvmet_cc_iosqes(ctrl->cc) != NVME_NVM_IOSQES || 116262306a36Sopenharmony_ci nvmet_cc_iocqes(ctrl->cc) != NVME_NVM_IOCQES)) { 116362306a36Sopenharmony_ci ctrl->csts = NVME_CSTS_CFS; 116462306a36Sopenharmony_ci return; 116562306a36Sopenharmony_ci } 116662306a36Sopenharmony_ci 116762306a36Sopenharmony_ci if (nvmet_cc_mps(ctrl->cc) != 0 || 116862306a36Sopenharmony_ci nvmet_cc_ams(ctrl->cc) != 0 || 116962306a36Sopenharmony_ci !nvmet_css_supported(nvmet_cc_css(ctrl->cc))) { 117062306a36Sopenharmony_ci ctrl->csts = NVME_CSTS_CFS; 117162306a36Sopenharmony_ci return; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci ctrl->csts = NVME_CSTS_RDY; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci /* 117762306a36Sopenharmony_ci * Controllers that are not yet enabled should not really enforce the 117862306a36Sopenharmony_ci * keep alive timeout, but we still want to track a timeout and cleanup 117962306a36Sopenharmony_ci * in case a host died before it enabled the controller. Hence, simply 118062306a36Sopenharmony_ci * reset the keep alive timer when the controller is enabled. 118162306a36Sopenharmony_ci */ 118262306a36Sopenharmony_ci if (ctrl->kato) 118362306a36Sopenharmony_ci mod_delayed_work(nvmet_wq, &ctrl->ka_work, ctrl->kato * HZ); 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_cistatic void nvmet_clear_ctrl(struct nvmet_ctrl *ctrl) 118762306a36Sopenharmony_ci{ 118862306a36Sopenharmony_ci lockdep_assert_held(&ctrl->lock); 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* XXX: tear down queues? */ 119162306a36Sopenharmony_ci ctrl->csts &= ~NVME_CSTS_RDY; 119262306a36Sopenharmony_ci ctrl->cc = 0; 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_civoid nvmet_update_cc(struct nvmet_ctrl *ctrl, u32 new) 119662306a36Sopenharmony_ci{ 119762306a36Sopenharmony_ci u32 old; 119862306a36Sopenharmony_ci 119962306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 120062306a36Sopenharmony_ci old = ctrl->cc; 120162306a36Sopenharmony_ci ctrl->cc = new; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci if (nvmet_cc_en(new) && !nvmet_cc_en(old)) 120462306a36Sopenharmony_ci nvmet_start_ctrl(ctrl); 120562306a36Sopenharmony_ci if (!nvmet_cc_en(new) && nvmet_cc_en(old)) 120662306a36Sopenharmony_ci nvmet_clear_ctrl(ctrl); 120762306a36Sopenharmony_ci if (nvmet_cc_shn(new) && !nvmet_cc_shn(old)) { 120862306a36Sopenharmony_ci nvmet_clear_ctrl(ctrl); 120962306a36Sopenharmony_ci ctrl->csts |= NVME_CSTS_SHST_CMPLT; 121062306a36Sopenharmony_ci } 121162306a36Sopenharmony_ci if (!nvmet_cc_shn(new) && nvmet_cc_shn(old)) 121262306a36Sopenharmony_ci ctrl->csts &= ~NVME_CSTS_SHST_CMPLT; 121362306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 121462306a36Sopenharmony_ci} 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_cistatic void nvmet_init_cap(struct nvmet_ctrl *ctrl) 121762306a36Sopenharmony_ci{ 121862306a36Sopenharmony_ci /* command sets supported: NVMe command set: */ 121962306a36Sopenharmony_ci ctrl->cap = (1ULL << 37); 122062306a36Sopenharmony_ci /* Controller supports one or more I/O Command Sets */ 122162306a36Sopenharmony_ci ctrl->cap |= (1ULL << 43); 122262306a36Sopenharmony_ci /* CC.EN timeout in 500msec units: */ 122362306a36Sopenharmony_ci ctrl->cap |= (15ULL << 24); 122462306a36Sopenharmony_ci /* maximum queue entries supported: */ 122562306a36Sopenharmony_ci if (ctrl->ops->get_max_queue_size) 122662306a36Sopenharmony_ci ctrl->cap |= ctrl->ops->get_max_queue_size(ctrl) - 1; 122762306a36Sopenharmony_ci else 122862306a36Sopenharmony_ci ctrl->cap |= NVMET_QUEUE_SIZE - 1; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci if (nvmet_is_passthru_subsys(ctrl->subsys)) 123162306a36Sopenharmony_ci nvmet_passthrough_override_cap(ctrl); 123262306a36Sopenharmony_ci} 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_cistruct nvmet_ctrl *nvmet_ctrl_find_get(const char *subsysnqn, 123562306a36Sopenharmony_ci const char *hostnqn, u16 cntlid, 123662306a36Sopenharmony_ci struct nvmet_req *req) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = NULL; 123962306a36Sopenharmony_ci struct nvmet_subsys *subsys; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci subsys = nvmet_find_get_subsys(req->port, subsysnqn); 124262306a36Sopenharmony_ci if (!subsys) { 124362306a36Sopenharmony_ci pr_warn("connect request for invalid subsystem %s!\n", 124462306a36Sopenharmony_ci subsysnqn); 124562306a36Sopenharmony_ci req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(subsysnqn); 124662306a36Sopenharmony_ci goto out; 124762306a36Sopenharmony_ci } 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci mutex_lock(&subsys->lock); 125062306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) { 125162306a36Sopenharmony_ci if (ctrl->cntlid == cntlid) { 125262306a36Sopenharmony_ci if (strncmp(hostnqn, ctrl->hostnqn, NVMF_NQN_SIZE)) { 125362306a36Sopenharmony_ci pr_warn("hostnqn mismatch.\n"); 125462306a36Sopenharmony_ci continue; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci if (!kref_get_unless_zero(&ctrl->ref)) 125762306a36Sopenharmony_ci continue; 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci /* ctrl found */ 126062306a36Sopenharmony_ci goto found; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci } 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci ctrl = NULL; /* ctrl not found */ 126562306a36Sopenharmony_ci pr_warn("could not find controller %d for subsys %s / host %s\n", 126662306a36Sopenharmony_ci cntlid, subsysnqn, hostnqn); 126762306a36Sopenharmony_ci req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(cntlid); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cifound: 127062306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 127162306a36Sopenharmony_ci nvmet_subsys_put(subsys); 127262306a36Sopenharmony_ciout: 127362306a36Sopenharmony_ci return ctrl; 127462306a36Sopenharmony_ci} 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ciu16 nvmet_check_ctrl_status(struct nvmet_req *req) 127762306a36Sopenharmony_ci{ 127862306a36Sopenharmony_ci if (unlikely(!(req->sq->ctrl->cc & NVME_CC_ENABLE))) { 127962306a36Sopenharmony_ci pr_err("got cmd %d while CC.EN == 0 on qid = %d\n", 128062306a36Sopenharmony_ci req->cmd->common.opcode, req->sq->qid); 128162306a36Sopenharmony_ci return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; 128262306a36Sopenharmony_ci } 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci if (unlikely(!(req->sq->ctrl->csts & NVME_CSTS_RDY))) { 128562306a36Sopenharmony_ci pr_err("got cmd %d while CSTS.RDY == 0 on qid = %d\n", 128662306a36Sopenharmony_ci req->cmd->common.opcode, req->sq->qid); 128762306a36Sopenharmony_ci return NVME_SC_CMD_SEQ_ERROR | NVME_SC_DNR; 128862306a36Sopenharmony_ci } 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (unlikely(!nvmet_check_auth_status(req))) { 129162306a36Sopenharmony_ci pr_warn("qid %d not authenticated\n", req->sq->qid); 129262306a36Sopenharmony_ci return NVME_SC_AUTH_REQUIRED | NVME_SC_DNR; 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci return 0; 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_cibool nvmet_host_allowed(struct nvmet_subsys *subsys, const char *hostnqn) 129862306a36Sopenharmony_ci{ 129962306a36Sopenharmony_ci struct nvmet_host_link *p; 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci lockdep_assert_held(&nvmet_config_sem); 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci if (subsys->allow_any_host) 130462306a36Sopenharmony_ci return true; 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci if (nvmet_is_disc_subsys(subsys)) /* allow all access to disc subsys */ 130762306a36Sopenharmony_ci return true; 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_ci list_for_each_entry(p, &subsys->hosts, entry) { 131062306a36Sopenharmony_ci if (!strcmp(nvmet_host_name(p->host), hostnqn)) 131162306a36Sopenharmony_ci return true; 131262306a36Sopenharmony_ci } 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci return false; 131562306a36Sopenharmony_ci} 131662306a36Sopenharmony_ci 131762306a36Sopenharmony_ci/* 131862306a36Sopenharmony_ci * Note: ctrl->subsys->lock should be held when calling this function 131962306a36Sopenharmony_ci */ 132062306a36Sopenharmony_cistatic void nvmet_setup_p2p_ns_map(struct nvmet_ctrl *ctrl, 132162306a36Sopenharmony_ci struct nvmet_req *req) 132262306a36Sopenharmony_ci{ 132362306a36Sopenharmony_ci struct nvmet_ns *ns; 132462306a36Sopenharmony_ci unsigned long idx; 132562306a36Sopenharmony_ci 132662306a36Sopenharmony_ci if (!req->p2p_client) 132762306a36Sopenharmony_ci return; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci ctrl->p2p_client = get_device(req->p2p_client); 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci xa_for_each(&ctrl->subsys->namespaces, idx, ns) 133262306a36Sopenharmony_ci nvmet_p2pmem_ns_add_p2p(ctrl, ns); 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci/* 133662306a36Sopenharmony_ci * Note: ctrl->subsys->lock should be held when calling this function 133762306a36Sopenharmony_ci */ 133862306a36Sopenharmony_cistatic void nvmet_release_p2p_ns_map(struct nvmet_ctrl *ctrl) 133962306a36Sopenharmony_ci{ 134062306a36Sopenharmony_ci struct radix_tree_iter iter; 134162306a36Sopenharmony_ci void __rcu **slot; 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci radix_tree_for_each_slot(slot, &ctrl->p2p_ns_map, &iter, 0) 134462306a36Sopenharmony_ci pci_dev_put(radix_tree_deref_slot(slot)); 134562306a36Sopenharmony_ci 134662306a36Sopenharmony_ci put_device(ctrl->p2p_client); 134762306a36Sopenharmony_ci} 134862306a36Sopenharmony_ci 134962306a36Sopenharmony_cistatic void nvmet_fatal_error_handler(struct work_struct *work) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = 135262306a36Sopenharmony_ci container_of(work, struct nvmet_ctrl, fatal_err_work); 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci pr_err("ctrl %d fatal error occurred!\n", ctrl->cntlid); 135562306a36Sopenharmony_ci ctrl->ops->delete_ctrl(ctrl); 135662306a36Sopenharmony_ci} 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ciu16 nvmet_alloc_ctrl(const char *subsysnqn, const char *hostnqn, 135962306a36Sopenharmony_ci struct nvmet_req *req, u32 kato, struct nvmet_ctrl **ctrlp) 136062306a36Sopenharmony_ci{ 136162306a36Sopenharmony_ci struct nvmet_subsys *subsys; 136262306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 136362306a36Sopenharmony_ci int ret; 136462306a36Sopenharmony_ci u16 status; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci status = NVME_SC_CONNECT_INVALID_PARAM | NVME_SC_DNR; 136762306a36Sopenharmony_ci subsys = nvmet_find_get_subsys(req->port, subsysnqn); 136862306a36Sopenharmony_ci if (!subsys) { 136962306a36Sopenharmony_ci pr_warn("connect request for invalid subsystem %s!\n", 137062306a36Sopenharmony_ci subsysnqn); 137162306a36Sopenharmony_ci req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(subsysnqn); 137262306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 137362306a36Sopenharmony_ci goto out; 137462306a36Sopenharmony_ci } 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci down_read(&nvmet_config_sem); 137762306a36Sopenharmony_ci if (!nvmet_host_allowed(subsys, hostnqn)) { 137862306a36Sopenharmony_ci pr_info("connect by host %s for subsystem %s not allowed\n", 137962306a36Sopenharmony_ci hostnqn, subsysnqn); 138062306a36Sopenharmony_ci req->cqe->result.u32 = IPO_IATTR_CONNECT_DATA(hostnqn); 138162306a36Sopenharmony_ci up_read(&nvmet_config_sem); 138262306a36Sopenharmony_ci status = NVME_SC_CONNECT_INVALID_HOST | NVME_SC_DNR; 138362306a36Sopenharmony_ci req->error_loc = offsetof(struct nvme_common_command, dptr); 138462306a36Sopenharmony_ci goto out_put_subsystem; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci up_read(&nvmet_config_sem); 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci status = NVME_SC_INTERNAL; 138962306a36Sopenharmony_ci ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 139062306a36Sopenharmony_ci if (!ctrl) 139162306a36Sopenharmony_ci goto out_put_subsystem; 139262306a36Sopenharmony_ci mutex_init(&ctrl->lock); 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci ctrl->port = req->port; 139562306a36Sopenharmony_ci ctrl->ops = req->ops; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci#ifdef CONFIG_NVME_TARGET_PASSTHRU 139862306a36Sopenharmony_ci /* By default, set loop targets to clear IDS by default */ 139962306a36Sopenharmony_ci if (ctrl->port->disc_addr.trtype == NVMF_TRTYPE_LOOP) 140062306a36Sopenharmony_ci subsys->clear_ids = 1; 140162306a36Sopenharmony_ci#endif 140262306a36Sopenharmony_ci 140362306a36Sopenharmony_ci INIT_WORK(&ctrl->async_event_work, nvmet_async_event_work); 140462306a36Sopenharmony_ci INIT_LIST_HEAD(&ctrl->async_events); 140562306a36Sopenharmony_ci INIT_RADIX_TREE(&ctrl->p2p_ns_map, GFP_KERNEL); 140662306a36Sopenharmony_ci INIT_WORK(&ctrl->fatal_err_work, nvmet_fatal_error_handler); 140762306a36Sopenharmony_ci INIT_DELAYED_WORK(&ctrl->ka_work, nvmet_keep_alive_timer); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci memcpy(ctrl->subsysnqn, subsysnqn, NVMF_NQN_SIZE); 141062306a36Sopenharmony_ci memcpy(ctrl->hostnqn, hostnqn, NVMF_NQN_SIZE); 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci kref_init(&ctrl->ref); 141362306a36Sopenharmony_ci ctrl->subsys = subsys; 141462306a36Sopenharmony_ci nvmet_init_cap(ctrl); 141562306a36Sopenharmony_ci WRITE_ONCE(ctrl->aen_enabled, NVMET_AEN_CFG_OPTIONAL); 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci ctrl->changed_ns_list = kmalloc_array(NVME_MAX_CHANGED_NAMESPACES, 141862306a36Sopenharmony_ci sizeof(__le32), GFP_KERNEL); 141962306a36Sopenharmony_ci if (!ctrl->changed_ns_list) 142062306a36Sopenharmony_ci goto out_free_ctrl; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci ctrl->sqs = kcalloc(subsys->max_qid + 1, 142362306a36Sopenharmony_ci sizeof(struct nvmet_sq *), 142462306a36Sopenharmony_ci GFP_KERNEL); 142562306a36Sopenharmony_ci if (!ctrl->sqs) 142662306a36Sopenharmony_ci goto out_free_changed_ns_list; 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci if (subsys->cntlid_min > subsys->cntlid_max) 142962306a36Sopenharmony_ci goto out_free_sqs; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci ret = ida_alloc_range(&cntlid_ida, 143262306a36Sopenharmony_ci subsys->cntlid_min, subsys->cntlid_max, 143362306a36Sopenharmony_ci GFP_KERNEL); 143462306a36Sopenharmony_ci if (ret < 0) { 143562306a36Sopenharmony_ci status = NVME_SC_CONNECT_CTRL_BUSY | NVME_SC_DNR; 143662306a36Sopenharmony_ci goto out_free_sqs; 143762306a36Sopenharmony_ci } 143862306a36Sopenharmony_ci ctrl->cntlid = ret; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* 144162306a36Sopenharmony_ci * Discovery controllers may use some arbitrary high value 144262306a36Sopenharmony_ci * in order to cleanup stale discovery sessions 144362306a36Sopenharmony_ci */ 144462306a36Sopenharmony_ci if (nvmet_is_disc_subsys(ctrl->subsys) && !kato) 144562306a36Sopenharmony_ci kato = NVMET_DISC_KATO_MS; 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci /* keep-alive timeout in seconds */ 144862306a36Sopenharmony_ci ctrl->kato = DIV_ROUND_UP(kato, 1000); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci ctrl->err_counter = 0; 145162306a36Sopenharmony_ci spin_lock_init(&ctrl->error_lock); 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci nvmet_start_keep_alive_timer(ctrl); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci mutex_lock(&subsys->lock); 145662306a36Sopenharmony_ci list_add_tail(&ctrl->subsys_entry, &subsys->ctrls); 145762306a36Sopenharmony_ci nvmet_setup_p2p_ns_map(ctrl, req); 145862306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci *ctrlp = ctrl; 146162306a36Sopenharmony_ci return 0; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ciout_free_sqs: 146462306a36Sopenharmony_ci kfree(ctrl->sqs); 146562306a36Sopenharmony_ciout_free_changed_ns_list: 146662306a36Sopenharmony_ci kfree(ctrl->changed_ns_list); 146762306a36Sopenharmony_ciout_free_ctrl: 146862306a36Sopenharmony_ci kfree(ctrl); 146962306a36Sopenharmony_ciout_put_subsystem: 147062306a36Sopenharmony_ci nvmet_subsys_put(subsys); 147162306a36Sopenharmony_ciout: 147262306a36Sopenharmony_ci return status; 147362306a36Sopenharmony_ci} 147462306a36Sopenharmony_ci 147562306a36Sopenharmony_cistatic void nvmet_ctrl_free(struct kref *ref) 147662306a36Sopenharmony_ci{ 147762306a36Sopenharmony_ci struct nvmet_ctrl *ctrl = container_of(ref, struct nvmet_ctrl, ref); 147862306a36Sopenharmony_ci struct nvmet_subsys *subsys = ctrl->subsys; 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci mutex_lock(&subsys->lock); 148162306a36Sopenharmony_ci nvmet_release_p2p_ns_map(ctrl); 148262306a36Sopenharmony_ci list_del(&ctrl->subsys_entry); 148362306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci nvmet_stop_keep_alive_timer(ctrl); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci flush_work(&ctrl->async_event_work); 148862306a36Sopenharmony_ci cancel_work_sync(&ctrl->fatal_err_work); 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci nvmet_destroy_auth(ctrl); 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci ida_free(&cntlid_ida, ctrl->cntlid); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci nvmet_async_events_free(ctrl); 149562306a36Sopenharmony_ci kfree(ctrl->sqs); 149662306a36Sopenharmony_ci kfree(ctrl->changed_ns_list); 149762306a36Sopenharmony_ci kfree(ctrl); 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci nvmet_subsys_put(subsys); 150062306a36Sopenharmony_ci} 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_civoid nvmet_ctrl_put(struct nvmet_ctrl *ctrl) 150362306a36Sopenharmony_ci{ 150462306a36Sopenharmony_ci kref_put(&ctrl->ref, nvmet_ctrl_free); 150562306a36Sopenharmony_ci} 150662306a36Sopenharmony_ci 150762306a36Sopenharmony_civoid nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl) 150862306a36Sopenharmony_ci{ 150962306a36Sopenharmony_ci mutex_lock(&ctrl->lock); 151062306a36Sopenharmony_ci if (!(ctrl->csts & NVME_CSTS_CFS)) { 151162306a36Sopenharmony_ci ctrl->csts |= NVME_CSTS_CFS; 151262306a36Sopenharmony_ci queue_work(nvmet_wq, &ctrl->fatal_err_work); 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci mutex_unlock(&ctrl->lock); 151562306a36Sopenharmony_ci} 151662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(nvmet_ctrl_fatal_error); 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_cistatic struct nvmet_subsys *nvmet_find_get_subsys(struct nvmet_port *port, 151962306a36Sopenharmony_ci const char *subsysnqn) 152062306a36Sopenharmony_ci{ 152162306a36Sopenharmony_ci struct nvmet_subsys_link *p; 152262306a36Sopenharmony_ci 152362306a36Sopenharmony_ci if (!port) 152462306a36Sopenharmony_ci return NULL; 152562306a36Sopenharmony_ci 152662306a36Sopenharmony_ci if (!strcmp(NVME_DISC_SUBSYS_NAME, subsysnqn)) { 152762306a36Sopenharmony_ci if (!kref_get_unless_zero(&nvmet_disc_subsys->ref)) 152862306a36Sopenharmony_ci return NULL; 152962306a36Sopenharmony_ci return nvmet_disc_subsys; 153062306a36Sopenharmony_ci } 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci down_read(&nvmet_config_sem); 153362306a36Sopenharmony_ci list_for_each_entry(p, &port->subsystems, entry) { 153462306a36Sopenharmony_ci if (!strncmp(p->subsys->subsysnqn, subsysnqn, 153562306a36Sopenharmony_ci NVMF_NQN_SIZE)) { 153662306a36Sopenharmony_ci if (!kref_get_unless_zero(&p->subsys->ref)) 153762306a36Sopenharmony_ci break; 153862306a36Sopenharmony_ci up_read(&nvmet_config_sem); 153962306a36Sopenharmony_ci return p->subsys; 154062306a36Sopenharmony_ci } 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci up_read(&nvmet_config_sem); 154362306a36Sopenharmony_ci return NULL; 154462306a36Sopenharmony_ci} 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_cistruct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn, 154762306a36Sopenharmony_ci enum nvme_subsys_type type) 154862306a36Sopenharmony_ci{ 154962306a36Sopenharmony_ci struct nvmet_subsys *subsys; 155062306a36Sopenharmony_ci char serial[NVMET_SN_MAX_SIZE / 2]; 155162306a36Sopenharmony_ci int ret; 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_ci subsys = kzalloc(sizeof(*subsys), GFP_KERNEL); 155462306a36Sopenharmony_ci if (!subsys) 155562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 155662306a36Sopenharmony_ci 155762306a36Sopenharmony_ci subsys->ver = NVMET_DEFAULT_VS; 155862306a36Sopenharmony_ci /* generate a random serial number as our controllers are ephemeral: */ 155962306a36Sopenharmony_ci get_random_bytes(&serial, sizeof(serial)); 156062306a36Sopenharmony_ci bin2hex(subsys->serial, &serial, sizeof(serial)); 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci subsys->model_number = kstrdup(NVMET_DEFAULT_CTRL_MODEL, GFP_KERNEL); 156362306a36Sopenharmony_ci if (!subsys->model_number) { 156462306a36Sopenharmony_ci ret = -ENOMEM; 156562306a36Sopenharmony_ci goto free_subsys; 156662306a36Sopenharmony_ci } 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci subsys->ieee_oui = 0; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_ci subsys->firmware_rev = kstrndup(UTS_RELEASE, NVMET_FR_MAX_SIZE, GFP_KERNEL); 157162306a36Sopenharmony_ci if (!subsys->firmware_rev) { 157262306a36Sopenharmony_ci ret = -ENOMEM; 157362306a36Sopenharmony_ci goto free_mn; 157462306a36Sopenharmony_ci } 157562306a36Sopenharmony_ci 157662306a36Sopenharmony_ci switch (type) { 157762306a36Sopenharmony_ci case NVME_NQN_NVME: 157862306a36Sopenharmony_ci subsys->max_qid = NVMET_NR_QUEUES; 157962306a36Sopenharmony_ci break; 158062306a36Sopenharmony_ci case NVME_NQN_DISC: 158162306a36Sopenharmony_ci case NVME_NQN_CURR: 158262306a36Sopenharmony_ci subsys->max_qid = 0; 158362306a36Sopenharmony_ci break; 158462306a36Sopenharmony_ci default: 158562306a36Sopenharmony_ci pr_err("%s: Unknown Subsystem type - %d\n", __func__, type); 158662306a36Sopenharmony_ci ret = -EINVAL; 158762306a36Sopenharmony_ci goto free_fr; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci subsys->type = type; 159062306a36Sopenharmony_ci subsys->subsysnqn = kstrndup(subsysnqn, NVMF_NQN_SIZE, 159162306a36Sopenharmony_ci GFP_KERNEL); 159262306a36Sopenharmony_ci if (!subsys->subsysnqn) { 159362306a36Sopenharmony_ci ret = -ENOMEM; 159462306a36Sopenharmony_ci goto free_fr; 159562306a36Sopenharmony_ci } 159662306a36Sopenharmony_ci subsys->cntlid_min = NVME_CNTLID_MIN; 159762306a36Sopenharmony_ci subsys->cntlid_max = NVME_CNTLID_MAX; 159862306a36Sopenharmony_ci kref_init(&subsys->ref); 159962306a36Sopenharmony_ci 160062306a36Sopenharmony_ci mutex_init(&subsys->lock); 160162306a36Sopenharmony_ci xa_init(&subsys->namespaces); 160262306a36Sopenharmony_ci INIT_LIST_HEAD(&subsys->ctrls); 160362306a36Sopenharmony_ci INIT_LIST_HEAD(&subsys->hosts); 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci return subsys; 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_cifree_fr: 160862306a36Sopenharmony_ci kfree(subsys->firmware_rev); 160962306a36Sopenharmony_cifree_mn: 161062306a36Sopenharmony_ci kfree(subsys->model_number); 161162306a36Sopenharmony_cifree_subsys: 161262306a36Sopenharmony_ci kfree(subsys); 161362306a36Sopenharmony_ci return ERR_PTR(ret); 161462306a36Sopenharmony_ci} 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_cistatic void nvmet_subsys_free(struct kref *ref) 161762306a36Sopenharmony_ci{ 161862306a36Sopenharmony_ci struct nvmet_subsys *subsys = 161962306a36Sopenharmony_ci container_of(ref, struct nvmet_subsys, ref); 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci WARN_ON_ONCE(!xa_empty(&subsys->namespaces)); 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci xa_destroy(&subsys->namespaces); 162462306a36Sopenharmony_ci nvmet_passthru_subsys_free(subsys); 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci kfree(subsys->subsysnqn); 162762306a36Sopenharmony_ci kfree(subsys->model_number); 162862306a36Sopenharmony_ci kfree(subsys->firmware_rev); 162962306a36Sopenharmony_ci kfree(subsys); 163062306a36Sopenharmony_ci} 163162306a36Sopenharmony_ci 163262306a36Sopenharmony_civoid nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys) 163362306a36Sopenharmony_ci{ 163462306a36Sopenharmony_ci struct nvmet_ctrl *ctrl; 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci mutex_lock(&subsys->lock); 163762306a36Sopenharmony_ci list_for_each_entry(ctrl, &subsys->ctrls, subsys_entry) 163862306a36Sopenharmony_ci ctrl->ops->delete_ctrl(ctrl); 163962306a36Sopenharmony_ci mutex_unlock(&subsys->lock); 164062306a36Sopenharmony_ci} 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_civoid nvmet_subsys_put(struct nvmet_subsys *subsys) 164362306a36Sopenharmony_ci{ 164462306a36Sopenharmony_ci kref_put(&subsys->ref, nvmet_subsys_free); 164562306a36Sopenharmony_ci} 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_cistatic int __init nvmet_init(void) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci int error = -ENOMEM; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci nvmet_ana_group_enabled[NVMET_DEFAULT_ANA_GRPID] = 1; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci nvmet_bvec_cache = kmem_cache_create("nvmet-bvec", 165462306a36Sopenharmony_ci NVMET_MAX_MPOOL_BVEC * sizeof(struct bio_vec), 0, 165562306a36Sopenharmony_ci SLAB_HWCACHE_ALIGN, NULL); 165662306a36Sopenharmony_ci if (!nvmet_bvec_cache) 165762306a36Sopenharmony_ci return -ENOMEM; 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci zbd_wq = alloc_workqueue("nvmet-zbd-wq", WQ_MEM_RECLAIM, 0); 166062306a36Sopenharmony_ci if (!zbd_wq) 166162306a36Sopenharmony_ci goto out_destroy_bvec_cache; 166262306a36Sopenharmony_ci 166362306a36Sopenharmony_ci buffered_io_wq = alloc_workqueue("nvmet-buffered-io-wq", 166462306a36Sopenharmony_ci WQ_MEM_RECLAIM, 0); 166562306a36Sopenharmony_ci if (!buffered_io_wq) 166662306a36Sopenharmony_ci goto out_free_zbd_work_queue; 166762306a36Sopenharmony_ci 166862306a36Sopenharmony_ci nvmet_wq = alloc_workqueue("nvmet-wq", WQ_MEM_RECLAIM, 0); 166962306a36Sopenharmony_ci if (!nvmet_wq) 167062306a36Sopenharmony_ci goto out_free_buffered_work_queue; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci error = nvmet_init_discovery(); 167362306a36Sopenharmony_ci if (error) 167462306a36Sopenharmony_ci goto out_free_nvmet_work_queue; 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_ci error = nvmet_init_configfs(); 167762306a36Sopenharmony_ci if (error) 167862306a36Sopenharmony_ci goto out_exit_discovery; 167962306a36Sopenharmony_ci return 0; 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ciout_exit_discovery: 168262306a36Sopenharmony_ci nvmet_exit_discovery(); 168362306a36Sopenharmony_ciout_free_nvmet_work_queue: 168462306a36Sopenharmony_ci destroy_workqueue(nvmet_wq); 168562306a36Sopenharmony_ciout_free_buffered_work_queue: 168662306a36Sopenharmony_ci destroy_workqueue(buffered_io_wq); 168762306a36Sopenharmony_ciout_free_zbd_work_queue: 168862306a36Sopenharmony_ci destroy_workqueue(zbd_wq); 168962306a36Sopenharmony_ciout_destroy_bvec_cache: 169062306a36Sopenharmony_ci kmem_cache_destroy(nvmet_bvec_cache); 169162306a36Sopenharmony_ci return error; 169262306a36Sopenharmony_ci} 169362306a36Sopenharmony_ci 169462306a36Sopenharmony_cistatic void __exit nvmet_exit(void) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci nvmet_exit_configfs(); 169762306a36Sopenharmony_ci nvmet_exit_discovery(); 169862306a36Sopenharmony_ci ida_destroy(&cntlid_ida); 169962306a36Sopenharmony_ci destroy_workqueue(nvmet_wq); 170062306a36Sopenharmony_ci destroy_workqueue(buffered_io_wq); 170162306a36Sopenharmony_ci destroy_workqueue(zbd_wq); 170262306a36Sopenharmony_ci kmem_cache_destroy(nvmet_bvec_cache); 170362306a36Sopenharmony_ci 170462306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_entry) != 1024); 170562306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct nvmf_disc_rsp_page_hdr) != 1024); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cimodule_init(nvmet_init); 170962306a36Sopenharmony_cimodule_exit(nvmet_exit); 171062306a36Sopenharmony_ci 171162306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 1712