Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.0-rc7 214 lines 5.2 kB view raw
1/* 2 * Enable Asynchronous Notification via SCLP. 3 * 4 * Copyright IBM Corp. 2009 5 * Author(s): Hans-Joachim Picht <hans@linux.vnet.ibm.com> 6 * 7 */ 8 9#include <linux/init.h> 10#include <linux/module.h> 11#include <linux/device.h> 12#include <linux/stat.h> 13#include <linux/string.h> 14#include <linux/slab.h> 15#include <linux/ctype.h> 16#include <linux/kmod.h> 17#include <linux/err.h> 18#include <linux/errno.h> 19#include <linux/proc_fs.h> 20#include <linux/sysctl.h> 21#include <linux/utsname.h> 22#include "sclp.h" 23 24static int callhome_enabled; 25static struct sclp_req *request; 26static struct sclp_async_sccb *sccb; 27static int sclp_async_send_wait(char *message); 28static struct ctl_table_header *callhome_sysctl_header; 29static DEFINE_SPINLOCK(sclp_async_lock); 30#define SCLP_NORMAL_WRITE 0x00 31 32struct async_evbuf { 33 struct evbuf_header header; 34 u64 reserved; 35 u8 rflags; 36 u8 empty; 37 u8 rtype; 38 u8 otype; 39 char comp_id[12]; 40 char data[3000]; /* there is still some space left */ 41} __attribute__((packed)); 42 43struct sclp_async_sccb { 44 struct sccb_header header; 45 struct async_evbuf evbuf; 46} __attribute__((packed)); 47 48static struct sclp_register sclp_async_register = { 49 .send_mask = EVTYP_ASYNC_MASK, 50}; 51 52static int call_home_on_panic(struct notifier_block *self, 53 unsigned long event, void *data) 54{ 55 strncat(data, init_utsname()->nodename, 56 sizeof(init_utsname()->nodename)); 57 sclp_async_send_wait(data); 58 return NOTIFY_DONE; 59} 60 61static struct notifier_block call_home_panic_nb = { 62 .notifier_call = call_home_on_panic, 63 .priority = INT_MAX, 64}; 65 66static int proc_handler_callhome(struct ctl_table *ctl, int write, 67 void __user *buffer, size_t *count, 68 loff_t *ppos) 69{ 70 unsigned long val; 71 int len, rc; 72 char buf[3]; 73 74 if (!*count || (*ppos && !write)) { 75 *count = 0; 76 return 0; 77 } 78 if (!write) { 79 len = snprintf(buf, sizeof(buf), "%d\n", callhome_enabled); 80 rc = copy_to_user(buffer, buf, sizeof(buf)); 81 if (rc != 0) 82 return -EFAULT; 83 } else { 84 len = *count; 85 rc = copy_from_user(buf, buffer, sizeof(buf)); 86 if (rc != 0) 87 return -EFAULT; 88 buf[sizeof(buf) - 1] = '\0'; 89 if (strict_strtoul(buf, 0, &val) != 0) 90 return -EINVAL; 91 if (val != 0 && val != 1) 92 return -EINVAL; 93 callhome_enabled = val; 94 } 95 *count = len; 96 *ppos += len; 97 return 0; 98} 99 100static struct ctl_table callhome_table[] = { 101 { 102 .procname = "callhome", 103 .mode = 0644, 104 .proc_handler = proc_handler_callhome, 105 }, 106 {} 107}; 108 109static struct ctl_table kern_dir_table[] = { 110 { 111 .procname = "kernel", 112 .maxlen = 0, 113 .mode = 0555, 114 .child = callhome_table, 115 }, 116 {} 117}; 118 119/* 120 * Function used to transfer asynchronous notification 121 * records which waits for send completion 122 */ 123static int sclp_async_send_wait(char *message) 124{ 125 struct async_evbuf *evb; 126 int rc; 127 unsigned long flags; 128 129 if (!callhome_enabled) 130 return 0; 131 sccb->evbuf.header.type = EVTYP_ASYNC; 132 sccb->evbuf.rtype = 0xA5; 133 sccb->evbuf.otype = 0x00; 134 evb = &sccb->evbuf; 135 request->command = SCLP_CMDW_WRITE_EVENT_DATA; 136 request->sccb = sccb; 137 request->status = SCLP_REQ_FILLED; 138 strncpy(sccb->evbuf.data, message, sizeof(sccb->evbuf.data)); 139 /* 140 * Retain Queue 141 * e.g. 5639CC140 500 Red Hat RHEL5 Linux for zSeries (RHEL AS) 142 */ 143 strncpy(sccb->evbuf.comp_id, "000000000", sizeof(sccb->evbuf.comp_id)); 144 sccb->evbuf.header.length = sizeof(sccb->evbuf); 145 sccb->header.length = sizeof(sccb->evbuf) + sizeof(sccb->header); 146 sccb->header.function_code = SCLP_NORMAL_WRITE; 147 rc = sclp_add_request(request); 148 if (rc) 149 return rc; 150 spin_lock_irqsave(&sclp_async_lock, flags); 151 while (request->status != SCLP_REQ_DONE && 152 request->status != SCLP_REQ_FAILED) { 153 sclp_sync_wait(); 154 } 155 spin_unlock_irqrestore(&sclp_async_lock, flags); 156 if (request->status != SCLP_REQ_DONE) 157 return -EIO; 158 rc = ((struct sclp_async_sccb *) 159 request->sccb)->header.response_code; 160 if (rc != 0x0020) 161 return -EIO; 162 if (evb->header.flags != 0x80) 163 return -EIO; 164 return rc; 165} 166 167static int __init sclp_async_init(void) 168{ 169 int rc; 170 171 rc = sclp_register(&sclp_async_register); 172 if (rc) 173 return rc; 174 rc = -EOPNOTSUPP; 175 if (!(sclp_async_register.sclp_receive_mask & EVTYP_ASYNC_MASK)) 176 goto out_sclp; 177 rc = -ENOMEM; 178 callhome_sysctl_header = register_sysctl_table(kern_dir_table); 179 if (!callhome_sysctl_header) 180 goto out_sclp; 181 request = kzalloc(sizeof(struct sclp_req), GFP_KERNEL); 182 sccb = (struct sclp_async_sccb *) get_zeroed_page(GFP_KERNEL | GFP_DMA); 183 if (!request || !sccb) 184 goto out_mem; 185 rc = atomic_notifier_chain_register(&panic_notifier_list, 186 &call_home_panic_nb); 187 if (!rc) 188 goto out; 189out_mem: 190 kfree(request); 191 free_page((unsigned long) sccb); 192 unregister_sysctl_table(callhome_sysctl_header); 193out_sclp: 194 sclp_unregister(&sclp_async_register); 195out: 196 return rc; 197} 198module_init(sclp_async_init); 199 200static void __exit sclp_async_exit(void) 201{ 202 atomic_notifier_chain_unregister(&panic_notifier_list, 203 &call_home_panic_nb); 204 unregister_sysctl_table(callhome_sysctl_header); 205 sclp_unregister(&sclp_async_register); 206 free_page((unsigned long) sccb); 207 kfree(request); 208} 209module_exit(sclp_async_exit); 210 211MODULE_AUTHOR("Copyright IBM Corp. 2009"); 212MODULE_AUTHOR("Hans-Joachim Picht <hans@linux.vnet.ibm.com>"); 213MODULE_LICENSE("GPL"); 214MODULE_DESCRIPTION("SCLP Asynchronous Notification Records");