/* * 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; } }
static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow) { struct schib schib; if (!slow) { /* Will be done on the slow path. */ return -EAGAIN; } if (stsch_err(schid, &schib)) { /* Subchannel is not provided. */ return -ENXIO; } if (!css_sch_is_valid(&schib)) { /* Unusable - ignore. */ return 0; } CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new\n", schid.ssid, schid.sch_no); return css_probe_device(schid); }
static int css_evaluate_subchannel(int irq, int slow) { int event, ret, disc; struct subchannel *sch; unsigned long flags; sch = get_subchannel_by_schid(irq); disc = sch ? device_is_disconnected(sch) : 0; if (disc && slow) { if (sch) put_device(&sch->dev); return 0; /* Already processed. */ } /* * We've got a machine check, so running I/O won't get an interrupt. * Kill any pending timers. */ if (sch) device_kill_pending_timer(sch); if (!disc && !slow) { if (sch) put_device(&sch->dev); return -EAGAIN; /* Will be done on the slow path. */ } event = css_get_subchannel_status(sch, irq); CIO_MSG_EVENT(4, "Evaluating schid %04x, event %d, %s, %s path.\n", irq, event, sch?(disc?"disconnected":"normal"):"unknown", slow?"slow":"fast"); switch (event) { case CIO_NO_PATH: case CIO_GONE: if (!sch) { /* Never used this subchannel. Ignore. */ ret = 0; break; } if (disc && (event == CIO_NO_PATH)) { /* * Uargh, hack again. Because we don't get a machine * check on configure on, our path bookkeeping can * be out of date here (it's fine while we only do * logical varying or get chsc machine checks). We * need to force reprobing or we might miss devices * coming operational again. It won't do harm in real * no path situations. */ spin_lock_irqsave(&sch->lock, flags); device_trigger_reprobe(sch); spin_unlock_irqrestore(&sch->lock, flags); ret = 0; break; } if (sch->driver && sch->driver->notify && sch->driver->notify(&sch->dev, event)) { cio_disable_subchannel(sch); device_set_disconnected(sch); ret = 0; break; } /* * Unregister subchannel. * The device will be killed automatically. */ cio_disable_subchannel(sch); device_unregister(&sch->dev); /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; cio_modify(sch); put_device(&sch->dev); ret = 0; break; case CIO_REVALIDATE: /* * Revalidation machine check. Sick. * We don't notify the driver since we have to throw the device * away in any case. */ if (!disc) { device_unregister(&sch->dev); /* Reset intparm to zeroes. */ sch->schib.pmcw.intparm = 0; cio_modify(sch); put_device(&sch->dev); ret = css_probe_device(irq); } else { /* * We can't immediately deregister the disconnected * device since it might block. */ spin_lock_irqsave(&sch->lock, flags); device_trigger_reprobe(sch); spin_unlock_irqrestore(&sch->lock, flags); ret = 0; } break; case CIO_OPER: if (disc) { spin_lock_irqsave(&sch->lock, flags); /* Get device operational again. */ device_trigger_reprobe(sch); spin_unlock_irqrestore(&sch->lock, flags); } ret = sch ? 0 : css_probe_device(irq); break; default: BUG(); ret = 0; } return ret; }