mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-13 16:50:05 +00:00
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:
parent
d475f942b1
commit
da5b6cb162
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user