Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src Add NVMe command passthrough support.



details:   https://anonhg.NetBSD.org/src/rev/b66ae5034f0c
branches:  trunk
changeset: 815808:b66ae5034f0c
user:      nonaka <nonaka%NetBSD.org@localhost>
date:      Sat Jun 04 16:11:50 2016 +0000

description:
Add NVMe command passthrough support.

diffstat:

 distrib/sets/lists/comp/mi |    4 +-
 etc/MAKEDEV.tmpl           |   20 ++-
 etc/etc.amd64/MAKEDEV.conf |    6 +-
 sys/conf/majors            |    4 +-
 sys/dev/ic/Makefile        |    5 +-
 sys/dev/ic/nvme.c          |  331 ++++++++++++++++++++++++++++++++++++++++++++-
 sys/dev/ic/nvmeio.h        |   97 +++++++++++++
 sys/dev/ic/nvmereg.h       |    7 +-
 sys/dev/ic/nvmevar.h       |    5 +-
 9 files changed, 469 insertions(+), 10 deletions(-)

diffs (truncated from 641 to 300 lines):

diff -r ba57e04006cf -r b66ae5034f0c distrib/sets/lists/comp/mi
--- a/distrib/sets/lists/comp/mi        Sat Jun 04 15:27:11 2016 +0000
+++ b/distrib/sets/lists/comp/mi        Sat Jun 04 16:11:50 2016 +0000
@@ -1,4 +1,4 @@
-#      $NetBSD: mi,v 1.2038 2016/06/03 21:55:50 joerg Exp $
+#      $NetBSD: mi,v 1.2039 2016/06/04 16:11:50 nonaka Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 ./etc/mtree/set.comp                           comp-sys-root
@@ -498,6 +498,8 @@
 ./usr/include/dev/ic/nec765reg.h               comp-obsolete           obsolete
 ./usr/include/dev/ic/ns16450reg.h              comp-obsolete           obsolete
 ./usr/include/dev/ic/ns16550reg.h              comp-obsolete           obsolete
+./usr/include/dev/ic/nvmeio.h                  comp-c-include
+./usr/include/dev/ic/nvmereg.h                 comp-c-include
 ./usr/include/dev/ic/opl3sa3.h                 comp-obsolete           obsolete
 ./usr/include/dev/ic/opl3sa3reg.h              comp-obsolete           obsolete
 ./usr/include/dev/ic/pcdisplay.h               comp-obsolete           obsolete
diff -r ba57e04006cf -r b66ae5034f0c etc/MAKEDEV.tmpl
--- a/etc/MAKEDEV.tmpl  Sat Jun 04 15:27:11 2016 +0000
+++ b/etc/MAKEDEV.tmpl  Sat Jun 04 16:11:50 2016 +0000
@@ -1,5 +1,5 @@
 #!/bin/sh -
-#      $NetBSD: MAKEDEV.tmpl,v 1.179 2016/01/28 19:06:39 riz Exp $
+#      $NetBSD: MAKEDEV.tmpl,v 1.180 2016/06/04 16:11:50 nonaka Exp $
 #
 # Copyright (c) 2003,2007,2008 The NetBSD Foundation, Inc.
 # All rights reserved.
@@ -264,6 +264,8 @@
 #      np*     UNIBUS Ethernet co-processor interface, for downloading.
 #      npf     NPF packet filter
 #      nsmb*   SMB requester
+#      nvme*   Non-Volatile Memory Host Controller Interface device driver
+#      nvme*ns* Non-Volatile Memory namespace
 #      openfirm OpenFirmware accessor
 #      pad*    Pseudo-audio device driver
 #      pci*    PCI bus access devices
@@ -2201,6 +2203,22 @@
        mkdev vchiq c %vchiq_chr% 0 600
        ;;
 
+nvme[0-9]*ns[0-9]*)
+       unit=${i#nvme}
+       unit=${unit%ns*}
+       subunit=${i#nvme${unit}ns}
+       if [ 0$subunit -le 0 -o 0$subunit -ge 65536 ]; then
+               warn "bad nsid for $i: $subunit"
+               break
+       fi
+       mkdev nvme${unit}ns$subunit c %nvmens_chr% $(($unit * 65536 + $subunit))
+       ;;
+
+nvme[0-9]*)
+       unit=${i#nvme}
+       mkdev nvme$unit c %nvme_chr% $unit
+       ;;
+
 midevend)
 %MI_DEVICES_END%
 local)
diff -r ba57e04006cf -r b66ae5034f0c etc/etc.amd64/MAKEDEV.conf
--- a/etc/etc.amd64/MAKEDEV.conf        Sat Jun 04 15:27:11 2016 +0000
+++ b/etc/etc.amd64/MAKEDEV.conf        Sat Jun 04 16:11:50 2016 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: MAKEDEV.conf,v 1.21 2015/02/22 14:42:44 christos Exp $
+# $NetBSD: MAKEDEV.conf,v 1.22 2016/06/04 16:11:50 nonaka Exp $
 
 # As of 2003-04-17, the "init" case must not create more than 890 entries.
 all_md)
@@ -12,6 +12,10 @@
        makedev ccd0 md0 random
        makedev cgd0 cgd1
        makedev amr0 iop0 mfi0 mlx0 mly0 dpti0 dpt0 twe0
+       makedev nvme0 nvme0ns1 nvme0ns2 nvme0ns3 nvme0ns4
+       makedev nvme1 nvme1ns1 nvme1ns2 nvme1ns3 nvme1ns4
+       makedev nvme2 nvme2ns1 nvme2ns2 nvme1ns3 nvme2ns4
+       makedev nvme3 nvme3ns1 nvme3ns2 nvme1ns3 nvme3ns4
        makedev raid0 raid1 raid2 raid3
        makedev ld0 ld1 ld2 ld3
        makedev xbd0 xbd1 xbd2 xbd3 xen
diff -r ba57e04006cf -r b66ae5034f0c sys/conf/majors
--- a/sys/conf/majors   Sat Jun 04 15:27:11 2016 +0000
+++ b/sys/conf/majors   Sat Jun 04 16:11:50 2016 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: majors,v 1.73 2016/05/13 07:41:47 skrll Exp $
+# $NetBSD: majors,v 1.74 2016/06/04 16:11:50 nonaka Exp $
 #
 # Device majors for Machine-Independent drivers.
 #
@@ -72,3 +72,5 @@
 # 310-339 reserved for previously not MI storage devices
 
 device-major hdmicec   char 340            hdmicec
+device-major nvme      char 341                   nvme
+device-major nvmens    char 342                   nvmens
diff -r ba57e04006cf -r b66ae5034f0c sys/dev/ic/Makefile
--- a/sys/dev/ic/Makefile       Sat Jun 04 15:27:11 2016 +0000
+++ b/sys/dev/ic/Makefile       Sat Jun 04 16:11:50 2016 +0000
@@ -1,9 +1,10 @@
-#      $NetBSD: Makefile,v 1.24 2005/12/11 12:21:25 christos Exp $
+#      $NetBSD: Makefile,v 1.25 2016/06/04 16:11:51 nonaka Exp $
 
 INCSDIR= /usr/include/dev/ic
 
 # Only install includes which are used by userland
 INCS=  athioctl.h bt8xx.h hd44780var.h icpreg.h icp_ioctl.h isp_ioctl.h \
-       mlxreg.h mlxio.h rrunnerreg.h rrunnervar.h wdcreg.h wi_ieee.h
+       mlxreg.h mlxio.h nvmeio.h nvmereg.h rrunnerreg.h rrunnervar.h \
+       wdcreg.h wi_ieee.h
 
 .include <bsd.kinc.mk>
diff -r ba57e04006cf -r b66ae5034f0c sys/dev/ic/nvme.c
--- a/sys/dev/ic/nvme.c Sat Jun 04 15:27:11 2016 +0000
+++ b/sys/dev/ic/nvme.c Sat Jun 04 16:11:50 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: nvme.c,v 1.2 2016/05/02 19:18:29 christos Exp $        */
+/*     $NetBSD: nvme.c,v 1.3 2016/06/04 16:11:51 nonaka Exp $  */
 /*     $OpenBSD: nvme.c,v 1.49 2016/04/18 05:59:50 dlg Exp $ */
 
 /*
@@ -18,7 +18,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.2 2016/05/02 19:18:29 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.3 2016/06/04 16:11:51 nonaka Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -26,14 +26,19 @@
 #include <sys/atomic.h>
 #include <sys/bus.h>
 #include <sys/buf.h>
+#include <sys/conf.h>
 #include <sys/device.h>
 #include <sys/kmem.h>
 #include <sys/once.h>
+#include <sys/proc.h>
 #include <sys/queue.h>
 #include <sys/mutex.h>
 
+#include <uvm/uvm_extern.h>
+
 #include <dev/ic/nvmereg.h>
 #include <dev/ic/nvmevar.h>
+#include <dev/ic/nvmeio.h>
 
 int nvme_adminq_size = 128;
 int nvme_ioq_size = 128;
@@ -95,6 +100,13 @@
 static void    nvme_ns_sync_done(struct nvme_queue *, struct nvme_ccb *,
                    struct nvme_cqe *);
 
+static void    nvme_pt_fill(struct nvme_queue *, struct nvme_ccb *,
+                   void *);
+static void    nvme_pt_done(struct nvme_queue *, struct nvme_ccb *,
+                   struct nvme_cqe *);
+static int     nvme_command_passthrough(struct nvme_softc *,
+                   struct nvme_pt_command *, uint16_t, struct lwp *, bool);
+
 #define nvme_read4(_s, _r) \
        bus_space_read_4((_s)->sc_iot, (_s)->sc_ioh, (_r))
 #define nvme_write4(_s, _r, _v) \
@@ -729,6 +741,136 @@
 }
 
 static void
+nvme_pt_fill(struct nvme_queue *q, struct nvme_ccb *ccb, void *slot)
+{
+       struct nvme_softc *sc = q->q_sc;
+       struct nvme_sqe *sqe = slot;
+       struct nvme_pt_command *pt = ccb->ccb_cookie;
+       bus_dmamap_t dmap = ccb->ccb_dmamap;
+       int i;
+
+       sqe->opcode = pt->cmd.opcode;
+       htolem32(&sqe->nsid, pt->cmd.nsid);
+
+       if (pt->buf != NULL && pt->len > 0) {
+               htolem64(&sqe->entry.prp[0], dmap->dm_segs[0].ds_addr);
+               switch (dmap->dm_nsegs) {
+               case 1:
+                       break;
+               case 2:
+                       htolem64(&sqe->entry.prp[1], dmap->dm_segs[1].ds_addr);
+                       break;
+               default:
+                       for (i = 1; i < dmap->dm_nsegs; i++) {
+                               htolem64(&ccb->ccb_prpl[i - 1],
+                                   dmap->dm_segs[i].ds_addr);
+                       }
+                       bus_dmamap_sync(sc->sc_dmat,
+                           NVME_DMA_MAP(q->q_ccb_prpls),
+                           ccb->ccb_prpl_off,
+                           sizeof(*ccb->ccb_prpl) * dmap->dm_nsegs - 1,
+                           BUS_DMASYNC_PREWRITE);
+                       htolem64(&sqe->entry.prp[1], ccb->ccb_prpl_dva);
+                       break;
+               }
+       }
+
+       htolem32(&sqe->cdw10, pt->cmd.cdw10);
+       htolem32(&sqe->cdw11, pt->cmd.cdw11);
+       htolem32(&sqe->cdw12, pt->cmd.cdw12);
+       htolem32(&sqe->cdw13, pt->cmd.cdw13);
+       htolem32(&sqe->cdw14, pt->cmd.cdw14);
+       htolem32(&sqe->cdw15, pt->cmd.cdw15);
+}
+
+static void
+nvme_pt_done(struct nvme_queue *q, struct nvme_ccb *ccb, struct nvme_cqe *cqe)
+{
+       struct nvme_softc *sc = q->q_sc;
+       struct nvme_pt_command *pt = ccb->ccb_cookie;
+       bus_dmamap_t dmap = ccb->ccb_dmamap;
+
+       if (pt->buf != NULL && pt->len > 0) {
+               if (dmap->dm_nsegs > 2) {
+                       bus_dmamap_sync(sc->sc_dmat,
+                           NVME_DMA_MAP(q->q_ccb_prpls),
+                           ccb->ccb_prpl_off,
+                           sizeof(*ccb->ccb_prpl) * dmap->dm_nsegs - 1,
+                           BUS_DMASYNC_POSTWRITE);
+               }
+
+               bus_dmamap_sync(sc->sc_dmat, dmap, 0, dmap->dm_mapsize,
+                   pt->is_read ? BUS_DMASYNC_POSTREAD : BUS_DMASYNC_POSTWRITE);
+               bus_dmamap_unload(sc->sc_dmat, dmap);
+       }
+
+       pt->cpl.cdw0 = cqe->cdw0;
+       pt->cpl.flags = cqe->flags & ~NVME_CQE_PHASE;
+}
+
+static int
+nvme_command_passthrough(struct nvme_softc *sc, struct nvme_pt_command *pt,
+    uint16_t nsid, struct lwp *l, bool is_adminq)
+{
+       struct nvme_queue *q;
+       struct nvme_ccb *ccb;
+       void *buf = NULL;
+       int error;
+
+       if ((pt->buf == NULL && pt->len > 0) ||
+           (pt->buf != NULL && pt->len == 0))
+               return EINVAL;
+
+       q = is_adminq ? sc->sc_admin_q : nvme_get_q(sc);
+       ccb = nvme_ccb_get(q);
+       if (ccb == NULL)
+               return EBUSY;
+
+       if (pt->buf != NULL && pt->len > 0) {
+               buf = kmem_alloc(pt->len, KM_SLEEP);
+               if (buf == NULL) {
+                       error = ENOMEM;
+                       goto ccb_put;
+               }
+               if (!pt->is_read) {
+                       error = copyin(pt->buf, buf, pt->len);
+                       if (error)
+                               goto kmem_free;
+               }
+               error = bus_dmamap_load(sc->sc_dmat, ccb->ccb_dmamap, buf,
+                   pt->len, NULL,
+                   BUS_DMA_WAITOK |
+                     (pt->is_read ? BUS_DMA_READ : BUS_DMA_WRITE));
+               if (error)
+                       goto kmem_free;
+               bus_dmamap_sync(sc->sc_dmat, ccb->ccb_dmamap,
+                   0, ccb->ccb_dmamap->dm_mapsize,
+                   pt->is_read ? BUS_DMASYNC_PREREAD : BUS_DMASYNC_PREWRITE);
+       }
+
+       ccb->ccb_done = nvme_pt_done;
+       ccb->ccb_cookie = pt;
+
+       pt->cmd.nsid = nsid;
+       if (nvme_poll(sc, q, ccb, nvme_pt_fill)) {
+               error = EIO;
+               goto out;
+       }
+
+       error = 0;
+out:
+       if (buf != NULL) {
+               if (error == 0 && pt->is_read)
+                       error = copyout(buf, pt->buf, pt->len);
+kmem_free:
+               kmem_free(buf, pt->len);
+       }
+ccb_put:
+       nvme_ccb_put(q, ccb);
+       return error;
+}
+
+static void
 nvme_q_submit(struct nvme_softc *sc, struct nvme_queue *q, struct nvme_ccb *ccb,
     void (*fill)(struct nvme_queue *, struct nvme_ccb *, void *))
 {



Home | Main Index | Thread Index | Old Index