[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