root/drivers/s390/char/sclp_rw.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sclp_make_buffer
  2. sclp_unmake_buffer
  3. sclp_initialize_mto
  4. sclp_finalize_mto
  5. sclp_write
  6. sclp_buffer_space
  7. sclp_chars_in_buffer
  8. sclp_set_columns
  9. sclp_set_htab
  10. sclp_rw_init
  11. sclp_writedata_callback
  12. sclp_emit_buffer

   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 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 *
  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 *
  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
  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
 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
 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
 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
 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  * sets or provides some values that influence the drivers behaviour
 341  */
 342 void
 343 sclp_set_columns(struct sclp_buffer *buffer, unsigned short columns)
 344 {
 345         buffer->columns = columns;
 346         if (buffer->current_line != NULL &&
 347             buffer->current_length > buffer->columns)
 348                 sclp_finalize_mto(buffer);
 349 }
 350 
 351 void
 352 sclp_set_htab(struct sclp_buffer *buffer, unsigned short htab)
 353 {
 354         buffer->htab = htab;
 355 }
 356 
 357 /*
 358  * called by sclp_console_init and/or sclp_tty_init
 359  */
 360 int
 361 sclp_rw_init(void)
 362 {
 363         static int init_done = 0;
 364         int rc;
 365 
 366         if (init_done)
 367                 return 0;
 368 
 369         rc = sclp_register(&sclp_rw_event);
 370         if (rc == 0)
 371                 init_done = 1;
 372         return rc;
 373 }
 374 
 375 #define SCLP_BUFFER_MAX_RETRY           1
 376 
 377 /*
 378  * second half of Write Event Data-function that has to be done after
 379  * interruption indicating completion of Service Call.
 380  */
 381 static void
 382 sclp_writedata_callback(struct sclp_req *request, void *data)
 383 {
 384         int rc;
 385         struct sclp_buffer *buffer;
 386         struct sccb_header *sccb;
 387 
 388         buffer = (struct sclp_buffer *) data;
 389         sccb = buffer->sccb;
 390 
 391         if (request->status == SCLP_REQ_FAILED) {
 392                 if (buffer->callback != NULL)
 393                         buffer->callback(buffer, -EIO);
 394                 return;
 395         }
 396         /* check SCLP response code and choose suitable action  */
 397         switch (sccb->response_code) {
 398         case 0x0020 :
 399                 /* Normal completion, buffer processed, message(s) sent */
 400                 rc = 0;
 401                 break;
 402 
 403         case 0x0340: /* Contained SCLP equipment check */
 404                 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
 405                         rc = -EIO;
 406                         break;
 407                 }
 408                 /* remove processed buffers and requeue rest */
 409                 if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
 410                         /* not all buffers were processed */
 411                         sccb->response_code = 0x0000;
 412                         buffer->request.status = SCLP_REQ_FILLED;
 413                         rc = sclp_add_request(request);
 414                         if (rc == 0)
 415                                 return;
 416                 } else
 417                         rc = 0;
 418                 break;
 419 
 420         case 0x0040: /* SCLP equipment check */
 421         case 0x05f0: /* Target resource in improper state */
 422                 if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
 423                         rc = -EIO;
 424                         break;
 425                 }
 426                 /* retry request */
 427                 sccb->response_code = 0x0000;
 428                 buffer->request.status = SCLP_REQ_FILLED;
 429                 rc = sclp_add_request(request);
 430                 if (rc == 0)
 431                         return;
 432                 break;
 433         default:
 434                 if (sccb->response_code == 0x71f0)
 435                         rc = -ENOMEM;
 436                 else
 437                         rc = -EINVAL;
 438                 break;
 439         }
 440         if (buffer->callback != NULL)
 441                 buffer->callback(buffer, rc);
 442 }
 443 
 444 /*
 445  * Setup the request structure in the struct sclp_buffer to do SCLP Write
 446  * Event Data and pass the request to the core SCLP loop. Return zero on
 447  * success, non-zero otherwise.
 448  */
 449 int
 450 sclp_emit_buffer(struct sclp_buffer *buffer,
 451                  void (*callback)(struct sclp_buffer *, int))
 452 {
 453         /* add current line if there is one */
 454         if (buffer->current_line != NULL)
 455                 sclp_finalize_mto(buffer);
 456 
 457         /* Are there messages in the output buffer ? */
 458         if (buffer->messages == 0)
 459                 return -EIO;
 460 
 461         buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
 462         buffer->request.status = SCLP_REQ_FILLED;
 463         buffer->request.callback = sclp_writedata_callback;
 464         buffer->request.callback_data = buffer;
 465         buffer->request.sccb = buffer->sccb;
 466         buffer->callback = callback;
 467         return sclp_add_request(&buffer->request);
 468 }

/* [<][>][^][v][top][bottom][index][help] */