freebsd-src/sys/i386/scsi/aic7xxx.h

397 lines
12 KiB
C
Raw Normal View History

/*
1995-05-30 08:16:23 +00:00
* Interface to the generic driver for the aic7xxx based adaptec
* SCSI controllers. This is used to implement product specific
* probe and attach routines.
*
* Copyright (c) 1994, 1995, 1996, 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 immediately at the beginning of the file, without modification,
* 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.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* 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: aic7xxx.h,v 1.39 1997/02/22 09:38:42 peter Exp $
*/
#ifndef _AIC7XXX_H_
#define _AIC7XXX_H_
#if defined(__FreeBSD__)
#include "ahc.h" /* for NAHC from config */
#include "opt_aic7xxx.h" /* for config options */
#endif
#if defined(__NetBSD__)
/*
* convert FreeBSD's <sys/queue.h> symbols to NetBSD's
*/
#define STAILQ_ENTRY SIMPLEQ_ENTRY
#define STAILQ_HEAD SIMPLEQ_HEAD
#define STAILQ_INIT SIMPLEQ_INIT
#define STAILQ_INSERT_HEAD SIMPLEQ_INSERT_HEAD
#define STAILQ_INSERT_TAIL SIMPLEQ_INSERT_TAIL
#define STAILQ_REMOVE_HEAD(head, field) \
SIMPLEQ_REMOVE_HEAD(head, (head)->sqh_first, field)
#define stqh_first sqh_first
#define stqe_next sqe_next
#endif
#define AHC_NSEG 32 /* The number of dma segments supported.
White space cleanup and other cosmetic style changes. Fix a few panics during error recovery: 1) Stupid mistake in the "no SCB match handler" where I was using the wrong variable (busy_scbid instead of scb_index). 2) Unbusy the target of an abort request if the command we are trying to abort is an untagged transaction. If we don't, we get a fatal NO_MATCH_BUSY condition which "should never happen". 3) When an abort completes, turn off ahc->in_timeout or else the next timeout will hit the protective "scb timesout again" panic. 4) Fix a typo that caused the requeued "abort" SCB to have its TAG_ENB and disconnect bits to be cleared (missing ~) so that devices would complain about overlapped commands. Be sure to turn off the unexpected busfree interrupt after we do a bus reset since we are expecting the bus to go free in that case. Return XS_TIMEOUT instead of XS_DRIVERSTUFFUP in certain scenarios. XS_TIMEOUT allows for retries, XS_DRIVERSTUFFUP does not. Allow commands with SDTR and WDTR negotiation to be tagged. The SCSI II spec says that you probably should not do this for fear of hitting bogus devices. The driver did this in the past for almost two years without any problem, and not doing it causes problems during error recovery to a tag capable device as the number of openings is higher than two and we'll start sending it tagged commands causing "overlapped commands attempted" type errors. The real fix needs to happen in the generic SCSI layer which can limit the number and type of transactions to a device during error recovery efficiently. Give ourselves at least 100ms to perform a request sense instead of relying on the original timeout to be long enough to complete this new command as well as the one that generated the condition. Removed some redundant code.
1997-02-03 02:16:16 +00:00
* AHC_NSEG can be maxed out at 256 entries,
* but the kernel will never need to transfer
* such a large (1MB) request. To reduce the
* driver's memory consumption, we reduce the
* max to 32. 16 would work if all transfers
* are paged alined since the kernel will only
* generate at most a 64k transfer, but to
* handle non-page aligned transfers, you need
* 17, so we round to the next power of two
* to make allocating SG space easy and
* efficient.
*/
Clean up a few nits in the aic7xxx driver: 1) Make the driver "quiet" by sticking most boot messages behind bootverbose conditionals. This means that you won't see the sync and wide negotiation, but you will find out if they fail. 2) Add support to the 93cx6 serial eeprom code to read at an abitrary offset. This is needed so that we can access the second half of the eeprom on 3940 cards where the second channel's config is stored. 3) Add flags argument to ahcprobe(). This is used by the pci probe code to tell the generic driver that an adapter should be treated as a channel B device as well as notify it of the presence of external SCB SRAM. These are needed for some motherboard implementations of the aic7870 and for the 3940 controllers. 4) Print "Channel A"/"Channel B" instead of "Single Channel" for the two busses of the 3940. I received many reports of confusion about how the 3940 was probed since most people belived that only one ahc entry was needed. This will hopefully make it clearer. 5) Walk the SCBs to determine just how many their are if external SCB ram is detected. 6) Hard code that external SCB ram is present for the 3940 since it doesn't use the documented reporting facility for reporting the SRAM. :( 255 commands per channel are supported on the 3940. 7) Read the seeprom starting at addres 32 for the second channel of the 3940 so we get the right info for that channel. 8) Clean up printing of the "Disabling tagged queuing message". 9) Queue timeouts if they occur while we are handling a timeout. The code was totally unprotected in this scenario. Reviewed by: Timeout code reviewed by David Greenman <davidg>
1995-09-05 23:52:03 +00:00
#define AHC_SCB_MAX 255 /*
* Up to 255 SCBs on some types of aic7xxx
* based boards. The aic7870 have 16 internal
* SCBs, but external SRAM bumps this to 255.
* The aic7770 family have only 4, and the
* aic7850 has only 3.
*/
typedef u_int32_t physaddr;
#if defined(__FreeBSD__)
extern u_long ahc_unit;
#endif
struct ahc_dma_seg {
physaddr addr;
u_int32_t len;
};
1995-05-30 08:16:23 +00:00
1995-06-11 19:33:05 +00:00
typedef enum {
AHC_NONE = 0x0000,
AHC_ULTRA = 0x0001, /* Supports 20MHz Transfers */
AHC_WIDE = 0x0002, /* Wide Channel */
AHC_TWIN = 0x0008, /* Twin Channel */
AHC_AIC7770 = 0x0010,
AHC_AIC7850 = 0x0020,
AHC_AIC7860 = 0x0021, /* ULTRA version of the aic7850 */
AHC_AIC7870 = 0x0040,
AHC_AIC7880 = 0x0041,
AHC_AIC78X0 = 0x0060, /* PCI Based Controller */
AHC_274 = 0x0110, /* EISA Based Controller */
AHC_284 = 0x0210, /* VL/ISA Based Controller */
AHC_294AU = 0x0421, /* aic7860 based '2940' */
AHC_294 = 0x0440, /* PCI Based Controller */
AHC_294U = 0x0441, /* ULTRA PCI Based Controller */
AHC_394 = 0x0840, /* Twin Channel PCI Controller */
AHC_394U = 0x0841, /* ULTRA, Twin Channel PCI Controller */
AHC_398 = 0x1040, /* Multi Channel PCI RAID Controller */
AHC_398U = 0x1041, /* ULTRA, Multi Channel PCI
* RAID Controller
*/
AHC_39X = 0x1800 /* Multi Channel PCI Adapter */
1995-06-11 19:33:05 +00:00
}ahc_type;
Clean up a few nits in the aic7xxx driver: 1) Make the driver "quiet" by sticking most boot messages behind bootverbose conditionals. This means that you won't see the sync and wide negotiation, but you will find out if they fail. 2) Add support to the 93cx6 serial eeprom code to read at an abitrary offset. This is needed so that we can access the second half of the eeprom on 3940 cards where the second channel's config is stored. 3) Add flags argument to ahcprobe(). This is used by the pci probe code to tell the generic driver that an adapter should be treated as a channel B device as well as notify it of the presence of external SCB SRAM. These are needed for some motherboard implementations of the aic7870 and for the 3940 controllers. 4) Print "Channel A"/"Channel B" instead of "Single Channel" for the two busses of the 3940. I received many reports of confusion about how the 3940 was probed since most people belived that only one ahc entry was needed. This will hopefully make it clearer. 5) Walk the SCBs to determine just how many their are if external SCB ram is detected. 6) Hard code that external SCB ram is present for the 3940 since it doesn't use the documented reporting facility for reporting the SRAM. :( 255 commands per channel are supported on the 3940. 7) Read the seeprom starting at addres 32 for the second channel of the 3940 so we get the right info for that channel. 8) Clean up printing of the "Disabling tagged queuing message". 9) Queue timeouts if they occur while we are handling a timeout. The code was totally unprotected in this scenario. Reviewed by: Timeout code reviewed by David Greenman <davidg>
1995-09-05 23:52:03 +00:00
typedef enum {
AHC_FNONE = 0x00,
AHC_INIT = 0x01,
AHC_RUNNING = 0x02,
AHC_PAGESCBS = 0x04, /* Enable SCB paging */
AHC_CHANNEL_B_PRIMARY = 0x08, /*
* On twin channel adapters, probe
* channel B first since it is the
* primary bus.
*/
AHC_USEDEFAULTS = 0x10, /*
* For cards without an seeprom
* or a BIOS to initialize the chip's
* SRAM, we use the default target
* settings.
*/
AHC_CHNLB = 0x20, /*
* Second controller on 3940/398X
Clean up a few nits in the aic7xxx driver: 1) Make the driver "quiet" by sticking most boot messages behind bootverbose conditionals. This means that you won't see the sync and wide negotiation, but you will find out if they fail. 2) Add support to the 93cx6 serial eeprom code to read at an abitrary offset. This is needed so that we can access the second half of the eeprom on 3940 cards where the second channel's config is stored. 3) Add flags argument to ahcprobe(). This is used by the pci probe code to tell the generic driver that an adapter should be treated as a channel B device as well as notify it of the presence of external SCB SRAM. These are needed for some motherboard implementations of the aic7870 and for the 3940 controllers. 4) Print "Channel A"/"Channel B" instead of "Single Channel" for the two busses of the 3940. I received many reports of confusion about how the 3940 was probed since most people belived that only one ahc entry was needed. This will hopefully make it clearer. 5) Walk the SCBs to determine just how many their are if external SCB ram is detected. 6) Hard code that external SCB ram is present for the 3940 since it doesn't use the documented reporting facility for reporting the SRAM. :( 255 commands per channel are supported on the 3940. 7) Read the seeprom starting at addres 32 for the second channel of the 3940 so we get the right info for that channel. 8) Clean up printing of the "Disabling tagged queuing message". 9) Queue timeouts if they occur while we are handling a timeout. The code was totally unprotected in this scenario. Reviewed by: Timeout code reviewed by David Greenman <davidg>
1995-09-05 23:52:03 +00:00
* Also encodes the offset in the
* SEEPROM for CHNLB info (32)
*/
AHC_CHNLC = 0x40 /*
* Third controller on 3985
* Also encodes the offset in the
* SEEPROM for CHNLC info (64)
*/
} ahc_flag;
Clean up a few nits in the aic7xxx driver: 1) Make the driver "quiet" by sticking most boot messages behind bootverbose conditionals. This means that you won't see the sync and wide negotiation, but you will find out if they fail. 2) Add support to the 93cx6 serial eeprom code to read at an abitrary offset. This is needed so that we can access the second half of the eeprom on 3940 cards where the second channel's config is stored. 3) Add flags argument to ahcprobe(). This is used by the pci probe code to tell the generic driver that an adapter should be treated as a channel B device as well as notify it of the presence of external SCB SRAM. These are needed for some motherboard implementations of the aic7870 and for the 3940 controllers. 4) Print "Channel A"/"Channel B" instead of "Single Channel" for the two busses of the 3940. I received many reports of confusion about how the 3940 was probed since most people belived that only one ahc entry was needed. This will hopefully make it clearer. 5) Walk the SCBs to determine just how many their are if external SCB ram is detected. 6) Hard code that external SCB ram is present for the 3940 since it doesn't use the documented reporting facility for reporting the SRAM. :( 255 commands per channel are supported on the 3940. 7) Read the seeprom starting at addres 32 for the second channel of the 3940 so we get the right info for that channel. 8) Clean up printing of the "Disabling tagged queuing message". 9) Queue timeouts if they occur while we are handling a timeout. The code was totally unprotected in this scenario. Reviewed by: Timeout code reviewed by David Greenman <davidg>
1995-09-05 23:52:03 +00:00
typedef enum {
SCB_FREE = 0x0000,
SCB_ACTIVE = 0x0001,
SCB_ABORTED = 0x0002,
SCB_DEVICE_RESET = 0x0004,
SCB_SENSE = 0x0008,
SCB_TIMEDOUT = 0x0010,
SCB_QUEUED_FOR_DONE = 0x0020,
SCB_RECOVERY_SCB = 0x0040,
SCB_WAITINGQ = 0x0080,
SCB_ASSIGNEDQ = 0x0100,
SCB_SENTORDEREDTAG = 0x0200,
SCB_MSGOUT_SDTR = 0x0400,
SCB_MSGOUT_WDTR = 0x0800,
SCB_ABORT = 0x1000,
SCB_QUEUED_ABORT = 0x2000
} scb_flag;
/*
* The driver keeps up to MAX_SCB scb structures per card in memory. The SCB
* consists of a "hardware SCB" mirroring the fields availible on the card
* and additional information the kernel stores for each transaction.
*/
struct hardware_scb {
/*0*/ u_int8_t control;
/*1*/ u_int8_t tcl; /* 4/1/3 bits */
/*2*/ u_int8_t status;
/*3*/ u_int8_t SG_segment_count;
/*4*/ physaddr SG_list_pointer;
/*8*/ u_int8_t residual_SG_segment_count;
/*9*/ u_int8_t residual_data_count[3];
/*12*/ physaddr data;
/*16*/ u_int32_t datalen; /* Really only three bits, but its
* faster to treat it as a long on
* a quad boundary.
*/
/*20*/ physaddr cmdpointer;
/*24*/ u_int8_t cmdlen;
/*25*/ u_int8_t tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
*/
#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
* via PIO to initialize a transaction.
*/
/*26*/ u_int8_t next; /* Used for threading SCBs in the
* "Waiting for Selection" and
* "Disconnected SCB" lists down
* in the sequencer.
*/
/*27*/ u_int8_t prev;
/*28*/ u_int32_t pad; /*
* Unused by the kernel, but we require
* the padding so that the array of
* hardware SCBs is alligned on 32 byte
* boundaries so the sequencer can
* index them easily.
*/
};
struct scb {
struct hardware_scb *hscb;
STAILQ_ENTRY(scb) links; /* for chaining */
struct scsi_xfer *xs; /* the scsi_xfer for this cmd */
scb_flag flags;
struct ahc_dma_seg *ahc_dma;/* Pointer to SG segments */
struct scsi_sense sense_cmd;
u_int8_t sg_count;/* How full ahc_dma_seg is */
u_int8_t position;/* Position in card's scbarray */
};
1995-05-30 08:16:23 +00:00
struct scb_data {
struct hardware_scb *hscbs; /* Array of hardware SCBs */
struct scb *scbarray[AHC_SCB_MAX]; /* Array of kernel SCBs */
STAILQ_HEAD(, scb) free_scbs; /*
* Pool of SCBs ready to be assigned
* commands to execute.
*/
u_int8_t numscbs;
u_int8_t maxhscbs; /* Number of SCBs on the card */
u_int8_t maxscbs; /*
* Max SCBs we allocate total including
* any that will force us to page SCBs
*/
};
struct ahc_busreset_args {
struct ahc_softc *ahc;
char bus;
};
struct ahc_softc {
#if defined(__FreeBSD__)
int unit;
#elif defined(__NetBSD__)
struct device sc_dev;
void *sc_ih;
bus_chipset_tag_t sc_bc;
bus_io_handle_t sc_ioh;
#endif
ahc_type type;
Clean up a few nits in the aic7xxx driver: 1) Make the driver "quiet" by sticking most boot messages behind bootverbose conditionals. This means that you won't see the sync and wide negotiation, but you will find out if they fail. 2) Add support to the 93cx6 serial eeprom code to read at an abitrary offset. This is needed so that we can access the second half of the eeprom on 3940 cards where the second channel's config is stored. 3) Add flags argument to ahcprobe(). This is used by the pci probe code to tell the generic driver that an adapter should be treated as a channel B device as well as notify it of the presence of external SCB SRAM. These are needed for some motherboard implementations of the aic7870 and for the 3940 controllers. 4) Print "Channel A"/"Channel B" instead of "Single Channel" for the two busses of the 3940. I received many reports of confusion about how the 3940 was probed since most people belived that only one ahc entry was needed. This will hopefully make it clearer. 5) Walk the SCBs to determine just how many their are if external SCB ram is detected. 6) Hard code that external SCB ram is present for the 3940 since it doesn't use the documented reporting facility for reporting the SRAM. :( 255 commands per channel are supported on the 3940. 7) Read the seeprom starting at addres 32 for the second channel of the 3940 so we get the right info for that channel. 8) Clean up printing of the "Disabling tagged queuing message". 9) Queue timeouts if they occur while we are handling a timeout. The code was totally unprotected in this scenario. Reviewed by: Timeout code reviewed by David Greenman <davidg>
1995-09-05 23:52:03 +00:00
ahc_flag flags;
#if defined(__FreeBSD__)
u_int32_t baseport;
#endif
volatile u_int8_t *maddr;
struct scb_data *scb_data;
struct ahc_busreset_args busreset_args;
struct ahc_busreset_args busreset_args_b;
struct scsi_link sc_link;
struct scsi_link sc_link_b; /* Second bus for Twin channel cards */
STAILQ_HEAD(, scb) waiting_scbs;/*
* SCBs waiting ready to go but
* waiting for space in the QINFIFO.
*/
u_int8_t activescbs;
u_int16_t needsdtr_orig; /* Targets we initiate sync neg with */
u_int16_t needwdtr_orig; /* Targets we initiate wide neg with */
u_int16_t needsdtr; /* Current list of negotiated targets */
u_int16_t needwdtr; /* Current list of negotiated targets */
u_int16_t sdtrpending; /* Pending SDTR to these targets */
u_int16_t wdtrpending; /* Pending WDTR to these targets */
u_int16_t tagenable; /* Targets that can handle tags */
u_int16_t orderedtag; /* Targets to use ordered tag on */
u_int16_t discenable; /* Targets allowed to disconnect */
u_int8_t our_id; /* our scsi id */
u_int8_t our_id_b; /* B channel scsi id */
u_int8_t qcntmask; /*
* Mask of valid registers in the
* Q*CNT registers.
*/
u_int8_t qfullcount; /*
* The maximum number of entries
* storable in the Q*FIFOs.
*/
u_int8_t curqincnt; /*
* The current value we "think" the
* QINCNT has. The reason it is
* "think" is that this is a cached
* value that is only updated when
* curqincount == qfullcount to reduce
* the amount of accesses made to the
* card.
*/
u_int8_t unpause;
u_int8_t pause;
u_int8_t in_timeout;
u_int8_t in_reset;
#define CHANNEL_A_RESET 0x01
#define CHANNEL_B_RESET 0x02
};
struct full_ahc_softc {
struct ahc_softc softc;
struct scb_data scb_data_storage;
};
/* #define AHC_DEBUG */
#ifdef AHC_DEBUG
/* Different debugging levels used when AHC_DEBUG is defined */
#define AHC_SHOWMISC 0x0001
#define AHC_SHOWCMDS 0x0002
#define AHC_SHOWSCBS 0x0004
#define AHC_SHOWABORTS 0x0008
#define AHC_SHOWSENSE 0x0010
#define AHC_SHOWSCBCNT 0x0020
extern int ahc_debug; /* Initialized in i386/scsi/aic7xxx.c */
#endif
#if defined(__FreeBSD__)
char *ahc_name __P((struct ahc_softc *ahc));
struct ahc_softc *ahc_alloc __P((int unit, u_int32_t io_base,
vm_offset_t maddr, ahc_type type,
ahc_flag flags, struct scb_data *scb_data));
#elif defined(__NetBSD__)
#define ahc_name(ahc) (ahc)->sc_dev.dv_xname
void ahc_construct __P((struct ahc_softc *ahc, bus_chipset_tag_t bc, bus_io_handle_t ioh, ahc_type type, ahc_flag flags));
#endif
void ahc_reset __P((struct ahc_softc *ahc));
void ahc_free __P((struct ahc_softc *));
int ahc_init __P((struct ahc_softc *));
int ahc_attach __P((struct ahc_softc *));
#if defined(__FreeBSD__)
void ahc_intr __P((void *arg));
#elif defined(__NetBSD__)
int ahc_intr __P((void *arg));
#endif
#if defined(__FreeBSD__)
static __inline u_int8_t ahc_inb __P((struct ahc_softc *ahc, u_int32_t port));
static __inline void ahc_outb __P((struct ahc_softc *ahc, u_int32_t port,
u_int8_t val));
static __inline void ahc_outsb __P((struct ahc_softc *ahc, u_int32_t port,
u_int8_t *valp, size_t size));
static __inline u_int8_t
ahc_inb(ahc, port)
struct ahc_softc *ahc;
u_int32_t port;
{
if (ahc->maddr != NULL)
return ahc->maddr[port];
else
return inb(ahc->baseport + port);
}
static __inline void
ahc_outb(ahc, port, val)
struct ahc_softc *ahc;
u_int32_t port;
u_int8_t val;
{
if (ahc->maddr != NULL)
ahc->maddr[port] = val;
else
outb(ahc->baseport + port, val);
}
static __inline void
ahc_outsb(ahc, port, valp, size)
struct ahc_softc *ahc;
u_int32_t port;
u_int8_t *valp;
size_t size;
{
if (ahc->maddr != NULL) {
__asm __volatile("
cld;
1: lodsb;
movb %%al,(%0);
loop 1b" :
:
"r" ((ahc)->maddr + (port)),
"S" ((valp)), "c" ((size)) :
"%esi", "%ecx", "%eax");
} else
outsb(ahc->baseport + port, valp, size);
}
#elif defined(__NetBSD__)
#define ahc_inb(ahc, port) \
bus_io_read_1((ahc)->sc_bc, (ahc)->sc_ioh, port)
#define ahc_outb(ahc, port, val) \
bus_io_write_1((ahc)->sc_bc, (ahc)->sc_ioh, port, val)
#define ahc_outsb(ahc, port, valp, size) \
bus_io_write_multi_1((ahc)->sc_bc, (ahc)->sc_ioh, port, valp, size)
#endif
#endif /* _AIC7XXX_H_ */