/*
* NVMe over Fabrics common host code.
* Copyright (c) 2015-2016 HGST, a Western Digital Company.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/parser.h>
#include <linux/seq_file.h>
#include "nvme.h"
#include "fabrics.h"
static LIST_HEAD(nvmf_transports);
static DECLARE_RWSEM(nvmf_transports_rwsem);
static LIST_HEAD(nvmf_hosts);
static DEFINE_MUTEX(nvmf_hosts_mutex);
static struct nvmf_host *nvmf_default_host;
static struct nvmf_host *__nvmf_host_find(const char *hostnqn)
{
struct nvmf_host *host;
list_for_each_entry(host, &nvmf_hosts, list) {
if (!strcmp(host->nqn, hostnqn))
return host;
}
return NULL;
}
static struct nvmf_host *nvmf_host_add(const char *hostnqn)
{
struct nvmf_host *host;
mutex_lock(&nvmf_hosts_mutex);
host = __nvmf_host_find(hostnqn);
if (host) {
kref_get(&host->ref);
goto out_unlock;
}
host = kmalloc(sizeof(*host), GFP_KERNEL);
if (!host)
goto out_unlock;
kref_init(&host->ref);
memcpy(host->nqn, hostnqn, NVMF_NQN_SIZE);
list_add_tail(&host->list, &nvmf_hosts);
out_unlock:
mutex_unlock(&nvmf_hosts_mutex);
return host;
}
static struct nvmf_host *nvmf_host_default(void)
{
struct nvmf_host *host;
host = kmalloc(sizeof(*host), GFP_KERNEL);
if (!host)
return NULL;
kref_init(&host->ref);
snprintf(host->nqn, NVMF_NQN_SIZE,
"nqn.2014-08.org.nvmexpress:uuid:%pUb", &host->id);
mutex_lock(&nvmf_hosts_mutex);
list_add_tail(&host->list, &nvmf_hosts);
mutex_unlock(&nvmf_hosts_mutex);
return host;
}
static void nvmf_host_destroy(struct kref *ref)
{
struct nvmf_host *host = container_of(ref, struct nvmf_host, ref);
mutex_lock(&nvmf_hosts_mutex);
list_del(&host->list);
mutex_unlock(&nvmf_hosts_mutex);
kfree(host);
}
static void nvmf_host_put(struct nvmf_host *host)
{
if (host)
kref_put(&host->ref, nvmf_host_destroy);
}
/**
* nvmf_get_address() - Get address/port
* @ctrl: Host NVMe controller instance which we got the address
* @buf: OUTPUT parameter that will contain the address/port
* @size: buffer size
*/
int nvmf_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
{
int len = 0;
if (ctrl->opts->mask & NVMF_OPT_TRADDR)
len += snprintf(buf, size, "traddr=%s", ctrl->opts->traddr);
if (ctrl->opts->mask & NVMF_OPT_TRSVCID)
len += snprintf(buf + len, size - len, "%strsvcid=%s",
(len) ? "," : "", ctrl->opts->trsvcid);
if (ctrl->opts->mask & NVMF_OPT_HOST_TRADDR)
len += snprintf(buf + len, size - len, "%shost_traddr=%s",
(len) ? "," : "", ctrl->opts->host_traddr);
len += snprintf(buf + len, size - len, "\n");
return len;
}
EXPORT_SYMBOL_GPL(nvmf_get_address);
/**
* nvmf_reg_read32() - NVMe Fabrics "Property Get" API function.
* @ctrl: Host NVMe controller instance maintaining the admin
* queue used to submit the property read command to
* the allocated NVMe controller resource on the target system.
* @off: Starting offset value of the targeted property
* register (see the fabrics section of the NVMe standard).
* @val: OUTPUT parameter that will contain the value of
* the property after a successful read.
*
* Used by the host system to retrieve a 32-bit capsule property value
* from an NVMe controller on the target system.
*
* ("Capsule property" is an "PCIe register concept" applied to the
* NVMe fabrics space.)
*
* Return:
* 0: successful read
* > 0: NVMe error status code
* < 0: Linux errno error code
*/
int nvmf_reg_read32(struct nvme_ctrl *ctrl, u32 off