summaryrefslogtreecommitdiffstats
path: root/drivers/s390/char/sclp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/s390/char/sclp.c')
-rw-r--r--drivers/s390/char/sclp.c58
1 files changed, 35 insertions, 23 deletions
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index e4e2df7a478e..e9aa71cdfc44 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -417,7 +417,7 @@ sclp_dispatch_evbufs(struct sccb_header *sccb)
reg = NULL;
list_for_each(l, &sclp_reg_list) {
reg = list_entry(l, struct sclp_register, list);
- if (reg->receive_mask & (1 << (32 - evbuf->type)))
+ if (reg->receive_mask & SCLP_EVTYP_MASK(evbuf->type))
break;
else
reg = NULL;
@@ -618,9 +618,12 @@ struct sclp_statechangebuf {
u16 _zeros : 12;
u16 mask_length;
u64 sclp_active_facility_mask;
- sccb_mask_t sclp_receive_mask;
- sccb_mask_t sclp_send_mask;
- u32 read_data_function_mask;
+ u8 masks[2 * 1021 + 4]; /* variable length */
+ /*
+ * u8 sclp_receive_mask[mask_length];
+ * u8 sclp_send_mask[mask_length];
+ * u32 read_data_function_mask;
+ */
} __attribute__((packed));
@@ -631,14 +634,14 @@ sclp_state_change_cb(struct evbuf_header *evbuf)
unsigned long flags;
struct sclp_statechangebuf *scbuf;
+ BUILD_BUG_ON(sizeof(struct sclp_statechangebuf) > PAGE_SIZE);
+
scbuf = (struct sclp_statechangebuf *) evbuf;
- if (scbuf->mask_length != sizeof(sccb_mask_t))
- return;
spin_lock_irqsave(&sclp_lock, flags);
if (scbuf->validity_sclp_receive_mask)
- sclp_receive_mask = scbuf->sclp_receive_mask;
+ sclp_receive_mask = sccb_get_recv_mask(scbuf);
if (scbuf->validity_sclp_send_mask)
- sclp_send_mask = scbuf->sclp_send_mask;
+ sclp_send_mask = sccb_get_send_mask(scbuf);
spin_unlock_irqrestore(&sclp_lock, flags);
if (scbuf->validity_sclp_active_facility_mask)
sclp.facilities = scbuf->sclp_active_facility_mask;
@@ -748,7 +751,7 @@ EXPORT_SYMBOL(sclp_remove_processed);
/* Prepare init mask request. Called while sclp_lock is locked. */
static inline void
-__sclp_make_init_req(u32 receive_mask, u32 send_mask)
+__sclp_make_init_req(sccb_mask_t receive_mask, sccb_mask_t send_mask)
{
struct init_sccb *sccb;
@@ -761,12 +764,15 @@ __sclp_make_init_req(u32 receive_mask, u32 send_mask)
sclp_init_req.callback = NULL;
sclp_init_req.callback_data = NULL;
sclp_init_req.sccb = sccb;
- sccb->header.length = sizeof(struct init_sccb);
- sccb->mask_length = sizeof(sccb_mask_t);
- sccb->receive_mask = receive_mask;
- sccb->send_mask = send_mask;
- sccb->sclp_receive_mask = 0;
- sccb->sclp_send_mask = 0;
+ sccb->header.length = sizeof(*sccb);
+ 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);
+ sccb_set_sclp_send_mask(sccb, 0);
}
/* Start init mask request. If calculate is non-zero, calculate the mask as
@@ -822,8 +828,8 @@ sclp_init_mask(int calculate)
sccb->header.response_code == 0x20) {
/* Successful request */
if (calculate) {
- sclp_receive_mask = sccb->sclp_receive_mask;
- sclp_send_mask = sccb->sclp_send_mask;
+ sclp_receive_mask = sccb_get_sclp_recv_mask(sccb);
+ sclp_send_mask = sccb_get_sclp_send_mask(sccb);
} else {
sclp_receive_mask = 0;
sclp_send_mask = 0;
@@ -974,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);