hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
/*
|
|
|
|
* 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
|
|
|
|
|
2021-02-04 16:55:48 +08:00
|
|
|
#include "qemu/uuid.h"
|
|
|
|
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
#define TYPE_NVME_NS "nvme-ns"
|
|
|
|
#define NVME_NS(obj) \
|
|
|
|
OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
|
|
|
|
|
2020-12-09 04:04:06 +08:00
|
|
|
typedef struct NvmeZone {
|
|
|
|
NvmeZoneDescr d;
|
|
|
|
uint64_t w_ptr;
|
|
|
|
QTAILQ_ENTRY(NvmeZone) entry;
|
|
|
|
} NvmeZone;
|
|
|
|
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
typedef struct NvmeNamespaceParams {
|
hw/block/nvme: support namespace detach
Given that now we have nvme-subsys device supported, we can manage
namespace allocated, but not attached: detached. This patch introduced
a parameter for nvme-ns device named 'detached'. This parameter
indicates whether the given namespace device is detached from
a entire NVMe subsystem('subsys' given case, shared namespace) or a
controller('bus' given case, private namespace).
- Allocated namespace
1) Shared ns in the subsystem 'subsys0':
-device nvme-ns,id=ns1,drive=blknvme0,nsid=1,subsys=subsys0,detached=true
2) Private ns for the controller 'nvme0' of the subsystem 'subsys0':
-device nvme-subsys,id=subsys0
-device nvme,serial=foo,id=nvme0,subsys=subsys0
-device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true
3) (Invalid case) Controller 'nvme0' has no subsystem to manage ns:
-device nvme,serial=foo,id=nvme0
-device nvme-ns,id=ns1,drive=blknvme0,nsid=1,bus=nvme0,detached=true
Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
2021-02-05 23:30:10 +08:00
|
|
|
bool detached;
|
hw/block/nvme: fix handling of private namespaces
Prior to this patch, if a private nvme-ns device (that is, a namespace
that is not linked to a subsystem) is wired up to an nvme-subsys linked
nvme controller device, the device fails to verify that the namespace id
is unique within the subsystem. NVM Express v1.4b, Section 6.1.6 ("NSID
and Namespace Usage") states that because the device supports Namespace
Management, "NSIDs *shall* be unique within the NVM subsystem".
Additionally, prior to this patch, private namespaces are not known to
the subsystem and the namespace is considered exclusive to the
controller with which it is initially wired up to. However, this is not
the definition of a private namespace; per Section 1.6.33 ("private
namespace"), a private namespace is just a namespace that does not
support multipath I/O or namespace sharing, which means "that it is only
able to be attached to one controller at a time".
Fix this by always allocating namespaces in the subsystem (if one is
linked to the controller), regardless of the shared/private status of
the namespace. Whether or not the namespace is shareable is controlled
by a new `shared` nvme-ns parameter.
Finally, this fix allows the nvme-ns `subsys` parameter to be removed,
since the `shared` parameter now serves the purpose of attaching the
namespace to all controllers in the subsystem upon device realization.
It is invalid to have an nvme-ns namespace device with a linked
subsystem without the parent nvme controller device also being linked to
one and since the nvme-ns devices will unconditionally be "attached" (in
QEMU terms that is) to an nvme controller device through an NvmeBus, the
nvme-ns namespace device can always get a reference to the subsystem of
the controller it is explicitly (using 'bus=' parameter) or implicitly
attaching to.
Fixes: e570768566b3 ("hw/block/nvme: support for shared namespace in subsystem")
Cc: Minwoo Im <minwoo.im.dev@gmail.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Minwoo Im <minwoo.im.dev@gmail.com>
2021-03-23 19:43:24 +08:00
|
|
|
bool shared;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
uint32_t nsid;
|
2020-12-09 04:03:59 +08:00
|
|
|
QemuUUID uuid;
|
2020-12-09 04:04:06 +08:00
|
|
|
|
2020-11-23 18:24:55 +08:00
|
|
|
uint16_t ms;
|
|
|
|
uint8_t mset;
|
2021-02-04 16:55:48 +08:00
|
|
|
uint8_t pi;
|
|
|
|
uint8_t pil;
|
2020-11-23 18:24:55 +08:00
|
|
|
|
2020-11-06 17:46:01 +08:00
|
|
|
uint16_t mssrl;
|
|
|
|
uint32_t mcl;
|
|
|
|
uint8_t msrc;
|
|
|
|
|
2020-12-09 04:04:06 +08:00
|
|
|
bool zoned;
|
|
|
|
bool cross_zone_read;
|
|
|
|
uint64_t zone_size_bs;
|
|
|
|
uint64_t zone_cap_bs;
|
2020-12-09 04:04:07 +08:00
|
|
|
uint32_t max_active_zones;
|
|
|
|
uint32_t max_open_zones;
|
2020-12-09 04:04:08 +08:00
|
|
|
uint32_t zd_extension_size;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
} NvmeNamespaceParams;
|
|
|
|
|
|
|
|
typedef struct NvmeNamespace {
|
|
|
|
DeviceState parent_obj;
|
|
|
|
BlockConf blkconf;
|
|
|
|
int32_t bootindex;
|
|
|
|
int64_t size;
|
2020-11-23 18:24:55 +08:00
|
|
|
int64_t mdata_offset;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
NvmeIdNs id_ns;
|
2020-12-09 04:04:02 +08:00
|
|
|
const uint32_t *iocs;
|
2020-12-09 04:04:03 +08:00
|
|
|
uint8_t csi;
|
2021-02-12 20:11:39 +08:00
|
|
|
uint16_t status;
|
hw/block/nvme: fix handling of private namespaces
Prior to this patch, if a private nvme-ns device (that is, a namespace
that is not linked to a subsystem) is wired up to an nvme-subsys linked
nvme controller device, the device fails to verify that the namespace id
is unique within the subsystem. NVM Express v1.4b, Section 6.1.6 ("NSID
and Namespace Usage") states that because the device supports Namespace
Management, "NSIDs *shall* be unique within the NVM subsystem".
Additionally, prior to this patch, private namespaces are not known to
the subsystem and the namespace is considered exclusive to the
controller with which it is initially wired up to. However, this is not
the definition of a private namespace; per Section 1.6.33 ("private
namespace"), a private namespace is just a namespace that does not
support multipath I/O or namespace sharing, which means "that it is only
able to be attached to one controller at a time".
Fix this by always allocating namespaces in the subsystem (if one is
linked to the controller), regardless of the shared/private status of
the namespace. Whether or not the namespace is shareable is controlled
by a new `shared` nvme-ns parameter.
Finally, this fix allows the nvme-ns `subsys` parameter to be removed,
since the `shared` parameter now serves the purpose of attaching the
namespace to all controllers in the subsystem upon device realization.
It is invalid to have an nvme-ns namespace device with a linked
subsystem without the parent nvme controller device also being linked to
one and since the nvme-ns devices will unconditionally be "attached" (in
QEMU terms that is) to an nvme controller device through an NvmeBus, the
nvme-ns namespace device can always get a reference to the subsystem of
the controller it is explicitly (using 'bus=' parameter) or implicitly
attaching to.
Fixes: e570768566b3 ("hw/block/nvme: support for shared namespace in subsystem")
Cc: Minwoo Im <minwoo.im.dev@gmail.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Minwoo Im <minwoo.im.dev@gmail.com>
2021-03-23 19:43:24 +08:00
|
|
|
int attached;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
|
2021-02-28 16:51:02 +08:00
|
|
|
QTAILQ_ENTRY(NvmeNamespace) entry;
|
hw/block/nvme: support for shared namespace in subsystem
nvme-ns device is registered to a nvme controller device during the
initialization in nvme_register_namespace() in case that 'bus' property
is given which means it's mapped to a single controller.
This patch introduced a new property 'subsys' just like the controller
device instance did to map a namespace to a NVMe subsystem.
If 'subsys' property is given to the nvme-ns device, it will belong to
the specified subsystem and will be attached to all controllers in that
subsystem by enabling shared namespace capability in NMIC(Namespace
Multi-path I/O and Namespace Capabilities) in Identify Namespace.
Usage:
-device nvme-subsys,id=subsys0
-device nvme,serial=foo,id=nvme0,subsys=subsys0
-device nvme,serial=bar,id=nvme1,subsys=subsys0
-device nvme,serial=baz,id=nvme2,subsys=subsys0
-device nvme-ns,id=ns1,drive=<drv>,nsid=1,subsys=subsys0 # Shared
-device nvme-ns,id=ns2,drive=<drv>,nsid=2,bus=nvme2 # Non-shared
In the above example, 'ns1' will be shared to 'nvme0' and 'nvme1' in
the same subsystem. On the other hand, 'ns2' will be attached to the
'nvme2' only as a private namespace in that subsystem.
All the namespace with 'subsys' parameter will attach all controllers in
the subsystem to the namespace by default.
Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
Tested-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
2021-01-24 10:54:50 +08:00
|
|
|
|
2020-12-09 04:04:06 +08:00
|
|
|
NvmeIdNsZoned *id_ns_zoned;
|
|
|
|
NvmeZone *zone_array;
|
|
|
|
QTAILQ_HEAD(, NvmeZone) exp_open_zones;
|
|
|
|
QTAILQ_HEAD(, NvmeZone) imp_open_zones;
|
|
|
|
QTAILQ_HEAD(, NvmeZone) closed_zones;
|
|
|
|
QTAILQ_HEAD(, NvmeZone) full_zones;
|
|
|
|
uint32_t num_zones;
|
|
|
|
uint64_t zone_size;
|
|
|
|
uint64_t zone_capacity;
|
|
|
|
uint32_t zone_size_log2;
|
2020-12-09 04:04:08 +08:00
|
|
|
uint8_t *zd_extensions;
|
2020-12-09 04:04:07 +08:00
|
|
|
int32_t nr_open_zones;
|
|
|
|
int32_t nr_active_zones;
|
2020-12-09 04:04:06 +08:00
|
|
|
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
NvmeNamespaceParams params;
|
2020-10-14 15:55:08 +08:00
|
|
|
|
|
|
|
struct {
|
|
|
|
uint32_t err_rec;
|
|
|
|
} features;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
} NvmeNamespace;
|
|
|
|
|
2021-02-12 20:11:39 +08:00
|
|
|
static inline uint16_t nvme_ns_status(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
return ns->status;
|
|
|
|
}
|
|
|
|
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
static inline uint32_t nvme_nsid(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
if (ns) {
|
|
|
|
return ns->params.nsid;
|
|
|
|
}
|
|
|
|
|
2021-03-24 17:11:55 +08:00
|
|
|
return 0;
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2020-11-23 18:24:55 +08:00
|
|
|
static inline size_t nvme_lsize(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
return 1 << nvme_ns_lbads(ns);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint16_t nvme_msize(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
return nvme_ns_lbaf(ns)->ms;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
|
|
|
|
{
|
|
|
|
return nvme_msize(ns) * lba;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool nvme_ns_ext(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* calculate the number of LBAs that the namespace can accomodate */
|
|
|
|
static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
|
|
|
|
{
|
2021-03-08 16:09:35 +08:00
|
|
|
if (nvme_msize(ns)) {
|
2020-11-23 18:24:55 +08:00
|
|
|
return ns->size / (nvme_lsize(ns) + nvme_msize(ns));
|
|
|
|
}
|
|
|
|
return ns->size >> nvme_ns_lbads(ns);
|
|
|
|
}
|
|
|
|
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
typedef struct NvmeCtrl NvmeCtrl;
|
|
|
|
|
2020-12-10 06:12:49 +08:00
|
|
|
static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
|
2020-12-09 04:04:06 +08:00
|
|
|
{
|
|
|
|
return zone->d.zs >> 4;
|
|
|
|
}
|
|
|
|
|
2020-12-10 06:12:49 +08:00
|
|
|
static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
|
2020-12-09 04:04:06 +08:00
|
|
|
{
|
|
|
|
zone->d.zs = state << 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
|
|
|
|
{
|
|
|
|
return zone->d.zslba + ns->zone_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
|
|
|
|
{
|
|
|
|
return zone->d.zslba + zone->d.zcap;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool nvme_wp_is_valid(NvmeZone *zone)
|
|
|
|
{
|
|
|
|
uint8_t st = nvme_get_zone_state(zone);
|
|
|
|
|
|
|
|
return st != NVME_ZONE_STATE_FULL &&
|
|
|
|
st != NVME_ZONE_STATE_READ_ONLY &&
|
|
|
|
st != NVME_ZONE_STATE_OFFLINE;
|
|
|
|
}
|
|
|
|
|
2020-12-09 04:04:08 +08:00
|
|
|
static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
|
|
|
|
uint32_t zone_idx)
|
|
|
|
{
|
|
|
|
return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
|
|
|
|
}
|
|
|
|
|
2020-12-09 04:04:07 +08:00
|
|
|
static inline void nvme_aor_inc_open(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
assert(ns->nr_open_zones >= 0);
|
|
|
|
if (ns->params.max_open_zones) {
|
|
|
|
ns->nr_open_zones++;
|
|
|
|
assert(ns->nr_open_zones <= ns->params.max_open_zones);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void nvme_aor_dec_open(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
if (ns->params.max_open_zones) {
|
|
|
|
assert(ns->nr_open_zones > 0);
|
|
|
|
ns->nr_open_zones--;
|
|
|
|
}
|
|
|
|
assert(ns->nr_open_zones >= 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void nvme_aor_inc_active(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
assert(ns->nr_active_zones >= 0);
|
|
|
|
if (ns->params.max_active_zones) {
|
|
|
|
ns->nr_active_zones++;
|
|
|
|
assert(ns->nr_active_zones <= ns->params.max_active_zones);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void nvme_aor_dec_active(NvmeNamespace *ns)
|
|
|
|
{
|
|
|
|
if (ns->params.max_active_zones) {
|
|
|
|
assert(ns->nr_active_zones > 0);
|
|
|
|
ns->nr_active_zones--;
|
|
|
|
assert(ns->nr_active_zones >= ns->nr_open_zones);
|
|
|
|
}
|
|
|
|
assert(ns->nr_active_zones >= 0);
|
|
|
|
}
|
|
|
|
|
2021-02-12 20:11:39 +08:00
|
|
|
void nvme_ns_init_format(NvmeNamespace *ns);
|
hw/block/nvme: fix handling of private namespaces
Prior to this patch, if a private nvme-ns device (that is, a namespace
that is not linked to a subsystem) is wired up to an nvme-subsys linked
nvme controller device, the device fails to verify that the namespace id
is unique within the subsystem. NVM Express v1.4b, Section 6.1.6 ("NSID
and Namespace Usage") states that because the device supports Namespace
Management, "NSIDs *shall* be unique within the NVM subsystem".
Additionally, prior to this patch, private namespaces are not known to
the subsystem and the namespace is considered exclusive to the
controller with which it is initially wired up to. However, this is not
the definition of a private namespace; per Section 1.6.33 ("private
namespace"), a private namespace is just a namespace that does not
support multipath I/O or namespace sharing, which means "that it is only
able to be attached to one controller at a time".
Fix this by always allocating namespaces in the subsystem (if one is
linked to the controller), regardless of the shared/private status of
the namespace. Whether or not the namespace is shareable is controlled
by a new `shared` nvme-ns parameter.
Finally, this fix allows the nvme-ns `subsys` parameter to be removed,
since the `shared` parameter now serves the purpose of attaching the
namespace to all controllers in the subsystem upon device realization.
It is invalid to have an nvme-ns namespace device with a linked
subsystem without the parent nvme controller device also being linked to
one and since the nvme-ns devices will unconditionally be "attached" (in
QEMU terms that is) to an nvme controller device through an NvmeBus, the
nvme-ns namespace device can always get a reference to the subsystem of
the controller it is explicitly (using 'bus=' parameter) or implicitly
attaching to.
Fixes: e570768566b3 ("hw/block/nvme: support for shared namespace in subsystem")
Cc: Minwoo Im <minwoo.im.dev@gmail.com>
Signed-off-by: Klaus Jensen <k.jensen@samsung.com>
Reviewed-by: Gollu Appalanaidu <anaidu.gollu@samsung.com>
Reviewed-by: Keith Busch <kbusch@kernel.org>
Reviewed-by: Minwoo Im <minwoo.im.dev@gmail.com>
2021-03-23 19:43:24 +08:00
|
|
|
int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
void nvme_ns_drain(NvmeNamespace *ns);
|
2020-12-09 04:03:58 +08:00
|
|
|
void nvme_ns_shutdown(NvmeNamespace *ns);
|
2020-12-09 04:04:06 +08:00
|
|
|
void nvme_ns_cleanup(NvmeNamespace *ns);
|
hw/block/nvme: support multiple namespaces
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>
2019-06-26 14:51:06 +08:00
|
|
|
|
|
|
|
#endif /* NVME_NS_H */
|