#ifndef SG_PT_NVME_H #define SG_PT_NVME_H /* * Copyright (c) 2017-2018 Douglas Gilbert. * All rights reserved. * Use of this source code is governed by a BSD-style * license that can be found in the BSD_LICENSE file. */ #include <stdint.h> #include <stdbool.h> #ifdef __cplusplus extern "C" { #endif /* structures copied and slightly modified from <linux/nvme_ioctl.h> which * is Copyright (c) 2011-2014, Intel Corporation. */ /* Note that the command input structure is in (packed) "cpu" format. That * means, for example, if the CPU is little endian (most are) then so is the * structure. However what comes out in the data-in buffer (e.g. for the * Admin Identify command response) is almost all little endian following ATA * (but no SCSI and IP which are big endian) and Intel's preference. There * are exceptions, for example the EUI-64 identifiers in the Admin Identify * response are big endian. * * Code online (e.g. nvme-cli at github.com) seems to like packed strcutures, * the author prefers byte offset plus a range of unaligned integer builders * such as those in sg_unaligned.h . */ #ifdef __GNUC__ #ifndef __clang__ struct __attribute__((__packed__)) sg_nvme_user_io #else struct sg_nvme_user_io #endif #else struct sg_nvme_user_io #endif { uint8_t opcode; uint8_t flags; uint16_t control; uint16_t nblocks; uint16_t rsvd; uint64_t metadata; uint64_t addr; uint64_t slba; uint32_t dsmgmt; uint32_t reftag; uint16_t apptag; uint16_t appmask; } #ifdef SG_LIB_FREEBSD __packed; #else ; #endif /* Using byte offsets and unaligned be/le copies safer than packed * structures. These are for sg_nvme_user_io . */ #define SG_NVME_IO_OPCODE 0 #define SG_NVME_IO_FLAGS 1 #define SG_NVME_IO_CONTROL 2 #define SG_NVME_IO_NBLOCKS 4 #define SG_NVME_IO_RSVD 6 #define SG_NVME_IO_METADATA 8 #define SG_NVME_IO_ADDR 16 #define SG_NVME_IO_SLBA 24 #define SG_NVME_IO_DSMGMT 32 #define SG_NVME_IO_REFTAG 36 #define SG_NVME_IO_APPTAG 40 #define SG_NVME_IO_APPMASK 42 #ifdef __GNUC__ #ifndef __clang__ struct __attribute__((__packed__)) sg_nvme_passthru_cmd #else struct sg_nvme_passthru_cmd #endif #else struct sg_nvme_passthru_cmd #endif { uint8_t opcode; uint8_t flags; uint16_t rsvd1; uint32_t nsid; uint32_t cdw2; uint32_t cdw3; uint64_t metadata; uint64_t addr; uint32_t metadata_len; uint32_t data_len; uint32_t cdw10; uint32_t cdw11; uint32_t cdw12; uint32_t cdw13; uint32_t cdw14; uint32_t cdw15; #ifdef SG_LIB_LINUX uint32_t timeout_ms; uint32_t result; /* out: DWord(0) from completion queue */ #endif } #ifdef SG_LIB_FREEBSD __packed; #else ; #endif /* Using byte offsets and unaligned be/le copies safer than packed * structures. These are for sg_nvme_passthru_cmd . */ #define SG_NVME_PT_OPCODE 0 /* length: 1 byte */ #define SG_NVME_PT_FLAGS 1 /* length: 1 byte */ #define SG_NVME_PT_RSVD1 2 /* length: 2 bytes */ #define SG_NVME_PT_NSID 4 /* length: 4 bytes */ #define SG_NVME_PT_CDW2 8 /* length: 4 bytes */ #define SG_NVME_PT_CDW3 12 /* length: 4 bytes */ #define SG_NVME_PT_METADATA 16 /* length: 8 bytes */ #define SG_NVME_PT_ADDR 24 /* length: 8 bytes */ #define SG_NVME_PT_METADATA_LEN 32 /* length: 4 bytes */ #define SG_NVME_PT_DATA_LEN 36 /* length: 4 bytes */ #define SG_NVME_PT_CDW10 40 /* length: 4 bytes */ #define SG_NVME_PT_CDW11 44 /* length: 4 bytes */ #define SG_NVME_PT_CDW12 48 /* length: 4 bytes */ #define SG_NVME_PT_CDW13 52 /* length: 4 bytes */ #define SG_NVME_PT_CDW14 56 /* length: 4 bytes */ #define SG_NVME_PT_CDW15 60 /* length: 4 bytes */ #ifdef SG_LIB_LINUX /* General references state that "all NVMe commands are 64 bytes long". If * so then the following are add-ons by Linux, go to the OS and not the * the NVMe device. */ #define SG_NVME_PT_TIMEOUT_MS 64 /* length: 4 bytes */ #define SG_NVME_PT_RESULT 68 /* length: 4 bytes */ #endif /* Byte offset of Result and Status (plus phase bit) in CQ */ #define SG_NVME_PT_CQ_RESULT 0 /* CDW0, length: 4 bytes */ #define SG_NVME_PT_CQ_DW0 0 /* CDW0, length: 4 bytes */ #define SG_NVME_PT_CQ_DW1 4 /* CDW1, length: 4 bytes */ #define SG_NVME_PT_CQ_DW2 8 /* CDW2, length: 4 bytes */ #define SG_NVME_PT_CQ_DW3 12 /* CDW3, length: 4 bytes */ #define SG_NVME_PT_CQ_STATUS_P 14 /* CDW3 31:16, length: 2 bytes */ /* Valid namespace IDs (nsid_s) range from 1 to 0xfffffffe, leaving: */ #define SG_NVME_BROADCAST_NSID 0xffffffff /* all namespaces */ #define SG_NVME_CTL_NSID 0x0 /* the "controller's" namespace */ /* Given the NVMe Identify Controller response and optionally the NVMe * Identify Namespace response (NULL otherwise), generate the SCSI VPD * page 0x83 (device identification) descriptor(s) in dop. Return the * number of bytes written which will not exceed max_do_len. Probably use * Peripheral Device Type (pdt) of 0 (disk) for don't know. Transport * protocol (tproto) should be -1 if not known, else SCSI value. * N.B. Does not write total VPD page length into dop[2:3] . */ int sg_make_vpd_devid_for_nvme(const uint8_t * nvme_id_ctl_p, const uint8_t * nvme_id_ns_p, int pdt, int tproto, uint8_t * dop, int max_do_len); #ifdef __cplusplus } #endif #endif /* SG_PT_NVME_H */