Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

s390/qeth: handle deferred cc1

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
commit 2297791c92d0 ("s390/cio: dont unregister subchannel from child-drivers")
and
commit 5ef1dc40ffa6 ("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: 2297791c92d0 ("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>

authored by

Alexandra Winter and committed by
Jakub Kicinski
afb373ff cc269926

+36 -2
+36 -2
drivers/s390/net/qeth_core_main.c
··· 1179 1179 } 1180 1180 } 1181 1181 1182 + /** 1183 + * qeth_irq() - qeth interrupt handler 1184 + * @cdev: ccw device 1185 + * @intparm: expect pointer to iob 1186 + * @irb: Interruption Response Block 1187 + * 1188 + * In the good path: 1189 + * corresponding qeth channel is locked with last used iob as active_cmd. 1190 + * But this function is also called for error interrupts. 1191 + * 1192 + * Caller ensures that: 1193 + * Interrupts are disabled; ccw device lock is held; 1194 + * 1195 + */ 1182 1196 static void qeth_irq(struct ccw_device *cdev, unsigned long intparm, 1183 1197 struct irb *irb) 1184 1198 { ··· 1234 1220 iob = (struct qeth_cmd_buffer *) (addr_t)intparm; 1235 1221 } 1236 1222 1237 - qeth_unlock_channel(card, channel); 1238 - 1239 1223 rc = qeth_check_irb_error(card, cdev, irb); 1240 1224 if (rc) { 1241 1225 /* IO was terminated, free its resources. */ 1226 + qeth_unlock_channel(card, channel); 1242 1227 if (iob) 1243 1228 qeth_cancel_cmd(iob, rc); 1244 1229 return; ··· 1281 1268 rc = qeth_get_problem(card, cdev, irb); 1282 1269 if (rc) { 1283 1270 card->read_or_write_problem = 1; 1271 + qeth_unlock_channel(card, channel); 1284 1272 if (iob) 1285 1273 qeth_cancel_cmd(iob, rc); 1286 1274 qeth_clear_ipacmd_list(card); ··· 1289 1275 return; 1290 1276 } 1291 1277 } 1278 + 1279 + if (scsw_cmd_is_valid_cc(&irb->scsw) && irb->scsw.cmd.cc == 1 && iob) { 1280 + /* channel command hasn't started: retry. 1281 + * active_cmd is still set to last iob 1282 + */ 1283 + QETH_CARD_TEXT(card, 2, "irqcc1"); 1284 + rc = ccw_device_start_timeout(cdev, __ccw_from_cmd(iob), 1285 + (addr_t)iob, 0, 0, iob->timeout); 1286 + if (rc) { 1287 + QETH_DBF_MESSAGE(2, 1288 + "ccw retry on %x failed, rc = %i\n", 1289 + CARD_DEVID(card), rc); 1290 + QETH_CARD_TEXT_(card, 2, " err%d", rc); 1291 + qeth_unlock_channel(card, channel); 1292 + qeth_cancel_cmd(iob, rc); 1293 + } 1294 + return; 1295 + } 1296 + 1297 + qeth_unlock_channel(card, channel); 1292 1298 1293 1299 if (iob) { 1294 1300 /* sanity check: */