scsi_debug.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,869 行 · 第 1/4 页
C
1,869 行
}DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show, sdebug_delay_store);static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);}static ssize_t sdebug_opts_store(struct device_driver * ddp, const char * buf, size_t count){ int opts; char work[20]; if (1 == sscanf(buf, "%10s", work)) { if (0 == strnicmp(work,"0x", 2)) { if (1 == sscanf(&work[2], "%x", &opts)) goto opts_done; } else { if (1 == sscanf(work, "%d", &opts)) goto opts_done; } } return -EINVAL;opts_done: scsi_debug_opts = opts; scsi_debug_cmnd_count = 0; return count;}DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show, sdebug_opts_store);static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);}static ssize_t sdebug_ptype_store(struct device_driver * ddp, const char * buf, size_t count){ int n; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { scsi_debug_ptype = n; return count; } return -EINVAL;}DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);}static ssize_t sdebug_num_tgts_store(struct device_driver * ddp, const char * buf, size_t count){ int n; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { scsi_debug_num_tgts = n; sdebug_max_tgts_luns(); return count; } return -EINVAL;}DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show, sdebug_num_tgts_store);static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);}DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);}DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);}static ssize_t sdebug_every_nth_store(struct device_driver * ddp, const char * buf, size_t count){ int nth; if ((count > 0) && (1 == sscanf(buf, "%d", &nth)) && (nth >= 0)) { scsi_debug_every_nth = nth; scsi_debug_cmnd_count = 0; return count; } return -EINVAL;}DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show, sdebug_every_nth_store);static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);}static ssize_t sdebug_max_luns_store(struct device_driver * ddp, const char * buf, size_t count){ int n; if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) { scsi_debug_max_luns = n; sdebug_max_tgts_luns(); return count; } return -EINVAL;}DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show, sdebug_max_luns_store);static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);}DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf){ return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);}static ssize_t sdebug_add_host_store(struct device_driver * ddp, const char * buf, size_t count){ int delta_hosts; char work[20]; if (1 != sscanf(buf, "%10s", work)) return -EINVAL; { /* temporary hack around sscanf() problem with -ve nums */ int neg = 0; if ('-' == *work) neg = 1; if (1 != sscanf(work + neg, "%d", &delta_hosts)) return -EINVAL; if (neg) delta_hosts = -delta_hosts; } if (delta_hosts > 0) { do { sdebug_add_adapter(); } while (--delta_hosts); } else if (delta_hosts < 0) { do { sdebug_remove_adapter(); } while (++delta_hosts); } return count;}DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, sdebug_add_host_store);static void do_create_driverfs_files(void){ driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host); driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth); driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns); driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts); driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype); driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts); driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);}static void do_remove_driverfs_files(void){ driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay); driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);}static int __init scsi_debug_init(void){ unsigned long sz; int host_to_add; int k; if (scsi_debug_dev_size_mb < 1) scsi_debug_dev_size_mb = 1; /* force minimum 1 MB ramdisk */ sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576; sdebug_capacity = sdebug_store_size / SECT_SIZE; /* play around with geometry, don't waste too much on track 0 */ sdebug_heads = 8; sdebug_sectors_per = 32; if (scsi_debug_dev_size_mb >= 16) sdebug_heads = 32; else if (scsi_debug_dev_size_mb >= 256) sdebug_heads = 64; sdebug_cylinders_per = (unsigned long)sdebug_capacity / (sdebug_sectors_per * sdebug_heads); if (sdebug_cylinders_per >= 1024) { /* other LLDs do this; implies >= 1GB ram disk ... */ sdebug_heads = 255; sdebug_sectors_per = 63; sdebug_cylinders_per = (unsigned long)sdebug_capacity / (sdebug_sectors_per * sdebug_heads); } sz = sdebug_store_size; fake_storep = vmalloc(sz); if (NULL == fake_storep) { printk(KERN_ERR "scsi_debug_init: out of memory, 1\n"); return -ENOMEM; } memset(fake_storep, 0, sz); if (scsi_debug_num_parts > 0) sdebug_build_parts(fake_storep); init_all_queued(); device_register(&pseudo_primary); bus_register(&pseudo_lld_bus); driver_register(&sdebug_driverfs_driver); do_create_driverfs_files(); sdebug_driver_template.proc_name = (char *)sdebug_proc_name; host_to_add = scsi_debug_add_host; scsi_debug_add_host = 0; for (k = 0; k < host_to_add; k++) { if (sdebug_add_adapter()) { printk(KERN_ERR "scsi_debug_init: " "sdebug_add_adapter failed k=%d\n", k); break; } } if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) { printk(KERN_INFO "scsi_debug_init: built %d host(s)\n", scsi_debug_add_host); } return 0;}static void __exit scsi_debug_exit(void){ int k = scsi_debug_add_host; stop_all_queued(); for (; k; k--) sdebug_remove_adapter(); do_remove_driverfs_files(); driver_unregister(&sdebug_driverfs_driver); bus_unregister(&pseudo_lld_bus); device_unregister(&pseudo_primary); vfree(fake_storep);}device_initcall(scsi_debug_init);module_exit(scsi_debug_exit);void pseudo_0_release(struct device * dev){ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");}static struct device pseudo_primary = { .bus_id = "pseudo_0", .release = pseudo_0_release,};static int pseudo_lld_bus_match(struct device *dev, struct device_driver *dev_driver){ return 1;}static struct bus_type pseudo_lld_bus = { .name = "pseudo", .match = pseudo_lld_bus_match,};static void sdebug_release_adapter(struct device * dev){ struct sdebug_host_info *sdbg_host; sdbg_host = to_sdebug_host(dev); kfree(sdbg_host);}static int sdebug_add_adapter(void){ int k, devs_per_host; int error = 0; struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *sdbg_devinfo; struct list_head *lh, *lh_sf; sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL); if (NULL == sdbg_host) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); return -ENOMEM; } memset(sdbg_host, 0, sizeof(*sdbg_host)); INIT_LIST_HEAD(&sdbg_host->dev_info_list); devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns; for (k = 0; k < devs_per_host; k++) { sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL); if (NULL == sdbg_devinfo) { printk(KERN_ERR "%s: out of memory at line %d\n", __FUNCTION__, __LINE__); error = -ENOMEM; goto clean; } memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo)); sdbg_devinfo->sdbg_host = sdbg_host; list_add_tail(&sdbg_devinfo->dev_list, &sdbg_host->dev_info_list); } spin_lock(&sdebug_host_list_lock); list_add_tail(&sdbg_host->host_list, &sdebug_host_list); spin_unlock(&sdebug_host_list_lock); sdbg_host->dev.bus = &pseudo_lld_bus; sdbg_host->dev.parent = &pseudo_primary; sdbg_host->dev.release = &sdebug_release_adapter; sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host); error = device_register(&sdbg_host->dev); if (error) goto clean; ++scsi_debug_add_host; return error;clean: list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, dev_list); list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } kfree(sdbg_host); return error;}static void sdebug_remove_adapter(void){ struct sdebug_host_info * sdbg_host = NULL; spin_lock(&sdebug_host_list_lock); if (!list_empty(&sdebug_host_list)) { sdbg_host = list_entry(sdebug_host_list.prev, struct sdebug_host_info, host_list); list_del(&sdbg_host->host_list); } spin_unlock(&sdebug_host_list_lock); if (!sdbg_host) return; device_unregister(&sdbg_host->dev); --scsi_debug_add_host;}static int sdebug_driver_probe(struct device * dev){ int error = 0; struct sdebug_host_info *sdbg_host; struct Scsi_Host *hpnt; sdbg_host = to_sdebug_host(dev); hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host)); if (NULL == hpnt) { printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__); error = -ENODEV; return error; } sdbg_host->shost = hpnt; *((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host; if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; hpnt->max_lun = scsi_debug_max_luns; error = scsi_add_host(hpnt, &sdbg_host->dev); if (error) { printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__); error = -ENODEV; scsi_host_put(hpnt); } else scsi_scan_host(hpnt); return error;}static int sdebug_driver_remove(struct device * dev){ struct list_head *lh, *lh_sf; struct sdebug_host_info *sdbg_host; struct sdebug_dev_info *sdbg_devinfo; sdbg_host = to_sdebug_host(dev); if (!sdbg_host) { printk(KERN_ERR "%s: Unable to locate host info\n", __FUNCTION__); return -ENODEV; } scsi_remove_host(sdbg_host->shost); list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) { sdbg_devinfo = list_entry(lh, struct sdebug_dev_info, dev_list); list_del(&sdbg_devinfo->dev_list); kfree(sdbg_devinfo); } scsi_host_put(sdbg_host->shost); return 0;}static void sdebug_max_tgts_luns(void){ struct sdebug_host_info * sdbg_host; struct Scsi_Host *hpnt; spin_lock(&sdebug_host_list_lock); list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) { hpnt = sdbg_host->shost; if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id)) hpnt->max_id = scsi_debug_num_tgts + 1; else hpnt->max_id = scsi_debug_num_tgts; hpnt->max_lun = scsi_debug_max_luns; } spin_unlock(&sdebug_host_list_lock);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?