📄 s390io.c
字号:
/* * Check whether we must issue a SENSE CCW ourselves if there is no * concurrent sense facility installed for the subchannel. * * Note: We should check for ioinfo[irq]->ui.flags.consns but VM * violates the ESA/390 architecture and doesn't present an * operand exception for virtual devices without concurrent * sense facility available/supported when enabling the * concurrent sense facility. */ if ( ( ( ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_UNIT_CHECK ) && ( !issense ) ) || ( ioinfo[irq]->ui.flags.delsense && ending_status ) ) { int ret_io; ccw1_t *s_ccw = &ioinfo[irq]->senseccw; unsigned long s_flag = 0; if ( ending_status ) { /* * We copy the current status information into the device driver * status area. Then we can use the local devstat area for device * sensing. When finally calling the IRQ handler we must not overlay * the original device status but copy the sense data only. */ memcpy( action->dev_id, &(ioinfo[irq]->devstat), sizeof( devstat_t) ); s_ccw->cmd_code = CCW_CMD_BASIC_SENSE; s_ccw->cda = (__u32)virt_to_phys( ioinfo[irq]->devstat.ii.sense.data); s_ccw->count = SENSE_MAX_COUNT; s_ccw->flags = CCW_FLAG_SLI; /* * If free_irq() or a sync do_IO/s390_start_IO() is in * process we have to sense synchronously */ if ( ioinfo[irq]->ui.flags.unready || ioinfo[irq]->ui.flags.syncio ) { s_flag = DOIO_WAIT_FOR_INTERRUPT; } /* endif */ /* * Reset status info * * It does not matter whether this is a sync. or async. * SENSE request, but we have to assure we don't call * the irq handler now, but keep the irq in busy state. * In sync. mode s390_process_IRQ() is called recursively, * while in async. mode we re-enter do_IRQ() with the * next interrupt. * * Note : this may be a delayed sense request ! */ allow4handler = 0; ioinfo[irq]->ui.flags.fast = 0; ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; ioinfo[irq]->ui.flags.delsense = 0; ioinfo[irq]->devstat.cstat = 0; ioinfo[irq]->devstat.dstat = 0; ioinfo[irq]->devstat.rescnt = SENSE_MAX_COUNT; ioinfo[irq]->ui.flags.w4sense = 1; ret_io = s390_start_IO( irq, s_ccw, 0xE2C5D5E2, // = SENSe 0, // n/a s_flag); } else { /* * we received an Unit Check but we have no final * status yet, therefore we must delay the SENSE * processing. However, we must not report this * intermediate status to the device interrupt * handler. */ ioinfo[irq]->ui.flags.fast = 0; ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.delsense = 1; allow4handler = 0; } /* endif */ } /* endif */ /* * we allow for the device action handler if . * - we received ending status * - the action handler requested to see all interrupts * - we received a PCI * - fast notification was requested (primary status) * - unsollicited interrupts * */ if ( allow4handler ) { allow4handler = ending_status || ( ioinfo[irq]->ui.flags.repall ) || ( ioinfo[irq]->devstat.ii.irb.scsw.cstat & SCHN_STAT_PCI ) || ( (ioinfo[irq]->ui.flags.fast ) && (stctl & SCSW_STCTL_PRIM_STATUS) ) || ( ioinfo[irq]->ui.flags.oper == 0 ); } /* endif */ /* * We used to copy the device status information right before * calling the device action handler. However, in status * pending situations during do_IO() or halt_IO(), as well as * enable_subchannel/disable_subchannel processing we must * synchronously return the status information and must not * call the device action handler. * */ if ( allow4handler ) { /* * if we were waiting for sense data we copy the sense * bytes only as the original status information was * saved prior to sense already. */ if ( ioinfo[irq]->ui.flags.w4sense ) { int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;#if CONFIG_DEBUG_IO if ( irq != cons_dev ) printk( "s390_process_IRQ( %04X ) : " "BASIC SENSE bytes avail %d\n", irq, sense_count );#endif ioinfo[irq]->ui.flags.w4sense = 0; ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FLAG_SENSE_AVAIL; ((devstat_t *)(action->dev_id))->scnt = sense_count; if ( sense_count >= 0 ) { memcpy( ((devstat_t *)(action->dev_id))->ii.sense.data, &(ioinfo[irq]->devstat.ii.sense.data), sense_count); } else {#if 1 panic( "s390_process_IRQ(%04x) encountered " "negative sense count\n", irq);#else printk( KERN_CRIT"s390_process_IRQ(%04x) encountered " "negative sense count\n", irq);#endif } /* endif */ } else { memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); } /* endif */ } /* endif */ /* * for status pending situations other than deferred interrupt * conditions detected by s390_process_IRQ() itself we must not * call the handler. This will synchronously be reported back * to the caller instead, e.g. when detected during do_IO(). */ if ( ioinfo[irq]->ui.flags.s_pend || ioinfo[irq]->ui.flags.unready ) allow4handler = 0; /* * Call device action handler if applicable */ if ( allow4handler ) { /* * We only reset the busy condition when we are sure that no further * interrupt is pending for the current I/O request (ending_status). */ if ( ending_status || !ioinfo[irq]->ui.flags.oper ) { ioinfo[irq]->ui.flags.oper = 1; /* dev IS oper */ ioinfo[irq]->ui.flags.busy = 0; ioinfo[irq]->ui.flags.doio = 0; ioinfo[irq]->ui.flags.haltio = 0; ioinfo[irq]->ui.flags.fast = 0; ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; ((devstat_t *)(action->dev_id))->flag |= DEVSTAT_FINAL_STATUS; action->handler( irq, action->dev_id, ®s); // // reset intparm after final status or we will badly present unsolicited // interrupts with a intparm value possibly no longer valid. // ioinfo[irq]->devstat.intparm = 0; // // Was there anything queued ? Start the pending channel program // if there is one. // if ( ioinfo[irq]->ui.flags.doio_q ) { int ret; ret = s390_start_IO( irq, ioinfo[irq]->qcpa, ioinfo[irq]->qintparm, ioinfo[irq]->qlpm, ioinfo[irq]->qflag); ioinfo[irq]->ui.flags.doio_q = 0; /* * If s390_start_IO() failed call the device's interrupt * handler, the IRQ related devstat area was setup by * s390_start_IO() accordingly already (status pending * condition). */ if ( ret ) { action->handler( irq, action->dev_id, ®s); } /* endif */ } /* endif */ } else { ioinfo[irq]->ui.flags.w4final = 1; action->handler( irq, action->dev_id, ®s); } /* endif */ } /* endif */ break; case 3: /* device not operational */ ioinfo[irq]->ui.flags.oper = 0; ioinfo[irq]->ui.flags.busy = 0; ioinfo[irq]->ui.flags.doio = 0; ioinfo[irq]->ui.flags.haltio = 0; ioinfo[irq]->devstat.cstat = 0; ioinfo[irq]->devstat.dstat = 0; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS; /* * When we find a device "not oper" we save the status * information into the device status area and call the * device specific interrupt handler. * * Note: currently we don't have any way to reenable * the device unless an unsolicited interrupt * is presented. We don't check for spurious * interrupts on "not oper" conditions. */ if ( ( ioinfo[irq]->ui.flags.fast ) && ( ioinfo[irq]->ui.flags.w4final ) ) { /* * If a new request was queued already, we have * to simulate the "not oper" status for the * queued request by switching the "intparm" value * and notify the interrupt handler. */ if ( ioinfo[irq]->ui.flags.doio_q ) { ioinfo[irq]->devstat.intparm = ioinfo[irq]->qintparm; } /* endif */ } /* endif */ ioinfo[irq]->ui.flags.fast = 0; ioinfo[irq]->ui.flags.repall = 0; ioinfo[irq]->ui.flags.w4final = 0; memcpy( action->dev_id, &(ioinfo[irq]->devstat), sdevstat ); ioinfo[irq]->devstat.intparm = 0; if ( !ioinfo[irq]->ui.flags.s_pend ) action->handler( irq, action->dev_id, ®s); ending_status = 1; break; } /* endswitch */ return( ending_status );}/* * Set the special i/o-interruption sublass 7 for the * device specified by parameter irq. There can only * be a single device been operated on this special * isc. This function is aimed being able to check * on special device interrupts in disabled state, * without having to delay I/O processing (by queueing) * for non-console devices. * * Setting of this isc is done by set_cons_dev(), while * reset_cons_dev() resets this isc and re-enables the * default isc3 for this device. wait_cons_dev() allows * to actively wait on an interrupt for this device in * disabed state. When the interrupt condition is * encountered, wait_cons_dev(9 calls do_IRQ() to have * the console device driver processing the interrupt. */int set_cons_dev( int irq ){ int ccode; unsigned long cr6 __attribute__ ((aligned (8))); int rc = 0; if ( cons_dev != -1 ) { rc = -EBUSY; } else if ( (irq > highest_subchannel) || (irq < 0) ) { rc = -ENODEV; } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); } else { /* * modify the indicated console device to operate * on special console interrupt sublass 7 */ ccode = stsch( irq, &(ioinfo[irq]->schib) ); if (ccode) { rc = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; } else { ioinfo[irq]->schib.pmcw.isc = 7; ccode = msch( irq, &(ioinfo[irq]->schib) ); if (ccode) { rc = -EIO; } else { cons_dev = irq; /* * enable console I/O-interrupt sublass 7 */ asm volatile ("STCTL 6,6,%0": "=m" (cr6)); cr6 |= 0x01000000; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); } /* endif */ } /* endif */ } /* endif */ return( rc);}int reset_cons_dev( int irq){ int rc = 0; int ccode; long cr6 __attribute__ ((aligned (8))); if ( cons_dev != -1 ) { rc = -EBUSY; } else if ( (irq > highest_subchannel) || (irq < 0) ) { rc = -ENODEV; } else if ( ioinfo[irq] == INVALID_STORAGE_AREA ) { return( -ENODEV); } else { /* * reset the indicated console device to operate * on default console interrupt sublass 3 */ ccode = stsch( irq, &(ioinfo[irq]->schib) ); if (ccode) { rc = -ENODEV; ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER; } else { ioinfo[irq]->schib.pmcw.isc = 3; ccode = msch( irq, &(ioinfo[irq]->schib) ); if (ccode) { rc = -EIO; } else { cons_dev = -1; /* * disable special console I/O-interrupt sublass 7 */ asm volatile ("STCTL 6,6,%0": "=m" (cr6)); cr6 &= 0xFEFFFFFF; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); } /* endif */ } /* endif */ } /* endif */ return( rc);}int wait_cons_dev( int irq ){ int rc = 0; long save_cr6; if ( irq == cons_dev ) { /* * before entering the spinlock we may already have * processed the interrupt on a different CPU ... */ if ( ioinfo[irq]->ui.flags.busy == 1 ) { long cr6 __attribute__ ((aligned (8))); /* * disable all, but isc 7 (console device) */ asm volatile ("STCTL 6,6,%0": "=m" (cr6)); save_cr6 = cr6; cr6 &= 0x01FFFFFF; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); do { tpi_info_t tpi_info; if (tpi(&tpi_info) == 1) { s390_process_IRQ( tpi_info.irq ); } else { s390irq_spin_unlock(irq); tod_wait(100); s390irq_spin_lock(irq); } eieio(); } while (ioinfo[irq]->ui.flags.busy == 1); /* * restore previous isc value */ asm volatile ("STCTL 6,6,%0": "=m" (cr6)); cr6 = save_cr6; asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory"); } /* endif */ } else { rc = EINVAL; } /* endif */ return(rc);}int enable_cpu_sync_isc( int irq ){ int ccode; long cr6 __attribute__ ((aligned (8))); int count = 0; int rc = 0; if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA ) { ccode = stsch( irq, &(ioinfo[irq]->schib) ); if ( !ccode ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -