diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2017-01-24 15:58:52 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2017-02-08 14:13:19 +0100 |
commit | d5ab7a34f9bbad54f89b812e6b0d2d898f9433db (patch) | |
tree | 3aa685926bc40dc71fb3482b7766705ca451fa3a | |
parent | 76fdf1416eed264dee18aa7db3a32dcfa8572e03 (diff) |
s390/sclp: make early sclp code readable
This patch
- unifies the old sclp early code and the sclp early printk code, so
they can use common functions
- makes sure all sclp early functions and variables have the same
"sclp_early" prefix
- converts the sclp early printk code into readable code by using
existing data structures instead of hard coded magic arrays
- splits the early sclp code into two files: sclp_early.c and
sclp_early_core.c. The core file contains everything that is
required by the kernel decompressor and may not call functions not
contained within the core file. Otherwise the result would be a
link error.
- changes interrupt handling to be completely synchronous. The old
early sclp code had a small window which allowed to receive several
interrupts instead of exactly the single expected interrupt. This
did hide a subtle potential bug, which is fixed with this large
rework.
- contains a couple of small cleanups.
Reviewed-by: Peter Oberparleiter <oberpar@linux.vnet.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/boot/compressed/misc.c | 2 | ||||
-rw-r--r-- | arch/s390/include/asm/sclp.h | 13 | ||||
-rw-r--r-- | arch/s390/kernel/als.c | 10 | ||||
-rw-r--r-- | arch/s390/kernel/early_printk.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/swsusp.S | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 25 | ||||
-rw-r--r-- | drivers/s390/char/sclp.h | 34 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early.c | 178 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early_core.c | 271 |
10 files changed, 244 insertions, 295 deletions
diff --git a/arch/s390/boot/compressed/misc.c b/arch/s390/boot/compressed/misc.c index 8515dd5a5663..fa95041fa9f6 100644 --- a/arch/s390/boot/compressed/misc.c +++ b/arch/s390/boot/compressed/misc.c @@ -66,7 +66,7 @@ static unsigned long free_mem_end_ptr; static int puts(const char *s) { - _sclp_print_early(s); + sclp_early_printk(s); return 0; } diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 415eaace3f1b..ace3bd315438 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h @@ -101,7 +101,12 @@ struct zpci_report_error_header { u8 data[0]; /* Subsequent Data passed verbatim to SCLP ET 24 */ } __packed; -int _sclp_get_core_info_early(struct sclp_core_info *info); +int sclp_early_get_core_info(struct sclp_core_info *info); +void sclp_early_get_ipl_info(struct sclp_ipl_info *info); +void sclp_early_detect(void); +void sclp_early_printk(const char *s); +void __sclp_early_printk(const char *s, unsigned int len); + int _sclp_get_core_info(struct sclp_core_info *info); int sclp_core_configure(u8 core); int sclp_core_deconfigure(u8 core); @@ -110,21 +115,17 @@ int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); int sclp_chp_configure(struct chp_id chpid); int sclp_chp_deconfigure(struct chp_id chpid); int sclp_chp_read_info(struct sclp_chp_info *info); -void sclp_get_ipl_info(struct sclp_ipl_info *info); int sclp_pci_configure(u32 fid); int sclp_pci_deconfigure(u32 fid); int sclp_pci_report(struct zpci_report_error_header *report, u32 fh, u32 fid); int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count); int memcpy_hsa_user(void __user *dest, unsigned long src, size_t count); -void sclp_early_detect(void); -void _sclp_print_early(const char *); -void __sclp_print_early(const char *s, unsigned int len); void sclp_ocf_cpc_name_copy(char *dst); static inline int sclp_get_core_info(struct sclp_core_info *info, int early) { if (early) - return _sclp_get_core_info_early(info); + return sclp_early_get_core_info(info); return _sclp_get_core_info(info); } diff --git a/arch/s390/kernel/als.c b/arch/s390/kernel/als.c index a16e9d1bf9e3..0b3a06f05f90 100644 --- a/arch/s390/kernel/als.c +++ b/arch/s390/kernel/als.c @@ -41,7 +41,7 @@ static void __init print_machine_type(void) get_cpu_id(&id); u16_to_hex(type_str, id.machine); strcat(mach_str, type_str); - _sclp_print_early(mach_str); + sclp_early_printk(mach_str); } static void __init u16_to_decimal(char *str, u16 val) @@ -79,7 +79,7 @@ static void __init print_missing_facilities(void) * z/VM adds a four character prefix. */ if (strlen(als_str) > 70) { - _sclp_print_early(als_str); + sclp_early_printk(als_str); *als_str = '\0'; } u16_to_decimal(val_str, i * BITS_PER_LONG + j); @@ -87,13 +87,13 @@ static void __init print_missing_facilities(void) first = 0; } } - _sclp_print_early(als_str); - _sclp_print_early("See Principles of Operations for facility bits"); + sclp_early_printk(als_str); + sclp_early_printk("See Principles of Operations for facility bits"); } static void __init facility_mismatch(void) { - _sclp_print_early("The Linux kernel requires more recent processor hardware"); + sclp_early_printk("The Linux kernel requires more recent processor hardware"); print_machine_type(); print_missing_facilities(); disabled_wait(0x8badcccc); diff --git a/arch/s390/kernel/early_printk.c b/arch/s390/kernel/early_printk.c index 54a4dc582b81..819cb15c67e8 100644 --- a/arch/s390/kernel/early_printk.c +++ b/arch/s390/kernel/early_printk.c @@ -9,7 +9,7 @@ static void sclp_early_write(struct console *con, const char *s, unsigned int len) { - __sclp_print_early(s, len); + __sclp_early_printk(s, len); } static struct console sclp_early_console = { diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 2c6ddced5394..5b91308f6117 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c @@ -1864,7 +1864,7 @@ static int __init s390_ipl_init(void) { char str[8] = {0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40}; - sclp_get_ipl_info(&sclp_ipl_info); + sclp_early_get_ipl_info(&sclp_ipl_info); /* * Fix loadparm: There are systems where the (SCSI) LOADPARM * returned by read SCP info is invalid (contains EBCDIC blanks) diff --git a/arch/s390/kernel/swsusp.S b/arch/s390/kernel/swsusp.S index 1ff21f05d7dd..6c56fb89f553 100644 --- a/arch/s390/kernel/swsusp.S +++ b/arch/s390/kernel/swsusp.S @@ -196,7 +196,7 @@ pgm_check_entry: larl %r15,init_thread_union ahi %r15,1<<(PAGE_SHIFT+THREAD_SIZE_ORDER) larl %r2,.Lpanic_string - larl %r3,_sclp_print_early + larl %r3,sclp_early_printk lghi %r1,0 sam31 sigp %r1,%r0,SIGP_SET_ARCHITECTURE diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c index befc07acd3e0..9c471ea1b99c 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -140,31 +140,6 @@ static void __sclp_make_read_req(void); static int sclp_init_mask(int calculate); static int sclp_init(void); -/* Perform service call. Return 0 on success, non-zero otherwise. */ -int -sclp_service_call(sclp_cmdw_t command, void *sccb) -{ - int cc = 4; /* Initialize for program check handling */ - - asm volatile( - "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ - "1: ipm %0\n" - " srl %0,28\n" - "2:\n" - EX_TABLE(0b, 2b) - EX_TABLE(1b, 2b) - : "+&d" (cc) : "d" (command), "a" (__pa(sccb)) - : "cc", "memory"); - if (cc == 4) - return -EINVAL; - if (cc == 3) - return -EIO; - if (cc == 2) - return -EBUSY; - return 0; -} - - static void __sclp_queue_read_req(void) { diff --git a/drivers/s390/char/sclp.h b/drivers/s390/char/sclp.h index 0c1fa376df9e..78d5f542d979 100644 --- a/drivers/s390/char/sclp.h +++ b/drivers/s390/char/sclp.h @@ -204,7 +204,6 @@ void sclp_unregister(struct sclp_register *reg); int sclp_remove_processed(struct sccb_header *sccb); int sclp_deactivate(void); int sclp_reactivate(void); -int sclp_service_call(sclp_cmdw_t command, void *sccb); int sclp_sync_request(sclp_cmdw_t command, void *sccb); int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout); @@ -222,8 +221,41 @@ extern int sclp_console_pages; extern int sclp_console_drop; extern unsigned long sclp_console_full; +extern char sclp_early_sccb[PAGE_SIZE]; + +void sclp_early_wait_irq(void); +int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb); +int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb); +unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb); +int sclp_early_set_event_mask(struct init_sccb *sccb, + unsigned long receive_mask, + unsigned long send_mask); + /* useful inlines */ +/* Perform service call. Return 0 on success, non-zero otherwise. */ +static inline int sclp_service_call(sclp_cmdw_t command, void *sccb) +{ + int cc = 4; /* Initialize for program check handling */ + + asm volatile( + "0: .insn rre,0xb2200000,%1,%2\n" /* servc %1,%2 */ + "1: ipm %0\n" + " srl %0,28\n" + "2:\n" + EX_TABLE(0b, 2b) + EX_TABLE(1b, 2b) + : "+&d" (cc) : "d" (command), "a" ((unsigned long)sccb) + : "cc", "memory"); + if (cc == 4) + return -EINVAL; + if (cc == 3) + return -EIO; + if (cc == 2) + return -EBUSY; + return 0; +} + /* VM uses EBCDIC 037, LPAR+native(SE+HMC) use EBCDIC 500 */ /* translate single character from ASCII to EBCDIC */ static inline unsigned char diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c index f8e46c22e641..2f9e50379e64 100644 --- a/drivers/s390/char/sclp_early.c +++ b/drivers/s390/char/sclp_early.c @@ -55,31 +55,12 @@ struct read_info_sccb { u8 _pad_128[4096 - 128]; /* 128-4095 */ } __packed __aligned(PAGE_SIZE); -static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata; static struct sclp_ipl_info sclp_ipl_info; struct sclp_info sclp; EXPORT_SYMBOL(sclp); -static int __init sclp_cmd_sync_early(sclp_cmdw_t cmd, void *sccb) -{ - int rc; - - __ctl_set_bit(0, 9); - rc = sclp_service_call(cmd, sccb); - if (rc) - goto out; - __load_psw_mask(PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_EA | - PSW_MASK_BA | PSW_MASK_EXT | PSW_MASK_WAIT); - local_irq_disable(); -out: - /* Contents of the sccb might have changed. */ - barrier(); - __ctl_clear_bit(0, 9); - return rc; -} - -static int __init sclp_read_info_early(struct read_info_sccb *sccb) +static int __init sclp_early_read_info(struct read_info_sccb *sccb) { int rc, i; sclp_cmdw_t commands[] = {SCLP_CMDW_READ_SCP_INFO_FORCED, @@ -91,7 +72,7 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) sccb->header.length = sizeof(*sccb); sccb->header.function_code = 0x80; sccb->header.control_mask[2] = 0x80; - rc = sclp_cmd_sync_early(commands[i], sccb); + rc = sclp_early_cmd_sync(commands[i], sccb); } while (rc == -EBUSY); if (rc) @@ -104,12 +85,12 @@ static int __init sclp_read_info_early(struct read_info_sccb *sccb) return -EIO; } -static void __init sclp_facilities_detect(struct read_info_sccb *sccb) +static void __init sclp_early_facilities_detect(struct read_info_sccb *sccb) { struct sclp_core_entry *cpue; u16 boot_cpu_address, cpu; - if (sclp_read_info_early(sccb)) + if (sclp_early_read_info(sccb)) return; sclp.facilities = sccb->facilities; @@ -172,59 +153,19 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb) } /* - * This function will be called after sclp_facilities_detect(), which gets - * called from early.c code. The sclp_facilities_detect() function retrieves + * This function will be called after sclp_early_facilities_detect(), which gets + * called from early.c code. The sclp_early_facilities_detect() function retrieves * and saves the IPL information. */ -void __init sclp_get_ipl_info(struct sclp_ipl_info *info) +void __init sclp_early_get_ipl_info(struct sclp_ipl_info *info) { *info = sclp_ipl_info; } -static int __init sclp_cmd_early(sclp_cmdw_t cmd, void *sccb) -{ - int rc; +static struct sclp_core_info sclp_early_core_info __initdata; +static int sclp_early_core_info_valid __initdata; - do { - rc = sclp_cmd_sync_early(cmd, sccb); - } while (rc == -EBUSY); - - if (rc) - return -EIO; - if (((struct sccb_header *) sccb)->response_code != 0x0020) - return -EIO; - return 0; -} - -static void __init sccb_init_eq_size(struct sdias_sccb *sccb) -{ - memset(sccb, 0, sizeof(*sccb)); - - sccb->hdr.length = sizeof(*sccb); - sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf); - sccb->evbuf.hdr.type = EVTYP_SDIAS; - sccb->evbuf.event_qual = SDIAS_EQ_SIZE; - sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP; - sccb->evbuf.event_id = 4712; - sccb->evbuf.dbs = 1; -} - -static int __init sclp_set_event_mask(struct init_sccb *sccb, - unsigned long receive_mask, - unsigned long send_mask) -{ - memset(sccb, 0, sizeof(*sccb)); - sccb->header.length = sizeof(*sccb); - sccb->mask_length = sizeof(sccb_mask_t); - sccb->receive_mask = receive_mask; - sccb->send_mask = send_mask; - return sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_MASK, sccb); -} - -static struct sclp_core_info sclp_core_info_early __initdata; -static int sclp_core_info_early_valid __initdata; - -static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb) +static void __init sclp_early_init_core_info(struct read_cpu_info_sccb *sccb) { int rc; @@ -233,80 +174,76 @@ static void __init sclp_init_core_info_early(struct read_cpu_info_sccb *sccb) memset(sccb, 0, sizeof(*sccb)); sccb->header.length = sizeof(*sccb); do { - rc = sclp_cmd_sync_early(SCLP_CMDW_READ_CPU_INFO, sccb); + rc = sclp_early_cmd_sync(SCLP_CMDW_READ_CPU_INFO, sccb); } while (rc == -EBUSY); if (rc) return; if (sccb->header.response_code != 0x0010) return; - sclp_fill_core_info(&sclp_core_info_early, sccb); - sclp_core_info_early_valid = 1; + sclp_fill_core_info(&sclp_early_core_info, sccb); + sclp_early_core_info_valid = 1; } -int __init _sclp_get_core_info_early(struct sclp_core_info *info) +int __init sclp_early_get_core_info(struct sclp_core_info *info) { - if (!sclp_core_info_early_valid) + if (!sclp_early_core_info_valid) return -EIO; - *info = sclp_core_info_early; + *info = sclp_early_core_info; return 0; } -static long __init sclp_hsa_size_init(struct sdias_sccb *sccb) +static long __init sclp_early_hsa_size_init(struct sdias_sccb *sccb) { - sccb_init_eq_size(sccb); - if (sclp_cmd_early(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) + memset(sccb, 0, sizeof(*sccb)); + sccb->hdr.length = sizeof(*sccb); + sccb->evbuf.hdr.length = sizeof(struct sdias_evbuf); + sccb->evbuf.hdr.type = EVTYP_SDIAS; + sccb->evbuf.event_qual = SDIAS_EQ_SIZE; + sccb->evbuf.data_id = SDIAS_DI_FCP_DUMP; + sccb->evbuf.event_id = 4712; + sccb->evbuf.dbs = 1; + if (sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb)) return -EIO; if (sccb->evbuf.blk_cnt == 0) return 0; return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; } -static long __init sclp_hsa_copy_wait(struct sccb_header *sccb) +static long __init sclp_early_hsa_copy_wait(struct sdias_sccb *sccb) { memset(sccb, 0, PAGE_SIZE); - sccb->length = PAGE_SIZE; - if (sclp_cmd_early(SCLP_CMDW_READ_EVENT_DATA, sccb)) + sccb->hdr.length = PAGE_SIZE; + if (sclp_early_cmd(SCLP_CMDW_READ_EVENT_DATA, sccb)) return -EIO; - if (((struct sdias_sccb *) sccb)->evbuf.blk_cnt == 0) + if (sccb->evbuf.blk_cnt == 0) return 0; - return (((struct sdias_sccb *) sccb)->evbuf.blk_cnt - 1) * PAGE_SIZE; + return (sccb->evbuf.blk_cnt - 1) * PAGE_SIZE; } -static void __init sclp_hsa_size_detect(void *sccb) +static void __init sclp_early_hsa_size_detect(void *sccb) { - long size; + unsigned long flags; + long size = -EIO; - /* First try synchronous interface (LPAR) */ - if (sclp_set_event_mask(sccb, 0, 0x40000010)) - return; - size = sclp_hsa_size_init(sccb); - if (size < 0) - return; - if (size != 0) + raw_local_irq_save(flags); + if (sclp_early_set_event_mask(sccb, EVTYP_SDIAS_MASK, EVTYP_SDIAS_MASK)) goto out; - /* Then try asynchronous interface (z/VM) */ - if (sclp_set_event_mask(sccb, 0x00000010, 0x40000010)) - return; - size = sclp_hsa_size_init(sccb); - if (size < 0) - return; - size = sclp_hsa_copy_wait(sccb); - if (size < 0) - return; + size = sclp_early_hsa_size_init(sccb); + /* First check for synchronous response (LPAR) */ + if (size) + goto out_mask; + if (!(S390_lowcore.ext_params & 1)) + sclp_early_wait_irq(); + size = sclp_early_hsa_copy_wait(sccb); +out_mask: + sclp_early_set_event_mask(sccb, 0, 0); out: - sclp.hsa_size = size; -} - -static unsigned int __init sclp_con_check_linemode(struct init_sccb *sccb) -{ - if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) - return 0; - if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) - return 0; - return 1; + raw_local_irq_restore(flags); + if (size > 0) + sclp.hsa_size = size; } -static void __init sclp_console_detect(struct init_sccb *sccb) +static void __init sclp_early_console_detect(struct init_sccb *sccb) { if (sccb->header.response_code != 0x20) return; @@ -314,21 +251,22 @@ static void __init sclp_console_detect(struct init_sccb *sccb) if (sccb->sclp_send_mask & EVTYP_VT220MSG_MASK) sclp.has_vt220 = 1; - if (sclp_con_check_linemode(sccb)) + if (sclp_early_con_check_linemode(sccb)) sclp.has_linemode = 1; } void __init sclp_early_detect(void) { - void *sccb = &sccb_early; + void *sccb = &sclp_early_sccb; - sclp_facilities_detect(sccb); - sclp_init_core_info_early(sccb); - sclp_hsa_size_detect(sccb); + sclp_early_facilities_detect(sccb); + sclp_early_init_core_info(sccb); + sclp_early_hsa_size_detect(sccb); - /* Turn off SCLP event notifications. Also save remote masks in the + /* + * Turn off SCLP event notifications. Also save remote masks in the * sccb. These are sufficient to detect sclp console capabilities. */ - sclp_set_event_mask(sccb, 0, 0); - sclp_console_detect(sccb); + sclp_early_set_event_mask(sccb, 0, 0); + sclp_early_console_detect(sccb); } diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index 2723ab56fb8f..97f4c84d6635 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c @@ -2,29 +2,24 @@ * Copyright IBM Corp. 2015 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> */ + #include <linux/kernel.h> +#include <asm/processor.h> +#include <asm/lowcore.h> #include <asm/ebcdic.h> #include <asm/irq.h> -#include <asm/lowcore.h> -#include <asm/processor.h> -#include <asm/sclp.h> - -#define EVTYP_VT220MSG_MASK 0x00000040 -#define EVTYP_MSG_MASK 0x40000000 - -static char _sclp_work_area[4096] __aligned(PAGE_SIZE) __section(data); -static bool have_vt220 __section(data); -static bool have_linemode __section(data); +#include "sclp.h" +#include "sclp_rw.h" +char sclp_early_sccb[PAGE_SIZE] __aligned(PAGE_SIZE) __section(data); int sclp_init_state __section(data) = sclp_init_state_uninitialized; -static void _sclp_wait_int(void) +void sclp_early_wait_irq(void) { - unsigned long psw_mask, addr, flags; + unsigned long psw_mask, addr; psw_t psw_ext_save, psw_wait; union ctlreg0 cr0, cr0_new; - raw_local_irq_save(flags); __ctl_store(cr0.val, 0, 0); cr0_new.val = cr0.val & ~CR0_IRQ_SUBCLASS_MASK; cr0_new.lap = 0; @@ -53,165 +48,173 @@ static void _sclp_wait_int(void) S390_lowcore.external_new_psw = psw_ext_save; __ctl_load(cr0.val, 0, 0); - raw_local_irq_restore(flags); } -static int _sclp_servc(unsigned int cmd, char *sccb) +int sclp_early_cmd_sync(sclp_cmdw_t cmd, void *sccb) { - unsigned int cc; + unsigned long flags; + int rc; - do { - asm volatile( - " .insn rre,0xb2200000,%1,%2\n" - " ipm %0\n" - : "=d" (cc) : "d" (cmd), "a" (sccb) - : "cc", "memory"); - cc >>= 28; - if (cc == 3) - return -EINVAL; - _sclp_wait_int(); - } while (cc != 0); - return (*(unsigned short *)(sccb + 6) == 0x20) ? 0 : -EIO; + raw_local_irq_save(flags); + rc = sclp_service_call(cmd, sccb); + if (rc) + goto out; + sclp_early_wait_irq(); +out: + raw_local_irq_restore(flags); + return rc; } -static int _sclp_setup(int disable) +int sclp_early_cmd(sclp_cmdw_t cmd, void *sccb) { - static unsigned char init_sccb[] = { - 0x00, 0x1c, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x04, - 0x80, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 - }; - unsigned int *masks; int rc; - memcpy(_sclp_work_area, init_sccb, 28); - masks = (unsigned int *)(_sclp_work_area + 12); - if (disable) - memset(masks, 0, 16); - /* SCLP write mask */ - rc = _sclp_servc(0x00780005, _sclp_work_area); + do { + rc = sclp_early_cmd_sync(cmd, sccb); + } while (rc == -EBUSY); if (rc) - return rc; - have_vt220 = masks[2] & EVTYP_VT220MSG_MASK; - have_linemode = masks[2] & EVTYP_MSG_MASK; + return -EIO; + if (((struct sccb_header *) sccb)->response_code != 0x0020) + return -EIO; return 0; } +struct write_sccb { + struct sccb_header header; + struct msg_buf msg; +} __packed; + /* Output multi-line text using SCLP Message interface. */ -static void _sclp_print_lm(const char *str, unsigned int len) +static void sclp_early_print_lm(const char *str, unsigned int len) { - static unsigned char write_head[] = { - /* sccb header */ - 0x00, 0x52, /* 0 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 2 */ - /* evbuf */ - 0x00, 0x4a, /* 8 */ - 0x02, 0x00, 0x00, 0x00, /* 10 */ - /* mdb */ - 0x00, 0x44, /* 14 */ - 0x00, 0x01, /* 16 */ - 0xd4, 0xc4, 0xc2, 0x40, /* 18 */ - 0x00, 0x00, 0x00, 0x01, /* 22 */ - /* go */ - 0x00, 0x38, /* 26 */ - 0x00, 0x01, /* 28 */ - 0x00, 0x00, 0x00, 0x00, /* 30 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 34 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 42 */ - 0x00, 0x00, 0x00, 0x00, /* 50 */ - 0x00, 0x00, /* 54 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 56 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 64 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 72 */ - 0x00, 0x00, /* 80 */ - }; - static unsigned char write_mto[] = { - /* mto */ - 0x00, 0x0a, /* 0 */ - 0x00, 0x04, /* 2 */ - 0x10, 0x00, /* 4 */ - 0x00, 0x00, 0x00, 0x00 /* 6 */ - }; - unsigned char *ptr, *end_ptr, ch; - unsigned int count, num; - - num = 0; - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - ptr = _sclp_work_area + sizeof(write_head); - end_ptr = _sclp_work_area + sizeof(_sclp_work_area) - 1; + unsigned char *ptr, *end, ch; + unsigned int count, offset; + struct write_sccb *sccb; + struct msg_buf *msg; + struct mdb *mdb; + struct mto *mto; + struct go *go; + + sccb = (struct write_sccb *) &sclp_early_sccb; + end = (unsigned char *) sccb + sizeof(sclp_early_sccb) - 1; + memset(sccb, 0, sizeof(*sccb)); + ptr = (unsigned char *) &sccb->msg.mdb.mto; + offset = 0; do { - if (ptr + sizeof(write_mto) > end_ptr) - break; - memcpy(ptr, write_mto, sizeof(write_mto)); - for (count = sizeof(write_mto); num < len; count++) { - num++; - ch = *str++; - if (ch == 0x0a) - break; - if (ptr > end_ptr) + for (count = sizeof(*mto); offset < len; count++) { + ch = str[offset++]; + if ((ch == 0x0a) || (ptr + count > end)) break; ptr[count] = _ascebc[ch]; } - /* Update length fields in mto, mdb, evbuf and sccb */ - *(unsigned short *) ptr = count; - *(unsigned short *)(_sclp_work_area + 14) += count; - *(unsigned short *)(_sclp_work_area + 8) += count; - *(unsigned short *)(_sclp_work_area + 0) += count; + mto = (struct mto *) ptr; + memset(mto, 0, sizeof(*mto)); + mto->length = count; + mto->type = 4; + mto->line_type_flags = LNTPFLGS_ENDTEXT; ptr += count; - } while (num < len); - - /* SCLP write data */ - _sclp_servc(0x00760005, _sclp_work_area); + } while ((offset < len) && (ptr + sizeof(*mto) <= end)); + len = ptr - (unsigned char *) sccb; + sccb->header.length = len - offsetof(struct write_sccb, header); + msg = &sccb->msg; + msg->header.type = EVTYP_MSG; + msg->header.length = len - offsetof(struct write_sccb, msg.header); + mdb = &msg->mdb; + mdb->header.type = 1; + mdb->header.tag = 0xD4C4C240; + mdb->header.revision_code = 1; + mdb->header.length = len - offsetof(struct write_sccb, msg.mdb.header); + go = &mdb->go; + go->length = sizeof(*go); + go->type = 1; + sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); } +struct vt220_sccb { + struct sccb_header header; + struct { + struct evbuf_header header; + char data[]; + } msg; +} __packed; + /* Output multi-line text (plus a newline) using SCLP VT220 * interface. */ -static void _sclp_print_vt220(const char *str, unsigned int len) +static void sclp_early_print_vt220(const char *str, unsigned int len) +{ + struct vt220_sccb *sccb; + + sccb = (struct vt220_sccb *) &sclp_early_sccb; + if (sizeof(*sccb) + len >= sizeof(sclp_early_sccb)) + len = sizeof(sclp_early_sccb) - sizeof(*sccb) - 1; + memset(sccb, 0, sizeof(*sccb)); + memcpy(&sccb->msg.data, str, len); + sccb->msg.data[len] = '\n'; + sccb->header.length = sizeof(*sccb) + len + 1; + sccb->msg.header.length = sizeof(sccb->msg) + len + 1; + sccb->msg.header.type = EVTYP_VT220MSG; + sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_DATA, sccb); +} + +int sclp_early_set_event_mask(struct init_sccb *sccb, + unsigned long receive_mask, + unsigned long send_mask) +{ + memset(sccb, 0, sizeof(*sccb)); + sccb->header.length = sizeof(*sccb); + sccb->mask_length = sizeof(sccb_mask_t); + sccb->receive_mask = receive_mask; + sccb->send_mask = send_mask; + return sclp_early_cmd(SCLP_CMDW_WRITE_EVENT_MASK, sccb); +} + +unsigned int sclp_early_con_check_linemode(struct init_sccb *sccb) { - static unsigned char const write_head[] = { - /* sccb header */ - 0x00, 0x0e, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* evbuf header */ - 0x00, 0x06, - 0x1a, 0x00, 0x00, 0x00, - }; - - if (sizeof(write_head) + len >= sizeof(_sclp_work_area)) - len = sizeof(_sclp_work_area) - sizeof(write_head) - 1; - - memcpy(_sclp_work_area, write_head, sizeof(write_head)); - memcpy(_sclp_work_area + sizeof(write_head), str, len); - _sclp_work_area[sizeof(write_head) + len] = '\n'; - - /* Update length fields in evbuf and sccb headers */ - *(unsigned short *)(_sclp_work_area + 8) += len + 1; - *(unsigned short *)(_sclp_work_area + 0) += len + 1; - - /* SCLP write data */ - (void)_sclp_servc(0x00760005, _sclp_work_area); + if (!(sccb->sclp_send_mask & EVTYP_OPCMD_MASK)) + return 0; + if (!(sccb->sclp_receive_mask & (EVTYP_MSG_MASK | EVTYP_PMSGCMD_MASK))) + return 0; + return 1; +} + +static int sclp_early_setup(int disable, int *have_linemode, int *have_vt220) +{ + unsigned long receive_mask, send_mask; + struct init_sccb *sccb; + int rc; + + *have_linemode = *have_vt220 = 0; + sccb = (struct init_sccb *) &sclp_early_sccb; + receive_mask = disable ? 0 : EVTYP_OPCMD_MASK; + send_mask = disable ? 0 : EVTYP_VT220MSG_MASK | EVTYP_MSG_MASK; + rc = sclp_early_set_event_mask(sccb, receive_mask, send_mask); + if (rc) + return rc; + *have_linemode = sclp_early_con_check_linemode(sccb); + *have_vt220 = sccb->send_mask & EVTYP_VT220MSG_MASK; + return rc; } /* Output one or more lines of text on the SCLP console (VT220 and / * or line-mode). All lines get terminated; no need for a trailing LF. */ -void __sclp_print_early(const char *str, unsigned int len) +void __sclp_early_printk(const char *str, unsigned int len) { + int have_linemode, have_vt220; + if (sclp_init_state != sclp_init_state_uninitialized) return; - if (_sclp_setup(0) != 0) + if (sclp_early_setup(0, &have_linemode, &have_vt220) != 0) return; if (have_linemode) - _sclp_print_lm(str, len); + sclp_early_print_lm(str, len); if (have_vt220) - _sclp_print_vt220(str, len); - _sclp_setup(1); + sclp_early_print_vt220(str, len); + sclp_early_setup(1, &have_linemode, &have_vt220); } -void _sclp_print_early(const char *str) +void sclp_early_printk(const char *str) { - __sclp_print_early(str, strlen(str)); + __sclp_early_printk(str, strlen(str)); } |