📄 tape.c
字号:
/*********************************************************************** * 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 <cotte@de.ibm.com> * Tuan Ngo-Anh <ngoanh@de.ibm.com> * *********************************************************************** */#include "tapedefs.h"#include <linux/config.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/version.h>#include <linux/proc_fs.h>#include <linux/init.h>#include <asm/types.h>#include <asm/ccwcache.h>#include <asm/idals.h>#include <asm/ebcdic.h>#include <linux/compatmac.h>#ifdef MODULE#include <linux/module.h>#endif #include <asm/debug.h>#ifdef CONFIG_S390_TAPE_DYNAMIC#include <asm/s390dyn.h>#endif#include "tape.h"#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:"/* state handling routines */inline void tapestate_set (tape_info_t * ti, int newstate);inline int tapestate_get (tape_info_t * ti);void tapestate_event (tape_info_t * ti, int event);/* our globals */tape_info_t *first_tape_info = NULL;tape_discipline_t *first_discipline = NULL;tape_frontend_t *first_frontend = NULL;devreg_t* tape_devreg[128];int devregct=0;#ifdef TAPE_DEBUGdebug_info_t *tape_debug_area = NULL;#endifchar* state_verbose[TS_SIZE]={ "TS_UNUSED", "TS_IDLE", "TS_DONE", "TS_FAILED", "TS_BLOCK_INIT", "TS_BSB_INIT", "TS_BSF_INIT", "TS_DSE_INIT", "TS_EGA_INIT", "TS_FSB_INIT", "TS_FSF_INIT", "TS_LDI_INIT", "TS_LBL_INIT", "TS_MSE_INIT", "TS_NOP_INIT", "TS_RBA_INIT", "TS_RBI_INIT", "TS_RBU_INIT", "TS_RBL_INIT", "TS_RDC_INIT", "TS_RFO_INIT", "TS_RSD_INIT", "TS_REW_INIT", "TS_REW_RELEASE_INIT", "TS_RUN_INIT", "TS_SEN_INIT", "TS_SID_INIT", "TS_SNP_INIT", "TS_SPG_INIT", "TS_SWI_INIT", "TS_SMR_INIT", "TS_SYN_INIT", "TS_TIO_INIT", "TS_UNA_INIT", "TS_WRI_INIT", "TS_WTM_INIT", "TS_NOT_OPER"};char* event_verbose[TE_SIZE]= { "TE_START", "TE_DONE", "TE_FAILED", "TE_ERROR", "TE_OTHER"};/* our root devfs handle */#ifdef CONFIG_DEVFS_FSdevfs_handle_t tape_devfs_root_entry;inline voidtape_mkdevfsroots (tape_info_t* ti) { char devno [5]; sprintf (devno,"%04x",ti->devinfo.devno); ti->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, ti);}inline voidtape_rmdevfsroots (tape_info_t* ti){ devfs_unregister (ti->devfs_dir);}#endif#ifdef CONFIG_PROC_FS/* our proc tapedevices entry */static struct proc_dir_entry *tape_devices_entry;typedef struct { char *data; int len;} tempinfo_t;static inttape_devices_open (struct inode *inode, struct file *file){ int size=80; tape_info_t* ti; tempinfo_t* tempinfo; char* data; int pos=0; tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL); if (!tempinfo) return -ENOMEM; for (ti=first_tape_info;ti!=NULL;ti=ti->next) size+=80; // FIXME: Guess better! data=vmalloc(size); if (!data) { kfree (tempinfo); return -ENOMEM; } pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n"); for (ti=first_tape_info;ti!=NULL;ti=ti->next) { pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",ti->rew_minor/2, ti->devinfo.devno,ti->devinfo.sid_data.cu_type, ti->devinfo.sid_data.cu_model,ti->devinfo.sid_data.dev_type, ti->devinfo.sid_data.dev_model,((tapestate_get(ti) >= 0) && (tapestate_get(ti) < TS_SIZE)) ? state_verbose[tapestate_get (ti)] : "TS UNKNOWN"); } tempinfo->len=pos; tempinfo->data=data; file->private_data= (void*) tempinfo;#ifdef MODULE MOD_INC_USE_COUNT;#endif return 0;}static ssize_ttape_devices_read (struct file *file, char *user_buf, size_t user_len, loff_t * offset){ loff_t len; tempinfo_t *p_info = (tempinfo_t *) file->private_data; if (*offset >= p_info->len) { return 0; /* 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; return len; /* number of bytes "read" */ }}static inttape_devices_release (struct inode *inode, struct file *file){ int rc = 0; tempinfo_t *p_info = (tempinfo_t *) file->private_data; if (p_info) { if (p_info->data) vfree (p_info->data); kfree (p_info); }#ifdef MODULE MOD_DEC_USE_COUNT;#endif return rc;}static struct file_operations tape_devices_file_ops ={ read:tape_devices_read, /* read */ open:tape_devices_open, /* open */ release:tape_devices_release, /* close */};static struct inode_operations tape_devices_inode_ops ={#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) default_file_ops:&tape_devices_file_ops /* file ops */#endif /* LINUX_IS_24 */};#endif /* CONFIG_PROC_FS *//* SECTION: Parameters for tape */char *tape[256] = { NULL, };#ifndef MODULEstatic char tape_parm_string[1024] __initdata = { 0, };static voidtape_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; } memset (tape[count], 0, len * sizeof (char)); memcpy (tape[count], tmp, len * sizeof (char)); count++; tmp = end; };}void __inittape_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 __inittape_parm_call_setup (char *str){ int dummy; tape_parm_setup (str, &dummy); return 1;}#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16))__setup("tape=", tape_parm_call_setup);#endif /* kernel <2.2.19 */#endif /* not defined MODULE */static inline inttape_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;}static inline devreg_t *tape_create_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;}static inline voidtape_parm_parse (char **str){ char *temp; int from, to,i,irq=0,rc,retries=0,tape_num=0; s390_dev_info_t dinfo; tape_info_t* ti,*tempti; tape_discipline_t* disc; long lockflags; if (*str==NULL) { /* no params present -> leave */ return; } while (*str) { temp = *str; from = 0; to = 0; /* turn off autodetect mode, if any range is present */ from = tape_parm_strtoul (temp, &temp); to = from; if (*temp == '-') { temp++; to = tape_parm_strtoul (temp, &temp); } for (i=from;i<=to;i++) { retries=0; // register for attch/detach of a devno tape_devreg[devregct]=tape_create_devreg(i); if (tape_devreg[devregct]==NULL) { PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n",i); } else { s390_device_register (tape_devreg[devregct++]); } // we are activating a device if it is present for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) { rc = get_dev_info_by_irq (irq, &dinfo); disc = first_discipline; while ((dinfo.devno == i) && (disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type)) disc = (tape_discipline_t *) (disc->next); if ((disc == NULL) || (rc == -ENODEV) || (i!=dinfo.devno)) { continue; }#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"det irq: "); debug_int_event (tape_debug_area,3,irq); debug_text_event (tape_debug_area,3,"cu: "); debug_int_event (tape_debug_area,3,disc->cu_type);#endif /* TAPE_DEBUG */ PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2); /* Allocate tape structure */ ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC); if (ti == NULL) {#ifdef TAPE_DEBUG debug_text_exception (tape_debug_area,3,"ti:no mem ");#endif /* TAPE_DEBUG */ PRINT_INFO ("tape: can't allocate memory for " "tape info structure\n"); continue; } memset(ti,0,sizeof(tape_info_t)); ti->discipline = disc; disc->tape = ti; rc = tape_setup (ti, irq, tape_num); if (rc) {#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"tsetup err");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -