mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 13:11:40 +00:00
[S390] Cleanup of CHSC event handling.
Change CHSC event handling to be more easily extensible. Signed-off-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
parent
0f008aa300
commit
184357a596
@ -461,144 +461,136 @@ __get_chpid_from_lir(void *data)
|
||||
return (u16) (lir->indesc[0]&0x000000ff);
|
||||
}
|
||||
|
||||
int
|
||||
chsc_process_crw(void)
|
||||
struct chsc_sei_area {
|
||||
struct chsc_header request;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
struct chsc_header response;
|
||||
u32 reserved4;
|
||||
u8 flags;
|
||||
u8 vf; /* validity flags */
|
||||
u8 rs; /* reporting source */
|
||||
u8 cc; /* content code */
|
||||
u16 fla; /* full link address */
|
||||
u16 rsid; /* reporting source id */
|
||||
u32 reserved5;
|
||||
u32 reserved6;
|
||||
u8 ccdf[4096 - 16 - 24]; /* content-code dependent field */
|
||||
/* ccdf has to be big enough for a link-incident record */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
|
||||
{
|
||||
int chpid;
|
||||
|
||||
CIO_CRW_EVENT(4, "chsc: link incident (rs=%02x, rs_id=%04x)\n",
|
||||
sei_area->rs, sei_area->rsid);
|
||||
if (sei_area->rs != 4)
|
||||
return 0;
|
||||
chpid = __get_chpid_from_lir(sei_area->ccdf);
|
||||
if (chpid < 0)
|
||||
CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
|
||||
else
|
||||
s390_set_chpid_offline(chpid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
|
||||
{
|
||||
int chpid, ret;
|
||||
struct res_acc_data res_data;
|
||||
struct {
|
||||
struct chsc_header request;
|
||||
u32 reserved1;
|
||||
u32 reserved2;
|
||||
u32 reserved3;
|
||||
struct chsc_header response;
|
||||
u32 reserved4;
|
||||
u8 flags;
|
||||
u8 vf; /* validity flags */
|
||||
u8 rs; /* reporting source */
|
||||
u8 cc; /* content code */
|
||||
u16 fla; /* full link address */
|
||||
u16 rsid; /* reporting source id */
|
||||
u32 reserved5;
|
||||
u32 reserved6;
|
||||
u32 ccdf[96]; /* content-code dependent field */
|
||||
/* ccdf has to be big enough for a link-incident record */
|
||||
} __attribute__ ((packed)) *sei_area;
|
||||
struct device *dev;
|
||||
int status;
|
||||
int rc;
|
||||
|
||||
CIO_CRW_EVENT(4, "chsc: resource accessibility event (rs=%02x, "
|
||||
"rs_id=%04x)\n", sei_area->rs, sei_area->rsid);
|
||||
if (sei_area->rs != 4)
|
||||
return 0;
|
||||
/* allocate a new channel path structure, if needed */
|
||||
status = get_chp_status(sei_area->rsid);
|
||||
if (status < 0)
|
||||
new_channel_path(sei_area->rsid);
|
||||
else if (!status)
|
||||
return 0;
|
||||
dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
|
||||
memset(&res_data, 0, sizeof(struct res_acc_data));
|
||||
res_data.chp = to_channelpath(dev);
|
||||
if ((sei_area->vf & 0xc0) != 0) {
|
||||
res_data.fla = sei_area->fla;
|
||||
if ((sei_area->vf & 0xc0) == 0xc0)
|
||||
/* full link address */
|
||||
res_data.fla_mask = 0xffff;
|
||||
else
|
||||
/* link address */
|
||||
res_data.fla_mask = 0xff00;
|
||||
}
|
||||
rc = s390_process_res_acc(&res_data);
|
||||
put_device(dev);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int chsc_process_sei(struct chsc_sei_area *sei_area)
|
||||
{
|
||||
int rc;
|
||||
|
||||
/* Check if we might have lost some information. */
|
||||
if (sei_area->flags & 0x40)
|
||||
CIO_CRW_EVENT(2, "chsc: event overflow\n");
|
||||
/* which kind of information was stored? */
|
||||
rc = 0;
|
||||
switch (sei_area->cc) {
|
||||
case 1: /* link incident*/
|
||||
rc = chsc_process_sei_link_incident(sei_area);
|
||||
break;
|
||||
case 2: /* i/o resource accessibiliy */
|
||||
rc = chsc_process_sei_res_acc(sei_area);
|
||||
break;
|
||||
default: /* other stuff */
|
||||
CIO_CRW_EVENT(4, "chsc: unhandled sei content code %d\n",
|
||||
sei_area->cc);
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int chsc_process_crw(void)
|
||||
{
|
||||
struct chsc_sei_area *sei_area;
|
||||
int ret;
|
||||
int rc;
|
||||
|
||||
if (!sei_page)
|
||||
return 0;
|
||||
/*
|
||||
* build the chsc request block for store event information
|
||||
* and do the call
|
||||
* This function is only called by the machine check handler thread,
|
||||
* so we don't need locking for the sei_page.
|
||||
*/
|
||||
/* Access to sei_page is serialized through machine check handler
|
||||
* thread, so no need for locking. */
|
||||
sei_area = sei_page;
|
||||
|
||||
CIO_TRACE_EVENT( 2, "prcss");
|
||||
ret = 0;
|
||||
do {
|
||||
int ccode, status;
|
||||
struct device *dev;
|
||||
memset(sei_area, 0, sizeof(*sei_area));
|
||||
memset(&res_data, 0, sizeof(struct res_acc_data));
|
||||
sei_area->request.length = 0x0010;
|
||||
sei_area->request.code = 0x000e;
|
||||
if (chsc(sei_area))
|
||||
break;
|
||||
|
||||
ccode = chsc(sei_area);
|
||||
if (ccode > 0)
|
||||
return 0;
|
||||
|
||||
switch (sei_area->response.code) {
|
||||
/* for debug purposes, check for problems */
|
||||
case 0x0001:
|
||||
CIO_CRW_EVENT(4, "chsc_process_crw: event information "
|
||||
"successfully stored\n");
|
||||
break; /* everything ok */
|
||||
case 0x0002:
|
||||
CIO_CRW_EVENT(2,
|
||||
"chsc_process_crw: invalid command!\n");
|
||||
return 0;
|
||||
case 0x0003:
|
||||
CIO_CRW_EVENT(2, "chsc_process_crw: error in chsc "
|
||||
"request block!\n");
|
||||
return 0;
|
||||
case 0x0005:
|
||||
CIO_CRW_EVENT(2, "chsc_process_crw: no event "
|
||||
"information stored\n");
|
||||
return 0;
|
||||
default:
|
||||
CIO_CRW_EVENT(2, "chsc_process_crw: chsc response %d\n",
|
||||
if (sei_area->response.code == 0x0001) {
|
||||
CIO_CRW_EVENT(4, "chsc: sei successful\n");
|
||||
rc = chsc_process_sei(sei_area);
|
||||
if (rc)
|
||||
ret = rc;
|
||||
} else {
|
||||
CIO_CRW_EVENT(2, "chsc: sei failed (rc=%04x)\n",
|
||||
sei_area->response.code);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check if we might have lost some information. */
|
||||
if (sei_area->flags & 0x40)
|
||||
CIO_CRW_EVENT(2, "chsc_process_crw: Event information "
|
||||
"has been lost due to overflow!\n");
|
||||
|
||||
if (sei_area->rs != 4) {
|
||||
CIO_CRW_EVENT(2, "chsc_process_crw: reporting source "
|
||||
"(%04X) isn't a chpid!\n",
|
||||
sei_area->rsid);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* which kind of information was stored? */
|
||||
switch (sei_area->cc) {
|
||||
case 1: /* link incident*/
|
||||
CIO_CRW_EVENT(4, "chsc_process_crw: "
|
||||
"channel subsystem reports link incident,"
|
||||
" reporting source is chpid %x\n",
|
||||
sei_area->rsid);
|
||||
chpid = __get_chpid_from_lir(sei_area->ccdf);
|
||||
if (chpid < 0)
|
||||
CIO_CRW_EVENT(4, "%s: Invalid LIR, skipping\n",
|
||||
__FUNCTION__);
|
||||
else
|
||||
s390_set_chpid_offline(chpid);
|
||||
break;
|
||||
|
||||
case 2: /* i/o resource accessibiliy */
|
||||
CIO_CRW_EVENT(4, "chsc_process_crw: "
|
||||
"channel subsystem reports some I/O "
|
||||
"devices may have become accessible\n");
|
||||
pr_debug("Data received after sei: \n");
|
||||
pr_debug("Validity flags: %x\n", sei_area->vf);
|
||||
|
||||
/* allocate a new channel path structure, if needed */
|
||||
status = get_chp_status(sei_area->rsid);
|
||||
if (status < 0)
|
||||
new_channel_path(sei_area->rsid);
|
||||
else if (!status)
|
||||
break;
|
||||
dev = get_device(&css[0]->chps[sei_area->rsid]->dev);
|
||||
res_data.chp = to_channelpath(dev);
|
||||
pr_debug("chpid: %x", sei_area->rsid);
|
||||
if ((sei_area->vf & 0xc0) != 0) {
|
||||
res_data.fla = sei_area->fla;
|
||||
if ((sei_area->vf & 0xc0) == 0xc0) {
|
||||
pr_debug(" full link addr: %x",
|
||||
sei_area->fla);
|
||||
res_data.fla_mask = 0xffff;
|
||||
} else {
|
||||
pr_debug(" link addr: %x",
|
||||
sei_area->fla);
|
||||
res_data.fla_mask = 0xff00;
|
||||
}
|
||||
}
|
||||
ret = s390_process_res_acc(&res_data);
|
||||
pr_debug("\n\n");
|
||||
put_device(dev);
|
||||
break;
|
||||
|
||||
default: /* other stuff */
|
||||
CIO_CRW_EVENT(4, "chsc_process_crw: event %d\n",
|
||||
sei_area->cc);
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
} while (sei_area->flags & 0x80);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user