/*
 * 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;
	}
}
Esempio n. 2
0
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);
}
Esempio n. 3
0
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;
}