s390io.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:198k
- pdi->status |= DEVSTAT_DEVICE_OWNED;
- if (!ioinfo[i]->ui.flags.unfriendly)
- rc = 0; /* found */
- else
- rc = -EUSERS;
- break;
- }
- }
- 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]->st)
- && (ioinfo[i]->schib.pmcw.dev == devno)
- && (ioinfo[i]->schib.pmcw.dnv == 1)) {
- rc = i;
- break;
- }
- }
- }
- return (rc);
- }
- unsigned int
- get_devno_by_irq (int irq)
- {
- if ((irq > highest_subchannel)
- || (irq < 0)
- || (ioinfo[irq] == INVALID_STORAGE_AREA)) {
- return -1;
- }
- if (ioinfo[irq]->st)
- return -1;
- /*
- * 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];
- sprintf (dbf_txt, "dri%x", irq);
- CIO_TRACE_EVENT (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]->st)
- && (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) {
- pgid_t pgid;
- /*
- * First thing we should do is a sensePGID in
- * order to find out how we can proceed with
- * the recognition process.
- * An unfriendly (locked by so else) device
- * won't take kindly to our attempts at
- * SetPGID and SenseID...
- */
-
- memcpy(&pgid, global_pgid, sizeof(pgid_t));
- ret = s390_SensePGID(irq, 0xff, &pgid);
- if (ret == -EOPNOTSUPP)
- /*
- * Doesn't prevent us from proceeding
- */
- ret = 0;
-
- if (!ret && !ioinfo[irq]->ui.flags.unfriendly) {
- ioinfo[irq]->ui.flags.unknown = 0;
-
- memset (&ioinfo[irq]->senseid, ' ',
- sizeof (senseid_t));
-
- if (cio_sid_with_pgid) {
-
- ret = s390_DevicePathVerification(irq,0);
-
- if (ret == -EOPNOTSUPP)
- /*
- * Doesn't prevent us from proceeding
- */
- ret = 0;
- }
- /*
- * we'll fallthrough here if we don't want
- * to do SPID before SID
- */
- if (!ret) {
- 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
- }
- }
- disable_cpu_sync_isc (irq);
- }
- free_irq (irq, &devstat);
- }
- }
- }
- /*
- * 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;
- CIO_TRACE_EVENT (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_trigger_resense
- *
- * try to re-sense the device on subchannel irq
- * only to be called without interrupt handler
- */
- int
- s390_trigger_resense(int irq)
- {
- char dbf_txt[8];
- SANITY_CHECK(irq);
- CIO_TRACE_EVENT (2, "tsns");
- sprintf(dbf_txt, "%x", irq);
- CIO_TRACE_EVENT (2, dbf_txt);
- if (ioinfo[irq]->ui.flags.ready) {
- printk (KERN_WARNING "s390_trigger_resense(%04X): "
- "Device is in use!n", irq);
- return -EBUSY;
- }
- s390_device_recognition_irq(irq);
- return 0;
- }
- /*
- * 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);
- CIO_MSG_EVENT(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;
- #ifdef CONFIG_CHSC
- int chp = 0;
- int mask;
- #endif /* CONFIG_CHSC */
- char dbf_txt[15];
- sprintf (dbf_txt, "vals%x", irq);
- CIO_TRACE_EVENT (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;
- }
- /*
- * 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;
- }
- ccode = stsch (irq, p_schib);
- if (ccode) {
- return -ENXIO;
- }
- /*
- * ... just being curious we check for non I/O subchannels
- */
- if (p_schib->pmcw.st) {
- if (cio_show_msg) {
- printk (KERN_INFO "Subchannel %04X reports "
- "non-I/O subchannel type %04Xn",
- irq, p_schib->pmcw.st);
- }
- CIO_MSG_EVENT(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;
- }
- if ((!p_schib->pmcw.dnv) && (!p_schib->pmcw.st)) {
- return -ENODEV;
- }
- if (!p_schib->pmcw.st) {
- 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
- CIO_MSG_EVENT(0,
- "Blacklisted device detected at devno %04Xn",
- p_schib->pmcw.dev);
- return -ENODEV;
- }
- }
-
- 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);
- }
- 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;
- }
- }
- }
- }
- /* initialize some values ... */
- ioinfo[irq]->irq = irq;
- ioinfo[irq]->st = ioinfo[irq]->schib.pmcw.st;
- if (ioinfo[irq]->st)
- return -ENODEV;
- 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;
- #ifdef CONFIG_CHSC
- if (ioinfo[irq]->opm) {
- for (chp=0;chp<=7;chp++) {
- mask = 0x80 >> chp;
- if (ioinfo[irq]->opm & mask) {
- if (!test_bit
- (ioinfo[irq]->schib.pmcw.chpid[chp],
- &chpids_logical)) {
- /* disable using this path */
- ioinfo[irq]->opm &= ~mask;
- }
- }
- }
- }
- #endif /* CONFIG_CHSC */
- 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);
- }
- CIO_MSG_EVENT(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
- */
- 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 */
- }
- 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 the 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);
- CIO_MSG_EVENT(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;
- }
- } else {
- printk (KERN_ERR
- " ... msch() (1) failed with "
- "CC = %Xn", ccode2);
- CIO_MSG_EVENT(0,
- "msch() (1) failed with "
- "CC = %Xn", ccode2);
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -EIO;
- }
- retry = 0;
- break;
- }
- } while (ccode2 && retry);
- if ((ccode2 != 0) && (ccode2 != 3)
- && (!retry)) {
- printk (KERN_ERR
- " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %dn",
- irq, ccode2);
- CIO_MSG_EVENT(0,
- " ... msch() retry count for "
- "subchannel %04X exceeded, CC = %dn",
- irq, ccode2);
- }
- } else {
- /* no path available ... */
- ioinfo[irq]->ui.flags.oper = 0;
- ret = -ENODEV;
- }
- 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 i;
- int failure = 0; /* nothing went wrong yet */
- SANITY_CHECK (irq);
- if (ioinfo[irq]->ui.flags.oper == 0) {
- return (-ENODEV);
- }
- if (ioinfo[irq]->ui.flags.unfriendly) {
- /* don't even try it */
- return -EUSERS;
- }
- CIO_TRACE_EVENT (4, "senseID");
- sprintf (dbf_txt, "%x", irq);
- CIO_TRACE_EVENT (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;
- }
- if (irq_ret) {
- return irq_ret;
- }
- 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));
- }
- /* 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;
- }
- for (i = 0; (i < 8); i++) {
- pathmask = 0x80 >> i;
- domask = ioinfo[irq]->opm & pathmask;
- if (lpm)
- domask &= lpm;
- if (!domask)
- continue;
- failure = 0;
- memset(psid, 0, sizeof(senseid_t));
- psid->cu_type = 0xFFFF; /* initialize fields ... */
- 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)
- && (psid->reserved == 0xFF)) {
- 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);
- }
- /*
- * if just the very first
- * was requested to be
- * sensed disable further
- * scans.
- */
- if (!lpm)
- lpm = domask;
- sbuffer = 1;
- }
- if (pdevstat->rescnt < (sizeof (senseid_t) - 8)) {
- ioinfo[irq]->ui.flags.esid = 1;
- }
- io_retry = 0;
- break;
- }
- 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
- CIO_MSG_EVENT(2,
- "SenseID : device %04X on "
- "Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo
- [irq]->schib.pmcw.dev, irq, retry);
- }
- 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
- CIO_MSG_EVENT(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
- CIO_MSG_EVENT(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]);
- }
- } 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
- CIO_MSG_EVENT(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 {
- #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
- CIO_MSG_EVENT(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);
- if (irq_ret == -ETIMEDOUT) {
- int xret;
- /*
- * Seems we need to cancel the first ssch sometimes...
- * On the next try, the ssch will usually be fine.
- */
- xret = cancel_IO (irq);
- if (!xret)
- CIO_MSG_EVENT(2,
- "SenseID: sch canceled "
- "successfully for irq %xn",
- irq);
- }
- }
- if (io_retry) {
- retry--;
- if (retry == 0) {
- io_retry = 0;
- }
- }
- if ((failure) && (io_retry)) {
- /* reset fields... */
- failure = 0;
- memset(psid, 0, sizeof(senseid_t));
- psid->cu_type = 0xFFFF;
- }
- } while ((io_retry));
- }
- if (init_IRQ_complete) {
- kfree (sense_ccw);
- } else {
- free_bootmem ((unsigned long) sense_ccw, 2 * sizeof (ccw1_t));
- }
- 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);
- }
- 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
- CIO_MSG_EVENT(2,
- "SenseID : unknown device %04X on subchannel %04Xn",
- ioinfo[irq]->schib.pmcw.dev, irq);
- ioinfo[irq]->ui.flags.unknown = 1;
- }
- /*
- * 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);
- CIO_MSG_EVENT(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);
- CIO_MSG_EVENT(2,
- "SenseID : device %04X reports:"
- " Dev Type/Mod = %04X/%02Xn",
- ioinfo[irq]->schib.
- pmcw.dev,
- sid->cu_type,
- sid->cu_model);
- }
- }
- if (!ioinfo[irq]->ui.flags.unknown)
- irq_ret = 0;
- else
- irq_ret = -ENODEV;
- 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);
- }
- 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;
- #ifdef CONFIG_CHSC
- int chp;
- int mask;
- int old_opm = 0;
- #endif /* CONFIG_CHSC */
- int ret = 0;
- int i;
- pgid_t pgid;
- __u8 dev_path;
- int first = 1;
- char dbf_txt[15];
- sprintf (dbf_txt, "dpvf%x", irq);
- CIO_TRACE_EVENT (4, dbf_txt);
- if (ioinfo[irq]->st)
- return -ENODEV;
- #ifdef CONFIG_CHSC
- old_opm = ioinfo[irq]->opm;
- #endif /* CONFIG_CHSC */
- ccode = stsch (irq, &(ioinfo[irq]->schib));
- if (ccode) {
- return -ENODEV;
- }
- 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;
- #ifdef CONFIG_CHSC
- /*
- * disable if chpid is logically offline
- */
- if (!test_bit(ioinfo[irq]->schib.pmcw.chpid[0],
- &chpids_logical)) {
- not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
- int was_oper = ioinfo[irq]->ui.flags.oper;
- ioinfo[irq]->opm = 0;
- ioinfo[irq]->ui.flags.oper = 0;
- printk(KERN_WARNING
- "No logical path for sch %d...n",
- irq);
- if (old_opm &&
- was_oper &&
- ioinfo[irq]->ui.flags.ready) {
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- cio_procfs_device_remove
- (ioinfo[irq]->devno);
- #endif /* CONFIG_PROC_FS */
- free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
- if (nopfunc)
- nopfunc( irq, DEVSTAT_DEVICE_GONE);
- }
- ret = -ENODEV;
- } else if (!old_opm) {
- /*
- * check for opm...
- */
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam
- & ioinfo[irq]->schib.pmcw.pom;
-
- if (ioinfo[irq]->opm) {
- devreg_t *pdevreg;
- ioinfo[irq]->ui.flags.oper = 1;
- pdevreg = s390_search_devreg( ioinfo[irq] );
- if (pdevreg)
- if (pdevreg->oper_func)
- pdevreg->oper_func
- ( irq, pdevreg);
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- if (highest_subchannel
- < MAX_CIO_PROCFS_ENTRIES) {
- cio_procfs_device_create
- (ioinfo[irq]->devno);
- }
- #endif /* CONFIG_PROC_FS */
- }
- ret = 0;
- } else {
- ret = 0;
- }
- #endif /* CONFIG_CHSC */
- return ret;
- }
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim
- & ioinfo[irq]->schib.pmcw.pam & ioinfo[irq]->schib.pmcw.pom;
- #ifdef CONFIG_CHSC
- if (ioinfo[irq]->opm) {
- for (chp=0;chp<=7;chp++) {
- mask = 0x80 >> chp;
- if (ioinfo[irq]->opm & mask) {
- if (!test_bit
- (ioinfo[irq]->schib.pmcw.chpid[chp],
- &chpids_logical)) {
- /* disable using this path */
- ioinfo[irq]->opm &= ~mask;
- }
- }
- }
- }
-
- if ((ioinfo[irq]->opm == 0) && (old_opm)) {
- not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
- int was_oper = ioinfo[irq]->ui.flags.ready;
- ioinfo[irq]->ui.flags.oper = 0;
- printk(KERN_WARNING "No logical path for sch %d...n",irq);
- if (was_oper && ioinfo[irq]->ui.flags.oper) {
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- cio_procfs_device_remove(ioinfo[irq]->devno);
- #endif /* CONFIG_PROC_FS */
- free_irq( irq, ioinfo[irq]->irq_desc.dev_id);
- if (nopfunc)
- nopfunc( irq, DEVSTAT_DEVICE_GONE);
- }
- return -ENODEV;
- }
- if (!old_opm) {
- /* Hey, we have a new logical path... */
- devreg_t *pdevreg;
-
- ioinfo[irq]->ui.flags.oper = 1;
- pdevreg = s390_search_devreg( ioinfo[irq] );
-
- if (pdevreg)
- if (pdevreg->oper_func)
- pdevreg->oper_func( irq, pdevreg);
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
- cio_procfs_device_create(ioinfo[irq]->devno);
- }
- #endif /* CONFIG_PROC_FS */
- }
- #endif /* CONFIG_CHSC */
- if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
- return( 0); /* just exit ... */
- if (usermask) {
- dev_path = usermask;
- } else {
- dev_path = ioinfo[irq]->opm;
- }
- if (ioinfo[irq]->ui.flags.pgid == 0) {
- memcpy (&ioinfo[irq]->pgid, global_pgid, sizeof (pgid_t));
- ioinfo[irq]->ui.flags.pgid = 1;
- }
- for (i = 0; i < 8 && !ret; i++) {
- pathmask = 0x80 >> i;
- domask = dev_path & pathmask;
- if (domask) {
- ret = s390_SetPGID (irq, domask);
- /*
- * 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;
- }
- } 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
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) "
- "- Device %04X doesn't "
- " support path groupingn",
- irq,
- ioinfo[irq]->schib.
- pmcw.dev);
-
- }
- } 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
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) - I/O error "
- "on device %04Xn", irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- ioinfo[irq]->ui.flags.pgid_supp = 0;
- } else if (ret == -ETIMEDOUT) {
- #ifdef CONFIG_DEBUG_IO
- printk (KERN_ERR
- "PathVerification(%04X) - I/O timed "
- "out on device %04Xn",
- irq,
- ioinfo[irq]->schib.pmcw.dev);
- #endif
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) - I/O timed "
- "out on device %04Xn", irq,
- ioinfo[irq]->schib.pmcw.dev);
-
- ioinfo[irq]->ui.flags.pgid_supp = 0;
- } else if (ret == -EAGAIN) {
- ret = 0;
- } else if (ret == -EUSERS) {
-
- #ifdef CONFIG_DEBUG_IO
- printk (KERN_ERR
- "PathVerification(%04X) "
- "- Device is locked by someone else!n",
- irq);
- #endif
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) "
- "- Device is locked by someone else!n",
- irq);
- } else if (ret == -ENODEV) {
- #ifdef CONFIG_DEBUG_IO
- printk (KERN_ERR
- "PathVerification(%04X) "
- "- Device %04X is no longer there?!?n",
- irq, ioinfo[irq]->schib.pmcw.dev);
- #endif
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) "
- "- Device %04X is no longer there?!?n",
- irq, ioinfo[irq]->schib.pmcw.dev);
- } else if (ret) {
- #ifdef CONFIG_DEBUG_IO
- printk (KERN_ERR
- "PathVerification(%04X) "
- "- Unexpected error %d on device %04Xn",
- irq, ret, ioinfo[irq]->schib.pmcw.dev);
- #endif
- CIO_MSG_EVENT(2,
- "PathVerification(%04X) - "
- "Unexpected error %d on device %04Xn",
- irq, ret, ioinfo[irq]->schib.pmcw.dev);
-
- ioinfo[irq]->ui.flags.pgid_supp = 0;
- }
- }
- }
- return ret;
- }
- /*
- * s390_SetPGID
- *
- * Set Path Group ID
- *
- */
- int
- s390_SetPGID (int irq, __u8 lpm)
- {
- 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);
- }
- if (ioinfo[irq]->ui.flags.unfriendly) {
- /* don't even try it */
- return -EUSERS;
- }
- sprintf (dbf_txt, "SPID%x", irq);
- CIO_TRACE_EVENT (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;
- }
- if (irq_ret) {
- return irq_ret;
- }
- 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));
- }
- 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 (&ioinfo[irq]->pgid);
- spid_ccw[1].count = sizeof (pgid_t);
- spid_ccw[1].flags = CCW_FLAG_SLI;
- ioinfo[irq]->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
- | DOIO_TIMEOUT);
- 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
- CIO_MSG_EVENT(2,
- "SPID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.
- dev, irq, retry);
- retry--;
- irq_ret = -EIO;
- }
- 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 (&ioinfo[irq]->pgid);
- spid_ccw[0].count =
- sizeof (pgid_t);
- spid_ccw[0].flags =
- CCW_FLAG_SLI;
- ioinfo[irq]->pgid.inf.fc =
- SPID_FUNC_SINGLE_PATH
- | SPID_FUNC_ESTABLISH;
- mpath = 0;
- retry--;
- irq_ret = -EIO;
- } else {
- irq_ret = -EOPNOTSUPP;
- retry = 0;
- }
- } 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
- CIO_MSG_EVENT(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;
- }
- } 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, "
- "lpm %02X, "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.
- dev, irq,
- lpm);
- CIO_MSG_EVENT(2,
- "SPID - Device %04X "
- "on Subchannel %04X, "
- "lpm %02X, "
- "became 'not operational'n",
- ioinfo[irq]->schib.
- pmcw.dev, irq,
- lpm);
- }
- retry = 0;
- ioinfo[irq]->opm &= ~lpm;
- irq_ret = -EAGAIN;
- }
- } else if (irq_ret == -ETIMEDOUT) {
- /*
- * SetPGID timed out, so we cancel it before
- * we retry
- */
- int xret;
- xret = cancel_IO(irq);
- if (!xret)
- CIO_MSG_EVENT(2,
- "SetPGID: sch canceled "
- "successfully for irq %xn",
- irq);
- retry--;
- } else if (irq_ret != -ENODEV) {
- retry--;
- irq_ret = -EIO;
- } else {
- retry = 0;
- irq_ret = -ENODEV;
- }
- } while (retry > 0);
- if (init_IRQ_complete) {
- kfree (spid_ccw);
- } else {
- free_bootmem ((unsigned long) spid_ccw, 2 * sizeof (ccw1_t));
- }
- 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);
- 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];
- pgid_t * tmp_pgid;
- 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);
- }
- sprintf (dbf_txt, "SNID%x", irq);
- CIO_TRACE_EVENT (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;
- }
- if (irq_ret) {
- return irq_ret;
- }
- s390irq_spin_lock_irqsave (irq, flags);
- ioinfo[irq]->ui.flags.unfriendly = 0; /* assume it's friendly... */
- if (init_IRQ_complete) {
- snid_ccw = kmalloc (sizeof (ccw1_t), GFP_DMA);
- tmp_pgid = kmalloc (sizeof (pgid_t), GFP_DMA);
- } else {
- snid_ccw = alloc_bootmem_low (sizeof (ccw1_t));
- tmp_pgid = alloc_bootmem_low (sizeof (pgid_t));
- }
- snid_ccw->cmd_code = CCW_CMD_SENSE_PGID;
- snid_ccw->cda = (__u32) virt_to_phys (tmp_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_TIMEOUT
- | 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 | SNS0_INTERVENTION_REQ)) {
- 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
- CIO_MSG_EVENT(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;
- }
- } 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, "
- "lpm %02X, "
- "became 'not operational'n",
- ioinfo[irq]->schib.pmcw.
- dev, irq,
- lpm);
- CIO_MSG_EVENT(2,
- "SNID - Device %04X "
- "on Subchannel %04X, "
- "lpm %02X, "
- "became 'not operational'n",
- ioinfo[irq]->schib.
- pmcw.dev, irq,
- lpm);
- }
- retry = 0;
- irq_ret = -EIO;
- } else {
- retry = 0; /* success ... */
- irq_ret = 0;
- /*
- * Check if device is locked by someone else
- * -- we'll fail other commands if that is
- * the case
- */
- if (pgid->inf.ps.state2 ==
- SNID_STATE2_RESVD_ELSE) {
- printk (KERN_WARNING
- "SNID - Device %04X "
- "on Subchannel %04X "
- "is reserved by "
- "someone elsen",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- CIO_MSG_EVENT(2,
- "SNID - Device %04X "
- "on Subchannel %04X "
- "is reserved by "
- "someone elsen",
- ioinfo[irq]->schib.
- pmcw.dev,
- irq);
-
- ioinfo[irq]->ui.flags.unfriendly = 1;
- } else {
- /*
- * device is friendly to us :)
- */
- ioinfo[irq]->ui.flags.unfriendly = 0;
- }
- memcpy(pgid, tmp_pgid, sizeof(pgid_t));
- }
- } else if (irq_ret == -ETIMEDOUT) {
- #ifdef CONFIG_DEBUG_IO
- printk(KERN_INFO "SNID - Operation timed out "
- "on Device %04X, Subchannel %04X... "
- "cancelling IOn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- #endif /* CONFIG_DEBUG_IO */
- CIO_MSG_EVENT(2,
- "SNID - Operation timed out "
- "on Device %04X, Subchannel %04X... "
- "cancelling IOn",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
- cancel_IO(irq);
- retry--;
- } 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
- CIO_MSG_EVENT(2,
- "SNID - Device %04X "
- "on Subchannel %04X "
- "reports pending status, "
- "retry : %dn",
- ioinfo[irq]->schib.pmcw.
- dev, irq, retry);
- }
- printk (KERN_WARNING "SNID - device %04X,"
- " start_io() reports rc : %d, retrying ...n",
- ioinfo[irq]->schib.pmcw.dev, irq_ret);
- CIO_MSG_EVENT(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;
- }
- } while (retry > 0);
- if (init_IRQ_complete) {
- kfree (snid_ccw);
- kfree (tmp_pgid);
- } else {
- free_bootmem ((unsigned long) snid_ccw, sizeof (ccw1_t));
- free_bootmem ((unsigned long) tmp_pgid, sizeof (pgid_t));
- }
- 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);
- return (irq_ret);
- }
- void
- s390_process_subchannel_source (int irq)
- {
- int dev_oper = 0;
- int dev_no = -1;
- int lock = 0;
- int is_owned = 0;
- /*
- * If the device isn't known yet
- * we can't lock it ...
- */
- if (ioinfo[irq] != INVALID_STORAGE_AREA) {
- s390irq_spin_lock (irq);
- lock = 1;
- if (!ioinfo[irq]->st) {
- 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;
- }
- }
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_DEBUG
- "do_crw_pending : subchannel validation - start ...n");
- #endif
- CIO_CRW_EVENT(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
- CIO_CRW_EVENT(4, "subchannel validation - donen");
- /*
- * After the validate processing
- * the ioinfo control block
- * should be allocated ...
- */
- if (lock) {
- s390irq_spin_unlock (irq);
- }
- 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
- #ifdef CONFIG_ARCH_S390X
- CIO_CRW_EVENT(4, "ioinfo at %08lXn",
- (unsigned long)ioinfo[irq]);
- #else /* CONFIG_ARCH_S390X */
- CIO_CRW_EVENT(4, "ioinfo at %08Xn",
- (unsigned)ioinfo[irq]);
- #endif /* CONFIG_ARCH_S390X */
- if (ioinfo[irq]->st)
- return;
- 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);
- }
- } else {
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_DEBUG
- "do_crw_pending : device "
- "recognition - start ...n");
- #endif
- CIO_CRW_EVENT( 4,
- "device recognition - startn");
- s390_device_recognition_irq (irq);
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_DEBUG
- "do_crw_pending : device "
- "recognition - donen");
- #endif
- CIO_CRW_EVENT( 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);
- }
- #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
- }
- }
- #ifdef CONFIG_PROC_FS
- /* get rid of dead procfs entries */
- if (cio_proc_devinfo)
- cio_procfs_device_purge ();
- #endif
- }
- }
- #ifdef CONFIG_CHSC
- static int
- chsc_get_sch_desc_irq(int irq)
- {
- int j = 0;
- int ccode;
- spin_lock(&chsc_lock_ssd);
-
- if (!chsc_area_ssd)
- chsc_area_ssd = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
-
- if (!chsc_area_ssd) {
- printk( KERN_CRIT "No memory to determine sch descriptions...n");
- spin_unlock(&chsc_lock_ssd);
- return -ENOMEM;
- }
-
- memset(chsc_area_ssd, 0, sizeof(chsc_area_t));
-
- chsc_area_ssd->request_block.command_code1=0x0010;
- chsc_area_ssd->request_block.command_code2=0x0004;
- chsc_area_ssd->request_block.request_block_data.ssd_req.f_sch=irq;
- chsc_area_ssd->request_block.request_block_data.ssd_req.l_sch=irq;
-
- ccode = chsc(chsc_area_ssd);
- #ifdef CONFIG_DEBUG_CHSC
- if (ccode)
- printk( KERN_DEBUG "chsc returned with ccode = %dn",ccode);
- #endif /* CONFIG_DEBUG_CHSC */
- if (!ccode) {
- if (chsc_area_ssd->response_block.response_code == 0x0003) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING "Error in chsc request block!n");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2, "Error in chsc request block!n");
- spin_unlock(&chsc_lock_ssd);
- return -EINVAL;
-
- } else if (chsc_area_ssd->response_block.response_code == 0x0004) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING "Model does not provide ssdn");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2, "Model does not provide ssdn");
- spin_unlock(&chsc_lock_ssd);
- return -EOPNOTSUPP;
- } else if (chsc_area_ssd->response_block.response_code == 0x0002) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING "chsc: Invalid command!n");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2,
- "chsc: Invalid command!n");
- return -EINVAL;
- } else if (chsc_area_ssd->response_block.response_code == 0x0001) {
- /* everything ok */
-
- switch (chsc_area_ssd->response_block.response_block_data.ssd_res.st) {
-
- case 0: /* I/O subchannel */
-
- /*
- * All fields have meaning
- */
- #ifdef CONFIG_DEBUG_CHSC
- if (cio_show_msg)
- printk( KERN_DEBUG
- "ssd: sch %x is I/O subchanneln",
- irq);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 6,
- "ssd: sch %x is I/O subchanneln",
- irq);
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- /* FIXME: we should do device rec. here... */
- break;
- ioinfo[irq]->ssd_info.valid = 1;
- ioinfo[irq]->ssd_info.type = 0;
- for (j=0;j<8;j++) {
- if ((0x80 >> j) &
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.path_mask &
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.fla_valid_mask) {
- if (chsc_area_ssd->response_block.
- response_block_data.ssd_res.chpid[j])
- if (!test_and_set_bit
- (chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids_known))
- if (test_bit
- (chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids_logical))
- set_bit(chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids);
- ioinfo[irq]->ssd_info.chpid[j] =
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.chpid[j];
- ioinfo[irq]->ssd_info.fla[j] =
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.fla[j];
- }
- }
- break;
-
- case 1: /* CHSC subchannel */
-
- /*
- * Only sch_val, st and sch have meaning
- */
- #ifdef CONFIG_DEBUG_CHSC
- if (cio_show_msg)
- printk( KERN_DEBUG
- "ssd: sch %x is chsc subchanneln",
- irq);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 6,
- "ssd: sch %x is chsc subchanneln",
- irq);
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- /* FIXME: we should do device rec. here... */
- break;
- ioinfo[irq]->ssd_info.valid = 1;
- ioinfo[irq]->ssd_info.type = 1;
- break;
-
- case 2: /* Message subchannel */
-
- /*
- * All fields except unit_addr have meaning
- */
- #ifdef CONFIG_DEBUG_CHSC
- if (cio_show_msg)
- printk( KERN_DEBUG
- "ssd: sch %x is message subchanneln",
- irq);
- #endif
- CIO_CRW_EVENT( 6,
- "ssd: sch %x is message subchanneln",
- irq);
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- /* FIXME: we should do device rec. here... */
- break;
- ioinfo[irq]->ssd_info.valid = 1;
- ioinfo[irq]->ssd_info.type = 2;
- for (j=0;j<8;j++) {
- if ((0x80 >> j) &
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.path_mask &
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.fla_valid_mask) {
- if (chsc_area_ssd->response_block.
- response_block_data.ssd_res.chpid[j])
- if (!test_and_set_bit
- (chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids_known))
- if (test_bit
- (chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids_logical))
- set_bit(chsc_area_ssd->response_block.
- response_block_data.
- ssd_res.chpid[j],
- &chpids);
- ioinfo[irq]->ssd_info.chpid[j] =
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.chpid[j];
- ioinfo[irq]->ssd_info.fla[j] =
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.fla[j];
- }
- }
- break;
-
- case 3: /* ADM subchannel */
-
- /*
- * Only sch_val, st and sch have meaning
- */
- #ifdef CONFIG_DEBUG_CHSC
- if (cio_show_msg)
- printk( KERN_DEBUG
- "ssd: sch %x is ADM subchanneln",
- irq);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 6,
- "ssd: sch %x is ADM subchanneln",
- irq);
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- /* FIXME: we should do device rec. here... */
- break;
- ioinfo[irq]->ssd_info.valid = 1;
- ioinfo[irq]->ssd_info.type = 3;
- break;
-
- default: /* uhm, that looks strange... */
- #ifdef CONFIG_DEBUG_CHSC
- if (cio_show_msg)
- printk( KERN_DEBUG
- "Strange subchannel type %d for sch %xn",
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.st,
- irq);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 0,
- "Strange subchannel type %d for "
- "sch %xn",
- chsc_area_ssd->response_block.
- response_block_data.ssd_res.st,
- irq);
- }
- spin_unlock(&chsc_lock_ssd);
- return 0;
- }
- } else {
- spin_unlock(&chsc_lock_ssd);
- if (ccode == 3)
- return -ENODEV;
- return -EBUSY;
- }
- return -EIO;
- }
- static int
- chsc_get_sch_descriptions( void )
- {
- int irq = 0;
- int err = 0;
- CIO_TRACE_EVENT( 4, "gsdesc");
- /*
- * get information about chpids and link addresses
- * by executing the chsc command 'store subchannel description'
- */
- if (init_IRQ_complete) {
-
- for (irq=0; irq<=highest_subchannel; irq++) {
- /*
- * retrieve information for each sch
- */
- err = chsc_get_sch_desc_irq(irq);
- if (err) {
- if (!cio_chsc_err_msg) {
- printk( KERN_ERR
- "chsc_get_sch_descriptions:"
- " Error %d while doing chsc; "
- "processing "
- "some machine checks may "
- "not workn",
- err);
- cio_chsc_err_msg=1;
- }
- return err;
- }
- }
- cio_chsc_desc_avail = 1;
- return 0;
- } else {
- /* Paranoia... */
-
- printk( KERN_ERR
- "Error: chsc_get_sch_descriptions called before "
- "initialization completen");
- return -EINVAL;
- }
-
- }
- __initcall(chsc_get_sch_descriptions);
- void
- s390_do_chpid_processing( __u8 chpid)
- {
- int irq;
- int j;
- int mask;
- char dbf_txt[15];
- int ccode;
- int was_oper;
- int chp = 0;
- int mask2;
- int ret = 0;
- sprintf(dbf_txt, "chpr%x", chpid);
- CIO_TRACE_EVENT( 2, dbf_txt);
- /*
- * TODO: the chpid may be not the chpid with the link incident,
- * but the chpid the report came in through. How to handle???
- */
- clear_bit(chpid, &chpids);
- if (!test_and_clear_bit(chpid, &chpids_known))
- return; /* we didn't know the chpid anyway */
- for (irq=0;irq<=highest_subchannel;irq++) {
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- continue; /* we don't know the device anyway */
- if (ioinfo[irq]->st)
- continue; /* non-io subchannel */
- for (j=0; j<8;j++) {
- if (ioinfo[irq]->schib.pmcw.chpid[j] == chpid) {
-
- /*
- * Send nops down each path to find out
- * which path is gone (ssch will yield cc=3
- * and the path will be switched off in the opm)
- */
-
- /*
- * Note: irq spinlock is grabbed several times
- * in here
- */
- for (chp=0;chp<=7;chp++) {
- mask2 = 0x80 >> chp;
- if (mask2 & ioinfo[irq]->opm)
- ret = s390_send_nop (irq, mask2);
- }
-
- s390irq_spin_lock(irq);
- /*
- * FIXME: is this neccessary?
- */
- ccode = stsch(irq, &ioinfo[irq]->schib);
- if (ccode) {
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_WARNING
- "do_crw_pending: device on "
- "sch %x is not operationaln",
- irq);
- #endif /* CONFIG_DEBUG_CRW */
- CIO_CRW_EVENT( 2,
- "device on sch %x is "
- "not operationaln",
- irq);
- ioinfo[irq]->ui.flags.oper = 0;
- break;
- }
- ioinfo[irq]->opm = ioinfo[irq]->schib.pmcw.pim &
- ioinfo[irq]->schib.pmcw.pam &
- ioinfo[irq]->schib.pmcw.pom;
- if (ioinfo[irq]->opm) {
- for (chp=0;chp<=7;chp++) {
- mask2 = 0x80 >> chp;
- if (ioinfo[irq]->opm & mask2) {
- if (!test_bit
- (ioinfo[irq]->
- schib.pmcw.chpid[chp],
- &chpids_logical)) {
- /* disable using this path */
- ioinfo[irq]->opm
- &= ~mask2;
- }
- }
- }
- }
- if (!ioinfo[irq]->opm) {
- /*
- * sh*t, our last path has gone...
- * Set the device status to not operational
- * and eventually notify the device driver
- */
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_WARNING
- "do_crw_pending: Last path gone for "
- "device %x, sch %xn",
- ioinfo[irq]->devno, irq);
- #endif /* CONFIG_DEBUG_CRW */
- CIO_CRW_EVENT( 2,
- "Last path gone for "
- "device %x, sch %xn",
- ioinfo[irq]->devno,
- irq);
-
- was_oper = ioinfo[irq]->ui.flags.oper;
-
- ioinfo[irq]->ui.flags.oper = 0;
-
- if (was_oper && ioinfo[irq]->ui.flags.ready) {
-
- not_oper_handler_func_t nopfunc =
- ioinfo[irq]->nopfunc;
- #ifdef CONFIG_PROC_FS
- if (cio_proc_devinfo)
- cio_procfs_device_remove
- (ioinfo[irq]->devno);
- #endif /* CONFIG_PROC_FS */
- free_irq(irq,
- ioinfo[irq]->irq_desc.dev_id);
- if (nopfunc)
- nopfunc(irq,
- DEVSTAT_DEVICE_GONE);
- }
-
- } else if (ioinfo[irq]->ui.flags.ready) {
- /*
- * Re-do path verification for the chpid in question
- * FIXME: is this neccessary?
- */
- mask = 0x80 >> j;
- if (!s390_DevicePathVerification(irq,mask)) {
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_DEBUG
- "DevicePathVerification "
- "successful for"
- " Subchannel %x, "
- "chpid %xn",
- irq, chpid);
- #endif /* CONFIG_DEBUG_CRW */
- CIO_CRW_EVENT( 2,
- "DevicePathVerification "
- "successful for"
- " Subchannel %x, "
- "chpid %xn",
- irq, chpid);
- }
- }
-
- j=8;
- s390irq_spin_unlock(irq);
- }
-
- }
- }
- }
- void
- s390_do_res_acc_processing( __u8 chpid, __u16 fla, int info)
- {
- char dbf_txt[15];
- int irq = 0;
- int ccode;
- __u32 fla_mask = 0xffff;
- int chp;
- int mask, mask2;
- int ret;
- sprintf(dbf_txt, "accp%x", chpid);
- CIO_TRACE_EVENT( 2, dbf_txt);
- if (info != CHSC_SEI_ACC_CHPID) {
- sprintf(dbf_txt, "fla%x", fla);
- CIO_TRACE_EVENT( 2, dbf_txt);
- }
- sprintf(dbf_txt, "info:%d", info);
- CIO_TRACE_EVENT( 2, dbf_txt);
-
- /*
- * I/O resources may have become accessible.
- * Scan through all subchannels that may be concerned and
- * do a validation on those.
- * The more information we have (info), the less scanning
- * will we have to do.
- */
- if (!cio_chsc_desc_avail)
- chsc_get_sch_descriptions();
- if (!cio_chsc_desc_avail) {
- /*
- * Something went wrong...
- */
- #ifdef CONFIG_DEBUG_CRW
- printk( KERN_WARNING
- "Error: Could not retrieve subchannel descriptions, "
- "will not process css machine check...n");
- #endif /* CONFIG_DEBUG_CRW */
- CIO_CRW_EVENT( 0,
- "Error: Could not retrieve subchannel descriptions, "
- "will not process css machine check...n");
- return;
- }
- if (!test_bit(chpid, &chpids_logical))
- return; /* no need to do the rest */
- switch (info) {
- case CHSC_SEI_ACC_CHPID: /*
- * worst case, we only know about the chpid
- * the devices are attached to
- */
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG "Looking at chpid %x...n", chpid);
- #endif /* CONFIG_DEBUG_CHSC */
-
- for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
-
- if((ioinfo[irq] != INVALID_STORAGE_AREA)
- && (!ioinfo[irq]->st)) {
-
- /*
- * Send nops down each path to find out
- * which path is there
- */
-
- for (chp=0;chp<=7;chp++) {
- mask = 0x80 >> chp;
- /*
- * check if chpid is in information
- * updated by ssd
- */
- if ((ioinfo[irq]->ssd_info.valid) &&
- (ioinfo[irq]->ssd_info.chpid[chp]
- == chpid))
- ret = s390_send_nop (irq, mask);
- }
- ccode = stsch(irq, &ioinfo[irq]->schib);
- if (!ccode) {
- ioinfo[irq]->opm =
- ioinfo[irq]->schib.pmcw.pim &
- ioinfo[irq]->schib.pmcw.pam &
- ioinfo[irq]->schib.pmcw.pom;
- if (ioinfo[irq]->opm) {
- for (chp=0;chp<=7;chp++) {
- mask = 0x80 >> chp;
- if (ioinfo[irq]->opm
- & mask) {
- if (!test_bit
- (ioinfo[irq]->
- schib.pmcw.chpid[chp],
- &chpids_logical)) {
- /* disable using this path */
- ioinfo[irq]->opm
- &= ~mask;
- }
- }
- }
- }
- if ((ioinfo[irq]->ui.flags.ready)
- && (chpid & ioinfo[irq]->opm))
- s390_DevicePathVerification(irq, chpid);
- } else {
- ioinfo[irq]->ui.flags.oper = 0;
- }
- } else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
- /*
- * We don't know the device yet, but since a path
- * may be available now to the device we'll have
- * to do recognition again.
- * Since we don't have any idea about which chpid
- * that beast may be on we'll have to do a stsch
- * on all devices, grr...
- */
- int valret = 0;
-
- valret = s390_validate_subchannel(irq,0);
- if (valret == -ENXIO) {
- /* We're through */
- return;
- }
- if (irq > highest_subchannel)
- highest_subchannel = irq;
- if (valret == 0)
- s390_device_recognition_irq(irq);
- }
- }
- break;
-
- case CHSC_SEI_ACC_LINKADDR: /*
- * better, we know the link determined by
- * the link address and the chpid
- */
- fla_mask = 0xff00;
- /* fallthrough */
- case CHSC_SEI_ACC_FULLLINKADDR: /*
- * best case, we know the CU image
- * by chpid and full link address
- */
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG "Looking at chpid %x, link addr %x...n",
- chpid, fla);
- #endif /* CONFIG_DEBUG_CHSC */
-
- for (irq=0; irq<=__MAX_SUBCHANNELS; irq++) {
-
- /*
- * Walk through all subchannels and
- * look if our chpid and our (masked) link
- * address are in somewhere
- * Do a stsch for the found subchannels and
- * perform path grouping
- */
- if ((ioinfo[irq] != INVALID_STORAGE_AREA)
- && (!ioinfo[irq]->st)) {
- int j;
-
- /* Update our ssd_info */
- if (chsc_get_sch_desc_irq(irq))
- break;
-
- for (j=0;j<8;j++) {
- if ((ioinfo[irq]->ssd_info.chpid[j] == chpid) &&
- ((ioinfo[irq]->ssd_info.fla[j]&fla_mask) == fla)) {
- mask2 = 0x80 >> j;
- ret = s390_send_nop (irq, mask2);
-
- ccode = stsch(irq,&ioinfo[irq]->schib);
- if (!ccode) {
- ioinfo[irq]->opm =
- ioinfo[irq]->schib.pmcw.pim &
- ioinfo[irq]->schib.pmcw.pam &
- ioinfo[irq]->schib.pmcw.pom;
- if (ioinfo[irq]->opm) {
- for (chp=0;chp<=7;chp++) {
- mask = 0x80 >> chp;
- if (ioinfo[irq]->opm
- & mask) {
- if (!test_bit
- (ioinfo[irq]->
- schib.pmcw.chpid[chp],
- &chpids_logical)) {
- /* disable using this path */
- ioinfo[irq]->opm
- &= ~mask;
- }
- }
- }
- }
- if (ioinfo[irq]->ui.flags.ready)
- s390_DevicePathVerification(irq, chpid);
- }
- break;
- }
- }
- } else if (ioinfo[irq] == INVALID_STORAGE_AREA) {
- /* The full program again (see above), grr... */
- int valret = 0;
-
- valret = s390_validate_subchannel(irq,0);
- if (valret == -ENXIO) {
- /* We're done */
- return;
- }
- if (irq > highest_subchannel)
- highest_subchannel = irq;
- if (valret == 0)
- s390_device_recognition_irq(irq);
-
- }
- }
-
- break;
- default: BUG();
- }
- }
- void
- s390_process_css( void )
- {
- int ccode;
- CIO_TRACE_EVENT( 2, "prcss");
- spin_lock(&chsc_lock_sei);
- if (!chsc_area_sei) {
- if (init_IRQ_complete)
- chsc_area_sei = kmalloc(sizeof(chsc_area_t),GFP_KERNEL);
- else
- chsc_area_sei = alloc_bootmem(sizeof(chsc_area_t));
- }
-
- if (!chsc_area_sei) {
- printk( KERN_CRIT
- "No memory to store event information...n");
- spin_unlock(&chsc_lock_sei);
- return;
- }
- /*
- * build the chsc request block for store event information
- * and do the call
- */
- memset(chsc_area_sei,0,sizeof(chsc_area_t));
- chsc_area_sei->request_block.command_code1=0x0010;
- chsc_area_sei->request_block.command_code2=0x000E;
- ccode = chsc(chsc_area_sei);
- if (!ccode) {
- /* for debug purposes, check for problems */
- if (chsc_area_sei->response_block.response_code == 0x0003) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING
- "s390_process_css: error in chsc request block!n");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2,
- "s390_process_css: "
- "error in chsc request block!n");
- } else if (chsc_area_sei->response_block.response_code == 0x0005) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING
- "s390_process_css: no event information storedn");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2,
- "s390_process_css: "
- "no event information storedn");
- } else if (chsc_area_sei->response_block.response_code == 0x0002) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_WARNING
- "s390_process_css: invalid command!n");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2,
- "s390_process_css: "
- "invalid command!n");
- } else if (chsc_area_sei->response_block.response_code == 0x0001) {
- /* everything ok */
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "s390_process_css: "
- "event information successfully storedn");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 4,
- "s390_process_css: "
- "event information successfully storedn");
- if (chsc_area_sei->response_block.
- response_block_data.sei_res.rs != 4) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_ERR
- "s390_process_css: "
- "reporting source (%04X) isn't a chpid!"
- "Aborting processing of machine check...n",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 2,
- "s390_process_css: "
- "reporting source (%04X) isn't a chpid!"
- "Aborting processing of machine check...n",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
- return;
- }
-
- /* which kind of information was stored? */
- switch (chsc_area_sei->response_block.
- response_block_data.sei_res.cc) {
- case 1: /* link incident*/
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "s390_process_css: "
- "channel subsystem reports link incident,"
- " source is chpid %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 4,
- "s390_process_css: "
- "channel subsystem reports "
- "link incident, "
- "source is chpid %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
- s390_do_chpid_processing(chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
-
- break;
- case 2: /* i/o resource accessibiliy */
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "s390_process_css: channel subsystem "
- "reports some I/O devices "
- "may have become accessablen");
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 4,
- "s390_process_css: "
- "channel subsystem reports "
- "some I/O devices "
- "may have become accessablen");
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "Data received after sei: n");
- printk( KERN_DEBUG
- "Validity flags: %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.vf);
- #endif /* CONFIG_DEBUG_CHSC */
- if ((chsc_area_sei->response_block.
- response_block_data.sei_res.vf&0x80)
- == 0) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG "chpid: %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid);
- #endif /* CONFIG_DEBUG_CHSC */
- s390_do_res_acc_processing
- (chsc_area_sei->response_block.
- response_block_data.sei_res.rsid,
- 0,
- CHSC_SEI_ACC_CHPID);
- } else if ((chsc_area_sei->response_block.
- response_block_data.sei_res.vf&0xc0)
- == 0x80) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "chpid: %x link addr: %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid,
- chsc_area_sei->response_block.
- response_block_data.sei_res.fla);
- #endif /* CONFIG_DEBUG_CHSC */
- s390_do_res_acc_processing
- (chsc_area_sei->response_block.
- response_block_data.sei_res.rsid,
- chsc_area_sei->response_block.
- response_block_data.sei_res.fla,
- CHSC_SEI_ACC_LINKADDR);
- } else if ((chsc_area_sei->response_block.
- response_block_data.sei_res.vf & 0xc0)
- == 0xc0) {
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "chpid: %x "
- "full link addr: %xn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.rsid,
- chsc_area_sei->response_block.
- response_block_data.sei_res.fla);
- #endif /* CONFIG_DEBUG_CHSC */
- s390_do_res_acc_processing
- (chsc_area_sei->response_block.
- response_block_data.sei_res.rsid,
- chsc_area_sei->response_block.
- response_block_data.sei_res.fla,
- CHSC_SEI_ACC_FULLLINKADDR);
- }
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG "n");
- #endif /* CONFIG_DEBUG_CHSC */
- break;
- default: /* other stuff */
- #ifdef CONFIG_DEBUG_CHSC
- printk( KERN_DEBUG
- "s390_process_css: event %dn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.cc);
- #endif /* CONFIG_DEBUG_CHSC */
- CIO_CRW_EVENT( 4,
- "s390_process_css: event %dn",
- chsc_area_sei->response_block.
- response_block_data.sei_res.cc);
- break;
- }
- }
- }
- spin_unlock(&chsc_lock_sei);
- }
- #endif
- /*
- * 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;
-
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_DEBUG "do_crw_pending : starting ...n");
- #endif
- CIO_CRW_EVENT( 2, "do_crw_pending: startingn");
- while (pcrwe != NULL) {
- 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
- CIO_CRW_EVENT(2, "source is subchannel %04Xn",
- irq);
- s390_process_subchannel_source (irq);
- break;
- case CRW_RSC_MONITOR:
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_NOTICE "do_crw_pending : source is "
- "monitoring facilityn");
- #endif
- CIO_CRW_EVENT(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
- CIO_CRW_EVENT(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
- CIO_CRW_EVENT(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
- CIO_CRW_EVENT(2, "source is channel subsystemn");
- #ifdef CONFIG_CHSC
- s390_process_css();
- #endif
- break;
- default:
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_NOTICE
- "do_crw_pending : unknown sourcen");
- #endif
- CIO_CRW_EVENT( 2, "unknown sourcen");
- break;
- }
- pcrwe = pcrwe->crwe_next;
- }
- #ifdef CONFIG_DEBUG_CRW
- printk (KERN_DEBUG "do_crw_pending : donen");
- #endif
- CIO_CRW_EVENT(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);
- debug_set_level (cio_debug_msg_id, 6);
- } 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);
- debug_set_level (cio_debug_trace_id, 6);
- } 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);
- debug_set_level (cio_debug_crw_id, 6);
- } else {
- ret = -1;
- }
- if (ret)
- return ret;
- cio_debug_initialized = 1;
- return 0;
- }
- __initcall (cio_debug_init);
- #ifdef CONFIG_PROC_FS
- #ifdef CONFIG_CHSC
- /*
- * Function: cio_parse_chpids_proc_parameters
- * parse the stuff piped to /proc/chpids
- */
- void
- cio_parse_chpids_proc_parameters(char* buf)
- {
- int i;
- int cp;
- int ret;
- if (strstr(buf, "on ")) {
- for (i=0; i<3; i++) {
- buf++;
- }
- cp = blacklist_strtoul(buf, &buf);
- chsc_get_sch_descriptions();
- if (!cio_chsc_desc_avail) {
- printk(KERN_ERR "Could not get chpid status, "
- "vary on/off not availablen");
- return;
- }
-
- if (!test_bit(cp, &chpids)) {
- ret = s390_vary_chpid(cp, 1);
- if (ret == -EINVAL) {
- #ifdef CONFIG_DEBUG_CHSC
- printk(KERN_ERR "/proc/chpids: "
- "Invalid chpid specifiedn");
- #else /* CONFIG_DEBUG_CHSC */
- printk(KERN_DEBUG "/proc/chpids: "
- "Invalid chpid specifiedn");
- #endif /* CONFIG_DEBUG_CHSC */
- } else if (ret == 0) {
- printk(KERN_INFO "/proc/chpids: "
- "Varied chpid %x logically onlinen",
- cp);
- }
- } else {
- printk(KERN_ERR "/proc/chpids: chpid %x is "
- "already onlinen",
- cp);
- }
- } else if (strstr(buf, "off ")) {
- for (i=0; i<4; i++) {
- buf++;
- }
- cp = blacklist_strtoul(buf, &buf);
- chsc_get_sch_descriptions();
- if (!cio_chsc_desc_avail) {
- printk(KERN_ERR "Could not get chpid status, "
- "vary on/off not availablen");
- return;
- }
-
- if (test_bit(cp, &chpids)) {
- ret = s390_vary_chpid(cp, 0);
- if (ret == -EINVAL) {
- #ifdef CONFIG_DEBUG_CHSC
- printk(KERN_ERR "/proc/chpids: "
- "Invalid chpid specifiedn");
- #else /* CONFIG_DEBUG_CHSC */
- printk(KERN_DEBUG "/proc/chpids: "
- "Invalid chpid specifiedn");
- #endif /* CONFIG_DEBUG_CHSC */
- } else if (ret == 0) {
- printk(KERN_INFO "/proc/chpids: "
- "Varied chpid %x logically offlinen",
- cp);
- }
- } else {
- printk(KERN_ERR "/proc/chpids: "
- "chpid %x is already offlinen",
- cp);
- }
- } else {
- printk(KERN_ERR "/proc/chpids: Parse error; "
- "try using '{on,off} <chpid>'n");
- }
- }
- /*
- * Function: s390_vary_chpid
- * Varies the specified chpid online or offline
- */
- int
- s390_vary_chpid( __u8 chpid, int on)
- {
- char dbf_text[15];
- int irq;
- if ((chpid <=0) || (chpid >= NR_CHPIDS))
- return -EINVAL;
- sprintf(dbf_text, on?"varyon%x":"varyoff%x", chpid);
- CIO_TRACE_EVENT( 2, dbf_text);
- if (!test_bit(chpid, &chpids_known)) {
- printk(KERN_ERR "Can't vary unknown chpid %02Xn", chpid);
- return -EINVAL;
- }
- if (on && test_bit(chpid, &chpids_logical)) {
- printk(KERN_ERR "chpid %02X already logically onlinen",
- chpid);
- return -EINVAL;
- }
- if (!on && !test_bit(chpid, &chpids_logical)) {
- printk(KERN_ERR "chpid %02X already logically offlinen",
- chpid);
- return -EINVAL;
- }
- if (on) {
- set_bit(chpid, &chpids_logical);
- set_bit(chpid, &chpids);
- } else {
- clear_bit(chpid, &chpids_logical);
- clear_bit(chpid, &chpids);
- }
- /*
- * Redo PathVerification on the devices the chpid connects to
- */
-
- for (irq=0;irq<=highest_subchannel;irq++) {
- /*
- * We don't need to adjust the opm, as this will be done in
- * DevicePathVerification...
- */
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- continue;
- if (ioinfo[irq]->st)
- continue;
- if (ioinfo[irq]->ssd_info.valid) {
- if ((ioinfo[irq]->ssd_info.chpid[0] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[1] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[2] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[3] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[4] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[5] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[6] == chpid) ||
- (ioinfo[irq]->ssd_info.chpid[7] == chpid)) {
- #ifdef CONFIG_DEBUG_CHSC
- printk(KERN_DEBUG "Calling "
- "DevicePathVerification for irq %dn",
- irq);
- #endif /* CONFIG_DEBUG_CHSC */
- s390_DevicePathVerification(irq, 0);
- }
- }
- }
- return 0;
- }
- #endif /* CONFIG_CHSC */
- /*
- * 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 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]->st )|| !(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 ",
- ioinfo[i]->schib.pmcw.pim,
- ioinfo[i]->schib.pmcw.pam,
- ioinfo[i]->schib.pmcw.pom);
- 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
-
- if(user_len > 65536)
- user_len = 65536;
-
- buffer = vmalloc (user_len + 1);
-
- if (buffer == NULL)
- return -ENOMEM;
- if (copy_from_user (buffer, user_buf, user_len)) {
- vfree (buffer);
- return -EFAULT;
- }
- buffer[user_len] = ' ';
- #ifdef CONFIG_DEBUG_IO
- printk (KERN_DEBUG "/proc/cio_ignore: '%s'n", buffer);
- #endif /* CONFIG_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);
- vfree (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);
- #ifdef CONFIG_CHSC
- /*
- * /proc/chpids to display available chpids
- * vary chpids on/off by piping to it
- */
- static struct proc_dir_entry *cio_chpids_proc_entry;
- static int
- cio_chpids_proc_open(struct inode *inode, struct file *file)
- {
- int rc = 0;
- int size = 1;
- int len = 0;
- tempinfo_t *info;
- int i;
- if (!cio_chsc_desc_avail) {
- /*
- * We have not yet retrieved the link addresses,
- * so we do it now.
- */
- chsc_get_sch_descriptions();
- }
- 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_CHPIDS * 16;
- info->data = (char *) vmalloc(size);
- if ( size && info->data == NULL) {
- printk( KERN_WARNING "No memory available for datan");
- vfree (info);
- rc = -ENOMEM;
- } else {
- /* update our stuff */
- chsc_get_sch_descriptions();
- if (!cio_chsc_desc_avail) {
- len += sprintf(info->data+len, "no info availablen");
- } else {
- for (i=0;i<NR_CHPIDS;i++) {
- if ((test_bit(i, &chpids)) &&
- test_bit(i, &chpids_logical))
- len += sprintf(info->data+len,
- "%02X onlinen",
- i);
- else if (test_bit(i, &chpids_known))
- len += sprintf(info->data+len,
- "%02X logically offlinen",
- i);
- }
- }
- info->len = len;
- }
- }
- return rc;
- }
- static int
- cio_chpids_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_chpids_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_chpids_proc_write (struct file *file, const char *user_buf,
- size_t user_len, loff_t * offset)
- {
- char *buffer;
-
- if(user_len > 65536)
- user_len = 65536;
-
- buffer = vmalloc (user_len + 1);
- 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("/proc/chpids: '%s'n", buffer);
- #endif /* CIO_DEBUG_IO */
- CIO_MSG_EVENT( 2, "/proc/chpids: '%s'n", buffer);
- cio_parse_chpids_proc_parameters(buffer);
- vfree (buffer);
- return user_len;
- }
- static struct file_operations cio_chpids_proc_file_ops =
- {
- read:cio_chpids_proc_read,
- open:cio_chpids_proc_open,
- write:cio_chpids_proc_write,
- release:cio_chpids_proc_close,
- };
- static int
- cio_chpids_proc_init(void)
- {
- cio_chpids_proc_entry = create_proc_entry("chpids", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
- cio_chpids_proc_entry->proc_fops = &cio_chpids_proc_file_ops;
-
- return 1;
- }
- __initcall(cio_chpids_proc_init);
- #endif
- /* 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;
- if (ioinfo[irq]->st)
- return NULL;
- return &ioinfo[irq]->schib;
- }
- int
- s390_set_private_data(int irq, void *data)
- {
- SANITY_CHECK(irq);
-
- ioinfo[irq]->private_data = data;
-
- return 0;
- }
- void *
- s390_get_private_data(int irq)
- {
- if ((irq > highest_subchannel) || (irq < 0))
- return NULL;
- if (ioinfo[irq] == INVALID_STORAGE_AREA)
- return NULL;
- if (ioinfo[irq]->st)
- return NULL;
- return ioinfo[irq]->private_data;
- }
- 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);
- EXPORT_SYMBOL (s390_set_private_data);
- EXPORT_SYMBOL (s390_get_private_data);
- EXPORT_SYMBOL (s390_trigger_resense);