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