diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 136 |
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 | ||
118 | static void scsi_disk_release(struct kref *kref); | ||
119 | |||
120 | struct scsi_disk { | 117 | struct 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 | ||
135 | static DEFINE_IDR(sd_index_idr); | 133 | static DEFINE_IDR(sd_index_idr); |
136 | static DEFINE_SPINLOCK(sd_index_lock); | 134 | static DEFINE_SPINLOCK(sd_index_lock); |
@@ -152,6 +150,92 @@ static int sd_issue_flush(struct device *, sector_t *); | |||
152 | static void sd_prepare_flush(request_queue_t *, struct request *); | 150 | static void sd_prepare_flush(request_queue_t *, struct request *); |
153 | static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, | 151 | static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, |
154 | unsigned char *buffer); | 152 | unsigned char *buffer); |
153 | static void scsi_disk_release(struct class_device *cdev); | ||
154 | |||
155 | static const char *sd_cache_types[] = { | ||
156 | "write through", "none", "write back", | ||
157 | "write back, no read (daft)" | ||
158 | }; | ||
159 | |||
160 | static 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 | |||
211 | static 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 | |||
219 | static 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 | |||
226 | static 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 | |||
233 | static 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 | ||
156 | static struct scsi_driver sd_template = { | 240 | static 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 | |||
200 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | 282 | static 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 | ||
1619 | out_put: | 1704 | out_put: |
1620 | put_disk(gd); | 1705 | put_disk(gd); |
1621 | out_free: | 1706 | out_free: |
1622 | kfree(sdkp); | 1707 | kfree(sdkp); |
1623 | out: | 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 | **/ |
1662 | static void scsi_disk_release(struct kref *kref) | 1748 | static 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 | ||
1737 | module_init(init_sd); | 1827 | module_init(init_sd); |