@samitouri / QOSamiQemu / commits / 33bece0fa1

s390x/css: firm up handling of chained TIC CCWs

The logic in css_interpret_ccw() correctly returns -EINVAL if a Transfer-In-Channel (TIC) CCW is command chained to another TIC CCW. The same routine also correctly returns -EINVAL if 256 CCWs do not perform a data transfer as part of the I/O operation [0]. What is missing, however, is a combination of these two, where a loop can be generated that will continue processing CCWs but without providing an opportunity to catch a breath. Fix this by capping the number of TIC CCWs in a channel program at the same limit as the CCWs without data transfer. [0] See "Invalid Sequence" in z/Architecture Principles of Operation (SA22-7832-14), p16-27 Cc: qemu-stable@nongnu.org Signed-off-by: Eric Farman <farman@linux.ibm.com> Acked-by: Christian Borntraeger <borntraeger@linux.ibm.com> Reviewed-by: Farhan Ali <alifm@linux.ibm.com> Signed-off-by: Christian Borntraeger <borntraeger@linux.ibm.com> Message-ID: <20260713074708.884282-1-borntraeger@linux.ibm.com> Signed-off-by: Cornelia Huck <cohuck@redhat.com>

Eric Farman committed Jul 13, 2026 at 09:47 UTC 33bece0fa121c0a85df4f0372145ca74b967e78e
2 files changed +8
hw/s390x/css.c
+7
@@ -1078,6 +1078,12 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr,
1078 ret = -EINVAL;
1079 break;
1080 }
1081 + /* Limit the number of TICs in a given channel program */
1082 + if (sch->ccw_tic_cnt == 255) {
1083 + ret = -EINVAL;
1084 + break;
1085 + }
1086 + sch->ccw_tic_cnt++;
1087 sch->channel_prog = ccw.cda;
1088 ret = -EAGAIN;
1089 break;
@@ -1129,6 +1135,7 @@ static void sch_handle_start_func_virtual(SubchDev *sch)
1135 sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT);
1136 schib->scsw.flags |= (sch->ccw_fmt_1) ? SCSW_FLAGS_MASK_FMT : 0;
1137 sch->ccw_no_data_cnt = 0;
1138 + sch->ccw_tic_cnt = 0;
1139 suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND);
1140 } else {
1141 /* Start Function resumed via rsch */
include/hw/s390x/css.h
+1
@@ -132,6 +132,7 @@ struct SubchDev {
132 bool ccw_fmt_1;
133 bool thinint_active;
134 uint8_t ccw_no_data_cnt;
135 + uint8_t ccw_tic_cnt;
136 uint16_t migrated_schid; /* used for mismatch detection */
137 CcwDataStream cds;
138 /* transport-provided data: */