📄 tape.c
字号:
debug_int_exception (tape_debug_area,3,rc);#endif /* TAPE_DEBUG */ kfree (ti); } else { s390irq_spin_lock_irqsave (irq, lockflags); if (first_tape_info == NULL) { first_tape_info = ti; } else { tempti = first_tape_info; while (tempti->next != NULL) tempti = tempti->next; tempti->next = ti; } s390irq_spin_unlock_irqrestore (irq, lockflags); } } tape_num+=2; } str++; }}/* SECTION: Managing wrappers for ccwcache */#define TAPE_EMERGENCY_REQUESTS 16static ccw_req_t *tape_emergency_req[TAPE_EMERGENCY_REQUESTS] ={NULL,};static spinlock_t tape_emergency_req_lock = SPIN_LOCK_UNLOCKED;static voidtape_init_emergency_req (void){ int i; for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) { tape_emergency_req[i] = (ccw_req_t *) get_free_page (GFP_KERNEL); }}#ifdef MODULE // We only cleanup the emergency requests on module unload.static voidtape_cleanup_emergency_req (void){ int i; for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) { if (tape_emergency_req[i]) free_page ((long) (tape_emergency_req[i])); else printk (KERN_WARNING PRINTK_HEADER "losing one page for 'in-use' emergency request\n"); }}#endifccw_req_t *tape_alloc_request (char *magic, int cplength, int datasize){ ccw_req_t *rv = NULL; int i; if ((rv = ccw_alloc_request (magic, cplength, datasize)) != NULL) { return rv; } if (cplength * sizeof (ccw1_t) + datasize + sizeof (ccw_req_t) > PAGE_SIZE) { return NULL; } spin_lock (&tape_emergency_req_lock); for (i = 0; i < TAPE_EMERGENCY_REQUESTS; i++) { if (tape_emergency_req[i] != NULL) { rv = tape_emergency_req[i]; tape_emergency_req[i] = NULL; } } spin_unlock (&tape_emergency_req_lock); if (rv) { memset (rv, 0, PAGE_SIZE); rv->cache = (kmem_cache_t *) (tape_emergency_req + i); strncpy ((char *) (&rv->magic), magic, 4); ASCEBC ((char *) (&rv->magic), 4); rv->cplength = cplength; rv->datasize = datasize; rv->data = (void *) ((long) rv + PAGE_SIZE - datasize); rv->cpaddr = (ccw1_t *) ((long) rv + sizeof (ccw_req_t)); } return rv;}voidtape_free_request (ccw_req_t * request){ if (request->cache >= (kmem_cache_t *) tape_emergency_req && request->cache <= (kmem_cache_t *) (tape_emergency_req + TAPE_EMERGENCY_REQUESTS)) { *((ccw_req_t **) (request->cache)) = request; } else { clear_normalized_cda ((ccw1_t *) (request->cpaddr)); // avoid memory leak caused by modeset_byte ccw_free_request (request); }}/* * Allocate a ccw request and reserve it for tape driver */inline ccw_req_t *tape_alloc_ccw_req (tape_info_t * ti, int cplength, int datasize){ char tape_magic_id[] = "tape"; ccw_req_t *cqr = NULL; if (!ti) return NULL; cqr = tape_alloc_request (tape_magic_id, cplength, datasize); if (!cqr) {#ifdef TAPE_DEBUG PRINT_WARN ("empty CQR generated\n");#endif } cqr->magic = TAPE_MAGIC; /* sets an identifier for tape driver */ cqr->device = ti; /* save pointer to tape info */ return cqr;}/* * Find the tape_info_t structure associated with irq */static inline tape_info_t *tapedev_find_info (int irq){ tape_info_t *ti; ti = first_tape_info; if (ti != NULL) do { if (ti->devinfo.irq == irq) break; } while ((ti = (tape_info_t *) ti->next) != NULL); return ti;}#define QUEUE_THRESHOLD 5/* * Tape interrupt routine, called from Ingo's I/O layer */voidtape_irq (int irq, void *int_parm, struct pt_regs *regs){ tape_info_t *ti = tapedev_find_info (irq); /* analyse devstat and fire event */ if (ti->devstat.dstat & DEV_STAT_UNIT_CHECK) { tapestate_event (ti, TE_ERROR); } else if (ti->devstat.dstat & (DEV_STAT_DEV_END)) { tapestate_event (ti, TE_DONE); } else tapestate_event (ti, TE_OTHER);}int tape_oper_handler ( int irq, struct _devreg *dreg) { tape_info_t* ti=first_tape_info; tape_info_t* newtape; int rc,tape_num,retries=0,i; s390_dev_info_t dinfo; tape_discipline_t* disc;#ifdef CONFIG_DEVFS_FS tape_frontend_t* frontend;#endif long lockflags; while ((ti!=NULL) && (ti->devinfo.irq!=irq)) ti=ti->next; if (ti!=NULL) { // irq is (still) used by tape. tell ingo to try again later PRINT_WARN ("Oper handler for irq %d called while irq still (internaly?) used.\n",irq); return -EAGAIN; } // irq is not used by tape rc = get_dev_info_by_irq (irq, &dinfo); if (rc == -ENODEV) { retries++; rc = get_dev_info_by_irq (irq, &dinfo); if (retries > 5) { PRINT_WARN ("No device information for new dev. could be retrieved.\n"); return -ENODEV; } } disc = first_discipline; while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type)) disc = (tape_discipline_t *) (disc->next); if (disc == NULL) PRINT_WARN ("No matching discipline for cu_type %x found, ignoring device %04x.\n",dinfo.sid_data.cu_type,dinfo.devno); if (rc == -ENODEV) PRINT_WARN ("No device information for new dev. could be retrieved.\n"); if ((disc == NULL) || (rc == -ENODEV)) return -ENODEV; /* Allocate tape structure */ ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC); if (ti == NULL) { PRINT_INFO ( "tape: can't allocate memory for " "tape info structure\n"); return -ENOBUFS; } memset(ti,0,sizeof(tape_info_t)); ti->discipline = disc; disc->tape = ti; tape_num=0; if (*tape) { // we have static device ranges, so fingure out the tape_num of the attached tape for (i=0;i<devregct;i++) if (tape_devreg[i]->ci.devno==dinfo.devno) { tape_num=2*i; break; } } else { // we are running in autoprobe mode, find a free tape_num newtape=first_tape_info; while (newtape!=NULL) { if (newtape->rew_minor==tape_num) { // tape num in use. try next one tape_num+=2; newtape=first_tape_info; } else { // tape num not used by newtape. look at next tape info newtape=newtape->next; } } } rc = tape_setup (ti, irq, tape_num); if (rc) { kfree (ti); return -ENOBUFS; }#ifdef CONFIG_DEVFS_FS for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) frontend->mkdevfstree(ti);#endif s390irq_spin_lock_irqsave (irq,lockflags); if (first_tape_info == NULL) { first_tape_info = ti; } else { newtape = first_tape_info; while (newtape->next != NULL) newtape = newtape->next; newtape->next = ti; } s390irq_spin_unlock_irqrestore (irq, lockflags); return 0;}static voidtape_noper_handler ( int irq, int status ) { tape_info_t *ti=first_tape_info; tape_info_t *lastti;#ifdef CONFIG_DEVFS_FS tape_frontend_t *frontend;#endif long lockflags; s390irq_spin_lock_irqsave(irq,lockflags); while (ti!=NULL && ti->devinfo.irq!=irq) ti=ti->next; if (ti==NULL) return; if (tapestate_get(ti)!=TS_UNUSED) { // device is in use! PRINT_WARN ("Tape #%d was detached while it was busy. Expect errors!",ti->blk_minor/2); tapestate_set(ti,TS_NOT_OPER); ti->rc=-ENODEV; ti->wanna_wakeup=1; switch (tapestate_get(ti)) { case TS_REW_RELEASE_INIT: tapestate_set(ti,TS_NOT_OPER); wake_up (&ti->wq); break;#ifdef CONFIG_S390_TAPE_BLOCK case TS_BLOCK_INIT: tapestate_set(ti,TS_NOT_OPER); schedule_tapeblock_exec_IO(ti); break;#endif default: tapestate_set(ti,TS_NOT_OPER); wake_up_interruptible (&ti->wq); } } else { // device is unused! PRINT_WARN ("Tape #%d was detached.\n",ti->blk_minor/2); 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; }#ifdef CONFIG_DEVFS_FS for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next) frontend->rmdevfstree(ti); tape_rmdevfsroots(ti);#endif kfree(ti); } s390irq_spin_unlock_irqrestore(irq,lockflags); return;}voidtape_dump_sense (devstat_t * stat){#ifdef TAPE_DEBUG int sl;#endif#if 0 PRINT_WARN ("------------I/O resulted in unit check:-----------\n"); for (sl = 0; sl < 4; sl++) { PRINT_WARN ("Sense:"); for (sct = 0; sct < 8; sct++) { PRINT_WARN (" %2d:0x%02X", 8 * sl + sct, stat->ii.sense.data[8 * sl + sct]); } PRINT_WARN ("\n"); } 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]);#endif#ifdef TAPE_DEBUG debug_text_event (tape_debug_area,3,"SENSE:"); for (sl=0;sl<31;sl++) { debug_int_event (tape_debug_area,3,stat->ii.sense.data[sl]); } debug_int_exception (tape_debug_area,3,stat->ii.sense.data[31]);#endif}/* * Setup tape_info_t structure of a tape device */inttape_setup (tape_info_t * ti, int irq, int minor){ long lockflags; int rc = 0; if (minor>254) { PRINT_WARN ("Device id %d on irq %d will not be accessible since this driver is restricted to 128 devices.\n",minor/2,irq); return -EINVAL; } rc = get_dev_info_by_irq (irq, &(ti->devinfo)); if (rc == -ENODEV) { /* end of device list */ return rc; } ti->rew_minor = minor; ti->nor_minor = minor + 1; ti->blk_minor = minor;#ifdef CONFIG_DEVFS_FS tape_mkdevfsroots(ti);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -