public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH] add scsi bus for virtual drivers
@ 2005-02-12  1:39 Mike Christie
  2005-02-12  2:25 ` Mike Christie
  0 siblings, 1 reply; 2+ messages in thread
From: Mike Christie @ 2005-02-12  1:39 UTC (permalink / raw)
  To: linux-scsi, linux-iscsi-devel

[-- Attachment #1: Type: text/plain, Size: 1069 bytes --]

Currently, LLDs using the newer driver model APIs use a driver's probe 
routine to perform setup and call scsi_host_alloc and scsi_add_host. 
And, then in remove the driver calls scsi_remove_host and scsi_host_put.

Virtual drivers like scsi_debug and software iscsi do not have a driver 
model bus or device_driver, so scsi_debug impements its own and software 
iscsi just adds and removes hosts from where ever makes it happy. A 
review comment we recieved for the software iscsi driver was to use a 
bus and driver and the callouts they provide. But instead of having the 
driver implement its own driver model bus code, the attached patch has 
scsi-ml maintain a virtual host bus for scsi_debug and software iscsi to 
use.

I had tried to just use the existing scsi bus, but it ends up that the 
host level device would need the bus's semaphore and the hosts' scanned 
scsi devices would try to grab the bus's semaphore at the same time.

The attached patch was made against scsi-rc-fixes-2.6.
I will also send a patch in the next mail to convert
scsi_debug.

Mike

[-- Attachment #2: add-ml-virtual-bus.patch --]
[-- Type: text/x-patch, Size: 14309 bytes --]

diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/hosts.c scsi-rc-fixes-2.6.work/drivers/scsi/hosts.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/hosts.c	2005-02-04 22:10:09.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/hosts.c	2005-02-11 16:18:20.000000000 -0800
@@ -31,6 +31,7 @@
 #include <linux/transport_class.h>
 
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
 
@@ -39,6 +40,7 @@
 
 
 static int scsi_host_next_hn;		/* host_no for next new host */
+static int scsi_host_next_vhn;		/* host_no for next new virtual host */
 
 
 static void scsi_host_cls_release(struct class_device *class_dev)
@@ -51,6 +53,16 @@ static struct class shost_class = {
 	.release	= scsi_host_cls_release,
 };
 
+static int scsi_host_match(struct device *dev, struct device_driver *gendrv)
+{
+	return 1;
+}
+
+static struct bus_type shost_bus_type = {
+        .name		= "scsi_host",
+        .match		= scsi_host_match,
+};
+
 /**
  * scsi_host_cancel - cancel outstanding IO to this host
  * @shost:	pointer to struct Scsi_Host
@@ -379,12 +391,23 @@ EXPORT_SYMBOL(scsi_host_put);
 
 int scsi_init_hosts(void)
 {
-	return class_register(&shost_class);
+	int error;
+
+	error = class_register(&shost_class);
+	if (error)
+		return error;
+
+	error = bus_register(&shost_bus_type);
+	if (error)
+		class_unregister(&shost_class);
+
+	return 0;
 }
 
 void scsi_exit_hosts(void)
 {
 	class_unregister(&shost_class);
+	bus_unregister(&shost_bus_type);
 }
 
 int scsi_is_host_device(const struct device *dev)
@@ -392,3 +415,141 @@ int scsi_is_host_device(const struct dev
 	return dev->release == scsi_host_dev_release;
 }
 EXPORT_SYMBOL(scsi_is_host_device);
+
+static void __scsi_host_driver_remove_host(struct scsi_host_driver *sdrv,
+					   struct scsi_virt_host *vhost)
+{
+	spin_lock(&sdrv->devices_lock);
+	list_del(&vhost->list);
+	spin_unlock(&sdrv->devices_lock);
+	device_unregister(&vhost->dev);
+}
+
+static ssize_t scsi_host_driver_remove_host(struct device *dev,
+					    const char *buf, size_t count)
+{
+	struct scsi_host_driver *sdrv = to_scsi_host_driver(dev->driver);
+	struct scsi_virt_host *vhost = to_scsi_virt_host(dev);
+
+	__scsi_host_driver_remove_host(sdrv, vhost);
+	return count;
+}
+static DEVICE_ATTR(remove_host, S_IWUSR, NULL, scsi_host_driver_remove_host);
+
+static void scsi_virt_host_release(struct device *dev)
+{
+	struct scsi_virt_host *vhost;
+
+	vhost = to_scsi_virt_host(dev);
+	kfree(vhost);
+}
+
+static ssize_t scsi_host_driver_add_host(struct device_driver *drv,
+					 const char *buf, size_t count)
+{
+	struct scsi_host_driver *sdrv = to_scsi_host_driver(drv);
+	struct device *dev;
+	struct scsi_virt_host *vhost;
+	int error;
+
+	vhost = kmalloc(sizeof(*vhost), GFP_KERNEL);
+	if (!vhost)
+		return -ENOMEM;
+
+	memset(vhost, 0, sizeof(*vhost));
+	INIT_LIST_HEAD(&vhost->list);
+	spin_lock(&sdrv->devices_lock);
+	list_add_tail(&vhost->list, &sdrv->devices);
+	spin_unlock(&sdrv->devices_lock);
+
+	dev = &vhost->dev;
+	dev->bus = &shost_bus_type;
+	dev->release = scsi_virt_host_release;
+	snprintf(dev->bus_id, BUS_ID_SIZE, "virt_host%d",
+		 scsi_host_next_vhn++);
+	error = device_register(dev);
+	if (error) {
+		kfree(vhost);
+		return error;
+	}
+	/*
+	 * this is not a ciritical file, so we can fail and limp on
+	 */
+	dev_attr_remove_host.attr.owner = sdrv->owner;
+	device_create_file(dev, &dev_attr_remove_host);
+
+	return count;
+}
+static DRIVER_ATTR(add_host, S_IWUSR, NULL, scsi_host_driver_add_host);
+
+static int scsi_host_driver_probe(struct device *dev)
+{
+	struct scsi_host_driver *sdrv;
+
+	sdrv = to_scsi_host_driver(dev->driver);
+	if (!sdrv->probe)
+		return 0;
+	return sdrv->probe(to_scsi_virt_host(dev));
+}
+
+static int scsi_host_driver_remove(struct device *dev)
+{
+	struct scsi_host_driver *sdrv;
+
+	sdrv = to_scsi_host_driver(dev->driver);
+	if (!sdrv->remove)
+		return 0;
+	return sdrv->remove(to_scsi_virt_host(dev));
+}
+
+int scsi_register_host_driver(struct scsi_host_driver *sdrv)
+{
+	int error;
+
+	INIT_LIST_HEAD(&sdrv->devices);
+	spin_lock_init(&sdrv->devices_lock);
+
+	sdrv->gendrv.name = sdrv->name;
+	sdrv->gendrv.owner = sdrv->owner;
+	sdrv->gendrv.probe = scsi_host_driver_probe;
+	sdrv->gendrv.remove = scsi_host_driver_remove;
+	sdrv->gendrv.bus = &shost_bus_type;
+
+	error = driver_register(&sdrv->gendrv);
+	if (error)
+		return error;
+
+	driver_attr_add_host.attr.owner = sdrv->owner;
+	error = driver_create_file(&sdrv->gendrv, &driver_attr_add_host);
+	if (error)
+		goto unregister_drv;
+
+	error = sysfs_create_group(&sdrv->gendrv.kobj, sdrv->attrs);
+	if (error)
+		goto remove_add_file;
+
+	return 0;
+
+ remove_add_file:
+	driver_remove_file(&sdrv->gendrv, &driver_attr_add_host);
+ unregister_drv:
+	driver_unregister(&sdrv->gendrv);
+	return error;
+}
+EXPORT_SYMBOL(scsi_register_host_driver);
+
+void scsi_unregister_host_driver(struct scsi_host_driver *sdrv)
+{
+	struct scsi_virt_host *vhost, *tmp;
+
+	driver_remove_file(&sdrv->gendrv, &driver_attr_add_host);
+	sysfs_remove_group(&sdrv->gendrv.kobj, sdrv->attrs);
+	/*
+	 * this is only called from LLDs module_exit functions
+	 * so we should not need a lock.
+	 */
+	list_for_each_entry_safe(vhost, tmp, &sdrv->devices, list)
+		__scsi_host_driver_remove_host(sdrv, vhost);
+	driver_unregister(&sdrv->gendrv);
+}
+EXPORT_SYMBOL(scsi_unregister_host_driver);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/osst.c scsi-rc-fixes-2.6.work/drivers/scsi/osst.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/osst.c	2005-02-04 22:10:56.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/osst.c	2005-02-11 16:28:05.000000000 -0800
@@ -170,7 +170,7 @@ static int osst_copy_from_buffer(struct 
 static int osst_probe(struct device *);
 static int osst_remove(struct device *);
 
-struct scsi_driver osst_template = {
+struct scsi_device_driver osst_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		=  "osst",
@@ -5850,7 +5850,7 @@ static int __init init_osst(void) 
 	validate_options();
 	osst_sysfs_init();
 
-	if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
+	if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_device_driver(&osst_template.gendrv)) {
 		printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
 		osst_sysfs_cleanup();
 		return 1;
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_lib.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_lib.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_lib.c	2005-02-04 22:11:02.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_lib.c	2005-02-10 20:25:50.000000000 -0800
@@ -966,12 +966,12 @@ static int scsi_issue_flush_fn(request_q
 			       sector_t *error_sector)
 {
 	struct scsi_device *sdev = q->queuedata;
-	struct scsi_driver *drv;
+	struct scsi_device_driver *drv;
 
 	if (sdev->sdev_state != SDEV_RUNNING)
 		return -ENXIO;
 
-	drv = *(struct scsi_driver **) disk->private_data;
+	drv = *(struct scsi_device_driver **) disk->private_data;
 	if (drv->issue_flush)
 		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
 
@@ -1073,7 +1073,7 @@ static int scsi_prep_fn(struct request_q
 	 * happening now.
 	 */
 	if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-		struct scsi_driver *drv;
+		struct scsi_device_driver *drv;
 		int ret;
 
 		/*
@@ -1100,7 +1100,7 @@ static int scsi_prep_fn(struct request_q
 		/*
 		 * Initialize the actual SCSI command for this request.
 		 */
-		drv = *(struct scsi_driver **)req->rq_disk->private_data;
+		drv = *(struct scsi_device_driver **)req->rq_disk->private_data;
 		if (unlikely(!drv->init_command(cmd))) {
 			scsi_release_buffers(cmd);
 			scsi_put_command(cmd);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_scan.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_scan.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_scan.c	2005-02-04 22:12:05.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_scan.c	2005-02-10 20:26:51.000000000 -0800
@@ -1089,12 +1089,12 @@ EXPORT_SYMBOL(__scsi_add_device);
 
 void scsi_rescan_device(struct device *dev)
 {
-	struct scsi_driver *drv;
+	struct scsi_device_driver *drv;
 	
 	if (!dev->driver)
 		return;
 
-	drv = to_scsi_driver(dev->driver);
+	drv = to_scsi_device_driver(dev->driver);
 	if (try_module_get(drv->owner)) {
 		if (drv->rescan)
 			drv->rescan(dev);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_sysfs.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_sysfs.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_sysfs.c	2005-02-04 22:10:23.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_sysfs.c	2005-02-11 16:27:33.000000000 -0800
@@ -197,6 +197,7 @@ struct class sdev_class = {
 static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
 {
 	struct scsi_device *sdp = to_scsi_device(dev);
+
 	if (sdp->no_uld_attach)
 		return 0;
 	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
@@ -653,13 +654,13 @@ out:
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
-int scsi_register_driver(struct device_driver *drv)
+int scsi_register_device_driver(struct device_driver *drv)
 {
 	drv->bus = &scsi_bus_type;
 
 	return driver_register(drv);
 }
-EXPORT_SYMBOL(scsi_register_driver);
+EXPORT_SYMBOL(scsi_register_device_driver);
 
 int scsi_register_interface(struct class_interface *intf)
 {
@@ -669,7 +670,6 @@ int scsi_register_interface(struct class
 }
 EXPORT_SYMBOL(scsi_register_interface);
 
-
 static struct class_device_attribute *class_attr_overridden(
 		struct class_device_attribute **attrs,
 		struct class_device_attribute *attr)
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/sd.c scsi-rc-fixes-2.6.work/drivers/scsi/sd.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/sd.c	2005-02-04 22:11:57.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/sd.c	2005-02-11 16:28:15.000000000 -0800
@@ -92,7 +92,7 @@
 static void scsi_disk_release(struct kref *kref);
 
 struct scsi_disk {
-	struct scsi_driver *driver;	/* always &sd_template */
+	struct scsi_device_driver *driver;	/* always &sd_template */
 	struct scsi_device *device;
 	struct kref	kref;
 	struct gendisk	*disk;
@@ -125,7 +125,7 @@ static int sd_issue_flush(struct device 
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
 		 struct scsi_request *SRpnt, unsigned char *buffer);
 
-static struct scsi_driver sd_template = {
+static struct scsi_device_driver sd_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		= "sd",
@@ -1631,7 +1631,7 @@ static int __init init_sd(void)
 	if (!majors)
 		return -ENODEV;
 
-	return scsi_register_driver(&sd_template.gendrv);
+	return scsi_register_device_driver(&sd_template.gendrv);
 }
 
 /**
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/sr.c scsi-rc-fixes-2.6.work/drivers/scsi/sr.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/sr.c	2005-02-04 22:13:14.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/sr.c	2005-02-11 16:28:25.000000000 -0800
@@ -74,7 +74,7 @@ static int sr_probe(struct device *);
 static int sr_remove(struct device *);
 static int sr_init_command(struct scsi_cmnd *);
 
-static struct scsi_driver sr_template = {
+static struct scsi_device_driver sr_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name   	= "sr",
@@ -947,7 +947,7 @@ static int __init init_sr(void)
 	rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
 	if (rc)
 		return rc;
-	return scsi_register_driver(&sr_template.gendrv);
+	return scsi_register_device_driver(&sr_template.gendrv);
 }
 
 static void __exit exit_sr(void)
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/st.c scsi-rc-fixes-2.6.work/drivers/scsi/st.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/st.c	2005-02-04 22:11:33.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/st.c	2005-02-11 16:28:32.000000000 -0800
@@ -198,7 +198,7 @@ static void do_create_driverfs_files(voi
 static void do_remove_driverfs_files(void);
 static void do_create_class_files(struct scsi_tape *, int, int);
 
-static struct scsi_driver st_template = {
+static struct scsi_device_driver st_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		= "st",
@@ -4062,7 +4062,7 @@ static int __init init_st(void)
 
 	if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
 				    ST_MAX_TAPE_ENTRIES, "st")) {
-		if (scsi_register_driver(&st_template.gendrv) == 0) {
+		if (scsi_register_device_driver(&st_template.gendrv) == 0) {
 			do_create_driverfs_files();
 			return 0;
 		}
diff -aurp scsi-rc-fixes-2.6.orig/include/scsi/scsi_driver.h scsi-rc-fixes-2.6.work/include/scsi/scsi_driver.h
--- scsi-rc-fixes-2.6.orig/include/scsi/scsi_driver.h	2005-02-04 22:11:49.000000000 -0800
+++ scsi-rc-fixes-2.6.work/include/scsi/scsi_driver.h	2005-02-11 16:26:50.000000000 -0800
@@ -7,7 +7,7 @@ struct module;
 struct scsi_cmnd;
 
 
-struct scsi_driver {
+struct scsi_device_driver {
 	struct module		*owner;
 	struct device_driver	gendrv;
 
@@ -15,15 +15,42 @@ struct scsi_driver {
 	void (*rescan)(struct device *);
 	int (*issue_flush)(struct device *, sector_t *);
 };
-#define to_scsi_driver(drv) \
-	container_of((drv), struct scsi_driver, gendrv)
+#define to_scsi_device_driver(drv) \
+	container_of((drv), struct scsi_device_driver, gendrv)
 
-extern int scsi_register_driver(struct device_driver *);
-#define scsi_unregister_driver(drv) \
+extern int scsi_register_device_driver(struct device_driver *);
+#define scsi_unregister_device_driver(drv) \
 	driver_unregister(drv);
 
 extern int scsi_register_interface(struct class_interface *);
 #define scsi_unregister_interface(intf) \
 	class_interface_unregister(intf)
 
+struct scsi_virt_host {
+	struct device		dev;
+	struct list_head	list;
+};
+#define to_scsi_virt_host(_dev) \
+	container_of((_dev), struct scsi_virt_host, dev)
+
+struct scsi_host_driver {
+	char			*name;
+	struct module		*owner;
+	struct attribute_group	*attrs;
+
+	int (*probe)(struct scsi_virt_host *);
+	int (*remove)(struct scsi_virt_host *);
+	/*
+	 * internal fields
+	 */
+	struct device_driver	gendrv;
+	struct list_head	devices;
+	spinlock_t		devices_lock;
+};
+#define to_scsi_host_driver(_drv) \
+	container_of((_drv), struct scsi_host_driver, gendrv)
+
+extern int scsi_register_host_driver(struct scsi_host_driver *);
+extern void scsi_unregister_host_driver(struct scsi_host_driver *);
+
 #endif /* _SCSI_SCSI_DRIVER_H */

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [PATCH] add scsi bus for virtual drivers
  2005-02-12  1:39 [PATCH] add scsi bus for virtual drivers Mike Christie
@ 2005-02-12  2:25 ` Mike Christie
  0 siblings, 0 replies; 2+ messages in thread
From: Mike Christie @ 2005-02-12  2:25 UTC (permalink / raw)
  To: linux-scsi; +Cc: linux-iscsi-devel

[-- Attachment #1: Type: text/plain, Size: 1235 bytes --]

oops, I think my mailer wrapped some lines and I had some
extra formatting. Let me try a again.


Mike Christie wrote:
> Currently, LLDs using the newer driver model APIs use a driver's probe 
> routine to perform setup and call scsi_host_alloc and scsi_add_host. 
> And, then in remove the driver calls scsi_remove_host and scsi_host_put.
> 
> Virtual drivers like scsi_debug and software iscsi do not have a driver 
> model bus or device_driver, so scsi_debug impements its own and software 
> iscsi just adds and removes hosts from where ever makes it happy. A 
> review comment we recieved for the software iscsi driver was to use a 
> bus and driver and the callouts they provide. But instead of having the 
> driver implement its own driver model bus code, the attached patch has 
> scsi-ml maintain a virtual host bus for scsi_debug and software iscsi to 
> use.
> 
> I had tried to just use the existing scsi bus, but it ends up that the 
> host level device would need the bus's semaphore and the hosts' scanned 
> scsi devices would try to grab the bus's semaphore at the same time.
> 
> The attached patch was made against scsi-rc-fixes-2.6.
> I will also send a patch in the next mail to convert
> scsi_debug.
> 
> Mike
> 

[-- Attachment #2: add-ml-virtual-bus2.patch --]
[-- Type: text/x-patch, Size: 13780 bytes --]

diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/hosts.c scsi-rc-fixes-2.6.work/drivers/scsi/hosts.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/hosts.c	2005-02-04 22:10:09.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/hosts.c	2005-02-11 16:18:20.000000000 -0800
@@ -31,6 +31,7 @@
 #include <linux/transport_class.h>
 
 #include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
 
@@ -39,6 +40,7 @@
 
 
 static int scsi_host_next_hn;		/* host_no for next new host */
+static int scsi_host_next_vhn;		/* host_no for next new virtual host */
 
 
 static void scsi_host_cls_release(struct class_device *class_dev)
@@ -51,6 +53,16 @@ static struct class shost_class = {
 	.release	= scsi_host_cls_release,
 };
 
+static int scsi_host_match(struct device *dev, struct device_driver *gendrv)
+{
+	return 1;
+}
+
+static struct bus_type shost_bus_type = {
+        .name		= "scsi_host",
+        .match		= scsi_host_match,
+};
+
 /**
  * scsi_host_cancel - cancel outstanding IO to this host
  * @shost:	pointer to struct Scsi_Host
@@ -379,12 +391,23 @@ EXPORT_SYMBOL(scsi_host_put);
 
 int scsi_init_hosts(void)
 {
-	return class_register(&shost_class);
+	int error;
+
+	error = class_register(&shost_class);
+	if (error)
+		return error;
+
+	error = bus_register(&shost_bus_type);
+	if (error)
+		class_unregister(&shost_class);
+
+	return 0;
 }
 
 void scsi_exit_hosts(void)
 {
 	class_unregister(&shost_class);
+	bus_unregister(&shost_bus_type);
 }
 
 int scsi_is_host_device(const struct device *dev)
@@ -392,3 +415,141 @@ int scsi_is_host_device(const struct dev
 	return dev->release == scsi_host_dev_release;
 }
 EXPORT_SYMBOL(scsi_is_host_device);
+
+static void __scsi_host_driver_remove_host(struct scsi_host_driver *sdrv,
+					   struct scsi_virt_host *vhost)
+{
+	spin_lock(&sdrv->devices_lock);
+	list_del(&vhost->list);
+	spin_unlock(&sdrv->devices_lock);
+	device_unregister(&vhost->dev);
+}
+
+static ssize_t scsi_host_driver_remove_host(struct device *dev,
+					    const char *buf, size_t count)
+{
+	struct scsi_host_driver *sdrv = to_scsi_host_driver(dev->driver);
+	struct scsi_virt_host *vhost = to_scsi_virt_host(dev);
+
+	__scsi_host_driver_remove_host(sdrv, vhost);
+	return count;
+}
+static DEVICE_ATTR(remove_host, S_IWUSR, NULL, scsi_host_driver_remove_host);
+
+static void scsi_virt_host_release(struct device *dev)
+{
+	struct scsi_virt_host *vhost;
+
+	vhost = to_scsi_virt_host(dev);
+	kfree(vhost);
+}
+
+static ssize_t scsi_host_driver_add_host(struct device_driver *drv,
+					 const char *buf, size_t count)
+{
+	struct scsi_host_driver *sdrv = to_scsi_host_driver(drv);
+	struct device *dev;
+	struct scsi_virt_host *vhost;
+	int error;
+
+	vhost = kmalloc(sizeof(*vhost), GFP_KERNEL);
+	if (!vhost)
+		return -ENOMEM;
+
+	memset(vhost, 0, sizeof(*vhost));
+	INIT_LIST_HEAD(&vhost->list);
+	spin_lock(&sdrv->devices_lock);
+	list_add_tail(&vhost->list, &sdrv->devices);
+	spin_unlock(&sdrv->devices_lock);
+
+	dev = &vhost->dev;
+	dev->bus = &shost_bus_type;
+	dev->release = scsi_virt_host_release;
+	snprintf(dev->bus_id, BUS_ID_SIZE, "virt_host%d",
+		 scsi_host_next_vhn++);
+	error = device_register(dev);
+	if (error) {
+		kfree(vhost);
+		return error;
+	}
+	/*
+	 * this is not a ciritical file, so we can fail and limp on
+	 */
+	dev_attr_remove_host.attr.owner = sdrv->owner;
+	device_create_file(dev, &dev_attr_remove_host);
+
+	return count;
+}
+static DRIVER_ATTR(add_host, S_IWUSR, NULL, scsi_host_driver_add_host);
+
+static int scsi_host_driver_probe(struct device *dev)
+{
+	struct scsi_host_driver *sdrv;
+
+	sdrv = to_scsi_host_driver(dev->driver);
+	if (!sdrv->probe)
+		return 0;
+	return sdrv->probe(to_scsi_virt_host(dev));
+}
+
+static int scsi_host_driver_remove(struct device *dev)
+{
+	struct scsi_host_driver *sdrv;
+
+	sdrv = to_scsi_host_driver(dev->driver);
+	if (!sdrv->remove)
+		return 0;
+	return sdrv->remove(to_scsi_virt_host(dev));
+}
+
+int scsi_register_host_driver(struct scsi_host_driver *sdrv)
+{
+	int error;
+
+	INIT_LIST_HEAD(&sdrv->devices);
+	spin_lock_init(&sdrv->devices_lock);
+
+	sdrv->gendrv.name = sdrv->name;
+	sdrv->gendrv.owner = sdrv->owner;
+	sdrv->gendrv.probe = scsi_host_driver_probe;
+	sdrv->gendrv.remove = scsi_host_driver_remove;
+	sdrv->gendrv.bus = &shost_bus_type;
+
+	error = driver_register(&sdrv->gendrv);
+	if (error)
+		return error;
+
+	driver_attr_add_host.attr.owner = sdrv->owner;
+	error = driver_create_file(&sdrv->gendrv, &driver_attr_add_host);
+	if (error)
+		goto unregister_drv;
+
+	error = sysfs_create_group(&sdrv->gendrv.kobj, sdrv->attrs);
+	if (error)
+		goto remove_add_file;
+
+	return 0;
+
+ remove_add_file:
+	driver_remove_file(&sdrv->gendrv, &driver_attr_add_host);
+ unregister_drv:
+	driver_unregister(&sdrv->gendrv);
+	return error;
+}
+EXPORT_SYMBOL(scsi_register_host_driver);
+
+void scsi_unregister_host_driver(struct scsi_host_driver *sdrv)
+{
+	struct scsi_virt_host *vhost, *tmp;
+
+	driver_remove_file(&sdrv->gendrv, &driver_attr_add_host);
+	sysfs_remove_group(&sdrv->gendrv.kobj, sdrv->attrs);
+	/*
+	 * this is only called from LLDs module_exit functions
+	 * so we should not need a lock.
+	 */
+	list_for_each_entry_safe(vhost, tmp, &sdrv->devices, list)
+		__scsi_host_driver_remove_host(sdrv, vhost);
+	driver_unregister(&sdrv->gendrv);
+}
+EXPORT_SYMBOL(scsi_unregister_host_driver);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/osst.c scsi-rc-fixes-2.6.work/drivers/scsi/osst.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/osst.c	2005-02-04 22:10:56.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/osst.c	2005-02-11 16:28:05.000000000 -0800
@@ -170,7 +170,7 @@ static int osst_copy_from_buffer(struct 
 static int osst_probe(struct device *);
 static int osst_remove(struct device *);
 
-struct scsi_driver osst_template = {
+struct scsi_device_driver osst_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		=  "osst",
@@ -5850,7 +5850,7 @@ static int __init init_osst(void) 
 	validate_options();
 	osst_sysfs_init();
 
-	if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
+	if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_device_driver(&osst_template.gendrv)) {
 		printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
 		osst_sysfs_cleanup();
 		return 1;
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_lib.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_lib.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_lib.c	2005-02-04 22:11:02.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_lib.c	2005-02-10 20:25:50.000000000 -0800
@@ -966,12 +966,12 @@ static int scsi_issue_flush_fn(request_q
 			       sector_t *error_sector)
 {
 	struct scsi_device *sdev = q->queuedata;
-	struct scsi_driver *drv;
+	struct scsi_device_driver *drv;
 
 	if (sdev->sdev_state != SDEV_RUNNING)
 		return -ENXIO;
 
-	drv = *(struct scsi_driver **) disk->private_data;
+	drv = *(struct scsi_device_driver **) disk->private_data;
 	if (drv->issue_flush)
 		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
 
@@ -1073,7 +1073,7 @@ static int scsi_prep_fn(struct request_q
 	 * happening now.
 	 */
 	if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
-		struct scsi_driver *drv;
+		struct scsi_device_driver *drv;
 		int ret;
 
 		/*
@@ -1100,7 +1100,7 @@ static int scsi_prep_fn(struct request_q
 		/*
 		 * Initialize the actual SCSI command for this request.
 		 */
-		drv = *(struct scsi_driver **)req->rq_disk->private_data;
+		drv = *(struct scsi_device_driver **)req->rq_disk->private_data;
 		if (unlikely(!drv->init_command(cmd))) {
 			scsi_release_buffers(cmd);
 			scsi_put_command(cmd);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_scan.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_scan.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_scan.c	2005-02-04 22:12:05.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_scan.c	2005-02-10 20:26:51.000000000 -0800
@@ -1089,12 +1089,12 @@ EXPORT_SYMBOL(__scsi_add_device);
 
 void scsi_rescan_device(struct device *dev)
 {
-	struct scsi_driver *drv;
+	struct scsi_device_driver *drv;
 	
 	if (!dev->driver)
 		return;
 
-	drv = to_scsi_driver(dev->driver);
+	drv = to_scsi_device_driver(dev->driver);
 	if (try_module_get(drv->owner)) {
 		if (drv->rescan)
 			drv->rescan(dev);
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_sysfs.c scsi-rc-fixes-2.6.work/drivers/scsi/scsi_sysfs.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/scsi_sysfs.c	2005-02-04 22:10:23.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/scsi_sysfs.c	2005-02-11 18:01:11.000000000 -0800
@@ -653,13 +653,13 @@ out:
 }
 EXPORT_SYMBOL(scsi_remove_device);
 
-int scsi_register_driver(struct device_driver *drv)
+int scsi_register_device_driver(struct device_driver *drv)
 {
 	drv->bus = &scsi_bus_type;
 
 	return driver_register(drv);
 }
-EXPORT_SYMBOL(scsi_register_driver);
+EXPORT_SYMBOL(scsi_register_device_driver);
 
 int scsi_register_interface(struct class_interface *intf)
 {
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/sd.c scsi-rc-fixes-2.6.work/drivers/scsi/sd.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/sd.c	2005-02-04 22:11:57.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/sd.c	2005-02-11 16:28:15.000000000 -0800
@@ -92,7 +92,7 @@
 static void scsi_disk_release(struct kref *kref);
 
 struct scsi_disk {
-	struct scsi_driver *driver;	/* always &sd_template */
+	struct scsi_device_driver *driver;	/* always &sd_template */
 	struct scsi_device *device;
 	struct kref	kref;
 	struct gendisk	*disk;
@@ -125,7 +125,7 @@ static int sd_issue_flush(struct device 
 static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
 		 struct scsi_request *SRpnt, unsigned char *buffer);
 
-static struct scsi_driver sd_template = {
+static struct scsi_device_driver sd_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		= "sd",
@@ -1631,7 +1631,7 @@ static int __init init_sd(void)
 	if (!majors)
 		return -ENODEV;
 
-	return scsi_register_driver(&sd_template.gendrv);
+	return scsi_register_device_driver(&sd_template.gendrv);
 }
 
 /**
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/sr.c scsi-rc-fixes-2.6.work/drivers/scsi/sr.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/sr.c	2005-02-04 22:13:14.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/sr.c	2005-02-11 16:28:25.000000000 -0800
@@ -74,7 +74,7 @@ static int sr_probe(struct device *);
 static int sr_remove(struct device *);
 static int sr_init_command(struct scsi_cmnd *);
 
-static struct scsi_driver sr_template = {
+static struct scsi_device_driver sr_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name   	= "sr",
@@ -947,7 +947,7 @@ static int __init init_sr(void)
 	rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
 	if (rc)
 		return rc;
-	return scsi_register_driver(&sr_template.gendrv);
+	return scsi_register_device_driver(&sr_template.gendrv);
 }
 
 static void __exit exit_sr(void)
diff -aurp scsi-rc-fixes-2.6.orig/drivers/scsi/st.c scsi-rc-fixes-2.6.work/drivers/scsi/st.c
--- scsi-rc-fixes-2.6.orig/drivers/scsi/st.c	2005-02-04 22:11:33.000000000 -0800
+++ scsi-rc-fixes-2.6.work/drivers/scsi/st.c	2005-02-11 16:28:32.000000000 -0800
@@ -198,7 +198,7 @@ static void do_create_driverfs_files(voi
 static void do_remove_driverfs_files(void);
 static void do_create_class_files(struct scsi_tape *, int, int);
 
-static struct scsi_driver st_template = {
+static struct scsi_device_driver st_template = {
 	.owner			= THIS_MODULE,
 	.gendrv = {
 		.name		= "st",
@@ -4062,7 +4062,7 @@ static int __init init_st(void)
 
 	if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
 				    ST_MAX_TAPE_ENTRIES, "st")) {
-		if (scsi_register_driver(&st_template.gendrv) == 0) {
+		if (scsi_register_device_driver(&st_template.gendrv) == 0) {
 			do_create_driverfs_files();
 			return 0;
 		}
diff -aurp scsi-rc-fixes-2.6.orig/include/scsi/scsi_driver.h scsi-rc-fixes-2.6.work/include/scsi/scsi_driver.h
--- scsi-rc-fixes-2.6.orig/include/scsi/scsi_driver.h	2005-02-04 22:11:49.000000000 -0800
+++ scsi-rc-fixes-2.6.work/include/scsi/scsi_driver.h	2005-02-11 16:26:50.000000000 -0800
@@ -7,7 +7,7 @@ struct module;
 struct scsi_cmnd;
 
 
-struct scsi_driver {
+struct scsi_device_driver {
 	struct module		*owner;
 	struct device_driver	gendrv;
 
@@ -15,15 +15,42 @@ struct scsi_driver {
 	void (*rescan)(struct device *);
 	int (*issue_flush)(struct device *, sector_t *);
 };
-#define to_scsi_driver(drv) \
-	container_of((drv), struct scsi_driver, gendrv)
+#define to_scsi_device_driver(drv) \
+	container_of((drv), struct scsi_device_driver, gendrv)
 
-extern int scsi_register_driver(struct device_driver *);
-#define scsi_unregister_driver(drv) \
+extern int scsi_register_device_driver(struct device_driver *);
+#define scsi_unregister_device_driver(drv) \
 	driver_unregister(drv);
 
 extern int scsi_register_interface(struct class_interface *);
 #define scsi_unregister_interface(intf) \
 	class_interface_unregister(intf)
 
+struct scsi_virt_host {
+	struct device		dev;
+	struct list_head	list;
+};
+#define to_scsi_virt_host(_dev) \
+	container_of((_dev), struct scsi_virt_host, dev)
+
+struct scsi_host_driver {
+	char			*name;
+	struct module		*owner;
+	struct attribute_group	*attrs;
+
+	int (*probe)(struct scsi_virt_host *);
+	int (*remove)(struct scsi_virt_host *);
+	/*
+	 * internal fields
+	 */
+	struct device_driver	gendrv;
+	struct list_head	devices;
+	spinlock_t		devices_lock;
+};
+#define to_scsi_host_driver(_drv) \
+	container_of((_drv), struct scsi_host_driver, gendrv)
+
+extern int scsi_register_host_driver(struct scsi_host_driver *);
+extern void scsi_unregister_host_driver(struct scsi_host_driver *);
+
 #endif /* _SCSI_SCSI_DRIVER_H */

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-02-12  2:25 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-02-12  1:39 [PATCH] add scsi bus for virtual drivers Mike Christie
2005-02-12  2:25 ` Mike Christie

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox