diff options
| author | thorpej <thorpej@NetBSD.org> | 2002-01-09 04:12:11 +0000 |
|---|---|---|
| committer | thorpej <thorpej@NetBSD.org> | 2002-01-09 04:12:11 +0000 |
| commit | 229efaff69c4cd7689140fd5748b8d34342f3789 (patch) | |
| tree | 14b686d13af7c0bdf37ca2f8e56e074e40525de7 /sys/dev | |
| parent | 2ad74785a41bdf47fbab20de4839a9a5ecd30c6f (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.c | 43 | ||||
| -rw-r--r-- | sys/dev/scsipi/sd_scsi.c | 107 | ||||
| -rw-r--r-- | sys/dev/scsipi/sdvar.h | 4 |
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 */ |
