diff options
-rw-r--r-- | drivers/s390/cio/chsc.c | 23 | ||||
-rw-r--r-- | drivers/s390/cio/chsc.h | 17 | ||||
-rw-r--r-- | drivers/s390/cio/qdio.h | 14 | ||||
-rw-r--r-- | drivers/s390/cio/qdio_setup.c | 47 |
4 files changed, 58 insertions, 43 deletions
diff --git a/drivers/s390/cio/chsc.c b/drivers/s390/cio/chsc.c index 8ea7d9b2c671..d119d0d87e9b 100644 --- a/drivers/s390/cio/chsc.c +++ b/drivers/s390/cio/chsc.c @@ -144,6 +144,29 @@ out: return ret; } +/** + * chsc_ssqd() - store subchannel QDIO data (SSQD) + * @schid: id of the subchannel on which SSQD is performed + * @ssqd: request and response block for SSQD + * + * Returns 0 on success. + */ +int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd) +{ + memset(ssqd, 0, sizeof(*ssqd)); + ssqd->request.length = 0x0010; + ssqd->request.code = 0x0024; + ssqd->first_sch = schid.sch_no; + ssqd->last_sch = schid.sch_no; + ssqd->ssid = schid.ssid; + + if (chsc(ssqd)) + return -EIO; + + return chsc_error_from_response(ssqd->response.code); +} +EXPORT_SYMBOL_GPL(chsc_ssqd); + static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) { spin_lock_irq(sch->lock); diff --git a/drivers/s390/cio/chsc.h b/drivers/s390/cio/chsc.h index 62d096f11e65..2b88e74e6b65 100644 --- a/drivers/s390/cio/chsc.h +++ b/drivers/s390/cio/chsc.h @@ -7,6 +7,7 @@ #include <asm/chpid.h> #include <asm/chsc.h> #include <asm/schid.h> +#include <asm/qdio.h> #define CHSC_SDA_OC_MSS 0x2 @@ -72,6 +73,20 @@ struct chsc_ssd_info { u16 fla[8]; }; +struct chsc_ssqd_area { + struct chsc_header request; + u16:10; + u8 ssid:2; + u8 fmt:4; + u16 first_sch; + u16:16; + u16 last_sch; + u32:32; + struct chsc_header response; + u32:32; + struct qdio_ssqd_desc qdio_ssqd; +} __packed; + struct chsc_scpd { struct chsc_header request; u32:2; @@ -111,7 +126,7 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, void chsc_chp_online(struct chp_id chpid); void chsc_chp_offline(struct chp_id chpid); int chsc_get_channel_measurement_chars(struct channel_path *chp); - +int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd); int chsc_error_from_response(int response); int chsc_siosl(struct subchannel_id schid); diff --git a/drivers/s390/cio/qdio.h b/drivers/s390/cio/qdio.h index 5132554d7917..b8bda2175b6c 100644 --- a/drivers/s390/cio/qdio.h +++ b/drivers/s390/cio/qdio.h @@ -140,20 +140,6 @@ struct siga_flag { u8:3; } __attribute__ ((packed)); -struct chsc_ssqd_area { - struct chsc_header request; - u16:10; - u8 ssid:2; - u8 fmt:4; - u16 first_sch; - u16:16; - u16 last_sch; - u32:32; - struct chsc_header response; - u32:32; - struct qdio_ssqd_desc qdio_ssqd; -} __attribute__ ((packed)); - struct scssc_area { struct chsc_header request; u16 operation_code; diff --git a/drivers/s390/cio/qdio_setup.c b/drivers/s390/cio/qdio_setup.c index 16ecd35b8e51..f5f4a91fab44 100644 --- a/drivers/s390/cio/qdio_setup.c +++ b/drivers/s390/cio/qdio_setup.c @@ -254,40 +254,31 @@ int qdio_setup_get_ssqd(struct qdio_irq *irq_ptr, int rc; DBF_EVENT("getssqd:%4x", schid->sch_no); - if (irq_ptr != NULL) - ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; - else + if (!irq_ptr) { ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); - memset(ssqd, 0, PAGE_SIZE); - - ssqd->request = (struct chsc_header) { - .length = 0x0010, - .code = 0x0024, - }; - ssqd->first_sch = schid->sch_no; - ssqd->last_sch = schid->sch_no; - ssqd->ssid = schid->ssid; - - if (chsc(ssqd)) - return -EIO; - rc = chsc_error_from_response(ssqd->response.code); + if (!ssqd) + return -ENOMEM; + } else { + ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; + } + + rc = chsc_ssqd(*schid, ssqd); if (rc) - return rc; + goto out; if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || (ssqd->qdio_ssqd.sch != schid->sch_no)) - return -EINVAL; - - if (irq_ptr != NULL) - memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, - sizeof(struct qdio_ssqd_desc)); - else { - memcpy(data, &ssqd->qdio_ssqd, - sizeof(struct qdio_ssqd_desc)); + rc = -EINVAL; + + if (!rc) + memcpy(data, &ssqd->qdio_ssqd, sizeof(*data)); + +out: + if (!irq_ptr) free_page((unsigned long)ssqd); - } - return 0; + + return rc; } void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) @@ -295,7 +286,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) unsigned char qdioac; int rc; - rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); + rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc); if (rc) { DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); DBF_ERROR("rc:%x", rc); |