s390 (5/8): old tape file.
PATCH 1/1 s390 (5/8): old tape file.
Remove last remaining file of the old tape driver.
diffstat:
tape.c | 1907 ----------------------------------------------------------------- 1 files changed, 1907 deletions(-)
drivers/s390/char/tape.c +0 -1907
@@ -1,1907 +0,0 @@ -/*********************************************************************** -* drivers/s390/char/tape.c -* tape device driver for S/390 and zSeries tapes. -* -* S390 and zSeries version -* Copyright (C) 2001 IBM Corporation -* Author(s): Carsten Otte <[email protected]> -* Michael Holzheu <[email protected]> -* Tuan Ngo-Anh <[email protected]> -* -*********************************************************************** -*/ - -#include "tapedefs.h" // kernel 2.2 compatibility defines - -#include <linux/stddef.h> // defines NULL -#include <linux/proc_fs.h> // for /proc/tapedevices -#include <linux/init.h> // for kernel parameters -#include <linux/kmod.h> // for requesting modules -#include <linux/spinlock.h> // for locks -#include <asm/types.h> // for variable types -#ifdef CONFIG_S390_TAPE_DYNAMIC -#include <asm/s390dyn.h> -#endif -#include "tape.h" -#ifdef CONFIG_S390_TAPE_3590 -#include "tape3590.h" -#endif -#ifdef CONFIG_S390_TAPE_3490 -#include "tape3490.h" -#endif -#ifdef CONFIG_S390_TAPE_3480 -#include "tape3480.h" -#endif -#ifdef CONFIG_S390_TAPE_BLOCK -#include "tapeblock.h" -#endif -#ifdef CONFIG_S390_TAPE_CHAR -#include "tapechar.h" -#endif -#ifdef CONFIG_PROC_FS -#include <linux/vmalloc.h> -#endif -#define PRINTK_HEADER "T390:" -#define TAPE_MAX_DEVREGS (256 / TAPE_MINORS_PER_DEV) - -#define TAPE_NO_IO 0 -#define TAPE_DO_IO 1 - -#define TAPE_CIO_PRIVATE_DATA - -#ifdef CONFIG_KMOD -#define tape_request_module (a) request_module(a) -#else -#define tape_request_module (a) -#endif - -/******************************************************************* -* Internal Prototypes -*******************************************************************/ - -static void tape_do_irq (int irq,void *int_parm,struct pt_regs *regs); -static inline int tape_halt_io (tape_dev_t * td); -static void tape_wait (tape_ccw_req_t * treq); -#ifdef CONFIG_S390_TAPE_DYNAMIC -/* functions for dyn. dev. attach/detach */ -static int tape_oper_handler (int irq,struct _devreg *dreg); -static void tape_noper_handler (int irq,int status ); -#endif -static inline void tape_disable_device (tape_dev_t * td); -static inline int tape_enable_device (tape_dev_t * td); - - -/******************************************************************* -* GLOBALS -*******************************************************************/ - -static devreg_t *tape_devreg[TAPE_MAX_DEVREGS ]; -static int tape_devregct=0 ; -static int tape_autoprobe =1 ; -static tape_discipline_t *tape_first_disc =NULL ; -tape_dev_t *tape_first_dev =NULL ; -tape_frontend_t *tape_first_front =NULL ; -char *tape[256 ] = {NULL , }; - -/* -* Lock hirarchy: -* tape_discipline_lock > tape_dev_lock > td->lock -*/ - -rwlock_t tape_dev_lock=RW_LOCK_UNLOCKED ; -static rwlock_t tape_discipline_lock=RW_LOCK_UNLOCKED ; - -#ifdef TAPE_DEBUG -debug_info_t *tape_dbf_area =NULL ; -#endif - -const char * tape_med_st_verbose[MS_SIZE ]={ -"UNKNOWN " , -"LOADED " , -"UNLOADED" -}; - -const char * tape_state_verbose[TS_SIZE ]={ -"UNUSED" , -"IN_USE" , -"INIT " , -"NOT_OP" -}; - -const char * tape_op_verbose[TO_SIZE ] = { -"BLK" , -"BSB" , -"BSF" , -"DSE" , -"EGA" , -"FSB" , -"FSF" , -"LDI" , -"LBL" , -"MSE" , -"NOP" , -"RBA" , -"RBI" , -"RBU" , -"RBL" , -"RDC" , -"RFO" , -"RSD" , -"REW" , -"RUN" , -"SEN" , -"SID" , -"SNP" , -"SPG" , -"SWI" , -"SMR" , -"SYN" , -"TIO" , -"UNA" , -"WRI" , -"WTM" , -"MSN" , -"LOA" , -"RCF" ,/* 3590 */ -"RAT" ,/* 3590 */ -"NOT" -}; - -/******************************************************************* -* DEVFS Functions -*******************************************************************/ - -#ifdef CONFIG_DEVFS_FS - -/* -* Create devfs root entry (devno in hex) for device td -*/ - -static inline devfs_handle_t -tape_mkdevfsroot (tape_dev_t * td) -{ -char devno [10 ]; -sprintf (devno,"tape/%04x" ,td->devinfo.devno); -return devfs_mk_dir (NULL , devno,NULL ); -} - -/* -* Remove devfs root entry for device td -*/ - -static inline void -tape_rmdevfsroot (tape_dev_t * td) -{ -devfs_remove ("tape/%04x" , td->devinfo.devno); -} - -#endif - -/******************************************************************* -* PROCFS Functions -*******************************************************************/ - -#ifdef CONFIG_PROC_FS -/* functions used in tape_proc_file_ops */ -static ssize_t tape_proc_devices_read (struct file *file,char *user_buf,size_t user_len,loff_t * offset); -static int tape_proc_devices_open (struct inode *inode,struct file *file); -static int tape_proc_devices_release (struct inode *inode,struct file *file); - -/* our proc tapedevices entry */ -static struct proc_dir_entry *tape_proc_devices; - -typedef struct { -char *data; -int len; -}tape_procinfo_t ; - -static struct file_operations tape_proc_devices_file_ops = -{ - .owner =THIS_MODULE , - .read = tape_proc_devices_read,/* read */ - .open = tape_proc_devices_open,/* open */ - .release = tape_proc_devices_release,/* close */ -}; - -/* -* Initialize procfs stuff on startup -*/ - -static inline void -tape_proc_init (void ) { - tape_proc_devices =create_proc_entry ("tapedevices" , -S_IFREG |S_IRUGO |S_IWUSR , - &proc_root); -if (tape_proc_devices ==NULL ) - goto error; - tape_proc_devices->proc_fops = &tape_proc_devices_file_ops; - tape_proc_devices->proc_iops = &tape_proc_devices_inode_ops; -return ; - error: -PRINT_WARN ("tape: Cannot register procfs entry tapedevices\n" ); -return ; -} - -/* -* Open function for /proc/tapedevices -*/ - -static int -tape_proc_devices_open (struct inode *inode,struct file *file) -{ -tape_dev_t * td; -tape_procinfo_t * procinfo; -char * data =NULL ; -int size=0 ,check_size =-1 ; -int pos=0 ; -int rc=0 ; -long lockflags,lockflags2; -tape_ccw_req_t *treq; - - procinfo =kmalloc (sizeof (tape_procinfo_t),GFP_KERNEL ); -if (!procinfo){ - rc = -ENOMEM ; - goto out_no_lock; - } - -/* Find out mem size for output, ensure that after releasing lock */ -/* (vmalloc must not be called with interrupts disabled) no devices */ -/* have been added/removed */ - -do { - size =100 ;// Headline -read_lock_irqsave (&tape_dev_lock,lockflags); - -for (td=tape_first_dev;td!=NULL ;td=td->next) - size+=100 ;// FIXME: Guess better! - -if (size == check_size) -break ; - -read_unlock_irqrestore (&tape_dev_lock,lockflags); - -if (data) -vfree (data); - data=vmalloc (size); -if (!data) { -kfree (procinfo); - rc = -ENOMEM ; - goto out_no_lock; - } - check_size = size; - }while (1 ); - -// We have the tape_dev lock now - -#ifdef CONFIG_S390_TAPE_CHAR - pos+=sprintf (data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevMod\tBlkSize\tState\tOp\tMedState\n" ); -#else - pos+=sprintf (data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevMod\tState\tOp\tMedState\n" ); -#endif - -for (td=tape_first_dev;td!=NULL ;td=td->next) { -s390irq_spin_lock_irqsave (td->devinfo.irq,lockflags2); - treq =tape_get_active_ccw_req (td); - pos+=sprintf (data+pos,"%d\t" ,td->first_minor/TAPE_MINORS_PER_DEV ); - pos+=sprintf (data+pos,"%04X\t" ,td->devinfo.devno); - pos+=sprintf (data+pos,"%04X\t" ,td->devinfo.sid_data.cu_type); - pos+=sprintf (data+pos,"%02X\t" ,td->devinfo.sid_data.cu_model); - pos+=sprintf (data+pos,"%04X\t" ,td->devinfo.sid_data.dev_type); - pos+=sprintf (data+pos,"%02X\t" ,td->devinfo.sid_data.dev_model); -#ifdef CONFIG_S390_TAPE_CHAR -if (td->char_data.block_size ==0 ) - pos+=sprintf (data+pos,"auto\t" ); -else - pos+=sprintf (data+pos,"%i\t" ,td->char_data.block_size); -#endif - pos+=sprintf (data+pos,"%s\t" ,((tape_state_get (td) >=0 ) && - (tape_state_get (td) <TS_SIZE )) ? - tape_state_verbose[tape_state_get (td)] :"UNKNOWN" ); - pos+=sprintf (data+pos,"%s\t" ,(treq !=NULL ) ? - tape_op_verbose[treq->op] :"---" ); - pos+=sprintf (data+pos,"%s\n" ,tape_med_st_verbose[td->medium_state]); -s390irq_spin_unlock_irqrestore (td->devinfo.irq,lockflags2); - } - - procinfo->data=data; - procinfo->len=pos; -if (pos>size)BUG ();// we've overwritten some memory - file->private_data= (void *) procinfo; -read_unlock_irqrestore (&tape_dev_lock,lockflags); -out_no_lock: -return rc; -} - -/* -* Read function for /proc/tapedevices -*/ - -static ssize_t -tape_proc_devices_read (struct file *file,char *user_buf,size_t user_len,loff_t * offset) -{ -loff_t len =0 ; -tape_procinfo_t *p_info = (tape_procinfo_t *) file->private_data; - -if (*offset >= p_info->len) { - goto out;/* EOF */ - }else { - len = user_len<(p_info->len - *offset)?user_len:(p_info->len - *offset); -if (copy_to_user (user_buf, &(p_info->data[*offset]), len)) -return -EFAULT ; - (*offset) += len; - } -out: -return len; -} - -/* -* Close function for /proc/tapedevices -*/ - -static int -tape_proc_devices_release (struct inode *inode,struct file *file) -{ -int rc =0 ; -tape_procinfo_t *p_info = (tape_procinfo_t *) file->private_data; -vfree (p_info->data); -kfree (p_info); -return rc; -} - -/* -* Cleanup all stuff registered to the procfs -*/ -static inline void -tape_proc_cleanup (void ) -{ -if (tape_proc_devices !=NULL ) -remove_proc_entry ("tapedevices" , &proc_root); -} - -#endif /* CONFIG_PROC_FS */ - -/******************************************************************* -* Wait/Wakeup Functions -*******************************************************************/ - -static void tape_wake_up_remove (tape_ccw_req_t * treq){ -tape_remove_ccw_req (treq->tape_dev,treq); -tape_free_ccw_req (treq); -} - -static void tape_wake_up (tape_ccw_req_t * treq){ - treq->wakeup =NULL ; -wake_up (&treq->wq); -} - -static void tape_wake_up_interruptible (tape_ccw_req_t * treq){ - treq->wakeup =NULL ; -wake_up_interruptible (&treq->wq); -} - -#ifdef CONFIG_S390_TAPE_BLOCK -static void tape_schedule_tapeblock (tape_ccw_req_t * treq){ - treq->wakeup =NULL ; -tapeblock_schedule_exec_io ((tape_dev_t *)(treq->tape_dev));; -} -#endif - -static void tape_wait_event (tape_ccw_req_t * treq){ -wait_event (treq->wq,(treq->wakeup ==NULL )); -} - -static void tape_wait_event_interruptible (tape_ccw_req_t * treq){ -wait_event_interruptible (treq->wq,(treq->wakeup ==NULL )); -if (signal_pending (current)) { - treq->rc =tape_halt_io (treq->tape_dev); -if (treq->rc == -ERESTARTSYS ) -PRINT_INFO ("IO stopped on irq %d\n" ,treq->tape_dev->devinfo.irq);/* FIXME: only put into dbf */ -else if (treq->rc ==0 ) -PRINT_INFO ("could not stop IO,irq was faster on irq %d\n" ,treq->tape_dev->devinfo.irq);/* FIXME: only put into dbf */ -else -PRINT_WARN ("IO error while stopping IO on irq %d\n" ,treq->tape_dev->devinfo.irq); - } -} - -static void tape_wait_event_interruptible_nohaltio (tape_ccw_req_t * treq){ -wait_event_interruptible (treq->wq,(treq->wakeup ==NULL )); -} - -/******************************************************************* -* DYNAMIC ATTACH/DETACH Functions -*******************************************************************/ - -static inline void -tape_init_devregs (void ) -{ -long lockflags; -write_lock_irqsave (&tape_dev_lock,lockflags); -memset (tape_devreg,0 ,sizeof (devreg_t *) *TAPE_MAX_DEVREGS ); -write_unlock_irqrestore (&tape_dev_lock,lockflags); -} - -/* -* Alloc a devreg for a devno -*/ - -static inline devreg_t * -tape_create_devno_devreg (int devno) -{ -devreg_t *devreg =kmalloc (sizeof (devreg_t),GFP_KERNEL ); -if (devreg !=NULL ) { -memset (devreg,0 ,sizeof (devreg_t)); - devreg->ci.devno = devno; - devreg->flag =DEVREG_TYPE_DEVNO ; - devreg->oper_func = tape_oper_handler; - } -return devreg; -} - -/* -* Alloc a devreg for a cu-type -*/ - -static inline devreg_t * -tape_create_cu_devreg (int cu_type) -{ -devreg_t *devreg =kmalloc (sizeof (devreg_t),GFP_KERNEL ); -if (devreg !=NULL ) { -memset (devreg,0 ,sizeof (devreg_t)); - devreg->ci.hc.ctype = cu_type; - devreg->flag =DEVREG_MATCH_CU_TYPE |DEVREG_TYPE_DEVCHARS ; - devreg->oper_func = tape_oper_handler; - } -return devreg; -} - -/* -* Create devregs for device numbers from "from" to "to" -*/ - -static inline void -tape_create_devregs_range (int from,int to) -{ -int i; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); -for (i=from;i<=to;i++) { -// register for attch/detach of a devno -if (tape_devregct >=TAPE_MAX_DEVREGS ){ -PRINT_WARN ("Could not create devregs for devno range %04x - %04x.\n" ,i,to); -PRINT_WARN ("These devices cannot be used. Use autoprobe\n" ); -PRINT_WARN ("or specify device ranges more precisely!\n" ); -break ; - } - tape_devreg[tape_devregct]=tape_create_devno_devreg (i); -if (tape_devreg[tape_devregct]!=NULL ) { -s390_device_register (tape_devreg[tape_devregct++]); - }else { -PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n" ,i); - } - } -write_unlock_irqrestore (&tape_dev_lock,lockflags); -return ; -} - -/* -* Create a devreg for a discipline -*/ - -static inline void -tape_create_devreg_for_disc (tape_discipline_t *disc) -{ -int devreg_nr; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); -for (devreg_nr =0 ; devreg_nr <TAPE_MAX_DEVREGS ; devreg_nr++){ -if (tape_devreg[devreg_nr] ==NULL ) -break ; - } -if (devreg_nr ==TAPE_MAX_DEVREGS ){ -PRINT_WARN ("Could not create devreg for discipline (%x), dyn. attach for this discipline deactivated.\n" ,disc->cu_type); - goto out_unlock; - } - tape_devreg[devreg_nr] =tape_create_cu_devreg (disc->cu_type); -if (tape_devreg[devreg_nr] !=NULL ) { -s390_device_register (tape_devreg[devreg_nr]); - }else { -PRINT_WARN ("Could not alloc devreg: Out of memory\n" ); -PRINT_WARN ("Dynamic attach/detach will not work!\n" ); - } -out_unlock: -write_unlock_irqrestore (&tape_dev_lock,lockflags); -return ; -} - -/* -* Free all devregs -*/ - -static inline void -tape_delete_all_devregs (void ) -{ -int i; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); - -for (i =0 ; i <TAPE_MAX_DEVREGS ; i++){ -if (tape_devreg[i]){ -s390_device_unregister (tape_devreg[i]); -kfree (tape_devreg[i]); - } - } -memset (tape_devreg,0 ,sizeof (devreg_t *) *TAPE_MAX_DEVREGS ); -write_unlock_irqrestore (&tape_dev_lock,lockflags); -} - -/* -* Free Devregs for a discipline -*/ - -static inline void -tape_delete_devreg_for_disc (tape_discipline_t * disc) -{ -int i; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); - -for (i =0 ; i <TAPE_MAX_DEVREGS ; i++){ -if (tape_devreg[i]){ -if (tape_devreg[i]->ci.hc.ctype == disc->cu_type){ -s390_device_unregister (tape_devreg[i]); -kfree (tape_devreg[i]); - tape_devreg[i] =NULL ; - } - } - } - -write_unlock_irqrestore (&tape_dev_lock,lockflags); -} - -/******************************************************************* -* Module/Kernel Parameter Handling -*******************************************************************/ - -#ifndef MODULE -static char tape_parm_string[1024 ]__initdata = {0 , }; - -/* -* Get Kernel parameters (str) seperated by "," -* and store them into the tape[] array -*/ - -static void -tape_split_parm_string (char *str) -{ -char *tmp = str; -int count =0 ; -while (tmp !=NULL && *tmp !='\0' ) { -char *end; -int len; - end =strchr (tmp,',' ); -if (end ==NULL ) { - len =strlen (tmp) +1 ; - }else { - len = (long ) end - (long ) tmp +1 ; - *end ='\0' ; - end++; - } - tape[count] =kmalloc (len *sizeof (char ),GFP_ATOMIC ); -if (tape[count] ==NULL ) { - printk (KERN_WARNING PRINTK_HEADER -"can't store tape= parameter no %d\n" , - count + 1); -break ; - } -memcpy (tape[count], tmp, len *sizeof (char )); - count++; - tmp = end; - }; -} - -/* -* This function is called for each "tape=" Kernel parameter -* at Kernel initialization. We need tape_parm_setup because of -* 2.2 compatibility (At least I assume this :-)) -*/ - -void __init -tape_parm_setup (char *str,int *ints) -{ -int len =strlen (tape_parm_string); -if (len !=0 ) { -strcat (tape_parm_string,"," ); - } -strcat (tape_parm_string, str); -} - -int __init -tape_parm_call_setup (char *str) -{ -int dummy; -tape_parm_setup (str, &dummy); -return 1 ; -} - -__setup ("tape=" , tape_parm_call_setup); -#endif /* not defined MODULE */ - - -/* -* Convert string to int -*/ - -static inline int -tape_parm_strtoul (char *str,char **stra) -{ -char *temp = str; -int val; -if (*temp =='0' ) { - temp++;/* strip leading zero */ -if (*temp =='x' ) - temp++;/* strip leading x */ - } - val =simple_strtoul (temp, &temp,16 );/* interpret anything as hex */ - *stra = temp; -return val; -} - -/* -* Parse Kernel/Module Parameters and create devregs for dynamic attach/detach -*/ - -static inline void -tape_parm_parse (char **str) -{ -char *temp; -int from, to; - -if (*str==NULL ) { -/* no params present -> leave */ -return ; - } -while (*str) { - temp = *str; - from =0 ; - to =0 ; - from =tape_parm_strtoul (temp, &temp); - to = from; -if (*temp =='-' ) { - temp++; - to =tape_parm_strtoul (temp, &temp); - } -tape_create_devregs_range (from,to); - str++; - } -} - -/******************************************************************* -* Tape device (td) functions for create, free, enq, deq, enable, -* disable, get and put -*******************************************************************/ - -/* -* Enable Device -*/ - -static inline int -tape_enable_device (tape_dev_t * td) -{ -#ifdef CONFIG_DEVFS_FS -tape_frontend_t * frontend; -#endif -int rc =0 ; - -if (td->discipline->setup_device (td) !=0 ){ - rc = -ENOMEM ; - goto out; - } - -/* Register IRQ */ - -#ifdef TAPE_CIO_PRIVATE_DATA -#ifdef CONFIG_S390_TAPE_DYNAMIC - rc =s390_request_irq_special (td->devinfo.irq, tape_do_irq, - tape_noper_handler,0 ,TAPE_MAGIC , &(td->devstat)); -#else - rc =s390_request_irq (td->devinfo.irq, tape_do_irq,0 ,TAPE_MAGIC , &(td->devstat)); -#endif -#else -#ifdef CONFIG_S390_TAPE_DYNAMIC - rc =s390_request_irq_special (td->devinfo.irq, tape_do_irq, - tape_noper_handler,0 , (char *)td, &(td->devstat)); -#else - rc =s390_request_irq (td->devinfo.irq, tape_do_irq,0 , (char *)td, &(td->devstat)); -#endif -#endif /* TAPE_CIO_PRIVATE_DATA */ -if (rc){ -PRINT_WARN ("Cannot register irq %d, rc=%d\n" , td->devinfo.irq, rc); - td->discipline->cleanup_device (td); - goto out; - } -/* Create devfs entries */ -#ifdef CONFIG_DEVFS_FS -if (tape_mkdevfsroot (td)==NULL ){ -PRINT_WARN ("Cannot create a devfs directory for device %04x\n" ,td->devinfo.devno); - goto out_undo; - } - -for (frontend=tape_first_front;frontend!=NULL ;frontend=frontend->next){ -if (frontend->mkdevfstree (td) ==NULL ){ - goto out_undo; - } - } -#endif -#ifdef TAPE_CIO_PRIVATE_DATA -s390_set_private_data (td->devinfo.irq,td); -#endif -out: -return rc; -out_undo: -tape_disable_device (td); -return -ENOMEM ; -} - -/* -* Disable Device -*/ - -static inline void -tape_disable_device (tape_dev_t * td) -{ -#ifdef CONFIG_DEVFS_FS -tape_frontend_t * frontend; -#endif - td->discipline->cleanup_device (td); -#ifdef TAPE_CIO_PRIVATE_DATA -s390_set_private_data (td->devinfo.irq,NULL ); -#else - ioinfo[td->devinfo.irq]->irq_desc.name =NULL ; -#endif - -free_irq (td->devinfo.irq, &(td->devstat)); -#ifdef CONFIG_DEVFS_FS -for (frontend=tape_first_front;frontend!=NULL ;frontend=frontend->next) - frontend->rmdevfstree (td); -tape_rmdevfsroot (td); -#endif -tape_state_set (td,TS_NOT_OPER ); -} - -/* -* Append Tape device (td) to our tape info list -* Must be called with hold tape_dev_lock -*/ - -static inline void -tape_enq_device (tape_dev_t * td) -{ -tape_dev_t *temptd =NULL ; - -if (tape_first_dev ==NULL ) { - tape_first_dev = td; - }else { - temptd = tape_first_dev; -while (temptd->next !=NULL ) - temptd = temptd->next; - temptd->next = td; - } -} - -/* -* Remove Tape device (td) from our tape info list -* Must be called with hold tape_dev_lock -*/ - -static inline void -tape_deq_device (tape_dev_t * td) -{ -tape_dev_t * lasttd; - -if (td==tape_first_dev) { - tape_first_dev=td->next; - }else { - lasttd=tape_first_dev; -while (lasttd->next!=td) lasttd=lasttd->next; - lasttd->next=td->next; - } -} - - -/* -* Get Free minor number -* Must be called with held tape_dev_lock -*/ - -static inline int -tape_get_new_minor (int devno) -{ -int i,tape_num =-1 ; -tape_dev_t * newtape; - -if (!tape_autoprobe){ -/* we have static device ranges, so fingure out the */ -/* tape_num of the attached tape */ -for (i=0 ;i<tape_devregct;i++){ -if (tape_devreg[i]->ci.devno==devno) { - tape_num=TAPE_MINORS_PER_DEV *i; - goto out; - } - } - }else { -/* we are running in autoprobe mode, find a free */ -/* tape_num */ - i =0 ; - newtape=tape_first_dev; -while (newtape!=NULL ) { -if (newtape->first_minor==i) { -/* tape num in use. try next one */ - i+=TAPE_MINORS_PER_DEV ; - newtape=tape_first_dev; - }else { -/* tape num not used by newtape. look at next */ -/* tape info */ - newtape=newtape->next; - } - } -if (i>255 )/* No more minor available */ - tape_num =-1 ; -else - tape_num = i; - } -out: -return tape_num; -} - - -/* -* Create device: Alloc, enable and enq device -*/ - -static inline tape_dev_t * -tape_create_device (int irq,int devno,tape_discipline_t * disc) -{ -int rc =0 ; -int tape_num; -tape_dev_t *td; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); - - td =kmalloc (sizeof (tape_dev_t),GFP_ATOMIC ); -if (td ==NULL ) { -tape_sprintf_exception (tape_dbf_area,2 ,"ti:no mem \n" ); -PRINT_INFO ("tape: can't allocate memory for " -"tape info structure\n" ); - goto error; - } -memset (td,0 ,sizeof (tape_dev_t)); - tape_num =tape_get_new_minor (devno); -if (tape_num ==-1 ){ -PRINT_WARN ("tape: could not get minor for tape %x\n" ,devno); - goto error; - } - rc =get_dev_info_by_irq (irq, &(td->devinfo)); -if (rc == -ENODEV ) {/* end of device list */ - goto error; - } - td->discipline = disc; -atomic_set (&(td->use_count),1 ); - td->first_minor = tape_num; - td->medium_state =MS_UNKNOWN ; - td->next =NULL ; - td->discdata = td->treq =NULL ; -tape_state_set (td,TS_INIT ); - td->discdata=NULL ; - td->last_op =TO_NOTHING ; - -if (td->discipline->setup_device (td) !=0 ) - goto error; -if (tape_enable_device (td) !=0 ) - goto error; -tape_enq_device (td); -PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n" ,devno,disc->cu_type,irq,tape_num/2 ); -write_unlock_irqrestore (&tape_dev_lock,lockflags); -return td; -error: -tape_sprintf_event (tape_dbf_area,3 ,"tsetup err: %x\n" ,rc); -if (td) -kfree (td); -write_unlock_irqrestore (&tape_dev_lock,lockflags); -return NULL ; -} - -/* -* Free Device storage -*/ - -static void -tape_free_device (tape_dev_t * td) -{ -if (TAPE_BUSY (td)) -BUG ();/* one should _not_ free the device when a request is pending */ -tape_sprintf_event (tape_dbf_area,6 ,"free irq: %x\n" ,td->devinfo.irq); -kfree (td); -} - -/* -* Decrement use count of tape structure -* if use count == 0 tape structure is freed -*/ - -inline void -tape_put_device (tape_dev_t * td) -{ -if (td==NULL ) -BUG (); -if (atomic_dec_and_test (&(td->use_count))) -tape_free_device (td); -} - -/* -* Find the tape_dev_t structure associated with member -* and increase use count: -* -* member: TAPE_MEMB_IRQ, TAPE_MEMB_MINOR -*/ - -tape_dev_t * -__tape_get_device_by_member (unsigned long value,int member) -{ -tape_dev_t *td =NULL ; -long lockflags; - -read_lock_irqsave (&tape_dev_lock,lockflags); - td = tape_first_dev; -while (td !=NULL ) { -switch (member){ -case TAPE_MEMB_IRQ : -if (td->devinfo.irq == value) - goto out; -break ; -case TAPE_MEMB_MINOR : -if ((value >= td->first_minor) && - (value < (td->first_minor +TAPE_MINORS_PER_DEV )) ) - goto out; -break ; -case TAPE_MEMB_QUEUE : -if (((unsigned long )(&td->blk_data.request_queue)) == value) - goto out; -break ; -default : -BUG (); - } - td = td->next; - } -out: -if (td)// found! -atomic_inc (&(td->use_count)); -read_unlock_irqrestore (&tape_dev_lock,lockflags); -return td; -} - -/* -* Scan all irqs an create tape devices for all matching cu types -*/ - -static inline void -tape_create_devs_for_disc (tape_discipline_t * disc) -{ -int irq,i; -tape_dev_t * td =NULL ; -s390_dev_info_t dinfo; - -for (irq =get_irq_first (); irq!=-ENODEV ; irq=get_irq_next (irq)) { -if (get_dev_info_by_irq (irq, &dinfo) == -ENODEV ) -continue ; -if (disc->cu_type != dinfo.sid_data.cu_type) -/* Wrong type - try next one */ -continue ; - -tape_sprintf_event (tape_dbf_area,3 ,"det irq: %x\n" ,irq); -tape_sprintf_event (tape_dbf_area,3 ,"cu : %x\n" ,disc->cu_type); - - -if (!tape_autoprobe) { -for ( i=0 ; i<tape_devregct; i++ ) { -if (tape_devreg[i]->ci.devno == dinfo.devno) { - td =tape_create_device (irq, dinfo.devno, disc); -if (!td) { -PRINT_WARN ("Could not initialize tape 0x%x\n" ,dinfo.devno); -continue ; - } -if (disc->init_device) - disc->init_device (td);/* XXX */ -tape_state_set (td,TS_UNUSED ); -break ; - } - } - } -else { - td =tape_create_device (irq,dinfo.devno,disc); - -if (!td){ -PRINT_WARN ("Could not initialize tape 0x%x\n" ,dinfo.devno); -continue ; - } -if (disc->init_device) - disc->init_device (td);/* XXX */ -tape_state_set (td,TS_UNUSED ); - } - } -} - -/* -* Go through our tape info list and disable, deq and free all devices with -* matching cu type -*/ - -static inline void -tape_delete_devs_for_disc (tape_discipline_t * disc) -{ -tape_dev_t *td; -long lockflags; - -write_lock_irqsave (&tape_dev_lock,lockflags); - td = tape_first_dev; -while (td !=NULL ){ -if (td->discipline == disc){ -tape_deq_device (td); -write_unlock_irqrestore (&tape_dev_lock,lockflags); -tape_disable_device (td); -tape_put_device (td); -write_lock_irqsave (&tape_dev_lock,lockflags); - td = tape_first_dev; - }else { - td=td->next; - } - } -write_unlock_irqrestore (&tape_dev_lock,lockflags); -} - -/******************************************************************* -* TAPE Request and IO Functions -*******************************************************************/ - -/* -* Allocate a new tape ccw request -*/ - -inline tape_ccw_req_t * -tape_alloc_ccw_req (int cplength,int datasize,int idal_buf_size,tape_op_t operation) -{ -tape_ccw_req_t * treq; -int kmalloc_flags; -if (in_interrupt ()) - kmalloc_flags =GFP_ATOMIC ; -else - kmalloc_flags =GFP_KERNEL ; - - treq = (tape_ccw_req_t *)kmalloc (sizeof (tape_ccw_req_t),kmalloc_flags); -if (!treq) - goto error; -memset (treq,0 ,sizeof (tape_ccw_req_t)); - treq->kernbuf_size = datasize; - treq->userbuf_size = datasize; - treq->op = operation; - treq->cplength = cplength; -init_waitqueue_head (&treq->wq); - -// alloc small kernel buffer - -if (datasize >PAGE_SIZE ) -BUG (); -if (datasize >0 ){ -// the kernbuf must be below 2GB --> GFP_DMA - treq->kernbuf =kmalloc (datasize,kmalloc_flags |GFP_DMA ); -if (!treq->kernbuf) - goto error; -memset (treq->kernbuf,0 , datasize); - } - -// alloc idal kernel buffer - -if (idal_buf_size >0 ){ - treq->idal_buf =idalbuf_alloc (idal_buf_size); -if (!treq->idal_buf) - goto error; - } - -if (cplength <0 ) -BUG (); - -// the channel program must be below 2GB --> GFP_DMA - treq->cpaddr =kmalloc (cplength *sizeof (ccw1_t), kmalloc_flags |GFP_DMA ); -if (!treq->cpaddr) - goto error; -memset (treq->cpaddr,0 , cplength*sizeof (ccw1_t)); -return treq; -error: -tape_sprintf_exception (tape_dbf_area,1 ,"cqra nomem\n" ); -if (treq) -tape_free_ccw_req (treq); -return NULL ; -} - -/* -* Free tape ccw request -*/ - -void -tape_free_ccw_req (tape_ccw_req_t * treq) -{ -if (!treq) -BUG (); -if (treq->cpaddr) -kfree (treq->cpaddr); -if (treq->kernbuf) -kfree (treq->kernbuf); -if (treq->idal_buf) -idalbuf_free (treq->idal_buf); -kfree (treq); -} - -/* -* Add request to request queue (At the moment queue length = 1) -*/ - -static inline int -tape_add_ccw_req (tape_dev_t * td,tape_ccw_req_t * treq) -{ -if (td->treq) -return -1 ; - td->treq = treq; - treq->tape_dev = td; -return 0 ; -} - -/* -* Remove request from request queue (At the moment queue length = 1) -*/ - -int -tape_remove_ccw_req (tape_dev_t * td,tape_ccw_req_t * treq) -{ -if (treq != td->treq) -BUG (); - td->last_op = treq->op; - td->treq=NULL ; - treq->tape_dev=NULL ; -return 0 ; -} - -/* -* Get the active ccw request -*/ - -tape_ccw_req_t * -tape_get_active_ccw_req (tape_dev_t * td) -{ -return td->treq; -} - -/* -* Stop the active ccw request -*/ - -static inline int -tape_halt_io (tape_dev_t * td) -{ -int retries =0 ; -int irq = td->devinfo.irq; -int rc =0 ; -long lockflags; -tape_ccw_req_t * treq; - -s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags); - treq =tape_get_active_ccw_req (td); -/* check if interrupt has already been processed */ -if (!treq) - goto out; -if (treq->wakeup ==NULL ) - goto out; -while (retries <5 ){ -if ( retries <2 ) - rc =halt_IO (irq, (long )treq, treq->options); -else - rc =clear_IO (irq, (long )treq, treq->options); -switch (rc) { -case 0 :/* termination successful */ - rc = -ERESTARTSYS ; - goto out; -case -ENODEV : -PRINT_INFO ("device gone, retry\n" );/* FIXME: s390dbf only */ -break ; -case -EIO : -PRINT_INFO ("I/O error, retry\n" );/* FIXME: s390dbf only */ -break ; -case -EBUSY : -PRINT_INFO ("device busy, retry later\n" );/* FIXME: s390dbf only */ -break ; -default : -PRINT_ERR ("line %d unknown RC=%d, please report" -" to [email protected]\n" , __LINE__, rc); -BUG (); - } - retries ++; - } -out: -s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags); -return rc; -} - - -/* -* The tape IO function: -* tape_do_io MUST be called with locked td lock! -*/ - -static inline int -__tape_do_io (tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type,int io) -{ -int rc =0 ; - -if ((td==NULL ) || (treq==NULL )) -BUG (); - -if (tape_state_get (td) ==TS_NOT_OPER ){ - rc = -ENODEV ; - goto out; - } -if (TAPE_BUSY (td)){ -tape_sprintf_event (tape_dbf_area,1 ,"tape: IRQ - Tape busy\n" ); - rc = -EBUSY ; - goto out; - } -tape_add_ccw_req (td,treq); -switch (type){ -case TAPE_REMOVE_REQ_ON_WAKEUP : - treq->wakeup = tape_wake_up_remove; -break ; -case TAPE_NO_WAIT : -// needed for retry -break ; -case TAPE_WAIT : - treq->wakeup = tape_wake_up; - treq->wait = tape_wait_event; -break ; -case TAPE_WAIT_INTERRUPTIBLE : - treq->wakeup = tape_wake_up_interruptible; - treq->wait = tape_wait_event_interruptible; -break ; -case TAPE_WAIT_INTERRUPTIBLE_NOHALTIO : -// neded for dummy load - treq->wakeup = tape_wake_up_interruptible; - treq->wait = tape_wait_event_interruptible_nohaltio; -break ; -#ifdef CONFIG_S390_TAPE_BLOCK -case TAPE_SCHED_BLOCK : - treq->wakeup = tape_schedule_tapeblock; - treq->wait =NULL ; -break ; -#endif -default : -BUG (); - } - -if (io) - rc =do_IO (td->devinfo.irq,treq->cpaddr, - (unsigned long )treq,0x00 , treq->options); - -if (rc) { -tape_sprintf_event (tape_dbf_area,1 ,"tape: DOIO failed with er = %i\n" ,rc); - treq->wakeup =NULL ; - treq->wait =NULL ;/*XXX ??*/ -tape_remove_ccw_req (td,treq); - } -out: -return rc; -} - -/* -* Do the io request and wait for it -*/ - -int -tape_do_io_and_wait (tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type) -{ -int rc =0 ; -long lockflags; -if (td==NULL ) -BUG (); -s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags); - rc =__tape_do_io (td,treq,type,TAPE_DO_IO ); -s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags); -if (rc ==0 ) -tape_wait (treq); -return rc; -} - -/* -* Needed for MTLOAD: Just create a wait request without doing io -*/ - -int -tape_do_wait_req (tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type) -{ -int rc =0 ; -long lockflags; -if (td==NULL ) -BUG (); -s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags); - rc =__tape_do_io (td,treq,type,TAPE_NO_IO ); -s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags); -tape_wait (treq); -return rc; -} - -/* -* Just do the io -*/ - -int -tape_do_io (tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type) -{ -int rc =0 ; -long lockflags; -s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags); - rc =__tape_do_io (td,treq,type,TAPE_DO_IO ); -s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags); -return rc; -} - -/* -* Just do the io, but we are already locked here (in irq) -*/ - -int -tape_do_io_irq (tape_dev_t * td,tape_ccw_req_t *treq,tape_wait_t type) -{ -return __tape_do_io (td,treq,type,TAPE_DO_IO ); -} - -/* -* Wait for an io request -*/ - -static void -tape_wait (tape_ccw_req_t * treq) -{ -tape_dev_t * td; -if (treq==NULL ) -BUG (); - td = treq->tape_dev; -if (td==NULL ) -BUG (); -if (treq->wait==NULL ) -BUG (); - treq->wait (treq); -tape_remove_ccw_req (td,treq); -} - -/* -* Tape interrupt routine, called from Ingo's I/O layer -*/ - -static void -tape_do_irq (int irq,void *int_parm,struct pt_regs *regs) -{ -tape_dev_t *td; -#ifdef TAPE_CIO_PRIVATE_DATA - td = (tape_dev_t *)s390_get_private_data (irq); -#else - td = (tape_dev_t *)ioinfo[irq]->irq_desc.name; -#endif -if (!td) { -PRINT_ERR ("tape: could not get device structure for irq %d in interrupt\n" ,irq); - goto out; - } -if (td->devstat.dstat !=0x0c ){ -tape_sprintf_event (tape_dbf_area,3 ,"-- Tape Interrupthandler --\n" ); -tape_dump_sense_dbf (td); - } -if (tape_state_get (td) ==TS_NOT_OPER ) { -tape_sprintf_event (tape_dbf_area,6 ,"tape:device is not operational\n" ); - goto out; - } - td->discipline->irq (td); -out: -return ; -} - -/* -* Oper Handler is called from Ingo's I/O layer when a new tape device is -* attached. We create a new devinfo for the new device, enable and enq it. -*/ - -static int -tape_oper_handler (int irq,struct _devreg *dreg) { -tape_dev_t * td=tape_first_dev; -int rc=0 ; -s390_dev_info_t dinfo; -tape_discipline_t * disc; -long lockflags; - - td =tape_get_device_by_irq (irq); -if (td!=NULL ) { -// irq is (still) used by tape. tell ingo to try again later -PRINT_ERR ("tape:Oper handler for irq %d called, but irq is still (internally) used.\n" ,irq); - rc = -EAGAIN ; - goto out; - } - - rc =get_dev_info_by_irq (irq, &dinfo); -if (rc == -ENODEV ) { -PRINT_ERR ("tape: Cannot get dev info for irq %d in the oper handler.\n" ,irq); - rc = -EAGAIN ; - goto out; - } - -read_lock_irqsave (&tape_discipline_lock,lockflags); - - disc = tape_first_disc; -while ((disc !=NULL ) && (disc->cu_type != dinfo.sid_data.cu_type)) - disc = (tape_discipline_t *) (disc->next); - -if (disc ==NULL ){ -PRINT_WARN ("tape: No matching discipline for cu_type %x found in the oper handler, ignoring device %04x.\n" ,dinfo.sid_data.cu_type,dinfo.devno); - rc = -ENODEV ; - goto out_unlock; - } - -/* Allocate tape structure */ - td =tape_create_device (irq,dinfo.devno,disc); - -if (td ==NULL ) { -PRINT_WARN ("Could not initialize tape 0x%x\n" ,dinfo.devno); - rc = -ENOBUFS ; - goto out_unlock; - }else { -if (disc->init_device) - disc->init_device (td); - } -tape_state_set (td,TS_UNUSED ); -out_unlock: -read_unlock_irqrestore (&tape_discipline_lock,lockflags); -out: -return rc; -} - -/* -* Not Oper Handler is called from Ingo's IO layer, when a tape device -* is detached. We deq, disable and free the tape info for this device -*/ - -static void -tape_noper_handler (int irq,int status ) { -tape_dev_t *td; -long lockflags; -tape_ccw_req_t *treq; - - td =tape_get_device_by_irq (irq); -if (td==NULL ) { -PRINT_ERR ("tape: not operational handler called for irq %x, but tape does not hold this irq.\n" ,irq); - goto error; - } - -write_lock_irqsave (&tape_dev_lock,lockflags); -tape_deq_device (td); -write_unlock_irqrestore (&tape_dev_lock,lockflags); - -tape_disable_device (td); - -s390irq_spin_lock_irqsave (td->devinfo.irq, lockflags); - treq =tape_get_active_ccw_req (td); -if (treq) { -// device is in use! - treq->rc= -ENODEV ; -if (treq->wakeup) - treq->wakeup (treq); -PRINT_WARN ("Tape #%d is detached while it was busy.\n" ,td->first_minor/TAPE_MINORS_PER_DEV ); - }else { -// device is unused! -PRINT_WARN ("Tape #%d is detached now.\n" ,td->first_minor/TAPE_MINORS_PER_DEV ); - } - -s390irq_spin_unlock_irqrestore (td->devinfo.irq, lockflags); - -/* decrement use count twice ! */ -tape_put_device (td); -tape_put_device (td); -error: -return ; -} - -/* -* Write sense data to dbf -*/ - -void tape_dump_sense_dbf (tape_dev_t * td) -{ -devstat_t *stat = &td->devstat; -const char * op; -if (TAPE_BUSY (td)) - op = tape_op_verbose[tape_get_active_ccw_req (td)->op]; -else - op ="---" ; -tape_sprintf_event (tape_dbf_area,3 ,"DSTAT : %02x CSTAT: %02x\n" ,stat->dstat,stat->cstat); -tape_sprintf_event (tape_dbf_area,3 ,"DEVICE: %04x OP : %s\n" ,td->devinfo.devno,op); -tape_sprintf_event (tape_dbf_area,3 ,"%08x %08x\n" ,*((unsigned int *)&stat->ii.sense.data[0 ]),*((unsigned int *)&stat->ii.sense.data[4 ])); -tape_sprintf_event (tape_dbf_area,3 ,"%08x %08x\n" ,*((unsigned int *)&stat->ii.sense.data[8 ]),*((unsigned int *)&stat->ii.sense.data[12 ])); -tape_sprintf_event (tape_dbf_area,3 ,"%08x %08x\n" ,*((unsigned int *)&stat->ii.sense.data[16 ]),*((unsigned int *)&stat->ii.sense.data[20 ])); -tape_sprintf_event (tape_dbf_area,3 ,"%08x %08x\n" ,*((unsigned int *)&stat->ii.sense.data[24 ]),*((unsigned int *)&stat->ii.sense.data[28 ])); -} - -/* -* Write sense data to console/dbf -*/ - -void -tape_dump_sense (tape_dev_t * td) -{ -devstat_t *stat = &td->devstat; -#if 1 /* XXX */ -PRINT_INFO ("-------------------------------------------------\n" ); -PRINT_INFO ("DSTAT : %02x CSTAT: %02x CPA: %04x\n" ,stat->dstat,stat->cstat,stat->cpa); -PRINT_INFO ("DEVICE: %04x\n" ,td->devinfo.devno); -if (TAPE_BUSY (td)) -PRINT_INFO ("OP : %s\n" ,tape_op_verbose[tape_get_active_ccw_req (td)->op]); - -PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " -" %02X%02X%02X%02X %02X%02X%02X%02X \n" , - stat->ii.sense.data[0 ], stat->ii.sense.data[1 ], - stat->ii.sense.data[2 ], stat->ii.sense.data[3 ], - stat->ii.sense.data[4 ], stat->ii.sense.data[5 ], - stat->ii.sense.data[6 ], stat->ii.sense.data[7 ], - stat->ii.sense.data[8 ], stat->ii.sense.data[9 ], - stat->ii.sense.data[10 ], stat->ii.sense.data[11 ], - stat->ii.sense.data[12 ], stat->ii.sense.data[13 ], - stat->ii.sense.data[14 ], stat->ii.sense.data[15 ]); -PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X " -" %02X%02X%02X%02X %02X%02X%02X%02X \n" , - stat->ii.sense.data[16 ], stat->ii.sense.data[17 ], - stat->ii.sense.data[18 ], stat->ii.sense.data[19 ], - stat->ii.sense.data[20 ], stat->ii.sense.data[21 ], - stat->ii.sense.data[22 ], stat->ii.sense.data[23 ], - stat->ii.sense.data[24 ], stat->ii.sense.data[25 ], - stat->ii.sense.data[26 ], stat->ii.sense.data[27 ], - stat->ii.sense.data[28 ], stat->ii.sense.data[29 ], - stat->ii.sense.data[30 ], stat->ii.sense.data[31 ]); -PRINT_INFO ("--------------------------------------------------\n" ); -#endif -} - -/******************************************************************* -* TAPE Discipline functions -*******************************************************************/ - -/* -* Register backend discipline -*/ - -int -tape_register_discipline (tape_discipline_t *disc) -{ -tape_discipline_t *disc_ptr; -long lockflags; - - disc->next =NULL ; - -write_lock_irqsave (&tape_discipline_lock,lockflags); - -if (tape_first_disc ==NULL ) { - tape_first_disc = disc; - }else { -for (disc_ptr = tape_first_disc; disc_ptr->next!=NULL ; disc_ptr=(tape_discipline_t *)disc_ptr->next); - disc_ptr->next = disc; - } - -tape_create_devs_for_disc (disc); -if (tape_autoprobe) -tape_create_devreg_for_disc (disc); - -write_unlock_irqrestore (&tape_discipline_lock,lockflags); -return 0 ; -} - -/* -* Unregister backend discipline -*/ - -void -tape_unregister_discipline (tape_discipline_t * disc) -{ -tape_discipline_t * lastdisc; -long lockflags; - -write_lock_irqsave (&tape_discipline_lock,lockflags); - -tape_delete_devs_for_disc (disc); -if (tape_autoprobe) -tape_delete_devreg_for_disc (disc); - -if (disc==tape_first_disc) { - tape_first_disc=disc->next; - }else { - lastdisc=tape_first_disc; -while (lastdisc->next!=disc) lastdisc=lastdisc->next; - lastdisc->next=disc->next; - } - - disc->shutdown (); - -write_unlock_irqrestore (&tape_discipline_lock,lockflags); -} - -/* -* Cleanup all registered disciplines -*/ - -static inline void -tape_cleanup_disciplines (void ) -{ -long lockflags; -tape_discipline_t * disc; -/* Unregister all backend disciplines - this also deletes the devices */ - -write_lock_irqsave (&tape_discipline_lock,lockflags); - disc=tape_first_disc; -while (disc !=NULL ) { -write_unlock_irqrestore (&tape_discipline_lock,lockflags); -tape_unregister_discipline (disc); -kfree (disc); -write_lock_irqsave (&tape_discipline_lock,lockflags); - disc=tape_first_disc; - } -write_unlock_irqrestore (&tape_discipline_lock,lockflags); -} - - -/******************************************************************* -* TAPE Init Functions -*******************************************************************/ - -/* -* tape_print_banner will be called on initialisation and print a nice banner -*/ - -static inline void -tape_print_banner (void ) -{ -char *opt_char,*opt_block; - -/* print banner */ -PRINT_WARN ("IBM zSeries Tape Device Driver (v%d.%02d).\n" ,TAPE_VERSION_MAJOR ,TAPE_VERSION_MINOR ); -PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000 - 2001\n" ); - opt_char=opt_block="not present" ; -#ifdef CONFIG_S390_TAPE_CHAR - opt_char="built in" ; -#endif -#ifdef CONFIG_S390_TAPE_BLOCK - opt_block="built in" ; -#endif -/* print feature info */ -PRINT_WARN ("character device frontend : %s\n" ,opt_char); -PRINT_WARN ("block device frontend : %s\n" ,opt_block); -} - -/* -* tape_init will register the driver for each tape. -*/ - -int -tape_init (void ) -{ -static int initialized=0 ; - -if (initialized)// Only init the devices once -return 0 ; - initialized=1 ; - -tape_init_devregs (); -#ifdef TAPE_DEBUG - tape_dbf_area =debug_register ("tape" ,2 ,2 ,3 *sizeof (long )); -debug_register_view (tape_dbf_area,&debug_sprintf_view); -tape_sprintf_event (tape_dbf_area,3 ,"begin init\n" ); -#endif /* TAPE_DEBUG */ -tape_print_banner (); -#ifndef MODULE -tape_split_parm_string (tape_parm_string); -#endif -#ifdef CONFIG_DEVFS_FS -devfs_mk_dir (NULL ,"tape" ,NULL ); -#endif /* CONFIG_DEVFS_FS */ - -tape_sprintf_event (tape_dbf_area,3 ,"dev detect\n" ); -/* Allocate the tape structures */ -if (*tape!=NULL ) {/* if parameters are present */ -PRINT_INFO ("Using ranges supplied in parameters, disabling autoprobe mode.\n" ); -tape_parm_parse (tape); - tape_autoprobe =0 ; - }else { -PRINT_INFO ("No parameters supplied, enabling autoprobe mode for all supported devices.\n" ); - tape_autoprobe =1 ; - } -#ifdef CONFIG_PROC_FS -tape_proc_init (); -#endif /* CONFIG_PROC_FS */ -#ifdef CONFIG_S390_TAPE_3480 -tape_register_discipline (tape3480_init ()); -#else -#ifndef CONFIG_S390_TAPE -tape_request_module ("tape_3480_mod" ); -#endif -#endif /* CONFIG_S390_TAPE_3480 */ - -#ifdef CONFIG_S390_TAPE_3490 -tape_register_discipline (tape3490_init ()); -#else -#ifndef CONFIG_S390_TAPE -tape_request_module ("tape_3490_mod" ); -#endif -#endif /* CONFIG_S390_TAPE_3490 */ - -#ifdef CONFIG_S390_TAPE_3590 -tape_register_discipline (tape3590_init ()); -#else -#ifndef CONFIG_S390_TAPE -tape_request_module ("tape_3590_mod" ); -#endif -#endif /* CONFIG_S390_TAPE_3590 */ -return 0 ; -} - -/******************************************************************* -* TAPE Module functions -*******************************************************************/ - -#ifdef MODULE -MODULE_AUTHOR ("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte and Michael Holzheu ([email protected],[email protected])" ); -MODULE_DESCRIPTION ("Linux on zSeries channel attached tape device driver" ); -MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s"); - -/* -* The famous init_module -*/ - -int -init_module (void ) -{ -#ifdef CONFIG_S390_TAPE_CHAR -tapechar_init (); -#endif -#ifdef CONFIG_S390_TAPE_BLOCK -tapeblock_init (); -#endif -return 0 ; -} - -/* -* Cleanup the frontends -*/ -static inline void -tape_cleanup_frontends (void ) -{ -tape_frontend_t * frontend, *tempfe; - -/* Now get rid of the frontends */ -#ifdef CONFIG_S390_TAPE_CHAR -tapechar_uninit (); -#endif -#ifdef CONFIG_S390_TAPE_BLOCK -tapeblock_uninit (); -#endif - frontend=tape_first_front; -while (frontend !=NULL ) { - tempfe = frontend; - frontend = frontend->next; -kfree (tempfe); - } -} - - -/* -* Cleanup module -*/ - -void -cleanup_module (void ) -{ -tape_sprintf_event (tape_dbf_area,6 ,"cleaup mod" ); -tape_cleanup_disciplines (); -#ifdef CONFIG_DEVFS_FS -devfs_remove ("tape" );/* devfs checks for NULL */ -#endif CONFIG_DEVFS_FS -#ifdef CONFIG_PROC_FS -tape_proc_cleanup (); -#endif -tape_cleanup_frontends (); -/* Deallocate devregs in case of not autoprobe */ -if (!tape_autoprobe) -tape_delete_all_devregs (); -#ifdef TAPE_DEBUG -debug_unregister (tape_dbf_area); -#endif /* TAPE_DEBUG */ -} -#endif /* MODULE */ - - -/******************************************************************* -* TAPE Tapestate functions -*******************************************************************/ - -inline void -tape_state_set (tape_dev_t * td,tape_state_t newstate) -{ -if (td->tape_state ==TS_NOT_OPER ) { -tape_sprintf_event (tape_dbf_area,3 ,"ts_set err: not oper\n" ); - }else { -tape_sprintf_event (tape_dbf_area,4 ,"ts. dev: %x\n" ,td->first_minor); -tape_sprintf_event (tape_dbf_area,4 ,"old ts: %s\n" ,(((tape_state_get (td) <TO_SIZE ) && (tape_state_get (td) >=0 )) ? tape_state_verbose[tape_state_get (td)] :"UNKNOWN TS" )); -tape_sprintf_event (tape_dbf_area,4 ,"%s\n" , - (((tape_state_get (td) <TO_SIZE ) && - (tape_state_get (td) >=0 )) ? - tape_state_verbose[tape_state_get (td)] : -"UNKNOWN TS" )); -tape_sprintf_event (tape_dbf_area,4 ,"new ts: \n" ); -tape_sprintf_event (tape_dbf_area,4 ,"%s\n" ,(((newstate <TO_SIZE ) && - (newstate >=0 )) ? - tape_state_verbose[newstate] : -"UNKNOWN TS" )); - td->tape_state = newstate; - } -} - -inline tape_state_t -tape_state_get (tape_dev_t * td) -{ -return (td->tape_state); -} - -inline void -tape_med_state_set (tape_dev_t * td,tape_medium_state_t newstate) -{ -if (td->medium_state == newstate) - goto out; -switch (newstate){ -case MS_UNLOADED : -PRINT_INFO ("(%x): Tape is unloaded\n" ,td->devstat.devno); -break ; -case MS_LOADED : -PRINT_INFO ("(%x): Tape has been mounted\n" ,td->devstat.devno); -break ; -default : -// print nothing -break ; - } - td->medium_state = newstate; -out: -return ; -} - - -/******************************************************************* -* TAPE Exported Functions -*******************************************************************/ - -EXPORT_SYMBOL (tape_register_discipline); -EXPORT_SYMBOL (tape_unregister_discipline); -EXPORT_SYMBOL (tape_dbf_area); -EXPORT_SYMBOL (tape_alloc_ccw_req); -EXPORT_SYMBOL (tape_free_ccw_req); -EXPORT_SYMBOL (tape_state_set); -EXPORT_SYMBOL (tape_state_get); -EXPORT_SYMBOL (tape_med_state_set); -EXPORT_SYMBOL (tape_state_verbose); -EXPORT_SYMBOL (tape_op_verbose); -EXPORT_SYMBOL (tape_dump_sense); -EXPORT_SYMBOL (tape_dump_sense_dbf); -EXPORT_SYMBOL (tape_do_io); -EXPORT_SYMBOL (tape_do_io_irq); -EXPORT_SYMBOL (tape_do_io_and_wait); -EXPORT_SYMBOL (tape_remove_ccw_req); -EXPORT_SYMBOL (tape_get_active_ccw_req);