summaryrefslogtreecommitdiff
path: root/scsi/adapters/scsi_aha17_hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'scsi/adapters/scsi_aha17_hdw.c')
-rw-r--r--scsi/adapters/scsi_aha17_hdw.c1371
1 files changed, 1371 insertions, 0 deletions
diff --git a/scsi/adapters/scsi_aha17_hdw.c b/scsi/adapters/scsi_aha17_hdw.c
new file mode 100644
index 0000000..d8afe6a
--- /dev/null
+++ b/scsi/adapters/scsi_aha17_hdw.c
@@ -0,0 +1,1371 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993 Carnegie Mellon University
+ * Copyright (c) 1993 University of Dublin
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and the following permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON AND THE UNIVERSITY OF DUBLIN ALLOW FREE USE OF
+ * THIS SOFTWARE IN ITS "AS IS" CONDITION. CARNEGIE MELLON AND THE
+ * UNIVERSITY OF DUBLIN DISCLAIM ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Support for AHA-174x in enhanced mode. Dominic Herity (dherity@cs.tcd.ie)
+ * Will refer to "Adaptec AHA-1740A/1742A/1744 Technical Reference Manual"
+ * page x-y as TRMx-y in comments below.
+ */
+
+#include <eaha.h>
+#if NEAHA > 0
+
+#define db_printf printf
+
+#include <cpus.h>
+#include <platforms.h>
+#include <aha.h>
+
+#ifdef OSF
+#include <eisa.h>
+#else
+#include <i386at/eisa.h>
+#endif
+
+#include <mach/std_types.h>
+#include <sys/types.h>
+#include <chips/busses.h>
+#include <scsi/compat_30.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi2.h>
+#include <scsi/scsi_defs.h>
+
+#include <scsi/adapters/scsi_aha15.h>
+#include <vm/vm_kern.h>
+
+#ifdef AT386
+#define MACHINE_PGBYTES I386_PGBYTES
+#define MAPPABLE 0
+#define gimmeabreak() asm("int3")
+
+
+#include <i386/pio.h> /* inlining of outb and inb */
+#ifdef OSF
+#include <machine/mp/mp.h>
+#endif
+#endif /*AT386*/
+
+#ifdef CBUS
+#include <cbus/cbus.h>
+#endif
+
+
+#ifndef MACHINE_PGBYTES /* cross compile check */
+#define MACHINE_PGBYTES 0x1000
+#define MAPPABLE 1
+#define gimmeabreak() Debugger("gimmeabreak");
+#endif
+
+int eaha_probe(), scsi_slave(), eaha_go(), eaha_intr();
+void scsi_attach();
+
+vm_offset_t eaha_std[NEAHA] = { 0 };
+struct bus_device *eaha_dinfo[NEAHA*8];
+struct bus_ctlr *eaha_minfo[NEAHA];
+struct bus_driver eaha_driver =
+ { eaha_probe, scsi_slave, scsi_attach, eaha_go, eaha_std, "rz",
+ eaha_dinfo, "eahac", eaha_minfo, BUS_INTR_B4_PROBE};
+
+
+#define TRACE
+#ifdef TRACE
+
+#define LOGSIZE 256
+int eaha_logpt;
+char eaha_log[LOGSIZE];
+
+#define MAXLOG_VALUE 0x1e
+struct {
+ char *name;
+ unsigned int count;
+} logtbl[MAXLOG_VALUE];
+
+static LOG(
+ int e,
+ char *f)
+{
+ eaha_log[eaha_logpt++] = (e);
+ if (eaha_logpt == LOGSIZE) eaha_logpt = 0;
+ if ((e) < MAXLOG_VALUE) {
+ logtbl[(e)].name = (f);
+ logtbl[(e)].count++;
+ }
+}
+
+eaha_print_log(
+ int skip)
+{
+ register int i, j;
+ register unsigned char c;
+
+ for (i = 0, j = eaha_logpt; i < LOGSIZE; i++) {
+ c = eaha_log[j];
+ if (++j == LOGSIZE) j = 0;
+ if (skip-- > 0)
+ continue;
+ if (c < MAXLOG_VALUE)
+ db_printf(" %s", logtbl[c].name);
+ else
+ db_printf("-%x", c & 0x7f);
+ }
+ return 0;
+}
+
+eaha_print_stat()
+{
+ register int i;
+ register char *p;
+ for (i = 0; i < MAXLOG_VALUE; i++) {
+ if (p = logtbl[i].name)
+ printf("%d %s\n", logtbl[i].count, p);
+ }
+}
+
+#else /*TRACE*/
+#define LOG(e,f)
+#define LOGSIZE
+#endif /*TRACE*/
+
+#ifdef DEBUG
+#define ASSERT(x) { if (!(x)) gimmeabreak() ; }
+#define MARK() gimmeabreak()
+#else
+#define ASSERT(x)
+#define MARK()
+#endif
+
+/*
+ * Notes :
+ *
+ * do each host command TRM6-4
+ * find targets in probe
+ * disable SCSI writes
+ * matching port with structs, eaha_go with port, eaha_intr with port
+ *
+ */
+
+/* eaha registers. See TRM4-11..23. dph */
+
+#define HID0(z) ((z)+0xC80)
+#define HID1(z) ((z)+0xC81)
+#define HID2(z) ((z)+0xC82)
+#define HID3(z) ((z)+0xC83)
+#define EBCTRL(z) ((z)+0xC84)
+#define PORTADDR(z) ((z)+0xCC0)
+#define BIOSADDR(z) ((z)+0xCC1)
+#define INTDEF(z) ((z)+0xCC2)
+#define SCSIDEF(z) ((z)+0xCC3)
+#define MBOXOUT0(z) ((z)+0xCD0)
+#define MBOXOUT1(z) ((z)+0xCD1)
+#define MBOXOUT2(z) ((z)+0xCD2)
+#define MBOXOUT3(z) ((z)+0xCD3)
+#define MBOXIN0(z) ((z)+0xCD8)
+#define MBOXIN1(z) ((z)+0xCD9)
+#define MBOXIN2(z) ((z)+0xCDA)
+#define MBOXIN3(z) ((z)+0xCDB)
+#define ATTN(z) ((z)+0xCD4)
+#define G2CNTRL(z) ((z)+0xCD5)
+#define G2INTST(z) ((z)+0xCD6)
+#define G2STAT(z) ((z)+0xCD7)
+#define G2STAT2(z) ((z)+0xCDC)
+
+/*
+ * Enhanced mode data structures: ring, enhanced ccbs, a per target buffer
+ */
+
+#define SCSI_TARGETS 8 /* Allow for SCSI-2 */
+
+
+/* Extended Command Control Block Format. See TRM6-3..12. */
+
+typedef struct {
+ unsigned short command ;
+# define EAHA_CMD_NOP 0
+# define EAHA_CMD_INIT_CMD 1
+# define EAHA_CMD_DIAG 5
+# define EAHA_CMD_INIT_SCSI 6
+# define EAHA_CMD_READ_SENS 8
+# define EAHA_CMD_DOWNLOAD 9
+# define EAHA_CMD_HOST_INQ 0x0a
+# define EAHA_CMD_TARG_CMD 0x10
+
+ /*
+ * It appears to be customary to tackle the endian-ness of
+ * bit fields as follows, so I won't deviate. However, nothing in
+ * K&R implies that bit fields are implemented so that the fields
+ * of an unsigned char are allocated lsb first. Indeed, K&R _warns_
+ * _against_ using bit fields to describe storage allocation.
+ * This issue is separate from endian-ness. dph
+ * And this is exactly the reason macros are used. If your compiler
+ * is weird just override the macros and we will all be happy. af
+ */
+ BITFIELD_3(unsigned char,
+ cne:1,
+ xxx0:6,
+ di:1) ;
+ BITFIELD_7(unsigned char,
+ xxx1:2,
+ ses:1,
+ xxx2:1,
+ sg:1,
+ xxx3:1,
+ dsb:1,
+ ars:1) ;
+
+ BITFIELD_5(unsigned char,
+ lun:3,
+ tag:1,
+ tt:2,
+ nd:1,
+ xxx4:1) ;
+ BITFIELD_7(unsigned char,
+ dat:1,
+ dir:1,
+ st:1,
+ chk:1,
+ xxx5:2,
+ rec:1,
+ nbr:1) ;
+
+ unsigned short xxx6 ;
+
+ vm_offset_t scather ; /* scatter/gather */
+ unsigned scathlen ;
+ vm_offset_t status ;
+ vm_offset_t chain ;
+ int xxx7 ;
+
+ vm_offset_t sense_p ;
+ unsigned char sense_len ;
+ unsigned char cdb_len ;
+ unsigned short checksum ;
+ scsi_command_group_5 cdb ;
+ unsigned char buffer[256] ; /* space for data returned. */
+
+} eccb ;
+
+#define NTARGETS (8)
+#define NECCBS (NTARGETS+2) /* Targets + 2 to allow for temporaries. */
+ /* Can be up to 64 (TRM6-2), but that entails lots of bss usage */
+
+typedef struct { /* Status Block Format. See TRM6-13..19. */
+ BITFIELD_8(unsigned char,
+ don:1,
+ du:1,
+ xxx0:1,
+ qf:1,
+ sc:1,
+ dover:1,
+ ch:1,
+ inti:1) ;
+ BITFIELD_8(unsigned char,
+ asa:1, /* Error in TRM6-15..16 says both asa and sns */
+ sns:1, /* bit 9. Bits 8 and 10 are not mentioned. */
+ xxx1:1,
+ ini:1,
+ me:1,
+ xxx2:1,
+ eca:1,
+ xxx3:1) ;
+
+ unsigned char ha_status ;
+# define HA_STATUS_SUCCESS 0x00
+# define HA_STATUS_HOST_ABORTED 0x04
+# define HA_STATUS_ADP_ABORTED 0x05
+# define HA_STATUS_NO_FIRM 0x08
+# define HA_STATUS_NOT_TARGET 0x0a
+# define HA_STATUS_SEL_TIMEOUT 0x11
+# define HA_STATUS_OVRUN 0x12
+# define HA_STATUS_BUS_FREE 0x13
+# define HA_STATUS_PHASE_ERROR 0x14
+# define HA_STATUS_BAD_OPCODE 0x16
+# define HA_STATUS_INVALID_LINK 0x17
+# define HA_STATUS_BAD_CBLOCK 0x18
+# define HA_STATUS_DUP_CBLOCK 0x19
+# define HA_STATUS_BAD_SCATHER 0x1a
+# define HA_STATUS_RSENSE_FAIL 0x1b
+# define HA_STATUS_TAG_REJECT 0x1c
+# define HA_STATUS_HARD_ERROR 0x20
+# define HA_STATUS_TARGET_NOATTN 0x21
+# define HA_STATUS_HOST_RESET 0x22
+# define HA_STATUS_OTHER_RESET 0x23
+# define HA_STATUS_PROG_BAD_SUM 0x80
+
+ scsi2_status_byte_t target_status ;
+
+ unsigned residue ;
+ vm_offset_t residue_buffer ;
+ unsigned short add_stat_len ;
+ unsigned char sense_len ;
+ char xxx4[9] ;
+ unsigned char cdb[6] ;
+
+} status_block ;
+
+typedef struct {
+ vm_offset_t ptr ;
+ unsigned len ;
+} scather_entry ;
+
+#define SCATHER_ENTRIES 128 /* TRM 6-11 */
+
+struct erccbx {
+ target_info_t *active_target;
+ eccb _eccb;
+ status_block status ;
+ struct erccbx *next ;
+} ;
+
+typedef struct erccbx erccb ;
+
+/* forward decls */
+int eaha_reset_scsibus();
+boolean_t eaha_probe_target();
+
+/*
+ * State descriptor for this layer. There is one such structure
+ * per (enabled) board
+ */
+typedef struct {
+ watchdog_t wd;
+ decl_simple_lock_data(, aha_lock)
+ int port; /* I/O port */
+
+ int has_sense_info [NTARGETS];
+ int sense_info_lun [NTARGETS];
+ /* 1742 enhanced mode will hang if target has
+ * sense info and host doesn't request it (TRM6-34).
+ * This sometimes happens in the scsi driver.
+ * These flags indicate when a target has sense
+ * info to disgorge.
+ * If set, eaha_go reads and discards sense info
+ * before running any command except request sense.
+ * dph
+ */
+
+ scsi_softc_t *sc; /* HBA-indep info */
+
+ erccb _erccbs[NECCBS] ; /* mailboxes */
+ erccb *toperccb ;
+
+ /* This chicanery is for mapping back the phys address
+ of a CCB (which we get in an MBI) to its virtual */
+ /* [we could use phystokv(), but it isn't standard] */
+ vm_offset_t I_hold_my_phys_address;
+
+ char host_inquiry_data[256] ; /* Check out ../scsi2.h */
+
+} eaha_softc ;
+
+eaha_softc eaha_softc_data[NEAHA];
+
+typedef eaha_softc *eaha_softc_t;
+
+eaha_softc_t eaha_softc_pool[NEAHA];
+
+int eaha_quiet ;
+
+erccb *erccb_alloc(
+ eaha_softc *eaha)
+{
+ erccb *e ;
+ int x ;
+
+ do {
+ while (eaha->toperccb == 0) ;/* Shouldn't be often or long, */
+ /* BUT should use a semaphore */
+ x = splbio() ;
+ e = eaha->toperccb ;
+ if (e == 0)
+ splx(x) ;
+ } while (!e) ;
+ eaha->toperccb = e->next ;
+ splx(x) ;
+ bzero(e,sizeof(*e)) ;
+ e->_eccb.status = kvtophys((vm_offset_t)&e->status) ;
+ return e ;
+}
+
+void erccb_free(
+ eaha_softc *eaha,
+ erccb *e)
+{
+ int x ;
+ ASSERT ( e >= eaha->_erccbs && e < eaha->_erccbs+NECCBS) ;
+ x = splbio() ;
+ e->next = eaha->toperccb ;
+ eaha->toperccb = e ;
+ splx(x) ;
+}
+
+void eaha_mboxout(
+ int port,
+ vm_offset_t phys)
+{
+ outb(MBOXOUT0(port),phys) ;
+ outb(MBOXOUT1(port),phys>>8) ;
+ outb(MBOXOUT2(port),phys>>16) ;
+ outb(MBOXOUT3(port),phys>>24) ;
+}
+
+void eaha_command( /* start a command */
+ int port,
+ erccb *_erccb)
+{
+ int s ;
+ vm_offset_t phys = kvtophys((vm_offset_t) &_erccb->_eccb) ;
+ while ((inb(G2STAT(port)) & 0x04)==0); /*While MBO busy. TRM6-1 */
+ s = splbio() ;
+ eaha_mboxout(port,phys) ;
+ while (inb(G2STAT(port)) & 1) ; /* While adapter busy. TRM6-2 */
+ outb(ATTN(port),0x40 | _erccb->active_target->target_id) ; /* TRM6-20 */
+ /* (Should use target id for intitiator command) */
+ splx(s) ;
+}
+
+eaha_reset(
+ eaha_softc_t eaha,
+ boolean_t quick)
+{
+ /*
+ * Reset board and wait till done
+ */
+ unsigned st ;
+ int target_id ;
+ int port = eaha->port ;
+
+ /* Reset adapter, maybe with SCSIbus */
+ eaha_mboxout(port, quick ? 0x00080080 : 0x00000080 ) ; /* TRM 6-43..45 */
+ outb(ATTN(port), 0x10 | inb(SCSIDEF(port)) & 0x0f) ;
+ outb(G2CNTRL(port),0x20) ; /* TRM 4-22 */
+
+ do {
+ st = inb(G2INTST(port)) >> 4 ;
+ } while (st == 0) ;
+ /* TRM 4-22 implies that 1 should not be returned in G2INTST, but
+ in practise, it is. So this code takes 0 to mean non-completion. */
+
+ for (target_id = 0 ; target_id < NTARGETS; target_id++)
+ eaha->has_sense_info[target_id] = FALSE ;
+
+}
+
+void eaha_init(
+ eaha_softc_t eaha)
+{
+ /* Do nothing - I guess */
+}
+
+void eaha_bus_reset(
+ eaha_softc_t eaha)
+
+{
+ LOG(0x1d,"bus_reset");
+
+ /*
+ * Clear bus descriptor
+ */
+ eaha->wd.nactive = 0;
+ eaha_reset(eaha, TRUE);
+ eaha_init(eaha);
+
+ printf("eaha: (%d) bus reset ", ++eaha->wd.reset_count);
+ delay(scsi_delay_after_reset); /* some targets take long to reset */
+
+ if (eaha->sc == 0) /* sanity */
+ return;
+
+ scsi_bus_was_reset(eaha->sc);
+}
+
+#ifdef notdef
+ /* functions added to complete 1742 support, but not used. Untested. */
+
+ void eaha_download(port, data, len)
+ int port ;
+ char *data ;
+ unsigned len ;
+ {
+ /* 1744 firmware download. Not implemented. TRM6-21 */
+ }
+
+ void eaha_initscsi(data, len)
+ char *data ;
+ unsigned len ;
+ {
+ /* initialize SCSI subsystem. Presume BIOS does it.
+ Not implemented. TRM6-23 */
+ }
+
+ void eaha_noop()
+ {
+ /* Not implemented. TRM6-27 */
+ }
+
+ erccb *eaha_host_adapter_inquiry(eaha) /* Returns a promise */
+ eaha_softc *eaha ; /* TRM6-31..33 */
+ {
+ erccb *_erccb = erccb_alloc(eaha) ;
+ _erccb->_eccb.scather = (vm_offset_t) kvtophys(eaha->host_inquiry_data) ;
+ _erccb->_eccb.scathlen = sizeof(eaha->host_inquiry_data) ;
+ _erccb->_eccb.ses = 1 ;
+ _erccb->_eccb.command = EAHA_CMD_HOST_INQ ;
+ eaha_command(eaha->port,_erccb->_eccb,0) ; /* Is scsi_id used */
+ return _erccb ;
+ }
+
+ erccb *eaha_read_sense_info(eaha, target, lun) /* TRM 6-33..35 */
+ eaha_softc *eaha ;
+ unsigned target, lun ;
+ { /* Don't think we need this because its done in scsi_alldevs.c */
+ #ifdef notdef
+ erccb *_erccb = erccb_alloc(eaha) ;
+ _erccb->_eccb.command = EAHA_CMD_READ_SENS ;
+ _erccb->_eccb.lun = lun ;
+ eaha_command(eaha->port,_erccb->_eccb, target) ;/*Wrong # args*/
+ return _erccb ;
+ #else
+ return 0 ;
+ #endif
+ }
+
+ void eaha_diagnostic(eaha)
+ eaha_softc *eaha ;
+ {
+ /* Not implemented. TRM6-36..37 */
+ }
+
+ erccb *eaha_target_cmd(eaha, target, lun, data, len) /* TRM6-38..39 */
+ eaha_softc *eaha ;
+ unsigned target, lun ;
+ char *data ;
+ unsigned len ;
+ {
+ erccb *_erccb = erccb_alloc(eaha) ;
+ _erccb->_eccb.command = EAHA_CMD_TARG_CMD ;
+ _erccb->_eccb.lun = lun ;
+ eaha_command(eaha->port,_erccb->_eccb,target);/*Wrong # args*/
+ return _erccb ;
+ }
+
+ erccb *eaha_init_cmd(port) /* SHOULD RETURN TOKEN. i.e. ptr to eccb */
+ /* Need list of free eccbs */
+ { /* to be continued,. possibly. */
+ }
+
+#endif /* notdef */
+
+target_info_t *
+eaha_tgt_alloc(
+ eaha_softc_t eaha,
+ int id,
+ target_info_t *tgt)
+{
+ erccb *_erccb;
+
+ if (tgt == 0)
+ tgt = scsi_slave_alloc(eaha - eaha_softc_data, id, eaha);
+
+ _erccb = erccb_alloc(eaha) ; /* This is very dodgy */
+ tgt->cmd_ptr = (char *)& _erccb->_eccb.cdb ;
+ tgt->dma_ptr = 0;
+ return tgt;
+}
+
+
+struct {
+ scsi_sense_data_t sns ;
+ unsigned char extra
+ [254-sizeof(scsi_sense_data_t)] ;
+} eaha_xsns [NTARGETS] ;/*must be bss to be contiguous*/
+
+
+/* Enhanced adapter probe routine */
+
+eaha_probe(
+ register int port,
+ struct bus_ctlr *ui)
+{
+ int unit = ui->unit;
+ eaha_softc_t eaha = &eaha_softc_data[unit] ;
+ int target_id ;
+ scsi_softc_t *sc ;
+ int s;
+ boolean_t did_banner = FALSE ;
+ struct aha_devs installed;
+ unsigned char my_scsi_id, my_interrupt ;
+
+ if (unit >= NEAHA)
+ return(0);
+
+ /* No interrupts yet */
+ s = splbio();
+
+ /*
+ * Detect prescence of 174x in enhanced mode. Ignore HID2 and HID3
+ * on the assumption that compatibility will be preserved. dph
+ */
+ if (inb(HID0(port)) != 0x04 || inb(HID1(port)) != 0x90 ||
+ (inb(PORTADDR(port)) & 0x80) != 0x80) {
+ splx(s);
+ return 0 ;
+ }
+
+ /* Issue RESET in case this is a reboot */
+
+ outb(EBCTRL(port),0x04) ; /* Disable board. TRM4-12 */
+ outb(PORTADDR(port),0x80) ; /* Disable standard mode ports. TRM4-13. */
+ my_interrupt = inb(INTDEF(port)) & 0x07 ;
+ outb(INTDEF(port), my_interrupt | 0x00) ;
+ /* Disable interrupts. TRM4-15 */
+ my_scsi_id = inb(SCSIDEF(port)) & 0x0f ;
+ outb(SCSIDEF(port), my_scsi_id | 0x10) ;
+ /* Force SCSI reset on hard reset. TRM4-16 */
+ outb(G2CNTRL(port),0xe0) ; /* Reset board, clear interrupt */
+ /* and set 'host ready'. */
+ delay(10*10) ; /* HRST must remain set for 10us. TRM4-22 */
+ /* (I don't believe the delay loop is slow enough.) */
+ outb(G2CNTRL(port),0x60);/*Un-reset board, set 'host ready'. TRM4-22*/
+
+ printf("Adaptec 1740A/1742A/1744 enhanced mode\n");
+
+ /* Get host inquiry data */
+
+ eaha_softc_pool[unit] = eaha ;
+ bzero(eaha,sizeof(*eaha)) ;
+ eaha->port = port ;
+
+ sc = scsi_master_alloc(unit, eaha) ;
+ eaha->sc = sc ;
+ sc->go = eaha_go ;
+ sc->watchdog = scsi_watchdog ;
+ sc->probe = eaha_probe_target ;
+ eaha->wd.reset = eaha_reset_scsibus ;
+ sc->max_dma_data = -1 ; /* Lets be optimistic */
+ sc->initiator_id = my_scsi_id ;
+ eaha_reset(eaha,TRUE) ;
+ eaha->I_hold_my_phys_address =
+ kvtophys((vm_offset_t)&eaha->I_hold_my_phys_address) ;
+ {
+ erccb *e ;
+ eaha->toperccb = eaha->_erccbs ;
+ for (e=eaha->_erccbs; e < eaha->_erccbs+NECCBS; e++) {
+ e->next = e+1 ;
+ e->_eccb.status =
+ kvtophys((vm_offset_t) &e->status) ;
+ }
+ eaha->_erccbs[NECCBS-1].next = 0 ;
+
+ }
+
+ ui->sysdep1 = my_interrupt + 9 ;
+ take_ctlr_irq(ui) ;
+
+ printf("%s%d: [port 0x%x intr ch %d] my SCSI id is %d",
+ ui->name, unit, port, my_interrupt + 9, my_scsi_id) ;
+
+ outb(INTDEF(port), my_interrupt | 0x10) ;
+ /* Enable interrupts. TRM4-15 */
+ outb(EBCTRL(port),0x01) ; /* Enable board. TRM4-12 */
+
+ { target_info_t *t = eaha_tgt_alloc(eaha, my_scsi_id, 0) ;
+ /* Haven't enabled target mode a la standard mode, because */
+ /* it doesn't seem to be necessary. */
+ sccpu_new_initiator(t, t) ;
+ }
+
+ /* Find targets, incl. ourselves. */
+
+ for (target_id=0; target_id < SCSI_TARGETS; target_id++)
+ if (target_id != sc->initiator_id) {
+ scsi_cmd_test_unit_ready_t *cmd;
+ erccb *_erccb = erccb_alloc(eaha) ;
+ unsigned attempts = 0 ;
+#define MAX_ATTEMPTS 2
+ target_info_t temp_targ ;
+
+ temp_targ.ior = 0 ;
+ temp_targ.hw_state = (char *) eaha ;
+ temp_targ.cmd_ptr = (char *) &_erccb->_eccb.cdb ;
+ temp_targ.target_id = target_id ;
+ temp_targ.lun = 0 ;
+ temp_targ.cur_cmd = SCSI_CMD_TEST_UNIT_READY;
+
+ cmd = (scsi_cmd_test_unit_ready_t *) temp_targ.cmd_ptr;
+
+ do {
+ cmd->scsi_cmd_code = SCSI_CMD_TEST_UNIT_READY;
+ cmd->scsi_cmd_lun_and_lba1 = 0; /*assume 1 lun?*/
+ cmd->scsi_cmd_lba2 = 0;
+ cmd->scsi_cmd_lba3 = 0;
+ cmd->scsi_cmd_ss_flags = 0;
+ cmd->scsi_cmd_ctrl_byte = 0; /* not linked */
+
+ eaha_go( &temp_targ,
+ sizeof(scsi_cmd_test_unit_ready_t),0,0);
+ /* ints disabled, so call isr yourself. */
+ while (temp_targ.done == SCSI_RET_IN_PROGRESS)
+ if (inb(G2STAT(eaha->port)) & 0x02) {
+ eaha_quiet = 1 ;
+ eaha_intr(unit) ;
+ eaha_quiet = 0 ;
+ }
+ if (temp_targ.done == SCSI_RET_NEED_SENSE) {
+ /* MUST get sense info : TRM6-34 */
+ if (eaha_retrieve_sense_info(
+ eaha, temp_targ.target_id,
+ temp_targ.lun) &&
+ attempts == MAX_ATTEMPTS-1) {
+
+ printf(
+ "\nTarget %d Check Condition : "
+ ,temp_targ.target_id) ;
+ scsi_print_sense_data(&eaha_xsns
+ [temp_targ.target_id]);
+ printf("\n") ;
+ }
+ }
+ } while (temp_targ.done != SCSI_RET_SUCCESS &&
+ temp_targ.done != SCSI_RET_ABORTED &&
+ ++attempts < MAX_ATTEMPTS) ;
+
+ /*
+ * Recognize target which is present, whether or not
+ * it is ready, e.g. drive with removable media.
+ */
+ if (temp_targ.done == SCSI_RET_SUCCESS ||
+ temp_targ.done == SCSI_RET_NEED_SENSE &&
+ _erccb->status.target_status.bits != 0) { /* Eureka */
+ installed.tgt_luns[target_id]=1;/*Assume 1 lun?*/
+ printf(", %s%d",
+ did_banner++ ? "" : "target(s) at ",
+ target_id);
+
+ erccb_free(eaha, _erccb) ;
+
+ /* Normally, only LUN 0 */
+ if (installed.tgt_luns[target_id] != 1)
+ printf("(%x)", installed.tgt_luns[target_id]);
+ /*
+ * Found a target
+ */
+ (void) eaha_tgt_alloc(eaha, target_id, 0);
+ /* Why discard ? */
+ } else
+ installed.tgt_luns[target_id]=0;
+ }
+
+ printf(".\n") ;
+ splx(s);
+ return 1 ;
+}
+
+int eaha_retrieve_sense_info (
+ eaha_softc_t eaha,
+ int tid,
+ int lun)
+{
+ int result ;
+ int s ;
+ target_info_t dummy_target ; /* Keeps eaha_command() happy. HACK */
+ erccb *_erccb1 = erccb_alloc(eaha) ;
+
+ _erccb1->active_target = &dummy_target ;
+ dummy_target.target_id = tid ;
+ _erccb1->_eccb.command =
+ EAHA_CMD_READ_SENS ;
+ _erccb1->_eccb.lun = lun ;
+ _erccb1->_eccb.sense_p = kvtophys((vm_offset_t) &eaha_xsns [tid]);
+ _erccb1->_eccb.sense_len = sizeof(eaha_xsns [tid]);
+ _erccb1->_eccb.ses = 1 ;
+ s = splbio() ;
+ eaha_command(eaha->port,_erccb1) ;
+ while ((inb(G2STAT(eaha->port)) & 0x02) == 0) ;
+ outb(G2CNTRL(eaha->port),0x40);/* Clear int */
+ splx(s) ;
+ result = _erccb1->status.target_status.bits != 0 ;
+ erccb_free(eaha,_erccb1) ;
+ return result ;
+}
+
+/*
+ * Start a SCSI command on a target (enhanced mode)
+ */
+eaha_go(
+ target_info_t *tgt,
+ int cmd_count,
+ int in_count,
+ boolean_t cmd_only)/*lint: unused*/
+{
+ eaha_softc_t eaha;
+ int s;
+ erccb *_erccb;
+ int len;
+ vm_offset_t virt;
+ int tid = tgt->target_id ;
+
+#ifdef CBUS
+ at386_io_lock_state();
+#endif
+ LOG(1,"go");
+
+#ifdef CBUS
+ at386_io_lock(MP_DEV_WAIT);
+#endif
+ eaha = (eaha_softc_t)tgt->hw_state;
+
+ if(eaha->has_sense_info[tid]) {
+ (void) eaha_retrieve_sense_info
+ (eaha, tid, eaha->sense_info_lun[tid]) ;
+ eaha->has_sense_info[tid] = FALSE ;
+ if (tgt->cur_cmd == SCSI_CMD_REQUEST_SENSE) {
+ bcopy(&eaha_xsns[tid],tgt->cmd_ptr,in_count) ;
+ tgt->done = SCSI_RET_SUCCESS;
+ tgt->transient_state.cmd_count = cmd_count;
+ tgt->transient_state.out_count = 0;
+ tgt->transient_state.in_count = in_count;
+ /* Fake up interrupt */
+ /* Highlights from eaha_initiator_intr(), */
+ /* ignoring errors */
+ if (tgt->ior)
+ (*tgt->dev_ops->restart)( tgt, TRUE);
+#ifdef CBUS
+ at386_io_unlock();
+#endif
+ return ;
+ }
+ }
+
+/* XXX delay the handling of the ccb till later */
+ _erccb = (erccb *)
+ ((unsigned)tgt->cmd_ptr - (unsigned) &((erccb *) 0)->_eccb.cdb);
+ /* Tell *rccb about target, eg. id ? */
+ _erccb->active_target = tgt;
+
+ /*
+ * We can do real DMA.
+ */
+/* tgt->transient_state.copy_count = 0; unused */
+/* tgt->transient_state.dma_offset = 0; unused */
+
+ tgt->transient_state.cmd_count = cmd_count;
+
+ if ((tgt->cur_cmd == SCSI_CMD_WRITE) ||
+ (tgt->cur_cmd == SCSI_CMD_LONG_WRITE)){
+ io_req_t ior = tgt->ior;
+ register int len = ior->io_count;
+
+ tgt->transient_state.out_count = len;
+
+ /* How do we avoid leaks here ? Trust the board
+ will do zero-padding, for now. XXX CHECKME */
+#if 0
+ if (len < tgt->block_size) {
+ bzero(to + len, tgt->block_size - len);
+ len = tgt->block_size;
+ tgt->transient_state.out_count = len;
+ }
+#endif
+ } else {
+ tgt->transient_state.out_count = 0;
+ }
+
+ /* See above for in_count < block_size */
+ tgt->transient_state.in_count = in_count;
+
+ /*
+ * Setup CCB state
+ */
+ tgt->done = SCSI_RET_IN_PROGRESS;
+
+ switch (tgt->cur_cmd) {
+ case SCSI_CMD_READ:
+ case SCSI_CMD_LONG_READ:
+ LOG(9,"readop");
+ virt = (vm_offset_t)tgt->ior->io_data;
+ len = tgt->transient_state.in_count;
+ break;
+ case SCSI_CMD_WRITE:
+ case SCSI_CMD_LONG_WRITE:
+ LOG(0x1a,"writeop");
+ virt = (vm_offset_t)tgt->ior->io_data;
+ len = tgt->transient_state.out_count;
+ break;
+ case SCSI_CMD_INQUIRY:
+ case SCSI_CMD_REQUEST_SENSE:
+ case SCSI_CMD_MODE_SENSE:
+ case SCSI_CMD_RECEIVE_DIAG_RESULTS:
+ case SCSI_CMD_READ_CAPACITY:
+ case SCSI_CMD_READ_BLOCK_LIMITS:
+ LOG(0x1c,"cmdop");
+ LOG(0x80+tgt->cur_cmd,0);
+ virt = (vm_offset_t)tgt->cmd_ptr;
+ len = tgt->transient_state.in_count;
+ break;
+ case SCSI_CMD_MODE_SELECT:
+ case SCSI_CMD_REASSIGN_BLOCKS:
+ case SCSI_CMD_FORMAT_UNIT:
+ tgt->transient_state.cmd_count = sizeof(scsi_command_group_0);
+ len =
+ tgt->transient_state.out_count = cmd_count - sizeof(scsi_command_group_0);
+ virt = (vm_offset_t)tgt->cmd_ptr+sizeof(scsi_command_group_0);
+ LOG(0x1c,"cmdop");
+ LOG(0x80+tgt->cur_cmd,0);
+ break;
+ default:
+ LOG(0x1c,"cmdop");
+ LOG(0x80+tgt->cur_cmd,0);
+ virt = 0;
+ len = 0;
+ }
+
+ eaha_prepare_rccb(tgt, _erccb, virt, len);
+
+ _erccb->_eccb.lun = tgt->lun;
+
+ /*
+ * XXX here and everywhere, locks!
+ */
+ s = splbio();
+
+ simple_lock(&eaha->aha_lock);
+ if (eaha->wd.nactive++ == 0)
+ eaha->wd.watchdog_state = SCSI_WD_ACTIVE;
+ simple_unlock(&eaha->aha_lock);
+
+ LOG(3,"enqueue");
+
+ eaha_command(eaha->port, _erccb) ;
+
+ splx(s);
+#ifdef CBUS
+ at386_io_unlock();
+#endif
+}
+
+eaha_prepare_rccb(
+ target_info_t *tgt,
+ erccb *_erccb,
+ vm_offset_t virt,
+ vm_size_t len)
+{
+ _erccb->_eccb.cdb_len = tgt->transient_state.cmd_count;
+
+ _erccb->_eccb.command = EAHA_CMD_INIT_CMD;/* default common case */
+
+ if (virt == 0) {
+ /* no xfers */
+ _erccb->_eccb.scather = 0 ;
+ _erccb->_eccb.scathlen = 0 ;
+ _erccb->_eccb.sg = 0 ;
+ } else {
+ /* messy xfer */
+ scather_entry *seglist;
+ vm_size_t l1, off;
+
+ _erccb->_eccb.sg = 1 ;
+
+ if (tgt->dma_ptr == 0)
+ eaha_alloc_segment_list(tgt);
+ seglist = (scather_entry *) tgt->dma_ptr;
+
+ _erccb->_eccb.scather = kvtophys((vm_offset_t) seglist);
+
+ l1 = MACHINE_PGBYTES - (virt & (MACHINE_PGBYTES - 1));
+ if (l1 > len)
+ l1 = len ;
+
+ off = 1;/* now #pages */
+ while (1) {
+ seglist->ptr = kvtophys(virt) ;
+ seglist->len = l1 ;
+ seglist++;
+
+ if (len <= l1)
+ break ;
+ len-= l1 ;
+ virt += l1; off++;
+
+ l1 = (len > MACHINE_PGBYTES) ? MACHINE_PGBYTES : len;
+ }
+ _erccb->_eccb.scathlen = off * sizeof(*seglist);
+ }
+}
+
+/*
+ * Allocate dynamically segment lists to
+ * targets (for scatter/gather)
+ */
+vm_offset_t eaha_seglist_next = 0, eaha_seglist_end = 0 ;
+#define EALLOC_SIZE (SCATHER_ENTRIES * sizeof(scather_entry))
+
+eaha_alloc_segment_list(
+ target_info_t *tgt)
+{
+
+/* XXX locking */
+/* ? Can't spl() for unknown duration */
+ if ((eaha_seglist_next + EALLOC_SIZE) > eaha_seglist_end) {
+ (void)kmem_alloc_wired(kernel_map,&eaha_seglist_next,PAGE_SIZE);
+ eaha_seglist_end = eaha_seglist_next + PAGE_SIZE;
+ }
+ tgt->dma_ptr = (char *)eaha_seglist_next;
+ eaha_seglist_next += EALLOC_SIZE;
+/* XXX locking */
+}
+
+/*
+ *
+ * shameless copy from above
+ */
+eaha_reset_scsibus(
+ register eaha_softc_t eaha)
+{
+ register target_info_t *tgt;
+ register port = eaha->port;
+ register int i;
+
+ for (i = 0; i < NECCBS; i++) {
+ tgt = eaha->_erccbs[i].active_target;
+ if (/*scsi_debug &&*/ tgt)
+ printf("Target %d was active, cmd x%x in x%x out x%x\n",
+ tgt->target_id, tgt->cur_cmd,
+ tgt->transient_state.in_count,
+ tgt->transient_state.out_count);
+ }
+ eaha_reset(eaha, FALSE);
+ delay(35);
+ /* no interrupt will come */
+ eaha_bus_reset(eaha);
+}
+
+boolean_t
+eaha_probe_target(
+ target_info_t *tgt,
+ io_req_t ior)
+{
+ eaha_softc_t eaha = eaha_softc_pool[tgt->masterno];
+ boolean_t newlywed;
+
+ newlywed = (tgt->cmd_ptr == 0);
+ if (newlywed) {
+ /* desc was allocated afresh */
+ (void) eaha_tgt_alloc(eaha,tgt->target_id, tgt);
+ }
+
+ if (scsi_inquiry(tgt, SCSI_INQ_STD_DATA) == SCSI_RET_DEVICE_DOWN)
+ return FALSE;
+
+ tgt->flags = TGT_ALIVE;
+ return TRUE;
+}
+
+
+/*
+ * Interrupt routine (enhanced mode)
+ * Take interrupts from the board
+ *
+ * Implementation:
+ * TBD
+ */
+eaha_intr(
+ int unit)
+{
+ register eaha_softc_t eaha;
+ register port;
+ unsigned g2intst, g2stat, g2stat2 ;
+ vm_offset_t mbi ;
+ erccb *_erccb ;
+ status_block *status ;
+
+#if MAPPABLE
+ extern boolean_t rz_use_mapped_interface;
+
+ if (rz_use_mapped_interface) {
+ EAHA_intr(unit);
+ return ;
+ }
+#endif /*MAPPABLE*/
+
+ eaha = eaha_softc_pool[unit];
+ port = eaha->port;
+
+ LOG(5,"\n\tintr");
+gotintr:
+ /* collect ephemeral information */
+
+ g2intst = inb(G2INTST(port)) ; /* See TRM4-22..23 */
+ g2stat = inb(G2STAT(port)) ; /*lint:set,not used*/
+ g2stat2 = inb(G2STAT2(port)) ; /*lint:set,not used*/
+ mbi = (vm_offset_t) inb(MBOXIN0(port)) + (inb(MBOXIN1(port))<<8) +
+ (inb(MBOXIN2(port))<<16) + (inb(MBOXIN3(port))<<24) ;
+
+ /* we got an interrupt allright */
+ if (eaha->wd.nactive)
+ eaha->wd.watchdog_state = SCSI_WD_ACTIVE;
+
+ outb(G2CNTRL(port),0x40) ; /* Clear EISA interrupt */
+
+ switch(g2intst>>4) {
+ case 0x07 : /* hardware error ? */
+ case 0x0a : /* immediate command complete - don't expect */
+ case 0x0e : /* ditto with failure */
+ default :
+ printf( "aha%d: Bogus status (x%x) in MBI\n",
+ unit, mbi);
+ gimmeabreak() ; /* Any of above is disaster */
+ break;
+
+ case 0x0d : /* Asynchronous event TRM6-41 */
+ if ((g2intst & 0x0f) == (inb(SCSIDEF(eaha->port)) & 0x0f))
+ eaha_reset_scsibus(eaha) ;
+ else
+ eaha_target_intr(eaha, mbi, g2intst & 0x0f);
+ break;
+
+ case 0x0c : /* ccb complete with error */
+ case 0x01 : /* ccb completed with success */
+ case 0x05 : /* ccb complete with success after retry */
+
+ _erccb = (erccb *)
+ ( ((vm_offset_t)&eaha->I_hold_my_phys_address) +
+ (mbi - eaha->I_hold_my_phys_address) -
+ (vm_offset_t)&(((erccb *)0)->_eccb) ) ;
+ /* That ain't necessary. As kernel (must be) */
+ /* contiguous, only need delta to translate */
+
+ status = &_erccb->status ;
+
+#ifdef NOTDEF
+ if (!eaha_quiet && (!status->don || status->qf ||
+ status->sc || status->dover ||
+ status->ini || status->me)) {
+ printf("\nccb complete error G2INTST=%02X\n",
+ g2intst) ;
+ DUMP(*_erccb) ;
+ gimmeabreak() ;
+ }
+#endif
+
+ eaha_initiator_intr(eaha, _erccb);
+ break;
+ }
+
+ /* See if more work ready */
+ if (inb(G2STAT(port)) & 0x02) {
+ LOG(7,"\n\tre-intr");
+ goto gotintr;
+ }
+}
+
+/*
+ * The interrupt routine turns to one of these two
+ * functions, depending on the incoming mbi's role
+ */
+eaha_target_intr(
+ eaha_softc_t eaha,
+ unsigned int mbi,
+ unsigned int peer)
+{
+ target_info_t *initiator; /* this is the caller */
+ target_info_t *self; /* this is us */
+ int len;
+
+ self = eaha->sc->target[eaha->sc->initiator_id];
+
+ initiator = eaha->sc->target[peer];
+
+ /* ..but initiators are not required to answer to our inquiry */
+ if (initiator == 0) {
+ /* allocate */
+ initiator = eaha_tgt_alloc(eaha, peer, 0);
+
+ /* We do not know here wether the host was down when
+ we inquired, or it refused the connection. Leave
+ the decision on how we will talk to it to higher
+ level code */
+ LOG(0xC, "new_initiator");
+ sccpu_new_initiator(self, initiator);
+ /* Bug fix: was (aha->sc, self, initiator); dph */
+ }
+
+ /* The right thing to do would be build an ior
+ and call the self->dev_ops->strategy routine,
+ but we cannot allocate it at interrupt level.
+ Also note that we are now disconnected from the
+ initiator, no way to do anything else with it
+ but reconnect and do what it wants us to do */
+
+ /* obviously, this needs both spl and MP protection */
+ self->dev_info.cpu.req_pending = TRUE;
+ self->dev_info.cpu.req_id = peer ;
+ self->dev_info.cpu.req_lun = (mbi>>24) & 0x07 ;
+ self->dev_info.cpu.req_cmd =
+ (mbi & 0x80000000) ? SCSI_CMD_SEND: SCSI_CMD_RECEIVE;
+ len = mbi & 0x00ffffff ;
+
+ self->dev_info.cpu.req_len = len;
+
+ LOG(0xB,"tgt-mode-restart");
+ (*self->dev_ops->restart)( self, FALSE);
+
+ /* The call above has either prepared the data,
+ placing an ior on self, or it handled it some
+ other way */
+ if (self->ior == 0)
+ return; /* I guess we'll do it later */
+
+ {
+ erccb *_erccb ;
+
+ _erccb = erccb_alloc(eaha) ;
+ _erccb->active_target = initiator;
+ _erccb->_eccb.command = EAHA_CMD_TARG_CMD ;
+ _erccb->_eccb.ses = 1 ;
+ _erccb->_eccb.dir = (self->cur_cmd == SCSI_CMD_SEND) ? 1 : 0 ;
+
+ eaha_prepare_rccb(initiator, _erccb,
+ (vm_offset_t)self->ior->io_data, self->ior->io_count);
+ _erccb->_eccb.lun = initiator->lun;
+
+ simple_lock(&eaha->aha_lock);
+ if (eaha->wd.nactive++ == 0)
+ eaha->wd.watchdog_state = SCSI_WD_ACTIVE;
+ simple_unlock(&eaha->aha_lock);
+
+ eaha_command(eaha->port, _erccb);
+ }
+}
+
+eaha_initiator_intr(
+ eaha_softc_t eaha,
+ erccb *_erccb)
+{
+ scsi2_status_byte_t status;
+ target_info_t *tgt;
+
+ tgt = _erccb->active_target;
+ _erccb->active_target = 0;
+
+ /* shortcut (sic!) */
+ if (_erccb->status.ha_status == HA_STATUS_SUCCESS)
+ goto allok;
+
+ switch (_erccb->status.ha_status) { /* TRM6-17 */
+ case HA_STATUS_SUCCESS :
+allok:
+ status = _erccb->status.target_status ;
+ if (status.st.scsi_status_code != SCSI_ST_GOOD) {
+ scsi_error(tgt, SCSI_ERR_STATUS, status.bits, 0);
+ tgt->done = (status.st.scsi_status_code == SCSI_ST_BUSY) ?
+ SCSI_RET_RETRY : SCSI_RET_NEED_SENSE;
+ } else
+ tgt->done = SCSI_RET_SUCCESS;
+ break;
+
+ case HA_STATUS_SEL_TIMEOUT :
+ if (tgt->flags & TGT_FULLY_PROBED)
+ tgt->flags = 0; /* went offline */
+ tgt->done = SCSI_RET_DEVICE_DOWN;
+ break;
+
+ case HA_STATUS_OVRUN :
+ /* BUT we don't know if this is an underrun.
+ It is ok if we get less data than we asked
+ for, in a number of cases. Most boards do not
+ seem to generate this anyways, but some do. */
+ { register int cmd = tgt->cur_cmd;
+ switch (cmd) {
+ case SCSI_CMD_INQUIRY:
+ case SCSI_CMD_REQUEST_SENSE:
+ case SCSI_CMD_RECEIVE_DIAG_RESULTS:
+ case SCSI_CMD_MODE_SENSE:
+ if (_erccb->status.du) /*Ignore underrun only*/
+ break;
+ default:
+ printf("eaha: U/OVRUN on scsi command x%x\n",cmd);
+ gimmeabreak();
+ }
+ }
+ goto allok;
+ case HA_STATUS_BUS_FREE :
+ printf("aha: bad disconnect\n");
+ tgt->done = SCSI_RET_ABORTED;
+ break;
+ case HA_STATUS_PHASE_ERROR :
+ /* we'll get an interrupt soon */
+ printf("aha: bad PHASE sequencing\n");
+ tgt->done = SCSI_RET_ABORTED;
+ break;
+ case HA_STATUS_BAD_OPCODE :
+printf("aha: BADCCB\n");gimmeabreak();
+ tgt->done = SCSI_RET_RETRY;
+ break;
+
+ case HA_STATUS_HOST_ABORTED :
+ case HA_STATUS_ADP_ABORTED :
+ case HA_STATUS_NO_FIRM :
+ case HA_STATUS_NOT_TARGET :
+ case HA_STATUS_INVALID_LINK : /* These aren't expected. */
+ case HA_STATUS_BAD_CBLOCK :
+ case HA_STATUS_DUP_CBLOCK :
+ case HA_STATUS_BAD_SCATHER :
+ case HA_STATUS_RSENSE_FAIL :
+ case HA_STATUS_TAG_REJECT :
+ case HA_STATUS_HARD_ERROR :
+ case HA_STATUS_TARGET_NOATTN :
+ case HA_STATUS_HOST_RESET :
+ case HA_STATUS_OTHER_RESET :
+ case HA_STATUS_PROG_BAD_SUM :
+ default :
+ printf("aha: bad ha_status (x%x)\n", _erccb->status.ha_status);
+ tgt->done = SCSI_RET_ABORTED;
+ break;
+ }
+
+ eaha->has_sense_info [tgt->target_id] =
+ (tgt->done == SCSI_RET_NEED_SENSE) ;
+ if (eaha->has_sense_info [tgt->target_id])
+ eaha->sense_info_lun [tgt->target_id] = tgt->lun ;
+
+ LOG(8,"end");
+
+ simple_lock(&eaha->aha_lock);
+ if (eaha->wd.nactive-- == 1)
+ eaha->wd.watchdog_state = SCSI_WD_INACTIVE;
+ simple_unlock(&eaha->aha_lock);
+
+ if (tgt->ior) {
+ LOG(0xA,"ops->restart");
+ (*tgt->dev_ops->restart)( tgt, TRUE);
+ }
+
+ return FALSE;/*lint: Always returns FALSE. ignored. */
+}
+
+#endif /* NEAHA > 0 */