diff options
Diffstat (limited to 'drivers/scsi/st.c')
| -rw-r--r-- | drivers/scsi/st.c | 947 |
1 files changed, 519 insertions, 428 deletions
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 0a52d9d2da2..14eb4b256a0 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 - 2008 Kai Makisara + Copyright 1992 - 2010 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 = "20080221"; +static const char *verstr = "20101219"; #include <linux/module.h> @@ -27,6 +27,7 @@ static const char *verstr = "20080221"; #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/cdrom.h> @@ -36,12 +37,12 @@ static const char *verstr = "20080221"; #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 <asm/uaccess.h> #include <asm/dma.h> -#include <asm/system.h> #include <scsi/scsi.h> #include <scsi/scsi_dbg.h> @@ -80,10 +81,8 @@ static int try_direct_io = TRY_DIRECT_IO; static int try_rdio = 1; static int try_wdio = 1; -static int st_dev_max; -static int st_nr_dev; - -static struct class *st_sysfs_class; +static struct class st_sysfs_class; +static const struct attribute_group *st_dev_groups[]; MODULE_AUTHOR("Kai Makisara"); MODULE_DESCRIPTION("SCSI tape (st) driver"); @@ -172,33 +171,27 @@ static int debugging = DEBUG; 24 bits) */ #define SET_DENS_AND_BLK 0x10001 -static DEFINE_RWLOCK(st_dev_arr_lock); - static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE; static int st_max_sg_segs = ST_MAX_SG; -static struct scsi_tape **scsi_tapes = NULL; - static int modes_defined; -static struct st_buffer *new_tape_buffer(int, int, int); static int enlarge_buffer(struct st_buffer *, int, 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 void buf_to_sg(struct st_buffer *, unsigned int); -static int sgl_map_user_pages(struct scatterlist *, const unsigned 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 scatterlist *, const unsigned int, 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 int do_create_sysfs_files(void); static void do_remove_sysfs_files(void); -static int do_create_class_files(struct scsi_tape *, int, int); static struct scsi_driver st_template = { .owner = THIS_MODULE, @@ -221,6 +214,10 @@ static void scsi_tape_release(struct kref *); #define to_scsi_tape(obj) container_of(obj, struct scsi_tape, kref) static DEFINE_MUTEX(st_ref_mutex); +static DEFINE_SPINLOCK(st_index_lock); +static DEFINE_SPINLOCK(st_use_lock); +static DEFINE_IDR(st_index_idr); + #include "osst_detect.h" @@ -238,10 +235,9 @@ static struct scsi_tape *scsi_tape_get(int dev) struct scsi_tape *STp = NULL; mutex_lock(&st_ref_mutex); - write_lock(&st_dev_arr_lock); + spin_lock(&st_index_lock); - if (dev < st_dev_max && scsi_tapes != NULL) - STp = scsi_tapes[dev]; + STp = idr_find(&st_index_idr, dev); if (!STp) goto out; kref_get(&STp->kref); @@ -258,7 +254,7 @@ out_put: kref_put(&STp->kref, scsi_tape_release); STp = NULL; out: - write_unlock(&st_dev_arr_lock); + spin_unlock(&st_index_lock); mutex_unlock(&st_ref_mutex); return STp; } @@ -374,9 +370,9 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) if (!debugging) { /* Abnormal conditions for tape */ if (!cmdstatp->have_sense) printk(KERN_WARNING - "%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - name, result, suggestion(result), - driver_byte(result) & DRIVER_MASK, host_byte(result)); + "%s: Error %x (driver bt 0x%x, host bt 0x%x).\n", + name, result, driver_byte(result), + host_byte(result)); else if (cmdstatp->have_sense && scode != NO_SENSE && scode != RECOVERED_ERROR && @@ -433,29 +429,87 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt) return (-EIO); } +static struct st_request *st_allocate_request(struct scsi_tape *stp) +{ + struct st_request *streq; + + streq = kzalloc(sizeof(*streq), GFP_KERNEL); + if (streq) + streq->stp = stp; + else { + DEBC(printk(KERN_ERR "%s: Can't get SCSI request.\n", + tape_name(stp));); + if (signal_pending(current)) + stp->buffer->syscall_result = -EINTR; + else + stp->buffer->syscall_result = -EBUSY; + } + + return streq; +} -/* Wakeup from interrupt */ -static void st_sleep_done(void *data, char *sense, int result, int resid) +static void st_release_request(struct st_request *streq) +{ + kfree(streq); +} + +static void st_scsi_execute_end(struct request *req, int uptodate) { - struct st_request *SRpnt = data; + struct st_request *SRpnt = req->end_io_data; struct scsi_tape *STp = SRpnt->stp; + struct bio *tmp; - memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); - (STp->buffer)->cmdstat.midlevel_result = SRpnt->result = result; - DEB( STp->write_pending = 0; ) + STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; + STp->buffer->cmdstat.residual = req->resid_len; + tmp = SRpnt->bio; if (SRpnt->waiting) complete(SRpnt->waiting); -} -static struct st_request *st_allocate_request(void) -{ - return kzalloc(sizeof(struct st_request), GFP_KERNEL); + blk_rq_unmap_user(tmp); + __blk_put_request(req->q, req); } -static void st_release_request(struct st_request *streq) +static int st_scsi_execute(struct st_request *SRpnt, const unsigned char *cmd, + int data_direction, void *buffer, unsigned bufflen, + int timeout, int retries) { - kfree(streq); + struct request *req; + struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; + int err = 0; + int write = (data_direction == DMA_TO_DEVICE); + + req = blk_get_request(SRpnt->stp->device->request_queue, write, + GFP_KERNEL); + if (!req) + return DRIVER_ERROR << 24; + + blk_rq_set_block_pc(req); + req->cmd_flags |= REQ_QUIET; + + mdata->null_mapped = 1; + + if (bufflen) { + err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, + GFP_KERNEL); + if (err) { + blk_put_request(req); + return DRIVER_ERROR << 24; + } + } + + SRpnt->bio = req->bio; + req->cmd_len = COMMAND_SIZE(cmd[0]); + memset(req->cmd, 0, BLK_MAX_CDB); + memcpy(req->cmd, cmd, req->cmd_len); + req->sense = SRpnt->sense; + req->sense_len = 0; + req->timeout = timeout; + req->retries = retries; + req->end_io_data = SRpnt; + + blk_execute_rq_nowait(req->q, NULL, req, 1, st_scsi_execute_end); + return 0; } /* Do the scsi command. Waits until command performed if do_wait is true. @@ -466,6 +520,8 @@ 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) { struct completion *waiting; + struct rq_map_data *mdata = &STp->buffer->map_data; + int ret; /* if async, make sure there's no command outstanding */ if (!do_wait && ((STp->buffer)->last_SRpnt)) { @@ -478,18 +534,10 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd return NULL; } - if (SRpnt == NULL) { - SRpnt = st_allocate_request(); - if (SRpnt == NULL) { - DEBC( printk(KERN_ERR "%s: Can't get SCSI request.\n", - tape_name(STp)); ); - if (signal_pending(current)) - (STp->buffer)->syscall_result = (-EINTR); - else - (STp->buffer)->syscall_result = (-EBUSY); + if (!SRpnt) { + SRpnt = st_allocate_request(STp); + if (!SRpnt) return NULL; - } - SRpnt->stp = STp; } /* If async IO, set last_SRpnt. This ptr tells write_behind_check @@ -501,21 +549,29 @@ st_do_scsi(struct st_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd init_completion(waiting); SRpnt->waiting = waiting; - if (!STp->buffer->do_dio) - buf_to_sg(STp->buffer, bytes); + if (STp->buffer->do_dio) { + mdata->page_order = 0; + mdata->nr_entries = STp->buffer->sg_segs; + mdata->pages = STp->buffer->mapped_pages; + } else { + mdata->page_order = STp->buffer->reserved_page_order; + mdata->nr_entries = + DIV_ROUND_UP(bytes, PAGE_SIZE << mdata->page_order); + mdata->pages = STp->buffer->reserved_pages; + mdata->offset = 0; + } memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); STp->buffer->cmdstat.have_sense = 0; STp->buffer->syscall_result = 0; - if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, - &((STp->buffer)->sg[0]), bytes, (STp->buffer)->sg_segs, - timeout, retries, SRpnt, st_sleep_done, GFP_KERNEL)) { + ret = st_scsi_execute(SRpnt, cmd, direction, NULL, bytes, timeout, + retries); + if (ret) { /* could not allocate the buffer or request was too large */ (STp->buffer)->syscall_result = (-EBUSY); (STp->buffer)->last_SRpnt = NULL; - } - else if (do_wait) { + } else if (do_wait) { wait_for_completion(waiting); SRpnt->waiting = NULL; (STp->buffer)->syscall_result = st_chk_result(STp, SRpnt); @@ -610,7 +666,8 @@ static int cross_eof(struct scsi_tape * STp, int forward) tape_name(STp), forward ? "forward" : "backward")); SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, - STp->device->timeout, MAX_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_RETRIES, 1); if (!SRpnt) return (STp->buffer)->syscall_result; @@ -626,9 +683,9 @@ static int cross_eof(struct scsi_tape * STp, int forward) /* Flush the write buffer (never need to write if variable blocksize). */ -static int flush_write_buffer(struct scsi_tape * STp) +static int st_flush_write_buffer(struct scsi_tape * STp) { - int offset, transfer, blks; + int transfer, blks; int result; unsigned char cmd[MAX_COMMAND_SIZE]; struct st_request *SRpnt; @@ -641,14 +698,10 @@ static int flush_write_buffer(struct scsi_tape * STp) result = 0; if (STp->dirty == 1) { - offset = (STp->buffer)->buffer_bytes; - transfer = ((offset + STp->block_size - 1) / - STp->block_size) * STp->block_size; + transfer = STp->buffer->buffer_bytes; DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n", tape_name(STp), transfer)); - memset((STp->buffer)->b_data + offset, 0, transfer - offset); - memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_6; cmd[1] = 1; @@ -658,7 +711,8 @@ static int flush_write_buffer(struct scsi_tape * STp) cmd[4] = blks; SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE, - STp->device->timeout, MAX_WRITE_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_WRITE_RETRIES, 1); if (!SRpnt) return (STp->buffer)->syscall_result; @@ -717,7 +771,7 @@ static int flush_buffer(struct scsi_tape *STp, int seek_next) return 0; STps = &(STp->ps[STp->partition]); if (STps->rw == ST_WRITING) /* Writing */ - return flush_write_buffer(STp); + return st_flush_write_buffer(STp); if (STp->block_size == 0) return 0; @@ -923,7 +977,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_path.dentry->d_inode; + struct inode *inode = file_inode(filp); int mode = TAPE_MODE(inode); STp->ready = ST_READY; @@ -988,7 +1042,8 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) cmd[0] = READ_BLOCK_LIMITS; SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE, - STp->device->timeout, MAX_READY_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; @@ -1015,7 +1070,8 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) cmd[4] = 12; SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE, - STp->device->timeout, MAX_READY_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); if (!SRpnt) { retval = (STp->buffer)->syscall_result; goto err_out; @@ -1045,6 +1101,12 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) STp->drv_buffer)); } STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; + if (!STp->drv_buffer && STp->immediate_filemark) { + printk(KERN_WARNING + "%s: non-buffered tape: disabling writing immediate filemarks\n", + name); + STp->immediate_filemark = 0; + } } st_release_request(SRpnt); SRpnt = NULL; @@ -1111,11 +1173,12 @@ static int check_tape(struct scsi_tape *STp, struct file *filp) } -/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host +/* Open the device. Needs to take the BKL only because of incrementing the SCSI host module count. */ static int st_open(struct inode *inode, struct file *filp) { int i, retval = (-EIO); + int resumed = 0; struct scsi_tape *STp; struct st_partstat *STps; int dev = TAPE_NR(inode); @@ -1128,24 +1191,30 @@ static int st_open(struct inode *inode, struct file *filp) */ filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); - if (!(STp = scsi_tape_get(dev))) + if (!(STp = scsi_tape_get(dev))) { return -ENXIO; + } - write_lock(&st_dev_arr_lock); filp->private_data = STp; name = tape_name(STp); + spin_lock(&st_use_lock); if (STp->in_use) { - write_unlock(&st_dev_arr_lock); + spin_unlock(&st_use_lock); scsi_tape_put(STp); DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); ) return (-EBUSY); } STp->in_use = 1; - write_unlock(&st_dev_arr_lock); + spin_unlock(&st_use_lock); STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0; + if (scsi_autopm_get_device(STp->device) < 0) { + retval = -EIO; + goto err_out; + } + resumed = 1; if (!scsi_block_when_processing_errors(STp->device)) { retval = (-ENXIO); goto err_out; @@ -1159,6 +1228,7 @@ static int st_open(struct inode *inode, struct file *filp) goto err_out; } + (STp->buffer)->cleared = 0; (STp->buffer)->writing = 0; (STp->buffer)->syscall_result = 0; @@ -1189,8 +1259,12 @@ static int st_open(struct inode *inode, struct file *filp) err_out: normalize_buffer(STp->buffer); + spin_lock(&st_use_lock); STp->in_use = 0; + spin_unlock(&st_use_lock); scsi_tape_put(STp); + if (resumed) + scsi_autopm_put_device(STp->device); return retval; } @@ -1211,7 +1285,7 @@ static int st_flush(struct file *filp, fl_owner_t id) return 0; if (STps->rw == ST_WRITING && !STp->pos_unknown) { - result = flush_write_buffer(STp); + result = st_flush_write_buffer(STp); if (result != 0 && result != (-ENOSPC)) goto out; } @@ -1238,10 +1312,13 @@ static int st_flush(struct file *filp, fl_owner_t id) memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = WRITE_FILEMARKS; + if (STp->immediate_filemark) + cmd[1] = 1; cmd[4] = 1 + STp->two_fm; SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE, - STp->device->timeout, MAX_WRITE_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_WRITE_RETRIES, 1); if (!SRpnt) { result = (STp->buffer)->syscall_result; goto out; @@ -1319,9 +1396,10 @@ static int st_release(struct inode *inode, struct file *filp) do_door_lock(STp, 0); normalize_buffer(STp->buffer); - write_lock(&st_dev_arr_lock); + spin_lock(&st_use_lock); STp->in_use = 0; - write_unlock(&st_dev_arr_lock); + spin_unlock(&st_use_lock); + scsi_autopm_put_device(STp->device); scsi_tape_put(STp); return result; @@ -1408,8 +1486,8 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, if (i && ((unsigned long)buf & queue_dma_alignment( STp->device->request_queue)) == 0) { - i = sgl_map_user_pages(&(STbp->sg[0]), STbp->use_sg, - (unsigned long)buf, count, (is_read ? READ : WRITE)); + i = sgl_map_user_pages(STbp, STbp->use_sg, (unsigned long)buf, + count, (is_read ? READ : WRITE)); if (i > 0) { STbp->do_dio = i; STbp->buffer_bytes = 0; /* can be used as transfer counter */ @@ -1417,7 +1495,6 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, else STbp->do_dio = 0; /* fall back to buffering with any error */ STbp->sg_segs = STbp->do_dio; - STbp->frp_sg_current = 0; DEB( if (STbp->do_dio) { STp->nbr_dio++; @@ -1432,8 +1509,14 @@ static int setup_buffering(struct scsi_tape *STp, const char __user *buf, if (STp->block_size) bufsize = STp->block_size > st_fixed_buffer_size ? STp->block_size : st_fixed_buffer_size; - else + else { bufsize = count; + /* Make sure that data from previous user is not leaked even if + HBA does not return correct residual */ + if (is_read && STp->sili && !STbp->cleared) + clear_buffer(STbp); + } + if (bufsize > STbp->buffer_size && !enlarge_buffer(STbp, bufsize, STp->restr_dma)) { printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n", @@ -1457,7 +1540,7 @@ static void release_buffering(struct scsi_tape *STp, int is_read) STbp = STp->buffer; if (STbp->do_dio) { - sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, is_read); + sgl_unmap_user_pages(STbp, STbp->do_dio, is_read); STbp->do_dio = 0; STbp->sg_segs = 0; } @@ -1622,7 +1705,8 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) cmd[4] = blks; SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE, - STp->device->timeout, MAX_WRITE_RETRIES, !async_write); + STp->device->request_queue->rq_timeout, + MAX_WRITE_RETRIES, !async_write); if (!SRpnt) { retval = STbp->syscall_result; goto out; @@ -1654,6 +1738,7 @@ st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) if (undone <= do_count) { /* Only data from this write is not written */ count += undone; + b_point -= undone; do_count -= undone; if (STp->block_size) blks = (transfer - undone) / STp->block_size; @@ -1783,13 +1868,16 @@ static long read_tape(struct scsi_tape *STp, long count, memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = READ_6; cmd[1] = (STp->block_size != 0); + if (!cmd[1] && STp->sili) + cmd[1] |= 2; cmd[2] = blks >> 16; cmd[3] = blks >> 8; cmd[4] = blks; SRpnt = *aSRpnt; SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE, - STp->device->timeout, MAX_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_RETRIES, 1); release_buffering(STp, 1); *aSRpnt = SRpnt; if (!SRpnt) @@ -1911,8 +1999,11 @@ static long read_tape(struct scsi_tape *STp, long count, } /* End of error handling */ - else /* Read successful */ + else { /* Read successful */ STbp->buffer_bytes = bytes; + if (STp->sili) /* In fixed block mode residual is always zero here */ + STbp->buffer_bytes -= STp->buffer->cmdstat.residual; + } if (STps->drv_block >= 0) { if (STp->block_size == 0) @@ -2090,7 +2181,9 @@ static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, STp->scsi2_logical); printk(KERN_INFO - "%s: sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate); + "%s: sysv: %d nowait: %d sili: %d nowait_filemark: %d\n", + name, STm->sysv, STp->immediate, STp->sili, + STp->immediate_filemark); printk(KERN_INFO "%s: debugging: %d\n", name, debugging); } @@ -2105,12 +2198,19 @@ static int st_set_options(struct scsi_tape *STp, long options) struct st_modedef *STm; char *name = tape_name(STp); struct cdev *cd0, *cd1; + struct device *d0, *d1; STm = &(STp->modes[STp->current_mode]); if (!STm->defined) { - cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1]; + cd0 = STm->cdevs[0]; + cd1 = STm->cdevs[1]; + d0 = STm->devs[0]; + d1 = STm->devs[1]; memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef)); - STm->cdevs[0] = cd0; STm->cdevs[1] = cd1; + STm->cdevs[0] = cd0; + STm->cdevs[1] = cd1; + STm->devs[0] = d0; + STm->devs[1] = d1; modes_defined = 1; DEBC(printk(ST_DEB_MSG "%s: Initialized mode %d definition from mode 0\n", @@ -2132,7 +2232,9 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; STp->immediate = (options & MT_ST_NOWAIT) != 0; + STp->immediate_filemark = (options & MT_ST_NOWAIT_EOF) != 0; STm->sysv = (options & MT_ST_SYSV) != 0; + STp->sili = (options & MT_ST_SILI) != 0; DEB( debugging = (options & MT_ST_DEBUGGING) != 0; st_log_options(STp, STm, name); ) } else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { @@ -2162,8 +2264,12 @@ static int st_set_options(struct scsi_tape *STp, long options) STp->scsi2_logical = value; if ((options & MT_ST_NOWAIT) != 0) STp->immediate = value; + if ((options & MT_ST_NOWAIT_EOF) != 0) + STp->immediate_filemark = value; if ((options & MT_ST_SYSV) != 0) STm->sysv = value; + if ((options & MT_ST_SILI) != 0) + STp->sili = value; DEB( if ((options & MT_ST_DEBUGGING) != 0) debugging = value; @@ -2191,14 +2297,16 @@ static int st_set_options(struct scsi_tape *STp, long options) DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name, (value & ~MT_ST_SET_LONG_TIMEOUT))); } else { - STp->device->timeout = value * HZ; + blk_queue_rq_timeout(STp->device->request_queue, + value * HZ); DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n", name, value) ); } } else if (code == MT_ST_SET_CLN) { value = (options & ~MT_ST_OPTIONS) & 0xff; if (value != 0 && - value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE) + (value < EXTENDED_SENSE_START || + value >= SCSI_SENSE_BUFFERSIZE)) return (-EINVAL); STp->cln_mode = value; STp->cln_sense_mask = (options >> 8) & 0xff; @@ -2289,7 +2397,7 @@ static int st_set_options(struct scsi_tape *STp, long options) static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) { unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt = NULL; + struct st_request *SRpnt; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SENSE; @@ -2298,14 +2406,14 @@ static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs) cmd[2] = page; cmd[4] = 255; - SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, - STp->device->timeout, 0, 1); + SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_FROM_DEVICE, + STp->device->request_queue->rq_timeout, 0, 1); if (SRpnt == NULL) return (STp->buffer)->syscall_result; st_release_request(SRpnt); - return (STp->buffer)->syscall_result; + return STp->buffer->syscall_result; } @@ -2315,7 +2423,8 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow) { int pgo; unsigned char cmd[MAX_COMMAND_SIZE]; - struct st_request *SRpnt = NULL; + struct st_request *SRpnt; + int timeout; memset(cmd, 0, MAX_COMMAND_SIZE); cmd[0] = MODE_SELECT; @@ -2329,14 +2438,16 @@ static int write_mode_page(struct scsi_tape *STp, int page, int slow) (STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP; (STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR; - SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, - (slow ? STp->long_timeout : STp->device->timeout), 0, 1); + timeout = slow ? + STp->long_timeout : STp->device->request_queue->rq_timeout; + SRpnt = st_do_scsi(NULL, STp, cmd, cmd[4], DMA_TO_DEVICE, + timeout, 0, 1); if (SRpnt == NULL) return (STp->buffer)->syscall_result; st_release_request(SRpnt); - return (STp->buffer)->syscall_result; + return STp->buffer->syscall_result; } @@ -2442,7 +2553,7 @@ static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_cod } if (STp->immediate) { cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; } else timeout = STp->long_timeout; @@ -2607,18 +2718,22 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon } break; case MTWEOF: + case MTWEOFI: case MTWSM: if (STp->write_prot) return (-EACCES); cmd[0] = WRITE_FILEMARKS; if (cmd_in == MTWSM) cmd[1] = 2; + if (cmd_in == MTWEOFI || + (cmd_in == MTWEOF && STp->immediate_filemark)) + cmd[1] |= 1; cmd[2] = (arg >> 16); cmd[3] = (arg >> 8); cmd[4] = arg; - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; DEBC( - if (cmd_in == MTWEOF) + if (cmd_in != MTWSM) printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name, cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); else @@ -2634,7 +2749,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon cmd[0] = REZERO_UNIT; if (STp->immediate) { cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; } DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name)); fileno = blkno = at_sm = 0; @@ -2647,7 +2762,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon cmd[0] = START_STOP; if (STp->immediate) { cmd[1] = 1; /* Don't wait for completion */ - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; } cmd[4] = 3; DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name)); @@ -2680,7 +2795,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon cmd[1] = (arg ? 1 : 0); /* Long erase with non-zero argument */ if (STp->immediate) { cmd[1] |= 2; /* Don't wait for completion */ - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; } else timeout = STp->long_timeout * 8; @@ -2732,7 +2847,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon (STp->buffer)->b_data[9] = (ltmp >> 16); (STp->buffer)->b_data[10] = (ltmp >> 8); (STp->buffer)->b_data[11] = ltmp; - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; DEBC( if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) printk(ST_DEB_MSG @@ -2774,11 +2889,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon ioctl_result = st_int_ioctl(STp, MTBSF, 1); if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) { - int old_block_size = STp->block_size; STp->block_size = arg & MT_ST_BLKSIZE_MASK; if (STp->block_size != 0) { - if (old_block_size == 0) - normalize_buffer(STp->buffer); (STp->buffer)->buffer_blocks = (STp->buffer)->buffer_size / STp->block_size; } @@ -2797,8 +2909,8 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon else if (chg_eof) STps->eof = ST_NOEOF; - if (cmd_in == MTWEOF) - STps->rw = ST_IDLE; + if (cmd_in == MTWEOF || cmd_in == MTWEOFI) + STps->rw = ST_IDLE; /* prevent automatic WEOF at close */ } else { /* SCSI command was not completely successful. Don't return from this block without releasing the SCSI command block! */ struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat; @@ -2815,7 +2927,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon else undone = 0; - if (cmd_in == MTWEOF && + if ((cmd_in == MTWEOF || cmd_in == MTWEOFI) && cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) { if (cmdstatp->sense_hdr.sense_key == NO_SENSE || @@ -2879,7 +2991,7 @@ static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned lon !(STp->use_pf & PF_TESTED)) { /* Try the other possible state of Page Format if not already tried */ - STp->use_pf = !STp->use_pf | PF_TESTED; + STp->use_pf = (STp->use_pf ^ USE_PF) | PF_TESTED; st_release_request(SRpnt); SRpnt = NULL; return st_int_ioctl(STp, cmd_in, arg); @@ -2922,7 +3034,8 @@ static int get_location(struct scsi_tape *STp, unsigned int *block, int *partiti scmd[1] = 1; } SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE, - STp->device->timeout, MAX_READY_RETRIES, 1); + STp->device->request_queue->rq_timeout, + MAX_READY_RETRIES, 1); if (!SRpnt) return (STp->buffer)->syscall_result; @@ -3023,7 +3136,7 @@ static int set_location(struct scsi_tape *STp, unsigned int block, int partition } if (STp->immediate) { scmd[1] |= 1; /* Don't wait for completion */ - timeout = STp->device->timeout; + timeout = STp->device->request_queue->rq_timeout; } SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE, @@ -3241,7 +3354,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) * may try and take the device offline, in which case all further * access to the device is prohibited. */ - retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file); + retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, + file->f_flags & O_NDELAY); if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV) goto out; retval = 0; @@ -3545,8 +3659,8 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg) !capable(CAP_SYS_RAWIO)) i = -EPERM; else - i = scsi_cmd_ioctl(file, STp->disk->queue, - STp->disk, cmd_in, p); + i = scsi_cmd_ioctl(STp->disk->queue, STp->disk, + file->f_mode, cmd_in, p); if (i != -ENOTTY) return i; break; @@ -3582,41 +3696,37 @@ static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long a /* Try to allocate a new tape buffer. Calling function must not hold dev_arr_lock. */ -static struct st_buffer * - new_tape_buffer(int from_initialization, int need_dma, int max_sg) +static struct st_buffer *new_tape_buffer(int need_dma, int max_sg) { - int i, got = 0; - gfp_t priority; struct st_buffer *tb; - if (from_initialization) - priority = GFP_ATOMIC; - else - priority = GFP_KERNEL; - - i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) + - max_sg * sizeof(struct st_buf_fragment); - tb = kzalloc(i, priority); + tb = kzalloc(sizeof(struct st_buffer), GFP_ATOMIC); if (!tb) { printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n"); return NULL; } - tb->frp_segs = tb->orig_frp_segs = 0; + tb->frp_segs = 0; tb->use_sg = max_sg; - tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg); - tb->dma = need_dma; - tb->buffer_size = got; - sg_init_table(tb->sg, max_sg); + tb->buffer_size = 0; + + tb->reserved_pages = kzalloc(max_sg * sizeof(struct page *), + GFP_ATOMIC); + if (!tb->reserved_pages) { + kfree(tb); + return NULL; + } return tb; } /* Try to allocate enough space in the tape buffer */ +#define ST_MAX_ORDER 6 + static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma) { - int segs, nbr, max_segs, b_size, order, got; + int segs, max_segs, b_size, order, got; gfp_t priority; if (new_size <= STbuffer->buffer_size) @@ -3626,56 +3736,80 @@ static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dm normalize_buffer(STbuffer); /* Avoid extra segment */ max_segs = STbuffer->use_sg; - nbr = max_segs - STbuffer->frp_segs; - if (nbr <= 0) - return 0; priority = GFP_KERNEL | __GFP_NOWARN; if (need_dma) priority |= GFP_DMA; - for (b_size = PAGE_SIZE, order=0; order <= 6 && - b_size < new_size - STbuffer->buffer_size; - order++, b_size *= 2) - ; /* empty */ + + if (STbuffer->cleared) + priority |= __GFP_ZERO; + + if (STbuffer->frp_segs) { + order = STbuffer->reserved_page_order; + b_size = PAGE_SIZE << order; + } else { + for (b_size = PAGE_SIZE, order = 0; + order < ST_MAX_ORDER && + max_segs * (PAGE_SIZE << order) < new_size; + order++, b_size *= 2) + ; /* empty */ + STbuffer->reserved_page_order = order; + } + if (max_segs * (PAGE_SIZE << order) < new_size) { + if (order == ST_MAX_ORDER) + return 0; + normalize_buffer(STbuffer); + return enlarge_buffer(STbuffer, new_size, need_dma); + } for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size; segs < max_segs && got < new_size;) { - STbuffer->frp[segs].page = alloc_pages(priority, order); - if (STbuffer->frp[segs].page == NULL) { - if (new_size - got <= (max_segs - segs) * b_size / 2) { - b_size /= 2; /* Large enough for the rest of the buffers */ - order--; - continue; - } + struct page *page; + + page = alloc_pages(priority, order); + if (!page) { DEB(STbuffer->buffer_size = got); normalize_buffer(STbuffer); return 0; } - STbuffer->frp[segs].length = b_size; + STbuffer->frp_segs += 1; got += b_size; STbuffer->buffer_size = got; + STbuffer->reserved_pages[segs] = page; segs++; } - STbuffer->b_data = page_address(STbuffer->frp[0].page); + STbuffer->b_data = page_address(STbuffer->reserved_pages[0]); return 1; } +/* Make sure that no data from previous user is in the internal buffer */ +static void clear_buffer(struct st_buffer * st_bp) +{ + int i; + + for (i=0; i < st_bp->frp_segs; i++) + memset(page_address(st_bp->reserved_pages[i]), 0, + PAGE_SIZE << st_bp->reserved_page_order); + st_bp->cleared = 1; +} + + /* Release the extra buffer */ static void normalize_buffer(struct st_buffer * STbuffer) { - int i, order; + int i, order = STbuffer->reserved_page_order; - for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) { - order = get_order(STbuffer->frp[i].length); - __free_pages(STbuffer->frp[i].page, order); - STbuffer->buffer_size -= STbuffer->frp[i].length; + for (i = 0; i < STbuffer->frp_segs; i++) { + __free_pages(STbuffer->reserved_pages[i], order); + STbuffer->buffer_size -= (PAGE_SIZE << order); } - STbuffer->frp_segs = STbuffer->orig_frp_segs; - STbuffer->frp_sg_current = 0; + STbuffer->frp_segs = 0; STbuffer->sg_segs = 0; + STbuffer->reserved_page_order = 0; + STbuffer->map_data.offset = 0; } @@ -3684,18 +3818,19 @@ 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) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->reserved_page_order; for (i = 0, offset = st_bp->buffer_bytes; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: append_to_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_from_user(page_address(page) + offset, ubp, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3715,18 +3850,19 @@ static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, in static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count) { int i, cnt, res, offset; + int length = PAGE_SIZE << st_bp->reserved_page_order; for (i = 0, offset = st_bp->read_pointer; - i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++) - offset -= st_bp->frp[i].length; + i < st_bp->frp_segs && offset >= length; i++) + offset -= length; if (i == st_bp->frp_segs) { /* Should never happen */ printk(KERN_WARNING "st: from_buffer offset overflow.\n"); return (-EIO); } for (; i < st_bp->frp_segs && do_count > 0; i++) { - cnt = st_bp->frp[i].length - offset < do_count ? - st_bp->frp[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt); + struct page *page = st_bp->reserved_pages[i]; + cnt = length - offset < do_count ? length - offset : do_count; + res = copy_to_user(ubp, page_address(page) + offset, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -3747,6 +3883,7 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) { int src_seg, dst_seg, src_offset = 0, dst_offset; int count, total; + int length = PAGE_SIZE << st_bp->reserved_page_order; if (offset == 0) return; @@ -3754,24 +3891,26 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) total=st_bp->buffer_bytes - offset; for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) { src_offset = offset; - if (src_offset < st_bp->frp[src_seg].length) + if (src_offset < length) break; - offset -= st_bp->frp[src_seg].length; + offset -= length; } st_bp->buffer_bytes = st_bp->read_pointer = total; for (dst_seg=dst_offset=0; total > 0; ) { - count = min(st_bp->frp[dst_seg].length - dst_offset, - st_bp->frp[src_seg].length - src_offset); - memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset, - page_address(st_bp->frp[src_seg].page) + src_offset, count); + struct page *dpage = st_bp->reserved_pages[dst_seg]; + struct page *spage = st_bp->reserved_pages[src_seg]; + + count = min(length - dst_offset, length - src_offset); + memmove(page_address(dpage) + dst_offset, + page_address(spage) + src_offset, count); src_offset += count; - if (src_offset >= st_bp->frp[src_seg].length) { + if (src_offset >= length) { src_seg++; src_offset = 0; } dst_offset += count; - if (dst_offset >= st_bp->frp[dst_seg].length) { + if (dst_offset >= length) { dst_seg++; dst_offset = 0; } @@ -3779,32 +3918,6 @@ static void move_buffer_data(struct st_buffer * st_bp, int offset) } } - -/* Fill the s/g list up to the length required for this transfer */ -static void buf_to_sg(struct st_buffer *STbp, unsigned int length) -{ - int i; - unsigned int count; - struct scatterlist *sg; - struct st_buf_fragment *frp; - - if (length == STbp->frp_sg_current) - return; /* work already done */ - - sg = &(STbp->sg[0]); - frp = STbp->frp; - for (i=count=0; count < length; i++) { - if (length - count > frp[i].length) - sg_set_page(&sg[i], frp[i].page, frp[i].length, 0); - else - sg_set_page(&sg[i], frp[i].page, length - count, 0); - count += sg[i].length; - } - STbp->sg_segs = i; - STbp->frp_sg_current = length; -} - - /* Validate the options from command line or module parameters */ static void validate_options(void) { @@ -3873,18 +3986,101 @@ static const struct file_operations st_fops = .open = st_open, .flush = st_flush, .release = st_release, + .llseek = noop_llseek, }; +static int create_one_cdev(struct scsi_tape *tape, int mode, int rew) +{ + int i, error; + dev_t cdev_devno; + struct cdev *cdev; + struct device *dev; + struct st_modedef *STm = &(tape->modes[mode]); + char name[10]; + int dev_num = tape->index; + + cdev_devno = MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, rew)); + + cdev = cdev_alloc(); + if (!cdev) { + pr_err("st%d: out of memory. Device not attached.\n", dev_num); + error = -ENOMEM; + goto out; + } + cdev->owner = THIS_MODULE; + cdev->ops = &st_fops; + + error = cdev_add(cdev, cdev_devno, 1); + if (error) { + pr_err("st%d: Can't add %s-rewind mode %d\n", dev_num, + rew ? "non" : "auto", mode); + pr_err("st%d: Device not attached.\n", dev_num); + goto out_free; + } + STm->cdevs[rew] = cdev; + + i = mode << (4 - ST_NBR_MODE_BITS); + snprintf(name, 10, "%s%s%s", rew ? "n" : "", + tape->disk->disk_name, st_formats[i]); + + dev = device_create(&st_sysfs_class, &tape->device->sdev_gendev, + cdev_devno, &tape->modes[mode], "%s", name); + if (IS_ERR(dev)) { + pr_err("st%d: device_create failed\n", dev_num); + error = PTR_ERR(dev); + goto out_free; + } + + STm->devs[rew] = dev; + + return 0; +out_free: + cdev_del(STm->cdevs[rew]); + STm->cdevs[rew] = NULL; +out: + return error; +} + +static int create_cdevs(struct scsi_tape *tape) +{ + int mode, error; + for (mode = 0; mode < ST_NBR_MODES; ++mode) { + error = create_one_cdev(tape, mode, 0); + if (error) + return error; + error = create_one_cdev(tape, mode, 1); + if (error) + return error; + } + + return sysfs_create_link(&tape->device->sdev_gendev.kobj, + &tape->modes[0].devs[0]->kobj, "tape"); +} + +static void remove_cdevs(struct scsi_tape *tape) +{ + int mode, rew; + sysfs_remove_link(&tape->device->sdev_gendev.kobj, "tape"); + for (mode = 0; mode < ST_NBR_MODES; mode++) { + struct st_modedef *STm = &(tape->modes[mode]); + for (rew = 0; rew < 2; rew++) { + if (STm->cdevs[rew]) + cdev_del(STm->cdevs[rew]); + if (STm->devs[rew]) + device_unregister(STm->devs[rew]); + } + } +} + static int st_probe(struct device *dev) { struct scsi_device *SDp = to_scsi_device(dev); struct gendisk *disk = NULL; - struct cdev *cdev = NULL; struct scsi_tape *tpnt = NULL; struct st_modedef *STm; struct st_partstat *STps; struct st_buffer *buffer; - int i, j, mode, dev_num, error; + int i, error; char *stp; if (SDp->type != TYPE_TAPE) @@ -3895,11 +4091,10 @@ static int st_probe(struct device *dev) return -ENODEV; } - i = min(SDp->request_queue->max_hw_segments, - SDp->request_queue->max_phys_segments); + i = queue_max_segments(SDp->request_queue); if (st_max_sg_segs < i) i = st_max_sg_segs; - buffer = new_tape_buffer(1, (SDp->host)->unchecked_isa_dma, i); + buffer = new_tape_buffer((SDp->host)->unchecked_isa_dma, i); if (buffer == NULL) { printk(KERN_ERR "st: Can't allocate new tape buffer. Device not attached.\n"); @@ -3912,58 +4107,20 @@ static int st_probe(struct device *dev) goto out_buffer_free; } - write_lock(&st_dev_arr_lock); - if (st_nr_dev >= st_dev_max) { - struct scsi_tape **tmp_da; - int tmp_dev_max; - - 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) { - write_unlock(&st_dev_arr_lock); - printk(KERN_ERR "st: Too many tape devices (max. %d).\n", - ST_MAX_TAPES); - goto out_put_disk; - } - - tmp_da = kzalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC); - if (tmp_da == NULL) { - write_unlock(&st_dev_arr_lock); - printk(KERN_ERR "st: Can't extend device array.\n"); - goto out_put_disk; - } - - if (scsi_tapes != NULL) { - memcpy(tmp_da, scsi_tapes, - st_dev_max * sizeof(struct scsi_tape *)); - kfree(scsi_tapes); - } - scsi_tapes = tmp_da; - - st_dev_max = tmp_dev_max; - } - - for (i = 0; i < st_dev_max; i++) - if (scsi_tapes[i] == NULL) - break; - if (i >= st_dev_max) - panic("scsi_devices corrupt (st)"); - tpnt = kzalloc(sizeof(struct scsi_tape), GFP_ATOMIC); if (tpnt == NULL) { - write_unlock(&st_dev_arr_lock); printk(KERN_ERR "st: Can't allocate device descriptor.\n"); goto out_put_disk; } kref_init(&tpnt->kref); tpnt->disk = disk; - sprintf(disk->disk_name, "st%d", i); disk->private_data = &tpnt->driver; disk->queue = SDp->request_queue; + /* SCSI tape doesn't register this gendisk via add_disk(). Manually + * take queue reference that release_disk() expects. */ + if (!blk_get_queue(disk->queue)) + goto out_put_disk; tpnt->driver = &st_template; - scsi_tapes[i] = tpnt; - dev_num = i; tpnt->device = SDp; if (SDp->scsi_level <= 2) @@ -3987,12 +4144,14 @@ static int st_probe(struct device *dev) 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; /* No forced buffering */ tpnt->partition = 0; tpnt->new_partition = 0; tpnt->nbr_partitions = 0; - tpnt->device->timeout = ST_TIMEOUT; + blk_queue_rq_timeout(tpnt->device->request_queue, ST_TIMEOUT); tpnt->long_timeout = ST_LONG_TIMEOUT; tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma; @@ -4007,6 +4166,7 @@ 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 */ + STm->tape = tpnt; } for (i = 0; i < ST_NBR_PARTITIONS; i++) { @@ -4026,38 +4186,25 @@ static int st_probe(struct device *dev) tpnt->blksize_changed = 0; mutex_init(&tpnt->lock); - st_nr_dev++; - write_unlock(&st_dev_arr_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_put_queue; + } + tpnt->index = error; + sprintf(disk->disk_name, "st%d", tpnt->index); - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - STm = &(tpnt->modes[mode]); - for (j=0; j < 2; j++) { - cdev = cdev_alloc(); - if (!cdev) { - printk(KERN_ERR - "st%d: out of memory. Device not attached.\n", - dev_num); - goto out_free_tape; - } - cdev->owner = THIS_MODULE; - cdev->ops = &st_fops; - - error = cdev_add(cdev, - MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, j)), - 1); - if (error) { - printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n", - dev_num, j ? "non" : "auto", mode); - printk(KERN_ERR "st%d: Device not attached.\n", dev_num); - goto out_free_tape; - } - STm->cdevs[j] = cdev; + dev_set_drvdata(dev, tpnt); - } - error = do_create_class_files(tpnt, dev_num, mode); - if (error) - goto out_free_tape; - } + + 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", tape_name(tpnt)); @@ -4067,28 +4214,13 @@ static int st_probe(struct device *dev) return 0; -out_free_tape: - for (mode=0; mode < ST_NBR_MODES; mode++) { - STm = &(tpnt->modes[mode]); - sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, - "tape"); - for (j=0; j < 2; j++) { - if (STm->cdevs[j]) { - if (cdev == STm->cdevs[j]) - cdev = NULL; - class_device_destroy(st_sysfs_class, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); - cdev_del(STm->cdevs[j]); - } - } - } - if (cdev) - cdev_del(cdev); - write_lock(&st_dev_arr_lock); - scsi_tapes[dev_num] = NULL; - st_nr_dev--; - write_unlock(&st_dev_arr_lock); +out_remove_devs: + remove_cdevs(tpnt); + spin_lock(&st_index_lock); + idr_remove(&st_index_idr, tpnt->index); + spin_unlock(&st_index_lock); +out_put_queue: + blk_put_queue(disk->queue); out_put_disk: put_disk(disk); kfree(tpnt); @@ -4101,37 +4233,18 @@ out: static int st_remove(struct device *dev) { - struct scsi_device *SDp = to_scsi_device(dev); - struct scsi_tape *tpnt; - int i, j, mode; - - write_lock(&st_dev_arr_lock); - for (i = 0; i < st_dev_max; i++) { - tpnt = scsi_tapes[i]; - if (tpnt != NULL && tpnt->device == SDp) { - scsi_tapes[i] = NULL; - st_nr_dev--; - write_unlock(&st_dev_arr_lock); - sysfs_remove_link(&tpnt->device->sdev_gendev.kobj, - "tape"); - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - for (j=0; j < 2; j++) { - class_device_destroy(st_sysfs_class, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(i, mode, j))); - cdev_del(tpnt->modes[mode].cdevs[j]); - tpnt->modes[mode].cdevs[j] = NULL; - } - } + struct scsi_tape *tpnt = dev_get_drvdata(dev); + int index = tpnt->index; - mutex_lock(&st_ref_mutex); - kref_put(&tpnt->kref, scsi_tape_release); - mutex_unlock(&st_ref_mutex); - return 0; - } - } + scsi_autopm_get_device(to_scsi_device(dev)); + remove_cdevs(tpnt); - write_unlock(&st_dev_arr_lock); + mutex_lock(&st_ref_mutex); + kref_put(&tpnt->kref, scsi_tape_release); + mutex_unlock(&st_ref_mutex); + spin_lock(&st_index_lock); + idr_remove(&st_index_idr, index); + spin_unlock(&st_index_lock); return 0; } @@ -4152,8 +4265,8 @@ static void scsi_tape_release(struct kref *kref) tpnt->device = NULL; if (tpnt->buffer) { - tpnt->buffer->orig_frp_segs = 0; normalize_buffer(tpnt->buffer); + kfree(tpnt->buffer->reserved_pages); kfree(tpnt->buffer); } @@ -4163,6 +4276,11 @@ static void scsi_tape_release(struct kref *kref) return; } +static struct class st_sysfs_class = { + .name = "scsi_tape", + .dev_groups = st_dev_groups, +}; + static int __init init_st(void) { int err; @@ -4172,10 +4290,10 @@ static int __init init_st(void) 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)) { - printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n"); - return PTR_ERR(st_sysfs_class); + err = class_register(&st_sysfs_class); + if (err) { + pr_err("Unable register sysfs class for SCSI tapes\n"); + return err; } err = register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), @@ -4202,7 +4320,7 @@ err_chrdev: unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); err_class: - class_destroy(st_sysfs_class); + class_unregister(&st_sysfs_class); return err; } @@ -4212,8 +4330,7 @@ static void __exit exit_st(void) scsi_unregister_driver(&st_template.gendrv); unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0), ST_MAX_TAPE_ENTRIES); - class_destroy(st_sysfs_class); - kfree(scsi_tapes); + class_unregister(&st_sysfs_class); printk(KERN_INFO "st: Unloaded.\n"); } @@ -4285,33 +4402,35 @@ static void do_remove_sysfs_files(void) driver_remove_file(sysfs, &driver_attr_try_direct_io); } - /* The sysfs simple class interface */ -static ssize_t st_defined_show(struct class_device *class_dev, char *buf) +static ssize_t +defined_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct st_modedef *STm = dev_get_drvdata(dev); ssize_t l = 0; l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined); return l; } +static DEVICE_ATTR_RO(defined); -CLASS_DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL); - -static ssize_t st_defblk_show(struct class_device *class_dev, char *buf) +static ssize_t +default_blksize_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct st_modedef *STm = dev_get_drvdata(dev); ssize_t l = 0; l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize); return l; } +static DEVICE_ATTR_RO(default_blksize); -CLASS_DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL); - -static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf) +static ssize_t +default_density_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct st_modedef *STm = dev_get_drvdata(dev); ssize_t l = 0; char *fmt; @@ -4319,86 +4438,70 @@ static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf) l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density); return l; } +static DEVICE_ATTR_RO(default_density); -CLASS_DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL); - -static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf) +static ssize_t +default_compression_show(struct device *dev, struct device_attribute *attr, + char *buf) { - struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev); + struct st_modedef *STm = dev_get_drvdata(dev); ssize_t l = 0; l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1); return l; } +static DEVICE_ATTR_RO(default_compression); -CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL); - -static int do_create_class_files(struct scsi_tape *STp, int dev_num, int mode) +static ssize_t +options_show(struct device *dev, struct device_attribute *attr, char *buf) { - int i, rew, error; - char name[10]; - struct class_device *st_class_member; - - for (rew=0; rew < 2; rew++) { - /* Make sure that the minor numbers corresponding to the four - first modes always get the same names */ - i = mode << (4 - ST_NBR_MODE_BITS); - snprintf(name, 10, "%s%s%s", rew ? "n" : "", - STp->disk->disk_name, st_formats[i]); - st_class_member = - class_device_create(st_sysfs_class, NULL, - MKDEV(SCSI_TAPE_MAJOR, - TAPE_MINOR(dev_num, mode, rew)), - &STp->device->sdev_gendev, "%s", name); - 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]); - - 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, - "tape"); - if (error) { - printk(KERN_ERR - "st%d: Can't create sysfs link from SCSI device.\n", - dev_num); - goto out; - } - } - } - - return 0; + struct st_modedef *STm = dev_get_drvdata(dev); + struct scsi_tape *STp = STm->tape; + int options; + ssize_t l = 0; -out: - return error; + options = STm->do_buffer_writes ? MT_ST_BUFFER_WRITES : 0; + options |= STm->do_async_writes ? MT_ST_ASYNC_WRITES : 0; + options |= STm->do_read_ahead ? MT_ST_READ_AHEAD : 0; + DEB( options |= debugging ? MT_ST_DEBUGGING : 0 ); + options |= STp->two_fm ? MT_ST_TWO_FM : 0; + options |= STp->fast_mteom ? MT_ST_FAST_MTEOM : 0; + options |= STm->defaults_for_writes ? MT_ST_DEF_WRITES : 0; + options |= STp->can_bsr ? MT_ST_CAN_BSR : 0; + options |= STp->omit_blklims ? MT_ST_NO_BLKLIMS : 0; + options |= STp->can_partitions ? MT_ST_CAN_PARTITIONS : 0; + options |= STp->scsi2_logical ? MT_ST_SCSI2LOGICAL : 0; + options |= STm->sysv ? MT_ST_SYSV : 0; + options |= STp->immediate ? MT_ST_NOWAIT : 0; + options |= STp->immediate_filemark ? MT_ST_NOWAIT_EOF : 0; + options |= STp->sili ? MT_ST_SILI : 0; + + l = snprintf(buf, PAGE_SIZE, "0x%08x\n", options); + return l; } +static DEVICE_ATTR_RO(options); + +static struct attribute *st_dev_attrs[] = { + &dev_attr_defined.attr, + &dev_attr_default_blksize.attr, + &dev_attr_default_density.attr, + &dev_attr_default_compression.attr, + &dev_attr_options.attr, + NULL, +}; +ATTRIBUTE_GROUPS(st_dev); /* The following functions may be useful for a larger audience. */ -static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, - unsigned long uaddr, size_t count, int rw) +static int sgl_map_user_pages(struct st_buffer *STbp, + const unsigned int max_pages, unsigned long uaddr, + size_t count, int rw) { unsigned long end = (uaddr + count + PAGE_SIZE - 1) >> PAGE_SHIFT; unsigned long start = uaddr >> PAGE_SHIFT; const int nr_pages = end - start; int res, i, j; struct page **pages; + struct rq_map_data *mdata = &STbp->map_data; /* User attempted Overflow! */ if ((uaddr + count) < uaddr) @@ -4440,24 +4543,10 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa flush_dcache_page(pages[i]); } - /* Populate the scatter/gather list */ - sg_set_page(&sgl[0], pages[0], 0, uaddr & ~PAGE_MASK); - if (nr_pages > 1) { - sgl[0].length = PAGE_SIZE - sgl[0].offset; - count -= sgl[0].length; - for (i=1; i < nr_pages ; i++) { - sg_set_page(&sgl[i], pages[i], - count < PAGE_SIZE ? count : PAGE_SIZE, 0);; - count -= PAGE_SIZE; - } - } - else { - sgl[0].length = count; - } + mdata->offset = uaddr & ~PAGE_MASK; + STbp->mapped_pages = pages; - kfree(pages); return nr_pages; - out_unmap: if (res > 0) { for (j=0; j < res; j++) @@ -4470,13 +4559,13 @@ static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pa /* And unmap them... */ -static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages, - int dirtied) +static int sgl_unmap_user_pages(struct st_buffer *STbp, + const unsigned int nr_pages, int dirtied) { int i; for (i=0; i < nr_pages; i++) { - struct page *page = sg_page(&sgl[i]); + struct page *page = STbp->mapped_pages[i]; if (dirtied) SetPageDirty(page); @@ -4485,6 +4574,8 @@ static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_p */ page_cache_release(page); } + kfree(STbp->mapped_pages); + STbp->mapped_pages = NULL; return 0; } |
