From 24669f75a3231fa37444977c92d1f4838bec1233 Mon Sep 17 00:00:00 2001 From: Jes Sorensen Date: Mon, 16 Jan 2006 10:31:18 -0500 Subject: [SCSI] SCSI core kmalloc2kzalloc Change the core SCSI code to use kzalloc rather than kmalloc+memset where possible. Signed-off-by: Jes Sorensen Signed-off-by: James Bottomley --- drivers/scsi/sd.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9d9872347f5..8ba2d988d05 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1517,11 +1517,10 @@ static int sd_probe(struct device *dev) "sd_attach\n")); error = -ENOMEM; - sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL); + sdkp = kzalloc(sizeof(*sdkp), GFP_KERNEL); if (!sdkp) goto out; - memset (sdkp, 0, sizeof(*sdkp)); kref_init(&sdkp->kref); gd = alloc_disk(16); -- cgit v1.2.3-70-g09d2 From 5e3c34c1e988a0dfe177c38cf324e8e321c55ef5 Mon Sep 17 00:00:00 2001 From: Greg KH Date: Wed, 18 Jan 2006 16:17:46 -0800 Subject: [SCSI] Remove devfs support from the SCSI subsystem As devfs has been disabled from the kernel tree for a number of months now (5 to be exact), here's a patch against 2.6.16-rc1-git1 that removes support for it from the SCSI subsystem. The patch also removes the scsi_disk devfs_name field as it's no longer needed. Signed-off-by: Greg Kroah-Hartman Signed-off-by: James Bottomley --- drivers/scsi/osst.c | 24 ++---------------------- drivers/scsi/scsi.c | 3 --- drivers/scsi/scsi_scan.c | 6 +----- drivers/scsi/sd.c | 2 -- drivers/scsi/sg.c | 10 ++-------- drivers/scsi/sr.c | 2 -- drivers/scsi/st.c | 20 -------------------- include/scsi/scsi_device.h | 1 - 8 files changed, 5 insertions(+), 63 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index d9946bd9549..b9f6084fdd9 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -48,7 +48,6 @@ static const char * osst_version = "0.99.3"; #include #include #include -#include #include #include #include @@ -107,8 +106,6 @@ static struct osst_dev_parm { }; #endif -static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"}; - /* Some default definitions have been moved to osst_options.h */ #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) @@ -5667,7 +5664,7 @@ static int osst_probe(struct device *dev) struct st_partstat * STps; struct osst_buffer * buffer; struct gendisk * drive; - int i, mode, dev_num; + int i, dev_num; if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) return -ENODEV; @@ -5803,18 +5800,6 @@ static int osst_probe(struct device *dev) snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); } - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - /* Rewind entry */ - devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/ot%s", SDp->devfs_name, osst_formats[mode]); - - /* No-rewind entry */ - devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/ot%sn", SDp->devfs_name, osst_formats[mode]); - } - drive->number = devfs_register_tape(SDp->devfs_name); sdev_printk(KERN_INFO, SDp, "osst :I: Attached OnStream %.5s tape as %s\n", @@ -5831,7 +5816,7 @@ static int osst_remove(struct device *dev) { struct scsi_device * SDp = to_scsi_device(dev); struct osst_tape * tpnt; - int i, mode; + int i; if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) return 0; @@ -5842,11 +5827,6 @@ static int osst_remove(struct device *dev) osst_sysfs_destroy(MKDEV(OSST_MAJOR, i)); osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128)); tpnt->device = NULL; - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]); - devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]); - } - devfs_unregister_tape(tpnt->drive->number); put_disk(tpnt->drive); os_scsi_tapes[i] = NULL; osst_nr_dev--; diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 11b27ba0cd4..6913b062316 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -48,7 +48,6 @@ #include #include #include -#include #include #include #include @@ -1247,7 +1246,6 @@ static int __init init_scsi(void) for_each_cpu(i) INIT_LIST_HEAD(&per_cpu(scsi_done_q, i)); - devfs_mk_dir("scsi"); printk(KERN_NOTICE "SCSI subsystem initialized\n"); return 0; @@ -1272,7 +1270,6 @@ static void __exit exit_scsi(void) scsi_exit_sysctl(); scsi_exit_hosts(); scsi_exit_devinfo(); - devfs_remove("scsi"); scsi_exit_procfs(); scsi_exit_queue(); } diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 74863da1d63..dfdbbd00863 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c @@ -687,12 +687,8 @@ static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags) if (inq_result[7] & 0x10) sdev->sdtr = 1; - sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d", - sdev->host->host_no, sdev->channel, - sdev->id, sdev->lun); - /* - * End driverfs/devfs code. + * End sysfs code. */ if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) && diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8ba2d988d05..76b4d14c0b3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1571,8 +1571,6 @@ static int sd_probe(struct device *dev) 'a' + m1, 'a' + m2, 'a' + m3); } - strcpy(gd->devfs_name, sdp->devfs_name); - gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index ecf2f6010e7..06fc8ed720f 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -44,7 +44,6 @@ static int sg_version_num = 30533; /* 2 digits for each component */ #include #include #include -#include #include #include #include @@ -1456,14 +1455,10 @@ sg_add(struct class_device *cl_dev, struct class_interface *cl_intf) k = error; sdp = sg_dev_arr[k]; - devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k), - S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, - "%s/generic", scsidp->devfs_name); error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1); - if (error) { - devfs_remove("%s/generic", scsidp->devfs_name); + if (error) goto out; - } + sdp->cdev = cdev; if (sg_sysfs_valid) { struct class_device * sg_class_member; @@ -1553,7 +1548,6 @@ sg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) class_device_destroy(sg_sysfs_class, MKDEV(SCSI_GENERIC_MAJOR, k)); cdev_del(sdp->cdev); sdp->cdev = NULL; - devfs_remove("%s/generic", scsidp->devfs_name); put_disk(sdp->disk); sdp->disk = NULL; if (NULL == sdp->headfp) diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index d8d12a1718b..328837b7ccb 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -573,8 +573,6 @@ static int sr_probe(struct device *dev) get_capabilities(cd); sr_vendor_init(cd); - snprintf(disk->devfs_name, sizeof(disk->devfs_name), - "%s/cd", sdev->devfs_name); disk->driverfs_dev = &sdev->sdev_gendev; set_capacity(disk, cd->capacity); disk->private_data = &cd->driver; diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index f0606da19d0..31c6eefba9d 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -35,7 +35,6 @@ static const char *verstr = "20050830"; #include #include #include -#include #include #include #include @@ -4053,21 +4052,6 @@ static int st_probe(struct device *dev) do_create_class_files(tpnt, dev_num, mode); } - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - /* Make sure that the minor numbers corresponding to the four - first modes always get the same names */ - i = mode << (4 - ST_NBR_MODE_BITS); - /* Rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%s", SDp->devfs_name, st_formats[i]); - /* No-rewind entry */ - devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)), - S_IFCHR | S_IRUGO | S_IWUGO, - "%s/mt%sn", SDp->devfs_name, st_formats[i]); - } - disk->number = devfs_register_tape(SDp->devfs_name); - sdev_printk(KERN_WARNING, SDp, "Attached scsi tape %s", tape_name(tpnt)); printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n", @@ -4121,13 +4105,9 @@ static int st_remove(struct device *dev) scsi_tapes[i] = NULL; st_nr_dev--; write_unlock(&st_dev_arr_lock); - devfs_unregister_tape(tpnt->disk->number); sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, "tape"); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - j = mode << (4 - ST_NBR_MODE_BITS); - devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]); - devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]); for (j=0; j < 2; j++) { class_device_destroy(st_sysfs_class, MKDEV(SCSI_TAPE_MAJOR, diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 290e3b4d2ae..cde84b39bb6 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -73,7 +73,6 @@ struct scsi_device { unsigned sector_size; /* size in bytes */ void *hostdata; /* available to low-level driver */ - char devfs_name[256]; /* devfs junk */ char type; char scsi_level; char inq_periph_qual; /* PQ from INQUIRY data */ -- cgit v1.2.3-70-g09d2 From 6d73c8514da241c6b1b8d710a6294786604d7142 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 23 Feb 2006 02:03:16 +0100 Subject: [SCSI] scsi_lib: fix recognition of cache type of Initio SBP-2 bridges Regardless what mode page was asked for, Initio INIC-14x0 and INIC-2430 always return page 6 without mode page headers. Try to recognise this as a special case in scsi_mode_sense and setting the mode sense headers accordingly. Signed-off-by: Al Viro Signed-off-by: James Bottomley --- drivers/scsi/scsi_lib.c | 13 +++++++++++-- drivers/scsi/sd.c | 6 ++++++ 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index 1fe4fd83e30..eab303d148d 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -1892,8 +1892,16 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, } if(scsi_status_is_good(result)) { - data->header_length = header_length; - if(use_10_for_ms) { + if (unlikely(buffer[0] == 0x86 && buffer[1] == 0x0b && + (modepage == 6 || modepage == 8))) { + /* Initio breakage? */ + header_length = 0; + data->length = 13; + data->medium_type = 0; + data->device_specific = 0; + data->longlba = 0; + data->block_descriptor_length = 0; + } else if(use_10_for_ms) { data->length = buffer[0]*256 + buffer[1] + 2; data->medium_type = buffer[2]; data->device_specific = buffer[3]; @@ -1906,6 +1914,7 @@ scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage, data->device_specific = buffer[2]; data->block_descriptor_length = buffer[3]; } + data->header_length = header_length; } return result; diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 76b4d14c0b3..31c9685ebc5 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1333,6 +1333,12 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, if (!scsi_status_is_good(res)) goto bad_sense; + if (!data.header_length) { + modepage = 6; + printk(KERN_ERR "%s: missing header in MODE_SENSE response\n", + diskname); + } + /* that went OK, now ask for the proper length */ len = data.length; -- cgit v1.2.3-70-g09d2 From f018fa552c52642a6b9db2bda90477762e42163f Mon Sep 17 00:00:00 2001 From: Rene Herman Date: Wed, 8 Mar 2006 00:14:20 -0800 Subject: [SCSI] MODULE_ALIAS_{BLOCK,CHAR}DEV_MAJOR for drivers/scsi Add device-major aliases in drivers/scsi, allowing kmod autoload: MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR) MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR) MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR) MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR) MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISKN_MAJOR) Signed-off-by: Andrew Morton Acked-by: Kai Makisara Signed-off-by: James Bottomley --- drivers/scsi/ch.c | 1 + drivers/scsi/osst.c | 1 + drivers/scsi/sd.c | 25 +++++++++++++++++++++---- drivers/scsi/sg.c | 2 +- drivers/scsi/sr.c | 4 ++++ drivers/scsi/st.c | 3 ++- 6 files changed, 30 insertions(+), 6 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index c3f27285db1..d9abd1645d1 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -39,6 +39,7 @@ MODULE_DESCRIPTION("device driver for scsi media changer devices"); MODULE_AUTHOR("Gerd Knorr "); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SCSI_CHANGER_MAJOR); static int init = 1; module_param(init, int, 0444); diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 00f3edc2417..66ea47a9c53 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -85,6 +85,7 @@ static int max_sg_segs = 0; MODULE_AUTHOR("Willem Riede"); MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); module_param(max_dev, int, 0444); MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 31c9685ebc5..3b01e5d6221 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -71,6 +71,27 @@ */ #define SD_MAJORS 16 +MODULE_AUTHOR("Eric Youngdale"); +MODULE_DESCRIPTION("SCSI disk (sd) driver"); +MODULE_LICENSE("GPL"); + +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); + /* * This is limited by the naming scheme enforced in sd_probe, * add another character to it if you really need more disks. @@ -1713,9 +1734,5 @@ static void __exit exit_sd(void) unregister_blkdev(sd_major(i), "sd"); } -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Eric Youngdale"); -MODULE_DESCRIPTION("SCSI disk (sd) driver"); - module_init(init_sd); module_exit(exit_sd); diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 06fc8ed720f..af3fea59a45 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -1569,6 +1569,7 @@ MODULE_AUTHOR("Douglas Gilbert"); MODULE_DESCRIPTION("SCSI generic (sg) driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(SG_VERSION_STR); +MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))"); @@ -2966,4 +2967,3 @@ static int sg_proc_seq_show_debug(struct seq_file *s, void *v) module_init(init_sg); module_exit(exit_sg); -MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR); diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c index 328837b7ccb..f9c1192dc15 100644 --- a/drivers/scsi/sr.c +++ b/drivers/scsi/sr.c @@ -60,6 +60,10 @@ #include "sr.h" +MODULE_DESCRIPTION("SCSI cdrom (sr) driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_CDROM_MAJOR); + #define SR_DISKS 256 #define MAX_RETRIES 3 diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 31c6eefba9d..d40e7c871c3 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -86,8 +86,9 @@ static int st_nr_dev; static struct class *st_sysfs_class; MODULE_AUTHOR("Kai Makisara"); -MODULE_DESCRIPTION("SCSI Tape Driver"); +MODULE_DESCRIPTION("SCSI tape (st) driver"); MODULE_LICENSE("GPL"); +MODULE_ALIAS_CHARDEV_MAJOR(SCSI_TAPE_MAJOR); /* Set 'perm' (4th argument) to 0 to disable module_param's definition * of sysfs parameters (which module_param doesn't yet support). -- cgit v1.2.3-70-g09d2 From 6bdaa1f17dd32ec62345c7b57842f53e6278a2fa Mon Sep 17 00:00:00 2001 From: James Bottomley Date: Sat, 18 Mar 2006 14:14:21 -0600 Subject: [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 --- drivers/scsi/sd.c | 136 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 113 insertions(+), 23 deletions(-) (limited to 'drivers/scsi/sd.c') diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 3b01e5d6221..024ef86c524 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -47,7 +47,6 @@ #include #include #include -#include #include #include #include @@ -115,12 +114,10 @@ MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR); */ #define SD_BUF_SIZE 512 -static void scsi_disk_release(struct kref *kref); - struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; - struct kref kref; + struct class_device cdev; struct gendisk *disk; unsigned int openers; /* protected by BKL for now, yuck */ sector_t capacity; /* size in 512-byte sectors */ @@ -131,6 +128,7 @@ struct scsi_disk { unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ }; +#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,cdev) static DEFINE_IDR(sd_index_idr); static DEFINE_SPINLOCK(sd_index_lock); @@ -152,6 +150,92 @@ static int sd_issue_flush(struct device *, sector_t *); static void sd_prepare_flush(request_queue_t *, struct request *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, unsigned char *buffer); +static void scsi_disk_release(struct class_device *cdev); + +static const char *sd_cache_types[] = { + "write through", "none", "write back", + "write back, no read (daft)" +}; + +static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf, + size_t count) +{ + int i, ct = -1, rcd, wce, sp; + struct scsi_disk *sdkp = to_scsi_disk(cdev); + struct scsi_device *sdp = sdkp->device; + char buffer[64]; + char *buffer_data; + struct scsi_mode_data data; + struct scsi_sense_hdr sshdr; + int len; + + if (sdp->type != TYPE_DISK) + /* 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; + + for (i = 0; i < sizeof(sd_cache_types)/sizeof(sd_cache_types[0]); i++) { + const int len = strlen(sd_cache_types[i]); + if (strncmp(sd_cache_types[i], buf, len) == 0 && + buf[len] == '\n') { + ct = i; + break; + } + } + if (ct < 0) + return -EINVAL; + rcd = ct & 0x01 ? 1 : 0; + wce = ct & 0x02 ? 1 : 0; + if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT, + SD_MAX_RETRIES, &data, NULL)) + return -EINVAL; + len = min(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; + + if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT, + SD_MAX_RETRIES, &data, &sshdr)) { + if (scsi_sense_valid(&sshdr)) + scsi_print_sense_hdr(sdkp->disk->disk_name, &sshdr); + return -EINVAL; + } + sd_revalidate_disk(sdkp->disk); + return count; +} + +static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + int ct = sdkp->RCD + 2*sdkp->WCE; + + return snprintf(buf, 40, "%s\n", sd_cache_types[ct]); +} + +static ssize_t sd_show_fua(struct class_device *cdev, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(cdev); + + return snprintf(buf, 20, "%u\n", sdkp->DPOFUA); +} + +static struct class_device_attribute sd_disk_attrs[] = { + __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, + sd_store_cache_type), + __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), + __ATTR_NULL, +}; + +static struct class sd_disk_class = { + .name = "scsi_disk", + .owner = THIS_MODULE, + .release = scsi_disk_release, + .class_dev_attrs = sd_disk_attrs, +}; static struct scsi_driver sd_template = { .owner = THIS_MODULE, @@ -195,8 +279,6 @@ static int sd_major(int major_idx) } } -#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref) - static inline struct scsi_disk *scsi_disk(struct gendisk *disk) { return container_of(disk->private_data, struct scsi_disk, driver); @@ -209,7 +291,7 @@ static struct scsi_disk *__scsi_disk_get(struct gendisk *disk) if (disk->private_data) { sdkp = scsi_disk(disk); if (scsi_device_get(sdkp->device) == 0) - kref_get(&sdkp->kref); + class_device_get(&sdkp->cdev); else sdkp = NULL; } @@ -243,7 +325,7 @@ static void scsi_disk_put(struct scsi_disk *sdkp) struct scsi_device *sdev = sdkp->device; mutex_lock(&sd_ref_mutex); - kref_put(&sdkp->kref, scsi_disk_release); + class_device_put(&sdkp->cdev); scsi_device_put(sdev); mutex_unlock(&sd_ref_mutex); } @@ -1381,10 +1463,6 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, res = sd_do_mode_sense(sdp, dbd, modepage, buffer, len, &data, &sshdr); if (scsi_status_is_good(res)) { - const char *types[] = { - "write through", "none", "write back", - "write back, no read (daft)" - }; int ct = 0; int offset = data.header_length + data.block_descriptor_length; @@ -1417,7 +1495,7 @@ sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, ct = sdkp->RCD + 2*sdkp->WCE; printk(KERN_NOTICE "SCSI device %s: drive cache: %s%s\n", - diskname, types[ct], + diskname, sd_cache_types[ct], sdkp->DPOFUA ? " w/ FUA" : ""); return; @@ -1548,8 +1626,6 @@ static int sd_probe(struct device *dev) if (!sdkp) goto out; - kref_init(&sdkp->kref); - gd = alloc_disk(16); if (!gd) goto out_free; @@ -1566,7 +1642,16 @@ static int sd_probe(struct device *dev) if (error) goto out_put; + class_device_initialize(&sdkp->cdev); + sdkp->cdev.dev = &sdp->sdev_gendev; + sdkp->cdev.class = &sd_disk_class; + strncpy(sdkp->cdev.class_id, sdp->sdev_gendev.bus_id, BUS_ID_SIZE); + + if (class_device_add(&sdkp->cdev)) + goto out_put; + get_device(&sdp->sdev_gendev); + sdkp->device = sdp; sdkp->driver = &sd_template; sdkp->disk = gd; @@ -1616,11 +1701,11 @@ static int sd_probe(struct device *dev) return 0; -out_put: + out_put: put_disk(gd); -out_free: + out_free: kfree(sdkp); -out: + out: return error; } @@ -1639,12 +1724,13 @@ static int sd_remove(struct device *dev) { struct scsi_disk *sdkp = dev_get_drvdata(dev); + class_device_del(&sdkp->cdev); del_gendisk(sdkp->disk); sd_shutdown(dev); mutex_lock(&sd_ref_mutex); dev_set_drvdata(dev, NULL); - kref_put(&sdkp->kref, scsi_disk_release); + class_device_put(&sdkp->cdev); mutex_unlock(&sd_ref_mutex); return 0; @@ -1652,16 +1738,16 @@ static int sd_remove(struct device *dev) /** * scsi_disk_release - Called to free the scsi_disk structure - * @kref: pointer to embedded kref + * @cdev: pointer to embedded class device * * sd_ref_mutex must be held entering this routine. Because it is * called on last put, you should always use the scsi_disk_get() * scsi_disk_put() helpers which manipulate the semaphore directly - * and never do a direct kref_put(). + * and never do a direct class_device_put(). **/ -static void scsi_disk_release(struct kref *kref) +static void scsi_disk_release(struct class_device *cdev) { - struct scsi_disk *sdkp = to_scsi_disk(kref); + struct scsi_disk *sdkp = to_scsi_disk(cdev); struct gendisk *disk = sdkp->disk; spin_lock(&sd_index_lock); @@ -1715,6 +1801,8 @@ static int __init init_sd(void) if (!majors) return -ENODEV; + class_register(&sd_disk_class); + return scsi_register_driver(&sd_template.gendrv); } @@ -1732,6 +1820,8 @@ static void __exit exit_sd(void) scsi_unregister_driver(&sd_template.gendrv); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); + + class_unregister(&sd_disk_class); } module_init(init_sd); -- cgit v1.2.3-70-g09d2