forked from mirrors/linux
		
	[SCSI] ses: add support for enclosure component hot removal
Right at the moment, hot removal of a device within an enclosure does nothing (because the intf_remove only copes with enclosure removal not with component removal). Fix this by adding a function to remove the component. Also needed to fix the prototype of enclosure_remove_device, since we know the device we've removed but not the internal component number Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
		
							parent
							
								
									163f52b6cf
								
							
						
					
					
						commit
						43d8eb9cfd
					
				
					 3 changed files with 41 additions and 16 deletions
				
			
		|  | @ -332,19 +332,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device); | ||||||
|  * Returns zero on success or an error. |  * Returns zero on success or an error. | ||||||
|  * |  * | ||||||
|  */ |  */ | ||||||
| int enclosure_remove_device(struct enclosure_device *edev, int component) | int enclosure_remove_device(struct enclosure_device *edev, struct device *dev) | ||||||
| { | { | ||||||
| 	struct enclosure_component *cdev; | 	struct enclosure_component *cdev; | ||||||
|  | 	int i; | ||||||
| 
 | 
 | ||||||
| 	if (!edev || component >= edev->components) | 	if (!edev || !dev) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	cdev = &edev->component[component]; | 	for (i = 0; i < edev->components; i++) { | ||||||
| 
 | 		cdev = &edev->component[i]; | ||||||
| 	device_del(&cdev->cdev); | 		if (cdev->dev == dev) { | ||||||
| 	put_device(cdev->dev); | 			enclosure_remove_links(cdev); | ||||||
| 	cdev->dev = NULL; | 			device_del(&cdev->cdev); | ||||||
| 	return device_add(&cdev->cdev); | 			put_device(dev); | ||||||
|  | 			cdev->dev = NULL; | ||||||
|  | 			return device_add(&cdev->cdev); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	return -ENODEV; | ||||||
| } | } | ||||||
| EXPORT_SYMBOL_GPL(enclosure_remove_device); | EXPORT_SYMBOL_GPL(enclosure_remove_device); | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -616,18 +616,26 @@ static int ses_remove(struct device *dev) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void ses_intf_remove(struct device *cdev, | static void ses_intf_remove_component(struct scsi_device *sdev) | ||||||
| 			    struct class_interface *intf) | { | ||||||
|  | 	struct enclosure_device *edev, *prev = NULL; | ||||||
|  | 
 | ||||||
|  | 	while ((edev = enclosure_find(&sdev->host->shost_gendev, prev)) != NULL) { | ||||||
|  | 		prev = edev; | ||||||
|  | 		if (!enclosure_remove_device(edev, &sdev->sdev_gendev)) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 	if (edev) | ||||||
|  | 		put_device(&edev->edev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void ses_intf_remove_enclosure(struct scsi_device *sdev) | ||||||
| { | { | ||||||
| 	struct scsi_device *sdev = to_scsi_device(cdev->parent); |  | ||||||
| 	struct enclosure_device *edev; | 	struct enclosure_device *edev; | ||||||
| 	struct ses_device *ses_dev; | 	struct ses_device *ses_dev; | ||||||
| 
 | 
 | ||||||
| 	if (!scsi_device_enclosure(sdev)) |  | ||||||
| 		return; |  | ||||||
| 
 |  | ||||||
| 	/*  exact match to this enclosure */ | 	/*  exact match to this enclosure */ | ||||||
| 	edev = enclosure_find(cdev->parent, NULL); | 	edev = enclosure_find(&sdev->sdev_gendev, NULL); | ||||||
| 	if (!edev) | 	if (!edev) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | @ -645,6 +653,17 @@ static void ses_intf_remove(struct device *cdev, | ||||||
| 	enclosure_unregister(edev); | 	enclosure_unregister(edev); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static void ses_intf_remove(struct device *cdev, | ||||||
|  | 			    struct class_interface *intf) | ||||||
|  | { | ||||||
|  | 	struct scsi_device *sdev = to_scsi_device(cdev->parent); | ||||||
|  | 
 | ||||||
|  | 	if (!scsi_device_enclosure(sdev)) | ||||||
|  | 		ses_intf_remove_component(sdev); | ||||||
|  | 	else | ||||||
|  | 		ses_intf_remove_enclosure(sdev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static struct class_interface ses_interface = { | static struct class_interface ses_interface = { | ||||||
| 	.add_dev	= ses_intf_add, | 	.add_dev	= ses_intf_add, | ||||||
| 	.remove_dev	= ses_intf_remove, | 	.remove_dev	= ses_intf_remove, | ||||||
|  |  | ||||||
|  | @ -122,7 +122,7 @@ enclosure_component_register(struct enclosure_device *, unsigned int, | ||||||
| 				 enum enclosure_component_type, const char *); | 				 enum enclosure_component_type, const char *); | ||||||
| int enclosure_add_device(struct enclosure_device *enclosure, int component, | int enclosure_add_device(struct enclosure_device *enclosure, int component, | ||||||
| 			 struct device *dev); | 			 struct device *dev); | ||||||
| int enclosure_remove_device(struct enclosure_device *enclosure, int component); | int enclosure_remove_device(struct enclosure_device *, struct device *); | ||||||
| struct enclosure_device *enclosure_find(struct device *dev, | struct enclosure_device *enclosure_find(struct device *dev, | ||||||
| 					struct enclosure_device *start); | 					struct enclosure_device *start); | ||||||
| int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), | int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *), | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 James Bottomley
						James Bottomley