Commit 99611f87 authored by Cornelia Huck's avatar Cornelia Huck Committed by Heiko Carstens
Browse files

[S390] cio: Repair chpid event handling.



Passing the affected chpid in chp_event() worked only by
chance since chpid is the first element in res_acc_data.
Make it work properly by generalizing res_acc_data as
chp_link and always passing around a properly filled out
chp_link structure in chp_event().
Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
parent 6ef556cc
...@@ -525,7 +525,7 @@ static void chp_process_crw(struct crw *crw0, struct crw *crw1, ...@@ -525,7 +525,7 @@ static void chp_process_crw(struct crw *crw0, struct crw *crw1,
} }
} }
int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data) int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct chp_link *link)
{ {
int i; int i;
int mask; int mask;
...@@ -534,10 +534,10 @@ int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data) ...@@ -534,10 +534,10 @@ int chp_ssd_get_mask(struct chsc_ssd_info *ssd, struct res_acc_data *data)
mask = 0x80 >> i; mask = 0x80 >> i;
if (!(ssd->path_mask & mask)) if (!(ssd->path_mask & mask))
continue; continue;
if (!chp_id_is_equal(&ssd->chpid[i], &data->chpid)) if (!chp_id_is_equal(&ssd->chpid[i], &link->chpid))
continue; continue;
if ((ssd->fla_valid_mask & mask) && if ((ssd->fla_valid_mask & mask) &&
((ssd->fla[i] & data->fla_mask) != data->fla)) ((ssd->fla[i] & link->fla_mask) != link->fla))
continue; continue;
return mask; return mask;
} }
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#define CHP_VARY_ON 2 #define CHP_VARY_ON 2
#define CHP_VARY_OFF 3 #define CHP_VARY_OFF 3
struct res_acc_data { struct chp_link {
struct chp_id chpid; struct chp_id chpid;
u32 fla_mask; u32 fla_mask;
u16 fla; u16 fla;
...@@ -60,5 +60,5 @@ int chp_new(struct chp_id chpid); ...@@ -60,5 +60,5 @@ int chp_new(struct chp_id chpid);
void chp_cfg_schedule(struct chp_id chpid, int configure); void chp_cfg_schedule(struct chp_id chpid, int configure);
void chp_cfg_cancel_deconfigure(struct chp_id chpid); void chp_cfg_cancel_deconfigure(struct chp_id chpid);
int chp_info_get_status(struct chp_id chpid); int chp_info_get_status(struct chp_id chpid);
int chp_ssd_get_mask(struct chsc_ssd_info *, struct res_acc_data *); int chp_ssd_get_mask(struct chsc_ssd_info *, struct chp_link *);
#endif /* S390_CHP_H */ #endif /* S390_CHP_H */
...@@ -146,15 +146,18 @@ out_unreg: ...@@ -146,15 +146,18 @@ out_unreg:
void chsc_chp_offline(struct chp_id chpid) void chsc_chp_offline(struct chp_id chpid)
{ {
char dbf_txt[15]; char dbf_txt[15];
struct chp_link link;
sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id); sprintf(dbf_txt, "chpr%x.%02x", chpid.cssid, chpid.id);
CIO_TRACE_EVENT(2, dbf_txt); CIO_TRACE_EVENT(2, dbf_txt);
if (chp_get_status(chpid) <= 0) if (chp_get_status(chpid) <= 0)
return; return;
memset(&link, 0, sizeof(struct chp_link));
link.chpid = chpid;
/* Wait until previous actions have settled. */ /* Wait until previous actions have settled. */
css_wait_for_slow_path(); css_wait_for_slow_path();
for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &chpid); for_each_subchannel_staged(s390_subchannel_remove_chpid, NULL, &link);
} }
static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data) static int s390_process_res_acc_new_sch(struct subchannel_id schid, void *data)
...@@ -187,15 +190,15 @@ static int __s390_process_res_acc(struct subchannel *sch, void *data) ...@@ -187,15 +190,15 @@ static int __s390_process_res_acc(struct subchannel *sch, void *data)
return 0; return 0;
} }
static void s390_process_res_acc (struct res_acc_data *res_data) static void s390_process_res_acc(struct chp_link *link)
{ {
char dbf_txt[15]; char dbf_txt[15];
sprintf(dbf_txt, "accpr%x.%02x", res_data->chpid.cssid, sprintf(dbf_txt, "accpr%x.%02x", link->chpid.cssid,
res_data->chpid.id); link->chpid.id);
CIO_TRACE_EVENT( 2, dbf_txt); CIO_TRACE_EVENT( 2, dbf_txt);
if (res_data->fla != 0) { if (link->fla != 0) {
sprintf(dbf_txt, "fla%x", res_data->fla); sprintf(dbf_txt, "fla%x", link->fla);
CIO_TRACE_EVENT( 2, dbf_txt); CIO_TRACE_EVENT( 2, dbf_txt);
} }
/* Wait until previous actions have settled. */ /* Wait until previous actions have settled. */
...@@ -208,7 +211,7 @@ static void s390_process_res_acc (struct res_acc_data *res_data) ...@@ -208,7 +211,7 @@ static void s390_process_res_acc (struct res_acc_data *res_data)
* will we have to do. * will we have to do.
*/ */
for_each_subchannel_staged(__s390_process_res_acc, for_each_subchannel_staged(__s390_process_res_acc,
s390_process_res_acc_new_sch, res_data); s390_process_res_acc_new_sch, link);
} }
static int static int
...@@ -281,7 +284,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area) ...@@ -281,7 +284,7 @@ static void chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{ {
struct res_acc_data res_data; struct chp_link link;
struct chp_id chpid; struct chp_id chpid;
int status; int status;
...@@ -297,18 +300,18 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area) ...@@ -297,18 +300,18 @@ static void chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
chp_new(chpid); chp_new(chpid);
else if (!status) else if (!status)
return; return;
memset(&res_data, 0, sizeof(struct res_acc_data)); memset(&link, 0, sizeof(struct chp_link));
res_data.chpid = chpid; link.chpid = chpid;
if ((sei_area->vf & 0xc0) != 0) { if ((sei_area->vf & 0xc0) != 0) {
res_data.fla = sei_area->fla; link.fla = sei_area->fla;
if ((sei_area->vf & 0xc0) == 0xc0) if ((sei_area->vf & 0xc0) == 0xc0)
/* full link address */ /* full link address */
res_data.fla_mask = 0xffff; link.fla_mask = 0xffff;
else else
/* link address */ /* link address */
res_data.fla_mask = 0xff00; link.fla_mask = 0xff00;
} }
s390_process_res_acc(&res_data); s390_process_res_acc(&link);
} }
struct chp_config_data { struct chp_config_data {
...@@ -413,18 +416,18 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow) ...@@ -413,18 +416,18 @@ static void chsc_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
void chsc_chp_online(struct chp_id chpid) void chsc_chp_online(struct chp_id chpid)
{ {
char dbf_txt[15]; char dbf_txt[15];
struct res_acc_data res_data; struct chp_link link;
sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id); sprintf(dbf_txt, "cadd%x.%02x", chpid.cssid, chpid.id);
CIO_TRACE_EVENT(2, dbf_txt); CIO_TRACE_EVENT(2, dbf_txt);
if (chp_get_status(chpid) != 0) { if (chp_get_status(chpid) != 0) {
memset(&res_data, 0, sizeof(struct res_acc_data)); memset(&link, 0, sizeof(struct chp_link));
res_data.chpid = chpid; link.chpid = chpid;
/* Wait until previous actions have settled. */ /* Wait until previous actions have settled. */
css_wait_for_slow_path(); css_wait_for_slow_path();
for_each_subchannel_staged(__s390_process_res_acc, NULL, for_each_subchannel_staged(__s390_process_res_acc, NULL,
&res_data); &link);
} }
} }
...@@ -432,13 +435,13 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch, ...@@ -432,13 +435,13 @@ static void __s390_subchannel_vary_chpid(struct subchannel *sch,
struct chp_id chpid, int on) struct chp_id chpid, int on)
{ {
unsigned long flags; unsigned long flags;
struct res_acc_data res_data; struct chp_link link;
memset(&res_data, 0, sizeof(struct res_acc_data)); memset(&link, 0, sizeof(struct chp_link));
res_data.chpid = chpid; link.chpid = chpid;
spin_lock_irqsave(sch->lock, flags); spin_lock_irqsave(sch->lock, flags);
if (sch->driver && sch->driver->chp_event) if (sch->driver && sch->driver->chp_event)
sch->driver->chp_event(sch, &res_data, sch->driver->chp_event(sch, &link,
on ? CHP_VARY_ON : CHP_VARY_OFF); on ? CHP_VARY_ON : CHP_VARY_OFF);
spin_unlock_irqrestore(sch->lock, flags); spin_unlock_irqrestore(sch->lock, flags);
} }
...@@ -479,6 +482,10 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data) ...@@ -479,6 +482,10 @@ __s390_vary_chpid_on(struct subchannel_id schid, void *data)
*/ */
int chsc_chp_vary(struct chp_id chpid, int on) int chsc_chp_vary(struct chp_id chpid, int on)
{ {
struct chp_link link;
memset(&link, 0, sizeof(struct chp_link));
link.chpid = chpid;
/* Wait until previous actions have settled. */ /* Wait until previous actions have settled. */
css_wait_for_slow_path(); css_wait_for_slow_path();
/* /*
...@@ -487,10 +494,10 @@ int chsc_chp_vary(struct chp_id chpid, int on) ...@@ -487,10 +494,10 @@ int chsc_chp_vary(struct chp_id chpid, int on)
if (on) if (on)
for_each_subchannel_staged(s390_subchannel_vary_chpid_on, for_each_subchannel_staged(s390_subchannel_vary_chpid_on,
__s390_vary_chpid_on, &chpid); __s390_vary_chpid_on, &link);
else else
for_each_subchannel_staged(s390_subchannel_vary_chpid_off, for_each_subchannel_staged(s390_subchannel_vary_chpid_off,
NULL, &chpid); NULL, &link);
return 0; return 0;
} }
......
...@@ -59,6 +59,7 @@ struct pgid { ...@@ -59,6 +59,7 @@ struct pgid {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct subchannel; struct subchannel;
struct chp_link;
/** /**
* struct css_driver - device driver for subchannels * struct css_driver - device driver for subchannels
* @owner: owning module * @owner: owning module
...@@ -77,7 +78,7 @@ struct css_driver { ...@@ -77,7 +78,7 @@ struct css_driver {
unsigned int subchannel_type; unsigned int subchannel_type;
struct device_driver drv; struct device_driver drv;
void (*irq)(struct subchannel *); void (*irq)(struct subchannel *);
int (*chp_event)(struct subchannel *, void *, int); int (*chp_event)(struct subchannel *, struct chp_link *, int);
int (*sch_event)(struct subchannel *, int); int (*sch_event)(struct subchannel *, int);
int (*probe)(struct subchannel *); int (*probe)(struct subchannel *);
int (*remove)(struct subchannel *); int (*remove)(struct subchannel *);
......
...@@ -128,7 +128,8 @@ static int io_subchannel_probe(struct subchannel *); ...@@ -128,7 +128,8 @@ static int io_subchannel_probe(struct subchannel *);
static int io_subchannel_remove(struct subchannel *); static int io_subchannel_remove(struct subchannel *);
static void io_subchannel_shutdown(struct subchannel *); static void io_subchannel_shutdown(struct subchannel *);
static int io_subchannel_sch_event(struct subchannel *, int); static int io_subchannel_sch_event(struct subchannel *, int);
static int io_subchannel_chp_event(struct subchannel *, void *, int); static int io_subchannel_chp_event(struct subchannel *, struct chp_link *,
int);
static struct css_driver io_subchannel_driver = { static struct css_driver io_subchannel_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -1329,14 +1330,12 @@ static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask) ...@@ -1329,14 +1330,12 @@ static void io_subchannel_terminate_path(struct subchannel *sch, u8 mask)
} }
static int io_subchannel_chp_event(struct subchannel *sch, void *data, static int io_subchannel_chp_event(struct subchannel *sch,
int event) struct chp_link *link, int event)
{ {
int mask; int mask;
struct res_acc_data *res_data;
res_data = data; mask = chp_ssd_get_mask(&sch->ssd_info, link);
mask = chp_ssd_get_mask(&sch->ssd_info, res_data);
if (!mask) if (!mask)
return 0; return 0;
switch (event) { switch (event) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment