719 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Character device driver for extended error reporting.4 *5 * Copyright IBM Corp. 20056 * extended error reporting for DASD ECKD devices7 * Author(s): Stefan Weinhuber <wein@de.ibm.com>8 */9 10#include <linux/init.h>11#include <linux/fs.h>12#include <linux/kernel.h>13#include <linux/miscdevice.h>14#include <linux/module.h>15#include <linux/moduleparam.h>16#include <linux/device.h>17#include <linux/poll.h>18#include <linux/mutex.h>19#include <linux/err.h>20#include <linux/slab.h>21 22#include <linux/uaccess.h>23#include <linux/atomic.h>24#include <asm/ebcdic.h>25 26#include "dasd_int.h"27#include "dasd_eckd.h"28 29/*30 * SECTION: the internal buffer31 */32 33/*34 * The internal buffer is meant to store obaque blobs of data, so it does35 * not know of higher level concepts like triggers.36 * It consists of a number of pages that are used as a ringbuffer. Each data37 * blob is stored in a simple record that consists of an integer, which38 * contains the size of the following data, and the data bytes themselfes.39 *40 * To allow for multiple independent readers we create one internal buffer41 * each time the device is opened and destroy the buffer when the file is42 * closed again. The number of pages used for this buffer is determined by43 * the module parmeter eer_pages.44 *45 * One record can be written to a buffer by using the functions46 * - dasd_eer_start_record (one time per record to write the size to the47 * buffer and reserve the space for the data)48 * - dasd_eer_write_buffer (one or more times per record to write the data)49 * The data can be written in several steps but you will have to compute50 * the total size up front for the invocation of dasd_eer_start_record.51 * If the ringbuffer is full, dasd_eer_start_record will remove the required52 * number of old records.53 *54 * A record is typically read in two steps, first read the integer that55 * specifies the size of the following data, then read the data.56 * Both can be done by57 * - dasd_eer_read_buffer58 *59 * For all mentioned functions you need to get the bufferlock first and keep60 * it until a complete record is written or read.61 *62 * All information necessary to keep track of an internal buffer is kept in63 * a struct eerbuffer. The buffer specific to a file pointer is strored in64 * the private_data field of that file. To be able to write data to all65 * existing buffers, each buffer is also added to the bufferlist.66 * If the user does not want to read a complete record in one go, we have to67 * keep track of the rest of the record. residual stores the number of bytes68 * that are still to deliver. If the rest of the record is invalidated between69 * two reads then residual will be set to -1 so that the next read will fail.70 * All entries in the eerbuffer structure are protected with the bufferlock.71 * To avoid races between writing to a buffer on the one side and creating72 * and destroying buffers on the other side, the bufferlock must also be used73 * to protect the bufferlist.74 */75 76static int eer_pages = 5;77module_param(eer_pages, int, S_IRUGO|S_IWUSR);78 79struct eerbuffer {80 struct list_head list;81 char **buffer;82 int buffersize;83 int buffer_page_count;84 int head;85 int tail;86 int residual;87};88 89static LIST_HEAD(bufferlist);90static DEFINE_SPINLOCK(bufferlock);91static DECLARE_WAIT_QUEUE_HEAD(dasd_eer_read_wait_queue);92 93/*94 * How many free bytes are available on the buffer.95 * Needs to be called with bufferlock held.96 */97static int dasd_eer_get_free_bytes(struct eerbuffer *eerb)98{99 if (eerb->head < eerb->tail)100 return eerb->tail - eerb->head - 1;101 return eerb->buffersize - eerb->head + eerb->tail -1;102}103 104/*105 * How many bytes of buffer space are used.106 * Needs to be called with bufferlock held.107 */108static int dasd_eer_get_filled_bytes(struct eerbuffer *eerb)109{110 111 if (eerb->head >= eerb->tail)112 return eerb->head - eerb->tail;113 return eerb->buffersize - eerb->tail + eerb->head;114}115 116/*117 * The dasd_eer_write_buffer function just copies count bytes of data118 * to the buffer. Make sure to call dasd_eer_start_record first, to119 * make sure that enough free space is available.120 * Needs to be called with bufferlock held.121 */122static void dasd_eer_write_buffer(struct eerbuffer *eerb,123 char *data, int count)124{125 126 unsigned long headindex,localhead;127 unsigned long rest, len;128 char *nextdata;129 130 nextdata = data;131 rest = count;132 while (rest > 0) {133 headindex = eerb->head / PAGE_SIZE;134 localhead = eerb->head % PAGE_SIZE;135 len = min(rest, PAGE_SIZE - localhead);136 memcpy(eerb->buffer[headindex]+localhead, nextdata, len);137 nextdata += len;138 rest -= len;139 eerb->head += len;140 if (eerb->head == eerb->buffersize)141 eerb->head = 0; /* wrap around */142 BUG_ON(eerb->head > eerb->buffersize);143 }144}145 146/*147 * Needs to be called with bufferlock held.148 */149static int dasd_eer_read_buffer(struct eerbuffer *eerb, char *data, int count)150{151 152 unsigned long tailindex,localtail;153 unsigned long rest, len, finalcount;154 char *nextdata;155 156 finalcount = min(count, dasd_eer_get_filled_bytes(eerb));157 nextdata = data;158 rest = finalcount;159 while (rest > 0) {160 tailindex = eerb->tail / PAGE_SIZE;161 localtail = eerb->tail % PAGE_SIZE;162 len = min(rest, PAGE_SIZE - localtail);163 memcpy(nextdata, eerb->buffer[tailindex] + localtail, len);164 nextdata += len;165 rest -= len;166 eerb->tail += len;167 if (eerb->tail == eerb->buffersize)168 eerb->tail = 0; /* wrap around */169 BUG_ON(eerb->tail > eerb->buffersize);170 }171 return finalcount;172}173 174/*175 * Whenever you want to write a blob of data to the internal buffer you176 * have to start by using this function first. It will write the number177 * of bytes that will be written to the buffer. If necessary it will remove178 * old records to make room for the new one.179 * Needs to be called with bufferlock held.180 */181static int dasd_eer_start_record(struct eerbuffer *eerb, int count)182{183 int tailcount;184 185 if (count + sizeof(count) > eerb->buffersize)186 return -ENOMEM;187 while (dasd_eer_get_free_bytes(eerb) < count + sizeof(count)) {188 if (eerb->residual > 0) {189 eerb->tail += eerb->residual;190 if (eerb->tail >= eerb->buffersize)191 eerb->tail -= eerb->buffersize;192 eerb->residual = -1;193 }194 dasd_eer_read_buffer(eerb, (char *) &tailcount,195 sizeof(tailcount));196 eerb->tail += tailcount;197 if (eerb->tail >= eerb->buffersize)198 eerb->tail -= eerb->buffersize;199 }200 dasd_eer_write_buffer(eerb, (char*) &count, sizeof(count));201 202 return 0;203};204 205/*206 * Release pages that are not used anymore.207 */208static void dasd_eer_free_buffer_pages(char **buf, int no_pages)209{210 int i;211 212 for (i = 0; i < no_pages; i++)213 free_page((unsigned long) buf[i]);214}215 216/*217 * Allocate a new set of memory pages.218 */219static int dasd_eer_allocate_buffer_pages(char **buf, int no_pages)220{221 int i;222 223 for (i = 0; i < no_pages; i++) {224 buf[i] = (char *) get_zeroed_page(GFP_KERNEL);225 if (!buf[i]) {226 dasd_eer_free_buffer_pages(buf, i);227 return -ENOMEM;228 }229 }230 return 0;231}232 233/*234 * SECTION: The extended error reporting functionality235 */236 237/*238 * When a DASD device driver wants to report an error, it calls the239 * function dasd_eer_write and gives the respective trigger ID as240 * parameter. Currently there are four kinds of triggers:241 *242 * DASD_EER_FATALERROR: all kinds of unrecoverable I/O problems243 * DASD_EER_PPRCSUSPEND: PPRC was suspended244 * DASD_EER_NOPATH: There is no path to the device left.245 * DASD_EER_STATECHANGE: The state of the device has changed.246 *247 * For the first three triggers all required information can be supplied by248 * the caller. For these triggers a record is written by the function249 * dasd_eer_write_standard_trigger.250 *251 * The DASD_EER_STATECHANGE trigger is special since a sense subsystem252 * status ccw need to be executed to gather the necessary sense data first.253 * The dasd_eer_snss function will queue the SNSS request and the request254 * callback will then call dasd_eer_write with the DASD_EER_STATCHANGE255 * trigger.256 *257 * To avoid memory allocations at runtime, the necessary memory is allocated258 * when the extended error reporting is enabled for a device (by259 * dasd_eer_probe). There is one sense subsystem status request for each260 * eer enabled DASD device. The presence of the cqr in device->eer_cqr261 * indicates that eer is enable for the device. The use of the snss request262 * is protected by the DASD_FLAG_EER_IN_USE bit. When this flag indicates263 * that the cqr is currently in use, dasd_eer_snss cannot start a second264 * request but sets the DASD_FLAG_EER_SNSS flag instead. The callback of265 * the SNSS request will check the bit and call dasd_eer_snss again.266 */267 268#define SNSS_DATA_SIZE 44269 270#define DASD_EER_BUSID_SIZE 10271struct dasd_eer_header {272 __u32 total_size;273 __u32 trigger;274 __u64 tv_sec;275 __u64 tv_usec;276 char busid[DASD_EER_BUSID_SIZE];277} __attribute__ ((packed));278 279/*280 * The following function can be used for those triggers that have281 * all necessary data available when the function is called.282 * If the parameter cqr is not NULL, the chain of requests will be searched283 * for valid sense data, and all valid sense data sets will be added to284 * the triggers data.285 */286static void dasd_eer_write_standard_trigger(struct dasd_device *device,287 struct dasd_ccw_req *cqr,288 int trigger)289{290 struct dasd_ccw_req *temp_cqr;291 int data_size;292 struct timespec64 ts;293 struct dasd_eer_header header;294 unsigned long flags;295 struct eerbuffer *eerb;296 char *sense;297 298 /* go through cqr chain and count the valid sense data sets */299 data_size = 0;300 for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers)301 if (dasd_get_sense(&temp_cqr->irb))302 data_size += 32;303 304 header.total_size = sizeof(header) + data_size + 4; /* "EOR" */305 header.trigger = trigger;306 ktime_get_real_ts64(&ts);307 header.tv_sec = ts.tv_sec;308 header.tv_usec = ts.tv_nsec / NSEC_PER_USEC;309 strscpy(header.busid, dev_name(&device->cdev->dev),310 DASD_EER_BUSID_SIZE);311 312 spin_lock_irqsave(&bufferlock, flags);313 list_for_each_entry(eerb, &bufferlist, list) {314 dasd_eer_start_record(eerb, header.total_size);315 dasd_eer_write_buffer(eerb, (char *) &header, sizeof(header));316 for (temp_cqr = cqr; temp_cqr; temp_cqr = temp_cqr->refers) {317 sense = dasd_get_sense(&temp_cqr->irb);318 if (sense)319 dasd_eer_write_buffer(eerb, sense, 32);320 }321 dasd_eer_write_buffer(eerb, "EOR", 4);322 }323 spin_unlock_irqrestore(&bufferlock, flags);324 wake_up_interruptible(&dasd_eer_read_wait_queue);325}326 327/*328 * This function writes a DASD_EER_STATECHANGE trigger.329 */330static void dasd_eer_write_snss_trigger(struct dasd_device *device,331 struct dasd_ccw_req *cqr,332 int trigger)333{334 int data_size;335 int snss_rc;336 struct timespec64 ts;337 struct dasd_eer_header header;338 unsigned long flags;339 struct eerbuffer *eerb;340 341 snss_rc = (cqr->status == DASD_CQR_DONE) ? 0 : -EIO;342 if (snss_rc)343 data_size = 0;344 else345 data_size = SNSS_DATA_SIZE;346 347 header.total_size = sizeof(header) + data_size + 4; /* "EOR" */348 header.trigger = DASD_EER_STATECHANGE;349 ktime_get_real_ts64(&ts);350 header.tv_sec = ts.tv_sec;351 header.tv_usec = ts.tv_nsec / NSEC_PER_USEC;352 strscpy(header.busid, dev_name(&device->cdev->dev),353 DASD_EER_BUSID_SIZE);354 355 spin_lock_irqsave(&bufferlock, flags);356 list_for_each_entry(eerb, &bufferlist, list) {357 dasd_eer_start_record(eerb, header.total_size);358 dasd_eer_write_buffer(eerb, (char *) &header , sizeof(header));359 if (!snss_rc)360 dasd_eer_write_buffer(eerb, cqr->data, SNSS_DATA_SIZE);361 dasd_eer_write_buffer(eerb, "EOR", 4);362 }363 spin_unlock_irqrestore(&bufferlock, flags);364 wake_up_interruptible(&dasd_eer_read_wait_queue);365}366 367/*368 * This function is called for all triggers. It calls the appropriate369 * function that writes the actual trigger records.370 */371void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr,372 unsigned int id)373{374 if (!device->eer_cqr)375 return;376 switch (id) {377 case DASD_EER_FATALERROR:378 case DASD_EER_PPRCSUSPEND:379 dasd_eer_write_standard_trigger(device, cqr, id);380 break;381 case DASD_EER_NOPATH:382 case DASD_EER_NOSPC:383 case DASD_EER_AUTOQUIESCE:384 dasd_eer_write_standard_trigger(device, NULL, id);385 break;386 case DASD_EER_STATECHANGE:387 dasd_eer_write_snss_trigger(device, cqr, id);388 break;389 default: /* unknown trigger, so we write it without any sense data */390 dasd_eer_write_standard_trigger(device, NULL, id);391 break;392 }393}394EXPORT_SYMBOL(dasd_eer_write);395 396/*397 * Start a sense subsystem status request.398 * Needs to be called with the device held.399 */400void dasd_eer_snss(struct dasd_device *device)401{402 struct dasd_ccw_req *cqr;403 404 cqr = device->eer_cqr;405 if (!cqr) /* Device not eer enabled. */406 return;407 if (test_and_set_bit(DASD_FLAG_EER_IN_USE, &device->flags)) {408 /* Sense subsystem status request in use. */409 set_bit(DASD_FLAG_EER_SNSS, &device->flags);410 return;411 }412 /* cdev is already locked, can't use dasd_add_request_head */413 clear_bit(DASD_FLAG_EER_SNSS, &device->flags);414 cqr->status = DASD_CQR_QUEUED;415 list_add(&cqr->devlist, &device->ccw_queue);416 dasd_schedule_device_bh(device);417}418 419/*420 * Callback function for use with sense subsystem status request.421 */422static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data)423{424 struct dasd_device *device = cqr->startdev;425 unsigned long flags;426 427 dasd_eer_write(device, cqr, DASD_EER_STATECHANGE);428 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);429 if (device->eer_cqr == cqr) {430 clear_bit(DASD_FLAG_EER_IN_USE, &device->flags);431 if (test_bit(DASD_FLAG_EER_SNSS, &device->flags))432 /* Another SNSS has been requested in the meantime. */433 dasd_eer_snss(device);434 cqr = NULL;435 }436 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);437 if (cqr)438 /*439 * Extended error recovery has been switched off while440 * the SNSS request was running. It could even have441 * been switched off and on again in which case there442 * is a new ccw in device->eer_cqr. Free the "old"443 * snss request now.444 */445 dasd_sfree_request(cqr, device);446}447 448/*449 * Enable error reporting on a given device.450 */451int dasd_eer_enable(struct dasd_device *device)452{453 struct dasd_ccw_req *cqr = NULL;454 unsigned long flags;455 struct ccw1 *ccw;456 int rc = 0;457 458 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);459 if (device->eer_cqr)460 goto out;461 else if (!device->discipline ||462 strcmp(device->discipline->name, "ECKD"))463 rc = -EMEDIUMTYPE;464 else if (test_bit(DASD_FLAG_OFFLINE, &device->flags))465 rc = -EBUSY;466 467 if (rc)468 goto out;469 470 cqr = dasd_smalloc_request(DASD_ECKD_MAGIC, 1 /* SNSS */,471 SNSS_DATA_SIZE, device, NULL);472 if (IS_ERR(cqr)) {473 rc = -ENOMEM;474 cqr = NULL;475 goto out;476 }477 478 cqr->startdev = device;479 cqr->retries = 255;480 cqr->expires = 10 * HZ;481 clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags);482 set_bit(DASD_CQR_ALLOW_SLOCK, &cqr->flags);483 484 ccw = cqr->cpaddr;485 ccw->cmd_code = DASD_ECKD_CCW_SNSS;486 ccw->count = SNSS_DATA_SIZE;487 ccw->flags = 0;488 ccw->cda = virt_to_dma32(cqr->data);489 490 cqr->buildclk = get_tod_clock();491 cqr->status = DASD_CQR_FILLED;492 cqr->callback = dasd_eer_snss_cb;493 494 if (!device->eer_cqr) {495 device->eer_cqr = cqr;496 cqr = NULL;497 }498 499out:500 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);501 502 if (cqr)503 dasd_sfree_request(cqr, device);504 505 return rc;506}507 508/*509 * Disable error reporting on a given device.510 */511void dasd_eer_disable(struct dasd_device *device)512{513 struct dasd_ccw_req *cqr;514 unsigned long flags;515 int in_use;516 517 if (!device->eer_cqr)518 return;519 spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);520 cqr = device->eer_cqr;521 device->eer_cqr = NULL;522 clear_bit(DASD_FLAG_EER_SNSS, &device->flags);523 in_use = test_and_clear_bit(DASD_FLAG_EER_IN_USE, &device->flags);524 spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);525 if (cqr && !in_use)526 dasd_sfree_request(cqr, device);527}528 529/*530 * SECTION: the device operations531 */532 533/*534 * On the one side we need a lock to access our internal buffer, on the535 * other side a copy_to_user can sleep. So we need to copy the data we have536 * to transfer in a readbuffer, which is protected by the readbuffer_mutex.537 */538static char readbuffer[PAGE_SIZE];539static DEFINE_MUTEX(readbuffer_mutex);540 541static int dasd_eer_open(struct inode *inp, struct file *filp)542{543 struct eerbuffer *eerb;544 unsigned long flags;545 546 eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL);547 if (!eerb)548 return -ENOMEM;549 eerb->buffer_page_count = eer_pages;550 if (eerb->buffer_page_count < 1 ||551 eerb->buffer_page_count > INT_MAX / PAGE_SIZE) {552 kfree(eerb);553 DBF_EVENT(DBF_WARNING, "can't open device since module "554 "parameter eer_pages is smaller than 1 or"555 " bigger than %d", (int)(INT_MAX / PAGE_SIZE));556 return -EINVAL;557 }558 eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE;559 eerb->buffer = kmalloc_array(eerb->buffer_page_count, sizeof(char *),560 GFP_KERNEL);561 if (!eerb->buffer) {562 kfree(eerb);563 return -ENOMEM;564 }565 if (dasd_eer_allocate_buffer_pages(eerb->buffer,566 eerb->buffer_page_count)) {567 kfree(eerb->buffer);568 kfree(eerb);569 return -ENOMEM;570 }571 filp->private_data = eerb;572 spin_lock_irqsave(&bufferlock, flags);573 list_add(&eerb->list, &bufferlist);574 spin_unlock_irqrestore(&bufferlock, flags);575 576 return nonseekable_open(inp,filp);577}578 579static int dasd_eer_close(struct inode *inp, struct file *filp)580{581 struct eerbuffer *eerb;582 unsigned long flags;583 584 eerb = (struct eerbuffer *) filp->private_data;585 spin_lock_irqsave(&bufferlock, flags);586 list_del(&eerb->list);587 spin_unlock_irqrestore(&bufferlock, flags);588 dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count);589 kfree(eerb->buffer);590 kfree(eerb);591 592 return 0;593}594 595static ssize_t dasd_eer_read(struct file *filp, char __user *buf,596 size_t count, loff_t *ppos)597{598 int tc,rc;599 int tailcount,effective_count;600 unsigned long flags;601 struct eerbuffer *eerb;602 603 eerb = (struct eerbuffer *) filp->private_data;604 if (mutex_lock_interruptible(&readbuffer_mutex))605 return -ERESTARTSYS;606 607 spin_lock_irqsave(&bufferlock, flags);608 609 if (eerb->residual < 0) { /* the remainder of this record */610 /* has been deleted */611 eerb->residual = 0;612 spin_unlock_irqrestore(&bufferlock, flags);613 mutex_unlock(&readbuffer_mutex);614 return -EIO;615 } else if (eerb->residual > 0) {616 /* OK we still have a second half of a record to deliver */617 effective_count = min(eerb->residual, (int) count);618 eerb->residual -= effective_count;619 } else {620 tc = 0;621 while (!tc) {622 tc = dasd_eer_read_buffer(eerb, (char *) &tailcount,623 sizeof(tailcount));624 if (!tc) {625 /* no data available */626 spin_unlock_irqrestore(&bufferlock, flags);627 mutex_unlock(&readbuffer_mutex);628 if (filp->f_flags & O_NONBLOCK)629 return -EAGAIN;630 rc = wait_event_interruptible(631 dasd_eer_read_wait_queue,632 eerb->head != eerb->tail);633 if (rc)634 return rc;635 if (mutex_lock_interruptible(&readbuffer_mutex))636 return -ERESTARTSYS;637 spin_lock_irqsave(&bufferlock, flags);638 }639 }640 WARN_ON(tc != sizeof(tailcount));641 effective_count = min(tailcount,(int)count);642 eerb->residual = tailcount - effective_count;643 }644 645 tc = dasd_eer_read_buffer(eerb, readbuffer, effective_count);646 WARN_ON(tc != effective_count);647 648 spin_unlock_irqrestore(&bufferlock, flags);649 650 if (copy_to_user(buf, readbuffer, effective_count)) {651 mutex_unlock(&readbuffer_mutex);652 return -EFAULT;653 }654 655 mutex_unlock(&readbuffer_mutex);656 return effective_count;657}658 659static __poll_t dasd_eer_poll(struct file *filp, poll_table *ptable)660{661 __poll_t mask;662 unsigned long flags;663 struct eerbuffer *eerb;664 665 eerb = (struct eerbuffer *) filp->private_data;666 poll_wait(filp, &dasd_eer_read_wait_queue, ptable);667 spin_lock_irqsave(&bufferlock, flags);668 if (eerb->head != eerb->tail)669 mask = EPOLLIN | EPOLLRDNORM ;670 else671 mask = 0;672 spin_unlock_irqrestore(&bufferlock, flags);673 return mask;674}675 676static const struct file_operations dasd_eer_fops = {677 .open = &dasd_eer_open,678 .release = &dasd_eer_close,679 .read = &dasd_eer_read,680 .poll = &dasd_eer_poll,681 .owner = THIS_MODULE,682 .llseek = noop_llseek,683};684 685static struct miscdevice *dasd_eer_dev = NULL;686 687int __init dasd_eer_init(void)688{689 int rc;690 691 dasd_eer_dev = kzalloc(sizeof(*dasd_eer_dev), GFP_KERNEL);692 if (!dasd_eer_dev)693 return -ENOMEM;694 695 dasd_eer_dev->minor = MISC_DYNAMIC_MINOR;696 dasd_eer_dev->name = "dasd_eer";697 dasd_eer_dev->fops = &dasd_eer_fops;698 699 rc = misc_register(dasd_eer_dev);700 if (rc) {701 kfree(dasd_eer_dev);702 dasd_eer_dev = NULL;703 DBF_EVENT(DBF_ERR, "%s", "dasd_eer_init could not "704 "register misc device");705 return rc;706 }707 708 return 0;709}710 711void dasd_eer_exit(void)712{713 if (dasd_eer_dev) {714 misc_deregister(dasd_eer_dev);715 kfree(dasd_eer_dev);716 dasd_eer_dev = NULL;717 }718}719