Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * driver: reading from and writing to system console on S/390 via SCLP
0004  *
0005  * Copyright IBM Corp. 1999, 2009
0006  *
0007  * Author(s): Martin Peschke <mpeschke@de.ibm.com>
0008  *        Martin Schwidefsky <schwidefsky@de.ibm.com>
0009  */
0010 
0011 #include <linux/kmod.h>
0012 #include <linux/types.h>
0013 #include <linux/err.h>
0014 #include <linux/string.h>
0015 #include <linux/spinlock.h>
0016 #include <linux/ctype.h>
0017 #include <linux/uaccess.h>
0018 
0019 #include "sclp.h"
0020 #include "sclp_rw.h"
0021 
0022 /*
0023  * The room for the SCCB (only for writing) is not equal to a pages size
0024  * (as it is specified as the maximum size in the SCLP documentation)
0025  * because of the additional data structure described above.
0026  */
0027 #define MAX_SCCB_ROOM (PAGE_SIZE - sizeof(struct sclp_buffer))
0028 
0029 /* Event type structure for write message and write priority message */
0030 static struct sclp_register sclp_rw_event = {
0031     .send_mask = EVTYP_MSG_MASK,
0032 };
0033 
0034 /*
0035  * Setup a sclp write buffer. Gets a page as input (4K) and returns
0036  * a pointer to a struct sclp_buffer structure that is located at the
0037  * end of the input page. This reduces the buffer space by a few
0038  * bytes but simplifies things.
0039  */
0040 struct sclp_buffer *
0041 sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
0042 {
0043     struct sclp_buffer *buffer;
0044     struct sccb_header *sccb;
0045 
0046     sccb = (struct sccb_header *) page;
0047     /*
0048      * We keep the struct sclp_buffer structure at the end
0049      * of the sccb page.
0050      */
0051     buffer = ((struct sclp_buffer *) ((addr_t) sccb + PAGE_SIZE)) - 1;
0052     buffer->sccb = sccb;
0053     buffer->retry_count = 0;
0054     buffer->messages = 0;
0055     buffer->char_sum = 0;
0056     buffer->current_line = NULL;
0057     buffer->current_length = 0;
0058     buffer->columns = columns;
0059     buffer->htab = htab;
0060 
0061     /* initialize sccb */
0062     memset(sccb, 0, sizeof(struct sccb_header));
0063     sccb->length = sizeof(struct sccb_header);
0064 
0065     return buffer;
0066 }
0067 
0068 /*
0069  * Return a pointer to the original page that has been used to create
0070  * the buffer.
0071  */
0072 void *
0073 sclp_unmake_buffer(struct sclp_buffer *buffer)
0074 {
0075     return buffer->sccb;
0076 }
0077 
0078 /*
0079  * Initialize a new message the end of the provided buffer with
0080  * enough room for max_len characters. Return 0 on success.
0081  */
0082 static int
0083 sclp_initialize_mto(struct sclp_buffer *buffer, int max_len)
0084 {
0085     struct sccb_header *sccb;
0086     struct msg_buf *msg;
0087     struct mdb *mdb;
0088     struct go *go;
0089     struct mto *mto;
0090     int msg_size;
0091 
0092     /* max size of new message including message text  */
0093     msg_size = sizeof(struct msg_buf) + max_len;
0094 
0095     /* check if current buffer sccb can contain the mto */
0096     sccb = buffer->sccb;
0097     if ((MAX_SCCB_ROOM - sccb->length) < msg_size)
0098         return -ENOMEM;
0099 
0100     msg = (struct msg_buf *)((addr_t) sccb + sccb->length);
0101     memset(msg, 0, sizeof(struct msg_buf));
0102     msg->header.length = sizeof(struct msg_buf);
0103     msg->header.type = EVTYP_MSG;
0104 
0105     mdb = &msg->mdb;
0106     mdb->header.length = sizeof(struct mdb);
0107     mdb->header.type = 1;
0108     mdb->header.tag = 0xD4C4C240;   /* ebcdic "MDB " */
0109     mdb->header.revision_code = 1;
0110 
0111     go = &mdb->go;
0112     go->length = sizeof(struct go);
0113     go->type = 1;
0114 
0115     mto = &mdb->mto;
0116     mto->length = sizeof(struct mto);
0117     mto->type = 4;  /* message text object */
0118     mto->line_type_flags = LNTPFLGS_ENDTEXT; /* end text */
0119 
0120     /* set pointer to first byte after struct mto. */
0121     buffer->current_msg = msg;
0122     buffer->current_line = (char *) (mto + 1);
0123     buffer->current_length = 0;
0124 
0125     return 0;
0126 }
0127 
0128 /*
0129  * Finalize message initialized by sclp_initialize_mto(),
0130  * updating the sizes of MTO, enclosing MDB, event buffer and SCCB.
0131  */
0132 static void
0133 sclp_finalize_mto(struct sclp_buffer *buffer)
0134 {
0135     struct sccb_header *sccb;
0136     struct msg_buf *msg;
0137 
0138     /*
0139      * update values of sizes
0140      * (SCCB, Event(Message) Buffer, Message Data Block)
0141      */
0142     sccb = buffer->sccb;
0143     msg = buffer->current_msg;
0144     msg->header.length += buffer->current_length;
0145     msg->mdb.header.length += buffer->current_length;
0146     msg->mdb.mto.length += buffer->current_length;
0147     sccb->length += msg->header.length;
0148 
0149     /*
0150      * count number of buffered messages (= number of Message Text
0151      * Objects) and number of buffered characters
0152      * for the SCCB currently used for buffering and at all
0153      */
0154     buffer->messages++;
0155     buffer->char_sum += buffer->current_length;
0156 
0157     buffer->current_line = NULL;
0158     buffer->current_length = 0;
0159     buffer->current_msg = NULL;
0160 }
0161 
0162 /*
0163  * processing of a message including escape characters,
0164  * returns number of characters written to the output sccb
0165  * ("processed" means that is not guaranteed that the character have already
0166  *  been sent to the SCLP but that it will be done at least next time the SCLP
0167  *  is not busy)
0168  */
0169 int
0170 sclp_write(struct sclp_buffer *buffer, const unsigned char *msg, int count)
0171 {
0172     int spaces, i_msg;
0173     int rc;
0174 
0175     /*
0176      * parse msg for escape sequences (\t,\v ...) and put formated
0177      * msg into an mto (created by sclp_initialize_mto).
0178      *
0179      * We have to do this work ourselfs because there is no support for
0180      * these characters on the native machine and only partial support
0181      * under VM (Why does VM interpret \n but the native machine doesn't ?)
0182      *
0183      * Depending on i/o-control setting the message is always written
0184      * immediately or we wait for a final new line maybe coming with the
0185      * next message. Besides we avoid a buffer overrun by writing its
0186      * content.
0187      *
0188      * RESTRICTIONS:
0189      *
0190      * \r and \b work within one line because we are not able to modify
0191      * previous output that have already been accepted by the SCLP.
0192      *
0193      * \t combined with following \r is not correctly represented because
0194      * \t is expanded to some spaces but \r does not know about a
0195      * previous \t and decreases the current position by one column.
0196      * This is in order to a slim and quick implementation.
0197      */
0198     for (i_msg = 0; i_msg < count; i_msg++) {
0199         switch (msg[i_msg]) {
0200         case '\n':  /* new line, line feed (ASCII)  */
0201             /* check if new mto needs to be created */
0202             if (buffer->current_line == NULL) {
0203                 rc = sclp_initialize_mto(buffer, 0);
0204                 if (rc)
0205                     return i_msg;
0206             }
0207             sclp_finalize_mto(buffer);
0208             break;
0209         case '\a':  /* bell, one for several times  */
0210             /* set SCLP sound alarm bit in General Object */
0211             if (buffer->current_line == NULL) {
0212                 rc = sclp_initialize_mto(buffer,
0213                              buffer->columns);
0214                 if (rc)
0215                     return i_msg;
0216             }
0217             buffer->current_msg->mdb.go.general_msg_flags |=
0218                 GNRLMSGFLGS_SNDALRM;
0219             break;
0220         case '\t':  /* horizontal tabulator  */
0221             /* check if new mto needs to be created */
0222             if (buffer->current_line == NULL) {
0223                 rc = sclp_initialize_mto(buffer,
0224                              buffer->columns);
0225                 if (rc)
0226                     return i_msg;
0227             }
0228             /* "go to (next htab-boundary + 1, same line)" */
0229             do {
0230                 if (buffer->current_length >= buffer->columns)
0231                     break;
0232                 /* ok, add a blank */
0233                 *buffer->current_line++ = 0x40;
0234                 buffer->current_length++;
0235             } while (buffer->current_length % buffer->htab);
0236             break;
0237         case '\f':  /* form feed  */
0238         case '\v':  /* vertical tabulator  */
0239             /* "go to (actual column, actual line + 1)" */
0240             /* = new line, leading spaces */
0241             if (buffer->current_line != NULL) {
0242                 spaces = buffer->current_length;
0243                 sclp_finalize_mto(buffer);
0244                 rc = sclp_initialize_mto(buffer,
0245                              buffer->columns);
0246                 if (rc)
0247                     return i_msg;
0248                 memset(buffer->current_line, 0x40, spaces);
0249                 buffer->current_line += spaces;
0250                 buffer->current_length = spaces;
0251             } else {
0252                 /* one an empty line this is the same as \n */
0253                 rc = sclp_initialize_mto(buffer,
0254                              buffer->columns);
0255                 if (rc)
0256                     return i_msg;
0257                 sclp_finalize_mto(buffer);
0258             }
0259             break;
0260         case '\b':  /* backspace  */
0261             /* "go to (actual column - 1, actual line)" */
0262             /* decrement counter indicating position, */
0263             /* do not remove last character */
0264             if (buffer->current_line != NULL &&
0265                 buffer->current_length > 0) {
0266                 buffer->current_length--;
0267                 buffer->current_line--;
0268             }
0269             break;
0270         case 0x00:  /* end of string  */
0271             /* transfer current line to SCCB */
0272             if (buffer->current_line != NULL)
0273                 sclp_finalize_mto(buffer);
0274             /* skip the rest of the message including the 0 byte */
0275             i_msg = count - 1;
0276             break;
0277         default:    /* no escape character  */
0278             /* do not output unprintable characters */
0279             if (!isprint(msg[i_msg]))
0280                 break;
0281             /* check if new mto needs to be created */
0282             if (buffer->current_line == NULL) {
0283                 rc = sclp_initialize_mto(buffer,
0284                              buffer->columns);
0285                 if (rc)
0286                     return i_msg;
0287             }
0288             *buffer->current_line++ = sclp_ascebc(msg[i_msg]);
0289             buffer->current_length++;
0290             break;
0291         }
0292         /* check if current mto is full */
0293         if (buffer->current_line != NULL &&
0294             buffer->current_length >= buffer->columns)
0295             sclp_finalize_mto(buffer);
0296     }
0297 
0298     /* return number of processed characters */
0299     return i_msg;
0300 }
0301 
0302 /*
0303  * Return the number of free bytes in the sccb
0304  */
0305 int
0306 sclp_buffer_space(struct sclp_buffer *buffer)
0307 {
0308     struct sccb_header *sccb;
0309     int count;
0310 
0311     sccb = buffer->sccb;
0312     count = MAX_SCCB_ROOM - sccb->length;
0313     if (buffer->current_line != NULL)
0314         count -= sizeof(struct msg_buf) + buffer->current_length;
0315     return count;
0316 }
0317 
0318 /*
0319  * Return number of characters in buffer
0320  */
0321 unsigned int
0322 sclp_chars_in_buffer(struct sclp_buffer *buffer)
0323 {
0324     unsigned int count;
0325 
0326     count = buffer->char_sum;
0327     if (buffer->current_line != NULL)
0328         count += buffer->current_length;
0329     return count;
0330 }
0331 
0332 /*
0333  * called by sclp_console_init and/or sclp_tty_init
0334  */
0335 int
0336 sclp_rw_init(void)
0337 {
0338     static int init_done = 0;
0339     int rc;
0340 
0341     if (init_done)
0342         return 0;
0343 
0344     rc = sclp_register(&sclp_rw_event);
0345     if (rc == 0)
0346         init_done = 1;
0347     return rc;
0348 }
0349 
0350 #define SCLP_BUFFER_MAX_RETRY       1
0351 
0352 /*
0353  * second half of Write Event Data-function that has to be done after
0354  * interruption indicating completion of Service Call.
0355  */
0356 static void
0357 sclp_writedata_callback(struct sclp_req *request, void *data)
0358 {
0359     int rc;
0360     struct sclp_buffer *buffer;
0361     struct sccb_header *sccb;
0362 
0363     buffer = (struct sclp_buffer *) data;
0364     sccb = buffer->sccb;
0365 
0366     if (request->status == SCLP_REQ_FAILED) {
0367         if (buffer->callback != NULL)
0368             buffer->callback(buffer, -EIO);
0369         return;
0370     }
0371     /* check SCLP response code and choose suitable action  */
0372     switch (sccb->response_code) {
0373     case 0x0020 :
0374         /* Normal completion, buffer processed, message(s) sent */
0375         rc = 0;
0376         break;
0377 
0378     case 0x0340: /* Contained SCLP equipment check */
0379         if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
0380             rc = -EIO;
0381             break;
0382         }
0383         /* remove processed buffers and requeue rest */
0384         if (sclp_remove_processed((struct sccb_header *) sccb) > 0) {
0385             /* not all buffers were processed */
0386             sccb->response_code = 0x0000;
0387             buffer->request.status = SCLP_REQ_FILLED;
0388             rc = sclp_add_request(request);
0389             if (rc == 0)
0390                 return;
0391         } else
0392             rc = 0;
0393         break;
0394 
0395     case 0x0040: /* SCLP equipment check */
0396     case 0x05f0: /* Target resource in improper state */
0397         if (++buffer->retry_count > SCLP_BUFFER_MAX_RETRY) {
0398             rc = -EIO;
0399             break;
0400         }
0401         /* retry request */
0402         sccb->response_code = 0x0000;
0403         buffer->request.status = SCLP_REQ_FILLED;
0404         rc = sclp_add_request(request);
0405         if (rc == 0)
0406             return;
0407         break;
0408     default:
0409         if (sccb->response_code == 0x71f0)
0410             rc = -ENOMEM;
0411         else
0412             rc = -EINVAL;
0413         break;
0414     }
0415     if (buffer->callback != NULL)
0416         buffer->callback(buffer, rc);
0417 }
0418 
0419 /*
0420  * Setup the request structure in the struct sclp_buffer to do SCLP Write
0421  * Event Data and pass the request to the core SCLP loop. Return zero on
0422  * success, non-zero otherwise.
0423  */
0424 int
0425 sclp_emit_buffer(struct sclp_buffer *buffer,
0426          void (*callback)(struct sclp_buffer *, int))
0427 {
0428     /* add current line if there is one */
0429     if (buffer->current_line != NULL)
0430         sclp_finalize_mto(buffer);
0431 
0432     /* Are there messages in the output buffer ? */
0433     if (buffer->messages == 0)
0434         return -EIO;
0435 
0436     buffer->request.command = SCLP_CMDW_WRITE_EVENT_DATA;
0437     buffer->request.status = SCLP_REQ_FILLED;
0438     buffer->request.callback = sclp_writedata_callback;
0439     buffer->request.callback_data = buffer;
0440     buffer->request.sccb = buffer->sccb;
0441     buffer->callback = callback;
0442     return sclp_add_request(&buffer->request);
0443 }