Commit 0f535a6a authored by Kai Mäkisara's avatar Kai Mäkisara Committed by James Bottomley

[PATCH] Add char_devs to st

This patch adds support for cdevs to the st driver. The changes are based on
Doug Gilbert's corresponding changes to the sg driver. Using cdevs brings the
following advantanges:
- support for many drives, currently the maximum is set to 128; the minor
  number assignment is explained in the patch to Documentation/scsi/README.st
- the tape devices appear in /sys/cdev/major/st*, as an example here are
  the entries for the first drive (4 modes, rewind and non-rewind
  devices):
  /sys/cdev/major/st0m0   /sys/cdev/major/st0m1   /sys/cdev/major/st0m2
  /sys/cdev/major/st0m3
  /sys/cdev/major/st0m0n  /sys/cdev/major/st0m1n  /sys/cdev/major/st0m2n
  /sys/cdev/major/st0m3n
parent ae1092b7
...@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver. ...@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
The driver is currently maintained by Kai Mäkisara (email The driver is currently maintained by Kai Mäkisara (email
Kai.Makisara@kolumbus.fi) Kai.Makisara@kolumbus.fi)
Last modified: Sat Apr 12 20:26:37 2003 by makisara Last modified: Sun Nov 9 22:36:02 2003 by makisara
BASICS BASICS
...@@ -95,6 +95,24 @@ tape in the drive (commands trying to write something return error if ...@@ -95,6 +95,24 @@ tape in the drive (commands trying to write something return error if
attempted). attempted).
MINOR NUMBERS
The tape driver currently supports 128 drives by default. This number
can be increased by editing st.h and recompiling the driver if
necessary. The upper limit is 2^17 drives if 4 modes for each drive
are used.
The minor numbers consist of the following bit fields:
dev_upper non-rew mode dev-lower
20 - 8 7 6 5 4 0
The non-rewind bit is always bit 7 (the uppermost bit in the lowermost
byte). The bits defining the mode are next to the non-rewind bits. The
remaining bits define the tape device number. This numbering is
backward compatible with the numbering used when the minor number was
only 8 bits wide.
BSD AND SYS V SEMANTICS BSD AND SYS V SEMANTICS
The user can choose between these two behaviours of the tape driver by The user can choose between these two behaviours of the tape driver by
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
*/ */
static char *verstr = "20030811"; static char *verstr = "20031228";
#include <linux/module.h> #include <linux/module.h>
...@@ -35,6 +35,7 @@ static char *verstr = "20030811"; ...@@ -35,6 +35,7 @@ static char *verstr = "20030811";
#include <linux/blkdev.h> #include <linux/blkdev.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/cdev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -140,14 +141,19 @@ DEB( static int debugging = DEBUG; ) ...@@ -140,14 +141,19 @@ DEB( static int debugging = DEBUG; )
#define ST_TIMEOUT (900 * HZ) #define ST_TIMEOUT (900 * HZ)
#define ST_LONG_TIMEOUT (14000 * HZ) #define ST_LONG_TIMEOUT (14000 * HZ)
#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT)) /* Remove mode bits and auto-rewind bit (7) */
#define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
(iminor(x) & ~(-1 << ST_MODE_SHIFT)) )
#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
/* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */
#define TAPE_MINOR(d, m, n) (((d & ~(255 >> (ST_NBR_MODE_BITS + 1))) << (ST_NBR_MODE_BITS + 1)) | \
(d & (255 >> (ST_NBR_MODE_BITS + 1))) | (m << ST_MODE_SHIFT) | ((n != 0) << 7) )
/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
24 bits) */ 24 bits) */
#define SET_DENS_AND_BLK 0x10001 #define SET_DENS_AND_BLK 0x10001
#define ST_DEV_ARR_LUMP 6
static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED; static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;
static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
...@@ -1006,7 +1012,6 @@ static int st_open(struct inode *inode, struct file *filp) ...@@ -1006,7 +1012,6 @@ static int st_open(struct inode *inode, struct file *filp)
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
if (!scsi_block_when_processing_errors(STp->device)) { if (!scsi_block_when_processing_errors(STp->device)) {
retval = (-ENXIO); retval = (-ENXIO);
goto err_out; goto err_out;
...@@ -1970,10 +1975,13 @@ static int st_set_options(Scsi_Tape *STp, long options) ...@@ -1970,10 +1975,13 @@ static int st_set_options(Scsi_Tape *STp, long options)
long code; long code;
ST_mode *STm; ST_mode *STm;
char *name = tape_name(STp); char *name = tape_name(STp);
struct cdev *cd0, *cd1;
STm = &(STp->modes[STp->current_mode]); STm = &(STp->modes[STp->current_mode]);
if (!STm->defined) { if (!STm->defined) {
cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
memcpy(STm, &(STp->modes[0]), sizeof(ST_mode)); memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
modes_defined = TRUE; modes_defined = TRUE;
DEBC(printk(ST_DEB_MSG DEBC(printk(ST_DEB_MSG
"%s: Initialized mode %d definition from mode 0\n", "%s: Initialized mode %d definition from mode 0\n",
...@@ -3704,12 +3712,13 @@ static struct file_operations st_fops = ...@@ -3704,12 +3712,13 @@ static struct file_operations st_fops =
static int st_probe(struct device *dev) static int st_probe(struct device *dev)
{ {
struct scsi_device *SDp = to_scsi_device(dev); struct scsi_device *SDp = to_scsi_device(dev);
struct gendisk *disk; struct gendisk *disk = NULL;
Scsi_Tape *tpnt; struct cdev *cdev = NULL;
Scsi_Tape *tpnt = NULL;
ST_mode *STm; ST_mode *STm;
ST_partstat *STps; ST_partstat *STps;
ST_buffer *buffer; ST_buffer *buffer;
int i, mode, dev_num; int i, j, mode, dev_num, error;
char *stp; char *stp;
u64 bounce_limit; u64 bounce_limit;
...@@ -3743,7 +3752,7 @@ static int st_probe(struct device *dev) ...@@ -3743,7 +3752,7 @@ static int st_probe(struct device *dev)
Scsi_Tape **tmp_da; Scsi_Tape **tmp_da;
int tmp_dev_max; int tmp_dev_max;
tmp_dev_max = st_nr_dev + ST_DEV_ARR_LUMP; tmp_dev_max = max(st_nr_dev * 2, 8);
if (tmp_dev_max > ST_MAX_TAPES) if (tmp_dev_max > ST_MAX_TAPES)
tmp_dev_max = ST_MAX_TAPES; tmp_dev_max = ST_MAX_TAPES;
if (tmp_dev_max <= st_nr_dev) { if (tmp_dev_max <= st_nr_dev) {
...@@ -3837,6 +3846,42 @@ static int st_probe(struct device *dev) ...@@ -3837,6 +3846,42 @@ static int st_probe(struct device *dev)
STm->default_compression = ST_DONT_TOUCH; STm->default_compression = ST_DONT_TOUCH;
STm->default_blksize = (-1); /* No forced size */ STm->default_blksize = (-1); /* No forced size */
STm->default_density = (-1); /* No forced density */ STm->default_density = (-1); /* No forced density */
for (j=0; j < 2; j++) {
cdev = cdev_alloc();
if (!cdev) {
printk(KERN_ERR
"st: out of memory. Device not attached.\n");
goto out_put_disk;
}
snprintf(cdev->kobj.name, KOBJ_NAME_LEN, "%sm%d%s", disk->disk_name,
i, j ? "n" : "");
cdev->owner = THIS_MODULE;
cdev->ops = &st_fops;
STm->cdevs[j] = cdev;
error = cdev_add(STm->cdevs[j],
MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, i, j)),
1);
if (error) {
printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n",
dev_num, j ? "non" : "auto", i);
}
error = sysfs_create_link(&STm->cdevs[j]->kobj, &SDp->sdev_gendev.kobj,
"device");
if (error) {
printk(KERN_ERR
"st%d: Can't create sysfs link from SCSI device.\n",
dev_num);
}
}
}
error = sysfs_create_link(&SDp->sdev_gendev.kobj, &tpnt->modes[0].cdevs[0]->kobj,
"tape");
if (error) {
printk(KERN_ERR "st%d: Can't create sysfs link from SCSI device.\n",
dev_num);
} }
for (i = 0; i < ST_NBR_PARTITIONS; i++) { for (i = 0; i < ST_NBR_PARTITIONS; i++) {
...@@ -3881,17 +3926,28 @@ static int st_probe(struct device *dev) ...@@ -3881,17 +3926,28 @@ static int st_probe(struct device *dev)
out_put_disk: out_put_disk:
put_disk(disk); put_disk(disk);
if (tpnt) {
for (i=0; i < ST_NBR_MODES; i++) {
STm = &(tpnt->modes[i]);
if (STm->cdevs[0])
kobject_put(&STm->cdevs[0]->kobj);
if (STm->cdevs[1])
kobject_put(&STm->cdevs[1]->kobj);
}
kfree(tpnt);
}
out_buffer_free: out_buffer_free:
kfree(buffer); kfree(buffer);
out: out:
return -ENODEV; return -ENODEV;
}; };
static int st_remove(struct device *dev) static int st_remove(struct device *dev)
{ {
Scsi_Device *SDp = to_scsi_device(dev); Scsi_Device *SDp = to_scsi_device(dev);
Scsi_Tape *tpnt; Scsi_Tape *tpnt;
int i, mode; int i, j, mode;
write_lock(&st_dev_arr_lock); write_lock(&st_dev_arr_lock);
for (i = 0; i < st_dev_max; i++) { for (i = 0; i < st_dev_max; i++) {
...@@ -3901,9 +3957,16 @@ static int st_remove(struct device *dev) ...@@ -3901,9 +3957,16 @@ static int st_remove(struct device *dev)
st_nr_dev--; st_nr_dev--;
write_unlock(&st_dev_arr_lock); write_unlock(&st_dev_arr_lock);
devfs_unregister_tape(tpnt->disk->number); devfs_unregister_tape(tpnt->disk->number);
sysfs_remove_link(&SDp->sdev_gendev.kobj, "tape");
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]); devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]);
devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]); devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]);
for (j=0; j < 2; j++) {
sysfs_remove_link(&tpnt->modes[mode].cdevs[j]->kobj,
"device");
cdev_del(tpnt->modes[mode].cdevs[j]);
tpnt->modes[mode].cdevs[j] = NULL;
}
} }
tpnt->device = NULL; tpnt->device = NULL;
...@@ -3930,12 +3993,14 @@ static int __init init_st(void) ...@@ -3930,12 +3993,14 @@ static int __init init_st(void)
"st: Version %s, fixed bufsize %d, s/g segs %d\n", "st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs); verstr, st_fixed_buffer_size, st_max_sg_segs);
if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) { if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES, "st")) {
if (scsi_register_driver(&st_template.gendrv) == 0) { if (scsi_register_driver(&st_template.gendrv) == 0) {
do_create_driverfs_files(); do_create_driverfs_files();
return 0; return 0;
} }
unregister_chrdev(SCSI_TAPE_MAJOR, "st"); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
} }
printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR); printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
...@@ -3946,7 +4011,8 @@ static void __exit exit_st(void) ...@@ -3946,7 +4011,8 @@ static void __exit exit_st(void)
{ {
do_remove_driverfs_files(); do_remove_driverfs_files();
scsi_unregister_driver(&st_template.gendrv); scsi_unregister_driver(&st_template.gendrv);
unregister_chrdev(SCSI_TAPE_MAJOR, "st"); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
ST_MAX_TAPE_ENTRIES);
kfree(scsi_tapes); kfree(scsi_tapes);
printk(KERN_INFO "st: Unloaded.\n"); printk(KERN_INFO "st: Unloaded.\n");
} }
......
...@@ -47,13 +47,16 @@ typedef struct { ...@@ -47,13 +47,16 @@ typedef struct {
unsigned char default_compression; /* 0 = don't touch, etc */ unsigned char default_compression; /* 0 = don't touch, etc */
short default_density; /* Forced density, -1 = no value */ short default_density; /* Forced density, -1 = no value */
int default_blksize; /* Forced blocksize, -1 = no value */ int default_blksize; /* Forced blocksize, -1 = no value */
struct cdev *cdevs[2]; /* Auto-rewind and non-rewind devices */
} ST_mode; } ST_mode;
#define ST_NBR_MODE_BITS 2 #define ST_NBR_MODE_BITS 2
#define ST_NBR_MODES (1 << ST_NBR_MODE_BITS) #define ST_NBR_MODES (1 << ST_NBR_MODE_BITS)
#define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS) #define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS)
#define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT) #define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT)
#define ST_MAX_TAPES (1 << ST_MODE_SHIFT)
#define ST_MAX_TAPES 128
#define ST_MAX_TAPE_ENTRIES (ST_MAX_TAPES << (ST_NBR_MODE_BITS + 1))
/* The status related to each partition */ /* The status related to each partition */
typedef struct { typedef struct {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment