qemu/hw/block/nvme-ns.h
<<
>>
Prefs
   1/*
   2 * QEMU NVM Express Virtual Namespace
   3 *
   4 * Copyright (c) 2019 CNEX Labs
   5 * Copyright (c) 2020 Samsung Electronics
   6 *
   7 * Authors:
   8 *  Klaus Jensen      <k.jensen@samsung.com>
   9 *
  10 * This work is licensed under the terms of the GNU GPL, version 2. See the
  11 * COPYING file in the top-level directory.
  12 *
  13 */
  14
  15#ifndef NVME_NS_H
  16#define NVME_NS_H
  17
  18#include "qemu/uuid.h"
  19
  20#define TYPE_NVME_NS "nvme-ns"
  21#define NVME_NS(obj) \
  22    OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
  23
  24typedef struct NvmeZone {
  25    NvmeZoneDescr   d;
  26    uint64_t        w_ptr;
  27    QTAILQ_ENTRY(NvmeZone) entry;
  28} NvmeZone;
  29
  30typedef struct NvmeNamespaceParams {
  31    bool     detached;
  32    bool     shared;
  33    uint32_t nsid;
  34    QemuUUID uuid;
  35
  36    uint16_t ms;
  37    uint8_t  mset;
  38    uint8_t  pi;
  39    uint8_t  pil;
  40
  41    uint16_t mssrl;
  42    uint32_t mcl;
  43    uint8_t  msrc;
  44
  45    bool     zoned;
  46    bool     cross_zone_read;
  47    uint64_t zone_size_bs;
  48    uint64_t zone_cap_bs;
  49    uint32_t max_active_zones;
  50    uint32_t max_open_zones;
  51    uint32_t zd_extension_size;
  52} NvmeNamespaceParams;
  53
  54typedef struct NvmeNamespace {
  55    DeviceState  parent_obj;
  56    BlockConf    blkconf;
  57    int32_t      bootindex;
  58    int64_t      size;
  59    int64_t      mdata_offset;
  60    NvmeIdNs     id_ns;
  61    const uint32_t *iocs;
  62    uint8_t      csi;
  63    uint16_t     status;
  64    int          attached;
  65
  66    QTAILQ_ENTRY(NvmeNamespace) entry;
  67
  68    NvmeIdNsZoned   *id_ns_zoned;
  69    NvmeZone        *zone_array;
  70    QTAILQ_HEAD(, NvmeZone) exp_open_zones;
  71    QTAILQ_HEAD(, NvmeZone) imp_open_zones;
  72    QTAILQ_HEAD(, NvmeZone) closed_zones;
  73    QTAILQ_HEAD(, NvmeZone) full_zones;
  74    uint32_t        num_zones;
  75    uint64_t        zone_size;
  76    uint64_t        zone_capacity;
  77    uint32_t        zone_size_log2;
  78    uint8_t         *zd_extensions;
  79    int32_t         nr_open_zones;
  80    int32_t         nr_active_zones;
  81
  82    NvmeNamespaceParams params;
  83
  84    struct {
  85        uint32_t err_rec;
  86    } features;
  87} NvmeNamespace;
  88
  89static inline uint16_t nvme_ns_status(NvmeNamespace *ns)
  90{
  91    return ns->status;
  92}
  93
  94static inline uint32_t nvme_nsid(NvmeNamespace *ns)
  95{
  96    if (ns) {
  97        return ns->params.nsid;
  98    }
  99
 100    return 0;
 101}
 102
 103static inline NvmeLBAF *nvme_ns_lbaf(NvmeNamespace *ns)
 104{
 105    NvmeIdNs *id_ns = &ns->id_ns;
 106    return &id_ns->lbaf[NVME_ID_NS_FLBAS_INDEX(id_ns->flbas)];
 107}
 108
 109static inline uint8_t nvme_ns_lbads(NvmeNamespace *ns)
 110{
 111    return nvme_ns_lbaf(ns)->ds;
 112}
 113
 114/* convert an LBA to the equivalent in bytes */
 115static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
 116{
 117    return lba << nvme_ns_lbads(ns);
 118}
 119
 120static inline size_t nvme_lsize(NvmeNamespace *ns)
 121{
 122    return 1 << nvme_ns_lbads(ns);
 123}
 124
 125static inline uint16_t nvme_msize(NvmeNamespace *ns)
 126{
 127    return nvme_ns_lbaf(ns)->ms;
 128}
 129
 130static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
 131{
 132    return nvme_msize(ns) * lba;
 133}
 134
 135static inline bool nvme_ns_ext(NvmeNamespace *ns)
 136{
 137    return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
 138}
 139
 140/* calculate the number of LBAs that the namespace can accomodate */
 141static inline uint64_t nvme_ns_nlbas(NvmeNamespace *ns)
 142{
 143    if (nvme_msize(ns)) {
 144        return ns->size / (nvme_lsize(ns) + nvme_msize(ns));
 145    }
 146    return ns->size >> nvme_ns_lbads(ns);
 147}
 148
 149typedef struct NvmeCtrl NvmeCtrl;
 150
 151static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
 152{
 153    return zone->d.zs >> 4;
 154}
 155
 156static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
 157{
 158    zone->d.zs = state << 4;
 159}
 160
 161static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
 162{
 163    return zone->d.zslba + ns->zone_size;
 164}
 165
 166static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
 167{
 168    return zone->d.zslba + zone->d.zcap;
 169}
 170
 171static inline bool nvme_wp_is_valid(NvmeZone *zone)
 172{
 173    uint8_t st = nvme_get_zone_state(zone);
 174
 175    return st != NVME_ZONE_STATE_FULL &&
 176           st != NVME_ZONE_STATE_READ_ONLY &&
 177           st != NVME_ZONE_STATE_OFFLINE;
 178}
 179
 180static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
 181                                             uint32_t zone_idx)
 182{
 183    return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
 184}
 185
 186static inline void nvme_aor_inc_open(NvmeNamespace *ns)
 187{
 188    assert(ns->nr_open_zones >= 0);
 189    if (ns->params.max_open_zones) {
 190        ns->nr_open_zones++;
 191        assert(ns->nr_open_zones <= ns->params.max_open_zones);
 192    }
 193}
 194
 195static inline void nvme_aor_dec_open(NvmeNamespace *ns)
 196{
 197    if (ns->params.max_open_zones) {
 198        assert(ns->nr_open_zones > 0);
 199        ns->nr_open_zones--;
 200    }
 201    assert(ns->nr_open_zones >= 0);
 202}
 203
 204static inline void nvme_aor_inc_active(NvmeNamespace *ns)
 205{
 206    assert(ns->nr_active_zones >= 0);
 207    if (ns->params.max_active_zones) {
 208        ns->nr_active_zones++;
 209        assert(ns->nr_active_zones <= ns->params.max_active_zones);
 210    }
 211}
 212
 213static inline void nvme_aor_dec_active(NvmeNamespace *ns)
 214{
 215    if (ns->params.max_active_zones) {
 216        assert(ns->nr_active_zones > 0);
 217        ns->nr_active_zones--;
 218        assert(ns->nr_active_zones >= ns->nr_open_zones);
 219    }
 220    assert(ns->nr_active_zones >= 0);
 221}
 222
 223void nvme_ns_init_format(NvmeNamespace *ns);
 224int nvme_ns_setup(NvmeCtrl *n, NvmeNamespace *ns, Error **errp);
 225void nvme_ns_drain(NvmeNamespace *ns);
 226void nvme_ns_shutdown(NvmeNamespace *ns);
 227void nvme_ns_cleanup(NvmeNamespace *ns);
 228
 229#endif /* NVME_NS_H */
 230