Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Driver for s390 eadm subchannels
  4 *
  5 * Copyright IBM Corp. 2012
  6 * Author(s): Sebastian Ott <sebott@linux.vnet.ibm.com>
  7 */
  8
  9#include <linux/kernel_stat.h>
 10#include <linux/completion.h>
 11#include <linux/workqueue.h>
 12#include <linux/spinlock.h>
 13#include <linux/device.h>
 14#include <linux/module.h>
 15#include <linux/timer.h>
 16#include <linux/slab.h>
 17#include <linux/list.h>
 18
 19#include <asm/css_chars.h>
 20#include <asm/debug.h>
 21#include <asm/isc.h>
 22#include <asm/cio.h>
 23#include <asm/scsw.h>
 24#include <asm/eadm.h>
 25
 26#include "eadm_sch.h"
 27#include "ioasm.h"
 28#include "cio.h"
 29#include "css.h"
 30#include "orb.h"
 31
 32MODULE_DESCRIPTION("driver for s390 eadm subchannels");
 33MODULE_LICENSE("GPL");
 34
 35#define EADM_TIMEOUT (7 * HZ)
 36static DEFINE_SPINLOCK(list_lock);
 37static LIST_HEAD(eadm_list);
 38
 39static debug_info_t *eadm_debug;
 40
 41#define EADM_LOG(imp, txt) do {					\
 42		debug_text_event(eadm_debug, imp, txt);		\
 43	} while (0)
 44
 45static void EADM_LOG_HEX(int level, void *data, int length)
 46{
 47	debug_event(eadm_debug, level, data, length);
 48}
 49
 50static void orb_init(union orb *orb)
 51{
 52	memset(orb, 0, sizeof(union orb));
 53	orb->eadm.compat1 = 1;
 54	orb->eadm.compat2 = 1;
 55	orb->eadm.fmt = 1;
 56	orb->eadm.x = 1;
 57}
 58
 59static int eadm_subchannel_start(struct subchannel *sch, struct aob *aob)
 60{
 61	union orb *orb = &get_eadm_private(sch)->orb;
 62	int cc;
 63
 64	orb_init(orb);
 65	orb->eadm.aob = (u32)__pa(aob);
 66	orb->eadm.intparm = (u32)(addr_t)sch;
 67	orb->eadm.key = PAGE_DEFAULT_KEY >> 4;
 68
 69	EADM_LOG(6, "start");
 70	EADM_LOG_HEX(6, &sch->schid, sizeof(sch->schid));
 71
 72	cc = ssch(sch->schid, orb);
 73	switch (cc) {
 74	case 0:
 75		sch->schib.scsw.eadm.actl |= SCSW_ACTL_START_PEND;
 76		break;
 77	case 1:		/* status pending */
 78	case 2:		/* busy */
 79		return -EBUSY;
 80	case 3:		/* not operational */
 81		return -ENODEV;
 82	}
 83	return 0;
 84}
 85
 86static int eadm_subchannel_clear(struct subchannel *sch)
 87{
 88	int cc;
 89
 90	cc = csch(sch->schid);
 91	if (cc)
 92		return -ENODEV;
 93
 94	sch->schib.scsw.eadm.actl |= SCSW_ACTL_CLEAR_PEND;
 95	return 0;
 96}
 97
 98static void eadm_subchannel_timeout(struct timer_list *t)
 99{
100	struct eadm_private *private = from_timer(private, t, timer);
101	struct subchannel *sch = private->sch;
102
103	spin_lock_irq(sch->lock);
104	EADM_LOG(1, "timeout");
105	EADM_LOG_HEX(1, &sch->schid, sizeof(sch->schid));
106	if (eadm_subchannel_clear(sch))
107		EADM_LOG(0, "clear failed");
108	spin_unlock_irq(sch->lock);
109}
110
111static void eadm_subchannel_set_timeout(struct subchannel *sch, int expires)
112{
113	struct eadm_private *private = get_eadm_private(sch);
114
115	if (expires == 0) {
116		del_timer(&private->timer);
117		return;
118	}
119	if (timer_pending(&private->timer)) {
120		if (mod_timer(&private->timer, jiffies + expires))
121			return;
122	}
123	private->timer.expires = jiffies + expires;
124	add_timer(&private->timer);
125}
126
127static void eadm_subchannel_irq(struct subchannel *sch)
128{
129	struct eadm_private *private = get_eadm_private(sch);
130	struct eadm_scsw *scsw = &sch->schib.scsw.eadm;
131	struct irb *irb = this_cpu_ptr(&cio_irb);
132	blk_status_t error = BLK_STS_OK;
133
134	EADM_LOG(6, "irq");
135	EADM_LOG_HEX(6, irb, sizeof(*irb));
136
137	inc_irq_stat(IRQIO_ADM);
138
139	if ((scsw->stctl & (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))
140	    && scsw->eswf == 1 && irb->esw.eadm.erw.r)
141		error = BLK_STS_IOERR;
142
143	if (scsw->fctl & SCSW_FCTL_CLEAR_FUNC)
144		error = BLK_STS_TIMEOUT;
145
146	eadm_subchannel_set_timeout(sch, 0);
147
148	if (private->state != EADM_BUSY) {
149		EADM_LOG(1, "irq unsol");
150		EADM_LOG_HEX(1, irb, sizeof(*irb));
151		private->state = EADM_NOT_OPER;
152		css_sched_sch_todo(sch, SCH_TODO_EVAL);
153		return;
154	}
155	scm_irq_handler((struct aob *)(unsigned long)scsw->aob, error);
156	private->state = EADM_IDLE;
157
158	if (private->completion)
159		complete(private->completion);
160}
161
162static struct subchannel *eadm_get_idle_sch(void)
163{
164	struct eadm_private *private;
165	struct subchannel *sch;
166	unsigned long flags;
167
168	spin_lock_irqsave(&list_lock, flags);
169	list_for_each_entry(private, &eadm_list, head) {
170		sch = private->sch;
171		spin_lock(sch->lock);
172		if (private->state == EADM_IDLE) {
173			private->state = EADM_BUSY;
174			list_move_tail(&private->head, &eadm_list);
175			spin_unlock(sch->lock);
176			spin_unlock_irqrestore(&list_lock, flags);
177
178			return sch;
179		}
180		spin_unlock(sch->lock);
181	}
182	spin_unlock_irqrestore(&list_lock, flags);
183
184	return NULL;
185}
186
187int eadm_start_aob(struct aob *aob)
188{
189	struct eadm_private *private;
190	struct subchannel *sch;
191	unsigned long flags;
192	int ret;
193
194	sch = eadm_get_idle_sch();
195	if (!sch)
196		return -EBUSY;
197
198	spin_lock_irqsave(sch->lock, flags);
199	eadm_subchannel_set_timeout(sch, EADM_TIMEOUT);
200	ret = eadm_subchannel_start(sch, aob);
201	if (!ret)
202		goto out_unlock;
203
204	/* Handle start subchannel failure. */
205	eadm_subchannel_set_timeout(sch, 0);
206	private = get_eadm_private(sch);
207	private->state = EADM_NOT_OPER;
208	css_sched_sch_todo(sch, SCH_TODO_EVAL);
209
210out_unlock:
211	spin_unlock_irqrestore(sch->lock, flags);
212
213	return ret;
214}
215EXPORT_SYMBOL_GPL(eadm_start_aob);
216
217static int eadm_subchannel_probe(struct subchannel *sch)
218{
219	struct eadm_private *private;
220	int ret;
221
222	private = kzalloc(sizeof(*private), GFP_KERNEL | GFP_DMA);
223	if (!private)
224		return -ENOMEM;
225
226	INIT_LIST_HEAD(&private->head);
227	timer_setup(&private->timer, eadm_subchannel_timeout, 0);
228
229	spin_lock_irq(sch->lock);
230	set_eadm_private(sch, private);
231	private->state = EADM_IDLE;
232	private->sch = sch;
233	sch->isc = EADM_SCH_ISC;
234	ret = cio_enable_subchannel(sch, (u32)(unsigned long)sch);
235	if (ret) {
236		set_eadm_private(sch, NULL);
237		spin_unlock_irq(sch->lock);
238		kfree(private);
239		goto out;
240	}
241	spin_unlock_irq(sch->lock);
242
243	spin_lock_irq(&list_lock);
244	list_add(&private->head, &eadm_list);
245	spin_unlock_irq(&list_lock);
246
247	if (dev_get_uevent_suppress(&sch->dev)) {
248		dev_set_uevent_suppress(&sch->dev, 0);
249		kobject_uevent(&sch->dev.kobj, KOBJ_ADD);
250	}
251out:
252	return ret;
253}
254
255static void eadm_quiesce(struct subchannel *sch)
256{
257	struct eadm_private *private = get_eadm_private(sch);
258	DECLARE_COMPLETION_ONSTACK(completion);
259	int ret;
260
261	spin_lock_irq(sch->lock);
262	if (private->state != EADM_BUSY)
263		goto disable;
264
265	if (eadm_subchannel_clear(sch))
266		goto disable;
267
268	private->completion = &completion;
269	spin_unlock_irq(sch->lock);
270
271	wait_for_completion_io(&completion);
272
273	spin_lock_irq(sch->lock);
274	private->completion = NULL;
275
276disable:
277	eadm_subchannel_set_timeout(sch, 0);
278	do {
279		ret = cio_disable_subchannel(sch);
280	} while (ret == -EBUSY);
281
282	spin_unlock_irq(sch->lock);
283}
284
285static int eadm_subchannel_remove(struct subchannel *sch)
286{
287	struct eadm_private *private = get_eadm_private(sch);
288
289	spin_lock_irq(&list_lock);
290	list_del(&private->head);
291	spin_unlock_irq(&list_lock);
292
293	eadm_quiesce(sch);
294
295	spin_lock_irq(sch->lock);
296	set_eadm_private(sch, NULL);
297	spin_unlock_irq(sch->lock);
298
299	kfree(private);
300
301	return 0;
302}
303
304static void eadm_subchannel_shutdown(struct subchannel *sch)
305{
306	eadm_quiesce(sch);
307}
308
309static int eadm_subchannel_freeze(struct subchannel *sch)
310{
311	return cio_disable_subchannel(sch);
312}
313
314static int eadm_subchannel_restore(struct subchannel *sch)
315{
316	return cio_enable_subchannel(sch, (u32)(unsigned long)sch);
317}
318
319/**
320 * eadm_subchannel_sch_event - process subchannel event
321 * @sch: subchannel
322 * @process: non-zero if function is called in process context
323 *
324 * An unspecified event occurred for this subchannel. Adjust data according
325 * to the current operational state of the subchannel. Return zero when the
326 * event has been handled sufficiently or -EAGAIN when this function should
327 * be called again in process context.
328 */
329static int eadm_subchannel_sch_event(struct subchannel *sch, int process)
330{
331	struct eadm_private *private;
332	unsigned long flags;
333
334	spin_lock_irqsave(sch->lock, flags);
335	if (!device_is_registered(&sch->dev))
336		goto out_unlock;
337
338	if (work_pending(&sch->todo_work))
339		goto out_unlock;
340
341	if (cio_update_schib(sch)) {
342		css_sched_sch_todo(sch, SCH_TODO_UNREG);
343		goto out_unlock;
344	}
345	private = get_eadm_private(sch);
346	if (private->state == EADM_NOT_OPER)
347		private->state = EADM_IDLE;
348
349out_unlock:
350	spin_unlock_irqrestore(sch->lock, flags);
351
352	return 0;
353}
354
355static struct css_device_id eadm_subchannel_ids[] = {
356	{ .match_flags = 0x1, .type = SUBCHANNEL_TYPE_ADM, },
357	{ /* end of list */ },
358};
359MODULE_DEVICE_TABLE(css, eadm_subchannel_ids);
360
361static struct css_driver eadm_subchannel_driver = {
362	.drv = {
363		.name = "eadm_subchannel",
364		.owner = THIS_MODULE,
365	},
366	.subchannel_type = eadm_subchannel_ids,
367	.irq = eadm_subchannel_irq,
368	.probe = eadm_subchannel_probe,
369	.remove = eadm_subchannel_remove,
370	.shutdown = eadm_subchannel_shutdown,
371	.sch_event = eadm_subchannel_sch_event,
372	.freeze = eadm_subchannel_freeze,
373	.thaw = eadm_subchannel_restore,
374	.restore = eadm_subchannel_restore,
375};
376
377static int __init eadm_sch_init(void)
378{
379	int ret;
380
381	if (!css_general_characteristics.eadm)
382		return -ENXIO;
383
384	eadm_debug = debug_register("eadm_log", 16, 1, 16);
385	if (!eadm_debug)
386		return -ENOMEM;
387
388	debug_register_view(eadm_debug, &debug_hex_ascii_view);
389	debug_set_level(eadm_debug, 2);
390
391	isc_register(EADM_SCH_ISC);
392	ret = css_driver_register(&eadm_subchannel_driver);
393	if (ret)
394		goto cleanup;
395
396	return ret;
397
398cleanup:
399	isc_unregister(EADM_SCH_ISC);
400	debug_unregister(eadm_debug);
401	return ret;
402}
403
404static void __exit eadm_sch_exit(void)
405{
406	css_driver_unregister(&eadm_subchannel_driver);
407	isc_unregister(EADM_SCH_ISC);
408	debug_unregister(eadm_debug);
409}
410module_init(eadm_sch_init);
411module_exit(eadm_sch_exit);