public inbox for linux-scsi@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH][RFC] Driverfs support for SCSI devices
@ 2002-06-17 21:18 sullivan
  2002-06-17 23:16 ` James Bottomley
  0 siblings, 1 reply; 3+ messages in thread
From: sullivan @ 2002-06-17 21:18 UTC (permalink / raw)
  To: linux-kernel, linux-scsi

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

The following patch for linux-2.5.22 provides support in driverfs for scsi devices including st, sr, sg, sd (and partitions). For the most part the implementation follows the architecture set by Patrick Mochel for the PCI device tree. The primary difference is an attempt to use info obtained from the Scsi Inquiry pages to create the content of the driverfs "name" file for each Scsi device. This code can be found in the scsi_scan.c portion of the patch. The goal of this extra code is to provide a name that can uniquely identify a device independant of it's topology or discovery order. 

The patch is also available at http://www-124.ibm.com/devreg/linux-2.5.22-driverfs.patch.gz

I would welcome any feedback or comments. Please copy me directly on your replies...



[-- Attachment #2: linux-2.5.22-driverfs.patch --]
[-- Type: text/plain, Size: 37295 bytes --]

diff -Naur linux-2.5.22.orig/drivers/cdrom/cdrom.c linux-2.5.22-driverfs/drivers/cdrom/cdrom.c
--- linux-2.5.22.orig/drivers/cdrom/cdrom.c	Sun Jun 16 21:31:26 2002
+++ linux-2.5.22-driverfs/drivers/cdrom/cdrom.c	Mon Jun 17 21:14:07 2002
@@ -431,6 +431,11 @@
 		topCdromPtr = cdi->next;
 	cdi->ops->n_minors--;
 	devfs_unregister (cdi->de);
+	if (atomic_read (&cdi->cdrom_driverfs_dev.refcount)) {
+		device_remove_file (&cdi->cdrom_driverfs_dev, "name");
+		device_remove_file (&cdi->cdrom_driverfs_dev, "kdev");
+		put_device (&cdi->cdrom_driverfs_dev);
+	}
 	devfs_dealloc_unique_number (&cdrom_numspace, cdi->number);
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
 	return 0;
diff -Naur linux-2.5.22.orig/drivers/scsi/hosts.h linux-2.5.22-driverfs/drivers/scsi/hosts.h
--- linux-2.5.22.orig/drivers/scsi/hosts.h	Sun Jun 16 21:31:29 2002
+++ linux-2.5.22-driverfs/drivers/scsi/hosts.h	Mon Jun 17 21:14:07 2002
@@ -418,6 +418,11 @@
      */
     struct pci_dev *pci_dev;
 
+    /* 
+     * Support for driverfs filesystem
+     */
+    struct device host_driverfs_dev;
+
     /*
      * We should ensure that this is aligned, both for better performance
      * and also because some compilers (m68k) don't automatically force
@@ -478,6 +483,7 @@
                                        struct pci_dev *pdev)
 {
 	SHpnt->pci_dev = pdev;
+	SHpnt->host_driverfs_dev.parent=&pdev->dev;
 }
 
 
@@ -516,6 +522,7 @@
     void (*detach)(Scsi_Device *);
     int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. 
                                            Selects command for blkdevs */
+    struct device_driver scsi_driverfs_driver;
 };
 
 void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi.c linux-2.5.22-driverfs/drivers/scsi/scsi.c
--- linux-2.5.22.orig/drivers/scsi/scsi.c	Sun Jun 16 21:31:33 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi.c	Tue Jun 18 00:22:21 2002
@@ -1939,6 +1939,11 @@
 				}
 				printk(KERN_INFO "scsi%d : %s\n",		/* And print a little message */
 				       shpnt->host_no, name);
+				strncpy(shpnt->host_driverfs_dev.name,name,
+					DEVICE_NAME_SIZE-1);
+				sprintf(shpnt->host_driverfs_dev.bus_id,
+					"scsi%d",
+					shpnt->host_no);
 			}
 		}
 
@@ -1947,6 +1952,8 @@
 		 */
 		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
 			if (shpnt->hostt == tpnt) {
+				/* first register parent with driverfs */
+				device_register(&shpnt->host_driverfs_dev);
 				scan_scsis(shpnt, 0, 0, 0, 0);
 				if (shpnt->select_queue_depths != NULL) {
 					(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
@@ -2101,6 +2108,7 @@
 				goto err_out;
 			}
 			devfs_unregister (SDpnt->de);
+			put_device(&SDpnt->sdev_driverfs_dev);
 		}
 	}
 
@@ -2151,6 +2159,7 @@
 		/* Remove the /proc/scsi directory entry */
 		sprintf(name,"%d",shpnt->host_no);
 		remove_proc_entry(name, tpnt->proc_dir);
+		put_device(&shpnt->host_driverfs_dev);
 		if (tpnt->release)
 			(*tpnt->release) (shpnt);
 		else {
@@ -2499,6 +2508,34 @@
 	mempool_free(sgl, sgp->pool);
 }
 
+static int scsi_bus_match(struct device *scsi_driverfs_dev, 
+                          struct device_driver *scsi_driverfs_drv)
+{
+        char *p=0;
+
+        if (!strcmp("sd", scsi_driverfs_drv->name)) {
+                if ((p = strstr(scsi_driverfs_dev->bus_id, ":disc")) || 
+		    (p = strstr(scsi_driverfs_dev->bus_id, ":p"))) { 
+                        return 1;
+                }
+        } else if (!strcmp("sg", scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id, ":gen"))
+                        return 1;
+        } else if (!strcmp("sr",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":cd"))
+                        return 1;
+        } else if (!strcmp("st",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":mt"))
+                        return 1;
+        }
+        return 0;
+}
+
+struct bus_type scsi_bus_type = {
+        name: "scsi",
+        match: scsi_bus_match,
+};
+
 static int __init init_scsi(void)
 {
 	struct proc_dir_entry *generic;
@@ -2544,6 +2581,8 @@
         if (scsihosts)
 		printk(KERN_INFO "scsi: host order: %s\n", scsihosts);	
 	scsi_host_no_init (scsihosts);
+
+	bus_register(&scsi_bus_type);
 	/*
 	 * This is where the processing takes place for most everything
 	 * when commands are completed.
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi.h linux-2.5.22-driverfs/drivers/scsi/scsi.h
--- linux-2.5.22.orig/drivers/scsi/scsi.h	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi.h	Mon Jun 17 21:14:07 2002
@@ -417,6 +417,8 @@
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 
+extern struct bus_type scsi_bus_type;
+
 
 /*
  * These are the error handling functions defined in scsi_error.c
@@ -622,6 +624,7 @@
 
 	// Flag to allow revalidate to succeed in sd_open
 	int allow_revalidate;
+	struct device sdev_driverfs_dev;
 };
 
 
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi_scan.c linux-2.5.22-driverfs/drivers/scsi/scsi_scan.c
--- linux-2.5.22.orig/drivers/scsi/scsi_scan.c	Sun Jun 16 21:31:35 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi_scan.c	Mon Jun 17 21:14:07 2002
@@ -54,6 +54,7 @@
 		char *scsi_result);
 static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
 				struct Scsi_Host *shpnt);
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt);
 
 struct dev_info {
 	const char *vendor;
@@ -288,6 +289,47 @@
 }
 #endif
 
+/* Driverfs file content handlers */
+char * scsi_type_names[] = {
+	"DISK",
+	"TAPE",
+	NULL,
+	"PROCESSOR",
+	"WORM",
+	"ROM",
+	"SCANNER",
+	"MOD",
+	"MEDIUM_CHANGER",
+	"COMM",
+	NULL,
+	NULL,
+	NULL,
+	"ENCLOSURE"};
+
+static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page, 
+	size_t count, loff_t off)
+{
+	struct scsi_device *SDpnt = list_entry(driverfs_dev,
+		struct scsi_device, sdev_driverfs_dev);
+
+	if ((SDpnt->type <= TYPE_ENCLOSURE) && 
+		(scsi_type_names[(int)SDpnt->type] != NULL))
+		return off ? 0 : 
+			sprintf(page, "%s\n", 
+				scsi_type_names[(int)SDpnt->type]);
+	else
+		return off ? 0 : sprintf(page, "UNKNOWN\n");
+
+	return 0;
+}
+
+static struct driver_file_entry scsi_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: scsi_device_type_read,
+};
+/* end content handlers */
+
 static void print_inquiry(unsigned char *data)
 {
 	int i;
@@ -786,6 +828,22 @@
 
 	print_inquiry(scsi_result);
 
+	/* interrogate scsi target to provide device identifier */
+	scsi_load_identifier(SDpnt, SRpnt);
+
+	/* create driverfs files */
+	sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
+		SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
+	
+	SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev;
+	SDpnt->sdev_driverfs_dev.bus = &scsi_bus_type;
+
+	device_register(&SDpnt->sdev_driverfs_dev); 
+
+	/* Create driverfs file entries */
+	device_create_file(&SDpnt->sdev_driverfs_dev, 
+			&scsi_device_type_file);
+
         sprintf (devname, "host%d/bus%d/target%d/lun%d",
                  SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
         if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
@@ -1306,3 +1364,374 @@
 	/* haven't found lun0, should send INQUIRY but take easy route */
 	return res;
 }
+
+#define SCSI_UID_DEV_ID  'U'
+#define SCSI_UID_SER_NUM 'S'
+#define SCSI_UID_UNKNOWN 'Z'
+
+unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	evpd_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
+	if (!evpd_page)
+		return NULL;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd) {
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x00;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* check to see if response was truncated */
+	if (evpd_page[3] > 255) {
+		int max_lgth = evpd_page[3] + 4;
+
+		kfree(evpd_page);
+		evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!evpd_page) {
+			kfree(scsi_cmd);
+			return NULL;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x00;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	kfree(scsi_cmd);
+	/* some ill behaved devices return the std inquiry here rather than
+		the evpd data. snoop the data to verify */
+	if (evpd_page[3] > 16) {
+		/* if vend id appears in the evpd page assume evpd is invalid */
+		if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) {
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	return evpd_page;
+}
+
+int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt)
+{
+	unsigned char *id_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int scnt, i, j, idtype;
+	char * id = SDpnt->sdev_driverfs_dev.name;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	id_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); 
+	if (!id_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x83;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+
+	/* check to see if response was truncated */
+	if (id_page[3] > 255) {
+		int max_lgth = id_page[3] + 4;
+
+		kfree(id_page);
+		id_page = kmalloc(max_lgth,
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC)); 
+		if (!id_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x83;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	idtype = 3;
+	while (idtype > 0) {
+		for(scnt = 4; scnt <= id_page[3] + 3; 
+		    scnt += id_page[scnt + 3] + 4) {
+			if ((id_page[scnt + 1] & 0x0f) != idtype) {
+				continue;
+			}
+			if ((id_page[scnt] & 0x0f) == 2) {  
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if (id_page[i] > 0x20) {
+						if (j == DEVICE_NAME_SIZE) {
+							memset(id, 0, 
+							    DEVICE_NAME_SIZE);
+							break;
+						}
+						id[j++] = id_page[i];
+					}
+				}
+			} else if ((id_page[scnt] & 0x0f) == 1) {
+				static const char hex_str[]="0123456789abcdef";
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if ((j + 1) == DEVICE_NAME_SIZE) {
+						memset(id, 0, DEVICE_NAME_SIZE);
+						break;
+					}
+					id[j++] = hex_str[(id_page[i] & 0xf0) >>
+								4];
+					id[j++] = hex_str[id_page[i] & 0x0f];
+				}
+			}
+			if (id[1] != 0) goto leave;
+		}
+		idtype--;
+	}
+ leave:
+	kfree(id_page);
+	if (id[1] != 0) {
+		id[0] = SCSI_UID_DEV_ID;
+		return 1;
+	}
+	return 0;
+}
+
+int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *serialnumber_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+	int i, j;
+
+	serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+	if (!serialnumber_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else	
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x80;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+	/* check to see if response was truncated */
+	if (serialnumber_page[3] > 255) {
+		int max_lgth = serialnumber_page[3] + 4;
+
+		kfree(serialnumber_page);
+		serialnumber_page = kmalloc(max_lgth, 
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!serialnumber_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x80;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, 
+				(void *) serialnumber_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
+	for(i = 0, j = 1; i < serialnumber_page[3]; i++) {
+		if (serialnumber_page[4 + i] > 0x20)
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				serialnumber_page[4 + i];
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i];
+		}
+	}
+	kfree(serialnumber_page);
+	return 1;
+ leave:
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	kfree(serialnumber_page);
+	return 0;
+}
+
+int scsi_get_default_name(Scsi_Device *SDpnt)
+{
+	int i, j;
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
+	for(i = 0, j = 1; i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->vendor[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); 
+	    i < 16; i++) {
+		if (SDpnt->model[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->model[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) {
+		if (SDpnt->rev[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i];
+		}
+	}	
+	return 1;
+}
+
+
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	int cnt;
+
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	evpd_page = scsi_get_evpd_page(SDpnt, SRpnt);
+	if (!evpd_page) {
+		/* try to obtain serial number anyway */
+		if (!scsi_get_serialnumber(SDpnt, SRpnt))
+			goto leave;
+		goto leave;
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x83) {
+			if (scsi_get_deviceid(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x80) {
+			if (scsi_get_serialnumber(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+leave:
+	if (SDpnt->sdev_driverfs_dev.name[0] == 0)
+		scsi_get_default_name(SDpnt);
+
+	if (evpd_page) kfree(evpd_page);
+	return;
+}
diff -Naur linux-2.5.22.orig/drivers/scsi/sd.c linux-2.5.22-driverfs/drivers/scsi/sd.c
--- linux-2.5.22.orig/drivers/scsi/sd.c	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sd.c	Mon Jun 17 21:19:04 2002
@@ -128,6 +128,7 @@
 
 static Scsi_Disk * sd_get_sdisk(int index);
 
+extern void driverfs_remove_partitions(struct gendisk *hd, int minor);
 
 #if defined(CONFIG_PPC32)
 /**
@@ -1276,12 +1277,15 @@
 
 		init_mem_lth(sd_gendisks[k].de_arr, N);
 		init_mem_lth(sd_gendisks[k].flags, N);
+		init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
-		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
+		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags ||
+				!sd_gendisks[k].driverfs_dev_arr)
 			goto cleanup_gendisks;
 
 		zero_mem_lth(sd_gendisks[k].de_arr, N);
 		zero_mem_lth(sd_gendisks[k].flags, N);
+		zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
 		sd_gendisks[k].major = SD_MAJOR(k);
 		sd_gendisks[k].major_name = "sd";
@@ -1290,7 +1294,9 @@
 		sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
 		sd_gendisks[k].nr_real = 0;
 	}
-
+	sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
+	sd_template.scsi_driverfs_driver.bus = &scsi_bus_type;
+	driver_register(&sd_template.scsi_driverfs_driver);
 	return 0;
 
 #undef init_mem_lth
@@ -1301,6 +1307,7 @@
 	for (k = 0; k < N_USED_SD_MAJORS; k++) {
 		vfree(sd_gendisks[k].de_arr);
 		vfree(sd_gendisks[k].flags);
+		vfree(sd_gendisks[k].driverfs_dev_arr);
 	}
 cleanup_mem:
 	vfree(sd_gendisks);
@@ -1435,6 +1442,8 @@
 	SD_GENDISK(dsk_nr).nr_real++;
         devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
         SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
+        SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] = 
+		&sdp->sdev_driverfs_dev;
         if (sdp->removable)
 		SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
 	sd_dskname(dsk_nr, diskname);
@@ -1534,6 +1543,8 @@
 	max_p = 1 << sd_gendisk.minor_shift;
 	start = dsk_nr << sd_gendisk.minor_shift;
 	dev = MKDEV_SD_PARTITION(start);
+	driverfs_remove_partitions(&SD_GENDISK (dsk_nr), 
+					SD_MINOR_NUMBER (start));
 	wipe_partitions(dev);
 	for (j = max_p - 1; j >= 0; j--)
 		sd_sizes[start + j] = 0;
@@ -1590,6 +1601,7 @@
 	sd_template.dev_max = 0;
 	if (sd_gendisks != &sd_gendisk)
 		vfree(sd_gendisks);
+	remove_driver(&sd_template.scsi_driverfs_driver);
 }
 
 static Scsi_Disk * sd_get_sdisk(int index)
diff -Naur linux-2.5.22.orig/drivers/scsi/sg.c linux-2.5.22-driverfs/drivers/scsi/sg.c
--- linux-2.5.22.orig/drivers/scsi/sg.c	Sun Jun 16 21:31:31 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sg.c	Mon Jun 17 21:17:48 2002
@@ -194,6 +194,7 @@
     volatile char detached;  /* 0->attached, 1->detached pending removal */
     volatile char exclude;   /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+    struct device sg_driverfs_dev;
 } Sg_device; /* 36 bytes long on i386 */
 
 
@@ -1347,6 +1348,9 @@
 #ifdef CONFIG_PROC_FS
     sg_proc_init();
 #endif  /* CONFIG_PROC_FS */
+    sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag;
+    sg_template.scsi_driverfs_driver.bus = &scsi_bus_type;
+    driver_register(&sg_template.scsi_driverfs_driver);
     return 0;
 }
 
@@ -1370,6 +1374,29 @@
 __setup("sg_def_reserved_size=", sg_def_reserved_size_setup);
 #endif
 
+/* Driverfs file support */
+static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off)
+{
+	Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
+	return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value);
+}
+static struct driver_file_entry sg_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sg_device_kdev_read,
+};
+
+static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sg_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sg_device_type_read,
+};
 
 static int sg_attach(Scsi_Device * scsidp)
 {
@@ -1428,6 +1455,18 @@
     sdp->detached = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
     sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
+
+    memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device));
+    sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
+	    scsidp->sdev_driverfs_dev.bus_id);
+    sprintf(sdp->sg_driverfs_dev.name, "%sgeneric", 
+	    scsidp->sdev_driverfs_dev.name);
+    sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
+    sdp->sg_driverfs_dev.bus = &scsi_bus_type;
+    device_register(&sdp->sg_driverfs_dev);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_type_file);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_kdev_file);
+
     sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
                              SCSI_GENERIC_MAJOR, k,
                              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
@@ -1496,6 +1535,9 @@
             }
 	    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
 	    devfs_unregister (sdp->de);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_type_file.name);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_kdev_file.name);
+	    put_device(&sdp->sg_driverfs_dev);
 	    sdp->de = NULL;
 	    if (NULL == sdp->headfp) {
 		kfree((char *)sdp);
@@ -1505,6 +1547,7 @@
         else { /* nothing active, simple case */
             SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 	    devfs_unregister (sdp->de);
+	    put_device(&sdp->sg_driverfs_dev);
 	    kfree((char *)sdp);
 	    sg_dev_arr[k] = NULL;
         }
@@ -1546,6 +1589,7 @@
         sg_dev_arr = NULL;
     }
     sg_template.dev_max = 0;
+    remove_driver(&sg_template.scsi_driverfs_driver);
 }
 
 
diff -Naur linux-2.5.22.orig/drivers/scsi/sr.c linux-2.5.22-driverfs/drivers/scsi/sr.c
--- linux-2.5.22.orig/drivers/scsi/sr.c	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sr.c	Mon Jun 17 21:19:13 2002
@@ -720,6 +720,9 @@
 	if (!sr_sizes)
 		goto cleanup_cds;
 	memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
+	sr_template.scsi_driverfs_driver.name = (char *)sr_template.tag;
+	sr_template.scsi_driverfs_driver.bus = &scsi_bus_type;
+	driver_register(&sr_template.scsi_driverfs_driver);
 	return 0;
 
 cleanup_cds:
@@ -730,6 +733,32 @@
 	return 1;
 }
 
+/* Driverfs file support */
+static ssize_t sr_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry sr_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sr_device_kdev_read,
+};
+
+static ssize_t sr_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sr_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sr_device_type_read,
+};
+
+
 void sr_finish()
 {
 	int i;
@@ -775,6 +804,20 @@
 
 		sprintf(name, "sr%d", i);
 		strcpy(SCp->cdi.name, name);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
+			SCp->device->sdev_driverfs_dev.bus_id);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.name, "%scdrom",
+			SCp->device->sdev_driverfs_dev.name);
+		SCp->cdi.cdrom_driverfs_dev.parent = 
+			&SCp->device->sdev_driverfs_dev;
+		SCp->cdi.cdrom_driverfs_dev.bus = &scsi_bus_type;
+		SCp->cdi.cdrom_driverfs_dev.driver_data = 
+			(void *)__mkdev(MAJOR_NR, i);
+		device_register(&SCp->cdi.cdrom_driverfs_dev);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_type_file);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_kdev_file);
                 SCp->cdi.de = devfs_register(SCp->device->de, "cd",
                                     DEVFS_FL_DEFAULT, MAJOR_NR, i,
                                     S_IFBLK | S_IRUGO | S_IWUGO,
@@ -832,6 +875,7 @@
 	blk_clear(MAJOR_NR);
 
 	sr_template.dev_max = 0;
+	remove_driver(&sr_template.scsi_driverfs_driver);
 }
 
 module_init(init_sr);
diff -Naur linux-2.5.22.orig/drivers/scsi/st.c linux-2.5.22-driverfs/drivers/scsi/st.c
--- linux-2.5.22.orig/drivers/scsi/st.c	Sun Jun 16 21:31:34 2002
+++ linux-2.5.22-driverfs/drivers/scsi/st.c	Mon Jun 17 21:18:05 2002
@@ -3677,6 +3677,31 @@
 
 #endif
 
+/* Driverfs file support */
+static ssize_t st_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry st_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: st_device_kdev_read,
+};
+
+static ssize_t st_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry st_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: st_device_type_read,
+};
+
 
 static struct file_operations st_fops =
 {
@@ -3779,6 +3804,18 @@
 
 	    /*  Rewind entry  */
 	    sprintf (name, "mt%s", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_r[mode].bus = &scsi_bus_type;
+	    tpnt->driverfs_dev_r[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5));
+	    device_register(&tpnt->driverfs_dev_r[mode]);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], 
+			       &st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], &st_device_kdev_file);
 	    tpnt->de_r[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5),
@@ -3786,6 +3823,19 @@
 				&st_fops, NULL);
 	    /*  No-rewind entry  */
 	    sprintf (name, "mt%sn", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_n[mode].bus = &scsi_bus_type;
+	    tpnt->driverfs_dev_n[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
+	    device_register(&tpnt->driverfs_dev_n[mode]);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_kdev_file);
 	    tpnt->de_n[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5) + 128,
@@ -3894,8 +3944,18 @@
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 				devfs_unregister (tpnt->de_r[mode]);
 				tpnt->de_r[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_r[mode]);
 				devfs_unregister (tpnt->de_n[mode]);
 				tpnt->de_n[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_n[mode]);
 			}
 			kfree(tpnt);
 			scsi_tapes[i] = 0;
@@ -3921,8 +3981,15 @@
 		verstr, st_buffer_size, st_write_threshold,
 		st_max_buffers, st_max_sg_segs);
 
-	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
-		return scsi_register_device(&st_template);
+	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) {
+		if (scsi_register_device(&st_template) == 0) {
+			st_template.scsi_driverfs_driver.name = 
+				(char *)st_template.tag;
+			st_template.scsi_driverfs_driver.bus = &scsi_bus_type;
+			driver_register(&st_template.scsi_driverfs_driver);
+			return 0;
+		}
+	}
 
 	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
 	return 1;
@@ -3951,6 +4018,7 @@
 		}
 	}
 	st_template.dev_max = 0;
+	remove_driver(&st_template.scsi_driverfs_driver);
 	printk(KERN_INFO "st: Unloaded.\n");
 }
 
diff -Naur linux-2.5.22.orig/drivers/scsi/st.h linux-2.5.22-driverfs/drivers/scsi/st.h
--- linux-2.5.22.orig/drivers/scsi/st.h	Sun Jun 16 21:31:28 2002
+++ linux-2.5.22-driverfs/drivers/scsi/st.h	Mon Jun 17 21:14:07 2002
@@ -94,6 +94,8 @@
 	int current_mode;
 	devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
 	devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
+	struct device driverfs_dev_r[ST_NBR_MODES];
+	struct device driverfs_dev_n[ST_NBR_MODES];
 
 	/* Status variables */
 	int partition;
diff -Naur linux-2.5.22.orig/fs/partitions/check.c linux-2.5.22-driverfs/fs/partitions/check.c
--- linux-2.5.22.orig/fs/partitions/check.c	Sun Jun 16 21:31:30 2002
+++ linux-2.5.22-driverfs/fs/partitions/check.c	Mon Jun 17 21:14:07 2002
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/raid/md.h>
 #include <linux/buffer_head.h>	/* for invalidate_bdev() */
+#include <linux/kmod.h>
 
 #include "check.h"
 
@@ -221,6 +222,136 @@
 #endif
 }
 
+/* Driverfs file support */
+static ssize_t partition_device_kdev_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf (page, "%x\n",kdev.value);
+}
+static struct driver_file_entry partition_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: partition_device_kdev_read,
+};
+
+static ssize_t partition_device_type_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "BLK\n");
+}
+static struct driver_file_entry partition_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: partition_device_type_read,
+};
+
+void driverfs_create_partitions(struct gendisk *hd, int minor)
+{
+	int pos = -1;
+	int devnum = minor >> hd->minor_shift;
+	char dirname[256];
+	struct device *parent = 0;
+	int max_p;
+	int part;
+	devfs_handle_t dir = 0;
+	
+	/* get parent driverfs device structure */
+	if (hd->driverfs_dev_arr)
+		parent = hd->driverfs_dev_arr[devnum];
+	else /* if driverfs not supported by subsystem, skip partitions */
+		return;
+	
+	/* get parent device node directory name */
+	if (hd->de_arr) {
+		dir = hd->de_arr[devnum];
+		if (dir)
+			pos = devfs_generate_path (dir, dirname, 
+						   sizeof dirname);
+	}
+	
+	if (pos < 0) {
+		disk_name(hd, minor, dirname);
+		pos = 0;
+	}
+	
+	max_p = (1 << hd->minor_shift);
+	
+	/* for all partitions setup parents and device node names */
+	for(part=0; part < max_p; part++) {
+		if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) {
+			struct device * current_driverfs_dev = 
+				&hd->part[minor+part].hd_driverfs_dev;
+			current_driverfs_dev->parent = parent;
+			/* handle disc case */
+			current_driverfs_dev->driver_data =
+					(void *)__mkdev(hd->major, minor+part);
+			if (part == 0) {
+				if (parent)  {
+					sprintf(current_driverfs_dev->name,
+						"%sdisc", parent->name);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:disc", parent->bus_id);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"disc");
+					sprintf(current_driverfs_dev->bus_id,
+						"disc");
+				}
+			} else { /* this is a partition */
+				if (parent) {
+					sprintf(current_driverfs_dev->name,
+						"%spart%d", parent->name, part);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:p%d", parent->bus_id, part);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"part%d", part);
+					sprintf(current_driverfs_dev->bus_id, 
+						"p%d" ,part);
+				}
+			}
+			if (parent) current_driverfs_dev->bus = parent->bus;
+			device_register(current_driverfs_dev);
+			device_create_file(current_driverfs_dev,
+					&partition_device_type_file);
+			device_create_file(current_driverfs_dev,
+					&partition_device_kdev_file);
+		}
+	}
+	return;
+}
+
+void driverfs_remove_partitions(struct gendisk *hd, int minor)
+{
+	int max_p;
+	int part;
+	struct device * current_driverfs_dev;
+	
+	max_p=(1 << hd->minor_shift);
+	
+	/* for all parts setup parent relationships and device node names */
+	for(part=1; part < max_p; part++) {
+		if ((hd->part[minor + part].nr_sects >= 1)) {
+			current_driverfs_dev = 
+				&hd->part[minor + part].hd_driverfs_dev;
+			device_remove_file(current_driverfs_dev,
+					partition_device_type_file.name);
+			device_remove_file(current_driverfs_dev,
+					partition_device_kdev_file.name);
+			put_device(current_driverfs_dev);	
+		}
+	}
+	current_driverfs_dev = &hd->part[minor].hd_driverfs_dev;
+	device_remove_file(current_driverfs_dev, 
+				partition_device_type_file.name);
+	device_remove_file(current_driverfs_dev, 
+				partition_device_kdev_file.name);
+	put_device(current_driverfs_dev);	
+	return;
+}
+
 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 {
 	devfs_handle_t de = NULL;
@@ -281,6 +412,13 @@
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 	bdput(bdev);
 	i = first_part_minor - 1;
+
+	/* Setup driverfs tree */
+	if (hd->sizes)
+		driverfs_create_partitions(hd, i);
+	else
+		driverfs_remove_partitions(hd, i);
+
 	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }
 
diff -Naur linux-2.5.22.orig/include/linux/cdrom.h linux-2.5.22-driverfs/include/linux/cdrom.h
--- linux-2.5.22.orig/include/linux/cdrom.h	Sun Jun 16 21:31:23 2002
+++ linux-2.5.22-driverfs/include/linux/cdrom.h	Mon Jun 17 21:14:07 2002
@@ -716,6 +716,7 @@
 
 #ifdef __KERNEL__
 #include <linux/devfs_fs_kernel.h>
+#include <linux/device.h>
 
 struct cdrom_write_settings {
 	unsigned char fpacket;		/* fixed/variable packets */
@@ -730,6 +731,7 @@
 	struct cdrom_device_info *next; /* next device_info for this major */
 	void *handle;		        /* driver-dependent data */
 	devfs_handle_t de;		/* real driver should create this  */
+	struct device cdrom_driverfs_dev; /* driverfs implementation */
 	int number;			/* generic driver updates this  */
 /* specifications */
         kdev_t dev;	                /* device number */
diff -Naur linux-2.5.22.orig/include/linux/genhd.h linux-2.5.22-driverfs/include/linux/genhd.h
--- linux-2.5.22.orig/include/linux/genhd.h	Sun Jun 16 21:31:26 2002
+++ linux-2.5.22-driverfs/include/linux/genhd.h	Mon Jun 17 21:14:07 2002
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/major.h>
+#include <linux/device.h>
 
 enum {
 /* These three have identical behaviour; use the second one if DOS fdisk gets
@@ -62,6 +63,7 @@
 	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
 	int number;                     /* stupid old code wastes space  */
+	struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -80,6 +82,7 @@
 	struct block_device_operations *fops;
 
 	devfs_handle_t *de_arr;         /* one per physical disc */
+	struct device **driverfs_dev_arr;/* support driverfs hierarchy */
 	char *flags;                    /* one per physical disc */
 };
 
@@ -241,6 +244,7 @@
 
 extern void devfs_register_partitions (struct gendisk *dev, int minor,
 				       int unregister);
+extern void driverfs_remove_partitions (struct gendisk *hd, int minor);
 
 static inline unsigned int disk_index (kdev_t dev)
 {
diff -Naur linux-2.5.22.orig/kernel/ksyms.c linux-2.5.22-driverfs/kernel/ksyms.c
--- linux-2.5.22.orig/kernel/ksyms.c	Sun Jun 16 21:31:23 2002
+++ linux-2.5.22-driverfs/kernel/ksyms.c	Mon Jun 17 21:14:07 2002
@@ -335,6 +335,7 @@
 EXPORT_SYMBOL(set_device_ro);
 EXPORT_SYMBOL(bmap);
 EXPORT_SYMBOL(devfs_register_partitions);
+EXPORT_SYMBOL(driverfs_remove_partitions);
 EXPORT_SYMBOL(blkdev_open);
 EXPORT_SYMBOL(blkdev_get);
 EXPORT_SYMBOL(blkdev_put);

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

* Re: [PATCH][RFC] Driverfs support for SCSI devices
  2002-06-17 21:18 [PATCH][RFC] Driverfs support for SCSI devices sullivan
@ 2002-06-17 23:16 ` James Bottomley
  2002-06-18 21:56   ` [PATCH][RFC] Driverfs support for SCSI devices (updated) sullivan
  0 siblings, 1 reply; 3+ messages in thread
From: James Bottomley @ 2002-06-17 23:16 UTC (permalink / raw)
  To: sullivan; +Cc: linux-kernel, linux-scsi

I get a BUG in device.h:213 trying to insert the st.o module, but other than 
that, it seems to be running OK.

You forgot to export the symbol scsi_bus_type which is needed for sd et al. to 
compile as modules.

This code:

+/* Driverfs file content handlers */
+char * scsi_type_names[] = {
+	"DISK",
+	"TAPE",
+	NULL,
+	"PROCESSOR",
+	"WORM",
+	"ROM",
+	"SCANNER",
+	"MOD",
+	"MEDIUM_CHANGER",
+	"COMM",
+	NULL,
+	NULL,
+	NULL,
+	"ENCLOSURE"};

Duplicates the scsi_device_types array (in scsi.c), but with slightly 
different names.  Could you use the same array? otherwise we're going to get 
different device types from driverfs and /proc/scsi/scsi.

And, of course, for a legacy array, all the LUNs have the same name:

3:0:3:0/  3:0:3:1/  3:0:3:2/  3:0:3:3/  name  power
jroot@malley> cat 3\:0\:3\:*/name
S1T41711424NCR
S1T41711424NCR
S1T41711424NCR
S1T41711424NCR

James

Oops trace for st insert:kernel BUG at /mnt2/jejb/BK/BUILD-2.5/include/linux/de
vice.h:213!
invalid operand: 0000
CPU:    0
EIP:    0010:[<c0178624>]    Not tainted
Using defaults from ksymoops -t elf32-i386 -a i386
EFLAGS: 00010246
eax: 00000000   ebx: f7d7e000   ecx: 00000000   edx: f7d7e004
esi: f88c81a0   edi: fffffff4   ebp: f7d7e3c4   esp: f7c5be68
ds: 0018   es: 0018   ss: 0018
Stack: f7d7e000 00000000 f7d7e3c4 f7c5bee4 f88c67a9 f7d7e3c4 f88c81a0 f7d7e3c4 
       f7d7e0a4 00000000 f7d7e130 f7d7e0e0 00000140 00000160 00000900 f7d7e0b4 
       f7d7e3f0 00000450 00000470 00000980 f7c5bee4 f7d7e004 f7d7e008 f7751d2c 
Call Trace: [<f88c67a9>] [<f88c81a0>] [<f88c8080>] [<f88096aa>] [<f88c6c78>] 
   [<f88c8080>] [<c011afc7>] [<f88c82ec>] [<f88c1060>] [<c0108977>] 
Code: 0f 0b d5 00 c0 76 20 c0 f0 ff 85 90 00 00 00 68 f0 01 00 00 

>>EIP; c0178624 <device_create_file+24/80>   <=====
Trace; f88c67a9 <[st]st_attach+489/760>
Trace; f88c81a0 <[st]st_device_type_file+0/20>
Trace; f88c8080 <[st]st_template+0/90>
Trace; f88096aa <[scsi_mod]scsi_register_device+aa/140>
Trace; f88c6c78 <[st]init_st+58/a0>
Trace; f88c8080 <[st]st_template+0/90>
Trace; c011afc7 <inter_module_put+797/870>
Trace; f88c82ec <[st].bss.end+1/6>
Trace; f88c1060 <[st]st_incompatible+0/f0>
Trace; c0108977 <__read_lock_failed+1137/3740>
Code;  c0178624 <device_create_file+24/80>
00000000 <_EIP>:
Code;  c0178624 <device_create_file+24/80>   <=====
   0:   0f 0b                     ud2a      <=====
Code;  c0178626 <device_create_file+26/80>
   2:   d5 00                     aad    $0x0
Code;  c0178628 <device_create_file+28/80>
   4:   c0                        (bad)  
Code;  c0178629 <device_create_file+29/80>
   5:   76 20                     jbe    27 <_EIP+0x27> c017864b 
<device_create_file+4b/80>
Code;  c017862b <device_create_file+2b/80>
   7:   c0                        (bad)  
Code;  c017862c <device_create_file+2c/80>
   8:   f0 ff 85 90 00 00 00      lock incl 0x90(%ebp)
Code;  c0178633 <device_create_file+33/80>
   f:   68 f0 01 00 00            push   $0x1f0









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

* Re: [PATCH][RFC] Driverfs support for SCSI devices (updated)
  2002-06-17 23:16 ` James Bottomley
@ 2002-06-18 21:56   ` sullivan
  0 siblings, 0 replies; 3+ messages in thread
From: sullivan @ 2002-06-18 21:56 UTC (permalink / raw)
  To: linux-kernel, linux-scsi; +Cc: James.Bottomley

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

On Mon, Jun 17, 2002 at 06:16:53PM -0500, James Bottomley wrote:
> I get a BUG in device.h:213 trying to insert the st.o module, but other than 
> that, it seems to be running OK.

Thanks James. Attached is an updated patch that fixes the st.o module and incorporates your other suggestions. The updated patch is also available at
http://www-124.ibm.com/devreg/linux-2.5.22-driverfs.patch.gz

[-- Attachment #2: linux-2.5.22-driverfs.patch --]
[-- Type: text/plain, Size: 38375 bytes --]

diff -Naur linux-2.5.22.orig/drivers/cdrom/cdrom.c linux-2.5.22-driverfs/drivers/cdrom/cdrom.c
--- linux-2.5.22.orig/drivers/cdrom/cdrom.c	Sun Jun 16 21:31:26 2002
+++ linux-2.5.22-driverfs/drivers/cdrom/cdrom.c	Mon Jun 17 21:14:07 2002
@@ -431,6 +431,11 @@
 		topCdromPtr = cdi->next;
 	cdi->ops->n_minors--;
 	devfs_unregister (cdi->de);
+	if (atomic_read (&cdi->cdrom_driverfs_dev.refcount)) {
+		device_remove_file (&cdi->cdrom_driverfs_dev, "name");
+		device_remove_file (&cdi->cdrom_driverfs_dev, "kdev");
+		put_device (&cdi->cdrom_driverfs_dev);
+	}
 	devfs_dealloc_unique_number (&cdrom_numspace, cdi->number);
 	cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" unregistered\n", cdi->name);
 	return 0;
diff -Naur linux-2.5.22.orig/drivers/scsi/hosts.h linux-2.5.22-driverfs/drivers/scsi/hosts.h
--- linux-2.5.22.orig/drivers/scsi/hosts.h	Sun Jun 16 21:31:29 2002
+++ linux-2.5.22-driverfs/drivers/scsi/hosts.h	Mon Jun 17 21:14:07 2002
@@ -418,6 +418,11 @@
      */
     struct pci_dev *pci_dev;
 
+    /* 
+     * Support for driverfs filesystem
+     */
+    struct device host_driverfs_dev;
+
     /*
      * We should ensure that this is aligned, both for better performance
      * and also because some compilers (m68k) don't automatically force
@@ -478,6 +483,7 @@
                                        struct pci_dev *pdev)
 {
 	SHpnt->pci_dev = pdev;
+	SHpnt->host_driverfs_dev.parent=&pdev->dev;
 }
 
 
@@ -516,6 +522,7 @@
     void (*detach)(Scsi_Device *);
     int (*init_command)(Scsi_Cmnd *);     /* Used by new queueing code. 
                                            Selects command for blkdevs */
+    struct device_driver scsi_driverfs_driver;
 };
 
 void  scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt);
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi.c linux-2.5.22-driverfs/drivers/scsi/scsi.c
--- linux-2.5.22.orig/drivers/scsi/scsi.c	Sun Jun 16 21:31:33 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi.c	Tue Jun 18 21:15:19 2002
@@ -1939,6 +1939,11 @@
 				}
 				printk(KERN_INFO "scsi%d : %s\n",		/* And print a little message */
 				       shpnt->host_no, name);
+				strncpy(shpnt->host_driverfs_dev.name,name,
+					DEVICE_NAME_SIZE-1);
+				sprintf(shpnt->host_driverfs_dev.bus_id,
+					"scsi%d",
+					shpnt->host_no);
 			}
 		}
 
@@ -1947,6 +1952,8 @@
 		 */
 		for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
 			if (shpnt->hostt == tpnt) {
+				/* first register parent with driverfs */
+				device_register(&shpnt->host_driverfs_dev);
 				scan_scsis(shpnt, 0, 0, 0, 0);
 				if (shpnt->select_queue_depths != NULL) {
 					(shpnt->select_queue_depths) (shpnt, shpnt->host_queue);
@@ -2101,6 +2108,7 @@
 				goto err_out;
 			}
 			devfs_unregister (SDpnt->de);
+			put_device(&SDpnt->sdev_driverfs_dev);
 		}
 	}
 
@@ -2151,6 +2159,7 @@
 		/* Remove the /proc/scsi directory entry */
 		sprintf(name,"%d",shpnt->host_no);
 		remove_proc_entry(name, tpnt->proc_dir);
+		put_device(&shpnt->host_driverfs_dev);
 		if (tpnt->release)
 			(*tpnt->release) (shpnt);
 		else {
@@ -2499,6 +2508,34 @@
 	mempool_free(sgl, sgp->pool);
 }
 
+static int scsi_bus_match(struct device *scsi_driverfs_dev, 
+                          struct device_driver *scsi_driverfs_drv)
+{
+        char *p=0;
+
+        if (!strcmp("sd", scsi_driverfs_drv->name)) {
+                if ((p = strstr(scsi_driverfs_dev->bus_id, ":disc")) || 
+		    (p = strstr(scsi_driverfs_dev->bus_id, ":p"))) { 
+                        return 1;
+                }
+        } else if (!strcmp("sg", scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id, ":gen"))
+                        return 1;
+        } else if (!strcmp("sr",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":cd"))
+                        return 1;
+        } else if (!strcmp("st",scsi_driverfs_drv->name)) {
+                if (strstr(scsi_driverfs_dev->bus_id,":mt"))
+                        return 1;
+        }
+        return 0;
+}
+
+struct bus_type scsi_driverfs_bus_type = {
+        name: "scsi",
+        match: scsi_bus_match,
+};
+
 static int __init init_scsi(void)
 {
 	struct proc_dir_entry *generic;
@@ -2544,6 +2581,8 @@
         if (scsihosts)
 		printk(KERN_INFO "scsi: host order: %s\n", scsihosts);	
 	scsi_host_no_init (scsihosts);
+
+	bus_register(&scsi_driverfs_bus_type);
 	/*
 	 * This is where the processing takes place for most everything
 	 * when commands are completed.
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi.h linux-2.5.22-driverfs/drivers/scsi/scsi.h
--- linux-2.5.22.orig/drivers/scsi/scsi.h	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi.h	Tue Jun 18 18:10:20 2002
@@ -417,6 +417,8 @@
 extern volatile int in_scan_scsis;
 extern const unsigned char scsi_command_size[8];
 
+extern struct bus_type scsi_driverfs_bus_type;
+
 
 /*
  * These are the error handling functions defined in scsi_error.c
@@ -622,6 +624,7 @@
 
 	// Flag to allow revalidate to succeed in sd_open
 	int allow_revalidate;
+	struct device sdev_driverfs_dev;
 };
 
 
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi_scan.c linux-2.5.22-driverfs/drivers/scsi/scsi_scan.c
--- linux-2.5.22.orig/drivers/scsi/scsi_scan.c	Sun Jun 16 21:31:35 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi_scan.c	Tue Jun 18 18:21:26 2002
@@ -54,6 +54,7 @@
 		char *scsi_result);
 static int find_lun0_scsi_level(unsigned int channel, unsigned int dev,
 				struct Scsi_Host *shpnt);
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt);
 
 struct dev_info {
 	const char *vendor;
@@ -288,6 +289,31 @@
 }
 #endif
 
+/* Driverfs file content handlers */
+static ssize_t scsi_device_type_read(struct device *driverfs_dev, char *page, 
+	size_t count, loff_t off)
+{
+	struct scsi_device *SDpnt = list_entry(driverfs_dev,
+		struct scsi_device, sdev_driverfs_dev);
+
+	if ((SDpnt->type <= MAX_SCSI_DEVICE_CODE) && 
+		(scsi_device_types[(int)SDpnt->type] != NULL))
+		return off ? 0 : 
+			sprintf(page, "%s\n", 
+				scsi_device_types[(int)SDpnt->type]);
+	else
+		return off ? 0 : sprintf(page, "UNKNOWN\n");
+
+	return 0;
+}
+
+static struct driver_file_entry scsi_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: scsi_device_type_read,
+};
+/* end content handlers */
+
 static void print_inquiry(unsigned char *data)
 {
 	int i;
@@ -786,6 +812,22 @@
 
 	print_inquiry(scsi_result);
 
+	/* interrogate scsi target to provide device identifier */
+	scsi_load_identifier(SDpnt, SRpnt);
+
+	/* create driverfs files */
+	sprintf(SDpnt->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
+		SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
+	
+	SDpnt->sdev_driverfs_dev.parent = &SDpnt->host->host_driverfs_dev;
+	SDpnt->sdev_driverfs_dev.bus = &scsi_driverfs_bus_type;
+
+	device_register(&SDpnt->sdev_driverfs_dev); 
+
+	/* Create driverfs file entries */
+	device_create_file(&SDpnt->sdev_driverfs_dev, 
+			&scsi_device_type_file);
+
         sprintf (devname, "host%d/bus%d/target%d/lun%d",
                  SDpnt->host->host_no, SDpnt->channel, SDpnt->id, SDpnt->lun);
         if (SDpnt->de) printk ("DEBUG: dir: \"%s\" already exists\n", devname);
@@ -1306,3 +1348,374 @@
 	/* haven't found lun0, should send INQUIRY but take easy route */
 	return res;
 }
+
+#define SCSI_UID_DEV_ID  'U'
+#define SCSI_UID_SER_NUM 'S'
+#define SCSI_UID_UNKNOWN 'Z'
+
+unsigned char *scsi_get_evpd_page(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	evpd_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC));
+	if (!evpd_page)
+		return NULL;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd) {
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x00;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		kfree(evpd_page);
+		return NULL;
+	}
+
+	/* check to see if response was truncated */
+	if (evpd_page[3] > 255) {
+		int max_lgth = evpd_page[3] + 4;
+
+		kfree(evpd_page);
+		evpd_page = kmalloc(max_lgth, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!evpd_page) {
+			kfree(scsi_cmd);
+			return NULL;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x00;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) evpd_page,
+			max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	kfree(scsi_cmd);
+	/* some ill behaved devices return the std inquiry here rather than
+		the evpd data. snoop the data to verify */
+	if (evpd_page[3] > 16) {
+		/* if vend id appears in the evpd page assume evpd is invalid */
+		if (!strncmp(&evpd_page[8], SDpnt->vendor, 8)) {
+			kfree(evpd_page);
+			return NULL;
+		}
+	}
+	return evpd_page;
+}
+
+int scsi_get_deviceid(Scsi_Device *SDpnt,Scsi_Request * SRpnt)
+{
+	unsigned char *id_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int scnt, i, j, idtype;
+	char * id = SDpnt->sdev_driverfs_dev.name;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+
+	id_page = kmalloc(255, 
+		(SDpnt->host->unchecked_isa_dma ? GFP_DMA : GFP_ATOMIC)); 
+	if (!id_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x83;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+
+	/* check to see if response was truncated */
+	if (id_page[3] > 255) {
+		int max_lgth = id_page[3] + 4;
+
+		kfree(id_page);
+		id_page = kmalloc(max_lgth,
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC)); 
+		if (!id_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x83;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) id_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	idtype = 3;
+	while (idtype > 0) {
+		for(scnt = 4; scnt <= id_page[3] + 3; 
+		    scnt += id_page[scnt + 3] + 4) {
+			if ((id_page[scnt + 1] & 0x0f) != idtype) {
+				continue;
+			}
+			if ((id_page[scnt] & 0x0f) == 2) {  
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if (id_page[i] > 0x20) {
+						if (j == DEVICE_NAME_SIZE) {
+							memset(id, 0, 
+							    DEVICE_NAME_SIZE);
+							break;
+						}
+						id[j++] = id_page[i];
+					}
+				}
+			} else if ((id_page[scnt] & 0x0f) == 1) {
+				static const char hex_str[]="0123456789abcdef";
+				for(i = scnt + 4, j = 1;
+				    i < scnt + 4 + id_page[scnt + 3]; 
+				    i++) {
+					if ((j + 1) == DEVICE_NAME_SIZE) {
+						memset(id, 0, DEVICE_NAME_SIZE);
+						break;
+					}
+					id[j++] = hex_str[(id_page[i] & 0xf0) >>
+								4];
+					id[j++] = hex_str[id_page[i] & 0x0f];
+				}
+			}
+			if (id[1] != 0) goto leave;
+		}
+		idtype--;
+	}
+ leave:
+	kfree(id_page);
+	if (id[1] != 0) {
+		id[0] = SCSI_UID_DEV_ID;
+		return 1;
+	}
+	return 0;
+}
+
+int scsi_get_serialnumber(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *serialnumber_page = NULL;
+	unsigned char *scsi_cmd = NULL;
+	int lun = SDpnt->lun;
+	int scsi_level = SDpnt->scsi_level;
+	int i, j;
+
+	serialnumber_page = kmalloc(255, (SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+	if (!serialnumber_page)
+		return 0;
+
+	scsi_cmd = kmalloc(MAX_COMMAND_SIZE, GFP_ATOMIC);
+	if (!scsi_cmd)
+		goto leave;
+
+	/* Use vital product pages to determine serial number */
+	/* Try Supported vital product data pages 0x00 first */
+	scsi_cmd[0] = INQUIRY;
+	if ((lun > 0) && (scsi_level <= SCSI_2))
+		scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+	else	
+		scsi_cmd[1] = 0x01;	/* SCSI_3 and higher, don't touch */
+	scsi_cmd[2] = 0x80;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 255;
+	scsi_cmd[5] = 0;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_sense_buffer[2] = 0;
+	SRpnt->sr_data_direction = SCSI_DATA_READ;
+	scsi_wait_req(SRpnt, (void *) scsi_cmd, (void *) serialnumber_page,
+			255, SCSI_TIMEOUT+4*HZ, 3);
+
+	if (SRpnt->sr_result) {
+		kfree(scsi_cmd);
+		goto leave;
+	}
+	/* check to see if response was truncated */
+	if (serialnumber_page[3] > 255) {
+		int max_lgth = serialnumber_page[3] + 4;
+
+		kfree(serialnumber_page);
+		serialnumber_page = kmalloc(max_lgth, 
+			(SDpnt->host->unchecked_isa_dma ? 
+			GFP_DMA : GFP_ATOMIC));
+		if (!serialnumber_page) {
+			kfree(scsi_cmd);
+			return 0;
+		}
+		memset(scsi_cmd, 0, MAX_COMMAND_SIZE);
+		scsi_cmd[0] = INQUIRY;
+		if ((lun > 0) && (scsi_level <= SCSI_2))
+			scsi_cmd[1] = ((lun << 5) & 0xe0) | 0x01;
+		else
+			scsi_cmd[1] = 0x01; /* SCSI_3 and higher, don't touch */
+		scsi_cmd[2] = 0x80;
+		scsi_cmd[3] = 0;
+		scsi_cmd[4] = max_lgth;
+		scsi_cmd[5] = 0;
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		scsi_wait_req(SRpnt, (void *) scsi_cmd, 
+				(void *) serialnumber_page,
+				max_lgth, SCSI_TIMEOUT+4*HZ, 3);
+		if (SRpnt->sr_result) {
+			kfree(scsi_cmd);
+			goto leave;
+		}
+	}
+	kfree(scsi_cmd);
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_SER_NUM;
+	for(i = 0, j = 1; i < serialnumber_page[3]; i++) {
+		if (serialnumber_page[4 + i] > 0x20)
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				serialnumber_page[4 + i];
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->vendor[i];
+		}
+	}
+	kfree(serialnumber_page);
+	return 1;
+ leave:
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	kfree(serialnumber_page);
+	return 0;
+}
+
+int scsi_get_default_name(Scsi_Device *SDpnt)
+{
+	int i, j;
+
+	SDpnt->sdev_driverfs_dev.name[0] = SCSI_UID_UNKNOWN;
+	for(i = 0, j = 1; i < 8; i++) {
+		if (SDpnt->vendor[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->vendor[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); 
+	    i < 16; i++) {
+		if (SDpnt->model[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = 
+				SDpnt->model[i];
+		}
+	}
+	for(i = 0, j = strlen(SDpnt->sdev_driverfs_dev.name); i < 4; i++) {
+		if (SDpnt->rev[i] > 0x20) {
+			SDpnt->sdev_driverfs_dev.name[j++] = SDpnt->rev[i];
+		}
+	}	
+	return 1;
+}
+
+
+static void scsi_load_identifier(Scsi_Device *SDpnt, Scsi_Request * SRpnt)
+{
+	unsigned char *evpd_page = NULL;
+	int cnt;
+
+	memset(SDpnt->sdev_driverfs_dev.name, 0, DEVICE_NAME_SIZE);
+	evpd_page = scsi_get_evpd_page(SDpnt, SRpnt);
+	if (!evpd_page) {
+		/* try to obtain serial number anyway */
+		if (!scsi_get_serialnumber(SDpnt, SRpnt))
+			goto leave;
+		goto leave;
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x83) {
+			if (scsi_get_deviceid(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+	for(cnt = 4; cnt <= evpd_page[3] + 3; cnt++) {
+		if (evpd_page[cnt] == 0x80) {
+			if (scsi_get_serialnumber(SDpnt, SRpnt))
+				goto leave;
+		}
+	}
+
+leave:
+	if (SDpnt->sdev_driverfs_dev.name[0] == 0)
+		scsi_get_default_name(SDpnt);
+
+	if (evpd_page) kfree(evpd_page);
+	return;
+}
diff -Naur linux-2.5.22.orig/drivers/scsi/scsi_syms.c linux-2.5.22-driverfs/drivers/scsi/scsi_syms.c
--- linux-2.5.22.orig/drivers/scsi/scsi_syms.c	Sun Jun 16 21:31:32 2002
+++ linux-2.5.22-driverfs/drivers/scsi/scsi_syms.c	Tue Jun 18 21:13:34 2002
@@ -101,3 +101,8 @@
 extern int scsi_delete_timer(Scsi_Cmnd *);
 EXPORT_SYMBOL(scsi_add_timer);
 EXPORT_SYMBOL(scsi_delete_timer);
+
+/*
+ * driverfs support for determining driver types
+ */
+EXPORT_SYMBOL(scsi_driverfs_bus_type);
diff -Naur linux-2.5.22.orig/drivers/scsi/sd.c linux-2.5.22-driverfs/drivers/scsi/sd.c
--- linux-2.5.22.orig/drivers/scsi/sd.c	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sd.c	Tue Jun 18 22:45:19 2002
@@ -128,6 +128,7 @@
 
 static Scsi_Disk * sd_get_sdisk(int index);
 
+extern void driverfs_remove_partitions(struct gendisk *hd, int minor);
 
 #if defined(CONFIG_PPC32)
 /**
@@ -1276,12 +1277,15 @@
 
 		init_mem_lth(sd_gendisks[k].de_arr, N);
 		init_mem_lth(sd_gendisks[k].flags, N);
+		init_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
-		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags)
+		if (!sd_gendisks[k].de_arr || !sd_gendisks[k].flags ||
+				!sd_gendisks[k].driverfs_dev_arr)
 			goto cleanup_gendisks;
 
 		zero_mem_lth(sd_gendisks[k].de_arr, N);
 		zero_mem_lth(sd_gendisks[k].flags, N);
+		zero_mem_lth(sd_gendisks[k].driverfs_dev_arr, N);
 
 		sd_gendisks[k].major = SD_MAJOR(k);
 		sd_gendisks[k].major_name = "sd";
@@ -1290,7 +1294,6 @@
 		sd_gendisks[k].sizes = sd_sizes + k * (N << 4);
 		sd_gendisks[k].nr_real = 0;
 	}
-
 	return 0;
 
 #undef init_mem_lth
@@ -1301,6 +1304,7 @@
 	for (k = 0; k < N_USED_SD_MAJORS; k++) {
 		vfree(sd_gendisks[k].de_arr);
 		vfree(sd_gendisks[k].flags);
+		vfree(sd_gendisks[k].driverfs_dev_arr);
 	}
 cleanup_mem:
 	vfree(sd_gendisks);
@@ -1435,6 +1439,8 @@
 	SD_GENDISK(dsk_nr).nr_real++;
         devnum = dsk_nr % SCSI_DISKS_PER_MAJOR;
         SD_GENDISK(dsk_nr).de_arr[devnum] = sdp->de;
+        SD_GENDISK(dsk_nr).driverfs_dev_arr[devnum] = 
+		&sdp->sdev_driverfs_dev;
         if (sdp->removable)
 		SD_GENDISK(dsk_nr).flags[devnum] |= GENHD_FL_REMOVABLE;
 	sd_dskname(dsk_nr, diskname);
@@ -1534,6 +1540,8 @@
 	max_p = 1 << sd_gendisk.minor_shift;
 	start = dsk_nr << sd_gendisk.minor_shift;
 	dev = MKDEV_SD_PARTITION(start);
+	driverfs_remove_partitions(&SD_GENDISK (dsk_nr), 
+					SD_MINOR_NUMBER (start));
 	wipe_partitions(dev);
 	for (j = max_p - 1; j >= 0; j--)
 		sd_sizes[start + j] = 0;
@@ -1555,9 +1563,16 @@
  **/
 static int __init init_sd(void)
 {
+	int rc;
 	SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
 	sd_template.module = THIS_MODULE;
-	return scsi_register_device(&sd_template);
+	rc = scsi_register_device(&sd_template);
+	if (!rc) {
+		sd_template.scsi_driverfs_driver.name = (char *)sd_template.tag;
+		sd_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sd_template.scsi_driverfs_driver);
+	}
+	return rc;
 }
 
 /**
@@ -1590,6 +1605,7 @@
 	sd_template.dev_max = 0;
 	if (sd_gendisks != &sd_gendisk)
 		vfree(sd_gendisks);
+	remove_driver(&sd_template.scsi_driverfs_driver);
 }
 
 static Scsi_Disk * sd_get_sdisk(int index)
diff -Naur linux-2.5.22.orig/drivers/scsi/sg.c linux-2.5.22-driverfs/drivers/scsi/sg.c
--- linux-2.5.22.orig/drivers/scsi/sg.c	Sun Jun 16 21:31:31 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sg.c	Tue Jun 18 22:43:06 2002
@@ -194,6 +194,7 @@
     volatile char detached;  /* 0->attached, 1->detached pending removal */
     volatile char exclude;   /* opened for exclusive access */
     char sgdebug;       /* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+    struct device sg_driverfs_dev;
 } Sg_device; /* 36 bytes long on i386 */
 
 
@@ -1370,6 +1371,29 @@
 __setup("sg_def_reserved_size=", sg_def_reserved_size_setup);
 #endif
 
+/* Driverfs file support */
+static ssize_t sg_device_kdev_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off)
+{
+	Sg_device * sdp=list_entry(driverfs_dev, Sg_device, sg_driverfs_dev);
+	return off ? 0 : sprintf(page, "%x\n",sdp->i_rdev.value);
+}
+static struct driver_file_entry sg_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sg_device_kdev_read,
+};
+
+static ssize_t sg_device_type_read(struct device *driverfs_dev, char *page, 
+		size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sg_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sg_device_type_read,
+};
 
 static int sg_attach(Scsi_Device * scsidp)
 {
@@ -1428,6 +1452,18 @@
     sdp->detached = 0;
     sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
     sdp->i_rdev = mk_kdev(SCSI_GENERIC_MAJOR, k);
+
+    memset(&sdp->sg_driverfs_dev, 0, sizeof(struct device));
+    sprintf(sdp->sg_driverfs_dev.bus_id, "%s:gen",
+	    scsidp->sdev_driverfs_dev.bus_id);
+    sprintf(sdp->sg_driverfs_dev.name, "%sgeneric", 
+	    scsidp->sdev_driverfs_dev.name);
+    sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev;
+    sdp->sg_driverfs_dev.bus = &scsi_driverfs_bus_type;
+    device_register(&sdp->sg_driverfs_dev);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_type_file);
+    device_create_file(&sdp->sg_driverfs_dev, &sg_device_kdev_file);
+
     sdp->de = devfs_register (scsidp->de, "generic", DEVFS_FL_DEFAULT,
                              SCSI_GENERIC_MAJOR, k,
                              S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
@@ -1496,6 +1532,9 @@
             }
 	    SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
 	    devfs_unregister (sdp->de);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_type_file.name);
+	    device_remove_file(&sdp->sg_driverfs_dev,sg_device_kdev_file.name);
+	    put_device(&sdp->sg_driverfs_dev);
 	    sdp->de = NULL;
 	    if (NULL == sdp->headfp) {
 		kfree((char *)sdp);
@@ -1505,6 +1544,7 @@
         else { /* nothing active, simple case */
             SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 	    devfs_unregister (sdp->de);
+	    put_device(&sdp->sg_driverfs_dev);
 	    kfree((char *)sdp);
 	    sg_dev_arr[k] = NULL;
         }
@@ -1529,9 +1569,16 @@
 MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
 
 static int __init init_sg(void) {
+    int rc;
     if (def_reserved_size >= 0)
 	sg_big_buff = def_reserved_size;
-    return scsi_register_device(&sg_template);
+    rc = scsi_register_device(&sg_template);
+    if (!rc) {
+	sg_template.scsi_driverfs_driver.name = (char *)sg_template.tag;
+	sg_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+	driver_register(&sg_template.scsi_driverfs_driver);
+    }
+    return rc; 
 }
 
 static void __exit exit_sg( void)
@@ -1546,6 +1593,7 @@
         sg_dev_arr = NULL;
     }
     sg_template.dev_max = 0;
+    remove_driver(&sg_template.scsi_driverfs_driver);
 }
 
 
diff -Naur linux-2.5.22.orig/drivers/scsi/sr.c linux-2.5.22-driverfs/drivers/scsi/sr.c
--- linux-2.5.22.orig/drivers/scsi/sr.c	Sun Jun 16 21:31:27 2002
+++ linux-2.5.22-driverfs/drivers/scsi/sr.c	Tue Jun 18 22:44:21 2002
@@ -730,6 +730,32 @@
 	return 1;
 }
 
+/* Driverfs file support */
+static ssize_t sr_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry sr_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: sr_device_kdev_read,
+};
+
+static ssize_t sr_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry sr_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: sr_device_type_read,
+};
+
+
 void sr_finish()
 {
 	int i;
@@ -775,6 +801,20 @@
 
 		sprintf(name, "sr%d", i);
 		strcpy(SCp->cdi.name, name);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.bus_id, "%s:cd",
+			SCp->device->sdev_driverfs_dev.bus_id);
+		sprintf(SCp->cdi.cdrom_driverfs_dev.name, "%scdrom",
+			SCp->device->sdev_driverfs_dev.name);
+		SCp->cdi.cdrom_driverfs_dev.parent = 
+			&SCp->device->sdev_driverfs_dev;
+		SCp->cdi.cdrom_driverfs_dev.bus = &scsi_driverfs_bus_type;
+		SCp->cdi.cdrom_driverfs_dev.driver_data = 
+			(void *)__mkdev(MAJOR_NR, i);
+		device_register(&SCp->cdi.cdrom_driverfs_dev);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_type_file);
+		device_create_file(&SCp->cdi.cdrom_driverfs_dev,
+				&sr_device_kdev_file);
                 SCp->cdi.de = devfs_register(SCp->device->de, "cd",
                                     DEVFS_FL_DEFAULT, MAJOR_NR, i,
                                     S_IFBLK | S_IRUGO | S_IWUGO,
@@ -815,7 +855,14 @@
 
 static int __init init_sr(void)
 {
-	return scsi_register_device(&sr_template);
+	int rc;
+	rc = scsi_register_device(&sr_template);
+	if (!rc) {
+		sr_template.scsi_driverfs_driver.name = (char *)sr_template.tag;
+		sr_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
+		driver_register(&sr_template.scsi_driverfs_driver);
+	}
+	return rc;
 }
 
 static void __exit exit_sr(void)
@@ -832,6 +879,7 @@
 	blk_clear(MAJOR_NR);
 
 	sr_template.dev_max = 0;
+	remove_driver(&sr_template.scsi_driverfs_driver);
 }
 
 module_init(init_sr);
diff -Naur linux-2.5.22.orig/drivers/scsi/st.c linux-2.5.22-driverfs/drivers/scsi/st.c
--- linux-2.5.22.orig/drivers/scsi/st.c	Sun Jun 16 21:31:34 2002
+++ linux-2.5.22-driverfs/drivers/scsi/st.c	Tue Jun 18 18:09:33 2002
@@ -3677,6 +3677,31 @@
 
 #endif
 
+/* Driverfs file support */
+static ssize_t st_device_kdev_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf(page, "%x\n",kdev.value);
+}
+static struct driver_file_entry st_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: st_device_kdev_read,
+};
+
+static ssize_t st_device_type_read(struct device *driverfs_dev, 
+				   char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "CHR\n");
+}
+static struct driver_file_entry st_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: st_device_type_read,
+};
+
 
 static struct file_operations st_fops =
 {
@@ -3779,6 +3804,18 @@
 
 	    /*  Rewind entry  */
 	    sprintf (name, "mt%s", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_r[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5));
+	    device_register(&tpnt->driverfs_dev_r[mode]);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], 
+			       &st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_r[mode], &st_device_kdev_file);
 	    tpnt->de_r[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5),
@@ -3786,6 +3823,19 @@
 				&st_fops, NULL);
 	    /*  No-rewind entry  */
 	    sprintf (name, "mt%sn", formats[mode]);
+	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", 
+		    SDp->sdev_driverfs_dev.name, name);
+	    tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
+	    tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
+	    tpnt->driverfs_dev_n[mode].driver_data =
+			(void *)__mkdev(MAJOR_NR, i + (mode << 5) + 128);
+	    device_register(&tpnt->driverfs_dev_n[mode]);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_type_file);
+	    device_create_file(&tpnt->driverfs_dev_n[mode], 
+			&st_device_kdev_file);
 	    tpnt->de_n[mode] =
 		devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
 				MAJOR_NR, i + (mode << 5) + 128,
@@ -3894,8 +3944,18 @@
 			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
 				devfs_unregister (tpnt->de_r[mode]);
 				tpnt->de_r[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_r[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_r[mode]);
 				devfs_unregister (tpnt->de_n[mode]);
 				tpnt->de_n[mode] = NULL;
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_type_file.name);
+				device_remove_file(&tpnt->driverfs_dev_n[mode],
+						   st_device_kdev_file.name);
+				put_device(&tpnt->driverfs_dev_n[mode]);
 			}
 			kfree(tpnt);
 			scsi_tapes[i] = 0;
@@ -3921,8 +3981,16 @@
 		verstr, st_buffer_size, st_write_threshold,
 		st_max_buffers, st_max_sg_segs);
 
-	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0)
-		return scsi_register_device(&st_template);
+	if (devfs_register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) {
+		if (scsi_register_device(&st_template) == 0) {
+			st_template.scsi_driverfs_driver.name = 
+				(char *)st_template.tag;
+			st_template.scsi_driverfs_driver.bus = 
+				&scsi_driverfs_bus_type;
+			driver_register(&st_template.scsi_driverfs_driver);
+			return 0;
+		}
+	}
 
 	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", MAJOR_NR);
 	return 1;
@@ -3951,6 +4019,7 @@
 		}
 	}
 	st_template.dev_max = 0;
+	remove_driver(&st_template.scsi_driverfs_driver);
 	printk(KERN_INFO "st: Unloaded.\n");
 }
 
diff -Naur linux-2.5.22.orig/drivers/scsi/st.h linux-2.5.22-driverfs/drivers/scsi/st.h
--- linux-2.5.22.orig/drivers/scsi/st.h	Sun Jun 16 21:31:28 2002
+++ linux-2.5.22-driverfs/drivers/scsi/st.h	Mon Jun 17 21:14:07 2002
@@ -94,6 +94,8 @@
 	int current_mode;
 	devfs_handle_t de_r[ST_NBR_MODES];  /*  Rewind entries     */
 	devfs_handle_t de_n[ST_NBR_MODES];  /*  No-rewind entries  */
+	struct device driverfs_dev_r[ST_NBR_MODES];
+	struct device driverfs_dev_n[ST_NBR_MODES];
 
 	/* Status variables */
 	int partition;
diff -Naur linux-2.5.22.orig/fs/partitions/check.c linux-2.5.22-driverfs/fs/partitions/check.c
--- linux-2.5.22.orig/fs/partitions/check.c	Sun Jun 16 21:31:30 2002
+++ linux-2.5.22-driverfs/fs/partitions/check.c	Mon Jun 17 21:14:07 2002
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/raid/md.h>
 #include <linux/buffer_head.h>	/* for invalidate_bdev() */
+#include <linux/kmod.h>
 
 #include "check.h"
 
@@ -221,6 +222,136 @@
 #endif
 }
 
+/* Driverfs file support */
+static ssize_t partition_device_kdev_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off)
+{
+	kdev_t kdev; 
+	kdev.value=(int)driverfs_dev->driver_data;
+	return off ? 0 : sprintf (page, "%x\n",kdev.value);
+}
+static struct driver_file_entry partition_device_kdev_file = {
+	name: "kdev",
+	mode: S_IRUGO,
+	show: partition_device_kdev_read,
+};
+
+static ssize_t partition_device_type_read(struct device *driverfs_dev, 
+			char *page, size_t count, loff_t off) 
+{
+	return off ? 0 : sprintf (page, "BLK\n");
+}
+static struct driver_file_entry partition_device_type_file = {
+	name: "type",
+	mode: S_IRUGO,
+	show: partition_device_type_read,
+};
+
+void driverfs_create_partitions(struct gendisk *hd, int minor)
+{
+	int pos = -1;
+	int devnum = minor >> hd->minor_shift;
+	char dirname[256];
+	struct device *parent = 0;
+	int max_p;
+	int part;
+	devfs_handle_t dir = 0;
+	
+	/* get parent driverfs device structure */
+	if (hd->driverfs_dev_arr)
+		parent = hd->driverfs_dev_arr[devnum];
+	else /* if driverfs not supported by subsystem, skip partitions */
+		return;
+	
+	/* get parent device node directory name */
+	if (hd->de_arr) {
+		dir = hd->de_arr[devnum];
+		if (dir)
+			pos = devfs_generate_path (dir, dirname, 
+						   sizeof dirname);
+	}
+	
+	if (pos < 0) {
+		disk_name(hd, minor, dirname);
+		pos = 0;
+	}
+	
+	max_p = (1 << hd->minor_shift);
+	
+	/* for all partitions setup parents and device node names */
+	for(part=0; part < max_p; part++) {
+		if ((part == 0) || (hd->part[minor + part].nr_sects >= 1)) {
+			struct device * current_driverfs_dev = 
+				&hd->part[minor+part].hd_driverfs_dev;
+			current_driverfs_dev->parent = parent;
+			/* handle disc case */
+			current_driverfs_dev->driver_data =
+					(void *)__mkdev(hd->major, minor+part);
+			if (part == 0) {
+				if (parent)  {
+					sprintf(current_driverfs_dev->name,
+						"%sdisc", parent->name);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:disc", parent->bus_id);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"disc");
+					sprintf(current_driverfs_dev->bus_id,
+						"disc");
+				}
+			} else { /* this is a partition */
+				if (parent) {
+					sprintf(current_driverfs_dev->name,
+						"%spart%d", parent->name, part);
+					sprintf(current_driverfs_dev->bus_id,
+						"%s:p%d", parent->bus_id, part);
+				} else {
+					sprintf(current_driverfs_dev->name, 
+						"part%d", part);
+					sprintf(current_driverfs_dev->bus_id, 
+						"p%d" ,part);
+				}
+			}
+			if (parent) current_driverfs_dev->bus = parent->bus;
+			device_register(current_driverfs_dev);
+			device_create_file(current_driverfs_dev,
+					&partition_device_type_file);
+			device_create_file(current_driverfs_dev,
+					&partition_device_kdev_file);
+		}
+	}
+	return;
+}
+
+void driverfs_remove_partitions(struct gendisk *hd, int minor)
+{
+	int max_p;
+	int part;
+	struct device * current_driverfs_dev;
+	
+	max_p=(1 << hd->minor_shift);
+	
+	/* for all parts setup parent relationships and device node names */
+	for(part=1; part < max_p; part++) {
+		if ((hd->part[minor + part].nr_sects >= 1)) {
+			current_driverfs_dev = 
+				&hd->part[minor + part].hd_driverfs_dev;
+			device_remove_file(current_driverfs_dev,
+					partition_device_type_file.name);
+			device_remove_file(current_driverfs_dev,
+					partition_device_kdev_file.name);
+			put_device(current_driverfs_dev);	
+		}
+	}
+	current_driverfs_dev = &hd->part[minor].hd_driverfs_dev;
+	device_remove_file(current_driverfs_dev, 
+				partition_device_type_file.name);
+	device_remove_file(current_driverfs_dev, 
+				partition_device_kdev_file.name);
+	put_device(current_driverfs_dev);	
+	return;
+}
+
 static void check_partition(struct gendisk *hd, kdev_t dev, int first_part_minor)
 {
 	devfs_handle_t de = NULL;
@@ -281,6 +412,13 @@
 	truncate_inode_pages(bdev->bd_inode->i_mapping, 0);
 	bdput(bdev);
 	i = first_part_minor - 1;
+
+	/* Setup driverfs tree */
+	if (hd->sizes)
+		driverfs_create_partitions(hd, i);
+	else
+		driverfs_remove_partitions(hd, i);
+
 	devfs_register_partitions (hd, i, hd->sizes ? 0 : 1);
 }
 
diff -Naur linux-2.5.22.orig/include/linux/cdrom.h linux-2.5.22-driverfs/include/linux/cdrom.h
--- linux-2.5.22.orig/include/linux/cdrom.h	Sun Jun 16 21:31:23 2002
+++ linux-2.5.22-driverfs/include/linux/cdrom.h	Mon Jun 17 21:14:07 2002
@@ -716,6 +716,7 @@
 
 #ifdef __KERNEL__
 #include <linux/devfs_fs_kernel.h>
+#include <linux/device.h>
 
 struct cdrom_write_settings {
 	unsigned char fpacket;		/* fixed/variable packets */
@@ -730,6 +731,7 @@
 	struct cdrom_device_info *next; /* next device_info for this major */
 	void *handle;		        /* driver-dependent data */
 	devfs_handle_t de;		/* real driver should create this  */
+	struct device cdrom_driverfs_dev; /* driverfs implementation */
 	int number;			/* generic driver updates this  */
 /* specifications */
         kdev_t dev;	                /* device number */
diff -Naur linux-2.5.22.orig/include/linux/genhd.h linux-2.5.22-driverfs/include/linux/genhd.h
--- linux-2.5.22.orig/include/linux/genhd.h	Sun Jun 16 21:31:26 2002
+++ linux-2.5.22-driverfs/include/linux/genhd.h	Mon Jun 17 21:14:07 2002
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/major.h>
+#include <linux/device.h>
 
 enum {
 /* These three have identical behaviour; use the second one if DOS fdisk gets
@@ -62,6 +63,7 @@
 	unsigned long nr_sects;
 	devfs_handle_t de;              /* primary (master) devfs entry  */
 	int number;                     /* stupid old code wastes space  */
+	struct device hd_driverfs_dev;  /* support driverfs hiearchy     */
 };
 
 #define GENHD_FL_REMOVABLE  1
@@ -80,6 +82,7 @@
 	struct block_device_operations *fops;
 
 	devfs_handle_t *de_arr;         /* one per physical disc */
+	struct device **driverfs_dev_arr;/* support driverfs hierarchy */
 	char *flags;                    /* one per physical disc */
 };
 
@@ -241,6 +244,7 @@
 
 extern void devfs_register_partitions (struct gendisk *dev, int minor,
 				       int unregister);
+extern void driverfs_remove_partitions (struct gendisk *hd, int minor);
 
 static inline unsigned int disk_index (kdev_t dev)
 {
diff -Naur linux-2.5.22.orig/kernel/ksyms.c linux-2.5.22-driverfs/kernel/ksyms.c
--- linux-2.5.22.orig/kernel/ksyms.c	Sun Jun 16 21:31:23 2002
+++ linux-2.5.22-driverfs/kernel/ksyms.c	Mon Jun 17 21:14:07 2002
@@ -335,6 +335,7 @@
 EXPORT_SYMBOL(set_device_ro);
 EXPORT_SYMBOL(bmap);
 EXPORT_SYMBOL(devfs_register_partitions);
+EXPORT_SYMBOL(driverfs_remove_partitions);
 EXPORT_SYMBOL(blkdev_open);
 EXPORT_SYMBOL(blkdev_get);
 EXPORT_SYMBOL(blkdev_put);

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

end of thread, other threads:[~2002-06-18 21:56 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-06-17 21:18 [PATCH][RFC] Driverfs support for SCSI devices sullivan
2002-06-17 23:16 ` James Bottomley
2002-06-18 21:56   ` [PATCH][RFC] Driverfs support for SCSI devices (updated) sullivan

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