📄 asc.c
字号:
/*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Ralph Campbell and Rick Macklem. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * @(#)asc.c 8.2 (Berkeley) 1/4/94 *//* * Mach Operating System * Copyright (c) 1991,1990,1989 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 * 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 the * rights to redistribute these changes. *//* * HISTORY * $Log: scsi_53C94_hdw.c,v $ * Revision 2.5 91/02/05 17:45:07 mrt * Added author notices * [91/02/04 11:18:43 mrt] * * Changed to use new Mach copyright * [91/02/02 12:17:20 mrt] * * Revision 2.4 91/01/08 15:48:24 rpd * Added continuation argument to thread_block. * [90/12/27 rpd] * * Revision 2.3 90/12/05 23:34:48 af * Recovered from pmax merge.. and from the destruction of a disk. * [90/12/03 23:40:40 af] * * Revision 2.1.1.1 90/11/01 03:39:09 af * Created, from the DEC specs: * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. * And from the NCR data sheets * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" * [90/09/03 af] *//* * File: scsi_53C94_hdw.h * Author: Alessandro Forin, Carnegie Mellon University * Date: 9/90 * * Bottom layer of the SCSI driver: chip-dependent functions * * This file contains the code that is specific to the NCR 53C94 * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start * operation, and interrupt routine. *//* * This layer works based on small simple 'scripts' that are installed * at the start of the command and drive the chip to completion. * The idea comes from the specs of the NCR 53C700 'script' processor. * * There are various reasons for this, mainly * - Performance: identify the common (successful) path, and follow it; * at interrupt time no code is needed to find the current status * - Code size: it should be easy to compact common operations * - Adaptability: the code skeleton should adapt to different chips without * terrible complications. * - Error handling: and it is easy to modify the actions performed * by the scripts to cope with strange but well identified sequences * */#include <asc.h>#if NASC > 0#include <sys/param.h>#include <sys/systm.h>#include <sys/dkstat.h>#include <sys/buf.h>#include <sys/conf.h>#include <sys/errno.h>#include <machine/machConst.h>#include <pmax/dev/device.h>#include <pmax/dev/scsi.h>#include <pmax/dev/ascreg.h>#include <pmax/pmax/asic.h>#include <pmax/pmax/kmin.h>#include <pmax/pmax/pmaxtype.h>#define readback(a) { register int foo; foo = (a); }extern int pmax_boardtype;/* * In 4ns ticks. */int asc_to_scsi_period[] = { 32, 33, 34, 35, 5, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,};/* * Internal forward declarations. */static void asc_reset();static void asc_startcmd();#ifdef DEBUGint asc_debug = 1;int asc_debug_cmd;int asc_debug_bn;int asc_debug_sz;#define NLOG 32struct asc_log { u_int status; u_char state; u_char msg; int target; int resid;} asc_log[NLOG], *asc_logp = asc_log;#define PACK(unit, status, ss, ir) \ ((unit << 24) | (status << 16) | (ss << 8) | ir)#endif/* * Scripts are entries in a state machine table. * A script has four parts: a pre-condition, an action, a command to the chip, * and an index into asc_scripts for the next state. The first triggers error * handling if not satisfied and in our case it is formed by the * values of the interrupt register and status register, this * basically captures the phase of the bus and the TC and BS * bits. The action part is just a function pointer, and the * command is what the 53C94 should be told to do at the end * of the action processing. This command is only issued and the * script proceeds if the action routine returns TRUE. * See asc_intr() for how and where this is all done. */typedef struct script { int condition; /* expected state at interrupt time */ int (*action)(); /* extra operations */ int command; /* command to the chip */ struct script *next; /* index into asc_scripts for next state */} script_t;/* Matching on the condition value */#define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8))/* forward decls of script actions */static int script_nop(); /* when nothing needed */static int asc_end(); /* all come to an end */static int asc_get_status(); /* get status from target */static int asc_dma_in(); /* start reading data from target */static int asc_last_dma_in(); /* cleanup after all data is read */static int asc_resume_in(); /* resume data in after a message */static int asc_resume_dma_in(); /* resume DMA after a disconnect */static int asc_dma_out(); /* send data to target via dma */static int asc_last_dma_out(); /* cleanup after all data is written */static int asc_resume_out(); /* resume data out after a message */static int asc_resume_dma_out(); /* resume DMA after a disconnect */static int asc_sendsync(); /* negotiate sync xfer */static int asc_replysync(); /* negotiate sync xfer */static int asc_msg_in(); /* process a message byte */static int asc_disconnect(); /* process an expected disconnect *//* Define the index into asc_scripts for various state transitions */#define SCRIPT_DATA_IN 0#define SCRIPT_CONTINUE_IN 2#define SCRIPT_DATA_OUT 3#define SCRIPT_CONTINUE_OUT 5#define SCRIPT_SIMPLE 6#define SCRIPT_GET_STATUS 7#define SCRIPT_MSG_IN 9#define SCRIPT_REPLY_SYNC 11#define SCRIPT_TRY_SYNC 12#define SCRIPT_DISCONNECT 15#define SCRIPT_RESEL 16#define SCRIPT_RESUME_IN 17#define SCRIPT_RESUME_DMA_IN 18#define SCRIPT_RESUME_OUT 19#define SCRIPT_RESUME_DMA_OUT 20#define SCRIPT_RESUME_NO_DATA 21/* * Scripts */script_t asc_scripts[] = { /* start data in */ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_IN + 1]}, {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ asc_last_dma_in, ASC_CMD_I_COMPLETE, &asc_scripts[SCRIPT_GET_STATUS]}, /* continue data in after a chunk is finished */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_IN + 1]}, /* start data out */ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_OUT + 1]}, {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ asc_last_dma_out, ASC_CMD_I_COMPLETE, &asc_scripts[SCRIPT_GET_STATUS]}, /* continue data out after a chunk is finished */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_OUT + 1]}, /* simple command with no data transfer */ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ script_nop, ASC_CMD_I_COMPLETE, &asc_scripts[SCRIPT_GET_STATUS]}, /* get status and finish command */ {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ asc_get_status, ASC_CMD_MSG_ACPT, &asc_scripts[SCRIPT_GET_STATUS + 1]}, {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ asc_end, ASC_CMD_NOP, &asc_scripts[SCRIPT_GET_STATUS + 1]}, /* message in */ {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ asc_msg_in, ASC_CMD_MSG_ACPT, &asc_scripts[SCRIPT_MSG_IN + 1]}, {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ script_nop, ASC_CMD_XFER_INFO, &asc_scripts[SCRIPT_MSG_IN]}, /* send synchonous negotiation reply */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ asc_replysync, ASC_CMD_XFER_INFO, &asc_scripts[SCRIPT_REPLY_SYNC]}, /* try to negotiate synchonous transfer parameters */ {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ asc_sendsync, ASC_CMD_XFER_INFO, &asc_scripts[SCRIPT_TRY_SYNC + 1]}, {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ script_nop, ASC_CMD_XFER_INFO, &asc_scripts[SCRIPT_MSG_IN]}, {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_RESUME_NO_DATA]}, /* handle a disconnect */ {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ asc_disconnect, ASC_CMD_ENABLE_SEL, &asc_scripts[SCRIPT_RESEL]}, /* reselect sequence: this is just a placeholder so match fails */ {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ script_nop, ASC_CMD_MSG_ACPT, &asc_scripts[SCRIPT_RESEL]}, /* resume data in after a message */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_IN + 1]}, /* resume partial DMA data in after a message */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_IN + 1]}, /* resume data out after a message */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_OUT + 1]}, /* resume partial DMA data out after a message */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, &asc_scripts[SCRIPT_DATA_OUT + 1]}, /* resume after a message when there is no more data */ {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ script_nop, ASC_CMD_I_COMPLETE, &asc_scripts[SCRIPT_GET_STATUS]},};/* * State kept for each active SCSI device. */typedef struct scsi_state { script_t *script; /* saved script while processing error */ int statusByte; /* status byte returned during STATUS_PHASE */ int error; /* errno to pass back to device driver */ u_char *dmaBufAddr; /* DMA buffer address */ u_int dmaBufSize; /* DMA buffer size */ int dmalen; /* amount to transfer in this chunk */ int dmaresid; /* amount not transfered if chunk suspended */ int buflen; /* total remaining amount of data to transfer */ char *buf; /* current pointer within scsicmd->buf */ int flags; /* see below */ int msglen; /* number of message bytes to read */ int msgcnt; /* number of message bytes received */ u_char sync_period; /* DMA synchronous period */ u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ u_char msg_out; /* next MSG_OUT byte to send */ u_char msg_in[16]; /* buffer for multibyte messages */} State;/* state flags */#define DISCONN 0x01 /* true if currently disconnected from bus */#define DMA_IN_PROGRESS 0x02 /* true if data DMA started */#define DMA_IN 0x04 /* true if reading from SCSI device */#define DMA_OUT 0x10 /* true if writing to SCSI device */#define DID_SYNC 0x20 /* true if synchronous offset was negotiated */#define TRY_SYNC 0x40 /* true if try neg. synchronous offset */#define PARITY_ERR 0x80 /* true if parity error seen *//* * State kept for each active SCSI host interface (53C94). */struct asc_softc { asc_regmap_t *regs; /* chip address */ volatile int *dmar; /* DMA address register address */ u_char *buff; /* RAM buffer address (uncached) */ int myid; /* SCSI ID of this interface */ int myidmask; /* ~(1 << myid) */ int state; /* current SCSI connection state */ int target; /* target SCSI ID if busy */ script_t *script; /* next expected interrupt & action */ ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ State st[ASC_NCMD]; /* state info for each active command */ void (*dma_start)(); /* Start dma routine */ void (*dma_end)(); /* End dma routine */ u_char *dma_next; int dma_xfer; /* Dma len still to go */ int min_period; /* Min transfer period clk/byte */ int max_period; /* Max transfer period clk/byte */ int ccf; /* CCF, whatever that really is? */ int timeout_250; /* 250ms timeout */ int tb_ticks; /* 4ns. ticks/tb channel ticks */} asc_softc[NASC];#define ASC_STATE_IDLE 0 /* idle state */#define ASC_STATE_BUSY 1 /* selecting or currently connected */#define ASC_STATE_TARGET 2 /* currently selected as target */#define ASC_STATE_RESEL 3 /* currently waiting for reselect */typedef struct asc_softc *asc_softc_t;/* * Dma operations. */#define ASCDMA_READ 1#define ASCDMA_WRITE 2static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end();extern u_long asc_iomem;extern u_long asic_base;/* * Definition of the controller for the auto-configuration program. */int asc_probe();void asc_start();void asc_intr();struct driver ascdriver = { "asc", asc_probe, asc_start, 0, asc_intr,};/* * Test to see if device is present. * Return true if found and initialized ok. */asc_probe(cp) register struct pmax_ctlr *cp;{ register asc_softc_t asc; register asc_regmap_t *regs; int unit, id, s, i; int bufsiz; if ((unit = cp->pmax_unit) >= NASC) return (0); if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) return (0); asc = &asc_softc[unit]; /* * Initialize hw descriptor, cache some pointers */ asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); /* * Set up machine dependencies. * 1) how to do dma * 2) timing based on turbochannel frequency */ switch (pmax_boardtype) { case DS_3MIN: case DS_MAXINE: case DS_3MAXPLUS: if (unit == 0) { asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); bufsiz = 8192; *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; asc->dma_start = asic_dma_start; asc->dma_end = asic_dma_end; break; } /* * Fall through for turbochannel option. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -