Skip to content

Commit

Permalink
s390/qdio: cancel the ESTABLISH ccw after timeout
Browse files Browse the repository at this point in the history
commit 1c1dc8b upstream.

When the ESTABLISH ccw does not complete within the specified timeout,
try our best to cancel the ccw program that is still active on the
device. Otherwise the IO subsystem might be accessing it even after
the driver eg. called qdio_free().

Fixes: 779e6e1 ("[S390] qdio: new qdio driver.")
Signed-off-by: Julian Wiedmann <jwi@linux.ibm.com>
Reviewed-by: Benjamin Block <bblock@linux.ibm.com>
Cc: <stable@vger.kernel.org> # 2.6.27
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
julianwiedmann authored and gregkh committed Sep 18, 2021
1 parent 693080b commit 9e2b438
Showing 1 changed file with 30 additions and 21 deletions.
51 changes: 30 additions & 21 deletions drivers/s390/cio/qdio_main.c
Expand Up @@ -890,6 +890,33 @@ static void qdio_shutdown_queues(struct qdio_irq *irq_ptr)
}
}

static int qdio_cancel_ccw(struct qdio_irq *irq, int how)
{
struct ccw_device *cdev = irq->cdev;
int rc;

spin_lock_irq(get_ccwdev_lock(cdev));
qdio_set_state(irq, QDIO_IRQ_STATE_CLEANUP);
if (how & QDIO_FLAG_CLEANUP_USING_CLEAR)
rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP);
else
/* default behaviour is halt */
rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
spin_unlock_irq(get_ccwdev_lock(cdev));
if (rc) {
DBF_ERROR("%4x SHUTD ERR", irq->schid.sch_no);
DBF_ERROR("rc:%4d", rc);
return rc;
}

wait_event_interruptible_timeout(cdev->private->wait_q,
irq->state == QDIO_IRQ_STATE_INACTIVE ||
irq->state == QDIO_IRQ_STATE_ERR,
10 * HZ);

return 0;
}

/**
* qdio_shutdown - shut down a qdio subchannel
* @cdev: associated ccw device
Expand Down Expand Up @@ -927,27 +954,7 @@ int qdio_shutdown(struct ccw_device *cdev, int how)
qdio_shutdown_queues(irq_ptr);
qdio_shutdown_debug_entries(irq_ptr);

/* cleanup subchannel */
spin_lock_irq(get_ccwdev_lock(cdev));
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_CLEANUP);
if (how & QDIO_FLAG_CLEANUP_USING_CLEAR)
rc = ccw_device_clear(cdev, QDIO_DOING_CLEANUP);
else
/* default behaviour is halt */
rc = ccw_device_halt(cdev, QDIO_DOING_CLEANUP);
spin_unlock_irq(get_ccwdev_lock(cdev));
if (rc) {
DBF_ERROR("%4x SHUTD ERR", irq_ptr->schid.sch_no);
DBF_ERROR("rc:%4d", rc);
goto no_cleanup;
}

wait_event_interruptible_timeout(cdev->private->wait_q,
irq_ptr->state == QDIO_IRQ_STATE_INACTIVE ||
irq_ptr->state == QDIO_IRQ_STATE_ERR,
10 * HZ);

no_cleanup:
rc = qdio_cancel_ccw(irq_ptr, how);
qdio_shutdown_thinint(irq_ptr);
qdio_shutdown_irq(irq_ptr);

Expand Down Expand Up @@ -1157,10 +1164,12 @@ int qdio_establish(struct ccw_device *cdev,
return 0;

err_ccw_timeout:
qdio_cancel_ccw(irq_ptr, QDIO_FLAG_CLEANUP_USING_CLEAR);
err_ccw_start:
qdio_shutdown_thinint(irq_ptr);
err_thinint:
qdio_shutdown_irq(irq_ptr);
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
mutex_unlock(&irq_ptr->setup_mutex);
return rc;
}
Expand Down

0 comments on commit 9e2b438

Please sign in to comment.