Loading arch/s390/include/asm/ccwdev.h +13 −5 Original line number Diff line number Diff line /* * include/asm-s390/ccwdev.h * include/asm-s390x/ccwdev.h * Copyright IBM Corp. 2002, 2009 * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Arnd Bergmann <arndb@de.ibm.com> * * Interface for CCW device drivers Loading Loading @@ -104,6 +102,11 @@ struct ccw_device { * @set_offline: called when setting device offline * @notify: notify driver of device state changes * @shutdown: called at device shutdown * @prepare: prepare for pm state transition * @complete: undo work done in @prepare * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation * @driver: embedded device driver structure * @name: device driver name */ Loading @@ -116,6 +119,11 @@ struct ccw_driver { int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); void (*shutdown) (struct ccw_device *); int (*prepare) (struct ccw_device *); void (*complete) (struct ccw_device *); int (*freeze)(struct ccw_device *); int (*thaw) (struct ccw_device *); int (*restore)(struct ccw_device *); struct device_driver driver; char *name; }; Loading drivers/s390/cio/cmf.c +5 −0 Original line number Diff line number Diff line Loading @@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); int ccw_set_cmf(struct ccw_device *cdev, int enable) { return cmbops->set(cdev, enable ? 2 : 0); } /** * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled Loading drivers/s390/cio/device.c +237 −0 Original line number Diff line number Diff line Loading @@ -1895,6 +1895,242 @@ static void ccw_device_shutdown(struct device *dev) disable_cmf(cdev); } static int ccw_device_pm_prepare(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (work_pending(&cdev->private->kick_work)) return -EAGAIN; /* Fail while device is being set online/offline. */ if (atomic_read(&cdev->private->onoff)) return -EAGAIN; if (cdev->online && cdev->drv && cdev->drv->prepare) return cdev->drv->prepare(cdev); return 0; } static void ccw_device_pm_complete(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (cdev->online && cdev->drv && cdev->drv->complete) cdev->drv->complete(cdev); } static int ccw_device_pm_freeze(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; /* Fail suspend while device is in transistional state. */ if (!dev_fsm_final_state(cdev)) return -EAGAIN; if (!cdev->online) return 0; if (cdev->drv && cdev->drv->freeze) { ret = cdev->drv->freeze(cdev); if (ret) return ret; } spin_lock_irq(sch->lock); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (cm_enabled) { /* Don't have the css write on memory. */ ret = ccw_set_cmf(cdev, 0); if (ret) return ret; } /* From here on, disallow device driver I/O. */ spin_lock_irq(sch->lock); ret = cio_disable_subchannel(sch); spin_unlock_irq(sch->lock); return ret; } static int ccw_device_pm_thaw(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; if (!cdev->online) return 0; spin_lock_irq(sch->lock); /* Allow device driver I/O again. */ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (ret) return ret; if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) return ret; } if (cdev->drv && cdev->drv->thaw) ret = cdev->drv->thaw(cdev); return ret; } static void __ccw_device_pm_restore(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret; if (cio_is_console(sch->schid)) goto out; /* * While we were sleeping, devices may have gone or become * available again. Kick re-detection. */ spin_lock_irq(sch->lock); cdev->private->flags.resuming = 1; ret = ccw_device_recognition(cdev); spin_unlock_irq(sch->lock); if (ret) { CIO_MSG_EVENT(0, "Couldn't start recognition for device " "%s (ret=%d)\n", dev_name(&cdev->dev), ret); spin_lock_irq(sch->lock); cdev->private->state = DEV_STATE_DISCONNECTED; spin_unlock_irq(sch->lock); /* notify driver after the resume cb */ goto out; } wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED); out: cdev->private->flags.resuming = 0; } static int resume_handle_boxed(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_BOXED; if (ccw_device_notify(cdev, CIO_BOXED)) return 0; ccw_device_schedule_sch_unregister(cdev); return -ENODEV; } static int resume_handle_disc(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_DISCONNECTED; if (ccw_device_notify(cdev, CIO_GONE)) return 0; ccw_device_schedule_sch_unregister(cdev); return -ENODEV; } static int ccw_device_pm_restore(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret = 0, cm_enabled; __ccw_device_pm_restore(cdev); spin_lock_irq(sch->lock); if (cio_is_console(sch->schid)) { cio_enable_subchannel(sch, (u32)(addr_t)sch); spin_unlock_irq(sch->lock); goto out_restore; } cdev->private->flags.donotify = 0; /* check recognition results */ switch (cdev->private->state) { case DEV_STATE_OFFLINE: break; case DEV_STATE_BOXED: ret = resume_handle_boxed(cdev); spin_unlock_irq(sch->lock); if (ret) goto out; goto out_restore; case DEV_STATE_DISCONNECTED: goto out_disc_unlock; default: goto out_unreg_unlock; } /* check if the device id has changed */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " "%04x to %04x)\n", dev_name(&sch->dev), cdev->private->dev_id.devno, sch->schib.pmcw.dev); goto out_unreg_unlock; } /* check if the device type has changed */ if (!ccw_device_test_sense_data(cdev)) { ccw_device_update_sense_data(cdev); PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); ret = -ENODEV; goto out_unlock; } if (!cdev->online) { ret = 0; goto out_unlock; } ret = ccw_device_online(cdev); if (ret) goto out_disc_unlock; cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); if (cdev->private->state != DEV_STATE_ONLINE) { spin_lock_irq(sch->lock); goto out_disc_unlock; } if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) { CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " "(rc=%d)\n", dev_name(&cdev->dev), ret); ret = 0; } } out_restore: if (cdev->online && cdev->drv && cdev->drv->restore) ret = cdev->drv->restore(cdev); out: return ret; out_disc_unlock: ret = resume_handle_disc(cdev); spin_unlock_irq(sch->lock); if (ret) return ret; goto out_restore; out_unreg_unlock: ccw_device_schedule_sch_unregister(cdev); ret = -ENODEV; out_unlock: spin_unlock_irq(sch->lock); return ret; } static struct dev_pm_ops ccw_pm_ops = { .prepare = ccw_device_pm_prepare, .complete = ccw_device_pm_complete, .freeze = ccw_device_pm_freeze, .thaw = ccw_device_pm_thaw, .restore = ccw_device_pm_restore, }; struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, Loading @@ -1902,6 +2138,7 @@ struct bus_type ccw_bus_type = { .probe = ccw_device_probe, .remove = ccw_device_remove, .shutdown = ccw_device_shutdown, .pm = &ccw_pm_ops, }; /** Loading drivers/s390/cio/device.h +3 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); void ccw_device_update_sense_data(struct ccw_device *); int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); Loading Loading @@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; void retry_set_schib(struct ccw_device *cdev); void cmf_retry_copy_block(struct ccw_device *); int cmf_reenable(struct ccw_device *); int ccw_set_cmf(struct ccw_device *cdev, int enable); extern struct device_attribute dev_attr_cmb_enable; #endif drivers/s390/cio/device_fsm.c +43 −53 Original line number Diff line number Diff line Loading @@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) panic("Can't stop i/o on subchannel.\n"); } static int ccw_device_handle_oper(struct ccw_device *cdev) void ccw_device_update_sense_data(struct ccw_device *cdev) { struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); cdev->private->flags.recog_done = 1; /* * Check if cu type and device type still match. If * not, it is certainly another device and we have to * de- and re-register. */ if (cdev->id.cu_type != cdev->private->senseid.cu_type || cdev->id.cu_model != cdev->private->senseid.cu_model || cdev->id.dev_type != cdev->private->senseid.dev_type || cdev->id.dev_model != cdev->private->senseid.dev_model) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); return 0; memset(&cdev->id, 0, sizeof(cdev->id)); cdev->id.cu_type = cdev->private->senseid.cu_type; cdev->id.cu_model = cdev->private->senseid.cu_model; cdev->id.dev_type = cdev->private->senseid.dev_type; cdev->id.dev_model = cdev->private->senseid.dev_model; } cdev->private->flags.donotify = 1; return 1; int ccw_device_test_sense_data(struct ccw_device *cdev) { return cdev->id.cu_type == cdev->private->senseid.cu_type && cdev->id.cu_model == cdev->private->senseid.cu_model && cdev->id.dev_type == cdev->private->senseid.dev_type && cdev->id.dev_model == cdev->private->senseid.dev_model; } /* Loading Loading @@ -233,7 +225,7 @@ static void ccw_device_recog_done(struct ccw_device *cdev, int state) { struct subchannel *sch; int notify, old_lpm, same_dev; int old_lpm; sch = to_subchannel(cdev->dev.parent); Loading Loading @@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) wake_up(&cdev->private->wait_q); return; } notify = 0; same_dev = 0; /* Keep the compiler quiet... */ if (cdev->private->flags.resuming) { cdev->private->state = state; cdev->private->flags.recog_done = 1; wake_up(&cdev->private->wait_q); return; } switch (state) { case DEV_STATE_NOT_OPER: CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " Loading @@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: if (cdev->online) { same_dev = ccw_device_handle_oper(cdev); notify = 1; } /* fill out sense information */ memset(&cdev->id, 0, sizeof(cdev->id)); cdev->id.cu_type = cdev->private->senseid.cu_type; cdev->id.cu_model = cdev->private->senseid.cu_model; cdev->id.dev_type = cdev->private->senseid.dev_type; cdev->id.dev_model = cdev->private->senseid.dev_model; if (notify) { cdev->private->state = DEV_STATE_OFFLINE; if (same_dev) { /* Get device online again. */ ccw_device_online(cdev); wake_up(&cdev->private->wait_q); } return; } if (!cdev->online) { ccw_device_update_sense_data(cdev); /* Issue device info message. */ CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", "CU Type/Mod = %04X/%02X, Dev Type/Mod " "= %04X/%02X\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, cdev->id.cu_type, cdev->id.cu_model, cdev->id.dev_type, cdev->id.dev_model); break; } cdev->private->state = DEV_STATE_OFFLINE; cdev->private->flags.recog_done = 1; if (ccw_device_test_sense_data(cdev)) { cdev->private->flags.donotify = 1; ccw_device_online(cdev); wake_up(&cdev->private->wait_q); } else { ccw_device_update_sense_data(cdev); PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); } return; case DEV_STATE_BOXED: CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " " subchannel 0.%x.%04x\n", Loading Loading @@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) struct subchannel *sch; int ret; if ((cdev->private->state != DEV_STATE_NOT_OPER) && (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) Loading Loading
arch/s390/include/asm/ccwdev.h +13 −5 Original line number Diff line number Diff line /* * include/asm-s390/ccwdev.h * include/asm-s390x/ccwdev.h * Copyright IBM Corp. 2002, 2009 * * Copyright (C) 2002 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Arnd Bergmann <arndb@de.ibm.com> * * Interface for CCW device drivers Loading Loading @@ -104,6 +102,11 @@ struct ccw_device { * @set_offline: called when setting device offline * @notify: notify driver of device state changes * @shutdown: called at device shutdown * @prepare: prepare for pm state transition * @complete: undo work done in @prepare * @freeze: callback for freezing during hibernation snapshotting * @thaw: undo work done in @freeze * @restore: callback for restoring after hibernation * @driver: embedded device driver structure * @name: device driver name */ Loading @@ -116,6 +119,11 @@ struct ccw_driver { int (*set_offline) (struct ccw_device *); int (*notify) (struct ccw_device *, int); void (*shutdown) (struct ccw_device *); int (*prepare) (struct ccw_device *); void (*complete) (struct ccw_device *); int (*freeze)(struct ccw_device *); int (*thaw) (struct ccw_device *); int (*restore)(struct ccw_device *); struct device_driver driver; char *name; }; Loading
drivers/s390/cio/cmf.c +5 −0 Original line number Diff line number Diff line Loading @@ -1204,6 +1204,11 @@ static ssize_t cmb_enable_store(struct device *dev, DEVICE_ATTR(cmb_enable, 0644, cmb_enable_show, cmb_enable_store); int ccw_set_cmf(struct ccw_device *cdev, int enable) { return cmbops->set(cdev, enable ? 2 : 0); } /** * enable_cmf() - switch on the channel measurement for a specific device * @cdev: The ccw device to be enabled Loading
drivers/s390/cio/device.c +237 −0 Original line number Diff line number Diff line Loading @@ -1895,6 +1895,242 @@ static void ccw_device_shutdown(struct device *dev) disable_cmf(cdev); } static int ccw_device_pm_prepare(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (work_pending(&cdev->private->kick_work)) return -EAGAIN; /* Fail while device is being set online/offline. */ if (atomic_read(&cdev->private->onoff)) return -EAGAIN; if (cdev->online && cdev->drv && cdev->drv->prepare) return cdev->drv->prepare(cdev); return 0; } static void ccw_device_pm_complete(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); if (cdev->online && cdev->drv && cdev->drv->complete) cdev->drv->complete(cdev); } static int ccw_device_pm_freeze(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; /* Fail suspend while device is in transistional state. */ if (!dev_fsm_final_state(cdev)) return -EAGAIN; if (!cdev->online) return 0; if (cdev->drv && cdev->drv->freeze) { ret = cdev->drv->freeze(cdev); if (ret) return ret; } spin_lock_irq(sch->lock); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (cm_enabled) { /* Don't have the css write on memory. */ ret = ccw_set_cmf(cdev, 0); if (ret) return ret; } /* From here on, disallow device driver I/O. */ spin_lock_irq(sch->lock); ret = cio_disable_subchannel(sch); spin_unlock_irq(sch->lock); return ret; } static int ccw_device_pm_thaw(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret, cm_enabled; if (!cdev->online) return 0; spin_lock_irq(sch->lock); /* Allow device driver I/O again. */ ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); if (ret) return ret; if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) return ret; } if (cdev->drv && cdev->drv->thaw) ret = cdev->drv->thaw(cdev); return ret; } static void __ccw_device_pm_restore(struct ccw_device *cdev) { struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret; if (cio_is_console(sch->schid)) goto out; /* * While we were sleeping, devices may have gone or become * available again. Kick re-detection. */ spin_lock_irq(sch->lock); cdev->private->flags.resuming = 1; ret = ccw_device_recognition(cdev); spin_unlock_irq(sch->lock); if (ret) { CIO_MSG_EVENT(0, "Couldn't start recognition for device " "%s (ret=%d)\n", dev_name(&cdev->dev), ret); spin_lock_irq(sch->lock); cdev->private->state = DEV_STATE_DISCONNECTED; spin_unlock_irq(sch->lock); /* notify driver after the resume cb */ goto out; } wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev) || cdev->private->state == DEV_STATE_DISCONNECTED); out: cdev->private->flags.resuming = 0; } static int resume_handle_boxed(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_BOXED; if (ccw_device_notify(cdev, CIO_BOXED)) return 0; ccw_device_schedule_sch_unregister(cdev); return -ENODEV; } static int resume_handle_disc(struct ccw_device *cdev) { cdev->private->state = DEV_STATE_DISCONNECTED; if (ccw_device_notify(cdev, CIO_GONE)) return 0; ccw_device_schedule_sch_unregister(cdev); return -ENODEV; } static int ccw_device_pm_restore(struct device *dev) { struct ccw_device *cdev = to_ccwdev(dev); struct subchannel *sch = to_subchannel(cdev->dev.parent); int ret = 0, cm_enabled; __ccw_device_pm_restore(cdev); spin_lock_irq(sch->lock); if (cio_is_console(sch->schid)) { cio_enable_subchannel(sch, (u32)(addr_t)sch); spin_unlock_irq(sch->lock); goto out_restore; } cdev->private->flags.donotify = 0; /* check recognition results */ switch (cdev->private->state) { case DEV_STATE_OFFLINE: break; case DEV_STATE_BOXED: ret = resume_handle_boxed(cdev); spin_unlock_irq(sch->lock); if (ret) goto out; goto out_restore; case DEV_STATE_DISCONNECTED: goto out_disc_unlock; default: goto out_unreg_unlock; } /* check if the device id has changed */ if (sch->schib.pmcw.dev != cdev->private->dev_id.devno) { CIO_MSG_EVENT(0, "resume: sch %s: failed (devno changed from " "%04x to %04x)\n", dev_name(&sch->dev), cdev->private->dev_id.devno, sch->schib.pmcw.dev); goto out_unreg_unlock; } /* check if the device type has changed */ if (!ccw_device_test_sense_data(cdev)) { ccw_device_update_sense_data(cdev); PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); ret = -ENODEV; goto out_unlock; } if (!cdev->online) { ret = 0; goto out_unlock; } ret = ccw_device_online(cdev); if (ret) goto out_disc_unlock; cm_enabled = cdev->private->cmb != NULL; spin_unlock_irq(sch->lock); wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev)); if (cdev->private->state != DEV_STATE_ONLINE) { spin_lock_irq(sch->lock); goto out_disc_unlock; } if (cm_enabled) { ret = ccw_set_cmf(cdev, 1); if (ret) { CIO_MSG_EVENT(2, "resume: cdev %s: cmf failed " "(rc=%d)\n", dev_name(&cdev->dev), ret); ret = 0; } } out_restore: if (cdev->online && cdev->drv && cdev->drv->restore) ret = cdev->drv->restore(cdev); out: return ret; out_disc_unlock: ret = resume_handle_disc(cdev); spin_unlock_irq(sch->lock); if (ret) return ret; goto out_restore; out_unreg_unlock: ccw_device_schedule_sch_unregister(cdev); ret = -ENODEV; out_unlock: spin_unlock_irq(sch->lock); return ret; } static struct dev_pm_ops ccw_pm_ops = { .prepare = ccw_device_pm_prepare, .complete = ccw_device_pm_complete, .freeze = ccw_device_pm_freeze, .thaw = ccw_device_pm_thaw, .restore = ccw_device_pm_restore, }; struct bus_type ccw_bus_type = { .name = "ccw", .match = ccw_bus_match, Loading @@ -1902,6 +2138,7 @@ struct bus_type ccw_bus_type = { .probe = ccw_device_probe, .remove = ccw_device_remove, .shutdown = ccw_device_shutdown, .pm = &ccw_pm_ops, }; /** Loading
drivers/s390/cio/device.h +3 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,8 @@ int ccw_device_is_orphan(struct ccw_device *); int ccw_device_recognition(struct ccw_device *); int ccw_device_online(struct ccw_device *); int ccw_device_offline(struct ccw_device *); void ccw_device_update_sense_data(struct ccw_device *); int ccw_device_test_sense_data(struct ccw_device *); void ccw_device_schedule_sch_unregister(struct ccw_device *); int ccw_purge_blacklisted(void); Loading Loading @@ -133,5 +135,6 @@ extern struct bus_type ccw_bus_type; void retry_set_schib(struct ccw_device *cdev); void cmf_retry_copy_block(struct ccw_device *); int cmf_reenable(struct ccw_device *); int ccw_set_cmf(struct ccw_device *cdev, int enable); extern struct device_attribute dev_attr_cmb_enable; #endif
drivers/s390/cio/device_fsm.c +43 −53 Original line number Diff line number Diff line Loading @@ -177,29 +177,21 @@ ccw_device_cancel_halt_clear(struct ccw_device *cdev) panic("Can't stop i/o on subchannel.\n"); } static int ccw_device_handle_oper(struct ccw_device *cdev) void ccw_device_update_sense_data(struct ccw_device *cdev) { struct subchannel *sch; sch = to_subchannel(cdev->dev.parent); cdev->private->flags.recog_done = 1; /* * Check if cu type and device type still match. If * not, it is certainly another device and we have to * de- and re-register. */ if (cdev->id.cu_type != cdev->private->senseid.cu_type || cdev->id.cu_model != cdev->private->senseid.cu_model || cdev->id.dev_type != cdev->private->senseid.dev_type || cdev->id.dev_model != cdev->private->senseid.dev_model) { PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); return 0; memset(&cdev->id, 0, sizeof(cdev->id)); cdev->id.cu_type = cdev->private->senseid.cu_type; cdev->id.cu_model = cdev->private->senseid.cu_model; cdev->id.dev_type = cdev->private->senseid.dev_type; cdev->id.dev_model = cdev->private->senseid.dev_model; } cdev->private->flags.donotify = 1; return 1; int ccw_device_test_sense_data(struct ccw_device *cdev) { return cdev->id.cu_type == cdev->private->senseid.cu_type && cdev->id.cu_model == cdev->private->senseid.cu_model && cdev->id.dev_type == cdev->private->senseid.dev_type && cdev->id.dev_model == cdev->private->senseid.dev_model; } /* Loading Loading @@ -233,7 +225,7 @@ static void ccw_device_recog_done(struct ccw_device *cdev, int state) { struct subchannel *sch; int notify, old_lpm, same_dev; int old_lpm; sch = to_subchannel(cdev->dev.parent); Loading Loading @@ -263,8 +255,12 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) wake_up(&cdev->private->wait_q); return; } notify = 0; same_dev = 0; /* Keep the compiler quiet... */ if (cdev->private->flags.resuming) { cdev->private->state = state; cdev->private->flags.recog_done = 1; wake_up(&cdev->private->wait_q); return; } switch (state) { case DEV_STATE_NOT_OPER: CIO_MSG_EVENT(2, "SenseID : unknown device %04x on " Loading @@ -273,34 +269,31 @@ ccw_device_recog_done(struct ccw_device *cdev, int state) sch->schid.ssid, sch->schid.sch_no); break; case DEV_STATE_OFFLINE: if (cdev->online) { same_dev = ccw_device_handle_oper(cdev); notify = 1; } /* fill out sense information */ memset(&cdev->id, 0, sizeof(cdev->id)); cdev->id.cu_type = cdev->private->senseid.cu_type; cdev->id.cu_model = cdev->private->senseid.cu_model; cdev->id.dev_type = cdev->private->senseid.dev_type; cdev->id.dev_model = cdev->private->senseid.dev_model; if (notify) { cdev->private->state = DEV_STATE_OFFLINE; if (same_dev) { /* Get device online again. */ ccw_device_online(cdev); wake_up(&cdev->private->wait_q); } return; } if (!cdev->online) { ccw_device_update_sense_data(cdev); /* Issue device info message. */ CIO_MSG_EVENT(4, "SenseID : device 0.%x.%04x reports: " "CU Type/Mod = %04X/%02X, Dev Type/Mod = " "%04X/%02X\n", "CU Type/Mod = %04X/%02X, Dev Type/Mod " "= %04X/%02X\n", cdev->private->dev_id.ssid, cdev->private->dev_id.devno, cdev->id.cu_type, cdev->id.cu_model, cdev->id.dev_type, cdev->id.dev_model); break; } cdev->private->state = DEV_STATE_OFFLINE; cdev->private->flags.recog_done = 1; if (ccw_device_test_sense_data(cdev)) { cdev->private->flags.donotify = 1; ccw_device_online(cdev); wake_up(&cdev->private->wait_q); } else { ccw_device_update_sense_data(cdev); PREPARE_WORK(&cdev->private->kick_work, ccw_device_do_unbind_bind); queue_work(ccw_device_work, &cdev->private->kick_work); } return; case DEV_STATE_BOXED: CIO_MSG_EVENT(0, "SenseID : boxed device %04x on " " subchannel 0.%x.%04x\n", Loading Loading @@ -502,9 +495,6 @@ ccw_device_recognition(struct ccw_device *cdev) struct subchannel *sch; int ret; if ((cdev->private->state != DEV_STATE_NOT_OPER) && (cdev->private->state != DEV_STATE_BOXED)) return -EINVAL; sch = to_subchannel(cdev->dev.parent); ret = cio_enable_subchannel(sch, (u32)(addr_t)sch); if (ret != 0) Loading