s390io.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:171k
- 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 (p_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;
- case 02: /* special device class ... */
- switch (p_diag_data->vrdcvtyp) {
- case 0x20: /* OSA */
- ps->cu_type = 0x3088;
- ps->cu_model = 0x60;
- break;
- default:
- error = 1;
- break;
- } /* endswitch */
- break;
- default:
- error = 1;
- break;
- } /* endswitch */
- if ( init_IRQ_complete )
- {
- kfree( p_diag_data );
- }
- else
- {
- free_bootmem( (unsigned long)p_diag_data, sizeof( diag210_t) );
- } /* endif */
- if ( error )
- {
- printk( KERN_ERR "DIAG X'210' for "
- "device %04X returned "
- "(cc = %d): vdev class : %02X, "
- "vdev type : %04X n ... rdev class : %02X, rdev type : %04X, rdev model: %02Xn",
- devno,
- ccode,
- p_diag_data->vrdcvcla,
- p_diag_data->vrdcvtyp,
- p_diag_data->vrdcrccl,
- p_diag_data->vrdccrty,
- p_diag_data->vrdccrmd );
- if (cio_debug_initialized)
- debug_sprintf_event( cio_debug_msg_id, 0,
- "DIAG X'210' for "
- "device %04X returned "
- "(cc = %d): vdev class : %02X, "
- "vdev type : %04X n ... rdev class : %02X, rdev type : %04X, rdev model: %02Xn",
- devno,
- ccode,
- p_diag_data->vrdcvcla,
- p_diag_data->vrdcvtyp,
- p_diag_data->vrdcrccl,
- p_diag_data->vrdccrty,
- p_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 = 0;
- int ret = 0;
- int emulated = 0;
- int retry = 5;
- char dbf_txt[15];
- if ( !buffer || !length )
- {
- return( -EINVAL );
- } /* endif */
- SANITY_CHECK(irq);
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
- } /* endif */
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "rddevch%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- /*
- * 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,
- SA_PROBE, "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->count = length;
- rdc_ccw->flags = CCW_FLAG_SLI;
- ret = set_normalized_cda( rdc_ccw, (unsigned long)rdc_buf );
- if (!ret) {
- memset( ioinfo[irq]->irq_desc.dev_id,
- ' ',
- sizeof( devstat_t));
- ret = s390_start_IO( irq,
- rdc_ccw,
- 0x00524443, // RDC
- 0, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_DONT_CALL_INTHDLR );
- retry--;
- devflag = ioinfo[irq]->irq_desc.dev_id->flag;
-
- clear_normalized_cda( rdc_ccw);
- } else {
- udelay(100); //wait for recovery
- retry--;
- }
- } while ( ( retry )
- && ( ret || (devflag & DEVSTAT_STATUS_PENDING) ) );
- } /* endif */
- if ( !retry )
- {
- ret = (ret==-ENOMEM)?-ENOMEM:-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, __u8 lpm )
- {
- unsigned long flags;
- int ciw_cnt;
- int found = 0; // RCD CIW found
- int ret = 0; // return code
- char dbf_txt[15];
- SANITY_CHECK(irq);
- if ( !buffer || !length )
- {
- return( -EINVAL);
- }
- else if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
- }
- else if ( ioinfo[irq]->ui.flags.esid == 0 )
- {
- return( -EOPNOTSUPP );
- } /* endif */
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "rdconf%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- /*
- * scan for RCD command in extended SenseID data
- */
-
- for ( ciw_cnt = 0; (found == 0) && (ciw_cnt < 62); ciw_cnt++ )
- {
- if ( ioinfo[irq]->senseid.ciw[ciw_cnt].ct == CIW_TYPE_RCD )
- {
- /*
- * paranoia check ...
- */
- if ( ioinfo[irq]->senseid.ciw[ciw_cnt].cmd != 0 )
- {
- found = 1;
- } /* endif */
- break;
- } /* endif */
- } /* endfor */
- if ( found )
- {
- devstat_t devstat; /* inline device status area */
- devstat_t *pdevstat;
- int ioflags;
- ccw1_t *rcd_ccw = &ioinfo[irq]->senseccw;
- char *rcd_buf = NULL;
- int emulated = 0; /* no i/O handler installed */
- int retry = 5; /* retry count */
- __save_flags(flags);
- __cli();
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- pdevstat = &devstat;
- ret = request_irq( irq,
- init_IRQ_handler,
- SA_PROBE, "RCD", pdevstat );
- if ( !ret )
- {
- emulated = 1;
- } /* endif */
- }
- else
- {
- pdevstat = ioinfo[irq]->irq_desc.dev_id;
- } /* endif */
- if ( !ret )
- {
- if ( init_IRQ_complete )
- {
- rcd_buf = kmalloc( ioinfo[irq]->senseid.ciw[ciw_cnt].count,
- GFP_DMA);
- }
- else
- {
- rcd_buf = alloc_bootmem_low( ioinfo[irq]->senseid.ciw[ciw_cnt].count);
- } /* endif */
- if ( rcd_buf == NULL )
- {
- ret = -ENOMEM;
- } /* endif */
- if ( !ret )
- {
- memset( rcd_buf,
- ' ',
- ioinfo[irq]->senseid.ciw[ciw_cnt].count);
-
- 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;
- memset( pdevstat, ' ', sizeof( devstat_t));
- if ( lpm )
- {
- ioflags = DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM
- | DOIO_DONT_CALL_INTHDLR;
- }
- else
- {
- ioflags = DOIO_WAIT_FOR_INTERRUPT
- | DOIO_DONT_CALL_INTHDLR;
-
- } /* endif */
- ret = s390_start_IO( irq,
- rcd_ccw,
- 0x00524344, // == RCD
- lpm,
- ioflags );
- switch ( ret ) {
- case 0:
- case -EIO:
-
- if ( !(pdevstat->flag & ( DEVSTAT_STATUS_PENDING
- | DEVSTAT_NOT_OPER
- | DEVSTAT_FLAG_SENSE_AVAIL ) ) )
- {
- retry = 0; // we got it ...
- }
- else
- {
- retry--; // try again ...
-
- } /* endif */
-
- break;
- default: // -EBUSY, -ENODEV, ???
- retry = 0;
-
- } /* endswitch */
-
- } while ( retry );
- } /* endif */
- __restore_flags( flags );
- } /* endif */
- /*
- * on success we update the user input parms
- */
- if ( ret == 0 )
- {
- *length = ioinfo[irq]->senseid.ciw[ciw_cnt].count;
- *buffer = rcd_buf;
- }
- else
- {
- if ( rcd_buf != NULL )
- {
- if ( init_IRQ_complete )
- {
- kfree( rcd_buf );
- }
- else
- {
- free_bootmem( (unsigned long)rcd_buf,
- ioinfo[irq]->senseid.ciw[ciw_cnt].count);
- } /* endif */
- } /* endif */
- *buffer = NULL;
- *length = 0;
-
- } /* endif */
- if ( emulated )
- free_irq( irq, pdevstat);
- }
- else
- {
- ret = -EOPNOTSUPP;
- } /* endif */
- return( ret );
- }
- int get_dev_info( int irq, s390_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 = -ENODEV;
- while ( pi!=NULL ) {
- if ( pi->ui.flags.oper ) {
- ret_val = pi->irq;
- break;
- } else {
- pi = pi->next;
- }
- }
- 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, s390_dev_info_t *pdi)
- {
- SANITY_CHECK(irq);
- if ( pdi == NULL )
- return -EINVAL;
- pdi->devno = ioinfo[irq]->schib.pmcw.dev;
- pdi->irq = irq;
-
- if ( ioinfo[irq]->ui.flags.oper
- && !ioinfo[irq]->ui.flags.unknown )
- {
- pdi->status = 0;
- memcpy( &(pdi->sid_data),
- &ioinfo[irq]->senseid,
- sizeof( senseid_t));
- }
- else if ( ioinfo[irq]->ui.flags.unknown )
- {
- pdi->status = DEVSTAT_UNKNOWN_DEV;
- memset( &(pdi->sid_data),
- ' ',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
- memset( &(pdi->sid_data),
- ' ',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
-
- } /* endif */
-
- if ( ioinfo[irq]->ui.flags.ready )
- pdi->status |= DEVSTAT_DEVICE_OWNED;
- return 0;
- }
- int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi)
- {
- int i;
- int rc = -ENODEV;
- if ( devno > 0x0000ffff )
- return -ENODEV;
- if ( pdi == NULL )
- return -EINVAL;
- for ( i=0; i <= highest_subchannel; i++ ) {
-
- if ( ioinfo[i] != INVALID_STORAGE_AREA
- && ioinfo[i]->schib.pmcw.dev == devno )
- {
-
- pdi->irq = i;
- pdi->devno = devno;
-
- if ( ioinfo[i]->ui.flags.oper
- && !ioinfo[i]->ui.flags.unknown )
- {
- pdi->status = 0;
- memcpy( &(pdi->sid_data),
- &ioinfo[i]->senseid,
- sizeof( senseid_t));
- }
- else if ( ioinfo[i]->ui.flags.unknown )
- {
- pdi->status = DEVSTAT_UNKNOWN_DEV;
- memset( &(pdi->sid_data),
- ' ',
- sizeof( senseid_t));
- pdi->sid_data.cu_type = 0xFFFF;
- }
- else
- {
- pdi->status = DEVSTAT_NOT_OPER;
-
- memset( &(pdi->sid_data),
- ' ',
- 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);
- }
- 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_irq
- *
- * Used for individual device recognition. Issues the device
- * independant SenseID command to obtain info the device type.
- *
- */
- void s390_device_recognition_irq( int irq )
- {
- int ret;
- char dbf_txt[15];
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "devrec%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- /*
- * 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 ) )
- {
- int irq_ret;
- devstat_t devstat;
- irq_ret = request_irq( irq,
- init_IRQ_handler,
- SA_PROBE,
- "INIT",
- &devstat);
- if ( !irq_ret )
- {
- ret = enable_cpu_sync_isc( irq );
- if ( !ret )
- {
- ioinfo[irq]->ui.flags.unknown = 0;
- memset( &ioinfo[irq]->senseid, ' ', sizeof( senseid_t));
- s390_SenseID( irq, &ioinfo[irq]->senseid, 0xff );
- #if 0 /* FIXME */
- /*
- * We initially check the configuration data for
- * those devices with more than a single path
- */
- if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
- {
- char *prcd;
- int lrcd;
- ret = read_conf_data( irq, (void **)&prcd, &lrcd, 0 );
- if ( !ret ) // on success only ...
- {
- char buffer[80];
- #ifdef CONFIG_DEBUG_IO
- sprintf( buffer,
- "RCD for device(%04X)/"
- "subchannel(%04X) returns :n",
- ioinfo[irq]->schib.pmcw.dev,
- irq );
- s390_displayhex( buffer, prcd, lrcd );
- #endif
- if (cio_debug_initialized) {
- sprintf( buffer,
- "RCD for device(%04X)/"
- "subchannel(%04X) returns :n",
- ioinfo[irq]->schib.pmcw.dev,
- irq );
-
- s390_displayhex2( buffer, prcd, lrcd, 2);
- }
- if ( init_IRQ_complete )
- {
- kfree( prcd );
- }
- else
- {
- free_bootmem( (unsigned long)prcd, lrcd );
- } /* endif */
- } /* endif */
-
- } /* endif */
- #endif
- disable_cpu_sync_isc( irq );
- } /* endif */
- free_irq( irq, &devstat );
- } /* endif */
-
- } /* endif */
- }
- /*
- * s390_device_recognition_all
- *
- * Used for system wide device recognition.
- *
- */
- void s390_device_recognition_all( void)
- {
- int irq = 0; /* let's start with subchannel 0 ... */
- do
- {
- s390_device_recognition_irq( irq );
- irq ++;
- } while ( irq <= highest_subchannel );
- }
- /*
- * Function: s390_redo_validation
- * Look for no longer blacklisted devices
- * FIXME: there must be a better way to do this...
- */
- void s390_redo_validation(void)
- {
- int irq = 0;
- int ret;
- if (cio_debug_initialized) {
- debug_text_event(cio_debug_trace_id, 0, "redoval");
- }
- do {
- if (ioinfo[irq] == INVALID_STORAGE_AREA) {
- ret = s390_validate_subchannel(irq, 0);
- if (!ret) {
- s390_device_recognition_irq(irq);
- if (ioinfo[irq]->ui.flags.oper) {
- devreg_t *pdevreg;
-
- pdevreg = s390_search_devreg( ioinfo[irq] );
- if ( pdevreg != NULL ) {
- if ( pdevreg->oper_func != NULL )
- pdevreg->oper_func( irq, pdevreg );
-
- }
- }
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- if (irq < MAX_CIO_PROCFS_ENTRIES) {
- cio_procfs_device_create(ioinfo[irq]->devno);
- }
- #endif
- }
- }
- irq++;
- } while (irq<=highest_subchannel);
- }
- /*
- * s390_search_devices
- *
- * Determines all subchannels available to the system.
- *
- */
- void s390_process_subchannels( void)
- {
- int ret;
- int irq = 0; /* Evaluate all subchannels starting with 0 ... */
- do
- {
- ret = s390_validate_subchannel( irq, 0);
- if ( ret != -ENXIO)
- irq++;
-
- } while ( (ret != -ENXIO) && (irq < __MAX_SUBCHANNELS) );
- highest_subchannel = (--irq);
- printk( KERN_INFO "Highest subchannel number detected (hex) : %04Xn",
- highest_subchannel);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "Highest subchannel number detected (hex) : %04Xn",
- 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 enable )
- {
- 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;
- int ret;
-
- char dbf_txt[15];
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "valsch%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- /*
- * 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 = p_init_schib;
- } /* endif */
- /*
- * If we knew the device before we assume the worst case ...
- */
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- ioinfo[irq]->ui.flags.oper = 0;
- ioinfo[irq]->ui.flags.dval = 0;
- } /* endif */
- ccode = stsch( irq, p_schib);
- if ( !ccode )
- {
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if ( p_schib->pmcw.st )
- {
- printk( KERN_INFO "Subchannel %04X reports "
- "non-I/O subchannel type %04Xn",
- irq,
- p_schib->pmcw.st);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "Subchannel %04X reports non-I/O subchannel type %04Xn",
- irq, p_schib->pmcw.st);
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- ioinfo[irq]->ui.flags.oper = 0;
- } /* endif */
- if ( p_schib->pmcw.dnv )
- {
- if ( is_blacklisted( p_schib->pmcw.dev )) {
- /*
- * This device must not be known to Linux. So we simply say that
- * there is no device and return ENODEV.
- */
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_DEBUG "Blacklisted device detected at devno %04Xn", p_schib->pmcw.dev );
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "Blacklisted device detected at devno %04Xn",
- p_schib->pmcw.dev);
- ret = -ENODEV;
- } else {
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- {
- if ( !init_IRQ_complete )
- {
- ioinfo[irq] =
- (ioinfo_t *)alloc_bootmem_low( sizeof(ioinfo_t));
- }
- else
- {
- ioinfo[irq] =
- (ioinfo_t *)kmalloc( sizeof(ioinfo_t),
- GFP_DMA );
- } /* endif */
- memset( ioinfo[irq], ' ', sizeof( ioinfo_t));
- memcpy( &ioinfo[irq]->schib,
- p_init_schib,
- sizeof( schib_t));
-
- /*
- * 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;
- for (pi=ioinfo_head; pi!=NULL; pi=pi->next) {
- 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 */
- }
- } /* endif */
- } /* endif */
- // initialize some values ...
- ioinfo[irq]->ui.flags.pgid_supp = 1;
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
- if ( cio_show_msg )
- {
- printk( KERN_INFO"Detected device %04X "
- "on subchannel %04X"
- " - PIM = %02X, PAM = %02X, POM = %02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- ioinfo[irq]->schib.pmcw.pim,
- ioinfo[irq]->schib.pmcw.pam,
- ioinfo[irq]->schib.pmcw.pom);
- } /* endif */
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "Detected device %04X "
- "on subchannel %04X"
- " - PIM = %02X, PAM = %02X, POM = %02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- ioinfo[irq]->schib.pmcw.pim,
- ioinfo[irq]->schib.pmcw.pam,
- ioinfo[irq]->schib.pmcw.pom);
- /*
- * initialize ioinfo structure
- */
- ioinfo[irq]->irq = irq;
- if(!ioinfo[irq]->ui.flags.ready)
- {
- ioinfo[irq]->nopfunc = NULL;
- ioinfo[irq]->ui.flags.busy = 0;
- ioinfo[irq]->ui.flags.dval = 1;
- ioinfo[irq]->devstat.intparm = 0;
-
- }
- ioinfo[irq]->devstat.devno = ioinfo[irq]->schib.pmcw.dev;
- ioinfo[irq]->devno = ioinfo[irq]->schib.pmcw.dev;
- /*
- * We should have at least one CHPID ...
- */
- if ( ioinfo[irq]->opm )
- {
- /*
- * 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 = enable;
- ioinfo[irq]->schib.pmcw.intparm =
- ioinfo[irq]->schib.pmcw.dev;
- if ( ( ioinfo[irq]->opm != 0x80 )
- && ( ioinfo[irq]->opm != 0x40 )
- && ( ioinfo[irq]->opm != 0x20 )
- && ( ioinfo[irq]->opm != 0x10 )
- && ( ioinfo[irq]->opm != 0x08 )
- && ( ioinfo[irq]->opm != 0x04 )
- && ( ioinfo[irq]->opm != 0x02 )
- && ( ioinfo[irq]->opm != 0x01 ) )
- {
- ioinfo[irq]->schib.pmcw.mp = 1; /* multipath mode */
- } /* endif */
- retry = 5;
- do
- {
- ccode2 = msch_err( irq, &ioinfo[irq]->schib);
- switch (ccode2) {
- case 0: // successful completion
- //
- // concurrent sense facility available ...
- //
- ioinfo[irq]->ui.flags.oper = 1;
- ioinfo[irq]->ui.flags.consns = 1;
- ret = 0;
- break;
-
- case 1: // status pending
- //
- // How can we have a pending status as
- // device is disabled for interrupts ?
- // Anyway, process it ...
- //
- ioinfo[irq]->ui.flags.s_pend = 1;
- s390_process_IRQ( irq);
- ioinfo[irq]->ui.flags.s_pend = 0;
- retry--;
- ret = -EIO;
- break;
-
- case 2: // busy
- /*
- * we mark it not-oper as we can't
- * properly operate it !
- */
- ioinfo[irq]->ui.flags.oper = 0;
- udelay( 100); /* allow for recovery */
- retry--;
- ret = -EBUSY;
- break;
- case 3: // not operational
- ioinfo[irq]->ui.flags.oper = 0;
- retry = 0;
- ret = -ENODEV;
- 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( KERN_ERR " ... msch() (2) failed with CC = %Xn",
- ccode2 );
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "msch() (2) failed with CC=%Xn",
- ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -EIO;
- }
- else
- {
- ioinfo[irq]->ui.flags.oper = 1;
- ioinfo[irq]->ui.flags.consns = 0;
- ret = 0;
- } /* endif */
- }
- else
- {
- printk( KERN_ERR " ... msch() (1) failed with CC = %Xn",
- ccode2);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- "msch() (1) failed with CC = %Xn",
- ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -EIO;
- } /* endif */
-
- retry = 0;
- break;
- } /* endswitch */
- } while ( ccode2 && retry );
- if ( (ccode2 != 0) && (ccode2 != 3) && (!retry) )
- {
- printk( KERN_ERR " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %dn",
- irq,
- ccode2);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 0,
- " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %dn",
- irq, ccode2);
- } /* endif */
- }
- else
- {
- /* no path available ... */
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- } /* endif */
- }
- }
- else
- {
- ret = -ENODEV;
- } /* endif */
- }
- else
- {
- ret = -ENXIO;
- } /* endif */
- return( ret );
- }
- /*
- * 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, __u8 lpm )
- {
- ccw1_t *sense_ccw; /* ccw area for SenseID command */
- senseid_t isid; /* internal sid */
- devstat_t devstat; /* required by request_irq() */
- __u8 pathmask; /* calulate path mask */
- __u8 domask; /* path mask to use */
- int inlreq; /* inline request_irq() */
- int irq_ret; /* return code */
- devstat_t *pdevstat; /* ptr to devstat in use */
- int retry; /* retry count */
- int io_retry; /* retry indicator */
- senseid_t *psid = sid;/* start with the external buffer */
- int sbuffer = 0; /* switch SID data buffer */
- char dbf_txt[15];
- int failure = 0; /* nothing went wrong yet */
- SANITY_CHECK(irq);
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
- } /* endif */
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "snsID%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- inlreq = 0; /* to make the compiler quiet... */
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- pdevstat = &devstat;
- /*
- * 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, SA_PROBE, "SID", &devstat);
- if ( irq_ret == 0 )
- inlreq = 1;
- }
- else
- {
- inlreq = 0;
- irq_ret = 0;
- pdevstat = ioinfo[irq]->irq_desc.dev_id;
- } /* endif */
- if ( irq_ret == 0 )
- {
- int i;
- s390irq_spin_lock( irq);
- if ( init_IRQ_complete )
- {
- sense_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
- }
- else
- {
- sense_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
- } /* endif */
- // more than one path installed ?
- if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
- {
- sense_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
- sense_ccw[0].cda = 0;
- sense_ccw[0].count = 0;
- sense_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- sense_ccw[1].cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw[1].cda = (__u32)virt_to_phys( sid );
- sense_ccw[1].count = sizeof( senseid_t);
- sense_ccw[1].flags = CCW_FLAG_SLI;
- }
- else
- {
- sense_ccw[0].cmd_code = CCW_CMD_SENSE_ID;
- sense_ccw[0].cda = (__u32)virt_to_phys( sid );
- sense_ccw[0].count = sizeof( senseid_t);
- sense_ccw[0].flags = CCW_FLAG_SLI;
- } /* endif */
- for ( i = 0 ; (i < 8) ; i++ )
- {
- pathmask = 0x80 >> i;
- domask = ioinfo[irq]->opm & pathmask;
- if ( lpm )
- domask &= lpm;
- if ( domask )
- {
- failure = 0;
-
- psid->reserved = 0;
- psid->cu_type = 0xFFFF; /* initialize fields ... */
- psid->cu_model = 0;
- psid->dev_type = 0;
- psid->dev_model = 0;
- retry = 5; /* retry count */
- io_retry = 1; /* enable retries */
- /*
- * We now issue a SenseID request. In case of BUSY,
- * STATUS PENDING or non-CMD_REJECT error conditions
- * we run simple retries.
- */
- do
- {
- memset( pdevstat, ' ', sizeof( devstat_t) );
- irq_ret = s390_start_IO( irq,
- sense_ccw,
- 0x00E2C9C4, // == SID
- domask,
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_TIMEOUT
- | DOIO_VALID_LPM
- | DOIO_DONT_CALL_INTHDLR );
- if ( psid->cu_type == 0xFFFF )
- {
- failure = 1;
- if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_DEBUG "SenseID : device %04X on "
- "Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : device %04X on "
- "Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- } /* endif */
- else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * if the device doesn't support the SenseID
- * command further retries wouldn't help ...
- */
- if ( pdevstat->ii.sense.data[0]
- & (SNS0_CMD_REJECT | SNS0_INTERVENTION_REQ) )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_ERR "SenseID : device %04X on "
- "Subchannel %04X "
- "reports cmd reject or "
- "intervention requiredn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : device %04X on "
- "Subchannel %04X "
- "reports cmd reject or "
- "intervention requiredn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- io_retry = 0;
- }
- else
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_WARNING "SenseID : UC on "
- "dev %04X, "
- "retry %d, "
- "lpum %02X, "
- "cnt %02d, "
- "sns :"
- " %02X%02X%02X%02X "
- "%02X%02X%02X%02X ...n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- pdevstat->lpum,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- #endif
- if (cio_debug_initialized) {
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : UC on "
- "dev %04X, "
- "retry %d, "
- "lpum %02X, "
- "cnt %02d, "
- "sns :"
- " %02X%02X%02X%02X "
- "%02X%02X%02X%02X ...n",
- ioinfo[irq]->schib.pmcw.dev,
- retry,
- pdevstat->lpum,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- if (psid->reserved != 0xFF)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID was not properly "
- "executed!n");
- }
- } /* endif */
- }
- else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER )
- || ( irq_ret == -ENODEV ) )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_ERR "SenseID : path %02X for "
- "device %04X on "
- "subchannel %04X "
- "is 'not operational'n",
- domask,
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : path %02X for "
- "device %04X on "
- "subchannel %04X "
- "is 'not operational'n",
- domask,
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- io_retry = 0;
- ioinfo[irq]->opm &= ~domask;
-
- }
- else if ( ( pdevstat->flag !=
- ( DEVSTAT_START_FUNCTION
- | DEVSTAT_FINAL_STATUS ) )
- && !( pdevstat->flag &
- DEVSTAT_STATUS_PENDING ) )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_INFO "SenseID : start_IO() for "
- "device %04X on "
- "subchannel %04X "
- "returns %d, retry %d, "
- "status %04Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- irq_ret,
- retry,
- pdevstat->flag);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : start_IO() for "
- "device %04X on "
- "subchannel %04X "
- "returns %d, retry %d, "
- "status %04Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- irq_ret,
- retry,
- pdevstat->flag);
- } /* endif */
- }
- else // we got it ...
- {
- if (psid->reserved != 0xFF) {
- /* No, we failed after all... */
- failure = 1;
- retry--;
- } else {
-
- if ( !sbuffer ) // switch buffers
- {
- /*
- * we report back the
- * first hit only
- */
- psid = &isid;
-
- if ( ioinfo[irq]->schib.pmcw.pim != 0x80 )
- {
- sense_ccw[1].cda = (__u32)virt_to_phys( psid );
- }
- else
- {
- sense_ccw[0].cda = (__u32)virt_to_phys( psid );
- } /* endif */
- /*
- * if just the very first
- * was requested to be
- * sensed disable further
- * scans.
- */
- if ( !lpm )
- lpm = domask;
-
- sbuffer = 1;
-
- } /* endif */
- if ( pdevstat->rescnt < (sizeof( senseid_t) - 8) )
- {
- ioinfo[irq]->ui.flags.esid = 1;
-
- } /* endif */
- io_retry = 0;
-
- }
- } /* endif */
- if ( io_retry )
- {
- retry--;
- if ( retry == 0 )
- {
- io_retry = 0;
- } /* endif */
-
- } /* endif */
- if ((failure) && (io_retry)) {
- /* reset fields... */
- failure = 0;
-
- psid->reserved = 0;
- psid->cu_type = 0xFFFF;
- psid->cu_model = 0;
- psid->dev_type = 0;
- psid->dev_model = 0;
- }
-
- } while ( (io_retry) );
- } /* endif - domask */
- } /* endfor */
- if ( init_IRQ_complete )
- {
- kfree( sense_ccw );
- }
- else
- {
- free_bootmem( (unsigned long)sense_ccw, 2*sizeof(ccw1_t) );
- } /* endif */
- s390irq_spin_unlock( irq);
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, pdevstat);
- /*
- * 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".
- */
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_WARNING "SenseID : unknown device %04X on subchannel %04Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : unknown device %04X on subchannel %04Xn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- ioinfo[irq]->ui.flags.unknown = 1;
- } /* endif */
-
- /*
- * Issue device info message if unit was operational .
- */
- if ( !ioinfo[irq]->ui.flags.unknown ) {
- if ( sid->dev_type != 0 ) {
- if ( cio_show_msg )
- printk( KERN_INFO"SenseID : device %04X reports: "
- "CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : device %04X reports: "
- "CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- } else {
- if ( cio_show_msg )
- printk( KERN_INFO"SenseID : device %04X reports:"
- " Dev Type/Mod = %04X/%02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SenseID : device %04X reports:"
- " Dev Type/Mod = %04X/%02Xn",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
- } /* endif */
- } /* endif */
- if ( !ioinfo[irq]->ui.flags.unknown )
- 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.
- *
- * Note : This function must not be called during normal device recognition,
- * but during device driver initiated request_irq() processing only.
- */
- int s390_DevicePathVerification( int irq, __u8 usermask )
- {
- int ccode;
- __u8 pathmask;
- __u8 domask;
- int ret = 0;
- char dbf_txt[15];
- if (cio_debug_initialized) {
- sprintf(dbf_txt, "dpver%x", irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
- {
- return( 0); // just exit ...
- } /* endif */
- ccode = stsch( irq, &(ioinfo[irq]->schib) );
- if ( ccode )
- {
- ret = -ENODEV;
- }
- else if ( ioinfo[irq]->schib.pmcw.pim == 0x80 )
- {
- /*
- * no error, just not required for single path only devices
- */
- ioinfo[irq]->ui.flags.pgid_supp = 0;
- ret = 0;
- }
- else
- {
- int i;
- pgid_t pgid;
- __u8 dev_path;
- int first = 1;
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
- if ( usermask )
- {
- dev_path = usermask;
- }
- else
- {
- dev_path = ioinfo[irq]->opm;
- } /* endif */
- /*
- * let's build a path group ID if we don't have one yet
- */
- if ( ioinfo[irq]->ui.flags.pgid == 0)
- {
- ioinfo[irq]->pgid.cpu_addr = *(__u16 *)__LC_CPUADDR;
- ioinfo[irq]->pgid.cpu_id = ((cpuid_t *)__LC_CPUID)->ident;
- ioinfo[irq]->pgid.cpu_model = ((cpuid_t *)__LC_CPUID)->machine;
- ioinfo[irq]->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;
- domask = dev_path & pathmask;
- if ( domask )
- {
- ret = s390_SetPGID( irq, domask, &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, domask, &pgid);
- first = 0;
- if ( ret == 0 )
- {
- /*
- * Check whether we retrieved
- * a reasonable PGID ...
- */
- if ( pgid.inf.ps.state1 == SNID_STATE1_GROUPED )
- {
- memcpy( &(ioinfo[irq]->pgid),
- &pgid,
- sizeof(pgid_t) );
- }
- else // ungrouped or garbage ...
- {
- ret = -EOPNOTSUPP;
- } /* endif */
- }
- else
- {
- ioinfo[irq]->ui.flags.pgid_supp = 0;
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_WARNING "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path groupingn",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path groupingn",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
- } /* endif */
- }
- else if ( ret == -EIO )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_ERR "PathVerification(%04X) - I/O error "
- "on device %04Xn", irq,
- ioinfo[irq]->schib.pmcw.dev);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "PathVerification(%04X) - I/O error "
- "on device %04Xn", irq,
- ioinfo[irq]->schib.pmcw.dev);
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- } else {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_ERR "PathVerification(%04X) "
- "- Unexpected error on device %04Xn",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "PathVerification(%04X) - "
- "Unexpected error on device %04Xn",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- ioinfo[irq]->ui.flags.pgid_supp = 0;
-
- } /* endif */
- } /* endif */
-
- } /* endfor */
- } /* endif */
- return ret;
- }
- /*
- * 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() */
- devstat_t *pdevstat = &devstat;
- unsigned long flags;
- char dbf_txt[15];
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
- int mpath = 1; /* try multi-path first */
- SANITY_CHECK(irq);
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
- } /* endif */
- if (cio_debug_initialized) {
- sprintf(dbf_txt,"SPID%x",irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SetPGID 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,
- SA_PROBE,
- "SPID",
- pdevstat);
- if ( irq_ret == 0 )
- inlreq = 1;
- }
- else
- {
- pdevstat = ioinfo[irq]->irq_desc.dev_id;
- } /* endif */
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock_irqsave( irq, flags);
- if ( init_IRQ_complete )
- {
- spid_ccw = kmalloc( 2*sizeof( ccw1_t), GFP_DMA);
- }
- else
- {
- spid_ccw = alloc_bootmem_low( 2*sizeof( ccw1_t));
- } /* endif */
- spid_ccw[0].cmd_code = CCW_CMD_SUSPEND_RECONN;
- spid_ccw[0].cda = 0;
- spid_ccw[0].count = 0;
- spid_ccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- spid_ccw[1].cmd_code = CCW_CMD_SET_PGID;
- spid_ccw[1].cda = (__u32)virt_to_phys( pgid );
- spid_ccw[1].count = sizeof( pgid_t);
- spid_ccw[1].flags = CCW_FLAG_SLI;
- pgid->inf.fc = SPID_FUNC_MULTI_PATH | SPID_FUNC_ESTABLISH;
- /*
- * We now issue a SetPGID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( pdevstat, ' ', sizeof( devstat_t) );
- irq_ret = s390_start_IO( irq,
- spid_ccw,
- 0xE2D7C9C4, // == SPID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM
- | DOIO_DONT_CALL_INTHDLR );
- if ( !irq_ret )
- {
- if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_DEBUG "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- retry--;
- irq_ret = -EIO;
- } /* endif */
- if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION
- | DEVSTAT_FINAL_STATUS ) )
- {
- retry = 0; // successfully set ...
- irq_ret = 0;
- }
- else if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- if ( mpath )
- {
- /*
- * We now try single path mode.
- * Note we must not issue the suspend
- * multipath reconnect, or we will get
- * a command reject by tapes.
- */
-
- spid_ccw[0].cmd_code = CCW_CMD_SET_PGID;
- spid_ccw[0].cda = (__u32)virt_to_phys( pgid );
- spid_ccw[0].count = sizeof( pgid_t);
- spid_ccw[0].flags = CCW_FLAG_SLI;
- pgid->inf.fc = SPID_FUNC_SINGLE_PATH
- | SPID_FUNC_ESTABLISH;
- mpath = 0;
- retry--;
- irq_ret = -EIO;
- }
- else
- {
- irq_ret = -EOPNOTSUPP;
- retry = 0;
- } /* endif */
- }
- else
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_WARNING "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,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "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,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- retry--;
- irq_ret = -EIO;
-
- } /* endif */
- }
- else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
- {
- /* don't issue warnings during startup unless requested*/
- if (init_IRQ_complete || cio_notoper_msg) {
-
- printk( KERN_WARNING "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- }
- retry = 0;
- irq_ret = -EIO;
- } /* endif */
- }
- else if ( irq_ret != -ENODEV )
- {
- retry--;
- irq_ret = -EIO;
- }
- else
- {
- retry = 0;
- irq_ret = -ENODEV;
- } /* endif */
- } while ( retry > 0 );
- if ( init_IRQ_complete )
- {
- kfree( spid_ccw );
- }
- else
- {
- free_bootmem( (unsigned long)spid_ccw, 2*sizeof(ccw1_t) );
- } /* endif */
- s390irq_spin_unlock_irqrestore( irq, flags);
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, pdevstat);
- } /* 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() */
- devstat_t *pdevstat = &devstat;
- char dbf_txt[15];
- int irq_ret = 0; /* return code */
- int retry = 5; /* retry count */
- int inlreq = 0; /* inline request_irq() */
- unsigned long flags;
- SANITY_CHECK(irq);
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- return( -ENODEV );
- } /* endif */
- if (cio_debug_initialized) {
- sprintf(dbf_txt,"SNID%x",irq);
- debug_text_event(cio_debug_trace_id, 4, dbf_txt);
- }
- if ( !ioinfo[irq]->ui.flags.ready )
- {
- /*
- * Perform SENSE PGID 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,
- SA_PROBE,
- "SNID",
- pdevstat);
- if ( irq_ret == 0 )
- inlreq = 1;
- }
- else
- {
- pdevstat = ioinfo[irq]->irq_desc.dev_id;
- } /* endif */
- if ( irq_ret == 0 )
- {
- s390irq_spin_lock_irqsave( irq, flags);
- if ( init_IRQ_complete )
- {
- snid_ccw = kmalloc( sizeof( ccw1_t), GFP_DMA);
- }
- else
- {
- snid_ccw = alloc_bootmem_low( sizeof( ccw1_t));
- } /* endif */
- 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 SensePGID request. In case of BUSY
- * or STATUS PENDING conditions we retry 5 times.
- */
- do
- {
- memset( pdevstat, ' ', sizeof( devstat_t) );
- irq_ret = s390_start_IO( irq,
- snid_ccw,
- 0xE2D5C9C4, // == SNID
- lpm, // n/a
- DOIO_WAIT_FOR_INTERRUPT
- | DOIO_VALID_LPM
- | DOIO_DONT_CALL_INTHDLR );
- if ( irq_ret == 0 )
- {
- if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
- {
- /*
- * If the device doesn't support the
- * Sense Path Group ID command
- * further retries wouldn't help ...
- */
- if ( pdevstat->ii.sense.data[0] & SNS0_CMD_REJECT )
- {
- retry = 0;
- irq_ret = -EOPNOTSUPP;
- }
- else
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_WARNING "SNID - device %04X,"
- " unit check,"
- " flag %04X, "
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...n",
- ioinfo[irq]->schib.pmcw.dev,
- pdevstat->flag,
- retry,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SNID - device %04X,"
- " unit check,"
- " flag %04X, "
- " retry %d, cnt %02d,"
- " sns :"
- " %02X%02X%02X%02X %02X%02X%02X%02X ...n",
- ioinfo[irq]->schib.pmcw.dev,
- pdevstat->flag,
- retry,
- pdevstat->scnt,
- pdevstat->ii.sense.data[0],
- pdevstat->ii.sense.data[1],
- pdevstat->ii.sense.data[2],
- pdevstat->ii.sense.data[3],
- pdevstat->ii.sense.data[4],
- pdevstat->ii.sense.data[5],
- pdevstat->ii.sense.data[6],
- pdevstat->ii.sense.data[7]);
- retry--;
- irq_ret = -EIO;
- } /* endif */
- }
- else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
- {
- /* don't issue warnings during startup unless requested*/
- if (init_IRQ_complete || cio_notoper_msg) {
- printk( KERN_WARNING "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- }
- retry = 0;
- irq_ret = -EIO;
- }
- else
- {
- retry = 0; // success ...
- irq_ret = 0;
- } /* endif */
- }
- else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
- {
- if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
- {
- #ifdef CONFIG_DEBUG_IO
- printk( KERN_INFO "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.dev,
- irq,
- retry);
- } /* endif */
- printk( KERN_WARNING "SNID - device %04X,"
- " start_io() reports rc : %d, retrying ...n",
- ioinfo[irq]->schib.pmcw.dev,
- irq_ret);
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2,
- "SNID - device %04X,"
- " start_io() reports rc : %d, retrying ...n",
- ioinfo[irq]->schib.pmcw.dev,
- irq_ret);
- retry--;
- irq_ret = -EIO;
- }
- else // -ENODEV ...
- {
- retry = 0;
- irq_ret = -ENODEV;
- } /* endif */
- } while ( retry > 0 );
- if ( init_IRQ_complete )
- {
- kfree( snid_ccw );
- }
- else
- {
- free_bootmem( (unsigned long)snid_ccw, sizeof(ccw1_t) );
- } /* endif */
- s390irq_spin_unlock_irqrestore( irq, flags);
- /*
- * If we installed the irq action handler we have to
- * release it too.
- */
- if ( inlreq )
- free_irq( irq, pdevstat);
- } /* endif */
- return( irq_ret );
- }
- /*
- * s390_do_crw_pending
- *
- * Called by the machine check handler to process CRW pending
- * conditions. It may be a single CRW, or CRWs may be chained.
- *
- * Note : we currently process CRWs for subchannel source only
- */
- void s390_do_crw_pending( crwe_t *pcrwe )
- {
- int irq;
- int chpid;
- int dev_oper = 0;
- int dev_no = -1;
- int lock = 0;
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : starting ...n");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "do_crw_pending: startingn");
- while ( pcrwe != NULL )
- {
- int is_owned = 0;
- switch ( pcrwe->crw.rsc ) {
- case CRW_RSC_SCH :
- irq = pcrwe->crw.rsid;
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE"do_crw_pending : source is "
- "subchannel %04Xn", irq);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "source is subchannel %04Xn", irq);
- /*
- * If the device isn't known yet
- * we can't lock it ...
- */
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- s390irq_spin_lock( irq );
- lock = 1;
- dev_oper = ioinfo[irq]->ui.flags.oper;
- if ( ioinfo[irq]->ui.flags.dval )
- dev_no = ioinfo[irq]->devno;
- is_owned = ioinfo[irq]->ui.flags.ready;
- } /* endif */
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : subchannel validation - start ...n");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 4,
- "subchannel validation - startn");
- s390_validate_subchannel( irq, is_owned );
- if ( irq > highest_subchannel )
- highest_subchannel = irq;
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : subchannel validation - donen");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 4,
- "subchannel validation - donen");
- /*
- * After the validate processing
- * the ioinfo control block
- * should be allocated ...
- */
- if ( lock )
- {
- s390irq_spin_unlock( irq );
- } /* endif */
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : ioinfo at "
- #ifdef CONFIG_ARCH_S390X
- "%08lXn",
- (unsigned long)ioinfo[irq]);
- #else /* CONFIG_ARCH_S390X */
- "%08Xn",
- (unsigned)ioinfo[irq]);
- #endif /* CONFIG_ARCH_S390X */
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 4,
- "ioinfo at "
- #ifdef CONFIG_ARCH_S390X
- "%08lXn",
- (unsigned long)ioinfo[irq]);
- #else /* CONFIG_ARCH_S390X */
- "%08Xn",
- (unsigned)ioinfo[irq]);
- #endif /* CONFIG_ARCH_S390X */
- } /* endif */
- if ( ioinfo[irq] != INVALID_STORAGE_AREA )
- {
- if ( ioinfo[irq]->ui.flags.oper == 0 )
- {
- not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
- #ifdef CONFIG_PROC_FS
- /* remove procfs entry */
- if (cio_proc_devinfo)
- cio_procfs_device_remove(dev_no);
- #endif
- /*
- * If the device has gone
- * call not oper handler
- */
- if (( dev_oper == 1 )
- && ( nopfunc != NULL))
- {
-
- free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
- nopfunc( irq,DEVSTAT_DEVICE_GONE );
- } /* endif */
- }
- else
- {
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : device "
- "recognition - start ...n");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 4,
- "device recognition - startn");
- s390_device_recognition_irq( irq );
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : device "
- "recognition - donen");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 4,
- "device recognition - donen");
- /*
- * the device became operational
- */
- if ( dev_oper == 0 )
- {
- devreg_t *pdevreg;
- pdevreg = s390_search_devreg( ioinfo[irq] );
- if ( pdevreg != NULL )
- {
- if ( pdevreg->oper_func != NULL )
- pdevreg->oper_func( irq, pdevreg );
- } /* endif */
- #ifdef CONFIG_PROC_FS
- /* add new procfs entry */
- if (cio_proc_devinfo)
- if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
- cio_procfs_device_create(ioinfo[irq]->devno);
- }
- #endif
- }
- /*
- * ... it is and was operational, but
- * the devno may have changed
- */
- else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))
- {
- #ifdef CONFIG_PROC_FS
- int devno_old = ioinfo[irq]->devno;
- #endif
- ioinfo[irq]->nopfunc( irq,
- DEVSTAT_REVALIDATE );
- #ifdef CONFIG_PROC_FS
- /* remove old entry, add new */
- if (cio_proc_devinfo) {
- cio_procfs_device_remove(devno_old);
- cio_procfs_device_create(ioinfo[irq]->devno);
- }
- #endif
- } /* endif */
- } /* endif */
- #ifdef CONFIG_PROC_FS
- /* get rid of dead procfs entries */
- if (cio_proc_devinfo)
- cio_procfs_device_purge();
- #endif
- } /* endif */
- break;
- case CRW_RSC_MONITOR :
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE "do_crw_pending : source is "
- "monitoring facilityn");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "source is monitoring facilityn");
- break;
- case CRW_RSC_CPATH :
- chpid = pcrwe->crw.rsid;
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE "do_crw_pending : source is "
- "channel path %02Xn", chpid);
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "source is channel path %02Xn");
- break;
- case CRW_RSC_CONFIG :
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE "do_crw_pending : source is "
- "configuration-alert facilityn");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "source is configuration-alert facilityn");
- break;
- case CRW_RSC_CSS :
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE "do_crw_pending : source is "
- "channel subsystemn");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "source is channel subsystemn");
- break;
- default :
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_NOTICE "do_crw_pending : unknown sourcen");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "unknown sourcen");
- break;
- } /* endswitch */
- pcrwe = pcrwe->crwe_next;
- } /* endwhile */
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG "do_crw_pending : donen");
- #endif
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_crw_id, 2,
- "do_crw_pending: donen");
- return;
- }
- /* added by Holger Smolinski for reipl support in reipl.S */
- extern void do_reipl (int);
- void
- reipl ( int sch )
- {
- int i;
- s390_dev_info_t dev_info;
- for ( i = 0; i <= highest_subchannel; i ++ )
- {
- if ( get_dev_info_by_irq( i, &dev_info ) == 0
- && (dev_info.status & DEVSTAT_DEVICE_OWNED) )
- {
- free_irq ( i, ioinfo[i]->irq_desc.dev_id );
- }
- }
- if (MACHINE_IS_VM)
- cpcmd("IPL", NULL, 0);
- else
- do_reipl( 0x10000 | sch );
- }
- /*
- * Function: cio_debug_init
- * Initializes three debug logs (under /proc/s390dbf) for common I/O:
- * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
- * - cio_trace logs the calling of different functions
- * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
- * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
- */
- int cio_debug_init( void )
- {
- int ret = 0;
- cio_debug_msg_id = debug_register("cio_msg",4,4,16*sizeof(long));
- if (cio_debug_msg_id != NULL) {
- debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
- #ifdef CONFIG_DEBUG_IO
- debug_set_level(cio_debug_msg_id, 6);
- #else /* CONFIG_DEBUG_IO */
- debug_set_level(cio_debug_msg_id, 2);
- #endif /* CONFIG_DEBUG_IO */
- } else {
- ret = -1;
- }
- cio_debug_trace_id = debug_register("cio_trace",4,4,8);
- if (cio_debug_trace_id != NULL) {
- debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
- #ifdef CONFIG_DEBUG_IO
- debug_set_level(cio_debug_trace_id, 6);
- #else /* CONFIG_DEBUG_IO */
- debug_set_level(cio_debug_trace_id, 2);
- #endif /* CONFIG_DEBUG_IO */
- } else {
- ret = -1;
- }
- cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
- if (cio_debug_crw_id != NULL) {
- debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
- #ifdef CONFIG_DEBUG_CRW
- debug_set_level(cio_debug_crw_id, 6);
- #else /* CONFIG_DEBUG_CRW */
- debug_set_level(cio_debug_crw_id, 2);
- #endif /* CONFIG_DEBUG_CRW */
- } else {
- ret = -1;
- }
- if (ret)
- return ret;
- cio_debug_initialized = 1;
- return 0;
- }
- __initcall(cio_debug_init);
- #ifdef CONFIG_PROC_FS
- /*
- * Display info on subchannels in /proc/subchannels.
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.
- */
- typedef struct {
- char *data;
- int len;
- } tempinfo_t;
- #define MIN(a,b) ((a)<(b)?(a):(b))
- static struct proc_dir_entry *chan_subch_entry;
- static int chan_subch_open( struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- int i = 0;
- int j = 0;
- tempinfo_t *info;
-
- info = (tempinfo_t *) vmalloc( sizeof (tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- return -ENOMEM;
- } else {
- file->private_data = ( void * ) info;
- }
- size += (highest_subchannel+1) * 128;
- info->data = (char *) vmalloc( size );
-
- if (size && info->data == NULL) {
- printk (KERN_WARNING "No memory available for datan");
- vfree (info);
- return -ENOMEM;
- }
-
- len += sprintf( info->data+len,
- "Device sch. Dev Type/Model CU in use PIM PAM POM LPUM CHPIDsn");
- len += sprintf( info->data+len,
- "--------------------------------------------------------------------------n");
- for ( i=0; i <= highest_subchannel; i++) {
- if ( !((ioinfo[i] == NULL) || (ioinfo[i] == INVALID_STORAGE_AREA) || !(ioinfo[i]->ui.flags.oper)) ) {
- len += sprintf( info->data+len,
- "%04X %04X ",
- ioinfo[i]->schib.pmcw.dev,
- i );
- if ( ioinfo[i]->senseid.dev_type != 0 ) {
- len += sprintf( info->data+len,
- "%04X/%02X %04X/%02X",
- ioinfo[i]->senseid.dev_type,
- ioinfo[i]->senseid.dev_model,
- ioinfo[i]->senseid.cu_type,
- ioinfo[i]->senseid.cu_model );
- } else {
- len += sprintf( info->data+len,
- " %04X/%02X",
- ioinfo[i]->senseid.cu_type,
- ioinfo[i]->senseid.cu_model );
- }
- if (ioinfo[i]->ui.flags.ready) {
- len += sprintf( info->data+len, " yes " );
- } else {
- len += sprintf( info->data+len, " " );
- }
- len += sprintf( info->data+len,
- " %02X %02X %02X %02X ",
- ioinfo[i]->schib.pmcw.pim,
- ioinfo[i]->schib.pmcw.pam,
- ioinfo[i]->schib.pmcw.pom,
- ioinfo[i]->schib.pmcw.lpum );
- for ( j=0; j < 8; j++ ) {
- len += sprintf( info->data+len,
- "%02X",
- ioinfo[i]->schib.pmcw.chpid[j] );
- if (j==3) {
- len += sprintf( info->data+len, " " );
- }
- }
- len += sprintf( info->data+len, "n" );
- }
- }
- info->len = len;
- return rc;
- }
- static int chan_subch_close( struct inode *inode, struct file *file)
- {
- int rc = 0;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (p_info) {
- if (p_info->data)
- vfree( p_info->data );
- vfree( p_info );
- }
-
- return rc;
- }
- static ssize_t chan_subch_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
- {
- loff_t len;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-
- if ( *offset>=p_info->len) {
- return 0;
- } else {
- len = MIN(user_len, (p_info->len - *offset));
- if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
- return -EFAULT;
- (* offset) += len;
- return len;
- }
- }
- static struct file_operations chan_subch_file_ops =
- {
- read:chan_subch_read,
- open:chan_subch_open,
- release:chan_subch_close,
- };
- static int chan_proc_init( void )
- {
- chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
- chan_subch_entry->proc_fops = &chan_subch_file_ops;
- return 1;
- }
- __initcall(chan_proc_init);
- void chan_proc_cleanup( void )
- {
- remove_proc_entry( "subchannels", &proc_root);
- }
- /*
- * Display device specific information under /proc/deviceinfo/<devno>
- */
- static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
- /*
- * cio_procfs_device_list holds all devno-specific procfs directories
- */
- typedef struct {
- int devno;
- struct proc_dir_entry *cio_device_entry;
- struct proc_dir_entry *cio_sensedata_entry;
- struct proc_dir_entry *cio_in_use_entry;
- struct proc_dir_entry *cio_chpid_entry;
- } cio_procfs_entry_t;
- typedef struct _cio_procfs_device{
- struct _cio_procfs_device *next;
- cio_procfs_entry_t *entry;
- } cio_procfs_device_t;
- cio_procfs_device_t *cio_procfs_device_list = NULL;
- /*
- * File operations
- */
- static int cio_device_entry_close( struct inode *inode, struct file *file)
- {
- int rc = 0;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (p_info) {
- if (p_info->data)
- vfree( p_info->data );
- vfree( p_info );
- }
-
- return rc;
- }
- static ssize_t cio_device_entry_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
- {
- loff_t len;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-
- if ( *offset>=p_info->len) {
- return 0;
- } else {
- len = MIN(user_len, (p_info->len - *offset));
- if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
- return -EFAULT;
- (* offset) += len;
- return len;
- }
- }
- static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- int irq;
- int devno;
- char * devno_str;
- info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- rc = -ENOMEM;
- } else {
- file->private_data = (void *) info;
- size += 2 * 32;
- info->data = (char *) vmalloc(size);
- if (size && info->data == NULL) {
- printk(KERN_WARNING "No memory available for datan");
- vfree(info);
- rc = -ENOMEM;
- } else {
- devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
- memset(devno_str, 0, 6*sizeof(char));
- memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
- devno = simple_strtoul(devno_str, &devno_str, 16);
- irq = get_irq_by_devno(devno);
- if (irq != -1) {
- len += sprintf(info->data+len, "Dev Type/Mod: ");
- if (ioinfo[irq]->senseid.dev_type == 0) {
- len += sprintf(info->data+len, "%04X/%02Xn",
- ioinfo[irq]->senseid.cu_type,
- ioinfo[irq]->senseid.cu_model);
- } else {
- len += sprintf(info->data+len, "%04X/%02Xn",
- ioinfo[irq]->senseid.dev_type,
- ioinfo[irq]->senseid.dev_model);
- len+= sprintf(info->data+len, "CU Type/Mod: %04X/%02Xn",
- ioinfo[irq]->senseid.cu_type,
- ioinfo[irq]->senseid.cu_model);
- }
- }
- info->len = len;
- }
- }
-
- return rc;
- }
- static int cio_in_use_entry_open( struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- int irq;
- int devno;
- char * devno_str;
- info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- rc = -ENOMEM;
- } else {
- file->private_data = (void *) info;
- size += 8;
- info->data = (char *) vmalloc(size);
- if (size && info->data == NULL) {
- printk(KERN_WARNING "No memory available for datan");
- vfree(info);
- rc = -ENOMEM;
- } else {
- devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
- memset(devno_str, 0, 6*sizeof(char));
- memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
- devno = simple_strtoul(devno_str, &devno_str, 16);
- irq = get_irq_by_devno(devno);
- if (irq != -1) {
- len += sprintf(info->data+len, "%sn", ioinfo[irq]->ui.flags.ready?"yes":"no");
- }
- info->len = len;
- }
- }
-
- return rc;
- }
- static int cio_chpid_entry_open( struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- int irq;
- int devno;
- int i;
- char * devno_str;
- info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- rc = -ENOMEM;
- } else {
- file->private_data = (void *) info;
- size += 8*16;
- info->data = (char *) vmalloc(size);
- if (size && info->data == NULL) {
- printk(KERN_WARNING "No memory available for datan");
- vfree(info);
- rc = -ENOMEM;
- } else {
- devno_str = kmalloc(6*sizeof(char), GFP_KERNEL);
- memset(devno_str, 0, 6*sizeof(char));
- memcpy(devno_str,file->f_dentry->d_parent->d_name.name, strlen(file->f_dentry->d_parent->d_name.name)+1);
- devno = simple_strtoul(devno_str, &devno_str, 16);
- irq = get_irq_by_devno(devno);
- if (irq != -1) {
- for (i=0; i<8; i++) {
- len += sprintf(info->data+len, "CHPID[%d]: ", i);
- len += sprintf(info->data+len, "%02Xn", ioinfo[irq]->schib.pmcw.chpid[i]);
- }
- }
- info->len = len;
- }
- }
- return rc;
- }
- static struct file_operations cio_sensedata_entry_file_ops =
- {
- read:cio_device_entry_read,
- open:cio_sensedata_entry_open,
- release:cio_device_entry_close,
- };
- static struct file_operations cio_in_use_entry_file_ops =
- {
- read:cio_device_entry_read,
- open:cio_in_use_entry_open,
- release:cio_device_entry_close,
- };
- static struct file_operations cio_chpid_entry_file_ops =
- {
- read:cio_device_entry_read,
- open:cio_chpid_entry_open,
- release:cio_device_entry_close,
- };
- /*
- * Function: cio_procfs_device_create
- * create procfs entry for given device number
- * and insert it into list
- */
- int cio_procfs_device_create(int devno)
- {
- cio_procfs_entry_t *entry;
- cio_procfs_device_t *tmp;
- cio_procfs_device_t *where;
- char buf[8];
- int i;
- int rc = 0;
- /* create the directory entry */
- entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
- if (entry) {
- entry->devno = devno;
- sprintf(buf, "%x", devno);
- entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
-
- if (entry->cio_device_entry) {
- tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
- if (tmp) {
- tmp->entry = entry;
-
- if (cio_procfs_device_list == NULL) {
- cio_procfs_device_list = tmp;
- tmp->next = NULL;
- } else {
- where = cio_procfs_device_list;
- i = where->entry->devno;
- while ((devno>i) && (where->next != NULL)) {
- where = where->next;
- i = where->entry->devno;
- }
- if (where->next == NULL) {
- where->next = tmp;
- tmp->next = NULL;
- } else {
- tmp->next = where->next;
- where->next = tmp;
- }
- }
- /* create the different entries */
- entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
- entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
- entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
- entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
- entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
- entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
- } else {
- printk( KERN_WARNING "Error, could not allocate procfs structure!n");
- remove_proc_entry(buf, cio_procfs_deviceinfo_root);
- kfree(entry);
- rc = -ENOMEM;
- }
- } else {
- printk( KERN_WARNING "Error, could not allocate procfs structure!n");
- kfree(entry);
- rc = -ENOMEM;
- }
- } else {
- printk( KERN_WARNING "Error, could not allocate procfs structure!n");
- rc = -ENOMEM;
- }
- return rc;
- }
- /*
- * Function: cio_procfs_device_remove
- * remove procfs entry for given device number
- */
- int cio_procfs_device_remove(int devno)
- {
- int rc = 0;
- cio_procfs_device_t *tmp;
- cio_procfs_device_t *prev = NULL;
- tmp=cio_procfs_device_list;
- while (tmp) {
- if (tmp->entry->devno == devno)
- break;
- prev = tmp;
- tmp = tmp->next;
- }
- if (tmp) {
- char buf[8];
-
- remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
- remove_proc_entry("in_use", tmp->entry->cio_device_entry);
- remove_proc_entry("chpid", tmp->entry->cio_device_entry);
- sprintf(buf, "%x", devno);
- remove_proc_entry(buf, cio_procfs_deviceinfo_root);
-
- if (tmp == cio_procfs_device_list) {
- cio_procfs_device_list = tmp->next;
- } else {
- prev->next = tmp->next;
- }
- kfree(tmp->entry);
- kfree(tmp);
- } else {
- rc = -ENODEV;
- }
- return rc;
- }
- /*
- * Function: cio_procfs_purge
- * purge /proc/deviceinfo of entries for gone devices
- */
- int cio_procfs_device_purge(void)
- {
- int i;
- for (i=0; i<=highest_subchannel; i++) {
- if (ioinfo[i] != INVALID_STORAGE_AREA) {
- if (!ioinfo[i]->ui.flags.oper)
- cio_procfs_device_remove(ioinfo[i]->devno);
- }
- }
- return 0;
- }
- /*
- * Function: cio_procfs_create
- * create /proc/deviceinfo/ and subdirs for the devices
- */
- static int cio_procfs_create( void )
- {
- int irq;
- if (cio_proc_devinfo) {
- cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
-
- if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
- printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
- "Not every device will get an entry.n");
- }
-
- for (irq=0; irq<=highest_subchannel; irq++) {
- if (irq >= MAX_CIO_PROCFS_ENTRIES)
- break;
- if (ioinfo[irq] != INVALID_STORAGE_AREA) {
- if (ioinfo[irq]->ui.flags.oper)
- if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
- printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
- "not all devices might show upn");
- break;
- }
- }
- }
-
- }
-
- return 1;
- }
- __initcall(cio_procfs_create);
- /*
- * Entry /proc/cio_ignore to display blacklisted ranges of devices.
- * un-ignore devices by piping to /proc/cio_ignore:
- * free all frees all blacklisted devices, free <range>,<range>,...
- * frees specified ranges of devnos
- * add <range>,<range>,... will add a range of devices to blacklist -
- * but only for devices not already known
- */
- static struct proc_dir_entry *cio_ignore_proc_entry;
- static int cio_ignore_proc_open(struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- long flags;
- int i, j;
- info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- rc = -ENOMEM;
- } else {
- file->private_data = (void *) info;
- size += nr_ignored * 6;
- info->data = (char *) vmalloc(size);
- if (size && info->data == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- vfree (info);
- rc = -ENOMEM;
- } else {
- spin_lock_irqsave( &blacklist_lock, flags );
- for (i=0;i<=highest_ignored;i++)
- if (test_bit(i,&bl_dev)) {
- len += sprintf(info->data+len, "%04x ", i);
- for (j=i;(j<=highest_ignored) && (test_bit(j,&bl_dev));j++);
- j--;
- if (i != j)
- len += sprintf(info->data+len, "- %04x", j);
- len += sprintf(info->data+len, "n");
- i=j;
- }
- spin_unlock_irqrestore( &blacklist_lock, flags );
- info->len = len;
- }
- }
- return rc;
- }
- static int cio_ignore_proc_close(struct inode *inode, struct file *file)
- {
- int rc = 0;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (p_info) {
- if (p_info->data)
- vfree( p_info->data );
- vfree( p_info );
- }
-
- return rc;
- }
- static ssize_t cio_ignore_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
- {
- loff_t len;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-
- if ( *offset>=p_info->len) {
- return 0;
- } else {
- len = MIN(user_len, (p_info->len - *offset));
- if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
- return -EFAULT;
- (* offset) += len;
- return len;
- }
- }
- static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
- size_t user_len, loff_t * offset)
- {
- char *buffer = vmalloc (user_len);
- if (buffer == NULL)
- return -ENOMEM;
- if (copy_from_user (buffer, user_buf, user_len)) {
- vfree (buffer);
- return -EFAULT;
- }
- buffer[user_len]=' ';
- #ifdef CIO_DEBUG_IO
- printk ( KERN_DEBUG "/proc/cio_ignore: '%s'n", buffer);
- #endif /* CIO_DEBUG_IO */
- if (cio_debug_initialized)
- debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'n",buffer);
- blacklist_parse_proc_parameters(buffer);
- return user_len;
- }
- static struct file_operations cio_ignore_proc_file_ops =
- {
- read:cio_ignore_proc_read,
- open:cio_ignore_proc_open,
- write:cio_ignore_proc_write,
- release:cio_ignore_proc_close,
- };
- static int cio_ignore_proc_init(void)
- {
- cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
- cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
- return 1;
- }
- __initcall(cio_ignore_proc_init);
- /*
- * Entry /proc/irq_count
- * display how many irqs have occured per cpu...
- */
- static struct proc_dir_entry *cio_irq_proc_entry;
- static int cio_irq_proc_open(struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- int i;
- info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
- if (info == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- rc = -ENOMEM;
- } else {
- file->private_data = (void *) info;
- size += NR_CPUS * 16;
- info->data = (char *) vmalloc(size);
- if (size && info->data == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- vfree (info);
- rc = -ENOMEM;
- } else {
- for (i=0; i< NR_CPUS; i++) {
- if (s390_irq_count[i] != 0)
- len += sprintf(info->data+len, "%lxn", s390_irq_count[i]);
- }
- info->len = len;
- }
- }
- return rc;
- }
- static int cio_irq_proc_close(struct inode *inode, struct file *file)
- {
- int rc = 0;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
- if (p_info) {
- if (p_info->data)
- vfree(p_info->data);
- vfree(p_info);
- }
- return rc;
- }
- static ssize_t cio_irq_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
- {
- loff_t len;
- tempinfo_t *p_info = (tempinfo_t *) file->private_data;
-
- if ( *offset>=p_info->len) {
- return 0;
- } else {
- len = MIN(user_len, (p_info->len - *offset));
- if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
- return -EFAULT;
- (* offset) += len;
- return len;
- }
- }
- static struct file_operations cio_irq_proc_file_ops =
- {
- read: cio_irq_proc_read,
- open: cio_irq_proc_open,
- release: cio_irq_proc_close,
- };
- static int cio_irq_proc_init(void)
- {
- int i;
- if (cio_count_irqs) {
- for (i=0; i<NR_CPUS; i++)
- s390_irq_count[i]=0;
- cio_irq_proc_entry = create_proc_entry("irq_count", S_IFREG|S_IRUGO, &proc_root);
- cio_irq_proc_entry->proc_fops = &cio_irq_proc_file_ops;
- }
- return 1;
- }
- __initcall(cio_irq_proc_init);
- /* end of procfs stuff */
- #endif
- schib_t *s390_get_schib( int irq )
- {
- if ( (irq > highest_subchannel) || (irq < 0) )
- return NULL;
- if ( ioinfo[irq] == INVALID_STORAGE_AREA )
- return NULL;
- return &ioinfo[irq]->schib;
- }
- EXPORT_SYMBOL(halt_IO);
- EXPORT_SYMBOL(clear_IO);
- EXPORT_SYMBOL(do_IO);
- EXPORT_SYMBOL(resume_IO);
- EXPORT_SYMBOL(ioinfo);
- EXPORT_SYMBOL(get_dev_info_by_irq);
- EXPORT_SYMBOL(get_dev_info_by_devno);
- EXPORT_SYMBOL(get_irq_by_devno);
- EXPORT_SYMBOL(get_devno_by_irq);
- EXPORT_SYMBOL(get_irq_first);
- EXPORT_SYMBOL(get_irq_next);
- EXPORT_SYMBOL(read_conf_data);
- EXPORT_SYMBOL(read_dev_chars);
- EXPORT_SYMBOL(s390_request_irq_special);
- EXPORT_SYMBOL(s390_get_schib);
- EXPORT_SYMBOL(s390_register_adapter_interrupt);
- EXPORT_SYMBOL(s390_unregister_adapter_interrupt);