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