patch -p0 -s -d /usr/src << '_EOF_' diff -urN linux/drivers/scsi/Config.in linux-2.0.32-megaraid/drivers/scsi/Config.in --- linux/drivers/scsi/Config.in Mon Sep 15 12:41:28 1997 +++ linux-2.0.32-megaraid/drivers/scsi/Config.in Tue Aug 11 09:40:32 1998 @@ -32,6 +32,7 @@ dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI +dep_tristate 'AMI MegaRAID support' CONFIG_SCSI_MEGARAID $CONFIG_SCSI dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI if [ "$CONFIG_SCSI_BUSLOGIC" != "n" ]; then bool ' Omit FlashPoint support' CONFIG_SCSI_OMIT_FLASHPOINT diff -urN linux/drivers/scsi/Makefile linux-2.0.32-megaraid/drivers/scsi/Makefile --- linux/drivers/scsi/Makefile Thu Aug 14 13:31:20 1997 +++ linux-2.0.32-megaraid/drivers/scsi/Makefile Tue Aug 11 18:09:11 1998 @@ -363,6 +363,13 @@ endif endif +ifeq ($(CONFIG_SCSI_MEGARAID),y) +L_OBJS += megaraid.o +else + ifeq ($(CONFIG_SCSI_MEGARAID),m) + M_OBJS += megaraid.o + endif +endif ifeq ($(CONFIG_BLK_DEV_IDESCSI),y) L_OBJS += ide-scsi.o @@ -400,6 +407,9 @@ g_NCR5380.o: g_NCR5380.c $(CC) $(CFLAGS) -DGENERIC_NCR5380_OVERRIDE="{{(NCR5380_map_type)0x350,5,0, BOARD_NCR53C400}};" -c g_NCR5380.c + +megaraid.o: megaraid.c + $(CC) $(CFLAGS) -c megaraid.c scsi_mod.o: $(MX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \ scsicam.o scsi_proc.o diff -urN linux/drivers/scsi/hosts.c linux-2.0.32-megaraid/drivers/scsi/hosts.c --- linux/drivers/scsi/hosts.c Thu Aug 14 13:31:20 1997 +++ linux-2.0.32-megaraid/drivers/scsi/hosts.c Tue Aug 11 09:42:40 1998 @@ -161,6 +161,10 @@ #include "AM53C974.h" #endif +#ifdef CONFIG_SCSI_MEGARAID +#include "megaraid.h" +#endif + #ifdef CONFIG_SCSI_PPA #include "ppa.h" #endif @@ -311,6 +315,9 @@ #endif #ifdef CONFIG_SCSI_AM53C974 AM53C974, +#endif +#ifdef CONFIG_SCSI_MEGARAID + MEGARAID, #endif #ifdef CONFIG_SCSI_PPA PPA, diff -urN linux/drivers/scsi/megaraid.c linux-2.0.32-megaraid/drivers/scsi/megaraid.c --- linux/drivers/scsi/megaraid.c Wed Dec 31 19:00:00 1969 +++ linux-2.0.32-megaraid/drivers/scsi/megaraid.c Wed Aug 19 18:53:01 1998 @@ -0,0 +1,1299 @@ +/*=================================================================== + * + * Linux MegaRAID device driver + * + * Copyright 1998 American Megatrends Inc. + * + * Version : 0.91 + * + * Description: Linux device driver for AMI MegaRAID controller + * + * History: + * + * Version 0.90: + * Works and has been tested with the MegaRAID 428 controller, and + * the MegaRAID 438 controller. Probably works with the 466 also, + * but not tested. + * + * Version 0.91: + * Aligned mailbox area on 16-byte boundry. + * Added schedule() at the end to properly clean up. + * Made improvements for conformity to linux driver standards. + * + * + *===================================================================*/ +#define QISR 1 + +#define CRLFSTR "\n" + +#define MULTIQ 1 + +#include + +#ifdef MODULE +#include +#include + +#if LINUX_VERSION_CODE > 0x20118 +char kernel_version[] = UTS_RELEASE; + +/* originally ported by Dell Corporation; updated, released, and maintained by + American Megatrends */ +MODULE_AUTHOR("American Megatrends Inc."); +MODULE_DESCRIPTION("AMI MegaRAID driver"); +#endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include /* for kmalloc() */ +#include /* for CONFIG_PCI */ +#if LINUX_VERSION_CODE <= 0x20100 +#include +#endif + +#include +#include + +#include "sd.h" +#include "scsi.h" +#include "hosts.h" + +#include "megaraid.h" + +//================================================================ +// +// #Defines +// +//================================================================ +#if LINUX_VERSION_CODE < 0x020100 +#define ioremap vremap +#define iounmap vfree +#endif + +#define MAX_SERBUF 160 +#define COM_BASE 0x2f8 + +#define ENQUEUE(obj,type,list,next) \ +{ type **node; long cpuflag; \ + save_flags(cpuflag); cli(); \ + for(node=&(list); *node; node=(type **)&(*node)->##next); \ + (*node) = obj; \ + (*node)->##next = NULL; \ + restore_flags(cpuflag); \ +}; + +#define DEQUEUE(obj,type,list,next) \ +{ long cpuflag; \ + save_flags(cpuflag); cli(); \ + if ((obj=list) != NULL) {\ + list = (type *)(list)->##next; \ + } \ + restore_flags(cpuflag); \ +}; + +u_long RDINDOOR(mega_host_config *megaCfg) +{ + return readl(megaCfg->base + 0x20); +} + +void WRINDOOR(mega_host_config *megaCfg, u_long value) +{ + writel(value,megaCfg->base+0x20); +} + +u_long RDOUTDOOR(mega_host_config *megaCfg) +{ + return readl(megaCfg->base+0x2C); +} + +void WROUTDOOR(mega_host_config *megaCfg, u_long value) +{ + writel(value,megaCfg->base+0x2C); +} + +//================================================================ +// +// Function prototypes +// +//================================================================ +static int MegaIssueCmd(mega_host_config *megaCfg, + u_char *mboxData, + mega_scb *scb, + int intr); +static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, + u_long *buffer, u_long *length); + +static void mega_runque(void *); +static void mega_rundoneq(void); +static void mega_cmd_done(mega_scb *, int); + +#define SERDEBUG 0 +#if SERDEBUG +static void ser_init(void); +static void ser_puts(char *str); +static void ser_putc(char c); +static int ser_printk(const char *fmt, ...); +#endif + +//================================================================ +// +// Global variables +// +//================================================================ +static int numCtlrs = 0; +static mega_host_config *megaCtlrs[4] = { 0 }; + +/* Change this to 0 if you want to see the raw drives */ +static int use_raid = 1; + +/* Queue of pending/completed SCBs */ +static mega_scb *qPending = NULL; +static Scsi_Cmnd *qCompleted = NULL; + +static struct tq_struct runq = {0,0,mega_runque,NULL}; + +struct proc_dir_entry proc_scsi_megaraid = { + PROC_SCSI_MEGARAID, 8, "megaraid", + S_IFDIR | S_IRUGO | S_IXUGO, 2 +}; + +#if SERDEBUG +static char strbuf[MAX_SERBUF+1]; + +static void ser_init() +{ + unsigned port=COM_BASE; + + outb(0x80,port+3); + outb(0,port+1); + /* 9600 Baud, if 19200: outb(6,port) */ + outb(12, port); + outb(3,port+3); + outb(0,port+1); +} + +static void ser_puts(char *str) +{ + char *ptr; + + ser_init(); + for (ptr=str;*ptr;++ptr) + ser_putc(*ptr); +} + +static void ser_putc(char c) +{ + unsigned port=COM_BASE; + + while ((inb(port+5) & 0x20)==0); + outb(c,port); + if (c==0x0a) + { + while ((inb(port+5) & 0x20)==0); + outb(0x0d,port); + } +} + +static int ser_printk(const char *fmt, ...) +{ + va_list args; + int i; + long flags; + + save_flags(flags); + cli(); + va_start(args,fmt); + i = vsprintf(strbuf,fmt,args); + ser_puts(strbuf); + va_end(args); + restore_flags(flags); + + return i; +} + +#define TRACE(a) { ser_printk a;} + +#else +#define TRACE(A) +#endif + +void callDone(Scsi_Cmnd *SCpnt) +{ + long flags; + + if (SCpnt->result) { + TRACE(("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, + SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, + SCpnt->result)); + } + save_flags(flags); + sti(); + SCpnt->scsi_done(SCpnt); + restore_flags(flags); +} + +/*------------------------------------------------------------------------- + * + * Local functions + * + *-------------------------------------------------------------------------*/ + +//================================================ +// Initialize SCB structures +//================================================ +static void initSCB(mega_host_config *megaCfg) +{ + int idx; + + for(idx=0; idxmax_cmds; idx++) { + megaCfg->scbList[idx].idx = -1; + megaCfg->scbList[idx].flag = 0; + megaCfg->scbList[idx].sgList = NULL; + megaCfg->scbList[idx].SCpnt = NULL; + } +} + +//=========================== +// Allocate a SCB structure +//=========================== +static mega_scb *allocateSCB(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) +{ + int idx; + long flags; + + save_flags(flags); + cli(); + for(idx=0; idxmax_cmds; idx++) { + if (megaCfg->scbList[idx].idx < 0) { + + /* Set Index and SCB pointer */ + megaCfg->scbList[idx].flag = 0; + megaCfg->scbList[idx].idx = idx; + megaCfg->scbList[idx].SCpnt = SCpnt; + megaCfg->scbList[idx].next = NULL; + + /* Lazy allocate Scatter-gather list */ + if (megaCfg->scbList[idx].sgList == NULL) { + megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist)*MAX_SGLIST, + GFP_ATOMIC|GFP_DMA); + } +#if 0 + TRACE(("kmalloc() = 0x%x\n",megaCfg->scbList[idx].sgList)); +#endif + restore_flags(flags); + + return &megaCfg->scbList[idx]; + } + } + restore_flags(flags); + + printk("Megaraid: Could not allocate free SCB!!!\n"); + + return NULL; +} + +//======================= +// Free a SCB structure +//======================= +static void freeSCB(mega_scb *scb) +{ + long flags; + + save_flags(flags); + cli(); + scb->flag = 0; + scb->idx = -1; + scb->next = NULL; + scb->SCpnt = NULL; + restore_flags(flags); +} + +/* Run through the list of completed requests */ +static void mega_rundoneq() +{ + mega_host_config *megaCfg; + Scsi_Cmnd *SCpnt; + long islogical; + + while(1) { + DEQUEUE(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + if (SCpnt == NULL) return; + + megaCfg = (mega_host_config *)SCpnt->host->hostdata; + + /* Check if we're allowing access to RAID drives or physical + * if use_raid == 1 and this wasn't a disk on the max channel or + * if use_raid == 0 and this was a disk on the max channel + * then fail. + */ + islogical = (SCpnt->channel == megaCfg->host->max_channel) ? 1 : 0; + if (SCpnt->cmnd[0] == INQUIRY && + ((((u_char*)SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && + (islogical != use_raid)) { + SCpnt->result = 0xF0; + } + + /* Convert result to error */ + switch(SCpnt->result) { + case 0x00: case 0x02: + SCpnt->result |= (DID_OK << 16); + break; + case 0x8: + SCpnt->result |= (DID_BUS_BUSY << 16); + break; + default: + SCpnt->result |= (DID_BAD_TARGET << 16); + break; + } + + /* Callback */ + callDone(SCpnt); + } +} + +/* Add command to the list of completed requests */ +static void mega_cmd_done(mega_scb *pScb, int status) +{ + pScb->SCpnt->result = status; + ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + freeSCB(pScb); +} + +/*---------------------------------------------------- + * Process pending queue list + * + * Run as a scheduled task + *----------------------------------------------------*/ +static void mega_runque(void *dummy) +{ + mega_host_config *megaCfg; + mega_scb *pScb; + long flags; + + /* Take care of any completed requests */ + mega_rundoneq(); + + DEQUEUE(pScb,mega_scb,qPending,next); + + if (pScb) { + megaCfg = (mega_host_config *)pScb->SCpnt->host->hostdata; + + if (megaCfg->mbox->busy || megaCfg->flag & (IN_ISR|PENDING)) { + printk("PENDING = %x, IN_ISR = %x, mbox.busy = %x\n",(u_int)(megaCfg->flag + & PENDING), (u_int)(megaCfg->flag & IN_ISR), megaCfg->mbox->busy); + TRACE(("%.08lx %.02x <%d.%d.%d> intr%d busy%d isr%d pending%d\n", + pScb->SCpnt->serial_number, + pScb->SCpnt->cmnd[0], + pScb->SCpnt->channel, + pScb->SCpnt->target, + pScb->SCpnt->lun, + intr_count, + megaCfg->mbox->busy, + (megaCfg->flag & IN_ISR) ? 1 : 0, + (megaCfg->flag & PENDING) ? 1 : 0)); + } + if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) { + printk("MegaIssueCmd returned BUSY. Rescheduling command.\n"); + /* We're BUSY... come back later */ + save_flags(flags); + cli(); + pScb->next = qPending; + qPending = pScb; + restore_flags(flags); + + if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */ + queue_task(&runq, &tq_scheduler); + } + } + } +} + +/*------------------------------------------------------------------- + * + * Build a SCB from a Scsi_Cmnd + * + * Returns a SCB pointer, or NULL + * If NULL is returned, the scsi_done function MUST have been called + * + *-------------------------------------------------------------------*/ +static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) +{ + mega_scb *pScb; + mega_mailbox *mbox; + mega_passthru *pthru; + long seg; + + /* We don't support multi-luns */ + if (SCpnt->lun != 0) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone(SCpnt); + return NULL; + } + + /*----------------------------------------------------- + * + * Logical drive commands + * + *-----------------------------------------------------*/ + if (SCpnt->channel == megaCfg->host->max_channel) { + switch(SCpnt->cmnd[0]) { + case TEST_UNIT_READY: + memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen); + SCpnt->result = (DID_OK << 16); + callDone(SCpnt); + return NULL; + + case MODE_SENSE: + memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]); + SCpnt->result = (DID_OK << 16); + callDone(SCpnt); + return NULL; + + case READ_CAPACITY: + case INQUIRY: + /* Allocate a SCB and initialize passthru */ + if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone(SCpnt); + return NULL; + } + pthru = &pScb->pthru; + mbox = (mega_mailbox *)&pScb->mboxData; + + memset(mbox, 0, sizeof(pScb->mboxData)); + memset(pthru, 0, sizeof(mega_passthru)); + pthru->timeout = 0; + pthru->ars = 0; + pthru->islogical = 1; + pthru->logdrv = SCpnt->target; + pthru->cdblen = SCpnt->cmd_len; + pthru->dataxferaddr = (u_long)SCpnt->request_buffer; + pthru->dataxferlen = SCpnt->request_bufflen; + memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + /* Initialize mailbox area */ + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = (u_long)pthru; + + return pScb; + + case READ_6: + case WRITE_6: + case READ_10: + case WRITE_10: + /* Allocate a SCB and initialize mailbox */ + if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone(SCpnt); + return NULL; + } + mbox = (mega_mailbox *)&pScb->mboxData; + + memset(mbox, 0, sizeof(pScb->mboxData)); + mbox->logdrv = SCpnt->target; + mbox->cmd = (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) ? + MEGA_MBOXCMD_LREAD : MEGA_MBOXCMD_LWRITE; + + /* 6-byte */ + if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == WRITE_6) { + mbox->numsectors = + (u_long)SCpnt->cmnd[4]; + mbox->lba = + ((u_long)SCpnt->cmnd[1] << 16) | + ((u_long)SCpnt->cmnd[2] << 8) | + (u_long)SCpnt->cmnd[3]; + mbox->lba &= 0x1FFFFF; + } + + /* 10-byte */ + if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) { + mbox->numsectors = + (u_long)SCpnt->cmnd[8] | + ((u_long)SCpnt->cmnd[7] << 8); + mbox->lba = + ((u_long)SCpnt->cmnd[2] << 24) | + ((u_long)SCpnt->cmnd[3] << 16) | + ((u_long)SCpnt->cmnd[4] << 8) | + (u_long)SCpnt->cmnd[5]; + } + + /* Calculate Scatter-Gather info */ + mbox->numsgelements = build_sglist(megaCfg, pScb, + (u_long*)&mbox->xferaddr, + (u_long*)&seg); + + return pScb; + + default: + SCpnt->result = (DID_BAD_TARGET << 16); + callDone(SCpnt); + return NULL; + } + } + /*----------------------------------------------------- + * + * Passthru drive commands + * + *-----------------------------------------------------*/ + else { + /* Allocate a SCB and initialize passthru */ + if ((pScb = allocateSCB(megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone(SCpnt); + return NULL; + } + pthru = &pScb->pthru; + mbox = (mega_mailbox *)pScb->mboxData; + + memset(mbox, 0, sizeof(pScb->mboxData)); + memset(pthru, 0, sizeof(mega_passthru)); + pthru->timeout = 0; + pthru->ars = 0; + pthru->islogical = 0; + pthru->channel = SCpnt->channel; + pthru->target = SCpnt->target; + pthru->cdblen = SCpnt->cmd_len; + memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + + pthru->numsgelements = build_sglist(megaCfg, pScb, + (u_long *)&pthru->dataxferaddr, + (u_long *)&pthru->dataxferlen); + + /* Initialize mailbox */ + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = (u_long)pthru; + + return pScb; + } + return NULL; +} + +/*-------------------------------------------------------------------- + * Interrupt service routine + *--------------------------------------------------------------------*/ +static void megaraid_isr(int irq, void *devp, struct pt_regs *regs) +{ + mega_host_config *megaCfg; + u_char byte, idx, sIdx; + u_long dword; + mega_mailbox *mbox; + mega_scb *pScb; + long flags; + int qCnt, qStatus; + + megaCfg = (mega_host_config *)devp; + mbox = (mega_mailbox *)megaCfg->mbox; + + if (megaCfg->host->irq == irq) { + save_flags(flags); + cli(); + + if (megaCfg->flag & IN_ISR) { + TRACE(("ISR called reentrantly!!\n")); + } + + megaCfg->flag |= IN_ISR; + + /* Check if a valid interrupt is pending */ + if (megaCfg->flag & BOARD_QUARTZ) { + dword = RDOUTDOOR(megaCfg); + if (dword != 0x10001234) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + restore_flags(flags); + return; + } + WROUTDOOR(megaCfg,dword); + } else { + byte = READ_PORT(megaCfg->host->io_port, INTR_PORT); + if ((byte & VALID_INTR_BYTE) == 0) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + restore_flags(flags); + return; + } + WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); + } + + qCnt = mbox->numstatus; + qStatus = mbox->status; + + if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt)) + printk("Got numstatus = %d\n",qCnt); + } + + for(idx=0; idxcompleted[idx]; + if (sIdx > 0) { + pScb = &megaCfg->scbList[sIdx-1]; + mega_cmd_done(&megaCfg->scbList[sIdx-1], qStatus); + } + } + if (megaCfg->flag & BOARD_QUARTZ) { + WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox)|0x2); + while (RDINDOOR(megaCfg) & 0x02); + } else { + CLEAR_INTR(megaCfg->host->io_port); + } + + megaCfg->flag &= ~IN_ISR; + megaCfg->flag &= ~PENDING; + + /* Queue as a delayed ISR routine */ + queue_task_irq_off(&runq, &tq_immediate); + mark_bh(IMMEDIATE_BH); + + restore_flags(flags); + } +} + +/*==================================================*/ +/* Wait until the controller's mailbox is available */ +/*==================================================*/ +static int busyWaitMbox(mega_host_config *megaCfg) +{ + mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; + long counter; + + for(counter=0; counter<0xFFFFFF; counter++) { + if (!mbox->busy) return 0; + } + return -1; +} + +//===================================================== +// Post a command to the card +// +// Arguments: +// mega_host_config *megaCfg - Controller structure +// u_char *mboxData - Mailbox area, 16 bytes +// mega_scb *pScb - SCB posting (or NULL if N/A) +// int intr - if 1, interrupt, 0 is blocking +//===================================================== +static int MegaIssueCmd(mega_host_config *megaCfg, + u_char *mboxData, + mega_scb *pScb, + int intr) +{ + mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; + long flags; + u_char byte; + u_long cmdDone; + +#if 0 + if (pScb) { + pScb->SCpnt->result = DID_BAD_TARGET << 16; + callDone(pScb->SCpnt); + freeSCB(pScb); + } + return 0; +#endif + + mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ + + /* gah.. issuing a command while pending seems to fall through + * the cracks.. + */ + if (megaCfg->flag & PENDING) { + return -1; + } + + /* Wait until mailbox is free */ + if (busyWaitMbox(megaCfg)) { + if (pScb) { + TRACE(("Mailbox busy %.08lx <%d.%d.%d>\n", pScb->SCpnt->serial_number, + pScb->SCpnt->channel, pScb->SCpnt->target, pScb->SCpnt->lun)); + } + return -1; + } + + /* Copy mailbox data into host structure */ + save_flags(flags); + cli(); + memset(mbox, 0, sizeof(mega_mailbox)); + memcpy(mbox, mboxData, 16); + restore_flags(flags); + + /* Kick IO */ + megaCfg->flag |= PENDING; + if (intr) { + /* Issue interrupt (non-blocking) command */ + if (megaCfg->flag & BOARD_QUARTZ) { + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); + } else { + ENABLE_INTR(megaCfg->host->io_port); + ISSUE_COMMAND(megaCfg->host->io_port); + } + } + else { /* Issue non-ISR (blocking) command */ + + if (megaCfg->flag & BOARD_QUARTZ) { + + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); + + while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234); + WROUTDOOR(megaCfg, cmdDone); + + if (pScb) { + mega_cmd_done(pScb, mbox->status); + mega_rundoneq(); + } + + WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2); + while(RDINDOOR(megaCfg) & 0x2); + + megaCfg->flag &= ~PENDING; + } + else { + DISABLE_INTR(megaCfg->host->io_port); + ISSUE_COMMAND(megaCfg->host->io_port); + + while(!((byte=READ_PORT(megaCfg->host->io_port,INTR_PORT))&INTR_VALID)); + WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); + + ENABLE_INTR(megaCfg->host->io_port); + CLEAR_INTR(megaCfg->host->io_port); + + if (pScb) { + mega_cmd_done(pScb, mbox->status); + mega_rundoneq(); + } + megaCfg->flag &= ~PENDING; + } + } + + return 0; +} + +/*------------------------------------------------------------------- + * Copies data to SGLIST + *-------------------------------------------------------------------*/ +static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, + u_long *buffer, u_long *length) +{ + struct scatterlist *sgList; + int idx; + + /* Scatter-gather not used */ + if (scb->SCpnt->use_sg == 0) { + *buffer = (u_long)scb->SCpnt->request_buffer; + *length = (u_long)scb->SCpnt->request_bufflen; + return 0; + } + + sgList = (struct scatterlist *)scb->SCpnt->buffer; + if (scb->SCpnt->use_sg == 1) { + *buffer = (u_long)sgList[0].address; + *length = (u_long)sgList[0].length; + return 0; + } + + /* Copy Scatter-Gather list info into controller structure */ + for(idx=0; idxSCpnt->use_sg; idx++) { + scb->sgList[idx].address = (u_long)sgList[idx].address; + scb->sgList[idx].length = (u_long)sgList[idx].length; + } + + /* Reset pointer and length fields */ + *buffer = (u_long)scb->sgList; + *length = 0; + + /* Return count of SG requests */ + return scb->SCpnt->use_sg; +} + +/*-------------------------------------------------------------------- + * Initializes the adress of the controller's mailbox register + * The mailbox register is used to issue commands to the card. + * Format of the mailbox area: + * 00 01 command + * 01 01 command id + * 02 02 # of sectors + * 04 04 logical bus address + * 08 04 physical buffer address + * 0C 01 logical drive # + * 0D 01 length of scatter/gather list + * 0E 01 reserved + * 0F 01 mailbox busy + * 10 01 numstatus byte + * 11 01 status byte + *--------------------------------------------------------------------*/ +static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr) +{ + /* align on 16-byte boundry */ + megaCfg->mbox = &megaCfg->mailbox; + megaCfg->mbox = (mega_mailbox *) ((((ulong)megaCfg->mbox) + 16)&0xfffffff0); + paddr = (paddr+16)&0xfffffff0; + + /* Register mailbox area with the firmware */ + if (megaCfg->flag & BOARD_QUARTZ) { + } + else { + WRITE_PORT(megaCfg->host->io_port, MBOX_PORT0, paddr & 0xFF); + WRITE_PORT(megaCfg->host->io_port, MBOX_PORT1, (paddr >> 8) & 0xFF); + WRITE_PORT(megaCfg->host->io_port, MBOX_PORT2, (paddr >> 16) & 0xFF); + WRITE_PORT(megaCfg->host->io_port, MBOX_PORT3, (paddr >> 24) & 0xFF); + WRITE_PORT(megaCfg->host->io_port, ENABLE_MBOX_REGION, ENABLE_MBOX_BYTE); + + CLEAR_INTR(megaCfg->host->io_port); + ENABLE_INTR(megaCfg->host->io_port); + } + return 0; +} + +/*------------------------------------------------------------------- + * Issue an adapter info query to the controller + *-------------------------------------------------------------------*/ +static int mega_i_query_adapter(mega_host_config *megaCfg) +{ + mega_RAIDINQ *adapterInfo; + mega_mailbox *mbox; + u_char mboxData[16]; + u_long paddr; + + /* Initialize adapter inquiry */ + paddr = virt_to_bus(megaCfg->mega_buffer); + mbox = (mega_mailbox *)mboxData; + + memset((void *)megaCfg->mega_buffer, 0, sizeof(megaCfg->mega_buffer)); + memset(mbox, 0, 16); + + /* Initialize mailbox registers */ + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; + mbox->xferaddr = paddr; + + /* Issue a blocking command to the card */ + MegaIssueCmd(megaCfg, mboxData, NULL, 0); + + /* Initialize host/local structures with Adapter info */ + adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + megaCfg->host->max_channel = adapterInfo->AdpInfo.ChanPresent; + megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; + megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; + +#if 0 + printk("---- Logical drive info ----\n"); + for(i=0; inumldrv; i++) { + printk("%d: size: %ld prop: %x state: %x\n",i, + adapterInfo->LogdrvInfo.LDrvSize[i], + adapterInfo->LogdrvInfo.LDrvProp[i], + adapterInfo->LogdrvInfo.LDrvState[i]); + } + printk("---- Physical drive info ----\n"); + for(i=0; iPhysdrvInfo.PDrvState[i]); + } + printk("\n"); +#endif + + megaCfg->max_cmds = adapterInfo->AdpInfo.MaxConcCmds; + +#ifdef HP /* use HP firmware and bios version encoding */ + sprintf(megaCfg->fwVer,"%c%d%d.%d%d", + adapterInfo->AdpInfo.FwVer[2], + adapterInfo->AdpInfo.FwVer[1] >> 8, + adapterInfo->AdpInfo.FwVer[1] & 0x0f, + adapterInfo->AdpInfo.FwVer[2] >> 8, + adapterInfo->AdpInfo.FwVer[2] & 0x0f); + sprintf(megaCfg->biosVer,"%c%d%d.%d%d", + adapterInfo->AdpInfo.BiosVer[2], + adapterInfo->AdpInfo.BiosVer[1] >> 8, + adapterInfo->AdpInfo.BiosVer[1] & 0x0f, + adapterInfo->AdpInfo.BiosVer[2] >> 8, + adapterInfo->AdpInfo.BiosVer[2] & 0x0f); +#else + memcpy(megaCfg->fwVer, adapterInfo->AdpInfo.FwVer, 4); + megaCfg->fwVer[4] = 0; + + memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); + megaCfg->biosVer[4] = 0; +#endif + + printk("megaraid: [%s:%s] detected %d logical drives" CRLFSTR, + megaCfg->fwVer, + megaCfg->biosVer, + megaCfg->numldrv); + return 0; +} + +/*------------------------------------------------------------------------- + * + * Driver interface functions + * + *-------------------------------------------------------------------------*/ + +/*---------------------------------------------------------- + * Returns data to be displayed in /proc/scsi/megaraid/X + *----------------------------------------------------------*/ +int megaraid_proc_info(char *buffer, char **start, off_t offset, + int length, int inode, int inout) +{ + *start = buffer; + return 0; +} + +int findCard(Scsi_Host_Template *pHostTmpl, + u_short pciVendor, u_short pciDev, + long flag) +{ + mega_host_config *megaCfg; + struct Scsi_Host *host; + u_char pciBus, pciDevFun, megaIrq; + u_long megaBase; + u_short pciIdx; + + pciIdx = 0; + while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) { + printk("megaraid: found 0x%4.04x:0x%4.04x:idx %d:bus %d:slot %d:fun %d\n", + pciVendor, + pciDev, + pciIdx, pciBus, + PCI_SLOT(pciDevFun), + PCI_FUNC(pciDevFun)); + + /* Read the base port and IRQ from PCI */ + pcibios_read_config_dword(pciBus, pciDevFun, + PCI_BASE_ADDRESS_0, + (u_int *)&megaBase); + pcibios_read_config_byte(pciBus, pciDevFun, + PCI_INTERRUPT_LINE, + &megaIrq); + pciIdx++; + + if (flag & BOARD_QUARTZ) { + megaBase &= PCI_BASE_ADDRESS_MEM_MASK; + megaBase = (long) ioremap(megaBase,128); + } + else { + megaBase &= PCI_BASE_ADDRESS_IO_MASK; + megaBase += 0x10; + } + + /* Initialize SCSI Host structure */ + host = scsi_register(pHostTmpl, sizeof(mega_host_config)); + megaCfg = (mega_host_config *)host->hostdata; + memset(megaCfg, 0, sizeof(mega_host_config)); + + printk(" scsi%d: Found a MegaRAID controller at 0x%x, IRQ: %d" CRLFSTR, + host->host_no, (u_int)megaBase, megaIrq); + + /* Copy resource info into structure */ + megaCfg->flag = flag; + megaCfg->host = host; + megaCfg->base = megaBase; + megaCfg->host->irq = megaIrq; + megaCfg->host->io_port = megaBase; + 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)) { + printk(KERN_WARNING "megaraid: Couldn't register I/O range!" CRLFSTR); + scsi_unregister(host); + continue; + } + request_region(megaBase, 16, "megaraid"); + } + + /* Request our IRQ */ + if (request_irq(megaIrq, megaraid_isr, SA_INTERRUPT|SA_SHIRQ, + "megaraid", megaCfg)) { + printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, + megaIrq); + scsi_unregister(host); + continue; + } + + mega_register_mailbox(megaCfg, virt_to_bus((void*)&megaCfg->mailbox)); + mega_i_query_adapter(megaCfg); + + /* Initialize SCBs */ + initSCB(megaCfg); + + } + return pciIdx; +} + +/*--------------------------------------------------------- + * Detects if a megaraid controller exists in this system + *---------------------------------------------------------*/ +int megaraid_detect(Scsi_Host_Template *pHostTmpl) +{ + int count = 0; + + pHostTmpl->proc_dir = &proc_scsi_megaraid; + + if (!pcibios_present()) + { + printk("megaraid: PCI bios not present." CRLFSTR); + return 0; + } + + count += findCard(pHostTmpl, 0x101E, 0x9010, 0); + count += findCard(pHostTmpl, 0x101E, 0x9060, 0); + count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + + return count; +} + +/*--------------------------------------------------------------------- + * Release the controller's resources + *---------------------------------------------------------------------*/ +int megaraid_release(struct Scsi_Host *pSHost) +{ + mega_host_config *megaCfg; + mega_mailbox *mbox; + u_char mboxData[16]; + + megaCfg = (mega_host_config*)pSHost->hostdata; + mbox = (mega_mailbox *)mboxData; + + /* Flush cache to disk */ + memset(mbox, 0, 16); + mboxData[0] = 0xA; + + /* Issue a blocking (interrupts disabled) command to the card */ + MegaIssueCmd(megaCfg, mboxData, NULL, 0); + + schedule(); + + /* Free our resources */ + if (megaCfg->flag & BOARD_QUARTZ) { + iounmap((void *)megaCfg->base); + } else { + release_region(megaCfg->host->io_port, 16); + } + free_irq(megaCfg->host->irq, megaCfg); /* Must be freed first, otherwise + extra interrupt is generated */ + scsi_unregister(pSHost); + + return 0; +} + +/*---------------------------------------------- + * Get information about the card/driver + *----------------------------------------------*/ +const char *megaraid_info(struct Scsi_Host *pSHost) +{ + static char buffer[512]; + mega_host_config *megaCfg; + mega_RAIDINQ *adapterInfo; + + megaCfg = (mega_host_config *)pSHost->hostdata; + adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + + sprintf(buffer, "AMI MegaRAID %s %d commands %d targs %d chans", + megaCfg->fwVer, + adapterInfo->AdpInfo.MaxConcCmds, + megaCfg->host->max_id, + megaCfg->host->max_channel); + return buffer; +} + +/*----------------------------------------------------------------- + * Perform a SCSI command + * Mailbox area: + * 00 01 command + * 01 01 command id + * 02 02 # of sectors + * 04 04 logical bus address + * 08 04 physical buffer address + * 0C 01 logical drive # + * 0D 01 length of scatter/gather list + * 0E 01 reserved + * 0F 01 mailbox busy + * 10 01 numstatus byte + * 11 01 status byte + *-----------------------------------------------------------------*/ +int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *)) +{ + mega_host_config *megaCfg; + mega_scb *pScb; + + megaCfg = (mega_host_config *)SCpnt->host->hostdata; + + if (!(megaCfg->flag & (1L << SCpnt->channel))) { + printk("scsi%d: scanning channel %c for devices.\n", + megaCfg->host->host_no, + SCpnt->channel + 'A'); + megaCfg->flag |= (1L << SCpnt->channel); + } + + SCpnt->scsi_done = pktComp; + + /* Allocate and build a SCB request */ + if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) { + /* Add SCB to the head of the pending queue */ + ENQUEUE(pScb, mega_scb, qPending, next); + + /* Issue the command to the card */ + mega_runque(NULL); + } + +#if 0 + SCpnt->result = (DID_BAD_TARGET << 16); + SCpnt->scsi_done = pktComp; + callDone(SCpnt); +#endif + return 0; +} + +/*---------------------------------------------------------------------- + * Issue a blocking command to the controller + *----------------------------------------------------------------------*/ +volatile static int internal_done_flag = 0; +volatile static int internal_done_errcode = 0; + +static void internal_done(Scsi_Cmnd *SCpnt) +{ + internal_done_errcode = SCpnt->result; + internal_done_flag++; +} + +int megaraid_command(Scsi_Cmnd *SCpnt) +{ + internal_done_flag = 0; + + /* Queue command, and wait until it has completed */ + megaraid_queue(SCpnt, internal_done); + + while(!internal_done_flag) + barrier(); + + return internal_done_errcode; +} + +/*--------------------------------------------------------------------- + * Abort a previous SCSI request + *---------------------------------------------------------------------*/ +int megaraid_abort(Scsi_Cmnd *SCpnt) +{ + mega_host_config *megaCfg; + int idx; + long flags; + + save_flags(flags); + cli(); + + megaCfg = (mega_host_config *)SCpnt->host->hostdata; + + TRACE(("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); + /* + * Walk list of SCBs for any that are still outstanding + */ + for(idx=0; idxmax_cmds; idx++) { + if (megaCfg->scbList[idx].idx >= 0) { + if (megaCfg->scbList[idx].SCpnt == SCpnt) { + freeSCB(&megaCfg->scbList[idx]); + + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); + callDone(SCpnt); + } + } + } + restore_flags(flags); + return SCSI_ABORT_SNOOZE; +} + +/*--------------------------------------------------------------------- + * Reset a previous SCSI request + *---------------------------------------------------------------------*/ +int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags) +{ + mega_host_config *megaCfg; + int idx; + long flags; + + save_flags(flags); + cli(); + + megaCfg = (mega_host_config *)SCpnt->host->hostdata; + + TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); + + /* + * Walk list of SCBs for any that are still outstanding + */ + for(idx=0; idxmax_cmds; idx++) { + if (megaCfg->scbList[idx].idx >= 0) { + SCpnt = megaCfg->scbList[idx].SCpnt; + freeSCB(&megaCfg->scbList[idx]); + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); + callDone(SCpnt); + } + } + restore_flags(flags); + return SCSI_RESET_PUNT; +} + +/*------------------------------------------------------------- + * Return the disk geometry for a particular disk + * Input: + * Disk *disk - Disk geometry + * kdev_t dev - Device node + * int *geom - Returns geometry fields + * geom[0] = heads + * geom[1] = sectors + * geom[2] = cylinders + *-------------------------------------------------------------*/ +int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom) +{ + int heads, sectors, cylinders; + mega_host_config *megaCfg; + + /* Get pointer to host config structure */ + megaCfg = (mega_host_config *)disk->device->host->hostdata; + + /* Default heads (64) & sectors (32) */ + heads = 64; + sectors = 32; + cylinders = disk->capacity / (heads * sectors); + + /* Handle extended translation size for logical drives > 1Gb */ + if (disk->capacity >= 0x200000) { + heads = 255; + sectors = 63; + cylinders = disk->capacity / (heads * sectors); + } + + /* return result */ + geom[0] = heads; + geom[1] = sectors; + geom[2] = cylinders; + + return 0; +} + +#ifdef MODULE +Scsi_Host_Template driver_template = MEGARAID; + +#include "scsi_module.c" +#endif diff -urN linux/drivers/scsi/megaraid.h linux-2.0.32-megaraid/drivers/scsi/megaraid.h --- linux/drivers/scsi/megaraid.h Wed Dec 31 19:00:00 1969 +++ linux-2.0.32-megaraid/drivers/scsi/megaraid.h Mon Aug 17 17:38:49 1998 @@ -0,0 +1,291 @@ +#ifndef __MEGARAID_H__ +#define __MEGARAID_H__ + +#define IN_ISR 0x80000000L +#define NO_INTR 0x40000000L +#define IN_TIMEOUT 0x20000000L +#define PENDING 0x10000000L +#define BOARD_QUARTZ 0x08000000L + +#define SCB_ACTIVE 0x1 +#define SCB_WAITQ 0x2 +#define SCB_ISSUED 0x4 + +#define SCB_FREE -1 +#define SCB_RESET -2 +#define SCB_ABORT -3 +#define SCB_LOCKED -4 + +#define MEGA_CMD_TIMEOUT 10 + +#define MAX_SGLIST 20 +#define MAX_COMMANDS 254 + +#define MAX_LOGICAL_DRIVES 8 +#define MAX_CHANNEL 5 +#define MAX_TARGET 15 +#define MAX_PHYSICAL_DRIVES MAX_CHANNEL*MAX_TARGET + +#define INQUIRY_DATA_SIZE 0x24 +#define MAX_CDB_LEN 0x0A +#define MAX_REQ_SENSE_LEN 0x20 + +#define INTR_VALID 0x40 + +/* Mailbox commands */ +#define MEGA_MBOXCMD_LREAD 0x01 +#define MEGA_MBOXCMD_LWRITE 0x02 +#define MEGA_MBOXCMD_PASSTHRU 0x03 +#define MEGA_MBOXCMD_ADAPTERINQ 0x05 + +/* Offsets into Mailbox */ +#define COMMAND_PORT 0x00 +#define COMMAND_ID_PORT 0x01 +#define SG_LIST_PORT0 0x08 +#define SG_LIST_PORT1 0x09 +#define SG_LIST_PORT2 0x0a +#define SG_LIST_PORT3 0x0b +#define SG_ELEMENT_PORT 0x0d +#define NO_FIRED_PORT 0x0f + +/* I/O Port offsets */ +#define I_CMD_PORT 0x00 +#define I_ACK_PORT 0x00 +#define I_TOGGLE_PORT 0x01 +#define INTR_PORT 0x0a + +#define MAILBOX_SIZE 70 +#define MBOX_BUSY_PORT 0x00 +#define MBOX_PORT0 0x04 +#define MBOX_PORT1 0x05 +#define MBOX_PORT2 0x06 +#define MBOX_PORT3 0x07 +#define ENABLE_MBOX_REGION 0x0B + +/* I/O Port Values */ +#define ISSUE_BYTE 0x10 +#define ACK_BYTE 0x08 +#define ENABLE_INTR_BYTE 0xc0 +#define DISABLE_INTR_BYTE 0x00 +#define VALID_INTR_BYTE 0x40 +#define MBOX_BUSY_BYTE 0x10 +#define ENABLE_MBOX_BYTE 0x00 + +/* Setup some port macros here */ +#define WRITE_MAILBOX(base,offset,value) *(base+offset)=value +#define READ_MAILBOX(base,offset) *(base+offset) + +#define WRITE_PORT(base,offset,value) outb_p(value,base+offset) +#define READ_PORT(base,offset) inb_p(base+offset) + +#define ISSUE_COMMAND(base) WRITE_PORT(base,I_CMD_PORT,ISSUE_BYTE) +#define CLEAR_INTR(base) WRITE_PORT(base,I_ACK_PORT,ACK_BYTE) +#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) + +/* Define AMI's PCI codes */ +#undef PCI_VENDOR_ID_AMI +#undef PCI_DEVICE_ID_AMI_MEGARAID + +#ifndef PCI_VENDOR_ID_AMI +#define PCI_VENDOR_ID_AMI 0x101E +#define PCI_DEVICE_ID_AMI_MEGARAID 0x9010 +#endif + +#define PCI_CONF_BASE_ADDR_OFFSET 0x10 +#define PCI_CONF_IRQ_OFFSET 0x3c + +#if LINUX_VERSION_CODE < 0x20100 +#define MEGARAID \ + { NULL, /* Next */\ + NULL, /* Usage Count Pointer */\ + NULL, /* /proc Directory Entry */\ + megaraid_proc_info, /* /proc Info Function */\ + "MegaRAID", /* Driver Name */\ + megaraid_detect, /* Detect Host Adapter */\ + megaraid_release, /* Release Host Adapter */\ + megaraid_info, /* Driver Info Function */\ + megaraid_command, /* Command Function */\ + megaraid_queue, /* Queue Command Function */\ + megaraid_abort, /* Abort Command Function */\ + megaraid_reset, /* Reset Command Function */\ + NULL, /* Slave Attach Function */\ + megaraid_biosparam, /* Disk BIOS Parameters */\ + 1, /* # of cmds that can be\ + outstanding at any time */\ + 7, /* HBA Target ID */\ + MAX_SGLIST, /* Scatter/Gather Table Size */\ + 1, /* SCSI Commands per LUN */\ + 0, /* Present */\ + 0, /* Default Unchecked ISA DMA */\ + ENABLE_CLUSTERING } /* Enable Clustering */ +#else +#define MEGARAID \ + { NULL, /* Next */\ + NULL, /* Module */\ + NULL, /* /proc Directory Entry */\ + NULL, /* /proc/fs entry */\ + "MegaRAID", /* Driver Name */\ + megaraid_detect, /* Detect Host Adapter */\ + megaraid_release, /* Release Host Adapter */\ + megaraid_info, /* Driver Info Function */\ + NULL, /* Ioctl interface */\ + megaraid_command, /* Command Function */\ + megaraid_queue, /* Queue Command Function */\ + NULL,\ + NULL,\ + NULL,\ + NULL,\ + NULL,\ + megaraid_abort, /* Abort Command Function */\ + megaraid_reset, /* Reset Command Function */\ + NULL, /* Slave Attach Function */\ + megaraid_biosparam, /* Disk BIOS Parameters */\ + 255, /* Can Queue */\ + 7, /* HBA Target ID */\ + MAX_SGLIST, /* Scatter/Gather Table Size */\ + 1, /* SCSI Commands per LUN */\ + 0, /* Present */\ + 0, /* Default Unchecked ISA DMA */\ + ENABLE_CLUSTERING } /* Enable Clustering */ +#endif + + +/* Structures */ +typedef struct _mega_ADP_INFO +{ + u_char MaxConcCmds; + u_char RbldRate; + u_char MaxTargPerChan; + u_char ChanPresent; + u_char FwVer[4]; + u_short AgeOfFlash; + u_char ChipSet; + u_char DRAMSize; + u_char CacheFlushInterval; + u_char BiosVer[4]; + u_char resvd[7]; +} mega_ADP_INFO; + +typedef struct _mega_LDRV_INFO +{ + u_char NumLDrv; + u_char resvd[3]; + u_long LDrvSize[MAX_LOGICAL_DRIVES]; + u_char LDrvProp[MAX_LOGICAL_DRIVES]; + u_char LDrvState[MAX_LOGICAL_DRIVES]; +} mega_LDRV_INFO; + +typedef struct _mega_PDRV_INFO +{ + u_char PDrvState[MAX_PHYSICAL_DRIVES]; + u_char resvd; +} mega_PDRV_INFO; + +// RAID inquiry: Mailbox command 0x5 +typedef struct _mega_RAIDINQ +{ + mega_ADP_INFO AdpInfo; + mega_LDRV_INFO LogdrvInfo; + mega_PDRV_INFO PhysdrvInfo; +} mega_RAIDINQ; + +// Passthrough command: Mailbox command 0x3 +typedef struct mega_passthru +{ + u_char timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */ + u_char ars:1; + u_char reserved:3; + u_char islogical:1; + u_char logdrv; /* if islogical == 1 */ + u_char channel; /* if islogical == 0 */ + u_char target; /* if islogical == 0 */ + u_char queuetag; /* unused */ + u_char queueaction; /* unused */ + u_char cdb[MAX_CDB_LEN]; + u_char cdblen; + u_char reqsenselen; + u_char reqsensearea[MAX_REQ_SENSE_LEN]; + u_char numsgelements; + u_char scsistatus; + u_long dataxferaddr; + u_long dataxferlen; +} mega_passthru; + +typedef struct _mega_mailbox +{ + /* 0x0 */ u_char cmd; + /* 0x1 */ u_char cmdid; + /* 0x2 */ u_short numsectors; + /* 0x4 */ u_long lba; + /* 0x8 */ u_long xferaddr; + /* 0xC */ u_char logdrv; + /* 0xD */ u_char numsgelements; + /* 0xE */ u_char resvd; + /* 0xF */ u_char busy; + /* 0x10*/ u_char numstatus; + /* 0x11*/ u_char status; + /* 0x12*/ u_char completed[46]; + u_char mraid_poll; + u_char mraid_ack; + u_char pad[16]; +} mega_mailbox; + +typedef struct _mega_sglist +{ + u_long address; + u_long length; +} mega_sglist; + +/* Queued command data */ +typedef struct _mega_scb mega_scb; + +struct _mega_scb +{ + int idx; + u_long flag; + Scsi_Cmnd *SCpnt; + u_char mboxData[16]; + mega_passthru pthru; + mega_sglist *sgList; + mega_scb *next; +}; + +/* Per-controller data */ +typedef struct _mega_host_config +{ + u_char numldrv; + u_long flag; + u_long base; + + struct tq_struct megaTq; + + /* Host adapter parameters */ + u_char fwVer[7]; + u_char biosVer[7]; + + struct Scsi_Host *host; + + /* The following must be DMA-able!! */ + volatile mega_mailbox *mbox; + volatile mega_mailbox mailbox; + volatile u_char mega_buffer[2*1024L]; + + u_char max_cmds; + mega_scb scbList[MAX_COMMANDS]; +} mega_host_config; + +extern struct proc_dir_entry proc_scsi_megaraid; + +const char *megaraid_info( struct Scsi_Host * ); +int megaraid_detect( Scsi_Host_Template * ); +int megaraid_release(struct Scsi_Host *); +int megaraid_command( Scsi_Cmnd * ); +int megaraid_abort( Scsi_Cmnd * ); +int megaraid_reset( Scsi_Cmnd *, unsigned int); +int megaraid_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); +int megaraid_biosparam( Disk *, kdev_t, int * ); +int megaraid_proc_info( char *buffer, char **start, off_t offset, + int length, int hostno, int inout ); + +#endif diff -urN linux/include/linux/proc_fs.h linux-2.0.32-megaraid/include/linux/proc_fs.h --- linux/include/linux/proc_fs.h Tue Nov 18 14:46:46 1997 +++ linux-2.0.32-megaraid/include/linux/proc_fs.h Tue Aug 11 10:54:47 1998 @@ -137,6 +137,7 @@ PROC_SCSI_AM53C974, PROC_SCSI_SSC, PROC_SCSI_NCR53C406A, + PROC_SCSI_MEGARAID, PROC_SCSI_PPA, PROC_SCSI_ESP, PROC_SCSI_A3000,