diff options
Diffstat (limited to 'drivers/scsi/st.c')
-rw-r--r-- | drivers/scsi/st.c | 138 |
1 files changed, 91 insertions, 47 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 7f669b600677..e016e0906e1a 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c @@ -9,7 +9,7 @@ Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky, Michael Schaefer, J"org Weule, and Eric Youngdale. - Copyright 1992 - 2005 Kai Makisara + Copyright 1992 - 2006 Kai Makisara email Kai.Makisara@kolumbus.fi Some small formal changes - aeb, 950809 @@ -17,7 +17,7 @@ Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support */ -static const char *verstr = "20050830"; +static const char *verstr = "20061107"; #include <linux/module.h> @@ -195,9 +195,9 @@ static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); static int st_probe(struct device *); static int st_remove(struct device *); -static void do_create_driverfs_files(void); +static int do_create_driverfs_files(void); static void do_remove_driverfs_files(void); -static void do_create_class_files(struct scsi_tape *, int, int); +static int do_create_class_files(struct scsi_tape *, int, int); static struct scsi_driver st_template = { .owner = THIS_MODULE, @@ -922,7 +922,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) struct st_modedef *STm; struct st_partstat *STps; char *name = tape_name(STp); - struct inode *inode = filp->f_dentry->d_inode; + struct inode *inode = filp->f_path.dentry->d_inode; int mode = TAPE_MODE(inode); STp->ready = ST_READY; @@ -999,7 +999,7 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) STp->min_block = ((STp->buffer)->b_data[4] << 8) | (STp->buffer)->b_data[5]; if ( DEB( debugging || ) !STp->inited) - printk(KERN_WARNING + printk(KERN_INFO "%s: Block limits %d - %d bytes.\n", name, STp->min_block, STp->max_block); } else { @@ -1177,7 +1177,10 @@ static int st_open(struct inode *inode, struct file *filp) goto err_out; if ((filp->f_flags & O_NONBLOCK) == 0 && retval != CHKRES_READY) { - retval = (-EIO); + if (STp->ready == NO_TAPE) + retval = (-ENOMEDIUM); + else + retval = (-EIO); goto err_out; } return 0; @@ -1221,7 +1224,7 @@ static int st_flush(struct file *filp, fl_owner_t id) } DEBC( if (STp->nbr_requests) - printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", + printk(KERN_DEBUG "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n", name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable)); if (STps->rw == ST_WRITING && !STp->pos_unknown) { @@ -4048,14 +4051,16 @@ static int st_probe(struct device *dev) STm->cdevs[j] = cdev; } - do_create_class_files(tpnt, dev_num, mode); + error = do_create_class_files(tpnt, dev_num, mode); + if (error) + goto out_free_tape; } - sdev_printk(KERN_WARNING, SDp, + sdev_printk(KERN_NOTICE, SDp, "Attached scsi tape %s\n", tape_name(tpnt)); - printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B)\n", - tape_name(tpnt), tpnt->try_dio ? "yes" : "no", - queue_dma_alignment(SDp->request_queue) + 1); + sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n", + tape_name(tpnt), tpnt->try_dio ? "yes" : "no", + queue_dma_alignment(SDp->request_queue) + 1); return 0; @@ -4157,32 +4162,45 @@ static void scsi_tape_release(struct kref *kref) static int __init init_st(void) { + int err; + validate_options(); - printk(KERN_INFO - "st: Version %s, fixed bufsize %d, s/g segs %d\n", + printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n", verstr, st_fixed_buffer_size, st_max_sg_segs); st_sysfs_class = class_create(THIS_MODULE, "scsi_tape"); if (IS_ERR(st_sysfs_class)) { - st_sysfs_class = NULL; printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); - return 1; + return PTR_ERR(st_sysfs_class); } - 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_region(MKDEV(SCSI_TAPE_MAJOR, 0), - ST_MAX_TAPE_ENTRIES); + err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), + ST_MAX_TAPE_ENTRIES, "st"); + if (err) { + printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", + SCSI_TAPE_MAJOR); + goto err_class; } - class_destroy(st_sysfs_class); - printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR); - return 1; + err = scsi_register_driver(&st_template.gendrv); + if (err) + goto err_chrdev; + + err = do_create_driverfs_files(); + if (err) + goto err_scsidrv; + + return 0; + +err_scsidrv: + scsi_unregister_driver(&st_template.gendrv); +err_chrdev: + unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), + ST_MAX_TAPE_ENTRIES); +err_class: + class_destroy(st_sysfs_class); + return err; } static void __exit exit_st(void) @@ -4225,14 +4243,33 @@ static ssize_t st_version_show(struct device_driver *ddd, char *buf) } static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL); -static void do_create_driverfs_files(void) +static int do_create_driverfs_files(void) { struct device_driver *driverfs = &st_template.gendrv; + int err; + + err = driver_create_file(driverfs, &driver_attr_try_direct_io); + if (err) + return err; + err = driver_create_file(driverfs, &driver_attr_fixed_buffer_size); + if (err) + goto err_try_direct_io; + err = driver_create_file(driverfs, &driver_attr_max_sg_segs); + if (err) + goto err_attr_fixed_buf; + err = driver_create_file(driverfs, &driver_attr_version); + if (err) + goto err_attr_max_sg; - driver_create_file(driverfs, &driver_attr_try_direct_io); - driver_create_file(driverfs, &driver_attr_fixed_buffer_size); - driver_create_file(driverfs, &driver_attr_max_sg_segs); - driver_create_file(driverfs, &driver_attr_version); + return 0; + +err_attr_max_sg: + driver_remove_file(driverfs, &driver_attr_max_sg_segs); +err_attr_fixed_buf: + driver_remove_file(driverfs, &driver_attr_fixed_buffer_size); +err_try_direct_io: + driver_remove_file(driverfs, &driver_attr_try_direct_io); + return err; } static void do_remove_driverfs_files(void) @@ -4293,15 +4330,12 @@ static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); -static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) +static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) { int i, rew, error; char name[10]; struct class_device *st_class_member; - if (!st_sysfs_class) - return; - for (rew=0; rew < 2; rew++) { /* Make sure that the minor numbers corresponding to the four first modes always get the same names */ @@ -4316,18 +4350,24 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) if (IS_ERR(st_class_member)) { printk(KERN_WARNING "st%d: class_device_create failed\n", dev_num); + error = PTR_ERR(st_class_member); goto out; } class_set_devdata(st_class_member, &STp->modes[mode]); - class_device_create_file(st_class_member, - &class_device_attr_defined); - class_device_create_file(st_class_member, - &class_device_attr_default_blksize); - class_device_create_file(st_class_member, - &class_device_attr_default_density); - class_device_create_file(st_class_member, - &class_device_attr_default_compression); + error = class_device_create_file(st_class_member, + &class_device_attr_defined); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_blksize); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_density); + if (error) goto out; + error = class_device_create_file(st_class_member, + &class_device_attr_default_compression); + if (error) goto out; + if (mode == 0 && rew == 0) { error = sysfs_create_link(&STp->device->sdev_gendev.kobj, &st_class_member->kobj, @@ -4336,11 +4376,15 @@ static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) printk(KERN_ERR "st%d: Can't create sysfs link from SCSI device.\n", dev_num); + goto out; } } } - out: - return; + + return 0; + +out: + return error; } /* The following functions may be useful for a larger audience. */ |