*
* Copyright (C) 2002 IBM Deutschland Entwicklung GmbH,
* IBM Corporation
- * Author(s): Cornelia Huck(cohuck@de.ibm.com)
+ * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
* Martin Schwidefsky (schwidefsky@de.ibm.com)
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/init.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
#include <asm/ccwdev.h>
-#include <asm/qdio.h>
+#include <asm/cio.h>
#include "cio.h"
#include "cio_debug.h"
#include "device.h"
#include "chsc.h"
#include "ioasm.h"
-#include "qdio.h"
+
+int
+device_is_online(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ if (!sch->dev.driver_data)
+ return 0;
+ cdev = sch->dev.driver_data;
+ return (cdev->private->state == DEV_STATE_ONLINE);
+}
int
device_is_disconnected(struct subchannel *sch)
return;
cdev = sch->dev.driver_data;
ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED;
}
add_timer(&cdev->private->timer);
}
+/* Kill any pending timers after machine check. */
+void
+device_kill_pending_timer(struct subchannel *sch)
+{
+ struct ccw_device *cdev;
+
+ if (!sch->dev.driver_data)
+ return;
+ cdev = sch->dev.driver_data;
+ ccw_device_set_timeout(cdev, 0);
+}
+
/*
* Cancel running i/o. This is called repeatedly since halt/clear are
* asynchronous operations. We do one try with cio_cancel, two tries
int ret;
sch = to_subchannel(cdev->dev.parent);
- ret = stsch(sch->irq, &sch->schib);
+ ret = stsch(sch->schid, &sch->schib);
if (ret || !sch->schib.pmcw.dnv)
return -ENODEV;
if (!sch->schib.pmcw.ena || sch->schib.scsw.actl == 0)
panic("Can't stop i/o on subchannel.\n");
}
-static void
+static int
ccw_device_handle_oper(struct ccw_device *cdev)
{
struct subchannel *sch;
PREPARE_WORK(&cdev->private->kick_work,
ccw_device_do_unreg_rereg, (void *)cdev);
queue_work(ccw_device_work, &cdev->private->kick_work);
- return;
+ return 0;
}
cdev->private->flags.donotify = 1;
- /* Get device online again. */
- ccw_device_online(cdev);
+ return 1;
}
/*
ccw_device_recog_done(struct ccw_device *cdev, int state)
{
struct subchannel *sch;
- int notify, old_lpm;
+ int notify, old_lpm, same_dev;
sch = to_subchannel(cdev->dev.parent);
* through ssch() and the path information is up to date.
*/
old_lpm = sch->lpm;
- stsch(sch->irq, &sch->schib);
+ stsch(sch->schid, &sch->schib);
sch->lpm = sch->schib.pmcw.pim &
sch->schib.pmcw.pam &
sch->schib.pmcw.pom &
sch->opm;
+ /* Check since device may again have become not operational. */
+ if (!sch->schib.pmcw.dnv)
+ state = DEV_STATE_NOT_OPER;
if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
/* Force reprobe on all chpids. */
old_lpm = 0;
/* Boxed devices don't need extra treatment. */
}
notify = 0;
+ same_dev = 0; /* Keep the compiler quiet... */
switch (state) {
case DEV_STATE_NOT_OPER:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : unknown device %04x on subchannel %04x\n",
- cdev->private->devno, sch->irq);
+ "SenseID : unknown device %04x on subchannel "
+ "0.%x.%04x\n", cdev->private->devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
case DEV_STATE_OFFLINE:
- if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
+ if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) {
+ same_dev = ccw_device_handle_oper(cdev);
notify = 1;
- else /* fill out sense information */
- cdev->id = (struct ccw_device_id) {
- .cu_type = cdev->private->senseid.cu_type,
- .cu_model = cdev->private->senseid.cu_model,
- .dev_type = cdev->private->senseid.dev_type,
- .dev_model = cdev->private->senseid.dev_model,
- };
+ }
+ /* fill out sense information */
+ cdev->id = (struct ccw_device_id) {
+ .cu_type = cdev->private->senseid.cu_type,
+ .cu_model = cdev->private->senseid.cu_model,
+ .dev_type = cdev->private->senseid.dev_type,
+ .dev_model = cdev->private->senseid.dev_model,
+ };
+ if (notify) {
+ cdev->private->state = DEV_STATE_OFFLINE;
+ if (same_dev) {
+ /* Get device online again. */
+ ccw_device_online(cdev);
+ wake_up(&cdev->private->wait_q);
+ }
+ return;
+ }
/* Issue device info message. */
- CIO_DEBUG(KERN_INFO, 2, "SenseID : device %04x reports: "
+ CIO_DEBUG(KERN_INFO, 2, "SenseID : device 0.%x.%04x reports: "
"CU Type/Mod = %04X/%02X, Dev Type/Mod = "
- "%04X/%02X\n", cdev->private->devno,
+ "%04X/%02X\n",
+ cdev->private->ssid, cdev->private->devno,
cdev->id.cu_type, cdev->id.cu_model,
cdev->id.dev_type, cdev->id.dev_model);
break;
case DEV_STATE_BOXED:
CIO_DEBUG(KERN_WARNING, 2,
- "SenseID : boxed device %04x on subchannel %04x\n",
- cdev->private->devno, sch->irq);
+ "SenseID : boxed device %04x on subchannel "
+ "0.%x.%04x\n", cdev->private->devno,
+ sch->schid.ssid, sch->schid.sch_no);
break;
}
cdev->private->state = state;
- if (notify && state == DEV_STATE_OFFLINE)
- ccw_device_handle_oper(cdev);
- else
- io_subchannel_recog_done(cdev);
+ io_subchannel_recog_done(cdev);
if (state != DEV_STATE_NOT_OPER)
wake_up(&cdev->private->wait_q);
}
if (state == DEV_STATE_BOXED)
CIO_DEBUG(KERN_WARNING, 2,
"Boxed device %04x on subchannel %04x\n",
- cdev->private->devno, sch->irq);
+ cdev->private->devno, sch->schid.sch_no);
if (cdev->private->flags.donotify) {
cdev->private->flags.donotify = 0;
(void *)cdev);
queue_work(ccw_device_work,
&cdev->private->kick_work);
- }
+ } else
+ put_device(&sch->dev);
}
} else {
cio_disable_subchannel(sch);
ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q);
}
}
-void
-device_call_nopath_notify(struct subchannel *sch)
-{
- struct ccw_device *cdev;
-
- if (!sch->dev.driver_data)
- return;
- cdev = sch->dev.driver_data;
- PREPARE_WORK(&cdev->private->kick_work,
- ccw_device_nopath_notify, (void *)cdev);
- queue_work(ccw_device_notify_work, &cdev->private->kick_work);
-}
-
-
void
ccw_device_verify_done(struct ccw_device *cdev, int err)
{
cdev->private->options.pgroup = 0;
case 0:
ccw_device_done(cdev, DEV_STATE_ONLINE);
+ /* Deliver fake irb to device driver, if needed. */
+ if (cdev->private->flags.fake_irb) {
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+ cdev->private->irb.scsw = (struct scsw) {
+ .cc = 1,
+ .fctl = SCSW_FCTL_START_FUNC,
+ .actl = SCSW_ACTL_START_PEND,
+ .stctl = SCSW_STCTL_STATUS_PEND,
+ };
+ cdev->private->flags.fake_irb = 0;
+ if (cdev->handler)
+ cdev->handler(cdev, cdev->private->intparm,
+ &cdev->private->irb);
+ memset(&cdev->private->irb, 0, sizeof(struct irb));
+ }
break;
case -ETIME:
ccw_device_done(cdev, DEV_STATE_BOXED);
struct subchannel *sch;
sch = to_subchannel(cdev->dev.parent);
+ if (stsch(sch->schid, &sch->schib) || !sch->schib.pmcw.dnv)
+ return -ENODEV;
if (cdev->private->state != DEV_STATE_ONLINE) {
if (sch->schib.scsw.actl != 0)
return -EBUSY;
cdev->private->state = DEV_STATE_NOT_OPER;
sch = to_subchannel(cdev->dev.parent);
- device_unregister(&sch->dev);
- sch->schib.pmcw.intparm = 0;
- cio_modify(sch);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister, (void *)cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
wake_up(&cdev->private->wait_q);
}
if (sch->driver->notify &&
sch->driver->notify(&sch->dev, sch->lpm ? CIO_GONE : CIO_NO_PATH)) {
ccw_device_set_timeout(cdev, 0);
+ cdev->private->flags.fake_irb = 0;
cdev->private->state = DEV_STATE_DISCONNECTED;
wake_up(&cdev->private->wait_q);
return;
// FIXME: not-oper indication to device driver ?
ccw_device_call_handler(cdev);
}
- device_unregister(&sch->dev);
- sch->schib.pmcw.intparm = 0;
- cio_modify(sch);
+ if (get_device(&cdev->dev)) {
+ PREPARE_WORK(&cdev->private->kick_work,
+ ccw_device_call_sch_unregister, (void *)cdev);
+ queue_work(ccw_device_work, &cdev->private->kick_work);
+ }
wake_up(&cdev->private->wait_q);
}
return;
}
sch = to_subchannel(cdev->dev.parent);
+ /*
+ * Since we might not just be coming from an interrupt from the
+ * subchannel we have to update the schib.
+ */
+ stsch(sch->schid, &sch->schib);
+
if (sch->schib.scsw.actl != 0 ||
(cdev->private->irb.scsw.stctl & SCSW_STCTL_STATUS_PEND)) {
/*
irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
- if (irb->scsw.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
+ if ((irb->scsw.stctl ==
+ (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+ && (!irb->scsw.cc)) {
+ if ((irb->scsw.dstat & DEV_STAT_UNIT_CHECK) &&
+ !irb->esw.esw0.erw.cons) {
+ /* Unit check but no sense data. Need basic sense. */
+ if (ccw_device_do_sense(cdev, irb) != 0)
+ goto call_handler_unsol;
+ memcpy(irb, &cdev->private->irb, sizeof(struct irb));
+ cdev->private->state = DEV_STATE_W4SENSE;
+ cdev->private->intparm = 0;
+ return;
+ }
+call_handler_unsol:
if (cdev->handler)
cdev->handler (cdev, 0, irb);
return;
/* Check for unsolicited interrupt. */
if (irb->scsw.stctl ==
(SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (cdev->handler)
- cdev->handler (cdev, 0, irb);
if (irb->scsw.cc == 1)
/* Basic sense hasn't started. Try again. */
ccw_device_do_sense(cdev, irb);
+ else {
+ printk("Huh? %s(%s): unsolicited interrupt...\n",
+ __FUNCTION__, cdev->dev.bus_id);
+ if (cdev->handler)
+ cdev->handler (cdev, 0, irb);
+ }
return;
}
/* Add basic sense info to irb. */
struct irb *irb;
irb = (struct irb *) __LC_IRB;
- /* Check for unsolicited interrupt. */
- if (irb->scsw.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (cdev->handler)
- cdev->handler (cdev, 0, irb);
- return;
- }
/* Accumulate status. We don't do basic sense. */
ccw_device_accumulate_irb(cdev, irb);
/* Try to start delayed device verification. */
struct subchannel *sch;
irb = (struct irb *) __LC_IRB;
- /* Check for unsolicited interrupt. */
- if (irb->scsw.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
- if (cdev->handler)
- cdev->handler (cdev, 0, irb);
- if (irb->scsw.cc == 1)
- goto call_handler;
- return;
- }
/*
* Accumulate status and find out if a basic sense is needed.
* This is fine since we have already adapted the lpm.
}
return;
}
-call_handler:
+
/* Iff device is idle, reset timeout. */
sch = to_subchannel(cdev->dev.parent);
- if (!stsch(sch->irq, &sch->schib))
+ if (!stsch(sch->schid, &sch->schib))
if (sch->schib.scsw.actl == 0)
ccw_device_set_timeout(cdev, 0);
/* Call the handler. */
case DEV_EVENT_INTERRUPT:
irb = (struct irb *) __LC_IRB;
/* Check for unsolicited interrupt. */
- if (irb->scsw.stctl ==
- (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS))
+ if ((irb->scsw.stctl ==
+ (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) &&
+ (!irb->scsw.cc))
/* FIXME: we should restart stlck here, but this
* is extremely unlikely ... */
goto out_wakeup;
device_trigger_reprobe(struct subchannel *sch)
{
struct ccw_device *cdev;
- unsigned long flags;
if (!sch->dev.driver_data)
return;
cdev = sch->dev.driver_data;
- spin_lock_irqsave(&sch->lock, flags);
- if (cdev->private->state != DEV_STATE_DISCONNECTED) {
- spin_unlock_irqrestore(&sch->lock, flags);
+ if (cdev->private->state != DEV_STATE_DISCONNECTED)
return;
- }
+
/* Update some values. */
- if (stsch(sch->irq, &sch->schib)) {
- spin_unlock_irqrestore(&sch->lock, flags);
+ if (stsch(sch->schid, &sch->schib))
return;
- }
+
/*
* The pim, pam, pom values may not be accurate, but they are the best
* we have before performing device selection :/
if ((sch->lpm & (sch->lpm - 1)) != 0)
sch->schib.pmcw.mp = 1;
sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
+ /* We should also udate ssd info, but this has to wait. */
ccw_device_start_id(cdev, 0);
- spin_unlock_irqrestore(&sch->lock, flags);
}
static void
* device statemachine
*/
fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
- [DEV_STATE_NOT_OPER] {
- [DEV_EVENT_NOTOPER] ccw_device_nop,
- [DEV_EVENT_INTERRUPT] ccw_device_bug,
- [DEV_EVENT_TIMEOUT] ccw_device_nop,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_NOT_OPER] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_nop,
+ [DEV_EVENT_INTERRUPT] = ccw_device_bug,
+ [DEV_EVENT_TIMEOUT] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_SENSE_PGID] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_sense_pgid_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_SENSE_PGID] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_sense_pgid_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_SENSE_ID] {
- [DEV_EVENT_NOTOPER] ccw_device_recog_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_sense_id_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_recog_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_SENSE_ID] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_OFFLINE] {
- [DEV_EVENT_NOTOPER] ccw_device_offline_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_offline_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_nop,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_OFFLINE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_offline_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_VERIFY] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_verify_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_VERIFY] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_verify_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_ONLINE] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_online_timeout,
- [DEV_EVENT_VERIFY] ccw_device_online_verify,
+ [DEV_STATE_ONLINE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
- [DEV_STATE_W4SENSE] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_w4sense,
- [DEV_EVENT_TIMEOUT] ccw_device_nop,
- [DEV_EVENT_VERIFY] ccw_device_online_verify,
+ [DEV_STATE_W4SENSE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
+ [DEV_EVENT_TIMEOUT] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_online_verify,
},
- [DEV_STATE_DISBAND_PGID] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_disband_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_onoff_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_DISBAND_PGID] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_disband_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_onoff_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_BOXED] {
- [DEV_EVENT_NOTOPER] ccw_device_offline_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_stlck_done,
- [DEV_EVENT_TIMEOUT] ccw_device_stlck_done,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_BOXED] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_offline_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_stlck_done,
+ [DEV_EVENT_TIMEOUT] = ccw_device_stlck_done,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* states to wait for i/o completion before doing something */
- [DEV_STATE_CLEAR_VERIFY] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_clear_verify,
- [DEV_EVENT_TIMEOUT] ccw_device_nop,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_CLEAR_VERIFY] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_clear_verify,
+ [DEV_EVENT_TIMEOUT] = ccw_device_nop,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_TIMEOUT_KILL] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_killing_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_killing_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop, //FIXME
+ [DEV_STATE_TIMEOUT_KILL] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
},
- [DEV_STATE_WAIT4IO] {
- [DEV_EVENT_NOTOPER] ccw_device_online_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_wait4io_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_wait4io_timeout,
- [DEV_EVENT_VERIFY] ccw_device_wait4io_verify,
+ [DEV_STATE_WAIT4IO] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_online_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_wait4io_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_wait4io_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_wait4io_verify,
},
- [DEV_STATE_QUIESCE] {
- [DEV_EVENT_NOTOPER] ccw_device_quiesce_done,
- [DEV_EVENT_INTERRUPT] ccw_device_quiesce_done,
- [DEV_EVENT_TIMEOUT] ccw_device_quiesce_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_QUIESCE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
+ [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done,
+ [DEV_EVENT_TIMEOUT] = ccw_device_quiesce_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
/* special states for devices gone not operational */
- [DEV_STATE_DISCONNECTED] {
- [DEV_EVENT_NOTOPER] ccw_device_nop,
- [DEV_EVENT_INTERRUPT] ccw_device_start_id,
- [DEV_EVENT_TIMEOUT] ccw_device_bug,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_DISCONNECTED] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_nop,
+ [DEV_EVENT_INTERRUPT] = ccw_device_start_id,
+ [DEV_EVENT_TIMEOUT] = ccw_device_bug,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_DISCONNECTED_SENSE_ID] {
- [DEV_EVENT_NOTOPER] ccw_device_recog_notoper,
- [DEV_EVENT_INTERRUPT] ccw_device_sense_id_irq,
- [DEV_EVENT_TIMEOUT] ccw_device_recog_timeout,
- [DEV_EVENT_VERIFY] ccw_device_nop,
+ [DEV_STATE_DISCONNECTED_SENSE_ID] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_recog_notoper,
+ [DEV_EVENT_INTERRUPT] = ccw_device_sense_id_irq,
+ [DEV_EVENT_TIMEOUT] = ccw_device_recog_timeout,
+ [DEV_EVENT_VERIFY] = ccw_device_nop,
},
- [DEV_STATE_CMFCHANGE] {
- [DEV_EVENT_NOTOPER] ccw_device_change_cmfstate,
- [DEV_EVENT_INTERRUPT] ccw_device_change_cmfstate,
- [DEV_EVENT_TIMEOUT] ccw_device_change_cmfstate,
- [DEV_EVENT_VERIFY] ccw_device_change_cmfstate,
+ [DEV_STATE_CMFCHANGE] = {
+ [DEV_EVENT_NOTOPER] = ccw_device_change_cmfstate,
+ [DEV_EVENT_INTERRUPT] = ccw_device_change_cmfstate,
+ [DEV_EVENT_TIMEOUT] = ccw_device_change_cmfstate,
+ [DEV_EVENT_VERIFY] = ccw_device_change_cmfstate,
},
};
CIO_TRACE_EVENT (3, "IRQ");
CIO_TRACE_EVENT (3, pdev->bus_id);
-
- dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
+ if (cdev)
+ dev_fsm_event(cdev, DEV_EVENT_INTERRUPT);
}
EXPORT_SYMBOL_GPL(ccw_device_set_timeout);