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

Commit cd6b4f27 authored by Cornelia Huck's avatar Cornelia Huck Committed by Martin Schwidefsky
Browse files

[S390] cio: Introduce subchannel->private.



Introduce a private pointer in struct subchannel to store
per-subchannel type data (cannot use dev->priv since this
is already used for something else).

Create a new header io_sch.h for I/O subchannel specific structures
and instructions.

Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent bc698bcf
Loading
Loading
Loading
Loading
+26 −17
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@
#include "css.h"
#include "css.h"
#include "chsc.h"
#include "chsc.h"
#include "ioasm.h"
#include "ioasm.h"
#include "io_sch.h"
#include "blacklist.h"
#include "blacklist.h"
#include "cio_debug.h"
#include "cio_debug.h"
#include "chp.h"
#include "chp.h"
@@ -182,29 +183,31 @@ cio_start_key (struct subchannel *sch, /* subchannel structure */
{
{
	char dbf_txt[15];
	char dbf_txt[15];
	int ccode;
	int ccode;
	struct orb *orb;


	CIO_TRACE_EVENT(4, "stIO");
	CIO_TRACE_EVENT(4, "stIO");
	CIO_TRACE_EVENT(4, sch->dev.bus_id);
	CIO_TRACE_EVENT(4, sch->dev.bus_id);


	orb = &to_io_private(sch)->orb;
	/* sch is always under 2G. */
	/* sch is always under 2G. */
	sch->orb.intparm = (__u32)(unsigned long)sch;
	orb->intparm = (u32)(addr_t)sch;
	sch->orb.fmt = 1;
	orb->fmt = 1;


	sch->orb.pfch = sch->options.prefetch == 0;
	orb->pfch = sch->options.prefetch == 0;
	sch->orb.spnd = sch->options.suspend;
	orb->spnd = sch->options.suspend;
	sch->orb.ssic = sch->options.suspend && sch->options.inter;
	orb->ssic = sch->options.suspend && sch->options.inter;
	sch->orb.lpm = (lpm != 0) ? lpm : sch->lpm;
	orb->lpm = (lpm != 0) ? lpm : sch->lpm;
#ifdef CONFIG_64BIT
#ifdef CONFIG_64BIT
	/*
	/*
	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
	 * for 64 bit we always support 64 bit IDAWs with 4k page size only
	 */
	 */
	sch->orb.c64 = 1;
	orb->c64 = 1;
	sch->orb.i2k = 0;
	orb->i2k = 0;
#endif
#endif
	sch->orb.key = key >> 4;
	orb->key = key >> 4;
	/* issue "Start Subchannel" */
	/* issue "Start Subchannel" */
	sch->orb.cpa = (__u32) __pa (cpa);
	orb->cpa = (__u32) __pa(cpa);
	ccode = ssch (sch->schid, &sch->orb);
	ccode = ssch(sch->schid, orb);


	/* process condition code */
	/* process condition code */
	sprintf(dbf_txt, "ccode:%d", ccode);
	sprintf(dbf_txt, "ccode:%d", ccode);
@@ -423,7 +426,7 @@ cio_enable_subchannel (struct subchannel *sch, unsigned int isc)
	for (retry = 5, ret = 0; retry > 0; retry--) {
	for (retry = 5, ret = 0; retry > 0; retry--) {
		sch->schib.pmcw.ena = 1;
		sch->schib.pmcw.ena = 1;
		sch->schib.pmcw.isc = isc;
		sch->schib.pmcw.isc = isc;
		sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
		sch->schib.pmcw.intparm = (u32)(addr_t)sch;
		ret = cio_modify(sch);
		ret = cio_modify(sch);
		if (ret == -ENODEV)
		if (ret == -ENODEV)
			break;
			break;
@@ -696,8 +699,14 @@ do_IRQ (struct pt_regs *regs)


#ifdef CONFIG_CCW_CONSOLE
#ifdef CONFIG_CCW_CONSOLE
static struct subchannel console_subchannel;
static struct subchannel console_subchannel;
static struct io_subchannel_private console_priv;
static int console_subchannel_in_use;
static int console_subchannel_in_use;


void *cio_get_console_priv(void)
{
	return &console_priv;
}

/*
/*
 * busy wait for the next interrupt on the console
 * busy wait for the next interrupt on the console
 */
 */
@@ -802,7 +811,7 @@ cio_probe_console(void)
	ctl_set_bit(6, 24);
	ctl_set_bit(6, 24);
	console_subchannel.schib.pmcw.isc = 7;
	console_subchannel.schib.pmcw.isc = 7;
	console_subchannel.schib.pmcw.intparm =
	console_subchannel.schib.pmcw.intparm =
		(__u32)(unsigned long)&console_subchannel;
		(u32)(addr_t)&console_subchannel;
	ret = cio_modify(&console_subchannel);
	ret = cio_modify(&console_subchannel);
	if (ret) {
	if (ret) {
		console_subchannel_in_use = 0;
		console_subchannel_in_use = 0;
+30 −54
Original line number Original line Diff line number Diff line
@@ -11,32 +11,32 @@
 * path management control word
 * path management control word
 */
 */
struct pmcw {
struct pmcw {
	__u32 intparm;		/* interruption parameter */
	u32 intparm;		/* interruption parameter */
	__u32 qf   : 1;		/* qdio facility */
	u32 qf	 : 1;		/* qdio facility */
	__u32 res0 : 1;		/* reserved zeros */
	u32 res0 : 1;		/* reserved zeros */
	__u32 isc  : 3;		/* interruption sublass */
	u32 isc  : 3;		/* interruption sublass */
	__u32 res5 : 3;		/* reserved zeros */
	u32 res5 : 3;		/* reserved zeros */
	__u32 ena  : 1;		/* enabled */
	u32 ena  : 1;		/* enabled */
	__u32 lm   : 2;		/* limit mode */
	u32 lm	 : 2;		/* limit mode */
	__u32 mme  : 2;		/* measurement-mode enable */
	u32 mme  : 2;		/* measurement-mode enable */
	__u32 mp   : 1;		/* multipath mode */
	u32 mp	 : 1;		/* multipath mode */
	__u32 tf   : 1;		/* timing facility */
	u32 tf	 : 1;		/* timing facility */
	__u32 dnv  : 1;		/* device number valid */
	u32 dnv  : 1;		/* device number valid */
	__u32 dev  : 16;	/* device number */
	u32 dev  : 16;		/* device number */
	__u8  lpm;		/* logical path mask */
	u8  lpm;		/* logical path mask */
	__u8  pnom;		/* path not operational mask */
	u8  pnom;		/* path not operational mask */
	__u8  lpum;		/* last path used mask */
	u8  lpum;		/* last path used mask */
	__u8  pim;		/* path installed mask */
	u8  pim;		/* path installed mask */
	__u16 mbi;		/* measurement-block index */
	u16 mbi;		/* measurement-block index */
	__u8  pom;		/* path operational mask */
	u8  pom;		/* path operational mask */
	__u8  pam;		/* path available mask */
	u8  pam;		/* path available mask */
	__u8  chpid[8];		/* CHPID 0-7 (if available) */
	u8  chpid[8];		/* CHPID 0-7 (if available) */
	__u32 unused1 : 8;	/* reserved zeros */
	u32 unused1 : 8;	/* reserved zeros */
	__u32 st      : 3;	/* subchannel type */
	u32 st	    : 3;	/* subchannel type */
	__u32 unused2 : 18;	/* reserved zeros */
	u32 unused2 : 18;	/* reserved zeros */
	__u32 mbfc    : 1;      /* measurement block format control */
	u32 mbfc    : 1;	/* measurement block format control */
	__u32 xmwme   : 1;      /* extended measurement word mode enable */
	u32 xmwme   : 1;	/* extended measurement word mode enable */
	__u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
	u32 csense  : 1;	/* concurrent sense; can be enabled ...*/
				/*  ... per MSCH, however, if facility */
				/*  ... per MSCH, however, if facility */
				/*  ... is not installed, this results */
				/*  ... is not installed, this results */
				/*  ... in an operand exception.       */
				/*  ... in an operand exception.       */
@@ -52,31 +52,6 @@ struct schib {
	__u8 mda[4];		 /* model dependent area */
	__u8 mda[4];		 /* model dependent area */
} __attribute__ ((packed,aligned(4)));
} __attribute__ ((packed,aligned(4)));


/*
 * operation request block
 */
struct orb {
	__u32 intparm;		/* interruption parameter */
	__u32 key  : 4; 	/* flags, like key, suspend control, etc. */
	__u32 spnd : 1; 	/* suspend control */
	__u32 res1 : 1; 	/* reserved */
	__u32 mod  : 1; 	/* modification control */
	__u32 sync : 1; 	/* synchronize control */
	__u32 fmt  : 1; 	/* format control */
	__u32 pfch : 1; 	/* prefetch control */
	__u32 isic : 1; 	/* initial-status-interruption control */
	__u32 alcc : 1; 	/* address-limit-checking control */
	__u32 ssic : 1; 	/* suppress-suspended-interr. control */
	__u32 res2 : 1; 	/* reserved */
	__u32 c64  : 1; 	/* IDAW/QDIO 64 bit control  */
	__u32 i2k  : 1; 	/* IDAW 2/4kB block size control */
	__u32 lpm  : 8; 	/* logical path mask */
	__u32 ils  : 1; 	/* incorrect length */
	__u32 zero : 6; 	/* reserved zeros */
	__u32 orbx : 1; 	/* ORB extension control */
	__u32 cpa;		/* channel program address */
}  __attribute__ ((packed,aligned(4)));

/* subchannel data structure used by I/O subroutines */
/* subchannel data structure used by I/O subroutines */
struct subchannel {
struct subchannel {
	struct subchannel_id schid;
	struct subchannel_id schid;
@@ -99,11 +74,10 @@ struct subchannel {
	__u8 lpm;		/* logical path mask */
	__u8 lpm;		/* logical path mask */
	__u8 opm;               /* operational path mask */
	__u8 opm;               /* operational path mask */
	struct schib schib;	/* subchannel information block */
	struct schib schib;	/* subchannel information block */
	struct orb orb;		/* operation request block */
	struct ccw1 sense_ccw;	/* static ccw for sense command */
	struct chsc_ssd_info ssd_info;	/* subchannel description */
	struct chsc_ssd_info ssd_info;	/* subchannel description */
	struct device dev;	/* entry in device tree */
	struct device dev;	/* entry in device tree */
	struct css_driver *driver;
	struct css_driver *driver;
	void *private; /* private per subchannel type data */
} __attribute__ ((aligned(8)));
} __attribute__ ((aligned(8)));


#define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
#define IO_INTERRUPT_TYPE	   0 /* I/O interrupt type */
@@ -133,10 +107,12 @@ extern void cio_release_console(void);
extern int cio_is_console(struct subchannel_id);
extern int cio_is_console(struct subchannel_id);
extern struct subchannel *cio_get_console_subchannel(void);
extern struct subchannel *cio_get_console_subchannel(void);
extern spinlock_t * cio_get_console_lock(void);
extern spinlock_t * cio_get_console_lock(void);
extern void *cio_get_console_priv(void);
#else
#else
#define cio_is_console(schid) 0
#define cio_is_console(schid) 0
#define cio_get_console_subchannel() NULL
#define cio_get_console_subchannel() NULL
#define cio_get_console_lock() NULL;
#define cio_get_console_lock() NULL
#define cio_get_console_priv() NULL
#endif
#endif


extern int cio_show_msg;
extern int cio_show_msg;
+1 −1
Original line number Original line Diff line number Diff line
@@ -77,7 +77,7 @@ css_alloc_subchannel(struct subchannel_id schid)
	 * This is fine even on 64bit since the subchannel is always located
	 * This is fine even on 64bit since the subchannel is always located
	 * under 2G.
	 * under 2G.
	 */
	 */
	sch->schib.pmcw.intparm = (__u32)(unsigned long)sch;
	sch->schib.pmcw.intparm = (u32)(addr_t)sch;
	ret = cio_modify(sch);
	ret = cio_modify(sch);
	if (ret) {
	if (ret) {
		kfree(sch->lock);
		kfree(sch->lock);
+0 −58
Original line number Original line Diff line number Diff line
@@ -58,64 +58,6 @@ struct pgid {
	__u32 tod_high;		/* high word TOD clock */
	__u32 tod_high;		/* high word TOD clock */
} __attribute__ ((packed));
} __attribute__ ((packed));


#define MAX_CIWS 8

/*
 * sense-id response buffer layout
 */
struct senseid {
	/* common part */
	__u8  reserved;     	/* always 0x'FF' */
	__u16 cu_type;	     	/* control unit type */
	__u8  cu_model;     	/* control unit model */
	__u16 dev_type;     	/* device type */
	__u8  dev_model;    	/* device model */
	__u8  unused;	     	/* padding byte */
	/* extended part */
	struct ciw ciw[MAX_CIWS];	/* variable # of CIWs */
}  __attribute__ ((packed,aligned(4)));

struct ccw_device_private {
	struct ccw_device *cdev;
	struct subchannel *sch;
	int state;		/* device state */
	atomic_t onoff;
	unsigned long registered;
	struct ccw_dev_id dev_id;	/* device id */
	struct subchannel_id schid;	/* subchannel number */
	__u8 imask;		/* lpm mask for SNID/SID/SPGID */
	int iretry;		/* retry counter SNID/SID/SPGID */
	struct {
		unsigned int fast:1;	/* post with "channel end" */
		unsigned int repall:1;	/* report every interrupt status */
		unsigned int pgroup:1;  /* do path grouping */
		unsigned int force:1;   /* allow forced online */
	} __attribute__ ((packed)) options;
	struct {
		unsigned int pgid_single:1; /* use single path for Set PGID */
		unsigned int esid:1;        /* Ext. SenseID supported by HW */
		unsigned int dosense:1;	    /* delayed SENSE required */
		unsigned int doverify:1;    /* delayed path verification */
		unsigned int donotify:1;    /* call notify function */
		unsigned int recog_done:1;  /* dev. recog. complete */
		unsigned int fake_irb:1;    /* deliver faked irb */
		unsigned int intretry:1;    /* retry internal operation */
	} __attribute__((packed)) flags;
	unsigned long intparm;	/* user interruption parameter */
	struct qdio_irq *qdio_data;
	struct irb irb;		/* device status */
	struct senseid senseid;	/* SenseID info */
	struct pgid pgid[8];	/* path group IDs per chpid*/
	struct ccw1 iccws[2];	/* ccws for SNID/SID/SPGID commands */
	struct work_struct kick_work;
	wait_queue_head_t wait_q;
	struct timer_list timer;
	void *cmb;			/* measurement information */
	struct list_head cmb_list;	/* list of measured devices */
	u64 cmb_start_time;		/* clock value of cmb reset */
	void *cmb_wait;			/* deferred cmb enable/disable */
};

/*
/*
 * A css driver handles all subchannels of one type.
 * A css driver handles all subchannels of one type.
 * Currently, we only care about I/O subchannels (type 0), these
 * Currently, we only care about I/O subchannels (type 0), these
+14 −2
Original line number Original line Diff line number Diff line
@@ -28,6 +28,7 @@
#include "css.h"
#include "css.h"
#include "device.h"
#include "device.h"
#include "ioasm.h"
#include "ioasm.h"
#include "io_sch.h"


/******************* bus type handling ***********************/
/******************* bus type handling ***********************/


@@ -1143,6 +1144,11 @@ io_subchannel_probe (struct subchannel *sch)
	 */
	 */
	dev_id.devno = sch->schib.pmcw.dev;
	dev_id.devno = sch->schib.pmcw.dev;
	dev_id.ssid = sch->schid.ssid;
	dev_id.ssid = sch->schid.ssid;
	/* Allocate I/O subchannel private data. */
	sch->private = kzalloc(sizeof(struct io_subchannel_private),
			       GFP_KERNEL | GFP_DMA);
	if (!sch->private)
		return -ENOMEM;
	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
	cdev = get_disc_ccwdev_by_dev_id(&dev_id, NULL);
	if (!cdev)
	if (!cdev)
		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
		cdev = get_orphaned_ccwdev_by_dev_id(to_css(sch->dev.parent),
@@ -1160,9 +1166,10 @@ io_subchannel_probe (struct subchannel *sch)
		return 0;
		return 0;
	}
	}
	cdev = io_subchannel_create_ccwdev(sch);
	cdev = io_subchannel_create_ccwdev(sch);
	if (IS_ERR(cdev))
	if (IS_ERR(cdev)) {
		kfree(sch->private);
		return PTR_ERR(cdev);
		return PTR_ERR(cdev);

	}
	rc = io_subchannel_recog(cdev, sch);
	rc = io_subchannel_recog(cdev, sch);
	if (rc) {
	if (rc) {
		spin_lock_irqsave(sch->lock, flags);
		spin_lock_irqsave(sch->lock, flags);
@@ -1170,6 +1177,7 @@ io_subchannel_probe (struct subchannel *sch)
		spin_unlock_irqrestore(sch->lock, flags);
		spin_unlock_irqrestore(sch->lock, flags);
		if (cdev->dev.release)
		if (cdev->dev.release)
			cdev->dev.release(&cdev->dev);
			cdev->dev.release(&cdev->dev);
		kfree(sch->private);
	}
	}


	return rc;
	return rc;
@@ -1191,6 +1199,7 @@ io_subchannel_remove (struct subchannel *sch)
	spin_unlock_irqrestore(cdev->ccwlock, flags);
	spin_unlock_irqrestore(cdev->ccwlock, flags);
	ccw_device_unregister(cdev);
	ccw_device_unregister(cdev);
	put_device(&cdev->dev);
	put_device(&cdev->dev);
	kfree(sch->private);
	return 0;
	return 0;
}
}


@@ -1279,6 +1288,9 @@ ccw_device_console_enable (struct ccw_device *cdev, struct subchannel *sch)
{
{
	int rc;
	int rc;


	/* Attach subchannel private data. */
	sch->private = cio_get_console_priv();
	memset(sch->private, 0, sizeof(struct io_subchannel_private));
	/* Initialize the ccw_device structure. */
	/* Initialize the ccw_device structure. */
	cdev->dev.parent= &sch->dev;
	cdev->dev.parent= &sch->dev;
	rc = io_subchannel_recog(cdev, sch);
	rc = io_subchannel_recog(cdev, sch);
Loading