[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:
Peter Oberparleiter 2007-02-05 21:17:42 +01:00 committed by Martin Schwidefsky
parent 0f008aa300
commit 184357a596

View File

@ -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;
}