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