Blame view

drivers/s390/cio/css.c 29.3 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
2
   * driver for channel subsystem
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
34aec07c1   Sebastian Ott   [S390] chsc: init...
4
   * Copyright IBM Corp. 2002, 2010
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
5
6
7
   *
   * Author(s): Arnd Bergmann (arndb@de.ibm.com)
   *	      Cornelia Huck (cornelia.huck@de.ibm.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   */
e6d5a428e   Michael Ernst   [S390] convert ci...
9
10
11
  
  #define KMSG_COMPONENT "cio"
  #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
15
16
17
  #include <linux/module.h>
  #include <linux/init.h>
  #include <linux/device.h>
  #include <linux/slab.h>
  #include <linux/errno.h>
  #include <linux/list.h>
a55360df4   Cornelia Huck   [S390] cio: Disab...
18
  #include <linux/reboot.h>
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
19
  #include <linux/suspend.h>
879acca58   Sebastian Ott   [S390] cio: intro...
20
  #include <linux/proc_fs.h>
3a3fc29a6   Cornelia Huck   [S390] cio: Intro...
21
  #include <asm/isc.h>
f5daba1d4   Heiko Carstens   [S390] split/move...
22
  #include <asm/crw.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
27
28
  
  #include "css.h"
  #include "cio.h"
  #include "cio_debug.h"
  #include "ioasm.h"
  #include "chsc.h"
40154b824   Peter Oberparleiter   [S390] cio async ...
29
  #include "device.h"
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
30
  #include "idset.h"
7ad6a2497   Peter Oberparleiter   [S390] cio: fix s...
31
  #include "chp.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
  int css_init_done = 0;
b0a285d31   Sebastian Ott   [S390] cio: idset...
34
  int max_ssid;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35

7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
36
  struct channel_subsystem *channel_subsystems[__MAX_CSSID + 1];
3041b6ab5   Sebastian Ott   [S390] css_bus_ty...
37
  static struct bus_type css_bus_type;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

4d284cac7   Heiko Carstens   [S390] Avoid exce...
39
  int
f97a56fb7   Cornelia Huck   [PATCH] s390: int...
40
41
42
43
44
45
46
47
  for_each_subchannel(int(*fn)(struct subchannel_id, void *), void *data)
  {
  	struct subchannel_id schid;
  	int ret;
  
  	init_subchannel_id(&schid);
  	ret = -ENODEV;
  	do {
fb6958a59   Cornelia Huck   [PATCH] s390: mul...
48
49
50
51
52
53
54
  		do {
  			ret = fn(schid, data);
  			if (ret)
  				break;
  		} while (schid.sch_no++ < __MAX_SUBCHANNEL);
  		schid.sch_no = 0;
  	} while (schid.ssid++ < max_ssid);
f97a56fb7   Cornelia Huck   [PATCH] s390: int...
55
56
  	return ret;
  }
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
57
58
59
60
61
62
63
64
65
66
67
68
  struct cb_data {
  	void *data;
  	struct idset *set;
  	int (*fn_known_sch)(struct subchannel *, void *);
  	int (*fn_unknown_sch)(struct subchannel_id, void *);
  };
  
  static int call_fn_known_sch(struct device *dev, void *data)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct cb_data *cb = data;
  	int rc = 0;
47d30674d   Peter Oberparleiter   s390/css: Prevent...
69
70
  	if (cb->set)
  		idset_sch_del(cb->set, sch->schid);
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  	if (cb->fn_known_sch)
  		rc = cb->fn_known_sch(sch, cb->data);
  	return rc;
  }
  
  static int call_fn_unknown_sch(struct subchannel_id schid, void *data)
  {
  	struct cb_data *cb = data;
  	int rc = 0;
  
  	if (idset_sch_contains(cb->set, schid))
  		rc = cb->fn_unknown_sch(schid, cb->data);
  	return rc;
  }
90ac24a5a   Sebastian Ott   [S390] cio: devic...
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
  static int call_fn_all_sch(struct subchannel_id schid, void *data)
  {
  	struct cb_data *cb = data;
  	struct subchannel *sch;
  	int rc = 0;
  
  	sch = get_subchannel_by_schid(schid);
  	if (sch) {
  		if (cb->fn_known_sch)
  			rc = cb->fn_known_sch(sch, cb->data);
  		put_device(&sch->dev);
  	} else {
  		if (cb->fn_unknown_sch)
  			rc = cb->fn_unknown_sch(schid, cb->data);
  	}
  
  	return rc;
  }
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
103
104
105
106
107
108
  int for_each_subchannel_staged(int (*fn_known)(struct subchannel *, void *),
  			       int (*fn_unknown)(struct subchannel_id,
  			       void *), void *data)
  {
  	struct cb_data cb;
  	int rc;
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
109
110
111
  	cb.data = data;
  	cb.fn_known_sch = fn_known;
  	cb.fn_unknown_sch = fn_unknown;
90ac24a5a   Sebastian Ott   [S390] cio: devic...
112

47d30674d   Peter Oberparleiter   s390/css: Prevent...
113
114
115
116
117
118
  	if (fn_known && !fn_unknown) {
  		/* Skip idset allocation in case of known-only loop. */
  		cb.set = NULL;
  		return bus_for_each_dev(&css_bus_type, NULL, &cb,
  					call_fn_known_sch);
  	}
90ac24a5a   Sebastian Ott   [S390] cio: devic...
119
120
121
122
123
124
  	cb.set = idset_sch_new();
  	if (!cb.set)
  		/* fall back to brute force scanning in case of oom */
  		return for_each_subchannel(call_fn_all_sch, &cb);
  
  	idset_fill(cb.set);
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
125
126
127
128
129
130
131
132
133
134
135
136
  	/* Process registered subchannels. */
  	rc = bus_for_each_dev(&css_bus_type, NULL, &cb, call_fn_known_sch);
  	if (rc)
  		goto out;
  	/* Process unregistered subchannels. */
  	if (fn_unknown)
  		rc = for_each_subchannel(call_fn_unknown_sch, &cb);
  out:
  	idset_free(cb.set);
  
  	return rc;
  }
390935aca   Peter Oberparleiter   [S390] cio: intro...
137
  static void css_sch_todo(struct work_struct *work);
e5dcf0025   Sebastian Ott   s390/css: move su...
138
139
140
141
142
143
144
145
146
147
148
  static int css_sch_create_locks(struct subchannel *sch)
  {
  	sch->lock = kmalloc(sizeof(*sch->lock), GFP_KERNEL);
  	if (!sch->lock)
  		return -ENOMEM;
  
  	spin_lock_init(sch->lock);
  	mutex_init(&sch->reg_mutex);
  
  	return 0;
  }
c135ad1ca   Sebastian Ott   s390/cio: split s...
149
150
  static void css_subchannel_release(struct device *dev)
  {
863fc8492   Sebastian Ott   s390/cio: get rid...
151
  	struct subchannel *sch = to_subchannel(dev);
c135ad1ca   Sebastian Ott   s390/cio: split s...
152

863fc8492   Sebastian Ott   s390/cio: get rid...
153
154
155
156
  	sch->config.intparm = 0;
  	cio_commit_config(sch);
  	kfree(sch->lock);
  	kfree(sch);
c135ad1ca   Sebastian Ott   s390/cio: split s...
157
  }
863fc8492   Sebastian Ott   s390/cio: get rid...
158
  struct subchannel *css_alloc_subchannel(struct subchannel_id schid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
  {
  	struct subchannel *sch;
  	int ret;
e5dcf0025   Sebastian Ott   s390/css: move su...
162
163
  	sch = kzalloc(sizeof(*sch), GFP_KERNEL | GFP_DMA);
  	if (!sch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
164
  		return ERR_PTR(-ENOMEM);
e5dcf0025   Sebastian Ott   s390/css: move su...
165
166
167
168
169
170
171
172
  
  	ret = cio_validate_subchannel(sch, schid);
  	if (ret < 0)
  		goto err;
  
  	ret = css_sch_create_locks(sch);
  	if (ret)
  		goto err;
390935aca   Peter Oberparleiter   [S390] cio: intro...
173
  	INIT_WORK(&sch->todo_work, css_sch_todo);
c135ad1ca   Sebastian Ott   s390/cio: split s...
174
175
  	sch->dev.release = &css_subchannel_release;
  	device_initialize(&sch->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  	return sch;
e5dcf0025   Sebastian Ott   s390/css: move su...
177
178
179
180
  
  err:
  	kfree(sch);
  	return ERR_PTR(ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
  }
07c6a3386   Cornelia Huck   [S390] cio: css_s...
182
  static int css_sch_device_register(struct subchannel *sch)
6ab4879a0   Cornelia Huck   [S390] subchannel...
183
184
185
186
  {
  	int ret;
  
  	mutex_lock(&sch->reg_mutex);
6ee4fec6b   Sebastian Ott   [S390] cio: remov...
187
188
  	dev_set_name(&sch->dev, "0.%x.%04x", sch->schid.ssid,
  		     sch->schid.sch_no);
c135ad1ca   Sebastian Ott   s390/cio: split s...
189
  	ret = device_add(&sch->dev);
6ab4879a0   Cornelia Huck   [S390] subchannel...
190
191
192
  	mutex_unlock(&sch->reg_mutex);
  	return ret;
  }
44a1c19e3   Cornelia Huck   [S390] cio: Expor...
193
194
195
196
  /**
   * css_sch_device_unregister - unregister a subchannel
   * @sch: subchannel to be unregistered
   */
6ab4879a0   Cornelia Huck   [S390] subchannel...
197
198
199
  void css_sch_device_unregister(struct subchannel *sch)
  {
  	mutex_lock(&sch->reg_mutex);
ef60cd13e   Sebastian Ott   [S390] cio: fix d...
200
201
  	if (device_is_registered(&sch->dev))
  		device_unregister(&sch->dev);
6ab4879a0   Cornelia Huck   [S390] subchannel...
202
203
  	mutex_unlock(&sch->reg_mutex);
  }
44a1c19e3   Cornelia Huck   [S390] cio: Expor...
204
  EXPORT_SYMBOL_GPL(css_sch_device_unregister);
6ab4879a0   Cornelia Huck   [S390] subchannel...
205

7ad6a2497   Peter Oberparleiter   [S390] cio: fix s...
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  static void ssd_from_pmcw(struct chsc_ssd_info *ssd, struct pmcw *pmcw)
  {
  	int i;
  	int mask;
  
  	memset(ssd, 0, sizeof(struct chsc_ssd_info));
  	ssd->path_mask = pmcw->pim;
  	for (i = 0; i < 8; i++) {
  		mask = 0x80 >> i;
  		if (pmcw->pim & mask) {
  			chp_id_init(&ssd->chpid[i]);
  			ssd->chpid[i].id = pmcw->chpid[i];
  		}
  	}
  }
  
  static void ssd_register_chpids(struct chsc_ssd_info *ssd)
  {
  	int i;
  	int mask;
  
  	for (i = 0; i < 8; i++) {
  		mask = 0x80 >> i;
  		if (ssd->path_mask & mask)
  			if (!chp_is_registered(ssd->chpid[i]))
  				chp_new(ssd->chpid[i]);
  	}
  }
  
  void css_update_ssd_info(struct subchannel *sch)
  {
  	int ret;
14556b33f   Sebastian Ott   s390/css: introdu...
238
239
  	ret = chsc_get_ssd_info(sch->schid, &sch->ssd_info);
  	if (ret)
7ad6a2497   Peter Oberparleiter   [S390] cio: fix s...
240
  		ssd_from_pmcw(&sch->ssd_info, &sch->schib.pmcw);
14556b33f   Sebastian Ott   s390/css: introdu...
241
242
  
  	ssd_register_chpids(&sch->ssd_info);
7ad6a2497   Peter Oberparleiter   [S390] cio: fix s...
243
  }
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  static ssize_t type_show(struct device *dev, struct device_attribute *attr,
  			 char *buf)
  {
  	struct subchannel *sch = to_subchannel(dev);
  
  	return sprintf(buf, "%01x
  ", sch->st);
  }
  
  static DEVICE_ATTR(type, 0444, type_show, NULL);
  
  static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
  			     char *buf)
  {
  	struct subchannel *sch = to_subchannel(dev);
  
  	return sprintf(buf, "css:t%01X
  ", sch->st);
  }
  
  static DEVICE_ATTR(modalias, 0444, modalias_show, NULL);
  
  static struct attribute *subch_attrs[] = {
  	&dev_attr_type.attr,
  	&dev_attr_modalias.attr,
  	NULL,
  };
  
  static struct attribute_group subch_attr_group = {
  	.attrs = subch_attrs,
  };
a4dbd6740   David Brownell   driver model: con...
275
  static const struct attribute_group *default_subch_attr_groups[] = {
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
276
277
278
  	&subch_attr_group,
  	NULL,
  };
14556b33f   Sebastian Ott   s390/css: introdu...
279
  int css_register_subchannel(struct subchannel *sch)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
281
282
283
  {
  	int ret;
  
  	/* Initialize the subchannel structure */
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
284
  	sch->dev.parent = &channel_subsystems[0]->device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  	sch->dev.bus = &css_bus_type;
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
286
  	sch->dev.groups = default_subch_attr_groups;
5bf04b206   Cornelia Huck   [S390] cio: Fix i...
287
288
289
290
291
  	/*
  	 * We don't want to generate uevents for I/O subchannels that don't
  	 * have a working ccw device behind them since they will be
  	 * unregistered before they can be used anyway, so we delay the add
  	 * uevent until after device recognition was successful.
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
292
293
294
  	 * Note that we suppress the uevent for all subchannel types;
  	 * the subchannel driver can decide itself when it wants to inform
  	 * userspace of its existence.
5bf04b206   Cornelia Huck   [S390] cio: Fix i...
295
  	 */
f67f129e5   Ming Lei   Driver core: impl...
296
  	dev_set_uevent_suppress(&sch->dev, 1);
7ad6a2497   Peter Oberparleiter   [S390] cio: fix s...
297
  	css_update_ssd_info(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
298
  	/* make it known to the system */
6ab4879a0   Cornelia Huck   [S390] subchannel...
299
  	ret = css_sch_device_register(sch);
7674da77c   Cornelia Huck   [S390] Some prepa...
300
  	if (ret) {
e556bbbd9   Cornelia Huck   [S390] cio: Clean...
301
302
303
  		CIO_MSG_EVENT(0, "Could not register sch 0.%x.%04x: %d
  ",
  			      sch->schid.ssid, sch->schid.sch_no, ret);
7674da77c   Cornelia Huck   [S390] Some prepa...
304
305
  		return ret;
  	}
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
306
307
308
309
310
311
  	if (!sch->driver) {
  		/*
  		 * No driver matched. Generate the uevent now so that
  		 * a fitting driver module may be loaded based on the
  		 * modalias.
  		 */
f67f129e5   Ming Lei   Driver core: impl...
312
  		dev_set_uevent_suppress(&sch->dev, 0);
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
313
314
  		kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
  	return ret;
  }
4e5ebd512   Sebastian Ott   s390/css: remove ...
317
  static int css_probe_device(struct subchannel_id schid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
  	struct subchannel *sch;
4e5ebd512   Sebastian Ott   s390/css: remove ...
320
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321

14556b33f   Sebastian Ott   s390/css: introdu...
322
323
324
  	sch = css_alloc_subchannel(schid);
  	if (IS_ERR(sch))
  		return PTR_ERR(sch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
325
  	ret = css_register_subchannel(sch);
863fc8492   Sebastian Ott   s390/cio: get rid...
326
327
  	if (ret)
  		put_device(&sch->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
  	return ret;
  }
b0744bd29   Cornelia Huck   [PATCH] s/390: Us...
330
331
332
333
  static int
  check_subchannel(struct device * dev, void * data)
  {
  	struct subchannel *sch;
a8237fc41   Cornelia Huck   [PATCH] s390: int...
334
  	struct subchannel_id *schid = data;
b0744bd29   Cornelia Huck   [PATCH] s/390: Us...
335
336
  
  	sch = to_subchannel(dev);
a8237fc41   Cornelia Huck   [PATCH] s390: int...
337
  	return schid_equal(&sch->schid, schid);
b0744bd29   Cornelia Huck   [PATCH] s/390: Us...
338
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
339
  struct subchannel *
a8237fc41   Cornelia Huck   [PATCH] s390: int...
340
  get_subchannel_by_schid(struct subchannel_id schid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
342
  	struct device *dev;
b0744bd29   Cornelia Huck   [PATCH] s/390: Us...
343
  	dev = bus_find_device(&css_bus_type, NULL,
12975aef6   Cornelia Huck   [S390] cio: remov...
344
  			      &schid, check_subchannel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

b0744bd29   Cornelia Huck   [PATCH] s/390: Us...
346
  	return dev ? to_subchannel(dev) : NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
  }
b279a4f56   Cornelia Huck   [S390] cio: I/O s...
348
349
350
351
352
353
354
355
  /**
   * css_sch_is_valid() - check if a subchannel is valid
   * @schib: subchannel information block for the subchannel
   */
  int css_sch_is_valid(struct schib *schib)
  {
  	if ((schib->pmcw.st == SUBCHANNEL_TYPE_IO) && !schib->pmcw.dnv)
  		return 0;
b3a686f47   Cornelia Huck   [S390] cio: Base ...
356
357
  	if ((schib->pmcw.st == SUBCHANNEL_TYPE_MSG) && !schib->pmcw.w)
  		return 0;
b279a4f56   Cornelia Huck   [S390] cio: I/O s...
358
359
360
  	return 1;
  }
  EXPORT_SYMBOL_GPL(css_sch_is_valid);
564337f34   Peter Oberparleiter   [S390] cio: subch...
361
362
363
364
365
366
367
368
  static int css_evaluate_new_subchannel(struct subchannel_id schid, int slow)
  {
  	struct schib schib;
  
  	if (!slow) {
  		/* Will be done on the slow path. */
  		return -EAGAIN;
  	}
cec854663   Sebastian Ott   s390/css: stop st...
369
370
371
372
373
  	if (stsch_err(schid, &schib)) {
  		/* Subchannel is not provided. */
  		return -ENXIO;
  	}
  	if (!css_sch_is_valid(&schib)) {
564337f34   Peter Oberparleiter   [S390] cio: subch...
374
375
  		/* Unusable - ignore. */
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  	}
5d6e6b6f6   Peter Oberparleiter   [S390] cio: intro...
377
378
379
  	CIO_MSG_EVENT(4, "event: sch 0.%x.%04x, new
  ", schid.ssid,
  		      schid.sch_no);
564337f34   Peter Oberparleiter   [S390] cio: subch...
380
381
382
  
  	return css_probe_device(schid);
  }
c820de39b   Cornelia Huck   [S390] cio: Rewor...
383
384
385
386
387
388
389
390
391
392
393
394
395
  static int css_evaluate_known_subchannel(struct subchannel *sch, int slow)
  {
  	int ret = 0;
  
  	if (sch->driver) {
  		if (sch->driver->sch_event)
  			ret = sch->driver->sch_event(sch, slow);
  		else
  			dev_dbg(&sch->dev,
  				"Got subchannel machine check but "
  				"no sch_event handler provided.
  ");
  	}
5d6e6b6f6   Peter Oberparleiter   [S390] cio: intro...
396
397
398
399
400
  	if (ret != 0 && ret != -EAGAIN) {
  		CIO_MSG_EVENT(2, "eval: sch 0.%x.%04x, rc=%d
  ",
  			      sch->schid.ssid, sch->schid.sch_no, ret);
  	}
c820de39b   Cornelia Huck   [S390] cio: Rewor...
401
402
  	return ret;
  }
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
403
  static void css_evaluate_subchannel(struct subchannel_id schid, int slow)
564337f34   Peter Oberparleiter   [S390] cio: subch...
404
405
406
407
408
409
410
411
412
413
  {
  	struct subchannel *sch;
  	int ret;
  
  	sch = get_subchannel_by_schid(schid);
  	if (sch) {
  		ret = css_evaluate_known_subchannel(sch, slow);
  		put_device(&sch->dev);
  	} else
  		ret = css_evaluate_new_subchannel(schid, slow);
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
414
415
  	if (ret == -EAGAIN)
  		css_schedule_eval(schid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
416
  }
817e5000e   Sebastian Ott   [S390] hibernate:...
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
  /**
   * css_sched_sch_todo - schedule a subchannel operation
   * @sch: subchannel
   * @todo: todo
   *
   * Schedule the operation identified by @todo to be performed on the slow path
   * workqueue. Do nothing if another operation with higher priority is already
   * scheduled. Needs to be called with subchannel lock held.
   */
  void css_sched_sch_todo(struct subchannel *sch, enum sch_todo todo)
  {
  	CIO_MSG_EVENT(4, "sch_todo: sched sch=0.%x.%04x todo=%d
  ",
  		      sch->schid.ssid, sch->schid.sch_no, todo);
  	if (sch->todo >= todo)
  		return;
  	/* Get workqueue ref. */
  	if (!get_device(&sch->dev))
  		return;
  	sch->todo = todo;
  	if (!queue_work(cio_work_q, &sch->todo_work)) {
  		/* Already queued, release workqueue ref. */
  		put_device(&sch->dev);
  	}
  }
01c5e6dc1   Sebastian Ott   s390/css: export ...
442
  EXPORT_SYMBOL_GPL(css_sched_sch_todo);
817e5000e   Sebastian Ott   [S390] hibernate:...
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
  
  static void css_sch_todo(struct work_struct *work)
  {
  	struct subchannel *sch;
  	enum sch_todo todo;
  	int ret;
  
  	sch = container_of(work, struct subchannel, todo_work);
  	/* Find out todo. */
  	spin_lock_irq(sch->lock);
  	todo = sch->todo;
  	CIO_MSG_EVENT(4, "sch_todo: sch=0.%x.%04x, todo=%d
  ", sch->schid.ssid,
  		      sch->schid.sch_no, todo);
  	sch->todo = SCH_TODO_NOTHING;
  	spin_unlock_irq(sch->lock);
  	/* Perform todo. */
  	switch (todo) {
  	case SCH_TODO_NOTHING:
  		break;
  	case SCH_TODO_EVAL:
  		ret = css_evaluate_known_subchannel(sch, 1);
  		if (ret == -EAGAIN) {
  			spin_lock_irq(sch->lock);
  			css_sched_sch_todo(sch, todo);
  			spin_unlock_irq(sch->lock);
  		}
  		break;
  	case SCH_TODO_UNREG:
  		css_sch_device_unregister(sch);
  		break;
  	}
  	/* Release workqueue ref. */
  	put_device(&sch->dev);
  }
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
478
479
  static struct idset *slow_subchannel_set;
  static spinlock_t slow_subchannel_lock;
255305536   Sebastian Ott   [S390] cio: intro...
480
481
  static wait_queue_head_t css_eval_wq;
  static atomic_t css_eval_scheduled;
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
482
483
  
  static int __init slow_subchannel_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
484
  {
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
485
  	spin_lock_init(&slow_subchannel_lock);
255305536   Sebastian Ott   [S390] cio: intro...
486
487
  	atomic_set(&css_eval_scheduled, 0);
  	init_waitqueue_head(&css_eval_wq);
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
488
489
  	slow_subchannel_set = idset_sch_new();
  	if (!slow_subchannel_set) {
e556bbbd9   Cornelia Huck   [S390] cio: Clean...
490
491
  		CIO_MSG_EVENT(0, "could not allocate slow subchannel set
  ");
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
492
493
494
  		return -ENOMEM;
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  }
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
496
  static int slow_eval_known_fn(struct subchannel *sch, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
  {
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
498
499
  	int eval;
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
  
  	spin_lock_irq(&slow_subchannel_lock);
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
502
503
504
505
506
507
508
  	eval = idset_sch_contains(slow_subchannel_set, sch->schid);
  	idset_sch_del(slow_subchannel_set, sch->schid);
  	spin_unlock_irq(&slow_subchannel_lock);
  	if (eval) {
  		rc = css_evaluate_known_subchannel(sch, 1);
  		if (rc == -EAGAIN)
  			css_schedule_eval(sch->schid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
  	}
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
510
511
512
513
514
515
516
517
518
519
520
  	return 0;
  }
  
  static int slow_eval_unknown_fn(struct subchannel_id schid, void *data)
  {
  	int eval;
  	int rc = 0;
  
  	spin_lock_irq(&slow_subchannel_lock);
  	eval = idset_sch_contains(slow_subchannel_set, schid);
  	idset_sch_del(slow_subchannel_set, schid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
  	spin_unlock_irq(&slow_subchannel_lock);
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
522
523
524
525
526
527
528
529
530
531
532
  	if (eval) {
  		rc = css_evaluate_new_subchannel(schid, 1);
  		switch (rc) {
  		case -EAGAIN:
  			css_schedule_eval(schid);
  			rc = 0;
  			break;
  		case -ENXIO:
  		case -ENOMEM:
  		case -EIO:
  			/* These should abort looping */
eb072a799   Sebastian Ott   s390/cio: fix unl...
533
  			spin_lock_irq(&slow_subchannel_lock);
cec854663   Sebastian Ott   s390/css: stop st...
534
  			idset_sch_del_subseq(slow_subchannel_set, schid);
eb072a799   Sebastian Ott   s390/cio: fix unl...
535
  			spin_unlock_irq(&slow_subchannel_lock);
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
536
537
538
539
  			break;
  		default:
  			rc = 0;
  		}
b207f5a8f   Peter Oberparleiter   s390/cio: Relax s...
540
541
542
  		/* Allow scheduling here since the containing loop might
  		 * take a while.  */
  		cond_resched();
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
543
544
545
546
547
548
  	}
  	return rc;
  }
  
  static void css_slow_path_func(struct work_struct *unused)
  {
255305536   Sebastian Ott   [S390] cio: intro...
549
  	unsigned long flags;
e82a1567e   Peter Oberparleiter   [S390] cio: reduc...
550
551
552
  	CIO_TRACE_EVENT(4, "slowpath");
  	for_each_subchannel_staged(slow_eval_known_fn, slow_eval_unknown_fn,
  				   NULL);
255305536   Sebastian Ott   [S390] cio: intro...
553
554
555
556
557
558
  	spin_lock_irqsave(&slow_subchannel_lock, flags);
  	if (idset_is_empty(slow_subchannel_set)) {
  		atomic_set(&css_eval_scheduled, 0);
  		wake_up(&css_eval_wq);
  	}
  	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  }
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
560
  static DECLARE_DELAYED_WORK(slow_path_work, css_slow_path_func);
be5d3823f   Sebastian Ott   [S390] cio: conso...
561
  struct workqueue_struct *cio_work_q;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562

83b3370c7   Peter Oberparleiter   [S390] cio: repla...
563
564
565
566
567
568
  void css_schedule_eval(struct subchannel_id schid)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&slow_subchannel_lock, flags);
  	idset_sch_add(slow_subchannel_set, schid);
255305536   Sebastian Ott   [S390] cio: intro...
569
  	atomic_set(&css_eval_scheduled, 1);
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
570
  	queue_delayed_work(cio_work_q, &slow_path_work, 0);
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
571
572
573
574
575
576
577
578
579
  	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
  }
  
  void css_schedule_eval_all(void)
  {
  	unsigned long flags;
  
  	spin_lock_irqsave(&slow_subchannel_lock, flags);
  	idset_fill(slow_subchannel_set);
255305536   Sebastian Ott   [S390] cio: intro...
580
  	atomic_set(&css_eval_scheduled, 1);
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
581
  	queue_delayed_work(cio_work_q, &slow_path_work, 0);
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
582
583
  	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
  }
703e5c999   Sebastian Ott   [S390] cio: intro...
584
  static int __unset_registered(struct device *dev, void *data)
22806dc1a   Cornelia Huck   [S390] cio: Fix r...
585
  {
703e5c999   Sebastian Ott   [S390] cio: intro...
586
587
  	struct idset *set = data;
  	struct subchannel *sch = to_subchannel(dev);
40154b824   Peter Oberparleiter   [S390] cio async ...
588

703e5c999   Sebastian Ott   [S390] cio: intro...
589
590
  	idset_sch_del(set, sch->schid);
  	return 0;
56e25e977   Peter Oberparleiter   [S390] cio: preve...
591
  }
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
592
  void css_schedule_eval_all_unreg(unsigned long delay)
40154b824   Peter Oberparleiter   [S390] cio async ...
593
  {
703e5c999   Sebastian Ott   [S390] cio: intro...
594
595
  	unsigned long flags;
  	struct idset *unreg_set;
40154b824   Peter Oberparleiter   [S390] cio async ...
596

703e5c999   Sebastian Ott   [S390] cio: intro...
597
598
599
600
601
  	/* Find unregistered subchannels. */
  	unreg_set = idset_sch_new();
  	if (!unreg_set) {
  		/* Fallback. */
  		css_schedule_eval_all();
56e25e977   Peter Oberparleiter   [S390] cio: preve...
602
603
  		return;
  	}
703e5c999   Sebastian Ott   [S390] cio: intro...
604
605
606
607
608
609
  	idset_fill(unreg_set);
  	bus_for_each_dev(&css_bus_type, NULL, unreg_set, __unset_registered);
  	/* Apply to slow_subchannel_set. */
  	spin_lock_irqsave(&slow_subchannel_lock, flags);
  	idset_add_set(slow_subchannel_set, unreg_set);
  	atomic_set(&css_eval_scheduled, 1);
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
610
  	queue_delayed_work(cio_work_q, &slow_path_work, delay);
703e5c999   Sebastian Ott   [S390] cio: intro...
611
612
  	spin_unlock_irqrestore(&slow_subchannel_lock, flags);
  	idset_free(unreg_set);
40154b824   Peter Oberparleiter   [S390] cio async ...
613
  }
703e5c999   Sebastian Ott   [S390] cio: intro...
614
615
  void css_wait_for_slow_path(void)
  {
be5d3823f   Sebastian Ott   [S390] cio: conso...
616
  	flush_workqueue(cio_work_q);
703e5c999   Sebastian Ott   [S390] cio: intro...
617
  }
40154b824   Peter Oberparleiter   [S390] cio async ...
618
619
620
621
  
  /* Schedule reprobing of all unregistered subchannels. */
  void css_schedule_reprobe(void)
  {
175746eb0   Peter Oberparleiter   s390/cio: Delay s...
622
623
  	/* Schedule with a delay to allow merging of subsequent calls. */
  	css_schedule_eval_all_unreg(1 * HZ);
40154b824   Peter Oberparleiter   [S390] cio async ...
624
  }
40154b824   Peter Oberparleiter   [S390] cio async ...
625
  EXPORT_SYMBOL_GPL(css_schedule_reprobe);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
626
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
   * Called from the machine check handler for subchannel report words.
   */
c11561897   Cornelia Huck   [S390] cio: Clean...
629
  static void css_process_crw(struct crw *crw0, struct crw *crw1, int overflow)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
630
  {
a8237fc41   Cornelia Huck   [PATCH] s390: int...
631
  	struct subchannel_id mchk_schid;
4bc4e965d   Sebastian Ott   [S390] css: updat...
632
  	struct subchannel *sch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633

c11561897   Cornelia Huck   [S390] cio: Clean...
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
  	if (overflow) {
  		css_schedule_eval_all();
  		return;
  	}
  	CIO_CRW_EVENT(2, "CRW0 reports slct=%d, oflw=%d, "
  		      "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X
  ",
  		      crw0->slct, crw0->oflw, crw0->chn, crw0->rsc, crw0->anc,
  		      crw0->erc, crw0->rsid);
  	if (crw1)
  		CIO_CRW_EVENT(2, "CRW1 reports slct=%d, oflw=%d, "
  			      "chn=%d, rsc=%X, anc=%d, erc=%X, rsid=%X
  ",
  			      crw1->slct, crw1->oflw, crw1->chn, crw1->rsc,
  			      crw1->anc, crw1->erc, crw1->rsid);
a8237fc41   Cornelia Huck   [PATCH] s390: int...
649
  	init_subchannel_id(&mchk_schid);
c11561897   Cornelia Huck   [S390] cio: Clean...
650
651
  	mchk_schid.sch_no = crw0->rsid;
  	if (crw1)
8d7bfb4a8   Sebastian Ott   [S390] css: fix r...
652
  		mchk_schid.ssid = (crw1->rsid >> 4) & 3;
fb6958a59   Cornelia Huck   [PATCH] s390: mul...
653

4bc4e965d   Sebastian Ott   [S390] css: updat...
654
655
656
657
658
659
660
  	if (crw0->erc == CRW_ERC_PMOD) {
  		sch = get_subchannel_by_schid(mchk_schid);
  		if (sch) {
  			css_update_ssd_info(sch);
  			put_device(&sch->dev);
  		}
  	}
c11561897   Cornelia Huck   [S390] cio: Clean...
661
  	/*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
662
663
664
665
  	 * Since we are always presented with IPI in the CRW, we have to
  	 * use stsch() to find out if the subchannel in question has come
  	 * or gone.
  	 */
83b3370c7   Peter Oberparleiter   [S390] cio: repla...
666
  	css_evaluate_subchannel(mchk_schid, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
669
  }
  
  static void __init
a28c69448   Cornelia Huck   [PATCH] s390: int...
670
  css_generate_pgid(struct channel_subsystem *css, u32 tod_high)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  {
94038a991   Martin Schwidefsky   [S390] More clean...
672
  	struct cpuid cpu_id;
75784c008   Cornelia Huck   [S390] cio: Get r...
673
  	if (css_general_characteristics.mcss) {
a28c69448   Cornelia Huck   [PATCH] s390: int...
674
675
676
  		css->global_pgid.pgid_high.ext_cssid.version = 0x80;
  		css->global_pgid.pgid_high.ext_cssid.cssid = css->cssid;
  	} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
677
  #ifdef CONFIG_SMP
7b4684880   Martin Schwidefsky   [S390] eliminate ...
678
  		css->global_pgid.pgid_high.cpu_addr = stap();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
  #else
a28c69448   Cornelia Huck   [PATCH] s390: int...
680
  		css->global_pgid.pgid_high.cpu_addr = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
681
682
  #endif
  	}
94038a991   Martin Schwidefsky   [S390] More clean...
683
684
685
  	get_cpu_id(&cpu_id);
  	css->global_pgid.cpu_id = cpu_id.ident;
  	css->global_pgid.cpu_model = cpu_id.machine;
a28c69448   Cornelia Huck   [PATCH] s390: int...
686
687
688
  	css->global_pgid.tod_high = tod_high;
  
  }
3b793060e   Cornelia Huck   [PATCH] s390: Fix...
689
690
691
692
693
694
  static void
  channel_subsystem_release(struct device *dev)
  {
  	struct channel_subsystem *css;
  
  	css = to_css(dev);
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
695
  	mutex_destroy(&css->mutex);
a2164b817   Cornelia Huck   [S390] cio: Corre...
696
697
698
699
700
  	if (css->pseudo_subchannel) {
  		/* Implies that it has been generated but never registered. */
  		css_subchannel_release(&css->pseudo_subchannel->dev);
  		css->pseudo_subchannel = NULL;
  	}
3b793060e   Cornelia Huck   [PATCH] s390: Fix...
701
702
  	kfree(css);
  }
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
703
704
705
706
707
  static ssize_t
  css_cm_enable_show(struct device *dev, struct device_attribute *attr,
  		   char *buf)
  {
  	struct channel_subsystem *css = to_css(dev);
8284fb19e   Michael Ernst   [S390] cio: fix p...
708
  	int ret;
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
709
710
711
  
  	if (!css)
  		return 0;
8284fb19e   Michael Ernst   [S390] cio: fix p...
712
713
714
715
716
  	mutex_lock(&css->mutex);
  	ret = sprintf(buf, "%x
  ", css->cm_enabled);
  	mutex_unlock(&css->mutex);
  	return ret;
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
717
718
719
720
721
722
723
724
  }
  
  static ssize_t
  css_cm_enable_store(struct device *dev, struct device_attribute *attr,
  		    const char *buf, size_t count)
  {
  	struct channel_subsystem *css = to_css(dev);
  	int ret;
2f9722023   Cornelia Huck   [S390] cio: Use s...
725
  	unsigned long val;
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
726

0178722be   Jingoo Han   s390: replace str...
727
  	ret = kstrtoul(buf, 16, &val);
2f9722023   Cornelia Huck   [S390] cio: Use s...
728
729
  	if (ret)
  		return ret;
8284fb19e   Michael Ernst   [S390] cio: fix p...
730
  	mutex_lock(&css->mutex);
2f9722023   Cornelia Huck   [S390] cio: Use s...
731
732
  	switch (val) {
  	case 0:
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
733
734
  		ret = css->cm_enabled ? chsc_secm(css, 0) : 0;
  		break;
2f9722023   Cornelia Huck   [S390] cio: Use s...
735
  	case 1:
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
736
737
738
739
740
  		ret = css->cm_enabled ? 0 : chsc_secm(css, 1);
  		break;
  	default:
  		ret = -EINVAL;
  	}
8284fb19e   Michael Ernst   [S390] cio: fix p...
741
  	mutex_unlock(&css->mutex);
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
742
743
744
745
  	return ret < 0 ? ret : count;
  }
  
  static DEVICE_ATTR(cm_enable, 0644, css_cm_enable_show, css_cm_enable_store);
4d284cac7   Heiko Carstens   [S390] Avoid exce...
746
  static int __init setup_css(int nr)
a28c69448   Cornelia Huck   [PATCH] s390: int...
747
748
  {
  	u32 tod_high;
d7b5a4c94   Cornelia Huck   [S390] Support fo...
749
  	int ret;
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
750
  	struct channel_subsystem *css;
a28c69448   Cornelia Huck   [PATCH] s390: int...
751

7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
752
753
754
755
756
  	css = channel_subsystems[nr];
  	memset(css, 0, sizeof(struct channel_subsystem));
  	css->pseudo_subchannel =
  		kzalloc(sizeof(*css->pseudo_subchannel), GFP_KERNEL);
  	if (!css->pseudo_subchannel)
d7b5a4c94   Cornelia Huck   [S390] Support fo...
757
  		return -ENOMEM;
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
758
759
  	css->pseudo_subchannel->dev.parent = &css->device;
  	css->pseudo_subchannel->dev.release = css_subchannel_release;
1bf5b2853   Cornelia Huck   [S390] bus_id -> ...
760
  	dev_set_name(&css->pseudo_subchannel->dev, "defunct");
5d6e6b6f6   Peter Oberparleiter   [S390] cio: intro...
761
  	mutex_init(&css->pseudo_subchannel->reg_mutex);
e5dcf0025   Sebastian Ott   s390/css: move su...
762
  	ret = css_sch_create_locks(css->pseudo_subchannel);
d7b5a4c94   Cornelia Huck   [S390] Support fo...
763
  	if (ret) {
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
764
  		kfree(css->pseudo_subchannel);
d7b5a4c94   Cornelia Huck   [S390] Support fo...
765
766
  		return ret;
  	}
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
767
768
769
  	mutex_init(&css->mutex);
  	css->valid = 1;
  	css->cssid = nr;
1bf5b2853   Cornelia Huck   [S390] bus_id -> ...
770
  	dev_set_name(&css->device, "css%x", nr);
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
771
  	css->device.release = channel_subsystem_release;
1aae0560d   Heiko Carstens   s390/time: rename...
772
  	tod_high = (u32) (get_tod_clock() >> 32);
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
773
  	css_generate_pgid(css, tod_high);
d7b5a4c94   Cornelia Huck   [S390] Support fo...
774
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
  }
a55360df4   Cornelia Huck   [S390] cio: Disab...
776
777
778
779
780
781
782
783
784
785
786
  static int css_reboot_event(struct notifier_block *this,
  			    unsigned long event,
  			    void *ptr)
  {
  	int ret, i;
  
  	ret = NOTIFY_DONE;
  	for (i = 0; i <= __MAX_CSSID; i++) {
  		struct channel_subsystem *css;
  
  		css = channel_subsystems[i];
8284fb19e   Michael Ernst   [S390] cio: fix p...
787
  		mutex_lock(&css->mutex);
a55360df4   Cornelia Huck   [S390] cio: Disab...
788
789
790
  		if (css->cm_enabled)
  			if (chsc_secm(css, 0))
  				ret = NOTIFY_BAD;
8284fb19e   Michael Ernst   [S390] cio: fix p...
791
  		mutex_unlock(&css->mutex);
a55360df4   Cornelia Huck   [S390] cio: Disab...
792
793
794
795
796
797
798
799
  	}
  
  	return ret;
  }
  
  static struct notifier_block css_reboot_notifier = {
  	.notifier_call = css_reboot_event,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
800
  /*
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
801
802
803
804
805
806
807
808
   * Since the css devices are neither on a bus nor have a class
   * nor have a special device type, we cannot stop/restart channel
   * path measurements via the normal suspend/resume callbacks, but have
   * to use notifiers.
   */
  static int css_power_event(struct notifier_block *this, unsigned long event,
  			   void *ptr)
  {
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
  	int ret, i;
  
  	switch (event) {
  	case PM_HIBERNATION_PREPARE:
  	case PM_SUSPEND_PREPARE:
  		ret = NOTIFY_DONE;
  		for (i = 0; i <= __MAX_CSSID; i++) {
  			struct channel_subsystem *css;
  
  			css = channel_subsystems[i];
  			mutex_lock(&css->mutex);
  			if (!css->cm_enabled) {
  				mutex_unlock(&css->mutex);
  				continue;
  			}
f0c077a8b   Akinobu Mita   PM: Improve error...
824
825
  			ret = __chsc_do_secm(css, 0);
  			ret = notifier_from_errno(ret);
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
  			mutex_unlock(&css->mutex);
  		}
  		break;
  	case PM_POST_HIBERNATION:
  	case PM_POST_SUSPEND:
  		ret = NOTIFY_DONE;
  		for (i = 0; i <= __MAX_CSSID; i++) {
  			struct channel_subsystem *css;
  
  			css = channel_subsystems[i];
  			mutex_lock(&css->mutex);
  			if (!css->cm_enabled) {
  				mutex_unlock(&css->mutex);
  				continue;
  			}
f0c077a8b   Akinobu Mita   PM: Improve error...
841
842
  			ret = __chsc_do_secm(css, 1);
  			ret = notifier_from_errno(ret);
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
  			mutex_unlock(&css->mutex);
  		}
  		/* search for subchannels, which appeared during hibernation */
  		css_schedule_reprobe();
  		break;
  	default:
  		ret = NOTIFY_DONE;
  	}
  	return ret;
  
  }
  static struct notifier_block css_power_notifier = {
  	.notifier_call = css_power_event,
  };
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
859
   * Now that the driver core is running, we can setup our channel subsystem.
14556b33f   Sebastian Ott   s390/css: introdu...
860
   * The struct subchannel's are created during probing.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
   */
2f17644d1   Sebastian Ott   [S390] cio: merge...
862
  static int __init css_bus_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
  {
a28c69448   Cornelia Huck   [PATCH] s390: int...
864
  	int ret, i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
865

34aec07c1   Sebastian Ott   [S390] chsc: init...
866
867
868
  	ret = chsc_init();
  	if (ret)
  		return ret;
34196f82b   Sebastian Ott   [S390] chsc: cons...
869
  	chsc_determine_css_characteristics();
b0a285d31   Sebastian Ott   [S390] cio: idset...
870
871
  	/* Try to enable MSS. */
  	ret = chsc_enable_facility(CHSC_SDA_OC_MSS);
818c272bd   Sebastian Ott   [S390] cio: allow...
872
  	if (ret)
b0a285d31   Sebastian Ott   [S390] cio: idset...
873
  		max_ssid = 0;
818c272bd   Sebastian Ott   [S390] cio: allow...
874
875
  	else /* Success. */
  		max_ssid = __MAX_SSID;
b0a285d31   Sebastian Ott   [S390] cio: idset...
876

4434a38c3   Cornelia Huck   [S390] cio: Reorg...
877
878
879
  	ret = slow_subchannel_init();
  	if (ret)
  		goto out;
f5daba1d4   Heiko Carstens   [S390] split/move...
880
  	ret = crw_register_handler(CRW_RSC_SCH, css_process_crw);
c11561897   Cornelia Huck   [S390] cio: Clean...
881
882
  	if (ret)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
883
884
  	if ((ret = bus_register(&css_bus_type)))
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
885

a28c69448   Cornelia Huck   [PATCH] s390: int...
886
887
  	/* Setup css structure. */
  	for (i = 0; i <= __MAX_CSSID; i++) {
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
888
889
890
891
  		struct channel_subsystem *css;
  
  		css = kmalloc(sizeof(struct channel_subsystem), GFP_KERNEL);
  		if (!css) {
a28c69448   Cornelia Huck   [PATCH] s390: int...
892
  			ret = -ENOMEM;
fb6958a59   Cornelia Huck   [PATCH] s390: mul...
893
  			goto out_unregister;
a28c69448   Cornelia Huck   [PATCH] s390: int...
894
  		}
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
895
  		channel_subsystems[i] = css;
d7b5a4c94   Cornelia Huck   [S390] Support fo...
896
  		ret = setup_css(i);
a2164b817   Cornelia Huck   [S390] cio: Corre...
897
898
899
900
  		if (ret) {
  			kfree(channel_subsystems[i]);
  			goto out_unregister;
  		}
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
901
  		ret = device_register(&css->device);
a2164b817   Cornelia Huck   [S390] cio: Corre...
902
903
904
905
  		if (ret) {
  			put_device(&css->device);
  			goto out_unregister;
  		}
75784c008   Cornelia Huck   [S390] cio: Get r...
906
  		if (css_chsc_characteristics.secm) {
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
907
  			ret = device_create_file(&css->device,
7e560814d   Cornelia Huck   [S390] path group...
908
909
910
911
  						 &dev_attr_cm_enable);
  			if (ret)
  				goto out_device;
  		}
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
912
  		ret = device_register(&css->pseudo_subchannel->dev);
c63049332   Sebastian Ott   [S390] proper use...
913
914
  		if (ret) {
  			put_device(&css->pseudo_subchannel->dev);
d7b5a4c94   Cornelia Huck   [S390] Support fo...
915
  			goto out_file;
c63049332   Sebastian Ott   [S390] proper use...
916
  		}
a28c69448   Cornelia Huck   [PATCH] s390: int...
917
  	}
a55360df4   Cornelia Huck   [S390] cio: Disab...
918
919
  	ret = register_reboot_notifier(&css_reboot_notifier);
  	if (ret)
a2164b817   Cornelia Huck   [S390] cio: Corre...
920
  		goto out_unregister;
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
921
922
923
924
925
  	ret = register_pm_notifier(&css_power_notifier);
  	if (ret) {
  		unregister_reboot_notifier(&css_reboot_notifier);
  		goto out_unregister;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
926
  	css_init_done = 1;
3a3fc29a6   Cornelia Huck   [S390] cio: Intro...
927
  	/* Enable default isc for I/O subchannels. */
6ef556ccc   Cornelia Huck   [S390] cio: Use i...
928
  	isc_register(IO_SCH_ISC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
929

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
  	return 0;
d7b5a4c94   Cornelia Huck   [S390] Support fo...
931
  out_file:
a2164b817   Cornelia Huck   [S390] cio: Corre...
932
933
934
  	if (css_chsc_characteristics.secm)
  		device_remove_file(&channel_subsystems[i]->device,
  				   &dev_attr_cm_enable);
7e560814d   Cornelia Huck   [S390] path group...
935
  out_device:
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
936
  	device_unregister(&channel_subsystems[i]->device);
fb6958a59   Cornelia Huck   [PATCH] s390: mul...
937
  out_unregister:
a28c69448   Cornelia Huck   [PATCH] s390: int...
938
  	while (i > 0) {
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
939
  		struct channel_subsystem *css;
a28c69448   Cornelia Huck   [PATCH] s390: int...
940
  		i--;
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
941
942
  		css = channel_subsystems[i];
  		device_unregister(&css->pseudo_subchannel->dev);
a2164b817   Cornelia Huck   [S390] cio: Corre...
943
  		css->pseudo_subchannel = NULL;
75784c008   Cornelia Huck   [S390] cio: Get r...
944
  		if (css_chsc_characteristics.secm)
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
945
  			device_remove_file(&css->device,
495a5b45a   Cornelia Huck   [PATCH] s390: cha...
946
  					   &dev_attr_cm_enable);
7c9f4e3aa   Cornelia Huck   [S390] cio: renam...
947
  		device_unregister(&css->device);
a28c69448   Cornelia Huck   [PATCH] s390: int...
948
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
949
950
  	bus_unregister(&css_bus_type);
  out:
34aec07c1   Sebastian Ott   [S390] chsc: init...
951
  	crw_unregister_handler(CRW_RSC_SCH);
b827d1c8b   Sebastian Ott   [S390] cio: dont ...
952
  	idset_free(slow_subchannel_set);
34aec07c1   Sebastian Ott   [S390] chsc: init...
953
  	chsc_init_cleanup();
e6d5a428e   Michael Ernst   [S390] convert ci...
954
955
956
  	pr_alert("The CSS device driver initialization failed with "
  		 "errno=%d
  ", ret);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
957
958
  	return ret;
  }
2f17644d1   Sebastian Ott   [S390] cio: merge...
959
960
961
962
963
964
965
966
967
968
969
970
971
972
  static void __init css_bus_cleanup(void)
  {
  	struct channel_subsystem *css;
  	int i;
  
  	for (i = 0; i <= __MAX_CSSID; i++) {
  		css = channel_subsystems[i];
  		device_unregister(&css->pseudo_subchannel->dev);
  		css->pseudo_subchannel = NULL;
  		if (css_chsc_characteristics.secm)
  			device_remove_file(&css->device, &dev_attr_cm_enable);
  		device_unregister(&css->device);
  	}
  	bus_unregister(&css_bus_type);
34aec07c1   Sebastian Ott   [S390] chsc: init...
973
  	crw_unregister_handler(CRW_RSC_SCH);
b827d1c8b   Sebastian Ott   [S390] cio: dont ...
974
  	idset_free(slow_subchannel_set);
34aec07c1   Sebastian Ott   [S390] chsc: init...
975
  	chsc_init_cleanup();
2f17644d1   Sebastian Ott   [S390] cio: merge...
976
977
978
979
980
981
982
983
984
985
  	isc_unregister(IO_SCH_ISC);
  }
  
  static int __init channel_subsystem_init(void)
  {
  	int ret;
  
  	ret = css_bus_init();
  	if (ret)
  		return ret;
be5d3823f   Sebastian Ott   [S390] cio: conso...
986
987
988
989
990
  	cio_work_q = create_singlethread_workqueue("cio");
  	if (!cio_work_q) {
  		ret = -ENOMEM;
  		goto out_bus;
  	}
2f17644d1   Sebastian Ott   [S390] cio: merge...
991
992
  	ret = io_subchannel_init();
  	if (ret)
be5d3823f   Sebastian Ott   [S390] cio: conso...
993
  		goto out_wq;
2f17644d1   Sebastian Ott   [S390] cio: merge...
994
995
  
  	return ret;
be5d3823f   Sebastian Ott   [S390] cio: conso...
996
997
998
999
1000
  out_wq:
  	destroy_workqueue(cio_work_q);
  out_bus:
  	css_bus_cleanup();
  	return ret;
2f17644d1   Sebastian Ott   [S390] cio: merge...
1001
1002
  }
  subsys_initcall(channel_subsystem_init);
8ea7f5590   Sebastian Ott   [S390] cio: intro...
1003
1004
1005
1006
1007
  static int css_settle(struct device_driver *drv, void *unused)
  {
  	struct css_driver *cssdrv = to_cssdriver(drv);
  
  	if (cssdrv->settle)
b4c707214   Sebastian Ott   [S390] cio: make ...
1008
  		return cssdrv->settle();
8ea7f5590   Sebastian Ott   [S390] cio: intro...
1009
1010
  	return 0;
  }
0d01bb892   Sebastian Ott   [S390] cio: trigg...
1011
  int css_complete_work(void)
879acca58   Sebastian Ott   [S390] cio: intro...
1012
1013
1014
1015
  {
  	int ret;
  
  	/* Wait for the evaluation of subchannels to finish. */
b4c707214   Sebastian Ott   [S390] cio: make ...
1016
1017
1018
1019
  	ret = wait_event_interruptible(css_eval_wq,
  				       atomic_read(&css_eval_scheduled) == 0);
  	if (ret)
  		return -EINTR;
879acca58   Sebastian Ott   [S390] cio: intro...
1020
1021
  	flush_workqueue(cio_work_q);
  	/* Wait for the subchannel type specific initialization to finish */
b4c707214   Sebastian Ott   [S390] cio: make ...
1022
  	return bus_for_each_drv(&css_bus_type, NULL, NULL, css_settle);
879acca58   Sebastian Ott   [S390] cio: intro...
1023
  }
2f17644d1   Sebastian Ott   [S390] cio: merge...
1024
1025
1026
1027
1028
1029
  /*
   * Wait for the initialization of devices to finish, to make sure we are
   * done with our setup if the search for the root device starts.
   */
  static int __init channel_subsystem_init_sync(void)
  {
14556b33f   Sebastian Ott   s390/css: introdu...
1030
1031
  	/* Register subchannels which are already in use. */
  	cio_register_early_subchannels();
703e5c999   Sebastian Ott   [S390] cio: intro...
1032
1033
  	/* Start initial subchannel evaluation. */
  	css_schedule_eval_all();
879acca58   Sebastian Ott   [S390] cio: intro...
1034
1035
  	css_complete_work();
  	return 0;
2f17644d1   Sebastian Ott   [S390] cio: merge...
1036
1037
  }
  subsys_initcall_sync(channel_subsystem_init_sync);
889ee9556   Sebastian Ott   [S390] add hook t...
1038
1039
  void channel_subsystem_reinit(void)
  {
62da177ac   Sebastian Ott   [S390] css: updat...
1040
1041
  	struct channel_path *chp;
  	struct chp_id chpid;
889ee9556   Sebastian Ott   [S390] add hook t...
1042
  	chsc_enable_facility(CHSC_SDA_OC_MSS);
62da177ac   Sebastian Ott   [S390] css: updat...
1043
1044
  	chp_id_for_each(&chpid) {
  		chp = chpid_to_chp(chpid);
cce0eacc2   Peter Oberparleiter   s390/cio: collect...
1045
1046
  		if (chp)
  			chp_update_desc(chp);
62da177ac   Sebastian Ott   [S390] css: updat...
1047
  	}
889ee9556   Sebastian Ott   [S390] add hook t...
1048
  }
879acca58   Sebastian Ott   [S390] cio: intro...
1049
1050
1051
1052
  #ifdef CONFIG_PROC_FS
  static ssize_t cio_settle_write(struct file *file, const char __user *buf,
  				size_t count, loff_t *ppos)
  {
b4c707214   Sebastian Ott   [S390] cio: make ...
1053
  	int ret;
879acca58   Sebastian Ott   [S390] cio: intro...
1054
1055
  	/* Handle pending CRW's. */
  	crw_wait_for_channel_report();
b4c707214   Sebastian Ott   [S390] cio: make ...
1056
1057
1058
  	ret = css_complete_work();
  
  	return ret ? ret : count;
879acca58   Sebastian Ott   [S390] cio: intro...
1059
1060
1061
  }
  
  static const struct file_operations cio_settle_proc_fops = {
58ea91c05   Martin Schwidefsky   [S390] avoid defa...
1062
  	.open = nonseekable_open,
879acca58   Sebastian Ott   [S390] cio: intro...
1063
  	.write = cio_settle_write,
6038f373a   Arnd Bergmann   llseek: automatic...
1064
  	.llseek = no_llseek,
879acca58   Sebastian Ott   [S390] cio: intro...
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  };
  
  static int __init cio_settle_init(void)
  {
  	struct proc_dir_entry *entry;
  
  	entry = proc_create("cio_settle", S_IWUSR, NULL,
  			    &cio_settle_proc_fops);
  	if (!entry)
  		return -ENOMEM;
  	return 0;
  }
  device_initcall(cio_settle_init);
  #endif /*CONFIG_PROC_FS*/
d7b5a4c94   Cornelia Huck   [S390] Support fo...
1079
1080
1081
1082
  int sch_is_pseudo_sch(struct subchannel *sch)
  {
  	return sch == to_css(sch->dev.parent)->pseudo_subchannel;
  }
f08adc008   Cornelia Huck   [S390] css: Use c...
1083
  static int css_bus_match(struct device *dev, struct device_driver *drv)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
  {
084325d80   Cornelia Huck   [S390] cio: Use h...
1085
1086
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *driver = to_cssdriver(drv);
f08adc008   Cornelia Huck   [S390] css: Use c...
1087
  	struct css_device_id *id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088

f08adc008   Cornelia Huck   [S390] css: Use c...
1089
1090
1091
1092
  	for (id = driver->subchannel_type; id->match_flags; id++) {
  		if (sch->st == id->type)
  			return 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1093
1094
1095
  
  	return 0;
  }
98c13c283   Cornelia Huck   [S390] cio: Reset...
1096
  static int css_probe(struct device *dev)
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1097
1098
  {
  	struct subchannel *sch;
98c13c283   Cornelia Huck   [S390] cio: Reset...
1099
  	int ret;
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1100
1101
  
  	sch = to_subchannel(dev);
084325d80   Cornelia Huck   [S390] cio: Use h...
1102
  	sch->driver = to_cssdriver(dev->driver);
98c13c283   Cornelia Huck   [S390] cio: Reset...
1103
1104
1105
1106
  	ret = sch->driver->probe ? sch->driver->probe(sch) : 0;
  	if (ret)
  		sch->driver = NULL;
  	return ret;
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1107
  }
98c13c283   Cornelia Huck   [S390] cio: Reset...
1108
  static int css_remove(struct device *dev)
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1109
1110
  {
  	struct subchannel *sch;
98c13c283   Cornelia Huck   [S390] cio: Reset...
1111
  	int ret;
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1112
1113
  
  	sch = to_subchannel(dev);
98c13c283   Cornelia Huck   [S390] cio: Reset...
1114
1115
1116
  	ret = sch->driver->remove ? sch->driver->remove(sch) : 0;
  	sch->driver = NULL;
  	return ret;
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1117
  }
98c13c283   Cornelia Huck   [S390] cio: Reset...
1118
  static void css_shutdown(struct device *dev)
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1119
1120
1121
1122
  {
  	struct subchannel *sch;
  
  	sch = to_subchannel(dev);
98c13c283   Cornelia Huck   [S390] cio: Reset...
1123
  	if (sch->driver && sch->driver->shutdown)
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1124
1125
  		sch->driver->shutdown(sch);
  }
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
  static int css_uevent(struct device *dev, struct kobj_uevent_env *env)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	int ret;
  
  	ret = add_uevent_var(env, "ST=%01X", sch->st);
  	if (ret)
  		return ret;
  	ret = add_uevent_var(env, "MODALIAS=css:t%01X", sch->st);
  	return ret;
  }
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
  static int css_pm_prepare(struct device *dev)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *drv;
  
  	if (mutex_is_locked(&sch->reg_mutex))
  		return -EAGAIN;
  	if (!sch->dev.driver)
  		return 0;
  	drv = to_cssdriver(sch->dev.driver);
  	/* Notify drivers that they may not register children. */
  	return drv->prepare ? drv->prepare(sch) : 0;
  }
  
  static void css_pm_complete(struct device *dev)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *drv;
  
  	if (!sch->dev.driver)
  		return;
  	drv = to_cssdriver(sch->dev.driver);
  	if (drv->complete)
  		drv->complete(sch);
  }
  
  static int css_pm_freeze(struct device *dev)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *drv;
  
  	if (!sch->dev.driver)
  		return 0;
  	drv = to_cssdriver(sch->dev.driver);
  	return drv->freeze ? drv->freeze(sch) : 0;
  }
  
  static int css_pm_thaw(struct device *dev)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *drv;
  
  	if (!sch->dev.driver)
  		return 0;
  	drv = to_cssdriver(sch->dev.driver);
  	return drv->thaw ? drv->thaw(sch) : 0;
  }
  
  static int css_pm_restore(struct device *dev)
  {
  	struct subchannel *sch = to_subchannel(dev);
  	struct css_driver *drv;
eb4f5d93d   Sebastian Ott   [S390] css: updat...
1189
  	css_update_ssd_info(sch);
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
1190
1191
1192
1193
1194
  	if (!sch->dev.driver)
  		return 0;
  	drv = to_cssdriver(sch->dev.driver);
  	return drv->restore ? drv->restore(sch) : 0;
  }
471452104   Alexey Dobriyan   const: constify r...
1195
  static const struct dev_pm_ops css_pm_ops = {
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
1196
1197
1198
1199
1200
1201
  	.prepare = css_pm_prepare,
  	.complete = css_pm_complete,
  	.freeze = css_pm_freeze,
  	.thaw = css_pm_thaw,
  	.restore = css_pm_restore,
  };
3041b6ab5   Sebastian Ott   [S390] css_bus_ty...
1202
  static struct bus_type css_bus_type = {
8bbace7e6   Cornelia Huck   [PATCH] Add {css,...
1203
1204
1205
1206
1207
  	.name     = "css",
  	.match    = css_bus_match,
  	.probe    = css_probe,
  	.remove   = css_remove,
  	.shutdown = css_shutdown,
7e9db9eae   Cornelia Huck   [S390] cio: Intro...
1208
  	.uevent   = css_uevent,
dcbd16d51   Sebastian Ott   [S390] pm: css bu...
1209
  	.pm = &css_pm_ops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1210
  };
25b7bb583   Cornelia Huck   [S390] cio: Add c...
1211
1212
1213
1214
1215
1216
1217
1218
1219
  /**
   * css_driver_register - register a css driver
   * @cdrv: css driver to register
   *
   * This is mainly a wrapper around driver_register that sets name
   * and bus_type in the embedded struct device_driver correctly.
   */
  int css_driver_register(struct css_driver *cdrv)
  {
25b7bb583   Cornelia Huck   [S390] cio: Add c...
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
  	cdrv->drv.bus = &css_bus_type;
  	return driver_register(&cdrv->drv);
  }
  EXPORT_SYMBOL_GPL(css_driver_register);
  
  /**
   * css_driver_unregister - unregister a css driver
   * @cdrv: css driver to unregister
   *
   * This is a wrapper around driver_unregister.
   */
  void css_driver_unregister(struct css_driver *cdrv)
  {
  	driver_unregister(&cdrv->drv);
  }
  EXPORT_SYMBOL_GPL(css_driver_unregister);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1236
  MODULE_LICENSE("GPL");