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>
This commit is contained in:
Sebastian Ott 2013-06-05 18:58:35 +02:00 committed by Martin Schwidefsky
parent d475f942b1
commit da5b6cb162
4 changed files with 56 additions and 41 deletions

View 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);

View 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);

View 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;

View 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);
if (!ssqd)
return -ENOMEM;
} else {
ssqd = (struct chsc_ssqd_area *)irq_ptr->chsc_page;
}
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);
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;
rc = -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));
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);