X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fosst.c;h=acb835837eec6213cae3f70679406570a5eba557;hb=7a0b73a49ab56fb1e836675c00d6d0d2ba39a714;hp=e3bd4bc339f438e177f20d52bed6e6224086085e;hpb=60c904ae5bded8bb71f7bff7d63f2a6959d2a8e4;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c index e3bd4bc..acb8358 100644 --- a/drivers/scsi/osst.c +++ b/drivers/scsi/osst.c @@ -50,6 +50,7 @@ static const char * osst_version = "0.99.4"; #include #include #include +#include #include #include #include @@ -87,6 +88,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)"); @@ -278,8 +280,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; @@ -315,18 +317,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 */ @@ -340,6 +349,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; + + req->cmd_type = REQ_TYPE_BLOCK_PC; + 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. */ @@ -401,8 +478,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) { @@ -521,10 +598,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); } /* @@ -541,7 +618,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 @@ -592,10 +669,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 && @@ -605,11 +683,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) { @@ -3297,7 +3376,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); /* @@ -3599,7 +3678,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; } @@ -3618,7 +3697,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); /* @@ -3784,7 +3863,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; } @@ -4356,7 +4435,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; @@ -4436,7 +4515,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)); @@ -4722,9 +4801,21 @@ err_out: return retval; } +/* BKL pushdown: spaghetti avoidance wrapper */ +static int os_scsi_tape_open(struct inode * inode, struct file * filp) +{ + int ret; + + lock_kernel(); + ret = __os_scsi_tape_open(inode, filp); + unlock_kernel(); + 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; @@ -4843,8 +4934,7 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) static int osst_ioctl(struct inode * inode,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; @@ -4852,7 +4942,7 @@ 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)) + if (mutex_lock_interruptible(&STp->lock)) return -ERESTARTSYS; #if DEBUG @@ -5163,14 +5253,14 @@ 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); out: if (SRpnt) osst_release_request(SRpnt); - up(&STp->lock); + mutex_unlock(&STp->lock); return retval; } @@ -5207,12 +5297,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; @@ -5252,30 +5342,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 @@ -5284,7 +5369,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; @@ -5316,7 +5401,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 @@ -5344,7 +5429,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; @@ -5377,7 +5462,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; @@ -5410,7 +5495,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; } @@ -5430,7 +5515,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; } @@ -5451,7 +5536,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; } @@ -5492,7 +5577,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]; @@ -5507,7 +5592,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, ','); @@ -5523,7 +5608,7 @@ __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, @@ -5575,23 +5660,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) @@ -5599,11 +5685,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) @@ -5611,11 +5699,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) @@ -5623,11 +5712,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) @@ -5635,11 +5726,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) @@ -5647,11 +5740,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) @@ -5659,54 +5753,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; - class_device_destroy(osst_sysfs_class, dev); + return 0; + +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); } /* @@ -5721,7 +5828,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; @@ -5758,13 +5865,12 @@ static int osst_probe(struct device *dev) 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; @@ -5846,16 +5952,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, @@ -5864,9 +5977,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) @@ -5903,19 +6020,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) @@ -5923,7 +6060,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();