1724117b7SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * finite state machine for device handling
41da177e4SLinus Torvalds *
5c820de39SCornelia Huck * Copyright IBM Corp. 2002, 2008
64ce3b30cSCornelia Huck * Author(s): Cornelia Huck (cornelia.huck@de.ibm.com)
71da177e4SLinus Torvalds * Martin Schwidefsky (schwidefsky@de.ibm.com)
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/init.h>
125c2e5a0cSAlexander Gordeev #include <linux/io.h>
134e57b681STim Schmielau #include <linux/jiffies.h>
144e57b681STim Schmielau #include <linux/string.h>
151da177e4SLinus Torvalds
161da177e4SLinus Torvalds #include <asm/ccwdev.h>
174c24da79SCornelia Huck #include <asm/cio.h>
18e5854a58SPeter Oberparleiter #include <asm/chpid.h>
191da177e4SLinus Torvalds
201da177e4SLinus Torvalds #include "cio.h"
211da177e4SLinus Torvalds #include "cio_debug.h"
221da177e4SLinus Torvalds #include "css.h"
231da177e4SLinus Torvalds #include "device.h"
241da177e4SLinus Torvalds #include "chsc.h"
251da177e4SLinus Torvalds #include "ioasm.h"
26e6b6e10aSPeter Oberparleiter #include "chp.h"
271da177e4SLinus Torvalds
2814ff56bbSSebastian Ott static int timeout_log_enabled;
2914ff56bbSSebastian Ott
ccw_timeout_log_setup(char * unused)3014ff56bbSSebastian Ott static int __init ccw_timeout_log_setup(char *unused)
3114ff56bbSSebastian Ott {
3214ff56bbSSebastian Ott timeout_log_enabled = 1;
3314ff56bbSSebastian Ott return 1;
3414ff56bbSSebastian Ott }
3514ff56bbSSebastian Ott
3614ff56bbSSebastian Ott __setup("ccw_timeout_log", ccw_timeout_log_setup);
3714ff56bbSSebastian Ott
ccw_timeout_log(struct ccw_device * cdev)3814ff56bbSSebastian Ott static void ccw_timeout_log(struct ccw_device *cdev)
3914ff56bbSSebastian Ott {
4014ff56bbSSebastian Ott struct schib schib;
4114ff56bbSSebastian Ott struct subchannel *sch;
42cd6b4f27SCornelia Huck struct io_subchannel_private *private;
4383262d63SPeter Oberparleiter union orb *orb;
4414ff56bbSSebastian Ott int cc;
4514ff56bbSSebastian Ott
4614ff56bbSSebastian Ott sch = to_subchannel(cdev->dev.parent);
47cd6b4f27SCornelia Huck private = to_io_private(sch);
4883262d63SPeter Oberparleiter orb = &private->orb;
4962e65da9SPeter Oberparleiter cc = stsch(sch->schid, &schib);
5014ff56bbSSebastian Ott
51eba8e1afSHeiko Carstens printk(KERN_WARNING "cio: ccw device timeout occurred at %lx, "
521aae0560SHeiko Carstens "device information:\n", get_tod_clock());
5314ff56bbSSebastian Ott printk(KERN_WARNING "cio: orb:\n");
5414ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
5583262d63SPeter Oberparleiter orb, sizeof(*orb), 0);
562a0217d5SKay Sievers printk(KERN_WARNING "cio: ccw device bus id: %s\n",
572a0217d5SKay Sievers dev_name(&cdev->dev));
582a0217d5SKay Sievers printk(KERN_WARNING "cio: subchannel bus id: %s\n",
592a0217d5SKay Sievers dev_name(&sch->dev));
6014ff56bbSSebastian Ott printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, "
6114ff56bbSSebastian Ott "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm);
6214ff56bbSSebastian Ott
6383262d63SPeter Oberparleiter if (orb->tm.b) {
6483262d63SPeter Oberparleiter printk(KERN_WARNING "cio: orb indicates transport mode\n");
6583262d63SPeter Oberparleiter printk(KERN_WARNING "cio: last tcw:\n");
6683262d63SPeter Oberparleiter print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
675c2e5a0cSAlexander Gordeev phys_to_virt(orb->tm.tcw),
6883262d63SPeter Oberparleiter sizeof(struct tcw), 0);
6983262d63SPeter Oberparleiter } else {
7083262d63SPeter Oberparleiter printk(KERN_WARNING "cio: orb indicates command mode\n");
7137db8985SHalil Pasic if ((void *)(addr_t)orb->cmd.cpa ==
7237db8985SHalil Pasic &private->dma_area->sense_ccw ||
7337db8985SHalil Pasic (void *)(addr_t)orb->cmd.cpa ==
7437db8985SHalil Pasic cdev->private->dma_area->iccws)
7583262d63SPeter Oberparleiter printk(KERN_WARNING "cio: last channel program "
7683262d63SPeter Oberparleiter "(intern):\n");
7714ff56bbSSebastian Ott else
7814ff56bbSSebastian Ott printk(KERN_WARNING "cio: last channel program:\n");
7914ff56bbSSebastian Ott
8014ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
815c2e5a0cSAlexander Gordeev phys_to_virt(orb->cmd.cpa),
82cd6b4f27SCornelia Huck sizeof(struct ccw1), 0);
8383262d63SPeter Oberparleiter }
8414ff56bbSSebastian Ott printk(KERN_WARNING "cio: ccw device state: %d\n",
8514ff56bbSSebastian Ott cdev->private->state);
8614ff56bbSSebastian Ott printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc);
8714ff56bbSSebastian Ott printk(KERN_WARNING "cio: schib:\n");
8814ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
8914ff56bbSSebastian Ott &schib, sizeof(schib), 0);
9014ff56bbSSebastian Ott printk(KERN_WARNING "cio: ccw device flags:\n");
9114ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1,
9214ff56bbSSebastian Ott &cdev->private->flags, sizeof(cdev->private->flags), 0);
9314ff56bbSSebastian Ott }
9414ff56bbSSebastian Ott
951da177e4SLinus Torvalds /*
961da177e4SLinus Torvalds * Timeout function. It just triggers a DEV_EVENT_TIMEOUT.
971da177e4SLinus Torvalds */
98846d0c6fSKees Cook void
ccw_device_timeout(struct timer_list * t)99846d0c6fSKees Cook ccw_device_timeout(struct timer_list *t)
1001da177e4SLinus Torvalds {
101846d0c6fSKees Cook struct ccw_device_private *priv = from_timer(priv, t, timer);
102846d0c6fSKees Cook struct ccw_device *cdev = priv->cdev;
1031da177e4SLinus Torvalds
1041da177e4SLinus Torvalds spin_lock_irq(cdev->ccwlock);
10514ff56bbSSebastian Ott if (timeout_log_enabled)
10614ff56bbSSebastian Ott ccw_timeout_log(cdev);
1071da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_TIMEOUT);
1081da177e4SLinus Torvalds spin_unlock_irq(cdev->ccwlock);
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds /*
1121da177e4SLinus Torvalds * Set timeout
1131da177e4SLinus Torvalds */
1141da177e4SLinus Torvalds void
ccw_device_set_timeout(struct ccw_device * cdev,int expires)1151da177e4SLinus Torvalds ccw_device_set_timeout(struct ccw_device *cdev, int expires)
1161da177e4SLinus Torvalds {
1174f45c37fSYu Liao if (expires == 0)
1181da177e4SLinus Torvalds del_timer(&cdev->private->timer);
1194f45c37fSYu Liao else
1204f45c37fSYu Liao mod_timer(&cdev->private->timer, jiffies + expires);
1211da177e4SLinus Torvalds }
1221da177e4SLinus Torvalds
1231da177e4SLinus Torvalds int
ccw_device_cancel_halt_clear(struct ccw_device * cdev)1241da177e4SLinus Torvalds ccw_device_cancel_halt_clear(struct ccw_device *cdev)
1251da177e4SLinus Torvalds {
1261da177e4SLinus Torvalds struct subchannel *sch;
1271da177e4SLinus Torvalds int ret;
1281da177e4SLinus Torvalds
1291da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
1305434da4dSDong Jia Shi ret = cio_cancel_halt_clear(sch, &cdev->private->iretry);
1315434da4dSDong Jia Shi
1325434da4dSDong Jia Shi if (ret == -EIO)
133376ae475SPeter Oberparleiter CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n",
1345434da4dSDong Jia Shi cdev->private->dev_id.ssid,
1355434da4dSDong Jia Shi cdev->private->dev_id.devno);
1365434da4dSDong Jia Shi
1375434da4dSDong Jia Shi return ret;
1381da177e4SLinus Torvalds }
1391da177e4SLinus Torvalds
ccw_device_update_sense_data(struct ccw_device * cdev)140823d494aSSebastian Ott void ccw_device_update_sense_data(struct ccw_device *cdev)
1411da177e4SLinus Torvalds {
142823d494aSSebastian Ott memset(&cdev->id, 0, sizeof(cdev->id));
14337db8985SHalil Pasic cdev->id.cu_type = cdev->private->dma_area->senseid.cu_type;
14437db8985SHalil Pasic cdev->id.cu_model = cdev->private->dma_area->senseid.cu_model;
14537db8985SHalil Pasic cdev->id.dev_type = cdev->private->dma_area->senseid.dev_type;
14637db8985SHalil Pasic cdev->id.dev_model = cdev->private->dma_area->senseid.dev_model;
1471da177e4SLinus Torvalds }
148823d494aSSebastian Ott
ccw_device_test_sense_data(struct ccw_device * cdev)149823d494aSSebastian Ott int ccw_device_test_sense_data(struct ccw_device *cdev)
150823d494aSSebastian Ott {
15137db8985SHalil Pasic return cdev->id.cu_type ==
15237db8985SHalil Pasic cdev->private->dma_area->senseid.cu_type &&
15337db8985SHalil Pasic cdev->id.cu_model ==
15437db8985SHalil Pasic cdev->private->dma_area->senseid.cu_model &&
15537db8985SHalil Pasic cdev->id.dev_type ==
15637db8985SHalil Pasic cdev->private->dma_area->senseid.dev_type &&
15737db8985SHalil Pasic cdev->id.dev_model ==
15837db8985SHalil Pasic cdev->private->dma_area->senseid.dev_model;
1591da177e4SLinus Torvalds }
1601da177e4SLinus Torvalds
1611da177e4SLinus Torvalds /*
1621da177e4SLinus Torvalds * The machine won't give us any notification by machine check if a chpid has
1631da177e4SLinus Torvalds * been varied online on the SE so we have to find out by magic (i. e. driving
1641da177e4SLinus Torvalds * the channel subsystem to device selection and updating our path masks).
1651da177e4SLinus Torvalds */
1664d284cacSHeiko Carstens static void
__recover_lost_chpids(struct subchannel * sch,int old_lpm)1671da177e4SLinus Torvalds __recover_lost_chpids(struct subchannel *sch, int old_lpm)
1681da177e4SLinus Torvalds {
1691da177e4SLinus Torvalds int mask, i;
170f86635faSPeter Oberparleiter struct chp_id chpid;
1711da177e4SLinus Torvalds
172f86635faSPeter Oberparleiter chp_id_init(&chpid);
1731da177e4SLinus Torvalds for (i = 0; i<8; i++) {
1741da177e4SLinus Torvalds mask = 0x80 >> i;
1751da177e4SLinus Torvalds if (!(sch->lpm & mask))
1761da177e4SLinus Torvalds continue;
1771da177e4SLinus Torvalds if (old_lpm & mask)
1781da177e4SLinus Torvalds continue;
179f86635faSPeter Oberparleiter chpid.id = sch->schib.pmcw.chpid[i];
18083b3370cSPeter Oberparleiter if (!chp_is_registered(chpid))
18183b3370cSPeter Oberparleiter css_schedule_eval_all();
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds }
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds /*
1861da177e4SLinus Torvalds * Stop device recognition.
1871da177e4SLinus Torvalds */
1881da177e4SLinus Torvalds static void
ccw_device_recog_done(struct ccw_device * cdev,int state)1891da177e4SLinus Torvalds ccw_device_recog_done(struct ccw_device *cdev, int state)
1901da177e4SLinus Torvalds {
1911da177e4SLinus Torvalds struct subchannel *sch;
192823d494aSSebastian Ott int old_lpm;
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
1951da177e4SLinus Torvalds
196ec64333cSSebastian Ott if (cio_disable_subchannel(sch))
197ec64333cSSebastian Ott state = DEV_STATE_NOT_OPER;
1981da177e4SLinus Torvalds /*
1991da177e4SLinus Torvalds * Now that we tried recognition, we have performed device selection
2001da177e4SLinus Torvalds * through ssch() and the path information is up to date.
2011da177e4SLinus Torvalds */
2021da177e4SLinus Torvalds old_lpm = sch->lpm;
203cdb912a4SSebastian Ott
2044ffa9234SCornelia Huck /* Check since device may again have become not operational. */
205cdb912a4SSebastian Ott if (cio_update_schib(sch))
2064ffa9234SCornelia Huck state = DEV_STATE_NOT_OPER;
207cdb912a4SSebastian Ott else
208cdb912a4SSebastian Ott sch->lpm = sch->schib.pmcw.pam & sch->opm;
209cdb912a4SSebastian Ott
2101da177e4SLinus Torvalds if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID)
2111da177e4SLinus Torvalds /* Force reprobe on all chpids. */
2121da177e4SLinus Torvalds old_lpm = 0;
2131da177e4SLinus Torvalds if (sch->lpm != old_lpm)
2141da177e4SLinus Torvalds __recover_lost_chpids(sch, old_lpm);
21547593bfaSSebastian Ott if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID &&
21647593bfaSSebastian Ott (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) {
2171da177e4SLinus Torvalds cdev->private->flags.recog_done = 1;
2181da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISCONNECTED;
219156013ffSSebastian Ott wake_up(&cdev->private->wait_q);
2201da177e4SLinus Torvalds return;
2211da177e4SLinus Torvalds }
2221da177e4SLinus Torvalds switch (state) {
2231da177e4SLinus Torvalds case DEV_STATE_NOT_OPER:
2241da177e4SLinus Torvalds break;
2251da177e4SLinus Torvalds case DEV_STATE_OFFLINE:
226823d494aSSebastian Ott if (!cdev->online) {
227823d494aSSebastian Ott ccw_device_update_sense_data(cdev);
2281da177e4SLinus Torvalds break;
229823d494aSSebastian Ott }
230823d494aSSebastian Ott cdev->private->state = DEV_STATE_OFFLINE;
231823d494aSSebastian Ott cdev->private->flags.recog_done = 1;
232823d494aSSebastian Ott if (ccw_device_test_sense_data(cdev)) {
233823d494aSSebastian Ott cdev->private->flags.donotify = 1;
234823d494aSSebastian Ott ccw_device_online(cdev);
235823d494aSSebastian Ott wake_up(&cdev->private->wait_q);
236823d494aSSebastian Ott } else {
237823d494aSSebastian Ott ccw_device_update_sense_data(cdev);
23837de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
239823d494aSSebastian Ott }
240823d494aSSebastian Ott return;
2411da177e4SLinus Torvalds case DEV_STATE_BOXED:
24247593bfaSSebastian Ott if (cdev->id.cu_type != 0) { /* device was recognized before */
24347593bfaSSebastian Ott cdev->private->flags.recog_done = 1;
24447593bfaSSebastian Ott cdev->private->state = DEV_STATE_BOXED;
24547593bfaSSebastian Ott wake_up(&cdev->private->wait_q);
24647593bfaSSebastian Ott return;
24747593bfaSSebastian Ott }
2481da177e4SLinus Torvalds break;
2491da177e4SLinus Torvalds }
2501da177e4SLinus Torvalds cdev->private->state = state;
2511da177e4SLinus Torvalds io_subchannel_recog_done(cdev);
2521da177e4SLinus Torvalds wake_up(&cdev->private->wait_q);
2531da177e4SLinus Torvalds }
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds /*
2561da177e4SLinus Torvalds * Function called from device_id.c after sense id has completed.
2571da177e4SLinus Torvalds */
2581da177e4SLinus Torvalds void
ccw_device_sense_id_done(struct ccw_device * cdev,int err)2591da177e4SLinus Torvalds ccw_device_sense_id_done(struct ccw_device *cdev, int err)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds switch (err) {
2621da177e4SLinus Torvalds case 0:
2631da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_OFFLINE);
2641da177e4SLinus Torvalds break;
2651da177e4SLinus Torvalds case -ETIME: /* Sense id stopped by timeout. */
2661da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_BOXED);
2671da177e4SLinus Torvalds break;
2681da177e4SLinus Torvalds default:
2691da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
2701da177e4SLinus Torvalds break;
2711da177e4SLinus Torvalds }
2721da177e4SLinus Torvalds }
2731da177e4SLinus Torvalds
27476e6fb4bSSebastian Ott /**
27576e6fb4bSSebastian Ott * ccw_device_notify() - inform the device's driver about an event
27625985edcSLucas De Marchi * @cdev: device for which an event occurred
27776e6fb4bSSebastian Ott * @event: event that occurred
27876e6fb4bSSebastian Ott *
27976e6fb4bSSebastian Ott * Returns:
28076e6fb4bSSebastian Ott * -%EINVAL if the device is offline or has no driver.
28176e6fb4bSSebastian Ott * -%EOPNOTSUPP if the device's driver has no notifier registered.
28276e6fb4bSSebastian Ott * %NOTIFY_OK if the driver wants to keep the device.
28376e6fb4bSSebastian Ott * %NOTIFY_BAD if the driver doesn't want to keep the device.
28476e6fb4bSSebastian Ott */
ccw_device_notify(struct ccw_device * cdev,int event)285c820de39SCornelia Huck int ccw_device_notify(struct ccw_device *cdev, int event)
286c820de39SCornelia Huck {
28776e6fb4bSSebastian Ott int ret = -EINVAL;
28876e6fb4bSSebastian Ott
289c820de39SCornelia Huck if (!cdev->drv)
29076e6fb4bSSebastian Ott goto out;
291c820de39SCornelia Huck if (!cdev->online)
29276e6fb4bSSebastian Ott goto out;
29391c36919SPeter Oberparleiter CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n",
29491c36919SPeter Oberparleiter cdev->private->dev_id.ssid, cdev->private->dev_id.devno,
29591c36919SPeter Oberparleiter event);
29676e6fb4bSSebastian Ott if (!cdev->drv->notify) {
29776e6fb4bSSebastian Ott ret = -EOPNOTSUPP;
29876e6fb4bSSebastian Ott goto out;
29976e6fb4bSSebastian Ott }
30076e6fb4bSSebastian Ott if (cdev->drv->notify(cdev, event))
30176e6fb4bSSebastian Ott ret = NOTIFY_OK;
30276e6fb4bSSebastian Ott else
30376e6fb4bSSebastian Ott ret = NOTIFY_BAD;
30476e6fb4bSSebastian Ott out:
30576e6fb4bSSebastian Ott return ret;
306c820de39SCornelia Huck }
307c820de39SCornelia Huck
ccw_device_oper_notify(struct ccw_device * cdev)30891c36919SPeter Oberparleiter static void ccw_device_oper_notify(struct ccw_device *cdev)
30991c36919SPeter Oberparleiter {
310585b954eSSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent);
311585b954eSSebastian Ott
31276e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) {
313*cada938aSHeiko Carstens /* Re-enable channel measurements, if needed. */
31437de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF);
315585b954eSSebastian Ott /* Save indication for new paths. */
316585b954eSSebastian Ott cdev->private->path_new_mask = sch->vpm;
31791c36919SPeter Oberparleiter return;
31891c36919SPeter Oberparleiter }
3191da177e4SLinus Torvalds /* Driver doesn't want device back. */
32091c36919SPeter Oberparleiter ccw_device_set_notoper(cdev);
32137de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_REBIND);
32294bb0633SCornelia Huck }
3231da177e4SLinus Torvalds
3241da177e4SLinus Torvalds /*
3251da177e4SLinus Torvalds * Finished with online/offline processing.
3261da177e4SLinus Torvalds */
3271da177e4SLinus Torvalds static void
ccw_device_done(struct ccw_device * cdev,int state)3281da177e4SLinus Torvalds ccw_device_done(struct ccw_device *cdev, int state)
3291da177e4SLinus Torvalds {
3301da177e4SLinus Torvalds struct subchannel *sch;
3311da177e4SLinus Torvalds
3321da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
3331da177e4SLinus Torvalds
334f1ee3281SCornelia Huck ccw_device_set_timeout(cdev, 0);
335f1ee3281SCornelia Huck
3361da177e4SLinus Torvalds if (state != DEV_STATE_ONLINE)
3371da177e4SLinus Torvalds cio_disable_subchannel(sch);
3381da177e4SLinus Torvalds
3391da177e4SLinus Torvalds /* Reset device status. */
34037db8985SHalil Pasic memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
3411da177e4SLinus Torvalds
3421da177e4SLinus Torvalds cdev->private->state = state;
3431da177e4SLinus Torvalds
3449a332116SPeter Oberparleiter switch (state) {
3459a332116SPeter Oberparleiter case DEV_STATE_BOXED:
346139b83ddSMichael Ernst CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n",
34778964268SCornelia Huck cdev->private->dev_id.devno, sch->schid.sch_no);
34876e6fb4bSSebastian Ott if (cdev->online &&
34976e6fb4bSSebastian Ott ccw_device_notify(cdev, CIO_BOXED) != NOTIFY_OK)
35037de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
35147593bfaSSebastian Ott cdev->private->flags.donotify = 0;
3529a332116SPeter Oberparleiter break;
3539a332116SPeter Oberparleiter case DEV_STATE_NOT_OPER:
354626e476aSSebastian Ott CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n",
355626e476aSSebastian Ott cdev->private->dev_id.devno, sch->schid.sch_no);
35676e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
35737de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
3586afcc775SPeter Oberparleiter else
3596afcc775SPeter Oberparleiter ccw_device_set_disconnected(cdev);
360626e476aSSebastian Ott cdev->private->flags.donotify = 0;
3619a332116SPeter Oberparleiter break;
3629a332116SPeter Oberparleiter case DEV_STATE_DISCONNECTED:
3639a332116SPeter Oberparleiter CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel "
3649a332116SPeter Oberparleiter "%04x\n", cdev->private->dev_id.devno,
3659a332116SPeter Oberparleiter sch->schid.sch_no);
3669bf05098SSebastian Ott if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) {
3679bf05098SSebastian Ott cdev->private->state = DEV_STATE_NOT_OPER;
36837de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
3699bf05098SSebastian Ott } else
3709a332116SPeter Oberparleiter ccw_device_set_disconnected(cdev);
3719a332116SPeter Oberparleiter cdev->private->flags.donotify = 0;
3729a332116SPeter Oberparleiter break;
3739a332116SPeter Oberparleiter default:
3749a332116SPeter Oberparleiter break;
375626e476aSSebastian Ott }
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvalds if (cdev->private->flags.donotify) {
3781da177e4SLinus Torvalds cdev->private->flags.donotify = 0;
37991c36919SPeter Oberparleiter ccw_device_oper_notify(cdev);
3801da177e4SLinus Torvalds }
3811da177e4SLinus Torvalds wake_up(&cdev->private->wait_q);
3821da177e4SLinus Torvalds }
3831da177e4SLinus Torvalds
3841da177e4SLinus Torvalds /*
3851da177e4SLinus Torvalds * Start device recognition.
3861da177e4SLinus Torvalds */
ccw_device_recognition(struct ccw_device * cdev)387736b5db8SPeter Oberparleiter void ccw_device_recognition(struct ccw_device *cdev)
3881da177e4SLinus Torvalds {
389736b5db8SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent);
3901da177e4SLinus Torvalds
3911da177e4SLinus Torvalds /*
3921da177e4SLinus Torvalds * We used to start here with a sense pgid to find out whether a device
3931da177e4SLinus Torvalds * is locked by someone else. Unfortunately, the sense pgid command
3941da177e4SLinus Torvalds * code has other meanings on devices predating the path grouping
3951da177e4SLinus Torvalds * algorithm, so we start with sense id and box the device after an
3961da177e4SLinus Torvalds * timeout (or if sense pgid during path verification detects the device
3971da177e4SLinus Torvalds * is locked, as may happen on newer devices).
3981da177e4SLinus Torvalds */
3991da177e4SLinus Torvalds cdev->private->flags.recog_done = 0;
4001da177e4SLinus Torvalds cdev->private->state = DEV_STATE_SENSE_ID;
4015c2e5a0cSAlexander Gordeev if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch))) {
402736b5db8SPeter Oberparleiter ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER);
403736b5db8SPeter Oberparleiter return;
404736b5db8SPeter Oberparleiter }
4051da177e4SLinus Torvalds ccw_device_sense_id_start(cdev);
4061da177e4SLinus Torvalds }
4071da177e4SLinus Torvalds
4081da177e4SLinus Torvalds /*
40939f5360bSPeter Oberparleiter * Handle events for states that use the ccw request infrastructure.
4101da177e4SLinus Torvalds */
ccw_device_request_event(struct ccw_device * cdev,enum dev_event e)41139f5360bSPeter Oberparleiter static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e)
4121da177e4SLinus Torvalds {
41339f5360bSPeter Oberparleiter switch (e) {
41439f5360bSPeter Oberparleiter case DEV_EVENT_NOTOPER:
41539f5360bSPeter Oberparleiter ccw_request_notoper(cdev);
4161da177e4SLinus Torvalds break;
41739f5360bSPeter Oberparleiter case DEV_EVENT_INTERRUPT:
41839f5360bSPeter Oberparleiter ccw_request_handler(cdev);
41939f5360bSPeter Oberparleiter break;
42039f5360bSPeter Oberparleiter case DEV_EVENT_TIMEOUT:
42139f5360bSPeter Oberparleiter ccw_request_timeout(cdev);
4221da177e4SLinus Torvalds break;
4231da177e4SLinus Torvalds default:
42439f5360bSPeter Oberparleiter break;
4251da177e4SLinus Torvalds }
4261da177e4SLinus Torvalds }
4271da177e4SLinus Torvalds
ccw_device_report_path_events(struct ccw_device * cdev)428585b954eSSebastian Ott static void ccw_device_report_path_events(struct ccw_device *cdev)
429585b954eSSebastian Ott {
430585b954eSSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent);
431585b954eSSebastian Ott int path_event[8];
432585b954eSSebastian Ott int chp, mask;
433585b954eSSebastian Ott
434585b954eSSebastian Ott for (chp = 0, mask = 0x80; chp < 8; chp++, mask >>= 1) {
435585b954eSSebastian Ott path_event[chp] = PE_NONE;
436585b954eSSebastian Ott if (mask & cdev->private->path_gone_mask & ~(sch->vpm))
437585b954eSSebastian Ott path_event[chp] |= PE_PATH_GONE;
438585b954eSSebastian Ott if (mask & cdev->private->path_new_mask & sch->vpm)
439585b954eSSebastian Ott path_event[chp] |= PE_PATH_AVAILABLE;
440585b954eSSebastian Ott if (mask & cdev->private->pgid_reset_mask & sch->vpm)
441585b954eSSebastian Ott path_event[chp] |= PE_PATHGROUP_ESTABLISHED;
442585b954eSSebastian Ott }
443585b954eSSebastian Ott if (cdev->online && cdev->drv->path_event)
444585b954eSSebastian Ott cdev->drv->path_event(cdev, path_event);
445585b954eSSebastian Ott }
446585b954eSSebastian Ott
ccw_device_reset_path_events(struct ccw_device * cdev)447585b954eSSebastian Ott static void ccw_device_reset_path_events(struct ccw_device *cdev)
448585b954eSSebastian Ott {
449585b954eSSebastian Ott cdev->private->path_gone_mask = 0;
450585b954eSSebastian Ott cdev->private->path_new_mask = 0;
451585b954eSSebastian Ott cdev->private->pgid_reset_mask = 0;
452585b954eSSebastian Ott }
453585b954eSSebastian Ott
create_fake_irb(struct irb * irb,int type)45450c8e31fSSebastian Ott static void create_fake_irb(struct irb *irb, int type)
45550c8e31fSSebastian Ott {
45650c8e31fSSebastian Ott memset(irb, 0, sizeof(*irb));
45750c8e31fSSebastian Ott if (type == FAKE_CMD_IRB) {
45850c8e31fSSebastian Ott struct cmd_scsw *scsw = &irb->scsw.cmd;
45950c8e31fSSebastian Ott scsw->cc = 1;
46050c8e31fSSebastian Ott scsw->fctl = SCSW_FCTL_START_FUNC;
46150c8e31fSSebastian Ott scsw->actl = SCSW_ACTL_START_PEND;
46250c8e31fSSebastian Ott scsw->stctl = SCSW_STCTL_STATUS_PEND;
46350c8e31fSSebastian Ott } else if (type == FAKE_TM_IRB) {
46450c8e31fSSebastian Ott struct tm_scsw *scsw = &irb->scsw.tm;
46550c8e31fSSebastian Ott scsw->x = 1;
46650c8e31fSSebastian Ott scsw->cc = 1;
46750c8e31fSSebastian Ott scsw->fctl = SCSW_FCTL_START_FUNC;
46850c8e31fSSebastian Ott scsw->actl = SCSW_ACTL_START_PEND;
46950c8e31fSSebastian Ott scsw->stctl = SCSW_STCTL_STATUS_PEND;
47050c8e31fSSebastian Ott }
47150c8e31fSSebastian Ott }
47250c8e31fSSebastian Ott
ccw_device_handle_broken_paths(struct ccw_device * cdev)47355fb7347SSebastian Ott static void ccw_device_handle_broken_paths(struct ccw_device *cdev)
47455fb7347SSebastian Ott {
47555fb7347SSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent);
47655fb7347SSebastian Ott u8 broken_paths = (sch->schib.pmcw.pam & sch->opm) ^ sch->vpm;
47755fb7347SSebastian Ott
47855fb7347SSebastian Ott if (broken_paths && (cdev->private->path_broken_mask != broken_paths))
47955fb7347SSebastian Ott ccw_device_schedule_recovery();
48055fb7347SSebastian Ott
48155fb7347SSebastian Ott cdev->private->path_broken_mask = broken_paths;
48255fb7347SSebastian Ott }
48355fb7347SSebastian Ott
ccw_device_verify_done(struct ccw_device * cdev,int err)48450c8e31fSSebastian Ott void ccw_device_verify_done(struct ccw_device *cdev, int err)
4851da177e4SLinus Torvalds {
48628bdc6f6SPeter Oberparleiter struct subchannel *sch;
48728bdc6f6SPeter Oberparleiter
48828bdc6f6SPeter Oberparleiter sch = to_subchannel(cdev->dev.parent);
48928bdc6f6SPeter Oberparleiter /* Update schib - pom may have changed. */
490cdb912a4SSebastian Ott if (cio_update_schib(sch)) {
4917c4d964fSPeter Oberparleiter err = -ENODEV;
4927c4d964fSPeter Oberparleiter goto callback;
493cdb912a4SSebastian Ott }
49428bdc6f6SPeter Oberparleiter /* Update lpm with verified path mask. */
49528bdc6f6SPeter Oberparleiter sch->lpm = sch->vpm;
49628bdc6f6SPeter Oberparleiter /* Repeat path verification? */
49728bdc6f6SPeter Oberparleiter if (cdev->private->flags.doverify) {
49828bdc6f6SPeter Oberparleiter ccw_device_verify_start(cdev);
49928bdc6f6SPeter Oberparleiter return;
50028bdc6f6SPeter Oberparleiter }
5017c4d964fSPeter Oberparleiter callback:
5021da177e4SLinus Torvalds switch (err) {
5031da177e4SLinus Torvalds case 0:
5041da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_ONLINE);
5051da177e4SLinus Torvalds /* Deliver fake irb to device driver, if needed. */
5061da177e4SLinus Torvalds if (cdev->private->flags.fake_irb) {
50737db8985SHalil Pasic create_fake_irb(&cdev->private->dma_area->irb,
50850c8e31fSSebastian Ott cdev->private->flags.fake_irb);
5091da177e4SLinus Torvalds cdev->private->flags.fake_irb = 0;
5101da177e4SLinus Torvalds if (cdev->handler)
5111da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm,
51237db8985SHalil Pasic &cdev->private->dma_area->irb);
51337db8985SHalil Pasic memset(&cdev->private->dma_area->irb, 0,
51437db8985SHalil Pasic sizeof(struct irb));
5151da177e4SLinus Torvalds }
516585b954eSSebastian Ott ccw_device_report_path_events(cdev);
51755fb7347SSebastian Ott ccw_device_handle_broken_paths(cdev);
5181da177e4SLinus Torvalds break;
5191da177e4SLinus Torvalds case -ETIME:
52052ef0608SPeter Oberparleiter case -EUSERS:
5218b42f5c2SPeter Oberparleiter /* Reset oper notify indication after verify error. */
5228b42f5c2SPeter Oberparleiter cdev->private->flags.donotify = 0;
5231da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_BOXED);
5241da177e4SLinus Torvalds break;
5257c4d964fSPeter Oberparleiter case -EACCES:
5267c4d964fSPeter Oberparleiter /* Reset oper notify indication after verify error. */
5277c4d964fSPeter Oberparleiter cdev->private->flags.donotify = 0;
5287c4d964fSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_DISCONNECTED);
5297c4d964fSPeter Oberparleiter break;
5301da177e4SLinus Torvalds default:
5318b42f5c2SPeter Oberparleiter /* Reset oper notify indication after verify error. */
5328b42f5c2SPeter Oberparleiter cdev->private->flags.donotify = 0;
5331da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_NOT_OPER);
5341da177e4SLinus Torvalds break;
5351da177e4SLinus Torvalds }
536585b954eSSebastian Ott ccw_device_reset_path_events(cdev);
5371da177e4SLinus Torvalds }
5381da177e4SLinus Torvalds
5391da177e4SLinus Torvalds /*
5401da177e4SLinus Torvalds * Get device online.
5411da177e4SLinus Torvalds */
5421da177e4SLinus Torvalds int
ccw_device_online(struct ccw_device * cdev)5431da177e4SLinus Torvalds ccw_device_online(struct ccw_device *cdev)
5441da177e4SLinus Torvalds {
5451da177e4SLinus Torvalds struct subchannel *sch;
5461da177e4SLinus Torvalds int ret;
5471da177e4SLinus Torvalds
5481da177e4SLinus Torvalds if ((cdev->private->state != DEV_STATE_OFFLINE) &&
5491da177e4SLinus Torvalds (cdev->private->state != DEV_STATE_BOXED))
5501da177e4SLinus Torvalds return -EINVAL;
5511da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
5525c2e5a0cSAlexander Gordeev ret = cio_enable_subchannel(sch, (u32)virt_to_phys(sch));
5531da177e4SLinus Torvalds if (ret != 0) {
5541da177e4SLinus Torvalds /* Couldn't enable the subchannel for i/o. Sick device. */
5551da177e4SLinus Torvalds if (ret == -ENODEV)
5561da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
5571da177e4SLinus Torvalds return ret;
5581da177e4SLinus Torvalds }
5597e560814SCornelia Huck /* Start initial path verification. */
5607e560814SCornelia Huck cdev->private->state = DEV_STATE_VERIFY;
5617e560814SCornelia Huck ccw_device_verify_start(cdev);
5621da177e4SLinus Torvalds return 0;
5631da177e4SLinus Torvalds }
5641da177e4SLinus Torvalds
5651da177e4SLinus Torvalds void
ccw_device_disband_done(struct ccw_device * cdev,int err)5661da177e4SLinus Torvalds ccw_device_disband_done(struct ccw_device *cdev, int err)
5671da177e4SLinus Torvalds {
5681da177e4SLinus Torvalds switch (err) {
5691da177e4SLinus Torvalds case 0:
5701da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_OFFLINE);
5711da177e4SLinus Torvalds break;
5721da177e4SLinus Torvalds case -ETIME:
5731da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_BOXED);
5741da177e4SLinus Torvalds break;
5751da177e4SLinus Torvalds default:
5763ecb0a5aSPeter Oberparleiter cdev->private->flags.donotify = 0;
5771da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_NOT_OPER);
5781da177e4SLinus Torvalds break;
5791da177e4SLinus Torvalds }
5801da177e4SLinus Torvalds }
5811da177e4SLinus Torvalds
5821da177e4SLinus Torvalds /*
5831da177e4SLinus Torvalds * Shutdown device.
5841da177e4SLinus Torvalds */
5851da177e4SLinus Torvalds int
ccw_device_offline(struct ccw_device * cdev)5861da177e4SLinus Torvalds ccw_device_offline(struct ccw_device *cdev)
5871da177e4SLinus Torvalds {
5881da177e4SLinus Torvalds struct subchannel *sch;
5891da177e4SLinus Torvalds
590b301ea8cSPeter Oberparleiter /* Allow ccw_device_offline while disconnected. */
591b301ea8cSPeter Oberparleiter if (cdev->private->state == DEV_STATE_DISCONNECTED ||
592b301ea8cSPeter Oberparleiter cdev->private->state == DEV_STATE_NOT_OPER) {
593b301ea8cSPeter Oberparleiter cdev->private->flags.donotify = 0;
594b301ea8cSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_NOT_OPER);
595b301ea8cSPeter Oberparleiter return 0;
596b301ea8cSPeter Oberparleiter }
597102e835dSPeter Oberparleiter if (cdev->private->state == DEV_STATE_BOXED) {
598102e835dSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_BOXED);
599102e835dSPeter Oberparleiter return 0;
600102e835dSPeter Oberparleiter }
601d7b5a4c9SCornelia Huck if (ccw_device_is_orphan(cdev)) {
602d7b5a4c9SCornelia Huck ccw_device_done(cdev, DEV_STATE_OFFLINE);
603d7b5a4c9SCornelia Huck return 0;
604d7b5a4c9SCornelia Huck }
6051da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
606cdb912a4SSebastian Ott if (cio_update_schib(sch))
6071da177e4SLinus Torvalds return -ENODEV;
60823d805b6SPeter Oberparleiter if (scsw_actl(&sch->schib.scsw) != 0)
6091da177e4SLinus Torvalds return -EBUSY;
61023d805b6SPeter Oberparleiter if (cdev->private->state != DEV_STATE_ONLINE)
6111da177e4SLinus Torvalds return -EINVAL;
6121da177e4SLinus Torvalds /* Are we doing path grouping? */
613454e1fa1SPeter Oberparleiter if (!cdev->private->flags.pgroup) {
6141da177e4SLinus Torvalds /* No, set state offline immediately. */
6151da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_OFFLINE);
6161da177e4SLinus Torvalds return 0;
6171da177e4SLinus Torvalds }
6181da177e4SLinus Torvalds /* Start Set Path Group commands. */
6191da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISBAND_PGID;
6201da177e4SLinus Torvalds ccw_device_disband_start(cdev);
6211da177e4SLinus Torvalds return 0;
6221da177e4SLinus Torvalds }
6231da177e4SLinus Torvalds
6241da177e4SLinus Torvalds /*
6253f4cf6e7SCornelia Huck * Handle not operational event in non-special state.
6261da177e4SLinus Torvalds */
ccw_device_generic_notoper(struct ccw_device * cdev,enum dev_event dev_event)6273f4cf6e7SCornelia Huck static void ccw_device_generic_notoper(struct ccw_device *cdev,
6283f4cf6e7SCornelia Huck enum dev_event dev_event)
6291da177e4SLinus Torvalds {
63076e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK)
63137de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG);
6326afcc775SPeter Oberparleiter else
6336afcc775SPeter Oberparleiter ccw_device_set_disconnected(cdev);
6341da177e4SLinus Torvalds }
6351da177e4SLinus Torvalds
6361da177e4SLinus Torvalds /*
6371f1148c8SPeter Oberparleiter * Handle path verification event in offline state.
6381f1148c8SPeter Oberparleiter */
ccw_device_offline_verify(struct ccw_device * cdev,enum dev_event dev_event)6391f1148c8SPeter Oberparleiter static void ccw_device_offline_verify(struct ccw_device *cdev,
6401f1148c8SPeter Oberparleiter enum dev_event dev_event)
6411f1148c8SPeter Oberparleiter {
6421f1148c8SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent);
6431f1148c8SPeter Oberparleiter
6441f1148c8SPeter Oberparleiter css_schedule_eval(sch->schid);
6451f1148c8SPeter Oberparleiter }
6461f1148c8SPeter Oberparleiter
6471f1148c8SPeter Oberparleiter /*
6481da177e4SLinus Torvalds * Handle path verification event.
6491da177e4SLinus Torvalds */
6501da177e4SLinus Torvalds static void
ccw_device_online_verify(struct ccw_device * cdev,enum dev_event dev_event)6511da177e4SLinus Torvalds ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event)
6521da177e4SLinus Torvalds {
6531da177e4SLinus Torvalds struct subchannel *sch;
6541da177e4SLinus Torvalds
6551da177e4SLinus Torvalds if (cdev->private->state == DEV_STATE_W4SENSE) {
6561da177e4SLinus Torvalds cdev->private->flags.doverify = 1;
6571da177e4SLinus Torvalds return;
6581da177e4SLinus Torvalds }
6591da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
6601da177e4SLinus Torvalds /*
6611da177e4SLinus Torvalds * Since we might not just be coming from an interrupt from the
6621da177e4SLinus Torvalds * subchannel we have to update the schib.
6631da177e4SLinus Torvalds */
664cdb912a4SSebastian Ott if (cio_update_schib(sch)) {
665cdb912a4SSebastian Ott ccw_device_verify_done(cdev, -ENODEV);
666cdb912a4SSebastian Ott return;
667cdb912a4SSebastian Ott }
6681da177e4SLinus Torvalds
66923d805b6SPeter Oberparleiter if (scsw_actl(&sch->schib.scsw) != 0 ||
67023d805b6SPeter Oberparleiter (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) ||
67137db8985SHalil Pasic (scsw_stctl(&cdev->private->dma_area->irb.scsw) &
67237db8985SHalil Pasic SCSW_STCTL_STATUS_PEND)) {
6731da177e4SLinus Torvalds /*
6741da177e4SLinus Torvalds * No final status yet or final status not yet delivered
67525985edcSLucas De Marchi * to the device driver. Can't do path verification now,
6761da177e4SLinus Torvalds * delay until final status was delivered.
6771da177e4SLinus Torvalds */
6781da177e4SLinus Torvalds cdev->private->flags.doverify = 1;
6791da177e4SLinus Torvalds return;
6801da177e4SLinus Torvalds }
6811da177e4SLinus Torvalds /* Device is idle, we can do the path verification. */
6821da177e4SLinus Torvalds cdev->private->state = DEV_STATE_VERIFY;
6831da177e4SLinus Torvalds ccw_device_verify_start(cdev);
6841da177e4SLinus Torvalds }
6851da177e4SLinus Torvalds
6861da177e4SLinus Torvalds /*
687d7d12ef2SPeter Oberparleiter * Handle path verification event in boxed state.
688d7d12ef2SPeter Oberparleiter */
ccw_device_boxed_verify(struct ccw_device * cdev,enum dev_event dev_event)689d7d12ef2SPeter Oberparleiter static void ccw_device_boxed_verify(struct ccw_device *cdev,
690d7d12ef2SPeter Oberparleiter enum dev_event dev_event)
691d7d12ef2SPeter Oberparleiter {
692d7d12ef2SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent);
693d7d12ef2SPeter Oberparleiter
694d7d12ef2SPeter Oberparleiter if (cdev->online) {
6955c2e5a0cSAlexander Gordeev if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)))
696d7d12ef2SPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_NOT_OPER);
697d7d12ef2SPeter Oberparleiter else
698d7d12ef2SPeter Oberparleiter ccw_device_online_verify(cdev, dev_event);
699d7d12ef2SPeter Oberparleiter } else
700d7d12ef2SPeter Oberparleiter css_schedule_eval(sch->schid);
701d7d12ef2SPeter Oberparleiter }
702d7d12ef2SPeter Oberparleiter
703d7d12ef2SPeter Oberparleiter /*
7048421d212SSebastian Ott * Pass interrupt to device driver.
7058421d212SSebastian Ott */
ccw_device_call_handler(struct ccw_device * cdev)7068421d212SSebastian Ott static int ccw_device_call_handler(struct ccw_device *cdev)
7078421d212SSebastian Ott {
7088421d212SSebastian Ott unsigned int stctl;
7098421d212SSebastian Ott int ending_status;
7108421d212SSebastian Ott
7118421d212SSebastian Ott /*
7128421d212SSebastian Ott * we allow for the device action handler if .
7138421d212SSebastian Ott * - we received ending status
7148421d212SSebastian Ott * - the action handler requested to see all interrupts
7158421d212SSebastian Ott * - we received an intermediate status
7168421d212SSebastian Ott * - fast notification was requested (primary status)
7178421d212SSebastian Ott * - unsolicited interrupts
7188421d212SSebastian Ott */
71937db8985SHalil Pasic stctl = scsw_stctl(&cdev->private->dma_area->irb.scsw);
7208421d212SSebastian Ott ending_status = (stctl & SCSW_STCTL_SEC_STATUS) ||
7218421d212SSebastian Ott (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) ||
7228421d212SSebastian Ott (stctl == SCSW_STCTL_STATUS_PEND);
7238421d212SSebastian Ott if (!ending_status &&
7248421d212SSebastian Ott !cdev->private->options.repall &&
7258421d212SSebastian Ott !(stctl & SCSW_STCTL_INTER_STATUS) &&
7268421d212SSebastian Ott !(cdev->private->options.fast &&
7278421d212SSebastian Ott (stctl & SCSW_STCTL_PRIM_STATUS)))
7288421d212SSebastian Ott return 0;
7298421d212SSebastian Ott
7308421d212SSebastian Ott if (ending_status)
7318421d212SSebastian Ott ccw_device_set_timeout(cdev, 0);
7328421d212SSebastian Ott
7338421d212SSebastian Ott if (cdev->handler)
7348421d212SSebastian Ott cdev->handler(cdev, cdev->private->intparm,
73537db8985SHalil Pasic &cdev->private->dma_area->irb);
7368421d212SSebastian Ott
73737db8985SHalil Pasic memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
7388421d212SSebastian Ott return 1;
7398421d212SSebastian Ott }
7408421d212SSebastian Ott
7418421d212SSebastian Ott /*
7421da177e4SLinus Torvalds * Got an interrupt for a normal io (state online).
7431da177e4SLinus Torvalds */
7441da177e4SLinus Torvalds static void
ccw_device_irq(struct ccw_device * cdev,enum dev_event dev_event)7451da177e4SLinus Torvalds ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event)
7461da177e4SLinus Torvalds {
7471da177e4SLinus Torvalds struct irb *irb;
74883262d63SPeter Oberparleiter int is_cmd;
7491da177e4SLinus Torvalds
7500bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb);
75183262d63SPeter Oberparleiter is_cmd = !scsw_is_tm(&irb->scsw);
7521da177e4SLinus Torvalds /* Check for unsolicited interrupt. */
75323d805b6SPeter Oberparleiter if (!scsw_is_solicited(&irb->scsw)) {
75483262d63SPeter Oberparleiter if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) &&
7551da177e4SLinus Torvalds !irb->esw.esw0.erw.cons) {
7561da177e4SLinus Torvalds /* Unit check but no sense data. Need basic sense. */
7571da177e4SLinus Torvalds if (ccw_device_do_sense(cdev, irb) != 0)
7581da177e4SLinus Torvalds goto call_handler_unsol;
75937db8985SHalil Pasic memcpy(&cdev->private->dma_area->irb, irb,
76037db8985SHalil Pasic sizeof(struct irb));
7611da177e4SLinus Torvalds cdev->private->state = DEV_STATE_W4SENSE;
7621da177e4SLinus Torvalds cdev->private->intparm = 0;
7631da177e4SLinus Torvalds return;
7641da177e4SLinus Torvalds }
7651da177e4SLinus Torvalds call_handler_unsol:
7661da177e4SLinus Torvalds if (cdev->handler)
7671da177e4SLinus Torvalds cdev->handler (cdev, 0, irb);
76818374d37SCornelia Huck if (cdev->private->flags.doverify)
76918374d37SCornelia Huck ccw_device_online_verify(cdev, 0);
7701da177e4SLinus Torvalds return;
7711da177e4SLinus Torvalds }
7721da177e4SLinus Torvalds /* Accumulate status and find out if a basic sense is needed. */
7731da177e4SLinus Torvalds ccw_device_accumulate_irb(cdev, irb);
77483262d63SPeter Oberparleiter if (is_cmd && cdev->private->flags.dosense) {
7751da177e4SLinus Torvalds if (ccw_device_do_sense(cdev, irb) == 0) {
7761da177e4SLinus Torvalds cdev->private->state = DEV_STATE_W4SENSE;
7771da177e4SLinus Torvalds }
7781da177e4SLinus Torvalds return;
7791da177e4SLinus Torvalds }
7801da177e4SLinus Torvalds /* Call the handler. */
7811da177e4SLinus Torvalds if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
7821da177e4SLinus Torvalds /* Start delayed path verification. */
7831da177e4SLinus Torvalds ccw_device_online_verify(cdev, 0);
7841da177e4SLinus Torvalds }
7851da177e4SLinus Torvalds
7861da177e4SLinus Torvalds /*
7871da177e4SLinus Torvalds * Got an timeout in online state.
7881da177e4SLinus Torvalds */
7891da177e4SLinus Torvalds static void
ccw_device_online_timeout(struct ccw_device * cdev,enum dev_event dev_event)7901da177e4SLinus Torvalds ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event)
7911da177e4SLinus Torvalds {
7921da177e4SLinus Torvalds int ret;
7931da177e4SLinus Torvalds
7941da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0);
795376ae475SPeter Oberparleiter cdev->private->iretry = 255;
796770b55c9SSebastian Ott cdev->private->async_kill_io_rc = -ETIMEDOUT;
7971da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev);
7981da177e4SLinus Torvalds if (ret == -EBUSY) {
7991da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ);
8001da177e4SLinus Torvalds cdev->private->state = DEV_STATE_TIMEOUT_KILL;
8011da177e4SLinus Torvalds return;
8021da177e4SLinus Torvalds }
803376ae475SPeter Oberparleiter if (ret)
8041da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_NOTOPER);
8053f4cf6e7SCornelia Huck else if (cdev->handler)
8061da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm,
8071da177e4SLinus Torvalds ERR_PTR(-ETIMEDOUT));
8081da177e4SLinus Torvalds }
8091da177e4SLinus Torvalds
8101da177e4SLinus Torvalds /*
8111da177e4SLinus Torvalds * Got an interrupt for a basic sense.
8121da177e4SLinus Torvalds */
8132b67fc46SHeiko Carstens static void
ccw_device_w4sense(struct ccw_device * cdev,enum dev_event dev_event)8141da177e4SLinus Torvalds ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event)
8151da177e4SLinus Torvalds {
8161da177e4SLinus Torvalds struct irb *irb;
8171da177e4SLinus Torvalds
8180bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb);
8191da177e4SLinus Torvalds /* Check for unsolicited interrupt. */
82023d805b6SPeter Oberparleiter if (scsw_stctl(&irb->scsw) ==
8211da177e4SLinus Torvalds (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) {
82223d805b6SPeter Oberparleiter if (scsw_cc(&irb->scsw) == 1)
8231da177e4SLinus Torvalds /* Basic sense hasn't started. Try again. */
8241da177e4SLinus Torvalds ccw_device_do_sense(cdev, irb);
8251da177e4SLinus Torvalds else {
826139b83ddSMichael Ernst CIO_MSG_EVENT(0, "0.%x.%04x: unsolicited "
827e556bbbdSCornelia Huck "interrupt during w4sense...\n",
828e556bbbdSCornelia Huck cdev->private->dev_id.ssid,
829e556bbbdSCornelia Huck cdev->private->dev_id.devno);
8301da177e4SLinus Torvalds if (cdev->handler)
8311da177e4SLinus Torvalds cdev->handler (cdev, 0, irb);
8321da177e4SLinus Torvalds }
8331da177e4SLinus Torvalds return;
8341da177e4SLinus Torvalds }
8353ba1998eSCornelia Huck /*
8363ba1998eSCornelia Huck * Check if a halt or clear has been issued in the meanwhile. If yes,
8373ba1998eSCornelia Huck * only deliver the halt/clear interrupt to the device driver as if it
8383ba1998eSCornelia Huck * had killed the original request.
8393ba1998eSCornelia Huck */
84023d805b6SPeter Oberparleiter if (scsw_fctl(&irb->scsw) &
84123d805b6SPeter Oberparleiter (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) {
8423ba1998eSCornelia Huck cdev->private->flags.dosense = 0;
84337db8985SHalil Pasic memset(&cdev->private->dma_area->irb, 0, sizeof(struct irb));
8443ba1998eSCornelia Huck ccw_device_accumulate_irb(cdev, irb);
8453ba1998eSCornelia Huck goto call_handler;
8463ba1998eSCornelia Huck }
8471da177e4SLinus Torvalds /* Add basic sense info to irb. */
8481da177e4SLinus Torvalds ccw_device_accumulate_basic_sense(cdev, irb);
8491da177e4SLinus Torvalds if (cdev->private->flags.dosense) {
8501da177e4SLinus Torvalds /* Another basic sense is needed. */
8511da177e4SLinus Torvalds ccw_device_do_sense(cdev, irb);
8521da177e4SLinus Torvalds return;
8531da177e4SLinus Torvalds }
8543ba1998eSCornelia Huck call_handler:
8551da177e4SLinus Torvalds cdev->private->state = DEV_STATE_ONLINE;
856217ee6c6SMichael Ernst /* In case sensing interfered with setting the device online */
857217ee6c6SMichael Ernst wake_up(&cdev->private->wait_q);
8581da177e4SLinus Torvalds /* Call the handler. */
8591da177e4SLinus Torvalds if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify)
8601da177e4SLinus Torvalds /* Start delayed path verification. */
8611da177e4SLinus Torvalds ccw_device_online_verify(cdev, 0);
8621da177e4SLinus Torvalds }
8631da177e4SLinus Torvalds
8641da177e4SLinus Torvalds static void
ccw_device_killing_irq(struct ccw_device * cdev,enum dev_event dev_event)8651da177e4SLinus Torvalds ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event)
8661da177e4SLinus Torvalds {
8671da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0);
8687c8427c3SCornelia Huck /* Start delayed path verification. */
8697c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0);
8701da177e4SLinus Torvalds /* OK, i/o is dead now. Call interrupt handler. */
8711da177e4SLinus Torvalds if (cdev->handler)
8721da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm,
873770b55c9SSebastian Ott ERR_PTR(cdev->private->async_kill_io_rc));
8741da177e4SLinus Torvalds }
8751da177e4SLinus Torvalds
8761da177e4SLinus Torvalds static void
ccw_device_killing_timeout(struct ccw_device * cdev,enum dev_event dev_event)8771da177e4SLinus Torvalds ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event)
8781da177e4SLinus Torvalds {
8791da177e4SLinus Torvalds int ret;
8801da177e4SLinus Torvalds
8811da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev);
8821da177e4SLinus Torvalds if (ret == -EBUSY) {
8831da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ);
8841da177e4SLinus Torvalds return;
8851da177e4SLinus Torvalds }
8867c8427c3SCornelia Huck /* Start delayed path verification. */
8877c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0);
8881da177e4SLinus Torvalds if (cdev->handler)
8891da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm,
890770b55c9SSebastian Ott ERR_PTR(cdev->private->async_kill_io_rc));
8911da177e4SLinus Torvalds }
8921da177e4SLinus Torvalds
ccw_device_kill_io(struct ccw_device * cdev)893c820de39SCornelia Huck void ccw_device_kill_io(struct ccw_device *cdev)
8941da177e4SLinus Torvalds {
8951da177e4SLinus Torvalds int ret;
8961da177e4SLinus Torvalds
897410d5e13SSebastian Ott ccw_device_set_timeout(cdev, 0);
898376ae475SPeter Oberparleiter cdev->private->iretry = 255;
899770b55c9SSebastian Ott cdev->private->async_kill_io_rc = -EIO;
9001da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev);
9011da177e4SLinus Torvalds if (ret == -EBUSY) {
9021da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ);
9031da177e4SLinus Torvalds cdev->private->state = DEV_STATE_TIMEOUT_KILL;
9041da177e4SLinus Torvalds return;
9051da177e4SLinus Torvalds }
9067c8427c3SCornelia Huck /* Start delayed path verification. */
9077c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0);
9081da177e4SLinus Torvalds if (cdev->handler)
9091da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm,
910e7769b48SCornelia Huck ERR_PTR(-EIO));
9111da177e4SLinus Torvalds }
9121da177e4SLinus Torvalds
9131da177e4SLinus Torvalds static void
ccw_device_delay_verify(struct ccw_device * cdev,enum dev_event dev_event)91428bdc6f6SPeter Oberparleiter ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event)
9151da177e4SLinus Torvalds {
91628bdc6f6SPeter Oberparleiter /* Start verification after current task finished. */
9171da177e4SLinus Torvalds cdev->private->flags.doverify = 1;
9181da177e4SLinus Torvalds }
9191da177e4SLinus Torvalds
9201da177e4SLinus Torvalds static void
ccw_device_start_id(struct ccw_device * cdev,enum dev_event dev_event)9211da177e4SLinus Torvalds ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event)
9221da177e4SLinus Torvalds {
9231da177e4SLinus Torvalds struct subchannel *sch;
9241da177e4SLinus Torvalds
9251da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
9265c2e5a0cSAlexander Gordeev if (cio_enable_subchannel(sch, (u32)virt_to_phys(sch)) != 0)
9271da177e4SLinus Torvalds /* Couldn't enable the subchannel for i/o. Sick device. */
9281da177e4SLinus Torvalds return;
9291da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID;
9301da177e4SLinus Torvalds ccw_device_sense_id_start(cdev);
9311da177e4SLinus Torvalds }
9321da177e4SLinus Torvalds
ccw_device_trigger_reprobe(struct ccw_device * cdev)933c820de39SCornelia Huck void ccw_device_trigger_reprobe(struct ccw_device *cdev)
9341da177e4SLinus Torvalds {
935c820de39SCornelia Huck struct subchannel *sch;
9361da177e4SLinus Torvalds
9371da177e4SLinus Torvalds if (cdev->private->state != DEV_STATE_DISCONNECTED)
9381da177e4SLinus Torvalds return;
9391da177e4SLinus Torvalds
940c820de39SCornelia Huck sch = to_subchannel(cdev->dev.parent);
9411da177e4SLinus Torvalds /* Update some values. */
942cdb912a4SSebastian Ott if (cio_update_schib(sch))
9437674da77SCornelia Huck return;
9441da177e4SLinus Torvalds /*
9451da177e4SLinus Torvalds * The pim, pam, pom values may not be accurate, but they are the best
9461da177e4SLinus Torvalds * we have before performing device selection :/
9471da177e4SLinus Torvalds */
94828bdc6f6SPeter Oberparleiter sch->lpm = sch->schib.pmcw.pam & sch->opm;
94913952ec1SSebastian Ott /*
950*cada938aSHeiko Carstens * Use the initial configuration since we can't be sure that the old
95113952ec1SSebastian Ott * paths are valid.
95213952ec1SSebastian Ott */
95313952ec1SSebastian Ott io_subchannel_init_config(sch);
954f444cc0eSSebastian Ott if (cio_commit_config(sch))
955f444cc0eSSebastian Ott return;
95613952ec1SSebastian Ott
9571da177e4SLinus Torvalds /* We should also udate ssd info, but this has to wait. */
958d7b5a4c9SCornelia Huck /* Check if this is another device which appeared on the same sch. */
9595d6e6b6fSPeter Oberparleiter if (sch->schib.pmcw.dev != cdev->private->dev_id.devno)
9605d6e6b6fSPeter Oberparleiter css_schedule_eval(sch->schid);
9615d6e6b6fSPeter Oberparleiter else
9621da177e4SLinus Torvalds ccw_device_start_id(cdev, 0);
9631da177e4SLinus Torvalds }
9641da177e4SLinus Torvalds
ccw_device_disabled_irq(struct ccw_device * cdev,enum dev_event dev_event)96516b9a057SPeter Oberparleiter static void ccw_device_disabled_irq(struct ccw_device *cdev,
96616b9a057SPeter Oberparleiter enum dev_event dev_event)
9671da177e4SLinus Torvalds {
9681da177e4SLinus Torvalds struct subchannel *sch;
9691da177e4SLinus Torvalds
9701da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent);
9711da177e4SLinus Torvalds /*
97216b9a057SPeter Oberparleiter * An interrupt in a disabled state means a previous disable was not
973ed04b892SCornelia Huck * successful - should not happen, but we try to disable again.
9741da177e4SLinus Torvalds */
9751da177e4SLinus Torvalds cio_disable_subchannel(sch);
9761da177e4SLinus Torvalds }
9771da177e4SLinus Torvalds
9781da177e4SLinus Torvalds static void
ccw_device_change_cmfstate(struct ccw_device * cdev,enum dev_event dev_event)9791da177e4SLinus Torvalds ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event)
9801da177e4SLinus Torvalds {
9811da177e4SLinus Torvalds retry_set_schib(cdev);
9821da177e4SLinus Torvalds cdev->private->state = DEV_STATE_ONLINE;
9831da177e4SLinus Torvalds dev_fsm_event(cdev, dev_event);
9841da177e4SLinus Torvalds }
9851da177e4SLinus Torvalds
ccw_device_update_cmfblock(struct ccw_device * cdev,enum dev_event dev_event)98694bb0633SCornelia Huck static void ccw_device_update_cmfblock(struct ccw_device *cdev,
98794bb0633SCornelia Huck enum dev_event dev_event)
98894bb0633SCornelia Huck {
98994bb0633SCornelia Huck cmf_retry_copy_block(cdev);
99094bb0633SCornelia Huck cdev->private->state = DEV_STATE_ONLINE;
99194bb0633SCornelia Huck dev_fsm_event(cdev, dev_event);
99294bb0633SCornelia Huck }
9931da177e4SLinus Torvalds
9941da177e4SLinus Torvalds static void
ccw_device_quiesce_done(struct ccw_device * cdev,enum dev_event dev_event)9951da177e4SLinus Torvalds ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event)
9961da177e4SLinus Torvalds {
9971da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0);
9981da177e4SLinus Torvalds cdev->private->state = DEV_STATE_NOT_OPER;
9991da177e4SLinus Torvalds wake_up(&cdev->private->wait_q);
10001da177e4SLinus Torvalds }
10011da177e4SLinus Torvalds
10021da177e4SLinus Torvalds static void
ccw_device_quiesce_timeout(struct ccw_device * cdev,enum dev_event dev_event)10031da177e4SLinus Torvalds ccw_device_quiesce_timeout(struct ccw_device *cdev, enum dev_event dev_event)
10041da177e4SLinus Torvalds {
10051da177e4SLinus Torvalds int ret;
10061da177e4SLinus Torvalds
10071da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev);
100856e6b796SSebastian Ott if (ret == -EBUSY) {
100956e6b796SSebastian Ott ccw_device_set_timeout(cdev, HZ/10);
101056e6b796SSebastian Ott } else {
10111da177e4SLinus Torvalds cdev->private->state = DEV_STATE_NOT_OPER;
10121da177e4SLinus Torvalds wake_up(&cdev->private->wait_q);
10131da177e4SLinus Torvalds }
10141da177e4SLinus Torvalds }
10151da177e4SLinus Torvalds
10161da177e4SLinus Torvalds /*
10171da177e4SLinus Torvalds * No operation action. This is used e.g. to ignore a timeout event in
10181da177e4SLinus Torvalds * state offline.
10191da177e4SLinus Torvalds */
10201da177e4SLinus Torvalds static void
ccw_device_nop(struct ccw_device * cdev,enum dev_event dev_event)10211da177e4SLinus Torvalds ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event)
10221da177e4SLinus Torvalds {
10231da177e4SLinus Torvalds }
10241da177e4SLinus Torvalds
10251da177e4SLinus Torvalds /*
10261da177e4SLinus Torvalds * device statemachine
10271da177e4SLinus Torvalds */
10281da177e4SLinus Torvalds fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = {
10291da177e4SLinus Torvalds [DEV_STATE_NOT_OPER] = {
10301da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_nop,
103116b9a057SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq,
10321da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop,
10331da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop,
10341da177e4SLinus Torvalds },
10351da177e4SLinus Torvalds [DEV_STATE_SENSE_ID] = {
103639f5360bSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event,
103739f5360bSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
103839f5360bSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
10391da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop,
10401da177e4SLinus Torvalds },
10411da177e4SLinus Torvalds [DEV_STATE_OFFLINE] = {
10423f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
104316b9a057SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq,
10441da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop,
10451f1148c8SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_offline_verify,
10461da177e4SLinus Torvalds },
10471da177e4SLinus Torvalds [DEV_STATE_VERIFY] = {
10489679baafSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event,
10499679baafSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
10509679baafSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
105128bdc6f6SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_delay_verify,
10521da177e4SLinus Torvalds },
10531da177e4SLinus Torvalds [DEV_STATE_ONLINE] = {
10543f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
10551da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_irq,
10561da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout,
10571da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_online_verify,
10581da177e4SLinus Torvalds },
10591da177e4SLinus Torvalds [DEV_STATE_W4SENSE] = {
10603f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
10611da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_w4sense,
10621da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop,
10631da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_online_verify,
10641da177e4SLinus Torvalds },
10651da177e4SLinus Torvalds [DEV_STATE_DISBAND_PGID] = {
10669679baafSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event,
10679679baafSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
10689679baafSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
10691da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop,
10701da177e4SLinus Torvalds },
10711da177e4SLinus Torvalds [DEV_STATE_BOXED] = {
10723f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
1073d7d12ef2SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_nop,
1074d7d12ef2SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_nop,
1075d7d12ef2SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_boxed_verify,
10761da177e4SLinus Torvalds },
10771da177e4SLinus Torvalds /* states to wait for i/o completion before doing something */
10781da177e4SLinus Torvalds [DEV_STATE_TIMEOUT_KILL] = {
10793f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper,
10801da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq,
10811da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout,
10821da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME
10831da177e4SLinus Torvalds },
10841da177e4SLinus Torvalds [DEV_STATE_QUIESCE] = {
10851da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done,
10861da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done,
10871da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_quiesce_timeout,
10881da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop,
10891da177e4SLinus Torvalds },
10901da177e4SLinus Torvalds /* special states for devices gone not operational */
10911da177e4SLinus Torvalds [DEV_STATE_DISCONNECTED] = {
10921da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_nop,
10931da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_start_id,
109416b9a057SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_nop,
109528bdc6f6SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_start_id,
10961da177e4SLinus Torvalds },
10971da177e4SLinus Torvalds [DEV_STATE_DISCONNECTED_SENSE_ID] = {
109839f5360bSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event,
109939f5360bSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
110039f5360bSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
11011da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop,
11021da177e4SLinus Torvalds },
11031da177e4SLinus Torvalds [DEV_STATE_CMFCHANGE] = {
11041da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_change_cmfstate,
11051da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_change_cmfstate,
11061da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_change_cmfstate,
11071da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_change_cmfstate,
11081da177e4SLinus Torvalds },
110994bb0633SCornelia Huck [DEV_STATE_CMFUPDATE] = {
111094bb0633SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_update_cmfblock,
111194bb0633SCornelia Huck [DEV_EVENT_INTERRUPT] = ccw_device_update_cmfblock,
111294bb0633SCornelia Huck [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock,
111394bb0633SCornelia Huck [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock,
111494bb0633SCornelia Huck },
1115d7d12ef2SPeter Oberparleiter [DEV_STATE_STEAL_LOCK] = {
1116d7d12ef2SPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event,
1117d7d12ef2SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event,
1118d7d12ef2SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event,
1119d7d12ef2SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_nop,
1120d7d12ef2SPeter Oberparleiter },
11211da177e4SLinus Torvalds };
11221da177e4SLinus Torvalds
11231da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(ccw_device_set_timeout);
1124