📄 aha152x.c
字号:
/* aha152x.c -- Adaptec AHA-152x driver
* Author: Juergen E. Fischer, fischer@server.et-inf.fho-emden.de
* Copyright 1993 Juergen E. Fischer
*
*
* This driver is based on
* fdomain.c -- Future Domain TMC-16x0 driver
* which is
* Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2, or (at your option) any
* later version.
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* $Id: aha152x.c,v 0.101 1993/12/13 01:16:27 root Exp $
*
* $Log: aha152x.c,v $
* Revision 0.101 1993/12/13 01:16:27 root
* - fixed STATUS phase (non-GOOD stati were dropped sometimes;
* fixes problems with CD-ROM sector size detection & media change)
*
* Revision 0.100 1993/12/10 16:58:47 root
* - fix for unsuccessful selections in case of non-continuous id assignments
* on the scsi bus.
*
* Revision 0.99 1993/10/24 16:19:59 root
* - fixed DATA IN (rare read errors gone)
*
* Revision 0.98 1993/10/17 12:54:44 root
* - fixed some recent fixes (shame on me)
* - moved initialization of scratch area to aha152x_queue
*
* Revision 0.97 1993/10/09 18:53:53 root
* - DATA IN fixed. Rarely left data in the fifo.
*
* Revision 0.96 1993/10/03 00:53:59 root
* - minor changes on DATA IN
*
* Revision 0.95 1993/09/24 10:36:01 root
* - change handling of MSGI after reselection
* - fixed sti/cli
* - minor changes
*
* Revision 0.94 1993/09/18 14:08:22 root
* - fixed bug in multiple outstanding command code
* - changed detection
* - support for kernel command line configuration
* - reset corrected
* - changed message handling
*
* Revision 0.93 1993/09/15 20:41:19 root
* - fixed bugs with multiple outstanding commands
*
* Revision 0.92 1993/09/13 02:46:33 root
* - multiple outstanding commands work (no problems with IBM drive)
*
* Revision 0.91 1993/09/12 20:51:46 root
* added multiple outstanding commands
* (some problem with this $%&? IBM device remain)
*
* Revision 0.9 1993/09/12 11:11:22 root
* - corrected auto-configuration
* - changed the auto-configuration (added some '#define's)
* - added support for dis-/reconnection
*
* Revision 0.8 1993/09/06 23:09:39 root
* - added support for the drive activity light
* - minor changes
*
* Revision 0.7 1993/09/05 14:30:15 root
* - improved phase detection
* - now using the new snarf_region code of 0.99pl13
*
* Revision 0.6 1993/09/02 11:01:38 root
* first public release; added some signatures and biosparam()
*
* Revision 0.5 1993/08/30 10:23:30 root
* fixed timing problems with my IBM drive
*
* Revision 0.4 1993/08/29 14:06:52 root
* fixed some problems with timeouts due incomplete commands
*
* Revision 0.3 1993/08/28 15:55:03 root
* writing data works too. mounted and worked on a dos partition
*
* Revision 0.2 1993/08/27 22:42:07 root
* reading data works. Mounted a msdos partition.
*
* Revision 0.1 1993/08/25 13:38:30 root
* first "damn thing doesn't work" version
*
* Revision 0.0 1993/08/14 19:54:25 root
* empty function bodies; detect() works.
*
**************************************************************************
DESCRIPTION:
This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522
SCSI host adapters.
PER-DEFINE CONFIGURABLE OPTIONS:
AUTOCONF : use configuration the controller reports (only 152x)
IRQ : override interrupt channel (9,10,11 or 12) (default 11)
SCSI_ID : override scsiid of AIC-6260 (0-7) (default 7)
RECONNECT : override target dis-/reconnection/multiple outstanding commands
SKIP_BIOSTEST : Don't test for BIOS signature (AHA-1510 or disabled BIOS)
PORTBASE : Force port base. Don't try to probe
LILO COMMAND LINE OPTIONS:
aha152x=<PORTBASE>,<IRQ>,<SCSI-ID>,<RECONNECT>
The normal configuration can be overridden by specifying a command line.
When you do this, the BIOS test is skipped. Entered values have to be
valid (known). Don't use values that aren't support under normal operation.
If you think that you need other value: contact me.
REFERENCES USED:
"AIC-6260 SCSI Chip Specification", Adaptec Corporation.
"SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
"Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
"Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
"Adaptec 1520/1522 User's Guide", Adaptec Corporation.
Michael K. Johnson (johnsonm@sunsite.unc.edu)
Drew Eckhardt (drew@cs.colorado.edu)
Eric Youngdale (eric@tantalus.nrl.navy.mil)
special thanks to Eric Youngdale for the free(!) supplying the
documentation on the chip.
**************************************************************************/
#include "aha152x.h"
#include <linux/sched.h>
#include <asm/io.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/ioport.h>
/* DEFINES */
/* If auto configuration is disabled, IRQ, SCSI_ID and RECONNECT have to
be predefined */
#if !defined(AUTOCONF)
#if !defined(IRQ)
#error undefined IRQ; define AUTOCONF or IRQ
#endif
#if !defined(SCSI_ID)
#error undefined SCSI_ID; define AUTOCONF or SCSI_ID
#endif
#if !defined(RECONNECT)
#error undefined RECONNECT; define AUTOCONF or RECONNECT
#endif
#endif
/* I use this when I'm looking for weird bugs */
#define DEBUG_TIMING
#if defined(DEBUG)
#undef SKIP_PORTS /* don't display ports */
#undef DEBUG_QUEUE /* debug queue() */
#undef DEBUG_RESET /* debug reset() */
#undef DEBUG_INTR /* debug intr() */
#undef DEBUG_SELECTION /* debug selection part in intr() */
#undef DEBUG_MSGO /* debug message out phase in intr() */
#undef DEBUG_MSGI /* debug message in phase in intr() */
#undef DEBUG_STATUS /* debug status phase in intr() */
#undef DEBUG_CMD /* debug command phase in intr() */
#undef DEBUG_DATAI /* debug data in phase in intr() */
#undef DEBUG_DATAO /* debug data out phase in intr() */
#undef DEBUG_ABORT /* debug abort() */
#undef DEBUG_DONE /* debug done() */
#undef DEBUG_BIOSPARAM /* debug biosparam() */
#undef DEBUG_RACE /* debug race conditions */
#undef DEBUG_PHASES /* debug phases (useful to trace) */
#undef DEBUG_QUEUES /* debug reselection */
/* recently used for debugging */
#if 0
#define DEBUG_PHASES
#define DEBUG_DATAI
#endif
#endif
#define DEBUG_RESET /* resets should be rare */
#define DEBUG_ABORT /* aborts too */
/* END OF DEFINES */
/* some additional "phases" for getphase() */
#define P_BUSFREE 1
#define P_PARITY 2
char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.101 $\n";
static int port_base = 0;
static int this_host = 0;
static int can_disconnect = 0;
static int commands = 0;
/* set by aha152x_setup according to the command line */
static int setup_called = 0;
static int setup_portbase = 0;
static int setup_irq = 0;
static int setup_scsiid = 0;
static int setup_reconnect = 0;
static char *setup_str = (char *)NULL;
enum {
not_issued = 0x01,
in_selection = 0x02,
disconnected = 0x04,
aborted = 0x08,
sent_ident = 0x10,
in_other = 0x20,
};
/*
* Command queues:
* issue_SC : commands that are queued to be issued
* current_SC : command that's currently using the bus
* disconnected_SC : commands that that have been disconnected
*/
static Scsi_Cmnd *issue_SC = NULL;
static Scsi_Cmnd *current_SC = NULL;
static Scsi_Cmnd *disconnected_SC = NULL;
static struct wait_queue *abortion_complete;
static int abort_result;
void aha152x_intr( int irqno );
void aha152x_done( int error );
void aha152x_setup( char *str, int *ints );
static void aha152x_reset_ports(void);
static void aha152x_panic(char *msg);
static void disp_ports(void);
static void show_command(Scsi_Cmnd *ptr);
static void show_queues(void);
static void disp_enintr(void);
#if defined(DEBUG_RACE)
static void enter_driver(const char *);
static void leave_driver(const char *);
#endif
/* possible locations for the Adaptec BIOS */
static void *addresses[] =
{
(void *) 0xdc000, /* default first */
(void *) 0xc8000,
(void *) 0xcc000,
(void *) 0xd0000,
(void *) 0xd4000,
(void *) 0xd8000,
(void *) 0xe0000,
(void *) 0xf0000,
};
#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
/* possible i/o adresses for the AIC-6260 */
static unsigned short ports[] =
{
0x340, /* default first */
0x140
};
#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
/* possible interrupt channels */
static unsigned short ints[] = { 9, 10, 11, 12 };
/* signatures for various AIC-6260 based controllers */
static struct signature {
char *signature;
int sig_offset;
int sig_length;
} signatures[] =
{
{
"Adaptec AHA-1520 BIOS\r\n\0\
Version 1.4 \r\n\0\
Copyright 1990 Adaptec, Inc.\r\n\
All Rights Reserved\r\n \r\n \r\n", 0x102e, 101
}, /* Adaptec 152x */
{
"Adaptec ASW-B626 BIOS\r\n\0\
Version 1.0 \r\n\0\
Copyright 1990 Adaptec, Inc.\r\n\
All Rights Reserved\r\n\0 \r\n \r\n", 0x1029, 102
}, /* on-board controller */
{ "Adaptec BIOS: ASW-B626", 0x0F, 22}, /* on-board controller */
{ "Adaptec ASW-B626 S2 BIOS", 0x2e6c, 24}, /* on-board controller */
};
#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
{
unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
while (jiffies < the_time)
;
}
/*
* queue services:
*/
static inline void append_SC( Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
{
Scsi_Cmnd *end;
new_SC->host_scribble = (unsigned char *) NULL;
if(!*SC)
*SC=new_SC;
else
{
for( end=*SC;
end->host_scribble;
end = (Scsi_Cmnd *) end->host_scribble )
;
end->host_scribble = (unsigned char *) new_SC;
}
}
static inline Scsi_Cmnd *remove_first_SC( Scsi_Cmnd **SC )
{
Scsi_Cmnd *ptr;
ptr=*SC;
if(ptr)
*SC= (Scsi_Cmnd *) (*SC)->host_scribble;
return ptr;
}
static inline Scsi_Cmnd *remove_SC( Scsi_Cmnd **SC, int target, int lun )
{
Scsi_Cmnd *ptr, *prev;
for( ptr=*SC, prev=NULL;
ptr && ((ptr->target!=target) || (ptr->lun!=lun));
prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble )
;
if(ptr)
if(prev)
prev->host_scribble = ptr->host_scribble;
else
*SC= (Scsi_Cmnd *) ptr->host_scribble;
return ptr;
}
/*
* read inbound byte and wait for ACK to get low
*/
static void make_acklow(void)
{
SETPORT( SXFRCTL0, CH1|SPIOEN );
GETPORT(SCSIDAT);
SETPORT( SXFRCTL0, CH1 );
while( TESTHI( SCSISIG, ACKI ) )
;
}
/*
* detect current phase more reliable:
* phase is valid, when the target asserts REQ after we've deasserted ACK.
*
* return value is a valid phase or an error code.
*
* errorcodes:
* P_BUSFREE BUS FREE phase detected
* P_PARITY parity error in DATA phase
*/
static int getphase(void)
{
int phase, sstat1;
while( 1 )
{
do
{
while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
;
if( sstat1 & BUSFREE )
return P_BUSFREE;
if( sstat1 & SCSIRSTI )
{
/* IBM drive responds with RSTI to RSTO */
printk("aha152x: RESET IN\n");
SETPORT( SSTAT1, SCSIRSTI );
}
}
while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) );
SETPORT( SSTAT1, CLRSCSIPERR );
phase = GETPORT( SCSISIG ) & P_MASK ;
if( TESTHI( SSTAT1, SCSIPERR ) )
{
if( (phase & (CDO|MSGO))==0 ) /* DATA phase */
return P_PARITY;
make_acklow();
}
else
return phase;
}
}
/* called from init/main.c */
void aha152x_setup( char *str, int *ints)
{
if(setup_called)
panic("aha152x: aha152x_setup called twice.\n");
setup_called=ints[0];
setup_str=str;
if(ints[0] != 4)
return;
setup_portbase = ints[1];
setup_irq = ints[2];
setup_scsiid = ints[3];
setup_reconnect = ints[4];
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -