patch-2.2.18 linux/drivers/scsi/megaraid.c
Next file: linux/drivers/scsi/megaraid.h
Previous file: linux/drivers/scsi/mac_scsi.h
Back to the patch index
Back to the overall index
- Lines: 1284
- Date:
Tue Nov 21 16:31:13 2000
- Orig file:
v2.2.17/drivers/scsi/megaraid.c
- Orig date:
Sun Jun 11 21:44:17 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/drivers/scsi/megaraid.c linux/drivers/scsi/megaraid.c
@@ -2,19 +2,19 @@
*
* Linux MegaRAID device driver
*
- * Copyright 1999 American Megatrends Inc.
+ * Copyright 2000 American Megatrends Inc.
*
* 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 : 1.07b
+ * Version : 1b08b
*
* Description: Linux device driver for AMI MegaRAID controller
*
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 490
- *
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
+ * 493.
* History:
*
* Version 0.90:
@@ -119,16 +119,67 @@
* Fixed the problem of unnecessary aborts in the abort entry point, which
* also enables the driver to handle large amount of I/O requests for
* long duration of time.
- *
+ * Version 1.06
+ * Intel Release
* Version 1.07
* Removed the usage of uaccess.h file for kernel versions less than
* 2.0.36, as this file is not present in those versions.
*
- * Version 1.07b
- * The MegaRAID 466 cards with 3.00 firmware lockup and seem to very
- * occasionally hang. We check such cards and report them. You can
- * get firmware upgrades to flash the board to 3.10 for free.
- *
+ * Version 108
+ * Modified mega_ioctl so that 40LD megamanager would run
+ * Made some changes for 2.3.XX compilation , esp wait structures
+ * Code merge between 1.05 and 1.06 .
+ * Bug fixed problem with ioctl interface for concurrency between
+ * 8ld and 40ld firwmare
+ * Removed the flawed semaphore logic for handling new config command
+ * Added support for building own scatter / gather list for big user
+ * mode buffers
+ * Added /proc file system support ,so that information is available in
+ * human readable format
+ *
+ * Version 1a08
+ * Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag
+ *
+ * Version 1b08
+ * Include file changes.
+ * Version 1b08b
+ * Change PCI ID value for the 471 card, use #defines when searching
+ * for megaraid cards.
+ *
+ * Version 1.10
+ *
+ * I) Changes made to make following ioctl commands work in 0x81 interface
+ * a)DCMD_DELETE_LOGDRV
+ * b)DCMD_GET_DISK_CONFIG
+ * c)DCMD_DELETE_DRIVEGROUP
+ * d)NC_SUBOP_ENQUIRY3
+ * e)DCMD_CHANGE_LDNO
+ * f)DCMD_CHANGE_LOOPID
+ * g)DCMD_FC_READ_NVRAM_CONFIG
+ * h)DCMD_WRITE_CONFIG
+ * II) Added mega_build_kernel_sg function
+ * III)Firmware flashing option
added
+ *
+ * Version 1.10a
+ *
+ * I)Dell updates included in the source code.
+ * Note: This change is not tested due to the unavailability of IA64 kernel
+ * and it is in the #ifdef DELL_MODIFICATION macro which is not defined
+ *
+ * Version 1.10b
+ *
+ * I)In IOCTL_CMD_NEW command the wrong way of copying the data
+ * to the user address corrected
+ *
+ * Version 1.10c
+ *
+ * I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes.
+ *
+ * Version 1.11
+ * I) Version number changed from 1.10c to 1.11
+ * II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from
+ * scatter/gather list mode to direct pointer mode..
+ *
* BUGS:
* Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
* fails to detect the controller as a pci device on the system.
@@ -143,8 +194,8 @@
#define CRLFSTR "\n"
#define IOCTL_CMD_NEW 0x81
-#define MEGARAID_VERSION "v107 (December 22, 1999)"
-
+#define MEGARAID_VERSION "v1.11 (Aug 23, 2000)"
+#define MEGARAID_IOCTL_VERSION 108
#include <linux/config.h>
#include <linux/version.h>
@@ -163,6 +214,7 @@
#include <linux/types.h>
#include <linux/errno.h>
+#include <linux/string.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
#include <linux/fcntl.h>
@@ -173,6 +225,9 @@
#include <linux/wait.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/kcomp.h>
+#include <asm/pgtable.h>
#include <linux/sched.h>
#include <linux/stat.h>
@@ -181,7 +236,11 @@
#if LINUX_VERSION_CODE < 0x20100
#include <linux/bios32.h>
#else
-#include <asm/spinlock.h>
+#if LINUX_VERSION_CODE < 0x20300
+# include <asm/spinlock.h>
+#else
+# include <linux/spinlock.h>
+#endif
#endif
#include <asm/io.h>
@@ -229,22 +288,22 @@
#define COM_BASE 0x2f8
-u32 RDINDOOR (mega_host_config * megaCfg)
+ulong RDINDOOR (mega_host_config * megaCfg)
{
return readl (megaCfg->base + 0x20);
}
-void WRINDOOR (mega_host_config * megaCfg, u32 value)
+void WRINDOOR (mega_host_config * megaCfg, ulong value)
{
writel (value, megaCfg->base + 0x20);
}
-u32 RDOUTDOOR (mega_host_config * megaCfg)
+ulong RDOUTDOOR (mega_host_config * megaCfg)
{
return readl (megaCfg->base + 0x2C);
}
-void WROUTDOOR (mega_host_config * megaCfg, u32 value)
+void WROUTDOOR (mega_host_config * megaCfg, ulong value)
{
writel (value, megaCfg->base + 0x2C);
}
@@ -276,7 +335,12 @@
#if LINUX_VERSION_CODE > 0x020100
+#if LINUX_VERSION_CODE < 0x20300
# include <asm/spinlock.h>
+# else
+# include <linux/spinlock.h>
+#endif
+
# include <linux/smp.h>
# define cpuid smp_processor_id()
# if LINUX_VERSION_CODE < 0x020195
@@ -329,6 +393,19 @@
static int ser_printk (const char *fmt,...);
#endif
+#ifdef CONFIG_PROC_FS
+#define COPY_BACK if (offset > megaCfg->procidx) { \
+ *eof = TRUE; \
+ megaCfg->procidx = 0; \
+ megaCfg->procbuf[0] = 0; \
+ return 0;} \
+ if ((count + offset) > megaCfg->procidx) { \
+ count = megaCfg->procidx - offset; \
+ *eof = TRUE; } \
+ memcpy(page, &megaCfg->procbuf[offset], count); \
+ megaCfg->procidx = 0; \
+ megaCfg->procbuf[0] = 0;
+#endif
/*================================================================
*
* Global variables
@@ -340,6 +417,8 @@
XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE
processor id cannot be scanned */
+
+
static char *megaraid;
#if LINUX_VERSION_CODE > 0x20100
#ifdef MODULE
@@ -350,6 +429,7 @@
static int numCtlrs = 0;
static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = {0};
+struct proc_dir_entry *mega_proc_dir_entry;
#if DEBUG
static u32 maxCmdTime = 0;
@@ -362,11 +442,20 @@
volatile static spinlock_t serial_lock;
#endif
+
+#if LINUX_VERSION_CODE < 0x20300
struct proc_dir_entry proc_scsi_megaraid =
{
PROC_SCSI_MEGARAID, 8, "megaraid",
S_IFDIR | S_IRUGO | S_IXUGO, 2
};
+#else
+struct proc_dir_entry *proc_scsi_megaraid;
+#endif
+
+#ifdef CONFIG_PROC_FS
+extern struct proc_dir_entry proc_root;
+#endif
#if SERDEBUG
static char strbuf[MAX_SERBUF + 1];
@@ -554,7 +643,7 @@
return 0;
}
-/* Run through the list of completed requests */
+/* Run through the list of completed requests and finish it*/
static void mega_rundoneq (mega_host_config *megaCfg)
{
Scsi_Cmnd *SCpnt;
@@ -597,6 +686,8 @@
mega_passthru *pthru;
mega_mailbox *mbox;
+
+
if (pScb == NULL) {
TRACE(("NULL pScb in mega_cmd_done!"));
printk("NULL pScb in mega_cmd_done!");
@@ -628,6 +719,7 @@
if ((SCpnt->cmnd[0] & 0x80) ) {/* i.e. ioctl cmd such as 0x80, 0x81 of megamgr*/
switch (status) {
+ case 2:
case 0xF0:
case 0xF4:
SCpnt->result=(DID_BAD_TARGET<<16)|status;
@@ -662,12 +754,7 @@
break;
}
}
- if ( SCpnt->cmnd[0]!=IOCTL_CMD_NEW )
- /* not IOCTL_CMD_NEW SCB, freeSCB()*/
- /* For IOCTL_CMD_NEW SCB, delay freeSCB() in megaraid_queue()
- * after copy data back to user space*/
mega_freeSCB(megaCfg, pScb);
-
/* Add Scsi_Command to end of completed queue */
if( megaCfg->qCompletedH == NULL ) {
megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
@@ -698,8 +785,8 @@
char islogical;
char lun = SCpnt->lun;
- if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) ) /* ioctl */
- return mega_ioctl (megaCfg, SCpnt);
+ if ((SCpnt->cmnd[0] == 0x80) || (SCpnt->cmnd[0] == IOCTL_CMD_NEW) )
+ return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */
islogical = (SCpnt->channel == megaCfg->host->max_channel);
@@ -715,7 +802,7 @@
return NULL;
}
- if ( islogical ) {
+ if (islogical) {
lun = (SCpnt->target * 8) + lun;
if ( lun > FC_MAX_LOGICAL_DRIVES ){
SCpnt->result = (DID_BAD_TARGET << 16);
@@ -797,6 +884,15 @@
((u32) SCpnt->cmnd[2] << 8) |
(u32) SCpnt->cmnd[3];
mbox->lba &= 0x1FFFFF;
+
+ if (*SCpnt->cmnd == READ_6) {
+ megaCfg->nReads[(int)lun]++;
+ megaCfg->nReadBlocks[(int)lun] += mbox->numsectors;
+ }
+ else {
+ megaCfg->nWrites[(int)lun]++;
+ megaCfg->nWriteBlocks[(int)lun] += mbox->numsectors;
+ }
}
/* 10-byte */
@@ -809,6 +905,15 @@
((u32) SCpnt->cmnd[3] << 16) |
((u32) SCpnt->cmnd[4] << 8) |
(u32) SCpnt->cmnd[5];
+
+ if (*SCpnt->cmnd == READ_10) {
+ megaCfg->nReads[(int)lun]++;
+ megaCfg->nReadBlocks[(int)lun] += mbox->numsectors;
+ }
+ else {
+ megaCfg->nWrites[(int)lun]++;
+ megaCfg->nWriteBlocks[(int)lun] += mbox->numsectors;
+ }
}
/* Calculate Scatter-Gather info */
@@ -865,6 +970,42 @@
return NULL;
}
+/* Handle Driver Level IOCTLs
+ * Return value of 0 indicates this function could not handle , so continue
+ * processing
+*/
+
+static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
+{
+ unsigned char *data = (unsigned char *)SCpnt->request_buffer;
+ mega_driver_info driver_info;
+
+ /* If this is not our command dont do anything */
+ if (SCpnt->cmnd[0] != DRIVER_IOCTL_INTERFACE)
+ return 0;
+
+ switch(SCpnt->cmnd[1]) {
+ case GET_DRIVER_INFO:
+ if (SCpnt->request_bufflen < sizeof(driver_info)) {
+ SCpnt->result = DID_BAD_TARGET << 16 ;
+ callDone(SCpnt);
+ return 1;
+ }
+
+ driver_info.size = sizeof(driver_info) - sizeof(int);
+ driver_info.version = MEGARAID_IOCTL_VERSION;
+ memcpy( data, &driver_info, sizeof(driver_info));
+ break;
+ default:
+ SCpnt->result = DID_BAD_TARGET << 16;
+ }
+
+ callDone(SCpnt);
+ return 1;
+}
+
+
+
/*--------------------------------------------------------------------
* build RAID commands for controller, passed down through ioctl()
*--------------------------------------------------------------------*/
@@ -875,9 +1016,9 @@
mega_mailbox *mailbox;
mega_passthru *pthru;
u8 *mboxdata;
- long seg;
+ long seg, i;
unsigned char *data = (unsigned char *)SCpnt->request_buffer;
- int i;
+
if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
SCpnt->result = (DID_ERROR << 16);
@@ -911,8 +1052,8 @@
(u32 *) & pthru->dataxferaddr,
(u32 *) & pthru->dataxferlen);
- for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) {
- data[i] = data[i+cdblen+7];
+ for (i = 0 ; i < (SCpnt->request_bufflen - cdblen - 7) ; i++) {
+ data[i] = data[i + cdblen + 7];
}
return pScb;
@@ -928,29 +1069,65 @@
*/
if (SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
- /* use external data area for large xfers */
+ /* use external data area for large xfers */
/* If cmnd[0] is set to IOCTL_CMD_NEW then *
* cmnd[4..7] = external user buffer *
* cmnd[8..11] = length of buffer *
* */
- char *kern_area;
char *user_area = *((char **)&SCpnt->cmnd[4]);
u32 xfer_size = *((u32 *)&SCpnt->cmnd[8]);
- if (verify_area(VERIFY_READ, user_area, xfer_size)) {
- printk("megaraid: Got bad user address.\n");
+ switch (data[0])
+ {
+ case FW_FIRE_WRITE:
+ case FW_FIRE_FLASH:
+ if ((ulong)user_area & (PAGE_SIZE - 1)) {
+ printk("megaraid:user address not aligned on 4K boundary.Error.\n");
+ SCpnt->result = (DID_ERROR << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+ break;
+ default:
+ break;
+ }
+ if(!(pScb->buff_ptr = kmalloc(xfer_size, GFP_KERNEL))) {
+ printk("megaraid: Insufficient mem for IOCTL_CMD_NEW.\n");
SCpnt->result = (DID_ERROR << 16);
callDone (SCpnt);
return NULL;
}
- kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA);
- if (kern_area == NULL) {
- printk("megaraid: Couldn't allocate kernel mem.\n");
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- copy_from_user(kern_area,user_area,xfer_size);
- pScb->kern_area = kern_area;
+
+ copy_from_user(pScb->buff_ptr,user_area,xfer_size);
+ pScb->sgList[0].address = virt_to_bus(pScb->buff_ptr);
+ pScb->sgList[0].length = xfer_size;
+ pScb->iDataSize = xfer_size;
+ mbox->xferaddr = virt_to_bus(pScb->sgList);
+ mbox->numsgelements = 1;
+
+ switch (data[0])
+ {
+ case DCMD_FC_CMD:
+ switch (data[1])
+ {
+ case DCMD_FC_READ_NVRAM_CONFIG:
+ case DCMD_GET_DISK_CONFIG:
+ {
+ if ((ulong) pScb->buff_ptr & (PAGE_SIZE - 1)) {
+ printk("megaraid:user address not sufficient Error.\n");
+ SCpnt->result = (DID_ERROR << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+ //building SG list
+ mega_build_kernel_sg(pScb->buff_ptr, xfer_size, pScb, mbox);
+ break;
+ }
+ default:
+ break;
+ }//switch (data[1])
+ break;
+ }
+
}
#endif
@@ -961,16 +1138,59 @@
mbox->logdrv = data[4];
if(SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
- if(data[0]==DCMD_FC_CMD){ /*i.e. 0xA1, then override some mbox data */
+ switch (data[0]) {
+ case FW_FIRE_WRITE:
+ mbox->cmd = FW_FIRE_WRITE;
+ mbox->channel = data[1]; /* Current Block Number */
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ case FW_FIRE_FLASH:
+ mbox->cmd = FW_FIRE_FLASH;
+ mbox->channel = data[1] | 0x80 ; /* Origin */
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ case DCMD_FC_CMD:
*(mboxdata+0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD*/
- *(mboxdata+2) = data[2]; /*sub command*/
- *(mboxdata+3) = 0; /*number of elements in SG list*/
- mbox->xferaddr /*i.e. mboxdata byte 0x8 to 0xb*/
- = virt_to_bus(pScb->kern_area);
- }
- else{
- mbox->xferaddr = virt_to_bus(pScb->kern_area);
- mbox->numsgelements = 0;
+ *(mboxdata+2) = data[1]; /*sub command*/
+ switch (data[1])
+ {
+ case DCMD_FC_READ_NVRAM_CONFIG:
+ *(mboxdata+3) = mbox->numsgelements; /*number of elements in SG list*/
+ break;
+ case DCMD_WRITE_CONFIG:
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ case DCMD_GET_DISK_CONFIG:
+ *(mboxdata+3) = data[2]; /*number of elements in SG list*/
+ *(mboxdata+4) = mbox->numsgelements; /*number of elements in SG list*/
+ break;
+ case DCMD_DELETE_LOGDRV:
+ case DCMD_DELETE_DRIVEGROUP:
+ case NC_SUBOP_ENQUIRY3:
+ *(mboxdata+3) = data[2];
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ case DCMD_CHANGE_LDNO:
+ case DCMD_CHANGE_LOOPID:
+ *(mboxdata+3) = data[2];
+ *(mboxdata+4) = data[3];
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ default:
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
+ }//switch
+ break;
+ default:
+ mbox->xferaddr = virt_to_bus(pScb->buff_ptr);
+ mbox->numsgelements = 0;
+ break;
}
}
else {
@@ -987,6 +1207,37 @@
return (pScb);
}
+void mega_build_kernel_sg(char *barea, ulong xfersize, mega_scb *pScb,
+ mega_ioctl_mbox *mbox)
+{
+ ulong i, buffer_area, len, end, end_page, x, idx = 0;
+
+ buffer_area = (ulong)barea;
+ i = buffer_area;
+ end = buffer_area + xfersize;
+ end_page = (end) & ~(PAGE_SIZE - 1);
+
+ do {
+ len = PAGE_SIZE - (i % PAGE_SIZE);
+ x = pScb->sgList[idx].address = virt_to_bus((volatile void *)i);
+ pScb->sgList[idx].length = len;
+ i += len;
+ idx++;
+ } while (i < end_page);
+
+ if ((end - i)< 0) {
+ printk("megaraid:Error in user address\n");
+ }
+
+ if (end - i) {
+ pScb->sgList[idx].address = virt_to_bus((volatile void *)i);
+ pScb->sgList[idx].length = end - i;
+ idx++;
+ }
+ mbox->xferaddr = virt_to_bus(pScb->sgList);
+ mbox->numsgelements = idx;
+}
+
#if DEBUG
static void showMbox(mega_scb *pScb)
{
@@ -1065,7 +1316,7 @@
#if LINUX_VERSION_CODE >= 0x20100
IO_LOCK;
#endif
-
+ megaCfg->nInterrupts++;
qCnt = 0xff;
while ((qCnt = megaCfg->mbox->numstatus) == 0xFF)
;
@@ -1135,17 +1386,21 @@
continue;
}
- if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW)
- { /* external user buffer */
- up(&pScb->sem);
- }
- /* Mark command as completed */
- mega_cmd_done(megaCfg, pScb, qStatus);
-
+ /* We don't want the ISR routine to touch IOCTL_CMD_NEW commands, so
+ * don't mark them as complete, instead we pop their semaphore so
+ * that the queue routine can finish them off
+ */
+ if(pScb->SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+ /* save the status byte for the queue routine to use */
+ pScb->SCpnt->result = qStatus;
+ up(&pScb->ioctl_sem);
+ } else {
+ /* Mark command as completed */
+ mega_cmd_done(megaCfg, pScb, qStatus);
+ }
}
else {
printk("megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx);
- for(;;);
}
}
@@ -1200,19 +1455,23 @@
mega_scb * pScb,
int intr)
{
- mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
+ volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
u_char byte;
- u32 cmdDone;
+
+#ifdef __LP64__
+ u64 phys_mbox;
+#else
u32 phys_mbox;
+#endif
u8 retval=-1;
- mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */
+ mboxData[0x1] = (pScb ? pScb->idx + 1: 0xFE); /* Set cmdid */
mboxData[0xF] = 1; /* Set busy */
phys_mbox = virt_to_bus (megaCfg->mbox);
#if DEBUG
- showMbox(pScb);
+ ShowMbox(pScb);
#endif
/* Wait until mailbox is free */
@@ -1237,7 +1496,7 @@
/* Copy mailbox data into host structure */
megaCfg->mbox64->xferSegment = 0;
- memcpy (mbox, mboxData, 16);
+ memcpy ((char *)mbox, mboxData, 16);
/* Kick IO */
if (intr) {
@@ -1261,10 +1520,18 @@
if (megaCfg->flag & BOARD_QUARTZ) {
mbox->mraid_poll = 0;
mbox->mraid_ack = 0;
+ mbox->numstatus = 0xFF;
+ mbox->status = 0xFF;
WRINDOOR (megaCfg, phys_mbox | 0x1);
- while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
- WROUTDOOR (megaCfg, cmdDone);
+ while (mbox->numstatus == 0xFF);
+ while (mbox->status == 0xFF);
+ while (mbox->mraid_poll != 0x77);
+ mbox->mraid_poll = 0;
+ mbox->mraid_ack = 0x77;
+
+ /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
+ WROUTDOOR (megaCfg, cmdDone);*/
if (pScb) {
mega_cmd_done (megaCfg, pScb, mbox->status);
@@ -1361,9 +1628,15 @@
{
/* align on 16-byte boundry */
megaCfg->mbox = &megaCfg->mailbox64.mailbox;
- megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xfffffff0);
+#ifdef __LP64__
+ megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ( (ulong)(-1) ^ 0x0F) );
megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
- paddr = (paddr + 4 + 16) & 0xfffffff0;
+ paddr = (paddr + 4 + 16) & ( (u64)(-1) ^ 0x0F );
+#else
+ megaCfg->mbox = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
+ megaCfg->mbox64 = (mega_mailbox64 *) (megaCfg->mbox - 4);
+ paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
+#endif
/* Register mailbox area with the firmware */
if (!(megaCfg->flag & BOARD_QUARTZ)) {
@@ -1509,10 +1782,10 @@
megaCfg->productInfo.BiosVer[2] >> 8,
megaCfg->productInfo.BiosVer[2] & 0x0f);
#else
- memcpy (megaCfg->fwVer, megaCfg->productInfo.FwVer, 4);
+ memcpy (megaCfg->fwVer, (char *)megaCfg->productInfo.FwVer, 4);
megaCfg->fwVer[4] = 0;
- memcpy (megaCfg->biosVer, megaCfg->productInfo.BiosVer, 4);
+ memcpy (megaCfg->biosVer, (char *)megaCfg->productInfo.BiosVer, 4);
megaCfg->biosVer[4] = 0;
#endif
@@ -1537,6 +1810,7 @@
int length, int host_no, int inout)
{
*start = buffer;
+
return 0;
}
@@ -1544,37 +1818,83 @@
u16 pciVendor, u16 pciDev,
long flag)
{
- mega_host_config *megaCfg;
- struct Scsi_Host *host;
+ mega_host_config *megaCfg = NULL;
+ struct Scsi_Host *host = NULL;
u_char pciBus, pciDevFun, megaIrq;
+
+#ifdef __LP64__
+ u64 megaBase;
+#else
u32 megaBase;
+#endif
+
u16 pciIdx = 0;
u16 numFound = 0;
#if LINUX_VERSION_CODE < 0x20100
while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) {
#else
-
+#if LINUX_VERSION_CODE > 0x20300
+ struct pci_dev *pdev = NULL;
+#else
struct pci_dev *pdev = pci_devices;
+#endif
while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) {
+
+#ifdef DELL_MODIFICATION
+ if (pci_enable_device(pdev))
+ continue;
+#endif
pciBus = pdev->bus->number;
pciDevFun = pdev->devfn;
#endif
if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
u16 magic;
-#if LINUX_VERSION_CODE < 0x20100
pcibios_read_config_word (pciBus, pciDevFun,
PCI_CONF_AMISIG,
&magic);
-#else
- pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
-#endif
if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471) ){
pciIdx++;
continue; /* not an AMI board */
}
}
+
+/* Hmmm...Should we not make this more modularized so that in future we dont add
+ for each firmware */
+
+ if (flag & BOARD_QUARTZ) {
+ /* Check to see if this is a Dell PERC RAID controller model 466 */
+ u16 subsysid, subsysvid;
+#if LINUX_VERSION_CODE < 0x20100
+ pcibios_read_config_word (pciBus, pciDevFun,
+ PCI_SUBSYSTEM_VENDOR_ID,
+ &subsysvid);
+ pcibios_read_config_word (pciBus, pciDevFun,
+ PCI_SUBSYSTEM_ID,
+ &subsysid);
+#else
+ pci_read_config_word (pdev,
+ PCI_SUBSYSTEM_VENDOR_ID,
+ &subsysvid);
+ pci_read_config_word (pdev,
+ PCI_SUBSYSTEM_ID,
+ &subsysid);
+#endif
+ if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
+ (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
+ printk(KERN_WARNING
+ "megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
+ "megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n"
+ "megaraid: with those firmware versions on this specific card. In order\n"
+ "megaraid: to protect your data, please upgrade your firmware to version\n"
+ "megaraid: 3.10 or later, available from the Dell Technical Support web\n"
+ "megaraid: site at\n"
+ "http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
+ continue;
+ }
+ }
+
printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:func %d\n",
pciVendor,
pciDev,
@@ -1583,28 +1903,15 @@
PCI_FUNC (pciDevFun));
/* Read the base port and IRQ from PCI */
-#if LINUX_VERSION_CODE < 0x20100
- pcibios_read_config_dword (pciBus, pciDevFun,
- PCI_BASE_ADDRESS_0,
- (u_int *) & megaBase);
- pcibios_read_config_byte (pciBus, pciDevFun,
- PCI_INTERRUPT_LINE,
- &megaIrq);
-#else
- megaBase = pdev->base_address[0];
+ megaBase = pci_resource_start (pdev, 0);
megaIrq = pdev->irq;
-#endif
- pciIdx++;
- if (flag & BOARD_QUARTZ) {
+ pciIdx++;
- megaBase &= PCI_BASE_ADDRESS_MEM_MASK;
- megaBase = (long) ioremap (megaBase, 128);
- }
- else {
- megaBase &= PCI_BASE_ADDRESS_IO_MASK;
- megaBase += 0x10;
- }
+ if (flag & BOARD_QUARTZ)
+ megaBase = (long) ioremap (megaBase, 128);
+ else
+ megaBase += 0x10;
/* Initialize SCSI Host structure */
host = scsi_register (pHostTmpl, sizeof (mega_host_config));
@@ -1632,6 +1939,7 @@
megaCfg->host->n_io_port = 16;
megaCfg->host->unique_id = (pciBus << 8) | pciDevFun;
megaCtlrs[numCtlrs++] = megaCfg;
+
if (flag != BOARD_QUARTZ) {
/* Request our IO Range */
if (check_region (megaBase, 16)) {
@@ -1654,42 +1962,9 @@
mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));
mega_i_query_adapter (megaCfg);
- if (flag == BOARD_QUARTZ) {
- /* Check to see if this is a Dell PERC RAID controller model 466 */
- u16 subsysid, subsysvid;
-#if LINUX_VERSION_CODE < 0x20100
- pcibios_read_config_word (pciBus, pciDevFun,
- PCI_SUBSYSTEM_VENDOR_ID,
- &subsysvid);
- pcibios_read_config_word (pciBus, pciDevFun,
- PCI_SUBSYSTEM_ID,
- &subsysid);
-#else
- pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
- pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);
-#endif
- if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
- (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
- printk(KERN_WARNING
-"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
-"megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n"
-"megaraid: with those firmware versions on this specific card. In order\n"
-"megaraid: to protect your data, please upgrade your firmware to version\n"
-"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
-"megaraid: site at\n"
-"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
- megaraid_release (host);
-#ifdef MODULE
- continue;
-#else
- while(1) schedule_timeout(1 * HZ);
-#endif
- }
- }
-
/* Initialize SCBs */
if (mega_initSCB (megaCfg)) {
- megaraid_release (host);
+ scsi_unregister (host);
continue;
}
@@ -1703,9 +1978,13 @@
*---------------------------------------------------------*/
int megaraid_detect (Scsi_Host_Template * pHostTmpl)
{
- int count = 0;
+ int ctlridx = 0, count = 0;
+#if LINUX_VERSION_CODE < 0x20300
pHostTmpl->proc_dir = &proc_scsi_megaraid;
+#else
+ pHostTmpl->proc_name = "megaraid";
+#endif
#if LINUX_VERSION_CODE < 0x20100
if (!pcibios_present ()) {
@@ -1726,9 +2005,31 @@
printk ("megaraid: " MEGARAID_VERSION CRLFSTR);
- count += mega_findCard (pHostTmpl, 0x101E, 0x9010, 0);
- count += mega_findCard (pHostTmpl, 0x101E, 0x9060, 0);
- count += mega_findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ);
+ count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+ PCI_DEVICE_ID_AMI_MEGARAID, 0);
+ count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+ PCI_DEVICE_ID_AMI_MEGARAID2, 0);
+ count += mega_findCard (pHostTmpl, 0x8086,
+ PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+ count += mega_findCard (pHostTmpl, PCI_VENDOR_ID_AMI,
+ PCI_DEVICE_ID_AMI_MEGARAID3, BOARD_QUARTZ);
+
+#ifdef CONFIG_PROC_FS
+ if (count) {
+#if LINUX_VERSION_CODE > 0x20300
+ mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+#else
+ mega_proc_dir_entry = create_proc_entry("megaraid",
+ S_IFDIR | S_IRUGO | S_IXUGO,
+ &proc_root);
+#endif
+ if (!mega_proc_dir_entry)
+ printk("megaraid: failed to create megaraid root\n");
+ else
+ for (ctlridx = 0; ctlridx < count ; ctlridx++)
+ mega_create_proc_entry(ctlridx, mega_proc_dir_entry);
+ }
+#endif
return count;
}
@@ -1741,6 +2042,7 @@
mega_host_config *megaCfg;
mega_mailbox *mbox;
u_char mboxData[16];
+ int i;
megaCfg = (mega_host_config *) pSHost->hostdata;
mbox = (mega_mailbox *) mboxData;
@@ -1766,6 +2068,22 @@
mega_freeSgList(megaCfg);
scsi_unregister (pSHost);
+#ifdef CONFIG_PROC_FS
+ if (megaCfg->controller_proc_dir_entry) {
+ remove_proc_entry("stat",megaCfg->controller_proc_dir_entry);
+ remove_proc_entry("status", megaCfg->controller_proc_dir_entry);
+ remove_proc_entry("config", megaCfg->controller_proc_dir_entry);
+ remove_proc_entry("mailbox", megaCfg->controller_proc_dir_entry);
+ for (i = 0; i < numCtlrs; i++) {
+ char buf[12];
+ memset(buf,0,12);
+ sprintf(buf,"%d",i);
+ remove_proc_entry(buf,mega_proc_dir_entry);
+ }
+ remove_proc_entry("megaraid", &proc_root);
+ }
+#endif
+
return 0;
}
@@ -1818,6 +2136,7 @@
DRIVER_LOCK_T
mega_host_config *megaCfg;
mega_scb *pScb;
+ char *user_area = NULL;
megaCfg = (mega_host_config *) SCpnt->host->hostdata;
DRIVER_LOCK(megaCfg);
@@ -1835,6 +2154,9 @@
SCpnt->scsi_done = pktComp;
+ if (mega_driver_ioctl(megaCfg, SCpnt))
+ return 0;
+
/* If driver in abort or reset.. cancel this command */
if (megaCfg->flag & IN_ABORT) {
SCpnt->result = (DID_ABORT << 16);
@@ -1886,31 +2208,31 @@
megaCfg->qPcnt++;
mega_runpendq(megaCfg);
+ if(pScb->SCpnt->cmnd[0] == IOCTL_CMD_NEW) {
+ pScb->ioctl_sem = MUTEX_LOCKED;
+ spin_unlock_irq(&io_request_lock);
+ down(&pScb->ioctl_sem);
+ user_area = *((char **)&pScb->SCpnt->cmnd[4]);
+ if(copy_to_user(user_area,pScb->buff_ptr,pScb->iDataSize)) {
+ printk("megaraid: Error copying ioctl return value to user buffer.\n");
+ pScb->SCpnt->result = (DID_ERROR << 16);
+ }
+ spin_lock_irq(&io_request_lock);
+ DRIVER_LOCK(megaCfg);
+ kfree(pScb->buff_ptr);
+ pScb->buff_ptr = NULL;
+ mega_cmd_done(megaCfg, pScb, pScb->SCpnt->result);
+ mega_rundoneq(megaCfg);
+ mega_runpendq(megaCfg);
+ DRIVER_UNLOCK(megaCfg);
+ }
-#if LINUX_VERSION_CODE > 0x020024
- if ( SCpnt->cmnd[0]==IOCTL_CMD_NEW )
- { /* user data from external user buffer */
- char *user_area;
- u32 xfer_size;
-
- pScb->sem=MUTEX_LOCKED;
- down(&pScb->sem);
-
- user_area = *((char **)&pScb->SCpnt->cmnd[4]);
- xfer_size = *((u32 *)&pScb->SCpnt->cmnd[8]);
-
- copy_to_user(user_area,pScb->kern_area,xfer_size);
-
- kfree(pScb->kern_area);
+ megaCfg->flag &= ~IN_QUEUE;
- mega_freeSCB(megaCfg, pScb);
- }
-#endif
}
- megaCfg->flag &= ~IN_QUEUE;
- DRIVER_UNLOCK(megaCfg);
+ DRIVER_UNLOCK(megaCfg);
return 0;
}
@@ -1919,7 +2241,13 @@
*----------------------------------------------------------------------*/
volatile static int internal_done_flag = 0;
volatile static int internal_done_errcode = 0;
-static struct wait_queue *internal_wait = NULL;
+
+#if LINUX_VERSION_CODE < 0x20300
+ static struct wait_queue *internal_wait = NULL;
+#else
+ static DECLARE_WAIT_QUEUE_HEAD(internal_wait);
+#endif
+
static void internal_done (Scsi_Cmnd * SCpnt)
{
@@ -2079,6 +2407,221 @@
mega_rundoneq(megaCfg);
return rc;
}
+
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs */
+static int proc_printf (mega_host_config *megaCfg, const char *fmt,...)
+{
+ va_list args;
+ int i;
+
+ if (megaCfg->procidx > PROCBUFSIZE)
+ return 0;
+
+ va_start (args, fmt);
+ i = vsprintf ((megaCfg->procbuf + megaCfg->procidx), fmt, args);
+ va_end (args);
+
+ megaCfg->procidx += i;
+ return i;
+}
+
+
+static int proc_read_config(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+
+ mega_host_config *megaCfg = (mega_host_config *)data;
+
+ *start = page;
+
+ if (megaCfg->productInfo.ProductName[0] != 0)
+ proc_printf(megaCfg,"%s\n",megaCfg->productInfo.ProductName);
+
+ proc_printf(megaCfg,"Controller Type: ");
+
+ if (megaCfg->flag & BOARD_QUARTZ)
+ proc_printf(megaCfg,"438/466/467/471/493\n");
+ else
+ proc_printf(megaCfg,"418/428/434\n");
+
+ if (megaCfg->flag & BOARD_40LD)
+ proc_printf(megaCfg,"Controller Supports 40 Logical Drives\n");
+
+ proc_printf(megaCfg,"Base = %08x, Irq = %d, ",megaCfg->base,
+ megaCfg->host->irq);
+
+ proc_printf(megaCfg, "Logical Drives = %d, Channels = %d\n",
+ megaCfg->numldrv, megaCfg->productInfo.SCSIChanPresent);
+
+ proc_printf(megaCfg, "Version =%s:%s, DRAM = %dMb\n",
+ megaCfg->fwVer,megaCfg->biosVer,
+ megaCfg->productInfo.DramSize);
+
+ proc_printf(megaCfg,"Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+ megaCfg->productInfo.MaxConcCmds, megaCfg->max_cmds);
+ COPY_BACK;
+ return count;
+}
+
+
+
+static int proc_read_stat(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ int i;
+ mega_host_config *megaCfg = (mega_host_config *)data;
+
+ *start = page;
+
+ proc_printf(megaCfg,"Statistical Information for this controller\n");
+ proc_printf(megaCfg,"Interrupts Collected = %d\n", megaCfg->nInterrupts);
+
+ for (i = 0; i < megaCfg->numldrv; i++) {
+ proc_printf(megaCfg,"Logical Drive %d:\n", i);
+ proc_printf(megaCfg,"\tReads Issued = %10d, Writes Issued = %10d\n",
+ megaCfg->nReads[i], megaCfg->nWrites[i]);
+
+ proc_printf(megaCfg,"\tSectors Read = %10d, Sectors Written = %10d\n\n", megaCfg->nReadBlocks[i],
+ megaCfg->nWriteBlocks[i]);
+ }
+
+ COPY_BACK;
+ return count;
+}
+
+
+
+static int proc_read_status(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+ mega_host_config *megaCfg = (mega_host_config *)data;
+ *start = page;
+
+ proc_printf(megaCfg,"TBD\n");
+ COPY_BACK;
+ return count;
+}
+
+
+static int proc_read_mbox(char *page, char **start, off_t offset,
+ int count, int *eof, void *data)
+{
+// int i;
+// char *dta = NULL;
+ mega_host_config *megaCfg = (mega_host_config *)data;
+ volatile mega_mailbox *mbox = megaCfg->mbox;
+
+ *start = page;
+
+ proc_printf(megaCfg,"Contents of Mail Box Structure\n");
+ proc_printf(megaCfg," Fw Command = 0x%02x\n", mbox->cmd);
+ proc_printf(megaCfg," Cmd Sequence = 0x%02x\n", mbox->cmdid);
+ proc_printf(megaCfg," No of Sectors= %04d\n", mbox->numsectors);
+ proc_printf(megaCfg," LBA = 0x%02x\n", mbox->lba);
+ proc_printf(megaCfg," DTA = 0x%08x\n", mbox->xferaddr);
+ proc_printf(megaCfg," Logical Drive= 0x%02x\n", mbox->logdrv);
+ proc_printf(megaCfg," No of SG Elmt= 0x%02x\n", mbox->numsgelements);
+ proc_printf(megaCfg," Busy = %01x\n", mbox->busy);
+ proc_printf(megaCfg," Status = 0x%02x\n", mbox->status);
+
+/* proc_printf(megaCfg, "Dump of MailBox\n");
+ for (i = 0; i < 16; i++)
+ proc_printf(megaCfg, "%02x ",*(mbox + i));
+
+proc_printf(megaCfg, "\n\nNumber of Status = %02d\n",mbox->numstatus);
+
+ for (i = 0; i < 46; i++) {
+ proc_printf(megaCfg,"%02d ",*(mbox + 16 + i));
+ if (i%16)
+ proc_printf(megaCfg,"\n");
+}
+
+if (!mbox->numsgelements) {
+ dta = phys_to_virt(mbox->xferaddr);
+ for (i = 0; i < mbox->numsgelements; i++)
+ if (dta) {
+ proc_printf(megaCfg,"Addr = %08x\n", (ulong)*(dta + i)); proc_printf(megaCfg,"Length = %08x\n",
+ (ulong)*(dta + i + 4));
+ }
+}*/
+ COPY_BACK;
+ return count;
+}
+
+
+#if LINUX_VERSION_CODE > 0x20300
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string, \
+ S_IRUSR | S_IFREG,\
+ controller_proc_dir_entry,\
+ fxn, megaCfg)
+#else
+#define CREATE_READ_PROC(string, fxn) create_proc_read_entry(string,S_IRUSR | S_IFREG, controller_proc_dir_entry, fxn, megaCfg)
+
+struct proc_dir_entry *create_proc_read_entry(const char *string,
+ int mode,
+ struct proc_dir_entry *parent,
+ read_proc_t *fxn,
+ mega_host_config *megaCfg)
+{
+ struct proc_dir_entry *temp = NULL;
+
+ temp = kmalloc(sizeof(struct proc_dir_entry),
+ GFP_KERNEL);
+ if (!temp)
+ return NULL;
+ memset(temp, 0, sizeof(struct proc_dir_entry));
+
+ if ( (temp->name = kmalloc(strlen(string) + 1, GFP_KERNEL)) == NULL) {
+ kfree(temp);
+ return NULL;
+ }
+
+ strcpy((char *)temp->name, string);
+ temp->namelen = strlen(string);
+ temp->mode = mode ; /*S_IFREG | S_IRUSR*/;
+ temp->data = (void *)megaCfg;
+ temp->read_proc = fxn;
+ proc_register(parent, temp);
+ return temp;
+}
+#endif
+
+
+
+void mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+ u_char string[64] = {0};
+ mega_host_config *megaCfg = megaCtlrs[index];
+ struct proc_dir_entry *controller_proc_dir_entry = NULL;
+
+ sprintf(string,"%d", index);
+
+#if LINUX_VERSION_CODE > 0x20300
+ controller_proc_dir_entry =
+ megaCfg->controller_proc_dir_entry =
+ proc_mkdir(string, parent);
+#else
+ controller_proc_dir_entry =
+ megaCfg->controller_proc_dir_entry =
+ create_proc_entry(string,S_IFDIR | S_IRUGO | S_IXUGO, parent);
+#endif
+
+ if (!controller_proc_dir_entry)
+ printk("\nmegaraid: proc_mkdir failed\n");
+ else
+ {
+ megaCfg->proc_read = CREATE_READ_PROC("config", proc_read_config);
+ megaCfg->proc_status = CREATE_READ_PROC("status", proc_read_status);
+ megaCfg->proc_stat = CREATE_READ_PROC("stat", proc_read_stat);
+ megaCfg->proc_mbox = CREATE_READ_PROC("mailbox", proc_read_mbox);
+ }
+
+}
+#endif /* CONFIG_PROC_FS */
+
+
/*-------------------------------------------------------------
* Return the disk geometry for a particular disk
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)