diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-13 16:29:25 +0000 |
commit | db7d4daea91e105e3859cf461d7e53b9b77454b2 (patch) | |
tree | 9bb65b95440af09e8aca63abe56970dd3360cc57 /drivers/scsi/megaraid.c | |
parent | 9c1c01ead627bdda9211c9abd5b758d6c687d8ac (diff) |
Merge with Linux 2.2.8.
Diffstat (limited to 'drivers/scsi/megaraid.c')
-rw-r--r-- | drivers/scsi/megaraid.c | 1655 |
1 files changed, 1007 insertions, 648 deletions
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 13882a253..05f95e626 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1,24 +1,27 @@ /*=================================================================== * * Linux MegaRAID device driver - * + * * Copyright 1998 American Megatrends Inc. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * Version : 0.92 + * Version : 1.00 * * Description: Linux device driver for AMI MegaRAID controller * + * Supported controllers: MegaRAID 418, 428, 438, 466, 762 + * + * Maintainer: Jeff L Jones <jeffreyj@ami.com> + * * 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. + * Original source contributed by Dell; integrated it into the kernel and + * cleaned up some things. Added support for 438/466 controllers. * * Version 0.91: * Aligned mailbox area on 16-byte boundry. @@ -35,43 +38,79 @@ * Removed setting of SA_INTERRUPT flag when requesting Irq. * * Version 0.92ac: - * Small changes to the comments/formatting. Plus a couple of - * added notes. Returned to the authors. No actual code changes - * save printk levels. - * 8 Oct 98 Alan Cox <alan.cox@linux.org> + * Small changes to the comments/formatting. Plus a couple of + * added notes. Returned to the authors. No actual code changes + * save printk levels. + * 8 Oct 98 Alan Cox <alan.cox@linux.org> * * Merged with 2.1.131 source tree. - * 12 Dec 98 K. Baranowski <kgb@knm.org.pl> + * 12 Dec 98 K. Baranowski <kgb@knm.org.pl> + * + * Version 0.93: + * Added support for vendor specific ioctl commands (0x80+xxh) + * Changed some fields in MEGARAID struct to better values. + * Added signature check for Rp controllers under 2.0 kernels + * Changed busy-wait loop to be time-based + * Fixed SMP race condition in isr + * Added kfree (sgList) on release + * Added #include linux/version.h to megaraid.h for hosts.h + * Changed max_id to represent max logical drives instead of targets. + * + * Version 0.94: + * Got rid of some excess locking/unlocking + * Fixed slight memory corruption problem while memcpy'ing into mailbox + * Changed logical drives to be reported as luns rather than targets + * Changed max_id to 16 since it is now max targets/chan again. + * Improved ioctl interface for upcoming megamgr + * + * Version 0.95: + * Fixed problem of queueing multiple commands to adapter; + * still has some strange problems on some setups, so still + * defaults to single. To enable parallel commands change + * #define MULTI_IO in megaraid.h + * Changed kmalloc allocation to be done in beginning. + * Got rid of C++ style comments + * + * Version 0.96: + * 762 fully supported. + * Version 0.97: + * Changed megaraid_command to use wait_queue. + * Fixed bug of undesirably detecting HP onboard controllers which + * are disabled. + * + * Version 1.00: + * Checks to see if an irq ocurred while in isr, and runs through + * routine again. + * Copies mailbox to temp area before processing in isr + * Added barrier() in busy wait to fix volatility bug + * Uses separate list for freed Scbs, keeps track of cmd state + * Put spinlocks around entire queue function for now... + * Full multi-io commands working stablely without previous problems + * Added skipXX LILO option for Madrona motherboard support + * * * BUGS: - * Tested with 2.1.90, but unfortunately there is a bug in pci.c which - * fails to detect our controller. Does work with 2.1.118--don't know - * which kernel in between it was fixed in. - * With SMP enabled under 2.1.118 with more than one processor, gets an - * error message "scsi_end_request: buffer-list destroyed" under heavy - * IO, but doesn't seem to affect operation, or data integrity. The - * message doesn't occur without SMP enabled, or with one proccessor with - * SMP enabled, or under any combination under 2.0 kernels. + * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that + * fails to detect the controller as a pci device on the system. + * + * Timeout period for mid scsi layer is too short for + * this controller. Must be increased or Aborts will occur. * *===================================================================*/ -#define QISR 1 #define CRLFSTR "\n" -#define MULTIQ 1 - #include <linux/version.h> #ifdef MODULE +#include <linux/modversions.h> #include <linux/module.h> #if LINUX_VERSION_CODE >= 0x20100 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"); +MODULE_AUTHOR ("American Megatrends Inc."); +MODULE_DESCRIPTION ("AMI MegaRAID driver"); #endif #endif @@ -112,14 +151,18 @@ MODULE_DESCRIPTION("AMI MegaRAID driver"); * * #Defines * - *================================================================*/ + *================================================================ + */ #if LINUX_VERSION_CODE < 0x020100 #define ioremap vremap #define iounmap vfree /* simulate spin locks */ -typedef struct {volatile char lock;} spinlock_t; +typedef struct { + volatile char lock; +} spinlock_t; + #define spin_lock_init(x) { (x)->lock = 0;} #define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();\ (x)->lock=1; save_flags(flags);\ @@ -143,7 +186,15 @@ typedef struct {volatile char lock;} spinlock_t; (*node) = obj; \ (*node)->##next = NULL; \ spin_unlock_irqrestore(&mega_lock,cpuflag);\ -}; +} + +/* a non-locking version (if we already have the lock) */ +#define ENQUEUE_NL(obj,type,list,next) \ +{ type **node; \ + for(node=&(list); *node; node=(type **)&(*node)->##next); \ + (*node) = obj; \ + (*node)->##next = NULL; \ +} #define DEQUEUE(obj,type,list,next) \ { long cpuflag; \ @@ -154,125 +205,146 @@ typedef struct {volatile char lock;} spinlock_t; spin_unlock_irqrestore(&mega_lock,cpuflag);\ }; -u_long RDINDOOR(mega_host_config *megaCfg) +u_long RDINDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base + 0x20); + return readl (megaCfg->base + 0x20); } -void WRINDOOR(mega_host_config *megaCfg, u_long value) +void WRINDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x20); + writel (value, megaCfg->base + 0x20); } -u_long RDOUTDOOR(mega_host_config *megaCfg) +u_long RDOUTDOOR (mega_host_config * megaCfg) { - return readl(megaCfg->base+0x2C); + return readl (megaCfg->base + 0x2C); } -void WROUTDOOR(mega_host_config *megaCfg, u_long value) +void WROUTDOOR (mega_host_config * megaCfg, u_long value) { - writel(value,megaCfg->base+0x2C); + writel (value, megaCfg->base + 0x2C); } /*================================================================ * * Function prototypes * - *================================================================*/ -static int MegaIssueCmd(mega_host_config *megaCfg, - u_char *mboxData, - mega_scb *scb, + *================================================================ + */ +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 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_host_config *,mega_scb *, int); +static int mega_busyWaitMbox(mega_host_config *); +static void mega_runpendq (mega_host_config *); +static void mega_rundoneq (void); +static void mega_cmd_done (mega_host_config *, mega_scb *, int); +static mega_scb *mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt); +static inline void freeSgList(mega_host_config *megaCfg); /* set SERDEBUG to 1 to enable serial debugging */ #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, ...); +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 }; + *================================================================ + */ + +/* Use "megaraid=skipXX" to prohibit driver from scanning XX scsi id + on each channel. Used for Madrona motherboard, where SAF_TE + processor id cannot be scanned */ +static char *megaraid; +#if LINUX_VERSION_CODE > 0x20100 +#ifdef MODULE +MODULE_PARM(megaraid, "s"); +#endif +#endif +static int skip_id; + +static int numCtlrs = 0; +static mega_host_config *megaCtlrs[12] = {0}; -/* Change this to 0 if you want to see the raw drives */ -static int use_raid = 1; +#if DEBUG +static u_long maxCmdTime = 0; +#endif + +static mega_scb *pLastScb = NULL; /* Queue of pending/completed SCBs */ -static mega_scb *qPending = NULL; static Scsi_Cmnd *qCompleted = NULL; +#if SERDEBUG +volatile static spinlock_t serial_lock; +#endif volatile static spinlock_t mega_lock; -static struct tq_struct runq = {0,0,mega_runque,NULL}; -struct proc_dir_entry proc_scsi_megaraid = { +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 char strbuf[MAX_SERBUF + 1]; -static void ser_init() +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); + 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) +static void ser_puts (char *str) { - char *ptr; + char *ptr; - ser_init(); - for (ptr=str;*ptr;++ptr) - ser_putc(*ptr); + ser_init (); + for (ptr = str; *ptr; ++ptr) + ser_putc (*ptr); } -static void ser_putc(char c) +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); - } + 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, ...) +static int ser_printk (const char *fmt,...) { - va_list args; - int i; - long flags; - - spin_lock_irqsave(mega_lock,flags); - va_start(args,fmt); - i = vsprintf(strbuf,fmt,args); - ser_puts(strbuf); - va_end(args); - spin_unlock_irqrestore(&mega_lock,flags); + va_list args; + int i; + long flags; + + spin_lock_irqsave(&serial_lock,flags); + va_start (args, fmt); + i = vsprintf (strbuf, fmt, args); + ser_puts (strbuf); + va_end (args); + spin_unlock_irqrestore(&serial_lock,flags); - return i; + return i; } #define TRACE(a) { ser_printk a;} @@ -281,14 +353,14 @@ static int ser_printk(const char *fmt, ...) #define TRACE(A) #endif -void callDone(Scsi_Cmnd *SCpnt) +void callDone (Scsi_Cmnd * SCpnt) { 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)); + TRACE (("*** %.08lx %.02x <%d.%d.%d> = %x\n", SCpnt->serial_number, + SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, + SCpnt->result)); } - SCpnt->scsi_done(SCpnt); + SCpnt->scsi_done (SCpnt); } /*------------------------------------------------------------------------- @@ -297,165 +369,164 @@ void callDone(Scsi_Cmnd *SCpnt) * *-------------------------------------------------------------------------*/ -/*================================================ - * Initialize SCB structures - *================================================*/ -static void initSCB(mega_host_config *megaCfg) +/*======================= + * Free a SCB structure + *======================= + */ +static void freeSCB (mega_host_config *megaCfg, mega_scb * pScb) { - int idx; + mega_scb **ppScb; - 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; + /* Unlink from pending queue */ + for(ppScb=&megaCfg->qPending; *ppScb; ppScb=&(*ppScb)->next) { + if (*ppScb == pScb) { + *ppScb = pScb->next; + break; + } } + + /* Link back into list */ + pScb->state = SCB_FREE; + pScb->SCpnt = NULL; + + pScb->next = megaCfg->qFree; + megaCfg->qFree = pScb; } /*=========================== * Allocate a SCB structure - *===========================*/ -static mega_scb *allocateSCB(mega_host_config *megaCfg,Scsi_Cmnd *SCpnt) + *=========================== + */ +static mega_scb * allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) { - int idx; - long flags; + mega_scb *pScb; - spin_lock_irqsave(&mega_lock,flags); - 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; - spin_unlock_irqrestore(&mega_lock,flags); - - if (megaCfg->scbList[idx].sgList == NULL) { - megaCfg->scbList[idx].sgList = - kmalloc(sizeof(mega_sglist)*MAX_SGLIST,GFP_ATOMIC|GFP_DMA); - } + /* Unlink command from Free List */ + if ((pScb = megaCfg->qFree) != NULL) { + megaCfg->qFree = pScb->next; + + pScb->isrcount = jiffies; + pScb->next = NULL; + pScb->state = SCB_ACTIVE; + pScb->SCpnt = SCpnt; - return &megaCfg->scbList[idx]; - } + return pScb; } - spin_unlock_irqrestore(&mega_lock,flags); - printk(KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); - + printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!\n"); + return NULL; } -/*======================= - * Free a SCB structure - *=======================*/ -static void freeSCB(mega_scb *scb) +/*================================================ + * Initialize SCB structures + *================================================ + */ +static int initSCB (mega_host_config * megaCfg) { - long flags; + int idx; - spin_lock_irqsave(&mega_lock,flags); - scb->flag = 0; - scb->idx = -1; - scb->next = NULL; - scb->SCpnt = NULL; - spin_unlock_irqrestore(&mega_lock,flags); + megaCfg->qFree = NULL; + for (idx = megaCfg->max_cmds-1; idx >= 0; idx--) { + megaCfg->scbList[idx].idx = idx; + megaCfg->scbList[idx].sgList = kmalloc(sizeof(mega_sglist) * MAX_SGLIST, + GFP_ATOMIC | GFP_DMA); + if (megaCfg->scbList[idx].sgList == NULL) { + printk(KERN_WARNING "Can't allocate sglist for id %d\n",idx); + freeSgList(megaCfg); + return -1; + } + + if (idx < MAX_COMMANDS) { + /* Link to free list */ + freeSCB(megaCfg, &megaCfg->scbList[idx]); + } + } + return 0; } /* Run through the list of completed requests */ -static void mega_rundoneq() +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; - } + Scsi_Cmnd *SCpnt; - /* 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; - } + while (1) { + DEQUEUE (SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + if (SCpnt == NULL) + return; /* Callback */ - callDone(SCpnt); + callDone (SCpnt); } } -/* Add command to the list of completed requests */ -static void mega_cmd_done(mega_host_config *megaCfg,mega_scb *pScb, int status) +/* + Runs through the list of pending requests + Assumes that mega_lock spin_lock has been acquired. +*/ +static void mega_runpendq(mega_host_config *megaCfg) { - pScb->SCpnt->result = status; - ENQUEUE(pScb->SCpnt, Scsi_Cmnd, qCompleted, host_scribble); - freeSCB(pScb); + mega_scb *pScb; + + /* Issue any pending commands to the card */ + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->state == SCB_ACTIVE) { + megaIssueCmd(megaCfg, pScb->mboxData, pScb, 1); + } + } } -/*---------------------------------------------------- - * Process pending queue list - * - * Run as a scheduled task - *----------------------------------------------------*/ -static void mega_runque(void *dummy) +/* Add command to the list of completed requests */ +static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, + int status) { - mega_host_config *megaCfg; - mega_scb *pScb; - long flags; + int islogical; + Scsi_Cmnd *SCpnt; - /* Take care of any completed requests */ - mega_rundoneq(); + if (pScb == NULL) { + TRACE(("NULL pScb in mega_cmd_done!")); + printk("NULL pScb in mega_cmd_done!"); + } - 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)) { - 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)); - } + SCpnt = pScb->SCpnt; + freeSCB(megaCfg, pScb); - if (MegaIssueCmd(megaCfg, pScb->mboxData, pScb, 1)) { - /* We're BUSY... come back later */ - spin_lock_irqsave(&mega_lock,flags); - pScb->next = qPending; - qPending = pScb; - spin_unlock_irqrestore(&mega_lock,flags); + if (SCpnt == NULL) { + TRACE(("NULL SCpnt in mega_cmd_done!")); + TRACE(("pScb->idx = ",pScb->idx)); + TRACE(("pScb->state = ",pScb->state)); + TRACE(("pScb->state = ",pScb->state)); + printk("Problem...!\n"); + while(1); + } - if (!(megaCfg->flag & PENDING)) { /* If PENDING, irq will schedule task */ - queue_task(&runq, &tq_scheduler); - } - } + islogical = (SCpnt->channel == megaCfg->host->max_channel && + SCpnt->target == 0); + if (SCpnt->cmnd[0] == INQUIRY && + ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && + !islogical) { + status = 0xF0; } + + SCpnt->result = 0; /* clear result; otherwise, success returns corrupt + value */ + + /* Convert MegaRAID status to Linux error code */ + switch (status) { + case 0x00: /* SUCCESS */ + case 0x02: /* ERROR_ABORTED */ + SCpnt->result |= (DID_OK << 16); + break; + case 0x8: /* ERR_DEST_DRIVE_FAILED */ + SCpnt->result |= (DID_BUS_BUSY << 16); + break; + default: + SCpnt->result |= (DID_BAD_TARGET << 16); + break; + } + + /* Add Scsi_Command to end of completed queue */ + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); } /*------------------------------------------------------------------- @@ -466,64 +537,82 @@ static void mega_runque(void *dummy) * 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) +static mega_scb * mega_build_cmd (mega_host_config * megaCfg, + Scsi_Cmnd * SCpnt) { - mega_scb *pScb; - mega_mailbox *mbox; + mega_scb *pScb; + mega_mailbox *mbox; mega_passthru *pthru; - long seg; + long seg; + char islogical; + + if (SCpnt == NULL) { + printk("NULL SCpnt in mega_build_cmd!\n"); + while(1); + } + + if (SCpnt->cmnd[0] & 0x80) /* ioctl from megamgr */ + return mega_ioctl (megaCfg, SCpnt); + + islogical = (SCpnt->channel == megaCfg->host->max_channel && SCpnt->target == 0); - /* We don't support multi-luns */ - if (SCpnt->lun != 0) { + if (!islogical && SCpnt->lun != 0) { SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } + if (!islogical && SCpnt->target == skip_id) { + SCpnt->result = (DID_BAD_TARGET << 16); + callDone (SCpnt); + return NULL; + } + /*----------------------------------------------------- * * Logical drive commands * *-----------------------------------------------------*/ - if (SCpnt->channel == megaCfg->host->max_channel) { - switch(SCpnt->cmnd[0]) { + if (islogical) { + switch (SCpnt->cmnd[0]) { case TEST_UNIT_READY: - memset(SCpnt->request_buffer, 0, SCpnt->request_bufflen); + memset (SCpnt->request_buffer, 0, SCpnt->request_bufflen); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case MODE_SENSE: - memset(SCpnt->request_buffer, 0, SCpnt->cmnd[4]); + memset (SCpnt->request_buffer, 0, SCpnt->cmnd[4]); SCpnt->result = (DID_OK << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; case READ_CAPACITY: case INQUIRY: /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + 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 = virt_to_bus(SCpnt->request_buffer); - pthru->dataxferlen = SCpnt->request_bufflen; - memcpy(pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len); + mbox = (mega_mailbox *) & pScb->mboxData; + + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; + pthru->islogical = 1; + pthru->logdrv = SCpnt->lun; + pthru->cdblen = SCpnt->cmd_len; + pthru->dataxferaddr = virt_to_bus (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 = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; @@ -532,51 +621,51 @@ static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) case READ_10: case WRITE_10: /* Allocate a SCB and initialize mailbox */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } - mbox = (mega_mailbox *)&pScb->mboxData; + 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) ? + memset (mbox, 0, sizeof (pScb->mboxData)); + mbox->logdrv = SCpnt->lun; + 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->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->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]; + ((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); + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); return pScb; - + default: SCpnt->result = (DID_BAD_TARGET << 16); - callDone(SCpnt); + callDone (SCpnt); return NULL; } } @@ -587,31 +676,32 @@ static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) *-----------------------------------------------------*/ else { /* Allocate a SCB and initialize passthru */ - if ((pScb = allocateSCB(megaCfg,SCpnt)) == NULL) { + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { SCpnt->result = (DID_ERROR << 16); - callDone(SCpnt); + 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; + mbox = (mega_mailbox *) pScb->mboxData; + + memset (mbox, 0, sizeof (pScb->mboxData)); + memset (pthru, 0, sizeof (mega_passthru)); + pthru->timeout = 0; + pthru->ars = 1; + pthru->reqsenselen = 14; 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); - + 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 = virt_to_bus(pthru); + mbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mbox->xferaddr = virt_to_bus (pthru); return pScb; } @@ -619,105 +709,229 @@ static mega_scb *mega_build_cmd(mega_host_config *megaCfg, Scsi_Cmnd *SCpnt) } /*-------------------------------------------------------------------- + * build RAID commands for controller, passed down through ioctl() + *--------------------------------------------------------------------*/ +static mega_scb * mega_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt) +{ + mega_scb *pScb; + mega_ioctl_mbox *mbox; + mega_mailbox *mailbox; + mega_passthru *pthru; + long seg; + unsigned char *data = (unsigned char *)SCpnt->request_buffer; + int i; + + if ((pScb = allocateSCB (megaCfg, SCpnt)) == NULL) { + SCpnt->result = (DID_ERROR << 16); + callDone (SCpnt); + return NULL; + } + +#if 0 + printk("\nBUF: "); + for (i=0;i<18;i++) { + printk(" %x",data[i]); + } + printk("......\n"); +#endif + + mbox = (mega_ioctl_mbox *) & pScb->mboxData; + mailbox = (mega_mailbox *) & pScb->mboxData; + memset (mailbox, 0, sizeof (pScb->mboxData)); + + if (data[0] == 0x03) { /* passthrough command */ + unsigned char cdblen = data[2]; + + pthru = &pScb->pthru; + memset (pthru, 0, sizeof (mega_passthru)); + pthru->islogical = (data[cdblen+3] & 0x80) ? 1:0; + pthru->timeout = data[cdblen+3] & 0x07; + pthru->reqsenselen = 14; + pthru->ars = (data[cdblen+3] & 0x08) ? 1:0; + pthru->logdrv = data[cdblen+4]; + pthru->channel = data[cdblen+5]; + pthru->target = data[cdblen+6]; + pthru->cdblen = cdblen; + memcpy (pthru->cdb, &data[3], cdblen); + + mailbox->cmd = MEGA_MBOXCMD_PASSTHRU; + mailbox->xferaddr = virt_to_bus (pthru); + + + pthru->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & pthru->dataxferaddr, + (u_long *) & pthru->dataxferlen); + + for (i=0;i<(SCpnt->request_bufflen-cdblen-7);i++) { + data[i] = data[i+cdblen+7]; + } + + return pScb; + } + /* else normal (nonpassthru) command */ + + mbox->cmd = data[0]; + mbox->channel = data[1]; + mbox->param = data[2]; + mbox->pad[0] = data[3]; + mbox->logdrv = data[4]; + + mbox->numsgelements = build_sglist (megaCfg, pScb, + (u_long *) & mbox->xferaddr, + (u_long *) & seg); + + for (i=0;i<(SCpnt->request_bufflen-6);i++) { + data[i] = data[i+6]; + } + + return (pScb); +} + +#if DEBUG +static void showMbox(mega_scb *pScb) +{ + mega_mailbox *mbox; + + if (pScb == NULL) return; + + mbox = (mega_mailbox *)pScb->mboxData; + printk("%u cmd:%x id:%x #scts:%x lba:%x addr:%x logdrv:%x #sg:%x\n", + pScb->SCpnt->pid, + mbox->cmd, mbox->cmdid, mbox->numsectors, + mbox->lba, mbox->xferaddr, mbox->logdrv, + mbox->numsgelements); +} +#endif + +/*-------------------------------------------------------------------- * Interrupt service routine *--------------------------------------------------------------------*/ -static void megaraid_isr(int irq, void *devp, struct pt_regs *regs) +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; + mega_host_config *megaCfg; + u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE]; + u_long dword; + mega_mailbox *mbox; + mega_scb *pScb; + long flags; + int qCnt, qStatus; - megaCfg = (mega_host_config *)devp; - mbox = (mega_mailbox *)megaCfg->mbox; + megaCfg = (mega_host_config *) devp; + mbox = (mega_mailbox *)tmpBox; - if (megaCfg->host->irq == irq) { - spin_lock_irqsave(&mega_lock,flags); +#if LINUX_VERSION_CODE >= 0x20100 + spin_lock_irqsave (&io_request_lock, flags); +#endif + + while (megaCfg->host->irq == irq) { + + spin_lock_irqsave (&mega_lock, flags); if (megaCfg->flag & IN_ISR) { - TRACE(("ISR called reentrantly!!\n")); + TRACE (("ISR called reentrantly!!\n")); } megaCfg->flag |= IN_ISR; + if (mega_busyWaitMbox(megaCfg)) { + printk(KERN_WARNING "Error: mailbox busy in isr!\n"); + } + + /* Check if a valid interrupt is pending */ if (megaCfg->flag & BOARD_QUARTZ) { - dword = RDOUTDOOR(megaCfg); - if (dword != 0x10001234) { - /* Spurious interrupt */ - megaCfg->flag &= ~IN_ISR; - spin_unlock_irqrestore(&mega_lock,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; - spin_unlock_irqrestore(&mega_lock,flags); - return; - } - WRITE_PORT(megaCfg->host->io_port, INTR_PORT, byte); + dword = RDOUTDOOR (megaCfg); + if (dword != 0x10001234) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); + break; + } + WROUTDOOR (megaCfg, dword); + + /* Copy to temp location */ + memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE); + + /* Acknowledge interrupt */ + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2); + while (RDINDOOR (megaCfg) & 0x02); } - - qCnt = mbox->numstatus; - qStatus = mbox->status; + else { + byte = READ_PORT (megaCfg->host->io_port, INTR_PORT); + if ((byte & VALID_INTR_BYTE) == 0) { + /* Spurious interrupt */ + megaCfg->flag &= ~IN_ISR; + spin_unlock_irqrestore (&mega_lock, flags); + break; + } + WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte); - if (qCnt > 1) {TRACE(("ISR: Received %d status\n", qCnt)) - printk(KERN_DEBUG "Got numstatus = %d\n",qCnt); + /* Copy to temp location */ + memcpy(tmpBox, (mega_mailbox *)megaCfg->mbox, MAILBOX_SIZE); + + /* Acknowledge interrupt */ + CLEAR_INTR (megaCfg->host->io_port); } - - for(idx=0; idx<qCnt; idx++) { + + qCnt = mbox->numstatus; + qStatus = mbox->status; + + for (idx = 0; idx < qCnt; idx++) { sIdx = mbox->completed[idx]; if (sIdx > 0) { - pScb = &megaCfg->scbList[sIdx-1]; - spin_unlock_irqrestore(&mega_lock,flags); /* locks within cmd_done */ - mega_cmd_done(megaCfg,&megaCfg->scbList[sIdx-1], qStatus); - spin_lock_irqsave(&mega_lock,flags); + pScb = &megaCfg->scbList[sIdx - 1]; + + /* ASSERT(pScb->state == SCB_ISSUED); */ + +#if DEBUG + if (((jiffies) - pScb->isrcount) > maxCmdTime) { + maxCmdTime = (jiffies) - pScb->isrcount; + printk("cmd time = %u\n", maxCmdTime); + } +#endif + + if (pScb->state == SCB_ABORTED) { + printk("Received aborted SCB! %u\n", (int)((jiffies)-pScb->isrcount)); + } + + /* Mark command as completed */ + mega_cmd_done(megaCfg, pScb, 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); - } + spin_unlock_irqrestore (&mega_lock, flags); megaCfg->flag &= ~IN_ISR; - megaCfg->flag &= ~PENDING; - - spin_unlock_irqrestore(&mega_lock,flags); - spin_lock_irqsave(&io_request_lock, flags); - mega_runque(NULL); - spin_unlock_irqrestore(&io_request_lock,flags); + mega_rundoneq(); -#if 0 - /* Queue as a delayed ISR routine */ - queue_task_irq_off(&runq, &tq_immediate); - mark_bh(IMMEDIATE_BH); + /* Loop through any pending requests */ + spin_lock_irqsave(&mega_lock, flags); + mega_runpendq(megaCfg); spin_unlock_irqrestore(&mega_lock,flags); -#endif - } + +#if LINUX_VERSION_CODE >= 0x20100 + spin_unlock_irqrestore (&io_request_lock, flags); +#endif } /*==================================================*/ /* Wait until the controller's mailbox is available */ /*==================================================*/ -static int busyWaitMbox(mega_host_config *megaCfg) +static int mega_busyWaitMbox (mega_host_config * megaCfg) { - mega_mailbox *mbox = (mega_mailbox *)megaCfg->mbox; - long counter; + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + long counter; - for(counter=0; counter<0xFFFFFF; counter++) { - if (!mbox->busy) return 0; + for (counter = 0; counter < 10000; counter++) { + if (!mbox->busy) { + return 0; + } + udelay (100); + barrier(); } - return -1; + return -1; /* give up after 1 second */ } /*===================================================== @@ -728,93 +942,113 @@ static int busyWaitMbox(mega_host_config *megaCfg) * 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) + *===================================================== + */ +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; - - mboxData[0x1] = (pScb ? pScb->idx+1 : 0x00); /* Set cmdid */ - mboxData[0xF] = 1; /* Set busy */ + mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox; + u_char byte; + u_long cmdDone; + Scsi_Cmnd *SCpnt; + + mboxData[0x1] = (pScb ? pScb->idx + 1: 0x0); /* Set cmdid */ + mboxData[0xF] = 1; /* Set busy */ - /* one bad report of problem when issuing a command while pending. - * Wasn't able to duplicate, but it doesn't really affect performance - * anyway, so don't allow command while PENDING - */ - if (megaCfg->flag & PENDING) { - return -1; +#if 0 + if (intr && mbox->busy) { + return 0; } +#endif /* 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)); + while (mega_busyWaitMbox (megaCfg)) { + printk("Blocked mailbox!!\n"); + udelay(1000); + +#if DEBUG + showMbox(pLastScb); +#endif + + /* Abort command */ + if (pScb == NULL) { + printk("NULL pScb in megaIssue\n"); + TRACE(("NULL pScb in megaIssue\n")); } - return -1; + SCpnt = pScb->SCpnt; + freeSCB(megaCfg, pScb); + + SCpnt->result = (DID_ABORT << 16); + callDone(SCpnt); + return 0; } + pLastScb = pScb; + /* Copy mailbox data into host structure */ - spin_lock_irqsave(&mega_lock,flags); - memset(mbox, 0, sizeof(mega_mailbox)); - memcpy(mbox, mboxData, 16); - spin_unlock_irqrestore(&mega_lock,flags); + memcpy (mbox, mboxData, 16); /* 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); + 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); } + pScb->state = SCB_ISSUED; } - else { /* Issue non-ISR (blocking) command */ - + else { /* Issue non-ISR (blocking) command */ + disable_irq(megaCfg->host->irq); if (megaCfg->flag & BOARD_QUARTZ) { + mbox->mraid_poll = 0; + mbox->mraid_ack = 0; + WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x1); - mbox->mraid_poll = 0; - mbox->mraid_ack = 0; - WRINDOOR(megaCfg, virt_to_bus(megaCfg->mbox) | 0x1); - - while((cmdDone=RDOUTDOOR(megaCfg)) != 0x10001234); - WROUTDOOR(megaCfg, cmdDone); + while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234); + WROUTDOOR (megaCfg, cmdDone); if (pScb) { - mega_cmd_done(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); } - WRINDOOR(megaCfg,virt_to_bus(megaCfg->mbox) | 0x2); - while(RDINDOOR(megaCfg) & 0x2); + 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); - + 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(megaCfg,pScb, mbox->status); - mega_rundoneq(); + mega_cmd_done (megaCfg, pScb, mbox->status); + mega_rundoneq (); + } + else { + TRACE (("Error: NULL pScb!\n")); } - megaCfg->flag &= ~PENDING; + } + enable_irq(megaCfg->host->irq); + } + while (mega_busyWaitMbox (megaCfg)) { + printk("Blocked mailbox on exit!\n"); + udelay(1000); } return 0; @@ -823,42 +1057,42 @@ static int MegaIssueCmd(mega_host_config *megaCfg, /*------------------------------------------------------------------- * Copies data to SGLIST *-------------------------------------------------------------------*/ -static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, - u_long *buffer, u_long *length) +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 = virt_to_bus(scb->SCpnt->request_buffer); - *length = (u_long)scb->SCpnt->request_bufflen; + *buffer = virt_to_bus (scb->SCpnt->request_buffer); + *length = (u_long) scb->SCpnt->request_bufflen; return 0; } - sgList = (struct scatterlist *)scb->SCpnt->buffer; + sgList = (struct scatterlist *) scb->SCpnt->request_buffer; if (scb->SCpnt->use_sg == 1) { - *buffer = virt_to_bus(sgList[0].address); - *length = (u_long)sgList[0].length; + *buffer = virt_to_bus (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 = virt_to_bus(sgList[idx].address); - scb->sgList[idx].length = (u_long)sgList[idx].length; + for (idx = 0; idx < scb->SCpnt->use_sg; idx++) { + scb->sgList[idx].address = virt_to_bus (sgList[idx].address); + scb->sgList[idx].length = (u_long) sgList[idx].length; } - + /* Reset pointer and length fields */ - *buffer = virt_to_bus(scb->sgList); + *buffer = virt_to_bus (scb->sgList); *length = 0; /* Return count of SG requests */ return scb->SCpnt->use_sg; } - + /*-------------------------------------------------------------------- - * Initializes the address of the controller's mailbox register + * 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 @@ -873,25 +1107,25 @@ static int build_sglist(mega_host_config *megaCfg, mega_scb *scb, * 10 01 numstatus byte * 11 01 status byte *--------------------------------------------------------------------*/ -static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr) +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; + 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); + 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; } @@ -899,77 +1133,80 @@ static int mega_register_mailbox(mega_host_config *megaCfg, u_long paddr) /*------------------------------------------------------------------- * Issue an adapter info query to the controller *-------------------------------------------------------------------*/ -static int mega_i_query_adapter(mega_host_config *megaCfg) +static int mega_i_query_adapter (mega_host_config * megaCfg) { mega_RAIDINQ *adapterInfo; mega_mailbox *mbox; - u_char mboxData[16]; - u_long paddr; + u_char mboxData[16]; + u_long paddr; + + spin_lock_init (&mega_lock); - spin_lock_init(&mega_lock); /* Initialize adapter inquiry */ - paddr = virt_to_bus(megaCfg->mega_buffer); - mbox = (mega_mailbox *)mboxData; + 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); + memset ((void *) megaCfg->mega_buffer, 0, sizeof (megaCfg->mega_buffer)); + memset (mbox, 0, 16); /* Initialize mailbox registers */ - mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; + mbox->cmd = MEGA_MBOXCMD_ADAPTERINQ; mbox->xferaddr = paddr; /* Issue a blocking command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); - + megaIssueCmd (megaCfg, mboxData, NULL, 0); + /* Initialize host/local structures with Adapter info */ - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + 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; +/* megaCfg->host->max_id = adapterInfo->AdpInfo.MaxTargPerChan; */ + megaCfg->host->max_id = 16; /* max targets/chan */ + megaCfg->numldrv = adapterInfo->LogdrvInfo.NumLDrv; #if 0 - printk(KERN_DEBUG "---- Logical drive info ----\n"); - for(i=0; i<megaCfg->numldrv; i++) { - printk(KERN_DEBUG "%d: size: %ld prop: %x state: %x\n",i, - adapterInfo->LogdrvInfo.LDrvSize[i], - adapterInfo->LogdrvInfo.LDrvProp[i], - adapterInfo->LogdrvInfo.LDrvState[i]); + printk ("KERN_DEBUG ---- 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(KERN_DEBUG "---- 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 (KERN_DEBUG "---- 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"); + 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); +#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->fwVer, adapterInfo->AdpInfo.FwVer, 4); + megaCfg->fwVer[4] = 0; - memcpy(megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); - megaCfg->biosVer[4] = 0; + memcpy (megaCfg->biosVer, adapterInfo->AdpInfo.BiosVer, 4); + megaCfg->biosVer[4] = 0; #endif - printk(KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, - megaCfg->fwVer, - megaCfg->biosVer, - megaCfg->numldrv); + printk (KERN_INFO "megaraid: [%s:%s] detected %d logical drives" CRLFSTR, + megaCfg->fwVer, + megaCfg->biosVer, + megaCfg->numldrv); return 0; } @@ -982,56 +1219,72 @@ static int mega_i_query_adapter(mega_host_config *megaCfg) /*---------------------------------------------------------- * 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) +int megaraid_proc_info (char *buffer, char **start, off_t offset, + int length, int host_no, int inout) { *start = buffer; return 0; } -int findCard(Scsi_Host_Template *pHostTmpl, - u_short pciVendor, u_short pciDev, - long flag) +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 = 0; + u_char pciBus, pciDevFun, megaIrq; + u_long megaBase; + u_short jdx,pciIdx = 0; + u_short numFound = 0; #if LINUX_VERSION_CODE < 0x20100 - while(!pcibios_find_device(pciVendor, pciDev, pciIdx,&pciBus,&pciDevFun)) { -#else - struct pci_dev *pdev=pci_devices; + while (!pcibios_find_device (pciVendor, pciDev, pciIdx, &pciBus, &pciDevFun)) { - while((pdev = pci_find_device(pciVendor, pciDev, pdev))) { +#if 0 + } /* keep auto-indenters happy */ +#endif +#else + + struct pci_dev *pdev = pci_devices; + + while ((pdev = pci_find_device (pciVendor, pciDev, pdev))) { pciBus = pdev->bus->number; pciDevFun = pdev->devfn; #endif - printk(KERN_INFO "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)); - + if (flag & BOARD_QUARTZ) { + u_short magic; + pcibios_read_config_word (pciBus, pciDevFun, + PCI_CONF_AMISIG, + &magic); + if (magic != AMI_SIGNATURE) { + pciIdx++; + continue; /* not an AMI board */ + } + } + printk (KERN_INFO "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 */ #if LINUX_VERSION_CODE < 0x20100 - pcibios_read_config_dword(pciBus, pciDevFun, - PCI_BASE_ADDRESS_0, - (u_int *)&megaBase); - pcibios_read_config_byte(pciBus, pciDevFun, - PCI_INTERRUPT_LINE, - &megaIrq); + pcibios_read_config_dword (pciBus, pciDevFun, + PCI_BASE_ADDRESS_0, + (u_int *) & megaBase); + pcibios_read_config_byte (pciBus, pciDevFun, + PCI_INTERRUPT_LINE, + &megaIrq); #else megaBase = pdev->base_address[0]; - megaIrq = pdev->irq; + megaIrq = pdev->irq; #endif pciIdx++; if (flag & BOARD_QUARTZ) { megaBase &= PCI_BASE_ADDRESS_MEM_MASK; - megaBase = (long) ioremap(megaBase,128); + megaBase = (long) ioremap (megaBase, 128); } else { megaBase &= PCI_BASE_ADDRESS_IO_MASK; @@ -1039,72 +1292,92 @@ int findCard(Scsi_Host_Template *pHostTmpl, } /* 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)); + 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); - printk(KERN_INFO " 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->qPending = NULL; + megaCfg->qFree = NULL; + 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; + 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); + 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_region (megaBase, 16, "megaraid"); } /* Request our IRQ */ - if (request_irq(megaIrq, megaraid_isr, SA_SHIRQ, - "megaraid", megaCfg)) { - printk(KERN_WARNING "megaraid: Couldn't register IRQ %d!" CRLFSTR, - megaIrq); - scsi_unregister(host); + if (request_irq (megaIrq, megaraid_isr, 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); + mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox)); + mega_i_query_adapter (megaCfg); + + for(jdx=0; jdx<MAX_LOGICAL_DRIVES; jdx++) { + megaCfg->nReads[jdx] = 0; + megaCfg->nWrites[jdx] = 0; + } /* Initialize SCBs */ - initSCB(megaCfg); + if (initSCB (megaCfg)) { + scsi_unregister (host); + continue; + } + numFound++; } - return pciIdx; + return numFound; } /*--------------------------------------------------------- * Detects if a megaraid controller exists in this system *---------------------------------------------------------*/ -int megaraid_detect(Scsi_Host_Template *pHostTmpl) +int megaraid_detect (Scsi_Host_Template * pHostTmpl) { int count = 0; pHostTmpl->proc_dir = &proc_scsi_megaraid; #if LINUX_VERSION_CODE < 0x20100 - if (!pcibios_present()) - { - printk(KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); - return 0; - } + if (!pcibios_present ()) { + printk (KERN_WARNING "megaraid: PCI bios not present." CRLFSTR); + return 0; + } #endif + skip_id = -1; + if (megaraid && !strncmp(megaraid,"skip",strlen("skip"))) { + if (megaraid[4] != '\0') { + skip_id = megaraid[4] - '0'; + if (megaraid[5] != '\0') { + skip_id = (skip_id * 10) + (megaraid[5] - '0'); + } + } + skip_id = (skip_id > 15) ? -1 : skip_id; + } - count += findCard(pHostTmpl, 0x101E, 0x9010, 0); - count += findCard(pHostTmpl, 0x101E, 0x9060, 0); - count += findCard(pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); + count += findCard (pHostTmpl, 0x101E, 0x9010, 0); + count += findCard (pHostTmpl, 0x101E, 0x9060, 0); + count += findCard (pHostTmpl, 0x8086, 0x1960, BOARD_QUARTZ); return count; } @@ -1112,54 +1385,66 @@ int megaraid_detect(Scsi_Host_Template *pHostTmpl) /*--------------------------------------------------------------------- * Release the controller's resources *---------------------------------------------------------------------*/ -int megaraid_release(struct Scsi_Host *pSHost) +int megaraid_release (struct Scsi_Host *pSHost) { mega_host_config *megaCfg; - mega_mailbox *mbox; - u_char mboxData[16]; + mega_mailbox *mbox; + u_char mboxData[16]; - megaCfg = (mega_host_config*)pSHost->hostdata; - mbox = (mega_mailbox *)mboxData; + megaCfg = (mega_host_config *) pSHost->hostdata; + mbox = (mega_mailbox *) mboxData; /* Flush cache to disk */ - memset(mbox, 0, 16); + memset (mbox, 0, 16); mboxData[0] = 0xA; - /* Issue a blocking (interrupts disabled) command to the card */ - MegaIssueCmd(megaCfg, mboxData, NULL, 0); + free_irq (megaCfg->host->irq, megaCfg);/* Must be freed first, otherwise + extra interrupt is generated */ - schedule(); + /* Issue a blocking (interrupts disabled) command to the card */ + megaIssueCmd (megaCfg, mboxData, NULL, 0); /* Free our resources */ if (megaCfg->flag & BOARD_QUARTZ) { - iounmap((void *)megaCfg->base); - } else { - release_region(megaCfg->host->io_port, 16); + 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); + + freeSgList(megaCfg); + scsi_unregister (pSHost); return 0; } +static inline void freeSgList(mega_host_config *megaCfg) +{ + int i; + + for (i = 0; i < megaCfg->max_cmds; i++) { + if (megaCfg->scbList[i].sgList) + kfree (megaCfg->scbList[i].sgList); /* free sgList */ + } +} + /*---------------------------------------------- * Get information about the card/driver *----------------------------------------------*/ -const char *megaraid_info(struct Scsi_Host *pSHost) +const char * megaraid_info (struct Scsi_Host *pSHost) { - static char buffer[512]; - mega_host_config *megaCfg; - mega_RAIDINQ *adapterInfo; + static char buffer[512]; + mega_host_config *megaCfg; + mega_RAIDINQ *adapterInfo; - megaCfg = (mega_host_config *)pSHost->hostdata; - adapterInfo = (mega_RAIDINQ *)megaCfg->mega_buffer; + 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); + 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; } @@ -1178,67 +1463,86 @@ const char *megaraid_info(struct Scsi_Host *pSHost) * 10 01 numstatus byte * 11 01 status byte *-----------------------------------------------------------------*/ -int megaraid_queue(Scsi_Cmnd *SCpnt, void (*pktComp)(Scsi_Cmnd *)) +int megaraid_queue (Scsi_Cmnd * SCpnt, void (*pktComp) (Scsi_Cmnd *)) { mega_host_config *megaCfg; - mega_scb *pScb; + mega_scb *pScb; + long flags; + + spin_lock_irqsave(&mega_lock,flags); - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg = (mega_host_config *) SCpnt->host->hostdata; if (!(megaCfg->flag & (1L << SCpnt->channel))) { - printk(KERN_INFO "scsi%d: scanning channel %c for devices.\n", - megaCfg->host->host_no, - SCpnt->channel + 'A'); + printk (KERN_INFO "scsi%d: scanning channel %c for devices.\n", + megaCfg->host->host_no, + SCpnt->channel + 'A'); megaCfg->flag |= (1L << SCpnt->channel); } SCpnt->scsi_done = pktComp; + /* If driver in abort or reset.. cancel this command */ + if (megaCfg->flag & IN_ABORT) { + SCpnt->result = (DID_ABORT << 16); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + + spin_unlock_irqrestore(&mega_lock,flags); + return 0; + } + else if (megaCfg->flag & IN_RESET) { + SCpnt->result = (DID_RESET << 16); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + + spin_unlock_irqrestore(&mega_lock,flags); + return 0; + } + /* Allocate and build a SCB request */ - if ((pScb = mega_build_cmd(megaCfg, SCpnt)) != NULL) { + if ((pScb = mega_build_cmd (megaCfg, SCpnt)) != NULL) { /* Add SCB to the head of the pending queue */ - ENQUEUE(pScb, mega_scb, qPending, next); + ENQUEUE_NL (pScb, mega_scb, megaCfg->qPending, next); - /* Issue the command to the card */ - mega_runque(NULL); + /* Issue any pending command to the card if not in ISR */ + if (!(megaCfg->flag & IN_ISR)) { + mega_runpendq(megaCfg); + } + else { + printk("IRQ pend...\n"); + } } + spin_unlock_irqrestore(&mega_lock,flags); + return 0; } /*---------------------------------------------------------------------- * Issue a blocking command to the controller - * - * Note - this isnt 2.0.x SMP safe *----------------------------------------------------------------------*/ -volatile static int internal_done_flag = 0; +volatile static int internal_done_flag = 0; volatile static int internal_done_errcode = 0; +static struct wait_queue *internal_wait = NULL; -static void internal_done(Scsi_Cmnd *SCpnt) +static void internal_done (Scsi_Cmnd * SCpnt) { internal_done_errcode = SCpnt->result; internal_done_flag++; + wake_up(&internal_wait); } -/* - * This seems dangerous in an SMP environment because - * while spinning on internal_done_flag in 2.0.x SMP - * no IRQ's will be taken, including those that might - * be needed to clear this. - * - * I think this should be using a wait queue ? - * -- AC - */ - -int megaraid_command(Scsi_Cmnd *SCpnt) +/* shouldn't be used, but included for completeness */ + +int megaraid_command (Scsi_Cmnd * SCpnt) { internal_done_flag = 0; /* Queue command, and wait until it has completed */ - megaraid_queue(SCpnt, internal_done); + megaraid_queue (SCpnt, internal_done); - while(!internal_done_flag) - barrier(); + while (!internal_done_flag) { + interruptible_sleep_on(&internal_wait); + } return internal_done_errcode; } @@ -1246,67 +1550,122 @@ int megaraid_command(Scsi_Cmnd *SCpnt) /*--------------------------------------------------------------------- * Abort a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_abort(Scsi_Cmnd *SCpnt) +int megaraid_abort (Scsi_Cmnd * SCpnt) { mega_host_config *megaCfg; - int idx; - long flags; + int rc, idx; + long flags; + mega_scb *pScb; - spin_lock_irqsave(&mega_lock,flags); + rc = SCSI_ABORT_SUCCESS; + + spin_lock_irqsave (&mega_lock, flags); + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg->flag |= IN_ABORT; + + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->SCpnt == SCpnt) { + /* Found an aborting command */ +#if DEBUG + showMbox(pScb); +#endif + + printk("Abort: %d %u\n", + SCpnt->timeout_per_command, + (uint)((jiffies) - pScb->isrcount)); + + switch(pScb->state) { + case SCB_ABORTED: /* Already aborted */ + rc = SCSI_ABORT_SNOOZE; + break; + case SCB_ISSUED: /* Waiting on ISR result */ + rc = SCSI_ABORT_PENDING; + pScb->state = SCB_ABORTED; + break; + } + } + } + +#if 0 + TRACE (("ABORT!!! %.08lx %.02x <%d.%d.%d>\n", + SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, + SCpnt->lun)); + for(pScb=megaCfg->qPending; pScb; pScb=pScb->next) { + if (pScb->SCpnt == SCpnt) { + ser_printk("** %d<%x> %c\n", pScb->SCpnt->pid, pScb->idx+1, + pScb->state == SCB_ACTIVE ? 'A' : 'I'); +#if DEBUG + showMbox(pScb); +#endif + } + } +#endif - 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) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + if (megaCfg->scbList[idx].state != SCB_FREE) { if (megaCfg->scbList[idx].SCpnt == SCpnt) { - freeSCB(&megaCfg->scbList[idx]); + freeSCB (megaCfg, &megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + SCpnt->result = (DID_ABORT << 16) | (SUGGEST_RETRY << 24); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); } } } - spin_unlock_irqrestore(&mega_lock,flags); - return SCSI_ABORT_SNOOZE; + + megaCfg->flag &= ~IN_ABORT; + + spin_unlock_irqrestore (&mega_lock, flags); + + mega_rundoneq(); + + return rc; } /*--------------------------------------------------------------------- * Reset a previous SCSI request *---------------------------------------------------------------------*/ -int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags) +int megaraid_reset (Scsi_Cmnd * SCpnt, unsigned int rstflags) { mega_host_config *megaCfg; - int idx; - long flags; + int idx; + long flags; - spin_lock_irqsave(&mega_lock,flags); + spin_lock_irqsave (&mega_lock, flags); + + megaCfg = (mega_host_config *) SCpnt->host->hostdata; - megaCfg = (mega_host_config *)SCpnt->host->hostdata; + megaCfg->flag |= IN_RESET; - TRACE(("RESET: %.08lx %.02x <%d.%d.%d>\n", - SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, - SCpnt->lun)); + 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) { + for (idx = 0; idx < megaCfg->max_cmds; idx++) { + if (megaCfg->scbList[idx].state != SCB_FREE) { SCpnt = megaCfg->scbList[idx].SCpnt; - freeSCB(&megaCfg->scbList[idx]); - SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY<<24); - callDone(SCpnt); + if (SCpnt != NULL) { + freeSCB (megaCfg, &megaCfg->scbList[idx]); + SCpnt->result = (DID_RESET << 16) | (SUGGEST_RETRY << 24); + ENQUEUE_NL(SCpnt, Scsi_Cmnd, qCompleted, host_scribble); + } } } - spin_unlock_irqrestore(&mega_lock,flags); + + megaCfg->flag &= ~IN_RESET; + + spin_unlock_irqrestore (&mega_lock, flags); + + mega_rundoneq(); return SCSI_RESET_PUNT; -} +} /*------------------------------------------------------------- * Return the disk geometry for a particular disk @@ -1318,23 +1677,23 @@ int megaraid_reset(Scsi_Cmnd *SCpnt, unsigned int rstflags) * geom[1] = sectors * geom[2] = cylinders *-------------------------------------------------------------*/ -int megaraid_biosparam(Disk *disk, kdev_t dev, int *geom) +int megaraid_biosparam (Disk * disk, kdev_t dev, int *geom) { - int heads, sectors, cylinders; + int heads, sectors, cylinders; mega_host_config *megaCfg; /* Get pointer to host config structure */ - megaCfg = (mega_host_config *)disk->device->host->hostdata; + megaCfg = (mega_host_config *) disk->device->host->hostdata; /* Default heads (64) & sectors (32) */ - 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; + heads = 255; + sectors = 63; cylinders = disk->capacity / (heads * sectors); } |