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 + -
显示快捷键?