summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorjdolecek <jdolecek@NetBSD.org>2017-04-05 20:15:49 +0000
committerjdolecek <jdolecek@NetBSD.org>2017-04-05 20:15:49 +0000
commitcd514d579fa72dd93688604a6eb6f79308c40c7d (patch)
tree05369857f32ed36c7fff7e8f08a2828b15721f4e /sys/dev
parentcc023536cfc218717969f339a6fd93f2f1ac8c5c (diff)
expose disk device FUA/DPO support via DIOCGCACHE, and allow the flags
to be set for I/O; implement support in sd(4) and nvme(4) discussed on tech-kern
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/ic/ld_nvme.c16
-rw-r--r--sys/dev/ic/nvme.c7
-rw-r--r--sys/dev/ic/nvmevar.h3
-rw-r--r--sys/dev/scsipi/scsipi_disk.h12
-rw-r--r--sys/dev/scsipi/sd.c43
5 files changed, 64 insertions, 17 deletions
diff --git a/sys/dev/ic/ld_nvme.c b/sys/dev/ic/ld_nvme.c
index 20f6c831b7a..8ba7d642bac 100644
--- a/sys/dev/ic/ld_nvme.c
+++ b/sys/dev/ic/ld_nvme.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_nvme.c,v 1.14 2017/02/28 20:55:09 jdolecek Exp $ */
+/* $NetBSD: ld_nvme.c,v 1.15 2017/04/05 20:15:49 jdolecek Exp $ */
/*-
* Copyright (C) 2016 NONAKA Kimihiro <nonaka@netbsd.org>
@@ -26,7 +26,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.14 2017/02/28 20:55:09 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_nvme.c,v 1.15 2017/04/05 20:15:49 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -152,11 +152,15 @@ static int
ld_nvme_start(struct ld_softc *ld, struct buf *bp)
{
struct ld_nvme_softc *sc = device_private(ld->sc_dv);
+ int flags = BUF_ISWRITE(bp) ? 0 : NVME_NS_CTX_F_READ;
+
+ if (bp->b_flags & B_MEDIA_FUA)
+ flags |= NVME_NS_CTX_F_FUA;
return nvme_ns_dobio(sc->sc_nvme, sc->sc_nsid, sc,
bp, bp->b_data, bp->b_bcount,
sc->sc_ld.sc_secsize, bp->b_rawblkno,
- BUF_ISWRITE(bp) ? 0 : NVME_NS_CTX_F_READ,
+ flags,
ld_nvme_biodone);
}
@@ -221,7 +225,11 @@ ld_nvme_getcache(struct ld_softc *ld, int *addr)
int error;
struct ld_nvme_softc *sc = device_private(ld->sc_dv);
- *addr = 0;
+ /*
+ * DPO not supported, Dataset Management (DSM) field doesn't specify
+ * the same semantics.
+ */
+ *addr = DKCACHE_FUA;
if (!nvme_has_volatile_write_cache(sc->sc_nvme)) {
/* cache simply not present */
diff --git a/sys/dev/ic/nvme.c b/sys/dev/ic/nvme.c
index 19a9ab2d9fc..394756ae633 100644
--- a/sys/dev/ic/nvme.c
+++ b/sys/dev/ic/nvme.c
@@ -1,4 +1,4 @@
-/* $NetBSD: nvme.c,v 1.25 2017/02/28 20:53:50 jdolecek Exp $ */
+/* $NetBSD: nvme.c,v 1.26 2017/04/05 20:15:49 jdolecek 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.25 2017/02/28 20:53:50 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD: nvme.c,v 1.26 2017/04/05 20:15:49 jdolecek Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -727,6 +727,9 @@ nvme_ns_io_fill(struct nvme_queue *q, struct nvme_ccb *ccb, void *slot)
htolem64(&sqe->slba, ccb->nnc_blkno);
+ if (ISSET(ccb->nnc_flags, NVME_NS_CTX_F_FUA))
+ htolem16(&sqe->ioflags, NVM_SQE_IO_FUA);
+
/* guaranteed by upper layers, but check just in case */
KASSERT((ccb->nnc_datasize % ccb->nnc_secsize) == 0);
htolem16(&sqe->nlb, (ccb->nnc_datasize / ccb->nnc_secsize) - 1);
diff --git a/sys/dev/ic/nvmevar.h b/sys/dev/ic/nvmevar.h
index c8b5f40143d..65b890861fd 100644
--- a/sys/dev/ic/nvmevar.h
+++ b/sys/dev/ic/nvmevar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: nvmevar.h,v 1.12 2017/02/28 20:53:50 jdolecek Exp $ */
+/* $NetBSD: nvmevar.h,v 1.13 2017/04/05 20:15:49 jdolecek Exp $ */
/* $OpenBSD: nvmevar.h,v 1.8 2016/04/14 11:18:32 dlg Exp $ */
/*
@@ -64,6 +64,7 @@ struct nvme_ccb {
uint16_t nnc_flags;
#define NVME_NS_CTX_F_READ __BIT(0)
#define NVME_NS_CTX_F_POLL __BIT(1)
+#define NVME_NS_CTX_F_FUA __BIT(2)
struct buf *nnc_buf;
daddr_t nnc_blkno;
diff --git a/sys/dev/scsipi/scsipi_disk.h b/sys/dev/scsipi/scsipi_disk.h
index 1f6f3cd6910..0f473aab6ef 100644
--- a/sys/dev/scsipi/scsipi_disk.h
+++ b/sys/dev/scsipi/scsipi_disk.h
@@ -1,4 +1,4 @@
-/* $NetBSD: scsipi_disk.h,v 1.21 2007/12/25 18:33:42 perry Exp $ */
+/* $NetBSD: scsipi_disk.h,v 1.22 2017/04/05 20:15:49 jdolecek Exp $ */
/*
* SCSI and SCSI-like interfaces description
@@ -62,9 +62,10 @@ struct scsipi_rw_10 {
u_int8_t opcode;
u_int8_t byte2;
#define SRWB_RELADDR 0x01 /* obsolete */
-#define SRWB_FUA_NV 0x02 /* force unit access non-volatile cache */
-#define SRWB_FUA 0x08 /* force unit access */
-#define SRWB_DPO 0x10 /* disable page out */
+#define SRWB_FUA_NV 0x02 /* force unit access non-volatile cache (SCSI-3) */
+#define SRWB_RESV2 0x04 /* reserved (SCSI-2) */
+#define SRWB_FUA 0x08 /* force unit access volatile cache (SCSI-2) */
+#define SRWB_DPO 0x10 /* disable page out (SCSI-2) */
#define SRWB_PROTECT(x) ((x) << 5)
u_int8_t addr[4];
u_int8_t reserved;
@@ -159,4 +160,7 @@ struct scsipi_capacity_descriptor {
#define SCSIPI_CAP_DESC_CODE_FORMATTED 0x2
#define SCSIPI_CAP_DESC_CODE_NONE 0x3
+/* defines for the device specific byte in the mode select/sense header */
+#define SMH_DSP_DPOFUA 0x10
+
#endif /* _DEV_SCSIPI_SCSIPI_DISK_H_ */
diff --git a/sys/dev/scsipi/sd.c b/sys/dev/scsipi/sd.c
index 2b0a966952e..59e6b74649f 100644
--- a/sys/dev/scsipi/sd.c
+++ b/sys/dev/scsipi/sd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sd.c,v 1.322 2016/12/21 21:28:30 mlelstv Exp $ */
+/* $NetBSD: sd.c,v 1.323 2017/04/05 20:15:49 jdolecek Exp $ */
/*-
* Copyright (c) 1998, 2003, 2004 The NetBSD Foundation, Inc.
@@ -47,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.322 2016/12/21 21:28:30 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.323 2017/04/05 20:15:49 jdolecek Exp $");
#ifdef _KERNEL_OPT
#include "opt_scsi.h"
@@ -654,6 +654,7 @@ sd_diskstart(device_t dev, struct buf *bp)
struct scsipi_generic *cmdp;
struct scsipi_xfer *xs;
int error, flags, nblks, cmdlen;
+ int cdb_flags;
mutex_enter(chan_mtx(chan));
@@ -698,12 +699,27 @@ sd_diskstart(device_t dev, struct buf *bp)
nblks = howmany(bp->b_bcount, sd->params.blksize);
/*
+ * Pass FUA and/or DPO if requested. Must be done before CDB
+ * selection, as 6-byte CDB doesn't support the flags.
+ */
+ cdb_flags = 0;
+
+ if (bp->b_flags & B_MEDIA_FUA)
+ cdb_flags |= SRWB_FUA;
+
+ if (bp->b_flags & B_MEDIA_DPO)
+ cdb_flags |= SRWB_DPO;
+
+ /*
* Fill out the scsi command. Use the smallest CDB possible
- * (6-byte, 10-byte, or 16-byte).
+ * (6-byte, 10-byte, or 16-byte). If we need FUA or DPO,
+ * need to use 10-byte or bigger, as the 6-byte doesn't support
+ * the flags.
*/
if (((bp->b_rawblkno & 0x1fffff) == bp->b_rawblkno) &&
((nblks & 0xff) == nblks) &&
- !(periph->periph_quirks & PQUIRK_ONLYBIG)) {
+ !(periph->periph_quirks & PQUIRK_ONLYBIG) &&
+ !cdb_flags) {
/* 6-byte CDB */
memset(&cmd_small, 0, sizeof(cmd_small));
cmd_small.opcode = (bp->b_flags & B_READ) ?
@@ -732,6 +748,9 @@ sd_diskstart(device_t dev, struct buf *bp)
cmdp = (struct scsipi_generic *)&cmd16;
}
+ if (cdb_flags)
+ cmdp->bytes[0] = cdb_flags;
+
/*
* Figure out what flags to use.
*/
@@ -1796,7 +1815,9 @@ sd_getcache(struct sd_softc *sd, int *bitsp)
int error, bits = 0;
int big;
union scsi_disk_pages *pages;
+ uint8_t dev_spec;
+ /* only SCSI-2 and later supported */
if (periph->periph_version < 2)
return (EOPNOTSUPP);
@@ -1806,10 +1827,13 @@ sd_getcache(struct sd_softc *sd, int *bitsp)
if (error)
return (error);
- if (big)
+ if (big) {
pages = (void *)(&scsipi_sense.header.big + 1);
- else
+ dev_spec = scsipi_sense.header.big.dev_spec;
+ } else {
pages = (void *)(&scsipi_sense.header.small + 1);
+ dev_spec = scsipi_sense.header.small.dev_spec;
+ }
if ((pages->caching_params.flags & CACHING_RCD) == 0)
bits |= DKCACHE_READ;
@@ -1818,6 +1842,13 @@ sd_getcache(struct sd_softc *sd, int *bitsp)
if (pages->caching_params.pg_code & PGCODE_PS)
bits |= DKCACHE_SAVE;
+ /*
+ * Support for FUA/DPO, defined starting with SCSI-2. Use only
+ * if device claims to support it, according to the MODE SENSE.
+ */
+ if (ISSET(dev_spec, SMH_DSP_DPOFUA))
+ bits |= DKCACHE_FUA | DKCACHE_DPO;
+
memset(&scsipi_sense, 0, sizeof(scsipi_sense));
error = sd_mode_sense(sd, SMS_DBD, &scsipi_sense,
sizeof(scsipi_sense.pages.caching_params),