File Index
Files and directories
Sign in
FILE

eadm_sch.c

File preview with syntax highlighting.

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