Skip to content

Commit 607638f

Browse files
oberparAlexander Gordeev
authored andcommitted
s390/qdio: handle deferred cc1
A deferred condition code 1 response indicates that I/O was not started and should be retried. The current QDIO implementation handles a cc1 response as I/O error, resulting in a failed QDIO setup. This can happen for example when a path verification request arrives at the same time as QDIO setup I/O is started. Fix this by retrying the QDIO setup I/O when a cc1 response is received. Note that since commit 2297791 ("s390/cio: dont unregister subchannel from child-drivers") commit 5ef1dc4 ("s390/cio: fix invalid -EBUSY on ccw_device_start") deferred cc1 responses are much more likely to occur. See the commit message of the latter for more background information. Fixes: 2297791 ("s390/cio: dont unregister subchannel from child-drivers") Reviewed-by: Alexandra Winter <[email protected]> Signed-off-by: Peter Oberparleiter <[email protected]> Signed-off-by: Alexander Gordeev <[email protected]>
1 parent 378ca2d commit 607638f

File tree

1 file changed

+23
-5
lines changed

1 file changed

+23
-5
lines changed

drivers/s390/cio/qdio_main.c

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -722,24 +722,27 @@ static void qdio_handle_activate_check(struct qdio_irq *irq_ptr,
722722
lgr_info_log();
723723
}
724724

725-
static void qdio_establish_handle_irq(struct qdio_irq *irq_ptr, int cstat,
726-
int dstat)
725+
static int qdio_establish_handle_irq(struct qdio_irq *irq_ptr, int cstat,
726+
int dstat, int dcc)
727727
{
728728
DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq");
729729

730730
if (cstat)
731731
goto error;
732732
if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END))
733733
goto error;
734+
if (dcc == 1)
735+
return -EAGAIN;
734736
if (!(dstat & DEV_STAT_DEV_END))
735737
goto error;
736738
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
737-
return;
739+
return 0;
738740

739741
error:
740742
DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no);
741743
DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
742744
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
745+
return -EIO;
743746
}
744747

745748
/* qdio interrupt handler */
@@ -748,7 +751,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
748751
{
749752
struct qdio_irq *irq_ptr = cdev->private->qdio_data;
750753
struct subchannel_id schid;
751-
int cstat, dstat;
754+
int cstat, dstat, rc, dcc;
752755

753756
if (!intparm || !irq_ptr) {
754757
ccw_device_get_schid(cdev, &schid);
@@ -768,10 +771,12 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
768771
qdio_irq_check_sense(irq_ptr, irb);
769772
cstat = irb->scsw.cmd.cstat;
770773
dstat = irb->scsw.cmd.dstat;
774+
dcc = scsw_cmd_is_valid_cc(&irb->scsw) ? irb->scsw.cmd.cc : 0;
775+
rc = 0;
771776

772777
switch (irq_ptr->state) {
773778
case QDIO_IRQ_STATE_INACTIVE:
774-
qdio_establish_handle_irq(irq_ptr, cstat, dstat);
779+
rc = qdio_establish_handle_irq(irq_ptr, cstat, dstat, dcc);
775780
break;
776781
case QDIO_IRQ_STATE_CLEANUP:
777782
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
@@ -785,12 +790,25 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
785790
if (cstat || dstat)
786791
qdio_handle_activate_check(irq_ptr, intparm, cstat,
787792
dstat);
793+
else if (dcc == 1)
794+
rc = -EAGAIN;
788795
break;
789796
case QDIO_IRQ_STATE_STOPPED:
790797
break;
791798
default:
792799
WARN_ON_ONCE(1);
793800
}
801+
802+
if (rc == -EAGAIN) {
803+
DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qint retry");
804+
rc = ccw_device_start(cdev, irq_ptr->ccw, intparm, 0, 0);
805+
if (!rc)
806+
return;
807+
DBF_ERROR("%4x RETRY ERR", irq_ptr->schid.sch_no);
808+
DBF_ERROR("rc:%4x", rc);
809+
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
810+
}
811+
794812
wake_up(&cdev->private->wait_q);
795813
}
796814

0 commit comments

Comments
 (0)