summaryrefslogtreecommitdiff
path: root/scsi/adapters/scsi_aha15_hdw.c
diff options
context:
space:
mode:
Diffstat (limited to 'scsi/adapters/scsi_aha15_hdw.c')
-rw-r--r--scsi/adapters/scsi_aha15_hdw.c1467
1 files changed, 0 insertions, 1467 deletions
diff --git a/scsi/adapters/scsi_aha15_hdw.c b/scsi/adapters/scsi_aha15_hdw.c
deleted file mode 100644
index 5514bc5..0000000
--- a/scsi/adapters/scsi_aha15_hdw.c
+++ /dev/null
@@ -1,1467 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
- * 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 this 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 ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS 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.
- */
-/*
- * File: scsi_aha15_hdw.c
- * Author: Alessandro Forin, Carnegie Mellon University
- * Date: 6/91
- *
- * Bottom layer of the SCSI driver: chip-dependent functions
- *
- * This file contains the code that is specific to the Adaptec
- * AHA-15xx family of Intelligent SCSI Host Adapter boards:
- * probing, start operation, and interrupt routine.
- */
-
-/*
- * Since the board is "Intelligent" we do not need scripts like
- * other simpler HBAs. Maybe.
- */
-#include <cpus.h>
-#include <platforms.h>
-
-#include <aha.h>
-#if NAHA > 0
-
-#include <mach/std_types.h>
-#include <machine/machspl.h>
-#include <sys/types.h>
-#include <chips/busses.h>
-#include <scsi/compat_30.h>
-
-/* #include <sys/syslog.h> */
-
-#include <scsi/scsi.h>
-#include <scsi/scsi2.h>
-#include <scsi/scsi_defs.h>
-
-#include <scsi/adapters/scsi_aha15.h>
-
-#ifdef AT386
-#define MACHINE_PGBYTES I386_PGBYTES
-#define MAPPABLE 0
-#define gimmeabreak() asm("int3")
-#include <i386/pio.h> /* inlining of outb and inb */
-#endif /*AT386*/
-
-#ifdef CBUS /* For the Corollary machine, physical */
-#include <i386at/mp/mp.h>
-#include <cbus/cbus.h>
-
-#define aha_cbus_window transient_state.hba_dep[0]
- /* must use windows for phys addresses */
- /* greater than 16 megs */
-
-#define kvtoAT cbus_kvtoAT
-#else /* CBUS */
-#define kvtoAT kvtophys
-#endif /* CBUS */
-
-#ifndef MACHINE_PGBYTES /* cross compile check */
-#define MACHINE_PGBYTES 0x1000
-#define MAPPABLE 1
-#define gimmeabreak() Debugger("gimmeabreak");
-#endif
-
-/*
- * Data structures: ring, ccbs, a per target buffer
- */
-
-#define AHA_NMBOXES 2 /* no need for more, I think */
-struct aha_mb_ctl {
- aha_mbox_t omb[AHA_NMBOXES];
- aha_mbox_t imb[AHA_NMBOXES];
- unsigned char iidx, oidx; /* roving ptrs into */
-};
-#define next_mbx_idx(i) ((((i)+1)==AHA_NMBOXES)?0:((i)+1))
-
-#define AHA_NCCB 8 /* for now */
-struct aha_ccb_raw {
- target_info_t *active_target;
- aha_ccb_t ccb;
- char buffer[256]; /* separate out this ? */
-};
-#define rccb_to_cmdptr(rccb) ((char*)&((rccb)->ccb.ccb_scsi_cmd))
-
-/* forward decls */
-int aha_reset_scsibus();
-boolean_t aha_probe_target();
-
-/*
- * State descriptor for this layer. There is one such structure
- * per (enabled) board
- */
-struct aha_softc {
- watchdog_t wd;
- decl_simple_lock_data(, aha_lock)
- unsigned int port; /* I/O port */
-
- int ntargets; /* how many alive on this scsibus */
-
- scsi_softc_t *sc; /* HBA-indep info */
-
- struct aha_mb_ctl mb; /* mailbox structures */
-
- /* 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;
- struct aha_ccb_raw aha_ccbs[AHA_NCCB];
-
-} aha_softc_data[NAHA];
-
-typedef struct aha_softc *aha_softc_t;
-
-aha_softc_t aha_softc[NAHA];
-
-struct aha_ccb_raw *
-mb_to_rccb(aha, mbi)
- aha_softc_t aha;
- aha_mbox_t mbi;
-{
- vm_offset_t addr;
-
- AHA_MB_GET_PTR(&mbi,addr); /* phys address of ccb */
-
- /* make virtual */
- addr = ((vm_offset_t)&aha->I_hold_my_phys_address) +
- (addr - aha->I_hold_my_phys_address);
-
- /* adjust by proper offset to get base */
- addr -= (vm_offset_t)&(((struct aha_ccb_raw *)0)->ccb);
-
- return (struct aha_ccb_raw *)addr;
-}
-
-target_info_t *
-aha_tgt_alloc(aha, id, sns_len, tgt)
- aha_softc_t aha;
- target_info_t *tgt;
-{
- struct aha_ccb_raw *rccb;
-
- aha->ntargets++;
-
- if (tgt == 0)
- tgt = scsi_slave_alloc(aha - aha_softc_data, id, aha);
-
- rccb = &(aha->aha_ccbs[id]);
- rccb->ccb.ccb_reqsns_len = sns_len;
- tgt->cmd_ptr = rccb_to_cmdptr(rccb);
- tgt->dma_ptr = 0;
-#ifdef CBUS
- tgt->aha_cbus_window = 0;
-#endif /* CBUS */
- return tgt;
-}
-
-/*
- * Synch xfer timing conversions
- */
-#define aha_to_scsi_period(a) ((200 + ((a) * 50)) >> 2)
-#define scsi_period_to_aha(p) ((((p) << 2) - 200) / 50)
-
-/*
- * Definition of the controller for the auto-configuration program.
- */
-
-/* DOCUMENTATION */
-/* base ports can be:
- 0x334, 0x330 (default), 0x234, 0x230, 0x134, 0x130
- possible interrupt channels are:
- 9, 10, 11 (default), 12, 14, 15
- DMA channels can be:
- 7, 6, 5 (default), 0
-/* DOCUMENTATION */
-
-int aha_probe(), scsi_slave(), aha_go(), aha_intr();
-void scsi_attach();
-
-vm_offset_t aha_std[NAHA] = { 0 };
-struct bus_device *aha_dinfo[NAHA*8];
-struct bus_ctlr *aha_minfo[NAHA];
-struct bus_driver aha_driver =
- { aha_probe, scsi_slave, scsi_attach, aha_go, aha_std, "rz", aha_dinfo,
- "ahac", aha_minfo, BUS_INTR_B4_PROBE};
-
-#define DEBUG 1
-#if DEBUG
-
-#define PRINT(x) if (scsi_debug) printf x
-
-aha_state(port)
-{
- register unsigned char st, intr;
-
- if (port == 0)
- port = 0x330;
- st = inb(AHA_STATUS_PORT(port));
- intr = inb(AHA_INTR_PORT(port));
-
- printf("status %x intr %x\n", st, intr);
- return 0;
-}
-
-aha_target_state(tgt)
- target_info_t *tgt;
-{
- if (tgt == 0)
- tgt = aha_softc[0]->sc->target[0];
- if (tgt == 0)
- return 0;
- printf("fl %x dma %X+%x cmd %x@%X id %x per %x off %x ior %X ret %X\n",
- tgt->flags, tgt->dma_ptr, tgt->transient_state.dma_offset, tgt->cur_cmd,
- tgt->cmd_ptr, tgt->target_id, tgt->sync_period, tgt->sync_offset,
- tgt->ior, tgt->done);
-
- return 0;
-}
-
-aha_all_targets(unit)
-{
- int i;
- target_info_t *tgt;
- for (i = 0; i < 8; i++) {
- tgt = aha_softc[unit]->sc->target[i];
- if (tgt)
- aha_target_state(tgt);
- }
-}
-
-#define TRMAX 200
-int tr[TRMAX+3];
-int trpt, trpthi;
-#define TR(x) tr[trpt++] = x
-#define TRWRAP trpthi = trpt; trpt = 0;
-#define TRCHECK if (trpt > TRMAX) {TRWRAP}
-
-#define TRACE
-
-#ifdef TRACE
-
-#define LOGSIZE 256
-#define LOG_KERN 0<<3 /* from syslog.h */
-
-int aha_logpt;
-char aha_log[LOGSIZE];
-
-#define MAXLOG_VALUE 0x1e
-struct {
- char *name;
- unsigned int count;
-} logtbl[MAXLOG_VALUE];
-
-static LOG(e,f)
- char *f;
-{
- aha_log[aha_logpt++] = (e);
- if (aha_logpt == LOGSIZE) aha_logpt = 0;
- if ((e) < MAXLOG_VALUE) {
- logtbl[(e)].name = (f);
- logtbl[(e)].count++;
- }
-}
-
-aha_print_log(skip)
- int skip;
-{
- register int i, j;
- register unsigned char c;
-
- for (i = 0, j = aha_logpt; i < LOGSIZE; i++) {
- c = aha_log[j];
- if (++j == LOGSIZE) j = 0;
- if (skip-- > 0)
- continue;
- if (c < MAXLOG_VALUE)
- printf(" %s", logtbl[c].name);
- else
- printf("-%x", c & 0x7f);
- }
- return 0;
-}
-
-aha_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*/
-
-#else /*DEBUG*/
-#define PRINT(x)
-#define LOG(e,f)
-#define LOGSIZE
-#define TRCHECK
-#define TR(a)
-
-#endif /*DEBUG*/
-
-/* Utility functions at end */
-
-
-/*
- * Probe/Slave/Attach functions
- */
-
-int aha_dotarget = 1; /* somehow on some boards this is trouble */
-
-/*
- * Probe routine:
- * Should find out (a) if the controller is
- * present and (b) which/where slaves are present.
- *
- * Implementation:
- * Just ask the board to do it
- */
-aha_probe(port, ui)
- register port;
- struct bus_ctlr *ui;
-{
- int unit = ui->unit;
- aha_softc_t aha = &aha_softc_data[unit];
- int target_id;
- scsi_softc_t *sc;
- spl_t s;
- boolean_t did_banner = FALSE;
- struct aha_devs installed;
- struct aha_conf conf;
-
- /* No interrupts yet */
- s = splbio();
-
- /*
- * We should be called with a sensible port, but you never know.
- * Send an echo command and see that we get it back properly
- */
- {
- register unsigned char st;
-
- st = inb(AHA_STATUS_PORT(port));
-
- /*
- * There is no board reset in case of reboot with
- * no power-on/power-off sequence. Test it and do
- * the reset if necessary.
- */
-
- if (!(st & AHA_CSR_INIT_REQ)) {
- outb(AHA_CONTROL_PORT(port),
- AHA_CTL_SOFT_RESET|AHA_CTL_HARD_RESET);
- while ((st = inb(AHA_STATUS_PORT(port))) &
- AHA_CSR_SELF_TEST);
- }
- if ((st & AHA_CSR_DATAO_FULL) ||
- !(st & AHA_CSR_INIT_REQ))
- goto fail;
-
- outb(AHA_COMMAND_PORT(port), AHA_CMD_ECHO);
- delay(1000);/*?*/
- st = inb(AHA_STATUS_PORT(port));
- if (st & (AHA_CSR_CMD_ERR|AHA_CSR_DATAO_FULL))
- goto fail;
-
- outb(AHA_COMMAND_PORT(port), 0x5e);
- delay(1000);
-
- st = inb(AHA_STATUS_PORT(port));
- if ((st & AHA_CSR_CMD_ERR) ||
- ((st & AHA_CSR_DATAI_FULL) == 0))
- goto fail;
-
- st = inb(AHA_DATA_PORT(port));
- if (st != 0x5e) {
-fail: splx(s);
- return 0;
- }
- /*
- * augment test with check for echoing inverse and with
- * test for enhanced adapter with standard ports enabled.
- */
-
- /* Check that 0xa1 echoed as well as 0x5e */
-
- outb(AHA_COMMAND_PORT(port), AHA_CMD_ECHO);
- delay(1000);/*?*/
- st = inb(AHA_STATUS_PORT(port));
- if (st & (AHA_CSR_CMD_ERR|AHA_CSR_DATAO_FULL))
- goto fail;
-
- outb(AHA_COMMAND_PORT(port), 0xa1);
- delay(1000);
-
- st = inb(AHA_STATUS_PORT(port));
- if ((st & AHA_CSR_CMD_ERR) ||
- ((st & AHA_CSR_DATAI_FULL) == 0))
- goto fail;
-
- st = inb(AHA_DATA_PORT(port));
- if (st != 0xa1)
- goto fail ;
-
- { /* Check that port isn't 174x in enhanced mode
- with standard mode ports enabled. This should be
- ignored because it will be caught and correctly
- handled by eaha_probe(). See TRM4-11..13.
- dph
- */
- unsigned z ;
- static unsigned port_table[] =
- {0,0,0x130,0x134,0x230,0x234,0x330,0x334};
- for (z= 0x1000; z<= 0xF000; z+= 0x1000)
- if (inb(z+0xC80) == 0x04 &&
- inb(z+0xC81) == 0x90 &&
- inb(z+0xCC0) & 0x80 == 0x80 &&
- port_table [inb(z+0xCC0) & 0x07] == port)
- goto fail ;
- }
- outb(AHA_CONTROL_PORT(port), AHA_CTL_INTR_CLR);
- }
-
-#if MAPPABLE
- /* Mappable version side */
- AHA_probe(port, ui);
-#endif /*MAPPABLE*/
-
- /*
- * Initialize hw descriptor, cache some pointers
- */
- aha_softc[unit] = aha;
- aha->port = port;
-
- sc = scsi_master_alloc(unit, aha);
- aha->sc = sc;
-
- simple_lock_init(&aha->aha_lock);
- sc->go = aha_go;
- sc->watchdog = scsi_watchdog;
- sc->probe = aha_probe_target;
- aha->wd.reset = aha_reset_scsibus;
-
- /* Stupid limitation, no way around it */
- sc->max_dma_data = (AHA_MAX_SEGLIST-1) * MACHINE_PGBYTES;
-
-
- /* XXX
- * I'm not sure how much use this bit of code is really.
- * On the 1542CF we don't really want to try and initialize
- * the mailboxes before unlocking them in any case, and
- * resetting the card is done above.
- */
-#if 0
-#if 0
- /*
- * Reset board.
- */
- aha_reset(port, TRUE);
-#else
- /*
- * Initialize mailboxes
- */
- aha_init_1(aha);
-#endif
-#endif
-
- /*
- * Who are we ?
- */
- {
- struct aha_inq inq;
- struct aha_extbios extbios;
- char *id;
-
- aha_command(port, AHA_CMD_INQUIRY, 0, 0, &inq, sizeof(inq), TRUE);
-
- switch (inq.board_id) {
- case AHA_BID_1540_B16:
- case AHA_BID_1540_B64:
- id = "1540"; break;
- case AHA_BID_1540B:
- id = "1540B/1542B"; break;
- case AHA_BID_1640:
- id = "1640"; break;
- case AHA_BID_1740:
- id = "1740 Unsupported!!"; break;
- case AHA_BID_1542C:
- id = "1542C"; aha_dotarget = 0; break;
- case AHA_BID_1542CF:
- id = "1542CF"; break;
- default:
- id = 0; break;
- }
-
- printf("Adaptec %s [id %x], rev %c%c, options x%x\n",
- id ? id : "Board",
- inq.board_id, inq.frl_1, inq.frl_2, inq.options);
-
- /*
- * If we are a 1542C or 1542CF disable the extended bios
- * so that the mailbox interface is unlocked.
- * No need to check the extended bios flags as some of the
- * extensions that cause us problems are not flagged in
- * that byte.
- */
- if (inq.board_id == 0x44 || inq.board_id == 0x45) {
- aha_command(port, AHA_EXT_BIOS, 0, 0, &extbios,
- sizeof(extbios), TRUE);
-#ifdef AHADEBUG
- printf("aha: extended bios flags 0x%x\n", extbios.flags);
- printf("aha: mailboxlock 0x%x\n", extbios.mblock);
-#endif /* AHADEBUG */
-
- printf("aha: 1542C/CF detected, unlocking mailbox\n");
-
- /* XXX - This sends the mailboxlock code out to the
- * controller. We need to output a 0, then the
- * code...so since we don't care about the flags
- * anyway, we just zero out that field and re-use
- * the struct.
- */
- extbios.flags = 0;
- aha_command(port, AHA_MBX_ENABLE, &extbios,
- sizeof(extbios), 0, 0, TRUE);
- }
-
- }
-doconf:
- /*
- * Readin conf data
- */
- aha_command(port, AHA_CMD_GET_CONFIG, 0, 0, &conf, sizeof(conf), TRUE);
-
- {
- unsigned char args;
-
- /*
- * Change the bus on/off times to not clash with
- * other dma users.
- */
- args = 7;
- aha_command(port, AHA_CMD_SET_BUSON, &args, 1, 0, 0, TRUE);
- args = 5;
- aha_command(port, AHA_CMD_SET_BUSOFF, &args, 1, 0, 0, TRUE);
- }
-
- /* XXX - This is _REALLY_ sickening. */
- /*
- * Set up the DMA channel we'll be using.
- */
- {
- register int d, i;
- static struct {
- unsigned char port;
- unsigned char init_data;
- } aha_dma_init[8][2] = {
- {{0x0b,0x0c}, {0x0a,0x00}}, /* channel 0 */
- {{0,0},{0,0}},
- {{0,0},{0,0}},
- {{0,0},{0,0}},
- {{0,0},{0,0}},
- {{0xd6,0xc1}, {0xd4,0x01}}, /* channel 5 (def) */
- {{0xd6,0xc2}, {0xd4,0x02}}, /* channel 6 */
- {{0xd6,0xc3}, {0xd4,0x03}} /* channel 7 */
- };
-
-
- for (i = 0; i < 8; i++)
- if ((1 << i) & conf.intr_ch) break;
- i += 9;
-
-#if there_was_a_way
- /*
- * On second unit, avoid clashes with first
- */
- if ((unit > 0) && (ui->sysdep1 != i)) {
- printf("Reprogramming irq and dma ch..\n");
- ....
- goto doconf;
- }
-#endif
-
- /*
- * Initialize the DMA controller viz the channel we'll use
- */
- for (d = 0; d < 8; d++)
- if ((1 << d) & conf.dma_arbitration) break;
-
- outb(aha_dma_init[d][0].port, aha_dma_init[d][0].init_data);
- outb(aha_dma_init[d][1].port, aha_dma_init[d][1].init_data);
-
- /* make mapping phys->virt possible for CCBs */
- aha->I_hold_my_phys_address =
- kvtoAT((vm_offset_t)&aha->I_hold_my_phys_address);
-
- /*
- * Our SCSI ID. (xxx) On some boards this is SW programmable.
- */
- sc->initiator_id = conf.my_scsi_id;
-
- printf("%s%d: [dma ch %d intr ch %d] my SCSI id is %d",
- ui->name, unit, d, i, sc->initiator_id);
-
- /* Interrupt vector setup */
- ui->sysdep1 = i;
- take_ctlr_irq(ui);
- }
-
- /*
- * More initializations
- */
- {
- register target_info_t *tgt;
-
- aha_init(aha);
-
- /* allocate a desc for tgt mode role */
- tgt = aha_tgt_alloc(aha, sc->initiator_id, 1, 0);
- sccpu_new_initiator(tgt, tgt); /* self */
-
- }
-
- /* Now we could take interrupts, BUT we do not want to
- be selected as targets by some other host just yet */
-
- /*
- * For all possible targets, see if there is one and allocate
- * a descriptor for it if it is there.
- * This includes ourselves, when acting as target
- */
- aha_command( port, AHA_CMD_FIND_DEVICES, 0, 0, &installed, sizeof(installed), TRUE);
- for (target_id = 0; target_id < 8; target_id++) {
-
- if (target_id == sc->initiator_id) /* done already */
- continue;
-
- if (installed.tgt_luns[target_id] == 0)
- continue;
-
- printf(",%s%d", did_banner++ ? " " : " target(s) at ",
- target_id);
-
- /* Normally, only LUN 0 */
- if (installed.tgt_luns[target_id] != 1)
- printf("(%x)", installed.tgt_luns[target_id]);
- /*
- * Found a target
- */
- (void) aha_tgt_alloc(aha, target_id, 1/*no REQSNS*/, 0);
-
- }
- printf(".\n");
- splx(s);
-
- return 1;
-}
-
-boolean_t
-aha_probe_target(tgt, ior)
- target_info_t *tgt;
- io_req_t ior;
-{
- aha_softc_t aha = aha_softc[tgt->masterno];
- boolean_t newlywed;
-
- newlywed = (tgt->cmd_ptr == 0);
- if (newlywed) {
- /* desc was allocated afresh */
- (void) aha_tgt_alloc(aha,tgt->target_id, 1/*no REQSNS*/, tgt);
- }
-
- if (scsi_inquiry(tgt, SCSI_INQ_STD_DATA) == SCSI_RET_DEVICE_DOWN)
- return FALSE;
-
- tgt->flags = TGT_ALIVE;
- return TRUE;
-}
-
-aha_reset(port, quick)
-{
- register unsigned char st;
-
- /*
- * Reset board and wait till done
- */
- outb(AHA_CONTROL_PORT(port), AHA_CTL_SOFT_RESET);
- do {
- delay(25);
- st = inb(AHA_STATUS_PORT(port));
- } while ((st & (AHA_CSR_IDLE|AHA_CSR_INIT_REQ)) == 0);
-
- if (quick) return;
-
- /*
- * reset the scsi bus. Does NOT generate an interrupt (bozos)
- */
- outb(AHA_CONTROL_PORT(port), AHA_CTL_SCSI_RST);
-}
-
-aha_init_1(aha)
- aha_softc_t aha;
-{
- struct aha_init a;
- vm_offset_t phys;
-
- bzero(&aha->mb, sizeof(aha->mb)); /* also means all free */
- a.mb_count = AHA_NMBOXES;
- phys = kvtoAT((vm_offset_t)&aha->mb);
- AHA_ADDRESS_SET(a.mb_ptr, phys);
- aha_command(aha->port, AHA_CMD_INIT, &a, sizeof(a), 0, 0, TRUE);
-}
-
-aha_init_2(port)
-{
- unsigned char disable = AHA_MBO_DISABLE;
- struct aha_tgt role;
-
- /* Disable MBO available interrupt */
- aha_command(port, AHA_CMD_MBO_IE, &disable, 1, 0,0, FALSE);
-
- if (aha_dotarget) {
- /* Enable target mode role */
- role.enable = 1;
- role.luns = 1; /* only LUN 0 */
- aha_command(port, AHA_CMD_ENB_TGT_MODE, &role, sizeof(role), 0, 0, TRUE);
- }
-}
-
-aha_init(aha)
- aha_softc_t aha;
-{
- aha_init_1(aha);
- aha_init_2(aha->port);
-}
-
-/*
- * Operational functions
- */
-
-/*
- * Start a SCSI command on a target
- */
-aha_go(tgt, cmd_count, in_count, cmd_only)
- target_info_t *tgt;
- boolean_t cmd_only;
-{
- aha_softc_t aha;
- spl_t s;
- struct aha_ccb_raw *rccb;
- int len;
- vm_offset_t virt, phys;
-
-#if CBUS
- at386_io_lock_state();
-#endif
-
- LOG(1,"go");
-
- aha = (aha_softc_t)tgt->hw_state;
-
-/* XXX delay the handling of the ccb till later */
- rccb = &(aha->aha_ccbs[tgt->target_id]);
- rccb->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;
- rccb->ccb.ccb_in = 1; rccb->ccb.ccb_out = 0;
- 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;
- rccb->ccb.ccb_in = 0; rccb->ccb.ccb_out = 1;
- 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:
- case SCSI_CMD_READ_TOC:
- case SCSI_CMD_READ_SUBCH:
- case SCSI_CMD_READ_HEADER:
- case 0xc4: /* despised: SCSI_CMD_DEC_PLAYBACK_STATUS */
- case 0xc6: /* despised: SCSI_CMD_TOSHIBA_READ_SUBCH_Q */
- case 0xc7: /* despised: SCSI_CMD_TOSHIBA_READ_TOC_ENTRY */
- case 0xdd: /* despised: SCSI_CMD_NEC_READ_SUBCH_Q */
- case 0xde: /* despised: SCSI_CMD_NEC_READ_TOC */
- LOG(0x1c,"cmdop");
- LOG(0x80+tgt->cur_cmd,0);
- virt = (vm_offset_t)tgt->cmd_ptr;
- len = tgt->transient_state.in_count;
- rccb->ccb.ccb_in = 1; rccb->ccb.ccb_out = 0;
- break;
- case SCSI_CMD_MODE_SELECT:
- case SCSI_CMD_REASSIGN_BLOCKS:
- case SCSI_CMD_FORMAT_UNIT:
- case 0xc9: /* vendor-spec: SCSI_CMD_DEC_PLAYBACK_CONTROL */
- { register int cs = sizeof_scsi_command(tgt->cur_cmd);
- tgt->transient_state.cmd_count = cs;
- len =
- tgt->transient_state.out_count = cmd_count - cs;
- virt = (vm_offset_t)tgt->cmd_ptr + cs;
- rccb->ccb.ccb_in = 0; rccb->ccb.ccb_out = 1;
- LOG(0x1c,"cmdop");
- LOG(0x80+tgt->cur_cmd,0);
- }
- break;
- default:
- LOG(0x1c,"cmdop");
- LOG(0x80+tgt->cur_cmd,0);
- virt = 0;
- len = 0;
- rccb->ccb.ccb_in = 0; rccb->ccb.ccb_out = 0;
- }
-
-#if CBUS
- at386_io_lock(MP_DEV_WAIT);
-#endif
- aha_prepare_rccb(tgt, rccb, virt, len);
-
- rccb->ccb.ccb_lun = tgt->lun;
- rccb->ccb.ccb_scsi_id = tgt->target_id;
-
-/* AHA_LENGTH_SET(rccb->ccb.ccb_linkptr, 0); unused */
-/* rccb->ccb.ccb_linkid = 0; unused */
-
-#if !CBUS
- s = splbio();
-#endif
-
- LOG(3,"enqueue");
-
- aha_start_scsi(aha, &rccb->ccb);
-
-#if CBUS
- at386_io_unlock();
-#else
- splx(s);
-#endif
-}
-
-aha_prepare_rccb(tgt, rccb, virt, len)
- target_info_t *tgt;
- struct aha_ccb_raw *rccb;
- vm_offset_t virt;
- vm_size_t len;
-{
- vm_offset_t phys;
-#ifdef CBUS
- int cbus_window;
-#endif /* CBUS */
-
- rccb->ccb.ccb_cmd_len = tgt->transient_state.cmd_count;
-
- /* this opcode is refused, grrrr. */
-/* rccb->ccb.ccb_code = AHA_CCB_I_CMD_R; /* default common case */
- rccb->ccb.ccb_code = AHA_CCB_I_CMD; /* default common case */
- AHA_LENGTH_SET(rccb->ccb.ccb_datalen, len);/* default common case */
-
-#ifdef CBUS
- if (tgt->aha_cbus_window == 0)
- tgt->aha_cbus_window = cbus_alloc_win(AHA_MAX_SEGLIST+1);
- cbus_window = tgt->aha_cbus_window;
-#endif /* CBUS */
-
- if (virt == 0) {
- /* no xfers */
- AHA_ADDRESS_SET(rccb->ccb.ccb_dataptr, 0);
- } else if (len <= MACHINE_PGBYTES) {
-/* INCORRECT: what if across two pages :INCORRECT */
- /* simple xfer */
-#ifdef CBUS
- phys = cbus_kvtoAT_ww(virt, cbus_window);
-#else /* CBUS */
- phys = kvtophys(virt);
-#endif /* CBUS */
- AHA_ADDRESS_SET(rccb->ccb.ccb_dataptr, phys);
- } else {
- /* messy xfer */
- aha_seglist_t *seglist;
- vm_offset_t ph1, off;
- vm_size_t l1;
-
- /* this opcode does not work, grrrrr */
-/* rccb->ccb.ccb_code = AHA_CCB_I_CMD_SG_R;*/
- rccb->ccb.ccb_code = AHA_CCB_I_CMD_SG;
-
- if (tgt->dma_ptr == 0)
- aha_alloc_segment_list(tgt);
- seglist = (aha_seglist_t *) tgt->dma_ptr;
-#ifdef CBUS
- phys = cbus_kvtoAT_ww(seglist, cbus_window);
- cbus_window++;
-#else /* CBUS */
- phys = kvtophys((vm_offset_t) seglist);
-#endif /* CBUS */
- AHA_ADDRESS_SET(rccb->ccb.ccb_dataptr, phys);
-
- ph1 = /*i386_trunc_page*/ virt & ~(MACHINE_PGBYTES - 1);
- off = virt & (MACHINE_PGBYTES - 1);
-#ifdef CBUS
- ph1 = cbus_kvtoAT_ww(ph1, cbus_window) + off;
- cbus_window++;
-#else /* CBUS */
- ph1 = kvtophys(ph1) + off;
-#endif /* CBUS */
- l1 = MACHINE_PGBYTES - off;
-
- off = 1;/* now #pages */
- while (1) {
- AHA_ADDRESS_SET(seglist->ptr, ph1);
- AHA_LENGTH_SET(seglist->len, l1);
- seglist++;
-
- if ((len -= l1) <= 0)
- break;
- virt += l1; off++;
-
-#ifdef CBUS
- ph1 = cbus_kvtoAT_ww(virt, cbus_window);
- cbus_window++;
-#else /* CBUS */
- ph1 = kvtophys(virt);
-#endif /* CBUS */
- l1 = (len > MACHINE_PGBYTES) ? MACHINE_PGBYTES : len;
- }
- l1 = off * sizeof(*seglist);
- AHA_LENGTH_SET(rccb->ccb.ccb_datalen, l1);
- }
-}
-
-aha_start_scsi(aha, ccb)
- aha_softc_t aha;
- aha_ccb_t *ccb;
-{
- register aha_mbox_t *mb;
- register idx;
- vm_offset_t phys;
- aha_mbox_t mbo;
- spl_t s;
-
- LOG(4,"start");
- LOG(0x80+ccb->ccb_scsi_id,0);
-
- /*
- * Get an MBO, spin if necessary (takes little time)
- */
- s = splbio();
- phys = kvtoAT((vm_offset_t)ccb);
- /* might cross pages, but should be ok (kernel is contig) */
- AHA_MB_SET_PTR(&mbo,phys);
- mbo.mb.mb_cmd = AHA_MBO_START;
-
- simple_lock(&aha->aha_lock);
- if (aha->wd.nactive++ == 0)
- aha->wd.watchdog_state = SCSI_WD_ACTIVE;
- idx = aha->mb.oidx;
- aha->mb.oidx = next_mbx_idx(idx);
- mb = &aha->mb.omb[idx];
- while (mb->mb.mb_status != AHA_MBO_FREE)
- delay(1);
- mb->bits = mbo.bits;
- simple_unlock(&aha->aha_lock);
-
- /*
- * Start the board going
- */
- aha_command(aha->port, AHA_CMD_START, 0, 0, 0, 0, FALSE);
- splx(s);
-}
-
-/*
- * Interrupt routine
- * Take interrupts from the board
- *
- * Implementation:
- * TBD
- */
-aha_intr(unit)
-{
- register aha_softc_t aha;
- register port;
- register csr, intr;
-#if MAPPABLE
- extern boolean_t rz_use_mapped_interface;
-
- if (rz_use_mapped_interface)
- return AHA_intr(unit);
-#endif /*MAPPABLE*/
-
- aha = aha_softc[unit];
- port = aha->port;
-
- LOG(5,"\n\tintr");
-gotintr:
- /* collect ephemeral information */
- csr = inb(AHA_STATUS_PORT(port));
- intr = inb(AHA_INTR_PORT(port));
-
- /*
- * Check for errors
- */
- if (csr & (AHA_CSR_DIAG_FAIL|AHA_CSR_CMD_ERR)) {
-/* XXX */ gimmeabreak();
- }
-
- /* drop spurious interrupts */
- if ((intr & AHA_INTR_PENDING) == 0) {
- LOG(2,"SPURIOUS");
- return;
- }
- outb(AHA_CONTROL_PORT(port), AHA_CTL_INTR_CLR);
-
-TR(csr);TR(intr);TRCHECK
-
- if (intr & AHA_INTR_RST)
- return aha_bus_reset(aha);
-
- /* we got an interrupt allright */
- if (aha->wd.nactive)
- aha->wd.watchdog_state = SCSI_WD_ACTIVE;
-
- if (intr == AHA_INTR_DONE) {
- /* csr & AHA_CSR_CMD_ERR --> with error */
- LOG(6,"done");
- return;
- }
-
-/* if (intr & AHA_INTR_MBO_AVAIL) will not happen */
-
- /* Some real work today ? */
- if (intr & AHA_INTR_MBI_FULL) {
- register int idx;
- register aha_mbox_t *mb;
- int nscan = 0;
- aha_mbox_t mbi;
-rescan:
- simple_lock(&aha->aha_lock);
- idx = aha->mb.iidx;
- aha->mb.iidx = next_mbx_idx(idx);
- mb = &aha->mb.imb[idx];
- mbi.bits = mb->bits;
- mb->mb.mb_status = AHA_MBI_FREE;
- simple_unlock(&aha->aha_lock);
-
- nscan++;
-
- switch (mbi.mb.mb_status) {
-
- case AHA_MBI_FREE:
- if (nscan >= AHA_NMBOXES)
- return;
- goto rescan;
- break;
-
- case AHA_MBI_SUCCESS:
- case AHA_MBI_ERROR:
- aha_initiator_intr(aha, mbi);
- break;
-
- case AHA_MBI_NEED_CCB:
- aha_target_intr(aha, mbi);
- break;
-
-/* case AHA_MBI_ABORTED: /* this we wont see */
-/* case AHA_MBI_NOT_FOUND: /* this we wont see */
- default:
- log( LOG_KERN,
- "aha%d: Bogus status (x%x) in MBI\n",
- unit, mbi.mb.mb_status);
- break;
- }
-
- /* peek ahead */
- if (aha->mb.imb[aha->mb.iidx].mb.mb_status != AHA_MBI_FREE)
- goto rescan;
- }
-
- /* See if more work ready */
- if (inb(AHA_INTR_PORT(port)) & AHA_INTR_PENDING) {
- LOG(7,"\n\tre-intr");
- goto gotintr;
- }
-}
-
-/*
- * The interrupt routine turns to one of these two
- * functions, depending on the incoming mbi's role
- */
-aha_target_intr(aha, mbi)
- aha_softc_t aha;
- aha_mbox_t mbi;
-{
- target_info_t *initiator; /* this is the caller */
- target_info_t *self; /* this is us */
- int len;
-
- if (mbi.mbt.mb_cmd != AHA_MBI_NEED_CCB)
- gimmeabreak();
-
- /* If we got here this is not zero .. */
- self = aha->sc->target[aha->sc->initiator_id];
-
- initiator = aha->sc->target[mbi.mbt.mb_initiator_id];
- /* ..but initiators are not required to answer to our inquiry */
- if (initiator == 0) {
- /* allocate */
- initiator = aha_tgt_alloc(aha, mbi.mbt.mb_initiator_id,
- sizeof(scsi_sense_data_t) + 5, 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);
- }
-
- /* 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 = mbi.mbt.mb_initiator_id;
- self->dev_info.cpu.req_lun = mbi.mbt.mb_lun;
- self->dev_info.cpu.req_cmd =
- mbi.mbt.mb_isa_send ? SCSI_CMD_SEND: SCSI_CMD_RECEIVE;
- len = (mbi.mbt.mb_data_len_msb << 16) |
- (mbi.mbt.mb_data_len_mid << 8 );
- len += 0x100;/* truncation problem */
- 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 */
-
- {
- struct aha_ccb_raw *rccb;
-
- rccb = &(aha->aha_ccbs[initiator->target_id]);
- rccb->active_target = initiator;
- if (self->dev_info.cpu.req_cmd == SCSI_CMD_SEND) {
- rccb->ccb.ccb_in = 1;
- rccb->ccb.ccb_out = 0;
- } else {
- rccb->ccb.ccb_in = 0;
- rccb->ccb.ccb_out = 1;
- }
-
- aha_prepare_rccb(initiator, rccb,
- (vm_offset_t)self->ior->io_data, self->ior->io_count);
- rccb->ccb.ccb_code = AHA_CCB_T_CMD;
- rccb->ccb.ccb_lun = initiator->lun;
- rccb->ccb.ccb_scsi_id = initiator->target_id;
-
- simple_lock(&aha->aha_lock);
- if (aha->wd.nactive++ == 0)
- aha->wd.watchdog_state = SCSI_WD_ACTIVE;
- simple_unlock(&aha->aha_lock);
-
- aha_start_scsi(aha, &rccb->ccb);
- }
-}
-
-aha_initiator_intr(aha, mbi)
- aha_softc_t aha;
- aha_mbox_t mbi;
-{
- struct aha_ccb_raw *rccb;
- scsi2_status_byte_t status;
- target_info_t *tgt;
-
- rccb = mb_to_rccb(aha,mbi);
- tgt = rccb->active_target;
- rccb->active_target = 0;
-
- /* shortcut (sic!) */
- if (mbi.mb.mb_status == AHA_MBI_SUCCESS)
- goto allok;
-
- switch (rccb->ccb.ccb_hstatus) {
- case AHA_HST_SUCCESS:
-allok:
- status = rccb->ccb.ccb_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 AHA_HST_SEL_TIMEO:
- if (tgt->flags & TGT_FULLY_PROBED)
- tgt->flags = 0; /* went offline */
- tgt->done = SCSI_RET_DEVICE_DOWN;
- break;
- case AHA_HST_DATA_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:
- break;
- default:
- printf("%sx%x\n",
- "aha: U/OVRUN on scsi command x%x\n",
- cmd);
- gimmeabreak();
- }
- }
- goto allok;
- case AHA_HST_BAD_DISCONN:
- printf("aha: bad disconnect\n");
- tgt->done = SCSI_RET_ABORTED;
- break;
- case AHA_HST_BAD_PHASE_SEQ:
- /* we'll get an interrupt soon */
- printf("aha: bad PHASE sequencing\n");
- tgt->done = SCSI_RET_ABORTED;
- break;
- case AHA_HST_BAD_OPCODE: /* fall through */
- case AHA_HST_BAD_PARAM:
-printf("aha: BADCCB\n");gimmeabreak();
- tgt->done = SCSI_RET_RETRY;
- break;
- case AHA_HST_BAD_LINK_LUN: /* these should not happen */
- case AHA_HST_INVALID_TDIR:
- case AHA_HST_DUPLICATED_CCB:
- printf("aha: bad hstatus (x%x)\n", rccb->ccb.ccb_hstatus);
- tgt->done = SCSI_RET_ABORTED;
- break;
- }
-
- LOG(8,"end");
-
- simple_lock(&aha->aha_lock);
- if (aha->wd.nactive-- == 1)
- aha->wd.watchdog_state = SCSI_WD_INACTIVE;
- simple_unlock(&aha->aha_lock);
-
- if (tgt->ior) {
- LOG(0xA,"ops->restart");
- (*tgt->dev_ops->restart)( tgt, TRUE);
- }
-
- return FALSE;
-}
-
-/*
- * The bus was reset
- */
-aha_bus_reset(aha)
- register aha_softc_t aha;
-{
- register port = aha->port;
-
- LOG(0x1d,"bus_reset");
-
- /*
- * Clear bus descriptor
- */
- aha->wd.nactive = 0;
- aha_reset(port, TRUE);
- aha_init(aha);
-
- printf("aha: (%d) bus reset ", ++aha->wd.reset_count);
- delay(scsi_delay_after_reset); /* some targets take long to reset */
-
- if (aha->sc == 0) /* sanity */
- return;
-
- scsi_bus_was_reset(aha->sc);
-}
-
-/*
- * Watchdog
- *
- * We know that some (name withdrawn) disks get
- * stuck in the middle of dma phases...
- */
-aha_reset_scsibus(aha)
- register aha_softc_t aha;
-{
- register target_info_t *tgt;
- register port = aha->port;
- register int i;
-
- for (i = 0; i < AHA_NCCB; i++) {
- tgt = aha->aha_ccbs[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);
- }
- aha_reset(port, FALSE);
- delay(35);
- /* no interrupt will come */
- aha_bus_reset(aha);
-}
-
-/*
- * Utilities
- */
-
-/*
- * Send a command to the board along with some
- * optional parameters, optionally receive the
- * results at command completion, returns how
- * many bytes we did NOT get back.
- */
-aha_command(port, cmd, outp, outc, inp, inc, clear_interrupt)
- unsigned char *outp, *inp;
-{
- register unsigned char st;
- boolean_t failed = TRUE;
-
- do {
- st = inb(AHA_STATUS_PORT(port));
- } while (st & AHA_CSR_DATAO_FULL);
-
- /* Output command and any data */
- outb(AHA_COMMAND_PORT(port), cmd);
- while (outc--) {
- do {
- st = inb(AHA_STATUS_PORT(port));
- if (st & AHA_CSR_CMD_ERR) goto out;
- } while (st & AHA_CSR_DATAO_FULL);
-
- outb(AHA_COMMAND_PORT(port), *outp++);
- }
-
- /* get any data */
- while (inc--) {
- do {
- st = inb(AHA_STATUS_PORT(port));
- if (st & AHA_CSR_CMD_ERR) goto out;
- } while ((st & AHA_CSR_DATAI_FULL) == 0);
-
- *inp++ = inb(AHA_DATA_PORT(port));
- }
- ++inc;
- failed = FALSE;
-
- /* wait command complete */
- if (clear_interrupt) do {
- delay(1);
- st = inb(AHA_INTR_PORT(port));
- } while ((st & AHA_INTR_DONE) == 0);
-
-out:
- if (clear_interrupt)
- outb(AHA_CONTROL_PORT(port), AHA_CTL_INTR_CLR);
- if (failed)
- printf("aha_command: error on (%x %x %x %x %x %x), status %x\n",
- port, cmd, outp, outc, inp, inc, st);
- return inc;
-}
-
-#include <vm/vm_kern.h>
-
-/*
- * Allocate dynamically segment lists to
- * targets (for scatter/gather)
- * Its a max of 17*6=102 bytes per target.
- */
-vm_offset_t aha_seglist_next, aha_seglist_end;
-
-aha_alloc_segment_list(tgt)
- target_info_t *tgt;
-{
-#define ALLOC_SIZE (AHA_MAX_SEGLIST * sizeof(aha_seglist_t))
-
-/* XXX locking */
- if ((aha_seglist_next + ALLOC_SIZE) > aha_seglist_end) {
- (void) kmem_alloc_wired(kernel_map, &aha_seglist_next, PAGE_SIZE);
- aha_seglist_end = aha_seglist_next + PAGE_SIZE;
- }
- tgt->dma_ptr = (char *)aha_seglist_next;
- aha_seglist_next += ALLOC_SIZE;
-/* XXX locking */
-}
-
-#endif /* NAHA > 0 */
-