Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 106577
b: refs/heads/master
c: 765cbc6
h: refs/heads/master
i:
  106575: f4a578a
v: v3
  • Loading branch information
Hannes Reinecke authored and James Bottomley committed Jul 26, 2008
1 parent 6a59b8d commit 9f05962
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 220 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 6d49f63b415ca02223e01e187076cb69a5a38eaf
refs/heads/master: 765cbc6dad16b87724803e359d6be792ddf08614
202 changes: 170 additions & 32 deletions trunk/drivers/scsi/device_handler/scsi_dh.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ static struct scsi_device_handler *get_device_handler(const char *name)

spin_lock(&list_lock);
list_for_each_entry(tmp, &scsi_dh_list, list) {
if (!strcmp(tmp->name, name)) {
if (!strncmp(tmp->name, name, strlen(tmp->name))) {
found = tmp;
break;
}
Expand All @@ -42,50 +42,172 @@ static struct scsi_device_handler *get_device_handler(const char *name)
return found;
}

static int scsi_dh_notifier_add(struct device *dev, void *data)
static int device_handler_match(struct scsi_device_handler *tmp,
struct scsi_device *sdev)
{
struct scsi_device_handler *scsi_dh = data;
int i;

for(i = 0; tmp->devlist[i].vendor; i++) {
if (!strncmp(sdev->vendor, tmp->devlist[i].vendor,
strlen(tmp->devlist[i].vendor)) &&
!strncmp(sdev->model, tmp->devlist[i].model,
strlen(tmp->devlist[i].model))) {
return 1;
}
}

scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_ADD_DEVICE, dev);
return 0;
}

/*
* scsi_register_device_handler - register a device handler personality
* module.
* @scsi_dh - device handler to be registered.
* scsi_dh_handler_attach - Attach a device handler to a device
* @sdev - SCSI device the device handler should attach to
* @scsi_dh - The device handler to attach
*/
static int scsi_dh_handler_attach(struct scsi_device *sdev,
struct scsi_device_handler *scsi_dh)
{
int err = 0;

if (sdev->scsi_dh_data) {
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
err = -EBUSY;
} else if (scsi_dh->attach)
err = scsi_dh->attach(sdev);

return err;
}

/*
* scsi_dh_handler_detach - Detach a device handler from a device
* @sdev - SCSI device the device handler should be detached from
* @scsi_dh - Device handler to be detached
*
* Returns 0 on success, -EBUSY if handler already registered.
* Detach from a device handler. If a device handler is specified,
* only detach if the currently attached handler is equal to it.
*/
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
static void scsi_dh_handler_detach(struct scsi_device *sdev,
struct scsi_device_handler *scsi_dh)
{
int ret = -EBUSY;
struct scsi_device_handler *tmp;
if (!sdev->scsi_dh_data)
return;

tmp = get_device_handler(scsi_dh->name);
if (tmp)
goto done;
if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
return;

ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
if (!scsi_dh)
scsi_dh = sdev->scsi_dh_data->scsi_dh;

if (scsi_dh && scsi_dh->detach)
scsi_dh->detach(sdev);
}

/*
* scsi_dh_notifier - notifier chain callback
*/
static int scsi_dh_notifier(struct notifier_block *nb,
unsigned long action, void *data)
{
struct device *dev = data;
struct scsi_device *sdev;
int err = 0;
struct scsi_device_handler *tmp, *devinfo = NULL;

if (!scsi_is_sdev_device(dev))
return 0;

sdev = to_scsi_device(dev);

bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
spin_lock(&list_lock);
list_add(&scsi_dh->list, &scsi_dh_list);
list_for_each_entry(tmp, &scsi_dh_list, list) {
if (device_handler_match(tmp, sdev)) {
devinfo = tmp;
break;
}
}
spin_unlock(&list_lock);

done:
return ret;
if (!devinfo)
goto out;

if (action == BUS_NOTIFY_ADD_DEVICE) {
err = scsi_dh_handler_attach(sdev, devinfo);
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
scsi_dh_handler_detach(sdev, NULL);
}
out:
return err;
}
EXPORT_SYMBOL_GPL(scsi_register_device_handler);

/*
* scsi_dh_notifier_add - Callback for scsi_register_device_handler
*/
static int scsi_dh_notifier_add(struct device *dev, void *data)
{
struct scsi_device_handler *scsi_dh = data;
struct scsi_device *sdev;

if (!scsi_is_sdev_device(dev))
return 0;

if (!get_device(dev))
return 0;

sdev = to_scsi_device(dev);

if (device_handler_match(scsi_dh, sdev))
scsi_dh_handler_attach(sdev, scsi_dh);

put_device(dev);

return 0;
}

/*
* scsi_dh_notifier_remove - Callback for scsi_unregister_device_handler
*/
static int scsi_dh_notifier_remove(struct device *dev, void *data)
{
struct scsi_device_handler *scsi_dh = data;
struct scsi_device *sdev;

if (!scsi_is_sdev_device(dev))
return 0;

if (!get_device(dev))
return 0;

sdev = to_scsi_device(dev);

scsi_dh_handler_detach(sdev, scsi_dh);

put_device(dev);

scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
return 0;
}

/*
* scsi_register_device_handler - register a device handler personality
* module.
* @scsi_dh - device handler to be registered.
*
* Returns 0 on success, -EBUSY if handler already registered.
*/
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
{
if (get_device_handler(scsi_dh->name))
return -EBUSY;

spin_lock(&list_lock);
list_add(&scsi_dh->list, &scsi_dh_list);
spin_unlock(&list_lock);
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
printk(KERN_INFO "%s: device handler registered\n", scsi_dh->name);

return SCSI_DH_OK;
}
EXPORT_SYMBOL_GPL(scsi_register_device_handler);

/*
* scsi_unregister_device_handler - register a device handler personality
* module.
Expand All @@ -95,23 +217,18 @@ static int scsi_dh_notifier_remove(struct device *dev, void *data)
*/
int scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
{
int ret = -ENODEV;
struct scsi_device_handler *tmp;

tmp = get_device_handler(scsi_dh->name);
if (!tmp)
goto done;

ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
if (!get_device_handler(scsi_dh->name))
return -ENODEV;

bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
scsi_dh_notifier_remove);
scsi_dh_notifier_remove);

spin_lock(&list_lock);
list_del(&scsi_dh->list);
spin_unlock(&list_lock);
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);

done:
return ret;
return SCSI_DH_OK;
}
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);

Expand Down Expand Up @@ -157,6 +274,27 @@ int scsi_dh_handler_exist(const char *name)
}
EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);

static struct notifier_block scsi_dh_nb = {
.notifier_call = scsi_dh_notifier
};

static int __init scsi_dh_init(void)
{
int r;

r = bus_register_notifier(&scsi_bus_type, &scsi_dh_nb);

return r;
}

static void __exit scsi_dh_exit(void)
{
bus_unregister_notifier(&scsi_bus_type, &scsi_dh_nb);
}

module_init(scsi_dh_init);
module_exit(scsi_dh_exit);

MODULE_DESCRIPTION("SCSI device handler");
MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
MODULE_LICENSE("GPL");
Loading

0 comments on commit 9f05962

Please sign in to comment.