#if defined(__DragonFly__)
#include "nvme_dragonfly.h"
#else
#error "build for OS unknown"
#endif
#include "nvme_fw.h"
#include "nvme_log.h"
#include "nvme_ident.h"
#include "nvme_ns.h"
#include "nvme_chipset.h"
#include "nvme_ioctl.h"
MALLOC_DECLARE(M_NVME);
#define NVME_MAX_QUEUES 1024
#define NVME_MAX_NAMESPACES 1024
struct nvme_queue;
struct nvme_softc;
struct nvme_softns;
typedef struct {
pci_vendor_id_t vendor;
pci_product_id_t product;
int (*attach)(device_t dev);
int (*detach)(device_t dev);
char *name;
} nvme_device_t;
typedef struct nvme_request {
struct nvme_request *next_avail;
struct nvme_subqueue *subq;
struct nvme_comqueue *comq;
uint32_t state;
uint32_t cmd_id;
int waiting;
nvme_allcmd_t cmd;
nvme_allres_t res;
nvme_admin_data_t *info;
bus_addr_t pinfo;
void (*callback)(struct nvme_request *req, struct lock *lk);
struct nvme_softns *nsc;
struct bio *bio;
} nvme_request_t;
#define NVME_REQ_AVAIL 0
#define NVME_REQ_ALLOCATED 1
#define NVME_REQ_SUBMITTED 2
#define NVME_REQ_COMPLETED 3
typedef struct nvme_subqueue {
struct lock lk;
struct nvme_softc *sc;
nvme_request_t *dump_req;
nvme_request_t *first_avail;
nvme_request_t *reqary;
uint32_t nqe;
uint16_t qid;
uint16_t comqid;
uint32_t subq_doorbell_reg;
uint32_t subq_head;
uint32_t subq_tail;
uint32_t unsubmitted;
int unused01;
int signal_requeue;
bus_dmamap_t sque_map;
bus_dmamap_t prps_map;
nvme_allcmd_t *ksubq;
uint64_t *kprps;
bus_addr_t psubq;
bus_addr_t pprps;
bus_dmamap_t adm_map;
bus_addr_t pdatapgs;
nvme_admin_data_t *kdatapgs;
} nvme_subqueue_t;
typedef struct nvme_comqueue {
struct lock lk;
struct nvme_softc *sc;
uint32_t nqe;
uint16_t phase;
uint16_t qid;
uint32_t comq_doorbell_reg;
uint32_t comq_head;
uint32_t comq_tail;
bus_dmamap_t cque_map;
nvme_allres_t *kcomq;
bus_addr_t pcomq;
} nvme_comqueue_t;
typedef struct nvme_softns {
struct nvme_softc *sc;
nvme_ident_ns_data_t idns;
struct bio_queue_head bioq;
struct lock lk;
int state;
int unit;
uint32_t nsid;
uint32_t blksize;
struct disk disk;
struct devstat stats;
cdev_t cdev;
} nvme_softns_t;
#define NVME_NSC_STATE_UNATTACHED 0
#define NVME_NSC_STATE_ATTACHED 1
typedef struct nvme_softc {
TAILQ_ENTRY(nvme_softc) entry;
device_t dev;
const nvme_device_t *ad;
thread_t admintd;
uint32_t maxqe;
uint64_t cap;
uint32_t vers;
uint32_t dstrd4;
uint32_t entimo;
uint16_t niosubqs;
uint16_t niocomqs;
uint16_t dumpqno;
uint16_t eventqno;
uint16_t qmap[SMP_MAXCPU][2];
uint32_t flags;
nvme_subqueue_t subqueues[NVME_MAX_QUEUES];
nvme_comqueue_t comqueues[NVME_MAX_QUEUES];
int cputovect[SMP_MAXCPU];
ulong opencnt;
struct resource *regs;
struct resource *bar4;
bus_space_tag_t iot;
bus_space_handle_t ioh;
int rid_regs;
int rid_bar4;
int nirqs;
int irq_type;
struct resource *irq[NVME_MAX_QUEUES];
int rid_irq[NVME_MAX_QUEUES];
void *irq_handle[NVME_MAX_QUEUES];
bus_dma_tag_t prps_tag;
bus_dma_tag_t sque_tag;
bus_dma_tag_t cque_tag;
bus_dma_tag_t adm_tag;
size_t prp_bytes;
size_t cmd_bytes;
size_t res_bytes;
size_t adm_bytes;
uint32_t admin_signal;
struct lock admin_lk;
struct lock ioctl_lk;
int (*admin_func)(struct nvme_softc *);
nvme_ident_ctlr_data_t idctlr;
nvme_softns_t *nscary[NVME_MAX_NAMESPACES];
int nscmax;
} nvme_softc_t;
#define NVME_SC_ATTACHED 0x00000001
#define NVME_SC_UNLOADING 0x00000002
#define ADMIN_SIG_STOP 0x00000001
#define ADMIN_SIG_RUNNING 0x00000002
#define ADMIN_SIG_PROBED 0x00000004
#define ADMIN_SIG_REQUEUE 0x00000008
#define ADMIN_SIG_RUN_MASK (ADMIN_SIG_STOP | ADMIN_SIG_REQUEUE)
#define NVME_QMAP_RD 0
#define NVME_QMAP_WR 1
typedef struct nvme_status_buf {
char buf[64];
} nvme_status_buf_t;
const nvme_device_t *nvme_lookup_device(device_t dev);
void nvme_os_sleep(int ms);
int nvme_os_softsleep(void);
void nvme_os_hardsleep(int us);
u_int32_t nvme_read(nvme_softc_t *sc, bus_size_t r);
u_int64_t nvme_read8(nvme_softc_t *sc, bus_size_t r);
void nvme_write(nvme_softc_t *sc, bus_size_t r, u_int32_t v);
void nvme_write8(nvme_softc_t *sc, bus_size_t r, u_int64_t v);
int nvme_enable(nvme_softc_t *sc, int enable);
int nvme_alloc_subqueue(nvme_softc_t *sc, uint16_t qid);
int nvme_alloc_comqueue(nvme_softc_t *sc, uint16_t qid);
void nvme_free_subqueue(nvme_softc_t *sc, uint16_t qid);
void nvme_free_comqueue(nvme_softc_t *sc, uint16_t qid);
nvme_request_t *nvme_get_admin_request(nvme_softc_t *sc, uint8_t opcode);
nvme_request_t *nvme_get_request(nvme_subqueue_t *queue, uint8_t opcode,
char *kva, size_t bytes);
nvme_request_t *nvme_get_dump_request(nvme_subqueue_t *queue, uint8_t opcode,
char *kva, size_t bytes);
void nvme_submit_request(nvme_request_t *req);
int nvme_wait_request(nvme_request_t *req);
int nvme_poll_request(nvme_request_t *req);
void nvme_put_request(nvme_request_t *req);
void nvme_put_dump_request(nvme_request_t *req);
void nvme_poll_completions(nvme_comqueue_t *queue, struct lock *lk);
int nvme_start_admin_thread(nvme_softc_t *sc);
void nvme_stop_admin_thread(nvme_softc_t *sc);
int nvme_create_subqueue(nvme_softc_t *sc, uint16_t qid);
int nvme_create_comqueue(nvme_softc_t *sc, uint16_t qid);
int nvme_delete_subqueue(nvme_softc_t *sc, uint16_t qid);
int nvme_delete_comqueue(nvme_softc_t *sc, uint16_t qid);
int nvme_issue_shutdown(nvme_softc_t *sc, int dopoll);
void nvme_disk_attach(nvme_softns_t *nsc);
void nvme_disk_detach(nvme_softns_t *nsc);
void nvme_disk_requeues(nvme_softc_t *sc);
int nvme_alloc_disk_unit(void);
int nvme_getlog_ioctl(nvme_softc_t *sc, nvme_getlog_ioctl_t *ioc);
void nvme_intr(void *arg);
size_t string_cleanup(char *str, int domiddle);