* Written by Julian Elischer (julian@tfs.com)
* for TRW Financial Systems for use under the MACH(2.5) operating system.
* TRW Financial Systems, in accordance with their agreement with Carnegie
* Mellon University, makes this software available to CMU to distribute
* or use in any manner that they see fit as long as this message is kept with
* the software. For this reason TFS also grants any other persons or
* organisations permission to use or modify this software.
* TFS supplies this software to be publicly redistributed
* on the understanding that TFS is not responsible for the correct
* functioning of this software in any circumstances.
* commenced: Sun Sep 27 18:14:01 PDT 1992
* $Id: aha1742.c,v 1.9 1993/08/28 03:07:40 rgrimes Exp $
#ifdef MACH /* EITHER CMU OR OSF */
#include <i386at/scsiconf.h>
#ifdef OSF /* OSF ONLY */
#include <i386/handler.h>
#include <i386/dispatcher.h>
#include <i386/AT386/atbus.h>
#include <i386at/atbus.h>
#endif MACH /* end of MACH specific */
#ifdef __386BSD__ /* 386BSD specific */
#define isa_dev isa_device
#define dev_addr id_iobase
#include <i386/include/pio.h>
#include <i386/isa/isa_device.h>
#include <scsi/scsi_all.h>
#include <scsi/scsiconf.h>
#define Debugger() panic("should call debugger here (adaptec.c)")
typedef unsigned long int physaddr
;
extern physaddr
kvtophys();
#define PHYSTOKV(x) phystokv(x)
#define KVTOPHYS(x) kvtophys(x)
#define KVTOPHYS(x) vtophys(x)
extern int delaycount
; /* from clock setup code */
#define NUM_CONCURRENT 16 /* number of concurrent ops per board */
#define AHB_NSEG 33 /* number of dma segments supported */
#define FUDGE(X) (X>>1) /* our loops are slower than spinwait() */
/***********************************************************************\
* AHA1740 standard EISA Host ID regs (Offset from slot base) *
\***********************************************************************/
#define HID0 0xC80 /* 0,1: msb of ID2, 3-7: ID1 */
#define HID1 0xC81 /* 0-4: ID3, 4-7: LSB ID2 */
#define HID2 0xC82 /* product, 0=174[20] 1 = 1744 */
#define HID3 0xC83 /* firmware revision */
#define CHAR1(B1,B2) (((B1>>2) & 0x1F) | '@')
#define CHAR2(B1,B2) (((B1<<3) & 0x18) | ((B2>>5) & 0x7)|'@')
#define CHAR3(B1,B2) ((B2 & 0x1F) | '@')
/* AHA1740 EISA board control registers (Offset from slot base) */
/***********************************************************************\
* AHA1740 EISA board mode registers (Offset from slot base) *
\***********************************************************************/
#define PORTADDR_ENHANCED 0x80
/**** bit definitions for INTDEF ****/
#define INTHIGH 0x08 /* int high=ACTIVE (else edge) */
/**** bit definitions for SCSIDEF ****/
#define HSCSIID 0x0F /* our SCSI ID */
#define RSTPWR 0x10 /* reset scsi bus on power up or reset */
/**** bit definitions for BUSDEF ****/
#define B0uS 0x00 /* give up bus immediatly */
#define B4uS 0x01 /* delay 4uSec. */
/***********************************************************************\
* AHA1740 ENHANCED mode mailbox control regs (Offset from slot base) *
\***********************************************************************/
/*******************************************************\
* Bit definitions for the 5 control/status registers *
\*******************************************************/
#define AHB_TARG_RESET 0x80
#define OP_START_ECB 0x40
#define OP_ABORT_ECB 0x50
#define G2CNTRL_SET_HOST_READY 0x20
#define G2CNTRL_CLEAR_EISA_INT 0x40
#define G2CNTRL_HARD_RESET 0x80
#define G2INTST_TARGET 0x0F
#define G2INTST_INT_STAT 0xF0
#define AHB_ECB_RECOVERED 0x50
#define AHB_IMMED_OK 0xA0
#define AHB_ASN 0xD0 /* for target mode */
#define AHB_IMMED_ERR 0xE0
#define G2STAT_INT_PEND 0x02
#define G2STAT_MBOX_EMPTY 0x04
#define G2STAT2_HOST_READY 0x01
# define HS_CMD_ABORTED_HOST 0x04
# define HS_CMD_ABORTED_ADAPTER 0x05
# define HS_TIMED_OUT 0x11
# define HS_HARDWARE_ERR 0x20
# define HS_SCSI_RESET_ADAPTER 0x22
# define HS_SCSI_RESET_INCOMING 0x23
# define TS_CHECK_CONDITION 0x02
# define ECB_SCSI_OP 0x01
/*-----------------end of hardware supported fields----------------*/
struct ecb
*next
; /* in free list */
struct scsi_xfer
*xs
; /* the scsi_xfer for this cmd */
struct ahb_dma_seg ahb_dma
[AHB_NSEG
];
struct ahb_ecb_status ecb_status
;
struct scsi_sense_data ecb_sense
;
struct ecb ecbs
[NUM_CONCURRENT
];
int our_id
; /* our scsi id */
struct ecb
*immed_ecb
; /* an outstanding immediete command */
long int ahb_adapter_info();
struct isa_driver ahbdriver
= { ahbprobe
, 0, ahb_attach
, "ahb", 0, 0, 0};
int (*ahbintrs
[])() = {ahbintr
, 0};
struct isa_driver ahbdriver
= { ahbprobe
, ahb_attach
, "ahb"};
static ahb_slot
= 0; /* slot last board was found in */
#define AHB_SHOWECBS 0x01
#define AHB_SHOWINTS 0x02
#define AHB_SHOWCMDS 0x04
#define AHB_SHOWMISC 0x08
struct scsi_switch ahb_switch
=
/***********************************************************************\
* Function to send a command out through a mailbox *
\***********************************************************************/
int port
= ahb_data
[unit
].baseport
;
int spincount
= FUDGE(delaycount
) * 1; /* 1ms should be enough */
int stport
= port
+ G2STAT
;
while( ((inb(stport
) & (G2STAT_BUSY
| G2STAT_MBOX_EMPTY
))
printf("ahb%d: board not responding\n",unit
);
outl(port
+ MBOXOUT0
,KVTOPHYS(ecb
)); /* don't know this will work */
outb(port
+ ATTN
, opcode
|target
);
/***********************************************************************\
* Function to poll for command completion when in poll mode *
\***********************************************************************/
ahb_poll(int unit
,int wait
) /* in msec */
int port
= ahb_data
[unit
].baseport
;
int spincount
= FUDGE(delaycount
) * wait
; /* in msec */
int stport
= port
+ G2STAT
;
while( (spincount
--) && (!(inb(stport
) & G2STAT_INT_PEND
)));
printf("ahb%d: board not responding\n",unit
);
if ((int)cheat
!= PHYSTOKV(inl(port
+ MBOXIN0
)))
printf("discarding %x ",inl(port
+ MBOXIN0
));
outb(port
+ G2CNTRL
, G2CNTRL_CLEAR_EISA_INT
);
}/* don't know this will work */
/***********************************************************************\
* Function to send an immediate type command to the adapter *
\***********************************************************************/
int port
= ahb_data
[unit
].baseport
;
int spincount
= FUDGE(delaycount
) * 1; /* 1ms should be enough */
int stport
= port
+ G2STAT
;
while( ((inb(stport
) & (G2STAT_BUSY
| G2STAT_MBOX_EMPTY
))
printf("ahb%d: board not responding\n",unit
);
outl(port
+ MBOXOUT0
,cmd
); /* don't know this will work */
outb(port
+ G2CNTRL
, G2CNTRL_SET_HOST_READY
);
outb(port
+ ATTN
, OP_IMMED
| target
);
/*******************************************************\
* Check the slots looking for a board we recognise *
* If we find one, note it's address (slot) and call *
* the actual probe routine to check it out. *
\*******************************************************/
u_char byte1
,byte2
,byte3
;
port
= 0x1000 * ahb_slot
;
byte1
= inb(port
+ HID0
);
byte2
= inb(port
+ HID1
);
byte3
= inb(port
+ HID2
);
if ((CHAR1(byte1
,byte2
) == 'A')
&& (CHAR2(byte1
,byte2
) == 'D')
&& (CHAR3(byte1
,byte2
) == 'P')
&& ((byte3
== 0 ) || (byte3
== 1)))
/*******************************************************\
* Check if the device can be found at the port given *
* and if so, set it up ready for further work *
* as an argument, takes the isa_dev structure from *
\*******************************************************/
/***********************************************\
* find unit and check we have that many defined *
\***********************************************/
static ihandler_t ahb_handler
[NAHB
];
static ihandler_id_t
*ahb_handler_id
[NAHB
];
register ihandler_t
*chp
= &ahb_handler
[unit
];;
#endif /* defined(OSF) */
ahb_data
[unit
].baseport
= dev
->dev_addr
;
printf("ahb: unit number (%d) too high\n",unit
);
/***********************************************\
* Try initialise a unit at this location *
* sets up dma and bus speed, loads ahb_data[unit].vect*
\***********************************************/
/***********************************************\
* If it's there, put in it's interrupt vectors *
\***********************************************/
dev
->dev_pic
= ahb_data
[unit
].vect
;
#if defined(OSF) /* OSF */
chp
->ih_level
= dev
->dev_pic
;
chp
->ih_handler
= dev
->dev_intr
[0];
chp
->ih_resolver
= i386_resolver
;
chp
->ih_stats
.intr_type
= INTR_DEVICE
;
chp
->ih_stats
.intr_cnt
= 0;
chp
->ih_hparam
[0].intparam
= unit
;
if ((ahb_handler_id
[unit
] = handler_add(chp
)) != NULL
)
handler_enable(ahb_handler_id
[unit
]);
panic("Unable to add ahb interrupt handler");
#endif /* !defined(OSF) */
printf("port=%x spl=%d\n", dev
->dev_addr
, dev
->dev_spl
);
#ifdef __386BSD__ /* 386BSD */
dev
->id_irq
= (1 << ahb_data
[unit
].vect
);
dev
->id_drq
= -1; /* use EISA dma */
/***********************************************\
* Attach all the sub-devices we can find *
\***********************************************/
int unit
= dev
->dev_unit
;
/***********************************************\
* ask the adapter what subunits are present *
\***********************************************/
scsi_attachdevs( unit
, ahb_data
[unit
].our_id
, &ahb_switch
);
#endif /* defined(OSF) */
/***********************************************\
* Return some information to the caller about *
* the adapter and it's capabilities *
\***********************************************/
long int ahb_adapter_info(unit
)
return(2); /* 2 outstanding requests at a time per device */
/***********************************************\
* Catch an interrupt from the adaptor *
\***********************************************/
int port
= ahb_data
[unit
].baseport
;
if(scsi_debug
& PRINTROUTINES
)
#endif /* defined(OSF) */
while(inb(port
+ G2STAT
) & G2STAT_INT_PEND
)
/***********************************************\
* First get all the information and then *
* acknowlege the interrupt *
\***********************************************/
ahbstat
= inb(port
+ G2INTST
);
target
= ahbstat
& G2INTST_TARGET
;
stat
= ahbstat
& G2INTST_INT_STAT
;
mboxval
= inl(port
+ MBOXIN0
);/* don't know this will work */
outb(port
+ G2CNTRL
, G2CNTRL_CLEAR_EISA_INT
);
if(scsi_debug
& TRACEINTERRUPTS
)
printf("status = 0x%x ",stat
);
/***********************************************\
* Process the completed operation *
\***********************************************/
if(stat
== AHB_ECB_OK
) /* common case is fast */
ecb
= (struct ecb
*)PHYSTOKV(mboxval
);
ecb
= ahb_data
[unit
].immed_ecb
;
ahb_data
[unit
].immed_ecb
= 0;
ecb
= ahb_data
[unit
].immed_ecb
;
ecb
->flags
|= ECB_IMMED_FAIL
;
ahb_data
[unit
].immed_ecb
= 0;
case AHB_ASN
: /* for target mode */
printf("ahb%d: Unexpected ASN interrupt(%x)\n",
printf("ahb%d: Hardware error interrupt(%x)\n",
ecb
= (struct ecb
*)PHYSTOKV(mboxval
);
ecb
= (struct ecb
*)PHYSTOKV(mboxval
);
printf(" Unknown return from ahb%d(%x)\n",unit
,ahbstat
);
if(ahb_debug
& AHB_SHOWCMDS
)
ahb_show_scsi_cmd(ecb
->xs
);
if((ahb_debug
& AHB_SHOWECBS
) && ecb
)
printf("<int ecb(%x)>",ecb
);
untimeout(ahb_timeout
,ecb
);
ahb_done(unit
,ecb
,((stat
== AHB_ECB_OK
)?SUCCESS
:FAIL
));
/***********************************************\
* We have a ecb which has been processed by the *
* adaptor, now we look to see how the operation *
\***********************************************/
struct ahb_ecb_status
*stat
= &ecb
->ecb_status
;
struct scsi_sense_data
*s1
,*s2
;
struct scsi_xfer
*xs
= ecb
->xs
;
if(scsi_debug
& (PRINTROUTINES
| TRACEINTERRUPTS
))
/***********************************************\
* Otherwise, put the results of the operation *
* into the xfer and call whoever started it *
\***********************************************/
if(ecb
->flags
& ECB_IMMED
)
if(ecb
->flags
& ECB_IMMED_FAIL
)
xs
->error
= XS_DRIVER_STUFFUP
;
if ( (state
== SUCCESS
) || (xs
->flags
& SCSI_ERR_OK
))
{ /* All went correctly OR errors expected */
case HS_SCSI_RESET_ADAPTER
:
case HS_SCSI_RESET_INCOMING
:
case HS_CMD_ABORTED_HOST
: /* No response */
case HS_CMD_ABORTED_ADAPTER
: /* No response */
case HS_TIMED_OUT
: /* No response */
if (ahb_debug
& AHB_SHOWMISC
)
printf("timeout reported back\n");
default: /* Other scsi protocol messes */
xs
->error
= XS_DRIVER_STUFFUP
;
if (ahb_debug
& AHB_SHOWMISC
)
printf("unexpected ha_status: %x\n",
switch(stat
->targ_status
)
if (ahb_debug
& AHB_SHOWMISC
)
printf("unexpected targ_status: %x\n",
xs
->error
= XS_DRIVER_STUFFUP
;
done
: xs
->flags
|= ITSDONE
;
ahb_free_ecb(unit
,ecb
, xs
->flags
);
(*(xs
->when_done
))(xs
->done_arg
,xs
->done_arg2
);
/***********************************************\
* A ecb (and hence a mbx-out is put onto the *
\***********************************************/
ahb_free_ecb(unit
,ecb
, flags
)
if(scsi_debug
& PRINTROUTINES
)
printf("ecb%d(0x%x)> ",unit
,flags
);
if (!(flags
& SCSI_NOMASK
))
ecb
->next
= ahb_data
[unit
].free_ecb
;
ahb_data
[unit
].free_ecb
= ecb
;
/***********************************************\
* If there were none, wake abybody waiting for *
* one to come free, starting with queued entries*
\***********************************************/
wakeup(&ahb_data
[unit
].free_ecb
);
if (!(flags
& SCSI_NOMASK
))
/***********************************************\
* Get a free ecb (and hence mbox-out entry) *
\***********************************************/
if(scsi_debug
& PRINTROUTINES
)
printf("<ecb%d(0x%x) ",unit
,flags
);
if (!(flags
& SCSI_NOMASK
))
/***********************************************\
* If we can and have to, sleep waiting for one *
\***********************************************/
while ((!(rc
= ahb_data
[unit
].free_ecb
)) && (!(flags
& SCSI_NOSLEEP
)))
sleep(&ahb_data
[unit
].free_ecb
, PRIBIO
);
ahb_data
[unit
].free_ecb
= rc
->next
;
if (!(flags
& SCSI_NOMASK
))
/***********************************************\
* Start the board, ready for normal operation *
\***********************************************/
int port
= ahb_data
[unit
].baseport
;
int spincount
= FUDGE(delaycount
) * 1000; /* 1 sec enough? */
int stport
= port
+ G2STAT
;
/***********************************************\
* reset board, If it doesn't respond, assume *
* that it's not there.. good for the probe *
\***********************************************/
outb(port
+ EBCTRL
,CDEN
); /* enable full card */
outb(port
+ PORTADDR
,PORTADDR_ENHANCED
);
outb(port
+ G2CNTRL
,G2CNTRL_HARD_RESET
);
while( ((inb(stport
) & G2STAT_BUSY
))
if (ahb_debug
& AHB_SHOWMISC
)
printf("ahb_init: No answer from bt742a board\n");
i
= inb(port
+ MBOXIN0
) & 0xff;
printf("self test failed, val = 0x%x\n",i
);
while( inb(stport
) & G2STAT_INT_PEND
)
outb(port
+ G2CNTRL
, G2CNTRL_CLEAR_EISA_INT
);
outb(port
+ EBCTRL
,CDEN
); /* enable full card */
outb(port
+ PORTADDR
,PORTADDR_ENHANCED
);
/***********************************************\
* Assume we have a board at this stage *
* setup dma channel from jumpers and save int *
\***********************************************/
printf("ahb%d: reading board settings, ",unit
);
intdef
= inb(port
+ INTDEF
);
ahb_data
[unit
].vect
= 10;
ahb_data
[unit
].vect
= 11;
ahb_data
[unit
].vect
= 12;
ahb_data
[unit
].vect
= 14;
ahb_data
[unit
].vect
= 15;
printf("illegal int setting\n");
printf("int=%d\n",ahb_data
[unit
].vect
);
printf("int=%d ",ahb_data
[unit
].vect
);
outb(port
+ INTDEF
,(intdef
| INTEN
)); /* make sure we can interrupt */
/* who are we on the scsi bus */
ahb_data
[unit
].our_id
= (inb(port
+ SCSIDEF
) & HSCSIID
);
/***********************************************\
* link up all our ECBs into a free list *
\***********************************************/
for (i
=0; i
< NUM_CONCURRENT
; i
++)
ahb_data
[unit
].ecbs
[i
].next
= ahb_data
[unit
].free_ecb
;
ahb_data
[unit
].free_ecb
= &ahb_data
[unit
].ecbs
[i
];
ahb_data
[unit
].free_ecb
->flags
= ECB_FREE
;
/***********************************************\
* Note that we are going and return (to probe) *
\***********************************************/
ahb_data
[unit
].flags
|= AHB_INIT
;
#define min(x,y) (x < y ? x : y)
bp
->b_flags
|= B_NPAGES
; /* can support scat/gather */
#endif /* defined(OSF) */
if(bp
->b_bcount
> ((AHB_NSEG
-1) * PAGESIZ
))
bp
->b_bcount
= ((AHB_NSEG
-1) * PAGESIZ
);
/***********************************************\
* start a scsi operation given the command and *
* the data address. Also needs the unit, target *
\***********************************************/
struct scsi_sense_data
*s1
,*s2
;
int seg
; /* scatter gather seg being worked on */
physaddr thisphys
,nextphys
;
int bytes_this_seg
,bytes_this_page
,datalen
,flags
;
if(scsi_debug
& PRINTROUTINES
)
/***********************************************\
* get a ecb (mbox-out) to use. If the transfer *
* is from a buf (possibly from interrupt time) *
* then we can't allow it to sleep *
\***********************************************/
if(xs
->bp
) flags
|= (SCSI_NOSLEEP
); /* just to be sure */
printf("ahb%d: Already done?",unit
);
printf("ahb%d: Not in use?",unit
);
if (!(ecb
= ahb_get_ecb(unit
,flags
)))
xs
->error
= XS_DRIVER_STUFFUP
;
if(ahb_debug
& AHB_SHOWECBS
)
printf("<start ecb(%x)>",ecb
);
if(scsi_debug
& SHOWCOMMANDS
)
/***********************************************\
* If it's a reset, we need to do an 'immediate' *
* command, and store it's ccb for later *
* if there is already an immediate waiting, *
\***********************************************/
if(ahb_data
[unit
].immed_ecb
)
ahb_data
[unit
].immed_ecb
= ecb
;
if (!(flags
& SCSI_NOMASK
))
ahb_send_immed(unit
,xs
->targ
,AHB_TARG_RESET
);
timeout(ahb_timeout
,ecb
,(xs
->timeout
* hz
)/1000);
return(SUCCESSFULLY_QUEUED
);
ahb_send_immed(unit
,xs
->targ
,AHB_TARG_RESET
);
/***********************************************\
* If we can't use interrupts, poll on completion*
\***********************************************/
if(scsi_debug
& TRACEINTERRUPTS
)
if( ahb_poll(unit
,xs
->timeout
))
ahb_free_ecb(unit
,ecb
,flags
);
/***********************************************\
* Put all the arguments for the xfer in the ecb *
\***********************************************/
ecb
->opcode
= ECB_SCSI_OP
;
ecb
->opt1
= ECB_SES
|ECB_DSB
|ECB_ARS
;
ecb
->opt2
= xs
->lu
| ECB_NRB
;
ecb
->cdblen
= xs
->cmdlen
;
ecb
->sense
= KVTOPHYS(&(ecb
->ecb_sense
));
ecb
->senselen
= sizeof(ecb
->ecb_sense
);
ecb
->status
= KVTOPHYS(&(ecb
->ecb_status
));
{ /* should use S/G only if not zero length */
ecb
->data
= KVTOPHYS(ecb
->ahb_dma
);
if(flags
& SCSI_DATA_UIO
)
iovp
= ((struct uio
*)xs
->data
)->uio_iov
;
datalen
= ((struct uio
*)xs
->data
)->uio_iovcnt
;
while ((datalen
) && (seg
< AHB_NSEG
))
sg
->addr
= (physaddr
)iovp
->iov_base
;
xs
->datalen
+= sg
->len
= iovp
->iov_len
;
if(scsi_debug
& SHOWSCATGATH
)
/***********************************************\
* Set up the scatter gather block *
\***********************************************/
if(scsi_debug
& SHOWSCATGATH
)
printf("%d @0x%x:- ",xs
->datalen
,xs
->data
);
thisphys
= KVTOPHYS(thiskv
);
while ((datalen
) && (seg
< AHB_NSEG
))
/* put in the base address */
if(scsi_debug
& SHOWSCATGATH
)
/* do it at least once */
while ((datalen
) && (thisphys
== nextphys
))
/*********************************************\
* This page is contiguous (physically) with *
* the the last, just extend the length *
\*********************************************/
/* how far to the end of the page */
nextphys
= (thisphys
& (~(PAGESIZ
- 1)))
bytes_this_page
= nextphys
- thisphys
;
bytes_this_page
= min(bytes_this_page
bytes_this_seg
+= bytes_this_page
;
datalen
-= bytes_this_page
;
/* get more ready for the next page */
thiskv
= (thiskv
& (~(PAGESIZ
- 1)))
thisphys
= KVTOPHYS(thiskv
);
/********************************************\
* next page isn't contiguous, finish the seg *
\********************************************/
if(scsi_debug
& SHOWSCATGATH
)
printf("(0x%x)",bytes_this_seg
);
sg
->len
= bytes_this_seg
;
} /*end of iov/kv decision */
ecb
->datalen
= seg
* sizeof(struct ahb_dma_seg
);
if(scsi_debug
& SHOWSCATGATH
)
{ /* there's still data, must have run out of segs! */
printf("ahb_scsi_cmd%d: more than %d DMA segs\n",
xs
->error
= XS_DRIVER_STUFFUP
;
ahb_free_ecb(unit
,ecb
,flags
);
{ /* No data xfer, use non S/G values */
ecb
->chain
= (physaddr
)0;
/***********************************************\
* Put the scsi command in the ecb and start it *
\***********************************************/
bcopy(xs
->cmd
, ecb
->cdb
, xs
->cmdlen
);
/***********************************************\
* Usually return SUCCESSFULLY QUEUED *
\***********************************************/
if (!(flags
& SCSI_NOMASK
))
ahb_send_mbox(unit
,OP_START_ECB
,xs
->targ
,ecb
);
timeout(ahb_timeout
,ecb
,(xs
->timeout
* hz
)/1000);
if(scsi_debug
& TRACEINTERRUPTS
)
return(SUCCESSFULLY_QUEUED
);
/***********************************************\
* If we can't use interrupts, poll on completion*
\***********************************************/
ahb_send_mbox(unit
,OP_START_ECB
,xs
->targ
,ecb
);
if(scsi_debug
& TRACEINTERRUPTS
)
if(ahb_poll(unit
,xs
->timeout
))
if (!(xs
->flags
& SCSI_SILENT
)) printf("cmd fail\n");
ahb_send_mbox(unit
,OP_ABORT_ECB
,xs
->targ
,ecb
);
printf("abort failed in wait\n");
ahb_free_ecb(unit
,ecb
,flags
);
xs
->error
= XS_DRIVER_STUFFUP
;
} while (!(xs
->flags
& ITSDONE
));/* something (?) else finished */
ahb_timeout(struct ecb
*ecb
)
printf("ahb%d:%d device timed out\n",unit
if(ahb_debug
& AHB_SHOWECBS
)
ahb_print_active_ecb(unit
);
/***************************************\
* If it's immediate, don't try abort it *
\***************************************/
if(ecb
->flags
& ECB_IMMED
)
ecb
->xs
->retries
= 0; /* I MEAN IT ! */
ecb
->flags
|= ECB_IMMED_FAIL
;
/***************************************\
* If it has been through before, then *
* a previous abort has failed, don't *
\***************************************/
if(ecb
->flags
== ECB_ABORTED
) /* abort timed out */
ecb
->xs
->retries
= 0; /* I MEAN IT ! */
ecb
->ecb_status
.ha_status
= HS_CMD_ABORTED_HOST
;
else /* abort the operation that has timed out */
ahb_send_mbox(unit
,OP_ABORT_ECB
,ecb
->xs
->targ
,ecb
);
/* 2 secs for the abort */
timeout(ahb_timeout
,ecb
,2 * hz
);
ecb
->flags
= ECB_ABORTED
;
ahb_show_scsi_cmd(struct scsi_xfer
*xs
)
u_char
*b
= (u_char
*)xs
->cmd
;
if(!(xs
->flags
& SCSI_RESET
))
printf("ahb%d:%d:%d-RESET-\n"
printf("ecb:%x op:%x cmdlen:%d senlen:%d\n"
printf(" datlen:%d hstat:%x tstat:%x flags:%x\n"
,ecb
->ecb_status
.ha_status
,ecb
->ecb_status
.targ_status
ahb_show_scsi_cmd(ecb
->xs
);
ahb_print_active_ecb(int unit
)
struct ecb
*ecb
= ahb_data
[unit
].ecbs
;
if(ecb
->flags
!= ECB_FREE
)