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> 124e57b681STim Schmielau #include <linux/jiffies.h> 134e57b681STim Schmielau #include <linux/string.h> 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <asm/ccwdev.h> 164c24da79SCornelia Huck #include <asm/cio.h> 17e5854a58SPeter Oberparleiter #include <asm/chpid.h> 181da177e4SLinus Torvalds 191da177e4SLinus Torvalds #include "cio.h" 201da177e4SLinus Torvalds #include "cio_debug.h" 211da177e4SLinus Torvalds #include "css.h" 221da177e4SLinus Torvalds #include "device.h" 231da177e4SLinus Torvalds #include "chsc.h" 241da177e4SLinus Torvalds #include "ioasm.h" 25e6b6e10aSPeter Oberparleiter #include "chp.h" 261da177e4SLinus Torvalds 2714ff56bbSSebastian Ott static int timeout_log_enabled; 2814ff56bbSSebastian Ott 2914ff56bbSSebastian Ott static int __init ccw_timeout_log_setup(char *unused) 3014ff56bbSSebastian Ott { 3114ff56bbSSebastian Ott timeout_log_enabled = 1; 3214ff56bbSSebastian Ott return 1; 3314ff56bbSSebastian Ott } 3414ff56bbSSebastian Ott 3514ff56bbSSebastian Ott __setup("ccw_timeout_log", ccw_timeout_log_setup); 3614ff56bbSSebastian Ott 3714ff56bbSSebastian Ott static void ccw_timeout_log(struct ccw_device *cdev) 3814ff56bbSSebastian Ott { 3914ff56bbSSebastian Ott struct schib schib; 4014ff56bbSSebastian Ott struct subchannel *sch; 41cd6b4f27SCornelia Huck struct io_subchannel_private *private; 4283262d63SPeter Oberparleiter union orb *orb; 4314ff56bbSSebastian Ott int cc; 4414ff56bbSSebastian Ott 4514ff56bbSSebastian Ott sch = to_subchannel(cdev->dev.parent); 46cd6b4f27SCornelia Huck private = to_io_private(sch); 4783262d63SPeter Oberparleiter orb = &private->orb; 4862e65da9SPeter Oberparleiter cc = stsch(sch->schid, &schib); 4914ff56bbSSebastian Ott 5014ff56bbSSebastian Ott printk(KERN_WARNING "cio: ccw device timeout occurred at %llx, " 511aae0560SHeiko Carstens "device information:\n", get_tod_clock()); 5214ff56bbSSebastian Ott printk(KERN_WARNING "cio: orb:\n"); 5314ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, 5483262d63SPeter Oberparleiter orb, sizeof(*orb), 0); 552a0217d5SKay Sievers printk(KERN_WARNING "cio: ccw device bus id: %s\n", 562a0217d5SKay Sievers dev_name(&cdev->dev)); 572a0217d5SKay Sievers printk(KERN_WARNING "cio: subchannel bus id: %s\n", 582a0217d5SKay Sievers dev_name(&sch->dev)); 5914ff56bbSSebastian Ott printk(KERN_WARNING "cio: subchannel lpm: %02x, opm: %02x, " 6014ff56bbSSebastian Ott "vpm: %02x\n", sch->lpm, sch->opm, sch->vpm); 6114ff56bbSSebastian Ott 6283262d63SPeter Oberparleiter if (orb->tm.b) { 6383262d63SPeter Oberparleiter printk(KERN_WARNING "cio: orb indicates transport mode\n"); 6483262d63SPeter Oberparleiter printk(KERN_WARNING "cio: last tcw:\n"); 6583262d63SPeter Oberparleiter print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, 6683262d63SPeter Oberparleiter (void *)(addr_t)orb->tm.tcw, 6783262d63SPeter Oberparleiter sizeof(struct tcw), 0); 6883262d63SPeter Oberparleiter } else { 6983262d63SPeter Oberparleiter printk(KERN_WARNING "cio: orb indicates command mode\n"); 7083262d63SPeter Oberparleiter if ((void *)(addr_t)orb->cmd.cpa == &private->sense_ccw || 7183262d63SPeter Oberparleiter (void *)(addr_t)orb->cmd.cpa == cdev->private->iccws) 7283262d63SPeter Oberparleiter printk(KERN_WARNING "cio: last channel program " 7383262d63SPeter Oberparleiter "(intern):\n"); 7414ff56bbSSebastian Ott else 7514ff56bbSSebastian Ott printk(KERN_WARNING "cio: last channel program:\n"); 7614ff56bbSSebastian Ott 7714ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, 7883262d63SPeter Oberparleiter (void *)(addr_t)orb->cmd.cpa, 79cd6b4f27SCornelia Huck sizeof(struct ccw1), 0); 8083262d63SPeter Oberparleiter } 8114ff56bbSSebastian Ott printk(KERN_WARNING "cio: ccw device state: %d\n", 8214ff56bbSSebastian Ott cdev->private->state); 8314ff56bbSSebastian Ott printk(KERN_WARNING "cio: store subchannel returned: cc=%d\n", cc); 8414ff56bbSSebastian Ott printk(KERN_WARNING "cio: schib:\n"); 8514ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, 8614ff56bbSSebastian Ott &schib, sizeof(schib), 0); 8714ff56bbSSebastian Ott printk(KERN_WARNING "cio: ccw device flags:\n"); 8814ff56bbSSebastian Ott print_hex_dump(KERN_WARNING, "cio: ", DUMP_PREFIX_NONE, 16, 1, 8914ff56bbSSebastian Ott &cdev->private->flags, sizeof(cdev->private->flags), 0); 9014ff56bbSSebastian Ott } 9114ff56bbSSebastian Ott 921da177e4SLinus Torvalds /* 931da177e4SLinus Torvalds * Timeout function. It just triggers a DEV_EVENT_TIMEOUT. 941da177e4SLinus Torvalds */ 95846d0c6fSKees Cook void 96846d0c6fSKees Cook ccw_device_timeout(struct timer_list *t) 971da177e4SLinus Torvalds { 98846d0c6fSKees Cook struct ccw_device_private *priv = from_timer(priv, t, timer); 99846d0c6fSKees Cook struct ccw_device *cdev = priv->cdev; 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds spin_lock_irq(cdev->ccwlock); 10214ff56bbSSebastian Ott if (timeout_log_enabled) 10314ff56bbSSebastian Ott ccw_timeout_log(cdev); 1041da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_TIMEOUT); 1051da177e4SLinus Torvalds spin_unlock_irq(cdev->ccwlock); 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds /* 1091da177e4SLinus Torvalds * Set timeout 1101da177e4SLinus Torvalds */ 1111da177e4SLinus Torvalds void 1121da177e4SLinus Torvalds ccw_device_set_timeout(struct ccw_device *cdev, int expires) 1131da177e4SLinus Torvalds { 1141da177e4SLinus Torvalds if (expires == 0) { 1151da177e4SLinus Torvalds del_timer(&cdev->private->timer); 1161da177e4SLinus Torvalds return; 1171da177e4SLinus Torvalds } 1181da177e4SLinus Torvalds if (timer_pending(&cdev->private->timer)) { 1191da177e4SLinus Torvalds if (mod_timer(&cdev->private->timer, jiffies + expires)) 1201da177e4SLinus Torvalds return; 1211da177e4SLinus Torvalds } 1221da177e4SLinus Torvalds cdev->private->timer.expires = jiffies + expires; 1231da177e4SLinus Torvalds add_timer(&cdev->private->timer); 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds int 1271da177e4SLinus Torvalds ccw_device_cancel_halt_clear(struct ccw_device *cdev) 1281da177e4SLinus Torvalds { 1291da177e4SLinus Torvalds struct subchannel *sch; 1301da177e4SLinus Torvalds int ret; 1311da177e4SLinus Torvalds 1321da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 1335434da4dSDong Jia Shi ret = cio_cancel_halt_clear(sch, &cdev->private->iretry); 1345434da4dSDong Jia Shi 1355434da4dSDong Jia Shi if (ret == -EIO) 136376ae475SPeter Oberparleiter CIO_MSG_EVENT(0, "0.%x.%04x: could not stop I/O\n", 1375434da4dSDong Jia Shi cdev->private->dev_id.ssid, 1385434da4dSDong Jia Shi cdev->private->dev_id.devno); 1395434da4dSDong Jia Shi 1405434da4dSDong Jia Shi return ret; 1411da177e4SLinus Torvalds } 1421da177e4SLinus Torvalds 143823d494aSSebastian Ott void ccw_device_update_sense_data(struct ccw_device *cdev) 1441da177e4SLinus Torvalds { 145823d494aSSebastian Ott memset(&cdev->id, 0, sizeof(cdev->id)); 146823d494aSSebastian Ott cdev->id.cu_type = cdev->private->senseid.cu_type; 147823d494aSSebastian Ott cdev->id.cu_model = cdev->private->senseid.cu_model; 148823d494aSSebastian Ott cdev->id.dev_type = cdev->private->senseid.dev_type; 149823d494aSSebastian Ott cdev->id.dev_model = cdev->private->senseid.dev_model; 1501da177e4SLinus Torvalds } 151823d494aSSebastian Ott 152823d494aSSebastian Ott int ccw_device_test_sense_data(struct ccw_device *cdev) 153823d494aSSebastian Ott { 154823d494aSSebastian Ott return cdev->id.cu_type == cdev->private->senseid.cu_type && 155823d494aSSebastian Ott cdev->id.cu_model == cdev->private->senseid.cu_model && 156823d494aSSebastian Ott cdev->id.dev_type == cdev->private->senseid.dev_type && 157823d494aSSebastian Ott cdev->id.dev_model == cdev->private->senseid.dev_model; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /* 1611da177e4SLinus Torvalds * The machine won't give us any notification by machine check if a chpid has 1621da177e4SLinus Torvalds * been varied online on the SE so we have to find out by magic (i. e. driving 1631da177e4SLinus Torvalds * the channel subsystem to device selection and updating our path masks). 1641da177e4SLinus Torvalds */ 1654d284cacSHeiko Carstens static void 1661da177e4SLinus Torvalds __recover_lost_chpids(struct subchannel *sch, int old_lpm) 1671da177e4SLinus Torvalds { 1681da177e4SLinus Torvalds int mask, i; 169f86635faSPeter Oberparleiter struct chp_id chpid; 1701da177e4SLinus Torvalds 171f86635faSPeter Oberparleiter chp_id_init(&chpid); 1721da177e4SLinus Torvalds for (i = 0; i<8; i++) { 1731da177e4SLinus Torvalds mask = 0x80 >> i; 1741da177e4SLinus Torvalds if (!(sch->lpm & mask)) 1751da177e4SLinus Torvalds continue; 1761da177e4SLinus Torvalds if (old_lpm & mask) 1771da177e4SLinus Torvalds continue; 178f86635faSPeter Oberparleiter chpid.id = sch->schib.pmcw.chpid[i]; 17983b3370cSPeter Oberparleiter if (!chp_is_registered(chpid)) 18083b3370cSPeter Oberparleiter css_schedule_eval_all(); 1811da177e4SLinus Torvalds } 1821da177e4SLinus Torvalds } 1831da177e4SLinus Torvalds 1841da177e4SLinus Torvalds /* 1851da177e4SLinus Torvalds * Stop device recognition. 1861da177e4SLinus Torvalds */ 1871da177e4SLinus Torvalds static void 1881da177e4SLinus Torvalds ccw_device_recog_done(struct ccw_device *cdev, int state) 1891da177e4SLinus Torvalds { 1901da177e4SLinus Torvalds struct subchannel *sch; 191823d494aSSebastian Ott int old_lpm; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 1941da177e4SLinus Torvalds 195ec64333cSSebastian Ott if (cio_disable_subchannel(sch)) 196ec64333cSSebastian Ott state = DEV_STATE_NOT_OPER; 1971da177e4SLinus Torvalds /* 1981da177e4SLinus Torvalds * Now that we tried recognition, we have performed device selection 1991da177e4SLinus Torvalds * through ssch() and the path information is up to date. 2001da177e4SLinus Torvalds */ 2011da177e4SLinus Torvalds old_lpm = sch->lpm; 202cdb912a4SSebastian Ott 2034ffa9234SCornelia Huck /* Check since device may again have become not operational. */ 204cdb912a4SSebastian Ott if (cio_update_schib(sch)) 2054ffa9234SCornelia Huck state = DEV_STATE_NOT_OPER; 206cdb912a4SSebastian Ott else 207cdb912a4SSebastian Ott sch->lpm = sch->schib.pmcw.pam & sch->opm; 208cdb912a4SSebastian Ott 2091da177e4SLinus Torvalds if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID) 2101da177e4SLinus Torvalds /* Force reprobe on all chpids. */ 2111da177e4SLinus Torvalds old_lpm = 0; 2121da177e4SLinus Torvalds if (sch->lpm != old_lpm) 2131da177e4SLinus Torvalds __recover_lost_chpids(sch, old_lpm); 21447593bfaSSebastian Ott if (cdev->private->state == DEV_STATE_DISCONNECTED_SENSE_ID && 21547593bfaSSebastian Ott (state == DEV_STATE_NOT_OPER || state == DEV_STATE_BOXED)) { 2161da177e4SLinus Torvalds cdev->private->flags.recog_done = 1; 2171da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISCONNECTED; 218156013ffSSebastian Ott wake_up(&cdev->private->wait_q); 2191da177e4SLinus Torvalds return; 2201da177e4SLinus Torvalds } 221823d494aSSebastian Ott if (cdev->private->flags.resuming) { 222823d494aSSebastian Ott cdev->private->state = state; 223823d494aSSebastian Ott cdev->private->flags.recog_done = 1; 224823d494aSSebastian Ott wake_up(&cdev->private->wait_q); 225823d494aSSebastian Ott return; 226823d494aSSebastian Ott } 2271da177e4SLinus Torvalds switch (state) { 2281da177e4SLinus Torvalds case DEV_STATE_NOT_OPER: 2291da177e4SLinus Torvalds break; 2301da177e4SLinus Torvalds case DEV_STATE_OFFLINE: 231823d494aSSebastian Ott if (!cdev->online) { 232823d494aSSebastian Ott ccw_device_update_sense_data(cdev); 2331da177e4SLinus Torvalds break; 234823d494aSSebastian Ott } 235823d494aSSebastian Ott cdev->private->state = DEV_STATE_OFFLINE; 236823d494aSSebastian Ott cdev->private->flags.recog_done = 1; 237823d494aSSebastian Ott if (ccw_device_test_sense_data(cdev)) { 238823d494aSSebastian Ott cdev->private->flags.donotify = 1; 239823d494aSSebastian Ott ccw_device_online(cdev); 240823d494aSSebastian Ott wake_up(&cdev->private->wait_q); 241823d494aSSebastian Ott } else { 242823d494aSSebastian Ott ccw_device_update_sense_data(cdev); 24337de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_REBIND); 244823d494aSSebastian Ott } 245823d494aSSebastian Ott return; 2461da177e4SLinus Torvalds case DEV_STATE_BOXED: 24747593bfaSSebastian Ott if (cdev->id.cu_type != 0) { /* device was recognized before */ 24847593bfaSSebastian Ott cdev->private->flags.recog_done = 1; 24947593bfaSSebastian Ott cdev->private->state = DEV_STATE_BOXED; 25047593bfaSSebastian Ott wake_up(&cdev->private->wait_q); 25147593bfaSSebastian Ott return; 25247593bfaSSebastian Ott } 2531da177e4SLinus Torvalds break; 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds cdev->private->state = state; 2561da177e4SLinus Torvalds io_subchannel_recog_done(cdev); 2571da177e4SLinus Torvalds wake_up(&cdev->private->wait_q); 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds /* 2611da177e4SLinus Torvalds * Function called from device_id.c after sense id has completed. 2621da177e4SLinus Torvalds */ 2631da177e4SLinus Torvalds void 2641da177e4SLinus Torvalds ccw_device_sense_id_done(struct ccw_device *cdev, int err) 2651da177e4SLinus Torvalds { 2661da177e4SLinus Torvalds switch (err) { 2671da177e4SLinus Torvalds case 0: 2681da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_OFFLINE); 2691da177e4SLinus Torvalds break; 2701da177e4SLinus Torvalds case -ETIME: /* Sense id stopped by timeout. */ 2711da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_BOXED); 2721da177e4SLinus Torvalds break; 2731da177e4SLinus Torvalds default: 2741da177e4SLinus Torvalds ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); 2751da177e4SLinus Torvalds break; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds } 2781da177e4SLinus Torvalds 27976e6fb4bSSebastian Ott /** 28076e6fb4bSSebastian Ott * ccw_device_notify() - inform the device's driver about an event 28125985edcSLucas De Marchi * @cdev: device for which an event occurred 28276e6fb4bSSebastian Ott * @event: event that occurred 28376e6fb4bSSebastian Ott * 28476e6fb4bSSebastian Ott * Returns: 28576e6fb4bSSebastian Ott * -%EINVAL if the device is offline or has no driver. 28676e6fb4bSSebastian Ott * -%EOPNOTSUPP if the device's driver has no notifier registered. 28776e6fb4bSSebastian Ott * %NOTIFY_OK if the driver wants to keep the device. 28876e6fb4bSSebastian Ott * %NOTIFY_BAD if the driver doesn't want to keep the device. 28976e6fb4bSSebastian Ott */ 290c820de39SCornelia Huck int ccw_device_notify(struct ccw_device *cdev, int event) 291c820de39SCornelia Huck { 29276e6fb4bSSebastian Ott int ret = -EINVAL; 29376e6fb4bSSebastian Ott 294c820de39SCornelia Huck if (!cdev->drv) 29576e6fb4bSSebastian Ott goto out; 296c820de39SCornelia Huck if (!cdev->online) 29776e6fb4bSSebastian Ott goto out; 29891c36919SPeter Oberparleiter CIO_MSG_EVENT(2, "notify called for 0.%x.%04x, event=%d\n", 29991c36919SPeter Oberparleiter cdev->private->dev_id.ssid, cdev->private->dev_id.devno, 30091c36919SPeter Oberparleiter event); 30176e6fb4bSSebastian Ott if (!cdev->drv->notify) { 30276e6fb4bSSebastian Ott ret = -EOPNOTSUPP; 30376e6fb4bSSebastian Ott goto out; 30476e6fb4bSSebastian Ott } 30576e6fb4bSSebastian Ott if (cdev->drv->notify(cdev, event)) 30676e6fb4bSSebastian Ott ret = NOTIFY_OK; 30776e6fb4bSSebastian Ott else 30876e6fb4bSSebastian Ott ret = NOTIFY_BAD; 30976e6fb4bSSebastian Ott out: 31076e6fb4bSSebastian Ott return ret; 311c820de39SCornelia Huck } 312c820de39SCornelia Huck 31391c36919SPeter Oberparleiter static void ccw_device_oper_notify(struct ccw_device *cdev) 31491c36919SPeter Oberparleiter { 315585b954eSSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent); 316585b954eSSebastian Ott 31776e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_OPER) == NOTIFY_OK) { 31891c36919SPeter Oberparleiter /* Reenable channel measurements, if needed. */ 31937de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_ENABLE_CMF); 320585b954eSSebastian Ott /* Save indication for new paths. */ 321585b954eSSebastian Ott cdev->private->path_new_mask = sch->vpm; 32291c36919SPeter Oberparleiter return; 32391c36919SPeter Oberparleiter } 3241da177e4SLinus Torvalds /* Driver doesn't want device back. */ 32591c36919SPeter Oberparleiter ccw_device_set_notoper(cdev); 32637de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_REBIND); 32794bb0633SCornelia Huck } 3281da177e4SLinus Torvalds 3291da177e4SLinus Torvalds /* 3301da177e4SLinus Torvalds * Finished with online/offline processing. 3311da177e4SLinus Torvalds */ 3321da177e4SLinus Torvalds static void 3331da177e4SLinus Torvalds ccw_device_done(struct ccw_device *cdev, int state) 3341da177e4SLinus Torvalds { 3351da177e4SLinus Torvalds struct subchannel *sch; 3361da177e4SLinus Torvalds 3371da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 3381da177e4SLinus Torvalds 339f1ee3281SCornelia Huck ccw_device_set_timeout(cdev, 0); 340f1ee3281SCornelia Huck 3411da177e4SLinus Torvalds if (state != DEV_STATE_ONLINE) 3421da177e4SLinus Torvalds cio_disable_subchannel(sch); 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds /* Reset device status. */ 3451da177e4SLinus Torvalds memset(&cdev->private->irb, 0, sizeof(struct irb)); 3461da177e4SLinus Torvalds 3471da177e4SLinus Torvalds cdev->private->state = state; 3481da177e4SLinus Torvalds 3499a332116SPeter Oberparleiter switch (state) { 3509a332116SPeter Oberparleiter case DEV_STATE_BOXED: 351139b83ddSMichael Ernst CIO_MSG_EVENT(0, "Boxed device %04x on subchannel %04x\n", 35278964268SCornelia Huck cdev->private->dev_id.devno, sch->schid.sch_no); 35376e6fb4bSSebastian Ott if (cdev->online && 35476e6fb4bSSebastian Ott ccw_device_notify(cdev, CIO_BOXED) != NOTIFY_OK) 35537de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); 35647593bfaSSebastian Ott cdev->private->flags.donotify = 0; 3579a332116SPeter Oberparleiter break; 3589a332116SPeter Oberparleiter case DEV_STATE_NOT_OPER: 359626e476aSSebastian Ott CIO_MSG_EVENT(0, "Device %04x gone on subchannel %04x\n", 360626e476aSSebastian Ott cdev->private->dev_id.devno, sch->schid.sch_no); 36176e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK) 36237de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); 3636afcc775SPeter Oberparleiter else 3646afcc775SPeter Oberparleiter ccw_device_set_disconnected(cdev); 365626e476aSSebastian Ott cdev->private->flags.donotify = 0; 3669a332116SPeter Oberparleiter break; 3679a332116SPeter Oberparleiter case DEV_STATE_DISCONNECTED: 3689a332116SPeter Oberparleiter CIO_MSG_EVENT(0, "Disconnected device %04x on subchannel " 3699a332116SPeter Oberparleiter "%04x\n", cdev->private->dev_id.devno, 3709a332116SPeter Oberparleiter sch->schid.sch_no); 3719bf05098SSebastian Ott if (ccw_device_notify(cdev, CIO_NO_PATH) != NOTIFY_OK) { 3729bf05098SSebastian Ott cdev->private->state = DEV_STATE_NOT_OPER; 37337de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); 3749bf05098SSebastian Ott } else 3759a332116SPeter Oberparleiter ccw_device_set_disconnected(cdev); 3769a332116SPeter Oberparleiter cdev->private->flags.donotify = 0; 3779a332116SPeter Oberparleiter break; 3789a332116SPeter Oberparleiter default: 3799a332116SPeter Oberparleiter break; 380626e476aSSebastian Ott } 3811da177e4SLinus Torvalds 3821da177e4SLinus Torvalds if (cdev->private->flags.donotify) { 3831da177e4SLinus Torvalds cdev->private->flags.donotify = 0; 38491c36919SPeter Oberparleiter ccw_device_oper_notify(cdev); 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds wake_up(&cdev->private->wait_q); 3871da177e4SLinus Torvalds } 3881da177e4SLinus Torvalds 3891da177e4SLinus Torvalds /* 3901da177e4SLinus Torvalds * Start device recognition. 3911da177e4SLinus Torvalds */ 392736b5db8SPeter Oberparleiter void ccw_device_recognition(struct ccw_device *cdev) 3931da177e4SLinus Torvalds { 394736b5db8SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent); 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds /* 3971da177e4SLinus Torvalds * We used to start here with a sense pgid to find out whether a device 3981da177e4SLinus Torvalds * is locked by someone else. Unfortunately, the sense pgid command 3991da177e4SLinus Torvalds * code has other meanings on devices predating the path grouping 4001da177e4SLinus Torvalds * algorithm, so we start with sense id and box the device after an 4011da177e4SLinus Torvalds * timeout (or if sense pgid during path verification detects the device 4021da177e4SLinus Torvalds * is locked, as may happen on newer devices). 4031da177e4SLinus Torvalds */ 4041da177e4SLinus Torvalds cdev->private->flags.recog_done = 0; 4051da177e4SLinus Torvalds cdev->private->state = DEV_STATE_SENSE_ID; 406736b5db8SPeter Oberparleiter if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) { 407736b5db8SPeter Oberparleiter ccw_device_recog_done(cdev, DEV_STATE_NOT_OPER); 408736b5db8SPeter Oberparleiter return; 409736b5db8SPeter Oberparleiter } 4101da177e4SLinus Torvalds ccw_device_sense_id_start(cdev); 4111da177e4SLinus Torvalds } 4121da177e4SLinus Torvalds 4131da177e4SLinus Torvalds /* 41439f5360bSPeter Oberparleiter * Handle events for states that use the ccw request infrastructure. 4151da177e4SLinus Torvalds */ 41639f5360bSPeter Oberparleiter static void ccw_device_request_event(struct ccw_device *cdev, enum dev_event e) 4171da177e4SLinus Torvalds { 41839f5360bSPeter Oberparleiter switch (e) { 41939f5360bSPeter Oberparleiter case DEV_EVENT_NOTOPER: 42039f5360bSPeter Oberparleiter ccw_request_notoper(cdev); 4211da177e4SLinus Torvalds break; 42239f5360bSPeter Oberparleiter case DEV_EVENT_INTERRUPT: 42339f5360bSPeter Oberparleiter ccw_request_handler(cdev); 42439f5360bSPeter Oberparleiter break; 42539f5360bSPeter Oberparleiter case DEV_EVENT_TIMEOUT: 42639f5360bSPeter Oberparleiter ccw_request_timeout(cdev); 4271da177e4SLinus Torvalds break; 4281da177e4SLinus Torvalds default: 42939f5360bSPeter Oberparleiter break; 4301da177e4SLinus Torvalds } 4311da177e4SLinus Torvalds } 4321da177e4SLinus Torvalds 433585b954eSSebastian Ott static void ccw_device_report_path_events(struct ccw_device *cdev) 434585b954eSSebastian Ott { 435585b954eSSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent); 436585b954eSSebastian Ott int path_event[8]; 437585b954eSSebastian Ott int chp, mask; 438585b954eSSebastian Ott 439585b954eSSebastian Ott for (chp = 0, mask = 0x80; chp < 8; chp++, mask >>= 1) { 440585b954eSSebastian Ott path_event[chp] = PE_NONE; 441585b954eSSebastian Ott if (mask & cdev->private->path_gone_mask & ~(sch->vpm)) 442585b954eSSebastian Ott path_event[chp] |= PE_PATH_GONE; 443585b954eSSebastian Ott if (mask & cdev->private->path_new_mask & sch->vpm) 444585b954eSSebastian Ott path_event[chp] |= PE_PATH_AVAILABLE; 445585b954eSSebastian Ott if (mask & cdev->private->pgid_reset_mask & sch->vpm) 446585b954eSSebastian Ott path_event[chp] |= PE_PATHGROUP_ESTABLISHED; 447585b954eSSebastian Ott } 448585b954eSSebastian Ott if (cdev->online && cdev->drv->path_event) 449585b954eSSebastian Ott cdev->drv->path_event(cdev, path_event); 450585b954eSSebastian Ott } 451585b954eSSebastian Ott 452585b954eSSebastian Ott static void ccw_device_reset_path_events(struct ccw_device *cdev) 453585b954eSSebastian Ott { 454585b954eSSebastian Ott cdev->private->path_gone_mask = 0; 455585b954eSSebastian Ott cdev->private->path_new_mask = 0; 456585b954eSSebastian Ott cdev->private->pgid_reset_mask = 0; 457585b954eSSebastian Ott } 458585b954eSSebastian Ott 45950c8e31fSSebastian Ott static void create_fake_irb(struct irb *irb, int type) 46050c8e31fSSebastian Ott { 46150c8e31fSSebastian Ott memset(irb, 0, sizeof(*irb)); 46250c8e31fSSebastian Ott if (type == FAKE_CMD_IRB) { 46350c8e31fSSebastian Ott struct cmd_scsw *scsw = &irb->scsw.cmd; 46450c8e31fSSebastian Ott scsw->cc = 1; 46550c8e31fSSebastian Ott scsw->fctl = SCSW_FCTL_START_FUNC; 46650c8e31fSSebastian Ott scsw->actl = SCSW_ACTL_START_PEND; 46750c8e31fSSebastian Ott scsw->stctl = SCSW_STCTL_STATUS_PEND; 46850c8e31fSSebastian Ott } else if (type == FAKE_TM_IRB) { 46950c8e31fSSebastian Ott struct tm_scsw *scsw = &irb->scsw.tm; 47050c8e31fSSebastian Ott scsw->x = 1; 47150c8e31fSSebastian Ott scsw->cc = 1; 47250c8e31fSSebastian Ott scsw->fctl = SCSW_FCTL_START_FUNC; 47350c8e31fSSebastian Ott scsw->actl = SCSW_ACTL_START_PEND; 47450c8e31fSSebastian Ott scsw->stctl = SCSW_STCTL_STATUS_PEND; 47550c8e31fSSebastian Ott } 47650c8e31fSSebastian Ott } 47750c8e31fSSebastian Ott 47855fb7347SSebastian Ott static void ccw_device_handle_broken_paths(struct ccw_device *cdev) 47955fb7347SSebastian Ott { 48055fb7347SSebastian Ott struct subchannel *sch = to_subchannel(cdev->dev.parent); 48155fb7347SSebastian Ott u8 broken_paths = (sch->schib.pmcw.pam & sch->opm) ^ sch->vpm; 48255fb7347SSebastian Ott 48355fb7347SSebastian Ott if (broken_paths && (cdev->private->path_broken_mask != broken_paths)) 48455fb7347SSebastian Ott ccw_device_schedule_recovery(); 48555fb7347SSebastian Ott 48655fb7347SSebastian Ott cdev->private->path_broken_mask = broken_paths; 48755fb7347SSebastian Ott } 48855fb7347SSebastian Ott 48950c8e31fSSebastian Ott void ccw_device_verify_done(struct ccw_device *cdev, int err) 4901da177e4SLinus Torvalds { 49128bdc6f6SPeter Oberparleiter struct subchannel *sch; 49228bdc6f6SPeter Oberparleiter 49328bdc6f6SPeter Oberparleiter sch = to_subchannel(cdev->dev.parent); 49428bdc6f6SPeter Oberparleiter /* Update schib - pom may have changed. */ 495cdb912a4SSebastian Ott if (cio_update_schib(sch)) { 4967c4d964fSPeter Oberparleiter err = -ENODEV; 4977c4d964fSPeter Oberparleiter goto callback; 498cdb912a4SSebastian Ott } 49928bdc6f6SPeter Oberparleiter /* Update lpm with verified path mask. */ 50028bdc6f6SPeter Oberparleiter sch->lpm = sch->vpm; 50128bdc6f6SPeter Oberparleiter /* Repeat path verification? */ 50228bdc6f6SPeter Oberparleiter if (cdev->private->flags.doverify) { 50328bdc6f6SPeter Oberparleiter ccw_device_verify_start(cdev); 50428bdc6f6SPeter Oberparleiter return; 50528bdc6f6SPeter Oberparleiter } 5067c4d964fSPeter Oberparleiter callback: 5071da177e4SLinus Torvalds switch (err) { 5081da177e4SLinus Torvalds case 0: 5091da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_ONLINE); 5101da177e4SLinus Torvalds /* Deliver fake irb to device driver, if needed. */ 5111da177e4SLinus Torvalds if (cdev->private->flags.fake_irb) { 51250c8e31fSSebastian Ott create_fake_irb(&cdev->private->irb, 51350c8e31fSSebastian Ott cdev->private->flags.fake_irb); 5141da177e4SLinus Torvalds cdev->private->flags.fake_irb = 0; 5151da177e4SLinus Torvalds if (cdev->handler) 5161da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm, 5171da177e4SLinus Torvalds &cdev->private->irb); 5181da177e4SLinus Torvalds memset(&cdev->private->irb, 0, sizeof(struct irb)); 5191da177e4SLinus Torvalds } 520585b954eSSebastian Ott ccw_device_report_path_events(cdev); 52155fb7347SSebastian Ott ccw_device_handle_broken_paths(cdev); 5221da177e4SLinus Torvalds break; 5231da177e4SLinus Torvalds case -ETIME: 52452ef0608SPeter Oberparleiter case -EUSERS: 5258b42f5c2SPeter Oberparleiter /* Reset oper notify indication after verify error. */ 5268b42f5c2SPeter Oberparleiter cdev->private->flags.donotify = 0; 5271da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_BOXED); 5281da177e4SLinus Torvalds break; 5297c4d964fSPeter Oberparleiter case -EACCES: 5307c4d964fSPeter Oberparleiter /* Reset oper notify indication after verify error. */ 5317c4d964fSPeter Oberparleiter cdev->private->flags.donotify = 0; 5327c4d964fSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_DISCONNECTED); 5337c4d964fSPeter Oberparleiter break; 5341da177e4SLinus Torvalds default: 5358b42f5c2SPeter Oberparleiter /* Reset oper notify indication after verify error. */ 5368b42f5c2SPeter Oberparleiter cdev->private->flags.donotify = 0; 5371da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_NOT_OPER); 5381da177e4SLinus Torvalds break; 5391da177e4SLinus Torvalds } 540585b954eSSebastian Ott ccw_device_reset_path_events(cdev); 5411da177e4SLinus Torvalds } 5421da177e4SLinus Torvalds 5431da177e4SLinus Torvalds /* 5441da177e4SLinus Torvalds * Get device online. 5451da177e4SLinus Torvalds */ 5461da177e4SLinus Torvalds int 5471da177e4SLinus Torvalds ccw_device_online(struct ccw_device *cdev) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds struct subchannel *sch; 5501da177e4SLinus Torvalds int ret; 5511da177e4SLinus Torvalds 5521da177e4SLinus Torvalds if ((cdev->private->state != DEV_STATE_OFFLINE) && 5531da177e4SLinus Torvalds (cdev->private->state != DEV_STATE_BOXED)) 5541da177e4SLinus Torvalds return -EINVAL; 5551da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 556edf22096SCornelia Huck ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); 5571da177e4SLinus Torvalds if (ret != 0) { 5581da177e4SLinus Torvalds /* Couldn't enable the subchannel for i/o. Sick device. */ 5591da177e4SLinus Torvalds if (ret == -ENODEV) 5601da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_NOTOPER); 5611da177e4SLinus Torvalds return ret; 5621da177e4SLinus Torvalds } 5637e560814SCornelia Huck /* Start initial path verification. */ 5647e560814SCornelia Huck cdev->private->state = DEV_STATE_VERIFY; 5657e560814SCornelia Huck ccw_device_verify_start(cdev); 5661da177e4SLinus Torvalds return 0; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds 5691da177e4SLinus Torvalds void 5701da177e4SLinus Torvalds ccw_device_disband_done(struct ccw_device *cdev, int err) 5711da177e4SLinus Torvalds { 5721da177e4SLinus Torvalds switch (err) { 5731da177e4SLinus Torvalds case 0: 5741da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_OFFLINE); 5751da177e4SLinus Torvalds break; 5761da177e4SLinus Torvalds case -ETIME: 5771da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_BOXED); 5781da177e4SLinus Torvalds break; 5791da177e4SLinus Torvalds default: 5803ecb0a5aSPeter Oberparleiter cdev->private->flags.donotify = 0; 5811da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_NOT_OPER); 5821da177e4SLinus Torvalds break; 5831da177e4SLinus Torvalds } 5841da177e4SLinus Torvalds } 5851da177e4SLinus Torvalds 5861da177e4SLinus Torvalds /* 5871da177e4SLinus Torvalds * Shutdown device. 5881da177e4SLinus Torvalds */ 5891da177e4SLinus Torvalds int 5901da177e4SLinus Torvalds ccw_device_offline(struct ccw_device *cdev) 5911da177e4SLinus Torvalds { 5921da177e4SLinus Torvalds struct subchannel *sch; 5931da177e4SLinus Torvalds 594b301ea8cSPeter Oberparleiter /* Allow ccw_device_offline while disconnected. */ 595b301ea8cSPeter Oberparleiter if (cdev->private->state == DEV_STATE_DISCONNECTED || 596b301ea8cSPeter Oberparleiter cdev->private->state == DEV_STATE_NOT_OPER) { 597b301ea8cSPeter Oberparleiter cdev->private->flags.donotify = 0; 598b301ea8cSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_NOT_OPER); 599b301ea8cSPeter Oberparleiter return 0; 600b301ea8cSPeter Oberparleiter } 601102e835dSPeter Oberparleiter if (cdev->private->state == DEV_STATE_BOXED) { 602102e835dSPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_BOXED); 603102e835dSPeter Oberparleiter return 0; 604102e835dSPeter Oberparleiter } 605d7b5a4c9SCornelia Huck if (ccw_device_is_orphan(cdev)) { 606d7b5a4c9SCornelia Huck ccw_device_done(cdev, DEV_STATE_OFFLINE); 607d7b5a4c9SCornelia Huck return 0; 608d7b5a4c9SCornelia Huck } 6091da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 610cdb912a4SSebastian Ott if (cio_update_schib(sch)) 6111da177e4SLinus Torvalds return -ENODEV; 61223d805b6SPeter Oberparleiter if (scsw_actl(&sch->schib.scsw) != 0) 6131da177e4SLinus Torvalds return -EBUSY; 61423d805b6SPeter Oberparleiter if (cdev->private->state != DEV_STATE_ONLINE) 6151da177e4SLinus Torvalds return -EINVAL; 6161da177e4SLinus Torvalds /* Are we doing path grouping? */ 617454e1fa1SPeter Oberparleiter if (!cdev->private->flags.pgroup) { 6181da177e4SLinus Torvalds /* No, set state offline immediately. */ 6191da177e4SLinus Torvalds ccw_device_done(cdev, DEV_STATE_OFFLINE); 6201da177e4SLinus Torvalds return 0; 6211da177e4SLinus Torvalds } 6221da177e4SLinus Torvalds /* Start Set Path Group commands. */ 6231da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISBAND_PGID; 6241da177e4SLinus Torvalds ccw_device_disband_start(cdev); 6251da177e4SLinus Torvalds return 0; 6261da177e4SLinus Torvalds } 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds /* 6293f4cf6e7SCornelia Huck * Handle not operational event in non-special state. 6301da177e4SLinus Torvalds */ 6313f4cf6e7SCornelia Huck static void ccw_device_generic_notoper(struct ccw_device *cdev, 6323f4cf6e7SCornelia Huck enum dev_event dev_event) 6331da177e4SLinus Torvalds { 63476e6fb4bSSebastian Ott if (ccw_device_notify(cdev, CIO_GONE) != NOTIFY_OK) 63537de53bbSPeter Oberparleiter ccw_device_sched_todo(cdev, CDEV_TODO_UNREG); 6366afcc775SPeter Oberparleiter else 6376afcc775SPeter Oberparleiter ccw_device_set_disconnected(cdev); 6381da177e4SLinus Torvalds } 6391da177e4SLinus Torvalds 6401da177e4SLinus Torvalds /* 6411f1148c8SPeter Oberparleiter * Handle path verification event in offline state. 6421f1148c8SPeter Oberparleiter */ 6431f1148c8SPeter Oberparleiter static void ccw_device_offline_verify(struct ccw_device *cdev, 6441f1148c8SPeter Oberparleiter enum dev_event dev_event) 6451f1148c8SPeter Oberparleiter { 6461f1148c8SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent); 6471f1148c8SPeter Oberparleiter 6481f1148c8SPeter Oberparleiter css_schedule_eval(sch->schid); 6491f1148c8SPeter Oberparleiter } 6501f1148c8SPeter Oberparleiter 6511f1148c8SPeter Oberparleiter /* 6521da177e4SLinus Torvalds * Handle path verification event. 6531da177e4SLinus Torvalds */ 6541da177e4SLinus Torvalds static void 6551da177e4SLinus Torvalds ccw_device_online_verify(struct ccw_device *cdev, enum dev_event dev_event) 6561da177e4SLinus Torvalds { 6571da177e4SLinus Torvalds struct subchannel *sch; 6581da177e4SLinus Torvalds 6591da177e4SLinus Torvalds if (cdev->private->state == DEV_STATE_W4SENSE) { 6601da177e4SLinus Torvalds cdev->private->flags.doverify = 1; 6611da177e4SLinus Torvalds return; 6621da177e4SLinus Torvalds } 6631da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 6641da177e4SLinus Torvalds /* 6651da177e4SLinus Torvalds * Since we might not just be coming from an interrupt from the 6661da177e4SLinus Torvalds * subchannel we have to update the schib. 6671da177e4SLinus Torvalds */ 668cdb912a4SSebastian Ott if (cio_update_schib(sch)) { 669cdb912a4SSebastian Ott ccw_device_verify_done(cdev, -ENODEV); 670cdb912a4SSebastian Ott return; 671cdb912a4SSebastian Ott } 6721da177e4SLinus Torvalds 67323d805b6SPeter Oberparleiter if (scsw_actl(&sch->schib.scsw) != 0 || 67423d805b6SPeter Oberparleiter (scsw_stctl(&sch->schib.scsw) & SCSW_STCTL_STATUS_PEND) || 67523d805b6SPeter Oberparleiter (scsw_stctl(&cdev->private->irb.scsw) & SCSW_STCTL_STATUS_PEND)) { 6761da177e4SLinus Torvalds /* 6771da177e4SLinus Torvalds * No final status yet or final status not yet delivered 67825985edcSLucas De Marchi * to the device driver. Can't do path verification now, 6791da177e4SLinus Torvalds * delay until final status was delivered. 6801da177e4SLinus Torvalds */ 6811da177e4SLinus Torvalds cdev->private->flags.doverify = 1; 6821da177e4SLinus Torvalds return; 6831da177e4SLinus Torvalds } 6841da177e4SLinus Torvalds /* Device is idle, we can do the path verification. */ 6851da177e4SLinus Torvalds cdev->private->state = DEV_STATE_VERIFY; 6861da177e4SLinus Torvalds ccw_device_verify_start(cdev); 6871da177e4SLinus Torvalds } 6881da177e4SLinus Torvalds 6891da177e4SLinus Torvalds /* 690d7d12ef2SPeter Oberparleiter * Handle path verification event in boxed state. 691d7d12ef2SPeter Oberparleiter */ 692d7d12ef2SPeter Oberparleiter static void ccw_device_boxed_verify(struct ccw_device *cdev, 693d7d12ef2SPeter Oberparleiter enum dev_event dev_event) 694d7d12ef2SPeter Oberparleiter { 695d7d12ef2SPeter Oberparleiter struct subchannel *sch = to_subchannel(cdev->dev.parent); 696d7d12ef2SPeter Oberparleiter 697d7d12ef2SPeter Oberparleiter if (cdev->online) { 698d7d12ef2SPeter Oberparleiter if (cio_enable_subchannel(sch, (u32) (addr_t) sch)) 699d7d12ef2SPeter Oberparleiter ccw_device_done(cdev, DEV_STATE_NOT_OPER); 700d7d12ef2SPeter Oberparleiter else 701d7d12ef2SPeter Oberparleiter ccw_device_online_verify(cdev, dev_event); 702d7d12ef2SPeter Oberparleiter } else 703d7d12ef2SPeter Oberparleiter css_schedule_eval(sch->schid); 704d7d12ef2SPeter Oberparleiter } 705d7d12ef2SPeter Oberparleiter 706d7d12ef2SPeter Oberparleiter /* 7078421d212SSebastian Ott * Pass interrupt to device driver. 7088421d212SSebastian Ott */ 7098421d212SSebastian Ott static int ccw_device_call_handler(struct ccw_device *cdev) 7108421d212SSebastian Ott { 7118421d212SSebastian Ott unsigned int stctl; 7128421d212SSebastian Ott int ending_status; 7138421d212SSebastian Ott 7148421d212SSebastian Ott /* 7158421d212SSebastian Ott * we allow for the device action handler if . 7168421d212SSebastian Ott * - we received ending status 7178421d212SSebastian Ott * - the action handler requested to see all interrupts 7188421d212SSebastian Ott * - we received an intermediate status 7198421d212SSebastian Ott * - fast notification was requested (primary status) 7208421d212SSebastian Ott * - unsolicited interrupts 7218421d212SSebastian Ott */ 7228421d212SSebastian Ott stctl = scsw_stctl(&cdev->private->irb.scsw); 7238421d212SSebastian Ott ending_status = (stctl & SCSW_STCTL_SEC_STATUS) || 7248421d212SSebastian Ott (stctl == (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND)) || 7258421d212SSebastian Ott (stctl == SCSW_STCTL_STATUS_PEND); 7268421d212SSebastian Ott if (!ending_status && 7278421d212SSebastian Ott !cdev->private->options.repall && 7288421d212SSebastian Ott !(stctl & SCSW_STCTL_INTER_STATUS) && 7298421d212SSebastian Ott !(cdev->private->options.fast && 7308421d212SSebastian Ott (stctl & SCSW_STCTL_PRIM_STATUS))) 7318421d212SSebastian Ott return 0; 7328421d212SSebastian Ott 7338421d212SSebastian Ott if (ending_status) 7348421d212SSebastian Ott ccw_device_set_timeout(cdev, 0); 7358421d212SSebastian Ott 7368421d212SSebastian Ott if (cdev->handler) 7378421d212SSebastian Ott cdev->handler(cdev, cdev->private->intparm, 7388421d212SSebastian Ott &cdev->private->irb); 7398421d212SSebastian Ott 7408421d212SSebastian Ott memset(&cdev->private->irb, 0, sizeof(struct irb)); 7418421d212SSebastian Ott return 1; 7428421d212SSebastian Ott } 7438421d212SSebastian Ott 7448421d212SSebastian Ott /* 7451da177e4SLinus Torvalds * Got an interrupt for a normal io (state online). 7461da177e4SLinus Torvalds */ 7471da177e4SLinus Torvalds static void 7481da177e4SLinus Torvalds ccw_device_irq(struct ccw_device *cdev, enum dev_event dev_event) 7491da177e4SLinus Torvalds { 7501da177e4SLinus Torvalds struct irb *irb; 75183262d63SPeter Oberparleiter int is_cmd; 7521da177e4SLinus Torvalds 7530bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb); 75483262d63SPeter Oberparleiter is_cmd = !scsw_is_tm(&irb->scsw); 7551da177e4SLinus Torvalds /* Check for unsolicited interrupt. */ 75623d805b6SPeter Oberparleiter if (!scsw_is_solicited(&irb->scsw)) { 75783262d63SPeter Oberparleiter if (is_cmd && (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) && 7581da177e4SLinus Torvalds !irb->esw.esw0.erw.cons) { 7591da177e4SLinus Torvalds /* Unit check but no sense data. Need basic sense. */ 7601da177e4SLinus Torvalds if (ccw_device_do_sense(cdev, irb) != 0) 7611da177e4SLinus Torvalds goto call_handler_unsol; 762e0ec5749SCornelia Huck memcpy(&cdev->private->irb, irb, sizeof(struct irb)); 7631da177e4SLinus Torvalds cdev->private->state = DEV_STATE_W4SENSE; 7641da177e4SLinus Torvalds cdev->private->intparm = 0; 7651da177e4SLinus Torvalds return; 7661da177e4SLinus Torvalds } 7671da177e4SLinus Torvalds call_handler_unsol: 7681da177e4SLinus Torvalds if (cdev->handler) 7691da177e4SLinus Torvalds cdev->handler (cdev, 0, irb); 77018374d37SCornelia Huck if (cdev->private->flags.doverify) 77118374d37SCornelia Huck ccw_device_online_verify(cdev, 0); 7721da177e4SLinus Torvalds return; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds /* Accumulate status and find out if a basic sense is needed. */ 7751da177e4SLinus Torvalds ccw_device_accumulate_irb(cdev, irb); 77683262d63SPeter Oberparleiter if (is_cmd && cdev->private->flags.dosense) { 7771da177e4SLinus Torvalds if (ccw_device_do_sense(cdev, irb) == 0) { 7781da177e4SLinus Torvalds cdev->private->state = DEV_STATE_W4SENSE; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds return; 7811da177e4SLinus Torvalds } 7821da177e4SLinus Torvalds /* Call the handler. */ 7831da177e4SLinus Torvalds if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify) 7841da177e4SLinus Torvalds /* Start delayed path verification. */ 7851da177e4SLinus Torvalds ccw_device_online_verify(cdev, 0); 7861da177e4SLinus Torvalds } 7871da177e4SLinus Torvalds 7881da177e4SLinus Torvalds /* 7891da177e4SLinus Torvalds * Got an timeout in online state. 7901da177e4SLinus Torvalds */ 7911da177e4SLinus Torvalds static void 7921da177e4SLinus Torvalds ccw_device_online_timeout(struct ccw_device *cdev, enum dev_event dev_event) 7931da177e4SLinus Torvalds { 7941da177e4SLinus Torvalds int ret; 7951da177e4SLinus Torvalds 7961da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0); 797376ae475SPeter Oberparleiter cdev->private->iretry = 255; 798770b55c9SSebastian Ott cdev->private->async_kill_io_rc = -ETIMEDOUT; 7991da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev); 8001da177e4SLinus Torvalds if (ret == -EBUSY) { 8011da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ); 8021da177e4SLinus Torvalds cdev->private->state = DEV_STATE_TIMEOUT_KILL; 8031da177e4SLinus Torvalds return; 8041da177e4SLinus Torvalds } 805376ae475SPeter Oberparleiter if (ret) 8061da177e4SLinus Torvalds dev_fsm_event(cdev, DEV_EVENT_NOTOPER); 8073f4cf6e7SCornelia Huck else if (cdev->handler) 8081da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm, 8091da177e4SLinus Torvalds ERR_PTR(-ETIMEDOUT)); 8101da177e4SLinus Torvalds } 8111da177e4SLinus Torvalds 8121da177e4SLinus Torvalds /* 8131da177e4SLinus Torvalds * Got an interrupt for a basic sense. 8141da177e4SLinus Torvalds */ 8152b67fc46SHeiko Carstens static void 8161da177e4SLinus Torvalds ccw_device_w4sense(struct ccw_device *cdev, enum dev_event dev_event) 8171da177e4SLinus Torvalds { 8181da177e4SLinus Torvalds struct irb *irb; 8191da177e4SLinus Torvalds 8200bf7fcf1SChristoph Lameter irb = this_cpu_ptr(&cio_irb); 8211da177e4SLinus Torvalds /* Check for unsolicited interrupt. */ 82223d805b6SPeter Oberparleiter if (scsw_stctl(&irb->scsw) == 8231da177e4SLinus Torvalds (SCSW_STCTL_STATUS_PEND | SCSW_STCTL_ALERT_STATUS)) { 82423d805b6SPeter Oberparleiter if (scsw_cc(&irb->scsw) == 1) 8251da177e4SLinus Torvalds /* Basic sense hasn't started. Try again. */ 8261da177e4SLinus Torvalds ccw_device_do_sense(cdev, irb); 8271da177e4SLinus Torvalds else { 828139b83ddSMichael Ernst CIO_MSG_EVENT(0, "0.%x.%04x: unsolicited " 829e556bbbdSCornelia Huck "interrupt during w4sense...\n", 830e556bbbdSCornelia Huck cdev->private->dev_id.ssid, 831e556bbbdSCornelia Huck cdev->private->dev_id.devno); 8321da177e4SLinus Torvalds if (cdev->handler) 8331da177e4SLinus Torvalds cdev->handler (cdev, 0, irb); 8341da177e4SLinus Torvalds } 8351da177e4SLinus Torvalds return; 8361da177e4SLinus Torvalds } 8373ba1998eSCornelia Huck /* 8383ba1998eSCornelia Huck * Check if a halt or clear has been issued in the meanwhile. If yes, 8393ba1998eSCornelia Huck * only deliver the halt/clear interrupt to the device driver as if it 8403ba1998eSCornelia Huck * had killed the original request. 8413ba1998eSCornelia Huck */ 84223d805b6SPeter Oberparleiter if (scsw_fctl(&irb->scsw) & 84323d805b6SPeter Oberparleiter (SCSW_FCTL_CLEAR_FUNC | SCSW_FCTL_HALT_FUNC)) { 8443ba1998eSCornelia Huck cdev->private->flags.dosense = 0; 8453ba1998eSCornelia Huck memset(&cdev->private->irb, 0, sizeof(struct irb)); 8463ba1998eSCornelia Huck ccw_device_accumulate_irb(cdev, irb); 8473ba1998eSCornelia Huck goto call_handler; 8483ba1998eSCornelia Huck } 8491da177e4SLinus Torvalds /* Add basic sense info to irb. */ 8501da177e4SLinus Torvalds ccw_device_accumulate_basic_sense(cdev, irb); 8511da177e4SLinus Torvalds if (cdev->private->flags.dosense) { 8521da177e4SLinus Torvalds /* Another basic sense is needed. */ 8531da177e4SLinus Torvalds ccw_device_do_sense(cdev, irb); 8541da177e4SLinus Torvalds return; 8551da177e4SLinus Torvalds } 8563ba1998eSCornelia Huck call_handler: 8571da177e4SLinus Torvalds cdev->private->state = DEV_STATE_ONLINE; 858217ee6c6SMichael Ernst /* In case sensing interfered with setting the device online */ 859217ee6c6SMichael Ernst wake_up(&cdev->private->wait_q); 8601da177e4SLinus Torvalds /* Call the handler. */ 8611da177e4SLinus Torvalds if (ccw_device_call_handler(cdev) && cdev->private->flags.doverify) 8621da177e4SLinus Torvalds /* Start delayed path verification. */ 8631da177e4SLinus Torvalds ccw_device_online_verify(cdev, 0); 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds 8661da177e4SLinus Torvalds static void 8671da177e4SLinus Torvalds ccw_device_killing_irq(struct ccw_device *cdev, enum dev_event dev_event) 8681da177e4SLinus Torvalds { 8691da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0); 8707c8427c3SCornelia Huck /* Start delayed path verification. */ 8717c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0); 8721da177e4SLinus Torvalds /* OK, i/o is dead now. Call interrupt handler. */ 8731da177e4SLinus Torvalds if (cdev->handler) 8741da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm, 875770b55c9SSebastian Ott ERR_PTR(cdev->private->async_kill_io_rc)); 8761da177e4SLinus Torvalds } 8771da177e4SLinus Torvalds 8781da177e4SLinus Torvalds static void 8791da177e4SLinus Torvalds ccw_device_killing_timeout(struct ccw_device *cdev, enum dev_event dev_event) 8801da177e4SLinus Torvalds { 8811da177e4SLinus Torvalds int ret; 8821da177e4SLinus Torvalds 8831da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev); 8841da177e4SLinus Torvalds if (ret == -EBUSY) { 8851da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ); 8861da177e4SLinus Torvalds return; 8871da177e4SLinus Torvalds } 8887c8427c3SCornelia Huck /* Start delayed path verification. */ 8897c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0); 8901da177e4SLinus Torvalds if (cdev->handler) 8911da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm, 892770b55c9SSebastian Ott ERR_PTR(cdev->private->async_kill_io_rc)); 8931da177e4SLinus Torvalds } 8941da177e4SLinus Torvalds 895c820de39SCornelia Huck void ccw_device_kill_io(struct ccw_device *cdev) 8961da177e4SLinus Torvalds { 8971da177e4SLinus Torvalds int ret; 8981da177e4SLinus Torvalds 899*410d5e13SSebastian Ott ccw_device_set_timeout(cdev, 0); 900376ae475SPeter Oberparleiter cdev->private->iretry = 255; 901770b55c9SSebastian Ott cdev->private->async_kill_io_rc = -EIO; 9021da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev); 9031da177e4SLinus Torvalds if (ret == -EBUSY) { 9041da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 3*HZ); 9051da177e4SLinus Torvalds cdev->private->state = DEV_STATE_TIMEOUT_KILL; 9061da177e4SLinus Torvalds return; 9071da177e4SLinus Torvalds } 9087c8427c3SCornelia Huck /* Start delayed path verification. */ 9097c8427c3SCornelia Huck ccw_device_online_verify(cdev, 0); 9101da177e4SLinus Torvalds if (cdev->handler) 9111da177e4SLinus Torvalds cdev->handler(cdev, cdev->private->intparm, 912e7769b48SCornelia Huck ERR_PTR(-EIO)); 9131da177e4SLinus Torvalds } 9141da177e4SLinus Torvalds 9151da177e4SLinus Torvalds static void 91628bdc6f6SPeter Oberparleiter ccw_device_delay_verify(struct ccw_device *cdev, enum dev_event dev_event) 9171da177e4SLinus Torvalds { 91828bdc6f6SPeter Oberparleiter /* Start verification after current task finished. */ 9191da177e4SLinus Torvalds cdev->private->flags.doverify = 1; 9201da177e4SLinus Torvalds } 9211da177e4SLinus Torvalds 9221da177e4SLinus Torvalds static void 9231da177e4SLinus Torvalds ccw_device_start_id(struct ccw_device *cdev, enum dev_event dev_event) 9241da177e4SLinus Torvalds { 9251da177e4SLinus Torvalds struct subchannel *sch; 9261da177e4SLinus Torvalds 9271da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 928edf22096SCornelia Huck if (cio_enable_subchannel(sch, (u32)(addr_t)sch) != 0) 9291da177e4SLinus Torvalds /* Couldn't enable the subchannel for i/o. Sick device. */ 9301da177e4SLinus Torvalds return; 9311da177e4SLinus Torvalds cdev->private->state = DEV_STATE_DISCONNECTED_SENSE_ID; 9321da177e4SLinus Torvalds ccw_device_sense_id_start(cdev); 9331da177e4SLinus Torvalds } 9341da177e4SLinus Torvalds 935c820de39SCornelia Huck void ccw_device_trigger_reprobe(struct ccw_device *cdev) 9361da177e4SLinus Torvalds { 937c820de39SCornelia Huck struct subchannel *sch; 9381da177e4SLinus Torvalds 9391da177e4SLinus Torvalds if (cdev->private->state != DEV_STATE_DISCONNECTED) 9401da177e4SLinus Torvalds return; 9411da177e4SLinus Torvalds 942c820de39SCornelia Huck sch = to_subchannel(cdev->dev.parent); 9431da177e4SLinus Torvalds /* Update some values. */ 944cdb912a4SSebastian Ott if (cio_update_schib(sch)) 9457674da77SCornelia Huck return; 9461da177e4SLinus Torvalds /* 9471da177e4SLinus Torvalds * The pim, pam, pom values may not be accurate, but they are the best 9481da177e4SLinus Torvalds * we have before performing device selection :/ 9491da177e4SLinus Torvalds */ 95028bdc6f6SPeter Oberparleiter sch->lpm = sch->schib.pmcw.pam & sch->opm; 95113952ec1SSebastian Ott /* 95213952ec1SSebastian Ott * Use the initial configuration since we can't be shure that the old 95313952ec1SSebastian Ott * paths are valid. 95413952ec1SSebastian Ott */ 95513952ec1SSebastian Ott io_subchannel_init_config(sch); 956f444cc0eSSebastian Ott if (cio_commit_config(sch)) 957f444cc0eSSebastian Ott return; 95813952ec1SSebastian Ott 9591da177e4SLinus Torvalds /* We should also udate ssd info, but this has to wait. */ 960d7b5a4c9SCornelia Huck /* Check if this is another device which appeared on the same sch. */ 9615d6e6b6fSPeter Oberparleiter if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) 9625d6e6b6fSPeter Oberparleiter css_schedule_eval(sch->schid); 9635d6e6b6fSPeter Oberparleiter else 9641da177e4SLinus Torvalds ccw_device_start_id(cdev, 0); 9651da177e4SLinus Torvalds } 9661da177e4SLinus Torvalds 96716b9a057SPeter Oberparleiter static void ccw_device_disabled_irq(struct ccw_device *cdev, 96816b9a057SPeter Oberparleiter enum dev_event dev_event) 9691da177e4SLinus Torvalds { 9701da177e4SLinus Torvalds struct subchannel *sch; 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds sch = to_subchannel(cdev->dev.parent); 9731da177e4SLinus Torvalds /* 97416b9a057SPeter Oberparleiter * An interrupt in a disabled state means a previous disable was not 975ed04b892SCornelia Huck * successful - should not happen, but we try to disable again. 9761da177e4SLinus Torvalds */ 9771da177e4SLinus Torvalds cio_disable_subchannel(sch); 9781da177e4SLinus Torvalds } 9791da177e4SLinus Torvalds 9801da177e4SLinus Torvalds static void 9811da177e4SLinus Torvalds ccw_device_change_cmfstate(struct ccw_device *cdev, enum dev_event dev_event) 9821da177e4SLinus Torvalds { 9831da177e4SLinus Torvalds retry_set_schib(cdev); 9841da177e4SLinus Torvalds cdev->private->state = DEV_STATE_ONLINE; 9851da177e4SLinus Torvalds dev_fsm_event(cdev, dev_event); 9861da177e4SLinus Torvalds } 9871da177e4SLinus Torvalds 98894bb0633SCornelia Huck static void ccw_device_update_cmfblock(struct ccw_device *cdev, 98994bb0633SCornelia Huck enum dev_event dev_event) 99094bb0633SCornelia Huck { 99194bb0633SCornelia Huck cmf_retry_copy_block(cdev); 99294bb0633SCornelia Huck cdev->private->state = DEV_STATE_ONLINE; 99394bb0633SCornelia Huck dev_fsm_event(cdev, dev_event); 99494bb0633SCornelia Huck } 9951da177e4SLinus Torvalds 9961da177e4SLinus Torvalds static void 9971da177e4SLinus Torvalds ccw_device_quiesce_done(struct ccw_device *cdev, enum dev_event dev_event) 9981da177e4SLinus Torvalds { 9991da177e4SLinus Torvalds ccw_device_set_timeout(cdev, 0); 10001da177e4SLinus Torvalds cdev->private->state = DEV_STATE_NOT_OPER; 10011da177e4SLinus Torvalds wake_up(&cdev->private->wait_q); 10021da177e4SLinus Torvalds } 10031da177e4SLinus Torvalds 10041da177e4SLinus Torvalds static void 10051da177e4SLinus Torvalds ccw_device_quiesce_timeout(struct ccw_device *cdev, enum dev_event dev_event) 10061da177e4SLinus Torvalds { 10071da177e4SLinus Torvalds int ret; 10081da177e4SLinus Torvalds 10091da177e4SLinus Torvalds ret = ccw_device_cancel_halt_clear(cdev); 101056e6b796SSebastian Ott if (ret == -EBUSY) { 101156e6b796SSebastian Ott ccw_device_set_timeout(cdev, HZ/10); 101256e6b796SSebastian Ott } else { 10131da177e4SLinus Torvalds cdev->private->state = DEV_STATE_NOT_OPER; 10141da177e4SLinus Torvalds wake_up(&cdev->private->wait_q); 10151da177e4SLinus Torvalds } 10161da177e4SLinus Torvalds } 10171da177e4SLinus Torvalds 10181da177e4SLinus Torvalds /* 10191da177e4SLinus Torvalds * No operation action. This is used e.g. to ignore a timeout event in 10201da177e4SLinus Torvalds * state offline. 10211da177e4SLinus Torvalds */ 10221da177e4SLinus Torvalds static void 10231da177e4SLinus Torvalds ccw_device_nop(struct ccw_device *cdev, enum dev_event dev_event) 10241da177e4SLinus Torvalds { 10251da177e4SLinus Torvalds } 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds /* 10281da177e4SLinus Torvalds * device statemachine 10291da177e4SLinus Torvalds */ 10301da177e4SLinus Torvalds fsm_func_t *dev_jumptable[NR_DEV_STATES][NR_DEV_EVENTS] = { 10311da177e4SLinus Torvalds [DEV_STATE_NOT_OPER] = { 10321da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_nop, 103316b9a057SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, 10341da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop, 10351da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, 10361da177e4SLinus Torvalds }, 10371da177e4SLinus Torvalds [DEV_STATE_SENSE_ID] = { 103839f5360bSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event, 103939f5360bSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event, 104039f5360bSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event, 10411da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, 10421da177e4SLinus Torvalds }, 10431da177e4SLinus Torvalds [DEV_STATE_OFFLINE] = { 10443f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, 104516b9a057SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_disabled_irq, 10461da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop, 10471f1148c8SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_offline_verify, 10481da177e4SLinus Torvalds }, 10491da177e4SLinus Torvalds [DEV_STATE_VERIFY] = { 10509679baafSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event, 10519679baafSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event, 10529679baafSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event, 105328bdc6f6SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_delay_verify, 10541da177e4SLinus Torvalds }, 10551da177e4SLinus Torvalds [DEV_STATE_ONLINE] = { 10563f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, 10571da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_irq, 10581da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_online_timeout, 10591da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_online_verify, 10601da177e4SLinus Torvalds }, 10611da177e4SLinus Torvalds [DEV_STATE_W4SENSE] = { 10623f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, 10631da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_w4sense, 10641da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_nop, 10651da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_online_verify, 10661da177e4SLinus Torvalds }, 10671da177e4SLinus Torvalds [DEV_STATE_DISBAND_PGID] = { 10689679baafSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event, 10699679baafSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event, 10709679baafSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event, 10711da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, 10721da177e4SLinus Torvalds }, 10731da177e4SLinus Torvalds [DEV_STATE_BOXED] = { 10743f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, 1075d7d12ef2SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_nop, 1076d7d12ef2SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_nop, 1077d7d12ef2SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_boxed_verify, 10781da177e4SLinus Torvalds }, 10791da177e4SLinus Torvalds /* states to wait for i/o completion before doing something */ 10801da177e4SLinus Torvalds [DEV_STATE_TIMEOUT_KILL] = { 10813f4cf6e7SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_generic_notoper, 10821da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_killing_irq, 10831da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_killing_timeout, 10841da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, //FIXME 10851da177e4SLinus Torvalds }, 10861da177e4SLinus Torvalds [DEV_STATE_QUIESCE] = { 10871da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_quiesce_done, 10881da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_quiesce_done, 10891da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_quiesce_timeout, 10901da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, 10911da177e4SLinus Torvalds }, 10921da177e4SLinus Torvalds /* special states for devices gone not operational */ 10931da177e4SLinus Torvalds [DEV_STATE_DISCONNECTED] = { 10941da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_nop, 10951da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_start_id, 109616b9a057SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_nop, 109728bdc6f6SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_start_id, 10981da177e4SLinus Torvalds }, 10991da177e4SLinus Torvalds [DEV_STATE_DISCONNECTED_SENSE_ID] = { 110039f5360bSPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event, 110139f5360bSPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event, 110239f5360bSPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event, 11031da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_nop, 11041da177e4SLinus Torvalds }, 11051da177e4SLinus Torvalds [DEV_STATE_CMFCHANGE] = { 11061da177e4SLinus Torvalds [DEV_EVENT_NOTOPER] = ccw_device_change_cmfstate, 11071da177e4SLinus Torvalds [DEV_EVENT_INTERRUPT] = ccw_device_change_cmfstate, 11081da177e4SLinus Torvalds [DEV_EVENT_TIMEOUT] = ccw_device_change_cmfstate, 11091da177e4SLinus Torvalds [DEV_EVENT_VERIFY] = ccw_device_change_cmfstate, 11101da177e4SLinus Torvalds }, 111194bb0633SCornelia Huck [DEV_STATE_CMFUPDATE] = { 111294bb0633SCornelia Huck [DEV_EVENT_NOTOPER] = ccw_device_update_cmfblock, 111394bb0633SCornelia Huck [DEV_EVENT_INTERRUPT] = ccw_device_update_cmfblock, 111494bb0633SCornelia Huck [DEV_EVENT_TIMEOUT] = ccw_device_update_cmfblock, 111594bb0633SCornelia Huck [DEV_EVENT_VERIFY] = ccw_device_update_cmfblock, 111694bb0633SCornelia Huck }, 1117d7d12ef2SPeter Oberparleiter [DEV_STATE_STEAL_LOCK] = { 1118d7d12ef2SPeter Oberparleiter [DEV_EVENT_NOTOPER] = ccw_device_request_event, 1119d7d12ef2SPeter Oberparleiter [DEV_EVENT_INTERRUPT] = ccw_device_request_event, 1120d7d12ef2SPeter Oberparleiter [DEV_EVENT_TIMEOUT] = ccw_device_request_event, 1121d7d12ef2SPeter Oberparleiter [DEV_EVENT_VERIFY] = ccw_device_nop, 1122d7d12ef2SPeter Oberparleiter }, 11231da177e4SLinus Torvalds }; 11241da177e4SLinus Torvalds 11251da177e4SLinus Torvalds EXPORT_SYMBOL_GPL(ccw_device_set_timeout); 1126