Skip to content

Commit 3cdb455

Browse files
committed
Merge tag 's390-6.9-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Alexander Gordeev: - Fix NULL pointer dereference in program check handler - Fake IRBs are important events relevant for problem analysis. Add traces when queueing and delivering - Fix a race condition in ccw_device_set_online() that can cause the online process to fail - 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 an error, resulting in a failed QDIO setup. Fix that by retrying the setup when a cc1 response is received * tag 's390-6.9-4' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/mm: Fix NULL pointer dereference s390/cio: log fake IRB events s390/cio: fix race condition during online processing s390/qdio: handle deferred cc1
2 parents 9c6e84e + d111855 commit 3cdb455

File tree

5 files changed

+46
-11
lines changed

5 files changed

+46
-11
lines changed

arch/s390/kernel/entry.S

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,8 @@ SYM_CODE_START(pgm_check_handler)
340340
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
341341
stctg %c1,%c1,__PT_CR1(%r11)
342342
#if IS_ENABLED(CONFIG_KVM)
343-
lg %r12,__LC_GMAP
343+
ltg %r12,__LC_GMAP
344+
jz 5f
344345
clc __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
345346
jne 5f
346347
BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST

drivers/s390/cio/device.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -363,10 +363,8 @@ int ccw_device_set_online(struct ccw_device *cdev)
363363

364364
spin_lock_irq(cdev->ccwlock);
365365
ret = ccw_device_online(cdev);
366-
spin_unlock_irq(cdev->ccwlock);
367-
if (ret == 0)
368-
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
369-
else {
366+
if (ret) {
367+
spin_unlock_irq(cdev->ccwlock);
370368
CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
371369
"device 0.%x.%04x\n",
372370
ret, cdev->private->dev_id.ssid,
@@ -375,7 +373,12 @@ int ccw_device_set_online(struct ccw_device *cdev)
375373
put_device(&cdev->dev);
376374
return ret;
377375
}
378-
spin_lock_irq(cdev->ccwlock);
376+
/* Wait until a final state is reached */
377+
while (!dev_fsm_final_state(cdev)) {
378+
spin_unlock_irq(cdev->ccwlock);
379+
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
380+
spin_lock_irq(cdev->ccwlock);
381+
}
379382
/* Check if online processing was successful */
380383
if ((cdev->private->state != DEV_STATE_ONLINE) &&
381384
(cdev->private->state != DEV_STATE_W4SENSE)) {

drivers/s390/cio/device_fsm.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -504,6 +504,11 @@ void ccw_device_verify_done(struct ccw_device *cdev, int err)
504504
ccw_device_done(cdev, DEV_STATE_ONLINE);
505505
/* Deliver fake irb to device driver, if needed. */
506506
if (cdev->private->flags.fake_irb) {
507+
CIO_MSG_EVENT(2, "fakeirb: deliver device 0.%x.%04x intparm %lx type=%d\n",
508+
cdev->private->dev_id.ssid,
509+
cdev->private->dev_id.devno,
510+
cdev->private->intparm,
511+
cdev->private->flags.fake_irb);
507512
create_fake_irb(&cdev->private->dma_area->irb,
508513
cdev->private->flags.fake_irb);
509514
cdev->private->flags.fake_irb = 0;

drivers/s390/cio/device_ops.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
208208
if (!cdev->private->flags.fake_irb) {
209209
cdev->private->flags.fake_irb = FAKE_CMD_IRB;
210210
cdev->private->intparm = intparm;
211+
CIO_MSG_EVENT(2, "fakeirb: queue device 0.%x.%04x intparm %lx type=%d\n",
212+
cdev->private->dev_id.ssid,
213+
cdev->private->dev_id.devno, intparm,
214+
cdev->private->flags.fake_irb);
211215
return 0;
212216
} else
213217
/* There's already a fake I/O around. */
@@ -551,6 +555,10 @@ int ccw_device_tm_start_timeout_key(struct ccw_device *cdev, struct tcw *tcw,
551555
if (!cdev->private->flags.fake_irb) {
552556
cdev->private->flags.fake_irb = FAKE_TM_IRB;
553557
cdev->private->intparm = intparm;
558+
CIO_MSG_EVENT(2, "fakeirb: queue device 0.%x.%04x intparm %lx type=%d\n",
559+
cdev->private->dev_id.ssid,
560+
cdev->private->dev_id.devno, intparm,
561+
cdev->private->flags.fake_irb);
554562
return 0;
555563
} else
556564
/* There's already a fake I/O around. */

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)