Browse Source

s390/qdio: cleanup chsc SSQD usage

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>
Sebastian Ott 12 years ago
parent
commit
da5b6cb162
4 changed files with 58 additions and 43 deletions
  1. 23 0
      drivers/s390/cio/chsc.c
  2. 16 1
      drivers/s390/cio/chsc.h
  3. 0 14
      drivers/s390/cio/qdio.h
  4. 19 28
      drivers/s390/cio/qdio_setup.c

+ 23 - 0
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);

+ 16 - 1
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);

+ 0 - 14
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;

+ 19 - 28
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);