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

Commit 9d92a7e1 authored by Cornelia Huck's avatar Cornelia Huck Committed by Heiko Carstens
Browse files

[S390] cio: Add chsc subchannel driver.



This patch adds a driver for subchannels of type chsc.

A device /dev/chsc is created which may be used to issue ioctls to:
- obtain information about the machine's I/O configuration
- dynamically change the machine's I/O configuration via
  asynchronous chsc commands

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 683c5418
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -117,6 +117,7 @@ Code Seq# Include File Comments
					<mailto:natalia@nikhefk.nikhef.nl>
'c'	00-7F	linux/comstats.h	conflict!
'c'	00-7F	linux/coda.h		conflict!
'c'	80-9F	asm-s390/chsc.h
'd'	00-FF	linux/char/drm/drm/h	conflict!
'd'	00-DF	linux/video_decoder.h	conflict!
'd'	F0-FF	linux/digi1.h
+16 −0
Original line number Diff line number Diff line
@@ -345,6 +345,22 @@ config QDIO_DEBUG

	  If unsure, say N.

config CHSC_SCH
	tristate "Support for CHSC subchannels"
	help
	  This driver allows usage of CHSC subchannels. A CHSC subchannel
	  is usually present on LPAR only.
	  The driver creates a device /dev/chsc, which may be used to
	  obtain I/O configuration information about the machine and
	  to issue asynchronous chsc commands (DANGEROUS).
	  You will usually only want to use this interface on a special
	  LPAR designated for system management.

	  To compile this driver as a module, choose M here: the
	  module will be called chsc_sch.

	  If unsure, say N.

comment "Misc"

config IPL
+1 −0
Original line number Diff line number Diff line
@@ -7,5 +7,6 @@ obj-y += airq.o blacklist.o chsc.o cio.o css.o chp.o idset.o isc.o scsw.o \
ccw_device-objs += device.o device_fsm.o device_ops.o
ccw_device-objs += device_id.o device_pgid.o device_status.o
obj-y += ccw_device.o cmf.o
obj-$(CONFIG_CHSC_SCH) += chsc_sch.o
obj-$(CONFIG_CCWGROUP) += ccwgroup.o
obj-$(CONFIG_QDIO) += qdio.o
+1 −1
Original line number Diff line number Diff line
@@ -407,7 +407,7 @@ int chp_new(struct chp_id chpid)
		 chpid.id);

	/* Obtain channel path description and fill it in. */
	ret = chsc_determine_channel_path_description(chpid, &chp->desc);
	ret = chsc_determine_base_channel_path_desc(chpid, &chp->desc);
	if (ret)
		goto out_free;
	if ((chp->desc.flags & 0x80) == 0) {
+41 −7
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@

#include <asm/cio.h>
#include <asm/chpid.h>
#include <asm/chsc.h>

#include "../s390mach.h"
#include "css.h"
@@ -627,23 +628,33 @@ chsc_secm(struct channel_subsystem *css, int enable)
	return ret;
}

int chsc_determine_channel_path_description(struct chp_id chpid,
					    struct channel_path_desc *desc)
int chsc_determine_channel_path_desc(struct chp_id chpid, int fmt, int rfmt,
				     int c, int m,
				     struct chsc_response_struct *resp)
{
	int ccode, ret;

	struct {
		struct chsc_header request;
		u32 : 24;
		u32 : 2;
		u32 m : 1;
		u32 c : 1;
		u32 fmt : 4;
		u32 cssid : 8;
		u32 : 4;
		u32 rfmt : 4;
		u32 first_chpid : 8;
		u32 : 24;
		u32 last_chpid : 8;
		u32 zeroes1;
		struct chsc_header response;
		u32 zeroes2;
		struct channel_path_desc desc;
		u8 data[PAGE_SIZE - 20];
	} __attribute__ ((packed)) *scpd_area;

	if ((rfmt == 1) && !css_general_characteristics.fcs)
		return -EINVAL;
	if ((rfmt == 2) && !css_general_characteristics.cib)
		return -EINVAL;
	scpd_area = (void *)get_zeroed_page(GFP_KERNEL | GFP_DMA);
	if (!scpd_area)
		return -ENOMEM;
@@ -651,8 +662,13 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
	scpd_area->request.length = 0x0010;
	scpd_area->request.code = 0x0002;

	scpd_area->cssid = chpid.cssid;
	scpd_area->first_chpid = chpid.id;
	scpd_area->last_chpid = chpid.id;
	scpd_area->m = m;
	scpd_area->c = c;
	scpd_area->fmt = fmt;
	scpd_area->rfmt = rfmt;

	ccode = chsc(scpd_area);
	if (ccode > 0) {
@@ -663,8 +679,7 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
	ret = chsc_error_from_response(scpd_area->response.code);
	if (ret == 0)
		/* Success. */
		memcpy(desc, &scpd_area->desc,
		       sizeof(struct channel_path_desc));
		memcpy(resp, &scpd_area->response, scpd_area->response.length);
	else
		CIO_CRW_EVENT(2, "chsc: scpd failed (rc=%04x)\n",
			      scpd_area->response.code);
@@ -672,6 +687,25 @@ int chsc_determine_channel_path_description(struct chp_id chpid,
	free_page((unsigned long)scpd_area);
	return ret;
}
EXPORT_SYMBOL_GPL(chsc_determine_channel_path_desc);

int chsc_determine_base_channel_path_desc(struct chp_id chpid,
					  struct channel_path_desc *desc)
{
	struct chsc_response_struct *chsc_resp;
	int ret;

	chsc_resp = kzalloc(sizeof(*chsc_resp), GFP_KERNEL);
	if (!chsc_resp)
		return -ENOMEM;
	ret = chsc_determine_channel_path_desc(chpid, 0, 0, 0, 0, chsc_resp);
	if (ret)
		goto out_free;
	memcpy(desc, &chsc_resp->data, chsc_resp->length);
out_free:
	kfree(chsc_resp);
	return ret;
}

static void
chsc_initialize_cmg_chars(struct channel_path *chp, u8 cmcv,
Loading