diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index 59e3219ce5c9..e9aa71cdfc44 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -765,7 +765,10 @@ __sclp_make_init_req(sccb_mask_t receive_mask, sccb_mask_t send_mask) sclp_init_req.callback_data = NULL; sclp_init_req.sccb = sccb; sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); + if (sclp_mask_compat_mode) + sccb->mask_length = SCLP_MASK_SIZE_COMPAT; + else + sccb->mask_length = sizeof(sccb_mask_t); sccb_set_recv_mask(sccb, receive_mask); sccb_set_send_mask(sccb, send_mask); sccb_set_sclp_recv_mask(sccb, 0); @@ -977,12 +980,18 @@ sclp_check_interface(void) irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL); spin_lock_irqsave(&sclp_lock, flags); del_timer(&sclp_request_timer); - if (sclp_init_req.status == SCLP_REQ_DONE && - sccb->header.response_code == 0x20) { - rc = 0; - break; - } else - rc = -EBUSY; + rc = -EBUSY; + if (sclp_init_req.status == SCLP_REQ_DONE) { + if (sccb->header.response_code == 0x20) { + rc = 0; + break; + } else if (sccb->header.response_code == 0x74f0) { + if (!sclp_mask_compat_mode) { + sclp_mask_compat_mode = true; + retry = 0; + } + } + } } unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler); spin_unlock_irqrestore(&sclp_lock, flags); diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index ee44d169f10f..45e6ffdc7f08 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -109,6 +109,8 @@ struct init_sccb { */ } __attribute__((packed)); +#define SCLP_MASK_SIZE_COMPAT 4 + static inline sccb_mask_t sccb_get_mask(u8 *masks, size_t len, int i) { sccb_mask_t res = 0; @@ -262,6 +264,7 @@ extern int sclp_init_state; extern int sclp_console_pages; extern int sclp_console_drop; extern unsigned long sclp_console_full; +extern bool sclp_mask_compat_mode; extern char sclp_early_sccb[PAGE_SIZE]; diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index c8c53260f4b7..5f8d9ea69ebd 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -14,6 +14,11 @@ char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(.data); int sclp_init_state __section(.data) = sclp_init_state_uninitialized; +/* + * Used to keep track of the size of the event masks. Qemu until version 2.11 + * only supports 4 and needs a workaround. + */ +bool sclp_mask_compat_mode; void sclp_early_wait_irq(void) { @@ -145,13 +150,21 @@ int sclp_early_set_event_mask(struct init_sccb *sccb, sccb_mask_t receive_mask, sccb_mask_t send_mask) { +retry: memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); + if (sclp_mask_compat_mode) + sccb->mask_length = SCLP_MASK_SIZE_COMPAT; + else + sccb->mask_length = sizeof(sccb_mask_t); sccb_set_recv_mask(sccb, receive_mask); sccb_set_send_mask(sccb, send_mask); if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb)) return -EIO; + if ((sccb->header.response_code == 0x74f0) && !sclp_mask_compat_mode) { + sclp_mask_compat_mode = true; + goto retry; + } if (sccb->header.response_code != 0x20) return -EIO; return 0;