1// SPDX-License-Identifier: GPL-2.0
2/*
3 * driver: reading from and writing to system console on S/390 via SCLP
4 *
5 * Copyright IBM Corp. 1999, 2009
6 *
7 * Author(s): Martin Peschke <mpeschke@de.ibm.com>
8 *	      Martin Schwidefsky <schwidefsky@de.ibm.com>
9 */
10
11#include <linux/kmod.h>
12#include <linux/types.h>
13#include <linux/err.h>
14#include <linux/string.h>
15#include <linux/spinlock.h>
16#include <linux/ctype.h>
17#include <linux/uaccess.h>
18
19#include "sclp.h"
20#include "sclp_rw.h"
21
22/*
23 * The room for the SCCB (only for writing) is not equal to a pages size
24 * (as it is specified as the maximum size in the SCLP documentation)
25 * because of the additional data structure described above.
26 */
27#define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
28
29static void sclp_rw_pm_event(struct sclp_register *reg,
30			     enum sclp_pm_event sclp_pm_event)
31{
32	sclp_console_pm_event(sclp_pm_event);
33}
34
35/* Event type structure for write message and write priority message */
36static struct sclp_register sclp_rw_event = {
37	.send_mask = EVTYP_MSG_MASK,
38	.pm_event_fn = sclp_rw_pm_event,
39};
40
41/*
42 * Setup a sclp write buffer. Gets a page as input (4K) and returns
43 * a pointer to a struct sclp_buffer structure that is located at the
44 * end of the input page. This reduces the buffer space by a few
45 * bytes but simplifies things.
46 */
47struct sclp_buffer *
48sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
49{
50	struct sclp_buffer *buffer;
51	struct sccb_header *sccb;
52
53	sccb = (struct sccb_header *) page;
54	/*
55	 * We keep the struct sclp_buffer structure at the end
56	 * of the sccb page.
57	 */
58	buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
59	buffer->sccb = sccb;
60	buffer->retry_count = 0;
61	buffer->messages = 0;
62	buffer->char_sum = 0;
63	buffer->current_line = NULL;
64	buffer->current_length = 0;
65	buffer->columns = columns;
66	buffer->htab = htab;
67
68	/* initialize sccb */
69	memset(sccb, 0, sizeof(struct sccb_header));
70	sccb->length = sizeof(struct sccb_header);
71
72	return buffer;
73}
74
75/*
76 * Return a pointer to the original page that has been used to create
77 * the buffer.
78 */
79void *
80sclp_unmake_buffer(struct sclp_buffer *buffer)
81{
82	return buffer->sccb;
83}
84
85/*
86 * Initialize a new message the end of the provided buffer with
87 * enough room for max_len characters. Return 0 on success.
88 */
89static int
90sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
91{
92	struct sccb_header *sccb;
93	struct msg_buf *msg;
94	struct mdb *mdb;
95	struct go *go;
96	struct mto *mto;
97	int msg_size;
98
99	/* max size of new message including message text  */
100	msg_size = sizeof(struct msg_buf) + max_len;
101
102	/* check if current buffer sccb can contain the mto */
103	sccb = buffer->sccb;
104	if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
105		return -ENOMEM;
106
107	msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
108	memset(msg, 0, sizeof(struct msg_buf));
109	msg->header.length = sizeof(struct msg_buf);
110	msg->header.type = EVTYP_MSG;
111
112	mdb = &msg->mdb;
113	mdb->header.length = sizeof(struct mdb);
114	mdb->header.type = 1;
115	mdb->header.tag = 0xD4C4C240;	/* ebcdic "MDB " */
116	mdb->header.revision_code = 1;
117
118	go = &mdb->go;
119	go->length = sizeof(struct go);
120	go->type = 1;
121
122	mto = &mdb->mto;
123	mto->length = sizeof(struct mto);
124	mto->type = 4;	/* message text object */
125	mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
126
127	/* set pointer to first byte after struct mto. */
128	buffer->current_msg = msg;
129	buffer->current_line = (char *) (mto + 1);
130	buffer->current_length = 0;
131
132	return 0;
133}
134
135/*
136 * Finalize message initialized by sclp_initialize_mto(),
137 * updating the sizes of MTO, enclosing MDB, event buffer and SCCB.
138 */
139static void
140sclp_finalize_mto(struct sclp_buffer *buffer)
141{
142	struct sccb_header *sccb;
143	struct msg_buf *msg;
144
145	/*
146	 * update values of sizes
147	 * (SCCB, Event(Message) Buffer, Message Data Block)
148	 */
149	sccb = buffer->sccb;
150	msg = buffer->current_msg;
151	msg->header.length += buffer->current_length;
152	msg->mdb.header.length += buffer->current_length;
153	msg->mdb.mto.length += buffer->current_length;
154	sccb->length += msg->header.length;
155
156	/*
157	 * count number of buffered messages (= number of Message Text
158	 * Objects) and number of buffered characters
159	 * for the SCCB currently used for buffering and at all
160	 */
161	buffer->messages++;
162	buffer->char_sum += buffer->current_length;
163
164	buffer->current_line = NULL;
165	buffer->current_length = 0;
166	buffer->current_msg = NULL;
167}
168
169/*
170 * processing of a message including escape characters,
171 * returns number of characters written to the output sccb
172 * ("processed" means that is not guaranteed that the character have already
173 *  been sent to the SCLP but that it will be done at least next time the SCLP
174 *  is not busy)
175 */
176int
177sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
178{
179	int spaces, i_msg;
180	int rc;
181
182	/*
183	 * parse msg for escape sequences (\t,\v ...) and put formated
184	 * msg into an mto (created by sclp_initialize_mto).
185	 *
186	 * We have to do this work ourselfs because there is no support for
187	 * these characters on the native machine and only partial support
188	 * under VM (Why does VM interpret \n but the native machine doesn't ?)
189	 *
190	 * Depending on i/o-control setting the message is always written
191	 * immediately or we wait for a final new line maybe coming with the
192	 * next message. Besides we avoid a buffer overrun by writing its
193	 * content.
194	 *
195	 * RESTRICTIONS:
196	 *
197	 * \r and \b work within one line because we are not able to modify
198	 * previous output that have already been accepted by the SCLP.
199	 *
200	 * \t combined with following \r is not correctly represented because
201	 * \t is expanded to some spaces but \r does not know about a
202	 * previous \t and decreases the current position by one column.
203	 * This is in order to a slim and quick implementation.
204	 */
205	for (i_msg = 0; i_msg < count; i_msg++) {
206		switch (msg[i_msg]) {
207		case '\n':	/* new line, line feed (ASCII)	*/
208			/* check if new mto needs to be created */
209			if (buffer->current_line == NULL) {
210				rc = sclp_initialize_mto(buffer, 0);
211				if (rc)
212					return i_msg;
213			}
214			sclp_finalize_mto(buffer);
215			break;
216		case '\a':	/* bell, one for several times	*/
217			/* set SCLP sound alarm bit in General Object */
218			if (buffer->current_line == NULL) {
219				rc = sclp_initialize_mto(buffer,
220							 buffer->columns);
221				if (rc)
222					return i_msg;
223			}
224			buffer->current_msg->mdb.go.general_msg_flags |=
225				GNRLMSGFLGS_SNDALRM;
226			break;
227		case '\t':	/* horizontal tabulator	 */
228			/* check if new mto needs to be created */
229			if (buffer->current_line == NULL) {
230				rc = sclp_initialize_mto(buffer,
231							 buffer->columns);
232				if (rc)
233					return i_msg;
234			}
235			/* "go to (next htab-boundary + 1, same line)" */
236			do {
237				if (buffer->current_length >= buffer->columns)
238					break;
239				/* ok, add a blank */
240				*buffer->current_line++ = 0x40;
241				buffer->current_length++;
242			} while (buffer->current_length % buffer->htab);
243			break;
244		case '\f':	/* form feed  */
245		case '\v':	/* vertical tabulator  */
246			/* "go to (actual column, actual line + 1)" */
247			/* = new line, leading spaces */
248			if (buffer->current_line != NULL) {
249				spaces = buffer->current_length;
250				sclp_finalize_mto(buffer);
251				rc = sclp_initialize_mto(buffer,
252							 buffer->columns);
253				if (rc)
254					return i_msg;
255				memset(buffer->current_line, 0x40, spaces);
256				buffer->current_line += spaces;
257				buffer->current_length = spaces;
258			} else {
259				/* one an empty line this is the same as \n */
260				rc = sclp_initialize_mto(buffer,
261							 buffer->columns);
262				if (rc)
263					return i_msg;
264				sclp_finalize_mto(buffer);
265			}
266			break;
267		case '\b':	/* backspace  */
268			/* "go to (actual column - 1, actual line)" */
269			/* decrement counter indicating position, */
270			/* do not remove last character */
271			if (buffer->current_line != NULL &&
272			    buffer->current_length > 0) {
273				buffer->current_length--;
274				buffer->current_line--;
275			}
276			break;
277		case 0x00:	/* end of string  */
278			/* transfer current line to SCCB */
279			if (buffer->current_line != NULL)
280				sclp_finalize_mto(buffer);
281			/* skip the rest of the message including the 0 byte */
282			i_msg = count - 1;
283			break;
284		default:	/* no escape character	*/
285			/* do not output unprintable characters */
286			if (!isprint(msg[i_msg]))
287				break;
288			/* check if new mto needs to be created */
289			if (buffer->current_line == NULL) {
290				rc = sclp_initialize_mto(buffer,
291							 buffer->columns);
292				if (rc)
293					return i_msg;
294			}
295			*buffer->current_line++ = sclp_ascebc(msg[i_msg]);
296			buffer->current_length++;
297			break;
298		}
299		/* check if current mto is full */
300		if (buffer->current_line != NULL &&
301		    buffer->current_length >= buffer->columns)
302			sclp_finalize_mto(buffer);
303	}
304
305	/* return number of processed characters */
306	return i_msg;
307}
308
309/*
310 * Return the number of free bytes in the sccb
311 */
312int
313sclp_buffer_space(struct sclp_buffer *buffer)
314{
315	struct sccb_header *sccb;
316	int count;
317
318	sccb = buffer->sccb;
319	count = MAX_SCCB_ROOM - sccb->length;
320	if (buffer->current_line != NULL)
321		count -= sizeof(struct msg_buf) + buffer->current_length;
322	return count;
323}
324
325/*
326 * Return number of characters in buffer
327 */
328int
329sclp_chars_in_buffer(struct sclp_buffer *buffer)
330{
331	int count;
332
333	count = buffer->char_sum;
334	if (buffer->current_line != NULL)
335		count += buffer->current_length;
336	return count;
337}
338
339/*
340 * called by sclp_console_init and/or sclp_tty_init
341 */
342int
343sclp_rw_init(void)
344{
345	static int init_done = 0;
346	int rc;
347
348	if (init_done)
349		return 0;
350
351	rc = sclp_register(&sclp_rw_event);
352	if (rc == 0)
353		init_done = 1;
354	return rc;
355}
356
357#define SCLP_BUFFER_MAX_RETRY		1
358
359/*
360 * second half of Write Event Data-function that has to be done after
361 * interruption indicating completion of Service Call.
362 */
363static void
364sclp_writedata_callback(struct sclp_req *request, void *data)
365{
366	int rc;
367	struct sclp_buffer *buffer;
368	struct sccb_header *sccb;
369
370	buffer = (struct sclp_buffer *) data;
371	sccb = buffer->sccb;
372
373	if (request->status == SCLP_REQ_FAILED) {
374		if (buffer->callback != NULL)
375			buffer->callback(buffer, -EIO);
376		return;
377	}
378	/* check SCLP response code and choose suitable action	*/
379	switch (sccb->response_code) {
380	case 0x0020 :
381		/* Normal completion, buffer processed, message(s) sent */
382		rc = 0;
383		break;
384
385	case 0x0340: /* Contained SCLP equipment check */
386		if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
387			rc = -EIO;
388			break;
389		}
390		/* remove processed buffers and requeue rest */
391		if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
392			/* not all buffers were processed */
393			sccb->response_code = 0x0000;
394			buffer->request.status = SCLP_REQ_FILLED;
395			rc = sclp_add_request(request);
396			if (rc == 0)
397				return;
398		} else
399			rc = 0;
400		break;
401
402	case 0x0040: /* SCLP equipment check */
403	case 0x05f0: /* Target resource in improper state */
404		if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
405			rc = -EIO;
406			break;
407		}
408		/* retry request */
409		sccb->response_code = 0x0000;
410		buffer->request.status = SCLP_REQ_FILLED;
411		rc = sclp_add_request(request);
412		if (rc == 0)
413			return;
414		break;
415	default:
416		if (sccb->response_code == 0x71f0)
417			rc = -ENOMEM;
418		else
419			rc = -EINVAL;
420		break;
421	}
422	if (buffer->callback != NULL)
423		buffer->callback(buffer, rc);
424}
425
426/*
427 * Setup the request structure in the struct sclp_buffer to do SCLP Write
428 * Event Data and pass the request to the core SCLP loop. Return zero on
429 * success, non-zero otherwise.
430 */
431int
432sclp_emit_buffer(struct sclp_buffer *buffer,
433		 void (*callback)(struct sclp_buffer *, int))
434{
435	/* add current line if there is one */
436	if (buffer->current_line != NULL)
437		sclp_finalize_mto(buffer);
438
439	/* Are there messages in the output buffer ? */
440	if (buffer->messages == 0)
441		return -EIO;
442
443	buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
444	buffer->request.status = SCLP_REQ_FILLED;
445	buffer->request.callback = sclp_writedata_callback;
446	buffer->request.callback_data = buffer;
447	buffer->request.sccb = buffer->sccb;
448	buffer->callback = callback;
449	return sclp_add_request(&buffer->request);
450}
451