dasd_eer.c
来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 683 行 · 第 1/2 页
C
683 行
data_size = SNSS_DATA_SIZE; header.total_size = sizeof(header) + data_size + 4; /* "EOR" */ header.trigger = DASD_EER_STATECHANGE; do_gettimeofday(&tv); header.tv_sec = tv.tv_sec; header.tv_usec = tv.tv_usec; strncpy(header.busid, device->cdev->dev.bus_id, DASD_EER_BUSID_SIZE); spin_lock_irqsave(&bufferlock, flags); list_for_each_entry(eerb, &bufferlist, list) { dasd_eer_start_record(eerb, header.total_size); dasd_eer_write_buffer(eerb, (char *) &header , sizeof(header)); if (!snss_rc) dasd_eer_write_buffer(eerb, cqr->data, SNSS_DATA_SIZE); dasd_eer_write_buffer(eerb, "EOR", 4); } spin_unlock_irqrestore(&bufferlock, flags); wake_up_interruptible(&dasd_eer_read_wait_queue);}/* * This function is called for all triggers. It calls the appropriate * function that writes the actual trigger records. */void dasd_eer_write(struct dasd_device *device, struct dasd_ccw_req *cqr, unsigned int id){ if (!device->eer_cqr) return; switch (id) { case DASD_EER_FATALERROR: case DASD_EER_PPRCSUSPEND: dasd_eer_write_standard_trigger(device, cqr, id); break; case DASD_EER_NOPATH: dasd_eer_write_standard_trigger(device, NULL, id); break; case DASD_EER_STATECHANGE: dasd_eer_write_snss_trigger(device, cqr, id); break; default: /* unknown trigger, so we write it without any sense data */ dasd_eer_write_standard_trigger(device, NULL, id); break; }}EXPORT_SYMBOL(dasd_eer_write);/* * Start a sense subsystem status request. * Needs to be called with the device held. */void dasd_eer_snss(struct dasd_device *device){ struct dasd_ccw_req *cqr; cqr = device->eer_cqr; if (!cqr) /* Device not eer enabled. */ return; if (test_and_set_bit(DASD_FLAG_EER_IN_USE, &device->flags)) { /* Sense subsystem status request in use. */ set_bit(DASD_FLAG_EER_SNSS, &device->flags); return; } clear_bit(DASD_FLAG_EER_SNSS, &device->flags); cqr->status = DASD_CQR_QUEUED; list_add(&cqr->list, &device->ccw_queue); dasd_schedule_bh(device);}/* * Callback function for use with sense subsystem status request. */static void dasd_eer_snss_cb(struct dasd_ccw_req *cqr, void *data){ struct dasd_device *device = cqr->device; unsigned long flags; dasd_eer_write(device, cqr, DASD_EER_STATECHANGE); spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); if (device->eer_cqr == cqr) { clear_bit(DASD_FLAG_EER_IN_USE, &device->flags); if (test_bit(DASD_FLAG_EER_SNSS, &device->flags)) /* Another SNSS has been requested in the meantime. */ dasd_eer_snss(device); cqr = NULL; } spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); if (cqr) /* * Extended error recovery has been switched off while * the SNSS request was running. It could even have * been switched off and on again in which case there * is a new ccw in device->eer_cqr. Free the "old" * snss request now. */ dasd_kfree_request(cqr, device);}/* * Enable error reporting on a given device. */int dasd_eer_enable(struct dasd_device *device){ struct dasd_ccw_req *cqr; unsigned long flags; if (device->eer_cqr) return 0; if (!device->discipline || strcmp(device->discipline->name, "ECKD")) return -EPERM; /* FIXME: -EMEDIUMTYPE ? */ cqr = dasd_kmalloc_request("ECKD", 1 /* SNSS */, SNSS_DATA_SIZE, device); if (!cqr) return -ENOMEM; cqr->device = device; cqr->retries = 255; cqr->expires = 10 * HZ; cqr->cpaddr->cmd_code = DASD_ECKD_CCW_SNSS; cqr->cpaddr->count = SNSS_DATA_SIZE; cqr->cpaddr->flags = 0; cqr->cpaddr->cda = (__u32)(addr_t) cqr->data; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; cqr->callback = dasd_eer_snss_cb; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); if (!device->eer_cqr) { device->eer_cqr = cqr; cqr = NULL; } spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); if (cqr) dasd_kfree_request(cqr, device); return 0;}/* * Disable error reporting on a given device. */void dasd_eer_disable(struct dasd_device *device){ struct dasd_ccw_req *cqr; unsigned long flags; int in_use; if (!device->eer_cqr) return; spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags); cqr = device->eer_cqr; device->eer_cqr = NULL; clear_bit(DASD_FLAG_EER_SNSS, &device->flags); in_use = test_and_clear_bit(DASD_FLAG_EER_IN_USE, &device->flags); spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); if (cqr && !in_use) dasd_kfree_request(cqr, device);}/* * SECTION: the device operations *//* * On the one side we need a lock to access our internal buffer, on the * other side a copy_to_user can sleep. So we need to copy the data we have * to transfer in a readbuffer, which is protected by the readbuffer_mutex. */static char readbuffer[PAGE_SIZE];static DECLARE_MUTEX(readbuffer_mutex);static int dasd_eer_open(struct inode *inp, struct file *filp){ struct eerbuffer *eerb; unsigned long flags; eerb = kzalloc(sizeof(struct eerbuffer), GFP_KERNEL); eerb->buffer_page_count = eer_pages; if (eerb->buffer_page_count < 1 || eerb->buffer_page_count > INT_MAX / PAGE_SIZE) { kfree(eerb); MESSAGE(KERN_WARNING, "can't open device since module " "parameter eer_pages is smaller then 1 or" " bigger then %d", (int)(INT_MAX / PAGE_SIZE)); return -EINVAL; } eerb->buffersize = eerb->buffer_page_count * PAGE_SIZE; eerb->buffer = kmalloc(eerb->buffer_page_count * sizeof(char *), GFP_KERNEL); if (!eerb->buffer) { kfree(eerb); return -ENOMEM; } if (dasd_eer_allocate_buffer_pages(eerb->buffer, eerb->buffer_page_count)) { kfree(eerb->buffer); kfree(eerb); return -ENOMEM; } filp->private_data = eerb; spin_lock_irqsave(&bufferlock, flags); list_add(&eerb->list, &bufferlist); spin_unlock_irqrestore(&bufferlock, flags); return nonseekable_open(inp,filp);}static int dasd_eer_close(struct inode *inp, struct file *filp){ struct eerbuffer *eerb; unsigned long flags; eerb = (struct eerbuffer *) filp->private_data; spin_lock_irqsave(&bufferlock, flags); list_del(&eerb->list); spin_unlock_irqrestore(&bufferlock, flags); dasd_eer_free_buffer_pages(eerb->buffer, eerb->buffer_page_count); kfree(eerb->buffer); kfree(eerb); return 0;}static ssize_t dasd_eer_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos){ int tc,rc; int tailcount,effective_count; unsigned long flags; struct eerbuffer *eerb; eerb = (struct eerbuffer *) filp->private_data; if (down_interruptible(&readbuffer_mutex)) return -ERESTARTSYS; spin_lock_irqsave(&bufferlock, flags); if (eerb->residual < 0) { /* the remainder of this record */ /* has been deleted */ eerb->residual = 0; spin_unlock_irqrestore(&bufferlock, flags); up(&readbuffer_mutex); return -EIO; } else if (eerb->residual > 0) { /* OK we still have a second half of a record to deliver */ effective_count = min(eerb->residual, (int) count); eerb->residual -= effective_count; } else { tc = 0; while (!tc) { tc = dasd_eer_read_buffer(eerb, (char *) &tailcount, sizeof(tailcount)); if (!tc) { /* no data available */ spin_unlock_irqrestore(&bufferlock, flags); up(&readbuffer_mutex); if (filp->f_flags & O_NONBLOCK) return -EAGAIN; rc = wait_event_interruptible( dasd_eer_read_wait_queue, eerb->head != eerb->tail); if (rc) return rc; if (down_interruptible(&readbuffer_mutex)) return -ERESTARTSYS; spin_lock_irqsave(&bufferlock, flags); } } WARN_ON(tc != sizeof(tailcount)); effective_count = min(tailcount,(int)count); eerb->residual = tailcount - effective_count; } tc = dasd_eer_read_buffer(eerb, readbuffer, effective_count); WARN_ON(tc != effective_count); spin_unlock_irqrestore(&bufferlock, flags); if (copy_to_user(buf, readbuffer, effective_count)) { up(&readbuffer_mutex); return -EFAULT; } up(&readbuffer_mutex); return effective_count;}static unsigned int dasd_eer_poll(struct file *filp, poll_table *ptable){ unsigned int mask; unsigned long flags; struct eerbuffer *eerb; eerb = (struct eerbuffer *) filp->private_data; poll_wait(filp, &dasd_eer_read_wait_queue, ptable); spin_lock_irqsave(&bufferlock, flags); if (eerb->head != eerb->tail) mask = POLLIN | POLLRDNORM ; else mask = 0; spin_unlock_irqrestore(&bufferlock, flags); return mask;}static struct file_operations dasd_eer_fops = { .open = &dasd_eer_open, .release = &dasd_eer_close, .read = &dasd_eer_read, .poll = &dasd_eer_poll, .owner = THIS_MODULE,};static struct miscdevice dasd_eer_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "dasd_eer", .fops = &dasd_eer_fops,};int __init dasd_eer_init(void){ int rc; rc = misc_register(&dasd_eer_dev); if (rc) { MESSAGE(KERN_ERR, "%s", "dasd_eer_init could not " "register misc device"); return rc; } return 0;}void __exit dasd_eer_exit(void){ WARN_ON(misc_deregister(&dasd_eer_dev) != 0);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?