s390 updates for 6.9-rc5
- 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 -----BEGIN PGP SIGNATURE----- iI0EABYIADUWIQQrtrZiYVkVzKQcYivNdxKlNrRb8AUCZiImyhccYWdvcmRlZXZA bGludXguaWJtLmNvbQAKCRDNdxKlNrRb8EXjAQCwB0N7NM94ENmF0vo2MwgcvorW XgoLZG/UkwfVNAJ0DAD8DzN4CTT8ZFkYsva5BIhLATjYAp1ePlIRfcnjgKdB6wg= =YdTJ -----END PGP SIGNATURE----- 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
This commit is contained in:
commit
3cdb455946
@ -340,7 +340,8 @@ SYM_CODE_START(pgm_check_handler)
|
||||
mvc __PT_LAST_BREAK(8,%r11),__LC_PGM_LAST_BREAK
|
||||
stctg %c1,%c1,__PT_CR1(%r11)
|
||||
#if IS_ENABLED(CONFIG_KVM)
|
||||
lg %r12,__LC_GMAP
|
||||
ltg %r12,__LC_GMAP
|
||||
jz 5f
|
||||
clc __GMAP_ASCE(8,%r12), __PT_CR1(%r11)
|
||||
jne 5f
|
||||
BPENTER __SF_SIE_FLAGS(%r10),_TIF_ISOLATE_BP_GUEST
|
||||
|
@ -363,10 +363,8 @@ int ccw_device_set_online(struct ccw_device *cdev)
|
||||
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
ret = ccw_device_online(cdev);
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
if (ret == 0)
|
||||
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
|
||||
else {
|
||||
if (ret) {
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
CIO_MSG_EVENT(0, "ccw_device_online returned %d, "
|
||||
"device 0.%x.%04x\n",
|
||||
ret, cdev->private->dev_id.ssid,
|
||||
@ -375,7 +373,12 @@ int ccw_device_set_online(struct ccw_device *cdev)
|
||||
put_device(&cdev->dev);
|
||||
return ret;
|
||||
}
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
/* Wait until a final state is reached */
|
||||
while (!dev_fsm_final_state(cdev)) {
|
||||
spin_unlock_irq(cdev->ccwlock);
|
||||
wait_event(cdev->private->wait_q, dev_fsm_final_state(cdev));
|
||||
spin_lock_irq(cdev->ccwlock);
|
||||
}
|
||||
/* Check if online processing was successful */
|
||||
if ((cdev->private->state != DEV_STATE_ONLINE) &&
|
||||
(cdev->private->state != DEV_STATE_W4SENSE)) {
|
||||
|
@ -504,6 +504,11 @@ callback:
|
||||
ccw_device_done(cdev, DEV_STATE_ONLINE);
|
||||
/* Deliver fake irb to device driver, if needed. */
|
||||
if (cdev->private->flags.fake_irb) {
|
||||
CIO_MSG_EVENT(2, "fakeirb: deliver device 0.%x.%04x intparm %lx type=%d\n",
|
||||
cdev->private->dev_id.ssid,
|
||||
cdev->private->dev_id.devno,
|
||||
cdev->private->intparm,
|
||||
cdev->private->flags.fake_irb);
|
||||
create_fake_irb(&cdev->private->dma_area->irb,
|
||||
cdev->private->flags.fake_irb);
|
||||
cdev->private->flags.fake_irb = 0;
|
||||
|
@ -208,6 +208,10 @@ int ccw_device_start_timeout_key(struct ccw_device *cdev, struct ccw1 *cpa,
|
||||
if (!cdev->private->flags.fake_irb) {
|
||||
cdev->private->flags.fake_irb = FAKE_CMD_IRB;
|
||||
cdev->private->intparm = intparm;
|
||||
CIO_MSG_EVENT(2, "fakeirb: queue device 0.%x.%04x intparm %lx type=%d\n",
|
||||
cdev->private->dev_id.ssid,
|
||||
cdev->private->dev_id.devno, intparm,
|
||||
cdev->private->flags.fake_irb);
|
||||
return 0;
|
||||
} else
|
||||
/* 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,
|
||||
if (!cdev->private->flags.fake_irb) {
|
||||
cdev->private->flags.fake_irb = FAKE_TM_IRB;
|
||||
cdev->private->intparm = intparm;
|
||||
CIO_MSG_EVENT(2, "fakeirb: queue device 0.%x.%04x intparm %lx type=%d\n",
|
||||
cdev->private->dev_id.ssid,
|
||||
cdev->private->dev_id.devno, intparm,
|
||||
cdev->private->flags.fake_irb);
|
||||
return 0;
|
||||
} else
|
||||
/* There's already a fake I/O around. */
|
||||
|
@ -722,8 +722,8 @@ static void qdio_handle_activate_check(struct qdio_irq *irq_ptr,
|
||||
lgr_info_log();
|
||||
}
|
||||
|
||||
static void qdio_establish_handle_irq(struct qdio_irq *irq_ptr, int cstat,
|
||||
int dstat)
|
||||
static int qdio_establish_handle_irq(struct qdio_irq *irq_ptr, int cstat,
|
||||
int dstat, int dcc)
|
||||
{
|
||||
DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qest irq");
|
||||
|
||||
@ -731,15 +731,18 @@ static void qdio_establish_handle_irq(struct qdio_irq *irq_ptr, int cstat,
|
||||
goto error;
|
||||
if (dstat & ~(DEV_STAT_DEV_END | DEV_STAT_CHN_END))
|
||||
goto error;
|
||||
if (dcc == 1)
|
||||
return -EAGAIN;
|
||||
if (!(dstat & DEV_STAT_DEV_END))
|
||||
goto error;
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ESTABLISHED);
|
||||
return;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
DBF_ERROR("%4x EQ:error", irq_ptr->schid.sch_no);
|
||||
DBF_ERROR("ds: %2x cs:%2x", dstat, cstat);
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* qdio interrupt handler */
|
||||
@ -748,7 +751,7 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||
{
|
||||
struct qdio_irq *irq_ptr = cdev->private->qdio_data;
|
||||
struct subchannel_id schid;
|
||||
int cstat, dstat;
|
||||
int cstat, dstat, rc, dcc;
|
||||
|
||||
if (!intparm || !irq_ptr) {
|
||||
ccw_device_get_schid(cdev, &schid);
|
||||
@ -768,10 +771,12 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||
qdio_irq_check_sense(irq_ptr, irb);
|
||||
cstat = irb->scsw.cmd.cstat;
|
||||
dstat = irb->scsw.cmd.dstat;
|
||||
dcc = scsw_cmd_is_valid_cc(&irb->scsw) ? irb->scsw.cmd.cc : 0;
|
||||
rc = 0;
|
||||
|
||||
switch (irq_ptr->state) {
|
||||
case QDIO_IRQ_STATE_INACTIVE:
|
||||
qdio_establish_handle_irq(irq_ptr, cstat, dstat);
|
||||
rc = qdio_establish_handle_irq(irq_ptr, cstat, dstat, dcc);
|
||||
break;
|
||||
case QDIO_IRQ_STATE_CLEANUP:
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_INACTIVE);
|
||||
@ -785,12 +790,25 @@ void qdio_int_handler(struct ccw_device *cdev, unsigned long intparm,
|
||||
if (cstat || dstat)
|
||||
qdio_handle_activate_check(irq_ptr, intparm, cstat,
|
||||
dstat);
|
||||
else if (dcc == 1)
|
||||
rc = -EAGAIN;
|
||||
break;
|
||||
case QDIO_IRQ_STATE_STOPPED:
|
||||
break;
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
}
|
||||
|
||||
if (rc == -EAGAIN) {
|
||||
DBF_DEV_EVENT(DBF_INFO, irq_ptr, "qint retry");
|
||||
rc = ccw_device_start(cdev, irq_ptr->ccw, intparm, 0, 0);
|
||||
if (!rc)
|
||||
return;
|
||||
DBF_ERROR("%4x RETRY ERR", irq_ptr->schid.sch_no);
|
||||
DBF_ERROR("rc:%4x", rc);
|
||||
qdio_set_state(irq_ptr, QDIO_IRQ_STATE_ERR);
|
||||
}
|
||||
|
||||
wake_up(&cdev->private->wait_q);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user