patch-2.4.2 linux/arch/s390/kernel/s390io.c
Next file: linux/arch/s390/kernel/s390mach.c
Previous file: linux/arch/s390/kernel/s390fpu.c
Back to the patch index
Back to the overall index
- Lines: 4606
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.4.1/linux/arch/s390/kernel/s390io.c
- Orig date:
Fri Aug 4 16:15:37 2000
diff -u --recursive --new-file v2.4.1/linux/arch/s390/kernel/s390io.c linux/arch/s390/kernel/s390io.c
@@ -1,4605 +0,0 @@
-/*
- * arch/s390/kernel/s390io.c
- * S/390 common I/O routines
- *
- * S390 version
- * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH,
- * IBM Corporation
- * Author(s): Ingo Adlung (adlung@de.ibm.com)
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/kernel_stat.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/interrupt.h>
-#include <linux/malloc.h>
-#include <linux/string.h>
-#include <linux/smp.h>
-#include <linux/tasks.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <linux/bootmem.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/bitops.h>
-#include <asm/smp.h>
-#include <asm/pgtable.h>
-#include <asm/delay.h>
-#include <asm/processor.h>
-#include <asm/lowcore.h>
-
-#include <asm/s390io.h>
-#include <asm/s390dyn.h>
-#include <asm/s390mach.h>
-
-#ifndef TRUE
-#define TRUE 1
-#define FALSE 0
-#endif
-
-#undef CONFIG_DEBUG_IO
-
-#define REIPL_DEVID_MAGIC 0x87654321
-
-struct irqaction init_IRQ_action;
-unsigned int highest_subchannel;
-ioinfo_t *ioinfo_head = NULL;
-ioinfo_t *ioinfo_tail = NULL;
-ioinfo_t *ioinfo[__MAX_SUBCHANNELS] = {
- [0 ... (__MAX_SUBCHANNELS-1)] = INVALID_STORAGE_AREA
-};
-
-static spinlock_t sync_isc; // synchronous irq processing lock
-static psw_t io_sync_wait; // wait PSW for sync IO, prot. by sync_isc
-static psw_t io_new_psw; // save I/O new PSW, prot. by sync_isc
-static int cons_dev = -1; // identify console device
-static int init_IRQ_complete = 0;
-static schib_t init_schib;
-static __u64 irq_IPL_TOD;
-
-/*
- * Dummy controller type for unused interrupts
- */
-int do_none(unsigned int irq, int cpu, struct pt_regs * regs) { return 0;}
-int enable_none(unsigned int irq) { return(-ENODEV); }
-int disable_none(unsigned int irq) { return(-ENODEV); }
-
-struct hw_interrupt_type no_irq_type = {
- "none",
- do_none,
- enable_none,
- disable_none
-};
-
-static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
-static int s390_setup_irq(unsigned int irq, struct irqaction * new);
-static void s390_process_subchannels( void);
-static void s390_device_recognition( void);
-static int s390_validate_subchannel( int irq);
-static int s390_SenseID( int irq, senseid_t *sid);
-static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid);
-static int s390_process_IRQ( unsigned int irq );
-static int s390_DevicePathVerification( int irq );
-
-extern int do_none(unsigned int irq, int cpu, struct pt_regs * regs);
-extern int enable_none(unsigned int irq);
-extern int disable_none(unsigned int irq);
-extern void tod_wait(unsigned long usecs);
-
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm );
-
-void s390_displayhex(char *str,void *ptr,s32 cnt);
-
-void s390_displayhex(char *str,void *ptr,s32 cnt)
-{
- s32 cnt1,cnt2,maxcnt2;
- u32 *currptr=(__u32 *)ptr;
-
- printk("\n%s\n",str);
-
- for(cnt1=0;cnt1<cnt;cnt1+=16)
- {
- printk("%08lX ",(unsigned long)currptr);
- maxcnt2=cnt-cnt1;
- if(maxcnt2>16)
- maxcnt2=16;
- for(cnt2=0;cnt2<maxcnt2;cnt2+=4)
- printk("%08X ",*currptr++);
- printk("\n");
- }
-}
-
-int s390_request_irq( unsigned int irq,
- void (*handler)(int, void *, struct pt_regs *),
- unsigned long irqflags,
- const char *devname,
- void *dev_id)
-{
- int retval;
- struct irqaction *action;
-
- if (irq >= __MAX_SUBCHANNELS)
- return -EINVAL;
-
- if ( !handler || !dev_id )
- return -EINVAL;
-
- /*
- * during init_IRQ() processing we don't have memory
- * management yet, thus need to use a statically
- * allocated irqaction control block
- */
- if ( init_IRQ_complete )
- {
- action = (struct irqaction *)
- kmalloc(sizeof(struct irqaction), GFP_KERNEL);
- }
- else
- {
- action = &init_IRQ_action;
-
- } /* endif */
-
- if (!action)
- {
- return -ENOMEM;
-
- } /* endif */
-
- action->handler = handler;
- action->flags = irqflags;
- action->mask = 0;
- action->name = devname;
- action->next = NULL;
- action->dev_id = dev_id;
-
- retval = s390_setup_irq( irq, action);
-
- if ( !retval )
- {
- retval = s390_DevicePathVerification( irq );
- }
- else if ( retval && init_IRQ_complete )
- {
- kfree(action);
-
- } /* endif */
-
- return retval;
-}
-
-void s390_free_irq(unsigned int irq, void *dev_id)
-{
- unsigned int flags;
- int ret;
-
- unsigned int count = 0;
-
- if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return;
-
- } /* endif */
-
- s390irq_spin_lock_irqsave( irq, flags);
-
-#ifdef CONFIG_KERNEL_DEBUG
- if ( irq != cons_dev )
- {
- printk("Trying to free IRQ%d\n",irq);
-
- } /* endif */
-#endif
-
- /*
- * disable the device and reset all IRQ info if
- * the IRQ is actually owned by the handler ...
- */
- if ( ioinfo[irq]->irq_desc.action )
- {
- if ( (dev_id == ioinfo[irq]->irq_desc.action->dev_id )
- || (dev_id == (devstat_t *)REIPL_DEVID_MAGIC) )
- {
- /* start deregister */
- ioinfo[irq]->ui.flags.unready = 1;
-
- do
- {
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
-
- count++;
-
- if ( ret == -EBUSY )
- {
- int iret;
-
- /*
- * kill it !
- * ... we first try sync and eventually
- * try terminating the current I/O by
- * an async request, twice halt, then
- * clear.
- */
- if ( count < 3 )
- {
- iret = halt_IO( irq,
- 0xC8C1D3E3,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- halt_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 200000 ); /* 200 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
- }
- else
- {
- iret = clear_IO( irq,
- 0x40C3D3D9,
- DOIO_WAIT_FOR_INTERRUPT );
-
- if ( iret == -EBUSY )
- {
- clear_IO( irq, 0xC8C1D3E3, 0);
- s390irq_spin_unlock_irqrestore( irq, flags);
- tod_wait( 1000000 ); /* 1000 ms */
- s390irq_spin_lock_irqsave( irq, flags);
-
- } /* endif */
-
- } /* endif */
-
- if ( count == 3 )
- {
- /* give it a very last try ... */
- ioinfo[irq]->irq_desc.handler->disable(irq);
-
- if ( ioinfo[irq]->ui.flags.busy )
- {
- printk( KERN_CRIT"free_irq(%04X) "
- "- device %04X busy, retry "
- "count exceeded\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- break; /* sigh, let's give up ... */
-
- } /* endif */
-
- } /* endif */
-
- } while ( ret == -EBUSY );
-
- if ( init_IRQ_complete )
- kfree( ioinfo[irq]->irq_desc.action );
-
- ioinfo[irq]->irq_desc.action = NULL;
- ioinfo[irq]->ui.flags.ready = 0;
-
- ioinfo[irq]->irq_desc.handler->enable = &enable_none;
- ioinfo[irq]->irq_desc.handler->disable = &disable_none;
-
- ioinfo[irq]->ui.flags.unready = 0; /* deregister ended */
-
- s390irq_spin_unlock_irqrestore( irq, flags);
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, dev_id does not match !");
-
- } /* endif */
-
- }
- else
- {
- s390irq_spin_unlock_irqrestore( irq, flags);
-
- printk("free_irq() : error, no action block ... !");
-
- } /* endif */
-
-}
-
-/*
- * Generic enable/disable code
- */
-int disable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- /*
- * At this point we may actually have a pending interrupt being active
- * on another CPU. So don't touch the IRQ_INPROGRESS bit..
- */
- ioinfo[irq]->irq_desc.status |= IRQ_DISABLED;
- ret = ioinfo[irq]->irq_desc.handler->disable(irq);
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- synchronize_irq();
-
- return( ret);
-}
-
-int enable_irq(unsigned int irq)
-{
- unsigned long flags;
- int ret;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- s390irq_spin_lock_irqsave(irq, flags);
-
- ioinfo[irq]->irq_desc.status = 0;
- ret = ioinfo[irq]->irq_desc.handler->enable(irq);
-
- s390irq_spin_unlock_irqrestore(irq, flags);
-
- return(ret);
-}
-
-/*
- * Enable IRQ by modifying the subchannel
- */
-static int enable_subchannel( unsigned int irq)
-{
- int ret;
- int ccode;
- int retry = 5;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return( -ENODEV);
-
- /*
- * If a previous disable request is pending we reset it. However, this
- * status implies that the device may (still) be not-operational.
- */
- if ( ioinfo[irq]->ui.flags.d_disable )
- {
- ioinfo[irq]->ui.flags.d_disable = 0;
- ret = 0;
- }
- else
- {
-
- ccode = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- ioinfo[irq]->schib.pmcw.ena = 1;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (ccode) {
- case 0:
- ret = 0;
- break;
-
- case 1:
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parameter for interface compatibility
- * only. Bottom-half handling cannot be
- * required as this must be an
- * unsolicited interrupt (!busy).
- */
-
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EIO; /* might be overwritten */
- /* ... on re-driving */
- /* ... the msch() */
- retry--;
- break;
-
- case 3:
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- break;
-
- default:
- printk( KERN_CRIT"enable_subchannel(%04X) "
- " : ccode 2 on msch() for device "
- "%04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
- ret = -ENODEV; // never reached
- }
-
- } while ( (ccode == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * Disable IRQ by modifying the subchannel
- */
-static int disable_subchannel( unsigned int irq)
-{
- int cc; /* condition code */
- int ret; /* function return value */
- int retry = 5;
-
- if ( irq > highest_subchannel )
- {
- ret = -ENODEV;
- }
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else if ( ioinfo[irq]->ui.flags.busy )
- {
- /*
- * the disable function must not be called while there are
- * requests pending for completion !
- */
- ret = -EBUSY;
- }
- else
- {
- /*
- * If device isn't operational we have to perform delayed
- * disabling when the next interrupt occurs - unless the
- * irq is re-requested prior to the interrupt to occur.
- */
- cc = stsch(irq, &(ioinfo[irq]->schib) );
-
- if ( cc == 3 )
- {
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0;
- }
- else // cc == 0
- {
- ioinfo[irq]->schib.pmcw.ena = 0;
-
- do
- {
- cc = msch( irq, &(ioinfo[irq]->schib) );
-
- switch (cc) {
- case 0 :
- ret = 0; /* done */
- break;
-
- case 1 :
- /*
- * very bad, requires interrupt alike
- * processing, where "rbh" is a dummy
- * parm for interface compatibility
- * only. Bottom-half handling cannot
- * be required as this must be an
- * unsolicited interrupt (!busy).
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- s390_process_IRQ( irq );
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- ret = -EBUSY; /* might be overwritten */
- /* ... on re-driving the */
- /* ... msch() call */
- retry--;
- break;
-
- case 2 :
- /*
- * *** must not occur ! ***
- * *** ***
- * *** indicates our internal ***
- * *** interrupt accounting is out ***
- * *** of sync ===> panic() ***
- */
- printk( KERN_CRIT"disable_subchannel(%04X) "
- "- unexpected busy condition for "
- "device %04X received !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- ret = -ENODEV; // never reached
- break;
-
- case 3 :
- /*
- * should hardly occur ?!
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.d_disable = 1;
-
- ret = 0; /* if the device has gone we */
- /* ... don't need to disable */
- /* ... it anymore ! */
- break;
-
- default :
- ret = -ENODEV; // never reached ...
- break;
-
- } /* endswitch */
-
- } while ( (cc == 1) && retry );
-
- } /* endif */
-
- } /* endif */
-
- return( ret);
-}
-
-
-
-int s390_setup_irq( unsigned int irq, struct irqaction * new)
-{
- unsigned long flags;
- int rc = 0;
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * The following block of code has to be executed atomically
- */
- s390irq_spin_lock_irqsave( irq, flags);
-
- if ( ioinfo[irq]->irq_desc.action == NULL )
- {
- ioinfo[irq]->irq_desc.action = new;
- ioinfo[irq]->irq_desc.status = 0;
- ioinfo[irq]->irq_desc.handler->enable = &enable_subchannel;
- ioinfo[irq]->irq_desc.handler->disable = &disable_subchannel;
- ioinfo[irq]->irq_desc.handler->handle = &handle_IRQ_event;
-
- ioinfo[irq]->ui.flags.ready = 1;
-
- ioinfo[irq]->irq_desc.handler->enable(irq);
- }
- else
- {
- /*
- * interrupt already owned, and shared interrupts
- * aren't supported on S/390.
- */
- rc = -EBUSY;
-
- } /* endif */
-
- s390irq_spin_unlock_irqrestore(irq,flags);
-
- return( rc);
-}
-
-void s390_init_IRQ( void )
-{
- unsigned long flags; /* PSW flags */
- long cr6 __attribute__ ((aligned (8)));
-
- // Hopefully bh_count's will get set when we copy the prefix lowcore
- // structure to other CPI's ( DJB )
- softirq_active(smp_processor_id()) = 0;
- softirq_mask(smp_processor_id()) = 0;
- local_bh_count(smp_processor_id()) = 0;
- local_irq_count(smp_processor_id()) = 0;
- syscall_count(smp_processor_id()) = 0;
-
- asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
-
- /*
- * As we don't know about the calling environment
- * we assure running disabled. Before leaving the
- * function we resestablish the old environment.
- *
- * Note : as we don't need a system wide lock, therefore
- * we shouldn't use cli(), but __cli() as this
- * affects the current CPU only.
- */
- __save_flags(flags);
- __cli();
-
- /*
- * disable all interrupts
- */
- cr6 = 0;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_process_subchannels();
-
- /*
- * enable default I/O-interrupt sublass 3
- */
- cr6 = 0x10000000;
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- s390_device_recognition();
-
- init_IRQ_complete = 1;
-
- s390_init_machine_check();
-
- __restore_flags(flags);
-
- return;
-}
-
-
-/*
- * dummy handler, used during init_IRQ() processing for compatibility only
- */
-void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs)
-{
- /* this is a dummy handler only ... */
-}
-
-
-int s390_start_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* logical channel prog addr */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags */
-{
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
- int ret = 0;
-
- /*
- * The flag usage is mutal exclusive ...
- */
- if ( (flag & DOIO_RETURN_CHAN_END)
- && (flag & DOIO_REPORT_ALL ) )
- {
- return( -EINVAL );
-
- } /* endif */
-
- memset( &(ioinfo[irq]->orb), '\0', sizeof( orb_t) );
-
- /*
- * setup ORB
- */
- ioinfo[irq]->orb.intparm = (__u32)&ioinfo[irq]->u_intparm;
- ioinfo[irq]->orb.fmt = 1;
-
- ioinfo[irq]->orb.pfch = !(flag & DOIO_DENY_PREFETCH);
- ioinfo[irq]->orb.spnd = (flag & DOIO_ALLOW_SUSPEND);
- ioinfo[irq]->orb.ssic = ( (flag & DOIO_ALLOW_SUSPEND )
- && (flag & DOIO_SUPPRESS_INTER) );
-
- if ( flag & DOIO_VALID_LPM )
- {
- ioinfo[irq]->orb.lpm = lpm;
- }
- else
- {
- ioinfo[irq]->orb.lpm = ioinfo[irq]->opm;
-
- } /* endif */
-
- ioinfo[irq]->orb.cpa = (__u32)virt_to_phys( cpa);
-
- /*
- * If sync processing was requested we lock the sync ISC, modify the
- * device to present interrupts for this ISC only and switch the
- * CPU to handle this ISC + the console ISC exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc, psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Start subchannel" and process condition code
- */
- ccode = ssch( irq, &(ioinfo[irq]->orb) );
-
- switch ( ccode ) {
- case 0:
-
- if ( !ioinfo[irq]->ui.flags.w4sense )
- {
- /*
- * init the device driver specific devstat irb area
- *
- * Note : donīt clear saved irb info in case of sense !
- */
- memset( &((devstat_t *)ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
- } /* endif */
-
- /*
- * initialize device status information
- */
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_START_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- ioinfo[irq]->ui.flags.fast = 0;
- ioinfo[irq]->ui.flags.repall = 0;
-
- /*
- * Check for either early (FAST) notification requests
- * or if we are to return all interrupt info.
- * Default is to call IRQ handler at secondary status only
- */
- if ( flag & DOIO_RETURN_CHAN_END )
- {
- ioinfo[irq]->ui.flags.fast = 1;
- }
- else if ( flag & DOIO_REPORT_ALL )
- {
- ioinfo[irq]->ui.flags.repall = 1;
-
- } /* endif */
-
- ioinfo[irq]->ulpm = ioinfo[irq]->orb.lpm;
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- // __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- int io_sub = -1;
- struct _lowcore *lc = NULL;
- int count = 30000;
-
- /*
- * We shouldn't perform a TPI loop, waiting for an
- * interrupt to occur, but should load a WAIT PSW
- * instead. Otherwise we may keep the channel subsystem
- * busy, not able to present the interrupt. When our
- * sync. interrupt arrived we reset the I/O old PSW to
- * its original value.
- */
- memcpy( &io_new_psw, &lc->io_new_psw, sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "start_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&io_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
- if ( flag & DOIO_TIMEOUT )
- {
- tpi_info_t tpi_info;
-
- do
- {
- if ( tpi(&tpi_info) == 1 )
- {
- io_sub = tpi_info.irq;
- break;
- }
- else
- {
- count--;
- tod_wait(100); /* usecs */
-
- } /* endif */
-
- } while ( count );
- }
- else
- {
- asm volatile ("lpsw %0" : : "m" (io_sync_wait));
-
-io_wakeup:
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- } /* endif */
-
- if ( count )
- ready = s390_process_IRQ( io_sub );
-
- /*
- * surrender when retry count's exceeded ...
- */
-
- } while ( !( ( io_sub == irq )
- && ( ready == 1 ))
- && count );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- if ( !count )
- ret = -ETIMEDOUT;
-
- } /* endif */
-
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending status.
- * However, we must avoid calling the user action handler, as
- * it won't be prepared to handle a pending status during
- * do_IO() processing inline. This also implies that process_IRQ
- * must terminate synchronously - especially if device sensing
- * is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last path
- * has gone, except we have previously restricted the I/O to
- * a particular path. A condition code 1 (0 won't occur)
- * results in return code EIO as well as 3 with another path
- * than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - irb for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib) ,
- sizeof(schib_t));
-
-
- if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL)
- {
- sprintf( buffer, "s390_start_IO(%04X) - sense "
- "data for "
- "device %04X, after status pending\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->ii.sense.data,
- ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->rescnt);
-
- }
- }
-#endif
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- ioinfo[irq]->ui.flags.oper = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
-
- memcpy( ioinfo[irq]->irq_desc.action->dev_id,
- &(ioinfo[irq]->devstat),
- sizeof( devstat_t) );
-
-#if CONFIG_DEBUG_IO
- {
- char buffer[80];
-
- stsch(irq, &(ioinfo[irq]->schib) );
-
- sprintf( buffer, "s390_start_IO(%04X) - schib for "
- "device %04X, after 'not oper' status\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->schib),
- sizeof(schib_t));
- }
-#endif
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- } /* endif */
-
- return( ret);
-}
-
-int do_IO( int irq, /* IRQ */
- ccw1_t *cpa, /* channel program address */
- unsigned long user_intparm, /* interruption parameter */
- __u8 lpm, /* logical path mask */
- unsigned long flag) /* flags : see above */
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /* handler registered ? or free_irq() in process already ? */
- if ( !ioinfo[irq]->ui.flags.ready || ioinfo[irq]->ui.flags.unready )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Note: We ignore the device operational status - if not operational,
- * the SSCH will lead to an -ENODEV condition ...
- */
- if ( !ioinfo[irq]->ui.flags.busy ) /* last I/O completed ? */
- {
- ret = s390_start_IO( irq, cpa, user_intparm, lpm, flag);
- }
- else if ( ioinfo[irq]->ui.flags.fast )
- {
- /*
- * If primary status was received and ending status is missing,
- * the device driver won't be notified on the ending status
- * if early (fast) interrupt notification was requested.
- * Therefore we have to queue the next incoming request. If
- * halt_IO() is issued while there is a request queued, a HSCH
- * needs to be issued and the queued request must be deleted
- * but its intparm must be returned (see halt_IO() processing)
- */
- if ( ioinfo[irq]->ui.flags.w4final
- && !ioinfo[irq]->ui.flags.doio_q )
- {
- ioinfo[irq]->qflag = flag;
- ioinfo[irq]->qcpa = cpa;
- ioinfo[irq]->qintparm = user_intparm;
- ioinfo[irq]->qlpm = lpm;
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
- }
- else
- {
- ret = -EBUSY;
-
- } /* endif */
-
- return( ret );
-
-}
-
-/*
- * resume suspended I/O operation
- */
-int resume_IO( int irq)
-{
- int ret = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * We allow for 'resume' requests only for active I/O operations
- */
- if ( ioinfo[irq]->ui.flags.busy )
- {
- int ccode;
-
- ccode = rsch( irq);
-
- switch (ccode) {
- case 0 :
- break;
-
- case 1 :
- s390_process_IRQ( irq );
- ret = -EBUSY;
- break;
-
- case 2 :
- ret = -EINVAL;
- break;
-
- case 3 :
- /*
- * useless to wait for request completion
- * as device is no longer operational !
- */
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- }
- else
- {
- ret = -ENOTCONN;
-
- } /* endif */
-
- return( ret);
-}
-
-/*
- * Note: The "intparm" parameter is not used by the halt_IO() function
- * itself, as no ORB is built for the HSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the halt_IO() request.
- */
-int halt_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = hsch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_HALT_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_HALT_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&hio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-hio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Note: The "intparm" parameter is not used by the clear_IO() function
- * itself, as no ORB is built for the CSCH instruction. However,
- * it allows the device interrupt handler to associate the upcoming
- * interrupt with the clear_IO() request.
- */
-int clear_IO( int irq,
- unsigned long user_intparm,
- unsigned long flag) /* possible DOIO_WAIT_FOR_INTERRUPT */
-{
- int ret;
- int ccode;
- unsigned long psw_flags;
-
- int sync_isc_locked = 0;
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- ret = -ENODEV;
- }
-
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- /*
- * we only allow for halt_IO if the device has an I/O handler associated
- */
- else if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = -ENODEV;
- }
- /*
- * we ignore the halt_io() request if ending_status was received but
- * a SENSE operation is waiting for completion.
- */
- else if ( ioinfo[irq]->ui.flags.w4sense )
- {
- ret = 0;
- }
- /*
- * We don't allow for halt_io with a sync do_IO() requests pending.
- * Concurrent I/O is possible in SMP environments only, but the
- * sync. I/O request can be gated to one CPU at a time only.
- */
- else if ( ioinfo[irq]->ui.flags.syncio )
- {
- ret = -EBUSY;
- }
- else
- {
- /*
- * If sync processing was requested we lock the sync ISC,
- * modify the device to present interrupts for this ISC only
- * and switch the CPU to handle this ISC + the console ISC
- * exclusively.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- //
- // check whether we run recursively (sense processing)
- //
- if ( !ioinfo[irq]->ui.flags.syncio )
- {
- spin_lock_irqsave( &sync_isc, psw_flags);
-
- ret = enable_cpu_sync_isc( irq);
-
- if ( ret )
- {
- spin_unlock_irqrestore( &sync_isc,
- psw_flags);
- return( ret);
- }
- else
- {
- sync_isc_locked = 1; // local
- ioinfo[irq]->ui.flags.syncio = 1; // global
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * Issue "Halt subchannel" and process condition code
- */
- ccode = csch( irq );
-
- switch ( ccode ) {
- case 0:
-
- ioinfo[irq]->ui.flags.haltio = 1;
-
- if ( !ioinfo[irq]->ui.flags.doio )
- {
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->u_intparm = user_intparm;
- ioinfo[irq]->devstat.cstat = 0;
- ioinfo[irq]->devstat.dstat = 0;
- ioinfo[irq]->devstat.lpum = 0;
- ioinfo[irq]->devstat.flag = DEVSTAT_CLEAR_FUNCTION;
- ioinfo[irq]->devstat.scnt = 0;
-
- }
- else
- {
- ioinfo[irq]->devstat.flag |= DEVSTAT_CLEAR_FUNCTION;
-
- } /* endif */
-
- /*
- * If synchronous I/O processing is requested, we have
- * to wait for the corresponding interrupt to occur by
- * polling the interrupt condition. However, as multiple
- * interrupts may be outstanding, we must not just wait
- * for the first interrupt, but must poll until ours
- * pops up.
- */
- if ( flag & DOIO_WAIT_FOR_INTERRUPT )
- {
- int io_sub;
- __u32 io_parm;
- psw_t io_new_psw;
- int ccode;
-
- int ready = 0;
- struct _lowcore *lc = NULL;
-
- /*
- * We shouldn't perform a TPI loop, waiting for
- * an interrupt to occur, but should load a
- * WAIT PSW instead. Otherwise we may keep the
- * channel subsystem busy, not able to present
- * the interrupt. When our sync. interrupt
- * arrived we reset the I/O old PSW to its
- * original value.
- */
- memcpy( &io_new_psw,
- &lc->io_new_psw,
- sizeof(psw_t));
-
- ccode = iac();
-
- switch (ccode) {
- case 0: // primary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_PRIM_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 1: // secondary-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_SEC_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- case 2: // access-register
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_ACC_REG_MODE
- | _PSW_IO_WAIT;
- break;
- case 3: // home-space
- io_sync_wait.mask = _IO_PSW_MASK
- | _PSW_HOME_SPACE_MODE
- | _PSW_IO_WAIT;
- break;
- default:
- panic( "halt_IO() : unexpected "
- "address-space-control %d\n",
- ccode);
- break;
- } /* endswitch */
-
- io_sync_wait.addr = FIX_PSW(&&cio_wakeup);
-
- /*
- * Martin didn't like modifying the new PSW, now we take
- * a fast exit in do_IRQ() instead
- */
- *(__u32 *)__LC_SYNC_IO_WORD = 1;
-
- do
- {
-
- asm volatile ( "lpsw %0" : : "m" (io_sync_wait) );
-cio_wakeup:
- io_parm = *(__u32 *)__LC_IO_INT_PARM;
- io_sub = (__u32)*(__u16 *)__LC_SUBCHANNEL_NR;
-
- ready = s390_process_IRQ( io_sub );
-
- } while ( !((io_sub == irq) && (ready == 1)) );
-
- *(__u32 *)__LC_SYNC_IO_WORD = 0;
-
- } /* endif */
-
- ret = 0;
- break;
-
- case 1 : /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- /*
- * initialize the device driver specific devstat irb area
- */
- memset( &((devstat_t *) ioinfo[irq]->irq_desc.action->dev_id)->ii.irb,
- '\0', sizeof( irb_t) );
-
- /*
- * Let the common interrupt handler process the pending
- * status. However, we must avoid calling the user
- * action handler, as it won't be prepared to handle
- * a pending status during do_IO() processing inline.
- * This also implies that s390_process_IRQ must
- * terminate synchronously - especially if device
- * sensing is required.
- */
- ioinfo[irq]->ui.flags.s_pend = 1;
- ioinfo[irq]->ui.flags.busy = 1;
- ioinfo[irq]->ui.flags.doio = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.doio = 0;
- ioinfo[irq]->ui.flags.repall = 0;
- ioinfo[irq]->ui.flags.w4final = 0;
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_FINAL_STATUS;
-
- /*
- * In multipath mode a condition code 3 implies the last
- * path has gone, except we have previously restricted
- * the I/O to a particular path. A condition code 1
- * (0 won't occur) results in return code EIO as well
- * as 3 with another path than the one used (i.e. path available mask is non-zero).
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cc == 3 )
- {
- ret = -ENODEV;
- ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ret = -EIO;
- ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
- ioinfo[irq]->ui.flags.oper = 1;
-
- } /* endif */
-
- break;
-
- case 2 : /* busy */
-
- ret = -EBUSY;
- break;
-
- default: /* device not operational */
-
- ret = -ENODEV;
- break;
-
- } /* endswitch */
-
- if ( ( flag & DOIO_WAIT_FOR_INTERRUPT )
- && ( sync_isc_locked ) )
- {
- sync_isc_locked = 0; // local setting
- ioinfo[irq]->ui.flags.syncio = 0; // global setting
-
- disable_cpu_sync_isc( irq );
-
- spin_unlock_irqrestore( &sync_isc, psw_flags);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-
-/*
- * do_IRQ() handles all normal I/O device IRQ's (the special
- * SMP cross-CPU interrupts have their own specific
- * handlers).
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-asmlinkage void do_IRQ( struct pt_regs regs,
- unsigned int irq,
- __u32 s390_intparm )
-{
-#ifdef CONFIG_FAST_IRQ
- int ccode;
- tpi_info_t tpi_info;
- int new_irq;
-#endif
- int use_irq = irq;
-// __u32 use_intparm = s390_intparm;
-
- //
- // fix me !!!
- //
- // We need to schedule device recognition, the interrupt stays
- // pending. We need to dynamically allocate an ioinfo structure.
- //
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return; /* this keeps the device boxed ... */
- }
-
- /*
- * take fast exit if CPU is in sync. I/O state
- *
- * Note: we have to turn off the WAIT bit and re-disable
- * interrupts prior to return as this was the initial
- * entry condition to synchronous I/O.
- */
- if ( *(__u32 *)__LC_SYNC_IO_WORD )
- {
- regs.psw.mask &= ~(_PSW_WAIT_MASK_BIT | _PSW_IO_MASK_BIT);
-
- return;
-
- } /* endif */
-
- s390irq_spin_lock(use_irq);
-
-#ifdef CONFIG_FAST_IRQ
- do {
-#endif /* CONFIG_FAST_IRQ */
-
- s390_process_IRQ( use_irq );
-
-#ifdef CONFIG_FAST_IRQ
-
- /*
- * more interrupts pending ?
- */
- ccode = tpi( &tpi_info );
-
- if ( ! ccode )
- break; // no, leave ...
-
- new_irq = tpi_info.irq;
-// use_intparm = tpi_info.intparm;
-
- /*
- * if the interrupt is for a different irq we
- * release the current irq lock and obtain
- * a new one ...
- */
- if ( new_irq != use_irq )
- {
- s390irq_spin_unlock(use_irq);
- use_irq = new_irq;
- s390irq_spin_lock(use_irq);
-
- } /* endif */
-
- } while ( 1 );
-
-#endif /* CONFIG_FAST_IRQ */
-
- s390irq_spin_unlock(use_irq);
-
- return;
-}
-
-/*
- * s390_process_IRQ() handles status pending situations and interrupts
- *
- * Called by : do_IRQ() - for "real" interrupts
- * s390_start_IO, halt_IO()
- * - status pending cond. after SSCH, or HSCH
- * disable_subchannel() - status pending conditions (after MSCH)
- *
- * Returns: 0 - no ending status received, no further action taken
- * 1 - interrupt handler was called with ending status
- */
-int s390_process_IRQ( unsigned int irq )
-{
- int ccode; /* condition code from tsch() operation */
- int irb_cc; /* condition code from irb */
- int sdevstat; /* effective struct devstat size to copy */
- unsigned int fctl; /* function control */
- unsigned int stctl; /* status control */
- unsigned int actl; /* activity control */
- struct irqaction *action;
- struct pt_regs regs; /* for interface compatibility only */
-
- int issense = 0;
- int ending_status = 0;
- int allow4handler = 1;
- int chnchk = 0;
-#if 0
- int cpu = smp_processor_id();
-
- kstat.irqs[cpu][irq]++;
-#endif
- action = ioinfo[irq]->irq_desc.action;
-
- /*
- * It might be possible that a device was not-oper. at the time
- * of free_irq() processing. This means the handler is no longer
- * available when the device possibly becomes ready again. In
- * this case we perform delayed disable_subchannel() processing.
- */
- if ( action == NULL )
- {
- if ( !ioinfo[irq]->ui.flags.d_disable )
- {
- printk( KERN_CRIT"s390_process_IRQ(%04X) "
- "- no interrupt handler registered"
- "for device %04X !\n",
- irq,
- ioinfo[irq]->devstat.devno);
-
- } /* endif */
-
- } /* endif */
-
- /*
- * retrieve the i/o interrupt information (irb),
- * update the device specific status information
- * and possibly call the interrupt handler.
- *
- * Note 1: At this time we don't process the resulting
- * condition code (ccode) from tsch(), although
- * we probably should.
- *
- * Note 2: Here we will have to check for channel
- * check conditions and call a channel check
- * handler.
- *
- * Note 3: If a start function was issued, the interruption
- * parameter relates to it. If a halt function was
- * issued for an idle device, the intparm must not
- * be taken from lowcore, but from the devstat area.
- */
- ccode = tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
-
- //
- // We must only accumulate the status if initiated by do_IO() or halt_IO()
- //
- if ( ioinfo[irq]->ui.flags.busy )
- {
- ioinfo[irq]->devstat.dstat |= ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat |= ioinfo[irq]->devstat.ii.irb.scsw.cstat;
- }
- else
- {
- ioinfo[irq]->devstat.dstat = ioinfo[irq]->devstat.ii.irb.scsw.dstat;
- ioinfo[irq]->devstat.cstat = ioinfo[irq]->devstat.ii.irb.scsw.cstat;
-
- ioinfo[irq]->devstat.flag = 0; // reset status flags
-
- } /* endif */
-
- ioinfo[irq]->devstat.lpum = ioinfo[irq]->devstat.ii.irb.esw.esw1.lpum;
-
- if ( ioinfo[irq]->ui.flags.busy)
- {
- ioinfo[irq]->devstat.intparm = ioinfo[irq]->u_intparm;
-
- } /* endif */
-
- /*
- * reset device-busy bit if no longer set in irb
- */
- if ( (ioinfo[irq]->devstat.dstat & DEV_STAT_BUSY )
- && ((ioinfo[irq]->devstat.ii.irb.scsw.dstat & DEV_STAT_BUSY) == 0))
- {
- ioinfo[irq]->devstat.dstat &= ~DEV_STAT_BUSY;
-
- } /* endif */
-
- /*
- * Save residual count and CCW information in case primary and
- * secondary status are presented with different interrupts.
- */
- if ( ioinfo[irq]->devstat.ii.irb.scsw.stctl & SCSW_STCTL_PRIM_STATUS )
- {
- ioinfo[irq]->devstat.rescnt = ioinfo[irq]->devstat.ii.irb.scsw.count;
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "residual count from irb after tsch() %d\n",
- irq, ioinfo[irq]->devstat.rescnt );
-#endif
- } /* endif */
-
- if ( ioinfo[irq]->devstat.ii.irb.scsw.cpa != 0 )
- {
- ioinfo[irq]->devstat.cpa = ioinfo[irq]->devstat.ii.irb.scsw.cpa;
-
- } /* endif */
-
- irb_cc = ioinfo[irq]->devstat.ii.irb.scsw.cc;
-
- //
- // check for any kind of channel or interface control check but don't
- // issue the message for the console device
- //
- if ( (ioinfo[irq]->devstat.ii.irb.scsw.cstat
- & ( SCHN_STAT_CHN_DATA_CHK
- | SCHN_STAT_CHN_CTRL_CHK
- | SCHN_STAT_INTF_CTRL_CHK ) )
- && (irq != cons_dev ) )
- {
- printk( "Channel-Check or Interface-Control-Check "
- "received\n"
- " ... device %04X on subchannel %04X, dev_stat "
- ": %02X sch_stat : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- chnchk = 1;
-
- } /* endif */
-
- issense = ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.cons;
-
- if ( issense )
- {
- ioinfo[irq]->devstat.scnt =
- ioinfo[irq]->devstat.ii.irb.esw.esw0.erw.scnt;
- ioinfo[irq]->devstat.flag |=
- DEVSTAT_FLAG_SENSE_AVAIL;
-
- sdevstat = sizeof( devstat_t);
-
-#if CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "concurrent sense bytes avail %d\n",
- irq, ioinfo[irq]->devstat.scnt );
-#endif
- }
- else
- {
- /* don't copy the sense data area ! */
- sdevstat = sizeof( devstat_t) - SENSE_MAX_COUNT;
-
- } /* endif */
-
- switch ( irb_cc ) {
- case 1: /* status pending */
-
- ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
-
- case 0: /* normal i/o interruption */
-
- fctl = ioinfo[irq]->devstat.ii.irb.scsw.fctl;
- stctl = ioinfo[irq]->devstat.ii.irb.scsw.stctl;
- actl = ioinfo[irq]->devstat.ii.irb.scsw.actl;
-
- if ( chnchk && (ioinfo[irq]->senseid.cu_type == 0x3088))
- {
- char buffer[80];
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X after channel check\n",
- irq,
- ioinfo[irq]->devstat.devno );
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
- } /* endif */
-
- ioinfo[irq]->stctl |= stctl;
-
- ending_status = ( stctl & SCSW_STCTL_SEC_STATUS )
- || ( stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND) )
- || ( (fctl == SCSW_FCTL_HALT_FUNC) && (stctl == SCSW_STCTL_STATUS_PEND) );
-
- /*
- * Check for unsolicited interrupts - for debug purposes only
- *
- * We only consider an interrupt as unsolicited, if the device was not
- * actively in use (busy) and an interrupt other than an ALERT status
- * was received.
- *
- * Note: We must not issue a message to the console, if the
- * unsolicited interrupt applies to the console device
- * itself !
- */
-#if CONFIG_DEBUG_IO
- if ( ( irq != cons_dev )
- && !( stctl & SCSW_STCTL_ALERT_STATUS )
- && ( ioinfo[irq]->ui.flags.busy == 0 ) )
- {
- char buffer[80];
-
- printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
- " ... device status : %02X subchannel status : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- ioinfo[irq]->devstat.dstat,
- ioinfo[irq]->devstat.cstat);
-
- sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
- "device %04X, ending_status %d\n",
- irq,
- ioinfo[irq]->devstat.devno,
- ending_status);
-
- s390_displayhex( buffer,
- &(ioinfo[irq]->devstat.ii.irb) ,
- sizeof(irb_t));
-
- } /* endif */
-
- /*
- * take fast exit if no handler is available
- */
- if ( !action )
- return( ending_status );
-
-#endif
- /*
- * 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 )
- {
- ioinfo[irq]->schib.pmcw.isc = 5;
-
- do
- {
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode == 0 )
- {
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 |= 0x04000000; // enable sync isc 5
- cr6 &= 0xEFFFFFFF; // disable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
- }
- else if (ccode == 3)
- {
- rc = -ENODEV; // device not-oper - very unlikely
-
- }
- else if (ccode == 2)
- {
- rc = -EBUSY; // device busy - should not happen
-
- }
- else if (ccode == 1)
- {
- //
- // process pending status
- //
- ioinfo[irq]->ui.flags.s_pend = 1;
-
- s390_process_IRQ( irq );
-
- ioinfo[irq]->ui.flags.s_pend = 0;
-
- count++;
-
- } /* endif */
-
- } while ( ccode == 1 && count < 3 );
-
- if ( count == 3)
- {
- rc = -EIO;
-
- } /* endif */
- }
- else
- {
- rc = -ENODEV; // device is not-operational
-
- } /* endif */
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-int disable_cpu_sync_isc( int irq)
-{
- int rc = 0;
- int ccode;
- long cr6 __attribute__ ((aligned (8)));
-
- if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- ioinfo[irq]->schib.pmcw.isc = 3;
-
- ccode = msch( irq, &(ioinfo[irq]->schib) );
-
- if (ccode)
- {
- rc = -EIO;
- }
- else
- {
-
- /*
- * enable interrupt subclass in CPU
- */
- asm volatile ("STCTL 6,6,%0": "=m" (cr6));
- cr6 &= 0xFBFFFFFF; // disable sync isc 5
- cr6 |= 0x10000000; // enable standard isc 3
- asm volatile ("LCTL 6,6,%0":: "m" (cr6):"memory");
-
- } /* endif */
-
- }
- else
- {
- rc = -EINVAL;
-
- } /* endif */
-
- return( rc);
-}
-
-//
-// Input :
-// devno - device number
-// ps - pointer to sense ID data area
-//
-// Output : none
-//
-void VM_virtual_device_info( __u16 devno,
- senseid_t *ps )
-{
- diag210_t diag_data;
- int ccode;
-
- int error = 0;
-
- diag_data.vrdcdvno = devno;
- diag_data.vrdclen = sizeof( diag210_t);
- ccode = diag210( (diag210_t *)virt_to_phys( &diag_data ) );
- ps->reserved = 0xff;
-
- switch (diag_data.vrdcvcla) {
- case 0x80:
-
- switch (diag_data.vrdcvtyp) {
- case 00:
-
- ps->cu_type = 0x3215;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x40:
-
- switch (diag_data.vrdcvtyp) {
- case 0xC0:
-
- ps->cu_type = 0x5080;
-
- break;
-
- case 0x80:
-
- ps->cu_type = 0x2250;
-
- break;
-
- case 0x04:
-
- ps->cu_type = 0x3277;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3278;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x20:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3505;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x2501;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x10:
-
- switch (diag_data.vrdcvtyp) {
- case 0x84:
-
- ps->cu_type = 0x3525;
-
- break;
-
- case 0x82:
-
- ps->cu_type = 0x2540;
-
- break;
-
- case 0x4F:
- case 0x4E:
- case 0x48:
-
- ps->cu_type = 0x3820;
-
- break;
-
- case 0x4D:
- case 0x49:
- case 0x45:
-
- ps->cu_type = 0x3800;
-
- break;
-
- case 0x4B:
-
- ps->cu_type = 0x4248;
-
- break;
-
- case 0x4A:
-
- ps->cu_type = 0x4245;
-
- break;
-
- case 0x47:
-
- ps->cu_type = 0x3262;
-
- break;
-
- case 0x43:
-
- ps->cu_type = 0x3203;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3211;
-
- break;
-
- case 0x41:
-
- ps->cu_type = 0x1403;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- case 0x08:
-
- switch (diag_data.vrdcvtyp) {
- case 0x82:
-
- ps->cu_type = 0x3422;
-
- break;
-
- case 0x81:
-
- ps->cu_type = 0x3490;
-
- break;
-
- case 0x10:
-
- ps->cu_type = 0x3420;
-
- break;
-
- case 0x02:
-
- ps->cu_type = 0x3430;
-
- break;
-
- case 0x01:
-
- ps->cu_type = 0x3480;
-
- break;
-
- case 0x42:
-
- ps->cu_type = 0x3424;
-
- break;
-
- case 0x44:
-
- ps->cu_type = 0x9348;
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- break;
-
- default:
-
- error = 1;
-
- break;
-
- } /* endswitch */
-
- if ( error )
- {printk( "DIAG X'210' for device %04X returned (cc = %d): vdev class : %02X, "
- "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
- devno,
- ccode,
- diag_data.vrdcvcla,
- diag_data.vrdcvtyp,
- diag_data.vrdcrccl,
- diag_data.vrdccrty,
- diag_data.vrdccrmd );
-
- } /* endif */
-
-}
-
-/*
- * This routine returns the characteristics for the device
- * specified. Some old devices might not provide the necessary
- * command code information during SenseID processing. In this
- * case the function returns -EINVAL. Otherwise the function
- * allocates a decice specific data buffer and provides the
- * device characteristics together with the buffer size. Its
- * the callers responability to release the kernel memory if
- * not longer needed. In case of persistent I/O problems -EBUSY
- * is returned.
- *
- * The function may be called enabled or disabled. However, the
- * caller must have locked the irq it is requesting data for.
- *
- * Note : It would have been nice to collect this information
- * during init_IRQ() processing but this is not possible
- *
- * a) without statically pre-allocation fixed size buffers
- * as virtual memory management isn't available yet.
- *
- * b) without unnecessarily increase system startup by
- * evaluating devices eventually not used at all.
- */
-int read_dev_chars( int irq, void **buffer, int length )
-{
- unsigned int flags;
- ccw1_t *rdc_ccw;
- devstat_t devstat;
- char *rdc_buf;
- int devflag;
-
- int ret = 0;
- int emulated = 0;
- int retry = 5;
-
- if ( !buffer || !length )
- {
- return( -EINVAL );
-
- } /* endif */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * Before playing around with irq locks we should assure
- * running disabled on (just) our CPU. Sync. I/O requests
- * also require to run disabled.
- *
- * Note : as no global lock is required, we must not use
- * cli(), but __cli() instead.
- */
- __save_flags(flags);
- __cli();
-
- rdc_ccw = &ioinfo[irq]->senseccw;
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RDC", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- if ( ! *buffer )
- {
- rdc_buf = kmalloc( length, GFP_KERNEL);
- }
- else
- {
- rdc_buf = *buffer;
-
- } /* endif */
-
- if ( !rdc_buf )
- {
- ret = -ENOMEM;
- }
- else
- {
- do
- {
- rdc_ccw->cmd_code = CCW_CMD_RDC;
- rdc_ccw->cda = (__u32)virt_to_phys( rdc_buf );
- rdc_ccw->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rdc_ccw,
- 0x00524443, // RDC
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
- retry--;
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- } /* endif */
-
- if ( !retry )
- {
- ret = -EBUSY;
-
- } /* endif */
-
- __restore_flags(flags);
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *buffer = rdc_buf;
-
- } /* endif */
-
- if ( emulated )
- {
- free_irq( irq, &devstat);
-
- } /* endif */
-
- } /* endif */
-
- return( ret );
-}
-
-/*
- * Read Configuration data
- */
-int read_conf_data( int irq, void **buffer, int *length )
-{
- int found = 0;
- int ciw_cnt = 0;
- unsigned int flags;
-
- int ret = 0;
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- /*
- * scan for RCD command in extended SenseID data
- */
- for ( ; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
- {
- if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
- {
- found = 1;
- break;
- } /* endif */
-
- } /* endfor */
-
- if ( found )
- {
- ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
- devstat_t devstat;
- char *rcd_buf;
- int devflag;
-
- int emulated = 0;
- int retry = 5;
-
- __save_flags(flags);
- __cli();
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- ret = request_irq( irq,
- init_IRQ_handler,
- 0, "RCD", &devstat );
-
- if ( !ret )
- {
- emulated = 1;
-
- } /* endif */
-
- } /* endif */
-
- if ( !ret )
- {
- rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
- GFP_KERNEL);
-
- do
- {
- rcd_ccw->cmd_code = ioinfo[irq]->senseid.ciw[ciw_cnt].cmd;
- rcd_ccw->cda = (__u32)virt_to_phys( rcd_buf );
- rcd_ccw->count = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- rcd_ccw->flags = CCW_FLAG_SLI;
-
- ret = s390_start_IO( irq,
- rcd_ccw,
- 0x00524344, // == RCD
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT );
-
- retry--;
-
- devflag = ((devstat_t *)(ioinfo[irq]->irq_desc.action->dev_id))->flag;
-
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
-
- if ( !retry )
- ret = -EBUSY;
-
- __restore_flags(flags);
-
- } /* endif */
-
- /*
- * on success we update the user input parms
- */
- if ( !ret )
- {
- *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- *buffer = rcd_buf;
-
- } /* endif */
-
- if ( emulated )
- free_irq( irq, &devstat);
- }
- else
- {
- ret = -EINVAL;
-
- } /* endif */
-
- return( ret );
-
-}
-
-int get_dev_info( int irq, dev_info_t * pdi)
-{
- return( get_dev_info_by_irq( irq, pdi));
-}
-
-static int __inline__ get_next_available_irq( ioinfo_t *pi)
-{
- int ret_val;
-
- while ( TRUE )
- {
- if ( pi->ui.flags.oper )
- {
- ret_val = pi->irq;
- break;
- }
- else
- {
- pi = pi->next;
-
- //
- // leave at end of list unconditionally
- //
- if ( pi == NULL )
- {
- ret_val = -ENODEV;
- break;
- }
-
- } /* endif */
-
- } /* endwhile */
-
- return ret_val;
-}
-
-
-int get_irq_first( void )
-{
- int ret_irq;
-
- if ( ioinfo_head )
- {
- if ( ioinfo_head->ui.flags.oper )
- {
- ret_irq = ioinfo_head->irq;
- }
- else if ( ioinfo_head->next )
- {
- ret_irq = get_next_available_irq( ioinfo_head->next );
-
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_irq_next( int irq )
-{
- int ret_irq;
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- if ( ioinfo[irq]->next )
- {
- if ( ioinfo[irq]->next->ui.flags.oper )
- {
- ret_irq = ioinfo[irq]->next->irq;
- }
- else
- {
- ret_irq = get_next_available_irq( ioinfo[irq]->next );
-
- } /* endif */
- }
- else
- {
- ret_irq = -ENODEV;
-
- } /* endif */
- }
- else
- {
- ret_irq = -EINVAL;
-
- } /* endif */
-
- return ret_irq;
-}
-
-int get_dev_info_by_irq( int irq, dev_info_t *pdi)
-{
-
- if ( irq > highest_subchannel || irq < 0 )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- }
- else
- {
- pdi->devno = ioinfo[irq]->schib.pmcw.dev;
- pdi->irq = irq;
-
- if ( ioinfo[irq]->ui.flags.oper )
- {
- pdi->status = 0;
- memcpy( &(pdi->sid_data),
- &ioinfo[irq]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- memcpy( &(pdi->sid_data),
- '\0',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- return 0;
-
- } /* endif */
-
-}
-
-
-int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi)
-{
- int i;
- int rc = -ENODEV;
-
- if ( devno > 0x0000ffff )
- {
- return -ENODEV;
- }
- else if ( pdi == NULL )
- {
- return -EINVAL;
- }
- else
- {
-
- for ( i=0; i <= highest_subchannel; i++ )
- {
-
- if ( ioinfo[i] != INVALID_STORAGE_AREA
- && ioinfo[i]->schib.pmcw.dev == devno )
- {
- if ( ioinfo[i]->ui.flags.oper )
- {
- pdi->status = 0;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data),
- &ioinfo[i]->senseid,
- sizeof( senseid_t));
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- pdi->irq = i;
- pdi->devno = devno;
-
- memcpy( &(pdi->sid_data), '\0', sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[i]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
-
- rc = 0; /* found */
- break;
-
- } /* endif */
-
- } /* endfor */
-
- return( rc);
-
- } /* endif */
-
-}
-
-int get_irq_by_devno( __u16 devno )
-{
- int i;
- int rc = -1;
-
- if ( devno <= 0x0000ffff )
- {
- for ( i=0; i <= highest_subchannel; i++ )
- {
- if ( (ioinfo[i] != INVALID_STORAGE_AREA )
- && (ioinfo[i]->schib.pmcw.dev == devno)
- && (ioinfo[i]->schib.pmcw.dnv == 1 ) )
- {
- rc = i;
- break;
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return( rc);
-}
-
-unsigned int get_devno_by_irq( int irq )
-{
-
- if ( ( irq > highest_subchannel )
- || ( irq < 0 )
- || ( ioinfo[irq] == INVALID_STORAGE_AREA ) )
- {
- return -1;
-
- } /* endif */
-
- /*
- * we don't need to check for the device be operational
- * as the initial STSCH will always present the device
- * number defined by the IOCDS regardless of the device
- * existing or not. However, there could be subchannels
- * defined who's device number isn't valid ...
- */
- if ( ioinfo[irq]->schib.pmcw.dnv )
- return( ioinfo[irq]->schib.pmcw.dev );
- else
- return -1;
-}
-
-/*
- * s390_device_recognition
- *
- * Used for system wide device recognition. Issues the device
- * independant SenseID command to obtain info the device type.
- *
- */
-void s390_device_recognition( void)
-{
-
- int irq = 0; /* let's start with subchannel 0 ... */
-
- do
- {
- /*
- * We issue the SenseID command on I/O subchannels we think are
- * operational only.
- */
- if ( ( ioinfo[irq] != INVALID_STORAGE_AREA )
- && ( ioinfo[irq]->schib.pmcw.st == 0 )
- && ( ioinfo[irq]->ui.flags.oper == 1 ) )
- {
- s390_SenseID( irq, &ioinfo[irq]->senseid );
-
- } /* endif */
-
- irq ++;
-
- } while ( irq <= highest_subchannel );
-
-}
-
-
-/*
- * s390_search_devices
- *
- * Determines all subchannels available to the system.
- *
- */
-void s390_process_subchannels( void)
-{
- int isValid;
- int irq = 0; /* Evaluate all subchannels starting with 0 ... */
-
- do
- {
- isValid = s390_validate_subchannel( irq);
-
- irq++;
-
- } while ( isValid && irq < __MAX_SUBCHANNELS );
-
- highest_subchannel = --irq;
-
- printk( "\nHighest subchannel number detected: %u\n",
- highest_subchannel);
-}
-
-/*
- * s390_validate_subchannel()
- *
- * Process the subchannel for the requested irq. Returns 1 for valid
- * subchannels, otherwise 0.
- */
-int s390_validate_subchannel( int irq )
-{
-
- int retry; /* retry count for status pending conditions */
- int ccode; /* condition code for stsch() only */
- int ccode2; /* condition code for other I/O routines */
- schib_t *p_schib;
-
- /*
- * The first subchannel that is not-operational (ccode==3)
- * indicates that there aren't any more devices available.
- */
- if ( ( init_IRQ_complete )
- && ( ioinfo[irq] != INVALID_STORAGE_AREA ) )
- {
- p_schib = &ioinfo[irq]->schib;
- }
- else
- {
- p_schib = &init_schib;
-
- } /* endif */
-
- ccode = stsch( irq, p_schib);
-
- if ( ccode == 0)
- {
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if ( p_schib->pmcw.st )
- {
- printk( "Subchannel %04X reports "
- "non-I/O subchannel type %04X\n",
- irq,
- p_schib->pmcw.st);
-
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- if ( p_schib->pmcw.dnv )
- {
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
-
- if ( !init_IRQ_complete )
- {
- ioinfo[irq] =
- (ioinfo_t *)alloc_bootmem( sizeof(ioinfo_t));
- }
- else
- {
- ioinfo[irq] =
- (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
- GFP_KERNEL );
-
- } /* endif */
-
- memset( ioinfo[irq], '\0', sizeof( ioinfo_t));
- memcpy( &ioinfo[irq]->schib,
- &init_schib,
- sizeof( schib_t));
- ioinfo[irq]->irq_desc.status = IRQ_DISABLED;
- ioinfo[irq]->irq_desc.handler = &no_irq_type;
-
- /*
- * We have to insert the new ioinfo element
- * into the linked list, either at its head,
- * its tail or insert it.
- */
- if ( ioinfo_head == NULL ) /* first element */
- {
- ioinfo_head = ioinfo[irq];
- ioinfo_tail = ioinfo[irq];
- }
- else if ( irq < ioinfo_head->irq ) /* new head */
- {
- ioinfo[irq]->next = ioinfo_head;
- ioinfo_head->prev = ioinfo[irq];
- ioinfo_head = ioinfo[irq];
- }
- else if ( irq > ioinfo_tail->irq ) /* new tail */
- {
- ioinfo_tail->next = ioinfo[irq];
- ioinfo[irq]->prev = ioinfo_tail;
- ioinfo_tail = ioinfo[irq];
- }
- else /* insert element */
- {
- ioinfo_t *pi = ioinfo_head;
-
- do
- {
- if ( irq < pi->next->irq )
- {
- ioinfo[irq]->next = pi->next;
- ioinfo[irq]->prev = pi;
- pi->next->prev = ioinfo[irq];
- pi->next = ioinfo[irq];
- break;
-
- } /* endif */
-
- pi = pi->next;
-
- } while ( 1 );
-
- } /* endif */
-
- } /* endif */
-
- // initialize some values ...
- ioinfo[irq]->ui.flags.pgid_supp = 1;
-
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- printk( "Detected device %04X on subchannel %04X"
- " - PIM = %02X, PAM = %02X, POM = %02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- ioinfo[irq]->schib.pmcw.pim,
- ioinfo[irq]->schib.pmcw.pam,
- ioinfo[irq]->schib.pmcw.pom);
-
- /*
- * We should have at least one CHPID ...
- */
- if ( ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom )
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- /*
- * We now have to initially ...
- * ... set "interruption sublass"
- * ... enable "concurrent sense"
- * ... enable "multipath mode" if more than one
- * CHPID is available. This is done regardless
- * whether multiple paths are available for us.
- *
- * Note : we don't enable the device here, this is temporarily
- * done during device sensing below.
- */
- ioinfo[irq]->schib.pmcw.isc = 3; /* could be smth. else */
- ioinfo[irq]->schib.pmcw.csense = 1; /* concurrent sense */
- ioinfo[irq]->schib.pmcw.ena = 0; /* force disable it */
- ioinfo[irq]->schib.pmcw.intparm =
- ioinfo[irq]->schib.pmcw.dev;
-
- if ( ( ioinfo[irq]->schib.pmcw.pim != 0 )
- && ( ioinfo[irq]->schib.pmcw.pim != 0x80 ) )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- } /* endif */
-
- /*
- * initialize ioinfo structure
- */
- ioinfo[irq]->irq = irq;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.ready = 0;
- ioinfo[irq]->ui.flags.oper = 1;
- ioinfo[irq]->devstat.intparm = 0;
- ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
-
- retry = 5;
-
- do
- {
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- switch (ccode2) {
- case 0: // successful completion
- //
- // concurrent sense facility available ...
- //
- ioinfo[irq]->ui.flags.consns = 1;
- break;
-
- case 1: // status pending
- //
- // How can we have a pending status as device is
- // disabled for interrupts ? Anyway, clear it ...
- //
- tsch( irq, &(ioinfo[irq]->devstat.ii.irb) );
- retry--;
- break;
-
- case 2: // busy
- retry--;
- break;
-
- case 3: // not operational
- ioinfo[irq]->ui.flags.oper = 0;
- retry = 0;
- break;
-
- default:
-#define PGMCHK_OPERAND_EXC 0x15
-
- if ( (ccode2 & PGMCHK_OPERAND_EXC) == PGMCHK_OPERAND_EXC )
- {
- /*
- * re-issue the modify subchannel without trying to
- * enable the concurrent sense facility
- */
- ioinfo[irq]->schib.pmcw.csense = 0;
-
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
-
- if ( ccode2 != 0 )
- {
- printk( " ... modify subchannel (2) failed with CC = %X\n",
- ccode2 );
- ioinfo[irq]->ui.flags.oper = 0;
- }
- else
- {
- ioinfo[irq]->ui.flags.consns = 0;
-
- } /* endif */
- }
- else
- {
- printk( " ... modify subchannel (1) failed with CC = %X\n",
- ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- retry = 0;
- break;
-
- } /* endswitch */
-
- } while ( ccode2 && retry );
-
- if ( (ccode2 < 3) && (!retry) )
- {
- printk( " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %d\n",
- irq,
- ccode2);
-
- } /* endif */
-
- }
- else
- {
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endif */
-
- /*
- * indicate whether the subchannel is valid
- */
- if ( ccode == 3)
- return(0);
- else
- return(1);
-}
-
-/*
- * s390_SenseID
- *
- * Try to obtain the 'control unit'/'device type' information
- * associated with the subchannel.
- *
- * The function is primarily meant to be called without irq
- * action handler in place. However, it also allows for
- * use with an action handler in place. If there is already
- * an action handler registered assure it can handle the
- * s390_SenseID() related device interrupts - interruption
- * parameter used is 0x00E2C9C4 ( SID ).
- */
-int s390_SenseID( int irq, senseid_t *sid )
-{
- ccw1_t sense_ccw; /* ccw area for SenseID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- sense_ccw.cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw.cda = (__u32)virt_to_phys( sid );
- sense_ccw.count = sizeof( senseid_t);
- sense_ccw.flags = CCW_FLAG_SLI;
-
- ioinfo[irq]->senseid.cu_type = 0xFFFF; /* initialize fields ... */
- ioinfo[irq]->senseid.cu_model = 0;
- ioinfo[irq]->senseid.dev_type = 0;
- ioinfo[irq]->senseid.dev_model = 0;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &sense_ccw,
- 0x00E2C9C4, // == SID
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_TIMEOUT );
-
- if ( irq_ret == -ETIMEDOUT )
- {
- halt_IO( irq,
- 0x80E2C9C4,
- DOIO_WAIT_FOR_INTERRUPT);
- devstat.flag |= DEVSTAT_NOT_OPER;
-
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF && devstat.flag != DEVSTAT_NOT_OPER )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "Device %04X on Subchannel %04X "
- "reports pending status, retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * if the device doesn't support the SenseID
- * command further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "Device %04X,"
- " UC/SenseID,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "Device %04X on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else // we got it or the device is not-operational ...
- {
- retry = 0;
-
- } /* endif */
-
- retry--;
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- /*
- * if running under VM check there ... perhaps we should do
- * only if we suffered a command reject, but it doesn't harm
- */
- if ( ( sid->cu_type == 0xFFFF )
- && ( MACHINE_IS_VM ) )
- {
- VM_virtual_device_info( ioinfo[irq]->schib.pmcw.dev,
- sid );
- } /* endif */
-
- if ( sid->cu_type == 0xFFFF )
- {
- /*
- * SenseID CU-type of 0xffff indicates that no device
- * information could be retrieved (pre-init value).
- *
- * If we can't couldn't identify the device type we
- * consider the device "not operational".
- */
- printk( "Unknown device %04X on subchannel %04X\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- ioinfo[irq]->ui.flags.oper = 0;
-
- } /* endif */
-
- /*
- * Issue device info message if unit was operational .
- */
- if ( ioinfo[irq]->ui.flags.oper )
- {
- if ( sid->dev_type != 0 )
- {
- printk( "Device %04X reports: CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- }
- else
- {
- printk( "Device %04X reports:"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
-
- } /* endif */
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper )
- irq_ret = 0;
- else
- irq_ret = -ENODEV;
-
- } /* endif */
-
- return( irq_ret );
-}
-
-static int __inline__ s390_SetMultiPath( int irq )
-{
- int cc;
-
- cc = stsch( irq, &ioinfo[irq]->schib );
-
- if ( !cc )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
-
- cc = msch( irq, &ioinfo[irq]->schib );
-
- } /* endif */
-
- return( cc);
-}
-
-/*
- * Device Path Verification
- *
- * Path verification is accomplished by checking which paths (CHPIDs) are
- * available. Further, a path group ID is set, if possible in multipath
- * mode, otherwise in single path mode.
- *
- */
-int s390_DevicePathVerification( int irq )
-{
-#if 0
- int ccode;
- __u8 pathmask;
-
- int ret = 0;
-
- if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
- {
- ret = -EOPNOTSUPP;
-
- } /* endif */
-
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
-
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else
- {
- int i;
- pgid_t pgid;
-
- int first = 1;
- __u8 dev_path = ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- /*
- * let's build a path group ID if we don't have one yet
- */
- if ( ioinfo[irq]->ui.flags.pgid == 0)
- {
- struct _lowcore *lowcore = &get_cpu_lowcore(cpu);
-
- ioinfo->pgid.cpu_addr = lowcore->cpu_data.cpu_addr;
- ioinfo->pgid.cpu_id = lowcore->cpu_data.cpu_id.ident;
- ioinfo->pgid.cpu_model = lowcore->cpu_data.cpu_id.machine;
- ioinfo->pgid.tod_high = *(__u32 *)&irq_IPL_TOD;
-
- ioinfo[irq]->ui.flags.pgid = 1;
-
- } /* endif */
-
- memcpy( &pgid, ioinfo[irq]->pgid, sizeof(pgid_t));
-
- for ( i = 0; i < 8 && !ret ; i++)
- {
- pathmask = 0x80 >> i;
-
- if ( dev_path & pathmask )
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- /*
- * For the *first* path we are prepared
- * for recovery
- *
- * - If we fail setting the PGID we assume its
- * using a different PGID already (VM) we
- * try to sense.
- */
- if ( ret == -EOPNOTSUPP && first )
- {
- *(int *)&pgid = 0;
-
- ret = s390_SensePGID( irq, pathmask, &pgid);
- first = 0;
-
- if ( !ret )
- {
- /*
- * Check whether we retrieved
- * a reasonable PGID ...
- */
- if ( !ret && (*(int *)&pgid == 0) )
- {
- ret = -EOPNOTSUPP;
- }
- else
- {
- ret = s390_SetPGID( irq, pathmask, &pgid );
-
- } /* endif */
-
- } /* endif */
-
- if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- printk( "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path grouping",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- } /* endif */
- }
- else if ( ret )
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- } /* endif */
-
- } /* endif */
-
- } /* endfor */
-
- } /* endif */
-
- return ret;
-#else
- return 0;
-#endif
-}
-
-/*
- * s390_SetPGID
- *
- * Set Path Group ID
- *
- */
-int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t spid_ccw; /* ccw area for SPID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
- int mpath = 1; /* try multi-path first */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SPID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- spid_ccw.cmd_code = CCW_CMD_SET_PGID;
- spid_ccw.cda = (__u32)virt_to_phys( pgid );
- spid_ccw.count = sizeof( pgid_t);
- spid_ccw.flags = CCW_FLAG_SLI;
-
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &spid_ccw,
- 0xE2D7C9C4, // == SPID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag == ( DEVSTAT_START_FUNCTION
- | DEVSTAT_FINAL_STATUS ) )
- {
- retry = 0; // successfully set ...
- }
- else if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- if ( mpath )
- {
- pgid->inf.fc = SPID_FUNC_ESTABLISH;
- mpath = 0;
- retry--;
- }
- else
- {
- irq_ret = -EOPNOTSUPP;
- retry = 0;
-
- } /* endif */
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SPID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-/*
- * s390_SensePGID
- *
- * Sense Path Group ID
- *
- */
-int s390_SensePGID( int irq, __u8 lpm, pgid_t *pgid )
-{
- ccw1_t snid_ccw; /* ccw area for SNID command */
- devstat_t devstat; /* required by request_irq() */
-
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
-
- if ( (irq > highest_subchannel) || (irq < 0 ) )
- {
- return( -ENODEV );
-
- }
- else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- return( -ENODEV);
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
-
- } /* endif */
-
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE ID command processing. We have to request device
- * ownership and provide a dummy I/O handler. We issue sync. I/O
- * requests and evaluate the devstat area on return therefore
- * we don't need a real I/O handler in place.
- */
- irq_ret = request_irq( irq, init_IRQ_handler, 0, "SNID", &devstat);
-
- if ( irq_ret == 0 )
- inlreq = 1;
-
- } /* endif */
-
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock( irq);
-
- snid_ccw.cmd_code = CCW_CMD_SENSE_PGID;
- snid_ccw.cda = (__u32)virt_to_phys( pgid );
- snid_ccw.count = sizeof( pgid_t);
- snid_ccw.flags = CCW_FLAG_SLI;
-
- /*
- * We now issue a SenseID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( &devstat, '\0', sizeof( devstat_t) );
-
- irq_ret = s390_start_IO( irq,
- &snid_ccw,
- 0xE2D5C9C4, // == SNID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM );
-
- if ( !irq_ret )
- {
- if ( devstat.flag & DEVSTAT_STATUS_PENDING )
- {
-#if CONFIG_DEBUG_IO
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %d\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
-#endif
- } /* endif */
-
- if ( devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( devstat.ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- irq_ret = -EOPNOTSUPP;
- }
-#if CONFIG_DEBUG_IO
- else
- {
- printk( "SNID - device %04X,"
- " unit check,"
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- devstat.scnt,
- devstat.ii.sense.data[0],
- devstat.ii.sense.data[1],
- devstat.ii.sense.data[2],
- devstat.ii.sense.data[3],
- devstat.ii.sense.data[4],
- devstat.ii.sense.data[5],
- devstat.ii.sense.data[6],
- devstat.ii.sense.data[7]);
-
- } /* endif */
-#endif
- }
- else if ( devstat.flag & DEVSTAT_NOT_OPER )
- {
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
-
- retry = 0;
-
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- }
- else
- {
- retry = 0;
-
- } /* endif */
-
- } while ( retry > 0 );
-
- s390irq_spin_unlock( irq);
-
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, &devstat);
-
- } /* endif */
-
- return( irq_ret );
-}
-
-
-void do_crw_pending( void )
-{
- return;
-}
-
-
-/* added by Holger Smolinski for reipl support in reipl.S */
-void
-reipl ( int sch )
-{
- int i;
-
- for ( i = 0; i < highest_subchannel; i ++ ) {
- free_irq ( i, (void*)REIPL_DEVID_MAGIC );
- }
- do_reipl( 0x10000 | sch );
-}
-
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)