]> git.hungrycats.org Git - linux/commitdiff
[PATCH] Add char_devs to st
authorKai Mäkisara <kai.makisara@kolumbus.fi>
Tue, 30 Dec 2003 05:17:13 +0000 (23:17 -0600)
committerJames Bottomley <jejb@raven.il.steeleye.com>
Tue, 30 Dec 2003 05:17:13 +0000 (23:17 -0600)
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

Documentation/scsi/st.txt
drivers/scsi/st.c
drivers/scsi/st.h

index d5a0ac9153bc2575d388b85c979f6934dd0485e9..a09b0e76eb4c01bc6e0843a69963448c9298873d 100644 (file)
@@ -2,7 +2,7 @@ This file contains brief information about the SCSI tape driver.
 The driver is currently maintained by Kai Mäkisara (email
 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
@@ -95,6 +95,24 @@ tape in the drive (commands trying to write something return error if
 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
 
 The user can choose between these two behaviours of the tape driver by
index a64e43ac2601ab461d0a30e5bf3c6f99df7047a5..76de0e21f4c247889042bb02dafd596a0593f63e 100644 (file)
@@ -17,7 +17,7 @@
    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>
 
@@ -35,6 +35,7 @@ static char *verstr = "20030811";
 #include <linux/blkdev.h>
 #include <linux/moduleparam.h>
 #include <linux/devfs_fs_kernel.h>
+#include <linux/cdev.h>
 #include <asm/uaccess.h>
 #include <asm/dma.h>
 #include <asm/system.h>
@@ -140,14 +141,19 @@ DEB( static int debugging = DEBUG; )
 #define ST_TIMEOUT (900 * 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)
 
+/* 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
    24 bits) */
 #define SET_DENS_AND_BLK 0x10001
 
-#define ST_DEV_ARR_LUMP  6
 static rwlock_t st_dev_arr_lock = RW_LOCK_UNLOCKED;
 
 static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
@@ -1006,7 +1012,6 @@ static int st_open(struct inode *inode, struct file *filp)
        write_unlock(&st_dev_arr_lock);
        STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
 
-
        if (!scsi_block_when_processing_errors(STp->device)) {
                retval = (-ENXIO);
                goto err_out;
@@ -1970,10 +1975,13 @@ static int st_set_options(Scsi_Tape *STp, long options)
        long code;
        ST_mode *STm;
        char *name = tape_name(STp);
+       struct cdev *cd0, *cd1;
 
        STm = &(STp->modes[STp->current_mode]);
        if (!STm->defined) {
+               cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
                memcpy(STm, &(STp->modes[0]), sizeof(ST_mode));
+               STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
                modes_defined = TRUE;
                 DEBC(printk(ST_DEB_MSG
                             "%s: Initialized mode %d definition from mode 0\n",
@@ -3704,12 +3712,13 @@ static struct file_operations st_fops =
 static int st_probe(struct device *dev)
 {
        struct scsi_device *SDp = to_scsi_device(dev);
-       struct gendisk *disk;
-       Scsi_Tape *tpnt;
+       struct gendisk *disk = NULL;
+       struct cdev *cdev = NULL;
+       Scsi_Tape *tpnt = NULL;
        ST_mode *STm;
        ST_partstat *STps;
        ST_buffer *buffer;
-       int i, mode, dev_num;
+       int i, j, mode, dev_num, error;
        char *stp;
        u64 bounce_limit;
 
@@ -3743,7 +3752,7 @@ static int st_probe(struct device *dev)
                Scsi_Tape **tmp_da;
                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)
                        tmp_dev_max = ST_MAX_TAPES;
                if (tmp_dev_max <= st_nr_dev) {
@@ -3837,6 +3846,42 @@ static int st_probe(struct device *dev)
                STm->default_compression = ST_DONT_TOUCH;
                STm->default_blksize = (-1);    /* No forced size */
                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++) {
@@ -3881,17 +3926,28 @@ static int st_probe(struct device *dev)
 
 out_put_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:
        kfree(buffer);
 out:
        return -ENODEV;
 };
 
+
 static int st_remove(struct device *dev)
 {
        Scsi_Device *SDp = to_scsi_device(dev);
        Scsi_Tape *tpnt;
-       int i, mode;
+       int i, j, mode;
 
        write_lock(&st_dev_arr_lock);
        for (i = 0; i < st_dev_max; i++) {
@@ -3901,9 +3957,16 @@ static int st_remove(struct device *dev)
                        st_nr_dev--;
                        write_unlock(&st_dev_arr_lock);
                        devfs_unregister_tape(tpnt->disk->number);
+                       sysfs_remove_link(&SDp->sdev_gendev.kobj, "tape");
                        for (mode = 0; mode < ST_NBR_MODES; ++mode) {
                                devfs_remove("%s/mt%s", 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;
 
@@ -3930,12 +3993,14 @@ static int __init init_st(void)
                "st: Version %s, fixed bufsize %d, s/g segs %d\n",
                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) {
                        do_create_driverfs_files();
                        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);
@@ -3946,7 +4011,8 @@ static void __exit exit_st(void)
 {
        do_remove_driverfs_files();
        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);
        printk(KERN_INFO "st: Unloaded.\n");
 }
index 80a0f397ce8a3373a2e49af94b22e89f4870fc0c..10690f994d037cb946ab29e0484824e453895547 100644 (file)
@@ -47,13 +47,16 @@ typedef struct {
        unsigned char default_compression;      /* 0 = don't touch, etc */
        short default_density;  /* Forced density, -1 = no value */
        int default_blksize;    /* Forced blocksize, -1 = no value */
+       struct cdev *cdevs[2];  /* Auto-rewind and non-rewind devices */
 } ST_mode;
 
 #define ST_NBR_MODE_BITS 2
 #define ST_NBR_MODES (1 << 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_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 */
 typedef struct {