summaryrefslogtreecommitdiff
path: root/sys/dev/ic/nvme.c
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2016-04-13 13:05:11 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2016-04-13 13:05:11 +0000
commitcf25a71629cad47b2bc2e9558a7c062647a5651d (patch)
tree7bafc223257cf58428b5b8abc56c71a9a42bc370 /sys/dev/ic/nvme.c
parent01d0916d48a3b61330263c0d1ff55bfb7ebbebbb (diff)
implement handling of scsi read capacity commands
read cap 16 claims the devices are thin.
Diffstat (limited to 'sys/dev/ic/nvme.c')
-rw-r--r--sys/dev/ic/nvme.c80
1 files changed, 78 insertions, 2 deletions
diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c
index 4f5d7907e55..a8ef3559af2 100644
--- a/sys/dev/ic/nvme.c
+++ b/sys/dev/ic/nvme.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: nvme.c,v 1.27 2016/04/13 12:59:28 dlg Exp $ */
+/* $OpenBSD: nvme.c,v 1.28 2016/04/13 13:05:10 dlg Exp $ */
/*
* Copyright (c) 2014 David Gwynne <dlg@openbsd.org>
@@ -29,7 +29,7 @@
#include <machine/bus.h>
#include <scsi/scsi_all.h>
-#include <scsi/scsi_all.h>
+#include <scsi/scsi_disk.h>
#include <scsi/scsiconf.h>
#include <dev/ic/nvmereg.h>
@@ -92,6 +92,8 @@ struct scsi_adapter nvme_switch = {
void nvme_scsi_inq(struct scsi_xfer *);
void nvme_scsi_inquiry(struct scsi_xfer *);
+void nvme_scsi_capacity16(struct scsi_xfer *);
+void nvme_scsi_capacity(struct scsi_xfer *);
#define nvme_read4(_s, _r) \
bus_space_read_4((_s)->sc_iot, (_s)->sc_ioh, (_r))
@@ -416,6 +418,13 @@ nvme_scsi_cmd(struct scsi_xfer *xs)
case INQUIRY:
nvme_scsi_inq(xs);
return;
+ case READ_CAPACITY_16:
+ nvme_scsi_capacity16(xs);
+ return;
+ case READ_CAPACITY:
+ nvme_scsi_capacity(xs);
+ return;
+
default:
break;
}
@@ -472,6 +481,73 @@ nvme_scsi_inquiry(struct scsi_xfer *xs)
}
void
+nvme_scsi_capacity16(struct scsi_xfer *xs)
+{
+ struct scsi_read_cap_data_16 rcd;
+ struct scsi_link *link = xs->sc_link;
+ struct nvme_softc *sc = link->adapter_softc;
+ struct nvm_identify_namespace *ns;
+ struct nvm_namespace_format *f;
+ u_int64_t nsze;
+ u_int16_t tpe = READ_CAP_16_TPE;
+
+ ns = sc->sc_namespaces[link->target].ident;
+
+ if (xs->cmdlen != sizeof(struct scsi_read_capacity_16)) {
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ return;
+ }
+
+ nsze = lemtoh64(&ns->nsze);
+ f = &ns->lbaf[NVME_ID_NS_FLBAS(ns->flbas)];
+
+ memset(&rcd, 0, sizeof(rcd));
+ _lto8b(nsze, rcd.addr);
+ _lto4b(1 << f->lbads, rcd.length);
+ _lto2b(tpe, rcd.lowest_aligned);
+
+ memcpy(xs->data, &rcd, MIN(sizeof(rcd), xs->datalen));
+
+ xs->error = XS_NOERROR;
+ scsi_done(xs);
+}
+
+void
+nvme_scsi_capacity(struct scsi_xfer *xs)
+{
+ struct scsi_read_cap_data rcd;
+ struct scsi_link *link = xs->sc_link;
+ struct nvme_softc *sc = link->adapter_softc;
+ struct nvm_identify_namespace *ns;
+ struct nvm_namespace_format *f;
+ u_int64_t nsze;
+
+ ns = sc->sc_namespaces[link->target].ident;
+
+ if (xs->cmdlen != sizeof(struct scsi_read_capacity)) {
+ xs->error = XS_DRIVER_STUFFUP;
+ scsi_done(xs);
+ return;
+ }
+
+ nsze = lemtoh64(&ns->nsze);
+ if (nsze > 0xffffffff)
+ nsze = 0xffffffff;
+
+ f = &ns->lbaf[NVME_ID_NS_FLBAS(ns->flbas)];
+
+ memset(&rcd, 0, sizeof(rcd));
+ _lto4b(nsze, rcd.addr);
+ _lto4b(1 << f->lbads, rcd.length);
+
+ memcpy(xs->data, &rcd, MIN(sizeof(rcd), xs->datalen));
+
+ xs->error = XS_NOERROR;
+ scsi_done(xs);
+}
+
+void
nvme_scsi_free(struct scsi_link *link)
{
struct nvme_softc *sc = link->adapter_softc;