Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
ba3f8ae2
Commit
ba3f8ae2
authored
Dec 06, 2002
by
Martin Schwidefsky
Committed by
Linus Torvalds
Dec 06, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] s390: sclp driver.
Add error recovery for sclp failures. Fix endless loop in sclp_process_evbufs.
parent
a50082c6
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
286 additions
and
136 deletions
+286
-136
drivers/s390/char/Makefile
drivers/s390/char/Makefile
+3
-3
drivers/s390/char/sclp.c
drivers/s390/char/sclp.c
+128
-54
drivers/s390/char/sclp.h
drivers/s390/char/sclp.h
+1
-4
drivers/s390/char/sclp_con.c
drivers/s390/char/sclp_con.c
+8
-6
drivers/s390/char/sclp_cpi.c
drivers/s390/char/sclp_cpi.c
+2
-1
drivers/s390/char/sclp_rw.c
drivers/s390/char/sclp_rw.c
+125
-54
drivers/s390/char/sclp_rw.h
drivers/s390/char/sclp_rw.h
+6
-2
drivers/s390/char/sclp_tty.c
drivers/s390/char/sclp_tty.c
+11
-10
drivers/s390/char/sclp_tty.h
drivers/s390/char/sclp_tty.h
+2
-2
No files found.
drivers/s390/char/Makefile
View file @
ba3f8ae2
...
...
@@ -2,7 +2,7 @@
# S/390 character devices
#
export-objs
:=
sclp
_rw
.o tape_core.o tape_devmap.o tape_std.o
export-objs
:=
sclp.o tape_core.o tape_devmap.o tape_std.o
tub3270-objs
:=
tuball.o tubfs.o tubtty.o
\
tubttyaid.o tubttybld.o tubttyscl.o
\
...
...
@@ -10,8 +10,8 @@ tub3270-objs := tuball.o tubfs.o tubtty.o \
obj-y
+=
ctrlchar.o
obj-$(CONFIG_TN3215)
+=
con3215.o
obj-$(CONFIG_SCLP)
+=
sclp.o
obj-$(CONFIG_SCLP_TTY)
+=
sclp_
rw.o sclp_
tty.o
obj-$(CONFIG_SCLP)
+=
sclp.o
sclp_rw.o
obj-$(CONFIG_SCLP_TTY)
+=
sclp_tty.o
obj-$(CONFIG_SCLP_CONSOLE)
+=
sclp_con.o
obj-$(CONFIG_SCLP_CPI)
+=
sclp_cpi.o
obj-$(CONFIG_TN3270)
+=
tub3270.o
...
...
drivers/s390/char/sclp.c
View file @
ba3f8ae2
...
...
@@ -10,6 +10,7 @@
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/bootmem.h>
#include <linux/err.h>
...
...
@@ -17,6 +18,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>
#include <linux/timer.h>
#include <asm/s390_ext.h>
#include "sclp.h"
...
...
@@ -53,12 +55,21 @@ static char sclp_read_sccb[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
/* sccb for write mask sccb */
static
char
sclp_init_sccb
[
PAGE_SIZE
]
__attribute__
((
__aligned__
(
PAGE_SIZE
)));
/* Timer for init mask retries. */
static
struct
timer_list
retry_timer
;
static
unsigned
long
sclp_status
=
0
;
/* some status flags */
#define SCLP_INIT 0
#define SCLP_RUNNING 1
#define SCLP_READING 2
#define SCLP_INIT_POLL_INTERVAL 1
#define SCLP_COMMAND_INITIATED 0
#define SCLP_BUSY 2
#define SCLP_NOT_OPERATIONAL 3
/*
* assembler instruction for Service Call
*/
...
...
@@ -86,7 +97,7 @@ __service_call(sclp_cmdw_t command, void *sccb)
* new SCCB unchanged
* cc == 3: SCLP function not operational
*/
if
(
cc
==
3
)
if
(
cc
==
SCLP_NOT_OPERATIONAL
)
return
-
EIO
;
/*
* We set the SCLP_RUNNING bit for cc 2 as well because if
...
...
@@ -94,7 +105,7 @@ __service_call(sclp_cmdw_t command, void *sccb)
* that has to complete first
*/
set_bit
(
SCLP_RUNNING
,
&
sclp_status
);
if
(
cc
==
2
)
if
(
cc
==
SCLP_BUSY
)
return
-
EBUSY
;
return
0
;
}
...
...
@@ -130,6 +141,7 @@ __sclp_start_request(void)
static
int
sclp_process_evbufs
(
struct
sccb_header
*
sccb
)
{
int
result
;
unsigned
long
flags
;
struct
evbuf_header
*
evbuf
;
struct
list_head
*
l
;
...
...
@@ -137,8 +149,10 @@ sclp_process_evbufs(struct sccb_header *sccb)
spin_lock_irqsave
(
&
sclp_lock
,
flags
);
evbuf
=
(
struct
evbuf_header
*
)
(
sccb
+
1
);
while
((
void
*
)
evbuf
<
(
void
*
)
sccb
+
sccb
->
length
)
{
result
=
0
;
while
((
addr_t
)
evbuf
<
(
addr_t
)
sccb
+
sccb
->
length
)
{
/* check registered event */
t
=
NULL
;
list_for_each
(
l
,
&
sclp_reg_list
)
{
t
=
list_entry
(
l
,
struct
sclp_register
,
list
);
if
(
t
->
receive_mask
&
(
1
<<
(
32
-
evbuf
->
type
)))
{
...
...
@@ -146,56 +160,72 @@ sclp_process_evbufs(struct sccb_header *sccb)
t
->
receiver_fn
(
evbuf
);
break
;
}
else
t
=
NULL
;
}
/* Check for unrequested event buffer */
if
(
t
==
NULL
)
result
=
-
ENOSYS
;
evbuf
=
(
struct
evbuf_header
*
)
((
addr_t
)
evbuf
+
evbuf
->
length
);
}
spin_unlock_irqrestore
(
&
sclp_lock
,
flags
);
return
-
ENOSYS
;
return
result
;
}
/*
* postprocessing of unconditional read service call
*/
static
void
sclp_unconditional_read_cb
(
struct
sclp_req
*
read_req
,
void
*
data
)
char
*
sclp_error_message
(
u16
rc
)
{
static
struct
{
u16
code
;
char
*
msg
;
}
errors
[]
=
{
}
sclp_errors
[]
=
{
{
0x0000
,
"No response code stored (machine malfunction)"
},
{
0x0020
,
"Normal Completion"
},
{
0x0040
,
"SCLP equipment check"
},
{
0x0100
,
"SCCB boundary violation"
},
{
0x01f0
,
"invalid command"
},
{
0x0300
,
"insufficient SCCB length"
},
{
0x40f0
,
"invalid function code"
},
{
0x60f0
,
"got interrupt but no data found"
},
{
0x62f0
,
"got interrupt but no data found"
},
{
0x70f0
,
"invalid selection mask"
}
{
0x01f0
,
"Invalid command"
},
{
0x0220
,
"Normal Completion; suppressed buffers pending"
},
{
0x0300
,
"Insufficient SCCB length"
},
{
0x0340
,
"Contained SCLP equipment check"
},
{
0x05f0
,
"Target resource in improper state"
},
{
0x40f0
,
"Invalid function code/not installed"
},
{
0x60f0
,
"No buffers stored"
},
{
0x62f0
,
"No buffers stored; suppressed buffers pending"
},
{
0x70f0
,
"Invalid selection mask"
},
{
0x71f0
,
"Event buffer exceeds available space"
},
{
0x72f0
,
"Inconsistent lengths"
},
{
0x73f0
,
"Event buffer syntax error"
}
};
struct
sccb_header
*
sccb
;
char
*
errmsg
;
int
i
;
for
(
i
=
0
;
i
<
sizeof
(
sclp_errors
)
/
sizeof
(
sclp_errors
[
0
]);
i
++
)
if
(
rc
==
sclp_errors
[
i
].
code
)
return
sclp_errors
[
i
].
msg
;
return
"Invalid response code"
;
}
/*
* postprocessing of unconditional read service call
*/
static
void
sclp_unconditional_read_cb
(
struct
sclp_req
*
read_req
,
void
*
data
)
{
struct
sccb_header
*
sccb
;
sccb
=
read_req
->
sccb
;
if
(
sccb
->
response_code
==
0x0020
||
sccb
->
response_code
==
0x0220
)
{
/* normal read completion, event buffers stored in sccb */
if
(
sclp_process_evbufs
(
sccb
)
==
0
)
{
clear_bit
(
SCLP_READING
,
&
sclp_status
);
return
;
}
errmsg
=
"invalid response code"
;
}
else
{
errmsg
=
NULL
;
for
(
i
=
0
;
i
<
sizeof
(
errors
)
/
sizeof
(
errors
[
0
]);
i
++
)
if
(
sccb
->
response_code
==
errors
[
i
].
code
)
{
errmsg
=
errors
[
i
].
msg
;
break
;
}
if
(
errmsg
==
NULL
)
errmsg
=
"invalid response code"
;
if
(
sclp_process_evbufs
(
sccb
)
!=
0
)
printk
(
KERN_WARNING
SCLP_CORE_PRINT_HEADER
"unconditional read: "
"unrequested event buffer received.
\n
"
);
}
if
(
sccb
->
response_code
!=
0x0020
)
printk
(
KERN_WARNING
SCLP_CORE_PRINT_HEADER
"unconditional read: %s (response code =0x%x).
\n
"
,
errmsg
,
sccb
->
response_code
);
"unconditional read: %s (response code=0x%x).
\n
"
,
sclp_error_message
(
sccb
->
response_code
),
sccb
->
response_code
);
clear_bit
(
SCLP_READING
,
&
sclp_status
);
}
...
...
@@ -209,7 +239,7 @@ __sclp_unconditional_read(void)
struct
sclp_req
*
read_req
;
/*
* Dont try to initiate Unconditional Read if we are not able to
* Don
'
t try to initiate Unconditional Read if we are not able to
* receive anything
*/
if
(
sclp_receive_mask
==
0
)
...
...
@@ -217,13 +247,13 @@ __sclp_unconditional_read(void)
/* Don't try reading if a read is already outstanding */
if
(
test_and_set_bit
(
SCLP_READING
,
&
sclp_status
))
return
;
/* Initiali
s
e read sccb */
/* Initiali
z
e read sccb */
sccb
=
(
struct
sccb_header
*
)
sclp_read_sccb
;
clear_page
(
sccb
);
sccb
->
length
=
PAGE_SIZE
;
sccb
->
function_code
=
0
;
/* unconditional read */
sccb
->
control_mask
[
2
]
=
0x80
;
/* variable length response */
/*
stick the request structure to the end of the pag
e */
/*
Initialize request structur
e */
read_req
=
&
sclp_read_req
;
read_req
->
command
=
SCLP_CMDW_READDATA
;
read_req
->
status
=
SCLP_REQ_QUEUED
;
...
...
@@ -233,6 +263,11 @@ __sclp_unconditional_read(void)
list_add
(
&
read_req
->
list
,
&
sclp_req_queue
);
}
/* Bit masks to interpret external interruption parameter contents. */
#define EXT_INT_SCCB_MASK 0xfffffff8
#define EXT_INT_STATECHANGE_PENDING 0x00000002
#define EXT_INT_EVBUF_PENDING 0x00000001
/*
* Handler for service-signal external interruptions
*/
...
...
@@ -242,15 +277,14 @@ sclp_interrupt_handler(struct pt_regs *regs, __u16 code)
u32
ext_int_param
,
finished_sccb
,
evbuf_pending
;
struct
list_head
*
l
;
struct
sclp_req
*
req
,
*
tmp
;
int
cpu
;
cpu
=
smp_processor_id
();
ext_int_param
=
S390_lowcore
.
ext_params
;
finished_sccb
=
ext_int_param
&
-
8U
;
evbuf_pending
=
ext_int_param
&
1
;
finished_sccb
=
ext_int_param
&
EXT_INT_SCCB_MASK
;
evbuf_pending
=
ext_int_param
&
(
EXT_INT_EVBUF_PENDING
|
EXT_INT_STATECHANGE_PENDING
);
irq_enter
();
/*
* Only do request call
sbacks if sclp is initialis
ed.
* Only do request call
backs if sclp is initializ
ed.
* This avoids strange effects for a pending request
* from before the last re-ipl.
*/
...
...
@@ -326,8 +360,8 @@ sclp_sync_wait(void)
}
/*
* Queue a
request to the tail of the ccw_queue. Start the I/O if
*
possible
.
* Queue a
n SCLP request. Request will immediately be processed if queue is
*
empty
.
*/
void
sclp_add_request
(
struct
sclp_req
*
req
)
...
...
@@ -391,17 +425,17 @@ sclp_state_change(struct evbuf_header *evbuf)
scbuf
=
(
struct
sclp_statechangebuf
*
)
evbuf
;
if
(
scbuf
->
validity_sclp_receive_mask
)
{
if
(
scbuf
->
mask_length
!=
4
)
if
(
scbuf
->
mask_length
!=
sizeof
(
sccb_mask_t
)
)
printk
(
KERN_WARNING
SCLP_CORE_PRINT_HEADER
"state change event with mask length %i
\n
"
,
scbuf
->
mask_length
);
else
/* set new
send
mask */
/* set new
receive
mask */
sclp_receive_mask
=
scbuf
->
sclp_receive_mask
;
}
if
(
scbuf
->
validity_sclp_send_mask
)
{
if
(
scbuf
->
mask_length
!=
4
)
if
(
scbuf
->
mask_length
!=
sizeof
(
sccb_mask_t
)
)
printk
(
KERN_WARNING
SCLP_CORE_PRINT_HEADER
"state change event with mask length %i
\n
"
,
scbuf
->
mask_length
);
...
...
@@ -496,6 +530,8 @@ struct init_sccb {
sccb_mask_t
sclp_receive_mask
;
}
__attribute__
((
packed
));
static
void
sclp_init_mask_retry
(
unsigned
long
);
static
int
sclp_init_mask
(
void
)
{
...
...
@@ -557,13 +593,34 @@ sclp_init_mask(void)
spin_lock_irqsave
(
&
sclp_lock
,
flags
);
}
while
(
rc
==
-
EBUSY
);
}
if
(
sccb
->
header
.
response_code
!=
0x0020
)
{
/* WRITEMASK failed - we cannot rely on receiving a state
change event, so initially, polling is the only alternative
for us to ever become operational. */
if
(
!
timer_pending
(
&
retry_timer
)
||
!
mod_timer
(
&
retry_timer
,
jiffies
+
SCLP_INIT_POLL_INTERVAL
*
HZ
))
{
retry_timer
.
function
=
sclp_init_mask_retry
;
retry_timer
.
data
=
0
;
retry_timer
.
expires
=
jiffies
+
SCLP_INIT_POLL_INTERVAL
*
HZ
;
add_timer
(
&
retry_timer
);
}
}
else
{
sclp_receive_mask
=
sccb
->
sclp_receive_mask
;
sclp_send_mask
=
sccb
->
sclp_send_mask
;
__sclp_notify_state_change
();
}
spin_unlock_irqrestore
(
&
sclp_lock
,
flags
);
return
0
;
}
static
void
sclp_init_mask_retry
(
unsigned
long
data
)
{
sclp_init_mask
();
}
/*
* sclp setup function. Called early (no kmalloc!) from sclp_console_init().
*/
...
...
@@ -573,7 +630,7 @@ sclp_init(void)
int
rc
;
if
(
test_bit
(
SCLP_INIT
,
&
sclp_status
))
/* Already initiali
s
ed. */
/* Already initiali
z
ed. */
return
0
;
/*
...
...
@@ -600,6 +657,7 @@ sclp_init(void)
*/
ctl_set_bit
(
0
,
9
);
init_timer
(
&
retry_timer
);
/* do the initial write event mask */
rc
=
sclp_init_mask
();
if
(
rc
==
0
)
{
...
...
@@ -616,6 +674,15 @@ sclp_init(void)
return
rc
;
}
/*
* Register the SCLP event listener identified by REG. Return 0 on success.
* Some error codes and their meaning:
*
* -ENODEV = SCLP interface is not supported on this machine
* -EBUSY = there is already a listener registered for the requested
* event type
* -EIO = SCLP interface is currently not operational
*/
int
sclp_register
(
struct
sclp_register
*
reg
)
{
...
...
@@ -650,6 +717,9 @@ sclp_register(struct sclp_register *reg)
return
0
;
}
/*
* Unregister the SCLP event listener identified by REG.
*/
void
sclp_unregister
(
struct
sclp_register
*
reg
)
{
...
...
@@ -661,3 +731,7 @@ sclp_unregister(struct sclp_register *reg)
sclp_init_mask
();
}
EXPORT_SYMBOL
(
sclp_add_request
);
EXPORT_SYMBOL
(
sclp_sync_wait
);
EXPORT_SYMBOL
(
sclp_register
);
EXPORT_SYMBOL
(
sclp_unregister
);
drivers/s390/char/sclp.h
View file @
ba3f8ae2
...
...
@@ -45,10 +45,6 @@
#define LnTpFlgs_EndText 0x1000
#define LnTpFlgs_PromptText 0x0800
#define SCLP_COMMAND_INITIATED 0
#define SCLP_BUSY 2
#define SCLP_NOT_OPERATIONAL 3
typedef
unsigned
int
sclp_cmdw_t
;
#define SCLP_CMDW_READDATA 0x00770005
...
...
@@ -129,6 +125,7 @@ void sclp_add_request(struct sclp_req *req);
void
sclp_sync_wait
(
void
);
int
sclp_register
(
struct
sclp_register
*
reg
);
void
sclp_unregister
(
struct
sclp_register
*
reg
);
char
*
sclp_error_message
(
u16
response_code
);
/* useful inlines */
...
...
drivers/s390/char/sclp_con.c
View file @
ba3f8ae2
...
...
@@ -51,13 +51,14 @@ sclp_conbuf_callback(struct sclp_buffer *buffer, int rc)
struct
sclp_buffer
*
next
;
void
*
page
;
/* FIXME: what if rc != 0x0020 */
/* Ignore return code - because console-writes aren't critical,
we do without a sophisticated error recovery mechanism. */
page
=
sclp_unmake_buffer
(
buffer
);
spin_lock_irqsave
(
&
sclp_con_lock
,
flags
);
list_add_tail
((
struct
list_head
*
)
page
,
&
sclp_con_pages
);
sclp_con_buffer_count
--
;
/* Remove buffer from outqueue */
list_del
(
&
buffer
->
list
);
sclp_con_buffer_count
--
;
list_add_tail
((
struct
list_head
*
)
page
,
&
sclp_con_pages
);
/* Check if there is a pending buffer on the out queue. */
next
=
NULL
;
if
(
!
list_empty
(
&
sclp_con_outqueue
))
...
...
@@ -104,7 +105,7 @@ sclp_console_write(struct console *console, const char *message,
void
*
page
;
int
written
;
if
(
count
<
=
0
)
if
(
count
=
=
0
)
return
;
spin_lock_irqsave
(
&
sclp_con_lock
,
flags
);
/*
...
...
@@ -125,7 +126,8 @@ sclp_console_write(struct console *console, const char *message,
sclp_con_width_htab
);
}
/* try to write the string to the current output buffer */
written
=
sclp_write
(
sclp_conbuf
,
message
,
count
,
0
);
written
=
sclp_write
(
sclp_conbuf
,
(
const
unsigned
char
*
)
message
,
count
,
0
);
if
(
written
==
-
EFAULT
||
written
==
count
)
break
;
/*
...
...
@@ -232,6 +234,6 @@ sclp_console_init(void)
sclp_con_columns
=
80
;
sclp_con_width_htab
=
8
;
/* enable printk
s
access to this driver */
/* enable printk
-
access to this driver */
register_console
(
&
sclp_console
);
}
drivers/s390/char/sclp_cpi.c
View file @
ba3f8ae2
...
...
@@ -130,7 +130,7 @@ cpi_prepare_req(void)
req
=
(
struct
sclp_req
*
)
kmalloc
(
sizeof
(
struct
sclp_req
),
GFP_KERNEL
);
if
(
req
==
NULL
)
return
ERR_PTR
(
-
ENOMEM
);
sccb
=
(
struct
cpi_sccb
*
)
get_free_page
(
GFP_KERNEL
);
sccb
=
(
struct
cpi_sccb
*
)
__
get_free_page
(
GFP_KERNEL
);
if
(
sccb
==
NULL
)
{
kfree
(
req
);
return
ERR_PTR
(
-
ENOMEM
);
...
...
@@ -227,6 +227,7 @@ cpi_module_init(void)
rc
=
0
;
cpi_free_req
(
req
);
sclp_unregister
(
&
sclp_cpi_event
);
return
rc
;
}
...
...
drivers/s390/char/sclp_rw.c
View file @
ba3f8ae2
...
...
@@ -54,6 +54,8 @@ sclp_make_buffer(void *page, unsigned short columns, unsigned short htab)
*/
buffer
=
((
struct
sclp_buffer
*
)
((
addr_t
)
sccb
+
PAGE_SIZE
))
-
1
;
buffer
->
sccb
=
sccb
;
buffer
->
retry_count
=
0
;
init_timer
(
&
buffer
->
retry_timer
);
buffer
->
mto_number
=
0
;
buffer
->
mto_char_sum
=
0
;
buffer
->
current_line
=
NULL
;
...
...
@@ -87,14 +89,11 @@ sclp_unmake_buffer(struct sclp_buffer *buffer)
}
/*
* Creates a new Message Text Object with enough room for str_len
* characters. This function will create a new sccb for buffering
* the mto if the current buffer sccb is full. A full buffer sccb
* is submitted for output.
* Returns a pointer to the start of the string in the mto.
* Initialize a new Message Text Object (MTO) at the end of the provided buffer
* with enough room for max_len characters. Return 0 on success.
*/
static
int
sclp_
creat
e_mto
(
struct
sclp_buffer
*
buffer
,
int
max_len
)
sclp_
initializ
e_mto
(
struct
sclp_buffer
*
buffer
,
int
max_len
)
{
struct
write_sccb
*
sccb
;
struct
mto
*
mto
;
...
...
@@ -109,7 +108,7 @@ sclp_create_mto(struct sclp_buffer *buffer, int max_len)
return
-
ENOMEM
;
/* find address of new message text object */
mto
=
(
struct
mto
*
)(((
unsigned
long
)
sccb
)
+
sccb
->
header
.
length
);
mto
=
(
struct
mto
*
)(((
addr_t
)
sccb
)
+
sccb
->
header
.
length
);
/*
* fill the new Message-Text Object,
...
...
@@ -128,11 +127,11 @@ sclp_create_mto(struct sclp_buffer *buffer, int max_len)
}
/*
*
Add the mto created with sclp_create_mto to the buffer sccb using
*
the str_len parameter as the real length of the string
.
*
Finalize MTO initialized by sclp_initialize_mto(), updating the sizes of
*
MTO, enclosing MDB, event buffer and SCCB
.
*/
static
void
sclp_
add
_mto
(
struct
sclp_buffer
*
buffer
)
sclp_
finalize
_mto
(
struct
sclp_buffer
*
buffer
)
{
struct
write_sccb
*
sccb
;
struct
mto
*
mto
;
...
...
@@ -147,7 +146,7 @@ sclp_add_mto(struct sclp_buffer *buffer)
/* find address of new message text object */
sccb
=
buffer
->
sccb
;
mto
=
(
struct
mto
*
)(((
unsigned
long
)
sccb
)
+
sccb
->
header
.
length
);
mto
=
(
struct
mto
*
)(((
addr_t
)
sccb
)
+
sccb
->
header
.
length
);
/* set size of message text object */
mto
->
length
=
mto_size
;
...
...
@@ -169,23 +168,6 @@ sclp_add_mto(struct sclp_buffer *buffer)
buffer
->
mto_char_sum
+=
str_len
;
}
void
sclp_move_current_line
(
struct
sclp_buffer
*
to
,
struct
sclp_buffer
*
from
)
{
if
(
from
->
current_line
==
NULL
)
return
;
if
(
sclp_create_mto
(
to
,
from
->
columns
)
!=
0
)
return
;
if
(
from
->
current_length
>
0
)
{
memcpy
(
to
->
current_line
,
from
->
current_line
-
from
->
current_length
,
from
->
current_length
);
to
->
current_line
+=
from
->
current_length
;
to
->
current_length
=
from
->
current_length
;
}
from
->
current_line
=
NULL
;
}
/*
* processing of a message including escape characters,
* returns number of characters written to the output sccb
...
...
@@ -195,7 +177,7 @@ sclp_move_current_line(struct sclp_buffer *to, struct sclp_buffer *from)
*/
int
sclp_write
(
struct
sclp_buffer
*
buffer
,
const
char
*
msg
,
int
count
,
int
from_user
)
const
unsigned
char
*
msg
,
int
count
,
int
from_user
)
{
int
spaces
,
i_msg
;
char
ch
;
...
...
@@ -203,7 +185,7 @@ sclp_write(struct sclp_buffer *buffer,
/*
* parse msg for escape sequences (\t,\v ...) and put formated
* msg into an mto (created by sclp_
creat
e_mto).
* msg into an mto (created by sclp_
initializ
e_mto).
*
* We have to do this work ourselfs because there is no support for
* these characters on the native machine and only partial support
...
...
@@ -235,11 +217,11 @@ sclp_write(struct sclp_buffer *buffer,
case
'\n'
:
/* new line, line feed (ASCII) */
/* check if new mto needs to be created */
if
(
buffer
->
current_line
==
NULL
)
{
rc
=
sclp_
creat
e_mto
(
buffer
,
0
);
rc
=
sclp_
initializ
e_mto
(
buffer
,
0
);
if
(
rc
)
return
i_msg
;
}
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
break
;
case
'\a'
:
/* bell, one for several times */
/* set SCLP sound alarm bit in General Object */
...
...
@@ -249,7 +231,8 @@ sclp_write(struct sclp_buffer *buffer,
case
'\t'
:
/* horizontal tabulator */
/* check if new mto needs to be created */
if
(
buffer
->
current_line
==
NULL
)
{
rc
=
sclp_create_mto
(
buffer
,
buffer
->
columns
);
rc
=
sclp_initialize_mto
(
buffer
,
buffer
->
columns
);
if
(
rc
)
return
i_msg
;
}
...
...
@@ -268,8 +251,9 @@ sclp_write(struct sclp_buffer *buffer,
/* = new line, leading spaces */
if
(
buffer
->
current_line
!=
NULL
)
{
spaces
=
buffer
->
current_length
;
sclp_add_mto
(
buffer
);
rc
=
sclp_create_mto
(
buffer
,
buffer
->
columns
);
sclp_finalize_mto
(
buffer
);
rc
=
sclp_initialize_mto
(
buffer
,
buffer
->
columns
);
if
(
rc
)
return
i_msg
;
memset
(
buffer
->
current_line
,
0x40
,
spaces
);
...
...
@@ -277,10 +261,11 @@ sclp_write(struct sclp_buffer *buffer,
buffer
->
current_length
=
spaces
;
}
else
{
/* one an empty line this is the same as \n */
rc
=
sclp_create_mto
(
buffer
,
buffer
->
columns
);
rc
=
sclp_initialize_mto
(
buffer
,
buffer
->
columns
);
if
(
rc
)
return
i_msg
;
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
}
break
;
case
'\b'
:
/* backspace */
...
...
@@ -296,7 +281,7 @@ sclp_write(struct sclp_buffer *buffer,
case
0x00
:
/* end of string */
/* transfer current line to SCCB */
if
(
buffer
->
current_line
!=
NULL
)
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
/* skip the rest of the message including the 0 byte */
i_msg
=
count
;
break
;
...
...
@@ -306,7 +291,8 @@ sclp_write(struct sclp_buffer *buffer,
break
;
/* check if new mto needs to be created */
if
(
buffer
->
current_line
==
NULL
)
{
rc
=
sclp_create_mto
(
buffer
,
buffer
->
columns
);
rc
=
sclp_initialize_mto
(
buffer
,
buffer
->
columns
);
if
(
rc
)
return
i_msg
;
}
...
...
@@ -317,7 +303,7 @@ sclp_write(struct sclp_buffer *buffer,
/* check if current mto is full */
if
(
buffer
->
current_line
!=
NULL
&&
buffer
->
current_length
>=
buffer
->
columns
)
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
}
/* return number of processed characters */
...
...
@@ -361,7 +347,7 @@ sclp_set_columns(struct sclp_buffer *buffer, unsigned short columns)
buffer
->
columns
=
columns
;
if
(
buffer
->
current_line
!=
NULL
&&
buffer
->
current_length
>
buffer
->
columns
)
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
}
void
...
...
@@ -377,13 +363,62 @@ int
sclp_rw_init
(
void
)
{
static
int
init_done
=
0
;
int
rc
;
if
(
init_done
)
return
0
;
rc
=
sclp_register
(
&
sclp_rw_event
);
if
(
rc
==
0
)
init_done
=
1
;
return
sclp_register
(
&
sclp_rw_event
)
;
return
rc
;
}
#define SCLP_EVBUF_PROCESSED 0x80
/*
* Traverse array of event buffers contained in SCCB and remove all buffers
* with a set "processed" flag. Return the number of unprocessed buffers.
*/
static
int
sclp_remove_processed
(
struct
sccb_header
*
sccb
)
{
struct
evbuf_header
*
evbuf
;
int
unprocessed
;
u16
remaining
;
evbuf
=
(
struct
evbuf_header
*
)
(
sccb
+
1
);
unprocessed
=
0
;
remaining
=
sccb
->
length
-
sizeof
(
struct
sccb_header
);
while
(
remaining
>
0
)
{
remaining
-=
evbuf
->
length
;
if
(
evbuf
->
flags
&
SCLP_EVBUF_PROCESSED
)
{
sccb
->
length
-=
evbuf
->
length
;
memcpy
((
void
*
)
evbuf
,
(
void
*
)
((
addr_t
)
evbuf
+
evbuf
->
length
),
remaining
);
}
else
{
unprocessed
++
;
evbuf
=
(
struct
evbuf_header
*
)
((
addr_t
)
evbuf
+
evbuf
->
length
);
}
}
return
unprocessed
;
}
static
void
sclp_buffer_retry
(
unsigned
long
data
)
{
struct
sclp_buffer
*
buffer
=
(
struct
sclp_buffer
*
)
data
;
buffer
->
request
.
status
=
SCLP_REQ_FILLED
;
buffer
->
sccb
->
header
.
response_code
=
0x0000
;
sclp_add_request
(
&
buffer
->
request
);
}
#define SCLP_BUFFER_MAX_RETRY 5
#define SCLP_BUFFER_RETRY_INTERVAL 2
/*
* second half of Write Event Data-function that has to be done after
* interruption indicating completion of Service Call.
...
...
@@ -391,32 +426,68 @@ sclp_rw_init(void)
static
void
sclp_writedata_callback
(
struct
sclp_req
*
request
,
void
*
data
)
{
int
rc
;
struct
sclp_buffer
*
buffer
;
struct
write_sccb
*
sccb
;
buffer
=
(
struct
sclp_buffer
*
)
data
;
sccb
=
buffer
->
sccb
;
/* FIXME: proper error handling */
if
(
request
->
status
==
SCLP_REQ_FAILED
)
{
if
(
buffer
->
callback
!=
NULL
)
buffer
->
callback
(
buffer
,
-
EIO
);
return
;
}
/* check SCLP response code and choose suitable action */
switch
(
sccb
->
header
.
response_code
)
{
case
0x0020
:
/* normal completion, buffer processed, message(s) sent */
/* Normal completion, buffer processed, message(s) sent */
rc
=
0
;
break
;
case
0x0340
:
/* contained SCLP equipment check */
case
0x40F0
:
/* function code disabled in SCLP receive mask */
case
0x0340
:
/* Contained SCLP equipment check */
if
(
buffer
->
retry_count
++
>
SCLP_BUFFER_MAX_RETRY
)
{
rc
=
-
EIO
;
break
;
}
/* remove processed buffers and requeue rest */
if
(
sclp_remove_processed
((
struct
sccb_header
*
)
sccb
)
>
0
)
{
/* not all buffers were processed */
sccb
->
header
.
response_code
=
0x0000
;
buffer
->
request
.
status
=
SCLP_REQ_FILLED
;
sclp_add_request
(
request
);
return
;
}
rc
=
0
;
break
;
case
0x0040
:
/* SCLP equipment check */
case
0x05f0
:
/* Target resource in improper state */
if
(
buffer
->
retry_count
++
>
SCLP_BUFFER_MAX_RETRY
)
{
rc
=
-
EIO
;
break
;
}
/* wait some time, then retry request */
buffer
->
retry_timer
.
function
=
sclp_buffer_retry
;
buffer
->
retry_timer
.
data
=
(
unsigned
long
)
buffer
;
buffer
->
retry_timer
.
expires
=
jiffies
+
SCLP_BUFFER_RETRY_INTERVAL
*
HZ
;
add_timer
(
&
buffer
->
retry_timer
);
return
;
default:
/* sclp_free_sccb(sccb); */
if
(
sccb
->
header
.
response_code
==
0x71f0
)
rc
=
-
ENOMEM
;
else
rc
=
-
EINVAL
;
printk
(
KERN_WARNING
SCLP_RW_PRINT_HEADER
"
write event data failed "
"(response code: 0x%x SCCB address %p).
\n
"
,
sccb
->
header
.
response_code
,
sccb
);
"
sclp_writedata_callback: %s (response code=0x%x).
\n
"
,
sclp_error_message
(
sccb
->
header
.
response_code
)
,
sccb
->
header
.
response_code
);
break
;
}
if
(
buffer
->
callback
!=
NULL
)
buffer
->
callback
(
buffer
,
sccb
->
header
.
response_code
);
buffer
->
callback
(
buffer
,
rc
);
}
/*
...
...
@@ -431,10 +502,10 @@ sclp_emit_buffer(struct sclp_buffer *buffer,
/* add current line if there is one */
if
(
buffer
->
current_line
!=
NULL
)
sclp_
add
_mto
(
buffer
);
sclp_
finalize
_mto
(
buffer
);
/* Are there messages in the output buffer ? */
if
(
buffer
->
mto_number
<
=
0
)
if
(
buffer
->
mto_number
=
=
0
)
return
;
sccb
=
buffer
->
sccb
;
...
...
drivers/s390/char/sclp_rw.h
View file @
ba3f8ae2
...
...
@@ -11,6 +11,9 @@
#ifndef __SCLP_RW_H__
#define __SCLP_RW_H__
#include <linux/list.h>
#include <linux/timer.h>
struct
mto
{
u16
length
;
u16
type
;
...
...
@@ -70,6 +73,8 @@ struct sclp_buffer {
struct
write_sccb
*
sccb
;
char
*
current_line
;
int
current_length
;
int
retry_count
;
struct
timer_list
retry_timer
;
/* output format settings */
unsigned
short
columns
;
unsigned
short
htab
;
...
...
@@ -84,8 +89,7 @@ int sclp_rw_init(void);
struct
sclp_buffer
*
sclp_make_buffer
(
void
*
,
unsigned
short
,
unsigned
short
);
void
*
sclp_unmake_buffer
(
struct
sclp_buffer
*
);
int
sclp_buffer_space
(
struct
sclp_buffer
*
);
int
sclp_write
(
struct
sclp_buffer
*
buffer
,
const
char
*
,
int
,
int
);
void
sclp_move_current_line
(
struct
sclp_buffer
*
,
struct
sclp_buffer
*
);
int
sclp_write
(
struct
sclp_buffer
*
buffer
,
const
unsigned
char
*
,
int
,
int
);
void
sclp_emit_buffer
(
struct
sclp_buffer
*
,
void
(
*
)(
struct
sclp_buffer
*
,
int
));
void
sclp_set_columns
(
struct
sclp_buffer
*
,
unsigned
short
);
void
sclp_set_htab
(
struct
sclp_buffer
*
,
unsigned
short
);
...
...
drivers/s390/char/sclp_tty.c
View file @
ba3f8ae2
...
...
@@ -32,7 +32,7 @@
#define SCLP_TTY_BUF_SIZE 512
/*
* There is ex
ca
tly one SCLP terminal, so we can keep things simple
* There is ex
ac
tly one SCLP terminal, so we can keep things simple
* and allocate all variables statically.
*/
...
...
@@ -265,13 +265,14 @@ sclp_ttybuf_callback(struct sclp_buffer *buffer, int rc)
struct
sclp_buffer
*
next
;
void
*
page
;
/* FIXME: what if rc != 0x0020 */
/* Ignore return code - because tty-writes aren't critical,
we do without a sophisticated error recovery mechanism. */
page
=
sclp_unmake_buffer
(
buffer
);
spin_lock_irqsave
(
&
sclp_tty_lock
,
flags
);
list_add_tail
((
struct
list_head
*
)
page
,
&
sclp_tty_pages
);
sclp_tty_buffer_count
--
;
/* Remove buffer from outqueue */
list_del
(
&
buffer
->
list
);
sclp_tty_buffer_count
--
;
list_add_tail
((
struct
list_head
*
)
page
,
&
sclp_tty_pages
);
/* Check if there is a pending buffer on the out queue. */
next
=
NULL
;
if
(
!
list_empty
(
&
sclp_tty_outqueue
))
...
...
@@ -489,8 +490,8 @@ void sclp_tty_input(unsigned char* buf, unsigned int count)
/* send (normal) input to line discipline */
memcpy
(
sclp_tty
->
flip
.
char_buf_ptr
,
buf
,
count
);
if
(
count
<
2
||
strncmp
(
buf
+
count
-
2
,
"^n"
,
2
)
||
strncmp
(
buf
+
count
-
2
,
"
\025
2n"
,
2
))
{
strncmp
(
(
const
char
*
)
buf
+
count
-
2
,
"^n"
,
2
)
||
strncmp
(
(
const
char
*
)
buf
+
count
-
2
,
"
\025
2n"
,
2
))
{
sclp_tty
->
flip
.
char_buf_ptr
[
count
]
=
'\n'
;
count
++
;
}
else
...
...
@@ -558,7 +559,7 @@ sclp_switch_cases(unsigned char *buf, int count,
}
static
void
sclp_get_input
(
char
*
start
,
char
*
end
)
sclp_get_input
(
unsigned
char
*
start
,
unsigned
char
*
end
)
{
int
count
;
...
...
@@ -572,7 +573,7 @@ sclp_get_input(char *start, char *end)
/*
* if set in ioctl find out characters in lower or upper case
* (depends on current case) sep
e
rated by a special character,
* (depends on current case) sep
a
rated by a special character,
* works on EBCDIC
*/
if
(
sclp_ioctls
.
delim
)
...
...
@@ -625,8 +626,8 @@ sclp_eval_selfdeftextmsg(struct gds_subvector *start,
subvec
=
find_gds_subvector
(
subvec
,
end
,
0x30
);
if
(
!
subvec
)
break
;
sclp_get_input
((
void
*
)(
subvec
+
1
),
(
void
*
)
subvec
+
subvec
->
length
);
sclp_get_input
((
unsigned
char
*
)(
subvec
+
1
),
(
unsigned
char
*
)
subvec
+
subvec
->
length
);
(
void
*
)
subvec
+=
subvec
->
length
;
}
}
...
...
drivers/s390/char/sclp_tty.h
View file @
ba3f8ae2
...
...
@@ -18,9 +18,9 @@ struct sclp_ioctls {
unsigned
short
htab
;
unsigned
char
echo
;
unsigned
short
columns
;
signed
char
final_nl
;
un
signed
char
final_nl
;
unsigned
short
max_sccb
;
unsigned
short
kmem_sccb
;
/* cant be modified at run time */
unsigned
short
kmem_sccb
;
/* can
'
t be modified at run time */
unsigned
char
tolower
;
unsigned
char
delim
;
};
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment