mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
bitkeeper revision 1.154.1.1 (3e7f35e65e93xTR77zgPWlou5QJAgw)
Added aic7xxx support
Included linux string library in place of cut down lib.{c,h} versions
Added missing strtoul prototype in lib.h
This commit is contained in:
1 parent
90a2fdc8c6
commit
4e089db0cd
53 files changed
+54010
-2
No files matched your search
@@ -246,6 +246,7 @@
|
||||
3e397e6619PgAfBbw2XFbXkewvUWgw xen/common/schedule.c
|
||||
3ddb79bdB9RNMnkQnUyZ5C9hhMSQQw xen/common/slab.c
|
||||
3ddb79bd0gVQYmL2zvuJnldvD0AGxQ xen/common/softirq.c
|
||||
3e7f358awXBC3Vw-wFRwPw18qL1khg xen/common/string.c
|
||||
3ddb79bdQqFHtHRGEO2dsxGgo6eAhw xen/common/timer.c
|
||||
3ddb79bd3zgV33PHdt-cgh3sxcb1hw xen/common/vsprintf.c
|
||||
3ddb79c0ppNeJtjC4va8j41ADCnchA xen/drivers/Makefile
|
||||
@@ -316,6 +317,51 @@
|
||||
3e564137taxQbEVa39h3mEVLFxRydQ xen/drivers/scsi/aacraid/linit.c
|
||||
3e564137vmALxpfK7vNINqEklSmQ1A xen/drivers/scsi/aacraid/rx.c
|
||||
3e564137EuYUJgvqnOunPERWxnp_mw xen/drivers/scsi/aacraid/sa.c
|
||||
3e7f358amV8HBe1Cyges2wsBHfh-cw xen/drivers/scsi/aic7xxx/Makefile
|
||||
3e7f358al_wJbBvERr7NzW5mLuTRpQ xen/drivers/scsi/aic7xxx/aic7770.c
|
||||
3e7f358aCCSVBMcmsh64S7CCVIgVQg xen/drivers/scsi/aic7xxx/aic7770_osm.c
|
||||
3e7f358aLNpSseMxk_DY6a-Ln9OyGg xen/drivers/scsi/aic7xxx/aic79xx.h
|
||||
3e7f358ad7OR21rmyDNJfKyE1X1sxg xen/drivers/scsi/aic7xxx/aic79xx.reg
|
||||
3e7f358a9Z39hG2enFVrNWjizvwthg xen/drivers/scsi/aic7xxx/aic79xx.seq
|
||||
3e7f358aKzcs8L8XYcLD0bF8FrmtVg xen/drivers/scsi/aic7xxx/aic79xx_core.c
|
||||
3e7f358ayrUAqJ9b8GxdRJQr5Po1zg xen/drivers/scsi/aic7xxx/aic79xx_host.h
|
||||
3e7f358aVDB0b6qAf__XSDPubVM1RA xen/drivers/scsi/aic7xxx/aic79xx_inline.h
|
||||
3e7f358aQFjWLEqUzd98Gy8z86vk2g xen/drivers/scsi/aic7xxx/aic79xx_osm.c
|
||||
3e7f358adsO2cSMKATR_r9hPZ9KCUg xen/drivers/scsi/aic7xxx/aic79xx_osm.h
|
||||
3e7f358avC9liKFAUFFRyWlVIIGZ2g xen/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
|
||||
3e7f358aQ0ZpnmwtiT16raQb1QSGKQ xen/drivers/scsi/aic7xxx/aic79xx_pci.c
|
||||
3e7f358af6BTct89-TCB31Rtw8NzQg xen/drivers/scsi/aic7xxx/aic79xx_proc.c
|
||||
3e7f358aK54-KV7Wj014Yf5FnWo2VQ xen/drivers/scsi/aic7xxx/aic79xx_reg.h
|
||||
3e7f358aZiCJAqEBttlmEDCMFcM-aA xen/drivers/scsi/aic7xxx/aic79xx_seq.h
|
||||
3e7f358aPZhHGnMNAM3YCQcBIAnCfw xen/drivers/scsi/aic7xxx/aic7xxx.h
|
||||
3e7f358aZRO8yoMXVLyDUyoFhsFnBw xen/drivers/scsi/aic7xxx/aic7xxx.reg
|
||||
3e7f358aADKO4MLsWISX0-d2hpru0g xen/drivers/scsi/aic7xxx/aic7xxx.seq
|
||||
3e7f358aB5x1ljQE7yWp63nvcfp4Mg xen/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
|
||||
3e7f358aDCmrU2Q35Ay765z7gWTSmQ xen/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
|
||||
3e7f358aXOqteLTeEH8XOlAeLPbXuQ xen/drivers/scsi/aic7xxx/aic7xxx_core.c
|
||||
3e7f358adzSPC6RFtP4NyHB2PoT-Ew xen/drivers/scsi/aic7xxx/aic7xxx_host.h
|
||||
3e7f358asCAiwyDZ1fBaiIxABh30BA xen/drivers/scsi/aic7xxx/aic7xxx_inline.h
|
||||
3e7f358aDwj6BY9tJ4spPuZnQqBiew xen/drivers/scsi/aic7xxx/aic7xxx_osm.c
|
||||
3e7f358anOWiWoFl7baNMWjqsPiYzg xen/drivers/scsi/aic7xxx/aic7xxx_osm.h
|
||||
3e7f358a1sRjg-XkczIXH7dUX8K1ZA xen/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
|
||||
3e7f358aj6uST9miAVmB9WNLqAGkCA xen/drivers/scsi/aic7xxx/aic7xxx_pci.c
|
||||
3e7f358aCwRu3fI3NP7MQsLRpWV73w xen/drivers/scsi/aic7xxx/aic7xxx_proc.c
|
||||
3e7f358aW8xbofV6VW2L8FPphmAXvg xen/drivers/scsi/aic7xxx/aic7xxx_reg.h
|
||||
3e7f358ayQSlIZBIAGWYXBM5dtAFrA xen/drivers/scsi/aic7xxx/aic7xxx_seq.h
|
||||
3e7f358acS9V8TbKLuyxvw-0SlgYmQ xen/drivers/scsi/aic7xxx/aicasm/Makefile
|
||||
3e7f358arkcPw6k1oC2Wrp5TXFbovg xen/drivers/scsi/aic7xxx/aicasm/aicasm.c
|
||||
3e7f358aF_JURnGn6q5V951k1TTnLg xen/drivers/scsi/aic7xxx/aicasm/aicasm.h
|
||||
3e7f358a2aopdml6zsS1HF9oibF5RQ xen/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
|
||||
3e7f358a2JQOz8ASFfi2oV5-k127RA xen/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
|
||||
3e7f358a5kU_nwzMFh0xbG96yLgJKA xen/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
|
||||
3e7f358a4FjmeDBfwgynM1InqFQ2nA xen/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
|
||||
3e7f358aoXDwp6vozr1x2Fwvb7x5BQ xen/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
|
||||
3e7f358aUYJHOx790PiwQiJIlYECbA xen/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
|
||||
3e7f358aPn8RK1slOgqrXC12x0FlgQ xen/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
|
||||
3e7f358a6BujWXsqDmuts6N_A8dGhw xen/drivers/scsi/aic7xxx/cam.h
|
||||
3e7f358anzaPhN49caB9AqMVw0_XKQ xen/drivers/scsi/aic7xxx/queue.h
|
||||
3e7f358a3ggaLCNsnuArANSmNT1t2A xen/drivers/scsi/aic7xxx/scsi_iu.h
|
||||
3e7f358arKN4VFRDcEasaM6Wj_VwTg xen/drivers/scsi/aic7xxx/scsi_message.h
|
||||
3e56411aOLzeD5CRbuXquOrX0lRijw xen/drivers/scsi/constants.c
|
||||
3ddb79beXZxwKh7cGyPfr40bhDyRrA xen/drivers/scsi/constants.h
|
||||
3e564120ZeinH9nf3IVSerB80T7dHg xen/drivers/scsi/hosts.c
|
||||
@@ -375,6 +421,7 @@
|
||||
3ddb79c3jn8ALV_S9W5aeTYUQRKBpg xen/include/asm-i386/smpboot.h
|
||||
3ddb79c3e9DCEoR-WzNxcOQDzLu7BQ xen/include/asm-i386/softirq.h
|
||||
3ddb79c3NiyQE2vQnyGiaBnNjBO1rA xen/include/asm-i386/spinlock.h
|
||||
3e7f358aG11EvMI9VJ4_9hD4LUO7rQ xen/include/asm-i386/string.h
|
||||
3ddb79c3ezddh34MdelJpa5tNR00Dw xen/include/asm-i386/system.h
|
||||
3e397e66xPNc8eaSqC9pPbyAtRGzHA xen/include/asm-i386/time.h
|
||||
3e450943TfE-iovQIY_tMO_VdGsPhA xen/include/asm-i386/timex.h
|
||||
@@ -453,6 +500,7 @@
|
||||
3ddb79c1-yIt89RT02wIPp2xDR8YjQ xen/include/xeno/socket.h
|
||||
3ddb79c2V2P9F2xMCzDJ9vbUofSg_Q xen/include/xeno/sockios.h
|
||||
3ddb79c2iIcESrDAB8samy_yAh6olQ xen/include/xeno/spinlock.h
|
||||
3e7f358aMtFMUVvN_Zjg5qvEJIqEBA xen/include/xeno/string.h
|
||||
3ddb79c0BnA20PbgmuMPSGIBljNRQw xen/include/xeno/time.h
|
||||
3ddb79c2HFkXuRxi1CriJtSFmY6Ybw xen/include/xeno/timer.h
|
||||
3ddb79c2_m8lT9jDKse_tePj7zcnNQ xen/include/xeno/timex.h
|
||||
|
||||
@@ -5,6 +5,7 @@ akw27@plucky.localdomain
|
||||
bd240@boulderdash.cl.cam.ac.uk
|
||||
bd240@labyrinth.cl.cam.ac.uk
|
||||
iap10@labyrinth.cl.cam.ac.uk
|
||||
jws@cairnwell.research
|
||||
kaf24@labyrinth.cl.cam.ac.uk
|
||||
kaf24@plym.cl.cam.ac.uk
|
||||
kaf24@scramble.cl.cam.ac.uk
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@
|
||||
#include <xeno/ctype.h>
|
||||
#include <xeno/lib.h>
|
||||
|
||||
#if 0 // jws - now in string.c, string.h, asm/string.h
|
||||
int memcmp(const void * cs,const void * ct,size_t count)
|
||||
{
|
||||
const unsigned char *su1, *su2;
|
||||
@@ -119,7 +120,7 @@ char * strstr(const char * s1,const char * s2)
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* for inc/ctype.h */
|
||||
unsigned char _ctype[] = {
|
||||
|
||||
@@ -0,0 +1,535 @@
|
||||
/*
|
||||
* linux/lib/string.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
/*
|
||||
* stupid library routines.. The optimized versions should generally be found
|
||||
* as inline code in <asm-xx/string.h>
|
||||
*
|
||||
* These are buggy as well..
|
||||
*
|
||||
* * Fri Jun 25 1999, Ingo Oeser <ioe@informatik.tu-chemnitz.de>
|
||||
* - Added strsep() which will replace strtok() soon (because strsep() is
|
||||
* reentrant and should be faster). Use only strsep() in new code, please.
|
||||
*/
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/ctype.h>
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNICMP
|
||||
/**
|
||||
* strnicmp - Case insensitive, length-limited string comparison
|
||||
* @s1: One string
|
||||
* @s2: The other string
|
||||
* @len: the maximum number of characters to compare
|
||||
*/
|
||||
int strnicmp(const char *s1, const char *s2, size_t len)
|
||||
{
|
||||
/* Yes, Virginia, it had better be unsigned */
|
||||
unsigned char c1, c2;
|
||||
|
||||
c1 = 0; c2 = 0;
|
||||
if (len) {
|
||||
do {
|
||||
c1 = *s1; c2 = *s2;
|
||||
s1++; s2++;
|
||||
if (!c1)
|
||||
break;
|
||||
if (!c2)
|
||||
break;
|
||||
if (c1 == c2)
|
||||
continue;
|
||||
c1 = tolower(c1);
|
||||
c2 = tolower(c2);
|
||||
if (c1 != c2)
|
||||
break;
|
||||
} while (--len);
|
||||
}
|
||||
return (int)c1 - (int)c2;
|
||||
}
|
||||
#endif
|
||||
|
||||
char * ___strtok;
|
||||
|
||||
#ifndef __HAVE_ARCH_STRCPY
|
||||
/**
|
||||
* strcpy - Copy a %NUL terminated string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
*/
|
||||
char * strcpy(char * dest,const char *src)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while ((*dest++ = *src++) != '\0')
|
||||
/* nothing */;
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNCPY
|
||||
/**
|
||||
* strncpy - Copy a length-limited, %NUL-terminated string
|
||||
* @dest: Where to copy the string to
|
||||
* @src: Where to copy the string from
|
||||
* @count: The maximum number of bytes to copy
|
||||
*
|
||||
* Note that unlike userspace strncpy, this does not %NUL-pad the buffer.
|
||||
* However, the result is not %NUL-terminated if the source exceeds
|
||||
* @count bytes.
|
||||
*/
|
||||
char * strncpy(char * dest,const char *src,size_t count)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while (count-- && (*dest++ = *src++) != '\0')
|
||||
/* nothing */;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRCAT
|
||||
/**
|
||||
* strcat - Append one %NUL-terminated string to another
|
||||
* @dest: The string to be appended to
|
||||
* @src: The string to append to it
|
||||
*/
|
||||
char * strcat(char * dest, const char * src)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while (*dest)
|
||||
dest++;
|
||||
while ((*dest++ = *src++) != '\0')
|
||||
;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNCAT
|
||||
/**
|
||||
* strncat - Append a length-limited, %NUL-terminated string to another
|
||||
* @dest: The string to be appended to
|
||||
* @src: The string to append to it
|
||||
* @count: The maximum numbers of bytes to copy
|
||||
*
|
||||
* Note that in contrast to strncpy, strncat ensures the result is
|
||||
* terminated.
|
||||
*/
|
||||
char * strncat(char *dest, const char *src, size_t count)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
if (count) {
|
||||
while (*dest)
|
||||
dest++;
|
||||
while ((*dest++ = *src++)) {
|
||||
if (--count == 0) {
|
||||
*dest = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRCMP
|
||||
/**
|
||||
* strcmp - Compare two strings
|
||||
* @cs: One string
|
||||
* @ct: Another string
|
||||
*/
|
||||
int strcmp(const char * cs,const char * ct)
|
||||
{
|
||||
register signed char __res;
|
||||
|
||||
while (1) {
|
||||
if ((__res = *cs - *ct++) != 0 || !*cs++)
|
||||
break;
|
||||
}
|
||||
|
||||
return __res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNCMP
|
||||
/**
|
||||
* strncmp - Compare two length-limited strings
|
||||
* @cs: One string
|
||||
* @ct: Another string
|
||||
* @count: The maximum number of bytes to compare
|
||||
*/
|
||||
int strncmp(const char * cs,const char * ct,size_t count)
|
||||
{
|
||||
register signed char __res = 0;
|
||||
|
||||
while (count) {
|
||||
if ((__res = *cs - *ct++) != 0 || !*cs++)
|
||||
break;
|
||||
count--;
|
||||
}
|
||||
|
||||
return __res;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRCHR
|
||||
/**
|
||||
* strchr - Find the first occurrence of a character in a string
|
||||
* @s: The string to be searched
|
||||
* @c: The character to search for
|
||||
*/
|
||||
char * strchr(const char * s, int c)
|
||||
{
|
||||
for(; *s != (char) c; ++s)
|
||||
if (*s == '\0')
|
||||
return NULL;
|
||||
return (char *) s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRRCHR
|
||||
/**
|
||||
* strrchr - Find the last occurrence of a character in a string
|
||||
* @s: The string to be searched
|
||||
* @c: The character to search for
|
||||
*/
|
||||
char * strrchr(const char * s, int c)
|
||||
{
|
||||
const char *p = s + strlen(s);
|
||||
do {
|
||||
if (*p == (char)c)
|
||||
return (char *)p;
|
||||
} while (--p >= s);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRLEN
|
||||
/**
|
||||
* strlen - Find the length of a string
|
||||
* @s: The string to be sized
|
||||
*/
|
||||
size_t strlen(const char * s)
|
||||
{
|
||||
const char *sc;
|
||||
|
||||
for (sc = s; *sc != '\0'; ++sc)
|
||||
/* nothing */;
|
||||
return sc - s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRNLEN
|
||||
/**
|
||||
* strnlen - Find the length of a length-limited string
|
||||
* @s: The string to be sized
|
||||
* @count: The maximum number of bytes to search
|
||||
*/
|
||||
size_t strnlen(const char * s, size_t count)
|
||||
{
|
||||
const char *sc;
|
||||
|
||||
for (sc = s; count-- && *sc != '\0'; ++sc)
|
||||
/* nothing */;
|
||||
return sc - s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRSPN
|
||||
/**
|
||||
* strspn - Calculate the length of the initial substring of @s which only
|
||||
* contain letters in @accept
|
||||
* @s: The string to be searched
|
||||
* @accept: The string to search for
|
||||
*/
|
||||
size_t strspn(const char *s, const char *accept)
|
||||
{
|
||||
const char *p;
|
||||
const char *a;
|
||||
size_t count = 0;
|
||||
|
||||
for (p = s; *p != '\0'; ++p) {
|
||||
for (a = accept; *a != '\0'; ++a) {
|
||||
if (*p == *a)
|
||||
break;
|
||||
}
|
||||
if (*a == '\0')
|
||||
return count;
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRPBRK
|
||||
/**
|
||||
* strpbrk - Find the first occurrence of a set of characters
|
||||
* @cs: The string to be searched
|
||||
* @ct: The characters to search for
|
||||
*/
|
||||
char * strpbrk(const char * cs,const char * ct)
|
||||
{
|
||||
const char *sc1,*sc2;
|
||||
|
||||
for( sc1 = cs; *sc1 != '\0'; ++sc1) {
|
||||
for( sc2 = ct; *sc2 != '\0'; ++sc2) {
|
||||
if (*sc1 == *sc2)
|
||||
return (char *) sc1;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRTOK
|
||||
/**
|
||||
* strtok - Split a string into tokens
|
||||
* @s: The string to be searched
|
||||
* @ct: The characters to search for
|
||||
*
|
||||
* WARNING: strtok is deprecated, use strsep instead.
|
||||
*/
|
||||
char * strtok(char * s,const char * ct)
|
||||
{
|
||||
char *sbegin, *send;
|
||||
|
||||
sbegin = s ? s : ___strtok;
|
||||
if (!sbegin) {
|
||||
return NULL;
|
||||
}
|
||||
sbegin += strspn(sbegin,ct);
|
||||
if (*sbegin == '\0') {
|
||||
___strtok = NULL;
|
||||
return( NULL );
|
||||
}
|
||||
send = strpbrk( sbegin, ct);
|
||||
if (send && *send != '\0')
|
||||
*send++ = '\0';
|
||||
___strtok = send;
|
||||
return (sbegin);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRSEP
|
||||
/**
|
||||
* strsep - Split a string into tokens
|
||||
* @s: The string to be searched
|
||||
* @ct: The characters to search for
|
||||
*
|
||||
* strsep() updates @s to point after the token, ready for the next call.
|
||||
*
|
||||
* It returns empty tokens, too, behaving exactly like the libc function
|
||||
* of that name. In fact, it was stolen from glibc2 and de-fancy-fied.
|
||||
* Same semantics, slimmer shape. ;)
|
||||
*/
|
||||
char * strsep(char **s, const char *ct)
|
||||
{
|
||||
char *sbegin = *s, *end;
|
||||
|
||||
if (sbegin == NULL)
|
||||
return NULL;
|
||||
|
||||
end = strpbrk(sbegin, ct);
|
||||
if (end)
|
||||
*end++ = '\0';
|
||||
*s = end;
|
||||
|
||||
return sbegin;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMSET
|
||||
/**
|
||||
* memset - Fill a region of memory with the given value
|
||||
* @s: Pointer to the start of the area.
|
||||
* @c: The byte to fill the area with
|
||||
* @count: The size of the area.
|
||||
*
|
||||
* Do not use memset() to access IO space, use memset_io() instead.
|
||||
*/
|
||||
void * memset(void * s,int c,size_t count)
|
||||
{
|
||||
char *xs = (char *) s;
|
||||
|
||||
while (count--)
|
||||
*xs++ = c;
|
||||
|
||||
return s;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_BCOPY
|
||||
/**
|
||||
* bcopy - Copy one area of memory to another
|
||||
* @src: Where to copy from
|
||||
* @dest: Where to copy to
|
||||
* @count: The size of the area.
|
||||
*
|
||||
* Note that this is the same as memcpy(), with the arguments reversed.
|
||||
* memcpy() is the standard, bcopy() is a legacy BSD function.
|
||||
*
|
||||
* You should not use this function to access IO space, use memcpy_toio()
|
||||
* or memcpy_fromio() instead.
|
||||
*/
|
||||
char * bcopy(const char * src, char * dest, int count)
|
||||
{
|
||||
char *tmp = dest;
|
||||
|
||||
while (count--)
|
||||
*tmp++ = *src++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMCPY
|
||||
/**
|
||||
* memcpy - Copy one area of memory to another
|
||||
* @dest: Where to copy to
|
||||
* @src: Where to copy from
|
||||
* @count: The size of the area.
|
||||
*
|
||||
* You should not use this function to access IO space, use memcpy_toio()
|
||||
* or memcpy_fromio() instead.
|
||||
*/
|
||||
void * memcpy(void * dest,const void *src,size_t count)
|
||||
{
|
||||
char *tmp = (char *) dest, *s = (char *) src;
|
||||
|
||||
while (count--)
|
||||
*tmp++ = *s++;
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMMOVE
|
||||
/**
|
||||
* memmove - Copy one area of memory to another
|
||||
* @dest: Where to copy to
|
||||
* @src: Where to copy from
|
||||
* @count: The size of the area.
|
||||
*
|
||||
* Unlike memcpy(), memmove() copes with overlapping areas.
|
||||
*/
|
||||
void * memmove(void * dest,const void *src,size_t count)
|
||||
{
|
||||
char *tmp, *s;
|
||||
|
||||
if (dest <= src) {
|
||||
tmp = (char *) dest;
|
||||
s = (char *) src;
|
||||
while (count--)
|
||||
*tmp++ = *s++;
|
||||
}
|
||||
else {
|
||||
tmp = (char *) dest + count;
|
||||
s = (char *) src + count;
|
||||
while (count--)
|
||||
*--tmp = *--s;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMCMP
|
||||
/**
|
||||
* memcmp - Compare two areas of memory
|
||||
* @cs: One area of memory
|
||||
* @ct: Another area of memory
|
||||
* @count: The size of the area.
|
||||
*/
|
||||
/*
|
||||
int memcmp(const void * cs,const void * ct,size_t count)
|
||||
{
|
||||
const unsigned char *su1, *su2;
|
||||
int res = 0;
|
||||
|
||||
for( su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
|
||||
if ((res = *su1 - *su2) != 0)
|
||||
break;
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMSCAN
|
||||
/**
|
||||
* memscan - Find a character in an area of memory.
|
||||
* @addr: The memory area
|
||||
* @c: The byte to search for
|
||||
* @size: The size of the area.
|
||||
*
|
||||
* returns the address of the first occurrence of @c, or 1 byte past
|
||||
* the area if @c is not found
|
||||
*/
|
||||
void * memscan(void * addr, int c, size_t size)
|
||||
{
|
||||
unsigned char * p = (unsigned char *) addr;
|
||||
|
||||
while (size) {
|
||||
if (*p == c)
|
||||
return (void *) p;
|
||||
p++;
|
||||
size--;
|
||||
}
|
||||
return (void *) p;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_STRSTR
|
||||
/**
|
||||
* strstr - Find the first substring in a %NUL terminated string
|
||||
* @s1: The string to be searched
|
||||
* @s2: The string to search for
|
||||
*/
|
||||
char * strstr(const char * s1,const char * s2)
|
||||
{
|
||||
int l1, l2;
|
||||
|
||||
l2 = strlen(s2);
|
||||
if (!l2)
|
||||
return (char *) s1;
|
||||
l1 = strlen(s1);
|
||||
while (l1 >= l2) {
|
||||
l1--;
|
||||
if (!memcmp(s1,s2,l2))
|
||||
return (char *) s1;
|
||||
s1++;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMCHR
|
||||
/**
|
||||
* memchr - Find a character in an area of memory.
|
||||
* @s: The memory area
|
||||
* @c: The byte to search for
|
||||
* @n: The size of the area.
|
||||
*
|
||||
* returns the address of the first occurrence of @c, or %NULL
|
||||
* if @c is not found
|
||||
*/
|
||||
void *memchr(const void *s, int c, size_t n)
|
||||
{
|
||||
const unsigned char *p = s;
|
||||
while (n-- != 0) {
|
||||
if ((unsigned char)c == *p++) {
|
||||
return (void *)(p-1);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,9 +3,11 @@ include $(BASEDIR)/Rules.mk
|
||||
|
||||
default: $(OBJS)
|
||||
$(MAKE) -C aacraid
|
||||
$(LD) -r -o driver.o $(OBJS) aacraid/aacraid.o
|
||||
$(MAKE) -C aic7xxx
|
||||
$(LD) -r -o driver.o $(OBJS) aacraid/aacraid.o aic7xxx/aic7xxx.o
|
||||
# $(LD) -r -o driver.o $(OBJS)
|
||||
|
||||
clean:
|
||||
$(MAKE) -C aacraid clean
|
||||
$(MAKE) -C aic7xxx clean
|
||||
rm -f *.o *~ core
|
||||
@@ -0,0 +1,69 @@
|
||||
#
|
||||
# drivers/scsi/aic7xxx/Makefile
|
||||
#
|
||||
# Makefile for the Linux aic7xxx SCSI driver.
|
||||
#
|
||||
|
||||
O_TARGET := aic7xxx_drv.o
|
||||
|
||||
include $(BASEDIR)/Rules.mk
|
||||
#CFLAGS += -I$(BASEDIR)/drivers/scsi
|
||||
|
||||
#list-multi := aic7xxx.o aic79xx.o
|
||||
|
||||
#obj-$(CONFIG_SCSI_AIC7XXX) += aic7xxx.o
|
||||
#ifeq ($(CONFIG_PCI),y)
|
||||
#obj-$(CONFIG_SCSI_AIC79XX) += aic79xx.o
|
||||
#endif
|
||||
|
||||
#EXTRA_CFLAGS += -g
|
||||
|
||||
# Platform Specific Files
|
||||
obj-aic7xxx = aic7xxx_osm.o aic7xxx_proc.o aic7770_osm.o
|
||||
#PCI Specific Platform Files
|
||||
#ifeq ($(CONFIG_PCI),y)
|
||||
obj-aic7xxx += aic7xxx_osm_pci.o
|
||||
#endif
|
||||
# Core Files
|
||||
obj-aic7xxx += aic7xxx_core.o aic7xxx_93cx6.o aic7770.o
|
||||
#PCI Specific Core Files
|
||||
#ifeq ($(CONFIG_PCI),y)
|
||||
obj-aic7xxx += aic7xxx_pci.o
|
||||
#endif
|
||||
|
||||
# Platform Specific U320 Files
|
||||
#obj-aic79xx = aic79xx_osm.o
|
||||
#obj-aic79xx += aic79xx_proc.o
|
||||
#obj-aic79xx += aic79xx_osm_pci.o
|
||||
# Core Files
|
||||
#obj-aic79xx += aic79xx_core.o
|
||||
#obj-aic79xx += aic79xx_pci.o
|
||||
|
||||
default: aic7xxx.o
|
||||
|
||||
aic7xxx_core.o: aic7xxx_seq.h
|
||||
$(obj-aic7xxx): aic7xxx_reg.h
|
||||
aic7xxx.o: aic7xxx_seq.h aic7xxx_reg.h $(obj-aic7xxx)
|
||||
$(LD) $(LD_RFLAG) -r -o $@ $(obj-aic7xxx)
|
||||
|
||||
aic79xx_core.o: aic79xx_seq.h
|
||||
$(obj-aic79xx): aic79xx_reg.h
|
||||
aic79xx.o: aic79xx_seq.h aic79xx_reg.h $(obj-aic79xx)
|
||||
$(LD) $(LD_RFLAG) -r -o $@ $(obj-aic79xx)
|
||||
|
||||
#ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
|
||||
#aic7xxx_seq.h aic7xxx_reg.h: aic7xxx.seq aic7xxx.reg aicasm/aicasm
|
||||
# aicasm/aicasm -I. -r aic7xxx_reg.h -o aic7xxx_seq.h aic7xxx.seq
|
||||
#endif
|
||||
|
||||
#ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
|
||||
#aic79xx_seq.h aic79xx_reg.h: aic79xx.seq aic79xx.reg aicasm/aicasm
|
||||
# aicasm/aicasm -I. -r aic79xx_reg.h -o aic79xx_seq.h aic79xx.seq
|
||||
#endif
|
||||
|
||||
#aicasm/aicasm: aicasm/*.[chyl]
|
||||
# $(MAKE) -C aicasm
|
||||
|
||||
clean:
|
||||
rm -f *.o *~ core
|
||||
|
||||
@@ -0,0 +1,369 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* 27/284X and aic7770 motherboard SCSI controllers
|
||||
*
|
||||
* Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7770.c#21 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aic7770.c,v 1.1 2000/09/16 20:02:27 gibbs Exp $
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_osm.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#else
|
||||
#include <dev/aic7xxx/aic7xxx_osm.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
#define ID_AIC7770 0x04907770
|
||||
#define ID_AHA_274x 0x04907771
|
||||
#define ID_AHA_284xB 0x04907756 /* BIOS enabled */
|
||||
#define ID_AHA_284x 0x04907757 /* BIOS disabled*/
|
||||
|
||||
static int aha2840_load_seeprom(struct ahc_softc *ahc);
|
||||
static ahc_device_setup_t ahc_aic7770_VL_setup;
|
||||
static ahc_device_setup_t ahc_aic7770_EISA_setup;;
|
||||
static ahc_device_setup_t ahc_aic7770_setup;
|
||||
|
||||
|
||||
struct aic7770_identity aic7770_ident_table [] =
|
||||
{
|
||||
{
|
||||
ID_AHA_274x,
|
||||
0xFFFFFFFF,
|
||||
"Adaptec 274X SCSI adapter",
|
||||
ahc_aic7770_EISA_setup
|
||||
},
|
||||
{
|
||||
ID_AHA_284xB,
|
||||
0xFFFFFFFE,
|
||||
"Adaptec 284X SCSI adapter",
|
||||
ahc_aic7770_VL_setup
|
||||
},
|
||||
/* Generic chip probes for devices we don't know 'exactly' */
|
||||
{
|
||||
ID_AIC7770,
|
||||
0xFFFFFFFF,
|
||||
"Adaptec aic7770 SCSI adapter",
|
||||
ahc_aic7770_EISA_setup
|
||||
}
|
||||
};
|
||||
const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table);
|
||||
|
||||
struct aic7770_identity *
|
||||
aic7770_find_device(uint32_t id)
|
||||
{
|
||||
struct aic7770_identity *entry;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ahc_num_aic7770_devs; i++) {
|
||||
entry = &aic7770_ident_table[i];
|
||||
if (entry->full_id == (id & entry->id_mask))
|
||||
return (entry);
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
|
||||
{
|
||||
u_long l;
|
||||
u_long s;
|
||||
int error;
|
||||
int have_seeprom;
|
||||
u_int hostconf;
|
||||
u_int irq;
|
||||
u_int intdef;
|
||||
|
||||
error = entry->setup(ahc);
|
||||
have_seeprom = 0;
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = aic7770_map_registers(ahc, io);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Before we continue probing the card, ensure that
|
||||
* its interrupts are *disabled*. We don't want
|
||||
* a misstep to hang the machine in an interrupt
|
||||
* storm.
|
||||
*/
|
||||
ahc_intr_enable(ahc, FALSE);
|
||||
|
||||
ahc->description = entry->name;
|
||||
error = ahc_softc_init(ahc);
|
||||
|
||||
error = ahc_reset(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Make sure we have a valid interrupt vector */
|
||||
intdef = ahc_inb(ahc, INTDEF);
|
||||
irq = intdef & VECTOR;
|
||||
switch (irq) {
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
case 12:
|
||||
case 14:
|
||||
case 15:
|
||||
break;
|
||||
default:
|
||||
printf("aic7770_config: illegal irq setting %d\n", intdef);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if ((intdef & EDGE_TRIG) != 0)
|
||||
ahc->flags |= AHC_EDGE_INTERRUPT;
|
||||
|
||||
switch (ahc->chip & (AHC_EISA|AHC_VL)) {
|
||||
case AHC_EISA:
|
||||
{
|
||||
u_int biosctrl;
|
||||
u_int scsiconf;
|
||||
u_int scsiconf1;
|
||||
|
||||
biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
|
||||
scsiconf = ahc_inb(ahc, SCSICONF);
|
||||
scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
|
||||
|
||||
/* Get the primary channel information */
|
||||
if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
|
||||
ahc->flags |= 1;
|
||||
|
||||
if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
if ((ahc->features & AHC_WIDE) != 0) {
|
||||
ahc->our_id = scsiconf1 & HWSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
} else {
|
||||
ahc->our_id = scsiconf & HSCSIID;
|
||||
ahc->our_id_b = scsiconf1 & HSCSIID;
|
||||
if (scsiconf & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
if (scsiconf1 & TERM_ENB)
|
||||
ahc->flags |= AHC_TERM_ENB_B;
|
||||
}
|
||||
}
|
||||
if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS))
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
|
||||
break;
|
||||
}
|
||||
case AHC_VL:
|
||||
{
|
||||
have_seeprom = aha2840_load_seeprom(ahc);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (have_seeprom == 0) {
|
||||
free(ahc->seep_config, M_DEVBUF);
|
||||
ahc->seep_config = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure autoflush is enabled
|
||||
*/
|
||||
ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
|
||||
|
||||
/* Setup the FIFO threshold and the bus off time */
|
||||
hostconf = ahc_inb(ahc, HOSTCONF);
|
||||
ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
|
||||
ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
|
||||
|
||||
/*
|
||||
* Generic aic7xxx initialization.
|
||||
*/
|
||||
error = ahc_init(ahc);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
error = aic7770_map_int(ahc, irq);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahc_list_lock(&l);
|
||||
/*
|
||||
* Link this softc in with all other ahc instances.
|
||||
*/
|
||||
ahc_softc_insert(ahc);
|
||||
|
||||
/*
|
||||
* Enable the board's BUS drivers
|
||||
*/
|
||||
ahc_outb(ahc, BCTL, ENABLE);
|
||||
|
||||
/*
|
||||
* Allow interrupts.
|
||||
*/
|
||||
ahc_lock(ahc, &s);
|
||||
ahc_intr_enable(ahc, TRUE);
|
||||
ahc_unlock(ahc, &s);
|
||||
|
||||
ahc_list_unlock(&l);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the 284x SEEPROM.
|
||||
*/
|
||||
static int
|
||||
aha2840_load_seeprom(struct ahc_softc *ahc)
|
||||
{
|
||||
struct seeprom_descriptor sd;
|
||||
struct seeprom_config *sc;
|
||||
int have_seeprom;
|
||||
uint8_t scsi_conf;
|
||||
|
||||
sd.sd_ahc = ahc;
|
||||
sd.sd_control_offset = SEECTL_2840;
|
||||
sd.sd_status_offset = STATUS_2840;
|
||||
sd.sd_dataout_offset = STATUS_2840;
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = 0;
|
||||
sd.sd_RDY = EEPROM_TF;
|
||||
sd.sd_CS = CS_2840;
|
||||
sd.sd_CK = CK_2840;
|
||||
sd.sd_DO = DO_2840;
|
||||
sd.sd_DI = DI_2840;
|
||||
sc = ahc->seep_config;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahc_name(ahc));
|
||||
have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)&sc,
|
||||
/*start_addr*/0, sizeof(sc)/2);
|
||||
|
||||
if (have_seeprom) {
|
||||
|
||||
if (ahc_verify_cksum(sc) == 0) {
|
||||
if(bootverbose)
|
||||
printf ("checksum error\n");
|
||||
have_seeprom = 0;
|
||||
} else if (bootverbose) {
|
||||
printf("done.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (!have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("%s: No SEEPROM available\n", ahc_name(ahc));
|
||||
ahc->flags |= AHC_USEDEFAULTS;
|
||||
} else {
|
||||
/*
|
||||
* Put the data we've collected down into SRAM
|
||||
* where ahc_init will find it.
|
||||
*/
|
||||
int i;
|
||||
int max_targ;
|
||||
uint16_t discenable;
|
||||
|
||||
max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
|
||||
discenable = 0;
|
||||
for (i = 0; i < max_targ; i++){
|
||||
uint8_t target_settings;
|
||||
|
||||
target_settings = (sc->device_flags[i] & CFXFER) << 4;
|
||||
if (sc->device_flags[i] & CFSYNCH)
|
||||
target_settings |= SOFS;
|
||||
if (sc->device_flags[i] & CFWIDEB)
|
||||
target_settings |= WIDEXFER;
|
||||
if (sc->device_flags[i] & CFDISC)
|
||||
discenable |= (0x01 << i);
|
||||
ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
|
||||
}
|
||||
ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
|
||||
ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
|
||||
|
||||
ahc->our_id = sc->brtime_id & CFSCSIID;
|
||||
|
||||
scsi_conf = (ahc->our_id & 0x7);
|
||||
if (sc->adapter_control & CFSPARITY)
|
||||
scsi_conf |= ENSPCHK;
|
||||
if (sc->adapter_control & CFRESETB)
|
||||
scsi_conf |= RESET_SCSI;
|
||||
|
||||
if (sc->bios_control & CF284XEXTEND)
|
||||
ahc->flags |= AHC_EXTENDED_TRANS_A;
|
||||
/* Set SCSICONF info */
|
||||
ahc_outb(ahc, SCSICONF, scsi_conf);
|
||||
|
||||
if (sc->adapter_control & CF284XSTERM)
|
||||
ahc->flags |= AHC_TERM_ENB_A;
|
||||
}
|
||||
return (have_seeprom);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_VL_setup(struct ahc_softc *ahc)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ahc_aic7770_setup(ahc);
|
||||
ahc->chip |= AHC_VL;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_EISA_setup(struct ahc_softc *ahc)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = ahc_aic7770_setup(ahc);
|
||||
ahc->chip |= AHC_EISA;
|
||||
return (error);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_aic7770_setup(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc->channel = 'A';
|
||||
ahc->channel_b = 'B';
|
||||
ahc->chip = AHC_AIC7770;
|
||||
ahc->features = AHC_AIC7770_FE;
|
||||
ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
|
||||
ahc->flags |= AHC_PAGESCBS;
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Linux driver attachment glue for aic7770 based controllers.
|
||||
*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#11 $
|
||||
*/
|
||||
|
||||
#include "aic7xxx_osm.h"
|
||||
|
||||
#define MINSLOT 1
|
||||
#define NUMSLOTS 16
|
||||
#define IDOFFSET 0x80
|
||||
|
||||
int
|
||||
aic7770_linux_probe(Scsi_Host_Template *template)
|
||||
{
|
||||
#if defined(__i386__) || defined(__alpha__)
|
||||
struct aic7770_identity *entry;
|
||||
struct ahc_softc *ahc;
|
||||
int i, slot;
|
||||
int eisaBase;
|
||||
int found;
|
||||
|
||||
eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
|
||||
found = 0;
|
||||
for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
|
||||
uint32_t eisa_id;
|
||||
size_t id_size;
|
||||
|
||||
if (check_region(eisaBase, AHC_EISA_IOSIZE) != 0)
|
||||
continue;
|
||||
|
||||
eisa_id = 0;
|
||||
id_size = sizeof(eisa_id);
|
||||
for (i = 0; i < 4; i++) {
|
||||
/* VLcards require priming*/
|
||||
outb(0x80 + i, eisaBase + IDOFFSET);
|
||||
eisa_id |= inb(eisaBase + IDOFFSET + i)
|
||||
<< ((id_size-i-1) * 8);
|
||||
}
|
||||
if (eisa_id & 0x80000000)
|
||||
continue; /* no EISA card in slot */
|
||||
|
||||
entry = aic7770_find_device(eisa_id);
|
||||
if (entry != NULL) {
|
||||
char buf[80];
|
||||
char *name;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Allocate a softc for this card and
|
||||
* set it up for attachment by our
|
||||
* common detect routine.
|
||||
*/
|
||||
sprintf(buf, "ahc_eisa:%d", slot);
|
||||
name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
|
||||
if (name == NULL)
|
||||
break;
|
||||
strcpy(name, buf);
|
||||
ahc = ahc_alloc(template, name);
|
||||
if (ahc == NULL) {
|
||||
/*
|
||||
* If we can't allocate this one,
|
||||
* chances are we won't be able to
|
||||
* allocate future card structures.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
error = aic7770_config(ahc, entry, eisaBase);
|
||||
if (error != 0) {
|
||||
ahc->bsh.ioport = 0;
|
||||
ahc_free(ahc);
|
||||
continue;
|
||||
}
|
||||
found++;
|
||||
}
|
||||
}
|
||||
return (found);
|
||||
#else
|
||||
return (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_map_registers(struct ahc_softc *ahc, u_int port)
|
||||
{
|
||||
/*
|
||||
* Lock out other contenders for our i/o space.
|
||||
*/
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
request_region(port, AHC_EISA_IOSIZE, "aic7xxx");
|
||||
#else
|
||||
if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0)
|
||||
return (ENOMEM);
|
||||
#endif
|
||||
ahc->tag = BUS_SPACE_PIO;
|
||||
ahc->bsh.ioport = port;
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
aic7770_map_int(struct ahc_softc *ahc, u_int irq)
|
||||
{
|
||||
int error;
|
||||
int shared;
|
||||
|
||||
shared = 0;
|
||||
if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
|
||||
shared = SA_SHIRQ;
|
||||
|
||||
error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc);
|
||||
if (error == 0)
|
||||
ahc->platform_data->irq = irq;
|
||||
|
||||
return (-error);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Adaptec AIC79xx device driver host template for Linux.
|
||||
*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_host.h#6 $
|
||||
*/
|
||||
|
||||
#ifndef _AIC79XX_LINUX_HOST_H_
|
||||
#define _AIC79XX_LINUX_HOST_H_
|
||||
|
||||
int ahd_linux_proc_info(char *, char **, off_t, int, int, int);
|
||||
int ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
|
||||
int ahd_linux_detect(Scsi_Host_Template *);
|
||||
int ahd_linux_release(struct Scsi_Host *);
|
||||
const char *ahd_linux_info(struct Scsi_Host *);
|
||||
int ahd_linux_biosparam(Disk *, kdev_t, int[]);
|
||||
int ahd_linux_bus_reset(Scsi_Cmnd *);
|
||||
int ahd_linux_dev_reset(Scsi_Cmnd *);
|
||||
int ahd_linux_abort(Scsi_Cmnd *);
|
||||
|
||||
#if defined(__i386__)
|
||||
# define AIC79XX_BIOSPARAM ahd_linux_biosparam
|
||||
#else
|
||||
# define AIC79XX_BIOSPARAM NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Scsi_Host_Template (see hosts.h) for AIC-79xx - some fields
|
||||
* to do with card config are filled in after the card is detected.
|
||||
*/
|
||||
#define AIC79XX { \
|
||||
next: NULL, \
|
||||
module: NULL, \
|
||||
proc_dir: NULL, \
|
||||
proc_info: ahd_linux_proc_info, \
|
||||
name: NULL, \
|
||||
detect: ahd_linux_detect, \
|
||||
release: ahd_linux_release, \
|
||||
info: ahd_linux_info, \
|
||||
command: NULL, \
|
||||
queuecommand: ahd_linux_queue, \
|
||||
eh_strategy_handler: NULL, \
|
||||
eh_abort_handler: ahd_linux_abort, \
|
||||
eh_device_reset_handler: ahd_linux_dev_reset, \
|
||||
eh_bus_reset_handler: ahd_linux_bus_reset, \
|
||||
eh_host_reset_handler: NULL, \
|
||||
abort: NULL, \
|
||||
reset: NULL, \
|
||||
slave_attach: NULL, \
|
||||
bios_param: AIC79XX_BIOSPARAM, \
|
||||
can_queue: AHD_MAX_QUEUE,/* max simultaneous cmds */\
|
||||
this_id: -1, /* scsi id of host adapter */\
|
||||
sg_tablesize: AHD_NSEG, /* max scatter-gather cmds */\
|
||||
cmd_per_lun: 2, /* cmds per lun */\
|
||||
present: 0, /* number of 7xxx's present */\
|
||||
unchecked_isa_dma: 0, /* no memory DMA restrictions*/\
|
||||
use_clustering: ENABLE_CLUSTERING, \
|
||||
use_new_eh_code: 1 \
|
||||
}
|
||||
|
||||
#endif /* _AIC79XX_LINUX_HOST_H_ */
|
||||
@@ -0,0 +1,997 @@
|
||||
/*
|
||||
* Inline routines shareable across OS platforms.
|
||||
*
|
||||
* Copyright (c) 1994-2001 Justin T. Gibbs.
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#28 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _AIC79XX_INLINE_H_
|
||||
#define _AIC79XX_INLINE_H_
|
||||
|
||||
/******************************** Debugging ***********************************/
|
||||
static __inline char *ahd_name(struct ahd_softc *ahd);
|
||||
|
||||
static __inline char *
|
||||
ahd_name(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd->name);
|
||||
}
|
||||
|
||||
/************************ Sequencer Execution Control *************************/
|
||||
static __inline void ahd_known_modes(struct ahd_softc *ahd,
|
||||
ahd_mode src, ahd_mode dst);
|
||||
static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
|
||||
ahd_mode src,
|
||||
ahd_mode dst);
|
||||
static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
|
||||
ahd_mode_state state,
|
||||
ahd_mode *src, ahd_mode *dst);
|
||||
static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
|
||||
ahd_mode dst);
|
||||
static __inline void ahd_update_modes(struct ahd_softc *ahd);
|
||||
static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
|
||||
ahd_mode dstmode, const char *file,
|
||||
int line);
|
||||
static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
|
||||
static __inline void ahd_restore_modes(struct ahd_softc *ahd,
|
||||
ahd_mode_state state);
|
||||
static __inline int ahd_is_paused(struct ahd_softc *ahd);
|
||||
static __inline void ahd_pause(struct ahd_softc *ahd);
|
||||
static __inline void ahd_unpause(struct ahd_softc *ahd);
|
||||
|
||||
static __inline void
|
||||
ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
{
|
||||
ahd->src_mode = src;
|
||||
ahd->dst_mode = dst;
|
||||
ahd->saved_src_mode = src;
|
||||
ahd->saved_dst_mode = dst;
|
||||
}
|
||||
|
||||
static __inline ahd_mode_state
|
||||
ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
{
|
||||
return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state,
|
||||
ahd_mode *src, ahd_mode *dst)
|
||||
{
|
||||
*src = (state & SRC_MODE) >> SRC_MODE_SHIFT;
|
||||
*dst = (state & DST_MODE) >> DST_MODE_SHIFT;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
|
||||
{
|
||||
if (ahd->src_mode == src && ahd->dst_mode == dst)
|
||||
return;
|
||||
#ifdef AHD_DEBUG
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
panic("Setting mode prior to saving it.\n");
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("Setting mode 0x%x\n",
|
||||
ahd_build_mode_state(ahd, src, dst));
|
||||
#endif
|
||||
ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
|
||||
ahd->src_mode = src;
|
||||
ahd->dst_mode = dst;
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_update_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_mode_state mode_ptr;
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
mode_ptr = ahd_inb(ahd, MODE_PTR);
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
|
||||
printf("Reading mode 0x%x\n", mode_ptr);
|
||||
#endif
|
||||
ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
|
||||
ahd_known_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
|
||||
ahd_mode dstmode, const char *file, int line)
|
||||
{
|
||||
#ifdef AHD_DEBUG
|
||||
if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
|
||||
|| (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
|
||||
panic("%s:%s:%d: Mode assertion failed.\n",
|
||||
ahd_name(ahd), file, line);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static __inline ahd_mode_state
|
||||
ahd_save_modes(struct ahd_softc *ahd)
|
||||
{
|
||||
if (ahd->src_mode == AHD_MODE_UNKNOWN
|
||||
|| ahd->dst_mode == AHD_MODE_UNKNOWN)
|
||||
ahd_update_modes(ahd);
|
||||
|
||||
return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
|
||||
{
|
||||
ahd_mode src;
|
||||
ahd_mode dst;
|
||||
|
||||
ahd_extract_mode_state(ahd, state, &src, &dst);
|
||||
ahd_set_modes(ahd, src, dst);
|
||||
}
|
||||
|
||||
#define AHD_ASSERT_MODES(ahd, source, dest) \
|
||||
ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
static __inline int
|
||||
ahd_is_paused(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_pause(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_outb(ahd, HCNTRL, ahd->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahd_is_paused(ahd) == 0)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_unpause(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
* Automatically restore our modes to those saved
|
||||
* prior to the first change of the mode.
|
||||
*/
|
||||
if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
|
||||
&& ahd->saved_dst_mode != AHD_MODE_UNKNOWN)
|
||||
ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
|
||||
|
||||
if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0)
|
||||
ahd_outb(ahd, HCNTRL, ahd->unpause);
|
||||
|
||||
ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
|
||||
}
|
||||
|
||||
/*********************** Untagged Transaction Routines ************************/
|
||||
static __inline void ahd_freeze_untagged_queues(struct ahd_softc *ahd);
|
||||
static __inline void ahd_release_untagged_queues(struct ahd_softc *ahd);
|
||||
|
||||
/*
|
||||
* Block our completion routine from starting the next untagged
|
||||
* transaction for this target or target lun.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_freeze_untagged_queues(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
* Assume we have enough space in the card's SCB
|
||||
* to obviate the need for a per target untagged
|
||||
* transaction limit.
|
||||
*/
|
||||
#if 0
|
||||
ahd->untagged_queue_lock++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the next untagged transaction for this target or target lun
|
||||
* to be executed. We use a counting semaphore to allow the lock
|
||||
* to be acquired recursively. Once the count drops to zero, the
|
||||
* transaction queues will be run.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_release_untagged_queues(struct ahd_softc *ahd)
|
||||
{
|
||||
/*
|
||||
* Assume we have enough space in the card's SCB
|
||||
* to obviate the need for a per target untagged
|
||||
* transaction limit.
|
||||
*/
|
||||
#if 0
|
||||
ahd->untagged_queue_lock--;
|
||||
if (ahd->untagged_queue_lock == 0)
|
||||
ahd_run_untagged_queues(ahd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*********************** Scatter Gather List Handling *************************/
|
||||
static __inline void *ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, bus_addr_t addr,
|
||||
bus_size_t len, int last);
|
||||
static __inline void ahd_setup_scb_common(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_setup_data_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_setup_noxfer_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
|
||||
static __inline void *
|
||||
ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
|
||||
void *sgptr, bus_addr_t addr, bus_size_t len, int last)
|
||||
{
|
||||
scb->sg_count++;
|
||||
if (sizeof(bus_addr_t) > 4
|
||||
&& (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)sgptr;
|
||||
sg->addr = ahd_htole64(addr);
|
||||
sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma_seg *)sgptr;
|
||||
sg->addr = ahd_htole64(addr);
|
||||
sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
|
||||
| (last ? AHD_DMA_LAST_SEG : 0));
|
||||
return (sg + 1);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/* XXX Handle target mode SCBs. */
|
||||
if ((scb->flags & SCB_PACKETIZED) != 0) {
|
||||
/* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */
|
||||
scb->hscb->task_attribute_nonpkt_tag =
|
||||
scb->hscb->control & SCB_TAG_TYPE;
|
||||
scb->hscb->task_management = 0;
|
||||
} else {
|
||||
scb->hscb->task_attribute_nonpkt_tag = SCB_GET_TAG(scb);
|
||||
}
|
||||
|
||||
if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
|
||||
|| (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
|
||||
scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
|
||||
ahd_htole32(scb->sense_busaddr);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
/*
|
||||
* Copy the first SG into the "current" data ponter area.
|
||||
*/
|
||||
if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
|
||||
struct ahd_dma64_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma64_seg *)scb->sg_list;
|
||||
scb->hscb->dataptr = sg->addr;
|
||||
scb->hscb->datacnt = sg->len;
|
||||
} else {
|
||||
struct ahd_dma_seg *sg;
|
||||
|
||||
sg = (struct ahd_dma_seg *)scb->sg_list;
|
||||
scb->hscb->dataptr = sg->addr;
|
||||
if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
|
||||
uint64_t high_addr;
|
||||
|
||||
high_addr = ahd_le32toh(sg->len) & 0x7F000000;
|
||||
scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
|
||||
}
|
||||
scb->hscb->datacnt = sg->len;
|
||||
}
|
||||
/*
|
||||
* Note where to find the SG entries in bus space.
|
||||
* We also set the full residual flag which the
|
||||
* sequencer will clear as soon as a data transfer
|
||||
* occurs.
|
||||
*/
|
||||
scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
|
||||
scb->hscb->dataptr = 0;
|
||||
scb->hscb->datacnt = 0;
|
||||
}
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static __inline size_t ahd_sg_size(struct ahd_softc *ahd);
|
||||
static __inline void *
|
||||
ahd_sg_bus_to_virt(struct ahd_softc *ahd,
|
||||
struct scb *scb,
|
||||
uint32_t sg_busaddr);
|
||||
static __inline uint32_t
|
||||
ahd_sg_virt_to_bus(struct ahd_softc *ahd,
|
||||
struct scb *scb,
|
||||
void *sg);
|
||||
static __inline void ahd_sync_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahd_sync_sglist(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahd_sync_sense(struct ahd_softc *ahd,
|
||||
struct scb *scb, int op);
|
||||
static __inline uint32_t
|
||||
ahd_targetcmd_offset(struct ahd_softc *ahd,
|
||||
u_int index);
|
||||
|
||||
static __inline size_t
|
||||
ahd_sg_size(struct ahd_softc *ahd)
|
||||
{
|
||||
if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
|
||||
return (sizeof(struct ahd_dma64_seg));
|
||||
return (sizeof(struct ahd_dma_seg));
|
||||
}
|
||||
|
||||
static __inline void *
|
||||
ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
bus_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
|
||||
return ((uint8_t *)scb->sg_list + sg_offset);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
|
||||
{
|
||||
bus_addr_t sg_offset;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
|
||||
- ahd_sg_size(ahd);
|
||||
|
||||
return (scb->sg_list_busaddr + sg_offset);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
|
||||
scb->hscb_map->dmamap,
|
||||
/*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
|
||||
scb->sg_map->dmamap,
|
||||
/*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
|
||||
/*len*/ahd_sg_size(ahd) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
|
||||
scb->sense_map->dmamap,
|
||||
/*offset*/scb->sense_busaddr,
|
||||
/*len*/AHD_SENSE_BUFSIZE, op);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahd->targetcmds[index])
|
||||
- (uint8_t *)ahd->qoutfifo);
|
||||
}
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
static __inline void ahd_complete_scb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_update_residual(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahd_tmode_tstate **tstate);
|
||||
static __inline struct scb*
|
||||
ahd_get_scb(struct ahd_softc *ahd);
|
||||
static __inline void ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
|
||||
static __inline uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outw(struct ahd_softc *ahd, u_int port,
|
||||
u_int value);
|
||||
static __inline uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outl(struct ahd_softc *ahd, u_int port,
|
||||
uint32_t value);
|
||||
static __inline uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port);
|
||||
static __inline void ahd_outq(struct ahd_softc *ahd, u_int port,
|
||||
uint64_t value);
|
||||
static __inline u_int ahd_get_scbptr(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
|
||||
static __inline u_int ahd_get_hnscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_hescb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_snscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_sescb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_get_sdscb_qoff(struct ahd_softc *ahd);
|
||||
static __inline void ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
|
||||
static __inline u_int ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline u_int ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline uint32_t
|
||||
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
|
||||
static __inline void ahd_swap_with_next_hscb(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline void ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
|
||||
static __inline uint8_t *
|
||||
ahd_get_sense_buf(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
static __inline uint32_t
|
||||
ahd_get_sense_bufaddr(struct ahd_softc *ahd,
|
||||
struct scb *scb);
|
||||
|
||||
static __inline void
|
||||
ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
uint32_t sgptr;
|
||||
|
||||
sgptr = ahd_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_STATUS_VALID) != 0)
|
||||
ahd_handle_scb_status(ahd, scb);
|
||||
else
|
||||
ahd_done(ahd, scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
uint32_t sgptr;
|
||||
|
||||
sgptr = ahd_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_STATUS_VALID) != 0)
|
||||
ahd_calc_residual(ahd, scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
static __inline struct ahd_initiator_tinfo *
|
||||
ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahd_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahd->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free scb. If there are none, see if we can allocate a new SCB.
|
||||
*/
|
||||
static __inline struct scb *
|
||||
ahd_get_scb(struct ahd_softc *ahd)
|
||||
{
|
||||
struct scb *scb;
|
||||
|
||||
if ((scb = SLIST_FIRST(&ahd->scb_data.free_scbs)) == NULL) {
|
||||
ahd_alloc_scbs(ahd);
|
||||
scb = SLIST_FIRST(&ahd->scb_data.free_scbs);
|
||||
if (scb == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
SLIST_REMOVE_HEAD(&ahd->scb_data.free_scbs, links.sle);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an SCB resource to the free list.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
|
||||
/* Clean up for the next user */
|
||||
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL;
|
||||
scb->flags = SCB_FREE;
|
||||
scb->hscb->control = 0;
|
||||
|
||||
SLIST_INSERT_HEAD(&ahd->scb_data.free_scbs, scb, links.sle);
|
||||
|
||||
/* Notify the OSM that a resource is now available. */
|
||||
ahd_platform_scb_free(ahd, scb);
|
||||
}
|
||||
|
||||
static __inline uint16_t
|
||||
ahd_inw(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
|
||||
{
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_inl(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, (value) & 0xFF);
|
||||
ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline uint64_t
|
||||
ahd_inq(struct ahd_softc *ahd, u_int port)
|
||||
{
|
||||
return ((ahd_inb(ahd, port))
|
||||
| (ahd_inb(ahd, port+1) << 8)
|
||||
| (ahd_inb(ahd, port+2) << 16)
|
||||
| (ahd_inb(ahd, port+3) << 24)
|
||||
| (((uint64_t)ahd_inb(ahd, port+4)) << 32)
|
||||
| (((uint64_t)ahd_inb(ahd, port+5)) << 40)
|
||||
| (((uint64_t)ahd_inb(ahd, port+6)) << 48)
|
||||
| (((uint64_t)ahd_inb(ahd, port+7)) << 56));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
|
||||
{
|
||||
ahd_outb(ahd, port, value & 0xFF);
|
||||
ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
|
||||
ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
|
||||
ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
|
||||
ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
|
||||
ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
|
||||
ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
|
||||
ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_scbptr(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
|
||||
~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
|
||||
ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
|
||||
ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_hnscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inw_atomic(ahd, HNSCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outw_atomic(ahd, HNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_hescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
return (ahd_inb(ahd, HESCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
ahd_outb(ahd, HESCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_snscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int oldvalue;
|
||||
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
oldvalue = ahd_inw(ahd, SNSCB_QOFF);
|
||||
ahd_outw(ahd, SNSCB_QOFF, oldvalue);
|
||||
return (oldvalue);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outw(ahd, SNSCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_sescb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SESCB_QOFF));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SESCB_QOFF, value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_get_sdscb_qoff(struct ahd_softc *ahd)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
|
||||
{
|
||||
AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
|
||||
ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
|
||||
ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
u_int value;
|
||||
|
||||
/*
|
||||
* Workaround PCI-X Rev A. hardware bug.
|
||||
* After a host read of SCB memory, the chip
|
||||
* may become confused into thinking prefetch
|
||||
* was required. This starts the discard timer
|
||||
* running and can cause an unexpected discard
|
||||
* timer interrupt. The work around is to read
|
||||
* a normal register prior to the exhaustion of
|
||||
* the discard timer. The mode pointer register
|
||||
* has no side effects and so serves well for
|
||||
* this purpose.
|
||||
*
|
||||
* Razor #528
|
||||
*/
|
||||
value = ahd_inb(ahd, offset);
|
||||
ahd_inb(ahd, MODE_PTR);
|
||||
return (value);
|
||||
}
|
||||
|
||||
static __inline u_int
|
||||
ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inb_scbram(ahd, offset)
|
||||
| (ahd_inb_scbram(ahd, offset+1) << 8));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
|
||||
{
|
||||
return (ahd_inb_scbram(ahd, offset)
|
||||
| (ahd_inb_scbram(ahd, offset+1) << 8)
|
||||
| (ahd_inb_scbram(ahd, offset+2) << 16)
|
||||
| (ahd_inb_scbram(ahd, offset+3) << 24));
|
||||
}
|
||||
|
||||
static __inline struct scb *
|
||||
ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
if (tag >= AHD_SCB_MAX)
|
||||
return (NULL);
|
||||
scb = ahd->scb_data.scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahd_sync_scb(ahd, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
uint32_t saved_hscb_busaddr;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB (by address) to download,
|
||||
* and we can't disappoint it. To achieve this, the next
|
||||
* SCB to download is saved off in ahd->next_queued_scb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahd->next_queued_scb->hscb;
|
||||
saved_hscb_busaddr = q_hscb->hscb_busaddr;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
q_hscb->hscb_busaddr = saved_hscb_busaddr;
|
||||
q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahd->next_queued_scb->hscb = scb->hscb;
|
||||
scb->hscb = q_hscb;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
/* XXX This should be constant now. Can we avoid the mapping? */
|
||||
ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
static __inline void
|
||||
ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
ahd_swap_with_next_hscb(ahd, scb);
|
||||
|
||||
if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
|
||||
panic("Attempt to queue invalid SCB tag %x\n",
|
||||
SCB_GET_TAG(scb));
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
|
||||
ahd->qinfifonext++;
|
||||
|
||||
if (scb->sg_count != 0)
|
||||
ahd_setup_data_scb(ahd, scb);
|
||||
else
|
||||
ahd_setup_noxfer_scb(ahd, scb);
|
||||
ahd_setup_scb_common(ahd, scb);
|
||||
|
||||
/*
|
||||
* Make sure our data is consistant from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
#ifdef AHD_DEBUG
|
||||
if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
|
||||
printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
|
||||
ahd_name(ahd),
|
||||
SCB_GET_TAG(scb), scb->hscb->hscb_busaddr,
|
||||
(u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF),
|
||||
(u_int)(scb->hscb->dataptr & 0xFFFFFFFF),
|
||||
scb->hscb->datacnt);
|
||||
}
|
||||
#endif
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
|
||||
}
|
||||
|
||||
static __inline uint8_t *
|
||||
ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
return (scb->sense_data);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
|
||||
{
|
||||
return (scb->sense_busaddr);
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static __inline void ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
|
||||
static __inline void ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
|
||||
static __inline u_int ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
|
||||
static __inline void ahd_intr(struct ahd_softc *ahd);
|
||||
|
||||
static __inline void
|
||||
ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
|
||||
/*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
|
||||
{
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_dmamap,
|
||||
ahd_targetcmd_offset(ahd, 0),
|
||||
sizeof(struct target_cmd) * AHD_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHD_RUN_QOUTFIFO 0x1
|
||||
#define AHD_RUN_TQINFIFO 0x2
|
||||
static __inline u_int
|
||||
ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
|
||||
/*offset*/ahd->qoutfifonext, /*len*/2,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->qoutfifo[ahd->qoutfifonext] != SCB_LIST_NULL_LE)
|
||||
retval |= AHD_RUN_QOUTFIFO;
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0
|
||||
&& (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
|
||||
ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
|
||||
ahd->shared_data_dmamap,
|
||||
ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHD_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline void
|
||||
ahd_intr(struct ahd_softc *ahd)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
|
||||
&& (ahd_check_cmdcmpltqueues(ahd) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else
|
||||
intstat = ahd_inb(ahd, INTSTAT);
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahd_outb(ahd, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
ahd_flush_device_writes(ahd);
|
||||
ahd_run_qoutfifo(ahd);
|
||||
#ifdef AHD_TARGET_MODE
|
||||
if ((ahd->flags & AHD_TARGETROLE) != 0)
|
||||
ahd_run_tqinfifo(ahd, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0)
|
||||
/* Hot eject */
|
||||
return;
|
||||
|
||||
if ((intstat & INT_PEND) == 0)
|
||||
return;
|
||||
|
||||
if (intstat & HWERRINT) {
|
||||
ahd_handle_hwerrint(ahd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((intstat & (PCIINT|SPLTINT)) != 0) {
|
||||
ahd->bus_intr(ahd);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahd_handle_seqint(ahd, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahd_handle_scsiint(ahd, intstat);
|
||||
}
|
||||
|
||||
#endif /* _AIC79XX_INLINE_H_ */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,428 @@
|
||||
/*
|
||||
* Linux driver attachment glue for PCI based U320 controllers.
|
||||
*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#11 $
|
||||
*/
|
||||
|
||||
#include "aic79xx_osm.h"
|
||||
#include "aic79xx_inline.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
struct pci_device_id
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ahd_linux_pci_dev_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent);
|
||||
static int ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
|
||||
u_long *base, u_long *base2);
|
||||
static int ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
|
||||
u_long *bus_addr,
|
||||
uint8_t **maddr);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
static void ahd_linux_pci_dev_remove(struct pci_dev *pdev);
|
||||
|
||||
/* We do our own ID filtering. So, grab all SCSI storage class devices. */
|
||||
static struct pci_device_id ahd_linux_pci_id_table[] = {
|
||||
{
|
||||
0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
|
||||
|
||||
struct pci_driver aic79xx_pci_driver = {
|
||||
name: "aic79xx",
|
||||
probe: ahd_linux_pci_dev_probe,
|
||||
remove: ahd_linux_pci_dev_remove,
|
||||
id_table: ahd_linux_pci_id_table
|
||||
};
|
||||
|
||||
static void
|
||||
ahd_linux_pci_dev_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ahd_softc *ahd;
|
||||
u_long l;
|
||||
|
||||
/*
|
||||
* We should be able to just perform
|
||||
* the free directly, but check our
|
||||
* list for extra sanity.
|
||||
*/
|
||||
ahd_list_lock(&l);
|
||||
ahd = ahd_find_softc((struct ahd_softc *)pdev->driver_data);
|
||||
if (ahd != NULL) {
|
||||
u_long s;
|
||||
|
||||
ahd_lock(ahd, &s);
|
||||
ahd_intr_enable(ahd, FALSE);
|
||||
ahd_unlock(ahd, &s);
|
||||
ahd_free(ahd);
|
||||
}
|
||||
ahd_list_unlock(&l);
|
||||
}
|
||||
#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
|
||||
|
||||
static int
|
||||
ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
char buf[80];
|
||||
struct ahd_softc *ahd;
|
||||
ahd_dev_softc_t pci;
|
||||
struct ahd_pci_identity *entry;
|
||||
char *name;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Some BIOSen report the same device multiple times.
|
||||
*/
|
||||
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
|
||||
struct pci_dev *probed_pdev;
|
||||
|
||||
probed_pdev = ahd->dev_softc;
|
||||
if (probed_pdev->bus->number == pdev->bus->number
|
||||
&& probed_pdev->devfn == pdev->devfn)
|
||||
break;
|
||||
}
|
||||
if (ahd != NULL) {
|
||||
/* Skip duplicate. */
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
pci = pdev;
|
||||
entry = ahd_find_pci_device(pci);
|
||||
if (entry == NULL)
|
||||
return (-ENODEV);
|
||||
|
||||
/*
|
||||
* Allocate a softc for this card and
|
||||
* set it up for attachment by our
|
||||
* common detect routine.
|
||||
*/
|
||||
sprintf(buf, "ahd_pci:%d:%d:%d",
|
||||
ahd_get_pci_bus(pci),
|
||||
ahd_get_pci_slot(pci),
|
||||
ahd_get_pci_function(pci));
|
||||
name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
|
||||
if (name == NULL)
|
||||
return (-ENOMEM);
|
||||
strcpy(name, buf);
|
||||
ahd = ahd_alloc(NULL, name);
|
||||
if (ahd == NULL)
|
||||
return (-ENOMEM);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
if (pci_enable_device(pdev)) {
|
||||
ahd_free(ahd);
|
||||
return (-ENODEV);
|
||||
}
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (sizeof(bus_addr_t) > 4) {
|
||||
uint64_t memsize;
|
||||
|
||||
memsize = ahd_linux_get_memsize();
|
||||
if (memsize >= 0x8000000000
|
||||
&& ahd_pci_set_dma_mask(pdev, 0xFFFFFFFFFFFFFFFFULL) == 0) {
|
||||
ahd->flags |= AHD_64BIT_ADDRESSING;
|
||||
ahd->platform_data->hw_dma_mask =
|
||||
(bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0);
|
||||
} else if (memsize > 0x80000000
|
||||
&& ahd_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
|
||||
ahd->flags |= AHD_39BIT_ADDRESSING;
|
||||
ahd->platform_data->hw_dma_mask =
|
||||
(bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
ahd->dev_softc = pci;
|
||||
error = ahd_pci_config(ahd, entry);
|
||||
if (error != 0) {
|
||||
ahd_free(ahd);
|
||||
return (-error);
|
||||
}
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
pdev->driver_data = ahd;
|
||||
if (aic79xx_detect_complete)
|
||||
ahd_linux_register_host(ahd, aic79xx_driver_template);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ahd_linux_pci_probe(Scsi_Host_Template *template)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
return (pci_module_init(&aic79xx_pci_driver));
|
||||
#else
|
||||
struct pci_dev *pdev;
|
||||
u_int class;
|
||||
int found;
|
||||
|
||||
/* If we don't have a PCI bus, we can't find any adapters. */
|
||||
if (pci_present() == 0)
|
||||
return (0);
|
||||
|
||||
found = 0;
|
||||
pdev = NULL;
|
||||
class = PCI_CLASS_STORAGE_SCSI << 8;
|
||||
while ((pdev = pci_find_class(class, pdev)) != NULL) {
|
||||
ahd_dev_softc_t pci;
|
||||
int error;
|
||||
|
||||
pci = pdev;
|
||||
error = ahd_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
|
||||
if (error == 0)
|
||||
found++;
|
||||
}
|
||||
return (found);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
|
||||
u_long *base2)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
|
||||
*base = pci_resource_start(ahd->dev_softc, 0);
|
||||
/*
|
||||
* This is really the 3rd bar and should be at index 2,
|
||||
* but the Linux PCI code doesn't know how to "count" 64bit
|
||||
* bars.
|
||||
*/
|
||||
*base2 = pci_resource_start(ahd->dev_softc, 3);
|
||||
#else
|
||||
*base = ahd_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR0, 4);
|
||||
*base2 = ahd_pci_read_config(ahd->dev_softc, AHD_PCI_IOADDR1, 4);
|
||||
*base &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
*base2 &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
#endif
|
||||
if (*base == 0 || *base2 == 0)
|
||||
return (ENOMEM);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
if (check_region(*base, 256) != 0
|
||||
|| check_region(*base2, 256) != 0)
|
||||
return (ENOMEM);
|
||||
else {
|
||||
request_region(*base, 256, "aic79xx");
|
||||
request_region(*base2, 256, "aic79xx");
|
||||
}
|
||||
#else
|
||||
if (request_region(*base, 256, "aic79xx") == 0)
|
||||
return (ENOMEM);
|
||||
if (request_region(*base2, 256, "aic79xx") == 0) {
|
||||
release_region(*base2, 256);
|
||||
return (ENOMEM);
|
||||
}
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
|
||||
u_long *bus_addr,
|
||||
uint8_t **maddr)
|
||||
{
|
||||
u_long start;
|
||||
u_long base_page;
|
||||
u_long base_offset;
|
||||
int error;
|
||||
|
||||
if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX
|
||||
&& (ahd->bugs & AHD_PCIX_MMAPIO_BUG) != 0)
|
||||
return (ENOMEM);
|
||||
|
||||
error = 0;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
|
||||
start = pci_resource_start(ahd->dev_softc, 1);
|
||||
base_page = start & PAGE_MASK;
|
||||
base_offset = start - base_page;
|
||||
#else
|
||||
start = ahd_pci_read_config(ahd->dev_softc, PCIR_MAPS+4, 4);
|
||||
base_offset = start & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
base_page = base_offset & PAGE_MASK;
|
||||
base_offset -= base_page;
|
||||
#endif
|
||||
if (start != 0) {
|
||||
*bus_addr = start;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
if (request_mem_region(start, 0x1000, "aic79xx") == 0)
|
||||
error = ENOMEM;
|
||||
#endif
|
||||
if (error == 0) {
|
||||
*maddr = ioremap_nocache(base_page, base_offset + 256);
|
||||
if (*maddr == NULL) {
|
||||
error = ENOMEM;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
release_mem_region(start, 0x1000);
|
||||
#endif
|
||||
} else
|
||||
*maddr += base_offset;
|
||||
}
|
||||
} else
|
||||
error = ENOMEM;
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ahd_pci_map_registers(struct ahd_softc *ahd)
|
||||
{
|
||||
uint32_t command;
|
||||
u_long base;
|
||||
uint8_t *maddr;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* If its allowed, we prefer memory mapped access.
|
||||
*/
|
||||
command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
|
||||
command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
|
||||
base = 0;
|
||||
maddr = NULL;
|
||||
#ifdef MMAPIO
|
||||
error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr);
|
||||
if (error == 0) {
|
||||
ahd->platform_data->mem_busaddr = base;
|
||||
ahd->tags[0] = BUS_SPACE_MEMIO;
|
||||
ahd->bshs[0].maddr = maddr;
|
||||
ahd->tags[1] = BUS_SPACE_MEMIO;
|
||||
ahd->bshs[1].maddr = maddr + 0x100;
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
|
||||
command | PCIM_CMD_MEMEN, 4);
|
||||
|
||||
/*
|
||||
* Do a quick test to see if memory mapped
|
||||
* I/O is functioning correctly.
|
||||
*/
|
||||
if (ahd_inb(ahd, HCNTRL) == 0xFF) {
|
||||
|
||||
printf("aic79xx: PCI Device %d:%d:%d "
|
||||
"failed memory mapped test\n",
|
||||
ahd_get_pci_bus(ahd->dev_softc),
|
||||
ahd_get_pci_slot(ahd->dev_softc),
|
||||
ahd_get_pci_function(ahd->dev_softc));
|
||||
ahd->bshs[0].maddr = NULL;
|
||||
maddr = NULL;
|
||||
} else
|
||||
command |= PCIM_CMD_MEMEN;
|
||||
} else {
|
||||
printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx "
|
||||
"unavailable. Cannot memory map device.\n",
|
||||
ahd_get_pci_bus(ahd->dev_softc),
|
||||
ahd_get_pci_slot(ahd->dev_softc),
|
||||
ahd_get_pci_function(ahd->dev_softc),
|
||||
base);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (maddr == NULL) {
|
||||
u_long base2;
|
||||
|
||||
error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2);
|
||||
if (error == 0) {
|
||||
ahd->tags[0] = BUS_SPACE_PIO;
|
||||
ahd->tags[1] = BUS_SPACE_PIO;
|
||||
ahd->bshs[0].ioport = base;
|
||||
ahd->bshs[1].ioport = base2;
|
||||
command |= PCIM_CMD_PORTEN;
|
||||
} else {
|
||||
printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx"
|
||||
"unavailable. Cannot map device.\n",
|
||||
ahd_get_pci_bus(ahd->dev_softc),
|
||||
ahd_get_pci_slot(ahd->dev_softc),
|
||||
ahd_get_pci_function(ahd->dev_softc),
|
||||
base, base2);
|
||||
}
|
||||
}
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ahd_pci_map_int(struct ahd_softc *ahd)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
|
||||
SA_SHIRQ, "aic79xx", ahd);
|
||||
if (error == 0)
|
||||
ahd->platform_data->irq = ahd->dev_softc->irq;
|
||||
|
||||
return (-error);
|
||||
}
|
||||
|
||||
void
|
||||
ahd_power_state_change(struct ahd_softc *ahd, ahd_power_state new_state)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
pci_set_power_state(ahd->dev_softc, new_state);
|
||||
#else
|
||||
uint32_t cap;
|
||||
u_int cap_offset;
|
||||
|
||||
/*
|
||||
* Traverse the capability list looking for
|
||||
* the power management capability.
|
||||
*/
|
||||
cap = 0;
|
||||
cap_offset = ahd_pci_read_config(ahd->dev_softc,
|
||||
PCIR_CAP_PTR, /*bytes*/1);
|
||||
while (cap_offset != 0) {
|
||||
|
||||
cap = ahd_pci_read_config(ahd->dev_softc,
|
||||
cap_offset, /*bytes*/4);
|
||||
if ((cap & 0xFF) == 1
|
||||
&& ((cap >> 16) & 0x3) > 0) {
|
||||
uint32_t pm_control;
|
||||
|
||||
pm_control = ahd_pci_read_config(ahd->dev_softc,
|
||||
cap_offset + 4,
|
||||
/*bytes*/4);
|
||||
pm_control &= ~0x3;
|
||||
pm_control |= new_state;
|
||||
ahd_pci_write_config(ahd->dev_softc,
|
||||
cap_offset + 4,
|
||||
pm_control, /*bytes*/2);
|
||||
break;
|
||||
}
|
||||
cap_offset = (cap >> 8) & 0xFF;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,792 @@
|
||||
/*
|
||||
* Product specific probe and attach routines for:
|
||||
* aic7901 and aic7902 SCSI controllers
|
||||
*
|
||||
* Copyright (c) 1994-2001 Justin T. Gibbs.
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#32 $
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic79xx_osm.h"
|
||||
#include "aic79xx_inline.h"
|
||||
#else
|
||||
#include <dev/aic7xxx/aic79xx_osm.h>
|
||||
#include <dev/aic7xxx/aic79xx_inline.h>
|
||||
#endif
|
||||
|
||||
static __inline uint64_t
|
||||
ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
|
||||
{
|
||||
uint64_t id;
|
||||
|
||||
id = subvendor
|
||||
| (subdevice << 16)
|
||||
| ((uint64_t)vendor << 32)
|
||||
| ((uint64_t)device << 48);
|
||||
|
||||
return (id);
|
||||
}
|
||||
|
||||
#define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull
|
||||
#define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull
|
||||
#define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull
|
||||
|
||||
#define ID_AIC7901 0x800F9005FFFF9005ull
|
||||
#define ID_AIC7901_IROC 0x80089005FFFF9005ull
|
||||
#define ID_AHA_29320 0x8000900500609005ull
|
||||
#define ID_AHA_29320LP 0x8000900500409005ull
|
||||
|
||||
#define ID_AIC7902 0x801F9005FFFF9005ull
|
||||
#define ID_AIC7902_IROC 0x80189005FFFF9005ull
|
||||
#define ID_AHA_39320 0x8010900500409005ull
|
||||
#define ID_AHA_39320D 0x8011900500419005ull
|
||||
#define ID_AHA_39320D_CPQ 0x8011900500AC0E11ull
|
||||
#define ID_AIC7902_PCI_REV_A3 0x2
|
||||
#define ID_AIC7902_PCI_REV_A4 0x3
|
||||
#define ID_AIC7902_PCI_REV_B0 0xFF /* Rev Id not yet known. */
|
||||
#define SUBID_CPQ 0x0E11
|
||||
|
||||
#define DEVID_9005_TYPE(id) ((id) & 0xF)
|
||||
#define DEVID_9005_TYPE_HBA 0x0 /* Standard Card */
|
||||
#define DEVID_9005_TYPE_HBA_2EXT 0x1 /* 2 External Ports */
|
||||
#define DEVID_9005_TYPE_IROC 0x8 /* Raid(0,1,10) Card */
|
||||
#define DEVID_9005_TYPE_MB 0xF /* On Motherboard */
|
||||
|
||||
#define DEVID_9005_MFUNC(id) ((id) & 0x10)
|
||||
|
||||
#define DEVID_9005_PACKETIZED(id) ((id) & 0x8000)
|
||||
|
||||
#define SUBID_9005_TYPE(id) ((id) & 0xF)
|
||||
#define SUBID_9005_TYPE_HBA 0x0 /* Standard Card */
|
||||
#define SUBID_9005_TYPE_MB 0xF /* On Motherboard */
|
||||
|
||||
#define SUBID_9005_AUTOTERM(id) (((id) & 0x10) == 0)
|
||||
|
||||
#define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20)
|
||||
|
||||
#define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6)
|
||||
#define SUBID_9005_SEEPTYPE_NONE 0x0
|
||||
#define SUBID_9005_SEEPTYPE_4K 0x1
|
||||
|
||||
static ahd_device_setup_t ahd_aic7901_setup;
|
||||
static ahd_device_setup_t ahd_aic7902_setup;
|
||||
|
||||
struct ahd_pci_identity ahd_pci_ident_table [] =
|
||||
{
|
||||
/* aic7901 based controllers */
|
||||
{
|
||||
ID_AHA_29320,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec 29320 Ultra320 SCSI adapter",
|
||||
ahd_aic7901_setup
|
||||
},
|
||||
{
|
||||
ID_AHA_29320LP,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec 29320LP Ultra320 SCSI adapter",
|
||||
ahd_aic7901_setup
|
||||
},
|
||||
/* aic7902 based controllers */
|
||||
{
|
||||
ID_AHA_39320,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec 39320 Ultra320 SCSI adapter",
|
||||
ahd_aic7902_setup
|
||||
},
|
||||
{
|
||||
ID_AHA_39320D,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec 39320D Ultra320 SCSI adapter",
|
||||
ahd_aic7902_setup
|
||||
},
|
||||
{
|
||||
ID_AHA_39320D_CPQ,
|
||||
ID_ALL_MASK,
|
||||
"Adaptec (Compaq OEM) 39320D Ultra320 SCSI adapter",
|
||||
ahd_aic7902_setup
|
||||
},
|
||||
/* Generic chip probes for devices we don't know 'exactly' */
|
||||
{
|
||||
ID_AIC7901 & ID_9005_GENERIC_MASK,
|
||||
ID_9005_GENERIC_MASK,
|
||||
"Adaptec aic7901 Ultra320 SCSI adapter",
|
||||
ahd_aic7901_setup
|
||||
},
|
||||
{
|
||||
ID_AIC7902 & ID_9005_GENERIC_MASK,
|
||||
ID_9005_GENERIC_MASK,
|
||||
"Adaptec aic7902 Ultra320 SCSI adapter",
|
||||
ahd_aic7902_setup
|
||||
}
|
||||
};
|
||||
|
||||
const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);
|
||||
|
||||
#define DEVCONFIG 0x40
|
||||
#define PCIXINITPAT 0x0000E000ul
|
||||
#define PCIXINIT_PCI33_66 0x0000E000ul
|
||||
#define PCIXINIT_PCIX50_66 0x0000C000ul
|
||||
#define PCIXINIT_PCIX66_100 0x0000A000ul
|
||||
#define PCIXINIT_PCIX100_133 0x00008000ul
|
||||
#define PCI_BUS_MODES_INDEX(devconfig) \
|
||||
(((devconfig) & PCIXINITPAT) >> 13)
|
||||
static const char *pci_bus_modes[] =
|
||||
{
|
||||
"PCI bus mode unknown",
|
||||
"PCI bus mode unknown",
|
||||
"PCI bus mode unknown",
|
||||
"PCI bus mode unknown",
|
||||
"PCI-X 101-133Mhz",
|
||||
"PCI-X 67-100Mhz",
|
||||
"PCI-X 50-66Mhz",
|
||||
"PCI 33 or 66Mhz"
|
||||
};
|
||||
|
||||
#define TESTMODE 0x00000800ul
|
||||
#define IRDY_RST 0x00000200ul
|
||||
#define FRAME_RST 0x00000100ul
|
||||
#define PCI64BIT 0x00000080ul
|
||||
#define MRDCEN 0x00000040ul
|
||||
#define ENDIANSEL 0x00000020ul
|
||||
#define MIXQWENDIANEN 0x00000008ul
|
||||
#define DACEN 0x00000004ul
|
||||
#define STPWLEVEL 0x00000002ul
|
||||
#define QWENDIANSEL 0x00000001ul
|
||||
|
||||
#define DEVCONFIG1 0x44
|
||||
#define PREQDIS 0x01
|
||||
|
||||
#define CSIZE_LATTIME 0x0c
|
||||
#define CACHESIZE 0x000000fful
|
||||
#define LATTIME 0x0000ff00ul
|
||||
|
||||
static int ahd_check_extport(struct ahd_softc *ahd);
|
||||
static void ahd_configure_termination(struct ahd_softc *ahd,
|
||||
u_int adapter_control);
|
||||
static void ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
|
||||
|
||||
struct ahd_pci_identity *
|
||||
ahd_find_pci_device(ahd_dev_softc_t pci)
|
||||
{
|
||||
uint64_t full_id;
|
||||
uint16_t device;
|
||||
uint16_t vendor;
|
||||
uint16_t subdevice;
|
||||
uint16_t subvendor;
|
||||
struct ahd_pci_identity *entry;
|
||||
u_int i;
|
||||
|
||||
vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
|
||||
device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
|
||||
subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
|
||||
subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
|
||||
full_id = ahd_compose_id(device,
|
||||
vendor,
|
||||
subdevice,
|
||||
subvendor);
|
||||
|
||||
for (i = 0; i < ahd_num_pci_devs; i++) {
|
||||
entry = &ahd_pci_ident_table[i];
|
||||
if (entry->full_id == (full_id & entry->id_mask)) {
|
||||
/* Honor exclusion entries. */
|
||||
if (entry->name == NULL)
|
||||
return (NULL);
|
||||
return (entry);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
int
|
||||
ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
|
||||
{
|
||||
struct scb_data *shared_scb_data;
|
||||
u_long l;
|
||||
u_long s;
|
||||
u_int command;
|
||||
uint32_t devconfig;
|
||||
uint16_t subvendor;
|
||||
int error;
|
||||
|
||||
shared_scb_data = NULL;
|
||||
error = entry->setup(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahd->description = entry->name;
|
||||
devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
|
||||
if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) {
|
||||
ahd->chip |= AHD_PCI;
|
||||
/* Disable PCIX workarounds when running in PCI mode. */
|
||||
ahd->bugs &= ~AHD_PCIX_BUG_MASK;
|
||||
} else {
|
||||
ahd->chip |= AHD_PCIX;
|
||||
}
|
||||
ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)];
|
||||
|
||||
/*
|
||||
* Record if this is a Compaq board.
|
||||
*/
|
||||
subvendor = ahd_pci_read_config(ahd->dev_softc,
|
||||
PCIR_SUBVEND_0, /*bytes*/2);
|
||||
if (subvendor == SUBID_CPQ)
|
||||
ahd->flags |= AHD_CPQ_BOARD;
|
||||
|
||||
ahd_power_state_change(ahd, AHD_POWER_STATE_D0);
|
||||
|
||||
error = ahd_pci_map_registers(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* If we need to support high memory, enable dual
|
||||
* address cycles. This bit must be set to enable
|
||||
* high address bit generation even if we are on a
|
||||
* 64bit bus (PCI64BIT set in devconfig).
|
||||
*/
|
||||
if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
|
||||
uint32_t devconfig;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Enabling 39Bit Addressing\n",
|
||||
ahd_name(ahd));
|
||||
devconfig = ahd_pci_read_config(ahd->dev_softc,
|
||||
DEVCONFIG, /*bytes*/4);
|
||||
devconfig |= DACEN;
|
||||
ahd_pci_write_config(ahd->dev_softc, DEVCONFIG,
|
||||
devconfig, /*bytes*/4);
|
||||
}
|
||||
|
||||
/* Ensure busmastering is enabled */
|
||||
command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1);
|
||||
command |= PCIM_CMD_BUSMASTEREN;
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
|
||||
|
||||
error = ahd_softc_init(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahd->bus_intr = ahd_pci_intr;
|
||||
|
||||
error = ahd_reset(ahd);
|
||||
if (error != 0)
|
||||
return (ENXIO);
|
||||
|
||||
ahd->pci_cachesize =
|
||||
ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME,
|
||||
/*bytes*/1) & CACHESIZE;
|
||||
ahd->pci_cachesize *= 4;
|
||||
|
||||
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
|
||||
/* See if we have a SEEPROM and perform auto-term */
|
||||
error = ahd_check_extport(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/* Core initialization */
|
||||
error = ahd_init(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
/*
|
||||
* Allow interrupts now that we are completely setup.
|
||||
*/
|
||||
error = ahd_pci_map_int(ahd);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahd_list_lock(&l);
|
||||
/*
|
||||
* Link this softc in with all other ahd instances.
|
||||
*/
|
||||
ahd_softc_insert(ahd);
|
||||
|
||||
ahd_lock(ahd, &s);
|
||||
ahd_intr_enable(ahd, TRUE);
|
||||
ahd_unlock(ahd, &s);
|
||||
|
||||
ahd_list_unlock(&l);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the external port logic for a serial eeprom
|
||||
* and termination/cable detection contrls.
|
||||
*/
|
||||
static int
|
||||
ahd_check_extport(struct ahd_softc *ahd)
|
||||
{
|
||||
struct seeprom_config *sc;
|
||||
u_int adapter_control;
|
||||
int have_seeprom;
|
||||
int error;
|
||||
|
||||
sc = ahd->seep_config;
|
||||
have_seeprom = ahd_acquire_seeprom(ahd);
|
||||
if (have_seeprom) {
|
||||
u_int start_addr;
|
||||
|
||||
if (bootverbose)
|
||||
printf("%s: Reading SEEPROM...", ahd_name(ahd));
|
||||
|
||||
/* Address is always in units of 16bit words */
|
||||
start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
|
||||
|
||||
error = ahd_read_seeprom(ahd, (uint16_t *)sc,
|
||||
start_addr, sizeof(*sc)/2);
|
||||
|
||||
if (error != 0) {
|
||||
printf("Unable to read SEEPROM\n");
|
||||
have_seeprom = 0;
|
||||
} else {
|
||||
have_seeprom = ahd_verify_cksum(sc);
|
||||
|
||||
if (bootverbose) {
|
||||
if (have_seeprom == 0)
|
||||
printf ("checksum error\n");
|
||||
else
|
||||
printf ("done.\n");
|
||||
}
|
||||
}
|
||||
ahd_release_seeprom(ahd);
|
||||
}
|
||||
|
||||
if (!have_seeprom) {
|
||||
u_int nvram_scb;
|
||||
|
||||
/*
|
||||
* Pull scratch ram settings and treat them as
|
||||
* if they are the contents of an seeprom if
|
||||
* the 'ADPT', 'BIOS', or 'ASPI' signature is found
|
||||
* in SCB 0xFF. We manually compose the data as 16bit
|
||||
* values to avoid endian issues.
|
||||
*/
|
||||
ahd_set_scbptr(ahd, 0xFF);
|
||||
nvram_scb = ahd_inb_scbram(ahd, SCB_BASE + NVRAM_SCB_OFFSET);
|
||||
printf("nvram_scb == 0x%x\n", nvram_scb);
|
||||
printf("SCBPTR == 0x%x\n", ahd_get_scbptr(ahd));
|
||||
printf("Signature = %c%c%c%c\n",
|
||||
ahd_inb_scbram(ahd, SCB_BASE + 0),
|
||||
ahd_inb_scbram(ahd, SCB_BASE + 1),
|
||||
ahd_inb_scbram(ahd, SCB_BASE + 2),
|
||||
ahd_inb_scbram(ahd, SCB_BASE + 3));
|
||||
if (nvram_scb != 0xFF
|
||||
&& ((ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 1) == 'D'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 3) == 'T')
|
||||
|| (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'B'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 1) == 'I'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 2) == 'O'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 3) == 'S')
|
||||
|| (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 1) == 'S'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
|
||||
&& ahd_inb_scbram(ahd, SCB_BASE + 3) == 'I'))) {
|
||||
uint16_t *sc_data;
|
||||
int i;
|
||||
|
||||
ahd_set_scbptr(ahd, nvram_scb);
|
||||
sc_data = (uint16_t *)sc;
|
||||
for (i = 0; i < 64; i += 2)
|
||||
*sc_data++ = ahd_inw_scbram(ahd, SCB_BASE+i);
|
||||
have_seeprom = ahd_verify_cksum(sc);
|
||||
if (have_seeprom)
|
||||
ahd->flags |= AHD_SCB_CONFIG_USED;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef AHD_DEBUG
|
||||
if (have_seeprom != 0
|
||||
&& (ahd_debug & AHD_DUMP_SEEPROM) != 0) {
|
||||
uint8_t *sc_data;
|
||||
int i;
|
||||
|
||||
printf("%s: Seeprom Contents:", ahd_name(ahd));
|
||||
sc_data = (uint8_t *)sc;
|
||||
for (i = 0; i < (sizeof(*sc)); i += 2)
|
||||
printf("\n\t0x%.4x",
|
||||
sc_data[i] | (sc_data[i+1] << 8));
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!have_seeprom) {
|
||||
if (bootverbose)
|
||||
printf("%s: No SEEPROM available.\n", ahd_name(ahd));
|
||||
ahd->flags |= AHD_USEDEFAULTS;
|
||||
error = ahd_default_config(ahd);
|
||||
adapter_control = CFAUTOTERM|CFSEAUTOTERM;
|
||||
free(ahd->seep_config, M_DEVBUF);
|
||||
ahd->seep_config = NULL;
|
||||
} else {
|
||||
error = ahd_parse_cfgdata(ahd, sc);
|
||||
adapter_control = sc->adapter_control;
|
||||
}
|
||||
if (error != 0)
|
||||
return (error);
|
||||
|
||||
ahd_configure_termination(ahd, adapter_control);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
|
||||
{
|
||||
int error;
|
||||
u_int sxfrctl1;
|
||||
uint8_t termctl;
|
||||
uint32_t devconfig;
|
||||
|
||||
devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
|
||||
devconfig &= ~STPWLEVEL;
|
||||
if ((ahd->flags & AHD_STPWLEVEL_A) != 0) {
|
||||
devconfig |= STPWLEVEL;
|
||||
}
|
||||
ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
|
||||
|
||||
/* Make sure current sensing is off. */
|
||||
if ((ahd->flags & AHD_CURRENT_SENSING) != 0) {
|
||||
(void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read to sense. Write to set.
|
||||
*/
|
||||
error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
|
||||
if ((adapter_control & CFAUTOTERM) == 0) {
|
||||
if (bootverbose)
|
||||
printf("%s: Manual Primary Termination\n",
|
||||
ahd_name(ahd));
|
||||
termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
|
||||
if ((adapter_control & CFSTERM) != 0)
|
||||
termctl |= FLX_TERMCTL_ENPRILOW;
|
||||
if ((adapter_control & CFWSTERM) != 0)
|
||||
termctl |= FLX_TERMCTL_ENPRIHIGH;
|
||||
} else if (error != 0) {
|
||||
printf("%s: Primary Auto-Term Sensing failed! "
|
||||
"Using Defaults.\n", ahd_name(ahd));
|
||||
termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
|
||||
}
|
||||
|
||||
if ((adapter_control & CFSEAUTOTERM) == 0) {
|
||||
if (bootverbose)
|
||||
printf("%s: Manual Secondary Termination\n",
|
||||
ahd_name(ahd));
|
||||
termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
|
||||
if ((adapter_control & CFSELOWTERM) != 0)
|
||||
termctl |= FLX_TERMCTL_ENSECLOW;
|
||||
if ((adapter_control & CFSEHIGHTERM) != 0)
|
||||
termctl |= FLX_TERMCTL_ENSECHIGH;
|
||||
} else if (error != 0) {
|
||||
printf("%s: Secondary Auto-Term Sensing failed! "
|
||||
"Using Defaults.\n", ahd_name(ahd));
|
||||
termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now set the termination based on what we found.
|
||||
*/
|
||||
sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN;
|
||||
if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) {
|
||||
ahd->flags |= AHD_TERM_ENB_A;
|
||||
sxfrctl1 |= STPWEN;
|
||||
}
|
||||
/* Must set the latch once in order to be effective. */
|
||||
ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
|
||||
ahd_outb(ahd, SXFRCTL1, sxfrctl1);
|
||||
|
||||
error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
|
||||
if (error != 0) {
|
||||
printf("%s: Unable to set termination settings!\n",
|
||||
ahd_name(ahd));
|
||||
} else if (bootverbose) {
|
||||
printf("%s: Primary High byte termination %sabled\n",
|
||||
ahd_name(ahd),
|
||||
(termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
|
||||
|
||||
printf("%s: Primary Low byte termination %sabled\n",
|
||||
ahd_name(ahd),
|
||||
(termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
|
||||
|
||||
printf("%s: Secondary High byte termination %sabled\n",
|
||||
ahd_name(ahd),
|
||||
(termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
|
||||
|
||||
printf("%s: Secondary Low byte termination %sabled\n",
|
||||
ahd_name(ahd),
|
||||
(termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#define DPE 0x80
|
||||
#define SSE 0x40
|
||||
#define RMA 0x20
|
||||
#define RTA 0x10
|
||||
#define STA 0x08
|
||||
#define DPR 0x01
|
||||
|
||||
static const char *split_status_source[] =
|
||||
{
|
||||
"DFF0",
|
||||
"DFF1",
|
||||
"OVLY",
|
||||
"CMC",
|
||||
};
|
||||
|
||||
static const char *pci_status_source[] =
|
||||
{
|
||||
"DFF0",
|
||||
"DFF1",
|
||||
"SG",
|
||||
"CMC",
|
||||
"OVLY",
|
||||
"NONE",
|
||||
"MSI",
|
||||
"TARG"
|
||||
};
|
||||
|
||||
static const char *split_status_strings[] =
|
||||
{
|
||||
"%s: Received split response in %s.\n"
|
||||
"%s: Received split completion error message in %s\n",
|
||||
"%s: Receive overrun in %s\n",
|
||||
"%s: Count not complete in %s\n",
|
||||
"%s: Split completion data bucket in %s\n",
|
||||
"%s: Split completion address error in %s\n",
|
||||
"%s: Split completion byte count error in %s\n",
|
||||
"%s: Signaled Target-abort to early terminate a split in %s\n",
|
||||
};
|
||||
|
||||
static const char *pci_status_strings[] =
|
||||
{
|
||||
"%s: Data Parity Error has been reported via PERR# in %s\n",
|
||||
"%s: Target initial wait state error in %s\n",
|
||||
"%s: Split completion read data parity error in %s\n",
|
||||
"%s: Split completion address attribute parity error in %s\n",
|
||||
"%s: Received a Target Abort in %s\n",
|
||||
"%s: Received a Master Abort in %s\n",
|
||||
"%s: Signal System Error Detected in %s\n",
|
||||
"%s: Address or Write Phase Parity Error Detected in %s.\n"
|
||||
};
|
||||
|
||||
void
|
||||
ahd_pci_intr(struct ahd_softc *ahd)
|
||||
{
|
||||
uint8_t pci_status[8];
|
||||
ahd_mode_state saved_modes;
|
||||
u_int pci_status1;
|
||||
u_int intstat;
|
||||
u_int i;
|
||||
u_int reg;
|
||||
|
||||
intstat = ahd_inb(ahd, INTSTAT);
|
||||
|
||||
if ((intstat & SPLTINT) != 0)
|
||||
ahd_pci_split_intr(ahd, intstat);
|
||||
|
||||
if ((intstat & PCIINT) == 0)
|
||||
return;
|
||||
|
||||
printf("%s: PCI error Interrupt\n", ahd_name(ahd));
|
||||
saved_modes = ahd_save_modes(ahd);
|
||||
ahd_dump_card_state(ahd);
|
||||
ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
|
||||
for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) {
|
||||
|
||||
if (i == 5)
|
||||
continue;
|
||||
pci_status[i] = ahd_inb(ahd, reg);
|
||||
/* Clear latched errors. So our interupt deasserts. */
|
||||
ahd_outb(ahd, reg, pci_status[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
u_int bit;
|
||||
|
||||
if (i == 5)
|
||||
continue;
|
||||
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
|
||||
if ((pci_status[i] & (0x1 << bit)) != 0) {
|
||||
static const char *s;
|
||||
|
||||
s = pci_status_strings[bit];
|
||||
if (i == 7/*TARG*/ && bit == 3)
|
||||
s = "%s: Signal Target Abort\n";
|
||||
printf(s, ahd_name(ahd), pci_status_source[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
pci_status1 = ahd_pci_read_config(ahd->dev_softc,
|
||||
PCIR_STATUS + 1, /*bytes*/1);
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
|
||||
pci_status1, /*bytes*/1);
|
||||
ahd_restore_modes(ahd, saved_modes);
|
||||
ahd_unpause(ahd);
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
|
||||
{
|
||||
uint8_t split_status[4];
|
||||
uint8_t split_status1[4];
|
||||
uint8_t sg_split_status[2];
|
||||
uint8_t sg_split_status1[2];
|
||||
ahd_mode_state saved_modes;
|
||||
u_int i;
|
||||
uint16_t pcix_status;
|
||||
|
||||
/*
|
||||
* Check for splits in all modes. Modes 0 and 1
|
||||
* additionally have SG engine splits to look at.
|
||||
*/
|
||||
pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS,
|
||||
/*bytes*/2);
|
||||
printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
|
||||
ahd_name(ahd), pcix_status);
|
||||
saved_modes = ahd_save_modes(ahd);
|
||||
for (i = 0; i < 4; i++) {
|
||||
ahd_set_modes(ahd, i, i);
|
||||
|
||||
split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0);
|
||||
split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1);
|
||||
/* Clear latched errors. So our interupt deasserts. */
|
||||
ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]);
|
||||
ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]);
|
||||
if (i != 0)
|
||||
continue;
|
||||
sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0);
|
||||
sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1);
|
||||
/* Clear latched errors. So our interupt deasserts. */
|
||||
ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]);
|
||||
ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]);
|
||||
}
|
||||
|
||||
for (i = 0; i < 4; i++) {
|
||||
u_int bit;
|
||||
|
||||
for (bit = 0; bit < 8; bit++) {
|
||||
|
||||
if ((split_status[i] & (0x1 << bit)) != 0) {
|
||||
static const char *s;
|
||||
|
||||
s = split_status_strings[bit];
|
||||
printf(s, ahd_name(ahd),
|
||||
split_status_source[i]);
|
||||
}
|
||||
|
||||
if (i != 0)
|
||||
continue;
|
||||
|
||||
if ((sg_split_status[i] & (0x1 << bit)) != 0) {
|
||||
static const char *s;
|
||||
|
||||
s = split_status_strings[bit];
|
||||
printf(s, ahd_name(ahd), "SG");
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Clear PCI-X status bits.
|
||||
*/
|
||||
ahd_pci_write_config(ahd->dev_softc, PCIXR_STATUS,
|
||||
pcix_status, /*bytes*/2);
|
||||
ahd_restore_modes(ahd, saved_modes);
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_aic7901_setup(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_dev_softc_t pci;
|
||||
|
||||
pci = ahd->dev_softc;
|
||||
ahd->channel = 'A';
|
||||
ahd->chip = AHD_AIC7901;
|
||||
ahd->features = AHD_AIC7901_FE;
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_aic7902_setup(struct ahd_softc *ahd)
|
||||
{
|
||||
ahd_dev_softc_t pci;
|
||||
u_int rev;
|
||||
u_int devconfig1;
|
||||
|
||||
pci = ahd->dev_softc;
|
||||
rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
|
||||
if (rev < ID_AIC7902_PCI_REV_A3) {
|
||||
printf("%s: Unable to attach to unsupported chip revision %d\n",
|
||||
ahd_name(ahd), rev);
|
||||
ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/1);
|
||||
return (ENXIO);
|
||||
}
|
||||
if (rev < ID_AIC7902_PCI_REV_B0) {
|
||||
/*
|
||||
* Pending request assertion does not work on the A if we have
|
||||
* DMA requests outstanding on both channels. See H2A3 Razors
|
||||
* #327 and #365.
|
||||
*/
|
||||
devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
|
||||
ahd_pci_write_config(pci, DEVCONFIG1,
|
||||
devconfig1|PREQDIS, /*bytes*/1);
|
||||
devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
|
||||
/*
|
||||
* Enable A series workarounds.
|
||||
*/
|
||||
ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG
|
||||
| AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG
|
||||
| AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG
|
||||
| AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG
|
||||
| AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG
|
||||
| AHD_PCIX_CHIPRST_BUG|AHD_PKTIZED_STATUS_BUG;
|
||||
if (rev < ID_AIC7902_PCI_REV_A4)
|
||||
ahd->bugs |= AHD_PCIX_ARBITER_BUG|AHD_PCIX_SPLIT_BUG;
|
||||
}
|
||||
|
||||
ahd->channel = ahd_get_pci_function(pci) + 'A';
|
||||
ahd->chip = AHD_AIC7902;
|
||||
ahd->features = AHD_AIC7902_FE;
|
||||
return (0);
|
||||
}
|
||||
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
|
||||
* sym driver.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#7 $
|
||||
*/
|
||||
#include "aic79xx_osm.h"
|
||||
#include "aic79xx_inline.h"
|
||||
|
||||
static void copy_mem_info(struct info_str *info, char *data, int len);
|
||||
static int copy_info(struct info_str *info, char *fmt, ...);
|
||||
static u_int scsi_calc_syncsrate(u_int period_factor);
|
||||
static void ahd_dump_target_state(struct ahd_softc *ahd,
|
||||
struct info_str *info,
|
||||
u_int our_id, char channel,
|
||||
u_int target_id, u_int target_offset);
|
||||
static void ahd_dump_device_state(struct info_str *info,
|
||||
struct ahd_linux_device *dev);
|
||||
static int ahd_proc_write_seeprom(struct ahd_softc *ahd,
|
||||
char *buffer, int length);
|
||||
|
||||
static void
|
||||
copy_mem_info(struct info_str *info, char *data, int len)
|
||||
{
|
||||
if (info->pos + len > info->offset + info->length)
|
||||
len = info->offset + info->length - info->pos;
|
||||
|
||||
if (info->pos + len < info->offset) {
|
||||
info->pos += len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->pos < info->offset) {
|
||||
off_t partial;
|
||||
|
||||
partial = info->offset - info->pos;
|
||||
data += partial;
|
||||
info->pos += partial;
|
||||
len -= partial;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(info->buffer, data, len);
|
||||
info->pos += len;
|
||||
info->buffer += len;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
copy_info(struct info_str *info, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[256];
|
||||
int len;
|
||||
|
||||
va_start(args, fmt);
|
||||
len = vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
copy_mem_info(info, buf, len);
|
||||
return (len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of syncrates that don't follow the "divisible by 4"
|
||||
* rule. This table will be expanded in future SCSI specs.
|
||||
*/
|
||||
static struct {
|
||||
u_int period_factor;
|
||||
u_int period; /* in 100ths of ns */
|
||||
} scsi_syncrates[] = {
|
||||
{ 0x08, 625 }, /* FAST-160 */
|
||||
{ 0x09, 1250 }, /* FAST-80 */
|
||||
{ 0x0a, 2500 }, /* FAST-40 40MHz */
|
||||
{ 0x0b, 3030 }, /* FAST-40 33MHz */
|
||||
{ 0x0c, 5000 } /* FAST-20 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the frequency in kHz corresponding to the given
|
||||
* sync period factor.
|
||||
*/
|
||||
static u_int
|
||||
scsi_calc_syncsrate(u_int period_factor)
|
||||
{
|
||||
int i;
|
||||
int num_syncrates;
|
||||
|
||||
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
|
||||
/* See if the period is in the "exception" table */
|
||||
for (i = 0; i < num_syncrates; i++) {
|
||||
|
||||
if (period_factor == scsi_syncrates[i].period_factor) {
|
||||
/* Period in kHz */
|
||||
return (100000000 / scsi_syncrates[i].period);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wasn't in the table, so use the standard
|
||||
* 4 times conversion.
|
||||
*/
|
||||
return (10000000 / (period_factor * 4 * 10));
|
||||
}
|
||||
|
||||
void
|
||||
ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
|
||||
{
|
||||
u_int speed;
|
||||
u_int freq;
|
||||
u_int mb;
|
||||
|
||||
speed = 3300;
|
||||
freq = 0;
|
||||
if (tinfo->offset != 0) {
|
||||
freq = scsi_calc_syncsrate(tinfo->period);
|
||||
speed = freq;
|
||||
}
|
||||
speed *= (0x01 << tinfo->width);
|
||||
mb = speed / 1000;
|
||||
if (mb > 0)
|
||||
copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
|
||||
else
|
||||
copy_info(info, "%dKB/s transfers", speed);
|
||||
|
||||
if (freq != 0) {
|
||||
copy_info(info, " (%d.%03dMHz%s, offset %d",
|
||||
freq / 1000, freq % 1000,
|
||||
(tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
|
||||
? " DT" : "", tinfo->offset);
|
||||
}
|
||||
|
||||
if (tinfo->width > 0) {
|
||||
if (freq != 0) {
|
||||
copy_info(info, ", ");
|
||||
} else {
|
||||
copy_info(info, " (");
|
||||
}
|
||||
copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
|
||||
} else if (freq != 0) {
|
||||
copy_info(info, ")");
|
||||
}
|
||||
copy_info(info, "\n");
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
|
||||
u_int our_id, char channel, u_int target_id,
|
||||
u_int target_offset)
|
||||
{
|
||||
struct ahd_linux_target *targ;
|
||||
struct ahd_initiator_tinfo *tinfo;
|
||||
struct ahd_tmode_tstate *tstate;
|
||||
int lun;
|
||||
|
||||
tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
|
||||
target_id, &tstate);
|
||||
copy_info(info, "Channel %c Target %d Negotiation Settings\n",
|
||||
channel, target_id);
|
||||
copy_info(info, "\tUser: ");
|
||||
ahd_format_transinfo(info, &tinfo->user);
|
||||
targ = ahd->platform_data->targets[target_offset];
|
||||
if (targ == NULL)
|
||||
return;
|
||||
|
||||
copy_info(info, "\tGoal: ");
|
||||
ahd_format_transinfo(info, &tinfo->goal);
|
||||
copy_info(info, "\tCurr: ");
|
||||
ahd_format_transinfo(info, &tinfo->curr);
|
||||
|
||||
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
|
||||
struct ahd_linux_device *dev;
|
||||
|
||||
dev = targ->devices[lun];
|
||||
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
|
||||
ahd_dump_device_state(info, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev)
|
||||
{
|
||||
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
|
||||
dev->target->channel + 'A', dev->target->target, dev->lun);
|
||||
|
||||
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
|
||||
copy_info(info, "\t\tCommands Active %d\n", dev->active);
|
||||
copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
|
||||
copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
|
||||
copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
|
||||
}
|
||||
|
||||
static int
|
||||
ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
|
||||
{
|
||||
ahd_mode_state saved_modes;
|
||||
int have_seeprom;
|
||||
u_long s;
|
||||
int paused;
|
||||
int written;
|
||||
|
||||
/* Default to failure. */
|
||||
written = -EINVAL;
|
||||
ahd_lock(ahd, &s);
|
||||
paused = ahd_is_paused(ahd);
|
||||
if (!paused)
|
||||
ahd_pause(ahd);
|
||||
|
||||
saved_modes = ahd_save_modes(ahd);
|
||||
ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
|
||||
if (length != sizeof(struct seeprom_config)) {
|
||||
printf("ahd_proc_write_seeprom: incorrect buffer size\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
|
||||
if (have_seeprom == 0) {
|
||||
printf("ahd_proc_write_seeprom: cksum verification failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
have_seeprom = ahd_acquire_seeprom(ahd);
|
||||
if (!have_seeprom) {
|
||||
printf("ahd_proc_write_seeprom: No Serial EEPROM\n");
|
||||
goto done;
|
||||
} else {
|
||||
u_int start_addr;
|
||||
|
||||
if (ahd->seep_config == NULL) {
|
||||
ahd->seep_config = malloc(sizeof(*ahd->seep_config),
|
||||
M_DEVBUF, M_NOWAIT);
|
||||
if (ahd->seep_config == NULL) {
|
||||
printf("aic79xx: Unable to allocate serial "
|
||||
"eeprom buffer. Write failing\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
printf("aic79xx: Writing Serial EEPROM\n");
|
||||
start_addr = 32 * (ahd->channel - 'A');
|
||||
ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
|
||||
sizeof(struct seeprom_config)/2);
|
||||
ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config,
|
||||
start_addr, sizeof(struct seeprom_config)/2);
|
||||
ahd_release_seeprom(ahd);
|
||||
written = length;
|
||||
}
|
||||
|
||||
done:
|
||||
ahd_restore_modes(ahd, saved_modes);
|
||||
if (!paused)
|
||||
ahd_unpause(ahd);
|
||||
ahd_unlock(ahd, &s);
|
||||
return (written);
|
||||
}
|
||||
/*
|
||||
* Return information to handle /proc support for the driver.
|
||||
*/
|
||||
int
|
||||
ahd_linux_proc_info(char *buffer, char **start, off_t offset,
|
||||
int length, int hostno, int inout)
|
||||
{
|
||||
struct ahd_softc *ahd;
|
||||
struct info_str info;
|
||||
char ahd_info[256];
|
||||
u_long l;
|
||||
u_int max_targ;
|
||||
u_int i;
|
||||
int retval;
|
||||
|
||||
retval = -EINVAL;
|
||||
ahd_list_lock(&l);
|
||||
TAILQ_FOREACH(ahd, &ahd_tailq, links) {
|
||||
if (ahd->platform_data->host->host_no == hostno)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ahd == NULL)
|
||||
goto done;
|
||||
|
||||
/* Has data been written to the file? */
|
||||
if (inout == TRUE) {
|
||||
retval = ahd_proc_write_seeprom(ahd, buffer, length);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (start)
|
||||
*start = buffer;
|
||||
|
||||
info.buffer = buffer;
|
||||
info.length = length;
|
||||
info.offset = offset;
|
||||
info.pos = 0;
|
||||
|
||||
copy_info(&info, "Adaptec AIC79xx driver version: %s\n",
|
||||
AIC79XX_DRIVER_VERSION);
|
||||
ahd_controller_info(ahd, ahd_info);
|
||||
copy_info(&info, "%s\n\n", ahd_info);
|
||||
|
||||
if (ahd->seep_config == NULL)
|
||||
copy_info(&info, "No Serial EEPROM\n");
|
||||
else {
|
||||
copy_info(&info, "Serial EEPROM:\n");
|
||||
for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) {
|
||||
if (((i % 8) == 0) && (i != 0)) {
|
||||
copy_info(&info, "\n");
|
||||
}
|
||||
copy_info(&info, "0x%.4x ",
|
||||
((uint16_t*)ahd->seep_config)[i]);
|
||||
}
|
||||
copy_info(&info, "\n");
|
||||
}
|
||||
copy_info(&info, "\n");
|
||||
|
||||
max_targ = 15;
|
||||
if ((ahd->features & AHD_WIDE) == 0)
|
||||
max_targ = 7;
|
||||
|
||||
for (i = 0; i <= max_targ; i++) {
|
||||
|
||||
ahd_dump_target_state(ahd, &info, ahd->our_id, 'A',
|
||||
/*target_id*/i, /*target_offset*/i);
|
||||
}
|
||||
retval = info.pos > info.offset ? info.pos - info.offset : 0;
|
||||
done:
|
||||
ahd_list_unlock(&l);
|
||||
return (retval);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
* DO NOT EDIT - This file is automatically generated
|
||||
* from the following source files:
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#42 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#34 $
|
||||
*/
|
||||
static uint8_t seqprog[] = {
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x60, 0x3a, 0x0c, 0x68,
|
||||
0x04, 0x46, 0x0d, 0x68,
|
||||
0xff, 0x21, 0x0d, 0x70,
|
||||
0x40, 0x4b, 0x16, 0x69,
|
||||
0x00, 0xe2, 0xe0, 0x58,
|
||||
0x40, 0x4b, 0x16, 0x69,
|
||||
0x20, 0x4b, 0x0a, 0x69,
|
||||
0xfc, 0x42, 0x16, 0x78,
|
||||
0x10, 0x40, 0x16, 0x78,
|
||||
0x00, 0xe2, 0xf4, 0x5c,
|
||||
0x20, 0x4d, 0x1a, 0x78,
|
||||
0x00, 0xe2, 0xf4, 0x5c,
|
||||
0x01, 0x52, 0x3c, 0x78,
|
||||
0x02, 0x58, 0x50, 0x31,
|
||||
0xff, 0xea, 0x10, 0x0b,
|
||||
0x08, 0xa8, 0x51, 0x03,
|
||||
0x01, 0xa4, 0x29, 0x78,
|
||||
0x00, 0xe2, 0xc6, 0x5a,
|
||||
0x00, 0xe2, 0x1a, 0x40,
|
||||
0xff, 0xea, 0xd4, 0x19,
|
||||
0x02, 0xa8, 0x82, 0x32,
|
||||
0x00, 0xea, 0xda, 0x58,
|
||||
0x00, 0xe2, 0xe8, 0x5c,
|
||||
0x00, 0xe2, 0x3c, 0x48,
|
||||
0x11, 0xea, 0xda, 0x58,
|
||||
0x00, 0xe2, 0xe8, 0x5c,
|
||||
0x00, 0xe2, 0x3c, 0x48,
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x00, 0xe2, 0xbe, 0x5a,
|
||||
0x00, 0xea, 0xda, 0x58,
|
||||
0x80, 0xf9, 0x42, 0x68,
|
||||
0x00, 0xe2, 0xd8, 0x58,
|
||||
0x11, 0xea, 0xda, 0x58,
|
||||
0x80, 0xf9, 0x48, 0x68,
|
||||
0x00, 0xe2, 0xd8, 0x58,
|
||||
0x00, 0xe2, 0x4c, 0x58,
|
||||
0x00, 0xe2, 0x00, 0x40,
|
||||
0x22, 0xea, 0xda, 0x58,
|
||||
0x18, 0xad, 0x94, 0x78,
|
||||
0x04, 0xad, 0x64, 0x68,
|
||||
0x80, 0xad, 0xa0, 0x7c,
|
||||
0x10, 0xad, 0x58, 0x78,
|
||||
0xe7, 0xad, 0x5a, 0x0d,
|
||||
0xe7, 0xad, 0x5a, 0x09,
|
||||
0x02, 0xea, 0x02, 0x00,
|
||||
0xff, 0xea, 0x56, 0x02,
|
||||
0x04, 0x7c, 0x76, 0x32,
|
||||
0x20, 0x16, 0xa0, 0x7c,
|
||||
0x04, 0x37, 0x77, 0x36,
|
||||
0x40, 0xad, 0xa0, 0x7c,
|
||||
0xe7, 0xad, 0x5a, 0x09,
|
||||
0x02, 0xa8, 0x40, 0x31,
|
||||
0x04, 0x94, 0x49, 0x32,
|
||||
0xff, 0xea, 0x2a, 0x03,
|
||||
0xff, 0xea, 0x2e, 0x03,
|
||||
0x10, 0xa8, 0x85, 0x68,
|
||||
0x3d, 0xa9, 0xc5, 0x29,
|
||||
0xfe, 0xe2, 0xc4, 0x09,
|
||||
0x01, 0xea, 0xc6, 0x01,
|
||||
0x02, 0xe2, 0xc8, 0x31,
|
||||
0x02, 0xec, 0x50, 0x31,
|
||||
0x02, 0xa0, 0xda, 0x31,
|
||||
0xff, 0xa9, 0x84, 0x70,
|
||||
0x02, 0xa0, 0x28, 0x33,
|
||||
0x01, 0x10, 0xd4, 0x35,
|
||||
0xff, 0x21, 0x8f, 0x70,
|
||||
0x02, 0x22, 0x51, 0x31,
|
||||
0x02, 0xa0, 0x2c, 0x33,
|
||||
0x02, 0xa0, 0x44, 0x32,
|
||||
0x01, 0x10, 0xd4, 0x35,
|
||||
0x02, 0xa0, 0x40, 0x32,
|
||||
0x02, 0xa0, 0x44, 0x32,
|
||||
0x01, 0x10, 0xd4, 0x35,
|
||||
0x04, 0x46, 0x99, 0x68,
|
||||
0x40, 0x16, 0xbc, 0x68,
|
||||
0xff, 0x2d, 0xc1, 0x60,
|
||||
0xff, 0x29, 0xa1, 0x74,
|
||||
0x02, 0x28, 0x55, 0x32,
|
||||
0x01, 0xea, 0x5a, 0x01,
|
||||
0x04, 0x3b, 0xf9, 0x30,
|
||||
0x02, 0x28, 0x61, 0x31,
|
||||
0x02, 0x28, 0x51, 0x31,
|
||||
0x00, 0xe2, 0xac, 0x40,
|
||||
0x02, 0x8c, 0x61, 0x31,
|
||||
0x02, 0x8c, 0x51, 0x31,
|
||||
0x01, 0x14, 0xd4, 0x31,
|
||||
0xff, 0x8d, 0xb5, 0x70,
|
||||
0x80, 0xac, 0xb4, 0x70,
|
||||
0x20, 0x16, 0xa8, 0x78,
|
||||
0x01, 0xac, 0x08, 0x31,
|
||||
0x09, 0xea, 0x5a, 0x01,
|
||||
0x02, 0x8c, 0x51, 0x32,
|
||||
0xff, 0xea, 0x1a, 0x07,
|
||||
0x04, 0x24, 0xf9, 0x30,
|
||||
0x1d, 0xea, 0xcc, 0x40,
|
||||
0x02, 0x2c, 0x51, 0x31,
|
||||
0x04, 0xac, 0xf9, 0x30,
|
||||
0x19, 0xea, 0xcc, 0x58,
|
||||
0x02, 0x8c, 0x59, 0x32,
|
||||
0x02, 0x28, 0x19, 0x33,
|
||||
0x02, 0xa8, 0x50, 0x36,
|
||||
0x30, 0xea, 0x08, 0x01,
|
||||
0x01, 0xe2, 0x5a, 0x31,
|
||||
0x01, 0x46, 0x8d, 0x06,
|
||||
0x02, 0xa8, 0xf4, 0x31,
|
||||
0x02, 0xf2, 0xf0, 0x35,
|
||||
0x02, 0xf2, 0xf0, 0x31,
|
||||
0x02, 0xf8, 0xe4, 0x35,
|
||||
0x80, 0xea, 0xb2, 0x01,
|
||||
0x01, 0xe2, 0x00, 0x30,
|
||||
0xff, 0xea, 0xb2, 0x0d,
|
||||
0x02, 0x20, 0xbd, 0x30,
|
||||
0x02, 0x20, 0xb9, 0x30,
|
||||
0x02, 0x20, 0x51, 0x31,
|
||||
0x4c, 0xa9, 0xd7, 0x28,
|
||||
0x10, 0xa8, 0xef, 0x78,
|
||||
0x01, 0x6b, 0xc0, 0x30,
|
||||
0x02, 0x64, 0xc8, 0x00,
|
||||
0x40, 0x3a, 0x74, 0x04,
|
||||
0x00, 0xea, 0xda, 0x58,
|
||||
0x80, 0xf9, 0xf6, 0x68,
|
||||
0x00, 0xe2, 0xd8, 0x58,
|
||||
0x11, 0xea, 0xda, 0x58,
|
||||
0x80, 0xf9, 0xfc, 0x68,
|
||||
0x00, 0xe2, 0xd8, 0x58,
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x30, 0x3f, 0xc0, 0x09,
|
||||
0x30, 0xe0, 0xf0, 0x60,
|
||||
0x02, 0xa8, 0x82, 0x32,
|
||||
0x01, 0x3f, 0x7e, 0x00,
|
||||
0x11, 0xea, 0xda, 0x58,
|
||||
0x02, 0x41, 0x51, 0x35,
|
||||
0x08, 0x3c, 0x78, 0x00,
|
||||
0xf0, 0x49, 0x68, 0x0a,
|
||||
0x0f, 0x67, 0xc0, 0x09,
|
||||
0x00, 0x34, 0x69, 0x02,
|
||||
0x20, 0xea, 0x96, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x40, 0x3a, 0x32, 0x69,
|
||||
0x02, 0x55, 0x00, 0x68,
|
||||
0x02, 0x56, 0x32, 0x69,
|
||||
0xff, 0x5b, 0x32, 0x61,
|
||||
0x02, 0x20, 0x51, 0x31,
|
||||
0x80, 0xea, 0xb2, 0x01,
|
||||
0x44, 0xea, 0x00, 0x00,
|
||||
0x01, 0x33, 0xc0, 0x31,
|
||||
0x33, 0xea, 0x00, 0x00,
|
||||
0xff, 0xea, 0xb2, 0x09,
|
||||
0xff, 0xe0, 0xc0, 0x19,
|
||||
0xff, 0xe0, 0x34, 0x79,
|
||||
0x02, 0x94, 0x51, 0x31,
|
||||
0x00, 0xe2, 0x2a, 0x41,
|
||||
0x02, 0x5e, 0x50, 0x31,
|
||||
0x02, 0xa8, 0xb8, 0x30,
|
||||
0x02, 0x5c, 0x50, 0x31,
|
||||
0xff, 0x95, 0x45, 0x71,
|
||||
0x02, 0x94, 0x41, 0x31,
|
||||
0x02, 0x22, 0x51, 0x31,
|
||||
0x02, 0xa0, 0x2c, 0x33,
|
||||
0x02, 0xa0, 0x44, 0x32,
|
||||
0x00, 0xe2, 0x4e, 0x41,
|
||||
0x10, 0xa8, 0x4f, 0x69,
|
||||
0x3d, 0xa9, 0xc9, 0x29,
|
||||
0x01, 0xe4, 0xc8, 0x01,
|
||||
0x01, 0xea, 0xca, 0x01,
|
||||
0xff, 0xea, 0xda, 0x01,
|
||||
0x02, 0x20, 0x51, 0x31,
|
||||
0x02, 0x96, 0x41, 0x32,
|
||||
0xff, 0x21, 0x57, 0x61,
|
||||
0xff, 0xea, 0x46, 0x02,
|
||||
0x02, 0x5c, 0x50, 0x31,
|
||||
0x40, 0xea, 0x96, 0x00,
|
||||
0x02, 0x56, 0xfc, 0x6c,
|
||||
0x01, 0x55, 0xfc, 0x6c,
|
||||
0x10, 0xa8, 0x63, 0x79,
|
||||
0x10, 0x40, 0x64, 0x69,
|
||||
0x01, 0x56, 0x00, 0x68,
|
||||
0xbf, 0x3a, 0x74, 0x08,
|
||||
0x01, 0xa9, 0x69, 0x32,
|
||||
0x01, 0xaa, 0x6b, 0x32,
|
||||
0x08, 0x3c, 0x78, 0x00,
|
||||
0x80, 0xea, 0x62, 0x02,
|
||||
0x40, 0xea, 0x66, 0x02,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0x01, 0x36, 0xc1, 0x31,
|
||||
0x9f, 0xe0, 0xc6, 0x7b,
|
||||
0x80, 0xe0, 0x82, 0x71,
|
||||
0xa0, 0xe0, 0xb4, 0x71,
|
||||
0xc0, 0xe0, 0xa6, 0x71,
|
||||
0xe0, 0xe0, 0xe4, 0x71,
|
||||
0x01, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0xee, 0x00, 0x86, 0x69,
|
||||
0x05, 0xea, 0xb4, 0x00,
|
||||
0x00, 0xe2, 0xfe, 0x58,
|
||||
0xef, 0x90, 0xd5, 0x19,
|
||||
0x00, 0xe2, 0x94, 0x51,
|
||||
0x0b, 0x84, 0xe1, 0x30,
|
||||
0x02, 0xea, 0x36, 0x00,
|
||||
0xa8, 0xea, 0x32, 0x00,
|
||||
0x00, 0xe2, 0x9c, 0x41,
|
||||
0x01, 0x90, 0xd1, 0x30,
|
||||
0x02, 0xea, 0xd2, 0x30,
|
||||
0x10, 0x80, 0x89, 0x31,
|
||||
0x20, 0xea, 0x32, 0x00,
|
||||
0x20, 0x19, 0x9c, 0x69,
|
||||
0xbf, 0x33, 0x67, 0x0a,
|
||||
0x02, 0x4d, 0x70, 0x69,
|
||||
0x40, 0x33, 0x67, 0x02,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x80, 0x33, 0xad, 0x79,
|
||||
0x03, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x01, 0x44, 0x10, 0x33,
|
||||
0x08, 0xa8, 0x51, 0x03,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x10, 0xea, 0x80, 0x00,
|
||||
0x01, 0x31, 0xc5, 0x31,
|
||||
0x80, 0xe2, 0xd0, 0x61,
|
||||
0x10, 0xa8, 0xf5, 0x69,
|
||||
0xc0, 0xaa, 0xc5, 0x01,
|
||||
0x40, 0xa8, 0xc1, 0x69,
|
||||
0xbf, 0xe2, 0xc4, 0x09,
|
||||
0x20, 0xa8, 0xd5, 0x79,
|
||||
0x01, 0xe2, 0x88, 0x30,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0xa0, 0x36, 0xdd, 0x61,
|
||||
0x23, 0xa8, 0x89, 0x08,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0xa0, 0x36, 0xdd, 0x61,
|
||||
0x00, 0xab, 0xd5, 0x41,
|
||||
0xff, 0xe2, 0xd4, 0x61,
|
||||
0x00, 0xe2, 0xf4, 0x41,
|
||||
0x40, 0xea, 0x98, 0x00,
|
||||
0x01, 0xe2, 0x88, 0x30,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0xa0, 0x36, 0xb3, 0x71,
|
||||
0x40, 0xea, 0x98, 0x00,
|
||||
0x01, 0x31, 0x87, 0x32,
|
||||
0x08, 0xea, 0x62, 0x02,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0xe0, 0xea, 0x36, 0x5b,
|
||||
0x80, 0xe0, 0x1a, 0x6a,
|
||||
0x04, 0xe0, 0xd4, 0x72,
|
||||
0x02, 0xe0, 0x0c, 0x73,
|
||||
0x00, 0xea, 0x9a, 0x72,
|
||||
0x03, 0xe0, 0x1c, 0x73,
|
||||
0x23, 0xe0, 0x04, 0x72,
|
||||
0x08, 0xe0, 0x16, 0x72,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0x07, 0xea, 0x04, 0x00,
|
||||
0x08, 0x41, 0x71, 0x71,
|
||||
0x04, 0x41, 0x01, 0x62,
|
||||
0x01, 0x42, 0x89, 0x30,
|
||||
0x00, 0xe2, 0xf4, 0x41,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0x00, 0xe2, 0xf4, 0x41,
|
||||
0x4c, 0x34, 0xc1, 0x28,
|
||||
0x01, 0x64, 0x14, 0x7a,
|
||||
0xa0, 0xea, 0x2e, 0x5b,
|
||||
0x01, 0xa0, 0x14, 0x62,
|
||||
0x01, 0x84, 0x11, 0x7a,
|
||||
0x01, 0xa7, 0x16, 0x7a,
|
||||
0x05, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x07, 0xea, 0x3e, 0x5b,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x4c, 0x34, 0xc5, 0x29,
|
||||
0x3f, 0xe0, 0x6a, 0x0a,
|
||||
0x01, 0x35, 0x51, 0x31,
|
||||
0x3d, 0xe2, 0x52, 0x29,
|
||||
0x07, 0xe2, 0xc4, 0x09,
|
||||
0x11, 0xe2, 0xc4, 0x29,
|
||||
0xb0, 0xe2, 0xc4, 0x19,
|
||||
0x01, 0xea, 0xc6, 0x01,
|
||||
0x02, 0xe2, 0xc8, 0x31,
|
||||
0x02, 0xec, 0x50, 0x31,
|
||||
0xff, 0xa9, 0x36, 0x72,
|
||||
0x20, 0xa8, 0x37, 0x6a,
|
||||
0x04, 0x92, 0x45, 0x31,
|
||||
0x00, 0xe2, 0x70, 0x42,
|
||||
0x80, 0x33, 0x67, 0x02,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0x00, 0xe2, 0x2a, 0x5b,
|
||||
0x01, 0x33, 0x67, 0x02,
|
||||
0xe0, 0x36, 0x97, 0x62,
|
||||
0x02, 0x33, 0x67, 0x02,
|
||||
0x20, 0x46, 0x92, 0x62,
|
||||
0x02, 0xa8, 0x40, 0x31,
|
||||
0xff, 0xea, 0x52, 0x09,
|
||||
0xa8, 0xea, 0x2e, 0x5b,
|
||||
0x01, 0xa8, 0x44, 0x31,
|
||||
0x01, 0xa2, 0xc0, 0x31,
|
||||
0x00, 0xab, 0x59, 0x62,
|
||||
0x01, 0x34, 0xc1, 0x31,
|
||||
0x00, 0xa9, 0x59, 0x62,
|
||||
0x01, 0x35, 0xc1, 0x31,
|
||||
0x00, 0xaa, 0x81, 0x72,
|
||||
0x01, 0xa9, 0x52, 0x11,
|
||||
0xff, 0xa9, 0x4c, 0x6a,
|
||||
0x02, 0xa0, 0x50, 0x31,
|
||||
0xff, 0xea, 0x42, 0x01,
|
||||
0x01, 0xa2, 0xc0, 0x31,
|
||||
0x00, 0xab, 0x6d, 0x72,
|
||||
0x02, 0xa8, 0x40, 0x31,
|
||||
0x02, 0x94, 0x51, 0x31,
|
||||
0xff, 0xa9, 0x62, 0x62,
|
||||
0x00, 0xe2, 0x92, 0x42,
|
||||
0x04, 0x92, 0x45, 0x31,
|
||||
0xff, 0xa1, 0x7a, 0x62,
|
||||
0x4c, 0x34, 0xc5, 0x29,
|
||||
0x01, 0x35, 0x51, 0x31,
|
||||
0x3d, 0xe2, 0x52, 0x29,
|
||||
0x02, 0xa4, 0xda, 0x31,
|
||||
0x00, 0xe2, 0x7e, 0x42,
|
||||
0x02, 0xa0, 0x50, 0x31,
|
||||
0x02, 0xa4, 0x28, 0x33,
|
||||
0x02, 0xa2, 0x50, 0x31,
|
||||
0x10, 0x33, 0x67, 0x02,
|
||||
0x04, 0xa8, 0x93, 0x7a,
|
||||
0xfb, 0xa8, 0x51, 0x0b,
|
||||
0xff, 0xea, 0x66, 0x0a,
|
||||
0x01, 0xa4, 0x8d, 0x6a,
|
||||
0x00, 0xe2, 0xfe, 0x58,
|
||||
0x10, 0xa8, 0x17, 0x7a,
|
||||
0xff, 0xea, 0x3e, 0x5b,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x04, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x04, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0xc0, 0x33, 0xa1, 0x7a,
|
||||
0x03, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x08, 0xa8, 0x9d, 0x7a,
|
||||
0x10, 0xa8, 0xa7, 0x7a,
|
||||
0x0a, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0xbe, 0x5a,
|
||||
0x00, 0xe2, 0xfc, 0x42,
|
||||
0x40, 0x4b, 0xae, 0x6a,
|
||||
0xbf, 0x3a, 0x74, 0x08,
|
||||
0x01, 0xe0, 0xf8, 0x31,
|
||||
0xff, 0xea, 0xc0, 0x09,
|
||||
0x01, 0x2e, 0x5d, 0x1a,
|
||||
0x00, 0x2f, 0x5f, 0x22,
|
||||
0x04, 0x46, 0x8d, 0x02,
|
||||
0x01, 0xfc, 0xc0, 0x35,
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x02, 0x41, 0x51, 0x31,
|
||||
0xff, 0x88, 0xcb, 0x6a,
|
||||
0x01, 0xa4, 0xc7, 0x6a,
|
||||
0x02, 0xa4, 0xcf, 0x6a,
|
||||
0x01, 0x84, 0xcf, 0x7a,
|
||||
0x02, 0x28, 0x19, 0x33,
|
||||
0x02, 0xa8, 0x50, 0x36,
|
||||
0xff, 0x88, 0xcf, 0x72,
|
||||
0x00, 0xe2, 0xaa, 0x5a,
|
||||
0x02, 0x2c, 0x19, 0x33,
|
||||
0x02, 0xa8, 0x58, 0x32,
|
||||
0x04, 0xa4, 0x49, 0x07,
|
||||
0xc0, 0x33, 0xdb, 0x7a,
|
||||
0x03, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x04, 0xa8, 0x51, 0x03,
|
||||
0x20, 0xa8, 0xe3, 0x7a,
|
||||
0x01, 0xab, 0xc1, 0x31,
|
||||
0x00, 0xa8, 0xfc, 0x72,
|
||||
0x02, 0xa8, 0x40, 0x31,
|
||||
0x4c, 0xa9, 0xc5, 0x29,
|
||||
0x01, 0xaa, 0x51, 0x31,
|
||||
0x3d, 0xe2, 0x52, 0x29,
|
||||
0x07, 0xe2, 0xc4, 0x09,
|
||||
0x11, 0xe2, 0xc4, 0x29,
|
||||
0xb0, 0xe2, 0xc4, 0x19,
|
||||
0x01, 0xea, 0xc6, 0x01,
|
||||
0x02, 0xe2, 0xc8, 0x31,
|
||||
0x02, 0xec, 0x44, 0x31,
|
||||
0x02, 0xa0, 0xda, 0x31,
|
||||
0x02, 0xa0, 0x50, 0x31,
|
||||
0x02, 0xa2, 0x28, 0x33,
|
||||
0xf7, 0x57, 0xae, 0x08,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0x00, 0xe2, 0x26, 0x5b,
|
||||
0xee, 0x00, 0x06, 0x6b,
|
||||
0x02, 0xea, 0xb4, 0x00,
|
||||
0x09, 0x4c, 0x06, 0x7b,
|
||||
0x08, 0x4c, 0x00, 0x68,
|
||||
0x0b, 0xea, 0x04, 0x00,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0x20, 0x33, 0x71, 0x79,
|
||||
0x00, 0xe2, 0x14, 0x5b,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x01, 0x84, 0x19, 0x7b,
|
||||
0x01, 0xa4, 0x49, 0x07,
|
||||
0x08, 0x60, 0x30, 0x33,
|
||||
0x08, 0x80, 0x41, 0x37,
|
||||
0xdf, 0x33, 0x67, 0x0a,
|
||||
0xee, 0x00, 0x22, 0x6b,
|
||||
0x05, 0xea, 0xb4, 0x00,
|
||||
0x00, 0xe2, 0xfe, 0x58,
|
||||
0x00, 0xe2, 0x16, 0x42,
|
||||
0x01, 0xea, 0x6c, 0x02,
|
||||
0xc0, 0xea, 0x66, 0x06,
|
||||
0xff, 0x42, 0x2a, 0x7b,
|
||||
0xe0, 0x41, 0x6c, 0x0e,
|
||||
0x01, 0x44, 0xd4, 0x31,
|
||||
0xff, 0x42, 0x30, 0x7b,
|
||||
0xe0, 0x41, 0x6c, 0x0a,
|
||||
0xe0, 0x36, 0x71, 0x61,
|
||||
0xff, 0xea, 0xca, 0x09,
|
||||
0x01, 0xe2, 0xc8, 0x31,
|
||||
0x01, 0x46, 0xda, 0x35,
|
||||
0x01, 0x44, 0xd4, 0x35,
|
||||
0x10, 0xea, 0x80, 0x00,
|
||||
0x01, 0xe2, 0x62, 0x36,
|
||||
0x04, 0xa6, 0xa0, 0x7c,
|
||||
0xff, 0xea, 0x4c, 0x09,
|
||||
0xff, 0xea, 0x5a, 0x0d,
|
||||
0x80, 0xea, 0xb2, 0x01,
|
||||
0x11, 0x00, 0x00, 0x10,
|
||||
0xff, 0xea, 0xb2, 0x0d,
|
||||
0x01, 0x00, 0x60, 0x32,
|
||||
0x02, 0xa6, 0x54, 0x7b,
|
||||
0x00, 0xe2, 0x5e, 0x5b,
|
||||
0x00, 0xe2, 0x48, 0x5b,
|
||||
0x02, 0xa6, 0x5a, 0x7b,
|
||||
0x00, 0xe2, 0x5e, 0x5b,
|
||||
0x00, 0xe2, 0x4c, 0x58,
|
||||
0x00, 0x30, 0xdb, 0x40,
|
||||
0x01, 0xa6, 0x78, 0x6b,
|
||||
0x10, 0xad, 0xa0, 0x7c,
|
||||
0x98, 0xad, 0x70, 0x73,
|
||||
0x08, 0xad, 0xa0, 0x6c,
|
||||
0x00, 0xea, 0x08, 0x81,
|
||||
0x02, 0x84, 0xf9, 0x88,
|
||||
0x03, 0x85, 0xfb, 0x30,
|
||||
0x19, 0xea, 0x5a, 0x01,
|
||||
0x04, 0xa6, 0x4c, 0x05,
|
||||
0x04, 0xa6, 0xa0, 0x7c,
|
||||
0x00, 0xe2, 0x46, 0x5b,
|
||||
0x03, 0x84, 0x59, 0x89,
|
||||
0x03, 0xea, 0x4c, 0x01,
|
||||
0x80, 0x1a, 0xa0, 0x7c,
|
||||
0x08, 0xb0, 0xe0, 0x30,
|
||||
0x04, 0xb0, 0xe0, 0x30,
|
||||
0x03, 0xb0, 0xf0, 0x30,
|
||||
0x01, 0x78, 0x84, 0x7b,
|
||||
0x01, 0xa7, 0x4e, 0x11,
|
||||
0x01, 0xb0, 0x06, 0x33,
|
||||
0x7f, 0x83, 0xe9, 0x08,
|
||||
0x04, 0xac, 0x58, 0x19,
|
||||
0xff, 0xea, 0xc0, 0x09,
|
||||
0x04, 0x84, 0x09, 0x9b,
|
||||
0x00, 0x85, 0x0b, 0x23,
|
||||
0x00, 0x86, 0x0d, 0x23,
|
||||
0x00, 0x87, 0x0f, 0x23,
|
||||
0x01, 0x84, 0xc5, 0x31,
|
||||
0x01, 0xa7, 0x9a, 0x7b,
|
||||
0x04, 0xe2, 0xc4, 0x01,
|
||||
0x80, 0x83, 0xa1, 0x7b,
|
||||
0x02, 0xe2, 0xc4, 0x01,
|
||||
0xff, 0xea, 0x4c, 0x09,
|
||||
0x01, 0xe2, 0x36, 0x30,
|
||||
0x88, 0x19, 0x32, 0x00,
|
||||
0x01, 0xac, 0xd4, 0x99,
|
||||
0x00, 0xe2, 0xa0, 0x54,
|
||||
0xfe, 0xa6, 0x4c, 0x0d,
|
||||
0x0b, 0x98, 0xe1, 0x30,
|
||||
0x01, 0xa0, 0x4f, 0x09,
|
||||
0xfd, 0xa4, 0x41, 0x09,
|
||||
0x80, 0xa3, 0xb5, 0x7b,
|
||||
0x02, 0xa0, 0x40, 0x01,
|
||||
0x01, 0xa7, 0xb8, 0x7b,
|
||||
0x04, 0xa0, 0x40, 0x01,
|
||||
0x01, 0xa0, 0x36, 0x30,
|
||||
0xa8, 0xea, 0x32, 0x00,
|
||||
0xfd, 0xa4, 0x49, 0x0b,
|
||||
0x05, 0xa3, 0x07, 0x33,
|
||||
0x80, 0x83, 0xc5, 0x6b,
|
||||
0x02, 0xea, 0x4c, 0x05,
|
||||
0xff, 0xea, 0x4c, 0x0d,
|
||||
0xc0, 0x33, 0xcb, 0x7b,
|
||||
0x03, 0xea, 0x04, 0x00,
|
||||
0x20, 0x33, 0xe3, 0x7b,
|
||||
0x01, 0x84, 0xd1, 0x6b,
|
||||
0x06, 0xea, 0x04, 0x00,
|
||||
0xee, 0x00, 0xd6, 0x6b,
|
||||
0x05, 0xea, 0xb4, 0x00,
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x80, 0x3d, 0x7a, 0x00,
|
||||
0x03, 0x42, 0xd8, 0x6b,
|
||||
0x7f, 0x3d, 0x7a, 0x08,
|
||||
0x11, 0xea, 0xda, 0x58,
|
||||
0x09, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x01, 0xa4, 0xd1, 0x6b,
|
||||
0x00, 0xe2, 0xaa, 0x5b,
|
||||
0x20, 0x33, 0x67, 0x02,
|
||||
0x00, 0xe2, 0x4e, 0x5b,
|
||||
0x20, 0x19, 0xe8, 0x6b,
|
||||
0x00, 0xe2, 0x06, 0x5c,
|
||||
0x04, 0x19, 0xfa, 0x6b,
|
||||
0x02, 0x19, 0x32, 0x00,
|
||||
0x01, 0x84, 0xfb, 0x7b,
|
||||
0x01, 0x1b, 0xf4, 0x7b,
|
||||
0x01, 0x1a, 0xfa, 0x6b,
|
||||
0x00, 0xe2, 0xc6, 0x43,
|
||||
0x80, 0x4b, 0x00, 0x6c,
|
||||
0x01, 0x4c, 0xfc, 0x7b,
|
||||
0x03, 0x42, 0xc6, 0x6b,
|
||||
0x00, 0xe2, 0x42, 0x5b,
|
||||
0x04, 0x33, 0x71, 0x79,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x02, 0x1b, 0x0e, 0x7c,
|
||||
0x08, 0x5d, 0x0c, 0x7c,
|
||||
0x03, 0x68, 0x00, 0x37,
|
||||
0x01, 0x84, 0x09, 0x07,
|
||||
0x08, 0x5d, 0x14, 0x6c,
|
||||
0x00, 0xe2, 0x4e, 0x5b,
|
||||
0x00, 0xe2, 0x06, 0x44,
|
||||
0x80, 0x1b, 0x1e, 0x7c,
|
||||
0x80, 0x84, 0x1f, 0x6c,
|
||||
0xff, 0x85, 0x0b, 0x1b,
|
||||
0xff, 0x86, 0x0d, 0x23,
|
||||
0xff, 0x87, 0x0f, 0x23,
|
||||
0xf8, 0x1b, 0x08, 0x0b,
|
||||
0xff, 0xea, 0x4e, 0x09,
|
||||
0x04, 0x1b, 0x26, 0x7c,
|
||||
0x01, 0xa7, 0x4e, 0x01,
|
||||
0xff, 0xea, 0x06, 0x0b,
|
||||
0x03, 0x68, 0x00, 0x37,
|
||||
0xff, 0xea, 0xd4, 0x09,
|
||||
0x20, 0x5b, 0x36, 0x6c,
|
||||
0x10, 0x5b, 0x40, 0x6c,
|
||||
0x08, 0x5b, 0x48, 0x6c,
|
||||
0x02, 0x5b, 0x44, 0x6d,
|
||||
0x12, 0xea, 0x04, 0x00,
|
||||
0x08, 0x19, 0x3c, 0x7c,
|
||||
0xdf, 0x5c, 0xb8, 0x08,
|
||||
0x01, 0xd9, 0xb2, 0x05,
|
||||
0x02, 0xea, 0xb4, 0x00,
|
||||
0x01, 0xd9, 0xb2, 0x05,
|
||||
0x01, 0xa4, 0x0f, 0x6d,
|
||||
0x00, 0xe2, 0xaa, 0x5b,
|
||||
0x00, 0xe2, 0x60, 0x5c,
|
||||
0x01, 0xd9, 0xb2, 0x05,
|
||||
0x00, 0xe2, 0xaa, 0x5a,
|
||||
0xf3, 0x90, 0xd5, 0x19,
|
||||
0x00, 0xe2, 0x54, 0x54,
|
||||
0x80, 0x90, 0x55, 0x6c,
|
||||
0x13, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x5c, 0x44,
|
||||
0x04, 0x8c, 0xe1, 0x30,
|
||||
0x01, 0xea, 0xf2, 0x00,
|
||||
0x02, 0xea, 0x36, 0x00,
|
||||
0xa8, 0xea, 0x32, 0x00,
|
||||
0x00, 0xe2, 0xd8, 0x5c,
|
||||
0x01, 0xd9, 0xb2, 0x05,
|
||||
0x02, 0xa8, 0xf4, 0x31,
|
||||
0x02, 0xa6, 0x72, 0x7c,
|
||||
0x00, 0xe2, 0xd4, 0x58,
|
||||
0x20, 0x5b, 0xba, 0x6c,
|
||||
0xfc, 0x42, 0x6c, 0x7c,
|
||||
0x10, 0x40, 0x6e, 0x6c,
|
||||
0x20, 0x4d, 0x70, 0x7c,
|
||||
0x08, 0x5d, 0xba, 0x6c,
|
||||
0x02, 0xa6, 0x5e, 0x6b,
|
||||
0x00, 0xe2, 0xd4, 0x58,
|
||||
0x20, 0x5b, 0xba, 0x6c,
|
||||
0x01, 0x1b, 0x82, 0x6c,
|
||||
0xfc, 0x42, 0x7c, 0x7c,
|
||||
0x10, 0x40, 0x7e, 0x6c,
|
||||
0x20, 0x4d, 0xa0, 0x7c,
|
||||
0x08, 0x5d, 0xba, 0x6c,
|
||||
0x00, 0xe2, 0xa0, 0x44,
|
||||
0x02, 0x19, 0x32, 0x00,
|
||||
0x08, 0xa8, 0xa3, 0x7c,
|
||||
0x04, 0x5d, 0x0e, 0x7d,
|
||||
0x01, 0x1a, 0x0e, 0x7d,
|
||||
0x01, 0xa4, 0x49, 0x03,
|
||||
0x80, 0xf9, 0xf2, 0x01,
|
||||
0x02, 0xa8, 0x82, 0x32,
|
||||
0x02, 0xea, 0xb4, 0x00,
|
||||
0x00, 0xe2, 0xba, 0x42,
|
||||
0x02, 0xa8, 0x82, 0x32,
|
||||
0x02, 0xea, 0xb4, 0x00,
|
||||
0xff, 0xea, 0xd4, 0x19,
|
||||
0x00, 0xe2, 0x48, 0x5b,
|
||||
0x00, 0xe2, 0xe8, 0x5c,
|
||||
0x00, 0xe2, 0xba, 0x52,
|
||||
0xff, 0xea, 0xd4, 0x0d,
|
||||
0x00, 0xe2, 0xd4, 0x58,
|
||||
0x40, 0x5b, 0xae, 0x6c,
|
||||
0x04, 0x5d, 0x0e, 0x7d,
|
||||
0x01, 0x1a, 0x0e, 0x7d,
|
||||
0x20, 0x4d, 0xa0, 0x7c,
|
||||
0x40, 0x5b, 0xfc, 0x7c,
|
||||
0x04, 0x5d, 0x0e, 0x7d,
|
||||
0x01, 0x1a, 0x0e, 0x7d,
|
||||
0x80, 0xf9, 0xf2, 0x01,
|
||||
0x01, 0xa4, 0x49, 0x03,
|
||||
0x08, 0xa8, 0x95, 0x6c,
|
||||
0x02, 0xea, 0xb4, 0x04,
|
||||
0x02, 0x19, 0x32, 0x00,
|
||||
0x01, 0x5b, 0x40, 0x31,
|
||||
0x20, 0xea, 0xb6, 0x00,
|
||||
0x00, 0xe2, 0x06, 0x5c,
|
||||
0x00, 0xe2, 0x14, 0x5b,
|
||||
0x00, 0xe2, 0x42, 0x5b,
|
||||
0x20, 0x5c, 0xb8, 0x00,
|
||||
0x80, 0xf9, 0xf2, 0x01,
|
||||
0x20, 0xa0, 0xfc, 0x7c,
|
||||
0x08, 0xa8, 0xd1, 0x7c,
|
||||
0x00, 0xe2, 0x94, 0x44,
|
||||
0x02, 0xea, 0xb4, 0x04,
|
||||
0xff, 0x6a, 0xde, 0x7c,
|
||||
0x14, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0xde, 0x44,
|
||||
0x00, 0xe2, 0xd2, 0x58,
|
||||
0x10, 0x5d, 0xd2, 0x6c,
|
||||
0x40, 0x5b, 0xa0, 0x7c,
|
||||
0x02, 0x19, 0x32, 0x00,
|
||||
0x80, 0xf9, 0xf2, 0x01,
|
||||
0xff, 0xea, 0x10, 0x03,
|
||||
0x08, 0xa8, 0x51, 0x03,
|
||||
0x00, 0xe2, 0x94, 0x44,
|
||||
0x80, 0xf9, 0xa0, 0x6c,
|
||||
0x01, 0x42, 0xc1, 0x31,
|
||||
0x00, 0xfb, 0xa0, 0x64,
|
||||
0x01, 0x41, 0xc1, 0x31,
|
||||
0x00, 0xfa, 0xa0, 0x64,
|
||||
0x01, 0xe8, 0xd4, 0x1d,
|
||||
0x30, 0x3f, 0xc0, 0x09,
|
||||
0x30, 0xe0, 0xa0, 0x64,
|
||||
0x40, 0x4b, 0xa0, 0x6c,
|
||||
0xff, 0xea, 0x52, 0x01,
|
||||
0xee, 0x00, 0x02, 0x6d,
|
||||
0x80, 0xf9, 0xf2, 0x01,
|
||||
0x02, 0xea, 0xb4, 0x00,
|
||||
0x20, 0xea, 0x9a, 0x00,
|
||||
0xf3, 0x42, 0x0a, 0x6d,
|
||||
0x18, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x11, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0x70, 0x41,
|
||||
0x15, 0xea, 0x04, 0x00,
|
||||
0x00, 0xe2, 0xaa, 0x5a,
|
||||
0x33, 0xea, 0xda, 0x58,
|
||||
0x80, 0x3d, 0x7a, 0x00,
|
||||
0x00, 0xe2, 0x2e, 0x5d,
|
||||
0xa8, 0xea, 0x32, 0x00,
|
||||
0x00, 0xe2, 0xd4, 0x58,
|
||||
0x40, 0x1a, 0x22, 0x7d,
|
||||
0x00, 0xe2, 0x2e, 0x5d,
|
||||
0x80, 0x19, 0x32, 0x00,
|
||||
0x40, 0x5b, 0x26, 0x6d,
|
||||
0x20, 0x4d, 0xa0, 0x7c,
|
||||
0x02, 0x84, 0x09, 0x03,
|
||||
0x40, 0x5b, 0xfc, 0x7c,
|
||||
0x08, 0xa8, 0x8d, 0x6c,
|
||||
0x02, 0xea, 0xb4, 0x04,
|
||||
0x01, 0x37, 0xe1, 0x30,
|
||||
0x05, 0x38, 0xe3, 0x98,
|
||||
0x01, 0xe0, 0xf8, 0x31,
|
||||
0xff, 0xea, 0xc0, 0x09,
|
||||
0x00, 0x39, 0xe5, 0x20,
|
||||
0x00, 0x3a, 0xe7, 0x20,
|
||||
0x01, 0xfc, 0xc0, 0x31,
|
||||
0x04, 0xea, 0xe8, 0x30,
|
||||
0xff, 0xea, 0xf0, 0x08,
|
||||
0x02, 0xea, 0xf2, 0x00,
|
||||
0xff, 0xea, 0xf4, 0x08
|
||||
};
|
||||
|
||||
static int aic_patch10_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch10_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch9_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch9_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
|
||||
}
|
||||
|
||||
static int aic_patch8_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch8_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->flags & AHD_INITIATORROLE) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch7_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch7_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->flags & AHD_TARGETROLE) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch6_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch6_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch5_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch5_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch4_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch4_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch3_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch3_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch2_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch2_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch1_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch1_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
|
||||
}
|
||||
|
||||
static int aic_patch0_func(struct ahd_softc *ahd);
|
||||
|
||||
static int
|
||||
aic_patch0_func(struct ahd_softc *ahd)
|
||||
{
|
||||
return (0);
|
||||
}
|
||||
|
||||
typedef int patch_func_t (struct ahd_softc *ahd);
|
||||
static struct patch {
|
||||
patch_func_t *patch_func;
|
||||
uint32_t begin :10,
|
||||
skip_instr :10,
|
||||
skip_patch :12;
|
||||
} patches[] = {
|
||||
{ aic_patch1_func, 112, 1, 1 },
|
||||
{ aic_patch1_func, 139, 16, 2 },
|
||||
{ aic_patch0_func, 155, 1, 1 },
|
||||
{ aic_patch2_func, 175, 2, 1 },
|
||||
{ aic_patch3_func, 283, 1, 1 },
|
||||
{ aic_patch3_func, 286, 1, 1 },
|
||||
{ aic_patch3_func, 288, 1, 1 },
|
||||
{ aic_patch3_func, 320, 1, 1 },
|
||||
{ aic_patch4_func, 445, 1, 2 },
|
||||
{ aic_patch0_func, 446, 1, 1 },
|
||||
{ aic_patch5_func, 451, 1, 1 },
|
||||
{ aic_patch4_func, 452, 1, 1 },
|
||||
{ aic_patch6_func, 504, 1, 1 },
|
||||
{ aic_patch7_func, 509, 1, 1 },
|
||||
{ aic_patch8_func, 510, 2, 1 },
|
||||
{ aic_patch7_func, 513, 1, 2 },
|
||||
{ aic_patch0_func, 514, 1, 1 },
|
||||
{ aic_patch6_func, 577, 1, 1 },
|
||||
{ aic_patch6_func, 605, 1, 1 },
|
||||
{ aic_patch6_func, 623, 1, 1 },
|
||||
{ aic_patch9_func, 649, 2, 2 },
|
||||
{ aic_patch0_func, 651, 2, 1 },
|
||||
{ aic_patch10_func, 654, 3, 1 },
|
||||
{ aic_patch10_func, 663, 11, 1 }
|
||||
};
|
||||
static struct cs {
|
||||
u_int16_t begin;
|
||||
u_int16_t end;
|
||||
} critical_sections[] = {
|
||||
{ 4, 5 },
|
||||
{ 6, 7 },
|
||||
{ 13, 19 },
|
||||
{ 20, 30 },
|
||||
{ 75, 102 },
|
||||
{ 105, 109 },
|
||||
{ 112, 120 },
|
||||
{ 139, 172 },
|
||||
{ 577, 594 },
|
||||
{ 599, 605 },
|
||||
{ 605, 617 },
|
||||
{ 623, 628 },
|
||||
{ 628, 634 }
|
||||
};
|
||||
static const int num_critical_sections = sizeof(critical_sections)
|
||||
/ sizeof(*critical_sections);
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* Interface for the 93C66/56/46/26/06 serial eeprom parts.
|
||||
*
|
||||
* Copyright (c) 1995, 1996 Daniel M. Eischen
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL").
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#15 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.c,v 1.8.2.5 2002/04/29 19:36:31 gibbs Exp $
|
||||
*/
|
||||
|
||||
/*
|
||||
* The instruction set of the 93C66/56/46/26/06 chips are as follows:
|
||||
*
|
||||
* Start OP *
|
||||
* Function Bit Code Address** Data Description
|
||||
* -------------------------------------------------------------------
|
||||
* READ 1 10 A5 - A0 Reads data stored in memory,
|
||||
* starting at specified address
|
||||
* EWEN 1 00 11XXXX Write enable must precede
|
||||
* all programming modes
|
||||
* ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
|
||||
* WRITE 1 01 A5 - A0 D15 - D0 Writes register
|
||||
* ERAL 1 00 10XXXX Erase all registers
|
||||
* WRAL 1 00 01XXXX D15 - D0 Writes to all registers
|
||||
* EWDS 1 00 00XXXX Disables all programming
|
||||
* instructions
|
||||
* *Note: A value of X for address is a don't care condition.
|
||||
* **Note: There are 8 address bits for the 93C56/66 chips unlike
|
||||
* the 93C46/26/06 chips which have 6 address bits.
|
||||
*
|
||||
* The 93C46 has a four wire interface: clock, chip select, data in, and
|
||||
* data out. In order to perform one of the above functions, you need
|
||||
* to enable the chip select for a clock period (typically a minimum of
|
||||
* 1 usec, with the clock high and low a minimum of 750 and 250 nsec
|
||||
* respectively). While the chip select remains high, you can clock in
|
||||
* the instructions (above) starting with the start bit, followed by the
|
||||
* OP code, Address, and Data (if needed). For the READ instruction, the
|
||||
* requested 16-bit register contents is read from the data out line but
|
||||
* is preceded by an initial zero (leading 0, followed by 16-bits, MSB
|
||||
* first). The clock cycling from low to high initiates the next data
|
||||
* bit to be sent from the chip.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aic7xxx_osm.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
#else
|
||||
#include <dev/aic7xxx/aic7xxx_osm.h>
|
||||
#include <dev/aic7xxx/aic7xxx_inline.h>
|
||||
#include <dev/aic7xxx/aic7xxx_93cx6.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Right now, we only have to read the SEEPROM. But we make it easier to
|
||||
* add other 93Cx6 functions.
|
||||
*/
|
||||
static struct seeprom_cmd {
|
||||
uint8_t len;
|
||||
uint8_t bits[9];
|
||||
} seeprom_read = {3, {1, 1, 0}};
|
||||
|
||||
static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
|
||||
static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
|
||||
static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
|
||||
|
||||
/*
|
||||
* Wait for the SEERDY to go high; about 800 ns.
|
||||
*/
|
||||
#define CLOCK_PULSE(sd, rdy) \
|
||||
while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) { \
|
||||
; /* Do nothing */ \
|
||||
} \
|
||||
(void)SEEPROM_INB(sd); /* Clear clock */
|
||||
|
||||
/*
|
||||
* Send a START condition and the given command
|
||||
*/
|
||||
static void
|
||||
send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
|
||||
{
|
||||
uint8_t temp;
|
||||
int i = 0;
|
||||
|
||||
/* Send chip select for one clock cycle. */
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
|
||||
for (i = 0; i < cmd->len; i++) {
|
||||
if (cmd->bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if (cmd->bits[i] != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear CS put the chip in the reset state, where it can wait for new commands.
|
||||
*/
|
||||
static void
|
||||
reset_seeprom(struct seeprom_descriptor *sd)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
temp = sd->sd_MS;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the serial EEPROM and returns 1 if successful and 0 if
|
||||
* not successful.
|
||||
*/
|
||||
int
|
||||
ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
u_int start_addr, u_int count)
|
||||
{
|
||||
int i = 0;
|
||||
u_int k = 0;
|
||||
uint16_t v;
|
||||
uint8_t temp;
|
||||
|
||||
/*
|
||||
* Read the requested registers of the seeprom. The loop
|
||||
* will range from 0 to count-1.
|
||||
*/
|
||||
for (k = start_addr; k < count + start_addr; k++) {
|
||||
/*
|
||||
* Now we're ready to send the read command followed by the
|
||||
* address of the 16-bit register we want to read.
|
||||
*/
|
||||
send_seeprom_cmd(sd, &seeprom_read);
|
||||
|
||||
/* Send the 6 or 8 bit address (MSB first, LSB last). */
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
for (i = (sd->sd_chip - 1); i >= 0; i--) {
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now read the 16 bit register. An initial 0 precedes the
|
||||
* register contents which begins with bit 15 (MSB) and ends
|
||||
* with bit 0 (LSB). The initial 0 will be shifted off the
|
||||
* top of our word as we let the loop run from 0 to 16.
|
||||
*/
|
||||
v = 0;
|
||||
for (i = 16; i >= 0; i--) {
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
v <<= 1;
|
||||
if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
|
||||
v |= 1;
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
}
|
||||
|
||||
buf[k - start_addr] = v;
|
||||
|
||||
/* Reset the chip select for the next command cycle. */
|
||||
reset_seeprom(sd);
|
||||
}
|
||||
#ifdef AHC_DUMP_EEPROM
|
||||
printf("\nSerial EEPROM:\n\t");
|
||||
for (k = 0; k < count; k = k + 1) {
|
||||
if (((k % 8) == 0) && (k != 0)) {
|
||||
printf ("\n\t");
|
||||
}
|
||||
printf (" 0x%x", buf[k]);
|
||||
}
|
||||
printf ("\n");
|
||||
#endif
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the serial EEPROM and return 1 if successful and 0 if
|
||||
* not successful.
|
||||
*/
|
||||
int
|
||||
ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
u_int start_addr, u_int count)
|
||||
{
|
||||
uint16_t v;
|
||||
uint8_t temp;
|
||||
int i, k;
|
||||
|
||||
/* Place the chip into write-enable mode */
|
||||
send_seeprom_cmd(sd, &seeprom_ewen);
|
||||
reset_seeprom(sd);
|
||||
|
||||
/* Write all requested data out to the seeprom. */
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
for (k = start_addr; k < count + start_addr; k++) {
|
||||
/* Send the write command */
|
||||
send_seeprom_cmd(sd, &seeprom_write);
|
||||
|
||||
/* Send the 6 or 8 bit address (MSB first). */
|
||||
for (i = (sd->sd_chip - 1); i >= 0; i--) {
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if ((k & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
|
||||
/* Write the 16 bit value, MSB first */
|
||||
v = buf[k - start_addr];
|
||||
for (i = 15; i >= 0; i--) {
|
||||
if ((v & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
if ((v & (1 << i)) != 0)
|
||||
temp ^= sd->sd_DO;
|
||||
}
|
||||
|
||||
/* Wait for the chip to complete the write */
|
||||
temp = sd->sd_MS;
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
temp = sd->sd_MS ^ sd->sd_CS;
|
||||
do {
|
||||
SEEPROM_OUTB(sd, temp);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
|
||||
CLOCK_PULSE(sd, sd->sd_RDY);
|
||||
} while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0);
|
||||
|
||||
reset_seeprom(sd);
|
||||
}
|
||||
|
||||
/* Put the chip back into write-protect mode */
|
||||
send_seeprom_cmd(sd, &seeprom_ewds);
|
||||
reset_seeprom(sd);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
int
|
||||
ahc_verify_cksum(struct seeprom_config *sc)
|
||||
{
|
||||
int i;
|
||||
int maxaddr;
|
||||
uint32_t checksum;
|
||||
uint16_t *scarray;
|
||||
|
||||
maxaddr = (sizeof(*sc)/2) - 1;
|
||||
checksum = 0;
|
||||
scarray = (uint16_t *)sc;
|
||||
|
||||
for (i = 0; i < maxaddr; i++)
|
||||
checksum = checksum + scarray[i];
|
||||
if (checksum == 0
|
||||
|| (checksum & 0xFFFF) != sc->checksum) {
|
||||
return (0);
|
||||
} else {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Interface to the 93C46/56 serial EEPROM that is used to store BIOS
|
||||
* settings for the aic7xxx based adaptec SCSI controllers. It can
|
||||
* also be used for 93C26 and 93C06 serial EEPROMS.
|
||||
*
|
||||
* Copyright (c) 1994, 1995, 2000 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#10 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_93cx6.h,v 1.7.2.3 2002/04/29 19:36:31 gibbs Exp $
|
||||
*/
|
||||
#ifndef _AIC7XXX_93CX6_H_
|
||||
#define _AIC7XXX_93CX6_H_
|
||||
|
||||
typedef enum {
|
||||
C46 = 6,
|
||||
C56_66 = 8
|
||||
} seeprom_chip_t;
|
||||
|
||||
struct seeprom_descriptor {
|
||||
struct ahc_softc *sd_ahc;
|
||||
u_int sd_control_offset;
|
||||
u_int sd_status_offset;
|
||||
u_int sd_dataout_offset;
|
||||
seeprom_chip_t sd_chip;
|
||||
uint16_t sd_MS;
|
||||
uint16_t sd_RDY;
|
||||
uint16_t sd_CS;
|
||||
uint16_t sd_CK;
|
||||
uint16_t sd_DO;
|
||||
uint16_t sd_DI;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function will read count 16-bit words from the serial EEPROM and
|
||||
* return their value in buf. The port address of the aic7xxx serial EEPROM
|
||||
* control register is passed in as offset. The following parameters are
|
||||
* also passed in:
|
||||
*
|
||||
* CS - Chip select
|
||||
* CK - Clock
|
||||
* DO - Data out
|
||||
* DI - Data in
|
||||
* RDY - SEEPROM ready
|
||||
* MS - Memory port mode select
|
||||
*
|
||||
* A failed read attempt returns 0, and a successful read returns 1.
|
||||
*/
|
||||
|
||||
#define SEEPROM_INB(sd) \
|
||||
ahc_inb(sd->sd_ahc, sd->sd_control_offset)
|
||||
#define SEEPROM_OUTB(sd, value) \
|
||||
do { \
|
||||
ahc_outb(sd->sd_ahc, sd->sd_control_offset, value); \
|
||||
ahc_flush_device_writes(sd->sd_ahc); \
|
||||
} while(0)
|
||||
|
||||
#define SEEPROM_STATUS_INB(sd) \
|
||||
ahc_inb(sd->sd_ahc, sd->sd_status_offset)
|
||||
#define SEEPROM_DATA_INB(sd) \
|
||||
ahc_inb(sd->sd_ahc, sd->sd_dataout_offset)
|
||||
|
||||
int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
u_int start_addr, u_int count);
|
||||
int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
|
||||
u_int start_addr, u_int count);
|
||||
int ahc_verify_cksum(struct seeprom_config *sc);
|
||||
|
||||
#endif /* _AIC7XXX_93CX6_H_ */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Adaptec AIC7xxx device driver host template for Linux.
|
||||
*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_host.h#9 $
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_HOST_H_
|
||||
#define _AIC7XXX_HOST_H_
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
int ahc_linux_proc_info(char *, char **, off_t, int, int, int);
|
||||
#endif
|
||||
int ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
|
||||
int ahc_linux_detect(Scsi_Host_Template *);
|
||||
int ahc_linux_release(struct Scsi_Host *);
|
||||
const char *ahc_linux_info(struct Scsi_Host *);
|
||||
int ahc_linux_biosparam(Disk *, kdev_t, int[]);
|
||||
int ahc_linux_bus_reset(Scsi_Cmnd *);
|
||||
int ahc_linux_dev_reset(Scsi_Cmnd *);
|
||||
int ahc_linux_abort(Scsi_Cmnd *);
|
||||
|
||||
#if defined(__i386__)
|
||||
# define AIC7XXX_BIOSPARAM ahc_linux_biosparam
|
||||
#else
|
||||
# define AIC7XXX_BIOSPARAM NULL
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
|
||||
* to do with card config are filled in after the card is detected.
|
||||
*/
|
||||
|
||||
// proc_dir: NULL,
|
||||
// proc_info: ahc_linux_proc_info,
|
||||
|
||||
|
||||
#define AIC7XXX { \
|
||||
next: NULL, \
|
||||
module: NULL, \
|
||||
name: NULL, \
|
||||
detect: ahc_linux_detect, \
|
||||
release: ahc_linux_release, \
|
||||
info: ahc_linux_info, \
|
||||
command: NULL, \
|
||||
queuecommand: ahc_linux_queue, \
|
||||
eh_strategy_handler: NULL, \
|
||||
eh_abort_handler: ahc_linux_abort, \
|
||||
eh_device_reset_handler: ahc_linux_dev_reset, \
|
||||
eh_bus_reset_handler: ahc_linux_bus_reset, \
|
||||
eh_host_reset_handler: NULL, \
|
||||
abort: NULL, \
|
||||
reset: NULL, \
|
||||
slave_attach: NULL, \
|
||||
bios_param: AIC7XXX_BIOSPARAM, \
|
||||
can_queue: AHC_MAX_QUEUE,/* max simultaneous cmds */\
|
||||
this_id: -1, /* scsi id of host adapter */\
|
||||
sg_tablesize: AHC_NSEG, /* max scatter-gather cmds */\
|
||||
cmd_per_lun: 2, /* cmds per lun */\
|
||||
present: 0, /* number of 7xxx's present */\
|
||||
unchecked_isa_dma: 0, /* no memory DMA restrictions*/\
|
||||
use_clustering: ENABLE_CLUSTERING, \
|
||||
use_new_eh_code: 1 \
|
||||
}
|
||||
|
||||
/* highmem_io: 1 \
|
||||
*/
|
||||
|
||||
#endif /* _AIC7XXX_HOST_H_ */
|
||||
@@ -0,0 +1,563 @@
|
||||
/*
|
||||
* Inline routines shareable across OS platforms.
|
||||
*
|
||||
* Copyright (c) 1994-2001 Justin T. Gibbs.
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#35 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aic7xxx_inline.h,v 1.2.2.11 2002/04/29 19:36:31 gibbs Exp $
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_INLINE_H_
|
||||
#define _AIC7XXX_INLINE_H_
|
||||
|
||||
/************************* Sequencer Execution Control ************************/
|
||||
static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
|
||||
static __inline int ahc_is_paused(struct ahc_softc *ahc);
|
||||
static __inline void ahc_pause(struct ahc_softc *ahc);
|
||||
static __inline void ahc_unpause(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Work around any chip bugs related to halting sequencer execution.
|
||||
* On Ultra2 controllers, we must clear the CIOBUS stretch signal by
|
||||
* reading a register that will set this signal and deassert it.
|
||||
* Without this workaround, if the chip is paused, by an interrupt or
|
||||
* manual pause while accessing scb ram, accesses to certain registers
|
||||
* will hang the system (infinite pci retries).
|
||||
*/
|
||||
static __inline void
|
||||
ahc_pause_bug_fix(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->features & AHC_ULTRA2) != 0)
|
||||
(void)ahc_inb(ahc, CCSCBCTL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer has halted code execution.
|
||||
* Returns non-zero status if the sequencer is stopped.
|
||||
*/
|
||||
static __inline int
|
||||
ahc_is_paused(struct ahc_softc *ahc)
|
||||
{
|
||||
return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Request that the sequencer stop and wait, indefinitely, for it
|
||||
* to stop. The sequencer will only acknowledge that it is paused
|
||||
* once it has reached an instruction boundary and PAUSEDIS is
|
||||
* cleared in the SEQCTL register. The sequencer may use PAUSEDIS
|
||||
* for critical sections.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_pause(struct ahc_softc *ahc)
|
||||
{
|
||||
ahc_outb(ahc, HCNTRL, ahc->pause);
|
||||
|
||||
/*
|
||||
* Since the sequencer can disable pausing in a critical section, we
|
||||
* must loop until it actually stops.
|
||||
*/
|
||||
while (ahc_is_paused(ahc) == 0)
|
||||
;
|
||||
|
||||
ahc_pause_bug_fix(ahc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the sequencer to continue program execution.
|
||||
* We check here to ensure that no additional interrupt
|
||||
* sources that would cause the sequencer to halt have been
|
||||
* asserted. If, for example, a SCSI bus reset is detected
|
||||
* while we are fielding a different, pausing, interrupt type,
|
||||
* we don't want to release the sequencer before going back
|
||||
* into our interrupt handler and dealing with this new
|
||||
* condition.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_unpause(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
|
||||
ahc_outb(ahc, HCNTRL, ahc->unpause);
|
||||
}
|
||||
|
||||
/*********************** Untagged Transaction Routines ************************/
|
||||
static __inline void ahc_freeze_untagged_queues(struct ahc_softc *ahc);
|
||||
static __inline void ahc_release_untagged_queues(struct ahc_softc *ahc);
|
||||
|
||||
/*
|
||||
* Block our completion routine from starting the next untagged
|
||||
* transaction for this target or target lun.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_freeze_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0)
|
||||
ahc->untagged_queue_lock++;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allow the next untagged transaction for this target or target lun
|
||||
* to be executed. We use a counting semaphore to allow the lock
|
||||
* to be acquired recursively. Once the count drops to zero, the
|
||||
* transaction queues will be run.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_release_untagged_queues(struct ahc_softc *ahc)
|
||||
{
|
||||
if ((ahc->flags & AHC_SCB_BTT) == 0) {
|
||||
ahc->untagged_queue_lock--;
|
||||
if (ahc->untagged_queue_lock == 0)
|
||||
ahc_run_untagged_queues(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
/************************** Memory mapping routines ***************************/
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb,
|
||||
uint32_t sg_busaddr);
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb,
|
||||
struct ahc_dma_seg *sg);
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
|
||||
static __inline void ahc_sync_scb(struct ahc_softc *ahc,
|
||||
struct scb *scb, int op);
|
||||
static __inline void ahc_sync_sglist(struct ahc_softc *ahc,
|
||||
struct scb *scb, int op);
|
||||
static __inline uint32_t
|
||||
ahc_targetcmd_offset(struct ahc_softc *ahc,
|
||||
u_int index);
|
||||
|
||||
static __inline struct ahc_dma_seg *
|
||||
ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index++;
|
||||
|
||||
return (&scb->sg_list[sg_index]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
|
||||
{
|
||||
int sg_index;
|
||||
|
||||
/* sg_list_phys points to entry 1, not 0 */
|
||||
sg_index = sg - &scb->sg_list[1];
|
||||
|
||||
return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (ahc->scb_data->hscb_busaddr
|
||||
+ (sizeof(struct hardware_scb) * index));
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
|
||||
ahc->scb_data->hscb_dmamap,
|
||||
/*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
|
||||
/*len*/sizeof(*scb->hscb), op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
|
||||
{
|
||||
if (scb->sg_count == 0)
|
||||
return;
|
||||
|
||||
ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
|
||||
/*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
|
||||
* sizeof(struct ahc_dma_seg),
|
||||
/*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
|
||||
{
|
||||
return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
|
||||
}
|
||||
|
||||
/******************************** Debugging ***********************************/
|
||||
static __inline char *ahc_name(struct ahc_softc *ahc);
|
||||
|
||||
static __inline char *
|
||||
ahc_name(struct ahc_softc *ahc)
|
||||
{
|
||||
return (ahc->name);
|
||||
}
|
||||
|
||||
/*********************** Miscelaneous Support Functions ***********************/
|
||||
|
||||
static __inline void ahc_update_residual(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc,
|
||||
char channel, u_int our_id,
|
||||
u_int remote_id,
|
||||
struct ahc_tmode_tstate **tstate);
|
||||
static __inline struct scb*
|
||||
ahc_get_scb(struct ahc_softc *ahc);
|
||||
static __inline void ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
static __inline void ahc_swap_with_next_hscb(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline void ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
|
||||
static __inline struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufaddr(struct ahc_softc *ahc,
|
||||
struct scb *scb);
|
||||
|
||||
/*
|
||||
* Determine whether the sequencer reported a residual
|
||||
* for this SCB/transaction.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
uint32_t sgptr;
|
||||
|
||||
sgptr = ahc_le32toh(scb->hscb->sgptr);
|
||||
if ((sgptr & SG_RESID_VALID) != 0)
|
||||
ahc_calc_residual(ahc, scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pointers to the transfer negotiation information
|
||||
* for the specified our_id/remote_id pair.
|
||||
*/
|
||||
static __inline struct ahc_initiator_tinfo *
|
||||
ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
|
||||
u_int remote_id, struct ahc_tmode_tstate **tstate)
|
||||
{
|
||||
/*
|
||||
* Transfer data structures are stored from the perspective
|
||||
* of the target role. Since the parameters for a connection
|
||||
* in the initiator role to a given target are the same as
|
||||
* when the roles are reversed, we pretend we are the target.
|
||||
*/
|
||||
if (channel == 'B')
|
||||
our_id += 8;
|
||||
*tstate = ahc->enabled_targets[our_id];
|
||||
return (&(*tstate)->transinfo[remote_id]);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a free scb. If there are none, see if we can allocate a new SCB.
|
||||
*/
|
||||
static __inline struct scb *
|
||||
ahc_get_scb(struct ahc_softc *ahc)
|
||||
{
|
||||
struct scb *scb;
|
||||
|
||||
if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
|
||||
ahc_alloc_scbs(ahc);
|
||||
scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
|
||||
if (scb == NULL)
|
||||
return (NULL);
|
||||
}
|
||||
SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return an SCB resource to the free list.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *hscb;
|
||||
|
||||
hscb = scb->hscb;
|
||||
/* Clean up for the next user */
|
||||
ahc->scb_data->scbindex[hscb->tag] = NULL;
|
||||
scb->flags = SCB_FREE;
|
||||
hscb->control = 0;
|
||||
|
||||
SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
|
||||
|
||||
/* Notify the OSM that a resource is now available. */
|
||||
ahc_platform_scb_free(ahc, scb);
|
||||
}
|
||||
|
||||
static __inline struct scb *
|
||||
ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
|
||||
{
|
||||
struct scb* scb;
|
||||
|
||||
scb = ahc->scb_data->scbindex[tag];
|
||||
if (scb != NULL)
|
||||
ahc_sync_scb(ahc, scb,
|
||||
BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
|
||||
return (scb);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
struct hardware_scb *q_hscb;
|
||||
u_int saved_tag;
|
||||
|
||||
/*
|
||||
* Our queuing method is a bit tricky. The card
|
||||
* knows in advance which HSCB to download, and we
|
||||
* can't disappoint it. To achieve this, the next
|
||||
* SCB to download is saved off in ahc->next_queued_scb.
|
||||
* When we are called to queue "an arbitrary scb",
|
||||
* we copy the contents of the incoming HSCB to the one
|
||||
* the sequencer knows about, swap HSCB pointers and
|
||||
* finally assign the SCB to the tag indexed location
|
||||
* in the scb_array. This makes sure that we can still
|
||||
* locate the correct SCB by SCB_TAG.
|
||||
*/
|
||||
q_hscb = ahc->next_queued_scb->hscb;
|
||||
saved_tag = q_hscb->tag;
|
||||
memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
|
||||
if ((scb->flags & SCB_CDB32_PTR) != 0) {
|
||||
q_hscb->shared_data.cdb_ptr =
|
||||
ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
|
||||
+ offsetof(struct hardware_scb, cdb32));
|
||||
}
|
||||
q_hscb->tag = saved_tag;
|
||||
q_hscb->next = scb->hscb->tag;
|
||||
|
||||
/* Now swap HSCB pointers. */
|
||||
ahc->next_queued_scb->hscb = scb->hscb;
|
||||
scb->hscb = q_hscb;
|
||||
|
||||
/* Now define the mapping from tag to SCB in the scbindex */
|
||||
ahc->scb_data->scbindex[scb->hscb->tag] = scb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tell the sequencer about a new transaction to execute.
|
||||
*/
|
||||
static __inline void
|
||||
ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
ahc_swap_with_next_hscb(ahc, scb);
|
||||
|
||||
if (scb->hscb->tag == SCB_LIST_NULL
|
||||
|| scb->hscb->next == SCB_LIST_NULL)
|
||||
panic("Attempt to queue invalid SCB tag %x:%x\n",
|
||||
scb->hscb->tag, scb->hscb->next);
|
||||
|
||||
/*
|
||||
* Keep a history of SCBs we've downloaded in the qinfifo.
|
||||
*/
|
||||
ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
|
||||
|
||||
/*
|
||||
* Make sure our data is consistant from the
|
||||
* perspective of the adapter.
|
||||
*/
|
||||
ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
|
||||
|
||||
/* Tell the adapter about the newly queued SCB */
|
||||
if ((ahc->features & AHC_QUEUE_REGS) != 0) {
|
||||
ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
|
||||
} else {
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_pause(ahc);
|
||||
ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
|
||||
if ((ahc->features & AHC_AUTOPAUSE) == 0)
|
||||
ahc_unpause(ahc);
|
||||
}
|
||||
}
|
||||
|
||||
static __inline struct scsi_sense_data *
|
||||
ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (&ahc->scb_data->sense[offset]);
|
||||
}
|
||||
|
||||
static __inline uint32_t
|
||||
ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
|
||||
{
|
||||
int offset;
|
||||
|
||||
offset = scb - ahc->scb_data->scbarray;
|
||||
return (ahc->scb_data->sense_busaddr
|
||||
+ (offset * sizeof(struct scsi_sense_data)));
|
||||
}
|
||||
|
||||
/************************** Interrupt Processing ******************************/
|
||||
static __inline void ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline void ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
|
||||
static __inline u_int ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
|
||||
static __inline void ahc_intr(struct ahc_softc *ahc);
|
||||
|
||||
static __inline void
|
||||
ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/0, /*len*/256, op);
|
||||
}
|
||||
|
||||
static __inline void
|
||||
ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
|
||||
{
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, 0),
|
||||
sizeof(struct target_cmd) * AHC_TMODE_CMDS,
|
||||
op);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the firmware has posted any completed commands
|
||||
* into our in-core command complete fifos.
|
||||
*/
|
||||
#define AHC_RUN_QOUTFIFO 0x1
|
||||
#define AHC_RUN_TQINFIFO 0x2
|
||||
static __inline u_int
|
||||
ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int retval;
|
||||
|
||||
retval = 0;
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
|
||||
/*offset*/ahc->qoutfifonext, /*len*/1,
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
|
||||
retval |= AHC_RUN_QOUTFIFO;
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0
|
||||
&& (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
|
||||
ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
|
||||
ahc->shared_data_dmamap,
|
||||
ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
|
||||
/*len*/sizeof(struct target_cmd),
|
||||
BUS_DMASYNC_POSTREAD);
|
||||
if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
|
||||
retval |= AHC_RUN_TQINFIFO;
|
||||
}
|
||||
#endif
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catch an interrupt from the adapter
|
||||
*/
|
||||
static __inline void
|
||||
ahc_intr(struct ahc_softc *ahc)
|
||||
{
|
||||
u_int intstat;
|
||||
|
||||
/*
|
||||
* Instead of directly reading the interrupt status register,
|
||||
* infer the cause of the interrupt by checking our in-core
|
||||
* completion queues. This avoids a costly PCI bus read in
|
||||
* most cases.
|
||||
*/
|
||||
if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
|
||||
&& (ahc_check_cmdcmpltqueues(ahc) != 0))
|
||||
intstat = CMDCMPLT;
|
||||
else {
|
||||
intstat = ahc_inb(ahc, INTSTAT);
|
||||
}
|
||||
|
||||
if (intstat & CMDCMPLT) {
|
||||
ahc_outb(ahc, CLRINT, CLRCMDINT);
|
||||
|
||||
/*
|
||||
* Ensure that the chip sees that we've cleared
|
||||
* this interrupt before we walk the output fifo.
|
||||
* Otherwise, we may, due to posted bus writes,
|
||||
* clear the interrupt after we finish the scan,
|
||||
* and after the sequencer has added new entries
|
||||
* and asserted the interrupt again.
|
||||
*/
|
||||
ahc_flush_device_writes(ahc);
|
||||
ahc_run_qoutfifo(ahc);
|
||||
#ifdef AHC_TARGET_MODE
|
||||
if ((ahc->flags & AHC_TARGETROLE) != 0)
|
||||
ahc_run_tqinfifo(ahc, /*paused*/FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
|
||||
/* Hot eject */
|
||||
return;
|
||||
|
||||
if ((intstat & INT_PEND) == 0) {
|
||||
#if AHC_PCI_CONFIG > 0
|
||||
if (ahc->unsolicited_ints > 500) {
|
||||
ahc->unsolicited_ints = 0;
|
||||
if ((ahc->chip & AHC_PCI) != 0
|
||||
&& (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
|
||||
ahc->bus_intr(ahc);
|
||||
}
|
||||
#endif
|
||||
ahc->unsolicited_ints++;
|
||||
return;
|
||||
}
|
||||
ahc->unsolicited_ints = 0;
|
||||
|
||||
if (intstat & BRKADRINT) {
|
||||
ahc_handle_brkadrint(ahc);
|
||||
/* Fatal error, no more interrupts to handle. */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((intstat & (SEQINT|SCSIINT)) != 0)
|
||||
ahc_pause_bug_fix(ahc);
|
||||
|
||||
if ((intstat & SEQINT) != 0)
|
||||
ahc_handle_seqint(ahc, intstat);
|
||||
|
||||
if ((intstat & SCSIINT) != 0)
|
||||
ahc_handle_scsiint(ahc, intstat);
|
||||
}
|
||||
|
||||
#endif /* _AIC7XXX_INLINE_H_ */
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,416 @@
|
||||
/*
|
||||
* Linux driver attachment glue for PCI based controllers.
|
||||
*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#32 $
|
||||
*/
|
||||
|
||||
#include "aic7xxx_osm.h"
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
struct pci_device_id
|
||||
{
|
||||
};
|
||||
#endif
|
||||
|
||||
static int ahc_linux_pci_dev_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *ent);
|
||||
static int ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
|
||||
u_long *base);
|
||||
#ifdef MMAPIO
|
||||
static int ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
|
||||
u_long *bus_addr,
|
||||
uint8_t **maddr);
|
||||
#endif /* MMAPIO */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
static void ahc_linux_pci_dev_remove(struct pci_dev *pdev);
|
||||
|
||||
/* We do our own ID filtering. So, grab all SCSI storage class devices. */
|
||||
static struct pci_device_id ahc_linux_pci_id_table[] = {
|
||||
{
|
||||
0x9004, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
|
||||
},
|
||||
{
|
||||
0x9005, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_STORAGE_SCSI << 8, 0xFFFF00, 0
|
||||
},
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
|
||||
|
||||
struct pci_driver aic7xxx_pci_driver = {
|
||||
name: "aic7xxx",
|
||||
probe: ahc_linux_pci_dev_probe,
|
||||
remove: ahc_linux_pci_dev_remove,
|
||||
id_table: ahc_linux_pci_id_table
|
||||
};
|
||||
|
||||
static void
|
||||
ahc_linux_pci_dev_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
u_long l;
|
||||
|
||||
/*
|
||||
* We should be able to just perform
|
||||
* the free directly, but check our
|
||||
* list for extra sanity.
|
||||
*/
|
||||
ahc_list_lock(&l);
|
||||
ahc = ahc_find_softc((struct ahc_softc *)pdev->driver_data);
|
||||
if (ahc != NULL) {
|
||||
u_long s;
|
||||
|
||||
ahc_lock(ahc, &s);
|
||||
ahc_intr_enable(ahc, FALSE);
|
||||
ahc_unlock(ahc, &s);
|
||||
ahc_free(ahc);
|
||||
}
|
||||
ahc_list_unlock(&l);
|
||||
}
|
||||
#endif /* !LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) */
|
||||
|
||||
static int
|
||||
ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
{
|
||||
char buf[80];
|
||||
struct ahc_softc *ahc;
|
||||
ahc_dev_softc_t pci;
|
||||
struct ahc_pci_identity *entry;
|
||||
char *name;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* Some BIOSen report the same device multiple times.
|
||||
*/
|
||||
TAILQ_FOREACH(ahc, &ahc_tailq, links) {
|
||||
struct pci_dev *probed_pdev;
|
||||
|
||||
probed_pdev = ahc->dev_softc;
|
||||
if (probed_pdev->bus->number == pdev->bus->number
|
||||
&& probed_pdev->devfn == pdev->devfn)
|
||||
break;
|
||||
}
|
||||
if (ahc != NULL) {
|
||||
/* Skip duplicate. */
|
||||
return (-ENODEV);
|
||||
}
|
||||
|
||||
pci = pdev;
|
||||
entry = ahc_find_pci_device(pci);
|
||||
if (entry == NULL)
|
||||
return (-ENODEV);
|
||||
|
||||
/*
|
||||
* Allocate a softc for this card and
|
||||
* set it up for attachment by our
|
||||
* common detect routine.
|
||||
*/
|
||||
sprintf(buf, "ahc_pci:%d:%d:%d",
|
||||
ahc_get_pci_bus(pci),
|
||||
ahc_get_pci_slot(pci),
|
||||
ahc_get_pci_function(pci));
|
||||
name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
|
||||
if (name == NULL)
|
||||
return (-ENOMEM);
|
||||
strcpy(name, buf);
|
||||
ahc = ahc_alloc(NULL, name);
|
||||
if (ahc == NULL)
|
||||
return (-ENOMEM);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
if (pci_enable_device(pdev)) {
|
||||
ahc_free(ahc);
|
||||
return (-ENODEV);
|
||||
}
|
||||
pci_set_master(pdev);
|
||||
|
||||
if (sizeof(bus_addr_t) > 4
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,3)
|
||||
&& ahc_linux_get_memsize() > 0x80000000
|
||||
&& pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) {
|
||||
#else
|
||||
&& ahc_linux_get_memsize() > 0x80000000) {
|
||||
|
||||
ahc->dev_softc->dma_mask =
|
||||
(bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
|
||||
#endif
|
||||
ahc->flags |= AHC_39BIT_ADDRESSING;
|
||||
ahc->platform_data->hw_dma_mask =
|
||||
(bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0);
|
||||
}
|
||||
#endif
|
||||
ahc->dev_softc = pci;
|
||||
error = ahc_pci_config(ahc, entry);
|
||||
if (error != 0) {
|
||||
ahc_free(ahc);
|
||||
return (-error);
|
||||
}
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
pci_set_drvdata(pdev, ahc);
|
||||
if (aic7xxx_detect_complete)
|
||||
ahc_linux_register_host(ahc, aic7xxx_driver_template);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
ahc_linux_pci_probe(Scsi_Host_Template *template)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
return (pci_module_init(&aic7xxx_pci_driver));
|
||||
#else
|
||||
struct pci_dev *pdev;
|
||||
u_int class;
|
||||
int found;
|
||||
|
||||
/* If we don't have a PCI bus, we can't find any adapters. */
|
||||
if (pci_present() == 0)
|
||||
return (0);
|
||||
|
||||
found = 0;
|
||||
pdev = NULL;
|
||||
class = PCI_CLASS_STORAGE_SCSI << 8;
|
||||
while ((pdev = pci_find_class(class, pdev)) != NULL) {
|
||||
ahc_dev_softc_t pci;
|
||||
int error;
|
||||
|
||||
pci = pdev;
|
||||
error = ahc_linux_pci_dev_probe(pdev, /*pci_devid*/NULL);
|
||||
if (error == 0)
|
||||
found++;
|
||||
}
|
||||
return (found);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
|
||||
*base = pci_resource_start(ahc->dev_softc, 0);
|
||||
#else
|
||||
*base = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS, 4);
|
||||
*base &= PCI_BASE_ADDRESS_IO_MASK;
|
||||
#endif
|
||||
if (*base == 0)
|
||||
return (ENOMEM);
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
|
||||
if (check_region(*base, 256) != 0)
|
||||
return (ENOMEM);
|
||||
else
|
||||
request_region(*base, 256, "aic7xxx");
|
||||
#else
|
||||
if (request_region(*base, 256, "aic7xxx") == 0)
|
||||
return (ENOMEM);
|
||||
#endif
|
||||
return (0);
|
||||
}
|
||||
|
||||
#ifdef MMAPIO
|
||||
static int
|
||||
ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
|
||||
u_long *bus_addr,
|
||||
uint8_t **maddr)
|
||||
{
|
||||
u_long start;
|
||||
u_long base_page;
|
||||
u_long base_offset;
|
||||
int error;
|
||||
|
||||
error = 0;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
|
||||
start = pci_resource_start(ahc->dev_softc, 1);
|
||||
base_page = start & PAGE_MASK;
|
||||
base_offset = start - base_page;
|
||||
#else
|
||||
start = ahc_pci_read_config(ahc->dev_softc, PCIR_MAPS+4, 4);
|
||||
base_offset = start & PCI_BASE_ADDRESS_MEM_MASK;
|
||||
base_page = base_offset & PAGE_MASK;
|
||||
base_offset -= base_page;
|
||||
#endif
|
||||
if (start != 0) {
|
||||
*bus_addr = start;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
|
||||
error = ENOMEM;
|
||||
#endif
|
||||
if (error == 0) {
|
||||
*maddr = ioremap_nocache(base_page, base_offset + 256);
|
||||
if (*maddr == NULL) {
|
||||
error = ENOMEM;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
release_mem_region(start, 0x1000);
|
||||
#endif
|
||||
} else
|
||||
*maddr += base_offset;
|
||||
}
|
||||
} else
|
||||
error = ENOMEM;
|
||||
return (error);
|
||||
}
|
||||
#endif /* MMAPIO */
|
||||
|
||||
int
|
||||
ahc_pci_map_registers(struct ahc_softc *ahc)
|
||||
{
|
||||
uint32_t command;
|
||||
u_long base;
|
||||
uint8_t *maddr;
|
||||
int error;
|
||||
|
||||
/*
|
||||
* If its allowed, we prefer memory mapped access.
|
||||
*/
|
||||
command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
|
||||
command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
|
||||
base = 0;
|
||||
maddr = NULL;
|
||||
#ifdef MMAPIO
|
||||
error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr);
|
||||
if (error == 0) {
|
||||
ahc->platform_data->mem_busaddr = base;
|
||||
ahc->tag = BUS_SPACE_MEMIO;
|
||||
ahc->bsh.maddr = maddr;
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
|
||||
command | PCIM_CMD_MEMEN, 4);
|
||||
|
||||
/*
|
||||
* Do a quick test to see if memory mapped
|
||||
* I/O is functioning correctly.
|
||||
*/
|
||||
if (ahc_inb(ahc, HCNTRL) == 0xFF) {
|
||||
|
||||
printf("aic7xxx: PCI Device %d:%d:%d "
|
||||
"failed memory mapped test\n",
|
||||
ahc_get_pci_bus(ahc->dev_softc),
|
||||
ahc_get_pci_slot(ahc->dev_softc),
|
||||
ahc_get_pci_function(ahc->dev_softc));
|
||||
iounmap((void *)((u_long)maddr & PAGE_MASK));
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
release_mem_region(ahc->platform_data->mem_busaddr,
|
||||
0x1000);
|
||||
#endif
|
||||
ahc->bsh.maddr = NULL;
|
||||
maddr = NULL;
|
||||
} else
|
||||
command |= PCIM_CMD_MEMEN;
|
||||
} else {
|
||||
printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
|
||||
"unavailable. Cannot memory map device.\n",
|
||||
ahc_get_pci_bus(ahc->dev_softc),
|
||||
ahc_get_pci_slot(ahc->dev_softc),
|
||||
ahc_get_pci_function(ahc->dev_softc),
|
||||
base);
|
||||
}
|
||||
#endif /* MMAPIO */
|
||||
|
||||
/*
|
||||
* We always prefer memory mapped access.
|
||||
*/
|
||||
if (maddr == NULL) {
|
||||
|
||||
error = ahc_linux_pci_reserve_io_region(ahc, &base);
|
||||
if (error == 0) {
|
||||
ahc->tag = BUS_SPACE_PIO;
|
||||
ahc->bsh.ioport = base;
|
||||
command |= PCIM_CMD_PORTEN;
|
||||
} else {
|
||||
printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
|
||||
"unavailable. Cannot map device.\n",
|
||||
ahc_get_pci_bus(ahc->dev_softc),
|
||||
ahc_get_pci_slot(ahc->dev_softc),
|
||||
ahc_get_pci_function(ahc->dev_softc),
|
||||
base);
|
||||
}
|
||||
}
|
||||
ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
ahc_pci_map_int(struct ahc_softc *ahc)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = request_irq(ahc->dev_softc->irq, ahc_linux_isr,
|
||||
SA_SHIRQ, "aic7xxx", ahc);
|
||||
if (error == 0)
|
||||
ahc->platform_data->irq = ahc->dev_softc->irq;
|
||||
|
||||
return (-error);
|
||||
}
|
||||
|
||||
void
|
||||
ahc_power_state_change(struct ahc_softc *ahc, ahc_power_state new_state)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
|
||||
pci_set_power_state(ahc->dev_softc, new_state);
|
||||
#else
|
||||
uint32_t cap;
|
||||
u_int cap_offset;
|
||||
|
||||
/*
|
||||
* Traverse the capability list looking for
|
||||
* the power management capability.
|
||||
*/
|
||||
cap = 0;
|
||||
cap_offset = ahc_pci_read_config(ahc->dev_softc,
|
||||
PCIR_CAP_PTR, /*bytes*/1);
|
||||
while (cap_offset != 0) {
|
||||
|
||||
cap = ahc_pci_read_config(ahc->dev_softc,
|
||||
cap_offset, /*bytes*/4);
|
||||
if ((cap & 0xFF) == 1
|
||||
&& ((cap >> 16) & 0x3) > 0) {
|
||||
uint32_t pm_control;
|
||||
|
||||
pm_control = ahc_pci_read_config(ahc->dev_softc,
|
||||
cap_offset + 4,
|
||||
/*bytes*/4);
|
||||
pm_control &= ~0x3;
|
||||
pm_control |= new_state;
|
||||
ahc_pci_write_config(ahc->dev_softc,
|
||||
cap_offset + 4,
|
||||
pm_control, /*bytes*/2);
|
||||
break;
|
||||
}
|
||||
cap_offset = (cap >> 8) & 0xFF;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Copyright (c) 2000-2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
|
||||
* sym driver.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#19 $
|
||||
*/
|
||||
#include "aic7xxx_osm.h"
|
||||
#include "aic7xxx_inline.h"
|
||||
#include "aic7xxx_93cx6.h"
|
||||
|
||||
static void copy_mem_info(struct info_str *info, char *data, int len);
|
||||
static int copy_info(struct info_str *info, char *fmt, ...);
|
||||
static u_int scsi_calc_syncsrate(u_int period_factor);
|
||||
static void ahc_dump_target_state(struct ahc_softc *ahc,
|
||||
struct info_str *info,
|
||||
u_int our_id, char channel,
|
||||
u_int target_id, u_int target_offset);
|
||||
static void ahc_dump_device_state(struct info_str *info,
|
||||
struct ahc_linux_device *dev);
|
||||
static int ahc_proc_write_seeprom(struct ahc_softc *ahc,
|
||||
char *buffer, int length);
|
||||
|
||||
static void
|
||||
copy_mem_info(struct info_str *info, char *data, int len)
|
||||
{
|
||||
if (info->pos + len > info->offset + info->length)
|
||||
len = info->offset + info->length - info->pos;
|
||||
|
||||
if (info->pos + len < info->offset) {
|
||||
info->pos += len;
|
||||
return;
|
||||
}
|
||||
|
||||
if (info->pos < info->offset) {
|
||||
off_t partial;
|
||||
|
||||
partial = info->offset - info->pos;
|
||||
data += partial;
|
||||
info->pos += partial;
|
||||
len -= partial;
|
||||
}
|
||||
|
||||
if (len > 0) {
|
||||
memcpy(info->buffer, data, len);
|
||||
info->pos += len;
|
||||
info->buffer += len;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
copy_info(struct info_str *info, char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
char buf[256];
|
||||
int len;
|
||||
|
||||
va_start(args, fmt);
|
||||
len = vsprintf(buf, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
copy_mem_info(info, buf, len);
|
||||
return (len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Table of syncrates that don't follow the "divisible by 4"
|
||||
* rule. This table will be expanded in future SCSI specs.
|
||||
*/
|
||||
static struct {
|
||||
u_int period_factor;
|
||||
u_int period; /* in 10ths of ns */
|
||||
} scsi_syncrates[] = {
|
||||
{ 0x09, 125 }, /* FAST-80 */
|
||||
{ 0x0a, 250 }, /* FAST-40 40MHz */
|
||||
{ 0x0b, 303 }, /* FAST-40 33MHz */
|
||||
{ 0x0c, 500 } /* FAST-20 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Return the frequency in kHz corresponding to the given
|
||||
* sync period factor.
|
||||
*/
|
||||
static u_int
|
||||
scsi_calc_syncsrate(u_int period_factor)
|
||||
{
|
||||
int i;
|
||||
int num_syncrates;
|
||||
|
||||
num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
|
||||
/* See if the period is in the "exception" table */
|
||||
for (i = 0; i < num_syncrates; i++) {
|
||||
|
||||
if (period_factor == scsi_syncrates[i].period_factor) {
|
||||
/* Period in kHz */
|
||||
return (10000000 / scsi_syncrates[i].period);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Wasn't in the table, so use the standard
|
||||
* 4 times conversion.
|
||||
*/
|
||||
return (10000000 / (period_factor * 4 * 10));
|
||||
}
|
||||
|
||||
void
|
||||
ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
|
||||
{
|
||||
u_int speed;
|
||||
u_int freq;
|
||||
u_int mb;
|
||||
|
||||
speed = 3300;
|
||||
freq = 0;
|
||||
if (tinfo->offset != 0) {
|
||||
freq = scsi_calc_syncsrate(tinfo->period);
|
||||
speed = freq;
|
||||
}
|
||||
speed *= (0x01 << tinfo->width);
|
||||
mb = speed / 1000;
|
||||
if (mb > 0)
|
||||
copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
|
||||
else
|
||||
copy_info(info, "%dKB/s transfers", speed);
|
||||
|
||||
if (freq != 0) {
|
||||
copy_info(info, " (%d.%03dMHz%s, offset %d",
|
||||
freq / 1000, freq % 1000,
|
||||
(tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
|
||||
? " DT" : "", tinfo->offset);
|
||||
}
|
||||
|
||||
if (tinfo->width > 0) {
|
||||
if (freq != 0) {
|
||||
copy_info(info, ", ");
|
||||
} else {
|
||||
copy_info(info, " (");
|
||||
}
|
||||
copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
|
||||
} else if (freq != 0) {
|
||||
copy_info(info, ")");
|
||||
}
|
||||
copy_info(info, "\n");
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
|
||||
u_int our_id, char channel, u_int target_id,
|
||||
u_int target_offset)
|
||||
{
|
||||
struct ahc_linux_target *targ;
|
||||
struct ahc_initiator_tinfo *tinfo;
|
||||
struct ahc_tmode_tstate *tstate;
|
||||
int lun;
|
||||
|
||||
tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
|
||||
target_id, &tstate);
|
||||
copy_info(info, "Channel %c Target %d Negotiation Settings\n",
|
||||
channel, target_id);
|
||||
copy_info(info, "\tUser: ");
|
||||
ahc_format_transinfo(info, &tinfo->user);
|
||||
targ = ahc->platform_data->targets[target_offset];
|
||||
if (targ == NULL)
|
||||
return;
|
||||
|
||||
copy_info(info, "\tGoal: ");
|
||||
ahc_format_transinfo(info, &tinfo->goal);
|
||||
copy_info(info, "\tCurr: ");
|
||||
ahc_format_transinfo(info, &tinfo->curr);
|
||||
|
||||
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
|
||||
struct ahc_linux_device *dev;
|
||||
|
||||
dev = targ->devices[lun];
|
||||
|
||||
if (dev == NULL)
|
||||
continue;
|
||||
|
||||
ahc_dump_device_state(info, dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
|
||||
{
|
||||
copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
|
||||
dev->target->channel + 'A', dev->target->target, dev->lun);
|
||||
|
||||
copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
|
||||
copy_info(info, "\t\tCommands Active %d\n", dev->active);
|
||||
copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
|
||||
copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
|
||||
copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
|
||||
}
|
||||
|
||||
static int
|
||||
ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
|
||||
{
|
||||
struct seeprom_descriptor sd;
|
||||
int have_seeprom;
|
||||
u_long s;
|
||||
int paused;
|
||||
int written;
|
||||
|
||||
/* Default to failure. */
|
||||
written = -EINVAL;
|
||||
ahc_lock(ahc, &s);
|
||||
paused = ahc_is_paused(ahc);
|
||||
if (!paused)
|
||||
ahc_pause(ahc);
|
||||
|
||||
if (length != sizeof(struct seeprom_config)) {
|
||||
printf("ahc_proc_write_seeprom: incorrect buffer size\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
|
||||
if (have_seeprom == 0) {
|
||||
printf("ahc_proc_write_seeprom: cksum verification failed\n");
|
||||
goto done;
|
||||
}
|
||||
|
||||
sd.sd_ahc = ahc;
|
||||
if ((ahc->chip & AHC_VL) != 0) {
|
||||
sd.sd_control_offset = SEECTL_2840;
|
||||
sd.sd_status_offset = STATUS_2840;
|
||||
sd.sd_dataout_offset = STATUS_2840;
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = 0;
|
||||
sd.sd_RDY = EEPROM_TF;
|
||||
sd.sd_CS = CS_2840;
|
||||
sd.sd_CK = CK_2840;
|
||||
sd.sd_DO = DO_2840;
|
||||
sd.sd_DI = DI_2840;
|
||||
have_seeprom = TRUE;
|
||||
} else {
|
||||
sd.sd_control_offset = SEECTL;
|
||||
sd.sd_status_offset = SEECTL;
|
||||
sd.sd_dataout_offset = SEECTL;
|
||||
if (ahc->flags & AHC_LARGE_SEEPROM)
|
||||
sd.sd_chip = C56_66;
|
||||
else
|
||||
sd.sd_chip = C46;
|
||||
sd.sd_MS = SEEMS;
|
||||
sd.sd_RDY = SEERDY;
|
||||
sd.sd_CS = SEECS;
|
||||
sd.sd_CK = SEECK;
|
||||
sd.sd_DO = SEEDO;
|
||||
sd.sd_DI = SEEDI;
|
||||
have_seeprom = ahc_acquire_seeprom(ahc, &sd);
|
||||
}
|
||||
|
||||
if (!have_seeprom) {
|
||||
printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
|
||||
goto done;
|
||||
} else {
|
||||
u_int start_addr;
|
||||
|
||||
if (ahc->seep_config == NULL) {
|
||||
ahc->seep_config = malloc(sizeof(*ahc->seep_config),
|
||||
M_DEVBUF, M_NOWAIT);
|
||||
if (ahc->seep_config == NULL) {
|
||||
printf("aic7xxx: Unable to allocate serial "
|
||||
"eeprom buffer. Write failing\n");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
printf("aic7xxx: Writing Serial EEPROM\n");
|
||||
start_addr = 32 * (ahc->channel - 'A');
|
||||
ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
|
||||
sizeof(struct seeprom_config)/2);
|
||||
ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config,
|
||||
start_addr, sizeof(struct seeprom_config)/2);
|
||||
if ((ahc->chip & AHC_VL) == 0)
|
||||
ahc_release_seeprom(&sd);
|
||||
written = length;
|
||||
}
|
||||
|
||||
done:
|
||||
if (!paused)
|
||||
ahc_unpause(ahc);
|
||||
ahc_unlock(ahc, &s);
|
||||
return (written);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return information to handle /proc support for the driver.
|
||||
*/
|
||||
int
|
||||
ahc_linux_proc_info(char *buffer, char **start, off_t offset,
|
||||
int length, int hostno, int inout)
|
||||
{
|
||||
struct ahc_softc *ahc;
|
||||
struct info_str info;
|
||||
char ahc_info[256];
|
||||
u_long s;
|
||||
u_int max_targ;
|
||||
u_int i;
|
||||
int retval;
|
||||
|
||||
retval = -EINVAL;
|
||||
ahc_list_lock(&s);
|
||||
TAILQ_FOREACH(ahc, &ahc_tailq, links) {
|
||||
if (ahc->platform_data->host->host_no == hostno)
|
||||
break;
|
||||
}
|
||||
|
||||
if (ahc == NULL)
|
||||
goto done;
|
||||
|
||||
/* Has data been written to the file? */
|
||||
if (inout == TRUE) {
|
||||
retval = ahc_proc_write_seeprom(ahc, buffer, length);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (start)
|
||||
*start = buffer;
|
||||
|
||||
info.buffer = buffer;
|
||||
info.length = length;
|
||||
info.offset = offset;
|
||||
info.pos = 0;
|
||||
|
||||
copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
|
||||
AIC7XXX_DRIVER_VERSION);
|
||||
ahc_controller_info(ahc, ahc_info);
|
||||
copy_info(&info, "%s\n\n", ahc_info);
|
||||
|
||||
if (ahc->seep_config == NULL)
|
||||
copy_info(&info, "No Serial EEPROM\n");
|
||||
else {
|
||||
copy_info(&info, "Serial EEPROM:\n");
|
||||
for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
|
||||
if (((i % 8) == 0) && (i != 0)) {
|
||||
copy_info(&info, "\n");
|
||||
}
|
||||
copy_info(&info, "0x%.4x ",
|
||||
((uint16_t*)ahc->seep_config)[i]);
|
||||
}
|
||||
copy_info(&info, "\n");
|
||||
}
|
||||
copy_info(&info, "\n");
|
||||
|
||||
max_targ = 15;
|
||||
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
|
||||
max_targ = 7;
|
||||
|
||||
for (i = 0; i <= max_targ; i++) {
|
||||
u_int our_id;
|
||||
u_int target_id;
|
||||
char channel;
|
||||
|
||||
channel = 'A';
|
||||
our_id = ahc->our_id;
|
||||
target_id = i;
|
||||
if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
|
||||
channel = 'B';
|
||||
our_id = ahc->our_id_b;
|
||||
target_id = i % 8;
|
||||
}
|
||||
|
||||
ahc_dump_target_state(ahc, &info, our_id,
|
||||
channel, target_id, i);
|
||||
}
|
||||
retval = info.pos > info.offset ? info.pos - info.offset : 0;
|
||||
done:
|
||||
ahc_list_unlock(&s);
|
||||
return (retval);
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
/*
|
||||
* DO NOT EDIT - This file is automatically generated
|
||||
* from the following source files:
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#43 $
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#30 $
|
||||
*/
|
||||
|
||||
#define SCSISEQ 0x00
|
||||
#define TEMODE 0x80
|
||||
#define SCSIRSTO 0x01
|
||||
|
||||
#define SXFRCTL0 0x01
|
||||
#define DFON 0x80
|
||||
#define DFPEXP 0x40
|
||||
#define FAST20 0x20
|
||||
#define CLRSTCNT 0x10
|
||||
#define SPIOEN 0x08
|
||||
#define SCAMEN 0x04
|
||||
#define CLRCHN 0x02
|
||||
|
||||
#define SXFRCTL1 0x02
|
||||
#define BITBUCKET 0x80
|
||||
#define SWRAPEN 0x40
|
||||
#define STIMESEL 0x18
|
||||
#define ENSTIMER 0x04
|
||||
#define ACTNEGEN 0x02
|
||||
#define STPWEN 0x01
|
||||
|
||||
#define SCSISIGO 0x03
|
||||
#define CDO 0x80
|
||||
#define IOO 0x40
|
||||
#define MSGO 0x20
|
||||
#define ATNO 0x10
|
||||
#define SELO 0x08
|
||||
#define BSYO 0x04
|
||||
#define REQO 0x02
|
||||
#define ACKO 0x01
|
||||
|
||||
#define SCSISIGI 0x03
|
||||
#define P_DATAIN_DT 0x60
|
||||
#define P_DATAOUT_DT 0x20
|
||||
#define ATNI 0x10
|
||||
#define SELI 0x08
|
||||
#define BSYI 0x04
|
||||
#define REQI 0x02
|
||||
#define ACKI 0x01
|
||||
|
||||
#define SCSIRATE 0x04
|
||||
#define WIDEXFER 0x80
|
||||
#define SXFR 0x70
|
||||
#define ENABLE_CRC 0x40
|
||||
#define SINGLE_EDGE 0x10
|
||||
#define SOFS 0x0f
|
||||
#define SXFR_ULTRA2 0x0f
|
||||
|
||||
#define SCSIID 0x05
|
||||
#define SCSIOFFSET 0x05
|
||||
#define SOFS_ULTRA2 0x7f
|
||||
|
||||
#define SCSIDATL 0x06
|
||||
|
||||
#define SCSIDATH 0x07
|
||||
|
||||
#define STCNT 0x08
|
||||
|
||||
#define OPTIONMODE 0x08
|
||||
#define AUTORATEEN 0x80
|
||||
#define AUTOACKEN 0x40
|
||||
#define ATNMGMNTEN 0x20
|
||||
#define BUSFREEREV 0x10
|
||||
#define EXPPHASEDIS 0x08
|
||||
#define SCSIDATL_IMGEN 0x04
|
||||
#define OPTIONMODE_DEFAULTS 0x03
|
||||
#define AUTO_MSGOUT_DE 0x02
|
||||
#define DIS_MSGIN_DUALEDGE 0x01
|
||||
|
||||
#define TARGCRCCNT 0x0a
|
||||
|
||||
#define CLRSINT0 0x0b
|
||||
#define CLRSELDO 0x40
|
||||
#define CLRSELDI 0x20
|
||||
#define CLRSELINGO 0x10
|
||||
#define CLRIOERR 0x08
|
||||
#define CLRSWRAP 0x08
|
||||
#define CLRSPIORDY 0x02
|
||||
|
||||
#define SSTAT0 0x0b
|
||||
#define TARGET 0x80
|
||||
#define SELDO 0x40
|
||||
#define SELDI 0x20
|
||||
#define SELINGO 0x10
|
||||
#define SWRAP 0x08
|
||||
#define IOERR 0x08
|
||||
#define SDONE 0x04
|
||||
#define SPIORDY 0x02
|
||||
#define DMADONE 0x01
|
||||
|
||||
#define CLRSINT1 0x0c
|
||||
#define CLRSELTIMEO 0x80
|
||||
#define CLRATNO 0x40
|
||||
#define CLRSCSIRSTI 0x20
|
||||
#define CLRBUSFREE 0x08
|
||||
#define CLRSCSIPERR 0x04
|
||||
#define CLRPHASECHG 0x02
|
||||
#define CLRREQINIT 0x01
|
||||
|
||||
#define SSTAT1 0x0c
|
||||
#define SELTO 0x80
|
||||
#define ATNTARG 0x40
|
||||
#define SCSIRSTI 0x20
|
||||
#define PHASEMIS 0x10
|
||||
#define BUSFREE 0x08
|
||||
#define SCSIPERR 0x04
|
||||
#define PHASECHG 0x02
|
||||
#define REQINIT 0x01
|
||||
|
||||
#define SSTAT2 0x0d
|
||||
#define OVERRUN 0x80
|
||||
#define SHVALID 0x40
|
||||
#define SFCNT 0x1f
|
||||
#define EXP_ACTIVE 0x10
|
||||
#define CRCVALERR 0x08
|
||||
#define CRCENDERR 0x04
|
||||
#define CRCREQERR 0x02
|
||||
#define DUAL_EDGE_ERR 0x01
|
||||
|
||||
#define SSTAT3 0x0e
|
||||
#define SCSICNT 0xf0
|
||||
#define U2OFFCNT 0x7f
|
||||
#define OFFCNT 0x0f
|
||||
|
||||
#define SCSIID_ULTRA2 0x0f
|
||||
|
||||
#define SIMODE0 0x10
|
||||
#define ENSELDO 0x40
|
||||
#define ENSELDI 0x20
|
||||
#define ENSELINGO 0x10
|
||||
#define ENIOERR 0x08
|
||||
#define ENSWRAP 0x08
|
||||
#define ENSDONE 0x04
|
||||
#define ENSPIORDY 0x02
|
||||
#define ENDMADONE 0x01
|
||||
|
||||
#define SIMODE1 0x11
|
||||
#define ENSELTIMO 0x80
|
||||
#define ENATNTARG 0x40
|
||||
#define ENSCSIRST 0x20
|
||||
#define ENPHASEMIS 0x10
|
||||
#define ENBUSFREE 0x08
|
||||
#define ENSCSIPERR 0x04
|
||||
#define ENPHASECHG 0x02
|
||||
#define ENREQINIT 0x01
|
||||
|
||||
#define SCSIBUSL 0x12
|
||||
|
||||
#define SCSIBUSH 0x13
|
||||
|
||||
#define SHADDR 0x14
|
||||
|
||||
#define SELTIMER 0x18
|
||||
#define TARGIDIN 0x18
|
||||
#define STAGE6 0x20
|
||||
#define STAGE5 0x10
|
||||
#define STAGE4 0x08
|
||||
#define STAGE3 0x04
|
||||
#define STAGE2 0x02
|
||||
#define STAGE1 0x01
|
||||
|
||||
#define SELID 0x19
|
||||
#define SELID_MASK 0xf0
|
||||
#define ONEBIT 0x08
|
||||
|
||||
#define SCAMCTL 0x1a
|
||||
#define ENSCAMSELO 0x80
|
||||
#define CLRSCAMSELID 0x40
|
||||
#define ALTSTIM 0x20
|
||||
#define DFLTTID 0x10
|
||||
#define SCAMLVL 0x03
|
||||
|
||||
#define TARGID 0x1b
|
||||
|
||||
#define SPIOCAP 0x1b
|
||||
#define SOFT1 0x80
|
||||
#define SOFT0 0x40
|
||||
#define SOFTCMDEN 0x20
|
||||
#define EXT_BRDCTL 0x10
|
||||
#define SEEPROM 0x08
|
||||
#define EEPROM 0x04
|
||||
#define ROM 0x02
|
||||
#define SSPIOCPS 0x01
|
||||
|
||||
#define BRDCTL 0x1d
|
||||
#define BRDDAT7 0x80
|
||||
#define BRDDAT6 0x40
|
||||
#define BRDDAT5 0x20
|
||||
#define BRDDAT4 0x10
|
||||
#define BRDSTB 0x10
|
||||
#define BRDDAT3 0x08
|
||||
#define BRDCS 0x08
|
||||
#define BRDDAT2 0x04
|
||||
#define BRDRW 0x04
|
||||
#define BRDRW_ULTRA2 0x02
|
||||
#define BRDCTL1 0x02
|
||||
#define BRDCTL0 0x01
|
||||
#define BRDSTB_ULTRA2 0x01
|
||||
|
||||
#define SEECTL 0x1e
|
||||
#define EXTARBACK 0x80
|
||||
#define EXTARBREQ 0x40
|
||||
#define SEEMS 0x20
|
||||
#define SEERDY 0x10
|
||||
#define SEECS 0x08
|
||||
#define SEECK 0x04
|
||||
#define SEEDO 0x02
|
||||
#define SEEDI 0x01
|
||||
|
||||
#define SBLKCTL 0x1f
|
||||
#define DIAGLEDEN 0x80
|
||||
#define DIAGLEDON 0x40
|
||||
#define AUTOFLUSHDIS 0x20
|
||||
#define ENAB40 0x08
|
||||
#define SELBUSB 0x08
|
||||
#define ENAB20 0x04
|
||||
#define SELWIDE 0x02
|
||||
#define XCVR 0x01
|
||||
|
||||
#define BUSY_TARGETS 0x20
|
||||
#define TARG_SCSIRATE 0x20
|
||||
|
||||
#define ULTRA_ENB 0x30
|
||||
#define CMDSIZE_TABLE 0x30
|
||||
|
||||
#define DISC_DSB 0x32
|
||||
|
||||
#define CMDSIZE_TABLE_TAIL 0x34
|
||||
|
||||
#define MWI_RESIDUAL 0x38
|
||||
|
||||
#define NEXT_QUEUED_SCB 0x39
|
||||
|
||||
#define MSG_OUT 0x3a
|
||||
|
||||
#define DMAPARAMS 0x3b
|
||||
#define PRELOADEN 0x80
|
||||
#define WIDEODD 0x40
|
||||
#define SCSIEN 0x20
|
||||
#define SDMAEN 0x10
|
||||
#define SDMAENACK 0x10
|
||||
#define HDMAEN 0x08
|
||||
#define HDMAENACK 0x08
|
||||
#define DIRECTION 0x04
|
||||
#define FIFOFLUSH 0x02
|
||||
#define FIFORESET 0x01
|
||||
|
||||
#define SEQ_FLAGS 0x3c
|
||||
#define IDENTIFY_SEEN 0x80
|
||||
#define TARGET_CMD_IS_TAGGED 0x40
|
||||
#define DPHASE 0x20
|
||||
#define TARG_CMD_PENDING 0x10
|
||||
#define CMDPHASE_PENDING 0x08
|
||||
#define DPHASE_PENDING 0x04
|
||||
#define SPHASE_PENDING 0x02
|
||||
#define NO_DISCONNECT 0x01
|
||||
|
||||
#define SAVED_SCSIID 0x3d
|
||||
|
||||
#define SAVED_LUN 0x3e
|
||||
|
||||
#define LASTPHASE 0x3f
|
||||
#define P_MESGIN 0xe0
|
||||
#define PHASE_MASK 0xe0
|
||||
#define P_STATUS 0xc0
|
||||
#define P_MESGOUT 0xa0
|
||||
#define P_COMMAND 0x80
|
||||
#define CDI 0x80
|
||||
#define P_DATAIN 0x40
|
||||
#define IOI 0x40
|
||||
#define MSGI 0x20
|
||||
#define P_BUSFREE 0x01
|
||||
#define P_DATAOUT 0x00
|
||||
|
||||
#define WAITING_SCBH 0x40
|
||||
|
||||
#define DISCONNECTED_SCBH 0x41
|
||||
|
||||
#define FREE_SCBH 0x42
|
||||
|
||||
#define COMPLETE_SCBH 0x43
|
||||
|
||||
#define HSCB_ADDR 0x44
|
||||
|
||||
#define SHARED_DATA_ADDR 0x48
|
||||
|
||||
#define KERNEL_QINPOS 0x4c
|
||||
|
||||
#define QINPOS 0x4d
|
||||
|
||||
#define QOUTPOS 0x4e
|
||||
|
||||
#define KERNEL_TQINPOS 0x4f
|
||||
|
||||
#define TQINPOS 0x50
|
||||
|
||||
#define ARG_1 0x51
|
||||
#define RETURN_1 0x51
|
||||
#define SEND_MSG 0x80
|
||||
#define SEND_SENSE 0x40
|
||||
#define SEND_REJ 0x20
|
||||
#define MSGOUT_PHASEMIS 0x10
|
||||
#define EXIT_MSG_LOOP 0x08
|
||||
#define CONT_MSG_LOOP 0x04
|
||||
#define CONT_TARG_SESSION 0x02
|
||||
|
||||
#define ARG_2 0x52
|
||||
#define RETURN_2 0x52
|
||||
|
||||
#define LAST_MSG 0x53
|
||||
|
||||
#define SCSISEQ_TEMPLATE 0x54
|
||||
#define ENSELO 0x40
|
||||
#define ENSELI 0x20
|
||||
#define ENRSELI 0x10
|
||||
#define ENAUTOATNO 0x08
|
||||
#define ENAUTOATNI 0x04
|
||||
#define ENAUTOATNP 0x02
|
||||
|
||||
#define DATA_COUNT_ODD 0x55
|
||||
|
||||
#define HA_274_BIOSGLOBAL 0x56
|
||||
#define INITIATOR_TAG 0x56
|
||||
#define HA_274_EXTENDED_TRANS 0x01
|
||||
|
||||
#define SEQ_FLAGS2 0x57
|
||||
#define TARGET_MSG_PENDING 0x02
|
||||
#define SCB_DMA 0x01
|
||||
|
||||
#define SCSICONF 0x5a
|
||||
#define TERM_ENB 0x80
|
||||
#define RESET_SCSI 0x40
|
||||
#define ENSPCHK 0x20
|
||||
#define HWSCSIID 0x0f
|
||||
#define HSCSIID 0x07
|
||||
|
||||
#define INTDEF 0x5c
|
||||
#define EDGE_TRIG 0x80
|
||||
#define VECTOR 0x0f
|
||||
|
||||
#define HOSTCONF 0x5d
|
||||
|
||||
#define HA_274_BIOSCTRL 0x5f
|
||||
#define BIOSDISABLED 0x30
|
||||
#define BIOSMODE 0x30
|
||||
#define CHANNEL_B_PRIMARY 0x08
|
||||
|
||||
#define SEQCTL 0x60
|
||||
#define PERRORDIS 0x80
|
||||
#define PAUSEDIS 0x40
|
||||
#define FAILDIS 0x20
|
||||
#define FASTMODE 0x10
|
||||
#define BRKADRINTEN 0x08
|
||||
#define STEP 0x04
|
||||
#define SEQRESET 0x02
|
||||
#define LOADRAM 0x01
|
||||
|
||||
#define SEQRAM 0x61
|
||||
|
||||
#define SEQADDR0 0x62
|
||||
|
||||
#define SEQADDR1 0x63
|
||||
#define SEQADDR1_MASK 0x01
|
||||
|
||||
#define ACCUM 0x64
|
||||
|
||||
#define SINDEX 0x65
|
||||
|
||||
#define DINDEX 0x66
|
||||
|
||||
#define ALLONES 0x69
|
||||
|
||||
#define ALLZEROS 0x6a
|
||||
|
||||
#define NONE 0x6a
|
||||
|
||||
#define FLAGS 0x6b
|
||||
#define ZERO 0x02
|
||||
#define CARRY 0x01
|
||||
|
||||
#define SINDIR 0x6c
|
||||
|
||||
#define DINDIR 0x6d
|
||||
|
||||
#define FUNCTION1 0x6e
|
||||
|
||||
#define STACK 0x6f
|
||||
|
||||
#define TARG_OFFSET 0x70
|
||||
|
||||
#define SRAM_BASE 0x70
|
||||
|
||||
#define BCTL 0x84
|
||||
#define ACE 0x08
|
||||
#define ENABLE 0x01
|
||||
|
||||
#define DSCOMMAND0 0x84
|
||||
#define CACHETHEN 0x80
|
||||
#define DPARCKEN 0x40
|
||||
#define MPARCKEN 0x20
|
||||
#define EXTREQLCK 0x10
|
||||
#define INTSCBRAMSEL 0x08
|
||||
#define RAMPS 0x04
|
||||
#define USCBSIZE32 0x02
|
||||
#define CIOPARCKEN 0x01
|
||||
|
||||
#define BUSTIME 0x85
|
||||
#define BOFF 0xf0
|
||||
#define BON 0x0f
|
||||
|
||||
#define DSCOMMAND1 0x85
|
||||
#define DSLATT 0xfc
|
||||
#define HADDLDSEL1 0x02
|
||||
#define HADDLDSEL0 0x01
|
||||
|
||||
#define BUSSPD 0x86
|
||||
#define DFTHRSH 0xc0
|
||||
#define DFTHRSH_75 0x80
|
||||
#define STBOFF 0x38
|
||||
#define STBON 0x07
|
||||
|
||||
#define HS_MAILBOX 0x86
|
||||
#define HOST_MAILBOX 0xf0
|
||||
#define HOST_TQINPOS 0x80
|
||||
#define SEQ_MAILBOX 0x0f
|
||||
|
||||
#define DSPCISTATUS 0x86
|
||||
#define DFTHRSH_100 0xc0
|
||||
|
||||
#define HCNTRL 0x87
|
||||
#define POWRDN 0x40
|
||||
#define SWINT 0x10
|
||||
#define IRQMS 0x08
|
||||
#define PAUSE 0x04
|
||||
#define INTEN 0x02
|
||||
#define CHIPRST 0x01
|
||||
#define CHIPRSTACK 0x01
|
||||
|
||||
#define HADDR 0x88
|
||||
|
||||
#define HCNT 0x8c
|
||||
|
||||
#define SCBPTR 0x90
|
||||
|
||||
#define INTSTAT 0x91
|
||||
#define SEQINT_MASK 0xf1
|
||||
#define OUT_OF_RANGE 0xe1
|
||||
#define NO_FREE_SCB 0xd1
|
||||
#define SCB_MISMATCH 0xc1
|
||||
#define MISSED_BUSFREE 0xb1
|
||||
#define MKMSG_FAILED 0xa1
|
||||
#define DATA_OVERRUN 0x91
|
||||
#define PERR_DETECTED 0x81
|
||||
#define BAD_STATUS 0x71
|
||||
#define HOST_MSG_LOOP 0x61
|
||||
#define PDATA_REINIT 0x51
|
||||
#define IGN_WIDE_RES 0x41
|
||||
#define NO_MATCH 0x31
|
||||
#define NO_IDENT 0x21
|
||||
#define SEND_REJECT 0x11
|
||||
#define INT_PEND 0x0f
|
||||
#define BRKADRINT 0x08
|
||||
#define SCSIINT 0x04
|
||||
#define CMDCMPLT 0x02
|
||||
#define BAD_PHASE 0x01
|
||||
#define SEQINT 0x01
|
||||
|
||||
#define CLRINT 0x92
|
||||
#define CLRPARERR 0x10
|
||||
#define CLRBRKADRINT 0x08
|
||||
#define CLRSCSIINT 0x04
|
||||
#define CLRCMDINT 0x02
|
||||
#define CLRSEQINT 0x01
|
||||
|
||||
#define ERROR 0x92
|
||||
#define CIOPARERR 0x80
|
||||
#define PCIERRSTAT 0x40
|
||||
#define MPARERR 0x20
|
||||
#define DPARERR 0x10
|
||||
#define SQPARERR 0x08
|
||||
#define ILLOPCODE 0x04
|
||||
#define ILLSADDR 0x02
|
||||
#define ILLHADDR 0x01
|
||||
|
||||
#define DFCNTRL 0x93
|
||||
|
||||
#define DFSTATUS 0x94
|
||||
#define PRELOAD_AVAIL 0x80
|
||||
#define DFCACHETH 0x40
|
||||
#define FIFOQWDEMP 0x20
|
||||
#define MREQPEND 0x10
|
||||
#define HDONE 0x08
|
||||
#define DFTHRESH 0x04
|
||||
#define FIFOFULL 0x02
|
||||
#define FIFOEMP 0x01
|
||||
|
||||
#define DFWADDR 0x95
|
||||
|
||||
#define DFRADDR 0x97
|
||||
|
||||
#define DFDAT 0x99
|
||||
|
||||
#define SCBCNT 0x9a
|
||||
#define SCBAUTO 0x80
|
||||
#define SCBCNT_MASK 0x1f
|
||||
|
||||
#define QINFIFO 0x9b
|
||||
|
||||
#define QINCNT 0x9c
|
||||
|
||||
#define QOUTFIFO 0x9d
|
||||
|
||||
#define CRCCONTROL1 0x9d
|
||||
#define CRCONSEEN 0x80
|
||||
#define CRCVALCHKEN 0x40
|
||||
#define CRCENDCHKEN 0x20
|
||||
#define CRCREQCHKEN 0x10
|
||||
#define TARGCRCENDEN 0x08
|
||||
#define TARGCRCCNTEN 0x04
|
||||
|
||||
#define QOUTCNT 0x9e
|
||||
|
||||
#define SCSIPHASE 0x9e
|
||||
#define STATUS_PHASE 0x20
|
||||
#define COMMAND_PHASE 0x10
|
||||
#define MSG_IN_PHASE 0x08
|
||||
#define MSG_OUT_PHASE 0x04
|
||||
#define DATA_PHASE_MASK 0x03
|
||||
#define DATA_IN_PHASE 0x02
|
||||
#define DATA_OUT_PHASE 0x01
|
||||
|
||||
#define SFUNCT 0x9f
|
||||
#define ALT_MODE 0x80
|
||||
|
||||
#define SCB_BASE 0xa0
|
||||
|
||||
#define SCB_CDB_PTR 0xa0
|
||||
#define SCB_RESIDUAL_DATACNT 0xa0
|
||||
#define SCB_CDB_STORE 0xa0
|
||||
|
||||
#define SCB_RESIDUAL_SGPTR 0xa4
|
||||
|
||||
#define SCB_SCSI_STATUS 0xa8
|
||||
|
||||
#define SCB_TARGET_PHASES 0xa9
|
||||
|
||||
#define SCB_TARGET_DATA_DIR 0xaa
|
||||
|
||||
#define SCB_TARGET_ITAG 0xab
|
||||
|
||||
#define SCB_DATAPTR 0xac
|
||||
|
||||
#define SCB_DATACNT 0xb0
|
||||
#define SG_LAST_SEG 0x80
|
||||
#define SG_HIGH_ADDR_BITS 0x7f
|
||||
|
||||
#define SCB_SGPTR 0xb4
|
||||
#define SG_RESID_VALID 0x04
|
||||
#define SG_FULL_RESID 0x02
|
||||
#define SG_LIST_NULL 0x01
|
||||
|
||||
#define SCB_CONTROL 0xb8
|
||||
#define TARGET_SCB 0x80
|
||||
#define DISCENB 0x40
|
||||
#define TAG_ENB 0x20
|
||||
#define MK_MESSAGE 0x10
|
||||
#define ULTRAENB 0x08
|
||||
#define DISCONNECTED 0x04
|
||||
#define SCB_TAG_TYPE 0x03
|
||||
|
||||
#define SCB_SCSIID 0xb9
|
||||
#define TID 0xf0
|
||||
#define TWIN_CHNLB 0x80
|
||||
#define TWIN_TID 0x70
|
||||
#define OID 0x0f
|
||||
|
||||
#define SCB_LUN 0xba
|
||||
#define LID 0xff
|
||||
|
||||
#define SCB_TAG 0xbb
|
||||
|
||||
#define SCB_CDB_LEN 0xbc
|
||||
|
||||
#define SCB_SCSIRATE 0xbd
|
||||
|
||||
#define SCB_SCSIOFFSET 0xbe
|
||||
|
||||
#define SCB_NEXT 0xbf
|
||||
|
||||
#define SCB_64_SPARE 0xc0
|
||||
|
||||
#define SEECTL_2840 0xc0
|
||||
#define CS_2840 0x04
|
||||
#define CK_2840 0x02
|
||||
#define DO_2840 0x01
|
||||
|
||||
#define STATUS_2840 0xc1
|
||||
#define EEPROM_TF 0x80
|
||||
#define BIOS_SEL 0x60
|
||||
#define ADSEL 0x1e
|
||||
#define DI_2840 0x01
|
||||
|
||||
#define SCB_64_BTT 0xd0
|
||||
|
||||
#define CCHADDR 0xe0
|
||||
|
||||
#define CCHCNT 0xe8
|
||||
|
||||
#define CCSGRAM 0xe9
|
||||
|
||||
#define CCSGADDR 0xea
|
||||
|
||||
#define CCSGCTL 0xeb
|
||||
#define CCSGDONE 0x80
|
||||
#define CCSGEN 0x08
|
||||
#define SG_FETCH_NEEDED 0x02
|
||||
#define CCSGRESET 0x01
|
||||
|
||||
#define CCSCBRAM 0xec
|
||||
|
||||
#define CCSCBADDR 0xed
|
||||
|
||||
#define CCSCBCTL 0xee
|
||||
#define CCSCBDONE 0x80
|
||||
#define ARRDONE 0x40
|
||||
#define CCARREN 0x10
|
||||
#define CCSCBEN 0x08
|
||||
#define CCSCBDIR 0x04
|
||||
#define CCSCBRESET 0x01
|
||||
|
||||
#define CCSCBCNT 0xef
|
||||
|
||||
#define SCBBADDR 0xf0
|
||||
|
||||
#define CCSCBPTR 0xf1
|
||||
|
||||
#define HNSCB_QOFF 0xf4
|
||||
|
||||
#define SNSCB_QOFF 0xf6
|
||||
|
||||
#define SDSCB_QOFF 0xf8
|
||||
|
||||
#define QOFF_CTLSTA 0xfa
|
||||
#define SCB_AVAIL 0x40
|
||||
#define SNSCB_ROLLOVER 0x20
|
||||
#define SDSCB_ROLLOVER 0x10
|
||||
#define SCB_QSIZE 0x07
|
||||
#define SCB_QSIZE_256 0x06
|
||||
|
||||
#define DFF_THRSH 0xfb
|
||||
#define WR_DFTHRSH 0x70
|
||||
#define WR_DFTHRSH_MAX 0x70
|
||||
#define WR_DFTHRSH_90 0x60
|
||||
#define WR_DFTHRSH_85 0x50
|
||||
#define WR_DFTHRSH_75 0x40
|
||||
#define WR_DFTHRSH_63 0x30
|
||||
#define WR_DFTHRSH_50 0x20
|
||||
#define WR_DFTHRSH_25 0x10
|
||||
#define RD_DFTHRSH 0x07
|
||||
#define RD_DFTHRSH_MAX 0x07
|
||||
#define RD_DFTHRSH_90 0x06
|
||||
#define RD_DFTHRSH_85 0x05
|
||||
#define RD_DFTHRSH_75 0x04
|
||||
#define RD_DFTHRSH_63 0x03
|
||||
#define RD_DFTHRSH_50 0x02
|
||||
#define RD_DFTHRSH_25 0x01
|
||||
#define RD_DFTHRSH_MIN 0x00
|
||||
#define WR_DFTHRSH_MIN 0x00
|
||||
|
||||
#define SG_CACHE_SHADOW 0xfc
|
||||
#define SG_ADDR_MASK 0xf8
|
||||
#define ODD_SEG 0x04
|
||||
#define LAST_SEG 0x02
|
||||
#define LAST_SEG_DONE 0x01
|
||||
|
||||
#define SG_CACHE_PRE 0xfc
|
||||
|
||||
|
||||
#define MAX_OFFSET_ULTRA2 0x7f
|
||||
#define MAX_OFFSET_16BIT 0x08
|
||||
#define BUS_8_BIT 0x00
|
||||
#define TARGET_CMD_CMPLT 0xfe
|
||||
#define STATUS_QUEUE_FULL 0x28
|
||||
#define STATUS_BUSY 0x08
|
||||
#define MAX_OFFSET_8BIT 0x0f
|
||||
#define BUS_32_BIT 0x02
|
||||
#define CCSGADDR_MAX 0x80
|
||||
#define TID_SHIFT 0x04
|
||||
#define SCB_DOWNLOAD_SIZE_64 0x30
|
||||
#define HOST_MAILBOX_SHIFT 0x04
|
||||
#define CMD_GROUP_CODE_SHIFT 0x05
|
||||
#define CCSGRAM_MAXSEGS 0x10
|
||||
#define SCB_LIST_NULL 0xff
|
||||
#define SG_SIZEOF 0x08
|
||||
#define SCB_DOWNLOAD_SIZE 0x20
|
||||
#define SEQ_MAILBOX_SHIFT 0x00
|
||||
#define TARGET_DATA_IN 0x01
|
||||
#define HOST_MSG 0xff
|
||||
#define BUS_16_BIT 0x01
|
||||
#define SCB_UPLOAD_SIZE 0x20
|
||||
|
||||
|
||||
/* Downloaded Constant Definitions */
|
||||
#define INVERTED_CACHESIZE_MASK 0x03
|
||||
#define SG_PREFETCH_ADDR_MASK 0x06
|
||||
#define SG_PREFETCH_ALIGN_MASK 0x05
|
||||
#define QOUTFIFO_OFFSET 0x00
|
||||
#define SG_PREFETCH_CNT 0x04
|
||||
#define CACHESIZE_MASK 0x02
|
||||
#define QINFIFO_OFFSET 0x01
|
||||
#define DOWNLOAD_CONST_COUNT 0x07
|
||||
|
||||
|
||||
/* Exported Labels */
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,65 @@
|
||||
PROG= aicasm
|
||||
|
||||
.SUFFIXES= .l .y .c .h
|
||||
|
||||
CSRCS= aicasm.c aicasm_symbol.c
|
||||
YSRCS= aicasm_gram.y aicasm_macro_gram.y
|
||||
LSRCS= aicasm_scan.l aicasm_macro_scan.l
|
||||
|
||||
GENHDRS= aicdb.h $(YSRCS:.y=.h)
|
||||
GENSRCS= $(YSRCS:.y=.c) $(LSRCS:.l=.c)
|
||||
|
||||
SRCS= ${CSRCS} ${GENSRCS}
|
||||
CLEANFILES= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output)
|
||||
# Override default kernel CFLAGS. This is a userland app.
|
||||
AICASM_CFLAGS:= -I/usr/include -I. -ldb
|
||||
YFLAGS= -d
|
||||
|
||||
NOMAN= noman
|
||||
|
||||
ifneq ($(HOSTCC),)
|
||||
AICASM_CC= $(HOSTCC)
|
||||
else
|
||||
AICASM_CC= $(CC)
|
||||
endif
|
||||
|
||||
ifdef DEBUG
|
||||
CFLAGS+= -DDEBUG -g
|
||||
YFLAGS+= -t -v
|
||||
LFLAGS= -d
|
||||
endif
|
||||
|
||||
$(PROG): ${GENHDRS} $(SRCS)
|
||||
$(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG)
|
||||
|
||||
aicdb.h:
|
||||
@if [ -e "/usr/include/db3/db_185.h" ]; then \
|
||||
echo "#include <db3/db_185.h>" > aicdb.h; \
|
||||
elif [ -e "/usr/include/db2/db_185.h" ]; then \
|
||||
echo "#include <db2/db_185.h>" > aicdb.h; \
|
||||
elif [ -e "/usr/include/db/db_185.h" ]; then \
|
||||
echo "#include <db/db_185.h>" > aicdb.h; \
|
||||
elif [ -e "/usr/include/db_185.h" ]; then \
|
||||
echo "#include <db_185.h>" > aicdb.h; \
|
||||
else \
|
||||
echo "*** Install db development libraries"; \
|
||||
fi
|
||||
|
||||
clean:
|
||||
rm -f $(CLEANFILES) $(PROG)
|
||||
|
||||
aicasm_gram.c aicasm_gram.h: aicasm_gram.y
|
||||
$(YACC) $(YFLAGS) -b $(<:.y=) $<
|
||||
mv $(<:.y=).tab.c $(<:.y=.c)
|
||||
mv $(<:.y=).tab.h $(<:.y=.h)
|
||||
|
||||
aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y
|
||||
$(YACC) $(YFLAGS) -b $(<:.y=) -p mm $<
|
||||
mv $(<:.y=).tab.c $(<:.y=.c)
|
||||
mv $(<:.y=).tab.h $(<:.y=.h)
|
||||
|
||||
aicasm_scan.c: aicasm_scan.l
|
||||
$(LEX) $(LFLAGS) -o$@ $<
|
||||
|
||||
aicasm_macro_scan.c: aicasm_macro_scan.l
|
||||
$(LEX) $(LFLAGS) -Pmm -o$@ $<
|
||||
@@ -0,0 +1,809 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs.
|
||||
* Copyright (c) 2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#16 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.c,v 1.28.2.5 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if linux
|
||||
#include <endian.h>
|
||||
#else
|
||||
#include <machine/endian.h>
|
||||
#endif
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm_insformat.h"
|
||||
|
||||
typedef struct patch {
|
||||
STAILQ_ENTRY(patch) links;
|
||||
int patch_func;
|
||||
u_int begin;
|
||||
u_int skip_instr;
|
||||
u_int skip_patch;
|
||||
} patch_t;
|
||||
|
||||
STAILQ_HEAD(patch_list, patch) patches;
|
||||
|
||||
static void usage(void);
|
||||
static void back_patch(void);
|
||||
static void output_code(void);
|
||||
static void output_listing(char *ifilename);
|
||||
static void dump_scope(scope_t *scope);
|
||||
static void emit_patch(scope_t *scope, int patch);
|
||||
static int check_patch(patch_t **start_patch, int start_instr,
|
||||
int *skip_addr, int *func_vals);
|
||||
|
||||
struct path_list search_path;
|
||||
int includes_search_curdir;
|
||||
char *appname;
|
||||
FILE *ofile;
|
||||
char *ofilename;
|
||||
char *regfilename;
|
||||
FILE *regfile;
|
||||
char *listfilename;
|
||||
FILE *listfile;
|
||||
int src_mode;
|
||||
int dst_mode;
|
||||
|
||||
static STAILQ_HEAD(,instruction) seq_program;
|
||||
struct cs_tailq cs_tailq;
|
||||
struct scope_list scope_stack;
|
||||
symlist_t patch_functions;
|
||||
|
||||
#if DEBUG
|
||||
extern int yy_flex_debug;
|
||||
extern int mm_flex_debug;
|
||||
extern int yydebug;
|
||||
extern int mmdebug;
|
||||
#endif
|
||||
extern FILE *yyin;
|
||||
extern int yyparse(void);
|
||||
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
extern char *optarg;
|
||||
extern int optind;
|
||||
int ch;
|
||||
int retval;
|
||||
char *inputfilename;
|
||||
scope_t *sentinal;
|
||||
|
||||
STAILQ_INIT(&patches);
|
||||
SLIST_INIT(&search_path);
|
||||
STAILQ_INIT(&seq_program);
|
||||
TAILQ_INIT(&cs_tailq);
|
||||
SLIST_INIT(&scope_stack);
|
||||
|
||||
/* Set Sentinal scope node */
|
||||
sentinal = scope_alloc();
|
||||
sentinal->type = SCOPE_ROOT;
|
||||
|
||||
includes_search_curdir = 1;
|
||||
appname = *argv;
|
||||
regfile = NULL;
|
||||
listfile = NULL;
|
||||
#if DEBUG
|
||||
yy_flex_debug = 0;
|
||||
mm_flex_debug = 0;
|
||||
yydebug = 0;
|
||||
mmdebug = 0;
|
||||
#endif
|
||||
while ((ch = getopt(argc, argv, "d:l:n:o:r:I:O:")) != -1) {
|
||||
switch(ch) {
|
||||
case 'd':
|
||||
#if DEBUG
|
||||
if (strcmp(optarg, "s") == 0) {
|
||||
yy_flex_debug = 1;
|
||||
mm_flex_debug = 1;
|
||||
} else if (strcmp(optarg, "p") == 0) {
|
||||
yydebug = 1;
|
||||
mmdebug = 1;
|
||||
} else {
|
||||
fprintf(stderr, "%s: -d Requires either an "
|
||||
"'s' or 'p' argument\n", appname);
|
||||
usage();
|
||||
}
|
||||
#else
|
||||
stop("-d: Assembler not built with debugging "
|
||||
"information", EX_SOFTWARE);
|
||||
#endif
|
||||
break;
|
||||
case 'l':
|
||||
/* Create a program listing */
|
||||
if ((listfile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
listfilename = optarg;
|
||||
break;
|
||||
case 'n':
|
||||
/* Don't complain about the -nostdinc directrive */
|
||||
if (strcmp(optarg, "ostdinc")) {
|
||||
fprintf(stderr, "%s: Unknown option -%c%s\n",
|
||||
appname, ch, optarg);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if ((ofile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
ofilename = optarg;
|
||||
break;
|
||||
case 'r':
|
||||
if ((regfile = fopen(optarg, "w")) == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_CANTCREAT);
|
||||
}
|
||||
regfilename = optarg;
|
||||
break;
|
||||
case 'I':
|
||||
{
|
||||
path_entry_t include_dir;
|
||||
|
||||
if (strcmp(optarg, "-") == 0) {
|
||||
if (includes_search_curdir == 0) {
|
||||
fprintf(stderr, "%s: Warning - '-I-' "
|
||||
"specified multiple "
|
||||
"times\n", appname);
|
||||
}
|
||||
includes_search_curdir = 0;
|
||||
for (include_dir = SLIST_FIRST(&search_path);
|
||||
include_dir != NULL;
|
||||
include_dir = SLIST_NEXT(include_dir,
|
||||
links))
|
||||
/*
|
||||
* All entries before a '-I-' only
|
||||
* apply to includes specified with
|
||||
* quotes instead of "<>".
|
||||
*/
|
||||
include_dir->quoted_includes_only = 1;
|
||||
} else {
|
||||
include_dir =
|
||||
(path_entry_t)malloc(sizeof(*include_dir));
|
||||
if (include_dir == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_OSERR);
|
||||
}
|
||||
include_dir->directory = strdup(optarg);
|
||||
if (include_dir->directory == NULL) {
|
||||
perror(optarg);
|
||||
stop(NULL, EX_OSERR);
|
||||
}
|
||||
include_dir->quoted_includes_only = 0;
|
||||
SLIST_INSERT_HEAD(&search_path, include_dir,
|
||||
links);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case '?':
|
||||
default:
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc != 1) {
|
||||
fprintf(stderr, "%s: No input file specifiled\n", appname);
|
||||
usage();
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
symtable_open();
|
||||
inputfilename = *argv;
|
||||
include_file(*argv, SOURCE_FILE);
|
||||
retval = yyparse();
|
||||
if (retval == 0) {
|
||||
if (SLIST_FIRST(&scope_stack) == NULL
|
||||
|| SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
|
||||
stop("Unterminated conditional expression", EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
/* Process outmost scope */
|
||||
process_scope(SLIST_FIRST(&scope_stack));
|
||||
/*
|
||||
* Decend the tree of scopes and insert/emit
|
||||
* patches as appropriate. We perform a depth first
|
||||
* tranversal, recursively handling each scope.
|
||||
*/
|
||||
/* start at the root scope */
|
||||
dump_scope(SLIST_FIRST(&scope_stack));
|
||||
|
||||
/* Patch up forward jump addresses */
|
||||
back_patch();
|
||||
|
||||
if (ofile != NULL)
|
||||
output_code();
|
||||
if (regfile != NULL) {
|
||||
symtable_dump(regfile);
|
||||
}
|
||||
if (listfile != NULL)
|
||||
output_listing(inputfilename);
|
||||
}
|
||||
|
||||
stop(NULL, 0);
|
||||
/* NOTREACHED */
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
usage()
|
||||
{
|
||||
|
||||
(void)fprintf(stderr,
|
||||
"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]
|
||||
[-r register_output_file] [-l program_list_file]
|
||||
input_file\n",
|
||||
appname);
|
||||
exit(EX_USAGE);
|
||||
}
|
||||
|
||||
static void
|
||||
back_patch()
|
||||
{
|
||||
struct instruction *cur_instr;
|
||||
|
||||
for (cur_instr = STAILQ_FIRST(&seq_program);
|
||||
cur_instr != NULL;
|
||||
cur_instr = STAILQ_NEXT(cur_instr, links)) {
|
||||
if (cur_instr->patch_label != NULL) {
|
||||
struct ins_format3 *f3_instr;
|
||||
u_int address;
|
||||
|
||||
if (cur_instr->patch_label->type != LABEL) {
|
||||
char buf[255];
|
||||
|
||||
snprintf(buf, sizeof(buf),
|
||||
"Undefined label %s",
|
||||
cur_instr->patch_label->name);
|
||||
stop(buf, EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
f3_instr = &cur_instr->format.format3;
|
||||
address = f3_instr->address;
|
||||
address += cur_instr->patch_label->info.linfo->address;
|
||||
f3_instr->address = address;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
output_code()
|
||||
{
|
||||
struct instruction *cur_instr;
|
||||
patch_t *cur_patch;
|
||||
critical_section_t *cs;
|
||||
symbol_node_t *cur_node;
|
||||
int instrcount;
|
||||
|
||||
instrcount = 0;
|
||||
fprintf(ofile,
|
||||
"/*
|
||||
* DO NOT EDIT - This file is automatically generated
|
||||
* from the following source files:
|
||||
*
|
||||
%s */\n", versions);
|
||||
|
||||
fprintf(ofile, "static uint8_t seqprog[] = {\n");
|
||||
for (cur_instr = STAILQ_FIRST(&seq_program);
|
||||
cur_instr != NULL;
|
||||
cur_instr = STAILQ_NEXT(cur_instr, links)) {
|
||||
|
||||
fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x",
|
||||
cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n",
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
cur_instr->format.bytes[0],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[3]);
|
||||
#else
|
||||
cur_instr->format.bytes[3],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[0]);
|
||||
#endif
|
||||
instrcount++;
|
||||
}
|
||||
fprintf(ofile, "\n};\n\n");
|
||||
|
||||
if (patch_arg_list == NULL)
|
||||
stop("Patch argument list not defined",
|
||||
EX_DATAERR);
|
||||
|
||||
/*
|
||||
* Output patch information. Patch functions first.
|
||||
*/
|
||||
for (cur_node = SLIST_FIRST(&patch_functions);
|
||||
cur_node != NULL;
|
||||
cur_node = SLIST_NEXT(cur_node,links)) {
|
||||
fprintf(ofile,
|
||||
"static int aic_patch%d_func(%s);
|
||||
|
||||
static int
|
||||
aic_patch%d_func(%s)
|
||||
{
|
||||
return (%s);
|
||||
}\n\n",
|
||||
cur_node->symbol->info.condinfo->func_num,
|
||||
patch_arg_list,
|
||||
cur_node->symbol->info.condinfo->func_num,
|
||||
patch_arg_list,
|
||||
cur_node->symbol->name);
|
||||
}
|
||||
|
||||
fprintf(ofile,
|
||||
"typedef int patch_func_t (%s);
|
||||
static struct patch {
|
||||
patch_func_t *patch_func;
|
||||
uint32_t begin :10,
|
||||
skip_instr :10,
|
||||
skip_patch :12;
|
||||
} patches[] = {\n", patch_arg_list);
|
||||
|
||||
for (cur_patch = STAILQ_FIRST(&patches);
|
||||
cur_patch != NULL;
|
||||
cur_patch = STAILQ_NEXT(cur_patch,links)) {
|
||||
fprintf(ofile, "%s\t{ aic_patch%d_func, %d, %d, %d }",
|
||||
cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n",
|
||||
cur_patch->patch_func, cur_patch->begin,
|
||||
cur_patch->skip_instr, cur_patch->skip_patch);
|
||||
}
|
||||
|
||||
fprintf(ofile, "\n};\n");
|
||||
|
||||
fprintf(ofile,
|
||||
"static struct cs {
|
||||
u_int16_t begin;
|
||||
u_int16_t end;
|
||||
} critical_sections[] = {\n");
|
||||
|
||||
for (cs = TAILQ_FIRST(&cs_tailq);
|
||||
cs != NULL;
|
||||
cs = TAILQ_NEXT(cs, links)) {
|
||||
fprintf(ofile, "%s\t{ %d, %d }",
|
||||
cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n",
|
||||
cs->begin_addr, cs->end_addr);
|
||||
}
|
||||
|
||||
fprintf(ofile, "\n};\n");
|
||||
|
||||
fprintf(ofile,
|
||||
"static const int num_critical_sections = sizeof(critical_sections)
|
||||
/ sizeof(*critical_sections);\n");
|
||||
|
||||
fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
|
||||
}
|
||||
|
||||
static void
|
||||
dump_scope(scope_t *scope)
|
||||
{
|
||||
scope_t *cur_scope;
|
||||
|
||||
/*
|
||||
* Emit the first patch for this scope
|
||||
*/
|
||||
emit_patch(scope, 0);
|
||||
|
||||
/*
|
||||
* Dump each scope within this one.
|
||||
*/
|
||||
cur_scope = TAILQ_FIRST(&scope->inner_scope);
|
||||
|
||||
while (cur_scope != NULL) {
|
||||
|
||||
dump_scope(cur_scope);
|
||||
|
||||
cur_scope = TAILQ_NEXT(cur_scope, scope_links);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emit the second, closing, patch for this scope
|
||||
*/
|
||||
emit_patch(scope, 1);
|
||||
}
|
||||
|
||||
void
|
||||
emit_patch(scope_t *scope, int patch)
|
||||
{
|
||||
patch_info_t *pinfo;
|
||||
patch_t *new_patch;
|
||||
|
||||
pinfo = &scope->patches[patch];
|
||||
|
||||
if (pinfo->skip_instr == 0)
|
||||
/* No-Op patch */
|
||||
return;
|
||||
|
||||
new_patch = (patch_t *)malloc(sizeof(*new_patch));
|
||||
|
||||
if (new_patch == NULL)
|
||||
stop("Could not malloc patch structure", EX_OSERR);
|
||||
|
||||
memset(new_patch, 0, sizeof(*new_patch));
|
||||
|
||||
if (patch == 0) {
|
||||
new_patch->patch_func = scope->func_num;
|
||||
new_patch->begin = scope->begin_addr;
|
||||
} else {
|
||||
new_patch->patch_func = 0;
|
||||
new_patch->begin = scope->end_addr;
|
||||
}
|
||||
new_patch->skip_instr = pinfo->skip_instr;
|
||||
new_patch->skip_patch = pinfo->skip_patch;
|
||||
STAILQ_INSERT_TAIL(&patches, new_patch, links);
|
||||
}
|
||||
|
||||
void
|
||||
output_listing(char *ifilename)
|
||||
{
|
||||
char buf[1024];
|
||||
FILE *ifile;
|
||||
struct instruction *cur_instr;
|
||||
patch_t *cur_patch;
|
||||
symbol_node_t *cur_func;
|
||||
int *func_values;
|
||||
int instrcount;
|
||||
int instrptr;
|
||||
int line;
|
||||
int func_count;
|
||||
int skip_addr;
|
||||
|
||||
instrcount = 0;
|
||||
instrptr = 0;
|
||||
line = 1;
|
||||
skip_addr = 0;
|
||||
if ((ifile = fopen(ifilename, "r")) == NULL) {
|
||||
perror(ifilename);
|
||||
stop(NULL, EX_DATAERR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Determine which options to apply to this listing.
|
||||
*/
|
||||
for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
|
||||
cur_func != NULL;
|
||||
cur_func = SLIST_NEXT(cur_func, links))
|
||||
func_count++;
|
||||
|
||||
func_values = NULL;
|
||||
if (func_count != 0) {
|
||||
func_values = (int *)malloc(func_count * sizeof(int));
|
||||
|
||||
if (func_values == NULL)
|
||||
stop("Could not malloc", EX_OSERR);
|
||||
|
||||
func_values[0] = 0; /* FALSE func */
|
||||
func_count--;
|
||||
|
||||
/*
|
||||
* Ask the user to fill in the return values for
|
||||
* the rest of the functions.
|
||||
*/
|
||||
|
||||
|
||||
for (cur_func = SLIST_FIRST(&patch_functions);
|
||||
cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
|
||||
cur_func = SLIST_NEXT(cur_func, links), func_count--) {
|
||||
int input;
|
||||
|
||||
fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
|
||||
fprintf(stdout,
|
||||
"Enter the return value for "
|
||||
"this expression[T/F]:");
|
||||
|
||||
while (1) {
|
||||
|
||||
input = getchar();
|
||||
input = toupper(input);
|
||||
|
||||
if (input == 'T') {
|
||||
func_values[func_count] = 1;
|
||||
break;
|
||||
} else if (input == 'F') {
|
||||
func_values[func_count] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (isatty(fileno(stdin)) == 0)
|
||||
putchar(input);
|
||||
}
|
||||
fprintf(stdout, "\nThanks!\n");
|
||||
}
|
||||
|
||||
/* Now output the listing */
|
||||
cur_patch = STAILQ_FIRST(&patches);
|
||||
for (cur_instr = STAILQ_FIRST(&seq_program);
|
||||
cur_instr != NULL;
|
||||
cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
|
||||
|
||||
if (check_patch(&cur_patch, instrcount,
|
||||
&skip_addr, func_values) == 0) {
|
||||
/* Don't count this instruction as it is in a patch
|
||||
* that was removed.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
while (line < cur_instr->srcline) {
|
||||
fgets(buf, sizeof(buf), ifile);
|
||||
fprintf(listfile, "\t\t%s", buf);
|
||||
line++;
|
||||
}
|
||||
fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
cur_instr->format.bytes[0],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[3]);
|
||||
#else
|
||||
cur_instr->format.bytes[3],
|
||||
cur_instr->format.bytes[2],
|
||||
cur_instr->format.bytes[1],
|
||||
cur_instr->format.bytes[0]);
|
||||
#endif
|
||||
fgets(buf, sizeof(buf), ifile);
|
||||
fprintf(listfile, "\t%s", buf);
|
||||
line++;
|
||||
instrptr++;
|
||||
}
|
||||
/* Dump the remainder of the file */
|
||||
while(fgets(buf, sizeof(buf), ifile) != NULL)
|
||||
fprintf(listfile, "\t\t%s", buf);
|
||||
|
||||
fclose(ifile);
|
||||
}
|
||||
|
||||
static int
|
||||
check_patch(patch_t **start_patch, int start_instr,
|
||||
int *skip_addr, int *func_vals)
|
||||
{
|
||||
patch_t *cur_patch;
|
||||
|
||||
cur_patch = *start_patch;
|
||||
|
||||
while (cur_patch != NULL && start_instr == cur_patch->begin) {
|
||||
if (func_vals[cur_patch->patch_func] == 0) {
|
||||
int skip;
|
||||
|
||||
/* Start rejecting code */
|
||||
*skip_addr = start_instr + cur_patch->skip_instr;
|
||||
for (skip = cur_patch->skip_patch;
|
||||
skip > 0 && cur_patch != NULL;
|
||||
skip--)
|
||||
cur_patch = STAILQ_NEXT(cur_patch, links);
|
||||
} else {
|
||||
/* Accepted this patch. Advance to the next
|
||||
* one and wait for our intruction pointer to
|
||||
* hit this point.
|
||||
*/
|
||||
cur_patch = STAILQ_NEXT(cur_patch, links);
|
||||
}
|
||||
}
|
||||
|
||||
*start_patch = cur_patch;
|
||||
if (start_instr < *skip_addr)
|
||||
/* Still skipping */
|
||||
return (0);
|
||||
|
||||
return (1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Print out error information if appropriate, and clean up before
|
||||
* terminating the program.
|
||||
*/
|
||||
void
|
||||
stop(const char *string, int err_code)
|
||||
{
|
||||
if (string != NULL) {
|
||||
fprintf(stderr, "%s: ", appname);
|
||||
if (yyfilename != NULL) {
|
||||
fprintf(stderr, "Stopped at file %s, line %d - ",
|
||||
yyfilename, yylineno);
|
||||
}
|
||||
fprintf(stderr, "%s\n", string);
|
||||
}
|
||||
|
||||
if (ofile != NULL) {
|
||||
fclose(ofile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, ofilename);
|
||||
unlink(ofilename);
|
||||
}
|
||||
}
|
||||
|
||||
if (regfile != NULL) {
|
||||
fclose(regfile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, regfilename);
|
||||
unlink(regfilename);
|
||||
}
|
||||
}
|
||||
|
||||
if (listfile != NULL) {
|
||||
fclose(listfile);
|
||||
if (err_code != 0) {
|
||||
fprintf(stderr, "%s: Removing %s due to error\n",
|
||||
appname, listfilename);
|
||||
unlink(listfilename);
|
||||
}
|
||||
}
|
||||
|
||||
symlist_free(&patch_functions);
|
||||
symtable_close();
|
||||
|
||||
exit(err_code);
|
||||
}
|
||||
|
||||
struct instruction *
|
||||
seq_alloc()
|
||||
{
|
||||
struct instruction *new_instr;
|
||||
|
||||
new_instr = (struct instruction *)malloc(sizeof(struct instruction));
|
||||
if (new_instr == NULL)
|
||||
stop("Unable to malloc instruction object", EX_SOFTWARE);
|
||||
memset(new_instr, 0, sizeof(*new_instr));
|
||||
STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
|
||||
new_instr->srcline = yylineno;
|
||||
return new_instr;
|
||||
}
|
||||
|
||||
critical_section_t *
|
||||
cs_alloc()
|
||||
{
|
||||
critical_section_t *new_cs;
|
||||
|
||||
new_cs= (critical_section_t *)malloc(sizeof(critical_section_t));
|
||||
if (new_cs == NULL)
|
||||
stop("Unable to malloc critical_section object", EX_SOFTWARE);
|
||||
memset(new_cs, 0, sizeof(*new_cs));
|
||||
|
||||
TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links);
|
||||
return new_cs;
|
||||
}
|
||||
|
||||
scope_t *
|
||||
scope_alloc()
|
||||
{
|
||||
scope_t *new_scope;
|
||||
|
||||
new_scope = (scope_t *)malloc(sizeof(scope_t));
|
||||
if (new_scope == NULL)
|
||||
stop("Unable to malloc scope object", EX_SOFTWARE);
|
||||
memset(new_scope, 0, sizeof(*new_scope));
|
||||
TAILQ_INIT(&new_scope->inner_scope);
|
||||
|
||||
if (SLIST_FIRST(&scope_stack) != NULL) {
|
||||
TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
|
||||
new_scope, scope_links);
|
||||
}
|
||||
/* This patch is now the current scope */
|
||||
SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
|
||||
return new_scope;
|
||||
}
|
||||
|
||||
void
|
||||
process_scope(scope_t *scope)
|
||||
{
|
||||
/*
|
||||
* We are "leaving" this scope. We should now have
|
||||
* enough information to process the lists of scopes
|
||||
* we encapsulate.
|
||||
*/
|
||||
scope_t *cur_scope;
|
||||
u_int skip_patch_count;
|
||||
u_int skip_instr_count;
|
||||
|
||||
cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
|
||||
skip_patch_count = 0;
|
||||
skip_instr_count = 0;
|
||||
while (cur_scope != NULL) {
|
||||
u_int patch0_patch_skip;
|
||||
|
||||
patch0_patch_skip = 0;
|
||||
switch (cur_scope->type) {
|
||||
case SCOPE_IF:
|
||||
case SCOPE_ELSE_IF:
|
||||
if (skip_instr_count != 0) {
|
||||
/* Create a tail patch */
|
||||
patch0_patch_skip++;
|
||||
cur_scope->patches[1].skip_patch =
|
||||
skip_patch_count + 1;
|
||||
cur_scope->patches[1].skip_instr =
|
||||
skip_instr_count;
|
||||
}
|
||||
|
||||
/* Count Head patch */
|
||||
patch0_patch_skip++;
|
||||
|
||||
/* Count any patches contained in our inner scope */
|
||||
patch0_patch_skip += cur_scope->inner_scope_patches;
|
||||
|
||||
cur_scope->patches[0].skip_patch = patch0_patch_skip;
|
||||
cur_scope->patches[0].skip_instr =
|
||||
cur_scope->end_addr - cur_scope->begin_addr;
|
||||
|
||||
skip_instr_count += cur_scope->patches[0].skip_instr;
|
||||
|
||||
skip_patch_count += patch0_patch_skip;
|
||||
if (cur_scope->type == SCOPE_IF) {
|
||||
scope->inner_scope_patches += skip_patch_count;
|
||||
skip_patch_count = 0;
|
||||
skip_instr_count = 0;
|
||||
}
|
||||
break;
|
||||
case SCOPE_ELSE:
|
||||
/* Count any patches contained in our innter scope */
|
||||
skip_patch_count += cur_scope->inner_scope_patches;
|
||||
|
||||
skip_instr_count += cur_scope->end_addr
|
||||
- cur_scope->begin_addr;
|
||||
break;
|
||||
case SCOPE_ROOT:
|
||||
stop("Unexpected scope type encountered", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* Copyright (c) 2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#10 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm.h,v 1.11.2.4 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "../queue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
typedef struct path_entry {
|
||||
char *directory;
|
||||
int quoted_includes_only;
|
||||
SLIST_ENTRY(path_entry) links;
|
||||
} *path_entry_t;
|
||||
|
||||
typedef enum {
|
||||
QUOTED_INCLUDE,
|
||||
BRACKETED_INCLUDE,
|
||||
SOURCE_FILE
|
||||
} include_type;
|
||||
|
||||
SLIST_HEAD(path_list, path_entry);
|
||||
|
||||
extern struct path_list search_path;
|
||||
extern struct cs_tailq cs_tailq;
|
||||
extern struct scope_list scope_stack;
|
||||
extern struct symlist patch_functions;
|
||||
extern int includes_search_curdir; /* False if we've seen -I- */
|
||||
extern char *appname;
|
||||
extern int yylineno;
|
||||
extern char *yyfilename;
|
||||
extern char *patch_arg_list;
|
||||
extern char *versions;
|
||||
extern int src_mode;
|
||||
extern int dst_mode;
|
||||
struct symbol;
|
||||
|
||||
void stop(const char *errstring, int err_code);
|
||||
void include_file(char *file_name, include_type type);
|
||||
void expand_macro(struct symbol *macro_symbol);
|
||||
struct instruction *seq_alloc(void);
|
||||
struct critical_section *cs_alloc(void);
|
||||
struct scope *scope_alloc(void);
|
||||
void process_scope(struct scope *);
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Instruction formats for the sequencer program downloaded to
|
||||
* Aic7xxx SCSI host adapters
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#9 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_insformat.h,v 1.3.2.3 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
struct ins_format1 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t immediate : 8,
|
||||
source : 9,
|
||||
destination : 9,
|
||||
ret : 1,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
ret : 1,
|
||||
destination : 9,
|
||||
source : 9,
|
||||
immediate : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ins_format2 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t shift_control : 8,
|
||||
source : 9,
|
||||
destination : 9,
|
||||
ret : 1,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
ret : 1,
|
||||
destination : 9,
|
||||
source : 9,
|
||||
shift_control : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct ins_format3 {
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
uint32_t immediate : 8,
|
||||
source : 9,
|
||||
address : 10,
|
||||
opcode : 4,
|
||||
parity : 1;
|
||||
#else
|
||||
uint32_t parity : 1,
|
||||
opcode : 4,
|
||||
address : 10,
|
||||
source : 9,
|
||||
immediate : 8;
|
||||
#endif
|
||||
};
|
||||
|
||||
union ins_formats {
|
||||
struct ins_format1 format1;
|
||||
struct ins_format2 format2;
|
||||
struct ins_format3 format3;
|
||||
uint8_t bytes[4];
|
||||
uint32_t integer;
|
||||
};
|
||||
struct instruction {
|
||||
union ins_formats format;
|
||||
u_int srcline;
|
||||
struct symbol *patch_label;
|
||||
STAILQ_ENTRY(instruction) links;
|
||||
};
|
||||
|
||||
#define AIC_OP_OR 0x0
|
||||
#define AIC_OP_AND 0x1
|
||||
#define AIC_OP_XOR 0x2
|
||||
#define AIC_OP_ADD 0x3
|
||||
#define AIC_OP_ADC 0x4
|
||||
#define AIC_OP_ROL 0x5
|
||||
#define AIC_OP_BMOV 0x6
|
||||
|
||||
#define AIC_OP_JMP 0x8
|
||||
#define AIC_OP_JC 0x9
|
||||
#define AIC_OP_JNC 0xa
|
||||
#define AIC_OP_CALL 0xb
|
||||
#define AIC_OP_JNE 0xc
|
||||
#define AIC_OP_JNZ 0xd
|
||||
#define AIC_OP_JE 0xe
|
||||
#define AIC_OP_JZ 0xf
|
||||
|
||||
/* Pseudo Ops */
|
||||
#define AIC_OP_SHL 0x10
|
||||
#define AIC_OP_SHR 0x20
|
||||
#define AIC_OP_ROR 0x30
|
||||
@@ -0,0 +1,164 @@
|
||||
%{
|
||||
/*
|
||||
* Sub-parser for macro invocation in the Aic7xxx SCSI
|
||||
* Host adapter sequencer assembler.
|
||||
*
|
||||
* Copyright (c) 2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_macro_gram.y,v 1.1.2.1 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "../queue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm_insformat.h"
|
||||
|
||||
static symbol_t *macro_symbol;
|
||||
|
||||
static void add_macro_arg(const char *argtext, int position);
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
int value;
|
||||
char *str;
|
||||
symbol_t *sym;
|
||||
}
|
||||
|
||||
|
||||
%token <str> T_ARG
|
||||
|
||||
%token <sym> T_SYMBOL
|
||||
|
||||
%type <value> macro_arglist
|
||||
|
||||
%%
|
||||
|
||||
macrocall:
|
||||
T_SYMBOL '('
|
||||
{
|
||||
macro_symbol = $1;
|
||||
}
|
||||
macro_arglist ')'
|
||||
{
|
||||
if (macro_symbol->info.macroinfo->narg != $4) {
|
||||
printf("Narg == %d", macro_symbol->info.macroinfo->narg);
|
||||
stop("Too few arguments for macro invocation",
|
||||
EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
macro_symbol = NULL;
|
||||
YYACCEPT;
|
||||
}
|
||||
;
|
||||
|
||||
macro_arglist:
|
||||
{
|
||||
/* Macros can take 0 arguments */
|
||||
$$ = 0;
|
||||
}
|
||||
| T_ARG
|
||||
{
|
||||
$$ = 1;
|
||||
add_macro_arg($1, 1);
|
||||
}
|
||||
| macro_arglist ',' T_ARG
|
||||
{
|
||||
if ($1 == 0) {
|
||||
stop("Comma without preceeding argument in arg list",
|
||||
EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
$$ = $1 + 1;
|
||||
add_macro_arg($3, $$);
|
||||
}
|
||||
;
|
||||
|
||||
%%
|
||||
|
||||
static void
|
||||
add_macro_arg(const char *argtext, int argnum)
|
||||
{
|
||||
struct macro_arg *marg;
|
||||
int i;
|
||||
|
||||
if (macro_symbol == NULL || macro_symbol->type != MACRO) {
|
||||
stop("Invalid current symbol for adding macro arg",
|
||||
EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
/*
|
||||
* Macro Invocation. Find the appropriate argument and fill
|
||||
* in the replace ment text for this call.
|
||||
*/
|
||||
i = 0;
|
||||
STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) {
|
||||
i++;
|
||||
if (i == argnum)
|
||||
break;
|
||||
}
|
||||
if (marg == NULL) {
|
||||
stop("Too many arguments for macro invocation", EX_DATAERR);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
marg->replacement_text = strdup(argtext);
|
||||
if (marg->replacement_text == NULL) {
|
||||
stop("Unable to replicate replacement text", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mmerror(const char *string)
|
||||
{
|
||||
stop(string, EX_DATAERR);
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
%{
|
||||
/*
|
||||
* Sub-Lexical Analyzer for macro invokation in
|
||||
* the Aic7xxx SCSI Host adapter sequencer assembler.
|
||||
*
|
||||
* Copyright (c) 2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_macro_scan.l,v 1.1.2.1 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#ifdef __linux__
|
||||
#include "../queue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm_macro_gram.h"
|
||||
|
||||
#define MAX_STR_CONST 4096
|
||||
static char string_buf[MAX_STR_CONST];
|
||||
static char *string_buf_ptr;
|
||||
static int parren_count;
|
||||
static char buf[255];
|
||||
%}
|
||||
|
||||
WORD [A-Za-z_][-A-Za-z_0-9]*
|
||||
SPACE [ \t]+
|
||||
MCARG [^(), \t]+
|
||||
|
||||
%x ARGLIST
|
||||
|
||||
%%
|
||||
\n {
|
||||
++yylineno;
|
||||
}
|
||||
<ARGLIST>{SPACE} ;
|
||||
<ARGLIST>\( {
|
||||
parren_count++;
|
||||
if (parren_count == 1) {
|
||||
string_buf_ptr = string_buf;
|
||||
return ('(');
|
||||
}
|
||||
*string_buf_ptr++ = '(';
|
||||
}
|
||||
<ARGLIST>\) {
|
||||
if (parren_count == 1) {
|
||||
if (string_buf_ptr != string_buf) {
|
||||
/*
|
||||
* Return an argument and
|
||||
* rescan this parren so we
|
||||
* can return it as well.
|
||||
*/
|
||||
*string_buf_ptr = '\0';
|
||||
mmlval.str = string_buf;
|
||||
string_buf_ptr = string_buf;
|
||||
unput(')');
|
||||
return T_ARG;
|
||||
}
|
||||
BEGIN INITIAL;
|
||||
return (')');
|
||||
}
|
||||
parren_count--;
|
||||
*string_buf_ptr++ = ')';
|
||||
}
|
||||
<ARGLIST>{MCARG} {
|
||||
char *yptr;
|
||||
|
||||
yptr = mmtext;
|
||||
while (*yptr)
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
<ARGLIST>\, {
|
||||
if (string_buf_ptr != string_buf) {
|
||||
/*
|
||||
* Return an argument and
|
||||
* rescan this comma so we
|
||||
* can return it as well.
|
||||
*/
|
||||
*string_buf_ptr = '\0';
|
||||
mmlval.str = string_buf;
|
||||
string_buf_ptr = string_buf;
|
||||
unput(',');
|
||||
return T_ARG;
|
||||
}
|
||||
return ',';
|
||||
}
|
||||
{WORD}[(] {
|
||||
/* May be a symbol or a macro invocation. */
|
||||
mmlval.sym = symtable_get(mmtext);
|
||||
if (mmlval.sym->type != MACRO) {
|
||||
stop("Expecting Macro Name",
|
||||
EX_DATAERR);
|
||||
}
|
||||
unput('(');
|
||||
parren_count = 0;
|
||||
BEGIN ARGLIST;
|
||||
return T_SYMBOL;
|
||||
}
|
||||
. {
|
||||
snprintf(buf, sizeof(buf), "Invalid character "
|
||||
"'%c'", mmtext[0]);
|
||||
stop(buf, EX_DATAERR);
|
||||
}
|
||||
%%
|
||||
|
||||
int
|
||||
mmwrap()
|
||||
{
|
||||
stop("EOF encountered in macro call", EX_DATAERR);
|
||||
}
|
||||
@@ -0,0 +1,594 @@
|
||||
%{
|
||||
/*
|
||||
* Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
|
||||
*
|
||||
* Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
|
||||
* Copyright (c) 2001 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#11 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_scan.l,v 1.13.2.4 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <limits.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
#ifdef __linux__
|
||||
#include "../queue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
#include "aicasm.h"
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm_gram.h"
|
||||
|
||||
/* This is used for macro body capture too, so err on the large size. */
|
||||
#define MAX_STR_CONST 4096
|
||||
static char string_buf[MAX_STR_CONST];
|
||||
static char *string_buf_ptr;
|
||||
static int parren_count;
|
||||
static int quote_count;
|
||||
static char buf[255];
|
||||
%}
|
||||
|
||||
PATH ([/]*[-A-Za-z0-9_.])+
|
||||
WORD [A-Za-z_][-A-Za-z_0-9]*
|
||||
SPACE [ \t]+
|
||||
MCARG [^(), \t]+
|
||||
MBODY ((\\[^\n])*[^\n\\]*)+
|
||||
|
||||
%x COMMENT
|
||||
%x CEXPR
|
||||
%x INCLUDE
|
||||
%x STRING
|
||||
%x MACRODEF
|
||||
%x MACROARGLIST
|
||||
%x MACROCALLARGS
|
||||
%x MACROBODY
|
||||
|
||||
%%
|
||||
\n { ++yylineno; }
|
||||
"/*" { BEGIN COMMENT; /* Enter comment eating state */ }
|
||||
<COMMENT>"/*" { fprintf(stderr, "Warning! Comment within comment."); }
|
||||
<COMMENT>\n { ++yylineno; }
|
||||
<COMMENT>[^*/\n]* ;
|
||||
<COMMENT>"*"+[^*/\n]* ;
|
||||
<COMMENT>"/"+[^*/\n]* ;
|
||||
<COMMENT>"*"+"/" { BEGIN INITIAL; }
|
||||
if[ \t]*\( {
|
||||
string_buf_ptr = string_buf;
|
||||
parren_count = 1;
|
||||
BEGIN CEXPR;
|
||||
return T_IF;
|
||||
}
|
||||
<CEXPR>\( { *string_buf_ptr++ = '('; parren_count++; }
|
||||
<CEXPR>\) {
|
||||
parren_count--;
|
||||
if (parren_count == 0) {
|
||||
/* All done */
|
||||
BEGIN INITIAL;
|
||||
*string_buf_ptr = '\0';
|
||||
yylval.sym = symtable_get(string_buf);
|
||||
return T_CEXPR;
|
||||
} else {
|
||||
*string_buf_ptr++ = ')';
|
||||
}
|
||||
}
|
||||
<CEXPR>\n { ++yylineno; }
|
||||
<CEXPR>[^()\n]+ {
|
||||
char *yptr;
|
||||
|
||||
yptr = yytext;
|
||||
while (*yptr != '\0') {
|
||||
/* Remove duplicate spaces */
|
||||
if (*yptr == '\t')
|
||||
*yptr = ' ';
|
||||
if (*yptr == ' '
|
||||
&& string_buf_ptr != string_buf
|
||||
&& string_buf_ptr[-1] == ' ')
|
||||
yptr++;
|
||||
else
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
}
|
||||
|
||||
VERSION { return T_VERSION; }
|
||||
PATCH_ARG_LIST { return T_PATCH_ARG_LIST; }
|
||||
\" {
|
||||
string_buf_ptr = string_buf;
|
||||
BEGIN STRING;
|
||||
}
|
||||
<STRING>[^"]+ {
|
||||
char *yptr;
|
||||
|
||||
yptr = yytext;
|
||||
while (*yptr)
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
<STRING>\" {
|
||||
/* All done */
|
||||
BEGIN INITIAL;
|
||||
*string_buf_ptr = '\0';
|
||||
yylval.str = string_buf;
|
||||
return T_STRING;
|
||||
}
|
||||
{SPACE} ;
|
||||
|
||||
/* Register/SCB/SRAM definition keywords */
|
||||
export { return T_EXPORT; }
|
||||
register { return T_REGISTER; }
|
||||
const { yylval.value = FALSE; return T_CONST; }
|
||||
download { return T_DOWNLOAD; }
|
||||
address { return T_ADDRESS; }
|
||||
access_mode { return T_ACCESS_MODE; }
|
||||
modes { return T_MODES; }
|
||||
RW|RO|WO {
|
||||
if (strcmp(yytext, "RW") == 0)
|
||||
yylval.value = RW;
|
||||
else if (strcmp(yytext, "RO") == 0)
|
||||
yylval.value = RO;
|
||||
else
|
||||
yylval.value = WO;
|
||||
return T_MODE;
|
||||
}
|
||||
BEGIN_CRITICAL { return T_BEGIN_CS; }
|
||||
END_CRITICAL { return T_END_CS; }
|
||||
SET_SRC_MODE { return T_SET_SRC_MODE; }
|
||||
SET_DST_MODE { return T_SET_DST_MODE; }
|
||||
bit { return T_BIT; }
|
||||
mask { return T_MASK; }
|
||||
alias { return T_ALIAS; }
|
||||
size { return T_SIZE; }
|
||||
scb { return T_SCB; }
|
||||
scratch_ram { return T_SRAM; }
|
||||
accumulator { return T_ACCUM; }
|
||||
mode_pointer { return T_MODE_PTR; }
|
||||
allones { return T_ALLONES; }
|
||||
allzeros { return T_ALLZEROS; }
|
||||
none { return T_NONE; }
|
||||
sindex { return T_SINDEX; }
|
||||
A { return T_A; }
|
||||
|
||||
/* Opcodes */
|
||||
shl { return T_SHL; }
|
||||
shr { return T_SHR; }
|
||||
ror { return T_ROR; }
|
||||
rol { return T_ROL; }
|
||||
mvi { return T_MVI; }
|
||||
mov { return T_MOV; }
|
||||
clr { return T_CLR; }
|
||||
jmp { return T_JMP; }
|
||||
jc { return T_JC; }
|
||||
jnc { return T_JNC; }
|
||||
je { return T_JE; }
|
||||
jne { return T_JNE; }
|
||||
jz { return T_JZ; }
|
||||
jnz { return T_JNZ; }
|
||||
call { return T_CALL; }
|
||||
add { return T_ADD; }
|
||||
adc { return T_ADC; }
|
||||
bmov { return T_BMOV; }
|
||||
inc { return T_INC; }
|
||||
dec { return T_DEC; }
|
||||
stc { return T_STC; }
|
||||
clc { return T_CLC; }
|
||||
cmp { return T_CMP; }
|
||||
not { return T_NOT; }
|
||||
xor { return T_XOR; }
|
||||
test { return T_TEST;}
|
||||
and { return T_AND; }
|
||||
or { return T_OR; }
|
||||
ret { return T_RET; }
|
||||
nop { return T_NOP; }
|
||||
else { return T_ELSE; }
|
||||
|
||||
/* Allowed Symbols */
|
||||
\<\< { return T_EXPR_LSHIFT; }
|
||||
\>\> { return T_EXPR_RSHIFT; }
|
||||
[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; }
|
||||
|
||||
/* Number processing */
|
||||
0[0-7]* {
|
||||
yylval.value = strtol(yytext, NULL, 8);
|
||||
return T_NUMBER;
|
||||
}
|
||||
|
||||
0[xX][0-9a-fA-F]+ {
|
||||
yylval.value = strtoul(yytext + 2, NULL, 16);
|
||||
return T_NUMBER;
|
||||
}
|
||||
|
||||
[1-9][0-9]* {
|
||||
yylval.value = strtol(yytext, NULL, 10);
|
||||
return T_NUMBER;
|
||||
}
|
||||
/* Include Files */
|
||||
#include{SPACE} {
|
||||
BEGIN INCLUDE;
|
||||
quote_count = 0;
|
||||
return T_INCLUDE;
|
||||
}
|
||||
<INCLUDE>[<] { return yytext[0]; }
|
||||
<INCLUDE>[>] { BEGIN INITIAL; return yytext[0]; }
|
||||
<INCLUDE>[\"] {
|
||||
if (quote_count != 0)
|
||||
BEGIN INITIAL;
|
||||
quote_count++;
|
||||
return yytext[0];
|
||||
}
|
||||
<INCLUDE>{PATH} {
|
||||
char *yptr;
|
||||
|
||||
yptr = yytext;
|
||||
string_buf_ptr = string_buf;
|
||||
while (*yptr)
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
yylval.str = string_buf;
|
||||
*string_buf_ptr = '\0';
|
||||
return T_PATH;
|
||||
}
|
||||
<INCLUDE>. { stop("Invalid include line", EX_DATAERR); }
|
||||
#define{SPACE} {
|
||||
BEGIN MACRODEF;
|
||||
return T_DEFINE;
|
||||
}
|
||||
<MACRODEF>{WORD}{SPACE} {
|
||||
char *yptr;
|
||||
|
||||
/* Strip space and return as a normal symbol */
|
||||
yptr = yytext;
|
||||
while (*yptr != ' ' && *yptr != '\t')
|
||||
yptr++;
|
||||
*yptr = '\0';
|
||||
yylval.sym = symtable_get(yytext);
|
||||
string_buf_ptr = string_buf;
|
||||
BEGIN MACROBODY;
|
||||
return T_SYMBOL;
|
||||
}
|
||||
<MACRODEF>{WORD}\( {
|
||||
/*
|
||||
* We store the symbol with its opening
|
||||
* parren so we can differentiate macros
|
||||
* that take args from macros with the
|
||||
* same name that do not take args as
|
||||
* is allowed in C.
|
||||
*/
|
||||
BEGIN MACROARGLIST;
|
||||
yylval.sym = symtable_get(yytext);
|
||||
unput('(');
|
||||
return T_SYMBOL;
|
||||
}
|
||||
<MACROARGLIST>{WORD} {
|
||||
yylval.str = yytext;
|
||||
return T_ARG;
|
||||
}
|
||||
<MACROARGLIST>{SPACE} ;
|
||||
<MACROARGLIST>[(,] {
|
||||
return yytext[0];
|
||||
}
|
||||
<MACROARGLIST>[)] {
|
||||
string_buf_ptr = string_buf;
|
||||
BEGIN MACROBODY;
|
||||
return ')';
|
||||
}
|
||||
<MACROARGLIST>. {
|
||||
snprintf(buf, sizeof(buf), "Invalid character "
|
||||
"'%c' in macro argument list",
|
||||
yytext[0]);
|
||||
stop(buf, EX_DATAERR);
|
||||
}
|
||||
<MACROCALLARGS>{SPACE} ;
|
||||
<MACROCALLARGS>\( {
|
||||
parren_count++;
|
||||
if (parren_count == 1)
|
||||
return ('(');
|
||||
*string_buf_ptr++ = '(';
|
||||
}
|
||||
<MACROCALLARGS>\) {
|
||||
parren_count--;
|
||||
if (parren_count == 0) {
|
||||
BEGIN INITIAL;
|
||||
return (')');
|
||||
}
|
||||
*string_buf_ptr++ = ')';
|
||||
}
|
||||
<MACROCALLARGS>{MCARG} {
|
||||
char *yptr;
|
||||
|
||||
yptr = yytext;
|
||||
while (*yptr)
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
<MACROCALLARGS>\, {
|
||||
if (string_buf_ptr != string_buf) {
|
||||
/*
|
||||
* Return an argument and
|
||||
* rescan this comma so we
|
||||
* can return it as well.
|
||||
*/
|
||||
*string_buf_ptr = '\0';
|
||||
yylval.str = string_buf;
|
||||
string_buf_ptr = string_buf;
|
||||
unput(',');
|
||||
return T_ARG;
|
||||
}
|
||||
return ',';
|
||||
}
|
||||
<MACROBODY>\\\n {
|
||||
/* Eat escaped newlines. */
|
||||
++yylineno;
|
||||
}
|
||||
<MACROBODY>\n {
|
||||
/* Macros end on the first unescaped newline. */
|
||||
BEGIN INITIAL;
|
||||
*string_buf_ptr = '\0';
|
||||
yylval.str = string_buf;
|
||||
++yylineno;
|
||||
return T_MACROBODY;
|
||||
}
|
||||
<MACROBODY>{MBODY} {
|
||||
char *yptr;
|
||||
|
||||
yptr = yytext;
|
||||
while (*yptr)
|
||||
*string_buf_ptr++ = *yptr++;
|
||||
}
|
||||
{WORD}\( {
|
||||
char *yptr;
|
||||
char *ycopy;
|
||||
|
||||
/* May be a symbol or a macro invocation. */
|
||||
yylval.sym = symtable_get(yytext);
|
||||
if (yylval.sym->type == MACRO) {
|
||||
YY_BUFFER_STATE old_state;
|
||||
YY_BUFFER_STATE temp_state;
|
||||
|
||||
ycopy = strdup(yytext);
|
||||
yptr = ycopy + yyleng;
|
||||
while (yptr > ycopy)
|
||||
unput(*--yptr);
|
||||
old_state = YY_CURRENT_BUFFER;
|
||||
temp_state =
|
||||
yy_create_buffer(stdin,
|
||||
YY_BUF_SIZE);
|
||||
yy_switch_to_buffer(temp_state);
|
||||
mm_switch_to_buffer(old_state);
|
||||
mmparse();
|
||||
mm_switch_to_buffer(temp_state);
|
||||
yy_switch_to_buffer(old_state);
|
||||
mm_delete_buffer(temp_state);
|
||||
expand_macro(yylval.sym);
|
||||
} else {
|
||||
if (yylval.sym->type == UNINITIALIZED) {
|
||||
/* Try without the '(' */
|
||||
symbol_delete(yylval.sym);
|
||||
yytext[yyleng-1] = '\0';
|
||||
yylval.sym =
|
||||
symtable_get(yytext);
|
||||
}
|
||||
unput('(');
|
||||
return T_SYMBOL;
|
||||
}
|
||||
}
|
||||
{WORD} {
|
||||
yylval.sym = symtable_get(yytext);
|
||||
if (yylval.sym->type == MACRO) {
|
||||
expand_macro(yylval.sym);
|
||||
} else {
|
||||
return T_SYMBOL;
|
||||
}
|
||||
}
|
||||
. {
|
||||
snprintf(buf, sizeof(buf), "Invalid character "
|
||||
"'%c'", yytext[0]);
|
||||
stop(buf, EX_DATAERR);
|
||||
}
|
||||
%%
|
||||
|
||||
typedef struct include {
|
||||
YY_BUFFER_STATE buffer;
|
||||
int lineno;
|
||||
char *filename;
|
||||
SLIST_ENTRY(include) links;
|
||||
}include_t;
|
||||
|
||||
SLIST_HEAD(, include) include_stack;
|
||||
|
||||
void
|
||||
include_file(char *file_name, include_type type)
|
||||
{
|
||||
FILE *newfile;
|
||||
include_t *include;
|
||||
|
||||
newfile = NULL;
|
||||
/* Try the current directory first */
|
||||
if (includes_search_curdir != 0 || type == SOURCE_FILE)
|
||||
newfile = fopen(file_name, "r");
|
||||
|
||||
if (newfile == NULL && type != SOURCE_FILE) {
|
||||
path_entry_t include_dir;
|
||||
for (include_dir = search_path.slh_first;
|
||||
include_dir != NULL;
|
||||
include_dir = include_dir->links.sle_next) {
|
||||
char fullname[PATH_MAX];
|
||||
|
||||
if ((include_dir->quoted_includes_only == TRUE)
|
||||
&& (type != QUOTED_INCLUDE))
|
||||
continue;
|
||||
|
||||
snprintf(fullname, sizeof(fullname),
|
||||
"%s/%s", include_dir->directory, file_name);
|
||||
|
||||
if ((newfile = fopen(fullname, "r")) != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (newfile == NULL) {
|
||||
perror(file_name);
|
||||
stop("Unable to open input file", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
if (type != SOURCE_FILE) {
|
||||
include = (include_t *)malloc(sizeof(include_t));
|
||||
if (include == NULL) {
|
||||
stop("Unable to allocate include stack entry",
|
||||
EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
include->buffer = YY_CURRENT_BUFFER;
|
||||
include->lineno = yylineno;
|
||||
include->filename = yyfilename;
|
||||
SLIST_INSERT_HEAD(&include_stack, include, links);
|
||||
}
|
||||
yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
|
||||
yylineno = 1;
|
||||
yyfilename = strdup(file_name);
|
||||
}
|
||||
|
||||
static void next_substitution(struct symbol *mac_symbol, const char *body_pos,
|
||||
const char **next_match,
|
||||
struct macro_arg **match_marg, regmatch_t *match);
|
||||
|
||||
void
|
||||
expand_macro(struct symbol *macro_symbol)
|
||||
{
|
||||
struct macro_arg *marg;
|
||||
struct macro_arg *match_marg;
|
||||
const char *body_head;
|
||||
const char *body_pos;
|
||||
const char *next_match;
|
||||
|
||||
/*
|
||||
* Due to the nature of unput, we must work
|
||||
* backwards through the macro body performing
|
||||
* any expansions.
|
||||
*/
|
||||
body_head = macro_symbol->info.macroinfo->body;
|
||||
body_pos = body_head + strlen(body_head);
|
||||
while (body_pos > body_head) {
|
||||
regmatch_t match;
|
||||
|
||||
next_match = body_head;
|
||||
match_marg = NULL;
|
||||
next_substitution(macro_symbol, body_pos, &next_match,
|
||||
&match_marg, &match);
|
||||
|
||||
/* Put back everything up until the replacement. */
|
||||
while (body_pos > next_match)
|
||||
unput(*--body_pos);
|
||||
|
||||
/* Perform the replacement. */
|
||||
if (match_marg != NULL) {
|
||||
const char *strp;
|
||||
|
||||
next_match = match_marg->replacement_text;
|
||||
strp = next_match + strlen(next_match);
|
||||
while (strp > next_match)
|
||||
unput(*--strp);
|
||||
|
||||
/* Skip past the unexpanded macro arg. */
|
||||
body_pos -= match.rm_eo - match.rm_so;
|
||||
}
|
||||
}
|
||||
|
||||
/* Cleanup replacement text. */
|
||||
STAILQ_FOREACH(marg, ¯o_symbol->info.macroinfo->args, links) {
|
||||
free(marg->replacement_text);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Find the next substitution in the macro working backwards from
|
||||
* body_pos until the beginning of the macro buffer. next_match
|
||||
* should be initialized to the beginning of the macro buffer prior
|
||||
* to calling this routine.
|
||||
*/
|
||||
static void
|
||||
next_substitution(struct symbol *mac_symbol, const char *body_pos,
|
||||
const char **next_match, struct macro_arg **match_marg,
|
||||
regmatch_t *match)
|
||||
{
|
||||
regmatch_t matches[2];
|
||||
struct macro_arg *marg;
|
||||
const char *search_pos;
|
||||
int retval;
|
||||
|
||||
do {
|
||||
search_pos = *next_match;
|
||||
|
||||
STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) {
|
||||
|
||||
retval = regexec(&marg->arg_regex, search_pos, 2,
|
||||
matches, 0);
|
||||
if (retval == 0
|
||||
&& (matches[1].rm_eo + search_pos) <= body_pos
|
||||
&& (matches[1].rm_eo + search_pos) > *next_match) {
|
||||
*match = matches[1];
|
||||
*next_match = match->rm_eo + search_pos;
|
||||
*match_marg = marg;
|
||||
}
|
||||
}
|
||||
} while (search_pos != *next_match);
|
||||
}
|
||||
|
||||
int
|
||||
yywrap()
|
||||
{
|
||||
include_t *include;
|
||||
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
(void)fclose(yyin);
|
||||
if (yyfilename != NULL)
|
||||
free(yyfilename);
|
||||
yyfilename = NULL;
|
||||
include = include_stack.slh_first;
|
||||
if (include != NULL) {
|
||||
yy_switch_to_buffer(include->buffer);
|
||||
yylineno = include->lineno;
|
||||
yyfilename = include->filename;
|
||||
SLIST_REMOVE_HEAD(&include_stack, links);
|
||||
free(include);
|
||||
return (0);
|
||||
}
|
||||
return (1);
|
||||
}
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#14 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.c,v 1.11.2.4 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#ifdef __linux__
|
||||
#include "aicdb.h"
|
||||
#else
|
||||
#include <db.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <regex.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sysexits.h>
|
||||
|
||||
#include "aicasm_symbol.h"
|
||||
#include "aicasm.h"
|
||||
|
||||
static DB *symtable;
|
||||
|
||||
symbol_t *
|
||||
symbol_create(char *name)
|
||||
{
|
||||
symbol_t *new_symbol;
|
||||
|
||||
new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
|
||||
if (new_symbol == NULL) {
|
||||
perror("Unable to create new symbol");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
memset(new_symbol, 0, sizeof(*new_symbol));
|
||||
new_symbol->name = strdup(name);
|
||||
new_symbol->type = UNINITIALIZED;
|
||||
return (new_symbol);
|
||||
}
|
||||
|
||||
void
|
||||
symbol_delete(symbol_t *symbol)
|
||||
{
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
|
||||
key.data = symbol->name;
|
||||
key.size = strlen(symbol->name);
|
||||
symtable->del(symtable, &key, /*flags*/0);
|
||||
}
|
||||
switch(symbol->type) {
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
case REGISTER:
|
||||
if (symbol->info.rinfo != NULL)
|
||||
free(symbol->info.rinfo);
|
||||
break;
|
||||
case ALIAS:
|
||||
if (symbol->info.ainfo != NULL)
|
||||
free(symbol->info.ainfo);
|
||||
break;
|
||||
case MASK:
|
||||
case BIT:
|
||||
if (symbol->info.minfo != NULL) {
|
||||
symlist_free(&symbol->info.minfo->symrefs);
|
||||
free(symbol->info.minfo);
|
||||
}
|
||||
break;
|
||||
case DOWNLOAD_CONST:
|
||||
case CONST:
|
||||
if (symbol->info.cinfo != NULL)
|
||||
free(symbol->info.cinfo);
|
||||
break;
|
||||
case LABEL:
|
||||
if (symbol->info.linfo != NULL)
|
||||
free(symbol->info.linfo);
|
||||
break;
|
||||
case UNINITIALIZED:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
free(symbol->name);
|
||||
free(symbol);
|
||||
}
|
||||
|
||||
void
|
||||
symtable_open()
|
||||
{
|
||||
symtable = dbopen(/*filename*/NULL,
|
||||
O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
|
||||
/*openinfo*/NULL);
|
||||
|
||||
if (symtable == NULL) {
|
||||
perror("Symbol table creation failed");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
symtable_close()
|
||||
{
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
DBT data;
|
||||
|
||||
while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
|
||||
symbol_t *stored_ptr;
|
||||
|
||||
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
|
||||
symbol_delete(stored_ptr);
|
||||
}
|
||||
symtable->close(symtable);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The semantics of get is to return an uninitialized symbol entry
|
||||
* if a lookup fails.
|
||||
*/
|
||||
symbol_t *
|
||||
symtable_get(char *name)
|
||||
{
|
||||
symbol_t *stored_ptr;
|
||||
DBT key;
|
||||
DBT data;
|
||||
int retval;
|
||||
|
||||
key.data = (void *)name;
|
||||
key.size = strlen(name);
|
||||
|
||||
if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
|
||||
if (retval == -1) {
|
||||
perror("Symbol table get operation failed");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
} else if (retval == 1) {
|
||||
/* Symbol wasn't found, so create a new one */
|
||||
symbol_t *new_symbol;
|
||||
|
||||
new_symbol = symbol_create(name);
|
||||
data.data = &new_symbol;
|
||||
data.size = sizeof(new_symbol);
|
||||
if (symtable->put(symtable, &key, &data,
|
||||
/*flags*/0) !=0) {
|
||||
perror("Symtable put failed");
|
||||
exit(EX_SOFTWARE);
|
||||
}
|
||||
return (new_symbol);
|
||||
} else {
|
||||
perror("Unexpected return value from db get routine");
|
||||
exit(EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
}
|
||||
memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
|
||||
return (stored_ptr);
|
||||
}
|
||||
|
||||
symbol_node_t *
|
||||
symlist_search(symlist_t *symlist, char *symname)
|
||||
{
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = SLIST_FIRST(symlist);
|
||||
while(curnode != NULL) {
|
||||
if (strcmp(symname, curnode->symbol->name) == 0)
|
||||
break;
|
||||
curnode = SLIST_NEXT(curnode, links);
|
||||
}
|
||||
return (curnode);
|
||||
}
|
||||
|
||||
void
|
||||
symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
|
||||
{
|
||||
symbol_node_t *newnode;
|
||||
|
||||
newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
|
||||
if (newnode == NULL) {
|
||||
stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
newnode->symbol = symbol;
|
||||
if (how == SYMLIST_SORT) {
|
||||
symbol_node_t *curnode;
|
||||
int mask;
|
||||
|
||||
mask = FALSE;
|
||||
switch(symbol->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
break;
|
||||
case BIT:
|
||||
case MASK:
|
||||
mask = TRUE;
|
||||
break;
|
||||
default:
|
||||
stop("symlist_add: Invalid symbol type for sorting",
|
||||
EX_SOFTWARE);
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
curnode = SLIST_FIRST(symlist);
|
||||
if (curnode == NULL
|
||||
|| (mask && (curnode->symbol->info.minfo->mask >
|
||||
newnode->symbol->info.minfo->mask))
|
||||
|| (!mask && (curnode->symbol->info.rinfo->address >
|
||||
newnode->symbol->info.rinfo->address))) {
|
||||
SLIST_INSERT_HEAD(symlist, newnode, links);
|
||||
return;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
if (SLIST_NEXT(curnode, links) == NULL) {
|
||||
SLIST_INSERT_AFTER(curnode, newnode,
|
||||
links);
|
||||
break;
|
||||
} else {
|
||||
symbol_t *cursymbol;
|
||||
|
||||
cursymbol = SLIST_NEXT(curnode, links)->symbol;
|
||||
if ((mask && (cursymbol->info.minfo->mask >
|
||||
symbol->info.minfo->mask))
|
||||
|| (!mask &&(cursymbol->info.rinfo->address >
|
||||
symbol->info.rinfo->address))){
|
||||
SLIST_INSERT_AFTER(curnode, newnode,
|
||||
links);
|
||||
break;
|
||||
}
|
||||
}
|
||||
curnode = SLIST_NEXT(curnode, links);
|
||||
}
|
||||
} else {
|
||||
SLIST_INSERT_HEAD(symlist, newnode, links);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
symlist_free(symlist_t *symlist)
|
||||
{
|
||||
symbol_node_t *node1, *node2;
|
||||
|
||||
node1 = SLIST_FIRST(symlist);
|
||||
while (node1 != NULL) {
|
||||
node2 = SLIST_NEXT(node1, links);
|
||||
free(node1);
|
||||
node1 = node2;
|
||||
}
|
||||
SLIST_INIT(symlist);
|
||||
}
|
||||
|
||||
void
|
||||
symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
|
||||
symlist_t *symlist_src2)
|
||||
{
|
||||
symbol_node_t *node;
|
||||
|
||||
*symlist_dest = *symlist_src1;
|
||||
while((node = SLIST_FIRST(symlist_src2)) != NULL) {
|
||||
SLIST_REMOVE_HEAD(symlist_src2, links);
|
||||
SLIST_INSERT_HEAD(symlist_dest, node, links);
|
||||
}
|
||||
|
||||
/* These are now empty */
|
||||
SLIST_INIT(symlist_src1);
|
||||
SLIST_INIT(symlist_src2);
|
||||
}
|
||||
|
||||
void
|
||||
symtable_dump(FILE *ofile)
|
||||
{
|
||||
/*
|
||||
* Sort the registers by address with a simple insertion sort.
|
||||
* Put bitmasks next to the first register that defines them.
|
||||
* Put constants at the end.
|
||||
*/
|
||||
symlist_t registers;
|
||||
symlist_t masks;
|
||||
symlist_t constants;
|
||||
symlist_t download_constants;
|
||||
symlist_t aliases;
|
||||
symlist_t exported_labels;
|
||||
u_int i;
|
||||
|
||||
SLIST_INIT(®isters);
|
||||
SLIST_INIT(&masks);
|
||||
SLIST_INIT(&constants);
|
||||
SLIST_INIT(&download_constants);
|
||||
SLIST_INIT(&aliases);
|
||||
SLIST_INIT(&exported_labels);
|
||||
|
||||
if (symtable != NULL) {
|
||||
DBT key;
|
||||
DBT data;
|
||||
int flag = R_FIRST;
|
||||
|
||||
while (symtable->seq(symtable, &key, &data, flag) == 0) {
|
||||
symbol_t *cursym;
|
||||
|
||||
memcpy(&cursym, data.data, sizeof(cursym));
|
||||
switch(cursym->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
symlist_add(®isters, cursym, SYMLIST_SORT);
|
||||
break;
|
||||
case MASK:
|
||||
case BIT:
|
||||
symlist_add(&masks, cursym, SYMLIST_SORT);
|
||||
break;
|
||||
case CONST:
|
||||
symlist_add(&constants, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
case DOWNLOAD_CONST:
|
||||
symlist_add(&download_constants, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
case ALIAS:
|
||||
symlist_add(&aliases, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
case LABEL:
|
||||
if (cursym->info.linfo->exported == 0)
|
||||
break;
|
||||
symlist_add(&exported_labels, cursym,
|
||||
SYMLIST_INSERT_HEAD);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
flag = R_NEXT;
|
||||
}
|
||||
|
||||
/* Put in the masks and bits */
|
||||
while (SLIST_FIRST(&masks) != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
symbol_node_t *regnode;
|
||||
char *regname;
|
||||
|
||||
curnode = SLIST_FIRST(&masks);
|
||||
SLIST_REMOVE_HEAD(&masks, links);
|
||||
|
||||
regnode =
|
||||
SLIST_FIRST(&curnode->symbol->info.minfo->symrefs);
|
||||
regname = regnode->symbol->name;
|
||||
regnode = symlist_search(®isters, regname);
|
||||
SLIST_INSERT_AFTER(regnode, curnode, links);
|
||||
}
|
||||
|
||||
/* Add the aliases */
|
||||
while (SLIST_FIRST(&aliases) != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
symbol_node_t *regnode;
|
||||
char *regname;
|
||||
|
||||
curnode = SLIST_FIRST(&aliases);
|
||||
SLIST_REMOVE_HEAD(&aliases, links);
|
||||
|
||||
regname = curnode->symbol->info.ainfo->parent->name;
|
||||
regnode = symlist_search(®isters, regname);
|
||||
SLIST_INSERT_AFTER(regnode, curnode, links);
|
||||
}
|
||||
|
||||
/* Output what we have */
|
||||
fprintf(ofile,
|
||||
"/*
|
||||
* DO NOT EDIT - This file is automatically generated
|
||||
* from the following source files:
|
||||
*
|
||||
%s */\n", versions);
|
||||
while (SLIST_FIRST(®isters) != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
u_int value;
|
||||
char *tab_str;
|
||||
char *tab_str2;
|
||||
|
||||
curnode = SLIST_FIRST(®isters);
|
||||
SLIST_REMOVE_HEAD(®isters, links);
|
||||
switch(curnode->symbol->type) {
|
||||
case REGISTER:
|
||||
case SCBLOC:
|
||||
case SRAMLOC:
|
||||
fprintf(ofile, "\n");
|
||||
value = curnode->symbol->info.rinfo->address;
|
||||
tab_str = "\t";
|
||||
tab_str2 = "\t\t";
|
||||
break;
|
||||
case ALIAS:
|
||||
{
|
||||
symbol_t *parent;
|
||||
|
||||
parent = curnode->symbol->info.ainfo->parent;
|
||||
value = parent->info.rinfo->address;
|
||||
tab_str = "\t";
|
||||
tab_str2 = "\t\t";
|
||||
break;
|
||||
}
|
||||
case MASK:
|
||||
case BIT:
|
||||
value = curnode->symbol->info.minfo->mask;
|
||||
tab_str = "\t\t";
|
||||
tab_str2 = "\t";
|
||||
break;
|
||||
default:
|
||||
value = 0; /* Quiet compiler */
|
||||
tab_str = NULL;
|
||||
tab_str2 = NULL;
|
||||
stop("symtable_dump: Invalid symbol type "
|
||||
"encountered", EX_SOFTWARE);
|
||||
break;
|
||||
}
|
||||
fprintf(ofile, "#define%s%-16s%s0x%02x\n",
|
||||
tab_str, curnode->symbol->name, tab_str2,
|
||||
value);
|
||||
free(curnode);
|
||||
}
|
||||
fprintf(ofile, "\n\n");
|
||||
|
||||
while (SLIST_FIRST(&constants) != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = SLIST_FIRST(&constants);
|
||||
SLIST_REMOVE_HEAD(&constants, links);
|
||||
fprintf(ofile, "#define\t%-8s\t0x%02x\n",
|
||||
curnode->symbol->name,
|
||||
curnode->symbol->info.cinfo->value);
|
||||
free(curnode);
|
||||
}
|
||||
|
||||
|
||||
fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
|
||||
|
||||
for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = SLIST_FIRST(&download_constants);
|
||||
SLIST_REMOVE_HEAD(&download_constants, links);
|
||||
fprintf(ofile, "#define\t%-8s\t0x%02x\n",
|
||||
curnode->symbol->name,
|
||||
curnode->symbol->info.cinfo->value);
|
||||
free(curnode);
|
||||
}
|
||||
fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);
|
||||
|
||||
fprintf(ofile, "\n\n/* Exported Labels */\n");
|
||||
|
||||
while (SLIST_FIRST(&exported_labels) != NULL) {
|
||||
symbol_node_t *curnode;
|
||||
|
||||
curnode = SLIST_FIRST(&exported_labels);
|
||||
SLIST_REMOVE_HEAD(&exported_labels, links);
|
||||
fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",
|
||||
curnode->symbol->name,
|
||||
curnode->symbol->info.linfo->address);
|
||||
free(curnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
* Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. Redistributions in binary form must reproduce at minimum a disclaimer
|
||||
* substantially similar to the "NO WARRANTY" disclaimer below
|
||||
* ("Disclaimer") and any redistribution must be conditioned upon
|
||||
* including a substantially similar Disclaimer requirement for further
|
||||
* binary redistribution.
|
||||
* 3. Neither the names of the above-listed copyright holders nor the names
|
||||
* of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL") version 2 as published by the Free
|
||||
* Software Foundation.
|
||||
*
|
||||
* NO WARRANTY
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGES.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#11 $
|
||||
*
|
||||
* $FreeBSD: src/sys/dev/aic7xxx/aicasm/aicasm_symbol.h,v 1.11.2.3 2002/04/29 19:36:36 gibbs Exp $
|
||||
*/
|
||||
|
||||
#ifdef __linux__
|
||||
#include "../queue.h"
|
||||
#else
|
||||
#include <sys/queue.h>
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
UNINITIALIZED,
|
||||
REGISTER,
|
||||
ALIAS,
|
||||
SCBLOC,
|
||||
SRAMLOC,
|
||||
MASK,
|
||||
BIT,
|
||||
CONST,
|
||||
DOWNLOAD_CONST,
|
||||
LABEL,
|
||||
CONDITIONAL,
|
||||
MACRO
|
||||
} symtype;
|
||||
|
||||
typedef enum {
|
||||
RO = 0x01,
|
||||
WO = 0x02,
|
||||
RW = 0x03
|
||||
}amode_t;
|
||||
|
||||
struct reg_info {
|
||||
u_int address;
|
||||
int size;
|
||||
amode_t mode;
|
||||
u_int8_t valid_bitmask;
|
||||
u_int8_t modes;
|
||||
int typecheck_masks;
|
||||
};
|
||||
|
||||
typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
|
||||
|
||||
struct mask_info {
|
||||
symlist_t symrefs;
|
||||
u_int8_t mask;
|
||||
};
|
||||
|
||||
struct const_info {
|
||||
u_int value;
|
||||
int define;
|
||||
};
|
||||
|
||||
struct alias_info {
|
||||
struct symbol *parent;
|
||||
};
|
||||
|
||||
struct label_info {
|
||||
int address;
|
||||
int exported;
|
||||
};
|
||||
|
||||
struct cond_info {
|
||||
int func_num;
|
||||
};
|
||||
|
||||
struct macro_arg {
|
||||
STAILQ_ENTRY(macro_arg) links;
|
||||
regex_t arg_regex;
|
||||
char *replacement_text;
|
||||
};
|
||||
STAILQ_HEAD(macro_arg_list, macro_arg) args;
|
||||
|
||||
struct macro_info {
|
||||
struct macro_arg_list args;
|
||||
int narg;
|
||||
const char* body;
|
||||
};
|
||||
|
||||
typedef struct expression_info {
|
||||
symlist_t referenced_syms;
|
||||
int value;
|
||||
} expression_t;
|
||||
|
||||
typedef struct symbol {
|
||||
char *name;
|
||||
symtype type;
|
||||
union {
|
||||
struct reg_info *rinfo;
|
||||
struct mask_info *minfo;
|
||||
struct const_info *cinfo;
|
||||
struct alias_info *ainfo;
|
||||
struct label_info *linfo;
|
||||
struct cond_info *condinfo;
|
||||
struct macro_info *macroinfo;
|
||||
}info;
|
||||
} symbol_t;
|
||||
|
||||
typedef struct symbol_ref {
|
||||
symbol_t *symbol;
|
||||
int offset;
|
||||
} symbol_ref_t;
|
||||
|
||||
typedef struct symbol_node {
|
||||
SLIST_ENTRY(symbol_node) links;
|
||||
symbol_t *symbol;
|
||||
} symbol_node_t;
|
||||
|
||||
typedef struct critical_section {
|
||||
TAILQ_ENTRY(critical_section) links;
|
||||
int begin_addr;
|
||||
int end_addr;
|
||||
} critical_section_t;
|
||||
|
||||
typedef enum {
|
||||
SCOPE_ROOT,
|
||||
SCOPE_IF,
|
||||
SCOPE_ELSE_IF,
|
||||
SCOPE_ELSE
|
||||
} scope_type;
|
||||
|
||||
typedef struct patch_info {
|
||||
int skip_patch;
|
||||
int skip_instr;
|
||||
} patch_info_t;
|
||||
|
||||
typedef struct scope {
|
||||
SLIST_ENTRY(scope) scope_stack_links;
|
||||
TAILQ_ENTRY(scope) scope_links;
|
||||
TAILQ_HEAD(, scope) inner_scope;
|
||||
scope_type type;
|
||||
int inner_scope_patches;
|
||||
int begin_addr;
|
||||
int end_addr;
|
||||
patch_info_t patches[2];
|
||||
int func_num;
|
||||
} scope_t;
|
||||
|
||||
TAILQ_HEAD(cs_tailq, critical_section);
|
||||
SLIST_HEAD(scope_list, scope);
|
||||
TAILQ_HEAD(scope_tailq, scope);
|
||||
|
||||
void symbol_delete __P((symbol_t *symbol));
|
||||
|
||||
void symtable_open __P((void));
|
||||
|
||||
void symtable_close __P((void));
|
||||
|
||||
symbol_t *
|
||||
symtable_get __P((char *name));
|
||||
|
||||
symbol_node_t *
|
||||
symlist_search __P((symlist_t *symlist, char *symname));
|
||||
|
||||
void
|
||||
symlist_add __P((symlist_t *symlist, symbol_t *symbol, int how));
|
||||
#define SYMLIST_INSERT_HEAD 0x00
|
||||
#define SYMLIST_SORT 0x01
|
||||
|
||||
void symlist_free __P((symlist_t *symlist));
|
||||
|
||||
void symlist_merge __P((symlist_t *symlist_dest, symlist_t *symlist_src1,
|
||||
symlist_t *symlist_src2));
|
||||
void symtable_dump __P((FILE *ofile));
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Data structures and definitions for the CAM system.
|
||||
*
|
||||
* Copyright (c) 1997 Justin T. Gibbs.
|
||||
* Copyright (c) 2000 Adaptec Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions, and the following disclaimer,
|
||||
* without modification.
|
||||
* 2. The name of the author may not be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of the
|
||||
* GNU General Public License ("GPL").
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/cam.h#11 $
|
||||
*/
|
||||
|
||||
#ifndef _AIC7XXX_CAM_H
|
||||
#define _AIC7XXX_CAM_H 1
|
||||
|
||||
/* Provide a mapping from CAM constructs to Linux SCSI constructs */
|
||||
|
||||
#define CAM_BUS_WILDCARD ((u_int)~0)
|
||||
#define CAM_TARGET_WILDCARD ((u_int)~0)
|
||||
#define CAM_LUN_WILDCARD ((u_int)~0)
|
||||
|
||||
/* CAM Status field values */
|
||||
typedef enum {
|
||||
/* CCB request is in progress */
|
||||
CAM_REQ_INPROG = 0x3F, /* Some value unused by Linux */
|
||||
/* CCB request completed without error */
|
||||
CAM_REQ_CMP = DID_OK,
|
||||
/* CCB request aborted by the host */
|
||||
CAM_REQ_ABORTED = DID_ABORT,
|
||||
/* Unable to abort CCB request */
|
||||
CAM_UA_ABORT = DID_ERROR,
|
||||
/* CCB request completed with an error */
|
||||
CAM_REQ_CMP_ERR = DID_ERROR,
|
||||
/* CAM subsytem is busy */
|
||||
CAM_BUSY = DID_BUS_BUSY,
|
||||
/* CCB request was invalid */
|
||||
CAM_REQ_INVALID = DID_BAD_TARGET,
|
||||
/* Supplied Path ID is invalid */
|
||||
CAM_PATH_INVALID = DID_BAD_TARGET,
|
||||
/* Target Selection Timeout */
|
||||
CAM_SEL_TIMEOUT = DID_NO_CONNECT,
|
||||
/* Command timeout */
|
||||
CAM_CMD_TIMEOUT = DID_ERROR, /*
|
||||
* Should never occur in Linux
|
||||
* as the upper level code
|
||||
* handles all timeout processing.
|
||||
*/
|
||||
/* SCSI error, look at error code in CCB */
|
||||
CAM_SCSI_STATUS_ERROR = DID_OK, /* Linux looks at status byte */
|
||||
/* SCSI Bus Reset Sent/Received */
|
||||
CAM_SCSI_BUS_RESET = DID_RESET,
|
||||
/* Uncorrectable parity error occurred */
|
||||
CAM_UNCOR_PARITY = DID_PARITY,
|
||||
/* Autosense: request sense cmd fail */
|
||||
CAM_AUTOSENSE_FAIL = DID_ERROR,
|
||||
/* No HBA Detected Error */
|
||||
CAM_NO_HBA = DID_ERROR,
|
||||
/* Data Overrun error */
|
||||
CAM_DATA_RUN_ERR = DID_ERROR,
|
||||
/* Unexpected Bus Free */
|
||||
CAM_UNEXP_BUSFREE = DID_ERROR,
|
||||
/* CCB length supplied is inadequate */
|
||||
CAM_CCB_LEN_ERR = DID_ERROR,
|
||||
/* Unable to provide requested capability */
|
||||
CAM_PROVIDE_FAIL = DID_ERROR,
|
||||
/* A SCSI BDR msg was sent to target */
|
||||
CAM_BDR_SENT = DID_RESET,
|
||||
/* CCB request terminated by the host */
|
||||
CAM_REQ_TERMIO = DID_ERROR,
|
||||
/* Unrecoverable Host Bus Adapter Error */
|
||||
CAM_UNREC_HBA_ERROR = DID_ERROR,
|
||||
/* The request was too large for this host */
|
||||
CAM_REQ_TOO_BIG = DID_ERROR,
|
||||
/*
|
||||
* This request should be requeued to preserve
|
||||
* transaction ordering. This typically occurs
|
||||
* when the SIM recognizes an error that should
|
||||
* freeze the queue and must place additional
|
||||
* requests for the target at the sim level
|
||||
* back into the XPT queue.
|
||||
*/
|
||||
CAM_REQUEUE_REQ = DID_BUS_BUSY,
|
||||
|
||||
CAM_STATUS_MASK = 0x3F
|
||||
} cam_status;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
|
||||
#define SCSI_DATA_READ 1
|
||||
#define SCSI_DATA_WRITE 2
|
||||
#define SCSI_DATA_NONE 3
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Definitions for the asynchronous callback CCB fields.
|
||||
*/
|
||||
typedef enum {
|
||||
AC_GETDEV_CHANGED = 0x800,/* Getdev info might have changed */
|
||||
AC_INQ_CHANGED = 0x400,/* Inquiry info might have changed */
|
||||
AC_TRANSFER_NEG = 0x200,/* New transfer settings in effect */
|
||||
AC_LOST_DEVICE = 0x100,/* A device went away */
|
||||
AC_FOUND_DEVICE = 0x080,/* A new device was found */
|
||||
AC_PATH_DEREGISTERED = 0x040,/* A path has de-registered */
|
||||
AC_PATH_REGISTERED = 0x020,/* A new path has been registered */
|
||||
AC_SENT_BDR = 0x010,/* A BDR message was sent to target */
|
||||
AC_SCSI_AEN = 0x008,/* A SCSI AEN has been received */
|
||||
AC_UNSOL_RESEL = 0x002,/* Unsolicited reselection occurred */
|
||||
AC_BUS_RESET = 0x001 /* A SCSI bus reset occurred */
|
||||
} ac_code;
|
||||
|
||||
typedef enum {
|
||||
CAM_DIR_IN = SCSI_DATA_READ,
|
||||
CAM_DIR_OUT = SCSI_DATA_WRITE,
|
||||
CAM_DIR_NONE = SCSI_DATA_NONE
|
||||
} ccb_flags;
|
||||
|
||||
#endif /* _AIC7XXX_CAM_H */
|
||||
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* Copyright (c) 1991, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)queue.h 8.5 (Berkeley) 8/20/94
|
||||
* $FreeBSD: src/sys/sys/queue.h,v 1.38 2000/05/26 02:06:56 jake Exp $
|
||||
*/
|
||||
|
||||
#ifndef _SYS_QUEUE_H_
|
||||
#define _SYS_QUEUE_H_
|
||||
|
||||
/*
|
||||
* This file defines five types of data structures: singly-linked lists,
|
||||
* singly-linked tail queues, lists, tail queues, and circular queues.
|
||||
*
|
||||
* A singly-linked list is headed by a single forward pointer. The elements
|
||||
* are singly linked for minimum space and pointer manipulation overhead at
|
||||
* the expense of O(n) removal for arbitrary elements. New elements can be
|
||||
* added to the list after an existing element or at the head of the list.
|
||||
* Elements being removed from the head of the list should use the explicit
|
||||
* macro for this purpose for optimum efficiency. A singly-linked list may
|
||||
* only be traversed in the forward direction. Singly-linked lists are ideal
|
||||
* for applications with large datasets and few or no removals or for
|
||||
* implementing a LIFO queue.
|
||||
*
|
||||
* A singly-linked tail queue is headed by a pair of pointers, one to the
|
||||
* head of the list and the other to the tail of the list. The elements are
|
||||
* singly linked for minimum space and pointer manipulation overhead at the
|
||||
* expense of O(n) removal for arbitrary elements. New elements can be added
|
||||
* to the list after an existing element, at the head of the list, or at the
|
||||
* end of the list. Elements being removed from the head of the tail queue
|
||||
* should use the explicit macro for this purpose for optimum efficiency.
|
||||
* A singly-linked tail queue may only be traversed in the forward direction.
|
||||
* Singly-linked tail queues are ideal for applications with large datasets
|
||||
* and few or no removals or for implementing a FIFO queue.
|
||||
*
|
||||
* A list is headed by a single forward pointer (or an array of forward
|
||||
* pointers for a hash table header). The elements are doubly linked
|
||||
* so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before
|
||||
* or after an existing element or at the head of the list. A list
|
||||
* may only be traversed in the forward direction.
|
||||
*
|
||||
* A tail queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or
|
||||
* after an existing element, at the head of the list, or at the end of
|
||||
* the list. A tail queue may be traversed in either direction.
|
||||
*
|
||||
* A circle queue is headed by a pair of pointers, one to the head of the
|
||||
* list and the other to the tail of the list. The elements are doubly
|
||||
* linked so that an arbitrary element can be removed without a need to
|
||||
* traverse the list. New elements can be added to the list before or after
|
||||
* an existing element, at the head of the list, or at the end of the list.
|
||||
* A circle queue may be traversed in either direction, but has a more
|
||||
* complex end of list detection.
|
||||
*
|
||||
* For details on the use of these macros, see the queue(3) manual page.
|
||||
*
|
||||
*
|
||||
* SLIST LIST STAILQ TAILQ CIRCLEQ
|
||||
* _HEAD + + + + +
|
||||
* _HEAD_INITIALIZER + + + + +
|
||||
* _ENTRY + + + + +
|
||||
* _INIT + + + + +
|
||||
* _EMPTY + + + + +
|
||||
* _FIRST + + + + +
|
||||
* _NEXT + + + + +
|
||||
* _PREV - - - + +
|
||||
* _LAST - - + + +
|
||||
* _FOREACH + + + + +
|
||||
* _FOREACH_REVERSE - - - + +
|
||||
* _INSERT_HEAD + + + + +
|
||||
* _INSERT_BEFORE - + - + +
|
||||
* _INSERT_AFTER + + + + +
|
||||
* _INSERT_TAIL - - + + +
|
||||
* _REMOVE_HEAD + - + - -
|
||||
* _REMOVE + + + + +
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Singly-linked List declarations.
|
||||
*/
|
||||
#define SLIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *slh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define SLIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define SLIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *sle_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked List functions.
|
||||
*/
|
||||
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
|
||||
|
||||
#define SLIST_FIRST(head) ((head)->slh_first)
|
||||
|
||||
#define SLIST_FOREACH(var, head, field) \
|
||||
for ((var) = SLIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = SLIST_NEXT((var), field))
|
||||
|
||||
#define SLIST_INIT(head) do { \
|
||||
SLIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
|
||||
SLIST_NEXT((slistelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_INSERT_HEAD(head, elm, field) do { \
|
||||
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
|
||||
SLIST_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
|
||||
|
||||
#define SLIST_REMOVE(head, elm, type, field) do { \
|
||||
if (SLIST_FIRST((head)) == (elm)) { \
|
||||
SLIST_REMOVE_HEAD((head), field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = SLIST_FIRST((head)); \
|
||||
while (SLIST_NEXT(curelm, field) != (elm)) \
|
||||
curelm = SLIST_NEXT(curelm, field); \
|
||||
SLIST_NEXT(curelm, field) = \
|
||||
SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define SLIST_REMOVE_HEAD(head, field) do { \
|
||||
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue declarations.
|
||||
*/
|
||||
#define STAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *stqh_first;/* first element */ \
|
||||
struct type **stqh_last;/* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define STAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).stqh_first }
|
||||
|
||||
#define STAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *stqe_next; /* next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Singly-linked Tail queue functions.
|
||||
*/
|
||||
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
|
||||
|
||||
#define STAILQ_FIRST(head) ((head)->stqh_first)
|
||||
|
||||
#define STAILQ_FOREACH(var, head, field) \
|
||||
for((var) = STAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = STAILQ_NEXT((var), field))
|
||||
|
||||
#define STAILQ_INIT(head) do { \
|
||||
STAILQ_FIRST((head)) = NULL; \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_NEXT((tqelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
STAILQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
STAILQ_NEXT((elm), field) = NULL; \
|
||||
STAILQ_LAST((head)) = (elm); \
|
||||
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_LAST(head) (*(head)->stqh_last)
|
||||
|
||||
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
|
||||
|
||||
#define STAILQ_REMOVE(head, elm, type, field) do { \
|
||||
if (STAILQ_FIRST((head)) == (elm)) { \
|
||||
STAILQ_REMOVE_HEAD(head, field); \
|
||||
} \
|
||||
else { \
|
||||
struct type *curelm = STAILQ_FIRST((head)); \
|
||||
while (STAILQ_NEXT(curelm, field) != (elm)) \
|
||||
curelm = STAILQ_NEXT(curelm, field); \
|
||||
if ((STAILQ_NEXT(curelm, field) = \
|
||||
STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
|
||||
(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD(head, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = \
|
||||
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
|
||||
if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
|
||||
(head)->stqh_last = &STAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* List declarations.
|
||||
*/
|
||||
#define LIST_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *lh_first; /* first element */ \
|
||||
}
|
||||
|
||||
#define LIST_HEAD_INITIALIZER(head) \
|
||||
{ NULL }
|
||||
|
||||
#define LIST_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *le_next; /* next element */ \
|
||||
struct type **le_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* List functions.
|
||||
*/
|
||||
|
||||
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
|
||||
|
||||
#define LIST_FIRST(head) ((head)->lh_first)
|
||||
|
||||
#define LIST_FOREACH(var, head, field) \
|
||||
for ((var) = LIST_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = LIST_NEXT((var), field))
|
||||
|
||||
#define LIST_INIT(head) do { \
|
||||
LIST_FIRST((head)) = NULL; \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
|
||||
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
|
||||
LIST_NEXT((listelm), field)->field.le_prev = \
|
||||
&LIST_NEXT((elm), field); \
|
||||
LIST_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.le_prev = (listelm)->field.le_prev; \
|
||||
LIST_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.le_prev = (elm); \
|
||||
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
|
||||
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
|
||||
LIST_FIRST((head)) = (elm); \
|
||||
(elm)->field.le_prev = &LIST_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
|
||||
|
||||
#define LIST_REMOVE(elm, field) do { \
|
||||
if (LIST_NEXT((elm), field) != NULL) \
|
||||
LIST_NEXT((elm), field)->field.le_prev = \
|
||||
(elm)->field.le_prev; \
|
||||
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Tail queue declarations.
|
||||
*/
|
||||
#define TAILQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *tqh_first; /* first element */ \
|
||||
struct type **tqh_last; /* addr of last next element */ \
|
||||
}
|
||||
|
||||
#define TAILQ_HEAD_INITIALIZER(head) \
|
||||
{ NULL, &(head).tqh_first }
|
||||
|
||||
#define TAILQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *tqe_next; /* next element */ \
|
||||
struct type **tqe_prev; /* address of previous next element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Tail queue functions.
|
||||
*/
|
||||
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
|
||||
|
||||
#define TAILQ_FIRST(head) ((head)->tqh_first)
|
||||
|
||||
#define TAILQ_FOREACH(var, head, field) \
|
||||
for ((var) = TAILQ_FIRST((head)); \
|
||||
(var); \
|
||||
(var) = TAILQ_NEXT((var), field))
|
||||
|
||||
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
|
||||
for ((var) = TAILQ_LAST((head), headname); \
|
||||
(var); \
|
||||
(var) = TAILQ_PREV((var), headname, field))
|
||||
|
||||
#define TAILQ_INIT(head) do { \
|
||||
TAILQ_FIRST((head)) = NULL; \
|
||||
(head)->tqh_last = &TAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_NEXT((listelm), field) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
|
||||
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
|
||||
TAILQ_NEXT((elm), field) = (listelm); \
|
||||
*(listelm)->field.tqe_prev = (elm); \
|
||||
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
|
||||
TAILQ_FIRST((head))->field.tqe_prev = \
|
||||
&TAILQ_NEXT((elm), field); \
|
||||
else \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
TAILQ_FIRST((head)) = (elm); \
|
||||
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
|
||||
TAILQ_NEXT((elm), field) = NULL; \
|
||||
(elm)->field.tqe_prev = (head)->tqh_last; \
|
||||
*(head)->tqh_last = (elm); \
|
||||
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#define TAILQ_LAST(head, headname) \
|
||||
(*(((struct headname *)((head)->tqh_last))->tqh_last))
|
||||
|
||||
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
|
||||
|
||||
#define TAILQ_PREV(elm, headname, field) \
|
||||
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
|
||||
|
||||
#define TAILQ_REMOVE(head, elm, field) do { \
|
||||
if ((TAILQ_NEXT((elm), field)) != NULL) \
|
||||
TAILQ_NEXT((elm), field)->field.tqe_prev = \
|
||||
(elm)->field.tqe_prev; \
|
||||
else \
|
||||
(head)->tqh_last = (elm)->field.tqe_prev; \
|
||||
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Circular queue declarations.
|
||||
*/
|
||||
#define CIRCLEQ_HEAD(name, type) \
|
||||
struct name { \
|
||||
struct type *cqh_first; /* first element */ \
|
||||
struct type *cqh_last; /* last element */ \
|
||||
}
|
||||
|
||||
#define CIRCLEQ_HEAD_INITIALIZER(head) \
|
||||
{ (void *)&(head), (void *)&(head) }
|
||||
|
||||
#define CIRCLEQ_ENTRY(type) \
|
||||
struct { \
|
||||
struct type *cqe_next; /* next element */ \
|
||||
struct type *cqe_prev; /* previous element */ \
|
||||
}
|
||||
|
||||
/*
|
||||
* Circular queue functions.
|
||||
*/
|
||||
#define CIRCLEQ_EMPTY(head) ((head)->cqh_first == (void *)(head))
|
||||
|
||||
#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
|
||||
|
||||
#define CIRCLEQ_FOREACH(var, head, field) \
|
||||
for ((var) = CIRCLEQ_FIRST((head)); \
|
||||
(var) != (void *)(head); \
|
||||
(var) = CIRCLEQ_NEXT((var), field))
|
||||
|
||||
#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
|
||||
for ((var) = CIRCLEQ_LAST((head)); \
|
||||
(var) != (void *)(head); \
|
||||
(var) = CIRCLEQ_PREV((var), field))
|
||||
|
||||
#define CIRCLEQ_INIT(head) do { \
|
||||
CIRCLEQ_FIRST((head)) = (void *)(head); \
|
||||
CIRCLEQ_LAST((head)) = (void *)(head); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
|
||||
CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field); \
|
||||
CIRCLEQ_PREV((elm), field) = (listelm); \
|
||||
if (CIRCLEQ_NEXT((listelm), field) == (void *)(head)) \
|
||||
CIRCLEQ_LAST((head)) = (elm); \
|
||||
else \
|
||||
CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
|
||||
CIRCLEQ_NEXT((listelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
|
||||
CIRCLEQ_NEXT((elm), field) = (listelm); \
|
||||
CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field); \
|
||||
if (CIRCLEQ_PREV((listelm), field) == (void *)(head)) \
|
||||
CIRCLEQ_FIRST((head)) = (elm); \
|
||||
else \
|
||||
CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
|
||||
CIRCLEQ_PREV((listelm), field) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
|
||||
CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head)); \
|
||||
CIRCLEQ_PREV((elm), field) = (void *)(head); \
|
||||
if (CIRCLEQ_LAST((head)) == (void *)(head)) \
|
||||
CIRCLEQ_LAST((head)) = (elm); \
|
||||
else \
|
||||
CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm); \
|
||||
CIRCLEQ_FIRST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
|
||||
CIRCLEQ_NEXT((elm), field) = (void *)(head); \
|
||||
CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head)); \
|
||||
if (CIRCLEQ_FIRST((head)) == (void *)(head)) \
|
||||
CIRCLEQ_FIRST((head)) = (elm); \
|
||||
else \
|
||||
CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm); \
|
||||
CIRCLEQ_LAST((head)) = (elm); \
|
||||
} while (0)
|
||||
|
||||
#define CIRCLEQ_LAST(head) ((head)->cqh_last)
|
||||
|
||||
#define CIRCLEQ_NEXT(elm,field) ((elm)->field.cqe_next)
|
||||
|
||||
#define CIRCLEQ_PREV(elm,field) ((elm)->field.cqe_prev)
|
||||
|
||||
#define CIRCLEQ_REMOVE(head, elm, field) do { \
|
||||
if (CIRCLEQ_NEXT((elm), field) == (void *)(head)) \
|
||||
CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field); \
|
||||
else \
|
||||
CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) = \
|
||||
CIRCLEQ_PREV((elm), field); \
|
||||
if (CIRCLEQ_PREV((elm), field) == (void *)(head)) \
|
||||
CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field); \
|
||||
else \
|
||||
CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) = \
|
||||
CIRCLEQ_NEXT((elm), field); \
|
||||
} while (0)
|
||||
|
||||
#endif /* !_SYS_QUEUE_H_ */
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is in the public domain.
|
||||
*/
|
||||
#ifndef _SCSI_SCSI_IU_H
|
||||
#define _SCSI_SCSI_IU_H 1
|
||||
|
||||
struct scsi_status_iu_header
|
||||
{
|
||||
u_int8_t reserved[2];
|
||||
u_int8_t flags;
|
||||
#define SIU_SNSVALID 0x2
|
||||
#define SIU_RSPVALID 0x1
|
||||
u_int8_t status;
|
||||
u_int8_t sense_length[4];
|
||||
u_int8_t pkt_failures_length[4];
|
||||
u_int8_t pkt_failures[1];
|
||||
};
|
||||
|
||||
#define SIU_PKTFAIL_OFFSET(siu) 12
|
||||
#define SIU_PKTFAIL_CODE(siu) (scsi_4btoul((siu)->pkt_failures) & 0xFF)
|
||||
#define SIU_PFC_NONE 0
|
||||
#define SIU_PFC_CIU_FIELDS_INVALID 2
|
||||
#define SIU_PFC_TMF_NOT_SUPPORTED 4
|
||||
#define SIU_PFC_TMF_FAILED 5
|
||||
#define SIU_PFC_INVALID_TYPE_CODE 6
|
||||
#define SIU_PFC_ILLEGAL_REQUEST 7
|
||||
#define SIU_SENSE_OFFSET(siu) \
|
||||
(12 + (((siu)->flags & SIU_RSPVALID) \
|
||||
? scsi_4btoul((siu)->pkt_failures_length) \
|
||||
: 0))
|
||||
#endif /*_SCSI_SCSI_IU_H*/
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is in the public domain.
|
||||
* $FreeBSD: src/sys/cam/scsi/scsi_message.h,v 1.2 2000/05/01 20:21:29 peter Exp $
|
||||
*/
|
||||
|
||||
/* Messages (1 byte) */ /* I/T (M)andatory or (O)ptional */
|
||||
#define MSG_CMDCOMPLETE 0x00 /* M/M */
|
||||
#define MSG_TASK_COMPLETE 0x00 /* M/M */ /* SPI3 Terminology */
|
||||
#define MSG_EXTENDED 0x01 /* O/O */
|
||||
#define MSG_SAVEDATAPOINTER 0x02 /* O/O */
|
||||
#define MSG_RESTOREPOINTERS 0x03 /* O/O */
|
||||
#define MSG_DISCONNECT 0x04 /* O/O */
|
||||
#define MSG_INITIATOR_DET_ERR 0x05 /* M/M */
|
||||
#define MSG_ABORT 0x06 /* O/M */
|
||||
#define MSG_ABORT_TASK_SET 0x06 /* O/M */ /* SPI3 Terminology */
|
||||
#define MSG_MESSAGE_REJECT 0x07 /* M/M */
|
||||
#define MSG_NOOP 0x08 /* M/M */
|
||||
#define MSG_PARITY_ERROR 0x09 /* M/M */
|
||||
#define MSG_LINK_CMD_COMPLETE 0x0a /* O/O */
|
||||
#define MSG_LINK_CMD_COMPLETEF 0x0b /* O/O */
|
||||
#define MSG_BUS_DEV_RESET 0x0c /* O/M */
|
||||
#define MSG_TARGET_RESET 0x0c /* O/M */ /* SPI3 Terminology */
|
||||
#define MSG_ABORT_TAG 0x0d /* O/O */
|
||||
#define MSG_ABORT_TASK 0x0d /* O/O */ /* SPI3 Terminology */
|
||||
#define MSG_CLEAR_QUEUE 0x0e /* O/O */
|
||||
#define MSG_CLEAR_TASK_SET 0x0e /* O/O */ /* SPI3 Terminology */
|
||||
#define MSG_INIT_RECOVERY 0x0f /* O/O */ /* Deprecated in SPI3 */
|
||||
#define MSG_REL_RECOVERY 0x10 /* O/O */ /* Deprecated in SPI3 */
|
||||
#define MSG_TERM_IO_PROC 0x11 /* O/O */ /* Deprecated in SPI3 */
|
||||
#define MSG_CLEAR_ACA 0x16 /* O/O */ /* SPI3 */
|
||||
#define MSG_LOGICAL_UNIT_RESET 0x17 /* O/O */ /* SPI3 */
|
||||
#define MSG_QAS_REQUEST 0x55 /* O/O */ /* SPI3 */
|
||||
|
||||
/* Messages (2 byte) */
|
||||
#define MSG_SIMPLE_Q_TAG 0x20 /* O/O */
|
||||
#define MSG_SIMPLE_TASK 0x20 /* O/O */ /* SPI3 Terminology */
|
||||
#define MSG_HEAD_OF_Q_TAG 0x21 /* O/O */
|
||||
#define MSG_HEAD_OF_QUEUE_TASK 0x21 /* O/O */ /* SPI3 Terminology */
|
||||
#define MSG_ORDERED_Q_TAG 0x22 /* O/O */
|
||||
#define MSG_ORDERED_TASK 0x22 /* O/O */ /* SPI3 Terminology */
|
||||
#define MSG_IGN_WIDE_RESIDUE 0x23 /* O/O */
|
||||
#define MSG_ACA_TASK 0x24 /* 0/0 */ /* SPI3 */
|
||||
|
||||
/* Identify message */ /* M/M */
|
||||
#define MSG_IDENTIFYFLAG 0x80
|
||||
#define MSG_IDENTIFY_DISCFLAG 0x40
|
||||
#define MSG_IDENTIFY(lun, disc) (((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
|
||||
#define MSG_ISIDENTIFY(m) ((m) & MSG_IDENTIFYFLAG)
|
||||
#define MSG_IDENTIFY_LUNMASK 0x3F
|
||||
|
||||
/* Extended messages (opcode and length) */
|
||||
#define MSG_EXT_SDTR 0x01
|
||||
#define MSG_EXT_SDTR_LEN 0x03
|
||||
|
||||
#define MSG_EXT_WDTR 0x03
|
||||
#define MSG_EXT_WDTR_LEN 0x02
|
||||
#define MSG_EXT_WDTR_BUS_8_BIT 0x00
|
||||
#define MSG_EXT_WDTR_BUS_16_BIT 0x01
|
||||
#define MSG_EXT_WDTR_BUS_32_BIT 0x02 /* Deprecated in SPI3 */
|
||||
|
||||
#define MSG_EXT_PPR 0x04 /* SPI3 */
|
||||
#define MSG_EXT_PPR_LEN 0x06
|
||||
#define MSG_EXT_PPR_PCOMP_EN 0x80
|
||||
#define MSG_EXT_PPR_RTI 0x40
|
||||
#define MSG_EXT_PPR_RD_STRM 0x20
|
||||
#define MSG_EXT_PPR_WR_FLOW 0x10
|
||||
#define MSG_EXT_PPR_HOLD_MCS 0x08
|
||||
#define MSG_EXT_PPR_QAS_REQ 0x04
|
||||
#define MSG_EXT_PPR_DT_REQ 0x02
|
||||
#define MSG_EXT_PPR_IU_REQ 0x01
|
||||
@@ -0,0 +1,500 @@
|
||||
#ifndef _I386_STRING_H_
|
||||
#define _I386_STRING_H_
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/config.h>
|
||||
/*
|
||||
* On a 486 or Pentium, we are better off not using the
|
||||
* byte string operations. But on a 386 or a PPro the
|
||||
* byte string ops are faster than doing it by hand
|
||||
* (MUCH faster on a Pentium).
|
||||
*
|
||||
* Also, the byte strings actually work correctly. Forget
|
||||
* the i486 routines for now as they may be broken..
|
||||
*/
|
||||
#if FIXED_486_STRING && defined(CONFIG_X86_USE_STRING_486)
|
||||
#include <asm/string-486.h>
|
||||
#else
|
||||
|
||||
/*
|
||||
* This string-include defines all string functions as inline
|
||||
* functions. Use gcc. It also assumes ds=es=data space, this should be
|
||||
* normal. Most of the string-functions are rather heavily hand-optimized,
|
||||
* see especially strtok,strstr,str[c]spn. They should work, but are not
|
||||
* very easy to understand. Everything is done entirely within the register
|
||||
* set, making the functions fast and clean. String instructions have been
|
||||
* used through-out, making for "slightly" unclear code :-)
|
||||
*
|
||||
* NO Copyright (C) 1991, 1992 Linus Torvalds,
|
||||
* consider these trivial functions to be PD.
|
||||
*/
|
||||
|
||||
|
||||
#define __HAVE_ARCH_STRCPY
|
||||
static inline char * strcpy(char * dest,const char *src)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
__asm__ __volatile__(
|
||||
"1:\tlodsb\n\t"
|
||||
"stosb\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b"
|
||||
: "=&S" (d0), "=&D" (d1), "=&a" (d2)
|
||||
:"0" (src),"1" (dest) : "memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRNCPY
|
||||
static inline char * strncpy(char * dest,const char *src,size_t count)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
__asm__ __volatile__(
|
||||
"1:\tdecl %2\n\t"
|
||||
"js 2f\n\t"
|
||||
"lodsb\n\t"
|
||||
"stosb\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n\t"
|
||||
"rep\n\t"
|
||||
"stosb\n"
|
||||
"2:"
|
||||
: "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
|
||||
:"0" (src),"1" (dest),"2" (count) : "memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRCAT
|
||||
static inline char * strcat(char * dest,const char * src)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
__asm__ __volatile__(
|
||||
"repne\n\t"
|
||||
"scasb\n\t"
|
||||
"decl %1\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"stosb\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b"
|
||||
: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
|
||||
: "0" (src), "1" (dest), "2" (0), "3" (0xffffffff):"memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRNCAT
|
||||
static inline char * strncat(char * dest,const char * src,size_t count)
|
||||
{
|
||||
int d0, d1, d2, d3;
|
||||
__asm__ __volatile__(
|
||||
"repne\n\t"
|
||||
"scasb\n\t"
|
||||
"decl %1\n\t"
|
||||
"movl %8,%3\n"
|
||||
"1:\tdecl %3\n\t"
|
||||
"js 2f\n\t"
|
||||
"lodsb\n\t"
|
||||
"stosb\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n"
|
||||
"2:\txorl %2,%2\n\t"
|
||||
"stosb"
|
||||
: "=&S" (d0), "=&D" (d1), "=&a" (d2), "=&c" (d3)
|
||||
: "0" (src),"1" (dest),"2" (0),"3" (0xffffffff), "g" (count)
|
||||
: "memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRCMP
|
||||
static inline int strcmp(const char * cs,const char * ct)
|
||||
{
|
||||
int d0, d1;
|
||||
register int __res;
|
||||
__asm__ __volatile__(
|
||||
"1:\tlodsb\n\t"
|
||||
"scasb\n\t"
|
||||
"jne 2f\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n\t"
|
||||
"xorl %%eax,%%eax\n\t"
|
||||
"jmp 3f\n"
|
||||
"2:\tsbbl %%eax,%%eax\n\t"
|
||||
"orb $1,%%al\n"
|
||||
"3:"
|
||||
:"=a" (__res), "=&S" (d0), "=&D" (d1)
|
||||
:"1" (cs),"2" (ct));
|
||||
return __res;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRNCMP
|
||||
static inline int strncmp(const char * cs,const char * ct,size_t count)
|
||||
{
|
||||
register int __res;
|
||||
int d0, d1, d2;
|
||||
__asm__ __volatile__(
|
||||
"1:\tdecl %3\n\t"
|
||||
"js 2f\n\t"
|
||||
"lodsb\n\t"
|
||||
"scasb\n\t"
|
||||
"jne 3f\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n"
|
||||
"2:\txorl %%eax,%%eax\n\t"
|
||||
"jmp 4f\n"
|
||||
"3:\tsbbl %%eax,%%eax\n\t"
|
||||
"orb $1,%%al\n"
|
||||
"4:"
|
||||
:"=a" (__res), "=&S" (d0), "=&D" (d1), "=&c" (d2)
|
||||
:"1" (cs),"2" (ct),"3" (count));
|
||||
return __res;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRCHR
|
||||
static inline char * strchr(const char * s, int c)
|
||||
{
|
||||
int d0;
|
||||
register char * __res;
|
||||
__asm__ __volatile__(
|
||||
"movb %%al,%%ah\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"cmpb %%ah,%%al\n\t"
|
||||
"je 2f\n\t"
|
||||
"testb %%al,%%al\n\t"
|
||||
"jne 1b\n\t"
|
||||
"movl $1,%1\n"
|
||||
"2:\tmovl %1,%0\n\t"
|
||||
"decl %0"
|
||||
:"=a" (__res), "=&S" (d0) : "1" (s),"0" (c));
|
||||
return __res;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRRCHR
|
||||
static inline char * strrchr(const char * s, int c)
|
||||
{
|
||||
int d0, d1;
|
||||
register char * __res;
|
||||
__asm__ __volatile__(
|
||||
"movb %%al,%%ah\n"
|
||||
"1:\tlodsb\n\t"
|
||||
"cmpb %%ah,%%al\n\t"
|
||||
"jne 2f\n\t"
|
||||
"leal -1(%%esi),%0\n"
|
||||
"2:\ttestb %%al,%%al\n\t"
|
||||
"jne 1b"
|
||||
:"=g" (__res), "=&S" (d0), "=&a" (d1) :"0" (0),"1" (s),"2" (c));
|
||||
return __res;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_STRLEN
|
||||
static inline size_t strlen(const char * s)
|
||||
{
|
||||
int d0;
|
||||
register int __res;
|
||||
__asm__ __volatile__(
|
||||
"repne\n\t"
|
||||
"scasb\n\t"
|
||||
"notl %0\n\t"
|
||||
"decl %0"
|
||||
:"=c" (__res), "=&D" (d0) :"1" (s),"a" (0), "0" (0xffffffff));
|
||||
return __res;
|
||||
}
|
||||
|
||||
static inline void * __memcpy(void * to, const void * from, size_t n)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
__asm__ __volatile__(
|
||||
"rep ; movsl\n\t"
|
||||
"testb $2,%b4\n\t"
|
||||
"je 1f\n\t"
|
||||
"movsw\n"
|
||||
"1:\ttestb $1,%b4\n\t"
|
||||
"je 2f\n\t"
|
||||
"movsb\n"
|
||||
"2:"
|
||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2)
|
||||
:"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from)
|
||||
: "memory");
|
||||
return (to);
|
||||
}
|
||||
|
||||
/*
|
||||
* This looks horribly ugly, but the compiler can optimize it totally,
|
||||
* as the count is constant.
|
||||
*/
|
||||
static inline void * __constant_memcpy(void * to, const void * from, size_t n)
|
||||
{
|
||||
switch (n) {
|
||||
case 0:
|
||||
return to;
|
||||
case 1:
|
||||
*(unsigned char *)to = *(const unsigned char *)from;
|
||||
return to;
|
||||
case 2:
|
||||
*(unsigned short *)to = *(const unsigned short *)from;
|
||||
return to;
|
||||
case 3:
|
||||
*(unsigned short *)to = *(const unsigned short *)from;
|
||||
*(2+(unsigned char *)to) = *(2+(const unsigned char *)from);
|
||||
return to;
|
||||
case 4:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
return to;
|
||||
case 6: /* for Ethernet addresses */
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(2+(unsigned short *)to) = *(2+(const unsigned short *)from);
|
||||
return to;
|
||||
case 8:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
return to;
|
||||
case 12:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
return to;
|
||||
case 16:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
|
||||
return to;
|
||||
case 20:
|
||||
*(unsigned long *)to = *(const unsigned long *)from;
|
||||
*(1+(unsigned long *)to) = *(1+(const unsigned long *)from);
|
||||
*(2+(unsigned long *)to) = *(2+(const unsigned long *)from);
|
||||
*(3+(unsigned long *)to) = *(3+(const unsigned long *)from);
|
||||
*(4+(unsigned long *)to) = *(4+(const unsigned long *)from);
|
||||
return to;
|
||||
}
|
||||
#define COMMON(x) \
|
||||
__asm__ __volatile__( \
|
||||
"rep ; movsl" \
|
||||
x \
|
||||
: "=&c" (d0), "=&D" (d1), "=&S" (d2) \
|
||||
: "0" (n/4),"1" ((long) to),"2" ((long) from) \
|
||||
: "memory");
|
||||
{
|
||||
int d0, d1, d2;
|
||||
switch (n % 4) {
|
||||
case 0: COMMON(""); return to;
|
||||
case 1: COMMON("\n\tmovsb"); return to;
|
||||
case 2: COMMON("\n\tmovsw"); return to;
|
||||
default: COMMON("\n\tmovsw\n\tmovsb"); return to;
|
||||
}
|
||||
}
|
||||
|
||||
#undef COMMON
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_MEMCPY
|
||||
|
||||
#define memcpy(t, f, n) \
|
||||
(__builtin_constant_p(n) ? \
|
||||
__constant_memcpy((t),(f),(n)) : \
|
||||
__memcpy((t),(f),(n)))
|
||||
|
||||
|
||||
/*
|
||||
* struct_cpy(x,y), copy structure *x into (matching structure) *y.
|
||||
*
|
||||
* We get link-time errors if the structure sizes do not match.
|
||||
* There is no runtime overhead, it's all optimized away at
|
||||
* compile time.
|
||||
*/
|
||||
//extern void __struct_cpy_bug (void);
|
||||
|
||||
/*
|
||||
#define struct_cpy(x,y) \
|
||||
({ \
|
||||
if (sizeof(*(x)) != sizeof(*(y))) \
|
||||
__struct_cpy_bug; \
|
||||
memcpy(x, y, sizeof(*(x))); \
|
||||
})
|
||||
*/
|
||||
|
||||
#define __HAVE_ARCH_MEMMOVE
|
||||
static inline void * memmove(void * dest,const void * src, size_t n)
|
||||
{
|
||||
int d0, d1, d2;
|
||||
if (dest<src)
|
||||
__asm__ __volatile__(
|
||||
"rep\n\t"
|
||||
"movsb"
|
||||
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||||
:"0" (n),"1" (src),"2" (dest)
|
||||
: "memory");
|
||||
else
|
||||
__asm__ __volatile__(
|
||||
"std\n\t"
|
||||
"rep\n\t"
|
||||
"movsb\n\t"
|
||||
"cld"
|
||||
: "=&c" (d0), "=&S" (d1), "=&D" (d2)
|
||||
:"0" (n),
|
||||
"1" (n-1+(const char *)src),
|
||||
"2" (n-1+(char *)dest)
|
||||
:"memory");
|
||||
return dest;
|
||||
}
|
||||
|
||||
#define memcmp __builtin_memcmp
|
||||
|
||||
#define __HAVE_ARCH_MEMCHR
|
||||
static inline void * memchr(const void * cs,int c,size_t count)
|
||||
{
|
||||
int d0;
|
||||
register void * __res;
|
||||
if (!count)
|
||||
return NULL;
|
||||
__asm__ __volatile__(
|
||||
"repne\n\t"
|
||||
"scasb\n\t"
|
||||
"je 1f\n\t"
|
||||
"movl $1,%0\n"
|
||||
"1:\tdecl %0"
|
||||
:"=D" (__res), "=&c" (d0) : "a" (c),"0" (cs),"1" (count));
|
||||
return __res;
|
||||
}
|
||||
|
||||
static inline void * __memset_generic(void * s, char c,size_t count)
|
||||
{
|
||||
int d0, d1;
|
||||
__asm__ __volatile__(
|
||||
"rep\n\t"
|
||||
"stosb"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
:"a" (c),"1" (s),"0" (count)
|
||||
:"memory");
|
||||
return s;
|
||||
}
|
||||
|
||||
/* we might want to write optimized versions of these later */
|
||||
#define __constant_count_memset(s,c,count) __memset_generic((s),(c),(count))
|
||||
|
||||
/*
|
||||
* memset(x,0,y) is a reasonably common thing to do, so we want to fill
|
||||
* things 32 bits at a time even when we don't know the size of the
|
||||
* area at compile-time..
|
||||
*/
|
||||
static inline void * __constant_c_memset(void * s, unsigned long c, size_t count)
|
||||
{
|
||||
int d0, d1;
|
||||
__asm__ __volatile__(
|
||||
"rep ; stosl\n\t"
|
||||
"testb $2,%b3\n\t"
|
||||
"je 1f\n\t"
|
||||
"stosw\n"
|
||||
"1:\ttestb $1,%b3\n\t"
|
||||
"je 2f\n\t"
|
||||
"stosb\n"
|
||||
"2:"
|
||||
: "=&c" (d0), "=&D" (d1)
|
||||
:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
|
||||
:"memory");
|
||||
return (s);
|
||||
}
|
||||
|
||||
/* Added by Gertjan van Wingerde to make minix and sysv module work */
|
||||
#define __HAVE_ARCH_STRNLEN
|
||||
static inline size_t strnlen(const char * s, size_t count)
|
||||
{
|
||||
int d0;
|
||||
register int __res;
|
||||
__asm__ __volatile__(
|
||||
"movl %2,%0\n\t"
|
||||
"jmp 2f\n"
|
||||
"1:\tcmpb $0,(%0)\n\t"
|
||||
"je 3f\n\t"
|
||||
"incl %0\n"
|
||||
"2:\tdecl %1\n\t"
|
||||
"cmpl $-1,%1\n\t"
|
||||
"jne 1b\n"
|
||||
"3:\tsubl %2,%0"
|
||||
:"=a" (__res), "=&d" (d0)
|
||||
:"c" (s),"1" (count));
|
||||
return __res;
|
||||
}
|
||||
/* end of additional stuff */
|
||||
|
||||
//#define __HAVE_ARCH_STRSTR
|
||||
|
||||
//extern char *strstr(const char *cs, const char *ct);
|
||||
|
||||
/*
|
||||
* This looks horribly ugly, but the compiler can optimize it totally,
|
||||
* as we by now know that both pattern and count is constant..
|
||||
*/
|
||||
static inline void * __constant_c_and_count_memset(void * s, unsigned long pattern, size_t count)
|
||||
{
|
||||
switch (count) {
|
||||
case 0:
|
||||
return s;
|
||||
case 1:
|
||||
*(unsigned char *)s = pattern;
|
||||
return s;
|
||||
case 2:
|
||||
*(unsigned short *)s = pattern;
|
||||
return s;
|
||||
case 3:
|
||||
*(unsigned short *)s = pattern;
|
||||
*(2+(unsigned char *)s) = pattern;
|
||||
return s;
|
||||
case 4:
|
||||
*(unsigned long *)s = pattern;
|
||||
return s;
|
||||
}
|
||||
#define COMMON(x) \
|
||||
__asm__ __volatile__( \
|
||||
"rep ; stosl" \
|
||||
x \
|
||||
: "=&c" (d0), "=&D" (d1) \
|
||||
: "a" (pattern),"0" (count/4),"1" ((long) s) \
|
||||
: "memory")
|
||||
{
|
||||
int d0, d1;
|
||||
switch (count % 4) {
|
||||
case 0: COMMON(""); return s;
|
||||
case 1: COMMON("\n\tstosb"); return s;
|
||||
case 2: COMMON("\n\tstosw"); return s;
|
||||
default: COMMON("\n\tstosw\n\tstosb"); return s;
|
||||
}
|
||||
}
|
||||
|
||||
#undef COMMON
|
||||
}
|
||||
|
||||
#define __constant_c_x_memset(s, c, count) \
|
||||
(__builtin_constant_p(count) ? \
|
||||
__constant_c_and_count_memset((s),(c),(count)) : \
|
||||
__constant_c_memset((s),(c),(count)))
|
||||
|
||||
#define __memset(s, c, count) \
|
||||
(__builtin_constant_p(count) ? \
|
||||
__constant_count_memset((s),(c),(count)) : \
|
||||
__memset_generic((s),(c),(count)))
|
||||
|
||||
#define __HAVE_ARCH_MEMSET
|
||||
#define memset(s, c, count) \
|
||||
(__builtin_constant_p(c) ? \
|
||||
__constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
|
||||
__memset((s),(c),(count)))
|
||||
|
||||
/*
|
||||
* find the first occurrence of byte 'c', or 1 past the area if none
|
||||
*/
|
||||
#define __HAVE_ARCH_MEMSCAN
|
||||
static inline void * memscan(void * addr, int c, size_t size)
|
||||
{
|
||||
if (!size)
|
||||
return addr;
|
||||
__asm__("repnz; scasb\n\t"
|
||||
"jnz 1f\n\t"
|
||||
"dec %%edi\n"
|
||||
"1:"
|
||||
: "=D" (addr), "=c" (size)
|
||||
: "0" (addr), "1" (size), "a" (c));
|
||||
return addr;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_X86_USE_STRING_486 */
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif
|
||||
@@ -14,6 +14,9 @@
|
||||
printk("Memory Reservation 0x%lx, %lu bytes\n", (_p), (_l))
|
||||
|
||||
/* lib.c */
|
||||
#include <xeno/string.h>
|
||||
|
||||
/* JWS - pulled over linux string library ({asm,linux}/string.h)
|
||||
int memcmp(const void * cs,const void * ct,size_t count);
|
||||
void * memcpy(void * dest,const void *src,size_t count);
|
||||
int strncmp(const char * cs,const char * ct,size_t count);
|
||||
@@ -25,6 +28,8 @@ size_t strnlen(const char * s, size_t count);
|
||||
size_t strlen(const char * s);
|
||||
char * strchr(const char *,int);
|
||||
char * strstr(const char * s1,const char * s2);
|
||||
*/
|
||||
|
||||
unsigned long str_to_quad(unsigned char *s);
|
||||
unsigned char *quad_to_str(unsigned long q, unsigned char *s);
|
||||
|
||||
@@ -46,6 +51,7 @@ extern int sscanf(const char *, const char *, ...)
|
||||
__attribute__ ((format (scanf,2,3)));
|
||||
extern int vsscanf(const char *, const char *, va_list);
|
||||
long simple_strtol(const char *cp,char **endp,unsigned int base);
|
||||
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
|
||||
long long simple_strtoll(const char *cp,char **endp,unsigned int base);
|
||||
|
||||
#endif /* __LIB_H__ */
|
||||
@@ -0,0 +1,90 @@
|
||||
#ifndef _LINUX_STRING_H_
|
||||
#define _LINUX_STRING_H_
|
||||
|
||||
/* We don't want strings.h stuff being user by user stuff by accident */
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/types.h> /* for size_t */
|
||||
//#include <linux/stddef.h> /* for NULL */
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define __kernel_size_t size_t
|
||||
|
||||
extern char * ___strtok;
|
||||
extern char * strpbrk(const char *,const char *);
|
||||
extern char * strtok(char *,const char *);
|
||||
extern char * strsep(char **,const char *);
|
||||
extern __kernel_size_t strspn(const char *,const char *);
|
||||
|
||||
|
||||
/*
|
||||
* Include machine specific inline routines
|
||||
*/
|
||||
#include <asm/string.h>
|
||||
|
||||
#ifndef __HAVE_ARCH_STRCPY
|
||||
extern char * strcpy(char *,const char *);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRNCPY
|
||||
extern char * strncpy(char *,const char *, __kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRCAT
|
||||
extern char * strcat(char *, const char *);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRNCAT
|
||||
extern char * strncat(char *, const char *, __kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRCMP
|
||||
extern int strcmp(const char *,const char *);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRNCMP
|
||||
extern int strncmp(const char *,const char *,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRNICMP
|
||||
extern int strnicmp(const char *, const char *, __kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRCHR
|
||||
extern char * strchr(const char *,int);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRRCHR
|
||||
extern char * strrchr(const char *,int);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRSTR
|
||||
extern char * strstr(const char *,const char *);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRLEN
|
||||
extern __kernel_size_t strlen(const char *);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_STRNLEN
|
||||
extern __kernel_size_t strnlen(const char *,__kernel_size_t);
|
||||
#endif
|
||||
|
||||
#ifndef __HAVE_ARCH_MEMSET
|
||||
extern void * memset(void *,int,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMCPY
|
||||
extern void * memcpy(void *,const void *,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMMOVE
|
||||
extern void * memmove(void *,const void *,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMSCAN
|
||||
extern void * memscan(void *,int,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMCMP
|
||||
extern int memcmp(const void *,const void *,__kernel_size_t);
|
||||
#endif
|
||||
#ifndef __HAVE_ARCH_MEMCHR
|
||||
extern void * memchr(const void *,int,__kernel_size_t);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* _LINUX_STRING_H_ */
|
||||