1994-11-17 20:22:31 +00:00
|
|
|
/*
|
1995-01-13 02:24:31 +00:00
|
|
|
* Generic driver for the aic7xxx based adaptec SCSI controllers
|
|
|
|
* Product specific probe and attach routines can be found in:
|
1996-01-03 06:32:12 +00:00
|
|
|
* i386/eisa/aic7770.c 27/284X and aic7770 motherboard controllers
|
1996-10-25 06:42:53 +00:00
|
|
|
* pci/aic7870.c 3940, 2940, aic7880, aic7870, aic7860,
|
|
|
|
* and aic7850 controllers
|
1995-01-13 02:24:31 +00:00
|
|
|
*
|
1996-04-20 21:29:27 +00:00
|
|
|
* Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
|
|
|
|
* All rights reserved.
|
1994-11-17 20:22:31 +00:00
|
|
|
*
|
1996-04-20 21:29:27 +00:00
|
|
|
* 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.
|
1994-11-17 20:22:31 +00:00
|
|
|
*
|
1996-04-20 21:29:27 +00:00
|
|
|
* 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.
|
1994-11-17 20:22:31 +00:00
|
|
|
*
|
1996-10-25 06:42:53 +00:00
|
|
|
* $Id: aic7xxx.c,v 1.75.2.5 1996/10/06 22:48:12 gibbs Exp $
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* Implement Target Mode
|
|
|
|
*
|
1996-10-25 06:42:53 +00:00
|
|
|
* A few notes on features of the driver.
|
1996-04-20 21:29:27 +00:00
|
|
|
*
|
|
|
|
* SCB paging takes advantage of the fact that devices stay disconnected
|
|
|
|
* from the bus a relatively long time and that while they're disconnected,
|
1996-10-25 06:42:53 +00:00
|
|
|
* having the SCBs for these transactions down on the host adapter is of
|
|
|
|
* little use. Instead of leaving this idle SCB down on the card we copy
|
|
|
|
* it back up into kernel memory and reuse the SCB slot on the card to
|
|
|
|
* schedule another transaction. This can be a real payoff when doing random
|
|
|
|
* I/O to tagged queueing devices since there are more transactions active at
|
|
|
|
* once for the device to sort for optimal seek reduction. The algorithm goes
|
|
|
|
* like this...
|
1996-04-20 21:29:27 +00:00
|
|
|
*
|
1996-10-25 06:42:53 +00:00
|
|
|
* The sequencer maintains two lists of its hardware SCBs. The first is the
|
|
|
|
* singly linked free list which tracks all SCBs that are not currently in
|
|
|
|
* use. The second is the doubly linked disconnected list which holds the
|
|
|
|
* SCBs of transactions that are in the disconnected state sorted most
|
|
|
|
* recently disconnected first. When the kernel queues a transaction to
|
|
|
|
* the card, a hardware SCB to "house" this transaction is retrieved from
|
|
|
|
* either of these two lists. If the SCB came from the disconnected list,
|
|
|
|
* a check is made to see if any data transfer or SCB linking (more on linking
|
|
|
|
* in a bit) information has been changed since it was copied from the host
|
|
|
|
* and if so, DMAs the SCB back up before it can be used. Once a hardware
|
|
|
|
* SCB has been obtained, the SCB is DMAed from the host. Before any work
|
|
|
|
* can begin on this SCB, the sequencer must ensure that either the SCB is
|
|
|
|
* for a tagged transaction or the target is not already working on another
|
|
|
|
* non-tagged transaction. If a conflict arises in the non-tagged case, the
|
|
|
|
* sequencer finds the SCB for the active transactions and sets the SCB_LINKED
|
|
|
|
* field in that SCB to this next SCB to execute. To facilitate finding
|
|
|
|
* active non-tagged SCBs, the last four bytes of up to the first four hardware
|
|
|
|
* SCBs serve as a storage area for the currently active SCB ID for each
|
|
|
|
* target.
|
1996-04-20 21:29:27 +00:00
|
|
|
*
|
1996-10-25 06:42:53 +00:00
|
|
|
* When a device reconnects, a search is made of the hardware SCBs to find
|
|
|
|
* the SCB for this transaction. If the search fails, a hardware SCB is
|
|
|
|
* pulled from either the free or disconnected SCB list and the proper
|
|
|
|
* SCB is DMAed from the host. If the SCB_ABORTED control bit is set
|
|
|
|
* in the control byte of the SCB while it was disconnected, the sequencer
|
|
|
|
* will send an abort or abort tag message to the target during the
|
|
|
|
* reconnection and signal the kernel that the abort was successfull.
|
1996-04-20 21:29:27 +00:00
|
|
|
*
|
1996-10-25 06:42:53 +00:00
|
|
|
* When a command completes, a check for non-zero status and residuals is
|
|
|
|
* made. If either of these conditions exists, the SCB is DMAed back up to
|
|
|
|
* the host so that it can interpret this information. Additionally, in the
|
|
|
|
* case of bad status, the sequencer generates a special interrupt and pauses
|
|
|
|
* itself. This allows the host to setup a request sense command if it
|
|
|
|
* chooses for this target synchronously with the error so that sense
|
|
|
|
* information isn't lost.
|
1996-04-20 21:29:27 +00:00
|
|
|
*
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/systm.h>
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
#include <sys/device.h>
|
|
|
|
#include <machine/bus.h>
|
|
|
|
#include <machine/intr.h>
|
|
|
|
#endif /* defined(__NetBSD__) */
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
#include <sys/malloc.h>
|
|
|
|
#include <sys/buf.h>
|
|
|
|
#include <sys/proc.h>
|
1995-12-06 23:52:35 +00:00
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
#include <scsi/scsi_all.h>
|
1996-10-06 16:38:45 +00:00
|
|
|
#include <scsi/scsi_message.h>
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
#include <scsi/scsi_debug.h>
|
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
#include <scsi/scsiconf.h>
|
1995-12-06 23:52:35 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-03-07 08:59:28 +00:00
|
|
|
#include <machine/clock.h>
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1995-12-06 23:52:35 +00:00
|
|
|
|
|
|
|
#include <vm/vm.h>
|
1995-12-07 12:48:31 +00:00
|
|
|
#include <vm/vm_param.h>
|
|
|
|
#include <vm/pmap.h>
|
1995-12-06 23:52:35 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-10-01 03:01:06 +00:00
|
|
|
#include "opt_aic7xxx.h"
|
1995-01-13 02:27:08 +00:00
|
|
|
#include <i386/scsi/aic7xxx.h>
|
1995-12-06 23:52:35 +00:00
|
|
|
|
1995-11-05 04:50:55 +00:00
|
|
|
#include <dev/aic7xxx/aic7xxx_reg.h>
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif /* defined(__FreeBSD__) */
|
|
|
|
|
|
|
|
#if defined(__NetBSD__)
|
|
|
|
#include <dev/ic/aic7xxxreg.h>
|
|
|
|
#include <dev/ic/aic7xxxvar.h>
|
|
|
|
|
|
|
|
#define bootverbose 1
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
#if DEBUGTARGET < 0 /* Negative numbrs for disabling cause warnings */
|
|
|
|
#define DEBUGTARGET 17
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
|
|
|
#endif /* defined(__NetBSD__) */
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
#include <sys/kernel.h>
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
1995-07-31 08:25:36 +00:00
|
|
|
#define ALL_TARGETS -1
|
Fixes to the aic7xxx sequencer code and device driver from Justin Gibbs:
1) If a target initiated a sync negotiation with us and happened to chose a
value above 15, the old code inadvertantly truncated it with an "& 0x0f".
If the periferal picked something really bad like 0x32, you'd end up with
an offset of 2 which would hang the drive since it didn't expect to ever
get something so low. We now do a MIN(maxoffset, given_offset).
2) In the case of Wide cards, we were turning on sync transfers after a
sucessfull wide negotiation. Now we leave the offset alone in the per
target scratch space (which implies asyncronous transfers since we initialize
it that way) until a syncronous negotation occurs.
3) We were advertizing a max offset of 15 instead of 8 for wide devices.
4) If the upper level SCSI code sent down a "SCSI_RESET", it would hang the
system because we would end up sending a null command to the sequencer. Now
we handle SCSI_RESET correctly by having the sequencer interrupt us when it
is about to fill the message buffer so that we can fill it in ourselves.
The sequencer will also "simulate" a command complete for these "message only"
SCBs so that the kernel driver can finish up properly. The cdplay utility
will send a "SCSI_REST" to the cdplayer if you use the reset command.
5) The code that handles SCSIINTs was broken in that if more than one type
of error was true at once, we'd do outbs without the card being paused.
The else clause after the busfree case was also an accident waiting to
happen. I've now turned this into an if, else if, else type of thing, since
in most cases when we handle one type of error, it should be okay to ignore
the rest (ie if we have a SELTO, who cares if there was a parity error on
the transaction?), but the section should really be rewritten after 2.0.5.
This fix was the least obtrusive way to patch the problem.
6) Only tag either SDTR or WDTR negotiation on an SCB. The real problem is
that I don't account for the case when an SCB that is tagged to do a particular
type of negotiation completes or SELTOs (selection timeout) without the
negotiation taking place, so the accounting of sdtrpending and wdtrpending
gets screwed up. In the wide case, if we tag it to do both wdtr and sdtr,
it only performs wdtr (since wdtr must occur first and we spread out the
negotiation over two commands) so we always have sdtrpending set for that
target and we never do a real SDTR. I fill properly fix the accounting
after 2.0.5 goes out the door, but this works (as confirmed by Dan) on
wide targets.
Other stuff that is also included:
1) Don't do a bzero when recycling SCBs. The only thing that must explicitly
be set to zero is the scb control byte which is done in ahc_get_scb. We also
need to set the SG_list_pointer and SG_list_count to 0 for commands that do
not transfer data.
2) Mask the interrupt type printout for the aic7870 case. The bit we were
using to determine interrupt type is only valid for the aic7770.
Submitted by: Justin Gibbs
1995-05-17 07:06:02 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-06 05:21:13 +00:00
|
|
|
u_long ahc_unit = 0;
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-04-20 21:29:27 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1996-05-30 07:19:59 +00:00
|
|
|
static int ahc_debug = AHC_DEBUG;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef AHC_BROKEN_CACHE
|
|
|
|
int ahc_broken_cache = 1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* "wbinvd" cause writing back whole cache (both CPU internal & external)
|
|
|
|
* to memory, so that the instruction takes a lot of time.
|
|
|
|
* This makes machine slow.
|
|
|
|
*/
|
|
|
|
#define INVALIDATE_CACHE() __asm __volatile("wbinvd")
|
1996-04-20 21:29:27 +00:00
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
/**** bit definitions for SCSIDEF ****/
|
1995-01-13 02:24:31 +00:00
|
|
|
#define HSCSIID 0x07 /* our SCSI ID */
|
|
|
|
#define HWSCSIID 0x0f /* our SCSI ID if Wide Bus */
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
static void ahcminphys __P((struct buf *bp));
|
|
|
|
static int32_t ahc_scsi_cmd __P((struct scsi_xfer *xs));
|
|
|
|
static void ahc_run_waiting_queue __P((struct ahc_data *ahc));
|
|
|
|
static struct scb *
|
|
|
|
ahc_get_scb __P((struct ahc_data *ahc, u_int32_t flags));
|
|
|
|
static void ahc_free_scb __P((struct ahc_data *ahc, struct scb *scb));
|
|
|
|
static struct scb *
|
|
|
|
ahc_alloc_scb __P((struct ahc_data *ahc));
|
1996-10-06 16:38:45 +00:00
|
|
|
static inline void pause_sequencer __P((struct ahc_data *ahc));
|
|
|
|
static inline void unpause_sequencer __P((struct ahc_data *ahc,
|
|
|
|
int unpause_always));
|
|
|
|
static inline void restart_sequencer __P((struct ahc_data *ahc));
|
1995-12-15 23:49:42 +00:00
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static struct scsi_adapter ahc_switch =
|
1995-05-30 08:16:23 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_scsi_cmd,
|
|
|
|
ahcminphys,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-10-25 06:42:53 +00:00
|
|
|
NULL,
|
|
|
|
"ahc",
|
|
|
|
{ 0, 0 }
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1995-05-30 08:16:23 +00:00
|
|
|
};
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static struct scsi_device ahc_dev =
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
NULL, /* Use default error handler */
|
|
|
|
NULL, /* have a queue, served by this */
|
|
|
|
NULL, /* have no async handler */
|
|
|
|
NULL, /* Use default 'done' routine */
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-10-25 06:42:53 +00:00
|
|
|
"ahc",
|
|
|
|
0,
|
|
|
|
{ 0, 0 }
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
};
|
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
static inline void
|
|
|
|
pause_sequencer(ahc)
|
|
|
|
struct ahc_data *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_INB(ahc, HCNTRL) & PAUSE) == 0)
|
1996-01-03 06:32:12 +00:00
|
|
|
;
|
1996-10-06 16:38:45 +00:00
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
static inline void
|
|
|
|
unpause_sequencer(ahc, unpause_always)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
int unpause_always;
|
|
|
|
{
|
|
|
|
if (unpause_always
|
1996-10-25 06:42:53 +00:00
|
|
|
|| (AHC_INB(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
|
1996-10-06 16:38:45 +00:00
|
|
|
AHC_OUTB(ahc, HCNTRL, ahc->unpause);
|
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Restart the sequencer program from address zero
|
|
|
|
*/
|
1996-10-06 16:38:45 +00:00
|
|
|
static inline void
|
|
|
|
restart_sequencer(ahc)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
{
|
|
|
|
do {
|
|
|
|
AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
|
1996-10-25 06:42:53 +00:00
|
|
|
} while ((AHC_INB(ahc, SEQADDR0) != 0)
|
|
|
|
|| (AHC_INB(ahc, SEQADDR1) != 0));
|
1996-10-06 16:38:45 +00:00
|
|
|
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
|
|
|
}
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
#define IS_SCSIBUS_B(ahc, sc_link) \
|
|
|
|
(((u_int32_t)(sc_link)->fordriver) & SELBUSB)
|
|
|
|
#else /* NetBSD/OpenBSD */
|
1996-05-30 07:19:59 +00:00
|
|
|
#define IS_SCSIBUS_B(ahc, sc_link) \
|
|
|
|
((sc_link)->scsibus == (ahc)->sc_link_b.scsibus)
|
|
|
|
#endif
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
static u_int8_t ahc_abort_wscb __P((struct ahc_data *ahc, struct scb *scbp,
|
|
|
|
u_int8_t scbpos, u_int8_t prev,
|
|
|
|
struct scb *timedout_scb,
|
|
|
|
u_int32_t xs_error));
|
1996-01-03 06:32:12 +00:00
|
|
|
static void ahc_done __P((struct ahc_data *ahc, struct scb *scbp));
|
1996-10-25 06:42:53 +00:00
|
|
|
static void ahc_handle_seqint __P((struct ahc_data *ahc, u_int8_t intstat));
|
|
|
|
static void ahc_handle_scsiint __P((struct ahc_data *ahc,
|
|
|
|
u_int8_t intstat));
|
1996-05-30 07:19:59 +00:00
|
|
|
static void ahc_loadseq __P((struct ahc_data *ahc));
|
1995-12-15 23:49:42 +00:00
|
|
|
static int ahc_match_scb __P((struct scb *scb, int target, char channel));
|
1996-01-29 03:17:39 +00:00
|
|
|
static int ahc_poll __P((struct ahc_data *ahc, int wait));
|
1995-12-15 23:49:42 +00:00
|
|
|
#ifdef AHC_DEBUG
|
|
|
|
static void ahc_print_scb __P((struct scb *scb));
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
static u_int8_t find_scb __P((struct ahc_data *ahc, struct scb *scb));
|
1996-01-03 06:32:12 +00:00
|
|
|
static int ahc_reset_channel __P((struct ahc_data *ahc, char channel,
|
1996-10-25 06:42:53 +00:00
|
|
|
struct scb *timedout_scb,
|
|
|
|
u_int32_t xs_error,
|
|
|
|
int initiate_reset));
|
1996-01-03 06:32:12 +00:00
|
|
|
static int ahc_reset_device __P((struct ahc_data *ahc, int target,
|
1996-10-25 06:42:53 +00:00
|
|
|
char channel, struct scb *timedout_scb,
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
u_int32_t xs_error));
|
1996-05-30 07:19:59 +00:00
|
|
|
static void ahc_reset_current_bus __P((struct ahc_data *ahc));
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
static void ahc_run_done_queue __P((struct ahc_data *ahc));
|
1996-10-06 16:38:45 +00:00
|
|
|
static void ahc_scsirate __P((struct ahc_data* ahc, u_int8_t *scsirate,
|
|
|
|
u_int8_t *period, u_int8_t *offset,
|
|
|
|
char channel, int target));
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-12-15 23:49:42 +00:00
|
|
|
static timeout_t
|
|
|
|
ahc_timeout;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
static void ahc_timeout __P((void *));
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
static void ahc_unbusy_target __P((struct ahc_data *ahc,
|
|
|
|
int target, char channel));
|
1996-10-25 06:42:53 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
static void ahc_construct_sdtr __P((struct ahc_data *ahc, int start_byte,
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t period, u_int8_t offset));
|
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
static void ahc_construct_wdtr __P((struct ahc_data *ahc, int start_byte,
|
|
|
|
u_int8_t bus_width));
|
1996-05-30 07:19:59 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
static void ahc_calc_residual __P((struct scb *scb));
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
|
|
|
|
char *ahc_name(ahc)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
{
|
|
|
|
static char name[10];
|
|
|
|
|
|
|
|
sprintf(name, "ahc%d", ahc->unit);
|
|
|
|
return (name);
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
struct cfdriver ahc_cd = {
|
|
|
|
NULL, "ahc", DV_DULL
|
|
|
|
};
|
|
|
|
#endif
|
1995-12-15 23:49:42 +00:00
|
|
|
|
1995-02-22 01:43:25 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc_print_scb(scb)
|
|
|
|
struct scb *scb;
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
|
|
|
|
scb,
|
|
|
|
scb->control,
|
|
|
|
scb->tcl,
|
|
|
|
scb->cmdlen,
|
|
|
|
scb->cmdpointer );
|
|
|
|
printf(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
|
|
|
|
scb->datalen,
|
|
|
|
scb->data,
|
|
|
|
scb->SG_segment_count,
|
|
|
|
scb->SG_list_pointer);
|
|
|
|
printf(" sg_addr:%lx sg_len:%ld\n",
|
|
|
|
scb->ahc_dma[0].addr,
|
|
|
|
scb->ahc_dma[0].len);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1995-02-22 01:43:25 +00:00
|
|
|
#endif
|
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
static struct {
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t errno;
|
1994-11-17 20:22:31 +00:00
|
|
|
char *errmesg;
|
|
|
|
} hard_error[] = {
|
1995-03-07 08:59:28 +00:00
|
|
|
{ ILLHADDR, "Illegal Host Access" },
|
|
|
|
{ ILLSADDR, "Illegal Sequencer Address referrenced" },
|
|
|
|
{ ILLOPCODE, "Illegal Opcode in sequencer program" },
|
|
|
|
{ PARERR, "Sequencer Ram Parity Error" }
|
1995-05-30 08:16:23 +00:00
|
|
|
};
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Valid SCSIRATE values. (p. 3-17)
|
|
|
|
* Provides a mapping of tranfer periods in ns to the proper value to
|
|
|
|
* stick in the scsiscfr reg to use that transfer rate.
|
|
|
|
*/
|
|
|
|
static struct {
|
1996-10-25 06:42:53 +00:00
|
|
|
int sxfr;
|
1995-10-26 23:57:18 +00:00
|
|
|
/* Rates in Ultra mode have bit 8 of sxfr set */
|
|
|
|
#define ULTRA_SXFR 0x100
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t period; /* Period to send to SCSI target */
|
1994-11-17 20:22:31 +00:00
|
|
|
char *rate;
|
|
|
|
} ahc_syncrates[] = {
|
1996-10-06 16:38:45 +00:00
|
|
|
{ 0x100, 12, "20.0" },
|
|
|
|
{ 0x110, 15, "16.0" },
|
|
|
|
{ 0x120, 18, "13.4" },
|
|
|
|
{ 0x000, 25, "10.0" },
|
|
|
|
{ 0x010, 31, "8.0" },
|
|
|
|
{ 0x020, 37, "6.67" },
|
|
|
|
{ 0x030, 43, "5.7" },
|
|
|
|
{ 0x040, 50, "5.0" },
|
|
|
|
{ 0x050, 56, "4.4" },
|
|
|
|
{ 0x060, 62, "4.0" },
|
|
|
|
{ 0x070, 68, "3.6" }
|
1994-11-17 20:22:31 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static int ahc_num_syncrates =
|
|
|
|
sizeof(ahc_syncrates) / sizeof(ahc_syncrates[0]);
|
|
|
|
|
|
|
|
/*
|
1995-11-05 04:50:55 +00:00
|
|
|
* Allocate a controller structures for a new device and initialize it.
|
|
|
|
* ahc_reset should be called before now since we assume that the card
|
|
|
|
* is paused.
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-05 04:50:55 +00:00
|
|
|
struct ahc_data *
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_alloc(unit, iobase, maddr, type, flags)
|
1995-01-13 02:24:31 +00:00
|
|
|
int unit;
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int32_t iobase;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
void
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_construct(ahc, bc, ioh, maddr, type, flags)
|
1996-05-30 07:19:59 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
bus_chipset_tag_t bc;
|
|
|
|
bus_io_handle_t ioh;
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
vm_offset_t maddr;
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc_type type;
|
1995-09-05 23:52:03 +00:00
|
|
|
ahc_flag flags;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
|
|
|
|
1996-01-03 06:32:12 +00:00
|
|
|
/*
|
|
|
|
* find unit and check we have that many defined
|
|
|
|
*/
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-01-03 06:32:12 +00:00
|
|
|
struct ahc_data *ahc;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-01-03 06:32:12 +00:00
|
|
|
/*
|
|
|
|
* Allocate a storage area for us
|
|
|
|
*/
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc = malloc(sizeof(struct ahc_data), M_TEMP, M_NOWAIT);
|
|
|
|
if (!ahc) {
|
|
|
|
printf("ahc%d: cannot malloc!\n", unit);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
bzero(ahc, sizeof(struct ahc_data));
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1996-04-20 21:29:27 +00:00
|
|
|
STAILQ_INIT(&ahc->free_scbs);
|
|
|
|
STAILQ_INIT(&ahc->waiting_scbs);
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-04-20 21:29:27 +00:00
|
|
|
ahc->unit = unit;
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__)
|
1996-04-20 21:29:27 +00:00
|
|
|
ahc->baseport = iobase;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
ahc->sc_bc = bc;
|
|
|
|
ahc->sc_ioh = ioh;
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc->maddr = (volatile u_int8_t *)maddr;
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc->type = type;
|
1995-09-05 23:52:03 +00:00
|
|
|
ahc->flags = flags;
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->unpause = (AHC_INB(ahc, HCNTRL) & IRQMS) | INTEN;
|
1995-11-05 04:50:55 +00:00
|
|
|
ahc->pause = ahc->unpause | PAUSE;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-01-03 06:32:12 +00:00
|
|
|
return (ahc);
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-11-05 04:50:55 +00:00
|
|
|
void
|
|
|
|
ahc_free(ahc)
|
1996-01-03 06:32:12 +00:00
|
|
|
struct ahc_data *ahc;
|
1995-11-05 04:50:55 +00:00
|
|
|
{
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-05 04:50:55 +00:00
|
|
|
free(ahc, M_DEVBUF);
|
|
|
|
return;
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1995-11-05 04:50:55 +00:00
|
|
|
void
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-05 04:50:55 +00:00
|
|
|
ahc_reset(iobase)
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int32_t iobase;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
ahc_reset(devname, bc, ioh)
|
|
|
|
char *devname;
|
|
|
|
bus_chipset_tag_t bc;
|
|
|
|
bus_io_handle_t ioh;
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t hcntrl;
|
1995-11-05 04:50:55 +00:00
|
|
|
int wait;
|
|
|
|
|
|
|
|
/* Retain the IRQ type accross the chip reset */
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-05 04:50:55 +00:00
|
|
|
hcntrl = (inb(HCNTRL + iobase) & IRQMS) | INTEN;
|
1996-05-10 16:21:05 +00:00
|
|
|
|
1995-11-05 04:50:55 +00:00
|
|
|
outb(HCNTRL + iobase, CHIPRST | PAUSE);
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
hcntrl = (bus_io_read_1(bc, ioh, HCNTRL) & IRQMS) | INTEN;
|
|
|
|
|
|
|
|
bus_io_write_1(bc, ioh, HCNTRL, CHIPRST | PAUSE);
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
/*
|
|
|
|
* Ensure that the reset has finished
|
|
|
|
*/
|
|
|
|
wait = 1000;
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-05-10 16:21:05 +00:00
|
|
|
while (--wait && !(inb(HCNTRL + iobase) & CHIPRSTACK))
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
while (--wait && !(bus_io_read_1(bc, ioh, HCNTRL) & CHIPRSTACK))
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
DELAY(1000);
|
1996-10-25 06:42:53 +00:00
|
|
|
if (wait == 0) {
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-06 05:21:13 +00:00
|
|
|
printf("ahc at 0x%lx: WARNING - Failed chip reset! "
|
1995-11-05 04:50:55 +00:00
|
|
|
"Trying to initialize anyway.\n", iobase);
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
printf("%s: WARNING - Failed chip reset! "
|
|
|
|
"Trying to initialize anyway.\n", devname);
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1995-11-05 04:50:55 +00:00
|
|
|
outb(HCNTRL + iobase, hcntrl | PAUSE);
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
bus_io_write_1(bc, ioh, HCNTRL, hcntrl | PAUSE);
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Look up the valid period to SCSIRATE conversion in our table.
|
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1996-05-21 18:37:25 +00:00
|
|
|
ahc_scsirate(ahc, scsirate, period, offset, channel, target )
|
1996-10-06 16:38:45 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int8_t *scsirate;
|
|
|
|
u_int8_t *period;
|
|
|
|
u_int8_t *offset;
|
|
|
|
char channel;
|
|
|
|
int target;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-01-03 06:32:12 +00:00
|
|
|
int i;
|
1996-10-06 16:38:45 +00:00
|
|
|
u_int32_t ultra_enb_addr;
|
|
|
|
u_int8_t sxfrctl0;
|
|
|
|
u_int8_t ultra_enb;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
i = ahc_num_syncrates; /* Default to async */
|
|
|
|
|
|
|
|
if (*period >= ahc_syncrates[0].period && *offset != 0) {
|
|
|
|
for (i = 0; i < ahc_num_syncrates; i++) {
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
if (*period <= ahc_syncrates[i].period) {
|
1996-05-21 18:37:25 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* Watch out for Ultra speeds when ultra is not
|
|
|
|
* enabled and vice-versa.
|
1996-05-21 18:37:25 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (!(ahc->type & AHC_ULTRA)
|
|
|
|
&& (ahc_syncrates[i].sxfr & ULTRA_SXFR)) {
|
1996-10-06 16:38:45 +00:00
|
|
|
/*
|
|
|
|
* This should only happen if the
|
|
|
|
* drive is the first to negotiate
|
|
|
|
* and chooses a high rate. We'll
|
|
|
|
* just move down the table util
|
|
|
|
* we hit a non ultra speed.
|
|
|
|
*/
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*scsirate = (ahc_syncrates[i].sxfr & 0xF0)
|
|
|
|
| (*offset & 0x0f);
|
|
|
|
*period = ahc_syncrates[i].period;
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose) {
|
|
|
|
printf("%s: target %d synchronous at "
|
|
|
|
"%sMHz, offset = 0x%x\n",
|
1996-10-06 16:38:45 +00:00
|
|
|
ahc_name(ahc), target,
|
|
|
|
ahc_syncrates[i].rate, *offset );
|
|
|
|
}
|
|
|
|
break;
|
1995-09-05 23:52:03 +00:00
|
|
|
}
|
1996-01-03 06:32:12 +00:00
|
|
|
}
|
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
if (i >= ahc_num_syncrates) {
|
|
|
|
/* Use asyncronous transfers. */
|
|
|
|
*scsirate = 0;
|
|
|
|
*period = 0;
|
|
|
|
*offset = 0;
|
1996-10-06 22:50:56 +00:00
|
|
|
if (bootverbose)
|
1996-10-06 16:38:45 +00:00
|
|
|
printf("%s: target %d using asyncronous transfers\n",
|
|
|
|
ahc_name(ahc), target );
|
1995-09-05 23:52:03 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
/*
|
|
|
|
* Ensure Ultra mode is set properly for
|
|
|
|
* this target.
|
|
|
|
*/
|
|
|
|
ultra_enb_addr = ULTRA_ENB;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (channel == 'B' || target > 7)
|
1996-10-06 16:38:45 +00:00
|
|
|
ultra_enb_addr++;
|
|
|
|
ultra_enb = AHC_INB(ahc, ultra_enb_addr);
|
|
|
|
sxfrctl0 = AHC_INB(ahc, SXFRCTL0);
|
|
|
|
if (*scsirate != 0 && ahc_syncrates[i].sxfr & ULTRA_SXFR) {
|
|
|
|
ultra_enb |= 0x01 << (target & 0x07);
|
|
|
|
sxfrctl0 |= ULTRAEN;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1996-10-06 16:38:45 +00:00
|
|
|
ultra_enb &= ~(0x01 << (target & 0x07));
|
|
|
|
sxfrctl0 &= ~ULTRAEN;
|
|
|
|
}
|
|
|
|
AHC_OUTB(ahc, ultra_enb_addr, ultra_enb);
|
|
|
|
AHC_OUTB(ahc, SXFRCTL0, sxfrctl0);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
int
|
|
|
|
ahcprint(aux, name)
|
|
|
|
void *aux;
|
|
|
|
char *name;
|
|
|
|
{
|
|
|
|
if (name != NULL)
|
|
|
|
printf("%s: scsibus ", name);
|
|
|
|
return UNCONF;
|
|
|
|
}
|
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
/*
|
|
|
|
* Attach all the sub-devices we can find
|
1995-05-30 08:16:23 +00:00
|
|
|
*/
|
1994-11-17 20:22:31 +00:00
|
|
|
int
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc_attach(ahc)
|
|
|
|
struct ahc_data *ahc;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1995-08-23 23:03:17 +00:00
|
|
|
struct scsibus_data *scbus;
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
#ifdef AHC_BROKEN_CACHE
|
|
|
|
if (cpu_class == CPUCLASS_386) /* doesn't have "wbinvd" instruction */
|
|
|
|
ahc_broken_cache = 0;
|
|
|
|
#endif
|
1995-08-23 23:03:17 +00:00
|
|
|
/*
|
1996-05-10 16:21:05 +00:00
|
|
|
* fill in the prototype scsi_links.
|
1995-08-23 23:03:17 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc->sc_link.adapter_unit = ahc->unit;
|
1995-08-23 23:03:17 +00:00
|
|
|
ahc->sc_link.adapter_targ = ahc->our_id;
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->sc_link.fordriver = 0;
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
ahc->sc_link.adapter_target = ahc->our_id;
|
|
|
|
#endif
|
1996-01-07 19:24:36 +00:00
|
|
|
ahc->sc_link.adapter_softc = ahc;
|
1995-08-23 23:03:17 +00:00
|
|
|
ahc->sc_link.adapter = &ahc_switch;
|
1995-03-17 23:58:27 +00:00
|
|
|
ahc->sc_link.opennings = 2;
|
1995-08-23 23:03:17 +00:00
|
|
|
ahc->sc_link.device = &ahc_dev;
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc->sc_link.flags = DEBUGLEVEL;
|
1994-11-18 20:34:30 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_TWIN) {
|
1996-05-10 16:21:05 +00:00
|
|
|
/* Configure the second scsi bus */
|
|
|
|
ahc->sc_link_b = ahc->sc_link;
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-05-10 16:21:05 +00:00
|
|
|
ahc->sc_link_b.adapter_targ = ahc->our_id_b;
|
|
|
|
ahc->sc_link_b.adapter_bus = 1;
|
|
|
|
ahc->sc_link_b.fordriver = (void *)SELBUSB;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
ahc->sc_link_b.adapter_target = ahc->our_id_b;
|
|
|
|
#endif
|
1996-05-10 16:21:05 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
|
|
|
|
#if defined(__FreeBSD__)
|
1995-08-23 23:03:17 +00:00
|
|
|
/*
|
|
|
|
* Prepare the scsibus_data area for the upperlevel
|
|
|
|
* scsi code.
|
|
|
|
*/
|
|
|
|
scbus = scsi_alloc_bus();
|
|
|
|
if(!scbus)
|
|
|
|
return 0;
|
1996-05-10 16:21:05 +00:00
|
|
|
scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ?
|
|
|
|
&ahc->sc_link_b : &ahc->sc_link;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_WIDE)
|
1995-08-23 23:03:17 +00:00
|
|
|
scbus->maxtarg = 15;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ask the adapter what subunits are present
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-05-10 16:21:05 +00:00
|
|
|
printf("ahc%d: Probing channel %c\n", ahc->unit,
|
|
|
|
(ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'B' : 'A');
|
1995-08-23 23:03:17 +00:00
|
|
|
scsi_attachdevs(scbus);
|
|
|
|
scbus = NULL; /* Upper-level SCSI code owns this now */
|
1996-05-10 16:21:05 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_TWIN) {
|
1995-08-23 23:03:17 +00:00
|
|
|
scbus = scsi_alloc_bus();
|
1996-10-25 06:42:53 +00:00
|
|
|
if (!scbus)
|
1995-08-23 23:03:17 +00:00
|
|
|
return 0;
|
1996-05-10 16:21:05 +00:00
|
|
|
scbus->adapter_link = (ahc->flags & AHC_CHANNEL_B_PRIMARY) ?
|
|
|
|
&ahc->sc_link : &ahc->sc_link_b;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_WIDE)
|
1995-08-23 23:03:17 +00:00
|
|
|
scbus->maxtarg = 15;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-05-10 16:21:05 +00:00
|
|
|
printf("ahc%d: Probing Channel %c\n", ahc->unit,
|
|
|
|
(ahc->flags & AHC_CHANNEL_B_PRIMARY) ? 'A': 'B');
|
1995-08-23 23:03:17 +00:00
|
|
|
scsi_attachdevs(scbus);
|
|
|
|
scbus = NULL; /* Upper-level SCSI code owns this now */
|
1995-05-30 08:16:23 +00:00
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
/*
|
|
|
|
* XXX - Update MI SCSI code
|
|
|
|
*
|
|
|
|
* if(ahc->type & AHC_WIDE)
|
|
|
|
* max target of both channel A and B = 15;
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ask the adapter what subunits are present
|
|
|
|
*/
|
|
|
|
if ((ahc->flags & AHC_CHANNEL_B_PRIMARY) == 0) {
|
|
|
|
/* make IS_SCSIBUS_B() == false, while probing channel A */
|
|
|
|
ahc->sc_link_b.scsibus = 0xff;
|
|
|
|
|
|
|
|
if (ahc->type & AHC_TWIN)
|
|
|
|
printf("%s: Probing channel A\n", ahc_name(ahc));
|
|
|
|
config_found((void *)ahc, &ahc->sc_link, ahcprint);
|
|
|
|
if (ahc->type & AHC_TWIN) {
|
|
|
|
printf("%s: Probing channel B\n", ahc_name(ahc));
|
|
|
|
config_found((void *)ahc, &ahc->sc_link_b, ahcprint);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* if implementation of IS_SCSIBUS_B() is changed to use
|
|
|
|
* ahc->sc_link.scsibus, then "ahc->sc_link.scsibus = 0xff;"
|
|
|
|
* is needed, here.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* assert(ahc->type & AHC_TWIN); */
|
|
|
|
printf("%s: Probing channel B\n", ahc_name(ahc));
|
|
|
|
config_found((void *)ahc, &ahc->sc_link_b, ahcprint);
|
|
|
|
printf("%s: Probing channel A\n", ahc_name(ahc));
|
|
|
|
config_found((void *)ahc, &ahc->sc_link, ahcprint);
|
|
|
|
}
|
|
|
|
#endif
|
1995-08-23 23:03:17 +00:00
|
|
|
return 1;
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
* Catch an interrupt from the adapter
|
1995-05-30 08:16:23 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-01-23 21:48:28 +00:00
|
|
|
void
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined (__NetBSD__)
|
|
|
|
int
|
|
|
|
#endif
|
1996-01-23 21:48:28 +00:00
|
|
|
ahc_intr(arg)
|
1995-11-05 04:50:55 +00:00
|
|
|
void *arg;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int8_t intstat;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc = (struct ahc_data *)arg;
|
1996-05-30 07:19:59 +00:00
|
|
|
intstat = AHC_INB(ahc, INTSTAT);
|
1995-03-31 13:54:41 +00:00
|
|
|
/*
|
|
|
|
* Is this interrupt for me? or for
|
|
|
|
* someone who is sharing my interrupt
|
|
|
|
*/
|
|
|
|
if (!(intstat & INT_PEND))
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-01-23 21:48:28 +00:00
|
|
|
return;
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
return 0;
|
|
|
|
#endif
|
1995-11-05 04:50:55 +00:00
|
|
|
|
1995-05-30 08:16:23 +00:00
|
|
|
if (intstat & BRKADRINT) {
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* We upset the sequencer :-(
|
|
|
|
* Lookup the error message
|
|
|
|
*/
|
|
|
|
int i, error, num_errors;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
error = AHC_INB(ahc, ERROR);
|
|
|
|
num_errors = sizeof(hard_error)/sizeof(hard_error[0]);
|
|
|
|
for (i = 0; error != 1 && i < num_errors; i++)
|
1994-11-17 20:22:31 +00:00
|
|
|
error >>= 1;
|
1996-05-30 07:19:59 +00:00
|
|
|
panic("%s: brkadrint, %s at seqaddr = 0x%x\n",
|
|
|
|
ahc_name(ahc), hard_error[i].errmesg,
|
|
|
|
(AHC_INB(ahc, SEQADDR1) << 8) |
|
|
|
|
AHC_INB(ahc, SEQADDR0));
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
if (intstat & SEQINT)
|
1996-10-06 16:38:45 +00:00
|
|
|
ahc_handle_seqint(ahc, intstat);
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
if (intstat & SCSIINT)
|
|
|
|
ahc_handle_scsiint(ahc, intstat);
|
1996-05-30 07:19:59 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (intstat & CMDCMPLT) {
|
|
|
|
struct scb *scb;
|
|
|
|
u_int8_t scb_index;
|
|
|
|
u_int8_t qoutcnt;
|
|
|
|
int int_cleared;
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
int_cleared = 0;
|
|
|
|
while (qoutcnt = (AHC_INB(ahc, QOUTCNT) & ahc->qcntmask)) {
|
|
|
|
|
|
|
|
for (; qoutcnt > 0; qoutcnt--) {
|
|
|
|
scb_index = AHC_INB(ahc, QOUTFIFO);
|
|
|
|
scb = ahc->scbarray[scb_index];
|
|
|
|
if (!scb || !(scb->flags & SCB_ACTIVE)) {
|
|
|
|
printf("%s: WARNING "
|
|
|
|
"no command for scb %d "
|
|
|
|
"(cmdcmplt)\nQOUTCNT == %d\n",
|
|
|
|
ahc_name(ahc), scb_index,
|
|
|
|
qoutcnt);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
untimeout(ahc_timeout, (caddr_t)scb);
|
1996-04-20 21:29:27 +00:00
|
|
|
/*
|
1996-10-25 06:42:53 +00:00
|
|
|
* Save off the residual if there is one.
|
1996-04-20 21:29:27 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scb->hscb->residual_SG_segment_count != 0)
|
|
|
|
ahc_calc_residual(scb);
|
|
|
|
ahc_done(ahc, scb);
|
1996-10-06 16:38:45 +00:00
|
|
|
}
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRCMDINT);
|
1996-10-25 06:42:53 +00:00
|
|
|
int_cleared++;
|
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (int_cleared == 0)
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRCMDINT);
|
1996-10-06 16:38:45 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
if (ahc->waiting_scbs.stqh_first != NULL)
|
|
|
|
ahc_run_waiting_queue(ahc);
|
1996-10-06 16:38:45 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
return 1;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ahc_handle_seqint(ahc, intstat)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int8_t intstat;
|
|
|
|
{
|
|
|
|
struct scb *scb;
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int16_t targ_mask;
|
|
|
|
u_int8_t target = (AHC_INB(ahc, SCSIID) >> 4) & 0x0f;
|
|
|
|
int scratch_offset = target;
|
1996-10-06 16:38:45 +00:00
|
|
|
char channel = AHC_INB(ahc, SBLKCTL) & SELBUSB ? 'B': 'A';
|
|
|
|
|
|
|
|
if (channel == 'B')
|
|
|
|
scratch_offset += 8;
|
|
|
|
targ_mask = (0x01 << scratch_offset);
|
|
|
|
|
|
|
|
switch (intstat & SEQINT_MASK) {
|
|
|
|
case NO_MATCH:
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("%s:%c:%d: no active SCB for reconnecting "
|
|
|
|
"target - issuing ABORT\n",
|
|
|
|
ahc_name(ahc), channel, target);
|
|
|
|
printf("SAVED_TCL == 0x%x\n",
|
|
|
|
AHC_INB(ahc, SAVED_TCL));
|
|
|
|
ahc_unbusy_target(ahc, target, channel);
|
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, 0);
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
|
|
|
|
AHC_OUTB(ahc, RETURN_1, 0);
|
1996-10-06 16:38:45 +00:00
|
|
|
break;
|
|
|
|
case SEND_REJECT:
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t rejbyte = AHC_INB(ahc, REJBYTE);
|
1996-10-06 16:38:45 +00:00
|
|
|
printf("%s:%c:%d: Warning - unknown message recieved from "
|
|
|
|
"target (0x%x). Rejecting\n",
|
|
|
|
ahc_name(ahc), channel, target, rejbyte);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case NO_IDENT:
|
|
|
|
panic("%s:%c:%d: Target did not send an IDENTIFY message. "
|
|
|
|
"SAVED_TCL == 0x%x\n",
|
|
|
|
ahc_name(ahc), channel, target,
|
|
|
|
AHC_INB(ahc, SAVED_TCL));
|
|
|
|
break;
|
|
|
|
case BAD_PHASE:
|
|
|
|
printf("%s:%c:%d: unknown scsi bus phase. Attempting to "
|
|
|
|
"continue\n", ahc_name(ahc), channel, target);
|
|
|
|
break;
|
|
|
|
case EXTENDED_MSG:
|
|
|
|
{
|
|
|
|
u_int8_t message_length;
|
|
|
|
u_int8_t message_code;
|
1995-01-13 02:24:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
message_length = AHC_INB(ahc, MSGIN_EXT_LEN);
|
|
|
|
message_code = AHC_INB(ahc, MSGIN_EXT_OPCODE);
|
1996-10-25 06:42:53 +00:00
|
|
|
switch (message_code) {
|
1996-10-06 16:38:45 +00:00
|
|
|
case MSG_EXT_SDTR:
|
|
|
|
{
|
|
|
|
u_int8_t period;
|
|
|
|
u_int8_t offset;
|
1996-10-06 19:43:36 +00:00
|
|
|
u_int8_t saved_offset;
|
1996-10-06 16:38:45 +00:00
|
|
|
u_int8_t targ_scratch;
|
|
|
|
u_int8_t maxoffset;
|
|
|
|
u_int8_t rate;
|
|
|
|
|
|
|
|
if (message_length != MSG_EXT_SDTR_LEN) {
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_REJ);
|
|
|
|
ahc->sdtrpending &= ~targ_mask;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
period = AHC_INB(ahc, MSGIN_EXT_BYTE0);
|
1996-10-06 19:43:36 +00:00
|
|
|
saved_offset = AHC_INB(ahc, MSGIN_EXT_BYTE1);
|
1996-10-06 16:38:45 +00:00
|
|
|
targ_scratch = AHC_INB(ahc, TARG_SCRATCH
|
|
|
|
+ scratch_offset);
|
|
|
|
if (targ_scratch & WIDEXFER)
|
|
|
|
maxoffset = MAX_OFFSET_16BIT;
|
|
|
|
else
|
|
|
|
maxoffset = MAX_OFFSET_8BIT;
|
1996-10-06 19:43:36 +00:00
|
|
|
offset = MIN(saved_offset, maxoffset);
|
1996-10-06 16:38:45 +00:00
|
|
|
ahc_scsirate(ahc, &rate, &period, &offset,
|
|
|
|
channel, target);
|
|
|
|
/* Preserve the WideXfer flag */
|
|
|
|
targ_scratch = rate | (targ_scratch & WIDEXFER);
|
1995-01-13 02:24:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
/*
|
|
|
|
* Update both the target scratch area and the
|
|
|
|
* current SCSIRATE.
|
|
|
|
*/
|
|
|
|
AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
|
|
|
|
targ_scratch);
|
|
|
|
AHC_OUTB(ahc, SCSIRATE, targ_scratch);
|
1995-01-13 02:24:31 +00:00
|
|
|
|
1996-10-06 19:43:36 +00:00
|
|
|
/*
|
|
|
|
* See if we initiated Sync Negotiation
|
|
|
|
* and didn't have to fall down to async
|
|
|
|
* transfers.
|
|
|
|
*/
|
|
|
|
if ((ahc->sdtrpending & targ_mask) != 0
|
|
|
|
&& (saved_offset == offset)) {
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* Don't send an SDTR back to
|
|
|
|
* the target
|
|
|
|
*/
|
|
|
|
AHC_OUTB(ahc, RETURN_1, 0);
|
1996-10-06 19:43:36 +00:00
|
|
|
ahc->needsdtr &= ~targ_mask;
|
|
|
|
ahc->sdtrpending &= ~targ_mask;
|
1996-10-06 16:38:45 +00:00
|
|
|
} else {
|
|
|
|
/*
|
|
|
|
* Send our own SDTR in reply
|
1995-01-16 16:33:47 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("Sending SDTR!!\n");
|
1996-10-06 16:38:45 +00:00
|
|
|
ahc_construct_sdtr(ahc, /*start_byte*/0,
|
|
|
|
period, offset);
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_MSG);
|
1996-10-06 19:43:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we aren't starting a re-negotiation
|
|
|
|
* because we had to go async in response
|
|
|
|
* to a "too low" response from the target
|
|
|
|
* clear the needsdtr flag for this target.
|
|
|
|
*/
|
|
|
|
if ((ahc->sdtrpending & targ_mask) == 0)
|
|
|
|
ahc->needsdtr &= ~targ_mask;
|
|
|
|
else
|
|
|
|
ahc->sdtrpending |= targ_mask;
|
1995-01-16 16:33:47 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case MSG_EXT_WDTR:
|
|
|
|
{
|
|
|
|
u_int8_t scratch, bus_width;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
if (message_length != MSG_EXT_WDTR_LEN) {
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_REJ);
|
|
|
|
ahc->wdtrpending &= ~targ_mask;
|
1994-12-31 19:31:56 +00:00
|
|
|
break;
|
1996-10-06 16:38:45 +00:00
|
|
|
}
|
1996-01-29 03:17:39 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
bus_width = AHC_INB(ahc, MSGIN_EXT_BYTE0);
|
|
|
|
scratch = AHC_INB(ahc, TARG_SCRATCH
|
|
|
|
+ scratch_offset);
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
if (ahc->wdtrpending & targ_mask) {
|
|
|
|
/*
|
|
|
|
* Don't send a WDTR back to the
|
|
|
|
* target, since we asked first.
|
|
|
|
*/
|
|
|
|
AHC_OUTB(ahc, RETURN_1, 0);
|
1996-10-25 06:42:53 +00:00
|
|
|
switch (bus_width){
|
1996-10-06 16:38:45 +00:00
|
|
|
case BUS_8_BIT:
|
|
|
|
scratch &= 0x7f;
|
|
|
|
break;
|
|
|
|
case BUS_16_BIT:
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-10-06 16:38:45 +00:00
|
|
|
printf("%s: target %d using "
|
|
|
|
"16Bit transfers\n",
|
|
|
|
ahc_name(ahc), target);
|
|
|
|
scratch |= WIDEXFER;
|
|
|
|
break;
|
|
|
|
case BUS_32_BIT:
|
1996-01-03 06:32:12 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* How can we do 32bit transfers
|
|
|
|
* on a 16bit bus?
|
1996-01-03 06:32:12 +00:00
|
|
|
*/
|
1996-10-06 16:38:45 +00:00
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_REJ);
|
|
|
|
printf("%s: target %d requested 32Bit "
|
|
|
|
"transfers. Rejecting...\n",
|
|
|
|
ahc_name(ahc), target);
|
|
|
|
break;
|
|
|
|
default:
|
1995-01-16 16:33:47 +00:00
|
|
|
break;
|
1994-12-31 19:31:56 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
} else {
|
1994-12-31 19:31:56 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* Send our own WDTR in reply
|
1994-12-31 19:31:56 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
switch (bus_width) {
|
1996-10-06 16:38:45 +00:00
|
|
|
case BUS_8_BIT:
|
|
|
|
scratch &= 0x7f;
|
|
|
|
break;
|
|
|
|
case BUS_32_BIT:
|
|
|
|
case BUS_16_BIT:
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_WIDE) {
|
1996-10-06 16:38:45 +00:00
|
|
|
/* Negotiate 16_BITS */
|
|
|
|
bus_width = BUS_16_BIT;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-10-06 16:38:45 +00:00
|
|
|
printf("%s: target %d "
|
|
|
|
"using 16Bit "
|
|
|
|
"transfers\n",
|
|
|
|
ahc_name(ahc),
|
|
|
|
target);
|
|
|
|
scratch |= WIDEXFER;
|
|
|
|
} else
|
|
|
|
bus_width = BUS_8_BIT;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ahc_construct_wdtr(ahc, /*start_byte*/0,
|
|
|
|
bus_width);
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_MSG);
|
1994-12-31 19:31:56 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
|
|
|
|
ahc->needwdtr &= ~targ_mask;
|
|
|
|
ahc->wdtrpending &= ~targ_mask;
|
|
|
|
AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset, scratch);
|
|
|
|
AHC_OUTB(ahc, SCSIRATE, scratch);
|
1994-12-31 19:31:56 +00:00
|
|
|
break;
|
1996-10-06 16:38:45 +00:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
/* Unknown extended message. Reject it. */
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_REJ);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
case REJECT_MSG:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* What we care about here is if we had an
|
|
|
|
* outstanding SDTR or WDTR message for this
|
|
|
|
* target. If we did, this is a signal that
|
|
|
|
* the target is refusing negotiation.
|
|
|
|
*/
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t targ_scratch;
|
1996-10-06 16:38:45 +00:00
|
|
|
|
|
|
|
targ_scratch = AHC_INB(ahc, TARG_SCRATCH
|
|
|
|
+ scratch_offset);
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->wdtrpending & targ_mask) {
|
1996-10-06 16:38:45 +00:00
|
|
|
/* note 8bit xfers and clear flag */
|
|
|
|
targ_scratch &= 0x7f;
|
|
|
|
ahc->needwdtr &= ~targ_mask;
|
|
|
|
ahc->wdtrpending &= ~targ_mask;
|
|
|
|
printf("%s:%c:%d: refuses WIDE negotiation. Using "
|
|
|
|
"8bit transfers\n", ahc_name(ahc),
|
|
|
|
channel, target);
|
1996-10-25 06:42:53 +00:00
|
|
|
} else if (ahc->sdtrpending & targ_mask) {
|
1996-10-06 16:38:45 +00:00
|
|
|
/* note asynch xfers and clear flag */
|
|
|
|
targ_scratch &= 0xf0;
|
|
|
|
ahc->needsdtr &= ~targ_mask;
|
|
|
|
ahc->sdtrpending &= ~targ_mask;
|
|
|
|
printf("%s:%c:%d: refuses syncronous negotiation. "
|
|
|
|
"Using asyncronous transfers\n",
|
|
|
|
ahc_name(ahc),
|
|
|
|
channel, target);
|
|
|
|
} else {
|
1995-03-31 13:54:41 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* Otherwise, we ignore it.
|
1995-03-31 13:54:41 +00:00
|
|
|
*/
|
1996-10-06 16:38:45 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc_debug & AHC_SHOWMISC)
|
1996-10-06 16:38:45 +00:00
|
|
|
printf("%s:%c:%d: Message reject -- ignored\n",
|
|
|
|
ahc_name(ahc), channel, target);
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset, targ_scratch);
|
|
|
|
AHC_OUTB(ahc, SCSIRATE, targ_scratch);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BAD_STATUS:
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t scb_index;
|
|
|
|
struct scsi_xfer *xs;
|
|
|
|
struct hardware_scb *hscb;
|
1996-10-06 16:38:45 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* The sequencer will notify us when a command
|
1996-10-06 16:38:45 +00:00
|
|
|
* has an error that would be of interest to
|
|
|
|
* the kernel. This allows us to leave the sequencer
|
|
|
|
* running in the common case of command completes
|
1996-10-25 06:42:53 +00:00
|
|
|
* without error. The sequencer will already have
|
|
|
|
* dma'd the SCB back up to us, so we can reference
|
|
|
|
* the in kernel copy directly.
|
1996-10-06 16:38:45 +00:00
|
|
|
*/
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
scb_index = AHC_INB(ahc, SCB_TAG);
|
|
|
|
scb = ahc->scbarray[scb_index];
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb = scb->hscb;
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
/*
|
|
|
|
* Set the default return value to 0 (don't
|
|
|
|
* send sense). The sense code will change
|
|
|
|
* this if needed and this reduces code
|
|
|
|
* duplication.
|
|
|
|
*/
|
|
|
|
AHC_OUTB(ahc, RETURN_1, 0);
|
|
|
|
if (!(scb && (scb->flags & SCB_ACTIVE))) {
|
|
|
|
printf("%s:%c:%d: ahc_intr - referenced scb "
|
|
|
|
"not valid during seqint 0x%x scb(%d)\n",
|
|
|
|
ahc_name(ahc),
|
|
|
|
channel, target, intstat,
|
|
|
|
scb_index);
|
|
|
|
goto clear;
|
|
|
|
}
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
xs = scb->xs;
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
xs->status = hscb->status;
|
|
|
|
switch (hscb->status){
|
1996-10-06 16:38:45 +00:00
|
|
|
case SCSI_OK:
|
|
|
|
printf("%s: Interrupted for staus of"
|
|
|
|
" 0???\n", ahc_name(ahc));
|
|
|
|
break;
|
|
|
|
case SCSI_CHECK:
|
|
|
|
#ifdef AHC_DEBUG
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc_debug & AHC_SHOWSENSE) {
|
1996-10-06 16:38:45 +00:00
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
printf("requests Check Status\n");
|
Fixes to the aic7xxx sequencer code and device driver from Justin Gibbs:
1) If a target initiated a sync negotiation with us and happened to chose a
value above 15, the old code inadvertantly truncated it with an "& 0x0f".
If the periferal picked something really bad like 0x32, you'd end up with
an offset of 2 which would hang the drive since it didn't expect to ever
get something so low. We now do a MIN(maxoffset, given_offset).
2) In the case of Wide cards, we were turning on sync transfers after a
sucessfull wide negotiation. Now we leave the offset alone in the per
target scratch space (which implies asyncronous transfers since we initialize
it that way) until a syncronous negotation occurs.
3) We were advertizing a max offset of 15 instead of 8 for wide devices.
4) If the upper level SCSI code sent down a "SCSI_RESET", it would hang the
system because we would end up sending a null command to the sequencer. Now
we handle SCSI_RESET correctly by having the sequencer interrupt us when it
is about to fill the message buffer so that we can fill it in ourselves.
The sequencer will also "simulate" a command complete for these "message only"
SCBs so that the kernel driver can finish up properly. The cdplay utility
will send a "SCSI_REST" to the cdplayer if you use the reset command.
5) The code that handles SCSIINTs was broken in that if more than one type
of error was true at once, we'd do outbs without the card being paused.
The else clause after the busfree case was also an accident waiting to
happen. I've now turned this into an if, else if, else type of thing, since
in most cases when we handle one type of error, it should be okay to ignore
the rest (ie if we have a SELTO, who cares if there was a parity error on
the transaction?), but the section should really be rewritten after 2.0.5.
This fix was the least obtrusive way to patch the problem.
6) Only tag either SDTR or WDTR negotiation on an SCB. The real problem is
that I don't account for the case when an SCB that is tagged to do a particular
type of negotiation completes or SELTOs (selection timeout) without the
negotiation taking place, so the accounting of sdtrpending and wdtrpending
gets screwed up. In the wide case, if we tag it to do both wdtr and sdtr,
it only performs wdtr (since wdtr must occur first and we spread out the
negotiation over two commands) so we always have sdtrpending set for that
target and we never do a real SDTR. I fill properly fix the accounting
after 2.0.5 goes out the door, but this works (as confirmed by Dan) on
wide targets.
Other stuff that is also included:
1) Don't do a bzero when recycling SCBs. The only thing that must explicitly
be set to zero is the scb control byte which is done in ahc_get_scb. We also
need to set the SG_list_pointer and SG_list_count to 0 for commands that do
not transfer data.
2) Mask the interrupt type printout for the aic7870 case. The bit we were
using to determine interrupt type is only valid for the aic7770.
Submitted by: Justin Gibbs
1995-05-17 07:06:02 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if ((xs->error == XS_NOERROR)
|
1996-10-25 06:42:53 +00:00
|
|
|
&& !(scb->flags & SCB_SENSE)) {
|
1996-10-06 16:38:45 +00:00
|
|
|
struct ahc_dma_seg *sg = scb->ahc_dma;
|
|
|
|
struct scsi_sense *sc = &(scb->sense_cmd);
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Save off the residual if there is one.
|
|
|
|
*/
|
|
|
|
if (hscb->residual_SG_segment_count != 0)
|
|
|
|
ahc_calc_residual(scb);
|
1996-10-06 16:38:45 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc_debug & AHC_SHOWSENSE) {
|
1996-10-06 16:38:45 +00:00
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
printf("Sending Sense\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
sc->op_code = REQUEST_SENSE;
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
sc->opcode = REQUEST_SENSE;
|
|
|
|
#endif
|
|
|
|
sc->byte2 = xs->sc_link->lun << 5;
|
|
|
|
sc->length = sizeof(struct scsi_sense_data);
|
|
|
|
sc->control = 0;
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
sg->addr = vtophys(&xs->sense);
|
1996-10-06 16:38:45 +00:00
|
|
|
sg->len = sizeof(struct scsi_sense_data);
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->control &= DISCENB;
|
|
|
|
hscb->status = 0;
|
|
|
|
hscb->SG_segment_count = 1;
|
|
|
|
hscb->SG_list_pointer = vtophys(sg);
|
|
|
|
hscb->data = sg->addr;
|
|
|
|
hscb->datalen &= 0xFF000000;
|
|
|
|
hscb->datalen |= sg->len;
|
|
|
|
hscb->cmdpointer = vtophys(sc);
|
|
|
|
hscb->cmdlen = sizeof(*sc);
|
1996-10-06 16:38:45 +00:00
|
|
|
|
|
|
|
scb->flags |= SCB_SENSE;
|
|
|
|
AHC_OUTB(ahc, RETURN_1, SEND_SENSE);
|
|
|
|
break;
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
1996-06-09 17:33:18 +00:00
|
|
|
/*
|
1996-10-06 16:38:45 +00:00
|
|
|
* Clear the SCB_SENSE Flag and have
|
|
|
|
* the sequencer do a normal command
|
|
|
|
* complete with either a "DRIVER_STUFFUP"
|
|
|
|
* error or whatever other error condition
|
|
|
|
* we already had.
|
1996-06-09 17:33:18 +00:00
|
|
|
*/
|
1996-10-06 16:38:45 +00:00
|
|
|
scb->flags &= ~SCB_SENSE;
|
|
|
|
if (xs->error == XS_NOERROR)
|
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
1996-06-09 17:33:18 +00:00
|
|
|
break;
|
1996-10-06 16:38:45 +00:00
|
|
|
case SCSI_BUSY:
|
|
|
|
xs->error = XS_BUSY;
|
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
printf("Target Busy\n");
|
1996-01-03 06:32:12 +00:00
|
|
|
break;
|
1996-10-06 16:38:45 +00:00
|
|
|
case SCSI_QUEUE_FULL:
|
|
|
|
/*
|
|
|
|
* The upper level SCSI code will someday
|
|
|
|
* handle this properly.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
xs->error = XS_BUSY;
|
1996-01-03 06:32:12 +00:00
|
|
|
break;
|
1996-10-06 16:38:45 +00:00
|
|
|
default:
|
|
|
|
sc_print_addr(xs->sc_link);
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("unexpected targ_status: %x\n", hscb->status);
|
1996-10-06 16:38:45 +00:00
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
1996-03-31 03:15:31 +00:00
|
|
|
break;
|
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case ABORT_TAG:
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t scb_index;
|
1996-10-06 16:38:45 +00:00
|
|
|
struct scsi_xfer *xs;
|
1996-03-31 03:15:31 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
scb_index = AHC_INB(ahc, SCB_TAG);
|
|
|
|
scb = ahc->scbarray[scb_index];
|
|
|
|
xs = scb->xs;
|
|
|
|
/*
|
|
|
|
* We didn't recieve a valid tag back from
|
|
|
|
* the target on a reconnect.
|
|
|
|
*/
|
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
printf("invalid tag recieved -- sending ABORT_TAG\n");
|
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
|
|
untimeout(ahc_timeout, (caddr_t)scb);
|
|
|
|
ahc_done(ahc, scb);
|
|
|
|
break;
|
1996-03-31 03:15:31 +00:00
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
case AWAITING_MSG:
|
|
|
|
{
|
|
|
|
int scb_index;
|
1996-10-25 06:42:53 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
scb_index = AHC_INB(ahc, SCB_TAG);
|
|
|
|
scb = ahc->scbarray[scb_index];
|
|
|
|
/*
|
1996-10-25 06:42:53 +00:00
|
|
|
* This SCB had MK_MESSAGE set in its control byte,
|
|
|
|
* informing the sequencer that we wanted to send a
|
|
|
|
* special message to this target.
|
1996-10-06 16:38:45 +00:00
|
|
|
*/
|
|
|
|
if (scb->flags & SCB_DEVICE_RESET) {
|
|
|
|
AHC_OUTB(ahc, MSG0,
|
|
|
|
MSG_BUS_DEV_RESET);
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, 1);
|
|
|
|
printf("Bus Device Reset Message Sent\n");
|
|
|
|
} else if (scb->flags & SCB_MSGOUT_WDTR) {
|
|
|
|
ahc_construct_wdtr(ahc, AHC_INB(ahc, MSG_LEN),
|
|
|
|
BUS_16_BIT);
|
|
|
|
} else if (scb->flags & SCB_MSGOUT_SDTR) {
|
|
|
|
u_int8_t target_scratch;
|
|
|
|
u_int8_t ultraenable;
|
|
|
|
int sxfr;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Pull the user defined setting */
|
|
|
|
target_scratch = AHC_INB(ahc, TARG_SCRATCH
|
|
|
|
+ scratch_offset);
|
|
|
|
|
|
|
|
sxfr = target_scratch & SXFR;
|
|
|
|
if (scratch_offset < 8)
|
|
|
|
ultraenable = AHC_INB(ahc, ULTRA_ENB);
|
|
|
|
else
|
|
|
|
ultraenable = AHC_INB(ahc, ULTRA_ENB + 1);
|
|
|
|
|
|
|
|
if (ultraenable & targ_mask)
|
|
|
|
/* Want an ultra speed in the table */
|
|
|
|
sxfr |= 0x100;
|
|
|
|
|
|
|
|
for (i = 0; i < ahc_num_syncrates; i++)
|
1996-10-06 22:50:56 +00:00
|
|
|
if (sxfr == ahc_syncrates[i].sxfr)
|
1996-10-06 16:38:45 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
ahc_construct_sdtr(ahc, AHC_INB(ahc, MSG_LEN),
|
|
|
|
ahc_syncrates[i].period,
|
1996-10-25 06:42:53 +00:00
|
|
|
(target_scratch & WIDEXFER) ?
|
1996-10-06 16:38:45 +00:00
|
|
|
MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
|
|
|
|
} else
|
|
|
|
panic("ahc_intr: AWAITING_MSG for an SCB that "
|
|
|
|
"does not have a waiting message");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case IMMEDDONE:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Take care of device reset messages
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t scbindex = AHC_INB(ahc, SCB_TAG);
|
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
scb = ahc->scbarray[scbindex];
|
|
|
|
if (scb->flags & SCB_DEVICE_RESET) {
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t targ_scratch;
|
1996-10-06 16:38:45 +00:00
|
|
|
int found;
|
|
|
|
/*
|
|
|
|
* Go back to async/narrow transfers and
|
|
|
|
* renegotiate.
|
|
|
|
*/
|
|
|
|
ahc_unbusy_target(ahc, target, channel);
|
|
|
|
ahc->needsdtr |= ahc->needsdtr_orig & targ_mask;
|
|
|
|
ahc->needwdtr |= ahc->needwdtr_orig & targ_mask;
|
|
|
|
ahc->sdtrpending &= ~targ_mask;
|
|
|
|
ahc->wdtrpending &= ~targ_mask;
|
|
|
|
targ_scratch = AHC_INB(ahc, TARG_SCRATCH
|
|
|
|
+ scratch_offset);
|
|
|
|
targ_scratch &= SXFR;
|
|
|
|
AHC_OUTB(ahc, TARG_SCRATCH + scratch_offset,
|
|
|
|
targ_scratch);
|
|
|
|
found = ahc_reset_device(ahc, target,
|
1996-10-25 06:42:53 +00:00
|
|
|
channel, NULL,
|
1996-10-06 16:38:45 +00:00
|
|
|
XS_NOERROR);
|
|
|
|
sc_print_addr(scb->xs->sc_link);
|
|
|
|
printf("Bus Device Reset delivered. "
|
|
|
|
"%d SCBs aborted\n", found);
|
|
|
|
ahc->in_timeout = FALSE;
|
|
|
|
ahc_run_done_queue(ahc);
|
|
|
|
} else
|
|
|
|
panic("ahc_intr: Immediate complete for "
|
|
|
|
"unknown operation.");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case DATA_OVERRUN:
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* When the sequencer detects an overrun, it
|
|
|
|
* sets STCNT to 0x00ffffff and allows the
|
|
|
|
* target to complete its transfer in
|
|
|
|
* BITBUCKET mode.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t scbindex = AHC_INB(ahc, SCB_TAG);
|
1996-10-06 16:38:45 +00:00
|
|
|
u_int32_t overrun;
|
|
|
|
scb = ahc->scbarray[scbindex];
|
|
|
|
overrun = AHC_INB(ahc, STCNT0)
|
|
|
|
| (AHC_INB(ahc, STCNT1) << 8)
|
|
|
|
| (AHC_INB(ahc, STCNT2) << 16);
|
|
|
|
overrun = 0x00ffffff - overrun;
|
|
|
|
sc_print_addr(scb->xs->sc_link);
|
|
|
|
printf("data overrun of %d bytes detected."
|
|
|
|
" Forcing a retry.\n", overrun);
|
|
|
|
/*
|
|
|
|
* Set this and it will take affect when the
|
|
|
|
* target does a command complete.
|
|
|
|
*/
|
|
|
|
scb->xs->error = XS_DRIVER_STUFFUP;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if NOT_YET
|
|
|
|
/* XXX Fill these in later */
|
|
|
|
case MESG_BUFFER_BUSY:
|
|
|
|
break;
|
|
|
|
case MSGIN_PHASEMIS:
|
|
|
|
break;
|
1996-05-30 07:19:59 +00:00
|
|
|
#endif
|
1996-10-06 16:38:45 +00:00
|
|
|
default:
|
|
|
|
printf("ahc_intr: seqint, "
|
|
|
|
"intstat == 0x%x, scsisigi = 0x%x\n",
|
|
|
|
intstat, AHC_INB(ahc, SCSISIGI));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
clear:
|
|
|
|
/*
|
|
|
|
* Clear the upper byte that holds SEQINT status
|
|
|
|
* codes and clear the SEQINT bit.
|
|
|
|
*/
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSEQINT);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The sequencer is paused immediately on
|
|
|
|
* a SEQINT, so we should restart it when
|
|
|
|
* we're done.
|
|
|
|
*/
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
1995-11-04 14:43:30 +00:00
|
|
|
}
|
1995-07-04 21:14:45 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
static void
|
|
|
|
ahc_handle_scsiint(ahc, intstat)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int8_t intstat;
|
|
|
|
{
|
|
|
|
u_int8_t scb_index;
|
|
|
|
u_int8_t status;
|
|
|
|
struct scb *scb;
|
|
|
|
|
|
|
|
scb_index = AHC_INB(ahc, SCB_TAG);
|
|
|
|
status = AHC_INB(ahc, SSTAT1);
|
|
|
|
scb = ahc->scbarray[scb_index];
|
|
|
|
|
|
|
|
if (status & SCSIRSTI) {
|
|
|
|
char channel;
|
|
|
|
channel = (AHC_INB(ahc, SBLKCTL) & SELBUSB) ? 'B' : 'A';
|
|
|
|
printf("%s: Someone reset channel %c\n",
|
|
|
|
ahc_name(ahc), channel);
|
|
|
|
ahc_reset_channel(ahc,
|
|
|
|
channel,
|
|
|
|
NULL,
|
|
|
|
XS_BUSY,
|
|
|
|
/* Initiate Reset */FALSE);
|
|
|
|
scb = NULL;
|
|
|
|
} else if (!(scb && (scb->flags & SCB_ACTIVE))){
|
|
|
|
printf("%s: ahc_intr - referenced scb not "
|
|
|
|
"valid during scsiint 0x%x scb(%d)\n",
|
|
|
|
ahc_name(ahc), status, scb_index);
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, status);
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
|
|
|
scb = NULL;
|
|
|
|
} else if (status & SCSIPERR) {
|
|
|
|
/*
|
|
|
|
* Determine the bus phase and
|
|
|
|
* queue an appropriate message
|
|
|
|
*/
|
|
|
|
char *phase;
|
|
|
|
u_int8_t mesg_out = MSG_NOOP;
|
|
|
|
u_int8_t lastphase = AHC_INB(ahc, LASTPHASE);
|
|
|
|
struct scsi_xfer *xs;
|
|
|
|
|
|
|
|
xs = scb->xs;
|
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
|
|
|
|
switch (lastphase) {
|
|
|
|
case P_DATAOUT:
|
|
|
|
phase = "Data-Out";
|
|
|
|
break;
|
|
|
|
case P_DATAIN:
|
|
|
|
phase = "Data-In";
|
|
|
|
mesg_out = MSG_INITIATOR_DET_ERR;
|
|
|
|
break;
|
|
|
|
case P_COMMAND:
|
|
|
|
phase = "Command";
|
|
|
|
break;
|
|
|
|
case P_MESGOUT:
|
|
|
|
phase = "Message-Out";
|
|
|
|
break;
|
|
|
|
case P_STATUS:
|
|
|
|
phase = "Status";
|
|
|
|
mesg_out = MSG_INITIATOR_DET_ERR;
|
|
|
|
break;
|
|
|
|
case P_MESGIN:
|
|
|
|
phase = "Message-In";
|
|
|
|
mesg_out = MSG_PARITY_ERROR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
phase = "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
printf("parity error during %s phase.\n", phase);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We've set the hardware to assert ATN if we
|
|
|
|
* get a parity error on "in" phases, so all we
|
|
|
|
* need to do is stuff the message buffer with
|
|
|
|
* the appropriate message. "In" phases have set
|
|
|
|
* mesg_out to something other than MSG_NOP.
|
|
|
|
*/
|
|
|
|
if (mesg_out != MSG_NOOP) {
|
|
|
|
AHC_OUTB(ahc, MSG0, mesg_out);
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, 1);
|
|
|
|
} else
|
|
|
|
/*
|
|
|
|
* Should we allow the target to make
|
|
|
|
* this decision for us?
|
|
|
|
*/
|
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
|
|
} else if (status & SELTO) {
|
|
|
|
struct scsi_xfer *xs;
|
|
|
|
u_int8_t scbptr;
|
|
|
|
u_int8_t nextscb;
|
|
|
|
u_int8_t flags;
|
|
|
|
|
|
|
|
xs = scb->xs;
|
|
|
|
xs->error = XS_SELTIMEOUT;
|
|
|
|
/*
|
|
|
|
* Clear any pending messages for the timed out
|
|
|
|
* target, and mark the target as free
|
|
|
|
*/
|
|
|
|
flags = AHC_INB(ahc, FLAGS);
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, 0);
|
|
|
|
ahc_unbusy_target(ahc, xs->sc_link->target,
|
|
|
|
IS_SCSIBUS_B(ahc, xs->sc_link) ? 'B' : 'A');
|
|
|
|
/* Stop the selection */
|
|
|
|
AHC_OUTB(ahc, SCSISEQ, 0);
|
|
|
|
|
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, 0);
|
|
|
|
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSELTIMEO);
|
|
|
|
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
|
|
|
|
|
|
|
/* Shift the waiting Q forward. */
|
|
|
|
scbptr = AHC_INB(ahc, WAITING_SCBH);
|
|
|
|
AHC_OUTB(ahc, SCBPTR, scbptr);
|
|
|
|
nextscb = AHC_INB(ahc, SCB_NEXT);
|
|
|
|
AHC_OUTB(ahc, WAITING_SCBH, nextscb);
|
|
|
|
|
|
|
|
/* Put this SCB back on the free list */
|
|
|
|
nextscb = AHC_INB(ahc, FREE_SCBH);
|
|
|
|
AHC_OUTB(ahc, SCB_NEXT, nextscb);
|
|
|
|
AHC_OUTB(ahc, FREE_SCBH, scbptr);
|
|
|
|
restart_sequencer(ahc);
|
|
|
|
} else if (!(status & BUSFREE)) {
|
|
|
|
sc_print_addr(scb->xs->sc_link);
|
|
|
|
printf("Unknown SCSIINT. Status = 0x%x\n", status);
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, status);
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
|
|
|
scb = NULL;
|
|
|
|
}
|
|
|
|
if (scb != NULL) {
|
|
|
|
/* We want to process the command */
|
|
|
|
untimeout(ahc_timeout, (caddr_t)scb);
|
|
|
|
ahc_done(ahc, scb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
/*
|
|
|
|
* We have a scb which has been processed by the
|
|
|
|
* adaptor, now we look to see how the operation
|
|
|
|
* went.
|
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc_done(ahc, scb)
|
|
|
|
struct ahc_data *ahc;
|
1996-03-31 03:15:31 +00:00
|
|
|
struct scb *scb;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-03-31 03:15:31 +00:00
|
|
|
struct scsi_xfer *xs = scb->xs;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-03-31 03:15:31 +00:00
|
|
|
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_done\n"));
|
|
|
|
/*
|
|
|
|
* Put the results of the operation
|
|
|
|
* into the xfer and call whoever started it
|
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
if (xs->error != XS_NOERROR) {
|
|
|
|
/* Don't override the error value. */
|
|
|
|
} else if (scb->flags & SCB_ABORTED) {
|
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
|
|
} else
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scb->flags & SCB_SENSE)
|
1994-12-31 19:31:56 +00:00
|
|
|
xs->error = XS_SENSE;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scb->flags & SCB_SENTORDEREDTAG)
|
1996-04-28 19:21:20 +00:00
|
|
|
ahc->in_timeout = FALSE;
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__FreeBSD__)
|
1996-03-31 03:15:31 +00:00
|
|
|
if ((xs->flags & SCSI_ERR_OK) && !(xs->error == XS_SENSE)) {
|
1994-11-17 20:22:31 +00:00
|
|
|
/* All went correctly OR errors expected */
|
1996-03-31 03:15:31 +00:00
|
|
|
xs->error = XS_NOERROR;
|
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
/*
|
|
|
|
* Since NetBSD doesn't have error ignoring operation mode
|
|
|
|
* (SCSI_ERR_OK in FreeBSD), we don't have to care this case.
|
|
|
|
*/
|
|
|
|
#endif
|
1996-03-31 03:15:31 +00:00
|
|
|
xs->flags |= ITSDONE;
|
1996-04-28 19:21:20 +00:00
|
|
|
#ifdef AHC_TAGENABLE
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* This functionality is provided by the generic SCSI layer
|
|
|
|
* in FreeBSD 2.2.
|
|
|
|
*/
|
|
|
|
if (xs->cmd->opcode == INQUIRY && xs->error == XS_NOERROR) {
|
1995-02-22 01:43:25 +00:00
|
|
|
struct scsi_inquiry_data *inq_data;
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int16_t mask = 0x01 << (xs->sc_link->target |
|
|
|
|
(scb->hscb->tcl & 0x08));
|
1995-02-22 01:43:25 +00:00
|
|
|
/*
|
|
|
|
* Sneak a look at the results of the SCSI Inquiry
|
|
|
|
* command and see if we can do Tagged queing. This
|
|
|
|
* should really be done by the higher level drivers.
|
|
|
|
*/
|
|
|
|
inq_data = (struct scsi_inquiry_data *)xs->data;
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((inq_data->flags & SID_CmdQue)
|
|
|
|
&& !(ahc->tagenable & mask)) {
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: target %d Tagged Queuing Device\n",
|
|
|
|
ahc_name(ahc), xs->sc_link->target);
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->tagenable |= mask;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->maxhscbs >= 16 || (ahc->flags&AHC_PAGESCBS)) {
|
1996-04-20 21:29:27 +00:00
|
|
|
/* Default to 8 tags */
|
1996-04-22 13:21:40 +00:00
|
|
|
xs->sc_link->opennings += 6;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1996-04-20 21:29:27 +00:00
|
|
|
/*
|
|
|
|
* Default to 4 tags on whimpy
|
|
|
|
* cards that don't have much SCB
|
|
|
|
* space and can't page. This prevents
|
|
|
|
* a single device from hogging all
|
|
|
|
* slots. We should really have a better
|
|
|
|
* way of providing fairness.
|
|
|
|
*/
|
|
|
|
xs->sc_link->opennings += 2;
|
|
|
|
}
|
1995-02-22 01:43:25 +00:00
|
|
|
}
|
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
#endif /* AHC_TAGENABLE */
|
|
|
|
ahc_free_scb(ahc, scb);
|
1996-03-31 03:15:31 +00:00
|
|
|
scsi_done(xs);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the board, ready for normal operation
|
|
|
|
*/
|
1995-11-05 04:50:55 +00:00
|
|
|
int
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc_init(ahc)
|
|
|
|
struct ahc_data *ahc;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-10-06 16:38:45 +00:00
|
|
|
u_int8_t scsi_conf, sblkctl, i;
|
|
|
|
u_int16_t ultraenable = 0;
|
1996-10-25 06:42:53 +00:00
|
|
|
int max_targ = 15;
|
1994-11-17 20:22:31 +00:00
|
|
|
/*
|
1995-11-05 04:50:55 +00:00
|
|
|
* Assume we have a board at this stage and it has been reset.
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
|
|
|
|
1996-04-20 21:29:27 +00:00
|
|
|
/* Handle the SCBPAGING option */
|
|
|
|
#ifndef AHC_SCBPAGING_ENABLE
|
|
|
|
ahc->flags &= ~AHC_PAGESCBS;
|
|
|
|
#endif
|
|
|
|
|
1996-03-31 03:15:31 +00:00
|
|
|
/* Determine channel configuration and who we are on the scsi bus. */
|
1996-10-25 06:42:53 +00:00
|
|
|
switch ((sblkctl = AHC_INB(ahc, SBLKCTL) & 0x0a)) {
|
|
|
|
case 0:
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->our_id = (AHC_INB(ahc, SCSICONF) & HSCSIID);
|
1996-05-10 16:21:05 +00:00
|
|
|
ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type == AHC_394)
|
1995-09-05 23:52:03 +00:00
|
|
|
printf("Channel %c, SCSI Id=%d, ",
|
|
|
|
ahc->flags & AHC_CHNLB ? 'B' : 'A',
|
|
|
|
ahc->our_id);
|
|
|
|
else
|
|
|
|
printf("Single Channel, SCSI Id=%d, ", ahc->our_id);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, FLAGS, SINGLE_BUS | (ahc->flags & AHC_PAGESCBS));
|
1996-03-31 03:15:31 +00:00
|
|
|
break;
|
1996-10-25 06:42:53 +00:00
|
|
|
case 2:
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->our_id = (AHC_INB(ahc, SCSICONF + 1) & HWSCSIID);
|
1996-05-10 16:21:05 +00:00
|
|
|
ahc->flags &= ~AHC_CHANNEL_B_PRIMARY;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type == AHC_394)
|
1995-09-05 23:52:03 +00:00
|
|
|
printf("Wide Channel %c, SCSI Id=%d, ",
|
|
|
|
ahc->flags & AHC_CHNLB ? 'B' : 'A',
|
|
|
|
ahc->our_id);
|
|
|
|
else
|
|
|
|
printf("Wide Channel, SCSI Id=%d, ", ahc->our_id);
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->type |= AHC_WIDE;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, FLAGS, WIDE_BUS | (ahc->flags & AHC_PAGESCBS));
|
1996-03-31 03:15:31 +00:00
|
|
|
break;
|
1996-10-25 06:42:53 +00:00
|
|
|
case 8:
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->our_id = (AHC_INB(ahc, SCSICONF) & HSCSIID);
|
|
|
|
ahc->our_id_b = (AHC_INB(ahc, SCSICONF + 1) & HSCSIID);
|
1996-03-31 03:15:31 +00:00
|
|
|
printf("Twin Channel, A SCSI Id=%d, B SCSI Id=%d, ",
|
1995-01-13 02:24:31 +00:00
|
|
|
ahc->our_id, ahc->our_id_b);
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->type |= AHC_TWIN;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, FLAGS, TWIN_BUS | (ahc->flags & AHC_PAGESCBS));
|
1996-03-31 03:15:31 +00:00
|
|
|
break;
|
1996-10-25 06:42:53 +00:00
|
|
|
default:
|
1996-03-31 03:15:31 +00:00
|
|
|
printf(" Unsupported adapter type. Ignoring\n");
|
|
|
|
return(-1);
|
|
|
|
}
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/* Determine the number of SCBs and initialize them */
|
1996-03-31 03:15:31 +00:00
|
|
|
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
/* SCB 0 heads the free list */
|
|
|
|
AHC_OUTB(ahc, FREE_SCBH, 0);
|
|
|
|
for (i = 0; i < AHC_SCB_MAX; i++) {
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, i);
|
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, i);
|
|
|
|
if(AHC_INB(ahc, SCB_CONTROL) != i)
|
1996-04-20 21:29:27 +00:00
|
|
|
break;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, 0);
|
|
|
|
if(AHC_INB(ahc, SCB_CONTROL) != 0)
|
1996-04-20 21:29:27 +00:00
|
|
|
break;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, i);
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
/* Clear the control byte. */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, 0);
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/* Set the next pointer */
|
|
|
|
AHC_OUTB(ahc, SCB_NEXT, i+1);
|
|
|
|
|
|
|
|
/* No Busy non-tagged targets yet */
|
|
|
|
AHC_OUTB(ahc, SCB_ACTIVE0, SCB_LIST_NULL);
|
|
|
|
AHC_OUTB(ahc, SCB_ACTIVE1, SCB_LIST_NULL);
|
|
|
|
AHC_OUTB(ahc, SCB_ACTIVE2, SCB_LIST_NULL);
|
|
|
|
AHC_OUTB(ahc, SCB_ACTIVE3, SCB_LIST_NULL);
|
1996-03-31 03:15:31 +00:00
|
|
|
}
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/* Make that the last SCB terminates the free list */
|
|
|
|
AHC_OUTB(ahc, SCBPTR, i-1);
|
|
|
|
AHC_OUTB(ahc, SCB_NEXT, SCB_LIST_NULL);
|
|
|
|
|
1996-04-20 21:29:27 +00:00
|
|
|
/* Ensure we clear the 0 SCB's control byte. */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, 0);
|
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, 0);
|
1996-04-20 21:29:27 +00:00
|
|
|
|
|
|
|
ahc->maxhscbs = i;
|
1996-03-31 03:15:31 +00:00
|
|
|
}
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((ahc->maxhscbs < AHC_SCB_MAX) && (ahc->flags & AHC_PAGESCBS)) {
|
1996-04-20 21:29:27 +00:00
|
|
|
ahc->maxscbs = AHC_SCB_MAX;
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("%d/%d SCBs\n", ahc->maxhscbs, ahc->maxscbs);
|
|
|
|
} else {
|
1996-04-20 21:29:27 +00:00
|
|
|
ahc->maxscbs = ahc->maxhscbs;
|
|
|
|
ahc->flags &= ~AHC_PAGESCBS;
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("%d SCBs\n", ahc->maxhscbs);
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
|
|
|
|
1995-04-27 17:47:17 +00:00
|
|
|
|
1996-01-03 06:32:12 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc_debug & AHC_SHOWMISC) {
|
|
|
|
printf("%s: hardware scb %d bytes; kernel scb %d bytes; "
|
1996-01-03 06:32:12 +00:00
|
|
|
"ahc_dma %d bytes\n",
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_name(ahc),
|
1996-10-25 06:42:53 +00:00
|
|
|
sizeof(struct hardware_scb),
|
|
|
|
sizeof(struct scb),
|
1996-01-03 06:32:12 +00:00
|
|
|
sizeof(struct ahc_dma_seg));
|
1995-05-30 08:16:23 +00:00
|
|
|
}
|
1996-01-03 06:32:12 +00:00
|
|
|
#endif /* AHC_DEBUG */
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-10-26 23:57:18 +00:00
|
|
|
/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_TWIN) {
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1995-01-22 00:48:39 +00:00
|
|
|
* The device is gated to channel B after a chip reset,
|
|
|
|
* so set those values first
|
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSIID, ahc->our_id_b);
|
|
|
|
scsi_conf = AHC_INB(ahc, SCSICONF + 1);
|
|
|
|
AHC_OUTB(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
|
1996-05-10 16:21:05 +00:00
|
|
|
| ENSTIMER|ACTNEGEN|STPWEN);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_ULTRA)
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN|ULTRAEN);
|
1995-10-29 05:57:48 +00:00
|
|
|
else
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scsi_conf & RESET_SCSI) {
|
1996-05-10 16:21:05 +00:00
|
|
|
/* Reset the bus */
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: Reseting Channel B\n",
|
|
|
|
ahc_name(ahc));
|
|
|
|
AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
|
1996-05-10 16:21:05 +00:00
|
|
|
DELAY(1000);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSISEQ, 0);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-05-10 16:21:05 +00:00
|
|
|
/* Ensure we don't get a RSTI interrupt from this */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
1996-05-10 16:21:05 +00:00
|
|
|
}
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1995-01-22 00:48:39 +00:00
|
|
|
/* Select Channel A */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SBLKCTL, 0);
|
1995-01-22 00:48:39 +00:00
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSIID, ahc->our_id);
|
|
|
|
scsi_conf = AHC_INB(ahc, SCSICONF);
|
|
|
|
AHC_OUTB(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
|
1996-05-10 16:21:05 +00:00
|
|
|
| ENSTIMER|ACTNEGEN|STPWEN);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_ULTRA)
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN|ULTRAEN);
|
1995-10-29 05:57:48 +00:00
|
|
|
else
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SXFRCTL0, DFON|SPIOEN);
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scsi_conf & RESET_SCSI) {
|
1996-05-10 16:21:05 +00:00
|
|
|
/* Reset the bus */
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: Reseting Channel A\n", ahc_name(ahc));
|
1996-05-10 16:21:05 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
|
1996-05-10 16:21:05 +00:00
|
|
|
DELAY(1000);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSISEQ, 0);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-05-10 16:21:05 +00:00
|
|
|
/* Ensure we don't get a RSTI interrupt from this */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
1996-05-10 16:21:05 +00:00
|
|
|
}
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
/*
|
1994-12-31 19:31:56 +00:00
|
|
|
* Look at the information that board initialization or
|
|
|
|
* the board bios has left us. In the lower four bits of each
|
|
|
|
* target's scratch space any value other than 0 indicates
|
1995-05-30 08:16:23 +00:00
|
|
|
* that we should initiate syncronous transfers. If it's zero,
|
|
|
|
* the user or the BIOS has decided to disable syncronous
|
1996-01-03 06:32:12 +00:00
|
|
|
* negotiation to that target so we don't activate the needsdtr
|
1994-12-31 19:31:56 +00:00
|
|
|
* flag.
|
|
|
|
*/
|
1995-01-16 16:33:47 +00:00
|
|
|
ahc->needsdtr_orig = 0;
|
|
|
|
ahc->needwdtr_orig = 0;
|
1995-07-04 21:14:45 +00:00
|
|
|
|
|
|
|
/* Grab the disconnection disable table and invert it for our needs */
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->flags & AHC_USEDEFAULTS) {
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: Host Adapter Bios disabled. Using default SCSI "
|
|
|
|
"device parameters\n", ahc_name(ahc));
|
1995-07-04 21:14:45 +00:00
|
|
|
ahc->discenable = 0xff;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc->discenable = ~((AHC_INB(ahc, DISC_DSB + 1) << 8)
|
|
|
|
| AHC_INB(ahc, DISC_DSB));
|
1995-07-04 21:14:45 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (!(ahc->type & (AHC_WIDE|AHC_TWIN)))
|
1995-09-05 23:52:03 +00:00
|
|
|
max_targ = 7;
|
1995-03-31 13:54:41 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
for (i = 0; i <= max_targ; i++) {
|
|
|
|
u_int8_t target_settings;
|
1996-01-03 06:32:12 +00:00
|
|
|
if (ahc->flags & AHC_USEDEFAULTS) {
|
1995-07-04 21:14:45 +00:00
|
|
|
target_settings = 0; /* 10MHz */
|
|
|
|
ahc->needsdtr_orig |= (0x01 << i);
|
1995-01-16 16:33:47 +00:00
|
|
|
ahc->needwdtr_orig |= (0x01 << i);
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1995-07-04 21:14:45 +00:00
|
|
|
/* Take the settings leftover in scratch RAM. */
|
1996-05-30 07:19:59 +00:00
|
|
|
target_settings = AHC_INB(ahc, TARG_SCRATCH + i);
|
1995-07-04 21:14:45 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (target_settings & 0x0f) {
|
1995-07-04 21:14:45 +00:00
|
|
|
ahc->needsdtr_orig |= (0x01 << i);
|
|
|
|
/*Default to a asyncronous transfers(0 offset)*/
|
|
|
|
target_settings &= 0xf0;
|
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
if (target_settings & 0x80) {
|
1995-07-04 21:14:45 +00:00
|
|
|
ahc->needwdtr_orig |= (0x01 << i);
|
|
|
|
/*
|
|
|
|
* We'll set the Wide flag when we
|
1996-01-03 06:32:12 +00:00
|
|
|
* are successful with Wide negotiation.
|
|
|
|
* Turn it off for now so we aren't
|
1995-07-04 21:14:45 +00:00
|
|
|
* confused.
|
|
|
|
*/
|
|
|
|
target_settings &= 0x7f;
|
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->type & AHC_ULTRA) {
|
1996-05-21 18:37:25 +00:00
|
|
|
/*
|
|
|
|
* Enable Ultra for any target that
|
|
|
|
* has a valid ultra syncrate setting.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t rate = target_settings & 0x70;
|
|
|
|
if (rate == 0x00 || rate == 0x10 ||
|
|
|
|
rate == 0x20 || rate == 0x40) {
|
|
|
|
if (rate == 0x40) {
|
1996-05-23 15:02:18 +00:00
|
|
|
/* Treat 10MHz specially */
|
|
|
|
target_settings &= ~0x70;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else
|
1996-05-23 15:02:18 +00:00
|
|
|
ultraenable |= (0x01 << i);
|
|
|
|
}
|
1996-05-21 18:37:25 +00:00
|
|
|
}
|
1995-01-13 02:24:31 +00:00
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, TARG_SCRATCH+i,target_settings);
|
1994-12-31 19:31:56 +00:00
|
|
|
}
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1995-02-22 01:43:25 +00:00
|
|
|
* If we are not a WIDE device, forget WDTR. This
|
|
|
|
* makes the driver work on some cards that don't
|
|
|
|
* leave these fields cleared when the BIOS is not
|
|
|
|
* installed.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((ahc->type & AHC_WIDE) == 0)
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->needwdtr_orig = 0;
|
1995-03-07 08:59:28 +00:00
|
|
|
ahc->needsdtr = ahc->needsdtr_orig;
|
1995-01-16 16:33:47 +00:00
|
|
|
ahc->needwdtr = ahc->needwdtr_orig;
|
1995-02-03 17:15:12 +00:00
|
|
|
ahc->sdtrpending = 0;
|
|
|
|
ahc->wdtrpending = 0;
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->tagenable = 0;
|
1996-04-28 19:21:20 +00:00
|
|
|
ahc->orderedtag = 0;
|
1995-03-17 23:58:27 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, ULTRA_ENB, ultraenable & 0xff);
|
|
|
|
AHC_OUTB(ahc, ULTRA_ENB + 1, (ultraenable >> 8) & 0xff);
|
1996-05-21 18:37:25 +00:00
|
|
|
|
1996-01-03 06:32:12 +00:00
|
|
|
#ifdef AHC_DEBUG
|
|
|
|
/* How did we do? */
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc_debug & AHC_SHOWMISC)
|
1996-01-03 06:32:12 +00:00
|
|
|
printf("NEEDSDTR == 0x%x\nNEEDWDTR == 0x%x\n"
|
|
|
|
"DISCENABLE == 0x%x\n", ahc->needsdtr,
|
|
|
|
ahc->needwdtr, ahc->discenable);
|
|
|
|
#endif
|
1994-12-31 19:31:56 +00:00
|
|
|
/*
|
1996-10-25 06:42:53 +00:00
|
|
|
* Set the number of availible hardware SCBs
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBCOUNT, ahc->maxhscbs);
|
1996-01-03 06:32:12 +00:00
|
|
|
|
|
|
|
/*
|
1996-04-20 21:29:27 +00:00
|
|
|
* 2's compliment of maximum tag value
|
1996-01-03 06:32:12 +00:00
|
|
|
*/
|
|
|
|
i = ahc->maxscbs;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, COMP_SCBCOUNT, -i & 0xff);
|
1994-12-31 19:31:56 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* Allocate enough "hardware scbs" to handle
|
|
|
|
* the maximum number of concurrent transactions
|
|
|
|
* we can have active. We have to use contigmalloc
|
|
|
|
* if this array crosses a page boundary since the
|
|
|
|
* sequencer depends on this array being physically
|
|
|
|
* contiguous.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
size_t array_size;
|
|
|
|
u_int32_t hscb_physaddr;
|
|
|
|
|
|
|
|
array_size = ahc->maxscbs * sizeof(struct hardware_scb);
|
|
|
|
if (array_size > PAGE_SIZE) {
|
|
|
|
ahc->hscbs = (struct hardware_scb *)
|
|
|
|
contigmalloc(array_size, M_DEVBUF,
|
|
|
|
M_NOWAIT, 0ul, 0xffffffff, PAGE_SIZE,
|
|
|
|
0x10000);
|
|
|
|
} else {
|
|
|
|
ahc->hscbs = (struct hardware_scb *)
|
|
|
|
malloc(array_size, M_DEVBUF, M_NOWAIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ahc->hscbs == NULL) {
|
|
|
|
printf("%s: unable to allocate hardware SCB array. "
|
|
|
|
"Failing attach\n");
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Tell the sequencer where it can find the hscb array. */
|
|
|
|
hscb_physaddr = vtophys(ahc->hscbs);
|
|
|
|
AHC_OUTB(ahc, HSCB_ADDR0, hscb_physaddr & 0xFF);
|
|
|
|
AHC_OUTB(ahc, HSCB_ADDR1, (hscb_physaddr >> 8)& 0xFF);
|
|
|
|
AHC_OUTB(ahc, HSCB_ADDR2, (hscb_physaddr >> 16)& 0xFF);
|
|
|
|
AHC_OUTB(ahc, HSCB_ADDR3, (hscb_physaddr >> 24)& 0xFF);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Q-Full-Count. Some cards have more Q space
|
|
|
|
* then SCBs.
|
|
|
|
*/
|
|
|
|
if (ahc->type & AHC_AIC7770) {
|
|
|
|
ahc->qfullcount = 4;
|
|
|
|
ahc->qcntmask = 0x07;
|
|
|
|
} else if (ahc->type & AHC_AIC7850) {
|
|
|
|
ahc->qfullcount = 8;
|
|
|
|
ahc->qcntmask = 0x0f;
|
|
|
|
} else if (ahc->maxhscbs == 255) {
|
|
|
|
/* 7870/7880 with external SRAM */
|
|
|
|
ahc->qfullcount = 255;
|
|
|
|
ahc->qcntmask = 0xff;
|
|
|
|
} else {
|
|
|
|
/* 7870/7880 */
|
|
|
|
ahc->qfullcount = 16;
|
|
|
|
ahc->qcntmask = 0x1f;
|
|
|
|
}
|
|
|
|
|
1996-03-31 03:15:31 +00:00
|
|
|
/*
|
|
|
|
* QCount mask to deal with broken aic7850s that
|
|
|
|
* sporatically get garbage in the upper bits of
|
|
|
|
* their QCount registers.
|
1996-10-25 06:42:53 +00:00
|
|
|
*
|
|
|
|
* QFullCount to guard against overflowing the
|
|
|
|
* QINFIFO or QOUTFIFO when we are paging SCBs.
|
1996-03-31 03:15:31 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, QCNTMASK, ahc->qcntmask);
|
1996-03-31 03:15:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
AHC_OUTB(ahc, QFULLCNT, ahc->qfullcount);
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-04-27 17:47:17 +00:00
|
|
|
/* We don't have any waiting selections */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, WAITING_SCBH, SCB_LIST_NULL);
|
1996-04-20 21:29:27 +00:00
|
|
|
|
|
|
|
/* Our disconnection list is empty too */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
|
1996-01-03 06:32:12 +00:00
|
|
|
|
|
|
|
/* Message out buffer starts empty */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, MSG_LEN, 0x00);
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1995-03-07 08:59:28 +00:00
|
|
|
/*
|
1996-01-03 06:32:12 +00:00
|
|
|
* Load the Sequencer program and Enable the adapter
|
|
|
|
* in "fast" mode.
|
1995-03-07 08:59:28 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: Downloading Sequencer Program...",
|
|
|
|
ahc_name(ahc));
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_loadseq(ahc);
|
1996-01-03 06:32:12 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bootverbose)
|
1995-09-05 23:52:03 +00:00
|
|
|
printf("Done\n");
|
1995-03-07 08:59:28 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SEQCTL, FASTMODE);
|
1995-03-07 08:59:28 +00:00
|
|
|
|
1996-10-06 16:38:45 +00:00
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Note that we are going and return (to probe)
|
|
|
|
*/
|
1996-04-20 21:29:27 +00:00
|
|
|
ahc->flags |= AHC_INIT;
|
1994-11-17 20:22:31 +00:00
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1994-11-17 20:22:31 +00:00
|
|
|
ahcminphys(bp)
|
1995-05-30 08:16:23 +00:00
|
|
|
struct buf *bp;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1995-01-13 02:24:31 +00:00
|
|
|
* Even though the card can transfer up to 16megs per command
|
1994-11-17 20:22:31 +00:00
|
|
|
* we are limited by the number of segments in the dma segment
|
|
|
|
* list that we can hold. The worst case is that all pages are
|
|
|
|
* discontinuous physically, hense the "page per segment" limit
|
|
|
|
* enforced here.
|
|
|
|
*/
|
1996-05-21 18:37:25 +00:00
|
|
|
if (bp->b_bcount > ((AHC_NSEG - 1) * PAGE_SIZE)) {
|
|
|
|
bp->b_bcount = ((AHC_NSEG - 1) * PAGE_SIZE);
|
1995-05-30 08:16:23 +00:00
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
#if defined(__NetBSD__)
|
|
|
|
minphys(bp);
|
|
|
|
#endif
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* start a scsi operation given the command and
|
1995-05-30 08:16:23 +00:00
|
|
|
* the data address, target, and lun all of which
|
1994-11-17 20:22:31 +00:00
|
|
|
* are stored in the scsi_xfer struct
|
|
|
|
*/
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
static int32_t
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc_scsi_cmd(xs)
|
|
|
|
struct scsi_xfer *xs;
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
struct scb *scb;
|
|
|
|
struct hardware_scb *hscb;
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int16_t mask;
|
|
|
|
int flags;
|
|
|
|
int s;
|
1995-01-13 02:24:31 +00:00
|
|
|
|
1996-01-07 19:24:36 +00:00
|
|
|
ahc = (struct ahc_data *)xs->sc_link->adapter_softc;
|
1996-06-23 20:02:37 +00:00
|
|
|
mask = (0x01 << (xs->sc_link->target
|
1996-10-25 06:42:53 +00:00
|
|
|
| (IS_SCSIBUS_B(ahc, xs->sc_link) ? SELBUSB : 0)));
|
1996-06-23 20:02:37 +00:00
|
|
|
SC_DEBUG(xs->sc_link, SDEV_DB2, ("ahc_scsi_cmd\n"));
|
1996-10-25 06:42:53 +00:00
|
|
|
flags = xs->flags;
|
1996-06-23 20:02:37 +00:00
|
|
|
/*
|
|
|
|
* get an scb to use. If the transfer
|
|
|
|
* is from a buf (possibly from interrupt time)
|
|
|
|
* then we can't allow it to sleep
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((scb = ahc_get_scb(ahc, flags)) == NULL) {
|
1996-06-23 20:02:37 +00:00
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
|
|
|
return (TRY_AGAIN_LATER);
|
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb = scb->hscb;
|
1996-06-23 20:02:37 +00:00
|
|
|
SC_DEBUG(xs->sc_link, SDEV_DB3, ("start scb(%p)\n", scb));
|
|
|
|
scb->xs = xs;
|
1996-10-25 06:42:53 +00:00
|
|
|
|
1996-06-23 20:02:37 +00:00
|
|
|
/*
|
|
|
|
* Put all the arguments for the xfer in the scb
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
if (ahc->discenable & mask)
|
|
|
|
hscb->control |= DISCENB;
|
|
|
|
|
|
|
|
if (flags & SCSI_RESET) {
|
|
|
|
scb->flags |= SCB_DEVICE_RESET|SCB_IMMED;
|
|
|
|
hscb->control |= MK_MESSAGE;
|
|
|
|
} else if ((ahc->needwdtr & mask) && !(ahc->wdtrpending & mask)) {
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->wdtrpending |= mask;
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->control |= MK_MESSAGE;
|
|
|
|
scb->flags |= SCB_MSGOUT_WDTR;
|
|
|
|
} else if((ahc->needsdtr & mask) && !(ahc->sdtrpending & mask)) {
|
1995-02-22 01:43:25 +00:00
|
|
|
ahc->sdtrpending |= mask;
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->control |= MK_MESSAGE;
|
|
|
|
scb->flags |= SCB_MSGOUT_SDTR;
|
|
|
|
} else if (ahc->orderedtag & mask) {
|
|
|
|
/* XXX this should be handled by the upper SCSI layer */
|
|
|
|
printf("Ordered Tag sent\n");
|
|
|
|
hscb->control |= MSG_ORDERED_Q_TAG;
|
|
|
|
ahc->orderedtag &= ~mask;
|
|
|
|
} else if (hscb->control & DISCENB) {
|
|
|
|
if (ahc->tagenable & mask)
|
|
|
|
hscb->control |= TAG_ENB;
|
|
|
|
}
|
|
|
|
hscb->tcl = ((xs->sc_link->target << 4) & 0xF0)
|
|
|
|
| (IS_SCSIBUS_B(ahc,xs->sc_link)? SELBUSB : 0)
|
|
|
|
| (xs->sc_link->lun & 0x07);
|
|
|
|
hscb->cmdlen = xs->cmdlen;
|
|
|
|
hscb->cmdpointer = vtophys(xs->cmd);
|
1995-03-31 13:54:41 +00:00
|
|
|
xs->resid = 0;
|
1995-06-11 19:33:05 +00:00
|
|
|
xs->status = 0;
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
/* Only use S/G if non-zero length */
|
|
|
|
if (xs->datalen) {
|
|
|
|
int seg;
|
|
|
|
u_int32_t datalen;
|
|
|
|
vm_offset_t vaddr;
|
|
|
|
u_int32_t paddr;
|
|
|
|
u_int32_t nextpaddr;
|
|
|
|
struct ahc_dma_seg *sg;
|
|
|
|
|
1996-04-20 21:29:27 +00:00
|
|
|
seg = 0;
|
|
|
|
datalen = xs->datalen;
|
1996-10-25 06:42:53 +00:00
|
|
|
vaddr = (vm_offset_t)xs->data;
|
|
|
|
paddr = vtophys(vaddr);
|
|
|
|
sg = scb->ahc_dma;
|
|
|
|
hscb->SG_list_pointer = vtophys(sg);
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
while ((datalen > 0) && (seg < AHC_NSEG)) {
|
|
|
|
/* put in the base address and length */
|
|
|
|
sg->addr = paddr;
|
|
|
|
sg->len = 0;
|
1996-04-20 21:29:27 +00:00
|
|
|
|
|
|
|
/* do it at least once */
|
1996-10-25 06:42:53 +00:00
|
|
|
nextpaddr = paddr;
|
|
|
|
|
|
|
|
while ((datalen > 0) && (paddr == nextpaddr)) {
|
|
|
|
u_int32_t size;
|
1996-04-20 21:29:27 +00:00
|
|
|
/*
|
|
|
|
* This page is contiguous (physically)
|
|
|
|
* with the the last, just extend the
|
|
|
|
* length
|
|
|
|
*/
|
|
|
|
/* how far to the end of the page */
|
1996-10-25 06:42:53 +00:00
|
|
|
nextpaddr = (paddr & (~PAGE_MASK)) + PAGE_SIZE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compute the maximum size
|
|
|
|
*/
|
|
|
|
size = nextpaddr - paddr;
|
|
|
|
if (size > datalen)
|
|
|
|
size = datalen;
|
|
|
|
|
|
|
|
sg->len += size;
|
|
|
|
vaddr += size;
|
|
|
|
datalen -= size;
|
|
|
|
if (datalen > 0)
|
|
|
|
paddr = vtophys(vaddr);
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* next page isn't contiguous, finish the seg
|
|
|
|
*/
|
|
|
|
seg++;
|
1996-10-25 06:42:53 +00:00
|
|
|
sg++;
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->SG_segment_count = seg;
|
1995-07-04 21:14:45 +00:00
|
|
|
|
|
|
|
/* Copy the first SG into the data pointer area */
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->data = scb->ahc_dma->addr;
|
|
|
|
hscb->datalen = scb->ahc_dma->len | (SCB_LIST_NULL << 24);
|
1996-04-20 21:29:27 +00:00
|
|
|
if (datalen) {
|
1995-07-04 21:14:45 +00:00
|
|
|
/* there's still data, must have run out of segs! */
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: ahc_scsi_cmd: more than %d DMA segs\n",
|
|
|
|
ahc_name(ahc), AHC_NSEG);
|
1996-04-20 21:29:27 +00:00
|
|
|
xs->error = XS_DRIVER_STUFFUP;
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_free_scb(ahc, scb);
|
1996-04-20 21:29:27 +00:00
|
|
|
return (COMPLETE);
|
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
#ifdef AHC_BROKEN_CACHE
|
|
|
|
if (ahc_broken_cache)
|
|
|
|
INVALIDATE_CACHE();
|
|
|
|
#endif
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
Fixes to the aic7xxx sequencer code and device driver from Justin Gibbs:
1) If a target initiated a sync negotiation with us and happened to chose a
value above 15, the old code inadvertantly truncated it with an "& 0x0f".
If the periferal picked something really bad like 0x32, you'd end up with
an offset of 2 which would hang the drive since it didn't expect to ever
get something so low. We now do a MIN(maxoffset, given_offset).
2) In the case of Wide cards, we were turning on sync transfers after a
sucessfull wide negotiation. Now we leave the offset alone in the per
target scratch space (which implies asyncronous transfers since we initialize
it that way) until a syncronous negotation occurs.
3) We were advertizing a max offset of 15 instead of 8 for wide devices.
4) If the upper level SCSI code sent down a "SCSI_RESET", it would hang the
system because we would end up sending a null command to the sequencer. Now
we handle SCSI_RESET correctly by having the sequencer interrupt us when it
is about to fill the message buffer so that we can fill it in ourselves.
The sequencer will also "simulate" a command complete for these "message only"
SCBs so that the kernel driver can finish up properly. The cdplay utility
will send a "SCSI_REST" to the cdplayer if you use the reset command.
5) The code that handles SCSIINTs was broken in that if more than one type
of error was true at once, we'd do outbs without the card being paused.
The else clause after the busfree case was also an accident waiting to
happen. I've now turned this into an if, else if, else type of thing, since
in most cases when we handle one type of error, it should be okay to ignore
the rest (ie if we have a SELTO, who cares if there was a parity error on
the transaction?), but the section should really be rewritten after 2.0.5.
This fix was the least obtrusive way to patch the problem.
6) Only tag either SDTR or WDTR negotiation on an SCB. The real problem is
that I don't account for the case when an SCB that is tagged to do a particular
type of negotiation completes or SELTOs (selection timeout) without the
negotiation taking place, so the accounting of sdtrpending and wdtrpending
gets screwed up. In the wide case, if we tag it to do both wdtr and sdtr,
it only performs wdtr (since wdtr must occur first and we spread out the
negotiation over two commands) so we always have sdtrpending set for that
target and we never do a real SDTR. I fill properly fix the accounting
after 2.0.5 goes out the door, but this works (as confirmed by Dan) on
wide targets.
Other stuff that is also included:
1) Don't do a bzero when recycling SCBs. The only thing that must explicitly
be set to zero is the scb control byte which is done in ahc_get_scb. We also
need to set the SG_list_pointer and SG_list_count to 0 for commands that do
not transfer data.
2) Mask the interrupt type printout for the aic7870 case. The bit we were
using to determine interrupt type is only valid for the aic7770.
Submitted by: Justin Gibbs
1995-05-17 07:06:02 +00:00
|
|
|
/*
|
1995-05-30 08:16:23 +00:00
|
|
|
* No data xfer, use non S/G values
|
Fixes to the aic7xxx sequencer code and device driver from Justin Gibbs:
1) If a target initiated a sync negotiation with us and happened to chose a
value above 15, the old code inadvertantly truncated it with an "& 0x0f".
If the periferal picked something really bad like 0x32, you'd end up with
an offset of 2 which would hang the drive since it didn't expect to ever
get something so low. We now do a MIN(maxoffset, given_offset).
2) In the case of Wide cards, we were turning on sync transfers after a
sucessfull wide negotiation. Now we leave the offset alone in the per
target scratch space (which implies asyncronous transfers since we initialize
it that way) until a syncronous negotation occurs.
3) We were advertizing a max offset of 15 instead of 8 for wide devices.
4) If the upper level SCSI code sent down a "SCSI_RESET", it would hang the
system because we would end up sending a null command to the sequencer. Now
we handle SCSI_RESET correctly by having the sequencer interrupt us when it
is about to fill the message buffer so that we can fill it in ourselves.
The sequencer will also "simulate" a command complete for these "message only"
SCBs so that the kernel driver can finish up properly. The cdplay utility
will send a "SCSI_REST" to the cdplayer if you use the reset command.
5) The code that handles SCSIINTs was broken in that if more than one type
of error was true at once, we'd do outbs without the card being paused.
The else clause after the busfree case was also an accident waiting to
happen. I've now turned this into an if, else if, else type of thing, since
in most cases when we handle one type of error, it should be okay to ignore
the rest (ie if we have a SELTO, who cares if there was a parity error on
the transaction?), but the section should really be rewritten after 2.0.5.
This fix was the least obtrusive way to patch the problem.
6) Only tag either SDTR or WDTR negotiation on an SCB. The real problem is
that I don't account for the case when an SCB that is tagged to do a particular
type of negotiation completes or SELTOs (selection timeout) without the
negotiation taking place, so the accounting of sdtrpending and wdtrpending
gets screwed up. In the wide case, if we tag it to do both wdtr and sdtr,
it only performs wdtr (since wdtr must occur first and we spread out the
negotiation over two commands) so we always have sdtrpending set for that
target and we never do a real SDTR. I fill properly fix the accounting
after 2.0.5 goes out the door, but this works (as confirmed by Dan) on
wide targets.
Other stuff that is also included:
1) Don't do a bzero when recycling SCBs. The only thing that must explicitly
be set to zero is the scb control byte which is done in ahc_get_scb. We also
need to set the SG_list_pointer and SG_list_count to 0 for commands that do
not transfer data.
2) Mask the interrupt type printout for the aic7870 case. The bit we were
using to determine interrupt type is only valid for the aic7770.
Submitted by: Justin Gibbs
1995-05-17 07:06:02 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->SG_segment_count = 0;
|
|
|
|
hscb->SG_list_pointer = 0;
|
|
|
|
hscb->data = 0;
|
|
|
|
hscb->datalen = (SCB_LIST_NULL << 24);
|
Fixes to the aic7xxx sequencer code and device driver from Justin Gibbs:
1) If a target initiated a sync negotiation with us and happened to chose a
value above 15, the old code inadvertantly truncated it with an "& 0x0f".
If the periferal picked something really bad like 0x32, you'd end up with
an offset of 2 which would hang the drive since it didn't expect to ever
get something so low. We now do a MIN(maxoffset, given_offset).
2) In the case of Wide cards, we were turning on sync transfers after a
sucessfull wide negotiation. Now we leave the offset alone in the per
target scratch space (which implies asyncronous transfers since we initialize
it that way) until a syncronous negotation occurs.
3) We were advertizing a max offset of 15 instead of 8 for wide devices.
4) If the upper level SCSI code sent down a "SCSI_RESET", it would hang the
system because we would end up sending a null command to the sequencer. Now
we handle SCSI_RESET correctly by having the sequencer interrupt us when it
is about to fill the message buffer so that we can fill it in ourselves.
The sequencer will also "simulate" a command complete for these "message only"
SCBs so that the kernel driver can finish up properly. The cdplay utility
will send a "SCSI_REST" to the cdplayer if you use the reset command.
5) The code that handles SCSIINTs was broken in that if more than one type
of error was true at once, we'd do outbs without the card being paused.
The else clause after the busfree case was also an accident waiting to
happen. I've now turned this into an if, else if, else type of thing, since
in most cases when we handle one type of error, it should be okay to ignore
the rest (ie if we have a SELTO, who cares if there was a parity error on
the transaction?), but the section should really be rewritten after 2.0.5.
This fix was the least obtrusive way to patch the problem.
6) Only tag either SDTR or WDTR negotiation on an SCB. The real problem is
that I don't account for the case when an SCB that is tagged to do a particular
type of negotiation completes or SELTOs (selection timeout) without the
negotiation taking place, so the accounting of sdtrpending and wdtrpending
gets screwed up. In the wide case, if we tag it to do both wdtr and sdtr,
it only performs wdtr (since wdtr must occur first and we spread out the
negotiation over two commands) so we always have sdtrpending set for that
target and we never do a real SDTR. I fill properly fix the accounting
after 2.0.5 goes out the door, but this works (as confirmed by Dan) on
wide targets.
Other stuff that is also included:
1) Don't do a bzero when recycling SCBs. The only thing that must explicitly
be set to zero is the scb control byte which is done in ahc_get_scb. We also
need to set the SG_list_pointer and SG_list_count to 0 for commands that do
not transfer data.
2) Mask the interrupt type printout for the aic7870 case. The bit we were
using to determine interrupt type is only valid for the aic7770.
Submitted by: Justin Gibbs
1995-05-17 07:06:02 +00:00
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-02-22 01:43:25 +00:00
|
|
|
#ifdef AHC_DEBUG
|
1996-10-25 06:42:53 +00:00
|
|
|
if((ahc_debug & AHC_SHOWSCBS) && (xs->sc_link->target == DEBUGTARGET))
|
1994-11-17 20:22:31 +00:00
|
|
|
ahc_print_scb(scb);
|
|
|
|
#endif
|
1996-04-20 21:29:27 +00:00
|
|
|
s = splbio();
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
STAILQ_INSERT_TAIL(&ahc->waiting_scbs, scb, links);
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
scb->flags |= SCB_ACTIVE;
|
|
|
|
|
|
|
|
ahc_run_waiting_queue(ahc);
|
|
|
|
|
|
|
|
if ((flags & SCSI_NOMASK) == 0) {
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb, (xs->timeout * hz) / 1000);
|
1996-04-20 21:29:27 +00:00
|
|
|
splx(s);
|
1996-01-29 03:17:39 +00:00
|
|
|
return (SUCCESSFULLY_QUEUED);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If we can't use interrupts, poll for completion
|
|
|
|
*/
|
1996-04-20 21:29:27 +00:00
|
|
|
SC_DEBUG(xs->sc_link, SDEV_DB3, ("cmd_poll\n"));
|
1996-01-29 03:17:39 +00:00
|
|
|
do {
|
|
|
|
if (ahc_poll(ahc, xs->timeout)) {
|
|
|
|
if (!(xs->flags & SCSI_SILENT))
|
|
|
|
printf("cmd fail\n");
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc_timeout(scb);
|
|
|
|
break;
|
1996-01-29 03:17:39 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
} while ((xs->flags & ITSDONE) == 0); /* a non command complete intr */
|
1996-01-29 03:17:39 +00:00
|
|
|
splx(s);
|
|
|
|
return (COMPLETE);
|
1995-05-30 08:16:23 +00:00
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* Look for space in the QINFIFO and queue as many SCBs in the waiting
|
|
|
|
* queue as possible. Assumes that it is called at splbio().
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ahc_run_waiting_queue(ahc)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
{
|
|
|
|
struct scb *scb;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* On aic78X0 chips, we rely on Auto Access Pause (AAP)
|
|
|
|
* instead of doing an explicit pause/unpause.
|
|
|
|
*/
|
|
|
|
if ((ahc->type & AHC_AIC78X0) == 0)
|
|
|
|
pause_sequencer(ahc);
|
|
|
|
|
|
|
|
while ((scb = ahc->waiting_scbs.stqh_first) != NULL) {
|
|
|
|
|
|
|
|
if (ahc->curqincnt >= ahc->qfullcount) {
|
|
|
|
ahc->curqincnt = AHC_INB(ahc, QINCNT) & ahc->qcntmask;
|
|
|
|
if (ahc->curqincnt >= ahc->qfullcount)
|
|
|
|
/* Still no space */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
STAILQ_REMOVE_HEAD(&ahc->waiting_scbs, links);
|
|
|
|
AHC_OUTB(ahc, QINFIFO, scb->hscb->tag);
|
|
|
|
|
|
|
|
if ((ahc->flags & AHC_PAGESCBS) != 0)
|
|
|
|
/*
|
|
|
|
* We only care about this statistic when paging
|
|
|
|
* since it is impossible to overflow the qinfifo
|
|
|
|
* in the non-paging case.
|
|
|
|
*/
|
|
|
|
ahc->curqincnt++;
|
|
|
|
}
|
|
|
|
if ((ahc->type & AHC_AIC78X0) == 0)
|
|
|
|
unpause_sequencer(ahc, /*Unpause always*/FALSE);
|
|
|
|
}
|
1994-11-17 20:22:31 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* A scb (and hence an scb entry on the board is put onto the
|
|
|
|
* free list.
|
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_free_scb(ahc, scb)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
struct scb *scb;
|
|
|
|
{
|
|
|
|
struct hardware_scb *hscb;
|
|
|
|
int opri;
|
|
|
|
|
|
|
|
hscb = scb->hscb;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-04-23 22:04:58 +00:00
|
|
|
opri = splbio();
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-06-23 20:02:37 +00:00
|
|
|
/* Clean up for the next user */
|
1996-04-20 21:29:27 +00:00
|
|
|
scb->flags = SCB_FREE;
|
1996-10-25 06:42:53 +00:00
|
|
|
hscb->control = 0;
|
|
|
|
hscb->status = 0;
|
1996-06-23 20:02:37 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
STAILQ_INSERT_HEAD(&ahc->free_scbs, scb, links);
|
|
|
|
if (scb->links.stqe_next == NULL) {
|
|
|
|
/*
|
|
|
|
* If there were no SCBs availible, wake anybody waiting
|
|
|
|
* for one to come free.
|
1996-04-20 21:29:27 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
wakeup((caddr_t)&ahc->free_scbs);
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
1996-06-23 20:02:37 +00:00
|
|
|
#ifdef AHC_DEBUG
|
|
|
|
ahc->activescbs--;
|
|
|
|
#endif
|
1995-04-23 22:04:58 +00:00
|
|
|
splx(opri);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1994-11-17 20:22:31 +00:00
|
|
|
/*
|
1996-04-20 21:29:27 +00:00
|
|
|
* Get a free scb, either one already assigned to a hardware slot
|
|
|
|
* on the adapter or one that will require an SCB to be paged out before
|
|
|
|
* use. If there are none, see if we can allocate a new SCB. Otherwise
|
|
|
|
* either return an error or sleep.
|
1994-11-17 20:22:31 +00:00
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static struct scb *
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc_get_scb(ahc, flags)
|
1996-10-25 06:42:53 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
u_int32_t flags;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-04-20 21:29:27 +00:00
|
|
|
struct scb *scbp;
|
1996-10-25 06:42:53 +00:00
|
|
|
int opri;
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1995-04-23 22:04:58 +00:00
|
|
|
opri = splbio();
|
1996-04-20 21:29:27 +00:00
|
|
|
/*
|
|
|
|
* If we can and have to, sleep waiting for one to come free
|
|
|
|
* but only if we can't allocate a new one.
|
|
|
|
*/
|
|
|
|
while (1) {
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((scbp = ahc->free_scbs.stqh_first)) {
|
1996-04-20 21:29:27 +00:00
|
|
|
STAILQ_REMOVE_HEAD(&ahc->free_scbs, links);
|
1996-10-25 06:42:53 +00:00
|
|
|
} else if(ahc->numscbs < ahc->maxscbs) {
|
|
|
|
scbp = ahc_alloc_scb(ahc);
|
|
|
|
if (scbp == NULL)
|
|
|
|
printf("%s: Can't malloc SCB\n", ahc_name(ahc));
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
else if ((flags & SCSI_NOSLEEP) == 0) {
|
|
|
|
tsleep((caddr_t)&ahc->free_scbs, PRIBIO,
|
|
|
|
"ahcscb", 0);
|
|
|
|
continue;
|
1996-03-31 03:15:31 +00:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
1995-04-23 22:04:58 +00:00
|
|
|
|
|
|
|
#ifdef AHC_DEBUG
|
1996-06-23 20:02:37 +00:00
|
|
|
if (scbp) {
|
1995-04-23 22:04:58 +00:00
|
|
|
ahc->activescbs++;
|
1996-01-03 06:32:12 +00:00
|
|
|
if((ahc_debug & AHC_SHOWSCBCNT)
|
1996-04-20 21:29:27 +00:00
|
|
|
&& (ahc->activescbs == ahc->maxhscbs))
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: Max SCBs active\n", ahc_name(ahc));
|
1996-03-31 03:15:31 +00:00
|
|
|
}
|
1996-06-23 20:02:37 +00:00
|
|
|
#endif
|
1995-04-23 22:04:58 +00:00
|
|
|
|
|
|
|
splx(opri);
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-03-31 03:15:31 +00:00
|
|
|
return (scbp);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
static struct scb *
|
|
|
|
ahc_alloc_scb(ahc)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
{
|
|
|
|
static struct ahc_dma_seg *next_sg_array = NULL;
|
|
|
|
static int sg_arrays_free;
|
|
|
|
struct scb *newscb;
|
|
|
|
|
|
|
|
newscb = (struct scb *) malloc(sizeof(struct scb), M_DEVBUF, M_NOWAIT);
|
|
|
|
if (newscb != NULL) {
|
|
|
|
bzero(newscb, sizeof(struct scb));
|
|
|
|
if (next_sg_array == NULL) {
|
|
|
|
size_t alloc_size = sizeof(struct ahc_dma_seg)
|
|
|
|
* AHC_NSEG;
|
|
|
|
sg_arrays_free = PAGE_SIZE / alloc_size;
|
|
|
|
/* Don't ever allocate more than we may need */
|
|
|
|
sg_arrays_free = MIN(ahc->maxscbs - ahc->numscbs,
|
|
|
|
sg_arrays_free);
|
|
|
|
alloc_size *= sg_arrays_free;
|
|
|
|
if (alloc_size == 0)
|
|
|
|
panic("%s: SG list doesn't fit in a page",
|
|
|
|
ahc_name(ahc));
|
|
|
|
next_sg_array = (struct ahc_dma_seg *)
|
|
|
|
malloc(alloc_size, M_DEVBUF, M_NOWAIT);
|
|
|
|
}
|
|
|
|
if (next_sg_array != NULL) {
|
|
|
|
struct hardware_scb *hscb;
|
|
|
|
|
|
|
|
newscb->ahc_dma = next_sg_array;
|
|
|
|
sg_arrays_free--;
|
|
|
|
if (sg_arrays_free == 0)
|
|
|
|
next_sg_array = NULL;
|
|
|
|
else
|
|
|
|
next_sg_array = &next_sg_array[AHC_NSEG];
|
|
|
|
hscb = &ahc->hscbs[ahc->numscbs];
|
|
|
|
newscb->hscb = hscb;
|
|
|
|
hscb->control = 0;
|
|
|
|
hscb->status = 0;
|
|
|
|
hscb->tag = ahc->numscbs;
|
|
|
|
hscb->residual_data_count[2] = 0;
|
|
|
|
hscb->residual_data_count[1] = 0;
|
|
|
|
hscb->residual_data_count[0] = 0;
|
|
|
|
hscb->residual_SG_segment_count = 0;
|
|
|
|
ahc->numscbs++;
|
|
|
|
/*
|
|
|
|
* Place in the scbarray
|
|
|
|
* Never is removed.
|
|
|
|
*/
|
|
|
|
ahc->scbarray[hscb->tag] = newscb;
|
|
|
|
} else {
|
|
|
|
free(newscb, M_DEVBUF);
|
|
|
|
newscb = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return newscb;
|
|
|
|
}
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
static void ahc_loadseq(ahc)
|
|
|
|
struct ahc_data *ahc;
|
1994-11-17 20:22:31 +00:00
|
|
|
{
|
1996-06-23 20:02:37 +00:00
|
|
|
static u_char seqprog[] = {
|
1995-01-13 02:24:31 +00:00
|
|
|
# include "aic7xxx_seq.h"
|
1996-03-31 03:15:31 +00:00
|
|
|
};
|
1995-05-30 08:16:23 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SEQCTL, PERRORDIS|SEQRESET|LOADRAM);
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTSB(ahc, SEQRAM, seqprog, sizeof(seqprog));
|
1994-11-17 20:22:31 +00:00
|
|
|
|
1996-06-08 06:55:01 +00:00
|
|
|
do {
|
|
|
|
AHC_OUTB(ahc, SEQCTL, SEQRESET|FASTMODE);
|
1996-10-25 06:42:53 +00:00
|
|
|
} while ((AHC_INB(ahc, SEQADDR0) != 0)
|
|
|
|
|| (AHC_INB(ahc, SEQADDR1) != 0));
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1996-01-29 03:17:39 +00:00
|
|
|
/*
|
|
|
|
* Function to poll for command completion when
|
|
|
|
* interrupts are disabled (crash dumps)
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
ahc_poll(ahc, wait)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
int wait; /* in msec */
|
|
|
|
{
|
|
|
|
while (--wait) {
|
|
|
|
DELAY(1000);
|
1996-05-30 07:19:59 +00:00
|
|
|
if (AHC_INB(ahc, INTSTAT) & INT_PEND)
|
1996-01-29 03:17:39 +00:00
|
|
|
break;
|
|
|
|
} if (wait == 0) {
|
1996-05-30 07:19:59 +00:00
|
|
|
printf("%s: board is not responding\n", ahc_name(ahc));
|
1996-01-29 03:17:39 +00:00
|
|
|
return (EIO);
|
|
|
|
}
|
|
|
|
ahc_intr((void *)ahc);
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc_timeout(arg)
|
|
|
|
void *arg;
|
1994-12-31 19:31:56 +00:00
|
|
|
{
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
struct scb *scb = (struct scb *)arg;
|
|
|
|
struct ahc_data *ahc;
|
1996-05-21 18:37:25 +00:00
|
|
|
int s, found;
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
u_char bus_state;
|
1994-12-31 19:31:56 +00:00
|
|
|
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
s = splbio();
|
|
|
|
|
|
|
|
if (!(scb->flags & SCB_ACTIVE)) {
|
|
|
|
/* Previous timeout took care of me already */
|
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ahc = (struct ahc_data *)scb->xs->sc_link->adapter_softc;
|
|
|
|
|
|
|
|
if (ahc->in_timeout) {
|
|
|
|
/*
|
|
|
|
* Some other SCB has started a recovery operation
|
|
|
|
* and is still working on cleaning things up.
|
|
|
|
*/
|
|
|
|
if (scb->flags & SCB_TIMEDOUT) {
|
|
|
|
/*
|
|
|
|
* This SCB has been here before and is not the
|
|
|
|
* recovery SCB. Cut our losses and panic. Its
|
|
|
|
* better to do this than trash a filesystem.
|
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
panic("%s: Timed-out command times out "
|
|
|
|
"again\n", ahc_name(ahc));
|
1996-10-25 06:42:53 +00:00
|
|
|
} else if ((scb->flags & (SCB_ABORTED | SCB_DEVICE_RESET
|
|
|
|
| SCB_SENTORDEREDTAG)) == 0) {
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
/*
|
|
|
|
* This is not the SCB that started this timeout
|
|
|
|
* processing. Give this scb another lifetime so
|
|
|
|
* that it can continue once we deal with the
|
|
|
|
* timeout.
|
|
|
|
*/
|
|
|
|
scb->flags |= SCB_TIMEDOUT;
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb,
|
|
|
|
(scb->xs->timeout * hz) / 1000);
|
|
|
|
splx(s);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ahc->in_timeout = TRUE;
|
|
|
|
|
|
|
|
/*
|
1995-07-31 08:25:36 +00:00
|
|
|
* Ensure that the card doesn't do anything
|
|
|
|
* behind our back.
|
1994-12-31 19:31:56 +00:00
|
|
|
*/
|
1996-10-06 16:38:45 +00:00
|
|
|
pause_sequencer(ahc);
|
1994-12-31 19:31:56 +00:00
|
|
|
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
sc_print_addr(scb->xs->sc_link);
|
|
|
|
printf("timed out ");
|
1994-12-31 19:31:56 +00:00
|
|
|
/*
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
* Take a snapshot of the bus state and print out
|
|
|
|
* some information so we can track down driver bugs.
|
1994-12-31 19:31:56 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
bus_state = AHC_INB(ahc, LASTPHASE);
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
|
|
|
|
switch(bus_state & PHASE_MASK)
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
case P_DATAOUT:
|
|
|
|
printf("in dataout phase");
|
|
|
|
break;
|
|
|
|
case P_DATAIN:
|
|
|
|
printf("in datain phase");
|
|
|
|
break;
|
|
|
|
case P_COMMAND:
|
|
|
|
printf("in command phase");
|
|
|
|
break;
|
|
|
|
case P_MESGOUT:
|
|
|
|
printf("in message out phase");
|
|
|
|
break;
|
|
|
|
case P_STATUS:
|
|
|
|
printf("in status phase");
|
|
|
|
break;
|
|
|
|
case P_MESGIN:
|
|
|
|
printf("in message in phase");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
printf("while idle, LASTPHASE == 0x%x",
|
|
|
|
bus_state);
|
|
|
|
/*
|
|
|
|
* We aren't in a valid phase, so assume we're
|
|
|
|
* idle.
|
|
|
|
*/
|
|
|
|
bus_state = 0;
|
|
|
|
break;
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
}
|
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
printf(", SCSISIGI == 0x%x\n", AHC_INB(ahc, SCSISIGI));
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
|
|
|
|
/* Decide our course of action */
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scb->flags & SCB_ABORTED) {
|
1994-12-31 19:31:56 +00:00
|
|
|
/*
|
1995-07-31 08:25:36 +00:00
|
|
|
* Been down this road before.
|
|
|
|
* Do a full bus reset.
|
1994-12-31 19:31:56 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
char channel = (scb->hscb->tcl & SELBUSB)
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
? 'B': 'A';
|
1996-10-25 06:42:53 +00:00
|
|
|
found = ahc_reset_channel(ahc, channel, scb,
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
XS_TIMEOUT, /*Initiate Reset*/TRUE);
|
1996-10-25 06:42:53 +00:00
|
|
|
printf("%s: Issued Channel %c Bus Reset. "
|
1996-05-30 07:19:59 +00:00
|
|
|
"%d SCBs aborted\n", ahc_name(ahc), channel, found);
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc->in_timeout = FALSE;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else if ((scb->hscb->control & TAG_ENB) != 0
|
|
|
|
&& (scb->flags & SCB_SENTORDEREDTAG) == 0) {
|
1996-04-28 19:21:20 +00:00
|
|
|
/*
|
|
|
|
* We could be starving this command
|
|
|
|
* try sending an ordered tag command
|
|
|
|
* to the target we come from.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
scb->flags |= SCB_SENTORDEREDTAG;
|
1996-04-28 19:21:20 +00:00
|
|
|
ahc->orderedtag |= 0xFF;
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb, (5 * hz));
|
1996-10-06 16:38:45 +00:00
|
|
|
unpause_sequencer(ahc, /*unpause_always*/FALSE);
|
1996-04-28 19:21:20 +00:00
|
|
|
printf("Ordered Tag queued\n");
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1995-05-30 08:16:23 +00:00
|
|
|
/*
|
1996-10-25 06:42:53 +00:00
|
|
|
* Send an Abort Message:
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
* The target that is holding up the bus may not
|
|
|
|
* be the same as the one that triggered this timeout
|
|
|
|
* (different commands have different timeout lengths).
|
1996-10-25 06:42:53 +00:00
|
|
|
* Our strategy here is to queue an abort message
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
* to the timed out target if it is disconnected.
|
|
|
|
* Otherwise, if we have an active target we stuff the
|
1996-10-25 06:42:53 +00:00
|
|
|
* message buffer with an abort message and assert ATN
|
|
|
|
* in the hopes that the target will let go of the bus
|
|
|
|
* and go to the mesgout phase. If this fails, we'll
|
|
|
|
* get another timeout 2 seconds later which will attempt
|
|
|
|
* a bus reset.
|
1994-12-31 19:31:56 +00:00
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t saved_scbptr;
|
|
|
|
u_int8_t active_scb_index;
|
|
|
|
struct scb *active_scb;
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
saved_scbptr = AHC_INB(ahc, SCBPTR);
|
|
|
|
active_scb_index = AHC_INB(ahc, SCB_TAG);
|
|
|
|
active_scb = ahc->scbarray[active_scb_index];
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
if (bus_state != 0) {
|
|
|
|
/* Send the abort to the active SCB */
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, 1);
|
|
|
|
AHC_OUTB(ahc, MSG0,
|
|
|
|
(active_scb->hscb->control & TAG_ENB) == 0 ?
|
|
|
|
MSG_ABORT : MSG_ABORT_TAG);
|
|
|
|
AHC_OUTB(ahc, SCSISIGO, bus_state|ATNO);
|
|
|
|
sc_print_addr(active_scb->xs->sc_link);
|
|
|
|
printf("abort message in message buffer\n");
|
|
|
|
active_scb->flags |= SCB_ABORTED;
|
|
|
|
if (active_scb != scb) {
|
|
|
|
untimeout(ahc_timeout,
|
|
|
|
(caddr_t)active_scb);
|
|
|
|
/* Give scb a new lease on life */
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb,
|
|
|
|
(scb->xs->timeout * hz) / 1000);
|
|
|
|
}
|
|
|
|
timeout(ahc_timeout, (caddr_t)active_scb, (2 * hz));
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/FALSE);
|
|
|
|
} else {
|
|
|
|
u_int8_t hscb_index;
|
|
|
|
int disconnected;
|
1996-04-20 21:29:27 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
disconnected = FALSE;
|
|
|
|
hscb_index = find_scb(ahc, scb);
|
|
|
|
if (hscb_index == SCB_LIST_NULL)
|
|
|
|
disconnected = TRUE;
|
|
|
|
else {
|
|
|
|
AHC_OUTB(ahc, SCBPTR, hscb_index);
|
|
|
|
if (AHC_INB(ahc, SCB_CONTROL) & DISCONNECTED)
|
|
|
|
disconnected = TRUE;
|
1996-04-20 21:29:27 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
scb->flags |= SCB_ABORTED;
|
|
|
|
if (disconnected) {
|
|
|
|
/* Simply set the ABORT_SCB control bit */
|
|
|
|
scb->hscb->control |= ABORT_SCB;
|
|
|
|
if (hscb_index != SCB_LIST_NULL)
|
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, ABORT_SCB);
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb, (2 * hz));
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, saved_scbptr);
|
|
|
|
unpause_sequencer(ahc, /*unpause_always*/FALSE);
|
|
|
|
if (!disconnected)
|
|
|
|
/* Go "immediatly" to the bus reset */
|
|
|
|
timeout(ahc_timeout, (caddr_t)scb, hz / 2);
|
1994-12-31 19:31:56 +00:00
|
|
|
}
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
1995-10-26 23:57:18 +00:00
|
|
|
splx(s);
|
1994-11-17 20:22:31 +00:00
|
|
|
}
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
/*
|
|
|
|
* Look through the SCB array of the card and attempt to find the
|
|
|
|
* hardware SCB that corresponds to the passed in SCB. Return
|
|
|
|
* SCB_LIST_NULL if unsuccessful. This routine assumes that the
|
|
|
|
* card is already paused.
|
|
|
|
*/
|
|
|
|
static u_int8_t
|
|
|
|
find_scb(ahc, scb)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
struct scb *scb;
|
|
|
|
{
|
|
|
|
u_int8_t saved_scbptr;
|
|
|
|
u_int8_t curindex;
|
|
|
|
|
|
|
|
saved_scbptr = AHC_INB(ahc, SCBPTR);
|
|
|
|
curindex = 0;
|
|
|
|
for (curindex = 0; curindex < ahc->maxhscbs; curindex++) {
|
|
|
|
AHC_OUTB(ahc, SCBPTR, curindex);
|
|
|
|
if (AHC_INB(ahc, SCB_TAG) == scb->hscb->tag)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
AHC_OUTB(ahc, SCBPTR, saved_scbptr);
|
|
|
|
if (curindex > ahc->maxhscbs)
|
|
|
|
curindex = SCB_LIST_NULL;
|
|
|
|
|
|
|
|
return curindex;
|
|
|
|
}
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The device at the given target/channel has been reset. Abort
|
|
|
|
* all active and queued scbs for that target/channel.
|
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static int
|
1996-01-03 06:32:12 +00:00
|
|
|
ahc_reset_device(ahc, target, channel, timedout_scb, xs_error)
|
1995-07-31 08:25:36 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
int target;
|
|
|
|
char channel;
|
1996-10-25 06:42:53 +00:00
|
|
|
struct scb *timedout_scb;
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
u_int32_t xs_error;
|
1995-07-31 08:25:36 +00:00
|
|
|
{
|
|
|
|
struct scb *scbp;
|
|
|
|
u_char active_scb;
|
|
|
|
int i = 0;
|
|
|
|
int found = 0;
|
|
|
|
|
|
|
|
/* restore this when we're done */
|
1996-05-30 07:19:59 +00:00
|
|
|
active_scb = AHC_INB(ahc, SCBPTR);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Search the QINFIFO.
|
|
|
|
*/
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t saved_queue[AHC_SCB_MAX];
|
|
|
|
u_int8_t queued = AHC_INB(ahc, QINCNT) & ahc->qcntmask;
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
for (i = 0; i < (queued - found); i++) {
|
1996-05-30 07:19:59 +00:00
|
|
|
saved_queue[i] = AHC_INB(ahc, QINFIFO);
|
1996-10-25 06:42:53 +00:00
|
|
|
scbp = ahc->scbarray[saved_queue[i]];
|
|
|
|
if (ahc_match_scb (scbp, target, channel)) {
|
1995-07-31 08:25:36 +00:00
|
|
|
/*
|
|
|
|
* We found an scb that needs to be aborted.
|
|
|
|
*/
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
|
1995-07-31 08:25:36 +00:00
|
|
|
scbp->xs->error |= xs_error;
|
1996-10-25 06:42:53 +00:00
|
|
|
if(scbp != timedout_scb)
|
1995-07-31 08:25:36 +00:00
|
|
|
untimeout(ahc_timeout, (caddr_t)scbp);
|
|
|
|
i--;
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Now put the saved scbs back. */
|
|
|
|
for (queued = 0; queued < i; queued++) {
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, QINFIFO, saved_queue[queued]);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Search waiting for selection list.
|
|
|
|
*/
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t next, prev;
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-05-30 07:19:59 +00:00
|
|
|
next = AHC_INB(ahc, WAITING_SCBH); /* Start at head of list. */
|
1995-07-31 08:25:36 +00:00
|
|
|
prev = SCB_LIST_NULL;
|
|
|
|
|
|
|
|
while (next != SCB_LIST_NULL) {
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, next);
|
|
|
|
scbp = ahc->scbarray[AHC_INB(ahc, SCB_TAG)];
|
1995-07-31 08:25:36 +00:00
|
|
|
if (ahc_match_scb(scbp, target, channel)) {
|
1996-10-25 06:42:53 +00:00
|
|
|
next = ahc_abort_wscb(ahc, scbp, next, prev,
|
|
|
|
timedout_scb, xs_error);
|
1995-07-31 08:25:36 +00:00
|
|
|
found++;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1995-07-31 08:25:36 +00:00
|
|
|
prev = next;
|
1996-05-30 07:19:59 +00:00
|
|
|
next = AHC_INB(ahc, SCB_NEXT);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Go through the entire SCB array now and look for
|
|
|
|
* commands for this target that are active. These
|
|
|
|
* are other (most likely tagged) commands that
|
|
|
|
* were disconnected when the reset occured.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
for (i = 0; i < ahc->numscbs; i++) {
|
1995-07-31 08:25:36 +00:00
|
|
|
scbp = ahc->scbarray[i];
|
1996-10-25 06:42:53 +00:00
|
|
|
if ((scbp->flags & SCB_ACTIVE)
|
1995-07-31 08:25:36 +00:00
|
|
|
&& ahc_match_scb(scbp, target, channel)) {
|
|
|
|
/* Ensure the target is "free" */
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_unbusy_target(ahc, target, channel);
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
|
1995-07-31 08:25:36 +00:00
|
|
|
scbp->xs->error |= xs_error;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scbp != timedout_scb)
|
1995-07-31 08:25:36 +00:00
|
|
|
untimeout(ahc_timeout, (caddr_t)scbp);
|
|
|
|
found++;
|
|
|
|
}
|
|
|
|
}
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, active_scb);
|
1995-07-31 08:25:36 +00:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Manipulate the waiting for selection list and return the
|
|
|
|
* scb that follows the one that we remove.
|
|
|
|
*/
|
1995-10-31 18:41:49 +00:00
|
|
|
static u_char
|
1996-10-25 06:42:53 +00:00
|
|
|
ahc_abort_wscb (ahc, scbp, scbpos, prev, timedout_scb, xs_error)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
struct scb *scbp;
|
|
|
|
u_int8_t scbpos;
|
|
|
|
u_int8_t prev;
|
|
|
|
struct scb *timedout_scb;
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
u_int32_t xs_error;
|
1995-07-31 08:25:36 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t curscb, next;
|
|
|
|
int target = ((scbp->hscb->tcl >> 4) & 0x0f);
|
|
|
|
char channel = (scbp->hscb->tcl & SELBUSB) ? 'B' : 'A';
|
1995-07-31 08:25:36 +00:00
|
|
|
/*
|
|
|
|
* Select the SCB we want to abort and
|
|
|
|
* pull the next pointer out of it.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
curscb = AHC_INB(ahc, SCBPTR);
|
|
|
|
AHC_OUTB(ahc, SCBPTR, scbpos);
|
1996-05-30 07:19:59 +00:00
|
|
|
next = AHC_INB(ahc, SCB_NEXT);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
/* Clear the necessary fields */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCB_CONTROL, 0);
|
|
|
|
AHC_OUTB(ahc, SCB_NEXT, SCB_LIST_NULL);
|
|
|
|
ahc_unbusy_target(ahc, target, channel);
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
/* update the waiting list */
|
1996-10-25 06:42:53 +00:00
|
|
|
if (prev == SCB_LIST_NULL)
|
1995-07-31 08:25:36 +00:00
|
|
|
/* First in the list */
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, WAITING_SCBH, next);
|
1995-07-31 08:25:36 +00:00
|
|
|
else {
|
|
|
|
/*
|
|
|
|
* Select the scb that pointed to us
|
|
|
|
* and update its next pointer.
|
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, prev);
|
|
|
|
AHC_OUTB(ahc, SCB_NEXT, next);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* Point us back at the original scb position
|
|
|
|
* and inform the SCSI system that the command
|
|
|
|
* has been aborted.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
AHC_OUTB(ahc, SCBPTR, curscb);
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
scbp->flags = SCB_ABORTED|SCB_QUEUED_FOR_DONE;
|
1995-07-31 08:25:36 +00:00
|
|
|
scbp->xs->error |= xs_error;
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scbp != timedout_scb)
|
1995-07-31 08:25:36 +00:00
|
|
|
untimeout(ahc_timeout, (caddr_t)scbp);
|
|
|
|
return next;
|
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_unbusy_target(ahc, target, channel)
|
1996-10-25 06:42:53 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
int target;
|
|
|
|
char channel;
|
1995-07-31 08:25:36 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t active_scb;
|
|
|
|
u_int8_t info_scb;
|
|
|
|
u_int32_t scb_offset;
|
1996-05-30 07:19:59 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
info_scb = target / 4;
|
|
|
|
if (channel == 'B')
|
|
|
|
info_scb += 2;
|
|
|
|
active_scb = AHC_INB(ahc, SCBPTR);
|
|
|
|
AHC_OUTB(ahc, SCBPTR, info_scb);
|
|
|
|
scb_offset = SCB_ACTIVE0 + (target & 0x03);
|
|
|
|
AHC_OUTB(ahc, scb_offset, SCB_LIST_NULL);
|
|
|
|
AHC_OUTB(ahc, SCBPTR, active_scb);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static void
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_reset_current_bus(ahc)
|
|
|
|
struct ahc_data *ahc;
|
1995-07-31 08:25:36 +00:00
|
|
|
{
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSISEQ, SCSIRSTO);
|
1995-07-31 08:25:36 +00:00
|
|
|
DELAY(1000);
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SCSISEQ, 0);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static int
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc_reset_channel(ahc, channel, timedout_scb, xs_error, initiate_reset)
|
1996-10-25 06:42:53 +00:00
|
|
|
struct ahc_data *ahc;
|
|
|
|
char channel;
|
|
|
|
struct scb *timedout_scb;
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
u_int32_t xs_error;
|
1996-10-25 06:42:53 +00:00
|
|
|
int initiate_reset;
|
1995-07-31 08:25:36 +00:00
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t sblkctl;
|
1995-07-31 08:25:36 +00:00
|
|
|
char cur_channel;
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int32_t offset, offset_max;
|
1995-07-31 08:25:36 +00:00
|
|
|
int found;
|
1996-10-25 06:42:53 +00:00
|
|
|
int target;
|
|
|
|
int maxtarget;
|
1995-07-31 08:25:36 +00:00
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
maxtarget = 8;
|
1995-07-31 08:25:36 +00:00
|
|
|
/*
|
|
|
|
* Clean up all the state information for the
|
|
|
|
* pending transactions on this bus.
|
|
|
|
*/
|
1996-01-03 06:32:12 +00:00
|
|
|
found = ahc_reset_device(ahc, ALL_TARGETS, channel,
|
1995-07-31 08:25:36 +00:00
|
|
|
timedout_scb, xs_error);
|
1996-10-25 06:42:53 +00:00
|
|
|
if (channel == 'B') {
|
1995-07-31 08:25:36 +00:00
|
|
|
ahc->needsdtr |= (ahc->needsdtr_orig & 0xff00);
|
|
|
|
ahc->sdtrpending &= 0x00ff;
|
1996-05-30 07:19:59 +00:00
|
|
|
offset = TARG_SCRATCH + 8;
|
|
|
|
offset_max = TARG_SCRATCH + 16;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else if (ahc->type & AHC_WIDE){
|
1995-07-31 08:25:36 +00:00
|
|
|
ahc->needsdtr = ahc->needsdtr_orig;
|
|
|
|
ahc->needwdtr = ahc->needwdtr_orig;
|
|
|
|
ahc->sdtrpending = 0;
|
|
|
|
ahc->wdtrpending = 0;
|
1996-10-25 06:42:53 +00:00
|
|
|
maxtarget = 16;
|
1996-05-30 07:19:59 +00:00
|
|
|
offset = TARG_SCRATCH;
|
|
|
|
offset_max = TARG_SCRATCH + 16;
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
1995-07-31 08:25:36 +00:00
|
|
|
ahc->needsdtr |= (ahc->needsdtr_orig & 0x00ff);
|
|
|
|
ahc->sdtrpending &= 0xff00;
|
1996-05-30 07:19:59 +00:00
|
|
|
offset = TARG_SCRATCH;
|
|
|
|
offset_max = TARG_SCRATCH + 8;
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
for (target = 0; target < maxtarget; target++)
|
|
|
|
ahc_unbusy_target(ahc, target, channel);
|
|
|
|
|
|
|
|
for (; offset < offset_max; offset++) {
|
1995-07-31 08:25:36 +00:00
|
|
|
/*
|
|
|
|
* Revert to async/narrow transfers
|
|
|
|
* until we renegotiate.
|
|
|
|
*/
|
1996-10-25 06:42:53 +00:00
|
|
|
u_int8_t targ_scratch;
|
1996-05-30 07:19:59 +00:00
|
|
|
|
|
|
|
targ_scratch = AHC_INB(ahc, offset);
|
1995-07-31 08:25:36 +00:00
|
|
|
targ_scratch &= SXFR;
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, offset, targ_scratch);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
* Reset the bus if we are initiating this reset and
|
|
|
|
* restart/unpause the sequencer
|
1995-07-31 08:25:36 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
sblkctl = AHC_INB(ahc, SBLKCTL);
|
1995-07-31 08:25:36 +00:00
|
|
|
cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
|
1996-10-25 06:42:53 +00:00
|
|
|
if (cur_channel != channel) {
|
|
|
|
/* Case 1: Command for another bus is active
|
|
|
|
* Stealthily reset the other bus without
|
|
|
|
* upsetting the current bus.
|
1995-07-31 08:25:36 +00:00
|
|
|
*/
|
1996-05-30 07:19:59 +00:00
|
|
|
AHC_OUTB(ahc, SBLKCTL, sblkctl ^ SELBUSB);
|
1996-10-25 06:42:53 +00:00
|
|
|
if (initiate_reset)
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_reset_current_bus(ahc);
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
|
|
|
AHC_OUTB(ahc, SBLKCTL, sblkctl);
|
1996-10-06 16:38:45 +00:00
|
|
|
unpause_sequencer(ahc, /*unpause_always*/TRUE);
|
1996-10-25 06:42:53 +00:00
|
|
|
} else {
|
|
|
|
/* Case 2: A command from this bus is active or we're idle */
|
|
|
|
if (initiate_reset)
|
1996-05-30 07:19:59 +00:00
|
|
|
ahc_reset_current_bus(ahc);
|
|
|
|
AHC_OUTB(ahc, CLRSINT1, CLRSCSIRSTI|CLRSELTIMEO);
|
|
|
|
AHC_OUTB(ahc, CLRINT, CLRSCSIINT);
|
1996-10-06 16:38:45 +00:00
|
|
|
restart_sequencer(ahc);
|
1995-07-31 08:25:36 +00:00
|
|
|
}
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc_run_done_queue(ahc);
|
1995-07-31 08:25:36 +00:00
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
void
|
|
|
|
ahc_run_done_queue(ahc)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
struct scb *scbp;
|
|
|
|
|
1996-10-25 06:42:53 +00:00
|
|
|
for (i = 0; i < ahc->numscbs; i++) {
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
scbp = ahc->scbarray[i];
|
1996-10-25 06:42:53 +00:00
|
|
|
if (scbp->flags & SCB_QUEUED_FOR_DONE)
|
bt.c, aic7xxx.c:
Cleanse the SCSI subsystem of its internally defined types
u_int32, u_int16, u_int8, int32, int16, int8.
Use the system defined *_t types instead.
aic7xxx.c:
Fix the reset code.
Instead of queing up all of the SCBs that timeout during timeout
processing, we take the first and have it champion the effort.
Any other scbs that timeout during timeout handling are given
another lifetime to complete in the hopes that once timeout
handing is finished, they will complete normally. If one of
these SCBs times out a second time, we panic and Justin tries
again.
The other major change is to queue flag aborted SCBs during timeout
handling, and "ahc_done" them all at once as soon as we have the
controller back into a sane state. Calling ahc_done any earlier
will cause the SCSI subsystem to toss the command right back at
us and the attempt to queue the command will conflict with what
the timeout routine is trying to accomplish.
The aic7xxx driver will now respond to bus resets initiated by
other devices.
1996-03-10 07:11:45 +00:00
|
|
|
ahc_done(ahc, scbp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1995-10-31 18:41:49 +00:00
|
|
|
static int
|
1995-07-31 08:25:36 +00:00
|
|
|
ahc_match_scb (scb, target, channel)
|
|
|
|
struct scb *scb;
|
|
|
|
int target;
|
|
|
|
char channel;
|
|
|
|
{
|
1996-10-25 06:42:53 +00:00
|
|
|
int targ = (scb->hscb->tcl >> 4) & 0x0f;
|
|
|
|
char chan = (scb->hscb->tcl & SELBUSB) ? 'B' : 'A';
|
1995-07-31 08:25:36 +00:00
|
|
|
|
|
|
|
if (target == ALL_TARGETS)
|
|
|
|
return (chan == channel);
|
|
|
|
else
|
|
|
|
return ((chan == channel) && (targ == target));
|
|
|
|
}
|
1996-10-06 16:38:45 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
ahc_construct_sdtr(ahc, start_byte, period, offset)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
int start_byte;
|
|
|
|
u_int8_t period;
|
|
|
|
u_int8_t offset;
|
|
|
|
{
|
|
|
|
AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
|
|
|
|
AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_SDTR_LEN);
|
|
|
|
AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_SDTR);
|
|
|
|
AHC_OUTB(ahc, MSG3 + start_byte, period);
|
|
|
|
AHC_OUTB(ahc, MSG4 + start_byte, offset);
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, start_byte + 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
ahc_construct_wdtr(ahc, start_byte, bus_width)
|
|
|
|
struct ahc_data *ahc;
|
|
|
|
int start_byte;
|
|
|
|
u_int8_t bus_width;
|
|
|
|
{
|
|
|
|
AHC_OUTB(ahc, MSG0 + start_byte, MSG_EXTENDED);
|
|
|
|
AHC_OUTB(ahc, MSG1 + start_byte, MSG_EXT_WDTR_LEN);
|
|
|
|
AHC_OUTB(ahc, MSG2 + start_byte, MSG_EXT_WDTR);
|
|
|
|
AHC_OUTB(ahc, MSG3 + start_byte, bus_width);
|
|
|
|
AHC_OUTB(ahc, MSG_LEN, start_byte + 4);
|
|
|
|
}
|
1996-10-25 06:42:53 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
ahc_calc_residual(scb)
|
|
|
|
struct scb *scb;
|
|
|
|
{
|
|
|
|
struct scsi_xfer *xs;
|
|
|
|
struct hardware_scb *hscb;
|
|
|
|
int resid_sgs;
|
|
|
|
|
|
|
|
xs = scb->xs;
|
|
|
|
hscb = scb->hscb;
|
|
|
|
|
|
|
|
if ((scb->flags & SCB_SENSE) == 0) {
|
|
|
|
/*
|
|
|
|
* Remainder of the SG where the transfer
|
|
|
|
* stopped.
|
|
|
|
*/
|
|
|
|
xs->resid = (hscb->residual_data_count[2] <<16) |
|
|
|
|
(hscb->residual_data_count[1] <<8) |
|
|
|
|
(hscb->residual_data_count[0]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add up the contents of all residual
|
|
|
|
* SG segments that are after the SG where
|
|
|
|
* the transfer stopped.
|
|
|
|
*/
|
|
|
|
resid_sgs = hscb->residual_SG_segment_count - 1;
|
|
|
|
while (resid_sgs > 0) {
|
|
|
|
int sg;
|
|
|
|
|
|
|
|
sg = hscb->SG_segment_count - resid_sgs;
|
|
|
|
xs->resid += scb->ahc_dma[sg].len;
|
|
|
|
resid_sgs--;
|
|
|
|
}
|
|
|
|
#if defined(__FreeBSD__)
|
|
|
|
xs->flags |= SCSI_RESID_VALID;
|
|
|
|
#elif defined(__NetBSD__)
|
|
|
|
/* XXX - Update to do this right */
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Clean out the residual information in this SCB for the
|
|
|
|
* next consumer of this SCB.
|
|
|
|
*/
|
|
|
|
hscb->residual_data_count[2] = 0;
|
|
|
|
hscb->residual_data_count[1] = 0;
|
|
|
|
hscb->residual_data_count[0] = 0;
|
|
|
|
hscb->residual_SG_segment_count = 0;
|
|
|
|
|
|
|
|
#ifdef AHC_DEBUG
|
|
|
|
if (ahc_debug & AHC_SHOWMISC) {
|
|
|
|
sc_print_addr(xs->sc_link);
|
|
|
|
printf("Handled Residual of %ld bytes\n" ,xs->resid);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|