scsi_devinfo.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 551 行 · 第 1/2 页

C
551
字号
 * scsi_dev_info_list_add_str: parse dev_list and add to the * scsi_dev_info_list. * @dev_list:	string of device flags to add * * Description: * 	Parse dev_list, and add entries to the scsi_dev_info_list. * 	dev_list is of the form "vendor:product:flag,vendor:product:flag". * 	dev_list is modified via strsep. Can be called for command line * 	addition, for proc or mabye a sysfs interface. * * Returns: 0 if OK, -error on failure. **/static int scsi_dev_info_list_add_str(char *dev_list){	char *vendor, *model, *strflags, *next;	char *next_check;	int res = 0;	next = dev_list;	if (next && next[0] == '"') {		/*		 * Ignore both the leading and trailing quote.		 */		next++;		next_check = ",\"";	} else {		next_check = ",";	}	/*	 * For the leading and trailing '"' case, the for loop comes	 * through the last time with vendor[0] == '\0'.	 */	for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0')	     && (res == 0); vendor = strsep(&next, ":")) {		strflags = NULL;		model = strsep(&next, ":");		if (model)			strflags = strsep(&next, next_check);		if (!model || !strflags) {			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"			       " '%s'\n", __FUNCTION__, vendor, model,			       strflags);			res = -EINVAL;		} else			res = scsi_dev_info_list_add(0 /* compatible */, vendor,						     model, strflags, 0);	}	return res;}/** * get_device_flags - get device specific flags from the dynamic device * list. Called during scan time. * @vendor:	vendor name * @model:	model name * * Description: *     Search the scsi_dev_info_list for an entry matching @vendor and *     @model, if found, return the matching flags value, else return *     the host or global default settings. **/int scsi_get_device_flags(struct scsi_device *sdev, unsigned char *vendor,			  unsigned char *model){	struct scsi_dev_info_list *devinfo;	unsigned int bflags;	bflags = sdev->sdev_bflags;	if (!bflags)		bflags = scsi_default_dev_flags;	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {		if (devinfo->compatible) {			/*			 * Behave like the older version of get_device_flags.			 */			size_t max;			/*			 * XXX why skip leading spaces? If an odd INQUIRY			 * value, that should have been part of the			 * scsi_static_device_list[] entry, such as "  FOO"			 * rather than "FOO". Since this code is already			 * here, and we don't know what device it is			 * trying to work with, leave it as-is.			 */			max = 8;	/* max length of vendor */			while ((max > 0) && *vendor == ' ') {				max--;				vendor++;			}			/*			 * XXX removing the following strlen() would be			 * good, using it means that for a an entry not in			 * the list, we scan every byte of every vendor			 * listed in scsi_static_device_list[], and never match			 * a single one (and still have to compare at			 * least the first byte of each vendor).			 */			if (memcmp(devinfo->vendor, vendor,				    min(max, strlen(devinfo->vendor))))				continue;			/*			 * Skip spaces again.			 */			max = 16;	/* max length of model */			while ((max > 0) && *model == ' ') {				max--;				model++;			}			if (memcmp(devinfo->model, model,				   min(max, strlen(devinfo->model))))				continue;			return devinfo->flags;		} else {			if (!memcmp(devinfo->vendor, vendor,				     sizeof(devinfo->vendor)) &&			     !memcmp(devinfo->model, model,				      sizeof(devinfo->model)))				return devinfo->flags;		}	}	return bflags;}#ifdef CONFIG_SCSI_PROC_FS/*  * proc_scsi_dev_info_read: dump the scsi_dev_info_list via * /proc/scsi/device_info */static int proc_scsi_devinfo_read(char *buffer, char **start,				  off_t offset, int length){	struct scsi_dev_info_list *devinfo;	int size, len = 0;	off_t begin = 0;	off_t pos = 0;	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {		size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",			devinfo->vendor, devinfo->model, devinfo->flags);		len += size;		pos = begin + len;		if (pos < offset) {			len = 0;			begin = pos;		}		if (pos > offset + length)			goto stop_output;	}stop_output:	*start = buffer + (offset - begin);	/* Start of wanted data */	len -= (offset - begin);	/* Start slop */	if (len > length)		len = length;	/* Ending slop */	return (len);}/*  * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via * /proc. * * Use: echo "vendor:model:flag" > /proc/scsi/device_info * * To add a black/white list entry for vendor and model with an integer * value of flag to the scsi device info list. */static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,				   unsigned long length, void *data){	char *buffer;	int err = length;	if (!buf || length>PAGE_SIZE)		return -EINVAL;	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))		return -ENOMEM;	if (copy_from_user(buffer, buf, length)) {		err =-EFAULT;		goto out;	}	if (length < PAGE_SIZE)		buffer[length] = '\0';	else if (buffer[PAGE_SIZE-1]) {		err = -EINVAL;		goto out;	}	scsi_dev_info_list_add_str(buffer);out:	free_page((unsigned long)buffer);	return err;}#endif /* CONFIG_SCSI_PROC_FS */module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0);MODULE_PARM_DESC(dev_flags,	 "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white"	 " list entries for vendor and model with an integer value of flags"	 " to the scsi device info list");module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR);MODULE_PARM_DESC(default_dev_flags,		 "scsi default device flag integer value");/** * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove * 	the scsi_dev_info_list. **/void scsi_exit_devinfo(void){	struct list_head *lh, *lh_next;	struct scsi_dev_info_list *devinfo;#ifdef CONFIG_SCSI_PROC_FS	remove_proc_entry("scsi/device_info", NULL);#endif	list_for_each_safe(lh, lh_next, &scsi_dev_info_list) {		devinfo = list_entry(lh, struct scsi_dev_info_list,				     dev_info_list);		kfree(devinfo);	}}/** * scsi_dev_list_init: set up the dynamic device list. * @dev_list:	string of device flags to add * * Description: * 	Add command line @dev_list entries, then add * 	scsi_static_device_list entries to the scsi device info list. **/int scsi_init_devinfo(void){#ifdef CONFIG_SCSI_PROC_FS	struct proc_dir_entry *p;#endif	int error, i;	error = scsi_dev_info_list_add_str(scsi_dev_flags);	if (error)		return error;	for (i = 0; scsi_static_device_list[i].vendor; i++) {		error = scsi_dev_info_list_add(1 /* compatibile */,				scsi_static_device_list[i].vendor,				scsi_static_device_list[i].model,				NULL,				scsi_static_device_list[i].flags);		if (error)			goto out;	}#ifdef CONFIG_SCSI_PROC_FS	p = create_proc_entry("scsi/device_info", 0, NULL);	if (!p) {		error = -ENOMEM;		goto out;	}	p->owner = THIS_MODULE;	p->get_info = proc_scsi_devinfo_read;	p->write_proc = proc_scsi_devinfo_write;#endif /* CONFIG_SCSI_PROC_FS */ out:	if (error)		scsi_exit_devinfo();	return error;}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?