scsi_sysfs.c

来自「linux 内核源代码」· C语言 代码 · 共 1,066 行 · 第 1/2 页

C
1,066
字号
store_rescan_field (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	scsi_rescan_device(dev);	return count;}static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);static void sdev_store_delete_callback(struct device *dev){	scsi_remove_device(to_scsi_device(dev));}static ssize_t sdev_store_delete(struct device *dev, struct device_attribute *attr, const char *buf,				 size_t count){	int rc;	/* An attribute cannot be unregistered by one of its own methods,	 * so we have to use this roundabout approach.	 */	rc = device_schedule_callback(dev, sdev_store_delete_callback);	if (rc)		count = rc;	return count;};static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);static ssize_tstore_state_field(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	int i;	struct scsi_device *sdev = to_scsi_device(dev);	enum scsi_device_state state = 0;	for (i = 0; i < ARRAY_SIZE(sdev_states); i++) {		const int len = strlen(sdev_states[i].name);		if (strncmp(sdev_states[i].name, buf, len) == 0 &&		   buf[len] == '\n') {			state = sdev_states[i].value;			break;		}	}	if (!state)		return -EINVAL;	if (scsi_device_set_state(sdev, state))		return -EINVAL;	return count;}static ssize_tshow_state_field(struct device *dev, struct device_attribute *attr, char *buf){	struct scsi_device *sdev = to_scsi_device(dev);	const char *name = scsi_device_state_name(sdev->sdev_state);	if (!name)		return -EINVAL;	return snprintf(buf, 20, "%s\n", name);}static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field);static ssize_tshow_queue_type_field(struct device *dev, struct device_attribute *attr, char *buf){	struct scsi_device *sdev = to_scsi_device(dev);	const char *name = "none";	if (sdev->ordered_tags)		name = "ordered";	else if (sdev->simple_tags)		name = "simple";	return snprintf(buf, 20, "%s\n", name);}static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);static ssize_tshow_iostat_counterbits(struct device *dev, struct device_attribute *attr, char *buf){	return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);}static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL);#define show_sdev_iostat(field)						\static ssize_t								\show_iostat_##field(struct device *dev, struct device_attribute *attr, char *buf)			\{									\	struct scsi_device *sdev = to_scsi_device(dev);			\	unsigned long long count = atomic_read(&sdev->field);		\	return snprintf(buf, 20, "0x%llx\n", count);			\}									\static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL)show_sdev_iostat(iorequest_cnt);show_sdev_iostat(iodone_cnt);show_sdev_iostat(ioerr_cnt);static ssize_tsdev_show_modalias(struct device *dev, struct device_attribute *attr, char *buf){	struct scsi_device *sdev;	sdev = to_scsi_device(dev);	return snprintf (buf, 20, SCSI_DEVICE_MODALIAS_FMT "\n", sdev->type);}static DEVICE_ATTR(modalias, S_IRUGO, sdev_show_modalias, NULL);#define DECLARE_EVT_SHOW(name, Cap_name)				\static ssize_t								\sdev_show_evt_##name(struct device *dev, struct device_attribute *attr,	\				char *buf)				\{									\	struct scsi_device *sdev = to_scsi_device(dev);			\	int val = test_bit(SDEV_EVT_##Cap_name, sdev->supported_events);\	return snprintf(buf, 20, "%d\n", val);				\}#define DECLARE_EVT_STORE(name, Cap_name)				\static ssize_t								\sdev_store_evt_##name(struct device *dev, struct device_attribute *attr, \		      const char *buf, size_t count)			\{									\	struct scsi_device *sdev = to_scsi_device(dev);			\	int val = simple_strtoul(buf, NULL, 0);				\	if (val == 0)							\		clear_bit(SDEV_EVT_##Cap_name, sdev->supported_events);	\	else if (val == 1)						\		set_bit(SDEV_EVT_##Cap_name, sdev->supported_events);	\	else								\		return -EINVAL;						\	return count;							\}#define DECLARE_EVT(name, Cap_name)					\	DECLARE_EVT_SHOW(name, Cap_name)				\	DECLARE_EVT_STORE(name, Cap_name)				\	static DEVICE_ATTR(evt_##name, S_IRUGO, sdev_show_evt_##name,	\			   sdev_store_evt_##name);#define REF_EVT(name) &dev_attr_evt_##name.attrDECLARE_EVT(media_change, MEDIA_CHANGE)/* Default template for device attributes.  May NOT be modified */static struct attribute *scsi_sdev_attrs[] = {	&dev_attr_device_blocked.attr,	&dev_attr_type.attr,	&dev_attr_scsi_level.attr,	&dev_attr_vendor.attr,	&dev_attr_model.attr,	&dev_attr_rev.attr,	&dev_attr_rescan.attr,	&dev_attr_delete.attr,	&dev_attr_state.attr,	&dev_attr_timeout.attr,	&dev_attr_iocounterbits.attr,	&dev_attr_iorequest_cnt.attr,	&dev_attr_iodone_cnt.attr,	&dev_attr_ioerr_cnt.attr,	&dev_attr_modalias.attr,	REF_EVT(media_change),	NULL};static struct attribute_group scsi_sdev_attr_group = {	.attrs =	scsi_sdev_attrs,};static struct attribute_group *scsi_sdev_attr_groups[] = {	&scsi_sdev_attr_group,	NULL};static ssize_t sdev_store_queue_depth_rw(struct device *dev, struct device_attribute *attr, const char *buf,					 size_t count){	int depth, retval;	struct scsi_device *sdev = to_scsi_device(dev);	struct scsi_host_template *sht = sdev->host->hostt;	if (!sht->change_queue_depth)		return -EINVAL;	depth = simple_strtoul(buf, NULL, 0);	if (depth < 1)		return -EINVAL;	retval = sht->change_queue_depth(sdev, depth);	if (retval < 0)		return retval;	return count;}static struct device_attribute sdev_attr_queue_depth_rw =	__ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,	       sdev_store_queue_depth_rw);static ssize_t sdev_store_queue_type_rw(struct device *dev, struct device_attribute *attr, const char *buf,					size_t count){	struct scsi_device *sdev = to_scsi_device(dev);	struct scsi_host_template *sht = sdev->host->hostt;	int tag_type = 0, retval;	int prev_tag_type = scsi_get_tag_type(sdev);	if (!sdev->tagged_supported || !sht->change_queue_type)		return -EINVAL;	if (strncmp(buf, "ordered", 7) == 0)		tag_type = MSG_ORDERED_TAG;	else if (strncmp(buf, "simple", 6) == 0)		tag_type = MSG_SIMPLE_TAG;	else if (strncmp(buf, "none", 4) != 0)		return -EINVAL;	if (tag_type == prev_tag_type)		return count;	retval = sht->change_queue_type(sdev, tag_type);	if (retval < 0)		return retval;	return count;}static struct device_attribute sdev_attr_queue_type_rw =	__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,	       sdev_store_queue_type_rw);/** * scsi_sysfs_add_sdev - add scsi device to sysfs * @sdev:	scsi_device to add * * Return value: * 	0 on Success / non-zero on Failure **/int scsi_sysfs_add_sdev(struct scsi_device *sdev){	int error, i;	struct request_queue *rq = sdev->request_queue;	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)		return error;	error = device_add(&sdev->sdev_gendev);	if (error) {		put_device(sdev->sdev_gendev.parent);		printk(KERN_INFO "error 1\n");		return error;	}	error = class_device_add(&sdev->sdev_classdev);	if (error) {		printk(KERN_INFO "error 2\n");		goto clean_device;	}	/* take a reference for the sdev_classdev; this is	 * released by the sdev_class .release */	get_device(&sdev->sdev_gendev);	/* create queue files, which may be writable, depending on the host */	if (sdev->host->hostt->change_queue_depth)		error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_depth_rw);	else		error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_depth);	if (error) {		__scsi_remove_device(sdev);		goto out;	}	if (sdev->host->hostt->change_queue_type)		error = device_create_file(&sdev->sdev_gendev, &sdev_attr_queue_type_rw);	else		error = device_create_file(&sdev->sdev_gendev, &dev_attr_queue_type);	if (error) {		__scsi_remove_device(sdev);		goto out;	}	error = bsg_register_queue(rq, &sdev->sdev_gendev, NULL);	if (error)		sdev_printk(KERN_INFO, sdev,			    "Failed to register bsg queue, errno=%d\n", error);	/* we're treating error on bsg register as non-fatal, so pretend	 * nothing went wrong */	error = 0;	/* add additional host specific attributes */	if (sdev->host->hostt->sdev_attrs) {		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {			error = device_create_file(&sdev->sdev_gendev,					sdev->host->hostt->sdev_attrs[i]);			if (error) {				__scsi_remove_device(sdev);				goto out;			}		}	}	transport_add_device(&sdev->sdev_gendev); out:	return error; clean_device:	scsi_device_set_state(sdev, SDEV_CANCEL);	device_del(&sdev->sdev_gendev);	transport_destroy_device(&sdev->sdev_gendev);	put_device(&sdev->sdev_gendev);	return error;}void __scsi_remove_device(struct scsi_device *sdev){	struct device *dev = &sdev->sdev_gendev;	if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)		return;	bsg_unregister_queue(sdev->request_queue);	class_device_unregister(&sdev->sdev_classdev);	transport_remove_device(dev);	device_del(dev);	scsi_device_set_state(sdev, SDEV_DEL);	if (sdev->host->hostt->slave_destroy)		sdev->host->hostt->slave_destroy(sdev);	transport_destroy_device(dev);	put_device(dev);}/** * scsi_remove_device - unregister a device from the scsi bus * @sdev:	scsi_device to unregister **/void scsi_remove_device(struct scsi_device *sdev){	struct Scsi_Host *shost = sdev->host;	mutex_lock(&shost->scan_mutex);	__scsi_remove_device(sdev);	mutex_unlock(&shost->scan_mutex);}EXPORT_SYMBOL(scsi_remove_device);static void __scsi_remove_target(struct scsi_target *starget){	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	unsigned long flags;	struct scsi_device *sdev;	spin_lock_irqsave(shost->host_lock, flags);	starget->reap_ref++; restart:	list_for_each_entry(sdev, &shost->__devices, siblings) {		if (sdev->channel != starget->channel ||		    sdev->id != starget->id ||		    sdev->sdev_state == SDEV_DEL)			continue;		spin_unlock_irqrestore(shost->host_lock, flags);		scsi_remove_device(sdev);		spin_lock_irqsave(shost->host_lock, flags);		goto restart;	}	spin_unlock_irqrestore(shost->host_lock, flags);	scsi_target_reap(starget);}static int __remove_child (struct device * dev, void * data){	if (scsi_is_target_device(dev))		__scsi_remove_target(to_scsi_target(dev));	return 0;}/** * scsi_remove_target - try to remove a target and all its devices * @dev: generic starget or parent of generic stargets to be removed * * Note: This is slightly racy.  It is possible that if the user * requests the addition of another device then the target won't be * removed. */void scsi_remove_target(struct device *dev){	struct device *rdev;	if (scsi_is_target_device(dev)) {		__scsi_remove_target(to_scsi_target(dev));		return;	}	rdev = get_device(dev);	device_for_each_child(dev, NULL, __remove_child);	put_device(rdev);}EXPORT_SYMBOL(scsi_remove_target);int scsi_register_driver(struct device_driver *drv){	drv->bus = &scsi_bus_type;	return driver_register(drv);}EXPORT_SYMBOL(scsi_register_driver);int scsi_register_interface(struct class_interface *intf){	intf->class = &sdev_class;	return class_interface_register(intf);}EXPORT_SYMBOL(scsi_register_interface);static struct class_device_attribute *class_attr_overridden(		struct class_device_attribute **attrs,		struct class_device_attribute *attr){	int i;	if (!attrs)		return NULL;	for (i = 0; attrs[i]; i++)		if (!strcmp(attrs[i]->attr.name, attr->attr.name))			return attrs[i];	return NULL;}static int class_attr_add(struct class_device *classdev,		struct class_device_attribute *attr){	struct class_device_attribute *base_attr;	/*	 * Spare the caller from having to copy things it's not interested in.	 */	base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr);	if (base_attr) {		/* extend permissions */		attr->attr.mode |= base_attr->attr.mode;		/* override null show/store with default */		if (!attr->show)			attr->show = base_attr->show;		if (!attr->store)			attr->store = base_attr->store;	}	return class_device_create_file(classdev, attr);}/** * scsi_sysfs_add_host - add scsi host to subsystem * @shost:     scsi host struct to add to subsystem * @dev:       parent struct device pointer **/int scsi_sysfs_add_host(struct Scsi_Host *shost){	int error, i;	if (shost->hostt->shost_attrs) {		for (i = 0; shost->hostt->shost_attrs[i]; i++) {			error = class_attr_add(&shost->shost_classdev,					shost->hostt->shost_attrs[i]);			if (error)				return error;		}	}	for (i = 0; scsi_sysfs_shost_attrs[i]; i++) {		if (!class_attr_overridden(shost->hostt->shost_attrs,					scsi_sysfs_shost_attrs[i])) {			error = class_device_create_file(&shost->shost_classdev,					scsi_sysfs_shost_attrs[i]);			if (error)				return error;		}	}	transport_register_device(&shost->shost_gendev);	return 0;}static struct device_type scsi_dev_type = {	.name =		"scsi_device",	.release =	scsi_device_dev_release,	.groups =	scsi_sdev_attr_groups,};void scsi_sysfs_device_initialize(struct scsi_device *sdev){	unsigned long flags;	struct Scsi_Host *shost = sdev->host;	struct scsi_target  *starget = sdev->sdev_target;	device_initialize(&sdev->sdev_gendev);	sdev->sdev_gendev.bus = &scsi_bus_type;	sdev->sdev_gendev.type = &scsi_dev_type;	sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",		sdev->host->host_no, sdev->channel, sdev->id,		sdev->lun);		class_device_initialize(&sdev->sdev_classdev);	sdev->sdev_classdev.dev = &sdev->sdev_gendev;	sdev->sdev_classdev.class = &sdev_class;	snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,		 "%d:%d:%d:%d", sdev->host->host_no,		 sdev->channel, sdev->id, sdev->lun);	sdev->scsi_level = starget->scsi_level;	transport_setup_device(&sdev->sdev_gendev);	spin_lock_irqsave(shost->host_lock, flags);	list_add_tail(&sdev->same_target_siblings, &starget->devices);	list_add_tail(&sdev->siblings, &shost->__devices);	spin_unlock_irqrestore(shost->host_lock, flags);}int scsi_is_sdev_device(const struct device *dev){	return dev->type == &scsi_dev_type;}EXPORT_SYMBOL(scsi_is_sdev_device);/* A blank transport template that is used in drivers that don't * yet implement Transport Attributes */struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, };

⌨️ 快捷键说明

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