#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/errno.h>
+#include <linux/idr.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include "scsi_logging.h"
-
/*
- * Remaining dev_t-handling stuff
+ * More than enough for everybody ;) The huge number of majors
+ * is a leftover from 16bit dev_t days, we don't really need that
+ * much numberspace.
*/
#define SD_MAJORS 16
-#define SD_DISKS 32768 /* anything between 256 and 262144 */
+
+/*
+ * This is limited by the naming scheme enforced in sd_probe,
+ * add another character to it if you really need more disks.
+ */
+#define SD_MAX_DISKS (((26 * 26) + 26 + 1) * 26)
/*
* Time out in seconds for disks and Magneto-opticals (which are slower).
unsigned RCD : 1; /* state of disk RCD bit, unused */
};
-
-static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG];
+static DEFINE_IDR(sd_index_idr);
static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;
/* This semaphore is used to mediate the 0->1 reference get in the
static void sd_shutdown(struct device *dev);
static void sd_rescan(struct device *);
static int sd_init_command(struct scsi_cmnd *);
+static int sd_issue_flush(struct device *, sector_t *);
static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
struct scsi_request *SRpnt, unsigned char *buffer);
},
.rescan = sd_rescan,
.init_command = sd_init_command,
+ .issue_flush = sd_issue_flush,
};
-/* Device no to disk mapping:
+/*
+ * Device no to disk mapping:
*
* major disc2 disc p1
* |............|.............|....|....| <- dev_t
* As we stay compatible with our numbering scheme, we can reuse
* the well-know SCSI majors 8, 65--71, 136--143.
*/
-
static int sd_major(int major_idx)
{
switch (major_idx) {
}
}
-static unsigned int make_sd_dev(unsigned int sd_nr, unsigned int part)
-{
- return (part & 0xf) | ((sd_nr & 0xf) << 4) |
- (sd_major((sd_nr & 0xf0) >> 4) << 20) | (sd_nr & 0xfff00);
-}
-
-/* reverse mapping dev -> (sd_nr, part) not currently needed */
-
#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref)
static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
if (disk->private_data == NULL)
goto out;
sdkp = scsi_disk(disk);
- if (!kref_get(&sdkp->kref))
- goto out_sdkp;
+ kref_get(&sdkp->kref);
if (scsi_device_get(sdkp->device))
goto out_put;
up(&sd_ref_sem);
return sdkp;
out_put:
- kref_put(&sdkp->kref);
- out_sdkp:
+ kref_put(&sdkp->kref, scsi_disk_release);
sdkp = NULL;
out:
up(&sd_ref_sem);
{
down(&sd_ref_sem);
scsi_device_put(sdkp->device);
- kref_put(&sdkp->kref);
+ kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem);
}
*/
retval = -ENODEV;
if (scsi_block_when_processing_errors(sdp))
- retval = scsi_ioctl(sdp, SCSI_IOCTL_TEST_UNIT_READY, NULL);
+ retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
/*
* Unable to test, unit probably not ready. This usually
return 1;
}
+static int sd_sync_cache(struct scsi_device *sdp)
+{
+ struct scsi_request *sreq;
+ int retries, res;
+
+ if (!scsi_device_online(sdp))
+ return -ENODEV;
+
+ sreq = scsi_allocate_request(sdp, GFP_KERNEL);
+ if (!sreq) {
+ printk("FAILED\n No memory for request\n");
+ return -ENOMEM;
+ }
+
+ sreq->sr_data_direction = DMA_NONE;
+ for (retries = 3; retries > 0; --retries) {
+ unsigned char cmd[10] = { 0 };
+
+ cmd[0] = SYNCHRONIZE_CACHE;
+ /*
+ * Leave the rest of the command zero to indicate
+ * flush everything.
+ */
+ scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
+ if (sreq->sr_result == 0)
+ break;
+ }
+
+ res = sreq->sr_result;
+ if (res) {
+ printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
+ "host = %d, driver = %02x\n ",
+ status_byte(res), msg_byte(res),
+ host_byte(res), driver_byte(res));
+ if (driver_byte(res) & DRIVER_SENSE)
+ scsi_print_req_sense("sd", sreq);
+ }
+
+ scsi_release_request(sreq);
+ return res;
+}
+
+static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+{
+ struct scsi_device *sdp = to_scsi_device(dev);
+ struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+ if (!sdkp)
+ return -ENODEV;
+
+ if (!sdkp->WCE)
+ return 0;
+
+ return sd_sync_cache(sdp);
+}
+
static void sd_rescan(struct device *dev)
{
struct scsi_disk *sdkp = dev_get_drvdata(dev);
struct scsi_disk *sdkp;
struct gendisk *gd;
u32 index;
- int error, devno;
+ int error;
error = -ENODEV;
if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))
goto out;
memset (sdkp, 0, sizeof(*sdkp));
- kref_init(&sdkp->kref, scsi_disk_release);
-
- /* Note: We can accomodate 64 partitions, but the genhd code
- * assumes partitions allocate consecutive minors, which they don't.
- * So for now stay with max 16 partitions and leave two spare bits.
- * Later, we may change the genhd code and the alloc_disk() call
- * and the ->minors assignment here. KG, 2004-02-10
- */
+ kref_init(&sdkp->kref);
+
gd = alloc_disk(16);
if (!gd)
goto out_free;
+ if (!idr_pre_get(&sd_index_idr, GFP_KERNEL))
+ goto out_put;
+
spin_lock(&sd_index_lock);
- index = find_first_zero_bit(sd_index_bits, SD_DISKS);
- if (index == SD_DISKS) {
- spin_unlock(&sd_index_lock);
+ error = idr_get_new(&sd_index_idr, NULL, &index);
+ spin_unlock(&sd_index_lock);
+
+ if (index >= SD_MAX_DISKS)
error = -EBUSY;
+ if (error)
goto out_put;
- }
- __set_bit(index, sd_index_bits);
- spin_unlock(&sd_index_lock);
sdkp->device = sdp;
sdkp->driver = &sd_template;
sdp->timeout = SD_MOD_TIMEOUT;
}
- devno = make_sd_dev(index, 0);
- gd->major = MAJOR(devno);
- gd->first_minor = MINOR(devno);
+ gd->major = sd_major((index & 0xf0) >> 4);
+ gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
gd->minors = 16;
gd->fops = &sd_fops;
if (index < 26) {
sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
- } else if (index < (26*27)) {
+ } else if (index < (26 + 1) * 26) {
sprintf(gd->disk_name, "sd%c%c",
'a' + index / 26 - 1,'a' + index % 26);
} else {
del_gendisk(sdkp->disk);
sd_shutdown(dev);
down(&sd_ref_sem);
- kref_put(&sdkp->kref);
+ kref_put(&sdkp->kref, scsi_disk_release);
up(&sd_ref_sem);
return 0;
struct gendisk *disk = sdkp->disk;
spin_lock(&sd_index_lock);
- clear_bit(sdkp->index, sd_index_bits);
+ idr_remove(&sd_index_idr, sdkp->index);
spin_unlock(&sd_index_lock);
disk->private_data = NULL;
static void sd_shutdown(struct device *dev)
{
struct scsi_device *sdp = to_scsi_device(dev);
- struct scsi_disk *sdkp;
- struct scsi_request *sreq;
- int retries, res;
+ struct scsi_disk *sdkp = dev_get_drvdata(dev);
- sdkp = dev_get_drvdata(dev);
if (!sdkp)
- return; /* this can happen */
+ return; /* this can happen */
- if (!scsi_device_online(sdp) || !sdkp->WCE)
+ if (!sdkp->WCE)
return;
- printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: ",
+ printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
sdkp->disk->disk_name);
-
- sreq = scsi_allocate_request(sdp, GFP_KERNEL);
- if (!sreq) {
- printk("FAILED\n No memory for request\n");
- return;
- }
-
- sreq->sr_data_direction = DMA_NONE;
- for (retries = 3; retries > 0; --retries) {
- unsigned char cmd[10] = { 0 };
-
- cmd[0] = SYNCHRONIZE_CACHE;
- /*
- * Leave the rest of the command zero to indicate
- * flush everything.
- */
- scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
- if (sreq->sr_result == 0)
- break;
- }
-
- res = sreq->sr_result;
- if (res) {
- printk(KERN_WARNING "FAILED\n status = %x, message = %02x, "
- "host = %d, driver = %02x\n ",
- status_byte(res), msg_byte(res),
- host_byte(res), driver_byte(res));
- if (driver_byte(res) & DRIVER_SENSE)
- scsi_print_req_sense("sd", sreq);
- }
-
- scsi_release_request(sreq);
- printk("\n");
+ sd_sync_cache(sdp);
}
/**