diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 172 |
1 files changed, 141 insertions, 31 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9d9872347f56..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> |
@@ -71,6 +70,27 @@ | |||
71 | */ | 70 | */ |
72 | #define SD_MAJORS 16 | 71 | #define SD_MAJORS 16 |
73 | 72 | ||
73 | MODULE_AUTHOR("Eric Youngdale"); | ||
74 | MODULE_DESCRIPTION("SCSI disk (sd) driver"); | ||
75 | MODULE_LICENSE("GPL"); | ||
76 | |||
77 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR); | ||
78 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR); | ||
79 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR); | ||
80 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR); | ||
81 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR); | ||
82 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR); | ||
83 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR); | ||
84 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR); | ||
85 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR); | ||
86 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR); | ||
87 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR); | ||
88 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR); | ||
89 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); | ||
90 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); | ||
91 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); | ||
92 | MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); | ||
93 | |||
74 | /* | 94 | /* |
75 | * This is limited by the naming scheme enforced in sd_probe, | 95 | * This is limited by the naming scheme enforced in sd_probe, |
76 | * add another character to it if you really need more disks. | 96 | * add another character to it if you really need more disks. |
@@ -94,12 +114,10 @@ | |||
94 | */ | 114 | */ |
95 | #define SD_BUF_SIZE 512 | 115 | #define SD_BUF_SIZE 512 |
96 | 116 | ||
97 | static void scsi_disk_release(struct kref *kref); | ||
98 | |||
99 | struct scsi_disk { | 117 | struct scsi_disk { |
100 | struct scsi_driver *driver; /* always &sd_template */ | 118 | struct scsi_driver *driver; /* always &sd_template */ |
101 | struct scsi_device *device; | 119 | struct scsi_device *device; |
102 | struct kref kref; | 120 | struct class_device cdev; |
103 | struct gendisk *disk; | 121 | struct gendisk *disk; |
104 | unsigned int openers; /* protected by BKL for now, yuck */ | 122 | unsigned int openers; /* protected by BKL for now, yuck */ |
105 | sector_t capacity; /* size in 512-byte sectors */ | 123 | sector_t capacity; /* size in 512-byte sectors */ |
@@ -110,6 +128,7 @@ struct scsi_disk { | |||
110 | unsigned RCD : 1; /* state of disk RCD bit, unused */ | 128 | unsigned RCD : 1; /* state of disk RCD bit, unused */ |
111 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ | 129 | unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ |
112 | }; | 130 | }; |
131 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) | ||
113 | 132 | ||
114 | static DEFINE_IDR(sd_index_idr); | 133 | static DEFINE_IDR(sd_index_idr); |
115 | static DEFINE_SPINLOCK(sd_index_lock); | 134 | static DEFINE_SPINLOCK(sd_index_lock); |
@@ -131,6 +150,92 @@ static int sd_issue_flush(struct device *, sector_t *); | |||
131 | static void sd_prepare_flush(request_queue_t *, struct request *); | 150 | static void sd_prepare_flush(request_queue_t *, struct request *); |
132 | static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, | 151 | static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, |
133 | 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 | }; | ||
134 | 239 | ||
135 | static struct scsi_driver sd_template = { | 240 | static struct scsi_driver sd_template = { |
136 | .owner = THIS_MODULE, | 241 | .owner = THIS_MODULE, |
@@ -174,8 +279,6 @@ static int sd_major(int major_idx) | |||
174 | } | 279 | } |
175 | } | 280 | } |
176 | 281 | ||
177 | #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref) | ||
178 | |||
179 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) | 282 | static inline struct scsi_disk *scsi_disk(struct gendisk *disk) |
180 | { | 283 | { |
181 | return container_of(disk->private_data, struct scsi_disk, driver); | 284 | return container_of(disk->private_data, struct scsi_disk, driver); |
@@ -188,7 +291,7 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) | |||
188 | if (disk->private_data) { | 291 | if (disk->private_data) { |
189 | sdkp = scsi_disk(disk); | 292 | sdkp = scsi_disk(disk); |
190 | if (scsi_device_get(sdkp->device) == 0) | 293 | if (scsi_device_get(sdkp->device) == 0) |
191 | kref_get(&sdkp->kref); | 294 | class_device_get(&sdkp->cdev); |
192 | else | 295 | else |
193 | sdkp = NULL; | 296 | sdkp = NULL; |
194 | } | 297 | } |
@@ -222,7 +325,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) | |||
222 | struct scsi_device *sdev = sdkp->device; | 325 | struct scsi_device *sdev = sdkp->device; |
223 | 326 | ||
224 | mutex_lock(&sd_ref_mutex); | 327 | mutex_lock(&sd_ref_mutex); |
225 | kref_put(&sdkp->kref, scsi_disk_release); | 328 | class_device_put(&sdkp->cdev); |
226 | scsi_device_put(sdev); | 329 | scsi_device_put(sdev); |
227 | mutex_unlock(&sd_ref_mutex); | 330 | mutex_unlock(&sd_ref_mutex); |
228 | } | 331 | } |
@@ -1333,6 +1436,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, | |||
1333 | if (!scsi_status_is_good(res)) | 1436 | if (!scsi_status_is_good(res)) |
1334 | goto bad_sense; | 1437 | goto bad_sense; |
1335 | 1438 | ||
1439 | if (!data.header_length) { | ||
1440 | modepage = 6; | ||
1441 | printk(KERN_ERR "%s: missing header in MODE_SENSE response\n", | ||
1442 | diskname); | ||
1443 | } | ||
1444 | |||
1336 | /* that went OK, now ask for the proper length */ | 1445 | /* that went OK, now ask for the proper length */ |
1337 | len = data.length; | 1446 | len = data.length; |
1338 | 1447 | ||
@@ -1354,10 +1463,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, | |||
1354 | 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); |
1355 | 1464 | ||
1356 | if (scsi_status_is_good(res)) { | 1465 | if (scsi_status_is_good(res)) { |
1357 | const char *types[] = { | ||
1358 | "write through", "none", "write back", | ||
1359 | "write back, no read (daft)" | ||
1360 | }; | ||
1361 | int ct = 0; | 1466 | int ct = 0; |
1362 | int offset = data.header_length + data.block_descriptor_length; | 1467 | int offset = data.header_length + data.block_descriptor_length; |
1363 | 1468 | ||
@@ -1390,7 +1495,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, | |||
1390 | ct = sdkp->RCD + 2*sdkp->WCE; | 1495 | ct = sdkp->RCD + 2*sdkp->WCE; |
1391 | 1496 | ||
1392 | printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", | 1497 | printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", |
1393 | diskname, types[ct], | 1498 | diskname, sd_cache_types[ct], |
1394 | sdkp->DPOFUA ? " w/ FUA" : ""); | 1499 | sdkp->DPOFUA ? " w/ FUA" : ""); |
1395 | 1500 | ||
1396 | return; | 1501 | return; |
@@ -1517,13 +1622,10 @@ static int sd_probe(struct device *dev) | |||
1517 | "sd_attach\n")); | 1622 | "sd_attach\n")); |
1518 | 1623 | ||
1519 | error = -ENOMEM; | 1624 | error = -ENOMEM; |
1520 | sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); | 1625 | sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); |
1521 | if (!sdkp) | 1626 | if (!sdkp) |
1522 | goto out; | 1627 | goto out; |
1523 | 1628 | ||
1524 | memset (sdkp, 0, sizeof(*sdkp)); | ||
1525 | kref_init(&sdkp->kref); | ||
1526 | |||
1527 | gd = alloc_disk(16); | 1629 | gd = alloc_disk(16); |
1528 | if (!gd) | 1630 | if (!gd) |
1529 | goto out_free; | 1631 | goto out_free; |
@@ -1540,7 +1642,16 @@ static int sd_probe(struct device *dev) | |||
1540 | if (error) | 1642 | if (error) |
1541 | goto out_put; | 1643 | goto out_put; |
1542 | 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 | |||
1543 | get_device(&sdp->sdev_gendev); | 1653 | get_device(&sdp->sdev_gendev); |
1654 | |||
1544 | sdkp->device = sdp; | 1655 | sdkp->device = sdp; |
1545 | sdkp->driver = &sd_template; | 1656 | sdkp->driver = &sd_template; |
1546 | sdkp->disk = gd; | 1657 | sdkp->disk = gd; |
@@ -1572,8 +1683,6 @@ static int sd_probe(struct device *dev) | |||
1572 | 'a' + m1, 'a' + m2, 'a' + m3); | 1683 | 'a' + m1, 'a' + m2, 'a' + m3); |
1573 | } | 1684 | } |
1574 | 1685 | ||
1575 | strcpy(gd->devfs_name, sdp->devfs_name); | ||
1576 | |||
1577 | gd->private_data = &sdkp->driver; | 1686 | gd->private_data = &sdkp->driver; |
1578 | gd->queue = sdkp->device->request_queue; | 1687 | gd->queue = sdkp->device->request_queue; |
1579 | 1688 | ||
@@ -1592,11 +1701,11 @@ static int sd_probe(struct device *dev) | |||
1592 | 1701 | ||
1593 | return 0; | 1702 | return 0; |
1594 | 1703 | ||
1595 | out_put: | 1704 | out_put: |
1596 | put_disk(gd); | 1705 | put_disk(gd); |
1597 | out_free: | 1706 | out_free: |
1598 | kfree(sdkp); | 1707 | kfree(sdkp); |
1599 | out: | 1708 | out: |
1600 | return error; | 1709 | return error; |
1601 | } | 1710 | } |
1602 | 1711 | ||
@@ -1615,12 +1724,13 @@ static int sd_remove(struct device *dev) | |||
1615 | { | 1724 | { |
1616 | struct scsi_disk *sdkp = dev_get_drvdata(dev); | 1725 | struct scsi_disk *sdkp = dev_get_drvdata(dev); |
1617 | 1726 | ||
1727 | class_device_del(&sdkp->cdev); | ||
1618 | del_gendisk(sdkp->disk); | 1728 | del_gendisk(sdkp->disk); |
1619 | sd_shutdown(dev); | 1729 | sd_shutdown(dev); |
1620 | 1730 | ||
1621 | mutex_lock(&sd_ref_mutex); | 1731 | mutex_lock(&sd_ref_mutex); |
1622 | dev_set_drvdata(dev, NULL); | 1732 | dev_set_drvdata(dev, NULL); |
1623 | kref_put(&sdkp->kref, scsi_disk_release); | 1733 | class_device_put(&sdkp->cdev); |
1624 | mutex_unlock(&sd_ref_mutex); | 1734 | mutex_unlock(&sd_ref_mutex); |
1625 | 1735 | ||
1626 | return 0; | 1736 | return 0; |
@@ -1628,16 +1738,16 @@ static int sd_remove(struct device *dev) | |||
1628 | 1738 | ||
1629 | /** | 1739 | /** |
1630 | * scsi_disk_release - Called to free the scsi_disk structure | 1740 | * scsi_disk_release - Called to free the scsi_disk structure |
1631 | * @kref: pointer to embedded kref | 1741 | * @cdev: pointer to embedded class device |
1632 | * | 1742 | * |
1633 | * 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 |
1634 | * 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() |
1635 | * scsi_disk_put() helpers which manipulate the semaphore directly | 1745 | * scsi_disk_put() helpers which manipulate the semaphore directly |
1636 | * and never do a direct kref_put(). | 1746 | * and never do a direct class_device_put(). |
1637 | **/ | 1747 | **/ |
1638 | static void scsi_disk_release(struct kref *kref) | 1748 | static void scsi_disk_release(struct class_device *cdev) |
1639 | { | 1749 | { |
1640 | struct scsi_disk *sdkp = to_scsi_disk(kref); | 1750 | struct scsi_disk *sdkp = to_scsi_disk(cdev); |
1641 | struct gendisk *disk = sdkp->disk; | 1751 | struct gendisk *disk = sdkp->disk; |
1642 | 1752 | ||
1643 | spin_lock(&sd_index_lock); | 1753 | spin_lock(&sd_index_lock); |
@@ -1691,6 +1801,8 @@ static int __init init_sd(void) | |||
1691 | if (!majors) | 1801 | if (!majors) |
1692 | return -ENODEV; | 1802 | return -ENODEV; |
1693 | 1803 | ||
1804 | class_register(&sd_disk_class); | ||
1805 | |||
1694 | return scsi_register_driver(&sd_template.gendrv); | 1806 | return scsi_register_driver(&sd_template.gendrv); |
1695 | } | 1807 | } |
1696 | 1808 | ||
@@ -1708,11 +1820,9 @@ static void __exit exit_sd(void) | |||
1708 | scsi_unregister_driver(&sd_template.gendrv); | 1820 | scsi_unregister_driver(&sd_template.gendrv); |
1709 | for (i = 0; i < SD_MAJORS; i++) | 1821 | for (i = 0; i < SD_MAJORS; i++) |
1710 | unregister_blkdev(sd_major(i), "sd"); | 1822 | unregister_blkdev(sd_major(i), "sd"); |
1711 | } | ||
1712 | 1823 | ||
1713 | MODULE_LICENSE("GPL"); | 1824 | class_unregister(&sd_disk_class); |
1714 | MODULE_AUTHOR("Eric Youngdale"); | 1825 | } |
1715 | MODULE_DESCRIPTION("SCSI disk (sd) driver"); | ||
1716 | 1826 | ||
1717 | module_init(init_sd); | 1827 | module_init(init_sd); |
1718 | module_exit(exit_sd); | 1828 | module_exit(exit_sd); |