summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/acorn/block/fd1772.c5
-rw-r--r--drivers/acorn/block/mfmhd.c12
-rw-r--r--drivers/base/core.c92
-rw-r--r--drivers/block/DAC960.c3
-rw-r--r--drivers/block/Makefile4
-rw-r--r--drivers/block/acsi.c18
-rw-r--r--drivers/block/amiflop.c11
-rw-r--r--drivers/block/ataflop.c20
-rw-r--r--drivers/block/blkpg.c310
-rw-r--r--drivers/block/block_ioctl.c83
-rw-r--r--drivers/block/cciss.c9
-rw-r--r--drivers/block/cpqarray.c7
-rw-r--r--drivers/block/floppy.c12
-rw-r--r--drivers/block/genhd.c85
-rw-r--r--drivers/block/ioctl.c215
-rw-r--r--drivers/block/ll_rw_blk.c15
-rw-r--r--drivers/block/loop.c2
-rw-r--r--drivers/block/nbd.c3
-rw-r--r--drivers/block/paride/pcd.c3
-rw-r--r--drivers/block/paride/pd.c6
-rw-r--r--drivers/block/paride/pf.c6
-rw-r--r--drivers/block/ps2esdi.c16
-rw-r--r--drivers/block/rd.c9
-rw-r--r--drivers/block/scsi_ioctl.c215
-rw-r--r--drivers/block/swim3.c2
-rw-r--r--drivers/block/swim_iop.c2
-rw-r--r--drivers/block/umem.c16
-rw-r--r--drivers/block/xd.c15
-rw-r--r--drivers/block/z2ram.c3
-rw-r--r--drivers/bluetooth/Config.help18
-rw-r--r--drivers/bluetooth/Config.in22
-rw-r--r--drivers/bluetooth/Makefile16
-rw-r--r--drivers/bluetooth/bluecard_cs.c6
-rw-r--r--drivers/bluetooth/bt3c_cs.c4
-rw-r--r--drivers/bluetooth/dtl1_cs.c6
-rw-r--r--drivers/bluetooth/hci_bcsp.c14
-rw-r--r--drivers/bluetooth/hci_h4.c8
-rw-r--r--drivers/bluetooth/hci_ldisc.c20
-rw-r--r--drivers/bluetooth/hci_usb.c18
-rw-r--r--drivers/bluetooth/hci_vhci.c10
-rw-r--r--drivers/cdrom/aztcd.c3
-rw-r--r--drivers/cdrom/cdu31a.c3
-rw-r--r--drivers/cdrom/cm206.c3
-rw-r--r--drivers/cdrom/gscd.c3
-rw-r--r--drivers/cdrom/mcd.c3
-rw-r--r--drivers/cdrom/mcdx.c3
-rw-r--r--drivers/cdrom/optcd.c3
-rw-r--r--drivers/cdrom/sbpcd.c3
-rw-r--r--drivers/cdrom/sjcd.c3
-rw-r--r--drivers/cdrom/sonycd535.c3
-rw-r--r--drivers/ide/ide-cd.c433
-rw-r--r--drivers/ide/ide-cd.h7
-rw-r--r--drivers/ide/ide-disk.c2
-rw-r--r--drivers/ide/ide-floppy.c2
-rw-r--r--drivers/ide/ide-probe.c3
-rw-r--r--drivers/ide/ide.c2
-rw-r--r--drivers/ide/legacy/hd.c14
-rw-r--r--drivers/md/md.c26
-rw-r--r--drivers/md/raid0.c39
-rw-r--r--drivers/media/video/bttv-driver.c1
-rw-r--r--drivers/message/i2o/i2o_block.c3
-rw-r--r--drivers/mtd/Config.help60
-rw-r--r--drivers/mtd/Config.in5
-rw-r--r--drivers/mtd/Makefile11
-rw-r--r--drivers/mtd/bootldr.c214
-rw-r--r--drivers/mtd/cmdline.c343
-rw-r--r--drivers/mtd/ftl.c3
-rw-r--r--drivers/mtd/maps/Config.help109
-rw-r--r--drivers/mtd/maps/Config.in12
-rw-r--r--drivers/mtd/maps/Makefile20
-rw-r--r--drivers/mtd/maps/autcpu12-nvram.c179
-rw-r--r--drivers/mtd/maps/ceiva.c408
-rw-r--r--drivers/mtd/maps/dc21285.c25
-rw-r--r--drivers/mtd/maps/edb7312.c202
-rw-r--r--drivers/mtd/maps/epxa10db-flash.c233
-rw-r--r--drivers/mtd/maps/fortunet.c309
-rw-r--r--drivers/mtd/maps/impa7.c234
-rw-r--r--drivers/mtd/maps/iq80310.c5
-rw-r--r--drivers/mtd/maps/pci.c385
-rw-r--r--drivers/mtd/maps/pcmciamtd.c893
-rw-r--r--drivers/mtd/maps/sa1100-flash.c1554
-rw-r--r--drivers/mtd/mtdblock.c5
-rw-r--r--drivers/mtd/mtdblock_ro.c4
-rw-r--r--drivers/mtd/mtdconcat.c675
-rw-r--r--drivers/mtd/nftlcore.c4
-rw-r--r--drivers/oprofile/buffer_sync.c394
-rw-r--r--drivers/oprofile/buffer_sync.h19
-rw-r--r--drivers/oprofile/cpu_buffer.c135
-rw-r--r--drivers/oprofile/cpu_buffer.h45
-rw-r--r--drivers/oprofile/event_buffer.c186
-rw-r--r--drivers/oprofile/event_buffer.h42
-rw-r--r--drivers/oprofile/oprof.c153
-rw-r--r--drivers/oprofile/oprof.h34
-rw-r--r--drivers/oprofile/oprofile_files.c91
-rw-r--r--drivers/oprofile/oprofile_stats.c77
-rw-r--r--drivers/oprofile/oprofile_stats.h31
-rw-r--r--drivers/oprofile/oprofilefs.c306
-rw-r--r--drivers/pcmcia/bulkmem.c26
-rw-r--r--drivers/s390/block/dasd.c4
-rw-r--r--drivers/s390/block/dasd_genhd.c3
-rw-r--r--drivers/s390/block/xpram.c18
-rw-r--r--drivers/sbus/char/jsflash.c50
-rw-r--r--drivers/scsi/BusLogic.c66
-rw-r--r--drivers/scsi/BusLogic.h2
-rw-r--r--drivers/scsi/aacraid/linit.c43
-rw-r--r--drivers/scsi/advansys.c60
-rw-r--r--drivers/scsi/advansys.h2
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux.c28
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_linux_host.h2
-rw-r--r--drivers/scsi/dpt_i2o.c23
-rw-r--r--drivers/scsi/dpti.h5
-rw-r--r--drivers/scsi/eata.c77
-rw-r--r--drivers/scsi/eata.h2
-rw-r--r--drivers/scsi/fcal.c23
-rw-r--r--drivers/scsi/fcal.h2
-rw-r--r--drivers/scsi/hosts.c1
-rw-r--r--drivers/scsi/hosts.h12
-rw-r--r--drivers/scsi/ips.c10
-rw-r--r--drivers/scsi/ips.h6
-rw-r--r--drivers/scsi/ncr53c8xx.c88
-rw-r--r--drivers/scsi/ncr53c8xx.h2
-rw-r--r--drivers/scsi/pluto.c25
-rw-r--r--drivers/scsi/pluto.h2
-rw-r--r--drivers/scsi/qla1280.c51
-rw-r--r--drivers/scsi/qla1280.h3
-rw-r--r--drivers/scsi/scsi.c44
-rw-r--r--drivers/scsi/scsi.h7
-rw-r--r--drivers/scsi/scsi_scan.c8
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/sg.c4
-rw-r--r--drivers/scsi/sr.c37
-rw-r--r--drivers/scsi/st.c124
-rw-r--r--drivers/scsi/st.h1
-rw-r--r--drivers/scsi/sym53c8xx.c89
-rw-r--r--drivers/scsi/sym53c8xx.h2
-rw-r--r--drivers/scsi/sym53c8xx_2/sym53c8xx.h3
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c100
138 files changed, 8071 insertions, 2297 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index 958ecc4df984..2224ec9303f6 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -38,7 +38,7 @@ obj-$(CONFIG_I2O) += message/
obj-$(CONFIG_I2C) += i2c/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
-obj-$(CONFIG_BLUEZ) += bluetooth/
+obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_HOTPLUG_PCI) += hotplug/
obj-$(CONFIG_ISDN_BOOL) += isdn/
diff --git a/drivers/acorn/block/fd1772.c b/drivers/acorn/block/fd1772.c
index 85b5b9cd8859..1d55917a10f8 100644
--- a/drivers/acorn/block/fd1772.c
+++ b/drivers/acorn/block/fd1772.c
@@ -1470,9 +1470,6 @@ static int floppy_open(struct inode *inode, struct file *filp)
int drive = minor(inode->i_rdev) & 3;
int old_dev;
- if ((minor(inode->i_rdev) >> 2) > NUM_DISK_TYPES)
- return -ENXIO;
-
old_dev = fd_device[drive];
if (fd_ref[drive])
@@ -1547,7 +1544,7 @@ int fd1772_init(void)
return 0;
for (i = 0; i < FD_MAX_UNITS; i++) {
- disks[i] = alloc_disk();
+ disks[i] = alloc_disk(1);
if (!disks[i])
goto out;
}
diff --git a/drivers/acorn/block/mfmhd.c b/drivers/acorn/block/mfmhd.c
index 32bef8806190..d4c01d605559 100644
--- a/drivers/acorn/block/mfmhd.c
+++ b/drivers/acorn/block/mfmhd.c
@@ -1186,14 +1186,6 @@ static int mfm_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long a
return 0;
}
-static int mfm_open(struct inode *inode, struct file *file)
-{
- int dev = DEVICE_NR(minor(inode->i_rdev));
- if (dev >= mfm_drives)
- return -ENODEV;
- return 0;
-}
-
/*
* This is to handle various kernel command line parameters
* specific to this driver.
@@ -1239,7 +1231,6 @@ void xd_set_geometry(struct block_device *bdev, unsigned char secsptrack,
static struct block_device_operations mfm_fops =
{
.owner = THIS_MODULE,
- .open = mfm_open,
.ioctl = mfm_ioctl,
};
@@ -1336,12 +1327,11 @@ static int __init mfm_init (void)
goto out3;
for (i = 0; i < mfm_drives; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(64);
if (!disk)
goto Enomem;
disk->major = MAJOR_NR;
disk->first_minor = i << 6;
- disk->minor_shift = 6;
disk->fops = &mfm_fops;
sprintf(disk->disk_name, "mfm%c", 'a'+i);
mfm_gendisk[i] = disk;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 4fc859d3ab57..83c31723d844 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -149,36 +149,16 @@ void driver_detach(struct device_driver * drv)
spin_unlock(&device_lock);
}
-/**
- * device_register - register a device
- * @dev: pointer to the device structure
- *
- * First, make sure that the device has a parent, create
- * a directory for it, then add it to the parent's list of
- * children.
- *
- * Maintains a global list of all devices, in depth-first ordering.
- * The head for that list is device_root.g_list.
- */
-int device_register(struct device *dev)
+int device_add(struct device *dev)
{
int error;
if (!dev || !strlen(dev->bus_id))
return -EINVAL;
- INIT_LIST_HEAD(&dev->node);
- INIT_LIST_HEAD(&dev->children);
- INIT_LIST_HEAD(&dev->g_list);
- INIT_LIST_HEAD(&dev->driver_list);
- INIT_LIST_HEAD(&dev->bus_list);
- INIT_LIST_HEAD(&dev->intf_list);
- spin_lock_init(&dev->lock);
- atomic_set(&dev->refcount,2);
- dev->present = 1;
spin_lock(&device_lock);
+ dev->present = 1;
if (dev->parent) {
- get_device_locked(dev->parent);
list_add_tail(&dev->g_list,&dev->parent->g_list);
list_add_tail(&dev->node,&dev->parent->children);
} else
@@ -209,10 +189,48 @@ int device_register(struct device *dev)
list_del_init(&dev->g_list);
list_del_init(&dev->node);
spin_unlock(&device_lock);
- if (dev->parent)
- put_device(dev->parent);
}
- put_device(dev);
+ return error;
+}
+
+void device_initialize(struct device *dev)
+{
+ INIT_LIST_HEAD(&dev->node);
+ INIT_LIST_HEAD(&dev->children);
+ INIT_LIST_HEAD(&dev->g_list);
+ INIT_LIST_HEAD(&dev->driver_list);
+ INIT_LIST_HEAD(&dev->bus_list);
+ INIT_LIST_HEAD(&dev->intf_list);
+ spin_lock_init(&dev->lock);
+ atomic_set(&dev->refcount,1);
+ if (dev->parent)
+ get_device(dev->parent);
+}
+
+/**
+ * device_register - register a device
+ * @dev: pointer to the device structure
+ *
+ * First, make sure that the device has a parent, create
+ * a directory for it, then add it to the parent's list of
+ * children.
+ *
+ * Maintains a global list of all devices, in depth-first ordering.
+ * The head for that list is device_root.g_list.
+ */
+int device_register(struct device *dev)
+{
+ int error;
+
+ if (!dev || !strlen(dev->bus_id))
+ return -EINVAL;
+
+ device_initialize(dev);
+ if (dev->parent)
+ get_device(dev->parent);
+ error = device_add(dev);
+ if (error && dev->parent)
+ put_device(dev->parent);
return error;
}
@@ -257,16 +275,7 @@ void put_device(struct device * dev)
put_device(parent);
}
-/**
- * device_unregister - unlink device
- * @dev: device going away
- *
- * The device has been removed from the system, so we disavow knowledge
- * of it. It might not be the final reference to the device, so we mark
- * it as !present, so no more references to it can be acquired.
- * In the end, we decrement the final reference count for it.
- */
-void device_unregister(struct device * dev)
+void device_del(struct device * dev)
{
spin_lock(&device_lock);
dev->present = 0;
@@ -293,7 +302,20 @@ void device_unregister(struct device * dev)
/* remove the driverfs directory */
device_remove_dir(dev);
+}
+/**
+ * device_unregister - unlink device
+ * @dev: device going away
+ *
+ * The device has been removed from the system, so we disavow knowledge
+ * of it. It might not be the final reference to the device, so we mark
+ * it as !present, so no more references to it can be acquired.
+ * In the end, we decrement the final reference count for it.
+ */
+void device_unregister(struct device * dev)
+{
+ device_del(dev);
put_device(dev);
}
diff --git a/drivers/block/DAC960.c b/drivers/block/DAC960.c
index 24a1ee66d93b..1c1a72e440e6 100644
--- a/drivers/block/DAC960.c
+++ b/drivers/block/DAC960.c
@@ -1962,7 +1962,6 @@ static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
sprintf(disk->disk_name, "rd/c%dd%d", Controller->ControllerNumber, n);
disk->major = MajorNumber;
disk->first_minor = n << DAC960_MaxPartitionsBits;
- disk->minor_shift = DAC960_MaxPartitionsBits;
disk->fops = &DAC960_BlockDeviceOperations;
}
/*
@@ -2200,7 +2199,7 @@ static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
}
memset(Controller, 0, sizeof(DAC960_Controller_T));
for (i = 0; i < DAC960_MaxLogicalDrives; i++) {
- Controller->disks[i] = alloc_disk();
+ Controller->disks[i] = alloc_disk(1<<DAC960_MaxPartitionsBits);
if (!Controller->disks[i])
goto Enomem;
}
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index eff7ee947ea7..6c22bb8963d6 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -9,9 +9,9 @@
#
export-objs := elevator.o ll_rw_blk.o loop.o genhd.o acsi.o \
- block_ioctl.o deadline-iosched.o
+ scsi_ioctl.o deadline-iosched.o
-obj-y := elevator.o ll_rw_blk.o blkpg.o genhd.o block_ioctl.o deadline-iosched.o
+obj-y := elevator.o ll_rw_blk.o ioctl.o genhd.o scsi_ioctl.o deadline-iosched.o
obj-$(CONFIG_MAC_FLOPPY) += swim3.o
obj-$(CONFIG_BLK_DEV_FD) += floppy.o
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 5d36adb832e2..520eeabab869 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -1086,8 +1086,6 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg )
{
int dev = DEVICE_NR(inode->i_rdev);
- if (dev >= NDevices)
- return -EINVAL;
switch (cmd) {
case HDIO_GETGEO:
/* HDIO_GETGEO is supported more for getting the partition's
@@ -1130,13 +1128,8 @@ static int acsi_ioctl( struct inode *inode, struct file *file,
static int acsi_open( struct inode * inode, struct file * filp )
{
- int device;
- struct acsi_info_struct *aip;
-
- device = DEVICE_NR(inode->i_rdev);
- if (device >= NDevices)
- return -ENXIO;
- aip = &acsi_info[device];
+ int device = DEVICE_NR(inode->i_rdev);
+ struct acsi_info_struct *aip = &acsi_info[device];
if (access_count[device] == 0 && aip->removable) {
#if 0
@@ -1729,7 +1722,7 @@ int acsi_init( void )
#endif
err = -ENOMEM;
for( i = 0; i < NDevices; ++i ) {
- acsi_gendisk[i] = alloc_disk();
+ acsi_gendisk[i] = alloc_disk(16);
if (!acsi_gendisk[i])
goto out4;
}
@@ -1739,7 +1732,10 @@ int acsi_init( void )
sprintf(disk->disk_name, "ad%c", 'a'+i);
disk->major = MAJOR_NR;
disk->first_minor = i << 4;
- disk->minor_shift = (acsi_info[i].type==HARDDISK)?4:0;
+ if (acsi_info[i].type != HARDDISK) {
+ disk->minor_shift = 0;
+ disk->minors = 1;
+ }
disk->fops = &acsi_fops;
set_capacity(disk, acsi_info[i].size);
add_disk(disk);
diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c
index 22790c4145fe..9e6ae34ae194 100644
--- a/drivers/block/amiflop.c
+++ b/drivers/block/amiflop.c
@@ -1607,9 +1607,6 @@ static int floppy_open(struct inode *inode, struct file *filp)
if (!kdev_same(old_dev, inode->i_rdev))
return -EBUSY;
- if (unit[drive].type->code == FD_NODRIVE)
- return -ENODEV;
-
if (filp && filp->f_mode & 3) {
check_disk_change(inode->i_bdev);
if (filp->f_mode & 2 ) {
@@ -1683,11 +1680,6 @@ static int amiga_floppy_change(kdev_t dev)
int changed;
static int first_time = 1;
- if (major(dev) != MAJOR_NR) {
- printk(KERN_CRIT "floppy_change: not a floppy\n");
- return 0;
- }
-
if (first_time)
changed = first_time--;
else {
@@ -1735,7 +1727,7 @@ static int __init fd_probe_drives(void)
fd_probe(drive);
if (unit[drive].type->code == FD_NODRIVE)
continue;
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk) {
unit[drive].type->code = FD_NODRIVE;
continue;
@@ -1751,7 +1743,6 @@ static int __init fd_probe_drives(void)
printk("fd%d ",drive);
disk->major = MAJOR_NR;
disk->first_minor = drive;
- disk->minor_shift = 0;
disk->fops = &floppy_fops;
sprintf(disk->disk_name, "fd%d", drive);
set_capacity(disk, 880*2);
diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c
index 12f3ae02b317..c2ae35bb875b 100644
--- a/drivers/block/ataflop.c
+++ b/drivers/block/ataflop.c
@@ -1358,12 +1358,6 @@ static int fd_device[4] = { 0,0,0,0 };
static int check_floppy_change (kdev_t dev)
{
unsigned int drive = minor(dev) & 0x03;
-
- if (major(dev) != MAJOR_NR) {
- printk(KERN_ERR "floppy_changed: not a floppy\n");
- return 0;
- }
-
if (test_bit (drive, &fake_change)) {
/* simulated change (e.g. after formatting) */
return 1;
@@ -1855,17 +1849,11 @@ static void __init config_types( void )
static int floppy_open( struct inode *inode, struct file *filp )
{
- int drive, type;
- int old_dev;
+ int drive = minor(inode->i_rdev) & 3;
+ int type = minor(inode->i_rdev) >> 2;
+ int old_dev = fd_device[drive];
- drive = minor(inode->i_rdev) & 3;
- type = minor(inode->i_rdev) >> 2;
DPRINT(("fd_open: type=%d\n",type));
- if (drive >= FD_MAX_UNITS || type > NUM_DISK_MINORS)
- return -ENXIO;
-
- old_dev = fd_device[drive];
-
if (fd_ref[drive] && old_dev != minor(inode->i_rdev))
return -EBUSY;
@@ -1949,7 +1937,7 @@ int __init atari_floppy_init (void)
}
for (i = 0; i < FD_MAX_UNITS; i++) {
- unit[i].disk = alloc_disk();
+ unit[i].disk = alloc_disk(1);
if (!unit[i].disk)
goto Enomem;
}
diff --git a/drivers/block/blkpg.c b/drivers/block/blkpg.c
deleted file mode 100644
index d5ba72a8ac86..000000000000
--- a/drivers/block/blkpg.c
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Partition table and disk geometry handling
- *
- * This obsoletes the partition-handling code in genhd.c:
- * Userspace can look at a disk in arbitrary format and tell
- * the kernel what partitions there are on the disk, and how
- * these should be numbered.
- * It also allows one to repartition a disk that is being used.
- *
- * A single ioctl with lots of subfunctions:
- *
- * Device number stuff:
- * get_whole_disk() (given the device number of a partition, find
- * the device number of the encompassing disk)
- * get_all_partitions() (given the device number of a disk, return the
- * device numbers of all its known partitions)
- *
- * Partition stuff:
- * add_partition()
- * delete_partition()
- * test_partition_in_use() (also for test_disk_in_use)
- *
- * Geometry stuff:
- * get_geometry()
- * set_geometry()
- * get_bios_drivedata()
- *
- * For today, only the partition stuff - aeb, 990515
- */
-
-#include <linux/errno.h>
-#include <linux/fs.h> /* for BLKROSET, ... */
-#include <linux/sched.h> /* for capable() */
-#include <linux/blk.h> /* for set_device_ro() */
-#include <linux/blkpg.h>
-#include <linux/genhd.h>
-#include <linux/module.h> /* for EXPORT_SYMBOL */
-#include <linux/backing-dev.h>
-#include <linux/buffer_head.h>
-
-#include <asm/uaccess.h>
-
-/*
- * What is the data describing a partition?
- *
- * 1. a device number (kdev_t)
- * 2. a starting sector and number of sectors (hd_struct)
- * given in the part[] array of the gendisk structure for the drive.
- *
- * The number of sectors is replicated in the sizes[] array of
- * the gendisk structure for the major, which again is copied to
- * the blk_size[][] array.
- * (However, hd_struct has the number of 512-byte sectors,
- * g->sizes[] and blk_size[][] have the number of 1024-byte blocks.)
- * Note that several drives may have the same major.
- */
-
-/*
- * Add a partition.
- *
- * returns: EINVAL: bad parameters
- * ENXIO: cannot find drive
- * EBUSY: proposed partition overlaps an existing one
- * or has the same number as an existing one
- * 0: all OK.
- */
-int add_partition(struct block_device *bdev, struct blkpg_partition *p)
-{
- struct gendisk *g;
- long long ppstart, pplength;
- int part, i;
-
- /* convert bytes to sectors */
- ppstart = (p->start >> 9);
- pplength = (p->length >> 9);
-
- /* check for fit in a hd_struct */
- if (sizeof(sector_t) == sizeof(long) &&
- sizeof(long long) > sizeof(long)) {
- long pstart, plength;
- pstart = ppstart;
- plength = pplength;
- if (pstart != ppstart || plength != pplength
- || pstart < 0 || plength < 0)
- return -EINVAL;
- }
-
- /* find the drive major */
- g = get_gendisk(bdev->bd_dev, &part);
- if (!g)
- return -ENXIO;
-
- /* existing drive? */
-
- /* drive and partition number OK? */
- if (bdev != bdev->bd_contains)
- return -EINVAL;
- if (part)
- BUG();
- if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
- return -EINVAL;
-
- /* partition number in use? */
- if (g->part[p->pno - 1].nr_sects != 0)
- return -EBUSY;
-
- /* overlap? */
- for (i = 0; i < (1<<g->minor_shift) - 1; i++)
- if (!(ppstart+pplength <= g->part[i].start_sect ||
- ppstart >= g->part[i].start_sect + g->part[i].nr_sects))
- return -EBUSY;
-
- /* all seems OK */
- g->part[p->pno - 1].start_sect = ppstart;
- g->part[p->pno - 1].nr_sects = pplength;
- update_partition(g, p->pno);
- return 0;
-}
-
-/*
- * Delete a partition given by partition number
- *
- * returns: EINVAL: bad parameters
- * ENXIO: cannot find partition
- * EBUSY: partition is busy
- * 0: all OK.
- *
- * Note that the dev argument refers to the entire disk, not the partition.
- */
-int del_partition(struct block_device *bdev, struct blkpg_partition *p)
-{
- struct gendisk *g;
- struct block_device *bdevp;
- int part;
- int holder;
-
- /* find the drive major */
- g = get_gendisk(bdev->bd_dev, &part);
- if (!g)
- return -ENXIO;
- if (bdev != bdev->bd_contains)
- return -EINVAL;
- if (part)
- BUG();
- if (p->pno <= 0 || p->pno >= (1 << g->minor_shift))
- return -EINVAL;
-
- /* existing drive and partition? */
- if (g->part[p->pno - 1].nr_sects == 0)
- return -ENXIO;
-
- /* partition in use? Incomplete check for now. */
- bdevp = bdget(MKDEV(g->major, g->first_minor + p->pno));
- if (!bdevp)
- return -ENOMEM;
- if (bd_claim(bdevp, &holder) < 0) {
- bdput(bdevp);
- return -EBUSY;
- }
-
- /* all seems OK */
- fsync_bdev(bdevp);
- invalidate_bdev(bdevp, 0);
-
- g->part[p->pno - 1].start_sect = 0;
- g->part[p->pno - 1].nr_sects = 0;
- update_partition(g, p->pno);
- bd_release(bdevp);
- bdput(bdevp);
-
- return 0;
-}
-
-int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
-{
- struct blkpg_ioctl_arg a;
- struct blkpg_partition p;
- int len;
-
- if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
- return -EFAULT;
-
- switch (a.op) {
- case BLKPG_ADD_PARTITION:
- case BLKPG_DEL_PARTITION:
- len = a.datalen;
- if (len < sizeof(struct blkpg_partition))
- return -EINVAL;
- if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
- return -EFAULT;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (a.op == BLKPG_ADD_PARTITION)
- return add_partition(bdev, &p);
- else
- return del_partition(bdev, &p);
- default:
- return -EINVAL;
- }
-}
-
-/*
- * Common ioctl's for block devices
- */
-int blk_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
-{
- request_queue_t *q;
- u64 ullval = 0;
- int intval;
- unsigned short usval;
- kdev_t dev = to_kdev_t(bdev->bd_dev);
- int holder;
- struct backing_dev_info *bdi;
-
- switch (cmd) {
- case BLKROSET:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (get_user(intval, (int *)(arg)))
- return -EFAULT;
- set_device_ro(dev, intval);
- return 0;
- case BLKROGET:
- intval = (bdev_read_only(bdev) != 0);
- return put_user(intval, (int *)(arg));
-
- case BLKRASET:
- case BLKFRASET:
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
- bdi = blk_get_backing_dev_info(bdev);
- if (bdi == NULL)
- return -ENOTTY;
- bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
- return 0;
-
- case BLKRAGET:
- case BLKFRAGET:
- if (!arg)
- return -EINVAL;
- bdi = blk_get_backing_dev_info(bdev);
- if (bdi == NULL)
- return -ENOTTY;
- return put_user((bdi->ra_pages * PAGE_CACHE_SIZE) / 512,
- (long *)arg);
-
- case BLKSECTGET:
- if ((q = bdev_get_queue(bdev)) == NULL)
- return -EINVAL;
-
- usval = q->max_sectors;
- blk_put_queue(q);
- return put_user(usval, (unsigned short *)arg);
-
- case BLKFLSBUF:
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- fsync_bdev(bdev);
- invalidate_bdev(bdev, 0);
- return 0;
-
- case BLKSSZGET:
- /* get block device hardware sector size */
- intval = bdev_hardsect_size(bdev);
- return put_user(intval, (int *) arg);
-
- case BLKGETSIZE:
- {
- unsigned long ret;
- /* size in sectors, works up to 2 TB */
- ullval = bdev->bd_inode->i_size;
- ret = ullval >> 9;
- if ((u64)ret != (ullval >> 9))
- return -EFBIG;
- return put_user(ret, (unsigned long *) arg);
- }
-
- case BLKGETSIZE64:
- /* size in bytes */
- ullval = bdev->bd_inode->i_size;
- return put_user(ullval, (u64 *) arg);
-
- case BLKPG:
- return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
- case BLKBSZGET:
- /* get the logical block size (cf. BLKSSZGET) */
- intval = block_size(bdev);
- return put_user(intval, (int *) arg);
-
- case BLKBSZSET:
- /* set the logical block size */
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
- if (!arg)
- return -EINVAL;
- if (get_user(intval, (int *) arg))
- return -EFAULT;
- if (intval > PAGE_SIZE || intval < 512 ||
- (intval & (intval - 1)))
- return -EINVAL;
- if (bd_claim(bdev, &holder) < 0)
- return -EBUSY;
- set_blocksize(bdev, intval);
- bd_release(bdev);
- return 0;
-
- default:
- return -EINVAL;
- }
-}
diff --git a/drivers/block/block_ioctl.c b/drivers/block/block_ioctl.c
deleted file mode 100644
index edde76503d60..000000000000
--- a/drivers/block/block_ioctl.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2001 Jens Axboe <axboe@suse.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
-
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public Licens
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
- *
- */
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/config.h>
-#include <linux/swap.h>
-#include <linux/init.h>
-#include <linux/smp_lock.h>
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/completion.h>
-
-#include <linux/cdrom.h>
-
-int blk_do_rq(request_queue_t *q, struct request *rq)
-{
- DECLARE_COMPLETION(wait);
- int err = 0;
-
- rq->flags |= REQ_NOMERGE;
- rq->waiting = &wait;
- elv_add_request(q, rq, 1);
- generic_unplug_device(q);
- wait_for_completion(&wait);
-
- /*
- * for now, never retry anything
- */
- if (rq->errors)
- err = -EIO;
-
- return err;
-}
-
-int block_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
-{
- request_queue_t *q;
- struct request *rq;
- int close = 0, err;
-
- q = bdev_get_queue(bdev);
- if (!q)
- return -ENXIO;
-
- switch (cmd) {
- case CDROMCLOSETRAY:
- close = 1;
- case CDROMEJECT:
- rq = blk_get_request(q, WRITE, __GFP_WAIT);
- rq->flags = REQ_BLOCK_PC;
- memset(rq->cmd, 0, sizeof(rq->cmd));
- rq->cmd[0] = GPCMD_START_STOP_UNIT;
- rq->cmd[4] = 0x02 + (close != 0);
- err = blk_do_rq(q, rq);
- blk_put_request(rq);
- break;
- default:
- err = -ENOTTY;
- }
-
- blk_put_queue(q);
- return err;
-}
-
-EXPORT_SYMBOL(block_ioctl);
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c
index ebd7a216810f..caa30e1c6e84 100644
--- a/drivers/block/cciss.c
+++ b/drivers/block/cciss.c
@@ -740,7 +740,7 @@ static int revalidate_allvol(kdev_t dev)
for(i=0; i< NWD; i++) {
struct gendisk *disk = hba[ctlr]->gendisk[i];
- if (disk->part)
+ if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
}
@@ -792,7 +792,7 @@ static int deregister_disk(int ctlr, int logvol)
spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
/* invalidate the devices and deregister the disk */
- if (disk->part)
+ if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
/* check to see if it was the last disk */
if (logvol == h->highest_lun) {
@@ -2274,7 +2274,7 @@ static int alloc_cciss_hba(void)
struct gendisk *disk[NWD];
int i, n;
for (n = 0; n < NWD; n++) {
- disk[n] = alloc_disk();
+ disk[n] = alloc_disk(1 << NWD_SHIFT);
if (!disk[n])
goto out;
}
@@ -2447,7 +2447,6 @@ static int __init cciss_init_one(struct pci_dev *pdev,
sprintf(disk->disk_name, "cciss/c%dd%d", i, j);
disk->major = MAJOR_NR + i;
disk->first_minor = j << NWD_SHIFT;
- disk->minor_shift = NWD_SHIFT;
if( !(drv->nr_blocks))
continue;
(BLK_DEFAULT_QUEUE(MAJOR_NR + i))->hardsect_size = drv->block_size;
@@ -2500,7 +2499,7 @@ static void __devexit cciss_remove_one (struct pci_dev *pdev)
/* remove it from the disk list */
for (j = 0; j < NWD; j++) {
struct gendisk *disk = hba[i]->gendisk[j];
- if (disk->part)
+ if (disk->flags & GENHD_FL_UP)
del_gendisk(disk);
}
diff --git a/drivers/block/cpqarray.c b/drivers/block/cpqarray.c
index 7bfa29a5bc89..c3b1c4b17ea7 100644
--- a/drivers/block/cpqarray.c
+++ b/drivers/block/cpqarray.c
@@ -304,7 +304,7 @@ static void __exit cpqarray_exit(void)
kfree(hba[i]->cmd_pool_bits);
for (j = 0; j < NWD; j++) {
- if (ida_gendisk[i][j]->part)
+ if (ida_gendisk[i][j]->flags & GENHD_FL_UP)
del_gendisk(ida_gendisk[i][j]);
put_disk(ida_gendisk[i][j]);
}
@@ -358,7 +358,7 @@ static int __init cpqarray_init(void)
}
num_cntlrs_reg++;
for (j=0; j<NWD; j++) {
- ida_gendisk[i][j] = alloc_disk();
+ ida_gendisk[i][j] = alloc_disk(1 << NWD_SHIFT);
if (!ida_gendisk[i][j])
goto Enomem2;
}
@@ -405,7 +405,6 @@ static int __init cpqarray_init(void)
sprintf(disk->disk_name, "ida/c%dd%d", i, j);
disk->major = MAJOR_NR + i;
disk->first_minor = j<<NWD_SHIFT;
- disk->minor_shift = NWD_SHIFT;
disk->flags = GENHD_FL_DEVFS;
disk->fops = &ida_fops;
if (!drv->nr_blks)
@@ -1428,7 +1427,7 @@ static int revalidate_allvol(kdev_t dev)
*/
for (i = 0; i < NWD; i++) {
struct gendisk *disk = ida_gendisk[ctlr][i];
- if (disk->part)
+ if (disk->flags & GENDH_FL_UP)
del_gendisk(disk);
}
memset(hba[ctlr]->drv, 0, sizeof(drv_info_t)*NWD);
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 924e1e011f76..3fde460ce7ea 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -3488,16 +3488,6 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
loc.start = 0;
return _COPYOUT(loc);
}
-
- case BLKGETSIZE:
- ECALL(get_floppy_geometry(drive, type, &g));
- return put_user(g->size, (unsigned long *) param);
-
- case BLKGETSIZE64:
- ECALL(get_floppy_geometry(drive, type, &g));
- return put_user((u64)g->size << 9, (u64 *) param);
- /* BLKRRPART is not defined as floppies don't have
- * partition tables */
}
/* convert the old style command into a new style command */
@@ -4240,7 +4230,7 @@ int __init floppy_init(void)
raw_cmd = NULL;
for (i=0; i<N_DRIVE; i++) {
- disks[i] = alloc_disk();
+ disks[i] = alloc_disk(1);
if (!disks[i])
goto Enomem;
}
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 3f6d259165f3..449e69061bbc 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -57,34 +57,13 @@ EXPORT_SYMBOL(blk_set_probe); /* Will go away */
* This function registers the partitioning information in @gp
* with the kernel.
*/
-static void add_gendisk(struct gendisk *gp)
+void add_disk(struct gendisk *disk)
{
- struct hd_struct *p = NULL;
-
- if (gp->minor_shift) {
- size_t size = sizeof(struct hd_struct)*((1<<gp->minor_shift)-1);
- p = kmalloc(size, GFP_KERNEL);
- if (!p) {
- printk(KERN_ERR "out of memory; no partitions for %s\n",
- gp->disk_name);
- gp->minor_shift = 0;
- } else
- memset(p, 0, size);
- }
- gp->part = p;
-
write_lock(&gendisk_lock);
- list_add(&gp->list, &gendisks[gp->major].list);
- if (gp->minor_shift)
- list_add_tail(&gp->full_list, &gendisk_list);
- else
- INIT_LIST_HEAD(&gp->full_list);
+ list_add(&disk->list, &gendisks[disk->major].list);
+ list_add_tail(&disk->full_list, &gendisk_list);
write_unlock(&gendisk_lock);
-}
-
-void add_disk(struct gendisk *disk)
-{
- add_gendisk(disk);
+ disk->flags |= GENHD_FL_UP;
register_disk(disk);
}
@@ -118,6 +97,8 @@ get_gendisk(dev_t dev, int *part)
read_lock(&gendisk_lock);
if (gendisks[major].get) {
disk = gendisks[major].get(minor);
+ if (disk)
+ get_disk(disk);
read_unlock(&gendisk_lock);
return disk;
}
@@ -125,8 +106,9 @@ get_gendisk(dev_t dev, int *part)
disk = list_entry(p, struct gendisk, list);
if (disk->first_minor > minor)
continue;
- if (disk->first_minor + (1<<disk->minor_shift) <= minor)
+ if (disk->first_minor + disk->minors <= minor)
continue;
+ get_disk(disk);
read_unlock(&gendisk_lock);
*part = minor - disk->first_minor;
return disk;
@@ -135,8 +117,6 @@ get_gendisk(dev_t dev, int *part)
return NULL;
}
-EXPORT_SYMBOL(get_gendisk);
-
#ifdef CONFIG_PROC_FS
/* iterator */
static void *part_start(struct seq_file *part, loff_t *pos)
@@ -173,7 +153,7 @@ static int show_partition(struct seq_file *part, void *v)
seq_puts(part, "major minor #blocks name\n\n");
/* Don't show non-partitionable devices or empty devices */
- if (!get_capacity(sgp))
+ if (!get_capacity(sgp) || sgp->minors == 1)
return 0;
/* show the full disk and all non-0 size partitions of it */
@@ -181,7 +161,7 @@ static int show_partition(struct seq_file *part, void *v)
sgp->major, sgp->first_minor,
(unsigned long long)get_capacity(sgp) >> 1,
disk_name(sgp, 0, buf));
- for (n = 0; n < (1<<sgp->minor_shift) - 1; n++) {
+ for (n = 0; n < sgp->minors - 1; n++) {
if (sgp->part[n].nr_sects == 0)
continue;
seq_printf(part, "%4d %4d %10llu %s\n",
@@ -210,6 +190,10 @@ struct device_class disk_devclass = {
.name = "disk",
};
+static struct bus_type disk_bus = {
+ name: "block",
+};
+
int __init device_init(void)
{
int i;
@@ -218,6 +202,7 @@ int __init device_init(void)
INIT_LIST_HEAD(&gendisks[i].list);
blk_dev_init();
devclass_register(&disk_devclass);
+ bus_register(&disk_bus);
return 0;
}
@@ -225,17 +210,51 @@ __initcall(device_init);
EXPORT_SYMBOL(disk_devclass);
-struct gendisk *alloc_disk(void)
+static void disk_release(struct device *dev)
+{
+ struct gendisk *disk = dev->driver_data;
+ kfree(disk->part);
+ kfree(disk);
+}
+
+struct gendisk *alloc_disk(int minors)
{
struct gendisk *disk = kmalloc(sizeof(struct gendisk), GFP_KERNEL);
- if (disk)
+ if (disk) {
memset(disk, 0, sizeof(struct gendisk));
+ if (minors > 1) {
+ int size = (minors - 1) * sizeof(struct hd_struct);
+ disk->part = kmalloc(size, GFP_KERNEL);
+ if (!disk->part) {
+ kfree(disk);
+ return NULL;
+ }
+ memset(disk->part, 0, size);
+ }
+ disk->minors = minors;
+ while (minors >>= 1)
+ disk->minor_shift++;
+ INIT_LIST_HEAD(&disk->full_list);
+ disk->disk_dev.bus = &disk_bus;
+ disk->disk_dev.release = disk_release;
+ disk->disk_dev.driver_data = disk;
+ device_initialize(&disk->disk_dev);
+ }
+ return disk;
+}
+
+struct gendisk *get_disk(struct gendisk *disk)
+{
+ atomic_inc(&disk->disk_dev.refcount);
return disk;
}
void put_disk(struct gendisk *disk)
{
- kfree(disk);
+ if (disk)
+ put_device(&disk->disk_dev);
}
+
EXPORT_SYMBOL(alloc_disk);
+EXPORT_SYMBOL(get_disk);
EXPORT_SYMBOL(put_disk);
diff --git a/drivers/block/ioctl.c b/drivers/block/ioctl.c
new file mode 100644
index 000000000000..e420c691763d
--- /dev/null
+++ b/drivers/block/ioctl.c
@@ -0,0 +1,215 @@
+#include <linux/sched.h> /* for capable() */
+#include <linux/blk.h> /* for set_device_ro() */
+#include <linux/blkpg.h>
+#include <linux/backing-dev.h>
+#include <linux/buffer_head.h>
+#include <asm/uaccess.h>
+
+static int blkpg_ioctl(struct block_device *bdev, struct blkpg_ioctl_arg *arg)
+{
+ struct block_device *bdevp;
+ int holder;
+ struct gendisk *disk;
+ struct blkpg_ioctl_arg a;
+ struct blkpg_partition p;
+ long long start, length;
+ int part;
+ int i;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (copy_from_user(&a, arg, sizeof(struct blkpg_ioctl_arg)))
+ return -EFAULT;
+ if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition)))
+ return -EFAULT;
+ disk = bdev->bd_disk;
+ if (bdev != bdev->bd_contains)
+ return -EINVAL;
+ part = p.pno;
+ if (part <= 0 || part >= disk->minors)
+ return -EINVAL;
+ switch (a.op) {
+ case BLKPG_ADD_PARTITION:
+ start = p.start >> 9;
+ length = p.length >> 9;
+ /* check for fit in a hd_struct */
+ if (sizeof(sector_t) == sizeof(long) &&
+ sizeof(long long) > sizeof(long)) {
+ long pstart = start, plength = length;
+ if (pstart != start || plength != length
+ || pstart < 0 || plength < 0)
+ return -EINVAL;
+ }
+ /* partition number in use? */
+ if (disk->part[part - 1].nr_sects != 0)
+ return -EBUSY;
+ /* overlap? */
+ for (i = 0; i < disk->minors - 1; i++) {
+ struct hd_struct *s = &disk->part[i];
+ if (!(start+length <= s->start_sect ||
+ start >= s->start_sect + s->nr_sects))
+ return -EBUSY;
+ }
+ /* all seems OK */
+ add_partition(disk, part, start, length);
+ return 0;
+ case BLKPG_DEL_PARTITION:
+ if (disk->part[part - 1].nr_sects == 0)
+ return -ENXIO;
+ /* partition in use? Incomplete check for now. */
+ bdevp = bdget(MKDEV(disk->major, disk->first_minor) + part);
+ if (!bdevp)
+ return -ENOMEM;
+ if (bd_claim(bdevp, &holder) < 0) {
+ bdput(bdevp);
+ return -EBUSY;
+ }
+ /* all seems OK */
+ fsync_bdev(bdevp);
+ invalidate_bdev(bdevp, 0);
+
+ delete_partition(disk, part);
+ bd_release(bdevp);
+ bdput(bdevp);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int blkdev_reread_part(struct block_device *bdev)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ int res;
+
+ if (disk->minors == 1 || bdev != bdev->bd_contains)
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (down_trylock(&bdev->bd_sem))
+ return -EBUSY;
+ res = rescan_partitions(disk, bdev);
+ up(&bdev->bd_sem);
+ return res;
+}
+
+static int put_ushort(unsigned long arg, unsigned short val)
+{
+ return put_user(val, (unsigned short *)arg);
+}
+
+static int put_int(unsigned long arg, int val)
+{
+ return put_user(val, (int *)arg);
+}
+
+static int put_long(unsigned long arg, long val)
+{
+ return put_user(val, (long *)arg);
+}
+
+static int put_ulong(unsigned long arg, unsigned long val)
+{
+ return put_user(val, (unsigned long *)arg);
+}
+
+static int put_u64(unsigned long arg, u64 val)
+{
+ return put_user(val, (u64 *)arg);
+}
+
+int blkdev_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+ unsigned long arg)
+{
+ struct block_device *bdev = inode->i_bdev;
+ struct backing_dev_info *bdi;
+ int holder;
+ int ret, n;
+
+ switch (cmd) {
+ case BLKELVGET:
+ case BLKELVSET:
+ /* deprecated, use the /proc/iosched interface instead */
+ return -ENOTTY;
+ case BLKRAGET:
+ case BLKFRAGET:
+ if (!arg)
+ return -EINVAL;
+ bdi = blk_get_backing_dev_info(bdev);
+ if (bdi == NULL)
+ return -ENOTTY;
+ return put_long(arg, (bdi->ra_pages * PAGE_CACHE_SIZE) / 512);
+ case BLKROGET:
+ return put_int(arg, bdev_read_only(bdev) != 0);
+ case BLKBSZGET: /* get the logical block size (cf. BLKSSZGET) */
+ return put_int(arg, block_size(bdev));
+ case BLKSSZGET: /* get block device hardware sector size */
+ return put_int(arg, bdev_hardsect_size(bdev));
+ case BLKSECTGET:
+ return put_ushort(arg, bdev->bd_queue->max_sectors);
+ case BLKRASET:
+ case BLKFRASET:
+ if(!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ bdi = blk_get_backing_dev_info(bdev);
+ if (bdi == NULL)
+ return -ENOTTY;
+ bdi->ra_pages = (arg * 512) / PAGE_CACHE_SIZE;
+ return 0;
+ case BLKBSZSET:
+ /* set the logical block size */
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (!arg)
+ return -EINVAL;
+ if (get_user(n, (int *) arg))
+ return -EFAULT;
+ if (n > PAGE_SIZE || n < 512 || (n & (n - 1)))
+ return -EINVAL;
+ if (bd_claim(bdev, &holder) < 0)
+ return -EBUSY;
+ set_blocksize(bdev, n);
+ bd_release(bdev);
+ return 0;
+ case BLKPG:
+ return blkpg_ioctl(bdev, (struct blkpg_ioctl_arg *) arg);
+ case BLKRRPART:
+ return blkdev_reread_part(bdev);
+ case BLKGETSIZE:
+ if ((bdev->bd_inode->i_size >> 9) > ~0UL)
+ return -EFBIG;
+ return put_ulong(arg, bdev->bd_inode->i_size >> 9);
+ case BLKGETSIZE64:
+ return put_u64(arg, bdev->bd_inode->i_size);
+ case BLKFLSBUF:
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (bdev->bd_op->ioctl) {
+ ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+ if (ret != -EINVAL)
+ return ret;
+ }
+ fsync_bdev(bdev);
+ invalidate_bdev(bdev, 0);
+ return 0;
+ case BLKROSET:
+ if (bdev->bd_op->ioctl) {
+ ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+ if (ret != -EINVAL)
+ return ret;
+ }
+ if (!capable(CAP_SYS_ADMIN))
+ return -EACCES;
+ if (get_user(n, (int *)(arg)))
+ return -EFAULT;
+ set_device_ro(to_kdev_t(bdev->bd_dev), n);
+ return 0;
+ default:
+ if (bdev->bd_op->ioctl) {
+ ret = bdev->bd_op->ioctl(inode, file, cmd, arg);
+ if (ret != -EINVAL)
+ return ret;
+ }
+ }
+ return -ENOTTY;
+}
diff --git a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index ea56c1d8456c..eb877e50a8d1 100644
--- a/drivers/block/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -1427,7 +1427,19 @@ void drive_stat_acct(struct request *rq, int nr_sectors, int new_io)
int rw = rq_data_dir(rq);
unsigned int index;
- index = disk_index(rq->rq_dev);
+ if (!rq->rq_disk)
+ return;
+
+ if (rw == READ) {
+ rq->rq_disk->rio += new_io;
+ rq->rq_disk->reads += nr_sectors;
+ } else if (rw == WRITE) {
+ rq->rq_disk->wio += new_io;
+ rq->rq_disk->writes += nr_sectors;
+ }
+
+ index = rq->rq_disk->first_minor >> rq->rq_disk->minor_shift;
+
if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
return;
@@ -1747,6 +1759,7 @@ get_rq:
req->waiting = NULL;
req->bio = req->biotail = bio;
req->rq_dev = to_kdev_t(bio->bi_bdev->bd_dev);
+ req->rq_disk = bio->bi_bdev->bd_disk;
add_request(q, req, insert_here);
out:
if (freereq)
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index e39755017faf..14fa8720f8db 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -1075,7 +1075,7 @@ int __init loop_init(void)
goto out_mem;
for (i = 0; i < max_loop; i++) {
- disks[i] = alloc_disk();
+ disks[i] = alloc_disk(1);
if (!disks[i])
goto out_mem2;
}
diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c
index be27027d32b8..27726bd0246a 100644
--- a/drivers/block/nbd.c
+++ b/drivers/block/nbd.c
@@ -507,7 +507,7 @@ static int __init nbd_init(void)
}
for (i = 0; i < MAX_NBD; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
goto out;
nbd_dev[i].disk = disk;
@@ -537,7 +537,6 @@ static int __init nbd_init(void)
nbd_bytesizes[i] = 0x7ffffc00; /* 2GB */
disk->major = MAJOR_NR;
disk->first_minor = i;
- disk->minor_shift = 0;
disk->fops = &nbd_fops;
sprintf(disk->disk_name, "nbd%d", i);
set_capacity(disk, 0x3ffffe);
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
index 0e4bac2bd1ef..95bedb2a580c 100644
--- a/drivers/block/paride/pcd.c
+++ b/drivers/block/paride/pcd.c
@@ -281,7 +281,7 @@ static void pcd_init_units(void)
pcd_drive_count = 0;
for (unit = 0, cd = pcd; unit < PCD_UNITS; unit++, cd++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
continue;
cd->disk = disk;
@@ -303,7 +303,6 @@ static void pcd_init_units(void)
cd->info.mask = 0;
disk->major = major;
disk->first_minor = unit;
- disk->minor_shift = 0;
strcpy(disk->disk_name, cd->name); /* umm... */
disk->fops = &pcd_bdops;
}
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
index 7fdf4a3e4b2a..2278ee4928ab 100644
--- a/drivers/block/paride/pd.c
+++ b/drivers/block/paride/pd.c
@@ -350,9 +350,6 @@ static int pd_open(struct inode *inode, struct file *file)
int unit = DEVICE_NR(inode->i_rdev);
struct pd_unit *disk = pd + unit;
- if (unit >= PD_UNITS || !disk->present)
- return -ENODEV;
-
disk->access++;
if (disk->removable) {
@@ -703,14 +700,13 @@ static int pd_detect(void)
}
for (unit = 0, disk = pd; unit < PD_UNITS; unit++, disk++) {
if (disk->present) {
- struct gendisk *p = alloc_disk();
+ struct gendisk *p = alloc_disk(1 << PD_BITS);
if (!p) {
disk->present = 0;
k--;
continue;
}
strcpy(p->disk_name, disk->name);
- p->minor_shift = PD_BITS;
p->fops = &pd_fops;
p->major = major;
p->first_minor = unit << PD_BITS;
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
index becf37efd5ec..9598323b5694 100644
--- a/drivers/block/paride/pf.c
+++ b/drivers/block/paride/pf.c
@@ -308,7 +308,7 @@ void pf_init_units(void)
pf_drive_count = 0;
for (unit = 0, pf = units; unit < PF_UNITS; unit++, pf++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
continue;
pf->disk = disk;
@@ -320,7 +320,6 @@ void pf_init_units(void)
disk->major = MAJOR_NR;
disk->first_minor = unit;
strcpy(disk->disk_name, pf->name);
- disk->minor_shift = 0;
disk->fops = &pf_fops;
if (!(*drives[unit])[D_PRT])
pf_drive_count++;
@@ -332,9 +331,6 @@ static int pf_open(struct inode *inode, struct file *file)
int unit = DEVICE_NR(inode->i_rdev);
struct pf_unit *pf = units + unit;
- if ((unit >= PF_UNITS) || (!pf->present))
- return -ENODEV;
-
pf_identify(pf);
if (pf->media_status == PF_NM)
diff --git a/drivers/block/ps2esdi.c b/drivers/block/ps2esdi.c
index 770fbfd4613f..0015ef9a1cd2 100644
--- a/drivers/block/ps2esdi.c
+++ b/drivers/block/ps2esdi.c
@@ -89,9 +89,6 @@ static void (*current_int_handler) (u_int) = NULL;
static void ps2esdi_normal_interrupt_handler(u_int);
static void ps2esdi_initial_reset_int_handler(u_int);
static void ps2esdi_geometry_int_handler(u_int);
-
-static int ps2esdi_open(struct inode *inode, struct file *file);
-
static int ps2esdi_ioctl(struct inode *inode, struct file *file,
u_int cmd, u_long arg);
@@ -141,7 +138,6 @@ static struct ps2esdi_i_struct ps2esdi_info[MAX_HD] =
static struct block_device_operations ps2esdi_fops =
{
.owner = THIS_MODULE,
- .open = ps2esdi_open,
.ioctl = ps2esdi_ioctl,
};
@@ -421,13 +417,12 @@ static int __init ps2esdi_geninit(void)
error = -ENOMEM;
for (i = 0; i < ps2esdi_drives; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(64);
if (!disk)
goto err_out4;
disk->major = MAJOR_NR;
disk->first_minor = i<<6;
sprintf(disk->disk_name, "ed%c", 'a'+i);
- disk->minor_shift = 6;
disk->fops = &ps2esdi_fops;
ps2esdi_gendisk[i] = disk;
}
@@ -1076,15 +1071,6 @@ static void dump_cmd_complete_status(u_int int_ret_code)
}
-
-static int ps2esdi_open(struct inode *inode, struct file *file)
-{
- int dev = DEVICE_NR(inode->i_rdev);
- if (dev >= ps2esdi_drives)
- return -ENODEV;
- return 0;
-}
-
static int ps2esdi_ioctl(struct inode *inode,
struct file *file, u_int cmd, u_long arg)
{
diff --git a/drivers/block/rd.c b/drivers/block/rd.c
index a0e60c5972a6..bbd247fa29dc 100644
--- a/drivers/block/rd.c
+++ b/drivers/block/rd.c
@@ -291,8 +291,6 @@ static int rd_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
if (cmd != BLKFLSBUF)
return -EINVAL;
- if (!capable(CAP_SYS_ADMIN))
- return -EACCES;
/* special: we want to release the ramdisk memory,
it's not like with the other blockdevices where
this ioctl only flushes away the buffer cache. */
@@ -383,6 +381,7 @@ static int rd_open(struct inode * inode, struct file * filp)
rd_bdev[unit]->bd_inode->i_mapping->a_ops = &ramdisk_aops;
rd_bdev[unit]->bd_inode->i_size = rd_length[unit];
rd_bdev[unit]->bd_queue = &blk_dev[MAJOR_NR].request_queue;
+ rd_bdev[unit]->bd_disk = get_disk(rd_disks[unit]);
}
return 0;
@@ -431,17 +430,16 @@ static int __init rd_init (void)
}
#ifdef CONFIG_BLK_DEV_INITRD
- initrd_disk = alloc_disk();
+ initrd_disk = alloc_disk(1);
if (!initrd_disk)
return -ENOMEM;
initrd_disk->major = MAJOR_NR;
initrd_disk->first_minor = INITRD_MINOR;
- initrd_disk->minor_shift = 0;
initrd_disk->fops = &rd_bd_op;
sprintf(initrd_disk->disk_name, "initrd");
#endif
for (i = 0; i < NUM_RAMDISKS; i++) {
- rd_disks[i] = alloc_disk();
+ rd_disks[i] = alloc_disk(1);
if (!rd_disks[i])
goto out;
}
@@ -460,7 +458,6 @@ static int __init rd_init (void)
rd_length[i] = rd_size << 10;
disk->major = MAJOR_NR;
disk->first_minor = i;
- disk->minor_shift = 0;
disk->fops = &rd_bd_op;
sprintf(disk->disk_name, "rd%d", i);
set_capacity(disk, rd_size * 2);
diff --git a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
new file mode 100644
index 000000000000..1f7ef11b1c62
--- /dev/null
+++ b/drivers/block/scsi_ioctl.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2001 Jens Axboe <axboe@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public Licens
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-
+ *
+ */
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/config.h>
+#include <linux/swap.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/completion.h>
+#include <linux/cdrom.h>
+#include <linux/slab.h>
+
+#include <scsi/scsi.h>
+
+#include <asm/uaccess.h>
+
+int blk_do_rq(request_queue_t *q, struct request *rq)
+{
+ DECLARE_COMPLETION(wait);
+ int err = 0;
+
+ rq->flags |= REQ_NOMERGE;
+ rq->waiting = &wait;
+ elv_add_request(q, rq, 1);
+ generic_unplug_device(q);
+ wait_for_completion(&wait);
+
+ /*
+ * for now, never retry anything
+ */
+ if (rq->errors)
+ err = -EIO;
+
+ return err;
+}
+
+#include <scsi/sg.h>
+
+static int sg_get_version(int *p)
+{
+ static int sg_version_num = 30527;
+ return put_user(sg_version_num, p);
+}
+
+static int scsi_get_idlun(request_queue_t *q, int *p)
+{
+ return put_user(0, p);
+}
+
+static int scsi_get_bus(request_queue_t *q, int *p)
+{
+ return put_user(0, p);
+}
+
+static int sg_get_timeout(request_queue_t *q)
+{
+ return HZ;
+}
+
+static int sg_set_timeout(request_queue_t *q, int *p)
+{
+ int timeout;
+ int error = get_user(timeout, p);
+ return error;
+}
+
+static int reserved_size = 0;
+
+static int sg_get_reserved_size(request_queue_t *q, int *p)
+{
+ return put_user(reserved_size, p);
+}
+
+static int sg_set_reserved_size(request_queue_t *q, int *p)
+{
+ int size;
+ int error = get_user(size, p);
+ if (!error)
+ reserved_size = size;
+ return error;
+}
+
+static int sg_emulated_host(request_queue_t *q, int *p)
+{
+ return put_user(1, p);
+}
+
+static int sg_io(request_queue_t *q, struct sg_io_hdr *uptr)
+{
+ int err;
+ struct sg_io_hdr hdr;
+ struct request *rq;
+ void *buffer;
+
+ if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr)))
+ return -EFAULT;
+ if (copy_from_user(&hdr, uptr, sizeof(*uptr)))
+ return -EFAULT;
+
+ if ( hdr.cmd_len > sizeof(rq->cmd) )
+ return -EINVAL;
+
+ buffer = NULL;
+ if (hdr.dxfer_len) {
+ unsigned int bytes = (hdr.dxfer_len + 511) & ~511;
+
+ switch (hdr.dxfer_direction) {
+ default:
+ return -EINVAL;
+ case SG_DXFER_TO_DEV:
+ case SG_DXFER_FROM_DEV:
+ case SG_DXFER_TO_FROM_DEV:
+ break;
+ }
+ buffer = kmalloc(bytes, GFP_USER);
+ if (!buffer)
+ return -ENOMEM;
+ if (hdr.dxfer_direction == SG_DXFER_TO_DEV ||
+ hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV)
+ copy_from_user(buffer, hdr.dxferp, hdr.dxfer_len);
+ }
+
+ rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ rq->timeout = 60*HZ;
+ rq->data = buffer;
+ rq->data_len = hdr.dxfer_len;
+ rq->flags = REQ_BLOCK_PC;
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+ copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len);
+ err = blk_do_rq(q, rq);
+
+ blk_put_request(rq);
+
+ copy_to_user(uptr, &hdr, sizeof(*uptr));
+ if (buffer) {
+ if (hdr.dxfer_direction == SG_DXFER_FROM_DEV ||
+ hdr.dxfer_direction == SG_DXFER_TO_FROM_DEV)
+ copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len);
+ kfree(buffer);
+ }
+ return err;
+}
+
+int scsi_cmd_ioctl(struct block_device *bdev, unsigned int cmd, unsigned long arg)
+{
+ request_queue_t *q;
+ struct request *rq;
+ int close = 0, err;
+
+ q = bdev_get_queue(bdev);
+ if (!q)
+ return -ENXIO;
+
+ switch (cmd) {
+ case SG_GET_VERSION_NUM:
+ return sg_get_version((int *) arg);
+ case SCSI_IOCTL_GET_IDLUN:
+ return scsi_get_idlun(q, (int *) arg);
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ return scsi_get_bus(q, (int *) arg);
+ case SG_SET_TIMEOUT:
+ return sg_set_timeout(q, (int *) arg);
+ case SG_GET_TIMEOUT:
+ return sg_get_timeout(q);
+ case SG_GET_RESERVED_SIZE:
+ return sg_get_reserved_size(q, (int *) arg);
+ case SG_SET_RESERVED_SIZE:
+ return sg_set_reserved_size(q, (int *) arg);
+ case SG_EMULATED_HOST:
+ return sg_emulated_host(q, (int *) arg);
+ case SG_IO:
+ return sg_io(q, (struct sg_io_hdr *) arg);
+ case CDROMCLOSETRAY:
+ close = 1;
+ case CDROMEJECT:
+ rq = blk_get_request(q, WRITE, __GFP_WAIT);
+ rq->flags = REQ_BLOCK_PC;
+ rq->data = NULL;
+ rq->data_len = 0;
+ rq->timeout = 60*HZ;
+ memset(rq->cmd, 0, sizeof(rq->cmd));
+ rq->cmd[0] = GPCMD_START_STOP_UNIT;
+ rq->cmd[4] = 0x02 + (close != 0);
+ err = blk_do_rq(q, rq);
+ blk_put_request(rq);
+ break;
+ default:
+ err = -ENOTTY;
+ }
+
+ blk_put_queue(q);
+ return err;
+}
+
+EXPORT_SYMBOL(scsi_cmd_ioctl);
diff --git a/drivers/block/swim3.c b/drivers/block/swim3.c
index b1cb36f3ca5c..2a5f3afefbfa 100644
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1037,7 +1037,7 @@ int swim3_init(void)
return -ENODEV;
for (i = 0; i < floppy_count; i++) {
- disks[i] = alloc_disk();
+ disks[i] = alloc_disk(1);
if (!disks[i])
goto out;
}
diff --git a/drivers/block/swim_iop.c b/drivers/block/swim_iop.c
index 29c2f1696063..3ec747c3f80f 100644
--- a/drivers/block/swim_iop.c
+++ b/drivers/block/swim_iop.c
@@ -188,7 +188,7 @@ int swimiop_init(void)
printk("SWIM-IOP: detected %d installed drives.\n", floppy_count);
for (i = 0; i < floppy_count; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
continue;
disk->major = MAJOR_NR;
diff --git a/drivers/block/umem.c b/drivers/block/umem.c
index 53dfd2a7c624..4a2b212f1261 100644
--- a/drivers/block/umem.c
+++ b/drivers/block/umem.c
@@ -864,18 +864,6 @@ static int mm_check_change(kdev_t i_rdev)
return 0;
}
-
-/*
------------------------------------------------------------------------------------
--- mm_open
------------------------------------------------------------------------------------
-*/
-static int mm_open(struct inode *i, struct file *filp)
-{
- if (DEVICE_NR(i->i_rdev) >= num_cards)
- return -ENXIO;
- return 0;
-}
/*
-----------------------------------------------------------------------------------
-- mm_fops
@@ -883,7 +871,6 @@ static int mm_open(struct inode *i, struct file *filp)
*/
static struct block_device_operations mm_fops = {
owner: THIS_MODULE,
- open: mm_open,
ioctl: mm_ioctl,
revalidate: mm_revalidate,
check_media_change: mm_check_change,
@@ -1190,7 +1177,7 @@ int __init mm_init(void)
}
for (i = 0; i < num_cards; i++) {
- mm_gendisk[i] = alloc_disk();
+ mm_gendisk[i] = alloc_disk(1 << MM_SHIFT);
if (!mm_gendisk[i])
goto out;
}
@@ -1203,7 +1190,6 @@ int __init mm_init(void)
spin_lock_init(&cards[i].lock);
disk->major = major_nr;
disk->first_minor = i << MM_SHIFT;
- disk->minor_shift = MM_SHIFT;
disk->fops = &mm_fops;
set_capacity(disk, cards[i].mm_size << 1);
add_disk(disk);
diff --git a/drivers/block/xd.c b/drivers/block/xd.c
index 3e3315e81bde..939901490525 100644
--- a/drivers/block/xd.c
+++ b/drivers/block/xd.c
@@ -130,7 +130,6 @@ static struct gendisk *xd_gendisk[2];
static struct block_device_operations xd_fops = {
owner: THIS_MODULE,
- open: xd_open,
ioctl: xd_ioctl,
};
static DECLARE_WAIT_QUEUE_HEAD(xd_wait_int);
@@ -205,12 +204,11 @@ static int __init xd_init(void)
goto out3;
for (i = 0; i < xd_drives; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(64);
if (!disk)
goto Enomem;
disk->major = MAJOR_NR;
disk->first_minor = i<<6;
- disk->minor_shift = 6;
sprintf(disk->disk_name, "xd%c", i+'a');
disk->fops = &xd_fops;
xd_gendisk[i] = disk;
@@ -284,15 +282,6 @@ static u_char __init xd_detect (u_char *controller, unsigned int *address)
return (found);
}
-/* xd_open: open a device */
-static int xd_open (struct inode *inode,struct file *file)
-{
- int dev = DEVICE_NR(inode->i_rdev);
- if (dev >= xd_drives)
- return -ENXIO;
- return 0;
-}
-
/* do_xd_request: handle an incoming request */
static void do_xd_request (request_queue_t * q)
{
@@ -337,8 +326,6 @@ static void do_xd_request (request_queue_t * q)
static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg)
{
int dev = DEVICE_NR(inode->i_rdev);
-
- if (dev >= xd_drives) return -EINVAL;
switch (cmd) {
case HDIO_GETGEO:
{
diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c
index 30625811de3e..edb2676680e3 100644
--- a/drivers/block/z2ram.c
+++ b/drivers/block/z2ram.c
@@ -365,14 +365,13 @@ z2_init( void )
MAJOR_NR );
return -EBUSY;
}
- z2ram_gendisk = alloc_disk();
+ z2ram_gendisk = alloc_disk(1);
if (!z2ram_gendisk) {
unregister_blkdev( MAJOR_NR, DEVICE_NAME );
return -ENOMEM;
}
z2ram_gendisk->major = MAJOR_NR;
z2ram_gendisk->first_minor = 0;
- z2ram_gendisk->minor_shift = 0;
z2ram_gendisk->fops = &z2_fops;
sprintf(z2ram_gendisk->disk_name, "z2ram");
diff --git a/drivers/bluetooth/Config.help b/drivers/bluetooth/Config.help
index 6196615c7ec2..212fec68fdb3 100644
--- a/drivers/bluetooth/Config.help
+++ b/drivers/bluetooth/Config.help
@@ -1,5 +1,5 @@
HCI UART driver
-CONFIG_BLUEZ_HCIUART
+CONFIG_BT_HCIUART
Bluetooth HCI UART driver.
This driver is required if you want to use Bluetooth devices with
serial port interface. You will also need this driver if you have
@@ -10,7 +10,7 @@ CONFIG_BLUEZ_HCIUART
kernel or say M to compile it as module (hci_uart.o).
HCI UART (H4) protocol support
-CONFIG_BLUEZ_HCIUART_H4
+CONFIG_BT_HCIUART_H4
UART (H4) is serial protocol for communication between Bluetooth
device and host. This protocol is required for most Bluetooth devices
with UART interface, including PCMCIA and CF cards.
@@ -18,7 +18,7 @@ CONFIG_BLUEZ_HCIUART_H4
Say Y here to compile support for HCI UART (H4) protocol.
HCI BCSP protocol support
-CONFIG_BLUEZ_HCIUART_BCSP
+CONFIG_BT_HCIUART_BCSP
BCSP (BlueCore Serial Protocol) is serial protocol for communication
between Bluetooth device and host. This protocol is required for non
USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
@@ -27,7 +27,7 @@ CONFIG_BLUEZ_HCIUART_BCSP
Say Y here to compile support for HCI BCSP protocol.
HCI USB driver
-CONFIG_BLUEZ_HCIUSB
+CONFIG_BT_HCIUSB
Bluetooth HCI USB driver.
This driver is required if you want to use Bluetooth devices with
USB interface.
@@ -36,7 +36,7 @@ CONFIG_BLUEZ_HCIUSB
kernel or say M to compile it as module (hci_usb.o).
HCI USB zero packet support
-CONFIG_BLUEZ_USB_ZERO_PACKET
+CONFIG_BT_USB_ZERO_PACKET
Support for USB zero packets.
This option is provided only as a work around for buggy Bluetooth USB
devices. Do _not_ enable it unless you know for sure that your device
@@ -44,7 +44,7 @@ CONFIG_BLUEZ_USB_ZERO_PACKET
Most people should say N here.
HCI VHCI Virtual HCI device driver
-CONFIG_BLUEZ_HCIVHCI
+CONFIG_BT_HCIVHCI
Bluetooth Virtual HCI device driver.
This driver is required if you want to use HCI Emulation software.
@@ -52,7 +52,7 @@ CONFIG_BLUEZ_HCIVHCI
kernel or say M to compile it as module (hci_vhci.o).
HCI DTL1 (PC Card) device driver
-CONFIG_BLUEZ_HCIDTL1
+CONFIG_BT_HCIDTL1
Bluetooth HCI DTL1 (PC Card) driver.
This driver provides support for Bluetooth PCMCIA devices with
Nokia DTL1 interface:
@@ -63,7 +63,7 @@ CONFIG_BLUEZ_HCIDTL1
kernel or say M to compile it as module (dtl1_cs.o).
HCI BT3C (PC Card) device driver
-CONFIG_BLUEZ_HCIBT3C
+CONFIG_BT_HCIBT3C
Bluetooth HCI BT3C (PC Card) driver.
This driver provides support for Bluetooth PCMCIA devices with
3Com BT3C interface:
@@ -77,7 +77,7 @@ CONFIG_BLUEZ_HCIBT3C
kernel or say M to compile it as module (bt3c_cs.o).
HCI BlueCard (PC Card) device driver
-CONFIG_BLUEZ_HCIBLUECARD
+CONFIG_BT_HCIBLUECARD
Bluetooth HCI BlueCard (PC Card) driver.
This driver provides support for Bluetooth PCMCIA devices with
Anycom BlueCard interface:
diff --git a/drivers/bluetooth/Config.in b/drivers/bluetooth/Config.in
index a411065d23b7..46f37275ff76 100644
--- a/drivers/bluetooth/Config.in
+++ b/drivers/bluetooth/Config.in
@@ -1,23 +1,23 @@
mainmenu_option next_comment
comment 'Bluetooth device drivers'
-dep_tristate 'HCI USB driver' CONFIG_BLUEZ_HCIUSB $CONFIG_BLUEZ $CONFIG_USB
-if [ "$CONFIG_BLUEZ_HCIUSB" != "n" ]; then
- bool ' USB zero packet support' CONFIG_BLUEZ_USB_ZERO_PACKET
+dep_tristate 'HCI USB driver' CONFIG_BT_HCIUSB $CONFIG_BT $CONFIG_USB
+if [ "$CONFIG_BT_HCIUSB" != "n" ]; then
+ bool ' USB zero packet support' CONFIG_BT_USB_ZERO_PACKET
fi
-dep_tristate 'HCI UART driver' CONFIG_BLUEZ_HCIUART $CONFIG_BLUEZ
-if [ "$CONFIG_BLUEZ_HCIUART" != "n" ]; then
- bool ' UART (H4) protocol support' CONFIG_BLUEZ_HCIUART_H4
- bool ' BCSP protocol support' CONFIG_BLUEZ_HCIUART_BCSP
+dep_tristate 'HCI UART driver' CONFIG_BT_HCIUART $CONFIG_BT
+if [ "$CONFIG_BT_HCIUART" != "n" ]; then
+ bool ' UART (H4) protocol support' CONFIG_BT_HCIUART_H4
+ bool ' BCSP protocol support' CONFIG_BT_HCIUART_BCSP
fi
-dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BLUEZ_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI DTL1 (PC Card) driver' CONFIG_BT_HCIDTL1 $CONFIG_PCMCIA $CONFIG_BT
-dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BLUEZ_HCIBT3C $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI BT3C (PC Card) driver' CONFIG_BT_HCIBT3C $CONFIG_PCMCIA $CONFIG_BT
-dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BLUEZ_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BLUEZ
+dep_tristate 'HCI BlueCard (PC Card) driver' CONFIG_BT_HCIBLUECARD $CONFIG_PCMCIA $CONFIG_BT
-dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BLUEZ_HCIVHCI $CONFIG_BLUEZ
+dep_tristate 'HCI VHCI (Virtual HCI device) driver' CONFIG_BT_HCIVHCI $CONFIG_BT
endmenu
diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile
index 15e76c032f2c..1fbd6f052b07 100644
--- a/drivers/bluetooth/Makefile
+++ b/drivers/bluetooth/Makefile
@@ -2,16 +2,16 @@
# Makefile for the Linux Bluetooth HCI device drivers.
#
-obj-$(CONFIG_BLUEZ_HCIUSB) += hci_usb.o
-obj-$(CONFIG_BLUEZ_HCIVHCI) += hci_vhci.o
-obj-$(CONFIG_BLUEZ_HCIUART) += hci_uart.o
-obj-$(CONFIG_BLUEZ_HCIDTL1) += dtl1_cs.o
-obj-$(CONFIG_BLUEZ_HCIBT3C) += bt3c_cs.o
-obj-$(CONFIG_BLUEZ_HCIBLUECARD) += bluecard_cs.o
+obj-$(CONFIG_BT_HCIUSB) += hci_usb.o
+obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o
+obj-$(CONFIG_BT_HCIUART) += hci_uart.o
+obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
+obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
+obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
hci_uart-y := hci_ldisc.o
-hci_uart-$(CONFIG_BLUEZ_HCIUART_H4) += hci_h4.o
-hci_uart-$(CONFIG_BLUEZ_HCIUART_BCSP) += hci_bcsp.o
+hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
+hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
hci_uart-objs := $(hci_uart-y)
include $(TOPDIR)/Rules.make
diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c
index 296d674bc38a..67dcad9138da 100644
--- a/drivers/bluetooth/bluecard_cs.c
+++ b/drivers/bluetooth/bluecard_cs.c
@@ -60,7 +60,7 @@ MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("BlueZ driver for the Anycom BlueCard (LSE039/LSE041)");
+MODULE_DESCRIPTION("Bluetooth driver for the Anycom BlueCard (LSE039/LSE041)");
MODULE_LICENSE("GPL");
@@ -396,7 +396,7 @@ static void bluecard_receive(bluecard_info_t *info, unsigned int offset)
if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
- if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
return;
}
@@ -571,7 +571,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud)
/* Ericsson baud rate command */
unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 };
- if (!(skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ if (!(skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
printk(KERN_WARNING "bluecard_cs: Can't allocate mem for new packet.\n");
return -1;
}
diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c
index 517fd86199a4..460652790b07 100644
--- a/drivers/bluetooth/bt3c_cs.c
+++ b/drivers/bluetooth/bt3c_cs.c
@@ -72,7 +72,7 @@ MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>, Jose Orlando Pereira <jop@di.uminho.pt>");
-MODULE_DESCRIPTION("BlueZ driver for the 3Com Bluetooth PCMCIA card");
+MODULE_DESCRIPTION("Bluetooth driver for the 3Com Bluetooth PCMCIA card");
MODULE_LICENSE("GPL");
@@ -264,7 +264,7 @@ static void bt3c_receive(bt3c_info_t *info)
if (info->rx_skb == NULL) {
info->rx_state = RECV_WAIT_PACKET_TYPE;
info->rx_count = 0;
- if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
printk(KERN_WARNING "bt3c_cs: Can't allocate mem for new packet.\n");
return;
}
diff --git a/drivers/bluetooth/dtl1_cs.c b/drivers/bluetooth/dtl1_cs.c
index 80df236ec1dc..63de1e3fc4ac 100644
--- a/drivers/bluetooth/dtl1_cs.c
+++ b/drivers/bluetooth/dtl1_cs.c
@@ -66,7 +66,7 @@ MODULE_PARM(irq_mask, "i");
MODULE_PARM(irq_list, "1-4i");
MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>");
-MODULE_DESCRIPTION("BlueZ driver for Nokia Connectivity Card DTL-1");
+MODULE_DESCRIPTION("Bluetooth driver for Nokia Connectivity Card DTL-1");
MODULE_LICENSE("GPL");
@@ -238,7 +238,7 @@ static void dtl1_receive(dtl1_info_t *info)
/* Allocate packet */
if (info->rx_skb == NULL)
- if (!(info->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
+ if (!(info->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC))) {
printk(KERN_WARNING "dtl1_cs: Can't allocate mem for new packet.\n");
info->rx_state = RECV_WAIT_NSH;
info->rx_count = NSHL;
@@ -433,7 +433,7 @@ static int dtl1_hci_send_frame(struct sk_buff *skb)
nsh.zero = 0;
nsh.len = skb->len;
- s = bluez_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
+ s = bt_skb_alloc(NSHL + skb->len + 1, GFP_ATOMIC);
skb_reserve(s, NSHL);
memcpy(skb_put(s, skb->len), skb->data, skb->len);
if (skb->len & 0x0001)
diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c
index b3f3c71c8287..bfd5401987ec 100644
--- a/drivers/bluetooth/hci_bcsp.c
+++ b/drivers/bluetooth/hci_bcsp.c
@@ -57,7 +57,7 @@
#include "hci_uart.h"
#include "hci_bcsp.h"
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
@@ -176,7 +176,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
u8 hdr[4], chan;
int rel, i;
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
u16 BCSP_CRC_INIT(bcsp_txmsg_crc);
#endif
@@ -228,7 +228,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
BT_DBG("Sending packet with seqno %u", bcsp->msgq_txseq);
bcsp->msgq_txseq = ++(bcsp->msgq_txseq) & 0x07;
}
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
hdr[0] |= 0x40;
#endif
@@ -240,7 +240,7 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
/* Put BCSP header */
for (i = 0; i < 4; i++) {
bcsp_slip_one_byte(nskb, hdr[i]);
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
bcsp_crc_update(&bcsp_txmsg_crc, hdr[i]);
#endif
}
@@ -248,12 +248,12 @@ static struct sk_buff *bcsp_prepare_pkt(struct bcsp_struct *bcsp, u8 *data,
/* Put payload */
for (i = 0; i < len; i++) {
bcsp_slip_one_byte(nskb, data[i]);
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
bcsp_crc_update(&bcsp_txmsg_crc, data[i]);
#endif
}
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP_TXCRC
+#ifdef CONFIG_BT_HCIUART_BCSP_TXCRC
/* Put CRC */
bcsp_txmsg_crc = bcsp_crc_reverse(bcsp_txmsg_crc);
bcsp_slip_one_byte(nskb, (u8) ((bcsp_txmsg_crc >> 8) & 0x00ff));
@@ -611,7 +611,7 @@ static int bcsp_recv(struct hci_uart *hu, void *data, int count)
* Allocate packet. Max len of a BCSP pkt=
* 0xFFF (payload) +4 (header) +2 (crc) */
- bcsp->rx_skb = bluez_skb_alloc(0x1005, GFP_ATOMIC);
+ bcsp->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC);
if (!bcsp->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
bcsp->rx_state = BCSP_W4_PKT_DELIMITER;
diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c
index 0e2a25e0526e..521eb19442be 100644
--- a/drivers/bluetooth/hci_h4.c
+++ b/drivers/bluetooth/hci_h4.c
@@ -23,7 +23,7 @@
*/
/*
- * BlueZ HCI UART(H4) protocol.
+ * Bluetooth HCI UART(H4) protocol.
*
* $Id: hci_h4.c,v 1.3 2002/09/09 01:17:32 maxk Exp $
*/
@@ -56,7 +56,7 @@
#include "hci_uart.h"
#include "hci_h4.h"
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
@@ -160,7 +160,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
ptr = data;
while (count) {
if (h4->rx_count) {
- len = MIN(h4->rx_count, count);
+ len = min_t(unsigned int, h4->rx_count, count);
memcpy(skb_put(h4->rx_skb, len), ptr, len);
h4->rx_count -= len; count -= len; ptr += len;
@@ -238,7 +238,7 @@ static int h4_recv(struct hci_uart *hu, void *data, int count)
ptr++; count--;
/* Allocate packet */
- h4->rx_skb = bluez_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+ h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
if (!h4->rx_skb) {
BT_ERR("Can't allocate mem for new packet");
h4->rx_state = H4_W4_PACKET_TYPE;
diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
index 067a25c7fc1f..e5196a92b7ba 100644
--- a/drivers/bluetooth/hci_ldisc.c
+++ b/drivers/bluetooth/hci_ldisc.c
@@ -23,7 +23,7 @@
*/
/*
- * BlueZ HCI UART driver.
+ * Bluetooth HCI UART driver.
*
* $Id: hci_ldisc.c,v 1.5 2002/10/02 18:37:20 maxk Exp $
*/
@@ -55,7 +55,7 @@
#include <net/bluetooth/hci_core.h>
#include "hci_uart.h"
-#ifndef HCI_UART_DEBUG
+#ifndef CONFIG_BT_HCIUART_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
@@ -507,11 +507,11 @@ static unsigned int hci_uart_tty_poll(struct tty_struct *tty, struct file *filp,
return 0;
}
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
int h4_init(void);
int h4_deinit(void);
#endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
int bcsp_init(void);
int bcsp_deinit(void);
#endif
@@ -521,7 +521,7 @@ int __init hci_uart_init(void)
static struct tty_ldisc hci_uart_ldisc;
int err;
- BT_INFO("BlueZ HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+ BT_INFO("Bluetooth HCI UART driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
VERSION);
BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
@@ -545,10 +545,10 @@ int __init hci_uart_init(void)
return err;
}
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
h4_init();
#endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
bcsp_init();
#endif
@@ -559,10 +559,10 @@ void hci_uart_cleanup(void)
{
int err;
-#ifdef CONFIG_BLUEZ_HCIUART_H4
+#ifdef CONFIG_BT_HCIUART_H4
h4_deinit();
#endif
-#ifdef CONFIG_BLUEZ_HCIUART_BCSP
+#ifdef CONFIG_BT_HCIUART_BCSP
bcsp_deinit();
#endif
@@ -575,5 +575,5 @@ module_init(hci_uart_init);
module_exit(hci_uart_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI UART driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth HCI UART driver ver " VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
index a94786f7d6ba..027b4463f3c9 100644
--- a/drivers/bluetooth/hci_usb.c
+++ b/drivers/bluetooth/hci_usb.c
@@ -23,7 +23,7 @@
*/
/*
- * BlueZ HCI USB driver.
+ * Bluetooth HCI USB driver.
* Based on original USB Bluetooth driver for Linux kernel
* Copyright (c) 2000 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (c) 2000 Mark Douglas Corner <mcorner@umich.edu>
@@ -59,14 +59,14 @@
#define HCI_MAX_PENDING (HCI_MAX_BULK_RX + HCI_MAX_BULK_TX + 1)
-#ifndef HCI_USB_DEBUG
+#ifndef CONFIG_BT_HCIUSB_DEBUG
#undef BT_DBG
#define BT_DBG( A... )
#undef BT_DMP
#define BT_DMP( A... )
#endif
-#ifndef CONFIG_BLUEZ_USB_ZERO_PACKET
+#ifndef CONFIG_BT_USB_ZERO_PACKET
#undef USB_ZERO_PACKET
#define USB_ZERO_PACKET 0
#endif
@@ -167,7 +167,7 @@ static int hci_usb_rx_submit(struct hci_usb *husb, struct urb *urb)
size = HCI_MAX_FRAME_SIZE;
- if (!(skb = bluez_skb_alloc(size, GFP_ATOMIC))) {
+ if (!(skb = bt_skb_alloc(size, GFP_ATOMIC))) {
usb_free_urb(urb);
return -ENOMEM;
}
@@ -465,7 +465,7 @@ static void hci_usb_interrupt(struct urb *urb)
if (count > len)
goto bad_len;
- skb = bluez_skb_alloc(len, GFP_ATOMIC);
+ skb = bt_skb_alloc(len, GFP_ATOMIC);
if (!skb) {
BT_ERR("%s no memory for event packet", husb->hdev.name);
goto done;
@@ -569,7 +569,7 @@ static void hci_usb_rx_complete(struct urb *urb)
if (count != size) {
BT_ERR("%s corrupted ACL packet: count %d, dlen %d",
husb->hdev.name, count, dlen);
- bluez_dump("hci_usb", skb->data, count);
+ bt_dump("hci_usb", skb->data, count);
husb->hdev.stat.err_rx++;
goto resubmit;
}
@@ -639,7 +639,7 @@ int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
/* Find endpoints that we need */
- ifn = MIN(udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
+ ifn = min_t(unsigned int, udev->actconfig->bNumInterfaces, HCI_MAX_IFACE_NUM);
for (i = 0; i < ifn; i++) {
iface = &udev->actconfig->interface[i];
for (a = 0; a < iface->num_altsetting; a++) {
@@ -781,7 +781,7 @@ int hci_usb_init(void)
{
int err;
- BT_INFO("BlueZ HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+ BT_INFO("Bluetooth HCI USB driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
VERSION);
BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
@@ -800,5 +800,5 @@ module_init(hci_usb_init);
module_exit(hci_usb_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ HCI USB driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c
index a3ca871e2049..a70eef0fd4d9 100644
--- a/drivers/bluetooth/hci_vhci.c
+++ b/drivers/bluetooth/hci_vhci.c
@@ -23,7 +23,7 @@
*/
/*
- * BlueZ HCI virtual device driver.
+ * Bluetooth HCI virtual device driver.
*
* $Id: hci_vhci.c,v 1.3 2002/04/17 17:37:20 maxk Exp $
*/
@@ -136,7 +136,7 @@ static inline ssize_t hci_vhci_get_user(struct hci_vhci_struct *hci_vhci, const
if (count > HCI_MAX_FRAME_SIZE)
return -EINVAL;
- if (!(skb = bluez_skb_alloc(count, GFP_KERNEL)))
+ if (!(skb = bt_skb_alloc(count, GFP_KERNEL)))
return -ENOMEM;
if (copy_from_user(skb_put(skb, count), buf, count)) {
@@ -172,7 +172,7 @@ static inline ssize_t hci_vhci_put_user(struct hci_vhci_struct *hci_vhci,
int len = count, total = 0;
char *ptr = buf;
- len = MIN(skb->len, len);
+ len = min_t(unsigned int, skb->len, len);
if (copy_to_user(ptr, skb->data, len))
return -EFAULT;
total += len;
@@ -331,7 +331,7 @@ static struct miscdevice hci_vhci_miscdev=
int __init hci_vhci_init(void)
{
- BT_INFO("BlueZ VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
+ BT_INFO("Bluetooth VHCI driver ver %s Copyright (C) 2000,2001 Qualcomm Inc",
VERSION);
BT_INFO("Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>");
@@ -352,5 +352,5 @@ module_init(hci_vhci_init);
module_exit(hci_vhci_cleanup);
MODULE_AUTHOR("Maxim Krasnyansky <maxk@qualcomm.com>");
-MODULE_DESCRIPTION("BlueZ VHCI driver ver " VERSION);
+MODULE_DESCRIPTION("Bluetooth VHCI driver ver " VERSION);
MODULE_LICENSE("GPL");
diff --git a/drivers/cdrom/aztcd.c b/drivers/cdrom/aztcd.c
index 53f8fe2bafe2..b8e1880d8714 100644
--- a/drivers/cdrom/aztcd.c
+++ b/drivers/cdrom/aztcd.c
@@ -1908,7 +1908,7 @@ static int __init aztcd_init(void)
}
devfs_register(NULL, "aztcd", DEVFS_FL_DEFAULT, MAJOR_NR, 0,
S_IFBLK | S_IRUGO | S_IWUGO, &azt_fops, NULL);
- azt_disk = alloc_disk();
+ azt_disk = alloc_disk(1);
if (!azt_disk)
goto err_out2;
if (register_blkdev(MAJOR_NR, "aztcd", &azt_fops) != 0) {
@@ -1921,7 +1921,6 @@ static int __init aztcd_init(void)
blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
azt_disk->major = MAJOR_NR;
azt_disk->first_minor = 0;
- azt_disk->minor_shift = 0;
azt_disk->fops = &azt_fops;
sprintf(azt_disk->disk_name, "aztcd");
add_disk(azt_disk);
diff --git a/drivers/cdrom/cdu31a.c b/drivers/cdrom/cdu31a.c
index 8863cb1254de..f4077094707a 100644
--- a/drivers/cdrom/cdu31a.c
+++ b/drivers/cdrom/cdu31a.c
@@ -3366,12 +3366,11 @@ int __init cdu31a_init(void)
goto errout2;
}
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk)
goto errout1;
disk->major = MAJOR_NR;
disk->first_minor = 0;
- disk->minor_shift = 0;
sprintf(disk->disk_name, "cdu31a");
disk->fops = &scd_bdops;
disk->flags = GENHD_FL_CD;
diff --git a/drivers/cdrom/cm206.c b/drivers/cdrom/cm206.c
index 0da8b3bcdf30..8a83a381bcc1 100644
--- a/drivers/cdrom/cm206.c
+++ b/drivers/cdrom/cm206.c
@@ -1470,12 +1470,11 @@ int __init cm206_init(void)
printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR);
goto out_blkdev;
}
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk)
goto out_disk;
disk->major = MAJOR_NR;
disk->first_minor = 0;
- disk->minor_shift = 0;
sprintf(disk->disk_name, "cm206");
disk->fops = &cm206_bdops;
disk->flags = GENHD_FL_CD;
diff --git a/drivers/cdrom/gscd.c b/drivers/cdrom/gscd.c
index 9e8a14ce9374..d82b99f5a4b5 100644
--- a/drivers/cdrom/gscd.c
+++ b/drivers/cdrom/gscd.c
@@ -972,12 +972,11 @@ static int __init gscd_init(void)
i++;
}
- gscd_disk = alloc_disk();
+ gscd_disk = alloc_disk(1);
if (!gscd_disk)
goto err_out1;
gscd_disk->major = MAJOR_NR;
gscd_disk->first_minor = 0;
- gscd_disk->minor_shift = 0;
gscd_disk->fops = &gscd_fops;
sprintf(gscd_disk->disk_name, "gscd");
diff --git a/drivers/cdrom/mcd.c b/drivers/cdrom/mcd.c
index 39eff9436cbf..e6c72eabda52 100644
--- a/drivers/cdrom/mcd.c
+++ b/drivers/cdrom/mcd.c
@@ -1031,7 +1031,7 @@ static void mcd_release(struct cdrom_device_info *cdi)
int __init mcd_init(void)
{
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
int count;
unsigned char result[3];
char msg[80];
@@ -1124,7 +1124,6 @@ int __init mcd_init(void)
disk->major = MAJOR_NR;
disk->first_minor = 0;
- disk->minor_shift = 0;
sprintf(disk->disk_name, "mcd");
disk->fops = &mcd_bdops;
disk->flags = GENHD_FL_CD;
diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c
index 7b6aaace0be1..9747c15b926b 100644
--- a/drivers/cdrom/mcdx.c
+++ b/drivers/cdrom/mcdx.c
@@ -1076,7 +1076,7 @@ int __init mcdx_init_drive(int drive)
return 1;
}
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk) {
xwarn("init() malloc failed\n");
kfree(stuffp);
@@ -1221,7 +1221,6 @@ int __init mcdx_init_drive(int drive)
stuffp->info.dev = mk_kdev(MAJOR_NR, drive);
disk->major = MAJOR_NR;
disk->first_minor = drive;
- disk->minor_shift = 0;
strcpy(disk->disk_name, stuffp->info.name);
disk->fops = &mcdx_bdops;
disk->flags = GENHD_FL_CD;
diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c
index baf39fd6f708..6abce539684e 100644
--- a/drivers/cdrom/optcd.c
+++ b/drivers/cdrom/optcd.c
@@ -2010,14 +2010,13 @@ static int __init optcd_init(void)
"optcd: no Optics Storage CDROM Initialization\n");
return -EIO;
}
- optcd_disk = alloc_disk();
+ optcd_disk = alloc_disk(1);
if (!optcd_disk) {
printk(KERN_ERR "optcd: can't allocate disk\n");
return -ENOMEM;
}
optcd_disk->major = MAJOR_NR;
optcd_disk->first_minor = 0;
- optcd_disk->minor_shift = 0;
optcd_disk->fops = &opt_fops;
sprintf(optcd_disk->disk_name, "optcd");
if (!request_region(optcd_port, 4, "optcd")) {
diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c
index 409aea0c4f0f..22a4ca708c6f 100644
--- a/drivers/cdrom/sbpcd.c
+++ b/drivers/cdrom/sbpcd.c
@@ -5831,10 +5831,9 @@ int __init sbpcd_init(void)
sbpcd_infop->dev = mk_kdev(MAJOR_NR, j);
sbpcd_infop->handle = p;
p->sbpcd_infop = sbpcd_infop;
- disk = alloc_disk();
+ disk = alloc_disk(1);
disk->major = MAJOR_NR;
disk->first_minor = j;
- disk->minor_shift = 0;
disk->fops = &sbpcd_bdops;
strcpy(disk->disk_name, sbpcd_infop->name);
disk->flags = GENHD_FL_CD;
diff --git a/drivers/cdrom/sjcd.c b/drivers/cdrom/sjcd.c
index c04647548625..9dcdda8741b0 100644
--- a/drivers/cdrom/sjcd.c
+++ b/drivers/cdrom/sjcd.c
@@ -1689,14 +1689,13 @@ static int __init sjcd_init(void)
blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), do_sjcd_request, &sjcd_lock);
blk_queue_hardsect_size(BLK_DEFAULT_QUEUE(MAJOR_NR), 2048);
- sjcd_disk = alloc_disk();
+ sjcd_disk = alloc_disk(1);
if (!sjcd_disk) {
printk(KERN_ERR "SJCD: can't allocate disk");
goto out1;
}
sjcd_disk->major = MAJOR_NR,
sjcd_disk->first_minor = 0,
- sjcd_disk->minor_shift = 0,
sjcd_disk->fops = &sjcd_fops,
sprintf(sjcd_disk->disk_name, "sjcd");
diff --git a/drivers/cdrom/sonycd535.c b/drivers/cdrom/sonycd535.c
index d73013c02bad..68e8103a7223 100644
--- a/drivers/cdrom/sonycd535.c
+++ b/drivers/cdrom/sonycd535.c
@@ -1605,12 +1605,11 @@ static int __init sony535_init(void)
}
initialized = 1;
- cdu_disk = alloc_disk();
+ cdu_disk = alloc_disk(1);
if (!cdu_disk)
goto out6;
cdu_disk->major = MAJOR_NR;
cdu_disk->first_minor = 0;
- cdu_disk->minor_shift = 0;
cdu_disk->fops = &cdu_fops;
sprintf(cdu_disk->disk_name, "cdu");
diff --git a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
index 012381dd73d9..8fffe423ab14 100644
--- a/drivers/ide/ide-cd.c
+++ b/drivers/ide/ide-cd.c
@@ -309,6 +309,8 @@
#include <linux/ide.h>
#include <linux/completion.h>
+#include <scsi/scsi.h> /* For SCSI -> ATAPI command conversion */
+
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/byteorder.h>
@@ -332,12 +334,12 @@ static void cdrom_saw_media_change (ide_drive_t *drive)
info->nsectors_buffered = 0;
}
-static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc,
+static int cdrom_log_sense(ide_drive_t *drive, struct request *rq,
struct request_sense *sense)
{
int log = 0;
- if (sense == NULL || pc == NULL || pc->quiet)
+ if (!sense || !rq || (rq->flags & REQ_QUIET))
return 0;
switch (sense->sense_key) {
@@ -370,10 +372,9 @@ static int cdrom_log_sense(ide_drive_t *drive, struct packet_command *pc,
static
void cdrom_analyze_sense_data(ide_drive_t *drive,
- struct packet_command *failed_command,
+ struct request *failed_command,
struct request_sense *sense)
{
-
if (!cdrom_log_sense(drive, failed_command, sense))
return;
@@ -382,7 +383,7 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
* the first toc has not been recorded yet, it will fail with
* 05/24/00 (which is a confusing error)
*/
- if (failed_command && failed_command->c[0] == GPCMD_READ_TOC_PMA_ATIP)
+ if (failed_command && failed_command->cmd[0] == GPCMD_READ_TOC_PMA_ATIP)
if (sense->sense_key == 0x05 && sense->asc == 0x24)
return;
@@ -453,20 +454,20 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
while (hi > lo) {
mid = (lo + hi) / 2;
if (packet_command_texts[mid].packet_command ==
- failed_command->c[0]) {
+ failed_command->cmd[0]) {
s = packet_command_texts[mid].text;
break;
}
if (packet_command_texts[mid].packet_command >
- failed_command->c[0])
+ failed_command->cmd[0])
hi = mid;
else
lo = mid+1;
}
printk (" The failed \"%s\" packet command was: \n \"", s);
- for (i=0; i<sizeof (failed_command->c); i++)
- printk ("%02x ", failed_command->c[i]);
+ for (i=0; i<sizeof (failed_command->cmd); i++)
+ printk ("%02x ", failed_command->cmd[i]);
printk ("\"\n");
}
@@ -512,30 +513,39 @@ void cdrom_analyze_sense_data(ide_drive_t *drive,
#endif /* not VERBOSE_IDE_CD_ERRORS */
}
+/*
+ * Initialize a ide-cd packet command request
+ */
+static void cdrom_prepare_request(struct request *rq)
+{
+ ide_init_drive_cmd(rq);
+ rq->flags = REQ_PC;
+}
+
static void cdrom_queue_request_sense(ide_drive_t *drive,
struct completion *wait,
- struct request_sense *sense,
- struct packet_command *failed_command)
+ void *sense,
+ struct request *failed_command)
{
struct cdrom_info *info = drive->driver_data;
- struct packet_command *pc = &info->request_sense_pc;
- struct request *rq;
+ struct request *rq = &info->request_sense_request;
if (sense == NULL)
sense = &info->sense_data;
- memset(pc, 0, sizeof(struct packet_command));
- pc->c[0] = GPCMD_REQUEST_SENSE;
- pc->c[4] = pc->buflen = 18;
- pc->buffer = (char *) sense;
- pc->sense = (struct request_sense *) failed_command;
-
/* stuff the sense request in front of our current request */
- rq = &info->request_sense_request;
- ide_init_drive_cmd(rq);
+ cdrom_prepare_request(rq);
+
+ rq->data = sense;
+ rq->cmd[0] = GPCMD_REQUEST_SENSE;
+ rq->cmd[4] = rq->data_len = 18;
+
rq->flags = REQ_SENSE;
- rq->buffer = (char *) pc;
rq->waiting = wait;
+
+ /* NOTE! Save the failed command in "rq->buffer" */
+ rq->buffer = (void *) failed_command;
+
(void) ide_do_drive_cmd(drive, rq, ide_preempt);
}
@@ -630,17 +640,26 @@ static void cdrom_end_request (ide_drive_t *drive, int uptodate)
struct request *rq = HWGROUP(drive)->rq;
if ((rq->flags & REQ_SENSE) && uptodate) {
- struct packet_command *pc = (struct packet_command *) rq->buffer;
- cdrom_analyze_sense_data(drive,
- (struct packet_command *) pc->sense,
- (struct request_sense *) (pc->buffer - pc->c[4]));
+ /* For REQ_SENSE, "rq->buffer" points to the original failed request */
+ struct request *failed = (struct request *) rq->buffer;
+ struct cdrom_info *info = drive->driver_data;
+ void * sense = &info->sense_data;
+
+ if (failed && failed->sense)
+ sense = failed->sense;
+
+ cdrom_analyze_sense_data(drive, failed, sense);
}
+
if (blk_fs_request(rq) && !rq->current_nr_sectors)
uptodate = 1;
ide_end_request(drive, uptodate, rq->hard_cur_sectors);
}
+/* Handle differences between SCSI and ATAPI packet commands */
+static int pre_transform_command(struct request *);
+static void post_transform_command(struct request *);
/* Returns 0 if the request should be continued.
Returns 1 if the request was ended. */
@@ -649,7 +668,6 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
{
struct request *rq = HWGROUP(drive)->rq;
int stat, err, sense_key;
- struct packet_command *pc;
/* Check for errors. */
*stat_ret = stat = HWIF(drive)->INB(IDE_STATUS_REG);
@@ -672,16 +690,18 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
from the drive (probably while trying
to recover from a former error). Just give up. */
- pc = (struct packet_command *) rq->buffer;
- pc->stat = 1;
- cdrom_end_request(drive, 1);
+ rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
*startstop = DRIVER(drive)->error(drive, "request sense failure", stat);
return 1;
} else if (rq->flags & (REQ_PC | REQ_BLOCK_PC)) {
/* All other functions, except for READ. */
struct completion *wait = NULL;
- pc = (struct packet_command *) rq->buffer;
+
+ /* Fix up any SCSI command differences.. */
+ if (rq->flags & REQ_BLOCK_PC)
+ post_transform_command(rq);
/* Check for tray open. */
if (sense_key == NOT_READY) {
@@ -691,7 +711,7 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
cdrom_saw_media_change (drive);
/*printk("%s: media changed\n",drive->name);*/
return 0;
- } else if (!pc->quiet) {
+ } else if (!(rq->flags & REQ_QUIET)) {
/* Otherwise, print an error. */
ide_dump_status(drive, "packet command error", stat);
}
@@ -710,11 +730,11 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
rq->waiting = NULL;
}
- pc->stat = 1;
- cdrom_end_request(drive, 1);
+ rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
if ((stat & ERR_STAT) != 0)
- cdrom_queue_request_sense(drive, wait, pc->sense, pc);
+ cdrom_queue_request_sense(drive, wait, rq->sense, rq);
} else if (blk_fs_request(rq)) {
/* Handle errors from READ and WRITE requests. */
@@ -770,7 +790,6 @@ static int cdrom_decode_status (ide_startstop_t *startstop, ide_drive_t *drive,
static int cdrom_timer_expiry(ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *) rq->buffer;
unsigned long wait = 0;
/*
@@ -779,7 +798,7 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
* this, but not all commands/drives support that. Let
* ide_timer_expiry keep polling us for these.
*/
- switch (pc->c[0]) {
+ switch (rq->cmd[0]) {
case GPCMD_BLANK:
case GPCMD_FORMAT_UNIT:
case GPCMD_RESERVE_RZONE_TRACK:
@@ -854,12 +873,12 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
* struct packet_command *pc; now packet_command_t *pc;
*/
static ide_startstop_t cdrom_transfer_packet_command (ide_drive_t *drive,
- struct packet_command *pc,
+ struct request *rq,
ide_handler_t *handler)
{
- unsigned char *cmd_buf = pc->c;
- int cmd_len = sizeof(pc->c);
- unsigned int timeout = pc->timeout;
+ unsigned char *cmd_buf = rq->cmd;
+ int cmd_len = sizeof(rq->cmd);
+ unsigned int timeout = rq->timeout;
struct cdrom_info *info = drive->driver_data;
ide_startstop_t startstop;
@@ -1029,6 +1048,7 @@ static ide_startstop_t cdrom_read_intr (ide_drive_t *drive)
if (rq->current_nr_sectors > 0) {
printk ("%s: cdrom_read_intr: data underrun (%d blocks)\n",
drive->name, rq->current_nr_sectors);
+ rq->flags |= REQ_FAILED;
cdrom_end_request(drive, 0);
} else
cdrom_end_request(drive, 1);
@@ -1179,7 +1199,6 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
*/
static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
{
- struct packet_command pc;
struct request *rq = HWGROUP(drive)->rq;
int nsect, sector, nframes, frame, nskip;
@@ -1222,11 +1241,10 @@ static ide_startstop_t cdrom_start_read_continuation (ide_drive_t *drive)
(65534 / CD_FRAMESIZE) : 65535);
/* Set up the command */
- memcpy(pc.c, rq->cmd, sizeof(pc.c));
- pc.timeout = WAIT_CMD;
+ rq->timeout = WAIT_CMD;
/* Send the command to the drive and return. */
- return cdrom_transfer_packet_command(drive, &pc, &cdrom_read_intr);
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_read_intr);
}
@@ -1262,7 +1280,6 @@ static ide_startstop_t cdrom_seek_intr (ide_drive_t *drive)
static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
{
- struct packet_command pc;
struct request *rq = HWGROUP(drive)->rq;
int sector, frame, nskip;
@@ -1273,11 +1290,11 @@ static ide_startstop_t cdrom_start_seek_continuation (ide_drive_t *drive)
frame = sector / SECTORS_PER_FRAME;
memset(rq->cmd, 0, sizeof(rq->cmd));
- pc.c[0] = GPCMD_SEEK;
- put_unaligned(cpu_to_be32(frame), (unsigned int *) &pc.c[2]);
+ rq->cmd[0] = GPCMD_SEEK;
+ put_unaligned(cpu_to_be32(frame), (unsigned int *) &rq->cmd[2]);
- pc.timeout = WAIT_CMD;
- return cdrom_transfer_packet_command(drive, &pc, &cdrom_seek_intr);
+ rq->timeout = WAIT_CMD;
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_seek_intr);
}
static ide_startstop_t cdrom_start_seek (ide_drive_t *drive, unsigned int block)
@@ -1296,6 +1313,7 @@ static void restore_request (struct request *rq)
{
if (rq->buffer != bio_data(rq->bio)) {
sector_t n = (rq->buffer - (char *) bio_data(rq->bio)) / SECTOR_SIZE;
+
rq->buffer = bio_data(rq->bio);
rq->nr_sectors += n;
rq->sector -= n;
@@ -1352,7 +1370,6 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
{
int ireason, len, stat, thislen;
struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
ide_startstop_t startstop;
u8 lowcyl = 0, highcyl = 0;
@@ -1372,16 +1389,16 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
if ((stat & DRQ_STAT) == 0) {
/* Some of the trailing request sense fields are optional, and
some drives don't send them. Sigh. */
- if (pc->c[0] == GPCMD_REQUEST_SENSE &&
- pc->buflen > 0 &&
- pc->buflen <= 5) {
- while (pc->buflen > 0) {
- *pc->buffer++ = 0;
- --pc->buflen;
+ if (rq->cmd[0] == GPCMD_REQUEST_SENSE &&
+ rq->data_len > 0 &&
+ rq->data_len <= 5) {
+ while (rq->data_len > 0) {
+ *(unsigned char *)rq->data++ = 0;
+ --rq->data_len;
}
}
- if (pc->buflen == 0)
+ if (rq->data_len == 0)
cdrom_end_request(drive, 1);
else {
/* Comment this out, because this always happens
@@ -1391,20 +1408,22 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
printk ("%s: cdrom_pc_intr: data underrun %d\n",
drive->name, pc->buflen);
*/
- pc->stat = 1;
- cdrom_end_request(drive, 1);
+ rq->flags |= REQ_FAILED;
+ cdrom_end_request(drive, 0);
}
return ide_stopped;
}
/* Figure out how much data to transfer. */
- thislen = pc->buflen;
+ thislen = rq->data_len;
if (thislen > len) thislen = len;
/* The drive wants to be written to. */
if ((ireason & 3) == 0) {
+ if (!rq->data)
+ goto confused;
/* Transfer the data. */
- HWIF(drive)->atapi_output_bytes(drive, pc->buffer, thislen);
+ HWIF(drive)->atapi_output_bytes(drive, rq->data, thislen);
/* If we haven't moved enough data to satisfy the drive,
add some padding. */
@@ -1415,15 +1434,16 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
}
/* Keep count of how much data we've moved. */
- pc->buffer += thislen;
- pc->buflen -= thislen;
+ rq->data += thislen;
+ rq->data_len -= thislen;
}
/* Same drill for reading. */
else if ((ireason & 3) == 2) {
-
+ if (!rq->data)
+ goto confused;
/* Transfer the data. */
- HWIF(drive)->atapi_input_bytes(drive, pc->buffer, thislen);
+ HWIF(drive)->atapi_input_bytes(drive, rq->data, thislen);
/* If we haven't moved enough data to satisfy the drive,
add some padding. */
@@ -1434,13 +1454,14 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
}
/* Keep count of how much data we've moved. */
- pc->buffer += thislen;
- pc->buflen -= thislen;
+ rq->data += thislen;
+ rq->data_len -= thislen;
} else {
+confused:
printk ("%s: cdrom_pc_intr: The drive "
"appears confused (ireason = 0x%2x)\n",
drive->name, ireason);
- pc->stat = 1;
+ rq->flags |= REQ_FAILED;
}
if (HWGROUP(drive)->handler != NULL)
@@ -1455,13 +1476,12 @@ static ide_startstop_t cdrom_pc_intr (ide_drive_t *drive)
static ide_startstop_t cdrom_do_pc_continuation (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
- if (!pc->timeout)
- pc->timeout = WAIT_CMD;
+ if (!rq->timeout)
+ rq->timeout = WAIT_CMD;
/* Send the command to the drive and return. */
- return cdrom_transfer_packet_command(drive, pc, &cdrom_pc_intr);
+ return cdrom_transfer_packet_command(drive, rq, &cdrom_pc_intr);
}
@@ -1469,13 +1489,12 @@ static ide_startstop_t cdrom_do_packet_command (ide_drive_t *drive)
{
int len;
struct request *rq = HWGROUP(drive)->rq;
- struct packet_command *pc = (struct packet_command *)rq->buffer;
struct cdrom_info *info = drive->driver_data;
info->dma = 0;
info->cmd = 0;
- pc->stat = 0;
- len = pc->buflen;
+ rq->flags &= ~REQ_FAILED;
+ len = rq->data_len;
/* Start sending the command to the drive. */
return cdrom_start_packet_command(drive, len, cdrom_do_pc_continuation);
@@ -1496,28 +1515,31 @@ void cdrom_sleep (int time)
}
static
-int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
+int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq)
{
struct request_sense sense;
- struct request req;
int retries = 10;
+ unsigned int flags = rq->flags;
- if (pc->sense == NULL)
- pc->sense = &sense;
+ if (rq->sense == NULL)
+ rq->sense = &sense;
/* Start of retry loop. */
do {
- ide_init_drive_cmd (&req);
- req.flags = REQ_PC;
- req.buffer = (char *)pc;
- ide_do_drive_cmd(drive, &req, ide_wait);
+ int error;
+ unsigned long time = jiffies;
+ rq->flags = flags;
+
+ error = ide_do_drive_cmd(drive, rq, ide_wait);
+ time = jiffies - time;
+
/* FIXME: we should probably abort/retry or something
* in case of failure */
- if (pc->stat != 0) {
+ if (rq->flags & REQ_FAILED) {
/* The request failed. Retry if it was due to a unit
attention status
(usually means media was changed). */
- struct request_sense *reqbuf = pc->sense;
+ struct request_sense *reqbuf = rq->sense;
if (reqbuf->sense_key == UNIT_ATTENTION)
cdrom_saw_media_change(drive);
@@ -1535,10 +1557,10 @@ int cdrom_queue_packet_command(ide_drive_t *drive, struct packet_command *pc)
}
/* End of retry loop. */
- } while (pc->stat != 0 && retries >= 0);
+ } while ((rq->flags & REQ_FAILED) && retries >= 0);
/* Return an error if the command failed. */
- return pc->stat ? -EIO : 0;
+ return (rq->flags & REQ_FAILED) ? -EIO : 0;
}
/*
@@ -1681,20 +1703,18 @@ static ide_startstop_t cdrom_write_intr(ide_drive_t *drive)
static ide_startstop_t cdrom_start_write_cont(ide_drive_t *drive)
{
- struct packet_command pc; /* packet_command_t pc; */
struct request *rq = HWGROUP(drive)->rq;
unsigned nframes, frame;
nframes = rq->nr_sectors >> 2;
frame = rq->sector >> 2;
- memcpy(pc.c, rq->cmd, sizeof(pc.c));
#if 0 /* the immediate bit */
- pc.c[1] = 1 << 3;
+ rq->cmd[1] = 1 << 3;
#endif
- pc.timeout = 2 * WAIT_CMD;
+ rq->timeout = 2 * WAIT_CMD;
- return cdrom_transfer_packet_command(drive, &pc, cdrom_write_intr);
+ return cdrom_transfer_packet_command(drive, rq, cdrom_write_intr);
}
static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
@@ -1728,20 +1748,54 @@ static ide_startstop_t cdrom_start_write(ide_drive_t *drive, struct request *rq)
return cdrom_start_packet_command(drive, 32768, cdrom_start_write_cont);
}
+/*
+ * Most of the SCSI commands are supported directly by ATAPI devices.
+ * This transform handles the few exceptions.
+ */
+static int pre_transform_command(struct request *req)
+{
+ u8 *c = req->cmd;
+ /* Transform 6-byte read/write commands to the 10-byte version. */
+ if (c[0] == READ_6 || c[0] == WRITE_6) {
+ c[8] = c[4];
+ c[5] = c[3];
+ c[4] = c[2];
+ c[3] = c[1] & 0x1f;
+ c[2] = 0;
+ c[1] &= 0xe0;
+ c[0] += (READ_10 - READ_6);
+ return 0;
+ }
+
+ /* These also need fixup, not done yet */
+ if (c[0] == MODE_SENSE || c[0] == MODE_SELECT)
+ return -EINVAL;
+
+ return 0;
+}
+
+static void post_transform_command(struct request *req)
+{
+}
+
static ide_startstop_t cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
{
- struct packet_command pc;
ide_startstop_t startstop;
+ struct cdrom_info *info;
- memset(&pc, 0, sizeof(pc));
- memcpy(pc.c, rq->cmd, sizeof(pc.c));
- pc.quiet = 1;
- pc.timeout = 60 * HZ;
- rq->buffer = (char *) &pc;
+ if (pre_transform_command(rq) < 0) {
+ cdrom_end_request(drive, 0);
+ return ide_stopped;
+ }
+
+ rq->flags |= REQ_QUIET;
- startstop = cdrom_do_packet_command(drive);
- if (pc.stat)
- rq->errors++;
+ info = drive->driver_data;
+ info->dma = 0;
+ info->cmd = 0;
+
+ /* Start sending the command to the drive. */
+ startstop = cdrom_start_packet_command(drive, rq->data_len, cdrom_do_pc_continuation);
return startstop;
}
@@ -1757,11 +1811,11 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
if (blk_fs_request(rq)) {
if (CDROM_CONFIG_FLAGS(drive)->seeking) {
- unsigned long elpased = jiffies - info->start_seek;
+ unsigned long elapsed = jiffies - info->start_seek;
int stat = HWIF(drive)->INB(IDE_STATUS_REG);
if ((stat & SEEK_STAT) != SEEK_STAT) {
- if (elpased < IDECD_SEEK_TIMEOUT) {
+ if (elapsed < IDECD_SEEK_TIMEOUT) {
ide_stall_queue(drive, IDECD_SEEK_TIMER);
return ide_stopped;
}
@@ -1781,14 +1835,14 @@ ide_do_rw_cdrom (ide_drive_t *drive, struct request *rq, sector_t block)
return action;
} else if (rq->flags & (REQ_PC | REQ_SENSE)) {
return cdrom_do_packet_command(drive);
+ } else if (rq->flags & REQ_BLOCK_PC) {
+ return cdrom_do_block_pc(drive, rq);
} else if (rq->flags & REQ_SPECIAL) {
/*
* right now this can only be a reset...
*/
cdrom_end_request(drive, 1);
return ide_stopped;
- } else if (rq->flags & REQ_BLOCK_PC) {
- return cdrom_do_block_pc(drive, rq);
}
blk_dump_rq_flags(rq, "ide-cd bad flags");
@@ -1853,23 +1907,23 @@ int msf_to_lba (byte m, byte s, byte f)
static int cdrom_check_status(ide_drive_t *drive, struct request_sense *sense)
{
- struct packet_command pc;
+ struct request req;
struct cdrom_info *info = drive->driver_data;
struct cdrom_device_info *cdi = &info->devinfo;
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
+ cdrom_prepare_request(&req);
- pc.c[0] = GPCMD_TEST_UNIT_READY;
+ req.sense = sense;
+ req.cmd[0] = GPCMD_TEST_UNIT_READY;
#if ! STANDARD_ATAPI
/* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to
switch CDs instead of supporting the LOAD_UNLOAD opcode */
- pc.c[7] = cdi->sanyo_slot % 3;
+ req.cmd[7] = cdi->sanyo_slot % 3;
#endif /* not STANDARD_ATAPI */
- return cdrom_queue_packet_command(drive, &pc);
+ return cdrom_queue_packet_command(drive, &req);
}
@@ -1878,7 +1932,7 @@ static int
cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
{
struct request_sense my_sense;
- struct packet_command pc;
+ struct request req;
int stat;
if (sense == NULL)
@@ -1888,11 +1942,11 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
if (CDROM_CONFIG_FLAGS(drive)->no_doorlock) {
stat = 0;
} else {
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
- pc.c[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
- pc.c[4] = lockflag ? 1 : 0;
- stat = cdrom_queue_packet_command(drive, &pc);
+ cdrom_prepare_request(&req);
+ req.sense = sense;
+ req.cmd[0] = GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL;
+ req.cmd[4] = lockflag ? 1 : 0;
+ stat = cdrom_queue_packet_command(drive, &req);
}
/* If we got an illegal field error, the drive
@@ -1922,7 +1976,7 @@ cdrom_lockdoor(ide_drive_t *drive, int lockflag, struct request_sense *sense)
static int cdrom_eject(ide_drive_t *drive, int ejectflag,
struct request_sense *sense)
{
- struct packet_command pc;
+ struct request req;
if (CDROM_CONFIG_FLAGS(drive)->no_eject && !ejectflag)
return -EDRIVE_CANT_DO_THIS;
@@ -1931,12 +1985,12 @@ static int cdrom_eject(ide_drive_t *drive, int ejectflag,
if (CDROM_STATE_FLAGS(drive)->door_locked && ejectflag)
return 0;
- memset(&pc, 0, sizeof (pc));
- pc.sense = sense;
+ cdrom_prepare_request(&req);
- pc.c[0] = GPCMD_START_STOP_UNIT;
- pc.c[4] = 0x02 + (ejectflag != 0);
- return cdrom_queue_packet_command(drive, &pc);
+ req.sense = sense;
+ req.cmd[0] = GPCMD_START_STOP_UNIT;
+ req.cmd[4] = 0x02 + (ejectflag != 0);
+ return cdrom_queue_packet_command(drive, &req);
}
static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
@@ -1948,16 +2002,16 @@ static int cdrom_read_capacity(ide_drive_t *drive, unsigned long *capacity,
} capbuf;
int stat;
- struct packet_command pc;
+ struct request req;
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
+ cdrom_prepare_request(&req);
- pc.c[0] = GPCMD_READ_CDVD_CAPACITY;
- pc.buffer = (char *)&capbuf;
- pc.buflen = sizeof(capbuf);
+ req.sense = sense;
+ req.cmd[0] = GPCMD_READ_CDVD_CAPACITY;
+ req.data = (char *)&capbuf;
+ req.data_len = sizeof(capbuf);
- stat = cdrom_queue_packet_command(drive, &pc);
+ stat = cdrom_queue_packet_command(drive, &req);
if (stat == 0)
*capacity = 1 + be32_to_cpu(capbuf.lba);
@@ -1968,24 +2022,24 @@ static int cdrom_read_tocentry(ide_drive_t *drive, int trackno, int msf_flag,
int format, char *buf, int buflen,
struct request_sense *sense)
{
- struct packet_command pc;
+ struct request req;
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
+ cdrom_prepare_request(&req);
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.quiet = 1;
- pc.c[0] = GPCMD_READ_TOC_PMA_ATIP;
- pc.c[6] = trackno;
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- pc.c[9] = (format << 6);
+ req.sense = sense;
+ req.data = buf;
+ req.data_len = buflen;
+ req.flags |= REQ_QUIET;
+ req.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+ req.cmd[6] = trackno;
+ req.cmd[7] = (buflen >> 8);
+ req.cmd[8] = (buflen & 0xff);
+ req.cmd[9] = (format << 6);
if (msf_flag)
- pc.c[1] = 2;
+ req.cmd[1] = 2;
- return cdrom_queue_packet_command(drive, &pc);
+ return cdrom_queue_packet_command(drive, &req);
}
@@ -2144,20 +2198,20 @@ static int cdrom_read_toc(ide_drive_t *drive, struct request_sense *sense)
static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
int buflen, struct request_sense *sense)
{
- struct packet_command pc;
+ struct request req;
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
+ cdrom_prepare_request(&req);
- pc.buffer = buf;
- pc.buflen = buflen;
- pc.c[0] = GPCMD_READ_SUBCHANNEL;
- pc.c[1] = 2; /* MSF addressing */
- pc.c[2] = 0x40; /* request subQ data */
- pc.c[3] = format;
- pc.c[7] = (buflen >> 8);
- pc.c[8] = (buflen & 0xff);
- return cdrom_queue_packet_command(drive, &pc);
+ req.sense = sense;
+ req.data = buf;
+ req.data_len = buflen;
+ req.cmd[0] = GPCMD_READ_SUBCHANNEL;
+ req.cmd[1] = 2; /* MSF addressing */
+ req.cmd[2] = 0x40; /* request subQ data */
+ req.cmd[3] = format;
+ req.cmd[7] = (buflen >> 8);
+ req.cmd[8] = (buflen & 0xff);
+ return cdrom_queue_packet_command(drive, &req);
}
/* ATAPI cdrom drives are free to select the speed you request or any slower
@@ -2165,45 +2219,45 @@ static int cdrom_read_subchannel(ide_drive_t *drive, int format, char *buf,
static int cdrom_select_speed(ide_drive_t *drive, int speed,
struct request_sense *sense)
{
- struct packet_command pc;
- memset(&pc, 0, sizeof(pc));
- pc.sense = sense;
+ struct request req;
+ cdrom_prepare_request(&req);
+ req.sense = sense;
if (speed == 0)
speed = 0xffff; /* set to max */
else
speed *= 177; /* Nx to kbytes/s */
- pc.c[0] = GPCMD_SET_SPEED;
+ req.cmd[0] = GPCMD_SET_SPEED;
/* Read Drive speed in kbytes/second MSB */
- pc.c[2] = (speed >> 8) & 0xff;
+ req.cmd[2] = (speed >> 8) & 0xff;
/* Read Drive speed in kbytes/second LSB */
- pc.c[3] = speed & 0xff;
+ req.cmd[3] = speed & 0xff;
if (CDROM_CONFIG_FLAGS(drive)->cd_r ||
CDROM_CONFIG_FLAGS(drive)->cd_rw ||
CDROM_CONFIG_FLAGS(drive)->dvd_r) {
/* Write Drive speed in kbytes/second MSB */
- pc.c[4] = (speed >> 8) & 0xff;
+ req.cmd[4] = (speed >> 8) & 0xff;
/* Write Drive speed in kbytes/second LSB */
- pc.c[5] = speed & 0xff;
+ req.cmd[5] = speed & 0xff;
}
- return cdrom_queue_packet_command(drive, &pc);
+ return cdrom_queue_packet_command(drive, &req);
}
static int cdrom_play_audio(ide_drive_t *drive, int lba_start, int lba_end)
{
struct request_sense sense;
- struct packet_command pc;
+ struct request req;
- memset(&pc, 0, sizeof (pc));
- pc.sense = &sense;
+ cdrom_prepare_request(&req);
- pc.c[0] = GPCMD_PLAY_AUDIO_MSF;
- lba_to_msf(lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
- lba_to_msf(lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
+ req.sense = &sense;
+ req.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+ lba_to_msf(lba_start, &req.cmd[3], &req.cmd[4], &req.cmd[5]);
+ lba_to_msf(lba_end-1, &req.cmd[6], &req.cmd[7], &req.cmd[8]);
- return cdrom_queue_packet_command(drive, &pc);
+ return cdrom_queue_packet_command(drive, &req);
}
static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
@@ -2237,7 +2291,7 @@ static int cdrom_get_toc_entry(ide_drive_t *drive, int track,
static int ide_cdrom_packet(struct cdrom_device_info *cdi,
struct cdrom_generic_command *cgc)
{
- struct packet_command pc;
+ struct request req;
ide_drive_t *drive = (ide_drive_t*) cdi->handle;
if (cgc->timeout <= 0)
@@ -2246,18 +2300,21 @@ static int ide_cdrom_packet(struct cdrom_device_info *cdi,
/* here we queue the commands from the uniform CD-ROM
layer. the packet must be complete, as we do not
touch it at all. */
- memset(&pc, 0, sizeof(pc));
- memcpy(pc.c, cgc->cmd, CDROM_PACKET_SIZE);
+ cdrom_prepare_request(&req);
+ memcpy(req.cmd, cgc->cmd, CDROM_PACKET_SIZE);
if (cgc->sense)
memset(cgc->sense, 0, sizeof(struct request_sense));
- pc.buffer = cgc->buffer;
- pc.buflen = cgc->buflen;
- pc.quiet = cgc->quiet;
- pc.timeout = cgc->timeout;
- pc.sense = cgc->sense;
- cgc->stat = cdrom_queue_packet_command(drive, &pc);
+ req.data = cgc->buffer;
+ req.data_len = cgc->buflen;
+ req.timeout = cgc->timeout;
+
+ if (cgc->quiet)
+ req.flags |= REQ_QUIET;
+
+ req.sense = cgc->sense;
+ cgc->stat = cdrom_queue_packet_command(drive, &req);
if (!cgc->stat)
- cgc->buflen -= pc.buflen;
+ cgc->buflen -= req.data_len;
return cgc->stat;
}
@@ -2393,7 +2450,7 @@ int ide_cdrom_reset (struct cdrom_device_info *cdi)
struct request req;
int ret;
- ide_init_drive_cmd (&req);
+ cdrom_prepare_request(&req);
req.flags = REQ_SPECIAL;
ret = ide_do_drive_cmd(drive, &req, ide_wait);
@@ -2969,6 +3026,14 @@ int ide_cdrom_ioctl (ide_drive_t *drive,
struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
+ int error;
+
+ /* Try the generic SCSI command ioctl's first.. */
+ error = scsi_cmd_ioctl(inode->i_bdev, cmd, arg);
+ if (error != -ENOTTY)
+ return error;
+
+ /* Then the generic cdrom ioctl's.. */
return cdrom_ioctl(inode, file, cmd, arg);
}
@@ -3128,8 +3193,10 @@ static int ide_cdrom_attach (ide_drive_t *drive)
memset(info, 0, sizeof (struct cdrom_info));
drive->driver_data = info;
DRIVER(drive)->busy++;
+ g->minors = 1;
g->minor_shift = 0;
g->de = drive->de;
+ g->driverfs_dev = &drive->gendev;
g->flags = GENHD_FL_CD;
if (ide_cdrom_setup(drive)) {
struct cdrom_device_info *devinfo = &info->devinfo;
diff --git a/drivers/ide/ide-cd.h b/drivers/ide/ide-cd.h
index 2455e002bfad..1126c6824bef 100644
--- a/drivers/ide/ide-cd.h
+++ b/drivers/ide/ide-cd.h
@@ -105,13 +105,6 @@ struct ide_cd_state_flags {
#define CDROM_STATE_FLAGS(drive) (&(((struct cdrom_info *)(drive->driver_data))->state_flags))
struct packet_command {
- char *buffer;
- int buflen;
- int stat;
- int quiet;
- int timeout;
- struct request_sense *sense;
- unsigned char c[12];
};
/* Structure of a MSF cdrom address. */
diff --git a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
index 5ff3daf64280..aecd9a7de7ed 100644
--- a/drivers/ide/ide-disk.c
+++ b/drivers/ide/ide-disk.c
@@ -1871,8 +1871,10 @@ static int idedisk_attach(ide_drive_t *drive)
goto failed;
}
DRIVER(drive)->busy--;
+ g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
g->de = drive->de;
+ g->driverfs_dev = &drive->gendev;
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
g->flags |= GENHD_FL_DEVFS;
set_capacity(g, current_capacity(drive));
diff --git a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c
index 60e3aed69166..f10543ba3d8f 100644
--- a/drivers/ide/ide-floppy.c
+++ b/drivers/ide/ide-floppy.c
@@ -2108,7 +2108,9 @@ static int idefloppy_attach (ide_drive_t *drive)
DRIVER(drive)->busy++;
idefloppy_setup (drive, floppy);
DRIVER(drive)->busy--;
+ g->minors = 1 << PARTN_BITS;
g->minor_shift = PARTN_BITS;
+ g->driverfs_dev = &drive->gendev;
g->de = drive->de;
g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;
g->flags |= GENHD_FL_DEVFS;
diff --git a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
index 6277ce3cb1e0..478bffc6aed8 100644
--- a/drivers/ide/ide-probe.c
+++ b/drivers/ide/ide-probe.c
@@ -986,7 +986,7 @@ static void init_gendisk (ide_hwif_t *hwif)
units = MAX_DRIVES;
for (unit = 0; unit < MAX_DRIVES; unit++) {
- disks[unit] = alloc_disk();
+ disks[unit] = alloc_disk(1 << PARTN_BITS);
if (!disks[unit])
goto err_kmalloc_gd;
}
@@ -996,7 +996,6 @@ static void init_gendisk (ide_hwif_t *hwif)
disk->major = hwif->major;
disk->first_minor = unit << PARTN_BITS;
sprintf(disk->disk_name,"hd%c",'a'+hwif->index*MAX_DRIVES+unit);
- disk->minor_shift = PARTN_BITS;
disk->fops = ide_fops;
hwif->drives[unit].disk = disk;
}
diff --git a/drivers/ide/ide.c b/drivers/ide/ide.c
index e2380bcb9fe8..00830680bb42 100644
--- a/drivers/ide/ide.c
+++ b/drivers/ide/ide.c
@@ -2639,7 +2639,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
case CDROMEJECT:
case CDROMCLOSETRAY:
- return block_ioctl(inode->i_bdev, cmd, arg);
+ return scsi_cmd_ioctl(inode->i_bdev, cmd, arg);
case HDIO_GET_BUSSTATE:
if (!capable(CAP_SYS_ADMIN))
diff --git a/drivers/ide/legacy/hd.c b/drivers/ide/legacy/hd.c
index b0f5f104876d..66ed54f354f7 100644
--- a/drivers/ide/legacy/hd.c
+++ b/drivers/ide/legacy/hd.c
@@ -677,21 +677,11 @@ static int hd_ioctl(struct inode * inode, struct file * file,
}
}
-static int hd_open(struct inode * inode, struct file * filp)
-{
- int target = DEVICE_NR(inode->i_rdev);
- if (target >= NR_HD)
- return -ENODEV;
- return 0;
-}
-
/*
* Releasing a block device means we sync() it, so that it can safely
* be forgotten about...
*/
-extern struct block_device_operations hd_fops;
-
static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
void (*handler)(void) = do_hd;
@@ -705,7 +695,6 @@ static void hd_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
static struct block_device_operations hd_fops = {
- .open = hd_open,
.ioctl = hd_ioctl,
};
@@ -802,12 +791,11 @@ static int __init hd_init(void)
goto out;
for (drive=0 ; drive < NR_HD ; drive++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(64);
if (!disk)
goto Enomem;
disk->major = MAJOR_NR;
disk->first_minor = drive << 6;
- disk->minor_shift = 6;
disk->fops = &hd_fops;
sprintf(disk->disk_name, "hd%c", 'a'+drive);
hd_gendisk[drive] = disk;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index a40c6af55da5..784e3b69213e 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1394,12 +1394,11 @@ static int do_md_run(mddev_t * mddev)
#endif
}
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk)
return -ENOMEM;
disk->major = MD_MAJOR;
disk->first_minor = mdidx(mddev);
- disk->minor_shift = 0;
sprintf(disk->disk_name, "md%d", mdidx(mddev));
disk->fops = &md_fops;
@@ -2732,18 +2731,9 @@ int unregister_md_personality(int pnum)
return 0;
}
-static unsigned int sync_io[DK_MAX_MAJOR][DK_MAX_DISK];
void md_sync_acct(mdk_rdev_t *rdev, unsigned long nr_sectors)
{
- kdev_t dev = to_kdev_t(rdev->bdev->bd_dev);
- unsigned int major = major(dev);
- unsigned int index;
-
- index = disk_index(dev);
- if ((index >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
- return;
-
- sync_io[major][index] += nr_sectors;
+ rdev->bdev->bd_disk->sync_io += nr_sectors;
}
static int is_mddev_idle(mddev_t *mddev)
@@ -2755,16 +2745,8 @@ static int is_mddev_idle(mddev_t *mddev)
idle = 1;
ITERATE_RDEV(mddev,rdev,tmp) {
- kdev_t dev = to_kdev_t(rdev->bdev->bd_dev);
- int major = major(dev);
- int idx = disk_index(dev);
-
- if ((idx >= DK_MAX_DISK) || (major >= DK_MAX_MAJOR))
- continue;
-
- curr_events = kstat.dk_drive_rblk[major][idx] +
- kstat.dk_drive_wblk[major][idx] ;
- curr_events -= sync_io[major][idx];
+ struct gendisk *disk = rdev->bdev->bd_disk;
+ curr_events = disk->reads + disk->writes - disk->sync_io;
if ((curr_events - rdev->last_events) > 32) {
rdev->last_events = curr_events;
idle = 0;
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index 99a221c8ccda..761aed5551c8 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -162,6 +162,29 @@ static int create_strip_zones (mddev_t *mddev)
return 1;
}
+/**
+ * raid0_mergeable_bvec -- tell bio layer if a two requests can be merged
+ * @q: request queue
+ * @bio: the buffer head that's been built up so far
+ * @biovec: the request that could be merged to it.
+ *
+ * Return 1 if the merge is not permitted (because the
+ * result would cross a chunk boundary), 0 otherwise.
+ */
+static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec)
+{
+ mddev_t *mddev = q->queuedata;
+ sector_t block;
+ unsigned int chunk_size;
+ unsigned int bio_sz;
+
+ chunk_size = mddev->chunk_size >> 10;
+ block = bio->bi_sector >> 1;
+ bio_sz = (bio->bi_size + biovec->bv_len) >> 10;
+
+ return chunk_size < ((block & (chunk_size - 1)) + bio_sz);
+}
+
static int raid0_run (mddev_t *mddev)
{
unsigned cur=0, i=0, nb_zone;
@@ -233,6 +256,8 @@ static int raid0_run (mddev_t *mddev)
conf->hash_table[i++].zone1 = conf->strip_zone + cur;
size -= (conf->smallest->size - zone0_size);
}
+ blk_queue_max_sectors(&mddev->queue, mddev->chunk_size >> 9);
+ blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec);
return 0;
out_free_zone_conf:
@@ -262,13 +287,6 @@ static int raid0_stop (mddev_t *mddev)
return 0;
}
-/*
- * FIXME - We assume some things here :
- * - requested buffers NEVER bigger than chunk size,
- * - requested buffers NEVER cross stripes limits.
- * Of course, those facts may not be valid anymore (and surely won't...)
- * Hey guys, there's some work out there ;-)
- */
static int raid0_make_request (request_queue_t *q, struct bio *bio)
{
mddev_t *mddev = q->queuedata;
@@ -286,13 +304,16 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
{
+#if __GNUC__ < 3
+ volatile
+#endif
sector_t x = block;
sector_div(x, (unsigned long)conf->smallest->size);
hash = conf->hash_table + x;
}
- /* Sanity check */
- if (chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))
+ /* Sanity check -- queue functions should prevent this happening */
+ if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10)))
goto bad_map;
if (!hash)
diff --git a/drivers/media/video/bttv-driver.c b/drivers/media/video/bttv-driver.c
index 4b87c907f425..8eee8bc1e804 100644
--- a/drivers/media/video/bttv-driver.c
+++ b/drivers/media/video/bttv-driver.c
@@ -31,6 +31,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <linux/kdev_t.h>
#include <asm/io.h>
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
index 0980a0b775c6..b6f8af6193f1 100644
--- a/drivers/message/i2o/i2o_block.c
+++ b/drivers/message/i2o/i2o_block.c
@@ -1647,7 +1647,7 @@ static int i2o_block_init(void)
}
for (i = 0; i < MAX_I2OB; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(16);
if (!disk)
goto oom;
i2o_disk[i] = disk;
@@ -1679,7 +1679,6 @@ static int i2o_block_init(void)
struct gendisk *disk = i2ob_disk + i;
disk->major = MAJOR_NR;
disk->first_minor = i<<4;
- disk->minor_shift = 4;
disk->fops = &i2ob_fops;
sprintf(disk->disk_name, "i2o/hd%c", 'a' + i);
}
diff --git a/drivers/mtd/Config.help b/drivers/mtd/Config.help
index 822dc7424d34..83e9b5c7d44b 100644
--- a/drivers/mtd/Config.help
+++ b/drivers/mtd/Config.help
@@ -21,36 +21,62 @@ CONFIG_MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
+CONFIG_MTD_CONCAT
+ Support for concatenating several MTD devices into a single
+ (virtual) one. This allows you to have -for example- a JFFS(2)
+ file system spanning multiple physical flash chips. If unsure,
+ say 'Y'.
+
CONFIG_MTD_REDBOOT_PARTS
RedBoot is a ROM monitor and bootloader which deals with multiple
- 'images' in flash devices by putting a table in the last erase block
- of the device, similar to a partition table, which gives the
- offsets, lengths and names of all the images stored in the flash.
+ 'images' in flash devices by putting a table in the last erase
+ block of the device, similar to a partition table, which gives
+ the offsets, lengths and names of all the images stored in the
+ flash.
If you need code which can detect and parse this table, and register
MTD 'partitions' corresponding to each image in the table, enable
- this option.
+ this option.
You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically. The
- SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
+ for your particular device. It won't happen automatically. The
+ SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
-CONFIG_MTD_BOOTLDR_PARTS
- The Compaq bootldr deals with multiple 'images' in flash devices
- by putting a table in one of the first erase blocks of the device,
- similar to a partition table, which gives the offsets, lengths and
- names of all the images stored in the flash.
-
- If you need code which can detect and parse this table, and register
- MTD 'partitions' corresponding to each image in the table, enable
- this option.
-
+CONFIG_MTD_CMDLINE_PARTS
+ Allow generic configuration of the MTD paritition tables via the kernel
+ command line. Multiple flash resources are supported for hardware where
+ different kinds of flash memory are available.
+
You will still need the parsing functions to be called by the driver
for your particular device. It won't happen automatically. The
SA1100 map driver (CONFIG_MTD_SA1100) has an option for this, for
example.
+ The format for the command line is as follows:
+
+ mtdparts=<mtddef>[;<mtddef]
+ <mtddef> := <mtd-id>:<partdef>[,<partdef>]
+ <partdef> := <size>[@offset][<name>][ro]
+ <mtd-id> := unique id used in mapping driver/device
+ <size> := standard linux memsize OR "-" to denote all
+ remaining space
+ <name> := (NAME)
+
+ Due to the way Linux handles the command line, no spaces are
+ allowed in the partition definition, including mtd id's and partition
+ names.
+
+ Examples:
+
+ 1 flash resource (mtd-id "sa1100"), with 1 single writable partition:
+ mtdparts=sa1100:-
+
+ Same flash, but 2 named partitions, the first one being read-only:
+ mtdparts=sa1100:256k(ARMboot)ro,-(root)
+
+ If unsure, say 'N'.
+
CONFIG_MTD_AFS_PARTS
The ARM Firmware Suite allows the user to divide flash devices into
multiple 'images'. Each such image has a header containing its name
@@ -61,7 +87,7 @@ CONFIG_MTD_AFS_PARTS
enable this option.
You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically. The
+ for your particular device. It won't happen automatically. The
'armflash' map driver (CONFIG_MTD_ARMFLASH) does this, for example.
CONFIG_MTD_DEBUG_VERBOSE
diff --git a/drivers/mtd/Config.in b/drivers/mtd/Config.in
index 797f79667844..7e3d3ffd2983 100644
--- a/drivers/mtd/Config.in
+++ b/drivers/mtd/Config.in
@@ -1,5 +1,5 @@
-# $Id: Config.in,v 1.71 2001/10/03 11:38:38 dwmw2 Exp $
+# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $
mainmenu_option next_comment
comment 'Memory Technology Devices (MTD)'
@@ -12,9 +12,10 @@ if [ "$CONFIG_MTD" = "y" -o "$CONFIG_MTD" = "m" ]; then
int ' Debugging verbosity (0 = quiet, 3 = noisy)' CONFIG_MTD_DEBUG_VERBOSE 0
fi
dep_tristate ' MTD partitioning support' CONFIG_MTD_PARTITIONS $CONFIG_MTD
+ dep_tristate ' MTD concatenating support' CONFIG_MTD_CONCAT $CONFIG_MTD
dep_tristate ' RedBoot partition table parsing' CONFIG_MTD_REDBOOT_PARTS $CONFIG_MTD_PARTITIONS
+ dep_tristate ' Command line partition table parsing' CONFIG_MTD_CMDLINE_PARTS $CONFIG_MTD_PARTITIONS
if [ "$CONFIG_ARM" = "y" ]; then
- dep_tristate ' Compaq bootldr partition table parsing' CONFIG_MTD_BOOTLDR_PARTS $CONFIG_MTD_PARTITIONS
dep_tristate ' ARM Firmware Suite partition parsing' CONFIG_MTD_AFS_PARTS $CONFIG_MTD_PARTITIONS
fi
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 4b8108198e7e..7ec5dfbb2501 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -1,12 +1,12 @@
#
# Makefile for the memory technology device drivers.
#
-#
-# $Id: Makefile,v 1.63 2001/06/13 09:43:07 dwmw2 Exp $
+# Based on:
+# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $
-export-objs := mtdcore.o mtdpart.o redboot.o bootldr.o afs.o
+export-objs := mtdcore.o mtdpart.o redboot.o cmdline.o afs.o mtdconcat.o
-obj-y += chips/ maps/ devices/ nand/
+obj-y += chips/ maps/ devices/ nand/
# *** BIG UGLY NOTE ***
#
@@ -26,9 +26,10 @@ obj-y += chips/ maps/ devices/ nand/
# Core functionality.
obj-$(CONFIG_MTD) += mtdcore.o
+obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o
obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
-obj-$(CONFIG_MTD_BOOTLDR_PARTS) += bootldr.o
+obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
# 'Users' - code which presents functionality to userspace.
diff --git a/drivers/mtd/bootldr.c b/drivers/mtd/bootldr.c
deleted file mode 100644
index 43fcd6bea8b8..000000000000
--- a/drivers/mtd/bootldr.c
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Read flash partition table from Compaq Bootloader
- *
- * Copyright 2001 Compaq Computer Corporation.
- *
- * $Id: bootldr.c,v 1.6 2001/10/02 15:05:11 dwmw2 Exp $
- *
- * Use consistent with the GNU GPL is permitted,
- * provided that this copyright notice is
- * preserved in its entirety in all copies and derived works.
- *
- * COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED,
- * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS
- * FITNESS FOR ANY PARTICULAR PURPOSE.
- *
- */
-
-/*
- * Maintainer: Jamey Hicks (jamey.hicks@compaq.com)
- */
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <asm/setup.h>
-#include <linux/bootmem.h>
-
-#define FLASH_PARTITION_NAMELEN 32
-enum LFR_FLAGS {
- LFR_SIZE_PREFIX = 1, /* prefix data with 4-byte size */
- LFR_PATCH_BOOTLDR = 2, /* patch bootloader's 0th instruction */
- LFR_KERNEL = 4, /* add BOOTIMG_MAGIC, imgsize and VKERNEL_BASE to head of programmed region (see bootldr.c) */
- LFR_EXPAND = 8 /* expand partition size to fit rest of flash */
-};
-
-// the tags are parsed too early to malloc or alloc_bootmem so we'll fix it
-// for now
-#define MAX_NUM_PARTITIONS 8
-typedef struct FlashRegion {
- char name[FLASH_PARTITION_NAMELEN];
- unsigned long base;
- unsigned long size;
- enum LFR_FLAGS flags;
-} FlashRegion;
-
-typedef struct BootldrFlashPartitionTable {
- int magic; /* should be filled with 0x646c7470 (btlp) BOOTLDR_PARTITION_MAGIC */
- int npartitions;
- struct FlashRegion partition[8];
-} BootldrFlashPartitionTable;
-
-#define BOOTLDR_MAGIC 0x646c7462 /* btld: marks a valid bootldr image */
-#define BOOTLDR_PARTITION_MAGIC 0x646c7470 /* btlp: marks a valid bootldr partition table in params sector */
-
-#define BOOTLDR_MAGIC_OFFSET 0x20 /* offset 0x20 into the bootldr */
-#define BOOTCAP_OFFSET 0X30 /* offset 0x30 into the bootldr */
-
-#define BOOTCAP_WAKEUP (1<<0)
-#define BOOTCAP_PARTITIONS (1<<1) /* partition table stored in params sector */
-#define BOOTCAP_PARAMS_AFTER_BOOTLDR (1<<2) /* params sector right after bootldr sector(s), else in last sector */
-
-static struct BootldrFlashPartitionTable Table;
-static struct BootldrFlashPartitionTable *partition_table = NULL;
-
-
-int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts)
-{
- struct mtd_partition *parts;
- int ret, retlen, i;
- int npartitions = 0;
- long partition_table_offset;
- long bootmagic = 0;
- long bootcap = 0;
- int namelen = 0;
-
- char *names;
-
-#if 0
- /* verify bootldr magic */
- ret = master->read(master, BOOTLDR_MAGIC_OFFSET, sizeof(long), &retlen, (void *)&bootmagic);
- if (ret)
- goto out;
- if (bootmagic != BOOTLDR_MAGIC)
- goto out;
- /* see if bootldr supports partition tables and where to find the partition table */
- ret = master->read(master, BOOTCAP_OFFSET, sizeof(long), &retlen, (void *)&bootcap);
- if (ret)
- goto out;
-
- if (!(bootcap & BOOTCAP_PARTITIONS))
- goto out;
- if (bootcap & BOOTCAP_PARAMS_AFTER_BOOTLDR)
- partition_table_offset = master->erasesize;
- else
- partition_table_offset = master->size - master->erasesize;
-
- printk(__FUNCTION__ ": partition_table_offset=%#lx\n", partition_table_offset);
- printk(__FUNCTION__ ": ptable_addr=%#lx\n", ptable_addr);
-
-
- /* Read the partition table */
- partition_table = (struct BootldrFlashPartitionTable *)kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!partition_table)
- return -ENOMEM;
-
- ret = master->read(master, partition_table_offset,
- PAGE_SIZE, &retlen, (void *)partition_table);
- if (ret)
- goto out;
-
-#endif
- if (!partition_table)
- return -ENOMEM;
-
-
- printk(__FUNCTION__ ": magic=%#x\n", partition_table->magic);
- printk(__FUNCTION__ ": numPartitions=%#x\n", partition_table->npartitions);
-
-
- /* check for partition table magic number */
- if (partition_table->magic != BOOTLDR_PARTITION_MAGIC)
- goto out;
- npartitions = (partition_table->npartitions > MAX_NUM_PARTITIONS)?
- MAX_NUM_PARTITIONS:partition_table->npartitions;
-
- printk(__FUNCTION__ ": npartitions=%#x\n", npartitions);
-
- for (i = 0; i < npartitions; i++) {
- namelen += strlen(partition_table->partition[i].name) + 1;
- }
-
- parts = kmalloc(sizeof(*parts)*npartitions + namelen, GFP_KERNEL);
- if (!parts) {
- ret = -ENOMEM;
- goto out;
- }
- names = (char *)&parts[npartitions];
- memset(parts, 0, sizeof(*parts)*npartitions + namelen);
-
-
-
- // from here we use the partition table
- for (i = 0; i < npartitions; i++) {
- struct FlashRegion *partition = &partition_table->partition[i];
- const char *name = partition->name;
- parts[i].name = names;
- names += strlen(name) + 1;
- strcpy(parts[i].name, name);
-
- if (partition->flags & LFR_EXPAND)
- parts[i].size = MTDPART_SIZ_FULL;
- else
- parts[i].size = partition->size;
- parts[i].offset = partition->base;
- parts[i].mask_flags = 0;
-
- printk(" partition %s o=%x s=%x\n",
- parts[i].name, parts[i].offset, parts[i].size);
-
- }
-
- ret = npartitions;
- *pparts = parts;
-
- out:
-#if 0
- if (partition_table)
- kfree(partition_table);
-#endif
-
- return ret;
-}
-
-
-static int __init parse_tag_ptable(const struct tag *tag)
-{
- char buf[128];
- int i;
- int j;
-
- partition_table = &Table;
-
-#ifdef CONFIG_DEBUG_LL
- sprintf(buf,"ptable: magic = = 0x%lx npartitions= %d \n",
- tag->u.ptable.magic,tag->u.ptable.npartitions);
- printascii(buf);
-
- for (i=0; i<tag->u.ptable.npartitions; i++){
- sprintf(buf,"ptable: partition name = %s base= 0x%lx size= 0x%lx flags= 0x%lx\n",
- (char *) (&tag->u.ptable.partition[i].name[0]),
- tag->u.ptable.partition[i].base,
- tag->u.ptable.partition[i].size,
- tag->u.ptable.partition[i].flags);
- printascii(buf);
- }
-#endif
-
- memcpy((void *)partition_table,(void *) (&(tag->u.ptable)),sizeof(partition_table) +
- sizeof(struct FlashRegion)*tag->u.ptable.npartitions);
-
-
- return 0;
-}
-
-__tagtable(ATAG_PTABLE, parse_tag_ptable);
-
-EXPORT_SYMBOL(parse_bootldr_partitions);
-
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Compaq Computer Corporation");
-MODULE_DESCRIPTION("Parsing code for Compaq bootldr partitions");
diff --git a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c
new file mode 100644
index 000000000000..4d92157f46de
--- /dev/null
+++ b/drivers/mtd/cmdline.c
@@ -0,0 +1,343 @@
+/*
+ * $Id: cmdline.c,v 1.4 2002/09/13 01:18:38 jamey Exp $
+ *
+ * Read flash partition table from command line
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * The format for the command line is as follows:
+ *
+ * mtdparts=<mtddef>[;<mtddef]
+ * <mtddef> := <mtd-id>:<partdef>[,<partdef>]
+ * <partdef> := <size>[@offset][<name>][ro]
+ * <mtd-id> := unique id used in mapping driver/device
+ * <size> := standard linux memsize OR "-" to denote all remaining space
+ * <name> := '(' NAME ')'
+ *
+ * Examples:
+ *
+ * 1 NOR Flash, with 1 single writable partition:
+ * edb7312-nor:-
+ *
+ * 1 NOR Flash with 2 partitions, 1 NAND with one
+ * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home)
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <asm/setup.h>
+#include <linux/bootmem.h>
+
+/* error message prefix */
+#define ERRP "mtd: "
+
+/* debug macro */
+#if 0
+#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0)
+#else
+#define dbg(x)
+#endif
+
+
+/* special size referring to all the remaining space in a partition */
+#define SIZE_REMAINING 0xffffffff
+
+struct cmdline_mtd_partition {
+ struct cmdline_mtd_partition *next;
+ char *mtd_id;
+ int num_parts;
+ struct mtd_partition *parts;
+};
+
+/* mtdpart_setup() parses into here */
+static struct cmdline_mtd_partition *partitions;
+
+/* the command line passed to mtdpart_setupd() */
+static char *cmdline;
+static int cmdline_parsed = 0;
+
+/*
+ * Parse one partition definition for an MTD. Since there can be many
+ * comma separated partition definitions, this function calls itself
+ * recursively until no more partition definitions are found. Nice side
+ * effect: the memory to keep the mtd_partition structs and the names
+ * is allocated upon the last definition being found. At that point the
+ * syntax has been verified ok.
+ */
+static struct mtd_partition * newpart(char *s,
+ char **retptr,
+ int *num_parts,
+ int this_part,
+ unsigned char **extra_mem_ptr,
+ int extra_mem_size)
+{
+ struct mtd_partition *parts;
+ unsigned long size;
+ unsigned long offset = 0;
+ char *name;
+ int name_len;
+ unsigned char *extra_mem;
+ char delim;
+ unsigned int mask_flags;
+
+ /* fetch the partition size */
+ if (*s == '-')
+ { /* assign all remaining space to this partition */
+ size = SIZE_REMAINING;
+ s++;
+ }
+ else
+ {
+ size = memparse(s, &s);
+ if (size < PAGE_SIZE)
+ {
+ printk(KERN_ERR ERRP "partition size too small (%lx)\n", size);
+ return 0;
+ }
+ }
+
+ /* fetch partition name and flags */
+ mask_flags = 0; /* this is going to be a regular partition */
+ delim = 0;
+ /* check for offset */
+ if (*s == '@')
+ {
+ s++;
+ offset = memparse(s, &s);
+ }
+ /* now look for name */
+ if (*s == '(')
+ {
+ delim = ')';
+ }
+ if (delim)
+ {
+ char *p;
+
+ name = ++s;
+ if ((p = strchr(name, delim)) == 0)
+ {
+ printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim);
+ return 0;
+ }
+ name_len = p - name;
+ s = p + 1;
+ }
+ else
+ {
+ name = NULL;
+ name_len = 13; /* Partition_000 */
+ }
+
+ /* record name length for memory allocation later */
+ extra_mem_size += name_len + 1;
+
+ /* test for options */
+ if (strncmp(s, "ro", 2) == 0)
+ {
+ mask_flags |= MTD_WRITEABLE;
+ s += 2;
+ }
+
+ /* test if more partitions are following */
+ if (*s == ',')
+ {
+ if (size == SIZE_REMAINING)
+ {
+ printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n");
+ return 0;
+ }
+ /* more partitions follow, parse them */
+ if ((parts = newpart(s + 1, &s, num_parts,
+ this_part + 1, &extra_mem, extra_mem_size)) == 0)
+ return 0;
+ }
+ else
+ { /* this is the last partition: allocate space for all */
+ int alloc_size;
+
+ *num_parts = this_part + 1;
+ alloc_size = *num_parts * sizeof(struct mtd_partition) +
+ extra_mem_size;
+ parts = kmalloc(alloc_size, GFP_KERNEL);
+ if (!parts)
+ {
+ printk(KERN_ERR ERRP "out of memory\n");
+ return 0;
+ }
+ memset(parts, 0, alloc_size);
+ extra_mem = (unsigned char *)(parts + *num_parts);
+ }
+ /* enter this partition (offset will be calculated later if it is zero at this point) */
+ parts[this_part].size = size;
+ parts[this_part].offset = offset;
+ parts[this_part].mask_flags = mask_flags;
+ if (name)
+ {
+ strncpy(extra_mem, name, name_len);
+ extra_mem[name_len] = 0;
+ }
+ else
+ {
+ sprintf(extra_mem, "Partition_%03d", this_part);
+ }
+ parts[this_part].name = extra_mem;
+ extra_mem += name_len + 1;
+
+ dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n",
+ this_part,
+ parts[this_part].name,
+ parts[this_part].offset,
+ parts[this_part].size,
+ parts[this_part].mask_flags));
+
+ /* return (updated) pointer to extra_mem memory */
+ if (extra_mem_ptr)
+ *extra_mem_ptr = extra_mem;
+
+ /* return (updated) pointer command line string */
+ *retptr = s;
+
+ /* return partition table */
+ return parts;
+}
+
+/*
+ * Parse the command line.
+ */
+static int mtdpart_setup_real(char *s)
+{
+ cmdline_parsed = 1;
+
+ for( ; s != NULL; )
+ {
+ struct cmdline_mtd_partition *this_mtd;
+ struct mtd_partition *parts;
+ int mtd_id_len;
+ int num_parts;
+ char *p, *mtd_id;
+
+ mtd_id = s;
+ /* fetch <mtd-id> */
+ if (!(p = strchr(s, ':')))
+ {
+ printk(KERN_ERR ERRP "no mtd-id\n");
+ return 0;
+ }
+ mtd_id_len = p - mtd_id;
+
+ dbg(("parsing <%s>\n", p+1));
+
+ /*
+ * parse one mtd. have it reserve memory for the
+ * struct cmdline_mtd_partition and the mtd-id string.
+ */
+ parts = newpart(p + 1, /* cmdline */
+ &s, /* out: updated cmdline ptr */
+ &num_parts, /* out: number of parts */
+ 0, /* first partition */
+ (unsigned char**)&this_mtd, /* out: extra mem */
+ mtd_id_len + 1 + sizeof(*this_mtd));
+
+ /* enter results */
+ this_mtd->parts = parts;
+ this_mtd->num_parts = num_parts;
+ this_mtd->mtd_id = (char*)(this_mtd + 1);
+ strncpy(this_mtd->mtd_id, mtd_id, mtd_id_len);
+ this_mtd->mtd_id[mtd_id_len] = 0;
+
+ /* link into chain */
+ this_mtd->next = partitions;
+ partitions = this_mtd;
+
+ dbg(("mtdid=<%s> num_parts=<%d>\n",
+ this_mtd->mtd_id, this_mtd->num_parts));
+
+
+ /* EOS - we're done */
+ if (*s == 0)
+ break;
+
+ /* does another spec follow? */
+ if (*s != ';')
+ {
+ printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s);
+ return 0;
+ }
+ s++;
+ }
+ return 1;
+}
+
+/*
+ * Main function to be called from the MTD mapping driver/device to
+ * obtain the partitioning information. At this point the command line
+ * arguments will actually be parsed and turned to struct mtd_partition
+ * information.
+ */
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id)
+{
+ unsigned long offset;
+ int i;
+ struct cmdline_mtd_partition *part;
+
+ if (!cmdline)
+ return -EINVAL;
+
+ /* parse command line */
+ if (!cmdline_parsed)
+ mtdpart_setup_real(cmdline);
+
+ for(part = partitions; part; part = part->next)
+ {
+ if (!strcmp(part->mtd_id, mtd_id))
+ {
+ for(i = 0, offset = 0; i < part->num_parts; i++)
+ {
+ if (!part->parts[i].offset)
+ part->parts[i].offset = offset;
+ else
+ offset = part->parts[i].offset;
+ if (part->parts[i].size == SIZE_REMAINING)
+ part->parts[i].size = master->size - offset;
+ if (offset + part->parts[i].size > master->size)
+ {
+ printk(KERN_WARNING ERRP
+ "%s: partitioning exceeds flash size, truncating\n",
+ mtd_id);
+ part->parts[i].size = master->size - offset;
+ part->num_parts = i;
+ }
+ offset += part->parts[i].size;
+ }
+ *pparts = part->parts;
+ return part->num_parts;
+ }
+ }
+ return -EINVAL;
+}
+
+
+/*
+ * This is the handler for our kernel parameter, called from
+ * main.c::checksetup(). Note that we can not yet kmalloc() anything,
+ * so we only save the commandline for later processing.
+ */
+static int __init mtdpart_setup(char *s)
+{
+ cmdline = s;
+ return 1;
+}
+
+__setup("mtdparts=", mtdpart_setup);
+
+EXPORT_SYMBOL(parse_cmdline_partitions);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Command line configuration of MTD partitions");
diff --git a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c
index 341ad2252885..e40e34d3c7d6 100644
--- a/drivers/mtd/ftl.c
+++ b/drivers/mtd/ftl.c
@@ -1223,7 +1223,7 @@ static void ftl_notify_add(struct mtd_info *mtd)
}
partition = kmalloc(sizeof(partition_t), GFP_KERNEL);
- disk = alloc_disk();
+ disk = alloc_disk(1 << PART_BITS);
if (!partition||!disk) {
printk(KERN_WARNING "No memory to scan for FTL on %s\n",
@@ -1237,7 +1237,6 @@ static void ftl_notify_add(struct mtd_info *mtd)
sprintf(disk->disk_name, "ftl%c", 'a' + device);
disk->major = FTL_MAJOR;
disk->first_minor = device << 4;
- disk->minor_shift = PART_BITS;
disk->fops = &ftl_blk_fops;
partition->mtd = mtd;
partition->disk = disk;
diff --git a/drivers/mtd/maps/Config.help b/drivers/mtd/maps/Config.help
index aaf3a1aa894e..d4cc1af6505e 100644
--- a/drivers/mtd/maps/Config.help
+++ b/drivers/mtd/maps/Config.help
@@ -1,3 +1,32 @@
+CONFIG_MTD_CDB89712
+ This enables access to the flash or ROM chips on the CDB89712 board.
+ If you have such a board, say 'Y'.
+
+CONFIG_MTD_CEIVA
+ This enables access to the flash chips on the Ceiva/Polaroid
+ PhotoMax Digital Picture Frame.
+ If you have such a device, say 'Y'.
+
+CONFIG_MTD_FORTUNET
+ This enables access to the Flash on the FortuNet board. If you
+ have such a board, say 'Y'.
+
+CONFIG_MTD_AUTCPU12
+ This enables access to the NV-RAM on autronix autcpu12 board.
+ If you have such a board, say 'Y'.
+
+CONFIG_MTD_EDB7312
+ This enables access to the CFI Flash on the Cogent EDB7312 board.
+ If you have such a board, say 'Y' here.
+
+CONFIG_MTD_NAND_EDB7312
+ This enables access to the NAND Flash on the Cogent EDB7312 board.
+ If you have such a board, say 'Y' here.
+
+CONFIG_MTD_IMPA7
+ This enables access to the NOR Flash on the impA7 board of
+ implementa GmbH. If you have such a board, say 'Y' here.
+
CONFIG_MTD_SA1100
This enables access to the flash chips on most platforms based on
the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
@@ -39,6 +68,12 @@ CONFIG_MTD_SUN_UFLASH
CONFIG_MTD_NORA
If you had to ask, you don't have one. Say 'N'.
+CONFIG_MTD_L440GX
+ Support for treating the BIOS flash chip on Intel L440GX motherboards
+ as an MTD device - with this you can reprogram your BIOS.
+
+ BE VERY CAREFUL.
+
CONFIG_MTD_PNC2000
PNC-2000 is the name of Network Camera product from PHOTRON
Ltd. in Japan. It uses CFI-compliant flash.
@@ -50,6 +85,13 @@ CONFIG_MTD_RPXLITE
to communicate with the chips on the RPXLite board. More at
<http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>.
+CONFIG_MTD_TQM8XXL
+ The TQM8xxL PowerPC board has up to two banks of CFI-compliant
+ chips, currently uses AMD one. This 'mapping' driver supports
+ that arrangement, allowing the CFI probe and command set driver
+ code to communicate with the chips on the TQM8xxL board. More at
+ <http://www.denx.de/embedded-ppc-en.html>.
+
CONFIG_MTD_SC520CDP
The SC520 CDP board has two banks of CFI-compliant chips and one
Dual-in-line JEDEC chip. This 'mapping' driver supports that
@@ -59,7 +101,7 @@ CONFIG_MTD_SBC_GXX
This provides a driver for the on-board flash of Arcom Control
Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX.
By default the flash is split into 3 partitions which are accessed
- as separate MTD devices. This board utilizes Intel StrataFlash.
+ as separate MTD devices. This board utilizes Intel StrataFlash.
More info at
<http://www.arcomcontrols.com/products/icp/pc104/processors/>.
@@ -78,6 +120,11 @@ CONFIG_MTD_NETSC520
demonstration board. If you have one of these boards and would like
to use the flash chips on it, say 'Y'.
+CONFIG_MTD_OCELOT
+ This enables access routines for the boot flash device and for the
+ NVRAM on the Momenco Ocelot board. If you have one of these boards
+ and would like access to either of these, say 'Y'.
+
CONFIG_MTD_ELAN_104NC
This provides a driver for the on-board flash of the Arcom Control
System's ELAN-104NC development board. By default the flash
@@ -91,17 +138,17 @@ CONFIG_MTD_DC21285
<http://developer.intel.com/design/bridge/quicklist/dsc-21285.htm>.
CONFIG_MTD_CSTM_MIPS_IXX
- This provides a mapping driver for the Integrated Tecnology Express,
- Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference
- Board. It provides the necessary addressing, length, buswidth, vpp
- code and addition setup of the flash device for these boards. In
- addition, this mapping driver can be used for other boards via
- setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/LEN/BUSWIDTH
- parameters. This mapping will provide one mtd device using one
- partition. The start address can be offset from the beginning of
- flash and the len can be less than the total flash device size to
- allow a window into the flash. Both CFI and JEDEC probes are
- called.
+ This provides a mapping driver for the Integrated Tecnology
+ Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR
+ Reference Board. It provides the necessary addressing, length,
+ buswidth, vpp code and addition setup of the flash device for
+ these boards. In addition, this mapping driver can be used for
+ other boards via setting of the CONFIG_MTD_CSTM_MIPS_IXX_START/
+ LEN/BUSWIDTH parameters. This mapping will provide one mtd device
+ using one partition. The start address can be offset from the
+ beginning of flash and the len can be less than the total flash
+ device size to allow a window into the flash. Both CFI and JEDEC
+ probes are called.
CONFIG_MTD_CSTM_MIPS_IXX_START
This is the physical memory location that the MTD driver will
@@ -141,6 +188,11 @@ CONFIG_MTD_OCTAGON
Computer. More information on the board is available at
<http://www.octagonsystems.com/Products/5066/5066.html>.
+CONFIG_MTD_PCMCIA
+ Map driver for accessing PCMCIA linear flash memory cards. These
+ cards are usually around 4-16MiB in size. This does not include
+ Compact Flash cards which are treated as IDE devices.
+
CONFIG_MTD_VMAX
This provides a 'mapping' driver which supports the way in which
the flash chips are connected in the Tempustech VMAX SBC301 Single
@@ -148,32 +200,21 @@ CONFIG_MTD_VMAX
<http://www.tempustech.com/tt301.htm>.
CONFIG_MTD_CFI_FLAGADM
- Mapping for the Flaga digital module. If you don´t have one, ignore
+ Mapping for the Flaga digital module. If you don´t have one, ignore
this setting.
-CONFIG_MTD_OCELOT
- This enables access routines for the boot flash device and for the
- NVRAM on the Momenco Ocelot board. If you have one of these boards
- and would like access to either of these, say 'Y'.
-
-CONFIG_MTD_CDB89712
- This enables access to the flash or ROM chips on the CDB89712 board.
- If you have such a board, say 'Y'.
-
-CONFIG_MTD_L440GX
- Support for treating the BIOS flash chip on Intel L440GX motherboards
- as an MTD device - with this you can reprogram your BIOS.
-
- BE VERY CAREFUL.
-
CONFIG_MTD_SOLUTIONENGINE
This enables access to the flash chips on the Hitachi SolutionEngine and
similar boards. Say 'Y' if you are building a kernel for such a board.
-CONFIG_MTD_TQM8XXL
- The TQM8xxL PowerPC board has up to two banks of CFI-compliant
- chips, currently uses AMD one. This 'mapping' driver supports
- that arrangement, allowing the CFI probe and command set driver
- code to communicate with the chips on the TQM8xxL board. More at
- <http://www.denx.de/embedded-ppc-en.html>.
+CONFIG_MTD_EPXA10DB
+ This enables support for the flash devices on the Altera
+ Excalibur XA10 Development Board. If you are building a kernel
+ for on of these boards then you should say 'Y' otherwise say 'N'.
+
+CONFIG_MTD_PCI
+ Mapping for accessing flash devices on add-in cards like the Intel XScale
+ IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode
+ (please see the manual for the link settings).
+ If you are not sure, say N.
diff --git a/drivers/mtd/maps/Config.in b/drivers/mtd/maps/Config.in
index 7b4cbd4eda85..e0668372fa79 100644
--- a/drivers/mtd/maps/Config.in
+++ b/drivers/mtd/maps/Config.in
@@ -56,8 +56,18 @@ if [ "$CONFIG_ARM" = "y" ]; then
dep_tristate ' CFI Flash device mapped on ARM Integrator/P720T' CONFIG_MTD_ARM_INTEGRATOR $CONFIG_MTD_CFI
dep_tristate ' Cirrus CDB89712 evaluation board mappings' CONFIG_MTD_CDB89712 $CONFIG_MTD_CFI $CONFIG_ARCH_CDB89712
dep_tristate ' CFI Flash device mapped on StrongARM SA11x0' CONFIG_MTD_SA1100 $CONFIG_MTD_CFI $CONFIG_ARCH_SA1100 $CONFIG_MTD_PARTITIONS
- dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE $CONFIG_MTD_PARTITIONS
+ dep_tristate ' CFI Flash device mapped on DC21285 Footbridge' CONFIG_MTD_DC21285 $CONFIG_MTD_CFI $CONFIG_ARCH_FOOTBRIDGE
dep_tristate ' CFI Flash device mapped on the XScale IQ80310 board' CONFIG_MTD_IQ80310 $CONFIG_MTD_CFI $CONFIG_ARCH_IQ80310
+ dep_tristate ' CFI Flash device mapped on Epxa10db' CONFIG_MTD_EPXA10DB $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_ARCH_CAMELOT
+ dep_tristate ' CFI Flash device mapped on the FortuNet board' CONFIG_MTD_FORTUNET $CONFIG_MTD_CFI $CONFIG_MTD_PARTITIONS $CONFIG_SA1100_FORTUNET
+ dep_tristate ' NV-RAM mapping AUTCPU12 board' CONFIG_MTD_AUTCPU12 $CONFIG_ARCH_AUTCPU12
+ dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_MTD_CFI
+ dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE
+ dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA
fi
+# This needs CFI or JEDEC, depending on the cards found.
+dep_tristate ' PCI MTD driver' CONFIG_MTD_PCI $CONFIG_MTD $CONFIG_PCI
+dep_tristate ' PCMCIA MTD driver' CONFIG_MTD_PCMCIA $CONFIG_MTD $CONFIG_PCMCIA
+
endmenu
diff --git a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile
index c0bdc2fa8f23..f4acee989d04 100644
--- a/drivers/mtd/maps/Makefile
+++ b/drivers/mtd/maps/Makefile
@@ -4,29 +4,37 @@
# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $
# Chip mappings
-obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
+obj-$(CONFIG_MTD_CDB89712) += cdb89712.o
obj-$(CONFIG_MTD_ARM_INTEGRATOR)+= integrator-flash.o
obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o
-obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
-obj-$(CONFIG_MTD_DC21285) += dc21285.o
-obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
+obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o
+obj-$(CONFIG_MTD_DC21285) += dc21285.o
+obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o
+obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o
obj-$(CONFIG_MTD_IQ80310) += iq80310.o
obj-$(CONFIG_MTD_L440GX) += l440gx.o
obj-$(CONFIG_MTD_NORA) += nora.o
+obj-$(CONFIG_MTD_CEIVA) += ceiva.o
obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o
obj-$(CONFIG_MTD_PHYSMAP) += physmap.o
obj-$(CONFIG_MTD_PNC2000) += pnc2000.o
+obj-$(CONFIG_MTD_PCMCIA) += pcmciamtd.o
obj-$(CONFIG_MTD_RPXLITE) += rpxlite.o
obj-$(CONFIG_MTD_TQM8XXL) += tqm8xxl.o
-obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
+obj-$(CONFIG_MTD_SA1100) += sa1100-flash.o
obj-$(CONFIG_MTD_SBC_GXX) += sbc_gxx.o
obj-$(CONFIG_MTD_SC520CDP) += sc520cdp.o
obj-$(CONFIG_MTD_NETSC520) += netsc520.o
-obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
+obj-$(CONFIG_MTD_SUN_UFLASH) += sun_uflash.o
obj-$(CONFIG_MTD_VMAX) += vmax301.o
obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o
obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o
obj-$(CONFIG_MTD_OCELOT) += ocelot.o
obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o
+obj-$(CONFIG_MTD_PCI) += pci.o
+obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o
+obj-$(CONFIG_MTD_EDB7312) += edb7312.o
+obj-$(CONFIG_MTD_IMPA7) += impa7.o
+obj-$(CONFIG_MTD_FORTUNET) += fortunet.o
include $(TOPDIR)/Rules.make
diff --git a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c
new file mode 100644
index 000000000000..db78b01e6438
--- /dev/null
+++ b/drivers/mtd/maps/autcpu12-nvram.c
@@ -0,0 +1,179 @@
+/*
+ * NV-RAM memory access on autcpu12
+ * (C) 2002 Thomas Gleixner (gleixner@autronix.de)
+ *
+ * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/hardware.h>
+#include <asm/arch/autcpu12.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+__u8 autcpu12_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 autcpu12_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 autcpu12_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ while(len) {
+ __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to);
+ from++;
+ to++;
+ len--;
+ }
+}
+
+static struct mtd_info *sram_mtd;
+
+struct map_info autcpu12_sram_map = {
+ name: "SRAM",
+ size: 32768,
+ buswidth: 8,
+ read8: autcpu12_read8,
+ read16: autcpu12_read16,
+ read32: autcpu12_read32,
+ copy_from: autcpu12_copy_from,
+ write8: autcpu12_write8,
+ write16: autcpu12_write16,
+ write32: autcpu12_write32,
+ copy_to: autcpu12_copy_to
+};
+
+static int __init init_autcpu12_sram (void)
+{
+ int err, save0, save1;
+
+ autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K);
+ if (!autcpu12_sram_map.map_priv_1) {
+ printk("Failed to ioremap autcpu12 NV-RAM space\n");
+ err = -EIO;
+ goto out;
+ }
+
+ /*
+ * Check for 32K/128K
+ * read ofs 0
+ * read ofs 0x10000
+ * Write complement to ofs 0x100000
+ * Read and check result on ofs 0x0
+ * Restore contents
+ */
+ save0 = autcpu12_read32(&autcpu12_sram_map,0);
+ save1 = autcpu12_read32(&autcpu12_sram_map,0x10000);
+ autcpu12_write32(&autcpu12_sram_map,~save0,0x10000);
+ /* if we find this pattern on 0x0, we have 32K size
+ * restore contents and exit
+ */
+ if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) {
+ autcpu12_write32(&autcpu12_sram_map,save0,0x0);
+ goto map;
+ }
+ /* We have a 128K found, restore 0x10000 and set size
+ * to 128K
+ */
+ autcpu12_write32(&autcpu12_sram_map,save1,0x10000);
+ autcpu12_sram_map.size = SZ_128K;
+
+map:
+ sram_mtd = do_map_probe("map_ram", &autcpu12_sram_map);
+ if (!sram_mtd) {
+ printk("NV-RAM probe failed\n");
+ err = -ENXIO;
+ goto out_ioremap;
+ }
+
+ sram_mtd->module = THIS_MODULE;
+ sram_mtd->erasesize = 16;
+
+ if (add_mtd_device(sram_mtd)) {
+ printk("NV-RAM device addition failed\n");
+ err = -ENOMEM;
+ goto out_probe;
+ }
+
+ printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K);
+
+ return 0;
+
+out_probe:
+ map_destroy(sram_mtd);
+ sram_mtd = 0;
+
+out_ioremap:
+ iounmap((void *)autcpu12_sram_map.map_priv_1);
+out:
+ return err;
+}
+
+static void __exit cleanup_autcpu12_maps(void)
+{
+ if (sram_mtd) {
+ del_mtd_device(sram_mtd);
+ map_destroy(sram_mtd);
+ iounmap((void *)autcpu12_sram_map.map_priv_1);
+ }
+}
+
+module_init(init_autcpu12_sram);
+module_exit(cleanup_autcpu12_maps);
+
+MODULE_AUTHOR("Thomas Gleixner");
+MODULE_DESCRIPTION("autcpu12 NV-RAM map driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c
new file mode 100644
index 000000000000..259a9a8b76c0
--- /dev/null
+++ b/drivers/mtd/maps/ceiva.c
@@ -0,0 +1,408 @@
+/*
+ * Ceiva flash memory driver.
+ * Copyright (C) 2002 Rob Scott <rscott@mtrob.fdns.net>
+ *
+ * Note: this driver supports jedec compatible devices. Modification
+ * for CFI compatible devices should be straight forward: change
+ * jedec_probe to cfi_probe.
+ *
+ * Based on: sa1100-flash.c, which has the following copyright:
+ * Flash memory access on SA11x0 based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ *
+ * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
+
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_CEIVA_STATICMAP
+
+static __u8 clps_read8(struct map_info *map, unsigned long ofs)
+{
+ return readb(map->map_priv_1 + ofs);
+}
+
+static __u16 clps_read16(struct map_info *map, unsigned long ofs)
+{
+ return readw(map->map_priv_1 + ofs);
+}
+
+static __u32 clps_read32(struct map_info *map, unsigned long ofs)
+{
+ return readl(map->map_priv_1 + ofs);
+}
+
+static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void clps_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ writeb(d, map->map_priv_1 + adr);
+}
+
+static void clps_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ writew(d, map->map_priv_1 + adr);
+}
+
+static void clps_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ writel(d, map->map_priv_1 + adr);
+}
+
+static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+static struct map_info clps_map __initdata = {
+ name: "clps flash",
+ read8: clps_read8,
+ read16: clps_read16,
+ read32: clps_read32,
+ copy_from: clps_copy_from,
+ write8: clps_write8,
+ write16: clps_write16,
+ write32: clps_write32,
+ copy_to: clps_copy_to,
+};
+
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+/*
+ * See include/linux/mtd/partitions.h for definition of the mtd_partition
+ * structure.
+ *
+ * Please note:
+ * 1. The flash size given should be the largest flash size that can
+ * be accomodated.
+ *
+ * 2. The bus width must defined in clps_setup_flash.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ */
+
+#ifdef CONFIG_ARCH_CEIVA
+/* Flash / Partition sizing */
+/* For the 28F8003, we use the block mapping to calcuate the sizes */
+#define MAX_SIZE_KiB (16 + 8 + 8 + 96 + (7*128))
+#define BOOT_PARTITION_SIZE_KiB (16)
+#define PARAMS_PARTITION_SIZE_KiB (8)
+#define KERNEL_PARTITION_SIZE_KiB (4*128)
+/* Use both remaing portion of first flash, and all of second flash */
+#define ROOT_PARTITION_SIZE_KiB (3*128) + (8*128)
+
+static struct mtd_partition ceiva_partitions[] = {
+ {
+ name: "Ceiva BOOT partition",
+ size: BOOT_PARTITION_SIZE_KiB*1024,
+ offset: 0,
+
+ },{
+ name: "Ceiva parameters partition",
+ size: PARAMS_PARTITION_SIZE_KiB*1024,
+ offset: (16 + 8) * 1024,
+ },{
+ name: "Ceiva kernel partition",
+ size: (KERNEL_PARTITION_SIZE_KiB)*1024,
+ offset: 0x20000,
+
+ },{
+ name: "Ceiva root filesystem partition",
+ offset: MTDPART_OFS_APPEND,
+ size: (ROOT_PARTITION_SIZE_KiB)*1024,
+ }
+};
+#endif
+
+static int __init clps_static_partitions(struct mtd_partition **parts)
+{
+ int nb_parts = 0;
+
+#ifdef CONFIG_ARCH_CEIVA
+ if (machine_is_ceiva()) {
+ *parts = ceiva_partitions;
+ nb_parts = ARRAY_SIZE(ceiva_partitions);
+ }
+#endif
+ return nb_parts;
+}
+#endif
+
+struct clps_info {
+ unsigned long base;
+ unsigned long size;
+ int width;
+ void *vbase;
+ struct map_info *map;
+ struct mtd_info *mtd;
+ struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct clps_info info[NR_SUBMTD];
+
+static int __init clps_setup_mtd(struct clps_info *clps, int nr, struct mtd_info **rmtd)
+{
+ struct mtd_info *subdev[nr];
+ struct map_info *maps;
+ int i, found = 0, ret = 0;
+
+ /*
+ * Allocate the map_info structs in one go.
+ */
+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
+
+ /*
+ * Claim and then map the memory regions.
+ */
+ for (i = 0; i < nr; i++) {
+ if (clps[i].base == (unsigned long)-1)
+ break;
+
+ clps[i].res = request_mem_region(clps[i].base, clps[i].size, "clps flash");
+ if (!clps[i].res) {
+ ret = -EBUSY;
+ break;
+ }
+
+ clps[i].map = maps + i;
+ memcpy(clps[i].map, &clps_map, sizeof(struct map_info));
+
+ clps[i].vbase = ioremap(clps[i].base, clps[i].size);
+ if (!clps[i].vbase) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase;
+ clps[i].map->buswidth = clps[i].width;
+ clps[i].map->size = clps[i].size;
+
+ clps[i].mtd = do_map_probe("jedec_probe", clps[i].map);
+ if (clps[i].mtd == NULL) {
+ ret = -ENXIO;
+ break;
+ }
+ clps[i].mtd->module = THIS_MODULE;
+ subdev[i] = clps[i].mtd;
+
+ printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, "
+ "%d-bit\n", clps[i].base, clps[i].mtd->size >> 20,
+ clps[i].width * 8);
+ found += 1;
+ }
+
+ /*
+ * ENXIO is special. It means we didn't find a chip when
+ * we probed. We need to tear down the mapping, free the
+ * resource and mark it as such.
+ */
+ if (ret == -ENXIO) {
+ iounmap(clps[i].vbase);
+ clps[i].vbase = NULL;
+ release_resource(clps[i].res);
+ clps[i].res = NULL;
+ }
+
+ /*
+ * If we found one device, don't bother with concat support.
+ * If we found multiple devices, use concat if we have it
+ * available, otherwise fail.
+ */
+ if (ret == 0 || ret == -ENXIO) {
+ if (found == 1) {
+ *rmtd = subdev[0];
+ ret = 0;
+ } else if (found > 1) {
+ /*
+ * We detected multiple devices. Concatenate
+ * them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ *rmtd = mtd_concat_create(subdev, found,
+ "clps flash");
+ if (*rmtd == NULL)
+ ret = -ENXIO;
+#else
+ printk(KERN_ERR "clps flash: multiple devices "
+ "found but MTD concat support disabled.\n");
+ ret = -ENXIO;
+#endif
+ }
+ }
+
+ /*
+ * If we failed, clean up.
+ */
+ if (ret) {
+ do {
+ if (clps[i].mtd)
+ map_destroy(clps[i].mtd);
+ if (clps[i].vbase)
+ iounmap(clps[i].vbase);
+ if (clps[i].res)
+ release_resource(clps[i].res);
+ } while (i--);
+
+ kfree(maps);
+ }
+
+ return ret;
+}
+
+static void __exit clps_destroy_mtd(struct clps_info *clps, struct mtd_info *mtd)
+{
+ int i;
+
+ del_mtd_partitions(mtd);
+
+ if (mtd != clps[0].mtd)
+ mtd_concat_destroy(mtd);
+
+ for (i = NR_SUBMTD; i >= 0; i--) {
+ if (clps[i].mtd)
+ map_destroy(clps[i].mtd);
+ if (clps[i].vbase)
+ iounmap(clps[i].vbase);
+ if (clps[i].res)
+ release_resource(clps[i].res);
+ }
+ kfree(clps[0].map);
+}
+
+/*
+ * We define the memory space, size, and width for the flash memory
+ * space here.
+ */
+
+static int __init clps_setup_flash(void)
+{
+ int nr;
+
+#ifdef CONFIG_ARCH_CEIVA
+ if (machine_is_ceiva()) {
+ info[0].base = CS0_PHYS_BASE;
+ info[0].size = SZ_32M;
+ info[0].width = CEIVA_FLASH_WIDTH;
+ info[1].base = CS1_PHYS_BASE;
+ info[1].size = SZ_32M;
+ info[1].width = CEIVA_FLASH_WIDTH;
+ nr = 2;
+ }
+#endif
+ return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init clps_locate_partitions(struct mtd_info *mtd)
+{
+ const char *part_type = NULL;
+ int nr_parts = 0;
+ do {
+ /*
+ * Partition selection stuff.
+ */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps");
+ if (nr_parts > 0) {
+ part_type = "command line";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "RedBoot";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_CEIVA_STATICMAP
+ nr_parts = clps_static_partitions(&parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "static";
+ break;
+ }
+ printk("found: %d partitions\n", nr_parts);
+#endif
+ } while (0);
+
+ if (nr_parts == 0) {
+ printk(KERN_NOTICE "clps flash: no partition info "
+ "available, registering whole flash\n");
+ add_mtd_device(mtd);
+ } else {
+ printk(KERN_NOTICE "clps flash: using %s partition "
+ "definition\n", part_type);
+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
+ }
+
+ /* Always succeeds. */
+}
+
+static void __exit clps_destroy_partitions(void)
+{
+ if (parsed_parts)
+ kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init clps_mtd_init(void)
+{
+ int ret;
+ int nr;
+
+ nr = clps_setup_flash();
+ if (nr < 0)
+ return nr;
+
+ ret = clps_setup_mtd(info, nr, &mymtd);
+ if (ret)
+ return ret;
+
+ clps_locate_partitions(mymtd);
+
+ return 0;
+}
+
+static void __exit clps_mtd_cleanup(void)
+{
+ clps_destroy_mtd(info, mymtd);
+ clps_destroy_partitions();
+}
+
+module_init(clps_mtd_init);
+module_exit(clps_mtd_cleanup);
+
+MODULE_AUTHOR("Rob Scott");
+MODULE_DESCRIPTION("Cirrus Logic JEDEC map driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c
index e7eea7ef53b2..f030f3447302 100644
--- a/drivers/mtd/maps/dc21285.c
+++ b/drivers/mtd/maps/dc21285.c
@@ -5,9 +5,9 @@
*
* This code is GPL
*
- * $Id: dc21285.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $
*/
-
+#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
@@ -44,15 +44,15 @@ void dc21285_copy_from(struct map_info *map, void *to, unsigned long from, ssize
void dc21285_write8(struct map_info *map, __u8 d, unsigned long adr)
{
- *CSR_ROMWRITEREG = adr;
+ *CSR_ROMWRITEREG = adr & 3;
adr &= ~3;
*(__u8*)(map->map_priv_1 + adr) = d;
}
void dc21285_write16(struct map_info *map, __u16 d, unsigned long adr)
{
- *CSR_ROMWRITEREG = adr;
- adr &= ~1;
+ *CSR_ROMWRITEREG = adr & 3;
+ adr &= ~3;
*(__u16*)(map->map_priv_1 + adr) = d;
}
@@ -131,7 +131,7 @@ int __init init_dc21285(void)
dc21285_map.buswidth*8);
/* Let's map the flash area */
- dc21285_map.map_priv_1 = (unsigned long)__ioremap(DC21285_FLASH, 16*1024*1024, 0);
+ dc21285_map.map_priv_1 = (unsigned long)ioremap(DC21285_FLASH, 16*1024*1024);
if (!dc21285_map.map_priv_1) {
printk("Failed to ioremap\n");
return -EIO;
@@ -139,21 +139,22 @@ int __init init_dc21285(void)
mymtd = do_map_probe("cfi_probe", &dc21285_map);
if (mymtd) {
- int nrparts;
+ int nrparts = 0;
mymtd->module = THIS_MODULE;
/* partition fixup */
+#ifdef CONFIG_MTD_REDBOOT_PARTS
nrparts = parse_redboot_partitions(mymtd, &dc21285_parts);
- if (nrparts <=0) {
+#endif
+ if (nrparts > 0) {
+ add_mtd_partitions(mymtd, dc21285_parts, nrparts);
+ } else if (nrparts == 0) {
printk(KERN_NOTICE "RedBoot partition table failed\n");
- iounmap((void *)dc21285_map.map_priv_1);
- return -ENXIO;
+ add_mtd_device(mymtd);
}
- add_mtd_partitions(mymtd, dc21285_parts, nrparts);
-
/*
* Flash timing is determined with bits 19-16 of the
* CSR_SA110_CNTL. The value is the number of wait cycles, or
diff --git a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c
new file mode 100644
index 000000000000..405429d92735
--- /dev/null
+++ b/drivers/mtd/maps/edb7312.c
@@ -0,0 +1,202 @@
+/*
+ * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on Cogent EDB7312 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR 0x00000000 /* physical properties of flash */
+#define WINDOW_SIZE 0x01000000
+#define BUSWIDTH 2
+#define FLASH_BLOCKSIZE_MAIN 0x20000
+#define FLASH_NUMBLOCKS_MAIN 128
+/* can be "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "cfi_probe", 0 }
+
+#define MSG_PREFIX "EDB7312-NOR:" /* prefix for our printk()'s */
+#define MTDID "edb7312-nor" /* for mtdparts= partitioning */
+
+static struct mtd_info *mymtd;
+
+__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void edb7312nor_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+struct map_info edb7312nor_map = {
+ name: "NOR flash on EDB7312",
+ size: WINDOW_SIZE,
+ buswidth: BUSWIDTH,
+ read8: edb7312nor_read8,
+ read16: edb7312nor_read16,
+ read32: edb7312nor_read32,
+ copy_from: edb7312nor_copy_from,
+ write8: edb7312nor_write8,
+ write16: edb7312nor_write16,
+ write32: edb7312nor_write32,
+ copy_to: edb7312nor_copy_to
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff
+ */
+static struct mtd_partition static_partitions[3] =
+{
+ {
+ name: "ARMboot",
+ size: 0x40000,
+ offset: 0
+ },
+ {
+ name: "Kernel",
+ size: 0x200000,
+ offset: 0x40000
+ },
+ {
+ name: "RootFS",
+ size: 0xDC0000,
+ offset: 0x240000
+ },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id);
+#endif
+
+#endif
+
+static int mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts = 0;
+
+int __init init_edb7312nor(void)
+{
+ static const char *rom_probe_types[] = PROBETYPES;
+ const char **type;
+ const char *part_type = 0;
+
+ printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n",
+ WINDOW_SIZE, WINDOW_ADDR);
+ edb7312nor_map.map_priv_1 = (unsigned long)
+ ioremap(WINDOW_ADDR, WINDOW_SIZE);
+
+ if (!edb7312nor_map.map_priv_1) {
+ printk(MSG_PREFIX "failed to ioremap\n");
+ return -EIO;
+ }
+
+ mymtd = 0;
+ type = rom_probe_types;
+ for(; !mymtd && *type; type++) {
+ mymtd = do_map_probe(*type, &edb7312nor_map);
+ }
+ if (mymtd) {
+ mymtd->module = THIS_MODULE;
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID);
+ if (mtd_parts_nb > 0)
+ part_type = "command line";
+#endif
+ if (mtd_parts_nb == 0)
+ {
+ mtd_parts = static_partitions;
+ mtd_parts_nb = NB_OF(static_partitions);
+ part_type = "static";
+ }
+#endif
+ add_mtd_device(mymtd);
+ if (mtd_parts_nb == 0)
+ printk(KERN_NOTICE MSG_PREFIX "no partition info available\n");
+ else
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "using %s partition definition\n", part_type);
+ add_mtd_partitions(mymtd, mtd_parts, mtd_parts_nb);
+ }
+ return 0;
+ }
+
+ iounmap((void *)edb7312nor_map.map_priv_1);
+ return -ENXIO;
+}
+
+static void __exit cleanup_edb7312nor(void)
+{
+ if (mymtd) {
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (edb7312nor_map.map_priv_1) {
+ iounmap((void *)edb7312nor_map.map_priv_1);
+ edb7312nor_map.map_priv_1 = 0;
+ }
+}
+
+module_init(init_edb7312nor);
+module_exit(cleanup_edb7312nor);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>");
+MODULE_DESCRIPTION("Generic configurable MTD map driver");
diff --git a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c
new file mode 100644
index 000000000000..cb4c76e4bb71
--- /dev/null
+++ b/drivers/mtd/maps/epxa10db-flash.c
@@ -0,0 +1,233 @@
+/*
+ * Flash memory access on EPXA based devices
+ *
+ * (C) 2000 Nicolas Pitre <nico@cam.org>
+ * Copyright (C) 2001 Altera Corporation
+ * Copyright (C) 2001 Red Hat, Inc.
+ *
+ * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/hardware.h>
+#ifdef CONFIG_EPXA10DB
+#define BOARD_NAME "EPXA10DB"
+#else
+#define BOARD_NAME "EPXA1DB"
+#endif
+
+static int nr_parts = 0;
+static struct mtd_partition *parts;
+
+static struct mtd_info *mymtd;
+
+extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **);
+static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+
+static __u8 epxa_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+static __u16 epxa_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+static __u32 epxa_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, (void *)(map->map_priv_1 + from), len);
+}
+
+static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio((void *)(map->map_priv_1 + to), from, len);
+}
+
+
+
+static struct map_info epxa_map = {
+ name: "EPXA flash",
+ size: FLASH_SIZE,
+ buswidth: 2,
+ read8: epxa_read8,
+ read16: epxa_read16,
+ read32: epxa_read32,
+ copy_from: epxa_copy_from,
+ write8: epxa_write8,
+ write16: epxa_write16,
+ write32: epxa_write32,
+ copy_to: epxa_copy_to
+};
+
+
+static int __init epxa_mtd_init(void)
+{
+ int i;
+
+ printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START);
+ epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE);
+ if (!epxa_map.map_priv_1) {
+ printk("Failed to ioremap %s flash\n",BOARD_NAME);
+ return -EIO;
+ }
+
+ mymtd = do_map_probe("cfi_probe", &epxa_map);
+ if (!mymtd) {
+ iounmap((void *)epxa_map.map_priv_1);
+ return -ENXIO;
+ }
+
+ mymtd->module = THIS_MODULE;
+
+ /* Unlock the flash device. */
+ if(mymtd->unlock){
+ for (i=0; i<mymtd->numeraseregions;i++){
+ int j;
+ for(j=0;j<mymtd->eraseregions[i].numblocks;j++){
+ mymtd->unlock(mymtd,mymtd->eraseregions[i].offset + j * mymtd->eraseregions[i].erasesize,mymtd->eraseregions[i].erasesize);
+ }
+ }
+ }
+
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mymtd, &parts);
+
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+#endif
+#ifdef CONFIG_MTD_AFS_PARTS
+ nr_parts = parse_afs_partitions(mymtd, &parts);
+
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+#endif
+
+ /* No recognised partitioning schemes found - use defaults */
+ nr_parts = epxa_default_partitions(mymtd, &parts);
+ if (nr_parts > 0) {
+ add_mtd_partitions(mymtd, parts, nr_parts);
+ return 0;
+ }
+
+ /* If all else fails... */
+ add_mtd_device(mymtd);
+ return 0;
+}
+
+static void __exit epxa_mtd_cleanup(void)
+{
+ if (mymtd) {
+ if (nr_parts)
+ del_mtd_partitions(mymtd);
+ else
+ del_mtd_device(mymtd);
+ map_destroy(mymtd);
+ }
+ if (epxa_map.map_priv_1) {
+ iounmap((void *)epxa_map.map_priv_1);
+ epxa_map.map_priv_1 = 0;
+ }
+}
+
+
+/*
+ * This will do for now, once we decide which bootldr we're finally
+ * going to use then we'll remove this function and do it properly
+ *
+ * Partions are currently (as offsets from base of flash):
+ * 0x00000000 - 0x003FFFFF - bootloader (!)
+ * 0x00400000 - 0x00FFFFFF - Flashdisk
+ */
+
+static int __init epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts)
+{
+ struct mtd_partition *parts;
+ int ret, i;
+ int npartitions = 0;
+ char *names;
+ const char *name = "jffs";
+
+ printk("Using default partitions for %s\n",BOARD_NAME);
+ npartitions=1;
+ parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL);
+ memzero(parts,npartitions*sizeof(*parts)+strlen(name));
+ if (!parts) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ i=0;
+ names = (char *)&parts[npartitions];
+ parts[i].name = names;
+ names += strlen(name) + 1;
+ strcpy(parts[i].name, name);
+
+#ifdef CONFIG_EPXA10DB
+ parts[i].size = FLASH_SIZE-0x00400000;
+ parts[i].offset = 0x00400000;
+#else
+ parts[i].size = FLASH_SIZE-0x00180000;
+ parts[i].offset = 0x00180000;
+#endif
+
+ out:
+ *pparts = parts;
+ return npartitions;
+}
+
+
+module_init(epxa_mtd_init);
+module_exit(epxa_mtd_cleanup);
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera epxa mtd flash map");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c
new file mode 100644
index 000000000000..98fd322e9523
--- /dev/null
+++ b/drivers/mtd/maps/fortunet.c
@@ -0,0 +1,309 @@
+/* fortunet.c memory map
+ *
+ * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+#define MAX_NUM_REGIONS 4
+#define MAX_NUM_PARTITIONS 8
+
+#define DEF_WINDOW_ADDR_PHY 0x00000000
+#define DEF_WINDOW_SIZE 0x00800000 // 8 Mega Bytes
+
+#define MTD_FORTUNET_PK "MTD FortuNet: "
+
+#define MAX_NAME_SIZE 128
+
+struct map_region
+{
+ int window_addr_phyical;
+ int altbuswidth;
+ struct map_info map_info;
+ struct mtd_info *mymtd;
+ struct mtd_partition parts[MAX_NUM_PARTITIONS];
+ char map_name[MAX_NAME_SIZE];
+ char parts_name[MAX_NUM_PARTITIONS][MAX_NAME_SIZE];
+};
+
+static struct map_region map_regions[MAX_NUM_REGIONS];
+static int map_regions_set[MAX_NUM_REGIONS] = {0,0,0,0};
+static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0};
+
+
+__u8 fortunet_read8(struct map_info *map, unsigned long ofs)
+{
+ return *(__u8 *)(map->map_priv_1 + ofs);
+}
+
+__u16 fortunet_read16(struct map_info *map, unsigned long ofs)
+{
+ return *(__u16 *)(map->map_priv_1 + ofs);
+}
+
+__u32 fortunet_read32(struct map_info *map, unsigned long ofs)
+{
+ return *(__u32 *)(map->map_priv_1 + ofs);
+}
+
+void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy(to, (void *)(map->map_priv_1 + from), len);
+}
+
+void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ *(__u8 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ *(__u16 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ *(__u32 *)(map->map_priv_1 + adr) = d;
+}
+
+void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy((void *)(map->map_priv_1 + to), from, len);
+}
+
+struct map_info default_map = {
+ size: DEF_WINDOW_SIZE,
+ buswidth: 4,
+ read8: fortunet_read8,
+ read16: fortunet_read16,
+ read32: fortunet_read32,
+ copy_from: fortunet_copy_from,
+ write8: fortunet_write8,
+ write16: fortunet_write16,
+ write32: fortunet_write32,
+ copy_to: fortunet_copy_to
+};
+
+static char * __init get_string_option(char *dest,int dest_size,char *sor)
+{
+ if(!dest_size)
+ return sor;
+ dest_size--;
+ while(*sor)
+ {
+ if(*sor==',')
+ {
+ sor++;
+ break;
+ }
+ else if(*sor=='\"')
+ {
+ sor++;
+ while(*sor)
+ {
+ if(*sor=='\"')
+ {
+ sor++;
+ break;
+ }
+ *dest = *sor;
+ dest++;
+ sor++;
+ dest_size--;
+ if(!dest_size)
+ {
+ *dest = 0;
+ return sor;
+ }
+ }
+ }
+ else
+ {
+ *dest = *sor;
+ dest++;
+ sor++;
+ dest_size--;
+ if(!dest_size)
+ {
+ *dest = 0;
+ return sor;
+ }
+ }
+ }
+ *dest = 0;
+ return sor;
+}
+
+static int __init MTD_New_Region(char *line)
+{
+ char string[MAX_NAME_SIZE];
+ int params[6];
+ get_options (get_string_option(string,sizeof(string),line),6,params);
+ if(params[0]<1)
+ {
+ printk(MTD_FORTUNET_PK "Bad paramters for MTD Region "
+ " name,region-number[,base,size,buswidth,altbuswidth]\n");
+ return 1;
+ }
+ if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+ {
+ printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+ params[1],MAX_NUM_REGIONS-1);
+ return 1;
+ }
+ memset(&map_regions[params[1]],0,sizeof(map_regions[params[1]]));
+ memcpy(&map_regions[params[1]].map_info,
+ &default_map,sizeof(map_regions[params[1]].map_info));
+ map_regions_set[params[1]] = 1;
+ map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+ map_regions[params[1]].altbuswidth = 2;
+ map_regions[params[1]].mymtd = NULL;
+ map_regions[params[1]].map_info.name = map_regions[params[1]].map_name;
+ strcpy(map_regions[params[1]].map_info.name,string);
+ if(params[0]>1)
+ {
+ map_regions[params[1]].window_addr_phyical = params[2];
+ }
+ if(params[0]>2)
+ {
+ map_regions[params[1]].map_info.size = params[3];
+ }
+ if(params[0]>3)
+ {
+ map_regions[params[1]].map_info.buswidth = params[4];
+ }
+ if(params[0]>4)
+ {
+ map_regions[params[1]].altbuswidth = params[5];
+ }
+ return 1;
+}
+
+static int __init MTD_New_Partion(char *line)
+{
+ char string[MAX_NAME_SIZE];
+ int params[4];
+ get_options (get_string_option(string,sizeof(string),line),4,params);
+ if(params[0]<3)
+ {
+ printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion "
+ " name,region-number,size,offset\n");
+ return 1;
+ }
+ if((params[1]<0)||(params[1]>=MAX_NUM_REGIONS))
+ {
+ printk(MTD_FORTUNET_PK "Bad region index of %d only have 0..%u regions\n",
+ params[1],MAX_NUM_REGIONS-1);
+ return 1;
+ }
+ if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS)
+ {
+ printk(MTD_FORTUNET_PK "Out of space for partion in this region\n");
+ return 1;
+ }
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].name =
+ map_regions[params[1]]. parts_name[map_regions_parts[params[1]]];
+ strcpy(map_regions[params[1]].parts[map_regions_parts[params[1]]].name,string);
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].size =
+ params[2];
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].offset =
+ params[3];
+ map_regions[params[1]].parts[map_regions_parts[params[1]]].mask_flags = 0;
+ map_regions_parts[params[1]]++;
+ return 1;
+}
+
+__setup("MTD_Region=", MTD_New_Region);
+__setup("MTD_Partion=", MTD_New_Partion);
+
+int __init init_fortunet(void)
+{
+ int ix,iy;
+ for(iy=ix=0;ix<MAX_NUM_REGIONS;ix++)
+ {
+ if(map_regions_parts[ix]&&(!map_regions_set[ix]))
+ {
+ printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n",
+ ix);
+ memset(&map_regions[ix],0,sizeof(map_regions[ix]));
+ memcpy(&map_regions[ix].map_info,&default_map,
+ sizeof(map_regions[ix].map_info));
+ map_regions_set[ix] = 1;
+ map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY;
+ map_regions[ix].altbuswidth = 2;
+ map_regions[ix].mymtd = NULL;
+ map_regions[ix].map_info.name = map_regions[ix].map_name;
+ strcpy(map_regions[ix].map_info.name,"FORTUNET");
+ }
+ if(map_regions_set[ix])
+ {
+ iy++;
+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly "
+ " address %x size %x\n",
+ map_regions[ix].map_info.name,
+ map_regions[ix].window_addr_phyical,
+ map_regions[ix].map_info.size);
+ map_regions[ix].map_info.map_priv_1 =
+ (int)ioremap_nocache(
+ map_regions[ix].window_addr_phyical,
+ map_regions[ix].map_info.size);
+ if(!map_regions[ix].map_info.map_priv_1)
+ {
+ printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n",
+ map_regions[ix].map_info.name);
+ return -ENXIO;
+ }
+ printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n",
+ map_regions[ix].map_info.name,
+ map_regions[ix].map_info.map_priv_1);
+ map_regions[ix].mymtd = do_map_probe("cfi_probe",
+ &map_regions[ix].map_info);
+ if((!map_regions[ix].mymtd)&&(
+ map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth))
+ {
+ printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth "
+ "for %s flash.\n",
+ map_regions[ix].map_info.name);
+ map_regions[ix].map_info.buswidth =
+ map_regions[ix].altbuswidth;
+ map_regions[ix].mymtd = do_map_probe("cfi_probe",
+ &map_regions[ix].map_info);
+ }
+ map_regions[ix].mymtd->module = THIS_MODULE;
+ add_mtd_partitions(map_regions[ix].mymtd,
+ map_regions[ix].parts,map_regions_parts[ix]);
+ }
+ }
+ if(iy)
+ return 0;
+ return -ENXIO;
+}
+
+static void __exit cleanup_fortunet(void)
+{
+ int ix;
+ for(ix=0;ix<MAX_NUM_REGIONS;ix++)
+ {
+ if(map_regions_set[ix])
+ {
+ if( map_regions[ix].mymtd )
+ {
+ del_mtd_partitions( map_regions[ix].mymtd );
+ map_destroy( map_regions[ix].mymtd );
+ }
+ iounmap((void *)map_regions[ix].map_info.map_priv_1);
+ }
+ }
+}
+
+module_init(init_fortunet);
+module_exit(cleanup_fortunet);
+
+MODULE_AUTHOR("FortuNet, Inc.");
+MODULE_DESCRIPTION("MTD map driver for FortuNet boards");
diff --git a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c
new file mode 100644
index 000000000000..3dc382bc9511
--- /dev/null
+++ b/drivers/mtd/maps/impa7.c
@@ -0,0 +1,234 @@
+/*
+ * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $
+ *
+ * Handle mapping of the NOR flash on implementa A7 boards
+ *
+ * Copyright 2002 SYSGO Real-Time Solutions GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/config.h>
+
+#ifdef CONFIG_MTD_PARTITIONS
+#include <linux/mtd/partitions.h>
+#endif
+
+#define WINDOW_ADDR0 0x00000000 /* physical properties of flash */
+#define WINDOW_SIZE0 0x00800000
+#define WINDOW_ADDR1 0x10000000 /* physical properties of flash */
+#define WINDOW_SIZE1 0x00800000
+#define NUM_FLASHBANKS 2
+#define BUSWIDTH 4
+
+/* can be { "cfi_probe", "jedec_probe", "map_rom", 0 }; */
+#define PROBETYPES { "jedec_probe", 0 }
+
+#define MSG_PREFIX "impA7:" /* prefix for our printk()'s */
+#define MTDID "impa7-%d" /* for mtdparts= partitioning */
+
+static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 };
+
+__u8 impa7_read8(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readb(map->map_priv_1 + ofs);
+}
+
+__u16 impa7_read16(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readw(map->map_priv_1 + ofs);
+}
+
+__u32 impa7_read32(struct map_info *map, unsigned long ofs)
+{
+ return __raw_readl(map->map_priv_1 + ofs);
+}
+
+void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ memcpy_fromio(to, map->map_priv_1 + from, len);
+}
+
+void impa7_write8(struct map_info *map, __u8 d, unsigned long adr)
+{
+ __raw_writeb(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_write16(struct map_info *map, __u16 d, unsigned long adr)
+{
+ __raw_writew(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_write32(struct map_info *map, __u32 d, unsigned long adr)
+{
+ __raw_writel(d, map->map_priv_1 + adr);
+ mb();
+}
+
+void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ memcpy_toio(map->map_priv_1 + to, from, len);
+}
+
+static struct map_info impa7_map[NUM_FLASHBANKS] = {
+ {
+ name: "impA7 NOR Flash Bank #0",
+ size: WINDOW_SIZE0,
+ buswidth: BUSWIDTH,
+ read8: impa7_read8,
+ read16: impa7_read16,
+ read32: impa7_read32,
+ copy_from: impa7_copy_from,
+ write8: impa7_write8,
+ write16: impa7_write16,
+ write32: impa7_write32,
+ copy_to: impa7_copy_to
+ },
+ {
+ name: "impA7 NOR Flash Bank #1",
+ size: WINDOW_SIZE1,
+ buswidth: BUSWIDTH,
+ read8: impa7_read8,
+ read16: impa7_read16,
+ read32: impa7_read32,
+ copy_from: impa7_copy_from,
+ write8: impa7_write8,
+ write16: impa7_write16,
+ write32: impa7_write32,
+ copy_to: impa7_copy_to
+ },
+};
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+/*
+ * MTD partitioning stuff
+ */
+static struct mtd_partition static_partitions[] =
+{
+ {
+ name: "FileSystem",
+ size: 0x800000,
+ offset: 0x00000000
+ },
+};
+
+#define NB_OF(x) (sizeof (x) / sizeof (x[0]))
+
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+int parse_cmdline_partitions(struct mtd_info *master,
+ struct mtd_partition **pparts,
+ const char *mtd_id);
+#endif
+
+#endif
+
+static int mtd_parts_nb = 0;
+static struct mtd_partition *mtd_parts = 0;
+
+int __init init_impa7(void)
+{
+ static const char *rom_probe_types[] = PROBETYPES;
+ const char **type;
+ const char *part_type = 0;
+ int i;
+ static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = {
+ { WINDOW_ADDR0, WINDOW_SIZE0 },
+ { WINDOW_ADDR1, WINDOW_SIZE1 },
+ };
+ char mtdid[10];
+ int devicesfound = 0;
+
+ for(i=0; i<NUM_FLASHBANKS; i++)
+ {
+ printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n",
+ pt[i].size, pt[i].addr);
+ impa7_map[i].map_priv_1 = (unsigned long)
+ ioremap(pt[i].addr, pt[i].size);
+
+ if (!impa7_map[i].map_priv_1) {
+ printk(MSG_PREFIX "failed to ioremap\n");
+ return -EIO;
+ }
+
+ impa7_mtd[i] = 0;
+ type = rom_probe_types;
+ for(; !impa7_mtd[i] && *type; type++) {
+ impa7_mtd[i] = do_map_probe(*type, &impa7_map[i]);
+ }
+
+ if (impa7_mtd[i])
+ {
+ impa7_mtd[i]->module = THIS_MODULE;
+ add_mtd_device(impa7_mtd[i]);
+ devicesfound++;
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ sprintf(mtdid, MTDID, i);
+ mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i],
+ &mtd_parts,
+ mtdid);
+ if (mtd_parts_nb > 0)
+ part_type = "command line";
+#endif
+ if (mtd_parts_nb <= 0)
+ {
+ mtd_parts = static_partitions;
+ mtd_parts_nb = NB_OF(static_partitions);
+ part_type = "static";
+ }
+ if (mtd_parts_nb <= 0)
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "no partition info available\n");
+ }
+ else
+ {
+ printk(KERN_NOTICE MSG_PREFIX
+ "using %s partition definition\n",
+ part_type);
+ add_mtd_partitions(impa7_mtd[i],
+ mtd_parts, mtd_parts_nb);
+ }
+#endif
+ }
+ else
+ iounmap((void *)impa7_map[i].map_priv_1);
+ }
+ return devicesfound == 0 ? -ENXIO : 0;
+}
+
+static void __exit cleanup_impa7(void)
+{
+ int i;
+ for (i=0; i<NUM_FLASHBANKS; i++)
+ {
+ if (impa7_mtd[i])
+ {
+ del_mtd_device(impa7_mtd[i]);
+ map_destroy(impa7_mtd[i]);
+ }
+ if (impa7_map[i].map_priv_1)
+ {
+ iounmap((void *)impa7_map[i].map_priv_1);
+ impa7_map[i].map_priv_1 = 0;
+ }
+ }
+}
+
+module_init(init_impa7);
+module_exit(cleanup_impa7);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Bartusek <pba@sysgo.de>");
+MODULE_DESCRIPTION("MTD map driver for implementa impA7");
diff --git a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c
index cb3cb05766d1..3a301135831b 100644
--- a/drivers/mtd/maps/iq80310.c
+++ b/drivers/mtd/maps/iq80310.c
@@ -1,5 +1,5 @@
/*
- * $Id: iq80310.c,v 1.8 2001/10/02 15:05:14 dwmw2 Exp $
+ * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $
*
* Mapping for the Intel XScale IQ80310 evaluation board
*
@@ -116,7 +116,7 @@ static int __init init_iq80310(void)
int parsed_nr_parts = 0;
char *part_type = "static";
- iq80310_map.map_priv_1 = (unsigned long)__ioremap(WINDOW_ADDR, WINDOW_SIZE, 0);
+ iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);
if (!iq80310_map.map_priv_1) {
printk("Failed to ioremap\n");
return -EIO;
@@ -161,7 +161,6 @@ static void __exit cleanup_iq80310(void)
}
if (iq80310_map.map_priv_1)
iounmap((void *)iq80310_map.map_priv_1);
- return 0;
}
module_init(init_iq80310);
diff --git a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c
new file mode 100644
index 000000000000..ccc854980c6f
--- /dev/null
+++ b/drivers/mtd/maps/pci.c
@@ -0,0 +1,385 @@
+/*
+ * linux/drivers/mtd/maps/pci.c
+ *
+ * Copyright (C) 2001 Russell King, All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $
+ *
+ * Generic PCI memory map driver. We support the following boards:
+ * - Intel IQ80310 ATU.
+ * - Intel EBSA285 (blank rom programming mode). Tested working 27/09/2001
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+
+struct map_pci_info;
+
+struct mtd_pci_info {
+ int (*init)(struct pci_dev *dev, struct map_pci_info *map);
+ void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+ unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+ const char *map_name;
+};
+
+struct map_pci_info {
+ struct map_info map;
+ void *base;
+ void (*exit)(struct pci_dev *dev, struct map_pci_info *map);
+ unsigned long (*translate)(struct map_pci_info *map, unsigned long ofs);
+ struct pci_dev *dev;
+};
+
+/*
+ * Intel IOP80310 Flash driver
+ */
+
+static int
+intel_iq80310_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+ u32 win_base;
+
+ map->map.buswidth = 1;
+ map->map.size = 0x00800000;
+ map->base = ioremap_nocache(pci_resource_start(dev, 0),
+ pci_resource_len(dev, 0));
+
+ if (!map->base)
+ return -ENOMEM;
+
+ /*
+ * We want to base the memory window at Xscale
+ * bus address 0, not 0x1000.
+ */
+ pci_read_config_dword(dev, 0x44, &win_base);
+ pci_write_config_dword(dev, 0x44, 0);
+
+ map->map.map_priv_2 = win_base;
+
+ return 0;
+}
+
+static void
+intel_iq80310_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+ if (map->base)
+ iounmap((void *)map->base);
+ pci_write_config_dword(dev, 0x44, map->map.map_priv_2);
+}
+
+static unsigned long
+intel_iq80310_translate(struct map_pci_info *map, unsigned long ofs)
+{
+ unsigned long page_addr = ofs & 0x00400000;
+
+ /*
+ * This mundges the flash location so we avoid
+ * the first 80 bytes (they appear to read nonsense).
+ */
+ if (page_addr) {
+ writel(0x00000008, map->base + 0x1558);
+ writel(0x00000000, map->base + 0x1550);
+ } else {
+ writel(0x00000007, map->base + 0x1558);
+ writel(0x00800000, map->base + 0x1550);
+ ofs += 0x00800000;
+ }
+
+ return ofs;
+}
+
+static struct mtd_pci_info intel_iq80310_info = {
+ init: intel_iq80310_init,
+ exit: intel_iq80310_exit,
+ translate: intel_iq80310_translate,
+ map_name: "cfi_probe",
+};
+
+/*
+ * Intel DC21285 driver
+ */
+
+static int
+intel_dc21285_init(struct pci_dev *dev, struct map_pci_info *map)
+{
+ unsigned long base, len;
+
+ base = pci_resource_start(dev, PCI_ROM_RESOURCE);
+ len = pci_resource_len(dev, PCI_ROM_RESOURCE);
+
+ if (!len || !base) {
+ /*
+ * No ROM resource
+ */
+ base = pci_resource_start(dev, 2);
+ len = pci_resource_len(dev, 2);
+
+ /*
+ * We need to re-allocate PCI BAR2 address range to the
+ * PCI ROM BAR, and disable PCI BAR2.
+ */
+ } else {
+ /*
+ * Hmm, if an address was allocated to the ROM resource, but
+ * not enabled, should we be allocating a new resource for it
+ * or simply enabling it?
+ */
+ if (!(pci_resource_flags(dev, PCI_ROM_RESOURCE) &
+ PCI_ROM_ADDRESS_ENABLE)) {
+ u32 val;
+ pci_resource_flags(dev, PCI_ROM_RESOURCE) |= PCI_ROM_ADDRESS_ENABLE;
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+ val |= PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+ printk("%s: enabling expansion ROM\n", dev->slot_name);
+ }
+ }
+
+ if (!len || !base)
+ return -ENXIO;
+
+ map->map.buswidth = 4;
+ map->map.size = len;
+ map->base = ioremap_nocache(base, len);
+
+ if (!map->base)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static void
+intel_dc21285_exit(struct pci_dev *dev, struct map_pci_info *map)
+{
+ u32 val;
+
+ if (map->base)
+ iounmap((void *)map->base);
+
+ /*
+ * We need to undo the PCI BAR2/PCI ROM BAR address alteration.
+ */
+ pci_resource_flags(dev, PCI_ROM_RESOURCE) &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_read_config_dword(dev, PCI_ROM_ADDRESS, &val);
+ val &= ~PCI_ROM_ADDRESS_ENABLE;
+ pci_write_config_dword(dev, PCI_ROM_ADDRESS, val);
+}
+
+static unsigned long
+intel_dc21285_translate(struct map_pci_info *map, unsigned long ofs)
+{
+ return ofs & 0x00ffffc0 ? ofs : (ofs ^ (1 << 5));
+}
+
+static struct mtd_pci_info intel_dc21285_info = {
+ init: intel_dc21285_init,
+ exit: intel_dc21285_exit,
+ translate: intel_dc21285_translate,
+ map_name: "jedec_probe",
+};
+
+/*
+ * PCI device ID table
+ */
+
+static struct pci_device_id mtd_pci_ids[] __devinitdata = {
+ {
+ vendor: PCI_VENDOR_ID_INTEL,
+ device: 0x530d,
+ subvendor: PCI_ANY_ID,
+ subdevice: PCI_ANY_ID,
+ class: PCI_CLASS_MEMORY_OTHER << 8,
+ class_mask: 0xffff00,
+ driver_data: (unsigned long)&intel_iq80310_info,
+ },
+ {
+ vendor: PCI_VENDOR_ID_DEC,
+ device: PCI_DEVICE_ID_DEC_21285,
+ subvendor: 0, /* DC21285 defaults to 0 on reset */
+ subdevice: 0, /* DC21285 defaults to 0 on reset */
+ class: 0,
+ class_mask: 0,
+ driver_data: (unsigned long)&intel_dc21285_info,
+ },
+ { 0, }
+};
+
+/*
+ * Generic code follows.
+ */
+
+static u8 mtd_pci_read8(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u8 val = readb(map->base + map->translate(map, ofs));
+// printk("read8 : %08lx => %02x\n", ofs, val);
+ return val;
+}
+
+static u16 mtd_pci_read16(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u16 val = readw(map->base + map->translate(map, ofs));
+// printk("read16: %08lx => %04x\n", ofs, val);
+ return val;
+}
+
+static u32 mtd_pci_read32(struct map_info *_map, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ u32 val = readl(map->base + map->translate(map, ofs));
+// printk("read32: %08lx => %08x\n", ofs, val);
+ return val;
+}
+
+static void mtd_pci_copyfrom(struct map_info *_map, void *to, unsigned long from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_fromio(to, map->base + map->translate(map, from), len);
+}
+
+static void mtd_pci_write8(struct map_info *_map, u8 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write8 : %08lx <= %02x\n", ofs, val);
+ writeb(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write16(struct map_info *_map, u16 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write16: %08lx <= %04x\n", ofs, val);
+ writew(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_write32(struct map_info *_map, u32 val, unsigned long ofs)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+// printk("write32: %08lx <= %08x\n", ofs, val);
+ writel(val, map->base + map->translate(map, ofs));
+}
+
+static void mtd_pci_copyto(struct map_info *_map, unsigned long to, const void *from, ssize_t len)
+{
+ struct map_pci_info *map = (struct map_pci_info *)_map;
+ memcpy_toio(map->base + map->translate(map, to), from, len);
+}
+
+static struct map_info mtd_pci_map = {
+ read8: mtd_pci_read8,
+ read16: mtd_pci_read16,
+ read32: mtd_pci_read32,
+ copy_from: mtd_pci_copyfrom,
+ write8: mtd_pci_write8,
+ write16: mtd_pci_write16,
+ write32: mtd_pci_write32,
+ copy_to: mtd_pci_copyto,
+};
+
+static int __devinit
+mtd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct mtd_pci_info *info = (struct mtd_pci_info *)id->driver_data;
+ struct map_pci_info *map = NULL;
+ struct mtd_info *mtd = NULL;
+ int err;
+
+ err = pci_enable_device(dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(dev, "pci mtd");
+ if (err)
+ goto out;
+
+ map = kmalloc(sizeof(*map), GFP_KERNEL);
+ err = -ENOMEM;
+ if (!map)
+ goto release;
+
+ map->map = mtd_pci_map;
+ map->map.name = dev->slot_name;
+ map->dev = dev;
+ map->exit = info->exit;
+ map->translate = info->translate;
+
+ err = info->init(dev, map);
+ if (err)
+ goto release;
+
+ /* tsk - do_map_probe should take const char * */
+ mtd = do_map_probe((char *)info->map_name, &map->map);
+ err = -ENODEV;
+ if (!mtd)
+ goto release;
+
+ mtd->module = THIS_MODULE;
+ add_mtd_device(mtd);
+
+ pci_set_drvdata(dev, mtd);
+
+ return 0;
+
+release:
+ if (mtd)
+ map_destroy(mtd);
+
+ if (map) {
+ map->exit(dev, map);
+ kfree(map);
+ }
+
+ pci_release_regions(dev);
+out:
+ return err;
+}
+
+static void __devexit
+mtd_pci_remove(struct pci_dev *dev)
+{
+ struct mtd_info *mtd = pci_get_drvdata(dev);
+ struct map_pci_info *map = mtd->priv;
+
+ del_mtd_device(mtd);
+ map_destroy(mtd);
+ map->exit(dev, map);
+ kfree(map);
+
+ pci_set_drvdata(dev, NULL);
+ pci_release_regions(dev);
+}
+
+static struct pci_driver mtd_pci_driver = {
+ name: "MTD PCI",
+ probe: mtd_pci_probe,
+ remove: mtd_pci_remove,
+ id_table: mtd_pci_ids,
+};
+
+static int __init mtd_pci_maps_init(void)
+{
+ return pci_module_init(&mtd_pci_driver);
+}
+
+static void __exit mtd_pci_maps_exit(void)
+{
+ pci_unregister_driver(&mtd_pci_driver);
+}
+
+module_init(mtd_pci_maps_init);
+module_exit(mtd_pci_maps_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+MODULE_DESCRIPTION("Generic PCI map driver");
+MODULE_DEVICE_TABLE(pci, mtd_pci_ids);
+
diff --git a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c
new file mode 100644
index 000000000000..fb87cdd8b873
--- /dev/null
+++ b/drivers/mtd/maps/pcmciamtd.c
@@ -0,0 +1,893 @@
+/*
+ * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $
+ *
+ * pcmciamtd.c - MTD driver for PCMCIA flash memory cards
+ *
+ * Author: Simon Evans <spse@secret.org.uk>
+ *
+ * Copyright (C) 2002 Simon Evans
+ *
+ * Licence: GPL
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include <linux/mtd/map.h>
+
+#ifdef CONFIG_MTD_DEBUG
+static int debug = CONFIG_MTD_DEBUG_VERBOSE;
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Set Debug Level 0=quiet, 5=noisy");
+#undef DEBUG
+#define DEBUG(n, format, arg...) \
+ if (n <= debug) { \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ }
+
+#else
+#undef DEBUG
+#define DEBUG(n, arg...)
+static const int debug = 0;
+#endif
+
+#define err(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg)
+#define info(format, arg...) printk(KERN_INFO __FILE__ ": " format "\n" , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING __FILE__ ": " format "\n" , ## arg)
+
+
+#define DRIVER_DESC "PCMCIA Flash memory card driver"
+#define DRIVER_VERSION "$Revision: 1.36 $"
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define MAX_PCMCIA_ADDR 0x4000000
+
+struct pcmciamtd_dev {
+ struct list_head list;
+ dev_link_t link; /* PCMCIA link */
+ caddr_t win_base; /* ioremapped address of PCMCIA window */
+ unsigned int win_size; /* size of window */
+ unsigned int cardsize; /* size of whole card */
+ unsigned int offset; /* offset into card the window currently points at */
+ struct map_info pcmcia_map;
+ struct mtd_info *mtd_info;
+ u8 vpp;
+ char mtd_name[sizeof(struct cistpl_vers_1_t)];
+};
+
+
+static dev_info_t dev_info = "pcmciamtd";
+static LIST_HEAD(dev_list);
+
+/* Module parameters */
+
+/* 2 = do 16-bit transfers, 1 = do 8-bit transfers */
+static int buswidth = 2;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed;
+
+/* Force the size of an SRAM card */
+static int force_size;
+
+/* Force Vpp */
+static int vpp;
+
+/* Set Vpp */
+static int setvpp;
+
+/* Force card to be treated as FLASH, ROM or RAM */
+static int mem_type;
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_PARM(buswidth, "i");
+MODULE_PARM_DESC(buswidth, "Set buswidth (1=8 bit, 2=16 bit, default=2)");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM_DESC(mem_speed, "Set memory access speed in ns");
+MODULE_PARM(force_size, "i");
+MODULE_PARM_DESC(force_size, "Force size of card in MB (1-64)");
+MODULE_PARM(setvpp, "i");
+MODULE_PARM_DESC(setvpp, "Set Vpp (0=Never, 1=On writes, 2=Always on, default=0)");
+MODULE_PARM(vpp, "i");
+MODULE_PARM_DESC(vpp, "Vpp value in 1/10ths eg 33=3.3V 120=12V (Dangerous)");
+MODULE_PARM(mem_type, "i");
+MODULE_PARM_DESC(mem_type, "Set Memory type (0=Flash, 1=RAM, 2=ROM, default=0)");
+
+
+
+static void inline cs_error(client_handle_t handle, int func, int ret)
+{
+ error_info_t err = { func, ret };
+ CardServices(ReportError, handle, &err);
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with window remapping to access whole card */
+
+static caddr_t remap_window(struct map_info *map, unsigned long to)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ window_handle_t win = (window_handle_t)map->map_priv_2;
+ memreq_t mrq;
+ int ret;
+
+ mrq.CardOffset = to & ~(dev->win_size-1);
+ if(mrq.CardOffset != dev->offset) {
+ DEBUG(2, "Remapping window from 0x%8.8x to 0x%8.8x",
+ dev->offset, mrq.CardOffset);
+ mrq.Page = 0;
+ if( (ret = CardServices(MapMemPage, win, &mrq)) != CS_SUCCESS) {
+ cs_error(dev->link.handle, MapMemPage, ret);
+ return NULL;
+ }
+ dev->offset = mrq.CardOffset;
+ }
+ return dev->win_base + (to & (dev->win_size-1));
+}
+
+
+static u8 pcmcia_read8_remap(struct map_info *map, unsigned long ofs)
+{
+ caddr_t addr;
+ u8 d;
+
+ addr = remap_window(map, ofs);
+ if(!addr)
+ return 0;
+
+ d = readb(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, addr, d);
+ return d;
+}
+
+
+static u16 pcmcia_read16_remap(struct map_info *map, unsigned long ofs)
+{
+ caddr_t addr;
+ u16 d;
+
+ addr = remap_window(map, ofs);
+ if(!addr)
+ return 0;
+
+ d = readw(addr);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, addr, d);
+ return d;
+}
+
+
+static void pcmcia_copy_from_remap(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ unsigned long win_size = dev->win_size;
+
+ DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+ while(len) {
+ int toread = win_size - (from & (win_size-1));
+ caddr_t addr;
+
+ if(toread > len)
+ toread = len;
+
+ addr = remap_window(map, from);
+ if(!addr)
+ return;
+
+ DEBUG(4, "memcpy from %p to %p len = %d", addr, to, toread);
+ memcpy_fromio(to, addr, toread);
+ len -= toread;
+ to += toread;
+ from += toread;
+ }
+}
+
+
+static void pcmcia_write8_remap(struct map_info *map, u8 d, unsigned long adr)
+{
+ caddr_t addr = remap_window(map, adr);
+
+ if(!addr)
+ return;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, addr, d);
+ writeb(d, addr);
+}
+
+
+static void pcmcia_write16_remap(struct map_info *map, u16 d, unsigned long adr)
+{
+ caddr_t addr = remap_window(map, adr);
+ if(!addr)
+ return;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, addr, d);
+ writew(d, addr);
+}
+
+
+static void pcmcia_copy_to_remap(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ unsigned long win_size = dev->win_size;
+
+ DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+ while(len) {
+ int towrite = win_size - (to & (win_size-1));
+ caddr_t addr;
+
+ if(towrite > len)
+ towrite = len;
+
+ addr = remap_window(map, to);
+ if(!addr)
+ return;
+
+ DEBUG(4, "memcpy from %p to %p len = %d", from, addr, towrite);
+ memcpy_toio(addr, from, towrite);
+ len -= towrite;
+ to += towrite;
+ from += towrite;
+ }
+}
+
+
+/* read/write{8,16} copy_{from,to} routines with direct access */
+
+static u8 pcmcia_read8(struct map_info *map, unsigned long ofs)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+ u8 d;
+
+ d = readb(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%02x", ofs, win_base + ofs, d);
+ return d;
+}
+
+
+static u16 pcmcia_read16(struct map_info *map, unsigned long ofs)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+ u16 d;
+
+ d = readw(win_base + ofs);
+ DEBUG(3, "ofs = 0x%08lx (%p) data = 0x%04x", ofs, win_base + ofs, d);
+ return d;
+}
+
+
+static void pcmcia_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "to = %p from = %lu len = %u", to, from, len);
+ memcpy_fromio(to, win_base + from, len);
+}
+
+
+static void pcmcia_write8(struct map_info *map, u8 d, unsigned long adr)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%02x", adr, win_base + adr, d);
+ writeb(d, win_base + adr);
+}
+
+
+static void pcmcia_write16(struct map_info *map, u16 d, unsigned long adr)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "adr = 0x%08lx (%p) data = 0x%04x", adr, win_base + adr, d);
+ writew(d, win_base + adr);
+}
+
+
+static void pcmcia_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)
+{
+ caddr_t win_base = (caddr_t)map->map_priv_2;
+
+ DEBUG(3, "to = %lu from = %p len = %u", to, from, len);
+ memcpy_toio(win_base + to, from, len);
+}
+
+
+static void pcmciamtd_set_vpp(struct map_info *map, int on)
+{
+ struct pcmciamtd_dev *dev = (struct pcmciamtd_dev *)map->map_priv_1;
+ dev_link_t *link = &dev->link;
+ modconf_t mod;
+ int ret;
+
+ mod.Attributes = CONF_VPP1_CHANGE_VALID | CONF_VPP2_CHANGE_VALID;
+ mod.Vcc = 0;
+ mod.Vpp1 = mod.Vpp2 = on ? dev->vpp : 0;
+
+ DEBUG(2, "dev = %p on = %d vpp = %d\n", dev, on, dev->vpp);
+ ret = CardServices(ModifyConfiguration, link->handle, &mod);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, ModifyConfiguration, ret);
+ }
+}
+
+
+/* After a card is removed, pcmciamtd_release() will unregister the
+ * device, and release the PCMCIA configuration. If the device is
+ * still open, this will be postponed until it is closed.
+ */
+
+static void pcmciamtd_release(u_long arg)
+{
+ dev_link_t *link = (dev_link_t *)arg;
+ struct pcmciamtd_dev *dev = NULL;
+ int ret;
+ struct list_head *temp1, *temp2;
+
+ DEBUG(3, "link = 0x%p", link);
+ /* Find device in list */
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev = list_entry(temp1, struct pcmciamtd_dev, list);
+ if(link == &dev->link)
+ break;
+ }
+ if(link != &dev->link) {
+ DEBUG(1, "Cant find %p in dev_list", link);
+ return;
+ }
+
+ if(dev) {
+ if(dev->mtd_info) {
+ del_mtd_device(dev->mtd_info);
+ dev->mtd_info = NULL;
+ MOD_DEC_USE_COUNT;
+ }
+ if (link->win) {
+ if(dev->win_base) {
+ iounmap(dev->win_base);
+ dev->win_base = NULL;
+ }
+ CardServices(ReleaseWindow, link->win);
+ }
+ ret = CardServices(ReleaseConfiguration, link->handle);
+ if(ret != CS_SUCCESS)
+ cs_error(link->handle, ReleaseConfiguration, ret);
+
+ }
+ link->state &= ~DEV_CONFIG;
+}
+
+
+static void card_settings(struct pcmciamtd_dev *dev, dev_link_t *link, int *new_name)
+{
+ int rc;
+ tuple_t tuple;
+ cisparse_t parse;
+ u_char buf[64];
+
+ tuple.Attributes = 0;
+ tuple.TupleData = (cisdata_t *)buf;
+ tuple.TupleDataMax = sizeof(buf);
+ tuple.TupleOffset = 0;
+ tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+
+ rc = CardServices(GetFirstTuple, link->handle, &tuple);
+ while(rc == CS_SUCCESS) {
+ rc = CardServices(GetTupleData, link->handle, &tuple);
+ if(rc != CS_SUCCESS) {
+ cs_error(link->handle, GetTupleData, rc);
+ break;
+ }
+ rc = CardServices(ParseTuple, link->handle, &tuple, &parse);
+ if(rc != CS_SUCCESS) {
+ cs_error(link->handle, ParseTuple, rc);
+ break;
+ }
+
+ switch(tuple.TupleCode) {
+ case CISTPL_FORMAT: {
+ cistpl_format_t *t = &parse.format;
+ (void)t; /* Shut up, gcc */
+ DEBUG(2, "Format type: %u, Error Detection: %u, offset = %u, length =%u",
+ t->type, t->edc, t->offset, t->length);
+ break;
+
+ }
+
+ case CISTPL_DEVICE: {
+ cistpl_device_t *t = &parse.device;
+ int i;
+ DEBUG(2, "Common memory:");
+ dev->pcmcia_map.size = t->dev[0].size;
+ for(i = 0; i < t->ndev; i++) {
+ DEBUG(2, "Region %d, type = %u", i, t->dev[i].type);
+ DEBUG(2, "Region %d, wp = %u", i, t->dev[i].wp);
+ DEBUG(2, "Region %d, speed = %u ns", i, t->dev[i].speed);
+ DEBUG(2, "Region %d, size = %u bytes", i, t->dev[i].size);
+ }
+ break;
+ }
+
+ case CISTPL_VERS_1: {
+ cistpl_vers_1_t *t = &parse.version_1;
+ int i;
+ if(t->ns) {
+ dev->mtd_name[0] = '\0';
+ for(i = 0; i < t->ns; i++) {
+ if(i)
+ strcat(dev->mtd_name, " ");
+ strcat(dev->mtd_name, t->str+t->ofs[i]);
+ }
+ }
+ DEBUG(2, "Found name: %s", dev->mtd_name);
+ break;
+ }
+
+ case CISTPL_JEDEC_C: {
+ cistpl_jedec_t *t = &parse.jedec;
+ int i;
+ for(i = 0; i < t->nid; i++) {
+ DEBUG(2, "JEDEC: 0x%02x 0x%02x", t->id[i].mfr, t->id[i].info);
+ }
+ break;
+ }
+
+ case CISTPL_DEVICE_GEO: {
+ cistpl_device_geo_t *t = &parse.device_geo;
+ int i;
+ dev->pcmcia_map.buswidth = t->geo[0].buswidth;
+ for(i = 0; i < t->ngeo; i++) {
+ DEBUG(2, "region: %d buswidth = %u", i, t->geo[i].buswidth);
+ DEBUG(2, "region: %d erase_block = %u", i, t->geo[i].erase_block);
+ DEBUG(2, "region: %d read_block = %u", i, t->geo[i].read_block);
+ DEBUG(2, "region: %d write_block = %u", i, t->geo[i].write_block);
+ DEBUG(2, "region: %d partition = %u", i, t->geo[i].partition);
+ DEBUG(2, "region: %d interleave = %u", i, t->geo[i].interleave);
+ }
+ break;
+ }
+
+ default:
+ DEBUG(2, "Unknown tuple code %d", tuple.TupleCode);
+ }
+
+ rc = CardServices(GetNextTuple, link->handle, &tuple, &parse);
+ }
+ if(!dev->pcmcia_map.size)
+ dev->pcmcia_map.size = MAX_PCMCIA_ADDR;
+
+ if(!dev->pcmcia_map.buswidth)
+ dev->pcmcia_map.buswidth = 2;
+
+ if(force_size) {
+ dev->pcmcia_map.size = force_size << 20;
+ DEBUG(2, "size forced to %dM", force_size);
+
+ }
+
+ if(buswidth) {
+ dev->pcmcia_map.buswidth = buswidth;
+ DEBUG(2, "buswidth forced to %d", buswidth);
+ }
+
+ dev->pcmcia_map.name = dev->mtd_name;
+ if(!dev->mtd_name[0]) {
+ strcpy(dev->mtd_name, "PCMCIA Memory card");
+ *new_name = 1;
+ }
+
+ DEBUG(1, "Device: Size: %lu Width:%d Name: %s",
+ dev->pcmcia_map.size, dev->pcmcia_map.buswidth << 3, dev->mtd_name);
+}
+
+
+/* pcmciamtd_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * MTD device available to the system.
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void pcmciamtd_config(dev_link_t *link)
+{
+ struct pcmciamtd_dev *dev = link->priv;
+ struct mtd_info *mtd = NULL;
+ cs_status_t status;
+ win_req_t req;
+ int last_ret = 0, last_fn = 0;
+ int ret;
+ int i;
+ config_info_t t;
+ static char *probes[] = { "jedec_probe", "cfi_probe" };
+ cisinfo_t cisinfo;
+ int new_name = 0;
+
+ DEBUG(3, "link=0x%p", link);
+
+ /* Configure card */
+ link->state |= DEV_CONFIG;
+
+ DEBUG(2, "Validating CIS");
+ ret = CardServices(ValidateCIS, link->handle, &cisinfo);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, GetTupleData, ret);
+ } else {
+ DEBUG(2, "ValidateCIS found %d chains", cisinfo.Chains);
+ }
+
+ card_settings(dev, link, &new_name);
+
+ dev->pcmcia_map.read8 = pcmcia_read8_remap;
+ dev->pcmcia_map.read16 = pcmcia_read16_remap;
+ dev->pcmcia_map.copy_from = pcmcia_copy_from_remap;
+ dev->pcmcia_map.write8 = pcmcia_write8_remap;
+ dev->pcmcia_map.write16 = pcmcia_write16_remap;
+ dev->pcmcia_map.copy_to = pcmcia_copy_to_remap;
+ if(setvpp == 1)
+ dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp;
+
+ /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum
+ that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the
+ whole card - otherwise we try smaller windows until we succeed */
+
+ req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE;
+ req.Attributes |= (dev->pcmcia_map.buswidth == 1) ? WIN_DATA_WIDTH_8 : WIN_DATA_WIDTH_16;
+ req.Base = 0;
+ req.AccessSpeed = mem_speed;
+ link->win = (window_handle_t)link->handle;
+ req.Size = (force_size) ? force_size << 20 : MAX_PCMCIA_ADDR;
+ dev->win_size = 0;
+
+ do {
+ int ret;
+ DEBUG(2, "requesting window with size = %dKB memspeed = %d",
+ req.Size >> 10, req.AccessSpeed);
+ link->win = (window_handle_t)link->handle;
+ ret = CardServices(RequestWindow, &link->win, &req);
+ DEBUG(2, "ret = %d dev->win_size = %d", ret, dev->win_size);
+ if(ret) {
+ req.Size >>= 1;
+ } else {
+ DEBUG(2, "Got window of size %dKB", req.Size >> 10);
+ dev->win_size = req.Size;
+ break;
+ }
+ } while(req.Size >= 0x1000);
+
+ DEBUG(2, "dev->win_size = %d", dev->win_size);
+
+ if(!dev->win_size) {
+ err("Cant allocate memory window");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10);
+
+ /* Get write protect status */
+ CS_CHECK(GetStatus, link->handle, &status);
+ DEBUG(2, "status value: 0x%x window handle = 0x%8.8lx",
+ status.CardState, (unsigned long)link->win);
+ dev->win_base = ioremap(req.Base, req.Size);
+ if(!dev->win_base) {
+ err("ioremap(%lu, %u) failed", req.Base, req.Size);
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "mapped window dev = %p req.base = 0x%lx base = %p size = 0x%x",
+ dev, req.Base, dev->win_base, req.Size);
+ dev->cardsize = 0;
+ dev->offset = 0;
+
+ dev->pcmcia_map.map_priv_1 = (unsigned long)dev;
+ dev->pcmcia_map.map_priv_2 = (unsigned long)link->win;
+
+ DEBUG(2, "Getting configuration");
+ CS_CHECK(GetConfigurationInfo, link->handle, &t);
+ DEBUG(2, "Vcc = %d Vpp1 = %d Vpp2 = %d", t.Vcc, t.Vpp1, t.Vpp2);
+ dev->vpp = (vpp) ? vpp : t.Vpp1;
+ link->conf.Attributes = 0;
+ link->conf.Vcc = t.Vcc;
+ if(setvpp == 2) {
+ link->conf.Vpp1 = dev->vpp;
+ link->conf.Vpp2 = dev->vpp;
+ } else {
+ link->conf.Vpp1 = 0;
+ link->conf.Vpp2 = 0;
+ }
+
+ link->conf.IntType = INT_MEMORY;
+ link->conf.ConfigBase = t.ConfigBase;
+ link->conf.Status = t.Status;
+ link->conf.Pin = t.Pin;
+ link->conf.Copy = t.Copy;
+ link->conf.ExtStatus = t.ExtStatus;
+ link->conf.ConfigIndex = 0;
+ link->conf.Present = t.Present;
+ DEBUG(2, "Setting Configuration");
+ ret = CardServices(RequestConfiguration, link->handle, &link->conf);
+ if(ret != CS_SUCCESS) {
+ cs_error(link->handle, RequestConfiguration, ret);
+ }
+
+ link->dev = NULL;
+ link->state &= ~DEV_CONFIG_PENDING;
+
+ if(mem_type == 1) {
+ mtd = do_map_probe("map_ram", &dev->pcmcia_map);
+ } else if(mem_type == 2) {
+ mtd = do_map_probe("map_rom", &dev->pcmcia_map);
+ } else {
+ for(i = 0; i < sizeof(probes) / sizeof(char *); i++) {
+ DEBUG(1, "Trying %s", probes[i]);
+ mtd = do_map_probe(probes[i], &dev->pcmcia_map);
+ if(mtd)
+ break;
+
+ DEBUG(1, "FAILED: %s", probes[i]);
+ }
+ }
+
+ if(!mtd) {
+ DEBUG(1, "Cant find an MTD");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+
+ dev->mtd_info = mtd;
+ mtd->module = THIS_MODULE;
+ dev->cardsize = mtd->size;
+
+ if(new_name) {
+ int size = 0;
+ char unit = ' ';
+ /* Since we are using a default name, make it better by adding in the
+ size */
+ if(mtd->size < 1048576) { /* <1MB in size, show size in K */
+ size = mtd->size >> 10;
+ unit = 'K';
+ } else {
+ size = mtd->size >> 20;
+ unit = 'M';
+ }
+ sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card");
+ }
+
+ /* If the memory found is fits completely into the mapped PCMCIA window,
+ use the faster non-remapping read/write functions */
+ if(dev->cardsize <= dev->win_size) {
+ DEBUG(1, "Using non remapping memory functions");
+
+ dev->pcmcia_map.map_priv_2 = (unsigned long)dev->win_base;
+ dev->pcmcia_map.read8 = pcmcia_read8;
+ dev->pcmcia_map.read16 = pcmcia_read16;
+ dev->pcmcia_map.copy_from = pcmcia_copy_from;
+ dev->pcmcia_map.write8 = pcmcia_write8;
+ dev->pcmcia_map.write16 = pcmcia_write16;
+ dev->pcmcia_map.copy_to = pcmcia_copy_to;
+ }
+
+ MOD_INC_USE_COUNT;
+ if(add_mtd_device(mtd)) {
+ dev->mtd_info = NULL;
+ MOD_DEC_USE_COUNT;
+ err("Couldnt register MTD device");
+ pcmciamtd_release((u_long)link);
+ return;
+ }
+ DEBUG(1, "mtd added @ %p mtd->priv = %p", mtd, mtd->priv);
+
+ return;
+
+ cs_failed:
+ cs_error(link->handle, last_fn, last_ret);
+ err("CS Error, exiting");
+ pcmciamtd_release((u_long)link);
+ return;
+}
+
+
+/* The card status event handler. Mostly, this schedules other
+ * stuff to run after an event is received. A CARD_REMOVAL event
+ * also sets some flags to discourage the driver from trying
+ * to talk to the card any more.
+ */
+
+static int pcmciamtd_event(event_t event, int priority,
+ event_callback_args_t *args)
+{
+ dev_link_t *link = args->client_data;
+
+ DEBUG(1, "event=0x%06x", event);
+ switch (event) {
+ case CS_EVENT_CARD_REMOVAL:
+ DEBUG(2, "EVENT_CARD_REMOVAL");
+ link->state &= ~DEV_PRESENT;
+ if (link->state & DEV_CONFIG)
+ mod_timer(&link->release, jiffies + HZ/20);
+ break;
+ case CS_EVENT_CARD_INSERTION:
+ DEBUG(2, "EVENT_CARD_INSERTION");
+ link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+ pcmciamtd_config(link);
+ break;
+ case CS_EVENT_PM_SUSPEND:
+ DEBUG(2, "EVENT_PM_SUSPEND");
+ link->state |= DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_RESET_PHYSICAL:
+ DEBUG(2, "EVENT_RESET_PHYSICAL");
+ /* get_lock(link); */
+ break;
+ case CS_EVENT_PM_RESUME:
+ DEBUG(2, "EVENT_PM_RESUME");
+ link->state &= ~DEV_SUSPEND;
+ /* Fall through... */
+ case CS_EVENT_CARD_RESET:
+ DEBUG(2, "EVENT_CARD_RESET");
+ /* free_lock(link); */
+ break;
+ default:
+ DEBUG(2, "Unknown event %d", event);
+ }
+ return 0;
+}
+
+
+/* This deletes a driver "instance". The device is de-registered
+ * with Card Services. If it has been released, all local data
+ * structures are freed. Otherwise, the structures will be freed
+ * when the device is released.
+ */
+
+static void pcmciamtd_detach(dev_link_t *link)
+{
+ int ret;
+ struct pcmciamtd_dev *dev = NULL;
+ struct list_head *temp1, *temp2;
+
+ DEBUG(3, "link=0x%p", link);
+
+ /* Find device in list */
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev = list_entry(temp1, struct pcmciamtd_dev, list);
+ if(link == &dev->link)
+ break;
+ }
+ if(link != &dev->link) {
+ DEBUG(1, "Cant find %p in dev_list", link);
+ return;
+ }
+
+ del_timer(&link->release);
+
+ if(!dev) {
+ DEBUG(3, "dev is NULL");
+ return;
+ }
+
+ if (link->state & DEV_CONFIG) {
+ //pcmciamtd_release((u_long)link);
+ DEBUG(3, "DEV_CONFIG set");
+ link->state |= DEV_STALE_LINK;
+ return;
+ }
+
+ if (link->handle) {
+ DEBUG(2, "Deregistering with card services");
+ ret = CardServices(DeregisterClient, link->handle);
+ if (ret != CS_SUCCESS)
+ cs_error(link->handle, DeregisterClient, ret);
+ }
+ DEBUG(3, "Freeing dev (%p)", dev);
+ list_del(&dev->list);
+ link->priv = NULL;
+ kfree(dev);
+}
+
+
+/* pcmciamtd_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device. The device is registered
+ * with Card Services.
+ */
+
+static dev_link_t *pcmciamtd_attach(void)
+{
+ struct pcmciamtd_dev *dev;
+ dev_link_t *link;
+ client_reg_t client_reg;
+ int ret;
+
+ /* Create new memory card device */
+ dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) return NULL;
+ DEBUG(1, "dev=0x%p", dev);
+
+ memset(dev, 0, sizeof(*dev));
+ link = &dev->link; link->priv = dev;
+
+ link->release.function = &pcmciamtd_release;
+ link->release.data = (u_long)link;
+
+ link->conf.Attributes = 0;
+ link->conf.IntType = INT_MEMORY;
+
+ list_add(&dev->list, &dev_list);
+
+ /* Register with Card Services */
+ client_reg.dev_info = &dev_info;
+ client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+ client_reg.EventMask =
+ CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+ CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+ CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+ client_reg.event_handler = &pcmciamtd_event;
+ client_reg.Version = 0x0210;
+ client_reg.event_callback_args.client_data = link;
+ DEBUG(2, "Calling RegisterClient");
+ ret = CardServices(RegisterClient, &link->handle, &client_reg);
+ if (ret != 0) {
+ cs_error(link->handle, RegisterClient, ret);
+ pcmciamtd_detach(link);
+ return NULL;
+ }
+
+ return link;
+}
+
+
+static int __init init_pcmciamtd(void)
+{
+ servinfo_t serv;
+
+ info(DRIVER_DESC " " DRIVER_VERSION);
+ CardServices(GetCardServicesInfo, &serv);
+ if (serv.Revision != CS_RELEASE_CODE) {
+ err("Card Services release does not match!");
+ return -1;
+ }
+
+ if(buswidth && buswidth != 1 && buswidth != 2) {
+ info("bad buswidth (%d), using default", buswidth);
+ buswidth = 2;
+ }
+ if(force_size && (force_size < 1 || force_size > 64)) {
+ info("bad force_size (%d), using default", force_size);
+ force_size = 0;
+ }
+ if(mem_type && mem_type != 1 && mem_type != 2) {
+ info("bad mem_type (%d), using default", mem_type);
+ mem_type = 0;
+ }
+ register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach);
+ return 0;
+}
+
+
+static void __exit exit_pcmciamtd(void)
+{
+ struct list_head *temp1, *temp2;
+
+ DEBUG(1, DRIVER_DESC " unloading");
+ unregister_pccard_driver(&dev_info);
+ list_for_each_safe(temp1, temp2, &dev_list) {
+ dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link;
+ if (link && (link->state & DEV_CONFIG)) {
+ pcmciamtd_release((u_long)link);
+ pcmciamtd_detach(link);
+ }
+ }
+}
+
+module_init(init_pcmciamtd);
+module_exit(exit_pcmciamtd);
diff --git a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
index b6c1c0f9efe7..b2592a0a0d63 100644
--- a/drivers/mtd/maps/sa1100-flash.c
+++ b/drivers/mtd/maps/sa1100-flash.c
@@ -3,28 +3,35 @@
*
* (C) 2000 Nicolas Pitre <nico@cam.org>
*
- * $Id: sa1100-flash.c,v 1.22 2001/10/02 10:04:52 rmk Exp $
+ * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/types.h>
+#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
#include <linux/mtd/partitions.h>
+#include <linux/mtd/concat.h>
#include <asm/hardware.h>
+#include <asm/mach-types.h>
#include <asm/io.h>
+#include <asm/sizes.h>
+#include <asm/arch/h3600.h>
#ifndef CONFIG_ARCH_SA1100
#error This is for SA1100 architecture only
#endif
-
-#define WINDOW_ADDR 0xe8000000
+/*
+ * This isnt complete yet, so...
+ */
+#define CONFIG_MTD_SA1100_STATICMAP 1
static __u8 sa1100_read8(struct map_info *map, unsigned long ofs)
{
@@ -66,33 +73,7 @@ static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *f
memcpy((void *)(map->map_priv_1 + to), from, len);
}
-
-#ifdef CONFIG_SA1100_H3600
-
-static void h3600_set_vpp(struct map_info *map, int vpp)
-{
- if (vpp)
- set_h3600_egpio(EGPIO_H3600_VPP_ON);
- else
- clr_h3600_egpio(EGPIO_H3600_VPP_ON);
-}
-
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-
-static void jornada720_set_vpp(int vpp)
-{
- if (vpp)
- PPSR |= 0x80;
- else
- PPSR &= ~0x80;
- PPDR |= 0x80;
-}
-
-#endif
-
-static struct map_info sa1100_map = {
+static struct map_info sa1100_map __initdata = {
name: "SA1100 flash",
read8: sa1100_read8,
read16: sa1100_read16,
@@ -102,609 +83,1232 @@ static struct map_info sa1100_map = {
write16: sa1100_write16,
write32: sa1100_write32,
copy_to: sa1100_copy_to,
-
- map_priv_1: WINDOW_ADDR,
};
+#ifdef CONFIG_MTD_SA1100_STATICMAP
/*
* Here are partition information for all known SA1100-based devices.
* See include/linux/mtd/partitions.h for definition of the mtd_partition
* structure.
- *
- * The *_max_flash_size is the maximum possible mapped flash size which
- * is not necessarily the actual flash size. It must correspond to the
- * value specified in the mapping definition defined by the
- * "struct map_desc *_io_desc" for the corresponding machine.
+ *
+ * Please note:
+ * 1. We no longer support static flash mappings via the machine io_desc
+ * structure.
+ * 2. The flash size given should be the largest flash size that can
+ * be accomodated.
+ *
+ * The MTD layer will detect flash chip aliasing and reduce the size of
+ * the map accordingly.
+ *
+ * Please keep these in alphabetical order, and formatted as per existing
+ * entries. Thanks.
*/
-#ifdef CONFIG_SA1100_ASSABET
+#ifdef CONFIG_SA1100_ADSBITSY
+static struct mtd_partition adsbitsy_partitions[] = {
+ {
+ name: "bootROM",
+ size: 0x80000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "zImage",
+ size: 0x100000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+#ifdef CONFIG_SA1100_ASSABET
/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
-static unsigned long assabet4_max_flash_size = 0x00400000;
static struct mtd_partition assabet4_partitions[] = {
- {
- name: "bootloader",
- size: 0x00020000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00020000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "jffs",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND
- }
+ {
+ name: "bootloader",
+ size: 0x00020000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00020000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "jffs",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
};
/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
-static unsigned long assabet5_max_flash_size = 0x02000000;
static struct mtd_partition assabet5_partitions[] = {
- {
- name: "bootloader",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "jffs",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND
- }
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "jffs",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
};
-#define assabet_max_flash_size assabet5_max_flash_size
-#define assabet_partitions assabet5_partitions
-
+#define assabet_partitions assabet5_partitions
#endif
-#ifdef CONFIG_SA1100_FLEXANET
-
-/* Flexanet has two 28F128J3A flash parts in bank 0: */
-static unsigned long flexanet_max_flash_size = 0x02000000;
-static struct mtd_partition flexanet_partitions[] = {
- {
- name: "bootloader",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE
- },{
- name: "bootloader params",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "kernel",
- size: 0x000C0000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "altkernel",
- size: 0x000C0000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "root",
- size: 0x00400000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free1",
- size: 0x00300000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free2",
- size: 0x00300000,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- },{
- name: "free3",
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND,
- mask_flags: MTD_WRITEABLE
- }
+#ifdef CONFIG_SA1100_BADGE4
+/*
+ * 1 x Intel 28F320C3BA100 Advanced+ Boot Block Flash (32 Mi bit)
+ * Eight 4 KiW Parameter Bottom Blocks (64 KiB)
+ * Sixty-three 32 KiW Main Blocks (4032 Ki b)
+ */
+static struct mtd_partition badge4_partitions[] = {
+ {
+ name: "BLOB boot loader",
+ offset: 0,
+ size: 0x0000A000
+ }, {
+ name: "params",
+ offset: MTDPART_OFS_APPEND,
+ size: 0x00006000
+ }, {
+ name: "kernel",
+ offset: MTDPART_OFS_APPEND,
+ size: 0x00100000
+ }, {
+ name: "root",
+ offset: MTDPART_OFS_APPEND,
+ size: MTDPART_SIZ_FULL
+ }
};
-
#endif
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-static unsigned long huw_webpanel_max_flash_size = 0x01000000;
-static struct mtd_partition huw_webpanel_partitions[] = {
- {
- name: "Loader",
- size: 0x00040000,
- offset: 0,
- },{
- name: "Sector 1",
- size: 0x00040000,
- offset: MTDPART_OFS_APPEND,
- },{
- size: MTDPART_SIZ_FULL,
- offset: MTDPART_OFS_APPEND,
+
+#ifdef CONFIG_SA1100_CERF
+#ifdef CONFIG_SA1100_CERF_FLASH_32MB
+static struct mtd_partition cerf_partitions[] = {
+ {
+ name: "firmware",
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ name: "params",
+ size: 0x00040000,
+ offset: 0x00040000,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+ name: "rootdisk",
+ size: 0x01E80000,
+ offset: 0x00180000,
}
};
-#endif /* CONFIG_SA1100_HUW_WEBPANEL */
-
-
-#ifdef CONFIG_SA1100_H3600
-
-static unsigned long h3600_max_flash_size = 0x02000000;
-static struct mtd_partition h3600_partitions[] = {
+#elif defined CONFIG_SA1100_CERF_FLASH_16MB
+static struct mtd_partition cerf_partitions[] = {
{
- name: "H3600 boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "H3600 kernel",
- size: 0x00080000,
- offset: 0x40000
- },{
- name: "H3600 params",
- size: 0x00040000,
- offset: 0xC0000
- },{
-#ifdef CONFIG_JFFS2_FS
- name: "H3600 root jffs2",
- offset: 0x00100000,
- size: MTDPART_SIZ_FULL
+ name: "firmware",
+ size: 0x00020000,
+ offset: 0,
+ }, {
+ name: "params",
+ size: 0x00020000,
+ offset: 0x00020000,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00040000,
+ }, {
+ name: "rootdisk",
+ size: 0x00EC0000,
+ offset: 0x00140000,
+ }
+};
+#elif defined CONFIG_SA1100_CERF_FLASH_8MB
+# error "Unwritten type definition"
#else
- name: "H3600 initrd",
- size: 0x00100000,
- offset: 0x00100000
- },{
- name: "H3600 root cramfs",
- size: 0x00300000,
- offset: 0x00200000
- },{
- name: "H3600 usr cramfs",
- size: 0x00800000,
- offset: 0x00500000
- },{
- name: "H3600 usr local",
- offset: 0x00d00000,
- size: MTDPART_SIZ_FULL
+# error "Undefined memory orientation for CERF in sa1100-flash.c"
+#endif
#endif
+
+#ifdef CONFIG_SA1100_CONSUS
+static struct mtd_partition consus_partitions[] = {
+ {
+ name: "Consus boot firmware",
+ offset: 0,
+ size: 0x00040000,
+ mask_flags: MTD_WRITABLE, /* force read-only */
+ }, {
+ name: "Consus kernel",
+ offset: 0x00040000,
+ size: 0x00100000,
+ mask_flags: 0,
+ }, {
+ name: "Consus disk",
+ offset: 0x00140000,
+ /* The rest (up to 16M) for jffs. We could put 0 and
+ make it find the size automatically, but right now
+ i have 32 megs. jffs will use all 32 megs if given
+ the chance, and this leads to horrible problems
+ when you try to re-flash the image because blob
+ won't erase the whole partition. */
+ size: 0x01000000 - 0x00140000,
+ mask_flags: 0,
+ }, {
+ /* this disk is a secondary disk, which can be used as
+ needed, for simplicity, make it the size of the other
+ consus partition, although realistically it could be
+ the remainder of the disk (depending on the file
+ system used) */
+ name: "Consus disk2",
+ offset: 0x01000000,
+ size: 0x01000000 - 0x00140000,
+ mask_flags: 0,
}
};
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+/* Flexanet has two 28F128J3A flash parts in bank 0: */
+#define FLEXANET_FLASH_SIZE 0x02000000
+static struct mtd_partition flexanet_partitions[] = {
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "kernel",
+ size: 0x000C0000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "altkernel",
+ size: 0x000C0000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "root",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free1",
+ size: 0x00300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free2",
+ size: 0x00300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }, {
+ name: "free3",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE,
+ }
+};
#endif
+
#ifdef CONFIG_SA1100_FREEBIRD
-static unsigned long freebird_max_flash_size = 0x02000000;
static struct mtd_partition freebird_partitions[] = {
#if CONFIG_SA1100_FREEBIRD_NEW
- {
- name: "firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "kernel",
- size: 0x00080000,
- offset: 0x40000
- },{
- name: "params",
- size: 0x00040000,
- offset: 0xC0000
- },{
- name: "initrd",
- size: 0x00100000,
- offset: 0x00100000
- },{
- name: "root cramfs",
- size: 0x00300000,
- offset: 0x00200000
- },{
- name: "usr cramfs",
- size: 0x00C00000,
- offset: 0x00500000
- },{
- name: "local",
- offset: 0x01100000,
- size: MTDPART_SIZ_FULL
+ {
+ name: "firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00080000,
+ offset: 0x00040000,
+ }, {
+ name: "params",
+ size: 0x00040000,
+ offset: 0x000C0000,
+ }, {
+ name: "initrd",
+ size: 0x00100000,
+ offset: 0x00100000,
+ }, {
+ name: "root cramfs",
+ size: 0x00300000,
+ offset: 0x00200000,
+ }, {
+ name: "usr cramfs",
+ size: 0x00C00000,
+ offset: 0x00500000,
+ }, {
+ name: "local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x01100000,
}
#else
- { offset: 0, size: 0x00040000, },
- { offset: MTDPART_OFS_APPEND, size: 0x000c0000, },
- { offset: MTDPART_OFS_APPEND, size: 0x00400000, },
- { offset: MTDPART_OFS_APPEND, size: MTDPART_SIZ_FULL }
+ {
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ size: 0x000c0000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
#endif
- };
+};
#endif
-
-
-#ifdef CONFIG_SA1100_CERF
-static unsigned long cerf_max_flash_size = 0x01000000;
-static struct mtd_partition cerf_partitions[] = {
- { offset: 0, size: 0x00800000 },
- { offset: MTDPART_OFS_APPEND, size: 0x00800000 }
+#ifdef CONFIG_SA1100_FRODO
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+static struct mtd_partition frodo_partitions[] =
+{
+ {
+ name: "bootloader",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "bootloader params",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "ramdisk",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE
+ }, {
+ name: "file system",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND
+ }
};
-
#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-
-static unsigned long graphicsclient_max_flash_size = 0x01000000;
static struct mtd_partition graphicsclient_partitions[] = {
- {
- name: "zImage",
- offset: 0,
- size: 0x100000
- },
- {
- name: "ramdisk.gz",
- offset: MTDPART_OFS_APPEND,
- size: 0x300000
- },
- {
- name: "User FS",
- offset: MTDPART_OFS_APPEND,
- size: MTDPART_SIZ_FULL
+ {
+ name: "zImage",
+ size: 0x100000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
}
};
-
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
-
-static unsigned long graphicsmaster_max_flash_size = 0x01000000;
static struct mtd_partition graphicsmaster_partitions[] = {
- {
- name: "zImage",
- offset: 0,
- size: 0x100000
+ {
+ name: "zImage",
+ size: 0x100000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
},
- {
- name: "ramdisk.gz",
- offset: MTDPART_OFS_APPEND,
- size: 0x300000
+ {
+ name: "ramdisk.gz",
+ size: 0x300000,
+ offset: MTDPART_OFS_APPEND,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
},
- {
- name: "User FS",
- offset: MTDPART_OFS_APPEND,
- size: MTDPART_SIZ_FULL
+ {
+ name: "User FS",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
}
};
+#endif
+#ifdef CONFIG_SA1100_H3XXX
+static struct mtd_partition h3xxx_partitions[] = {
+ {
+ name: "H3XXX boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+#ifdef CONFIG_MTD_2PARTS_IPAQ
+ name: "H3XXX root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00040000,
+#else
+ name: "H3XXX kernel",
+ size: 0x00080000,
+ offset: 0x00040000,
+ }, {
+ name: "H3XXX params",
+ size: 0x00040000,
+ offset: 0x000C0000,
+ }, {
+#ifdef CONFIG_JFFS2_FS
+ name: "H3XXX root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00100000,
+#else
+ name: "H3XXX initrd",
+ size: 0x00100000,
+ offset: 0x00100000,
+ }, {
+ name: "H3XXX root cramfs",
+ size: 0x00300000,
+ offset: 0x00200000,
+ }, {
+ name: "H3XXX usr cramfs",
+ size: 0x00800000,
+ offset: 0x00500000,
+ }, {
+ name: "H3XXX usr local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00d00000,
+#endif
#endif
+ }
+};
-#ifdef CONFIG_SA1100_PANGOLIN
+static void h3xxx_set_vpp(struct map_info *map, int vpp)
+{
+ assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
+}
+#else
+#define h3xxx_set_vpp NULL
+#endif
-static unsigned long pangolin_max_flash_size = 0x04000000;
-static struct mtd_partition pangolin_partitions[] = {
- {
- name: "boot firmware",
- offset: 0x00000000,
- size: 0x00080000,
- mask_flags: MTD_WRITEABLE, /* force read-only */
- },
- {
- name: "kernel",
- offset: 0x00080000,
- size: 0x00100000,
- },
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+static struct mtd_partition huw_webpanel_partitions[] = {
{
- name: "initrd",
- offset: 0x00180000,
- size: 0x00280000,
- },
+ name: "Loader",
+ size: 0x00040000,
+ offset: 0,
+ }, {
+ name: "Sector 1",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_JORNADA720
+static struct mtd_partition jornada720_partitions[] = {
{
- name: "initrd-test",
- offset: 0x00400000,
- size: 0x03C00000,
+ name: "JORNADA720 boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "JORNADA720 kernel",
+ size: 0x000c0000,
+ offset: 0x00040000,
+ }, {
+ name: "JORNADA720 params",
+ size: 0x00040000,
+ offset: 0x00100000,
+ }, {
+ name: "JORNADA720 initrd",
+ size: 0x00100000,
+ offset: 0x00140000,
+ }, {
+ name: "JORNADA720 root cramfs",
+ size: 0x00300000,
+ offset: 0x00240000,
+ }, {
+ name: "JORNADA720 usr cramfs",
+ size: 0x00800000,
+ offset: 0x00540000,
+ }, {
+ name: "JORNADA720 usr local",
+ size: 0 /* will expand to the end of the flash */
+ offset: 0x00d00000,
}
};
+static void jornada720_set_vpp(int vpp)
+{
+ if (vpp)
+ PPSR |= 0x80;
+ else
+ PPSR &= ~0x80;
+ PPDR |= 0x80;
+}
+#else
+#define jornada720_set_vpp NULL
#endif
-#ifdef CONFIG_SA1100_YOPY
+#ifdef CONFIG_SA1100_PANGOLIN
+static struct mtd_partition pangolin_partitions[] = {
+ {
+ name: "boot firmware",
+ size: 0x00080000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+ name: "initrd",
+ size: 0x00280000,
+ offset: 0x00180000,
+ }, {
+ name: "initrd-test",
+ size: 0x03C00000,
+ offset: 0x00400000,
+ }
+};
+#endif
-static unsigned long yopy_max_flash_size = 0x08000000;
-static struct mtd_partition yopy_partitions[] = {
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+/* erase size is 0x40000 == 256k partitions have to have this boundary */
+static struct mtd_partition system3_partitions[] = {
{
- name: "boot firmware",
- offset: 0x00000000,
- size: 0x00040000,
- mask_flags: MTD_WRITEABLE, /* force read-only */
+ name: "BLOB",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "config",
+ size: 0x00040000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ name: "kernel",
+ size: 0x00100000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ name: "root",
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
+
+#ifdef CONFIG_SA1100_SHANNON
+static struct mtd_partition shannon_partitions[] = {
+ {
+ name: "BLOB boot loader",
+ offset: 0,
+ size: 0x20000
},
{
name: "kernel",
- offset: 0x00080000,
- size: 0x00080000,
+ offset: MTDPART_OFS_APPEND,
+ size: 0xe0000
},
- {
+ {
name: "initrd",
- offset: 0x00100000,
- size: 0x00300000,
- },
- {
- name: "root",
- offset: 0x00400000,
- size: 0x01000000,
- },
+ offset: MTDPART_OFS_APPEND,
+ size: MTDPART_SIZ_FULL
+ }
};
#endif
-#ifdef CONFIG_SA1100_JORNADA720
-
-static unsigned long jornada720_max_flash_size = 0x02000000;
-static struct mtd_partition jornada720_partitions[] = {
+#ifdef CONFIG_SA1100_SHERMAN
+static struct mtd_partition sherman_partitions[] = {
{
- name: "JORNADA720 boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "JORNADA720 kernel",
- size: 0x000c0000,
- offset: 0x40000
- },{
- name: "JORNADA720 params",
- size: 0x00040000,
- offset: 0x100000
- },{
- name: "JORNADA720 initrd",
- size: 0x00100000,
- offset: 0x00140000
- },{
- name: "JORNADA720 root cramfs",
- size: 0x00300000,
- offset: 0x00240000
- },{
- name: "JORNADA720 usr cramfs",
- size: 0x00800000,
- offset: 0x00540000
- },{
- name: "JORNADA720 usr local",
- offset: 0x00d00000,
- size: 0 /* will expand to the end of the flash */
+ size: 0x50000,
+ offset: 0,
+ }, {
+ size: 0x70000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0x600000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: 0xA0000,
+ offset: MTDPART_OFS_APPEND,
}
};
#endif
-#ifdef CONFIG_SA1100_SHERMAN
-
-static unsigned long sherman_max_flash_size = 0x02000000;
-static struct mtd_partition sherman_partitions[] = {
- { offset: 0, size: 0x50000 },
- { offset: MTDPART_OFS_APPEND, size: 0x70000 },
- { offset: MTDPART_OFS_APPEND, size: 0x600000 },
- { offset: MTDPART_OFS_APPEND, size: 0xA0000 }
-};
-
+#ifdef CONFIG_SA1100_SIMPAD
+static struct mtd_partition simpad_partitions[] = {
+ {
+ name: "SIMpad boot firmware",
+ size: 0x00080000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "SIMpad kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
+#ifdef CONFIG_JFFS2_FS
+ name: "SIMpad root jffs2",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00180000,
+#else
+ name: "SIMpad initrd",
+ size: 0x00300000,
+ offset: 0x00180000,
+ }, {
+ name: "SIMpad root cramfs",
+ size: 0x00300000,
+ offset: 0x00480000,
+ }, {
+ name: "SIMpad usr cramfs",
+ size: 0x005c0000,
+ offset: 0x00780000,
+ }, {
+ name: "SIMpad usr local",
+ size: MTDPART_SIZ_FULL,
+ offset: 0x00d40000,
#endif
+ }
+};
+#endif /* CONFIG_SA1100_SIMPAD */
#ifdef CONFIG_SA1100_STORK
-
-static unsigned long stork_max_flash_size = 0x02000000;
static struct mtd_partition stork_partitions[] = {
{
- name: "STORK boot firmware",
- size: 0x00040000,
- offset: 0,
- mask_flags: MTD_WRITEABLE /* force read-only */
- },{
- name: "STORK params",
- size: 0x00040000,
- offset: 0x40000
- },{
- name: "STORK kernel",
- size: 0x00100000,
- offset: 0x80000
- },{
+ name: "STORK boot firmware",
+ size: 0x00040000,
+ offset: 0,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "STORK params",
+ size: 0x00040000,
+ offset: 0x00040000,
+ }, {
+ name: "STORK kernel",
+ size: 0x00100000,
+ offset: 0x00080000,
+ }, {
#ifdef CONFIG_JFFS2_FS
- name: "STORK root jffs2",
- offset: 0x00180000,
- size: MTDPART_SIZ_FULL
+ name: "STORK root jffs2",
+ offset: 0x00180000,
+ size: MTDPART_SIZ_FULL,
#else
- name: "STORK initrd",
- size: 0x00100000,
- offset: 0x00180000
- },{
- name: "STORK root cramfs",
- size: 0x00300000,
- offset: 0x00280000
- },{
- name: "STORK usr cramfs",
- size: 0x00800000,
- offset: 0x00580000
- },{
- name: "STORK usr local",
- offset: 0x00d80000,
- size: MTDPART_SIZ_FULL
+ name: "STORK initrd",
+ size: 0x00100000,
+ offset: 0x00180000,
+ }, {
+ name: "STORK root cramfs",
+ size: 0x00300000,
+ offset: 0x00280000,
+ }, {
+ name: "STORK usr cramfs",
+ size: 0x00800000,
+ offset: 0x00580000,
+ }, {
+ name: "STORK usr local",
+ offset: 0x00d80000,
+ size: MTDPART_SIZ_FULL,
#endif
}
};
-
#endif
-#define NB_OF(x) (sizeof(x)/sizeof(x[0]))
-
-
-extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
-extern int parse_bootldr_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+#ifdef CONFIG_SA1100_TRIZEPS
+static struct mtd_partition trizeps_partitions[] = {
+ {
+ name: "Bootloader & the kernel",
+ size: 0x00200000,
+ offset: 0,
+ }, {
+ name: "Data",
+ size: 0x00400000,
+ offset: MTDPART_OFS_APPEND,
+ }, {
+ size: MTDPART_SIZ_FULL,
+ offset: MTDPART_OFS_APPEND,
+ }
+};
+#endif
-static struct mtd_partition *parsed_parts;
-static struct mtd_info *mymtd;
+#ifdef CONFIG_SA1100_YOPY
+static struct mtd_partition yopy_partitions[] = {
+ {
+ name: "boot firmware",
+ size: 0x00040000,
+ offset: 0x00000000,
+ mask_flags: MTD_WRITEABLE, /* force read-only */
+ }, {
+ name: "kernel",
+ size: 0x00080000,
+ offset: 0x00080000,
+ }, {
+ name: "initrd",
+ size: 0x00300000,
+ offset: 0x00100000,
+ }, {
+ name: "root",
+ size: 0x01000000,
+ offset: 0x00400000,
+ }
+};
+#endif
-int __init sa1100_mtd_init(void)
+static int __init sa1100_static_partitions(struct mtd_partition **parts)
{
- struct mtd_partition *parts;
int nb_parts = 0;
- int parsed_nr_parts = 0;
- char *part_type;
-
- /* Default flash buswidth */
- sa1100_map.buswidth = (MSC0 & MSC_RBW) ? 2 : 4;
- /*
- * Static partition definition selection
- */
- part_type = "static";
+#ifdef CONFIG_SA1100_ADSBITSY
+ if (machine_is_adsbitsy()) {
+ *parts = adsbitsy_partitions;
+ nb_parts = ARRAY_SIZE(adsbitsy_partitions);
+ }
+#endif
#ifdef CONFIG_SA1100_ASSABET
if (machine_is_assabet()) {
- parts = assabet_partitions;
- nb_parts = NB_OF(assabet_partitions);
- sa1100_map.size = assabet_max_flash_size;
+ *parts = assabet_partitions;
+ nb_parts = ARRAY_SIZE(assabet_partitions);
}
#endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
- if (machine_is_huw_webpanel()) {
- parts = huw_webpanel_partitions;
- nb_parts = NB_OF(huw_webpanel_partitions);
- sa1100_map.size = huw_webpanel_max_flash_size;
+#ifdef CONFIG_SA1100_BADGE4
+ if (machine_is_badge4()) {
+ *parts = badge4_partitions;
+ nb_parts = ARRAY_SIZE(badge4_partitions);
}
#endif
-
-#ifdef CONFIG_SA1100_H3600
- if (machine_is_h3600()) {
- parts = h3600_partitions;
- nb_parts = NB_OF(h3600_partitions);
- sa1100_map.size = h3600_max_flash_size;
- sa1100_map.set_vpp = h3600_set_vpp;
+#ifdef CONFIG_SA1100_CERF
+ if (machine_is_cerf()) {
+ *parts = cerf_partitions;
+ nb_parts = ARRAY_SIZE(cerf_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_CONSUS
+ if (machine_is_consus()) {
+ *parts = consus_partitions;
+ nb_parts = ARRAY_SIZE(consus_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_FLEXANET
+ if (machine_is_flexanet()) {
+ *parts = flexanet_partitions;
+ nb_parts = ARRAY_SIZE(flexanet_partitions);
}
#endif
#ifdef CONFIG_SA1100_FREEBIRD
if (machine_is_freebird()) {
- parts = freebird_partitions;
- nb_parts = NB_OF(freebird_partitions);
- sa1100_map.size = freebird_max_flash_size;
+ *parts = freebird_partitions;
+ nb_parts = ARRAY_SIZE(freebird_partitions);
}
#endif
-#ifdef CONFIG_SA1100_CERF
- if (machine_is_cerf()) {
- parts = cerf_partitions;
- nb_parts = NB_OF(cerf_partitions);
- sa1100_map.size = cerf_max_flash_size;
+#ifdef CONFIG_SA1100_FRODO
+ if (machine_is_frodo()) {
+ *parts = frodo_partitions;
+ nb_parts = ARRAY_SIZE(frodo_partitions);
}
-#endif
+#endif
#ifdef CONFIG_SA1100_GRAPHICSCLIENT
if (machine_is_graphicsclient()) {
- parts = graphicsclient_partitions;
- nb_parts = NB_OF(graphicsclient_partitions);
- sa1100_map.size = graphicsclient_max_flash_size;
- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+ *parts = graphicsclient_partitions;
+ nb_parts = ARRAY_SIZE(graphicsclient_partitions);
}
#endif
#ifdef CONFIG_SA1100_GRAPHICSMASTER
if (machine_is_graphicsmaster()) {
- parts = graphicsmaster_partitions;
- nb_parts = NB_OF(graphicsmaster_partitions);
- sa1100_map.size = graphicsmaster_max_flash_size;
- sa1100_map.buswidth = (MSC1 & MSC_RBW) ? 2:4;
+ *parts = graphicsmaster_partitions;
+ nb_parts = ARRAY_SIZE(graphicsmaster_partitions);
}
#endif
-#ifdef CONFIG_SA1100_PANGOLIN
- if (machine_is_pangolin()) {
- parts = pangolin_partitions;
- nb_parts = NB_OF(pangolin_partitions);
- sa1100_map.size = pangolin_max_flash_size;
+#ifdef CONFIG_SA1100_H3XXX
+ if (machine_is_h3xxx()) {
+ *parts = h3xxx_partitions;
+ nb_parts = ARRAY_SIZE(h3xxx_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_HUW_WEBPANEL
+ if (machine_is_huw_webpanel()) {
+ *parts = huw_webpanel_partitions;
+ nb_parts = ARRAY_SIZE(huw_webpanel_partitions);
}
#endif
#ifdef CONFIG_SA1100_JORNADA720
if (machine_is_jornada720()) {
- parts = jornada720_partitions;
- nb_parts = NB_OF(jornada720_partitions);
- sa1100_map.size = jornada720_max_flash_size;
- sa1100_map.set_vpp = jornada720_set_vpp;
+ *parts = jornada720_partitions;
+ nb_parts = ARRAY_SIZE(jornada720_partitions);
}
#endif
-#ifdef CONFIG_SA1100_YOPY
- if (machine_is_yopy()) {
- parts = yopy_partitions;
- nb_parts = NB_OF(yopy_partitions);
- sa1100_map.size = yopy_max_flash_size;
+#ifdef CONFIG_SA1100_PANGOLIN
+ if (machine_is_pangolin()) {
+ *parts = pangolin_partitions;
+ nb_parts = ARRAY_SIZE(pangolin_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_PT_SYSTEM3
+ if (machine_is_pt_system3()) {
+ *parts = system3_partitions;
+ nb_parts = ARRAY_SIZE(system3_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_SHANNON
+ if (machine_is_shannon()) {
+ *parts = shannon_partitions;
+ nb_parts = ARRAY_SIZE(shannon_partitions);
}
#endif
#ifdef CONFIG_SA1100_SHERMAN
if (machine_is_sherman()) {
- parts = sherman_partitions;
- nb_parts = NB_OF(sherman_partitions);
- sa1100_map.size = sherman_max_flash_size;
+ *parts = sherman_partitions;
+ nb_parts = ARRAY_SIZE(sherman_partitions);
}
#endif
-#ifdef CONFIG_SA1100_FLEXANET
- if (machine_is_flexanet()) {
- parts = flexanet_partitions;
- nb_parts = NB_OF(flexanet_partitions);
- sa1100_map.size = flexanet_max_flash_size;
+#ifdef CONFIG_SA1100_SIMPAD
+ if (machine_is_simpad()) {
+ *parts = simpad_partitions;
+ nb_parts = ARRAY_SIZE(simpad_partitions);
}
#endif
#ifdef CONFIG_SA1100_STORK
if (machine_is_stork()) {
- parts = stork_partitions;
- nb_parts = NB_OF(stork_partitions);
- sa1100_map.size = stork_max_flash_size;
+ *parts = stork_partitions;
+ nb_parts = ARRAY_SIZE(stork_partitions);
+ }
+#endif
+#ifdef CONFIG_SA1100_TRIZEPS
+ if (machine_is_trizeps()) {
+ *parts = trizeps_partitions;
+ nb_parts = ARRAY_SIZE(trizeps_parititons);
+ }
+#endif
+#ifdef CONFIG_SA1100_YOPY
+ if (machine_is_yopy()) {
+ *parts = yopy_partitions;
+ nb_parts = ARRAY_SIZE(yopy_partitions);
}
#endif
+ return nb_parts;
+}
+#endif
+
+struct sa_info {
+ unsigned long base;
+ unsigned long size;
+ int width;
+ void *vbase;
+ struct map_info *map;
+ struct mtd_info *mtd;
+ struct resource *res;
+};
+
+#define NR_SUBMTD 4
+
+static struct sa_info info[NR_SUBMTD];
+
+static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
+{
+ struct mtd_info *subdev[nr];
+ struct map_info *maps;
+ int i, found = 0, ret = 0;
+
/*
- * Now let's probe for the actual flash. Do it here since
- * specific machine settings might have been set above.
+ * Allocate the map_info structs in one go.
*/
- printk(KERN_NOTICE "SA1100 flash: probing %d-bit flash bus\n", sa1100_map.buswidth*8);
- mymtd = do_map_probe("cfi_probe", &sa1100_map);
- if (!mymtd)
- return -ENXIO;
- mymtd->module = THIS_MODULE;
+ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
+ if (!maps)
+ return -ENOMEM;
/*
- * Dynamic partition selection stuff (might override the static ones)
+ * Claim and then map the memory regions.
*/
-#ifdef CONFIG_MTD_REDBOOT_PARTS
- if (parsed_nr_parts == 0) {
- int ret = parse_redboot_partitions(mymtd, &parsed_parts);
-
- if (ret > 0) {
- part_type = "RedBoot";
- parsed_nr_parts = ret;
+ for (i = 0; i < nr; i++) {
+ if (sa[i].base == (unsigned long)-1)
+ break;
+
+ sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
+ if (!sa[i].res) {
+ ret = -EBUSY;
+ break;
+ }
+
+ sa[i].map = maps + i;
+ memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info));
+
+ sa[i].vbase = ioremap(sa[i].base, sa[i].size);
+ if (!sa[i].vbase) {
+ ret = -ENOMEM;
+ break;
}
+
+ sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase;
+ sa[i].map->buswidth = sa[i].width;
+ sa[i].map->size = sa[i].size;
+
+ /*
+ * Now let's probe for the actual flash. Do it here since
+ * specific machine settings might have been set above.
+ */
+ sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
+ if (sa[i].mtd == NULL) {
+ ret = -ENXIO;
+ break;
+ }
+ sa[i].mtd->module = THIS_MODULE;
+ subdev[i] = sa[i].mtd;
+
+ printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
+ "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
+ sa[i].width * 8);
+ found += 1;
}
+
+ /*
+ * ENXIO is special. It means we didn't find a chip when
+ * we probed. We need to tear down the mapping, free the
+ * resource and mark it as such.
+ */
+ if (ret == -ENXIO) {
+ iounmap(sa[i].vbase);
+ sa[i].vbase = NULL;
+ release_resource(sa[i].res);
+ sa[i].res = NULL;
+ }
+
+ /*
+ * If we found one device, don't bother with concat support.
+ * If we found multiple devices, use concat if we have it
+ * available, otherwise fail.
+ */
+ if (ret == 0 || ret == -ENXIO) {
+ if (found == 1) {
+ *rmtd = subdev[0];
+ ret = 0;
+ } else if (found > 1) {
+ /*
+ * We detected multiple devices. Concatenate
+ * them together.
+ */
+#ifdef CONFIG_MTD_CONCAT
+ *rmtd = mtd_concat_create(subdev, found,
+ "sa1100 flash");
+ if (*rmtd == NULL)
+ ret = -ENXIO;
+#else
+ printk(KERN_ERR "SA1100 flash: multiple devices "
+ "found but MTD concat support disabled.\n");
+ ret = -ENXIO;
#endif
-#ifdef CONFIG_MTD_BOOTLDR_PARTS
- if (parsed_nr_parts == 0) {
- int ret = parse_bootldr_partitions(mymtd, &parsed_parts);
- if (ret > 0) {
- part_type = "Compaq bootldr";
- parsed_nr_parts = ret;
}
}
-#endif
- if (parsed_nr_parts > 0) {
- parts = parsed_parts;
- nb_parts = parsed_nr_parts;
+ /*
+ * If we failed, clean up.
+ */
+ if (ret) {
+ do {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].vbase)
+ iounmap(sa[i].vbase);
+ if (sa[i].res)
+ release_resource(sa[i].res);
+ } while (i--);
+
+ kfree(maps);
}
- if (nb_parts == 0) {
- printk(KERN_NOTICE "SA1100 flash: no partition info available, registering whole flash at once\n");
- add_mtd_device(mymtd);
+ return ret;
+}
+
+static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
+{
+ int i;
+
+ del_mtd_partitions(mtd);
+
+ if (mtd != sa[0].mtd)
+ mtd_concat_destroy(mtd);
+
+ for (i = NR_SUBMTD; i >= 0; i--) {
+ if (sa[i].mtd)
+ map_destroy(sa[i].mtd);
+ if (sa[i].vbase)
+ iounmap(sa[i].vbase);
+ if (sa[i].res)
+ release_resource(sa[i].res);
+ }
+ kfree(sa[0].map);
+}
+
+static int __init sa1100_locate_flash(void)
+{
+ int i, nr = -ENODEV;
+
+ if (machine_is_adsbitsy()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_assabet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ info[1].base = SA1100_CS1_PHYS; /* neponset */
+ info[1].size = SZ_32M;
+ nr = 2;
+ }
+ if (machine_is_badge4()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ nr = 1;
+ }
+ if (machine_is_cerf()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_consus()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_flexanet()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_freebird()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_frodo()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsclient()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_graphicsmaster()) {
+ info[0].base = SA1100_CS1_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_h3xxx()) {
+ sa1100_map.set_vpp = h3xxx_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_huw_webpanel()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_itsy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_jornada720()) {
+ sa1100_map.set_vpp = jornada720_set_vpp;
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_nanoengine()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[1].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pangolin()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ nr = 1;
+ }
+ if (machine_is_pfs168()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_pleb()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_4M;
+ nr = 2;
+ }
+ if (machine_is_pt_system3()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_shannon()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_4M;
+ nr = 1;
+ }
+ if (machine_is_sherman()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_simpad()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_stork()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_32M;
+ nr = 1;
+ }
+ if (machine_is_trizeps()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_16M;
+ nr = 1;
+ }
+ if (machine_is_victor()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_2M;
+ nr = 1;
+ }
+ if (machine_is_yopy()) {
+ info[0].base = SA1100_CS0_PHYS;
+ info[0].size = SZ_64M;
+ info[1].base = SA1100_CS1_PHYS;
+ info[1].size = SZ_64M;
+ nr = 2;
+ }
+
+ if (nr < 0)
+ return nr;
+
+ /*
+ * Retrieve the buswidth from the MSC registers.
+ * We currently only implement CS0 and CS1 here.
+ */
+ for (i = 0; i < nr; i++) {
+ switch (info[i].base) {
+ default:
+ printk(KERN_WARNING "SA1100 flash: unknown base address "
+ "0x%08lx, assuming CS0\n", info[i].base);
+ case SA1100_CS0_PHYS:
+ info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
+ break;
+
+ case SA1100_CS1_PHYS:
+ info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+ break;
+ }
+ }
+
+ return nr;
+}
+
+extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts);
+extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *);
+
+static struct mtd_partition *parsed_parts;
+
+static void __init sa1100_locate_partitions(struct mtd_info *mtd)
+{
+ const char *part_type = NULL;
+ int nr_parts = 0;
+
+ do {
+ /*
+ * Partition selection stuff.
+ */
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+ nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100");
+ if (nr_parts > 0) {
+ part_type = "command line";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_REDBOOT_PARTS
+ nr_parts = parse_redboot_partitions(mtd, &parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "RedBoot";
+ break;
+ }
+#endif
+#ifdef CONFIG_MTD_SA1100_STATICMAP
+ nr_parts = sa1100_static_partitions(&parsed_parts);
+ if (nr_parts > 0) {
+ part_type = "static";
+ break;
+ }
+#endif
+ } while (0);
+
+ if (nr_parts == 0) {
+ printk(KERN_NOTICE "SA1100 flash: no partition info "
+ "available, registering whole flash\n");
+ add_mtd_device(mtd);
} else {
- printk(KERN_NOTICE "Using %s partition definition\n", part_type);
- add_mtd_partitions(mymtd, parts, nb_parts);
+ printk(KERN_NOTICE "SA1100 flash: using %s partition "
+ "definition\n", part_type);
+ add_mtd_partitions(mtd, parsed_parts, nr_parts);
}
- return 0;
+
+ /* Always succeeds. */
+}
+
+static void __exit sa1100_destroy_partitions(void)
+{
+ if (parsed_parts)
+ kfree(parsed_parts);
+}
+
+static struct mtd_info *mymtd;
+
+static int __init sa1100_mtd_init(void)
+{
+ int ret;
+ int nr;
+
+ nr = sa1100_locate_flash();
+ if (nr < 0)
+ return nr;
+
+ ret = sa1100_setup_mtd(info, nr, &mymtd);
+ if (ret == 0)
+ sa1100_locate_partitions(mymtd);
+
+ return ret;
}
static void __exit sa1100_mtd_cleanup(void)
{
- if (mymtd) {
- del_mtd_partitions(mymtd);
- map_destroy(mymtd);
- if (parsed_parts)
- kfree(parsed_parts);
- }
+ sa1100_destroy_mtd(info, mymtd);
+ sa1100_destroy_partitions();
}
module_init(sa1100_mtd_init);
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 1ad148bd3364..a39bcab25891 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -295,7 +295,7 @@ static int mtdblock_open(struct inode *inode, struct file *file)
spin_unlock(&mtdblks_lock);
mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!mtdblk || !disk)
goto Enomem;
memset(mtdblk, 0, sizeof(*mtdblk));
@@ -313,7 +313,6 @@ static int mtdblock_open(struct inode *inode, struct file *file)
}
disk->major = MAJOR_NR;
disk->first_minor = dev;
- disk->minor_shift = 0;
disk->fops = &mtd_fops;
sprintf(disk->disk_name, "mtd%d", dev);
mtdblk->disk = disk;
@@ -518,8 +517,6 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
switch (cmd) {
case BLKFLSBUF:
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
down(&mtdblk->cache_sem);
diff --git a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c
index 65b97e3a11df..1878f540f3b6 100644
--- a/drivers/mtd/mtdblock_ro.c
+++ b/drivers/mtd/mtdblock_ro.c
@@ -201,8 +201,6 @@ static int mtdblock_ioctl(struct inode * inode, struct file * file,
if (!mtd || cmd != BLKFLSBUF)
return -EINVAL;
- if(!capable(CAP_SYS_ADMIN))
- return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
if (mtd->sync)
@@ -224,7 +222,7 @@ int __init init_mtdblock(void)
int i;
for (i = 0; i < MAX_MTD_DEVICES; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
goto out;
disk->major = MAJOR_NR;
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
new file mode 100644
index 000000000000..4c16c0e43e0f
--- /dev/null
+++ b/drivers/mtd/mtdconcat.c
@@ -0,0 +1,675 @@
+/*
+ * MTD device concatenation layer
+ *
+ * (C) 2002 Robert Kaiser <rkaiser@sysgo.de>
+ *
+ * This code is GPL
+ *
+ * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/concat.h>
+
+/*
+ * Our storage structure:
+ * Subdev points to an array of pointers to struct mtd_info objects
+ * which is allocated along with this structure
+ *
+ */
+struct mtd_concat {
+ struct mtd_info mtd;
+ int num_subdev;
+ struct mtd_info **subdev;
+};
+
+/*
+ * how to calculate the size required for the above structure,
+ * including the pointer array subdev points to:
+ */
+#define SIZEOF_STRUCT_MTD_CONCAT(num_subdev) \
+ ((sizeof(struct mtd_concat) + (num_subdev) * sizeof(struct mtd_info *)))
+
+
+/*
+ * Given a pointer to the MTD object in the mtd_concat structure,
+ * we can retrieve the pointer to that structure with this macro.
+ */
+#define CONCAT(x) ((struct mtd_concat *)(x))
+
+
+/*
+ * MTD methods which look up the relevant subdevice, translate the
+ * effective address and pass through to the subdevice.
+ */
+
+static int concat_read (struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (from >= subdev->size)
+ {
+ size = 0;
+ from -= subdev->size;
+ }
+ else
+ {
+ if (from + len > subdev->size)
+ size = subdev->size - from;
+ else
+ size = len;
+
+ err = subdev->read(subdev, from, size, &retsize, buf);
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ from = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_write (struct mtd_info *mtd, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int err = -EINVAL;
+ int i;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ *retlen = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size, retsize;
+
+ if (to >= subdev->size)
+ {
+ size = 0;
+ to -= subdev->size;
+ }
+ else
+ {
+ if (to + len > subdev->size)
+ size = subdev->size - to;
+ else
+ size = len;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ err = -EROFS;
+ else
+ err = subdev->write(subdev, to, size, &retsize, buf);
+
+ if(err)
+ break;
+
+ *retlen += retsize;
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ buf += size;
+ to = 0;
+ }
+ }
+ return err;
+}
+
+static void concat_erase_callback (struct erase_info *instr)
+{
+ wake_up((wait_queue_head_t *)instr->priv);
+}
+
+static int concat_dev_erase(struct mtd_info *mtd, struct erase_info *erase)
+{
+ int err;
+ wait_queue_head_t waitq;
+ DECLARE_WAITQUEUE(wait, current);
+
+ /*
+ * This code was stol^H^H^H^Hinspired by mtdchar.c
+ */
+ init_waitqueue_head(&waitq);
+
+ erase->mtd = mtd;
+ erase->callback = concat_erase_callback;
+ erase->priv = (unsigned long)&waitq;
+
+ /*
+ * FIXME: Allow INTERRUPTIBLE. Which means
+ * not having the wait_queue head on the stack.
+ */
+ err = mtd->erase(mtd, erase);
+ if (!err)
+ {
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ add_wait_queue(&waitq, &wait);
+ if (erase->state != MTD_ERASE_DONE && erase->state != MTD_ERASE_FAILED)
+ schedule();
+ remove_wait_queue(&waitq, &wait);
+ set_current_state(TASK_RUNNING);
+
+ err = (erase->state == MTD_ERASE_FAILED) ? -EIO : 0;
+ }
+ return err;
+}
+
+static int concat_erase (struct mtd_info *mtd, struct erase_info *instr)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ struct mtd_info *subdev;
+ int i, err;
+ u_int32_t length;
+ struct erase_info *erase;
+
+ if (!(mtd->flags & MTD_WRITEABLE))
+ return -EROFS;
+
+ if(instr->addr > concat->mtd.size)
+ return -EINVAL;
+
+ if(instr->len + instr->addr > concat->mtd.size)
+ return -EINVAL;
+
+ /*
+ * Check for proper erase block alignment of the to-be-erased area.
+ * It is easier to do this based on the super device's erase
+ * region info rather than looking at each particular sub-device
+ * in turn.
+ */
+ if (!concat->mtd.numeraseregions)
+ { /* the easy case: device has uniform erase block size */
+ if(instr->addr & (concat->mtd.erasesize - 1))
+ return -EINVAL;
+ if(instr->len & (concat->mtd.erasesize - 1))
+ return -EINVAL;
+ }
+ else
+ { /* device has variable erase size */
+ struct mtd_erase_region_info *erase_regions = concat->mtd.eraseregions;
+
+ /*
+ * Find the erase region where the to-be-erased area begins:
+ */
+ for(i = 0; i < concat->mtd.numeraseregions &&
+ instr->addr >= erase_regions[i].offset; i++)
+ ;
+ --i;
+
+ /*
+ * Now erase_regions[i] is the region in which the
+ * to-be-erased area begins. Verify that the starting
+ * offset is aligned to this region's erase size:
+ */
+ if (instr->addr & (erase_regions[i].erasesize-1))
+ return -EINVAL;
+
+ /*
+ * now find the erase region where the to-be-erased area ends:
+ */
+ for(; i < concat->mtd.numeraseregions &&
+ (instr->addr + instr->len) >= erase_regions[i].offset ; ++i)
+ ;
+ --i;
+ /*
+ * check if the ending offset is aligned to this region's erase size
+ */
+ if ((instr->addr + instr->len) & (erase_regions[i].erasesize-1))
+ return -EINVAL;
+ }
+
+ /* make a local copy of instr to avoid modifying the caller's struct */
+ erase = kmalloc(sizeof(struct erase_info),GFP_KERNEL);
+
+ if (!erase)
+ return -ENOMEM;
+
+ *erase = *instr;
+ length = instr->len;
+
+ /*
+ * find the subdevice where the to-be-erased area begins, adjust
+ * starting offset to be relative to the subdevice start
+ */
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ subdev = concat->subdev[i];
+ if(subdev->size <= erase->addr)
+ erase->addr -= subdev->size;
+ else
+ break;
+ }
+ if(i >= concat->num_subdev) /* must never happen since size */
+ BUG(); /* limit has been verified above */
+
+ /* now do the erase: */
+ err = 0;
+ for(;length > 0; i++) /* loop for all subevices affected by this request */
+ {
+ subdev = concat->subdev[i]; /* get current subdevice */
+
+ /* limit length to subdevice's size: */
+ if(erase->addr + length > subdev->size)
+ erase->len = subdev->size - erase->addr;
+ else
+ erase->len = length;
+
+ if (!(subdev->flags & MTD_WRITEABLE))
+ {
+ err = -EROFS;
+ break;
+ }
+ length -= erase->len;
+ if ((err = concat_dev_erase(subdev, erase)))
+ {
+ if(err == -EINVAL) /* sanity check: must never happen since */
+ BUG(); /* block alignment has been checked above */
+ break;
+ }
+ /*
+ * erase->addr specifies the offset of the area to be
+ * erased *within the current subdevice*. It can be
+ * non-zero only the first time through this loop, i.e.
+ * for the first subdevice where blocks need to be erased.
+ * All the following erases must begin at the start of the
+ * current subdevice, i.e. at offset zero.
+ */
+ erase->addr = 0;
+ }
+ kfree(erase);
+ if (err)
+ return err;
+
+ instr->state = MTD_ERASE_DONE;
+ if (instr->callback)
+ instr->callback(instr);
+ return 0;
+}
+
+static int concat_lock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = -EINVAL;
+
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size;
+
+ if (ofs >= subdev->size)
+ {
+ size = 0;
+ ofs -= subdev->size;
+ }
+ else
+ {
+ if (ofs + len > subdev->size)
+ size = subdev->size - ofs;
+ else
+ size = len;
+
+ err = subdev->lock(subdev, ofs, size);
+
+ if(err)
+ break;
+
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ ofs = 0;
+ }
+ }
+ return err;
+}
+
+static int concat_unlock (struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, err = 0;
+
+ if ((len + ofs) > mtd->size)
+ return -EINVAL;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ size_t size;
+
+ if (ofs >= subdev->size)
+ {
+ size = 0;
+ ofs -= subdev->size;
+ }
+ else
+ {
+ if (ofs + len > subdev->size)
+ size = subdev->size - ofs;
+ else
+ size = len;
+
+ err = subdev->unlock(subdev, ofs, size);
+
+ if(err)
+ break;
+
+ len -= size;
+ if(len == 0)
+ break;
+
+ err = -EINVAL;
+ ofs = 0;
+ }
+ }
+ return err;
+}
+
+static void concat_sync(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ subdev->sync(subdev);
+ }
+}
+
+static int concat_suspend(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i, rc = 0;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ if((rc = subdev->suspend(subdev)) < 0)
+ return rc;
+ }
+ return rc;
+}
+
+static void concat_resume(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ int i;
+
+ for(i = 0; i < concat->num_subdev; i++)
+ {
+ struct mtd_info *subdev = concat->subdev[i];
+ subdev->resume(subdev);
+ }
+}
+
+/*
+ * This function constructs a virtual MTD device by concatenating
+ * num_devs MTD devices. A pointer to the new device object is
+ * stored to *new_dev upon success. This function does _not_
+ * register any devices: this is the caller's responsibility.
+ */
+struct mtd_info *mtd_concat_create(
+ struct mtd_info *subdev[], /* subdevices to concatenate */
+ int num_devs, /* number of subdevices */
+ char *name) /* name for the new device */
+{
+ int i;
+ size_t size;
+ struct mtd_concat *concat;
+ u_int32_t max_erasesize, curr_erasesize;
+ int num_erase_region;
+
+ printk(KERN_NOTICE "Concatenating MTD devices:\n");
+ for(i = 0; i < num_devs; i++)
+ printk(KERN_NOTICE "(%d): \"%s\"\n", i, subdev[i]->name);
+ printk(KERN_NOTICE "into device \"%s\"\n", name);
+
+ /* allocate the device structure */
+ size = SIZEOF_STRUCT_MTD_CONCAT(num_devs);
+ concat = kmalloc (size, GFP_KERNEL);
+ if(!concat)
+ {
+ printk ("memory allocation error while creating concatenated device \"%s\"\n",
+ name);
+ return NULL;
+ }
+ memset(concat, 0, size);
+ concat->subdev = (struct mtd_info **)(concat + 1);
+
+ /*
+ * Set up the new "super" device's MTD object structure, check for
+ * incompatibilites between the subdevices.
+ */
+ concat->mtd.type = subdev[0]->type;
+ concat->mtd.flags = subdev[0]->flags;
+ concat->mtd.size = subdev[0]->size;
+ concat->mtd.erasesize = subdev[0]->erasesize;
+ concat->mtd.oobblock = subdev[0]->oobblock;
+ concat->mtd.oobsize = subdev[0]->oobsize;
+ concat->mtd.ecctype = subdev[0]->ecctype;
+ concat->mtd.eccsize = subdev[0]->eccsize;
+
+ concat->subdev[0] = subdev[0];
+
+ for(i = 1; i < num_devs; i++)
+ {
+ if(concat->mtd.type != subdev[i]->type)
+ {
+ kfree(concat);
+ printk ("Incompatible device type on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ if(concat->mtd.flags != subdev[i]->flags)
+ { /*
+ * Expect all flags except MTD_WRITEABLE to be equal on
+ * all subdevices.
+ */
+ if((concat->mtd.flags ^ subdev[i]->flags) & ~MTD_WRITEABLE)
+ {
+ kfree(concat);
+ printk ("Incompatible device flags on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ else /* if writeable attribute differs, make super device writeable */
+ concat->mtd.flags |= subdev[i]->flags & MTD_WRITEABLE;
+ }
+ concat->mtd.size += subdev[i]->size;
+ if(concat->mtd.oobblock != subdev[i]->oobblock ||
+ concat->mtd.oobsize != subdev[i]->oobsize ||
+ concat->mtd.ecctype != subdev[i]->ecctype ||
+ concat->mtd.eccsize != subdev[i]->eccsize)
+ {
+ kfree(concat);
+ printk ("Incompatible OOB or ECC data on \"%s\"\n", subdev[i]->name);
+ return NULL;
+ }
+ concat->subdev[i] = subdev[i];
+
+ }
+
+ concat->num_subdev = num_devs;
+ concat->mtd.name = name;
+
+ /*
+ * NOTE: for now, we do not provide any readv()/writev() methods
+ * because they are messy to implement and they are not
+ * used to a great extent anyway.
+ */
+ concat->mtd.erase = concat_erase;
+ concat->mtd.read = concat_read;
+ concat->mtd.write = concat_write;
+ concat->mtd.sync = concat_sync;
+ concat->mtd.lock = concat_lock;
+ concat->mtd.unlock = concat_unlock;
+ concat->mtd.suspend = concat_suspend;
+ concat->mtd.resume = concat_resume;
+
+
+ /*
+ * Combine the erase block size info of the subdevices:
+ *
+ * first, walk the map of the new device and see how
+ * many changes in erase size we have
+ */
+ max_erasesize = curr_erasesize = subdev[0]->erasesize;
+ num_erase_region = 1;
+ for(i = 0; i < num_devs; i++)
+ {
+ if(subdev[i]->numeraseregions == 0)
+ { /* current subdevice has uniform erase size */
+ if(subdev[i]->erasesize != curr_erasesize)
+ { /* if it differs from the last subdevice's erase size, count it */
+ ++num_erase_region;
+ curr_erasesize = subdev[i]->erasesize;
+ if(curr_erasesize > max_erasesize)
+ max_erasesize = curr_erasesize;
+ }
+ }
+ else
+ { /* current subdevice has variable erase size */
+ int j;
+ for(j = 0; j < subdev[i]->numeraseregions; j++)
+ { /* walk the list of erase regions, count any changes */
+ if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+ {
+ ++num_erase_region;
+ curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+ if(curr_erasesize > max_erasesize)
+ max_erasesize = curr_erasesize;
+ }
+ }
+ }
+ }
+
+ if(num_erase_region == 1)
+ { /*
+ * All subdevices have the same uniform erase size.
+ * This is easy:
+ */
+ concat->mtd.erasesize = curr_erasesize;
+ concat->mtd.numeraseregions = 0;
+ }
+ else
+ { /*
+ * erase block size varies across the subdevices: allocate
+ * space to store the data describing the variable erase regions
+ */
+ struct mtd_erase_region_info *erase_region_p;
+ u_int32_t begin, position;
+
+ concat->mtd.erasesize = max_erasesize;
+ concat->mtd.numeraseregions = num_erase_region;
+ concat->mtd.eraseregions = erase_region_p = kmalloc (
+ num_erase_region * sizeof(struct mtd_erase_region_info), GFP_KERNEL);
+ if(!erase_region_p)
+ {
+ kfree(concat);
+ printk ("memory allocation error while creating erase region list"
+ " for device \"%s\"\n", name);
+ return NULL;
+ }
+
+ /*
+ * walk the map of the new device once more and fill in
+ * in erase region info:
+ */
+ curr_erasesize = subdev[0]->erasesize;
+ begin = position = 0;
+ for(i = 0; i < num_devs; i++)
+ {
+ if(subdev[i]->numeraseregions == 0)
+ { /* current subdevice has uniform erase size */
+ if(subdev[i]->erasesize != curr_erasesize)
+ { /*
+ * fill in an mtd_erase_region_info structure for the area
+ * we have walked so far:
+ */
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ begin = position;
+
+ curr_erasesize = subdev[i]->erasesize;
+ ++erase_region_p;
+ }
+ position += subdev[i]->size;
+ }
+ else
+ { /* current subdevice has variable erase size */
+ int j;
+ for(j = 0; j < subdev[i]->numeraseregions; j++)
+ { /* walk the list of erase regions, count any changes */
+ if(subdev[i]->eraseregions[j].erasesize != curr_erasesize)
+ {
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ begin = position;
+
+ curr_erasesize = subdev[i]->eraseregions[j].erasesize;
+ ++erase_region_p;
+ }
+ position += subdev[i]->eraseregions[j].numblocks * curr_erasesize;
+ }
+ }
+ }
+ /* Now write the final entry */
+ erase_region_p->offset = begin;
+ erase_region_p->erasesize = curr_erasesize;
+ erase_region_p->numblocks = (position - begin) / curr_erasesize;
+ }
+
+ return &concat->mtd;
+}
+
+/*
+ * This function destroys an MTD object obtained from concat_mtd_devs()
+ */
+
+void mtd_concat_destroy(struct mtd_info *mtd)
+{
+ struct mtd_concat *concat = CONCAT(mtd);
+ if(concat->mtd.numeraseregions)
+ kfree(concat->mtd.eraseregions);
+ kfree(concat);
+}
+
+
+EXPORT_SYMBOL(mtd_concat_create);
+EXPORT_SYMBOL(mtd_concat_destroy);
+
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Robert Kaiser <rkaiser@sysgo.de>");
+MODULE_DESCRIPTION("Generic support for concatenating of MTD devices");
diff --git a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c
index 60d26b10740e..292894af8252 100644
--- a/drivers/mtd/nftlcore.c
+++ b/drivers/mtd/nftlcore.c
@@ -74,7 +74,7 @@ static void NFTL_setup(struct mtd_info *mtd)
}
nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL);
- gd = alloc_disk();
+ gd = alloc_disk(1 << NFTL_PARTN_BITS);
if (!nftl || !gd) {
kfree(nftl);
put_disk(gd);
@@ -132,7 +132,6 @@ static void NFTL_setup(struct mtd_info *mtd)
sprintf(gd->disk_name, "nftl%c", 'a' + firstfree);
gd->major = MAJOR_NR;
gd->first_minor = firstfree << NFTL_PARTN_BITS;
- gd->minor_shift = NFTL_PARTN_BITS;
set_capacity(gd, nftl->nr_sects);
nftl->disk = gd;
add_disk(gd);
@@ -771,7 +770,6 @@ static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd
return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0;
}
case BLKFLSBUF:
- if (!capable(CAP_SYS_ADMIN)) return -EACCES;
fsync_bdev(inode->i_bdev);
invalidate_bdev(inode->i_bdev, 0);
if (nftl->mtd->sync)
diff --git a/drivers/oprofile/buffer_sync.c b/drivers/oprofile/buffer_sync.c
new file mode 100644
index 000000000000..79b92c1c7965
--- /dev/null
+++ b/drivers/oprofile/buffer_sync.c
@@ -0,0 +1,394 @@
+/**
+ * @file buffer_sync.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * This is the core of the buffer management. Each
+ * CPU buffer is processed and entered into the
+ * global event buffer. Such processing is necessary
+ * in several circumstances, mentioned below.
+ *
+ * The processing does the job of converting the
+ * transitory EIP value into a persistent dentry/offset
+ * value that the profiler can record at its leisure.
+ *
+ * See fs/dcookies.c for a description of the dentry/offset
+ * objects.
+ */
+
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <linux/dcookies.h>
+#include <linux/notifier.h>
+#include <linux/profile.h>
+#include <linux/workqueue.h>
+
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "oprofile_stats.h"
+
+#define DEFAULT_EXPIRE (HZ / 4)
+
+static void wq_sync_buffers(void *);
+static DECLARE_WORK(sync_wq, wq_sync_buffers, 0);
+
+static struct timer_list sync_timer;
+static void timer_ping(unsigned long data);
+static void sync_cpu_buffers(void);
+
+
+/* We must make sure to process every entry in the CPU buffers
+ * before a task got the PF_EXITING flag, otherwise we will hold
+ * references to a possibly freed task_struct. We are safe with
+ * samples past the PF_EXITING point in do_exit(), because we
+ * explicitly check for that in cpu_buffer.c
+ */
+static int exit_task_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+ sync_cpu_buffers();
+ return 0;
+}
+
+/* There are two cases of tasks modifying task->mm->mmap list we
+ * must concern ourselves with. First, when a task is about to
+ * exit (exit_mmap()), we should process the buffer to deal with
+ * any samples in the CPU buffer, before we lose the ->mmap information
+ * we need. Second, a task may unmap (part of) an executable mmap,
+ * so we want to process samples before that happens too
+ */
+static int mm_notify(struct notifier_block * self, unsigned long val, void * data)
+{
+ sync_cpu_buffers();
+ return 0;
+}
+
+
+static struct notifier_block exit_task_nb = {
+ .notifier_call = exit_task_notify,
+};
+
+static struct notifier_block exec_unmap_nb = {
+ .notifier_call = mm_notify,
+};
+
+static struct notifier_block exit_mmap_nb = {
+ .notifier_call = mm_notify,
+};
+
+
+int sync_start(void)
+{
+ int err = profile_event_register(EXIT_TASK, &exit_task_nb);
+ if (err)
+ goto out;
+ err = profile_event_register(EXIT_MMAP, &exit_mmap_nb);
+ if (err)
+ goto out2;
+ err = profile_event_register(EXEC_UNMAP, &exec_unmap_nb);
+ if (err)
+ goto out3;
+
+ sync_timer.function = timer_ping;
+ sync_timer.expires = jiffies + DEFAULT_EXPIRE;
+ add_timer(&sync_timer);
+out:
+ return err;
+out3:
+ profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
+out2:
+ profile_event_unregister(EXIT_TASK, &exit_task_nb);
+ goto out;
+}
+
+
+void sync_stop(void)
+{
+ profile_event_unregister(EXIT_TASK, &exit_task_nb);
+ profile_event_unregister(EXIT_MMAP, &exit_mmap_nb);
+ profile_event_unregister(EXEC_UNMAP, &exec_unmap_nb);
+ del_timer_sync(&sync_timer);
+}
+
+
+/* Optimisation. We can manage without taking the dcookie sem
+ * because we cannot reach this code without at least one
+ * dcookie user still being registered (namely, the reader
+ * of the event buffer). */
+static inline u32 fast_get_dcookie(struct dentry * dentry,
+ struct vfsmount * vfsmnt)
+{
+ u32 cookie;
+
+ if (dentry->d_cookie)
+ return (u32)dentry;
+ get_dcookie(dentry, vfsmnt, &cookie);
+ return cookie;
+}
+
+
+/* Look up the dcookie for the task's first VM_EXECUTABLE mapping,
+ * which corresponds loosely to "application name". This is
+ * not strictly necessary but allows oprofile to associate
+ * shared-library samples with particular applications
+ */
+static u32 get_exec_dcookie(struct mm_struct * mm)
+{
+ u32 cookie = 0;
+ struct vm_area_struct * vma;
+
+ if (!mm)
+ goto out;
+
+ for (vma = mm->mmap; vma; vma = vma->vm_next) {
+ if (!vma->vm_file)
+ continue;
+ if (!vma->vm_flags & VM_EXECUTABLE)
+ continue;
+ cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ break;
+ }
+
+out:
+ return cookie;
+}
+
+
+/* Convert the EIP value of a sample into a persistent dentry/offset
+ * pair that can then be added to the global event buffer. We make
+ * sure to do this lookup before a mm->mmap modification happens so
+ * we don't lose track.
+ */
+static u32 lookup_dcookie(struct mm_struct * mm, unsigned long addr, off_t * offset)
+{
+ u32 cookie = 0;
+ struct vm_area_struct * vma;
+
+ for (vma = find_vma(mm, addr); vma; vma = vma->vm_next) {
+ if (!vma)
+ goto out;
+
+ if (!vma->vm_file)
+ continue;
+
+ if (addr < vma->vm_start || addr >= vma->vm_end)
+ continue;
+
+ cookie = fast_get_dcookie(vma->vm_file->f_dentry,
+ vma->vm_file->f_vfsmnt);
+ *offset = (vma->vm_pgoff << PAGE_SHIFT) + addr - vma->vm_start;
+ break;
+ }
+out:
+ return cookie;
+}
+
+
+static u32 last_cookie = ~0UL;
+
+static void add_cpu_switch(int i)
+{
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(CPU_SWITCH_CODE);
+ add_event_entry(i);
+ last_cookie = ~0UL;
+}
+
+
+static void add_ctx_switch(pid_t pid, u32 cookie)
+{
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(CTX_SWITCH_CODE);
+ add_event_entry(pid);
+ add_event_entry(cookie);
+}
+
+
+static void add_cookie_switch(u32 cookie)
+{
+ add_event_entry(ESCAPE_CODE);
+ add_event_entry(COOKIE_SWITCH_CODE);
+ add_event_entry(cookie);
+}
+
+
+static void add_sample_entry(unsigned long offset, unsigned long event)
+{
+ add_event_entry(offset);
+ add_event_entry(event);
+}
+
+
+static void add_us_sample(struct mm_struct * mm, struct op_sample * s)
+{
+ u32 cookie;
+ off_t offset;
+
+ cookie = lookup_dcookie(mm, s->eip, &offset);
+
+ if (!cookie)
+ return;
+
+ if (cookie != last_cookie) {
+ add_cookie_switch(cookie);
+ last_cookie = cookie;
+ }
+
+ add_sample_entry(offset, s->event);
+}
+
+
+static inline int is_kernel(unsigned long val)
+{
+ return val > __PAGE_OFFSET;
+}
+
+
+/* Add a sample to the global event buffer. If possible the
+ * sample is converted into a persistent dentry/offset pair
+ * for later lookup from userspace.
+ */
+static void add_sample(struct mm_struct * mm, struct op_sample * s)
+{
+ if (is_kernel(s->eip)) {
+ add_sample_entry(s->eip, s->event);
+ } else if (mm) {
+ add_us_sample(mm, s);
+ }
+}
+
+
+static void release_mm(struct mm_struct * mm)
+{
+ if (mm)
+ up_read(&mm->mmap_sem);
+}
+
+
+/* Take the task's mmap_sem to protect ourselves from
+ * races when we do lookup_dcookie().
+ */
+static struct mm_struct * take_task_mm(struct task_struct * task)
+{
+ struct mm_struct * mm;
+ task_lock(task);
+ mm = task->mm;
+ task_unlock(task);
+
+ /* if task->mm !NULL, mm_count must be at least 1. It cannot
+ * drop to 0 without the task exiting, which will have to sleep
+ * on buffer_sem first. So we do not need to mark mm_count
+ * ourselves.
+ */
+ if (mm) {
+ /* More ugliness. If a task took its mmap
+ * sem then came to sleep on buffer_sem we
+ * will deadlock waiting for it. So we can
+ * but try. This will lose samples :/
+ */
+ if (!down_read_trylock(&mm->mmap_sem)) {
+ /* FIXME: this underestimates samples lost */
+ atomic_inc(&oprofile_stats.sample_lost_mmap_sem);
+ mm = NULL;
+ }
+ }
+
+ return mm;
+}
+
+
+static inline int is_ctx_switch(unsigned long val)
+{
+ return val == ~0UL;
+}
+
+
+/* Sync one of the CPU's buffers into the global event buffer.
+ * Here we need to go through each batch of samples punctuated
+ * by context switch notes, taking the task's mmap_sem and doing
+ * lookup in task->mm->mmap to convert EIP into dcookie/offset
+ * value.
+ */
+static void sync_buffer(struct oprofile_cpu_buffer * cpu_buf)
+{
+ struct mm_struct * mm = 0;
+ struct task_struct * new;
+ u32 cookie;
+ int i;
+
+ for (i=0; i < cpu_buf->pos; ++i) {
+ struct op_sample * s = &cpu_buf->buffer[i];
+
+ if (is_ctx_switch(s->eip)) {
+ new = (struct task_struct *)s->event;
+
+ release_mm(mm);
+ mm = take_task_mm(new);
+
+ cookie = get_exec_dcookie(mm);
+ add_ctx_switch(new->pid, cookie);
+ } else {
+ add_sample(mm, s);
+ }
+ }
+ release_mm(mm);
+
+ cpu_buf->pos = 0;
+}
+
+
+/* Process each CPU's local buffer into the global
+ * event buffer.
+ */
+static void sync_cpu_buffers(void)
+{
+ int i;
+
+ down(&buffer_sem);
+
+ for (i = 0; i < NR_CPUS; ++i) {
+ struct oprofile_cpu_buffer * cpu_buf;
+
+ if (!cpu_possible(i))
+ continue;
+
+ cpu_buf = &cpu_buffer[i];
+
+ /* We take a spin lock even though we might
+ * sleep. It's OK because other users are try
+ * lockers only, and this region is already
+ * protected by buffer_sem. It's raw to prevent
+ * the preempt bogometer firing. Fruity, huh ? */
+ _raw_spin_lock(&cpu_buf->int_lock);
+ add_cpu_switch(i);
+ sync_buffer(cpu_buf);
+ _raw_spin_unlock(&cpu_buf->int_lock);
+ }
+
+ up(&buffer_sem);
+
+ mod_timer(&sync_timer, jiffies + DEFAULT_EXPIRE);
+}
+
+
+static void wq_sync_buffers(void * data)
+{
+ sync_cpu_buffers();
+}
+
+
+/* It is possible that we could have no munmap() or
+ * other events for a period of time. This will lead
+ * the CPU buffers to overflow and lose samples and
+ * context switches. We try to reduce the problem
+ * by timing out when nothing happens for a while.
+ */
+static void timer_ping(unsigned long data)
+{
+ schedule_work(&sync_wq);
+ /* timer is re-added by the scheduled task */
+}
diff --git a/drivers/oprofile/buffer_sync.h b/drivers/oprofile/buffer_sync.h
new file mode 100644
index 000000000000..a8def27d8502
--- /dev/null
+++ b/drivers/oprofile/buffer_sync.h
@@ -0,0 +1,19 @@
+/**
+ * @file buffer_sync.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROFILE_BUFFER_SYNC_H
+#define OPROFILE_BUFFER_SYNC_H
+
+/* add the necessary profiling hooks */
+int sync_start(void);
+
+/* remove the hooks */
+void sync_stop(void);
+
+#endif /* OPROFILE_BUFFER_SYNC_H */
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c
new file mode 100644
index 000000000000..42af606defd4
--- /dev/null
+++ b/drivers/oprofile/cpu_buffer.c
@@ -0,0 +1,135 @@
+/**
+ * @file cpu_buffer.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * Each CPU has a local buffer that stores PC value/event
+ * pairs. We also log context switches when we notice them.
+ * Eventually each CPU's buffer is processed into the global
+ * event buffer by sync_cpu_buffers().
+ *
+ * We use a local buffer for two reasons: an NMI or similar
+ * interrupt cannot synchronise, and high sampling rates
+ * would lead to catastrophic global synchronisation if
+ * a global buffer was used.
+ */
+
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+
+#include "cpu_buffer.h"
+#include "oprof.h"
+#include "oprofile_stats.h"
+
+struct oprofile_cpu_buffer cpu_buffer[NR_CPUS] __cacheline_aligned;
+
+static unsigned long buffer_size;
+
+static void __free_cpu_buffers(int num)
+{
+ int i;
+
+ for (i=0; i < num; ++i) {
+ struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+
+ if (!cpu_possible(i))
+ continue;
+
+ vfree(b->buffer);
+ }
+}
+
+
+int alloc_cpu_buffers(void)
+{
+ int i;
+
+ buffer_size = fs_cpu_buffer_size;
+
+ for (i=0; i < NR_CPUS; ++i) {
+ struct oprofile_cpu_buffer * b = &cpu_buffer[i];
+
+ if (!cpu_possible(i))
+ continue;
+
+ b->buffer = vmalloc(sizeof(struct op_sample) * buffer_size);
+ if (!b->buffer)
+ goto fail;
+
+ spin_lock_init(&b->int_lock);
+ b->pos = 0;
+ b->last_task = 0;
+ b->sample_received = 0;
+ b->sample_lost_locked = 0;
+ b->sample_lost_overflow = 0;
+ }
+ return 0;
+fail:
+ __free_cpu_buffers(i);
+ return -ENOMEM;
+}
+
+
+void free_cpu_buffers(void)
+{
+ __free_cpu_buffers(NR_CPUS);
+}
+
+
+/* Note we can't use a semaphore here as this is supposed to
+ * be safe from any context. Instead we trylock the CPU's int_lock.
+ * int_lock is taken by the processing code in sync_cpu_buffers()
+ * so we avoid disturbing that.
+ */
+void oprofile_add_sample(unsigned long eip, unsigned long event, int cpu)
+{
+ struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
+ struct task_struct * task;
+
+ /* temporary ? */
+ BUG_ON(!oprofile_started);
+
+ cpu_buf->sample_received++;
+
+ if (!spin_trylock(&cpu_buf->int_lock)) {
+ cpu_buf->sample_lost_locked++;
+ return;
+ }
+
+ if (cpu_buf->pos > buffer_size - 2) {
+ cpu_buf->sample_lost_overflow++;
+ goto out;
+ }
+
+ task = current;
+
+ /* notice a task switch */
+ if (cpu_buf->last_task != task) {
+ cpu_buf->last_task = task;
+ if (!(task->flags & PF_EXITING)) {
+ cpu_buf->buffer[cpu_buf->pos].eip = ~0UL;
+ cpu_buf->buffer[cpu_buf->pos].event = (unsigned long)task;
+ cpu_buf->pos++;
+ }
+ }
+
+ /* If the task is exiting it's not safe to take a sample
+ * as the task_struct is about to be freed. We can't just
+ * notify at release_task() time because of CLONE_DETACHED
+ * tasks that release_task() themselves.
+ */
+ if (task->flags & PF_EXITING) {
+ cpu_buf->sample_lost_task_exit++;
+ goto out;
+ }
+
+ cpu_buf->buffer[cpu_buf->pos].eip = eip;
+ cpu_buf->buffer[cpu_buf->pos].event = event;
+ cpu_buf->pos++;
+out:
+ spin_unlock(&cpu_buf->int_lock);
+}
diff --git a/drivers/oprofile/cpu_buffer.h b/drivers/oprofile/cpu_buffer.h
new file mode 100644
index 000000000000..87ce0a18550d
--- /dev/null
+++ b/drivers/oprofile/cpu_buffer.h
@@ -0,0 +1,45 @@
+/**
+ * @file cpu_buffer.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROFILE_CPU_BUFFER_H
+#define OPROFILE_CPU_BUFFER_H
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+
+struct task_struct;
+
+/* allocate a sample buffer for each CPU */
+int alloc_cpu_buffers(void);
+
+void free_cpu_buffers(void);
+
+/* CPU buffer is composed of such entries (which are
+ * also used for context switch notes)
+ */
+struct op_sample {
+ unsigned long eip;
+ unsigned long event;
+};
+
+struct oprofile_cpu_buffer {
+ spinlock_t int_lock;
+ /* protected by int_lock */
+ unsigned long pos;
+ struct task_struct * last_task;
+ struct op_sample * buffer;
+ unsigned long sample_received;
+ unsigned long sample_lost_locked;
+ unsigned long sample_lost_overflow;
+ unsigned long sample_lost_task_exit;
+} ____cacheline_aligned;
+
+extern struct oprofile_cpu_buffer cpu_buffer[];
+
+#endif /* OPROFILE_CPU_BUFFER_H */
diff --git a/drivers/oprofile/event_buffer.c b/drivers/oprofile/event_buffer.c
new file mode 100644
index 000000000000..3552be34eca7
--- /dev/null
+++ b/drivers/oprofile/event_buffer.c
@@ -0,0 +1,186 @@
+/**
+ * @file event_buffer.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ *
+ * This is the global event buffer that the user-space
+ * daemon reads from. The event buffer is an untyped array
+ * of unsigned longs. Entries are prefixed by the
+ * escape value ESCAPE_CODE followed by an identifying code.
+ */
+
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+#include <linux/smp.h>
+#include <linux/dcookies.h>
+#include <linux/oprofile.h>
+#include <asm/uaccess.h>
+#include <asm/atomic.h>
+
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "oprof.h"
+#include "oprofile_stats.h"
+
+DECLARE_MUTEX(buffer_sem);
+
+static unsigned long buffer_opened;
+static DECLARE_WAIT_QUEUE_HEAD(buffer_wait);
+static unsigned long * event_buffer;
+static unsigned long buffer_size;
+static unsigned long buffer_watershed;
+static size_t buffer_pos;
+/* atomic_t because wait_event checks it outside of buffer_sem */
+static atomic_t buffer_ready = ATOMIC_INIT(0);
+
+/* Add an entry to the event buffer. When we
+ * get near to the end we wake up the process
+ * sleeping on the read() of the file.
+ */
+void add_event_entry(unsigned long value)
+{
+ if (buffer_pos == buffer_size) {
+ atomic_inc(&oprofile_stats.event_lost_overflow);
+ return;
+ }
+
+ event_buffer[buffer_pos] = value;
+ if (++buffer_pos == buffer_size - buffer_watershed) {
+ atomic_set(&buffer_ready, 1);
+ wake_up(&buffer_wait);
+ }
+}
+
+
+/* Wake up the waiting process if any. This happens
+ * on "echo 0 >/dev/oprofile/enable" so the daemon
+ * processes the data remaining in the event buffer.
+ */
+void wake_up_buffer_waiter(void)
+{
+ down(&buffer_sem);
+ atomic_set(&buffer_ready, 1);
+ wake_up(&buffer_wait);
+ up(&buffer_sem);
+}
+
+
+int alloc_event_buffer(void)
+{
+ int err = -ENOMEM;
+
+ spin_lock(&oprofilefs_lock);
+ buffer_size = fs_buffer_size;
+ buffer_watershed = fs_buffer_watershed;
+ spin_unlock(&oprofilefs_lock);
+
+ if (buffer_watershed >= buffer_size)
+ return -EINVAL;
+
+ event_buffer = vmalloc(sizeof(unsigned long) * buffer_size);
+ if (!event_buffer)
+ goto out;
+
+ err = 0;
+out:
+ return err;
+}
+
+
+void free_event_buffer(void)
+{
+ vfree(event_buffer);
+}
+
+
+int event_buffer_open(struct inode * inode, struct file * file)
+{
+ int err = -EPERM;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ if (test_and_set_bit(0, &buffer_opened))
+ return -EBUSY;
+
+ /* Register as a user of dcookies
+ * to ensure they persist for the lifetime of
+ * the open event file
+ */
+ err = -EINVAL;
+ file->private_data = dcookie_register();
+ if (!file->private_data)
+ goto out;
+
+ if ((err = oprofile_setup()))
+ goto fail;
+
+ /* NB: the actual start happens from userspace
+ * echo 1 >/dev/oprofile/enable
+ */
+
+ return 0;
+
+fail:
+ dcookie_unregister(file->private_data);
+out:
+ clear_bit(0, &buffer_opened);
+ return err;
+}
+
+
+int event_buffer_release(struct inode * inode, struct file * file)
+{
+ oprofile_stop();
+ oprofile_shutdown();
+ dcookie_unregister(file->private_data);
+ buffer_pos = 0;
+ atomic_set(&buffer_ready, 0);
+ clear_bit(0, &buffer_opened);
+ return 0;
+}
+
+
+ssize_t event_buffer_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+ int retval = -EINVAL;
+ size_t const max = buffer_size * sizeof(unsigned long);
+
+ /* handling partial reads is more trouble than it's worth */
+ if (count != max || *offset)
+ return -EINVAL;
+
+ /* wait for the event buffer to fill up with some data */
+ wait_event_interruptible(buffer_wait, atomic_read(&buffer_ready));
+ if (signal_pending(current))
+ return -EINTR;
+
+ down(&buffer_sem);
+
+ atomic_set(&buffer_ready, 0);
+
+ retval = -EFAULT;
+
+ count = buffer_pos * sizeof(unsigned long);
+
+ if (copy_to_user(buf, event_buffer, count))
+ goto out;
+
+ retval = count;
+ buffer_pos = 0;
+
+out:
+ up(&buffer_sem);
+ return retval;
+}
+
+struct file_operations event_buffer_fops = {
+ .open = event_buffer_open,
+ .release = event_buffer_release,
+ .read = event_buffer_read,
+};
diff --git a/drivers/oprofile/event_buffer.h b/drivers/oprofile/event_buffer.h
new file mode 100644
index 000000000000..11d2ed4dea42
--- /dev/null
+++ b/drivers/oprofile/event_buffer.h
@@ -0,0 +1,42 @@
+/**
+ * @file event_buffer.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef EVENT_BUFFER_H
+#define EVENT_BUFFER_H
+
+#include <linux/types.h>
+#include <linux/sem.h>
+
+int alloc_event_buffer(void);
+
+void free_event_buffer(void);
+
+/* wake up the process sleeping on the event file */
+void wake_up_buffer_waiter(void);
+
+/* Each escaped entry is prefixed by ESCAPE_CODE
+ * then one of the following codes, then the
+ * relevant data.
+ */
+#define ESCAPE_CODE ~0UL
+#define CTX_SWITCH_CODE 1
+#define CPU_SWITCH_CODE 2
+#define COOKIE_SWITCH_CODE 3
+
+/* add data to the event buffer */
+void add_event_entry(unsigned long data);
+
+extern struct file_operations event_buffer_fops;
+
+/* mutex between sync_cpu_buffers() and the
+ * file reading code.
+ */
+extern struct semaphore buffer_sem;
+
+#endif /* EVENT_BUFFER_H */
diff --git a/drivers/oprofile/oprof.c b/drivers/oprofile/oprof.c
new file mode 100644
index 000000000000..91e120f1ac75
--- /dev/null
+++ b/drivers/oprofile/oprof.c
@@ -0,0 +1,153 @@
+/**
+ * @file oprof.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/notifier.h>
+#include <linux/profile.h>
+#include <linux/oprofile.h>
+
+#include "oprof.h"
+#include "event_buffer.h"
+#include "cpu_buffer.h"
+#include "buffer_sync.h"
+#include "oprofile_stats.h"
+
+struct oprofile_operations * oprofile_ops;
+enum oprofile_cpu oprofile_cpu_type;
+unsigned long oprofile_started;
+static unsigned long is_setup;
+static DECLARE_MUTEX(start_sem);
+
+int oprofile_setup(void)
+{
+ int err;
+
+ if ((err = alloc_cpu_buffers()))
+ goto out;
+
+ if ((err = alloc_event_buffer()))
+ goto out1;
+
+ if (oprofile_ops->setup && (err = oprofile_ops->setup()))
+ goto out2;
+
+ /* Note even though this starts part of the
+ * profiling overhead, it's necessary to prevent
+ * us missing task deaths and eventually oopsing
+ * when trying to process the event buffer.
+ */
+ if ((err = sync_start()))
+ goto out3;
+
+ down(&start_sem);
+ is_setup = 1;
+ up(&start_sem);
+ return 0;
+
+out3:
+ if (oprofile_ops->shutdown)
+ oprofile_ops->shutdown();
+out2:
+ free_event_buffer();
+out1:
+ free_cpu_buffers();
+out:
+ return err;
+}
+
+
+/* Actually start profiling (echo 1>/dev/oprofile/enable) */
+int oprofile_start(void)
+{
+ int err = -EINVAL;
+
+ down(&start_sem);
+
+ if (!is_setup)
+ goto out;
+
+ err = 0;
+
+ if (oprofile_started)
+ goto out;
+
+ if ((err = oprofile_ops->start()))
+ goto out;
+
+ oprofile_started = 1;
+ oprofile_reset_stats();
+out:
+ up(&start_sem);
+ return err;
+}
+
+
+/* echo 0>/dev/oprofile/enable */
+void oprofile_stop(void)
+{
+ down(&start_sem);
+ if (!oprofile_started)
+ goto out;
+ oprofile_ops->stop();
+ oprofile_started = 0;
+ /* wake up the daemon to read what remains */
+ wake_up_buffer_waiter();
+out:
+ up(&start_sem);
+}
+
+
+void oprofile_shutdown(void)
+{
+ sync_stop();
+ if (oprofile_ops->shutdown)
+ oprofile_ops->shutdown();
+ /* down() is also necessary to synchronise all pending events
+ * before freeing */
+ down(&buffer_sem);
+ is_setup = 0;
+ up(&buffer_sem);
+ free_event_buffer();
+ free_cpu_buffers();
+}
+
+
+static int __init oprofile_init(void)
+{
+ int err;
+
+ /* Architecture must fill in the interrupt ops and the
+ * logical CPU type.
+ */
+ err = oprofile_arch_init(&oprofile_ops, &oprofile_cpu_type);
+ if (err)
+ goto out;
+
+ err = oprofilefs_register();
+ if (err)
+ goto out;
+
+out:
+ return err;
+}
+
+
+static void __exit oprofile_exit(void)
+{
+ oprofilefs_unregister();
+}
+
+MODULE_LICENSE("GPL");
+module_init(oprofile_init);
+module_exit(oprofile_exit);
diff --git a/drivers/oprofile/oprof.h b/drivers/oprofile/oprof.h
new file mode 100644
index 000000000000..9f19ba5f39b9
--- /dev/null
+++ b/drivers/oprofile/oprof.h
@@ -0,0 +1,34 @@
+/**
+ * @file oprof.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#ifndef OPROF_H
+#define OPROF_H
+
+#include <linux/spinlock.h>
+#include <linux/oprofile.h>
+
+int oprofile_setup(void);
+void oprofile_shutdown(void);
+
+int oprofilefs_register(void);
+void oprofilefs_unregister(void);
+
+int oprofile_start(void);
+void oprofile_stop(void);
+
+extern unsigned long fs_buffer_size;
+extern unsigned long fs_cpu_buffer_size;
+extern unsigned long fs_buffer_watershed;
+extern enum oprofile_cpu oprofile_cpu_type;
+extern struct oprofile_operations * oprofile_ops;
+extern unsigned long oprofile_started;
+
+void oprofile_create_files(struct super_block * sb, struct dentry * root);
+
+#endif /* OPROF_H */
diff --git a/drivers/oprofile/oprofile_files.c b/drivers/oprofile/oprofile_files.c
new file mode 100644
index 000000000000..22d8bf5994b6
--- /dev/null
+++ b/drivers/oprofile/oprofile_files.c
@@ -0,0 +1,91 @@
+/**
+ * @file oprofile_files.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon <levon@movementarian.org>
+ */
+
+#include <linux/oprofile.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+
+#include "oprof.h"
+#include "event_buffer.h"
+#include "oprofile_stats.h"
+
+unsigned long fs_buffer_size = 131072;
+unsigned long fs_cpu_buffer_size = 8192;
+unsigned long fs_buffer_watershed = 32768; /* FIXME: tune */
+
+
+static int simple_open(struct inode * inode, struct file * filp)
+{
+ return 0;
+}
+
+
+static ssize_t cpu_type_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+ unsigned long cpu_type = oprofile_cpu_type;
+
+ return oprofilefs_ulong_to_user(&cpu_type, buf, count, offset);
+}
+
+
+static struct file_operations cpu_type_fops = {
+ .open = simple_open,
+ .read = cpu_type_read,
+};
+
+
+static ssize_t enable_read(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+ return oprofilefs_ulong_to_user(&oprofile_started, buf, count, offset);
+}
+
+
+static ssize_t enable_write(struct file *file, char const * buf, size_t count, loff_t * offset)
+{
+ unsigned long val;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = oprofilefs_ulong_from_user(&val, buf, count);
+ if (retval)
+ return retval;
+
+ if (val)
+ retval = oprofile_start();
+ else
+ oprofile_stop();
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+
+static struct file_operations enable_fops = {
+ .open = simple_open,
+ .read = enable_read,
+ .write = enable_write,
+};
+
+
+void oprofile_create_files(struct super_block * sb, struct dentry * root)
+{
+ oprofilefs_create_file(sb, root, "enable", &enable_fops);
+ oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
+ oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
+ oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
+ oprofilefs_create_ulong(sb, root, "cpu_buffer_size", &fs_cpu_buffer_size);
+ oprofilefs_create_file(sb, root, "cpu_type", &cpu_type_fops);
+ oprofile_create_stats_files(sb, root);
+ if (oprofile_ops->create_files)
+ oprofile_ops->create_files(sb, root);
+}
diff --git a/drivers/oprofile/oprofile_stats.c b/drivers/oprofile/oprofile_stats.c
new file mode 100644
index 000000000000..479d8315558f
--- /dev/null
+++ b/drivers/oprofile/oprofile_stats.c
@@ -0,0 +1,77 @@
+/**
+ * @file oprofile_stats.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ */
+
+#include <linux/oprofile.h>
+#include <linux/smp.h>
+
+#include "oprofile_stats.h"
+#include "cpu_buffer.h"
+
+struct oprofile_stat_struct oprofile_stats;
+
+void oprofile_reset_stats(void)
+{
+ struct oprofile_cpu_buffer * cpu_buf;
+ int i;
+
+ for (i = 0; i < NR_CPUS; ++i) {
+ if (!cpu_possible(i))
+ continue;
+
+ cpu_buf = &cpu_buffer[i];
+ cpu_buf->sample_received = 0;
+ cpu_buf->sample_lost_locked = 0;
+ cpu_buf->sample_lost_overflow = 0;
+ cpu_buf->sample_lost_task_exit = 0;
+ }
+
+ atomic_set(&oprofile_stats.sample_lost_mmap_sem, 0);
+ atomic_set(&oprofile_stats.event_lost_overflow, 0);
+}
+
+
+void oprofile_create_stats_files(struct super_block * sb, struct dentry * root)
+{
+ struct oprofile_cpu_buffer * cpu_buf;
+ struct dentry * cpudir;
+ struct dentry * dir;
+ char buf[10];
+ int i;
+
+ dir = oprofilefs_mkdir(sb, root, "stats");
+ if (!dir)
+ return;
+
+ for (i = 0; i < NR_CPUS; ++i) {
+ if (!cpu_possible(i))
+ continue;
+
+ cpu_buf = &cpu_buffer[i];
+ snprintf(buf, 6, "cpu%d", i);
+ cpudir = oprofilefs_mkdir(sb, dir, buf);
+
+ /* Strictly speaking access to these ulongs is racy,
+ * but we can't simply lock them, and they are
+ * informational only.
+ */
+ oprofilefs_create_ro_ulong(sb, cpudir, "sample_received",
+ &cpu_buf->sample_received);
+ oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_locked",
+ &cpu_buf->sample_lost_locked);
+ oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_overflow",
+ &cpu_buf->sample_lost_overflow);
+ oprofilefs_create_ro_ulong(sb, cpudir, "sample_lost_task_exit",
+ &cpu_buf->sample_lost_task_exit);
+ }
+
+ oprofilefs_create_ro_atomic(sb, dir, "sample_lost_mmap_sem",
+ &oprofile_stats.sample_lost_mmap_sem);
+ oprofilefs_create_ro_atomic(sb, dir, "event_lost_overflow",
+ &oprofile_stats.event_lost_overflow);
+}
diff --git a/drivers/oprofile/oprofile_stats.h b/drivers/oprofile/oprofile_stats.h
new file mode 100644
index 000000000000..8ca3596c2bef
--- /dev/null
+++ b/drivers/oprofile/oprofile_stats.h
@@ -0,0 +1,31 @@
+/**
+ * @file oprofile_stats.h
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ */
+
+#ifndef OPROFILE_STATS_H
+#define OPROFILE_STATS_H
+
+#include <asm/atomic.h>
+
+struct oprofile_stat_struct {
+ atomic_t sample_lost_mmap_sem;
+ atomic_t event_lost_overflow;
+};
+
+extern struct oprofile_stat_struct oprofile_stats;
+
+/* reset all stats to zero */
+void oprofile_reset_stats(void);
+
+struct super_block;
+struct dentry;
+
+/* create the stats/ dir */
+void oprofile_create_stats_files(struct super_block * sb, struct dentry * root);
+
+#endif /* OPROFILE_STATS_H */
diff --git a/drivers/oprofile/oprofilefs.c b/drivers/oprofile/oprofilefs.c
new file mode 100644
index 000000000000..a86100975cb8
--- /dev/null
+++ b/drivers/oprofile/oprofilefs.c
@@ -0,0 +1,306 @@
+/**
+ * @file oprofilefs.c
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author John Levon
+ *
+ * A simple filesystem for configuration and
+ * access of oprofile.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pagemap.h>
+#include <linux/fs.h>
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/namei.h>
+#include <linux/oprofile.h>
+#include <asm/uaccess.h>
+
+#include "oprof.h"
+
+#define OPROFILEFS_MAGIC 0x6f70726f
+
+spinlock_t oprofilefs_lock = SPIN_LOCK_UNLOCKED;
+
+static struct inode * oprofilefs_get_inode(struct super_block * sb, int mode)
+{
+ struct inode * inode = new_inode(sb);
+
+ if (inode) {
+ inode->i_mode = mode;
+ inode->i_uid = 0;
+ inode->i_gid = 0;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
+ return inode;
+}
+
+
+static struct super_operations s_ops = {
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+};
+
+#define TMPBUFSIZE 50
+
+ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset)
+{
+ char tmpbuf[TMPBUFSIZE];
+ size_t maxlen;
+
+ if (!count)
+ return 0;
+
+ spin_lock(&oprofilefs_lock);
+ maxlen = snprintf(tmpbuf, TMPBUFSIZE, "%lu\n", *val);
+ spin_unlock(&oprofilefs_lock);
+ if (maxlen > TMPBUFSIZE)
+ maxlen = TMPBUFSIZE;
+
+ if (*offset > maxlen)
+ return 0;
+
+ if (count > maxlen - *offset)
+ count = maxlen - *offset;
+
+ if (copy_to_user(buf, tmpbuf + *offset, count))
+ return -EFAULT;
+
+ *offset += count;
+
+ return count;
+}
+
+
+int oprofilefs_ulong_from_user(unsigned long * val, char const * buf, size_t count)
+{
+ char tmpbuf[TMPBUFSIZE];
+
+ if (!count)
+ return 0;
+
+ if (count > TMPBUFSIZE - 1)
+ return -EINVAL;
+
+ memset(tmpbuf, 0x0, TMPBUFSIZE);
+
+ if (copy_from_user(tmpbuf, buf, count))
+ return -EFAULT;
+
+ spin_lock(&oprofilefs_lock);
+ *val = simple_strtoul(tmpbuf, NULL, 10);
+ spin_unlock(&oprofilefs_lock);
+ return 0;
+}
+
+
+static ssize_t ulong_read_file(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+ return oprofilefs_ulong_to_user(file->private_data, buf, count, offset);
+}
+
+
+static ssize_t ulong_write_file(struct file * file, char const * buf, size_t count, loff_t * offset)
+{
+ unsigned long * value = file->private_data;
+ int retval;
+
+ if (*offset)
+ return -EINVAL;
+
+ retval = oprofilefs_ulong_from_user(value, buf, count);
+
+ if (retval)
+ return retval;
+ return count;
+}
+
+
+static int default_open(struct inode * inode, struct file * filp)
+{
+ if (inode->u.generic_ip)
+ filp->private_data = inode->u.generic_ip;
+ return 0;
+}
+
+
+static struct file_operations ulong_fops = {
+ .read = ulong_read_file,
+ .write = ulong_write_file,
+ .open = default_open,
+};
+
+
+static struct file_operations ulong_ro_fops = {
+ .read = ulong_read_file,
+ .open = default_open,
+};
+
+
+static struct dentry * __oprofilefs_create_file(struct super_block * sb,
+ struct dentry * root, char const * name, struct file_operations * fops)
+{
+ struct dentry * dentry;
+ struct inode * inode;
+ struct qstr qname;
+ qname.name = name;
+ qname.len = strlen(name);
+ qname.hash = full_name_hash(qname.name, qname.len);
+ dentry = d_alloc(root, &qname);
+ if (!dentry)
+ return 0;
+ inode = oprofilefs_get_inode(sb, S_IFREG | 0644);
+ if (!inode) {
+ dput(dentry);
+ return 0;
+ }
+ inode->i_fop = fops;
+ d_add(dentry, inode);
+ return dentry;
+}
+
+
+int oprofilefs_create_ulong(struct super_block * sb, struct dentry * root,
+ char const * name, unsigned long * val)
+{
+ struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_fops);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->u.generic_ip = val;
+ return 0;
+}
+
+
+int oprofilefs_create_ro_ulong(struct super_block * sb, struct dentry * root,
+ char const * name, unsigned long * val)
+{
+ struct dentry * d = __oprofilefs_create_file(sb, root, name, &ulong_ro_fops);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->u.generic_ip = val;
+ return 0;
+}
+
+
+static ssize_t atomic_read_file(struct file * file, char * buf, size_t count, loff_t * offset)
+{
+ atomic_t * aval = file->private_data;
+ unsigned long val = atomic_read(aval);
+ return oprofilefs_ulong_to_user(&val, buf, count, offset);
+}
+
+
+static struct file_operations atomic_ro_fops = {
+ .read = atomic_read_file,
+ .open = default_open,
+};
+
+
+int oprofilefs_create_ro_atomic(struct super_block * sb, struct dentry * root,
+ char const * name, atomic_t * val)
+{
+ struct dentry * d = __oprofilefs_create_file(sb, root, name, &atomic_ro_fops);
+ if (!d)
+ return -EFAULT;
+
+ d->d_inode->u.generic_ip = val;
+ return 0;
+}
+
+
+int oprofilefs_create_file(struct super_block * sb, struct dentry * root,
+ char const * name, struct file_operations * fops)
+{
+ if (!__oprofilefs_create_file(sb, root, name, fops))
+ return -EFAULT;
+ return 0;
+}
+
+
+struct dentry * oprofilefs_mkdir(struct super_block * sb,
+ struct dentry * root, char const * name)
+{
+ struct dentry * dentry;
+ struct inode * inode;
+ struct qstr qname;
+ qname.name = name;
+ qname.len = strlen(name);
+ qname.hash = full_name_hash(qname.name, qname.len);
+ dentry = d_alloc(root, &qname);
+ if (!dentry)
+ return 0;
+ inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
+ if (!inode) {
+ dput(dentry);
+ return 0;
+ }
+ inode->i_op = &simple_dir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+ d_add(dentry, inode);
+ return dentry;
+}
+
+
+static int oprofilefs_fill_super(struct super_block * sb, void * data, int silent)
+{
+ struct inode * root_inode;
+ struct dentry * root_dentry;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = OPROFILEFS_MAGIC;
+ sb->s_op = &s_ops;
+
+ root_inode = oprofilefs_get_inode(sb, S_IFDIR | 0755);
+ if (!root_inode)
+ return -ENOMEM;
+ root_inode->i_op = &simple_dir_inode_operations;
+ root_inode->i_fop = &simple_dir_operations;
+ root_dentry = d_alloc_root(root_inode);
+ if (!root_dentry) {
+ iput(root_inode);
+ return -ENOMEM;
+ }
+
+ sb->s_root = root_dentry;
+
+ oprofile_create_files(sb, root_dentry);
+
+ // FIXME: verify kill_litter_super removes our dentries
+ return 0;
+}
+
+
+static struct super_block * oprofilefs_get_sb(struct file_system_type * fs_type,
+ int flags, char * dev_name, void * data)
+{
+ return get_sb_single(fs_type, flags, data, oprofilefs_fill_super);
+}
+
+
+static struct file_system_type oprofilefs_type = {
+ .owner = THIS_MODULE,
+ .name = "oprofilefs",
+ .get_sb = oprofilefs_get_sb,
+ .kill_sb = kill_litter_super,
+};
+
+
+int __init oprofilefs_register(void)
+{
+ return register_filesystem(&oprofilefs_type);
+}
+
+
+void __exit oprofilefs_unregister(void)
+{
+ unregister_filesystem(&oprofilefs_type);
+}
diff --git a/drivers/pcmcia/bulkmem.c b/drivers/pcmcia/bulkmem.c
index e4757451ab17..bb68d267ad2b 100644
--- a/drivers/pcmcia/bulkmem.c
+++ b/drivers/pcmcia/bulkmem.c
@@ -211,7 +211,7 @@ static void handle_erase_timeout(u_long arg)
retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
}
-static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
+static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
{
erase_busy_t *busy;
region_info_t *info;
@@ -229,8 +229,10 @@ static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
else {
erase->State = 1;
busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
- if (!busy)
- return CS_GENERAL_FAILURE;
+ if (!busy) {
+ erase->State = ERASE_FAILED;
+ return;
+ }
busy->erase = erase;
busy->client = handle;
init_timer(&busy->timeout);
@@ -240,7 +242,6 @@ static int setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
retry_erase(busy, 0);
}
}
- return CS_SUCCESS;
} /* setup_erase_request */
/*======================================================================
@@ -325,7 +326,7 @@ int MTDHelperEntry(int func, void *a1, void *a2)
======================================================================*/
-static int setup_regions(client_handle_t handle, int attr,
+static void setup_regions(client_handle_t handle, int attr,
memory_handle_t *list)
{
int i, code, has_jedec, has_geo;
@@ -340,7 +341,7 @@ static int setup_regions(client_handle_t handle, int attr,
code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
if (read_tuple(handle, code, &device) != CS_SUCCESS)
- return CS_GENERAL_FAILURE;
+ return;
code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
if (has_jedec && (device.ndev != jedec.nid)) {
@@ -363,8 +364,10 @@ static int setup_regions(client_handle_t handle, int attr,
if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
(device.dev[i].size != 0)) {
r = kmalloc(sizeof(*r), GFP_KERNEL);
- if (!r)
- return CS_GENERAL_FAILURE;
+ if (!r) {
+ printk(KERN_NOTICE "cs: setup_regions: kmalloc failed!\n");
+ return;
+ }
r->region_magic = REGION_MAGIC;
r->state = 0;
r->dev_info[0] = '\0';
@@ -389,7 +392,6 @@ static int setup_regions(client_handle_t handle, int attr,
}
offset += device.dev[i].size;
}
- return CS_SUCCESS;
} /* setup_regions */
/*======================================================================
@@ -423,10 +425,8 @@ int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn)
if ((handle->Attributes & INFO_MASTER_CLIENT) &&
(!(s->state & SOCKET_REGION_INFO))) {
- if (setup_regions(handle, 0, &s->c_region) != CS_SUCCESS)
- return CS_GENERAL_FAILURE;
- if (setup_regions(handle, 1, &s->a_region) != CS_SUCCESS)
- return CS_GENERAL_FAILURE;
+ setup_regions(handle, 0, &s->c_region);
+ setup_regions(handle, 1, &s->a_region);
s->state |= SOCKET_REGION_INFO;
}
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 98c4f53bcec3..2d97de4e1e2a 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -2110,8 +2110,6 @@ dasd_open(struct inode *inp, struct file *filp)
dasd_device_t *device;
int rc;
- if ((!inp) || kdev_none(inp->i_rdev))
- return -EINVAL;
if (dasd_probeonly) {
MESSAGE(KERN_INFO,
"No access to device (%d:%d) due to probeonly mode",
@@ -2154,8 +2152,6 @@ dasd_release(struct inode *inp, struct file *filp)
dasd_devmap_t *devmap;
dasd_device_t *device;
- if ((!inp) || kdev_none(inp->i_rdev))
- return -EINVAL;
devmap = dasd_devmap_from_kdev(inp->i_rdev);
device = (devmap != NULL) ?
dasd_get_device(devmap) : ERR_PTR(-ENODEV);
diff --git a/drivers/s390/block/dasd_genhd.c b/drivers/s390/block/dasd_genhd.c
index be6c7dc5aa0a..67597043b718 100644
--- a/drivers/s390/block/dasd_genhd.c
+++ b/drivers/s390/block/dasd_genhd.c
@@ -190,14 +190,13 @@ dasd_gendisk_alloc(int devindex)
}
}
- gdp = alloc_disk();
+ gdp = alloc_disk(1 << DASD_PARTN_BITS);
if (!gdp)
return ERR_PTR(-ENOMEM);
/* Initialize gendisk structure. */
gdp->major = mi->major;
gdp->first_minor = index << DASD_PARTN_BITS;
- gdp->minor_shift = DASD_PARTN_BITS;
gdp->fops = &dasd_device_operations;
/*
diff --git a/drivers/s390/block/xpram.c b/drivers/s390/block/xpram.c
index 80f8b7573a41..2c22f4d9e78d 100644
--- a/drivers/s390/block/xpram.c
+++ b/drivers/s390/block/xpram.c
@@ -324,24 +324,12 @@ fail:
return 0;
}
-/*
- * The file operations
- */
-static int xpram_open (struct inode *inode, struct file *filp)
-{
- if (minor(inode->i_rdev) >= xpram_devs)
- return -ENODEV;
- return 0;
-}
-
static int xpram_ioctl (struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
struct hd_geometry *geo;
unsigned long size;
int idx = minor(inode->i_rdev);
- if (idx >= xpram_devs)
- return -ENODEV;
if (cmd != HDIO_GETGEO)
return -EINVAL;
/*
@@ -350,8 +338,6 @@ static int xpram_ioctl (struct inode *inode, struct file *filp,
* whatever cylinders. Tell also that data starts at sector. 4.
*/
geo = (struct hd_geometry *) arg;
- if (geo == NULL)
- return -EINVAL;
size = (xpram_pages * 8) & ~0x3f;
put_user(size >> 6, &geo->cylinders);
put_user(4, &geo->heads);
@@ -364,7 +350,6 @@ static struct block_device_operations xpram_devops =
{
owner: THIS_MODULE,
ioctl: xpram_ioctl,
- open: xpram_open,
};
/*
@@ -441,7 +426,7 @@ static int __init xpram_setup_blkdev(void)
int i, rc = -ENOMEM;
for (i = 0; i < xpram_devs; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
goto out;
xpram_disks[i] = disk;
@@ -481,7 +466,6 @@ static int __init xpram_setup_blkdev(void)
offset += xpram_devices[i].size;
disk->major = XPRAM_MAJOR;
disk->first_minor = i;
- disk->minor_shift = 0;
disk->fops = &xpram_devops;
sprintf(disk->disk_name, "slram%d", i);
set_capacity(disk, xpram_sizes[i] << 1);
diff --git a/drivers/sbus/char/jsflash.c b/drivers/sbus/char/jsflash.c
index 16386c234938..932c1ded3f32 100644
--- a/drivers/sbus/char/jsflash.c
+++ b/drivers/sbus/char/jsflash.c
@@ -104,7 +104,6 @@ static void jsf_outl(unsigned long addr, __u32 data)
struct jsfd_part {
unsigned long dbase;
unsigned long dsize;
- int refcnt;
};
struct jsflash {
@@ -454,54 +453,12 @@ static int jsf_open(struct inode * inode, struct file * filp)
return 0; /* XXX What security? */
}
-static int jsfd_open(struct inode *inode, struct file *file)
-{
- struct jsfd_part *jdp;
- int dev;
-
- if (!inode)
- return -EINVAL;
- dev = MINOR(inode->i_rdev);
- if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
- printk(KERN_ALERT "jsfd_open: illegal minor %d\n", dev);
- return -ENODEV;
- }
-
- jdp = &jsf0.dv[dev];
- jdp->refcnt++;
-
- return 0;
-}
-
static int jsf_release(struct inode *inode, struct file *file)
{
jsf0.busy = 0;
return 0;
}
-static int jsfd_release(struct inode *inode, struct file *file)
-{
- struct jsfd_part *jdp;
- int dev;
-
- if (!inode)
- return -ENODEV;
- dev = MINOR(inode->i_rdev);
- if (dev >= JSF_MAX || (dev & JSF_PART_MASK) >= JSF_NPART) {
- printk(KERN_ALERT "jsfd_release: illegal minor %d\n", dev);
- return -ENODEV;
- }
-
- jdp = &jsf0.dv[dev];
- if (jdp->refcnt <= 0) {
- printk(KERN_ALERT "jsfd_release: bad ref on minor %d\n", dev);
- } else {
- --jdp->refcnt;
- }
- /* N.B. Doesn't lo->file need an fput?? */
- return 0;
-}
-
static struct file_operations jsf_fops = {
.owner = THIS_MODULE,
.llseek = jsf_lseek,
@@ -517,8 +474,6 @@ static struct miscdevice jsf_dev = { JSF_MINOR, "jsflash", &jsf_fops };
static struct block_device_operations jsfd_fops = {
.owner = THIS_MODULE,
- .open = jsfd_open,
- .release = jsfd_release,
};
static int jsflash_init(void)
@@ -622,7 +577,7 @@ static int jsfd_init(void)
err = -ENOMEM;
for (i = 0; i < JSF_MAX; i++) {
- struct gendisk *disk = alloc_disk();
+ struct gendisk *disk = alloc_disk(1);
if (!disk)
goto out;
jsfd_disk[i] = disk;
@@ -642,13 +597,10 @@ static int jsfd_init(void)
jsf = &jsf0; /* actually, &jsfv[i >> JSF_PART_BITS] */
jdp = &jsf->dv[i&JSF_PART_MASK];
- jdp->refcnt = 0;
-
disk->major = JSFD_MAJOR;
disk->first_minor = i;
sprintf(disk->disk_name, "jsfd%d", i);
disk->fops = &jsfd_fops;
- disk->minor_shift = 0;
set_capacity(disk, jdp->dsize >> 9);
add_disk(disk);
set_device_ro(MKDEV(JSFD_MAJOR, i), 1);
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index d32420b99220..b4ee7032b7d7 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2604,21 +2604,21 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
through Host Adapter.
*/
-static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
+/*static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
*HostAdapter)
{
int TargetID;
- /*
+*/ /*
Inhibit the Target Device Inquiry and Reporting if requested.
*/
- if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
+/* if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
HostAdapter->DriverOptions != NULL &&
HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
return;
- /*
+*/ /*
Report on the Target Devices found.
*/
- for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+/* for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
{
BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported)
@@ -2674,7 +2674,7 @@ static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
}
}
}
-
+*/
/*
BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
@@ -2700,6 +2700,49 @@ static void BusLogic_InitializeHostStructure(BusLogic_HostAdapter_T
Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth;
}
+/*
+ BusLogic_SlaveAttach will actually set the queue depth on individual
+ scsi devices as they are permanently added to the device chain. We
+ shamelessly rip off the SelectQueueDepths code to make this work mostly
+ like it used to. Since we don't get called once at the end of the scan
+ but instead get called for each device, we have to do things a bit
+ differently.
+*/
+int BusLogic_SlaveAttach(SCSI_Device_T *Device)
+{
+ BusLogic_HostAdapter_T *HostAdapter =
+ (BusLogic_HostAdapter_T *) Device->host->hostdata;
+ int TargetID = Device->id;
+ int QueueDepth = HostAdapter->QueueDepth[TargetID];
+
+ if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
+ (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
+ {
+ if (QueueDepth == 0)
+ QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+ HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth);
+ }
+ else
+ {
+ HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
+ QueueDepth = HostAdapter->UntaggedQueueDepth;
+ HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ scsi_adjust_queue_depth(Device, 0, QueueDepth);
+ }
+ QueueDepth = 0;
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->TargetFlags[TargetID].TargetExists)
+ {
+ QueueDepth += HostAdapter->QueueDepth[TargetID];
+ }
+ if (QueueDepth > HostAdapter->AllocatedCCBs)
+ BusLogic_CreateAdditionalCCBs(HostAdapter,
+ QueueDepth
+ - HostAdapter->AllocatedCCBs,
+ false);
+ return 0;
+}
/*
BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based
@@ -2709,7 +2752,7 @@ static void BusLogic_InitializeHostStructure(BusLogic_HostAdapter_T
since all the Target Devices have now been probed.
*/
-static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
+/* static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
SCSI_Device_T *DeviceList)
{
BusLogic_HostAdapter_T *HostAdapter =
@@ -2764,8 +2807,8 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
for (Device = DeviceList; Device != NULL; Device = Device->next)
if (Device->host == Host)
Device->queue_depth = HostAdapter->QueueDepth[Device->id];
- /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
- AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
+*/ /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
+/* AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth)
AllocatedQueueDepth = HostAdapter->DriverQueueDepth;
BusLogic_CreateAdditionalCCBs(HostAdapter,
@@ -2778,7 +2821,7 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
HostAdapter = HostAdapter->Next)
BusLogic_ReportTargetDeviceInfo(HostAdapter);
}
-
+*/
/*
BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard
@@ -2881,7 +2924,10 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
HostAdapter->SCSI_Host = Host;
HostAdapter->HostNumber = Host->host_no;
+ /*
+ * This function is deprecated
Host->select_queue_depths = BusLogic_SelectQueueDepths;
+ */
/*
Add Host Adapter to the end of the list of registered BusLogic
Host Adapters.
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 00fb8207a3a8..4f064b12903e 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -60,6 +60,7 @@ extern int BusLogic_ResetCommand(SCSI_Command_T *, unsigned int);
extern int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, struct block_device *,
int *);
extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
+extern int BusLogic_SlaveAttach(SCSI_Device_T *);
/*
@@ -76,6 +77,7 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \
abort: BusLogic_AbortCommand, /* Abort Command Function */ \
reset: BusLogic_ResetCommand, /* Reset Command Function */ \
+ slave_attach: BusLogic_SlaveAttach, /* Configure a SCSI_Device*/ \
bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \
unchecked_isa_dma: 1, /* Default Initial Value */ \
max_sectors: 128, /* I/O queue len limit */ \
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index 797025c9bfc6..27b28318d974 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -128,7 +128,7 @@ static int aac_eh_device_reset(Scsi_Cmnd* cmd);
static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
static int aac_eh_reset(Scsi_Cmnd* cmd);
-static void aac_queuedepth(struct Scsi_Host *, Scsi_Device *);
+static int aac_slave_attach(Scsi_Device *);
/**
* aac_detect - Probe for aacraid cards
@@ -227,12 +227,6 @@ static int aac_detect(Scsi_Host_Template *template)
* value returned as aac->id.
*/
host_ptr->unique_id = aac_count - 1;
- /*
- * This function is called after the device list has
- * been built to find the tagged queueing depth
- * supported for each device.
- */
- host_ptr->select_queue_depths = aac_queuedepth;
aac = (struct aac_dev *)host_ptr->hostdata;
/* attach a pointer back to Scsi_Host */
aac->scsi_host_ptr = host_ptr;
@@ -520,31 +514,25 @@ static int aac_biosparm(Scsi_Disk *disk, struct block_device *bdev, int *geom)
}
/**
- * aac_queuedepth - compute queue depths
- * @host: SCSI host in question
- * @dev: SCSI device we are considering
+ * aac_slave_attach - do device specific setup
+ * @dev: SCSI device we are attaching
*
- * Selects queue depths for each target device based on the host adapter's
- * total capacity and the queue depth supported by the target device.
- * A queue depth of one automatically disables tagged queueing.
+ * Currently, all we do is set the queue depth on the device.
*/
-static void aac_queuedepth(struct Scsi_Host * host, Scsi_Device * dev )
+static int aac_slave_attach(Scsi_Device * dev )
{
- Scsi_Device * dptr;
- dprintk((KERN_DEBUG "aac_queuedepth.\n"));
- dprintk((KERN_DEBUG "Device # Q Depth Online\n"));
- dprintk((KERN_DEBUG "---------------------------\n"));
- for(dptr = dev; dptr != NULL; dptr = dptr->next)
- {
- if(dptr->host == host)
- {
- dptr->queue_depth = 10;
- dprintk((KERN_DEBUG " %2d %d %d\n",
- dptr->id, dptr->queue_depth, dptr->online));
- }
- }
+ if(dev->tagged_supported)
+ scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, 128);
+ else
+ scsi_adjust_queue_depth(dev, 0, 1);
+
+ dprintk((KERN_DEBUG "(scsi%d:%d:%d:%d) Tagged Queue depth %2d, "
+ "%s\n", dev->host->host_no, dev->channel,
+ dev->id, dev->lun, dev->new_queue_depth,
+ dev->online ? "OnLine" : "OffLine"));
+ return 0;
}
@@ -693,6 +681,7 @@ static Scsi_Host_Template driver_template = {
ioctl: aac_ioctl,
queuecommand: aac_queuecommand,
bios_param: aac_biosparm,
+ slave_attach: aac_slave_attach,
can_queue: AAC_NUM_IO_FIB,
this_id: 16,
sg_tablesize: 16,
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 3aeaa5953e25..6df9ff071b23 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -673,6 +673,10 @@
3.3GJ (4/15/02):
1. hacks for lk 2.5 series (D. Gilbert)
+ 3.3GJD (10/14/02):
+ 1. change select_queue_depths to slave_attach
+ 2. make cmd_per_lun be sane again
+
I. Known Problems/Fix List (XXX)
1. Need to add memory mapping workaround. Test the memory mapping.
@@ -4208,8 +4212,7 @@ STATIC PortAddr _asc_def_iop_base[];
*/
STATIC void advansys_interrupt(int, void *, struct pt_regs *);
-STATIC void advansys_select_queue_depths(struct Scsi_Host *,
- Scsi_Device *);
+STATIC int advansys_slave_attach(Scsi_Device *);
STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *);
STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *);
@@ -5307,17 +5310,15 @@ advansys_detect(Scsi_Host_Template *tpnt)
* compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
* SCSI function 'allocate_device' will panic. To allow the driver
* to work as a module in these kernels set 'cmd_per_lun' to 1.
- */
+ *
+ * Note: This is wrong. cmd_per_lun should be set to the depth
+ * you want on untagged devices always.
#ifdef MODULE
+ */
shp->cmd_per_lun = 1;
-#else /* MODULE */
+/* #else
shp->cmd_per_lun = 0;
-#endif /* MODULE */
- /*
- * Use the host 'select_queue_depths' function to determine
- * the number of commands to queue per device.
- */
- shp->select_queue_depths = advansys_select_queue_depths;
+#endif */
/*
* Set the maximum number of scatter-gather elements the
@@ -6346,34 +6347,33 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* Set the number of commands to queue per device for the
* specified host adapter.
*/
-STATIC void
-advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
+STATIC int
+advansys_slave_attach(Scsi_Device *device)
{
- Scsi_Device *device;
asc_board_t *boardp;
- boardp = ASC_BOARDP(shp);
+ boardp = ASC_BOARDP(device->host);
boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
- for (device = devicelist; device != NULL; device = device->next) {
- if (device->host != shp) {
- continue;
- }
- /*
- * Save a pointer to the device and set its initial/maximum
- * queue depth.
- */
+ /*
+ * Save a pointer to the device and set its initial/maximum
+ * queue depth. Only save the pointer for a lun0 dev though.
+ */
+ if(device->lun == 0)
boardp->device[device->id] = device;
+ if(device->tagged_supported) {
if (ASC_NARROW_BOARD(boardp)) {
- device->queue_depth =
- boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id];
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+ boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]);
} else {
- device->queue_depth =
- boardp->dvc_var.adv_dvc_var.max_dvc_qng;
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+ boardp->dvc_var.adv_dvc_var.max_dvc_qng);
}
- ASC_DBG3(1,
- "advansys_select_queue_depths: shp 0x%lx, id %d, depth %d\n",
- (ulong) shp, device->id, device->queue_depth);
+ } else {
+ scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
}
+ ASC_DBG3(1, "advansys_slave_attach: shp 0x%lx, id %d, depth %d\n",
+ (ulong) shp, device->id, device->queue_depth);
+ return 0;
}
/*
@@ -8432,7 +8432,7 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
continue;
}
len = asc_prt_line(cp, leftlen, " %X:%d",
- i, boardp->device[i]->queue_depth);
+ i, boardp->device[i]->current_queue_depth);
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
index 756e5c64cc78..131ee5378922 100644
--- a/drivers/scsi/advansys.h
+++ b/drivers/scsi/advansys.h
@@ -53,6 +53,7 @@ const char *advansys_info(struct Scsi_Host *);
int advansys_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int advansys_reset(Scsi_Cmnd *);
int advansys_biosparam(Disk *, struct block_device *, int[]);
+static int advansys_slave_attach(Scsi_Device *);
#ifdef CONFIG_PROC_FS
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28)
extern struct proc_dir_entry proc_scsi_advansys;
@@ -79,6 +80,7 @@ void advansys_setup(char *, int *);
queuecommand: advansys_queuecommand, \
eh_bus_reset_handler: advansys_reset, \
bios_param: advansys_biosparam, \
+ slave_attach: advansys_slave_attach, \
/* \
* Because the driver may control an ISA adapter 'unchecked_isa_dma' \
* must be set. The flag will be cleared in advansys_detect for non-ISA \
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux.c b/drivers/scsi/aic7xxx/aic7xxx_linux.c
index 70c2109703d5..21e35f436d75 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux.c
@@ -430,8 +430,7 @@ static void ahc_linux_freeze_sim_queue(struct ahc_softc *ahc);
static void ahc_linux_release_sim_queue(u_long arg);
static int ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
-static void ahc_linux_select_queue_depth(struct Scsi_Host *host,
- Scsi_Device *scsi_devs);
+static int ahc_linux_slave_attach(Scsi_Device *device);
static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
Scsi_Device *device);
static struct ahc_linux_target* ahc_linux_alloc_target(struct ahc_softc*,
@@ -1131,7 +1130,6 @@ ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
host->can_queue = AHC_MAX_QUEUE;
host->cmd_per_lun = 2;
host->sg_tablesize = AHC_NSEG;
- host->select_queue_depths = ahc_linux_select_queue_depth;
/* XXX No way to communicate the ID for multiple channels */
host->this_id = ahc->our_id;
host->irq = ahc->platform_data->irq;
@@ -1449,25 +1447,17 @@ ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel,
* Sets the queue depth for each SCSI device hanging
* off the input host adapter.
*/
-static void
-ahc_linux_select_queue_depth(struct Scsi_Host * host,
- Scsi_Device * scsi_devs)
+static int
+ahc_linux_slave_attach(Scsi_Device * device)
{
- Scsi_Device *device;
struct ahc_softc *ahc;
u_long flags;
- int scbnum;
- ahc = *((struct ahc_softc **)host->hostdata);
+ ahc = *((struct ahc_softc **)device->host->hostdata);
ahc_lock(ahc, &flags);
- scbnum = 0;
- for (device = scsi_devs; device != NULL; device = device->next) {
- if (device->host == host) {
- ahc_linux_device_queue_depth(ahc, device);
- scbnum += device->queue_depth;
- }
- }
+ ahc_linux_device_queue_depth(ahc, device);
ahc_unlock(ahc, &flags);
+ return 0;
}
/*
@@ -1512,7 +1502,8 @@ ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
}
}
if (tags != 0) {
- device->queue_depth = tags;
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, tags);
+ /* device->queue_depth = tags; */
ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
printf("scsi%d:%c:%d:%d: Tagged Queuing enabled. Depth %d\n",
ahc->platform_data->host->host_no, device->channel + 'A',
@@ -1523,8 +1514,9 @@ ahc_linux_device_queue_depth(struct ahc_softc *ahc, Scsi_Device * device)
* us at any time even though we can only execute them
* serially on the controller/device. This should remove
* some latency.
- */
device->queue_depth = 2;
+ */
+ scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
}
}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
index 4c3735f5a392..de53201f4df1 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
+++ b/drivers/scsi/aic7xxx/aic7xxx_linux_host.h
@@ -80,7 +80,7 @@ int ahc_linux_abort(Scsi_Cmnd *);
eh_host_reset_handler: NULL, \
abort: NULL, \
reset: NULL, \
- slave_attach: NULL, \
+ slave_attach: ahc_linux_slave_attach, \
bios_param: AIC7XXX_BIOSPARAM, \
can_queue: 253, /* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 9be5e152413b..a8b2860f9c21 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -48,7 +48,6 @@ MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
#include <linux/proc_fs.h>
#include <linux/blk.h>
#include <linux/delay.h> /* for udelay */
-#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <linux/kernel.h> /* for printk */
#include <linux/sched.h>
@@ -356,23 +355,20 @@ static void adpt_inquiry(adpt_hba* pHba)
}
-static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist)
+static int adpt_slave_attach(Scsi_Device * device)
{
- Scsi_Device *device; /* scsi layer per device information */
+ struct Scsi_Host *host = device->host;
adpt_hba* pHba;
pHba = (adpt_hba *) host->hostdata[0];
- for (device = devicelist; device != NULL; device = device->next) {
- if (device->host != host) {
- continue;
- }
- if (host->can_queue) {
- device->queue_depth = host->can_queue - 1;
- } else {
- device->queue_depth = 1;
- }
+ if (host->can_queue && device->tagged_supported) {
+ scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+ host->can_queue - 1);
+ } else {
+ scsi_adjust_queue_depth(device, 0, 1);
}
+ return 0;
}
static int adpt_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
@@ -2194,11 +2190,10 @@ static s32 adpt_scsi_register(adpt_hba* pHba,Scsi_Host_Template * sht)
host->max_id = 16;
host->max_lun = 256;
host->max_channel = pHba->top_scsi_channel + 1;
- host->cmd_per_lun = 256;
+ host->cmd_per_lun = 1;
host->unique_id = (uint) pHba;
host->sg_tablesize = pHba->sg_tablesize;
host->can_queue = pHba->post_fifo_size;
- host->select_queue_depths = adpt_select_queue_depths;
return 0;
}
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
index dfff119adc2b..f9ff2b603629 100644
--- a/drivers/scsi/dpti.h
+++ b/drivers/scsi/dpti.h
@@ -43,6 +43,7 @@ static int adpt_queue(Scsi_Cmnd * cmd, void (*cmdcomplete) (Scsi_Cmnd *));
static int adpt_abort(Scsi_Cmnd * cmd);
static int adpt_reset(Scsi_Cmnd* cmd);
static int adpt_release(struct Scsi_Host *host);
+static int adpt_slave_attach(Scsi_Device *);
static const char *adpt_info(struct Scsi_Host *pSHost);
static int adpt_bios_param(Disk * disk, struct block_device *dev, int geom[]);
@@ -90,10 +91,11 @@ static int adpt_device_reset(Scsi_Cmnd* cmd);
eh_bus_reset_handler: adpt_bus_reset, \
eh_host_reset_handler: adpt_reset, \
bios_param: adpt_bios_param, \
+ slave_attach: adpt_slave_attach, \
can_queue: MAX_TO_IOP_MESSAGES, /* max simultaneous cmds */\
this_id: 7, /* scsi id of host adapter */\
sg_tablesize: 0, /* max scatter-gather cmds */\
- cmd_per_lun: 256, /* cmds per lun (linked cmds) */\
+ cmd_per_lun: 1, /* cmds per lun (linked cmds) */\
use_clustering: ENABLE_CLUSTERING, \
proc_name: "dpt_i2o" /* this is the name of our proc node*/ \
}
@@ -346,7 +348,6 @@ static s32 adpt_rescan(adpt_hba* pHba);
static s32 adpt_i2o_reparse_lct(adpt_hba* pHba);
static s32 adpt_send_nop(adpt_hba*pHba,u32 m);
static void adpt_i2o_delete_hba(adpt_hba* pHba);
-static void adpt_select_queue_depths(struct Scsi_Host *host, Scsi_Device * devicelist);
static void adpt_inquiry(adpt_hba* pHba);
static void adpt_fail_posted_scbs(adpt_hba* pHba);
static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 9690e38bed42..41835b5571a2 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -750,63 +750,34 @@ static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS;
static int max_queue_depth = MAX_CMD_PER_LUN;
#endif
-static void select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist) {
- Scsi_Device *dev;
- int j, ntag = 0, nuntag = 0, tqd, utqd;
+static int eata2x_slave_attach(Scsi_Device *dev) {
+ int j, tqd, utqd;
+ char *link_suffix = "";
+ struct Scsi_Host *host = dev->host;
j = ((struct hostdata *) host->hostdata)->board_number;
- for(dev = devlist; dev; dev = dev->next) {
-
- if (dev->host != host) continue;
-
- if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm))
- ntag++;
- else
- nuntag++;
- }
-
utqd = MAX_CMD_PER_LUN;
+ tqd = (host->can_queue - utqd);
- tqd = (host->can_queue - utqd * nuntag) / (ntag ? ntag : 1);
-
- if (tqd > max_queue_depth) tqd = max_queue_depth;
-
- if (tqd < MAX_CMD_PER_LUN) tqd = MAX_CMD_PER_LUN;
-
- for(dev = devlist; dev; dev = dev->next) {
- char *tag_suffix = "", *link_suffix = "";
-
- if (dev->host != host) continue;
-
- if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm))
- dev->queue_depth = tqd;
+ if (TLDEV(dev->type) && (dev->tagged_supported || linked_comm)) {
+ if(!dev->tagged_supported)
+ scsi_adjust_queue_depth(dev, 0, tqd);
else
- dev->queue_depth = utqd;
-
- if (TLDEV(dev->type)) {
- if (linked_comm && dev->queue_depth > 2)
- link_suffix = ", sorted";
- else
- link_suffix = ", unsorted";
- }
-
- if (tagged_comm && dev->tagged_supported && TLDEV(dev->type)) {
- dev->tagged_queue = 1;
- dev->current_tag = 1;
- }
-
- if (dev->tagged_supported && TLDEV(dev->type) && dev->tagged_queue)
- tag_suffix = ", soft-tagged";
- else if (dev->tagged_supported && TLDEV(dev->type))
- tag_suffix = ", tagged";
+ scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
+ } else {
+ scsi_adjust_queue_depth(dev, 0, utqd);
+ }
- printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
- BN(j), host->host_no, dev->channel, dev->id, dev->lun,
- dev->queue_depth, link_suffix, tag_suffix);
- }
+ if (!dev->simple_tags && dev->new_queue_depth > 2)
+ link_suffix = ", sorted";
+ else if (dev->simple_tags)
+ link_suffix = ", unsorted";
- return;
+ printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s.\n",
+ BN(j), host->host_no, dev->channel, dev->id, dev->lun,
+ dev->new_queue_depth, link_suffix);
+ return 0;
}
static inline int wait_on_busy(unsigned long iobase, unsigned int loop) {
@@ -1071,7 +1042,6 @@ static inline int port_detect \
sh[j]->this_id = (ushort) info.host_addr[3];
sh[j]->can_queue = (ushort) be16_to_cpu(info.queue_size);
sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
- sh[j]->select_queue_depths = select_queue_depths;
memset(HD(j), 0, sizeof(struct hostdata));
HD(j)->subversion = subversion;
HD(j)->protocol_rev = protocol_rev;
@@ -1542,7 +1512,7 @@ static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
/* Map DMA buffers and SG list */
map_dma(i, j);
- if (SCpnt->device->tagged_queue) {
+ if (SCpnt->device->simple_tags) {
if (HD(j)->target_redo[SCpnt->target][SCpnt->channel] ||
HD(j)->target_to[SCpnt->target][SCpnt->channel])
@@ -1560,8 +1530,7 @@ static inline int do_qcomm(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
cpp->mess[1] = SCpnt->device->current_tag++;
}
- if (linked_comm && SCpnt->device->queue_depth > 2
- && TLDEV(SCpnt->device->type)) {
+ if (SCpnt->device->new_queue_depth > 2 && !SCpnt->device->simple_tags) {
HD(j)->cp_stat[i] = READY;
flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
return 0;
@@ -2071,7 +2040,7 @@ static inline void ihdlr(int irq, unsigned int j) {
sync_dma(i, j);
- if (linked_comm && SCpnt->device->queue_depth > 2
+ if (linked_comm && SCpnt->device->new_queue_depth > 2
&& TLDEV(SCpnt->device->type))
flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index 56f00bf01c7b..471e51ebfb55 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -12,6 +12,7 @@ int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int eata2x_abort(Scsi_Cmnd *);
int eata2x_reset(Scsi_Cmnd *);
int eata2x_biosparam(Disk *, struct block_device *, int *);
+static int eata2x_slave_attach(Scsi_Device *);
#define EATA_VERSION "7.22.00"
@@ -27,6 +28,7 @@ int eata2x_biosparam(Disk *, struct block_device *, int *);
eh_bus_reset_handler: NULL, \
eh_host_reset_handler: eata2x_reset, \
bios_param: eata2x_biosparam, \
+ slave_attach: eata2x_slave_attach, \
this_id: 7, \
unchecked_isa_dma: 1, \
use_clustering: ENABLE_CLUSTERING, \
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
index 47d20082c1af..77192c05310f 100644
--- a/drivers/scsi/fcal.c
+++ b/drivers/scsi/fcal.c
@@ -70,17 +70,21 @@ static unsigned char target2alpa[] = {
static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
-static void fcal_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
+int fcal_slave_attach(Scsi_Device *device)
{
- Scsi_Device *device;
+ int depth_to_use;
- for (device = devlist; device; device = device->next) {
- if (device->host != host) continue;
- if (device->tagged_supported)
- device->queue_depth = /* 254 */ 8;
- else
- device->queue_depth = 2;
- }
+ if (device->tagged_supported)
+ depth_to_use = /* 254 */ 8;
+ else
+ depth_to_use = 2;
+
+ scsi_adjust_queue_depth(device,
+ (device->tagged_supported ?
+ MSG_SIMPLE_TAG : 0),
+ depth_to_use);
+
+ return 0;
}
/* Detect all FC Arbitrated Loops attached to the machine.
@@ -165,7 +169,6 @@ int __init fcal_detect(Scsi_Host_Template *tpnt)
#ifdef __sparc_v9__
host->unchecked_isa_dma = 1;
#endif
- host->select_queue_depths = fcal_select_queue_depths;
fc->channels = 1;
fc->targets = 127;
diff --git a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
index 8246571b9cb8..194e3d0e0637 100644
--- a/drivers/scsi/fcal.h
+++ b/drivers/scsi/fcal.h
@@ -23,6 +23,7 @@ struct fcal {
int fcal_detect(Scsi_Host_Template *);
int fcal_release(struct Scsi_Host *);
int fcal_proc_info (char *, char **, off_t, int, int, int);
+int fcal_slave_attach(Scsi_Device *);
#define FCAL { \
name: "Fibre Channel Arbitrated Loop",\
@@ -30,6 +31,7 @@ int fcal_proc_info (char *, char **, off_t, int, int, int);
release: fcal_release, \
proc_info: fcal_proc_info, \
queuecommand: fcp_scsi_queuecommand, \
+ slave_attach: fcal_slave_attach, \
can_queue: FCAL_CAN_QUEUE, \
this_id: -1, \
sg_tablesize: 1, \
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 1e295555b26f..520f31dfbf82 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -229,7 +229,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j)
if (!blk_nohighio)
retval->highmem_io = tpnt->highmem_io;
- retval->select_queue_depths = tpnt->select_queue_depths;
retval->max_sectors = tpnt->max_sectors;
retval->use_blk_tcq = tpnt->use_blk_tcq;
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index 44eb4ac53880..a899c89ded0b 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -266,14 +266,6 @@ typedef struct SHT
*/
int (* bios_param)(Disk *, struct block_device *, int []);
-
- /*
- * Used to set the queue depth for a specific device.
- *
- * Once the slave_attach() function is in full use, this will go away.
- */
- void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
-
/*
* This determines if we will use a non-interrupt driven
* or an interrupt driven scheme, It is set to the maximum number
@@ -384,6 +376,8 @@ struct Scsi_Host
*/
struct Scsi_Host * next;
Scsi_Device * host_queue;
+ struct list_head all_scsi_hosts;
+ struct list_head my_devices;
spinlock_t default_lock;
spinlock_t *host_lock;
@@ -489,8 +483,6 @@ struct Scsi_Host
*/
unsigned int max_host_blocked;
- void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
-
/*
* For SCSI hosts which are PCI devices, set pci_dev so that
* we can do BIOS EDD 3.0 mappings
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index 6963127669ce..fa060c14118c 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1879,10 +1879,12 @@ ips_slave_attach(Scsi_Device *SDptr)
int min;
ha = IPS_HA(SDptr->host);
- min = ha->max_cmds / 4;
- if (min < 8)
- min = ha->max_cmds - 1;
- scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+ if (SDptr->tagged_supported) {
+ min = ha->max_cmds / 2;
+ if (min <= 16)
+ min = ha->max_cmds - 1;
+ scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+ }
return 0;
}
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
index e13b6bc9d4cc..13d2ecb5a6ba 100644
--- a/drivers/scsi/ips.h
+++ b/drivers/scsi/ips.h
@@ -429,7 +429,7 @@
can_queue : 0, \
this_id: -1, \
sg_tablesize : IPS_MAX_SG, \
- cmd_per_lun: 16, \
+ cmd_per_lun: 3, \
present : 0, \
unchecked_isa_dma : 0, \
use_clustering : ENABLE_CLUSTERING, \
@@ -458,7 +458,7 @@
can_queue : 0, \
this_id: -1, \
sg_tablesize : IPS_MAX_SG, \
- cmd_per_lun: 16, \
+ cmd_per_lun: 3, \
present : 0, \
unchecked_isa_dma : 0, \
use_clustering : ENABLE_CLUSTERING, \
@@ -488,7 +488,7 @@
can_queue : 0, \
this_id: -1, \
sg_tablesize : IPS_MAX_SG, \
- cmd_per_lun: 16, \
+ cmd_per_lun: 3, \
present : 0, \
unchecked_isa_dma : 0, \
use_clustering : ENABLE_CLUSTERING, \
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index c056da9c0ed9..26ce03f229c2 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -378,8 +378,6 @@ static Scsi_Host_Template *the_template = NULL;
#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
-static void ncr53c8xx_select_queue_depths(
- struct Scsi_Host *host, struct scsi_device *devlist);
static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
static void ncr53c8xx_timeout(unsigned long np);
@@ -3710,7 +3708,6 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
instance->dma_channel = 0;
instance->cmd_per_lun = MAX_TAGS;
instance->can_queue = (MAX_START-4);
- instance->select_queue_depths = ncr53c8xx_select_queue_depths;
scsi_set_pci_device(instance, device->pdev);
#ifdef SCSI_NCR_INTEGRITY_CHECKING
@@ -8500,56 +8497,57 @@ static void __init ncr_getclock (ncb_p np, int mult)
** Linux select queue depths function
*/
-static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
+int ncr53c8xx_slave_attach(Scsi_Device *device)
{
- struct scsi_device *device;
+ struct Scsi_Host *host = device->host;
+ ncb_p np;
+ tcb_p tp;
+ lcb_p lp;
+ int numtags, depth_to_use;
- for (device = devlist; device; device = device->next) {
- ncb_p np;
- tcb_p tp;
- lcb_p lp;
- int numtags;
+ np = ((struct host_data *) host->hostdata)->ncb;
+ tp = &np->target[device->id];
+ lp = tp->lp[device->lun];
- if (device->host != host)
- continue;
+ /*
+ ** Select queue depth from driver setup.
+ ** Donnot use more than configured by user.
+ ** Use at least 2.
+ ** Donnot use more than our maximum.
+ */
+ numtags = device_queue_depth(np->unit, device->id, device->lun);
+ if (numtags > tp->usrtags)
+ numtags = tp->usrtags;
+ if (!device->tagged_supported)
+ numtags = 1;
+ depth_to_use = numtags;
+ if (depth_to_use < 2)
+ depth_to_use = 2;
+ if (depth_to_use > MAX_TAGS)
+ depth_to_use = MAX_TAGS;
- np = ((struct host_data *) host->hostdata)->ncb;
- tp = &np->target[device->id];
- lp = tp->lp[device->lun];
+ scsi_adjust_queue_depth(device,
+ (device->tagged_supported ?
+ MSG_SIMPLE_TAG : 0),
+ depth_to_use);
- /*
- ** Select queue depth from driver setup.
- ** Donnot use more than configured by user.
- ** Use at least 2.
- ** Donnot use more than our maximum.
- */
- numtags = device_queue_depth(np->unit, device->id, device->lun);
- if (numtags > tp->usrtags)
- numtags = tp->usrtags;
- if (!device->tagged_supported)
- numtags = 1;
- device->queue_depth = numtags;
- if (device->queue_depth < 2)
- device->queue_depth = 2;
- if (device->queue_depth > MAX_TAGS)
- device->queue_depth = MAX_TAGS;
-
- /*
- ** Since the queue depth is not tunable under Linux,
- ** we need to know this value in order not to
- ** announce stupid things to user.
- */
- if (lp) {
- lp->numtags = lp->maxtags = numtags;
- lp->scdev_depth = device->queue_depth;
- }
- ncr_setup_tags (np, device->id, device->lun);
+ /*
+ ** Since the queue depth is not tunable under Linux,
+ ** we need to know this value in order not to
+ ** announce stupid things to user.
+ */
+ if (lp) {
+ lp->numtags = lp->maxtags = numtags;
+ lp->scdev_depth = depth_to_use;
+ }
+ ncr_setup_tags (np, device->id, device->lun);
#ifdef DEBUG_NCR53C8XX
-printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
- np->unit, device->id, device->lun, device->queue_depth);
+ printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+ np->unit, device->id, device->lun, depth_to_use);
#endif
- }
+
+ return 0;
}
/*
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index ac4e795a1403..ed4e569aa613 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -59,6 +59,7 @@ int ncr53c8xx_detect(Scsi_Host_Template *tpnt);
const char *ncr53c8xx_info(struct Scsi_Host *host);
int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
+int ncr53c8xx_slave_attach(Scsi_Device *);
#ifdef MODULE
int ncr53c8xx_release(struct Scsi_Host *);
@@ -74,6 +75,7 @@ int ncr53c8xx_release(struct Scsi_Host *);
release: ncr53c8xx_release, \
info: ncr53c8xx_info, \
queuecommand: ncr53c8xx_queue_command,\
+ slave_attach: ncr53c8xx_slave_attach, \
abort: ncr53c8xx_abort, \
reset: ncr53c8xx_reset, \
bios_param: scsicam_bios_param, \
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
index c812e3b291d6..52d03fa98168 100644
--- a/drivers/scsi/pluto.c
+++ b/drivers/scsi/pluto.c
@@ -71,17 +71,21 @@ static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
up(&fc_sem);
}
-static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
+int pluto_slave_attach(Scsi_Device *device)
{
- Scsi_Device *device;
-
- for (device = devlist; device; device = device->next) {
- if (device->host != host) continue;
- if (device->tagged_supported)
- device->queue_depth = /* 254 */ 8;
- else
- device->queue_depth = 2;
- }
+ int depth_to_use;
+
+ if (device->tagged_supported)
+ depth_to_use = /* 254 */ 8;
+ else
+ depth_to_use = 2;
+
+ scsi_adjust_queue_depth(device,
+ (device->tagged_supported ?
+ MSG_SIMPLE_TAG : 0),
+ depth_to_use);
+
+ return 0;
}
/* Detect all SSAs attached to the machine.
@@ -241,7 +245,6 @@ int __init pluto_detect(Scsi_Host_Template *tpnt)
host->unchecked_isa_dma = 1;
#endif
- host->select_queue_depths = pluto_select_queue_depths;
fc->channels = inq->channels + 1;
fc->targets = inq->targets;
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
index 01d34564f1b8..558693d10b90 100644
--- a/drivers/scsi/pluto.h
+++ b/drivers/scsi/pluto.h
@@ -41,6 +41,7 @@ struct pluto_inquiry {
int pluto_detect(Scsi_Host_Template *);
int pluto_release(struct Scsi_Host *);
const char * pluto_info(struct Scsi_Host *);
+int pluto_slave_attach(Scsi_Device *);
#define PLUTO { \
name: "Sparc Storage Array 100/200", \
@@ -48,6 +49,7 @@ const char * pluto_info(struct Scsi_Host *);
release: pluto_release, \
info: pluto_info, \
queuecommand: fcp_scsi_queuecommand, \
+ slave_attach: pluto_slave_attach, \
can_queue: PLUTO_CAN_QUEUE, \
this_id: -1, \
sg_tablesize: 1, \
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 68731d7505ec..9417679c4ef1 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -382,8 +382,7 @@ static void qla1280_done(struct scsi_qla_host *, srb_t **, srb_t **);
static void qla1280_next(struct scsi_qla_host *, scsi_lu_t *, int);
static void qla1280_putq_t(scsi_lu_t *, srb_t *);
static void qla1280_done_q_put(srb_t *, srb_t **, srb_t **);
-static void qla1280_device_queue_depth(struct scsi_qla_host *, Scsi_Device *);
-static void qla1280_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+static int qla1280_slave_attach(Scsi_Device *);
#if STOP_ON_ERROR
static void qla1280_panic(char *, struct Scsi_Host *host);
#endif
@@ -840,7 +839,6 @@ qla1280_do_device_init(struct pci_dev *pdev,
host->can_queue = 0xfffff; /* unlimited */
host->cmd_per_lun = 1;
- host->select_queue_depths = qla1280_select_queue_depth;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18)
host->base = (unsigned char *)ha->mmpbase;
#else
@@ -1796,7 +1794,7 @@ qla1280_do_dpc(void *p)
}
/**************************************************************************
- * qla1280_device_queue_depth
+ * qla1280_slave_attach
*
* Description:
* Determines the queue depth for a given device. There are two ways
@@ -1806,51 +1804,28 @@ qla1280_do_dpc(void *p)
* as the default queue depth. Otherwise, we use either 4 or 8 as the
* default queue depth (dependent on the number of hardware SCBs).
**************************************************************************/
-static void
-qla1280_device_queue_depth(struct scsi_qla_host *p, Scsi_Device * device)
+static int
+qla1280_slave_attach(Scsi_Device * device)
{
- int default_depth = 3;
+ struct scsi_qla_host *p = (struct scsi_qla_host *)device->host->hostdata;
int bus = device->channel;
int target = device->id;
- device->queue_depth = default_depth;
-
+ if (qla1280_check_for_dead_scsi_bus(p, bus))
+ return 1;
if (device->tagged_supported &&
(p->bus_settings[bus].qtag_enables & (BIT_0 << target))) {
- device->tagged_queue = 1;
- device->current_tag = 0;
- device->queue_depth = p->bus_settings[bus].hiwat;
+ scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+ p->bus_settings[bus].hiwat);
/* device->queue_depth = 20; */
printk(KERN_INFO "scsi(%li:%d:%d:%d): Enabled tagged queuing, "
"queue depth %d.\n", p->host_no, device->channel,
- device->id, device->lun, device->queue_depth);
+ device->id, device->lun, device->new_queue_depth);
+ } else {
+ scsi_adjust_queue_depth(device, 0 /* TCQ off */, 3);
}
qla12160_get_target_parameters(p, bus, target, device->lun);
-}
-
-/**************************************************************************
- * qla1280_select_queue_depth
- *
- * Sets the queue depth for each SCSI device hanging off the input
- * host adapter. We use a queue depth of 2 for devices that do not
- * support tagged queueing.
- **************************************************************************/
-static void
-qla1280_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
-{
- Scsi_Device *device;
- struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
-
- ENTER("qla1280_select_queue_depth");
- for (device = scsi_devs; device != NULL; device = device->next) {
- if (device->host == host)
- qla1280_device_queue_depth (ha, device);
- }
-
- if (scsi_devs)
- qla1280_check_for_dead_scsi_bus(ha, scsi_devs->channel);
-
- LEAVE("qla1280_select_queue_depth");
+ return 0;
}
/*
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
index 1139d7d023a7..5dbaf0a89cb8 100644
--- a/drivers/scsi/qla1280.h
+++ b/drivers/scsi/qla1280.h
@@ -1314,6 +1314,7 @@ int qla1280_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
int qla1280_abort(Scsi_Cmnd *);
int qla1280_reset(Scsi_Cmnd *, unsigned int);
int qla1280_biosparam(Disk *, struct block_device *, int[]);
+static int qla1280_slave_attach(Scsi_Device *);
void qla1280_intr_handler(int, void *, struct pt_regs *);
void qla1280_setup(char *s, int *dummy);
@@ -1342,7 +1343,7 @@ void qla1280_setup(char *s, int *dummy);
/* use_new_eh_code: 0, */ \
abort: qla1280_abort, \
reset: qla1280_reset, \
- slave_attach: NULL, \
+ slave_attach: qla1280_slave_attach, \
bios_param: qla1280_biosparam, \
can_queue: 255, /* max simultaneous cmds */\
this_id: -1, /* scsi id of host adapter */\
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 1ba787fcad2e..d05400f6d047 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -568,7 +568,7 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
atomic_read(&SCpnt->host->host_active),
SCpnt->host->host_failed));
- if(SDpnt->queue_depth > SDpnt->new_queue_depth) {
+ if(SDpnt->current_queue_depth > SDpnt->new_queue_depth) {
Scsi_Cmnd *prev, *next;
/*
* Release the command block and decrement the queue
@@ -582,10 +582,10 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
else
prev->next = next->next;
kfree((char *)SCpnt);
- SDpnt->queue_depth--;
- } else if(SDpnt->queue_depth < SDpnt->new_queue_depth) {
+ SDpnt->current_queue_depth--;
+ } else if(SDpnt->current_queue_depth < SDpnt->new_queue_depth) {
alloc_cmd = 1;
- SDpnt->queue_depth++;
+ SDpnt->current_queue_depth++;
}
spin_unlock_irqrestore(&device_request_lock, flags);
@@ -633,7 +633,7 @@ inline void __scsi_release_command(Scsi_Cmnd * SCpnt)
spin_unlock_irqrestore(&device_request_lock, flags);
} else {
spin_lock_irqsave(&device_request_lock, flags);
- SDpnt->queue_depth--;
+ SDpnt->current_queue_depth--;
spin_unlock_irqrestore(&device_request_lock, flags);
}
}
@@ -1505,7 +1505,7 @@ void scsi_release_commandblocks(Scsi_Device * SDpnt)
SDpnt->device_queue = SCnext = SCpnt->next;
kfree((char *) SCpnt);
}
- SDpnt->queue_depth = 0;
+ SDpnt->current_queue_depth = 0;
SDpnt->new_queue_depth = 0;
spin_unlock_irqrestore(&device_request_lock, flags);
}
@@ -1529,7 +1529,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
unsigned long flags;
Scsi_Cmnd *SCpnt;
- if (SDpnt->queue_depth != 0)
+ if (SDpnt->current_queue_depth != 0)
return;
SCpnt = (Scsi_Cmnd *) kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC |
@@ -1567,7 +1567,7 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
spin_lock_irqsave(&device_request_lock, flags);
if(SDpnt->new_queue_depth == 0)
SDpnt->new_queue_depth = 1;
- SDpnt->queue_depth++;
+ SDpnt->current_queue_depth++;
SCpnt->next = SDpnt->device_queue;
SDpnt->device_queue = SCpnt;
spin_unlock_irqrestore(&device_request_lock, flags);
@@ -1597,12 +1597,13 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
*
* If cmdblocks != 0 then we are a live device. We just set the
* new_queue_depth variable and when the scsi completion handler
- * notices that queue_depth != new_queue_depth it will work to
- * rectify the situation. If new_queue_depth is less than current
- * queue_depth, then it will free the completed command instead of
- * putting it back on the free list and dec queue_depth. Otherwise
- * it will try to allocate a new command block for the device and
- * put it on the free list along with the command that is being
+ * notices that current_queue_depth != new_queue_depth it will
+ * work to rectify the situation. If new_queue_depth is less than
+ * current_queue_depth, then it will free the completed command
+ * instead of putting it back on the free list and dec
+ * current_queue_depth. Otherwise it will try to allocate a new
+ * command block for the device and put it on the free list along
+ * with the command that is being
* completed. Obviously, if the device isn't doing anything then
* neither is this code, so it will bring the devices queue depth
* back into line when the device is actually being used. This
@@ -1648,14 +1649,11 @@ void scsi_adjust_queue_depth(Scsi_Device *SDpnt, int tagged, int tags)
SDpnt->channel, SDpnt->id, SDpnt->lun);
case 0:
SDpnt->ordered_tags = SDpnt->simple_tags = 0;
- if(SDpnt->host->cmd_per_lun)
- SDpnt->new_queue_depth = SDpnt->host->cmd_per_lun;
- else
- SDpnt->new_queue_depth = 1;
+ SDpnt->new_queue_depth = tags;
break;
}
spin_unlock_irqrestore(&device_request_lock, flags);
- if(SDpnt->queue_depth == 0)
+ if(SDpnt->current_queue_depth == 0)
{
scsi_build_commandblocks(SDpnt);
}
@@ -2116,7 +2114,7 @@ int scsi_register_host(Scsi_Host_Template * tpnt)
(*sdtpnt->attach) (SDpnt);
if (SDpnt->attached) {
scsi_build_commandblocks(SDpnt);
- if (SDpnt->queue_depth == 0)
+ if (SDpnt->current_queue_depth == 0)
out_of_space = 1;
}
}
@@ -2405,10 +2403,10 @@ int scsi_register_device(struct Scsi_Device_Template *tpnt)
* If this driver attached to the device, and don't have any
* command blocks for this device, allocate some.
*/
- if (SDpnt->attached && SDpnt->queue_depth == 0) {
+ if (SDpnt->attached && SDpnt->current_queue_depth == 0) {
SDpnt->online = TRUE;
scsi_build_commandblocks(SDpnt);
- if (SDpnt->queue_depth == 0)
+ if (SDpnt->current_queue_depth == 0)
out_of_space = 1;
}
}
@@ -2816,7 +2814,7 @@ Scsi_Device * scsi_get_host_dev(struct Scsi_Host * SHpnt)
SDpnt->new_queue_depth = 1;
scsi_build_commandblocks(SDpnt);
- if(SDpnt->queue_depth == 0) {
+ if(SDpnt->current_queue_depth == 0) {
kfree(SDpnt);
return NULL;
}
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index cd936544cef6..f616c4b8cdf7 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -557,15 +557,19 @@ struct scsi_device {
*/
struct scsi_device *next; /* Used for linked list */
struct scsi_device *prev; /* Used for linked list */
+ struct list_head siblings; /* list of all devices on this host */
+ struct list_head same_target_siblings; /* just the devices sharing same target id */
wait_queue_head_t scpnt_wait; /* Used to wait if
device is busy */
struct Scsi_Host *host;
request_queue_t request_queue;
atomic_t device_active; /* commands checked out for device */
volatile unsigned short device_busy; /* commands actually active on low-level */
+ struct list_head free_cmnds; /* list of available Scsi_Cmnd structs */
+ struct list_head busy_cmnds; /* list of Scsi_Cmnd structs in use */
Scsi_Cmnd *device_queue; /* queue of SCSI Command structures */
Scsi_Cmnd *current_cmnd; /* currently active command */
- unsigned short queue_depth; /* How deep of a queue we have */
+ unsigned short current_queue_depth;/* How deep of a queue we have */
unsigned short new_queue_depth; /* How deep of a queue we want */
unsigned int id, lun, channel;
@@ -713,6 +717,7 @@ struct scsi_cmnd {
Scsi_Request *sc_request;
struct scsi_cmnd *next;
struct scsi_cmnd *reset_chain;
+ struct list_head list_entry; /* Used to place us on the cmd lists */
int eh_state; /* Used for state tracking in error handlr */
int eh_eflags; /* Used by error handlr */
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 0f52ed55b210..6d174708da82 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -1532,7 +1532,7 @@ static int scsi_probe_and_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
*/
sdevscan->new_queue_depth = 1;
scsi_build_commandblocks(sdevscan);
- if (sdevscan->queue_depth == 0)
+ if (sdevscan->current_queue_depth == 0)
goto alloc_failed;
sreq = scsi_allocate_request(sdevscan);
@@ -1606,7 +1606,7 @@ alloc_failed:
kfree(scsi_result);
if (sreq != NULL)
scsi_release_request(sreq);
- if (sdevscan->queue_depth != 0)
+ if (sdevscan->current_queue_depth != 0)
scsi_release_commandblocks(sdevscan);
return SCSI_SCAN_NO_RESPONSE;
}
@@ -1762,7 +1762,7 @@ static int scsi_report_lun_scan(Scsi_Device *sdevscan)
sdevscan->new_queue_depth = 1;
scsi_build_commandblocks(sdevscan);
- if (sdevscan->queue_depth == 0) {
+ if (sdevscan->current_queue_depth == 0) {
printk(ALLOC_FAILURE_MSG, __FUNCTION__);
/*
* We are out of memory, don't try scanning any further.
@@ -2030,7 +2030,7 @@ static void scsi_scan_selected_lun(struct Scsi_Host *shost, uint channel,
(*sdt->attach) (sdev);
if (sdev->attached) {
scsi_build_commandblocks(sdev);
- if (sdev->queue_depth == 0)
+ if (sdev->current_queue_depth == 0)
printk(ALLOC_FAILURE_MSG,
__FUNCTION__);
}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 5863cdcf9bba..1b7abd00b167 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -1386,7 +1386,7 @@ static int sd_attach(Scsi_Device * sdp)
((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)))
return 0;
- gd = alloc_disk();
+ gd = alloc_disk(16);
if (!gd)
return 1;
@@ -1423,7 +1423,6 @@ static int sd_attach(Scsi_Device * sdp)
gd->de = sdp->de;
gd->major = SD_MAJOR(dsk_nr>>4);
gd->first_minor = (dsk_nr & 15)<<4;
- gd->minor_shift = 4;
gd->fops = &sd_fops;
if (dsk_nr > 26)
sprintf(gd->disk_name, "sd%c%c",'a'+dsk_nr/26-1,'a'+dsk_nr%26);
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 056861b80c12..a18bf6db8fcf 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -852,7 +852,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
__put_user((int) sdp->device->type, &sg_idp->scsi_type);
__put_user((short) sdp->device->host->cmd_per_lun,
&sg_idp->h_cmd_per_lun);
- __put_user((short) sdp->device->queue_depth,
+ __put_user((short) sdp->device->new_queue_depth,
&sg_idp->d_queue_depth);
__put_user(0, &sg_idp->unused[0]);
__put_user(0, &sg_idp->unused[1]);
@@ -3039,7 +3039,7 @@ sg_proc_dev_info(char *buffer, int *len, off_t * begin, off_t offset, int size)
scsidp->host->host_no, scsidp->channel,
scsidp->id, scsidp->lun, (int) scsidp->type,
(int) scsidp->access_count,
- (int) scsidp->queue_depth,
+ (int) scsidp->new_queue_depth,
(int) scsidp->device_busy,
(int) scsidp->online);
else
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index ab50575b899c..39af5cce16f0 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -726,24 +726,6 @@ cleanup_dev:
return 1;
}
-/* Driverfs file support */
-static ssize_t sr_device_kdev_read(struct device *driverfs_dev,
- char *page, size_t count, loff_t off)
-{
- kdev_t kdev;
- kdev.value=(int)(long)driverfs_dev->driver_data;
- return off ? 0 : sprintf(page, "%x\n",kdev.value);
-}
-static DEVICE_ATTR(kdev,S_IRUGO,sr_device_kdev_read,NULL);
-
-static ssize_t sr_device_type_read(struct device *driverfs_dev,
- char *page, size_t count, loff_t off)
-{
- return off ? 0 : sprintf (page, "CHR\n");
-}
-static DEVICE_ATTR(type,S_IRUGO,sr_device_type_read,NULL);
-
-
void sr_finish()
{
int i;
@@ -757,7 +739,7 @@ void sr_finish()
* with loadable modules. */
if (cd->disk)
continue;
- disk = alloc_disk();
+ disk = alloc_disk(1);
if (!disk)
continue;
if (cd->disk) {
@@ -766,7 +748,6 @@ void sr_finish()
}
disk->major = MAJOR_NR;
disk->first_minor = i;
- disk->minor_shift = 0;
strcpy(disk->disk_name, cd->cdi.name);
disk->fops = &sr_bdops;
disk->flags = GENHD_FL_CD;
@@ -798,22 +779,8 @@ void sr_finish()
*/
get_capabilities(cd);
sr_vendor_init(cd);
-
- sprintf(cd->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
- cd->device->sdev_driverfs_dev.bus_id);
- sprintf(cd->cdi.cdrom_driverfs_dev.name, "%scdrom",
- cd->device->sdev_driverfs_dev.name);
- cd->cdi.cdrom_driverfs_dev.parent =
- &cd->device->sdev_driverfs_dev;
- cd->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
- cd->cdi.cdrom_driverfs_dev.driver_data =
- (void *)(long)__mkdev(MAJOR_NR, i);
- device_register(&cd->cdi.cdrom_driverfs_dev);
- device_create_file(&cd->cdi.cdrom_driverfs_dev,
- &dev_attr_type);
- device_create_file(&cd->cdi.cdrom_driverfs_dev,
- &dev_attr_kdev);
disk->de = cd->device->de;
+ disk->driverfs_dev = &cd->device->sdev_driverfs_dev;
register_cdrom(&cd->cdi);
set_capacity(disk, cd->capacity);
add_disk(disk);
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 8f22ecfc2dae..194077d101ba 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -12,13 +12,13 @@
Copyright 1992 - 2002 Kai Makisara
email Kai.Makisara@metla.fi
- Last modified: Sun Sep 29 22:29:16 2002 by makisara
+ Last modified: Tue Oct 15 22:01:04 2002 by makisara
Some small formal changes - aeb, 950809
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/
-static char *verstr = "20020929";
+static char *verstr = "20021015";
#include <linux/module.h>
@@ -291,6 +291,8 @@ static int st_chk_result(Scsi_Tape *STp, Scsi_Request * SRpnt)
if (sense[12] == 0 && sense[13] == 0x17) /* ASC and ASCQ => cleaning requested */
STp->cleaning_req = 1;
+ STp->pos_unknown |= STp->device->was_reset;
+
if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR
#if ST_RECOVERED_WRITE_FATAL
@@ -566,7 +568,7 @@ static int flush_buffer(Scsi_Tape *STp, int seek_next)
* If there was a bus reset, block further access
* to this device.
*/
- if (STp->device->was_reset)
+ if (STp->pos_unknown)
return (-EIO);
if (STp->ready != ST_READY)
@@ -640,6 +642,52 @@ static int set_mode_densblk(Scsi_Tape * STp, ST_mode * STm)
}
return 0;
}
+
+
+/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
+static int do_door_lock(Scsi_Tape * STp, int do_lock)
+{
+ int retval, cmd;
+ DEB(int dev = TAPE_NR(STp->devt);)
+
+
+ cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
+ DEBC(printk(ST_DEB_MSG "st%d: %socking drive door.\n", dev,
+ do_lock ? "L" : "Unl"));
+ retval = scsi_ioctl(STp->device, cmd, NULL);
+ if (!retval) {
+ STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
+ }
+ else {
+ STp->door_locked = ST_LOCK_FAILS;
+ }
+ return retval;
+}
+
+
+/* Set the internal state after reset */
+static void reset_state(Scsi_Tape *STp)
+{
+ int i;
+ ST_partstat *STps;
+
+ STp->pos_unknown = 0;
+ for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+ STps = &(STp->ps[i]);
+ STps->rw = ST_IDLE;
+ STps->eof = ST_NOEOF;
+ STps->at_sm = 0;
+ STps->last_block_valid = FALSE;
+ STps->drv_block = -1;
+ STps->drv_file = -1;
+ }
+ if (STp->can_partitions) {
+ STp->partition = find_partition(STp);
+ if (STp->partition < 0)
+ STp->partition = 0;
+ STp->new_partition = STp->partition;
+ }
+}
/* Test if the drive is ready. Returns either one of the codes below or a negative system
error code. */
@@ -757,7 +805,7 @@ static int check_tape(Scsi_Tape *STp, struct file *filp)
goto err_out;
if (retval == CHKRES_NEW_SESSION) {
- (STp->device)->was_reset = 0;
+ STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0;
if (STp->can_partitions)
STp->nbr_partitions = 1; /* This guess will be updated later
@@ -1021,7 +1069,7 @@ static int st_flush(struct file *filp)
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
- if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+ if (STps->rw == ST_WRITING && !STp->pos_unknown) {
result = flush_write_buffer(STp);
if (result != 0 && result != (-ENOSPC))
goto out;
@@ -1040,7 +1088,7 @@ static int st_flush(struct file *filp)
printk(KERN_WARNING "st%d: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
dev, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
- if (STps->rw == ST_WRITING && !(STp->device)->was_reset) {
+ if (STps->rw == ST_WRITING && !STp->pos_unknown) {
DEBC(printk(ST_DEB_MSG "st%d: File length %ld bytes.\n",
dev, (long) (filp->f_pos));
@@ -1136,7 +1184,7 @@ static int st_release(struct inode *inode, struct file *filp)
read_unlock(&st_dev_arr_lock);
if (STp->door_locked == ST_LOCKED_AUTO)
- st_int_ioctl(STp, MTUNLOCK, 0);
+ do_door_lock(STp, 0);
normalize_buffer(STp->buffer);
write_lock(&st_dev_arr_lock);
@@ -1189,7 +1237,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t
* If there was a bus reset, block further access
* to this device.
*/
- if (STp->device->was_reset) {
+ if (STp->pos_unknown) {
retval = (-EIO);
goto out;
}
@@ -1216,7 +1264,7 @@ static ssize_t rw_checks(Scsi_Tape *STp, struct file *filp, size_t count, loff_t
}
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
- !st_int_ioctl(STp, MTLOCK, 0))
+ !do_door_lock(STp, 1))
STp->door_locked = ST_LOCKED_AUTO;
out:
@@ -2502,18 +2550,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
DEBC(printk(ST_DEB_MSG "st%d: Erasing tape.\n", dev));
fileno = blkno = at_sm = 0;
break;
- case MTLOCK:
- chg_eof = FALSE;
- cmd[0] = ALLOW_MEDIUM_REMOVAL;
- cmd[4] = SCSI_REMOVAL_PREVENT;
- DEBC(printk(ST_DEB_MSG "st%d: Locking drive door.\n", dev));
- break;
- case MTUNLOCK:
- chg_eof = FALSE;
- cmd[0] = ALLOW_MEDIUM_REMOVAL;
- cmd[4] = SCSI_REMOVAL_ALLOW;
- DEBC(printk(ST_DEB_MSG "st%d: Unlocking drive door.\n", dev));
- break;
case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */
@@ -2594,11 +2630,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
STps->drv_file = fileno;
STps->at_sm = at_sm;
- if (cmd_in == MTLOCK)
- STp->door_locked = ST_LOCKED_EXPLICIT;
- else if (cmd_in == MTUNLOCK)
- STp->door_locked = ST_UNLOCKED;
-
if (cmd_in == MTBSFM)
ioctl_result = st_int_ioctl(STp, MTFSF, 1);
else if (cmd_in == MTFSFM)
@@ -2713,9 +2744,6 @@ static int st_int_ioctl(Scsi_Tape *STp, unsigned int cmd_in, unsigned long arg)
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
STps->eof = ST_EOD;
- if (cmd_in == MTLOCK)
- STp->door_locked = ST_LOCK_FAILS;
-
scsi_release_request(SRpnt);
SRpnt = NULL;
}
@@ -3104,7 +3132,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
goto out;
}
- if (!(STp->device)->was_reset) {
+ if (!STp->pos_unknown) {
if (STps->eof == ST_FM_HIT) {
if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
@@ -3152,16 +3180,9 @@ static int st_ioctl(struct inode *inode, struct file *file,
retval = (-EIO);
goto out;
}
+ reset_state(STp);
+ /* remove this when the midlevel properly clears was_reset */
STp->device->was_reset = 0;
- if (STp->door_locked != ST_UNLOCKED &&
- STp->door_locked != ST_LOCK_FAILS) {
- if (st_int_ioctl(STp, MTLOCK, 0)) {
- printk(KERN_NOTICE
- "st%d: Could not relock door after bus reset.\n",
- dev);
- STp->door_locked = ST_UNLOCKED;
- }
- }
}
if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
@@ -3170,7 +3191,7 @@ static int st_ioctl(struct inode *inode, struct file *file,
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
- st_int_ioctl(STp, MTUNLOCK, 0); /* Ignore result! */
+ do_door_lock(STp, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0) {
@@ -3238,6 +3259,11 @@ static int st_ioctl(struct inode *inode, struct file *file,
goto out;
}
+ if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
+ retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
+ goto out;
+ }
+
if (STp->can_partitions && STp->ready == ST_READY &&
(i = switch_partition(STp)) < 0) {
retval = i;
@@ -3642,13 +3668,13 @@ static DEVICE_ATTR(type,S_IRUGO,st_device_type_read,NULL);
static struct file_operations st_fops =
{
- owner: THIS_MODULE,
- read: st_read,
- write: st_write,
- ioctl: st_ioctl,
- open: st_open,
- flush: st_flush,
- release: st_release,
+ .owner = THIS_MODULE,
+ .read = st_read,
+ .write = st_write,
+ .ioctl = st_ioctl,
+ .open = st_open,
+ .flush = st_flush,
+ .release = st_release,
};
static int st_attach(Scsi_Device * SDp)
@@ -3909,12 +3935,12 @@ static void st_detach(Scsi_Device * SDp)
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_kdev);
- put_device(&tpnt->driverfs_dev_r[mode]);
+ device_unregister(&tpnt->driverfs_dev_r[mode]);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
- put_device(&tpnt->driverfs_dev_n[mode]);
+ device_unregister(&tpnt->driverfs_dev_n[mode]);
}
if (tpnt->buffer) {
tpnt->buffer->orig_frp_segs = 0;
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
index 79f71bb9081e..922b9e07abf9 100644
--- a/drivers/scsi/st.h
+++ b/drivers/scsi/st.h
@@ -94,6 +94,7 @@ typedef struct {
unsigned char use_pf; /* Set Page Format bit in all mode selects? */
unsigned char try_dio; /* try direct i/o? */
unsigned char c_algo; /* compression algorithm */
+ unsigned char pos_unknown; /* after reset position unknown */
int tape_type;
int write_threshold;
int timeout; /* timeout for normal commands */
diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
index 5558ae08a692..4e02050bd885 100644
--- a/drivers/scsi/sym53c8xx.c
+++ b/drivers/scsi/sym53c8xx.c
@@ -1341,8 +1341,6 @@ MODULE_PARM(sym53c8xx, "s");
#define SetScsiAbortResult(cmd) SetScsiResult(cmd, DID_ABORT, 0xff)
#endif
-static void sym53c8xx_select_queue_depths(
- struct Scsi_Host *host, struct scsi_device *devlist);
static void sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
static void sym53c8xx_timeout(unsigned long np);
@@ -5923,8 +5921,6 @@ ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
#endif
#endif
- instance->select_queue_depths = sym53c8xx_select_queue_depths;
-
NCR_UNLOCK_NCB(np, flags);
/*
@@ -13545,56 +13541,57 @@ static int device_queue_depth(ncb_p np, int target, int lun)
return DEF_DEPTH;
}
-static void sym53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist)
+int sym53c8xx_slave_attach(Scsi_Device *device)
{
- struct scsi_device *device;
-
- for (device = devlist; device; device = device->next) {
- ncb_p np;
- tcb_p tp;
- lcb_p lp;
- int numtags;
+ struct Scsi_Host *host = device->host;
+ ncb_p np;
+ tcb_p tp;
+ lcb_p lp;
+ int numtags, depth_to_use;
- if (device->host != host)
- continue;
+ np = ((struct host_data *) host->hostdata)->ncb;
+ tp = &np->target[device->id];
+ lp = ncr_lp(np, tp, device->lun);
- np = ((struct host_data *) host->hostdata)->ncb;
- tp = &np->target[device->id];
- lp = ncr_lp(np, tp, device->lun);
+ /*
+ ** Select queue depth from driver setup.
+ ** Donnot use more than configured by user.
+ ** Use at least 2.
+ ** Donnot use more than our maximum.
+ */
+ numtags = device_queue_depth(np, device->id, device->lun);
+ if (numtags > tp->usrtags)
+ numtags = tp->usrtags;
+ if (!device->tagged_supported)
+ numtags = 1;
+ depth_to_use = numtags;
+ if (depth_to_use < 2)
+ depth_to_use = 2;
+ if (depth_to_use > MAX_TAGS)
+ depth_to_use = MAX_TAGS;
- /*
- ** Select queue depth from driver setup.
- ** Donnot use more than configured by user.
- ** Use at least 2.
- ** Donnot use more than our maximum.
- */
- numtags = device_queue_depth(np, device->id, device->lun);
- if (numtags > tp->usrtags)
- numtags = tp->usrtags;
- if (!device->tagged_supported)
- numtags = 1;
- device->queue_depth = numtags;
- if (device->queue_depth < 2)
- device->queue_depth = 2;
- if (device->queue_depth > MAX_TAGS)
- device->queue_depth = MAX_TAGS;
+ scsi_adjust_queue_depth(device,
+ (device->tagged_supported ?
+ MSG_SIMPLE_TAG : 0),
+ depth_to_use);
- /*
- ** Since the queue depth is not tunable under Linux,
- ** we need to know this value in order not to
- ** announce stupid things to user.
- */
- if (lp) {
- lp->numtags = lp->maxtags = numtags;
- lp->scdev_depth = device->queue_depth;
- }
- ncr_setup_tags (np, device->id, device->lun);
+ /*
+ ** Since the queue depth is not tunable under Linux,
+ ** we need to know this value in order not to
+ ** announce stupid things to user.
+ */
+ if (lp) {
+ lp->numtags = lp->maxtags = numtags;
+ lp->scdev_depth = depth_to_use;
+ }
+ ncr_setup_tags (np, device->id, device->lun);
#ifdef DEBUG_SYM53C8XX
-printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
- np->unit, device->id, device->lun, device->queue_depth);
+ printk("sym53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+ np->unit, device->id, device->lun, depth_to_use);
#endif
- }
+
+ return 0;
}
/*
diff --git a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h
index 256d34b6461b..cc689df0373d 100644
--- a/drivers/scsi/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx.h
@@ -74,6 +74,7 @@ int sym53c8xx_detect(Scsi_Host_Template *tpnt);
const char *sym53c8xx_info(struct Scsi_Host *host);
int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int sym53c8xx_reset(Scsi_Cmnd *, unsigned int);
+int sym53c8xx_slave_attach(Scsi_Device *);
#ifdef MODULE
int sym53c8xx_release(struct Scsi_Host *);
@@ -89,6 +90,7 @@ int sym53c8xx_release(struct Scsi_Host *);
release: sym53c8xx_release, \
info: sym53c8xx_info, \
queuecommand: sym53c8xx_queue_command,\
+ slave_attach: sym53c8xx_slave_attach, \
abort: sym53c8xx_abort, \
reset: sym53c8xx_reset, \
bios_param: scsicam_bios_param, \
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
index 0f6114bda636..f36c1c5f2903 100644
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -89,6 +89,8 @@ int sym53c8xx_eh_device_reset_handler(Scsi_Cmnd *);
int sym53c8xx_eh_bus_reset_handler(Scsi_Cmnd *);
int sym53c8xx_eh_host_reset_handler(Scsi_Cmnd *);
+int sym53c8xx_slave_attach(Scsi_Device *);
+
#ifdef MODULE
int sym53c8xx_release(struct Scsi_Host *);
#else
@@ -109,6 +111,7 @@ int sym53c8xx_release(struct Scsi_Host *);
release: sym53c8xx_release, \
info: sym53c8xx_info, \
queuecommand: sym53c8xx_queue_command, \
+ slave_attach: sym53c8xx_slave_attach, \
eh_abort_handler: sym53c8xx_eh_abort_handler, \
eh_device_reset_handler:sym53c8xx_eh_device_reset_handler, \
eh_bus_reset_handler: sym53c8xx_eh_bus_reset_handler, \
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index 564802b6c8c2..685a29399965 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -1327,66 +1327,63 @@ static int device_queue_depth(hcb_p np, int target, int lun)
/*
* Linux entry point for device queue sizing.
*/
-static void
-sym53c8xx_select_queue_depths(struct Scsi_Host *host,
- struct scsi_device *devlist)
+int
+sym53c8xx_slave_attach(Scsi_Device *device)
{
- struct scsi_device *device;
-
- for (device = devlist; device; device = device->next) {
- hcb_p np;
- tcb_p tp;
- lcb_p lp;
- int reqtags;
-
- if (device->host != host)
- continue;
+ struct Scsi_Host *host = device->host;
+ hcb_p np;
+ tcb_p tp;
+ lcb_p lp;
+ int reqtags, depth_to_use;
- np = ((struct host_data *) host->hostdata)->ncb;
- tp = &np->target[device->id];
+ np = ((struct host_data *) host->hostdata)->ncb;
+ tp = &np->target[device->id];
- /*
- * Get user settings for transfer parameters.
- */
- tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16);
- sym_update_trans_settings(np, tp);
+ /*
+ * Get user settings for transfer parameters.
+ */
+ tp->inq_byte7_valid = (INQ7_SYNC|INQ7_WIDE16);
+ sym_update_trans_settings(np, tp);
- /*
- * Allocate the LCB if not yet.
- * If it fail, we may well be in the sh*t. :)
- */
- lp = sym_alloc_lcb(np, device->id, device->lun);
- if (!lp) {
- device->queue_depth = 1;
- continue;
- }
+ /*
+ * Allocate the LCB if not yet.
+ * If it fail, we may well be in the sh*t. :)
+ */
+ lp = sym_alloc_lcb(np, device->id, device->lun);
+ if (!lp)
+ return -ENOMEM;
- /*
- * Get user flags.
- */
- lp->curr_flags = lp->user_flags;
+ /*
+ * Get user flags.
+ */
+ lp->curr_flags = lp->user_flags;
- /*
- * Select queue depth from driver setup.
- * Donnot use more than configured by user.
- * Use at least 2.
- * Donnot use more than our maximum.
- */
- reqtags = device_queue_depth(np, device->id, device->lun);
- if (reqtags > tp->usrtags)
- reqtags = tp->usrtags;
- if (!device->tagged_supported)
- reqtags = 0;
+ /*
+ * Select queue depth from driver setup.
+ * Donnot use more than configured by user.
+ * Use at least 2.
+ * Donnot use more than our maximum.
+ */
+ reqtags = device_queue_depth(np, device->id, device->lun);
+ if (reqtags > tp->usrtags)
+ reqtags = tp->usrtags;
+ if (!device->tagged_supported)
+ reqtags = 0;
#if 1 /* Avoid to locally queue commands for no good reasons */
- if (reqtags > SYM_CONF_MAX_TAG)
- reqtags = SYM_CONF_MAX_TAG;
- device->queue_depth = reqtags ? reqtags : 2;
+ if (reqtags > SYM_CONF_MAX_TAG)
+ reqtags = SYM_CONF_MAX_TAG;
+ depth_to_use = (reqtags ? reqtags : 2);
#else
- device->queue_depth = reqtags ? SYM_CONF_MAX_TAG : 2;
+ depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
#endif
- lp->s.scdev_depth = device->queue_depth;
- sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
- }
+ scsi_adjust_queue_depth(device,
+ (device->tagged_supported ?
+ MSG_SIMPLE_TAG : 0),
+ depth_to_use);
+ lp->s.scdev_depth = depth_to_use;
+ sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
+
+ return 0;
}
/*
@@ -2132,7 +2129,6 @@ sym_attach (Scsi_Host_Template *tpnt, int unit, sym_device *dev)
#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
instance->max_cmd_len = 16;
#endif
- instance->select_queue_depths = sym53c8xx_select_queue_depths;
instance->highmem_io = 1;
SYM_UNLOCK_HCB(np, flags);