aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@steeleye.com>2006-03-18 15:14:21 -0500
committerJames Bottomley <jejb@mulgrave.il.steeleye.com>2006-03-19 11:19:51 -0500
commit6bdaa1f17dd32ec62345c7b57842f53e6278a2fa (patch)
treefd84576b5b62a48676ed3a9ef136a3f653431cc7 /drivers/scsi
parent5baba830e93732e802dc7e0a362eb730e1917f58 (diff)
[SCSI] allow displaying and setting of cache type via sysfs
I think I promised to do this two years ago This patch adds a scsi_disk class with the cache type and FUA parameters, so user land application can easily obtain them without having to parse dmesg. It also allows setting the cache type (use with care...) This patch is a bit dangerous because I've replaced the disk kref with a class device reference ... Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/sd.c136
1 files changed, 113 insertions, 23 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 3b01e5d6221c..024ef86c5242 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -47,7 +47,6 @@
47#include <linux/init.h> 47#include <linux/init.h>
48#include <linux/blkdev.h> 48#include <linux/blkdev.h>
49#include <linux/blkpg.h> 49#include <linux/blkpg.h>
50#include <linux/kref.h>
51#include <linux/delay.h> 50#include <linux/delay.h>
52#include <linux/mutex.h> 51#include <linux/mutex.h>
53#include <asm/uaccess.h> 52#include <asm/uaccess.h>
@@ -115,12 +114,10 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);
115 */ 114 */
116#define SD_BUF_SIZE 512 115#define SD_BUF_SIZE 512
117 116
118static void scsi_disk_release(struct kref *kref);
119
120struct scsi_disk { 117struct scsi_disk {
121 struct scsi_driver *driver; /* always &sd_template */ 118 struct scsi_driver *driver; /* always &sd_template */
122 struct scsi_device *device; 119 struct scsi_device *device;
123 struct kref kref; 120 struct class_device cdev;
124 struct gendisk *disk; 121 struct gendisk *disk;
125 unsigned int openers; /* protected by BKL for now, yuck */ 122 unsigned int openers; /* protected by BKL for now, yuck */
126 sector_t capacity; /* size in 512-byte sectors */ 123 sector_t capacity; /* size in 512-byte sectors */
@@ -131,6 +128,7 @@ struct scsi_disk {
131 unsigned RCD : 1; /* state of disk RCD bit, unused */ 128 unsigned RCD : 1; /* state of disk RCD bit, unused */
132 unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ 129 unsigned DPOFUA : 1; /* state of disk DPOFUA bit */
133}; 130};
131#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev)
134 132
135static DEFINE_IDR(sd_index_idr); 133static DEFINE_IDR(sd_index_idr);
136static DEFINE_SPINLOCK(sd_index_lock); 134static DEFINE_SPINLOCK(sd_index_lock);
@@ -152,6 +150,92 @@ static int sd_issue_flush(struct device *, sector_t *);
152static void sd_prepare_flush(request_queue_t *, struct request *); 150static void sd_prepare_flush(request_queue_t *, struct request *);
153static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, 151static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
154 unsigned char *buffer); 152 unsigned char *buffer);
153static void scsi_disk_release(struct class_device *cdev);
154
155static const char *sd_cache_types[] = {
156 "write through", "none", "write back",
157 "write back, no read (daft)"
158};
159
160static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,
161 size_t count)
162{
163 int i, ct = -1, rcd, wce, sp;
164 struct scsi_disk *sdkp = to_scsi_disk(cdev);
165 struct scsi_device *sdp = sdkp->device;
166 char buffer[64];
167 char *buffer_data;
168 struct scsi_mode_data data;
169 struct scsi_sense_hdr sshdr;
170 int len;
171
172 if (sdp->type != TYPE_DISK)
173 /* no cache control on RBC devices; theoretically they
174 * can do it, but there's probably so many exceptions
175 * it's not worth the risk */
176 return -EINVAL;
177
178 for (i = 0; i < sizeof(sd_cache_types)/sizeof(sd_cache_types[0]); i++) {
179 const int len = strlen(sd_cache_types[i]);
180 if (strncmp(sd_cache_types[i], buf, len) == 0 &&
181 buf[len] == '\n') {
182 ct = i;
183 break;
184 }
185 }
186 if (ct < 0)
187 return -EINVAL;
188 rcd = ct & 0x01 ? 1 : 0;
189 wce = ct & 0x02 ? 1 : 0;
190 if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,
191 SD_MAX_RETRIES, &data, NULL))
192 return -EINVAL;
193 len = min(sizeof(buffer), data.length - data.header_length -
194 data.block_descriptor_length);
195 buffer_data = buffer + data.header_length +
196 data.block_descriptor_length;
197 buffer_data[2] &= ~0x05;
198 buffer_data[2] |= wce << 2 | rcd;
199 sp = buffer_data[0] & 0x80 ? 1 : 0;
200
201 if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,
202 SD_MAX_RETRIES, &data, &sshdr)) {
203 if (scsi_sense_valid(&sshdr))
204 scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr);
205 return -EINVAL;
206 }
207 sd_revalidate_disk(sdkp->disk);
208 return count;
209}
210
211static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf)
212{
213 struct scsi_disk *sdkp = to_scsi_disk(cdev);
214 int ct = sdkp->RCD + 2*sdkp->WCE;
215
216 return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);
217}
218
219static ssize_t sd_show_fua(struct class_device *cdev, char *buf)
220{
221 struct scsi_disk *sdkp = to_scsi_disk(cdev);
222
223 return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);
224}
225
226static struct class_device_attribute sd_disk_attrs[] = {
227 __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,
228 sd_store_cache_type),
229 __ATTR(FUA, S_IRUGO, sd_show_fua, NULL),
230 __ATTR_NULL,
231};
232
233static struct class sd_disk_class = {
234 .name = "scsi_disk",
235 .owner = THIS_MODULE,
236 .release = scsi_disk_release,
237 .class_dev_attrs = sd_disk_attrs,
238};
155 239
156static struct scsi_driver sd_template = { 240static struct scsi_driver sd_template = {
157 .owner = THIS_MODULE, 241 .owner = THIS_MODULE,
@@ -195,8 +279,6 @@ static int sd_major(int major_idx)
195 } 279 }
196} 280}
197 281
198#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref)
199
200static inline struct scsi_disk *scsi_disk(struct gendisk *disk) 282static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
201{ 283{
202 return container_of(disk->private_data, struct scsi_disk, driver); 284 return container_of(disk->private_data, struct scsi_disk, driver);
@@ -209,7 +291,7 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk)
209 if (disk->private_data) { 291 if (disk->private_data) {
210 sdkp = scsi_disk(disk); 292 sdkp = scsi_disk(disk);
211 if (scsi_device_get(sdkp->device) == 0) 293 if (scsi_device_get(sdkp->device) == 0)
212 kref_get(&sdkp->kref); 294 class_device_get(&sdkp->cdev);
213 else 295 else
214 sdkp = NULL; 296 sdkp = NULL;
215 } 297 }
@@ -243,7 +325,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp)
243 struct scsi_device *sdev = sdkp->device; 325 struct scsi_device *sdev = sdkp->device;
244 326
245 mutex_lock(&sd_ref_mutex); 327 mutex_lock(&sd_ref_mutex);
246 kref_put(&sdkp->kref, scsi_disk_release); 328 class_device_put(&sdkp->cdev);
247 scsi_device_put(sdev); 329 scsi_device_put(sdev);
248 mutex_unlock(&sd_ref_mutex); 330 mutex_unlock(&sd_ref_mutex);
249} 331}
@@ -1381,10 +1463,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
1381 res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); 1463 res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr);
1382 1464
1383 if (scsi_status_is_good(res)) { 1465 if (scsi_status_is_good(res)) {
1384 const char *types[] = {
1385 "write through", "none", "write back",
1386 "write back, no read (daft)"
1387 };
1388 int ct = 0; 1466 int ct = 0;
1389 int offset = data.header_length + data.block_descriptor_length; 1467 int offset = data.header_length + data.block_descriptor_length;
1390 1468
@@ -1417,7 +1495,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
1417 ct = sdkp->RCD + 2*sdkp->WCE; 1495 ct = sdkp->RCD + 2*sdkp->WCE;
1418 1496
1419 printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", 1497 printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n",
1420 diskname, types[ct], 1498 diskname, sd_cache_types[ct],
1421 sdkp->DPOFUA ? " w/ FUA" : ""); 1499 sdkp->DPOFUA ? " w/ FUA" : "");
1422 1500
1423 return; 1501 return;
@@ -1548,8 +1626,6 @@ static int sd_probe(struct device *dev)
1548 if (!sdkp) 1626 if (!sdkp)
1549 goto out; 1627 goto out;
1550 1628
1551 kref_init(&sdkp->kref);
1552
1553 gd = alloc_disk(16); 1629 gd = alloc_disk(16);
1554 if (!gd) 1630 if (!gd)
1555 goto out_free; 1631 goto out_free;
@@ -1566,7 +1642,16 @@ static int sd_probe(struct device *dev)
1566 if (error) 1642 if (error)
1567 goto out_put; 1643 goto out_put;
1568 1644
1645 class_device_initialize(&sdkp->cdev);
1646 sdkp->cdev.dev = &sdp->sdev_gendev;
1647 sdkp->cdev.class = &sd_disk_class;
1648 strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE);
1649
1650 if (class_device_add(&sdkp->cdev))
1651 goto out_put;
1652
1569 get_device(&sdp->sdev_gendev); 1653 get_device(&sdp->sdev_gendev);
1654
1570 sdkp->device = sdp; 1655 sdkp->device = sdp;
1571 sdkp->driver = &sd_template; 1656 sdkp->driver = &sd_template;
1572 sdkp->disk = gd; 1657 sdkp->disk = gd;
@@ -1616,11 +1701,11 @@ static int sd_probe(struct device *dev)
1616 1701
1617 return 0; 1702 return 0;
1618 1703
1619out_put: 1704 out_put:
1620 put_disk(gd); 1705 put_disk(gd);
1621out_free: 1706 out_free:
1622 kfree(sdkp); 1707 kfree(sdkp);
1623out: 1708 out:
1624 return error; 1709 return error;
1625} 1710}
1626 1711
@@ -1639,12 +1724,13 @@ static int sd_remove(struct device *dev)
1639{ 1724{
1640 struct scsi_disk *sdkp = dev_get_drvdata(dev); 1725 struct scsi_disk *sdkp = dev_get_drvdata(dev);
1641 1726
1727 class_device_del(&sdkp->cdev);
1642 del_gendisk(sdkp->disk); 1728 del_gendisk(sdkp->disk);
1643 sd_shutdown(dev); 1729 sd_shutdown(dev);
1644 1730
1645 mutex_lock(&sd_ref_mutex); 1731 mutex_lock(&sd_ref_mutex);
1646 dev_set_drvdata(dev, NULL); 1732 dev_set_drvdata(dev, NULL);
1647 kref_put(&sdkp->kref, scsi_disk_release); 1733 class_device_put(&sdkp->cdev);
1648 mutex_unlock(&sd_ref_mutex); 1734 mutex_unlock(&sd_ref_mutex);
1649 1735
1650 return 0; 1736 return 0;
@@ -1652,16 +1738,16 @@ static int sd_remove(struct device *dev)
1652 1738
1653/** 1739/**
1654 * scsi_disk_release - Called to free the scsi_disk structure 1740 * scsi_disk_release - Called to free the scsi_disk structure
1655 * @kref: pointer to embedded kref 1741 * @cdev: pointer to embedded class device
1656 * 1742 *
1657 * sd_ref_mutex must be held entering this routine. Because it is 1743 * sd_ref_mutex must be held entering this routine. Because it is
1658 * called on last put, you should always use the scsi_disk_get() 1744 * called on last put, you should always use the scsi_disk_get()
1659 * scsi_disk_put() helpers which manipulate the semaphore directly 1745 * scsi_disk_put() helpers which manipulate the semaphore directly
1660 * and never do a direct kref_put(). 1746 * and never do a direct class_device_put().
1661 **/ 1747 **/
1662static void scsi_disk_release(struct kref *kref) 1748static void scsi_disk_release(struct class_device *cdev)
1663{ 1749{
1664 struct scsi_disk *sdkp = to_scsi_disk(kref); 1750 struct scsi_disk *sdkp = to_scsi_disk(cdev);
1665 struct gendisk *disk = sdkp->disk; 1751 struct gendisk *disk = sdkp->disk;
1666 1752
1667 spin_lock(&sd_index_lock); 1753 spin_lock(&sd_index_lock);
@@ -1715,6 +1801,8 @@ static int __init init_sd(void)
1715 if (!majors) 1801 if (!majors)
1716 return -ENODEV; 1802 return -ENODEV;
1717 1803
1804 class_register(&sd_disk_class);
1805
1718 return scsi_register_driver(&sd_template.gendrv); 1806 return scsi_register_driver(&sd_template.gendrv);
1719} 1807}
1720 1808
@@ -1732,6 +1820,8 @@ static void __exit exit_sd(void)
1732 scsi_unregister_driver(&sd_template.gendrv); 1820 scsi_unregister_driver(&sd_template.gendrv);
1733 for (i = 0; i < SD_MAJORS; i++) 1821 for (i = 0; i < SD_MAJORS; i++)
1734 unregister_blkdev(sd_major(i), "sd"); 1822 unregister_blkdev(sd_major(i), "sd");
1823
1824 class_unregister(&sd_disk_class);
1735} 1825}
1736 1826
1737module_init(init_sd); 1827module_init(init_sd);