--- megaraid.c Tue Jan 9 19:40:43 2001 +++ megaraid.c Fri Feb 23 15:46:40 2001 @@ -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,15 +119,66 @@ * 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 @@ -143,23 +194,26 @@ #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 #ifdef MODULE #include +#if LINUX_VERSION_CODE >= 0x20100 char kernel_version[] = UTS_RELEASE; MODULE_AUTHOR ("American Megatrends Inc."); MODULE_DESCRIPTION ("AMI MegaRAID driver"); #endif +#endif #include #include #include +#include #include #include #include @@ -170,9 +224,19 @@ #include #include #include +#include +#include #include -#include +#if LINUX_VERSION_CODE < 0x20100 +#include +#else +#if LINUX_VERSION_CODE < 0x20300 +# include +#else +# include +#endif +#endif #include #include @@ -193,26 +257,48 @@ *================================================================ */ +#if LINUX_VERSION_CODE < 0x020100 +#define ioremap vremap +#define iounmap vfree + +/* simulate spin locks */ +typedef struct { + volatile char lock; +} spinlock_t; + +#define spin_lock_init(x) { (x)->lock = 0;} +#define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ + (x)->lock=1; save_flags(flags);\ + cli();} +#define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);} + +#endif + +#if LINUX_VERSION_CODE >= 0x020100 +#define queue_task_irq(a,b) queue_task(a,b) +#define queue_task_irq_off(a,b) queue_task(a,b) +#endif + #define MAX_SERBUF 160 #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); } @@ -264,6 +350,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 @@ -274,14 +373,20 @@ /* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE processor id cannot be scanned */ -#ifdef MODULE + + + static char *megaraid = NULL; +#if LINUX_VERSION_CODE > 0x20100 +#ifdef MODULE MODULE_PARM(megaraid, "s"); #endif +#endif static int skip_id; 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; @@ -294,6 +399,21 @@ static spinlock_t serial_lock = SPIN_LOCK_UNLOCKED; #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]; @@ -480,7 +600,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; @@ -523,6 +643,8 @@ mega_passthru *pthru; mega_mailbox *mbox; + + if (pScb == NULL) { TRACE(("NULL pScb in mega_cmd_done!")); printk("NULL pScb in mega_cmd_done!"); @@ -554,6 +676,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; @@ -588,12 +711,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; @@ -624,8 +742,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); @@ -641,7 +759,7 @@ return NULL; } - if ( islogical ) { + if (islogical) { lun = (SCpnt->target * 8) + lun; if ( lun > FC_MAX_LOGICAL_DRIVES ){ SCpnt->result = (DID_BAD_TARGET << 16); @@ -723,6 +841,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 */ @@ -735,6 +862,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 */ @@ -791,6 +927,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() *--------------------------------------------------------------------*/ @@ -801,9 +973,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); @@ -837,8 +1009,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; @@ -859,24 +1031,56 @@ * 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; } - kern_area = kmalloc(xfer_size, GFP_ATOMIC | GFP_DMA); - if (kern_area == NULL) { - printk("megaraid: Couldn't allocate kernel mem.\n"); + 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; } - 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 @@ -887,16 +1091,58 @@ 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); + *(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 { @@ -913,6 +1159,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) { @@ -955,6 +1232,7 @@ mbox = (mega_mailbox *)tmpBox; if (megaCfg->host->irq == irq) { + if (megaCfg->flag & IN_ISR) { printk(KERN_ERR "ISR called reentrantly!!\n"); } @@ -986,8 +1264,10 @@ for(idx=0;idx= 0x20100 IO_LOCK; - +#endif + megaCfg->nInterrupts++; qCnt = 0xff; while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ; @@ -1057,13 +1337,18 @@ continue; } - if (*(pScb->SCpnt->cmnd)==IOCTL_CMD_NEW) - { /* external user buffer */ - up(&pScb->sem); - } + /* 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(KERN_ERR "megaraid: wrong cmd id completed from firmware:id=%x\n",sIdx); @@ -1073,7 +1358,6 @@ mega_rundoneq(megaCfg); megaCfg->flag &= ~IN_ISR; - /* Loop through any pending requests */ mega_runpendq(megaCfg); #if LINUX_VERSION_CODE >= 0x20100 @@ -1081,6 +1365,7 @@ #endif } + } /*==================================================*/ @@ -1121,19 +1406,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 */ @@ -1158,7 +1447,7 @@ /* Copy mailbox data into host structure */ megaCfg->mbox64->xferSegment = 0; - memcpy (mbox, mboxData, 16); + memcpy ((char *)mbox, mboxData, 16); /* Kick IO */ if (intr) { @@ -1182,10 +1471,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); @@ -1282,9 +1579,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) & ( (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; + paddr = (paddr + 4 + 16) & 0xFFFFFFF0; +#endif /* Register mailbox area with the firmware */ if (!(megaCfg->flag & BOARD_QUARTZ)) { @@ -1430,10 +1733,10 @@ megaCfg->productInfo.BiosVer[2] >> 8, megaCfg->productInfo.BiosVer[2] & 0x0f); #else - memcpy (megaCfg->fwVer, (void *)megaCfg->productInfo.FwVer, 4); + memcpy (megaCfg->fwVer, (char *)megaCfg->productInfo.FwVer, 4); megaCfg->fwVer[4] = 0; - memcpy (megaCfg->biosVer, (void *)megaCfg->productInfo.BiosVer, 4); + memcpy (megaCfg->biosVer, (char *)megaCfg->productInfo.BiosVer, 4); megaCfg->biosVer[4] = 0; #endif @@ -1458,6 +1761,7 @@ int length, int host_no, int inout) { *start = buffer; + return 0; } @@ -1465,32 +1769,106 @@ u16 pciVendor, u16 pciDev, long flag) { - mega_host_config *megaCfg; - struct Scsi_Host *host; - u_char megaIrq; + 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 + skip_id = -1; + if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) { + if (megaraid[4] != '\0') { + skip_id = megaraid[4] - '0'; + if (megaraid[5] != '\0') { + skip_id = (skip_id * 10) + (megaraid[5] - '0'); + } + } + skip_id = (skip_id > 15) ? -1 : skip_id; + } 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; - pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic); - if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471)) + pcibios_read_config_word (pciBus, pciDevFun, + PCI_CONF_AMISIG, + &magic); + if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471) ){ + pciIdx++; continue; /* not an AMI board */ } - printk (KERN_INFO "megaraid: found 0x%4.04x:0x%4.04x: in %s\n", + } + +/* 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, - pdev->slot_name); + pciIdx, pciBus, + PCI_SLOT (pciDevFun), + PCI_FUNC (pciDevFun)); /* Read the base port and IRQ from PCI */ megaBase = pci_resource_start (pdev, 0); megaIrq = pdev->irq; + pciIdx++; + if (flag & BOARD_QUARTZ) megaBase = (long) ioremap (megaBase, 128); else @@ -1524,6 +1902,7 @@ megaCfg->host->n_io_port = 16; megaCfg->host->unique_id = (pdev->bus->number << 8) | pdev->devfn; megaCtlrs[numCtlrs++] = megaCfg; + if (flag != BOARD_QUARTZ) { /* Request our IO Range */ if (request_region (megaBase, 16, "megaraid")) { @@ -1545,42 +1924,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; } @@ -1594,20 +1940,53 @@ *---------------------------------------------------------*/ int megaraid_detect (Scsi_Host_Template * pHostTmpl) { - int count = 0; + int ctlridx = 0, count = 0; #ifdef MODULE if (megaraid) megaraid_setup(megaraid); #endif +#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 ()) { + printk (KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); + return 0; + } +#endif 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; } @@ -1620,6 +1999,7 @@ mega_host_config *megaCfg; mega_mailbox *mbox; u_char mboxData[16]; + int i; megaCfg = (mega_host_config *) pSHost->hostdata; mbox = (mega_mailbox *) mboxData; @@ -1645,6 +2025,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; } @@ -1697,6 +2093,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); @@ -1714,6 +2111,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); @@ -1765,31 +2165,31 @@ megaCfg->qPcnt++; mega_runpendq(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; - - init_MUTEX_LOCKED(&pScb->sem); - down(&pScb->sem); - + if(pScb->SCpnt->cmnd[0] == IOCTL_CMD_NEW) { + init_MUTEX_LOCKED(&pScb->ioctl_sem); + spin_unlock_irq(&io_request_lock); + down(&pScb->ioctl_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); - - mega_freeSCB(megaCfg, pScb); + 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); } -#endif + 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); } megaCfg->flag &= ~IN_QUEUE; - DRIVER_UNLOCK(megaCfg); + } + + + DRIVER_UNLOCK(megaCfg); return 0; } @@ -1798,7 +2198,13 @@ *----------------------------------------------------------------------*/ volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; -static DECLARE_WAIT_QUEUE_HEAD(internal_wait); + +#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) { @@ -1958,6 +2364,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 --- megaraid.h Mon Dec 11 22:19:40 2000 +++ megaraid.h Fri Feb 23 15:46:36 2001 @@ -22,6 +22,11 @@ #define SCB_RESET 0x6 #endif +/* IOCTL DRIVER INFO */ +#define DRIVER_IOCTL_INTERFACE 0x82 +/* Methods */ +#define GET_DRIVER_INFO 1 + #define MEGA_CMD_TIMEOUT 10 /* Feel free to fiddle with these.. max values are: @@ -96,13 +101,42 @@ #define ENABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,ENABLE_INTR_BYTE) #define DISABLE_INTR(base) WRITE_PORT(base,I_TOGGLE_PORT,DISABLE_INTR_BYTE) +/* Special Adapter Commands */ +#define FW_FIRE_WRITE 0x2C +#define FW_FIRE_FLASH 0x2D + +#define FC_NEW_CONFIG 0xA1 +#define DCMD_FC_CMD 0xA1 + #define DCMD_FC_PROCEED 0x02 + #define DCMD_DELETE_LOGDRV 0x03 + #define DCMD_FC_READ_NVRAM_CONFIG 0x04 + #define DCMD_FC_READ_FINAL_CONFIG 0x05 + #define DCMD_GET_DISK_CONFIG 0x06 + #define DCMD_CHANGE_LDNO 0x07 + #define DCMD_COMPACT_CONFIG 0x08 + #define DCMD_DELETE_DRIVEGROUP 0x09 + #define DCMD_GET_LOOPID_INFO 0x0A + #define DCMD_CHANGE_LOOPID 0x0B + #define DCMD_GET_NUM_SCSI_CHANS 0x0C + #define DCMD_WRITE_CONFIG 0x0D /* writes 40-ld config */ + #define NC_SUBOP_PRODUCT_INFO 0x0E + #define NC_SUBOP_ENQUIRY3 0x0F + #define ENQ3_GET_SOLICITED_NOTIFY_ONLY 0x01 + #define ENQ3_GET_SOLICITED_FULL 0x02 + #define ENQ3_GET_UNSOLICITED 0x03 + + /* Define AMI's PCI codes */ #undef PCI_VENDOR_ID_AMI #undef PCI_DEVICE_ID_AMI_MEGARAID +#undef PCI_DEVICE_ID_AMI_MEGARAID2 +#undef PCI_DEVICE_ID_AMI_MEGARAID3 #ifndef PCI_VENDOR_ID_AMI #define PCI_VENDOR_ID_AMI 0x101E #define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 +#define PCI_DEVICE_ID_AMI_MEGARAID2 0x9060 +#define PCI_DEVICE_ID_AMI_MEGARAID3 0x1960 #endif #define PCI_CONF_BASE_ADDR_OFFSET 0x10 @@ -528,8 +562,8 @@ /* 0x10 */ u8 numstatus; /* 0x11 */ u8 status; /* 0x12 */ u8 completed[46]; - u8 mraid_poll; - u8 mraid_ack; + volatile u8 mraid_poll; + volatile u8 mraid_ack; u8 pad[16]; /* for alignment purposes */ }__attribute__((packed)); typedef struct _mega_mailbox mega_mailbox; @@ -574,9 +608,9 @@ mega_passthru pthru; Scsi_Cmnd *SCpnt; mega_sglist *sgList; - char *kern_area; /* Only used for large ioctl xfers */ - struct wait_queue *ioctl_wait; - struct semaphore sem; + struct semaphore ioctl_sem; + void *buff_ptr; + u32 iDataSize; mega_scb *next; }; @@ -584,7 +618,12 @@ typedef struct _mega_host_config { u8 numldrv; u32 flag; + +#ifdef __LP64__ + u64 base; +#else u32 base; +#endif mega_scb *qFreeH; mega_scb *qFreeT; @@ -598,7 +637,10 @@ u32 qCcnt; u32 nReads[FC_MAX_LOGICAL_DRIVES]; + u32 nReadBlocks[FC_MAX_LOGICAL_DRIVES]; u32 nWrites[FC_MAX_LOGICAL_DRIVES]; + u32 nWriteBlocks[FC_MAX_LOGICAL_DRIVES]; + u32 nInterrupts; /* Host adapter parameters */ u8 fwVer[7]; @@ -622,8 +664,18 @@ u8 max_cmds; mega_scb scbList[MAX_COMMANDS]; +#define PROCBUFSIZE 4096 + char procbuf[PROCBUFSIZE]; + int procidx; + struct proc_dir_entry *controller_proc_dir_entry; + struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox; } mega_host_config; +typedef struct _driver_info { + int size; + ulong version; +} mega_driver_info; + const char *megaraid_info(struct Scsi_Host *); int megaraid_detect(Scsi_Host_Template *); int megaraid_release(struct Scsi_Host *); @@ -634,5 +686,8 @@ int megaraid_biosparam(Disk *, kdev_t, int *); int megaraid_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); + +void mega_build_kernel_sg(char *, ulong , mega_scb *, mega_ioctl_mbox *); +void mega_create_proc_entry(int index, struct proc_dir_entry *); #endif