This adds support for multiple namespaces by introducing a new 'nvme-ns' device model. The nvme device creates a bus named from the device name ('id'). The nvme-ns devices then connect to this and registers themselves with the nvme device. This changes how an nvme device is created. Example with two namespaces: -drive file=nvme0n1.img,if=none,id=disk1 -drive file=nvme0n2.img,if=none,id=disk2 -device nvme,serial=deadbeef,id=nvme0 -device nvme-ns,drive=disk1,bus=nvme0,nsid=1 -device nvme-ns,drive=disk2,bus=nvme0,nsid=2 The drive property is kept on the nvme device to keep the change backward compatible, but the property is now optional. Specifying a drive for the nvme device will always create the namespace with nsid 1. Signed-off-by: Klaus Jensen <k.jensen@samsung.com> Reviewed-by: Keith Busch <kbusch@kernel.org> Reviewed-by: Minwoo Im <minwoo.im.dev@gmail.com>
75 lines
1.6 KiB
C
75 lines
1.6 KiB
C
/*
|
|
* QEMU NVM Express Virtual Namespace
|
|
*
|
|
* Copyright (c) 2019 CNEX Labs
|
|
* Copyright (c) 2020 Samsung Electronics
|
|
*
|
|
* Authors:
|
|
* Klaus Jensen <k.jensen@samsung.com>
|
|
*
|
|
* This work is licensed under the terms of the GNU GPL, version 2. See the
|
|
* COPYING file in the top-level directory.
|
|
*
|
|
*/
|
|
|
|
#ifndef NVME_NS_H
|
|
#define NVME_NS_H
|
|
|
|
#define TYPE_NVME_NS "nvme-ns"
|
|
#define NVME_NS(obj) \
|
|
OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
|
|
|
|
typedef struct NvmeNamespaceParams {
|
|
uint32_t nsid;
|
|
} NvmeNamespaceParams;
|
|
|
|
typedef struct NvmeNamespace {
|
|
DeviceState parent_obj;
|
|
BlockConf blkconf;
|
|
int32_t bootindex;
|
|
int64_t size;
|
|
NvmeIdNs id_ns;
|
|
|
|
NvmeNamespaceParams params;
|
|
} NvmeNamespace;
|
|
|
|
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
|
|
{
|
|
if (ns) {
|
|
return ns->params.nsid;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
|
|
{
|
|
NvmeIdNs *id_ns = &ns->id_ns;
|
|
return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
|
|
}
|
|
|
|
static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
|
|
{
|
|
return nvme_ns_lbaf(ns)->ds;
|
|
}
|
|
|
|
/* calculate the number of LBAs that the namespace can accomodate */
|
|
static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
|
|
{
|
|
return ns->size >> nvme_ns_lbads(ns);
|
|
}
|
|
|
|
/* convert an LBA to the equivalent in bytes */
|
|
static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
|
|
{
|
|
return lba << nvme_ns_lbads(ns);
|
|
}
|
|
|
|
typedef struct NvmeCtrl NvmeCtrl;
|
|
|
|
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
|
|
void nvme_ns_drain(NvmeNamespace *ns);
|
|
void nvme_ns_flush(NvmeNamespace *ns);
|
|
|
|
#endif /* NVME_NS_H */
|