linux/drivers/s390/char/sclp_rw.c
<<
>>
Prefs
   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 * sets or provides some values that influence the drivers behaviour
 341 */
 342void
 343sclp_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
 351void
 352sclp_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 */
 360int
 361sclp_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 */
 381static void
 382sclp_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 */
 449int
 450sclp_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}
 469