numam-spdk/lib/nvmf/nvmf_io_cmd.c
Daniel Verkamp 0f912a0eaf nvmf: add NVMe over Fabrics userspace target
Change-Id: I739916824d033bd1a8f8b7f5def09e58f23d13cb
Signed-off-by: Daniel Verkamp <daniel.verkamp@intel.com>
2016-06-06 15:21:25 -07:00

162 lines
5.4 KiB
C

/*-
* BSD LICENSE
*
* Copyright (c) Intel Corporation.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "nvmf.h"
#include "nvmf_internal.h"
#include "session.h"
#include "subsystem_grp.h"
#include "spdk/log.h"
#include "spdk/nvme.h"
#include "spdk/nvme_spec.h"
#include "spdk/pci.h"
#include "spdk/trace.h"
extern struct rte_mempool *request_mempool;
int
nvmf_process_io_cmd(struct nvmf_session *session,
struct spdk_nvme_cmd *cmd,
void *buf, uint32_t len,
struct nvmf_request *req_state)
{
struct spdk_nvme_cpl *response;
struct spdk_nvmf_subsystem *subsystem = session->subsys;
struct spdk_nvmf_namespace *nvmf_ns;
struct spdk_nvme_ctrlr *ctrlr = NULL;
struct spdk_nvme_ns *ns = NULL;
struct spdk_nvme_qpair *qpair;
uint32_t nsid = 0;
struct nvme_read_cdw12 *cdw12;
uint64_t lba_address;
uint32_t lba_count;
uint32_t io_flags;
int rc = 0;
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: req_state %p\n", req_state);
/* pre-set response details for this command */
response = &req_state->rsp->nvme_cpl;
response->status.sc = SPDK_NVME_SC_SUCCESS;
response->cid = cmd->cid;
/* verify subsystem */
if (subsystem == NULL) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Subsystem Not Initialized!\n");
response->status.sc = SPDK_NVME_SC_INTERNAL_DEVICE_ERROR;
return -1;
}
/* verify that the contoller is ready to process commands */
if (session->vcprop.csts.bits.rdy == 0) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Subsystem Controller Not Ready!\n");
response->status.sc = SPDK_NVME_SC_NAMESPACE_NOT_READY;
return -1;
}
/* verify namespace id */
if (cmd->nsid == 0 || cmd->nsid > MAX_PER_SUBSYSTEM_NAMESPACES) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Invalid NS_ID %x\n",
cmd->nsid);
response->status.sc = SPDK_NVME_SC_INVALID_NAMESPACE_OR_FORMAT;
return -1;
}
nvmf_ns = &subsystem->ns_list_map[cmd->nsid - 1];
ctrlr = nvmf_ns->ctrlr;
nsid = nvmf_ns->nvme_ns_id;
ns = nvmf_ns->ns;
qpair = nvmf_ns->qpair;
switch (cmd->opc) {
case SPDK_NVME_OPC_READ:
case SPDK_NVME_OPC_WRITE:
cdw12 = (struct nvme_read_cdw12 *)&cmd->cdw12;
/* NVMe library read/write interface expects non-0based lba_count value */
lba_count = cdw12->nlb + 1;
lba_address = cmd->cdw11;
lba_address = (lba_address << 32) + cmd->cdw10;
io_flags = cmd->cdw12 & 0xFFFF0000U;
if (cmd->opc == SPDK_NVME_OPC_READ) {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Read; lba address %lx, lba count %x\n",
lba_address, lba_count);
spdk_trace_record(TRACE_NVMF_LIB_READ_START, 0, 0,
(uint64_t)req_state->fabric_rx_ctx, 0);
spdk_nvme_ns_cmd_read(ns, qpair,
buf, lba_address, lba_count,
nvmf_complete_cmd,
(void *)req_state, io_flags);
} else {
SPDK_TRACELOG(SPDK_TRACE_NVMF, "nvmf_process_io_cmd: Write; lba address %lx, lba count %x\n",
lba_address, lba_count);
spdk_trace_record(TRACE_NVMF_LIB_WRITE_START, 0, 0,
(uint64_t)req_state->fabric_rx_ctx, 0);
spdk_nvme_ns_cmd_write(ns, qpair,
buf, lba_address, lba_count,
nvmf_complete_cmd,
(void *)req_state, io_flags);
}
break;
default:
SPDK_TRACELOG(SPDK_TRACE_NVMF, "RAW Passthrough: I/O Opcode %x\n", cmd->opc);
cmd->nsid = nsid;
spdk_nvme_ctrlr_cmd_io_raw(ctrlr, qpair,
cmd,
buf, len,
nvmf_complete_cmd,
(void *)req_state);
break;
}
return rc;
}
void
nvmf_check_io_completions(struct nvmf_session *session)
{
struct spdk_nvmf_subsystem *subsystem = session->subsys;
struct spdk_nvme_qpair *qpair, *prev_qpair = NULL;
int i;
for (i = 0; i < MAX_PER_SUBSYSTEM_NAMESPACES; i++) {
qpair = subsystem->ns_list_map[i].qpair;
if (qpair == NULL)
continue;
if (qpair != NULL && qpair != prev_qpair) {
spdk_nvme_qpair_process_completions(qpair, 0);
prev_qpair = qpair;
}
}
}