📄 dasd.c
字号:
e.g. not _IN_IO */ cqr->status = DASD_CQR_FAILED; cqr->stopclk = get_clock(); rc = 1; break; case DASD_CQR_DONE: case DASD_CQR_FAILED: /* already finished - do nothing */ break; default: DEV_MESSAGE(KERN_ALERT, device, "invalid status %02x in request", cqr->status); BUG(); } 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(request_queue_t * 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. */static intdasd_alloc_queue(struct dasd_device * device){ 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;#if 0 elevator_exit(device->request_queue); rc = elevator_init(device->request_queue, &elevator_noop); if (rc) { blk_cleanup_queue(device->request_queue); return rc; }#endif 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);}/* * 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 (!list_empty(&device->request_queue->queue_head)) { req = elv_next_request(device->request_queue); if (req == NULL) break; dasd_end_request(req, 0); blkdev_dequeue_request(req); } 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) { MESSAGE(KERN_INFO, "No access to device %s due to probeonly mode", disk->disk_name); 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;}struct block_device_operationsdasd_device_operations = { .owner = THIS_MODULE, .open = dasd_open, .release = dasd_release, .ioctl = dasd_ioctl,};static voiddasd_exit(void){#ifdef CONFIG_PROC_FS dasd_proc_exit();#endif dasd_ioctl_exit(); dasd_gendisk_exit(); dasd_devmap_exit(); devfs_remove("dasd"); 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 = 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); } cdev->handler = &dasd_int_handler; 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; 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 *discipline){ struct dasd_device *device; int rc; device = dasd_create_device(cdev); if (IS_ERR(device)) return PTR_ERR(device); if (test_bit(DASD_FLAG_USE_DIAG, &device->flags)) { 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; } device->discipline = discipline; rc = discipline->check_device(device); if (rc) { printk (KERN_WARNING "dasd_generic couldn't online device %s " "with discipline %s\n", cdev->dev.bus_id, discipline->name); 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; 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; if (atomic_read(&device->open_count) > max_count) { printk (KERN_WARNING "Can't offline dasd device with open" " count = %i.\n", atomic_read(&device->open_count)); 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: 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; dasd_schedule_bh(device); } else { list_for_each_entry(cqr, &device->ccw_queue, list) if (cqr->status == DASD_CQR_IN_IO) cqr->status = DASD_CQR_QUEUED; device->stopped |= DASD_STOPPED_DC_WAIT; dasd_set_timer(device, 0); } 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;}/* * Automatically online either all dasd devices (dasd_autodetect) or * all devices specified with dasd= parameters. */voiddasd_generic_auto_online (struct ccw_driver *dasd_discipline_driver){ struct device_driver *drv; struct device *d, *dev; struct ccw_device *cdev; drv = get_driver(&dasd_discipline_driver->driver); down_read(&drv->bus->subsys.rwsem); dev = NULL; list_for_each_entry(d, &drv->devices, driver_list) { dev = get_device(d); if (!dev) continue; cdev = to_ccwdev(dev); if (dasd_autodetect || dasd_busid_known(cdev->dev.bus_id) == 0) ccw_device_set_online(cdev); put_device(dev); } up_read(&drv->bus->subsys.rwsem); put_driver(drv);}static int __initdasd_init(void){ int rc; init_waitqueue_head(&dasd_init_waitq); /* register 'common' DASD debug area, used for all DBF_XXX calls */ dasd_debug_area = debug_register("dasd", 0, 2, 8 * sizeof (long)); if (dasd_debug_area == NULL) { rc = -ENOMEM; goto failed; } debug_register_view(dasd_debug_area, &debug_hex_ascii_view); debug_set_level(dasd_debug_area, DBF_ERR); DBF_EVENT(DBF_EMERG, "%s", "debug area created"); dasd_diag_discipline_pointer = NULL; rc = devfs_mk_dir("dasd"); if (rc) goto failed; 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_ioctl_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);EXPORT_SYMBOL_GPL(dasd_generic_auto_online);/* * Overrides for Emacs so that we follow Linus's tabbing style. * Emacs will notice this stuff at the end of the file and automatically * adjust the settings for this buffer only. This must remain at the end * of the file. * --------------------------------------------------------------------------- * Local variables: * c-indent-level: 4 * c-brace-imaginary-offset: 0 * c-brace-offset: -4 * c-argdecl-indent: 4 * c-label-offset: -4 * c-continued-statement-offset: 4 * c-continued-brace-offset: 0 * indent-tabs-mode: 1 * tab-width: 8 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -