summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorthorpej <thorpej@NetBSD.org>2002-01-09 04:12:11 +0000
committerthorpej <thorpej@NetBSD.org>2002-01-09 04:12:11 +0000
commit229efaff69c4cd7689140fd5748b8d34342f3789 (patch)
tree14b686d13af7c0bdf37ca2f8e56e074e40525de7 /sys/dev
parent2ad74785a41bdf47fbab20de4839a9a5ecd30c6f (diff)
Add ioctls to get (DIOCGCACHE) and set (DIOCSCACHE) cache enables
on disks in a generic way. Implement these ioctls for SCSI disks. This is not fully fleshed-out yet, but it allows people to experiment with disk caches more easily.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/scsipi/sd.c43
-rw-r--r--sys/dev/scsipi/sd_scsi.c107
-rw-r--r--sys/dev/scsipi/sdvar.h4
3 files changed, 148 insertions, 6 deletions
diff --git a/sys/dev/scsipi/sd.c b/sys/dev/scsipi/sd.c
index 3b9dc239151..3183a58303c 100644
--- a/sys/dev/scsipi/sd.c
+++ b/sys/dev/scsipi/sd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sd.c,v 1.180 2001/11/15 09:48:17 lukem Exp $ */
+/* $NetBSD: sd.c,v 1.181 2002/01/09 04:12:11 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.180 2001/11/15 09:48:17 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd.c,v 1.181 2002/01/09 04:12:11 thorpej Exp $");
#include "opt_scsi.h"
#include "rnd.h"
@@ -760,7 +760,7 @@ sdstart(periph)
cmdlen = sizeof(cmd_small);
cmdp = (struct scsipi_generic *)&cmd_small;
} else
-#endif
+#endif /* NSD_SCSIBUS > 0 */
{
/*
* Need a large cdb.
@@ -914,6 +914,8 @@ sdioctl(dev, cmd, addr, flag, p)
case DIOCLOCK:
case DIOCEJECT:
case ODIOCEJECT:
+ case DIOCGCACHE:
+ case DIOCSCACHE:
case SCIOCIDENTIFY:
case OSCIOCIDENTIFY:
case SCIOCCOMMAND:
@@ -1050,6 +1052,41 @@ sdioctl(dev, cmd, addr, flag, p)
return (0);
#endif
+ case DIOCGCACHE:
+ if (sd->sc_ops->sdo_getcache != NULL)
+ return ((*sd->sc_ops->sdo_getcache)(sd, (int *) addr));
+
+ /* Not supported on this device. */
+ *(int *) addr = 0;
+ return (0);
+
+ case DIOCSCACHE:
+ if ((flag & FWRITE) == 0)
+ return (EBADF);
+ if (sd->sc_ops->sdo_setcache != NULL)
+ return ((*sd->sc_ops->sdo_setcache)(sd, *(int *) addr));
+
+ /* Not supported on this device. */
+ return (EOPNOTSUPP);
+
+ case DIOCCACHESYNC:
+ /*
+ * XXX Do we really need to care about having a writeable
+ * file descriptor here?
+ */
+ if ((flag & FWRITE) == 0)
+ return (EBADF);
+ if (((sd->flags & SDF_DIRTY) != 0 || *(int *)addr != 0) &&
+ sd->sc_ops->sdo_flush != NULL) {
+ error = (*sd->sc_ops->sdo_flush)(sd, 0);
+ if (error)
+ sd->flags &= ~SDF_FLUSHING;
+ else
+ sd->flags &= ~(SDF_FLUSHING|SDF_DIRTY);
+ } else
+ error = 0;
+ return (error);
+
default:
if (part != RAW_PART)
return (ENOTTY);
diff --git a/sys/dev/scsipi/sd_scsi.c b/sys/dev/scsipi/sd_scsi.c
index d2e20f11825..21a2bc7f509 100644
--- a/sys/dev/scsipi/sd_scsi.c
+++ b/sys/dev/scsipi/sd_scsi.c
@@ -1,4 +1,4 @@
-/* $NetBSD: sd_scsi.c,v 1.21 2001/11/15 09:48:18 lukem Exp $ */
+/* $NetBSD: sd_scsi.c,v 1.22 2002/01/09 04:12:12 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -54,7 +54,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: sd_scsi.c,v 1.21 2001/11/15 09:48:18 lukem Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sd_scsi.c,v 1.22 2002/01/09 04:12:12 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@@ -64,6 +64,7 @@ __KERNEL_RCSID(0, "$NetBSD: sd_scsi.c,v 1.21 2001/11/15 09:48:18 lukem Exp $");
#include <sys/errno.h>
#include <sys/device.h>
#include <sys/disk.h>
+#include <sys/dkio.h>
#include <dev/scsipi/scsipi_all.h>
#include <dev/scsipi/scsi_all.h>
@@ -104,10 +105,14 @@ static int sd_scsibus_get_parms __P((struct sd_softc *,
static int sd_scsibus_get_optparms __P((struct sd_softc *,
struct disk_parms *, int));
static int sd_scsibus_flush __P((struct sd_softc *, int));
+static int sd_scsibus_getcache __P((struct sd_softc *, int *));
+static int sd_scsibus_setcache __P((struct sd_softc *, int));
const struct sd_ops sd_scsibus_ops = {
sd_scsibus_get_parms,
sd_scsibus_flush,
+ sd_scsibus_getcache,
+ sd_scsibus_setcache,
};
int
@@ -372,3 +377,101 @@ sd_scsibus_flush(sd, flags)
} else
return(0);
}
+
+int
+sd_scsibus_getcache(sd, bitsp)
+ struct sd_softc *sd;
+ int *bitsp;
+{
+ struct scsipi_periph *periph = sd->sc_periph;
+ struct sd_scsibus_mode_sense_data scsipi_sense;
+ int error, bits = 0;
+
+ if (periph->periph_version < 2)
+ return (EOPNOTSUPP);
+
+ error = sd_scsibus_mode_sense(sd, &scsipi_sense, 8, 0);
+ if (error)
+ return (error);
+
+ if ((scsipi_sense.pages.caching_params.flags & CACHING_RCD) == 0)
+ bits |= DKCACHE_READ;
+ if (scsipi_sense.pages.caching_params.flags & CACHING_WCE)
+ bits |= DKCACHE_WRITE;
+ if (scsipi_sense.pages.caching_params.pg_code & PGCODE_PS)
+ bits |= DKCACHE_SAVE;
+
+ error = sd_scsibus_mode_sense(sd, &scsipi_sense,
+ SMS_PAGE_CTRL_CHANGEABLE|8, 0);
+ if (error == 0) {
+ if (scsipi_sense.pages.caching_params.flags & CACHING_RCD)
+ bits |= DKCACHE_RCHANGE;
+ if (scsipi_sense.pages.caching_params.flags & CACHING_WCE)
+ bits |= DKCACHE_WCHANGE;
+ }
+
+ *bitsp = bits;
+
+ return (0);
+}
+
+int
+sd_scsibus_setcache(sd, bits)
+ struct sd_softc *sd;
+ int bits;
+{
+ struct scsipi_periph *periph = sd->sc_periph;
+ struct sd_scsibus_mode_sense_data scsipi_sense;
+ int error, size;
+ uint8_t oflags, byte2 = 0;
+
+ if (periph->periph_version < 2)
+ return (EOPNOTSUPP);
+
+ error = sd_scsibus_mode_sense(sd, &scsipi_sense, 8, 0);
+ if (error)
+ return (error);
+
+ oflags = scsipi_sense.pages.caching_params.flags;
+
+ if (bits & DKCACHE_READ)
+ scsipi_sense.pages.caching_params.flags &= ~CACHING_RCD;
+ else
+ scsipi_sense.pages.caching_params.flags |= CACHING_RCD;
+
+ if (bits & DKCACHE_WRITE)
+ scsipi_sense.pages.caching_params.flags |= CACHING_WCE;
+ else
+ scsipi_sense.pages.caching_params.flags &= ~CACHING_WCE;
+
+ if (oflags == scsipi_sense.pages.caching_params.flags)
+ return (0);
+
+ scsipi_sense.pages.caching_params.pg_code &= PGCODE_MASK;
+
+ if (bits & DKCACHE_SAVE)
+ byte2 |= SMS_SP;
+
+ size = sizeof(scsipi_sense.header) + sizeof(scsipi_sense.blk_desc) +
+ sizeof(struct scsipi_mode_page_header) +
+ scsipi_sense.pages.caching_params.pg_length;
+
+ if ((sd->sc_periph->periph_quirks & PQUIRK_ONLYBIG) &&
+ !(sd->sc_periph->periph_quirks & PQUIRK_NOBIGMODESENSE)) {
+ scsipi_sense.header.data_length = 0;
+ /* 2nd length byte in BIG header */
+ scsipi_sense.header.medium_type = 0;
+ error = scsipi_mode_select_big(sd->sc_periph, SMS_PF,
+ (struct scsipi_mode_header_big*)&scsipi_sense.header,
+ size, /* XS_CTL_SILENT | */ XS_CTL_DATA_ONSTACK,
+ SDRETRIES, 10000);
+ } else {
+ scsipi_sense.header.data_length = 0;
+ error = scsipi_mode_select(sd->sc_periph, SMS_PF,
+ &scsipi_sense.header, size,
+ /* XS_CTL_SILENT | */ XS_CTL_DATA_ONSTACK,
+ SDRETRIES, 10000);
+ }
+
+ return (error);
+}
diff --git a/sys/dev/scsipi/sdvar.h b/sys/dev/scsipi/sdvar.h
index c46152b61f4..969736a2589 100644
--- a/sys/dev/scsipi/sdvar.h
+++ b/sys/dev/scsipi/sdvar.h
@@ -1,4 +1,4 @@
-/* $NetBSD: sdvar.h,v 1.15 2001/05/23 02:16:19 chs Exp $ */
+/* $NetBSD: sdvar.h,v 1.16 2002/01/09 04:12:12 thorpej Exp $ */
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
@@ -109,6 +109,8 @@ struct sd_ops {
int (*sdo_get_parms) __P((struct sd_softc *, struct disk_parms *,
int));
int (*sdo_flush) __P((struct sd_softc *, int));
+ int (*sdo_getcache) __P((struct sd_softc *, int *));
+ int (*sdo_setcache) __P((struct sd_softc *, int));
};
#define SDGP_RESULT_OK 0 /* paramters obtained */
#define SDGP_RESULT_OFFLINE 1 /* no media, or otherwise losing */