Beispiel #1
0
/**
 * Setup admin queue.
 * @param   ses         session
 */
static void unvme_adminq_create(unvme_session_t* ses)
{
    DEBUG_FN("%x: qs=%d", unvme_dev.vfiodev->pci, ses->qsize);

    unvme_queue_t* adminq = ses->queues;
    adminq->ses = ses;
    adminq->sqdma = vfio_dma_alloc(unvme_dev.vfiodev,
                                   ses->qsize * sizeof(nvme_sq_entry_t));
    if (!adminq->sqdma) FATAL("vfio_dma_alloc");
    adminq->cqdma = vfio_dma_alloc(unvme_dev.vfiodev,
                                   ses->qsize * sizeof(nvme_cq_entry_t));
    if (!adminq->cqdma) FATAL("vfio_dma_alloc");
    adminq->nvq = nvme_setup_adminq(unvme_dev.nvmedev, ses->qsize,
                                    adminq->sqdma->buf, adminq->sqdma->addr,
                                    adminq->cqdma->buf, adminq->cqdma->addr);
    if (!adminq->nvq) FATAL("nvme_setup_adminq");
}
Beispiel #2
0
/**
 * Create an I/O queue.
 * @param   ses         session
 * @param   sqi         session queue id
 */
static void unvme_ioq_create(unvme_session_t* ses, int sqi)
{
    unvme_queue_t* ioq = &ses->queues[sqi];
    ioq->ses = ses;

    if (sqi == 0) {
        ses->id = ses->prev->queues[ses->prev->qcount-1].id + 1;
        ses->ns.sid = ses->id;
    }
    ioq->id = ses->id + sqi;
    DEBUG_FN("%x: q=%d qs=%d", unvme_dev.vfiodev->pci, ioq->id, ses->qsize);

    int i;
    for (i = 0; i < 16; i++) unvme_get_desc(ioq);
    ioq->descfree = ioq->desclist;
    ioq->desclist = NULL;
    ioq->desccount = 0;
    ioq->cidmask = zalloc(ses->masksize);

    // assume maxppio fits 1 PRP list page
    ioq->prpsize = ses->ns.pagesize;
    ioq->prplist = vfio_dma_alloc(unvme_dev.vfiodev, ioq->prpsize * ses->qsize);
    if (!ioq->prplist) FATAL("vfio_dma_alloc");
    ioq->sqdma = vfio_dma_alloc(unvme_dev.vfiodev,
                                ses->qsize * sizeof(nvme_sq_entry_t));
    if (!ioq->sqdma) FATAL("vfio_dma_alloc");
    ioq->cqdma = vfio_dma_alloc(unvme_dev.vfiodev,
                                ses->qsize * sizeof(nvme_cq_entry_t));
    if (!ioq->cqdma) FATAL("vfio_dma_alloc");

    ioq->nvq = nvme_create_ioq(unvme_dev.nvmedev, ioq->id, ses->qsize,
                               ioq->sqdma->buf, ioq->sqdma->addr,
                               ioq->cqdma->buf, ioq->cqdma->addr);
    if (!ioq->nvq) FATAL("nvme_create_ioq");

    unvme_dev.numioqs++;

    INFO_FN("%x: q=%d qc=%d qs=%d db=%#04lx", unvme_dev.vfiodev->pci,
            ioq->nvq->id, unvme_dev.numioqs, ioq->nvq->size,
            (u64)ioq->nvq->sq_doorbell - (u64)unvme_dev.nvmedev->reg);
}
Beispiel #3
0
/**
 * Create a namespace object.
 * @param   ses         session
 * @param   nsid        namespace id
 */
static void unvme_ns_init(unvme_session_t* ses, int nsid)
{
    unvme_ns_t* ns = &ses->ns;
    ns->maxqsize = unvme_dev.nvmedev->maxqsize;
    ns->pageshift = unvme_dev.nvmedev->pageshift;
    ns->pagesize = 1 << ns->pageshift;

    vfio_dma_t* dma = vfio_dma_alloc(unvme_dev.vfiodev, ns->pagesize << 1);
    if (!dma) FATAL("vfio_dma_alloc");
    if (nvme_acmd_identify(unvme_dev.nvmedev, nsid, dma->addr,
                        dma->addr + ns->pagesize)) FATAL("nvme_acmd_identify");

    if (nsid == 0) {
        int i;
        nvme_identify_ctlr_t* idc = (nvme_identify_ctlr_t*)dma->buf;
        ns->vid = idc->vid;
        memcpy(ns->sn, idc->sn, sizeof(ns->sn));
        for (i = sizeof(ns->sn) - 1; i > 0 && ns->sn[i] == ' '; i--) ns->sn[i] = 0;
        memcpy(ns->mn, idc->mn, sizeof(ns->mn));
        for (i = sizeof(ns->mn) - 1; i > 0 && ns->mn[i] == ' '; i--) ns->mn[i] = 0;
        memcpy(ns->fr, idc->fr, sizeof(ns->fr));
        for (i = sizeof(ns->fr) - 1; i > 0 && ns->fr[i] == ' '; i--) ns->fr[i] = 0;
        ns->maxppio = ns->pagesize / sizeof(u64); // limit to 1 PRP list page
        if (idc->mdts) {
            int maxp = 2;
            for (i = 1; i < idc->mdts; i++) maxp *= 2;
            if (ns->maxppio > maxp) ns->maxppio = maxp;
        }
    } else {
        memcpy(ns, &unvme_dev.ses->ns, sizeof(unvme_ns_t));
        nvme_identify_ns_t* idns = (nvme_identify_ns_t*)dma->buf;
        ns->blockcount = idns->ncap;
        ns->blockshift = idns->lbaf[idns->flbas & 0xF].lbads;
        ns->blocksize = 1 << ns->blockshift;
        if (ns->blocksize > ns->pagesize || ns->blockcount < 8) {
            FATAL("ps=%d bs=%d bc=%ld",
                  ns->pagesize, ns->blocksize, ns->blockcount);
        }
        ns->nbpp = ns->pagesize / ns->blocksize;
        ns->maxbpio = ns->maxppio * ns->nbpp;
        ns->maxiopq = ses->qsize - 1;
    }
    ns->id = nsid;
    ns->ses = ses;
    ns->qcount = ses->qcount;
    ns->qsize = ses->qsize;

    if (vfio_dma_free(dma)) FATAL("vfio_dma_free");
}
Beispiel #4
0
/**
 * Allocate an I/O buffer associated with a session.
 * @param   ses         session
 * @param   size        buffer size
 * @return  the allocated buffer or NULL if failure.
 */
void* unvme_do_alloc(unvme_session_t* ses, u64 size)
{
    void* buf = NULL;

    pthread_spin_lock(&ses->iomem.lock);
    vfio_dma_t* dma = vfio_dma_alloc(unvme_dev.vfiodev, size);
    if (dma) {
        unvme_iomem_t* iomem = &ses->iomem;
        if (iomem->count >= iomem->size) {
            iomem->size += 256;
            iomem->map = realloc(iomem->map, iomem->size * sizeof (vfio_dma_t*));
        }
        iomem->map[iomem->count++] = dma;
        buf = dma->buf;
    }
    pthread_spin_unlock(&ses->iomem.lock);

    return buf;
}
Beispiel #5
0
/**
 * Main program.
 */
int main(int argc, char* argv[])
{
    const char* usage = "Usage: %s pciname nsid log_page_id\n\
where\n\
      log_page_id 1 = error information\n\
      log_page_id 2 = SMART / Health information\n\
      log_page_id 3 = firmware slot information\n";

    error_print_progname = no_progname;
    if (argc != 4) error(1, 0, usage, argv[0]);

    char* s = argv[2];
    int nsid = strtol(s, &s, 0);
    if (*s || nsid <= 0) error(1, 0, usage, argv[0]);
    int lid = strtol(argv[3], &s, 0);
    if (*s || (lid < 1 || lid > 3)) error(1, 0, usage, argv[0]);

    nvme_setup(argv[1], 8);
    vfio_dma_t* dma = vfio_dma_alloc(vfiodev, 2 << PAGESHIFT);
    if (!dma) error(1, 0, "vfio_dma_alloc");

    int numd = dma->size / sizeof(u32) - 1;
    u64 prp1 = dma->addr;
    u64 prp2 = dma->addr + (1 << PAGESHIFT);
    int err = nvme_acmd_get_log_page(nvmedev, nsid, lid, numd, prp1, prp2);
    if (err) error(1, 0, "nvme_acmd_get_log_page");

    switch (lid) {
        case 1: print_error_info(dma->buf); break;
        case 2: print_smart_health(dma->buf); break;
        case 3: print_firmware_slot(dma->buf); break;
    }

    nvme_cleanup();
    return 0;
}