From 8b1015ad10955163aa54c353a10bef714f3e83fb Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:22:11 -0500 Subject: [PATCH] Linux 2.2.18pre3 o Clean up most of the compatibility macros (Alan Cox) that various people use. I've systematically moved the 100% correct ones to the headers used in 2.4 o Fix newly introduced bug in kmem_cache_shrink (Daniel Roesen) o Further updates to symbios drivers (Gerhard Roudier) o Remove emu10K warning and mtrr warning (Daniel Roesen) o Fix symbol clash between cs4281 and esssolo1 (Arjan van de Ven) o Fix acenic non modular/module build issues (Arjan van de Ven) o Fix bug in alpha csum_partial_copy that could (Herbert Xu) cause spurious EFAULTs o Yet another eepro100 variant sighted (Torben Mathiasen) o Minor microcode.c final tweak (Daniel Roesen) o Document that ATIFB is now modular (Marcelo Tosatti) o Parport update (Tim Waugh) o First set of ext2 updates/fixes (Al Viro) o Bring smbfs back into line with 2.2 (Urban Widmark) | This should make OS/2 work again o Fix S/390 _stext (still doesnt build dasd) (Kurt Roeckx) o Remove unused vars in arch/i386/kernel/bios32.c (Daniel Roesen) o Update the DHCP initrd support (Chip Salzenberg) o Allow opening empty scsi removables like IDE with O_NONBLOCK (needed for some ioctls) (Chip Salzenberg) o Back out vibra mixer change o Fix error returns in sbni driver (Dawson Engler) o Initial merge of the aacraid driver (Adaptec) | Much deuglification left to be done here o Report megaraid: on obscure megaraid error (Daniel Deimert) strings o Add another CS4299 id string (Mulder Tjeerd) --- Documentation/Configure.help | 12 + MAINTAINERS | 6 + Makefile | 2 +- arch/alpha/lib/csum_partial_copy.c | 43 +- arch/i386/defconfig | 1 + arch/i386/kernel/apm.c | 8 - arch/i386/kernel/bios32.c | 2 - arch/i386/kernel/microcode.c | 2 +- arch/i386/kernel/mtrr.c | 2 +- drivers/char/n_hdlc.c | 7 - drivers/char/synclink.c | 8 - drivers/misc/parport_pc.c | 8 +- drivers/net/acenic.c | 3 +- drivers/net/cosa.c | 7 - drivers/net/eepro100.c | 7 + drivers/net/sbni.c | 12 +- drivers/scsi/ChangeLog.ncr53c8xx | 5 + drivers/scsi/ChangeLog.sym53c8xx | 7 + drivers/scsi/Config.in | 1 + drivers/scsi/Makefile | 15 + drivers/scsi/aacraid/Makefile | 37 + drivers/scsi/aacraid/aachba.c | 1769 +++++++++++++++ drivers/scsi/aacraid/aacid.c | 130 ++ drivers/scsi/aacraid/commctrl.c | 795 +++++++ drivers/scsi/aacraid/comminit.c | 1027 +++++++++ drivers/scsi/aacraid/commsup.c | 1931 +++++++++++++++++ drivers/scsi/aacraid/crapfile | 170 ++ drivers/scsi/aacraid/dpcsup.c | 399 ++++ .../scsi/aacraid/include/AacGenericTypes.h | 54 + drivers/scsi/aacraid/include/aac_unix_defs.h | 282 +++ drivers/scsi/aacraid/include/adapter.h | 170 ++ drivers/scsi/aacraid/include/afacomm.h | 104 + drivers/scsi/aacraid/include/aifstruc.h | 315 +++ drivers/scsi/aacraid/include/build_number.h | 36 + drivers/scsi/aacraid/include/commdata.h | 104 + drivers/scsi/aacraid/include/commerr.h | 122 ++ drivers/scsi/aacraid/include/commfibcontext.h | 93 + drivers/scsi/aacraid/include/comprocs.h | 84 + drivers/scsi/aacraid/include/comproto.h | 74 + drivers/scsi/aacraid/include/comstruc.h | 412 ++++ drivers/scsi/aacraid/include/comsup.h | 124 ++ drivers/scsi/aacraid/include/fsact.h | 152 ++ drivers/scsi/aacraid/include/fsafs.h | 79 + drivers/scsi/aacraid/include/fsaioctl.h | 129 ++ drivers/scsi/aacraid/include/fsaport.h | 124 ++ drivers/scsi/aacraid/include/fsatypes.h | 197 ++ drivers/scsi/aacraid/include/linit.h | 105 + drivers/scsi/aacraid/include/monkerapi.h | 87 + drivers/scsi/aacraid/include/nodetype.h | 64 + drivers/scsi/aacraid/include/nvramioctl.h | 110 + drivers/scsi/aacraid/include/osheaders.h | 113 + drivers/scsi/aacraid/include/ostypes.h | 145 ++ drivers/scsi/aacraid/include/pcisup.h | 93 + drivers/scsi/aacraid/include/perfpack.h | 107 + drivers/scsi/aacraid/include/port.h | 47 + drivers/scsi/aacraid/include/protocol.h | 243 +++ drivers/scsi/aacraid/include/revision.h | 347 +++ drivers/scsi/aacraid/include/rx.h | 53 + drivers/scsi/aacraid/include/rxcommon.h | 94 + drivers/scsi/aacraid/include/sap1.h | 57 + drivers/scsi/aacraid/include/sap1common.h | 105 + drivers/scsi/aacraid/linit.c | 939 ++++++++ drivers/scsi/aacraid/osddi.c | 362 +++ drivers/scsi/aacraid/osfuncs.c | 472 ++++ drivers/scsi/aacraid/ossup.c | 164 ++ drivers/scsi/aacraid/port.c | 233 ++ drivers/scsi/aacraid/rx.c | 702 ++++++ drivers/scsi/aacraid/sap1sup.c | 633 ++++++ drivers/scsi/hosts.c | 7 + drivers/scsi/megaraid.c | 6 +- drivers/scsi/ncr53c8xx.c | 14 +- drivers/scsi/scsi.c | 2 + drivers/scsi/sd.c | 50 +- drivers/scsi/sym53c8xx.c | 22 +- drivers/scsi/sym53c8xx_defs.h | 10 +- drivers/sound/ac97_codec.c | 2 + drivers/sound/cs4281.c | 2 +- drivers/sound/emu10k1/emu_wrapper.h | 33 - drivers/sound/emu10k1/midi.c | 2 +- drivers/sound/es1370.c | 8 - drivers/sound/es1371.c | 8 - drivers/sound/esssolo1.c | 9 +- drivers/sound/maestro.c | 3 - drivers/sound/sb_mixer.c | 9 +- drivers/sound/sonicvibes.c | 8 - drivers/usb/acm.c | 1 + fs/Config.in | 3 + fs/ext2/balloc.c | 17 +- fs/ext2/inode.c | 187 +- fs/nls/Config.in | 3 +- fs/smbfs/ChangeLog | 10 + fs/smbfs/dir.c | 13 +- fs/smbfs/inode.c | 34 +- fs/smbfs/proc.c | 444 ++-- fs/smbfs/sock.c | 17 +- include/asm-alpha/page.h | 13 + include/asm-alpha/semaphore.h | 5 + include/asm-alpha/types.h | 2 + include/asm-arm/page.h | 13 + include/asm-arm/semaphore.h | 5 + include/asm-arm/types.h | 2 + include/asm-i386/page.h | 20 + include/asm-i386/semaphore.h | 5 + include/asm-i386/types.h | 2 + include/asm-m68k/page.h | 13 + include/asm-m68k/semaphore.h | 5 + include/asm-m68k/types.h | 2 + include/asm-mips/page.h | 16 +- include/asm-mips/semaphore.h | 5 + include/asm-mips/types.h | 2 + include/asm-ppc/page.h | 14 + include/asm-ppc/semaphore.h | 5 + include/asm-s390/irq.h | 5 +- include/asm-s390/page.h | 14 + include/asm-s390/semaphore.h | 5 + include/asm-s390/types.h | 2 + include/asm-sparc/semaphore.h | 5 + include/asm-sparc64/semaphore.h | 5 + include/linux/compatmac.h | 11 - include/linux/devfs_fs_kernel.h | 2 + include/linux/fs.h | 7 + include/linux/i2o.h | 6 - include/linux/joystick.h | 8 +- include/linux/kcomp.h | 41 - include/linux/list.h | 13 + include/linux/pci.h | 5 + include/linux/proc_fs.h | 16 + include/linux/sched.h | 7 + include/linux/smb.h | 6 + include/linux/smb_fs.h | 9 +- include/linux/smb_fs_sb.h | 16 +- include/linux/smb_mount.h | 26 +- include/linux/videodev.h | 2 + include/linux/vmalloc.h | 5 +- include/linux/wait.h | 7 + mm/slab.c | 2 +- net/ipv4/Config.in | 2 +- net/ipv4/ipconfig.c | 172 +- 138 files changed, 15232 insertions(+), 566 deletions(-) create mode 100644 drivers/scsi/aacraid/Makefile create mode 100644 drivers/scsi/aacraid/aachba.c create mode 100644 drivers/scsi/aacraid/aacid.c create mode 100644 drivers/scsi/aacraid/commctrl.c create mode 100644 drivers/scsi/aacraid/comminit.c create mode 100644 drivers/scsi/aacraid/commsup.c create mode 100644 drivers/scsi/aacraid/crapfile create mode 100644 drivers/scsi/aacraid/dpcsup.c create mode 100644 drivers/scsi/aacraid/include/AacGenericTypes.h create mode 100644 drivers/scsi/aacraid/include/aac_unix_defs.h create mode 100644 drivers/scsi/aacraid/include/adapter.h create mode 100644 drivers/scsi/aacraid/include/afacomm.h create mode 100644 drivers/scsi/aacraid/include/aifstruc.h create mode 100644 drivers/scsi/aacraid/include/build_number.h create mode 100644 drivers/scsi/aacraid/include/commdata.h create mode 100644 drivers/scsi/aacraid/include/commerr.h create mode 100644 drivers/scsi/aacraid/include/commfibcontext.h create mode 100644 drivers/scsi/aacraid/include/comprocs.h create mode 100644 drivers/scsi/aacraid/include/comproto.h create mode 100644 drivers/scsi/aacraid/include/comstruc.h create mode 100644 drivers/scsi/aacraid/include/comsup.h create mode 100644 drivers/scsi/aacraid/include/fsact.h create mode 100644 drivers/scsi/aacraid/include/fsafs.h create mode 100644 drivers/scsi/aacraid/include/fsaioctl.h create mode 100644 drivers/scsi/aacraid/include/fsaport.h create mode 100644 drivers/scsi/aacraid/include/fsatypes.h create mode 100644 drivers/scsi/aacraid/include/linit.h create mode 100644 drivers/scsi/aacraid/include/monkerapi.h create mode 100644 drivers/scsi/aacraid/include/nodetype.h create mode 100644 drivers/scsi/aacraid/include/nvramioctl.h create mode 100644 drivers/scsi/aacraid/include/osheaders.h create mode 100644 drivers/scsi/aacraid/include/ostypes.h create mode 100644 drivers/scsi/aacraid/include/pcisup.h create mode 100644 drivers/scsi/aacraid/include/perfpack.h create mode 100644 drivers/scsi/aacraid/include/port.h create mode 100644 drivers/scsi/aacraid/include/protocol.h create mode 100644 drivers/scsi/aacraid/include/revision.h create mode 100644 drivers/scsi/aacraid/include/rx.h create mode 100644 drivers/scsi/aacraid/include/rxcommon.h create mode 100644 drivers/scsi/aacraid/include/sap1.h create mode 100644 drivers/scsi/aacraid/include/sap1common.h create mode 100644 drivers/scsi/aacraid/linit.c create mode 100644 drivers/scsi/aacraid/osddi.c create mode 100644 drivers/scsi/aacraid/osfuncs.c create mode 100644 drivers/scsi/aacraid/ossup.c create mode 100644 drivers/scsi/aacraid/port.c create mode 100644 drivers/scsi/aacraid/rx.c create mode 100644 drivers/scsi/aacraid/sap1sup.c diff --git a/Documentation/Configure.help b/Documentation/Configure.help index fe6b95c1eb29..1e973bc0881c 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1818,6 +1818,11 @@ ATI Mach64 display support CONFIG_FB_ATY This driver supports graphics boards with the ATI Mach64 chips. + This driver is also available as a module ( = code which can be + inserted and removed from the running kernel whenever you want). + The module will be called atyfb.o. If you want to compile it as + a module, say M here and read Documentation/modules.txt. + PowerMac "control" frame buffer device support CONFIG_FB_CONTROL This driver supports a frame buffer for the graphics adapter in the @@ -7933,6 +7938,13 @@ CONFIG_SMB_FS want), say M here and read Documentation/modules.txt. The module will be called smbfs.o. Most people say N, however. +nls support setting +CONFIG_SMB_NLS_REMOTE + This setting allows you to specify a default value for which + codepage the server uses. If this field is left blank no + translations will be done. The local codepage/charset default to + CONFIG_NLS_DEFAULT, you need to set that value in the NLS menu. + Coda filesystem support CONFIG_CODA_FS Coda is an advanced network filesystem, similar to NFS in that it diff --git a/MAINTAINERS b/MAINTAINERS index 0c448948f905..6bf6450cbfdb 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -93,6 +93,12 @@ M: p_gortmaker@yahoo.com L: linux-net@vger.kernel.org S: Maintained +AACRAID ADAPTEC RAID DRIVER +P: Brian M. Boerner +M: aacraid@ntc.adaptec.com +L: To Be Announced +S: Maintained + AD1816 SOUND DRIVER P: Thorsten Knabe M: Thorsten Knabe diff --git a/Makefile b/Makefile index 6d895658e2c0..67fa7747ccb8 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 18 -EXTRAVERSION = pre2 +EXTRAVERSION = pre3 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c index 7130813301d0..5638a1a0c582 100644 --- a/arch/alpha/lib/csum_partial_copy.c +++ b/arch/alpha/lib/csum_partial_copy.c @@ -173,11 +173,11 @@ csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst, { unsigned long carry = 0; unsigned long word; + unsigned long second_dest; int err = 0; mskql(partial_dest, doff, partial_dest); while (len >= 0) { - unsigned long second_dest; err |= __get_user(word, src); len -= 8; insql(word, doff, second_dest); @@ -189,35 +189,30 @@ csum_partial_cfu_src_aligned(const unsigned long *src, unsigned long *dst, carry = checksum < word; dst++; } - len += doff; - checksum += carry; - if (len >= 0) { - unsigned long second_dest; + len += 8; + if (len) { + checksum += carry; err |= __get_user(word, src); - mskql(word, len-doff, word); + mskql(word, len, word); + len -= 8; checksum += word; insql(word, doff, second_dest); - stq_u(partial_dest | second_dest, dst); + len += doff; carry = checksum < word; - if (len) { - ldq_u(second_dest, dst+1); + partial_dest |= second_dest; + if (len >= 0) { + stq_u(partial_dest, dst); + if (!len) goto out; + dst++; insqh(word, doff, partial_dest); - mskqh(second_dest, len, second_dest); - stq_u(partial_dest | second_dest, dst+1); } - checksum += carry; - } else if (len & 7) { - unsigned long second_dest; - err |= __get_user(word, src); - ldq_u(second_dest, dst); - mskql(word, len-doff, word); - checksum += word; - mskqh(second_dest, len, second_dest); - carry = checksum < word; - insql(word, doff, word); - stq_u(partial_dest | word | second_dest, dst); - checksum += carry; + doff = len; } + ldq_u(second_dest, dst); + mskqh(second_dest, doff, second_dest); + stq_u(partial_dest | second_dest, dst); +out: + checksum += carry; if (err) *errp = err; return checksum; } @@ -283,7 +278,7 @@ csum_partial_cfu_unaligned(const unsigned long * src, unsigned long * dst, stq_u(partial_dest | second_dest, dst+1); } checksum += carry; - } else if (len & 7) { + } else { unsigned long second, word; unsigned long second_dest; diff --git a/arch/i386/defconfig b/arch/i386/defconfig index 057ffb9800eb..db49025f23bc 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -166,6 +166,7 @@ CONFIG_SCSI_CONSTANTS=y # CONFIG_SCSI_AHA152X is not set # CONFIG_SCSI_AHA1542 is not set # CONFIG_SCSI_AHA1740 is not set +# CONFIG_SCSI_AACRAID is not set # CONFIG_SCSI_AIC7XXX is not set # CONFIG_SCSI_IPS is not set # CONFIG_SCSI_ADVANSYS is not set diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index 6723c98f2a40..9565f40d2118 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -171,16 +171,8 @@ #include /* 2.2-2.3 Compatability defines */ -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} #define __setup(x, y) #define module_init(x) -#define set_current_state(a) current->state = (a) -#define create_proc_info_entry(n, m, b, g) \ - { \ - struct proc_dir_entry *r = create_proc_entry(n, m, b); \ - if (r) r->get_info = g; \ - } EXPORT_SYMBOL(apm_register_callback); EXPORT_SYMBOL(apm_unregister_callback); diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index 3f019e0f3c76..dc89e5d79ca1 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -1055,7 +1055,6 @@ static void __init pci_fixup_serverworks(struct pci_dev *d) /* * Find and scan busses behind ServerWorks north bridge chips */ - struct pci_bus *bus; unsigned char busno, busmax; pci_probe |= PCI_NO_PEER_FIXUP; pci_read_config_byte(d, 0x44, &busno); @@ -1070,7 +1069,6 @@ static void __init pci_fixup_compaq(struct pci_dev *d) /* * Find and scan busses behind RCC LE north bridge chips */ - struct pci_bus *bus; unsigned char busno, busmax; pci_probe |= PCI_NO_PEER_FIXUP; pci_read_config_byte(d, 0xc8, &busno); diff --git a/arch/i386/kernel/microcode.c b/arch/i386/kernel/microcode.c index ba12cc426b47..7e27accd52ae 100644 --- a/arch/i386/kernel/microcode.c +++ b/arch/i386/kernel/microcode.c @@ -119,6 +119,7 @@ int __init microcode_init(void) return 0; } +#ifdef MODULE static void microcode_exit(void) { misc_deregister(µcode_dev); @@ -128,7 +129,6 @@ static void microcode_exit(void) MICROCODE_VERSION); } -#ifdef MODULE int init_module(void) { return microcode_init(); diff --git a/arch/i386/kernel/mtrr.c b/arch/i386/kernel/mtrr.c index f6e7eb67be9f..54a8a8e0db8d 100644 --- a/arch/i386/kernel/mtrr.c +++ b/arch/i386/kernel/mtrr.c @@ -305,7 +305,7 @@ static char *ascii_buffer = NULL; static unsigned int ascii_buf_bytes = 0; #endif static unsigned int *usage_table = NULL; -static spinlock_t main_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t main_lock __attribute((unused)) = SPIN_LOCK_UNLOCKED; /* Private functions */ #ifdef CONFIG_PROC_FS diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 1a9272c5c74c..eddb88f7f768 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -118,13 +118,6 @@ #include #endif -#if LINUX_VERSION_CODE < VERSION(2,3,0) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} -#define init_waitqueue_head(head) *(head) = NULL -#define set_current_state(a) current->state = (a) -#endif - #if LINUX_VERSION_CODE >= VERSION(2,1,4) #include #define GET_USER(error,value,addr) error = get_user(value,addr) diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index 5e2158e96ff1..0dc91c991d68 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -102,14 +102,6 @@ #include #include -#if LINUX_VERSION_CODE < VERSION(2,3,0) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(name,task) struct wait_queue (name) = {(task),NULL} -#define init_waitqueue_head(head) *(head) = NULL -#define DECLARE_MUTEX(name) struct semaphore (name) = MUTEX -#define set_current_state(a) current->state = (a) -#endif - #ifdef CONFIG_SYNCLINK_SYNCPPP_MODULE #define CONFIG_SYNCLINK_SYNCPPP 1 #endif diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c index 71fffaffd2cc..3853ce1840ef 100644 --- a/drivers/misc/parport_pc.c +++ b/drivers/misc/parport_pc.c @@ -902,11 +902,13 @@ static int parport_pc_init_pci (int irq, int dma) { { 0, -1 }, } }, { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DUAL_PAR_B, 1, { { 0, -1 }, } }, + { PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_BOCA_IOPPAR, 1, + { { 0, -1 }, } }, { PCI_VENDOR_ID_AFAVLAB, PCI_DEVICE_ID_AFAVLAB_TK9902, 1, { { 0, 1 }, } }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889, 1, - { { 2, -1 }, } }, - { PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_4008A, 1, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954PP, 1, + { { 0, -1 }, } }, + { PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_12PCI840, 1, { { 0, 1 }, } }, { 0, } }; diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 97df972e13dd..5c34490a0ad5 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -126,7 +126,6 @@ #endif #if (LINUX_VERSION_CODE < 0x02032a) -typedef u32 dma_addr_t; static inline void *pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) @@ -608,6 +607,7 @@ MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(max_tx_desc, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(rx_coal_tick, "1-" __MODULE_STRING(8) "i"); MODULE_PARM(max_rx_desc, "1-" __MODULE_STRING(8) "i"); +#endif void __exit ace_module_cleanup(void) @@ -697,7 +697,6 @@ void __exit ace_module_cleanup(void) root_dev = next; } } -#endif int __init ace_module_init(void) diff --git a/drivers/net/cosa.c b/drivers/net/cosa.c index 4879d8101b99..5267df34ce34 100644 --- a/drivers/net/cosa.c +++ b/drivers/net/cosa.c @@ -102,13 +102,6 @@ #include "syncppp.h" #include "cosa.h" -/* Linux version stuff */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,1) -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(wait, current) \ - struct wait_queue wait = { current, NULL } -#endif - /* Maximum length of the identification string. */ #define COSA_MAX_ID_STRING 128 diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c index 382dac4dd0e6..d726acb0f20f 100644 --- a/drivers/net/eepro100.c +++ b/drivers/net/eepro100.c @@ -167,6 +167,9 @@ MODULE_PARM(multicast_filter_limit, "i"); #ifndef PCI_DEVICE_ID_INTEL_ID1030 #define PCI_DEVICE_ID_INTEL_ID1030 0x1030 #endif +#ifndef PCI_DEVICE_ID_INTEL_ID2449 +#define PCI_DEVICE_ID_INTEL_ID2449 0x2449 +#endif /* The total I/O port extent of the board. The registers beyond 0x18 only exist on the i82558. */ @@ -326,6 +329,10 @@ struct pci_id_info { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID1030, 0 }, + { "Intel PCI EtherExpress Pro100 82562EM", + PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ID2449, + 0 + }, {0,} /* 0 terminated list. */ }; diff --git a/drivers/net/sbni.c b/drivers/net/sbni.c index cfe043919212..208851c4ea2c 100644 --- a/drivers/net/sbni.c +++ b/drivers/net/sbni.c @@ -342,7 +342,7 @@ int __init sbni_probe(struct device *dev) if(base_addr > 0x1ff) /* Check a single specified location. */ return sbni_probe1(dev, base_addr); else if(base_addr != 0) /* Don't probe at all. */ - return ENXIO; + return -ENXIO; for(i = 0; (base_addr = netcard_portlist[i]); i++) { if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1) @@ -353,7 +353,7 @@ int __init sbni_probe(struct device *dev) return 0; } } - return ENODEV; + return -ENODEV; } #endif /* have devlist*/ @@ -416,7 +416,7 @@ static int __init sbni_probe1(struct device *dev, int ioaddr) } if(bad_card) - return ENODEV; + return -ENODEV; else outb(0, ioaddr + CSR0); if(dev->irq < 2) @@ -429,8 +429,8 @@ static int __init sbni_probe1(struct device *dev, int ioaddr) if(autoirq == 0) { - printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr); - return EAGAIN; + printk(KERN_ERR "sbni probe at %#x failed to detect IRQ line\n", ioaddr); + return -EAGAIN; } } /* clear FIFO buffer */ @@ -444,7 +444,7 @@ static int __init sbni_probe1(struct device *dev, int ioaddr) if (irqval) { printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); - return EAGAIN; + return -EAGAIN; } } diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx index b2977866f610..8d53f0c46920 100644 --- a/drivers/scsi/ChangeLog.ncr53c8xx +++ b/drivers/scsi/ChangeLog.ncr53c8xx @@ -1,3 +1,8 @@ +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version ncr53c8xx-3.4.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Remove trailing argument #2 from a couple of #undefs. + Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) * version ncr53c8xx-3.4.0 - Remove the PROFILE C and SCRIPTS code. diff --git a/drivers/scsi/ChangeLog.sym53c8xx b/drivers/scsi/ChangeLog.sym53c8xx index 7f20a09c92f8..73aba7f397a9 100644 --- a/drivers/scsi/ChangeLog.sym53c8xx +++ b/drivers/scsi/ChangeLog.sym53c8xx @@ -1,3 +1,10 @@ +Wed Jul 26 23:30 2000 Gerard Roudier (groudier@club-internet.fr) + * version sym53c8xx-1.7.1 + - Provide OpenFirmare path through the proc FS on PPC. + - Download of on-chip SRAM using memcpy_toio() doesn't work + on PPC. Restore previous method (MEMORY MOVE from SCRIPTS). + - Remove trailing argument #2 from a couple of #undefs. + Sun Jul 09 16:30 2000 Gerard Roudier (groudier@club-internet.fr) * version sym53c8xx-1.7.0 - Remove the PROFILE C and SCRIPTS code. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 40e9c7e3969c..e2c882917ac2 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -26,6 +26,7 @@ dep_tristate 'ACARD SCSI support' CONFIG_SCSI_ACARD $CONFIG_SCSI dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI +dep_tristate 'Adaptec RAID Controller support' CONFIG_SCSI_AACRAID $CONFIG_SCSI dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then bool ' Enable Tagged Command Queueing (TCQ) by default' CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 8558d08eebcc..3287ab01532b 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -5,6 +5,10 @@ # unless it's something special (ie not a .c file). # +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) aacraid + L_TARGET := scsi.a L_OBJS := M_OBJS := @@ -346,6 +350,16 @@ else endif endif +ifeq ($(CONFIG_SCSI_AACRAID),y) + SUB_DIRS += aacraid + MOD_IN_SUB_DIRS += aacraid + L_OBJS += aacraid/aacraid.o +else + ifeq ($(CONFIG_SCSI_AACRAID),m) + MOD_IN_SUB_DIRS += aacraid + endif +endif + ifeq ($(CONFIG_SCSI_AIC7XXX),y) L_OBJS += aic7xxx.o else @@ -705,3 +719,4 @@ sr_mod.o: sr.o sr_ioctl.o sr_vendor.o sd_mod.o: sd.o sd_ioctl.o $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o + diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile new file mode 100644 index 000000000000..013b570b235b --- /dev/null +++ b/drivers/scsi/aacraid/Makefile @@ -0,0 +1,37 @@ +# +# Makefile for the Adaptec aacraid adapter driver +# + +O_OBJS:= linit.o \ + aacid.o \ + osfuncs.o \ + osddi.o \ + aachba.o \ + commctrl.o \ + comminit.o \ + commsup.o \ + dpcsup.o \ + ossup.o \ + port.o \ + rx.o \ + sap1sup.o + +ifeq ($(CONFIG_SCSI_AACRAID),y) + O_TARGET := aacraid.o +else + ifeq ($(CONFIG_SCSI_AACRAID),m) + MOD_LIST_NAME := AACRAID_MODULES + M_OBJS := aacraid.o + O_TARGET := aacraid.o + endif +endif + +EXTRA_CFLAGS += -Iinclude -I.. + +include $(TOPDIR)/Rules.make + +clean: + rm -f core *.o *.a *.s + + + diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c new file mode 100644 index 000000000000..b147551decbc --- /dev/null +++ b/drivers/scsi/aacraid/aachba.c @@ -0,0 +1,1769 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aachba.c + * + * Abstract: driver... + * +--*/ +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ +#include "osheaders.h" +#include "AacGenericTypes.h" +#include "aac_unix_defs.h" +#include "comstruc.h" +#include "monkerapi.h" +#include "protocol.h" +#include "fsafs.h" +#include "fsact.h" +#include "fsaioctl.h" + +#include "sap1common.h" +#include "fsaport.h" +#include "pcisup.h" +#include "sap1.h" +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +/* SCSI Commands */ +#define SS_TEST 0x00 /* Test unit ready */ +#define SS_REZERO 0x01 /* Rezero unit */ +#define SS_REQSEN 0x03 /* Request Sense */ +#define SS_REASGN 0x07 /* Reassign blocks */ +#define SS_READ 0x08 /* Read 6 */ +#define SS_WRITE 0x0A /* Write 6 */ +#define SS_INQUIR 0x12 /* inquiry */ +#define SS_ST_SP 0x1B /* Start/Stop unit */ +#define SS_LOCK 0x1E /* prevent/allow medium removal */ +#define SS_RESERV 0x16 /* Reserve */ +#define SS_RELES 0x17 /* Release */ +#define SS_MODESEN 0x1A /* Mode Sense 6 */ +#define SS_RDCAP 0x25 /* Read Capacity */ +#define SM_READ 0x28 /* Read 10 */ +#define SM_WRITE 0x2A /* Write 10 */ +#define SS_SEEK 0x2B /* Seek */ + +/* values for inqd_pdt: Peripheral device type in plain English */ +#define INQD_PDT_DA 0x00 /* Direct-access (DISK) device */ +#define INQD_PDT_PROC 0x03 /* Processor device */ +#define INQD_PDT_CHNGR 0x08 /* Changer (jukebox, scsi2) */ +#define INQD_PDT_COMM 0x09 /* Communication device (scsi2) */ +#define INQD_PDT_NOLUN2 0x1f /* Unknown Device (scsi2) */ +#define INQD_PDT_NOLUN 0x7f /* Logical Unit Not Present */ + +#define INQD_PDT_DMASK 0x1F /* Peripheral Device Type Mask */ +#define INQD_PDT_QMASK 0xE0 /* Peripheral Device Qualifer Mask */ + +#define TARGET_LUN_TO_CONTAINER(Target, Lun) (((Lun) << 4) | Target) +#define CONTAINER_TO_TARGET(Container) ((Container) & 0xf) +#define CONTAINER_TO_LUN(Container) ((Container) >> 4) + +#define MAX_FIB_DATA (sizeof(FIB) - sizeof(FIB_HEADER)) + +#define MAX_DRIVER_SG_SEGMENT_COUNT 17 + +// ------------------------------------------------------ +// Sense keys +// +#define SENKEY_NO_SENSE 0x00 // +#define SENKEY_UNDEFINED 0x01 // +#define SENKEY_NOT_READY 0x02 // +#define SENKEY_MEDIUM_ERR 0x03 // +#define SENKEY_HW_ERR 0x04 // +#define SENKEY_ILLEGAL 0x05 // +#define SENKEY_ATTENTION 0x06 // +#define SENKEY_PROTECTED 0x07 // +#define SENKEY_BLANK 0x08 // +#define SENKEY_V_UNIQUE 0x09 // +#define SENKEY_CPY_ABORT 0x0A // +#define SENKEY_ABORT 0x0B // +#define SENKEY_EQUAL 0x0C // +#define SENKEY_VOL_OVERFLOW 0x0D // +#define SENKEY_MISCOMP 0x0E // +#define SENKEY_RESERVED 0x0F // + +// ------------------------------------------------------ +// Sense codes +// +#define SENCODE_NO_SENSE 0x00 +#define SENCODE_END_OF_DATA 0x00 +#define SENCODE_BECOMING_READY 0x04 +#define SENCODE_INIT_CMD_REQUIRED 0x04 +#define SENCODE_PARAM_LIST_LENGTH_ERROR 0x1A +#define SENCODE_INVALID_COMMAND 0x20 +#define SENCODE_LBA_OUT_OF_RANGE 0x21 +#define SENCODE_INVALID_CDB_FIELD 0x24 +#define SENCODE_LUN_NOT_SUPPORTED 0x25 +#define SENCODE_INVALID_PARAM_FIELD 0x26 +#define SENCODE_PARAM_NOT_SUPPORTED 0x26 +#define SENCODE_PARAM_VALUE_INVALID 0x26 +#define SENCODE_RESET_OCCURRED 0x29 +#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x3E +#define SENCODE_INQUIRY_DATA_CHANGED 0x3F +#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x39 +#define SENCODE_DIAGNOSTIC_FAILURE 0x40 +#define SENCODE_INTERNAL_TARGET_FAILURE 0x44 +#define SENCODE_INVALID_MESSAGE_ERROR 0x49 +#define SENCODE_LUN_FAILED_SELF_CONFIG 0x4c +#define SENCODE_OVERLAPPED_COMMAND 0x4E + +// ------------------------------------------------------ +// Additional sense codes +// +#define ASENCODE_NO_SENSE 0x00 +#define ASENCODE_END_OF_DATA 0x05 +#define ASENCODE_BECOMING_READY 0x01 +#define ASENCODE_INIT_CMD_REQUIRED 0x02 +#define ASENCODE_PARAM_LIST_LENGTH_ERROR 0x00 +#define ASENCODE_INVALID_COMMAND 0x00 +#define ASENCODE_LBA_OUT_OF_RANGE 0x00 +#define ASENCODE_INVALID_CDB_FIELD 0x00 +#define ASENCODE_LUN_NOT_SUPPORTED 0x00 +#define ASENCODE_INVALID_PARAM_FIELD 0x00 +#define ASENCODE_PARAM_NOT_SUPPORTED 0x01 +#define ASENCODE_PARAM_VALUE_INVALID 0x02 +#define ASENCODE_RESET_OCCURRED 0x00 +#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET 0x00 +#define ASENCODE_INQUIRY_DATA_CHANGED 0x03 +#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED 0x00 +#define ASENCODE_DIAGNOSTIC_FAILURE 0x80 +#define ASENCODE_INTERNAL_TARGET_FAILURE 0x00 +#define ASENCODE_INVALID_MESSAGE_ERROR 0x00 +#define ASENCODE_LUN_FAILED_SELF_CONFIG 0x00 +#define ASENCODE_OVERLAPPED_COMMAND 0x00 + +#define BYTE0( x ) ( unsigned char )( x ) +#define BYTE1( x ) ( unsigned char )( x >> 8 ) +#define BYTE2( x ) ( unsigned char )( x >> 16 ) +#define BYTE3( x ) ( unsigned char )( x >> 24 ) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +/* SCSI inquiry data */ + +struct inquiry_data { + u8 inqd_pdt; /* Peripheral qualifier | Peripheral Device Type */ + u8 inqd_dtq; /* RMB | Device Type Qualifier */ + u8 inqd_ver; /* ISO version | ECMA version | ANSI-approved version */ + u8 inqd_rdf; /* AENC | TrmIOP | Response data format */ + u8 inqd_len; /* Additional length (n-4) */ + u8 inqd_pad1[2]; /* Reserved - must be zero */ + u8 inqd_pad2; /* RelAdr | WBus32 | WBus16 | Sync | Linked |Reserved| CmdQue | SftRe */ + u8 inqd_vid[8]; /* Vendor ID */ + u8 inqd_pid[16]; /* Product ID */ + u8 inqd_prl[4]; /* Product Revision Level */ +}; + +struct sense_data { + u8 error_code; // 70h (current errors), 71h(deferred errors) + u8 valid:1; // A valid bit of one indicates that the information + // field contains valid information as defined in the + // SCSI-2 Standard. + + u8 segment_number; // Only used for COPY, COMPARE, or COPY AND VERIFY + // commands + + u8 sense_key:4; // Sense Key + u8 reserved:1; + u8 ILI:1; // Incorrect Length Indicator + u8 EOM:1; // End Of Medium - reserved for random access devices + u8 filemark:1; // Filemark - reserved for random access devices + + u8 information[4]; // for direct-access devices, contains the unsigned + // logical block address or residue associated with + // the sense key + u8 add_sense_len; // number of additional sense bytes to follow this field + u8 cmnd_info[4]; // not used + u8 ASC; // Additional Sense Code + u8 ASCQ; // Additional Sense Code Qualifier + u8 FRUC; // Field Replaceable Unit Code - not used + + u8 bit_ptr:3; // indicates which byte of the CDB or parameter data + // was in error + u8 BPV:1; // bit pointer valid (BPV): 1- indicates that + // the bit_ptr field has valid value + u8 reserved2:2; + u8 CD:1; // command data bit: 1- illegal parameter in CDB. + // 0- illegal parameter in data. + u8 SKSV:1; + + u8 field_ptr[2]; // byte of the CDB or parameter data in error +}; + +/*------------------------------------------------------------------------------ + * G L O B A L S + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + * M O D U L E G L O B A L S + *----------------------------------------------------------------------------*/ + +static fsadev_t *g_fsa_dev_array[8]; // SCSI Device Instance Pointers +static struct sense_data g_sense_data[MAXIMUM_NUM_CONTAINERS]; + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ + +AAC_STATUS AacHba_OpenAdapter(void * arg); +AAC_STATUS AacHba_CloseAdapter(void * arg); +int AacHba_HandleAif(void * arg, PFIB_CONTEXT FibContext); +int AacHba_AdapterDeviceControl (void * arg, PAFA_IOCTL_CMD IoctlCmdPtr, int * ReturnStatus); +void AacHba_CompleteScsi(Scsi_Cmnd *scsi_cmnd_ptr); +void AacHba_CompleteScsiNoLock(Scsi_Cmnd *scsi_cmnd_ptr); +static void AacHba_ReadCallback(void *context, PFIB_CONTEXT FibContext, int FibStatus ); +static void AacHba_WriteCallback(void *context, PFIB_CONTEXT FibContext, int FibStatus ); +int AacHba_DoScsiRead(Scsi_Cmnd *scsi_cmnd_ptr, int ContainerId, int wait); +int AacHba_DoScsiWrite(Scsi_Cmnd *scsi_cmnd_ptr, int ContainerId, int wait); +int AacHba_QueryDisk(void * arg, PAFA_IOCTL_CMD IoctlCmdPtr); +int AacHba_ForceDeleteDisk(void * arg, PAFA_IOCTL_CMD IoctlCmdPtr); +int AacHba_DeleteDisk(void * arg, PAFA_IOCTL_CMD IoctlCmdPtr); +void AacHba_DetachAdapter(void * arg); +int AacCommDetachAdapter(PAFA_COMM_ADAPTER adapter); +void AacHba_SetSenseData(char * sense_buf,u8 sense_key,u8 sense_code, + u8 a_sense_code, u8 incorrect_length, u8 bit_pointer, + unsigned field_pointer, unsigned long residue); +static void get_sd_devname(long disknum, char * buffer); + +// Keep these here for the time being - #REVIEW# + +int AfaCommAdapterDeviceControl (void * arg,PAFA_IOCTL_CMD IoctlCmdPtr); + +AAC_STATUS AfaCommRegisterNewClassDriver(PAFA_COMM_ADAPTER adapter, + PAFA_NEW_CLASS_DRIVER NewClassDriver, + PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse +); + +void SetInqDataStr(int, void *, int); + + +/*------------------------------------------------------------------------------ + * F U N C T I O N S + *----------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------------ + AacHba_ClassDriverInit() + + Setup 'core' class driver to answer ioctl's + *----------------------------------------------------------------------------*/ + +int AacHba_ClassDriverInit(PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr) +{ + AFA_NEW_CLASS_DRIVER NewClassDriver; + AFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse; + PAFA_COMM_ADAPTER adapter; + + adapter = (AFA_COMM_ADAPTER *)CommonExtensionPtr->Adapter; + + RtlZeroMemory( &NewClassDriver, sizeof( AFA_NEW_CLASS_DRIVER ) ); + + // ClassDriverExtension is the first argument passed to class driver functions below + NewClassDriver.ClassDriverExtension = CommonExtensionPtr; + + NewClassDriver.OpenAdapter = AacHba_OpenAdapter; + NewClassDriver.CloseAdapter = AacHba_CloseAdapter; + NewClassDriver.DeviceControl = AacHba_AdapterDeviceControl; + NewClassDriver.HandleAif = AacHba_HandleAif; + AfaCommRegisterNewClassDriver( adapter, &NewClassDriver, &NewClassDriverResponse ); + + return(0); +} + + +/*------------------------------------------------------------------------------ + AacHba_ProbeContainers() + + Make a list of all containers in the system. + *----------------------------------------------------------------------------*/ +int AacHba_ProbeContainers( + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr ) +/*----------------------------------------------------------------------------*/ +{ + fsadev_t *fsa_dev_ptr; + int Index, Status; + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + PFIB_CONTEXT FibContext; + AFA_COMM_ADAPTER *adapter; + unsigned instance; + + adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id; + + if( !( FibContext = adapter->CommFuncs.AllocateFib( adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" ); + return( STATUS_UNSUCCESSFUL ); + } + + for ( Index = 0; Index < MAXIMUM_NUM_CONTAINERS; Index++ ) + { + adapter->CommFuncs.InitializeFib( FibContext ); + + DiskInfo = ( PMNTINFO )adapter->CommFuncs.GetFibData( FibContext ); + + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = Index; + DiskInfo->MntType = FT_FILESYS; + + Status = adapter->CommFuncs.SendFib(ContainerCommand, + FibContext, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + if ( Status ) + { + cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" ); + break; + } + + DiskInfoResponse = ( PMNTINFORESPONSE )adapter->CommFuncs.GetFibData( FibContext ); + + if ( ( DiskInfoResponse->Status == ST_OK ) && + ( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) + { + + + fsa_dev_ptr->ContainerValid[Index] = TRUE; + fsa_dev_ptr->ContainerType[Index] = DiskInfoResponse->MntTable[0].VolType; + fsa_dev_ptr->ContainerSize[Index] = DiskInfoResponse->MntTable[0].Capacity; + + if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY) + fsa_dev_ptr->ContainerReadOnly[Index] = TRUE; + } + + adapter->CommFuncs.CompleteFib( FibContext ); + + // If there are no more containers, then stop asking. + if ((Index + 1) >= DiskInfoResponse->MntRespCount) + break; + + } // end for() + + adapter->CommFuncs.FreeFib( FibContext ); + + g_fsa_dev_array[instance] = fsa_dev_ptr; + + return( Status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_ProbeContainer() + + Probe a single container. + *----------------------------------------------------------------------------*/ +int AacHba_ProbeContainer( PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr, int ContainerId ) +/*----------------------------------------------------------------------------*/ +{ + fsadev_t *fsa_dev_ptr; + int Status; + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + PFIB_CONTEXT FibContext; + AFA_COMM_ADAPTER *adapter; + unsigned instance; + + adapter = ( AFA_COMM_ADAPTER * )CommonExtensionPtr->Adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + instance = CommonExtensionPtr->OsDep.scsi_host_ptr->unique_id; + + if( !( FibContext = adapter->CommFuncs.AllocateFib( adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_ProbeContainers: AllocateFib failed" ); + return( STATUS_UNSUCCESSFUL ); + } + + adapter->CommFuncs.InitializeFib( FibContext ); + + DiskInfo = ( PMNTINFO )adapter->CommFuncs.GetFibData( FibContext ); + + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = ContainerId; + DiskInfo->MntType = FT_FILESYS; + + Status = adapter->CommFuncs.SendFib( ContainerCommand, + FibContext, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + if ( Status ) + { + cmn_err( CE_WARN, "ProbeContainers: SendFIb Failed" ); + adapter->CommFuncs.CompleteFib( FibContext ); + adapter->CommFuncs.FreeFib( FibContext ); + return( Status ); + } + + DiskInfoResponse = ( PMNTINFORESPONSE )adapter->CommFuncs.GetFibData( FibContext ); + + if ( ( DiskInfoResponse->Status == ST_OK ) && + ( DiskInfoResponse->MntTable[0].VolType != CT_NONE ) ) + { + + fsa_dev_ptr->ContainerValid[ContainerId] = TRUE; + fsa_dev_ptr->ContainerType[ContainerId] = DiskInfoResponse->MntTable[0].VolType; + fsa_dev_ptr->ContainerSize[ContainerId] = DiskInfoResponse->MntTable[0].Capacity; + if (DiskInfoResponse->MntTable[0].ContentState & FSCS_READONLY) + fsa_dev_ptr->ContainerReadOnly[ContainerId] = TRUE; + } + + adapter->CommFuncs.CompleteFib( FibContext ); + adapter->CommFuncs.FreeFib( FibContext ); + + return( Status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CompleteScsi() + + Call SCSI completion routine after acquiring io_request_lock + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ + +void AacHba_CompleteScsi(Scsi_Cmnd *scsi_cmnd_ptr) +{ + unsigned long cpu_flags; + spin_lock_irqsave( &io_request_lock, cpu_flags ); + scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr ); + spin_unlock_irqrestore( &io_request_lock, cpu_flags ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CompleteScsiNoLock() + + Call SCSI completion routine + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ + +void AacHba_CompleteScsiNoLock(Scsi_Cmnd *scsi_cmnd_ptr) +{ + scsi_cmnd_ptr->scsi_done( scsi_cmnd_ptr ); +} + +/*------------------------------------------------------------------------------ + AacHba_DoScsiCmd() + + Process SCSI command + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ + +int AacHba_DoScsiCmd(Scsi_Cmnd *scsi_cmnd_ptr, int wait) +{ + int ContainerId = 0; + fsadev_t *fsa_dev_ptr; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + int MiniPortIndex; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + MiniPortIndex = CommonExtensionPtr->OsDep.MiniPortIndex; + + fsa_dev_ptr = g_fsa_dev_array[ scsi_cmnd_ptr->host->unique_id ]; + + // If the bus, target or lun is out of range, return fail + // Test does not apply to ID 16, the pseudo id for the controller itself. + if ( scsi_cmnd_ptr->target != scsi_cmnd_ptr->host->this_id ) + { + if( ( scsi_cmnd_ptr->channel > 0 ) || + ( scsi_cmnd_ptr->target > 15 ) || + ( scsi_cmnd_ptr->lun > 7 ) ) + { + cmn_err( CE_DEBUG, "The bus, target or lun is out of range = %d, %d, %d", + scsi_cmnd_ptr->channel, + scsi_cmnd_ptr->target, + scsi_cmnd_ptr->lun ); + scsi_cmnd_ptr->result = DID_BAD_TARGET << 16; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + + // If the target container doesn't exist, it may have been newly created + if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 ) + { + switch( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_INQUIR: + case SS_RDCAP: + case SS_TEST: + spin_unlock_irq( &io_request_lock ); + AacHba_ProbeContainer( CommonExtensionPtr, ContainerId ); + spin_lock_irq( &io_request_lock ); + default: + break; + } + } + + // If the target container still doesn't exist, return failure + if( fsa_dev_ptr->ContainerValid[ContainerId] == 0 ) + { + cmn_err( CE_DEBUG, "Target container %d doesn't exist", ContainerId ); + scsi_cmnd_ptr->result = DID_BAD_TARGET << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + } + else // the command is for the controller itself + if( ( scsi_cmnd_ptr->cmnd[0] != SS_INQUIR ) && // only INQUIRY & TUR cmnd supported for controller + ( scsi_cmnd_ptr->cmnd[0] != SS_TEST ) ) + { + cmn_err( CE_WARN, "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x", + scsi_cmnd_ptr->cmnd[0] ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( (char *)&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( -1 ); + } + + // Handle commands here that don't really require going out to the adapter + switch ( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_INQUIR: + { + struct inquiry_data *inq_data_ptr; + + cmn_err( CE_DEBUG, "INQUIRY command, ID: %d", scsi_cmnd_ptr->target ); + inq_data_ptr = ( struct inquiry_data * )scsi_cmnd_ptr->request_buffer; + bzero( inq_data_ptr, sizeof( struct inquiry_data ) ); + + inq_data_ptr->inqd_ver = 2; // claim compliance to SCSI-2 + + inq_data_ptr->inqd_dtq = 0x80; // set RMB bit to one indicating + // that the medium is removable + inq_data_ptr->inqd_rdf = 2; // A response data format value of + // two indicates that the data shall + // be in the format specified in SCSI-2 + inq_data_ptr->inqd_len = 31; + + // Set the Vendor, Product, and Revision Level see: .c i.e. aac.c + SetInqDataStr( MiniPortIndex, + (void *)(inq_data_ptr->inqd_vid), + fsa_dev_ptr->ContainerType[ContainerId]); + + if ( scsi_cmnd_ptr->target == scsi_cmnd_ptr->host->this_id ) + inq_data_ptr->inqd_pdt = INQD_PDT_PROC; // Processor device + else + inq_data_ptr->inqd_pdt = INQD_PDT_DA; // Direct/random access device + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + case SS_RDCAP: + { + int capacity; + char *cp; + + cmn_err( CE_DEBUG, "READ CAPACITY command" ); + capacity = fsa_dev_ptr->ContainerSize[ContainerId]; + cp = scsi_cmnd_ptr->request_buffer; + cp[0] = ( capacity >> 24 ) & 0xff; + cp[1] = ( capacity >> 16 ) & 0xff; + cp[2] = ( capacity >> 8 ) & 0xff; + cp[3] = ( capacity >> 0 ) & 0xff; + cp[4] = 0; + cp[5] = 0; + cp[6] = 2; + cp[7] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + case SS_MODESEN: + { + char *mode_buf; + + cmn_err( CE_DEBUG, "MODE SENSE command" ); + mode_buf = scsi_cmnd_ptr->request_buffer; + mode_buf[0] = 0; // Mode data length (MSB) + mode_buf[1] = 6; // Mode data length (LSB) + mode_buf[2] = 0; // Medium type - default + mode_buf[3] = 0; // Device-specific param, bit 8: 0/1 = write enabled/protected + mode_buf[4] = 0; // reserved + mode_buf[5] = 0; // reserved + mode_buf[6] = 0; // Block descriptor length (MSB) + mode_buf[7] = 0; // Block descriptor length (LSB) + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + return ( 0 ); + } + + + // These commands are all No-Ops + case SS_TEST: + cmn_err( CE_DEBUG, "TEST UNIT READY command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REQSEN: + cmn_err( CE_DEBUG, "REQUEST SENSE command" ); + + memcpy( scsi_cmnd_ptr->sense_buffer, &g_sense_data[ContainerId], + sizeof( struct sense_data ) ); + bzero( &g_sense_data[ContainerId], sizeof( struct sense_data ) ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_LOCK: + cmn_err(CE_DEBUG, "LOCK command"); + + if( scsi_cmnd_ptr->cmnd[4] ) + fsa_dev_ptr->ContainerLocked[ContainerId] = 1; + else + fsa_dev_ptr->ContainerLocked[ContainerId] = 0; + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RESERV: + cmn_err( CE_DEBUG, "RESERVE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_RELES: + cmn_err( CE_DEBUG, "RELEASE command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REZERO: + cmn_err( CE_DEBUG, "REZERO command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_REASGN: + cmn_err( CE_DEBUG, "REASSIGN command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_SEEK: + cmn_err( CE_DEBUG, "SEEK command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + + case SS_ST_SP: + cmn_err( CE_DEBUG, "START/STOP command" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + + switch ( scsi_cmnd_ptr->cmnd[0] ) + { + case SS_READ: + case SM_READ: + // Hack to keep track of ordinal number of the device that corresponds + // to a container. Needed to convert containers to /dev/sd device names + fsa_dev_ptr->ContainerDevNo[ContainerId] = + DEVICE_NR( scsi_cmnd_ptr->request.rq_dev ); + + return( AacHba_DoScsiRead( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + + case SS_WRITE: + case SM_WRITE: + return( AacHba_DoScsiWrite( scsi_cmnd_ptr, ContainerId, wait ) ); + break; + } + // + // Unhandled commands + // + cmn_err( CE_WARN, "Unhandled SCSI Command: 0x%x", scsi_cmnd_ptr->cmnd[0] ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_COMMAND, ASENCODE_INVALID_COMMAND, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiRead() + + Handles SCSI READ requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiRead( + Scsi_Cmnd *scsi_cmnd_ptr, + int ContainerId, + int wait ) +/*----------------------------------------------------------------------------*/ +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKREAD BlockReadDisk; + PBLOCKREADRESPONSE BlockReadResponse; + u16 FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_READ ) // 6 byte command + { + cmn_err( CE_DEBUG, "aachba: received a read(6) command on target %d", ContainerId ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a read(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiRead[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockRead command + if( !( cmd_fibcontext = adapter->CommFuncs.AllocateFib( adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockReadDisk = ( PBLOCKREAD )adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockReadDisk->Command = VM_CtBlockRead; + BlockReadDisk->ContainerId = ContainerId; + BlockReadDisk->BlockNumber = lba; + BlockReadDisk->ByteCount = count * 512; + BlockReadDisk->SgMap.SgCount = 1; + + if( BlockReadDisk->ByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + //------------------------------------------------------------------------- + // Build Scatter/Gather list + // + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int segment; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + byte_count = 0; + for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) + { + BlockReadDisk->SgMap.SgEntry[segment].SgAddress = + ( void * )virt_to_bus(scatterlist_ptr[segment].address ); + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount = + scatterlist_ptr[segment].length; + +#ifdef DEBUG_SGBUFFER + memset( scatterlist_ptr[segment].address, 0xa5, + scatterlist_ptr[segment].length ); +#endif + + byte_count += scatterlist_ptr[segment].length; + + if( BlockReadDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + /* + cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", + segment, + BlockReadDisk->SgMap.SgEntry[segment].SgAddress, + BlockReadDisk->SgMap.SgEntry[segment].SgByteCount); + */ + } + BlockReadDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg; + + if( BlockReadDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: READ request with SgCount > %d", + MAX_DRIVER_SG_SEGMENT_COUNT ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + goto err_return; + } + } + else // one piece of contiguous phys mem + { + BlockReadDisk->SgMap.SgEntry[0].SgAddress = + ( void * )virt_to_bus( scsi_cmnd_ptr->request_buffer ); + BlockReadDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen; + + byte_count = scsi_cmnd_ptr->request_bufflen; + + if( BlockReadDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: Single segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + } + + if( byte_count != BlockReadDisk->ByteCount ) + cmn_err( CE_WARN, "AacHba_DoScsiRead: byte_count != BlockReadDisk->ByteCount" ); + + //------------------------------------------------------------------------- + // Now send the Fib to the adapter + // + FibSize = sizeof( BLOCKREAD ) + ( ( BlockReadDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) ); + + if( wait ) + { + Status = adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL); + + BlockReadResponse = ( PBLOCKREADRESPONSE ) + adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockReadResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiRead: BlockReadCommand failed with status: %d", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_ReadCallback, + ( void *)scsi_cmnd_ptr ); + // don't call done func here + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DoScsiWrite() + + Handles SCSI WRITE requests + + Preconditions: + Postconditions: + Returns 0 on success, -1 on failure + *----------------------------------------------------------------------------*/ +int AacHba_DoScsiWrite(Scsi_Cmnd *scsi_cmnd_ptr, int ContainerId, int wait ) +{ + u_long lba; + u_long count; + u_long byte_count; + int Status; + + PBLOCKWRITE BlockWriteDisk; + PBLOCKWRITERESPONSE BlockWriteResponse; + uint16_t FibSize; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *adapter; + PFIB_CONTEXT cmd_fibcontext; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + // Get block address and transfer length + if ( scsi_cmnd_ptr->cmnd[0] == SS_WRITE ) // 6 byte command + { + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + count = scsi_cmnd_ptr->cmnd[4]; + + + if ( count == 0 ) + count = 256; + } + else + { + cmn_err( CE_DEBUG, "aachba: received a write(10) command on target %d", ContainerId ); + + lba = ( scsi_cmnd_ptr->cmnd[2] << 24 ) | ( scsi_cmnd_ptr->cmnd[3] << 16 ) | + ( scsi_cmnd_ptr->cmnd[4] << 8 ) | scsi_cmnd_ptr->cmnd[5]; + + count = ( scsi_cmnd_ptr->cmnd[7] << 8 ) | scsi_cmnd_ptr->cmnd[8]; + } + cmn_err( CE_DEBUG, "AacHba_DoScsiWrite[cpu %d]: lba = %lu, t = %ld", smp_processor_id(), lba, jiffies ); + + //------------------------------------------------------------------------- + // Alocate and initialize a Fib + // Setup BlockWrite command + if( !( cmd_fibcontext = adapter->CommFuncs.AllocateFib( adapter ) ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: AllocateFib failed\n" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + + adapter->CommFuncs.InitializeFib( cmd_fibcontext ); + + BlockWriteDisk = (PBLOCKWRITE) adapter->CommFuncs.GetFibData( cmd_fibcontext ); + BlockWriteDisk->Command = VM_CtBlockWrite; + BlockWriteDisk->ContainerId = ContainerId; + BlockWriteDisk->BlockNumber = lba; + BlockWriteDisk->ByteCount = count * 512; + BlockWriteDisk->SgMap.SgCount = 1; + + if ( BlockWriteDisk->ByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + //------------------------------------------------------------------------- + // Build Scatter/Gather list + // + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int segment; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + byte_count = 0; + for( segment = 0; segment< scsi_cmnd_ptr->use_sg; segment++ ) + { + BlockWriteDisk->SgMap.SgEntry[segment].SgAddress = + ( HOSTADDRESS )virt_to_bus( scatterlist_ptr[segment].address ); + BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount = + scatterlist_ptr[segment].length; + + byte_count += scatterlist_ptr[segment].length; + + if ( BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: Segment byte count is larger than 64K" ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + + /* + cmn_err(CE_DEBUG, "SgEntry[%d].SgAddress = 0x%x, Byte count = 0x%x", + segment, + BlockWriteDisk->SgMap.SgEntry[segment].SgAddress, + BlockWriteDisk->SgMap.SgEntry[segment].SgByteCount); + */ + } + BlockWriteDisk->SgMap.SgCount = scsi_cmnd_ptr->use_sg; + + if( BlockWriteDisk->SgMap.SgCount > MAX_DRIVER_SG_SEGMENT_COUNT ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: WRITE request with SgCount > %d", + MAX_DRIVER_SG_SEGMENT_COUNT ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + goto err_return; + } + } + else // one piece of contiguous phys mem + { + BlockWriteDisk->SgMap.SgEntry[0].SgAddress = + ( HOSTADDRESS )virt_to_bus( scsi_cmnd_ptr->request_buffer ); + BlockWriteDisk->SgMap.SgEntry[0].SgByteCount = scsi_cmnd_ptr->request_bufflen; + + byte_count = scsi_cmnd_ptr->request_bufflen; + + if ( BlockWriteDisk->SgMap.SgEntry[0].SgByteCount > ( 64 * 1024 ) ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: Single segment byte count is larger than 64K" ); + + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_ILLEGAL, SENCODE_INVALID_CDB_FIELD, ASENCODE_INVALID_CDB_FIELD, + 0, 0, 7, 0 ); + + goto err_return; + } + } + + if( byte_count != BlockWriteDisk->ByteCount ) + cmn_err( CE_WARN, "AacHba_DoScsiWrite: byte_count != BlockReadDisk->ByteCount" ); + + //------------------------------------------------------------------------- + // Now send the Fib to the adapter + // + FibSize = sizeof( BLOCKWRITE ) + ( ( BlockWriteDisk->SgMap.SgCount - 1 ) * sizeof( SGENTRY ) ); + + if( wait ) + { + Status = adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL ); + + BlockWriteResponse = ( PBLOCKWRITERESPONSE ) + adapter->CommFuncs.GetFibData( cmd_fibcontext ); + + adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + if( BlockWriteResponse->Status != ST_OK ) + { + cmn_err( CE_WARN, "AacHba_DoScsiWrite: BlockWriteCommand failed with status: %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION;; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( -1 ); + } + else + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + return ( 0 ); + } + else + { + Status = adapter->CommFuncs.SendFib( ContainerCommand, + cmd_fibcontext, + FibSize, + FsaNormal, + FALSE, + NULL, + TRUE, + ( PFIB_CALLBACK )AacHba_WriteCallback, + ( void * )scsi_cmnd_ptr ); + + // don't call done func here - it should be called by the WriteCallback + return ( 0 ); + } + +err_return: + AacHba_CompleteScsiNoLock( scsi_cmnd_ptr ); + + adapter->CommFuncs.CompleteFib( cmd_fibcontext ); + adapter->CommFuncs.FreeFib( cmd_fibcontext ); + + return ( -1 ); +} + + +/*------------------------------------------------------------------------------ + AacHba_ReadCallback() + *----------------------------------------------------------------------------*/ +void AacHba_ReadCallback(void *context, PFIB_CONTEXT FibContext, int FibStatus ) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *adapter; + BLOCKREADRESPONSE *BlockReadResponse; + Scsi_Cmnd *scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_ReadCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_ReadCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockReadResponse = ( PBLOCKREADRESPONSE )adapter->CommFuncs.GetFibData( FibContext ); + + if ( BlockReadResponse->Status == ST_OK ) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_ReadCallback: read failed, status = %d\n", + BlockReadResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + +#ifdef DEBUG_SGBUFFER + if ( scsi_cmnd_ptr->use_sg ) // use scatter/gather list + { + struct scatterlist *scatterlist_ptr; + int i, segment, count; + char *ptr; + + scatterlist_ptr = ( struct scatterlist * )scsi_cmnd_ptr->request_buffer; + + for( segment = 0; segment < scsi_cmnd_ptr->use_sg; segment++ ) + { + count = 0; + ptr = scatterlist_ptr[segment].address; + for( i = 0; i < scatterlist_ptr[segment].length; i++ ) + { + if( *( ptr++ ) == 0xa5 ) + count++; + } + if( count == scatterlist_ptr[segment].length ) + cmn_err( CE_WARN, "AacHba_ReadCallback: segment %d not filled", segment ); + + } + } +#endif + + adapter->CommFuncs.CompleteFib( FibContext ); + adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + +/*------------------------------------------------------------------------------ + AacHba_WriteCallback() + *----------------------------------------------------------------------------*/ +void AacHba_WriteCallback(void *context, PFIB_CONTEXT FibContext, int FibStatus ) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *adapter; + BLOCKWRITERESPONSE *BlockWriteResponse; + Scsi_Cmnd *scsi_cmnd_ptr; + u_long lba; + int ContainerId; + + scsi_cmnd_ptr = ( Scsi_Cmnd * )context; + + CommonExtension = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + adapter = ( AFA_COMM_ADAPTER * )CommonExtension->Adapter; + + ContainerId = TARGET_LUN_TO_CONTAINER( scsi_cmnd_ptr->target, scsi_cmnd_ptr->lun ); + + lba = ( ( scsi_cmnd_ptr->cmnd[1] & 0x1F ) << 16 ) | + ( scsi_cmnd_ptr->cmnd[2] << 8 ) | + scsi_cmnd_ptr->cmnd[3]; + cmn_err( CE_DEBUG, "AacHba_WriteCallback[cpu %d]: lba = %ld, t = %ld", smp_processor_id(), lba, jiffies ); + if( FibContext == 0 ) + { + cmn_err( CE_WARN, "AacHba_WriteCallback: no fib context" ); + scsi_cmnd_ptr->result = DID_ERROR << 16; + AacHba_CompleteScsi( scsi_cmnd_ptr ); + return; + } + + BlockWriteResponse = (PBLOCKWRITERESPONSE) adapter->CommFuncs.GetFibData( FibContext ); + if (BlockWriteResponse->Status == ST_OK) + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | GOOD; + else + { + cmn_err( CE_WARN, "AacHba_WriteCallback: write failed, status = %d\n", + BlockWriteResponse->Status ); + scsi_cmnd_ptr->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | CHECK_CONDITION; + AacHba_SetSenseData( ( char * )&g_sense_data[ ContainerId ], + SENKEY_HW_ERR, SENCODE_INTERNAL_TARGET_FAILURE, ASENCODE_INTERNAL_TARGET_FAILURE, + 0, 0, 0, 0 ); + } + + adapter->CommFuncs.CompleteFib( FibContext ); + adapter->CommFuncs.FreeFib( FibContext ); + + AacHba_CompleteScsi( scsi_cmnd_ptr ); +} + + +/*------------------------------------------------------------------------------ + AacHba_Ioctl() + + Handle IOCTL requests + + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +int AacHba_Ioctl(PCI_MINIPORT_COMMON_EXTENSION *CommonExtension, int cmd, void * arg ) +/*----------------------------------------------------------------------------*/ +{ + Sa_ADAPTER_EXTENSION *AdapterExtension; + AFA_IOCTL_CMD IoctlCmd; + int status; + + AdapterExtension = ( Sa_ADAPTER_EXTENSION * )CommonExtension->MiniPort; + + cmn_err( CE_DEBUG, "AacHba_Ioctl, type = %d", cmd ); + switch( cmd ) + { + case FSACTL_SENDFIB: + cmn_err( CE_DEBUG, "FSACTL_SENDFIB" ); + break; + + case FSACTL_AIF_THREAD: + cmn_err( CE_DEBUG, "FSACTL_AIF_THREAD" ); + break; + + case FSACTL_NULL_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_NULL_IO_TEST" ); + break; + + case FSACTL_SIM_IO_TEST: + cmn_err( CE_DEBUG, "FSACTL_SIM_IO_TEST" ); + break; + + case FSACTL_GET_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_GET_FIBTIMES" ); + break; + + case FSACTL_ZERO_FIBTIMES: + cmn_err( CE_DEBUG, "FSACTL_ZERO_FIBTIMES"); + break; + + case FSACTL_GET_VAR: + cmn_err( CE_DEBUG, "FSACTL_GET_VAR" ); + break; + + case FSACTL_SET_VAR: + cmn_err( CE_DEBUG, "FSACTL_SET_VAR" ); + break; + + case FSACTL_OPEN_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_OPEN_ADAPTER_CONFIG" ); + break; + + case FSACTL_CLOSE_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_ADAPTER_CONFIG" ); + break; + + case FSACTL_QUERY_ADAPTER_CONFIG: + cmn_err( CE_DEBUG, "FSACTL_QUERY_ADAPTER_CONFIG" ); + break; + + case FSACTL_OPEN_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_OPEN_GET_ADAPTER_FIB" ); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_GET_NEXT_ADAPTER_FIB" ); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + cmn_err( CE_DEBUG, "FSACTL_CLOSE_GET_ADAPTER_FIB" ); + break; + + case FSACTL_MINIPORT_REV_CHECK: + cmn_err( CE_DEBUG, "FSACTL_MINIPORT_REV_CHECK" ); + break; + + case FSACTL_OPENCLS_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_OPENCLS_COMM_PERF_DATA" ); + break; + + case FSACTL_GET_COMM_PERF_DATA: + cmn_err( CE_DEBUG, "FSACTL_GET_COMM_PERF_DATA" ); + break; + + case FSACTL_QUERY_DISK: + cmn_err( CE_DEBUG, "FSACTL_QUERY_DISK" ); + break; + + case FSACTL_DELETE_DISK: + cmn_err( CE_DEBUG, "FSACTL_DELETE_DISK" ); + break; + + default: + cmn_err( CE_DEBUG, "Unknown ioctl: 0x%x", cmd ); + } + + IoctlCmd.cmd = cmd; + IoctlCmd.arg = ( intptr_t )arg; + IoctlCmd.flag = 0; + IoctlCmd.cred_p = 0; + IoctlCmd.rval_p = 0; + + status = AfaCommAdapterDeviceControl( CommonExtension->Adapter, &IoctlCmd ); + cmn_err( CE_DEBUG, "AAC_Ioctl, completion status = %d", status ); + return( status ); +} + + +/*------------------------------------------------------------------------------ + AacHba_AdapterDeviceControl() + + Preconditions: + Postconditions: + Returns TRUE if ioctl handled, FALSE otherwise + *ReturnStatus set to completion status + *----------------------------------------------------------------------------*/ +int AacHba_AdapterDeviceControl (void * adapter, PAFA_IOCTL_CMD IoctlCmdPtr, int *ret) +{ + int handled = TRUE; // start out handling it. + int status = EFAULT; + + switch( IoctlCmdPtr->cmd ) + { + case FSACTL_QUERY_DISK: + status = AacHba_QueryDisk( adapter, IoctlCmdPtr ); + break; + + case FSACTL_DELETE_DISK: + status = AacHba_DeleteDisk( adapter, IoctlCmdPtr ); + break; + + case FSACTL_FORCE_DELETE_DISK: + status = AacHba_ForceDeleteDisk( adapter, IoctlCmdPtr ); + break; + + case 2131: + if( AacHba_ProbeContainers( ( PCI_MINIPORT_COMMON_EXTENSION * )adapter ) ) + status = -EFAULT; + break; + + default: + handled = FALSE; + break; + } + + *ret = status; + + return( handled ); +} + + +/*------------------------------------------------------------------------------ + AacHba_QueryDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ + +int AacHba_QueryDisk(void * adapter, PAFA_IOCTL_CMD IoctlCmdPtr ) +{ + UNIX_QUERY_DISK QueryDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if( copyin( IoctlCmdPtr->arg, &QueryDisk, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + if (QueryDisk.ContainerNumber == -1) + QueryDisk.ContainerNumber = TARGET_LUN_TO_CONTAINER( QueryDisk.Target, QueryDisk.Lun ); + else + if( ( QueryDisk.Bus == -1 ) && ( QueryDisk.Target == -1 ) && ( QueryDisk.Lun == -1 ) ) + { + if( QueryDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + QueryDisk.Instance = CommonExtensionPtr->OsDep.scsi_host_ptr->host_no; + QueryDisk.Bus = 0; + QueryDisk.Target = CONTAINER_TO_TARGET( QueryDisk.ContainerNumber ); + QueryDisk.Lun = CONTAINER_TO_LUN( QueryDisk.ContainerNumber ); + } + else + return( -EINVAL ); + + QueryDisk.Valid = fsa_dev_ptr->ContainerValid[QueryDisk.ContainerNumber]; + QueryDisk.Locked = fsa_dev_ptr->ContainerLocked[QueryDisk.ContainerNumber]; + QueryDisk.Deleted = fsa_dev_ptr->ContainerDeleted[QueryDisk.ContainerNumber]; + + if( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber] == -1 ) + QueryDisk.UnMapped = TRUE; + else + QueryDisk.UnMapped = FALSE; + + get_sd_devname( fsa_dev_ptr->ContainerDevNo[QueryDisk.ContainerNumber], + QueryDisk.diskDeviceName ); + + if( copyout( &QueryDisk, IoctlCmdPtr->arg, sizeof( UNIX_QUERY_DISK ) ) ) + return( -EFAULT ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + get_sd_devname() + *----------------------------------------------------------------------------*/ + +static void get_sd_devname(long disknum, char * buffer) +{ + if( disknum < 0 ) + { + sprintf(buffer, "%s", ""); + return; + } + + if( disknum < 26 ) + sprintf(buffer, "sd%c", 'a' + disknum); + else { + unsigned int min1; + unsigned int min2; + /* + * For larger numbers of disks, we need to go to a new + * naming scheme. + */ + min1 = disknum / 26; + min2 = disknum % 26; + sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2); + } +} + + +/*------------------------------------------------------------------------------ + AacHba_ForceDeleteDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + *----------------------------------------------------------------------------*/ +int AacHba_ForceDeleteDisk(void * adapter, // CommonExtensionPtr + PAFA_IOCTL_CMD IoctlCmdPtr ) +{ + DELETE_DISK DeleteDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if ( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) + return( -EFAULT ); + + if ( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + // Mark this container as being deleted. + fsa_dev_ptr->ContainerDeleted[DeleteDisk.ContainerNumber] = TRUE; + + return( 0 ); +} + +/* + * #REVIEW# + * 1- Why ContainerValid = 0 down below and ContainerDeleted = TRUE above ??? + */ + +/*------------------------------------------------------------------------------ + AacHba_DeleteDisk() + + Postconditions: + Return values + 0 = OK + -EFAULT = Bad address + -EINVAL = Bad container number + -EBUSY = Device locked + *----------------------------------------------------------------------------*/ + +int AacHba_DeleteDisk(void * adapter,PAFA_IOCTL_CMD IoctlCmdPtr) +{ + DELETE_DISK DeleteDisk; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + fsadev_t *fsa_dev_ptr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )adapter; + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + + if( copyin( IoctlCmdPtr->arg, &DeleteDisk, sizeof( DELETE_DISK ) ) ) + return( -EFAULT ); + + if( DeleteDisk.ContainerNumber > MAXIMUM_NUM_CONTAINERS ) + return( -EINVAL ); + + // If the container is locked, it can not be deleted by the API. + if( fsa_dev_ptr->ContainerLocked[DeleteDisk.ContainerNumber] ) + return( -EBUSY ); + else + { + // Mark the container as no longer being valid. + fsa_dev_ptr->ContainerValid[DeleteDisk.ContainerNumber] = 0; + fsa_dev_ptr->ContainerDevNo[DeleteDisk.ContainerNumber] = -1; + return(0); + } +} + + +/*------------------------------------------------------------------------------ + AacHba_OpenAdapter() + *----------------------------------------------------------------------------*/ + +AAC_STATUS AacHba_OpenAdapter(void * adapter) +{ + return( STATUS_SUCCESS ); +} + + +/*------------------------------------------------------------------------------ + AacHba_CloseAdapter() + *----------------------------------------------------------------------------*/ + +AAC_STATUS AacHba_CloseAdapter(void * adapter ) +{ + return( STATUS_SUCCESS ); +} + + +/*------------------------------------------------------------------------------ + AacHba_DetachAdapter() + *----------------------------------------------------------------------------*/ + +void AacHba_DetachAdapter(void * adapter ) +{ + AacCommDetachAdapter( adapter ); +} + + +/*------------------------------------------------------------------------------ + AacHba_AbortScsiCommand() + *----------------------------------------------------------------------------*/ +void AacHba_AbortScsiCommand(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + u16 interrupt_status; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + interrupt_status = Sa_READ_USHORT( ( PSa_ADAPTER_EXTENSION )( CommonExtensionPtr->MiniPort ), + DoorbellReg_p ); + cmn_err( CE_WARN, "interrupt_status = %d", interrupt_status ); + + if( interrupt_status & DOORBELL_1) { // Adapter -> Host Normal Command Ready + cmn_err( CE_WARN, "DOORBELL_1: Adapter -> Host Normal Command Ready" ); + } + + if( interrupt_status & DOORBELL_2) { // Adapter -> Host Normal Response Ready + cmn_err( CE_WARN, "DOORBELL_2: Adapter -> Host Normal Response Ready" ); + } + + if ( interrupt_status & DOORBELL_3) { // Adapter -> Host Normal Command Not Full + cmn_err( CE_WARN, "DOORBELL_3: Adapter -> Host Normal Command Not Full" ); + } + + if ( interrupt_status & DOORBELL_4) { // Adapter -> Host Normal Response Not Full + cmn_err( CE_WARN, "DOORBELL_4: Adapter -> Host Normal Response Not Full" ); + } + +} + + +/*------------------------------------------------------------------------------ + AacHba_HandleAif() + *----------------------------------------------------------------------------*/ + +int AacHba_HandleAif(void * adapter,PFIB_CONTEXT FibContext ) +{ + return( FALSE ); +} + + +/*------------------------------------------------------------------------------ + AacHba_SetSenseData() + Fill in the sense data. + Preconditions: + Postconditions: + *----------------------------------------------------------------------------*/ +void AacHba_SetSenseData( + char * sense_buf, + u8 sense_key, + u8 sense_code, + u8 a_sense_code, + u8 incorrect_length, + u8 bit_pointer, + unsigned field_pointer, + unsigned long residue ) +{ + sense_buf[0] = 0xF0; // Sense data valid, err code 70h (current error) + sense_buf[1] = 0; // Segment number, always zero + + if( incorrect_length ) + { + sense_buf[2] = sense_key | 0x20; // Set the ILI bit | sense key + sense_buf[3] = BYTE3(residue); + sense_buf[4] = BYTE2(residue); + sense_buf[5] = BYTE1(residue); + sense_buf[6] = BYTE0(residue); + } + else + sense_buf[2] = sense_key; // Sense key + + if( sense_key == SENKEY_ILLEGAL ) + sense_buf[7] = 10; // Additional sense length + else + sense_buf[7] = 6; // Additional sense length + + sense_buf[12] = sense_code; // Additional sense code + sense_buf[13] = a_sense_code; // Additional sense code qualifier + if( sense_key == SENKEY_ILLEGAL ) + { + sense_buf[15] = 0; + + if( sense_code == SENCODE_INVALID_PARAM_FIELD ) + sense_buf[15] = 0x80; // Std sense key specific field + // Illegal parameter is in the parameter block + + if( sense_code == SENCODE_INVALID_CDB_FIELD ) + sense_buf[15] = 0xc0; // Std sense key specific field + // Illegal parameter is in the CDB block + sense_buf[15] |= bit_pointer; + sense_buf[16] = field_pointer >> 8; // MSB + sense_buf[17] = field_pointer; // LSB + } +} + diff --git a/drivers/scsi/aacraid/aacid.c b/drivers/scsi/aacraid/aacid.c new file mode 100644 index 000000000000..13d6ad02404f --- /dev/null +++ b/drivers/scsi/aacraid/aacid.c @@ -0,0 +1,130 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * aac.c + * + * Abstract: Data structures for controller specific info. + * +--*/ + +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsaport.h" +#include "pcisup.h" + +#include "version.h" + + +/* Function Prototypes */ +void InqStrCopy(char *a, char *b); /* ossup.c */ + +/* Device name used to register and unregister + the device in linit.c */ +char devicestr[]="aac"; + +char *container_types[] = { + "None", + "Volume", + "Mirror", + "Stripe", + "RAID5", + "SSRW", + "SSRO", + "Morph", + "Legacy", + "RAID4", + "RAID10", + "RAID00", + "V-MIRRORS", + "PSEUDO R4", + "Unknown" +}; + +/* Local Structure to set SCSI inquiry data strings */ +typedef struct _INQSTR { + char vid[8]; /* Vendor ID */ + char pid[16]; /* Product ID */ + char prl[4]; /* Product Revision Level */ +} INQSTR, *INQSTRP; + +FSA_MINIPORT MiniPorts[]; + +/* Function: SetInqDataStr + * + * Arguments: [1] pointer to void [1] int + * + * Purpose: Sets SCSI inquiry data strings for vendor, product + * and revision level. Allows strings to be set in platform dependant + * files instead of in OS dependant driver source. + */ + +void SetInqDataStr (int MiniPortIndex, void *dataPtr, int tindex) +{ + INQSTRP InqStrPtr; + char *findit; + FSA_MINIPORT *mp; + + mp = &MiniPorts[MiniPortIndex]; + + InqStrPtr = (INQSTRP)(dataPtr); /* cast dataPtr to type INQSTRP */ + + InqStrCopy (mp->Vendor, InqStrPtr->vid); + InqStrCopy (mp->Model, InqStrPtr->pid); /* last six chars reserved for vol type */ + + findit = InqStrPtr->pid; + + for ( ; *findit != ' '; findit++); /* walk till we find a space then incr by 1 */ + findit++; + + if (tindex < (sizeof(container_types)/sizeof(char *))) + InqStrCopy (container_types[tindex], findit); + + InqStrCopy ("0001", InqStrPtr->prl); +} + +int SaInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot); +int RxInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot); + +/* + * Because of the way Linux names scsi devices, the order in this table has + * become important. Check for on-board Raid first, add-in cards second. + */ + +FSA_MINIPORT MiniPorts[] = +{ + { 0x1028, 0x0001, 0x1028, 0x0001, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 2400 + { 0x1028, 0x0002, 0x1028, 0x0002, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 4400 + { 0x1028, 0x0003, 0x1028, 0x0003, "afa", RxInitDevice, "percraid", "DELL ", "PERCRAID " }, // PowerEdge 2450 + { 0x1011, 0x0046, 0x9005, 0x1364, "afa", SaInitDevice, "percraid", "DELL ", "PERCRAID " }, // Dell PERC2 "Quad Channel" + { 0x1011, 0x0046, 0x103c, 0x10c2, "hpn", SaInitDevice, "hpnraid", "HP ", "NetRAID-4M " } // HP NetRAID-4M +}; + + +#define NUM_MINIPORTS (sizeof(MiniPorts) / sizeof(FSA_MINIPORT)) + +int NumMiniPorts = NUM_MINIPORTS; + +char DescriptionString[] = "AACxxx Raid Controller" FSA_VERSION_STRING ; diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c new file mode 100644 index 000000000000..6f5877d86302 --- /dev/null +++ b/drivers/scsi/aacraid/commctrl.c @@ -0,0 +1,795 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commctrl.c + * + * Abstract: Contains all routines for control of the AFA comm layer + * +--*/ + +#include "comprocs.h" +#include "osheaders.h" +#include "ostypes.h" + +#include + +/*++ + +Routine Description: + This routine validates the revision of the caller with the current revision + of the filesystem. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + IrpContext - Supplies the IrpContext. + +Return Value: + AAC_STATUS + +--*/ + +AAC_STATUS FsaCtlCheckRevision(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + RevCheck APIRevCheck; + RevCheckResp APIRevCheckResp; + RevComponent APICallingComponent; + u32 APIBuildNumber; + + if (COPYIN((caddr_t) IoctlCmdPtr->arg, (caddr_t) & APIRevCheck, sizeof(RevCheck), IoctlCmdPtr->flag)) { + return EFAULT; + } + + APICallingComponent = APIRevCheck.callingComponent; + APIBuildNumber = APIRevCheck.callingRevision.buildNumber; + APIRevCheckResp.possiblyCompatible = RevCheckCompatibility(RevMiniportDriver, APICallingComponent, APIBuildNumber); + APIRevCheckResp.adapterSWRevision.external.ul = RevGetExternalRev(); + APIRevCheckResp.adapterSWRevision.buildNumber = RevGetBuildNumber(); + + if (COPYOUT((caddr_t) & APIRevCheckResp, (caddr_t) IoctlCmdPtr->arg, sizeof(RevCheckResp), IoctlCmdPtr->flag)) { + return EFAULT; + } + return 0; +} + + +int AfaCommAdapterDeviceControl(void *arg, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + PAFA_COMM_ADAPTER adapter = (PAFA_COMM_ADAPTER) arg; + int status = ENOTTY; + PAFA_CLASS_DRIVER dev; + + // + // First loop through all of the class drivers to give them a chance to handle + // the Device control first. + // + + dev = adapter->ClassDriverList; + + while (dev) { + if (dev->DeviceControl) { + if (dev->DeviceControl(dev->ClassDriverExtension, IoctlCmdPtr, &status)) { + return (status); + } + } + dev = dev->Next; + } + + switch (IoctlCmdPtr->cmd) { + case FSACTL_SENDFIB: + status = AfaCommCtlSendFib(adapter, IoctlCmdPtr); + break; + + case FSACTL_AIF_THREAD: + status = AfaCommCtlAifThread(adapter, IoctlCmdPtr); + break; + + case FSACTL_OPEN_GET_ADAPTER_FIB: + status = FsaCtlOpenGetAdapterFib(adapter, IoctlCmdPtr); + break; + + case FSACTL_GET_NEXT_ADAPTER_FIB: + status = FsaCtlGetNextAdapterFib(adapter, IoctlCmdPtr); + break; + + case FSACTL_CLOSE_GET_ADAPTER_FIB: + status = FsaCtlCloseGetAdapterFib(adapter, IoctlCmdPtr); + break; + + case FSACTL_MINIPORT_REV_CHECK: + status = FsaCtlCheckRevision(adapter, IoctlCmdPtr); + break; + + default: + status = ENOTTY; + break; + } + return status; +} + +/*++ + +Routine Description: + This routine registers a new class driver for the comm layer. + It will return a pointer to the communication functions for the class driver + to use. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_SUCCESS - Everything OK. + +--*/ + +AAC_STATUS AfaCommRegisterNewClassDriver(PAFA_COMM_ADAPTER adapter, + PAFA_NEW_CLASS_DRIVER NewClassDriver, PAFA_NEW_CLASS_DRIVER_RESPONSE NewClassDriverResponse) +{ + AAC_STATUS status; + PAFA_CLASS_DRIVER dev; + + dev = (PAFA_CLASS_DRIVER)kmalloc(sizeof(AFA_CLASS_DRIVER), GFP_KERNEL); + + if (dev == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + return status; + } + // + // If the class driver has sent in user Vars, then copy them into the global + // area. + // + + if (NewClassDriver->NumUserVars) { + PFSA_USER_VAR NewUserVars; + NewUserVars = kmalloc((FsaCommData.NumUserVars + + NewClassDriver->NumUserVars) * sizeof(FSA_USER_VAR), GFP_KERNEL); + + // + // First copy the existing into the new area. + // + + RtlCopyMemory(NewUserVars, FsaCommData.UserVars, FsaCommData.NumUserVars * sizeof(FSA_USER_VAR)); + + // + // Next copy the new vars passed in from class driver. + // + + RtlCopyMemory((NewUserVars + FsaCommData.NumUserVars), + NewClassDriver->UserVars, NewClassDriver->NumUserVars * sizeof(FSA_USER_VAR)); + + // + // Free up the old user vars. + // + + kfree(FsaCommData.UserVars); + + // + // Point the global to the new area. + // + + FsaCommData.UserVars = NewUserVars; + + // + // Update the total count. + // + + FsaCommData.NumUserVars += NewClassDriver->NumUserVars; + } + + dev->OpenAdapter = NewClassDriver->OpenAdapter; + dev->CloseAdapter = NewClassDriver->CloseAdapter; + dev->DeviceControl = NewClassDriver->DeviceControl; + dev->HandleAif = NewClassDriver->HandleAif; + dev->ClassDriverExtension = NewClassDriver->ClassDriverExtension; + + dev->Next = adapter->ClassDriverList; + adapter->ClassDriverList = dev; + + // + // Now return the information needed by the class driver to communicate to us. + // + + NewClassDriverResponse->CommFuncs = &adapter->CommFuncs; + NewClassDriverResponse->CommPortExtension = adapter; + NewClassDriverResponse->MiniPortExtension = adapter->AdapterExtension; + NewClassDriverResponse->SpinLockCookie = adapter->SpinLockCookie; + NewClassDriverResponse->Dip = adapter->Dip; + + return (STATUS_SUCCESS); +} + +/*++ + +Routine Description: + This routine sends a fib to the adapter on behalf of a user level + program. + +Arguments: + adapter - Supplies which adapter is being processed. + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + STATUS_SUCCESS - Everything OK. + +--*/ + +int AfaCommCtlSendFib(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + PFIB KFib; + PCOMM_FIB_CONTEXT fc; + PSGMAP_CONTEXT SgMapContext; + SGMAP_CONTEXT _SgMapContext; + QUEUE_TYPES WhichQueue; + void *UsersAddress; + AAC_STATUS status; + + fc = AllocateFib(adapter); + + KFib = fc->Fib; + + // + // First copy in the header so that we can check the size field. + // + + if (COPYIN((caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, sizeof(FIB_HEADER), IoctlCmdPtr->flag)) { + FreeFib(fc); + status = EFAULT; + return (status); + } + // + // Since we copy based on the fib header size, make sure that we + // will not overrun the buffer when we copy the memory. Return + // an error if we would. + // + + if (KFib->Header.Size > sizeof(FIB) - sizeof(FIB_HEADER)) { + FreeFib(fc); + status = EINVAL; + return status; + } + + if (COPYIN((caddr_t) IoctlCmdPtr->arg, (caddr_t) KFib, KFib->Header.Size + sizeof(FIB_HEADER), IoctlCmdPtr->flag)) { + FreeFib(fc); + status = EFAULT; + return (status); + } + + WhichQueue = AdapNormCmdQueue; + + if (KFib->Header.Command == TakeABreakPt) { + InterruptAdapter(adapter); + // + // Since we didn't really send a fib, zero out the state to allow + // cleanup code not to assert. + // + KFib->Header.XferState = 0; + } else { + if (SendFib(KFib->Header.Command, fc, KFib->Header.Size, + FsaNormal, TRUE, NULL, TRUE, NULL, NULL) != FSA_SUCCESS) { + FsaCommPrint("User SendFib failed!.\n"); + FreeFib(fc); + return (ENXIO); + } + if (CompleteFib(fc) != FSA_SUCCESS) { + FsaCommPrint("User Complete FIB failed.\n"); + FreeFib(fc); + return (ENXIO); + } + } + // + // Make sure that the size returned by the adapter (which includes + // the header) is less than or equal to the size of a fib, so we + // don't corrupt application data. Then copy that size to the user + // buffer. (Don't try to add the header information again, since it + // was already included by the adapter.) + // + ASSERT(KFib->Header.Size <= sizeof(FIB)); + if (COPYOUT((caddr_t) KFib, (caddr_t) IoctlCmdPtr->arg, KFib->Header.Size, IoctlCmdPtr->flag)) { + FreeFib(fc); + status = EFAULT; + return (status); + } + FreeFib(fc); + return (0); +} + +/*++ + +Routine Description: + This routine will act as the AIF thread for this adapter. + +Arguments: + adapter - Supplies which adapter is being processed. + IoctlCmdPtr - Pointer to the arguments to the IOCTL call + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + STATUS_SUCCESS - Everything OK. + +--*/ + +int AfaCommCtlAifThread(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + return (NormCommandThread(adapter)); +} + + + +#ifdef GATHER_FIB_TIMES +/*++ + +Routine Description: + This routine returns the gathered fibtimes to the user. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + STATUS_SUCCESS - Everything OK. + +--*/ + +AAC_STATUS AfaCommGetFibTimes(PAFA_COMM_ADAPTER adapter, PIRP Irp) +{ + PALL_FIB_TIMES AllFibTimes; + PLARGE_INTEGER FreqPtr; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + FreqPtr = (PLARGE_INTEGER) IrpSp->Parameters.FileSystemControl.Type3InputBuffer; + *FreqPtr = adapter->FibTimesFrequency; + AllFibTimes = (PALL_FIB_TIMES) ((PUCHAR) FreqPtr + sizeof(LARGE_INTEGER)); + RtlCopyMemory(AllFibTimes, adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + Irp->IoStatus.Information = 0; + return (STATUS_SUCCESS); + +} + +/*++ + +Routine Description: + This routine zero's the FibTimes structure within the adapter structure. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + STATUS_SUCCESS - Everything OK. +--*/ + +AAC_STATUS AfaCommZeroFibTimes(PAFA_COMM_ADAPTER adapter, PIRP Irp) +{ + PFIB_TIMES FibTimesPtr; + int i; + PIO_STACK_LOCATION IrpSp; + + // + // Get a pointer to the current Irp stack location + // + + IrpSp = IoGetCurrentIrpStackLocation(Irp); + + // + // Initialize the Fib timing data structures + // + RtlZeroMemory(adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + for (i = 0; i < MAX_FSACOMMAND_NUM; i++) { + FibTimesPtr = &adapter->FibTimes->FileSys[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + FibTimesPtr = &adapter->FibTimes->Read[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + FibTimesPtr = &adapter->FibTimes->Write[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + + FibTimesPtr = &adapter->FibTimes->Other; + + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + + Irp->IoStatus.Information = 0; + + return (STATUS_SUCCESS); +} +#endif // GATHER_FIB_TIMES + +#ifndef unix_aif + +/*++ + +Routine Description: + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_INSUFFICIENT_RESOURCES - If a memory allocation failed. + STATUS_SUCCESS - Everything OK. + +--*/ + +int FsaCtlOpenGetAdapterFib(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + PGET_ADAPTER_FIB_CONTEXT afc; + int status; + + // + // The context must be allocated from NonPagedPool because we need to use MmIsAddressValid. + // + + afc = kmalloc(sizeof(GET_ADAPTER_FIB_CONTEXT), GFP_KERNEL); + if (afc == NULL) { + status = ENOMEM; + } else { + afc->NodeTypeCode = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT; + afc->NodeByteSize = sizeof(GET_ADAPTER_FIB_CONTEXT); + + // + // Initialize the conditional variable use to wait for the next AIF. + // + + OsCv_init(&afc->UserEvent); + + // + // Set WaitingForFib to FALSE to indicate we are not in a WaitForSingleObject + // + + afc->WaitingForFib = FALSE; + + // + // Initialize the FibList and set the count of fibs on the list to 0. + // + + afc->FibCount = 0; + InitializeListHead(&afc->FibList); + + // + // Now add this context onto the adapter's AdapterFibContext list. + // + + OsCvLockAcquire(adapter->AdapterFibMutex); + InsertTailList(&adapter->AdapterFibContextList, &afc->NextContext); + OsCvLockRelease(adapter->AdapterFibMutex); + + if (COPYOUT(&afc, (caddr_t) IoctlCmdPtr->arg, sizeof(PGET_ADAPTER_FIB_CONTEXT), IoctlCmdPtr->flag)) { + status = EFAULT; + } else { + status = 0; + } + } + return (status); +} + +/*++ + +Routine Description: + This routine will get the next Fib, if available, from the AdapterFibContext + passed in from the user. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_NO_MORE_ENTRIES - There are no more Fibs for this AdapterFibContext. + STATUS_SUCCESS - Everything OK. + +--*/ + +int FsaCtlGetNextAdapterFib(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + GET_ADAPTER_FIB_IOCTL AdapterFibIoctl; + PGET_ADAPTER_FIB_CONTEXT afc; + PFIB Fib; + int status; + + if (COPYIN((caddr_t) IoctlCmdPtr->arg, (caddr_t) & AdapterFibIoctl, sizeof(GET_ADAPTER_FIB_IOCTL), IoctlCmdPtr->flag)) { + return (EFAULT); + } + // + // Extract the AdapterFibContext from the Input parameters. + // + + afc = (PGET_ADAPTER_FIB_CONTEXT) AdapterFibIoctl.AdapterFibContext; + + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // rpbfix : determine if there is a way to validate the AdapterFibContext address. + // + + if ((afc->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) + || (afc->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT))) { + return (EINVAL); + + } + + status = STATUS_SUCCESS; + OsCvLockAcquire(adapter->AdapterFibMutex); + // + // If there are no fibs to send back, then either wait or return EAGAIN + // +return_fib: + + if (!IsListEmpty(&afc->FibList)) { + PLIST_ENTRY entry; + // + // Pull the next fib from the FibList + // + entry = RemoveHeadList(&afc->FibList); + Fib = CONTAINING_RECORD(entry, FIB, Header.FibLinks); + afc->FibCount--; + if (COPYOUT(Fib, AdapterFibIoctl.AifFib, sizeof(FIB), IoctlCmdPtr->flag)) { + OsCvLockRelease(adapter->AdapterFibMutex); + kfree(Fib); + return (EFAULT); + + } + // + // Free the space occupied by this copy of the fib. + // + + kfree(Fib); + status = 0; + } else { + if (AdapterFibIoctl.Wait) { + if (OsCv_wait_sig(&afc->UserEvent, adapter->AdapterFibMutex) == 0) { + status = EINTR; + } else { + goto return_fib; + } + } else { + status = EAGAIN; + } + } + OsCvLockRelease(adapter->AdapterFibMutex); + return (status); +} + +/*++ + +Routine Description: + This routine will close down the AdapterFibContext passed in from the user. + +Arguments: + adapter - Supplies which adapter is being processed. + Irp - Supplies the Irp being processed. + +Return Value: + STATUS_INVALID_PARAMETER - If the AdapterFibContext was not a valid pointer. + STATUS_SUCCESS - Everything OK. + +--*/ + +int FsaCtlCloseGetAdapterFib(PAFA_COMM_ADAPTER adapter, PAFA_IOCTL_CMD IoctlCmdPtr) +{ + PGET_ADAPTER_FIB_CONTEXT afc; + AAC_STATUS status; + + // + // Extract the AdapterFibContext from the Input parameters + // + + afc = (PGET_ADAPTER_FIB_CONTEXT) IoctlCmdPtr->arg; + + if (afc == 0) { + cmn_err(CE_WARN, "FsaCtlCloseGetAdapterFib: AdapterFibContext is NULL"); + return (EINVAL); + } + // + // Verify that the HANDLE passed in was a valid AdapterFibContext + // + // rpbfix : verify pointer sent in from user. + // + + if ((afc->NodeTypeCode != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) + || (afc->NodeByteSize != sizeof(GET_ADAPTER_FIB_CONTEXT))) { + return (EINVAL); + } + + OsCvLockAcquire(adapter->AdapterFibMutex); + status = FsaCloseAdapterFibContext(adapter, afc); + OsCvLockRelease(adapter->AdapterFibMutex); + + return (status); +} + +int FsaCloseAdapterFibContext(PAFA_COMM_ADAPTER adapter, PGET_ADAPTER_FIB_CONTEXT afc) +{ + int status; + PFIB Fib; + + // + // First free any FIBs that have not been consumed yet. + // + + while (!IsListEmpty(&afc->FibList)) { + PLIST_ENTRY entry; + // + // Pull the next fib from the FibList + // + entry = RemoveHeadList(&afc->FibList); + Fib = CONTAINING_RECORD(entry, FIB, Header.FibLinks); + afc->FibCount--; + // + // Free the space occupied by this copy of the fib. + // + kfree(Fib); + } + // + // Remove the Context from the AdapterFibContext List + // + RemoveEntryList(&afc->NextContext); + OsCv_destroy(&afc->UserEvent); + // + // Invalidate context + // + afc->NodeTypeCode = 0; + // + // Free the space occupied by the Context + // + kfree(afc); + status = STATUS_SUCCESS; + return status; +} +#endif + +/*++ + +Routine Description: + The routine will get called by the miniport each time a user issues a CreateFile on the DeviceObject + for the adapter. + + The main purpose of this routine is to set up any data structures that may be needed + to handle any requests made on this DeviceObject. + +Arguments: + adapter - Pointer to which adapter miniport was opened. + +Return Value: + STATUS_SUCCESS + +--*/ + +AAC_STATUS AfaCommOpenAdapter(void *arg) +{ + PAFA_COMM_ADAPTER adapter = (PAFA_COMM_ADAPTER) arg; + AAC_STATUS status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER dev; + + dev = adapter->ClassDriverList; + + while (dev) { + if (dev->OpenAdapter) { + status = dev->OpenAdapter(dev->ClassDriverExtension); + if (status != STATUS_SUCCESS) + break; + } + dev = dev->Next; + } + return (status); +} + +/*++ + +Routine Description: + This routine will get called by the miniport each time a user issues a CloseHandle on the DeviceObject + for the adapter. + + The main purpose of this routine is to cleanup any data structures that have been set up + while this FileObject has been opened. + + This routine loops through all of the AdapterFibContext structures to determine if any need + to be deleted for this FileObject. + +Arguments: + adapter - Pointer to adapter miniport + Irp - Pointer to Irp that caused this close + +Return Value: + Status value returned from File system driver AdapterClose + +--*/ + +AAC_STATUS AfaCommCloseAdapter(void *arg) +{ + PAFA_COMM_ADAPTER adapter = (PAFA_COMM_ADAPTER) arg; + PLIST_ENTRY entry, next; + PGET_ADAPTER_FIB_CONTEXT afc; + AAC_STATUS status = STATUS_SUCCESS; + PAFA_CLASS_DRIVER dev; + + OsCvLockAcquire(adapter->AdapterFibMutex); + entry = adapter->AdapterFibContextList.Flink; + + // + // Loop through all of the AdapterFibContext, looking for any that + // were created with the FileObject that is being closed. + // + while (entry != &adapter->AdapterFibContextList) { + // + // Extract the AdapterFibContext + // + afc = CONTAINING_RECORD(entry, GET_ADAPTER_FIB_CONTEXT, NextContext); + // + // Save the next entry because CloseAdapterFibContext will delete the AdapterFibContext + // + next = entry->Flink; + entry = next; + } + +#ifdef unix_config_file + // + // If this FileObject had the adapter open for configuration, then release it. + // + if (adapter->AdapterConfigFileObject == IrpSp->FileObject) { + + adapter->AdapterConfigFileObject = NULL; + + } +#endif + + OsCvLockRelease(adapter->AdapterFibMutex); + dev = adapter->ClassDriverList; + while (dev) { + if (dev->CloseAdapter) { + status = dev->CloseAdapter(dev->ClassDriverExtension); + if (status != STATUS_SUCCESS) + break; + } + dev = dev->Next; + } + return status; +} diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c new file mode 100644 index 000000000000..fd3ed9c8d978 --- /dev/null +++ b/drivers/scsi/aacraid/comminit.c @@ -0,0 +1,1027 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comminit.c + * + * Abstract: This supports the initialization of the host adapter commuication interface. + * This is a platform dependent module for the pci cyclone board. + * + --*/ +#include "comprocs.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_COMMINIT) + +void AfaCommBugcheckHandler(void * buf,u32 len); +void ThrottlePeriodEndDpcRtn(PKDPC Dpc,void * DeferredContext, void * SystemArgument1, void * SystemArgument2); +FSA_COMM_DATA FsaCommData; + +AAC_STATUS HardInterruptModeration1Changed(void * AdapterContext, u32 nv) +{ + PAFA_COMM_ADAPTER adapter = AdapterContext; + // + // If we are using interrupt moderation, then disable the interrupt + // until we need to use it. + // + if (FsaCommData.HardInterruptModeration1) + DisableInterrupt( adapter, AdapNormCmdNotFull, FALSE ); + else + EnableInterrupt( adapter, AdapNormCmdNotFull, FALSE ); + return (STATUS_SUCCESS); +} + +AAC_STATUS FsaFibTimeoutChanged(void * AdapterContext, u32 nv) +{ + return (STATUS_SUCCESS); +} + +#ifdef GATHER_FIB_TIMES +extern int GatherFibTimes; +#endif + +FSA_USER_VAR FsaCommUserVars[] = { +#ifdef FIB_CHECKSUMS + { "do_fib_checksums", (u32 *)&FsaCommData.do_fib_checksums, NULL }, +#endif +#ifdef GATHER_FIB_TIMES + { "GatherFibTimes", (u32 *)&GatherFibTimes, NULL }, +#endif + { "EnableAdapterTimeouts", (u32 *)&FsaCommData.EnableAdapterTimeouts, NULL}, + { "EnableInterruptModeration", (u32 *)&FsaCommData.EnableInterruptModeration, NULL }, + { "FsaDataFibsSent", (u32 *) &FsaCommData.FibsSent, NULL }, + { "FsaDataFibRecved", (u32 *) &FsaCommData.FibRecved, NULL }, + { "HardInterruptModeration", (u32 *)&FsaCommData.HardInterruptModeration, NULL}, + { "HardInterruptModeration1", (u32 *)&FsaCommData.HardInterruptModeration1, HardInterruptModeration1Changed}, + { "EnableFibTimeoutBreak", (u32 *)&FsaCommData.EnableFibTimeoutBreak, NULL}, + { "PeakFibsConsumed", (u32 *)&FsaCommData.PeakFibsConsumed, NULL }, + { "ZeroFibsConsumed", (u32 *)&FsaCommData.ZeroFibsConsumed, NULL }, + { "FibTimeoutSeconds", (u32 *) &FsaCommData.FibTimeoutSeconds, FsaFibTimeoutChanged }, +}; + +#define NUM_COMM_USER_VARS (sizeof(FsaCommUserVars) / sizeof(FSA_USER_VAR) ) + + + +/*++ + +Routine Description: + This is the initialization routine for the FileArray Comm layer device driver. + +Arguments: + DriverObject - Pointer to driver object created by the system. + +Return Value: + AAC_STATUS - The function value is the final status from the initialization + operation. + +--*/ + +AAC_STATUS AacCommDriverEntry(void) +{ + AAC_STATUS status; + void * bugbuf; + RtlZeroMemory( &FsaCommData, sizeof(FSA_COMM_DATA) ); + + // + // Load the global timeout value for the adapter timeout + // Also init the global that enables or disables adapter timeouts + // + +// FsaCommData.AdapterTimeout = RtlConvertLongToLargeInteger(-10*1000*1000*180); + FsaCommData.FibTimeoutSeconds = 180; + FsaCommData.EnableAdapterTimeouts = TRUE; +// FsaCommData.QueueFreeTimeout = RtlConvertLongToLargeInteger(QUEUE_ENTRY_FREE_TIMEOUT); +#ifdef unix_fib_timeout + FsaCommData.FibTimeoutIncrement = (180 * 1000 * 1000 * 10) / KeQueryTimeIncrement(); +#endif + FsaCommData.EnableInterruptModeration = FALSE; + + // + // Preload UserVars with all variables from the comm layer. The class layers will + // include theirs when they register. + // + + FsaCommData.UserVars = kmalloc(NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR), GFP_KERNEL); + FsaCommData.NumUserVars = NUM_COMM_USER_VARS; + + RtlCopyMemory( FsaCommData.UserVars, &FsaCommUserVars, NUM_COMM_USER_VARS * sizeof(FSA_USER_VAR) ); + +#ifdef AACDISK + // + // Call the disk driver to initialize itself. + // + + AacDiskDriverEntry(); +#endif + return (STATUS_SUCCESS); +} + + +/*++ + +Routine Description: + This routine will release all of the resources used by a given queue. + +Arguments: + adapter - Which adapter the queue belongs to + Queue - Pointer to the queue itself + WhichQueue - Identifies which of the host queues this is. + +Return Value: + NONE. + +--*/ + +void DetachNTQueue(PAFA_COMM_ADAPTER adapter, PCOMM_QUE queue, QUEUE_TYPES which) +{ + switch (which) + { + case HostNormCmdQueue: + Os_remove_softintr( queue->ConsumerRoutine ); + OsSpinLockDestroy( queue->QueueLock ); + OsCv_destroy( &queue->CommandReady ); + break; + + case HostHighCmdQueue: + Os_remove_softintr( queue->ConsumerRoutine ); + OsSpinLockDestroy( queue->QueueLock ); + OsCv_destroy( &queue->CommandReady ); + break; + + case HostNormRespQueue: + Os_remove_softintr( queue->ConsumerRoutine ); + OsSpinLockDestroy( queue->QueueLock ); + break; + + case HostHighRespQueue: + Os_remove_softintr( queue->ConsumerRoutine ); + OsSpinLockDestroy( queue->QueueLock ); + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + OsCv_destroy( &queue->QueueFull ); + break; + } +} + +/*++ + +Routine Description: + Will initialize all entries in the queue that is NT specific. + +Arguments: + +Return Value: + Nothing there is nothing to allocate so nothing should fail + +--*/ + +void InitializeNTQueue(PAFA_COMM_ADAPTER adapter, PCOMM_QUE queue, QUEUE_TYPES which) +{ + queue->NumOutstandingIos = 0; + // + // Store a pointer to the adapter structure. + // + queue->Adapter = adapter; + InitializeListHead( &queue->OutstandingIoQueue ); + + switch (which) + { + case HostNormCmdQueue: + OsCv_init( &queue->CommandReady); + OsSpinLockInit( queue->QueueLock, adapter->SpinLockCookie); + if (ddi_add_softintr( adapter->Dip, DDI_SOFTINT_HIGH, &queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandNormDpc, + (caddr_t)queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + InitializeListHead(&queue->CommandQueue); + break; + + case HostHighCmdQueue: + OsCv_init( &queue->CommandReady); + OsSpinLockInit( queue->QueueLock, adapter->SpinLockCookie); + if (ddi_add_softintr( adapter->Dip, DDI_SOFTINT_HIGH, &queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostCommandHighDpc, + (caddr_t) queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + InitializeListHead(&queue->CommandQueue); + break; + + case HostNormRespQueue: + OsSpinLockInit( queue->QueueLock, adapter->SpinLockCookie); + if (ddi_add_softintr( adapter->Dip, DDI_SOFTINT_HIGH, &queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseNormalDpc, + (caddr_t) queue ) != DDI_SUCCESS) { + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case HostHighRespQueue: + OsSpinLockInit( queue->QueueLock, adapter->SpinLockCookie); + if (ddi_add_softintr( adapter->Dip, DDI_SOFTINT_HIGH, &queue->ConsumerRoutine, NULL, + NULL, (PUNIX_INTR_HANDLER)HostResponseHighDpc, + (caddr_t) queue ) != DDI_SUCCESS) { + + cmn_err(CE_CONT, "OS_addr_intr failed\n"); + } + break; + + case AdapNormCmdQueue: + case AdapHighCmdQueue: + case AdapNormRespQueue: + case AdapHighRespQueue: + OsCv_init( &queue->QueueFull); + break; + } +} + +/*++ + +Routine Description: + Create and start the command receiver threads. + +Arguments: + +Return Value: + Nothing + +--*/ + +int StartFsaCommandThreads(PAFA_COMM_ADAPTER adapter) +{ + return(TRUE); +} + +/*++ + +Routine Description: + This routine will do all of the work necessary to timeout the given fib. + +Arguments: + adapter - Pointer to an adapter structure. + fc - Pointer to the context to time out. + +Return Value: + Nothing. + +--*/ + +void AfaCommTimeoutFib(PAFA_COMM_ADAPTER adapter, PCOMM_FIB_CONTEXT fc) +{ + PFIB Fib = fc->Fib; + +#ifdef unix_fib_timeout + if (Fib->Header.XferState & Async) { + fc->FibCallback(fc->FibCallbackContext, fc, STATUS_IO_TIMEOUT); + } else { + KeSetEvent(&fc->FsaEvent, 0, FALSE); + } +#endif +} + +/*++ + +Routine Description: + This DPC routine is executed by the expiration of a periodic timer. The purpose of this routine + is to check for fib's that should be timed out. + +Arguments: + Dpc - Pointer to this routine. + +Return Value: + Nothing. + +--*/ + +void AfaCommTimeoutRoutine(PKDPC Dpc, void *NullArgument, void *Argument1, void * Argument2) +{ +#ifdef unix_fib_timeout + PCOMM_QUE OurQueue; + PLIST_ENTRY Entry, NextEntry; + LIST_ENTRY TimeoutQueue; + PCOMM_FIB_CONTEXT fc; + LARGE_INTEGER TickCount; + PAFA_COMM_ADAPTER adapter; + + adapter = FsaCommData.AdapterList; + while (adapter) { + InitializeListHead( &TimeoutQueue ); + OurQueue = &adapter->CommRegion->AdapNormCmdQue; + +// KeAcquireSpinLockAtDpcLevel( OurQueue->QueueLock ); + OsSpinLockAcquire( OurQueue->QueueLock ); + KeQueryTickCount(&TickCount); + Entry = OurQueue->OutstandingIoQueue.Flink; + + while (Entry != &OurQueue->OutstandingIoQueue) { + fc = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + // + // If the current tick count if less than the first fib on the queue, then + // none of the fib's have timed out. + // + if (TickCount.QuadPart <= fc->TimeoutValue.QuadPart) { + break; + } + + // + // First, grab the next entry, then put this entry onto the queue to be timed out. + // + NextEntry = Entry->Flink; + + // + // Mark the FibContext as timed out while we have the SpinLock. + // + fc = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + fc->Flags |= FIB_CONTEXT_FLAG_TIMED_OUT; + fc->Fib->Header.XferState |= TimedOut; + + RemoveEntryList( Entry ); + OurQueue->NumOutstandingIos--; + + InsertTailList( &TimeoutQueue, Entry ); + Entry = NextEntry; + } +// KeReleaseSpinLockFromDpcLevel( OurQueue->QueueLock ); + OsSpinLockRelease( OurQueue->QueueLock ); + // + // Now walk through all fibs that need to be timed out. + // + + while (!IsListEmpty( &TimeoutQueue )) { + Entry = RemoveHeadList( &TimeoutQueue ); + fc = CONTAINING_RECORD( Entry, COMM_FIB_CONTEXT, QueueEntry ); + AfaCommTimeoutFib( adapter, fc ); + } + adapter = adapter->NextAdapter; + } +#endif +} + +/*++ + +Routine Description: + This routine gets called to detach all resources that have been allocated for + this adapter. + +Arguments: + adapter - Pointer to the adapter structure to detach. + +Return Value: + TRUE - All resources have been properly released. + FALSE - An error occured while trying to release resources. + +--*/ + +int AacCommDetachAdapter(PAFA_COMM_ADAPTER adapter) +{ + PAFA_CLASS_DRIVER dev; + // + // First remove this adapter from the list of adapters. + // + + if (FsaCommData.AdapterList == adapter) { + FsaCommData.AdapterList = adapter->NextAdapter; + } else { + PAFA_COMM_ADAPTER CurrentAdapter, NextAdapter; + + CurrentAdapter = FsaCommData.AdapterList; + NextAdapter = CurrentAdapter->NextAdapter; + + while (NextAdapter) { + if (NextAdapter == adapter) { + CurrentAdapter->NextAdapter = NextAdapter->NextAdapter; + break; + } + CurrentAdapter = NextAdapter; + NextAdapter = CurrentAdapter->NextAdapter; + } + } + + // + // First send a shutdown to the adapter. + // + + AfaCommShutdown( adapter ); + + // + // Destroy the FibContextZone for this adapter. This will free up all + // of the fib space used by this adapter. + // + + FsaFreeFibContextZone( adapter ); + + // + // Destroy the mutex used for synch'ing adapter fibs. + // + + OsCvLockDestroy( adapter->AdapterFibMutex ); + + // + // Detach all of the host queues. + // + + DetachNTQueue( adapter, &adapter->CommRegion->AdapHighRespQue, AdapHighRespQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->AdapNormRespQue, AdapNormRespQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->HostHighRespQue, HostHighRespQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->HostNormRespQue, HostNormRespQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->AdapHighCmdQue, AdapHighCmdQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->AdapNormCmdQue, AdapNormCmdQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->HostHighCmdQue, HostHighCmdQueue ); + DetachNTQueue( adapter, &adapter->CommRegion->HostNormCmdQue, HostNormCmdQueue ); + + // + // Destroy the mutex used to protect the FibContextZone + // + + OsSpinLockDestroy( adapter->FibContextZoneSpinLock ); + + // + // Call the miniport to free the space allocated for the shared comm queues + // between the host and the adapter. + // + + FsaFreeAdapterCommArea( adapter ); + + // + // Free the memory used by the comm region for this adapter + // + + kfree(adapter->CommRegion); + + // + // Free the memory used by the adapter structure. + // + dev = adapter->ClassDriverList; + adapter->ClassDriverList = adapter->ClassDriverList->Next; + kfree(dev); + kfree(adapter); + + return (TRUE); +} + +void *AfaCommInitNewAdapter(PFSA_NEW_ADAPTER NewAdapter) +{ + void * bugbuf; + PAFA_COMM_ADAPTER adapter; + MAPFIB_CONTEXT MapFibContext; + LARGE_INTEGER Time; + char ErrorBuffer[60]; + +// adapter = (PAFA_COMM_ADAPTER)ExAllocatePool(NonPagedPoolMustSucceed, sizeof(AFA_COMM_ADAPTER)); + adapter = (PAFA_COMM_ADAPTER) kmalloc( sizeof(AFA_COMM_ADAPTER) , GFP_KERNEL ); + + if (adapter == NULL) + return (NULL); + + RtlZeroMemory(adapter, sizeof(AFA_COMM_ADAPTER)); + + + // + // Save the current adapter number and increment the total number. + // + + adapter->AdapterNumber = FsaCommData.TotalAdapters++; + + + // + // Fill in the pointer back to the device specific structures. + // The device specific driver has also passed a pointer for us to + // fill in with the Adapter object that we have created. + // + + adapter->AdapterExtension = NewAdapter->AdapterExtension; + adapter->AdapterFuncs = NewAdapter->AdapterFuncs; + adapter->InterruptsBelowDpc = NewAdapter->AdapterInterruptsBelowDpc; + adapter->AdapterUserVars = NewAdapter->AdapterUserVars; + adapter->AdapterUserVarsSize = NewAdapter->AdapterUserVarsSize; + + adapter->Dip = NewAdapter->Dip; + + // + // Fill in Our address into the function dispatch table + // + + NewAdapter->AdapterFuncs->InterruptHost = AfaCommInterruptHost; + NewAdapter->AdapterFuncs->OpenAdapter = AfaCommOpenAdapter; + NewAdapter->AdapterFuncs->CloseAdapter = AfaCommCloseAdapter; + NewAdapter->AdapterFuncs->DeviceControl = AfaCommAdapterDeviceControl; + + // + // Ok now init the communication subsystem + // + + adapter->CommRegion = (PCOMM_REGION)kmalloc(sizeof(COMM_REGION), GFP_KERNEL); + if (adapter->CommRegion == NULL) { + cmn_err(CE_WARN, "Error could not allocate comm region.\n"); + return (NULL); + } + RtlZeroMemory(adapter->CommRegion, sizeof(COMM_REGION)); + + // + // Get a pointer to the iblock_cookie + // + + ddi_get_soft_iblock_cookie( adapter->Dip, DDI_SOFTINT_HIGH, &adapter->SpinLockCookie ); + + if (!CommInit(adapter)) { + FsaCommPrint("Failed to init the commuication subsystem.\n"); + return(NULL); + } + +#ifdef unix_fib_timeout + // + // If this is the first adapter, then start the timeout routine timer. + // + + if (adapter->AdapterNumber == 0) { + // + // Initialize the DPC used to check for Fib timeouts. + // + + KeInitializeDpc( &FsaCommData.TimeoutDPC, AfaCommTimeoutRoutine, NULL ); + + // + // Initialize the Timer used to check for Fib Timeouts. + // + + KeInitializeTimer( &FsaCommData.TimeoutTimer ); + + // + // Set the timer to go off every 15 seconds. + // + + Time.QuadPart = - (15 * 10 * 1000 * 1000); + KeSetTimerEx( &FsaCommData.TimeoutTimer, Time, (15 * 1000), &FsaCommData.TimeoutDPC ); + } +#endif + + + // + // Initialize the list of AdapterFibContext's. + // + + InitializeListHead(&adapter->AdapterFibContextList); + + // + // Initialize the fast mutex used for synchronization of the adapter fibs + // + + adapter->AdapterFibMutex = OsCvLockAlloc(); + OsCvLockInit(adapter->AdapterFibMutex, NULL); + + // + // Allocate and start the FSA command threads. These threads will handle + // command requests from the adapter. They will wait on an event then pull + // all CDBs off the thread's queue. Each CDB will be given to a worker thread + // upto a defined limit. When that limit is reached wait a event will be waited + // on till a worker thread is finished. + // + + if (!StartFsaCommandThreads(adapter)) { + FsaCommPrint("Fsainit could not initilize the command receiver threads.\n"); + return (NULL); + } + +#ifdef unix_crash_dump + // + // Allocate and map a fib for use by the synch path, which is used for crash + // dumps. + // + // Allocate an entire page so that alignment is correct. + // + + adapter->SyncFib = kmalloc(PAGE_SIZE, GFP_KERNEL); + MapFibContext.Fib = adapter->SyncFib; + MapFibContext.Size = sizeof(FIB); + MapFib( adapter, &MapFibContext ); + adapter->SyncFibPhysicalAddress = MapFibContext.LogicalFibAddress.LowPart; +#endif + + adapter->CommFuncs.SizeOfAfaCommFuncs = sizeof(AFACOMM_FUNCS); + + adapter->CommFuncs.AllocateFib = AllocateFib; + + adapter->CommFuncs.FreeFib = FreeFib; + adapter->CommFuncs.FreeFibFromDpc = FreeFibFromDpc; + adapter->CommFuncs.DeallocateFib = DeallocateFib; + + adapter->CommFuncs.InitializeFib = InitializeFib; + adapter->CommFuncs.GetFibData = FsaGetFibData; + adapter->CommFuncs.SendFib = SendFib; + adapter->CommFuncs.CompleteFib = CompleteFib; + adapter->CommFuncs.CompleteAdapterFib = CompleteAdapterFib; + + adapter->CommFuncs.SendSynchFib = SendSynchFib; + +#ifdef GATHER_FIB_TIMES + // + // Initialize the Fib timing data structures + // + { + PFIB_TIMES FibTimesPtr; + int i; + + KeQueryPerformanceCounter(&adapter->FibTimesFrequency); + adapter->FibTimesFrequency.QuadPart >>= 7; + adapter->FibTimes = (PALL_FIB_TIMES)ExAllocatePool(NonPagedPool, sizeof(ALL_FIB_TIMES)); + RtlZeroMemory(adapter->FibTimes, sizeof(ALL_FIB_TIMES)); + + for (i = 0; i < MAX_FSACOMMAND_NUM; i++) { + FibTimesPtr = &adapter->FibTimes->FileSys[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + FibTimesPtr = &adapter->FibTimes->Read[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + for (i = 0; i < MAX_RW_FIB_TIMES; i++) { + FibTimesPtr = &adapter->FibTimes->Write[i]; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } + FibTimesPtr = &adapter->FibTimes->Other; + FibTimesPtr->Minimum.LowPart = 0xffffffff; + FibTimesPtr->Minimum.HighPart = 0x7fffffff; + FibTimesPtr->AdapterMinimum.LowPart = 0xffffffff; + FibTimesPtr->AdapterMinimum.HighPart = 0x7fffffff; + } +#endif + // + // Add this adapter in to our Adapter List. + // + + adapter->NextAdapter = FsaCommData.AdapterList; + FsaCommData.AdapterList = adapter; + NewAdapter->Adapter = adapter; +// AfaDiskInitNewAdapter( adapter->AdapterNumber, adapter ); + return (adapter); +} + +AAC_STATUS CommInitialize(PAFA_COMM_ADAPTER adapter) +{ + // + // Now allocate and initialize the zone structures used as our pool + // of FIB context records. The size of the zone is based on the + // system memory size. We also initialize the mutex used to protect + // the zone. + // + adapter->FibContextZoneSpinLock= OsSpinLockAlloc(); + OsSpinLockInit( adapter->FibContextZoneSpinLock, adapter->SpinLockCookie ); + adapter->FibContextZoneExtendSize = 64; + return (STATUS_SUCCESS); +} + + + +/*++ + +Routine Description: + Initializes the data structures that are required for the FSA commuication + interface to operate. + +Arguments: + None - all global or allocated data. + +Return Value: + TRUE - if we were able to init the commuication interface. + FALSE - If there were errors initing. This is a fatal error. +--*/ + +int CommInit(PAFA_COMM_ADAPTER adapter) +{ + u32 SizeOfHeaders = (sizeof(QUEUE_INDEX) * NUMBER_OF_COMM_QUEUES) * 2; + u32 SizeOfQueues = sizeof(QUEUE_ENTRY) * TOTAL_QUEUE_ENTRIES; + PQUEUE_INDEX Headers; + PQUEUE_ENTRY Queues; + u32 TotalSize; + PCOMM_REGION CommRegion = adapter->CommRegion; + + CommInitialize( adapter ); + FsaCommPrint("CommInit: Queue entry size is 0x%x, Queue index size is 0x%x, Number of total entries is 0x%x, # queues = 0x%x.\n", + sizeof(QUEUE_ENTRY), sizeof(QUEUE_INDEX), TOTAL_QUEUE_ENTRIES, NUMBER_OF_COMM_QUEUES); + // + // + // Allocate the physically contigous space for the commuication queue + // headers. + // + + TotalSize = SizeOfHeaders + SizeOfQueues; + if (!FsaAllocateAdapterCommArea(adapter, (void * *)&Headers, TotalSize, QUEUE_ALIGNMENT)) + return (FALSE); + +#ifdef API_THROTTLE + // + // Initialize the throttle semaphore. + // Its a counted semaphore so we can allow a + // number of threads to be signalled by it at once. + // + + CommRegion->ThrottleLimit = THROTTLE_MAX_DATA_FIBS; + CommRegion->ThrottleTimeout = RtlConvertLongToLargeInteger(THROTTLE_PERIOD_DURATION); + CommRegion->ThrottleWaitTimeout = RtlConvertLongToLargeInteger(THROTTLE_WAIT_DURATION); + CommRegion->ThrottleActive = FALSE; // Is there a current throttle active period ? + CommRegion->ThrottleTimerFires = 0; // No fires of throttle timer yet. + CommRegion->ThrottleTimerSets = 0; + + CommRegion->ThrottledFibs = 0; + CommRegion->ThrottleTimedoutFibs = 0; + CommRegion->ApiFibs = 0; + CommRegion->NonPassiveFibs = 0; + CommRegion->TotalFibs = 0; + CommRegion->FSInfoFibs = 0; + CommRegion->ThrottleTimedoutFibs = 0; + + // + // Initialize the semaphore controlling I/Os to the adapter. + // We set it not signalled with a maximum signalled count + // representing the maximum number of I/Os we'll allow at + // once at the adapter. + // + KeInitializeSemaphore(&CommRegion->ThrottleReleaseSema, + CommRegion->ThrottleLimit, + CommRegion->ThrottleLimit); + // + // Initialize the Timer and Dpc for the Throttle timeout routine. + // + KeInitializeTimer(&CommRegion->ThrottleTimer); + KeInitializeDpc(&CommRegion->ThrottleDpc, + (PKDEFERRED_ROUTINE) &ThrottlePeriodEndDpcRtn, + (void *) adapter); + +#endif // #ifdef API_THROTTLE + Queues = (PQUEUE_ENTRY)((unsigned char *)Headers + SizeOfHeaders); + if (ddi_add_softintr( adapter->Dip, DDI_SOFTINT_HIGH, &CommRegion->QueueNotFullDpc, NULL, + NULL, (PUNIX_INTR_HANDLER)CommonNotFullDpc, + (caddr_t)CommRegion ) != DDI_SUCCESS) { + cmn_err(CE_CONT, "Os_addr_intr failed\n"); + } + + // adapter to Host normal priority Command queue + CommRegion->HostNormCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->HostNormCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostNormCmdQue.Headers.ProducerIndex = HOST_NORM_CMD_ENTRIES; + *CommRegion->HostNormCmdQue.Headers.ConsumerIndex = HOST_NORM_CMD_ENTRIES; + + CommRegion->HostNormCmdQue.SavedIrql = 0; + CommRegion->HostNormCmdQue.BaseAddress = Queues; + CommRegion->HostNormCmdQue.QueueEntries = HOST_NORM_CMD_ENTRIES; + CommRegion->HostNormCmdQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostNormCmdQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(adapter, &CommRegion->HostNormCmdQue, HostNormCmdQueue); + Queues += HOST_NORM_CMD_ENTRIES; + + // Adapter to Host high priority command queue + CommRegion->HostHighCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->HostHighCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostHighCmdQue.Headers.ProducerIndex = HOST_HIGH_CMD_ENTRIES; + *CommRegion->HostHighCmdQue.Headers.ConsumerIndex = HOST_HIGH_CMD_ENTRIES; + CommRegion->HostHighCmdQue.SavedIrql = 0; + CommRegion->HostHighCmdQue.BaseAddress = Queues; + CommRegion->HostHighCmdQue.QueueEntries = HOST_HIGH_CMD_ENTRIES; +// CommRegion->HostHighCmdQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostHighCmdQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostHighCmdQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(adapter, &CommRegion->HostHighCmdQue, HostHighCmdQueue); + Queues += HOST_HIGH_CMD_ENTRIES; + + // Host to adapter normal priority command queue + + CommRegion->AdapNormCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapNormCmdQue.Headers.ProducerIndex = ADAP_NORM_CMD_ENTRIES; + *CommRegion->AdapNormCmdQue.Headers.ConsumerIndex = ADAP_NORM_CMD_ENTRIES; + + CommRegion->AdapNormCmdQue.SavedIrql = 0; + CommRegion->AdapNormCmdQue.BaseAddress = Queues; + CommRegion->AdapNormCmdQue.QueueEntries = ADAP_NORM_CMD_ENTRIES; + InitializeNTQueue(adapter, &CommRegion->AdapNormCmdQue, AdapNormCmdQueue); + + Queues += ADAP_NORM_CMD_ENTRIES; + + // host to adapter high priority command queue + CommRegion->AdapHighCmdQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapHighCmdQue.Headers.ProducerIndex = ADAP_HIGH_CMD_ENTRIES; + *CommRegion->AdapHighCmdQue.Headers.ConsumerIndex = ADAP_HIGH_CMD_ENTRIES; + + CommRegion->AdapHighCmdQue.SavedIrql = 0; + CommRegion->AdapHighCmdQue.BaseAddress = Queues; + CommRegion->AdapHighCmdQue.QueueEntries = ADAP_HIGH_CMD_ENTRIES; + InitializeNTQueue(adapter, &CommRegion->AdapHighCmdQue, AdapHighCmdQueue); + + Queues += ADAP_HIGH_CMD_ENTRIES; + + // adapter to host normal priority response queue + CommRegion->HostNormRespQue.Headers.ProducerIndex = Headers++; + CommRegion->HostNormRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostNormRespQue.Headers.ProducerIndex = HOST_NORM_RESP_ENTRIES; + *CommRegion->HostNormRespQue.Headers.ConsumerIndex = HOST_NORM_RESP_ENTRIES; + + CommRegion->HostNormRespQue.SavedIrql = 0; + CommRegion->HostNormRespQue.BaseAddress = Queues; + CommRegion->HostNormRespQue.QueueEntries = HOST_NORM_RESP_ENTRIES; +// CommRegion->HostNormRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostNormRespQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostNormRespQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(adapter, &CommRegion->HostNormRespQue, HostNormRespQueue); + + Queues += HOST_NORM_RESP_ENTRIES; + + // adapter to host high priority response queue + + CommRegion->HostHighRespQue.Headers.ProducerIndex = Headers++; + CommRegion->HostHighRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->HostHighRespQue.Headers.ProducerIndex = HOST_HIGH_RESP_ENTRIES; + *CommRegion->HostHighRespQue.Headers.ConsumerIndex = HOST_HIGH_RESP_ENTRIES; + + CommRegion->HostHighRespQue.SavedIrql = 0; + CommRegion->HostHighRespQue.BaseAddress = Queues; + CommRegion->HostHighRespQue.QueueEntries = HOST_HIGH_RESP_ENTRIES; +// CommRegion->HostHighRespQue.QueueLock = (PKSPIN_LOCK) ExAllocatePool(NonPagedPool, sizeof(KSPIN_LOCK)); + CommRegion->HostHighRespQue.QueueLock = OsSpinLockAlloc(); + if (CommRegion->HostHighRespQue.QueueLock == NULL) { + return (FALSE); + } + InitializeNTQueue(adapter, &CommRegion->HostHighRespQue, HostHighRespQueue); + Queues += HOST_HIGH_RESP_ENTRIES; + + // host to adapter normal priority response queue + + CommRegion->AdapNormRespQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapNormRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapNormRespQue.Headers.ProducerIndex = ADAP_NORM_RESP_ENTRIES; + *CommRegion->AdapNormRespQue.Headers.ConsumerIndex = ADAP_NORM_RESP_ENTRIES; + + CommRegion->AdapNormRespQue.SavedIrql = 0; + CommRegion->AdapNormRespQue.BaseAddress = Queues; + CommRegion->AdapNormRespQue.QueueEntries = ADAP_NORM_RESP_ENTRIES; + InitializeNTQueue(adapter, &CommRegion->AdapNormRespQue, AdapNormRespQueue); + + Queues += ADAP_NORM_RESP_ENTRIES; + + // host to adapter high priority response queue + + CommRegion->AdapHighRespQue.Headers.ProducerIndex = Headers++; + CommRegion->AdapHighRespQue.Headers.ConsumerIndex = Headers++; + *CommRegion->AdapHighRespQue.Headers.ProducerIndex = ADAP_HIGH_RESP_ENTRIES; + *CommRegion->AdapHighRespQue.Headers.ConsumerIndex = ADAP_HIGH_RESP_ENTRIES; + + CommRegion->AdapHighRespQue.SavedIrql = 0; + CommRegion->AdapHighRespQue.BaseAddress = Queues; + CommRegion->AdapHighRespQue.QueueEntries = ADAP_HIGH_RESP_ENTRIES; + InitializeNTQueue(adapter, &CommRegion->AdapHighRespQue, AdapHighRespQueue); + + CommRegion->AdapNormCmdQue.QueueLock = CommRegion->HostNormRespQue.QueueLock; + CommRegion->AdapHighCmdQue.QueueLock = CommRegion->HostHighRespQue.QueueLock; + CommRegion->AdapNormRespQue.QueueLock = CommRegion->HostNormCmdQue.QueueLock; + CommRegion->AdapHighRespQue.QueueLock = CommRegion->HostHighCmdQue.QueueLock; + + return(TRUE); +} + +/*++ + +Routine Description: + This routine will send a shutdown request to each adapter. + +Arguments: + adapter - which adapter to send the shutdown to. + +Return Value: + NT status success. + +--*/ + +AAC_STATUS AfaCommShutdown(PAFA_COMM_ADAPTER adapter) +{ + PFIB_CONTEXT fc; + PCLOSECOMMAND CloseCommand; + AAC_STATUS status; + + fc = AllocateFib( adapter ); + InitializeFib( fc ); + + CloseCommand = (PCLOSECOMMAND) FsaGetFibData( fc ); + CloseCommand->Command = VM_CloseAll; + CloseCommand->ContainerId = 0xffffffff; + + status = SendFib( ContainerCommand, fc, sizeof(CLOSECOMMAND), FsaNormal, TRUE, NULL, TRUE, NULL, NULL ); + + if (status != STATUS_SUCCESS) { + FreeFib( fc ); + goto ret; + } + CompleteFib( fc ); + FreeFib( fc ); + status = STATUS_SUCCESS; +ret: + return (status); +} + +/*++ + +Routine Description: + This routine will shutdown the adapter if there is a bugcheck and + copy the shutdown data from the adapter response into the buffer + so it will show up in the host dump file. + +Arguments: + buf - This buffer will be written to the host dump by nt for us. + len - The size of the buffer. + +Return Value: + N/A + +--*/ + +void AfaCommBugcheckHandler(void * buf, u32 len) +{ + PAFA_COMM_ADAPTER adapter = FsaCommData.AdapterList; + while (adapter) { + NotifyAdapter(adapter, HostShutdown); + adapter = adapter->NextAdapter; + } +} + +void FsaCommLogEvent(PFIB_CONTEXT fc, PDEVICE_OBJECT DeviceObject, + AAC_STATUS FsaStatus, AAC_STATUS AacStatus, + u32 LocationCode, u16 Category, + unsigned char * String, int DumpFib) +{ +} + +AfaCommProbeDisks(PAFA_COMM_ADAPTER adapter) +{ + PMNTINFO DiskInfo; + PMNTINFORESPONSE DiskInfoResponse; + AAC_STATUS status; + PCOMM_FIB_CONTEXT fc; + + fc = AllocateFib( adapter ); + InitializeFib( fc ); + + DiskInfo = (PMNTINFO) fc->Fib->data; + DiskInfo->Command = VM_NameServe; + DiskInfo->MntCount = 0; + DiskInfo->MntType = FT_FILESYS; + + status = SendFib(ContainerCommand, + fc, + sizeof(MNTINFO), + FsaNormal, + TRUE, + NULL, + TRUE, + NULL, + NULL); + + DiskInfoResponse = (PMNTINFORESPONSE) fc->Fib->data; + + if (DiskInfoResponse->MntRespCount) { + cmn_err(CE_CONT, "container found on adapter, size = 0x%x blocks\n", + DiskInfoResponse->MntTable[0].Capacity); + } else { + cmn_err(CE_CONT, "no containers found on adapter\n"); + } + CompleteFib( fc ); + FreeFib( fc ); +} + + diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c new file mode 100644 index 000000000000..09b654707ae2 --- /dev/null +++ b/drivers/scsi/aacraid/commsup.c @@ -0,0 +1,1931 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commsup.c + * + * Abstract: Contain all routines that are required for FSA host/adapter + * commuication. + * + * + --*/ +#include "comprocs.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_COMMSUP) + +int CommPrinting; + +void ThrottleExceptionHandler(PCOMM_REGION comm, AAC_STATUS Status); +void ThrottlePeriodEndDpcRtn(PKDPC Dpc, void *DeferredContext, void *SystemArgument1, void *SystemArgument2); + +/*++ + +Routine Description: + This routine will free all resources used by a given FibContextSegment. + +Arguments: + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + ZoneSegment - The segment to release resources from. + +Return Value: + TRUE - All resources were properly freed. + FALSE - An Error occured while freeing resources. + +--*/ + +int FsaFreeFibContextSegment(PAFA_COMM_ADAPTER Adapter, PFIB_CONTEXT_ZONE_SEGMENT ZoneSegment) +{ + PCOMM_FIB_CONTEXT fc; + int i; + + // Account for the ZONE_SEGMENT_HEADER before the first actual FibContext. + for (i = 0, fc = (PCOMM_FIB_CONTEXT)((unsigned char *)ZoneSegment->FibContextSegment + sizeof(ZONE_SEGMENT_HEADER)); + i < ZoneSegment->ExtendSize; i++, fc++) { + OsCvLockDestroy( fc->FsaEventMutex ); + OsCv_destroy( &fc->FsaEvent ); + } + UnmapAndFreeFibSpace(Adapter, &ZoneSegment->MapFibContext); + kfree(ZoneSegment->FibContextSegment); + kfree(ZoneSegment); + return TRUE; +} + +/*++ + +Routine Description: + + This routine will walk through the FibContextSegmentList and free up all + resources used by the FibContextZone. + +Arguments: + + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + +Return Value: + + TRUE - All resources were properly freed. + FALSE - An Error occured while freeing resources. + +--*/ + +int FsaFreeFibContextZone(PAFA_COMM_ADAPTER Adapter) +{ + PFIB_CONTEXT_ZONE_SEGMENT zone, next; + zone = Adapter->FibContextSegmentList; + + while (zone) { + next = zone->Next; + FsaFreeFibContextSegment( Adapter, zone ); + zone = next; + } + return (TRUE); +} + + + +int FsaExtendFibContextZone(PAFA_COMM_ADAPTER Adapter) +{ + int ExtendSize; + KIRQL SavedIrql; + u32 segallocsize, fiballocsize; + void * FibContextSegment; + PCOMM_FIB_CONTEXT fc; + PFIB Fib; + void * fib_pa; + int i; + PFIB_CONTEXT_ZONE_SEGMENT seg; + + // + // Allocate space to describe this zone segment. + // + + seg = kmalloc(sizeof( FIB_CONTEXT_ZONE_SEGMENT ), GFP_KERNEL); + ExtendSize = Adapter->FibContextZoneExtendSize; + segallocsize = (ExtendSize * sizeof(COMM_FIB_CONTEXT)) + sizeof(ZONE_SEGMENT_HEADER); + + FibContextSegment = kmalloc(segallocsize, GFP_KERNEL); + if (FibContextSegment == NULL) { + return (FALSE); + } + + RtlZeroMemory( FibContextSegment, segallocsize ); + seg->FibContextSegment = FibContextSegment; + seg->FibContextSegmentSize = segallocsize; + seg->ExtendSize = ExtendSize; + fiballocsize = ExtendSize * sizeof(FIB); + seg->MapFibContext.Size = fiballocsize; + AllocateAndMapFibSpace( Adapter, &seg->MapFibContext ); + Fib = seg->MapFibContext.FibVirtualAddress; + fib_pa = seg->MapFibContext.FibPhysicalAddress; + RtlZeroMemory( Fib, fiballocsize ); + // Account for the ZONE_SEGMENT_HEADER before the first actual FibContext. + + for (i = 0, fc = (PCOMM_FIB_CONTEXT)((u8 *)FibContextSegment + sizeof(ZONE_SEGMENT_HEADER)); + i < ExtendSize; i++, fc++) { + fc->Adapter = Adapter; + fc->Fib = Fib; + fc->FibData = (void *) fc->Fib->data; + OsCv_init( &fc->FsaEvent); + fc->FsaEventMutex = OsCvLockAlloc(); + OsCvLockInit( fc->FsaEventMutex, Adapter->SpinLockCookie ); + Fib->Header.XferState = 0xffffffff; + Fib->Header.SenderSize = sizeof(FIB); + fc->LogicalFibAddress.LowPart = (u32) fib_pa; + Fib = (PFIB)((u8 *)Fib + sizeof(FIB)); + fib_pa = (void *)((u8 *)fib_pa + sizeof(FIB)); + } + + // + // If FibContextZone.TotalSegmentSize is non-zero, then a zone has already been + // initialized, we just need to extend it. + // + + if (Adapter->FibContextZone.TotalSegmentSize) { + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + ExExtendZone( &Adapter->FibContextZone, + FibContextSegment, + segallocsize ); + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + } else { + if (ExInitializeZone( &Adapter->FibContextZone, + sizeof(COMM_FIB_CONTEXT), + FibContextSegment, + segallocsize ) != STATUS_SUCCESS) + FsaBugCheck(0,0,0); + } + + // + // Add this segment to the adapter's list of segments + // + seg->Next = Adapter->FibContextSegmentList; + Adapter->FibContextSegmentList = seg; + return (TRUE); +} + + + + +/*++ + +Routine Description: + This routine creates a new COMM_FIB_CONTEXT record + +Arguments: + Adapter - The adapter that this COMM_FIB_CONTEXT will communicate with. + +Return Value: + PCOMM_FIB_CONTEXT - returns a pointer to the newly allocate COMM_FIB_CONTEXT Record + +--*/ + +PFIB_CONTEXT AllocateFib (void * AdapterArg) +{ + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) AdapterArg; + KIRQL SavedIrql; + PCOMM_FIB_CONTEXT fc; + int FullZoneLoopCounter = 0; + + // + // Acquire the zone spin lock, and check to see if the zone is full. + // If it is, then release the spin lock and allocate more fibs for the + // zone. The ExtendFibZone routine will re-acquire the spin lock to add + // the new fibs onto the zone. + // + + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + + while (ExIsFullZone( &Adapter->FibContextZone )) + { + if (++FullZoneLoopCounter > 10) + FsaBugCheck(0,0,0); + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + if (FsaExtendFibContextZone(Adapter) == FALSE) { + return (NULL); + } + OsSpinLockAcquire( Adapter->FibContextZoneSpinLock ); + } + + // + // At this point we now know that the zone has at least one more + // IRP context record available. So allocate from the zone and + // then release the mutex. + // + + fc = (PCOMM_FIB_CONTEXT) ExAllocateFromZone( &Adapter->FibContextZone ); + OsSpinLockRelease( Adapter->FibContextZoneSpinLock ); + + // + // Set the proper node type code and node byte size + // + + fc->NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + fc->NodeByteSize = sizeof( COMM_FIB_CONTEXT ); + + // + // Null out fields that depend on being zero at the start of each I/O + // + + fc->Fib->Header.XferState = 0; + fc->FibCallback = NULL; + fc->FibCallbackContext = NULL; + + // + // return and tell the caller + // + + return ((PFIB_CONTEXT) fc); +} + + +/*++ + +Routine Description: + + This routine deallocates and removes the specified COMM_FIB_CONTEXT record + from the Fsafs in memory data structures. It should only be called + by FsaCompleteRequest. + +Arguments: + + fc - Supplies the COMM_FIB_CONTEXT to remove + +Return Value: + + None + +--*/ + +void FreeFib (PFIB_CONTEXT Context) +{ + KIRQL SavedIrql; + PCOMM_FIB_CONTEXT fc = Context; + + ASSERT(fc->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT); + + OsSpinLockAcquire( fc->Adapter->FibContextZoneSpinLock ); + + if (fc->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + FsaCommData.TimedOutFibs++; + fc->Next = fc->Adapter->FibContextTimedOutList; + fc->Adapter->FibContextTimedOutList = fc; + } else { + ASSERT(fc->Fib->Header.XferState == 0); + if (fc->Fib->Header.XferState != 0) { + cmn_err(CE_WARN, "FreeFib, XferState != 0, fc = 0x%x, XferState = 0x%x\n", + fc, fc->Fib->Header.XferState); + } + ExFreeToZone( &fc->Adapter->FibContextZone, fc ); + } + OsSpinLockRelease( fc->Adapter->FibContextZoneSpinLock ); + // + // return and tell the caller + // + return; +} + + +/*++ + +Routine Description: + + This routine deallocates and removes the specified COMM_FIB_CONTEXT record + from the Fsafs in memory data structures. It should only be called + from the dpc routines to from dpc to free an FibContext from an async or + no response io + +Arguments: + + fc - Supplies the COMM_FIB_CONTEXT to remove + +Return Value: + + None + +--*/ + +void FreeFibFromDpc(PFIB_CONTEXT Context) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + ASSERT(fc->NodeTypeCode == FSAFS_NTC_FIB_CONTEXT); + + OsSpinLockAcquire(fc->Adapter->FibContextZoneSpinLock); + if (fc->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) { + FsaCommData.TimedOutFibs++; + fc->Next = fc->Adapter->FibContextTimedOutList; + fc->Adapter->FibContextTimedOutList = fc; + } else { + ASSERT(fc->Fib->Header.XferState == 0); + if (fc->Fib->Header.XferState != 0) { + cmn_err(CE_WARN, "FreeFibFromDpc, XferState != 0, fc = 0x%x, XferState = 0x%x\n", + fc, fc->Fib->Header.XferState); + } + ExFreeToZone( &fc->Adapter->FibContextZone, fc ); + } + OsSpinLockRelease(fc->Adapter->FibContextZoneSpinLock); + // + // return and tell the caller + // + return; +} + + + +/*++ + +Routine Description: + Will initialize a FIB of the requested size. + +Arguments: + Fib is a pointer to a location which will receive the address of the allocated + FIB. + Size is the size of the Fib to allocate. + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS InitializeFib(PFIB_CONTEXT Context) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + PFIB Fib = fc->Fib; + + Fib->Header.StructType = TFib; + Fib->Header.Size = sizeof(FIB); + Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty | FastResponseCapable; + Fib->Header.SenderFibAddress = 0; + Fib->Header.ReceiverFibAddress = 0; + Fib->Header.SenderSize = sizeof(FIB); + return(STATUS_SUCCESS); +} + +/*++ + +Routine Description: + Will allocate and initialize a FIB of the requested size and return a + pointer to the structure. The size allocated may be larger than the size + requested due to allocation performace optimizations. + +Arguments: + Fib is a pointer to a location which will receive the address of the allocated + FIB. + Size is the size of the Fib to allocate. + JustInitialize is a boolean which indicates a Fib has been allocated most likly in an + imbedded structure the FS always allocates. So just initiaize it and return. + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS AllocatePoolFib(PFIB *Fib, u16 Size) +{ +} + +/*++ + +Routine Description: + + Will deallocate and return to the free pool the FIB pointed to by the + caller. Upon return accessing locations pointed to by the FIB parameter + could cause system access faults. + +Arguments: + + Fib is a pointer to the FIB that caller wishes to deallocate. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS DeallocateFib(PFIB_CONTEXT Context) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + PFIB Fib = fc->Fib; + + if ( Fib->Header.StructType != TFib ) { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + + Fib->Header.XferState = 0; + return(STATUS_SUCCESS); +} + + +/*++ + +Routine Description: + Gets a QE off the requested response queue and gets the response FIB into + host memory. The FIB may already be in host memory depending on the bus + interface, or may require the host to DMA it over from the adapter. The routine + will return the FIB to the caller. + +Arguments: + ResponseQueue - Is the queue the caller wishes to have the response gotten from. + Fib - Is the Fib which was the response from the adapter + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if there was no Fib to return to the caller. + bkpfix - add in all the other possible errors ect + +--*/ + +AAC_STATUS GetResponse(PCOMM_QUE ResponseQueue, PFIB Fib) +{ + return(STATUS_UNSUCCESSFUL); +} + +// +// Commuication primitives define and support the queuing method we use to +// support host to adapter commuication. All queue accesses happen through +// these routines and are the only routines which have a knowledge of the +// how these queues are implemented. +// + +/*++ + +Routine Description: + + With a priority the routine returns a queue entry if the queue has free entries. If the queue + is full(no free entries) than no entry is returned and the function returns FALSE otherwise TRUE is + returned. + +Arguments: + + Priority is an enumerated type which determines which priority level + command queue the QE is going to be queued on. + + entry is a pointer to the address of where to return the address of + the queue entry from the requested command queue. + + Index is a pointer to the address of where to store the index of the new + queue entry returned. + + DontInterrupt - We set this true if the queue state is such that we don't + need to interrupt the adapter for this queue entry. + +Return Value: + + TRUE - If a queue entry is returned + FALSE - If there are no free queue entries on the requested command queue. + +--*/ + +int GetEntry(PAFA_COMM_ADAPTER Adapter, QUEUE_TYPES WhichQueue, PQUEUE_ENTRY *entry, PQUEUE_INDEX Index, u32 *DontInterrupt) +{ + u32 QueueOffset; + int status; + PCOMM_REGION comm; + + comm = Adapter->CommRegion; + + // + // All of the queues wrap when they reach the end, so we check to see if they + // have reached the end and if they have we just set the index back to zero. + // This is a wrap. You could or off the high bits in all updates but this is + // a bit faster I think. + // + + if (WhichQueue == AdapHighCmdQueue) + { + *Index = *(comm->AdapHighCmdQue.Headers.ProducerIndex); + if (*Index - 2 == *(comm->AdapHighCmdQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + if (*Index >= ADAP_HIGH_CMD_ENTRIES) + *Index = 0; + if (*Index + 1 == *(comm->AdapHighCmdQue.Headers.ConsumerIndex)) + { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter High Command Queue full, %d outstanding", + comm->AdapHighCmdQue.NumOutstandingIos); + } else { + QueueOffset = sizeof(QUEUE_ENTRY) * (*Index); + *entry = QueueOffset + comm->AdapHighCmdQue.BaseAddress; + status = TRUE; + } + } + else if (WhichQueue == AdapNormCmdQueue) + { + *Index = *(comm->AdapNormCmdQue.Headers.ProducerIndex); + if (*Index - 2 == *(comm->AdapNormCmdQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + // + // If we are at the end of the QUEUE then wrap back to + // the beginning. + // + if (*Index >= ADAP_NORM_CMD_ENTRIES) + *Index = 0; // Wrap to front of the Producer Queue. + + // + // The IEEE spec says that it the producer is one behind the consumer then + // the queue is full. + // + + ASSERT(*(comm->AdapNormCmdQue.Headers.ConsumerIndex) != 0); + if (*Index + 1 == *(comm->AdapNormCmdQue.Headers.ConsumerIndex)) + { + // Queue is full + cmn_err(CE_WARN, "Adapter Norm Command Queue full, %d outstanding", + comm->AdapNormCmdQue.NumOutstandingIos); + status = FALSE; + } else { + // + // The success case just falls through and returns the a valid queue entry. + // +#ifdef commdebug + FsaCommPrint("queue entry = %x.\n",comm->AdapNormCmdQue.BaseAddress + *Index); + FsaCommPrint("GetEntry: Index = %d, QueueOffset = %x, entry = %x, *entry = %x.\n", + *Index, QueueOffset, entry, *entry); +#endif + *entry = comm->AdapNormCmdQue.BaseAddress + *Index; + status = TRUE; + } + } + else if (WhichQueue == AdapHighRespQueue) + { + *Index = *(comm->AdapHighRespQue.Headers.ProducerIndex); + if (*Index - 2 == *(comm->AdapHighRespQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + if (*Index >= ADAP_HIGH_RESP_ENTRIES) + *Index = 0; + if (*Index + 1 == *(comm->AdapHighRespQue.Headers.ConsumerIndex)) { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter High Resp Queue full, %d outstanding", + comm->AdapHighRespQue.NumOutstandingIos); + } + else + { + *entry = comm->AdapHighRespQue.BaseAddress + *Index; + status = TRUE; + } + } + else if (WhichQueue == AdapNormRespQueue) + { + *Index = *(comm->AdapNormRespQue.Headers.ProducerIndex); + if (*Index - 2 == *(comm->AdapNormRespQue.Headers.ConsumerIndex)) + *DontInterrupt = TRUE; + // + // If we are at the end of the QUEUE then wrap back to + // the beginning. + // + + if (*Index >= ADAP_NORM_RESP_ENTRIES) + *Index = 0; // Wrap to front of the Producer Queue. + // + // The IEEE spec says that it the producer is one behind the consumer then + // the queue is full. + // + + if (*Index + 1 == *(comm->AdapNormRespQue.Headers.ConsumerIndex)) { // Queue is full + status = FALSE; + cmn_err(CE_WARN, "Adapter Norm Resp Queue full, %d outstanding", + comm->AdapNormRespQue.NumOutstandingIos); + } + else + { + // + // The success case just falls through and returns the a valid queue entry. + // + *entry = comm->AdapNormRespQue.BaseAddress + *Index; +#ifdef commdebug + FsaCommPrint("queue entry = %x.\n",comm->AdapNormRespQue.BaseAddress + *Index); + FsaCommPrint("GetEntry: Index = %d, entry = %x, *entry = %x.\n",*Index, entry, *entry); +#endif + status = TRUE; + } + } + else + { + cmn_err(CE_PANIC, "GetEntry: invalid queue %d", WhichQueue); + } + return (status); +} + +#ifdef API_THROTTLE + +/*++ + +Routine Description: + This routine implements data I/O throttling. Throttling occurs when + a CLI FIB is detected. To ensure the CLI responds quickly (the user + is waiting for the response), this mechanism restricts the queue + depth of data IOs at the adapter for a period of time (called the + Throttle Period, default 5 seconds). + + The mechanism uses a counted semaphore to place threads into a wait + state should there be too many data I/Os outstanding. + + At the start of a throttle period (indicated by the first CLI FIB) + a timer is started. When the timer expires, new requests can go to + the adapter freely. Throttled requests gradually drain to the + adapter as each outstanding throttle I/O completes. + + To avoid hurting regular I/O performance, we use a flag in the FIB + header to mark FIBs involved in throttling. This means we only need + take the extra spinlock in the response DPC routine for FIBs who + were subject to throttling. If no throttling is occurring, the cost + to the regular code paths is a handful of instructions. + +Arguments: + Adapter - Pointer to per-adapter context. This is used to locate the + throttle information for this adapter. + Fib - Pointer to the header for the fib being sent. + +Return Value: + None. + +--*/ + +void ThrottleCheck(PAFA_COMM_ADAPTER Adapter, PFIB Fib) +{ + PCOMM_REGION comm = Adapter->CommRegion; + AAC_STATUS status; + + // + // This routine is called under protection of the queue spinlock. + // As such we are allowed to check and change the counts for the + // throttle. + // Check the FIB. If its not a data operation, send it on without + // throttle check. If it is a data operation, check for throttle. + // + comm->TotalFibs++; // Keep statistics + + if ((Fib->Header.XferState & ApiFib) != 0) { + comm->ApiFibs++; // Keep statistics + // + // Its an API fib. If the throttle is not already active, + // make it so. This will prevent new data Fibs being sent + // if they exceed the throttle check. + // + if (!comm->ThrottleActive) { + int InQue; + + // This causes new data I/Os to be throttled + comm->ThrottleActive = TRUE; + // + // Schedule a timer for the throttle active period. When + // it expires, we'll be called back at routine ThrottleDpcRoutine + // above. This will signify the throttle active period ended + // and any waiting threads will be signalled to restart. + // + + FsaCommPrint("Throttle Period Start - comm: %x\n", comm); + comm->ThrottleTimerSets++; + InQue = KeSetTimer( &comm->ThrottleTimer, + comm->ThrottleTimeout, + &comm->ThrottleDpc); + ASSERT(InQue == FALSE); + } + return; + } + + // + // Its a non-API fib, so subject to throttle checks. + // The following are exempt from throttling: + // o FIBs marked as "throttle exempt" by upper layers. + // o I/Os issued from a raised IRQL. We can't suspend + // a thread when at raised IRQL so throttling is exempt. + // + + if (comm->AdapNormCmdQue.SavedIrql != PASSIVE_LEVEL) { + comm->NonPassiveFibs++; + FsaCommPrint("ThrottleCheck: Non-Passive level FIB bypasses throttle: %x\n", Fib); + return; + } + + if (comm->ThrottleActive) { + // + // Throttle is active. + // Check if the FIB is a read or write. If so, and its to the + // file system information area, let it through without throttling. + // + if (Fib->Header.Command == ContainerCommand) { + PBLOCKREAD BlockDisk = (PBLOCKREAD) &Fib->data; + // + // *** Note *** We are using read and write command formats + // interchangably here. This is ok for this purpose as the + // command is in the same place for both. Read and write command + // formats are different at higher offsets though. + // + if ( ((BlockDisk->Command == VM_CtBlockRead) || + (BlockDisk->Command == VM_CtBlockWrite)) && + (BlockDisk->BlockNumber <= FILESYSTEM_INFO_MAX_BLKNO)) { + comm->FSInfoFibs++; // Keep statistics + return; + } + } + // + // Throttle the FIB. + // Mark it as throttle active so that it can signal a waiter + // when it completes. + + comm->ThrottledFibs++; + Fib->Header.Flags |= ThrottledFib; + + // + // Release the spinlock so we can wait the thread if necessary. + // Since we specify a timeout, check the caller is at passive level. + // + + OsSpinLockRelease((comm->AdapNormCmdQue.QueueLock), comm->AdapNormCmdQue.SavedIrql); + FsaCommPrint("ThrottleCheck - Thread Suspension - FIB: %x\n", Fib); + status = KeWaitForSingleObject(&comm->ThrottleReleaseSema, + Executive, // Don't allow user APCs to wake us + KernelMode, // Wait in kernel mode + FALSE, // Not alertable + &comm->ThrottleWaitTimeout); // Timeout after this time + // + // Check the signal status. If we've timed out, clear the throttle + // flag on the FIB to avoid us signalling the semaphore on completion. + // We never acquired the semaphore. + // + if (status == STATUS_TIMEOUT) { + comm->ThrottleTimedoutFibs++; + FsaCommPrint("ThrottledFib Timed Out - FIB: %x\n", Fib); + Fib->Header.Flags &= ~ThrottledFib; // Clear the throttledfib flag + } else { + ASSERT(status == STATUS_SUCCESS); // No other return is possible + } + + // + // We've been woken up and can now send the FIB to the adapter. + // Acquire the spinlock again so we can get a queue entry. This + // returns to GetQueueEntry. + // + + FsaCommPrint("ThrottleCheck - Thread Resume - FIB: %x\n", Fib); + KeAcquireSpinLock((comm->AdapNormCmdQue.QueueLock), &(comm->AdapNormCmdQue.SavedIrql)); + comm->ThrottleOutstandingFibs++; // There's another throttle controlled FIB going. + return; + } +} + +#endif //#ifdef API_THROTTLE + +int GetQueueEntryTimeouts = 0; +/*++ + +Routine Description: + Gets the next free QE off the requested priorty adapter command queue and + associates the Fib with the QE. The QE represented by index is ready to + insert on the queue when this routine returns success. + +Arguments: + Index is the returned value which represents the QE which is ready to + insert on the adapter's command queue. + + Priority is an enumerated type which determines which priority level + command queue the QE is going to be queued on. + + Fib is a pointer to the FIB the caller wishes to have associated with the QE. + + Wait is a boolean which determines if the routine will wait if there are + no free QEs on the requested priority command queue. + + FibContext is where the driver stores all system resources required to execute the + command requested from the calling thread. This includes mapping resources for + the FIB and the 'users' buffer. + + DontInterrupt - We set this true if the queue state is such that we don't + need to interrupt the adapter for this queue entry. + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS GetQueueEntry(PAFA_COMM_ADAPTER Adapter, PQUEUE_INDEX Index, + QUEUE_TYPES WhichQueue, PFIB Fib, int wait, PCOMM_FIB_CONTEXT fc, + u32 *DontInterrupt) +{ + PQUEUE_ENTRY QueueEntry = NULL; + int MapAddress = FALSE; + int timeouts = 0; + AAC_STATUS status; + PCOMM_REGION comm; + + comm = Adapter->CommRegion; + + // + // Get the spinlock for the queue we are putting a command on + // + + if (WhichQueue == AdapHighCmdQueue) + OsSpinLockAcquire(comm->AdapHighCmdQue.QueueLock); + else if (WhichQueue == AdapNormCmdQueue) + OsSpinLockAcquire(comm->AdapNormCmdQue.QueueLock); + else if (WhichQueue == AdapHighRespQueue) + OsSpinLockAcquire(comm->AdapHighRespQue.QueueLock); + else if (WhichQueue == AdapNormRespQueue) + OsSpinLockAcquire(comm->AdapNormRespQue.QueueLock); + else { + FsaCommPrint("Invalid queue priority passed to GetQueueEntry.\n"); + return(FSA_INVALID_QUEUE); + } + + // + // Get the pointers to a queue entry on the queue the caller wishes to queue + // a command request on. If there are no entries then wait if that is what the + // caller requested. + // + + if (WhichQueue == AdapHighCmdQueue) + { + while ( !GetEntry(Adapter, AdapHighCmdQueue, &QueueEntry, Index, DontInterrupt) ) + { + // if no entries wait for some if caller wants to + cmn_err(CE_PANIC, "GetEntries failed (1)\n"); + } + // + // Setup queue entry with a command, status and Fib mapped + // + QueueEntry->Size = Fib->Header.Size; + MapAddress = TRUE; + } + else if (WhichQueue == AdapNormCmdQueue) + { +#ifdef API_THROTTLE + // + // Check if this is a data I/O that may be throttled. Throttling + // occurs if FAST is trying to issue FIBs to the adapter for management + // commands. If a FAST FIB is detected by ThrottleCheck it is allowed + // to go to the adapter (barring no queue entries being available). If + // the FAST fib is the first FAST fib to be detected, a data I/O throttle + // period is started. New incoming data I/Os are restricted so that only + // a few can be outstanding to the adapter at once. This prevents the + // FAST FIBs being starved out from the disks. Once the period has ended, + // normal service is resumed. + // New data FIBs (i.e. non-FAST FIB) can be initiated so long as they + // don't exceed the throttle maximum of outstanding FIBs. If the new FIB + // *would* exceed the maximum, the thread is put to sleep, waiting on the + // data I/O throttle synchronization semaphore. When the first data FIB completes + // that takes the outstanding count to below the threshold, the throttle + // synchronization semaphore is signalled once. It is signaled for each completing + // FIB until the throttle period ends and all throttled FIBs have completed. + // + ThrottleCheck(Adapter, Fib); // Thread may be suspended here with spinlock released ! +#endif // #ifdef API_THROTTLE +#ifdef commdebug + FsaCommPrint("Requesting a qe address in address %x.\n", &QueueEntry); +#endif + while ( !GetEntry(Adapter, AdapNormCmdQueue, &QueueEntry, Index, DontInterrupt) ) + { + // if no entries wait for some if caller wants to + cmn_err(CE_PANIC, "GetEntries failed (2)\n"); + } + + // + // Setup queue entry with command, status and Fib mapped + // + +#ifdef commdebug + FsaCommPrint("We got a QE from the normal command queue address of %x, Index returned = %d\n", *QueueEntry, *Index); +#endif + QueueEntry->Size = Fib->Header.Size; + MapAddress = TRUE; + } + else if (WhichQueue == AdapHighRespQueue) + { + while ( !GetEntry(Adapter, AdapHighRespQueue, &QueueEntry, Index, DontInterrupt) ) + { + // if no entries wait for some if caller wants to + } + // + // Setup queue entry with command, status and Fib mapped + // + QueueEntry->Size = Fib->Header.Size; + QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB + Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data + MapAddress = FALSE; + } else if (WhichQueue == AdapNormRespQueue) + { + while ( !GetEntry(Adapter, AdapNormRespQueue, &QueueEntry, Index, DontInterrupt) ) + { + // if no entries wait for some if caller wants to + } + // + // Setup queue entry with command, status, adapter's pointer to the Fib it sent + // + QueueEntry->Size = Fib->Header.Size; + QueueEntry->FibAddress = Fib->Header.SenderFibAddress; // Restore adapters pointer to the FIB + Fib->Header.ReceiverFibAddress = Fib->Header.SenderFibAddress; // Let the adapter now where to find its data + MapAddress = FALSE; + } + + // + // If MapFib is true than we need to map the Fib and put pointers in the queue entry. + // + + if (MapAddress) + { + QueueEntry->FibAddress = (u32)(fc->LogicalFibAddress.LowPart); + } + + // + // Return + // +#ifdef commdebug + FsaCommPrint("Queue Entry contents:.\n"); + FsaCommPrint(" Command = %d.\n", QueueEntry->Command); + FsaCommPrint(" status = %x.\n", QueueEntry->Status); + FsaCommPrint(" Rec Fib address low = %x.\n", QueueEntry->FibAddressLow); + FsaCommPrint(" Fib size in bytes = %d.\n", QueueEntry->Size); +#endif + return(FSA_SUCCESS); +} + +/*++ + +Routine Description: + + Gets the next free QE off the requested priorty adapter command queue and + associates the Fib with the QE. The QE represented by index is ready to + insert on the queue when this routine returns success. + +Arguments: + + Index is the returned value which represents the QE which is ready to + insert on the adapter's command queue. + + WhichQueue tells us which queue the caller wishes to have the entry put. + +Return Value: + + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS InsertQueueEntry(PAFA_COMM_ADAPTER Adapter, QUEUE_INDEX Index, + QUEUE_TYPES WhichQueue, u32 DontInterrupt) +{ + PCOMM_REGION comm; + comm = Adapter->CommRegion; + + // + // We have already verified the queue in getentry, but we still have to make + // sure we don't wrap here too. + // + + if (WhichQueue == AdapHighCmdQueue) + { + *(comm->AdapHighCmdQue.Headers.ProducerIndex) = Index + 1; + OsSpinLockRelease(comm->AdapHighCmdQue.QueueLock); + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapHighCmdQue); + } + else if (WhichQueue == AdapNormCmdQueue) + { +#ifdef commdebug + FsaCommPrint("InsertQueueEntry: Inerting with an index of %d.\n",Index); +#endif + *(comm->AdapNormCmdQue.Headers.ProducerIndex) = Index + 1; + OsSpinLockRelease(comm->AdapNormCmdQue.QueueLock); + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapNormCmdQue); + } + else if (WhichQueue == AdapHighRespQueue) + { + *(comm->AdapHighRespQue.Headers.ProducerIndex) = Index + 1; + OsSpinLockRelease(comm->AdapHighRespQue.QueueLock); + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapHighRespQue); + } + else if (WhichQueue == AdapNormRespQueue) + { + *(comm->AdapNormRespQue.Headers.ProducerIndex) = Index + 1; + OsSpinLockRelease(comm->AdapNormRespQue.QueueLock); + if (!DontInterrupt) + NotifyAdapter(Adapter, AdapNormRespQue); + } + else + { + FsaCommPrint("Invalid queue priority passed to InsertQueueEntry.\n"); + return(FSA_INVALID_QUEUE_PRIORITY); + } + return(FSA_SUCCESS); +} + +extern int GatherFibTimes; + +/*++ + +Routine Description: + This routine will send a synchronous FIB to the adapter and wait for its + completion. + +Arguments: + DeviceExtension - Pointer to adapter extension structure. + +Return Value: + int + +--*/ + +int SendSynchFib(void *Arg, FIB_COMMAND Command, void *Data, u16 Size, + void *Response, u16 *ResponseSize) +{ + PAFA_COMM_ADAPTER Adapter = Arg; + FIB *Fib; + u32 returnStatus; + + Fib = Adapter->SyncFib; + + Fib->Header.StructType = TFib; + Fib->Header.Size = sizeof(FIB); + Fib->Header.XferState = HostOwned | FibInitialized | FibEmpty; + Fib->Header.ReceiverFibAddress = 0; + Fib->Header.SenderSize = sizeof(FIB); + Fib->Header.SenderFibAddress = (u32)Fib; + Fib->Header.Command = Command; + + // + // Copy the Data portion into the Fib. + // + RtlCopyMemory( Fib->data, Data, Size ); + Fib->Header.XferState |= (SentFromHost | NormalPriority); + + // + // Set the size of the Fib we want to send to the adapter + // + Fib->Header.Size = sizeof(FIB_HEADER) + Size; + if (!Adapter->AdapterFuncs->SendSynchFib( Adapter->AdapterExtension, Adapter->SyncFibPhysicalAddress )) { + return (FALSE); + } + + // + // Copy the response back to the caller's buffer. + // + RtlCopyMemory( Response, Fib->data, Fib->Header.Size - sizeof(FIB_HEADER) ); + *ResponseSize = Fib->Header.Size - sizeof(FIB_HEADER); + + // + // Indicate success + // + return (TRUE); +} + +// +// Define the highest level of host to adapter communication routines. These +// routines will support host to adapter FS commuication. These routines have +// no knowledge of the commuication method used. This level sends and receives +// FIBs. This level has no knowledge of how these FIBs get passed back and forth. +// + +/*++ + +Routine Description: + Sends the requested FIB to the adapter and optionally will wait for a + response FIB. If the caller does not wish to wait for a response than + an event to wait on must be supplied. This event will be set when a + response FIB is received from the adapter. + +Arguments: + Fib is a pointer to the FIB the caller wishes to send to the adapter. + Size - Size of the data portion of the Fib. + Priority is an enumerated type which determines which priority level + the caller wishes to send this command at. + wait is a boolean which determines if the routine will wait for the + completion Fib to be returned(TRUE), or return when the Fib has been + successfully received by the adapter(FALSE). + waitOn is only vaild when wait is FALSE. The Event will be set when the response + FIB has been returned by the adapter. + ReturnFib is an optional pointer to a FIB that if present the response FIB will + copied to. + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS SendFib(FIB_COMMAND Command, PFIB_CONTEXT Context, u32 Size, + COMM_PRIORITIES Priority, int wait, void * WaitOn, + int ResponseExpected, PFIB_CALLBACK FibCallback, void * FibCallbackContext) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + QUEUE_INDEX Index; + QUEUE_TYPES WhichQueue; + LARGE_INTEGER Timeout; + AAC_STATUS status; + PAFA_COMM_ADAPTER Adapter = fc->Adapter; + u32 DontInterrupt = FALSE; + PFIB Fib = fc->Fib; + PCOMM_QUE OurQueue; + +// cmn_err( CE_NOTE, "^SendFib entered\n"); + + Timeout = FsaCommData.AdapterTimeout; + + if (!(Fib->Header.XferState & HostOwned)) + { + FsaCommPrint("SendFib was called with a xfer state not set to HostOwned!\n"); + FsaCommLogEvent(fc, + FsaCommData.DeviceObject, + FSAFS_FIB_INVALID, + STATUS_UNSUCCESSFUL, + BugCheckFileId | __LINE__, + FACILITY_FSAFS_ERROR_CODE, + NULL, + TRUE); + return(STATUS_UNSUCCESSFUL); + } + + // + // There are 5 cases with the wait and reponse requested flags. The only invalid cases + // are if the caller requests to wait and does not request a response and if the + // caller does not want a response and the Fib is not allocated from pool. If a response + // is not requesed the Fib will just be deallocaed by the DPC routine when the response + // comes back from the adapter. No further processing will be done besides deleting the + // Fib. We will have a debug mode where the adapter can notify the host it had a problem + // and the host can log that fact. + + if (wait && !ResponseExpected) + { + FsaCommLogEvent(fc, + FsaCommData.DeviceObject, + FSAFS_FIB_INVALID, + STATUS_UNSUCCESSFUL, + BugCheckFileId | __LINE__, + FACILITY_FSAFS_ERROR_CODE, + NULL, + TRUE); + return(STATUS_UNSUCCESSFUL); + } + else if (!wait && ResponseExpected) + { + Fib->Header.XferState |= (Async | ResponseExpected); + FIB_COUNTER_INCREMENT(FsaCommData.AsyncSent); + } + else if (!wait && !ResponseExpected) + { + Fib->Header.XferState |= NoResponseExpected; + FIB_COUNTER_INCREMENT(FsaCommData.NoResponseSent); + } + else if (wait && ResponseExpected) + { +// OsCv_init(&fc->FsaEvent, NULL, CV_DRIVER, NULL); + Fib->Header.XferState |= ResponseExpected; + FIB_COUNTER_INCREMENT(FsaCommData.NormalSent); + } + Fib->Header.SenderData = (u32)fc; // so we can complete the io in the dpc routine + + // + // Set FIB state to indicate where it came from and if we want a response from the + // adapter. Also load the command from the caller. + // + + Fib->Header.SenderFibAddress = (u32)Fib; + Fib->Header.Command = Command; + Fib->Header.XferState |= SentFromHost; + fc->Fib->Header.Flags = 0; // Zero the flags field - its internal only... + + // + // Set the size of the Fib we want to send to the adapter + // + + Fib->Header.Size = sizeof(FIB_HEADER) + Size; + if (Fib->Header.Size > Fib->Header.SenderSize) + { + return(STATUS_BUFFER_OVERFLOW); + } + // + // Get a queue entry connect the FIB to it and send an notify the adapter a command is ready. + // + + if (Priority == FsaHigh) + { + Fib->Header.XferState |= HighPriority; + WhichQueue = AdapHighCmdQueue; + OurQueue = &Adapter->CommRegion->AdapHighCmdQue; + } + else + { + Fib->Header.XferState |= NormalPriority; + WhichQueue = AdapNormCmdQueue; + OurQueue = &Adapter->CommRegion->AdapNormCmdQue; + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) + { + if (Command == NuFileSystem) + { + FSACOMMAND FsaCommand; + PREAD ReadCommand; + PWRITE WriteCommand; + int Index; + FsaCommand = (FSACOMMAND)Fib->data[0]; + + switch (FsaCommand) { + case Read: + ReadCommand = (PREAD)Fib->data; + Index = ReadCommand->ByteCount >> 9; // divide by 512 + fc->FibTimesPtr = &Adapter->FibTimes->Read[Index]; + break; + + case Write: + WriteCommand = (PWRITE)Fib->data; + Index = WriteCommand->ByteCount >> 9; // divide by 512 + fc->FibTimesPtr = &Adapter->FibTimes->Write[Index]; + break; + + default: + fc->FibTimesPtr = &Adapter->FibTimes->FileSys[FsaCommand]; + break; + } + } + else + { + fc->FibTimesPtr = &Adapter->FibTimes->Other; + } + } +#endif + +#ifdef FIB_CHECKSUMS + if (FsaCommData.do_fib_checksums) + { + int i; + unsigned char *pFib; + u32 CheckSum = 0; + Fib->Header.FibCheckSum = 0; // Zero out checksum before computing + + pFib = (unsigned char *)Fib; + for (i = 0; i < Fib->Header.Size; i++) { + CheckSum += *pFib++; + } + Fib->Header.FibCheckSum = CheckSum; + } +#endif + + if ( GetQueueEntry( Adapter, &Index, WhichQueue, Fib, TRUE, fc, &DontInterrupt) != FSA_SUCCESS ) + { + return(STATUS_UNSUCCESSFUL); + //FsaBugCheck(IrpContext, Index, WhichQueue); + } + +#ifdef commdebug + FsaCommPrint("SendFib: inserting a queue entry at index %d.\n",Index); + FsaCommPrint("Fib contents:.\n"); + FsaCommPrint(" Command = %d.\n", Fib->Header.Command); + FsaCommPrint(" XferState = %x.\n", Fib->Header.XferState ); + FsaCommPrint(" Send Fib low address = %x.\n", Fib->Header.SenderFibAddressLow); + FsaCommPrint(" Send Fib high address = %x.\n", Fib->Header.SenderFibAddressHigh); + FsaCommPrint(" Sender data low = %x.\n", Fib->Header.SenderDataLow); + FsaCommPrint(" Sender data High = %x.\n", Fib->Header.SenderDataHigh); + FsaCommPrint(" Rec Fib address low = %x.\n", Fib->Header.ReceiverFibAddressLow); +#endif + + // + // Fill in the Callback and CallbackContext if we are not going to wait. + // + + if (!wait) { + fc->FibCallback = FibCallback; + fc->FibCallbackContext = FibCallbackContext; + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) { + fc->FibTimeStamp.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7; + } +#endif // GATHER_FIB_TIMES + + FIB_COUNTER_INCREMENT(FsaCommData.FibsSent); + +#ifdef unix_fib_timeout + // + // Put this fib onto the Outstanding I/O queue and increment the number of outstanding fibs. + // + + KeQueryTickCount( &fc->TimeoutValue ); + fc->TimeoutValue.QuadPart += FsaCommData.FibTimeoutIncrement; +#endif + InsertTailList( &OurQueue->OutstandingIoQueue, &fc->QueueEntry ); + OurQueue->NumOutstandingIos++; + + fc->FibComplete = 0; + + if ( InsertQueueEntry( Adapter, Index, WhichQueue, (DontInterrupt & FsaCommData.EnableInterruptModeration)) != FSA_SUCCESS ) { + return(STATUS_UNSUCCESSFUL); + //FsaBugCheck(IrpContext, Index, WhichQueue); + } + + // + // If the caller wanted us to wait for response wait now. + // If Timeouts are enabled than set the timeout otherwise wait forever. + // + + FSA_DO_PERF_INC(FibsSent) + + if (wait) + { + OsCvLockAcquire( fc->FsaEventMutex ); + while (fc->FibComplete == 0) { + OsCv_wait( &fc->FsaEvent, fc->FsaEventMutex ); + } + OsCvLockRelease( fc->FsaEventMutex ); + if ( (fc->Flags & FIB_CONTEXT_FLAG_TIMED_OUT) ) { + return(STATUS_IO_TIMEOUT); + } else { + return(STATUS_SUCCESS); + } + } + + // + // If the user does not want a response than return success otherwise return pending + // + + ASSERT( FibCallback ); + + if (ResponseExpected) + return(STATUS_PENDING); + else + return(STATUS_SUCCESS); +} + +/*++ + +Routine Description: + + Will return a pointer to the entry on the top of the queue requested that we are a consumer + of, and return the address of the queue entry. It does not change the state of the queue. + +Arguments: + + OurQueue - is the queue the queue entry should be removed from. + + entry - is a pointer where the address of the queue entry should be returned. + +Return Value: + + TRUE if there was a queue entry on the response queue for the host to consume. + FALSE if there were no queue entries to consume. + +--*/ + +int GetConsumerEntry(PAFA_COMM_ADAPTER Adapter, PCOMM_QUE OurQueue, PQUEUE_ENTRY *entry) +{ + QUEUE_INDEX Index; + int status; + + if (*OurQueue->Headers.ProducerIndex == *OurQueue->Headers.ConsumerIndex) + { + status = FALSE; + } else { + // + // The consumer index must be wrapped if we have reached the end of + // the queue. + // Else we just use the entry pointed to by the header index + // + + if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries) + Index = 0; + else + Index = *OurQueue->Headers.ConsumerIndex; + *entry = OurQueue->BaseAddress + Index; +#ifdef commdebug + FsaCommPrint("Got a QE at Index %d, QE Addrss of %x.\n",Index,*entry); +#endif + status = TRUE; + } + return(status); +} + +int ConsumerEntryAvailable(PAFA_COMM_ADAPTER Adapter, PCOMM_QUE OurQueue) +{ + return (*OurQueue->Headers.ProducerIndex != *OurQueue->Headers.ConsumerIndex); +} + +/*++ + +Routine Description: + Frees up the current top of the queue we are a consumer of. If the queue was full + notify the producer that the queue is no longer full. + +Arguments: + OurQueue - is the queue we will free the current consumer entry on. + +Return Value: + TRUE if there was a queue entry on the response queue for the host to consume. + FALSE if there were no queue entries to consume. + +--*/ + +void FreeConsumerEntry(PAFA_COMM_ADAPTER Adapter, PCOMM_QUE OurQueue, QUEUE_TYPES WhichQueue) +{ + int WasFull = FALSE; + HOST_2_ADAP_EVENT Notify; + + if (*OurQueue->Headers.ProducerIndex+1 == *OurQueue->Headers.ConsumerIndex) + WasFull = TRUE; + + if (*OurQueue->Headers.ConsumerIndex >= OurQueue->QueueEntries) + *OurQueue->Headers.ConsumerIndex = 1; + else + *OurQueue->Headers.ConsumerIndex += 1; + + if (WasFull) + { + switch (WhichQueue) + { + case HostNormCmdQueue: + Notify = HostNormCmdNotFull; + break; + case HostHighCmdQueue: + Notify = HostHighCmdNotFull; + break; + case HostNormRespQueue: + Notify = HostNormRespNotFull; + break; + case HostHighRespQueue: + Notify = HostHighRespNotFull; + break; + } + NotifyAdapter(Adapter, Notify); + } +} + +/*++ + +Routine Description: + Will do all necessary work to complete a FIB that was sent from the adapter. + +Arguments: + Fib is a pointer to the FIB that caller wishes to complete processing on. + Size - Size of the completion Packet(Opitional). If not present than the current + largest size in the Fib will be used + Adapter - Pointer to which adapter sent this FIB + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS CompleteAdapterFib(PFIB_CONTEXT Context, u16 Size) +{ + PCOMM_FIB_CONTEXT fc = Context; + PFIB Fib = fc->Fib; + PAFA_COMM_ADAPTER Adapter = fc->Adapter; + u32 DontInterrupt = FALSE; + + if (Fib->Header.XferState == 0) + return(STATUS_SUCCESS); + + // + // If we plan to do anything check the structure type first. + // + if ( Fib->Header.StructType != TFib ) + { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + + // + // This block handles the case where the adapter had sent us a command and we + // have finished processing the command. We call completeFib when we are done + // processing the command and want to send a response back to the adapter. This + // will send the completed cdb to the adapter. + // + + if (Fib->Header.XferState & SentFromAdapter) + { + Fib->Header.XferState |= HostProcessed; + if (Fib->Header.XferState & HighPriority) + { + QUEUE_INDEX Index; + if (Size) + { + Size += sizeof(FIB_HEADER); + if (Size > Fib->Header.SenderSize) + return(STATUS_BUFFER_OVERFLOW); + Fib->Header.Size = Size; + } + if (GetQueueEntry(Adapter, &Index, AdapHighRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) + { + FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n"); + return(FSA_FATAL); + } + if (InsertQueueEntry(Adapter, Index, AdapHighRespQueue, + (DontInterrupt & (int)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) + { + FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n"); + } + } + else if (Fib->Header.XferState & NormalPriority) + { + QUEUE_INDEX Index; + + if (Size) + { + Size += sizeof(FIB_HEADER); + if (Size > Fib->Header.SenderSize) + return(STATUS_BUFFER_OVERFLOW); + Fib->Header.Size = Size; + } + if (GetQueueEntry(Adapter, &Index, AdapNormRespQueue, Fib, TRUE, NULL, &DontInterrupt) != STATUS_SUCCESS) + { + FsaCommPrint("CompleteFib got an error geting a queue entry for a response.\n"); + return(FSA_FATAL); + } + if (InsertQueueEntry(Adapter, Index, AdapNormRespQueue, + (DontInterrupt & (int)FsaCommData.EnableInterruptModeration)) != STATUS_SUCCESS) + { + FsaCommPrint("CompleteFib failed while inserting entry on the queue.\n"); + } + } + } + else + { + cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n"); + FsaBugCheck(0,0,0); + } + return(STATUS_SUCCESS); +} + +/*++ + +Routine Description: + Will do all necessary work to complete a FIB. If the caller wishes to + reuse the FIB after post processing has been completed Reinitialize + should be called set to TRUE, otherwise the FIB will be returned to the + free FIB pool. If Reinitialize is set to TRUE then the FIB header is + reinitialzied and is ready for reuse on return from this routine. + +Arguments: + Fib is a pointer to the FIB that caller wishes to complete processing on. + Size - Size of the completion Packet(Opitional). If not present than the current + largest size in the Fib will be used + Reinitialize is a boolean which determines if the routine will ready the + completed FIB for reuse(TRUE) or not(FALSE). + +Return Value: + NT_SUCCESS if a Fib was returned to the caller. + NT_ERROR if event was an invalid event. + +--*/ + +AAC_STATUS CompleteFib(PFIB_CONTEXT Context) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + PAFA_COMM_ADAPTER Adapter = fc->Adapter; + PFIB Fib = fc->Fib; + + // + // Check for a fib which has already been completed + // + + // ASSERT(Fib->Header.XferState & AdapterProcessed); + if (Fib->Header.XferState == 0) + return(STATUS_SUCCESS); + + // + // If we plan to do anything check the structure type first. + // + + if ( Fib->Header.StructType != TFib ) { + FsaCommPrint("Error CompleteFib called with a non Fib structure.\n"); + return(STATUS_UNSUCCESSFUL); + } + +#if 0 + //#if FSA_ADAPTER_METER + // + // Meter the completion + // + fsaMeterEnd( // meter the end of an operation + &(Adapter->FibMeter), // .. the meter + IrpContext->FibMeterType, // .. type of operation + &(IrpContext->FibStartTime), // .. ptr to operation start timestamp + FibGetMeterSize(Fib, // .. number of bytes in operation + IrpContext->FibMeterType, + IrpContext->FibSubCommand)); +#endif // FSA_ADAPTER_METER + + // + // This block completes a cdb which orginated on the host and we just need + // to deallocate the cdb or reinit it. At this point the command is complete + // that we had sent to the adapter and this cdb could be reused. + // + + if ( (Fib->Header.XferState & SentFromHost) && + (Fib->Header.XferState & AdapterProcessed)) + { + ASSERT(fc->LogicalFibAddress.LowPart != 0); + return( DeallocateFib(fc) ); + // + // This handles the case when the host has aborted the I/O to the + // adapter because the adapter is not responding + // + + } + else if (Fib->Header.XferState & SentFromHost) + { + ASSERT(fc->LogicalFibAddress.LowPart != 0); + return( DeallocateFib(fc) ); + } + else if (Fib->Header.XferState & HostOwned) + { + return(DeallocateFib(fc)); + } + else + { + cmn_err(CE_WARN, "CompleteFib: Unknown xferstate detected.\n"); + FsaBugCheck(0,0,0); + } + return(STATUS_SUCCESS); +} + +/*++ + +Routine Description: + + This routine handles a driver notify fib from the adapter and dispatches it to + the appropriate routine for handling. + +Arguments: + + Adapter - Which adapter this fib is from + fc - Pointer to FibContext from adapter. + +Return Value: + + Nothing. + +--*/ + +void HandleDriverAif(PAFA_COMM_ADAPTER Adapter, PCOMM_FIB_CONTEXT fc) +{ + PFIB Fib = fc->Fib; + PAFA_CLASS_DRIVER dev; + int Handled = FALSE; + + + // + // First loop through all of the class drivers to give them a chance to handle + // the Fib. + // + + dev = Adapter->ClassDriverList; + while (dev) { + if (dev->HandleAif) { + if (dev->HandleAif( dev->ClassDriverExtension, fc ) ) { + Handled = TRUE; + break; + } + } + dev = dev->Next; + } + + if (!Handled) { + // + // Set the status of this FIB to be Invalid parameter. + // +// *(FSASTATUS *)Fib->data = ST_INVAL; + *(FSASTATUS *)Fib->data = ST_OK; + CompleteAdapterFib(fc, sizeof(FSASTATUS)); + } +} + +/*++ + +Routine Description: + Waits on the commandready event in it's queue. When the event gets set it will + pull FIBs off it's queue. It will continue to pull FIBs off till the queue is empty. + When the queue is empty it will wait for more FIBs. + +Arguments: + Context is used. All data os global + +Return Value: + Nothing. + +--*/ + +int NormCommandThread(PAFA_COMM_ADAPTER Adapter) +{ + PFIB fib, newfib; + COMM_FIB_CONTEXT fc; // for error logging + KIRQL SavedIrql; + PCOMM_REGION comm = Adapter->CommRegion; + PLIST_ENTRY entry; + PGET_ADAPTER_FIB_CONTEXT afc; + + // + // We can only have one thread per adapter for AIF's. + // + + if (Adapter->AifThreadStarted) { + return (EINVAL); + } + + // cmn_err(CE_NOTE, "AIF thread started"); + + // + // Let the DPC know it has a place to send the AIF's to. + // + + Adapter->AifThreadStarted = TRUE; + RtlZeroMemory(&fc, sizeof(COMM_FIB_CONTEXT)); + OsSpinLockAcquire(comm->HostNormCmdQue.QueueLock); + + while (TRUE) { + // + // NOTE : the QueueLock is held at the top of each loop. + // + + ASSERT(OsSpinLockOwned(comm->HostNormCmdQue.QueueLock)); + + while (!IsListEmpty(&(comm->HostNormCmdQue.CommandQueue))) { + PLIST_ENTRY entry; + PAIFCOMMANDTOHOST AifCommandToHost; + + entry = RemoveHeadList(&(comm->HostNormCmdQue.CommandQueue)); + OsSpinLockRelease(comm->HostNormCmdQue.QueueLock); + fib = CONTAINING_RECORD( entry, FIB, Header.FibLinks ); + + // + // We will process the FIB here or pass it to a worker thread that is TBD. We Really + // can't do anything at this point since we don't have anything defined for this thread to + // do. + // + + // cmn_err(CE_NOTE, "Got Fib from the adapter with a NORMAL priority, command 0x%x.\n", fib->Header.Command); + + RtlZeroMemory( &fc, sizeof(COMM_FIB_CONTEXT) ); + fc.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + fc.NodeByteSize = sizeof( COMM_FIB_CONTEXT ); + fc.Fib = fib; + fc.FibData = fib->data; + fc.Adapter = Adapter; + + // + // We only handle AifRequest fibs from the adapter. + // + + ASSERT(fib->Header.Command == AifRequest); + AifCommandToHost = (PAIFCOMMANDTOHOST) fib->data; + if (AifCommandToHost->command == AifCmdDriverNotify) { + HandleDriverAif( Adapter, &fc ); + } else { + OsCvLockAcquire(Adapter->AdapterFibMutex); + entry = Adapter->AdapterFibContextList.Flink; + + // + // For each Context that is on the AdapterFibContextList, make a copy of the + // fib, and then set the event to wake up the thread that is waiting for it. + // + + while (entry != &Adapter->AdapterFibContextList) { + // + // Extract the AdapterFibContext + // + + afc = CONTAINING_RECORD( entry, GET_ADAPTER_FIB_CONTEXT, NextContext ); + + // Warning: sleep possible while holding spinlock + newfib = kmalloc(sizeof(FIB), GFP_KERNEL); + if (newfib) { + // + // Make the copy of the FIB + // + + RtlCopyMemory(newfib, fib, sizeof(FIB)); + + // + // Put the FIB onto the AdapterFibContext's FibList + // + + InsertTailList(&afc->FibList, &newfib->Header.FibLinks); + afc->FibCount++; + + // + // Set the event to wake up the thread that will waiting. + // + OsCv_signal(&afc->UserEvent); + } + entry = entry->Flink; + } + + // + // Set the status of this FIB + // + *(FSASTATUS *)fib->data = ST_OK; + CompleteAdapterFib( &fc, sizeof(FSASTATUS) ); + OsCvLockRelease(Adapter->AdapterFibMutex); + } + OsSpinLockAcquire(comm->HostNormCmdQue.QueueLock); + } + + // + // There are no more AIF's, call cv_wait_sig to wait for more + // to process. + // + + // cmn_err(CE_NOTE, "no more AIF's going to sleep\n"); + + if (OsCv_wait_sig( &(comm->HostNormCmdQue.CommandReady), + comm->HostNormCmdQue.QueueLock ) == 0) { + OsSpinLockRelease(comm->HostNormCmdQue.QueueLock); + Adapter->AifThreadStarted = FALSE; + // cmn_err(CE_NOTE, "AifThread awoken by a signal\n"); + return (EINTR); + } + // cmn_err(CE_NOTE, "^Aif thread awake, going to look for more AIF's\n"); + } +} + + +void *FsaGetFibData(PFIB_CONTEXT Context) +{ + PCOMM_FIB_CONTEXT fc = (PCOMM_FIB_CONTEXT) Context; + return ((void *)fc->Fib->data); +} + + +#ifdef API_THROTTLE + +/*++ + +Routine Description: + + This routine is called as a DPC when a throttle period expires. It + restarts all threads suspended due to the throttling flow control. + + The throttling counted semaphore is signalled for all waiting threads + and the indicator of throttling active is cleared. + +Arguments: + Dpc - Pointer to Dpc structure. Not used. + DefferedContext - Pointer to per-adapter context. This is used to locate the + throttle information for this adapter. + SystemArgument1 - Not used + SystemArgument2 - Not used + +Return Value: + None. + +--*/ + +void ThrottlePeriodEndDpcRtn(PKDPC Dpc, void * DeferredContext, void * SystemArgument1, void * SystemArgument2) +{ + PCOMM_REGION comm; + PAFA_COMM_ADAPTER Adapter = (PAFA_COMM_ADAPTER) DeferredContext; + + comm = Adapter->CommRegion; + + // + // Acquire the spinlock protecting the throttle status. + // + OsSpinLockAcquire(comm->AdapNormCmdQue.QueueLock); + FsaCommPrint("ThrottlePeriodEndDpc\n"); + + // + // Check that the timer has fired as many times as it was set ! + // + + comm->ThrottleTimerFires++; + ASSERT(comm->ThrottleTimerFires == comm->ThrottleTimerSets); + + // + // The throttle period is now over. Restart all threads waiting + // on the throttle being released. + // Clear the throttle active indicator. This will allow new FIBs + // to be sent to the adapter once we release the spinlock on exiting + // the DPC. This means all restarted threads will be runnable + // threads by then. + // + + ASSERT(comm->ThrottleActive == TRUE); // The throttle had better be on ! + comm->ThrottleActive = FALSE; // This allows new data FIBs to go to the adapter on dpc exit + + OsSpinLockRelease(comm->AdapNormCmdQue.QueueLock); +} + +#endif // #ifdef API_THROTTLE + diff --git a/drivers/scsi/aacraid/crapfile b/drivers/scsi/aacraid/crapfile new file mode 100644 index 000000000000..69ccf4c0f8ce --- /dev/null +++ b/drivers/scsi/aacraid/crapfile @@ -0,0 +1,170 @@ +# +# Makefile aacraid Raid Controller +# + +############################################################################### +### SOURCE FILES DEFINES +############################################################################### + +CFILES_DRIVER=\ + ./aachba.c \ + ./aacid.c \ + ./commctrl.c \ + ./comminit.c \ + ./commsup.c \ + ./dpcsup.c \ + ./linit.c \ + ./osddi.c \ + ./osfuncs.c \ + ./ossup.c \ + ./port.c \ + ./rx.c \ + ./sap1sup.c + +IFILES_DRIVER=\ + ./include/AacGenericTypes.h \ + ./include/aac_unix_defs.h \ + ./include/adapter.h \ + ./include/afacomm.h \ + ./include/aifstruc.h \ + ./include/build_number.h \ + ./include/commdata.h \ + ./include/commerr.h \ + ./include/commfibcontext.h \ + ./include/comprocs.h \ + ./include/comproto.h \ + ./include/comstruc.h \ + ./include/comsup.h \ + ./include/fsact.h \ + ./include/fsafs.h \ + ./include/fsaioctl.h \ + ./include/fsaport.h \ + ./include/fsatypes.h \ + ./include/linit.h \ + ./include/monkerapi.h \ + ./include/nodetype.h \ + ./include/nvramioctl.h \ + ./include/osheaders.h \ + ./include/ostypes.h \ + ./include/pcisup.h \ + ./include/perfpack.h \ + ./include/port.h \ + ./include/protocol.h \ + ./include/revision.h \ + ./include/rxcommon.h \ + ./include/rx.h \ + ./include/sap1common.h \ + ./include/sap1.h \ + ./include/version.h + +ALL_SOURCE=\ + ${CFILES_DRIVER} \ + ${IFILES_DRIVER} + +############################################################################### +### OBJECT FILES DEFINES +############################################################################### + + +OFILES_DRIVER=\ + linit.o \ + osfuncs.o \ + osddi.o \ + aachba.o \ + commctrl.o \ + comminit.o \ + commsup.o \ + dpcsup.o \ + ossup.o \ + port.o \ + rx.o \ + sap1sup.o + +TARGET_OFILES= ${OFILES_DRIVER} aacid.o + +############################################################################### +### GENERAL DEFINES +############################################################################### + +# Remember that we're doing a chdir one level lower, so we need an extra ../ +INCS= \ + -I./include \ + -I/usr/src/linux/include -I/usr/src/linux/drivers/scsi + +WARNINGS= -w -Wall -Wno-unused -Wno-switch -Wno-missing-prototypes -Wno-implicit + +COMMON_FLAGS=\ + -D__KERNEL__=1 -DUNIX -DCVLOCK_USE_SPINLOCK -DLINUX \ + -Wall -Wstrict-prototypes \ + ${INCS} \ + ${WARNINGS} \ + -O2 -fomit-frame-pointer + +CFLAGS=${COMMON_FLAGS} ${EXTRA_FLAGS} + +############################################################################### +### DO GENERAL STUFF +############################################################################### + +.SUFFIXES: +.SUFFIXES: .c .o .h .a + +all: source ${TARGET_OFILES} aacraid.o + +source: ${ALL_SOURCE} + +clean: + rm *.o + +############################################################################### +### DRIVER LINKS +############################################################################### + +aacraid.o: source ${TARGET_OFILES} + ld -r -o $@ $(TARGET_OFILES) + cp -r aacraid.o ../ + +############################################################################### +### SIMPLE COMPILES +############################################################################### + +linit.o: ./linit.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o linit.o ./linit.c + +aachba.o: ./aachba.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o aachba.o ./aachba.c + +osddi.o: ./osddi.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o osddi.o ./osddi.c + +osfuncs.o: ./osfuncs.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o osfuncs.o ./osfuncs.c + +commctrl.o: ./commctrl.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o commctrl.o ./commctrl.c + +comminit.o: ./comminit.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o comminit.o ./comminit.c + +commsup.o: ./commsup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o commsup.o ./commsup.c + +dpcsup.o: ./dpcsup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o dpcsup.o ./dpcsup.c + +aacid.o: ./aacid.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o aacid.o ./aacid.c + +port.o: ./port.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o port.o ./port.c + +ossup.o: ./ossup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o ossup.o ./ossup.c + +rx.o: ./rx.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o rx.o ./rx.c + +sap1sup.o: ./sap1sup.c + $(CC) $(COMMON_FLAGS) $(CFLAGS) -c -o sap1sup.o ./sap1sup.c + + diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c new file mode 100644 index 000000000000..93cb393c1cf8 --- /dev/null +++ b/drivers/scsi/aacraid/dpcsup.c @@ -0,0 +1,399 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * dpcsup.c + * + * Abstract: All DPC processing routines for the cyclone board occur here. + * + * + --*/ +#include "comprocs.h" + + +// +// The Bug check file id for this module +// + +#define BugCheckFileId (FSAFS_BUG_CHECK_DPCSUP) +#define Dbg (DEBUG_TRACE_DPCSUP) + +/*++ + +Routine Description: + This DPC routine will be queued when the adapter interrupts us to let us know the queue is + no longer full. The Isr will pass the queue that we will set the not full event. + +Arguments: + Dpc - Pointer to this routine. + Dummy - is a pointer to the comm region which is global so we don't need it anyway + Queue is a pointer to the queue structure we will operate on. + MoreData2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ + +unsigned int CommonNotFullDpc(PCOMM_REGION CommRegion) +{ +#ifdef unix_queue_full + KeSetEvent(&Queue->QueueFull, 0, FALSE); +#endif +} + +int GatherFibTimes = 0; + +// XXX - hack this in until I figure out which header file should contain it. +extern u32 FibGetMeterSize(PFIB pFib, u32 MeterType, char SubCommand); + +/*++ + +Routine Description: + This DPC routine will be queued when the adapter interrupts us to let us know there + is a response on our normal priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + Dpc - Pointer to this routine. + queue is a pointer to the queue structure we will operate on. + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ + +unsigned int HostResponseNormalDpc(PCOMM_QUE queue) +{ + PAFA_COMM_ADAPTER Adapter = queue->Adapter; + PQUEUE_ENTRY entry; + PFIB Fib; + PCOMM_FIB_CONTEXT FibContext; + int consumed = 0; + KIRQL OldIrql; + LARGE_INTEGER ResponseAllocSize; + +#ifdef commdebug + FsaCommPrint("entering the host normal reponse dpc routine.\n"); +#endif + +// cmn_err( CE_CONT, "^HostNormalResponseDpc entered\n"); + + OsSpinLockAcquire(queue->QueueLock); + + // + // Keep pulling response QEs off the response queue and waking + // up the waiters until there are no more QEs. We then return + // back to the system. If no response was requesed we just + // deallocate the Fib here and continue. + // + +loop: + while (GetConsumerEntry(Adapter, queue, &entry)) + { + int IsFastResponse; + IsFastResponse = (int) (entry->FibAddress & 0x01); + Fib = (PFIB) (entry->FibAddress & ~0x01); + FreeConsumerEntry(Adapter, queue, HostNormRespQueue); +#ifdef API_THROTTLE + // + // Throttling support to improve CLI responsiveness under load. + // Check if this FIB was participating in throttle I/O. + // If so, take the spinlock to protect the throttle values + // and count the completion. Then signal the next waiting + // thread. + // + + if ((Fib->Header.Flags & ThrottledFib) != 0) { + PCOMM_REGION CommRegion = Adapter->CommRegion; + FsaCommPrint("NormResponseDpc Throttled FIB Completion - FIB: %x, ThrottledFibs: %d\n", + Fib, CommRegion->ThrottleOutstandingFibs); + + // + // Account for the completion. + // + ASSERT(CommRegion->ThrottleOutstandingFibs > 0); + CommRegion->ThrottleOutstandingFibs--; // One less FIB outstanding + KeReleaseSemaphore(&CommRegion->ThrottleReleaseSema, 0, 1, FALSE); // Release a waiting thread + } // End of throttle code +#endif // #ifdef API_THROTTLE + + FibContext = (PCOMM_FIB_CONTEXT) Fib->Header.SenderData; + ASSERT(FibContext->Fib == Fib); + + // + // Remove this FibContext from the Outstanding I/O queue. + // But only if it has not already been timed out. + // + // If the fib has been timed out already, then just continue. + // The caller has already been notified that the fib timed out. + // + + if (!(FibContext->Flags & FIB_CONTEXT_FLAG_TIMED_OUT)) { + RemoveEntryList(&FibContext->QueueEntry); + Adapter->CommRegion->AdapNormCmdQue.NumOutstandingIos--; + } else { + FsaCommLogEvent(FibContext, + FsaCommData.DeviceObject, + FSAFS_TIMED_OUT_FIB_COMPLETED, + STATUS_UNSUCCESSFUL, BugCheckFileId | __LINE__, FACILITY_FSAFS_ERROR_CODE, NULL, TRUE); + continue; + } + OsSpinLockRelease(queue->QueueLock); + + if (IsFastResponse) { + // + // doctor the fib + // + *(FSASTATUS *) Fib->data = ST_OK; + Fib->Header.XferState |= AdapterProcessed; + } + +#ifdef GATHER_FIB_TIMES + if (GatherFibTimes) { + LARGE_INTEGER FibTime, FibTimeDelta; + LARGE_INTEGER AdapterFibTimeDelta; + PFIB_TIMES FibTimesPtr; + u32 Index; + u32 LowAdapterFibTimeDelta; + + FibTimesPtr = FibContext->FibTimesPtr; + FibTime.QuadPart = KeQueryPerformanceCounter(NULL).QuadPart >> 7; + FibTimeDelta = RtlLargeIntegerSubtract(FibTime, FibContext->FibTimeStamp); + + if (RtlLargeIntegerLessThan(FibTimeDelta, FibTimesPtr->Minimum)) { + FibTimesPtr->Minimum = FibTimeDelta; + } + if (RtlLargeIntegerGreaterThan(FibTimeDelta, FibTimesPtr->Maximum)) { + FibTimesPtr->Maximum = FibTimeDelta; + } + + FibTimesPtr->TotalTime = RtlLargeIntegerAdd(FibTimesPtr->TotalTime, FibTimeDelta); + FibTimesPtr->TotalFibs = RtlLargeIntegerAdd(FibTimesPtr->TotalFibs, RtlConvertLongToLargeInteger(1)); + + if (Fib->Header.ReceiverTimeDone > Fib->Header.ReceiverTimeStart) { + AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone - Fib->Header.ReceiverTimeStart); + } else { + AdapterFibTimeDelta = RtlConvertLongToLargeInteger(Fib->Header.ReceiverTimeDone + + ((u32) (0xffffffff) - Fib->Header.ReceiverTimeStart)); + } + + if (RtlLargeIntegerLessThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMinimum)) { + FibTimesPtr->AdapterMinimum = AdapterFibTimeDelta; + } + if (RtlLargeIntegerGreaterThan(AdapterFibTimeDelta, FibTimesPtr->AdapterMaximum)) { + FibTimesPtr->AdapterMaximum = AdapterFibTimeDelta; + } + + FibTimesPtr->AdapterTotalTime = RtlLargeIntegerAdd(FibTimesPtr->AdapterTotalTime, AdapterFibTimeDelta); + if (GatherFibTimes == 1) { + LowAdapterFibTimeDelta = AdapterFibTimeDelta.LowPart; + } else { + LowAdapterFibTimeDelta = FibTimeDelta.LowPart; + } + + if ((LowAdapterFibTimeDelta & 0xffffff00) == 0) { + Index = (LowAdapterFibTimeDelta & 0xf0) >> 4; + } else if ((LowAdapterFibTimeDelta & 0xfffff000) == 0) { + Index = 16 + ((LowAdapterFibTimeDelta & 0xf00) >> 8); + } else if ((LowAdapterFibTimeDelta & 0xffff0000) == 0) { + Index = 32 + ((LowAdapterFibTimeDelta & 0xf000) >> 12); + } else if ((LowAdapterFibTimeDelta & 0xfff00000) == 0) { + + Index = 48 + ((LowAdapterFibTimeDelta & 0xf0000) >> 16); + } else { + Index = 64; + } + FibTimesPtr->AdapterBuckets[Index]++; + } +#endif + ASSERT((Fib->Header.XferState & (AdapterProcessed | HostOwned | SentFromHost)) == + (AdapterProcessed | HostOwned | SentFromHost)); + + FIB_COUNTER_INCREMENT(FsaCommData.FibRecved); + ASSERT(FsaCommData.FibsSent >= FsaCommData.FibRecved); + + if (Fib->Header.Command == NuFileSystem) { + FSASTATUS *pstatus = (FSASTATUS *) Fib->data; + if (*pstatus & 0xffff0000) { + u32 Hint = *pstatus; + *pstatus = ST_OK; + } + } + if (Fib->Header.XferState & (NoResponseExpected | Async)) { + ASSERT(FibContext->FibCallback); + if (Fib->Header.XferState & NoResponseExpected) + FIB_COUNTER_INCREMENT(FsaCommData.NoResponseRecved); + else + FIB_COUNTER_INCREMENT(FsaCommData.AsyncRecved); + // + // NOTE: we can not touch the FibContext after this call, because it may have been + // deallocated. + // + FibContext->FibCallback(FibContext->FibCallbackContext, FibContext, STATUS_SUCCESS); + } else { + OsCvLockAcquire(FibContext->FsaEventMutex); + FibContext->FibComplete = 1; + OsCv_signal(&FibContext->FsaEvent); + OsCvLockRelease(FibContext->FsaEventMutex); + FIB_COUNTER_INCREMENT(FsaCommData.NormalRecved); + } + consumed++; + OsSpinLockAcquire(queue->QueueLock); + } + if (consumed > FsaCommData.PeakFibsConsumed) + FsaCommData.PeakFibsConsumed = consumed; + if (consumed == 0) + FsaCommData.ZeroFibsConsumed++; + if (FsaCommData.HardInterruptModeration) { + // + // Re-Enable the interrupt from the adapter, then recheck to see if anything has + // been put on the queue. This removes the race condition that exists between the + // last time we checked the queue, and when we re-enabled the interrupt. + // + // If there is something on the queue, then go handle it. + // + EnableInterrupt(Adapter, HostNormRespQue, FALSE); + if (ConsumerEntryAvailable(Adapter, queue)) { + DisableInterrupt(Adapter, HostNormRespQue, FALSE); + goto loop; + } + } +#ifdef commdebug + FsaCommPrint("Exiting host normal reponse dpc routine after consuming %d QE(s).\n", consumed); +#endif + OsSpinLockRelease(queue->QueueLock); +} + +/*++ + +Routine Description: + This DPC routine wiol be queued when the adapter interrupts us to let us know there + is a response on our high priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + Dpc - Pointer to this routine. + queue is a pointer to the queue structure we will operate on. + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ + +unsigned int HostResponseHighDpc(PCOMM_QUE queue) +{ +} + +/*++ + +Routine Description: + This DPC routine will be queued when the adapter interrupts us to let us know there + is a command on our high priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + Dpc - Pointer to this routine. + queue is a pointer to the queue structure we will operate on. + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ + +unsigned int HostCommandHighDpc(PCOMM_QUE queue) +{ +} + + +/*++ + +Routine Description: + This DPC routine will be queued when the adapter interrupts us to let us know there + is a command on our normal priority queue. We will pull off all QE there are and wake + up all the waiters before exiting. We will take a spinlock out on the queue before operating + on it. + +Arguments: + Dpc - Pointer to this routine. + queue is a pointer to the queue structure we will operate on. + MoreData1&2 are DPC parameters we don't need for this function. Maybe we can add some accounting + stuff in here. + +Return Value: + Nothing. + +--*/ + +unsigned int HostCommandNormDpc(PCOMM_QUE queue) +{ + PAFA_COMM_ADAPTER Adapter = queue->Adapter; + PQUEUE_ENTRY entry; + + OsSpinLockAcquire(queue->QueueLock); + + // + // Keep pulling response QEs off the response queue and waking + // up the waiters until there are no more QEs. We then return + // back to the system. + // + + while (GetConsumerEntry(Adapter, queue, &entry)) { + PFIB Fib; + Fib = (PFIB) entry->FibAddress; + + if (Adapter->AifThreadStarted) { +// cmn_err(CE_CONT, "^Received AIF, putting onto command queue\n"); + InsertTailList(&queue->CommandQueue, &Fib->Header.FibLinks); + FreeConsumerEntry(Adapter, queue, HostNormCmdQueue); + OsCv_signal(&queue->CommandReady); + } else { + COMM_FIB_CONTEXT FibContext; + FreeConsumerEntry(Adapter, queue, HostNormCmdQueue); + OsSpinLockRelease(queue->QueueLock); +// cmn_err(CE_CONT, "^Received AIF, thread not started\n"); + RtlZeroMemory(&FibContext, sizeof(COMM_FIB_CONTEXT)); + FibContext.NodeTypeCode = FSAFS_NTC_FIB_CONTEXT; + FibContext.NodeByteSize = sizeof(COMM_FIB_CONTEXT); + FibContext.Fib = Fib; + FibContext.FibData = Fib->data; + FibContext.Adapter = Adapter; + + // + // Set the status of this FIB + // + + *(FSASTATUS *) Fib->data = ST_OK; + CompleteAdapterFib(&FibContext, sizeof(FSASTATUS)); + + OsSpinLockAcquire(queue->QueueLock); + } + } + OsSpinLockRelease(queue->QueueLock); +} diff --git a/drivers/scsi/aacraid/include/AacGenericTypes.h b/drivers/scsi/aacraid/include/AacGenericTypes.h new file mode 100644 index 000000000000..c11fbce0168e --- /dev/null +++ b/drivers/scsi/aacraid/include/AacGenericTypes.h @@ -0,0 +1,54 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * AacGenericTypes.h + * + * Abstract: + * + * The module defines the generic data types that all of the other header files + * depend upon. + --*/ +#ifndef _AAC_GENERIC_TYPES +#define _AAC_GENERIC_TYPES + +typedef s8 AAC_INT8, *PAAC_INT8; +typedef s16 AAC_INT16, *PAAC_INT16; +typedef s32 AAC_INT32, *PAAC_INT32; +typedef s64 AAC_INT64, *PAAC_INT64; + +typedef u8 AAC_UINT8, *PAAC_UINT8; +typedef u16 AAC_UINT16, *PAAC_UINT16; +typedef u32 AAC_UINT32, *PAAC_UINT32; +typedef u64 AAC_UINT64, *PAAC_UINT64; + +typedef void AAC_VOID, *PAAC_VOID; + +// +// this compiler uses 32 bit enum data types +// + +#define AAC_32BIT_ENUMS 1 +#define FAILURE 1 +#define INTR_UNCLAIMED 1 +#define INTR_CLAIMED 0 + +#endif // _AAC_GENERIC_TYPES + diff --git a/drivers/scsi/aacraid/include/aac_unix_defs.h b/drivers/scsi/aacraid/include/aac_unix_defs.h new file mode 100644 index 000000000000..dbed280260a1 --- /dev/null +++ b/drivers/scsi/aacraid/include/aac_unix_defs.h @@ -0,0 +1,282 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * aac_unix_defs.h + * + * Abstract: + * + * Macro definition and typedefs + * + --*/ + +#ifndef _AAC_UNIX_DEFS +#define _AAC_UNIX_DEFS + +#define AAC_MAX_ADAPTERS 64 + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef unsigned long AAC_STATUS, *PNT_STATUS; + +typedef struct { + unsigned long LowPart; + unsigned long HighPart; +} LARGE_INTEGER; + +typedef LARGE_INTEGER PHYSICAL_ADDRESS; + + +typedef struct _AFA_IOCTL_CMD { + int cmd; + intptr_t arg; + int flag; + cred_t *cred_p; + int *rval_p; +} AFA_IOCTL_CMD, *PAFA_IOCTL_CMD; + + +// +// Singly linked list structure. Can be used as either a list head, or +// as link words. +// + +typedef struct _SINGLE_LIST_ENTRY { + struct _SINGLE_LIST_ENTRY *Next; +} SINGLE_LIST_ENTRY, *PSINGLE_LIST_ENTRY; + + +// +// Calculate the address of the base of the structure given its type, and an +// address of a field within the structure. +// + +#define CONTAINING_RECORD(address, type, field) ((type *)( \ + (char *)(address) - \ + (char *)(&((type *)0)->field))) + +typedef void * PMDL; +typedef void * PDEVICE_OBJECT; +typedef void * PADAPTER_OBJECT; +typedef u32 KIRQL; +typedef void * HANDLE; +typedef void * KDPC, *PKDPC; +typedef void * PFILE_OBJECT; +typedef void * PIRP; +typedef void * PDRIVER_OBJECT; +typedef u32 KTIMER; + + +#define STATUS_SUCCESS 0x00000000 +#define STATUS_PENDING 0x40000001 +#define STATUS_IO_TIMEOUT 0xc0000001 +#define STATUS_UNSUCCESSFUL 0xc0000002 +#define STATUS_INSUFFICIENT_RESOURCES 0xc0000005 +#define STATUS_BUFFER_OVERFLOW 0xc0000003 + + +#define OUT + + + +typedef u_int (*PUNIX_INTR_HANDLER)(caddr_t Arg); + +// +// Zone Allocation +// + +typedef struct _ZONE_SEGMENT_HEADER { + SINGLE_LIST_ENTRY SegmentList; + void * Reserved; +} ZONE_SEGMENT_HEADER, *PZONE_SEGMENT_HEADER; + +typedef struct _ZONE_HEADER { + SINGLE_LIST_ENTRY FreeList; + SINGLE_LIST_ENTRY SegmentList; + u32 BlockSize; + u32 TotalSegmentSize; +} ZONE_HEADER, *PZONE_HEADER; + + +//++ +// +// void * +// ExAllocateFromZone( +// PZONE_HEADER Zone +// ) +// +// Routine Description: +// +// This routine removes an entry from the zone and returns a pointer to it. +// +// Arguments: +// +// Zone - Pointer to the zone header controlling the storage from which the +// entry is to be allocated. +// +// Return Value: +// +// The function value is a pointer to the storage allocated from the zone. +// +//-- + +#define ExAllocateFromZone(Zone) \ + (void *)((Zone)->FreeList.Next); \ + if ( (Zone)->FreeList.Next ) (Zone)->FreeList.Next = (Zone)->FreeList.Next->Next + +//++ +// +// void * +// ExFreeToZone( +// PZONE_HEADER Zone, +// void * Block +// ) +// +// Routine Description: +// +// This routine places the specified block of storage back onto the free +// list in the specified zone. +// +// Arguments: +// +// Zone - Pointer to the zone header controlling the storage to which the +// entry is to be inserted. +// +// Block - Pointer to the block of storage to be freed back to the zone. +// +// Return Value: +// +// Pointer to previous block of storage that was at the head of the free +// list. NULL implies the zone went from no available free blocks to +// at least one free block. +// +//-- + +#define ExFreeToZone(Zone,Block) \ + ( ((PSINGLE_LIST_ENTRY)(Block))->Next = (Zone)->FreeList.Next, \ + (Zone)->FreeList.Next = ((PSINGLE_LIST_ENTRY)(Block)), \ + ((PSINGLE_LIST_ENTRY)(Block))->Next \ + ) + +//++ +// +// BOOLEAN +// ExIsFullZone( +// PZONE_HEADER Zone +// ) +// +// Routine Description: +// +// This routine determines if the specified zone is full or not. A zone +// is considered full if the free list is empty. +// +// Arguments: +// +// Zone - Pointer to the zone header to be tested. +// +// Return Value: +// +// TRUE if the zone is full and FALSE otherwise. +// +//-- + +#define ExIsFullZone(Zone) \ + ( (Zone)->FreeList.Next == (PSINGLE_LIST_ENTRY)NULL ) + + +#define RtlCopyMemory( Destination, Source, Size ) bcopy( (Source), (Destination), (Size) ) +#define RtlZeroMemory( Destination, Size ) bzero( (Destination), (Size) ) + +// +// Doubly-linked list manipulation routines. Implemented as macros +// but logically these are procedures. +// + +// +// VOID +// InitializeListHead( +// PLIST_ENTRY ListHead +// ); +// + +#define InitializeListHead(ListHead) (\ + (ListHead)->Flink = (ListHead)->Blink = (ListHead)) + +// +// BOOLEAN +// IsListEmpty( +// PLIST_ENTRY ListHead +// ); +// + +#define IsListEmpty(ListHead) \ + ((ListHead)->Flink == (ListHead)) + +// +// PLIST_ENTRY +// RemoveHeadList( +// PLIST_ENTRY ListHead +// ); +// + +#define RemoveHeadList(ListHead) \ + (ListHead)->Flink;\ + {RemoveEntryList((ListHead)->Flink)} + + +// +// VOID +// RemoveEntryList( +// PLIST_ENTRY Entry +// ); +// + +#define RemoveEntryList(Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_Flink;\ + _EX_Flink = (Entry)->Flink;\ + _EX_Blink = (Entry)->Blink;\ + _EX_Blink->Flink = _EX_Flink;\ + _EX_Flink->Blink = _EX_Blink;\ + } + +// +// VOID +// InsertTailList( +// PLIST_ENTRY ListHead, +// PLIST_ENTRY Entry +// ); +// + +#define InsertTailList(ListHead,Entry) {\ + PLIST_ENTRY _EX_Blink;\ + PLIST_ENTRY _EX_ListHead;\ + _EX_ListHead = (ListHead);\ + _EX_Blink = _EX_ListHead->Blink;\ + (Entry)->Flink = _EX_ListHead;\ + (Entry)->Blink = _EX_Blink;\ + _EX_Blink->Flink = (Entry);\ + _EX_ListHead->Blink = (Entry);\ + } + +#endif /* AAC_UNIX_DEFS */ diff --git a/drivers/scsi/aacraid/include/adapter.h b/drivers/scsi/aacraid/include/adapter.h new file mode 100644 index 000000000000..d20a8b17f88f --- /dev/null +++ b/drivers/scsi/aacraid/include/adapter.h @@ -0,0 +1,170 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * + * Adapter.h + * + * Abstract: + * The module contains the definitions for a comm layer view of the adapter. + * + * + * + --*/ + +#ifndef _ADAPTER_ +#define _ADAPTER_ + + +typedef struct _GET_ADAPTER_FIB_CONTEXT { + NODE_TYPE_CODE NodeTypeCode; // used for verification of structure + NODE_BYTE_SIZE NodeByteSize; + PFILE_OBJECT FileObject; // used for cleanup + LIST_ENTRY NextContext; // used to link context's into a linked list + OS_CV_T UserEvent; // this is used to wait for the next fib to arrive. + int WaitingForFib; // Set to true when thread is in WaitForSingleObject + u32 FibCount; // total number of FIBs on FibList + LIST_ENTRY FibList; +} GET_ADAPTER_FIB_CONTEXT; +typedef GET_ADAPTER_FIB_CONTEXT *PGET_ADAPTER_FIB_CONTEXT; + + +typedef struct _FIB_CONTEXT_ZONE_SEGMENT { + struct _FIB_CONTEXT_ZONE_SEGMENT *Next; + u32 FibContextSegmentSize; + void * FibContextSegment; + u32 ExtendSize; + MAPFIB_CONTEXT MapFibContext; +} FIB_CONTEXT_ZONE_SEGMENT; +typedef FIB_CONTEXT_ZONE_SEGMENT *PFIB_CONTEXT_ZONE_SEGMENT; + +typedef struct _AFA_COMM_ADAPTER { + struct _AFA_COMM_ADAPTER *NextAdapter; + // + // The following fields are used to allocate FIB context structures + // using the zone allocator, and other fixed sized structures from a + // small cache. The mutex protects access to the zone/lists + // + + ZONE_HEADER FibContextZone; + OS_SPINLOCK *FibContextZoneSpinLock; + int FibContextZoneExtendSize; + + PFIB_CONTEXT_ZONE_SEGMENT FibContextSegmentList; + + void * FibContextTimedOutList; + + PFIB SyncFib; + u32 SyncFibPhysicalAddress; + + PCOMM_REGION CommRegion; + + OS_SPINLOCK_COOKIE SpinLockCookie; + +// UNICODE_STRING TimeoutString; + +#ifdef GATHER_FIB_TIMES + // + // The following contains detailed timings of round trip to the adapter + // depending on which Fib type + // + + PALL_FIB_TIMES FibTimes; + LARGE_INTEGER FibTimesFrequency; +#endif + + // + // The user API will use an IOCTL to register itself to receive FIBs + // from the adapter. The following list is used to keep track of all + // the threads that have requested these FIBs. The mutex is used to + // synchronize access to all data associated with the adapter fibs. + // + LIST_ENTRY AdapterFibContextList; + OS_CVLOCK *AdapterFibMutex; + + // + // The following holds which FileObject is allow to send configuration + // commands to the adapter that would modify the configuration. + // + // This is controlled by the FSACTL_OPEN_ADAPTER_CONFIG and FSACTL_CLOSE_ADAPTER_CONFIG + // ioctls. + // + PFILE_OBJECT AdapterConfigFileObject; + + // + // The following is really here because of the simulator + // + int InterruptsBelowDpc; + + // + // The following is the device specific extension. + // + void * AdapterExtension; + PFSAPORT_FUNCS AdapterFuncs; + void *Dip; + + // + // The following are user variables that are specific to the mini port. + // + PFSA_USER_VAR AdapterUserVars; + u32 AdapterUserVarsSize; + + // + // The following is the number of the individual adapter..i.e. \Device\Afa0 + // + s32 AdapterNumber; + + AFACOMM_FUNCS CommFuncs; + + PAFA_CLASS_DRIVER ClassDriverList; + + int AifThreadStarted; + +} AFA_COMM_ADAPTER; + +typedef AFA_COMM_ADAPTER *PAFA_COMM_ADAPTER; + + +#define FsaAllocateAdapterCommArea(Adapter, BaseAddress, Size, Alignment) \ + Adapter->AdapterFuncs->AllocateAdapterCommArea(Adapter->AdapterExtension, BaseAddress, Size, Alignment) + +#define FsaFreeAdapterCommArea(Adapter) \ + Adapter->AdapterFuncs->FreeAdapterCommArea(Adapter->AdapterExtension) + + +#define AllocateAndMapFibSpace(Adapter, MapFibContext) \ + Adapter->AdapterFuncs->AllocateAndMapFibSpace(Adapter->AdapterExtension, MapFibContext) + +#define UnmapAndFreeFibSpace(Adapter, MapFibContext) \ + Adapter->AdapterFuncs->UnmapAndFreeFibSpace(Adapter->AdapterExtension, MapFibContext) + +#define InterruptAdapter(Adapter) \ + Adapter->AdapterFuncs->InterruptAdapter(Adapter->AdapterExtension) + +#define NotifyAdapter(Adapter, AdapterEvent) \ + Adapter->AdapterFuncs->NotifyAdapter(Adapter->AdapterExtension, AdapterEvent) + +#define EnableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \ + Adapter->AdapterFuncs->EnableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq) + +#define DisableInterrupt(Adapter, AdapterEvent, AtDeviceIrq) \ + Adapter->AdapterFuncs->DisableInterrupt(Adapter->AdapterExtension, AdapterEvent, AtDeviceIrq) + + +#endif // _ADAPTER_ diff --git a/drivers/scsi/aacraid/include/afacomm.h b/drivers/scsi/aacraid/include/afacomm.h new file mode 100644 index 000000000000..eb3d2e4478ff --- /dev/null +++ b/drivers/scsi/aacraid/include/afacomm.h @@ -0,0 +1,104 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * AfaComm.h + * + * Abstract: + * This module defines all of the external interfaces to the AFA comm layer. + * + * + * + --*/ +#ifndef _AFACOMM_ +#define _AFACOMM_ + +#include "fsaport.h" + +typedef void *PFIB_CONTEXT; + +typedef void (*PFIB_CALLBACK)(void * FibCallbackContext, PFIB_CONTEXT FibContext, AAC_STATUS Status); +typedef PFIB_CONTEXT (*PAFA_COMM_ALLOCATE_FIB) (void * AdapterExtension); +typedef void (*PAFA_COMM_FREE_FIB) (PFIB_CONTEXT FibContext); +typedef AAC_STATUS(*PAFA_COMM_DEALLOCATE_FIB) (PFIB_CONTEXT FibContext); +typedef void(*PAFA_COMM_FREE_FIB_FROM_DPC) (PFIB_CONTEXT FibContext); +typedef AAC_STATUS(*PAFA_COMM_INITIALIZE_FIB) (PFIB_CONTEXT FibContext); +typedef void *(*PAFA_COMM_GET_FIB_DATA) (PFIB_CONTEXT FibContext); +typedef AAC_STATUS(*PAFA_COMM_SEND_FIB) (FIB_COMMAND Command, PFIB_CONTEXT FibContext, u32 Size, COMM_PRIORITIES Priority, int Wait, void * WaitOn, int ResponseExpected, PFIB_CALLBACK FibCallback, void * FibCallbackContext); +typedef AAC_STATUS(*PAFA_COMM_COMPLETE_FIB) (PFIB_CONTEXT FibContext); +typedef AAC_STATUS(*PAFA_COMM_COMPLETE_ADAPTER_FIB) (PFIB_CONTEXT FibContext, u16 Size); +typedef int (*PAFA_COMM_SEND_SYNCH_FIB) (void * AdapterExtension, FIB_COMMAND Command, void * Data, u16 Size, void * Response, u16 *ResponseSize); + +typedef struct _AFACOMM_FUNCS +{ + u32 SizeOfAfaCommFuncs; + PAFA_COMM_ALLOCATE_FIB AllocateFib; + PAFA_COMM_FREE_FIB FreeFib; + PAFA_COMM_FREE_FIB_FROM_DPC FreeFibFromDpc; + PAFA_COMM_DEALLOCATE_FIB DeallocateFib; + PAFA_COMM_INITIALIZE_FIB InitializeFib; + PAFA_COMM_GET_FIB_DATA GetFibData; + PAFA_COMM_SEND_FIB SendFib; + PAFA_COMM_COMPLETE_FIB CompleteFib; + PAFA_COMM_COMPLETE_ADAPTER_FIB CompleteAdapterFib; + PAFA_COMM_SEND_SYNCH_FIB SendSynchFib; + PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress; +} AFACOMM_FUNCS; +typedef AFACOMM_FUNCS *PAFACOMM_FUNCS; + + +typedef AAC_STATUS(*PAFA_CLASS_OPEN_ADAPTER) (void * Adapter); +typedef AAC_STATUS(*PAFA_CLASS_CLOSE_ADAPTER) (void * Adapter); +typedef int(*PAFA_CLASS_DEV_CONTROL) (void * Adapter, PAFA_IOCTL_CMD IoctlCmdPtr, int * Status); +typedef int(*PAFA_CLASS_HANDLE_AIF) (void * Adapter, PFIB_CONTEXT FibContext); + +typedef struct _AFA_NEW_CLASS_DRIVER { + void * ClassDriverExtension; + PAFA_CLASS_OPEN_ADAPTER OpenAdapter; + PAFA_CLASS_CLOSE_ADAPTER CloseAdapter; + PAFA_CLASS_DEV_CONTROL DeviceControl; + PAFA_CLASS_HANDLE_AIF HandleAif; + PFSA_USER_VAR UserVars; + u32 NumUserVars; +} AFA_NEW_CLASS_DRIVER; +typedef AFA_NEW_CLASS_DRIVER *PAFA_NEW_CLASS_DRIVER; + + +typedef struct _AFA_NEW_CLASS_DRIVER_RESPONSE { + PAFACOMM_FUNCS CommFuncs; + void * CommPortExtension; + void * MiniPortExtension; + OS_SPINLOCK_COOKIE SpinLockCookie; + void *Dip; +} AFA_NEW_CLASS_DRIVER_RESPONSE; +typedef AFA_NEW_CLASS_DRIVER_RESPONSE *PAFA_NEW_CLASS_DRIVER_RESPONSE; + + +typedef struct _AFA_CLASS_DRIVER { + struct _AFA_CLASS_DRIVER *Next; + void * ClassDriverExtension; + PAFA_CLASS_OPEN_ADAPTER OpenAdapter; + PAFA_CLASS_CLOSE_ADAPTER CloseAdapter; + PAFA_CLASS_DEV_CONTROL DeviceControl; + PAFA_CLASS_HANDLE_AIF HandleAif; +} AFA_CLASS_DRIVER; +typedef AFA_CLASS_DRIVER *PAFA_CLASS_DRIVER; + + +#endif // _AFACOMM_ diff --git a/drivers/scsi/aacraid/include/aifstruc.h b/drivers/scsi/aacraid/include/aifstruc.h new file mode 100644 index 000000000000..af369142f658 --- /dev/null +++ b/drivers/scsi/aacraid/include/aifstruc.h @@ -0,0 +1,315 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * Aifstruc.h + * + * Abstract: + * Define all shared data types relating to + * the set of features utilizing Adapter + * Initiated Fibs. + * + * + * + --*/ +#ifndef _AIFSTRUC_H +#define _AIFSTRUC_H + +#include + +// +// Progress report structure definitions +// +typedef enum { + AifJobStsSuccess = 1, + AifJobStsFinished, + AifJobStsAborted, + AifJobStsFailed, + AifJobStsLastReportMarker = 100, // All before mean last report + AifJobStsSuspended, + AifJobStsRunning +} _E_AifJobStatus; + +#ifdef AAC_32BIT_ENUMS +typedef _E_AifJobStatus AifJobStatus; +#else +typedef AAC_UINT32 AifJobStatus; +#endif + + +typedef enum { + AifJobScsiMin = 1, // Minimum value for Scsi operation + AifJobScsiZero, // SCSI device clear operation + AifJobScsiVerify, // SCSI device Verify operation NO REPAIR + AifJobScsiExercise, // SCSI device Exercise operation + AifJobScsiVerifyRepair, // SCSI device Verify operation WITH repair + // Add new SCSI task types above this line + AifJobScsiMax = 99, // Max Scsi value + AifJobCtrMin, // Min Ctr op value + AifJobCtrZero, // Container clear operation + AifJobCtrCopy, // Container copy operation + AifJobCtrCreateMirror, // Container Create Mirror operation + AifJobCtrMergeMirror, // Container Merge Mirror operation + AifJobCtrScrubMirror, // Container Scrub Mirror operation + AifJobCtrRebuildRaid5, // Container Rebuild Raid5 operation + AifJobCtrScrubRaid5, // Container Scrub Raid5 operation + AifJobCtrMorph, // Container morph operation + AifJobCtrPartCopy, // Container Partition copy operation + AifJobCtrRebuildMirror, // Container Rebuild Mirror operation + AifJobCtrCrazyCache, // crazy cache + // Add new container task types above this line + AifJobCtrMax = 199, // Max Ctr type operation + AifJobFsMin, // Min Fs type operation + AifJobFsCreate, // File System Create operation + AifJobFsVerify, // File System Verify operation + AifJobFsExtend, // File System Extend operation + // Add new file system task types above this line + AifJobFsMax = 299, // Max Fs type operation + // Add new API task types here + AifJobApiFormatNTFS, // Format a drive to NTFS + AifJobApiFormatFAT, // Format a drive to FAT + AifJobApiUpdateSnapshot, // update the read/write half of a snapshot + AifJobApiFormatFAT32, // Format a drive to FAT32 + AifJobApiMax = 399, // Max API type operation + AifJobCtlContinuousCtrVerify, // Controller operation + AifJobCtlMax = 499 // Max Controller type operation +} _E_AifJobType; + +#ifdef AAC_32BIT_ENUMS +typedef _E_AifJobType AifJobType; +#else +typedef AAC_UINT32 AifJobType; +#endif + +union SrcContainer { + AAC_UINT32 from; + AAC_UINT32 master; + AAC_UINT32 container; +}; + +union DstContainer { + AAC_UINT32 to; + AAC_UINT32 slave; + AAC_UINT32 container; +}; + + +struct AifContainers { + union SrcContainer src; + union DstContainer dst; +}; + +union AifJobClient { + + struct AifContainers container; // For Container nd file system progress ops; + AAC_INT32 scsi_dh; // For SCSI progress ops +}; + +struct AifJobDesc { + AAC_UINT32 jobID; // DO NOT FILL IN! Will be filled in by AIF + AifJobType type; // Operation that is being performed + union AifJobClient client; // Details +}; + +struct AifJobProgressReport { + struct AifJobDesc jd; + AifJobStatus status; + AAC_UINT32 finalTick; + AAC_UINT32 currentTick; + AAC_UINT32 jobSpecificData1; + AAC_UINT32 jobSpecificData2; +}; + +// +// Notification of events structure definition starts here +// +typedef enum { + // General application notifies start here + AifEnGeneric = 1, // Generic notification + AifEnTaskComplete, // Task has completed + AifEnConfigChange, // Adapter configuration change occurred + AifEnContainerChange, // Adapter specific container configuration change + AifEnDeviceFailure, // SCSI device failed + AifEnMirrorFailover, // Mirror failover started + AifEnContainerEvent, // Significant container event + AifEnFileSystemChange, // File system changed + AifEnConfigPause, // Container pause event + AifEnConfigResume, // Container resume event + AifEnFailoverChange, // Failover space assignment changed + AifEnRAID5RebuildDone, // RAID5 rebuild finished + AifEnEnclosureManagement, // Enclosure management event + AifEnBatteryEvent, // Significant NV battery event + AifEnAddContainer, // A new container was created. + AifEnDeleteContainer, // A container was deleted. + AifEnSMARTEvent, // SMART Event + AifEnBatteryNeedsRecond, // The battery needs reconditioning + AifEnClusterEvent, // Some cluster event + AifEnDiskSetEvent, // A disk set event occured. + // Add general application notifies above this comment + AifDriverNotifyStart=199, // Notifies for host driver go here + // Host driver notifications start here + AifDenMorphComplete, // A morph operation completed + AifDenVolumeExtendComplete // A volume expand operation completed + // Add host driver notifications above this comment +} _E_AifEventNotifyType; + +#ifdef AAC_32BIT_ENUMS +typedef _E_AifEventNotifyType AifEventNotifyType; +#else +typedef AAC_UINT32 AifEventNotifyType; +#endif + +struct AifEnsGeneric { + AAC_INT8 text[132]; // Generic text +}; + +struct AifEnsDeviceFailure { + AAC_INT32 deviceHandle; // SCSI device handle +}; + +struct AifEnsMirrorFailover { + AAC_UINT32 container; // Container with failed element + AAC_UINT32 failedSlice; // Old slice which failed + AAC_UINT32 creatingSlice; // New slice used for auto-create +}; + +struct AifEnsContainerChange { + AAC_UINT32 container[2]; // container that changed, -1 if no container +}; + +struct AifEnsContainerEvent { + AAC_UINT32 container; // container number + AAC_UINT32 eventType; // event type +}; + +struct AifEnsEnclosureEvent { + AAC_UINT32 empID; // enclosure management processor number + AAC_UINT32 unitID; // unitId, fan id, power supply id, slot id, tempsensor id. + AAC_UINT32 eventType; // event type +}; + + +struct AifEnsBatteryEvent { + NVBATT_TRANSITION transition_type; // e.g. from low to ok + NVBATTSTATUS current_state; // current battery state + NVBATTSTATUS prior_state; // previous battery state +}; + +struct AifEnsDiskSetEvent { + AAC_UINT32 eventType; + AAC_UINT32 DsNum[2]; + AAC_UINT32 CreatorId[2]; +}; + + + +typedef enum _CLUSTER_AIF_EVENT { + CLUSTER_NULL_EVENT = 0, + CLUSTER_PARTNER_NAME_EVENT, // change in partner hostname or adaptername from NULL to non-NULL + // (partner's agent may be up) + CLUSTER_PARTNER_NULL_NAME_EVENT // change in partner hostname or adaptername from non-null to NULL + // (partner has rebooted) +} _E_CLUSTER_AIF_EVENT; + +#ifdef AAC_32BIT_ENUMS +typedef _E_CLUSTER_AIF_EVENT CLUSTER_AIF_EVENT; +#else +typedef AAC_UINT32 CLUSTER_AIF_EVENT; +#endif + +struct AifEnsClusterEvent { + CLUSTER_AIF_EVENT eventType; +}; + +struct AifEventNotify { + AifEventNotifyType type; + union { + struct AifEnsGeneric EG; + struct AifEnsDeviceFailure EDF; + struct AifEnsMirrorFailover EMF; + struct AifEnsContainerChange ECC; + struct AifEnsContainerEvent ECE; + struct AifEnsEnclosureEvent EEE; + struct AifEnsBatteryEvent EBE; + struct AifEnsDiskSetEvent EDS; +#ifdef BRIDGE + struct AifEnsSMARTEvent ES; +#endif + struct AifEnsClusterEvent ECLE; + } data; +}; + +// +// Generic API structure +// +#define AIF_API_REPORT_MAX_SIZE 64 +typedef AAC_INT8 AifApiReport[AIF_API_REPORT_MAX_SIZE]; + +// +// For FIB communication, we need all of the following things +// to send back to the user. +// + +typedef enum { + AifCmdEventNotify = 1, // Notify of event + AifCmdJobProgress, // Progress report + AifCmdAPIReport, // Report from other user of API + AifCmdDriverNotify, // Notify host driver of event + AifReqJobList = 100, // Gets back complete job list + AifReqJobsForCtr, // Gets back jobs for specific container + AifReqJobsForScsi, // Gets back jobs for specific SCSI device + AifReqJobReport, // Gets back a specific job report or list of them + AifReqTerminateJob, // Terminates job + AifReqSuspendJob, // Suspends a job + AifReqResumeJob, // Resumes a job + AifReqSendAPIReport, // API generic report requests + AifReqAPIJobStart, // Start a job from the API + AifReqAPIJobUpdate, // Update a job report from the API + AifReqAPIJobFinish // Finish a job from the API +} _E_AIFCOMMAND; + +#ifdef AAC_32BIT_ENUMS +typedef _E_AIFCOMMAND AIFCOMMAND; +#else +typedef AAC_UINT32 AIFCOMMAND; +#endif + + + +// +// Adapter Initiated FIB command structures. Start with the adapter +// initiated FIBs that really come from the adapter, and get responded +// to by the host. +// +typedef struct _AIFCOMMANDTOHOST { + AIFCOMMAND command; // Tell host what type of notify this is + AAC_UINT32 seqNumber; // To allow ordering of reports (if necessary) + union { + // First define data going to the adapter + struct AifEventNotify EN; // Event notify structure + struct AifJobProgressReport PR[1]; // Progress report + AifApiReport AR; + } data; +} AIFCOMMANDTOHOST, *PAIFCOMMANDTOHOST; + + +#endif // _AIFSTRUC_H + + + diff --git a/drivers/scsi/aacraid/include/build_number.h b/drivers/scsi/aacraid/include/build_number.h new file mode 100644 index 000000000000..ea423631aaec --- /dev/null +++ b/drivers/scsi/aacraid/include/build_number.h @@ -0,0 +1,36 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * build_number.h + * + * Abstract: + * DThis module contains the single location where the build number + * is kept. + * + * + * + --*/ +#ifndef _BUILD_NUMBER_H +#define _BUILD_NUMBER_H + +#define REV_BUILD_NUMBER 3911 + +#endif // _BUILD_NUMBER_H + diff --git a/drivers/scsi/aacraid/include/commdata.h b/drivers/scsi/aacraid/include/commdata.h new file mode 100644 index 000000000000..a03761d4d971 --- /dev/null +++ b/drivers/scsi/aacraid/include/commdata.h @@ -0,0 +1,104 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commdata.h + * + * Abstract: Define the communication layer of the adapter + * + * + * + --*/ +#ifndef _COMMDATA_ +#define _COMMDATA_ + +typedef struct _FSA_COMM_DATA { + // + // A pointer to the Driver and Device object we were initialized with + // + + PDRIVER_OBJECT DriverObject; + PDEVICE_OBJECT DeviceObject; + + // + // A list of all adapters we have configured. + // + + PAFA_COMM_ADAPTER AdapterList; + u32 TotalAdapters; + + // + // Adapter timeout support. This is the default timeout to wait for the + // adapter to respond(setup in initfs.c), and a boolean to indicate if + // we should timeout requests to the adapter or not. + // + + LARGE_INTEGER QueueFreeTimeout; + LARGE_INTEGER AdapterTimeout; + int EnableAdapterTimeouts; + + u32 FibTimeoutIncrement; + + u32 FibsSent; + u32 FibRecved; + u32 NoResponseSent; + u32 NoResponseRecved; + u32 AsyncSent; + u32 AsyncRecved; + u32 NormalSent; + u32 NormalRecved; + + u32 TimedOutFibs; + + KDPC TimeoutDPC; + KTIMER TimeoutTimer; + + // + // If this value is set to 1 then interrupt moderation will occur + // in the base commuication support. + // + + u32 EnableInterruptModeration; + + int HardInterruptModeration; + int HardInterruptModeration1; + int PeakFibsConsumed; + int ZeroFibsConsumed; + int EnableFibTimeoutBreak; + u32 FibTimeoutSeconds; + + // + // The following holds all of the available user settable variables. + // This includes all for the comm layer as well as any from the class + // drivers as well. + // + + FSA_USER_VAR *UserVars; + u32 NumUserVars; + u32 MeterFlag; +#ifdef FIB_CHECKSUMS + int do_fib_checksums; +#endif +} FSA_COMM_DATA; + +typedef FSA_COMM_DATA *PFSA_COMM_DATA; +extern FSA_COMM_DATA FsaCommData; + +#endif // _COMMDATA_ + diff --git a/drivers/scsi/aacraid/include/commerr.h b/drivers/scsi/aacraid/include/commerr.h new file mode 100644 index 000000000000..17b0d64ba636 --- /dev/null +++ b/drivers/scsi/aacraid/include/commerr.h @@ -0,0 +1,122 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commerr.h + * + * Abstract: This file defines all errors that are unique to the Adaptec Fsa Filesystem + * + * + * + --*/ + +#ifndef _FSAERR_ +#define _FSAERR_ +// +// Note: comments in the .mc file must use both ";" and "//". +// +// Status values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-------------------------+-------------------------------+ +// |Sev|C| Facility | Code | +// +---+-+-------------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// Facility - is the facility code +// +// Code - is the facility's status code +// + + +// +// %1 is reserved by the IO Manager. If IoAllocateErrorLogEntry is +// called with a device, the name of the device will be inserted into +// the message at %1. Otherwise, the place of %1 will be left empty. +// In either case, the insertion strings from the driver's error log +// entry starts at %2. In other words, the first insertion string goes +// to %2, the second to %3 and so on. +// + +// +// Values are 32 bit values layed out as follows: +// +// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 +// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 +// +---+-+-+-----------------------+-------------------------------+ +// |Sev|C|R| Facility | Code | +// +---+-+-+-----------------------+-------------------------------+ +// +// where +// +// Sev - is the severity code +// +// 00 - Success +// 01 - Informational +// 10 - Warning +// 11 - Error +// +// C - is the Customer code flag +// +// R - is a reserved bit +// +// Facility - is the facility code +// +// Code - is the facility's status code +// +// +// Define the facility codes +// + + +#define FACILITY_FSAFS_ERROR_CODE 0x7 + + + +// +// MessageId: FSAFS_FIB_INVALID +// +// MessageText: +// +// A communication packet was detected to be formatted poorly. Please Contact Adaptec support. +// +#define FSAFS_FIB_INVALID ((AAC_STATUS)0xE0070009L) + + +// +// MessageId: FSAFS_TIMED_OUT_FIB_COMPLETED +// +// MessageText: +// +// A Fib previously timed out by host has been completed by the adapter. (\\.\Afa%2) +// +#define FSAFS_TIMED_OUT_FIB_COMPLETED ((AAC_STATUS)0xA007000EL) + +#endif _FSAERR_ diff --git a/drivers/scsi/aacraid/include/commfibcontext.h b/drivers/scsi/aacraid/include/commfibcontext.h new file mode 100644 index 000000000000..60a3e60dc1b7 --- /dev/null +++ b/drivers/scsi/aacraid/include/commfibcontext.h @@ -0,0 +1,93 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * commfibcontext.h + * + * Abstract: defines the _COMM_FIB_CONTEXT strcuture + * + * + * + --*/ +#ifndef _COMM_FIB_CONTEXT_ +#define _COMM_FIB_CONTEXT_ + +typedef struct _COMM_FIB_CONTEXT { + void * Next; // this is used by the zone allocation + + // + // Type and size of this record (must be FSA_NTC_FIB_CONTEXT) + // + // NOTE: THIS STRUCTURE MUST REMAIN 64-bit ALIGNED IN SIZE, SINCE + // IT IS ZONE ALLOCATED, AND REPINNED_BCBS_ARRAY_SIZE AFFECTS + // ITS SIZE. + // + + NODE_TYPE_CODE NodeTypeCode; + NODE_BYTE_SIZE NodeByteSize; + + // + // The Adapter that this I/O is destined for. + // + + PAFA_COMM_ADAPTER Adapter; + + PHYSICAL_ADDRESS LogicalFibAddress; + + // + // This is the event the sendfib routine will wait on if the + // caller did not pass one and this is synch io. + // + + OS_CV_T FsaEvent; + OS_CVLOCK *FsaEventMutex; + + u32 FibComplete; // gets set to 1 when fib is complete + + PFIB_CALLBACK FibCallback; + void * FibCallbackContext; + + u32 Flags; + + +#ifdef GATHER_FIB_TIMES + LARGE_INTEGER FibTimeStamp; + PFIB_TIMES FibTimesPtr; +#endif + + // + // The following is used to put this fib context onto the Outstanding I/O queue. + // + + LIST_ENTRY QueueEntry; + + // + // The following is used to timeout a fib to the adapter. + // + + LARGE_INTEGER TimeoutValue; + + void *FibData; + PFIB Fib; +} COMM_FIB_CONTEXT; + +typedef COMM_FIB_CONTEXT *PCOMM_FIB_CONTEXT; +#define FIB_CONTEXT_FLAG_TIMED_OUT (0x00000001) + +#endif /* _COMM_FIB_CONTEXT_ */ diff --git a/drivers/scsi/aacraid/include/comprocs.h b/drivers/scsi/aacraid/include/comprocs.h new file mode 100644 index 000000000000..d88bdcd715b7 --- /dev/null +++ b/drivers/scsi/aacraid/include/comprocs.h @@ -0,0 +1,84 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comprocs.h + * + * Abstract: This module defines all of the globally used procedures in the Afa comm layer + * + * + * + --*/ +#ifndef _COMPROCS_ +#define _COMPROCS_ + +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "nodetype.h" + +// #define GATHER_FIB_TIMES + +#include "fsatypes.h" + +#include "perfpack.h" + +#include "comstruc.h" + +//#include "unix_protocol.h" + +#include "fsact.h" + +#include "protocol.h" + +#include "fsaioctl.h" + +#undef GATHER_FIB_TIMES + +#include "aifstruc.h" + +#include "fsaport.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +#include "commfibcontext.h" +#include "comproto.h" +#include "commdata.h" +#include "commerr.h" + + + + +// +// The following macro is used when sending and receiving FIBs. It is only used for +// debugging. + +#if DBG +#define FIB_COUNTER_INCREMENT(Counter) InterlockedIncrement(&(Counter)) +#else +#define FIB_COUNTER_INCREMENT(Counter) +#endif + +int AfaCommAdapterDeviceControl(void * AdapterArg, PAFA_IOCTL_CMD IoctlCmdPtr); + +#endif // _COMPROCS_ diff --git a/drivers/scsi/aacraid/include/comproto.h b/drivers/scsi/aacraid/include/comproto.h new file mode 100644 index 000000000000..0281c8e83f4f --- /dev/null +++ b/drivers/scsi/aacraid/include/comproto.h @@ -0,0 +1,74 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comproto.h + * + * Abstract: Global routines for the commuication interface that are device + * independant. + * + * + * + --*/ +#ifndef _COMM_PROTO +#define _COMM_PROTO + +// +// define the routines we need so we can commuicate with the +// fsa adapter +// + +// +// The following 4 dpc routines will support commuication from the adapter to the +// host. There is one DPC routine to deal with each type of queue that supports +// commuication from the adapter. (adapter to host resposes, adapter to host commands) +// These routines will simply pull off the QE and set an event. In the case of a +// adapter to host command they will also put the FIB on a queue to be processed by +// a FS thread running at passive level. +// + +// Handle queue not full notification to the file system thread waiting for a queue entry +u_int CommonNotFullDpc(PCOMM_REGION CommRegion); + +// Adapter to host normal priority responses +u_int HostResponseNormalDpc(PCOMM_QUE OurQueue); + +// Adapter to host high priority responses +u_int HostResponseHighDpc(PCOMM_QUE OurQueue); + +// Adapter to host high priority commands +u_int HostCommandHighDpc(PCOMM_QUE OurQueue); + +// Adapter to host normal priority commands +u_int HostCommandNormDpc(PCOMM_QUE OurQueue); +int SendSynchFib(void * Arg, FIB_COMMAND Command, void * Data, u16 Size, void * Response, u16 *ResponseSize); +PFIB_CONTEXT AllocateFib(void * Adapter); +void FreeFib (PFIB_CONTEXT FibContext); +void FreeFibFromDpc(PFIB_CONTEXT FibContext); +AAC_STATUS DeallocateFib(PFIB_CONTEXT FibContext); +AAC_STATUS SendFib(FIB_COMMAND Command, PFIB_CONTEXT FibContext, u32 Size, COMM_PRIORITIES Priority, int Wait, void * WaitOn, int ResponseExpected, PFIB_CALLBACK FibCallback, void *FibCallbackContext); +AAC_STATUS CompleteFib(PFIB_CONTEXT FibContext); +AAC_STATUS CompleteAdapterFib(PFIB_CONTEXT FibContext, u16 Size); +AAC_STATUS InitializeFib(PFIB_CONTEXT FibContext); +void *FsaGetFibData(PFIB_CONTEXT FibContext); +AAC_STATUS AfaCommOpenAdapter(void *AdapterArg); +AAC_STATUS AfaCommCloseAdapter(void *AdapterArg); +void AfaCommInterruptHost(void *Adapter,ADAPTER_EVENT AdapterEvent); + +#endif // _COMM_PROTO diff --git a/drivers/scsi/aacraid/include/comstruc.h b/drivers/scsi/aacraid/include/comstruc.h new file mode 100644 index 000000000000..9a677e2c9e50 --- /dev/null +++ b/drivers/scsi/aacraid/include/comstruc.h @@ -0,0 +1,412 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comstruc.h + * + * Abstract: This module defines the data structures that make up the communication + * region for the FSA filesystem. This region is how the host based code + * communicates both control and data to the adapter based code. + * + * + * + --*/ +#ifndef _COMM_STRUCT +#define _COMM_STRUCT + +// +// Define all the constants needed for the communication interface +// + +// Define how many queue entries each queue will have and the total number of +// entries for the entire communication interface. Also define how many queues +// we support. + +#define NUMBER_OF_COMM_QUEUES 8 // 4 command; 4 response + +#define HOST_HIGH_CMD_ENTRIES 4 +#define HOST_NORM_CMD_ENTRIES 8 +#define ADAP_HIGH_CMD_ENTRIES 4 +#define ADAP_NORM_CMD_ENTRIES 512 +#define HOST_HIGH_RESP_ENTRIES 4 +#define HOST_NORM_RESP_ENTRIES 512 +#define ADAP_HIGH_RESP_ENTRIES 4 +#define ADAP_NORM_RESP_ENTRIES 8 + +#define TOTAL_QUEUE_ENTRIES \ + (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \ + HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES) + + + + +// Set the queues on a 16 byte alignment +#define QUEUE_ALIGNMENT 16 + + +// +// The queue headers define the Communication Region queues. These +// are physically contiguous and accessible by both the adapter and the +// host. Even though all queue headers are in the same contiguous block they will be +// represented as individual units in the data structures. +// + +typedef AAC_UINT32 QUEUE_INDEX; + +typedef QUEUE_INDEX *PQUEUE_INDEX; + +typedef struct _QUEUE_ENTRY { + + AAC_UINT32 Size; // Size in bytes of the Fib which this QE points to + AAC_UINT32 FibAddress; // Receiver addressable address of the FIB (low 32 address bits) + +} QUEUE_ENTRY; + +typedef QUEUE_ENTRY *PQUEUE_ENTRY; + + + +// The adapter assumes the ProducerIndex and ConsumerIndex are grouped +// adjacently and in that order. +// +typedef struct _QUEUE_HEADERS { + + PHYSICAL_ADDRESS LogicalHeaderAddress; // Address to hand the adapter to access to this queue head + PQUEUE_INDEX ProducerIndex; // The producer index for this queue (host address) + PQUEUE_INDEX ConsumerIndex; // The consumer index for this queue (host address) + +} QUEUE_HEADERS; +typedef QUEUE_HEADERS *PQUEUE_HEADERS; + +// +// Define all the events which the adapter would like to notify +// the host of. +// +typedef enum _ADAPTER_EVENT { + HostNormCmdQue = 1, // Change in host normal priority command queue + HostHighCmdQue, // Change in host high priority command queue + HostNormRespQue, // Change in host normal priority response queue + HostHighRespQue, // Change in host high priority response queue + AdapNormRespNotFull, + AdapHighRespNotFull, + AdapNormCmdNotFull, + AdapHighCmdNotFull, + SynchCommandComplete, + AdapInternalError = 0xfe // The adapter detected an internal error shutting down + +} _E_ADAPTER_EVENT; + +#ifdef AAC_32BIT_ENUMS +typedef _E_ADAPTER_EVENT ADAPTER_EVENT; +#else +typedef AAC_UINT32 ADAPTER_EVENT; +#endif + +// +// Define all the events the host wishes to notify the +// adapter of. +// +typedef enum _HOST_2_ADAP_EVENT { + AdapNormCmdQue = 1, + AdapHighCmdQue, + AdapNormRespQue, + AdapHighRespQue, + HostShutdown, + HostPowerFail, + FatalCommError, + HostNormRespNotFull, + HostHighRespNotFull, + HostNormCmdNotFull, + HostHighCmdNotFull, + FastIo, + AdapPrintfDone +} _E_HOST_2_ADAP_EVENT; + +#ifdef AAC_32BIT_ENUMS +typedef _E_HOST_2_ADAP_EVENT HOST_2_ADAP_EVENT; +#else +typedef AAC_UINT32 HOST_2_ADAP_EVENT; +#endif + +// +// Define all the queues that the adapter and host use to communicate +// + +typedef enum _QUEUE_TYPES { + HostNormCmdQueue = 1, // Adapter to host normal priority command traffic + HostHighCmdQueue, // Adapter to host high priority command traffic + AdapNormRespQueue, // Host to adapter normal priority response traffic + AdapHighRespQueue, // Host to adapter high priority response traffic + AdapNormCmdQueue, // Host to adapter normal priority command traffic + AdapHighCmdQueue, // Host to adapter high priority command traffic + HostNormRespQueue, // Adapter to host normal priority response traffic + HostHighRespQueue // Adapter to host high priority response traffic +} _E_QUEUE_TYPES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_QUEUE_TYPES QUEUE_TYPES; +#else +typedef AAC_UINT32 QUEUE_TYPES; +#endif + + +// +// Assign type values to the FSA communication data structures +// + +typedef enum _STRUCT_TYPES { + TFib = 1, + TQe, + TCtPerf +} _E_STRUCT_TYPES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_STRUCT_TYPES STRUCT_TYPES; +#else +typedef AAC_UINT32 STRUCT_TYPES; +#endif + +// +// Define the priority levels the FSA communication routines support. +// + +typedef enum _COMM_PRIORITIES { + FsaNormal = 1, + FsaHigh +} _E_COMM_PRIORITIES; + +#ifdef AAC_32BIT_ENUMS +typedef _E_COMM_PRIORITIES COMM_PRIORITIES; +#else +typedef AAC_UINT32 COMM_PRIORITIES; +#endif + + + +// +// Define the LIST_ENTRY structure. This structure is used on the NT side to link +// the FIBs together in a linked list. Since this structure gets compiled on the adapter +// as well, we need to define this structure for the adapter's use. If '_NT_DEF_' +// is defined, then this header is being included from the NT side, and therefore LIST_ENTRY +// is already defined. +#if !defined(_NTDEF_) && !defined(_WINNT_) +typedef struct _LIST_ENTRY { + struct _LIST_ENTRY *Flink; + struct _LIST_ENTRY *Blink; +} LIST_ENTRY; +typedef LIST_ENTRY *PLIST_ENTRY; +#endif + + +// +// Define the FIB. The FIB is the where all the requested data and +// command information are put to the application on the FSA adapter. +// + +typedef struct _FIB_HEADER { + AAC_UINT32 XferState; // Current transfer state for this CCB + AAC_UINT16 Command; // Routing information for the destination + AAC_UINT8 StructType; // Type FIB + AAC_UINT8 Flags; // Flags for FIB + AAC_UINT16 Size; // Size of this FIB in bytes + AAC_UINT16 SenderSize; // Size of the FIB in the sender (for response sizing) + AAC_UINT32 SenderFibAddress; // Host defined data in the FIB + AAC_UINT32 ReceiverFibAddress; // Logical address of this FIB for the adapter + AAC_UINT32 SenderData; // Place holder for the sender to store data +#ifndef __midl + union { + struct { + AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib + AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + LIST_ENTRY _FibLinks; // Used to link Adapter Initiated Fibs on the host + } _u; +#else // The MIDL compiler does not support unions without a discriminant. + struct { // Since nothing during the midl compile actually looks into this + struct { // structure, this shoudl be ok. + AAC_UINT32 _ReceiverTimeStart; // Timestamp for receipt of fib + AAC_UINT32 _ReceiverTimeDone; // Timestamp for completion of fib + } _s; + } _u; +#endif +} FIB_HEADER; + + +#define FibLinks _u._FibLinks + + +#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(FIB_HEADER)) + + +typedef struct _FIB { + +#ifdef BRIDGE //rma + DLQUE link; +#endif + FIB_HEADER Header; + + AAC_UINT8 data[FIB_DATA_SIZE_IN_BYTES]; // Command specific data + +} FIB; +typedef FIB *PFIB; + + + +// +// FIB commands +// + +typedef enum _FIB_COMMANDS { + TestCommandResponse = 1, + TestAdapterCommand = 2, + + // Lowlevel and comm commands + + LastTestCommand = 100, + ReinitHostNormCommandQueue = 101, + ReinitHostHighCommandQueue = 102, + ReinitHostHighRespQueue = 103, + ReinitHostNormRespQueue = 104, + ReinitAdapNormCommandQueue = 105, + ReinitAdapHighCommandQueue = 107, + ReinitAdapHighRespQueue = 108, + ReinitAdapNormRespQueue = 109, + InterfaceShutdown = 110, + DmaCommandFib = 120, + StartProfile = 121, + TermProfile = 122, + SpeedTest = 123, + TakeABreakPt = 124, + RequestPerfData = 125, + SetInterruptDefTimer= 126, + SetInterruptDefCount= 127, + GetInterruptDefStatus= 128, + LastCommCommand = 129, + + // Filesystem commands + + NuFileSystem = 300, + UFS = 301, + HostFileSystem = 302, + LastFileSystemCommand = 303, + + // Container Commands + + ContainerCommand = 500, + ContainerCommand64 = 501, + + // Cluster Commands + + ClusterCommand = 550, + + // Scsi Port commands (scsi passthrough) + + ScsiPortCommand = 600, + + // misc house keeping and generic adapter initiated commands + + AifRequest = 700, + CheckRevision = 701, + FsaHostShutdown = 702, + RequestAdapterInfo = 703, + IsAdapterPaused = 704, + SendHostTime = 705, + LastMiscCommand = 706 + +} _E_FIB_COMMANDS; + + + +typedef AAC_UINT16 FIB_COMMAND; + +// +// Commands that will target the failover level on the FSA adapter +// + +typedef enum _FIB_XFER_STATE { + HostOwned = (1<<0), + AdapterOwned = (1<<1), + FibInitialized = (1<<2), + FibEmpty = (1<<3), + AllocatedFromPool = (1<<4), + SentFromHost = (1<<5), + SentFromAdapter = (1<<6), + ResponseExpected = (1<<7), + NoResponseExpected = (1<<8), + AdapterProcessed = (1<<9), + HostProcessed = (1<<10), + HighPriority = (1<<11), + NormalPriority = (1<<12), + Async = (1<<13), + AsyncIo = (1<<13), // rpbfix: remove with new regime + PageFileIo = (1<<14), // rpbfix: remove with new regime + ShutdownRequest = (1<<15), + LazyWrite = (1<<16), // rpbfix: remove with new regime + AdapterMicroFib = (1<<17), + BIOSFibPath = (1<<18), + FastResponseCapable = (1<<19), + ApiFib = (1<<20) // Its an API Fib. + +} _E_FIB_XFER_STATE; + + +typedef enum _FSA_ERRORS { + FSA_NORMAL = 0, + FSA_SUCCESS = 0, + FSA_PENDING = 0x01, + FSA_FATAL = 0x02, + FSA_INVALID_QUEUE = 0x03, + FSA_NOENTRIES = 0x04, + FSA_SENDFAILED = 0x05, + FSA_INVALID_QUEUE_PRIORITY = 0x06, + FSA_FIB_ALLOCATION_FAILED = 0x07, + FSA_FIB_DEALLOCATION_FAILED = 0x08 + +} _E_FSA_ERRORS; + + +// +// The following defines needs to be updated any time there is an incompatible change made +// to the ADAPTER_INIT_STRUCT structure. +// +#define ADAPTER_INIT_STRUCT_REVISION 3 + +typedef struct _ADAPTER_INIT_STRUCT { + AAC_UINT32 InitStructRevision; + AAC_UINT32 MiniPortRevision; + AAC_UINT32 FilesystemRevision; + PAAC_VOID CommHeaderAddress; + PAAC_VOID FastIoCommAreaAddress; + PAAC_VOID AdapterFibsPhysicalAddress; + PAAC_VOID AdapterFibsVirtualAddress; + AAC_UINT32 AdapterFibsSize; + AAC_UINT32 AdapterFibAlign; + PAAC_VOID PrintfBufferAddress; + AAC_UINT32 PrintfBufferSize; + AAC_UINT32 HostPhysMemPages; // number of 4k pages of host physical memory + AAC_UINT32 HostElapsedSeconds; // number of seconds since 1970. +} ADAPTER_INIT_STRUCT; +typedef ADAPTER_INIT_STRUCT *PADAPTER_INIT_STRUCT; + + + + +#endif //_COMM_STRUCT + + diff --git a/drivers/scsi/aacraid/include/comsup.h b/drivers/scsi/aacraid/include/comsup.h new file mode 100644 index 000000000000..0ca38071401a --- /dev/null +++ b/drivers/scsi/aacraid/include/comsup.h @@ -0,0 +1,124 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * comsup.h + * + * Abstract: This module defines the data structures that make up the + * commuication region for the FSA filesystem. This region is + * how the host based code commuicates both control and data + * to the adapter based code. + * + * + * + --*/ +#ifndef _COMM_SUP_DEF +#define _COMM_SUP_DEF + + +// +// The adapter interface specs all queues to be located in the same physically +// contigous block. The host structure that defines the commuication queues will +// assume they are each a seperate physically contigous memory region that will +// support them all being one big contigous block. +// There is a command and response queue for each level and direction of +// commuication. These regions are accessed by both the host and adapter. +// +typedef struct _COMM_QUE { + PHYSICAL_ADDRESS LogicalAddress; // This is the address we give the adapter + PQUEUE_ENTRY BaseAddress; // This is the system virtual address + QUEUE_HEADERS Headers; // A pointer to the producer and consumer queue headers for this queue + u32 QueueEntries; // Number of queue entries on this queue + OS_CV_T QueueFull; // Event to wait on if the queue is full + OS_CV_T CommandReady; // Indicates there is a Command ready from the adapter on this queue. + // This is only valid for adapter to host command queues. + OS_SPINLOCK *QueueLock; // Spinlock for this queue must take this lock before accessing the lock + KIRQL SavedIrql; // Previous IRQL when the spin lock is taken + ddi_softintr_t ConsumerRoutine;// The DPC routine which will consume entries off this queue + // Only queues which the host will be the consumer will this field be valid + LIST_ENTRY CommandQueue; // A queue of FIBs which need to be prcessed by the FS thread. This is + // only valid for command queues which receive entries from the adapter. + LIST_ENTRY OutstandingIoQueue; // A queue of outstanding fib's to the adapter. + u32 NumOutstandingIos; // Number of entries on outstanding queue. + void * Adapter; // Back pointer to adapter structure +} COMM_QUE; +typedef COMM_QUE *PCOMM_QUE; + + +typedef struct _COMM_REGION { + COMM_QUE HostNormCmdQue; // Command queue for normal priority commands from the host + COMM_QUE HostNormRespQue; // A response for normal priority adapter responses + + COMM_QUE HostHighCmdQue; // Command queue for high priority commands from the host + COMM_QUE HostHighRespQue; // A response for normal priority adapter responses + + COMM_QUE AdapNormCmdQue; // Command queue for normal priority command from the adapter + COMM_QUE AdapNormRespQue; // A response for normal priority host responses + + COMM_QUE AdapHighCmdQue; // Command queue for high priority command from the adapter + COMM_QUE AdapHighRespQue; // A response for high priority host responses + + // + // The 2 threads below are the threads which handle command traffic from the + // the adapter. There is one for normal priority and one for high priority queues. + // These threads will wait on the commandready event for it's queue. + // + + HANDLE NormCommandThread; + HANDLE HighCommandThread; + + // + // This dpc routine will handle the setting the of not full event when the adapter + // lets us know the queue is not longer full via interrupt + // + + KDPC QueueNotFullDpc; + +#ifdef API_THROTTLE + // + // Support for data I/O throttling to improve CLI performance + // while the system is under load. + // This is the throttling mechanism built into the COMM layer. + // Look in commsup.c, dpcsup.c and comminit.c for use. + // + + int ThrottleLimit; // Max queue depth of data ops allowed during throttle + int ThrottleOutstandingFibs; // Number of data FIBs outstanding to adapter + LARGE_INTEGER ThrottleTimeout; // Duration of a a throttle period + LARGE_INTEGER ThrottleWaitTimeout; // Timeout for a suspended threads to wait + int ThrottleActive; // Is there a current throttle active period ? + KTIMER ThrottleTimer; // Throttle timer to end a throttle period. + KDPC ThrottleDpc; // Throttle timer timeout DPC routine. + KSEMAPHORE ThrottleReleaseSema; // Semaphore callers of SendFib wait on during a throttle. + + unsigned int ThrottleExceptionsCount; // Number of times throttle exception handler executed (0!) + unsigned int ThrottleTimerFires; // Debug info - #times throttle timer Dpc has fired + unsigned int ThrottleTimerSets; // Debug info - #times throttle timer was set + + unsigned int ThrottledFibs; + unsigned int ThrottleTimedoutFibs; + unsigned int ApiFibs; + unsigned int NonPassiveFibs; + unsigned int TotalFibs; + unsigned int FSInfoFibs; +#endif // #ifdef API_THROTTLE +} COMM_REGION; +typedef COMM_REGION *PCOMM_REGION; + +#endif // _COMM_SUP diff --git a/drivers/scsi/aacraid/include/fsact.h b/drivers/scsi/aacraid/include/fsact.h new file mode 100644 index 000000000000..d38294ccd2ed --- /dev/null +++ b/drivers/scsi/aacraid/include/fsact.h @@ -0,0 +1,152 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsact.h + * + * Abstract: Common container structures that are required to be + * known on both the host and adapter. + * + * + --*/ +#ifndef _FSACT_H_ +#define _FSACT_H_ + +//#include +//#include +#include // definitions for FSASTATUS + +/* + * Object-Server / Volume-Manager Dispatch Classes + */ +typedef enum _VM_COMMANDS { + VM_Null = 0, + VM_NameServe, + VM_ContainerConfig, + VM_Ioctl, + VM_FilesystemIoctl, + VM_CloseAll, + VM_CtBlockRead, // see protocol.h for BlockRead command layout + VM_CtBlockWrite, // see protocol.h for BlockWrite command layout + VM_SliceBlockRead, // raw access to configured "storage objects" + VM_SliceBlockWrite, + VM_DriveBlockRead, // raw access to physical devices + VM_DriveBlockWrite, + VM_EnclosureMgt, // enclosure management + VM_Unused, // used to be diskset management + VM_CtBlockVerify, // see protocol.h for BlockVerify command layout + VM_CtPerf, // performance test + VM_CtBlockRead64, // see protocol.h for BlockRead64 command layout + VM_CtBlockWrite64, // see protocol.h for BlockWrite64 command layout + VM_CtBlockVerify64, // see protocol.h for BlockVerify64 command layout + MAX_VMCOMMAND_NUM // used for sizing stats array - leave last +} _E_VMCOMMAND; + +#ifdef AAC_32BIT_ENUMS +typedef _E_VMCOMMAND VMCOMMAND; +#else +typedef AAC_UINT32 VMCOMMAND; +#endif + + + +// +// Descriptive information (eg, vital stats) +// that a content manager might report. The +// FileArray filesystem component is one example +// of a content manager. Raw mode might be +// another. +// + +struct FileSysInfo { +/* + a) DOS usage - THINK ABOUT WHERE THIS MIGHT GO -- THXXX + b) FSA usage (implemented by ObjType and ContentState fields) + c) Block size + d) Frag size + e) Max file system extension size - (fsMaxExtendSize * fsSpaceUnits) + f) I-node density - (computed from other fields) +*/ + AAC_UINT32 fsTotalSize; // consumed by fs, incl. metadata + AAC_UINT32 fsBlockSize; + AAC_UINT32 fsFragSize; + AAC_UINT32 fsMaxExtendSize; + AAC_UINT32 fsSpaceUnits; + AAC_UINT32 fsMaxNumFiles; + AAC_UINT32 fsNumFreeFiles; + AAC_UINT32 fsInodeDensity; +}; // valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) + +union ContentManagerInfo { + struct FileSysInfo FileSys; // valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) +}; + +// +// Query for "mountable" objects, ie, objects that are typically +// associated with a drive letter on the client (host) side. +// + +typedef struct _MNTOBJ { + AAC_UINT32 ObjectId; + FSASTRING FileSystemName; // if applicable + ContainerCreationInfo CreateInfo; // if applicable + AAC_UINT32 Capacity; + FSAVOLTYPE VolType; // substrate structure + FTYPE ObjType; // FT_FILESYS, FT_DATABASE, etc. + AAC_UINT32 ContentState; // unready for mounting, readonly, etc. + + union ContentManagerInfo + ObjExtension; // Info specific to content manager (eg, filesystem) + + AAC_UINT32 AlterEgoId; // != ObjectId <==> snapshot or broken mirror exists +} MNTOBJ; + + +#define FSCS_READONLY 0x0002 // possible result of broken mirror + +typedef struct _MNTINFO { + VMCOMMAND Command; + FTYPE MntType; + AAC_UINT32 MntCount; +} MNTINFO; +typedef MNTINFO *PMNTINFO; + +typedef struct _MNTINFORESPONSE { + FSASTATUS Status; + FTYPE MntType; // should be same as that requested + AAC_UINT32 MntRespCount; + MNTOBJ MntTable[1]; +} MNTINFORESPONSE; +typedef MNTINFORESPONSE *PMNTINFORESPONSE; + + +// +// The following command is sent to shut down each container. +// + +typedef struct _CLOSECOMMAND { + VMCOMMAND Command; + AAC_UINT32 ContainerId; +} CLOSECOMMAND; +typedef CLOSECOMMAND *PCLOSECOMMAND; + + +#endif /* _FSACT_H_ */ + + diff --git a/drivers/scsi/aacraid/include/fsafs.h b/drivers/scsi/aacraid/include/fsafs.h new file mode 100644 index 000000000000..a3acce3ae4d7 --- /dev/null +++ b/drivers/scsi/aacraid/include/fsafs.h @@ -0,0 +1,79 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsafs.h + * + * Abstract: Common file system structures that are required to be + * known on both the host and adapter + * + * + * + --*/ + +#ifndef _FSAFS_H_ +#define _FSAFS_H_ 1 + + +#include // core types, shared by client and server, eg, u_long + +/* + * Maximum number of filesystems. + */ + +#define NFILESYS 24 + +/* + * File identifier. + * These are unique and self validating within a filesystem + * on a single machine and can persist across reboots. + * The hint field may be volatile and is not guaranteed to persist + * across reboots but is used to speed up the FID to file object translation + * if possible. The opaque f1 and f2 fields are guaranteed to uniquely identify + * the file object (assuming a filesystem context, i.e. driveno). + */ + +typedef struct { + AAC_UINT32 hint; // last used hint for fast reclaim + AAC_UINT32 f1; // opaque + AAC_UINT32 f2; // opaque +} fileid_t; /* intra-filesystem file ID type */ + + +/* + * Generic file handle + */ +struct fhandle { + fsid_t fh_fsid; /* File system id of mount point */ + fileid_t fh_fid; /* File sys specific file id */ +}; +typedef struct fhandle fhandle_t; + +#define FIDSIZE sizeof(fhandle_t) + +typedef struct { + union { + AAC_INT8 fid_data[FIDSIZE]; + struct fhandle fsafid; + } fidu; +} FSAFID; /* FSA File ID type */ + + +#endif /* _FSAFS_H_ */ + diff --git a/drivers/scsi/aacraid/include/fsaioctl.h b/drivers/scsi/aacraid/include/fsaioctl.h new file mode 100644 index 000000000000..be8d50ad2875 --- /dev/null +++ b/drivers/scsi/aacraid/include/fsaioctl.h @@ -0,0 +1,129 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsaioctl.h + * + * Abstract: Defines the interface structures between user mode applications + * and the fsa driver. This structures are used in + * DeviceIoControl() calls. + * + * + * + --*/ +#ifndef _FSAIOCTL_H_ +#define _FSAIOCTL_H_ + +#ifndef IOTRACEUSER + +#ifndef CTL_CODE + +#define FILE_DEVICE_CONTROLLER 0x00000004 + +// +// Macro definition for defining IOCTL and FSCTL function control codes. Note +// that function codes 0-2047 are reserved for Microsoft Corporation, and +// 2048-4095 are reserved for customers. +// + +#define CTL_CODE( DeviceType, Function, Method, Access ) ( \ + ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method) \ +) + +// +// Define the method codes for how buffers are passed for I/O and FS controls +// + +#define METHOD_BUFFERED 0 +#define METHOD_NEITHER 3 + +// +// Define the access check value for any access +// +// +// The FILE_READ_ACCESS and FILE_WRITE_ACCESS constants are also defined in +// ntioapi.h as FILE_READ_DATA and FILE_WRITE_DATA. The values for these +// constants *MUST* always be in sync. +// + +#define FILE_ANY_ACCESS 0 + +#endif + +typedef struct _UNIX_QUERY_DISK { + AAC_INT32 ContainerNumber; + AAC_INT32 Bus; + AAC_INT32 Target; + AAC_INT32 Lun; + AAC_BOOLEAN Valid; + AAC_BOOLEAN Locked; + AAC_BOOLEAN Deleted; + AAC_INT32 Instance; + AAC_INT8 diskDeviceName[10]; + AAC_BOOLEAN UnMapped; +} UNIX_QUERY_DISK; +typedef UNIX_QUERY_DISK *PUNIX_QUERY_DISK; + +typedef struct _DELETE_DISK { + AAC_UINT32 NtDiskNumber; + AAC_UINT32 ContainerNumber; +} DELETE_DISK; +typedef DELETE_DISK *PDELETE_DISK; + +#endif /*IOTRACEUSER*/ + +#define FSACTL_NULL_IO_TEST 0x43 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSACTL_SIM_IO_TEST 0x53 // CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS) + +#define FSACTL_SENDFIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2050, METHOD_BUFFERED, FILE_ANY_ACCESS) + +#define FSACTL_GET_VAR 0x93 +#define FSACTL_SET_VAR 0xa3 +#define FSACTL_GET_FIBTIMES 0xb3 +#define FSACTL_ZERO_FIBTIMES 0xc3 +#define FSACTL_DELETE_DISK 0x163 +#define FSACTL_QUERY_DISK 0x173 + +// AfaComm perfmon ioctls +#define FSACTL_GET_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2084, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_OPENCLS_COMM_PERF_DATA CTL_CODE(FILE_DEVICE_CONTROLLER, 2085, METHOD_BUFFERED, FILE_ANY_ACCESS) + + +typedef struct _GET_ADAPTER_FIB_IOCTL { + char *AdapterFibContext; + int Wait; + char *AifFib; +} GET_ADAPTER_FIB_IOCTL, *PGET_ADAPTER_FIB_IOCTL; + +// +// filesystem ioctls +// +#define FSACTL_OPEN_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2100, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_GET_NEXT_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2101, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_CLOSE_GET_ADAPTER_FIB CTL_CODE(FILE_DEVICE_CONTROLLER, 2102, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_OPEN_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2103, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSACTL_CLOSE_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2104, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSACTL_MINIPORT_REV_CHECK CTL_CODE(FILE_DEVICE_CONTROLLER, 2107, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_QUERY_ADAPTER_CONFIG CTL_CODE(FILE_DEVICE_CONTROLLER, 2113, METHOD_BUFFERED, FILE_ANY_ACCESS) +#define FSACTL_FORCE_DELETE_DISK CTL_CODE(FILE_DEVICE_CONTROLLER, 2120, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSACTL_AIF_THREAD CTL_CODE(FILE_DEVICE_CONTROLLER, 2127, METHOD_NEITHER, FILE_ANY_ACCESS) + +#endif // _FSAIOCTL_H_ + + diff --git a/drivers/scsi/aacraid/include/fsaport.h b/drivers/scsi/aacraid/include/fsaport.h new file mode 100644 index 000000000000..ff99fc7d5bfa --- /dev/null +++ b/drivers/scsi/aacraid/include/fsaport.h @@ -0,0 +1,124 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsaport.h + * + * Abstract: This module defines all of the globally used procedures in the FSA + * file system. + * + * + * + --*/ +#ifndef _FSAPORT_ +#define _FSAPORT_ + +// +// The scatter/gather map context is the information we +// we need to keep the map and transfer data to and from the +// adapter. +// + +typedef struct _SGMAP_CONTEXT { + caddr_t BaseAddress; + void * MapRegBase; + u32 NumberMapRegs; + PSGMAP SgMapPtr; + u32 ByteCount; // Used to check the Mdl length. + int WriteToDevice; + struct buf *bp; +} SGMAP_CONTEXT; +typedef SGMAP_CONTEXT *PSGMAP_CONTEXT; + +typedef struct _MAPFIB_CONTEXT { + PMDL Mdl; + void * MapRegBase; + u32 NumberMapRegs; + void * FibVirtualAddress; + u32 Size; + void * FibPhysicalAddress; +} MAPFIB_CONTEXT; +typedef MAPFIB_CONTEXT *PMAPFIB_CONTEXT; + +typedef int (*PFSA_ALLOCATE_ADAPTER_COMM_AREA)(void * AdapterExtension, void * *BaseAddress, u32 Size, u32 Alignment); +typedef int (*PFSA_FREE_ADAPTER_COMM_AREA)(void * AdapterExtension); +typedef void (*PFSA_FREE_DMA_RESOURCES)(void * AdapterExtension, PSGMAP_CONTEXT SgMapContext); +typedef int (*PFSA_ALLOCATE_AND_MAP_FIB_SPACE)(void * AdapterExtension, PMAPFIB_CONTEXT MapFibContext); +typedef int (*PFSA_UNMAP_AND_FREE_FIB_SPACE)(void * AdapterExtension, PMAPFIB_CONTEXT MapFibContext); +typedef void (*PFSA_INTERRUPT_ADAPTER)(void * AdapterExtension); +typedef void(*PFSA_NOTIFY_ADAPTER)(void * AdapterExtension, HOST_2_ADAP_EVENT AdapterEvent); +typedef void (*PFSA_RESET_DEVICE)(void * AdapterExtension); +typedef void * (*PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR)(void * AdapterExtension, void * AdapterAddress); +typedef void (*PFSA_INTERRUPT_HOST)(void * Adapter, ADAPTER_EVENT AdapterEvent); +typedef void (*PFSA_ENABLE_INTERRUPT)(void * Adapter, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq); +typedef void (*PFSA_DISABLE_INTERRUPT)(void * Adapter, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq); +typedef AAC_STATUS (*PFSA_OPEN_ADAPTER) (void * Adapter); +typedef int (*PFSA_DEVICE_CONTROL) (void * Adapter, PAFA_IOCTL_CMD IoctlCmdPtr); +typedef AAC_STATUS (*PFSA_CLOSE_ADAPTER) (void * Adapter); +typedef int (*PFSA_SEND_SYNCH_FIB) (void * Adapter,u32 FibPhysicalAddress); + +typedef struct _FSAPORT_FUNCS { + u32 SizeOfFsaPortFuncs; + + PFSA_ALLOCATE_ADAPTER_COMM_AREA AllocateAdapterCommArea; + PFSA_FREE_ADAPTER_COMM_AREA FreeAdapterCommArea; + PFSA_ALLOCATE_AND_MAP_FIB_SPACE AllocateAndMapFibSpace; + PFSA_UNMAP_AND_FREE_FIB_SPACE UnmapAndFreeFibSpace; + PFSA_INTERRUPT_ADAPTER InterruptAdapter; + PFSA_NOTIFY_ADAPTER NotifyAdapter; + PFSA_ENABLE_INTERRUPT EnableInterrupt; + PFSA_DISABLE_INTERRUPT DisableInterrupt; + PFSA_RESET_DEVICE ResetDevice; + PFSA_ADAPTER_ADDR_TO_SYSTEM_ADDR AdapterAddressToSystemAddress; + + PFSA_INTERRUPT_HOST InterruptHost; + PFSA_OPEN_ADAPTER OpenAdapter; + PFSA_DEVICE_CONTROL DeviceControl; + PFSA_CLOSE_ADAPTER CloseAdapter; + + PFSA_SEND_SYNCH_FIB SendSynchFib; +} FSAPORT_FUNCS; + +typedef FSAPORT_FUNCS *PFSAPORT_FUNCS; + +typedef AAC_STATUS (*PFSA_SETVAR_CALLBACK) (void * Adapter, u32 NewValue); + +typedef struct _FSA_USER_VAR { + char Name[32]; + u32 *Address; + PFSA_SETVAR_CALLBACK SetVarCallback; +} FSA_USER_VAR; + +typedef FSA_USER_VAR *PFSA_USER_VAR; + +typedef struct _FSA_NEW_ADAPTER { + void * AdapterExtension; + PFSAPORT_FUNCS AdapterFuncs; + void * Adapter; + int AdapterInterruptsBelowDpc; + PFSA_USER_VAR AdapterUserVars; + u32 AdapterUserVarsSize; + void *Dip; +} FSA_NEW_ADAPTER; +typedef FSA_NEW_ADAPTER *PFSA_NEW_ADAPTER; + +#define FSAFS_GET_NEXT_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2048, METHOD_NEITHER, FILE_ANY_ACCESS) +#define FSAFS_INIT_NEW_ADAPTER CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 2049, METHOD_NEITHER, FILE_ANY_ACCESS) + +#endif diff --git a/drivers/scsi/aacraid/include/fsatypes.h b/drivers/scsi/aacraid/include/fsatypes.h new file mode 100644 index 000000000000..96f37bbad92d --- /dev/null +++ b/drivers/scsi/aacraid/include/fsatypes.h @@ -0,0 +1,197 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * fsatypes.h + * + * Abstract: Define all shared data types here, ie, those + * types shared among several components, such + * as host (driver + apps), adapter, and BIOS. + * + * + --*/ +#ifndef _FSATYPES_H +#define _FSATYPES_H + +typedef AAC_UINT32 AAC_BOOLEAN; + +// +// Define a 64-bit address structure for use on +// a 32-bit processor architecture. +// +typedef struct { + AAC_UINT32 lo32; + AAC_UINT32 hi32; +} AAC_UINT64S, *PAAC_UINT64S; + +// +// Container Types +// +typedef struct { + AAC_UINT32 data[2]; // RMA FIX, make this a real serial number when we + // know what it looks like. Note, BIOS sees this + // definition and it must be coded in such a way + // that it appears to be 64 bits. ints are 16 bits + // in BIOS land; fortunately, longs are 32 bits. +} SerialNumberT; + + + +// +// *********************** +// DON'T CHANGE THE ORDER, ctdevsw use this order to map the drivers +// *********************** +// drivers for CT_NONE to CT_PASSTHRU +// + +typedef enum _FSAVOLTYPE { + CT_NONE = 0, + CT_VOLUME, + CT_MIRROR, + CT_STRIPE, + CT_RAID5, + CT_SSRW, + CT_SSRO, + CT_MORPH, + CT_PASSTHRU, + CT_RAID4, + CT_RAID10, // stripe of mirror + CT_RAID00, // stripe of stripe + CT_VOLUME_OF_MIRRORS, // volume of mirror + CT_PSEUDO_RAID3, // really raid4 + CT_LAST_VOLUME_TYPE +} _E_FSAVOLTYPE; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FSAVOLTYPE FSAVOLTYPE; +#else +typedef AAC_UINT32 FSAVOLTYPE; +#endif + + +// +// Types of objects addressable in some fashion by the client. +// This is a superset of those objects handled just by the filesystem +// and includes "raw" objects that an administrator would use to +// configure containers and filesystems. +// +typedef enum _FTYPE { + FT_REG = 1, // regular file + FT_DIR, // directory + FT_BLK, // "block" device - reserved + FT_CHR, // "character special" device - reserved + FT_LNK, // symbolic link + FT_SOCK, // socket + FT_FIFO, // fifo + FT_FILESYS, // ADAPTEC's "FSA"(tm) filesystem + FT_DRIVE, // physical disk - addressable in scsi by bus/target/lun + FT_SLICE, // virtual disk - raw volume - slice + FT_PARTITION, // FSA partition - carved out of a slice - building block for containers + FT_VOLUME, // Container - Volume Set + FT_STRIPE, // Container - Stripe Set + FT_MIRROR, // Container - Mirror Set + FT_RAID5, // Container - Raid 5 Set + FT_DATABASE // Storage object with "foreign" content manager +} _E_FTYPE; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FTYPE FTYPE; +#else +typedef AAC_UINT32 FTYPE; +#endif + +// +// Host side memory scatter gather list +// Used by the adapter for read, write, and readdirplus operations +// +typedef PAAC_UINT8 HOSTADDRESS; + +typedef struct _SGENTRY { + HOSTADDRESS SgAddress; /* 32-bit Base address. */ + AAC_UINT32 SgByteCount; /* Length. */ +} SGENTRY; + +typedef SGENTRY *PSGENTRY; + +// +// SGMAP +// +// This is the SGMAP structure for all commands that use +// 32-bit addressing. +// +// Note that the upper 16 bits of SgCount are used as flags. +// Only the lower 16 bits of SgCount are actually used as the +// SG element count. +// +typedef struct _SGMAP { + AAC_UINT32 SgCount; + SGENTRY SgEntry[1]; +} SGMAP; +typedef SGMAP *PSGMAP; + +// +// SGMAP64 +// +// This is the SGMAP structure for 64-bit container commands. +// +typedef struct _SGMAP64 { + AAC_UINT8 SgCount; + AAC_UINT8 SgSectorsPerPage; + AAC_UINT16 SgByteOffset; // For the first page + AAC_UINT64S SgEntry[1]; // Must be last entry +} SGMAP64; +typedef SGMAP64 *PSGMAP64; + + + + +// +// attempt at common time structure across host and adapter +// +typedef struct __TIME_T { + AAC_UINT32 tv_sec; /* seconds (maybe, depends upon host) */ + AAC_UINT32 tv_usec; /* and nanoseconds (maybe, depends upon host)*/ +} TIME_T; +typedef TIME_T *PTIME_T; + +#ifndef _TIME_T +#define timespec __TIME_T +#define ts_sec tv_sec +#define ts_nsec tv_usec +#endif + +typedef struct _ContainerCreationInfo +{ + AAC_UINT8 ViaBuildNumber; // e.g., 588 + AAC_UINT8 MicroSecond; // e.g., 588 + AAC_UINT8 Via; // e.g., 1 = FSU, + // 2 = API, + AAC_UINT8 YearsSince1900; // e.g., 1997 = 97 + AAC_UINT32 Date; // + // unsigned Month :4; // 1 - 12 + // unsigned Day :6; // 1 - 32 + // unsigned Hour :6; // 0 - 23 + // unsigned Minute :6; // 0 - 60 + // unsigned Second :6; // 0 - 60 + SerialNumberT ViaAdapterSerialNumber; // e.g., 0x1DEADB0BFAFAF001 +} ContainerCreationInfo; + +#endif // _FSATYPES_H + + diff --git a/drivers/scsi/aacraid/include/linit.h b/drivers/scsi/aacraid/include/linit.h new file mode 100644 index 000000000000..f1e590e8ee95 --- /dev/null +++ b/drivers/scsi/aacraid/include/linit.h @@ -0,0 +1,105 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.h + * + * Abstract: Header file for Linux Driver for Adaptec RAID Array Controller + * + --*/ +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ + +#ifndef _LINIT_H_ +#define _LINIT_H_ + +#include + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +/* Define the AAC SCSI Host Template structure. */ +#define AAC_HOST_TEMPLATE_ENTRY \ +{\ + proc_dir: &AAC_ProcDirectoryEntry, /* ProcFS Directory Entry */ \ + proc_info: AAC_ProcDirectoryInfo, /* ProcFS Info Function */ \ + name: "AAC", /* Driver Name */ \ + detect: AAC_DetectHostAdapter, /* Detect Host Adapter */ \ + release: AAC_ReleaseHostAdapter, /* Release Host Adapter */ \ + info: AAC_DriverInfo, /* Driver Info Function */ \ + ioctl: AAC_Ioctl, /* ioctl Interface */ \ + command: AAC_Command, /* unqueued command */ \ + queuecommand: AAC_QueueCommand, /* Queue Command Function */ \ + abort: AAC_AbortCommand, /* Abort Command Function */ \ + reset: AAC_ResetCommand, /* Reset Command Function */ \ + bios_param: AAC_BIOSDiskParameters, /* BIOS Disk Parameters */ \ + can_queue: 1, /* Default initial value */ \ + this_id: 0, /* Default initial value */ \ + sg_tablesize: 0, /* Default initial value */ \ + cmd_per_lun: 0, /* Default initial value */ \ + present: 0, /* Default initial value */ \ + unchecked_isa_dma: 0, /* Default Initial Value */ \ + use_new_eh_code: 0, /* Default initial value */ \ + eh_abort_handler: AAC_AbortCommand, /* New Abort Command func */ \ + eh_strategy_handler: NULL, /* New Strategy Error Handler */ \ + eh_device_reset_handler: NULL, /* New Device Reset Handler */ \ + eh_bus_reset_handler: NULL, /* New Bus Reset Handler */ \ + eh_host_reset_handler: NULL, /* New Host reset Handler */ \ + use_clustering: ENABLE_CLUSTERING /* Disable Clustering */ \ +} + + +/*------------------------------------------------------------------------------ + * T Y P E D E F S / S T R U C T S + *----------------------------------------------------------------------------*/ + +typedef struct AAC_BIOS_DiskParameters +{ + int heads; + int sectors; + int cylinders; +} AAC_BIOS_DiskParameters_T; + + +/*------------------------------------------------------------------------------ + * P R O G R A M G L O B A L S + *----------------------------------------------------------------------------*/ + +const char *AAC_DriverInfo( struct Scsi_Host * ); +extern struct proc_dir_entry AAC_ProcDirectoryEntry; + + + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +/* Define prototypes for the AAC Driver Interface Functions. */ +int AAC_DetectHostAdapter(Scsi_Host_Template *); +int AAC_ReleaseHostAdapter(struct Scsi_Host *); +int AAC_QueueCommand(Scsi_Cmnd *, void ( *CompletionRoutine)(Scsi_Cmnd *)); +int AAC_Command( Scsi_Cmnd *); +int AAC_ResetCommand(Scsi_Cmnd *, unsigned int); +int AAC_BIOSDiskParameters(Disk *, kdev_t, int * ); +int AAC_ProcDirectoryInfo(char *, char **, off_t, int, int, int); +int AAC_Ioctl(Scsi_Device *, int, void *); +void AAC_SelectQueueDepths(struct Scsi_Host *, Scsi_Device *); +int AAC_AbortCommand( Scsi_Cmnd *scsi_cmnd_ptr ); + +#endif /* _LINIT_H_ */ diff --git a/drivers/scsi/aacraid/include/monkerapi.h b/drivers/scsi/aacraid/include/monkerapi.h new file mode 100644 index 000000000000..de84348de8ee --- /dev/null +++ b/drivers/scsi/aacraid/include/monkerapi.h @@ -0,0 +1,87 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * monkerapi.h + * + * Abstract: This module contains the definitions used by the Host Adapter + * Communications interface. + * This is the interface used for by host programs and the Adapter + * to communicate via synchronous commands via a shared set of registers + * on a platform (typically doorbells and mailboxes). + * + --*/ +//********************************************************************** +// +// Monitor / Kernel API +// +// 03/24/1998 Bob Peret Initial creation +// +//********************************************************************** + +#ifndef MONKER_H +#define MONKER_H + + +#define BREAKPOINT_REQUEST 0x00000004 +#define INIT_STRUCT_BASE_ADDRESS 0x00000005 + + +#define SEND_SYNCHRONOUS_FIB 0x0000000c + + +// +// Adapter Status Register +// +// Phase Staus mailbox is 32bits: +// <31:16> = Phase Status +// <15:0> = Phase +// +// The adapter reports is present state through the phase. Only +// a single phase should be ever be set. Each phase can have multiple +// phase status bits to provide more detailed information about the +// state of the board. Care should be taken to ensure that any phase status +// bits that are set when changing the phase are also valid for the new phase +// or be cleared out. Adapter software (monitor, iflash, kernel) is responsible +// for properly maintining the phase status mailbox when it is running. + +// +// MONKER_API Phases +// +// Phases are bit oriented. It is NOT valid +// to have multiple bits set +// + +#define SELF_TEST_FAILED 0x00000004 +#define KERNEL_UP_AND_RUNNING 0x00000080 +#define KERNEL_PANIC 0x00000100 + +// +// Doorbell bit defines +// + +#define DoorBellPrintfDone (1<<5) // Host -> Adapter +#define DoorBellAdapterNormCmdReady (1<<1) // Adapter -> Host +#define DoorBellAdapterNormRespReady (1<<2) // Adapter -> Host +#define DoorBellAdapterNormCmdNotFull (1<<3) // Adapter -> Host +#define DoorBellAdapterNormRespNotFull (1<<4) // Adapter -> Host +#define DoorBellPrintfReady (1<<5) // Adapter -> Host + +#endif // MONKER_H + diff --git a/drivers/scsi/aacraid/include/nodetype.h b/drivers/scsi/aacraid/include/nodetype.h new file mode 100644 index 000000000000..af4b637abee4 --- /dev/null +++ b/drivers/scsi/aacraid/include/nodetype.h @@ -0,0 +1,64 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * nodetype.h + * + * Abstract: This module defines all of the node type codes used in this development + * shell. Every major data structure in the file system is assigned a node + * type code that is. This code is the first CSHORT in the structure and is + * followed by a CSHORT containing the size, in bytes, of the structure. + * + --*/ +#ifndef _NODETYPE_ +#define _NODETYPE_ + +typedef u16 NODE_TYPE_CODE; + + +#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT ((NODE_TYPE_CODE)0x030b) +#define FSAFS_NTC_FIB_CONTEXT ((NODE_TYPE_CODE)0x030c) + + +typedef u16 NODE_BYTE_SIZE; + + +// +// The following definitions are used to generate meaningful blue bugcheck +// screens. On a bugcheck the file system can output 4 ulongs of useful +// information. The first ulong will have encoded in it a source file id +// (in the high word) and the line number of the bugcheck (in the low word). +// The other values can be whatever the caller of the bugcheck routine deems +// necessary. +// +// Each individual file that calls bugcheck needs to have defined at the +// start of the file a constant called BugCheckFileId with one of the +// FSAFS_BUG_CHECK_ values defined below and then use FsaBugCheck to bugcheck +// the system. +// + + +#define FSAFS_BUG_CHECK_COMMSUP (0X001e0000) +#define FSAFS_BUG_CHECK_DPCSUP (0X001f0000) + + +#define FsaBugCheck(A,B,C) { cmn_err( CE_PANIC, "aacdisk: module %x, line %x, 0x%x, 0x%x, 0x%x ", BugCheckFileId, __LINE__, A, B, C); } + + +#endif // _NODETYPE_ diff --git a/drivers/scsi/aacraid/include/nvramioctl.h b/drivers/scsi/aacraid/include/nvramioctl.h new file mode 100644 index 000000000000..ea36d3a03547 --- /dev/null +++ b/drivers/scsi/aacraid/include/nvramioctl.h @@ -0,0 +1,110 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * nvramioctl.h + * + * Abstract: This file defines the data structures related to querying + * and controlling the FSA NVRAM/WriteCache subsystem via the NVRAMIOCTL FIB. + * + --*/ +#ifndef _NVRAMIOCTL_H_ +#define _NVRAMIOCTL_H_ 1 + +/* + * NVRAM/Write Cache subsystem states + */ +typedef enum _NVSTATUS { + NVSTATUS_DISABLED = 0, // present, clean, not being used + NVSTATUS_ENABLED, // present, possibly dirty, ready for use + NVSTATUS_ERROR, // present, dirty, contains dirty data + // for bad/missing device + NVSTATUS_BATTERY, // present, bad or low battery, may contain dirty data + // for bad/missing device + NVSTATUS_UNKNOWN // present????? +} _E_NVSTATUS; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVSTATUS NVSTATUS; +#else +typedef AAC_UINT32 NVSTATUS; +#endif + +/* + * NVRAM/Write Cache subsystem battery component states + * + */ +//NB: this enum should be identical to battery_status in nvram.h +// or else collapsed into one enum someday +typedef enum _NVBATTSTATUS { + NVBATTSTATUS_NONE = 0, // battery has no power or is not present + NVBATTSTATUS_LOW, // battery is low on power + NVBATTSTATUS_OK, // battery is okay - normal operation possible only in this state + NVBATTSTATUS_RECONDITIONING // no battery present - reconditioning in process +} _E_NVBATTSTATUS; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVBATTSTATUS NVBATTSTATUS; +#else +typedef AAC_UINT32 NVBATTSTATUS; +#endif + +/* + * battery transition type + */ +typedef enum _NVBATT_TRANSITION { + NVBATT_TRANSITION_NONE = 0, // battery now has no power or is not present + NVBATT_TRANSITION_LOW, // battery is now low on power + NVBATT_TRANSITION_OK // battery is now okay - normal operation possible only in this state +} _E_NVBATT_TRANSITION; + +#ifdef AAC_32BIT_ENUMS +typedef _E_NVBATT_TRANSITION NVBATT_TRANSITION; +#else +typedef AAC_UINT32 NVBATT_TRANSITION; +#endif + +/* + * NVRAM Info structure returned for NVRAM_GetInfo call + */ +typedef struct _NVRAMDEVINFO { + AAC_UINT32 NV_Enabled; /* write caching enabled */ + AAC_UINT32 NV_Error; /* device in error state */ + AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */ + AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */ +} NVRAMDEVINFO, *PNVRAMDEVINFO; + +typedef struct _NVRAMINFO { + NVSTATUS NV_Status; /* nvram subsystem status */ + NVBATTSTATUS NV_BattStatus; /* battery status */ + AAC_UINT32 NV_Size; /* size of WriteCache NVRAM in bytes */ + AAC_UINT32 NV_BufSize; /* size of NVRAM buffers in bytes */ + AAC_UINT32 NV_NBufs; /* number of NVRAM buffers */ + AAC_UINT32 NV_NDirty; /* count of dirty NVRAM buffers */ + AAC_UINT32 NV_NClean; /* count of clean NVRAM buffers */ + AAC_UINT32 NV_NActive; /* count of NVRAM buffers being written */ + AAC_UINT32 NV_NBrokered; /* count of brokered NVRAM buffers */ + NVRAMDEVINFO NV_DevInfo[NFILESYS]; /* per device info */ + AAC_UINT32 NV_BattNeedsReconditioning; /* boolean */ + AAC_UINT32 NV_TotalSize; /* total size of all non-volatile memories in bytes */ +} NVRAMINFO, *PNVRAMINFO; + +#endif /* !_NVRAMIOCTL_H_ */ + + diff --git a/drivers/scsi/aacraid/include/osheaders.h b/drivers/scsi/aacraid/include/osheaders.h new file mode 100644 index 000000000000..96eeba5c47e2 --- /dev/null +++ b/drivers/scsi/aacraid/include/osheaders.h @@ -0,0 +1,113 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osheaders.h + * + * Abstract: Holds all of the header file includes for a particular O/S flavor. + * + --*/ +#ifndef _OSHEADERS_H_ +#define _OSHEADERS_H_ + +#include // retrieve the kernel configuration info +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" + +#ifndef intptr_t +#define intptr_t void * +#endif + +#ifndef cred_t +#define cred_t void +#endif + +#ifndef paddr32_t +#define paddr32_t unsigned +#endif + +#ifndef bzero +#define bzero(b,len) memset(b,0,len) +#endif + +#ifndef bcopy +#define bcopy(src,dst,len) memcpy(dst,src,len ) +#endif + +#ifndef DEVICE_NR +#define DEVICE_NR(device) ( ( ( MAJOR( device ) & 7 ) << 4 ) + ( MINOR( device ) >> 4 ) ) +#endif + +typedef unsigned uint_t; + +typedef enum +{ + CE_PANIC = 0, + CE_WARN, + CE_NOTE, + CE_CONT, + CE_DEBUG, + CE_DEBUG2, + CE_TAIL +} CE_ENUM_T; + +#define CMN_ERR_LEVEL CE_WARN + +// usage of READ & WRITE as a typedefs in protocol.h +// conflicts with definition. +#ifdef READ +#undef READ +#endif + +#ifdef WRITE +#undef WRITE +#endif + +typedef struct aac_options +{ + int message_level; + int reverse_scan; +} aac_options_t; + +#endif // _OSHEADERS_H_ + diff --git a/drivers/scsi/aacraid/include/ostypes.h b/drivers/scsi/aacraid/include/ostypes.h new file mode 100644 index 000000000000..15f7b427b9ee --- /dev/null +++ b/drivers/scsi/aacraid/include/ostypes.h @@ -0,0 +1,145 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * ostypes.h + * + * Abstract: Holds all of the O/S specific types. + * + --*/ +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +#ifndef _OSTYPES_H_ +#define _OSTYPES_H_ + +#define MAXIMUM_NUM_CONTAINERS 64 // 4 Luns * 16 Targets +#define MAXIMUM_NUM_ADAPTERS 8 + +#define OS_ALLOC_MEM_SLEEP GFP_KERNEL + +#define Os_remove_softintr OsSoftInterruptRemove +#define OsPrintf printk +#define FsaCommPrint OsPrintf + +// the return values for copy_from_user & copy_to_user is the +// number of bytes not transferred. Thus if an internal error +// occurs, the return value is greater than zero. +#define COPYIN(SRC,DST,COUNT,FLAGS) copy_from_user(DST,SRC,COUNT) +#define COPYOUT(SRC,DST,COUNT,FLAGS) copy_to_user(DST,SRC,COUNT) + +#define copyin(SRC,DST,COUNT) copy_from_user(DST,SRC,COUNT) +#define copyout(SRC,DST,COUNT) copy_to_user(DST,SRC,COUNT) + +/*------------------------------------------------------------------------------ + * S T R U C T S / T Y P E D E F S + *----------------------------------------------------------------------------*/ +typedef struct OS_MUTEX +{ + unsigned long lock_var; + struct wait_queue * wq_ptr; + unsigned owner; +} OS_MUTEX; + +typedef struct OS_SPINLOCK +{ + spinlock_t spin_lock; + unsigned cpu_lock_count[8]; + long cpu_flag; + long lockout_count; +} OS_SPINLOCK; + +#ifdef CVLOCK_USE_SPINLOCK + typedef OS_SPINLOCK OS_CVLOCK; +#else + typedef OS_MUTEX OS_CVLOCK; +#endif + +typedef size_t OS_SIZE_T; + +typedef struct OS_CV_T +{ + unsigned long lock_var; + unsigned long type; + struct wait_queue *wq_ptr; +} OS_CV_T; + +struct fsa_scsi_hba { + void *CommonExtension; + unsigned long ContainerSize[MAXIMUM_NUM_CONTAINERS]; + unsigned long ContainerType[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerValid[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerReadOnly[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerLocked[MAXIMUM_NUM_CONTAINERS]; + unsigned char ContainerDeleted[MAXIMUM_NUM_CONTAINERS]; + long ContainerDevNo[MAXIMUM_NUM_CONTAINERS]; +}; + +typedef struct fsa_scsi_hba fsadev_t; + +typedef struct OsKI +{ + struct Scsi_Host *scsi_host_ptr; + void * dip; // #REVISIT# + fsadev_t fsa_dev; + int thread_pid; + int MiniPortIndex; +} OsKI_t; + +#define dev_info_t fsadev_t + +typedef int OS_SPINLOCK_COOKIE; + +typedef unsigned int OS_STATUS; + +typedef struct tq_struct OS_SOFTINTR; + +typedef OS_SOFTINTR *ddi_softintr_t; + + + +//----------------------------------------------------------------------------- +// Conditional variable functions + +void OsCv_init ( + OS_CV_T *cv_ptr ); + + +//----------------------------------------------------------------------------- +// Printing functions +void printk_err(int flag, char *fmt, ...); + +#define cmn_err printk_err + + +// +// just ignore these solaris ddi functions in the code +// +#define DDI_SUCCESS 0 + +#define ddi_add_softintr(A,B,C,D,E,F,G) OsSoftInterruptAdd(C,F,G) + +//#REVIEW# +#define ddi_remove_softintr(A) 0 +#define ddi_get_soft_iblock_cookie(A, B, C) 0 + +#define ASSERT(expr) ((void) 0) +#define drv_usecwait udelay + +#endif // _OSTYPES_H_ diff --git a/drivers/scsi/aacraid/include/pcisup.h b/drivers/scsi/aacraid/include/pcisup.h new file mode 100644 index 000000000000..3dafee16f32a --- /dev/null +++ b/drivers/scsi/aacraid/include/pcisup.h @@ -0,0 +1,93 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * pcisup.h + * + * Abstract: This module defines functions that are defined in PciSup.c + * + --*/ +#ifndef _PCISUP_ +#define _PCISUP_ + + + + +/* + * define which interrupt handler needs to be installed + */ + +#define SaISR 1 +#define RxISR 2 + +typedef struct _PCI_MINIPORT_COMMON_EXTENSION { + u32 AdapterNumber; // Which FSA# this miniport is + u32 PciBusNumber; // Which PCI bus we are located on + u32 PciSlotNumber; // Whiat PCI slot we are in + + void * Adapter; // Back pointer to Fsa adapter object + u32 AdapterIndex; // Index into PlxAdapterTypes array + PDEVICE_OBJECT DeviceObject; // Pointer to our device object + + FSAPORT_FUNCS AdapterFuncs; + u32 FilesystemRevision; // Main driver's revision number + +// KIRQL IsrIrql; // irql our isr runs at +// PKINTERRUPT IsrObject; // Our Interrupt object +// u32 NumMapRegs; // Max amount map regs per dma allowed by the system +// PADAPTER_OBJECT NtAdapter; // The adapter object for the cyclone board + + PADAPTER_INIT_STRUCT InitStruct; // Holds initialization info to communicate with adapter + void * PhysicalInitStruct; // Holds physical address of the init struct + +// PFASTIO_STRUCT FastIoCommArea; // pointer to common buffer used for FastIo communication (Host view) + + void * PrintfBufferAddress; // pointer to buffer used for printf's from the adapter + + int AdapterPrintfsToScreen; + int AdapterConfigured; // set to true when we know adapter can take FIBs + + void * MiniPort; + + caddr_t CommAddress; // Base address of Comm area + paddr32_t CommPhysAddr; // Physical Address of Comm area + size_t CommSize; + + OsKI_t OsDep; // OS dependent kernel interfaces +} PCI_MINIPORT_COMMON_EXTENSION; + +typedef PCI_MINIPORT_COMMON_EXTENSION *PPCI_MINIPORT_COMMON_EXTENSION; + +typedef int (*PFSA_MINIPORT_INIT) (PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot); + +typedef struct _FSA_MINIPORT { + u16 VendorId; + u16 DeviceId; + u16 SubVendorId; + u16 SubSystemId; + char * DevicePrefix; + PFSA_MINIPORT_INIT InitRoutine; + char * DeviceName; + char * Vendor; + char * Model; +} FSA_MINIPORT; +typedef FSA_MINIPORT *PFSA_MINIPORT; + + +#endif // _PCISUP_ diff --git a/drivers/scsi/aacraid/include/perfpack.h b/drivers/scsi/aacraid/include/perfpack.h new file mode 100644 index 000000000000..6e0c40029514 --- /dev/null +++ b/drivers/scsi/aacraid/include/perfpack.h @@ -0,0 +1,107 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * perfpack.h + * + * Abstract: This file defines the layout of the performance data that is passed + * back from the FSA filesystem driver. + * + * + --*/ + +#ifndef _FSA_PERFPACK_H_ +#define _FSA_PERFPACK_H_ 1 + + +//#define FSA_DO_PERF 1 /* enable the engineering counters */ + +#ifdef FSA_DO_PERF +// +// engineering counters +// +typedef struct _FSA_PERF_DATA { + u32 FibsSent; + u32 ReadDirs; + u32 GetAttrs; + u32 SetAttrs; + u32 Lookups; + u32 ReadFibs; + u32 WriteFibs; + u32 CreateFibs; + u32 MakeDirs; + u32 RemoveFibs; + u32 RemoveDirs; + u32 RenameFibs; + u32 ReadDirPlus; + u32 FsStat; + u32 WriteBytes; + u32 ReadBytes; +// NT FSA entry points + u32 FsaFsdCreateCount; + u32 FsaFsdCloseCount; + u32 FsaFsdReadCount; + u32 FsaFsdWriteCount; + u32 FsaFsdQueryInformationCount; + struct _FsaFsdSetInfomation{ + u32 FsaSetAllocationInfoCount; + u32 FsaSetBasicInfoCount; + u32 FsaSetDispositionInfoCount; + u32 FsaSetEndOfFileInfoCount; + u32 FsaSetPositionInfoCount; + u32 FsaSetRenameInfoCount; + u32 FsaClearArchiveBitCount; + }; + u32 FsaFsdFlushBuffersCount; + u32 FsaFsdQueryVolumeInfoCount; + u32 FsaFsdSetVolumeInfoCount; + u32 FsaFsdCleanupCount; + u32 FsaFsdDirectoryControlCount; + u32 FsaFsdFileSystemControlCount; + u32 FsaFsdLockControlCount; + u32 FsaFsdDeviceControlCount; + u32 FsaFsdShutdownCount; + u32 FsaFsdQuerySecurityInfo; + u32 FsaFsdSetSecurityInfo; + u32 FastIoCheckIfPossibleCount; + u32 FastIoReadCount; + u32 FastIoWriteCount; + u32 FastIoQueryBasicInfoCount; + u32 FastIoQueryStandardInfoCount; + u32 FastIoLockCount; + u32 FastIoUnlockSingleCount; + u32 FastIoUnlockAllCount; + u32 FastIoUnlockAllByKeyCount; + u32 FastIoDeviceControlCount; +} FSA_PERF_DATA; + +typedef FSA_PERF_DATA *PFSA_PERF_DATA; + + +#else /* FSA_DO_PERF */ + +// +// engineering performance counters are disabled +// +#define FSA_DO_PERF_INC(Counter) /* */ +#define FSA_DO_FSP_PERF_INC(Counter) /* */ + +#endif /* FSA_DO_PERF */ + +#endif // _FSA_PERFPACK_H_ diff --git a/drivers/scsi/aacraid/include/port.h b/drivers/scsi/aacraid/include/port.h new file mode 100644 index 000000000000..ceb4d63b0fa8 --- /dev/null +++ b/drivers/scsi/aacraid/include/port.h @@ -0,0 +1,47 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * port.h + * + * Abstract: This module defines functions and structures that are in common among all miniports + * + * + --*/ + +#ifndef _PORT_ +#define _PORT_ + + +#ifdef DBG +#define AfaPortPrint if (AfaPortPrinting) DbgPrint +extern int AfaPortPrinting; +#else +#define AfaPortPrint +#endif DBG + +extern int AfaPortPrinting; + +int AfaPortAllocateAdapterCommArea(void *arg1,void **CommHeaderAddress, u32 CommAreaSize, u32 CommAreaAlignment); +int AfaPortFreeAdapterCommArea(void *arg1); +int AfaPortAllocateAndMapFibSpace(void *arg1, PMAPFIB_CONTEXT MapFibContext); +int AfaPortUnmapAndFreeFibSpace(void *arg1, PMAPFIB_CONTEXT MapFibContext); + +#endif // _PORT_ + diff --git a/drivers/scsi/aacraid/include/protocol.h b/drivers/scsi/aacraid/include/protocol.h new file mode 100644 index 000000000000..72e77d1ca34a --- /dev/null +++ b/drivers/scsi/aacraid/include/protocol.h @@ -0,0 +1,243 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * protocol.h + * + * Abstract: Defines the commands and command data which enables the nt + * filesystem driver to be the client of the fsa adapter + * filesystem. This protocol is largely modeled after the NFS + * V3 protocol with modifications allowed due to the unique + * client/server model FSA works under. + * + * + * + --*/ + +#ifndef _PROTOCOL_H_ +#define _PROTOCOL_H_ + + +#include // definition of FSAFID; includes fsatypes.h +#include // for NVRAMINFO definition + +// #define MDL_READ_WRITE + +// +// Define the command values +// +typedef enum _FSA_COMMANDS { + Null = 0, + GetAttributes, + SetAttributes, + Lookup, + ReadLink, + Read, + Write, + Create, + MakeDirectory, + SymbolicLink, + MakeNode, + Removex, + RemoveDirectoryx, // bkpfix added x to this because already defined in nt + Rename, + Link, + ReadDirectory, + ReadDirectoryPlus, + FileSystemStatus, + FileSystemInfo, + PathConfigure, + Commit, + Mount, + UnMount, + Newfs, + FsCheck, + FsSync, + SimReadWrite, + SetFileSystemStatus, + BlockRead, + BlockWrite, + NvramIoctl, + FsSyncWait, + ClearArchiveBit, +#ifdef MDL_READ_WRITE + MdlReadComplete, + MdlWriteComplete, + MdlRead, // these are used solely for stats, Mdl really controlled by + MdlWrite, // flags field in Fib. +#endif + SetAcl, + GetAcl, + AssignAcl, + FaultInsertion, // Fault Insertion Command + CrazyCache, // crazycache + MAX_FSACOMMAND_NUM //CJ: used for sizing stats array - leave last +} _E_FSACOMMAND; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FSACOMMAND FSACOMMAND; +#else +typedef AAC_UINT32 FSACOMMAND; +#endif + + + +// +// Define the status returns +// +// See include/comm/errno.h for adapter kernel errno's +// + +typedef enum _FSASTATUS { + ST_OK = 0, + ST_PERM = 1, + ST_NOENT = 2, + ST_IO = 5, + ST_NXIO = 6, + ST_E2BIG = 7, + ST_ACCES = 13, + ST_EXIST = 17, + ST_XDEV = 18, + ST_NODEV = 19, + ST_NOTDIR = 20, + ST_ISDIR = 21, + ST_INVAL = 22, + ST_FBIG = 27, + ST_NOSPC = 28, + ST_ROFS = 30, + ST_MLINK = 31, + ST_WOULDBLOCK = 35, + ST_NAMETOOLONG = 63, + ST_NOTEMPTY = 66, + ST_DQUOT = 69, + ST_STALE = 70, + ST_REMOTE = 71, + ST_BADHANDLE = 10001, + ST_NOT_SYNC = 10002, + ST_BAD_COOKIE = 10003, + ST_NOTSUPP = 10004, + ST_TOOSMALL = 10005, + ST_SERVERFAULT = 10006, + ST_BADTYPE = 10007, + ST_JUKEBOX = 10008, + ST_NOTMOUNTED = 10009, + ST_MAINTMODE = 10010, + ST_STALEACL = 10011 +} _E_FSASTATUS; + +#ifdef AAC_32BIT_ENUMS +typedef _E_FSASTATUS FSASTATUS; +#else +typedef AAC_UINT32 FSASTATUS; +#endif + +// +// On writes how does the client want the data written. +// + +typedef enum _CACHELEVEL { + CSTABLE = 1, + CUNSTABLE +} _E_CACHELEVEL; + +#ifdef AAC_32BIT_ENUMS +typedef _E_CACHELEVEL CACHELEVEL; +#else +typedef AAC_UINT32 CACHELEVEL; +#endif + +// +// Lets the client know at which level the data was commited on a write request +// + +typedef enum _COMMITLEVEL { + CMFILE_SYNCH_NVRAM = 1, + CMDATA_SYNCH_NVRAM, + CMFILE_SYNCH, + CMDATA_SYNCH, + CMUNSTABLE +} _E_COMMITLEVEL; + +#ifdef AAC_32BIT_ENUMS +typedef _E_COMMITLEVEL COMMITLEVEL; +#else +typedef AAC_UINT32 COMMITLEVEL; +#endif + + + +// +// The following are all the different commands or FIBs which can be sent to the +// FSA filesystem. We will define a required subset which cannot return STATUS_NOT_IMPLEMENTED, +// but others outside that subset are allowed to return not implemented. The client is then +// responsible for dealing with the fact it is not implemented. +// + +typedef AAC_INT8 FSASTRING[16]; +typedef AAC_UINT32 BYTECOUNT; // only 32 bit-ism + +// +// BlockRead +// + +typedef struct _BLOCKREAD { // variable size struct + FSACOMMAND Command; + AAC_UINT32 ContainerId; + BYTECOUNT BlockNumber; + BYTECOUNT ByteCount; + SGMAP SgMap; // Must be last in struct because it is variable +} BLOCKREAD; + +typedef BLOCKREAD *PBLOCKREAD; + +typedef struct _BLOCKREADRESPONSE { + FSASTATUS Status; + BYTECOUNT ByteCount; +} BLOCKREADRESPONSE; + +typedef BLOCKREADRESPONSE *PBLOCKREADRESPONSE; + +// +// BlockWrite +// + +typedef struct _BLOCKWRITE { // variable size struct + FSACOMMAND Command; + AAC_UINT32 ContainerId; + BYTECOUNT BlockNumber; + BYTECOUNT ByteCount; + CACHELEVEL Stable; + SGMAP SgMap; // Must be last in struct because it is variable +} BLOCKWRITE; + +typedef BLOCKWRITE *PBLOCKWRITE; + + +typedef struct _BLOCKWRITERESPONSE { + FSASTATUS Status; + BYTECOUNT ByteCount; + COMMITLEVEL Committed; +} BLOCKWRITERESPONSE; + +typedef BLOCKWRITERESPONSE *PBLOCKWRITERESPONSE; + + + +#endif // _PROTOCOL_H_ + diff --git a/drivers/scsi/aacraid/include/revision.h b/drivers/scsi/aacraid/include/revision.h new file mode 100644 index 000000000000..0895e89bfd76 --- /dev/null +++ b/drivers/scsi/aacraid/include/revision.h @@ -0,0 +1,347 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * revision.h + * + * Abstract: This module contains all of the revision information for + * the FSA product, as well as the support routines for + * checking module compatibility. + * + * Before editing anything in this module, make sure that + * you read the comments. Some lines are changed automatically + * as part of the build, and should never be changed by hand. + * + * Routines (all inlines): + * + * RevGetBuildNumber - Retrieve current build number + * RevGetExternalRev - Retrieve revision for external use + * RevGetFullRevision - Retrieve full revision structure + * + * RevCheckCompatibility - Checks compatibility base on internal table + * + * RevCheckCompatibilityFullInfo - Check for static component + * RevGetCompInfoTableSize - Get size for static component table + * RevGetCompInfoTable - Get actual table to place on static component + * RevGetBuildNumberFromInfo - Get build number for static component. + * + * + * + --*/ + +#ifndef _REVISION_H +#define _REVISION_H + + +#include "version.h" // revision numbers kept separate so they can be used by resource compiler as well + +typedef int REV_BOOL; + +#define REV_TRUE 1 +#define REV_FALSE 0 + +// +// Define Revision Levels for this product +// +// IMPORTANT: Do NOT modify BUILD_NUMBER define, this is modified +// automatically by the build. +// +// Version is VMAJOR.MINOR-DASH TYPE (Build BUILD_NUMBER) +// +// IMPORTANT: Don't access these revisions directly. They can be +// accessed via, the RevGetXxxxx rouines. +// + +#define REV_AS_LONGWORD \ + ((REV_MAJOR << 24) | (REV_MINOR << 16) | (REV_TYPE << 8) | (REV_DASH)) + + + +#ifndef BIOS + +// +// Enumerate the types of product levels we can have +// +enum { + RevType_Devo=1, // Development mode, testing all of latest + RevType_Alpha, // Alpha - Internal field test + RevType_Beta, // Beta - External field test + RevType_Release // Release - Retail version +}; + +// +// Define the basic structure for all revision information. Note +// that the ordering of the components is such that they should +// always increase. dash will be updated the most, then the version +// type, then minor and major. +// +typedef struct { + union { + struct { + unsigned char dash; // Dash version number + unsigned char type; // Type, 1=Devo, 2=Alpha, 3=Beta, 4=Release + unsigned char minor;// Minor version minor + unsigned char major;// Major version number + } comp; // Components to external viewed rev number + unsigned long ul; // External revision as single 32-bit value + } external; // External revision number (union) + unsigned long buildNumber; // Automatically generated build number +} FsaRevision; + + +// +// Define simple routines to get basic revision information. The +// definitions should never be accessed directly. These routines +// are meant to be used to access all relevant information no matter +// how simple. +// + +static inline unsigned long RevGetBuildNumber(void) {return REV_BUILD_NUMBER;} +static inline unsigned long RevGetExternalRev(void) {return REV_AS_LONGWORD;} + +// +// Enumerate different components that may have to check +// compatibility. This list of components can be changed +// at any time. +// +// IMPORTANT: ONLY add to the END of this enum structure. Otherwise, +// incompatibilities between component rev checking will +// cause wrong checking results. +// +typedef enum { + RevApplication = 1, // Any user End application + RevDkiCli, // ADAPTEC proprietary interface (knows FIBs) + RevNetService, // Network Service Revision (under API) + RevApi, // ADAPTEC User mode API + RevFileSysDriver, // FSA File System Driver + RevMiniportDriver, // FSA File System Miniport Driver + RevAdapterSW, // Adapter Software (or NT Simulator) + RevMonitor, // Monitor for adapter hardware (MON960 for now) + RevRemoteApi // The remote API. + // ALWAYS ADD NEW COMPONENTS HERE - AT END +} RevComponent; + +// +// Define a structure so that we can create a compatibility table. +// +typedef struct { + RevComponent A,B; + unsigned long BuildNumOfB_RequiredByA; + unsigned long BuildNumOfA_RequiredByB; +} RevCompareElement; + +// +// Now, define the table. This table should only be included once, +// in one program. If it is linked from 2 modules, there will likely +// be a multiply defined symbol error from the linker. +// +// To fix this problem, REV_REFERENCE_ONLY can be defined. This will +// allow access to the revision information table without a redefinition +// of the tables. +// +extern const int RevCompareTableLength; + +extern const RevCompareElement RevCompareTable[]; + +/********************************************************************\ +* Routine: RevCheckCompatibility(callerComp,compB,compB_BuildNumber) +* +* The following routine is used to check compatibility between +* the calling component and a component that has some dependencies +* on it. If this routine returns REV_FALSE, it is expected that the caller +* will send an appropriate incompatibility message and stop. +* +* This routine is only meant to check for compatibility in the +* absolute sense. If code wishes to execute a different path based +* on the CompB_BuildNumber, then this routine is not useful. The +* routine RevGetBuildNumber can be used to get the calling module's +* current build number for a comparison check. +* +* The return value is REV_TRUE, if compatibility is possible, and REV_FALSE +* if the components are definitely not compatible, or there is an +* error when trying to figure it out. To be more specific: +* +* 1) REV_TRUE if component B is newer than calling component. (In this +* case, the revision check done by component B with respect to +* this component will give the real compatibility information. +* It is the only one with the knowledge, since this component +* could not look into the future.) +* 2) REV_TRUE if calling component is more recent and table shows okay +* 3) REV_FALSE if calling component more recent and table show not okay +* 4) REV_FALSE if calling component is more recent and table entry to +* check does not exist. +* +* Note that the CompB_BuildNumber must be attained by the calling +* routine through some mechanism done by the caller. +* +* Input: +* +* callerComp - Name of component making this call +* compB - Name of component to check compatibility with +* compB_BuildNumber - Build number to component B +* +* Output: +* +* None +* +* Return Value: +* +* REV_TRUE - Component compatibility is possible, continue as usual. compB +* must give true compatibility information. +* REV_FALSE - Incompatible components, notify and end +* +\********************************************************************/ +static inline REV_BOOL RevCheckCompatibility( + RevComponent callerComp, + RevComponent compB, + unsigned long compB_BuildNumber) +{ + int i; + unsigned long RevForB; + + // + // Compatibility check is possible, so we should continue. When + // compB makes this call in its own component, it will get the + // true compatibility information, since only it can know. + // + if (RevGetBuildNumber() < compB_BuildNumber) return REV_TRUE; + + // + // Go through rev table. When the components are found in the + // same table entry, return the approprate number. + // + for (i=0; i= RevForB); + } + } else if (RevCompareTable[i].B == callerComp) { + if (RevCompareTable[i].A == compB) { + RevForB = RevCompareTable[i].BuildNumOfA_RequiredByB; + return (compB_BuildNumber >= RevForB); + } + } + } + + // + // Uh oh! No relevant table entry was found (this should never + // happen). + // + return REV_FALSE; +} + + +// +// Now create a structure that can be used by a FIB to check +// compatibility. +// +typedef struct _RevCheck { + RevComponent callingComponent; + FsaRevision callingRevision; +} RevCheck; + +typedef struct _RevCheckResp { + REV_BOOL possiblyCompatible; + FsaRevision adapterSWRevision; +} RevCheckResp; + +#endif /* bios */ +#endif /* _REVISION_H */ + +// +// The following allows for inclusion of revision.h in other h +// files. when you include this file in another h file, simply +// define REV_REFERENCE_ONLY. This will be undefined later, so that +// the single C file inclusion in the module will be used to +// implement the global structures. +// +#ifndef REV_REFERENCE_ONLY +#ifndef _REVISION_H_GLOBAL +#define _REVISION_H_GLOBAL + + + +// +// The following array is the table of compatibility. This table +// can be modified in two ways: +// +// 1) A component which has an incompatible change done to +// it, can get a new build number. +// +// 2) A new component can be added, requiring more entries +// to be place into this table. +// +// +// In case (1), you must change the revision number in the appropriate +// column, based on which component absolutely requires an upgrade. +// +// Example: A new FIB used by the API, in build number 105 +// {RevApi, RevAdapterSW, 100, 100} +// ---> would be changed to <--- +// {RevApi, RevAdapterSW, 105, 100} +// +// Example: A structure is changed for a FIB that only the API uses +// {RevApi, RevAdapterSW, 100, 100} +// ---> would be changed to <--- +// {RevApi, RevAdapterSW, 105, 105} +// +// +// In case (2), the less common case, the enumerated list of +// components must be changed to include the new component. Then +// entries need to be placed into this table. +// +// Since the revisions must be communicated between the two +// components, it is likely that you would need to put in the +// current build number for both columns. That is the recommended +// way to start revision test. +// +const RevCompareElement RevCompareTable[] = { + // Component A Component B MinBForA MinAForB + // ----------- ----------- -------- -------- + {RevApplication, RevApi, 2120, 2120 }, + {RevDkiCli, RevApi, 2120, 2120 }, + {RevDkiCli, RevFileSysDriver, 257, 257 }, + {RevDkiCli, RevMiniportDriver, 257, 257 }, + {RevDkiCli, RevAdapterSW, 257, 257 }, + {RevApi, RevFileSysDriver, 2120, 2120 }, + {RevApi, RevMiniportDriver, 2120, 2120 }, + {RevApi, RevAdapterSW, 2120, 2120 }, + {RevApi, RevNetService, 2120, 2120 }, + {RevFileSysDriver, RevMiniportDriver, 100, 100 }, + {RevFileSysDriver, RevAdapterSW, 257, 257 }, + {RevMiniportDriver, RevAdapterSW, 257, 257 }, + {RevMiniportDriver, RevMonitor, 100, 100 }, + {RevApi, RevNetService, 2120, 2120 }, + {RevApi, RevRemoteApi, 2120, 2120 }, + {RevNetService, RevRemoteApi, 2120, 2120 } +}; + +const int RevCompareTableLength = sizeof(RevCompareTable)/sizeof(RevCompareElement); + +#endif /* _REVISION_H_GLOBAL */ +#endif /* REV_REFERENCE_ONLY */ +#undef REV_REFERENCE_ONLY + + + + + + + diff --git a/drivers/scsi/aacraid/include/rx.h b/drivers/scsi/aacraid/include/rx.h new file mode 100644 index 000000000000..4ca443208705 --- /dev/null +++ b/drivers/scsi/aacraid/include/rx.h @@ -0,0 +1,53 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.h + * + * Abstract: Prototypes and data structures unique to the Rx based controller board. + * + * + --*/ + + +typedef struct _Rx_ADAPTER_EXTENSION { + // + // The following must be first. + // + PPCI_MINIPORT_COMMON_EXTENSION Common; + struct _Rx_ADAPTER_EXTENSION *Next; // Next adapter miniport structure + u16 LocalMaskInterruptControl; + PRx_DEVICE_REGISTERS Device; +} Rx_ADAPTER_EXTENSION; + +typedef Rx_ADAPTER_EXTENSION *PRx_ADAPTER_EXTENSION; + +/* + * + */ + +#define Rx_READ_UCHAR(AEP, CSR) *(volatile unsigned char *) &((AEP)->Device->CSR) +#define Rx_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR) +#define Rx_WRITE_UCHAR(AEP, CSR, Value) *(volatile unsigned char *) &((AEP)->Device->CSR) = (Value) +#define Rx_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value) + +void RxInterruptAdapter(void *arg1); +void RxNotifyAdapter(void *arg1, HOST_2_ADAP_EVENT AdapterEvent); +void RxResetDevice(void *arg1); + diff --git a/drivers/scsi/aacraid/include/rxcommon.h b/drivers/scsi/aacraid/include/rxcommon.h new file mode 100644 index 000000000000..b4ef43146472 --- /dev/null +++ b/drivers/scsi/aacraid/include/rxcommon.h @@ -0,0 +1,94 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rxcommon.h + * + * Abstract: Structures and defines for the i960 Rx chip. + * + * + --*/ + +#ifndef _Rx_COMMON_H_ +#define _Rx_COMMON_H_ + +// +// Rx Message Unit Registers +// + +typedef volatile struct _StructRxMURegisters { + // Local | PCI* | Name + // | | + u32 ARSR; // 1300h | 00h | APIC Register Select Register + u32 reserved0; // 1304h | 04h | Reserved + u32 AWR; // 1308h | 08h | APIC Window Register + u32 reserved1; // 130Ch | 0Ch | Reserved + u32 IMRx[2]; // 1310h | 10h | Inbound Message Registers + u32 OMRx[2]; // 1318h | 18h | Outbound Message Registers + u32 IDR; // 1320h | 20h | Inbound Doorbell Register + u32 IISR; // 1324h | 24h | Inbound Interrupt Status Register + u32 IIMR; // 1328h | 28h | Inbound Interrupt Mask Register + u32 ODR; // 132Ch | 2Ch | Outbound Doorbell Register + u32 OISR; // 1330h | 30h | Outbound Interrupt Status Register + u32 OIMR; // 1334h | 34h | Outbound Interrupt Mask Register + // * Must access trhough ATU Inbound Translation Window +}Rx_MU_CONFIG; + +typedef Rx_MU_CONFIG *PRx_MU_CONFIG; + +typedef volatile struct _Rx_Inbound { + u32 Mailbox[8]; +}Rx_Inbound; + +typedef Rx_Inbound *PRx_Inbound; + +#define InboundMailbox0 IndexRegs.Mailbox[0] +#define InboundMailbox1 IndexRegs.Mailbox[1] +#define InboundMailbox2 IndexRegs.Mailbox[2] +#define InboundMailbox3 IndexRegs.Mailbox[3] +#define InboundMailbox4 IndexRegs.Mailbox[4] + +#define INBOUNDDOORBELL_0 0x00000001 +#define INBOUNDDOORBELL_1 0x00000002 +#define INBOUNDDOORBELL_2 0x00000004 +#define INBOUNDDOORBELL_3 0x00000008 +#define INBOUNDDOORBELL_4 0x00000010 +#define INBOUNDDOORBELL_5 0x00000020 +#define INBOUNDDOORBELL_6 0x00000040 + +#define OUTBOUNDDOORBELL_0 0x00000001 +#define OUTBOUNDDOORBELL_1 0x00000002 +#define OUTBOUNDDOORBELL_2 0x00000004 +#define OUTBOUNDDOORBELL_3 0x00000008 +#define OUTBOUNDDOORBELL_4 0x00000010 + +#define InboundDoorbellReg MUnit.IDR +#define OutboundDoorbellReg MUnit.ODR + +typedef struct _Rx_DEVICE_REGISTERS { + Rx_MU_CONFIG MUnit; // 1300h - 1334h + u32 reserved1[6]; // 1338h - 134ch + Rx_Inbound IndexRegs; +} Rx_DEVICE_REGISTERS; + +typedef Rx_DEVICE_REGISTERS *PRx_DEVICE_REGISTERS; + +#endif // _Rx_COMMON_H_ + + diff --git a/drivers/scsi/aacraid/include/sap1.h b/drivers/scsi/aacraid/include/sap1.h new file mode 100644 index 000000000000..109066210749 --- /dev/null +++ b/drivers/scsi/aacraid/include/sap1.h @@ -0,0 +1,57 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1.h + * + * Abstract: Prototypes and data structures unique to the Strong Arm based controller board. + * + * + --*/ + +#define Sa_MINIPORT_REVISION 1 + +typedef struct _Sa_ADAPTER_EXTENSION { + // + // The following must be first. + // + PPCI_MINIPORT_COMMON_EXTENSION Common; + struct _Sa_ADAPTER_EXTENSION *Next; // Next adapter miniport structure + u32 LocalMaskInterruptControl; + PSa_DEVICE_REGISTERS Device; +} Sa_ADAPTER_EXTENSION; + +typedef Sa_ADAPTER_EXTENSION *PSa_ADAPTER_EXTENSION; + + +/* + * + */ + +#define Sa_READ_USHORT(AEP, CSR) *(volatile unsigned short *) &((AEP)->Device->CSR) +#define Sa_READ_ULONG(AEP, CSR) *(volatile unsigned int *) &((AEP)->Device->CSR) +#define Sa_WRITE_USHORT(AEP, CSR, Value) *(volatile unsigned short *) &((AEP)->Device->CSR) = (Value) +#define Sa_WRITE_ULONG(AEP, CSR, Value) *(volatile unsigned int *) &((AEP)->Device->CSR) = (Value) + + +void SaInterruptAdapter(void* arg1); +void SaNotifyAdapter(void* arg1,HOST_2_ADAP_EVENT AdapterEvent); +void SaResetDevice(void* arg1); + + diff --git a/drivers/scsi/aacraid/include/sap1common.h b/drivers/scsi/aacraid/include/sap1common.h new file mode 100644 index 000000000000..7a3028d48822 --- /dev/null +++ b/drivers/scsi/aacraid/include/sap1common.h @@ -0,0 +1,105 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1common.h + * + * Abstract: Structures and defines for the Drawbridge and StrongArm110 chip. + * + --*/ + +#ifndef _Sa_COMMON_H_ +#define _Sa_COMMON_H_ + + +// +// SaP1 Message Unit Registers +// + +typedef volatile struct _StructSaDrawbridge_CSR_RegisterMap { + // Offset | Name + u32 reserved[10]; // 00h-27h | Reserved + u8 LUT_Offset; // 28h | Looup Table Offset + u8 reserved1[3]; // 29h-2bh | Reserved + u32 LUT_Data; // 2ch | Looup Table Data + u32 reserved2[26]; // 30h-97h | Reserved + u16 PRICLEARIRQ; // 98h | Primary Clear Irq + u16 SECCLEARIRQ; // 9ah | Secondary Clear Irq + u16 PRISETIRQ; // 9ch | Primary Set Irq + u16 SECSETIRQ; // 9eh | Secondary Set Irq + u16 PRICLEARIRQMASK; // a0h | Primary Clear Irq Mask + u16 SECCLEARIRQMASK; // a2h | Secondary Clear Irq Mask + u16 PRISETIRQMASK; // a4h | Primary Set Irq Mask + u16 SECSETIRQMASK; // a6h | Secondary Set Irq Mask + u32 MAILBOX0; // a8h | Scratchpad 0 + u32 MAILBOX1; // ach | Scratchpad 1 + u32 MAILBOX2; // b0h | Scratchpad 2 + u32 MAILBOX3; // b4h | Scratchpad 3 + u32 MAILBOX4; // b8h | Scratchpad 4 + u32 MAILBOX5; // bch | Scratchpad 5 + u32 MAILBOX6; // c0h | Scratchpad 6 + u32 MAILBOX7; // c4h | Scratchpad 7 + + u32 ROM_Setup_Data; // c8h | Rom Setup and Data + u32 ROM_Control_Addr; // cch | Rom Control and Address + + u32 reserved3[12]; // d0h-ffh | reserved + u32 LUT[64]; // 100h-1ffh| Lookup Table Entries + + // + // TO DO + // need to add DMA, I2O, UART, etc registers form 80h to 364h + // + +}Sa_Drawbridge_CSR; + +typedef Sa_Drawbridge_CSR *PSa_Drawbridge_CSR; + +#define Mailbox0 SaDbCSR.MAILBOX0 +#define Mailbox1 SaDbCSR.MAILBOX1 +#define Mailbox2 SaDbCSR.MAILBOX2 +#define Mailbox3 SaDbCSR.MAILBOX3 +#define Mailbox4 SaDbCSR.MAILBOX4 + +#define Mailbox7 SaDbCSR.MAILBOX7 + +#define DoorbellReg_p SaDbCSR.PRISETIRQ +#define DoorbellReg_s SaDbCSR.SECSETIRQ +#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ + +#define DOORBELL_0 0x00000001 +#define DOORBELL_1 0x00000002 +#define DOORBELL_2 0x00000004 +#define DOORBELL_3 0x00000008 +#define DOORBELL_4 0x00000010 +#define DOORBELL_5 0x00000020 +#define DOORBELL_6 0x00000040 + +#define PrintfReady DOORBELL_5 +#define PrintfDone DOORBELL_5 + +typedef struct _Sa_DEVICE_REGISTERS { + Sa_Drawbridge_CSR SaDbCSR; // 98h - c4h +} Sa_DEVICE_REGISTERS; + +typedef Sa_DEVICE_REGISTERS *PSa_DEVICE_REGISTERS; + + +#endif // _Sa_COMMON_H_ + diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c new file mode 100644 index 000000000000..695fe6cb4528 --- /dev/null +++ b/drivers/scsi/aacraid/linit.c @@ -0,0 +1,939 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * linit.c + * + * Abstract: Linux Driver entry module for Adaptec RAID Array Controller + * + * Provides the following driver entry points: + * AAC_DetectHostAdapter() + * AAC_ReleaseHostAdapter() + * AAC_QueueCommand() + * AAC_ResetCommand() + * AAC_BIOSDiskParameters() + * AAC_ProcDirectoryInfo() + * + --*/ + +/*------------------------------------------------------------------------------ + * D E F I N E S + *----------------------------------------------------------------------------*/ +#define AAC_DRIVER_VERSION "0.1.1" +#define AAC_DRIVER_BUILD_DATE __DATE__ +#define MAX_DRIVER_QUEUE_DEPTH 500 + +/*------------------------------------------------------------------------------ + * I N C L U D E S + *----------------------------------------------------------------------------*/ +#include "osheaders.h" + +#include "AacGenericTypes.h" + +#ifdef MODULE +#include +#endif +#include "sd.h" +#include "linit.h" +#include "aac_unix_defs.h" +#include "fsatypes.h" +#include "comstruc.h" +#include "fsaport.h" +#include "pcisup.h" +#include "port.h" + +/*------------------------------------------------------------------------------ + * G L O B A L S + *----------------------------------------------------------------------------*/ +extern FSA_MINIPORT MiniPorts[]; +extern int CommPrinting; +extern char DescriptionString[]; +extern char devicestr[]; + +/*------------------------------------------------------------------------------ + * M O D U L E G L O B A L S + *----------------------------------------------------------------------------*/ +aac_options_t g_options = { CMN_ERR_LEVEL, 0 }; // default message_level + +char g_DriverName[] = { "aacraid" }; +#define module_options aacraid_options +static char * aacraid_options = NULL; + +/* AAC_ProcDirectoryEntry is the /proc/scsi directory entry.*/ +static struct proc_dir_entry AAC_ProcDirectoryEntry = { + PROC_SCSI_SCSI, 3, "aacraid", S_IFDIR | S_IRUGO | S_IXUGO, 2, + 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +PCI_MINIPORT_COMMON_EXTENSION *g_CommonExtensionPtrArray[ MAXIMUM_NUM_ADAPTERS ]; + +unsigned g_HostAdapterCount = 0; +unsigned g_chardev_major = 0; +int g_single_command_done = FALSE; + +/*------------------------------------------------------------------------------ + * F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ + +int AacHba_Ioctl(PCI_MINIPORT_COMMON_EXTENSION *CommonExtension,int cmd, void *arg); +int AacHba_ProbeContainers(PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr); +int AacHba_DoScsiCmd(Scsi_Cmnd *scsi_cmnd_ptr, int wait); +void AacHba_DetachAdapter(void *AdapterArg ); +int AacHba_ClassDriverInit(PCI_MINIPORT_COMMON_EXTENSION * CommonExtensionPtr); +void AacHba_AbortScsiCommand(Scsi_Cmnd *scsi_cmnd_ptr); + + +/*------------------------------------------------------------------------------ + * L O C A L F U N C T I O N P R O T O T Y P E S + *----------------------------------------------------------------------------*/ +static int parse_keyword(char ** str_ptr, char * keyword ); +static void AAC_ParseDriverOptions(char * cmnd_line_options_str); +static void AAC_AnnounceDriver(void); +int AAC_ChardevIoctl(struct inode * inode_ptr, struct file * file_ptr, unsigned int cmd, unsigned long arg); +int AAC_ChardevOpen(struct inode * inode_ptr, struct file * file_ptr ); +int AAC_ChardevRelease(struct inode * inode_ptr, struct file * file_ptr ); + +struct file_operations AAC_fops = { + NULL, // lseek + NULL, // read + NULL, // write + NULL, // readdir + NULL, // poll + AAC_ChardevIoctl, // ioctl + NULL, // mmap + AAC_ChardevOpen, // open + NULL, // flush + AAC_ChardevRelease, // release + NULL, // fsync + NULL, // fasync + NULL, // check media change + NULL, // revalidate + NULL // lock +}; + +/*------------------------------------------------------------------------------ + * F U N C T I O N S + *----------------------------------------------------------------------------*/ +/*------------------------------------------------------------------------------ + AAC_AnnounceDriver() + + Announce the driver name, version and date. + *----------------------------------------------------------------------------*/ + +static void AAC_AnnounceDriver( void ) +{ + printk(KERN_INFO "%s, %s\n", "aacraid raid driver version", AAC_DRIVER_BUILD_DATE ); + schedule(); /* ??? !!! */ +} + + +/*------------------------------------------------------------------------------ + AAC_DetectHostAdapter() + + Probe for AAC Host Adapters initialize, register, and report the + configuration of each AAC Host Adapter found. + + Preconditions: + Postconditions: + - Returns the number of adapters successfully initialized and + registered. + - Initialize all data necessary for this particular SCSI driver. + Notes: + The detect routine must not call any of the mid level functions + to queue commands because things are not guaranteed to be set + up yet. The detect routine can send commands to the host adapter + as long as the program control will not be passed to scsi.c in + the processing of the command. Note especially that + scsi_malloc/scsi_free must not be called. + *----------------------------------------------------------------------------*/ + +int AAC_DetectHostAdapter(Scsi_Host_Template *HostTemplate) +{ + int index; + int ContainerId; + uint16_t vendor_id, device_id, sub_vendor_id, sub_system_id; + struct Scsi_Host *host_ptr; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + struct pci_dev *dev = NULL; + extern int NumMiniPorts; + fsadev_t *fsa_dev_ptr; + char *DeviceName; + struct pci_dev *devp; + int first_index, last_index, increment; + CommPrinting = TRUE; + + AAC_AnnounceDriver(); + if( module_options != NULL ) + AAC_ParseDriverOptions( module_options ); + + // NumMiniPorts & MiniPorts[] defined in aacid.c + if (g_options.reverse_scan == 0) { + first_index = 0; + last_index = NumMiniPorts; + increment = 1; + } else { + first_index = NumMiniPorts -1; + last_index = -1; + increment = -1; + } + + for( index = first_index; index != last_index; index += increment ) + { + device_id = MiniPorts[index].DeviceId; + vendor_id = MiniPorts[index].VendorId; + DeviceName = MiniPorts[index].DeviceName; + cmn_err(CE_DEBUG, "Checking %s %x/%x/%x/%x", + DeviceName, + vendor_id, + device_id, + MiniPorts[index].SubVendorId, + MiniPorts[index].SubSystemId); + + + // pci_find_device traverses the pci_devices linked list for devices + // with matching vendor and device ids. + + dev = NULL; // start from beginning of list + while( ( dev = pci_find_device( vendor_id, device_id, dev ) ) ) + { + if( pci_read_config_word( dev, PCI_SUBSYSTEM_VENDOR_ID, &sub_vendor_id ) ){ + cmn_err(CE_WARN, "pci_read_config_word SUBSYS_VENDOR_ID failed"); + break; + } + if( pci_read_config_word( dev, PCI_SUBSYSTEM_ID, &sub_system_id ) ){ + cmn_err(CE_WARN, "pci_read_config_work SUBSYSTEM_ID failed"); + break; + } + + cmn_err(CE_DEBUG, " found: %x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id); + if( ( sub_vendor_id != MiniPorts[index].SubVendorId ) || + ( sub_system_id != MiniPorts[index].SubSystemId ) ){ + continue; + } + + printk(KERN_INFO "%s device detected\n", DeviceName ); + // cmn_err(CE_WARN, "%x/%x/%x/%x", vendor_id, device_id, sub_vendor_id, sub_system_id); + + // Increment the host adapter count + g_HostAdapterCount++; + + // scsi_register() allocates memory for a Scsi_Hosts structure and + // links it into the linked list of host adapters. This linked list + // contains the data for all possible scsi hosts. + // This is similar to the Scsi_Host_Template, except that we have + // one entry for each actual physical host adapter on the system, + // stored as a linked list. If there are two AAC boards, then we + // will need to make two Scsi_Host entries, but there will be only + // one Scsi_Host_Template entry. The second argument to scsi_register() + // specifies the size of the extra memory we want to hold any device + // specific information. + host_ptr = scsi_register( HostTemplate, + sizeof( PCI_MINIPORT_COMMON_EXTENSION ) ); + + // These three parameters can be used to allow for wide SCSI + // and for host adapters that support multiple buses. + host_ptr->max_id = 17; + host_ptr->max_lun = 8; + host_ptr->max_channel = 1; + + host_ptr->irq = dev->irq; // Adapter IRQ number + host_ptr->base = ( char * )(dev->base_address[0] & ~0xff); + + cmn_err( CE_DEBUG, "Device base address = 0x%lx [0x%lx]", host_ptr->base, dev->base_address[0] ); + cmn_err( CE_DEBUG, "Device irq = 0x%lx", dev->irq ); + + // The unique_id field is a unique identifier that must be assigned + // so that we have some way of identifying each host adapter properly + // and uniquely. For hosts that do not support more than one card in the + // system, this does not need to be set. It is initialized to zero in + // scsi_register(). This is the value returned from OsGetDeviceInstance(). + host_ptr->unique_id = g_HostAdapterCount - 1; + + host_ptr->this_id = 16; // SCSI Id for the adapter itself + + // Set the maximum number of simultaneous commands supported by the driver. + host_ptr->can_queue = MAX_DRIVER_QUEUE_DEPTH; + + // Define the maximum number of scatter/gather elements supported by + // the driver. + host_ptr->sg_tablesize = 17; + + host_ptr->cmd_per_lun = 1; // untagged queue depth + + // This function is called after the device list has been built to find + // tagged queueing depth supported for each device. + host_ptr->select_queue_depths = AAC_SelectQueueDepths; + + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata; + + // attach a pointer back to Scsi_Host + CommonExtensionPtr->OsDep.scsi_host_ptr = host_ptr; + CommonExtensionPtr->OsDep.MiniPortIndex = index; + + // Initialize the ordinal number of the device to -1 + fsa_dev_ptr = &( CommonExtensionPtr->OsDep.fsa_dev ); + for( ContainerId = 0; ContainerId < MAXIMUM_NUM_CONTAINERS; ContainerId++ ) + fsa_dev_ptr->ContainerDevNo[ContainerId] = -1; + + // Call initialization routine + if( ( *MiniPorts[index].InitRoutine ) + ( CommonExtensionPtr, host_ptr->unique_id, dev->bus->number, 0 ) != 0 ) + { + // device initialization failed + cmn_err( CE_WARN, "%s:%d device initialization failed", DeviceName, host_ptr->unique_id ); + scsi_unregister( host_ptr ); + g_HostAdapterCount--; + } + else + { + cmn_err( CE_NOTE, "%s:%d device initialization successful", DeviceName, host_ptr->unique_id ); + AacHba_ClassDriverInit( CommonExtensionPtr ); + cmn_err(CE_NOTE, "%d:%d AacHba_ClassDriverInit complete", DeviceName, host_ptr->unique_id); + AacHba_ProbeContainers( CommonExtensionPtr ); + cmn_err( CE_DEBUG, "Probe containers completed" ); + g_CommonExtensionPtrArray[ g_HostAdapterCount - 1 ] = CommonExtensionPtr; + // OsSleep( 1 ); + } + } + } + + if( g_HostAdapterCount ) + if( !( g_chardev_major = register_chrdev( 0, devicestr, &AAC_fops ) ) ) + cmn_err( CE_WARN, "%s: unable to register %s device", DeviceName, devicestr); + + HostTemplate->present = g_HostAdapterCount; // # of cards of this type found + return( g_HostAdapterCount ); +} + + +/*------------------------------------------------------------------------------ + AAC_ReleaseHostAdapter() + + Release all resources previously acquired to support a specific Host + Adapter and unregister the AAC Host Adapter. + *----------------------------------------------------------------------------*/ +int AAC_ReleaseHostAdapter(struct Scsi_Host *host_ptr) +/*----------------------------------------------------------------------------*/ +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_ReleaseHostAdapter" ); + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )host_ptr->hostdata; + + // kill any threads we started + kill_proc(CommonExtensionPtr->OsDep.thread_pid, SIGKILL, 0); + + // Call the comm layer to detach from this adapter + AacHba_DetachAdapter( CommonExtensionPtr->Adapter ); + + // remove interrupt binding + OsDetachInterrupt( CommonExtensionPtr->MiniPort ); + SaDetachDevice( CommonExtensionPtr ); + + // unregister adapter + scsi_unregister( host_ptr ); + + if( g_chardev_major ) + { + unregister_chrdev( g_chardev_major, devicestr ); + g_chardev_major = 0; + } + return( 0 ); // #REVISIT# return code +} + + +/*------------------------------------------------------------------------------ + AAC_QueueCommand() + + Queues a command for execution by the associated Host Adapter. + *----------------------------------------------------------------------------*/ + +int AAC_QueueCommand(Scsi_Cmnd *scsi_cmnd_ptr, void ( *CompletionRoutine )( Scsi_Cmnd * ) ) +{ + scsi_cmnd_ptr->scsi_done = CompletionRoutine; + // AacHba_DoScsiCmd() handles command processing, setting the + // result code and calling completion routine. +#ifdef SYNC_FIB + if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 1 ) ) // called with wait = TRUE +#else + if( AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 ) ) // called with wait = FALSE +#endif + cmn_err( CE_DEBUG, "AacHba_DoScsiCmd failed" ); + return 0; +} + + +/*------------------------------------------------------------------------------ + AAC_Done() + + Callback function for a non-queued command. + + Postconditions + Sets g_single_command done to TRUE + *----------------------------------------------------------------------------*/ + +static void AAC_Done( Scsi_Cmnd * scsi_cmnd_ptr ) +{ + g_single_command_done = TRUE; +} + + +/*------------------------------------------------------------------------------ + AAC_Command() + + Accepts a single command for execution by the associated Host Adapter. + + Postconditions + Returns an int where: + Byte 0 = SCSI status code + Byte 1 = SCSI 1 byte message + Byte 2 = host error return + Byte 3 = mid level error return + *----------------------------------------------------------------------------*/ + +int AAC_Command(Scsi_Cmnd *scsi_cmnd_ptr ) +{ + scsi_cmnd_ptr->scsi_done = AAC_Done; + cmn_err( CE_DEBUG, "AAC_Command" ); + + // AacHba_DoScsiCmd() handles command processing, setting the + // result code and calling completion routine. + g_single_command_done = FALSE; + + AacHba_DoScsiCmd( scsi_cmnd_ptr, 0 ); + while( !g_single_command_done ); + return( scsi_cmnd_ptr->result ); +} + + +/*------------------------------------------------------------------------------ + AAC_AbortCommand() + + Abort command if possible. + *----------------------------------------------------------------------------*/ + +int AAC_AbortCommand(Scsi_Cmnd *scsi_cmnd_ptr) +{ + int target = scsi_cmnd_ptr->target; + int hba = scsi_cmnd_ptr->host->unique_id; + int result = 0; + u16 interrupt_status; + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *name; + + cmn_err( CE_WARN, "%s:%d ABORT", g_DriverName, hba, target ); + AacHba_AbortScsiCommand( scsi_cmnd_ptr ); + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + name = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + + /* + cmn_err( CE_WARN, "%s:%d Unable to abort command to target %d - " + "command already completed", name, hba, target); + result = SCSI_ABORT_NOT_RUNNING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "no command found\n", name, hba, target); + result = SCSI_ABORT_NOT_RUNNING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "command reset\n", name, hba, target); + result = SCSI_ABORT_PENDING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d - " + "abort tag not supported\n", name, hba, target); + result = SCSI_ABORT_SNOOZE; + + cmn_err(CE_WARN, "%s:%d Aborting command to target %d - pending", + name, hba, target); + result = SCSI_ABORT_PENDING; + + cmn_err(CE_WARN, "%s:%d Unable to abort command to target %d", + name, hba, target); + result = SCSI_ABORT_BUSY; + + cmn_err(CE_WARN, "%s:%d Aborted command to target %d\n", + name, hba, target); + result = SCSI_ABORT_SUCCESS; + */ + + // Abort not supported yet + result = SCSI_ABORT_BUSY; + return result; +} + + +/*------------------------------------------------------------------------------ + AAC_ResetCommand() + + Reset command handling. + *----------------------------------------------------------------------------*/ + +int AAC_ResetCommand( struct scsi_cmnd *scsi_cmnd_ptr, unsigned int reset_flags ) +{ + int target = scsi_cmnd_ptr->target; + int hba = scsi_cmnd_ptr->host->unique_id; + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *name; + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( scsi_cmnd_ptr->host->hostdata ); + name = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + cmn_err( CE_WARN, "%s:%d RESET", name, hba, target ); + return SCSI_RESET_PUNT; +} + + +/*------------------------------------------------------------------------------ + AAC_DriverInfo() + + Returns the host adapter name + *----------------------------------------------------------------------------*/ + +const char *AAC_DriverInfo(struct Scsi_Host *host_ptr) +{ + PCI_MINIPORT_COMMON_EXTENSION *cep; + char *name; + + cep = ( PCI_MINIPORT_COMMON_EXTENSION * )( host_ptr->hostdata ); + name = MiniPorts[cep->OsDep.MiniPortIndex].DeviceName; + + cmn_err( CE_DEBUG, "AAC_DriverInfo" ); + return name; +} + + +/*------------------------------------------------------------------------------ + AAC_BIOSDiskParameters() + + Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk. + The default disk geometry is 64 heads, 32 sectors, and the appropriate + number of cylinders so as not to exceed drive capacity. In order for + disks equal to or larger than 1 GB to be addressable by the BIOS + without exceeding the BIOS limitation of 1024 cylinders, Extended + Translation should be enabled. With Extended Translation enabled, + drives between 1 GB inclusive and 2 GB exclusive are given a disk + geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive + are given a disk geometry of 255 heads and 63 sectors. However, if + the BIOS detects that the Extended Translation setting does not match + the geometry in the partition table, then the translation inferred + from the partition table will be used by the BIOS, and a warning may + be displayed. + *----------------------------------------------------------------------------*/ + +int AAC_BIOSDiskParameters(Scsi_Disk *scsi_disk_ptr, kdev_t device, int *parameter_ptr ) +{ + AAC_BIOS_DiskParameters_T *disk_parameters = ( AAC_BIOS_DiskParameters_T *)parameter_ptr; + struct buffer_head * buffer_head_ptr; + + cmn_err( CE_DEBUG, "AAC_BIOSDiskParameters" ); + + // Assuming extended translation is enabled - #REVISIT# + if( scsi_disk_ptr->capacity >= 2 * 1024 * 1024 ) // 1 GB in 512 byte sectors + { + if( scsi_disk_ptr->capacity >= 4 * 1024 * 1024 ) // 2 GB in 512 byte sectors + { + disk_parameters->heads = 255; + disk_parameters->sectors = 63; + } + else + { + disk_parameters->heads = 128; + disk_parameters->sectors = 32; + } + } + else + { + disk_parameters->heads = 64; + disk_parameters->sectors = 32; + } + + disk_parameters->cylinders = scsi_disk_ptr->capacity / + (disk_parameters->heads * disk_parameters->sectors); + + // Read the first 1024 bytes from the disk device + buffer_head_ptr = bread( MKDEV( MAJOR( device ), + MINOR( device ) & ~0x0F ), + 0, 1024 ); + + if( buffer_head_ptr == NULL ) + return( 0 ); + /* + If the boot sector partition table is valid, search for a partition + table entry whose end_head matches one of the standard geometry + translations ( 64/32, 128/32, 255/63 ). + */ + if( *( unsigned short * )( buffer_head_ptr->b_data + 0x1fe ) == 0xaa55 ) + { + struct partition *first_partition_entry = ( struct partition * )( buffer_head_ptr->b_data + 0x1be ); + struct partition *partition_entry = first_partition_entry; + int saved_cylinders = disk_parameters->cylinders; + int partition_number; + unsigned char partition_entry_end_head, partition_entry_end_sector; + + for( partition_number = 0; partition_number < 4; partition_number++ ) + { + partition_entry_end_head = partition_entry->end_head; + partition_entry_end_sector = partition_entry->end_sector & 0x3f; + + if( partition_entry_end_head == ( 64 - 1 ) ) + { + disk_parameters->heads = 64; + disk_parameters->sectors = 32; + break; + } + else if( partition_entry_end_head == ( 128 - 1 ) ) + { + disk_parameters->heads = 128; + disk_parameters->sectors = 32; + break; + } + else if( partition_entry_end_head == ( 255 - 1 ) ) + { + disk_parameters->heads = 255; + disk_parameters->sectors = 63; + break; + } + partition_entry++; + } + + if( partition_number == 4 ) + { + partition_entry_end_head = first_partition_entry->end_head; + partition_entry_end_sector = first_partition_entry->end_sector & 0x3f; + } + + disk_parameters->cylinders = scsi_disk_ptr->capacity / + (disk_parameters->heads * disk_parameters->sectors); + + if( partition_number < 4 && partition_entry_end_sector == disk_parameters->sectors) + { + if( disk_parameters->cylinders != saved_cylinders ) + cmn_err( CE_NOTE, "Adopting geometry: heads=%d, sectors=%d from partition table %d", + disk_parameters->heads, disk_parameters->sectors, partition_number ); + } + else if(partition_entry_end_head > 0 || partition_entry_end_sector > 0) + { + cmn_err( CE_NOTE, "Strange geometry: heads=%d, sectors=%d in partition table %d", + partition_entry_end_head + 1, partition_entry_end_sector, partition_number ); + cmn_err( CE_NOTE, "Using geometry: heads=%d, sectors=%d", + disk_parameters->heads, disk_parameters->sectors ); + } + } + brelse( buffer_head_ptr ); + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ProcDirectoryInfo() + + Implement /proc/scsi//. + Used to export driver statistics and other infos to the world outside + the kernel using the proc file system. Also provides an interface to + feed the driver with information. + + Postconditions + For reads + - if offset > 0 return 0 + - if offset == 0 write data to proc_buffer and set the start_ptr to + beginning of proc_buffer, return the number of characters written. + For writes + - writes currently not supported, return 0 + *----------------------------------------------------------------------------*/ +int AAC_ProcDirectoryInfo( + char *proc_buffer, // read/write buffer + char **start_ptr, // start of valid data in the buffer + off_t offset, // offset from the beginning of the imaginary file + int bytes_available, // bytes available + int host_no, // SCSI host number + int write ) // direction of dataflow: TRUE for writes, FALSE for reads +{ + int length = 0; + cmn_err( CE_DEBUG, "AAC_ProcDirectoryInfo" ); + + if(write || offset > 0) + return( 0 ); + *start_ptr = proc_buffer; + return( sprintf(&proc_buffer[length], "%s %d\n", "Raid Controller, scsi hba number", host_no ) ); +} + + + +/*------------------------------------------------------------------------------ + AAC_SelectQueueDepths() + + Selects queue depths for each target device based on the host adapter's + total capacity and the queue depth supported by the target device. + A queue depth of one automatically disables tagged queueing. + *----------------------------------------------------------------------------*/ + +void AAC_SelectQueueDepths(struct Scsi_Host * host_ptr, Scsi_Device * scsi_device_ptr ) +{ + Scsi_Device * device_ptr; + + cmn_err( CE_DEBUG, "AAC_SelectQueueDepths" ); + cmn_err( CE_DEBUG, "Device # Q Depth Online" ); + cmn_err( CE_DEBUG, "---------------------------" ); + for( device_ptr = scsi_device_ptr; device_ptr != NULL; device_ptr = device_ptr->next ) + if( device_ptr->host == host_ptr ) + { + device_ptr->queue_depth = 10; + cmn_err( CE_DEBUG, " %2d %d %d", + device_ptr->id, device_ptr->queue_depth, device_ptr->online ); + } +} + + +/*------------------------------------------------------------------------------ + AAC_SearchBiosSignature() + + Locate adapter signature in BIOS + *----------------------------------------------------------------------------*/ +int AAC_SearchBiosSignature( void ) +/*----------------------------------------------------------------------------*/ +{ + unsigned base; + unsigned namep; + int index; + int val; + char name_buf[32]; + int result = FALSE; + + for( base = 0xc8000; base < 0xdffff; base += 0x4000 ) + { + val = readb( base ); + if( val != 0x55 ) + continue; + + result = TRUE; + namep = base + 0x1e; + memcpy_fromio( name_buf, namep, 32 ); + name_buf[31] = '\0'; + } + return( result ); +} + + +/*------------------------------------------------------------------------------ + AAC_Ioctl() + + Handle SCSI ioctls + *----------------------------------------------------------------------------*/ + +int AAC_Ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg ) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_Ioctl" ); + CommonExtensionPtr = ( PCI_MINIPORT_COMMON_EXTENSION * )scsi_dev_ptr->host->hostdata; + return( AacHba_Ioctl( CommonExtensionPtr, cmd, arg ) ); +} + + + +/*------------------------------------------------------------------------------ + AAC_ChardevOpen() + + Handle character device open + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ + +int AAC_ChardevOpen(struct inode * inode_ptr, struct file * file_ptr ) +{ + unsigned minor_number; + cmn_err( CE_DEBUG, "AAC_ChardevOpen" ); + + // extract & check the minor number + minor_number = MINOR( inode_ptr->i_rdev ); + if( minor_number > ( g_HostAdapterCount - 1 ) ) + { + cmn_err( CE_WARN, "AAC_ChardevOpen: Minor number %d not supported", minor_number ); + return( -ENODEV ); + } + MOD_INC_USE_COUNT; + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ChardevRelease() + Handle character device release. + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ + +int AAC_ChardevRelease(struct inode * inode_ptr, struct file * file_ptr ) +{ + cmn_err( CE_DEBUG, "AAC_ChardevRelease" ); + MOD_DEC_USE_COUNT; + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + AAC_ChardevIoctl() + + Handle character device interface ioctls + + Preconditions: + Postconditions: + Returns 0 if successful, -ENODEV or -EINVAL otherwise + *----------------------------------------------------------------------------*/ + +int AAC_ChardevIoctl(struct inode * inode_ptr, struct file * file_ptr, unsigned int cmd, unsigned long arg ) +{ + unsigned minor_number; + PCI_MINIPORT_COMMON_EXTENSION *CommonExtensionPtr; + + cmn_err( CE_DEBUG, "AAC_ChardevIoctl" ); + + // check device permissions in file_ptr->f_mode ?? + + // extract & check the minor number + minor_number = MINOR( inode_ptr->i_rdev ); + if( minor_number > ( g_HostAdapterCount - 1 ) ) + { + cmn_err( CE_WARN, "AAC_ChardevIoctl: Minor number %d not supported", minor_number ); + return( -ENODEV ); + } + + // get device pointer + CommonExtensionPtr = g_CommonExtensionPtrArray[ minor_number ]; + + // dispatch ioctl - AacHba_Ioctl() returns zero on success + if( AacHba_Ioctl( CommonExtensionPtr, cmd, ( void * )arg ) ) + return( -EINVAL ); + + return( 0 ); +} + + +/*------------------------------------------------------------------------------ + parse_keyword() + + Look for the keyword in str_ptr + + Preconditions: + Postconditions: + If keyword found + - return true and update the pointer str_ptr. + otherwise + - return false + *----------------------------------------------------------------------------*/ + +static int parse_keyword(char ** str_ptr, char * keyword ) +{ + char * ptr = *str_ptr; + + while( *keyword != '\0' ) + { + char string_char = *ptr++; + char keyword_char = *keyword++; + + if ( ( string_char >= 'A' ) && ( string_char <= 'Z' ) ) + string_char += 'a' - 'Z'; + if( ( keyword_char >= 'A' ) && ( keyword_char <= 'Z' ) ) + keyword_char += 'a' - 'Z'; + if( string_char != keyword_char ) + return FALSE; + } + *str_ptr = ptr; + return TRUE; +} + + +/*------------------------------------------------------------------------------ + AAC_ParseDriverOptions() + + For modules the usage is: + insmod -f aacraid.o 'aacraid_options=""' + *----------------------------------------------------------------------------*/ + +static void AAC_ParseDriverOptions(char * cmnd_line_options_str) +{ + int message_level; + int reverse_scan; + char *cp; + char *endp; + + cp = cmnd_line_options_str; + + cmn_err(CE_DEBUG, "AAC_ParseDriverOptions: <%s>", cp); + + while( *cp ) { + if( parse_keyword( &cp, "message_level:" ) ) { + message_level = simple_strtoul( cp, 0, 0 ); + if( ( message_level < CE_TAIL ) && ( message_level >= 0 ) ) { + g_options.message_level = message_level; + cmn_err( CE_WARN, "%s: new message level = %d", g_DriverName, g_options.message_level ); + } + else { + cmn_err( CE_WARN, "%s: invalid message level = %d", g_DriverName, message_level ); + } + } else if (parse_keyword( &cp, "reverse_scan:" ) ) { + reverse_scan = simple_strtoul( cp, 0, 0 ); + if (reverse_scan) { + g_options.reverse_scan = 1; + cmn_err( CE_WARN, "%s: reversing device discovery order", g_DriverName, g_options.message_level ); + } + } + else { + cmn_err( CE_WARN, "%s: unknown command line option <%s>", g_DriverName, cp ); + } + + /* + * skip to next option, accept " ", ";", and "," as delimiters + */ + while ( *cp && (*cp != ' ') && (*cp != ';') && (*cp != ',')) + cp++; + if (*cp) /* skip over the delimiter */ + cp++; + } +} + + +/*------------------------------------------------------------------------------ + Include Module support if requested. + + To use the low level SCSI driver support using the linux kernel loadable + module interface we should initialize the global variable driver_interface + (datatype Scsi_Host_Template) and then include the file scsi_module.c. + This should also be wrapped in a #ifdef MODULE/#endif + *----------------------------------------------------------------------------*/ +#ifdef MODULE + +/* + The Loadable Kernel Module Installation Facility may pass us + a pointer to a driver specific options string to be parsed, + we assign this to options string. +*/ +MODULE_PARM( module_options, "s" ); + +EXPORT_NO_SYMBOLS; + +Scsi_Host_Template driver_template = AAC_HOST_TEMPLATE_ENTRY; + +#include "scsi_module.c" + +#endif diff --git a/drivers/scsi/aacraid/osddi.c b/drivers/scsi/aacraid/osddi.c new file mode 100644 index 000000000000..52dce9ca18da --- /dev/null +++ b/drivers/scsi/aacraid/osddi.c @@ -0,0 +1,362 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osddi.c + * + * Abstract: This file contains all the proceedures which use LINUX specific Device + * Driver Interfaces. + * + --*/ +#include "osheaders.h" + +#include + +#ifdef fsid_t +#undef fsid_t +#endif +#include "AacGenericTypes.h" +#include "aac_unix_defs.h" +#include "comstruc.h" +#include "monkerapi.h" +#include "protocol.h" +#include "fsafs.h" + +#include "sap1common.h" +#include "fsaport.h" +#include "pcisup.h" +#include "sap1.h" +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + + +void AacSaPciIsr(int irq, void *irq_data, struct pt_regs *regs); +void AacRxPciIsr(int irq, void *irq_data, struct pt_regs *regs); +unsigned SaPciIsr(PSa_ADAPTER_EXTENSION AdapterExtension); +unsigned RxPciIsr(PSa_ADAPTER_EXTENSION AdapterExtension); + + +/*----------------------------------------------------------------------------*/ + +void AfaCommInterruptHost(void *AdapterArg, ADAPTER_EVENT AdapterEvent ) +{ + PAFA_COMM_ADAPTER Adapter = ( PAFA_COMM_ADAPTER ) AdapterArg; + PCOMM_REGION CommRegion = Adapter->CommRegion; + + switch (AdapterEvent) { + + case HostNormRespQue: + OsSoftInterruptTrigger( CommRegion->HostNormRespQue.ConsumerRoutine ); + // #REVIEW# - what do we do with this + // if (FsaCommData.HardInterruptModeration) + // DisableInterrupt( Adapter, HostNormRespQue, TRUE ); + break; + + case AdapNormCmdNotFull: + OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc ); + break; + + case HostNormCmdQue: + OsSoftInterruptTrigger( CommRegion->HostNormCmdQue.ConsumerRoutine ); + break; + + case AdapNormRespNotFull: + OsSoftInterruptTrigger( CommRegion->QueueNotFullDpc ); + break; + + // #REVIEW# - what do we do with these + case HostHighCmdQue: + case HostHighRespQue: + case AdapHighCmdNotFull: + case AdapHighRespNotFull: + case SynchCommandComplete: + case AdapInternalError: + break; + } +} + + +// get the device name associated with this instance of the device +/*----------------------------------------------------------------------------*/ + +char *OsGetDeviceName(void *AdapterExtension ) +{ + return(((Sa_ADAPTER_EXTENSION *)AdapterExtension)->Common->OsDep.scsi_host_ptr->hostt->name); +} + + +/*----------------------------------------------------------------------------*/ + +int OsGetDeviceInstance(void *AdapterExtension ) +{ + return((int)((Sa_ADAPTER_EXTENSION *)AdapterExtension)->Common->OsDep.scsi_host_ptr->unique_id); +} + + +/*------------------------------------------------------------------------------ + OsMapDeviceRegisters() + + Postconditions: + Return zero on success non-zero otherwise. + *----------------------------------------------------------------------------*/ + +int OsMapDeviceRegisters(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + + CommonExtension = AdapterExtension->Common; + + if( AdapterExtension->Device = ( Sa_DEVICE_REGISTERS * ) + ioremap( ( unsigned long )CommonExtension->OsDep.scsi_host_ptr->base, 8192 ) ) + { + cmn_err( CE_DEBUG, "Device mapped to virtual address 0x%x", AdapterExtension->Device ); + return( 0 ); + } + else + { + cmn_err( CE_WARN, "OsMapDeviceRegisters: ioremap() failed" ); + return( 1 ); + } +} + + +/*------------------------------------------------------------------------------ + OsUnMapDeviceRegisters() + + Postconditions: + *----------------------------------------------------------------------------*/ + +void OsUnMapDeviceRegisters(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + iounmap((void *)AdapterExtension->Device); +} + + +/*----------------------------------------------------------------------------*/ + +int OsAttachInterrupt(Sa_ADAPTER_EXTENSION *AdapterExtension ,int WhichIsr) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + void *irq_data; + void (*Isr)(); + + CommonExtension = AdapterExtension->Common; + irq_data = (void *)AdapterExtension; + + switch (WhichIsr) + { + case SaISR: + Isr = AacSaPciIsr; + break; + case RxISR: + Isr = AacRxPciIsr; + break; + default: + cmn_err(CE_WARN, "OsAttachInterrupt: invalid ISR case: 0x%x", WhichIsr); + return FAILURE; + } + + if(request_irq(CommonExtension->OsDep.scsi_host_ptr->irq, // interrupt number + Isr, // handler function + SA_INTERRUPT|SA_SHIRQ, + "aacraid", + irq_data)) + { + cmn_err(CE_DEBUG, "OsAttachInterrupt: Failed for IRQ: 0x%x", + CommonExtension->OsDep.scsi_host_ptr->irq); + return(FAILURE); + } + return 0; +} + + +/*----------------------------------------------------------------------------*/ + +void AacSaPciIsr(int irq, void *irq_data, struct pt_regs *regs) +{ + // call the actual interrupt handler + SaPciIsr((Sa_ADAPTER_EXTENSION *)irq_data); +} + +/*----------------------------------------------------------------------------*/ +void AacRxPciIsr(int irq, void *irq_data, struct pt_regs *regs) +{ + // call the actual interrupt handler + RxPciIsr((Sa_ADAPTER_EXTENSION *)irq_data); +} + + +/*----------------------------------------------------------------------------*/ +void OsDetachInterrupt(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + void *irq_data; + + CommonExtension = AdapterExtension->Common; + irq_data = (void *)AdapterExtension; + + free_irq(CommonExtension->OsDep.scsi_host_ptr->irq, irq_data); +} + + +/*----------------------------------------------------------------------------*/ +void OsDetachDevice(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + OsUnMapDeviceRegisters( AdapterExtension ); + return 0; +} + +/*----------------------------------------------------------------------------*/ +u32 *OsAllocCommPhysMem(Sa_ADAPTER_EXTENSION *AdapterExtension, u32 size, u32 **virt_addr_pptr, u32 *phys_addr_ptr) +{ + if((*virt_addr_pptr = (u32 *)kmalloc(size,GFP_KERNEL))) + { + *phys_addr_ptr = virt_to_bus((volatile void *)*virt_addr_pptr); + if(!*phys_addr_ptr) + { + cmn_err(CE_WARN, "OsAllocCommPhysMem: OsVirtToPhys failed"); + } + return *virt_addr_pptr; + } + else + return NULL; +} + +OsAifKernelThread(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + struct fs_struct *fs; + int i; + struct task_struct *tsk; + + tsk = current; + + /* + * set up the name that will appear in 'ps' + * stored in task_struct.comm[16]. + */ + + sprintf(tsk->comm, "AIFd"); + // use_init_fs_context(); only exists in 2.2.13 onward. + lock_kernel(); + + /* + * we were started as a result of loading the module. + * free all of user space pages + */ + + exit_mm(tsk); + exit_files(tsk); + exit_fs(tsk); + + fs = init_task.fs; + tsk->fs = fs; + + tsk->session = 1; + tsk->pgrp = 1; + + if (fs) + atomic_inc(&fs->count); + + unlock_kernel(); + NormCommandThread(AdapterExtension); + /* NOT REACHED */ +} + +/*----------------------------------------------------------------------------*/ + +void OsStartKernelThreads(Sa_ADAPTER_EXTENSION *AdapterExtension) +{ + PCI_MINIPORT_COMMON_EXTENSION *CommonExtension; + AFA_COMM_ADAPTER *Adapter; + extern void NormCommandThread(void *Adapter); + + CommonExtension = AdapterExtension->Common; + Adapter = (AFA_COMM_ADAPTER *)CommonExtension->Adapter; + + // + // Start thread which will handle AdapterInititatedFibs from this adapter + // + CommonExtension->OsDep.thread_pid = kernel_thread((int (*)(void *))OsAifKernelThread, Adapter, 0 ); +} + +/*----------------------------------------------------------------------------*/ + +int AfaPortAllocateAndMapFibSpace(void * Arg1, PMAPFIB_CONTEXT MapFibContext ) +{ + void *BaseAddress; + u32 PhysAddress; + + if(!(BaseAddress = (u32 *)kmalloc(MapFibContext->Size, GFP_KERNEL))) + { + cmn_err( CE_WARN, "AfaPortAllocateAndMapFibSpace: OsAllocMemory failed" ); + return( FALSE ); + } + + PhysAddress = virt_to_bus(BaseAddress); + + MapFibContext->FibVirtualAddress = BaseAddress; + MapFibContext->FibPhysicalAddress = (void *)PhysAddress; + + return (TRUE); +} + +/*----------------------------------------------------------------------------*/ + +int AfaPortUnmapAndFreeFibSpace(void *Arg1, PMAPFIB_CONTEXT MapFibContext) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + kfree(MapFibContext->FibVirtualAddress); + return (TRUE); +} + +/*----------------------------------------------------------------------------*/ + +int AfaPortFreeAdapterCommArea(void * Arg1) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + kfree(CommonExtension->CommAddress); + return (TRUE); +} + + +/* ================================================================================ */ +/* + * Not sure if the functions below here ever get called in the current code + * These probably should be a different file. + */ +/* +ddi_dma_attr_t AfaPortDmaAttributes = { + //rpbfix : we may want something different for I/O + DMA_ATTR_V0, + 0, + 0xffffffff, + 0x0000ffff, + 1, + 1, + 1, + 0x0000ffff, + 0x0000ffff, + 17, + 512, + 0 +}; +*/ + diff --git a/drivers/scsi/aacraid/osfuncs.c b/drivers/scsi/aacraid/osfuncs.c new file mode 100644 index 000000000000..1a744e4ac9f7 --- /dev/null +++ b/drivers/scsi/aacraid/osfuncs.c @@ -0,0 +1,472 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * osfuncs.c + * + * Abstract: Holds all of the O/S specific interface functions. + * + --*/ + +#include "osheaders.h" + +//static LKINFO_DECL(fsa_locks, "fsa_locks",0); + +extern aac_options_t g_options; + +OS_SOFTINTR g_idle_task = { 0, 0, 0, 0 }; +struct wait_queue * g_wait_queue_ptr = NULL; +struct wait_queue g_wait; +int * OsIdleTask( void * data ); + + +//----------------------------------------------------------------------------- +// MUTEX functions + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsMutexInit( + OS_MUTEX *Mutex, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + Mutex->wq_ptr = NULL; + Mutex->lock_var = 0; + return ( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexDestroy( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexAcquire( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long time_stamp; + + time_stamp = jiffies; + + if( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 ) + { + if( in_interrupt() ) + panic( "OsMutexAcquire going to sleep at interrupt time\n" ); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &( Mutex->wq_ptr ), &wait ); + while( test_and_set_bit( 0, &( Mutex->lock_var ) ) != 0 ) + schedule(); + remove_wait_queue( &( Mutex->wq_ptr ), &wait ); + } + + if( ( jiffies - 1 ) > time_stamp ) + cmn_err( CE_WARN, "Mutex %ld locked out for %ld ticks", + Mutex, jiffies - time_stamp ); +} + + +/*----------------------------------------------------------------------------*/ +void OsMutexRelease( + OS_MUTEX *Mutex ) +/*----------------------------------------------------------------------------*/ +{ + if( test_and_clear_bit( 0, &( Mutex->lock_var ) ) == 0 ) + cmn_err( CE_WARN, "OsMutexRelease: mutex not locked" ); + wake_up_interruptible( &( Mutex->wq_ptr ) ); +} + +// see man hierarchy(D5) +#define FSA_LOCK 1 + +//----------------------------------------------------------------------------- +// Spinlock functions + +/*----------------------------------------------------------------------------*/ +OS_SPINLOCK * OsSpinLockAlloc( void ) +/*----------------------------------------------------------------------------*/ +{ + OS_SPINLOCK *SpinLock; + int i; + + SpinLock = ( OS_SPINLOCK * )kmalloc( sizeof( OS_SPINLOCK ), GFP_KERNEL ); + SpinLock->spin_lock = SPIN_LOCK_UNLOCKED; + for( i = 0; i < 8; i++ ) + SpinLock->cpu_lock_count[ i ] = 0; + return( SpinLock ); +} + + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsSpinLockInit( + OS_SPINLOCK *SpinLock, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + return( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockDestroy( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + kfree( SpinLock ); + SpinLock = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockAcquire( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + unsigned cpu_id, i; + + if( SpinLock ) + { + /* + if( OsSpinLockOwned( SpinLock ) ) + { + SpinLock->lockout_count++; + if( SpinLock->lockout_count > 200 ) + { + cmn_err( CE_WARN, "spin lock #%ld: lockout_count high", SpinLock ); + SpinLock->lockout_count = 0; + } + } + */ + cpu_id = smp_processor_id(); + if( SpinLock->cpu_lock_count[ cpu_id ] ) + panic( "CPU %d trying to acquire lock again: lock count = %d\n", + cpu_id, SpinLock->cpu_lock_count[ cpu_id ] ); + /* + for( i = 0; i < 8; i++ ) + if( SpinLock->cpu_lock_count[ i ] ) + panic( "Another CPU has the lock\n" ); + */ + spin_lock_irqsave( &( SpinLock->spin_lock ), SpinLock->cpu_flag ); + SpinLock->cpu_lock_count[ cpu_id ]++; + } + else + cmn_err( CE_WARN, "OsSpinLockAcquire: lock does not exist" ); +} + + +/*----------------------------------------------------------------------------*/ +void OsSpinLockRelease( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ + if( SpinLock ) + { + SpinLock->cpu_lock_count[ smp_processor_id() ]--; + spin_unlock_irqrestore( &( SpinLock->spin_lock ), SpinLock->cpu_flag ); + } + else + cmn_err( CE_WARN, "OsSpinLockRelease: lock does not exist" ); +} + + +/*----------------------------------------------------------------------------*/ +int OsSpinLockOwned( + OS_SPINLOCK *SpinLock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef __SMP__ + if( SpinLock->spin_lock.lock != 0 ) + return( 1 ); + else +#endif + return( 0 ); +} + + +//----------------------------------------------------------------------------- +// CvLock functions + +/*----------------------------------------------------------------------------*/ +OS_CVLOCK *OsCvLockAlloc( void ) +/*----------------------------------------------------------------------------*/ +{ + OS_CVLOCK *cv_lock; + +#ifdef CVLOCK_USE_SPINLOCK + cv_lock = OsSpinLockAlloc(); +#else + cv_lock = ( OS_CVLOCK * )kmalloc( sizeof( OS_CVLOCK ), GFP_KERNEL ); + cv_lock->wq_ptr = NULL; + cv_lock->lock_var = 0; +#endif + + return( cv_lock ); +} + + +/*----------------------------------------------------------------------------*/ +OS_STATUS OsCvLockInit( + OS_CVLOCK *cv_lock, + OS_SPINLOCK_COOKIE Cookie ) +/*----------------------------------------------------------------------------*/ +{ + return ( 0 ); +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockDestroy( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ + if( cv_lock ) + kfree( cv_lock ); + cv_lock = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockAcquire( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef CVLOCK_USE_SPINLOCK + OsSpinLockAcquire( cv_lock ); +#else + OsMutexAcquire( cv_lock ); +#endif +} + + +/*----------------------------------------------------------------------------*/ +void OsCvLockRelease( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ +#ifdef CVLOCK_USE_SPINLOCK + OsSpinLockRelease( cv_lock ); +#else + OsMutexRelease( cv_lock ); +#endif +} + + +/*----------------------------------------------------------------------------*/ +int OsCvLockOwned( + OS_CVLOCK *cv_lock ) +/*----------------------------------------------------------------------------*/ +{ + return( 1 ); +} + + +//----------------------------------------------------------------------------- +// Conditional variable functions + +/*----------------------------------------------------------------------------*/ +void OsCv_init ( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ + cv_ptr->lock_var = 1; + cv_ptr->wq_ptr = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_destroy( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_wait( + OS_CV_T *cv_ptr, + OS_CVLOCK *cv_lock_ptr ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + + if( in_interrupt() ) + panic( "OsCv_wait going to sleep at interrupt time\n" ); + + cv_ptr->type = TASK_UNINTERRUPTIBLE; + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockRelease( cv_lock_ptr ); + schedule(); + + while( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) + { + if( in_interrupt() ) + panic( "OsCv_wait going to sleep at interrupt time\n" ); + schedule(); + } + + remove_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockAcquire( cv_lock_ptr ); +} + + +/*----------------------------------------------------------------------------*/ +int OsCv_wait_sig( + OS_CV_T *cv_ptr, + OS_CVLOCK *cv_lock_ptr ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + unsigned long flags; + int signal_state = 1; + + if( in_interrupt() ) + panic( "OsCv_wait_sig going to sleep at interrupt time\n" ); + + cv_ptr->type = TASK_INTERRUPTIBLE; + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockRelease( cv_lock_ptr ); + schedule(); + + while( ( test_and_set_bit( 0, &( cv_ptr->lock_var ) ) != 0 ) && + ( !signal_pending( current ) ) ) + { + if( in_interrupt() ) + panic( "OsCv_wait_sig going to sleep at interrupt time\n" ); + schedule(); + } + + if( signal_pending( current ) ) + signal_state = 0; + + remove_wait_queue( &( cv_ptr->wq_ptr ), &wait ); + + OsCvLockAcquire( cv_lock_ptr ); + return( signal_state ); +} + + +/*----------------------------------------------------------------------------*/ +void OsCv_signal( + OS_CV_T *cv_ptr ) +/*----------------------------------------------------------------------------*/ +{ + clear_bit( 0, &( cv_ptr->lock_var ) ); + if( cv_ptr->type == TASK_INTERRUPTIBLE ) + wake_up_interruptible( &( cv_ptr->wq_ptr ) ); + else + wake_up( &( cv_ptr->wq_ptr ) ); +} + + +//----------------------------------------------------------------------------- +// Deferred procedure call functions + +// create a soft interrupt object +/*----------------------------------------------------------------------------*/ +int OsSoftInterruptAdd( + OS_SOFTINTR **ptr, + void * handler, + void * data ) +/*----------------------------------------------------------------------------*/ +{ + OS_SOFTINTR *tmp_ptr; + + if( !( tmp_ptr = ( OS_SOFTINTR * )kmalloc( sizeof( OS_SOFTINTR ), GFP_KERNEL ) ) ) + return( -1 ); + tmp_ptr->routine = handler; + tmp_ptr->data = data; + tmp_ptr->next = NULL; + tmp_ptr->sync = 0; + + *ptr = tmp_ptr; + + return( 0 ); +} + +/* + Use kernel_thread( ( int ( * )( void * ) )OsIdleTask, NULL, 0 ); to start +*/ +/*----------------------------------------------------------------------------*/ +int * OsIdleTask( void * data ) +/*----------------------------------------------------------------------------*/ +{ + struct wait_queue wait = { current, NULL }; + + while( 1 ) + { + //interruptible_sleep_on( &g_wait_queue_ptr ); + current->state = TASK_INTERRUPTIBLE; + add_wait_queue( &g_wait_queue_ptr, &wait ); + schedule(); + remove_wait_queue( &g_wait_queue_ptr, &wait ); + wait.task = current; + wait.next = NULL; + } + return( NULL ); +} + + +// dispatch a soft interrupt +/*----------------------------------------------------------------------------*/ +void OsSoftInterruptTrigger( + OS_SOFTINTR *soft_intr_ptr ) +/*----------------------------------------------------------------------------*/ +{ + // wake up a kernel thread + //wake_up_interruptible( &g_wait_queue_ptr ); + + // put in scheduler task queue + //queue_task( soft_intr_ptr, &tq_scheduler ); + + // call the completion routine directly + soft_intr_ptr->routine( soft_intr_ptr->data ); +} + + +// delete a soft interrupt object +/*----------------------------------------------------------------------------*/ +void OsSoftInterruptRemove( + OS_SOFTINTR *arg ) +/*----------------------------------------------------------------------------*/ +{ + if( arg ) + kfree( arg ); + arg = NULL; +} + + +/*----------------------------------------------------------------------------*/ +void OsSleep(unsigned time) // in seconds +/*----------------------------------------------------------------------------*/ +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(time*HZ); +} + + diff --git a/drivers/scsi/aacraid/ossup.c b/drivers/scsi/aacraid/ossup.c new file mode 100644 index 000000000000..61696f98eae2 --- /dev/null +++ b/drivers/scsi/aacraid/ossup.c @@ -0,0 +1,164 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * ossup.c + * + * + * + --*/ + +#include "osheaders.h" + +#include "aac_unix_defs.h" + + + +/*++ + +Routine Description: + + This function initializes a zone header. Once successfully + initialized, blocks can be allocated and freed from the zone, and + the zone can be extended. + +Arguments: + + Zone - Supplies the address of a zone header to be initialized. + + BlockSize - Supplies the block size of the allocatable unit within + the zone. The size must be larger that the size of the + initial segment, and must be 64-bit aligned. + + InitialSegment - Supplies the address of a segment of storage. The + first ZONE_SEGMENT_HEADER-sized portion of the segment + is used by the zone allocator. The remainder of + the segment is carved up into fixed size + (BlockSize) blocks and is made available for + allocation and deallocation from the zone. The + address of the segment must be aligned on a 64-bit + boundary. + + InitialSegmentSize - Supplies the size in bytes of the InitialSegment. + +Return Value: + + STATUS_UNSUCCESSFUL - BlockSize or InitialSegment was not aligned on + 64-bit boundaries, or BlockSize was larger than + the initial segment size. + + STATUS_SUCCESS - The zone was successfully initialized. + +--*/ + +AAC_STATUS ExInitializeZone(PZONE_HEADER Zone, u32 BlockSize, void * InitialSegment, u32 InitialSegmentSize) +{ + u32 i; + char * p; + + + Zone->BlockSize = BlockSize; + + Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList; + ((PZONE_SEGMENT_HEADER) InitialSegment)->SegmentList.Next = NULL; + ((PZONE_SEGMENT_HEADER) InitialSegment)->Reserved = NULL; + + Zone->FreeList.Next = NULL; + + p = (char *)InitialSegment + sizeof(ZONE_SEGMENT_HEADER); + + for (i = sizeof(ZONE_SEGMENT_HEADER); + i <= InitialSegmentSize - BlockSize; + i += BlockSize + ) { + ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next; + Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p; + p += BlockSize; + } + Zone->TotalSegmentSize = i; + + return STATUS_SUCCESS; +} + + +/*++ + +Routine Description: + + This function extends a zone by adding another segment's worth of + blocks to the zone. + +Arguments: + + Zone - Supplies the address of a zone header to be extended. + + Segment - Supplies the address of a segment of storage. The first + ZONE_SEGMENT_HEADER-sized portion of the segment is used by the + zone allocator. The remainder of the segment is carved up + into fixed-size (BlockSize) blocks and is added to the + zone. The address of the segment must be aligned on a 64- + bit boundary. + + SegmentSize - Supplies the size in bytes of Segment. + +Return Value: + + STATUS_UNSUCCESSFUL - BlockSize or Segment was not aligned on + 64-bit boundaries, or BlockSize was larger than + the segment size. + + STATUS_SUCCESS - The zone was successfully extended. + +--*/ + +AAC_STATUS ExExtendZone(PZONE_HEADER Zone, void * Segment, u32 SegmentSize) +{ + u32 i; + char * p; + + ((PZONE_SEGMENT_HEADER) Segment)->SegmentList.Next = Zone->SegmentList.Next; + Zone->SegmentList.Next = &((PZONE_SEGMENT_HEADER) Segment)->SegmentList; + + p = (char *)Segment + sizeof(ZONE_SEGMENT_HEADER); + + for (i = sizeof(ZONE_SEGMENT_HEADER); i <= SegmentSize - Zone->BlockSize; i += Zone->BlockSize) + { + ((PSINGLE_LIST_ENTRY)p)->Next = Zone->FreeList.Next; + Zone->FreeList.Next = (PSINGLE_LIST_ENTRY)p; + p += Zone->BlockSize; + } + Zone->TotalSegmentSize += i; + + return STATUS_SUCCESS; +} + +/* Function: InqStrCopy() + * + * Arguments: [2] pointer to char + * + * Purpose: Copy a String from one location to another + * without copying \0 + */ + +void InqStrCopy(char *a, char *b) +{ + while(*a != (char)0) + *b++ = *a++; +} + diff --git a/drivers/scsi/aacraid/port.c b/drivers/scsi/aacraid/port.c new file mode 100644 index 000000000000..ceeffd7d2955 --- /dev/null +++ b/drivers/scsi/aacraid/port.c @@ -0,0 +1,233 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * port.c + * + * Abstract: All support routines for FSA communication which are miniport specific. + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "protocol.h" + +#include "fsaport.h" +#include "fsaioctl.h" + +#include "pcisup.h" +#include "port.h" + +int AfaPortPrinting = 1; + +extern AAC_STATUS AfaPort_Err_Adapter_Printf; +extern AAC_STATUS AfaPort_Warn_Adapter_Printf; +extern AAC_STATUS AfaPort_Info_Adapter_Printf; +extern AAC_STATUS AfaPort_Err_FastAfa_Load_Driver; + + +/*++ + +Routine Description: + Does all of the work to log an error log entry + +Arguments: + CommonExtension - Pointer to the adapter that caused the error. + ErrorCode - Which error is being logged. + StringBuffer - Pointer to optional String for error log entry. + StringLength - Length of StringBuffer. + +Return Value: + Nothing + +--*/ + +voidAfaPortLogError(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, AAC_STATUS ErrorCode, unsigned char * StringBuffer, u32 StringLength) +{ + +} + +int AfaPortGetNextAdapterNumber(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT *FsaDeviceObject, PFILE_OBJECT *FileObject, u32 *AdapterNumber) +{ +} + +int AfaPortAllocateAdapterCommArea(void *Arg1, void **CommHeaderAddress, u32 CommAreaSize, u32 CommAreaAlignment) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + void * BaseAddress; + PHYSICAL_ADDRESS PhysicalBaseAddress; + u32 TotalSize, BytesToAlign; + size_t RealLength; + uint_t Count; +// u32 SizeOfFastIoComm = sizeof(FASTIO_STRUCT); +// u32 AdapterFibsSize = PAGE_SIZE; + u32 AdapterFibsSize = 4096; + u32 PrintfBufferSize = 256; + PADAPTER_INIT_STRUCT InitStruct; + extern int MiniPortRevision; + u32 PhysAddress; + +// TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment + +// SizeOfFastIoComm + PrintfBufferSize; + TotalSize = AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT) + CommAreaSize + CommAreaAlignment + + PrintfBufferSize; + + + OsAllocCommPhysMem(CommonExtension->MiniPort, TotalSize, &BaseAddress, &PhysAddress); + + CommonExtension->CommAddress = BaseAddress; + CommonExtension->CommPhysAddr = PhysAddress; + CommonExtension->CommSize = TotalSize; + + PhysicalBaseAddress.HighPart = 0; + PhysicalBaseAddress.LowPart = PhysAddress; + + CommonExtension->InitStruct = (PADAPTER_INIT_STRUCT)((unsigned char *)(BaseAddress) + AdapterFibsSize); + CommonExtension->PhysicalInitStruct = (PADAPTER_INIT_STRUCT)((unsigned char *)(PhysicalBaseAddress.LowPart) + AdapterFibsSize); + + InitStruct = CommonExtension->InitStruct; + + InitStruct->InitStructRevision = ADAPTER_INIT_STRUCT_REVISION; + InitStruct->MiniPortRevision = MiniPortRevision; + InitStruct->FilesystemRevision = CommonExtension->FilesystemRevision; + + // + // Adapter Fibs are the first thing allocated so that they start page aligned + // + InitStruct->AdapterFibsVirtualAddress = BaseAddress; + InitStruct->AdapterFibsPhysicalAddress = (void *) PhysicalBaseAddress.LowPart; + InitStruct->AdapterFibsSize = AdapterFibsSize; + InitStruct->AdapterFibAlign = sizeof(FIB); + + // + // Increment the base address by the amount already used + // + BaseAddress = (void *)((unsigned char *)(BaseAddress) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT)); + PhysicalBaseAddress.LowPart = (u32)((unsigned char *)(PhysicalBaseAddress.LowPart) + AdapterFibsSize + sizeof(ADAPTER_INIT_STRUCT)); + + // + // Align the beginning of Headers to CommAreaAlignment + // + BytesToAlign = (CommAreaAlignment - ((u32)(BaseAddress) & (CommAreaAlignment - 1))); + BaseAddress = (void *)((unsigned char *)(BaseAddress) + BytesToAlign); + PhysicalBaseAddress.LowPart = (u32)((unsigned char *)(PhysicalBaseAddress.LowPart) + BytesToAlign); + + // + // Fill in addresses of the Comm Area Headers and Queues + // + *CommHeaderAddress = BaseAddress; + InitStruct->CommHeaderAddress = (void *)PhysicalBaseAddress.LowPart; + + // + // Increment the base address by the size of the CommArea + // + BaseAddress = (void *)((unsigned char *)(BaseAddress) + CommAreaSize); + PhysicalBaseAddress.LowPart = (u32)((unsigned char *)(PhysicalBaseAddress.LowPart) + CommAreaSize); + + + // + // Place the Printf buffer area after the Fast I/O comm area. + // + CommonExtension->PrintfBufferAddress = (void *)(BaseAddress); + InitStruct->PrintfBufferAddress = (void *)PhysicalBaseAddress.LowPart; + InitStruct->PrintfBufferSize = PrintfBufferSize; + + AfaPortPrint("FsaAllocateAdapterCommArea: allocated a common buffer of 0x%x bytes from address 0x%x to address 0x%x\n", + TotalSize, InitStruct->AdapterFibsVirtualAddress, + (unsigned char *)(InitStruct->AdapterFibsVirtualAddress) + TotalSize); + + AfaPortPrint("Mapped on to PCI address 0x%x\n", InitStruct->AdapterFibsPhysicalAddress); + + return (TRUE); +} + +/*++ + +Routine Description: + The routine will get called each time a user issues a CreateFile on the DeviceObject + for the adapter. + + The main purpose of this routine is to set up any data structures that may be needed + to handle any requests made on this DeviceObject. + +Arguments: + DeviceObject - Pointer to device object representing adapter + Irp - Pointer to Irp that caused this open + + +Return Value: + Status value returned from File system driver AdapterOpen + +--*/ + +AAC_STATUS AfaPortCreate(PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ +} + +/*++ + +Routine Description: + This routine will get called each time a user issues a CloseHandle on the DeviceObject + for the adapter. + + The main purpose of this routine is to cleanup any data structures that have been set up + while this FileObject has been opened. + +Arguments: + DeviceObject - Pointer to device object representing adapter + Irp - Pointer to Irp that caused this close + +Return Value: + Status value returned from File system driver AdapterClose + +--*/ + +AAC_STATUS AfaPortClose (PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ +} + +AAC_STATUS AfaPortDeviceControl (PDEVICE_OBJECT DeviceObject, PIRP Irp) +{ +} + +/*++ + +Routine Description: + This routine determines the max physical page in host memory. + +Arguments: + AdapterExtension + +Return Value: + Max physical page in host memory. + +--*/ + +u32 AfaPortGetMaxPhysicalPage(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension) +{ +} + + diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c new file mode 100644 index 000000000000..c4c1afc64d7f --- /dev/null +++ b/drivers/scsi/aacraid/rx.c @@ -0,0 +1,702 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * rx.c + * + * Abstract: Hardware miniport for Drawbridge specific hardware functions. + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsact.h" +#include "protocol.h" + +#define DEFINE_PCI_IDS +#include "rxcommon.h" +#include "monkerapi.h" + +#include "fsaport.h" +#include "fsaioctl.h" + +#include "pcisup.h" +#include "rx.h" + +#include "port.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP) + +// #define RxBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (u32)A, (u32)B,(u32)C ); } + +#define RxBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); } + +#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */ + + +// +// The list of all the Rx adapter structures +// + +PRx_ADAPTER_EXTENSION RxAdapterList; + +int RxInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot); +int RxSendSynchFib(void * Arg1, u32 FibPhysicalAddress); + +FSA_USER_VAR RxUserVars[] = { + { "AfaPortPrinting", (u32 *)&AfaPortPrinting, NULL }, +}; + + +// +// Declare private use routines for this modual +// + + +/*++ + +Routine Description: + The Isr routine for fsa Rx based adapter boards. + +Arguments: + +Return Value: + TRUE - if the interrupt was handled by this isr + FALSE - if the interrupt was not handled by this isr + +--*/ + +u_int RxPciIsr (PRx_ADAPTER_EXTENSION AdapterExtension) +{ + u32 DoorbellBits; + u8 InterruptStatus, Mask; + u_int OurInterrupt = INTR_UNCLAIMED; + + //cmn_err(CE_WARN, "RxPciIsr entered\n"); + + InterruptStatus = Rx_READ_UCHAR(AdapterExtension, MUnit.OISR); + + // + // Read mask and invert because drawbridge is reversed. + // + // This allows us to only service interrupts that have been enabled. + // + + Mask = ~(Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR)); + + // Check to see if this is our interrupt. If it isn't just return FALSE. + + if (InterruptStatus & Mask) { + DoorbellBits = Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg); + OurInterrupt = INTR_CLAIMED; + if (DoorbellBits & DoorBellPrintfReady) { + cmn_err(CE_CONT, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellPrintfReady); //clear PrintfReady + Rx_WRITE_ULONG(AdapterExtension, InboundDoorbellReg,DoorBellPrintfDone); + } else if (DoorbellBits & DoorBellAdapterNormCmdReady) { // Adapter -> Host Normal Command Ready + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdReady); + } else if (DoorbellBits & DoorBellAdapterNormRespReady) { // Adapter -> Host Normal Response Ready + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR,DoorBellAdapterNormRespReady); + } else if (DoorbellBits & DoorBellAdapterNormCmdNotFull) { // Adapter -> Host Normal Command Not Full + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormCmdNotFull); + } else if (DoorbellBits & DoorBellAdapterNormRespNotFull) { // Adapter -> Host Normal Response Not Full + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull); + Rx_WRITE_ULONG(AdapterExtension, MUnit.ODR, DoorBellAdapterNormRespNotFull); + } + } + return(OurInterrupt); +} + +/*++ + +Routine Description: + This routine will enable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + AdapterExtension - Which adapter to enable. + AdapterEvent - Which adapter event. + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + Nothing. + +--*/ + +void RxEnableInterrupt(void *Arg1, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + //cmn_err(CE_WARN, "RxEnableInterrupt"); + switch (AdapterEvent) { + case HostNormCmdQue: + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_1); + break; + case HostNormRespQue: + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_2); + break; + case AdapNormCmdNotFull: + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_3); + break; + case AdapNormRespNotFull: + AdapterExtension->LocalMaskInterruptControl &= ~(OUTBOUNDDOORBELL_4); + break; + } +} + +/*++ + +Routine Description: + + This routine will disable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + + AdapterExtension - Which adapter to enable. + + AdapterEvent - Which adapter event. + + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + + Nothing. + +--*/ + +void RxDisableInterrupt(void *Arg1, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + //cmn_err(CE_WARN, "RxEnableInterrupt"); + + switch (AdapterEvent) + { + case HostNormCmdQue: + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_1); + break; + case HostNormRespQue: + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_2); + break; + case AdapNormCmdNotFull: + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_3); + break; + case AdapNormRespNotFull: + AdapterExtension->LocalMaskInterruptControl |= (OUTBOUNDDOORBELL_4); + break; + } +} + + + +void RxDetachDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension) +{ + PRx_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort; + + // + // Free the register mapping. + // + + OsDetachDevice( AdapterExtension); + kfree(AdapterExtension); +} + + +/*++ + +Routine Description: + Scans the PCI bus looking for the Rx card. When found all resources for the + device will be allocated and the interrupt vectors and csrs will be allocated and + mapped. + + The device_interface in the commregion will be allocated and linked to the comm region. + +Arguments: + +Return Value: + TRUE - if the device was setup with not problems + FALSE - if the device could not be mapped and init successfully + +--*/ + +int RxInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot) +{ + AAC_STATUS Status; + PRx_ADAPTER_EXTENSION AdapterExtension = NULL; + FSA_NEW_ADAPTER NewAdapter; + u32 StartTime, EndTime, WaitTime; + u32 InitStatus; + int instance; + int nIntrs; + char * name; + + AfaPortPrint("In init device.\n"); + + //cmn_err(CE_WARN, "In RxInitDevice"); + +// AdapterExtension->Common->AdapterIndex = AdapterIndex; + CommonExtension->AdapterNumber = AdapterNumber; + + CommonExtension->PciBusNumber = PciBus; + CommonExtension->PciSlotNumber = PciSlot; + + AdapterExtension = kmalloc(sizeof(Rx_ADAPTER_EXTENSION), GFP_KERNEL); + AdapterExtension->Common = CommonExtension; + CommonExtension->MiniPort = AdapterExtension; + + instance = OsGetDeviceInstance(AdapterExtension); + name = OsGetDeviceName(AdapterExtension); + // + // Map in the registers from the adapter, register space 0 is config space, + // register space 1 is the memery space. + // + + if (OsMapDeviceRegisters(AdapterExtension)) { + cmn_err(CE_CONT, "%s%d: can't map device registers\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + } + + // + // Check to see if the board failed any self tests. + // + + if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & SELF_TEST_FAILED) { + cmn_err(CE_CONT, "%s%d: adapter self-test failed\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + } + //cmn_err(CE_WARN, "RxInitDevice: %s%d: adapter passwd self-test\n", + // OsGetDeviceName(AdapterExtension), instance); + + // + // Check to see if the board panic'd while booting. + // + + if (Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_PANIC) { + cmn_err(CE_CONT, "%s%d: adapter kernel panic'd\n", + OsGetDeviceName(AdapterExtension), instance); + return(FAILURE); + } + + StartTime = jiffies/HZ; + WaitTime = 0; + + // + // Wait for the adapter to be up and running. Wait up until 3 minutes. + // + + while (!(Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING)) { + EndTime = jiffies/HZ; + WaitTime = EndTime - StartTime; + if ( WaitTime > (3 * 10) ) { + InitStatus = Rx_READ_ULONG( AdapterExtension, IndexRegs.Mailbox[7]) >> 16; + cmn_err(CE_CONT, "%s%d: adapter kernel failed to start, init status = %d\n", + OsGetDeviceName(AdapterExtension), instance, InitStatus); + return(FAILURE); + } + } + + if (OsAttachInterrupt(AdapterExtension,RxISR)) { + cmn_err(CE_WARN, "%s%d RxInitDevice: failed OsAttachIntterupt", name, instance); + return(FAILURE); + } + + // + // Fill in the function dispatch table. + // + + AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS); + AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace; + AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace; + AdapterExtension->Common->AdapterFuncs.InterruptAdapter = RxInterruptAdapter; + AdapterExtension->Common->AdapterFuncs.EnableInterrupt = RxEnableInterrupt; + AdapterExtension->Common->AdapterFuncs.DisableInterrupt = RxDisableInterrupt; + AdapterExtension->Common->AdapterFuncs.NotifyAdapter = RxNotifyAdapter; + AdapterExtension->Common->AdapterFuncs.ResetDevice = RxResetDevice; + AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL; + AdapterExtension->Common->AdapterFuncs.SendSynchFib = RxSendSynchFib; + + NewAdapter.AdapterExtension = CommonExtension; + NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs; + NewAdapter.AdapterInterruptsBelowDpc = FALSE; + NewAdapter.AdapterUserVars = RxUserVars; + NewAdapter.AdapterUserVarsSize = sizeof(RxUserVars) / sizeof(FSA_USER_VAR); + + NewAdapter.Dip = CommonExtension->OsDep.dip; + + if (AfaCommInitNewAdapter( &NewAdapter ) == NULL) { + cmn_err(CE_WARN, "AfaCommInitNewAdapter failed\n"); + return (FAILURE); + } + + AdapterExtension->Common->Adapter = NewAdapter.Adapter; + + if (AdapterExtension->Common->Adapter == NULL) { + AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0); + cmn_err(CE_WARN, "%s%d RxInitDevice: No Adapter pointer", name, instance); + return (FAILURE); + } + + // + // Start any kernel threads needed + // + OsStartKernelThreads(AdapterExtension); + + // + // Tell the adapter that all is configure, and it can start accepting requests + // + + RxStartAdapter(AdapterExtension); + + // + // Put this adapter into the list of Rx adapters + // + + AdapterExtension->Next = RxAdapterList; + RxAdapterList = AdapterExtension; + + AdapterExtension->Common->AdapterConfigured = TRUE; + +#ifdef AACDISK + // + // Call the disk layer to initialize itself. + // + + AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter ); +#endif + +init_done: + AdapterExtension->Common->AdapterPrintfsToScreen = FALSE; + return(0); +} + +void RxStartAdapter(PRx_ADAPTER_EXTENSION AdapterExtension) +{ + u32 ReturnStatus; + LARGE_INTEGER HostTime; + u32 ElapsedSeconds; + PADAPTER_INIT_STRUCT InitStruct; + + //cmn_err(CE_WARN, "RxStartAdapter"); + // + // Fill in the remaining pieces of the InitStruct. + // + + InitStruct = AdapterExtension->Common->InitStruct; + InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common); + ElapsedSeconds = jiffies/HZ; + InitStruct->HostElapsedSeconds = ElapsedSeconds; + + // + // Tell the adapter we are back and up and running so it will scan its command + // queues and enable our interrupts + // + + AdapterExtension->LocalMaskInterruptControl = + (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4); + + // + // First clear out all interrupts. Then enable the one's that we can handle. + // + + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xff); + Rx_WRITE_ULONG( AdapterExtension, MUnit.ODR, 0xffffffff); +// Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK); + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, 0xfb); + + RxSendSynchCommand(AdapterExtension, + INIT_STRUCT_BASE_ADDRESS, + (u32) AdapterExtension->Common->PhysicalInitStruct, + 0, + 0, + 0, + &ReturnStatus); +} + + +void RxResetDevice(void * Arg1) +{ +} + +/*++ + +Routine Description: + The will cause the adapter to take a break point. + +Arguments: + None + +Return Value: + Nothing + +--*/ + +void RxInterruptAdapter(void * Arg1) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + u32 ReturnStatus; + RxSendSynchCommand(AdapterExtension, + BREAKPOINT_REQUEST, + 0, + 0, + 0, + 0, + &ReturnStatus); +} + +/*++ + +Routine Description: + Will read the adapter CSRs to find the reason the adapter has + interrupted us. + +Arguments: + AdapterEvent - Enumerated type the returns the reason why we were interrutped. + +Return Value: + Nothing + +--*/ + +void RxNotifyAdapter(void * Arg1, HOST_2_ADAP_EVENT AdapterEvent) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + u32 ReturnStatus; + + //cmn_err(CE_WARN, "RxNotifyAdapter %d", AdapterEvent); + + switch (AdapterEvent) + { + case AdapNormCmdQue: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_1); + break; + + case HostNormRespNotFull: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_4); + break; + + case AdapNormRespQue: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_2); + break; + + case HostNormCmdNotFull: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_3); + break; + + case HostShutdown: +// RxSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus); + break; + + case FastIo: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_6); + break; + + case AdapPrintfDone: + Rx_WRITE_ULONG(AdapterExtension, MUnit.IDR,INBOUNDDOORBELL_5); + break; + + default: + RxBugCheck(0,0,0); + AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent); + break; + } +} + +/*++ + +Routine Description: + This routine will send a synchronous comamnd to the adapter and wait for its + completion. + +Arguments: + AdapterExtension - Pointer to adapter extension structure. + Command - Which command to send + Parameter1 - 4 - Parameters for command + ReturnStatus - return status from adapter after completion of command + +Return Value: + AAC_STATUS + +--*/ + +AAC_STATUS RxSendSynchCommand(void * Arg1, u32 Command, u32 Parameter1, u32 Parameter2, u32 Parameter3, u32 Parameter4, u32 *ReturnStatus) +{ + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) Arg1; + u32 StartTime,EndTime,WaitTime; + int CommandSucceeded; + + //cmn_err(CE_WARN, "RxSendSyncCommand"); + // + // Write the Command into Mailbox 0 + // + + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox0, Command); + + // + // Write the parameters into Mailboxes 1 - 4 + // + + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox1, Parameter1); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox2, Parameter2); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox3, Parameter3); + Rx_WRITE_ULONG( AdapterExtension, InboundMailbox4, Parameter4); + + // + // Clear the synch command doorbell to start on a clean slate. + // + + Rx_WRITE_ULONG( AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + // + // disable doorbell interrupts + // + + Rx_WRITE_UCHAR( AdapterExtension, MUnit.OIMR, + Rx_READ_UCHAR(AdapterExtension, MUnit.OIMR) | 0x04); + + // + // force the completion of the mask register write before issuing the interrupt. + // + + Rx_READ_UCHAR ( AdapterExtension, MUnit.OIMR); + + // + // Signal that there is a new synch command + // + + Rx_WRITE_ULONG( AdapterExtension, InboundDoorbellReg, INBOUNDDOORBELL_0); + CommandSucceeded = FALSE; + StartTime = jiffies/HZ; + WaitTime = 0; + + while (WaitTime < 30) { // wait up to 30 seconds + drv_usecwait(5); // delay 5 microseconds to let Mon960 get info. + + // + // Mon110 will set doorbell0 bit when it has completed the command. + // + + if (Rx_READ_ULONG(AdapterExtension, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) { + + // + // clear the doorbell. + // + + Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + CommandSucceeded = TRUE; + break; + } + EndTime = jiffies/HZ; + WaitTime = EndTime - StartTime; + } + + if (CommandSucceeded != TRUE) { + // + // restore interrupt mask even though we timed out + // + + Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, + Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb); + + return (STATUS_IO_TIMEOUT); + } + + // + // Pull the synch status from Mailbox 0. + // + + *ReturnStatus = Rx_READ_ULONG(AdapterExtension, IndexRegs.Mailbox[0]); + + // + // Clear the synch command doorbell. + // + + Rx_WRITE_ULONG(AdapterExtension, OutboundDoorbellReg, OUTBOUNDDOORBELL_0); + + // + // restore interrupt mask + // + + Rx_WRITE_UCHAR(AdapterExtension, MUnit.OIMR, + Rx_READ_ULONG(AdapterExtension, MUnit.OIMR) & 0xfb); + + // + // Return SUCCESS + // + return (STATUS_SUCCESS); +} + +/*++ + +Routine Description: + + This routine will send a synchronous fib to the adapter and wait for its + completion. + +Arguments: + + AdapterExtension - Pointer to adapter extension structure. + FibPhysicalAddress - Physical address of fib to send. + + +Return Value: + + int + +--*/ + +int RxSendSynchFib(void * Arg1, u32 FibPhysicalAddress) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PRx_ADAPTER_EXTENSION AdapterExtension = (PRx_ADAPTER_EXTENSION) CommonExtension->MiniPort; + u32 returnStatus; + + if (RxSendSynchCommand( AdapterExtension, + SEND_SYNCHRONOUS_FIB, + FibPhysicalAddress, + 0, + 0, + 0, + &returnStatus ) != STATUS_SUCCESS ) + { + return (FALSE); + } + return (TRUE); +} + diff --git a/drivers/scsi/aacraid/sap1sup.c b/drivers/scsi/aacraid/sap1sup.c new file mode 100644 index 000000000000..e7126e089f95 --- /dev/null +++ b/drivers/scsi/aacraid/sap1sup.c @@ -0,0 +1,633 @@ +/*++ + * Adaptec aacraid device driver for Linux. + * + * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * + * 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, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Module Name: + * sap1sup.c + * + * Abstract: Drawbridge specific support functions + * + --*/ + +#include "osheaders.h" + + +#include "AacGenericTypes.h" + +#include "aac_unix_defs.h" + +#include "fsatypes.h" +#include "comstruc.h" +#include "fsact.h" +#include "protocol.h" + +#define DEFINE_PCI_IDS +#include "sap1common.h" +#include "monkerapi.h" + +#include "fsaport.h" +#include "fsaioctl.h" + + +#include "pcisup.h" +#include "sap1.h" + +#include "port.h" + +#include "nodetype.h" +#include "comsup.h" +#include "afacomm.h" +#include "adapter.h" + +#define BugCheckFileId (FSAFS_BUG_CHECK_CYCLONESUP) + +// #define SaBugCheck(A,B,C) { KeBugCheckEx(0x00000AFA, __LINE__, (u32)A, (u32)B,(u32)C ); } + +#define SaBugCheck(A, B, C) { cmn_err(CE_PANIC, "aacdisk : line %s, 0x%x, 0x%x, 0x%x ", __LINE__, A, B, C); } + +#define NUM_TICKS_PER_SECOND (1000 * 1000 * 10) /* time is in 100 nanoseconds */ + +int MiniPortRevision = Sa_MINIPORT_REVISION; + +// +// The list of all the Sa adapter structures +// + +PSa_ADAPTER_EXTENSION SaAdapterList; +int SaInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot); +int SaSendSynchFib( void * Arg1, u32 FibPhysicalAddress); + +FSA_USER_VAR SaUserVars[] = { + { "AfaPortPrinting", (u32 *)&AfaPortPrinting, NULL }, +}; + + +// +// Declare private use routines for this modual +// + +/*++ + +Routine Description: + The Isr routine for fsa Sa based adapter boards. + +Arguments: + +Return Value: + TRUE - if the interrupt was handled by this isr + FALSE - if the interrupt was not handled by this isr + +--*/ + +u_int SaPciIsr (PSa_ADAPTER_EXTENSION AdapterExtension) +{ + u16 InterruptStatus, Mask; + u_int OurInterrupt = INTR_UNCLAIMED; + +// cmn_err(CE_WARN, "SaPciIsr entered\n"); + InterruptStatus = Sa_READ_USHORT( AdapterExtension, DoorbellReg_p); + + // + // Read mask and invert because drawbridge is reversed. + // + // This allows us to only service interrupts that have been enabled. + // + + Mask = ~(Sa_READ_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK)); + + // Check to see if this is our interrupt. If it isn't just return FALSE. + if (InterruptStatus & Mask) { + OurInterrupt = INTR_CLAIMED; + if (InterruptStatus & PrintfReady) { + cmn_err(CE_WARN, "%s:%s", OsGetDeviceName(AdapterExtension), AdapterExtension->Common->PrintfBufferAddress); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,PrintfReady); //clear PrintfReady + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,PrintfDone); + } else if (InterruptStatus & DOORBELL_1) { // Adapter -> Host Normal Command Ready + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormCmdQue); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_1); + } else if (InterruptStatus & DOORBELL_2) { // Adapter -> Host Normal Response Ready + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, HostNormRespQue); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p,DOORBELL_2); + } else if (InterruptStatus & DOORBELL_3) { // Adapter -> Host Normal Command Not Full + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormCmdNotFull); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_3); + } else if (InterruptStatus & DOORBELL_4) { // Adapter -> Host Normal Response Not Full + AdapterExtension->Common->AdapterFuncs.InterruptHost(AdapterExtension->Common->Adapter, AdapNormRespNotFull); + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_4); + } + } + return(OurInterrupt); +} + +/*++ + +Routine Description: + This routine will enable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + AdapterExtension - Which adapter to enable. + AdapterEvent - Which adapter event. + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + Nothing. + +--*/ + +void SaEnableInterrupt(void * Arg1, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + switch (AdapterEvent) { + case HostNormCmdQue: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_1 ); + break; + case HostNormRespQue: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_2 ); + break; + case AdapNormCmdNotFull: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_3 ); + break; + case AdapNormRespNotFull: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, DOORBELL_4 ); + break; + default: + } +} + +/*++ + +Routine Description: + This routine will disable the corresponding adapter event to cause an interrupt on + the host. + +Arguments: + AdapterExtension - Which adapter to enable. + AdapterEvent - Which adapter event. + AtDeviceIrq - Whether the system is in DEVICE irql + +Return Value: + Nothing. + +--*/ + +void SaDisableInterrupt(void * Arg1, ADAPTER_EVENT AdapterEvent, int AtDeviceIrq) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + + switch (AdapterEvent) + { + case HostNormCmdQue: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_1 ); + break; + case HostNormRespQue: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_2 ); + break; + case AdapNormCmdNotFull: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_3 ); + break; + case AdapNormRespNotFull: + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, DOORBELL_4 ); + break; + default: + } +} + +void SaDetachDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension) +{ + PSa_ADAPTER_EXTENSION AdapterExtension = CommonExtension->MiniPort; + // + // Free the register mapping. + // + OsDetachDevice(AdapterExtension); + kfree(AdapterExtension); +} + + +/*++ + +Routine Description: + Scans the PCI bus looking for the Sa card. When found all resources for the + device will be allocated and the interrupt vectors and csrs will be allocated and + mapped. + + The device_interface in the commregion will be allocated and linked to the comm region. + +Arguments: + +Return Value: + TRUE - if the device was setup with not problems + FALSE - if the device could not be mapped and init successfully + +--*/ + +int SaInitDevice(PPCI_MINIPORT_COMMON_EXTENSION CommonExtension, u32 AdapterNumber, u32 PciBus, u32 PciSlot) +{ + AAC_STATUS Status; + PSa_ADAPTER_EXTENSION AdapterExtension = NULL; + FSA_NEW_ADAPTER NewAdapter; + u32 StartTime, EndTime, WaitTime; + u32 InitStatus; + int instance; + char *name; + + AfaPortPrint("In init device.\n"); + +// cmn_err(CE_NOTE, "SaInitDevice "); + +// AdapterExtension->Common->AdapterIndex = AdapterIndex; + CommonExtension->AdapterNumber = AdapterNumber; + CommonExtension->PciBusNumber = PciBus; + CommonExtension->PciSlotNumber = PciSlot; + AdapterExtension = kmalloc(sizeof(Sa_ADAPTER_EXTENSION), GFP_KERNEL); + AdapterExtension->Common = CommonExtension; + CommonExtension->MiniPort = AdapterExtension; + + instance = OsGetDeviceInstance(AdapterExtension); + name = OsGetDeviceName(AdapterExtension); + + // + // Map in the registers from the adapter, register space 0 is config space, + // register space 1 is the memery space. + // + + if (OsMapDeviceRegisters(AdapterExtension)){ + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsMapDeviceRegisters", name, instance); + return(FAILURE); + } + + // + // Check to see if the board failed any self tests. + // + + if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & SELF_TEST_FAILED) { + cmn_err(CE_WARN, "%s%d: adapter self-test failed\n", + name, instance); + return(FAILURE); + } + + // + // Check to see if the board panic'd while booting. + // + + if (Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_PANIC) { + cmn_err(CE_WARN, "%s%d: adapter kernel panic'd\n", + name, instance); + return(FAILURE); + } + + StartTime = jiffies/HZ; + WaitTime = 0; + + // + // Wait for the adapter to be up and running. Wait up until 3 minutes. + // + + while (!(Sa_READ_ULONG( AdapterExtension, Mailbox7) & KERNEL_UP_AND_RUNNING)) { + EndTime = jiffies/HZ; + WaitTime = EndTime - StartTime; + if ( WaitTime > (3 * 60) ) { + InitStatus = Sa_READ_ULONG( AdapterExtension, Mailbox7) >> 16; + cmn_err(CE_WARN, "%s%d: adapter kernel failed to start, init status = %d\n", + name, instance, InitStatus); + return(FAILURE); + } + } + + if (OsAttachInterrupt(AdapterExtension, SaISR)) { + cmn_err(CE_WARN, "%s%d SaInitDevice: failed OsAttachIntterupt", name, instance); + return(FAILURE); + } + + // + // Fill in the function dispatch table. + // + + AdapterExtension->Common->AdapterFuncs.SizeOfFsaPortFuncs = sizeof(FSAPORT_FUNCS); + AdapterExtension->Common->AdapterFuncs.AllocateAdapterCommArea = AfaPortAllocateAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.FreeAdapterCommArea = AfaPortFreeAdapterCommArea; + AdapterExtension->Common->AdapterFuncs.AllocateAndMapFibSpace = AfaPortAllocateAndMapFibSpace; + AdapterExtension->Common->AdapterFuncs.UnmapAndFreeFibSpace = AfaPortUnmapAndFreeFibSpace; + AdapterExtension->Common->AdapterFuncs.InterruptAdapter = SaInterruptAdapter; + AdapterExtension->Common->AdapterFuncs.EnableInterrupt = SaEnableInterrupt; + AdapterExtension->Common->AdapterFuncs.DisableInterrupt = SaDisableInterrupt; + AdapterExtension->Common->AdapterFuncs.NotifyAdapter = SaNotifyAdapter; + AdapterExtension->Common->AdapterFuncs.ResetDevice = SaResetDevice; + AdapterExtension->Common->AdapterFuncs.InterruptHost = NULL; + AdapterExtension->Common->AdapterFuncs.SendSynchFib = SaSendSynchFib; + + NewAdapter.AdapterExtension = CommonExtension; + NewAdapter.AdapterFuncs = &AdapterExtension->Common->AdapterFuncs; + NewAdapter.AdapterInterruptsBelowDpc = FALSE; + NewAdapter.AdapterUserVars = SaUserVars; + NewAdapter.AdapterUserVarsSize = sizeof(SaUserVars) / sizeof(FSA_USER_VAR); + NewAdapter.Dip = CommonExtension->OsDep.dip; + + if ( AfaCommInitNewAdapter( &NewAdapter ) == NULL) { + cmn_err(CE_WARN, "SaInitDevice: AfaCommInitNewAdapter failed\n"); + return (FAILURE); + }; + + AdapterExtension->Common->Adapter = NewAdapter.Adapter; + + if (AdapterExtension->Common->Adapter == NULL) { + AfaPortLogError(AdapterExtension->Common, FAILURE, NULL, 0); + cmn_err(CE_WARN, "%s%d SaInitDevice: No Adapter pointer", name, instance); + return (FAILURE); + } + // + // Start any kernel threads needed + OsStartKernelThreads(AdapterExtension); + // + // Tell the adapter that all is configure, and it can start accepting requests + // + + SaStartAdapter(AdapterExtension); + + // + // Put this adapter into the list of Sa adapters + // + + AdapterExtension->Next = SaAdapterList; + SaAdapterList = AdapterExtension; + AdapterExtension->Common->AdapterConfigured = TRUE; +#ifdef AACDISK + // + // Call the disk layer to initialize itself. + // + + AfaDiskInitNewAdapter( AdapterExtension->Common->AdapterNumber, AdapterExtension->Common->Adapter ); +#endif +init_done: + AdapterExtension->Common->AdapterPrintfsToScreen = FALSE; + return (0); +init_error: + return (FAILURE); +} + +void SaStartAdapter(PSa_ADAPTER_EXTENSION AdapterExtension) +{ + u32 ReturnStatus; + LARGE_INTEGER HostTime; + u32 ElapsedSeconds; + PADAPTER_INIT_STRUCT InitStruct; + + // + // Fill in the remaining pieces of the InitStruct. + // + + InitStruct = AdapterExtension->Common->InitStruct; + InitStruct->HostPhysMemPages = AfaPortGetMaxPhysicalPage(AdapterExtension->Common); + ElapsedSeconds = jiffies/HZ; + InitStruct->HostElapsedSeconds = ElapsedSeconds; + + // + // Tell the adapter we are back and up and running so it will scan its command + // queues and enable our interrupts + // + + AdapterExtension->LocalMaskInterruptControl = + (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4); + + // + // First clear out all interrupts. Then enable the one's that we can handle. + // + + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRISETIRQMASK, (u16) 0xffff ); + Sa_WRITE_USHORT( AdapterExtension, SaDbCSR.PRICLEARIRQMASK, + (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4) ); + + SaSendSynchCommand(AdapterExtension, + INIT_STRUCT_BASE_ADDRESS, + (u32) AdapterExtension->Common->PhysicalInitStruct, + 0, + 0, + 0, + &ReturnStatus); +} + + +void SaResetDevice(void * Arg1) +{ +} + +/*++ + +Routine Description: + The will cause the adapter to take a break point. + +Arguments: + None + +Return Value: + Nothing + +--*/ + +void SaInterruptAdapter(void * Arg1) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + u32 ReturnStatus; + + SaSendSynchCommand(AdapterExtension, + BREAKPOINT_REQUEST, + 0, + 0, + 0, + 0, + &ReturnStatus); +} + +/*++ + +Routine Description: + Will read the adapter CSRs to find the reason the adapter has + interrupted us. + +Arguments: + AdapterEvent - Enumerated type the returns the reason why we were interrutped. + +Return Value: + Nothing + +--*/ + +void SaNotifyAdapter(void * Arg1, HOST_2_ADAP_EVENT AdapterEvent) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + u32 ReturnStatus; + + switch (AdapterEvent) + { + case AdapNormCmdQue: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_1); + break; + case HostNormRespNotFull: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_4); + break; + case AdapNormRespQue: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_2); + break; + case HostNormCmdNotFull: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_3); + break; + case HostShutdown: +// SaSendSynchCommand(AdapterExtension, HOST_CRASHING, 0, 0, 0, 0, &ReturnStatus); + break; + case FastIo: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_6); + break; + case AdapPrintfDone: + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s,DOORBELL_5); + break; + default: + SaBugCheck(0,0,0); + AfaPortPrint("Notify requested with an invalid request 0x%x.\n",AdapterEvent); + break; + } +} + +/*++ + +Routine Description: + This routine will send a synchronous comamnd to the adapter and wait for its + completion. + +Arguments: + AdapterExtension - Pointer to adapter extension structure. + Command - Which command to send + Parameter1 - 4 - Parameters for command + ReturnStatus - return status from adapter after completion of command + +Return Value: + AAC_STATUS + +--*/ + +AAC_STATUS SaSendSynchCommand(void * Arg1, u32 Command, u32 Parameter1, u32 Parameter2, u32 Parameter3, u32 Parameter4, u32 * ReturnStatus) +{ + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) Arg1; + u32 StartTime,EndTime,WaitTime; + int CommandSucceeded; + + // + // Write the Command into Mailbox 0 + // + + Sa_WRITE_ULONG( AdapterExtension, Mailbox0, Command); + + // + // Write the parameters into Mailboxes 1 - 4 + // + + Sa_WRITE_ULONG( AdapterExtension, Mailbox1, Parameter1); + Sa_WRITE_ULONG( AdapterExtension, Mailbox2, Parameter2); + Sa_WRITE_ULONG( AdapterExtension, Mailbox3, Parameter3); + Sa_WRITE_ULONG( AdapterExtension, Mailbox4, Parameter4); + + // + // Clear the synch command doorbell to start on a clean slate. + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0); + + // + // Signal that there is a new synch command + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellReg_s, DOORBELL_0); + + CommandSucceeded = FALSE; + + StartTime = jiffies/HZ; + WaitTime = 0; + + while (WaitTime < 30) { // wait up to 30 seconds + drv_usecwait(5); // delay 5 microseconds to let Mon960 get info. + // + // Mon110 will set doorbell0 bit when it has completed the command. + // + if( Sa_READ_USHORT( AdapterExtension, DoorbellReg_p) & DOORBELL_0 ) { + CommandSucceeded = TRUE; + break; + } + EndTime = jiffies/HZ; + WaitTime = EndTime - StartTime; + } + + if (CommandSucceeded != TRUE) { + return (STATUS_IO_TIMEOUT); + } + + // + // Clear the synch command doorbell. + // + + Sa_WRITE_USHORT( AdapterExtension, DoorbellClrReg_p, DOORBELL_0); + + // + // Pull the synch status from Mailbox 0. + // + + *ReturnStatus = Sa_READ_ULONG( AdapterExtension, Mailbox0); + + // + // Return SUCCESS + // + return (STATUS_SUCCESS); +} + +/*++ + +Routine Description: + This routine will send a synchronous fib to the adapter and wait for its + completion. + +Arguments: + AdapterExtension - Pointer to adapter extension structure. + FibPhysicalAddress - Physical address of fib to send. + +Return Value: + int + +--*/ + +int SaSendSynchFib(void * Arg1, u32 FibPhysicalAddress) +{ + PPCI_MINIPORT_COMMON_EXTENSION CommonExtension = (PPCI_MINIPORT_COMMON_EXTENSION) Arg1; + PSa_ADAPTER_EXTENSION AdapterExtension = (PSa_ADAPTER_EXTENSION) CommonExtension->MiniPort; + u32 returnStatus; + + if (SaSendSynchCommand( AdapterExtension, + SEND_SYNCHRONOUS_FIB, + FibPhysicalAddress, + 0, + 0, + 0, + &returnStatus ) != STATUS_SUCCESS ) + { + return (FALSE); + } + return (TRUE); +} + diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 21cdcd17323e..d3647f5af52f 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -131,6 +131,10 @@ #include "aha1740.h" #endif +#ifdef CONFIG_SCSI_AACRAID +#include "aacraid/include/linit.h" +#endif + #ifdef CONFIG_SCSI_AIC7XXX #include "aic7xxx.h" #endif @@ -484,6 +488,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] = #ifdef CONFIG_SCSI_AHA1740 AHA1740, #endif +#ifdef CONFIG_SCSI_AACRAID + AAC_HOST_TEMPLATE_ENTRY, +#endif #ifdef CONFIG_SCSI_AIC7XXX AIC7XXX, #endif diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c index 269655ea1bdf..725eb12e0b0f 100644 --- a/drivers/scsi/megaraid.c +++ b/drivers/scsi/megaraid.c @@ -1323,7 +1323,7 @@ static int megaIssueCmd (mega_host_config * megaCfg, /* Wait until mailbox is free */ if (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox......!!\n"); + printk(KERN_ERR "megaraid: Blocked mailbox......!!\n"); udelay(1000); #if DEBUG @@ -1333,7 +1333,7 @@ static int megaIssueCmd (mega_host_config * megaCfg, /* Abort command */ if (pScb == NULL) { TRACE(("NULL pScb in megaIssue\n")); - printk("NULL pScb in megaIssue\n"); + printk(KERN_WARNING "megaraid: NULL pScb in megaIssue\n"); } mega_cmd_done (megaCfg, pScb, 0x08); return -1; @@ -1410,7 +1410,7 @@ static int megaIssueCmd (mega_host_config * megaCfg, } #if DEBUG while (mega_busyWaitMbox (megaCfg)) { - printk("Blocked mailbox on exit......!\n"); + printk(KERN_ERR "megaraid: Blocked mailbox on exit......!\n"); udelay(1000); } #endif diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index 8e60a52df68c..97ec7862ec99 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -103,7 +103,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.0-20000709" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx-3.4.1-20000726" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -144,6 +144,10 @@ #include #include +#ifdef CONFIG_ALL_PPC +#include +#endif + #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) #include #endif @@ -9070,6 +9074,9 @@ printk("ncr_user_command: data=%ld\n", uc->data); static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) { struct info_str info; +#ifdef CONFIG_ALL_PPC + struct device_node* of_node; +#endif info.buffer = ptr; info.length = len; @@ -9090,6 +9097,11 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) __irq_itoa(np->irq)); #else (int) np->irq); +#endif +#ifdef CONFIG_ALL_PPC + of_node = find_pci_device_OFnode(np->bus, np->device_fn); + if (of_node && of_node->full_name) + copy_info(&info, "PPC OpenFirmware path : %s\n", of_node->full_name); #endif copy_info(&info, " Synchronous period factor %d, " "max commands per lun %d\n", diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 68db2d08cff7..4192be647e87 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -314,6 +314,8 @@ static struct dev_info device_list[] = {"DGC", "DISK", "*", BLIST_SPARSELUN}, /* Dell PV 650F (no tgt @ LUN 0) */ {"DELL", "PV530F", "*", BLIST_SPARSELUN}, /* Dell PV 530F */ {"SONY", "TSL", "*", BLIST_FORCELUN}, /* DDS3 & DDS4 autoloaders */ +{"DELL", "PERCRAID", "*", BLIST_FORCELUN}, +{"HP", "NetRAID-4M", "*", BLIST_FORCELUN}, /* * Must be at end of list... */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index c8b4c219f8ea..bb99bc1d14d7 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -150,36 +150,43 @@ static int sd_open(struct inode * inode, struct file * filp) * This is also used to lock out further access when the partition table * is being re-read. */ - while (rscsi_disks[target].device->busy) barrier(); - if(rscsi_disks[target].device->removable) { + + /* + * When opening removable disks, we check media... + * ... unless media don't matter, due to O_NONBLOCK. + */ + if ( rscsi_disks[target].device->removable + && !(filp->f_flags & O_NONBLOCK) ) + { + /* + * Note disk change and/or removal. + * Also try to read new partition table (if any). + */ check_disk_change(inode->i_rdev); - /* - * If the drive is empty, just let the open fail. - */ + /* + * If the drive is empty, let the open fail. + */ if ( !rscsi_disks[target].ready ) - return -ENXIO; + return -ENXIO; - /* - * Similarly, if the device has the write protect tab set, - * have the open fail if the user expects to be able to write - * to the thing. - */ - if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) - return -EROFS; + /* + * If the device has the write protect tab set, + * let the open fail if the user expects to be able to write. + */ + if ( (rscsi_disks[target].write_prot) && (filp->f_mode & 2) ) + return -EROFS; } /* - * It is possible that the disk changing stuff resulted in the device being taken - * offline. If this is the case, report this to the user, and don't pretend that - * the open actually succeeded. + * It is possible that the disk changing stuff (or something + * else?) resulted in the device being taken offline. + * If so, let the open fail. */ - if( !rscsi_disks[target].device->online ) - { + if ( !rscsi_disks[target].device->online ) return -ENXIO; - } /* * See if we are requesting a non-existent partition. Do this @@ -1068,7 +1075,6 @@ static int check_scsidisk_media_change(kdev_t full_dev){ int retval; int target; struct inode inode; - int flag = 0; target = DEVICE_NR(full_dev); @@ -1120,11 +1126,11 @@ static int check_scsidisk_media_change(kdev_t full_dev){ * presence of disk in the drive. This is kept in the Scsi_Disk * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) */ - rscsi_disks[target].ready = 1; /* FLOPTICAL */ retval = rscsi_disks[target].device->changed; - if(!flag) rscsi_disks[target].device->changed = 0; + rscsi_disks[target].device->changed = 0; + return retval; } diff --git a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c index bf2083514979..4632f6c3ecce 100644 --- a/drivers/scsi/sym53c8xx.c +++ b/drivers/scsi/sym53c8xx.c @@ -85,7 +85,7 @@ /* ** Name and version of the driver */ -#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.0-20000709" +#define SCSI_NCR_DRIVER_NAME "sym53c8xx-1.7.1-20000726" #define SCSI_NCR_DEBUG_FLAGS (0) @@ -129,6 +129,10 @@ #include #include +#ifdef CONFIG_ALL_PPC +#include +#endif + #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) #include #endif @@ -14108,6 +14112,9 @@ static int copy_info(struct info_str *info, char *fmt, ...) static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) { struct info_str info; +#ifdef CONFIG_ALL_PPC + struct device_node* of_node; +#endif info.buffer = ptr; info.length = len; @@ -14129,6 +14136,11 @@ static int ncr_host_info(ncb_p np, char *ptr, off_t offset, int len) __irq_itoa(np->irq)); #else (int) np->irq); +#endif +#ifdef CONFIG_ALL_PPC + of_node = find_pci_device_OFnode(np->bus, np->device_fn); + if (of_node && of_node->full_name) + copy_info(&info, "PPC OpenFirmware path : %s\n", of_node->full_name); #endif copy_info(&info, " Synchronous period factor %d, " "max commands per lun %d\n", @@ -14413,10 +14425,10 @@ out: return retv; } -#undef SET_BIT 0 -#undef CLR_BIT 1 -#undef SET_CLK 2 -#undef CLR_CLK 3 +#undef SET_BIT +#undef CLR_BIT +#undef SET_CLK +#undef CLR_CLK /* * Try reading Symbios NVRAM. diff --git a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h index c1649d325aec..168e4cf2e61b 100644 --- a/drivers/scsi/sym53c8xx_defs.h +++ b/drivers/scsi/sym53c8xx_defs.h @@ -180,12 +180,16 @@ #endif /* - * Use normal IO if configured. Forced for alpha and ppc. + * Use normal IO if configured. Forced for alpha and powerpc. + * Powerpc fails copying to on-chip RAM using memcpy_toio(). */ -#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) || defined(SCSI_NCR_PCI_MEM_NOT_SUPPORTED) +#if defined(CONFIG_SCSI_NCR53C8XX_IOMAPPED) #define SCSI_NCR_IOMAPPED -#elif defined(__alpha__) || defined(__powerpc__) +#elif defined(__alpha__) #define SCSI_NCR_IOMAPPED +#elif defined(__powerpc__) +#define SCSI_NCR_IOMAPPED +#define SCSI_NCR_PCI_MEM_NOT_SUPPORTED #elif defined(__sparc__) #undef SCSI_NCR_IOMAPPED #endif diff --git a/drivers/sound/ac97_codec.c b/drivers/sound/ac97_codec.c index 6bea81712b37..3308f6e8f170 100644 --- a/drivers/sound/ac97_codec.c +++ b/drivers/sound/ac97_codec.c @@ -66,6 +66,7 @@ static struct { {0x43525923, "Cirrus Logic CS4298" , NULL}, {0x4352592B, "Cirrus Logic CS4294" , NULL}, {0x43525931, "Cirrus Logic CS4299" , NULL}, + {0x43525934, "Cirrus Logic CS4299" , NULL}, {0x4e534331, "National Semiconductor LM4549" , NULL}, {0x53494c22, "Silicon Laboratory Si3036" , NULL}, {0x53494c23, "Silicon Laboratory Si3038" , NULL}, @@ -648,6 +649,7 @@ static int enable_eapd(struct ac97_codec * codec) { codec->codec_write(codec, AC97_POWER_CONTROL, codec->codec_read(codec, AC97_POWER_CONTROL)|0x8000); + return 0; } diff --git a/drivers/sound/cs4281.c b/drivers/sound/cs4281.c index f5bd0468005b..44d6207c1248 100644 --- a/drivers/sound/cs4281.c +++ b/drivers/sound/cs4281.c @@ -182,7 +182,7 @@ struct cs4281_state { }; -struct cs4281_state *devs = NULL; +static struct cs4281_state *devs = NULL; // --------------------------------------------------------------------- // // Hardware Interfaces For the CS4281 diff --git a/drivers/sound/emu10k1/emu_wrapper.h b/drivers/sound/emu10k1/emu_wrapper.h index 10dd81138657..aff2666619be 100644 --- a/drivers/sound/emu10k1/emu_wrapper.h +++ b/drivers/sound/emu10k1/emu_wrapper.h @@ -14,11 +14,6 @@ #include #define vma_get_pgoff(v) vma_get_offset(v) -#define wait_queue_head_t struct wait_queue * -#define DECLARE_WAITQUEUE(a, b) struct wait_queue a = {b, NULL}; -#define init_waitqueue_head(a) init_waitqueue(a) - -#define init_MUTEX(a) *(a) = MUTEX #define UP_INODE_SEM(a) up(a) #define DOWN_INODE_SEM(a) down(a) @@ -60,14 +55,6 @@ #define MODULE_DEVICE_TABLE(foo,bar) -static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - #define pci_dma_supported(dev, mask) 1 #define PCI_ANY_ID (~0) @@ -117,21 +104,6 @@ void *compat_request_region (unsigned long start, unsigned long n, const char *n void * pci_compat_get_driver_data (struct pci_dev *dev); void pci_compat_set_driver_data (struct pci_dev *dev, void *driver_data); -typedef u32 dma_addr_t; - -extern __inline__ int __compat_get_order(unsigned long size) -{ - int order; - - size = (size-1) >> (PAGE_SHIFT-1); - order = -1; - do { - size >>= 1; - order++; - } while (size); - return order; -} - extern __inline__ void * pci_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { @@ -170,9 +142,4 @@ static inline int pci_module_init(struct pci_driver *drv) return -ENODEV; } -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - __asm__ __volatile__(".byte 0x0f,0x0b"); \ -} while (0) - #endif diff --git a/drivers/sound/emu10k1/midi.c b/drivers/sound/emu10k1/midi.c index c943a86114f2..c23a2a772ca8 100644 --- a/drivers/sound/emu10k1/midi.c +++ b/drivers/sound/emu10k1/midi.c @@ -40,7 +40,7 @@ #include "cardmi.h" #include "midi.h" -static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED; +static spinlock_t midi_spinlock __attribute((unused)) = SPIN_LOCK_UNLOCKED; static void init_midi_hdr(struct midi_hdr *midihdr) { diff --git a/drivers/sound/es1370.c b/drivers/sound/es1370.c index 810476f74810..ccb0c6806647 100644 --- a/drivers/sound/es1370.c +++ b/drivers/sound/es1370.c @@ -172,14 +172,6 @@ #define module_init(x) /* nothing */ #endif -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define wait_queue_head_t struct wait_queue * -#define init_waitqueue_head(w) *(w) = 0 -#define init_MUTEX(m) *(m) = MUTEX -#define __set_current_state(x) do { current->state = (x); } while (0) -#define set_current_state(x) __set_current_state(x) - /* --------------------------------------------------------------------- */ #ifndef PCI_VENDOR_ID_ENSONIQ diff --git a/drivers/sound/es1371.c b/drivers/sound/es1371.c index af30dbe37c43..761e425f6677 100644 --- a/drivers/sound/es1371.c +++ b/drivers/sound/es1371.c @@ -140,14 +140,6 @@ #define module_init(x) /* nothing */ #endif -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define wait_queue_head_t struct wait_queue * -#define init_waitqueue_head(w) *(w) = 0 -#define init_MUTEX(m) *(m) = MUTEX -#define __set_current_state(x) do { current->state = (x); } while (0) -#define set_current_state(x) __set_current_state(x) - /* --------------------------------------------------------------------- */ #ifndef PCI_VENDOR_ID_ENSONIQ diff --git a/drivers/sound/esssolo1.c b/drivers/sound/esssolo1.c index 54c5c9854c4a..fc2d2030c124 100644 --- a/drivers/sound/esssolo1.c +++ b/drivers/sound/esssolo1.c @@ -141,13 +141,6 @@ #define module_init(x) /* nothing */ #endif -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define wait_queue_head_t struct wait_queue * -#define init_waitqueue_head(w) *(w) = 0 -#define init_MUTEX(m) *(m) = MUTEX -#define __set_current_state(x) do { current->state = (x); } while (0) -#define set_current_state(x) __set_current_state(x) #endif /* --------------------------------------------------------------------- */ @@ -229,7 +222,7 @@ struct solo1_state { /* --------------------------------------------------------------------- */ -struct solo1_state *devs = NULL; +static struct solo1_state *devs = NULL; /* --------------------------------------------------------------------- */ diff --git a/drivers/sound/maestro.c b/drivers/sound/maestro.c index 0af9a2222e78..e35e64319abf 100644 --- a/drivers/sound/maestro.c +++ b/drivers/sound/maestro.c @@ -210,11 +210,8 @@ #include #include -#define DECLARE_WAITQUEUE(QUEUE,INIT) struct wait_queue QUEUE = {INIT, NULL} -#define wait_queue_head_t struct wait_queue * #define SILLY_PCI_BASE_ADDRESS(PCIDEV) (PCIDEV->base_address[0] & PCI_BASE_ADDRESS_IO_MASK) #define SILLY_INIT_SEM(SEM) SEM=MUTEX; -#define init_waitqueue_head init_waitqueue #define SILLY_MAKE_INIT(FUNC) __initfunc(FUNC) #define SILLY_OFFSET(VMA) ((VMA)->vm_offset) diff --git a/drivers/sound/sb_mixer.c b/drivers/sound/sb_mixer.c index c7f4b8f41ee1..0bad5eb58aed 100644 --- a/drivers/sound/sb_mixer.c +++ b/drivers/sound/sb_mixer.c @@ -109,7 +109,7 @@ MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), -MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 4, 5, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_IMIX, 0x3c, 0, 1, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2), /* Obsolete. Use IGAIN */ MIX_ENT(SOUND_MIXER_IGAIN, 0x3f, 7, 2, 0x40, 7, 2), @@ -599,13 +599,6 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg) ret = set_outmask(devc, val); break; - case SOUND_MIXER_IMIX: - val = *(int *) arg; - devc->levels[SOUND_MIXER_IMIX] = val & 0x1f; - sb_setmixer (devc, 0x3c, val); - return val; - break; - default: ret = sb_mixer_set(devc, cmd & 0xff, val); } diff --git a/drivers/sound/sonicvibes.c b/drivers/sound/sonicvibes.c index 926f3c6af992..54f0a5561735 100644 --- a/drivers/sound/sonicvibes.c +++ b/drivers/sound/sonicvibes.c @@ -123,14 +123,6 @@ #define module_init(x) /* nothing */ #endif -#define DECLARE_WAIT_QUEUE_HEAD(w) struct wait_queue *w = NULL -#define DECLARE_WAITQUEUE(w,c) struct wait_queue w = {(c), NULL} -#define wait_queue_head_t struct wait_queue * -#define init_waitqueue_head(w) *(w) = 0 -#define init_MUTEX(m) *(m) = MUTEX -#define __set_current_state(x) do { current->state = (x); } while (0) -#define set_current_state(x) __set_current_state(x) - /* --------------------------------------------------------------------- */ #ifndef PCI_VENDOR_ID_S3 diff --git a/drivers/usb/acm.c b/drivers/usb/acm.c index 7951c5895bea..35221b64749a 100644 --- a/drivers/usb/acm.c +++ b/drivers/usb/acm.c @@ -51,6 +51,7 @@ #include //#define DEBUG #include +#include /* * CMSPAR, some architectures can't have space and mark parity. diff --git a/fs/Config.in b/fs/Config.in index c5e8c904c521..ed91c5532c75 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -91,6 +91,9 @@ if [ "$CONFIG_INET" = "y" ]; then fi fi tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS + if [ "$CONFIG_SMB_FS" != "n" ]; then + string 'Default Remote NLS Option' CONFIG_SMB_NLS_REMOTE "" + fi fi if [ "$CONFIG_IPX" != "n" -o "$CONFIG_INET" != "n" ]; then tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 3c224e300ebd..cdfb7d0ce770 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -553,20 +553,21 @@ got_block: * Do block preallocation now if required. */ #ifdef EXT2_PREALLOCATE - if (prealloc_block) { + if (prealloc_count && !*prealloc_count) { int prealloc_goal; + unsigned long next_block = tmp + 1; prealloc_goal = es->s_prealloc_blocks ? es->s_prealloc_blocks : EXT2_DEFAULT_PREALLOC_BLOCKS; - *prealloc_count = 0; - *prealloc_block = tmp + 1; + *prealloc_block = next_block; for (k = 1; k < prealloc_goal && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); - k++) { + k++, next_block++) { if (DQUOT_PREALLOC_BLOCK(sb, inode, 1)) break; - if (ext2_set_bit (j + k, bh->b_data)) { + if (*prealloc_block + *prealloc_count != next_block || + ext2_set_bit (j + k, bh->b_data)) { DQUOT_FREE_BLOCK(sb, inode, 1); break; } @@ -574,12 +575,12 @@ got_block: } gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - - *prealloc_count); + (k - 1)); es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - - *prealloc_count); + (k - 1)); ext2_debug ("Preallocated a further %lu bits.\n", - *prealloc_count); + (k - 1)); } #endif diff --git a/fs/ext2/inode.c b/fs/ext2/inode.c index f9a924b40b5e..465949937eb0 100644 --- a/fs/ext2/inode.c +++ b/fs/ext2/inode.c @@ -65,17 +65,6 @@ void ext2_delete_inode (struct inode * inode) #define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)]) -static inline int block_bmap (struct buffer_head * bh, int nr) -{ - int tmp; - - if (!bh) - return 0; - tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]); - brelse (bh); - return tmp; -} - /* * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the * superblock in the same manner as are ext2_free_blocks and @@ -149,61 +138,89 @@ static int ext2_alloc_block (struct inode * inode, unsigned long goal, int * err return result; } +/** + * ext2_block_to_path - parse the block number into array of offsets + * @inode: inode in question (we are only interested in its superblock) + * @i_block: block number to be parsed + * @offsets: array to store the offsets in + * + * To store the locations of file's data ext2 uses a data structure common + * for UNIX filesystems - tree of pointers anchored in the inode, with + * data blocks at leaves and indirect blocks in intermediate nodes. + * This function translates the block number into path in that tree - + * return value is the path length and @offsets[n] is the offset of + * pointer to (n+1)th node in the nth one. If @block is out of range + * (negative or too large) warning is printed and zero returned. + * + * Note: function doesn't find node addresses, so no IO is needed. All + * we need to know is the capacity of indirect blocks (taken from the + * inode->i_sb). + */ + +/* + * Portability note: the last comparison (check that we fit into triple + * indirect block) is spelled differently, because otherwise on an + * architecture with 32-bit longs and 8Kb pages we might get into trouble + * if our filesystem had 8Kb blocks. We might use long long, but that would + * kill us on x86. Oh, well, at least the sign propagation does not matter - + * i_block would have to be negative in the very beginning, so we would not + * get there at all. + */ + +static int ext2_block_to_path(struct inode *inode, long i_block, int offsets[4]) +{ + int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); + const long direct_blocks = EXT2_NDIR_BLOCKS, + indirect_blocks = ptrs, + double_blocks = (1 << (ptrs_bits * 2)); + int n = 0; + + if (i_block < 0) { + ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0"); + } else if (i_block < direct_blocks) { + offsets[n++] = i_block; + } else if ( (i_block -= direct_blocks) < indirect_blocks) { + offsets[n++] = EXT2_IND_BLOCK; + offsets[n++] = i_block; + } else if ((i_block -= indirect_blocks) < double_blocks) { + offsets[n++] = EXT2_DIND_BLOCK; + offsets[n++] = i_block >> ptrs_bits; + offsets[n++] = i_block & (ptrs - 1); + } else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) { + offsets[n++] = EXT2_TIND_BLOCK; + offsets[n++] = i_block >> (ptrs_bits * 2); + offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1); + offsets[n++] = i_block & (ptrs - 1); + } else { + ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big"); + } + return n; +} + int ext2_bmap (struct inode * inode, int block) { + int offsets[4], *p; + int depth = ext2_block_to_path(inode, block, offsets); + struct buffer_head *bh; int i; - int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); - - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_bmap", "block < 0"); - return 0; - } - if (block >= EXT2_NDIR_BLOCKS + addr_per_block + - (1 << (addr_per_block_bits * 2)) + - ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { - ext2_warning (inode->i_sb, "ext2_bmap", "block > big"); - return 0; - } - if (block < EXT2_NDIR_BLOCKS) - return inode_bmap (inode, block); - block -= EXT2_NDIR_BLOCKS; - if (block < addr_per_block) { - i = inode_bmap (inode, EXT2_IND_BLOCK); + + if (depth == 0) + goto fail; + i = inode_bmap (inode, *(p=offsets)); + while (--depth) { if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), block); + break; + bh = bread (inode->i_dev, i, inode->i_sb->s_blocksize); + if (!bh) + goto fail; + i = le32_to_cpu(((u32 *) bh->b_data)[*++p]); + brelse (bh); } - block -= addr_per_block; - if (block < (1 << (addr_per_block_bits * 2))) { - i = inode_bmap (inode, EXT2_DIND_BLOCK); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block >> addr_per_block_bits); - if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, - inode->i_sb->s_blocksize), - block & (addr_per_block - 1)); - } - block -= (1 << (addr_per_block_bits * 2)); - i = inode_bmap (inode, EXT2_TIND_BLOCK); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block >> (addr_per_block_bits * 2)); - if (!i) - return 0; - i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - (block >> addr_per_block_bits) & (addr_per_block - 1)); - if (!i) - return 0; - return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), - block & (addr_per_block - 1)); + return i; +fail: + return 0; } static struct buffer_head * inode_getblk (struct inode * inode, int nr, @@ -349,21 +366,12 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block, int create, int * err) { struct buffer_head * bh; - unsigned long b; - unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); - int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb); + int offsets[4], *p; + int depth = ext2_block_to_path(inode, block, offsets); *err = -EIO; - if (block < 0) { - ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); - return NULL; - } - if (block > EXT2_NDIR_BLOCKS + addr_per_block + - (1 << (addr_per_block_bits * 2)) + - ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) { - ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); - return NULL; - } + if (depth == 0) + goto fail; /* * If this is a sequential block allocation, set the next_alloc_block * to this block now so that all the indblock and data block @@ -380,31 +388,14 @@ struct buffer_head * ext2_getblk (struct inode * inode, long block, } *err = -ENOSPC; - b = block; - if (block < EXT2_NDIR_BLOCKS) - return inode_getblk (inode, block, create, b, err); - block -= EXT2_NDIR_BLOCKS; - if (block < addr_per_block) { - bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err); - return block_getblk (inode, bh, block, create, - inode->i_sb->s_blocksize, b, err); - } - block -= addr_per_block; - if (block < (1 << (addr_per_block_bits * 2))) { - bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block >> addr_per_block_bits, - create, inode->i_sb->s_blocksize, b, err); - return block_getblk (inode, bh, block & (addr_per_block - 1), - create, inode->i_sb->s_blocksize, b, err); - } - block -= (1 << (addr_per_block_bits * 2)); - bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); - bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2), - create, inode->i_sb->s_blocksize, b, err); - bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1), - create, inode->i_sb->s_blocksize, b, err); - return block_getblk (inode, bh, block & (addr_per_block - 1), create, - inode->i_sb->s_blocksize, b, err); + bh = inode_getblk (inode, *(p=offsets), create, block, err); + while (--depth) { + bh = block_getblk (inode, bh, *++p, create, + inode->i_sb->s_blocksize, block, err); + } + return bh; +fail: + return NULL; } struct buffer_head * ext2_bread (struct inode * inode, int block, diff --git a/fs/nls/Config.in b/fs/nls/Config.in index b402c722e744..aeeeb216662f 100644 --- a/fs/nls/Config.in +++ b/fs/nls/Config.in @@ -4,7 +4,8 @@ # msdos and Joliet want NLS if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \ - -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" ]; then + -o "$CONFIG_NTFS_FS" != "n" -o "$CONFIG_NCPFS_NLS" = "y" \ + -o "$CONFIG_SMB_FS" != n ]; then define_bool CONFIG_NLS y else define_bool CONFIG_NLS n diff --git a/fs/smbfs/ChangeLog b/fs/smbfs/ChangeLog index 2ce92a04eb18..3a48f4f9eaad 100644 --- a/fs/smbfs/ChangeLog +++ b/fs/smbfs/ChangeLog @@ -1,5 +1,15 @@ ChangeLog for smbfs. +2000-09-01 Urban Widmark + + * proc.c: add back lanman2 support (OS/2 and others) + * proc.c: check length of paths to avoid buffer overflow + * proc.c: don't do interruptable_sleep in smb_retry to avoid signal + problem/race. + * proc.c: O_RDONLY & smb_revalidate_inode fix (tail -f) + * proc.c: add nls support + * sock.c: attempt to fix smb_data_callback (avoid infinite loop) + 2000-07-20 Urban Widmark * proc.c: fix 2 places where bad server responses could cause an Oops. diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index d60f2ad52d49..234a0dfd8145 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -167,7 +167,7 @@ out: } /* - * Note: in order to allow the smbclient process to open the + * Note: in order to allow the smbmount process to open the * mount point, we don't revalidate if conn_pid is NULL. */ static int @@ -194,10 +194,10 @@ static void smb_delete_dentry(struct dentry *); static struct dentry_operations smbfs_dentry_operations = { - smb_lookup_validate, /* d_revalidate(struct dentry *) */ - smb_hash_dentry, /* d_hash */ - smb_compare_dentry, /* d_compare */ - smb_delete_dentry /* d_delete(struct dentry *) */ + d_revalidate: smb_lookup_validate, + d_hash: smb_hash_dentry, + d_compare: smb_compare_dentry, + d_delete: smb_delete_dentry }; /* @@ -256,8 +256,7 @@ smb_compare_dentry(struct dentry *dir, struct qstr *a, struct qstr *b) if (a->len != b->len) goto out; - for (i=0; i < a->len; i++) - { + for (i=0; i < a->len; i++) { if (tolower(a->name[i]) != tolower(b->name[i])) goto out; } diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 18d18c2dcfed..2ac79f78d6dc 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -320,13 +321,22 @@ smb_put_super(struct super_block *sb) if (server->packet) smb_vfree(server->packet); + if(sb->u.smbfs_sb.remote_nls) { + unload_nls(sb->u.smbfs_sb.remote_nls); + sb->u.smbfs_sb.remote_nls = NULL; + } + if(sb->u.smbfs_sb.local_nls) { + unload_nls(sb->u.smbfs_sb.local_nls); + sb->u.smbfs_sb.local_nls = NULL; + } + MOD_DEC_USE_COUNT; } struct super_block * smb_read_super(struct super_block *sb, void *raw_data, int silent) { - struct smb_mount_data *mnt; + struct smb_mount_data_kernel *mnt; struct inode *root_inode; struct smb_fattr root; @@ -357,23 +367,37 @@ smb_read_super(struct super_block *sb, void *raw_data, int silent) goto out_no_mem; /* Allocate the global temp buffer */ - sb->u.smbfs_sb.temp_buf = kmalloc(SMB_MAXPATHLEN + 20, GFP_KERNEL); + sb->u.smbfs_sb.temp_buf = kmalloc(2*SMB_MAXPATHLEN + 20, GFP_KERNEL); if (!sb->u.smbfs_sb.temp_buf) goto out_no_temp; + /* Setup NLS stuff */ + sb->u.smbfs_sb.remote_nls = NULL; + sb->u.smbfs_sb.local_nls = NULL; + sb->u.smbfs_sb.name_buf = sb->u.smbfs_sb.temp_buf + SMB_MAXPATHLEN + 20; + /* Allocate the mount data structure */ - mnt = kmalloc(sizeof(struct smb_mount_data), GFP_KERNEL); + mnt = kmalloc(sizeof(struct smb_mount_data_kernel), GFP_KERNEL); if (!mnt) goto out_no_mount; - *mnt = *((struct smb_mount_data *) raw_data); + memcpy(mnt, raw_data, sizeof(struct smb_mount_data)); + strncpy(mnt->codepage.local_name, CONFIG_NLS_DEFAULT, + SMB_NLS_MAXNAMELEN); + strncpy(mnt->codepage.remote_name, CONFIG_SMB_NLS_REMOTE, + SMB_NLS_MAXNAMELEN); + /* FIXME: ** temp ** pass config flags in file mode */ - mnt->version = (mnt->file_mode >> 9); + mnt->flags = (mnt->file_mode >> 9); mnt->file_mode &= (S_IRWXU | S_IRWXG | S_IRWXO); mnt->file_mode |= S_IFREG; mnt->dir_mode &= (S_IRWXU | S_IRWXG | S_IRWXO); mnt->dir_mode |= S_IFDIR; sb->u.smbfs_sb.mnt = mnt; + smb_setcodepage(&sb->u.smbfs_sb, &mnt->codepage); + if (!sb->u.smbfs_sb.convert) + PARANOIA("convert funcptr was NULL!\n"); + /* * Keep the super block locked while we get the root inode. */ diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index f412b76ff444..e47be5a85d2e 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -48,6 +49,19 @@ smb_proc_do_getattr(struct dentry *dir, struct smb_fattr *fattr, struct smb_sb_info *server); +static inline void +smb_lock_server(struct smb_sb_info *server) +{ + down(&(server->sem)); +} + +static inline void +smb_unlock_server(struct smb_sb_info *server) +{ + up(&(server->sem)); +} + + /* reverse a string inline. This is used by the dircache walking routines */ static void reverse_string(char *buf, int len) { char c; @@ -60,6 +74,100 @@ static void reverse_string(char *buf, int len) { } } +/* no conversion, just a wrapper for memcpy. */ +static int convert_memcpy(char *output, int olen, + const char *input, int ilen, + struct nls_table *nls_from, + struct nls_table *nls_to) +{ + memcpy(output, input, ilen); + return ilen; +} + +/* convert from one "codepage" to another (possibly being utf8). */ +static int convert_cp(char *output, int olen, + const char *input, int ilen, + struct nls_table *nls_from, + struct nls_table *nls_to) +{ + int len = 0; + int n; + unsigned char ch; + unsigned char cl; + + /* we don't need this, but we are a bit paranoid ... */ + if (!nls_from || !nls_to) { + PARANOIA("nls_from=%p, nls_to=%p\n", nls_from, nls_to); + return convert_memcpy(output, olen, input, ilen, NULL, NULL); + } + + while (ilen > 0) { + /* convert by changing to unicode and back to the new cp */ + n = -1; + nls_from->char2uni((unsigned char *)input, &n, &cl, &ch); + if (n < 0) + goto out; + input += n; + ilen -= n; + + n = -1; + nls_to->uni2char(ch, cl, output, olen, &n); + if (n < 0) + goto out; + output += n; + olen -= n; + + len += n; + } +out: + return len; +} + +static int setcodepage(struct smb_sb_info *server, + struct nls_table **p, char *name) +{ + struct nls_table *nls; + + if (!name || !*name) { + nls = NULL; + } else if ( (nls = load_nls(name)) == NULL) { + printk (KERN_ERR "smbfs: failed to load nls '%s'\n", name); + return -EINVAL; + } + + /* if already set, unload the previous one. */ + if (*p) + unload_nls(*p); + *p = nls; + + return 0; +} + +/* Handles all changes to codepage settings. */ +int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp) +{ + int n; + + smb_lock_server(server); + + n = setcodepage(server, &server->local_nls, cp->local_name); + if (n != 0) + goto out; + n = setcodepage(server, &server->remote_nls, cp->remote_name); + if (n != 0) + setcodepage(server, &server->local_nls, NULL); + +out: + if (server->local_nls != NULL && server->remote_nls != NULL) + server->convert = convert_cp; + else + server->convert = convert_memcpy; + + smb_unlock_server(server); + return n; +} + + /*****************************************************************************/ /* */ /* Encoding/Decoding section */ @@ -81,12 +189,14 @@ smb_encode_smb_length(__u8 * p, __u32 len) } /* - * smb_build_path: build the path to entry and name storing it in buf. + * smb_encode_path: build the path to entry and name storing it in buf. * The path returned will have the trailing '\0'. */ -static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf) +static int smb_encode_path(struct smb_sb_info *server, char * buf, + struct dentry * entry, struct qstr * name) { char *path = buf; + int len; if (entry == NULL) goto test_name_and_out; @@ -106,9 +216,16 @@ static int smb_build_path(struct dentry * entry, struct qstr * name, char * buf) * and store it in reversed order [see reverse_string()] */ for (;;) { - memcpy(path, entry->d_name.name, entry->d_name.len); - reverse_string(path, entry->d_name.len); - path += entry->d_name.len; + if (entry->d_name.len > SMB_MAXNAMELEN) + return -ENAMETOOLONG; + if (path - buf + entry->d_name.len > SMB_MAXPATHLEN) + return -ENAMETOOLONG; + + len = server->convert(path, SMB_MAXNAMELEN, + entry->d_name.name, entry->d_name.len, + server->local_nls, server->remote_nls); + reverse_string(path, len); + path += len; *(path++) = '\\'; @@ -124,22 +241,16 @@ test_name_and_out: if (name != NULL) { *(path++) = '\\'; name_and_out: - memcpy(path, name->name, name->len); - path += name->len; + len = server->convert(path, SMB_MAXNAMELEN, + name->name, name->len, + server->local_nls, server->remote_nls); + path += len; } out: *(path++) = '\0'; return (path-buf); } -static char *smb_encode_path(struct smb_sb_info *server, char *buf, - struct dentry *dir, struct qstr *name) -{ - buf += smb_build_path(dir, name, buf); - - return buf; -} - /* The following are taken directly from msdos-fs */ /* Linear day numbers of the respective 1sts in non-leap years. */ @@ -434,24 +545,12 @@ err_unknown: return EIO; } -static inline void -smb_lock_server(struct smb_sb_info *server) -{ - down(&(server->sem)); -} - -static inline void -smb_unlock_server(struct smb_sb_info *server) -{ - up(&(server->sem)); -} - /* * smb_retry: This function should be called when smb_request_ok has - indicated an error. If the error was indicated because the - connection was killed, we try to reconnect. If smb_retry returns 0, - the error was indicated for another reason, so a retry would not be - of any use. + * indicated an error. If the error was indicated because the + * connection was killed, we try to reconnect. If smb_retry returns 0, + * the error was indicated for another reason, so a retry would not be + * of any use. * N.B. The server must be locked for this call. */ static int @@ -465,8 +564,7 @@ smb_retry(struct smb_sb_info *server) smb_close_socket(server); - if (pid == 0) - { + if (pid == 0) { printk(KERN_ERR "smb_retry: no connection process\n"); server->state = CONN_RETRIED; goto out; @@ -481,26 +579,35 @@ smb_retry(struct smb_sb_info *server) * Note: use the "priv" flag, as a user process may need to reconnect. */ error = kill_proc(pid, SIGUSR1, 1); - if (error) - { + if (error) { printk(KERN_ERR "smb_retry: signal failed, error=%d\n", error); goto out_restore; } - VERBOSE("signalled pid %d, waiting for new connection\n", - server->conn_pid); + VERBOSE("signalled pid %d, waiting for new connection\n", pid); /* * Wait for the new connection. */ +#ifdef SMB_RETRY_INTR interruptible_sleep_on_timeout(&server->wait, 5*HZ); if (signal_pending(current)) printk(KERN_INFO "caught signal\n"); +#else + /* + * We don't want to be interrupted. For example, what if 'current' + * already has recieved a signal? sleep_on would terminate immediately + * and smbmount would not be able to re-establish connection. + * + * smbmount should be able to reconnect later, but it can't because + * it will get an -EIO on attempts to open the mountpoint! + */ + sleep_on_timeout(&server->wait, 5*HZ); +#endif /* * Check for a valid connection. */ - if (server->state == CONN_VALID) - { + if (server->state == CONN_VALID) { PARANOIA("sucessful, new pid=%d, generation=%d\n", server->conn_pid, server->generation); result = 1; @@ -599,8 +706,13 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) !capable(CAP_SYS_ADMIN)) goto out; - if (opt->protocol < SMB_PROTOCOL_NT1) { - printk(KERN_NOTICE "smbfs: protocols older than NT1 are not suppported\n"); + /* + * Support NT1 & LANMAN2, they are not that different and + * some people are still using LANMAN2 (OS/2) + */ + if (opt->protocol < SMB_PROTOCOL_LANMAN2) { + printk(KERN_NOTICE "smbfs: protocols older than LANMAN2 are not" + " suppported [%d]\n", opt->protocol); goto out; } @@ -626,9 +738,10 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) /* now that we have an established connection we can detect the server type and enable bug workarounds */ - if ((server->opt.max_xmit < 0x1000) && + if (server->opt.protocol == SMB_PROTOCOL_NT1 && + (server->opt.max_xmit < 0x1000) && !(server->opt.capabilities & SMB_CAP_NT_SMBS)) { - server->mnt->version |= SMB_FIX_WIN95; + server->mnt->flags |= SMB_MOUNT_WIN95; #ifdef SMBFS_DEBUG_VERBOSE printk(KERN_NOTICE "smb_newconn: detected WIN95 server\n"); #endif @@ -639,7 +752,11 @@ smb_newconn(struct smb_sb_info *server, struct smb_conn_opt *opt) server->opt.capabilities); out: +#ifdef SMB_RETRY_INTR wake_up_interruptible(&server->wait); +#else + wake_up(&server->wait); +#endif return error; out_putf: @@ -706,7 +823,7 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish) { struct inode *ino = dentry->d_inode; int mode, read_write = 0x42, read_only = 0x40; - int error; + int res; char *p; /* @@ -716,29 +833,33 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish) if (!(ino->i_mode & (S_IWUSR | S_IWGRP | S_IWOTH))) mode = read_only; #if 0 + /* FIXME: why is this code not in? below we fix it so that a caller + wanting RO doesn't get RW. smb_revalidate_inode does some + optimization based on access mode. tail -f needs it to be correct. */ if (!(wish & (O_WRONLY | O_RDWR))) mode = read_only; #endif - retry: +retry: p = smb_setup_header(server, SMBopen, 2, 0); WSET(server->packet, smb_vwv0, mode); WSET(server->packet, smb_vwv1, aSYSTEM | aHIDDEN | aDIR); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + res = smb_encode_path(server, p, dentry, NULL); + if (res < 0) + goto out; + p += res; smb_setup_bcc(server, p); - error = smb_request_ok(server, SMBopen, 7, 0); - if (error != 0) - { + res = smb_request_ok(server, SMBopen, 7, 0); + if (res != 0) { if (smb_retry(server)) goto retry; if (mode == read_write && - (error == -EACCES || error == -ETXTBSY || error == -EROFS)) - { + (res == -EACCES || res == -ETXTBSY || res == -EROFS)) { VERBOSE("%s/%s R/W failed, error=%d, retrying R/O\n", - DENTRY_PATH(dentry), error); + DENTRY_PATH(dentry), res); mode = read_only; goto retry; } @@ -751,10 +872,12 @@ smb_proc_open(struct smb_sb_info *server, struct dentry *dentry, int wish) /* smb_vwv2 has mtime */ /* smb_vwv4 has size */ ino->u.smbfs_i.access = (WVAL(server->packet, smb_vwv6) & SMB_ACCMASK); + if (!(wish & (O_WRONLY | O_RDWR))) + ino->u.smbfs_i.access = SMB_O_RDONLY; ino->u.smbfs_i.open = server->generation; out: - return error; + return res; } /* @@ -768,8 +891,7 @@ smb_open(struct dentry *dentry, int wish) int result; result = -ENOENT; - if (!inode) - { + if (!inode) { printk(KERN_ERR "smb_open: no inode for dentry %s/%s\n", DENTRY_PATH(dentry)); goto out; @@ -780,16 +902,14 @@ smb_open(struct dentry *dentry, int wish) * currently open, we can be sure that the file isn't about * to be closed. (See smb_close_dentry() below.) */ - if (!smb_is_open(inode)) - { + if (!smb_is_open(inode)) { struct smb_sb_info *server = SMB_SERVER(inode); smb_lock_server(server); result = 0; if (!smb_is_open(inode)) result = smb_proc_open(server, dentry, wish); smb_unlock_server(server); - if (result) - { + if (result) { PARANOIA("%s/%s open failed, result=%d\n", DENTRY_PATH(dentry), result); goto out; @@ -805,8 +925,7 @@ smb_open(struct dentry *dentry, int wish) */ result = 0; if (inode->u.smbfs_i.access != wish && - inode->u.smbfs_i.access != SMB_O_RDWR) - { + inode->u.smbfs_i.access != SMB_O_RDWR) { PARANOIA("%s/%s access denied, access=%x, wish=%x\n", DENTRY_PATH(dentry), inode->u.smbfs_i.access, wish); result = -EACCES; @@ -871,6 +990,8 @@ smb_proc_close_inode(struct smb_sb_info *server, struct inode * ino) /* * Force a revalidation after closing */ + if (server->opt.protocol < SMB_PROTOCOL_NT1) + ino->u.smbfs_i.oldmtime = 0; ino->u.smbfs_i.closed = jiffies; } return result; @@ -1029,31 +1150,33 @@ smb_proc_create(struct dentry *dentry, __u16 attr, time_t ctime, __u16 *fileid) { struct smb_sb_info *server = server_from_dentry(dentry); char *p; - int error; + int result; smb_lock_server(server); - retry: +retry: p = smb_setup_header(server, SMBcreate, 3, 0); WSET(server->packet, smb_vwv0, attr); DSET(server->packet, smb_vwv1, utc2local(server, ctime)); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); - error = smb_request_ok(server, SMBcreate, 1, 0); - if (error < 0) - { + result = smb_request_ok(server, SMBcreate, 1, 0); + if (result < 0) { if (smb_retry(server)) goto retry; goto out; } *fileid = WVAL(server->packet, smb_vwv0); - error = 0; + result = 0; out: smb_unlock_server(server); - return error; + return result; } int @@ -1065,17 +1188,22 @@ smb_proc_mv(struct dentry *old_dentry, struct dentry *new_dentry) smb_lock_server(server); - retry: +retry: p = smb_setup_header(server, SMBmv, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN | aDIR); *p++ = 4; - p = smb_encode_path(server, p, old_dentry, NULL); + result = smb_encode_path(server, p, old_dentry, NULL); + if (result < 0) + goto out; + p += result; *p++ = 4; - p = smb_encode_path(server, p, new_dentry, NULL); + result = smb_encode_path(server, p, new_dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); - if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBmv, 0, 0)) < 0) { if (smb_retry(server)) goto retry; goto out; @@ -1098,15 +1226,17 @@ smb_proc_generic_command(struct dentry *dentry, __u8 command) smb_lock_server(server); - retry: +retry: p = smb_setup_header(server, command, 0, 0); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); result = smb_request_ok(server, command, 0, 0); - if (result < 0) - { + if (result < 0) { if (smb_retry(server)) goto retry; goto out; @@ -1165,15 +1295,17 @@ smb_proc_unlink(struct dentry *dentry) smb_lock_server(server); - retry: +retry: p = smb_setup_header(server, SMBunlink, 1, 0); WSET(server->packet, smb_vwv0, aSYSTEM | aHIDDEN); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); - if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) - { + if ((result = smb_request_ok(server, SMBunlink, 0, 0)) < 0) { #if SMBFS_POSIX_UNLINK if (result == -EACCES && !flag) { /* Posix semantics is for the read-only state @@ -1292,7 +1424,7 @@ smb_init_root_dirent(struct smb_sb_info *server, struct smb_fattr *fattr) */ static char * smb_decode_long_dirent(struct smb_sb_info *server, char *p, - struct cache_dirent *entry) + struct cache_dirent *entry, int level) { char *result; unsigned int len = 0; @@ -1302,19 +1434,39 @@ smb_decode_long_dirent(struct smb_sb_info *server, char *p, */ entry->ino = 0; - result = p + WVAL(p, 0); - len = DVAL(p, 60); - if (len > SMB_MAXNAMELEN) - len = SMB_MAXNAMELEN; - /* NT4 null terminates */ - entry->name = p + 94; - if (len && entry->name[len-1] == '\0') - len--; - entry->len = len; - - VERBOSE("info 260 at %p, len=%d, name=%.*s\n", - p, entry->len, entry->len, entry->name); + switch (level) { + case 1: + len = *((unsigned char *) p + 22); + entry->name = p + 23; + result = p + 24 + len; + + VERBOSE("info 1 at %p, len=%d, name=%.*s\n", + p, len, len, entry->name); + break; + case 260: + result = p + WVAL(p, 0); + len = DVAL(p, 60); + if (len > SMB_MAXNAMELEN) + len = SMB_MAXNAMELEN; + /* NT4 null terminates */ + entry->name = p + 94; + if (len && entry->name[len-1] == '\0') + len--; + + VERBOSE("info 260 at %p, len=%d, name=%.*s\n", + p, len, len, entry->name); + break; + default: + PARANOIA("Unknown info level %d\n", level); + result = p + WVAL(p, 0); + goto out; + } + entry->len = server->convert(server->name_buf, SMB_MAXNAMELEN, + entry->name, len, + server->remote_nls, server->local_nls); + entry->name = server->name_buf; +out: return result; } @@ -1336,9 +1488,11 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, void *cachep) { unsigned char *p; - char *mask, *param = server->temp_buf; + char *mask, *lastname, *param = server->temp_buf; __u16 command; int first, entries, entries_seen; + + /* Both NT and OS/2 accept info level 1 (but see note below). */ int info_level = 260; const int max_matches = 512; @@ -1348,19 +1502,30 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, int resp_param_len = 0; int ff_searchcount = 0; int ff_eos = 0; + int ff_lastname = 0; int ff_dir_handle = 0; int loop_count = 0; int mask_len, i, result; static struct qstr star = { "*", 1, 0 }; + /* + * use info level 1 for older servers that don't do 260 + */ + if (server->opt.protocol < SMB_PROTOCOL_NT1) + info_level = 1; + smb_lock_server(server); - retry: +retry: /* * Encode the initial path */ mask = param + 12; - mask_len = smb_encode_path(server, mask, dir, &star) - mask; + mask_len = smb_encode_path(server, mask, dir, &star); + if (mask_len < 0) { + entries = mask_len; + goto unlock_return; + } first = 1; VERBOSE("starting fpos=%d, mask=%s\n", fpos, mask); @@ -1386,15 +1551,10 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, command = TRANSACT2_FINDFIRST; WSET(param, 0, aSYSTEM | aHIDDEN | aDIR); WSET(param, 2, max_matches); /* max count */ - WSET(param, 4, - SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); + WSET(param, 4, SMB_CLOSE_IF_END); WSET(param, 6, info_level); DSET(param, 8, 0); } else { - /* we don't need the mask after the first bit */ - mask_len = 0; - mask[0] = 0; - command = TRANSACT2_FINDNEXT; VERBOSE("handle=0x%X, mask=%s\n", @@ -1404,8 +1564,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, WSET(param, 2, max_matches); /* max count */ WSET(param, 4, info_level); DSET(param, 6, 0); /* ff_resume_key */ - WSET(param, 10, - SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); + WSET(param, 10, SMB_CONTINUE_BIT|SMB_CLOSE_IF_END); } result = smb_trans2_request(server, command, @@ -1444,14 +1603,42 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, ff_dir_handle = WVAL(resp_param, 0); ff_searchcount = WVAL(resp_param, 2); ff_eos = WVAL(resp_param, 4); + ff_lastname = WVAL(resp_param, 8); } else { ff_searchcount = WVAL(resp_param, 0); ff_eos = WVAL(resp_param, 2); + ff_lastname = WVAL(resp_param, 6); } if (ff_searchcount == 0) break; + /* we might need the lastname for continuations */ + mask_len = 0; + if (ff_lastname > 0) { + lastname = resp_data + ff_lastname; + switch (info_level) { + case 260: + if (ff_lastname < resp_data_len) + mask_len = resp_data_len - ff_lastname; + break; + case 1: + /* Win NT 4.0 doesn't set the length byte */ + lastname++; + if (ff_lastname + 2 < resp_data_len) + mask_len = strlen(lastname); + break; + } + /* + * Update the mask string for the next message. + */ + if (mask_len > 255) + mask_len = 255; + if (mask_len) + strncpy(mask, lastname, mask_len); + } + mask[mask_len] = 0; + /* Now we are ready to parse smb directory entries. */ /* point to the data bytes */ @@ -1470,7 +1657,7 @@ smb_proc_readdir_long(struct smb_sb_info *server, struct dentry *dir, int fpos, goto unlock_return; } - p = smb_decode_long_dirent(server, p, entry); + p = smb_decode_long_dirent(server, p, entry,info_level); /* ignore . and .. from the server */ if (entries_seen == 2 && entry->name[0] == '.') { @@ -1517,10 +1704,13 @@ smb_proc_getattr_core(struct smb_sb_info *server, struct dentry *dir, int result; char *p; - retry: +retry: p = smb_setup_header(server, SMBgetatr, 0, 0); *p++ = 4; - p = smb_encode_path(server, p, dir, NULL); + result = smb_encode_path(server, p, dir, NULL); + if (result < 0) + goto out; + p += result; smb_setup_bcc(server, p); if ((result = smb_request_ok(server, SMBgetatr, 10, 0)) < 0) { @@ -1571,31 +1761,32 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, int resp_param_len = 0; int result; - retry: +retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); - p = smb_encode_path(server, param + 6, dir, NULL); + p = param + 6; + result = smb_encode_path(server, p, dir, NULL); + if (result < 0) + goto out; + p += result; result = smb_trans2_request(server, TRANSACT2_QPATHINFO, 0, NULL, p - param, param, &resp_data_len, &resp_data, &resp_param_len, &resp_param); - if (result < 0) - { + if (result < 0) { if (smb_retry(server)) goto retry; goto out; } - if (server->rcls != 0) - { + if (server->rcls != 0) { VERBOSE("for %s: result=%d, rcls=%d, err=%d\n", ¶m[6], result, server->rcls, server->err); result = -smb_errno(server); goto out; } result = -ENOENT; - if (resp_data_len < 22) - { + if (resp_data_len < 22) { PARANOIA("not enough data for %s, len=%d\n", ¶m[6], resp_data_len); goto out; @@ -1605,7 +1796,7 @@ smb_proc_getattr_trans2(struct smb_sb_info *server, struct dentry *dir, * Kludge alert: Win 95 swaps the date and time field, * contrary to the CIFS docs and Win NT practice. */ - if (server->mnt->version & SMB_FIX_WIN95) { + if (server->mnt->flags & SMB_MOUNT_WIN95) { off_date = 2; off_time = 0; } @@ -1649,7 +1840,7 @@ smb_proc_do_getattr(struct dentry *dir, struct smb_fattr *fattr, * Select whether to use core or trans2 getattr. * Win 95 appears to break with the trans2 getattr. */ - if (server->mnt->version & SMB_FIX_WIN95) { + if (server->mnt->flags & SMB_MOUNT_WIN95) { result = smb_proc_getattr_core(server, dir, fattr); } else { result = smb_proc_getattr_trans2(server, dir, fattr); @@ -1702,7 +1893,10 @@ smb_proc_setattr_core(struct smb_sb_info *server, struct dentry *dentry, WSET(server->packet, smb_vwv6, 0); WSET(server->packet, smb_vwv7, 0); *p++ = 4; - p = smb_encode_path(server, p, dentry, NULL); + result = smb_encode_path(server, p, dentry, NULL); + if (result < 0) + goto out; + p += result; *p++ = 4; *p++ = 0; smb_setup_bcc(server, p); @@ -1803,7 +1997,11 @@ smb_proc_setattr_trans2(struct smb_sb_info *server, retry: WSET(param, 0, 1); /* Info level SMB_INFO_STANDARD */ DSET(param, 2, 0); - p = smb_encode_path(server, param + 6, dir, NULL); + p = param + 6; + result = smb_encode_path(server, p, dir, NULL); + if (result < 0) + goto out; + p += result; WSET(data, 0, 0); /* creation time */ WSET(data, 2, 0); @@ -1867,7 +2065,7 @@ smb_proc_settime(struct dentry *dentry, struct smb_fattr *fattr) smb_lock_server(server); /* setting the time on a Win95 server fails (tridge) */ - if (!(server->mnt->version & SMB_FIX_WIN95)) { + if (!(server->mnt->flags & SMB_MOUNT_WIN95)) { if (smb_is_open(inode) && inode->u.smbfs_i.access != SMB_O_RDONLY) result = smb_proc_setattr_ext(server, inode, fattr); @@ -1907,7 +2105,7 @@ smb_proc_dskattr(struct super_block *sb, struct statfs *attr) smb_lock_server(server); - retry: +retry: smb_setup_header(server, SMBdskattr, 0, 0); if ((error = smb_request_ok(server, SMBdskattr, 5, 0)) < 0) { diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index fa0a3b2e3a7d..4a4f8077559f 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -108,23 +108,24 @@ smb_data_callback(void* ptr) unsigned char peek_buf[4]; int result; mm_segment_t fs; + int count = 100; /* this is a lot, we should have some data waiting */ + int found = 0; fs = get_fs(); set_fs(get_ds()); lock_kernel(); - while (1) - { + while (count-- > 0) { + peek_buf[0] = 0; result = -EIO; - if (job->sk->dead) - { + if (job->sk->dead) { PARANOIA("sock dead!\n"); break; } result = _recvfrom(socket, (void *) peek_buf, 1, MSG_PEEK | MSG_DONTWAIT); - if (result == -EAGAIN) + if (result < 0) break; if (peek_buf[0] != 0x85) break; @@ -135,13 +136,15 @@ smb_data_callback(void* ptr) DEBUG1("got SESSION KEEPALIVE\n"); - if (result == -EAGAIN) + if (result < 0) break; + found = 1; } unlock_kernel(); set_fs(fs); - if (result != -EAGAIN) + DEBUG1("found=%d, count=%d, result=%d\n", found, count, result); + if (found) found_data(job->sk); kfree(ptr); } diff --git a/include/asm-alpha/page.h b/include/asm-alpha/page.h index c2d27951e54e..0d57b715db84 100644 --- a/include/asm-alpha/page.h +++ b/include/asm-alpha/page.h @@ -68,6 +68,19 @@ static inline void copy_page(unsigned long _to, unsigned long _from) } while (count); } +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #ifdef STRICT_MM_TYPECHECKS /* * These are used to make use of C type-checking.. diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h index 698ce18211a8..7e84e93da15f 100644 --- a/include/asm-alpha/semaphore.h +++ b/include/asm-alpha/semaphore.h @@ -26,6 +26,11 @@ struct semaphore { #define sema_init(sem, val) atomic_set(&((sem)->count), val) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern int __down_trylock(struct semaphore * sem); diff --git a/include/asm-alpha/types.h b/include/asm-alpha/types.h index 381d5f0441dc..d8d3e2f8975b 100644 --- a/include/asm-alpha/types.h +++ b/include/asm-alpha/types.h @@ -73,5 +73,7 @@ typedef unsigned long u64; #endif +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif /* _ALPHA_TYPES_H */ diff --git a/include/asm-arm/page.h b/include/asm-arm/page.h index 704b99b05cda..78a0b360a809 100644 --- a/include/asm-arm/page.h +++ b/include/asm-arm/page.h @@ -19,4 +19,17 @@ /* void *__va(unsigned long x) */ #define __va(x) ((void *)(__phys_to_virt((unsigned long)(x)))) +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif diff --git a/include/asm-arm/semaphore.h b/include/asm-arm/semaphore.h index 1a3db3ee2ed5..173d516262e5 100644 --- a/include/asm-arm/semaphore.h +++ b/include/asm-arm/semaphore.h @@ -16,6 +16,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + asmlinkage void __down_failed (void /* special register calling convention */); asmlinkage int __down_interruptible_failed (void /* special register calling convention */); asmlinkage int __down_failed_trylock(void /* params in registers */); diff --git a/include/asm-arm/types.h b/include/asm-arm/types.h index a1e76285adac..6ba26b692871 100644 --- a/include/asm-arm/types.h +++ b/include/asm-arm/types.h @@ -41,6 +41,8 @@ typedef unsigned long long u64; #define BITS_PER_LONG 32 +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-i386/page.h b/include/asm-i386/page.h index 0490404b7b6c..e3d39bf711e0 100644 --- a/include/asm-i386/page.h +++ b/include/asm-i386/page.h @@ -53,6 +53,25 @@ typedef unsigned long pgprot_t; #define __pgprot(x) (x) #endif + +#define BUG() do { \ + printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ + __asm__ __volatile__(".byte 0x0f,0x0b"); \ +} while (0) + +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ @@ -89,6 +108,7 @@ typedef unsigned long pgprot_t; #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) + #endif /* __KERNEL__ */ #endif /* _I386_PAGE_H */ diff --git a/include/asm-i386/semaphore.h b/include/asm-i386/semaphore.h index afb4786a1d9e..a6278090b7e3 100644 --- a/include/asm-i386/semaphore.h +++ b/include/asm-i386/semaphore.h @@ -41,6 +41,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); asmlinkage int __down_failed_trylock(void /* params in registers */); diff --git a/include/asm-i386/types.h b/include/asm-i386/types.h index d792546f9fb7..93ecd4c7dcba 100644 --- a/include/asm-i386/types.h +++ b/include/asm-i386/types.h @@ -41,6 +41,8 @@ typedef unsigned long long u64; #define BITS_PER_LONG 32 +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-m68k/page.h b/include/asm-m68k/page.h index 8cc546aac4fe..ef44ce9fca5f 100644 --- a/include/asm-m68k/page.h +++ b/include/asm-m68k/page.h @@ -130,6 +130,19 @@ extern inline void *__va(unsigned long physaddr) } #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* __KERNEL__ */ #endif /* _M68K_PAGE_H */ diff --git a/include/asm-m68k/semaphore.h b/include/asm-m68k/semaphore.h index 787c273a723a..425d3b7f3379 100644 --- a/include/asm-m68k/semaphore.h +++ b/include/asm-m68k/semaphore.h @@ -24,6 +24,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); asmlinkage int __down_failed_trylock(void /* params in registers */); diff --git a/include/asm-m68k/types.h b/include/asm-m68k/types.h index b0ece7bda893..68e71e240c5d 100644 --- a/include/asm-m68k/types.h +++ b/include/asm-m68k/types.h @@ -49,6 +49,8 @@ typedef unsigned long long u64; #define BITS_PER_LONG 32 +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif /* _M68K_TYPES_H */ diff --git a/include/asm-mips/page.h b/include/asm-mips/page.h index aa740dcd03fc..bcc5882ced31 100644 --- a/include/asm-mips/page.h +++ b/include/asm-mips/page.h @@ -25,6 +25,21 @@ extern void (*clear_page)(unsigned long page); extern void (*copy_page)(unsigned long to, unsigned long from); +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + +#endif /* defined (__KERNEL__) */ + #ifdef STRICT_MM_TYPECHECKS /* * These are used to make use of C type-checking.. @@ -79,6 +94,5 @@ typedef unsigned long pgprot_t; #define __va(x) ((void *)((unsigned long) (x) + PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) -#endif /* defined (__KERNEL__) */ #endif /* __ASM_MIPS_PAGE_H */ diff --git a/include/asm-mips/semaphore.h b/include/asm-mips/semaphore.h index dc79272e5ccb..6fbb01d95e3c 100644 --- a/include/asm-mips/semaphore.h +++ b/include/asm-mips/semaphore.h @@ -25,6 +25,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + asmlinkage void __down(struct semaphore * sem); asmlinkage int __down_interruptible(struct semaphore * sem); asmlinkage int __down_trylock(struct semaphore * sem); diff --git a/include/asm-mips/types.h b/include/asm-mips/types.h index 5bbc1a4b873a..bdd171525dea 100644 --- a/include/asm-mips/types.h +++ b/include/asm-mips/types.h @@ -69,6 +69,8 @@ typedef unsigned long u64; #endif #define BITS_PER_LONG _MIPS_SZLONG +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif /* __ASM_MIPS_TYPES_H */ diff --git a/include/asm-ppc/page.h b/include/asm-ppc/page.h index 46ad64784afb..55e9b6e3d01e 100644 --- a/include/asm-ppc/page.h +++ b/include/asm-ppc/page.h @@ -81,6 +81,20 @@ extern void copy_page(unsigned long to, unsigned long from); #define MAP_PAGE_RESERVED (1<<15) extern unsigned long get_zero_page_fast(void); + +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #endif /* __KERNEL__ */ #endif /* __ASSEMBLY__ */ #endif /* _PPC_PAGE_H */ diff --git a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h index ab21c33a6356..86d5616d0a04 100644 --- a/include/asm-ppc/semaphore.h +++ b/include/asm-ppc/semaphore.h @@ -23,6 +23,11 @@ struct semaphore { #define MUTEX_LOCKED ((struct semaphore) \ { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern int __down_trylock(struct semaphore * sem); diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h index 9fb7b8ff8cbb..d641cacffa4e 100644 --- a/include/asm-s390/irq.h +++ b/include/asm-s390/irq.h @@ -799,12 +799,13 @@ static inline void irq_exit(int cpu, unsigned int irq) * x86 profiling function, SMP safe. We might want to do this in * assembly totally? */ -extern char _stext; +extern char _stext[]; + static inline void s390_do_profile (unsigned long addr) { if (prof_buffer && current->pid) { addr &= 0x7fffffff; - addr -= (unsigned long) &_stext; + addr -= (unsigned long)&_stext[0]; addr >>= prof_shift; /* * Don't ignore out-of-bounds EIP values silently, diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index 730a794e67b0..434f5cc1cd57 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -26,6 +26,19 @@ #define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) #define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) +extern __inline__ int get_order(unsigned long size) +{ + int order; + + size = (size-1) >> (PAGE_SHIFT-1); + order = -1; + do { + size >>= 1; + order++; + } while (size); + return order; +} + #ifdef STRICT_MM_TYPECHECKS /* * These are used to make use of C type-checking.. @@ -91,6 +104,7 @@ typedef unsigned long pgprot_t; #define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) #define MAP_NR(addr) (__pa(addr) >> PAGE_SHIFT) + #endif /* __KERNEL__ */ #endif /* _S390_PAGE_H */ diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h index 52b30a829d52..3387203954ca 100644 --- a/include/asm-s390/semaphore.h +++ b/include/asm-s390/semaphore.h @@ -26,6 +26,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), 0, NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), 0, NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + asmlinkage void __down_failed(void /* special register calling convention */); asmlinkage int __down_failed_interruptible(void /* params in registers */); asmlinkage int __down_failed_trylock(void /* params in registers */); diff --git a/include/asm-s390/types.h b/include/asm-s390/types.h index 542fa03ef94a..027311e283dd 100644 --- a/include/asm-s390/types.h +++ b/include/asm-s390/types.h @@ -60,5 +60,7 @@ typedef unsigned long long u64; #define FALSE 0 #endif +typedef u32 dma_addr_t; + #endif /* __KERNEL__ */ #endif diff --git a/include/asm-sparc/semaphore.h b/include/asm-sparc/semaphore.h index 1123c966e837..540f1731d39d 100644 --- a/include/asm-sparc/semaphore.h +++ b/include/asm-sparc/semaphore.h @@ -16,6 +16,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern int __down_trylock(struct semaphore * sem); diff --git a/include/asm-sparc64/semaphore.h b/include/asm-sparc64/semaphore.h index e35a66513153..224818a28296 100644 --- a/include/asm-sparc64/semaphore.h +++ b/include/asm-sparc64/semaphore.h @@ -16,6 +16,11 @@ struct semaphore { #define MUTEX ((struct semaphore) { ATOMIC_INIT(1), ATOMIC_INIT(0), NULL }) #define MUTEX_LOCKED ((struct semaphore) { ATOMIC_INIT(0), ATOMIC_INIT(0), NULL }) +#define init_MUTEX(x) *(x)=MUTEX +#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED +#define DECLARE_MUTEX(name) struct semaphore name=MUTEX +#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED + extern void __down(struct semaphore * sem); extern int __down_interruptible(struct semaphore * sem); extern int __down_trylock(struct semaphore * sem); diff --git a/include/linux/compatmac.h b/include/linux/compatmac.h index 07d8356d075f..5f9175d2c836 100644 --- a/include/linux/compatmac.h +++ b/include/linux/compatmac.h @@ -149,15 +149,4 @@ static inline void *ioremap(unsigned long base, long length) #endif -#ifndef TWO_THREE -/* These are new in 2.3. The source now uses 2.3 syntax, and here is - the compatibility define... */ -#define wait_queue_head_t struct wait_queue * -#define DECLARE_MUTEX(name) struct semaphore name = MUTEX -#define DECLARE_WAITQUEUE(wait, current) \ - struct wait_queue wait = { current, NULL } - -#endif - - #endif diff --git a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h index b14727d080fb..bfca2619a006 100644 --- a/include/linux/devfs_fs_kernel.h +++ b/include/linux/devfs_fs_kernel.h @@ -5,3 +5,5 @@ typedef int* devfs_handle_t; #define devfs_mk_dir(a,b,c,d) NULL #define devfs_register_chrdev(a,b,c) register_chrdev(a,b,c) #define devfs_unregister_chrdev(a,b) unregister_chrdev(a,b) +#define tty_register_devfs(driver,flags,minor) +#define tty_unregister_devfs(driver,minor) diff --git a/include/linux/fs.h b/include/linux/fs.h index c64f5f4db987..b2d0ebe50d9c 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -658,6 +658,13 @@ struct file_system_type { struct file_system_type * next; }; +#define DECLARE_FSTYPE(var,type,read,flags) \ +struct file_system_type var = { \ + name: type, \ + read_super: read, \ + fs_flags: flags, \ +} + extern int register_filesystem(struct file_system_type *); extern int unregister_filesystem(struct file_system_type *); diff --git a/include/linux/i2o.h b/include/linux/i2o.h index 57306246e2f9..0bc39c91a58a 100644 --- a/include/linux/i2o.h +++ b/include/linux/i2o.h @@ -638,12 +638,6 @@ extern const char *i2o_get_class_name(int); #define I2O_POST_WAIT_OK 0 #define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT -#define DECLARE_MUTEX(name) struct semaphore name=MUTEX - -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAIT_QUEUE_HEAD(wait)\ - wait_queue_head_t wait - #endif /* __KERNEL__ */ #endif /* _I2O_H */ diff --git a/include/linux/joystick.h b/include/linux/joystick.h index 6dbb24eb2372..746f018ee411 100644 --- a/include/linux/joystick.h +++ b/include/linux/joystick.h @@ -134,9 +134,9 @@ struct JS_DATA_SAVE_TYPE { #error "You need to use at least v2.2 Linux kernel." #endif +#include + #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#include -typedef struct wait_queue *wait_queue_head_t; #define __exit #ifdef MODULE #define module_init(x) int init_module(void) { return x(); } @@ -147,13 +147,9 @@ typedef struct wait_queue *wait_queue_head_t; #endif #define __setup(a,b) #define BASE_ADDRESS(x,i) ((x)->base_address[i]) -#define DECLARE_WAITQUEUE(x,y) struct wait_queue x = { y, NULL } -#define init_waitqueue_head(x) do { *(x) = NULL; } while (0) -#define __set_current_state(x) current->state = x #define SETUP_PARAM char *str, int *ints #define SETUP_PARSE(x) do {} while (0) #else -#include #define BASE_ADDRESS(x,i) ((x)->resource[i].start) #define SETUP_PARAM char *str #define SETUP_PARSE(x) int ints[x]; get_options(str, x, ints) diff --git a/include/linux/kcomp.h b/include/linux/kcomp.h index 98b1ca61921d..4b0290e48406 100644 --- a/include/linux/kcomp.h +++ b/include/linux/kcomp.h @@ -7,31 +7,6 @@ #include #include -#define LIST_HEAD_INIT(name) { &(name), &(name) } -static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -typedef struct wait_queue wait_queue_t; -typedef struct wait_queue *wait_queue_head_t; -#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } -#define DECLARE_WAIT_QUEUE_HEAD(wait) wait_queue_head_t wait -#define init_waitqueue_head(x) *(x)=NULL -#define init_waitqueue_entry(q,p) ((q)->task)=(p) - -#define init_MUTEX(x) *(x)=MUTEX -#define init_MUTEX_LOCKED(x) *(x)=MUTEX_LOCKED -#define DECLARE_MUTEX(name) struct semaphore name=MUTEX -#define DECLARE_MUTEX_LOCKED(name) struct semaphore name=MUTEX_LOCKED - -#define __set_current_state(state_value) do { current->state = state_value; } while (0) -#ifdef __SMP__ -#define set_current_state(state_value) do { mb(); __set_current_state(state_value); } while (0) -#else -#define set_current_state(state_value) __set_current_state(state_value) -#endif - #define __exit #ifdef __alpha @@ -43,13 +18,9 @@ static inline long kernel_thread (int (*fn) (void *), void *arg, unsigned long f #undef CONFIG_APM #endif -#define proc_mkdir(buf, usbdir) create_proc_entry(buf, S_IFDIR, usbdir) #define pci_enable_device(x) 0 -#define VID_HARDWARE_CPIA 24 -#define VID_HARDWARE_OV511 27 - #define page_address(x) (x | PAGE_OFFSET) #ifdef MODULE @@ -78,19 +49,7 @@ static inline long kernel_thread (int (*fn) (void *), void *arg, unsigned long f #define NET_XMIT_DROP 1 #define NET_XMIT_CN 2 -#define tty_register_devfs(driver,flags,minor) -#define tty_unregister_devfs(driver,minor) - -#define DECLARE_FSTYPE(var,type,read,flags) \ -struct file_system_type var = { \ - name: type, \ - read_super: read, \ - fs_flags: flags, \ -} - #define IORESOURCE_IO 1 #define pci_resource_start(dev, i) (dev->base_address[i] & ~IORESOURCE_IO) -#define pci_resource_len(dev, i) 0x100 /* FIXME */ #define pci_resource_flags(dev, i) (dev->base_address[i] & IORESOURCE_IO) -#define vmalloc_32 vmalloc diff --git a/include/linux/list.h b/include/linux/list.h index e77559a68fda..27a6ff42163b 100644 --- a/include/linux/list.h +++ b/include/linux/list.h @@ -17,6 +17,8 @@ struct list_head { struct list_head *next, *prev; }; +#define LIST_HEAD_INIT(name) { &(name), &(name) } + #define LIST_HEAD(name) \ struct list_head name = { &name, &name } @@ -48,6 +50,14 @@ static __inline__ void list_add(struct list_head *new, struct list_head *head) __list_add(new, head, head->next); } +/* + * Insert a new entry at the tail + */ +static __inline__ void list_add_tail(struct list_head *new, struct list_head *head) +{ + __list_add(new, head->prev, head); +} + /* * Delete a list entry by making the prev/next entries * point to each other. @@ -94,6 +104,9 @@ static __inline__ void list_splice(struct list_head *list, struct list_head *hea #define list_entry(ptr, type, member) \ ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) +#define list_for_each(pos, head) \ + for (pos = (head)->next; pos != (head); pos = pos->next) + #endif /* __KERNEL__ */ #endif diff --git a/include/linux/pci.h b/include/linux/pci.h index b87a9b6f8c77..7c6757440ad5 100644 --- a/include/linux/pci.h +++ b/include/linux/pci.h @@ -1056,11 +1056,16 @@ #define PCI_DEVICE_ID_LAVA_PARALLEL 0x8000 #define PCI_DEVICE_ID_LAVA_DUAL_PAR_A 0x8002 /* The Lava Dual Parallel is */ #define PCI_DEVICE_ID_LAVA_DUAL_PAR_B 0x8003 /* two PCI devices on a card */ +#define PCI_DEVICE_ID_LAVA_BOCA_IOPPAR 0x8800 #define PCI_VENDOR_ID_TIMEDIA 0x1409 #define PCI_DEVICE_ID_TIMEDIA_1889 0x7168 #define PCI_DEVICE_ID_TIMEDIA_4008A 0x7268 +#define PCI_VENDOR_ID_OXSEMI 0x1415 +#define PCI_DEVICE_ID_OXSEMI_12PCI840 0x8403 +#define PCI_DEVICE_ID_OXSEMI_16PCI954PP 0x9513 + #define PCI_VENDOR_ID_AFAVLAB 0x14db #define PCI_DEVICE_ID_AFAVLAB_TK9902 0x2120 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 205aa387a793..0c4a9c82204e 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -436,6 +436,12 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent); void remove_proc_entry(const char *name, struct proc_dir_entry *parent); +#define create_proc_info_entry(n, m, b, g) \ + { \ + struct proc_dir_entry *r = create_proc_entry(n, m, b); \ + if (r) r->get_info = g; \ + } + /* * proc_tty.c */ @@ -463,6 +469,13 @@ extern inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t return NULL; } +#define create_proc_info_entry(n, m, b, g) \ + { \ + struct proc_dir_entry *r = create_proc_entry(n, m, b); \ + if (r) r->get_info = g; \ + } + + extern inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {}; extern inline void proc_tty_register_driver(struct tty_driver *driver) {}; @@ -471,4 +484,7 @@ extern inline void proc_tty_unregister_driver(struct tty_driver *driver) {}; extern struct proc_dir_entry proc_root; #endif /* CONFIG_PROC_FS */ + +#define proc_mkdir(buf, usbdir) create_proc_entry(buf, S_IFDIR, usbdir) + #endif /* _LINUX_PROC_FS_H */ diff --git a/include/linux/sched.h b/include/linux/sched.h index 52bf90605167..3fd1d14d4ca9 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -497,6 +497,13 @@ extern void FASTCALL(wake_up_process(struct task_struct * tsk)); #define wake_up(x) __wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE) #define wake_up_interruptible(x) __wake_up((x),TASK_INTERRUPTIBLE) +#define __set_current_state(state_value) do { current->state = state_value; } while (0) +#ifdef __SMP__ +#define set_current_state(state_value) do { mb(); __set_current_state(state_value); } while (0) +#else +#define set_current_state(state_value) __set_current_state(state_value) +#endif + extern int in_group_p(gid_t grp); extern int in_egroup_p(gid_t grp); diff --git a/include/linux/smb.h b/include/linux/smb.h index 852d5b0dd89c..1e4caaae9aa9 100644 --- a/include/linux/smb.h +++ b/include/linux/smb.h @@ -62,6 +62,12 @@ struct smb_conn_opt { #ifdef __KERNEL__ +#define SMB_NLS_MAXNAMELEN 20 +struct smb_nls_codepage { + char local_name[SMB_NLS_MAXNAMELEN]; + char remote_name[SMB_NLS_MAXNAMELEN]; +}; + #define SMB_MAXNAMELEN 255 #define SMB_MAXPATHLEN 1024 diff --git a/include/linux/smb_fs.h b/include/linux/smb_fs.h index 424f699165f8..53ffc44e3a5a 100644 --- a/include/linux/smb_fs.h +++ b/include/linux/smb_fs.h @@ -70,14 +70,6 @@ smb_vfree(void *obj) #define SMB_F_CACHEVALID 0x01 /* directory cache valid */ #define SMB_F_LOCALWRITE 0x02 /* file modified locally */ -/* - * Bug fix flags - */ -#define SMB_FIX_WIN95 0x0001 /* Win 95 server */ -#define SMB_FIX_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ -#define SMB_FIX_DIRATTR 0x0004 /* Use find_first for getattr */ - - /* NT1 protocol capability bits */ #define SMB_CAP_RAW_MODE 0x0001 #define SMB_CAP_MPX_MODE 0x0002 @@ -117,6 +109,7 @@ struct inode *smb_iget(struct super_block *, struct smb_fattr *); extern int init_smb_fs(void); /* linux/fs/smbfs/proc.c */ +int smb_setcodepage(struct smb_sb_info *server, struct smb_nls_codepage *cp); __u32 smb_len(unsigned char *); __u8 *smb_encode_smb_length(__u8 *, __u32); __u8 *smb_setup_header(struct smb_sb_info *, __u8, __u16, __u16); diff --git a/include/linux/smb_fs_sb.h b/include/linux/smb_fs_sb.h index cedbb5ab8409..188ec72eb23e 100644 --- a/include/linux/smb_fs_sb.h +++ b/include/linux/smb_fs_sb.h @@ -23,7 +23,7 @@ struct smb_sb_info { enum smb_conn_state state; struct file * sock_file; - struct smb_mount_data *mnt; + struct smb_mount_data_kernel *mnt; unsigned char *temp_buf; /* Connections are counted. Each time a new socket arrives, @@ -41,8 +41,20 @@ struct smb_sb_info { unsigned short rcls; /* The error codes we received */ unsigned short err; - /* We use our on data_ready callback, but need the original one */ + /* We use our own data_ready callback, but need the original one */ void *data_ready; + + /* nls pointers for codepage conversions */ + struct nls_table *remote_nls; + struct nls_table *local_nls; + + /* utf8 can make strings longer so we can't do in-place conversion. + This is a buffer for temporary stuff. We only need one so no need + to put it on the stack. This points to temp_buf space. */ + char *name_buf; + + int (*convert)(char *, int, const char *, int, + struct nls_table *, struct nls_table *); }; #endif /* __KERNEL__ */ diff --git a/include/linux/smb_mount.h b/include/linux/smb_mount.h index 886d945d5fe0..25bdb3937d01 100644 --- a/include/linux/smb_mount.h +++ b/include/linux/smb_mount.h @@ -11,7 +11,7 @@ #include -#define SMB_MOUNT_VERSION 6 +#define SMB_MOUNT_VERSION 6 struct smb_mount_data { int version; @@ -22,4 +22,28 @@ struct smb_mount_data { __kernel_mode_t dir_mode; }; + +#ifdef __KERNEL__ + +/* flags */ +#define SMB_MOUNT_WIN95 0x0001 /* Win 95 server */ +#define SMB_MOUNT_OLDATTR 0x0002 /* Use core getattr (Win 95 speedup) */ +#define SMB_MOUNT_DIRATTR 0x0004 /* Use find_first for getattr */ +#define SMB_MOUNT_CASE 0x0008 /* Be case sensitive */ + +struct smb_mount_data_kernel { + int _version; + __kernel_uid_t mounted_uid; /* Who may umount() this filesystem? */ + __kernel_uid_t uid; + __kernel_gid_t gid; + __kernel_mode_t file_mode; + __kernel_mode_t dir_mode; + + u32 flags; + + struct smb_nls_codepage codepage; +}; + +#endif + #endif diff --git a/include/linux/videodev.h b/include/linux/videodev.h index f42ad08396ab..cfcc6ddcf06f 100644 --- a/include/linux/videodev.h +++ b/include/linux/videodev.h @@ -279,6 +279,8 @@ struct video_unit #define VID_HARDWARE_VINO 20 /* Reserved for SGI Indy Vino */ #define VID_HARDWARE_CADET 21 /* Cadet radio */ #define VID_HARDWARE_TRUST 22 /* Trust FM Radio */ +#define VID_HARDWARE_CPIA 24 +#define VID_HARDWARE_OV511 27 /* * Initialiser list diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h index 340544fd6e55..40895b853bcf 100644 --- a/include/linux/vmalloc.h +++ b/include/linux/vmalloc.h @@ -19,6 +19,9 @@ void * vmalloc(unsigned long size); long vread(char *buf, char *addr, unsigned long count); void vmfree_area_pages(unsigned long address, unsigned long size); int vmalloc_area_pages(unsigned long address, unsigned long size); - +extern inline void * vmalloc_32(unsigned long size) +{ + return vmalloc(size); +} #endif diff --git a/include/linux/wait.h b/include/linux/wait.h index 6514693c26e5..995f28111043 100644 --- a/include/linux/wait.h +++ b/include/linux/wait.h @@ -15,7 +15,14 @@ struct wait_queue { struct wait_queue * next; }; +typedef struct wait_queue wait_queue_t; +typedef struct wait_queue *wait_queue_head_t; + #define WAIT_QUEUE_HEAD(x) ((struct wait_queue *)((x)-1)) +#define DECLARE_WAITQUEUE(wait, current) struct wait_queue wait = { current, NULL } +#define DECLARE_WAIT_QUEUE_HEAD(wait) wait_queue_head_t wait +#define init_waitqueue_head(x) *(x)=NULL +#define init_waitqueue_entry(q,p) ((q)->task)=(p) static inline void init_waitqueue(struct wait_queue **q) { diff --git a/mm/slab.c b/mm/slab.c index b67614e2803e..010e4d71f15a 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -1047,7 +1047,7 @@ found: int kmem_cache_shrink(kmem_cache_t *cachep) { - __kmem_cache_shrink(cachep,0); + return __kmem_cache_shrink(cachep,0); } /* diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index e14b5461ff26..94aa9bd85c08 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -15,7 +15,7 @@ if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then bool 'IP: fast network address translation' CONFIG_IP_ROUTE_NAT fi fi -bool 'IP: kernel level autoconfiguration' CONFIG_IP_PNP +bool 'IP: kernel-level configuration support' CONFIG_IP_PNP if [ "$CONFIG_IP_PNP" = "y" ]; then bool ' DHCP support' CONFIG_IP_PNP_DHCP bool ' BOOTP support' CONFIG_IP_PNP_BOOTP diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 2dcfc00fb60d..f5c806c79485 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -74,8 +74,9 @@ #define CONF_POST_OPEN (1*HZ) /* After opening: 1 second */ /* Define the timeout for waiting for a DHCP/BOOTP/RARP reply */ -#define CONF_OPEN_RETRIES 3 /* (Re)open devices three times */ -#define CONF_SEND_RETRIES 3 /* Send requests three times */ +#define CONF_OPEN_RETRIES 2 /* (Re)open devices twice */ +#define CONF_SEND_RETRIES 6 /* Send six requests per open */ +#define CONF_INTER_TIMEOUT (HZ/2) /* Inter-device timeout: 1/2 second */ #define CONF_BASE_TIMEOUT (HZ*2) /* Initial timeout: 2 seconds */ #define CONF_TIMEOUT_RANDOM (HZ) /* Maximum amount of randomization */ #define CONF_TIMEOUT_MULT *7/4 /* Rate of timeout growth */ @@ -86,7 +87,7 @@ * Public IP configuration */ -int ic_enable __initdata = 1; /* Automatic IP cfg enabled? */ +int ic_enable __initdata = 0; /* IP config enabled? */ /* Protocol choice */ static int ic_proto_enabled __initdata = 0 @@ -129,10 +130,11 @@ static char user_dev_name[IFNAMSIZ] __initdata = { 0, }; static int ic_proto_have_if __initdata = 0; #ifdef IPCONFIG_DYNAMIC -static volatile int ic_got_reply = 0; /* Protocol(s) we got reply from */ +static spinlock_t ic_recv_lock = SPIN_LOCK_UNLOCKED; +static volatile int ic_got_reply __initdata = 0; /* Proto(s) that replied */ #endif #ifdef IPCONFIG_DHCP -static int ic_dhcp_msgtype __initdata = 0; /* Last incoming msg type */ +static int ic_dhcp_msgtype __initdata = 0; /* DHCP msg type received */ #endif @@ -144,11 +146,12 @@ struct ic_device { struct ic_device *next; struct device *dev; unsigned short flags; - int able; + short able; + u32 xid; }; -static struct ic_device *ic_first_dev __initdata = NULL;/* List of open device */ -static struct device *ic_dev __initdata = NULL; /* Selected device */ +static struct ic_device *ic_first_dev __initdata = NULL; /* Open devices */ +static struct device *ic_dev __initdata = NULL; /* Selected device */ static int __init ic_open_devs(void) { @@ -185,8 +188,13 @@ static int __init ic_open_devs(void) last = &d->next; d->flags = oflags; d->able = able; + if (able & IC_BOOTP) + get_random_bytes(&d->xid, sizeof(u32)); + else + d->xid = 0; ic_proto_have_if |= able; - DBG((SELF "%s UP (able=%d)\n", dev->name, able)); + DBG((SELF "%s UP (able=%d, xid=%08x)\n", + dev->name, able, d->xid)); } *last = NULL; @@ -386,11 +394,22 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) unsigned char *rarp_ptr = (unsigned char *) (rarp + 1); unsigned long sip, tip; unsigned char *sha, *tha; /* s for "source", t for "target" */ + struct ic_device *d; + + /* One reply at a time, please. */ + spin_lock(&ic_recv_lock); /* If we already have a reply, just drop the packet */ if (ic_got_reply) goto drop; + /* Find the ic_device that the packet arrived on */ + d = ic_first_dev; + while (d && d->dev != dev) + d = d->next; + if (!d) + goto drop; /* should never happen */ + /* If this test doesn't pass, it's not IP, or we should ignore it anyway */ if (rarp->ar_hln != dev->addr_len || dev->type != ntohs(rarp->ar_hrd)) goto drop; @@ -420,7 +439,7 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) if (ic_servaddr != INADDR_NONE && ic_servaddr != sip) goto drop; - /* Victory! The packet is what we were looking for! */ + /* We have a winner! */ ic_dev = dev; if (ic_myaddr == INADDR_NONE) ic_myaddr = tip; @@ -428,8 +447,12 @@ ic_rarp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) ic_got_reply = IC_RARP; drop: - /* and throw the packet out */ + /* Show's over. Nothing to see here. */ + spin_unlock(&ic_recv_lock); + + /* Throw the packet out. */ kfree_skb(skb); + return 0; } @@ -437,16 +460,23 @@ drop: /* * Send RARP request packet over all devices which allow RARP. */ +static void __init ic_rarp_send_if(struct ic_device *d) +{ + struct device *dev = d->dev; + arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, + dev->dev_addr, dev->dev_addr); +} + +/* + * Send RARP request package over a single interface. + */ static void __init ic_rarp_send(void) { struct ic_device *d; for (d=ic_first_dev; d; d=d->next) - if (d->able & IC_RARP) { - struct device *dev = d->dev; - arp_send(ARPOP_RREQUEST, ETH_P_RARP, 0, dev, 0, NULL, - dev->dev_addr, dev->dev_addr); - } + if (d->able & IC_RARP) + ic_rarp_send_if(d); } #endif @@ -491,8 +521,6 @@ struct bootp_pkt { /* BOOTP packet format */ #define DHCPRELEASE 7 #define DHCPINFORM 8 -static u32 ic_bootp_xid; - static int ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct packet_type *pt); @@ -516,12 +544,12 @@ static const u8 ic_bootp_cookie[4] = { 99, 130, 83, 99 }; static void __init ic_dhcp_init_options(u8 *options) { - u8 msgtype = ((ic_dhcp_msgtype == DHCPOFFER) - ? DHCPREQUEST : DHCPDISCOVER); + u8 mt = ((ic_servaddr == INADDR_NONE) + ? DHCPDISCOVER : DHCPREQUEST); u8 *e = options; #ifdef IPCONFIG_DEBUG - printk("DHCP: Sending message type %d\n", msgtype); + printk("DHCP: Sending message type %d\n", mt); #endif memcpy(e, ic_bootp_cookie, 4); /* RFC1048 Magic Cookie */ @@ -529,9 +557,14 @@ ic_dhcp_init_options(u8 *options) *e++ = 53; /* DHCP message type */ *e++ = 1; - *e++ = msgtype; + *e++ = mt; + + if (mt == DHCPREQUEST) { + *e++ = 54; /* Server ID (IP address) */ + *e++ = 4; + memcpy(e, &ic_servaddr, 4); + e += 4; - if (msgtype == DHCPREQUEST) { *e++ = 50; /* Requested IP address */ *e++ = 4; memcpy(e, &ic_myaddr, 4); @@ -595,8 +628,6 @@ ic_bootp_init_ext(u8 *ext) static inline void ic_bootp_init(void) { - get_random_bytes(&ic_bootp_xid, sizeof(u32)); - DBG(("DHCP/BOOTP: XID=%08x\n", ic_bootp_xid)); dev_add_pack(&bootp_packet_type); } @@ -656,7 +687,7 @@ ic_bootp_send_if(struct ic_device *d, u32 jiffies) b->server_ip = INADDR_NONE; memcpy(b->hw_addr, dev->dev_addr, dev->addr_len); b->secs = htons(jiffies / HZ); - b->xid = ic_bootp_xid; + b->xid = d->xid; /* add DHCP options or BOOTP extensions */ #ifdef IPCONFIG_DHCP @@ -756,12 +787,23 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct { struct bootp_pkt *b = (struct bootp_pkt *) skb->nh.iph; struct iphdr *h = &b->iph; + struct ic_device *d; int len; + /* One reply at a time, please. */ + spin_lock(&ic_recv_lock); + /* If we already have a reply, just drop the packet */ if (ic_got_reply) goto drop; + /* Find the ic_device that the packet arrived on */ + d = ic_first_dev; + while (d && d->dev != dev) + d = d->next; + if (!d) + goto drop; /* should never happen */ + /* Check whether it's a BOOTP packet */ if (skb->pkt_type == PACKET_OTHERHOST || skb->len < sizeof(struct udphdr) + sizeof(struct iphdr) || @@ -783,9 +825,9 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct /* Is it a reply to our BOOTP request? */ len = ntohs(b->udph.len) - sizeof(struct udphdr); - if (len < 300 || /* See RFC 951:2.1 */ + if (len < 300 || /* See RFC 951:2.1 */ b->op != BOOTP_REPLY || - b->xid != ic_bootp_xid) { + b->xid != d->xid) { printk("?"); goto drop; } @@ -798,7 +840,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct #ifdef IPCONFIG_DHCP u32 server_id = INADDR_NONE; - ic_dhcp_msgtype = 0; + int mt = 0; ext = &b->exten[4]; while (ext < end && *ext != 0xff) { @@ -811,7 +853,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct switch (*opt) { case 53: /* Message type */ if (opt[1]) - ic_dhcp_msgtype = opt[2]; + mt = opt[2]; break; case 54: /* Server ID (IP address) */ if (opt[1] >= 4) @@ -821,11 +863,15 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct } #ifdef IPCONFIG_DEBUG - printk("DHCP: Got message type %d\n", ic_dhcp_msgtype); + printk("DHCP: Got message type %d\n", mt); #endif - switch (ic_dhcp_msgtype) { + switch (mt) { case DHCPOFFER: + /* While in the process of accepting one offer, + ignore all others. */ + if (ic_myaddr != INADDR_NONE) + goto drop; /* Let's accept that offer. */ ic_myaddr = b->your_ip; ic_servaddr = server_id; @@ -833,7 +879,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct printk("DHCP: Offered address %s", in_ntoa(ic_myaddr)); printk(" by server %s\n", in_ntoa(ic_servaddr)); #endif - goto drop; + break; case DHCPACK: /* Yeah! */ @@ -846,6 +892,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct goto drop; } + ic_dhcp_msgtype = mt; + #endif /* IPCONFIG_DHCP */ ext = &b->exten[4]; @@ -859,6 +907,7 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct } } + /* We have a winner! */ ic_dev = dev; ic_myaddr = b->your_ip; ic_servaddr = b->server_ip; @@ -869,8 +918,12 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct device *dev, struct ic_got_reply = IC_BOOTP; drop: - /* and throw the packet out */ + /* Show's over. Nothing to see here. */ + spin_unlock(&ic_recv_lock); + + /* Throw the packet out. */ kfree_skb(skb); + return 0; } @@ -887,8 +940,8 @@ drop: static int __init ic_dynamic(void) { int retries; - unsigned long timeout, jiff; - unsigned long start_jiffies; + struct ic_device *d; + unsigned long start_jiffies, timeout, jiff; int do_bootp = ic_proto_have_if & IC_BOOTP; int do_rarp = ic_proto_have_if & IC_RARP; @@ -936,36 +989,39 @@ static int __init ic_dynamic(void) * [Actually we could now, but the nothing else running note still * applies.. - AC] */ - printk(KERN_NOTICE "Sending %s%s%s requests ", + printk(KERN_NOTICE "Sending %s%s%s requests .", do_bootp ? ((ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP") : "", (do_bootp && do_rarp) ? " and " : "", do_rarp ? "RARP" : ""); + start_jiffies = jiffies; + d = ic_first_dev; retries = CONF_SEND_RETRIES; get_random_bytes(&timeout, sizeof(timeout)); timeout = CONF_BASE_TIMEOUT + (timeout % (unsigned) CONF_TIMEOUT_RANDOM); for(;;) { #ifdef IPCONFIG_BOOTP - if (do_bootp) - ic_bootp_send(jiffies - start_jiffies); + if (do_bootp && (d->able & IC_BOOTP)) + ic_bootp_send_if(d, jiffies - start_jiffies); #endif #ifdef IPCONFIG_RARP - if (do_rarp) - ic_rarp_send(); + if (do_rarp && (d->able & IC_RARP)) + ic_rarp_send_if(d); #endif - printk("."); - jiff = jiffies + timeout; + jiff = jiffies + (d->next ? CONF_INTER_TIMEOUT : timeout); while (jiffies < jiff && !ic_got_reply) ; + #ifdef IPCONFIG_DHCP + /* DHCP isn't done until we get a DHCPACK. */ if ((ic_got_reply & IC_BOOTP) && (ic_proto_enabled & IC_USE_DHCP) && ic_dhcp_msgtype != DHCPACK) { - printk(","); ic_got_reply = 0; + printk(","); continue; } #endif /* IPCONFIG_DHCP */ @@ -975,14 +1031,21 @@ static int __init ic_dynamic(void) break; } + if ((d = d->next)) + continue; + if (! --retries) { printk(" timed out!\n"); break; } + d = ic_first_dev; + timeout = timeout CONF_TIMEOUT_MULT; if (timeout > CONF_TIMEOUT_MAX) timeout = CONF_TIMEOUT_MAX; + + printk("."); } #ifdef IPCONFIG_BOOTP @@ -997,7 +1060,8 @@ static int __init ic_dynamic(void) if (!ic_got_reply) return -1; - printk(SELF "Got %s answer from %s\n", + printk(SELF "%s: Got %s answer from %s\n", + ic_dev->name, ((ic_got_reply & IC_RARP) ? "RARP" : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), in_ntoa(ic_servaddr)); @@ -1167,7 +1231,7 @@ int __init ip_auto_config(void) * Clue in the operator. */ printk(SELF "Complete:"); - printk("\n device=%s", ic_dev->name); + printk( "\n if=%s", ic_dev->name); printk(", addr=%s", in_ntoa(ic_myaddr)); printk(", mask=%s", in_ntoa(ic_netmask)); printk(", gw=%s", in_ntoa(ic_gateway)); @@ -1199,14 +1263,14 @@ int __init ip_auto_config(void) * by BOOTP * - use all available devices * : - * dhcp|bootp|rarp - use given protocol - * both or empty - use both BOOTP and RARP (not DHCP) - * off or none - don't do autoconfig at all + * off|none - don't do autoconfig at all (DEFAULT) + * on|any - use any configured protocol + * dhcp|bootp|rarp - use only the specified protocol + * both - use both BOOTP and RARP (not DHCP) */ static int __init ic_proto_name(char *name) { - if (!strcmp(name, "off") || !strcmp(name, "none")) { - ic_proto_enabled = 0; + if (!strcmp(name, "on") || !strcmp(name, "any")) { return 1; } #ifdef CONFIG_IP_PNP_DHCP @@ -1241,10 +1305,10 @@ void __init ip_auto_config_setup(char *addrs, int *ints) char *cp, *ip, *dp; int num = 0; - if (!strcmp(addrs, "off") || !strcmp(addrs, "none")) { - ic_enable = 0; + ic_enable = (*addrs && strcmp(addrs, "off") && strcmp(addrs, "none")); + if (!ic_enable) return; - } + if (ic_proto_name(addrs)) return; -- 2.39.5