* 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.14 1994/01/11 07:24:32 rgrimes Exp $
#ifdef KERNEL /* don't laugh, it compiles as a program too.. look */
#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 timeout_func_t timeout_t
;
typedef unsigned long int physaddr
;
#define KVTOPHYS(x) vtophys(x)
#define AHB_ECB_MAX 32 /* store up to 32ECBs at any one time */
/* in aha1742 H/W ( Not MAX ? ) */
#define ECB_HASH_SIZE 32 /* when we have a physical addr. for */
/* a ecb and need to find the ecb in */
/* space, look it up in the hash table */
#define ECB_HASH_SHIFT 9 /* only hash on multiples of 512 */
#define ECB_HASH(x) ((((long int)(x))>>ECB_HASH_SHIFT) % ECB_HASH_SIZE)
#define AHB_NSEG 33 /* number of dma segments supported */
* 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
/*-----------------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
;
physaddr hashkey
; /* physaddr of this struct */
struct ecb
*ecbhash
[ECB_HASH_SIZE
];
int our_id
; /* our scsi id */
struct ecb
*immed_ecb
; /* an outstanding immediete command */
struct scsi_link sc_link
;
int ahbprobe1
__P((struct isa_device
*dev
));
int ahb_init
__P((int unit
));
void ahb_timeout(caddr_t
, int);
struct ecb
*ahb_ecb_phys_kv();
u_int32
ahb_adapter_info();
#define MAX_SLOTS 8 /* XXX should this be 16?? Need EISA spec */
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 isa_driver ahbdriver
=
struct scsi_adapter ahb_switch
=
/* the below structure is so we have a default dev struct for our link struct */
struct scsi_device ahb_dev
=
NULL
, /* Use default error handler */
NULL
, /* have a queue, served by this */
NULL
, /* have no async handler */
NULL
, /* Use default 'done' routine */
printf("ahb_data size is %d\n", sizeof(struct ahb_data
));
printf("ecb size is %d\n", sizeof(struct ecb
));
* Function to send a command out through a mailbox
ahb_send_mbox(int unit
, int opcode
, int target
, struct ecb
*ecb
)
int port
= ahbdata
[unit
]->baseport
;
int wait
= 300; /* 3ms should be enough */
int stport
= port
+ G2STAT
;
if ((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
)
struct ahb_data
*ahb
= ahbdata
[unit
];
int port
= ahb
->baseport
;
int stport
= port
+ G2STAT
;
if (inb(stport
) & G2STAT_INT_PEND
)
printf("ahb%d: board not responding\n", unit
);
if (cheat
!= ahb_ecb_phys_kv(ahb
, 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
ahb_send_immed(int unit
, int target
, u_long cmd
)
int port
= ahbdata
[unit
]->baseport
;
int stport
= port
+ G2STAT
;
int wait
= 100; /* 1 ms enough? */
if ((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
;
while (ahb_slot
<= MAX_SLOTS
) {
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_device structure from
* find unit and check we have that many defined
printf("ahb: unit number (%d) too high\n", unit
);
* Allocate a storage area for us
printf("ahb%d: memory already allocated\n", unit
);
ahb
= malloc(sizeof(struct ahb_data
), M_TEMP
, M_NOWAIT
);
printf("ahb%d: cannot malloc!\n", unit
);
bzero(ahb
, sizeof(struct ahb_data
));
ahb
->baseport
= dev
->id_iobase
;
* Try initialise a unit at this location
* sets up dma and bus speed, loads ahb->vect
if (ahb_init(unit
) != 0) {
* If it's there, put in it's interrupt vectors
dev
->id_irq
= (1 << ahb
->vect
);
dev
->id_drq
= -1; /* use EISA dma */
* Attach all the sub-devices we can find
int unit
= dev
->id_masunit
;
struct ahb_data
*ahb
= ahbdata
[unit
];
* fill in the prototype scsi_link.
ahb
->sc_link
.adapter_unit
= unit
;
ahb
->sc_link
.adapter_targ
= ahb
->our_id
;
ahb
->sc_link
.adapter
= &ahb_switch
;
ahb
->sc_link
.device
= &ahb_dev
;
* ask the adapter what subunits are present
scsi_attachdevs(&(ahb
->sc_link
));
* Return some information to the caller about
* the adapter and it's capabilities
return (2); /* 2 outstanding requests at a time per device */
* Catch an interrupt from the adaptor
struct ahb_data
*ahb
= ahbdata
[unit
];
int port
= ahb
->baseport
;
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
);
printf("status = 0x%x ", stat
);
* Process the completed operation
if (stat
== AHB_ECB_OK
) { /* common case is fast */
ecb
= ahb_ecb_phys_kv(ahb
, mboxval
);
ecb
->flags
|= ECB_IMMED_FAIL
;
case AHB_ASN
: /* for target mode */
printf("ahb%d: Unexpected ASN interrupt(%x)\n",
printf("ahb%d: Hardware error interrupt(%x)\n",
ecb
= ahb_ecb_phys_kv(ahb
, mboxval
);
ecb
= ahb_ecb_phys_kv(ahb
, mboxval
);
printf(" Unknown return from ahb%d(%x)\n", unit
, ahbstat
);
if (ahb_debug
& AHB_SHOWCMDS
) {
if ((ahb_debug
& AHB_SHOWECBS
) && ecb
)
printf("<int ecb(%x)>", ecb
);
untimeout((timeout_t
)ahb_timeout
, (caddr_t
)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
ahb_done(unit
, ecb
, state
)
struct ahb_ecb_status
*stat
= &ecb
->ecb_status
;
struct scsi_sense_data
*s1
, *s2
;
struct scsi_xfer
*xs
= ecb
->xs
;
SC_DEBUG(xs
->sc_link
, SDEV_DB2
, ("ahb_done\n"));
* 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 */
switch (stat
->ha_status
) {
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
) {
/* structure copy!!!!! */
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
);
* A ecb (and hence a mbx-out is put onto the
ahb_free_ecb(unit
, ecb
, flags
)
struct ahb_data
*ahb
= ahbdata
[unit
];
if (!(flags
& SCSI_NOMASK
))
ecb
->next
= ahb
->free_ecb
;
* If there were none, wake abybody waiting for
* one to come free, starting with queued entries
wakeup((caddr_t
)&ahb
->free_ecb
);
if (!(flags
& SCSI_NOMASK
))
* If there are none, see if we can allocate a
* new one. If so, put it in the hash table too
* otherwise either return an error or sleep
struct ahb_data
*ahb
= ahbdata
[unit
];
if (!(flags
& SCSI_NOMASK
))
* If we can and have to, sleep waiting for one to come free
* but only if we can't allocate a new one.
while (!(ecbp
= ahb
->free_ecb
)) {
if (ahb
->numecbs
< AHB_ECB_MAX
) {
ecbp
= (struct ecb
*) malloc(sizeof(struct ecb
),
bzero(ecbp
, sizeof(struct ecb
));
ecbp
->flags
= ECB_ACTIVE
;
* put in the phystokv hash table
ecbp
->hashkey
= KVTOPHYS(ecbp
);
hashnum
= ECB_HASH(ecbp
->hashkey
);
ecbp
->nexthash
= ahb
->ecbhash
[hashnum
];
ahb
->ecbhash
[hashnum
] = ecbp
;
printf("ahb%d: Can't malloc ECB\n", unit
);
if (!(flags
& SCSI_NOSLEEP
)) {
tsleep((caddr_t
)&ahb
->free_ecb
, PRIBIO
,
/* Get ECB from from free list */
ahb
->free_ecb
= ecbp
->next
;
ecbp
->flags
= ECB_ACTIVE
;
gottit
: if (!(flags
& SCSI_NOMASK
))
* given a physical address, find the ecb that
ahb_ecb_phys_kv(ahb
, ecb_phys
)
int hashnum
= ECB_HASH(ecb_phys
);
struct ecb
*ecbp
= ahb
->ecbhash
[hashnum
];
if (ecbp
->hashkey
== ecb_phys
)
* Start the board, ready for normal operation
struct ahb_data
*ahb
= ahbdata
[unit
];
int port
= ahb
->baseport
;
int wait
= 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
);
if ((inb(stport
) & G2STAT_BUSY
) == 0)
if (ahb_debug
& AHB_SHOWMISC
)
printf("ahb_init: No answer from aha1742 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
);
printf("illegal int setting\n");
printf("int=%d\n", ahb
->vect
);
outb(port
+ INTDEF
, (intdef
| INTEN
)); /* make sure we can interrupt */
/* who are we on the scsi bus? */
ahb
->our_id
= (inb(port
+ SCSIDEF
) & HSCSIID
);
* Note that we are going and return (to probe)
#define min(x,y) (x < y ? x : y)
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
int seg
; /* scatter gather seg being worked on */
physaddr thisphys
, nextphys
;
int unit
= xs
->sc_link
->adapter_unit
;
int bytes_this_seg
, bytes_this_page
, datalen
, flags
;
struct ahb_data
*ahb
= ahbdata
[unit
];
SC_DEBUG(xs
->sc_link
, SDEV_DB2
, ("ahb_scsi_cmd\n"));
* 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
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
;
return (TRY_AGAIN_LATER
);
SC_DEBUG(xs
->sc_link
, SDEV_DB3
, ("start ecb(%x)\n", ecb
));
* If it's a reset, we need to do an 'immediate'
* command, and store it's ecb for later
* if there is already an immediate waiting,
if (flags
& SCSI_RESET
) {
return (TRY_AGAIN_LATER
);
if (!(flags
& SCSI_NOMASK
)) {
ahb_send_immed(unit
, xs
->sc_link
->target
, AHB_TARG_RESET
);
timeout(ahb_timeout
, (caddr_t
)ecb
, (xs
->timeout
* hz
) / 1000);
return (SUCCESSFULLY_QUEUED
);
ahb_send_immed(unit
, xs
->sc_link
->target
, AHB_TARG_RESET
);
* If we can't use interrupts, poll on completion
SC_DEBUG(xs
->sc_link
, SDEV_DB3
, ("wait\n"));
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
->sc_link
->lun
| ECB_NRB
;
ecb
->cdblen
= xs
->cmdlen
;
ecb
->sense
= KVTOPHYS(&(ecb
->ecb_sense
));
ecb
->senselen
= sizeof(ecb
->ecb_sense
);
ecb
->status
= KVTOPHYS(&(ecb
->ecb_status
));
if (xs
->datalen
) { /* 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
;
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
,
("(0x%x@0x%x)", iovp
->iov_len
* Set up the scatter gather block
SC_DEBUG(xs
->sc_link
, SDEV_DB4
,
("%d @0x%x:- ", xs
->datalen
, xs
->data
));
thisphys
= KVTOPHYS(thiskv
);
while ((datalen
) && (seg
< AHB_NSEG
)) {
/* put in the base address */
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
, ("0x%x", thisphys
));
/* 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
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
,
("(0x%x)", bytes_this_seg
));
sg
->len
= bytes_this_seg
;
} /*end of iov/kv decision */
ecb
->datalen
= seg
* sizeof(struct ahb_dma_seg
);
SC_DEBUGN(xs
->sc_link
, SDEV_DB4
, ("\n"));
if (datalen
) { /* 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
);
} else { /* No data xfer, use non S/G values */
ecb
->data
= (physaddr
) 0;
} 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
->sc_link
->target
, ecb
);
timeout(ahb_timeout
, (caddr_t
)ecb
, (xs
->timeout
* hz
) / 1000);
SC_DEBUG(xs
->sc_link
, SDEV_DB3
, ("cmd_sent\n"));
return (SUCCESSFULLY_QUEUED
);
* If we can't use interrupts, poll on completion
ahb_send_mbox(unit
, OP_START_ECB
, xs
->sc_link
->target
, ecb
);
SC_DEBUG(xs
->sc_link
, SDEV_DB3
, ("cmd_wait\n"));
if (ahb_poll(unit
, xs
->timeout
)) {
if (!(xs
->flags
& SCSI_SILENT
))
ahb_send_mbox(unit
, OP_ABORT_ECB
, xs
->sc_link
->target
, ecb
);
if (ahb_poll(unit
, 2000)) {
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(caddr_t arg1
, int arg2
)
struct ecb
* ecb
= (struct ecb
*)arg1
;
unit
= ecb
->xs
->sc_link
->adapter_unit
;
printf("ahb%d:%d:%d (%s%d) timed out ", unit
,ecb
->xs
->sc_link
->target
,ecb
->xs
->sc_link
->device
->name
,ecb
->xs
->sc_link
->dev_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
;
ahb_done(unit
, ecb
, FAIL
);
* If it has been through before, then
* a previous abort has failed, don't
if (ecb
->flags
== ECB_ABORTED
) {
ecb
->xs
->retries
= 0; /* I MEAN IT ! */
ecb
->ecb_status
.ha_status
= HS_CMD_ABORTED_HOST
;
ahb_done(unit
, ecb
, FAIL
);
} else { /* abort the operation that has timed out */
ahb_send_mbox(unit
, OP_ABORT_ECB
, ecb
->xs
->sc_link
->target
, ecb
);
/* 2 secs for the abort */
timeout(ahb_timeout
, (caddr_t
)ecb
, 2 * hz
);
ecb
->flags
= ECB_ABORTED
;
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_print_active_ecb(int unit
)
struct ahb_data
*ahb
= ahbdata
[unit
];
while (i
< ECB_HASH_SIZE
) {
if (ecb
->flags
!= ECB_FREE
) {