X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=block%2Fbsg.c;h=b571869928a83c16dbcf6fb0c94aa5dc0c90e2da;hb=e58712111fe6eb7573fd6dd12d80de3bec13f277;hp=cdb00e5544b10712ff261c04310902a9695580c0;hpb=46f6ef4afc14ae1426883a973c18735cfcd70d8f;p=powerpc.git diff --git a/block/bsg.c b/block/bsg.c index cdb00e5544..b571869928 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -33,7 +33,8 @@ #include #include -const static char bsg_version[] = "block layer sg (bsg) 0.4"; +#define BSG_DESCRIPTION "Block layer SCSI generic (bsg) driver" +#define BSG_VERSION "0.4" struct bsg_device { request_queue_t *queue; @@ -72,7 +73,6 @@ static DEFINE_MUTEX(bsg_mutex); static int bsg_device_nr, bsg_minor_idx; #define BSG_LIST_ARRAY_SIZE 8 -#define bsg_list_idx(minor) ((minor) & (BSG_LIST_ARRAY_SIZE - 1)) static struct hlist_head bsg_device_list[BSG_LIST_ARRAY_SIZE]; static struct class *bsg_class; @@ -139,9 +139,9 @@ out: return bc; } -static inline void -bsg_add_done_cmd(struct bsg_device *bd, struct bsg_command *bc) +static inline struct hlist_head *bsg_dev_idx_hash(int index) { + return &bsg_device_list[index & (BSG_LIST_ARRAY_SIZE - 1)]; } static int bsg_io_schedule(struct bsg_device *bd) @@ -748,8 +748,7 @@ static struct bsg_device *bsg_add_device(struct inode *inode, atomic_set(&bd->ref_count, 1); bd->minor = iminor(inode); mutex_lock(&bsg_mutex); - hlist_add_head(&bd->dev_list, - &bsg_device_list[bd->minor & (BSG_LIST_ARRAY_SIZE - 1)]); + hlist_add_head(&bd->dev_list, bsg_dev_idx_hash(bd->minor)); strncpy(bd->name, rq->bsg_dev.class_dev->class_id, sizeof(bd->name) - 1); dprintk("bound to <%s>, max queue %d\n", @@ -761,14 +760,12 @@ static struct bsg_device *bsg_add_device(struct inode *inode, static struct bsg_device *__bsg_get_device(int minor) { - struct hlist_head *list; struct bsg_device *bd = NULL; struct hlist_node *entry; mutex_lock(&bsg_mutex); - list = &bsg_device_list[minor & (BSG_LIST_ARRAY_SIZE - 1)]; - hlist_for_each(entry, list) { + hlist_for_each(entry, bsg_dev_idx_hash(minor)) { bd = hlist_entry(entry, struct bsg_device, dev_list); if (bd->minor == minor) { atomic_inc(&bd->ref_count); @@ -935,24 +932,34 @@ void bsg_unregister_queue(struct request_queue *q) { struct bsg_class_device *bcd = &q->bsg_dev; - WARN_ON(!bcd->class_dev); + if (!bcd->class_dev) + return; mutex_lock(&bsg_mutex); sysfs_remove_link(&q->kobj, "bsg"); - class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor)); + class_device_unregister(bcd->class_dev); + put_device(bcd->dev); bcd->class_dev = NULL; + bcd->dev = NULL; list_del_init(&bcd->list); bsg_device_nr--; mutex_unlock(&bsg_mutex); } EXPORT_SYMBOL_GPL(bsg_unregister_queue); -int bsg_register_queue(struct request_queue *q, const char *name) +int bsg_register_queue(struct request_queue *q, struct device *gdev, + const char *name) { struct bsg_class_device *bcd, *__bcd; dev_t dev; int ret = -EMFILE; struct class_device *class_dev = NULL; + const char *devname; + + if (name) + devname = name; + else + devname = gdev->bus_id; /* * we need a proper transport to send commands, not a stacked device @@ -985,18 +992,20 @@ retry: bsg_minor_idx = 0; bcd->queue = q; + bcd->dev = get_device(gdev); dev = MKDEV(bsg_major, bcd->minor); - class_dev = class_device_create(bsg_class, NULL, dev, bcd->dev, "%s", name); + class_dev = class_device_create(bsg_class, NULL, dev, gdev, "%s", + devname); if (IS_ERR(class_dev)) { ret = PTR_ERR(class_dev); - goto err; + goto err_put; } bcd->class_dev = class_dev; if (q->kobj.sd) { ret = sysfs_create_link(&q->kobj, &bcd->class_dev->kobj, "bsg"); if (ret) - goto err; + goto err_unregister; } list_add_tail(&bcd->list, &bsg_class_list); @@ -1004,37 +1013,17 @@ retry: mutex_unlock(&bsg_mutex); return 0; + +err_unregister: + class_device_unregister(class_dev); +err_put: + put_device(gdev); err: - if (class_dev) - class_device_destroy(bsg_class, MKDEV(bsg_major, bcd->minor)); mutex_unlock(&bsg_mutex); return ret; } EXPORT_SYMBOL_GPL(bsg_register_queue); -static int bsg_add(struct class_device *cl_dev, struct class_interface *cl_intf) -{ - int ret; - struct scsi_device *sdp = to_scsi_device(cl_dev->dev); - struct request_queue *rq = sdp->request_queue; - - if (rq->kobj.parent) - ret = bsg_register_queue(rq, kobject_name(rq->kobj.parent)); - else - ret = bsg_register_queue(rq, kobject_name(&sdp->sdev_gendev.kobj)); - return ret; -} - -static void bsg_remove(struct class_device *cl_dev, struct class_interface *cl_intf) -{ - bsg_unregister_queue(to_scsi_device(cl_dev->dev)->request_queue); -} - -static struct class_interface bsg_intf = { - .add = bsg_add, - .remove = bsg_remove, -}; - static struct cdev bsg_cdev = { .kobj = {.name = "bsg", }, .owner = THIS_MODULE, @@ -1046,7 +1035,7 @@ static int __init bsg_init(void) dev_t devid; bsg_cmd_cachep = kmem_cache_create("bsg_cmd", - sizeof(struct bsg_command), 0, 0, NULL, NULL); + sizeof(struct bsg_command), 0, 0, NULL); if (!bsg_cmd_cachep) { printk(KERN_ERR "bsg: failed creating slab cache\n"); return -ENOMEM; @@ -1057,43 +1046,35 @@ static int __init bsg_init(void) bsg_class = class_create(THIS_MODULE, "bsg"); if (IS_ERR(bsg_class)) { - kmem_cache_destroy(bsg_cmd_cachep); - return PTR_ERR(bsg_class); + ret = PTR_ERR(bsg_class); + goto destroy_kmemcache; } ret = alloc_chrdev_region(&devid, 0, BSG_MAX_DEVS, "bsg"); - if (ret) { - kmem_cache_destroy(bsg_cmd_cachep); - class_destroy(bsg_class); - return ret; - } + if (ret) + goto destroy_bsg_class; bsg_major = MAJOR(devid); cdev_init(&bsg_cdev, &bsg_fops); ret = cdev_add(&bsg_cdev, MKDEV(bsg_major, 0), BSG_MAX_DEVS); - if (ret) { - kmem_cache_destroy(bsg_cmd_cachep); - class_destroy(bsg_class); - unregister_chrdev_region(MKDEV(bsg_major, 0), BSG_MAX_DEVS); - return ret; - } - - ret = scsi_register_interface(&bsg_intf); - if (ret) { - printk(KERN_ERR "bsg: failed register scsi interface %d\n", ret); - kmem_cache_destroy(bsg_cmd_cachep); - class_destroy(bsg_class); - unregister_chrdev(bsg_major, "bsg"); - return ret; - } + if (ret) + goto unregister_chrdev; - printk(KERN_INFO "%s loaded (major %d)\n", bsg_version, bsg_major); + printk(KERN_INFO BSG_DESCRIPTION " version " BSG_VERSION + " loaded (major %d)\n", bsg_major); return 0; +unregister_chrdev: + unregister_chrdev_region(MKDEV(bsg_major, 0), BSG_MAX_DEVS); +destroy_bsg_class: + class_destroy(bsg_class); +destroy_kmemcache: + kmem_cache_destroy(bsg_cmd_cachep); + return ret; } MODULE_AUTHOR("Jens Axboe"); -MODULE_DESCRIPTION("Block layer SGSI generic (sg) driver"); +MODULE_DESCRIPTION(BSG_DESCRIPTION); MODULE_LICENSE("GPL"); device_initcall(bsg_init);