📄 tapeblock.c
字号:
/*************************************************************************** * * drivers/s390/char/tapeblock.c * block device frontend for tape device driver * * S390 and zSeries version * Copyright (C) 2001 IBM Corporation * Author(s): Carsten Otte <cotte@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * * **************************************************************************** */#include "tapedefs.h"#include <linux/config.h>#include <linux/blkdev.h>#include <linux/blk.h>#include <linux/version.h>#include <linux/interrupt.h>#include <asm/ccwcache.h> /* CCW allocations */#include <asm/debug.h>#include <asm/s390dyn.h>#include <linux/compatmac.h>#ifdef MODULE#define __NO_VERSION__#include <linux/module.h>#endif#include "tape.h"#include "tapeblock.h"#define PRINTK_HEADER "TBLOCK:"/* * file operation structure for tape devices */#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))static struct block_device_operations tapeblock_fops = {#elsestatic struct file_operations tapeblock_fops = {#endif owner : THIS_MODULE, open : tapeblock_open, /* open */ release : tapeblock_release, /* release */ };int tapeblock_major = 0;#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))static void tape_request_fn (request_queue_t * queue);#elsestatic void tape_request_fn (void);#endifstatic request_queue_t* tapeblock_getqueue (kdev_t kdev);#ifdef CONFIG_DEVFS_FSvoidtapeblock_mkdevfstree (tape_info_t* ti) { ti->devfs_block_dir=devfs_mk_dir (ti->devfs_dir, "block", ti); ti->devfs_disc=devfs_register(ti->devfs_block_dir, "disc",DEVFS_FL_DEFAULT, tapeblock_major, ti->blk_minor, TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, ti);}voidtapeblock_rmdevfstree (tape_info_t* ti) { devfs_unregister(ti->devfs_disc); devfs_unregister(ti->devfs_block_dir);}#endifvoid tapeblock_setup(tape_info_t* ti) { blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default. hardsect_size[tapeblock_major][ti->blk_minor]=512; blk_init_queue (&ti->request_queue, tape_request_fn); blk_queue_headactive (&ti->request_queue, 0); #ifdef CONFIG_DEVFS_FS tapeblock_mkdevfstree(ti);#endif}inttapeblock_init(void) { int result; tape_frontend_t* blkfront,*temp; tape_info_t* ti; tape_init(); /* Register the tape major number to the kernel */#ifdef CONFIG_DEVFS_FS result = devfs_register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);#else result = register_blkdev(tapeblock_major, "tBLK", &tapeblock_fops);#endif if (result < 0) { PRINT_WARN(KERN_ERR "tape: can't get major %d for block device\n", tapeblock_major); panic ("cannot get major number for tape block device"); } if (tapeblock_major == 0) tapeblock_major = result; /* accept dynamic major number*/ INIT_BLK_DEV(tapeblock_major,tape_request_fn,tapeblock_getqueue,NULL); read_ahead[tapeblock_major]=TAPEBLOCK_READAHEAD; PRINT_WARN(KERN_ERR " tape gets major %d for block device\n", result); blk_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC); memset(blk_size[tapeblock_major],0,256*sizeof(int)); blksize_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC); memset(blksize_size[tapeblock_major],0,256*sizeof(int)); hardsect_size[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC); memset(hardsect_size[tapeblock_major],0,256*sizeof(int)); max_sectors[tapeblock_major] = (int*) kmalloc (256*sizeof(int),GFP_ATOMIC); memset(max_sectors[tapeblock_major],0,256*sizeof(int)); blkfront = kmalloc(sizeof(tape_frontend_t),GFP_KERNEL); if (blkfront==NULL) panic ("no mem for tape block device structure"); blkfront->device_setup=tapeblock_setup;#ifdef CONFIG_DEVFS_FS blkfront->mkdevfstree = tapeblock_mkdevfstree; blkfront->rmdevfstree = tapeblock_rmdevfstree;#endif blkfront->next=NULL; if (first_frontend==NULL) { first_frontend=blkfront; } else { temp=first_frontend; while (temp->next!=NULL) temp=temp->next; temp->next=blkfront; } ti=first_tape_info; while (ti!=NULL) { tapeblock_setup(ti); ti=ti->next; } return 0;}void tapeblock_uninit(void) { unregister_blkdev(tapeblock_major, "tBLK");}inttapeblock_open(struct inode *inode, struct file *filp) { tape_info_t *ti; kdev_t dev; int rc; long lockflags; inode = filp->f_dentry->d_inode; ti = first_tape_info; while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; if (ti == NULL) return -ENODEV;#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"b:open:"); debug_int_event (tape_debug_area,6,ti->blk_minor);#endif s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); if (tapestate_get (ti) != TS_UNUSED) { s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"b:dbusy");#endif return -EBUSY; } tapestate_set (ti, TS_IDLE); ti->position=-1; s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); rc=tapeblock_mediumdetect(ti); if (rc) { s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); tapestate_set (ti, TS_UNUSED); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return rc; // in case of errors, we don't have a size of the medium } dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev)); /* Get the device */ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); ti->blk_filp = filp; filp->private_data = ti; /* save the dev.info for later reference */ ti->cqr=NULL; s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); return 0;}inttapeblock_release(struct inode *inode, struct file *filp) { long lockflags; tape_info_t *ti,*lastti; ti = first_tape_info; while ((ti != NULL) && (ti->blk_minor != MINOR (inode->i_rdev))) ti = (tape_info_t *) ti->next; if ((ti != NULL) && (tapestate_get (ti) == TS_NOT_OPER)) { if (ti==first_tape_info) { first_tape_info=ti->next; } else { lastti=first_tape_info; while (lastti->next!=ti) lastti=lastti->next; lastti->next=ti->next; } kfree(ti); return 0; } if ((ti == NULL) || (tapestate_get (ti) != TS_IDLE)) {#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"b:notidle!");#endif return -ENXIO; /* error in tape_release */ }#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,6,"b:release:"); debug_int_event (tape_debug_area,6,ti->blk_minor);#endif s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags); tapestate_set (ti, TS_UNUSED); s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags); invalidate_buffers(inode->i_rdev); return 0;}static voidtapeblock_end_request(tape_info_t* ti) { struct buffer_head *bh; int uptodate; if ((tapestate_get(ti)!=TS_FAILED) && (tapestate_get(ti)!=TS_DONE)) BUG(); // A request has to be completed to end it uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?#ifdef TAPE_DEBUG if (uptodate) { debug_text_event (tape_debug_area,6,"b:done:"); debug_int_event (tape_debug_area,6,(long)ti->cqr); } else { debug_text_event (tape_debug_area,3,"b:failed:"); debug_int_event (tape_debug_area,3,(long)ti->cqr); }#endif // now inform ll_rw_block about a request status while ((bh = ti->current_request->bh) != NULL) { ti->current_request->bh = bh->b_reqnext; bh->b_reqnext = NULL; bh->b_end_io (bh, uptodate); } if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {#ifndef DEVICE_NO_RANDOM add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));#endif end_that_request_last (ti->current_request); } ti->discipline->free_bread(ti->cqr,ti); ti->cqr=NULL; ti->current_request=NULL; if (tapestate_get(ti)!=TS_NOT_OPER) tapestate_set(ti,TS_IDLE); return;}static voidtapeblock_exec_IO (tape_info_t* ti) { int rc; struct request* req; if (ti->cqr) { // process done/failed request while ((tapestate_get(ti)==TS_FAILED) && ti->blk_retries>0) { ti->blk_retries--; ti->position=-1; tapestate_set(ti,TS_BLOCK_INIT);#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"b:retryreq:"); debug_int_event (tape_debug_area,3,(long)ti->cqr);#endif rc = do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 0x00, ti->cqr->options); if (rc) {#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"b:doIOfail:"); debug_int_event (tape_debug_area,3,(long)ti->cqr);#endif continue; // one retry lost 'cause doIO failed } return; } tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl } if (ti->cqr!=NULL) BUG(); // tape should be idle now, request should be freed! if (tapestate_get (ti) == TS_NOT_OPER) { ti->blk_minor=ti->rew_minor=ti->nor_minor=-1; ti->devinfo.irq=-1; return; }#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) if (list_empty (&ti->request_queue.queue_head)) {#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -