mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-27 12:57:53 +00:00
s390/qeth: handle deferred cc1
[ Upstream commitafb373ff3f
] The IO subsystem expects a driver to retry a ccw_device_start, when the subsequent interrupt response block (irb) contains a deferred condition code 1. Symptoms before this commit: On the read channel we always trigger the next read anyhow, so no different behaviour here. On the write channel we may experience timeout errors, because the expected reply will never be received without the retry. Other callers of qeth_send_control_data() may wrongly assume that the ccw was successful, which may cause problems later. Note that since commit2297791c92
("s390/cio: dont unregister subchannel from child-drivers") and commit5ef1dc40ff
("s390/cio: fix invalid -EBUSY on ccw_device_start") deferred CC1s are much more likely to occur. See the commit message of the latter for more background information. Fixes:2297791c92
("s390/cio: dont unregister subchannel from child-drivers") Signed-off-by: Alexandra Winter <wintera@linux.ibm.com> Co-developed-by: Thorsten Winkler <twinkler@linux.ibm.com> Signed-off-by: Thorsten Winkler <twinkler@linux.ibm.com> Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com> Link: https://lore.kernel.org/r/20240321115337.3564694-1-wintera@linux.ibm.com Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
231b189fa1
commit
16307e7bc1
1 changed files with 36 additions and 2 deletions
|
@ -1179,6 +1179,20 @@ static int qeth_check_irb_error(struct qeth_card *card, struct ccw_device *cdev,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* qeth_irq() - qeth interrupt handler
|
||||||
|
* @cdev: ccw device
|
||||||
|
* @intparm: expect pointer to iob
|
||||||
|
* @irb: Interruption Response Block
|
||||||
|
*
|
||||||
|
* In the good path:
|
||||||
|
* corresponding qeth channel is locked with last used iob as active_cmd.
|
||||||
|
* But this function is also called for error interrupts.
|
||||||
|
*
|
||||||
|
* Caller ensures that:
|
||||||
|
* Interrupts are disabled; ccw device lock is held;
|
||||||
|
*
|
||||||
|
*/
|
||||||
static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
|
static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||||
struct irb *irb)
|
struct irb *irb)
|
||||||
{
|
{
|
||||||
|
@ -1220,11 +1234,10 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||||
iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
|
iob = (struct qeth_cmd_buffer *) (addr_t)intparm;
|
||||||
}
|
}
|
||||||
|
|
||||||
qeth_unlock_channel(card, channel);
|
|
||||||
|
|
||||||
rc = qeth_check_irb_error(card, cdev, irb);
|
rc = qeth_check_irb_error(card, cdev, irb);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
/* IO was terminated, free its resources. */
|
/* IO was terminated, free its resources. */
|
||||||
|
qeth_unlock_channel(card, channel);
|
||||||
if (iob)
|
if (iob)
|
||||||
qeth_cancel_cmd(iob, rc);
|
qeth_cancel_cmd(iob, rc);
|
||||||
return;
|
return;
|
||||||
|
@ -1268,6 +1281,7 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||||
rc = qeth_get_problem(card, cdev, irb);
|
rc = qeth_get_problem(card, cdev, irb);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
card->read_or_write_problem = 1;
|
card->read_or_write_problem = 1;
|
||||||
|
qeth_unlock_channel(card, channel);
|
||||||
if (iob)
|
if (iob)
|
||||||
qeth_cancel_cmd(iob, rc);
|
qeth_cancel_cmd(iob, rc);
|
||||||
qeth_clear_ipacmd_list(card);
|
qeth_clear_ipacmd_list(card);
|
||||||
|
@ -1276,6 +1290,26 @@ static void qeth_irq(struct ccw_device *cdev, unsigned long intparm,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (scsw_cmd_is_valid_cc(&irb->scsw) && irb->scsw.cmd.cc == 1 && iob) {
|
||||||
|
/* channel command hasn't started: retry.
|
||||||
|
* active_cmd is still set to last iob
|
||||||
|
*/
|
||||||
|
QETH_CARD_TEXT(card, 2, "irqcc1");
|
||||||
|
rc = ccw_device_start_timeout(cdev, __ccw_from_cmd(iob),
|
||||||
|
(addr_t)iob, 0, 0, iob->timeout);
|
||||||
|
if (rc) {
|
||||||
|
QETH_DBF_MESSAGE(2,
|
||||||
|
"ccw retry on %x failed, rc = %i\n",
|
||||||
|
CARD_DEVID(card), rc);
|
||||||
|
QETH_CARD_TEXT_(card, 2, " err%d", rc);
|
||||||
|
qeth_unlock_channel(card, channel);
|
||||||
|
qeth_cancel_cmd(iob, rc);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
qeth_unlock_channel(card, channel);
|
||||||
|
|
||||||
if (iob) {
|
if (iob) {
|
||||||
/* sanity check: */
|
/* sanity check: */
|
||||||
if (irb->scsw.cmd.count > iob->length) {
|
if (irb->scsw.cmd.count > iob->length) {
|
||||||
|
|
Loading…
Reference in a new issue