4 * Copyright (c) 2012 Intel Corporation
5 * Copyright (c) 2021 Minwoo Im
6 * Copyright (c) 2021 Samsung Electronics Co., Ltd.
9 * Keith Busch <kbusch@kernel.org>
10 * Klaus Jensen <k.jensen@samsung.com>
11 * Gollu Appalanaidu <anaidu.gollu@samsung.com>
12 * Dmitry Fomichev <dmitry.fomichev@wdc.com>
13 * Minwoo Im <minwoo.im.dev@gmail.com>
15 * This code is licensed under the GNU GPL v2 or later.
18 #ifndef HW_NVME_INTERNAL_H
19 #define HW_NVME_INTERNAL_H
21 #include "qemu/uuid.h"
22 #include "hw/pci/pci.h"
23 #include "hw/block/block.h"
25 #include "block/nvme.h"
27 #define NVME_MAX_CONTROLLERS 32
28 #define NVME_MAX_NAMESPACES 256
29 #define NVME_EUI64_DEFAULT ((uint64_t)0x5254000000000000)
31 QEMU_BUILD_BUG_ON(NVME_MAX_NAMESPACES
> NVME_NSID_BROADCAST
- 1);
33 typedef struct NvmeCtrl NvmeCtrl
;
34 typedef struct NvmeNamespace NvmeNamespace
;
36 #define TYPE_NVME_BUS "nvme-bus"
37 OBJECT_DECLARE_SIMPLE_TYPE(NvmeBus
, NVME_BUS
)
39 typedef struct NvmeBus
{
43 #define TYPE_NVME_SUBSYS "nvme-subsys"
44 #define NVME_SUBSYS(obj) \
45 OBJECT_CHECK(NvmeSubsystem, (obj), TYPE_NVME_SUBSYS)
47 typedef struct NvmeSubsystem
{
48 DeviceState parent_obj
;
52 NvmeCtrl
*ctrls
[NVME_MAX_CONTROLLERS
];
53 NvmeNamespace
*namespaces
[NVME_MAX_NAMESPACES
+ 1];
60 int nvme_subsys_register_ctrl(NvmeCtrl
*n
, Error
**errp
);
61 void nvme_subsys_unregister_ctrl(NvmeSubsystem
*subsys
, NvmeCtrl
*n
);
63 static inline NvmeCtrl
*nvme_subsys_ctrl(NvmeSubsystem
*subsys
,
66 if (!subsys
|| cntlid
>= NVME_MAX_CONTROLLERS
) {
70 return subsys
->ctrls
[cntlid
];
73 static inline NvmeNamespace
*nvme_subsys_ns(NvmeSubsystem
*subsys
,
76 if (!subsys
|| !nsid
|| nsid
> NVME_MAX_NAMESPACES
) {
80 return subsys
->namespaces
[nsid
];
83 #define TYPE_NVME_NS "nvme-ns"
84 #define NVME_NS(obj) \
85 OBJECT_CHECK(NvmeNamespace, (obj), TYPE_NVME_NS)
87 typedef struct NvmeZone
{
90 QTAILQ_ENTRY(NvmeZone
) entry
;
93 typedef struct NvmeNamespaceParams
{
111 bool cross_zone_read
;
112 uint64_t zone_size_bs
;
113 uint64_t zone_cap_bs
;
114 uint32_t max_active_zones
;
115 uint32_t max_open_zones
;
116 uint32_t zd_extension_size
;
117 } NvmeNamespaceParams
;
119 typedef struct NvmeNamespace
{
120 DeviceState parent_obj
;
128 const uint32_t *iocs
;
133 QTAILQ_ENTRY(NvmeNamespace
) entry
;
135 NvmeIdNsZoned
*id_ns_zoned
;
136 NvmeZone
*zone_array
;
137 QTAILQ_HEAD(, NvmeZone
) exp_open_zones
;
138 QTAILQ_HEAD(, NvmeZone
) imp_open_zones
;
139 QTAILQ_HEAD(, NvmeZone
) closed_zones
;
140 QTAILQ_HEAD(, NvmeZone
) full_zones
;
143 uint64_t zone_capacity
;
144 uint32_t zone_size_log2
;
145 uint8_t *zd_extensions
;
146 int32_t nr_open_zones
;
147 int32_t nr_active_zones
;
149 NvmeNamespaceParams params
;
156 static inline uint32_t nvme_nsid(NvmeNamespace
*ns
)
159 return ns
->params
.nsid
;
165 static inline size_t nvme_l2b(NvmeNamespace
*ns
, uint64_t lba
)
167 return lba
<< ns
->lbaf
.ds
;
170 static inline size_t nvme_m2b(NvmeNamespace
*ns
, uint64_t lba
)
172 return ns
->lbaf
.ms
* lba
;
175 static inline int64_t nvme_moff(NvmeNamespace
*ns
, uint64_t lba
)
177 return ns
->moff
+ nvme_m2b(ns
, lba
);
180 static inline bool nvme_ns_ext(NvmeNamespace
*ns
)
182 return !!NVME_ID_NS_FLBAS_EXTENDED(ns
->id_ns
.flbas
);
185 static inline NvmeZoneState
nvme_get_zone_state(NvmeZone
*zone
)
187 return zone
->d
.zs
>> 4;
190 static inline void nvme_set_zone_state(NvmeZone
*zone
, NvmeZoneState state
)
192 zone
->d
.zs
= state
<< 4;
195 static inline uint64_t nvme_zone_rd_boundary(NvmeNamespace
*ns
, NvmeZone
*zone
)
197 return zone
->d
.zslba
+ ns
->zone_size
;
200 static inline uint64_t nvme_zone_wr_boundary(NvmeZone
*zone
)
202 return zone
->d
.zslba
+ zone
->d
.zcap
;
205 static inline bool nvme_wp_is_valid(NvmeZone
*zone
)
207 uint8_t st
= nvme_get_zone_state(zone
);
209 return st
!= NVME_ZONE_STATE_FULL
&&
210 st
!= NVME_ZONE_STATE_READ_ONLY
&&
211 st
!= NVME_ZONE_STATE_OFFLINE
;
214 static inline uint8_t *nvme_get_zd_extension(NvmeNamespace
*ns
,
217 return &ns
->zd_extensions
[zone_idx
* ns
->params
.zd_extension_size
];
220 static inline void nvme_aor_inc_open(NvmeNamespace
*ns
)
222 assert(ns
->nr_open_zones
>= 0);
223 if (ns
->params
.max_open_zones
) {
225 assert(ns
->nr_open_zones
<= ns
->params
.max_open_zones
);
229 static inline void nvme_aor_dec_open(NvmeNamespace
*ns
)
231 if (ns
->params
.max_open_zones
) {
232 assert(ns
->nr_open_zones
> 0);
235 assert(ns
->nr_open_zones
>= 0);
238 static inline void nvme_aor_inc_active(NvmeNamespace
*ns
)
240 assert(ns
->nr_active_zones
>= 0);
241 if (ns
->params
.max_active_zones
) {
242 ns
->nr_active_zones
++;
243 assert(ns
->nr_active_zones
<= ns
->params
.max_active_zones
);
247 static inline void nvme_aor_dec_active(NvmeNamespace
*ns
)
249 if (ns
->params
.max_active_zones
) {
250 assert(ns
->nr_active_zones
> 0);
251 ns
->nr_active_zones
--;
252 assert(ns
->nr_active_zones
>= ns
->nr_open_zones
);
254 assert(ns
->nr_active_zones
>= 0);
257 void nvme_ns_init_format(NvmeNamespace
*ns
);
258 int nvme_ns_setup(NvmeNamespace
*ns
, Error
**errp
);
259 void nvme_ns_drain(NvmeNamespace
*ns
);
260 void nvme_ns_shutdown(NvmeNamespace
*ns
);
261 void nvme_ns_cleanup(NvmeNamespace
*ns
);
263 typedef struct NvmeAsyncEvent
{
264 QTAILQ_ENTRY(NvmeAsyncEvent
) entry
;
265 NvmeAerResult result
;
269 NVME_SG_ALLOC
= 1 << 0,
270 NVME_SG_DMA
= 1 << 1,
273 typedef struct NvmeSg
{
282 typedef enum NvmeTxDirection
{
283 NVME_TX_DIRECTION_TO_DEVICE
= 0,
284 NVME_TX_DIRECTION_FROM_DEVICE
= 1,
287 typedef struct NvmeRequest
{
288 struct NvmeSQueue
*sq
;
289 struct NvmeNamespace
*ns
;
295 BlockAcctCookie acct
;
297 QTAILQ_ENTRY(NvmeRequest
)entry
;
300 typedef struct NvmeBounceContext
{
309 static inline const char *nvme_adm_opc_str(uint8_t opc
)
312 case NVME_ADM_CMD_DELETE_SQ
: return "NVME_ADM_CMD_DELETE_SQ";
313 case NVME_ADM_CMD_CREATE_SQ
: return "NVME_ADM_CMD_CREATE_SQ";
314 case NVME_ADM_CMD_GET_LOG_PAGE
: return "NVME_ADM_CMD_GET_LOG_PAGE";
315 case NVME_ADM_CMD_DELETE_CQ
: return "NVME_ADM_CMD_DELETE_CQ";
316 case NVME_ADM_CMD_CREATE_CQ
: return "NVME_ADM_CMD_CREATE_CQ";
317 case NVME_ADM_CMD_IDENTIFY
: return "NVME_ADM_CMD_IDENTIFY";
318 case NVME_ADM_CMD_ABORT
: return "NVME_ADM_CMD_ABORT";
319 case NVME_ADM_CMD_SET_FEATURES
: return "NVME_ADM_CMD_SET_FEATURES";
320 case NVME_ADM_CMD_GET_FEATURES
: return "NVME_ADM_CMD_GET_FEATURES";
321 case NVME_ADM_CMD_ASYNC_EV_REQ
: return "NVME_ADM_CMD_ASYNC_EV_REQ";
322 case NVME_ADM_CMD_NS_ATTACHMENT
: return "NVME_ADM_CMD_NS_ATTACHMENT";
323 case NVME_ADM_CMD_FORMAT_NVM
: return "NVME_ADM_CMD_FORMAT_NVM";
324 default: return "NVME_ADM_CMD_UNKNOWN";
328 static inline const char *nvme_io_opc_str(uint8_t opc
)
331 case NVME_CMD_FLUSH
: return "NVME_NVM_CMD_FLUSH";
332 case NVME_CMD_WRITE
: return "NVME_NVM_CMD_WRITE";
333 case NVME_CMD_READ
: return "NVME_NVM_CMD_READ";
334 case NVME_CMD_COMPARE
: return "NVME_NVM_CMD_COMPARE";
335 case NVME_CMD_WRITE_ZEROES
: return "NVME_NVM_CMD_WRITE_ZEROES";
336 case NVME_CMD_DSM
: return "NVME_NVM_CMD_DSM";
337 case NVME_CMD_VERIFY
: return "NVME_NVM_CMD_VERIFY";
338 case NVME_CMD_COPY
: return "NVME_NVM_CMD_COPY";
339 case NVME_CMD_ZONE_MGMT_SEND
: return "NVME_ZONED_CMD_MGMT_SEND";
340 case NVME_CMD_ZONE_MGMT_RECV
: return "NVME_ZONED_CMD_MGMT_RECV";
341 case NVME_CMD_ZONE_APPEND
: return "NVME_ZONED_CMD_ZONE_APPEND";
342 default: return "NVME_NVM_CMD_UNKNOWN";
346 typedef struct NvmeSQueue
{
347 struct NvmeCtrl
*ctrl
;
356 QTAILQ_HEAD(, NvmeRequest
) req_list
;
357 QTAILQ_HEAD(, NvmeRequest
) out_req_list
;
358 QTAILQ_ENTRY(NvmeSQueue
) entry
;
361 typedef struct NvmeCQueue
{
362 struct NvmeCtrl
*ctrl
;
365 uint16_t irq_enabled
;
372 QTAILQ_HEAD(, NvmeSQueue
) sq_list
;
373 QTAILQ_HEAD(, NvmeRequest
) req_list
;
376 #define TYPE_NVME "nvme"
378 OBJECT_CHECK(NvmeCtrl, (obj), TYPE_NVME)
380 typedef struct NvmeParams
{
382 uint32_t num_queues
; /* deprecated since 5.1 */
383 uint32_t max_ioqpairs
;
385 uint32_t cmb_size_mb
;
387 uint32_t aer_max_queued
;
392 bool auto_transition_zones
;
396 typedef struct NvmeCtrl
{
397 PCIDevice parent_obj
;
408 uint16_t max_prp_ents
;
413 uint8_t outstanding_aers
;
416 uint64_t host_timestamp
; /* Timestamp sent by the host */
417 uint64_t timestamp_set_qemu_clock_ms
; /* QEMU clock time */
418 uint64_t starttime_ms
;
419 uint16_t temperature
;
420 uint8_t smart_critical_warning
;
430 HostMemoryBackend
*dev
;
436 NvmeRequest
**aer_reqs
;
437 QTAILQ_HEAD(, NvmeAsyncEvent
) aer_queue
;
442 /* Namespace ID is started with 1 so bitmap should be 1-based */
443 #define NVME_CHANGED_NSID_SIZE (NVME_MAX_NAMESPACES + 1)
444 DECLARE_BITMAP(changed_nsids
, NVME_CHANGED_NSID_SIZE
);
446 NvmeSubsystem
*subsys
;
448 NvmeNamespace
namespace;
449 NvmeNamespace
*namespaces
[NVME_MAX_NAMESPACES
+ 1];
458 uint16_t temp_thresh_hi
;
459 uint16_t temp_thresh_low
;
461 uint32_t async_config
;
465 static inline NvmeNamespace
*nvme_ns(NvmeCtrl
*n
, uint32_t nsid
)
467 if (!nsid
|| nsid
> NVME_MAX_NAMESPACES
) {
471 return n
->namespaces
[nsid
];
474 static inline NvmeCQueue
*nvme_cq(NvmeRequest
*req
)
476 NvmeSQueue
*sq
= req
->sq
;
477 NvmeCtrl
*n
= sq
->ctrl
;
479 return n
->cq
[sq
->cqid
];
482 static inline NvmeCtrl
*nvme_ctrl(NvmeRequest
*req
)
484 NvmeSQueue
*sq
= req
->sq
;
488 static inline uint16_t nvme_cid(NvmeRequest
*req
)
494 return le16_to_cpu(req
->cqe
.cid
);
497 void nvme_attach_ns(NvmeCtrl
*n
, NvmeNamespace
*ns
);
498 uint16_t nvme_bounce_data(NvmeCtrl
*n
, uint8_t *ptr
, uint32_t len
,
499 NvmeTxDirection dir
, NvmeRequest
*req
);
500 uint16_t nvme_bounce_mdata(NvmeCtrl
*n
, uint8_t *ptr
, uint32_t len
,
501 NvmeTxDirection dir
, NvmeRequest
*req
);
502 void nvme_rw_complete_cb(void *opaque
, int ret
);
503 uint16_t nvme_map_dptr(NvmeCtrl
*n
, NvmeSg
*sg
, size_t len
,
506 /* from Linux kernel (crypto/crct10dif_common.c) */
507 static const uint16_t t10_dif_crc_table
[256] = {
508 0x0000, 0x8BB7, 0x9CD9, 0x176E, 0xB205, 0x39B2, 0x2EDC, 0xA56B,
509 0xEFBD, 0x640A, 0x7364, 0xF8D3, 0x5DB8, 0xD60F, 0xC161, 0x4AD6,
510 0x54CD, 0xDF7A, 0xC814, 0x43A3, 0xE6C8, 0x6D7F, 0x7A11, 0xF1A6,
511 0xBB70, 0x30C7, 0x27A9, 0xAC1E, 0x0975, 0x82C2, 0x95AC, 0x1E1B,
512 0xA99A, 0x222D, 0x3543, 0xBEF4, 0x1B9F, 0x9028, 0x8746, 0x0CF1,
513 0x4627, 0xCD90, 0xDAFE, 0x5149, 0xF422, 0x7F95, 0x68FB, 0xE34C,
514 0xFD57, 0x76E0, 0x618E, 0xEA39, 0x4F52, 0xC4E5, 0xD38B, 0x583C,
515 0x12EA, 0x995D, 0x8E33, 0x0584, 0xA0EF, 0x2B58, 0x3C36, 0xB781,
516 0xD883, 0x5334, 0x445A, 0xCFED, 0x6A86, 0xE131, 0xF65F, 0x7DE8,
517 0x373E, 0xBC89, 0xABE7, 0x2050, 0x853B, 0x0E8C, 0x19E2, 0x9255,
518 0x8C4E, 0x07F9, 0x1097, 0x9B20, 0x3E4B, 0xB5FC, 0xA292, 0x2925,
519 0x63F3, 0xE844, 0xFF2A, 0x749D, 0xD1F6, 0x5A41, 0x4D2F, 0xC698,
520 0x7119, 0xFAAE, 0xEDC0, 0x6677, 0xC31C, 0x48AB, 0x5FC5, 0xD472,
521 0x9EA4, 0x1513, 0x027D, 0x89CA, 0x2CA1, 0xA716, 0xB078, 0x3BCF,
522 0x25D4, 0xAE63, 0xB90D, 0x32BA, 0x97D1, 0x1C66, 0x0B08, 0x80BF,
523 0xCA69, 0x41DE, 0x56B0, 0xDD07, 0x786C, 0xF3DB, 0xE4B5, 0x6F02,
524 0x3AB1, 0xB106, 0xA668, 0x2DDF, 0x88B4, 0x0303, 0x146D, 0x9FDA,
525 0xD50C, 0x5EBB, 0x49D5, 0xC262, 0x6709, 0xECBE, 0xFBD0, 0x7067,
526 0x6E7C, 0xE5CB, 0xF2A5, 0x7912, 0xDC79, 0x57CE, 0x40A0, 0xCB17,
527 0x81C1, 0x0A76, 0x1D18, 0x96AF, 0x33C4, 0xB873, 0xAF1D, 0x24AA,
528 0x932B, 0x189C, 0x0FF2, 0x8445, 0x212E, 0xAA99, 0xBDF7, 0x3640,
529 0x7C96, 0xF721, 0xE04F, 0x6BF8, 0xCE93, 0x4524, 0x524A, 0xD9FD,
530 0xC7E6, 0x4C51, 0x5B3F, 0xD088, 0x75E3, 0xFE54, 0xE93A, 0x628D,
531 0x285B, 0xA3EC, 0xB482, 0x3F35, 0x9A5E, 0x11E9, 0x0687, 0x8D30,
532 0xE232, 0x6985, 0x7EEB, 0xF55C, 0x5037, 0xDB80, 0xCCEE, 0x4759,
533 0x0D8F, 0x8638, 0x9156, 0x1AE1, 0xBF8A, 0x343D, 0x2353, 0xA8E4,
534 0xB6FF, 0x3D48, 0x2A26, 0xA191, 0x04FA, 0x8F4D, 0x9823, 0x1394,
535 0x5942, 0xD2F5, 0xC59B, 0x4E2C, 0xEB47, 0x60F0, 0x779E, 0xFC29,
536 0x4BA8, 0xC01F, 0xD771, 0x5CC6, 0xF9AD, 0x721A, 0x6574, 0xEEC3,
537 0xA415, 0x2FA2, 0x38CC, 0xB37B, 0x1610, 0x9DA7, 0x8AC9, 0x017E,
538 0x1F65, 0x94D2, 0x83BC, 0x080B, 0xAD60, 0x26D7, 0x31B9, 0xBA0E,
539 0xF0D8, 0x7B6F, 0x6C01, 0xE7B6, 0x42DD, 0xC96A, 0xDE04, 0x55B3
542 uint16_t nvme_check_prinfo(NvmeNamespace
*ns
, uint8_t prinfo
, uint64_t slba
,
544 uint16_t nvme_dif_mangle_mdata(NvmeNamespace
*ns
, uint8_t *mbuf
, size_t mlen
,
546 void nvme_dif_pract_generate_dif(NvmeNamespace
*ns
, uint8_t *buf
, size_t len
,
547 uint8_t *mbuf
, size_t mlen
, uint16_t apptag
,
549 uint16_t nvme_dif_check(NvmeNamespace
*ns
, uint8_t *buf
, size_t len
,
550 uint8_t *mbuf
, size_t mlen
, uint8_t prinfo
,
551 uint64_t slba
, uint16_t apptag
,
552 uint16_t appmask
, uint32_t *reftag
);
553 uint16_t nvme_dif_rw(NvmeCtrl
*n
, NvmeRequest
*req
);
556 #endif /* HW_NVME_INTERNAL_H */