- struct set_schib_struct *set_data;
-
- set_data = cdev->private->cmb_wait;
- if (!set_data) {
- WARN_ON(1);
- return;
- }
- kref_get(&set_data->kref);
- set_data->ret = set_schib(cdev, set_data->mme, set_data->mbfc,
- set_data->address);
- wake_up(&set_data->wait);
- kref_put(&set_data->kref, cmf_set_schib_release);
-}
-
-static int cmf_copy_block(struct ccw_device *cdev)
-{
- struct subchannel *sch;
- void *reference_buf;
- void *hw_block;
- struct cmb_data *cmb_data;
-
- sch = to_subchannel(cdev->dev.parent);
-
- if (stsch(sch->schid, &sch->schib))
- return -ENODEV;
-
- if (sch->schib.scsw.fctl & SCSW_FCTL_START_FUNC) {
- /* Don't copy if a start function is in progress. */
- if ((!sch->schib.scsw.actl & SCSW_ACTL_SUSPENDED) &&
- (sch->schib.scsw.actl &
- (SCSW_ACTL_DEVACT | SCSW_ACTL_SCHACT)) &&
- (!sch->schib.scsw.stctl & SCSW_STCTL_SEC_STATUS))
- return -EBUSY;
- }
- cmb_data = cdev->private->cmb;
- hw_block = cmbops->align(cmb_data->hw_block);
- if (!memcmp(cmb_data->last_block, hw_block, cmb_data->size))
- /* No need to copy. */
- return 0;
- reference_buf = kzalloc(cmb_data->size, GFP_ATOMIC);
- if (!reference_buf)
- return -ENOMEM;
- /* Ensure consistency of block copied from hardware. */
- do {
- memcpy(cmb_data->last_block, hw_block, cmb_data->size);
- memcpy(reference_buf, hw_block, cmb_data->size);
- } while (memcmp(cmb_data->last_block, reference_buf, cmb_data->size));
- cmb_data->last_update = get_clock();
- kfree(reference_buf);
- return 0;
-}
-
-struct copy_block_struct {
- wait_queue_head_t wait;
- int ret;
- struct kref kref;
-};
-
-static void cmf_copy_block_release(struct kref *kref)
-{
- struct copy_block_struct *copy_block;
-
- copy_block = container_of(kref, struct copy_block_struct, kref);
- kfree(copy_block);
-}
-
-static int cmf_cmb_copy_wait(struct ccw_device *cdev)
-{
- struct copy_block_struct *copy_block;
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(cdev->ccwlock, flags);
- if (!cdev->private->cmb) {
- ret = -ENODEV;
- goto out;
- }
- copy_block = kzalloc(sizeof(struct copy_block_struct), GFP_ATOMIC);
- if (!copy_block) {
- ret = -ENOMEM;
- goto out;
- }
- init_waitqueue_head(©_block->wait);
- kref_init(©_block->kref);
-
- ret = cmf_copy_block(cdev);
- if (ret != -EBUSY)
- goto out_put;
-
- if (cdev->private->state != DEV_STATE_ONLINE) {
- ret = -EBUSY;
- goto out_put;
- }
-
- cdev->private->state = DEV_STATE_CMFUPDATE;
- copy_block->ret = CMF_PENDING;
- cdev->private->cmb_wait = copy_block;
-
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- if (wait_event_interruptible(copy_block->wait,
- copy_block->ret != CMF_PENDING)) {
- spin_lock_irqsave(cdev->ccwlock, flags);
- if (copy_block->ret == CMF_PENDING) {
- copy_block->ret = -ERESTARTSYS;
- if (cdev->private->state == DEV_STATE_CMFUPDATE)
- cdev->private->state = DEV_STATE_ONLINE;
- }
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- }
- spin_lock_irqsave(cdev->ccwlock, flags);
- cdev->private->cmb_wait = NULL;
- ret = copy_block->ret;
-out_put:
- kref_put(©_block->kref, cmf_copy_block_release);
-out:
- spin_unlock_irqrestore(cdev->ccwlock, flags);
- return ret;
-}
-
-void cmf_retry_copy_block(struct ccw_device *cdev)
-{
- struct copy_block_struct *copy_block;