diff -u b/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- b/drivers/scsi/scsi_lib.c	2004-09-12 22:20:59 -07:00
+++ b/drivers/scsi/scsi_lib.c	2004-09-12 22:22:18 -07:00
@@ -365,7 +365,7 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(shost->host_lock, flags);
-	current_sdev->sdev_target->starget_sdev_user = NULL;
+	scsi_target(current_sdev)->starget_sdev_user = NULL;
 	spin_unlock_irqrestore(shost->host_lock, flags);
 
 	/*
@@ -377,7 +377,7 @@
 	blk_run_queue(current_sdev->request_queue);
 
 	spin_lock_irqsave(shost->host_lock, flags);
-	if (current_sdev->sdev_target->starget_sdev_user)
+	if (scsi_target(current_sdev)->starget_sdev_user)
 		goto out;
 	list_for_each_entry_safe(sdev, tmp, &current_sdev->same_target_siblings,
 			same_target_siblings) {
@@ -1253,10 +1253,10 @@
 		if (!scsi_host_queue_ready(q, shost, sdev))
 			goto not_ready;
 		if (sdev->single_lun) {
-			if (sdev->sdev_target->starget_sdev_user &&
-			    sdev->sdev_target->starget_sdev_user != sdev)
+			if (scsi_target(sdev)->starget_sdev_user &&
+			    scsi_target(sdev)->starget_sdev_user != sdev)
 				goto not_ready;
-			sdev->sdev_target->starget_sdev_user = sdev;
+			scsi_target(sdev)->starget_sdev_user = sdev;
 		}
 		shost->host_busy++;
 
@@ -1753,0 +1754,28 @@
+
+static int
+device_quiesce_fn(struct device *dev, void *data)
+{
+	scsi_device_quiesce(to_scsi_device(dev));
+	return 0;
+}
+
+void
+scsi_target_quiesce(struct scsi_target *starget)
+{
+	device_for_each_child(&starget->dev, NULL, device_quiesce_fn);
+}
+EXPORT_SYMBOL(scsi_target_quiesce);
+
+static int
+device_resume_fn(struct device *dev, void *data)
+{
+	scsi_device_resume(to_scsi_device(dev));
+	return 0;
+}
+
+void
+scsi_target_resume(struct scsi_target *starget)
+{
+	device_for_each_child(&starget->dev, NULL, device_resume_fn);
+}
+EXPORT_SYMBOL(scsi_target_resume);
diff -u b/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
--- b/drivers/scsi/tmscsim.c	2004-09-12 22:20:59 -07:00
+++ b/drivers/scsi/tmscsim.c	2004-09-12 22:22:18 -07:00
@@ -1075,7 +1075,7 @@
 	.use_clustering		= DISABLE_CLUSTERING,
 };
 
-static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
+static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cd)
 {
 	u8 carryFlag = 1, j = 0x80, i, bval, regval;
 
only in patch2:
unchanged:
--- a/drivers/scsi/53c700.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/53c700.c	2004-09-12 22:22:18 -07:00
@@ -287,8 +287,9 @@
 	struct NCR_700_Host_Parameters *hostdata = 
 		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
 
-	return NCR_700_offset_period_to_sxfer(hostdata, spi_offset(SDp),
-					      spi_period(SDp));
+	return NCR_700_offset_period_to_sxfer(hostdata,
+					      spi_offset(SDp->sdev_target),
+					      spi_period(SDp->sdev_target));
 }
 
 struct Scsi_Host *
@@ -403,6 +404,8 @@
 	       (hostdata->fast ? "53c700-66" : "53c700"),
 	       hostdata->rev, hostdata->differential ?
 	       "(Differential)" : "");
+	spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
+		SPI_SIGNAL_SE;
 	/* reset the chip */
 	NCR_700_chip_reset(host);
 
@@ -803,7 +806,7 @@
 			}
 			
 			if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
-				if(spi_offset(SCp->device) != 0)
+				if(spi_offset(SCp->device->sdev_target) != 0)
 					printk(KERN_INFO "scsi%d: (%d:%d) Synchronous at offset %d, period %dns\n",
 					       host->host_no, pun, lun,
 					       offset, period*4);
@@ -813,8 +816,8 @@
 				NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
 			}
 				
-			spi_offset(SCp->device) = offset;
-			spi_period(SCp->device) = period;
+			spi_offset(SCp->device->sdev_target) = offset;
+			spi_period(SCp->device->sdev_target) = period;
 			
 
 			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
@@ -894,7 +897,8 @@
 	case A_REJECT_MSG:
 		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
 			/* Rejected our sync negotiation attempt */
-			spi_period(SCp->device) = spi_offset(SCp->device) = 0;
+			spi_period(SCp->device->sdev_target) =
+				spi_offset(SCp->device->sdev_target) = 0;
 			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
 			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 		} else if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING)) {
@@ -1420,8 +1424,8 @@
 	   NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
 		memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
 		       sizeof(NCR_700_SDTR_msg));
-		hostdata->msgout[count+3] = spi_period(SCp->device);
-		hostdata->msgout[count+4] = spi_offset(SCp->device);
+		hostdata->msgout[count+3] = spi_period(SCp->device->sdev_target);
+		hostdata->msgout[count+4] = spi_offset(SCp->device->sdev_target);
 		count += sizeof(NCR_700_SDTR_msg);
 		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
 	}
@@ -1999,10 +2003,11 @@
 }
 
 STATIC void
-NCR_700_set_period(struct scsi_device *SDp, int period)
+NCR_700_set_period(struct scsi_target *STp, int period)
 {
+	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
 	struct NCR_700_Host_Parameters *hostdata = 
-		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
 	
 	if(!hostdata->fast)
 		return;
@@ -2010,17 +2015,18 @@
 	if(period < hostdata->min_period)
 		period = hostdata->min_period;
 
-	spi_period(SDp) = period;
-	NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
-	NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
-	NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+	spi_period(STp) = period;
+	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
 }
 
 STATIC void
-NCR_700_set_offset(struct scsi_device *SDp, int offset)
+NCR_700_set_offset(struct scsi_target *STp, int offset)
 {
+	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
 	struct NCR_700_Host_Parameters *hostdata = 
-		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
 	int max_offset = hostdata->chip710
 		? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET;
 	
@@ -2031,14 +2037,14 @@
 		offset = max_offset;
 
 	/* if we're currently async, make sure the period is reasonable */
-	if(spi_offset(SDp) == 0 && (spi_period(SDp) < hostdata->min_period ||
-				    spi_period(SDp) > 0xff))
-		spi_period(SDp) = hostdata->min_period;
-
-	spi_offset(SDp) = offset;
-	NCR_700_clear_flag(SDp, NCR_700_DEV_NEGOTIATED_SYNC);
-	NCR_700_clear_flag(SDp, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
-	NCR_700_set_flag(SDp, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+	if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period ||
+				    spi_period(STp) > 0xff))
+		spi_period(STp) = hostdata->min_period;
+
+	spi_offset(STp) = offset;
+	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
 }
 
 
@@ -2058,10 +2064,11 @@
 	}
 	if(hostdata->fast) {
 		/* Find the correct offset and period via domain validation */
-		spi_dv_device(SDp);
+		if (!spi_initial_dv(SDp->sdev_target))
+			spi_dv_device(SDp);
 	} else {
-		spi_offset(SDp) = 0;
-		spi_period(SDp) = 0;
+		spi_offset(SDp->sdev_target) = 0;
+		spi_period(SDp->sdev_target) = 0;
 	}
 	return 0;
 }
only in patch2:
unchanged:
--- a/drivers/scsi/53c700.h	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/53c700.h	2004-09-12 22:22:18 -07:00
@@ -121,22 +121,22 @@
 static inline int
 NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag)
 {
-	return (((unsigned long)SDp->hostdata) & flag) == flag;
+	return (spi_flags(SDp->sdev_target) & flag) == flag;
 }
 static inline int
 NCR_700_is_flag_clear(struct scsi_device *SDp, __u32 flag)
 {
-	return (((unsigned long)SDp->hostdata) & flag) == 0;
+	return (spi_flags(SDp->sdev_target) & flag) == 0;
 }
 static inline void
 NCR_700_set_flag(struct scsi_device *SDp, __u32 flag)
 {
-	SDp->hostdata = (void *)((long)SDp->hostdata | (flag & 0xffff0000));
+	spi_flags(SDp->sdev_target) |= flag;
 }
 static inline void
 NCR_700_clear_flag(struct scsi_device *SDp, __u32 flag)
 {
-	SDp->hostdata = (void *)((long)SDp->hostdata & ~(flag & 0xffff0000));
+	spi_flags(SDp->sdev_target) &= ~flag;
 }
 
 struct NCR_700_command_slot {
only in patch2:
unchanged:
--- a/drivers/scsi/NCR_D700.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/NCR_D700.c	2004-09-12 22:22:18 -07:00
@@ -99,6 +99,9 @@
 #include <linux/mca.h>
 #include <asm/io.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
 
 #include "53c700.h"
 #include "NCR_D700.h"
only in patch2:
unchanged:
--- a/drivers/scsi/hosts.c	2004-09-12 22:22:17 -07:00
+++ b/drivers/scsi/hosts.c	2004-09-12 22:22:18 -07:00
@@ -82,6 +82,8 @@
 	set_bit(SHOST_DEL, &shost->shost_state);
 
 	class_device_unregister(&shost->shost_classdev);
+	if (shost->transport_classdev.class)
+		class_device_unregister(&shost->transport_classdev);
 	device_del(&shost->shost_gendev);
 }
 
@@ -154,6 +156,7 @@
 
 	scsi_proc_hostdir_rm(shost->hostt);
 	scsi_destroy_command_freelist(shost);
+	kfree(shost->shost_data);
 
 	/*
 	 * Some drivers (eg aha1542) do scsi_register()/scsi_unregister()
@@ -278,15 +281,26 @@
 	snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
 		  shost->host_no);
 
+	if (shost->transportt->host_size &&
+	    (shost->shost_data = kmalloc(shost->transportt->host_size,
+					 GFP_KERNEL)) == NULL)
+		goto fail_destroy_freelist;
+
+	if (shost->transportt->host_setup)
+		shost->transportt->host_setup(shost);
+
 	shost->eh_notify = &complete;
 	rval = kernel_thread(scsi_error_handler, shost, 0);
 	if (rval < 0)
-		goto fail_destroy_freelist;
+		goto fail_free_shost_data;
 	wait_for_completion(&complete);
 	shost->eh_notify = NULL;
+
 	scsi_proc_hostdir_add(shost->hostt);
 	return shost;
 
+ fail_free_shost_data:
+	kfree(shost->shost_data);
  fail_destroy_freelist:
 	scsi_destroy_command_freelist(shost);
  fail_kfree:
only in patch2:
unchanged:
--- a/drivers/scsi/lasi700.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/lasi700.c	2004-09-12 22:22:18 -07:00
@@ -50,6 +50,9 @@
 #include <asm/delay.h>
 
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
 
 #include "lasi700.h"
 #include "53c700.h"
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_priv.h	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/scsi_priv.h	2004-09-12 22:22:18 -07:00
@@ -58,16 +58,6 @@
  */
 #define SCAN_WILD_CARD	~0
 
-/*
- * scsi_target: representation of a scsi target, for now, this is only
- * used for single_lun devices. If no one has active IO to the target,
- * starget_sdev_user is NULL, else it points to the active sdev.
- */
-struct scsi_target {
-	struct scsi_device	*starget_sdev_user;
-	unsigned int		starget_refcnt;
-};
-
 /* hosts.c */
 extern int scsi_init_hosts(void);
 extern void scsi_exit_hosts(void);
@@ -156,6 +146,8 @@
 extern int scsi_sysfs_add_host(struct Scsi_Host *);
 extern int scsi_sysfs_register(void);
 extern void scsi_sysfs_unregister(void);
+extern int scsi_sysfs_device_initialize(struct scsi_device *);
+extern int scsi_sysfs_target_initialize(struct scsi_device *);
 extern struct scsi_transport_template blank_transport_template;
 
 extern struct class sdev_class;
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_scan.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/scsi_scan.c	2004-09-12 22:22:18 -07:00
@@ -202,10 +202,11 @@
 static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
 	       	uint channel, uint id, uint lun, void *hostdata)
 {
-	struct scsi_device *sdev, *device;
+	struct scsi_device *sdev;
 	unsigned long flags;
 
-	sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC);
+	sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
+		       GFP_ATOMIC);
 	if (!sdev)
 		goto out;
 
@@ -256,67 +257,28 @@
 			goto out_free_queue;
 	}
 
-	if (shost->transportt->setup) {
-		if (shost->transportt->setup(sdev))
+	if (shost->transportt->device_setup) {
+		if (shost->transportt->device_setup(sdev))
 			goto out_cleanup_slave;
 	}
 
-	if (get_device(&sdev->host->shost_gendev)) {
-
-		device_initialize(&sdev->sdev_gendev);
-		sdev->sdev_gendev.parent = &sdev->host->shost_gendev;
-		sdev->sdev_gendev.bus = &scsi_bus_type;
-		sdev->sdev_gendev.release = scsi_device_dev_release;
-		sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
-			sdev->host->host_no, sdev->channel, sdev->id,
-			sdev->lun);
-
-		class_device_initialize(&sdev->sdev_classdev);
-		sdev->sdev_classdev.dev = &sdev->sdev_gendev;
-		sdev->sdev_classdev.class = &sdev_class;
-		snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
-			 "%d:%d:%d:%d", sdev->host->host_no,
-			 sdev->channel, sdev->id, sdev->lun);
-
-		class_device_initialize(&sdev->transport_classdev);
-		sdev->transport_classdev.dev = &sdev->sdev_gendev;
-		sdev->transport_classdev.class = sdev->host->transportt->class;
-		snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE,
-			 "%d:%d:%d:%d", sdev->host->host_no,
-			 sdev->channel, sdev->id, sdev->lun);
-	} else
-		goto out_cleanup_transport;
+	if (get_device(&sdev->host->shost_gendev) == NULL ||
+	    scsi_sysfs_device_initialize(sdev) != 0)
+		goto out_cleanup_slave;
 
-	/*
-	 * If there are any same target siblings, add this to the
-	 * sibling list
-	 */
-	spin_lock_irqsave(shost->host_lock, flags);
-	list_for_each_entry(device, &shost->__devices, siblings) {
-		if (device->id == sdev->id &&
-		    device->channel == sdev->channel) {
-			list_add_tail(&sdev->same_target_siblings,
-				      &device->same_target_siblings);
-			sdev->scsi_level = device->scsi_level;
-			break;
-		}
-	}
 
-	/*
-	 * If there wasn't another lun already configured at this
-	 * target, then default this device to SCSI_2 until we
-	 * know better
-	 */
-	if (!sdev->scsi_level)
-		sdev->scsi_level = SCSI_2;
+	/* NOTE: this target initialisation code depends critically on
+	 * lun scanning being sequential. */
+	if (scsi_sysfs_target_initialize(sdev))
+		goto out_remove_siblings;
 
-	list_add_tail(&sdev->siblings, &shost->__devices);
-	spin_unlock_irqrestore(shost->host_lock, flags);
 	return sdev;
 
-out_cleanup_transport:
-	if (shost->transportt->cleanup)
-		shost->transportt->cleanup(sdev);
+out_remove_siblings:
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_del(&sdev->siblings);
+	list_del(&sdev->same_target_siblings);
+	spin_unlock_irqrestore(shost->host_lock, flags);
 out_cleanup_slave:
 	if (shost->hostt->slave_destroy)
 		shost->hostt->slave_destroy(sdev);
@@ -500,10 +462,6 @@
  **/
 static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
 {
-	struct scsi_device *sdev_sibling;
-	struct scsi_target *starget;
-	unsigned long flags;
-
 	/*
 	 * XXX do not save the inquiry, since it can change underneath us,
 	 * save just vendor/model/rev.
@@ -612,40 +570,9 @@
 	if (*bflags & BLIST_NOSTARTONADD)
 		sdev->no_start_on_add = 1;
 
-	/*
-	 * If we need to allow I/O to only one of the luns attached to
-	 * this target id at a time set single_lun, and allocate or modify
-	 * sdev_target.
-	 */
-	if (*bflags & BLIST_SINGLELUN) {
+	if (*bflags & BLIST_SINGLELUN)
 		sdev->single_lun = 1;
-		spin_lock_irqsave(sdev->host->host_lock, flags);
-		starget = NULL;
-		/*
-		 * Search for an existing target for this sdev.
-		 */
-		list_for_each_entry(sdev_sibling, &sdev->same_target_siblings,
-				    same_target_siblings) {
-			if (sdev_sibling->sdev_target != NULL) {
-				starget = sdev_sibling->sdev_target;
-				break;
-			}
-		}
-		if (!starget) {
-			starget = kmalloc(sizeof(*starget), GFP_ATOMIC);
-			if (!starget) {
-				printk(ALLOC_FAILURE_MSG, __FUNCTION__);
-				spin_unlock_irqrestore(sdev->host->host_lock,
-						       flags);
-				return SCSI_SCAN_NO_RESPONSE;
-			}
-			starget->starget_refcnt = 0;
-			starget->starget_sdev_user = NULL;
-		}
-		starget->starget_refcnt++;
-		sdev->sdev_target = starget;
-		spin_unlock_irqrestore(sdev->host->host_lock, flags);
-	}
+
 
 	sdev->use_10_for_rw = 1;
 
@@ -785,8 +712,6 @@
 	} else {
 		if (sdev->host->hostt->slave_destroy)
 			sdev->host->hostt->slave_destroy(sdev);
-		if (sdev->host->transportt->cleanup)
-			sdev->host->transportt->cleanup(sdev);
 		put_device(&sdev->sdev_gendev);
 	}
  out:
@@ -1345,7 +1270,5 @@
 
 	if (sdev->host->hostt->slave_destroy)
 		sdev->host->hostt->slave_destroy(sdev);
-	if (sdev->host->transportt->cleanup)
-		sdev->host->transportt->cleanup(sdev);
 	put_device(&sdev->sdev_gendev);
 }
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_sysfs.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/scsi_sysfs.c	2004-09-12 22:22:18 -07:00
@@ -153,25 +153,36 @@
 	struct scsi_device *sdev;
 	struct device *parent;
 	unsigned long flags;
+	int delete;
 
 	parent = dev->parent;
 	sdev = to_scsi_device(dev);
 
 	spin_lock_irqsave(sdev->host->host_lock, flags);
+	/* If we're the last LUN on the target, destroy the target */
+	delete = list_empty(&sdev->same_target_siblings);
 	list_del(&sdev->siblings);
 	list_del(&sdev->same_target_siblings);
 	list_del(&sdev->starved_entry);
-	if (sdev->single_lun && --sdev->sdev_target->starget_refcnt == 0)
-		kfree(sdev->sdev_target);
 	spin_unlock_irqrestore(sdev->host->host_lock, flags);
 
+	if (delete) {
+		struct scsi_target *starget = to_scsi_target(parent);
+		if (!starget->create) {
+			device_del(parent);
+			if (starget->transport_classdev.class)
+				class_device_unregister(&starget->transport_classdev);
+		}
+		put_device(parent);
+	}
 	if (sdev->request_queue)
 		scsi_free_queue(sdev->request_queue);
 
 	kfree(sdev->inquiry);
 	kfree(sdev);
 
-	put_device(parent);
+	if (parent)
+		put_device(parent);
 }
 
 struct class sdev_class = {
@@ -430,6 +441,14 @@
 	return device_create_file(dev, attr);
 }
 
+static void scsi_target_dev_release(struct device *dev)
+{
+	struct scsi_target *starget = to_scsi_target(dev);
+	struct device *parent = dev->parent;
+	kfree(starget);
+	put_device(parent);
+}
+
 /**
  * scsi_sysfs_add_sdev - add scsi device to sysfs
  * @sdev:	scsi_device to add
@@ -440,13 +459,55 @@
 int scsi_sysfs_add_sdev(struct scsi_device *sdev)
 {
 	struct class_device_attribute **attrs;
-	int error, i;
+	struct scsi_target *starget = sdev->sdev_target;
+	struct Scsi_Host *shost = sdev->host;
+	int error, i, create;
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	create = starget->create;
+	starget->create = 0;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	if (create) {
+		error = device_add(&starget->dev);
+		if (error) {
+			printk(KERN_ERR "Target device_add failed\n");
+			return error;
+		}
+		if (starget->transport_classdev.class) {
+			int i;
+			struct class_device_attribute **attrs =
+				sdev->host->transportt->target_attrs;
+
+			error = class_device_add(&starget->transport_classdev);
+			if (error) {
+				dev_printk(KERN_ERR, &starget->dev,
+					   "Target transport add failed\n");
+				return error;
+			}
+
+			/* take a reference for the transport_classdev; this
+			 * is released by the transport_class .release */
+			get_device(&starget->dev);
+			for (i = 0; attrs[i]; i++) {
+				error = class_device_create_file(&starget->transport_classdev,
+								 attrs[i]);
+				if (error) {
+					dev_printk(KERN_ERR, &starget->dev,
+						   "Target transport attr add failed\n");
+					return error;
+				}
+			}
+		}
+	}
 
 	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
 		return error;
 
 	error = device_add(&sdev->sdev_gendev);
 	if (error) {
+		put_device(sdev->sdev_gendev.parent);
 		printk(KERN_INFO "error 1\n");
 		return error;
 	}
@@ -459,7 +520,6 @@
 	/* take a reference for the sdev_classdev; this is
 	 * released by the sdev_class .release */
 	get_device(&sdev->sdev_gendev);
-
 	if (sdev->transport_classdev.class) {
 		error = class_device_add(&sdev->transport_classdev);
 		if (error)
@@ -494,7 +554,7 @@
 	}
 
  	if (sdev->transport_classdev.class) {
- 		attrs = sdev->host->transportt->attrs;
+ 		attrs = sdev->host->transportt->device_attrs;
  		for (i = 0; attrs[i]; i++) {
  			error = class_device_create_file(&sdev->transport_classdev,
  							 attrs[i]);
@@ -538,8 +598,6 @@
 	scsi_device_set_state(sdev, SDEV_DEL);
 	if (sdev->host->hostt->slave_destroy)
 		sdev->host->hostt->slave_destroy(sdev);
-	if (sdev->host->transportt->cleanup)
-		sdev->host->transportt->cleanup(sdev);
 	put_device(&sdev->sdev_gendev);
 
 out:
@@ -626,6 +684,120 @@
 		}
 	}
 
+	class_device_initialize(&shost->transport_classdev);
+	shost->transport_classdev.class = shost->transportt->host_class;
+	shost->transport_classdev.dev = &shost->shost_gendev;
+	snprintf(shost->transport_classdev.class_id, BUS_ID_SIZE,
+		 "host%d", shost->host_no);
+
+	if (shost->transport_classdev.class) {
+		struct class_device_attribute **attrs =
+			shost->transportt->host_attrs;
+		error = class_device_add(&shost->transport_classdev);
+		if (error)
+			return error;
+		/* take a reference for the transport_classdev; this
+		 * is released by the transport_class .release */
+		get_device(&shost->shost_gendev);
+		for (i = 0; attrs[i]; i++) {
+ 			error = class_device_create_file(&shost->transport_classdev,
+ 							 attrs[i]);
+ 			if (error)
+				return error;
+ 		}
+ 	}
+
+	return 0;
+}
+
+int scsi_sysfs_device_initialize(struct scsi_device *sdev)
+{
+	device_initialize(&sdev->sdev_gendev);
+	sdev->sdev_gendev.bus = &scsi_bus_type;
+	sdev->sdev_gendev.release = scsi_device_dev_release;
+	sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
+		sdev->host->host_no, sdev->channel, sdev->id,
+		sdev->lun);
+	
+	class_device_initialize(&sdev->sdev_classdev);
+	sdev->sdev_classdev.dev = &sdev->sdev_gendev;
+	sdev->sdev_classdev.class = &sdev_class;
+	snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
+		 "%d:%d:%d:%d", sdev->host->host_no,
+		 sdev->channel, sdev->id, sdev->lun);
+
+	class_device_initialize(&sdev->transport_classdev);
+	sdev->transport_classdev.dev = &sdev->sdev_gendev;
+	sdev->transport_classdev.class = sdev->host->transportt->device_class;
+	snprintf(sdev->transport_classdev.class_id, BUS_ID_SIZE,
+		 "%d:%d:%d:%d", sdev->host->host_no,
+		 sdev->channel, sdev->id, sdev->lun);
+	return 0;
+}
+
+int scsi_sysfs_target_initialize(struct scsi_device *sdev)
+{
+	struct scsi_target *starget = NULL;
+	struct Scsi_Host *shost = sdev->host;
+	struct scsi_device *device;
+	struct device *dev = NULL;
+	unsigned long flags;
+	int create = 0;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	/*
+	 * Search for an existing target for this sdev.
+	 */
+	list_for_each_entry(device, &shost->__devices, siblings) {
+		if (device->id == sdev->id &&
+		    device->channel == sdev->channel) {
+			list_add_tail(&sdev->same_target_siblings,
+				      &device->same_target_siblings);
+			sdev->scsi_level = device->scsi_level;
+			starget = device->sdev_target;
+			break;
+		}
+	}
+			
+	if (!starget) {
+		const int size = sizeof(*starget) +
+			shost->transportt->target_size;
+		starget = kmalloc(size, GFP_ATOMIC);
+		if (!starget) {
+			printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+			spin_unlock_irqrestore(shost->host_lock,
+					       flags);
+			return -ENOMEM;
+		}
+		memset(starget, 0, size);
+		dev = &starget->dev;
+		device_initialize(dev);
+		dev->parent = &shost->shost_gendev;
+		dev->release = scsi_target_dev_release;
+		sprintf(dev->bus_id, "target%d:%d:%d",
+			shost->host_no, sdev->channel, sdev->id);
+		class_device_initialize(&starget->transport_classdev);
+		starget->transport_classdev.dev = &starget->dev;
+		starget->transport_classdev.class = shost->transportt->target_class;
+		snprintf(starget->transport_classdev.class_id, BUS_ID_SIZE,
+			 "target%d:%d:%d",
+			 shost->host_no, sdev->channel, sdev->id);
+		starget->id = sdev->id;
+		create = starget->create = 1;
+		/*
+		 * If there wasn't another lun already configured at
+		 * this target, then default this device to SCSI_2
+		 * until we know better
+		 */
+		sdev->scsi_level = SCSI_2;
+	}
+	get_device(&starget->dev);
+	sdev->sdev_gendev.parent = &starget->dev;
+	sdev->sdev_target = starget;
+	list_add_tail(&sdev->siblings, &shost->__devices);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	if (create && shost->transportt->target_setup)
+		shost->transportt->target_setup(starget);
 	return 0;
 }
 
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_transport_fc.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/scsi_transport_fc.c	2004-09-12 22:22:18 -07:00
@@ -84,7 +84,7 @@
 	struct scsi_device *sdev = transport_class_to_sdev(cdev);	\
 	struct fc_transport_attrs *tp;					\
 	struct fc_internal *i = to_fc_internal(sdev->host->transportt);	\
-	tp = (struct fc_transport_attrs *)&sdev->transport_data;	\
+	tp = (struct fc_transport_attrs *)&sdev->sdev_data;		\
 	if (i->f->get_##field)						\
 		i->f->get_##field(sdev);				\
 	return snprintf(buf, 20, format_string, cast tp->field);	\
@@ -156,10 +156,10 @@
 
 	memset(i, 0, sizeof(struct fc_internal));
 
-	i->t.attrs = &i->attrs[0];
-	i->t.class = &fc_transport_class;
-	i->t.setup = &fc_setup_transport_attrs;
-	i->t.size = sizeof(struct fc_transport_attrs);
+	i->t.device_attrs = &i->attrs[0];
+	i->t.device_class = &fc_transport_class;
+	i->t.device_setup = &fc_setup_transport_attrs;
+	i->t.device_size = sizeof(struct fc_transport_attrs);
 	i->f = ft;
 
 	SETUP_ATTRIBUTE_RD(port_id);
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_transport_spi.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/scsi_transport_spi.c	2004-09-12 22:22:18 -07:00
@@ -27,25 +27,28 @@
 #include <asm/scatterlist.h>
 #include <asm/io.h>
 #include <scsi/scsi.h>
+#include "scsi_priv.h"
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_request.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_spi.h>
 
-#define SPI_PRINTK(x, l, f, a...)	printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a)
+#define SPI_PRINTK(x, l, f, a...)	dev_printk(l, &(x)->dev, f , ##a)
 
 static void transport_class_release(struct class_device *class_dev);
+static void host_class_release(struct class_device *class_dev);
 
 #define SPI_NUM_ATTRS 10	/* increase this if you add attributes */
 #define SPI_OTHER_ATTRS 1	/* Increase this if you add "always
 				 * on" attributes */
+#define SPI_HOST_ATTRS	1
 
 #define SPI_MAX_ECHO_BUFFER_SIZE	4096
 
 /* Private data accessors (keep these out of the header file) */
-#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dv_pending)
-#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->transport_data)->dv_sem)
+#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
 
 struct spi_internal {
 	struct scsi_transport_template t;
@@ -55,6 +58,8 @@
 	/* The array of null terminated pointers to attributes 
 	 * needed by scsi_sysfs.c */
 	struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
+	struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
+	struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
 };
 
 #define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
@@ -80,43 +85,100 @@
  * by 4 */
 #define SPI_STATIC_PPR	0x0c
 
+static struct {
+	enum spi_signal_type	value;
+	char			*name;
+} signal_types[] = {
+	{ SPI_SIGNAL_UNKNOWN, "unknown" },
+	{ SPI_SIGNAL_SE, "SE" },
+	{ SPI_SIGNAL_LVD, "LVD" },
+	{ SPI_SIGNAL_HVD, "HVD" },
+};
+
+static inline const char *spi_signal_to_string(enum spi_signal_type type)
+{
+	int i;
+
+	for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+		if (type == signal_types[i].value)
+			return signal_types[i].name;
+	}
+	return NULL;
+}
+static inline enum spi_signal_type spi_signal_to_value(const char *name)
+{
+	int i, len;
+
+	for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+		len =  strlen(signal_types[i].name);
+		if (strncmp(name, signal_types[i].name, len) == 0 &&
+		    (name[len] == '\n' || name[len] == '\0'))
+			return signal_types[i].value;
+	}
+	return SPI_SIGNAL_UNKNOWN;
+}
+
+
 struct class spi_transport_class = {
 	.name = "spi_transport",
 	.release = transport_class_release,
 };
 
+struct class spi_host_class = {
+	.name = "spi_host",
+	.release = host_class_release,
+};
+
 static __init int spi_transport_init(void)
 {
+	int error = class_register(&spi_host_class);
+	if (error)
+		return error;
 	return class_register(&spi_transport_class);
 }
 
 static void __exit spi_transport_exit(void)
 {
 	class_unregister(&spi_transport_class);
+	class_unregister(&spi_host_class);
+}
+
+static int spi_setup_host_attrs(struct Scsi_Host *shost)
+{
+	spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
+
+	return 0;
 }
 
-static int spi_setup_transport_attrs(struct scsi_device *sdev)
+static int spi_setup_transport_attrs(struct scsi_target *starget)
 {
-	spi_period(sdev) = -1;	/* illegal value */
-	spi_offset(sdev) = 0;	/* async */
-	spi_width(sdev) = 0;	/* narrow */
-	spi_iu(sdev) = 0;	/* no IU */
-	spi_dt(sdev) = 0;	/* ST */
-	spi_qas(sdev) = 0;
-	spi_wr_flow(sdev) = 0;
-	spi_rd_strm(sdev) = 0;
-	spi_rti(sdev) = 0;
-	spi_pcomp_en(sdev) = 0;
-	spi_dv_pending(sdev) = 0;
-	init_MUTEX(&spi_dv_sem(sdev));
+	spi_period(starget) = -1;	/* illegal value */
+	spi_offset(starget) = 0;	/* async */
+	spi_width(starget) = 0;	/* narrow */
+	spi_iu(starget) = 0;	/* no IU */
+	spi_dt(starget) = 0;	/* ST */
+	spi_qas(starget) = 0;
+	spi_wr_flow(starget) = 0;
+	spi_rd_strm(starget) = 0;
+	spi_rti(starget) = 0;
+	spi_pcomp_en(starget) = 0;
+	spi_dv_pending(starget) = 0;
+	spi_initial_dv(starget) = 0;
+	init_MUTEX(&spi_dv_sem(starget));
 
 	return 0;
 }
 
 static void transport_class_release(struct class_device *class_dev)
 {
-	struct scsi_device *sdev = transport_class_to_sdev(class_dev);
-	put_device(&sdev->sdev_gendev);
+	struct scsi_target *starget = transport_class_to_starget(class_dev);
+	put_device(&starget->dev);
+}
+
+static void host_class_release(struct class_device *class_dev)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(class_dev);
+	put_device(&shost->shost_gendev);
 }
 
 #define spi_transport_show_function(field, format_string)		\
@@ -124,12 +186,13 @@
 static ssize_t								\
 show_spi_transport_##field(struct class_device *cdev, char *buf)	\
 {									\
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);	\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
 	struct spi_transport_attrs *tp;					\
-	struct spi_internal *i = to_spi_internal(sdev->host->transportt); \
-	tp = (struct spi_transport_attrs *)&sdev->transport_data;	\
+	struct spi_internal *i = to_spi_internal(shost->transportt);	\
+	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
 	if (i->f->get_##field)						\
-		i->f->get_##field(sdev);				\
+		i->f->get_##field(starget);				\
 	return snprintf(buf, 20, format_string, tp->field);		\
 }
 
@@ -139,11 +202,12 @@
 			    size_t count)				\
 {									\
 	int val;							\
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);	\
-	struct spi_internal *i = to_spi_internal(sdev->host->transportt); \
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct spi_internal *i = to_spi_internal(shost->transportt);	\
 									\
 	val = simple_strtoul(buf, NULL, 0);				\
-	i->f->set_##field(sdev, val);					\
+	i->f->set_##field(starget, val);				\
 	return count;							\
 }
 
@@ -168,8 +232,13 @@
 static ssize_t
 store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count)
 {
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);
+	struct scsi_target *starget = transport_class_to_starget(cdev);
 
+	/* FIXME: we're relying on an awful lot of device internals
+	 * here.  We really need a function to get the first available
+	 * child */
+	struct device *dev = container_of(starget->dev.children.next, struct device, node);
+	struct scsi_device *sdev = to_scsi_device(dev);
 	spi_dv_device(sdev);
 	return count;
 }
@@ -180,15 +249,16 @@
 static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)
 
 {
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
 	struct spi_transport_attrs *tp;
 	const char *str;
-	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
 
-	tp = (struct spi_transport_attrs *)&sdev->transport_data;
+	tp = (struct spi_transport_attrs *)&starget->starget_data;
 
 	if (i->f->get_period)
-		i->f->get_period(sdev);
+		i->f->get_period(starget);
 
 	switch(tp->period) {
 
@@ -212,8 +282,9 @@
 store_spi_transport_period(struct class_device *cdev, const char *buf,
 			    size_t count)
 {
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);
-	struct spi_internal *i = to_spi_internal(sdev->host->transportt);
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
 	int j, period = -1;
 
 	for (j = 0; j < SPI_STATIC_PPR; j++) {
@@ -246,7 +317,7 @@
 	if (period > 0xff)
 		period = 0xff;
 
-	i->f->set_period(sdev, period);
+	i->f->set_period(starget, period);
 
 	return count;
 }
@@ -255,9 +326,36 @@
 			 show_spi_transport_period,
 			 store_spi_transport_period);
 
+static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+
+	if (i->f->get_signalling)
+		i->f->get_signalling(shost);
+
+	return sprintf(buf, "%s\n", spi_signal_to_string(spi_signalling(shost)));
+}
+static ssize_t store_spi_host_signalling(struct class_device *cdev,
+					 const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+	enum spi_signal_type type = spi_signal_to_value(buf);
+
+	if (type != SPI_SIGNAL_UNKNOWN)
+		return count;
+
+	i->f->set_signalling(shost, type);
+	return count;
+}
+static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
+			 show_spi_host_signalling,
+			 store_spi_host_signalling);
+
 #define DV_SET(x, y)			\
 	if(i->f->set_##x)		\
-		i->f->set_##x(sdev, y)
+		i->f->set_##x(sdev->sdev_target, y)
 
 #define DV_LOOPS	3
 #define DV_TIMEOUT	(10*HZ)
@@ -325,7 +423,7 @@
 			      DV_TIMEOUT, DV_RETRIES);
 		if(sreq->sr_result || !scsi_device_online(sdev)) {
 			scsi_device_set_state(sdev, SDEV_QUIESCE);
-			SPI_PRINTK(sdev, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result);
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result);
 			return 0;
 		}
 
@@ -401,8 +499,8 @@
 
 		/* OK, retrain, fallback */
 		if (i->f->get_period)
-			i->f->get_period(sdev);
-		newperiod = spi_period(sdev);
+			i->f->get_period(sdev->sdev_target);
+		newperiod = spi_period(sdev->sdev_target);
 		period = newperiod > period ? newperiod : period;
 		if (period < 0x0d)
 			period++;
@@ -411,11 +509,11 @@
 
 		if (unlikely(period > 0xff || period == prevperiod)) {
 			/* Total failure; set to async and return */
-			SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
 			DV_SET(offset, 0);
 			return 0;
 		}
-		SPI_PRINTK(sdev, KERN_ERR, "Domain Validation detected failure, dropping back\n");
+		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation detected failure, dropping back\n");
 		DV_SET(period, period);
 		prevperiod = period;
 	}
@@ -486,20 +584,20 @@
 	DV_SET(width, 0);
 	
 	if (!spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)) {
-		SPI_PRINTK(sdev, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
+		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
 		/* FIXME: should probably offline the device here? */
 		return;
 	}
 
 	/* test width */
 	if (i->f->set_width && sdev->wdtr) {
-		i->f->set_width(sdev, 1);
+		i->f->set_width(sdev->sdev_target, 1);
 
 		if (!spi_dv_device_compare_inquiry(sreq, buffer,
 						   buffer + len,
 						   DV_LOOPS)) {
-			SPI_PRINTK(sdev, KERN_ERR, "Wide Transfers Fail\n");
-			i->f->set_width(sdev, 0);
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Wide Transfers Fail\n");
+			i->f->set_width(sdev->sdev_target, 0);
 		}
 	}
 
@@ -521,11 +619,11 @@
 	 * test, now try an echo buffer test (if the device allows it) */
 
 	if ((len = spi_dv_device_get_echo_buffer(sreq, buffer)) == 0) {
-		SPI_PRINTK(sdev, KERN_INFO, "Domain Validation skipping write tests\n");
+		SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n");
 		return;
 	}
 	if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
-		SPI_PRINTK(sdev, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
+		SPI_PRINTK(sdev->sdev_target, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
 		len = SPI_MAX_ECHO_BUFFER_SIZE;
 	}
 
@@ -547,6 +645,7 @@
 spi_dv_device(struct scsi_device *sdev)
 {
 	struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	struct scsi_target *starget = sdev->sdev_target;
 	u8 *buffer;
 	const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
 
@@ -563,22 +662,28 @@
 
 	memset(buffer, 0, len);
 
+	/* We need to verify that the actual device will quiesce; the
+	 * later target quiesce is just a nice to have */
 	if (unlikely(scsi_device_quiesce(sdev)))
 		goto out_free;
 
-	spi_dv_pending(sdev) = 1;
-	down(&spi_dv_sem(sdev));
+	scsi_target_quiesce(starget);
+
+	spi_dv_pending(starget) = 1;
+	down(&spi_dv_sem(starget));
 
-	SPI_PRINTK(sdev, KERN_INFO, "Beginning Domain Validation\n");
+	SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n");
 
 	spi_dv_device_internal(sreq, buffer);
 
-	SPI_PRINTK(sdev, KERN_INFO, "Ending Domain Validation\n");
+	SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n");
 
-	up(&spi_dv_sem(sdev));
-	spi_dv_pending(sdev) = 0;
+	up(&spi_dv_sem(starget));
+	spi_dv_pending(starget) = 0;
 
-	scsi_device_resume(sdev);
+	scsi_target_resume(starget);
+
+	spi_initial_dv(starget) = 1;
 
  out_free:
 	kfree(buffer);
@@ -602,7 +707,7 @@
 
 	kfree(wqw);
 	spi_dv_device(sdev);
-	spi_dv_pending(sdev) = 0;
+	spi_dv_pending(sdev->sdev_target) = 0;
 	scsi_device_put(sdev);
 }
 
@@ -625,15 +730,15 @@
 	if (unlikely(!wqw))
 		return;
 
-	if (unlikely(spi_dv_pending(sdev))) {
+	if (unlikely(spi_dv_pending(sdev->sdev_target))) {
 		kfree(wqw);
 		return;
 	}
 	/* Set pending early (dv_device doesn't check it, only sets it) */
-	spi_dv_pending(sdev) = 1;
+	spi_dv_pending(sdev->sdev_target) = 1;
 	if (unlikely(scsi_device_get(sdev))) {
 		kfree(wqw);
-		spi_dv_pending(sdev) = 0;
+		spi_dv_pending(sdev->sdev_target) = 0;
 		return;
 	}
 
@@ -654,6 +759,15 @@
 	if (i->f->show_##field)						\
 		count++
 
+#define SETUP_HOST_ATTRIBUTE(field)					\
+	i->private_host_attrs[count] = class_device_attr_##field;	\
+	if (!i->f->set_##field) {					\
+		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_host_attrs[count].store = NULL;		\
+	}								\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	count++
+
 struct scsi_transport_template *
 spi_attach_transport(struct spi_function_template *ft)
 {
@@ -666,10 +780,14 @@
 	memset(i, 0, sizeof(struct spi_internal));
 
 
-	i->t.attrs = &i->attrs[0];
-	i->t.class = &spi_transport_class;
-	i->t.setup = &spi_setup_transport_attrs;
-	i->t.size = sizeof(struct spi_transport_attrs);
+	i->t.target_attrs = &i->attrs[0];
+	i->t.target_class = &spi_transport_class;
+	i->t.target_setup = &spi_setup_transport_attrs;
+	i->t.target_size = sizeof(struct spi_transport_attrs);
+	i->t.host_attrs = &i->host_attrs[0];
+	i->t.host_class = &spi_host_class;
+	i->t.host_setup = &spi_setup_host_attrs;
+	i->t.host_size = sizeof(struct spi_host_attrs);
 	i->f = ft;
 
 	SETUP_ATTRIBUTE(period);
@@ -688,6 +806,13 @@
 	BUG_ON(count > SPI_NUM_ATTRS);
 
 	i->attrs[count++] = &class_device_attr_revalidate;
+
+	i->attrs[count] = NULL;
+
+	count = 0;
+	SETUP_HOST_ATTRIBUTE(signalling);
+
+	BUG_ON(count > SPI_HOST_ATTRS);
 
 	i->attrs[count] = NULL;
 
only in patch2:
unchanged:
--- a/drivers/scsi/sim710.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/sim710.c	2004-09-12 22:22:18 -07:00
@@ -36,6 +36,9 @@
 #include <linux/eisa.h>
 #include <linux/interrupt.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
 
 #include "53c700.h"
 
only in patch2:
unchanged:
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-09-12 22:22:18 -07:00
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-09-12 22:22:18 -07:00
@@ -1096,7 +1096,8 @@
 	lp->s.scdev_depth = depth_to_use;
 	sym_tune_dev_queuing(np, device->id, device->lun, reqtags);
 
-	spi_dv_device(device);
+	if (!spi_initial_dv(device->sdev_target))
+		spi_dv_device(device);
 
 	return 0;
 }
@@ -2304,35 +2305,61 @@
 	attach_count--;
 }
 
-static void sym2_get_offset(struct scsi_device *sdev)
+static void sym2_get_signalling(struct Scsi_Host *shost)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	enum spi_signal_type type;
 
-	spi_offset(sdev) = tp->tinfo.curr.offset;
+	switch (np->scsi_mode) {
+	case SMODE_SE:
+		type =  SPI_SIGNAL_SE;
+		break;
+	case SMODE_LVD:
+		type = SPI_SIGNAL_LVD;
+		break;
+	case SMODE_HVD:
+		type = SPI_SIGNAL_HVD;
+		break;
+	default:
+		type = SPI_SIGNAL_UNKNOWN;
+		break;
+	}
+	spi_signalling(shost) = type;
+}
+
+static void sym2_get_offset(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	spi_offset(starget) = tp->tinfo.curr.offset;
 }
 
-static void sym2_set_offset(struct scsi_device *sdev, int offset)
+static void sym2_set_offset(struct scsi_target *starget, int offset)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
 	tp->tinfo.goal.offset = offset;
 }
 
 
-static void sym2_get_period(struct scsi_device *sdev)
+static void sym2_get_period(struct scsi_target *starget)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
-	spi_period(sdev) = tp->tinfo.curr.period;
+	spi_period(starget) = tp->tinfo.curr.period;
 }
 
-static void sym2_set_period(struct scsi_device *sdev, int period)
+static void sym2_set_period(struct scsi_target *starget, int period)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
 	/* have to have DT for these transfers */
 	if (period <= np->minsync)
@@ -2341,18 +2368,20 @@
 	tp->tinfo.goal.period = period;
 }
 
-static void sym2_get_width(struct scsi_device *sdev)
+static void sym2_get_width(struct scsi_target *starget)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
-	spi_width(sdev) = tp->tinfo.curr.width ? 1 : 0;
+	spi_width(starget) = tp->tinfo.curr.width ? 1 : 0;
 }
 
-static void sym2_set_width(struct scsi_device *sdev, int width)
+static void sym2_set_width(struct scsi_target *starget, int width)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
 	/* It is illegal to have DT set on narrow transfers */
 	if (width == 0)
@@ -2361,18 +2390,20 @@
 	tp->tinfo.goal.width = width;
 }
 
-static void sym2_get_dt(struct scsi_device *sdev)
+static void sym2_get_dt(struct scsi_target *starget)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
-	spi_dt(sdev) = (tp->tinfo.curr.options & PPR_OPT_DT) ? 1 : 0;
+	spi_dt(starget) = (tp->tinfo.curr.options & PPR_OPT_DT) ? 1 : 0;
 }
 
-static void sym2_set_dt(struct scsi_device *sdev, int dt)
+static void sym2_set_dt(struct scsi_target *starget, int dt)
 {
-	struct sym_hcb *np = ((struct host_data *)sdev->host->hostdata)->ncb;
-	struct sym_tcb *tp = &np->target[sdev->id];
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct sym_tcb *tp = &np->target[starget->id];
 
 	if (dt)
 		tp->tinfo.goal.options |= PPR_OPT_DT;
@@ -2394,6 +2425,7 @@
 	.get_dt		= sym2_get_dt,
 	.set_dt		= sym2_set_dt,
 	.show_dt	= 1,
+	.get_signalling	= sym2_get_signalling,
 };
 
 static struct pci_device_id sym2_id_table[] __devinitdata = {
only in patch2:
unchanged:
--- a/include/scsi/scsi_device.h	2004-09-12 22:22:17 -07:00
+++ b/include/scsi/scsi_device.h	2004-09-12 22:22:17 -07:00
@@ -120,7 +120,7 @@
 	struct class_device	transport_classdev;
 
 	enum scsi_device_state sdev_state;
-	unsigned long		transport_data[0];
+	unsigned long		sdev_data[0];
 } __attribute__((aligned(sizeof(unsigned long))));
 #define	to_scsi_device(d)	\
 	container_of(d, struct scsi_device, sdev_gendev)
@@ -129,6 +129,29 @@
 #define transport_class_to_sdev(class_dev) \
 	container_of(class_dev, struct scsi_device, transport_classdev)
 
+/*
+ * scsi_target: representation of a scsi target, for now, this is only
+ * used for single_lun devices. If no one has active IO to the target,
+ * starget_sdev_user is NULL, else it points to the active sdev.
+ */
+struct scsi_target {
+	struct scsi_device	*starget_sdev_user;
+	struct device		dev;
+	unsigned int		id; /* target id ... replace
+				     * scsi_device.id eventually */
+	struct class_device	transport_classdev;
+	unsigned long		create:1; /* signal that it needs to be added */
+	unsigned long		starget_data[0];
+} __attribute__((aligned(sizeof(unsigned long))));
+
+#define to_scsi_target(d)	container_of(d, struct scsi_target, dev)
+static inline struct scsi_target *scsi_target(struct scsi_device *sdev)
+{
+	return to_scsi_target(sdev->sdev_gendev.parent);
+}
+#define transport_class_to_starget(class_dev) \
+	container_of(class_dev, struct scsi_target, transport_classdev)
+
 extern struct scsi_device *__scsi_add_device(struct Scsi_Host *,
 		uint, uint, uint, void *hostdata);
 #define scsi_add_device(host, channel, target, lun) \
@@ -191,6 +214,8 @@
 				 enum scsi_device_state state);
 extern int scsi_device_quiesce(struct scsi_device *sdev);
 extern void scsi_device_resume(struct scsi_device *sdev);
+extern void scsi_target_quiesce(struct scsi_target *);
+extern void scsi_target_resume(struct scsi_target *);
 extern const char *scsi_device_state_name(enum scsi_device_state);
 static inline int scsi_device_online(struct scsi_device *sdev)
 {
only in patch2:
unchanged:
--- a/include/scsi/scsi_host.h	2004-09-12 22:22:18 -07:00
+++ b/include/scsi/scsi_host.h	2004-09-12 22:22:18 -07:00
@@ -511,6 +511,13 @@
 	struct list_head sht_legacy_list;
 
 	/*
+	 * Points to the transport data (if any) which is allocated
+	 * separately
+	 */
+	void *shost_data;
+	struct class_device transport_classdev;
+
+	/*
 	 * We should ensure that this is aligned, both for better performance
 	 * and also because some compilers (m68k) don't automatically force
 	 * alignment to a long boundary.
@@ -522,6 +529,9 @@
 	container_of(d, struct Scsi_Host, shost_gendev)
 #define		class_to_shost(d)	\
 	container_of(d, struct Scsi_Host, shost_classdev)
+#define		transport_class_to_shost(class_dev) \
+	container_of(class_dev, struct Scsi_Host, transport_classdev)
+
 
 extern struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *, int);
 extern int scsi_add_host(struct Scsi_Host *, struct device *);
only in patch2:
unchanged:
--- a/include/scsi/scsi_transport.h	2004-09-12 22:22:18 -07:00
+++ b/include/scsi/scsi_transport.h	2004-09-12 22:22:18 -07:00
@@ -24,18 +24,27 @@
 	/* The NULL terminated list of transport attributes
 	 * that should be exported.
 	 */
-	struct class_device_attribute **attrs;
+	struct class_device_attribute **device_attrs;
+	struct class_device_attribute **target_attrs;
+	struct class_device_attribute **host_attrs;
+
 
 	/* The transport class that the device is in */
-	struct class *class;
+	struct class *device_class;
+	struct class *target_class;
+	struct class *host_class;
+
+	/* Constructor functions */
+	int (*device_setup)(struct scsi_device *);
+	int (*target_setup)(struct scsi_target *);
+	int (*host_setup)(struct Scsi_Host *);
 
-	/* Constructor/Destructor functions */
-	int (* setup)(struct scsi_device *);
-	void (* cleanup)(struct scsi_device *);
 	/* The size of the specific transport attribute structure (a
 	 * space of this size will be left at the end of the
-	 * scsi_device structure */
-	int	size;
+	 * scsi_* structure */
+	int	device_size;
+	int	target_size;
+	int	host_size;
 };
 
 #endif /* SCSI_TRANSPORT_H */
only in patch2:
unchanged:
--- a/include/scsi/scsi_transport_fc.h	2004-09-12 22:22:18 -07:00
+++ b/include/scsi/scsi_transport_fc.h	2004-09-12 22:22:18 -07:00
@@ -31,9 +31,9 @@
 };
 
 /* accessor functions */
-#define fc_port_id(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->port_id)
-#define fc_node_name(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->node_name)
-#define fc_port_name(x)	(((struct fc_transport_attrs *)&(x)->transport_data)->port_name)
+#define fc_port_id(x)	(((struct fc_transport_attrs *)&(x)->sdev_data)->port_id)
+#define fc_node_name(x)	(((struct fc_transport_attrs *)&(x)->sdev_data)->node_name)
+#define fc_port_name(x)	(((struct fc_transport_attrs *)&(x)->sdev_data)->port_name)
 
 /* The functions by which the transport class and the driver communicate */
 struct fc_function_template {
only in patch2:
unchanged:
--- a/include/scsi/scsi_transport_spi.h	2004-09-12 22:22:18 -07:00
+++ b/include/scsi/scsi_transport_spi.h	2004-09-12 22:22:18 -07:00
@@ -35,45 +35,63 @@
 	unsigned int rd_strm:1;	/* Read streaming enabled */
 	unsigned int rti:1;	/* Retain Training Information */
 	unsigned int pcomp_en:1;/* Precompensation enabled */
+	unsigned int initial_dv:1; /* DV done to this target yet  */
+	unsigned long flags;	/* flags field for drivers to use */
 	/* Private Fields */
 	unsigned int dv_pending:1; /* Internal flag */
 	struct semaphore dv_sem; /* semaphore to serialise dv */
 };
 
+enum spi_signal_type {
+	SPI_SIGNAL_UNKNOWN = 1,
+	SPI_SIGNAL_SE,
+	SPI_SIGNAL_LVD,
+	SPI_SIGNAL_HVD,
+};
+
+struct spi_host_attrs {
+	enum spi_signal_type signalling;
+};
+
 /* accessor functions */
-#define spi_period(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->period)
-#define spi_offset(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->offset)
-#define spi_width(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->width)
-#define spi_iu(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->iu)
-#define spi_dt(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->dt)
-#define spi_qas(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->qas)
-#define spi_wr_flow(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->wr_flow)
-#define spi_rd_strm(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->rd_strm)
-#define spi_rti(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->rti)
-#define spi_pcomp_en(x)	(((struct spi_transport_attrs *)&(x)->transport_data)->pcomp_en)
+#define spi_period(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->period)
+#define spi_offset(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->offset)
+#define spi_width(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->width)
+#define spi_iu(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->iu)
+#define spi_dt(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->dt)
+#define spi_qas(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->qas)
+#define spi_wr_flow(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->wr_flow)
+#define spi_rd_strm(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->rd_strm)
+#define spi_rti(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->rti)
+#define spi_pcomp_en(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->pcomp_en)
+#define spi_initial_dv(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->initial_dv)
+#define spi_flags(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->flags)
+#define spi_signalling(h)	(((struct spi_host_attrs *)&(h)->shost_data)->signalling)
 
 /* The functions by which the transport class and the driver communicate */
 struct spi_function_template {
-	void	(*get_period)(struct scsi_device *);
-	void	(*set_period)(struct scsi_device *, int);
-	void	(*get_offset)(struct scsi_device *);
-	void	(*set_offset)(struct scsi_device *, int);
-	void	(*get_width)(struct scsi_device *);
-	void	(*set_width)(struct scsi_device *, int);
-	void	(*get_iu)(struct scsi_device *);
-	void	(*set_iu)(struct scsi_device *, int);
-	void	(*get_dt)(struct scsi_device *);
-	void	(*set_dt)(struct scsi_device *, int);
-	void	(*get_qas)(struct scsi_device *);
-	void	(*set_qas)(struct scsi_device *, int);
-	void	(*get_wr_flow)(struct scsi_device *);
-	void	(*set_wr_flow)(struct scsi_device *, int);
-	void	(*get_rd_strm)(struct scsi_device *);
-	void	(*set_rd_strm)(struct scsi_device *, int);
-	void	(*get_rti)(struct scsi_device *);
-	void	(*set_rti)(struct scsi_device *, int);
-	void	(*get_pcomp_en)(struct scsi_device *);
-	void	(*set_pcomp_en)(struct scsi_device *, int);
+	void	(*get_period)(struct scsi_target *);
+	void	(*set_period)(struct scsi_target *, int);
+	void	(*get_offset)(struct scsi_target *);
+	void	(*set_offset)(struct scsi_target *, int);
+	void	(*get_width)(struct scsi_target *);
+	void	(*set_width)(struct scsi_target *, int);
+	void	(*get_iu)(struct scsi_target *);
+	void	(*set_iu)(struct scsi_target *, int);
+	void	(*get_dt)(struct scsi_target *);
+	void	(*set_dt)(struct scsi_target *, int);
+	void	(*get_qas)(struct scsi_target *);
+	void	(*set_qas)(struct scsi_target *, int);
+	void	(*get_wr_flow)(struct scsi_target *);
+	void	(*set_wr_flow)(struct scsi_target *, int);
+	void	(*get_rd_strm)(struct scsi_target *);
+	void	(*set_rd_strm)(struct scsi_target *, int);
+	void	(*get_rti)(struct scsi_target *);
+	void	(*set_rti)(struct scsi_target *, int);
+	void	(*get_pcomp_en)(struct scsi_target *);
+	void	(*set_pcomp_en)(struct scsi_target *, int);
+	void	(*get_signalling)(struct Scsi_Host *);
+	void	(*set_signalling)(struct Scsi_Host *, enum spi_signal_type);
 	/* The driver sets these to tell the transport class it
 	 * wants the attributes displayed in sysfs.  If the show_ flag
 	 * is not set, the attribute will be private to the transport