static const char *verstr = …;
#include <linux/module.h>
#include <linux/compat.h>
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched/signal.h>
#include <linux/mm.h>
#include <linux/init.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/mtio.h>
#include <linux/major.h>
#include <linux/cdrom.h>
#include <linux/ioctl.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/blkdev.h>
#include <linux/moduleparam.h>
#include <linux/cdev.h>
#include <linux/idr.h>
#include <linux/delay.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <asm/dma.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_device.h>
#include <scsi/scsi_driver.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
#include <scsi/sg.h>
#define DEBUG …
#define NO_DEBUG …
#define ST_DEB_MSG …
#if DEBUG
#define DEB(a) …
#define DEBC(a) …
#else
#define DEB …
#define DEBC …
#endif
#define ST_KILOBYTE …
#include "st_options.h"
#include "st.h"
static int buffer_kbs;
static int max_sg_segs;
static int try_direct_io = …;
static int try_rdio = …;
static int try_wdio = …;
static int debug_flag;
static const struct class st_sysfs_class;
static const struct attribute_group *st_dev_groups[];
static const struct attribute_group *st_drv_groups[];
MODULE_AUTHOR(…) …;
MODULE_DESCRIPTION(…) …;
MODULE_LICENSE(…) …;
MODULE_ALIAS_CHARDEV_MAJOR(…);
MODULE_ALIAS_SCSI_DEVICE(…);
module_param_named(buffer_kbs, buffer_kbs, int, 0);
MODULE_PARM_DESC(…) …;
module_param_named(max_sg_segs, max_sg_segs, int, 0);
MODULE_PARM_DESC(…) …;
module_param_named(try_direct_io, try_direct_io, int, 0);
MODULE_PARM_DESC(…) …;
module_param_named(debug_flag, debug_flag, int, 0);
MODULE_PARM_DESC(…) …;
module_param_named(try_rdio, try_rdio, int, 0);
MODULE_PARM_DESC(…) …;
module_param_named(try_wdio, try_wdio, int, 0);
MODULE_PARM_DESC(…) …;
#ifndef MODULE
static int write_threshold_kbs;
static struct st_dev_parm { … } parms[] __initdata = …;
#endif
#if ST_NBR_MODES > 16
#error "Maximum number of modes is 16"
#endif
static const char *st_formats[] = …;
#define ST_FIXED_BUFFER_SIZE …
#if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1)
#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
#endif
static int debugging = …;
#define MAX_RETRIES …
#define MAX_WRITE_RETRIES …
#define MAX_READY_RETRIES …
#define NO_TAPE …
#define ST_TIMEOUT …
#define ST_LONG_TIMEOUT …
#define TAPE_NR(x) …
#define TAPE_MODE(x) …
#define TAPE_MINOR(d, m, n) …
#define SET_DENS_AND_BLK …
static int st_fixed_buffer_size = …;
static int st_max_sg_segs = …;
static int modes_defined;
static int enlarge_buffer(struct st_buffer *, int);
static void clear_buffer(struct st_buffer *);
static void normalize_buffer(struct st_buffer *);
static int append_to_buffer(const char __user *, struct st_buffer *, int);
static int from_buffer(struct st_buffer *, char __user *, int);
static void move_buffer_data(struct st_buffer *, int);
static int sgl_map_user_pages(struct st_buffer *, const unsigned int,
unsigned long, size_t, int);
static int sgl_unmap_user_pages(struct st_buffer *, const unsigned int, int);
static int st_probe(struct device *);
static int st_remove(struct device *);
static struct scsi_driver st_template = …;
static int st_compression(struct scsi_tape *, int);
static int find_partition(struct scsi_tape *);
static int switch_partition(struct scsi_tape *);
static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long);
static void scsi_tape_release(struct kref *);
#define to_scsi_tape(obj) …
static DEFINE_MUTEX(st_ref_mutex);
static DEFINE_SPINLOCK(st_index_lock);
static DEFINE_SPINLOCK(st_use_lock);
static DEFINE_IDR(st_index_idr);
#ifndef SIGS_FROM_OSST
#define SIGS_FROM_OSST …
#endif
static struct scsi_tape *scsi_tape_get(int dev)
{ … }
static void scsi_tape_put(struct scsi_tape *STp)
{ … }
struct st_reject_data { … };
static struct st_reject_data reject_list[] = …;
static char * st_incompatible(struct scsi_device* SDp)
{ … }
#define st_printk(prefix, t, fmt, a...) …
#ifdef DEBUG
#define DEBC_printk(t, fmt, a...) …
#else
#define DEBC_printk …
#endif
static void st_analyze_sense(struct st_request *SRpnt, struct st_cmdstatus *s)
{ … }
static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
{ … }
static struct st_request *st_allocate_request(struct scsi_tape *stp)
{ … }
static void st_release_request(struct st_request *streq)
{ … }
static void st_do_stats(struct scsi_tape *STp, struct request *req)
{ … }
static enum rq_end_io_ret st_scsi_execute_end(struct request *req,
blk_status_t status)
{ … }
static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd,
int data_direction, void *buffer, unsigned bufflen,
int timeout, int retries)
{ … }
static struct st_request *
st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
int bytes, int direction, int timeout, int retries, int do_wait)
{ … }
static int write_behind_check(struct scsi_tape * STp)
{ … }
static int cross_eof(struct scsi_tape * STp, int forward)
{ … }
static int st_flush_write_buffer(struct scsi_tape * STp)
{ … }
static int flush_buffer(struct scsi_tape *STp, int seek_next)
{ … }
static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
{ … }
static int do_door_lock(struct scsi_tape * STp, int do_lock)
{ … }
static void reset_state(struct scsi_tape *STp)
{ … }
#define CHKRES_READY …
#define CHKRES_NEW_SESSION …
#define CHKRES_NOT_READY …
#define CHKRES_NO_TAPE …
#define MAX_ATTENTIONS …
static int test_ready(struct scsi_tape *STp, int do_wait)
{ … }
static int check_tape(struct scsi_tape *STp, struct file *filp)
{ … }
static int st_open(struct inode *inode, struct file *filp)
{ … }
static int st_flush(struct file *filp, fl_owner_t id)
{ … }
static int st_release(struct inode *inode, struct file *filp)
{ … }
static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
{ … }
static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
size_t count, int is_read)
{ … }
static void release_buffering(struct scsi_tape *STp, int is_read)
{ … }
static ssize_t
st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{ … }
static long read_tape(struct scsi_tape *STp, long count,
struct st_request ** aSRpnt)
{ … }
static ssize_t
st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
{ … }
DEB(…)
static int st_set_options(struct scsi_tape *STp, long options)
{ … }
#define MODE_HEADER_LENGTH …
#define MH_OFF_DATA_LENGTH …
#define MH_OFF_MEDIUM_TYPE …
#define MH_OFF_DEV_SPECIFIC …
#define MH_OFF_BDESCS_LENGTH …
#define MP_OFF_PAGE_NBR …
#define MP_OFF_PAGE_LENGTH …
#define MH_BIT_WP …
#define MP_MSK_PAGE_NBR …
#define MODE_SENSE_OMIT_BDESCS …
#define MODE_SELECT_PAGE_FORMAT …
static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
{ … }
static int write_mode_page(struct scsi_tape *STp, int page, int slow)
{ … }
#define COMPRESSION_PAGE …
#define COMPRESSION_PAGE_LENGTH …
#define CP_OFF_DCE_DCC …
#define CP_OFF_C_ALGO …
#define DCE_MASK …
#define DCC_MASK …
#define RED_MASK …
static int st_compression(struct scsi_tape * STp, int state)
{ … }
static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
{ … }
#if DEBUG
#define ST_DEB_FORWARD …
#define ST_DEB_BACKWARD …
static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd)
{ … }
#else
#define ST_DEB_FORWARD …
#define ST_DEB_BACKWARD …
static void deb_space_print(struct scsi_tape *STp, int direction, char *units, unsigned char *cmd) {}
#endif
static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
{ … }
static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition,
int logical)
{ … }
static int set_location(struct scsi_tape *STp, unsigned int block, int partition,
int logical)
{ … }
static int find_partition(struct scsi_tape *STp)
{ … }
static int switch_partition(struct scsi_tape *STp)
{ … }
#define PART_PAGE …
#define PART_PAGE_FIXED_LENGTH …
#define PP_OFF_MAX_ADD_PARTS …
#define PP_OFF_NBR_ADD_PARTS …
#define PP_OFF_FLAGS …
#define PP_OFF_PART_UNITS …
#define PP_OFF_RESERVED …
#define PP_BIT_IDP …
#define PP_BIT_FDP …
#define PP_MSK_PSUM_MB …
#define PP_MSK_PSUM_UNITS …
#define PP_MSK_POFM …
static int nbr_partitions(struct scsi_tape *STp)
{ … }
static int format_medium(struct scsi_tape *STp, int format)
{ … }
static int partition_tape(struct scsi_tape *STp, int size)
{ … }
static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{ … }
#ifdef CONFIG_COMPAT
static long st_compat_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
{ … }
#endif
static struct st_buffer *new_tape_buffer(int max_sg)
{ … }
#define ST_MAX_ORDER …
static int enlarge_buffer(struct st_buffer * STbuffer, int new_size)
{ … }
static void clear_buffer(struct st_buffer * st_bp)
{ … }
static void normalize_buffer(struct st_buffer * STbuffer)
{ … }
static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
{ … }
static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
{ … }
static void move_buffer_data(struct st_buffer * st_bp, int offset)
{ … }
static void validate_options(void)
{ … }
#ifndef MODULE
static int __init st_setup(char *str)
{ … }
__setup(…);
#endif
static const struct file_operations st_fops = …;
static int create_one_cdev(struct scsi_tape *tape, int mode, int rew)
{ … }
static int create_cdevs(struct scsi_tape *tape)
{ … }
static void remove_cdevs(struct scsi_tape *tape)
{ … }
static int st_probe(struct device *dev)
{
struct scsi_device *SDp = to_scsi_device(dev);
struct scsi_tape *tpnt = NULL;
struct st_modedef *STm;
struct st_partstat *STps;
struct st_buffer *buffer;
int i, error;
if (SDp->type != TYPE_TAPE)
return -ENODEV;
if (st_incompatible(SDp)) {
sdev_printk(KERN_INFO, SDp,
"OnStream tapes are no longer supported;\n");
sdev_printk(KERN_INFO, SDp,
"please mail to [email protected].\n");
return -ENODEV;
}
scsi_autopm_get_device(SDp);
i = queue_max_segments(SDp->request_queue);
if (st_max_sg_segs < i)
i = st_max_sg_segs;
buffer = new_tape_buffer(i);
if (buffer == NULL) {
sdev_printk(KERN_ERR, SDp,
"st: Can't allocate new tape buffer. "
"Device not attached.\n");
goto out;
}
tpnt = kzalloc(sizeof(struct scsi_tape), GFP_KERNEL);
if (tpnt == NULL) {
sdev_printk(KERN_ERR, SDp,
"st: Can't allocate device descriptor.\n");
goto out_buffer_free;
}
kref_init(&tpnt->kref);
tpnt->device = SDp;
if (SDp->scsi_level <= 2)
tpnt->tape_type = MT_ISSCSI1;
else
tpnt->tape_type = MT_ISSCSI2;
tpnt->buffer = buffer;
tpnt->buffer->last_SRpnt = NULL;
tpnt->inited = 0;
tpnt->dirty = 0;
tpnt->in_use = 0;
tpnt->drv_buffer = 1;
tpnt->use_pf = (SDp->scsi_level >= SCSI_2);
tpnt->density = 0;
tpnt->do_auto_lock = ST_AUTO_LOCK;
tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS);
tpnt->can_partitions = 0;
tpnt->two_fm = ST_TWO_FM;
tpnt->fast_mteom = ST_FAST_MTEOM;
tpnt->scsi2_logical = ST_SCSI2LOGICAL;
tpnt->sili = ST_SILI;
tpnt->immediate = ST_NOWAIT;
tpnt->immediate_filemark = 0;
tpnt->default_drvbuffer = 0xff;
tpnt->partition = 0;
tpnt->new_partition = 0;
tpnt->nbr_partitions = 0;
blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT);
tpnt->long_timeout = ST_LONG_TIMEOUT;
tpnt->try_dio = try_direct_io;
for (i = 0; i < ST_NBR_MODES; i++) {
STm = &(tpnt->modes[i]);
STm->defined = 0;
STm->sysv = ST_SYSV;
STm->defaults_for_writes = 0;
STm->do_async_writes = ST_ASYNC_WRITES;
STm->do_buffer_writes = ST_BUFFER_WRITES;
STm->do_read_ahead = ST_READ_AHEAD;
STm->default_compression = ST_DONT_TOUCH;
STm->default_blksize = (-1);
STm->default_density = (-1);
STm->tape = tpnt;
}
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps = &(tpnt->ps[i]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
STps->last_block_valid = 0;
STps->drv_block = (-1);
STps->drv_file = (-1);
}
tpnt->current_mode = 0;
tpnt->modes[0].defined = 1;
tpnt->density_changed = tpnt->compression_changed =
tpnt->blksize_changed = 0;
mutex_init(&tpnt->lock);
idr_preload(GFP_KERNEL);
spin_lock(&st_index_lock);
error = idr_alloc(&st_index_idr, tpnt, 0, ST_MAX_TAPES + 1, GFP_NOWAIT);
spin_unlock(&st_index_lock);
idr_preload_end();
if (error < 0) {
pr_warn("st: idr allocation failed: %d\n", error);
goto out_free_tape;
}
tpnt->index = error;
sprintf(tpnt->name, "st%d", tpnt->index);
tpnt->stats = kzalloc(sizeof(struct scsi_tape_stats), GFP_KERNEL);
if (tpnt->stats == NULL) {
sdev_printk(KERN_ERR, SDp,
"st: Can't allocate statistics.\n");
goto out_idr_remove;
}
dev_set_drvdata(dev, tpnt);
error = create_cdevs(tpnt);
if (error)
goto out_remove_devs;
scsi_autopm_put_device(SDp);
sdev_printk(KERN_NOTICE, SDp,
"Attached scsi tape %s\n", tpnt->name);
sdev_printk(KERN_INFO, SDp, "%s: try direct i/o: %s (alignment %d B)\n",
tpnt->name, tpnt->try_dio ? "yes" : "no",
queue_dma_alignment(SDp->request_queue) + 1);
return 0;
out_remove_devs:
remove_cdevs(tpnt);
kfree(tpnt->stats);
out_idr_remove:
spin_lock(&st_index_lock);
idr_remove(&st_index_idr, tpnt->index);
spin_unlock(&st_index_lock);
out_free_tape:
kfree(tpnt);
out_buffer_free:
kfree(buffer);
out:
scsi_autopm_put_device(SDp);
return -ENODEV;
};
static int st_remove(struct device *dev)
{ … }
static void scsi_tape_release(struct kref *kref)
{ … }
static const struct class st_sysfs_class = …;
static int __init init_st(void)
{ … }
static void __exit exit_st(void)
{ … }
module_init(…) …;
module_exit(exit_st);
static ssize_t try_direct_io_show(struct device_driver *ddp, char *buf)
{ … }
static DRIVER_ATTR_RO(try_direct_io);
static ssize_t fixed_buffer_size_show(struct device_driver *ddp, char *buf)
{ … }
static DRIVER_ATTR_RO(fixed_buffer_size);
static ssize_t max_sg_segs_show(struct device_driver *ddp, char *buf)
{ … }
static DRIVER_ATTR_RO(max_sg_segs);
static ssize_t version_show(struct device_driver *ddd, char *buf)
{ … }
static DRIVER_ATTR_RO(version);
#if DEBUG
static ssize_t debug_flag_store(struct device_driver *ddp,
const char *buf, size_t count)
{ … }
static ssize_t debug_flag_show(struct device_driver *ddp, char *buf)
{ … }
static DRIVER_ATTR_RW(debug_flag);
#endif
static struct attribute *st_drv_attrs[] = …;
ATTRIBUTE_GROUPS(…);
static ssize_t
defined_show(struct device *dev, struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(defined);
static ssize_t
default_blksize_show(struct device *dev, struct device_attribute *attr,
char *buf)
{ … }
static DEVICE_ATTR_RO(default_blksize);
static ssize_t
default_density_show(struct device *dev, struct device_attribute *attr,
char *buf)
{ … }
static DEVICE_ATTR_RO(default_density);
static ssize_t
default_compression_show(struct device *dev, struct device_attribute *attr,
char *buf)
{ … }
static DEVICE_ATTR_RO(default_compression);
static ssize_t
options_show(struct device *dev, struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(options);
static ssize_t read_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(read_cnt);
static ssize_t read_byte_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(read_byte_cnt);
static ssize_t read_ns_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(read_ns);
static ssize_t write_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(write_cnt);
static ssize_t write_byte_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(write_byte_cnt);
static ssize_t write_ns_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(write_ns);
static ssize_t in_flight_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(in_flight);
static ssize_t io_ns_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(io_ns);
static ssize_t other_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(other_cnt);
static ssize_t resid_cnt_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ … }
static DEVICE_ATTR_RO(resid_cnt);
static struct attribute *st_dev_attrs[] = …;
static struct attribute *st_stats_attrs[] = …;
static struct attribute_group stats_group = …;
static struct attribute_group st_group = …;
static const struct attribute_group *st_dev_groups[] = …;
static int sgl_map_user_pages(struct st_buffer *STbp,
const unsigned int max_pages, unsigned long uaddr,
size_t count, int rw)
{ … }
static int sgl_unmap_user_pages(struct st_buffer *STbp,
const unsigned int nr_pages, int dirtied)
{ … }