s390/qdio: cleanup chsc SSQD usage
authorSebastian Ott <sebott@linux.vnet.ibm.com>
Wed, 5 Jun 2013 16:58:35 +0000 (18:58 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 26 Jun 2013 19:10:14 +0000 (21:10 +0200)
Cleanup the function qdio_setup_get_ssqd. Fix some possible
memleaks and an unchecked allocation and create a wrapper
for SSQD in chsc.c .

Reviewed-by: Ursula Braun <ursula.braun@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
drivers/s390/cio/chsc.c
drivers/s390/cio/chsc.h
drivers/s390/cio/qdio.h
drivers/s390/cio/qdio_setup.c

index 8ea7d9b2c671a3555c7c5d2c57b505d9f338033c..d119d0d87e9bf68b784b615d60122ad63f8770d7 100644 (file)
@@ -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);
index 62d096f11e65bc66542fe2877a2dfd7ce214f02c..2b88e74e6b6559d6c07ad544c9b81535fb7ae259 100644 (file)
@@ -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);
index 5132554d7917f0994f543aea947dcdfdcdcb17d4..b8bda2175b6ce80fdbe74a9188fff633c7e02a72 100644 (file)
@@ -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;
index 16ecd35b8e5137dbd675f2e51527224ea0370557..f5f4a91fab44e71b3c7d8ca5e307c19b2b139912 100644 (file)
@@ -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);