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