Subject: Re: Explicit enabling of disk caches
To: None <tech-kern@netbsd.org>
From: Jason R Thorpe <thorpej@wasabisystems.com>
List: tech-kern
Date: 09/05/2001 09:38:49
--jL2BoiuKMElzg3CS
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Sun, Sep 02, 2001 at 10:31:04AM -0700, Jason R Thorpe wrote:

 > I've been thinking of ways we can improve I/O performance, and one
 > obvious way is to provide a mechanism to explicitly manipulate the
 > read and write caches on disks.

I've done a little more work on this in my spare time, and have fleshed
the DKCACHE bits out a bit more.

I know of at least one person who is quite happy with these changes (because
his RAID performance improved roughly 4x), and can live with write-back
mode because he trusts his UPS :-)

Later this week I will probably look into gluing the disk cache knowledge
into the file system code.

-- 
        -- Jason R. Thorpe <thorpej@wasabisystems.com>

--jL2BoiuKMElzg3CS
Content-Type: text/plain; charset=us-ascii
Content-Description: dkcache.diffs
Content-Disposition: attachment; filename=foo

Index: sys/dkio.h
===================================================================
RCS file: /cvsroot/syssrc/sys/sys/dkio.h,v
retrieving revision 1.5
diff -c -r1.5 dkio.h
*** sys/dkio.h	2001/01/07 17:55:41	1.5
--- sys/dkio.h	2001/09/05 16:40:53
***************
*** 75,78 ****
--- 75,91 ----
  #define	ODIOCGDEFLABEL	_IOR('d', 114, struct olddisklabel)
  #endif
  
+ 		/* disk cache enable/disable */
+ #define	DIOCGCACHE	_IOR('d', 116, int)	/* get cache enables */
+ #define	DIOCSCACHE	_IOW('d', 117, int)	/* set cache enables */
+ 
+ #define	DKCACHE_READ	0x000001 /* read cache enabled */
+ #define	DKCACHE_WRITE	0x000002 /* write(back) cache enabled */
+ #define	DKCACHE_RCHANGE	0x000100 /* read enable is changeable */
+ #define	DKCACHE_WCHANGE	0x000200 /* write enable is changeable */
+ #define	DKCACHE_SAVE	0x010000 /* cache parameters are savable/save them */
+ 
+ 		/* sync disk cache */
+ #define	DIOCCACHESYNC	_IOW('d', 118, int)	/* sync cache (force?) */
+ 
  #endif /* _SYS_DKIO_H_ */
Index: dev/scsipi/sd.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/sd.c,v
retrieving revision 1.178
diff -c -r1.178 sd.c
*** dev/scsipi/sd.c	2001/07/18 18:21:05	1.178
--- dev/scsipi/sd.c	2001/09/05 16:40:54
***************
*** 912,917 ****
--- 912,919 ----
  		case DIOCLOCK:
  		case DIOCEJECT:
  		case ODIOCEJECT:
+ 		case DIOCGCACHE:
+ 		case DIOCSCACHE:
  		case SCIOCIDENTIFY:
  		case OSCIOCIDENTIFY:
  		case SCIOCCOMMAND:
***************
*** 1047,1052 ****
--- 1049,1089 ----
  		memcpy(addr, &newlabel, sizeof (struct olddisklabel));
  		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)
Index: dev/scsipi/sd_scsi.c
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/sd_scsi.c,v
retrieving revision 1.19
diff -c -r1.19 sd_scsi.c
*** dev/scsipi/sd_scsi.c	2001/08/31 07:09:42	1.19
--- dev/scsipi/sd_scsi.c	2001/09/05 16:40:54
***************
*** 62,67 ****
--- 62,68 ----
  #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>
***************
*** 102,111 ****
--- 103,116 ----
  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
***************
*** 369,372 ****
--- 374,475 ----
  		       flags|XS_CTL_IGNORE_ILLEGAL_REQUEST));
  	} 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);
  }
Index: dev/scsipi/sdvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/dev/scsipi/sdvar.h,v
retrieving revision 1.15
diff -c -r1.15 sdvar.h
*** dev/scsipi/sdvar.h	2001/05/23 02:16:19	1.15
--- dev/scsipi/sdvar.h	2001/09/05 16:40:54
***************
*** 109,114 ****
--- 109,116 ----
  	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 */

--jL2BoiuKMElzg3CS--