int cio_cancel (struct subchannel *sch) { int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT(2, "cancelIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: if (cio_update_schib(sch)) return -ENODEV; return 0; case 1: return -EBUSY; case 2: return -EINVAL; default: return -ENODEV; } }
int cio_disable_subchannel(struct subchannel *sch) { int retry; int ret; CIO_TRACE_EVENT(2, "dissch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return 0; if (cio_update_schib(sch)) return -ENODEV; sch->config.ena = 0; for (retry = 0; retry < 3; retry++) { ret = cio_commit_config(sch); if (ret == -EBUSY) { struct irb irb; if (tsch(sch->schid, &irb) != 0) break; } else break; } CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; }
int cio_halt(struct subchannel *sch) { int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT(2, "haltIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = hsch (sch->schid); CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND; return 0; case 1: case 2: return -EBUSY; default: return -ENODEV; } }
/* * resume suspended I/O operation */ int cio_resume (struct subchannel *sch) { char dbf_txt[15]; int ccode; CIO_TRACE_EVENT (4, "resIO"); CIO_TRACE_EVENT (4, sch->dev.bus_id); ccode = rsch (sch->irq); sprintf (dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT (4, dbf_txt); switch (ccode) { case 0: sch->schib.scsw.actl |= SCSW_ACTL_RESUME_PEND; return 0; case 1: return -EBUSY; case 2: return -EINVAL; default: /* * useless to wait for request completion * as device is no longer operational ! */ return -ENODEV; } }
/** * cio_enable_subchannel - enable a subchannel. * @sch: subchannel to be enabled * @intparm: interruption parameter to set */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { int ret; CIO_TRACE_EVENT(2, "ensch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return -EINVAL; if (cio_update_schib(sch)) return -ENODEV; sch->config.ena = 1; sch->config.isc = sch->isc; sch->config.intparm = intparm; ret = cio_commit_config(sch); if (ret == -EIO) { /* * Got a program check in msch. Try without * the concurrent sense bit the next time. */ sch->config.csense = 0; ret = cio_commit_config(sch); } CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; }
/* * halt I/O operation */ int cio_halt(struct subchannel *sch) { char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT (2, "haltIO"); CIO_TRACE_EVENT (2, sch->dev.bus_id); /* * Issue "Halt subchannel" and process condition code */ ccode = hsch (sch->irq); sprintf (dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT (2, dbf_txt); switch (ccode) { case 0: sch->schib.scsw.actl |= SCSW_ACTL_HALT_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ return -EBUSY; default: /* device not operational */ return -ENODEV; } }
/* * Clear I/O operation */ int cio_clear(struct subchannel *sch) { int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT(2, "clearIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Clear subchannel" and process condition code */ ccode = csch (sch->schid); CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: sch->schib.scsw.cmd.actl |= SCSW_ACTL_CLEAR_PEND; return 0; default: /* device not operational */ return -ENODEV; } }
/* * Function: cio_cancel * Issues a "Cancel Subchannel" on the specified subchannel * Note: We don't need any fancy intparms and flags here * since xsch is executed synchronously. * Only for common I/O internal use as for now. */ int cio_cancel (struct subchannel *sch) { int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT(2, "cancelIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); ccode = xsch (sch->schid); CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: /* success */ /* Update information in scsw. */ if (cio_update_schib(sch)) return -ENODEV; return 0; case 1: /* status pending */ return -EBUSY; case 2: /* not applicable */ return -EINVAL; default: /* not oper */ return -ENODEV; } }
/* * halt I/O operation */ int cio_halt(struct subchannel *sch) { int ccode; if (!sch) return -ENODEV; CIO_TRACE_EVENT(2, "haltIO"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); /* * Issue "Halt subchannel" and process condition code */ ccode = hsch (sch->schid); CIO_HEX_EVENT(2, &ccode, sizeof(ccode)); switch (ccode) { case 0: sch->schib.scsw.cmd.actl |= SCSW_ACTL_HALT_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ return -EBUSY; default: /* device not operational */ return -ENODEV; } }
/* * resume suspended I/O operation */ int cio_resume (struct subchannel *sch) { int ccode; CIO_TRACE_EVENT(4, "resIO"); CIO_TRACE_EVENT(4, dev_name(&sch->dev)); ccode = rsch (sch->schid); CIO_HEX_EVENT(4, &ccode, sizeof(ccode)); switch (ccode) { case 0: sch->schib.scsw.cmd.actl |= SCSW_ACTL_RESUME_PEND; return 0; case 1: return -EBUSY; case 2: return -EINVAL; default: /* * useless to wait for request completion * as device is no longer operational ! */ return -ENODEV; } }
/* * Function: cio_cancel * Issues a "Cancel Subchannel" on the specified subchannel * Note: We don't need any fancy intparms and flags here * since xsch is executed synchronously. * Only for common I/O internal use as for now. */ int cio_cancel (struct subchannel *sch) { char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; sprintf (dbf_txt, "cancelIO%x", sch->irq); CIO_TRACE_EVENT (2, dbf_txt); ccode = xsch (sch->irq); sprintf (dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT (2, dbf_txt); switch (ccode) { case 0: /* success */ /* Update information in scsw. */ stsch (sch->irq, &sch->schib); return 0; case 1: /* status pending */ return -EBUSY; case 2: /* not applicable */ return -EINVAL; default: /* not oper */ return -ENODEV; } }
/* * Clear I/O operation */ int cio_clear(struct subchannel *sch) { char dbf_txt[15]; int ccode; if (!sch) return -ENODEV; sprintf (dbf_txt, "clearIO%x", sch->irq); CIO_TRACE_EVENT (2, dbf_txt); /* * Issue "Clear subchannel" and process condition code */ ccode = csch (sch->irq); sprintf (dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT (2, dbf_txt); switch (ccode) { case 0: sch->schib.scsw.actl |= SCSW_ACTL_CLEAR_PEND; return 0; default: /* device not operational */ return -ENODEV; } }
int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { int retry; int ret; CIO_TRACE_EVENT(2, "ensch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return -EINVAL; if (cio_update_schib(sch)) return -ENODEV; sch->config.ena = 1; sch->config.isc = sch->isc; sch->config.intparm = intparm; for (retry = 0; retry < 3; retry++) { ret = cio_commit_config(sch); if (ret == -EIO) { sch->config.csense = 0; } else if (ret == -EBUSY) { struct irb irb; if (tsch(sch->schid, &irb) != 0) break; } else break; } CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; }
int cio_start_key (struct subchannel *sch, /* subchannel structure */ struct ccw1 * cpa, /* logical channel prog addr */ __u8 lpm, /* logical path mask */ __u8 key) /* storage key */ { char dbf_txt[15]; int ccode; union orb *orb; CIO_TRACE_EVENT(4, "stIO"); CIO_TRACE_EVENT(4, dev_name(&sch->dev)); orb = &to_io_private(sch)->orb; memset(orb, 0, sizeof(union orb)); /* sch is always under 2G. */ orb->cmd.intparm = (u32)(addr_t)sch; orb->cmd.fmt = 1; orb->cmd.pfch = sch->options.prefetch == 0; orb->cmd.spnd = sch->options.suspend; orb->cmd.ssic = sch->options.suspend && sch->options.inter; orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_64BIT /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ orb->cmd.c64 = 1; orb->cmd.i2k = 0; #endif orb->cmd.key = key >> 4; /* issue "Start Subchannel" */ orb->cmd.cpa = (__u32) __pa(cpa); ccode = ssch(sch->schid, orb); /* process condition code */ sprintf(dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT(4, dbf_txt); switch (ccode) { case 0: /* * initialize device status information */ sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ return -EBUSY; case 3: /* device/path not operational */ return cio_start_handle_notoper(sch, lpm); default: return ccode; } }
int cio_start_key (struct subchannel *sch, /* subchannel structure */ struct ccw1 * cpa, /* logical channel prog addr */ __u8 lpm, /* logical path mask */ __u8 key) /* storage key */ { char dbf_txt[15]; int ccode; CIO_TRACE_EVENT (4, "stIO"); CIO_TRACE_EVENT (4, sch->dev.bus_id); /* sch is always under 2G. */ sch->orb.intparm = (__u32)(unsigned long)sch; sch->orb.fmt = 1; sch->orb.pfch = sch->options.prefetch == 0; sch->orb.spnd = sch->options.suspend; sch->orb.ssic = sch->options.suspend && sch->options.inter; sch->orb.lpm = (lpm != 0) ? (lpm & sch->opm) : sch->lpm; #ifdef CONFIG_ARCH_S390X /* * for 64 bit we always support 64 bit IDAWs with 4k page size only */ sch->orb.c64 = 1; sch->orb.i2k = 0; #endif sch->orb.key = key >> 4; /* issue "Start Subchannel" */ sch->orb.cpa = (__u32) __pa (cpa); ccode = ssch (sch->irq, &sch->orb); /* process condition code */ sprintf (dbf_txt, "ccode:%d", ccode); CIO_TRACE_EVENT (4, dbf_txt); switch (ccode) { case 0: /* * initialize device status information */ sch->schib.scsw.actl |= SCSW_ACTL_START_PEND; return 0; case 1: /* status pending */ case 2: /* busy */ return -EBUSY; default: /* device/path not operational */ return cio_start_handle_notoper(sch, lpm); } }
/** * s390_register_adapter_interrupt() - register adapter interrupt handler * @handler: adapter handler to be registered * @drv_data: driver data passed with each call to the handler * @isc: isc for which the handler should be called * * Returns: * Pointer to the indicator to be used on success * ERR_PTR() if registration failed */ void *s390_register_adapter_interrupt(adapter_int_handler_t handler, void *drv_data, u8 isc) { struct airq_t *airq; char dbf_txt[16]; int ret; if (isc > MAX_ISC) return ERR_PTR(-EINVAL); airq = kmalloc(sizeof(struct airq_t), GFP_KERNEL); if (!airq) { ret = -ENOMEM; goto out; } airq->handler = handler; airq->drv_data = drv_data; ret = register_airq(airq, isc); out: snprintf(dbf_txt, sizeof(dbf_txt), "rairq:%d", ret); CIO_TRACE_EVENT(4, dbf_txt); if (ret < 0) { kfree(airq); return ERR_PTR(ret); } else return &indicators[isc].byte[ret]; }
/* * Function: s390_redo_validation * Look for no longer blacklisted devices * FIXME: there must be a better way to do this */ static inline void s390_redo_validation (void) { unsigned int irq; CIO_TRACE_EVENT (0, "redoval"); for (irq = 0; irq <= __MAX_SUBCHANNELS; irq++) { int ret; struct subchannel *sch; sch = get_subchannel_by_schid(irq); if (sch) { /* Already known. */ put_device(&sch->dev); continue; } ret = css_probe_device(irq); if (ret == -ENXIO) break; /* We're through. */ if (ret == -ENOMEM) /* * Stop validation for now. Bad, but no need for a * panic. */ break; } }
/* * Function: s390_vary_chpid * Varies the specified chpid online or offline */ static int s390_vary_chpid(struct chp_id chpid, int on) { char dbf_text[15]; int status; sprintf(dbf_text, on?"varyon%x.%02x":"varyoff%x.%02x", chpid.cssid, chpid.id); CIO_TRACE_EVENT(2, dbf_text); status = chp_get_status(chpid); if (status < 0) { printk(KERN_ERR "Can't vary unknown chpid %x.%02x\n", chpid.cssid, chpid.id); return -EINVAL; } if (!on && !status) { printk(KERN_ERR "chpid %x.%02x is already offline\n", chpid.cssid, chpid.id); return -EINVAL; } set_chp_logically_online(chpid, on); chsc_chp_vary(chpid, on); return 0; }
int cio_start_key (struct subchannel *sch, struct ccw1 * cpa, __u8 lpm, __u8 key) { struct io_subchannel_private *priv = to_io_private(sch); union orb *orb = &priv->orb; int ccode; CIO_TRACE_EVENT(5, "stIO"); CIO_TRACE_EVENT(5, dev_name(&sch->dev)); memset(orb, 0, sizeof(union orb)); orb->cmd.intparm = (u32)(addr_t)sch; orb->cmd.fmt = 1; orb->cmd.pfch = priv->options.prefetch == 0; orb->cmd.spnd = priv->options.suspend; orb->cmd.ssic = priv->options.suspend && priv->options.inter; orb->cmd.lpm = (lpm != 0) ? lpm : sch->lpm; #ifdef CONFIG_64BIT orb->cmd.c64 = 1; orb->cmd.i2k = 0; #endif orb->cmd.key = key >> 4; orb->cmd.cpa = (__u32) __pa(cpa); ccode = ssch(sch->schid, orb); CIO_HEX_EVENT(5, &ccode, sizeof(ccode)); switch (ccode) { case 0: sch->schib.scsw.cmd.actl |= SCSW_ACTL_START_PEND; return 0; case 1: case 2: return -EBUSY; case 3: return cio_start_handle_notoper(sch, lpm); default: return ccode; } }
void do_adapter_IO (void) { CIO_TRACE_EVENT (6, "doaio"); if (adapter_handler) (*adapter_handler) (); }
/** * cio_validate_subchannel - basic validation of subchannel * @sch: subchannel structure to be filled out * @schid: subchannel id * * Find out subchannel type and initialize struct subchannel. * Return codes: * 0 on success * -ENXIO for non-defined subchannels * -ENODEV for invalid subchannels or blacklisted devices * -EIO for subchannels in an invalid subchannel set */ int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) { char dbf_txt[15]; int ccode; int err; sprintf(dbf_txt, "valsch%x", schid.sch_no); CIO_TRACE_EVENT(4, dbf_txt); /* Nuke all fields. */ memset(sch, 0, sizeof(struct subchannel)); sch->schid = schid; if (cio_is_console(schid)) { sch->lock = cio_get_console_lock(); } else { err = cio_create_sch_lock(sch); if (err) goto out; } mutex_init(&sch->reg_mutex); /* * The first subchannel that is not-operational (ccode==3) * indicates that there aren't any more devices available. * If stsch gets an exception, it means the current subchannel set * is not valid. */ ccode = stsch_err (schid, &sch->schib); if (ccode) { err = (ccode == 3) ? -ENXIO : ccode; goto out; } /* Copy subchannel type from path management control word. */ sch->st = sch->schib.pmcw.st; switch (sch->st) { case SUBCHANNEL_TYPE_IO: err = cio_validate_io_subchannel(sch); break; case SUBCHANNEL_TYPE_MSG: err = cio_validate_msg_subchannel(sch); break; default: err = 0; } if (err) goto out; CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", sch->schid.ssid, sch->schid.sch_no, sch->st); return 0; out: if (!cio_is_console(schid)) kfree(sch->lock); sch->lock = NULL; return err; }
/** * cio_disable_subchannel - disable a subchannel. * @sch: subchannel to disable */ int cio_disable_subchannel(struct subchannel *sch) { char dbf_txt[15]; int ccode; int retry; int ret; CIO_TRACE_EVENT (2, "dissch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return 0; ccode = stsch (sch->schid, &sch->schib); if (ccode == 3) /* Not operational. */ return -ENODEV; if (scsw_actl(&sch->schib.scsw) != 0) /* * the disable function must not be called while there are * requests pending for completion ! */ return -EBUSY; for (retry = 5, ret = 0; retry > 0; retry--) { sch->schib.pmcw.ena = 0; ret = cio_modify(sch); if (ret == -ENODEV) break; if (ret == -EBUSY) /* * The subchannel is busy or status pending. * We'll disable when the next interrupt was delivered * via the state machine. */ break; if (ret == 0) { stsch (sch->schid, &sch->schib); if (!sch->schib.pmcw.ena) break; } } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; }
/** * cio_disable_subchannel - disable a subchannel. * @sch: subchannel to disable */ int cio_disable_subchannel(struct subchannel *sch) { int ret; CIO_TRACE_EVENT(2, "dissch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return 0; if (cio_update_schib(sch)) return -ENODEV; sch->config.ena = 0; ret = cio_commit_config(sch); CIO_HEX_EVENT(2, &ret, sizeof(ret)); return ret; }
/** * cio_enable_subchannel - enable a subchannel. * @sch: subchannel to be enabled * @intparm: interruption parameter to set */ int cio_enable_subchannel(struct subchannel *sch, u32 intparm) { char dbf_txt[15]; int ccode; int retry; int ret; CIO_TRACE_EVENT (2, "ensch"); CIO_TRACE_EVENT(2, dev_name(&sch->dev)); if (sch_is_pseudo_sch(sch)) return -EINVAL; ccode = stsch (sch->schid, &sch->schib); if (ccode) return -ENODEV; for (retry = 5, ret = 0; retry > 0; retry--) { sch->schib.pmcw.ena = 1; sch->schib.pmcw.isc = sch->isc; sch->schib.pmcw.intparm = intparm; ret = cio_modify(sch); if (ret == -ENODEV) break; if (ret == -EIO) /* * Got a program check in cio_modify. Try without * the concurrent sense bit the next time. */ sch->schib.pmcw.csense = 0; if (ret == 0) { stsch (sch->schid, &sch->schib); if (sch->schib.pmcw.ena) break; } if (ret == -EBUSY) { struct irb irb; if (tsch(sch->schid, &irb) != 0) break; } } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; }
/* * Enable subchannel. */ int cio_enable_subchannel (struct subchannel *sch, unsigned int isc) { char dbf_txt[15]; int ccode; int retry; int ret; CIO_TRACE_EVENT (2, "ensch"); CIO_TRACE_EVENT (2, sch->dev.bus_id); ccode = stsch (sch->irq, &sch->schib); if (ccode) return -ENODEV; for (retry = 5, ret = 0; retry > 0; retry--) { sch->schib.pmcw.ena = 1; sch->schib.pmcw.isc = isc; sch->schib.pmcw.intparm = (__u32)(unsigned long)sch; ret = cio_modify(sch); if (ret == -ENODEV) break; if (ret == -EIO) /* * Got a program check in cio_modify. Try without * the concurrent sense bit the next time. */ sch->schib.pmcw.csense = 0; if (ret == 0) { stsch (sch->irq, &sch->schib); if (sch->schib.pmcw.ena) break; } if (ret == -EBUSY) { struct irb irb; if (tsch(sch->irq, &irb) != 0) break; } } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (2, dbf_txt); return ret; }
static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { struct irb *irb = &cdev->private->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; enum uc_todo todo; if (ccw_device_accumulate_and_sense(cdev, lcirb)) return IO_RUNNING; if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) return IO_KILLED; if (scsw->cc == 3 || scsw->pno) return IO_PATH_ERROR; if (irb->esw.esw0.erw.cons) { CIO_TRACE_EVENT(2, "sensedata"); CIO_HEX_EVENT(2, &cdev->private->dev_id, sizeof(struct ccw_dev_id)); CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT); if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; if (cdev->drv && cdev->drv->uc_handler) { todo = cdev->drv->uc_handler(cdev, lcirb); CIO_TRACE_EVENT(2, "uc_response"); CIO_HEX_EVENT(2, &todo, sizeof(todo)); switch (todo) { case UC_TODO_RETRY: return IO_STATUS_ERROR; case UC_TODO_RETRY_ON_NEW_PATH: return IO_PATH_ERROR; case UC_TODO_STOP: return IO_REJECTED; default: return IO_STATUS_ERROR; } } return IO_STATUS_ERROR; }
/* * Return the status of the internal I/O started on the specified ccw device. * Perform BASIC SENSE if required. */ static enum io_status ccwreq_status(struct ccw_device *cdev, struct irb *lcirb) { struct irb *irb = &cdev->private->irb; struct cmd_scsw *scsw = &irb->scsw.cmd; enum uc_todo todo; /* Perform BASIC SENSE if needed. */ if (ccw_device_accumulate_and_sense(cdev, lcirb)) return IO_RUNNING; /* Check for halt/clear interrupt. */ if (scsw->fctl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) return IO_KILLED; /* Check for path error. */ if (scsw->cc == 3 || scsw->pno) return IO_PATH_ERROR; /* Handle BASIC SENSE data. */ if (irb->esw.esw0.erw.cons) { CIO_TRACE_EVENT(2, "sensedata"); CIO_HEX_EVENT(2, &cdev->private->dev_id, sizeof(struct ccw_dev_id)); CIO_HEX_EVENT(2, &cdev->private->irb.ecw, SENSE_MAX_COUNT); /* Check for command reject. */ if (irb->ecw[0] & SNS0_CMD_REJECT) return IO_REJECTED; /* Ask the driver what to do */ if (cdev->drv && cdev->drv->uc_handler) { todo = cdev->drv->uc_handler(cdev, lcirb); CIO_TRACE_EVENT(2, "uc_response"); CIO_HEX_EVENT(2, &todo, sizeof(todo)); switch (todo) { case UC_TODO_RETRY: return IO_STATUS_ERROR; case UC_TODO_RETRY_ON_NEW_PATH: return IO_PATH_ERROR; case UC_TODO_STOP: return IO_REJECTED; default: return IO_STATUS_ERROR; } } /* Assume that unexpected SENSE data implies an error. */ return IO_STATUS_ERROR; }
int s390_unregister_adapter_interrupt (adapter_int_handler_t handler) { int ret; char dbf_txt[15]; CIO_TRACE_EVENT (4, "urgaint"); if (handler == NULL) ret = -EINVAL; else { adapter_handler = NULL; synchronize_sched(); /* Allow interrupts to complete. */ ret = 0; } sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (4, dbf_txt); return ret; }
/* * register for adapter interrupts * * With HiperSockets the zSeries architecture provides for * means of adapter interrups, pseudo I/O interrupts that are * not tied to an I/O subchannel, but to an adapter. However, * it doesn't disclose the info how to enable/disable them, but * to recognize them only. Perhaps we should consider them * being shared interrupts, and thus build a linked list * of adapter handlers ... to be evaluated ... */ int s390_register_adapter_interrupt (adapter_int_handler_t handler) { int ret; char dbf_txt[15]; CIO_TRACE_EVENT (4, "rgaint"); if (handler == NULL) ret = -EINVAL; else ret = (cmpxchg(&adapter_handler, NULL, handler) ? -EBUSY : 0); if (!ret) synchronize_sched(); /* Allow interrupts to complete. */ sprintf (dbf_txt, "ret:%d", ret); CIO_TRACE_EVENT (4, dbf_txt); return ret; }
int cio_validate_subchannel(struct subchannel *sch, struct subchannel_id schid) { char dbf_txt[15]; int ccode; int err; sprintf(dbf_txt, "valsch%x", schid.sch_no); CIO_TRACE_EVENT(4, dbf_txt); memset(sch, 0, sizeof(struct subchannel)); sch->schid = schid; if (cio_is_console(schid)) { sch->lock = cio_get_console_lock(); } else { err = cio_create_sch_lock(sch); if (err) goto out; } mutex_init(&sch->reg_mutex); ccode = stsch_err (schid, &sch->schib); if (ccode) { err = (ccode == 3) ? -ENXIO : ccode; goto out; } sch->st = sch->schib.pmcw.st; switch (sch->st) { case SUBCHANNEL_TYPE_IO: err = cio_validate_io_subchannel(sch); break; case SUBCHANNEL_TYPE_MSG: err = cio_validate_msg_subchannel(sch); break; default: err = 0; } if (err) goto out; CIO_MSG_EVENT(4, "Subchannel 0.%x.%04x reports subchannel type %04X\n", sch->schid.ssid, sch->schid.sch_no, sch->st); return 0; out: if (!cio_is_console(schid)) kfree(sch->lock); sch->lock = NULL; return err; }