xref: /openbmc/qemu/hw/nvme/nvme.h (revision b0fde9e86133f66c054b31722fa29640f57e975c)
188eea45cSKlaus Jensen /*
288eea45cSKlaus Jensen  * QEMU NVM Express
388eea45cSKlaus Jensen  *
488eea45cSKlaus Jensen  * Copyright (c) 2012 Intel Corporation
588eea45cSKlaus Jensen  * Copyright (c) 2021 Minwoo Im
688eea45cSKlaus Jensen  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
788eea45cSKlaus Jensen  *
888eea45cSKlaus Jensen  * Authors:
988eea45cSKlaus Jensen  *   Keith Busch            <kbusch@kernel.org>
1088eea45cSKlaus Jensen  *   Klaus Jensen           <k.jensen@samsung.com>
1188eea45cSKlaus Jensen  *   Gollu Appalanaidu      <anaidu.gollu@samsung.com>
1288eea45cSKlaus Jensen  *   Dmitry Fomichev        <dmitry.fomichev@wdc.com>
1388eea45cSKlaus Jensen  *   Minwoo Im              <minwoo.im.dev@gmail.com>
1488eea45cSKlaus Jensen  *
1588eea45cSKlaus Jensen  * This code is licensed under the GNU GPL v2 or later.
1688eea45cSKlaus Jensen  */
1788eea45cSKlaus Jensen 
1888eea45cSKlaus Jensen #ifndef HW_NVME_INTERNAL_H
1988eea45cSKlaus Jensen #define HW_NVME_INTERNAL_H
2088eea45cSKlaus Jensen 
2188eea45cSKlaus Jensen #include "qemu/uuid.h"
2288eea45cSKlaus Jensen #include "hw/pci/pci.h"
2388eea45cSKlaus Jensen #include "hw/block/block.h"
2488eea45cSKlaus Jensen 
2588eea45cSKlaus Jensen #include "block/nvme.h"
2688eea45cSKlaus Jensen 
2788eea45cSKlaus Jensen #define NVME_MAX_CONTROLLERS 32
2888eea45cSKlaus Jensen #define NVME_MAX_NAMESPACES  256
293276dde4SHeinrich Schuchardt #define NVME_EUI64_DEFAULT ((uint64_t)0x5254000000000000)
3088eea45cSKlaus Jensen 
3138f4ac65SKlaus Jensen QEMU_BUILD_BUG_ON(NVME_MAX_NAMESPACES > NVME_NSID_BROADCAST - 1);
3238f4ac65SKlaus Jensen 
3388eea45cSKlaus Jensen typedef struct NvmeCtrl NvmeCtrl;
3488eea45cSKlaus Jensen typedef struct NvmeNamespace NvmeNamespace;
3588eea45cSKlaus Jensen 
3688eea45cSKlaus Jensen #define TYPE_NVME_SUBSYS "nvme-subsys"
3788eea45cSKlaus Jensen #define NVME_SUBSYS(obj) \
3888eea45cSKlaus Jensen     OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)
3988eea45cSKlaus Jensen 
4088eea45cSKlaus Jensen typedef struct NvmeSubsystem {
4188eea45cSKlaus Jensen     DeviceState parent_obj;
4288eea45cSKlaus Jensen     uint8_t     subnqn[256];
4388eea45cSKlaus Jensen 
4488eea45cSKlaus Jensen     NvmeCtrl      *ctrls[NVME_MAX_CONTROLLERS];
4588eea45cSKlaus Jensen     NvmeNamespace *namespaces[NVME_MAX_NAMESPACES + 1];
4688eea45cSKlaus Jensen 
4788eea45cSKlaus Jensen     struct {
4888eea45cSKlaus Jensen         char *nqn;
4988eea45cSKlaus Jensen     } params;
5088eea45cSKlaus Jensen } NvmeSubsystem;
5188eea45cSKlaus Jensen 
5288eea45cSKlaus Jensen int nvme_subsys_register_ctrl(NvmeCtrl *n, Error **errp);
53*b0fde9e8SKlaus Jensen void nvme_subsys_unregister_ctrl(NvmeSubsystem *subsys, NvmeCtrl *n);
5488eea45cSKlaus Jensen 
5588eea45cSKlaus Jensen static inline NvmeCtrl *nvme_subsys_ctrl(NvmeSubsystem *subsys,
5688eea45cSKlaus Jensen                                          uint32_t cntlid)
5788eea45cSKlaus Jensen {
5888eea45cSKlaus Jensen     if (!subsys || cntlid >= NVME_MAX_CONTROLLERS) {
5988eea45cSKlaus Jensen         return NULL;
6088eea45cSKlaus Jensen     }
6188eea45cSKlaus Jensen 
6288eea45cSKlaus Jensen     return subsys->ctrls[cntlid];
6388eea45cSKlaus Jensen }
6488eea45cSKlaus Jensen 
6588eea45cSKlaus Jensen static inline NvmeNamespace *nvme_subsys_ns(NvmeSubsystem *subsys,
6688eea45cSKlaus Jensen                                             uint32_t nsid)
6788eea45cSKlaus Jensen {
6888eea45cSKlaus Jensen     if (!subsys || !nsid || nsid > NVME_MAX_NAMESPACES) {
6988eea45cSKlaus Jensen         return NULL;
7088eea45cSKlaus Jensen     }
7188eea45cSKlaus Jensen 
7288eea45cSKlaus Jensen     return subsys->namespaces[nsid];
7388eea45cSKlaus Jensen }
7488eea45cSKlaus Jensen 
7588eea45cSKlaus Jensen #define TYPE_NVME_NS "nvme-ns"
7688eea45cSKlaus Jensen #define NVME_NS(obj) \
7788eea45cSKlaus Jensen     OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
7888eea45cSKlaus Jensen 
7988eea45cSKlaus Jensen typedef struct NvmeZone {
8088eea45cSKlaus Jensen     NvmeZoneDescr   d;
8188eea45cSKlaus Jensen     uint64_t        w_ptr;
8288eea45cSKlaus Jensen     QTAILQ_ENTRY(NvmeZone) entry;
8388eea45cSKlaus Jensen } NvmeZone;
8488eea45cSKlaus Jensen 
8588eea45cSKlaus Jensen typedef struct NvmeNamespaceParams {
8688eea45cSKlaus Jensen     bool     detached;
8788eea45cSKlaus Jensen     bool     shared;
8888eea45cSKlaus Jensen     uint32_t nsid;
8988eea45cSKlaus Jensen     QemuUUID uuid;
906870cfb8SHeinrich Schuchardt     uint64_t eui64;
913276dde4SHeinrich Schuchardt     bool     eui64_default;
9288eea45cSKlaus Jensen 
9388eea45cSKlaus Jensen     uint16_t ms;
9488eea45cSKlaus Jensen     uint8_t  mset;
9588eea45cSKlaus Jensen     uint8_t  pi;
9688eea45cSKlaus Jensen     uint8_t  pil;
9788eea45cSKlaus Jensen 
9888eea45cSKlaus Jensen     uint16_t mssrl;
9988eea45cSKlaus Jensen     uint32_t mcl;
10088eea45cSKlaus Jensen     uint8_t  msrc;
10188eea45cSKlaus Jensen 
10288eea45cSKlaus Jensen     bool     zoned;
10388eea45cSKlaus Jensen     bool     cross_zone_read;
10488eea45cSKlaus Jensen     uint64_t zone_size_bs;
10588eea45cSKlaus Jensen     uint64_t zone_cap_bs;
10688eea45cSKlaus Jensen     uint32_t max_active_zones;
10788eea45cSKlaus Jensen     uint32_t max_open_zones;
10888eea45cSKlaus Jensen     uint32_t zd_extension_size;
10988eea45cSKlaus Jensen } NvmeNamespaceParams;
11088eea45cSKlaus Jensen 
11188eea45cSKlaus Jensen typedef struct NvmeNamespace {
11288eea45cSKlaus Jensen     DeviceState  parent_obj;
11388eea45cSKlaus Jensen     BlockConf    blkconf;
11488eea45cSKlaus Jensen     int32_t      bootindex;
11588eea45cSKlaus Jensen     int64_t      size;
11688eea45cSKlaus Jensen     int64_t      moff;
11788eea45cSKlaus Jensen     NvmeIdNs     id_ns;
11888eea45cSKlaus Jensen     NvmeLBAF     lbaf;
11988eea45cSKlaus Jensen     size_t       lbasz;
12088eea45cSKlaus Jensen     const uint32_t *iocs;
12188eea45cSKlaus Jensen     uint8_t      csi;
12288eea45cSKlaus Jensen     uint16_t     status;
12388eea45cSKlaus Jensen     int          attached;
12488eea45cSKlaus Jensen 
12588eea45cSKlaus Jensen     QTAILQ_ENTRY(NvmeNamespace) entry;
12688eea45cSKlaus Jensen 
12788eea45cSKlaus Jensen     NvmeIdNsZoned   *id_ns_zoned;
12888eea45cSKlaus Jensen     NvmeZone        *zone_array;
12988eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeZone) exp_open_zones;
13088eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeZone) imp_open_zones;
13188eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeZone) closed_zones;
13288eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeZone) full_zones;
13388eea45cSKlaus Jensen     uint32_t        num_zones;
13488eea45cSKlaus Jensen     uint64_t        zone_size;
13588eea45cSKlaus Jensen     uint64_t        zone_capacity;
13688eea45cSKlaus Jensen     uint32_t        zone_size_log2;
13788eea45cSKlaus Jensen     uint8_t         *zd_extensions;
13888eea45cSKlaus Jensen     int32_t         nr_open_zones;
13988eea45cSKlaus Jensen     int32_t         nr_active_zones;
14088eea45cSKlaus Jensen 
14188eea45cSKlaus Jensen     NvmeNamespaceParams params;
14288eea45cSKlaus Jensen 
14388eea45cSKlaus Jensen     struct {
14488eea45cSKlaus Jensen         uint32_t err_rec;
14588eea45cSKlaus Jensen     } features;
14688eea45cSKlaus Jensen } NvmeNamespace;
14788eea45cSKlaus Jensen 
14888eea45cSKlaus Jensen static inline uint32_t nvme_nsid(NvmeNamespace *ns)
14988eea45cSKlaus Jensen {
15088eea45cSKlaus Jensen     if (ns) {
15188eea45cSKlaus Jensen         return ns->params.nsid;
15288eea45cSKlaus Jensen     }
15388eea45cSKlaus Jensen 
15488eea45cSKlaus Jensen     return 0;
15588eea45cSKlaus Jensen }
15688eea45cSKlaus Jensen 
15788eea45cSKlaus Jensen static inline size_t nvme_l2b(NvmeNamespace *ns, uint64_t lba)
15888eea45cSKlaus Jensen {
15988eea45cSKlaus Jensen     return lba << ns->lbaf.ds;
16088eea45cSKlaus Jensen }
16188eea45cSKlaus Jensen 
16288eea45cSKlaus Jensen static inline size_t nvme_m2b(NvmeNamespace *ns, uint64_t lba)
16388eea45cSKlaus Jensen {
16488eea45cSKlaus Jensen     return ns->lbaf.ms * lba;
16588eea45cSKlaus Jensen }
16688eea45cSKlaus Jensen 
16788eea45cSKlaus Jensen static inline int64_t nvme_moff(NvmeNamespace *ns, uint64_t lba)
16888eea45cSKlaus Jensen {
16988eea45cSKlaus Jensen     return ns->moff + nvme_m2b(ns, lba);
17088eea45cSKlaus Jensen }
17188eea45cSKlaus Jensen 
17288eea45cSKlaus Jensen static inline bool nvme_ns_ext(NvmeNamespace *ns)
17388eea45cSKlaus Jensen {
17488eea45cSKlaus Jensen     return !!NVME_ID_NS_FLBAS_EXTENDED(ns->id_ns.flbas);
17588eea45cSKlaus Jensen }
17688eea45cSKlaus Jensen 
17788eea45cSKlaus Jensen static inline NvmeZoneState nvme_get_zone_state(NvmeZone *zone)
17888eea45cSKlaus Jensen {
17988eea45cSKlaus Jensen     return zone->d.zs >> 4;
18088eea45cSKlaus Jensen }
18188eea45cSKlaus Jensen 
18288eea45cSKlaus Jensen static inline void nvme_set_zone_state(NvmeZone *zone, NvmeZoneState state)
18388eea45cSKlaus Jensen {
18488eea45cSKlaus Jensen     zone->d.zs = state << 4;
18588eea45cSKlaus Jensen }
18688eea45cSKlaus Jensen 
18788eea45cSKlaus Jensen static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace *ns, NvmeZone *zone)
18888eea45cSKlaus Jensen {
18988eea45cSKlaus Jensen     return zone->d.zslba + ns->zone_size;
19088eea45cSKlaus Jensen }
19188eea45cSKlaus Jensen 
19288eea45cSKlaus Jensen static inline uint64_t nvme_zone_wr_boundary(NvmeZone *zone)
19388eea45cSKlaus Jensen {
19488eea45cSKlaus Jensen     return zone->d.zslba + zone->d.zcap;
19588eea45cSKlaus Jensen }
19688eea45cSKlaus Jensen 
19788eea45cSKlaus Jensen static inline bool nvme_wp_is_valid(NvmeZone *zone)
19888eea45cSKlaus Jensen {
19988eea45cSKlaus Jensen     uint8_t st = nvme_get_zone_state(zone);
20088eea45cSKlaus Jensen 
20188eea45cSKlaus Jensen     return st != NVME_ZONE_STATE_FULL &&
20288eea45cSKlaus Jensen            st != NVME_ZONE_STATE_READ_ONLY &&
20388eea45cSKlaus Jensen            st != NVME_ZONE_STATE_OFFLINE;
20488eea45cSKlaus Jensen }
20588eea45cSKlaus Jensen 
20688eea45cSKlaus Jensen static inline uint8_t *nvme_get_zd_extension(NvmeNamespace *ns,
20788eea45cSKlaus Jensen                                              uint32_t zone_idx)
20888eea45cSKlaus Jensen {
20988eea45cSKlaus Jensen     return &ns->zd_extensions[zone_idx * ns->params.zd_extension_size];
21088eea45cSKlaus Jensen }
21188eea45cSKlaus Jensen 
21288eea45cSKlaus Jensen static inline void nvme_aor_inc_open(NvmeNamespace *ns)
21388eea45cSKlaus Jensen {
21488eea45cSKlaus Jensen     assert(ns->nr_open_zones >= 0);
21588eea45cSKlaus Jensen     if (ns->params.max_open_zones) {
21688eea45cSKlaus Jensen         ns->nr_open_zones++;
21788eea45cSKlaus Jensen         assert(ns->nr_open_zones <= ns->params.max_open_zones);
21888eea45cSKlaus Jensen     }
21988eea45cSKlaus Jensen }
22088eea45cSKlaus Jensen 
22188eea45cSKlaus Jensen static inline void nvme_aor_dec_open(NvmeNamespace *ns)
22288eea45cSKlaus Jensen {
22388eea45cSKlaus Jensen     if (ns->params.max_open_zones) {
22488eea45cSKlaus Jensen         assert(ns->nr_open_zones > 0);
22588eea45cSKlaus Jensen         ns->nr_open_zones--;
22688eea45cSKlaus Jensen     }
22788eea45cSKlaus Jensen     assert(ns->nr_open_zones >= 0);
22888eea45cSKlaus Jensen }
22988eea45cSKlaus Jensen 
23088eea45cSKlaus Jensen static inline void nvme_aor_inc_active(NvmeNamespace *ns)
23188eea45cSKlaus Jensen {
23288eea45cSKlaus Jensen     assert(ns->nr_active_zones >= 0);
23388eea45cSKlaus Jensen     if (ns->params.max_active_zones) {
23488eea45cSKlaus Jensen         ns->nr_active_zones++;
23588eea45cSKlaus Jensen         assert(ns->nr_active_zones <= ns->params.max_active_zones);
23688eea45cSKlaus Jensen     }
23788eea45cSKlaus Jensen }
23888eea45cSKlaus Jensen 
23988eea45cSKlaus Jensen static inline void nvme_aor_dec_active(NvmeNamespace *ns)
24088eea45cSKlaus Jensen {
24188eea45cSKlaus Jensen     if (ns->params.max_active_zones) {
24288eea45cSKlaus Jensen         assert(ns->nr_active_zones > 0);
24388eea45cSKlaus Jensen         ns->nr_active_zones--;
24488eea45cSKlaus Jensen         assert(ns->nr_active_zones >= ns->nr_open_zones);
24588eea45cSKlaus Jensen     }
24688eea45cSKlaus Jensen     assert(ns->nr_active_zones >= 0);
24788eea45cSKlaus Jensen }
24888eea45cSKlaus Jensen 
24988eea45cSKlaus Jensen void nvme_ns_init_format(NvmeNamespace *ns);
2505e4f6bccSKlaus Jensen int nvme_ns_setup(NvmeNamespace *ns, Error **errp);
25188eea45cSKlaus Jensen void nvme_ns_drain(NvmeNamespace *ns);
25288eea45cSKlaus Jensen void nvme_ns_shutdown(NvmeNamespace *ns);
25388eea45cSKlaus Jensen void nvme_ns_cleanup(NvmeNamespace *ns);
25488eea45cSKlaus Jensen 
25588eea45cSKlaus Jensen typedef struct NvmeAsyncEvent {
25688eea45cSKlaus Jensen     QTAILQ_ENTRY(NvmeAsyncEvent) entry;
25788eea45cSKlaus Jensen     NvmeAerResult result;
25888eea45cSKlaus Jensen } NvmeAsyncEvent;
25988eea45cSKlaus Jensen 
26088eea45cSKlaus Jensen enum {
26188eea45cSKlaus Jensen     NVME_SG_ALLOC = 1 << 0,
26288eea45cSKlaus Jensen     NVME_SG_DMA   = 1 << 1,
26388eea45cSKlaus Jensen };
26488eea45cSKlaus Jensen 
26588eea45cSKlaus Jensen typedef struct NvmeSg {
26688eea45cSKlaus Jensen     int flags;
26788eea45cSKlaus Jensen 
26888eea45cSKlaus Jensen     union {
26988eea45cSKlaus Jensen         QEMUSGList   qsg;
27088eea45cSKlaus Jensen         QEMUIOVector iov;
27188eea45cSKlaus Jensen     };
27288eea45cSKlaus Jensen } NvmeSg;
27388eea45cSKlaus Jensen 
27488eea45cSKlaus Jensen typedef enum NvmeTxDirection {
27588eea45cSKlaus Jensen     NVME_TX_DIRECTION_TO_DEVICE   = 0,
27688eea45cSKlaus Jensen     NVME_TX_DIRECTION_FROM_DEVICE = 1,
27788eea45cSKlaus Jensen } NvmeTxDirection;
27888eea45cSKlaus Jensen 
27988eea45cSKlaus Jensen typedef struct NvmeRequest {
28088eea45cSKlaus Jensen     struct NvmeSQueue       *sq;
28188eea45cSKlaus Jensen     struct NvmeNamespace    *ns;
28288eea45cSKlaus Jensen     BlockAIOCB              *aiocb;
28388eea45cSKlaus Jensen     uint16_t                status;
28488eea45cSKlaus Jensen     void                    *opaque;
28588eea45cSKlaus Jensen     NvmeCqe                 cqe;
28688eea45cSKlaus Jensen     NvmeCmd                 cmd;
28788eea45cSKlaus Jensen     BlockAcctCookie         acct;
28888eea45cSKlaus Jensen     NvmeSg                  sg;
28988eea45cSKlaus Jensen     QTAILQ_ENTRY(NvmeRequest)entry;
29088eea45cSKlaus Jensen } NvmeRequest;
29188eea45cSKlaus Jensen 
29288eea45cSKlaus Jensen typedef struct NvmeBounceContext {
29388eea45cSKlaus Jensen     NvmeRequest *req;
29488eea45cSKlaus Jensen 
29588eea45cSKlaus Jensen     struct {
29688eea45cSKlaus Jensen         QEMUIOVector iov;
29788eea45cSKlaus Jensen         uint8_t *bounce;
29888eea45cSKlaus Jensen     } data, mdata;
29988eea45cSKlaus Jensen } NvmeBounceContext;
30088eea45cSKlaus Jensen 
30188eea45cSKlaus Jensen static inline const char *nvme_adm_opc_str(uint8_t opc)
30288eea45cSKlaus Jensen {
30388eea45cSKlaus Jensen     switch (opc) {
30488eea45cSKlaus Jensen     case NVME_ADM_CMD_DELETE_SQ:        return "NVME_ADM_CMD_DELETE_SQ";
30588eea45cSKlaus Jensen     case NVME_ADM_CMD_CREATE_SQ:        return "NVME_ADM_CMD_CREATE_SQ";
30688eea45cSKlaus Jensen     case NVME_ADM_CMD_GET_LOG_PAGE:     return "NVME_ADM_CMD_GET_LOG_PAGE";
30788eea45cSKlaus Jensen     case NVME_ADM_CMD_DELETE_CQ:        return "NVME_ADM_CMD_DELETE_CQ";
30888eea45cSKlaus Jensen     case NVME_ADM_CMD_CREATE_CQ:        return "NVME_ADM_CMD_CREATE_CQ";
30988eea45cSKlaus Jensen     case NVME_ADM_CMD_IDENTIFY:         return "NVME_ADM_CMD_IDENTIFY";
31088eea45cSKlaus Jensen     case NVME_ADM_CMD_ABORT:            return "NVME_ADM_CMD_ABORT";
31188eea45cSKlaus Jensen     case NVME_ADM_CMD_SET_FEATURES:     return "NVME_ADM_CMD_SET_FEATURES";
31288eea45cSKlaus Jensen     case NVME_ADM_CMD_GET_FEATURES:     return "NVME_ADM_CMD_GET_FEATURES";
31388eea45cSKlaus Jensen     case NVME_ADM_CMD_ASYNC_EV_REQ:     return "NVME_ADM_CMD_ASYNC_EV_REQ";
31488eea45cSKlaus Jensen     case NVME_ADM_CMD_NS_ATTACHMENT:    return "NVME_ADM_CMD_NS_ATTACHMENT";
31588eea45cSKlaus Jensen     case NVME_ADM_CMD_FORMAT_NVM:       return "NVME_ADM_CMD_FORMAT_NVM";
31688eea45cSKlaus Jensen     default:                            return "NVME_ADM_CMD_UNKNOWN";
31788eea45cSKlaus Jensen     }
31888eea45cSKlaus Jensen }
31988eea45cSKlaus Jensen 
32088eea45cSKlaus Jensen static inline const char *nvme_io_opc_str(uint8_t opc)
32188eea45cSKlaus Jensen {
32288eea45cSKlaus Jensen     switch (opc) {
32388eea45cSKlaus Jensen     case NVME_CMD_FLUSH:            return "NVME_NVM_CMD_FLUSH";
32488eea45cSKlaus Jensen     case NVME_CMD_WRITE:            return "NVME_NVM_CMD_WRITE";
32588eea45cSKlaus Jensen     case NVME_CMD_READ:             return "NVME_NVM_CMD_READ";
32688eea45cSKlaus Jensen     case NVME_CMD_COMPARE:          return "NVME_NVM_CMD_COMPARE";
32788eea45cSKlaus Jensen     case NVME_CMD_WRITE_ZEROES:     return "NVME_NVM_CMD_WRITE_ZEROES";
32888eea45cSKlaus Jensen     case NVME_CMD_DSM:              return "NVME_NVM_CMD_DSM";
32988eea45cSKlaus Jensen     case NVME_CMD_VERIFY:           return "NVME_NVM_CMD_VERIFY";
33088eea45cSKlaus Jensen     case NVME_CMD_COPY:             return "NVME_NVM_CMD_COPY";
33188eea45cSKlaus Jensen     case NVME_CMD_ZONE_MGMT_SEND:   return "NVME_ZONED_CMD_MGMT_SEND";
33288eea45cSKlaus Jensen     case NVME_CMD_ZONE_MGMT_RECV:   return "NVME_ZONED_CMD_MGMT_RECV";
33388eea45cSKlaus Jensen     case NVME_CMD_ZONE_APPEND:      return "NVME_ZONED_CMD_ZONE_APPEND";
33488eea45cSKlaus Jensen     default:                        return "NVME_NVM_CMD_UNKNOWN";
33588eea45cSKlaus Jensen     }
33688eea45cSKlaus Jensen }
33788eea45cSKlaus Jensen 
33888eea45cSKlaus Jensen typedef struct NvmeSQueue {
33988eea45cSKlaus Jensen     struct NvmeCtrl *ctrl;
34088eea45cSKlaus Jensen     uint16_t    sqid;
34188eea45cSKlaus Jensen     uint16_t    cqid;
34288eea45cSKlaus Jensen     uint32_t    head;
34388eea45cSKlaus Jensen     uint32_t    tail;
34488eea45cSKlaus Jensen     uint32_t    size;
34588eea45cSKlaus Jensen     uint64_t    dma_addr;
34688eea45cSKlaus Jensen     QEMUTimer   *timer;
34788eea45cSKlaus Jensen     NvmeRequest *io_req;
34888eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeRequest) req_list;
34988eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeRequest) out_req_list;
35088eea45cSKlaus Jensen     QTAILQ_ENTRY(NvmeSQueue) entry;
35188eea45cSKlaus Jensen } NvmeSQueue;
35288eea45cSKlaus Jensen 
35388eea45cSKlaus Jensen typedef struct NvmeCQueue {
35488eea45cSKlaus Jensen     struct NvmeCtrl *ctrl;
35588eea45cSKlaus Jensen     uint8_t     phase;
35688eea45cSKlaus Jensen     uint16_t    cqid;
35788eea45cSKlaus Jensen     uint16_t    irq_enabled;
35888eea45cSKlaus Jensen     uint32_t    head;
35988eea45cSKlaus Jensen     uint32_t    tail;
36088eea45cSKlaus Jensen     uint32_t    vector;
36188eea45cSKlaus Jensen     uint32_t    size;
36288eea45cSKlaus Jensen     uint64_t    dma_addr;
36388eea45cSKlaus Jensen     QEMUTimer   *timer;
36488eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeSQueue) sq_list;
36588eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeRequest) req_list;
36688eea45cSKlaus Jensen } NvmeCQueue;
36788eea45cSKlaus Jensen 
36888eea45cSKlaus Jensen #define TYPE_NVME_BUS "nvme-bus"
36988eea45cSKlaus Jensen #define NVME_BUS(obj) OBJECT_CHECK(NvmeBus, (obj), TYPE_NVME_BUS)
37088eea45cSKlaus Jensen 
37188eea45cSKlaus Jensen typedef struct NvmeBus {
37288eea45cSKlaus Jensen     BusState parent_bus;
37388eea45cSKlaus Jensen } NvmeBus;
37488eea45cSKlaus Jensen 
37588eea45cSKlaus Jensen #define TYPE_NVME "nvme"
37688eea45cSKlaus Jensen #define NVME(obj) \
37788eea45cSKlaus Jensen         OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
37888eea45cSKlaus Jensen 
37988eea45cSKlaus Jensen typedef struct NvmeParams {
38088eea45cSKlaus Jensen     char     *serial;
38188eea45cSKlaus Jensen     uint32_t num_queues; /* deprecated since 5.1 */
38288eea45cSKlaus Jensen     uint32_t max_ioqpairs;
38388eea45cSKlaus Jensen     uint16_t msix_qsize;
38488eea45cSKlaus Jensen     uint32_t cmb_size_mb;
38588eea45cSKlaus Jensen     uint8_t  aerl;
38688eea45cSKlaus Jensen     uint32_t aer_max_queued;
38788eea45cSKlaus Jensen     uint8_t  mdts;
38888eea45cSKlaus Jensen     uint8_t  vsl;
38988eea45cSKlaus Jensen     bool     use_intel_id;
39088eea45cSKlaus Jensen     uint8_t  zasl;
391cccc2651SNiklas Cassel     bool     auto_transition_zones;
39288eea45cSKlaus Jensen     bool     legacy_cmb;
39388eea45cSKlaus Jensen } NvmeParams;
39488eea45cSKlaus Jensen 
39588eea45cSKlaus Jensen typedef struct NvmeCtrl {
39688eea45cSKlaus Jensen     PCIDevice    parent_obj;
39788eea45cSKlaus Jensen     MemoryRegion bar0;
39888eea45cSKlaus Jensen     MemoryRegion iomem;
39988eea45cSKlaus Jensen     NvmeBar      bar;
40088eea45cSKlaus Jensen     NvmeParams   params;
40188eea45cSKlaus Jensen     NvmeBus      bus;
40288eea45cSKlaus Jensen 
40388eea45cSKlaus Jensen     uint16_t    cntlid;
40488eea45cSKlaus Jensen     bool        qs_created;
40588eea45cSKlaus Jensen     uint32_t    page_size;
40688eea45cSKlaus Jensen     uint16_t    page_bits;
40788eea45cSKlaus Jensen     uint16_t    max_prp_ents;
40888eea45cSKlaus Jensen     uint16_t    cqe_size;
40988eea45cSKlaus Jensen     uint16_t    sqe_size;
41088eea45cSKlaus Jensen     uint32_t    reg_size;
41188eea45cSKlaus Jensen     uint32_t    max_q_ents;
41288eea45cSKlaus Jensen     uint8_t     outstanding_aers;
41388eea45cSKlaus Jensen     uint32_t    irq_status;
41483d7ed5cSKlaus Jensen     int         cq_pending;
41588eea45cSKlaus Jensen     uint64_t    host_timestamp;                 /* Timestamp sent by the host */
41688eea45cSKlaus Jensen     uint64_t    timestamp_set_qemu_clock_ms;    /* QEMU clock time */
41788eea45cSKlaus Jensen     uint64_t    starttime_ms;
41888eea45cSKlaus Jensen     uint16_t    temperature;
41988eea45cSKlaus Jensen     uint8_t     smart_critical_warning;
42088eea45cSKlaus Jensen 
42188eea45cSKlaus Jensen     struct {
42288eea45cSKlaus Jensen         MemoryRegion mem;
42388eea45cSKlaus Jensen         uint8_t      *buf;
42488eea45cSKlaus Jensen         bool         cmse;
42588eea45cSKlaus Jensen         hwaddr       cba;
42688eea45cSKlaus Jensen     } cmb;
42788eea45cSKlaus Jensen 
42888eea45cSKlaus Jensen     struct {
42988eea45cSKlaus Jensen         HostMemoryBackend *dev;
43088eea45cSKlaus Jensen         bool              cmse;
43188eea45cSKlaus Jensen         hwaddr            cba;
43288eea45cSKlaus Jensen     } pmr;
43388eea45cSKlaus Jensen 
43488eea45cSKlaus Jensen     uint8_t     aer_mask;
43588eea45cSKlaus Jensen     NvmeRequest **aer_reqs;
43688eea45cSKlaus Jensen     QTAILQ_HEAD(, NvmeAsyncEvent) aer_queue;
43788eea45cSKlaus Jensen     int         aer_queued;
43888eea45cSKlaus Jensen 
43988eea45cSKlaus Jensen     uint32_t    dmrsl;
44088eea45cSKlaus Jensen 
44188eea45cSKlaus Jensen     /* Namespace ID is started with 1 so bitmap should be 1-based */
44288eea45cSKlaus Jensen #define NVME_CHANGED_NSID_SIZE  (NVME_MAX_NAMESPACES + 1)
44388eea45cSKlaus Jensen     DECLARE_BITMAP(changed_nsids, NVME_CHANGED_NSID_SIZE);
44488eea45cSKlaus Jensen 
44588eea45cSKlaus Jensen     NvmeSubsystem   *subsys;
44688eea45cSKlaus Jensen 
44788eea45cSKlaus Jensen     NvmeNamespace   namespace;
44888eea45cSKlaus Jensen     NvmeNamespace   *namespaces[NVME_MAX_NAMESPACES + 1];
44988eea45cSKlaus Jensen     NvmeSQueue      **sq;
45088eea45cSKlaus Jensen     NvmeCQueue      **cq;
45188eea45cSKlaus Jensen     NvmeSQueue      admin_sq;
45288eea45cSKlaus Jensen     NvmeCQueue      admin_cq;
45388eea45cSKlaus Jensen     NvmeIdCtrl      id_ctrl;
45488eea45cSKlaus Jensen 
45588eea45cSKlaus Jensen     struct {
45688eea45cSKlaus Jensen         struct {
45788eea45cSKlaus Jensen             uint16_t temp_thresh_hi;
45888eea45cSKlaus Jensen             uint16_t temp_thresh_low;
45988eea45cSKlaus Jensen         };
46088eea45cSKlaus Jensen         uint32_t    async_config;
46188eea45cSKlaus Jensen     } features;
46288eea45cSKlaus Jensen } NvmeCtrl;
46388eea45cSKlaus Jensen 
46488eea45cSKlaus Jensen static inline NvmeNamespace *nvme_ns(NvmeCtrl *n, uint32_t nsid)
46588eea45cSKlaus Jensen {
46688eea45cSKlaus Jensen     if (!nsid || nsid > NVME_MAX_NAMESPACES) {
46788eea45cSKlaus Jensen         return NULL;
46888eea45cSKlaus Jensen     }
46988eea45cSKlaus Jensen 
47088eea45cSKlaus Jensen     return n->namespaces[nsid];
47188eea45cSKlaus Jensen }
47288eea45cSKlaus Jensen 
47388eea45cSKlaus Jensen static inline NvmeCQueue *nvme_cq(NvmeRequest *req)
47488eea45cSKlaus Jensen {
47588eea45cSKlaus Jensen     NvmeSQueue *sq = req->sq;
47688eea45cSKlaus Jensen     NvmeCtrl *n = sq->ctrl;
47788eea45cSKlaus Jensen 
47888eea45cSKlaus Jensen     return n->cq[sq->cqid];
47988eea45cSKlaus Jensen }
48088eea45cSKlaus Jensen 
48188eea45cSKlaus Jensen static inline NvmeCtrl *nvme_ctrl(NvmeRequest *req)
48288eea45cSKlaus Jensen {
48388eea45cSKlaus Jensen     NvmeSQueue *sq = req->sq;
48488eea45cSKlaus Jensen     return sq->ctrl;
48588eea45cSKlaus Jensen }
48688eea45cSKlaus Jensen 
48788eea45cSKlaus Jensen static inline uint16_t nvme_cid(NvmeRequest *req)
48888eea45cSKlaus Jensen {
48988eea45cSKlaus Jensen     if (!req) {
49088eea45cSKlaus Jensen         return 0xffff;
49188eea45cSKlaus Jensen     }
49288eea45cSKlaus Jensen 
49388eea45cSKlaus Jensen     return le16_to_cpu(req->cqe.cid);
49488eea45cSKlaus Jensen }
49588eea45cSKlaus Jensen 
49688eea45cSKlaus Jensen void nvme_attach_ns(NvmeCtrl *n, NvmeNamespace *ns);
49788eea45cSKlaus Jensen uint16_t nvme_bounce_data(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
49888eea45cSKlaus Jensen                           NvmeTxDirection dir, NvmeRequest *req);
49988eea45cSKlaus Jensen uint16_t nvme_bounce_mdata(NvmeCtrl *n, uint8_t *ptr, uint32_t len,
50088eea45cSKlaus Jensen                            NvmeTxDirection dir, NvmeRequest *req);
50188eea45cSKlaus Jensen void nvme_rw_complete_cb(void *opaque, int ret);
50288eea45cSKlaus Jensen uint16_t nvme_map_dptr(NvmeCtrl *n, NvmeSg *sg, size_t len,
50388eea45cSKlaus Jensen                        NvmeCmd *cmd);
50488eea45cSKlaus Jensen 
50588eea45cSKlaus Jensen /* from Linux kernel (crypto/crct10dif_common.c) */
50688eea45cSKlaus Jensen static const uint16_t t10_dif_crc_table[256] = {
50788eea45cSKlaus Jensen     0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
50888eea45cSKlaus Jensen     0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
50988eea45cSKlaus Jensen     0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
51088eea45cSKlaus Jensen     0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
51188eea45cSKlaus Jensen     0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
51288eea45cSKlaus Jensen     0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
51388eea45cSKlaus Jensen     0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
51488eea45cSKlaus Jensen     0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
51588eea45cSKlaus Jensen     0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
51688eea45cSKlaus Jensen     0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
51788eea45cSKlaus Jensen     0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
51888eea45cSKlaus Jensen     0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
51988eea45cSKlaus Jensen     0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
52088eea45cSKlaus Jensen     0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
52188eea45cSKlaus Jensen     0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
52288eea45cSKlaus Jensen     0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
52388eea45cSKlaus Jensen     0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
52488eea45cSKlaus Jensen     0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
52588eea45cSKlaus Jensen     0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
52688eea45cSKlaus Jensen     0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
52788eea45cSKlaus Jensen     0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
52888eea45cSKlaus Jensen     0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
52988eea45cSKlaus Jensen     0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
53088eea45cSKlaus Jensen     0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
53188eea45cSKlaus Jensen     0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
53288eea45cSKlaus Jensen     0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
53388eea45cSKlaus Jensen     0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
53488eea45cSKlaus Jensen     0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
53588eea45cSKlaus Jensen     0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
53688eea45cSKlaus Jensen     0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
53788eea45cSKlaus Jensen     0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
53888eea45cSKlaus Jensen     0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
53988eea45cSKlaus Jensen };
54088eea45cSKlaus Jensen 
5412a132309SKlaus Jensen uint16_t nvme_check_prinfo(NvmeNamespace *ns, uint8_t prinfo, uint64_t slba,
54288eea45cSKlaus Jensen                            uint32_t reftag);
54388eea45cSKlaus Jensen uint16_t nvme_dif_mangle_mdata(NvmeNamespace *ns, uint8_t *mbuf, size_t mlen,
54488eea45cSKlaus Jensen                                uint64_t slba);
54588eea45cSKlaus Jensen void nvme_dif_pract_generate_dif(NvmeNamespace *ns, uint8_t *buf, size_t len,
54688eea45cSKlaus Jensen                                  uint8_t *mbuf, size_t mlen, uint16_t apptag,
5470ca5c3ccSKlaus Jensen                                  uint32_t *reftag);
54888eea45cSKlaus Jensen uint16_t nvme_dif_check(NvmeNamespace *ns, uint8_t *buf, size_t len,
5492a132309SKlaus Jensen                         uint8_t *mbuf, size_t mlen, uint8_t prinfo,
55088eea45cSKlaus Jensen                         uint64_t slba, uint16_t apptag,
5510ca5c3ccSKlaus Jensen                         uint16_t appmask, uint32_t *reftag);
55288eea45cSKlaus Jensen uint16_t nvme_dif_rw(NvmeCtrl *n, NvmeRequest *req);
55388eea45cSKlaus Jensen 
55488eea45cSKlaus Jensen 
55588eea45cSKlaus Jensen #endif /* HW_NVME_INTERNAL_H */
556