dasd_devmap.c

来自「LINUX 2.6.17.4的源码」· C语言 代码 · 共 944 行 · 第 1/2 页

C
944
字号
	spin_unlock(&dasd_devmap_lock);	return device;}/* * Return devmap for cdev. If no devmap exists yet, create one and * connect it to the cdev. */static struct dasd_devmap *dasd_devmap_from_cdev(struct ccw_device *cdev){	struct dasd_devmap *devmap;	devmap = dasd_find_busid(cdev->dev.bus_id);	if (IS_ERR(devmap))		devmap = dasd_add_busid(cdev->dev.bus_id,					DASD_FEATURE_DEFAULT);	return devmap;}/* * Create a dasd device structure for cdev. */struct dasd_device *dasd_create_device(struct ccw_device *cdev){	struct dasd_devmap *devmap;	struct dasd_device *device;	int rc;	devmap = dasd_devmap_from_cdev(cdev);	if (IS_ERR(devmap))		return (void *) devmap;	cdev->dev.driver_data = devmap;	device = dasd_alloc_device();	if (IS_ERR(device))		return device;	atomic_set(&device->ref_count, 2);	spin_lock(&dasd_devmap_lock);	if (!devmap->device) {		devmap->device = device;		device->devindex = devmap->devindex;		device->features = devmap->features;		get_device(&cdev->dev);		device->cdev = cdev;		rc = 0;	} else		/* Someone else was faster. */		rc = -EBUSY;	spin_unlock(&dasd_devmap_lock);	if (rc) {		dasd_free_device(device);		return ERR_PTR(rc);	}	return device;}/* * Wait queue for dasd_delete_device waits. */static DECLARE_WAIT_QUEUE_HEAD(dasd_delete_wq);/* * Remove a dasd device structure. The passed referenced * is destroyed. */voiddasd_delete_device(struct dasd_device *device){	struct ccw_device *cdev;	struct dasd_devmap *devmap;	/* First remove device pointer from devmap. */	devmap = dasd_find_busid(device->cdev->dev.bus_id);	BUG_ON(IS_ERR(devmap));	spin_lock(&dasd_devmap_lock);	if (devmap->device != device) {		spin_unlock(&dasd_devmap_lock);		dasd_put_device(device);		return;	}	devmap->device = NULL;	spin_unlock(&dasd_devmap_lock);	/* Drop ref_count by 2, one for the devmap reference and	 * one for the passed reference. */	atomic_sub(2, &device->ref_count);	/* Wait for reference counter to drop to zero. */	wait_event(dasd_delete_wq, atomic_read(&device->ref_count) == 0);	/* Disconnect dasd_device structure from ccw_device structure. */	cdev = device->cdev;	device->cdev = NULL;	/* Disconnect dasd_devmap structure from ccw_device structure. */	cdev->dev.driver_data = NULL;	/* Put ccw_device structure. */	put_device(&cdev->dev);	/* Now the device structure can be freed. */	dasd_free_device(device);}/* * Reference counter dropped to zero. Wake up waiter * in dasd_delete_device. */voiddasd_put_device_wake(struct dasd_device *device){	wake_up(&dasd_delete_wq);}/* * Return dasd_device structure associated with cdev. */struct dasd_device *dasd_device_from_cdev(struct ccw_device *cdev){	struct dasd_devmap *devmap;	struct dasd_device *device;	device = ERR_PTR(-ENODEV);	spin_lock(&dasd_devmap_lock);	devmap = cdev->dev.driver_data;	if (devmap && devmap->device) {		device = devmap->device;		dasd_get_device(device);	}	spin_unlock(&dasd_devmap_lock);	return device;}/* * SECTION: files in sysfs *//* * readonly controls the readonly status of a dasd */static ssize_tdasd_ro_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	int ro_flag;	devmap = dasd_find_busid(dev->bus_id);	if (!IS_ERR(devmap))		ro_flag = (devmap->features & DASD_FEATURE_READONLY) != 0;	else		ro_flag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_READONLY) != 0;	return snprintf(buf, PAGE_SIZE, ro_flag ? "1\n" : "0\n");}static ssize_tdasd_ro_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct dasd_devmap *devmap;	int ro_flag;	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));	if (IS_ERR(devmap))		return PTR_ERR(devmap);	ro_flag = buf[0] == '1';	spin_lock(&dasd_devmap_lock);	if (ro_flag)		devmap->features |= DASD_FEATURE_READONLY;	else		devmap->features &= ~DASD_FEATURE_READONLY;	if (devmap->device)		devmap->device->features = devmap->features;	if (devmap->device && devmap->device->gdp)		set_disk_ro(devmap->device->gdp, ro_flag);	spin_unlock(&dasd_devmap_lock);	return count;}static DEVICE_ATTR(readonly, 0644, dasd_ro_show, dasd_ro_store);/* * use_diag controls whether the driver should use diag rather than ssch * to talk to the device */static ssize_t dasd_use_diag_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	int use_diag;	devmap = dasd_find_busid(dev->bus_id);	if (!IS_ERR(devmap))		use_diag = (devmap->features & DASD_FEATURE_USEDIAG) != 0;	else		use_diag = (DASD_FEATURE_DEFAULT & DASD_FEATURE_USEDIAG) != 0;	return sprintf(buf, use_diag ? "1\n" : "0\n");}static ssize_tdasd_use_diag_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct dasd_devmap *devmap;	ssize_t rc;	int use_diag;	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));	if (IS_ERR(devmap))		return PTR_ERR(devmap);	use_diag = buf[0] == '1';	spin_lock(&dasd_devmap_lock);	/* Changing diag discipline flag is only allowed in offline state. */	rc = count;	if (!devmap->device) {		if (use_diag)			devmap->features |= DASD_FEATURE_USEDIAG;		else			devmap->features &= ~DASD_FEATURE_USEDIAG;	} else		rc = -EPERM;	spin_unlock(&dasd_devmap_lock);	return rc;}staticDEVICE_ATTR(use_diag, 0644, dasd_use_diag_show, dasd_use_diag_store);static ssize_tdasd_discipline_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	char *dname;	spin_lock(&dasd_devmap_lock);	dname = "none";	devmap = dev->driver_data;	if (devmap && devmap->device && devmap->device->discipline)		dname = devmap->device->discipline->name;	spin_unlock(&dasd_devmap_lock);	return snprintf(buf, PAGE_SIZE, "%s\n", dname);}static DEVICE_ATTR(discipline, 0444, dasd_discipline_show, NULL);static ssize_tdasd_alias_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	int alias;	devmap = dasd_find_busid(dev->bus_id);	spin_lock(&dasd_devmap_lock);	if (!IS_ERR(devmap))		alias = devmap->uid.alias;	else		alias = 0;	spin_unlock(&dasd_devmap_lock);	return sprintf(buf, alias ? "1\n" : "0\n");}static DEVICE_ATTR(alias, 0444, dasd_alias_show, NULL);static ssize_tdasd_vendor_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	char *vendor;	devmap = dasd_find_busid(dev->bus_id);	spin_lock(&dasd_devmap_lock);	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)		vendor = devmap->uid.vendor;	else		vendor = "";	spin_unlock(&dasd_devmap_lock);	return snprintf(buf, PAGE_SIZE, "%s\n", vendor);}static DEVICE_ATTR(vendor, 0444, dasd_vendor_show, NULL);#define UID_STRLEN ( /* vendor */ 3 + 1 + /* serial    */ 14 + 1 +\		     /* SSID   */ 4 + 1 + /* unit addr */ 2 + 1)static ssize_tdasd_uid_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	char uid[UID_STRLEN];	devmap = dasd_find_busid(dev->bus_id);	spin_lock(&dasd_devmap_lock);	if (!IS_ERR(devmap) && strlen(devmap->uid.vendor) > 0)		snprintf(uid, sizeof(uid), "%s.%s.%04x.%02x",			 devmap->uid.vendor, devmap->uid.serial,			 devmap->uid.ssid, devmap->uid.unit_addr);	else		uid[0] = 0;	spin_unlock(&dasd_devmap_lock);	return snprintf(buf, PAGE_SIZE, "%s\n", uid);}static DEVICE_ATTR(uid, 0444, dasd_uid_show, NULL);/* * extended error-reporting */static ssize_tdasd_eer_show(struct device *dev, struct device_attribute *attr, char *buf){	struct dasd_devmap *devmap;	int eer_flag;	devmap = dasd_find_busid(dev->bus_id);	if (!IS_ERR(devmap) && devmap->device)		eer_flag = dasd_eer_enabled(devmap->device);	else		eer_flag = 0;	return snprintf(buf, PAGE_SIZE, eer_flag ? "1\n" : "0\n");}static ssize_tdasd_eer_store(struct device *dev, struct device_attribute *attr,	       const char *buf, size_t count){	struct dasd_devmap *devmap;	int rc;	devmap = dasd_devmap_from_cdev(to_ccwdev(dev));	if (IS_ERR(devmap))		return PTR_ERR(devmap);	if (!devmap->device)		return count;	if (buf[0] == '1') {		rc = dasd_eer_enable(devmap->device);		if (rc)			return rc;	} else		dasd_eer_disable(devmap->device);	return count;}static DEVICE_ATTR(eer_enabled, 0644, dasd_eer_show, dasd_eer_store);static struct attribute * dasd_attrs[] = {	&dev_attr_readonly.attr,	&dev_attr_discipline.attr,	&dev_attr_alias.attr,	&dev_attr_vendor.attr,	&dev_attr_uid.attr,	&dev_attr_use_diag.attr,	&dev_attr_eer_enabled.attr,	NULL,};static struct attribute_group dasd_attr_group = {	.attrs = dasd_attrs,};/* * Return copy of the device unique identifier. */intdasd_get_uid(struct ccw_device *cdev, struct dasd_uid *uid){	struct dasd_devmap *devmap;	devmap = dasd_find_busid(cdev->dev.bus_id);	if (IS_ERR(devmap))		return PTR_ERR(devmap);	spin_lock(&dasd_devmap_lock);	*uid = devmap->uid;	spin_unlock(&dasd_devmap_lock);	return 0;}/* * Register the given device unique identifier into devmap struct. */intdasd_set_uid(struct ccw_device *cdev, struct dasd_uid *uid){	struct dasd_devmap *devmap;	devmap = dasd_find_busid(cdev->dev.bus_id);	if (IS_ERR(devmap))		return PTR_ERR(devmap);	spin_lock(&dasd_devmap_lock);	devmap->uid = *uid;	spin_unlock(&dasd_devmap_lock);	return 0;}EXPORT_SYMBOL(dasd_set_uid);/* * Return value of the specified feature. */intdasd_get_feature(struct ccw_device *cdev, int feature){	struct dasd_devmap *devmap;	devmap = dasd_find_busid(cdev->dev.bus_id);	if (IS_ERR(devmap))		return (int) PTR_ERR(devmap);	return ((devmap->features & feature) != 0);}/* * Set / reset given feature. * Flag indicates wether to set (!=0) or the reset (=0) the feature. */intdasd_set_feature(struct ccw_device *cdev, int feature, int flag){	struct dasd_devmap *devmap;	devmap = dasd_find_busid(cdev->dev.bus_id);	if (IS_ERR(devmap))		return (int) PTR_ERR(devmap);	spin_lock(&dasd_devmap_lock);	if (flag)		devmap->features |= feature;	else		devmap->features &= ~feature;	if (devmap->device)		devmap->device->features = devmap->features;	spin_unlock(&dasd_devmap_lock);	return 0;}intdasd_add_sysfs_files(struct ccw_device *cdev){	return sysfs_create_group(&cdev->dev.kobj, &dasd_attr_group);}voiddasd_remove_sysfs_files(struct ccw_device *cdev){	sysfs_remove_group(&cdev->dev.kobj, &dasd_attr_group);}intdasd_devmap_init(void){	int i;	/* Initialize devmap structures. */	dasd_max_devindex = 0;	for (i = 0; i < 256; i++)		INIT_LIST_HEAD(&dasd_hashlists[i]);	return 0;}voiddasd_devmap_exit(void){	dasd_forget_ranges();}

⌨️ 快捷键说明

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