diff options
| author | jdolecek <jdolecek@NetBSD.org> | 2017-04-05 20:15:49 +0000 |
|---|---|---|
| committer | jdolecek <jdolecek@NetBSD.org> | 2017-04-05 20:15:49 +0000 |
| commit | cd514d579fa72dd93688604a6eb6f79308c40c7d (patch) | |
| tree | 05369857f32ed36c7fff7e8f08a2828b15721f4e /sys/dev | |
| parent | cc023536cfc218717969f339a6fd93f2f1ac8c5c (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.c | 16 | ||||
| -rw-r--r-- | sys/dev/ic/nvme.c | 7 | ||||
| -rw-r--r-- | sys/dev/ic/nvmevar.h | 3 | ||||
| -rw-r--r-- | sys/dev/scsipi/scsipi_disk.h | 12 | ||||
| -rw-r--r-- | sys/dev/scsipi/sd.c | 43 |
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), |
