dasd.c
来自「linux 内核源代码」· C语言 代码 · 共 2,303 行 · 第 1/4 页
C
2,303 行
} spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags); dasd_schedule_bh(device); return rc;}/* * SECTION: Block device operations (request queue, partitions, open, release). *//* * Dasd request queue function. Called from ll_rw_blk.c */static voiddo_dasd_request(struct request_queue * queue){ struct dasd_device *device; device = (struct dasd_device *) queue->queuedata; spin_lock(get_ccwdev_lock(device->cdev)); /* Get new request from the block device request queue */ __dasd_process_blk_queue(device); /* Now check if the head of the ccw queue needs to be started. */ __dasd_start_head(device); spin_unlock(get_ccwdev_lock(device->cdev));}/* * Allocate and initialize request queue and default I/O scheduler. */static intdasd_alloc_queue(struct dasd_device * device){ int rc; device->request_queue = blk_init_queue(do_dasd_request, &device->request_queue_lock); if (device->request_queue == NULL) return -ENOMEM; device->request_queue->queuedata = device; elevator_exit(device->request_queue->elevator); rc = elevator_init(device->request_queue, "deadline"); if (rc) { blk_cleanup_queue(device->request_queue); return rc; } return 0;}/* * Allocate and initialize request queue. */static voiddasd_setup_queue(struct dasd_device * device){ int max; blk_queue_hardsect_size(device->request_queue, device->bp_block); max = device->discipline->max_blocks << device->s2b_shift; blk_queue_max_sectors(device->request_queue, max); blk_queue_max_phys_segments(device->request_queue, -1L); blk_queue_max_hw_segments(device->request_queue, -1L); blk_queue_max_segment_size(device->request_queue, -1L); blk_queue_segment_boundary(device->request_queue, -1L); blk_queue_ordered(device->request_queue, QUEUE_ORDERED_TAG, NULL);}/* * Deactivate and free request queue. */static voiddasd_free_queue(struct dasd_device * device){ if (device->request_queue) { blk_cleanup_queue(device->request_queue); device->request_queue = NULL; }}/* * Flush request on the request queue. */static voiddasd_flush_request_queue(struct dasd_device * device){ struct request *req; if (!device->request_queue) return; spin_lock_irq(&device->request_queue_lock); while ((req = elv_next_request(device->request_queue))) { blkdev_dequeue_request(req); dasd_end_request(req, 0); } spin_unlock_irq(&device->request_queue_lock);}static intdasd_open(struct inode *inp, struct file *filp){ struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; int rc; atomic_inc(&device->open_count); if (test_bit(DASD_FLAG_OFFLINE, &device->flags)) { rc = -ENODEV; goto unlock; } if (!try_module_get(device->discipline->owner)) { rc = -EINVAL; goto unlock; } if (dasd_probeonly) { DEV_MESSAGE(KERN_INFO, device, "%s", "No access to device due to probeonly mode"); rc = -EPERM; goto out; } if (device->state <= DASD_STATE_BASIC) { DBF_DEV_EVENT(DBF_ERR, device, " %s", " Cannot open unrecognized device"); rc = -ENODEV; goto out; } return 0;out: module_put(device->discipline->owner);unlock: atomic_dec(&device->open_count); return rc;}static intdasd_release(struct inode *inp, struct file *filp){ struct gendisk *disk = inp->i_bdev->bd_disk; struct dasd_device *device = disk->private_data; atomic_dec(&device->open_count); module_put(device->discipline->owner); return 0;}/* * Return disk geometry. */static intdasd_getgeo(struct block_device *bdev, struct hd_geometry *geo){ struct dasd_device *device; device = bdev->bd_disk->private_data; if (!device) return -ENODEV; if (!device->discipline || !device->discipline->fill_geometry) return -EINVAL; device->discipline->fill_geometry(device, geo); geo->start = get_start_sect(bdev) >> device->s2b_shift; return 0;}struct block_device_operationsdasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, .ioctl = dasd_ioctl, .compat_ioctl = dasd_compat_ioctl, .getgeo = dasd_getgeo,};static voiddasd_exit(void){#ifdef CONFIG_PROC_FS dasd_proc_exit();#endif dasd_eer_exit(); if (dasd_page_cache != NULL) { kmem_cache_destroy(dasd_page_cache); dasd_page_cache = NULL; } dasd_gendisk_exit(); dasd_devmap_exit(); if (dasd_debug_area != NULL) { debug_unregister(dasd_debug_area); dasd_debug_area = NULL; }}/* * SECTION: common functions for ccw_driver use *//* * Initial attempt at a probe function. this can be simplified once * the other detection code is gone. */intdasd_generic_probe (struct ccw_device *cdev, struct dasd_discipline *discipline){ int ret; ret = ccw_device_set_options(cdev, CCWDEV_DO_PATHGROUP); if (ret) { printk(KERN_WARNING "dasd_generic_probe: could not set ccw-device options " "for %s\n", cdev->dev.bus_id); return ret; } ret = dasd_add_sysfs_files(cdev); if (ret) { printk(KERN_WARNING "dasd_generic_probe: could not add sysfs entries " "for %s\n", cdev->dev.bus_id); return ret; } cdev->handler = &dasd_int_handler; /* * Automatically online either all dasd devices (dasd_autodetect) * or all devices specified with dasd= parameters during * initial probe. */ if ((dasd_get_feature(cdev, DASD_FEATURE_INITIAL_ONLINE) > 0 ) || (dasd_autodetect && dasd_busid_known(cdev->dev.bus_id) != 0)) ret = ccw_device_set_online(cdev); if (ret) printk(KERN_WARNING "dasd_generic_probe: could not initially online " "ccw-device %s\n", cdev->dev.bus_id); return ret;}/* * This will one day be called from a global not_oper handler. * It is also used by driver_unregister during module unload. */voiddasd_generic_remove (struct ccw_device *cdev){ struct dasd_device *device; cdev->handler = NULL; dasd_remove_sysfs_files(cdev); device = dasd_device_from_cdev(cdev); if (IS_ERR(device)) return; if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { /* Already doing offline processing */ dasd_put_device(device); return; } /* * This device is removed unconditionally. Set offline * flag to prevent dasd_open from opening it while it is * no quite down yet. */ dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ dasd_delete_device(device);}/* * Activate a device. This is called from dasd_{eckd,fba}_probe() when either * the device is detected for the first time and is supposed to be used * or the user has started activation through sysfs. */intdasd_generic_set_online (struct ccw_device *cdev, struct dasd_discipline *base_discipline){ struct dasd_discipline *discipline; struct dasd_device *device; int rc; /* first online clears initial online feature flag */ dasd_set_feature(cdev, DASD_FEATURE_INITIAL_ONLINE, 0); device = dasd_create_device(cdev); if (IS_ERR(device)) return PTR_ERR(device); discipline = base_discipline; if (device->features & DASD_FEATURE_USEDIAG) { if (!dasd_diag_discipline_pointer) { printk (KERN_WARNING "dasd_generic couldn't online device %s " "- discipline DIAG not available\n", cdev->dev.bus_id); dasd_delete_device(device); return -ENODEV; } discipline = dasd_diag_discipline_pointer; } if (!try_module_get(base_discipline->owner)) { dasd_delete_device(device); return -EINVAL; } if (!try_module_get(discipline->owner)) { module_put(base_discipline->owner); dasd_delete_device(device); return -EINVAL; } device->base_discipline = base_discipline; device->discipline = discipline; rc = discipline->check_device(device); if (rc) { printk (KERN_WARNING "dasd_generic couldn't online device %s " "with discipline %s rc=%i\n", cdev->dev.bus_id, discipline->name, rc); module_put(discipline->owner); module_put(base_discipline->owner); dasd_delete_device(device); return rc; } dasd_set_target_state(device, DASD_STATE_ONLINE); if (device->state <= DASD_STATE_KNOWN) { printk (KERN_WARNING "dasd_generic discipline not found for %s\n", cdev->dev.bus_id); rc = -ENODEV; dasd_set_target_state(device, DASD_STATE_NEW); dasd_delete_device(device); } else pr_debug("dasd_generic device %s found\n", cdev->dev.bus_id); /* FIXME: we have to wait for the root device but we don't want * to wait for each single device but for all at once. */ wait_event(dasd_init_waitq, _wait_for_device(device)); dasd_put_device(device); return rc;}intdasd_generic_set_offline (struct ccw_device *cdev){ struct dasd_device *device; int max_count, open_count; device = dasd_device_from_cdev(cdev); if (IS_ERR(device)) return PTR_ERR(device); if (test_and_set_bit(DASD_FLAG_OFFLINE, &device->flags)) { /* Already doing offline processing */ dasd_put_device(device); return 0; } /* * We must make sure that this device is currently not in use. * The open_count is increased for every opener, that includes * the blkdev_get in dasd_scan_partitions. We are only interested * in the other openers. */ max_count = device->bdev ? 0 : -1; open_count = (int) atomic_read(&device->open_count); if (open_count > max_count) { if (open_count > 0) printk (KERN_WARNING "Can't offline dasd device with " "open count = %i.\n", open_count); else printk (KERN_WARNING "%s", "Can't offline dasd device due to internal " "use\n"); clear_bit(DASD_FLAG_OFFLINE, &device->flags); dasd_put_device(device); return -EBUSY; } dasd_set_target_state(device, DASD_STATE_NEW); /* dasd_delete_device destroys the device reference. */ dasd_delete_device(device); return 0;}intdasd_generic_notify(struct ccw_device *cdev, int event){ struct dasd_device *device; struct dasd_ccw_req *cqr; unsigned long flags; int ret; device = dasd_device_from_cdev(cdev); if (IS_ERR(device)) return 0; spin_lock_irqsave(get_ccwdev_lock(cdev), flags); ret = 0; switch (event) { case CIO_GONE: case CIO_NO_PATH: /* First of all call extended error reporting. */ dasd_eer_write(device, NULL, DASD_EER_NOPATH); if (device->state < DASD_STATE_BASIC) break; /* Device is active. We want to keep it. */ if (test_bit(DASD_FLAG_DSC_ERROR, &device->flags)) { list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_FAILED; device->stopped |= DASD_STOPPED_DC_EIO; } else { list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_IN_IO) { cqr->status = DASD_CQR_QUEUED; cqr->retries++; } device->stopped |= DASD_STOPPED_DC_WAIT; dasd_set_timer(device, 0); } dasd_schedule_bh(device); ret = 1; break; case CIO_OPER: /* FIXME: add a sanity check. */ device->stopped &= ~(DASD_STOPPED_DC_WAIT|DASD_STOPPED_DC_EIO); dasd_schedule_bh(device); ret = 1; break; } spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags); dasd_put_device(device); return ret;}static struct dasd_ccw_req *dasd_generic_build_rdc(struct dasd_device *device, void *rdc_buffer, int rdc_buffer_size, char *magic){ struct dasd_ccw_req *cqr; struct ccw1 *ccw; cqr = dasd_smalloc_request(magic, 1 /* RDC */, rdc_buffer_size, device); if (IS_ERR(cqr)) { DEV_MESSAGE(KERN_WARNING, device, "%s", "Could not allocate RDC request"); return cqr; } ccw = cqr->cpaddr; ccw->cmd_code = CCW_CMD_RDC; ccw->cda = (__u32)(addr_t)rdc_buffer; ccw->count = rdc_buffer_size; cqr->device = device; cqr->expires = 10*HZ; clear_bit(DASD_CQR_FLAGS_USE_ERP, &cqr->flags); cqr->retries = 2; cqr->buildclk = get_clock(); cqr->status = DASD_CQR_FILLED; return cqr;}int dasd_generic_read_dev_chars(struct dasd_device *device, char *magic, void **rdc_buffer, int rdc_buffer_size){ int ret; struct dasd_ccw_req *cqr; cqr = dasd_generic_build_rdc(device, *rdc_buffer, rdc_buffer_size, magic); if (IS_ERR(cqr)) return PTR_ERR(cqr); ret = dasd_sleep_on(cqr); dasd_sfree_request(cqr, cqr->device); return ret;}EXPORT_SYMBOL_GPL(dasd_generic_read_dev_chars);static int __initdasd_init(void){ int rc; init_waitqueue_head(&dasd_init_waitq); init_waitqueue_head(&dasd_flush_wq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ dasd_debug_area = debug_register("dasd", 1, 2, 8 * sizeof (long)); if (dasd_debug_area == NULL) { rc = -ENOMEM; goto failed; } debug_register_view(dasd_debug_area, &debug_sprintf_view); debug_set_level(dasd_debug_area, DBF_WARNING); DBF_EVENT(DBF_EMERG, "%s", "debug area created"); dasd_diag_discipline_pointer = NULL; rc = dasd_devmap_init(); if (rc) goto failed; rc = dasd_gendisk_init(); if (rc) goto failed; rc = dasd_parse(); if (rc) goto failed; rc = dasd_eer_init(); if (rc) goto failed;#ifdef CONFIG_PROC_FS rc = dasd_proc_init(); if (rc) goto failed;#endif return 0;failed: MESSAGE(KERN_INFO, "%s", "initialization not performed due to errors"); dasd_exit(); return rc;}module_init(dasd_init);module_exit(dasd_exit);EXPORT_SYMBOL(dasd_debug_area);EXPORT_SYMBOL(dasd_diag_discipline_pointer);EXPORT_SYMBOL(dasd_add_request_head);EXPORT_SYMBOL(dasd_add_request_tail);EXPORT_SYMBOL(dasd_cancel_req);EXPORT_SYMBOL(dasd_clear_timer);EXPORT_SYMBOL(dasd_enable_device);EXPORT_SYMBOL(dasd_int_handler);EXPORT_SYMBOL(dasd_kfree_request);EXPORT_SYMBOL(dasd_kick_device);EXPORT_SYMBOL(dasd_kmalloc_request);EXPORT_SYMBOL(dasd_schedule_bh);EXPORT_SYMBOL(dasd_set_target_state);EXPORT_SYMBOL(dasd_set_timer);EXPORT_SYMBOL(dasd_sfree_request);EXPORT_SYMBOL(dasd_sleep_on);EXPORT_SYMBOL(dasd_sleep_on_immediatly);EXPORT_SYMBOL(dasd_sleep_on_interruptible);EXPORT_SYMBOL(dasd_smalloc_request);EXPORT_SYMBOL(dasd_start_IO);EXPORT_SYMBOL(dasd_term_IO);EXPORT_SYMBOL_GPL(dasd_generic_probe);EXPORT_SYMBOL_GPL(dasd_generic_remove);EXPORT_SYMBOL_GPL(dasd_generic_notify);EXPORT_SYMBOL_GPL(dasd_generic_set_online);EXPORT_SYMBOL_GPL(dasd_generic_set_offline);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?