diff -u b/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- b/drivers/scsi/Kconfig	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/Kconfig	2004-10-06 22:21:18 -07:00
@@ -1028,6 +1028,7 @@
 config SCSI_ZALON
 	tristate "Zalon SCSI support"
 	depends on GSC && SCSI
+	select SCSI_SPI_ATTRS
 	help
 	  The Zalon is a GSC/HSC bus interface chip that sits between the
 	  PA-RISC processor and the NCR 53c720 SCSI controller on C100,
@@ -1038,6 +1039,7 @@
 config SCSI_NCR_Q720
 	tristate "NCR Quad 720 MCA SCSI support"
 	depends on MCA && SCSI
+	select SCSI_SPI_ATTRS
 	help
 	  This is a driver for the MicroChannel Quad 720 card produced by
 	  NCR and commonly used in 345x/35xx/4100 class machines.  It always
diff -u b/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- b/drivers/scsi/ncr53c8xx.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/ncr53c8xx.c	2004-10-06 22:21:18 -07:00
@@ -123,6 +123,8 @@
 #include <scsi/scsi_cmnd.h>
 #include <scsi/scsi_device.h>
 #include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
 
 #include "ncr53c8xx.h"
 
@@ -412,6 +414,8 @@
 **==========================================================
 */
 
+static struct scsi_transport_template *ncr53c8xx_transport_template = NULL;
+
 struct tcb;
 struct lcb;
 struct ccb;
@@ -532,7 +536,7 @@
 	u_char	usrwide;
 	u_char	usrtags;
 	u_char	usrflag;
-	struct scsi_device *sdev;
+	struct scsi_target *starget;
 };
 
 /*========================================================================
@@ -1212,7 +1216,7 @@
 static	void	ncr_init_ccb	(struct ncb *np, struct ccb *cp);
 static	void	ncr_init_tcb	(struct ncb *np, u_char tn);
 static	struct lcb *	ncr_alloc_lcb	(struct ncb *np, u_char tn, u_char ln);
-static	struct lcb *	ncr_setup_lcb	(struct ncb *np, u_char tn, u_char ln);
+static	struct lcb *	ncr_setup_lcb	(struct ncb *np, struct scsi_device *sdev);
 static	void	ncr_getclock	(struct ncb *np, int mult);
 static	void	ncr_selectclock	(struct ncb *np, u_char scntl3);
 static	struct ccb *ncr_get_ccb	(struct ncb *np, u_char tn, u_char ln);
@@ -1232,7 +1236,7 @@
 static	int	ncr_scatter	(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd);
 static	void	ncr_getsync	(struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p);
 static	void	ncr_setsync	(struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer);
-static	void	ncr_setup_tags	(struct ncb *np, u_char tn, u_char ln);
+static	void	ncr_setup_tags	(struct ncb *np, struct scsi_device *sdev);
 static	void	ncr_setwide	(struct ncb *np, struct ccb *cp, u_char wide, u_char ack);
 static	int	ncr_show_msg	(u_char * msg);
 static  void    ncr_print_msg   (struct ccb *cp, char *label, u_char *msg);
@@ -3363,16 +3367,16 @@
 	struct tcb *tp = &np->target[cp->target];
 	int msglen = 0;
 	int nego = 0;
-	struct scsi_device *sdev = tp->sdev;
+	struct scsi_target *starget = tp->starget;
 
-	if (likely(sdev)) {
+	if (likely(starget)) {
 
 		/*
 		**	negotiate wide transfers ?
 		*/
 
 		if (!tp->widedone) {
-			if (sdev->wdtr) {
+			if (spi_support_wide(starget)) {
 				nego = NS_WIDE;
 			} else
 				tp->widedone=1;
@@ -3384,7 +3388,7 @@
 		*/
 
 		if (!nego && !tp->period) {
-			if (sdev->sdtr) {
+			if (spi_support_sync(starget)) {
 				nego = NS_SYNC;
 			} else {
 				tp->period  =0xffff;
@@ -4273,7 +4277,7 @@
 			if (lp->num_good >= 1000) {
 				lp->num_good = 0;
 				++lp->numtags;
-				ncr_setup_tags (np, cmd->device->id, cmd->device->lun);
+				ncr_setup_tags (np, cmd->device);
 			}
 		}
 	} else if ((cp->host_status == HS_COMPLETE)
@@ -4723,8 +4727,11 @@
 	if (minsync > np->maxsync)
 		minsync = 255;
 
+	if (tp->maxoffs > np->maxoffs)
+		tp->maxoffs = np->maxoffs;
+
 	tp->minsync = minsync;
-	tp->maxoffs = (minsync<255 ? np->maxoffs : 0);
+	tp->maxoffs = (minsync<255 ? tp->maxoffs : 0);
 
 	/*
 	**	period=0: has to negotiate sync transfer
@@ -4978,12 +4985,12 @@
 **==========================================================
 */
 
-static void ncr_setup_tags (struct ncb *np, u_char tn, u_char ln)
+static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev)
 {
+	unsigned char tn = sdev->id, ln = sdev->lun;
 	struct tcb *tp = &np->target[tn];
 	struct lcb *lp = tp->lp[ln];
 	u_char   reqtags, maxdepth;
-	struct scsi_device *sdev = tp->sdev;
 
 	/*
 	**	Just in case ...
@@ -5939,7 +5946,7 @@
 		if (disc_cnt < lp->numtags) {
 			lp->numtags	= disc_cnt > 2 ? disc_cnt : 2;
 			lp->num_good	= 0;
-			ncr_setup_tags (np, cmd->device->id, cmd->device->lun);
+			ncr_setup_tags (np, cmd->device);
 		}
 		/*
 		**	Requeue the command to the start queue.
@@ -6078,6 +6085,7 @@
 	u_long	dsa    = INL (nc_dsa);
 	u_char	target = INB (nc_sdid) & 0x0f;
 	struct tcb *tp     = &np->target[target];
+	struct scsi_target *starget = tp->starget;
 
 	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
 
@@ -6235,10 +6243,13 @@
 
 		case NS_SYNC:
 			ncr_setsync (np, cp, 0, 0xe0);
+			spi_period(starget) = 0;
+			spi_offset(starget) = 0;
 			break;
 
 		case NS_WIDE:
 			ncr_setwide (np, cp, 0, 0);
+			spi_width(starget) = 0;
 			break;
 
 		};
@@ -6273,8 +6284,8 @@
 		**	      it CAN transfer synch.
 		*/
 
-		if (ofs && tp->sdev)
-			tp->sdev->sdtr = 1;
+		if (ofs && tp->starget)
+			spi_support_sync(tp->starget) = 1;
 
 		/*
 		**	check values against driver limits.
@@ -6325,18 +6336,23 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setsync (np, cp, 0, 0xe0);
+					spi_period(starget) = 0;
+					spi_offset(starget) = 0;
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
 					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+					spi_period(starget) = per;
+					spi_offset(starget) = ofs;
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
 			case NS_WIDE:
 				ncr_setwide (np, cp, 0, 0);
+				spi_width(starget) = 0;
 				break;
 			};
 		};
@@ -6347,6 +6363,8 @@
 		*/
 
 		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+		spi_period(starget) = per;
+		spi_offset(starget) = ofs;
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 3;
@@ -6394,8 +6412,8 @@
 		**	      it CAN transfer wide.
 		*/
 
-		if (wide && tp->sdev)
-			tp->sdev->wdtr = 1;
+		if (wide && tp->starget)
+			spi_support_wide(tp->starget) = 1;
 
 		/*
 		**	check values against driver limits.
@@ -6422,18 +6440,22 @@
 					**	Answer wasn't acceptable.
 					*/
 					ncr_setwide (np, cp, 0, 1);
+					spi_width(starget) = 0;
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
 				} else {
 					/*
 					**	Answer is ok.
 					*/
 					ncr_setwide (np, cp, wide, 1);
+					spi_width(starget) = wide;
 					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
 				};
 				return;
 
 			case NS_SYNC:
 				ncr_setsync (np, cp, 0, 0xe0);
+				spi_period(starget) = 0;
+				spi_offset(starget) = 0;
 				break;
 			};
 		};
@@ -6444,6 +6466,7 @@
 		*/
 
 		ncr_setwide (np, cp, wide, 1);
+		spi_width(starget) = wide;
 
 		np->msgout[0] = M_EXTENDED;
 		np->msgout[1] = 2;
@@ -6573,13 +6596,6 @@
 			ncr_alloc_ccb(np, tn, ln);
 
 		/*
-		**	Tune tag mode if asked by user.
-		*/
-		if (lp->queuedepth != lp->numtags) {
-			ncr_setup_tags(np, tn, ln);
-		}
-			
-		/*
 		**	Look for free CCB
 		*/
 		qp = ncr_list_pop(&lp->free_ccbq);
@@ -6796,7 +6812,6 @@
 	np->ccb->link_ccb = cp;
 
 	list_add(&cp->link_ccbq, &lp->free_ccbq);
-	ncr_setup_tags (np, tn, ln);
 }
 
 /*==========================================================
@@ -6994,11 +7009,12 @@
 **	will play with CHANGE DEFINITION commands. :-)
 **------------------------------------------------------------------------
 */
-static struct lcb *ncr_setup_lcb (struct ncb *np, u_char tn, u_char ln)
+static struct lcb *ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev)
 {
+	unsigned char tn = sdev->id, ln = sdev->lun;
 	struct tcb *tp = &np->target[tn];
 	struct lcb *lp = tp->lp[ln];
-	struct scsi_device *sdev = tp->sdev;
+	struct scsi_target *starget = tp->starget;
 
 	/*
 	**	If no lcb, try to allocate it.
@@ -7009,7 +7025,7 @@
 	/*
 	**	Prepare negotiation
 	*/
-	if (sdev->wdtr || sdev->sdtr)
+	if (spi_support_wide(starget) || spi_support_sync(starget))
 		ncr_negotiate(np, tp);
 
 	/*
@@ -7031,7 +7047,7 @@
 			lp->cb_tags[i] = i;
 		lp->maxnxs = MAX_TAGS;
 		lp->tags_stime = ktime_get(3*HZ);
-		ncr_setup_tags (np, tn, ln);
+		ncr_setup_tags (np, sdev);
 	}
 
 
@@ -7416,9 +7432,9 @@
 	struct lcb *lp = tp->lp[device->lun];
 	int numtags, depth_to_use;
 
-	tp->sdev = device;
+	tp->starget = device->sdev_target;
 
-	ncr_setup_lcb(np, device->id, device->lun);
+	ncr_setup_lcb(np, device);
 
 	/*
 	**	Select queue depth from driver setup.
@@ -7455,13 +7471,16 @@
 		lp->numtags = lp->maxtags = numtags;
 		lp->scdev_depth = depth_to_use;
 	}
-	ncr_setup_tags (np, device->id, device->lun);
+	ncr_setup_tags (np, device);
 
 #ifdef DEBUG_NCR53C8XX
 	printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
 	       np->unit, device->id, device->lun, depth_to_use);
 #endif
 
+	if (spi_support_sync(device->sdev_target) &&
+	    !spi_initial_dv(device->sdev_target))
+		spi_dv_device(device);
 	return 0;
 }
 
@@ -7856,6 +7875,10 @@
 	instance->dma_channel	= 0;
 	instance->cmd_per_lun	= MAX_TAGS;
 	instance->can_queue	= (MAX_START-4);
+	/* This can happen if you forget to call ncr53c8xx_init from
+	 * your module_init */
+	BUG_ON(!ncr53c8xx_transport_template);
+	instance->transportt	= ncr53c8xx_transport_template;
 	scsi_set_device(instance, device->dev);
 
 	/* Patch script to physical addresses */
@@ -7986,0 +8010,70 @@
+
+static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (period > np->maxsync)
+		period = np->maxsync;
+	else if (period < np->minsync)
+		period = np->minsync;
+
+	tp->usrsync = period;
+
+	ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_offset(struct scsi_target *starget, int offset)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (offset > np->maxoffs)
+		offset = np->maxoffs;
+	else if (offset < 0)
+		offset = 0;
+
+	tp->maxoffs = offset;
+
+	ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_width(struct scsi_target *starget, int width)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (width > np->maxwide)
+		width = np->maxwide;
+	else if (width < 0)
+		width = 0;
+
+	tp->usrwide = width;
+
+	ncr_negotiate(np, tp);
+}
+
+static struct spi_function_template ncr53c8xx_transport_functions =  {
+	.set_period	= ncr53c8xx_set_period,
+	.show_period	= 1,
+	.set_offset	= ncr53c8xx_set_offset,
+	.show_offset	= 1,
+	.set_width	= ncr53c8xx_set_width,
+	.show_width	= 1,
+};
+
+int __init ncr53c8xx_init(void)
+{
+	ncr53c8xx_transport_template = spi_attach_transport(&ncr53c8xx_transport_functions);
+	if (!ncr53c8xx_transport_template)
+		return -ENODEV;
+	return 0;
+}
+
+void ncr53c8xx_exit(void)
+{
+	spi_release_transport(ncr53c8xx_transport_template);
+}
diff -u b/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
--- b/drivers/scsi/ncr53c8xx.h	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/ncr53c8xx.h	2004-10-06 22:21:18 -07:00
@@ -96,4 +96,6 @@
 extern int ncr53c8xx_release(struct Scsi_Host *host);
 irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+extern int ncr53c8xx_init(void);
+extern void ncr53c8xx_exit(void);
 
 #endif /* NCR53C8XX_H */
diff -u b/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
--- b/drivers/scsi/qla2xxx/qla_os.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/qla2xxx/qla_os.c	2004-10-06 22:21:19 -07:00
@@ -4451,61 +4451,64 @@
 }
 
 static void
-qla2xxx_get_port_id(struct scsi_device *sdev)
+qla2xxx_get_port_id(struct scsi_target *starget)
 {
-	scsi_qla_host_t *ha = to_qla_host(sdev->host);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
 	struct fc_port *fc;
 
 	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == sdev->id) {
-			fc_port_id(sdev) = fc->d_id.b.domain << 16 |
+		if (fc->os_target_id == starget->id) {
+			fc_starget_port_id(starget) = fc->d_id.b.domain << 16 |
 				fc->d_id.b.area << 8 | 
 				fc->d_id.b.al_pa;
 			return;
 		}
 	}
-	fc_port_id(sdev) = -1;
+	fc_starget_port_id(starget) = -1;
 }
 
 static void
-qla2xxx_get_port_name(struct scsi_device *sdev)
+qla2xxx_get_port_name(struct scsi_target *starget)
 {
-	scsi_qla_host_t *ha = to_qla_host(sdev->host);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
 	struct fc_port *fc;
 
 	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == sdev->id) {
-			fc_port_name(sdev) =
+		if (fc->os_target_id == starget->id) {
+			fc_starget_port_name(starget) =
 				__be64_to_cpu(*(uint64_t *)fc->port_name);
 			return;
 		}
 	}
-	fc_port_name(sdev) = -1;
+	fc_starget_port_name(starget) = -1;
 }
 
 static void
-qla2xxx_get_node_name(struct scsi_device *sdev)
+qla2xxx_get_node_name(struct scsi_target *starget)
 {
-	scsi_qla_host_t *ha = to_qla_host(sdev->host);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
 	struct fc_port *fc;
 
 	list_for_each_entry(fc, &ha->fcports, list) {
-		if (fc->os_target_id == sdev->id) {
-			fc_node_name(sdev) =
+		if (fc->os_target_id == starget->id) {
+			fc_starget_node_name(starget) =
 				__be64_to_cpu(*(uint64_t *)fc->node_name);
 			return;
 		}
 	}
-	fc_node_name(sdev) = -1;
+	fc_starget_node_name(starget) = -1;
 }
 
 static struct fc_function_template qla2xxx_transport_functions = {
-	.get_port_id = qla2xxx_get_port_id,
-	.show_port_id = 1,
-	.get_port_name = qla2xxx_get_port_name,
-	.show_port_name = 1,
-	.get_node_name = qla2xxx_get_node_name,
-	.show_node_name = 1,
+	.get_starget_port_id = qla2xxx_get_port_id,
+	.show_starget_port_id = 1,
+	.get_starget_port_name = qla2xxx_get_port_name,
+	.show_starget_port_name = 1,
+	.get_starget_node_name = qla2xxx_get_node_name,
+	.show_starget_node_name = 1,
 };
 
 /**
diff -u b/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- b/drivers/scsi/scsi.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/scsi.c	2004-10-06 22:21:18 -07:00
@@ -528,6 +528,26 @@
 		/* return 0 (because the command has been processed) */
 		goto out;
 	}
+
+	/* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
+	if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+		/* 
+		 * in SDEV_BLOCK, the command is just put back on the device
+		 * queue.  The suspend state has already blocked the queue so
+		 * future requests should not occur until the device 
+		 * transitions out of the suspend state.
+		 */
+		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
+
+		/*
+		 * NOTE: rtn is still zero here because we don't need the
+		 * queue to be plugged on return (it's already stopped)
+		 */
+		goto out;
+	}
+
 	/* Assign a unique nonzero serial_number. */
 	/* XXX(hch): this is racy */
 	if (++serial_number == 0)
@@ -1113,8 +1133,8 @@
 
 /**
  * scsi_device_cancel - cancel outstanding IO to this device
- * @sdev:	pointer to struct scsi_device
- * @data:	pointer to cancel value.
+ * @sdev:	Pointer to struct scsi_device
+ * @recovery:	Boolean instructing function to recover device or not.
  *
  **/
 int scsi_device_cancel(struct scsi_device *sdev, int recovery)
diff -u b/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- b/drivers/scsi/scsi_lib.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/scsi_lib.c	2004-10-06 22:21: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++;
 
@@ -1642,6 +1642,7 @@
 		case SDEV_CREATED:
 		case SDEV_OFFLINE:
 		case SDEV_QUIESCE:
+		case SDEV_BLOCK:
 			break;
 		default:
 			goto illegal;
@@ -1669,11 +1670,22 @@
 		}
 		break;
 
+	case SDEV_BLOCK:
+		switch (oldstate) {
+		case SDEV_CREATED:
+		case SDEV_RUNNING:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
 	case SDEV_CANCEL:
 		switch (oldstate) {
 		case SDEV_CREATED:
 		case SDEV_RUNNING:
 		case SDEV_OFFLINE:
+		case SDEV_BLOCK:
 			break;
 		default:
 			goto illegal;
@@ -1753,0 +1766,109 @@
+
+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);
+
+/**
+ * scsi_internal_device_block - internal function to put a device
+ *				temporarily into the SDEV_BLOCK state
+ * @sdev:	device to block
+ *
+ * Block request made by scsi lld's to temporarily stop all
+ * scsi commands on the specified device.  Called from interrupt
+ * or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:       
+ *	This routine transitions the device to the SDEV_BLOCK state
+ *	(which must be a legal transition).  When the device is in this
+ *	state, all commands are deferred until the scsi lld reenables
+ *	the device with scsi_device_unblock or device_block_tmo fires.
+ *	This routine assumes the host_lock is held on entry.
+ **/
+int
+scsi_internal_device_block(struct scsi_device *sdev)
+{
+	request_queue_t *q = sdev->request_queue;
+	unsigned long flags;
+	int err = 0;
+
+	err = scsi_device_set_state(sdev, SDEV_BLOCK);
+	if (err)
+		return err;
+
+	/* 
+	 * The device has transitioned to SDEV_BLOCK.  Stop the
+	 * block layer from calling the midlayer with this device's
+	 * request queue. 
+	 */
+	spin_lock_irqsave(q->queue_lock, flags);
+	blk_stop_queue(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_block);
+ 
+/**
+ * scsi_internal_device_unblock - resume a device after a block request
+ * @sdev:	device to resume
+ *
+ * Called by scsi lld's or the midlayer to restart the device queue
+ * for the previously suspended scsi device.  Called from interrupt or
+ * normal process context.
+ *
+ * Returns zero if successful or error if not.
+ *
+ * Notes:       
+ *	This routine transitions the device to the SDEV_RUNNING state
+ *	(which must be a legal transition) allowing the midlayer to
+ *	goose the queue for this device.  This routine assumes the 
+ *	host_lock is held upon entry.
+ **/
+int
+scsi_internal_device_unblock(struct scsi_device *sdev)
+{
+	request_queue_t *q = sdev->request_queue; 
+	int err;
+	unsigned long flags;
+	
+	/* 
+	 * Try to transition the scsi device to SDEV_RUNNING
+	 * and goose the device queue if successful.  
+	 */
+	err = scsi_device_set_state(sdev, SDEV_RUNNING);
+	if (err)
+		return err;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	blk_start_queue(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
diff -u b/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- b/drivers/scsi/scsi_scan.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/scsi_scan.c	2004-10-06 22:21:18 -07:00
@@ -202,11 +202,12 @@
 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;
 	int display_failure_msg = 1, ret;
 
-	sdev = kmalloc(sizeof(*sdev) + shost->transportt->size, GFP_ATOMIC);
+	sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
+		       GFP_ATOMIC);
 	if (!sdev)
 		goto out;
 
@@ -265,67 +266,28 @@
 		}
 	}
 
-	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)) {
+	if (get_device(&sdev->host->shost_gendev) == NULL ||
+	    scsi_sysfs_device_initialize(sdev) != 0)
+		goto out_cleanup_slave;
 
-		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 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;
-		}
-	}
+	/* NOTE: this target initialisation code depends critically on
+	 * lun scanning being sequential. */
+	if (scsi_sysfs_target_initialize(sdev))
+		goto out_remove_siblings;
 
-	/*
-	 * 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;
-
-	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);
@@ -510,10 +472,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.
@@ -630,40 +588,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;
 
@@ -686,7 +613,10 @@
 	if (*bflags & BLIST_NOT_LOCKABLE)
 		sdev->lockable = 0;
 
-	if(sdev->host->hostt->slave_configure)
+	if (sdev->host->transportt->device_configure)
+		sdev->host->transportt->device_configure(sdev);
+
+	if (sdev->host->hostt->slave_configure)
 		sdev->host->hostt->slave_configure(sdev);
 
 	/*
@@ -803,8 +733,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:
@@ -1364,6 +1292,4 @@
 	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);
 }
diff -u b/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- b/drivers/scsi/scsi_sysfs.c	2004-10-06 22:21:09 -07:00
+++ b/drivers/scsi/scsi_sysfs.c	2004-10-06 22:21:18 -07:00
@@ -30,6 +30,7 @@
 	{ SDEV_DEL, "deleted" },
 	{ SDEV_QUIESCE, "quiesce" },
 	{ SDEV_OFFLINE,	"offline" },
+	{ SDEV_BLOCK,	"blocked" },
 };
 
 const char *scsi_device_state_name(enum scsi_device_state state)
@@ -153,25 +154,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 = {
@@ -432,6 +444,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
@@ -442,13 +462,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;
 	}
@@ -461,7 +523,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)
@@ -496,7 +557,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]);
@@ -540,8 +601,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:
@@ -628,6 +687,121 @@
 		}
 	}
 
+	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;
+		starget->channel = sdev->channel;
+		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;
 }
 
diff -u b/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- b/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-10-06 22:21:10 -07:00
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	2004-10-06 22:21:19 -07:00
@@ -1083,7 +1083,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;
 }
@@ -2302,35 +2303,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)
@@ -2339,18 +2366,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)
@@ -2359,18 +2388,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;
@@ -2392,6 +2423,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 = {
diff -u b/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
--- b/include/scsi/scsi_device.h	2004-10-06 22:21:09 -07:00
+++ b/include/scsi/scsi_device.h	2004-10-06 22:21:18 -07:00
@@ -30,6 +30,9 @@
 				 * originate in the mid-layer) */
 	SDEV_OFFLINE,		/* Device offlined (by error handling or
 				 * user request */
+	SDEV_BLOCK,		/* Device blocked by scsi lld.  No scsi 
+				 * commands from user or midlayer should be issued
+				 * to the scsi lld. */
 };
 
 struct scsi_device {
@@ -122,7 +125,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)
@@ -131,6 +134,30 @@
 #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		channel;
+	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) \
@@ -193,6 +220,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)
 {
diff -u b/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
--- b/include/scsi/scsi_host.h	2004-10-06 22:21:09 -07:00
+++ b/include/scsi/scsi_host.h	2004-10-06 22:21:18 -07:00
@@ -502,6 +502,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.
@@ -513,6 +520,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 __must_check scsi_add_host(struct Scsi_Host *, struct device *);
only in patch2:
unchanged:
--- a/drivers/s390/scsi/zfcp_scsi.c	2004-10-06 22:21:19 -07:00
+++ b/drivers/s390/scsi/zfcp_scsi.c	2004-10-06 22:21:19 -07:00
@@ -48,6 +48,8 @@
 
 static struct zfcp_unit *zfcp_unit_lookup(struct zfcp_adapter *, int, scsi_id_t,
 					  scsi_lun_t);
+static struct zfcp_port * zfcp_port_lookup(struct zfcp_adapter *, int,
+					 scsi_id_t);
 
 static struct device_attribute *zfcp_sysfs_sdev_attrs[];
 
@@ -398,6 +400,26 @@
  out:
 	return retval;
 }
+/*
+ * function:    zfcp_unit_tgt_lookup
+ *
+ * purpose:
+ *
+ * returns:
+ *
+ * context:	
+ */
+static struct zfcp_port *
+zfcp_port_lookup(struct zfcp_adapter *adapter, int channel, scsi_id_t id)
+{
+	struct zfcp_port *port;
+
+	list_for_each_entry(port, &adapter->port_list_head, list) {
+		if (id == port->scsi_id)
+			return port;
+	}
+	return (zfcp_port *)NULL;
+}
 
 /*
  * function:	zfcp_scsi_eh_abort_handler
@@ -839,39 +861,63 @@
  * Support functions for FC transport class
  */
 static void
-zfcp_get_port_id(struct scsi_device *sdev)
+zfcp_get_port_id(struct scsi_target *starget)
 {
-	struct zfcp_unit *unit;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
+	struct zfcp_port *port;
+	unsigned long flags;
 
-	unit = (struct zfcp_unit *) sdev->hostdata;
-	fc_port_id(sdev) = unit->port->d_id;
+	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
+	if (port)
+		fc_starget_port_id(starget) = port->d_id;
+	else
+		fc_starget_port_id(starget) = -1;
+	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
 static void
-zfcp_get_port_name(struct scsi_device *sdev)
+zfcp_get_port_name(struct scsi_target *starget)
 {
-	struct zfcp_unit *unit;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
+	struct zfcp_port *port;
+	unsigned long flags;
 
-	unit = (struct zfcp_unit *) sdev->hostdata;
-	fc_port_name(sdev) = unit->port->wwpn;
+	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
+	if (port)
+		fc_starget_port_name(starget) = port->wwpn;
+	else
+		fc_starget_port_name(starget) = -1;
+	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
 static void
-zfcp_get_node_name(struct scsi_device *sdev)
+zfcp_get_node_name(struct scsi_target *starget)
 {
-	struct zfcp_unit *unit;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct zfcp_adapter *adapter = (struct zfcp_adapter *)shost->hostdata[0];
+	struct zfcp_port *port;
+	unsigned long flags;
 
-	unit = (struct zfcp_unit *) sdev->hostdata;
-	fc_node_name(sdev) = unit->port->wwnn;
+	read_lock_irqsave(&zfcp_data.config_lock, flags);
+	port = zfcp_port_lookup(adapter, starget->channel, starget->id);
+	if (port)
+		fc_starget_node_name(starget) = port->wwnn;
+	else
+		fc_starget_node_name(starget) = -1;
+	read_unlock_irqrestore(&zfcp_data.config_lock, flags);
 }
 
 struct fc_function_template zfcp_transport_functions = {
-	.get_port_id = zfcp_get_port_id,
-	.get_port_name = zfcp_get_port_name,
-	.get_node_name = zfcp_get_node_name,
-	.show_port_id = 1,
-	.show_port_name = 1,
-	.show_node_name = 1,
+	.get_starget_port_id = zfcp_get_port_id,
+	.get_starget_port_name = zfcp_get_port_name,
+	.get_starget_node_name = zfcp_get_node_name,
+	.show_starget_port_id = 1,
+	.show_starget_port_name = 1,
+	.show_starget_node_name = 1,
 };
 
 /**
only in patch2:
unchanged:
--- a/drivers/scsi/53c700.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/53c700.c	2004-10-06 22:21: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-10-06 22:21:18 -07:00
+++ b/drivers/scsi/53c700.h	2004-10-06 22:21: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-10-06 22:21:18 -07:00
+++ b/drivers/scsi/NCR_D700.c	2004-10-06 22:21: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/NCR_Q720.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/NCR_Q720.c	2004-10-06 22:21:18 -07:00
@@ -358,13 +358,19 @@
 static int __init
 NCR_Q720_init(void)
 {
-	return mca_register_driver(&NCR_Q720_driver);
+	int ret = ncr53c8xx_init();
+	if (!ret)
+		ret = mca_register_driver(&NCR_Q720_driver);
+	if (ret)
+		ncr53c8xx_exit();
+	return ret;
 }
 
 static void __exit
 NCR_Q720_exit(void)
 {
 	mca_unregister_driver(&NCR_Q720_driver);
+	ncr53c8xx_exit();
 }
 
 module_init(NCR_Q720_init);
only in patch2:
unchanged:
--- a/drivers/scsi/hosts.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/hosts.c	2004-10-06 22:21: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-10-06 22:21:18 -07:00
+++ b/drivers/scsi/lasi700.c	2004-10-06 22:21: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-10-06 22:21:18 -07:00
+++ b/drivers/scsi/scsi_priv.h	2004-10-06 22:21: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,9 +146,20 @@
 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;
 extern struct bus_type scsi_bus_type;
+
+/* 
+ * internal scsi timeout functions: for use by mid-layer and transport
+ * classes.
+ */
+
+#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT	(HZ*60)
+extern int scsi_internal_device_block(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev);
 
 #endif /* _SCSI_PRIV_H */
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_transport_fc.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/scsi_transport_fc.c	2004-10-06 22:21:18 -07:00
@@ -23,23 +23,31 @@
 #include <scsi/scsi_host.h>
 #include <scsi/scsi_transport.h>
 #include <scsi/scsi_transport_fc.h>
+#include "scsi_priv.h"
 
 #define FC_PRINTK(x, l, f, a...)	printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a)
 
 static void transport_class_release(struct class_device *class_dev);
+static void host_class_release(struct class_device *class_dev);
 
-#define FC_NUM_ATTRS 	3	/* increase this if you add attributes */
-#define FC_OTHER_ATTRS 	0	/* increase this if you add "always on"
-				 * attributes */
+#define FC_STARGET_NUM_ATTRS 	4	/* increase this if you add attributes */
+#define FC_STARGET_OTHER_ATTRS 	0	/* increase this if you add "always on"
+					 * attributes */
+#define FC_HOST_NUM_ATTRS	1
 
 struct fc_internal {
 	struct scsi_transport_template t;
 	struct fc_function_template *f;
 	/* The actual attributes */
-	struct class_device_attribute private_attrs[FC_NUM_ATTRS];
+	struct class_device_attribute private_starget_attrs[
+						FC_STARGET_NUM_ATTRS];
 	/* The array of null terminated pointers to attributes
 	 * needed by scsi_sysfs.c */
-	struct class_device_attribute *attrs[FC_NUM_ATTRS + FC_OTHER_ATTRS + 1];
+	struct class_device_attribute *starget_attrs[
+			FC_STARGET_NUM_ATTRS + FC_STARGET_OTHER_ATTRS + 1];
+
+	struct class_device_attribute private_host_attrs[FC_HOST_NUM_ATTRS];
+	struct class_device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1];
 };
 
 #define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t)
@@ -49,101 +57,211 @@
 	.release = transport_class_release,
 };
 
+struct class fc_host_class = {
+	.name = "fc_host",
+	.release = host_class_release,
+};
+
 static __init int fc_transport_init(void)
 {
+	int error = class_register(&fc_host_class);
+	if (error)
+		return error;
 	return class_register(&fc_transport_class);
 }
 
 static void __exit fc_transport_exit(void)
 {
 	class_unregister(&fc_transport_class);
+	class_unregister(&fc_host_class);
 }
 
-static int fc_setup_transport_attrs(struct scsi_device *sdev)
+static int fc_setup_starget_transport_attrs(struct scsi_target *starget)
 {
-	/* I'm not sure what values are invalid.  We should pick some invalid
-	 * values for the defaults */
-	fc_node_name(sdev) = -1;
-	fc_port_name(sdev) = -1;
-	fc_port_id(sdev) = -1;
+	/* 
+	 * Set default values easily detected by the midlayer as
+	 * failure cases.  The scsi lldd is responsible for initializing
+	 * all transport attributes to valid values per target.
+	 */
+	fc_starget_node_name(starget) = -1;
+	fc_starget_port_name(starget) = -1;
+	fc_starget_port_id(starget) = -1;
+	fc_starget_dev_loss_tmo(starget) = -1;
+	init_timer(&fc_starget_dev_loss_timer(starget));
+	return 0;
+}
 
+static int fc_setup_host_transport_attrs(struct Scsi_Host *shost)
+{
+	/* 
+	 * Set default values easily detected by the midlayer as
+	 * failure cases.  The scsi lldd is responsible for initializing
+	 * all transport attributes to valid values per host.
+	 */
+	fc_host_link_down_tmo(shost) = -1;
+	init_timer(&fc_host_link_down_timer(shost));
 	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);
 }
 
-#define fc_transport_show_function(field, format_string, cast)		\
-									\
+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);
+}
+
+
+/*
+ * Remote Port Attribute Management
+ */
+
+#define fc_starget_show_function(field, format_string, cast)		\
 static ssize_t								\
-show_fc_transport_##field (struct class_device *cdev, char *buf)	\
+show_fc_starget_##field (struct class_device *cdev, char *buf)		\
 {									\
-	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;	\
-	if (i->f->get_##field)						\
-		i->f->get_##field(sdev);				\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_starget_attrs *tp;					\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	tp = (struct fc_starget_attrs *)&starget->starget_data;		\
+	if (i->f->get_starget_##field)					\
+		i->f->get_starget_##field(starget);			\
 	return snprintf(buf, 20, format_string, cast tp->field);	\
 }
 
-#define fc_transport_store_function(field, format_string)		\
+#define fc_starget_store_function(field, format_string)			\
 static ssize_t								\
-store_fc_transport_##field(struct class_device *cdev, const char *buf,	\
+store_fc_starget_##field(struct class_device *cdev, const char *buf,	\
 			   size_t count)				\
 {									\
 	int val;							\
-	struct scsi_device *sdev = transport_class_to_sdev(cdev);	\
-	struct fc_internal *i = to_fc_internal(sdev->host->transportt);	\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
 									\
 	val = simple_strtoul(buf, NULL, 0);				\
-	i->f->set_##field(sdev, val);					\
+	i->f->set_starget_##field(starget, val);			\
 	return count;							\
 }
 
-#define fc_transport_rd_attr(field, format_string)			\
-	fc_transport_show_function(field, format_string, )		\
+#define fc_starget_rd_attr(field, format_string)			\
+	fc_starget_show_function(field, format_string, )		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
+			 show_fc_starget_##field, NULL)
+
+#define fc_starget_rd_attr_cast(field, format_string, cast)		\
+	fc_starget_show_function(field, format_string, (cast))		\
 static CLASS_DEVICE_ATTR(field, S_IRUGO,				\
-			 show_fc_transport_##field, NULL)
+			  show_fc_starget_##field, NULL)
 
-#define fc_transport_rd_attr_cast(field, format_string, cast)		\
-	fc_transport_show_function(field, format_string, (cast))	\
-static CLASS_DEVICE_ATTR( field, S_IRUGO,				\
-			  show_fc_transport_##field, NULL)
-
-#define fc_transport_rw_attr(field, format_string)			\
-	fc_transport_show_function(field, format_string, )		\
-	fc_transport_store_function(field, format_string)		\
+#define fc_starget_rw_attr(field, format_string)			\
+	fc_starget_show_function(field, format_string, )		\
+	fc_starget_store_function(field, format_string)			\
 static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
-			show_fc_transport_##field,			\
-			store_fc_transport_##field)
+			show_fc_starget_##field,			\
+			store_fc_starget_##field)
 
-/* the FiberChannel Tranport Attributes: */
-fc_transport_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
-fc_transport_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
-fc_transport_rd_attr(port_id, "0x%06x\n");
-
-#define SETUP_ATTRIBUTE_RD(field)				\
-	i->private_attrs[count] = class_device_attr_##field;	\
-	i->private_attrs[count].attr.mode = S_IRUGO;		\
-	i->private_attrs[count].store = NULL;			\
-	i->attrs[count] = &i->private_attrs[count];		\
-	if (i->f->show_##field)					\
+#define SETUP_STARGET_ATTRIBUTE_RD(field)				\
+	i->private_starget_attrs[count] = class_device_attr_##field;	\
+	i->private_starget_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_starget_attrs[count].store = NULL;			\
+	i->starget_attrs[count] = &i->private_starget_attrs[count];	\
+	if (i->f->show_starget_##field)					\
 		count++
 
-#define SETUP_ATTRIBUTE_RW(field)				\
-	i->private_attrs[count] = class_device_attr_##field;	\
-	if (!i->f->set_##field) {				\
-		i->private_attrs[count].attr.mode = S_IRUGO;	\
-		i->private_attrs[count].store = NULL;		\
-	}							\
-	i->attrs[count] = &i->private_attrs[count];		\
-	if (i->f->show_##field)					\
+#define SETUP_STARGET_ATTRIBUTE_RW(field)				\
+	i->private_starget_attrs[count] = class_device_attr_##field;	\
+	if (!i->f->set_starget_##field) {				\
+		i->private_starget_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_starget_attrs[count].store = NULL;		\
+	}								\
+	i->starget_attrs[count] = &i->private_starget_attrs[count];	\
+	if (i->f->show_starget_##field)					\
 		count++
 
+/* The FC Tranport Remote Port (Target) Attributes: */
+fc_starget_rd_attr_cast(node_name, "0x%llx\n", unsigned long long);
+fc_starget_rd_attr_cast(port_name, "0x%llx\n", unsigned long long);
+fc_starget_rd_attr(port_id, "0x%06x\n");
+fc_starget_rw_attr(dev_loss_tmo, "%d\n");
+
+
+/*
+ * Host Attribute Management
+ */
+
+#define fc_host_show_function(field, format_string, cast)		\
+static ssize_t								\
+show_fc_host_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct fc_host_attrs *tp;					\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	tp = (struct fc_host_attrs *)&shost->shost_data;		\
+	if (i->f->get_host_##field)					\
+		i->f->get_host_##field(shost);				\
+	return snprintf(buf, 20, format_string, cast tp->field);	\
+}
+
+#define fc_host_store_function(field, format_string)			\
+static ssize_t								\
+store_fc_host_##field(struct class_device *cdev, const char *buf,	\
+			   size_t count)				\
+{									\
+	int val;							\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+									\
+	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_host_##field(shost, val);				\
+	return count;							\
+}
+
+#define fc_host_rd_attr(field, format_string)				\
+	fc_host_show_function(field, format_string, )			\
+static CLASS_DEVICE_ATTR(host_##field, S_IRUGO,				\
+			 show_fc_host_##field, NULL)
+
+#define fc_host_rd_attr_cast(field, format_string, cast)		\
+	fc_host_show_function(field, format_string, (cast))		\
+static CLASS_DEVICE_ATTR(host_##field, S_IRUGO,				\
+			  show_fc_host_##field, NULL)
+
+#define fc_host_rw_attr(field, format_string)				\
+	fc_host_show_function(field, format_string, )			\
+	fc_host_store_function(field, format_string)			\
+static CLASS_DEVICE_ATTR(host_##field, S_IRUGO | S_IWUSR,		\
+			show_fc_host_##field,				\
+			store_fc_host_##field)
+
+#define SETUP_HOST_ATTRIBUTE_RD(field)					\
+	i->private_host_attrs[count] = class_device_attr_host_##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];		\
+	if (i->f->show_host_##field)					\
+		count++
+
+#define SETUP_HOST_ATTRIBUTE_RW(field)					\
+	i->private_host_attrs[count] = class_device_attr_host_##field;	\
+	if (!i->f->set_host_##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];		\
+	if (i->f->show_host_##field)					\
+		count++
+
+/* The FC Tranport Host Attributes: */
+fc_host_rw_attr(link_down_tmo, "%d\n");
+
+
+
 struct scsi_transport_template *
 fc_attach_transport(struct fc_function_template *ft)
 {
@@ -156,21 +274,43 @@
 
 	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.target_attrs = &i->starget_attrs[0];
+	i->t.target_class = &fc_transport_class;
+	i->t.target_setup = &fc_setup_starget_transport_attrs;
+	i->t.target_size = sizeof(struct fc_starget_attrs);
+
+	i->t.host_attrs = &i->host_attrs[0];
+	i->t.host_class = &fc_host_class;
+	i->t.host_setup = &fc_setup_host_transport_attrs;
+	i->t.host_size = sizeof(struct fc_host_attrs);
 	i->f = ft;
 
-	SETUP_ATTRIBUTE_RD(port_id);
-	SETUP_ATTRIBUTE_RD(port_name);
-	SETUP_ATTRIBUTE_RD(node_name);
+	
+	/*
+	 * setup remote port (target) attributes
+	 */
+	SETUP_STARGET_ATTRIBUTE_RD(port_id);
+	SETUP_STARGET_ATTRIBUTE_RD(port_name);
+	SETUP_STARGET_ATTRIBUTE_RD(node_name);
+	SETUP_STARGET_ATTRIBUTE_RW(dev_loss_tmo);
 
-	BUG_ON(count > FC_NUM_ATTRS);
+	BUG_ON(count > FC_STARGET_NUM_ATTRS);
 
 	/* Setup the always-on attributes here */
 
-	i->attrs[count] = NULL;
+	i->starget_attrs[count] = NULL;
+
+
+	/* setup host attributes */
+	count=0;
+	SETUP_HOST_ATTRIBUTE_RW(link_down_tmo);
+
+	BUG_ON(count > FC_HOST_NUM_ATTRS);
+
+	/* Setup the always-on attributes here */
+
+	i->host_attrs[count] = NULL;
+
 
 	return &i->t;
 }
@@ -184,6 +324,204 @@
 }
 EXPORT_SYMBOL(fc_release_transport);
 
+
+
+/**
+ * fc_device_block - called by target functions to block a scsi device
+ * @dev:	scsi device
+ * @data:	unused
+ **/
+static int fc_device_block(struct device *dev, void *data)
+{
+	scsi_internal_device_block(to_scsi_device(dev));
+	return 0;
+}
+
+/**
+ * fc_device_unblock - called by target functions to unblock a scsi device
+ * @dev:	scsi device
+ * @data:	unused
+ **/
+static int fc_device_unblock(struct device *dev, void *data)
+{
+	scsi_internal_device_unblock(to_scsi_device(dev));
+	return 0;
+}
+
+/**
+ * fc_timeout_blocked_tgt - Timeout handler for blocked scsi targets
+ *			 that fail to recover in the alloted time.
+ * @data:	scsi target that failed to reappear in the alloted time.
+ **/
+static void fc_timeout_blocked_tgt(unsigned long data)
+{
+	struct scsi_target *starget = (struct scsi_target *)data;
+
+	dev_printk(KERN_ERR, &starget->dev, 
+		"blocked target time out: target resuming\n");
+
+	/* 
+	 * set the device going again ... if the scsi lld didn't
+	 * unblock this device, then IO errors will probably
+	 * result if the host still isn't ready.
+	 */
+	device_for_each_child(&starget->dev, NULL, fc_device_unblock);
+}
+
+/**
+ * fc_target_block - block a target by temporarily putting all its scsi devices
+ *		into the SDEV_BLOCK state.
+ * @starget:	scsi target managed by this fc scsi lldd.
+ *
+ * scsi lldd's with a FC transport call this routine to temporarily stop all
+ * scsi commands to all devices managed by this scsi target.  Called 
+ * from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:       
+ *	The timeout and timer types are extracted from the fc transport 
+ *	attributes from the caller's target pointer.  This routine assumes no
+ *	locks are held on entry.
+ **/
+int
+fc_target_block(struct scsi_target *starget)
+{
+	int timeout = fc_starget_dev_loss_tmo(starget);
+	struct timer_list *timer = &fc_starget_dev_loss_timer(starget);
+
+	if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+		return -EINVAL;
+
+	device_for_each_child(&starget->dev, NULL, fc_device_block);
+
+	/* The scsi lld blocks this target for the timeout period only. */
+	timer->data = (unsigned long)starget;
+	timer->expires = jiffies + timeout * HZ;
+	timer->function = fc_timeout_blocked_tgt;
+	add_timer(timer);
+
+	return 0;
+}
+EXPORT_SYMBOL(fc_target_block);
+
+/**
+ * fc_target_unblock - unblock a target following a fc_target_block request.
+ * @starget:	scsi target managed by this fc scsi lldd.	
+ *
+ * scsi lld's with a FC transport call this routine to restart IO to all 
+ * devices associated with the caller's scsi target following a fc_target_block
+ * request.  Called from interrupt or normal process context.
+ *
+ * Notes:       
+ *	This routine assumes no locks are held on entry.
+ **/
+void
+fc_target_unblock(struct scsi_target *starget)
+{
+	/* 
+	 * Stop the target timer first. Take no action on the del_timer
+	 * failure as the state machine state change will validate the
+	 * transaction. 
+	 */
+	del_timer_sync(&fc_starget_dev_loss_timer(starget));
+
+	device_for_each_child(&starget->dev, NULL, fc_device_unblock);
+}
+EXPORT_SYMBOL(fc_target_unblock);
+
+/**
+ * fc_timeout_blocked_host - Timeout handler for blocked scsi hosts
+ *			 that fail to recover in the alloted time.
+ * @data:	scsi host that failed to recover its devices in the alloted
+ *		time.
+ **/
+static void fc_timeout_blocked_host(unsigned long data)
+{
+	struct Scsi_Host *shost = (struct Scsi_Host *)data;
+	struct scsi_device *sdev;
+
+	dev_printk(KERN_ERR, &shost->shost_gendev, 
+		"blocked host time out: host resuming\n");
+
+	shost_for_each_device(sdev, shost) {
+		/* 
+		 * set the device going again ... if the scsi lld didn't
+		 * unblock this device, then IO errors will probably
+		 * result if the host still isn't ready.
+		 */
+		scsi_internal_device_unblock(sdev);
+	}
+}
+
+/**
+ * fc_host_block - block all scsi devices managed by the calling host temporarily 
+ *		by putting each device in the SDEV_BLOCK state.
+ * @shost:	scsi host pointer that contains all scsi device siblings.
+ *
+ * scsi lld's with a FC transport call this routine to temporarily stop all
+ * scsi commands to all devices managed by this host.  Called 
+ * from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ *	The timeout and timer types are extracted from the fc transport 
+ *	attributes from the caller's host pointer.  This routine assumes no
+ *	locks are held on entry.
+ **/
+int
+fc_host_block(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+	int timeout = fc_host_link_down_tmo(shost);
+	struct timer_list *timer = &fc_host_link_down_timer(shost);
+
+	if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+		return -EINVAL;
+
+	shost_for_each_device(sdev, shost) {
+		scsi_internal_device_block(sdev);
+	}
+
+	/* The scsi lld blocks this host for the timeout period only. */
+	timer->data = (unsigned long)shost;
+	timer->expires = jiffies + timeout * HZ;
+	timer->function = fc_timeout_blocked_host;
+	add_timer(timer);
+
+	return 0;
+}
+EXPORT_SYMBOL(fc_host_block);
+
+/**
+ * fc_host_unblock - unblock all devices managed by this host following a 
+ *		fc_host_block request.
+ * @shost:	scsi host containing all scsi device siblings to unblock.
+ *
+ * scsi lld's with a FC transport call this routine to restart IO to all scsi
+ * devices managed by the specified scsi host following an fc_host_block 
+ * request.  Called from interrupt or normal process context.
+ *
+ * Notes:       
+ *	This routine assumes no locks are held on entry.
+ **/
+void
+fc_host_unblock(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+
+	/* 
+	 * Stop the host timer first. Take no action on the del_timer
+	 * failure as the state machine state change will validate the
+	 * transaction.
+	 */
+	del_timer_sync(&fc_host_link_down_timer(shost));
+	shost_for_each_device(sdev, shost) {
+		scsi_internal_device_unblock(sdev);
+	}
+}
+EXPORT_SYMBOL(fc_host_unblock);
 
 MODULE_AUTHOR("Martin Hicks");
 MODULE_DESCRIPTION("FC Transport Attributes");
only in patch2:
unchanged:
--- a/drivers/scsi/scsi_transport_spi.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/scsi_transport_spi.c	2004-10-06 22:21: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,117 @@
  * 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_configure_device(struct scsi_device *sdev)
 {
-	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));
+	struct scsi_target *starget = sdev->sdev_target;
+
+	/* Populate the target capability fields with the values
+	 * gleaned from the device inquiry */
+
+	spi_support_sync(starget) = scsi_device_sync(sdev);
+	spi_support_wide(starget) = scsi_device_wide(sdev);
+	spi_support_dt(starget) = scsi_device_dt(sdev);
+	spi_support_dt_only(starget) = scsi_device_dt_only(sdev);
+	spi_support_ius(starget) = scsi_device_ius(sdev);
+	spi_support_qas(starget) = scsi_device_qas(sdev);
+
+	return 0;
+}
+
+static int spi_setup_transport_attrs(struct scsi_target *starget)
+{
+	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 +203,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 +219,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 +249,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 +266,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 +299,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 +334,7 @@
 	if (period > 0xff)
 		period = 0xff;
 
-	i->f->set_period(sdev, period);
+	i->f->set_period(starget, period);
 
 	return count;
 }
@@ -255,9 +343,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 +440,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 +516,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 +526,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 +601,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 +636,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 +662,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 +679,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_PRINTK(sdev, KERN_INFO, "Beginning Domain Validation\n");
+	spi_dv_pending(starget) = 1;
+	down(&spi_dv_sem(starget));
+
+	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(starget));
+	spi_dv_pending(starget) = 0;
 
-	up(&spi_dv_sem(sdev));
-	spi_dv_pending(sdev) = 0;
+	scsi_target_resume(starget);
 
-	scsi_device_resume(sdev);
+	spi_initial_dv(starget) = 1;
 
  out_free:
 	kfree(buffer);
@@ -602,7 +724,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 +747,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 +776,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 +797,15 @@
 	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.device_configure = &spi_configure_device;
+	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);
@@ -690,6 +826,13 @@
 	i->attrs[count++] = &class_device_attr_revalidate;
 
 	i->attrs[count] = NULL;
+
+	count = 0;
+	SETUP_HOST_ATTRIBUTE(signalling);
+
+	BUG_ON(count > SPI_HOST_ATTRS);
+
+	i->host_attrs[count] = NULL;
 
 	return &i->t;
 }
only in patch2:
unchanged:
--- a/drivers/scsi/sim710.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/sim710.c	2004-10-06 22:21: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/zalon.c	2004-10-06 22:21:18 -07:00
+++ b/drivers/scsi/zalon.c	2004-10-06 22:21:18 -07:00
@@ -190,7 +190,12 @@
 
 static int __init zalon7xx_init(void)
 {
-	return register_parisc_driver(&zalon_driver);
+	int ret = ncr53c8xx_init();
+	if (!ret)
+		ret = register_parisc_driver(&zalon_driver);
+	if (ret)
+		ncr53c8xx_exit();
+	return ret;
 }
 
 static void __exit zalon7xx_exit(void)
only in patch2:
unchanged:
--- a/include/scsi/scsi_transport.h	2004-10-06 22:21:18 -07:00
+++ b/include/scsi/scsi_transport.h	2004-10-06 22:21:18 -07:00
@@ -24,18 +24,28 @@
 	/* 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 (*device_configure)(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-10-06 22:21:18 -07:00
+++ b/include/scsi/scsi_transport_fc.h	2004-10-06 22:21:18 -07:00
@@ -24,33 +24,68 @@
 
 struct scsi_transport_template;
 
-struct fc_transport_attrs {
+struct fc_starget_attrs {	/* aka fc_target_attrs */
 	int port_id;
 	uint64_t node_name;
 	uint64_t port_name;
+	uint32_t dev_loss_tmo;	/* Remote Port loss timeout in seconds. */
+	struct timer_list dev_loss_timer;
 };
 
-/* 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_starget_port_id(x) \
+	(((struct fc_starget_attrs *)&(x)->starget_data)->port_id)
+#define fc_starget_node_name(x) \
+	(((struct fc_starget_attrs *)&(x)->starget_data)->node_name)
+#define fc_starget_port_name(x)	\
+	(((struct fc_starget_attrs *)&(x)->starget_data)->port_name)
+#define fc_starget_dev_loss_tmo(x) \
+	(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_tmo)
+#define fc_starget_dev_loss_timer(x) \
+	(((struct fc_starget_attrs *)&(x)->starget_data)->dev_loss_timer)
+
+struct fc_host_attrs {
+	uint32_t link_down_tmo;	/* Link Down timeout in seconds. */
+	struct timer_list link_down_timer;
+};
+
+#define fc_host_link_down_tmo(x) \
+	(((struct fc_host_attrs *)&(x)->shost_data)->link_down_tmo)
+#define fc_host_link_down_timer(x) \
+	(((struct fc_host_attrs *)&(x)->shost_data)->link_down_timer)
+
 
 /* The functions by which the transport class and the driver communicate */
 struct fc_function_template {
-	void 	(*get_port_id)(struct scsi_device *);
-	void	(*get_node_name)(struct scsi_device *);
-	void	(*get_port_name)(struct scsi_device *);
-	/* The driver sets these to tell the transport class it
+	void 	(*get_starget_port_id)(struct scsi_target *);
+	void	(*get_starget_node_name)(struct scsi_target *);
+	void	(*get_starget_port_name)(struct scsi_target *);
+	void    (*get_starget_dev_loss_tmo)(struct scsi_target *);
+	void	(*set_starget_dev_loss_tmo)(struct scsi_target *, uint32_t);
+
+	void    (*get_host_link_down_tmo)(struct Scsi_Host *);
+	void	(*set_host_link_down_tmo)(struct Scsi_Host *, uint32_t);
+
+	/* 
+	 * 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
-	 * class */
-	unsigned long	show_port_id:1;
-	unsigned long	show_node_name:1;
-	unsigned long	show_port_name:1;
+	 * class 
+	 */
+	unsigned long	show_starget_port_id:1;
+	unsigned long	show_starget_node_name:1;
+	unsigned long	show_starget_port_name:1;
+	unsigned long   show_starget_dev_loss_tmo:1;
+
+	unsigned long   show_host_link_down_tmo:1;
+
 	/* Private Attributes */
 };
 
 struct scsi_transport_template *fc_attach_transport(struct fc_function_template *);
 void fc_release_transport(struct scsi_transport_template *);
+int fc_target_block(struct scsi_target *starget);
+void fc_target_unblock(struct scsi_target *starget);
+int fc_host_block(struct Scsi_Host *shost);
+void fc_host_unblock(struct Scsi_Host *shost);
 
 #endif /* SCSI_TRANSPORT_FC_H */
only in patch2:
unchanged:
--- a/include/scsi/scsi_transport_spi.h	2004-10-06 22:21:18 -07:00
+++ b/include/scsi/scsi_transport_spi.h	2004-10-06 22:21:18 -07:00
@@ -35,45 +35,80 @@
 	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 */
+	/* Device Properties fields */
+	unsigned int support_sync:1; /* synchronous support */
+	unsigned int support_wide:1; /* wide support */
+	unsigned int support_dt:1; /* allows DT phases */
+	unsigned int support_dt_only; /* disallows ST phases */
+	unsigned int support_ius; /* support Information Units */
+	unsigned int support_qas; /* supports quick arbitration and selection */
 	/* 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_support_sync(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_sync)
+#define spi_support_wide(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_wide)
+#define spi_support_dt(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_dt)
+#define spi_support_dt_only(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_dt_only)
+#define spi_support_ius(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_ius)
+#define spi_support_qas(x)	(((struct spi_transport_attrs *)&(x)->starget_data)->support_qas)
+
+#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