[SCSI] scsi_dh: Implement common device table handling
Instead of having each and every driver implement its own device table scanning code we should rather implement a common routine and scan the device tables there. This allows us also to implement a general notifier chain callback for all device handler instead for one per handler. [sekharan: Fix rejections caused by conflicting bug fix] Signed-off-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Chandra Seetharaman <sekharan@us.ibm.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
This commit is contained in:
committed by
James Bottomley
parent
6d49f63b41
commit
765cbc6dad
@@ -33,7 +33,7 @@ static struct scsi_device_handler *get_device_handler(const char *name)
|
|||||||
|
|
||||||
spin_lock(&list_lock);
|
spin_lock(&list_lock);
|
||||||
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
||||||
if (!strcmp(tmp->name, name)) {
|
if (!strncmp(tmp->name, name, strlen(tmp->name))) {
|
||||||
found = tmp;
|
found = tmp;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -42,11 +42,147 @@ static struct scsi_device_handler *get_device_handler(const char *name)
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int device_handler_match(struct scsi_device_handler *tmp,
|
||||||
|
struct scsi_device *sdev)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*
|
||||||
|
* Detach from a device handler. If a device handler is specified,
|
||||||
|
* only detach if the currently attached handler is equal to it.
|
||||||
|
*/
|
||||||
|
static void scsi_dh_handler_detach(struct scsi_device *sdev,
|
||||||
|
struct scsi_device_handler *scsi_dh)
|
||||||
|
{
|
||||||
|
if (!sdev->scsi_dh_data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (scsi_dh && scsi_dh != sdev->scsi_dh_data->scsi_dh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
spin_lock(&list_lock);
|
||||||
|
list_for_each_entry(tmp, &scsi_dh_list, list) {
|
||||||
|
if (device_handler_match(tmp, sdev)) {
|
||||||
|
devinfo = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock(&list_lock);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* scsi_dh_notifier_add - Callback for scsi_register_device_handler
|
||||||
|
*/
|
||||||
static int scsi_dh_notifier_add(struct device *dev, void *data)
|
static int scsi_dh_notifier_add(struct device *dev, void *data)
|
||||||
{
|
{
|
||||||
struct scsi_device_handler *scsi_dh = 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_ADD_DEVICE, dev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,33 +195,19 @@ static int scsi_dh_notifier_add(struct device *dev, void *data)
|
|||||||
*/
|
*/
|
||||||
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
|
||||||
{
|
{
|
||||||
int ret = -EBUSY;
|
if (get_device_handler(scsi_dh->name))
|
||||||
struct scsi_device_handler *tmp;
|
return -EBUSY;
|
||||||
|
|
||||||
tmp = get_device_handler(scsi_dh->name);
|
|
||||||
if (tmp)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
ret = bus_register_notifier(&scsi_bus_type, &scsi_dh->nb);
|
|
||||||
|
|
||||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh, scsi_dh_notifier_add);
|
|
||||||
spin_lock(&list_lock);
|
spin_lock(&list_lock);
|
||||||
list_add(&scsi_dh->list, &scsi_dh_list);
|
list_add(&scsi_dh->list, &scsi_dh_list);
|
||||||
spin_unlock(&list_lock);
|
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);
|
||||||
|
|
||||||
done:
|
return SCSI_DH_OK;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(scsi_register_device_handler);
|
EXPORT_SYMBOL_GPL(scsi_register_device_handler);
|
||||||
|
|
||||||
static int scsi_dh_notifier_remove(struct device *dev, void *data)
|
|
||||||
{
|
|
||||||
struct scsi_device_handler *scsi_dh = data;
|
|
||||||
|
|
||||||
scsi_dh->nb.notifier_call(&scsi_dh->nb, BUS_NOTIFY_DEL_DEVICE, dev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scsi_unregister_device_handler - register a device handler personality
|
* scsi_unregister_device_handler - register a device handler personality
|
||||||
* module.
|
* module.
|
||||||
@@ -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 scsi_unregister_device_handler(struct scsi_device_handler *scsi_dh)
|
||||||
{
|
{
|
||||||
int ret = -ENODEV;
|
if (!get_device_handler(scsi_dh->name))
|
||||||
struct scsi_device_handler *tmp;
|
return -ENODEV;
|
||||||
|
|
||||||
tmp = get_device_handler(scsi_dh->name);
|
|
||||||
if (!tmp)
|
|
||||||
goto done;
|
|
||||||
|
|
||||||
ret = bus_unregister_notifier(&scsi_bus_type, &scsi_dh->nb);
|
|
||||||
|
|
||||||
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
|
bus_for_each_dev(&scsi_bus_type, NULL, scsi_dh,
|
||||||
scsi_dh_notifier_remove);
|
scsi_dh_notifier_remove);
|
||||||
|
|
||||||
spin_lock(&list_lock);
|
spin_lock(&list_lock);
|
||||||
list_del(&scsi_dh->list);
|
list_del(&scsi_dh->list);
|
||||||
spin_unlock(&list_lock);
|
spin_unlock(&list_lock);
|
||||||
|
printk(KERN_INFO "%s: device handler unregistered\n", scsi_dh->name);
|
||||||
|
|
||||||
done:
|
return SCSI_DH_OK;
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
|
EXPORT_SYMBOL_GPL(scsi_unregister_device_handler);
|
||||||
|
|
||||||
@@ -157,6 +274,27 @@ int scsi_dh_handler_exist(const char *name)
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(scsi_dh_handler_exist);
|
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_DESCRIPTION("SCSI device handler");
|
||||||
MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
|
MODULE_AUTHOR("Chandra Seetharaman <sekharan@us.ibm.com>");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
@@ -238,12 +238,12 @@ done:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get block request for REQ_BLOCK_PC command issued to path. Currently
|
* Get block request for REQ_BLOCK_PC command issued to path. Currently
|
||||||
* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
|
* limited to MODE_SELECT (trespass) and INQUIRY (VPD page 0xC0) commands.
|
||||||
*
|
*
|
||||||
* Uses data and sense buffers in hardware handler context structure and
|
* Uses data and sense buffers in hardware handler context structure and
|
||||||
* assumes serial servicing of commands, both issuance and completion.
|
* assumes serial servicing of commands, both issuance and completion.
|
||||||
*/
|
*/
|
||||||
static struct request *get_req(struct scsi_device *sdev, int cmd)
|
static struct request *get_req(struct scsi_device *sdev, int cmd)
|
||||||
{
|
{
|
||||||
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
struct clariion_dh_data *csdev = get_clariion_data(sdev);
|
||||||
@@ -390,21 +390,21 @@ static int clariion_check_sense(struct scsi_device *sdev,
|
|||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
const struct scsi_dh_devlist clariion_dev_list[] = {
|
||||||
char *vendor;
|
|
||||||
char *model;
|
|
||||||
} clariion_dev_list[] = {
|
|
||||||
{"DGC", "RAID"},
|
{"DGC", "RAID"},
|
||||||
{"DGC", "DISK"},
|
{"DGC", "DISK"},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int clariion_bus_notify(struct notifier_block *, unsigned long, void *);
|
static int clariion_bus_attach(struct scsi_device *sdev);
|
||||||
|
static void clariion_bus_detach(struct scsi_device *sdev);
|
||||||
|
|
||||||
static struct scsi_device_handler clariion_dh = {
|
static struct scsi_device_handler clariion_dh = {
|
||||||
.name = CLARIION_NAME,
|
.name = CLARIION_NAME,
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.nb.notifier_call = clariion_bus_notify,
|
.devlist = clariion_dev_list,
|
||||||
|
.attach = clariion_bus_attach,
|
||||||
|
.detach = clariion_bus_detach,
|
||||||
.check_sense = clariion_check_sense,
|
.check_sense = clariion_check_sense,
|
||||||
.activate = clariion_activate,
|
.activate = clariion_activate,
|
||||||
};
|
};
|
||||||
@@ -412,75 +412,52 @@ static struct scsi_device_handler clariion_dh = {
|
|||||||
/*
|
/*
|
||||||
* TODO: need some interface so we can set trespass values
|
* TODO: need some interface so we can set trespass values
|
||||||
*/
|
*/
|
||||||
static int clariion_bus_notify(struct notifier_block *nb,
|
static int clariion_bus_attach(struct scsi_device *sdev)
|
||||||
unsigned long action, void *data)
|
|
||||||
{
|
{
|
||||||
struct device *dev = data;
|
|
||||||
struct scsi_device *sdev;
|
|
||||||
struct scsi_dh_data *scsi_dh_data;
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
struct clariion_dh_data *h;
|
struct clariion_dh_data *h;
|
||||||
int i, found = 0;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!scsi_is_sdev_device(dev))
|
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||||
return 0;
|
+ sizeof(*h) , GFP_KERNEL);
|
||||||
|
if (!scsi_dh_data) {
|
||||||
sdev = to_scsi_device(dev);
|
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
||||||
|
|
||||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
|
||||||
for (i = 0; clariion_dev_list[i].vendor; i++) {
|
|
||||||
if (!strncmp(sdev->vendor, clariion_dev_list[i].vendor,
|
|
||||||
strlen(clariion_dev_list[i].vendor)) &&
|
|
||||||
!strncmp(sdev->model, clariion_dev_list[i].model,
|
|
||||||
strlen(clariion_dev_list[i].model))) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
|
||||||
+ sizeof(*h) , GFP_KERNEL);
|
|
||||||
if (!scsi_dh_data) {
|
|
||||||
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
|
||||||
CLARIION_NAME);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_dh_data->scsi_dh = &clariion_dh;
|
|
||||||
h = (struct clariion_dh_data *) scsi_dh_data->buf;
|
|
||||||
h->default_sp = CLARIION_UNBOUND_LU;
|
|
||||||
h->current_sp = CLARIION_UNBOUND_LU;
|
|
||||||
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
sdev->scsi_dh_data = scsi_dh_data;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
|
|
||||||
try_module_get(THIS_MODULE);
|
|
||||||
|
|
||||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
|
||||||
if (sdev->scsi_dh_data == NULL ||
|
|
||||||
sdev->scsi_dh_data->scsi_dh != &clariion_dh)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
scsi_dh_data = sdev->scsi_dh_data;
|
|
||||||
sdev->scsi_dh_data = NULL;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n",
|
|
||||||
CLARIION_NAME);
|
CLARIION_NAME);
|
||||||
|
return -ENOMEM;
|
||||||
kfree(scsi_dh_data);
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
scsi_dh_data->scsi_dh = &clariion_dh;
|
||||||
|
h = (struct clariion_dh_data *) scsi_dh_data->buf;
|
||||||
|
h->default_sp = CLARIION_UNBOUND_LU;
|
||||||
|
h->current_sp = CLARIION_UNBOUND_LU;
|
||||||
|
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
sdev->scsi_dh_data = scsi_dh_data;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", CLARIION_NAME);
|
||||||
|
try_module_get(THIS_MODULE);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clariion_bus_detach(struct scsi_device *sdev)
|
||||||
|
{
|
||||||
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
scsi_dh_data = sdev->scsi_dh_data;
|
||||||
|
sdev->scsi_dh_data = NULL;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Detached %s.\n",
|
||||||
|
CLARIION_NAME);
|
||||||
|
|
||||||
|
kfree(scsi_dh_data);
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
}
|
||||||
|
|
||||||
static int __init clariion_init(void)
|
static int __init clariion_init(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@@ -108,87 +108,65 @@ done:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
|
||||||
char *vendor;
|
|
||||||
char *model;
|
|
||||||
} hp_sw_dh_data_list[] = {
|
|
||||||
{"COMPAQ", "MSA"},
|
{"COMPAQ", "MSA"},
|
||||||
{"HP", "HSV"},
|
{"HP", "HSV"},
|
||||||
{"DEC", "HSG80"},
|
{"DEC", "HSG80"},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int hp_sw_bus_notify(struct notifier_block *, unsigned long, void *);
|
static int hp_sw_bus_attach(struct scsi_device *sdev);
|
||||||
|
static void hp_sw_bus_detach(struct scsi_device *sdev);
|
||||||
|
|
||||||
static struct scsi_device_handler hp_sw_dh = {
|
static struct scsi_device_handler hp_sw_dh = {
|
||||||
.name = HP_SW_NAME,
|
.name = HP_SW_NAME,
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.nb.notifier_call = hp_sw_bus_notify,
|
.devlist = hp_sw_dh_data_list,
|
||||||
|
.attach = hp_sw_bus_attach,
|
||||||
|
.detach = hp_sw_bus_detach,
|
||||||
.activate = hp_sw_activate,
|
.activate = hp_sw_activate,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int hp_sw_bus_notify(struct notifier_block *nb,
|
static int hp_sw_bus_attach(struct scsi_device *sdev)
|
||||||
unsigned long action, void *data)
|
|
||||||
{
|
{
|
||||||
struct device *dev = data;
|
|
||||||
struct scsi_device *sdev;
|
|
||||||
struct scsi_dh_data *scsi_dh_data;
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
int i, found = 0;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!scsi_is_sdev_device(dev))
|
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||||
|
+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
|
||||||
|
if (!scsi_dh_data) {
|
||||||
|
sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
|
||||||
|
HP_SW_NAME);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdev = to_scsi_device(dev);
|
|
||||||
|
|
||||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
|
||||||
for (i = 0; hp_sw_dh_data_list[i].vendor; i++) {
|
|
||||||
if (!strncmp(sdev->vendor, hp_sw_dh_data_list[i].vendor,
|
|
||||||
strlen(hp_sw_dh_data_list[i].vendor)) &&
|
|
||||||
!strncmp(sdev->model, hp_sw_dh_data_list[i].model,
|
|
||||||
strlen(hp_sw_dh_data_list[i].model))) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
|
||||||
+ sizeof(struct hp_sw_dh_data) , GFP_KERNEL);
|
|
||||||
if (!scsi_dh_data) {
|
|
||||||
sdev_printk(KERN_ERR, sdev, "Attach Failed %s.\n",
|
|
||||||
HP_SW_NAME);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_dh_data->scsi_dh = &hp_sw_dh;
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
sdev->scsi_dh_data = scsi_dh_data;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
try_module_get(THIS_MODULE);
|
|
||||||
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
|
|
||||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
|
||||||
if (sdev->scsi_dh_data == NULL ||
|
|
||||||
sdev->scsi_dh_data->scsi_dh != &hp_sw_dh)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
scsi_dh_data = sdev->scsi_dh_data;
|
|
||||||
sdev->scsi_dh_data = NULL;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", HP_SW_NAME);
|
|
||||||
|
|
||||||
kfree(scsi_dh_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
scsi_dh_data->scsi_dh = &hp_sw_dh;
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
sdev->scsi_dh_data = scsi_dh_data;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
try_module_get(THIS_MODULE);
|
||||||
|
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", HP_SW_NAME);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hp_sw_bus_detach( struct scsi_device *sdev )
|
||||||
|
{
|
||||||
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
scsi_dh_data = sdev->scsi_dh_data;
|
||||||
|
sdev->scsi_dh_data = NULL;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", HP_SW_NAME);
|
||||||
|
|
||||||
|
kfree(scsi_dh_data);
|
||||||
|
}
|
||||||
|
|
||||||
static int __init hp_sw_init(void)
|
static int __init hp_sw_init(void)
|
||||||
{
|
{
|
||||||
return scsi_register_device_handler(&hp_sw_dh);
|
return scsi_register_device_handler(&hp_sw_dh);
|
||||||
|
@@ -569,10 +569,7 @@ static int rdac_check_sense(struct scsi_device *sdev,
|
|||||||
return SCSI_RETURN_NOT_HANDLED;
|
return SCSI_RETURN_NOT_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct {
|
const struct scsi_dh_devlist rdac_dev_list[] = {
|
||||||
char *vendor;
|
|
||||||
char *model;
|
|
||||||
} rdac_dev_list[] = {
|
|
||||||
{"IBM", "1722"},
|
{"IBM", "1722"},
|
||||||
{"IBM", "1724"},
|
{"IBM", "1724"},
|
||||||
{"IBM", "1726"},
|
{"IBM", "1726"},
|
||||||
@@ -590,89 +587,69 @@ static const struct {
|
|||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rdac_bus_notify(struct notifier_block *, unsigned long, void *);
|
static int rdac_bus_attach(struct scsi_device *sdev);
|
||||||
|
static void rdac_bus_detach(struct scsi_device *sdev);
|
||||||
|
|
||||||
static struct scsi_device_handler rdac_dh = {
|
static struct scsi_device_handler rdac_dh = {
|
||||||
.name = RDAC_NAME,
|
.name = RDAC_NAME,
|
||||||
.module = THIS_MODULE,
|
.module = THIS_MODULE,
|
||||||
.nb.notifier_call = rdac_bus_notify,
|
.devlist = rdac_dev_list,
|
||||||
.prep_fn = rdac_prep_fn,
|
.prep_fn = rdac_prep_fn,
|
||||||
.check_sense = rdac_check_sense,
|
.check_sense = rdac_check_sense,
|
||||||
|
.attach = rdac_bus_attach,
|
||||||
|
.detach = rdac_bus_detach,
|
||||||
.activate = rdac_activate,
|
.activate = rdac_activate,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
static int rdac_bus_attach(struct scsi_device *sdev)
|
||||||
* TODO: need some interface so we can set trespass values
|
|
||||||
*/
|
|
||||||
static int rdac_bus_notify(struct notifier_block *nb,
|
|
||||||
unsigned long action, void *data)
|
|
||||||
{
|
{
|
||||||
struct device *dev = data;
|
|
||||||
struct scsi_device *sdev;
|
|
||||||
struct scsi_dh_data *scsi_dh_data;
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
struct rdac_dh_data *h;
|
struct rdac_dh_data *h;
|
||||||
int i, found = 0;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
if (!scsi_is_sdev_device(dev))
|
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
||||||
|
+ sizeof(*h) , GFP_KERNEL);
|
||||||
|
if (!scsi_dh_data) {
|
||||||
|
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
||||||
|
RDAC_NAME);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
sdev = to_scsi_device(dev);
|
|
||||||
|
|
||||||
if (action == BUS_NOTIFY_ADD_DEVICE) {
|
|
||||||
for (i = 0; rdac_dev_list[i].vendor; i++) {
|
|
||||||
if (!strncmp(sdev->vendor, rdac_dev_list[i].vendor,
|
|
||||||
strlen(rdac_dev_list[i].vendor)) &&
|
|
||||||
!strncmp(sdev->model, rdac_dev_list[i].model,
|
|
||||||
strlen(rdac_dev_list[i].model))) {
|
|
||||||
found = 1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!found)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
scsi_dh_data = kzalloc(sizeof(struct scsi_device_handler *)
|
|
||||||
+ sizeof(*h) , GFP_KERNEL);
|
|
||||||
if (!scsi_dh_data) {
|
|
||||||
sdev_printk(KERN_ERR, sdev, "Attach failed %s.\n",
|
|
||||||
RDAC_NAME);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
scsi_dh_data->scsi_dh = &rdac_dh;
|
|
||||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
|
||||||
h->lun = UNINITIALIZED_LUN;
|
|
||||||
h->state = RDAC_STATE_ACTIVE;
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
sdev->scsi_dh_data = scsi_dh_data;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
try_module_get(THIS_MODULE);
|
|
||||||
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Attached %s.\n", RDAC_NAME);
|
|
||||||
|
|
||||||
} else if (action == BUS_NOTIFY_DEL_DEVICE) {
|
|
||||||
if (sdev->scsi_dh_data == NULL ||
|
|
||||||
sdev->scsi_dh_data->scsi_dh != &rdac_dh)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
|
||||||
scsi_dh_data = sdev->scsi_dh_data;
|
|
||||||
sdev->scsi_dh_data = NULL;
|
|
||||||
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
|
||||||
|
|
||||||
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
|
||||||
if (h->ctlr)
|
|
||||||
kref_put(&h->ctlr->kref, release_controller);
|
|
||||||
kfree(scsi_dh_data);
|
|
||||||
module_put(THIS_MODULE);
|
|
||||||
sdev_printk(KERN_NOTICE, sdev, "Dettached %s.\n", RDAC_NAME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out:
|
scsi_dh_data->scsi_dh = &rdac_dh;
|
||||||
|
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||||
|
h->lun = UNINITIALIZED_LUN;
|
||||||
|
h->state = RDAC_STATE_ACTIVE;
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
sdev->scsi_dh_data = scsi_dh_data;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
try_module_get(THIS_MODULE);
|
||||||
|
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Attached %s\n", RDAC_NAME);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rdac_bus_detach( struct scsi_device *sdev )
|
||||||
|
{
|
||||||
|
struct scsi_dh_data *scsi_dh_data;
|
||||||
|
struct rdac_dh_data *h;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
|
||||||
|
scsi_dh_data = sdev->scsi_dh_data;
|
||||||
|
sdev->scsi_dh_data = NULL;
|
||||||
|
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
|
||||||
|
|
||||||
|
h = (struct rdac_dh_data *) scsi_dh_data->buf;
|
||||||
|
if (h->ctlr)
|
||||||
|
kref_put(&h->ctlr->kref, release_controller);
|
||||||
|
kfree(scsi_dh_data);
|
||||||
|
module_put(THIS_MODULE);
|
||||||
|
sdev_printk(KERN_NOTICE, sdev, "Detached %s\n", RDAC_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int __init rdac_init(void)
|
static int __init rdac_init(void)
|
||||||
{
|
{
|
||||||
int r;
|
int r;
|
||||||
|
@@ -167,15 +167,22 @@ struct scsi_device {
|
|||||||
unsigned long sdev_data[0];
|
unsigned long sdev_data[0];
|
||||||
} __attribute__((aligned(sizeof(unsigned long))));
|
} __attribute__((aligned(sizeof(unsigned long))));
|
||||||
|
|
||||||
|
struct scsi_dh_devlist {
|
||||||
|
char *vendor;
|
||||||
|
char *model;
|
||||||
|
};
|
||||||
|
|
||||||
struct scsi_device_handler {
|
struct scsi_device_handler {
|
||||||
/* Used by the infrastructure */
|
/* Used by the infrastructure */
|
||||||
struct list_head list; /* list of scsi_device_handlers */
|
struct list_head list; /* list of scsi_device_handlers */
|
||||||
struct notifier_block nb;
|
|
||||||
|
|
||||||
/* Filled by the hardware handler */
|
/* Filled by the hardware handler */
|
||||||
struct module *module;
|
struct module *module;
|
||||||
const char *name;
|
const char *name;
|
||||||
|
const struct scsi_dh_devlist *devlist;
|
||||||
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
|
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
|
||||||
|
int (*attach)(struct scsi_device *);
|
||||||
|
void (*detach)(struct scsi_device *);
|
||||||
int (*activate)(struct scsi_device *);
|
int (*activate)(struct scsi_device *);
|
||||||
int (*prep_fn)(struct scsi_device *, struct request *);
|
int (*prep_fn)(struct scsi_device *, struct request *);
|
||||||
};
|
};
|
||||||
|
Reference in New Issue
Block a user