patch-2.4.21 linux-2.4.21/drivers/scsi/megaraid.c

Next file: linux-2.4.21/drivers/scsi/megaraid.h
Previous file: linux-2.4.21/drivers/scsi/mac_scsi.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.20/drivers/scsi/megaraid.c linux-2.4.21/drivers/scsi/megaraid.c
@@ -2,14 +2,14 @@
  *
  *                    Linux MegaRAID device driver
  *
- * Copyright 2001  American Megatrends Inc.
+ * Copyright 2001  LSI Logic Corporation.
  *
  *              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.
  *
- * Version : v1.18 (Oct 11, 2001)
+ * Version : v1.18f (Dec 10, 2002)
  *
  * Description: Linux device driver for LSI Logic MegaRAID controller
  *
@@ -459,6 +459,58 @@
  *
  * References to AMI have been changed to LSI Logic.
  *
+ * Version 1.18a
+ * Mon Mar 11 11:38:38 EST 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * RAID On MotherBoard (ROMB) - boot from logical or physical drives
+ *
+ * Support added for discovery(ROMB) vendor and device ids.
+ *
+ * Data transfer length for passthru commands must be valid even if the
+ * command has an associated scatter-gather list.
+ *
+ *
+ * Version 1.18b
+ * Tue Apr 23 11:01:58 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * typo corrected for scsi condition CHECK_CONDITION in mega_cmd_done()
+ *
+ * Support added for PCI_VENDOR_ID_LSI_LOGIC with device id
+ * PCI_DEVICE_ID_AMI_MEGARAID3.
+ *
+ *
+ * Version 1.18c
+ * Thu May 16 10:27:55 EDT 2002 - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * Retrun valid return status for mega passthru commands resulting in
+ * contingent allegiance condition. Check for 64-bit passthru commands also.
+ *
+ * Do not check_region() anymore and check for return value of
+ * request_region()
+ *
+ * Send valid sense data to appliations using the private ioctl interface.
+ *
+ *
+ * Version 1.18d
+ * Wed Aug  7 18:51:51 EDT 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Added support for yellowstone and verde controller
+ *
+ * Version 1.18e
+ * Mon Nov 18 12:11:02 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * Don't use virt_to_bus in mega_register_mailbox when you've got the DMA
+ * address already. Submitted by Jens Axboe and is included in SuSE Linux
+ * Enterprise Server 7.
+ *
+ * s/pcibios_read_config/pci_read_config - Matt Domsch <mdomsch@dell.com>
+ *
+ * remove an unsed variable
+ *
+ * Version 1.18f
+ * Tue Dec 10 09:54:39 EST 2002 - Atul Mukker <atul.mukker@lsil.com>
+ *
+ * remove GFP_DMA flag for ioctl. This was causing overrun of DMA buffers.
  *
  * BUGS:
  *     Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
@@ -772,7 +824,7 @@
 static struct mcontroller mcontroller[MAX_CONTROLLERS];
 
 /* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 0x118C;
 
 /* major number used by the device for character interface */
 static int major;
@@ -795,8 +847,7 @@
 extern struct proc_dir_entry proc_root;
 #endif
 
-static char mega_ch_class;	/* channels are raid or scsi */
-#define	IS_RAID_CH(ch)	( (mega_ch_class >> (ch)) & 0x01 )
+#define	IS_RAID_CH(this, ch)	( (this->mega_ch_class >> (ch)) & 0x01 )
 
 #if SERDEBUG
 static char strbuf[MAX_SERBUF + 1];
@@ -1076,11 +1127,14 @@
 		panic(KERN_ERR "megaraid:Problem...!\n");
 	}
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (SCpnt->channel == megaCfg->host->max_channel);
 #endif
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Special Case to handle PassThrough->XferAddrress > 4GB */
@@ -1117,7 +1171,7 @@
 			status = 0xF0;
 		}
 #endif
-		if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+		if(IS_RAID_CH(megaCfg, SCpnt->channel) && ((c & 0x1F) == TYPE_DISK)) {
 			status = 0xF0;
 		}
 	}
@@ -1126,7 +1180,7 @@
 	/* clear result; otherwise, success returns corrupt value */
 	SCpnt->result = 0;
 
-	if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
+	if ( 0 && SCpnt->cmnd[0] & M_RD_IOCTL_CMD ) {	/* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
 		switch (status) {
 		case 2:
 		case 0xF0:
@@ -1146,18 +1200,21 @@
 		case 0x02:	/* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
 
 			/*set sense_buffer and result fields */
-			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
+			if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU || mbox->cmd ==
+							MEGA_MBOXCMD_PASSTHRU64 ) {
+
 				memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				memcpy(
-					SCpnt->sense_buffer,
-					epthru->reqsensearea, 14
-				);
-				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
-				/*SCpnt->result =
-					(DRIVER_SENSE << 24) |
-					(DID_ERROR << 16) | status;*/
+
+				memcpy( SCpnt->sense_buffer, epthru->reqsensearea, 14);
+
+				SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+
 			} else {
 				SCpnt->sense_buffer[0] = 0x70;
 				SCpnt->sense_buffer[2] = ABORTED_COMMAND;
@@ -1204,8 +1261,10 @@
 	mega_ext_passthru *epthru;
 	long seg;
 	char islogical;
-	int lun = SCpnt->lun;
-	int		max_lun;
+	int		max_ldrv_num;
+	int		channel = 0;
+	int		target = 0;
+	int		ldrv_num = 0;	/* logical drive number */
 
 	if ((SCpnt->cmnd[0] == MEGADEVIOC))
 		return megadev_doioctl (megaCfg, SCpnt);
@@ -1222,15 +1281,61 @@
 	}
 #endif
 
+#if 0
 	islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
 					(SCpnt->channel <= megaCfg->host->max_channel) );
+#endif
 #if 0
 	islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
 						(SCpnt->channel == megaCfg->host->max_channel));
 #endif
 
+	/*
+	 * We know on what channels are our logical drives - mega_findCard()
+	 */
+	islogical = megaCfg->logdrv_chan[SCpnt->channel];
+
+	/*
+	 * The theory: If physical drive is chosen for boot, all the physical
+	 * devices are exported before the logical drives, otherwise physical
+	 * devices are pushed after logical drives, in which case - Kernel sees
+	 * the physical devices on virtual channel which is obviously converted
+	 * to actual channel on the HBA.
+	 */
+	if( megaCfg->boot_pdrv_enabled ) {
+		if( islogical ) {
+			/* logical channel */
+			channel = SCpnt->channel - megaCfg->productInfo.SCSIChanPresent;
+		}
+		else {
+			channel = SCpnt->channel; /* this is physical channel */
+			target = SCpnt->target;
+
+			/*
+			 * boot from a physical disk, that disk needs to be exposed first
+			 * IF both the channels are SCSI, then booting from the second
+			 * channel is not allowed.
+			 */
+			if( target == 0 ) {
+				target = megaCfg->boot_pdrv_tgt;
+			}
+			else if( target == megaCfg->boot_pdrv_tgt ) {
+				target = 0;
+			}
+		}
+	}
+	else {
+		if( islogical ) {
+			channel = SCpnt->channel; /* this is the logical channel */
+		}
+		else {
+			channel = SCpnt->channel - NVIRT_CHAN;	/* physical channel */
+			target = SCpnt->target;
+		}
+	}
+
 	if ( ! megaCfg->support_ext_cdb ) {
-		if (!islogical && lun != 0) {
+		if (!islogical && SCpnt->lun != 0) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
@@ -1252,39 +1357,26 @@
 			return NULL;
 		}
 
-		lun = mega_get_lun(megaCfg, SCpnt);
+		ldrv_num = mega_get_ldrv_num(megaCfg, SCpnt, channel);
 
-	    max_lun = (megaCfg->flag & BOARD_40LD) ?
+	    max_ldrv_num = (megaCfg->flag & BOARD_40LD) ?
 						FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
 
 		 /*
-		  * max_lun increases by 0x80 if some logical drive was deleted.
+		  * max_ldrv_num increases by 0x80 if some logical drive was deleted.
 		  */
 		if(megaCfg->read_ldidmap) {
-			max_lun += 0x80;
+			max_ldrv_num += 0x80;
 		}
 
-		if( lun > max_lun ) {
+		if( ldrv_num > max_ldrv_num ) {
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
 			return NULL;
 		}
 
-		/*
-		 * If we have a logical drive with boot enabled, project it first
-		 */
-		if( megaCfg->boot_ldrv_enabled ) {
-			if( lun == 0 ) {
-				lun = megaCfg->boot_ldrv;
-			}
-			else {
-				if( lun <= megaCfg->boot_ldrv ) {
-					lun--;
-				}
-			}
-		}
 	} else {
-		if ( lun > 7) {
+		if ( SCpnt->lun > 7) {
 				/* Do not support lun >7 for physically accessed devices */
 			SCpnt->result = (DID_BAD_TARGET << 16);
 			callDone (SCpnt);
@@ -1312,6 +1404,14 @@
 
 		case READ_CAPACITY:
 		case INQUIRY:
+			if(!(megaCfg->flag & (1L << SCpnt->channel))) {
+				printk(KERN_NOTICE
+					"scsi%d: scanning virtual channel %d for logical drives.\n",
+					megaCfg->host->host_no, channel);
+
+				megaCfg->flag |= (1L << SCpnt->channel);
+			}
+
 			/* Allocate a SCB and initialize passthru */
 			if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
 				SCpnt->result = (DID_ERROR << 16);
@@ -1331,7 +1431,7 @@
 			pthru->ars = 1;
 			pthru->reqsenselen = 14;
 			pthru->islogical = 1;
-			pthru->logdrv = lun;
+			pthru->logdrv = ldrv_num;
 			pthru->cdblen = SCpnt->cmd_len;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -1386,7 +1486,7 @@
 			mbox = (mega_mailbox *) & pScb->mboxData;
 
 			memset (mbox, 0, sizeof (pScb->mboxData));
-			mbox->logdrv = lun;
+			mbox->logdrv = ldrv_num;
 
 			if (megaCfg->flag & BOARD_64BIT) {
 				mbox->cmd = (*SCpnt->cmnd == READ_6
@@ -1410,12 +1510,12 @@
 				mbox->lba &= 0x1FFFFF;
 
 				if (*SCpnt->cmnd == READ_6) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1432,12 +1532,12 @@
 				    (u32) SCpnt->cmnd[5];
 
 				if (*SCpnt->cmnd == READ_10) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1457,12 +1557,12 @@
 				    (u32) SCpnt->cmnd[9];
 
 				if (*SCpnt->cmnd == READ_12) {
-					megaCfg->nReads[(int) lun]++;
-					megaCfg->nReadBlocks[(int) lun] +=
+					megaCfg->nReads[(int)ldrv_num]++;
+					megaCfg->nReadBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				} else {
-					megaCfg->nWrites[(int) lun]++;
-					megaCfg->nWriteBlocks[(int) lun] +=
+					megaCfg->nWrites[(int)ldrv_num]++;
+					megaCfg->nWriteBlocks[(int)ldrv_num] +=
 					    mbox->numsectors;
 				}
 			}
@@ -1516,7 +1616,8 @@
 		memset (mbox, 0, sizeof (pScb->mboxData));
 
 		if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
-			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+			epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt, channel,
+					target);
 			mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 			mbox->xferaddr = pScb->dma_ext_passthruhandle64;
@@ -1531,7 +1632,8 @@
 #endif
 		}
 		else {
-			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
+			pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt, channel,
+					target);
 
 			/* Initialize mailbox */
 			mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
@@ -1553,18 +1655,30 @@
 }
 
 static int
-mega_get_lun(mega_host_config *this_hba, Scsi_Cmnd *sc)
+mega_get_ldrv_num(mega_host_config *this_hba, Scsi_Cmnd *sc, int channel)
 {
 	int		tgt;
-	int		lun;
-	int		virt_chan;
+	int		ldrv_num;
 
 	tgt = sc->target;
 	
 	if ( tgt > 7 ) tgt--;	/* we do not get inquires for tgt 7 */
 
-	virt_chan = sc->channel - this_hba->productInfo.SCSIChanPresent;
-	lun = (virt_chan * 15) + tgt;
+	ldrv_num = (channel * 15) + tgt; /* 14 targets per channel */
+
+	/*
+	 * If we have a logical drive with boot enabled, project it first
+	 */
+	if( this_hba->boot_ldrv_enabled ) {
+		if( ldrv_num == 0 ) {
+			ldrv_num = this_hba->boot_ldrv;
+		}
+		else {
+			if( ldrv_num <= this_hba->boot_ldrv ) {
+				ldrv_num--;
+			}
+		}
+	}
 
 	/*
 	 * If "delete logical drive" feature is enabled on this controller.
@@ -1582,16 +1696,17 @@
 		case WRITE_6:	/* fall through */
 		case READ_10:	/* fall through */
 		case WRITE_10:
-			lun += 0x80;
+			ldrv_num += 0x80;
 		}
 	 }
 
-	 return lun;
+	 return ldrv_num;
 }
 
 
 static mega_passthru *
-mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc,
+		int channel, int target)
 {
 	mega_passthru *pthru;
 
@@ -1608,9 +1723,9 @@
 	pthru->ars = 1;
 	pthru->reqsenselen = 14;
 	pthru->islogical = 0;
-	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	pthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	pthru->cdblen = sc->cmd_len;
 	pthru->logdrv = sc->lun;
 
@@ -1624,6 +1739,15 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		pthru->numsgelements = 0;
 		pthru->dataxferaddr = scb->dma_bounce_buffer;
 		pthru->dataxferlen = sc->request_bufflen;
@@ -1647,7 +1771,8 @@
 }
 
 static mega_ext_passthru *
-mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb,
+		Scsi_Cmnd *sc, int channel, int target)
 {
 	mega_ext_passthru *epthru;
 
@@ -1664,9 +1789,9 @@
 	epthru->ars = 1;
 	epthru->reqsenselen = 14;
 	epthru->islogical = 0;
-	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+	epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : channel;
 	epthru->target = (megacfg->flag & BOARD_40LD) ?
-	    (sc->channel << 4) | sc->target : sc->target;
+	    (channel << 4) | target : target;
 	epthru->cdblen = sc->cmd_len;
 	epthru->logdrv = sc->lun;
 
@@ -1680,6 +1805,14 @@
 	switch (sc->cmnd[0]) {
 	case INQUIRY:
 	case READ_CAPACITY:
+		if(!(megacfg->flag & (1L << sc->channel))) {
+			printk(KERN_NOTICE
+				"scsi%d: scanning physical channel %d for devices.\n",
+				megacfg->host->host_no, channel);
+
+			megacfg->flag |= (1L << sc->channel);
+		}
+
 		epthru->numsgelements = 0;
 		epthru->dataxferaddr = scb->dma_bounce_buffer;
 		epthru->dataxferlen = sc->request_bufflen;
@@ -2240,7 +2373,6 @@
 			return 0;
 		}
 		udelay (100);
-		barrier ();
 	}
 	return -1;		/* give up after 1 second */
 }
@@ -2439,7 +2571,7 @@
 			scb->sg64List[0].address = scb->dma_h_bulkdata;
 			scb->sg64List[0].length = scb->SCpnt->request_bufflen;
 			*buffer = scb->dma_sghandle64;
-			*length = 0;
+			*length = (u32)scb->SCpnt->request_bufflen;
 			scb->sglist_count = 1;
 			return 1;
 		} else {
@@ -2520,7 +2652,15 @@
 #else
 	*buffer = virt_to_bus (scb->sgList);
 #endif
+
+#if 0
 	*length = 0;
+#endif
+	/*
+	 * For passthru command, dataxferlen must be set, even for commands with a
+	 * sg list
+	 */
+	*length = (u32)scb->SCpnt->request_bufflen;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	/* Return count of SG requests */
@@ -2743,12 +2883,7 @@
 		megaCfg->productInfo.SCSIChanPresent + NVIRT_CHAN -1;
 
 	megaCfg->host->max_id = 16;	/* max targets per channel */
-	/*(megaCfg->flag & BOARD_40LD)?FC_MAX_TARGETS_PER_CHANNEL:MAX_TARGET+1; */
-#if 0
-	megaCfg->host->max_lun =	/* max lun */
-	    (megaCfg->flag & BOARD_40LD) ?
-			FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
-#endif
+
 	megaCfg->host->max_lun = 7;	/* Upto 7 luns for non disk devices */
 
 	megaCfg->host->cmd_per_lun = MAX_CMD_PER_LUN;
@@ -2760,12 +2895,6 @@
 
 	megaCfg->host->can_queue = megaCfg->max_cmds - 1;
 
-#if 0
-	if (megaCfg->host->can_queue >= MAX_COMMANDS) {
-		megaCfg->host->can_queue = MAX_COMMANDS - 16;
-	}
-#endif
-
 	/* use HP firmware and bios version encoding */
 	if (megaCfg->productInfo.subSystemVendorID == HP_SUBSYS_ID) {
 		sprintf (megaCfg->fwVer, "%c%d%d.%d%d",
@@ -2833,7 +2962,7 @@
 	u32 magic64;
 #endif
 
-	int		i;
+	int		i, j;
 
 #if BITS_PER_LONG==64
 	u64 megaBase;
@@ -2863,20 +2992,27 @@
 		pciDevFun = pdev->devfn;
 #endif
 		if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
-			pcibios_read_config_word (pciBus, pciDevFun,
-						  PCI_CONF_AMISIG, &magic);
-			if ((magic != AMI_SIGNATURE)
-			    && (magic != AMI_SIGNATURE_471)) {
-				pciIdx++;
-				continue;	/* not an AMI board */
-			}
+				if( (pciVendor == PCI_VENDOR_ID_PERC4_DI_YSTONE &&
+					pciDev == PCI_DEVICE_ID_PERC4_DI_YSTONE) ||
+					(pciVendor == PCI_VENDOR_ID_PERC4_QC_VERDE &&
+					pciDev == PCI_DEVICE_ID_PERC4_QC_VERDE) ) {
+
+					flag |= BOARD_64BIT;
+				}
+				else {
+					pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
+					if ((magic != AMI_SIGNATURE)
+						&& (magic != AMI_SIGNATURE_471)) {
+						pciIdx++;
+						continue;	/* not an AMI board */
+					}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-			pcibios_read_config_dword (pciBus, pciDevFun,
-						   PCI_CONF_AMISIG64, &magic64);
+					pci_read_config_dword (pdev, PCI_CONF_AMISIG64, &magic64);
 
-			if (magic64 == AMI_64BIT_SIGNATURE)
-				flag |= BOARD_64BIT;
+					if (magic64 == AMI_64BIT_SIGNATURE)
+						flag |= BOARD_64BIT;
 #endif
+				}
 		}
 
 		/* Hmmm...Should we not make this more modularized so that in future we dont add
@@ -2898,24 +3034,15 @@
 					      PCI_SUBSYSTEM_ID, &subsysid);
 #endif
 
-#if 0
 			/*
-			 * This routine is called with well know values and we
-			 * should not be getting what we have not asked.
-			 * Also, the check is not right. It should have been for
-			 * pci_vendor_id not subsysvid - AM
-			 */
-
-			/* If we dont detect this valid subsystem vendor id's 
-			   we refuse to load the driver 
-			   PART of PC200X compliance
+			 * If we do not find the valid subsys vendor id, refuse to load
+			 * the driver. This is part of PCI200X compliance
 			 */
+			if( (subsysvid != AMI_SUBSYS_ID) &&
+					(subsysvid != DELL_SUBSYS_ID) &&
+					(subsysvid != LSI_SUBSYS_ID) &&
+					(subsysvid != HP_SUBSYS_ID) ) continue;
 
-			if ((subsysvid != AMI_SUBSYS_ID)
-			    && (subsysvid != DELL_SUBSYS_ID)
-			    && (subsysvid != HP_SUBSYS_ID))
-				continue;
-#endif
 		}
 
 		printk (KERN_NOTICE
@@ -3004,11 +3131,10 @@
 		megaCtlrs[numCtlrs] = megaCfg;
 
 		if (!(flag & BOARD_QUARTZ)) {
+
 			/* Request our IO Range */
-			if (!request_region(megaBase, 16, "megaraid")) {
-				printk(KERN_WARNING "megaraid: Couldn't register I/O range!\n");
+			if( !request_region(megaBase, 16, "megaraid") )
 				goto err_unregister;
-			}
 		}
 
 		/* Request our IRQ */
@@ -3031,9 +3157,7 @@
 					    sizeof (mega_mailbox64),
 					    &(megaCfg->dma_handle64));
 
-		mega_register_mailbox (megaCfg,
-				       virt_to_bus ((void *) megaCfg->
-						    mailbox64ptr));
+		mega_register_mailbox (megaCfg,megaCfg->dma_handle64);
 #else
 		mega_register_mailbox (megaCfg,
 				       virt_to_bus ((void *) &megaCfg->
@@ -3097,18 +3221,35 @@
 		 * Find out which channel is raid and which is scsi
 		 */
 		mega_enum_raid_scsi(megaCfg);
-		for( i = 0; i < megaCfg->productInfo.SCSIChanPresent; i++ ) {
-			if(IS_RAID_CH(i))
-				printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
-			else
-				printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
-		}
 
 		/*
 		 * Find out if a logical drive is set as the boot drive. If there is
 		 * one, will make that as the first logical drive.
+		 * ROMB: Do we have to boot from a physical drive. Then all the
+		 * physical drives would appear before the logical disks. Else, all
+		 * the physical drives would be exported to the mid layer after
+		 * logical disks.
 		 */
-		mega_get_boot_ldrv(megaCfg);
+		mega_get_boot_drv(megaCfg);
+
+		if( ! megaCfg->boot_pdrv_enabled ) {
+			for( i = 0; i < NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+
+			for( i = NVIRT_CHAN; i < MAX_CHANNEL + NVIRT_CHAN; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			megaCfg->mega_ch_class <<= NVIRT_CHAN;
+		}
+		else {
+			j = megaCfg->productInfo.SCSIChanPresent;
+			for( i = 0; i < j; i++ )
+				megaCfg->logdrv_chan[i] = 0;
+
+			for( i = j; i < NVIRT_CHAN + j; i++ )
+				megaCfg->logdrv_chan[i] = 1;
+		}
+
 
 		mega_hbas[numCtlrs].hostdata_addr = megaCfg;
 
@@ -3208,6 +3349,12 @@
 
 	memset (mega_hbas, 0, sizeof (mega_hbas));
 
+	/* Detect ROMBs first */
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_DISCOVERY,
+				PCI_DEVICE_ID_DISCOVERY, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_DI_YSTONE,
+				PCI_DEVICE_ID_PERC4_DI_YSTONE, BOARD_QUARTZ);
+	/* Then detect cards based on date they were produced, oldest first */
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID, 0);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
@@ -3216,6 +3363,10 @@
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
 	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
 				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_LSI_LOGIC,
+				PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+	count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_PERC4_QC_VERDE,
+				PCI_DEVICE_ID_PERC4_QC_VERDE, BOARD_QUARTZ);
 
 	mega_reorder_hosts ();
 
@@ -3366,7 +3517,7 @@
 /*
  * Find out what channels are RAID/SCSI
  */
-void
+static void
 mega_enum_raid_scsi(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
@@ -3401,16 +3552,16 @@
 	 * Non-ROMB firware fail this command, so all channels
 	 * must be shown RAID
 	 */
+	megacfg->mega_ch_class = 0xFF;
 	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
-		mega_ch_class = *((char *)megacfg->mega_buffer);
-
-		for( i = 0; i < NVIRT_CHAN; i++ ) {
-			/* logical drives channel is RAID */
-			mega_ch_class |= (0x01 << (megacfg->productInfo.SCSIChanPresent+i));
-		}
+		megacfg->mega_ch_class = *((char *)megacfg->mega_buffer);
 	}
-	else {
-		mega_ch_class = 0xFF;
+
+	for( i = 0; i < megacfg->productInfo.SCSIChanPresent; i++ ) {
+		if( (megacfg->mega_ch_class >> i) & 0x01 )
+			printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+		else
+			printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
 	}
 
 
@@ -3426,13 +3577,14 @@
  * get the boot logical drive number if enabled
  */
 void
-mega_get_boot_ldrv(mega_host_config *megacfg)
+mega_get_boot_drv(mega_host_config *megacfg)
 {
 	mega_mailbox *mboxp;
 	unsigned char mbox[16];
 	struct private_bios_data *prv_bios_data;
 	u16		cksum = 0;
-	char	*cksum_p;
+	u8		*cksum_p;
+	u8		boot_pdrv;
 	int		i;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
@@ -3459,19 +3611,35 @@
 
 	megacfg->boot_ldrv_enabled = 0;
 	megacfg->boot_ldrv = 0;
-	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 
+	megacfg->boot_pdrv_enabled = 0;
+	megacfg->boot_pdrv_ch = 0;
+	megacfg->boot_pdrv_tgt = 0;
+
+	if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
 		prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
 
 		cksum = 0;
-		cksum_p = (char *)prv_bios_data;
+		cksum_p = (u8 *)prv_bios_data;
 		for( i = 0; i < 14; i++ ) {
-			cksum += (u16)(*cksum_p++);
+			cksum += *cksum_p++;
 		}
 
 		if( prv_bios_data->cksum == (u16)(0-cksum) ) {
-			megacfg->boot_ldrv_enabled = 1;
-			megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+
+			/*
+			 * If MSB is set, a physical drive is set as boot device
+			 */
+			if( prv_bios_data->boot_drv & 0x80 ) {
+				megacfg->boot_pdrv_enabled = 1;
+				boot_pdrv = prv_bios_data->boot_drv & 0x7F;
+				megacfg->boot_pdrv_ch = boot_pdrv / 16;
+				megacfg->boot_pdrv_tgt = boot_pdrv % 16;
+			}
+			else {
+				megacfg->boot_ldrv_enabled = 1;
+				megacfg->boot_ldrv = prv_bios_data->boot_drv;
+			}
 		}
 	}
 
@@ -3681,7 +3849,7 @@
 	sprintf (buffer,
 		 "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns",
 		 megaCfg->fwVer, megaCfg->productInfo.MaxConcCmds,
-		 megaCfg->host->max_id, megaCfg->host->max_channel,
+		 megaCfg->host->max_id-1, megaCfg->host->max_channel,
 		 megaCfg->host->max_lun);
 	return buffer;
 }
@@ -3710,6 +3878,7 @@
 	megaCfg = (mega_host_config *) SCpnt->host->hostdata;
 	DRIVER_LOCK (megaCfg);
 
+#if 0
 	if (!(megaCfg->flag & (1L << SCpnt->channel))) {
 		if (SCpnt->channel < megaCfg->productInfo.SCSIChanPresent)
 			printk ( KERN_NOTICE
@@ -3723,6 +3892,7 @@
 
 		megaCfg->flag |= (1L << SCpnt->channel);
 	}
+#endif
 
 	SCpnt->scsi_done = pktComp;
 
@@ -4232,7 +4402,7 @@
 	/* Get pointer to host config structure */
 	megaCfg = (mega_host_config *) disk->device->host->hostdata;
 
-	if( IS_RAID_CH(disk->device->channel)) {
+	if( IS_RAID_CH(megaCfg, disk->device->channel)) {
 			/* Default heads (64) & sectors (32) */
 			heads = 64;
 			sectors = 32;
@@ -4297,7 +4467,15 @@
 	int heads, cyls, sectors;
 	int capacity = disk->capacity;
 
-	if(!(bh = bread(MKDEV(MAJOR(dev), MINOR(dev)&~0xf), 0, block_size(dev))))
+	int ma = MAJOR(dev);
+	int mi = (MINOR(dev) & ~0xf);
+
+	int block = 1024; 
+
+	if(blksize_size[ma])
+		block = blksize_size[ma][mi];
+		
+	if(!(bh = bread(MKDEV(ma,mi), 0, block)))
 		return -1;
 
 	if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
@@ -4626,9 +4804,10 @@
 			/*
 			 * Copy struct mcontroller to user area
 			 */
-			copy_to_user (ioc.data,
+			if (copy_to_user (ioc.data,
 				      mcontroller + adapno,
-				      sizeof (struct mcontroller));
+				      sizeof (struct mcontroller)))
+				      return -EFAULT;
 			return 0;
 
 		default:
@@ -4694,7 +4873,7 @@
 		if(shpnt == NULL)  return -ENODEV;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4716,19 +4895,18 @@
 
 			if( kvaddr == NULL ) {
 				printk(KERN_WARNING "megaraid:allocation failed\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)	/*0x20400 */
-				kfree(scsicmd);
-#else
-				scsi_init_free((char *)scsicmd, sizeof(Scsi_Cmnd));
-#endif
-				return -ENOMEM;
+				ret = -ENOMEM;
+				goto out;
 			}
 
 			ioc.ui.fcs.buffer = kvaddr;
 
 			if (inlen) {
 				/* copyin the user data */
-				copy_from_user(kvaddr, (char *)uaddr, length );
+				if (copy_from_user(kvaddr, (char *)uaddr, length )) {
+					ret = -EFAULT;
+					goto out;
+				}
 			}
 		}
 
@@ -4745,7 +4923,9 @@
 		down(&mimd_ioctl_sem);
 
 		if( !scsicmd->result && outlen ) {
-			copy_to_user(uaddr, kvaddr, length);
+			if (copy_to_user(uaddr, kvaddr, length))
+				ret = -EFAULT;
+				goto out;
 		}
 
 		/*
@@ -4755,12 +4935,16 @@
 
 		if( ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
 			put_user( scsicmd->result, &uioc->pthru.scsistatus );
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ))
+				ret= -EFAULT;
 		} else {
 			put_user(1, &uioc->mbox[16]);	/* numstatus */
 			/* status */
 			put_user (scsicmd->result, &uioc->mbox[17]);
 		}
 
+out:
 		if (kvaddr) {
 			dma_free_consistent(pdevp, length, kvaddr, dma_addr);
 		}
@@ -4836,7 +5020,7 @@
 		}
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL|GFP_DMA);
+		scsicmd = (Scsi_Cmnd *)kmalloc(sizeof(Scsi_Cmnd), GFP_KERNEL);
 #else
 		scsicmd = (Scsi_Cmnd *)scsi_init_malloc(sizeof(Scsi_Cmnd),
 							  GFP_ATOMIC | GFP_DMA);
@@ -4894,9 +5078,11 @@
 
 		if (!scsicmd->result && outlen) {
 			if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
-				copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen);
+				if (copy_to_user (uaddr, kvaddr, ioc.pthru.dataxferlen))	
+					ret = -EFAULT;
 			} else {
-				copy_to_user (uaddr, kvaddr, outlen);
+				if (copy_to_user (uaddr, kvaddr, outlen)) 
+					ret = -EFAULT;
 			}
 		}
 
@@ -4907,6 +5093,15 @@
 
 		if (ioc.mbox[0] == MEGA_MBOXCMD_PASSTHRU) {
 			put_user (scsicmd->result, &uioc->pthru.scsistatus);
+
+			/*
+			 * If scsicmd->result is 0x02 (CHECK CONDITION) then copy the
+			 * SCSI sense data into user area
+			 */
+			if (copy_to_user( uioc->pthru.reqsensearea, scsicmd->sense_buffer,
+							  MAX_REQ_SENSE_LEN ))
+				ret = -EFAULT;
+							
 		} else {
 			put_user (1, &uioc->mbox[16]);	/* numstatus */
 			put_user (scsicmd->result, &uioc->mbox[17]); /* status */
@@ -4995,7 +5190,7 @@
 			scb->sg64List[0].length = 4096;	// TODO: Check this
 			pthru->dataxferaddr = scb->dma_sghandle64;
 			pthru->numsgelements = 1;
-			mboxpthru->cmd = 0xC3;
+			mboxpthru->cmd = MEGA_MBOXCMD_PASSTHRU64;
 		} else {
 			mboxpthru->dataxferaddr = scb->dma_passthruhandle64;
 			pthru->dataxferaddr =
@@ -5189,8 +5384,6 @@
 		return rval;
 	}
 
-	printk("megaraid: logical drive %d deleted.\n", logdrv);
-
 	/*
 	 * After deleting first logical drive, the logical drives must be
 	 * addressed by adding 0x80 to the logical drive id.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)