megaraid.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:136k
- /*===================================================================
- *
- * Linux MegaRAID device driver
- *
- * Copyright 2001 American Megatrends Inc.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- *
- * Version : v1.18 (Oct 11, 2001)
- *
- * Description: Linux device driver for LSI Logic MegaRAID controller
- *
- * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490
- * 493.
- * History:
- *
- * Version 0.90:
- * 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 boundary.
- * Added schedule() at the end to properly clean up.
- * Made improvements for conformity to linux driver standards.
- *
- * Version 0.92:
- * Added support for 2.1 kernels.
- * Reads from pci_dev struct, so it's not dependent on pcibios.
- * Added some missing virt_to_bus() translations.
- * Added support for SMP.
- * Changed global cli()'s to spinlocks for 2.1, and simulated
- * spinlocks for 2.0.
- * 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>
- *
- * Merged with 2.1.131 source tree.
- * 12 Dec 98 K. Baranowski <kgb@knm.org.pl>
- *
- * Version 0.93:
- * Added support for vendor specific ioctl commands (M_RD_IOCTL_CMD+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.
- *
- * Version 1.00:
- * Checks to see if an irq occurred 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
- *
- * Version 1.01:
- * Fixed bug in mega_cmd_done() for megamgr control commands,
- * the host_byte in the result code from the scsi request to
- * scsi midlayer is set to DID_BAD_TARGET when adapter's
- * returned codes are 0xF0 and 0xF4.
- *
- * Version 1.02:
- * Fixed the tape drive bug by extending the adapter timeout value
- * for passthrough command to 60 seconds in mega_build_cmd().
- *
- * Version 1.03:
- * Fixed Madrona support.
- * Changed the adapter timeout value from 60 sec in 1.02 to 10 min
- * for bigger and slower tape drive.
- * Added driver version printout at driver loadup time
- *
- * Version 1.04
- * Added code for 40 ld FW support.
- * Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
- * data area greater than 4 KB, which is the upper bound for data
- * tranfer through scsi_ioctl interface.
- * The additional 32 bit field for 64bit address in the newly defined
- * mailbox64 structure is set to 0 at this point.
- *
- * Version 1.05
- * Changed the queing implementation for handling SCBs and completed
- * commands.
- * Added spinlocks in the interrupt service routine to enable the driver
- * function in the SMP environment.
- * Fixed the problem of unnecessary aborts in the abort entry point, which
- * also enables the driver to handle large amount of I/O requests for
- * long duration of time.
- * Version 1.06
- * Intel Release
- * Version 1.07
- * Removed the usage of uaccess.h file for kernel versions less than
- * 2.0.36, as this file is not present in those versions.
- *
- * Version 108
- * Modified mega_ioctl so that 40LD megamanager would run
- * Made some changes for 2.3.XX compilation , esp wait structures
- * Code merge between 1.05 and 1.06 .
- * Bug fixed problem with ioctl interface for concurrency between
- * 8ld and 40ld firwmare
- * Removed the flawed semaphore logic for handling new config command
- * Added support for building own scatter / gather list for big user
- * mode buffers
- * Added /proc file system support ,so that information is available in
- * human readable format
- *
- * Version 1a08
- * Changes for IA64 kernels. Checked for CONFIG_PROC_FS flag
- *
- * Version 1b08
- * Include file changes.
- * Version 1b08b
- * Change PCI ID value for the 471 card, use #defines when searching
- * for megaraid cards.
- *
- * Version 1.10
- *
- * I) Changes made to make following ioctl commands work in 0x81 interface
- * a)DCMD_DELETE_LOGDRV
- * b)DCMD_GET_DISK_CONFIG
- * c)DCMD_DELETE_DRIVEGROUP
- * d)NC_SUBOP_ENQUIRY3
- * e)DCMD_CHANGE_LDNO
- * f)DCMD_CHANGE_LOOPID
- * g)DCMD_FC_READ_NVRAM_CONFIG
- * h)DCMD_WRITE_CONFIG
- * II) Added mega_build_kernel_sg function
- * III)Firmware flashing option added
- *
- * Version 1.10a
- *
- * I)Dell updates included in the source code.
- * Note: This change is not tested due to the unavailability of IA64 kernel
- * and it is in the #ifdef DELL_MODIFICATION macro which is not defined
- *
- * Version 1.10b
- *
- * I)In M_RD_IOCTL_CMD_NEW command the wrong way of copying the data
- * to the user address corrected
- *
- * Version 1.10c
- *
- * I) DCMD_GET_DISK_CONFIG opcode updated for the firmware changes.
- *
- * Version 1.11
- * I) Version number changed from 1.10c to 1.11
- * II) DCMD_WRITE_CONFIG(0x0D) command in the driver changed from
- * scatter/gather list mode to direct pointer mode..
- * Fixed bug of undesirably detecting HP onboard controllers which
- * are disabled.
- *
- * Version 1.12 (Sep 21, 2000)
- *
- * I. Changes have been made for Dynamic DMA mapping in IA64 platform.
- * To enable all these changes define M_RD_DYNAMIC_DMA_SUPPORT in megaraid.h
- * II. Got rid of windows mode comments
- * III. Removed unwanted code segments
- * IV. Fixed bug of HP onboard controller information (commented with
- * MEGA_HP_FIX)
- *
- * Version 1a12
- * I. reboot notifier and new ioctl changes ported from 1c09
- *
- * Version 1b12
- * I. Changes in new ioctl interface routines ( Nov 06, 2000 )
- *
- * Version 1c12
- * I. Changes in new ioctl interface routines ( Nov 07, 2000 )
- *
- * Version 1d12
- * I. Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
- *
- * Version 1e12, 1f12
- * 1. Fixes for pci_map_single, pci_alloc_consistent along with mailbox
- * alignment
- *
- * Version 1.13beta
- * Added Support for Full 64bit address space support. If firmware
- * supports 64bit, it goes to 64 bit mode even on x86 32bit
- * systems. Data Corruption Issues while running on test9 kernel
- * on IA64 systems. This issue not seen on test11 on x86 system
- *
- * Version 1.13c
- * 1. Resolved Memory Leak when using M_RD_IOCTL_CMD interface
- * 2. Resolved Queuing problem when MailBox Blocks
- * 3. Added unregister_reboot_notifier support
- *
- * Version 1.13d
- * Experimental changes in interfacing with the controller in ISR
- *
- * Version 1.13e
- * Fixed Broken 2.2.XX compilation changes + misc changes
- *
- * Version 1.13f to 1.13i
- * misc changes + code clean up
- * Cleaned up the ioctl code and added set_mbox_xfer_addr()
- * Support for START_DEV (6)
- *
- * Version 1.13j
- * Moved some code to megaraid.h file, replaced some hard coded values
- * with respective macros. Changed some functions to static
- *
- * Version 1.13k
- * Only some idendation correction to 1.13j
- *
- * Version 1.13l , 1.13m, 1.13n, 1.13o
- * Minor Identation changes + misc changes
- *
- * Version 1.13q
- * Paded the new uioctl_t MIMD structure for maintaining alignment
- * and size across 32 / 64 bit platforms
- * Changed the way MIMD IOCTL interface used virt_to_bus() to use pci
- * memory location
- *
- * Version 1.13r
- * 2.4.xx SCSI Changes.
- *
- * Version 1.13s
- * Stats counter fixes
- * Temporary fix for some 64 bit firmwares in 2.4.XX kernels
- *
- * Version 1.13t
- * Support for 64bit version of READ/WRITE/VIEW DISK CONFIG
- *
- * Version 1.14
- * Did away with MEGADEV_IOCTL flag. It is now standard part of driver
- * without need for a special #define flag
- * Disabled old scsi ioctl path for kernel versions > 2.3.xx. This is due
- * to the nature in which the new scsi code queues a new scsi command to
- * controller during SCSI IO Completion
- * Driver now checks for sub-system vendor id before taking ownership of
- * the controller
- *
- * Version 1.14a
- * Added Host re-ordering
- *
- * Version 1.14b
- * Corrected some issue which caused the older cards not to work
- *
- * Version 1.14c
- * IOCTL changes for not handling the non-64bit firmwares under 2.4.XX
- * kernel
- *
- * Version 1.14d
- * Fixed Various MIMD Synchronization Issues
- *
- * Version 1.14e
- * Fixed the error handling during card initialization
- *
- * Version 1.14f
- * Multiple invocations of mimd phase I ioctl stalls the cpu. Replaced
- * spinlock with semaphore(mutex)
- *
- * Version 1.14g
- * Fixed running out of scbs issues while running MIMD apps under heavy IO
- *
- * Version 1.14g-ac - 02/03/01
- * Reformatted to Linux format so I could compare to old one and cross
- * check bug fixes
- * Re fixed the assorted missing 'static' cases
- * Removed some unneeded version checks
- * Cleaned up some of the VERSION checks in the code
- * Left 2.0 support but removed 2.1.x support.
- * Collected much of the compat glue into one spot
- *
- * Version 1.14g-ac2 - 22/03/01
- * Fixed a non obvious dereference after free in the driver unload path
- *
- * Version 1.14i
- * changes for making 32bit application run on IA64
- *
- * Version 1.14j
- * Tue Mar 13 14:27:54 EST 2001 - AM
- * Changes made in the driver to be able to run applications if the
- * system has memory >4GB.
- *
- *
- * Version 1.14k
- * Thu Mar 15 18:38:11 EST 2001 - AM
- *
- * Firmware version check removed if subsysid==0x1111 and
- * subsysvid==0x1111, since its not yet initialized.
- *
- * changes made to correctly calculate the base in mega_findCard.
- *
- * Driver informational messages now appear on the console as well as
- * with dmesg
- *
- * Older ioctl interface is returned failure on newer(2.4.xx) kernels.
- *
- * Inclusion of "modversions.h" is still a debatable question. It is
- * included anyway with this release.
- *
- * Version 1.14l
- * Mon Mar 19 17:39:46 EST 2001 - AM
- *
- * Assorted changes to remove compilation error in 1.14k when compiled
- * with kernel < 2.4.0
- *
- * Version 1.14m
- * Tue Mar 27 12:09:22 EST 2001 - AM
- *
- * Added support for extended CDBs ( > 10 bytes ) and OBDR ( One Button
- * Disaster Recovery ) feature.
- *
- *
- * Version 1.14n
- * Tue Apr 10 14:28:13 EDT 2001 - AM
- *
- * "modeversions.h" is no longer included in the code.
- * 2.4.xx style mutex initialization used for older kernels also
- *
- * Version 1.14o
- * Wed Apr 18 17:47:26 EDT 2001 - PJ
- *
- * Before returning status for 'inquiry', we first check if request buffer
- * is SG list, and then return appropriate status
- *
- * Version 1.14p
- * Wed Apr 25 13:44:48 EDT 2001 - PJ
- *
- * SCSI result made appropriate in case of check conditions for extended
- * passthru commands
- *
- * Do not support lun >7 for physically accessed devices
- *
- *
- * Version 1.15
- * Thu Apr 19 09:38:38 EDT 2001 - AM
- *
- * 1.14l rollover to 1.15 - merged with main trunk after 1.15d
- *
- * Version 1.15b
- * Wed May 16 20:10:01 EDT 2001 - AM
- *
- * "modeversions.h" is no longer included in the code.
- * 2.4.xx style mutex initialization used for older kernels also
- * Brought in-sync with Alan's changes in 2.4.4
- * Note: 1.15a is on OBDR branch(main trunk), and is not merged with yet.
- *
- * Version 1.15c
- * Mon May 21 23:10:42 EDT 2001 - AM
- *
- * ioctl interface uses 2.4.x conforming pci dma calls
- * similar calls used for older kernels
- *
- * Version 1.15d
- * Wed May 30 17:30:41 EDT 2001 - AM
- *
- * NULL is not a valid first argument for pci_alloc_consistent() on
- * IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
- * "pci_dev" before making calls to pci interface routines.
- *
- * Version 1.16pre
- * Fri Jun 1 19:40:48 EDT 2001 - AM
- *
- * 1.14p and 1.15d merged
- * ROMB support added
- *
- * Version 1.16-pre1
- * Mon Jun 4 15:01:01 EDT 2001 - AM
- *
- * Non-ROMB firmware do no DMA support 0xA9 command. Value 0xFF
- * (all channels are raid ) is chosen for those firmware.
- *
- * Version 1.16-pre2
- * Mon Jun 11 18:15:31 EDT 2001 - AM
- *
- * Changes for boot from any logical drive
- *
- * Version 1.16
- * Tue Jun 26 18:07:02 EDT 2001 - AM
- *
- * branched at 1.14p
- *
- * Check added for HP 1M/2M controllers if having firmware H.01.07 or
- * H.01.08. If found, disable 64 bit support since these firmware have
- * limitations for 64 bit addressing
- *
- *
- * Version 1.17
- * Thu Jul 12 11:14:09 EDT 2001 - AM
- *
- * 1.16pre2 and 1.16 merged.
- *
- * init_MUTEX and init_MUTEX_LOCKED are defined in 2.2.19. Pre-processor
- * statements are added for them
- *
- * Linus's 2.4.7pre3 kernel introduces a new field 'max_sectors' in Scsi_Host
- * structure, to improve IO performance.
- *
- *
- * Version 1.17a
- * Fri Jul 13 18:44:01 EDT 2001 - AM
- *
- * Starting from kernel 2.4.x, LUN is not < 8 - following SCSI-III. So to have
- * our current formula working to calculate logical drive number, return
- * failure for LUN > 7
- *
- *
- * Version 1.17b
- * Mon Jul 30 19:24:02 EDT 2001 - AM
- *
- * Added support for random deletion of logical drives
- *
- * Version 1.17c
- * Tue Sep 25 09:37:49 EDT 2001 - Atul Mukker <atulm@lsil.com>
- *
- * With single and dual channel controllers, some virtaul channels are
- * displayed negative.
- *
- * Version 1.17a-ac
- * Mon Aug 6 14:59:29 BST 2001 - "Michael Johnson" <johnsom@home.com>
- *
- * Make the HP print formatting and check for buggy firmware runtime not
- * ifdef dependant.
- *
- *
- * Version 1.17d
- * Thu Oct 11 10:48:45 EDT 2001 - Atul Mukker <atulm@lsil.com>
- *
- * Driver 1.17c oops when loaded without controller.
- *
- * Special case for "use_sg == 1" removed while building the scatter gather
- * list.
- *
- * Version 1.18
- * Thu Oct 11 15:02:53 EDT 2001 - Atul Mukker <atulm@lsil.com>
- *
- * References to AMI have been changed to LSI Logic.
- *
- *
- * BUGS:
- * Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
- * fails to detect the controller as a pci device on the system.
- *
- * Timeout period for upper scsi layer, i.e. SD_TIMEOUT in
- * /drivers/scsi/sd.c, is too short for this controller. SD_TIMEOUT
- * value must be increased to (30 * HZ) otherwise false timeouts
- * will occur in the upper layer.
- *
- * Never set skip_id. The existing PCI code the megaraid uses fails
- * to properly check the vendor subid in some cases. Setting this then
- * makes it steal other i960's and crashes some boxes
- *
- * Far too many ifdefs for versions.
- *
- *===================================================================*/
- #include <linux/config.h>
- #include <linux/version.h>
- #include <linux/module.h>
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/string.h>
- #include <linux/kernel.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/mm.h>
- #include <asm/pgtable.h>
- #include <linux/sched.h>
- #include <linux/stat.h>
- #include <linux/slab.h> /* for kmalloc() */
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) /* 0x20100 */
- #include <linux/bios32.h>
- #else
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) /* 0x20300 */
- #include <asm/spinlock.h>
- #else
- #include <linux/spinlock.h>
- #endif
- #endif
- #include <asm/io.h>
- #include <asm/irq.h>
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /* 0x020024 */
- #include <asm/uaccess.h>
- #endif
- /*
- * These header files are required for Shutdown Notification routines
- */
- #include <linux/notifier.h>
- #include <linux/reboot.h>
- #include <linux/init.h>
- #include "sd.h"
- #include "scsi.h"
- #include "hosts.h"
- #include "megaraid.h"
- /*
- *================================================================
- * #Defines
- *================================================================
- */
- #define MAX_SERBUF 160
- #define COM_BASE 0x2f8
- static ulong RDINDOOR (mega_host_config * megaCfg)
- {
- return readl (megaCfg->base + 0x20);
- }
- static void WRINDOOR (mega_host_config * megaCfg, ulong value)
- {
- writel (value, megaCfg->base + 0x20);
- }
- static ulong RDOUTDOOR (mega_host_config * megaCfg)
- {
- return readl (megaCfg->base + 0x2C);
- }
- static void WROUTDOOR (mega_host_config * megaCfg, ulong value)
- {
- writel (value, megaCfg->base + 0x2C);
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */
- #include <linux/smp.h>
- #define cpuid smp_processor_id()
- #endif
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
- #define scsi_set_pci_device(x,y)
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */
- /*
- * Linux 2.4 and higher
- *
- * No driver private lock
- * Use the io_request_lock not cli/sti
- * queue task is a simple api without irq forms
- */
- MODULE_AUTHOR ("LSI Logic Corporation");
- MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
- MODULE_LICENSE ("GPL");
- #define DRIVER_LOCK_T
- #define DRIVER_LOCK_INIT(p)
- #define DRIVER_LOCK(p)
- #define DRIVER_UNLOCK(p)
- #define IO_LOCK_T unsigned long io_flags = 0
- #define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
- #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
- #define queue_task_irq(a,b) queue_task(a,b)
- #define queue_task_irq_off(a,b) queue_task(a,b)
- #elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) /* 0x020200 */
- /*
- * Linux 2.2 and higher
- *
- * No driver private lock
- * Use the io_request_lock not cli/sti
- * No pci region api
- * queue_task is now a single simple API
- */
- static char kernel_version[] = UTS_RELEASE;
- MODULE_AUTHOR ("LSI Logic Corporation");
- MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
- #define DRIVER_LOCK_T
- #define DRIVER_LOCK_INIT(p)
- #define DRIVER_LOCK(p)
- #define DRIVER_UNLOCK(p)
- #define IO_LOCK_T unsigned long io_flags = 0
- #define IO_LOCK spin_lock_irqsave(&io_request_lock,io_flags);
- #define IO_UNLOCK spin_unlock_irqrestore(&io_request_lock,io_flags);
- #define pci_free_consistent(a,b,c,d)
- #define pci_unmap_single(a,b,c,d)
- #define pci_enable_device(x) (0)
- #define queue_task_irq(a,b) queue_task(a,b)
- #define queue_task_irq_off(a,b) queue_task(a,b)
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */
- #define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)
- #define init_MUTEX(x) (*(x)=MUTEX)
- #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
- #endif
- #else
- /*
- * Linux 2.0 macros. Here we have to provide some of our own
- * functionality. We also only work little endian 32bit.
- * Again no pci_alloc/free api
- * IO_LOCK/IO_LOCK_T were never used in 2.0 so now are empty
- */
-
- #define cpuid 0
- #define DRIVER_LOCK_T long cpu_flags;
- #define DRIVER_LOCK_INIT(p)
- #define DRIVER_LOCK(p)
- save_flags(cpu_flags);
- cli();
- #define DRIVER_UNLOCK(p)
- restore_flags(cpu_flags);
- #define IO_LOCK_T
- #define IO_LOCK(p)
- #define IO_UNLOCK(p)
- #define le32_to_cpu(x) (x)
- #define cpu_to_le32(x) (x)
- #define pci_free_consistent(a,b,c,d)
- #define pci_unmap_single(a,b,c,d)
- #define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)
- #define init_MUTEX(x) (*(x)=MUTEX)
- #define pci_enable_device(x) (0)
- /*
- * 2.0 lacks spinlocks, iounmap/ioremap
- */
- #define ioremap vremap
- #define iounmap vfree
- /* simulate spin locks */
- typedef struct {
- volatile char lock;
- } spinlock_t;
- #define spin_lock_init(x) { (x)->lock = 0;}
- #define spin_lock_irqsave(x,flags) { while ((x)->lock) barrier();
- (x)->lock=1; save_flags(flags);
- cli();}
- #define spin_unlock_irqrestore(x,flags) { (x)->lock=0; restore_flags(flags);}
- #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */
- #define dma_alloc_consistent pci_alloc_consistent
- #define dma_free_consistent pci_free_consistent
- #else
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */
- typedef unsigned long dma_addr_t;
- #endif
- void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
- void dma_free_consistent(void *, size_t, void *, dma_addr_t);
- int mega_get_order(int);
- int pow_2(int);
- #endif
- /* 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, ...);
- #endif
- #ifdef CONFIG_PROC_FS
- #define COPY_BACK if (offset > megaCfg->procidx) {
- *eof = TRUE;
- megaCfg->procidx = 0;
- megaCfg->procbuf[0] = 0;
- return 0;}
- if ((count + offset) > megaCfg->procidx) {
- count = megaCfg->procidx - offset;
- *eof = TRUE; }
- memcpy(page, &megaCfg->procbuf[offset], count);
- megaCfg->procidx = 0;
- megaCfg->procbuf[0] = 0;
- #endif
- /*
- * ================================================================
- * Global variables
- *================================================================
- */
- /* Use "megaraid=skipXX" as LILO option to prohibit driver from scanning
- XX scsi id on each channel. Used for Madrona motherboard, where SAF_TE
- processor id cannot be scanned */
- static char *megaraid;
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) /* 0x20100 */
- #ifdef MODULE
- MODULE_PARM (megaraid, "s");
- #endif
- #endif
- static int skip_id = -1;
- static int numCtlrs = 0;
- static mega_host_config *megaCtlrs[FC_MAX_CHANNELS] = { 0 };
- static struct proc_dir_entry *mega_proc_dir_entry;
- #if DEBUG
- static u32 maxCmdTime = 0;
- #endif
- static mega_scb *pLastScb = NULL;
- static struct notifier_block mega_notifier = {
- megaraid_reboot_notify,
- NULL,
- 0
- };
- /* For controller re-ordering */
- struct mega_hbas mega_hbas[MAX_CONTROLLERS];
- /*
- * The File Operations structure for the serial/ioctl interface of the driver
- */
- /* For controller re-ordering */
- static struct file_operations megadev_fops = {
- ioctl:megadev_ioctl_entry,
- open:megadev_open,
- release:megadev_close,
- };
- /*
- * Array to structures for storing the information about the controllers. This
- * information is sent to the user level applications, when they do an ioctl
- * for this information.
- */
- static struct mcontroller mcontroller[MAX_CONTROLLERS];
- /* The current driver version */
- static u32 driver_ver = 114;
- /* major number used by the device for character interface */
- static int major;
- static struct semaphore mimd_ioctl_sem;
- static struct semaphore mimd_entry_mtx;
- #if SERDEBUG
- volatile static spinlock_t serial_lock;
- #endif
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) /* 0x20300 */
- static struct proc_dir_entry proc_scsi_megaraid = {
- PROC_SCSI_MEGARAID, 8, "megaraid",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
- };
- #endif
- #ifdef CONFIG_PROC_FS
- extern struct proc_dir_entry proc_root;
- #endif
- static char mega_ch_class; /* channels are raid or scsi */
- #define IS_RAID_CH(ch) ( (mega_ch_class >> (ch)) & 0x01 )
- #if SERDEBUG
- static char strbuf[MAX_SERBUF + 1];
- static void ser_init (void)
- {
- 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;
- 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;
- }
- #define TRACE(a) { ser_printk a;}
- #else
- #define TRACE(A)
- #endif
- #define TRACE1(a)
- static void callDone (Scsi_Cmnd * SCpnt)
- {
- if (SCpnt->result) {
- TRACE (("*** %.08lx %.02x <%d.%d.%d> = %xn",
- SCpnt->serial_number, SCpnt->cmnd[0], SCpnt->channel,
- SCpnt->target, SCpnt->lun, SCpnt->result));
- }
- SCpnt->scsi_done (SCpnt);
- }
- /*-------------------------------------------------------------------------
- *
- * Local functions
- *
- *-------------------------------------------------------------------------*/
- /*=======================
- * Free a SCB structure
- *=======================
- */
- static void mega_freeSCB (mega_host_config * megaCfg, mega_scb * pScb)
- {
- mega_scb *pScbtmp;
- if ((pScb == NULL) || (pScb->idx >= 0xFE)) {
- return;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- switch (pScb->dma_type) {
- case M_RD_DMA_TYPE_NONE:
- break;
- case M_RD_PTHRU_WITH_BULK_DATA:
- pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
- pScb->pthru->dataxferlen,
- pScb->dma_direction);
- break;
- case M_RD_EPTHRU_WITH_BULK_DATA:
- pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
- pScb->epthru->dataxferlen,
- pScb->dma_direction);
- break;
- case M_RD_PTHRU_WITH_SGLIST:
- {
- int count;
- for (count = 0; count < pScb->sglist_count; count++) {
- pci_unmap_single (megaCfg->dev,
- pScb->dma_h_sglist[count],
- pScb->sgList[count].length,
- pScb->dma_direction);
- }
- break;
- }
- case M_RD_BULK_DATA_ONLY:
- pci_unmap_single (megaCfg->dev,
- pScb->dma_h_bulkdata,
- pScb->iDataSize, pScb->dma_direction);
- break;
- case M_RD_SGLIST_ONLY:
- pci_unmap_sg (megaCfg->dev,
- pScb->SCpnt->request_buffer,
- pScb->SCpnt->use_sg, pScb->dma_direction);
- break;
- default:
- break;
- }
- #endif
- /* Unlink from pending queue */
- if (pScb == megaCfg->qPendingH) {
- if (megaCfg->qPendingH == megaCfg->qPendingT)
- megaCfg->qPendingH = megaCfg->qPendingT = NULL;
- else
- megaCfg->qPendingH = megaCfg->qPendingH->next;
- megaCfg->qPcnt--;
- } else {
- for (pScbtmp = megaCfg->qPendingH; pScbtmp;
- pScbtmp = pScbtmp->next) {
- if (pScbtmp->next == pScb) {
- pScbtmp->next = pScb->next;
- if (pScb == megaCfg->qPendingT) {
- megaCfg->qPendingT = pScbtmp;
- }
- megaCfg->qPcnt--;
- break;
- }
- }
- }
- /* Link back into free list */
- pScb->state = SCB_FREE;
- pScb->SCpnt = NULL;
- if (megaCfg->qFreeH == (mega_scb *) NULL) {
- megaCfg->qFreeH = megaCfg->qFreeT = pScb;
- } else {
- megaCfg->qFreeT->next = pScb;
- megaCfg->qFreeT = pScb;
- }
- megaCfg->qFreeT->next = NULL;
- megaCfg->qFcnt++;
- }
- /*===========================
- * Allocate a SCB structure
- *===========================
- */
- static mega_scb *mega_allocateSCB (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
- {
- mega_scb *pScb;
- /* Unlink command from Free List */
- if ((pScb = megaCfg->qFreeH) != NULL) {
- megaCfg->qFreeH = pScb->next;
- megaCfg->qFcnt--;
- pScb->isrcount = jiffies;
- pScb->next = NULL;
- pScb->state = SCB_ACTIVE;
- pScb->SCpnt = SCpnt;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pScb->dma_type = M_RD_DMA_TYPE_NONE;
- #endif
- return pScb;
- }
- printk (KERN_WARNING "Megaraid: Could not allocate free SCB!!!n");
- return NULL;
- }
- /* Run through the list of completed requests and finish it */
- static void mega_rundoneq (mega_host_config * megaCfg)
- {
- Scsi_Cmnd *SCpnt;
- while ((SCpnt = megaCfg->qCompletedH) != NULL) {
- megaCfg->qCompletedH = (Scsi_Cmnd *) SCpnt->host_scribble;
- megaCfg->qCcnt--;
- SCpnt->host_scribble = (unsigned char *) NULL; /* XC : sep 14 */
- /* Callback */
- callDone (SCpnt);
- }
- megaCfg->qCompletedH = megaCfg->qCompletedT = NULL;
- }
- /*
- * Runs through the list of pending requests
- * Assumes that mega_lock spin_lock has been acquired.
- */
- static int mega_runpendq (mega_host_config * megaCfg)
- {
- mega_scb *pScb;
- int rc;
- /* Issue any pending commands to the card */
- for (pScb = megaCfg->qPendingH; pScb; pScb = pScb->next) {
- if (pScb->state == SCB_ACTIVE) {
- if ((rc =
- megaIssueCmd (megaCfg, pScb->mboxData, pScb, 1)) == -1)
- return rc;
- }
- }
- return 0;
- }
- /* Add command to the list of completed requests */
- static void mega_cmd_done (mega_host_config * megaCfg, mega_scb * pScb, int status)
- {
- int islogical;
- Scsi_Cmnd *SCpnt;
- mega_passthru *pthru;
- mega_ext_passthru *epthru;
- mega_mailbox *mbox;
- struct scatterlist *sgList;
- u8 c;
- if (pScb == NULL) {
- TRACE (("NULL pScb in mega_cmd_done!"));
- printk(KERN_CRIT "NULL pScb in mega_cmd_done!");
- }
- SCpnt = pScb->SCpnt;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pthru = pScb->pthru;
- epthru = pScb->epthru;
- #else
- pthru = &pScb->pthru;
- epthru = &pScb->epthru;
- #endif
- mbox = (mega_mailbox *) & pScb->mboxData;
- 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));
- panic(KERN_ERR "megaraid:Problem...!n");
- }
- islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
- (SCpnt->channel <= megaCfg->host->max_channel) );
- #if 0
- islogical = (SCpnt->channel == megaCfg->host->max_channel);
- #endif
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* Special Case to handle PassThrough->XferAddrress > 4GB */
- switch (SCpnt->cmnd[0]) {
- case INQUIRY:
- case READ_CAPACITY:
- memcpy (SCpnt->request_buffer,
- pScb->bounce_buffer, SCpnt->request_bufflen);
- break;
- }
- #endif
- mega_freeSCB (megaCfg, pScb);
- /*
- * Do not return the presence of hard disk on the channel so, inquiry
- * sent, and returned data==hard disk or removable hard disk and not
- * logical, request should return failure! - PJ
- */
- #if 0
- if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
- status = 0xF0;
- }
- #endif
- if (SCpnt->cmnd[0] == INQUIRY && !islogical) {
- if ( SCpnt->use_sg ) {
- sgList = (struct scatterlist *)SCpnt->request_buffer;
- memcpy(&c, sgList[0].address, 0x1);
- } else {
- memcpy(&c, SCpnt->request_buffer, 0x1);
- }
- #if 0
- if( (c & 0x1F ) == TYPE_DISK ) {
- status = 0xF0;
- }
- #endif
- if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
- status = 0xF0;
- }
- }
- /* clear result; otherwise, success returns corrupt value */
- SCpnt->result = 0;
- if ((SCpnt->cmnd[0] & M_RD_IOCTL_CMD)) { /* i.e. ioctl cmd such as M_RD_IOCTL_CMD, M_RD_IOCTL_CMD_NEW of megamgr */
- switch (status) {
- case 2:
- case 0xF0:
- case 0xF4:
- SCpnt->result = (DID_BAD_TARGET << 16) | status;
- break;
- default:
- SCpnt->result |= status;
- } /*end of switch */
- } else {
- /* Convert MegaRAID status to Linux error code */
- switch (status) {
- case 0x00: /* SUCCESS , i.e. SCSI_STATUS_GOOD */
- SCpnt->result |= (DID_OK << 16);
- break;
- case 0x02: /* ERROR_ABORTED, i.e. SCSI_STATUS_CHECK_CONDITION */
- /*set sense_buffer and result fields */
- if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
- memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
- } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
- SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
- memcpy(
- SCpnt->sense_buffer,
- epthru->reqsensearea, 14
- );
- SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION << 1);
- /*SCpnt->result =
- (DRIVER_SENSE << 24) |
- (DID_ERROR << 16) | status;*/
- } else {
- SCpnt->sense_buffer[0] = 0x70;
- SCpnt->sense_buffer[2] = ABORTED_COMMAND;
- SCpnt->result |= (CHECK_CONDITION << 1);
- }
- break;
- case 0x08: /* ERR_DEST_DRIVE_FAILED, i.e. SCSI_STATUS_BUSY */
- SCpnt->result |= (DID_BUS_BUSY << 16) | status;
- break;
- default:
- SCpnt->result |= (DID_BAD_TARGET << 16) | status;
- break;
- }
- }
- /* Add Scsi_Command to end of completed queue */
- if (megaCfg->qCompletedH == NULL) {
- megaCfg->qCompletedH = megaCfg->qCompletedT = SCpnt;
- } else {
- megaCfg->qCompletedT->host_scribble = (unsigned char *) SCpnt;
- megaCfg->qCompletedT = SCpnt;
- }
- megaCfg->qCompletedT->host_scribble = (unsigned char *) NULL;
- megaCfg->qCcnt++;
- }
- /*-------------------------------------------------------------------
- *
- * 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;
- mega_ext_passthru *epthru;
- long seg;
- char islogical;
- int lun = SCpnt->lun;
- int max_lun;
- if ((SCpnt->cmnd[0] == MEGADEVIOC))
- return megadev_doioctl (megaCfg, SCpnt);
- if ((SCpnt->cmnd[0] == M_RD_IOCTL_CMD)
- || (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW))
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
- return mega_ioctl (megaCfg, SCpnt); /* Handle IOCTL command */
- #else
- {
- printk(KERN_WARNING "megaraid ioctl: older interface - "
- "not supported.n");
- return NULL;
- }
- #endif
- islogical = ( (SCpnt->channel >= megaCfg->productInfo.SCSIChanPresent) &&
- (SCpnt->channel <= megaCfg->host->max_channel) );
- #if 0
- islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
- (SCpnt->channel == megaCfg->host->max_channel));
- #endif
- if ( ! megaCfg->support_ext_cdb ) {
- if (!islogical && lun != 0) {
- SCpnt->result = (DID_BAD_TARGET << 16);
- callDone (SCpnt);
- return NULL;
- }
- }
- if (!islogical && SCpnt->target == skip_id) {
- SCpnt->result = (DID_BAD_TARGET << 16);
- callDone (SCpnt);
- return NULL;
- }
- if (islogical) {
- /* have just LUN 0 for each target on virtual channels */
- if( SCpnt->lun != 0 ) {
- SCpnt->result = (DID_BAD_TARGET << 16);
- callDone (SCpnt);
- return NULL;
- }
- lun = mega_get_lun(megaCfg, SCpnt);
- max_lun = (megaCfg->flag & BOARD_40LD) ?
- FC_MAX_LOGICAL_DRIVES : MAX_LOGICAL_DRIVES;
- /*
- * max_lun increases by 0x80 if some logical drive was deleted.
- */
- if(megaCfg->read_ldidmap) {
- max_lun += 0x80;
- }
- if( lun > max_lun ) {
- SCpnt->result = (DID_BAD_TARGET << 16);
- callDone (SCpnt);
- return NULL;
- }
- /*
- * If we have a logical drive with boot enabled, project it first
- */
- if( megaCfg->boot_ldrv_enabled ) {
- if( lun == 0 ) {
- lun = megaCfg->boot_ldrv;
- }
- else {
- if( lun <= megaCfg->boot_ldrv ) {
- lun--;
- }
- }
- }
- } else {
- if ( lun > 7) {
- /* Do not support lun >7 for physically accessed devices */
- SCpnt->result = (DID_BAD_TARGET << 16);
- callDone (SCpnt);
- return NULL;
- }
- }
- /*-----------------------------------------------------
- *
- * Logical drive commands
- *
- *-----------------------------------------------------*/
- if (islogical) {
- 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 = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pthru = pScb->pthru;
- #else
- pthru = &pScb->pthru;
- #endif
- 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 = lun;
- pthru->cdblen = SCpnt->cmd_len;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /*Not sure about the direction */
- pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
- pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
- #if 0
- /* Normal Code w/o the need for bounce buffer */
- pScb->dma_h_bulkdata
- = pci_map_single (megaCfg->dev,
- SCpnt->request_buffer,
- SCpnt->request_bufflen,
- pScb->dma_direction);
- pthru->dataxferaddr = pScb->dma_h_bulkdata;
- #else
- /* Special Code to use bounce buffer for READ_CAPA/INQ */
- pthru->dataxferaddr = pScb->dma_bounce_buffer;
- pScb->dma_type = M_RD_DMA_TYPE_NONE;
- #endif
- #else
- pthru->dataxferaddr =
- virt_to_bus (SCpnt->request_buffer);
- #endif
- pthru->dataxferlen = SCpnt->request_bufflen;
- memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
- /* Initialize mailbox area */
- mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- mbox->xferaddr = pScb->dma_passthruhandle64;
- TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled n"));
- #else
- mbox->xferaddr = virt_to_bus (pthru);
- #endif
- return pScb;
- case READ_6:
- case WRITE_6:
- case READ_10:
- case WRITE_10:
- /* Allocate a SCB and initialize mailbox */
- if ((pScb = mega_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 = lun;
- if (megaCfg->flag & BOARD_64BIT) {
- mbox->cmd = (*SCpnt->cmnd == READ_6
- || *SCpnt->cmnd ==
- READ_10) ? MEGA_MBOXCMD_LREAD64 :
- MEGA_MBOXCMD_LWRITE64;
- } else {
- 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 = (u32) SCpnt->cmnd[4];
- mbox->lba =
- ((u32) SCpnt->cmnd[1] << 16) |
- ((u32) SCpnt->cmnd[2] << 8) |
- (u32) SCpnt->cmnd[3];
- mbox->lba &= 0x1FFFFF;
- if (*SCpnt->cmnd == READ_6) {
- megaCfg->nReads[(int) lun]++;
- megaCfg->nReadBlocks[(int) lun] +=
- mbox->numsectors;
- } else {
- megaCfg->nWrites[(int) lun]++;
- megaCfg->nWriteBlocks[(int) lun] +=
- mbox->numsectors;
- }
- }
- /* 10-byte */
- if (*SCpnt->cmnd == READ_10 || *SCpnt->cmnd == WRITE_10) {
- mbox->numsectors =
- (u32) SCpnt->cmnd[8] |
- ((u32) SCpnt->cmnd[7] << 8);
- mbox->lba =
- ((u32) SCpnt->cmnd[2] << 24) |
- ((u32) SCpnt->cmnd[3] << 16) |
- ((u32) SCpnt->cmnd[4] << 8) |
- (u32) SCpnt->cmnd[5];
- if (*SCpnt->cmnd == READ_10) {
- megaCfg->nReads[(int) lun]++;
- megaCfg->nReadBlocks[(int) lun] +=
- mbox->numsectors;
- } else {
- megaCfg->nWrites[(int) lun]++;
- megaCfg->nWriteBlocks[(int) lun] +=
- mbox->numsectors;
- }
- }
- /* 12-byte */
- if (*SCpnt->cmnd == READ_12 || *SCpnt->cmnd == WRITE_12) {
- mbox->lba =
- ((u32) SCpnt->cmnd[2] << 24) |
- ((u32) SCpnt->cmnd[3] << 16) |
- ((u32) SCpnt->cmnd[4] << 8) |
- (u32) SCpnt->cmnd[5];
- mbox->numsectors =
- ((u32) SCpnt->cmnd[6] << 24) |
- ((u32) SCpnt->cmnd[7] << 16) |
- ((u32) SCpnt->cmnd[8] << 8) |
- (u32) SCpnt->cmnd[9];
- if (*SCpnt->cmnd == READ_12) {
- megaCfg->nReads[(int) lun]++;
- megaCfg->nReadBlocks[(int) lun] +=
- mbox->numsectors;
- } else {
- megaCfg->nWrites[(int) lun]++;
- megaCfg->nWriteBlocks[(int) lun] +=
- mbox->numsectors;
- }
- }
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10
- || *SCpnt->cmnd == READ_12) {
- pScb->dma_direction = PCI_DMA_FROMDEVICE;
- } else { /*WRITE_6 or WRITE_10 */
- pScb->dma_direction = PCI_DMA_TODEVICE;
- }
- #endif
- /* Calculate Scatter-Gather info */
- mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *)&mbox->xferaddr, (u32 *)&seg);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pScb->iDataSize = seg;
- if (mbox->numsgelements) {
- pScb->dma_type = M_RD_SGLIST_ONLY;
- TRACE1 (("M_RD_SGLIST_ONLY Enabled n"));
- } else {
- pScb->dma_type = M_RD_BULK_DATA_ONLY;
- TRACE1 (("M_RD_BULK_DATA_ONLY Enabled n"));
- }
- #endif
- 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 = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- mbox = (mega_mailbox *) pScb->mboxData;
- memset (mbox, 0, sizeof (pScb->mboxData));
- if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
- epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
- mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- mbox->xferaddr = pScb->dma_ext_passthruhandle64;
- if(epthru->numsgelements) {
- pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
- } else {
- pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA;
- }
- #else
- mbox->xferaddr = virt_to_bus(epthru);
- #endif
- }
- else {
- pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
- /* Initialize mailbox */
- mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- mbox->xferaddr = pScb->dma_passthruhandle64;
- if (pthru->numsgelements) {
- pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
- } else {
- pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
- }
- #else
- mbox->xferaddr = virt_to_bus(pthru);
- #endif
- }
- return pScb;
- }
- return NULL;
- }
- static int
- mega_get_lun(mega_host_config *this_hba, Scsi_Cmnd *sc)
- {
- int tgt;
- int lun;
- int virt_chan;
- tgt = sc->target;
-
- if ( tgt > 7 ) tgt--; /* we do not get inquires for tgt 7 */
- virt_chan = sc->channel - this_hba->productInfo.SCSIChanPresent;
- lun = (virt_chan * 15) + tgt;
- /*
- * If "delete logical drive" feature is enabled on this controller.
- * Do only if at least one delete logical drive operation was done.
- *
- * Also, after logical drive deletion, instead of logical drive number,
- * the value returned should be 0x80+logical drive id.
- *
- * These is valid only for IO commands.
- */
- if( this_hba->support_random_del && this_hba->read_ldidmap ) {
- switch(sc->cmnd[0]) {
- case READ_6: /* fall through */
- case WRITE_6: /* fall through */
- case READ_10: /* fall through */
- case WRITE_10:
- lun += 0x80;
- }
- }
- return lun;
- }
- static mega_passthru *
- mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
- {
- mega_passthru *pthru;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pthru = scb->pthru;
- #else
- pthru = &scb->pthru;
- #endif
- memset (pthru, 0, sizeof (mega_passthru));
- /* set adapter timeout value to 10 min. for tape drive */
- /* 0=6sec/1=60sec/2=10min/3=3hrs */
- pthru->timeout = 2;
- pthru->ars = 1;
- pthru->reqsenselen = 14;
- pthru->islogical = 0;
- pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
- pthru->target = (megacfg->flag & BOARD_40LD) ?
- (sc->channel << 4) | sc->target : sc->target;
- pthru->cdblen = sc->cmd_len;
- pthru->logdrv = sc->lun;
- memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* Not sure about the direction */
- scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
- /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
- switch (sc->cmnd[0]) {
- case INQUIRY:
- case READ_CAPACITY:
- pthru->numsgelements = 0;
- pthru->dataxferaddr = scb->dma_bounce_buffer;
- pthru->dataxferlen = sc->request_bufflen;
- break;
- default:
- pthru->numsgelements =
- mega_build_sglist(
- megacfg, scb, (u32 *)&pthru->dataxferaddr,
- (u32 *)&pthru->dataxferlen
- );
- break;
- }
- #else
- pthru->numsgelements =
- mega_build_sglist(
- megacfg, scb, (u32 *)&pthru->dataxferaddr,
- (u32 *)&pthru->dataxferlen
- );
- #endif
- return pthru;
- }
- static mega_ext_passthru *
- mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
- {
- mega_ext_passthru *epthru;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- epthru = scb->epthru;
- #else
- epthru = &scb->epthru;
- #endif
- memset(epthru, 0, sizeof(mega_ext_passthru));
- /* set adapter timeout value to 10 min. for tape drive */
- /* 0=6sec/1=60sec/2=10min/3=3hrs */
- epthru->timeout = 2;
- epthru->ars = 1;
- epthru->reqsenselen = 14;
- epthru->islogical = 0;
- epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
- epthru->target = (megacfg->flag & BOARD_40LD) ?
- (sc->channel << 4) | sc->target : sc->target;
- epthru->cdblen = sc->cmd_len;
- epthru->logdrv = sc->lun;
- memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* Not sure about the direction */
- scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
- /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
- switch (sc->cmnd[0]) {
- case INQUIRY:
- case READ_CAPACITY:
- epthru->numsgelements = 0;
- epthru->dataxferaddr = scb->dma_bounce_buffer;
- epthru->dataxferlen = sc->request_bufflen;
- break;
- default:
- epthru->numsgelements =
- mega_build_sglist(
- megacfg, scb, (u32 *)&epthru->dataxferaddr,
- (u32 *)&epthru->dataxferlen
- );
- break;
- }
- #else
- epthru->numsgelements =
- mega_build_sglist(
- megacfg, scb, (u32 *)&epthru->dataxferaddr,
- (u32 *)&epthru->dataxferlen
- );
- #endif
- return epthru;
- }
- /* Handle Driver Level IOCTLs
- * Return value of 0 indicates this function could not handle , so continue
- * processing
- */
- static int mega_driver_ioctl (mega_host_config * megaCfg, Scsi_Cmnd * SCpnt)
- {
- unsigned char *data = (unsigned char *) SCpnt->request_buffer;
- mega_driver_info driver_info;
- /* If this is not our command dont do anything */
- if (SCpnt->cmnd[0] != M_RD_DRIVER_IOCTL_INTERFACE)
- return 0;
- switch (SCpnt->cmnd[1]) {
- case GET_DRIVER_INFO:
- if (SCpnt->request_bufflen < sizeof (driver_info)) {
- SCpnt->result = DID_BAD_TARGET << 16;
- callDone (SCpnt);
- return 1;
- }
- driver_info.size = sizeof (driver_info) - sizeof (int);
- driver_info.version = MEGARAID_IOCTL_VERSION;
- memcpy (data, &driver_info, sizeof (driver_info));
- break;
- default:
- SCpnt->result = DID_BAD_TARGET << 16;
- }
- callDone (SCpnt);
- return 1;
- }
- static void inline set_mbox_xfer_addr (mega_host_config * megaCfg, mega_scb * pScb,
- mega_ioctl_mbox * mbox, u32 direction)
- {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- switch (direction) {
- case TO_DEVICE:
- pScb->dma_direction = PCI_DMA_TODEVICE;
- break;
- case FROM_DEVICE:
- pScb->dma_direction = PCI_DMA_FROMDEVICE;
- break;
- case FROMTO_DEVICE:
- pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
- break;
- }
- pScb->dma_h_bulkdata
- = pci_map_single (megaCfg->dev,
- pScb->buff_ptr,
- pScb->iDataSize, pScb->dma_direction);
- mbox->xferaddr = pScb->dma_h_bulkdata;
- pScb->dma_type = M_RD_BULK_DATA_ONLY;
- TRACE1 (("M_RD_BULK_DATA_ONLY Enabled n"));
- #else
- mbox->xferaddr = virt_to_bus (pScb->buff_ptr);
- #endif
- }
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
- /*--------------------------------------------------------------------
- * 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;
- u8 *mboxdata;
- long seg, i = 0;
- unsigned char *data = (unsigned char *) SCpnt->request_buffer;
- if ((pScb = mega_allocateSCB (megaCfg, SCpnt)) == NULL) {
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- pthru = &pScb->pthru;
- mboxdata = (u8 *) & pScb->mboxData;
- 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];
- 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;
- pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *) & pthru->
- dataxferaddr,
- (u32 *) & pthru->
- dataxferlen);
- mailbox->xferaddr = virt_to_bus (pthru);
- for (i = 0; i < (SCpnt->request_bufflen - cdblen - 7); i++) {
- data[i] = data[i + cdblen + 7];
- }
- return pScb;
- }
- /* else normal (nonpassthru) command */
- #if LINUX_VERSION_CODE > KERNEL_VERSION(2,0,24) /*0x020024 */
- /*
- *usage of the function copy from user is used in case of data more than
- *4KB.This is used only with adapters which supports more than 8 logical
- * drives.This feature is disabled on kernels earlier or same as 2.0.36
- * as the uaccess.h file is not available with those kernels.
- */
- if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
- /* use external data area for large xfers */
- /* If cmnd[0] is set to M_RD_IOCTL_CMD_NEW then *
- * cmnd[4..7] = external user buffer *
- * cmnd[8..11] = length of buffer *
- * */
- char *user_area = (char *)*((u32*)&SCpnt->cmnd[4]);
- u32 xfer_size = *((u32 *) & SCpnt->cmnd[8]);
- switch (data[0]) {
- case FW_FIRE_WRITE:
- case FW_FIRE_FLASH:
- if ((ulong) user_area & (PAGE_SIZE - 1)) {
- printk
- ("megaraid:user address not aligned on 4K boundary.Error.n");
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- break;
- default:
- break;
- }
- if (!(pScb->buff_ptr = kmalloc (xfer_size, GFP_KERNEL))) {
- printk
- ("megaraid: Insufficient mem for M_RD_IOCTL_CMD_NEW.n");
- SCpnt->result = (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- copy_from_user (pScb->buff_ptr, user_area, xfer_size);
- pScb->iDataSize = xfer_size;
- switch (data[0]) {
- case DCMD_FC_CMD:
- switch (data[1]) {
- case DCMD_FC_READ_NVRAM_CONFIG:
- case DCMD_GET_DISK_CONFIG:
- {
- if ((ulong) pScb->
- buff_ptr & (PAGE_SIZE - 1)) {
- printk
- ("megaraid:user address not sufficient Error.n");
- SCpnt->result =
- (DID_ERROR << 16);
- callDone (SCpnt);
- return NULL;
- }
- /*building SG list */
- mega_build_kernel_sg (pScb->buff_ptr,
- xfer_size,
- pScb, mbox);
- break;
- }
- default:
- break;
- } /*switch (data[1]) */
- break;
- }
- }
- #endif
- mbox->cmd = data[0];
- mbox->channel = data[1];
- mbox->param = data[2];
- mbox->pad[0] = data[3];
- mbox->logdrv = data[4];
- if (SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
- switch (data[0]) {
- case FW_FIRE_WRITE:
- mbox->cmd = FW_FIRE_WRITE;
- mbox->channel = data[1]; /* Current Block Number */
- set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
- mbox->numsgelements = 0;
- break;
- case FW_FIRE_FLASH:
- mbox->cmd = FW_FIRE_FLASH;
- mbox->channel = data[1] | 0x80; /* Origin */
- set_mbox_xfer_addr (megaCfg, pScb, mbox, TO_DEVICE);
- mbox->numsgelements = 0;
- break;
- case DCMD_FC_CMD:
- *(mboxdata + 0) = data[0]; /*mailbox byte 0: DCMD_FC_CMD */
- *(mboxdata + 2) = data[1]; /*sub command */
- switch (data[1]) {
- case DCMD_FC_READ_NVRAM_CONFIG:
- case DCMD_FC_READ_NVRAM_CONFIG_64:
- /* number of elements in SG list */
- *(mboxdata + 3) = mbox->numsgelements;
- if (megaCfg->flag & BOARD_64BIT)
- *(mboxdata + 2) =
- DCMD_FC_READ_NVRAM_CONFIG_64;
- break;
- case DCMD_WRITE_CONFIG:
- case DCMD_WRITE_CONFIG_64:
- if (megaCfg->flag & BOARD_64BIT)
- *(mboxdata + 2) = DCMD_WRITE_CONFIG_64;
- set_mbox_xfer_addr (megaCfg, pScb, mbox,
- TO_DEVICE);
- mbox->numsgelements = 0;
- break;
- case DCMD_GET_DISK_CONFIG:
- case DCMD_GET_DISK_CONFIG_64:
- if (megaCfg->flag & BOARD_64BIT)
- *(mboxdata + 2) =
- DCMD_GET_DISK_CONFIG_64;
- *(mboxdata + 3) = data[2]; /*number of elements in SG list */
- /*nr of elements in SG list */
- *(mboxdata + 4) = mbox->numsgelements;
- break;
- case DCMD_DELETE_LOGDRV:
- case DCMD_DELETE_DRIVEGROUP:
- case NC_SUBOP_ENQUIRY3:
- *(mboxdata + 3) = data[2];
- set_mbox_xfer_addr (megaCfg, pScb, mbox,
- FROMTO_DEVICE);
- mbox->numsgelements = 0;
- break;
- case DCMD_CHANGE_LDNO:
- case DCMD_CHANGE_LOOPID:
- *(mboxdata + 3) = data[2];
- *(mboxdata + 4) = data[3];
- set_mbox_xfer_addr (megaCfg, pScb, mbox,
- TO_DEVICE);
- mbox->numsgelements = 0;
- break;
- default:
- set_mbox_xfer_addr (megaCfg, pScb, mbox,
- FROMTO_DEVICE);
- mbox->numsgelements = 0;
- break;
- } /*switch */
- break;
- default:
- set_mbox_xfer_addr (megaCfg, pScb, mbox, FROMTO_DEVICE);
- mbox->numsgelements = 0;
- break;
- }
- } else {
- mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *) & mbox->
- xferaddr,
- (u32 *) & seg);
- /* Handling some of the fw special commands */
- switch (data[0]) {
- case 6: /* START_DEV */
- mbox->xferaddr = *((u32 *) & data[i + 6]);
- break;
- default:
- break;
- }
- for (i = 0; i < (SCpnt->request_bufflen - 6); i++) {
- data[i] = data[i + 6];
- }
- }
- return (pScb);
- }
- static void mega_build_kernel_sg (char *barea, ulong xfersize, mega_scb * pScb, mega_ioctl_mbox * mbox)
- {
- ulong i, buffer_area, len, end, end_page, x, idx = 0;
- buffer_area = (ulong) barea;
- i = buffer_area;
- end = buffer_area + xfersize;
- end_page = (end) & ~(PAGE_SIZE - 1);
- do {
- len = PAGE_SIZE - (i % PAGE_SIZE);
- x = pScb->sgList[idx].address =
- virt_to_bus ((volatile void *) i);
- pScb->sgList[idx].length = len;
- i += len;
- idx++;
- } while (i < end_page);
- if ((end - i) < 0) {
- printk ("megaraid:Error in user addressn");
- }
- if (end - i) {
- pScb->sgList[idx].address = virt_to_bus ((volatile void *) i);
- pScb->sgList[idx].length = end - i;
- idx++;
- }
- mbox->xferaddr = virt_to_bus (pScb->sgList);
- mbox->numsgelements = idx;
- }
- #endif
- #if DEBUG
- static unsigned int cum_time = 0;
- static unsigned int cum_time_cnt = 0;
- 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:%xn",
- 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)
- {
- IO_LOCK_T;
- mega_host_config * megaCfg;
- u_char byte, idx, sIdx, tmpBox[MAILBOX_SIZE];
- u32 dword = 0;
- mega_mailbox *mbox;
- mega_scb *pScb;
- u_char qCnt, qStatus;
- u_char completed[MAX_FIRMWARE_STATUS];
- Scsi_Cmnd *SCpnt;
- megaCfg = (mega_host_config *) devp;
- mbox = (mega_mailbox *) tmpBox;
- if (megaCfg->host->irq == irq) {
- if (megaCfg->flag & IN_ISR) {
- TRACE (("ISR called reentrantly!!n"));
- printk ("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;
- return;
- }
- } else {
- byte = READ_PORT (megaCfg->host->io_port, INTR_PORT);
- if ((byte & VALID_INTR_BYTE) == 0) {
- /* Spurious interrupt */
- megaCfg->flag &= ~IN_ISR;
- return;
- }
- WRITE_PORT (megaCfg->host->io_port, INTR_PORT, byte);
- }
- for (idx = 0; idx < MAX_FIRMWARE_STATUS; idx++)
- completed[idx] = 0;
- IO_LOCK;
- megaCfg->nInterrupts++;
- qCnt = 0xff;
- while ((qCnt = megaCfg->mbox->numstatus) == 0xFF) ;
- qStatus = 0xff;
- while ((qStatus = megaCfg->mbox->status) == 0xFF) ;
- /* Get list of completed requests */
- for (idx = 0; idx < qCnt; idx++) {
- while ((sIdx = megaCfg->mbox->completed[idx]) == 0xFF) {
- printk ("p");
- }
- completed[idx] = sIdx;
- sIdx = 0xFF;
- }
- if (megaCfg->flag & BOARD_QUARTZ) {
- WROUTDOOR (megaCfg, dword);
- /* Acknowledge interrupt */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* In this case mbox contains physical address */
- #if 0
- WRINDOOR (megaCfg, megaCfg->adjdmahandle64 | 0x2);
- #else
- WRINDOOR (megaCfg, 0x2);
- #endif
- #else
- #if 0
- WRINDOOR (megaCfg, virt_to_bus (megaCfg->mbox) | 0x2);
- #else
- WRINDOOR (megaCfg, 0x2);
- #endif
- #endif
- #if 0
- while (RDINDOOR (megaCfg) & 0x02) ;
- #endif
- } else {
- CLEAR_INTR (megaCfg->host->io_port);
- }
- #if DEBUG
- if (qCnt >= MAX_FIRMWARE_STATUS) {
- printk ("megaraid_isr: cmplt=%d ", qCnt);
- }
- #endif
- for (idx = 0; idx < qCnt; idx++) {
- sIdx = completed[idx];
- if ((sIdx > 0) && (sIdx <= MAX_COMMANDS)) {
- pScb = &megaCfg->scbList[sIdx - 1];
- /* ASSERT(pScb->state == SCB_ISSUED); */
- #if DEBUG
- if (((jiffies) - pScb->isrcount) > maxCmdTime) {
- maxCmdTime = (jiffies) - pScb->isrcount;
- printk
- ("megaraid_isr : cmd time = %un",
- maxCmdTime);
- }
- #endif
- /*
- * Assuming that the scsi command, for which
- * an abort request was received earlier, has
- * completed.
- */
- if (pScb->state == SCB_ABORTED) {
- SCpnt = pScb->SCpnt;
- }
- if (pScb->state == SCB_RESET) {
- SCpnt = pScb->SCpnt;
- mega_freeSCB (megaCfg, pScb);
- SCpnt->result = (DID_RESET << 16);
- if (megaCfg->qCompletedH == NULL) {
- megaCfg->qCompletedH =
- megaCfg->qCompletedT =
- SCpnt;
- } else {
- megaCfg->qCompletedT->
- host_scribble =
- (unsigned char *) SCpnt;
- megaCfg->qCompletedT = SCpnt;
- }
- megaCfg->qCompletedT->host_scribble =
- (unsigned char *) NULL;
- megaCfg->qCcnt++;
- continue;
- }
- /* We don't want the ISR routine to touch M_RD_IOCTL_CMD_NEW commands, so
- * don't mark them as complete, instead we pop their semaphore so
- * that the queue routine can finish them off
- */
- if (pScb->SCpnt->cmnd[0] == M_RD_IOCTL_CMD_NEW) {
- /* save the status byte for the queue routine to use */
- pScb->SCpnt->result = qStatus;
- up (&pScb->ioctl_sem);
- } else {
- /* Mark command as completed */
- mega_cmd_done (megaCfg, pScb, qStatus);
- }
- } else {
- printk
- ("megaraid: wrong cmd id completed from firmware:id=%xn",
- sIdx);
- }
- }
- mega_rundoneq (megaCfg);
- megaCfg->flag &= ~IN_ISR;
- /* Loop through any pending requests */
- mega_runpendq (megaCfg);
- IO_UNLOCK;
- }
- }
- /*==================================================*/
- /* Wait until the controller's mailbox is available */
- /*==================================================*/
- static int mega_busyWaitMbox (mega_host_config * megaCfg)
- {
- mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
- long counter;
- for (counter = 0; counter < 10000; counter++) {
- if (!mbox->busy) {
- return 0;
- }
- udelay (100);
- barrier ();
- }
- return -1; /* give up after 1 second */
- }
- /*=====================================================
- * 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
- * Return Value: (added on 7/26 for 40ld/64bit)
- * -1: the command was not actually issued out
- * other cases:
- * intr==0, return ScsiStatus, i.e. mbox->status
- * intr==1, return 0
- *=====================================================
- */
- static int megaIssueCmd (mega_host_config * megaCfg, u_char * mboxData,
- mega_scb * pScb, int intr)
- {
- volatile mega_mailbox *mbox = (mega_mailbox *) megaCfg->mbox;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- volatile mega_mailbox64 *mbox64 = (mega_mailbox64 *) megaCfg->mbox64;
- #endif
- u_char byte;
- #if BITS_PER_LONG==64
- u64 phys_mbox;
- #else
- u32 phys_mbox;
- #endif
- u8 retval = -1;
- mboxData[0x1] = (pScb ? pScb->idx + 1 : 0xFE); /* Set cmdid */
- mboxData[0xF] = 1; /* Set busy */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* In this case mbox contains physical address */
- phys_mbox = megaCfg->adjdmahandle64;
- #else
- phys_mbox = virt_to_bus (megaCfg->mbox);
- #endif
- #if DEBUG
- ShowMbox (pScb);
- #endif
- /* Wait until mailbox is free */
- if (mega_busyWaitMbox (megaCfg)) {
- printk ("Blocked mailbox......!!n");
- udelay (1000);
- #if DEBUG
- showMbox (pLastScb);
- #endif
- /* Abort command */
- if (pScb == NULL) {
- TRACE (("NULL pScb in megaIssuen"));
- printk ("NULL pScb in megaIssuen");
- }
- mega_cmd_done (megaCfg, pScb, 0x08);
- return -1;
- }
- pLastScb = pScb;
- /* Copy mailbox data into host structure */
- megaCfg->mbox64->xferSegment_lo = 0;
- megaCfg->mbox64->xferSegment_hi = 0;
- memcpy ((char *) mbox, mboxData, 16);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- switch (mboxData[0]) {
- case MEGA_MBOXCMD_LREAD64:
- case MEGA_MBOXCMD_LWRITE64:
- mbox64->xferSegment_lo = mbox->xferaddr;
- mbox64->xferSegment_hi = 0;
- mbox->xferaddr = 0xFFFFFFFF;
- break;
- }
- #endif
- /* Kick IO */
- if (intr) {
- /* Issue interrupt (non-blocking) command */
- if (megaCfg->flag & BOARD_QUARTZ) {
- mbox->mraid_poll = 0;
- mbox->mraid_ack = 0;
- WRINDOOR (megaCfg, phys_mbox | 0x1);
- } else {
- ENABLE_INTR (megaCfg->host->io_port);
- ISSUE_COMMAND (megaCfg->host->io_port);
- }
- pScb->state = SCB_ISSUED;
- retval = 0;
- } else { /* Issue non-ISR (blocking) command */
- disable_irq (megaCfg->host->irq);
- if (megaCfg->flag & BOARD_QUARTZ) {
- mbox->mraid_poll = 0;
- mbox->mraid_ack = 0;
- mbox->numstatus = 0xFF;
- mbox->status = 0xFF;
- WRINDOOR (megaCfg, phys_mbox | 0x1);
- while (mbox->numstatus == 0xFF) ;
- while (mbox->status == 0xFF) ;
- while (mbox->mraid_poll != 0x77) ;
- mbox->mraid_poll = 0;
- mbox->mraid_ack = 0x77;
- /* while ((cmdDone = RDOUTDOOR (megaCfg)) != 0x10001234);
- WROUTDOOR (megaCfg, cmdDone); */
- if (pScb) {
- mega_cmd_done (megaCfg, pScb, mbox->status);
- }
- WRINDOOR (megaCfg, phys_mbox | 0x2);
- while (RDINDOOR (megaCfg) & 0x2) ;
- } 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 (megaCfg, pScb, mbox->status);
- } else {
- TRACE (("Error: NULL pScb!n"));
- }
- }
- enable_irq (megaCfg->host->irq);
- retval = mbox->status;
- }
- #if DEBUG
- while (mega_busyWaitMbox (megaCfg)) {
- printk(KERN_ERR "Blocked mailbox on exit......!n");
- udelay (1000);
- }
- #endif
- return retval;
- }
- /*-------------------------------------------------------------------
- * Copies data to SGLIST
- *-------------------------------------------------------------------*/
- /* Note:
- For 64 bit cards, we need a minimum of one SG element for read/write
- */
- static int
- mega_build_sglist (mega_host_config * megaCfg, mega_scb * scb,
- u32 * buffer, u32 * length)
- {
- struct scatterlist *sgList;
- int idx;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- int sgcnt;
- #endif
- mega_mailbox *mbox = NULL;
- mbox = (mega_mailbox *) scb->mboxData;
- /* Scatter-gather not used */
- if (scb->SCpnt->use_sg == 0) {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
- scb->SCpnt->request_buffer,
- scb->SCpnt->request_bufflen,
- scb->dma_direction);
- /* We need to handle special commands like READ64, WRITE64
- as they need a minimum of 1 SG irrespective of actually SG
- */
- if ((megaCfg->flag & BOARD_64BIT) &&
- ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
- (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
- scb->sg64List[0].address = scb->dma_h_bulkdata;
- scb->sg64List[0].length = scb->SCpnt->request_bufflen;
- *buffer = scb->dma_sghandle64;
- *length = 0;
- scb->sglist_count = 1;
- return 1;
- } else {
- *buffer = scb->dma_h_bulkdata;
- *length = (u32) scb->SCpnt->request_bufflen;
- }
- #else
- *buffer = virt_to_bus (scb->SCpnt->request_buffer);
- *length = (u32) scb->SCpnt->request_bufflen;
- #endif
- return 0;
- }
- sgList = (struct scatterlist *) scb->SCpnt->request_buffer;
- #if 0
- if (scb->SCpnt->use_sg == 1) {
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- scb->dma_h_bulkdata = pci_map_single (megaCfg->dev,
- sgList[0].address,
- sgList[0].length, scb->dma_direction);
- if ((megaCfg->flag & BOARD_64BIT) &&
- ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
- (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
- scb->sg64List[0].address = scb->dma_h_bulkdata;
- scb->sg64List[0].length = scb->SCpnt->request_bufflen;
- *buffer = scb->dma_sghandle64;
- *length = 0;
- scb->sglist_count = 1;
- return 1;
- } else {
- *buffer = scb->dma_h_bulkdata;
- *length = (u32) sgList[0].length;
- }
- #else
- *buffer = virt_to_bus (sgList[0].address);
- *length = (u32) sgList[0].length;
- #endif
- return 0;
- }
- #endif
- /* Copy Scatter-Gather list info into controller structure */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- sgcnt = pci_map_sg (megaCfg->dev,
- sgList, scb->SCpnt->use_sg, scb->dma_direction);
- /* Determine the validity of the new count */
- if (sgcnt == 0)
- printk ("pci_map_sg returned zero!!! ");
- for (idx = 0; idx < sgcnt; idx++, sgList++) {
- if ((megaCfg->flag & BOARD_64BIT) &&
- ((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
- (mbox->cmd == MEGA_MBOXCMD_LWRITE64))) {
- scb->sg64List[idx].address = sg_dma_address (sgList);
- scb->sg64List[idx].length = sg_dma_len (sgList);
- } else {
- scb->sgList[idx].address = sg_dma_address (sgList);
- scb->sgList[idx].length = sg_dma_len (sgList);
- }
- }
- #else
- for (idx = 0; idx < scb->SCpnt->use_sg; idx++) {
- scb->sgList[idx].address = virt_to_bus (sgList[idx].address);
- scb->sgList[idx].length = (u32) sgList[idx].length;
- }
- #endif
- /* Reset pointer and length fields */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- *buffer = scb->dma_sghandle64;
- scb->sglist_count = scb->SCpnt->use_sg;
- #else
- *buffer = virt_to_bus (scb->sgList);
- #endif
- *length = 0;
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* Return count of SG requests */
- return sgcnt;
- #else
- /* Return count of SG requests */
- return scb->SCpnt->use_sg;
- #endif
- }
- /*--------------------------------------------------------------------
- * Initializes the address 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, u32 paddr)
- {
- /* align on 16-byte boundary */
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
- #else
- megaCfg->mbox = &megaCfg->mailbox64.mailbox;
- #endif
- #if BITS_PER_LONG==64
- megaCfg->mbox = (mega_mailbox *) ((((u64) megaCfg->mbox) + 16) & ((u64) (-1) ^ 0x0F));
- megaCfg->adjdmahandle64 = (megaCfg->dma_handle64 + 16) & ((u64) (-1) ^ 0x0F);
- megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - sizeof (u64));
- paddr = (paddr + 4 + 16) & ((u64) (-1) ^ 0x0F);
- #else
- megaCfg->mbox
- = (mega_mailbox *) ((((u32) megaCfg->mbox) + 16) & 0xFFFFFFF0);
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- megaCfg->adjdmahandle64 = ((megaCfg->dma_handle64 + 16) & 0xFFFFFFF0);
- #endif
- megaCfg->mbox64 = (mega_mailbox64 *) ((u_char *) megaCfg->mbox - 8);
- paddr = (paddr + 4 + 16) & 0xFFFFFFF0;
- #endif
- /* Register mailbox area with the firmware */
- if (!(megaCfg->flag & BOARD_QUARTZ)) {
- 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;
- }
- /*---------------------------------------------------------------------------
- * mega_Convert8ldTo40ld() -- takes all info in AdapterInquiry structure and
- * puts it into ProductInfo and Enquiry3 structures for later use
- *---------------------------------------------------------------------------*/
- static void mega_Convert8ldTo40ld (mega_RAIDINQ * inquiry,
- mega_Enquiry3 * enquiry3,
- megaRaidProductInfo * productInfo)
- {
- int i;
- productInfo->MaxConcCmds = inquiry->AdpInfo.MaxConcCmds;
- enquiry3->rbldRate = inquiry->AdpInfo.RbldRate;
- productInfo->SCSIChanPresent = inquiry->AdpInfo.ChanPresent;
- for (i = 0; i < 4; i++) {
- productInfo->FwVer[i] = inquiry->AdpInfo.FwVer[i];
- productInfo->BiosVer[i] = inquiry->AdpInfo.BiosVer[i];
- }
- enquiry3->cacheFlushInterval = inquiry->AdpInfo.CacheFlushInterval;
- productInfo->DramSize = inquiry->AdpInfo.DramSize;
- enquiry3->numLDrv = inquiry->LogdrvInfo.NumLDrv;
- for (i = 0; i < MAX_LOGICAL_DRIVES; i++) {
- enquiry3->lDrvSize[i] = inquiry->LogdrvInfo.LDrvSize[i];
- enquiry3->lDrvProp[i] = inquiry->LogdrvInfo.LDrvProp[i];
- enquiry3->lDrvState[i]
- = inquiry->LogdrvInfo.LDrvState[i];
- }
- for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++) {
- enquiry3->pDrvState[i]
- = inquiry->PhysdrvInfo.PDrvState[i];
- }
- }
- /*-------------------------------------------------------------------
- * Issue an adapter info query to the controller
- *-------------------------------------------------------------------*/
- static int mega_i_query_adapter (mega_host_config * megaCfg)
- {
- mega_Enquiry3 *enquiry3Pnt;
- mega_mailbox *mbox;
- u_char mboxData[16];
- #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- dma_addr_t raid_inq_dma_handle = 0, prod_info_dma_handle = 0, enquiry3_dma_handle = 0;
- #endif
- u8 retval;
- /* Initialize adapter inquiry mailbox */
- mbox = (mega_mailbox *) mboxData;
- memset ((void *) megaCfg->mega_buffer, 0,
- sizeof (megaCfg->mega_buffer));