[SCSI] fusion - Greater than 255 target and lun support

Add support for greater than 255 target and luns.
Kill the hd->Target[] field, and change all references
of bus_id/target_id, to channel/id.

Signed-off-by: Eric Moore <Eric.Moore@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
diff --git a/drivers/message/fusion/mptspi.c b/drivers/message/fusion/mptspi.c
index 203c661..aec0c2f 100644
--- a/drivers/message/fusion/mptspi.c
+++ b/drivers/message/fusion/mptspi.c
@@ -95,25 +95,76 @@
 static int	mptspiTaskCtx = -1;
 static int	mptspiInternalCtx = -1; /* Used only for internal commands */
 
+
+/**
+ *	mptspi_is_raid - Determines whether target is belonging to volume
+ *	@hd: Pointer to a SCSI HOST structure
+ *	@id: target device id
+ *
+ *	Return:
+ *		non-zero = true
+ *		zero = false
+ *
+ */
+static int
+mptspi_is_raid(struct _MPT_SCSI_HOST *hd, u32 id)
+{
+	int i, rc = 0;
+
+	if (!hd->ioc->raid_data.pIocPg2)
+		goto out;
+
+	if (!hd->ioc->raid_data.pIocPg2->NumActiveVolumes)
+		goto out;
+	for (i=0; i < hd->ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
+		if (hd->ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id) {
+			rc = 1;
+			goto out;
+		}
+	}
+
+ out:
+	return rc;
+}
+
 static int mptspi_target_alloc(struct scsi_target *starget)
 {
 	struct Scsi_Host *shost = dev_to_shost(&starget->dev);
 	struct _MPT_SCSI_HOST *hd = (struct _MPT_SCSI_HOST *)shost->hostdata;
-	int ret;
+	VirtTarget		*vtarget;
 
 	if (hd == NULL)
 		return -ENODEV;
 
-	ret = mptscsih_target_alloc(starget);
-	if (ret)
-		return ret;
+	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
+	if (!vtarget)
+		return -ENOMEM;
 
-	/* if we're a device on virtual channel 1 and we're not part
-	 * of an array, just return here (otherwise the setup below
-	 * may actually affect a real physical device on channel 0 */
-	if (starget->channel == 1 &&
-	    mptscsih_raid_id_to_num(hd, starget->id) < 0)
-		return 0;
+	vtarget->ioc_id = hd->ioc->id;
+	vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
+	vtarget->id = (u8)starget->id;
+	vtarget->channel = (u8)starget->channel;
+	vtarget->starget = starget;
+	starget->hostdata = vtarget;
+
+	if (starget->channel == 1) {
+		if (mptscsih_is_phys_disk(hd->ioc, 0, starget->id) == 0)
+			return 0;
+		vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
+		/* The real channel for this device is zero */
+		vtarget->channel = 0;
+		/* The actual physdisknum (for RAID passthrough) */
+		vtarget->id = mptscsih_raid_id_to_num(hd->ioc, 0,
+		    starget->id);
+	}
+
+	if (starget->channel == 0 &&
+	    mptspi_is_raid(hd, starget->id)) {
+		vtarget->raidVolume = 1;
+		ddvprintk((KERN_INFO
+		    "RAID Volume @ channel=%d id=%d\n", starget->channel,
+		    starget->id));
+	}
 
 	if (hd->ioc->spi_data.nvram &&
 	    hd->ioc->spi_data.nvram[starget->id] != MPT_HOST_NVRAM_INVALID) {
@@ -132,6 +183,14 @@
 	return 0;
 }
 
+void
+mptspi_target_destroy(struct scsi_target *starget)
+{
+	if (starget->hostdata)
+		kfree(starget->hostdata);
+	starget->hostdata = NULL;
+}
+
 static int mptspi_read_spi_device_pg0(struct scsi_target *starget,
 			     struct _CONFIG_PAGE_SCSI_DEVICE_0 *pass_pg0)
 {
@@ -147,7 +206,7 @@
 
 	/* No SPI parameters for RAID devices */
 	if (starget->channel == 0 &&
-	    (hd->ioc->raid_data.isRaid & (1 << starget->id)))
+	    mptspi_is_raid(hd, starget->id))
 		return -1;
 
 	size = ioc->spi_data.sdp0length * 4;
@@ -233,7 +292,7 @@
 }
 
 static int
-mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, int disk)
+mptscsih_quiesce_raid(MPT_SCSI_HOST *hd, int quiesce, u8 channel, u8 id)
 {
 	MpiRaidActionRequest_t	*pReq;
 	MPT_FRAME_HDR		*mf;
@@ -253,8 +312,8 @@
 	pReq->Reserved1 = 0;
 	pReq->ChainOffset = 0;
 	pReq->Function = MPI_FUNCTION_RAID_ACTION;
-	pReq->VolumeID = disk;
-	pReq->VolumeBus = 0;
+	pReq->VolumeID = id;
+	pReq->VolumeBus = channel;
 	pReq->PhysDiskNum = 0;
 	pReq->MsgFlags = 0;
 	pReq->Reserved2 = 0;
@@ -263,8 +322,8 @@
 	mpt_add_sge((char *)&pReq->ActionDataSGE,
 		MPT_SGE_FLAGS_SSIMPLE_READ | 0, (dma_addr_t) -1);
 
-	ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action %x id %d\n",
-			hd->ioc->name, action, io->id));
+	ddvprintk((MYIOC_s_INFO_FMT "RAID Volume action=%x channel=%d id=%d\n",
+			hd->ioc->name, pReq->Action, channel, id));
 
 	hd->pLocal = NULL;
 	hd->timer.expires = jiffies + HZ*10; /* 10 second timeout */
@@ -292,12 +351,12 @@
 
 	/* no DV on RAID devices */
 	if (sdev->channel == 0 &&
-	    (hd->ioc->raid_data.isRaid & (1 << sdev->id)))
+	    mptspi_is_raid(hd, sdev->id))
 		return;
 
 	/* If this is a piece of a RAID, then quiesce first */
 	if (sdev->channel == 1 &&
-	    mptscsih_quiesce_raid(hd, 1, vtarget->target_id) < 0) {
+	    mptscsih_quiesce_raid(hd, 1, vtarget->channel, vtarget->id) < 0) {
 		starget_printk(KERN_ERR, scsi_target(sdev),
 			       "Integrated RAID quiesce failed\n");
 		return;
@@ -306,7 +365,7 @@
 	spi_dv_device(sdev);
 
 	if (sdev->channel == 1 &&
-	    mptscsih_quiesce_raid(hd, 0, vtarget->target_id) < 0)
+	    mptscsih_quiesce_raid(hd, 0, vtarget->channel, vtarget->id) < 0)
 		starget_printk(KERN_ERR, scsi_target(sdev),
 			       "Integrated RAID resume failed\n");
 
@@ -317,33 +376,32 @@
 
 static int mptspi_slave_alloc(struct scsi_device *sdev)
 {
-	int ret;
 	MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *)sdev->host->hostdata;
-	/* gcc doesn't see that all uses of this variable occur within
-	 * the if() statements, so stop it from whining */
-	int physdisknum = 0;
+	VirtTarget		*vtarget;
+	VirtDevice		*vdev;
+	struct scsi_target 	*starget;
 
-	if (sdev->channel == 1) {
-		physdisknum = mptscsih_raid_id_to_num(hd, sdev->id);
+	if (sdev->channel == 1 &&
+		mptscsih_is_phys_disk(hd->ioc, 0, sdev->id) == 0)
+			return -ENXIO;
 
-		if (physdisknum < 0)
-			return physdisknum;
+	vdev = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
+	if (!vdev) {
+		printk(MYIOC_s_ERR_FMT "slave_alloc kmalloc(%zd) FAILED!\n",
+				hd->ioc->name, sizeof(VirtDevice));
+		return -ENOMEM;
 	}
 
-	ret = mptscsih_slave_alloc(sdev);
+	vdev->lun = sdev->lun;
+	sdev->hostdata = vdev;
 
-	if (ret)
-		return ret;
+	starget = scsi_target(sdev);
+	vtarget = starget->hostdata;
+	vdev->vtarget = vtarget;
+	vtarget->num_luns++;
 
-	if (sdev->channel == 1) {
-		VirtDevice *vdev = sdev->hostdata;
+	if (sdev->channel == 1)
 		sdev->no_uld_attach = 1;
-		vdev->vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
-		/* The real channel for this device is zero */
-		vdev->vtarget->bus_id = 0;
-		/* The actual physdisknum (for RAID passthrough) */
-		vdev->vtarget->target_id = physdisknum;
-	}
 
 	return 0;
 }
@@ -358,13 +416,35 @@
 		return ret;
 
 	if ((sdev->channel == 1 ||
-	     !(hd->ioc->raid_data.isRaid & (1 << sdev->id))) &&
+	     !(mptspi_is_raid(hd, sdev->id))) &&
 	    !spi_initial_dv(sdev->sdev_target))
 		mptspi_dv_device(hd, sdev);
 
 	return 0;
 }
 
+static int
+mptspi_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	struct _MPT_SCSI_HOST *hd = (MPT_SCSI_HOST *) SCpnt->device->host->hostdata;
+	VirtDevice	*vdev = SCpnt->device->hostdata;
+
+	if (!vdev || !vdev->vtarget) {
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+
+	if (SCpnt->device->channel == 1 &&
+		mptscsih_is_phys_disk(hd->ioc, 0, SCpnt->device->id) == 0) {
+		SCpnt->result = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+
+	return mptscsih_qcmd(SCpnt,done);
+}
+
 static void mptspi_slave_destroy(struct scsi_device *sdev)
 {
 	struct scsi_target *starget = scsi_target(sdev);
@@ -392,11 +472,11 @@
 	.proc_info			= mptscsih_proc_info,
 	.name				= "MPT SPI Host",
 	.info				= mptscsih_info,
-	.queuecommand			= mptscsih_qcmd,
+	.queuecommand			= mptspi_qcmd,
 	.target_alloc			= mptspi_target_alloc,
 	.slave_alloc			= mptspi_slave_alloc,
 	.slave_configure		= mptspi_slave_configure,
-	.target_destroy			= mptscsih_target_destroy,
+	.target_destroy			= mptspi_target_destroy,
 	.slave_destroy			= mptspi_slave_destroy,
 	.change_queue_depth 		= mptscsih_change_queue_depth,
 	.eh_abort_handler		= mptscsih_abort,
@@ -427,7 +507,7 @@
 
 	/* don't allow updating nego parameters on RAID devices */
 	if (starget->channel == 0 &&
-	    (hd->ioc->raid_data.isRaid & (1 << starget->id)))
+	    mptspi_is_raid(hd, starget->id))
 		return -1;
 
 	size = ioc->spi_data.sdp1length * 4;
@@ -672,9 +752,9 @@
 		if (sdev->channel != 1)
 			continue;
 
-		/* The target_id is the raid PhysDiskNum, even if
+		/* The id is the raid PhysDiskNum, even if
 		 * starget->id is the actual target address */
-		if(vtarget->target_id != disk)
+		if(vtarget->id != disk)
 			continue;
 
 		starget_printk(KERN_INFO, vtarget->starget,
@@ -727,7 +807,7 @@
 {
 	struct _MPT_SCSI_HOST *hd =
 		(struct _MPT_SCSI_HOST *)dev_to_shost(starget->dev.parent)->hostdata;
-	return ((hd->ioc->raid_data.isRaid & (1 << starget->id)) &&
+	return ((mptspi_is_raid(hd, starget->id)) &&
 		starget->channel == 0) ? 1 : 0;
 }
 
@@ -945,7 +1025,7 @@
 	 * max_lun = 1 + actual last lun,
 	 *	see hosts.h :o(
 	 */
-	sh->max_id = MPT_MAX_SCSI_DEVICES;
+	sh->max_id = ioc->devices_per_bus;
 
 	sh->max_lun = MPT_LAST_LUN + 1;
 	/*
@@ -1009,20 +1089,6 @@
 	dprintk((MYIOC_s_INFO_FMT "ScsiLookup @ %p\n",
 		 ioc->name, hd->ScsiLookup));
 
-	/* Allocate memory for the device structures.
-	 * A non-Null pointer at an offset
-	 * indicates a device exists.
-	 * max_id = 1 + maximum id (hosts.h)
-	 */
-	hd->Targets = kcalloc(sh->max_id * (sh->max_channel + 1),
-			      sizeof(void *), GFP_ATOMIC);
-	if (!hd->Targets) {
-		error = -ENOMEM;
-		goto out_mptspi_probe;
-	}
-
-	dprintk((KERN_INFO "  vdev @ %p\n", hd->Targets));
-
 	/* Clear the TM flags
 	 */
 	hd->tmPending = 0;