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