diff options
author | Michael Ernst <mernst@de.ibm.com> | 2008-01-26 14:10:55 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-01-26 14:11:08 +0100 |
commit | c05ffc4f2b208da8ba7d3a9b5ab886c76f8939b5 (patch) | |
tree | 4cd35a23eaf7eb3b5a15f30e82a676b590622448 /drivers/s390/char/sclp_cpi.c | |
parent | dfa77f611ff295598e218aa0eb6efa73a5cf26d0 (diff) |
[S390] sclp: sysfs interface for SCLP cpi
Signed-off-by: Michael Ernst <mernst@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/char/sclp_cpi.c')
-rw-r--r-- | drivers/s390/char/sclp_cpi.c | 246 |
1 files changed, 16 insertions, 230 deletions
diff --git a/drivers/s390/char/sclp_cpi.c b/drivers/s390/char/sclp_cpi.c index 82a13d9fdfe..5716487b8c9 100644 --- a/drivers/s390/char/sclp_cpi.c +++ b/drivers/s390/char/sclp_cpi.c @@ -1,255 +1,41 @@ /* - * Author: Martin Peschke <mpeschke@de.ibm.com> - * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation + * drivers/s390/char/sclp_cpi.c + * SCLP control programm identification * - * SCLP Control-Program Identification. + * Copyright IBM Corp. 2001, 2007 + * Author(s): Martin Peschke <mpeschke@de.ibm.com> + * Michael Ernst <mernst@de.ibm.com> */ -#include <linux/version.h> #include <linux/kmod.h> #include <linux/module.h> #include <linux/moduleparam.h> -#include <linux/init.h> -#include <linux/timer.h> -#include <linux/string.h> -#include <linux/err.h> -#include <linux/slab.h> -#include <asm/ebcdic.h> -#include <asm/semaphore.h> - -#include "sclp.h" -#include "sclp_rw.h" - -#define CPI_LENGTH_SYSTEM_TYPE 8 -#define CPI_LENGTH_SYSTEM_NAME 8 -#define CPI_LENGTH_SYSPLEX_NAME 8 - -struct cpi_evbuf { - struct evbuf_header header; - u8 id_format; - u8 reserved0; - u8 system_type[CPI_LENGTH_SYSTEM_TYPE]; - u64 reserved1; - u8 system_name[CPI_LENGTH_SYSTEM_NAME]; - u64 reserved2; - u64 system_level; - u64 reserved3; - u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME]; - u8 reserved4[16]; -} __attribute__((packed)); - -struct cpi_sccb { - struct sccb_header header; - struct cpi_evbuf cpi_evbuf; -} __attribute__((packed)); - -/* Event type structure for write message and write priority message */ -static struct sclp_register sclp_cpi_event = -{ - .send_mask = EVTYP_CTLPROGIDENT_MASK -}; +#include <linux/version.h> +#include "sclp_cpi_sys.h" MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Identify this operating system instance " + "to the System z hardware"); +MODULE_AUTHOR("Martin Peschke <mpeschke@de.ibm.com>, " + "Michael Ernst <mernst@de.ibm.com>"); -MODULE_AUTHOR( - "Martin Peschke, IBM Deutschland Entwicklung GmbH " - "<mpeschke@de.ibm.com>"); - -MODULE_DESCRIPTION( - "identify this operating system instance to the S/390 " - "or zSeries hardware"); +static char *system_name = ""; +static char *sysplex_name = ""; -static char *system_name = NULL; module_param(system_name, charp, 0); MODULE_PARM_DESC(system_name, "e.g. hostname - max. 8 characters"); - -static char *sysplex_name = NULL; -#ifdef ALLOW_SYSPLEX_NAME module_param(sysplex_name, charp, 0); MODULE_PARM_DESC(sysplex_name, "if applicable - max. 8 characters"); -#endif - -/* use default value for this field (as well as for system level) */ -static char *system_type = "LINUX"; -static int -cpi_check_parms(void) +static int __init cpi_module_init(void) { - /* reject if no system type specified */ - if (!system_type) { - printk("cpi: bug: no system type specified\n"); - return -EINVAL; - } - - /* reject if system type larger than 8 characters */ - if (strlen(system_type) > CPI_LENGTH_SYSTEM_NAME) { - printk("cpi: bug: system type has length of %li characters - " - "only %i characters supported\n", - strlen(system_type), CPI_LENGTH_SYSTEM_TYPE); - return -EINVAL; - } - - /* reject if no system name specified */ - if (!system_name) { - printk("cpi: no system name specified\n"); - return -EINVAL; - } - - /* reject if system name larger than 8 characters */ - if (strlen(system_name) > CPI_LENGTH_SYSTEM_NAME) { - printk("cpi: system name has length of %li characters - " - "only %i characters supported\n", - strlen(system_name), CPI_LENGTH_SYSTEM_NAME); - return -EINVAL; - } - - /* reject if specified sysplex name larger than 8 characters */ - if (sysplex_name && strlen(sysplex_name) > CPI_LENGTH_SYSPLEX_NAME) { - printk("cpi: sysplex name has length of %li characters" - " - only %i characters supported\n", - strlen(sysplex_name), CPI_LENGTH_SYSPLEX_NAME); - return -EINVAL; - } - return 0; + return sclp_cpi_set_data(system_name, sysplex_name, "LINUX", + LINUX_VERSION_CODE); } -static void -cpi_callback(struct sclp_req *req, void *data) -{ - struct semaphore *sem; - - sem = (struct semaphore *) data; - up(sem); -} - -static struct sclp_req * -cpi_prepare_req(void) -{ - struct sclp_req *req; - struct cpi_sccb *sccb; - struct cpi_evbuf *evb; - - req = kmalloc(sizeof(struct sclp_req), GFP_KERNEL); - if (req == NULL) - return ERR_PTR(-ENOMEM); - sccb = (struct cpi_sccb *) __get_free_page(GFP_KERNEL | GFP_DMA); - if (sccb == NULL) { - kfree(req); - return ERR_PTR(-ENOMEM); - } - memset(sccb, 0, sizeof(struct cpi_sccb)); - - /* setup SCCB for Control-Program Identification */ - sccb->header.length = sizeof(struct cpi_sccb); - sccb->cpi_evbuf.header.length = sizeof(struct cpi_evbuf); - sccb->cpi_evbuf.header.type = 0x0B; - evb = &sccb->cpi_evbuf; - - /* set system type */ - memset(evb->system_type, ' ', CPI_LENGTH_SYSTEM_TYPE); - memcpy(evb->system_type, system_type, strlen(system_type)); - sclp_ascebc_str(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); - EBC_TOUPPER(evb->system_type, CPI_LENGTH_SYSTEM_TYPE); - - /* set system name */ - memset(evb->system_name, ' ', CPI_LENGTH_SYSTEM_NAME); - memcpy(evb->system_name, system_name, strlen(system_name)); - sclp_ascebc_str(evb->system_name, CPI_LENGTH_SYSTEM_NAME); - EBC_TOUPPER(evb->system_name, CPI_LENGTH_SYSTEM_NAME); - - /* set system level */ - evb->system_level = LINUX_VERSION_CODE; - - /* set sysplex name */ - if (sysplex_name) { - memset(evb->sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME); - memcpy(evb->sysplex_name, sysplex_name, strlen(sysplex_name)); - sclp_ascebc_str(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); - EBC_TOUPPER(evb->sysplex_name, CPI_LENGTH_SYSPLEX_NAME); - } - - /* prepare request data structure presented to SCLP driver */ - req->command = SCLP_CMDW_WRITE_EVENT_DATA; - req->sccb = sccb; - req->status = SCLP_REQ_FILLED; - req->callback = cpi_callback; - return req; -} - -static void -cpi_free_req(struct sclp_req *req) -{ - free_page((unsigned long) req->sccb); - kfree(req); -} - -static int __init -cpi_module_init(void) -{ - struct semaphore sem; - struct sclp_req *req; - int rc; - - rc = cpi_check_parms(); - if (rc) - return rc; - - rc = sclp_register(&sclp_cpi_event); - if (rc) { - /* could not register sclp event. Die. */ - printk(KERN_WARNING "cpi: could not register to hardware " - "console.\n"); - return -EINVAL; - } - if (!(sclp_cpi_event.sclp_send_mask & EVTYP_CTLPROGIDENT_MASK)) { - printk(KERN_WARNING "cpi: no control program identification " - "support\n"); - sclp_unregister(&sclp_cpi_event); - return -EOPNOTSUPP; - } - - req = cpi_prepare_req(); - if (IS_ERR(req)) { - printk(KERN_WARNING "cpi: couldn't allocate request\n"); - sclp_unregister(&sclp_cpi_event); - return PTR_ERR(req); - } - - /* Prepare semaphore */ - sema_init(&sem, 0); - req->callback_data = &sem; - /* Add request to sclp queue */ - rc = sclp_add_request(req); - if (rc) { - printk(KERN_WARNING "cpi: could not start request\n"); - cpi_free_req(req); - sclp_unregister(&sclp_cpi_event); - return rc; - } - /* make "insmod" sleep until callback arrives */ - down(&sem); - - rc = ((struct cpi_sccb *) req->sccb)->header.response_code; - if (rc != 0x0020) { - printk(KERN_WARNING "cpi: failed with response code 0x%x\n", - rc); - rc = -ECOMM; - } else - rc = 0; - - cpi_free_req(req); - sclp_unregister(&sclp_cpi_event); - - return rc; -} - - static void __exit cpi_module_exit(void) { } - -/* declare driver module init/cleanup functions */ module_init(cpi_module_init); module_exit(cpi_module_exit); - |