/* * Function: cio_modify * Issues a "Modify Subchannel" on the specified subchannel */ int cio_modify (struct subchannel *sch) { int ccode, retry, ret; ret = 0; for (retry = 0; retry < 5; retry++) { ccode = msch_err (sch->irq, &sch->schib); if (ccode < 0) /* -EIO if msch gets a program check. */ return ccode; switch (ccode) { case 0: /* successfull */ return 0; case 1: /* status pending */ return -EBUSY; case 2: /* busy */ udelay (100); /* allow for recovery */ ret = -EBUSY; break; case 3: /* not operational */ return -ENODEV; } } return ret; }
static int set_schib(struct ccw_device *cdev, u32 mme, int mbfc, unsigned long address) { int ret; int retry; struct subchannel *sch; struct schib *schib; sch = to_subchannel(cdev->dev.parent); schib = &sch->schib; /* msch can silently fail, so do it again if necessary */ for (retry = 0; retry < 3; retry++) { /* prepare schib */ stsch(sch->schid, schib); schib->pmcw.mme = mme; schib->pmcw.mbfc = mbfc; /* address can be either a block address or a block index */ if (mbfc) schib->mba = address; else schib->pmcw.mbi = address; /* try to submit it */ switch(ret = msch_err(sch->schid, schib)) { case 0: break; case 1: case 2: /* in I/O or status pending */ ret = -EBUSY; break; case 3: /* subchannel is no longer valid */ ret = -ENODEV; break; default: /* msch caught an exception */ ret = -EINVAL; break; } stsch(sch->schid, schib); /* restore the schib */ if (ret) break; /* check if it worked */ if (schib->pmcw.mme == mme && schib->pmcw.mbfc == mbfc && (mbfc ? (schib->mba == address) : (schib->pmcw.mbi == address))) return 0; ret = -EINVAL; } return ret; }
static int __disable_subchannel_easy(struct subchannel_id schid, struct schib *schib) { int retry, cc; cc = 0; for (retry=0;retry<3;retry++) { schib->pmcw.ena = 0; cc = msch_err(schid, schib); if (cc) return (cc==3?-ENODEV:-EBUSY); if (stsch_err(schid, schib) || !css_sch_is_valid(schib)) return -ENODEV; if (!schib->pmcw.ena) return 0; } return -EBUSY; /* uhm... */ }
/* * cio_commit_config - apply configuration to the subchannel */ int cio_commit_config(struct subchannel *sch) { int ccode, retry, ret = 0; struct schib schib; struct irb irb; if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; for (retry = 0; retry < 5; retry++) { /* copy desired changes to local schib */ cio_apply_config(sch, &schib); ccode = msch_err(sch->schid, &schib); if (ccode < 0) /* -EIO if msch gets a program check. */ return ccode; switch (ccode) { case 0: /* successful */ if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; if (cio_check_config(sch, &schib)) { /* commit changes from local schib */ memcpy(&sch->schib, &schib, sizeof(schib)); return 0; } ret = -EAGAIN; break; case 1: /* status pending */ ret = -EBUSY; if (tsch(sch->schid, &irb)) return ret; break; case 2: /* busy */ udelay(100); /* allow for recovery */ ret = -EBUSY; break; case 3: /* not operational */ return -ENODEV; } } return ret; }
int cio_commit_config(struct subchannel *sch) { struct schib schib; int ccode, retry, ret = 0; if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; for (retry = 0; retry < 5; retry++) { cio_apply_config(sch, &schib); ccode = msch_err(sch->schid, &schib); if (ccode < 0) return ccode; switch (ccode) { case 0: if (stsch_err(sch->schid, &schib) || !css_sch_is_valid(&schib)) return -ENODEV; if (cio_check_config(sch, &schib)) { memcpy(&sch->schib, &schib, sizeof(schib)); return 0; } ret = -EAGAIN; break; case 1: return -EBUSY; case 2: udelay(100); ret = -EBUSY; break; case 3: return -ENODEV; } } return ret; }