[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
|
@ -332,19 +332,25 @@ EXPORT_SYMBOL_GPL(enclosure_add_device);
|
|||
* 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;
|
||||
int i;
|
||||
|
||||
if (!edev || component >= edev->components)
|
||||
if (!edev || !dev)
|
||||
return -EINVAL;
|
||||
|
||||
cdev = &edev->component[component];
|
||||
|
||||
device_del(&cdev->cdev);
|
||||
put_device(cdev->dev);
|
||||
cdev->dev = NULL;
|
||||
return device_add(&cdev->cdev);
|
||||
for (i = 0; i < edev->components; i++) {
|
||||
cdev = &edev->component[i];
|
||||
if (cdev->dev == dev) {
|
||||
enclosure_remove_links(cdev);
|
||||
device_del(&cdev->cdev);
|
||||
put_device(dev);
|
||||
cdev->dev = NULL;
|
||||
return device_add(&cdev->cdev);
|
||||
}
|
||||
}
|
||||
return -ENODEV;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(enclosure_remove_device);
|
||||
|
||||
|
|
|
@ -616,18 +616,26 @@ static int ses_remove(struct device *dev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void ses_intf_remove(struct device *cdev,
|
||||
struct class_interface *intf)
|
||||
static void ses_intf_remove_component(struct scsi_device *sdev)
|
||||
{
|
||||
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 ses_device *ses_dev;
|
||||
|
||||
if (!scsi_device_enclosure(sdev))
|
||||
return;
|
||||
|
||||
/* exact match to this enclosure */
|
||||
edev = enclosure_find(cdev->parent, NULL);
|
||||
edev = enclosure_find(&sdev->sdev_gendev, NULL);
|
||||
if (!edev)
|
||||
return;
|
||||
|
||||
|
@ -645,6 +653,17 @@ static void ses_intf_remove(struct device *cdev,
|
|||
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 = {
|
||||
.add_dev = ses_intf_add,
|
||||
.remove_dev = ses_intf_remove,
|
||||
|
|
|
@ -122,7 +122,7 @@ enclosure_component_register(struct enclosure_device *, unsigned int,
|
|||
enum enclosure_component_type, const char *);
|
||||
int enclosure_add_device(struct enclosure_device *enclosure, int component,
|
||||
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 *start);
|
||||
int enclosure_for_each_device(int (*fn)(struct enclosure_device *, void *),
|
||||
|
|
Loading…
Reference in New Issue
Block a user