struct spdk_nvme_ctrlr_opts{
    uint32_t num_io_queues;                       // DEFAULT_MAX_IO_QUEUES 1024
    bool use_cmb_sqs;                             // true
    bool no_shn_notification;                     // 
    enum spdk_nvme_cc_ams arb_mechanism;          // SPDK_NVME_CC_AMS_RR
    uint8_t arbitration_burst;
    uint8_t low_priority_weight; // valid when SPDK_NVME_CC_AMS_WRR,
    uint8_t medium_priority_weight;
    uint8_t high_priority_weight;
    uint32_t keep_alive_timeout_ms; //spdk_nvme_ctrlr_process_admin_completions 
    uint8_t transport_retry_count;
    uint32_t io_queue_size;      //the queue depth of each NVME I/O queue  
                                // DEFAULT_IO_QUEUE_SIZE 256
    char hostnqn[SPDK_NVMF_NQN_MAX_LEN + 1];    // for NVMEoF
    uint32_t io_queue_requests;  //the number of requests of each NVME I/O queue
                    // this should be at least as large as io_queue_size.  
                    // DEFAULT_IO_QUEUE_REQUESTS 512
    char src_addr[SPDK_NVMF_TRADDR_MAX_LEN + 1];// for NVMEoF
    char src_svcid[SPDK_NVMF_TRSVCID_MAX_LEN + 1];// for NVMEoF
    uint8_t host_id[8];
    uint8_t extended_host_id[16];
    enum spdk_nvme_cc_css command_set;
    uint32_t admin_timeout_ms;
    bool header_digest;
    bool data_digest;
    bool disable_error_logging;
}

struct spdk_nvme_ctrlr{
    ...
    struct spdk_nvme_qpair *adminq;
    ...
    TAILQ_HEAD(, spdk_nvme_ctrlr_process)   active_procs;
    ...
}
struct spdk_pcie_qpair{
    volatile uint32_t *sq_tdbl; // submission queue tail doorbell 
    volatile uint32_t *cq_hdbl; // completion queue head doorbell
    struct spdk_nvme_cmd *cmd;  // submission queue
    struct spdk_nvme_cpl *cpl;  // completion queue
    ...
    uint16_t last_sq_tail;
    uint16_t sq_tail;
    uint16_t cq_head;
    uint16_t sq_head;
    ...
    struct spdk_nvme_qpair qpair;
    ...

}
struct spdk_nvme_qpair{
    struct spdk_nvme_ctrlr *ctrlr;
    ...
    STAILQ_HEAD(, nvme_request)     free_req;
    STAILQ_HEAD(, nvme_request)     queued_req;
    ...

}
struct nvme_request{
    ...
    bool timed_out; // for nvme_request_check_timeout
    ...
    struct spdk_nvme_qpair *qpair; // adminq or dataq ?
    ...
    uint64_t submit_tick; // used for check timeout
    pid_t pid; // if equal with g_spdk_nvme_pid
    ...

}
struct spdk_nvme_probe_ctx{
    struct spdk_nvme_transport_id           trid;
    void                                    *cb_ctx;
    spdk_nvme_probe_cb                      probe_cb;
    spdk_nvme_attach_cb                     attach_cb;
    spdk_nvme_remove_cb                     remove_cb;
    TAILQ_HEAD(, spdk_nvme_ctrlr)           init_ctrlrs;
    //probe_ctx->init_ctrlrs  --->  g_spdk_nvme_driver->shared_attached_ctrlrs
}
struct spdk_nvme_transport_id {
    enum spdk_nvme_transport_type trtype;// for PCIE, SPDK_NVME_TRANSPORT_PCIE
    ...
    char traddr[SPDK_NVMF_TRADDR_MAX_LEN + 1]; // for PCIE, domain/bus/dev/func
    ...
}
pci device :
    domain/bus/dev/func
nvme transport:
    PCIE/TCP/RDMA/FC
nvme_pcie_qpair_construct
    ===init struct spdk_nvme_qpair==

nvme_ctrlr_probe: (init ctrlr & admin qpair)
    probe_cb
        g_nvme_attached_ctrlrs
        g_spdk_nvme_driver
        nvme_transport_ctrlr_construct  --- (nvme_pcie_ctrlr_construct)
            spdk_pci_device_claim
                get file from /tmp/spdk_pci_lock_%domain_%bus_%dev_%func
                open the file & mmap
            spdk_zmalloc
                alloc struct nvme_pcie_ctrlr(pctrlr)
            nvme_ctrlr_construct
                struct spdk_nvme_ctrlr (pctrlr->ctrlr)
            ...
            nvme_pcie_ctrlr_construct_admin_qpair(pctrlr->ctrlr  ctrlr->adminq)
                alloc struct nvme_pcie_qpair
                init qpair
                nvme_pcie_qpair_construct
                
            nvme_ctrlr_add_process
nvme_driver_init:(alloc struct nvme_driver && set to g_spdk_nvme_driver)
    g_spdk_nvme_pid
    g_spdk_nvme_driver(struct nvme_driver)
nvme_request_check_timeout:
    check admin q req->timeout(struct nvme_request)
nvme_qpair_is_admin_queue
    qpair->id == 0
    init in func nvme_pcie_ctrlr_construct_admin_qpair
nvme_allocate_request
    find req from free_req(nvme_request)
    && init req(nvme_request)
nvme_allocate_request_contig
    nvme_allocate_request
nvme_allocate_request_user_copy
    spdk_zmallloc(payload_size)  <---- memcpy(buffer)
    nvme_allocate_request_contig
        nvme_allocate_request && init req
nvme_user_copy_cmd_complete
    ????
spdk_nvme_qpair_process_completions
    nvme_transport_qpair_process_completions
        return num_completions
spdk_nvme_wait_for_completion_timeout
    spdk_nvme_qpair_process_completions
spdk_nvme_wait_for_completion
    spdk_nvme_wait_for_completion_robust_lock
        spdk_nvme_qpair_process_completions

nvme_pcie_ctrlr_scan
    spdk_pci_enumerate
        g_pci_devices
        pcie_nvme_enum_cb
            nvme_ctrlr_probe
spdk_nvme_connect_async(init probe_ctx && ctrlr_scan && probe_cb && attach_cb)
    nvme_driver_init
    alloc probe_ctx (struct spdk_nvme_probe_ctx)
    spdk_nvme_probe_ctx_init
        probe_cb: spdk_nvme_connect_probe_cb
        attach_cb: 
    spdk_nvme_probe_internal(ctrlr_scan && probe_cb && attach_cb)
        nvme_transport_ctrlr_scan
            nvme_pcie_ctrlr_scan
nvme_init_controllers()
    spdk_nvme_probe_poll_async
        nvme_ctrlr_poll_internal
spdk_nvme_connect(spdk_nvme_connect_async && nvme_init_controllers && spdk_nvme_get_ctrlr_by_trid)
    spdk_nvme_connect_async
    nvme_init_controllers
    spdk_nvme_get_ctrlr_by_trid
spdk_nvme_probe_async(init g_spdk_nvme_driver && init probe_ctx && )
    nvme_driver_init
    alloc probe_ctx(struct spdk_nvme_probe_ctx)
    spdk_nvme_probe_ctx_init
    spdk_nvme_probe_internal
spdk_nvme_probe
    spdk_nvme_probe_async
    nvme_init_controllers
spdk_nvme_probe_poll_async(check nvme_ctrlr status && probe_cb)
    nvme_ctrlr_poll_internal
        nvme_ctrlr_process_init
            nvme_ctrlr_get_cc  //Controller Configuration 详见最后的nvme bar空间
            nvme_ctrlr_get_csts // Controller Status  详见最后的nvme bar空间
            enum nvme_ctrlr_state {
                NVME_CTRLR_STATE_INIT_DELAY
                NVME_CTRLR_STATE_INIT
                NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_1
                NVME_CTRLR_STATE_DISABLE_WAIT_FOR_READY_0
                NVME_CTRLR_STATE_ENABLE
                NVME_CTRLR_STATE_ENABLE_WAIT_FOR_READY_1
                NVME_CTRLR_STATE_ENABLE_ADMIN_QUEUE
                NVME_CTRLR_STATE_IDENTIFY
                NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY
                NVME_CTRLR_STATE_SET_NUM_QUEUES
                NVME_CTRLR_STATE_WAIT_FOR_SET_NUM_QUEUES
                NVME_CTRLR_STATE_GET_NUM_QUEUES
                NVME_CTRLR_STATE_WAIT_FOR_GET_NUM_QUEUES
                NVME_CTRLR_STATE_CONSTRUCT_NS
                NVME_CTRLR_STATE_IDENTIFY_ACTIVE_NS
                NVME_CTRLR_STATE_IDENTIFY_NS
                NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_NS
                NVME_CTRLR_STATE_IDENTIFY_ID_DESCS
                NVME_CTRLR_STATE_WAIT_FOR_IDENTIFY_ID_DESCS
                NVME_CTRLR_STATE_CONFIGURE_AER
                NVME_CTRLR_STATE_WAIT_FOR_CONFIGURE_AER
                NVME_CTRLR_STATE_SET_SUPPORTED_LOG_PAGES
                NVME_CTRLR_STATE_SET_SUPPORTED_FEATURES
                NVME_CTRLR_STATE_SET_DB_BUF_CFG
                NVME_CTRLR_STATE_WAIT_FOR_DB_BUF_CFG
                NVME_CTRLR_STATE_SET_KEEP_ALIVE_TIMEOUT
                NVME_CTRLR_STATE_WAIT_FOR_KEEP_ALIVE_TIMEOUT
                NVME_CTRLR_STATE_SET_HOST_ID
                NVME_CTRLR_STATE_WAIT_FOR_HOST_ID
                NVME_CTRLR_STATE_READY
                NVME_CTRLR_STATE_ERROR
            }
            probe_ctx->probe_cb
struct nvme_bar {
    __u64                   cap;    /* Controller Capabilities */
    __u32                   vs;     /* Version */
    __u32                   intms;  /* Interrupt Mask Set */
    __u32                   intmc;  /* Interrupt Mask Clear */
    __u32                   cc;     /* Controller Configuration */
    __u32                   rsvd1;  /* Reserved */
    __u32                   csts;   /* Controller Status */
    __u32                   rsvd2;  /* Reserved */
    __u32                   aqa;    /* Admin Queue Attributes */
    __u64                   asq;    /* Admin SQ Base Address */
    __u64                   acq;    /* Admin CQ Base Address */
 };
spdk_nvme_prchk_flags_str
    check prchk_flags: 
        "prchk:reftag|guard" / "prchk:reftag" / "prchk:guard"

    {
        SPDK_NVME_IO_FLAGS_PRCHK_REFTAG
        // Enable protection information checking of the Logical Block Reference Tag field
        SPDK_NVME_IO_FLAGS_PRCHK_GUARD
        //Enable protection information checking of the Guard field
    }
spdk_nvme_prchk_flags_parse
    ...
spdk_nvme_transport_id_compare
    if trtype == SPDK_NVME_TRANSPORT_PCIE, parse traddr to {domain/bus/dev/func} & compare these vals;
    
spdk_nvme_host_id_parse
spdk_nvme_transport_id_parse
parse_next_key
spdk_nvme_transport_id_adrfam_str
spdk_nvme_transport_id_parse_adrfam
spdk_nvme_transport_id_trtype_str
spdk_nvme_transport_id_parse_trtype

nvme_ctrlr.c*

spdk_nvme_ctrlr_alloc_io_qpair
    spdk_nvme_ctrlr_get_default_io_qpair_opts
    nvme_ctrlr_get_cc
    spdk_bit_array_find_first_set
    nvme_transport_ctrlr_create_io_qpair
        nvme_pcie_ctrlr_create_io_qpair
            spdk_zmalloc pqpair (struct nvme_pcie_qpair) & qpair (struct spdk_nvme_qpair)
            nvme_qpair_init
            nvme_pcie_qpair_construct
            _nvme_pcie_ctrlr_create_io_qpair

//

probe_ctx->init_ctrlrs  --->  g_spdk_nvme_driver->shared_attached_ctrlrs

nvme_transport_ctrlr_scan(nvme_pcie_ctrlr_scan)
spdk_nvme_probe_internal(nvme_transport_ctrlr_scan && probe_cb && attach_cb)

spdk_nvme_probe_async(init g_spdk_nvme_driver && init probe_ctx && spdk_nvme_probe_internal)
spdk_nvme_probe(spdk_nvme_probe_async && nvme_init_controllers)

nvme_ctrlr_process_init(nvme_ctrlr_get_cc && nvme_ctrlr_get_csts)

spdk_nvme_probe_poll_async(nvme_ctrlr_process_init && remove from probe_ctx->init_ctrlrs && insert to g_spdk_nvme_driver->shared_attached_ctrlrs && attach_cb)
nvme_init_controllers(spdk_nvme_probe_poll_async)


spdk_nvme_connect_async(init probe_ctx && spdk_nvme_probe_internal)
spdk_nvme_connect(spdk_nvme_connect_async && nvme_init_controllers && spdk_nvme_get_ctrlr_by_trid)

nvme_init_controllers(spdk_nvme_probe_poll_async)

nvme_ctrlr_probe(probe_cb && attach_cb)

nvme_ctrlr_poll_internal(nvme_ctrlr_process_init && remove from probe_ctx->init_ctrlrs && insert g_spdk_nvme_driver->shared_attached_ctrlrs && attach_cb)  [add ctrlr shared]


getctrlr:(protected by g_spdk_nvme_driver->lock)
g_nvme_attached_ctrlrs //per-process list
g_spdk_nvme_driver->shared_attached_ctrlrs //multi-process shared list


layer:
nvme_transport
nvme_pcie