1 /* 2 * drivers/s390/char/monwriter.c 3 * 4 * Character device driver for writing z/VM *MONITOR service records. 5 * 6 * Copyright (C) IBM Corp. 2006 7 * 8 * Author(s): Melissa Howland <Melissa.Howland@us.ibm.com> 9 */ 10 11 #define KMSG_COMPONENT "monwriter" 12 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 14 #include <linux/module.h> 15 #include <linux/moduleparam.h> 16 #include <linux/init.h> 17 #include <linux/errno.h> 18 #include <linux/smp_lock.h> 19 #include <linux/types.h> 20 #include <linux/kernel.h> 21 #include <linux/miscdevice.h> 22 #include <linux/ctype.h> 23 #include <linux/poll.h> 24 #include <linux/mutex.h> 25 #include <asm/uaccess.h> 26 #include <asm/ebcdic.h> 27 #include <asm/io.h> 28 #include <asm/appldata.h> 29 #include <asm/monwriter.h> 30 31 #define MONWRITE_MAX_DATALEN 4010 32 33 static int mon_max_bufs = 255; 34 static int mon_buf_count; 35 36 struct mon_buf { 37 struct list_head list; 38 struct monwrite_hdr hdr; 39 int diag_done; 40 char *data; 41 }; 42 43 struct mon_private { 44 struct list_head list; 45 struct monwrite_hdr hdr; 46 size_t hdr_to_read; 47 size_t data_to_read; 48 struct mon_buf *current_buf; 49 struct mutex thread_mutex; 50 }; 51 52 /* 53 * helper functions 54 */ 55 56 static int monwrite_diag(struct monwrite_hdr *myhdr, char *buffer, int fcn) 57 { 58 struct appldata_product_id id; 59 int rc; 60 61 strcpy(id.prod_nr, "LNXAPPL"); 62 id.prod_fn = myhdr->applid; 63 id.record_nr = myhdr->record_num; 64 id.version_nr = myhdr->version; 65 id.release_nr = myhdr->release; 66 id.mod_lvl = myhdr->mod_level; 67 rc = appldata_asm(&id, fcn, (void *) buffer, myhdr->datalen); 68 if (rc <= 0) 69 return rc; 70 pr_err("Writing monitor data failed with rc=%i\n", rc); 71 if (rc == 5) 72 return -EPERM; 73 return -EINVAL; 74 } 75 76 static struct mon_buf *monwrite_find_hdr(struct mon_private *monpriv, 77 struct monwrite_hdr *monhdr) 78 { 79 struct mon_buf *entry, *next; 80 81 list_for_each_entry_safe(entry, next, &monpriv->list, list) 82 if ((entry->hdr.mon_function == monhdr->mon_function || 83 monhdr->mon_function == MONWRITE_STOP_INTERVAL) && 84 entry->hdr.applid == monhdr->applid && 85 entry->hdr.record_num == monhdr->record_num && 86 entry->hdr.version == monhdr->version && 87 entry->hdr.release == monhdr->release && 88 entry->hdr.mod_level == monhdr->mod_level) 89 return entry; 90 91 return NULL; 92 } 93 94 static int monwrite_new_hdr(struct mon_private *monpriv) 95 { 96 struct monwrite_hdr *monhdr = &monpriv->hdr; 97 struct mon_buf *monbuf; 98 int rc; 99 100 if (monhdr->datalen > MONWRITE_MAX_DATALEN || 101 monhdr->mon_function > MONWRITE_START_CONFIG || 102 monhdr->hdrlen != sizeof(struct monwrite_hdr)) 103 return -EINVAL; 104 monbuf = NULL; 105 if (monhdr->mon_function != MONWRITE_GEN_EVENT) 106 monbuf = monwrite_find_hdr(monpriv, monhdr); 107 if (monbuf) { 108 if (monhdr->mon_function == MONWRITE_STOP_INTERVAL) { 109 monhdr->datalen = monbuf->hdr.datalen; 110 rc = monwrite_diag(monhdr, monbuf->data, 111 APPLDATA_STOP_REC); 112 list_del(&monbuf->list); 113 mon_buf_count--; 114 kfree(monbuf->data); 115 kfree(monbuf); 116 monbuf = NULL; 117 } 118 } else if (monhdr->mon_function != MONWRITE_STOP_INTERVAL) { 119 if (mon_buf_count >= mon_max_bufs) 120 return -ENOSPC; 121 monbuf = kzalloc(sizeof(struct mon_buf), GFP_KERNEL); 122 if (!monbuf) 123 return -ENOMEM; 124 monbuf->data = kzalloc(monhdr->datalen, 125 GFP_KERNEL | GFP_DMA); 126 if (!monbuf->data) { 127 kfree(monbuf); 128 return -ENOMEM; 129 } 130 monbuf->hdr = *monhdr; 131 list_add_tail(&monbuf->list, &monpriv->list); 132 if (monhdr->mon_function != MONWRITE_GEN_EVENT) 133 mon_buf_count++; 134 } 135 monpriv->current_buf = monbuf; 136 return 0; 137 } 138 139 static int monwrite_new_data(struct mon_private *monpriv) 140 { 141 struct monwrite_hdr *monhdr = &monpriv->hdr; 142 struct mon_buf *monbuf = monpriv->current_buf; 143 int rc = 0; 144 145 switch (monhdr->mon_function) { 146 case MONWRITE_START_INTERVAL: 147 if (!monbuf->diag_done) { 148 rc = monwrite_diag(monhdr, monbuf->data, 149 APPLDATA_START_INTERVAL_REC); 150 monbuf->diag_done = 1; 151 } 152 break; 153 case MONWRITE_START_CONFIG: 154 if (!monbuf->diag_done) { 155 rc = monwrite_diag(monhdr, monbuf->data, 156 APPLDATA_START_CONFIG_REC); 157 monbuf->diag_done = 1; 158 } 159 break; 160 case MONWRITE_GEN_EVENT: 161 rc = monwrite_diag(monhdr, monbuf->data, 162 APPLDATA_GEN_EVENT_REC); 163 list_del(&monpriv->current_buf->list); 164 kfree(monpriv->current_buf->data); 165 kfree(monpriv->current_buf); 166 monpriv->current_buf = NULL; 167 break; 168 default: 169 /* monhdr->mon_function is checked in monwrite_new_hdr */ 170 BUG(); 171 } 172 return rc; 173 } 174 175 /* 176 * file operations 177 */ 178 179 static int monwrite_open(struct inode *inode, struct file *filp) 180 { 181 struct mon_private *monpriv; 182 183 monpriv = kzalloc(sizeof(struct mon_private), GFP_KERNEL); 184 if (!monpriv) 185 return -ENOMEM; 186 lock_kernel(); 187 INIT_LIST_HEAD(&monpriv->list); 188 monpriv->hdr_to_read = sizeof(monpriv->hdr); 189 mutex_init(&monpriv->thread_mutex); 190 filp->private_data = monpriv; 191 unlock_kernel(); 192 return nonseekable_open(inode, filp); 193 } 194 195 static int monwrite_close(struct inode *inode, struct file *filp) 196 { 197 struct mon_private *monpriv = filp->private_data; 198 struct mon_buf *entry, *next; 199 200 list_for_each_entry_safe(entry, next, &monpriv->list, list) { 201 if (entry->hdr.mon_function != MONWRITE_GEN_EVENT) 202 monwrite_diag(&entry->hdr, entry->data, 203 APPLDATA_STOP_REC); 204 mon_buf_count--; 205 list_del(&entry->list); 206 kfree(entry->data); 207 kfree(entry); 208 } 209 kfree(monpriv); 210 return 0; 211 } 212 213 static ssize_t monwrite_write(struct file *filp, const char __user *data, 214 size_t count, loff_t *ppos) 215 { 216 struct mon_private *monpriv = filp->private_data; 217 size_t len, written; 218 void *to; 219 int rc; 220 221 mutex_lock(&monpriv->thread_mutex); 222 for (written = 0; written < count; ) { 223 if (monpriv->hdr_to_read) { 224 len = min(count - written, monpriv->hdr_to_read); 225 to = (char *) &monpriv->hdr + 226 sizeof(monpriv->hdr) - monpriv->hdr_to_read; 227 if (copy_from_user(to, data + written, len)) { 228 rc = -EFAULT; 229 goto out_error; 230 } 231 monpriv->hdr_to_read -= len; 232 written += len; 233 if (monpriv->hdr_to_read > 0) 234 continue; 235 rc = monwrite_new_hdr(monpriv); 236 if (rc) 237 goto out_error; 238 monpriv->data_to_read = monpriv->current_buf ? 239 monpriv->current_buf->hdr.datalen : 0; 240 } 241 242 if (monpriv->data_to_read) { 243 len = min(count - written, monpriv->data_to_read); 244 to = monpriv->current_buf->data + 245 monpriv->hdr.datalen - monpriv->data_to_read; 246 if (copy_from_user(to, data + written, len)) { 247 rc = -EFAULT; 248 goto out_error; 249 } 250 monpriv->data_to_read -= len; 251 written += len; 252 if (monpriv->data_to_read > 0) 253 continue; 254 rc = monwrite_new_data(monpriv); 255 if (rc) 256 goto out_error; 257 } 258 monpriv->hdr_to_read = sizeof(monpriv->hdr); 259 } 260 mutex_unlock(&monpriv->thread_mutex); 261 return written; 262 263 out_error: 264 monpriv->data_to_read = 0; 265 monpriv->hdr_to_read = sizeof(struct monwrite_hdr); 266 mutex_unlock(&monpriv->thread_mutex); 267 return rc; 268 } 269 270 static const struct file_operations monwrite_fops = { 271 .owner = THIS_MODULE, 272 .open = &monwrite_open, 273 .release = &monwrite_close, 274 .write = &monwrite_write, 275 }; 276 277 static struct miscdevice mon_dev = { 278 .name = "monwriter", 279 .fops = &monwrite_fops, 280 .minor = MISC_DYNAMIC_MINOR, 281 }; 282 283 /* 284 * module init/exit 285 */ 286 287 static int __init mon_init(void) 288 { 289 if (MACHINE_IS_VM) 290 return misc_register(&mon_dev); 291 else 292 return -ENODEV; 293 } 294 295 static void __exit mon_exit(void) 296 { 297 WARN_ON(misc_deregister(&mon_dev) != 0); 298 } 299 300 module_init(mon_init); 301 module_exit(mon_exit); 302 303 module_param_named(max_bufs, mon_max_bufs, int, 0644); 304 MODULE_PARM_DESC(max_bufs, "Maximum number of sample monitor data buffers " 305 "that can be active at one time"); 306 307 MODULE_AUTHOR("Melissa Howland <Melissa.Howland@us.ibm.com>"); 308 MODULE_DESCRIPTION("Character device driver for writing z/VM " 309 "APPLDATA monitor records."); 310 MODULE_LICENSE("GPL"); 311