diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2016-04-13 13:05:11 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2016-04-13 13:05:11 +0000 |
commit | cf25a71629cad47b2bc2e9558a7c062647a5651d (patch) | |
tree | 7bafc223257cf58428b5b8abc56c71a9a42bc370 /sys/dev/ic/nvme.c | |
parent | 01d0916d48a3b61330263c0d1ff55bfb7ebbebbb (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.c | 80 |
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; |