home *** CD-ROM | disk | FTP | other *** search
Text File | 1998-08-29 | 50.3 KB | 3,345 lines |
- 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 <linux/config.h>
-
- +
-
- +#ifdef MODULE
-
- +#include <linux/version.h>
-
- +#include <linux/module.h>
-
- +
-
- +#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 <linux/types.h>
-
- +#include <linux/errno.h>
-
- +#include <linux/kernel.h>
-
- +#include <linux/sched.h>
-
- +#include <linux/malloc.h>
-
- +#include <linux/ioport.h>
-
- +#include <linux/fcntl.h>
-
- +#include <linux/delay.h>
-
- +#include <linux/pci.h>
-
- +#include <linux/proc_fs.h>
-
- +#include <linux/blk.h>
-
- +#include <linux/wait.h>
-
- +#include <linux/tqueue.h>
-
- +#include <linux/interrupt.h>
-
- +
-
- +#include <linux/sched.h>
-
- +#include <linux/stat.h>
-
- +#include <linux/malloc.h> /* for kmalloc() */
-
- +#include <linux/config.h> /* for CONFIG_PCI */
-
- +#if LINUX_VERSION_CODE <= 0x20100
-
- +#include <linux/bios32.h>
-
- +#endif
-
- +
-
- +#include <asm/io.h>
-
- +#include <asm/irq.h>
-
- +
-
- +#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; idx<megaCfg->max_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; idx<megaCfg->max_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; idx<qCnt; idx++) {
-
- + sIdx = mbox->completed[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; idx<scb->SCpnt->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; i<megaCfg->numldrv; 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; i<MAX_PHYSICAL_DRIVES; i++) {
-
- + if (i && !(i % 8)) printk("\n");
-
- + printk("%d: %x ", i, adapterInfo->PhysdrvInfo.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; idx<megaCfg->max_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; idx<megaCfg->max_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,
-
-