Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 184357a5 authored by Peter Oberparleiter's avatar Peter Oberparleiter Committed by Martin Schwidefsky
Browse files

[S390] Cleanup of CHSC event handling.



Change CHSC event handling to be more easily extensible.

Signed-off-by: default avatarPeter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 0f008aa3
Loading
Loading
Loading
Loading
+112 −120
Original line number Diff line number Diff line
@@ -461,12 +461,7 @@ __get_chpid_from_lir(void *data)
	return (u16) (lir->indesc[0]&0x000000ff);
}

int
chsc_process_crw(void)
{
	int chpid, ret;
	struct res_acc_data res_data;
	struct {
struct chsc_sei_area {
	struct chsc_header request;
	u32 reserved1;
	u32 reserved2;
@@ -481,124 +476,121 @@ chsc_process_crw(void)
	u16 rsid;	/* reporting source id */
	u32 reserved5;
	u32 reserved6;
		u32 ccdf[96];	/* content-code dependent field */
	u8 ccdf[4096 - 16 - 24];	/* content-code dependent field */
	/* ccdf has to be big enough for a link-incident record */
	} __attribute__ ((packed)) *sei_area;
} __attribute__ ((packed));

	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.
	 */
	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;

		ccode = chsc(sei_area);
		if (ccode > 0)
			return 0;
static int chsc_process_sei_link_incident(struct chsc_sei_area *sei_area)
{
	int chpid;

		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");
	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;
		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",
				      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__);
		CIO_CRW_EVENT(4, "chsc: link incident - invalid LIR\n");
	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);
	return 0;
}

static int chsc_process_sei_res_acc(struct chsc_sei_area *sei_area)
{
	struct res_acc_data res_data;
	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)
				break;
		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);
			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);
		if ((sei_area->vf & 0xc0) == 0xc0)
			/* full link address */
			res_data.fla_mask = 0xffff;
				} else {
					pr_debug(" link addr: %x",
						 sei_area->fla);
		else
			/* link address */
			res_data.fla_mask = 0xff00;
	}
			}
			ret = s390_process_res_acc(&res_data);
			pr_debug("\n\n");
	rc = s390_process_res_acc(&res_data);
	put_device(dev);
			break;

	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_process_crw: event %d\n",
		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;
	/* 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 {
		memset(sei_area, 0, sizeof(*sei_area));
		sei_area->request.length = 0x0010;
		sei_area->request.code = 0x000e;
		if (chsc(sei_area))
			break;

		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);
			ret = 0;
			break;
		}
	} while (sei_area->flags & 0x80);

	return ret;
}