r3343 - in trunk/kernel/source/kernel-source-2.6.12-2.6.12: . debian/patches

Jurij Smakov jurij-guest@costa.debian.org
Sat, 18 Jun 2005 16:17:45 +0000


Author: jurij-guest
Date: 2005-06-18 16:17:44 +0000 (Sat, 18 Jun 2005)
New Revision: 3343

Added:
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-calibrate-tau.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-fix-power3-ftbfs.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-g3-750cxe.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-pmac-cache-power34-fix.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-ppc64-ibmvscsi.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-serial.patch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/sparc64-hme-lockup.dpatch
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/tty-locking-fixes9.patch
Modified:
   trunk/kernel/source/kernel-source-2.6.12-2.6.12/TODO.patches
Log:
Add more patches, rediffed/tested against 2.6.12
and update TODO.patches accordingly.


Modified: trunk/kernel/source/kernel-source-2.6.12-2.6.12/TODO.patches
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/TODO.patches	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/TODO.patches	2005-06-18 16:17:44 UTC (rev 3343)
@@ -9,6 +9,22 @@
 ia64-generic-nosmp.patch
 	NOT ACCEPTED.
 	One hunk (include/asm-ia64/smp.h) fails to apply.
+powerpc-g4-l2-flush-errata.patch
+	NOT ACCEPTED. Needs to be reviewed. Last hunk fails to apply
+	to include/asm-ppc/cputable.h, as patch introduces a #define
+	conflicting with the existing one.
+powerpc-ppc64-biarch-override.patch
+	NOT ACCEPTED. Needs to be reviewed, as fails to apply completely.
+qla2xxx-removed.patch
+	NOT ACCEPTED. Fails to apply, needs work.
+remove-references-to-removed-drivers.patch
+	NOT ACCEPTED. Fails to apply, needs work
+sparc32-hypersparc-srmmu.patch
+	Presumably not required, but as sparc32 is currently
+	broken, there is no way to tell for sure.
+x86-i486_emu.patch
+       	NOT ACCEPTED. 
+	Makx wrote: not a backport but defintely dropped
 
 These are already processed:
 ----------------------------
@@ -91,18 +107,13 @@
 drivers-media-video-mt352-update.patch
 docbook-move-kernel-doc-comment-next-to-function.patch
 arch-ppc64-hugepage-aio-panic.patch
-	backports
-
-These are not processed yet:
-----------------------------
+	Backports
 powerpc-calibrate-tau.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | REDIFFED | INCLUDED.
 powerpc-fix-power3-ftbfs.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | INCLUDED.
 powerpc-g3-750cxe.patch
-	NOT ACCEPTED.
-powerpc-g4-l2-flush-errata.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | INCLUDED.
 powerpc-mv643xx-enet.patch
 	ACCEPTED.
 powerpc-mv643xx-eth-pegasos.patch
@@ -110,30 +121,21 @@
 powerpc-pmac-agp-sleep.patch
 	ACCEPTED.
 powerpc-pmac-cache-power34-fix.patch
-	NOT ACCEPTED.
-powerpc-ppc64-biarch-override.patch
-	NOT ACCEPTED (may need rediffing).
+	NOT ACCEPTED | INCLUDED.
 powerpc-ppc64-ibmvscsi.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | REDIFFED | INCLUDED.
 powerpc-prep-motorola-irq-fix.patch
 	ACCEPTED.
 powerpc-serial.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | REDIFFED | INCLUDED.
 powerpc-therm-adt746x-new-i2c-fix.patch
 	ACCEPTED.
-qla2xxx-removed.patch
-	NOT ACCEPTED.
-remove-references-to-removed-drivers.patch
-	NOT ACCEPTED (may need rediffing).
 sparc-sunsab-serial-lockup.patch
 	SUPERSEDED by sunsab-uart-update-timeout.patch
-sparc32-hypersparc-srmmu.patch
-	Presumably not required, but as sparc32 is currently
-	broken, there is no way to tell for sure.
 sparc64-compat-nanoseconds.patch
 	ACCEPTED.
 sparc64-hme-lockup.patch
-	NOT ACCEPTED.
+	NOT ACCEPTED | REDIFFED | INCLUDED.
 sparc64-rtc-mostek.patch
 	ACCEPTED.
 sparc64-sb1500-clock-2.6.patch
@@ -145,7 +147,4 @@
 sunsab-uart-update-timeout.patch
 	ACCEPTED.
 tty-locking-fixes9.patch
-	NOT ACCEPTED.
-x86-i486_emu.patch
-       	NOT ACCEPTED. 
-	Makx wrote: not a backport but defintely dropped
+	NOT ACCEPTED | INCLUDED.

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-calibrate-tau.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-calibrate-tau.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-calibrate-tau.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,69 @@
+#! /bin/sh -e 
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Adds support TAU calibration on G3 processors
+## DP: Patch author: Nicolas DET <nd@bplan-gmbh.de>
+## DP: Upstream status: submitted
+
+diff -aurN a/arch/ppc/Kconfig b/arch/ppc/Kconfig
+--- a/arch/ppc/Kconfig	2005-06-06 11:22:29.000000000 -0400
++++ b/arch/ppc/Kconfig	2005-06-17 20:48:38.000000000 -0400
+@@ -198,6 +198,24 @@
+ 
+ 	  If in doubt, say N here.
+ 
++config TAU_CALIBRATED
++        bool "The CPU sensor has been calibrated."
++	depends on TAU
++	help
++	   Enable it you got the real temperature with an external sensor
++	   and you know the offset between the one advertised by the CPU
++	   and the real one
++
++config TAU_CALIBRATED_VALUE
++	int "Offset of the themal sensor"
++	depends on TAU_CALIBRATED
++	default "0"
++	help
++	  This is the offset of the thermal sensor compare to the real value
++	  For example, if you get 27°C in /proc/cpuinfo (uncalibrated) and
++	  you know real one is 53°C, then you should set 26 as offset.
++	  value = Real val - CPU val;
++
+ config MATH_EMULATION
+ 	bool "Math emulation"
+ 	depends on 4xx || 8xx || E500
+diff -aurN a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c
+--- a/arch/ppc/kernel/setup.c	2005-06-06 11:22:29.000000000 -0400
++++ b/arch/ppc/kernel/setup.c	2005-06-17 20:50:14.000000000 -0400
+@@ -201,17 +201,25 @@
+ 
+ #ifdef CONFIG_TAU
+ 	if (cur_cpu_spec[i]->cpu_features & CPU_FTR_TAU) {
++#ifdef CONFIG_TAU_CALIBRATED
++		int is_calibrated	= 1;
++		int temp_offset		= CONFIG_TAU_CALIBRATED_VALUE;
++#else
++		int is_calibrated 	= 0;
++		int temp_offset		= 0;
++#endif
+ #ifdef CONFIG_TAU_AVERAGE
+ 		/* more straightforward, but potentially misleading */
+-		seq_printf(m,  "temperature \t: %u C (uncalibrated)\n",
+-			   cpu_temp(i));
++		seq_printf(m,  "temperature \t: %u C %s- average\n",
++			   cpu_temp(i) + temp_offset,  is_calibrated ? "" : "(uncalibrated) " );
+ #else
+ 		/* show the actual temp sensor range */
+ 		u32 temp;
+ 		temp = cpu_temp_both(i);
+-		seq_printf(m, "temperature \t: %u-%u C (uncalibrated)\n",
+-			   temp & 0xff, temp >> 16);
+-#endif
++		seq_printf(m, "temperature \t: %u-%u C %s\n",
++			   (temp & 0xff) + temp_offset, (temp >> 16) + temp_offset, is_calibrated ? "" : "(uncalibrated)" );
++
++#endif /* CONFIG_TAU_AVERAGE */
+ 	}
+ #endif /* CONFIG_TAU */
+ 

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-fix-power3-ftbfs.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-fix-power3-ftbfs.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-fix-power3-ftbfs.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,27 @@
+#! /bin/sh -e 
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Works around a broken build system, namely the
+## DP: Description: simple bootloader on power 3/4.
+## DP: Misc: Pulled from the ubuntu tree.
+## DP: Patch author: fabbione@ubuntu.com
+## DP: Upstream status: FTBFS fix, guess it will be fixed upstream too
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+diff -urNad linux-source-2.6.10-2.6.10/arch/ppc/boot/simple/misc-prep.c /usr/src/dpatchtemp/dpep.cQRwcC/linux-source-2.6.10-2.6.10/arch/ppc/boot/simple/misc-prep.c
+--- linux-source-2.6.10-2.6.10/arch/ppc/boot/simple/misc-prep.c	2004-12-24 22:33:51.000000000 +0100
++++ /usr/src/dpatchtemp/dpep.cQRwcC/linux-source-2.6.10-2.6.10/arch/ppc/boot/simple/misc-prep.c	2004-12-28 10:43:29.838010536 +0100
+@@ -152,9 +152,11 @@
+ 		hold_residual->VitalProductData.Reserved5 = 0xdeadbeef;
+ 	}
+ 
++#if defined(CONFIG_6xx)
+ 	/* Now go and clear out the BATs and ensure that our MSR is
+ 	 * correct .*/
+ 	disable_6xx_mmu();
++#endif
+ 
+ 	/* Make r3 be a pointer to the residual data. */
+ 	return (unsigned long)hold_residual;

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-g3-750cxe.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-g3-750cxe.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-g3-750cxe.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,68 @@
+#! /bin/sh -e 
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Adds support for 750CXe rev 3.1, prv 0008 3311 (previously recognized as 745/755).
+## DP: Patch author: Nicolas DET <nd@bplan-gmbh.de>
+## DP: Upstream status: submitted
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+--- linux-2.6.11.orig/arch/ppc/kernel/cputable.c	2005-03-02 08:38:09.000000000 +0100
++++ linux-2.6.11_nico/arch/ppc/kernel/cputable.c	2005-03-04 15:39:11.032975088 +0100
+@@ -198,20 +198,6 @@
+ 		.num_pmcs		= 4,
+ 		.cpu_setup		= __setup_cpu_750
+ 	},
+-	{	/* 745/755 */
+-		.pvr_mask		= 0xfffff000,
+-		.pvr_value		= 0x00083000,
+-		.cpu_name		= "745/755",
+-		.cpu_features		= CPU_FTR_COMMON |
+-			CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
+-			CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
+-			CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
+-		.cpu_user_features	= COMMON_PPC,
+-		.icache_bsize		= 32,
+-		.dcache_bsize		= 32,
+-		.num_pmcs		= 4,
+-		.cpu_setup		= __setup_cpu_750
+-	},
+ 	{	/* 750CX (80100 and 8010x?) */
+ 		.pvr_mask		= 0xfffffff0,
+ 		.pvr_value		= 0x00080100,
+@@ -254,6 +240,34 @@
+ 		.num_pmcs		= 4,
+ 		.cpu_setup		= __setup_cpu_750cx
+ 	},
++	{	/* 750CXe (00082311 or 00083311) revision 3.1 / 3.1 pre_GA */
++		.pvr_mask		= 0xffff0fff,
++		.pvr_value		= 0x00080311,
++		.cpu_name		= "750CXe rev 3.1",
++		.cpu_features		= CPU_FTR_COMMON |
++			CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
++			CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
++			CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
++		.cpu_user_features	= COMMON_PPC,
++		.icache_bsize		= 32,
++		.dcache_bsize		= 32,
++		.num_pmcs		= 4,
++		.cpu_setup		= __setup_cpu_750cx
++	},
++	{	/* 745/755 */
++		.pvr_mask		= 0xfffff000,
++		.pvr_value		= 0x00083000,
++		.cpu_name		= "745/755",
++		.cpu_features		= CPU_FTR_COMMON |
++			CPU_FTR_SPLIT_ID_CACHE | CPU_FTR_MAYBE_CAN_DOZE |
++			CPU_FTR_USE_TB | CPU_FTR_L2CR | CPU_FTR_TAU |
++			CPU_FTR_HPTE_TABLE | CPU_FTR_MAYBE_CAN_NAP,
++		.cpu_user_features	= COMMON_PPC,
++		.icache_bsize		= 32,
++		.dcache_bsize		= 32,
++		.num_pmcs		= 4,
++		.cpu_setup		= __setup_cpu_750
++	},
+ 	{	/* 750FX rev 1.x */
+ 		.pvr_mask		= 0xffffff00,
+ 		.pvr_value		= 0x70000100,

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-pmac-cache-power34-fix.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-pmac-cache-power34-fix.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-pmac-cache-power34-fix.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,30 @@
+#! /bin/sh -e
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: [PATCH] ppc32: fixes FTBFS on power3/4.
+## DP: This patch doesn't build pmac_cache.S on power3/power4, since it is
+## DP: broken there and not needed.
+## DP: Patch author: Sven Luther <luther@debian.org>
+## DP: Upstream status: FTBFS, submitted to linuxppc-dev and benh.
+
+. $(dirname $0)/DPATCH
+
+@DPATCH@
+--- kernel-source-2.6.11/arch/ppc/platforms/Makefile.orig	2005-03-27 11:38:25.000000000 +0200
++++ kernel-source-2.6.11/arch/ppc/platforms/Makefile	2005-03-27 11:39:23.000000000 +0200
+@@ -9,9 +9,15 @@
+ ifeq ($(CONFIG_APUS),y)
+ obj-$(CONFIG_PCI)		+= apus_pci.o
+ endif
++ifeq ($(CONFIG_6xx),y)
+ obj-$(CONFIG_PPC_PMAC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
+ 					pmac_feature.o pmac_pci.o pmac_sleep.o \
+ 					pmac_low_i2c.o pmac_cache.o
++else
++obj-$(CONFIG_PPC_PMAC)		+= pmac_pic.o pmac_setup.o pmac_time.o \
++					pmac_feature.o pmac_pci.o pmac_sleep.o \
++					pmac_low_i2c.o
++endif
+ obj-$(CONFIG_PPC_CHRP)		+= chrp_setup.o chrp_time.o chrp_pci.o \
+ 					chrp_pegasos_eth.o
+ obj-$(CONFIG_PPC_PREP)		+= prep_pci.o prep_setup.o

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-ppc64-ibmvscsi.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-ppc64-ibmvscsi.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-ppc64-ibmvscsi.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,2868 @@
+#! /bin/sh -e 
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Enables IBM eServer i/pSeries Virtual SCSI Target Driver 
+## DP: Description: Needed for i/pSeries with logical partitions (LPAR).
+## DP: Patch author: Dave Boutcher (boutcher@us.ibm.com)
+## DP: Upstream status: unknown, sent to me by Cajus Pollmeier.
+
+diff -aurN a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
+--- a/drivers/scsi/Kconfig	2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/scsi/Kconfig	2005-06-18 12:02:58.000000000 -0400
+@@ -813,6 +813,14 @@
+ 	  To compile this driver as a module, choose M here: the
+ 	  module will be called ibmvscsic.
+ 
++config SCSI_IBMVSCSIS
++        tristate "IBM Virtual SCSI Server support"
++        depends on PPC_PSERIES
++        help
++          This is the IBM Virtual SCSI Server
++          To compile this driver as a module, choose M here: the
++          module will be called ibmvscsis.
++
+ config SCSI_INITIO
+ 	tristate "Initio 9100U(W) support"
+ 	depends on PCI && SCSI
+diff -aurN a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
+--- a/drivers/scsi/ibmvscsi/Makefile	2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/scsi/ibmvscsi/Makefile	2005-06-18 12:02:58.000000000 -0400
+@@ -3,3 +3,5 @@
+ ibmvscsic-y			+= ibmvscsi.o
+ ibmvscsic-$(CONFIG_PPC_ISERIES)	+= iseries_vscsi.o 
+ ibmvscsic-$(CONFIG_PPC_PSERIES)	+= rpa_vscsi.o 
++
++obj-$(CONFIG_SCSI_IBMVSCSIS)    += ibmvscsis.o
+diff -aurN a/drivers/scsi/ibmvscsi/ibmvscsis.c b/drivers/scsi/ibmvscsi/ibmvscsis.c
+--- a/drivers/scsi/ibmvscsi/ibmvscsis.c	1969-12-31 19:00:00.000000000 -0500
++++ b/drivers/scsi/ibmvscsi/ibmvscsis.c	2005-06-18 12:02:58.000000000 -0400
+@@ -0,0 +1,2818 @@
++/**************************************************************************/
++/* -*- -linux- -*-                                                        */
++/* IBM eServer i/pSeries Virtual SCSI Target Driver                       */
++/* Copyright (C) 2003 Dave Boutcher (boutcher@us.ibm.com) IBM Corp.       */
++/*                                                                        */
++/*  This program is free software; you can redistribute it and/or modify  */
++/*  it under the terms of the GNU General Public License as published by  */
++/*  the Free Software Foundation; either version 2 of the License, or     */
++/*  (at your option) any later version.                                   */
++/*                                                                        */
++/*  This program is distributed in the hope that it will be useful,       */
++/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
++/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
++/*  GNU General Public License for more details.                          */
++/*                                                                        */
++/*  You should have received a copy of the GNU General Public License     */
++/*  along with this program; if not, write to the Free Software           */
++/*  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  */
++/*                                                                   USA  */
++/*                                                                        */
++/* This module contains the eServer virtual SCSI target code.  The driver */
++/* takes SRP requests from the virtual SCSI client (the linux version is  */
++/* int ibmvscsi.c, but there can be other clients, like AIX or OF) and    */
++/* passes them on to real devices in this system.                         */
++/*                                                                        */
++/* The basic hierarchy (and somewhat the organization of this file) is    */
++/* that SCSI CDBs are in SRPs are in CRQs.                                */
++/*                                                                        */
++/**************************************************************************/
++/*
++  TODO:
++  - Support redirecting SRP SCSI requests to a real SCSI driver
++*/
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/interrupt.h>
++#include <linux/list.h>
++#include <linux/pagemap.h>
++#include <linux/dma-mapping.h>
++#include <linux/sched.h>
++#include <linux/blkdev.h>
++#include <linux/fs.h>
++#include <linux/bio.h>
++
++#include <asm/hvcall.h>
++#include <asm/vio.h>
++#include <asm/iommu.h>
++
++#include "../scsi.h"
++#include "viosrp.h"
++
++#define IBMVSCSIS_VERSION "1.2"
++
++MODULE_DESCRIPTION("IBM Virtual SCSI Target");
++MODULE_AUTHOR("Dave Boutcher");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(IBMVSCSIS_VERSION);
++
++static int ibmvscsis_debug = 0;
++
++/* These are fixed and come from the device tree...we
++ * just store them here to save getting them every time.
++ */
++static char system_id[64] = "";
++static char partition_name[97] = "UNKNOWN";
++static unsigned int partition_number = -1;
++
++/*
++ * Quick macro to enable/disable interrupts
++ * TODO: move to vio.h to be common with ibmvscsi.c
++ */
++#define h_vio_signal(ua, mode) \
++  plpar_hcall_norets(H_VIO_SIGNAL, ua, mode)
++
++/* 
++ * These are indexes into the following table, and have to match!!!
++ */
++#define SENSE_SUCCESS       0
++#define SENSE_ABORT         1
++#define SENSE_INVALID_ID    2
++#define SENSE_DEVICE_FAULT  3
++#define SENSE_DEVICE_BUSY   4
++#define SENSE_UNIT_OFFLINE  5
++#define SENSE_INVALID_CMD   6
++#define SENSE_INTERMEDIATE  7
++#define SENSE_WRITE_PROT    8
++#define SENSE_INVALID_FIELD 9
++
++#define TARGET_MAX_NAME_LEN 128
++
++static unsigned char ibmvscsis_sense_data[][3] = {
++/*
++ * Sense key lookup table
++ * Format: SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
++ * Adapted from 3w-xxxx.h
++ */
++	{0x00, 0x00, 0x00},	/* Success           */
++	{0x0b, 0x00, 0x00},	/* Aborted command   */
++	{0x0b, 0x14, 0x00},	/* ID not found      */
++	{0x04, 0x00, 0x00},	/* Device fault      */
++	{0x0b, 0x00, 0x00},	/* Device busy       */
++	{0x02, 0x04, 0x00},	/* Unit offline      */
++	{0x05, 0x20, 0x00},	/* Invalid Command   */
++	{0x10, 0x00, 0x00},	/* Intermediate      */
++	{0x07, 0x27, 0x00},	/* Write Protected   */
++	{0x05, 0x24, 0x00},	/* Invalid field     */
++};
++
++/*
++ * SCSI defined structure for inquiry data
++ * TODO: Seral number is currently messed up if you do
++ *       scsiinfo.  I'm not sure why and I think it comes out of 
++ *       here
++ */
++struct inquiry_data {
++	u8 qual_type;
++	u8 rmb_reserve;
++	u8 version;
++	u8 aerc_naca_hisup_format;
++	u8 addl_len;
++	u8 sccs_reserved;
++	u8 bque_encserv_vs_multip_mchngr_reserved;
++	u8 reladr_reserved_linked_cmdqueue_vs;
++	char vendor[8];
++	char product[16];
++	char revision[4];
++	char vendor_specific[20];
++	char reserved1[2];
++	char version_descriptor[16];
++	char reserved2[22];
++	char unique[158];
++};
++
++extern int vio_num_address_cells;
++
++/* 
++ * an RPA command/response transport queue.  This is our structure
++ * that points to the actual queue.  feel free to modify this structure
++ * as needed
++ */
++struct crq_queue {
++	struct viosrp_crq *msgs;
++	int size, cur;
++	dma_addr_t msg_token;
++	spinlock_t lock;
++};
++
++/*
++ * This structure tracks our fundamental unit of work.  Whenever
++ * an SRP Information Unit (IU) arrives, we track all the good stuff
++ * here
++ */
++struct iu_entry {
++	union viosrp_iu *iu;
++	struct server_adapter *adapter;
++	struct list_head next;
++	dma_addr_t iu_token;
++	int aborted;
++	struct {
++		dma_addr_t remote_token;
++		char *data_buffer;
++		dma_addr_t data_token;
++		long data_len;
++		struct vdev *vd;
++		char in_use:1;
++		char diunder:1;
++		char diover:1;
++		char dounder:1;
++		char doover:1;
++		char write:1;
++		char linked:1;
++		int data_out_residual_count;
++		int data_in_residual_count;
++		int ioerr;
++	} req;
++};
++
++/* 
++ * a pool of ius for use 
++ */
++struct iu_pool {
++	spinlock_t lock;
++	struct list_head iu_entries;
++	struct iu_entry *list;
++	union viosrp_iu *iu_storage;
++	dma_addr_t iu_token;
++	u32 size;
++};
++
++/*
++ * Represents a single device that someone told us about
++ * that we treat as a LUN
++ */
++struct vdev {
++	struct list_head list;
++	char type;		/* 'B' for block, 'S' for SCSI */
++	atomic_t refcount;
++	int disabled;
++	u64 lun;
++	struct kobject kobj;
++	struct {
++		char device_name[TARGET_MAX_NAME_LEN];
++		struct block_device *bdev;
++		long blksize;
++		long lastlba;
++		int ro;
++	} b;
++};
++
++/*
++ * Represents a bus.  target #'s in SCSI are 6 bits long,
++ * so you can have 64 targets per bus
++ */
++#define TARGETS_PER_BUS (64)
++#define BUS_PER_ADAPTER (8)
++struct vbus {
++	struct vdev *vdev[TARGETS_PER_BUS];
++	atomic_t num_targets;
++	struct kobject kobj;
++	int bus_num;
++};
++
++/*
++ * Buffer cache
++ */
++struct dma_buffer {
++	dma_addr_t token;
++	char *addr;
++	size_t len;
++};
++#define DMA_BUFFER_CACHE_SIZE (16)
++#define DMA_BUFFER_INIT_COUNT (4)
++#define DMA_BUFFER_INIT_LEN (PAGE_SIZE*16)
++
++/* all driver data associated with a host adapter */
++struct server_adapter {
++	struct device *dev;
++	struct vio_dev *dma_dev;
++	struct crq_queue queue;
++	struct work_struct crq_task;
++	struct tasklet_struct endio_tasklet;
++	struct iu_pool pool;
++	spinlock_t lock;
++	struct bio *bio_done;
++	struct bio *bio_donetail;
++	struct list_head inflight;
++	struct vbus *vbus[8];
++	int nvdevs;
++	char name[32];
++	unsigned long liobn;
++	unsigned long riobn;
++
++	atomic_t num_buses;
++	struct kobject stats_kobj;
++
++	/* This ugly expression allocates a bit array of 
++	 * in-use flags large enough for the number of buffers
++	 */
++	unsigned long dma_buffer_use[(DMA_BUFFER_CACHE_SIZE +
++				      sizeof(unsigned long) - 1)
++				     / sizeof(unsigned long)];
++	struct dma_buffer dma_buffer[DMA_BUFFER_CACHE_SIZE];
++
++	/* Statistics only */
++	atomic_t iu_count;	/* number allocated */
++	atomic_t bio_count;	/* number allocated */
++	atomic_t crq_processed;
++	atomic_t interrupts;
++	atomic_t read_processed;
++	atomic_t write_processed;
++	atomic_t buffers_allocated;
++	atomic_t errors;
++};
++
++/* 
++ * Forward declarations
++ */
++static long send_rsp(struct iu_entry *iue, int status);
++
++/*
++ * The following are lifted from usb.h
++ */
++#define DEBUG 1
++#ifdef DEBUG
++#define dbg(format, arg...) if (ibmvscsis_debug) printk(KERN_WARNING __FILE__ ": " format , ## arg)
++#else
++#define dbg(format, arg...) do {} while (0)
++#endif
++#define err(format, arg...) printk(KERN_ERR "ibmvscsis: " format , ## arg)
++#define info(format, arg...) printk(KERN_INFO "ibmvscsis: " format  , ## arg)
++#define warn(format, arg...) printk(KERN_WARNING "ibmvscsis: " format , ## arg)
++
++/* ==============================================================
++ * Utility Routines
++ * ==============================================================
++ */
++/*
++ * return an 8 byte lun given a bus, target, lun.  
++ * Today this only supports single level luns.  Should we add a level or a
++ * 64 bit LUN as input to support multi-level luns?
++ */
++u64 make_lun(unsigned int bus, unsigned int target, unsigned int lun)
++{
++	u16 result = (0x8000 |
++		      ((target & 0x003f) << 8) |
++		      ((bus & 0x0007) << 5) | (lun & 0x001f));
++	return ((u64) result) << 48;
++}
++
++/*
++ * Given an 8 byte LUN, return the first level bus/target/lun.
++ * Today this doesn't support multi-level LUNs
++ */
++#define GETBUS(x) ((int)((((u64)(x)) >> 53) & 0x0007))
++#define GETTARGET(x) ((int)((((u64)(x)) >> 56) & 0x003f))
++#define GETLUN(x) ((int)((((u64)(x)) >> 48) & 0x001f))
++
++static u8 getcontrolbyte(u8 * cdb)
++{
++	return cdb[COMMAND_SIZE(cdb[0]) - 1];
++}
++
++static u8 getlink(struct iu_entry *iue)
++{
++	return (getcontrolbyte(iue->iu->srp.cmd.cdb) & 0x01);
++}
++
++/*
++ * Given an SRP, figure out the data in length
++ */
++static int did_len(struct srp_cmd *cmd)
++{
++	struct memory_descriptor *md;
++	struct indirect_descriptor *id;
++	int offset = cmd->additional_cdb_len * 4;
++
++	switch (cmd->data_out_format) {
++	case SRP_NO_BUFFER:
++		offset += 0;
++		break;
++	case SRP_DIRECT_BUFFER:
++		offset += sizeof(struct memory_descriptor);
++		break;
++	case SRP_INDIRECT_BUFFER:
++		offset += sizeof(struct indirect_descriptor)
++		    +
++		    ((cmd->data_out_count -
++		      1) * sizeof(struct memory_descriptor));
++		break;
++	default:
++		err("client error. Invalid data_out_format %d\n",
++		    cmd->data_out_format);
++		return 0;
++	}
++
++	switch (cmd->data_in_format) {
++	case SRP_NO_BUFFER:
++		return 0;
++	case SRP_DIRECT_BUFFER:
++		md = (struct memory_descriptor *)(cmd->additional_data +
++						  offset);
++		return md->length;
++	case SRP_INDIRECT_BUFFER:
++		id = (struct indirect_descriptor *)(cmd->additional_data +
++						    offset);
++		return id->total_length;
++	default:
++		err("client error.  Invalid data_in_format %d\n",
++		    cmd->data_in_format);
++		return 0;
++	}
++}
++
++/* 
++ * We keep a pool of IUs, this routine builds the pool.  The pool is 
++ * per-adapter.  The size of the pool is negotiated as part of the SRP
++ * login, where we negotiate the number of requests (IUs) the client
++ * can send us.  This routine is not synchronized.
++ */
++static int initialize_iu_pool(struct server_adapter *adapter, int size)
++{
++	struct iu_pool *pool = &adapter->pool;
++	int i;
++
++	pool->size = size;
++	pool->lock = SPIN_LOCK_UNLOCKED;
++	INIT_LIST_HEAD(&pool->iu_entries);
++
++	pool->list = kmalloc(pool->size * sizeof(*pool->list), GFP_KERNEL);
++	if (!pool->list) {
++		err("Error: Cannot allocate memory for IU list\n");
++		return -ENOMEM;
++	}
++	memset(pool->list, 0x00, pool->size * sizeof(*pool->list));
++
++	pool->iu_storage =
++	    dma_alloc_coherent(adapter->dev,
++			       pool->size * sizeof(*pool->iu_storage),
++			       &pool->iu_token, 0);
++	if (!pool->iu_storage) {
++		err("Error: Cannot allocate memory for IU pool\n");
++		kfree(pool->list);
++		return -ENOMEM;
++	}
++
++	for (i = 0; i < pool->size; ++i) {
++		pool->list[i].iu = pool->iu_storage + i;
++		pool->list[i].iu_token =
++		    pool->iu_token + sizeof(*pool->iu_storage) * i;
++		pool->list[i].adapter = adapter;
++		list_add_tail(&pool->list[i].next, &pool->iu_entries);
++	}
++
++	return 0;
++}
++
++/*
++ * Free the pool we allocated in initialize_iu_pool
++ */
++static void release_iu_pool(struct server_adapter *adapter)
++{
++	struct iu_pool *pool = &adapter->pool;
++	int i, in_use = 0;
++	for (i = 0; i < pool->size; ++i)
++		if (pool->list[i].req.in_use)
++			++in_use;
++	if (in_use)
++		err("Releasing event pool with %d events still in use?\n", 
++		    in_use);
++	kfree(pool->list);
++	dma_free_coherent(adapter->dev, pool->size * sizeof(*pool->iu_storage),
++			  pool->iu_storage, pool->iu_token);
++}
++
++/*
++ * Get an IU from the pool.  Return NULL of the pool is empty.  This
++ * routine is syncronized by a lock.  The routine sets all the important
++ * fields to 0
++ */
++static struct iu_entry *get_iu(struct server_adapter *adapter)
++{
++	struct iu_entry *e;
++	unsigned long flags;
++
++	spin_lock_irqsave(&adapter->pool.lock, flags);
++	if (!list_empty(&adapter->pool.iu_entries)) {
++		e = list_entry(adapter->pool.iu_entries.next, struct iu_entry,
++			       next);
++		list_del(adapter->pool.iu_entries.next);
++
++		if (e->req.in_use) {
++			err("Found in-use iue in free pool!");
++		}
++
++		memset(&e->req, 0x00, sizeof(e->req));
++
++		e->req.in_use = 1;
++	} else {
++		e = NULL;
++	}
++
++	spin_unlock_irqrestore(&adapter->pool.lock, flags);
++	atomic_inc(&adapter->iu_count);
++	return e;
++}
++
++/* 
++ * Return an IU to the pool.  This routine is synchronized
++ */
++static void free_iu(struct iu_entry *iue)
++{
++	unsigned long flags;
++	if (iue->req.vd) {
++		atomic_dec(&iue->req.vd->refcount);
++	}
++
++	spin_lock_irqsave(&iue->adapter->pool.lock, flags);
++	if (iue->req.in_use == 0) {
++		warn("Internal error, freeing iue twice!\n");
++	} else {
++		iue->req.in_use = 0;
++		list_add_tail(&iue->next, &iue->adapter->pool.iu_entries);
++	}
++	spin_unlock_irqrestore(&iue->adapter->pool.lock, flags);
++	atomic_dec(&iue->adapter->iu_count);
++}
++
++/*
++ * Get a CRQ from the inter-partition queue.
++ */
++static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
++{
++	struct viosrp_crq *crq;
++	unsigned long flags;
++
++	spin_lock_irqsave(&queue->lock, flags);
++	crq = &queue->msgs[queue->cur];
++	if (crq->valid & 0x80) {
++		if (++queue->cur == queue->size)
++			queue->cur = 0;
++	} else
++		crq = NULL;
++	spin_unlock_irqrestore(&queue->lock, flags);
++
++	return crq;
++}
++
++/* 
++ * Make the RDMA hypervisor call.  There should be a better way to do this
++ * than inline assembler.
++ * TODO: Fix the inline assembler
++ */
++static long h_copy_rdma(long length,
++			unsigned long sliobn, unsigned long slioba,
++			unsigned long dliobn, unsigned long dlioba)
++{
++	long lpar_rc = 0;
++	__asm__ __volatile__(" li 3,0x110 \n\t"
++			     " mr 4, %1 \n\t"
++			     " mr 5, %2 \n\t"
++			     " mr 6, %3 \n\t"
++			     " mr 7, %4 \n\t"
++			     " mr 8, %5 \n\t"
++			     " .long 0x44000022 \n\t"
++			     " mr %0, 3 \n\t":"=&r"(lpar_rc)
++			     :"r"(length), "r"(sliobn), "r"(slioba),
++			     "r"(dliobn), "r"(dlioba)
++			     :"r0", "r3", "r4", "r5", "r6", "r7", "r8", "cr0",
++			     "cr1", "ctr", "xer", "memory");
++	return lpar_rc;
++}
++
++/*
++ * Send an SRP to another partition using the CRQ.
++ */
++static int send_srp(struct iu_entry *iue, u64 length)
++{
++	long rc, rc1;
++	union {
++		struct viosrp_crq cooked;
++		u64 raw[2];
++	} crq;
++
++	/* First copy the SRP */
++	rc = h_copy_rdma(length,
++			 iue->adapter->liobn,
++			 iue->iu_token,
++			 iue->adapter->riobn, iue->req.remote_token);
++
++	if (rc) {
++		err("Error %ld transferring data to client\n", rc);
++	}
++
++	crq.cooked.valid = 0x80;
++	crq.cooked.format = VIOSRP_SRP_FORMAT;
++	crq.cooked.reserved = 0x00;
++	crq.cooked.timeout = 0x00;
++	crq.cooked.IU_length = length;
++	crq.cooked.IU_data_ptr = iue->iu->srp.generic.tag;
++
++	if (rc == 0) {
++		crq.cooked.status = 0x99;	/* TODO: is this right? */
++	} else {
++		crq.cooked.status = 0x00;
++	}
++
++	rc1 =
++	    plpar_hcall_norets(H_SEND_CRQ, iue->adapter->dma_dev->unit_address,
++			       crq.raw[0], crq.raw[1]);
++
++	if (rc1) {
++		err("Error %ld sending response to client\n", rc1);
++		return rc1;
++	}
++
++	return rc;
++}
++
++/*
++ * Send data to a single SRP memory descriptor
++ * Returns amount of data sent, or negative value on error
++ */
++static long send_md_data(dma_addr_t stoken, int len,
++			 struct memory_descriptor *md,
++			 struct server_adapter *adapter)
++{
++	int tosend;
++	long rc;
++
++	if (len < md->length)
++		tosend = len;
++	else
++		tosend = md->length;
++
++	rc = h_copy_rdma(tosend,
++			 adapter->liobn,
++			 stoken, adapter->riobn, md->virtual_address);
++
++	if (rc != H_Success) {
++		err(" Error %ld transferring data to client\n", rc);
++		return -1;
++	}
++
++	return tosend;
++}
++
++/*
++ * Send data to the SRP data_in buffers
++ * Returns amount of data sent, or negative value on error
++ */
++static long send_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue)
++{
++	struct srp_cmd *cmd = &iue->iu->srp.cmd;
++	struct memory_descriptor *md;
++	struct indirect_descriptor *id;
++	int offset = 0;
++	int total_length = 0;
++	int i;
++	int thislen;
++	int bytes;
++	int sentlen = 0;
++
++	offset = cmd->additional_cdb_len * 4;
++
++	switch (cmd->data_out_format) {
++	case SRP_NO_BUFFER:
++		offset += 0;
++		break;
++	case SRP_DIRECT_BUFFER:
++		offset += sizeof(struct memory_descriptor);
++		break;
++	case SRP_INDIRECT_BUFFER:
++		offset += sizeof(struct indirect_descriptor)
++		    +
++		    ((cmd->data_out_count -
++		      1) * sizeof(struct memory_descriptor));
++		break;
++	default:
++		err("client error: Invalid data_out_format %d\n",
++		    cmd->data_out_format);
++		return 0;
++	}
++
++	switch (cmd->data_in_format) {
++	case SRP_NO_BUFFER:
++		return 0;
++	case SRP_DIRECT_BUFFER:
++		md = (struct memory_descriptor *)(cmd->additional_data +
++						  offset);
++		sentlen = send_md_data(stoken, len, md, iue->adapter);
++		len -= sentlen;
++		if (len) {
++			iue->req.diover = 1;
++			iue->req.data_in_residual_count = len;
++		}
++		return sentlen;
++	}
++
++	if (cmd->data_in_format != SRP_INDIRECT_BUFFER) {
++		err("client error Invalid data_in_format %d\n",
++		    cmd->data_in_format);
++		return 0;
++	}
++
++	id = (struct indirect_descriptor *)(cmd->additional_data + offset);
++
++	total_length = id->total_length;
++
++	/* Work through the partial memory descriptor list */
++	for (i = 0; ((i < cmd->data_in_count) && (len)); i++) {
++		if (len > id->list[i].length) {
++			thislen = id->list[i].length;
++		} else {
++			thislen = len;
++		}
++
++		bytes =
++		    send_md_data(stoken + sentlen, thislen, id->list + i,
++				 iue->adapter);
++		if (bytes < 0)
++			return bytes;
++
++		if (bytes != thislen) {
++			warn("Error: Tried to send %d, sent %d\n", thislen,
++			     bytes);
++		}
++
++		sentlen += bytes;
++		total_length -= bytes;
++		len -= bytes;
++	}
++
++	if (len) {
++		iue->req.diover = 1;
++		iue->req.data_in_residual_count = len;
++	}
++
++	return sentlen;
++}
++
++/*
++ * Get data from the other partition from a single SRP memory descriptor
++ * Returns amount of data sent, or negative value on error
++ */
++static long get_md_data(dma_addr_t ttoken, int len,
++			struct memory_descriptor *md,
++			struct server_adapter *adapter)
++{
++	int toget;
++	long rc;
++
++	if (len < md->length)
++		toget = len;
++	else
++		toget = md->length;
++
++	rc = h_copy_rdma(toget,
++			 adapter->riobn,
++			 md->virtual_address, adapter->liobn, ttoken);
++
++	if (rc != H_Success) {
++		err("Error %ld transferring data to client\n", rc);
++		return -1;
++	}
++
++	return toget;
++}
++
++/*
++ * Get data from an SRP data in area.
++ * Returns amount of data sent, or negative value on error
++ */
++static long get_cmd_data(dma_addr_t stoken, int len, struct iu_entry *iue)
++{
++	struct srp_cmd *cmd = &iue->iu->srp.cmd;
++	struct memory_descriptor *md;
++	struct indirect_descriptor *id;
++	int offset = 0;
++	int total_length = 0;
++	int i;
++	int thislen;
++	int bytes;
++	int sentlen = 0;
++
++	offset = cmd->additional_cdb_len * 4;
++
++	switch (cmd->data_out_format) {
++	case SRP_NO_BUFFER:
++		return 0;
++		break;
++	case SRP_DIRECT_BUFFER:
++		md = (struct memory_descriptor *)(cmd->additional_data +
++						  offset);
++		return get_md_data(stoken, len, md, iue->adapter);
++		break;
++	}
++
++	if (cmd->data_out_format != SRP_INDIRECT_BUFFER) {
++		err("client error: Invalid data_out_format %d\n",
++		    cmd->data_out_format);
++		return 0;
++	}
++
++	id = (struct indirect_descriptor *)(cmd->additional_data + offset);
++
++	total_length = id->total_length;
++
++	/* Work through the partial memory descriptor list */
++	for (i = 0; ((i < cmd->data_out_count) && (len)); i++) {
++		if (len > id->list[i].length) {
++			thislen = id->list[i].length;
++		} else {
++			thislen = len;
++		}
++
++		bytes =
++		    get_md_data(stoken + sentlen, thislen, id->list + i,
++				iue->adapter);
++		if (bytes < 0)
++			return bytes;
++
++		if (bytes != thislen) {
++			err("Partial data sent to client (%d/%d)\n", bytes, thislen);
++		}
++
++		sentlen += bytes;
++		total_length -= bytes;
++		len -= bytes;
++	}
++
++	return sentlen;
++}
++
++/*
++ * Get some data buffers to start.  This doesn't lock the adapter structure!
++ */
++static void init_data_buffer(struct server_adapter *adapter)
++{
++	int i;
++
++	for (i = 0; i < DMA_BUFFER_INIT_COUNT; i++) {
++		if (adapter->dma_buffer[i].addr == NULL) {
++			adapter->dma_buffer[i].addr = (char *)
++			    dma_alloc_coherent(adapter->dev,
++					       DMA_BUFFER_INIT_LEN,
++					       &adapter->dma_buffer[i].token,
++					       0);
++			adapter->dma_buffer[i].len = DMA_BUFFER_INIT_LEN;
++			dbg("data buf %p token %8.8x, len %ld\n",
++			    adapter->dma_buffer[i].addr,
++			    adapter->dma_buffer[i].token,
++			    adapter->dma_buffer[i].len);
++			atomic_inc(&adapter->buffers_allocated);
++		}
++	}
++
++	return;
++}
++
++/*
++ * Get a memory buffer that includes a mapped TCE.  
++ */
++static void get_data_buffer(char **buffer, dma_addr_t * data_token, size_t len,
++			    struct server_adapter *adapter)
++{
++	int i;
++
++	for (i = 0; i < DMA_BUFFER_CACHE_SIZE; i++) {
++		if ((adapter->dma_buffer[i].addr) &&
++		    (adapter->dma_buffer[i].len >= len) &&
++		    (!test_and_set_bit(i, adapter->dma_buffer_use))) {
++			*buffer = adapter->dma_buffer[i].addr;
++			*data_token = adapter->dma_buffer[i].token;
++			return;
++		}
++	}
++
++	/* Couldn't get a buffer!  Try and get a new one */
++	*buffer = (char *)dma_alloc_coherent(adapter->dev, len, data_token, 0);
++	atomic_inc(&adapter->buffers_allocated);
++	dbg("get:  %p, %8.8x, %ld\n", *buffer, *data_token, len);
++	return;
++}
++
++/*
++ * Free a memory buffer that includes a mapped TCE.  
++ */
++static void free_data_buffer(char *buffer, dma_addr_t data_token, size_t len,
++			     struct server_adapter *adapter)
++{
++	int i;
++
++	/* First see if this buffer is already in the cache */
++	for (i = 0; i < DMA_BUFFER_CACHE_SIZE; i++) {
++		if (adapter->dma_buffer[i].addr == buffer) {
++			if (adapter->dma_buffer[i].token != data_token) {
++				err("Inconsistent data buffer pool info!\n");
++			}
++			if (!test_and_clear_bit(i, adapter->dma_buffer_use)) {
++				err("Freeing data buffer twice!\n");
++			}
++			return;
++		}
++	}
++
++	/* See if there is an empty slot in our list */
++	for (i = 0; i < DMA_BUFFER_CACHE_SIZE; i++) {
++		if (!test_and_set_bit(i, adapter->dma_buffer_use)) {
++			if (adapter->dma_buffer[i].addr == NULL) {
++				adapter->dma_buffer[i].addr = buffer;
++				adapter->dma_buffer[i].token = data_token;
++				adapter->dma_buffer[i].len = len;
++				clear_bit(i, adapter->dma_buffer_use);
++				return;
++			} else {
++				clear_bit(i, adapter->dma_buffer_use);
++			}
++		}
++	}
++
++	/* Now see if there is a smaller buffer we should throw out */
++	for (i = 0; i < DMA_BUFFER_CACHE_SIZE; i++) {
++		if (!test_and_set_bit(i, adapter->dma_buffer_use)) {
++			if (adapter->dma_buffer[i].len < len) {
++				dbg("fre1: %p, %8.8x, %ld\n",
++				    adapter->dma_buffer[i].addr,
++				    adapter->dma_buffer[i].token,
++				    adapter->dma_buffer[i].len);
++
++				dma_free_coherent(adapter->dev,
++						  adapter->dma_buffer[i].len,
++						  adapter->dma_buffer[i].addr,
++						  adapter->dma_buffer[i].token);
++
++				atomic_dec(&adapter->buffers_allocated);
++
++				adapter->dma_buffer[i].addr = buffer;
++				adapter->dma_buffer[i].token = data_token;
++				adapter->dma_buffer[i].len = len;
++				clear_bit(i, adapter->dma_buffer_use);
++				return;
++			} else {
++				clear_bit(i, adapter->dma_buffer_use);
++			}
++		}
++	}
++
++	/* No space to cache this.  Give it back to the kernel */
++	dbg("fre2: %p, %8.8x, %ld\n", buffer, data_token, len);
++	dma_free_coherent(adapter->dev, len, buffer, data_token);
++	atomic_dec(&adapter->buffers_allocated);
++}
++
++/*
++ * Release all the data buffers
++ */
++static void release_data_buffer(struct server_adapter *adapter)
++{
++	int i;
++	int free_in_use = 0;
++
++	for (i = 0; i < DMA_BUFFER_INIT_COUNT; i++) {
++		if (adapter->dma_buffer[i].addr != NULL) {
++			if (test_bit(i, adapter->dma_buffer_use)) {
++				free_in_use++;
++			}
++			dma_free_coherent(adapter->dev,
++					  adapter->dma_buffer[i].len,
++					  adapter->dma_buffer[i].addr,
++					  adapter->dma_buffer[i].token);
++
++			atomic_dec(&adapter->buffers_allocated);
++		}
++	}
++
++	if (free_in_use) {
++		err("Freeing %d in-use data buffers\n", free_in_use);
++	}
++	return;
++}
++
++/*
++ * the routine that gets called on end_io of our bios.  We basically
++ * schedule the processing to be done in our task, since we don't want
++ * do things like RDMA in someone else's interrupt handler
++ *
++ * Each iu request may result in multiple bio requests.  only proceed
++ * when all the bio requests have done.
++ */
++static int ibmvscsis_end_io(struct bio *bio, unsigned int nbytes, int error)
++{
++	struct iu_entry *iue = (struct iu_entry *)bio->bi_private;
++	struct server_adapter *adapter = iue->adapter;
++	unsigned long flags;
++
++	if (bio->bi_size)
++		return 1;
++
++	if (!test_bit(BIO_UPTODATE, &bio->bi_flags)) {
++		iue->req.ioerr = 1;
++	};
++
++	/* Add the bio to the done queue */
++	spin_lock_irqsave(&adapter->lock, flags);
++	if (adapter->bio_donetail) {
++		adapter->bio_donetail->bi_next = bio;
++		adapter->bio_donetail = bio;
++	} else
++		adapter->bio_done = adapter->bio_donetail = bio;
++	bio->bi_next = NULL;
++	spin_unlock_irqrestore(&adapter->lock, flags);
++
++	/* Schedule the task */
++	tasklet_schedule(&adapter->endio_tasklet);
++
++	return 0;
++}
++
++/*
++ * Find the vdev structure from the LUN field in an SRP IUE
++ * Note that this routine bumps a refcount field in the vdev.
++ * Normally this is done when free_iu is called.
++ */
++static struct vdev *find_device(struct iu_entry *iue)
++{
++	u16 *lun = (u16 *) & iue->iu->srp.cmd.lun;
++	u32 bus = (lun[0] & 0x00E0) >> 5;
++	u32 target = (lun[0] & 0x3F00) >> 8;
++	u32 slun = (lun[0] & 0x001F);
++	struct vdev *vd;
++	unsigned long flags;
++
++	/* If asking for a lun other than 0, return nope */
++	if (slun) {
++		return NULL;
++	}
++
++	/* Only from SRP CMD */
++	if (iue->iu->srp.generic.type != SRP_CMD_TYPE)
++		return NULL;
++
++	/* if not a recognized LUN format, return NULL */
++	if ((lun[0] & 0xC000) != 0x8000)
++		return NULL;
++
++	spin_lock_irqsave(&iue->adapter->lock, flags);
++	if (iue->adapter->vbus[bus] == NULL) {
++		spin_unlock_irqrestore(&iue->adapter->lock, flags);
++		return NULL;
++	}
++
++	vd = iue->adapter->vbus[bus]->vdev[target];
++
++	if ((vd == NULL) || (vd->disabled)) {
++		spin_unlock_irqrestore(&iue->adapter->lock, flags);
++		return NULL;
++	}
++
++	if (vd) {
++		atomic_inc(&vd->refcount);
++	}
++	spin_unlock_irqrestore(&iue->adapter->lock, flags);
++
++	return vd;
++}
++
++/*
++ * Process BH buffer completions.  When the end_io routine gets called 
++ * we queue the bio on an internal queue and start a task to process them
++ */
++static void endio_task(unsigned long data)
++{
++	struct server_adapter *adapter = (struct server_adapter *)data;
++	struct iu_entry *iue= NULL;
++	struct bio *bio;
++	int bytes;
++	unsigned long flags;
++
++	do {
++		spin_lock_irqsave(&adapter->lock, flags);
++		if ((bio = adapter->bio_done)) {
++			if (bio == adapter->bio_donetail)
++				adapter->bio_donetail = NULL;
++			adapter->bio_done = bio->bi_next;
++			bio->bi_next = NULL;
++		}
++		if (bio) {
++			/* Remove this iue from the in-flight list */
++			iue = (struct iu_entry *)bio->bi_private;
++			if (!iue->req.in_use) {
++				err("Internal error! freed iue in bio!!!\n");
++				spin_unlock_irqrestore(&adapter->lock, flags);
++				return;
++			}
++				
++			list_del(&iue->next);
++		}
++
++		spin_unlock_irqrestore(&adapter->lock, flags);
++
++		if (bio) {
++			/* Send back the SRP and data if this request was NOT
++			 * aborted 
++			 */
++			if (!iue->aborted) {
++
++				if (!iue->req.ioerr) {
++					/* return data if this was a read */
++					if (!iue->req.write) {
++						bytes =
++						    send_cmd_data(iue->req.
++								  data_token,
++								  iue->req.
++								  data_len,
++								  iue);
++						if (bytes != iue->req.data_len) {
++							err("Error sending data "
++							    "on response "
++							    "(tried %d, sent %d\n", 
++							    bio->bi_size, bytes);
++							send_rsp(iue,
++								 SENSE_ABORT);
++						} else {
++							send_rsp(iue,
++								 SENSE_SUCCESS);
++						}
++					} else {
++						send_rsp(iue, SENSE_SUCCESS);
++					}
++				} else {
++					err("Block operation failed\n");
++					print_command(iue->iu->srp.cmd.cdb);
++					send_rsp(iue, SENSE_DEVICE_FAULT);
++				}
++			}
++
++			spin_lock_irqsave(&adapter->lock, flags);
++			free_data_buffer(iue->req.data_buffer,
++					 iue->req.data_token, iue->req.data_len,
++					 adapter);
++			spin_unlock_irqrestore(&adapter->lock, flags);
++
++			free_iu(iue);
++
++			bio_put(bio);
++			atomic_dec(&adapter->bio_count);
++		}
++	} while (bio);
++}
++
++/* ==============================================================
++ * SCSI Command Emulation Routines
++ * ==============================================================
++ */
++
++/*
++ * Process an inquiry SCSI Command
++ */
++static void process_inquiry(struct iu_entry *iue)
++{
++	struct inquiry_data *id;
++	dma_addr_t data_token;
++	u8 *raw_id;
++	int bytes;
++
++	id = (struct inquiry_data *)dma_alloc_coherent(iue->adapter->dev,
++						       sizeof(*id),
++						       &data_token, 0);
++	raw_id = (u8 *)id;
++	memset(id, 0x00, sizeof(*id));
++
++	/* If we have a valid device */
++	if (iue->req.vd) {
++		/* Standard inquiry page */
++		if ((iue->iu->srp.cmd.cdb[1] == 0x00) &&
++		    (iue->iu->srp.cmd.cdb[2] == 0x00)) {
++			dbg("  inquiry returning device\n");
++			id->qual_type = 0x00;	/* Direct Access    */
++			id->rmb_reserve = 0x00;	/* TODO: CD is removable  */
++			id->version = 0x84;	/* ISO/IE                 */
++			id->aerc_naca_hisup_format = 0x22;/* naca & fmt 0x02 */
++			id->addl_len = sizeof(*id) - 4;	
++			id->bque_encserv_vs_multip_mchngr_reserved = 0x00;
++			id->reladr_reserved_linked_cmdqueue_vs = 0x02;/*CMDQ*/
++			memcpy(id->vendor, "IBM     ", 8);
++			memcpy(id->product, "VSCSI blkdev    ", 16);
++			memcpy(id->revision, "0001", 4);
++			snprintf(id->unique,sizeof(id->unique),
++				 "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n",
++				 system_id,
++				 partition_number,
++				 iue->adapter->dma_dev->unit_address,
++				 GETBUS(iue->req.vd->lun),
++				 GETTARGET(iue->req.vd->lun),
++				 GETLUN(iue->req.vd->lun));
++		} else if ((iue->iu->srp.cmd.cdb[1] == 0x01) &&
++			   (iue->iu->srp.cmd.cdb[2] == 0x00)) {
++			/* Supported VPD pages */
++			raw_id[0] = 0x00; /* qualifier & type */
++			raw_id[1] = 0x80; /* page */
++			raw_id[2] = 0x00; /* reserved */
++			raw_id[3] = 0x03; /* length */
++			raw_id[4] = 0x00; /* page 0 */
++			raw_id[5] = 0x80; /* serial number page */
++		} else if ((iue->iu->srp.cmd.cdb[1] == 0x01) &&
++			   (iue->iu->srp.cmd.cdb[2] == 0x80)) {
++			/* serial number page */
++			raw_id[0] = 0x00; /* qualifier & type */
++			raw_id[1] = 0x80; /* page */
++			raw_id[2] = 0x00; /* reserved */
++			snprintf((char *)(raw_id+4),
++				 sizeof(*id)-4,
++				 "IBM-VSCSI-%s-P%d-%x-%d-%d-%d\n",
++				 system_id,
++				 partition_number,
++				 iue->adapter->dma_dev->unit_address,
++				 GETBUS(iue->req.vd->lun),
++				 GETTARGET(iue->req.vd->lun),
++				 GETLUN(iue->req.vd->lun));
++			raw_id[3] = strlen((char *)raw_id+4);
++		} else {
++			/* Some unsupported data */
++			send_rsp(iue, SENSE_INVALID_FIELD);
++			free_iu(iue);
++			return;
++		}
++	} else {
++		dbg("  inquiry returning no device\n");
++		id->qual_type = 0x7F;	/* Not supported, no device */
++	}
++
++	bytes = send_cmd_data(data_token, sizeof(*id), iue);
++
++	dma_free_coherent(iue->adapter->dev, sizeof(*id), id, data_token);
++
++	if (bytes < 0) {
++		send_rsp(iue, SENSE_DEVICE_FAULT);
++	} else {
++		send_rsp(iue, SENSE_SUCCESS);
++	}
++
++	free_iu(iue);
++}
++
++/*
++ * Handle an I/O.  Called by WRITE6, WRITE10, etc
++ */
++static void process_rw(char *cmd, int rw, struct iu_entry *iue, long lba,
++		       long len)
++{
++	char *buffer;
++	struct bio *bio;
++	int bytes;
++	int num_biovec;
++	int cur_biovec;
++	long flags;
++
++	dbg("%s %16.16lx[%d:%d:%d][%s] lba %ld len %ld reladr %d link %d\n",
++	    cmd,
++	    iue->iu->srp.cmd.lun,
++	    GETBUS(iue->iu->srp.cmd.lun),
++	    GETTARGET(iue->iu->srp.cmd.lun),
++	    GETLUN(iue->iu->srp.cmd.lun),
++	    iue->req.vd->b.device_name,
++	    lba,
++	    len / iue->req.vd->b.blksize,
++	    iue->iu->srp.cmd.cdb[1] & 0x01, iue->req.linked);
++
++	if (rw == WRITE) {
++		atomic_inc(&iue->adapter->write_processed);
++	} else if (rw == READ) {
++		atomic_inc(&iue->adapter->read_processed);
++	} else {
++		err("Major internal error...rw not read or write\n");
++		send_rsp(iue, SENSE_DEVICE_FAULT);
++
++		free_iu(iue);
++		return;
++	}
++
++	if (len == 0) {
++		warn("Zero length I/O\n");
++		send_rsp(iue, SENSE_INVALID_CMD);
++
++		free_iu(iue);
++		return;
++	}
++
++	/* Writing to a read-only device */
++	if ((rw == WRITE) && (iue->req.vd->b.ro)) {
++		warn("WRITE to read-only device\n");
++		send_rsp(iue, SENSE_WRITE_PROT);
++
++		free_iu(iue);
++		return;
++	}
++
++	get_data_buffer(&buffer, &iue->req.data_token, len, iue->adapter);
++	iue->req.data_buffer = buffer;
++	iue->req.data_len = len;
++	if (buffer == NULL) {
++		err("Not able to get a data buffer (%lu pages)\n",
++		    len / PAGE_SIZE);
++		send_rsp(iue, SENSE_DEVICE_FAULT);
++
++		free_iu(iue);
++		return;
++	}
++
++	/* if reladr */
++	if (iue->iu->srp.cmd.cdb[1] & 0x01) {
++		lba = lba + iue->req.vd->b.lastlba;
++	}
++
++	/* If this command is linked, Keep this lba */
++	if (iue->req.linked) {
++		iue->req.vd->b.lastlba = lba;
++	} else {
++		iue->req.vd->b.lastlba = 0;
++	}
++
++	if (rw == WRITE) {
++		iue->req.write = 1;
++		/* Get the data */
++		bytes = get_cmd_data(iue->req.data_token, len, iue);
++		if (bytes != len) {
++			err("Error transferring data\n");
++			send_rsp(iue, SENSE_DEVICE_FAULT);
++
++			free_iu(iue);
++			return;
++		}
++	}
++
++	num_biovec = (len - 1) / PAGE_CACHE_SIZE + 1;
++
++	bio = bio_alloc(GFP_ATOMIC, num_biovec);
++	if (!bio) {
++		/* Ouch.  couldn't get a bio.  Mark this I/O as 
++		 * in error, then decrement the outstanding bio.
++		 * If there are still outstanding bio, they will send
++		 * the error and free the IU.  If there are none, we
++		 * should do it here
++		 */
++		iue->req.ioerr = 1;
++		err("Not able to allocate a bio\n");
++		send_rsp(iue, SENSE_DEVICE_FAULT);
++		free_iu(iue);
++		return;
++	}
++
++	iue->aborted = 0;
++	spin_lock_irqsave(&iue->adapter->lock, flags);
++	list_add_tail(&iue->next, &iue->adapter->inflight);
++	spin_unlock_irqrestore(&iue->adapter->lock, flags);
++
++	atomic_inc(&iue->adapter->bio_count);
++	bio->bi_size = len;
++	bio->bi_bdev = iue->req.vd->b.bdev;
++	bio->bi_sector = lba;
++	bio->bi_end_io = &ibmvscsis_end_io;
++	bio->bi_private = iue;
++	bio->bi_rw = (rw == WRITE) ? 1 : 0;
++	bio->bi_phys_segments = 1;
++	bio->bi_hw_segments = 1;
++
++	/* This all assumes that the buffers we get are page-aligned */
++	for (cur_biovec = 0; cur_biovec < num_biovec; cur_biovec++) {
++		long thislen;
++
++		if (len > PAGE_CACHE_SIZE) {
++			thislen = PAGE_CACHE_SIZE;
++		} else {
++			thislen = len;
++		}
++
++		bio->bi_io_vec[cur_biovec].bv_page = virt_to_page(buffer);
++		bio->bi_io_vec[cur_biovec].bv_len = thislen;
++		bio->bi_io_vec[cur_biovec].bv_offset =
++		    (unsigned long)buffer & PAGE_OFFSET_MASK;
++		bio->bi_vcnt++;
++
++		len -= thislen;
++		buffer += thislen;
++	}
++	generic_make_request(bio);
++}
++
++/*
++ * Process a READ6
++ */
++static void processRead6(struct iu_entry *iue)
++{
++	long lba = (*((u32 *) (iue->iu->srp.cmd.cdb))) & 0x001FFFFF;
++	long len = iue->iu->srp.cmd.cdb[4];
++
++	/* Length of 0 indicates 256 */
++	if (len == 0) {
++		len = 256;
++	}
++
++	len = len * iue->req.vd->b.blksize;
++
++	process_rw("Read6", READ, iue, lba, len);
++}
++
++/*
++ * Process a READ10
++ */
++static void processRead10(struct iu_entry *iue)
++{
++	long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2));
++	long len =
++	    *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.blksize;
++
++	process_rw("Read10", READ, iue, lba, len);
++}
++
++/*
++ * Process a READ10
++ */
++static void processRead12(struct iu_entry *iue)
++{
++	long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2));
++	long len =
++	    *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.blksize;
++
++	process_rw("Read12", READ, iue, lba, len);
++}
++
++static void processWrite6(struct iu_entry *iue)
++{
++	long lba = (*((u32 *) (iue->iu->srp.cmd.cdb))) & 0x001FFFFF;
++	long len = iue->iu->srp.cmd.cdb[4];
++
++	/* Length of 0 indicates 256 */
++	if (len == 0) {
++		len = 256;
++	}
++
++	len = len * iue->req.vd->b.blksize;
++
++	process_rw("Write6", WRITE, iue, lba, len);
++}
++
++static void processWrite10(struct iu_entry *iue)
++{
++	long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2));
++	long len =
++	    *((u16 *) (iue->iu->srp.cmd.cdb + 7)) * iue->req.vd->b.blksize;
++
++	process_rw("Write10", WRITE, iue, lba, len);
++}
++
++static void processWrite12(struct iu_entry *iue)
++{
++	long lba = *((u32 *) (iue->iu->srp.cmd.cdb + 2));
++	long len =
++	    *((u32 *) (iue->iu->srp.cmd.cdb + 6)) * iue->req.vd->b.blksize;
++
++	process_rw("Write12", WRITE, iue, lba, len);
++}
++
++/*
++ * Handle Read Capacity
++ */
++static void processReadCapacity(struct iu_entry *iue)
++{
++	struct ReadCapacityData {
++		u32 blocks;
++		u32 blocksize;
++	} *cap;
++	dma_addr_t data_token;
++	int bytes;
++
++	cap = (struct ReadCapacityData *)dma_alloc_coherent(iue->adapter->dev,
++							    sizeof(*cap),
++							    &data_token, 0);
++
++	/* return block size and last valid block */
++	cap->blocksize = iue->req.vd->b.blksize;
++	cap->blocks = iue->req.vd->b.bdev->bd_inode->i_size
++	    / iue->req.vd->b.blksize 
++	    - 1;
++
++	info("Reporting capacity as %u block of size %u\n", cap->blocks,
++	     cap->blocksize);
++
++	bytes = send_cmd_data(data_token, sizeof(*cap), iue);
++
++	dma_free_coherent(iue->adapter->dev, sizeof(*cap), cap, data_token);
++
++	if (bytes != sizeof(*cap)) {
++		err("Error sending read capacity data. bytes %d, wanted %ld\n",
++		    bytes, sizeof(*cap));
++	}
++
++	send_rsp(iue, SENSE_SUCCESS);
++
++	free_iu(iue);
++}
++
++/*
++ * Process Mode Sense
++ * TODO: I know scsiinfo asks for a bunch of mode pages not implemented here.
++ *       Also, we need to act differently for virtual disk and virtual CD
++ */
++#define MODE_SENSE_BUFFER_SIZE (512)
++static void processModeSense(struct iu_entry *iue)
++{
++	dma_addr_t data_token;
++	int bytes;
++
++	u8 *mode = (u8 *) dma_alloc_coherent(iue->adapter->dev,
++					     MODE_SENSE_BUFFER_SIZE,
++					     &data_token, 0);
++	/* which page */
++	switch (iue->iu->srp.cmd.cdb[2]) {
++	case 0:
++	case 0x3f:
++		mode[1] = 0x00;	/* Default medium */
++		if (iue->req.vd->b.ro) {
++			mode[2] = 0x80;	/* device specific  */
++		} else {
++			mode[2] = 0x00;	/* device specific  */
++		}
++		/* note the DPOFUA bit is set to zero! */
++		mode[3] = 0x08;	/* block descriptor length */
++		*((u32 *) & mode[4]) = iue->req.vd->b.bdev->bd_inode->i_size /
++		    iue->req.vd->b.blksize;
++		*((u32 *) & mode[8]) = iue->req.vd->b.blksize;
++		bytes = mode[0] = 12;	/* length */
++		break;
++
++	case 0x08:		/* Cache page */
++		/* length should be 4 */
++		if (iue->iu->srp.cmd.cdb[4] != 4
++		    && iue->iu->srp.cmd.cdb[4] != 0x20) {
++			send_rsp(iue, SENSE_INVALID_CMD);
++			dma_free_coherent(iue->adapter->dev,
++					  MODE_SENSE_BUFFER_SIZE,
++					  mode, data_token);
++			free_iu(iue);
++			return;
++		}
++
++		mode[1] = 0x00;	/* Default medium */
++		if (iue->req.vd->b.ro) {
++			mode[2] = 0x80;	/* device specific */
++		} else {
++			mode[2] = 0x00;	/* device specific */
++		}
++		/* note the DPOFUA bit is set to zero! */
++		mode[3] = 0x08;	/* block descriptor length */
++		*((u32 *) & mode[4]) = iue->req.vd->b.bdev->bd_inode->i_size /
++		    iue->req.vd->b.blksize;
++		*((u32 *) & mode[8]) = iue->req.vd->b.blksize;
++
++		/* Cache page */
++		mode[12] = 0x08;	/* page */
++		mode[13] = 0x12;	/* page length */
++		mode[14] = 0x01;	/* no cache (0x04 for read/write cache) */
++
++		bytes = mode[0] = 12 + mode[13];	/* length */
++		break;
++	default:
++		warn("Request for unknown mode page %d\n",
++		     iue->iu->srp.cmd.cdb[2]);
++		send_rsp(iue, SENSE_INVALID_CMD);
++		dma_free_coherent(iue->adapter->dev,
++				  MODE_SENSE_BUFFER_SIZE, mode, data_token);
++		free_iu(iue);
++		return;
++	}
++
++	bytes = send_cmd_data(data_token, bytes, iue);
++
++	dma_free_coherent(iue->adapter->dev,
++			  MODE_SENSE_BUFFER_SIZE, mode, data_token);
++
++	send_rsp(iue, SENSE_SUCCESS);
++
++	free_iu(iue);
++	return;
++}
++
++/*
++ * Report LUNS command.
++ */
++static void processReportLUNs(struct iu_entry *iue)
++{
++	int listsize = did_len(&iue->iu->srp.cmd);
++	dma_addr_t data_token;
++	int index = 2;		/* Start after the two entries (length and LUN0) */
++	int bus;
++	int target;
++	int bytes;
++	unsigned long flags;
++
++	u64 *lunlist = (u64 *) dma_alloc_coherent(iue->adapter->dev,
++						  listsize,
++						  &data_token, 0);
++
++	memset(lunlist, 0x00, listsize);
++
++	/* work out list size in units of u64 */
++	listsize = listsize / 8;
++
++	if (listsize < 1) {
++		send_rsp(iue, SENSE_INVALID_CMD);
++		free_iu(iue);
++	}
++
++	spin_lock_irqsave(&iue->adapter->lock, flags);
++
++	/* send lunlist of size 1 when requesting lun is not all zeros */
++	if (iue->iu->srp.cmd.lun != 0x0LL) {
++		*lunlist = ((u64) 1 * 8) << 32;
++		goto send_lunlist;
++	}
++
++	/* return the total number of luns plus LUN0 in bytes */
++	*lunlist = (((u64) ((iue->adapter->nvdevs + 1) * 8)) << 32);
++
++	dbg("reporting %d luns\n", iue->adapter->nvdevs + 1);
++	/* loop through the bus */
++	for (bus = 0; bus < BUS_PER_ADAPTER; bus++) {
++		/* If this bus exists */
++		if (iue->adapter->vbus[bus]) {
++			/* loop through the targets */
++			for (target = 0; target < TARGETS_PER_BUS; target++) {
++				/* If the target exists */
++				if (iue->adapter->vbus[bus]->vdev[target]) {
++					if ((index < listsize) &&
++					    (!iue->adapter->vbus[bus]->
++					     vdev[target]->disabled)) {
++						lunlist[index++] =
++						    iue->adapter->vbus[bus]->
++						    vdev[target]->lun;
++						dbg("  lun %16.16lx\n",
++						    iue->adapter->vbus[bus]->
++						    vdev[target]->lun);
++					}
++				}
++			}
++		}
++	}
++
++      send_lunlist:
++	spin_unlock_irqrestore(&iue->adapter->lock, flags);
++
++	bytes = send_cmd_data(data_token, (index * 8), iue);
++
++	dma_free_coherent(iue->adapter->dev, listsize * 8, lunlist, data_token);
++
++	if (bytes != (index * 8)) {
++		err("Error sending report luns data. bytes %d, wanted %d\n",
++		    bytes, index * 4);
++		send_rsp(iue, SENSE_ABORT);
++	} else {
++		send_rsp(iue, SENSE_SUCCESS);
++	}
++
++	free_iu(iue);
++	return;
++}
++
++/*
++ * Process an IU.  
++ *
++ * Note that THIS routine is responsible for returning the IU from the pool
++ * The current assumption is that all the process routines called from here
++ * are, in turn, responsible for freeing the IU
++ */
++static void process_cmd(struct iu_entry *iue)
++{
++	union viosrp_iu *iu = iue->iu;
++
++	iue->req.vd = find_device(iue);
++
++	if ((iue->req.vd == NULL) &&
++	    (iu->srp.cmd.cdb[0] != REPORT_LUNS) &&
++	    (iu->srp.cmd.cdb[0] != INQUIRY)) {
++		dbg("Cmd %2.2x for unknown LUN %16.16lx\n",
++		    iu->srp.cmd.cdb[0], iue->iu->srp.cmd.lun);
++		send_rsp(iue, SENSE_INVALID_ID);
++		free_iu(iue);
++		return;
++	}
++
++	iue->req.linked = getlink(iue);
++
++	switch (iu->srp.cmd.cdb[0]) {
++	case READ_6:
++		processRead6(iue);
++		break;
++	case READ_10:
++		processRead10(iue);
++		break;
++	case READ_12:
++		processRead12(iue);
++		break;
++	case WRITE_6:
++		processWrite6(iue);
++		break;
++	case WRITE_10:
++		processWrite10(iue);
++		break;
++	case WRITE_12:
++		processWrite12(iue);
++		break;
++	case REPORT_LUNS:
++		dbg("REPORT LUNS lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		processReportLUNs(iue);
++		break;
++	case INQUIRY:
++		dbg("INQUIRY lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		process_inquiry(iue);
++		break;
++	case READ_CAPACITY:
++		dbg("READ CAPACITY lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		processReadCapacity(iue);
++		break;
++	case MODE_SENSE:
++		dbg("MODE SENSE lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		processModeSense(iue);
++		break;
++	case TEST_UNIT_READY:
++		/* we already know the device exists */
++		dbg("TEST UNIT READY lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		send_rsp(iue, SENSE_SUCCESS);
++		free_iu(iue);
++		break;
++	case START_STOP:
++		/* just respond OK */
++		dbg("START_STOP lun %16.16lx\n", iue->iu->srp.cmd.lun);
++		send_rsp(iue, SENSE_SUCCESS);
++		free_iu(iue);
++		break;
++	default:
++		warn("Unsupported SCSI Command 0x%2.2x\n", iu->srp.cmd.cdb[0]);
++		send_rsp(iue, SENSE_INVALID_CMD);
++		free_iu(iue);
++	}
++}
++
++u16 send_adapter_info(struct iu_entry *iue,
++		      dma_addr_t remote_buffer, u16 length)
++{
++	dma_addr_t data_token;
++	struct mad_adapter_info_data *info =
++	    (struct mad_adapter_info_data *)dma_alloc_coherent(iue->adapter->
++							       dev,
++							       sizeof(*info),
++							       &data_token, 0);
++
++	dbg("in send_adapter_info\n ");
++	if ((info) && (!dma_mapping_error(data_token))) {
++		int rc;
++		memset(info, 0x00, sizeof(*info));
++
++		dbg("building adapter_info\n ");
++		strcpy(info->srp_version, "1.6a");
++		strncpy(info->partition_name, partition_name,
++			sizeof(info->partition_name));
++		info->partition_number = partition_number;
++		info->mad_version = 1;
++		info->os_type = 3;
++
++		rc = h_copy_rdma(sizeof(*info),
++				 iue->adapter->liobn,
++				 data_token,
++				 iue->adapter->riobn,
++				 remote_buffer);
++
++		dma_free_coherent(iue->adapter->dev,
++				  sizeof(*info), info, data_token);
++
++		if (rc != H_Success) {
++			err("Error sending adapter info rc %d\n",rc);
++			return 1;
++		}
++	} else {
++		dbg("bad dma_alloc_cohereint in adapter_info\n ");
++		return 1;
++	}
++	return 0;
++
++}
++
++/* ==============================================================
++ * SRP Processing Routines
++ * ==============================================================
++ */
++/*
++ * Process an incoming SRP Login request
++ */
++static void process_login(struct iu_entry *iue)
++{
++	union viosrp_iu *iu = iue->iu;
++	u64 tag = iu->srp.generic.tag;
++
++	/* TODO handle case that requested size is wrong and buffer format is wrong */
++	memset(iu, 0x00, sizeof(struct srp_login_rsp));
++	iu->srp.login_rsp.type = SRP_LOGIN_RSP_TYPE;
++	iu->srp.login_rsp.request_limit_delta = iue->adapter->pool.size;
++	iu->srp.login_rsp.tag = tag;
++	iu->srp.login_rsp.max_initiator_to_target_iulen = sizeof(union srp_iu);
++	iu->srp.login_rsp.max_target_to_initiator_iulen = sizeof(union srp_iu);
++	iu->srp.login_rsp.supported_buffer_formats = 0x0006;	/* direct and indirect */
++	iu->srp.login_rsp.multi_channel_result = 0x00;	/* TODO fix if we were already logged in */
++
++	send_srp(iue, sizeof(iu->srp.login_rsp));
++}
++
++/*
++ * Send an SRP response that includes sense data
++ */
++static long send_rsp(struct iu_entry *iue, int status)
++{
++	u8 *sense = iue->iu->srp.rsp.sense_and_response_data;
++	u64 tag = iue->iu->srp.generic.tag;
++	union viosrp_iu *iu = iue->iu;
++
++	if (status != SENSE_SUCCESS) {
++		atomic_inc(&iue->adapter->errors);
++	}
++
++	/* If the linked bit is on and status is good */
++	if ((iue->req.linked) && (status == SENSE_SUCCESS)) {
++		status = SENSE_INTERMEDIATE;
++	}
++
++	memset(iu, 0x00, sizeof(struct srp_rsp));
++	iu->srp.rsp.type = SRP_RSP_TYPE;
++	iu->srp.rsp.request_limit_delta = 1;
++	iu->srp.rsp.tag = tag;
++
++	iu->srp.rsp.diunder = iue->req.diunder;
++	iu->srp.rsp.diover = iue->req.diover;
++	iu->srp.rsp.dounder = iue->req.dounder;
++	iu->srp.rsp.doover = iue->req.doover;
++
++	iu->srp.rsp.data_in_residual_count = iue->req.data_in_residual_count;
++	iu->srp.rsp.data_out_residual_count = iue->req.data_out_residual_count;
++
++	iu->srp.rsp.rspvalid = 0;
++
++	iu->srp.rsp.response_data_list_length = 0;
++
++	if (status) {
++		iu->srp.rsp.status = SAM_STAT_CHECK_CONDITION;
++		iu->srp.rsp.snsvalid = 1;
++		iu->srp.rsp.sense_data_list_length = 18;	/* TODO be smarter about this */
++
++		/* Valid bit and 'current errors' */
++		sense[0] = (0x1 << 7 | 0x70);
++
++		/* Sense key */
++		sense[2] = ibmvscsis_sense_data[status][0];
++
++		/* Additional sense length */
++		sense[7] = 0xa;	/* 10 bytes */
++
++		/* Additional sense code */
++		sense[12] = ibmvscsis_sense_data[status][1];
++
++		/* Additional sense code qualifier */
++		sense[13] = ibmvscsis_sense_data[status][2];
++	} else {
++		iu->srp.rsp.status = 0;
++	}
++
++	send_srp(iue, sizeof(iu->srp.rsp));
++
++	return 0;
++}
++
++static void process_device_reset(struct iu_entry *iue)
++{
++	struct iu_entry *tmp_iue;
++	unsigned long flags;
++	union viosrp_iu *iu = iue->iu;
++
++	info("device reset for lun %16.16lx\n", iu->srp.tsk_mgmt.lun);
++
++	spin_lock_irqsave(&iue->adapter->lock, flags);
++
++	list_for_each_entry(tmp_iue, &iue->adapter->inflight, next) {
++		if (iu->srp.tsk_mgmt.lun == tmp_iue->iu->srp.cmd.lun) {
++			{
++				tmp_iue->aborted = 1;
++			}
++		}
++
++	}
++
++	spin_unlock_irqrestore(&iue->adapter->lock, flags);
++	send_rsp(iue, SENSE_SUCCESS);
++}
++
++static void process_abort(struct iu_entry *iue)
++{
++	struct iu_entry *tmp_iue;
++	unsigned long flags;
++	union viosrp_iu *iu = iue->iu;
++
++	info("aborting task with tag %16.16lx, lun %16.16lx\n",
++	     iu->srp.tsk_mgmt.managed_task_tag, iu->srp.tsk_mgmt.lun);
++
++	spin_lock_irqsave(&iue->adapter->lock, flags);
++
++	list_for_each_entry(tmp_iue, &iue->adapter->inflight, next) {
++		if (tmp_iue->iu->srp.cmd.tag ==
++		    iu->srp.tsk_mgmt.managed_task_tag) {
++			{
++				tmp_iue->aborted = 1;
++				info("abort successful\n");
++				spin_unlock_irqrestore(&iue->adapter->lock,
++						       flags);
++				send_rsp(iue, SENSE_SUCCESS);
++				return;
++			}
++		}
++	}
++	info("unable to abort cmd\n");
++
++	spin_unlock_irqrestore(&iue->adapter->lock, flags);
++	send_rsp(iue, SENSE_INVALID_ID);
++}
++
++static void process_tsk_mgmt(struct iu_entry *iue)
++{
++	union viosrp_iu *iu = iue->iu;
++
++	if (iu->srp.tsk_mgmt.task_mgmt_flags == 0x01) {
++		process_abort(iue);
++	} else if (iu->srp.tsk_mgmt.task_mgmt_flags == 0x08) {
++		process_device_reset(iue);
++	} else {
++		send_rsp(iue, SENSE_INVALID_CMD);
++	}
++}
++
++static void process_iu(struct viosrp_crq *crq, struct server_adapter *adapter)
++{
++	struct iu_entry *iue = get_iu(adapter);
++	union viosrp_iu *iu;
++	int queued = 0;
++	long rc;
++
++	if (iue == NULL) {
++		/* TODO Yikes! */
++		warn("Error getting IU from pool, other side exceeded limit\n");
++		return;
++	}
++
++	iue->req.remote_token = crq->IU_data_ptr;
++
++	rc = h_copy_rdma(crq->IU_length,
++			 iue->adapter->riobn,
++			 iue->req.remote_token, adapter->liobn, iue->iu_token);
++
++	iu = iue->iu;
++
++	if (rc) {
++		err("Error %ld transferring data to client\n", rc);
++	}
++
++	if (crq->format == VIOSRP_MAD_FORMAT) {
++		switch (iu->mad.empty_iu.common.type) {
++		case VIOSRP_EMPTY_IU_TYPE:
++			warn("Unsupported EMPTY MAD IU\n");
++			break;
++		case VIOSRP_ERROR_LOG_TYPE:
++			warn("Unsupported ERROR LOG MAD IU\n");
++			iu->mad.error_log.common.status = 1;
++			send_srp(iue, sizeof(iu->mad.error_log));
++			break;
++		case VIOSRP_ADAPTER_INFO_TYPE:
++			iu->mad.adapter_info.common.status =
++			    send_adapter_info(iue,
++					      iu->mad.adapter_info.buffer,
++					      iu->mad.adapter_info.common.
++					      length);
++
++			send_srp(iue, sizeof(iu->mad.adapter_info));
++			break;
++		case VIOSRP_HOST_CONFIG_TYPE:
++			iu->mad.host_config.common.status = 1;
++			send_srp(iue, sizeof(iu->mad.host_config));
++			break;
++		default:
++			warn("Unsupported MAD type %d\n", iu->srp.generic.type);
++		}
++	} else {
++		switch (iu->srp.generic.type) {
++		case SRP_LOGIN_REQ_TYPE:
++			dbg("SRP LOGIN\n");
++			process_login(iue);
++			break;
++		case SRP_LOGIN_RSP_TYPE:
++			warn("Unsupported LOGIN_RSP SRP IU\n");
++			break;
++		case SRP_I_LOGOUT_TYPE:
++			warn("Unsupported I_LOGOUT SRP IU\n");
++			break;
++		case SRP_T_LOGOUT_TYPE:
++			warn("Unsupported T_LOGOUT SRP IU\n");
++			break;
++		case SRP_TSK_MGMT_TYPE:
++			process_tsk_mgmt(iue);
++			break;
++		case SRP_CMD_TYPE:
++			process_cmd(iue);
++			queued = 1;
++			break;
++		case SRP_RSP_TYPE:
++			warn("Unsupported RSP SRP IU\n");
++			break;
++		case SRP_CRED_REQ_TYPE:
++			warn("Unsupported CRED_REQ SRP IU\n");
++			break;
++		case SRP_CRED_RSP_TYPE:
++			warn("Unsupported CRED_RSP SRP IU\n");
++			break;
++		case SRP_AER_REQ_TYPE:
++			warn("Unsupported AER_REQ SRP IU\n");
++			break;
++		case SRP_AER_RSP_TYPE:
++			warn("Unsupported AER_RSP SRP IU\n");
++			break;
++		default:
++			warn("Unsupported SRP type %d\n", iu->srp.generic.type);
++		}
++	}
++
++	/* 
++	 * If no one has queued the IU for further work, free it 
++	 * Note that this is kind of an ugly design based on setting
++	 * this variable up above in cases where the routine we call
++	 * is responsible for freeing the IU
++	 */
++	if (!queued)
++		free_iu(iue);
++}
++
++/* ==============================================================
++ * CRQ Processing Routines
++ * ==============================================================
++ */
++
++/*
++ * Handle a CRQ event
++ */
++static void handle_crq(struct viosrp_crq *crq, struct server_adapter *adapter)
++{
++	switch (crq->valid) {
++	case 0xC0:		/* initialization */
++		switch (crq->format) {
++		case 0x01:
++			info("Client just initialized\n");
++			plpar_hcall_norets(H_SEND_CRQ,
++					   adapter->dma_dev->unit_address,
++					   0xC002000000000000, 0);
++			break;
++		case 0x02:
++			info("Client initialization complete\n");
++			break;
++		default:
++			err("Client error: Unknwn msg format %d\n", 
++			    crq->format);
++		}
++		return;
++	case 0xFF:		/* transport event */
++		info("Client closed\n");
++		return;
++	case 0x80:		/* real payload */
++		{
++			switch (crq->format) {
++			case VIOSRP_SRP_FORMAT:
++			case VIOSRP_MAD_FORMAT:
++				process_iu(crq, adapter);
++				break;
++			case VIOSRP_OS400_FORMAT:
++				warn("Unsupported OS400 format CRQ\n");
++				break;
++
++			case VIOSRP_AIX_FORMAT:
++				warn("Unsupported AIX format CRQ\n");
++				break;
++
++			case VIOSRP_LINUX_FORMAT:
++				warn("Unsupported LINUX format CRQ\n");
++				break;
++
++			case VIOSRP_INLINE_FORMAT:
++				warn("Unsupported _INLINE_ format CRQ\n");
++				break;
++
++			default:
++				err("Client error: Unsupported  msg format %d\n", 
++				    crq->format);
++			}
++		}
++		break;
++	default:
++		err("Client error: unknown message type 0x%02x!?\n",
++		    crq->valid);
++		return;
++	}
++
++}
++
++/*
++ * Task to handle CRQs and completions
++ */
++static void crq_task(void *data)
++{
++	struct server_adapter *adapter = (struct server_adapter *)data;
++	struct viosrp_crq *crq;
++	long rc;
++	int done = 0;
++
++	while (!done) {
++
++		/* Loop through and process CRQs */
++		while ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) {
++			atomic_inc(&adapter->crq_processed);
++			handle_crq(crq, adapter);
++			crq->valid = 0x00;
++		}
++
++		rc = h_vio_signal(adapter->dma_dev->unit_address, 1);
++		if (rc != 0) {
++			err("Error %ld enabling interrupts!!!\n", rc);
++		}
++		if ((crq = crq_queue_next_crq(&adapter->queue)) != NULL) {
++			rc = h_vio_signal(adapter->dma_dev->unit_address, 0);
++			if (rc != 0) {
++				err("Error %ld enabling interrupts!!!\n", rc);
++			}
++			handle_crq(crq, adapter);
++			crq->valid = 0x00;
++		} else {
++			done = 1;
++		}
++	}
++}
++
++/*
++ * Handle the interrupt that occurs when something is placed on our CRQ
++ */
++static irqreturn_t handle_interrupt(int irq, void *dev_instance,
++				    struct pt_regs *regs)
++{
++	struct server_adapter *adapter = (struct server_adapter *)dev_instance;
++	long rc;
++
++	rc = h_vio_signal(adapter->dma_dev->unit_address, 0);
++	if (rc != 0) {
++		err(" Error %ld disabling interrupts!!!\n", rc);
++	}
++
++	atomic_inc(&adapter->interrupts);
++
++	kblockd_schedule_work(&adapter->crq_task);
++
++	return IRQ_HANDLED;
++}
++
++/* 
++ * Initialize our CRQ
++ * return zero on success, non-zero on failure 
++ */
++static int initialize_crq_queue(struct crq_queue *queue,
++				struct server_adapter *adapter)
++{
++	int rc;
++
++	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
++	if (!queue->msgs)
++		goto malloc_failed;
++	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
++
++	queue->msg_token = dma_map_single(adapter->dev, queue->msgs,
++					  queue->size * sizeof(*queue->msgs),
++					  DMA_BIDIRECTIONAL);
++
++	if (dma_mapping_error(queue->msg_token))
++		goto map_failed;
++
++	rc = plpar_hcall_norets(H_REG_CRQ, adapter->dma_dev->unit_address,
++				queue->msg_token, PAGE_SIZE);
++	
++	if ((rc != 0) && (rc != 2)) {
++		err("Error 0x%x opening virtual adapter\n", rc);
++		goto reg_crq_failed;
++	}
++
++	if (request_irq
++	    (adapter->dma_dev->irq, &handle_interrupt, SA_INTERRUPT,
++	     "ibmvscsis", adapter) != 0)
++		goto req_irq_failed;
++
++	rc = h_vio_signal(adapter->dma_dev->unit_address, 1);
++	if (rc != 0) {
++		err("Error %d enabling interrupts!!!\n", rc);
++		goto req_irq_failed;
++	}
++
++	plpar_hcall_norets(H_SEND_CRQ, adapter->dma_dev->unit_address,
++				   0xC001000000000000, 0);
++
++	queue->cur = 0;
++	queue->lock = SPIN_LOCK_UNLOCKED;
++
++	return 0;
++
++      req_irq_failed:
++	do {
++		rc = plpar_hcall_norets(H_FREE_CRQ, adapter->dma_dev->unit_address);
++	} while ((rc == H_Busy) || (H_isLongBusy(rc)));
++	
++      reg_crq_failed:
++	dma_unmap_single(adapter->dev, queue->msg_token,
++			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
++      map_failed:
++	free_page((unsigned long)queue->msgs);
++      malloc_failed:
++	return -1;
++}
++
++/*
++ * Release the CRQ
++ */
++static void release_crq_queue(struct crq_queue *queue,
++			      struct server_adapter *adapter)
++{
++	int rc;
++
++	info("releasing adapter\n");
++	free_irq(adapter->dma_dev->irq, adapter);
++	do {
++		rc = plpar_hcall_norets(H_FREE_CRQ, adapter->dma_dev->unit_address);
++	} while ((rc == H_Busy) || (H_isLongBusy(rc)));
++	dma_unmap_single(adapter->dev, queue->msg_token,
++			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
++	free_page((unsigned long)queue->msgs);
++}
++
++/* ==============================================================
++ * Module Management
++ * ==============================================================
++ */
++/*
++ * Add a block device as a SCSI LUN
++ */
++static int activate_block_device(struct vdev *vdev)
++{
++	struct block_device *bdev;
++	char *name = vdev->b.device_name;
++	int ro = vdev->b.ro;
++
++	bdev = open_bdev_excl(name, ro, activate_block_device);
++	if (IS_ERR(bdev))
++		return PTR_ERR(bdev);;
++
++	vdev->b.bdev = bdev;
++	vdev->disabled = 0;
++
++	info("Activating block device %s as %sLUN 0x%lx\n",
++	     name, ro ? "read only " : "", vdev->lun);
++
++	return 0;
++}
++
++static void deactivate_block_device(struct vdev *vdev)
++{
++	info("Deactivating block device, LUN 0x%lx\n", vdev->lun);
++
++	/* Wait while any users of this device finish.  Note there should
++	 * be no new users, since we have marked this disabled
++	 *
++	 * We just poll here, since we are blocking write
++	 */
++	while (atomic_read(&vdev->refcount)) {
++		schedule_timeout(HZ / 4);	/* 1/4 second */
++	}
++
++	vdev->disabled = 1;
++	close_bdev_excl(vdev->b.bdev);
++}
++
++
++#define ATTR(_type, _name, _mode)      \
++struct attribute vscsi_##_type##_##_name##_attr = {               \
++.name = __stringify(_name), .mode = _mode, .owner = THIS_MODULE \
++};
++
++static struct kobj_type ktype_vscsi_target;
++static struct kobj_type ktype_vscsi_bus;
++static struct kobj_type ktype_vscsi_stats;
++
++static void set_num_targets(struct vbus* vbus, long value)
++{
++	struct device *dev = 
++		container_of(vbus->kobj.parent, struct device , kobj);
++	struct server_adapter *adapter = (struct server_adapter *)to_vio_dev(dev)->driver_data;
++	int cur_num_targets = atomic_read(&vbus->num_targets);
++	unsigned long flags;
++
++	spin_lock_irqsave(&adapter->lock, flags);
++
++	if (cur_num_targets < value) { //growing
++		int i;
++		for (i = cur_num_targets; i < value; i++) {
++			vbus->vdev[i] = (struct vdev *)
++				kmalloc(sizeof(struct vdev), GFP_KERNEL);
++			if (!vbus->vdev[i]) {
++				spin_unlock_irqrestore(&adapter->lock, flags);
++				err("Couldn't allocate target memory %d\n", i);
++				return;
++			}
++			memset(vbus->vdev[i], 0x00, sizeof(struct vdev));
++
++			vbus->vdev[i]->lun = make_lun(vbus->bus_num, i, 0);
++			vbus->vdev[i]->b.blksize = 512;
++			vbus->vdev[i]->disabled = 1;
++
++			vbus->vdev[i]->kobj.parent = &vbus->kobj;
++			sprintf(vbus->vdev[i]->kobj.name, "target%d", i);
++			vbus->vdev[i]->kobj.ktype = &ktype_vscsi_target;
++			kobject_register(&vbus->vdev[i]->kobj);
++			adapter->nvdevs++;
++			atomic_inc(&vbus->num_targets);
++		}
++	} else { //shrinking
++		int i;
++		for (i = cur_num_targets - 1; i >= value; i--)
++		{
++			if (!vbus->vdev[i]->disabled) {
++				spin_unlock_irqrestore(&adapter->lock, flags);
++				err("Can't remove active target %d\n", i);
++				return;
++			}
++
++			kobject_unregister(&vbus->vdev[i]->kobj);
++
++			kfree(vbus->vdev[i]);
++
++			adapter->nvdevs--;
++			atomic_dec(&vbus->num_targets);
++		}
++	}
++	spin_unlock_irqrestore(&adapter->lock, flags);
++}
++
++static void set_num_buses(struct device *dev, long value)
++{
++	struct server_adapter *adapter = (struct server_adapter *)to_vio_dev(dev)->driver_data;
++	int cur_num_buses = atomic_read(&adapter->num_buses);
++	unsigned long flags= 0L;
++
++
++	if (cur_num_buses < value) { // growing
++		int i;
++		for (i = cur_num_buses; i < value; i++) {
++			adapter->vbus[i] = (struct vbus *)
++				kmalloc(sizeof(struct vbus), GFP_KERNEL);
++			if (!adapter->vbus[i]) {
++				spin_unlock_irqrestore(&adapter->lock, flags);
++				err("Couldn't allocate bus %d memory\n", i);
++				return;
++			}
++			memset(adapter->vbus[i], 0x00, sizeof(struct vbus));
++
++			spin_lock_irqsave(&adapter->lock, flags);
++
++			adapter->vbus[i]->bus_num = i;
++
++			adapter->vbus[i]->kobj.parent = &dev->kobj;
++			sprintf(adapter->vbus[i]->kobj.name, "bus%d", i);
++			adapter->vbus[i]->kobj.ktype = &ktype_vscsi_bus; 
++			kobject_register(&adapter->vbus[i]->kobj);
++			
++			atomic_inc(&adapter->num_buses);
++			spin_unlock_irqrestore(&adapter->lock, flags);
++
++			set_num_targets(adapter->vbus[i], 1);
++		}
++
++	} else if (cur_num_buses > value) { //shrinking
++		int i, j, active_target;
++		for (i = cur_num_buses - 1; i >= value; i--) {
++			active_target = -1;
++			for (j = 0; j < TARGETS_PER_BUS; j++) {
++				if (adapter->vbus[i]->vdev[j] && 
++				    !adapter->vbus[i]->vdev[j]->disabled) {
++					active_target = j;
++					break;
++				}
++			}
++			if (active_target != -1) {
++				err("Can't remove bus%d, target%d active\n", 
++					i, active_target);
++				return ;
++			}
++
++			set_num_targets(adapter->vbus[i], 0);
++
++			spin_lock_irqsave(&adapter->lock, flags);
++			atomic_dec(&adapter->num_buses);
++			kobject_unregister(&adapter->vbus[i]->kobj);
++			kfree(adapter->vbus[i]);
++			adapter->vbus[i] = NULL;
++			spin_unlock_irqrestore(&adapter->lock, flags);
++		}
++	}
++}
++
++
++/* Target sysfs stuff */
++static ATTR(target, type, 0644);
++static ATTR(target, device, 0644);
++static ATTR(target, active, 0644);
++static ATTR(target, ro, 0644);
++
++static ssize_t vscsi_target_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++	struct vdev *vdev = container_of(kobj, struct vdev, kobj);
++	struct device *dev = container_of(kobj->parent->parent, struct device, kobj);
++	struct server_adapter *adapter = (struct server_adapter *)to_vio_dev(dev)->driver_data;
++	unsigned long flags;
++	ssize_t returned= (ssize_t)0;
++
++	spin_lock_irqsave(&adapter->lock, flags);
++
++	if (attr == &vscsi_target_type_attr)
++		returned = sprintf(buf, "%c\n", vdev->type);
++	else if (attr == &vscsi_target_device_attr)
++		returned = sprintf(buf, "%s\n", vdev->b.device_name);
++	else if (attr == &vscsi_target_active_attr)
++		returned = sprintf(buf, "%d\n", !vdev->disabled);
++	else if (attr == &vscsi_target_ro_attr)
++		returned = sprintf(buf, "%d\n", vdev->b.ro);
++	else {
++		spin_unlock_irqrestore(&adapter->lock, flags);
++		BUG();
++	}
++
++	spin_unlock_irqrestore(&adapter->lock, flags);
++
++	return returned;
++}
++
++static ssize_t vscsi_target_store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count)
++{
++	struct vdev *vdev = container_of(kobj, struct vdev, kobj);
++	struct device *dev = container_of(kobj->parent->parent, struct device, kobj);
++	struct server_adapter *adapter = (struct server_adapter *)to_vio_dev(dev)->driver_data;
++	long flags;
++	long value = simple_strtol(buf, NULL, 10);
++
++	if (attr != &vscsi_target_active_attr && !vdev->disabled) {
++		err("Error: Can't modify properties while target is active.\n");
++		return -EPERM;
++	}
++
++	if (attr == &vscsi_target_type_attr) {
++		if (buf[0] == 'B' ||  buf[0] == 'b')
++			vdev->type = 'B';
++		else if (buf[0] == 'S' || buf[0] == 's') {
++			// TODO
++			err ("SCSI mode not supported yet\n");		
++			return -EINVAL;
++		} else 
++			return -EINVAL;
++	} else if (attr == &vscsi_target_device_attr) {
++		int i;
++		spin_lock_irqsave(&adapter->lock, flags);
++		i  = strlcpy(vdev->b.device_name, buf, TARGET_MAX_NAME_LEN);
++		for (; i >= 0; i--)
++			if (vdev->b.device_name[i] == '\n')
++				vdev->b.device_name[i] = '\0';
++		spin_unlock_irqrestore(&adapter->lock, flags);
++	} else if (attr == &vscsi_target_active_attr) {
++		if (value) {
++			int rc;
++			if (!vdev->disabled) {
++				warn("Warning: Target was already active\n");
++				return -EINVAL;
++			}
++			if (vdev->type == '\0') {
++				err("Error: Type not specified\n");
++				return -EPERM;
++			}
++			rc = activate_block_device(vdev);
++			if (rc) {
++				err("Error opening block device=%d\n", rc);
++				return rc;
++			}
++		} else {
++			if (!vdev->disabled) 
++				deactivate_block_device(vdev);
++		}
++	} else if (attr == &vscsi_target_ro_attr)
++		vdev->b.ro = value > 0 ? 1 : 0;
++	else 
++		BUG();
++
++	return count;
++}
++
++static struct attribute * vscsi_target_attrs[] = {
++	&vscsi_target_type_attr,
++	&vscsi_target_device_attr,
++	&vscsi_target_active_attr,
++	&vscsi_target_ro_attr,
++	NULL,
++};
++
++static struct sysfs_ops vscsi_target_ops = {
++	.show   = vscsi_target_show,
++	.store  = vscsi_target_store,
++};
++
++static struct kobj_type ktype_vscsi_target = {
++	.release        = NULL,
++	.sysfs_ops      = &vscsi_target_ops, 
++	.default_attrs  = vscsi_target_attrs,
++};
++
++
++
++/* Bus sysfs stuff */
++static ssize_t vscsi_bus_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++	struct vbus *vbus = container_of(kobj, struct vbus, kobj);
++	return sprintf(buf, "%d\n", atomic_read(&vbus->num_targets));
++}
++
++static ssize_t vscsi_bus_store(struct kobject * kobj, struct attribute * attr, 
++const char * buf, size_t count)
++{
++	struct vbus *vbus = container_of(kobj, struct vbus, kobj);
++	long value = simple_strtol(buf, NULL, 10);
++	
++	if (value < 0 || value > TARGETS_PER_BUS)
++		return -EINVAL;
++	
++	set_num_targets(vbus, value);
++
++	return count;
++}
++
++
++static ATTR(bus, num_targets, 0644);
++
++static struct attribute * vscsi_bus_attrs[] = {
++	&vscsi_bus_num_targets_attr,
++	NULL,
++};
++
++static struct sysfs_ops vscsi_bus_ops = {
++	.show   = vscsi_bus_show,
++	.store  = vscsi_bus_store,
++};
++
++static struct kobj_type ktype_vscsi_bus = {
++	.release        = NULL,
++	.sysfs_ops      = &vscsi_bus_ops, 
++	.default_attrs  = vscsi_bus_attrs,
++};
++
++
++/* Device attributes */
++static ssize_t vscsi_dev_bus_show(struct device * dev, char * buf)
++{
++	struct server_adapter *adapter = (struct server_adapter *)to_vio_dev(dev)->driver_data;
++
++	return sprintf(buf, "%d\n", atomic_read(&adapter->num_buses));
++}
++
++static ssize_t vscsi_dev_bus_store(struct device * dev, const char * buf, size_t count)
++{
++	long value = simple_strtol(buf, NULL, 10);
++	
++	if (value < 0 || value > BUS_PER_ADAPTER)
++		return -EINVAL;
++
++	set_num_buses(dev, value);
++	return count;
++}
++
++static DEVICE_ATTR(num_buses, 0644, vscsi_dev_bus_show, vscsi_dev_bus_store);
++
++
++/* Stats kobj stuff */
++
++static ATTR(stats, interrupts, 0444);
++static ATTR(stats, read_ops, 0444);
++static ATTR(stats, write_ops, 0444);
++static ATTR(stats, crq_msgs, 0444);
++static ATTR(stats, iu_allocs, 0444);
++static ATTR(stats, bio_allocs, 0444);
++static ATTR(stats, buf_allocs, 0444);
++static ATTR(stats, errors, 0444);
++
++static struct attribute * vscsi_stats_attrs[] = {
++	&vscsi_stats_interrupts_attr,
++	&vscsi_stats_read_ops_attr,
++	&vscsi_stats_write_ops_attr,
++	&vscsi_stats_crq_msgs_attr,
++	&vscsi_stats_iu_allocs_attr,
++	&vscsi_stats_bio_allocs_attr,
++	&vscsi_stats_buf_allocs_attr,
++	&vscsi_stats_errors_attr,
++	NULL,
++};
++
++
++static ssize_t vscsi_stats_show(struct kobject * kobj, struct attribute * attr, char * buf)
++{
++	struct server_adapter *adapter= container_of(kobj, struct server_adapter, stats_kobj);
++	if (attr == &vscsi_stats_interrupts_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->interrupts));
++	if (attr == &vscsi_stats_read_ops_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->read_processed));
++	if (attr == &vscsi_stats_write_ops_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->write_processed));
++	if (attr == &vscsi_stats_crq_msgs_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->crq_processed));
++	if (attr == &vscsi_stats_iu_allocs_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->iu_count));
++	if (attr == &vscsi_stats_bio_allocs_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->bio_count));
++	if (attr == &vscsi_stats_buf_allocs_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->buffers_allocated));
++	if (attr == &vscsi_stats_errors_attr)
++		return sprintf(buf, "%d\n", 
++		 atomic_read(&adapter->errors));
++	
++	BUG();
++	return 0;
++}
++
++static struct sysfs_ops vscsi_stats_ops = {
++	.show   = vscsi_stats_show,
++	.store  = NULL,
++};
++
++static struct kobj_type ktype_vscsi_stats = {
++	.release        = NULL,
++	.sysfs_ops      = &vscsi_stats_ops, 
++	.default_attrs  = vscsi_stats_attrs,
++};
++
++
++static int ibmvscsis_probe(struct vio_dev *dev, const struct vio_device_id *id)
++{
++	struct server_adapter *adapter;
++	int rc;
++	unsigned int *dma_window;
++	unsigned int dma_window_property_size;
++
++	adapter = kmalloc(sizeof(*adapter), GFP_KERNEL);
++	if (!adapter) {
++		err("couldn't allocate adapter memory\n");
++		return -1;
++	}
++	memset(adapter, 0x00, sizeof(*adapter));
++	adapter->dma_dev = dev;
++	adapter->dev = &dev->dev;
++	dev->driver_data = adapter;
++	sprintf(adapter->name, "%x", dev->unit_address);
++	adapter->lock = SPIN_LOCK_UNLOCKED;
++
++	dma_window =
++	    (unsigned int *)vio_get_attribute(dev, "ibm,my-dma-window",
++					      &dma_window_property_size);
++	if (!dma_window) {
++		warn("Couldn't find ibm,my-dma-window property\n");
++	}
++
++	adapter->liobn = dma_window[0];
++	/* RPA docs say that #address-cells is always 1 for virtual
++	   devices, but some older boxes' OF returns 2.  This should
++	   be removed by GA, unless there is legacy OFs that still
++	   have 2 or 3 for #address-cells */
++	/*adapter->riobn = dma_window[2+vio_num_address_cells]; */
++
++	/* This is just an ugly kludge. Remove as soon as the OF for all
++	   machines actually follow the spec and encodes the offset field
++	   as phys-encode (that is, #address-cells wide) */
++	if (dma_window_property_size == 24) {
++		adapter->riobn = dma_window[3];
++	} else if (dma_window_property_size == 40) {
++		adapter->riobn = dma_window[5];
++	} else {
++		warn("Invalid size of ibm,my-dma-window=%i\n",
++		     dma_window_property_size);
++	}
++
++	INIT_WORK(&adapter->crq_task, crq_task, adapter);
++
++	tasklet_init(&adapter->endio_tasklet,
++		     endio_task, (unsigned long)adapter);
++
++	INIT_LIST_HEAD(&adapter->inflight);
++
++	/* Initialize the buffer cache */
++	init_data_buffer(adapter);
++
++	/* Arbitrarily support 16 IUs right now */
++	rc = initialize_iu_pool(adapter, 16);
++	if (rc) {
++		kfree(adapter);
++		return rc;
++	}
++
++	rc = initialize_crq_queue(&adapter->queue, adapter);
++	if (rc != 0) {
++		kfree(adapter);
++		return rc;
++	}
++
++	set_num_buses(&dev->dev, 1);
++	device_create_file(&dev->dev, &dev_attr_num_buses);
++
++	adapter->stats_kobj.parent = &dev->dev.kobj;
++	strcpy(adapter->stats_kobj.name, "stats");
++	adapter->stats_kobj.ktype = & ktype_vscsi_stats;
++	kobject_register(&adapter->stats_kobj);
++
++	return 0;
++}
++
++static int ibmvscsis_remove(struct vio_dev *dev)
++{
++	int bus;
++	int target;
++	unsigned long flags;
++	struct server_adapter *adapter =
++	    (struct server_adapter *)dev->driver_data;
++
++	spin_lock_irqsave(&adapter->lock, flags);
++
++	/* 
++	 * Loop through the bus
++	 */
++	for (bus = 0; bus < BUS_PER_ADAPTER; bus++) {
++		/* If this bus exists */
++		if (adapter->vbus[bus]) {
++			/* loop through the targets */
++			for (target = 0; target < TARGETS_PER_BUS; target++) {
++				/* If the target exists */
++				if (adapter->vbus[bus]->vdev[target] &&
++				    !adapter->vbus[bus]->vdev[target]
++				     ->disabled) {
++					deactivate_block_device(adapter->
++					 vbus[bus]->vdev[target]);
++				}
++			}
++			spin_unlock_irqrestore(&adapter->lock, flags);
++			set_num_targets(adapter->vbus[bus], 0);
++			spin_lock_irqsave(&adapter->lock, flags);
++		}
++	}
++
++	spin_unlock_irqrestore(&adapter->lock, flags);
++	set_num_buses(adapter->dev, 0);
++	release_crq_queue(&adapter->queue, adapter);
++
++	release_iu_pool(adapter);
++
++	release_data_buffer(adapter);
++
++	kobject_unregister(&adapter->stats_kobj);
++	device_remove_file(&dev->dev, &dev_attr_num_buses);
++
++	kfree(adapter);
++
++	return 0;
++}
++
++static struct vio_device_id ibmvscsis_device_table[] __devinitdata = {
++	{"v-scsi-host", "IBM,v-scsi-host"},
++	{0,}
++};
++
++MODULE_DEVICE_TABLE(vio, ibmvscsis_device_table);
++
++static struct vio_driver ibmvscsis_driver = {
++	.name = "ibmvscsis",
++	.id_table = ibmvscsis_device_table,
++	.probe = ibmvscsis_probe,
++	.remove = ibmvscsis_remove,
++};
++
++static int mod_init(void)
++{
++	struct device_node *rootdn;
++	char *ppartition_name;
++	char *psystem_id;
++	char *pmodel;
++	unsigned int *p_number_ptr;
++	int rc;
++
++	/* Retrieve information about this partition */
++	rootdn = find_path_device("/");
++	if (rootdn) {
++		pmodel = get_property(rootdn, "model", NULL);
++		psystem_id = get_property(rootdn, "system-id", NULL);
++		if (pmodel && psystem_id) 
++			snprintf(system_id,sizeof(system_id),
++				 "%s-%s",
++				 pmodel, psystem_id);
++		ppartition_name =
++			get_property(rootdn, "ibm,partition-name", NULL);
++		if (ppartition_name)
++			strncpy(partition_name, ppartition_name,
++				sizeof(partition_name));
++		p_number_ptr =
++			(unsigned int *)get_property(rootdn, "ibm,partition-no",
++						     NULL);
++		if (p_number_ptr)
++			partition_number = *p_number_ptr;
++	}
++
++	info("initialized version "IBMVSCSIS_VERSION"\n");
++
++	rc = vio_register_driver(&ibmvscsis_driver);
++
++	if (rc) {
++		warn("rc %d from vio_register_driver\n", rc);
++	}
++
++	return rc;
++}
++
++static void mod_exit(void)
++{
++	info("terminated\n");
++
++	vio_unregister_driver(&ibmvscsis_driver);
++}
++
++module_init(mod_init);
++module_exit(mod_exit);
+diff -aurN a/include/asm-ppc64/vio.h b/include/asm-ppc64/vio.h
+--- a/include/asm-ppc64/vio.h	2005-06-17 15:48:29.000000000 -0400
++++ b/include/asm-ppc64/vio.h	2005-06-18 12:02:58.000000000 -0400
+@@ -91,6 +91,7 @@
+ 	char *type;
+ 	uint32_t unit_address;	
+ 	unsigned int irq;
++	void *driver_data;
+ 
+ 	struct device dev;
+ };

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-serial.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-serial.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/powerpc-serial.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,48 @@
+#! /bin/sh -e 
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Description: Disables legacy serial driver on powermacs.
+## DP: Patch author: Sven Luther <luther@debian.org> 
+## DP: Patch author: adapted from the SuSE kernel tree.
+## DP: Upstream status: workaround hack waiting for a clean legacy device solution.
+
+diff -aurN a/drivers/serial/8250.c b/drivers/serial/8250.c
+--- a/drivers/serial/8250.c	2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/serial/8250.c	2005-06-18 12:05:39.000000000 -0400
+@@ -46,6 +46,10 @@
+ 
+ #include "8250.h"
+ 
++#ifdef CONFIG_PPC_MULTIPLATFORM
++#include <asm/processor.h>
++#endif
++
+ /*
+  * Configuration:
+  *   share_irqs - whether we pass SA_SHIRQ to request_irq().  This option
+@@ -2188,6 +2192,12 @@
+ 
+ static int __init serial8250_console_init(void)
+ {
++#ifdef CONFIG_PPC_MULTIPLATFORM
++	if(_machine == _MACH_Pmac) {
++		printk("%s: nothing to do on PowerMac\n",__FUNCTION__);
++		return -ENODEV;
++	}
++#endif
+ 	serial8250_isa_init_ports();
+ 	register_console(&serial8250_console);
+ 	return 0;
+@@ -2491,6 +2501,12 @@
+ {
+ 	int ret, i;
+ 
++#ifdef CONFIG_PPC_MULTIPLATFORM
++	if(_machine == _MACH_Pmac) {
++		printk("%s: nothing to do on PowerMac\n",__FUNCTION__);
++		return -ENODEV;
++	}
++#endif
+ 	printk(KERN_INFO "Serial: 8250/16550 driver $Revision: 1.90 $ "
+ 		"%d ports, IRQ sharing %sabled\n", (int) UART_NR,
+ 		share_irqs ? "en" : "dis");

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/sparc64-hme-lockup.dpatch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/sparc64-hme-lockup.dpatch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/sparc64-hme-lockup.dpatch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,16 @@
+# origin: Debian (bcollins)
+# cset: n/a
+# inclusion: not suitable for upstream
+# revision date: 2004-10-08
+
+diff -aurN a/drivers/net/sunhme.c b/drivers/net/sunhme.c
+--- a/drivers/net/sunhme.c	2005-06-17 15:48:29.000000000 -0400
++++ b/drivers/net/sunhme.c	2005-06-18 12:12:18.000000000 -0400
+@@ -1996,6 +1996,7 @@
+ 	}
+ 	hp->tx_old = elem;
+ 	TXD((">"));
++	udelay(1);
+ 
+ 	if (netif_queue_stopped(dev) &&
+ 	    TX_BUFFS_AVAIL(hp) > (MAX_SKB_FRAGS + 1))

Added: trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/tty-locking-fixes9.patch
===================================================================
--- trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/tty-locking-fixes9.patch	2005-06-18 11:56:32 UTC (rev 3342)
+++ trunk/kernel/source/kernel-source-2.6.12-2.6.12/debian/patches/tty-locking-fixes9.patch	2005-06-18 16:17:44 UTC (rev 3343)
@@ -0,0 +1,12 @@
+--- kernel-source-2.6.11-2.6.11-orig/drivers/serial/serial_core.c	2005-03-02 08:37:50.000000000 +0100
++++ kernel-source-2.6.11-2.6.11/drivers/serial/serial_core.c	2005-03-05 10:46:43.417109240 +0100
+@@ -108,7 +108,8 @@
+ static void uart_tasklet_action(unsigned long data)
+ {
+ 	struct uart_state *state = (struct uart_state *)data;
+-	tty_wakeup(state->info->tty);
++	if (state->info->tty)
++		tty_wakeup(state->info->tty);
+ }
+ 
+ static inline void