• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
sclp_rw_pm_event(struct sclp_register * reg,enum sclp_pm_event sclp_pm_event)29 static 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 */
36 static 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  */
47 struct sclp_buffer *
sclp_make_buffer(void * page,unsigned short columns,unsigned short htab)48 sclp_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  */
79 void *
sclp_unmake_buffer(struct sclp_buffer * buffer)80 sclp_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  */
89 static int
sclp_initialize_mto(struct sclp_buffer * buffer,int max_len)90 sclp_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  */
139 static void
sclp_finalize_mto(struct sclp_buffer * buffer)140 sclp_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  */
176 int
sclp_write(struct sclp_buffer * buffer,const unsigned char * msg,int count)177 sclp_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  */
312 int
sclp_buffer_space(struct sclp_buffer * buffer)313 sclp_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  */
328 int
sclp_chars_in_buffer(struct sclp_buffer * buffer)329 sclp_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  */
342 int
sclp_rw_init(void)343 sclp_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  */
363 static void
sclp_writedata_callback(struct sclp_req * request,void * data)364 sclp_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  */
431 int
sclp_emit_buffer(struct sclp_buffer * buffer,void (* callback)(struct sclp_buffer *,int))432 sclp_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