[RFC PATCH] scsi: sd: add wce_rcd sysfs interface

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



add user friendly interface wce_rcd to enable/disable
write&read cache. The code base on cache_type, but need short input.

enable both write and read cache:
echo "10" > wce_rcd

wce rcd write_cache read_cache
0   0   off         on
0   1   off         off
1   0   on          on
1   1   on          off

Signed-off-by: weiping zhang <zhangweiping@xxxxxxxxxxxxxxx>
---
 drivers/scsi/sd.c | 84 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 84 insertions(+)

diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a028ab3..9ab210c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -139,6 +139,15 @@ static const char *sd_cache_types[] = {
 	"write back, no read (daft)"
 };
 
+/*
+ * wce rcd write_cache read_cache
+ * 0   0   off         on
+ * 0   1   off         off
+ * 1   0   on          on
+ * 1   1   on          off
+ */
+static const char * const sd_wce_rcd[] = {"00", "01", "10", "11"};
+
 static void sd_set_flush_flag(struct scsi_disk *sdkp)
 {
 	bool wc = false, fua = false;
@@ -287,6 +296,80 @@ cache_type_show(struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR_RW(cache_type);
 
 static ssize_t
+wce_rcd_store(struct device *dev, struct device_attribute *attr,
+		 const char *buf, size_t count)
+{
+	int ct, rcd, wce, sp;
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+	struct scsi_device *sdp = sdkp->device;
+	char buffer[64];
+	char *buffer_data;
+	struct scsi_mode_data data;
+	struct scsi_sense_hdr sshdr;
+	static const char temp[] = "temp ";
+	int len;
+
+	if (sdp->type != TYPE_DISK && sdp->type != TYPE_ZBC)
+		/* no cache control on RBC devices; theoretically they
+		 * can do it, but there's probably so many exceptions
+		 * it's not worth the risk
+		 */
+		return -EINVAL;
+
+	if (strncmp(buf, temp, sizeof(temp) - 1) == 0) {
+		buf += sizeof(temp) - 1;
+		sdkp->cache_override = 1;
+	} else {
+		sdkp->cache_override = 0;
+	}
+
+	ct = sysfs_match_string(sd_wce_rcd, buf);
+	if (ct < 0)
+		return -EINVAL;
+
+	rcd = ct & 0x01 ? 1 : 0;
+	wce = (ct & 0x02) && !sdkp->write_prot ? 1 : 0;
+
+	if (sdkp->cache_override) {
+		sdkp->WCE = wce;
+		sdkp->RCD = rcd;
+		sd_set_flush_flag(sdkp);
+		return count;
+	}
+
+	if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
+			    SD_MAX_RETRIES, &data, NULL))
+		return -EINVAL;
+	len = min_t(size_t, sizeof(buffer), data.length - data.header_length -
+		  data.block_descriptor_length);
+	buffer_data = buffer + data.header_length +
+		data.block_descriptor_length;
+	buffer_data[2] &= ~0x05;
+	buffer_data[2] |= wce << 2 | rcd;
+	sp = buffer_data[0] & 0x80 ? 1 : 0;
+	buffer_data[0] &= ~0x80;
+
+	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
+			     SD_MAX_RETRIES, &data, &sshdr)) {
+		if (scsi_sense_valid(&sshdr))
+			sd_print_sense_hdr(sdkp, &sshdr);
+		return -EINVAL;
+	}
+	revalidate_disk(sdkp->disk);
+	return count;
+}
+
+static ssize_t
+wce_rcd_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(dev);
+	int ct = sdkp->RCD + 2*sdkp->WCE;
+
+	return sprintf(buf, "%s\n", sd_wce_rcd[ct]);
+}
+static DEVICE_ATTR_RW(wce_rcd);
+
+static ssize_t
 FUA_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct scsi_disk *sdkp = to_scsi_disk(dev);
@@ -524,6 +607,7 @@ static DEVICE_ATTR_RW(max_write_same_blocks);
 
 static struct attribute *sd_disk_attrs[] = {
 	&dev_attr_cache_type.attr,
+	&dev_attr_wce_rcd.attr,
 	&dev_attr_FUA.attr,
 	&dev_attr_allow_restart.attr,
 	&dev_attr_manage_start_stop.attr,
-- 
2.9.4




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux