diff options
Diffstat (limited to 'drivers/scsi/osst.c')
| -rw-r--r-- | drivers/scsi/osst.c | 427 |
1 files changed, 287 insertions, 140 deletions
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index 66ea47a9c53..0727ea7cc38 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -38,6 +38,7 @@ static const char * osst_version = "0.99.4"; #include <linux/sched.h> #include <linux/proc_fs.h> #include <linux/mm.h> +#include <linux/slab.h> #include <linux/init.h> #include <linux/string.h> #include <linux/errno.h> @@ -49,9 +50,10 @@ static const char * osst_version = "0.99.4"; #include <linux/blkdev.h> #include <linux/moduleparam.h> #include <linux/delay.h> +#include <linux/jiffies.h> +#include <linux/mutex.h> #include <asm/uaccess.h> #include <asm/dma.h> -#include <asm/system.h> /* The driver prints some debugging information on the console if DEBUG is defined and non-zero. */ @@ -77,6 +79,7 @@ static const char * osst_version = "0.99.4"; #include "osst_options.h" #include "osst_detect.h" +static DEFINE_MUTEX(osst_int_mutex); static int max_dev = 0; static int write_threshold_kbs = 0; static int max_sg_segs = 0; @@ -86,6 +89,7 @@ MODULE_AUTHOR("Willem Riede"); MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); +MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); module_param(max_dev, int, 0444); MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); @@ -277,8 +281,8 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) static int notyetprinted = 1; printk(KERN_WARNING - "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n", - name, result, suggestion(result), driver_byte(result) & DRIVER_MASK, + "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", + name, result, driver_byte(result), host_byte(result)); if (notyetprinted) { notyetprinted = 0; @@ -314,18 +318,25 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) /* Wakeup from interrupt */ -static void osst_sleep_done(void *data, char *sense, int result, int resid) +static void osst_end_async(struct request *req, int update) { - struct osst_request *SRpnt = data; + struct osst_request *SRpnt = req->end_io_data; struct osst_tape *STp = SRpnt->stp; + struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; - memcpy(SRpnt->sense, sense, SCSI_SENSE_BUFFERSIZE); - STp->buffer->cmdstat.midlevel_result = SRpnt->result = result; + STp->buffer->cmdstat.midlevel_result = SRpnt->result = req->errors; #if DEBUG STp->write_pending = 0; #endif if (SRpnt->waiting) complete(SRpnt->waiting); + + if (SRpnt->bio) { + kfree(mdata->pages); + blk_rq_unmap_user(SRpnt->bio); + } + + __blk_put_request(req->q, req); } /* osst_request memory management */ @@ -339,6 +350,74 @@ static void osst_release_request(struct osst_request *streq) kfree(streq); } +static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, + int cmd_len, int data_direction, void *buffer, unsigned bufflen, + int use_sg, int timeout, int retries) +{ + struct request *req; + struct page **pages = NULL; + 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; + + SRpnt->bio = NULL; + + if (use_sg) { + struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; + int i; + + pages = kzalloc(use_sg * sizeof(struct page *), GFP_KERNEL); + if (!pages) + goto free_req; + + for_each_sg(sgl, sg, use_sg, i) + pages[i] = sg_page(sg); + + mdata->null_mapped = 1; + + mdata->page_order = get_order(sgl[0].length); + mdata->nr_entries = + DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); + mdata->offset = 0; + + err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); + if (err) { + kfree(pages); + goto free_req; + } + SRpnt->bio = req->bio; + mdata->pages = pages; + + } else if (bufflen) { + err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); + if (err) + goto free_req; + } + + req->cmd_len = cmd_len; + memset(req->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after 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, osst_end_async); + return 0; +free_req: + blk_put_request(req); + return DRIVER_ERROR << 24; +} + /* Do the scsi command. Waits until command performed if do_wait is true. Otherwise osst_write_behind_check() is used to check that the command has finished. */ @@ -400,8 +479,8 @@ static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct oss STp->buffer->cmdstat.have_sense = 0; STp->buffer->syscall_result = 0; - if (scsi_execute_async(STp->device, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, - use_sg, timeout, retries, SRpnt, osst_sleep_done, GFP_KERNEL)) + if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, + use_sg, timeout, retries)) /* could not allocate the buffer or request was too large */ (STp->buffer)->syscall_result = (-EBUSY); else if (do_wait) { @@ -520,10 +599,10 @@ static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_ break; default: ; /* probably FILL */ } - aux->filemark_cnt = ntohl(STp->filemark_cnt); - aux->phys_fm = ntohl(0xffffffff); - aux->last_mark_ppos = ntohl(STp->last_mark_ppos); - aux->last_mark_lbn = ntohl(STp->last_mark_lbn); + aux->filemark_cnt = htonl(STp->filemark_cnt); + aux->phys_fm = htonl(0xffffffff); + aux->last_mark_ppos = htonl(STp->last_mark_ppos); + aux->last_mark_lbn = htonl(STp->last_mark_lbn); } /* @@ -540,7 +619,7 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q if (STp->raw) { if (STp->buffer->syscall_result) { for (i=0; i < STp->buffer->sg_segs; i++) - memset(page_address(STp->buffer->sg[i].page), + memset(page_address(sg_page(&STp->buffer->sg[i])), 0, STp->buffer->sg[i].length); strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); } else @@ -591,10 +670,11 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q if (aux->frame_type != OS_FRAME_TYPE_DATA && aux->frame_type != OS_FRAME_TYPE_EOD && aux->frame_type != OS_FRAME_TYPE_MARKER) { - if (!quiet) + if (!quiet) { #if DEBUG printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); #endif + } goto err_out; } if (aux->frame_type == OS_FRAME_TYPE_EOD && @@ -604,11 +684,12 @@ static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int q goto err_out; } if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { - if (!quiet) + if (!quiet) { #if DEBUG printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", name, ntohl(aux->frame_seq_num), frame_seq_number); #endif + } goto err_out; } if (aux->frame_type == OS_FRAME_TYPE_MARKER) { @@ -856,7 +937,7 @@ static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt ) && result >= 0) { #if DEBUG - if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC) + if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC)) printk (OSST_DEB_MSG "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", name, curr, curr+minlast, STp->first_frame_position, @@ -867,7 +948,7 @@ static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt return 0; } #if DEBUG - if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted) + if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted) { printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", name, curr, curr+minlast, STp->first_frame_position, @@ -1284,7 +1365,7 @@ error: /* The values below are based on the OnStream frame payload size of 32K == 2**15, * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions - * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. + * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. */ #define OSST_FRAME_SHIFT 6 #define OSST_SECTOR_SHIFT 9 @@ -1402,7 +1483,7 @@ static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst int dbg = debugging; #endif - if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) + if ((buffer = vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL) return (-EIO); printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", @@ -2214,7 +2295,7 @@ static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRp if (STp->raw) return 0; if (STp->header_cache == NULL) { - if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { + if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); return (-ENOMEM); } @@ -2402,7 +2483,7 @@ static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** name, ppos, update_frame_cntr); #endif if (STp->header_cache == NULL) { - if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) { + if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); return 0; } @@ -3049,7 +3130,7 @@ static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** } #if DEBUG if (debugging) - printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n", + printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", name, offset, transfer, blks); #endif @@ -3296,7 +3377,7 @@ static ssize_t osst_write(struct file * filp, const char __user * buf, size_t co char * name = tape_name(STp); - if (down_interruptible(&STp->lock)) + if (mutex_lock_interruptible(&STp->lock)) return (-ERESTARTSYS); /* @@ -3506,7 +3587,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name if (i == (-ENOSPC)) { transfer = STp->buffer->writing; /* FIXME -- check this logic */ if (transfer <= do_count) { - filp->f_pos += do_count - transfer; + *ppos += do_count - transfer; count -= do_count - transfer; if (STps->drv_block >= 0) { STps->drv_block += (do_count - transfer) / STp->block_size; @@ -3544,7 +3625,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name goto out; } - filp->f_pos += do_count; + *ppos += do_count; b_point += do_count; count -= do_count; if (STps->drv_block >= 0) { @@ -3566,7 +3647,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name if (STps->drv_block >= 0) { STps->drv_block += blks; } - filp->f_pos += count; + *ppos += count; count = 0; } @@ -3598,7 +3679,7 @@ if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name out: if (SRpnt != NULL) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -3617,7 +3698,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo char * name = tape_name(STp); - if (down_interruptible(&STp->lock)) + if (mutex_lock_interruptible(&STp->lock)) return (-ERESTARTSYS); /* @@ -3729,7 +3810,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo if (transfer == 0) { printk(KERN_WARNING - "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n", + "%s:W: Nothing can be transferred, requested %Zd, tape block size (%d%c).\n", name, count, STp->block_size < 1024? STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); @@ -3742,7 +3823,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo } STp->logical_blk_num += transfer / STp->block_size; STps->drv_block += transfer / STp->block_size; - filp->f_pos += transfer; + *ppos += transfer; buf += transfer; total += transfer; } @@ -3783,7 +3864,7 @@ static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, lo out: if (SRpnt != NULL) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -4355,7 +4436,7 @@ os_bypass: /* Open the device */ -static int os_scsi_tape_open(struct inode * inode, struct file * filp) +static int __os_scsi_tape_open(struct inode * inode, struct file * filp) { unsigned short flags; int i, b_size, new_session = 0, retval = 0; @@ -4435,7 +4516,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) for (i = 0, b_size = 0; (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); b_size += STp->buffer->sg[i++].length); - STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size); + STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size); #if DEBUG printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); @@ -4616,12 +4697,14 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) break; if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { + int j; + STp->pos_unknown = 0; STp->partition = STp->new_partition = 0; if (STp->can_partitions) STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ - for (i=0; i < ST_NBR_PARTITIONS; i++) { - STps = &(STp->ps[i]); + for (j = 0; j < ST_NBR_PARTITIONS; j++) { + STps = &(STp->ps[j]); STps->rw = ST_IDLE; STps->eof = ST_NOEOF; STps->at_sm = 0; @@ -4721,9 +4804,21 @@ err_out: return retval; } +/* BKL pushdown: spaghetti avoidance wrapper */ +static int os_scsi_tape_open(struct inode * inode, struct file * filp) +{ + int ret; + + mutex_lock(&osst_int_mutex); + ret = __os_scsi_tape_open(inode, filp); + mutex_unlock(&osst_int_mutex); + return ret; +} + + /* Flush the tape buffer before close */ -static int os_scsi_tape_flush(struct file * filp) +static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) { int result = 0, result2; struct osst_tape * STp = filp->private_data; @@ -4839,11 +4934,10 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) /* The ioctl command */ -static int osst_ioctl(struct inode * inode,struct file * file, +static long osst_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg) { - int i, cmd_nr, cmd_type, retval = 0; - unsigned int blk; + int i, cmd_nr, cmd_type, blk, retval = 0; struct st_modedef * STm; struct st_partstat * STps; struct osst_request * SRpnt = NULL; @@ -4851,8 +4945,11 @@ static int osst_ioctl(struct inode * inode,struct file * file, char * name = tape_name(STp); void __user * p = (void __user *)arg; - if (down_interruptible(&STp->lock)) + mutex_lock(&osst_int_mutex); + if (mutex_lock_interruptible(&STp->lock)) { + mutex_unlock(&osst_int_mutex); return -ERESTARTSYS; + } #if DEBUG if (debugging && !STp->in_use) { @@ -5162,14 +5259,17 @@ static int osst_ioctl(struct inode * inode,struct file * file, } if (SRpnt) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); - return scsi_ioctl(STp->device, cmd_in, p); + retval = scsi_ioctl(STp->device, cmd_in, p); + mutex_unlock(&osst_int_mutex); + return retval; out: if (SRpnt) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); + mutex_unlock(&osst_int_mutex); return retval; } @@ -5206,12 +5306,12 @@ static struct osst_buffer * new_tape_buffer( int from_initialization, int need_d priority = GFP_KERNEL; i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); - tb = (struct osst_buffer *)kmalloc(i, priority); + tb = kzalloc(i, priority); if (!tb) { printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); return NULL; } - memset(tb, 0, i); + tb->sg_segs = tb->orig_sg_segs = 0; tb->use_sg = max_sg; tb->in_use = 1; @@ -5251,30 +5351,25 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) /* Try to allocate the first segment up to OS_DATA_SIZE and the others big enough to reach the goal (code assumes no segments in place) */ for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) { - STbuffer->sg[0].page = alloc_pages(priority, order); + struct page *page = alloc_pages(priority, order); + STbuffer->sg[0].offset = 0; - if (STbuffer->sg[0].page != NULL) { - STbuffer->sg[0].length = b_size; - STbuffer->b_data = page_address(STbuffer->sg[0].page); + if (page != NULL) { + sg_set_page(&STbuffer->sg[0], page, b_size, 0); + STbuffer->b_data = page_address(page); break; } } - if (STbuffer->sg[0].page == NULL) { + if (sg_page(&STbuffer->sg[0]) == NULL) { printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n"); return 0; } /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */ for (segs=STbuffer->sg_segs=1, got=b_size; segs < max_segs && got < OS_FRAME_SIZE; ) { - STbuffer->sg[segs].page = - alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); + struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); STbuffer->sg[segs].offset = 0; - if (STbuffer->sg[segs].page == NULL) { - if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) { - b_size /= 2; /* Large enough for the rest of the buffers */ - order--; - continue; - } + if (page == NULL) { printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", OS_FRAME_SIZE); #if DEBUG @@ -5283,7 +5378,7 @@ static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) normalize_buffer(STbuffer); return 0; } - STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size; + sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0); got += STbuffer->sg[segs].length; STbuffer->buffer_size = got; STbuffer->sg_segs = ++segs; @@ -5315,7 +5410,7 @@ static void normalize_buffer(struct osst_buffer *STbuffer) b_size < STbuffer->sg[i].length; b_size *= 2, order++); - __free_pages(STbuffer->sg[i].page, order); + __free_pages(sg_page(&STbuffer->sg[i]), order); STbuffer->buffer_size -= STbuffer->sg[i].length; } #if DEBUG @@ -5343,7 +5438,7 @@ static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, i for ( ; i < st_bp->sg_segs && do_count > 0; i++) { cnt = st_bp->sg[i].length - offset < do_count ? st_bp->sg[i].length - offset : do_count; - res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt); + res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -5376,7 +5471,7 @@ static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count for ( ; i < st_bp->sg_segs && do_count > 0; i++) { cnt = st_bp->sg[i].length - offset < do_count ? st_bp->sg[i].length - offset : do_count; - res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt); + res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt); if (res) return (-EFAULT); do_count -= cnt; @@ -5409,7 +5504,7 @@ static int osst_zero_buffer_tail(struct osst_buffer *st_bp) i < st_bp->sg_segs && do_count > 0; i++) { cnt = st_bp->sg[i].length - offset < do_count ? st_bp->sg[i].length - offset : do_count ; - memset(page_address(st_bp->sg[i].page) + offset, 0, cnt); + memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt); do_count -= cnt; offset = 0; } @@ -5429,7 +5524,7 @@ static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr) for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { cnt = st_bp->sg[i].length < do_count ? st_bp->sg[i].length : do_count ; - memcpy(page_address(st_bp->sg[i].page), ptr, cnt); + memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt); do_count -= cnt; ptr += cnt; } @@ -5450,7 +5545,7 @@ static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr) for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { cnt = st_bp->sg[i].length < do_count ? st_bp->sg[i].length : do_count ; - memcpy(ptr, page_address(st_bp->sg[i].page), cnt); + memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt); do_count -= cnt; ptr += cnt; } @@ -5491,7 +5586,7 @@ static int __init osst_setup (char *str) char *stp; stp = get_options(str, ARRAY_SIZE(ints), ints); - + if (ints[0] > 0) { for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) *parms[i].val = ints[i + 1]; @@ -5506,7 +5601,7 @@ static int __init osst_setup (char *str) break; } } - if (i >= sizeof(parms) / sizeof(struct osst_dev_parm)) + if (i >= ARRAY_SIZE(parms)) printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n", stp); stp = strchr(stp, ','); @@ -5522,17 +5617,18 @@ __setup("osst=", osst_setup); #endif -static struct file_operations osst_fops = { +static const struct file_operations osst_fops = { .owner = THIS_MODULE, .read = osst_read, .write = osst_write, - .ioctl = osst_ioctl, + .unlocked_ioctl = osst_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = osst_compat_ioctl, #endif .open = os_scsi_tape_open, .flush = os_scsi_tape_flush, .release = os_scsi_tape_close, + .llseek = noop_llseek, }; static int osst_supports(struct scsi_device * SDp) @@ -5574,23 +5670,24 @@ static ssize_t osst_version_show(struct device_driver *ddd, char *buf) static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL); -static void osst_create_driverfs_files(struct device_driver *driverfs) +static int osst_create_sysfs_files(struct device_driver *sysfs) { - driver_create_file(driverfs, &driver_attr_version); + return driver_create_file(sysfs, &driver_attr_version); } -static void osst_remove_driverfs_files(struct device_driver *driverfs) +static void osst_remove_sysfs_files(struct device_driver *sysfs) { - driver_remove_file(driverfs, &driver_attr_version); + driver_remove_file(sysfs, &driver_attr_version); } /* * sysfs support for accessing ADR header information */ -static ssize_t osst_adr_rev_show(struct class_device *class_dev, char *buf) +static ssize_t osst_adr_rev_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5598,11 +5695,13 @@ static ssize_t osst_adr_rev_show(struct class_device *class_dev, char *buf) return l; } -CLASS_DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); +DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); -static ssize_t osst_linux_media_version_show(struct class_device *class_dev, char *buf) +static ssize_t osst_linux_media_version_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5610,11 +5709,12 @@ static ssize_t osst_linux_media_version_show(struct class_device *class_dev, cha return l; } -CLASS_DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); +DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); -static ssize_t osst_capacity_show(struct class_device *class_dev, char *buf) +static ssize_t osst_capacity_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5622,11 +5722,13 @@ static ssize_t osst_capacity_show(struct class_device *class_dev, char *buf) return l; } -CLASS_DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); +DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); -static ssize_t osst_first_data_ppos_show(struct class_device *class_dev, char *buf) +static ssize_t osst_first_data_ppos_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5634,11 +5736,13 @@ static ssize_t osst_first_data_ppos_show(struct class_device *class_dev, char *b return l; } -CLASS_DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); +DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); -static ssize_t osst_eod_frame_ppos_show(struct class_device *class_dev, char *buf) +static ssize_t osst_eod_frame_ppos_show(struct device *dev, + struct device_attribute *attr, + char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5646,11 +5750,12 @@ static ssize_t osst_eod_frame_ppos_show(struct class_device *class_dev, char *bu return l; } -CLASS_DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); +DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); -static ssize_t osst_filemark_cnt_show(struct class_device *class_dev, char *buf) +static ssize_t osst_filemark_cnt_show(struct device *dev, + struct device_attribute *attr, char *buf) { - struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev); + struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); ssize_t l = 0; if (STp && STp->header_ok && STp->linux_media) @@ -5658,54 +5763,67 @@ static ssize_t osst_filemark_cnt_show(struct class_device *class_dev, char *buf) return l; } -CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); +DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); static struct class *osst_sysfs_class; -static int osst_sysfs_valid = 0; - -static void osst_sysfs_init(void) +static int osst_sysfs_init(void) { osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); - if ( IS_ERR(osst_sysfs_class) ) - printk(KERN_WARNING "osst :W: Unable to register sysfs class\n"); - else - osst_sysfs_valid = 1; + if (IS_ERR(osst_sysfs_class)) { + printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); + return PTR_ERR(osst_sysfs_class); + } + + return 0; } -static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) +static void osst_sysfs_destroy(dev_t dev) { - struct class_device *osst_class_member; + device_destroy(osst_sysfs_class, dev); +} - if (!osst_sysfs_valid) return; +static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) +{ + struct device *osst_member; + int err; - osst_class_member = class_device_create(osst_sysfs_class, NULL, dev, device, "%s", name); - if (IS_ERR(osst_class_member)) { + osst_member = device_create(osst_sysfs_class, device, dev, STp, + "%s", name); + if (IS_ERR(osst_member)) { printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); - return; - } - class_set_devdata(osst_class_member, STp); - class_device_create_file(osst_class_member, &class_device_attr_ADR_rev); - class_device_create_file(osst_class_member, &class_device_attr_media_version); - class_device_create_file(osst_class_member, &class_device_attr_capacity); - class_device_create_file(osst_class_member, &class_device_attr_BOT_frame); - class_device_create_file(osst_class_member, &class_device_attr_EOD_frame); - class_device_create_file(osst_class_member, &class_device_attr_file_count); -} + return PTR_ERR(osst_member); + } -static void osst_sysfs_destroy(dev_t dev) -{ - if (!osst_sysfs_valid) return; + err = device_create_file(osst_member, &dev_attr_ADR_rev); + if (err) + goto err_out; + err = device_create_file(osst_member, &dev_attr_media_version); + if (err) + goto err_out; + err = device_create_file(osst_member, &dev_attr_capacity); + if (err) + goto err_out; + err = device_create_file(osst_member, &dev_attr_BOT_frame); + if (err) + goto err_out; + err = device_create_file(osst_member, &dev_attr_EOD_frame); + if (err) + goto err_out; + err = device_create_file(osst_member, &dev_attr_file_count); + if (err) + goto err_out; + + return 0; - class_device_destroy(osst_sysfs_class, dev); +err_out: + osst_sysfs_destroy(dev); + return err; } static void osst_sysfs_cleanup(void) { - if (osst_sysfs_valid) { - class_destroy(osst_sysfs_class); - osst_sysfs_valid = 0; - } + class_destroy(osst_sysfs_class); } /* @@ -5720,7 +5838,7 @@ static int osst_probe(struct device *dev) struct st_partstat * STps; struct osst_buffer * buffer; struct gendisk * drive; - int i, dev_num; + int i, dev_num, err = -ENODEV; if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) return -ENODEV; @@ -5734,9 +5852,7 @@ static int osst_probe(struct device *dev) /* if this is the first attach, build the infrastructure */ write_lock(&os_scsi_tapes_lock); if (os_scsi_tapes == NULL) { - os_scsi_tapes = - (struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *), - GFP_ATOMIC); + os_scsi_tapes = kmalloc(osst_max_dev * sizeof(struct osst_tape *), GFP_ATOMIC); if (os_scsi_tapes == NULL) { write_unlock(&os_scsi_tapes_lock); printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); @@ -5752,18 +5868,18 @@ static int osst_probe(struct device *dev) } /* find a free minor number */ - for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++); + for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++) + ; if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); dev_num = i; /* allocate a struct osst_tape for this device */ - tpnt = (struct osst_tape *)kmalloc(sizeof(struct osst_tape), GFP_ATOMIC); - if (tpnt == NULL) { + tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); + if (!tpnt) { write_unlock(&os_scsi_tapes_lock); printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); goto out_put_disk; } - memset(tpnt, 0, sizeof(struct osst_tape)); /* allocate a buffer for this device */ i = SDp->host->sg_tablesize; @@ -5845,16 +5961,23 @@ static int osst_probe(struct device *dev) tpnt->modes[2].defined = 1; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; - init_MUTEX(&tpnt->lock); + mutex_init(&tpnt->lock); osst_nr_dev++; write_unlock(&os_scsi_tapes_lock); + { char name[8]; + /* Rewind entry */ - osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); + err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); + if (err) + goto out_free_buffer; + /* No-rewind entry */ snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); - osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); + err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); + if (err) + goto out_free_sysfs1; } sdev_printk(KERN_INFO, SDp, @@ -5863,9 +5986,13 @@ static int osst_probe(struct device *dev) return 0; +out_free_sysfs1: + osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); +out_free_buffer: + kfree(buffer); out_put_disk: put_disk(drive); - return -ENODEV; + return err; }; static int osst_remove(struct device *dev) @@ -5902,19 +6029,39 @@ static int osst_remove(struct device *dev) static int __init init_osst(void) { + int err; + printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); validate_options(); - osst_sysfs_init(); - if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) { + err = osst_sysfs_init(); + if (err) + return err; + + err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); + if (err < 0) { printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); - osst_sysfs_cleanup(); - return 1; + goto err_out; } - osst_create_driverfs_files(&osst_template.gendrv); + + err = scsi_register_driver(&osst_template.gendrv); + if (err) + goto err_out_chrdev; + + err = osst_create_sysfs_files(&osst_template.gendrv); + if (err) + goto err_out_scsidrv; return 0; + +err_out_scsidrv: + scsi_unregister_driver(&osst_template.gendrv); +err_out_chrdev: + unregister_chrdev(OSST_MAJOR, "osst"); +err_out: + osst_sysfs_cleanup(); + return err; } static void __exit exit_osst (void) @@ -5922,7 +6069,7 @@ static void __exit exit_osst (void) int i; struct osst_tape * STp; - osst_remove_driverfs_files(&osst_template.gendrv); + osst_remove_sysfs_files(&osst_template.gendrv); scsi_unregister_driver(&osst_template.gendrv); unregister_chrdev(OSST_MAJOR, "osst"); osst_sysfs_cleanup(); |
