summaryrefslogtreecommitdiff
path: root/drivers/s390/cio/css.h
blob: c2b175592bb7360e32a5063030204aa5f203a1dc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _CSS_H
#define _CSS_H

#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/workqueue.h>
#include <linux/device.h>
#include <linux/types.h>

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

#include "cio.h"

/*
 * path grouping stuff
 */
#define SPID_FUNC_SINGLE_PATH	   0x00
#define SPID_FUNC_MULTI_PATH	   0x80
#define SPID_FUNC_ESTABLISH	   0x00
#define SPID_FUNC_RESIGN	   0x40
#define SPID_FUNC_DISBAND	   0x20

#define SNID_STATE1_RESET	   0
#define SNID_STATE1_UNGROUPED	   2
#define SNID_STATE1_GROUPED	   3

#define SNID_STATE2_NOT_RESVD	   0
#define SNID_STATE2_RESVD_ELSE	   2
#define SNID_STATE2_RESVD_SELF	   3

#define SNID_STATE3_MULTI_PATH	   1
#define SNID_STATE3_SINGLE_PATH	   0

/*
 * Miscellaneous constants
 */

#define CSS_NUM_CUB_PAGES		2
#define CSS_CUES_PER_PAGE		128
#define CSS_NUM_ECUB_PAGES		4
#define CSS_ECUES_PER_PAGE		64

/*
 * Conditions used to specify which subchannels need evaluation
 */
enum css_eval_cond {
	CSS_EVAL_NO_PATH,		/* Subchannels with no operational paths */
	CSS_EVAL_NOT_ONLINE	/* sch without an online-device */
};

struct path_state {
	__u8  state1 : 2;	/* path state value 1 */
	__u8  state2 : 2;	/* path state value 2 */
	__u8  state3 : 1;	/* path state value 3 */
	__u8  resvd  : 3;	/* reserved */
} __attribute__ ((packed));

struct extended_cssid {
	u8 version;
	u8 cssid;
} __attribute__ ((packed));

struct pgid {
	union {
		__u8 fc;   	/* SPID function code */
		struct path_state ps;	/* SNID path state */
	} __attribute__ ((packed)) inf;
	union {
		__u32 cpu_addr	: 16;	/* CPU address */
		struct extended_cssid ext_cssid;
	} __attribute__ ((packed)) pgid_high;
	__u32 cpu_id	: 24;	/* CPU identification */
	__u32 cpu_model : 16;	/* CPU model */
	__u32 tod_high;		/* high word TOD clock */
} __attribute__ ((packed));

struct subchannel;
struct chp_link;
/**
 * struct css_driver - device driver for subchannels
 * @subchannel_type: subchannel type supported by this driver
 * @drv: embedded device driver structure
 * @irq: called on interrupts
 * @chp_event: called for events affecting a channel path
 * @sch_event: called for events affecting the subchannel
 * @probe: function called on probe
 * @remove: function called on remove
 * @shutdown: called at device shutdown
 * @settle: wait for asynchronous work to finish
 */
struct css_driver {
	struct css_device_id *subchannel_type;
	struct device_driver drv;
	void (*irq)(struct subchannel *);
	int (*chp_event)(struct subchannel *, struct chp_link *, int);
	int (*sch_event)(struct subchannel *, int);
	int (*probe)(struct subchannel *);
	void (*remove)(struct subchannel *);
	void (*shutdown)(struct subchannel *);
	int (*settle)(void);
};

#define to_cssdriver(n) container_of(n, struct css_driver, drv)

extern int css_driver_register(struct css_driver *);
extern void css_driver_unregister(struct css_driver *);

extern void css_sch_device_unregister(struct subchannel *);
extern int css_register_subchannel(struct subchannel *);
extern struct subchannel *css_alloc_subchannel(struct subchannel_id,
					       struct schib *schib);
extern struct subchannel *get_subchannel_by_schid(struct subchannel_id);
extern int css_init_done;
extern int max_ssid;
int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
			       int (*fn_unknown)(struct subchannel_id,
			       void *), void *data);
extern int for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *);
void css_update_ssd_info(struct subchannel *sch);

struct channel_subsystem {
	u8 cssid;
	u8 iid;
	bool id_valid; /* cssid,iid */
	struct channel_path *chps[__MAX_CHPID + 1];
	struct device device;
	struct pgid global_pgid;
	struct mutex mutex;
	/* channel measurement related */
	int cm_enabled;
	void *cub[CSS_NUM_CUB_PAGES];
	void *ecub[CSS_NUM_ECUB_PAGES];
	/* for orphaned ccw devices */
	struct subchannel *pseudo_subchannel;
};
#define to_css(dev) container_of(dev, struct channel_subsystem, device)

extern struct channel_subsystem *channel_subsystems[];

/* Dummy helper which needs to change once we support more than one css. */
static inline struct channel_subsystem *css_by_id(u8 cssid)
{
	return channel_subsystems[0];
}

/* Dummy iterator which needs to change once we support more than one css. */
#define for_each_css(css)						\
	for ((css) = channel_subsystems[0]; (css); (css) = NULL)

/* Helper functions to build lists for the slow path. */
void css_schedule_eval(struct subchannel_id schid);
void css_schedule_eval_all(void);
void css_schedule_eval_cond(enum css_eval_cond, unsigned long delay);
int css_complete_work(void);

int sch_is_pseudo_sch(struct subchannel *);
struct schib;
int css_sch_is_valid(struct schib *);

extern struct workqueue_struct *cio_work_q;
void css_wait_for_slow_path(void);
void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo);
#endif