diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2013-06-05 12:58:35 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2013-06-26 15:10:14 -0400 |
commit | da5b6cb162b6bef39d76446a5e015d6a111459b1 (patch) | |
tree | dae7bc447358be3c4f2a25e27c9a2d2bf1e1034b /drivers/s390 | |
parent | d475f942b1dd6a897dac3ad4ed98d6994b275378 (diff) |
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>
Diffstat (limited to 'drivers/s390')
-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: | |||
144 | return ret; | 144 | return ret; |
145 | } | 145 | } |
146 | 146 | ||
147 | /** | ||
148 | * chsc_ssqd() - store subchannel QDIO data (SSQD) | ||
149 | * @schid: id of the subchannel on which SSQD is performed | ||
150 | * @ssqd: request and response block for SSQD | ||
151 | * | ||
152 | * Returns 0 on success. | ||
153 | */ | ||
154 | int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd) | ||
155 | { | ||
156 | memset(ssqd, 0, sizeof(*ssqd)); | ||
157 | ssqd->request.length = 0x0010; | ||
158 | ssqd->request.code = 0x0024; | ||
159 | ssqd->first_sch = schid.sch_no; | ||
160 | ssqd->last_sch = schid.sch_no; | ||
161 | ssqd->ssid = schid.ssid; | ||
162 | |||
163 | if (chsc(ssqd)) | ||
164 | return -EIO; | ||
165 | |||
166 | return chsc_error_from_response(ssqd->response.code); | ||
167 | } | ||
168 | EXPORT_SYMBOL_GPL(chsc_ssqd); | ||
169 | |||
147 | static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) | 170 | static int s390_subchannel_remove_chpid(struct subchannel *sch, void *data) |
148 | { | 171 | { |
149 | spin_lock_irq(sch->lock); | 172 | 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 @@ | |||
7 | #include <asm/chpid.h> | 7 | #include <asm/chpid.h> |
8 | #include <asm/chsc.h> | 8 | #include <asm/chsc.h> |
9 | #include <asm/schid.h> | 9 | #include <asm/schid.h> |
10 | #include <asm/qdio.h> | ||
10 | 11 | ||
11 | #define CHSC_SDA_OC_MSS 0x2 | 12 | #define CHSC_SDA_OC_MSS 0x2 |
12 | 13 | ||
@@ -72,6 +73,20 @@ struct chsc_ssd_info { | |||
72 | u16 fla[8]; | 73 | u16 fla[8]; |
73 | }; | 74 | }; |
74 | 75 | ||
76 | struct chsc_ssqd_area { | ||
77 | struct chsc_header request; | ||
78 | u16:10; | ||
79 | u8 ssid:2; | ||
80 | u8 fmt:4; | ||
81 | u16 first_sch; | ||
82 | u16:16; | ||
83 | u16 last_sch; | ||
84 | u32:32; | ||
85 | struct chsc_header response; | ||
86 | u32:32; | ||
87 | struct qdio_ssqd_desc qdio_ssqd; | ||
88 | } __packed; | ||
89 | |||
75 | struct chsc_scpd { | 90 | struct chsc_scpd { |
76 | struct chsc_header request; | 91 | struct chsc_header request; |
77 | u32:2; | 92 | u32:2; |
@@ -111,7 +126,7 @@ int chsc_determine_fmt1_channel_path_desc(struct chp_id chpid, | |||
111 | void chsc_chp_online(struct chp_id chpid); | 126 | void chsc_chp_online(struct chp_id chpid); |
112 | void chsc_chp_offline(struct chp_id chpid); | 127 | void chsc_chp_offline(struct chp_id chpid); |
113 | int chsc_get_channel_measurement_chars(struct channel_path *chp); | 128 | int chsc_get_channel_measurement_chars(struct channel_path *chp); |
114 | 129 | int chsc_ssqd(struct subchannel_id schid, struct chsc_ssqd_area *ssqd); | |
115 | int chsc_error_from_response(int response); | 130 | int chsc_error_from_response(int response); |
116 | 131 | ||
117 | int chsc_siosl(struct subchannel_id schid); | 132 | 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 { | |||
140 | u8:3; | 140 | u8:3; |
141 | } __attribute__ ((packed)); | 141 | } __attribute__ ((packed)); |
142 | 142 | ||
143 | struct chsc_ssqd_area { | ||
144 | struct chsc_header request; | ||
145 | u16:10; | ||
146 | u8 ssid:2; | ||
147 | u8 fmt:4; | ||
148 | u16 first_sch; | ||
149 | u16:16; | ||
150 | u16 last_sch; | ||
151 | u32:32; | ||
152 | struct chsc_header response; | ||
153 | u32:32; | ||
154 | struct qdio_ssqd_desc qdio_ssqd; | ||
155 | } __attribute__ ((packed)); | ||
156 | |||
157 | struct scssc_area { | 143 | struct scssc_area { |
158 | struct chsc_header request; | 144 | struct chsc_header request; |
159 | u16 operation_code; | 145 | 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, | |||
254 | int rc; | 254 | int rc; |
255 | 255 | ||
256 | DBF_EVENT("getssqd:%4x", schid->sch_no); | 256 | DBF_EVENT("getssqd:%4x", schid->sch_no); |
257 | if (irq_ptr != NULL) | 257 | if (!irq_ptr) { |
258 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; | ||
259 | else | ||
260 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); | 258 | ssqd = (struct chsc_ssqd_area *)__get_free_page(GFP_KERNEL); |
261 | memset(ssqd, 0, PAGE_SIZE); | 259 | if (!ssqd) |
262 | 260 | return -ENOMEM; | |
263 | ssqd->request = (struct chsc_header) { | 261 | } else { |
264 | .length = 0x0010, | 262 | ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page; |
265 | .code = 0x0024, | 263 | } |
266 | }; | 264 | |
267 | ssqd->first_sch = schid->sch_no; | 265 | rc = chsc_ssqd(*schid, ssqd); |
268 | ssqd->last_sch = schid->sch_no; | ||
269 | ssqd->ssid = schid->ssid; | ||
270 | |||
271 | if (chsc(ssqd)) | ||
272 | return -EIO; | ||
273 | rc = chsc_error_from_response(ssqd->response.code); | ||
274 | if (rc) | 266 | if (rc) |
275 | return rc; | 267 | goto out; |
276 | 268 | ||
277 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || | 269 | if (!(ssqd->qdio_ssqd.flags & CHSC_FLAG_QDIO_CAPABILITY) || |
278 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || | 270 | !(ssqd->qdio_ssqd.flags & CHSC_FLAG_VALIDITY) || |
279 | (ssqd->qdio_ssqd.sch != schid->sch_no)) | 271 | (ssqd->qdio_ssqd.sch != schid->sch_no)) |
280 | return -EINVAL; | 272 | rc = -EINVAL; |
281 | 273 | ||
282 | if (irq_ptr != NULL) | 274 | if (!rc) |
283 | memcpy(&irq_ptr->ssqd_desc, &ssqd->qdio_ssqd, | 275 | memcpy(data, &ssqd->qdio_ssqd, sizeof(*data)); |
284 | sizeof(struct qdio_ssqd_desc)); | 276 | |
285 | else { | 277 | out: |
286 | memcpy(data, &ssqd->qdio_ssqd, | 278 | if (!irq_ptr) |
287 | sizeof(struct qdio_ssqd_desc)); | ||
288 | free_page((unsigned long)ssqd); | 279 | free_page((unsigned long)ssqd); |
289 | } | 280 | |
290 | return 0; | 281 | return rc; |
291 | } | 282 | } |
292 | 283 | ||
293 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | 284 | void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) |
@@ -295,7 +286,7 @@ void qdio_setup_ssqd_info(struct qdio_irq *irq_ptr) | |||
295 | unsigned char qdioac; | 286 | unsigned char qdioac; |
296 | int rc; | 287 | int rc; |
297 | 288 | ||
298 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, NULL); | 289 | rc = qdio_setup_get_ssqd(irq_ptr, &irq_ptr->schid, &irq_ptr->ssqd_desc); |
299 | if (rc) { | 290 | if (rc) { |
300 | DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); | 291 | DBF_ERROR("%4x ssqd ERR", irq_ptr->schid.sch_no); |
301 | DBF_ERROR("rc:%x", rc); | 292 | DBF_ERROR("rc:%x", rc); |