152889Sbostic /*- 2*63205Sbostic * Copyright (c) 1992, 1993 3*63205Sbostic * The Regents of the University of California. All rights reserved. 452889Sbostic * 552889Sbostic * This code is derived from software contributed to Berkeley by 656819Sralph * Ralph Campbell and Rick Macklem. 752889Sbostic * 852889Sbostic * %sccs.include.redist.c% 952889Sbostic * 10*63205Sbostic * @(#)asc.c 8.1 (Berkeley) 06/10/93 1152889Sbostic */ 1252889Sbostic 1352889Sbostic /* 1452889Sbostic * Mach Operating System 1552889Sbostic * Copyright (c) 1991,1990,1989 Carnegie Mellon University 1652889Sbostic * All Rights Reserved. 1752889Sbostic * 1852889Sbostic * Permission to use, copy, modify and distribute this software and its 1952889Sbostic * documentation is hereby granted, provided that both the copyright 2052889Sbostic * notice and this permission notice appear in all copies of the 2152889Sbostic * software, derivative works or modified versions, and any portions 2252889Sbostic * thereof, and that both notices appear in supporting documentation. 2352889Sbostic * 2452889Sbostic * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 2552889Sbostic * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 2652889Sbostic * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 2752889Sbostic * 2852889Sbostic * Carnegie Mellon requests users of this software to return to 2952889Sbostic * 3052889Sbostic * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 3152889Sbostic * School of Computer Science 3252889Sbostic * Carnegie Mellon University 3352889Sbostic * Pittsburgh PA 15213-3890 3452889Sbostic * 3552889Sbostic * any improvements or extensions that they make and grant Carnegie the 3652889Sbostic * rights to redistribute these changes. 3752889Sbostic */ 3852889Sbostic 3952889Sbostic /* 4052889Sbostic * HISTORY 4152889Sbostic * $Log: scsi_53C94_hdw.c,v $ 4252889Sbostic * Revision 2.5 91/02/05 17:45:07 mrt 4352889Sbostic * Added author notices 4452889Sbostic * [91/02/04 11:18:43 mrt] 4552889Sbostic * 4652889Sbostic * Changed to use new Mach copyright 4752889Sbostic * [91/02/02 12:17:20 mrt] 4852889Sbostic * 4952889Sbostic * Revision 2.4 91/01/08 15:48:24 rpd 5052889Sbostic * Added continuation argument to thread_block. 5152889Sbostic * [90/12/27 rpd] 5252889Sbostic * 5352889Sbostic * Revision 2.3 90/12/05 23:34:48 af 5452889Sbostic * Recovered from pmax merge.. and from the destruction of a disk. 5552889Sbostic * [90/12/03 23:40:40 af] 5652889Sbostic * 5752889Sbostic * Revision 2.1.1.1 90/11/01 03:39:09 af 5852889Sbostic * Created, from the DEC specs: 5952889Sbostic * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" 6052889Sbostic * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. 6152889Sbostic * And from the NCR data sheets 6252889Sbostic * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" 6352889Sbostic * [90/09/03 af] 6452889Sbostic */ 6552889Sbostic 6652889Sbostic /* 6752889Sbostic * File: scsi_53C94_hdw.h 6852889Sbostic * Author: Alessandro Forin, Carnegie Mellon University 6952889Sbostic * Date: 9/90 7052889Sbostic * 7152889Sbostic * Bottom layer of the SCSI driver: chip-dependent functions 7252889Sbostic * 7352889Sbostic * This file contains the code that is specific to the NCR 53C94 7452889Sbostic * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start 7552889Sbostic * operation, and interrupt routine. 7652889Sbostic */ 7752889Sbostic 7852889Sbostic /* 7952889Sbostic * This layer works based on small simple 'scripts' that are installed 8052889Sbostic * at the start of the command and drive the chip to completion. 8152889Sbostic * The idea comes from the specs of the NCR 53C700 'script' processor. 8252889Sbostic * 8352889Sbostic * There are various reasons for this, mainly 8452889Sbostic * - Performance: identify the common (successful) path, and follow it; 8552889Sbostic * at interrupt time no code is needed to find the current status 8652889Sbostic * - Code size: it should be easy to compact common operations 8752889Sbostic * - Adaptability: the code skeleton should adapt to different chips without 8852889Sbostic * terrible complications. 8952889Sbostic * - Error handling: and it is easy to modify the actions performed 9052889Sbostic * by the scripts to cope with strange but well identified sequences 9152889Sbostic * 9252889Sbostic */ 9352889Sbostic 9456819Sralph #include <asc.h> 9552889Sbostic #if NASC > 0 9652889Sbostic 9756522Sbostic #include <sys/param.h> 9856522Sbostic #include <sys/systm.h> 9956819Sralph #include <sys/dkstat.h> 10056819Sralph #include <sys/buf.h> 10156819Sralph #include <sys/conf.h> 10256522Sbostic #include <sys/errno.h> 10352889Sbostic 10456819Sralph #include <machine/machConst.h> 10556819Sralph 10656525Sbostic #include <pmax/dev/device.h> 10756525Sbostic #include <pmax/dev/scsi.h> 10856525Sbostic #include <pmax/dev/ascreg.h> 10952889Sbostic 11056819Sralph #include <pmax/pmax/asic.h> 11156819Sralph #include <pmax/pmax/kmin.h> 11256819Sralph #include <pmax/pmax/pmaxtype.h> 11356819Sralph 11456819Sralph #define readback(a) { register int foo; foo = (a); } 11556819Sralph extern int pmax_boardtype; 11656819Sralph 11756819Sralph /* 11856819Sralph * In 4ns ticks. 11956819Sralph */ 12052889Sbostic int asc_to_scsi_period[] = { 12156819Sralph 32, 12256819Sralph 33, 12356819Sralph 34, 12456819Sralph 35, 12556819Sralph 5, 12656819Sralph 5, 12756819Sralph 6, 12856819Sralph 7, 12956819Sralph 8, 13056819Sralph 9, 13156819Sralph 10, 13256819Sralph 11, 13356819Sralph 12, 13456819Sralph 13, 13556819Sralph 14, 13656819Sralph 15, 13756819Sralph 16, 13856819Sralph 17, 13956819Sralph 18, 14056819Sralph 19, 14156819Sralph 20, 14256819Sralph 21, 14356819Sralph 22, 14456819Sralph 23, 14556819Sralph 24, 14656819Sralph 25, 14756819Sralph 26, 14856819Sralph 27, 14956819Sralph 28, 15056819Sralph 29, 15156819Sralph 30, 15256819Sralph 31, 15352889Sbostic }; 15452889Sbostic 15552889Sbostic /* 15652889Sbostic * Internal forward declarations. 15752889Sbostic */ 15852889Sbostic static void asc_reset(); 15952889Sbostic static void asc_startcmd(); 16052889Sbostic 16152889Sbostic #ifdef DEBUG 16252889Sbostic int asc_debug = 1; 16352889Sbostic int asc_debug_cmd; 16452889Sbostic int asc_debug_bn; 16552889Sbostic int asc_debug_sz; 16658658Sralph #define NLOG 32 16752889Sbostic struct asc_log { 16852889Sbostic u_int status; 16952889Sbostic u_char state; 17052889Sbostic u_char msg; 17152889Sbostic int target; 17258658Sralph int resid; 17352889Sbostic } asc_log[NLOG], *asc_logp = asc_log; 17452889Sbostic #define PACK(unit, status, ss, ir) \ 17552889Sbostic ((unit << 24) | (status << 16) | (ss << 8) | ir) 17652889Sbostic #endif 17752889Sbostic 17852889Sbostic /* 17952889Sbostic * Scripts are entries in a state machine table. 18052889Sbostic * A script has four parts: a pre-condition, an action, a command to the chip, 18152889Sbostic * and an index into asc_scripts for the next state. The first triggers error 18252889Sbostic * handling if not satisfied and in our case it is formed by the 18352889Sbostic * values of the interrupt register and status register, this 18452889Sbostic * basically captures the phase of the bus and the TC and BS 18552889Sbostic * bits. The action part is just a function pointer, and the 18652889Sbostic * command is what the 53C94 should be told to do at the end 18752889Sbostic * of the action processing. This command is only issued and the 18852889Sbostic * script proceeds if the action routine returns TRUE. 18952889Sbostic * See asc_intr() for how and where this is all done. 19052889Sbostic */ 19152889Sbostic typedef struct script { 19252889Sbostic int condition; /* expected state at interrupt time */ 19352889Sbostic int (*action)(); /* extra operations */ 19452889Sbostic int command; /* command to the chip */ 19552889Sbostic struct script *next; /* index into asc_scripts for next state */ 19652889Sbostic } script_t; 19752889Sbostic 19852889Sbostic /* Matching on the condition value */ 19958658Sralph #define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8)) 20052889Sbostic 20152889Sbostic /* forward decls of script actions */ 20256819Sralph static int script_nop(); /* when nothing needed */ 20356819Sralph static int asc_end(); /* all come to an end */ 20456819Sralph static int asc_get_status(); /* get status from target */ 20556819Sralph static int asc_dma_in(); /* start reading data from target */ 20656819Sralph static int asc_last_dma_in(); /* cleanup after all data is read */ 20756819Sralph static int asc_resume_in(); /* resume data in after a message */ 20856819Sralph static int asc_resume_dma_in(); /* resume DMA after a disconnect */ 20956819Sralph static int asc_dma_out(); /* send data to target via dma */ 21056819Sralph static int asc_last_dma_out(); /* cleanup after all data is written */ 21156819Sralph static int asc_resume_out(); /* resume data out after a message */ 21256819Sralph static int asc_resume_dma_out(); /* resume DMA after a disconnect */ 21356819Sralph static int asc_sendsync(); /* negotiate sync xfer */ 21456819Sralph static int asc_replysync(); /* negotiate sync xfer */ 21556819Sralph static int asc_msg_in(); /* process a message byte */ 21656819Sralph static int asc_disconnect(); /* process an expected disconnect */ 21752889Sbostic 21852889Sbostic /* Define the index into asc_scripts for various state transitions */ 21952889Sbostic #define SCRIPT_DATA_IN 0 22052942Sralph #define SCRIPT_CONTINUE_IN 2 22152942Sralph #define SCRIPT_DATA_OUT 3 22252942Sralph #define SCRIPT_CONTINUE_OUT 5 22352942Sralph #define SCRIPT_SIMPLE 6 22452942Sralph #define SCRIPT_GET_STATUS 7 22552942Sralph #define SCRIPT_MSG_IN 9 22652942Sralph #define SCRIPT_REPLY_SYNC 11 22752889Sbostic #define SCRIPT_TRY_SYNC 12 22852942Sralph #define SCRIPT_DISCONNECT 15 22952942Sralph #define SCRIPT_RESEL 16 23052942Sralph #define SCRIPT_RESUME_IN 17 23152942Sralph #define SCRIPT_RESUME_DMA_IN 18 23252942Sralph #define SCRIPT_RESUME_OUT 19 23352942Sralph #define SCRIPT_RESUME_DMA_OUT 20 23452942Sralph #define SCRIPT_RESUME_NO_DATA 21 23552889Sbostic 23652889Sbostic /* 23752889Sbostic * Scripts 23852889Sbostic */ 23952889Sbostic script_t asc_scripts[] = { 24052942Sralph /* start data in */ 24152889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 24252889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 24352942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 24452889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 24552889Sbostic asc_last_dma_in, ASC_CMD_I_COMPLETE, 24652942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 24752889Sbostic 24858570Sralph /* continue data in after a chunk is finished */ 24952942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 25052942Sralph asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 25152942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 25252942Sralph 25352942Sralph /* start data out */ 25452942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 25552889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 25652942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 25752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 25852889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 25952942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 26052889Sbostic 26158570Sralph /* continue data out after a chunk is finished */ 26252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 26352942Sralph asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 26452942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 26552942Sralph 26652889Sbostic /* simple command with no data transfer */ 26752942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 26852889Sbostic script_nop, ASC_CMD_I_COMPLETE, 26952942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 27052889Sbostic 27152889Sbostic /* get status and finish command */ 27252942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 27352889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 27452942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 27552942Sralph {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 27652889Sbostic asc_end, ASC_CMD_NOP, 27752942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 27852889Sbostic 27952889Sbostic /* message in */ 28052942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 28152942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 28252942Sralph &asc_scripts[SCRIPT_MSG_IN + 1]}, 28352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 28452889Sbostic script_nop, ASC_CMD_XFER_INFO, 28552942Sralph &asc_scripts[SCRIPT_MSG_IN]}, 28652889Sbostic 28752889Sbostic /* send synchonous negotiation reply */ 28852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 28952889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 29052942Sralph &asc_scripts[SCRIPT_REPLY_SYNC]}, 29152889Sbostic 29252889Sbostic /* try to negotiate synchonous transfer parameters */ 29352889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 29452889Sbostic asc_sendsync, ASC_CMD_XFER_INFO, 29553080Sralph &asc_scripts[SCRIPT_TRY_SYNC + 1]}, 29653080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ 29752889Sbostic script_nop, ASC_CMD_XFER_INFO, 29853080Sralph &asc_scripts[SCRIPT_MSG_IN]}, 29953080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ 30053080Sralph script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 30153080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]}, 30252889Sbostic 30352942Sralph /* handle a disconnect */ 30452942Sralph {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 30552942Sralph asc_disconnect, ASC_CMD_ENABLE_SEL, 30652942Sralph &asc_scripts[SCRIPT_RESEL]}, 30752942Sralph 30852889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 30952942Sralph {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 31052889Sbostic script_nop, ASC_CMD_MSG_ACPT, 31152942Sralph &asc_scripts[SCRIPT_RESEL]}, 31252889Sbostic 31352942Sralph /* resume data in after a message */ 31452942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 31552942Sralph asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 31652942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 31752942Sralph 31852942Sralph /* resume partial DMA data in after a message */ 31952942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 32052889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32152942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 32252889Sbostic 32352942Sralph /* resume data out after a message */ 32452942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 32552942Sralph asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32652942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 32752942Sralph 32852942Sralph /* resume partial DMA data out after a message */ 32952942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 33052889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 33152942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 33252942Sralph 33352942Sralph /* resume after a message when there is no more data */ 33452942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 33552942Sralph script_nop, ASC_CMD_I_COMPLETE, 33652942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 33752889Sbostic }; 33852889Sbostic 33952889Sbostic /* 34052889Sbostic * State kept for each active SCSI device. 34152889Sbostic */ 34252889Sbostic typedef struct scsi_state { 34352889Sbostic script_t *script; /* saved script while processing error */ 34452889Sbostic int statusByte; /* status byte returned during STATUS_PHASE */ 34552889Sbostic int error; /* errno to pass back to device driver */ 34652889Sbostic u_char *dmaBufAddr; /* DMA buffer address */ 34752889Sbostic u_int dmaBufSize; /* DMA buffer size */ 34852889Sbostic int dmalen; /* amount to transfer in this chunk */ 34952889Sbostic int dmaresid; /* amount not transfered if chunk suspended */ 35052889Sbostic int buflen; /* total remaining amount of data to transfer */ 35152889Sbostic char *buf; /* current pointer within scsicmd->buf */ 35252889Sbostic int flags; /* see below */ 35352889Sbostic int msglen; /* number of message bytes to read */ 35452889Sbostic int msgcnt; /* number of message bytes received */ 35552889Sbostic u_char sync_period; /* DMA synchronous period */ 35652889Sbostic u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 35752889Sbostic u_char msg_out; /* next MSG_OUT byte to send */ 35852889Sbostic u_char msg_in[16]; /* buffer for multibyte messages */ 35952889Sbostic } State; 36052889Sbostic 36152889Sbostic /* state flags */ 36252889Sbostic #define DISCONN 0x01 /* true if currently disconnected from bus */ 36353080Sralph #define DMA_IN_PROGRESS 0x02 /* true if data DMA started */ 36452889Sbostic #define DMA_IN 0x04 /* true if reading from SCSI device */ 36552889Sbostic #define DMA_OUT 0x10 /* true if writing to SCSI device */ 36652889Sbostic #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 36752889Sbostic #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 36858658Sralph #define PARITY_ERR 0x80 /* true if parity error seen */ 36952889Sbostic 37052889Sbostic /* 37152889Sbostic * State kept for each active SCSI host interface (53C94). 37252889Sbostic */ 37352889Sbostic struct asc_softc { 37452889Sbostic asc_regmap_t *regs; /* chip address */ 37552889Sbostic volatile int *dmar; /* DMA address register address */ 37656819Sralph u_char *buff; /* RAM buffer address (uncached) */ 37752889Sbostic int myid; /* SCSI ID of this interface */ 37852889Sbostic int myidmask; /* ~(1 << myid) */ 37952889Sbostic int state; /* current SCSI connection state */ 38052889Sbostic int target; /* target SCSI ID if busy */ 38152889Sbostic script_t *script; /* next expected interrupt & action */ 38252889Sbostic ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 38352889Sbostic State st[ASC_NCMD]; /* state info for each active command */ 38456819Sralph void (*dma_start)(); /* Start dma routine */ 38556819Sralph void (*dma_end)(); /* End dma routine */ 38656819Sralph u_char *dma_next; 38756819Sralph int dma_xfer; /* Dma len still to go */ 38856819Sralph int min_period; /* Min transfer period clk/byte */ 38956819Sralph int max_period; /* Max transfer period clk/byte */ 39056819Sralph int ccf; /* CCF, whatever that really is? */ 39156819Sralph int timeout_250; /* 250ms timeout */ 39256819Sralph int tb_ticks; /* 4ns. ticks/tb channel ticks */ 39352889Sbostic } asc_softc[NASC]; 39452889Sbostic 39552889Sbostic #define ASC_STATE_IDLE 0 /* idle state */ 39652889Sbostic #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 39752889Sbostic #define ASC_STATE_TARGET 2 /* currently selected as target */ 39852889Sbostic #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 39952889Sbostic 40052889Sbostic typedef struct asc_softc *asc_softc_t; 40152889Sbostic 40252889Sbostic /* 40356819Sralph * Dma operations. 40456819Sralph */ 40556819Sralph #define ASCDMA_READ 1 40656819Sralph #define ASCDMA_WRITE 2 40756819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end(); 40857233Sralph extern u_long asc_iomem; 40957233Sralph extern u_long asic_base; 41056819Sralph 41156819Sralph /* 41252889Sbostic * Definition of the controller for the auto-configuration program. 41352889Sbostic */ 41452889Sbostic int asc_probe(); 41552889Sbostic void asc_start(); 41652889Sbostic void asc_intr(); 41752889Sbostic struct driver ascdriver = { 41852889Sbostic "asc", asc_probe, asc_start, 0, asc_intr, 41952889Sbostic }; 42052889Sbostic 42152889Sbostic /* 42252889Sbostic * Test to see if device is present. 42352889Sbostic * Return true if found and initialized ok. 42452889Sbostic */ 42552889Sbostic asc_probe(cp) 42652889Sbostic register struct pmax_ctlr *cp; 42752889Sbostic { 42852889Sbostic register asc_softc_t asc; 42952889Sbostic register asc_regmap_t *regs; 43052889Sbostic int unit, id, s, i; 43157233Sralph int bufsiz; 43252889Sbostic 43352889Sbostic if ((unit = cp->pmax_unit) >= NASC) 43452889Sbostic return (0); 43552889Sbostic if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 43652889Sbostic return (0); 43752889Sbostic asc = &asc_softc[unit]; 43852889Sbostic 43952889Sbostic /* 44052889Sbostic * Initialize hw descriptor, cache some pointers 44152889Sbostic */ 44252889Sbostic asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 44352889Sbostic 44456819Sralph /* 44556819Sralph * Set up machine dependencies. 44656819Sralph * 1) how to do dma 44756819Sralph * 2) timing based on turbochannel frequency 44856819Sralph */ 44956819Sralph switch (pmax_boardtype) { 45056819Sralph case DS_3MIN: 45156819Sralph case DS_MAXINE: 45257233Sralph case DS_3MAXPLUS: 45356819Sralph if (unit == 0) { 45457233Sralph asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); 45557233Sralph bufsiz = 8192; 45657233Sralph *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 45757233Sralph *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 45857233Sralph *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 45956819Sralph asc->dma_start = asic_dma_start; 46056819Sralph asc->dma_end = asic_dma_end; 46156819Sralph break; 46256819Sralph } 46356819Sralph /* 46456819Sralph * Fall through for turbochannel option. 46556819Sralph */ 46656819Sralph case DS_3MAX: 46756819Sralph default: 46856819Sralph asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 46956819Sralph asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 47057233Sralph bufsiz = PER_TGT_DMA_SIZE; 47156819Sralph asc->dma_start = tb_dma_start; 47256819Sralph asc->dma_end = tb_dma_end; 47356819Sralph }; 47456819Sralph /* 47556819Sralph * Now for timing. The 3max has a 25Mhz tb whereas the 3min and 47656819Sralph * maxine are 12.5Mhz. 47756819Sralph */ 47856819Sralph switch (pmax_boardtype) { 47956819Sralph case DS_3MAX: 48057233Sralph case DS_3MAXPLUS: 48156819Sralph asc->min_period = ASC_MIN_PERIOD25; 48256819Sralph asc->max_period = ASC_MAX_PERIOD25; 48356819Sralph asc->ccf = ASC_CCF(25); 48456819Sralph asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf); 48556819Sralph asc->tb_ticks = 10; 48656819Sralph break; 48756819Sralph case DS_3MIN: 48856819Sralph case DS_MAXINE: 48956819Sralph default: 49056819Sralph asc->min_period = ASC_MIN_PERIOD12; 49156819Sralph asc->max_period = ASC_MAX_PERIOD12; 49256819Sralph asc->ccf = ASC_CCF(13); 49356819Sralph asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); 49456819Sralph asc->tb_ticks = 20; 49556819Sralph break; 49656819Sralph }; 49756819Sralph 49852889Sbostic asc->state = ASC_STATE_IDLE; 49952889Sbostic asc->target = -1; 50052889Sbostic 50152889Sbostic regs = asc->regs; 50252889Sbostic 50352889Sbostic /* 50452889Sbostic * Reset chip, fully. Note that interrupts are already enabled. 50552889Sbostic */ 50652889Sbostic s = splbio(); 50752889Sbostic 50852889Sbostic /* preserve our ID for now */ 50952889Sbostic asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 51052889Sbostic asc->myidmask = ~(1 << asc->myid); 51152889Sbostic 51252889Sbostic asc_reset(asc, regs); 51352889Sbostic 51452889Sbostic /* 51552889Sbostic * Our SCSI id on the bus. 51652889Sbostic * The user can set this via the prom on 3maxen/pmaxen. 51752889Sbostic * If this changes it is easy to fix: make a default that 51852889Sbostic * can be changed as boot arg. 51952889Sbostic */ 52052889Sbostic #ifdef unneeded 52152889Sbostic regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 52252889Sbostic (scsi_initiator_id[unit] & 0x7); 52352889Sbostic #endif 52452889Sbostic id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 52552889Sbostic splx(s); 52652889Sbostic 52752889Sbostic /* 52852889Sbostic * Statically partition the DMA buffer between targets. 52952889Sbostic * This way we will eventually be able to attach/detach 53052889Sbostic * drives on-fly. And 18k/target is plenty for normal use. 53152889Sbostic */ 53252889Sbostic 53352889Sbostic /* 53452889Sbostic * Give each target its own DMA buffer region. 53552889Sbostic * We may want to try ping ponging buffers later. 53652889Sbostic */ 53752889Sbostic for (i = 0; i < ASC_NCMD; i++) { 53857233Sralph asc->st[i].dmaBufAddr = asc->buff + bufsiz * i; 53957233Sralph asc->st[i].dmaBufSize = bufsiz; 54052889Sbostic } 54152889Sbostic printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 54252889Sbostic unit, cp->pmax_addr, cp->pmax_pri, id); 54352889Sbostic return (1); 54452889Sbostic } 54552889Sbostic 54652889Sbostic /* 54752889Sbostic * Start activity on a SCSI device. 54852889Sbostic * We maintain information on each device separately since devices can 54952889Sbostic * connect/disconnect during an operation. 55052889Sbostic */ 55152889Sbostic void 55252889Sbostic asc_start(scsicmd) 55352889Sbostic register ScsiCmd *scsicmd; /* command to start */ 55452889Sbostic { 55552889Sbostic register struct scsi_device *sdp = scsicmd->sd; 55652889Sbostic register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 55752889Sbostic int s; 55852889Sbostic 55952889Sbostic s = splbio(); 56052889Sbostic /* 56152889Sbostic * Check if another command is already in progress. 56252889Sbostic * We may have to change this if we allow SCSI devices with 56352889Sbostic * separate LUNs. 56452889Sbostic */ 56552889Sbostic if (asc->cmd[sdp->sd_drive]) { 56652889Sbostic printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 56752889Sbostic sdp->sd_driver->d_name); 56852889Sbostic (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 56952889Sbostic scsicmd->buflen, 0); 57052889Sbostic splx(s); 57152889Sbostic } 57252889Sbostic asc->cmd[sdp->sd_drive] = scsicmd; 57352889Sbostic asc_startcmd(asc, sdp->sd_drive); 57452889Sbostic splx(s); 57552889Sbostic } 57652889Sbostic 57752889Sbostic static void 57852889Sbostic asc_reset(asc, regs) 57952889Sbostic asc_softc_t asc; 58052889Sbostic asc_regmap_t *regs; 58152889Sbostic { 58252889Sbostic 58352889Sbostic /* 58452889Sbostic * Reset chip and wait till done 58552889Sbostic */ 58652889Sbostic regs->asc_cmd = ASC_CMD_RESET; 58752889Sbostic MachEmptyWriteBuffer(); DELAY(25); 58852889Sbostic 58952889Sbostic /* spec says this is needed after reset */ 59052889Sbostic regs->asc_cmd = ASC_CMD_NOP; 59152889Sbostic MachEmptyWriteBuffer(); DELAY(25); 59252889Sbostic 59352889Sbostic /* 59452889Sbostic * Set up various chip parameters 59552889Sbostic */ 59656819Sralph regs->asc_ccf = asc->ccf; 59752889Sbostic MachEmptyWriteBuffer(); DELAY(25); 59856819Sralph regs->asc_sel_timo = asc->timeout_250; 59952889Sbostic /* restore our ID */ 60052889Sbostic regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 60157233Sralph /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ 60257233Sralph regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; 60352889Sbostic regs->asc_cnfg3 = 0; 60452889Sbostic /* zero anything else */ 60552889Sbostic ASC_TC_PUT(regs, 0); 60656819Sralph regs->asc_syn_p = asc->min_period; 60752889Sbostic regs->asc_syn_o = 0; /* async for now */ 60852889Sbostic MachEmptyWriteBuffer(); 60952889Sbostic } 61052889Sbostic 61152889Sbostic /* 61252889Sbostic * Start a SCSI command on a target. 61352889Sbostic */ 61452889Sbostic static void 61552889Sbostic asc_startcmd(asc, target) 61652889Sbostic asc_softc_t asc; 61752889Sbostic int target; 61852889Sbostic { 61952889Sbostic register asc_regmap_t *regs; 62052889Sbostic register ScsiCmd *scsicmd; 62152889Sbostic register State *state; 62252889Sbostic int len; 62352889Sbostic 62452889Sbostic /* 62552889Sbostic * See if another target is currently selected on this SCSI bus. 62652889Sbostic */ 62752889Sbostic if (asc->target >= 0) 62852889Sbostic return; 62952889Sbostic 63052889Sbostic regs = asc->regs; 63152889Sbostic 63252889Sbostic /* 63358658Sralph * If a reselection is in progress, it is Ok to ignore it since 63458658Sralph * the ASC will automatically cancel the command and flush 63558658Sralph * the FIFO if the ASC is reselected before the command starts. 63658658Sralph * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if 63758658Sralph * a reselect occurs before starting the command. 63852889Sbostic */ 63952889Sbostic 64052889Sbostic asc->state = ASC_STATE_BUSY; 64152889Sbostic asc->target = target; 64252889Sbostic 64352889Sbostic /* cache some pointers */ 64452889Sbostic scsicmd = asc->cmd[target]; 64552889Sbostic state = &asc->st[target]; 64652889Sbostic 64752889Sbostic #ifdef DEBUG 64852889Sbostic if (asc_debug > 1) { 64952889Sbostic printf("asc_startcmd: %s target %d cmd %x len %d\n", 65052889Sbostic scsicmd->sd->sd_driver->d_name, target, 65152889Sbostic scsicmd->cmd[0], scsicmd->buflen); 65252889Sbostic } 65352889Sbostic #endif 65452889Sbostic 65552889Sbostic /* 65652889Sbostic * Init the chip and target state. 65752889Sbostic */ 65853080Sralph state->flags = state->flags & DID_SYNC; 65952889Sbostic state->error = 0; 66052889Sbostic state->script = (script_t *)0; 66152889Sbostic state->msg_out = SCSI_NO_OP; 66252889Sbostic 66352889Sbostic /* 66452889Sbostic * Copy command data to the DMA buffer. 66552889Sbostic */ 66660301Sralph len = scsicmd->cmdlen; 66752889Sbostic state->dmalen = len; 66860301Sralph bcopy(scsicmd->cmd, state->dmaBufAddr, len); 66952889Sbostic 67052889Sbostic /* check for simple SCSI command with no data transfer */ 67152889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 67252889Sbostic /* check for sync negotiation */ 67352889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 67452889Sbostic !(state->flags & DID_SYNC)) { 67552889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 67652889Sbostic state->flags |= TRY_SYNC; 67752889Sbostic } else 67852889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 67952889Sbostic state->buf = (char *)0; 68052889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 68152889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 68253080Sralph state->buf = scsicmd->buf; 68352889Sbostic state->flags |= DMA_OUT; 68452889Sbostic } else { 68552889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 68652889Sbostic state->buf = scsicmd->buf; 68752889Sbostic state->flags |= DMA_IN; 68852889Sbostic } 68952889Sbostic 69058792Sralph #ifdef DEBUG 69158792Sralph asc_debug_cmd = scsicmd->cmd[0]; 69258792Sralph if (scsicmd->cmd[0] == SCSI_READ_EXT) { 69358792Sralph asc_debug_bn = (scsicmd->cmd[2] << 24) | 69458792Sralph (scsicmd->cmd[3] << 16) | 69558792Sralph (scsicmd->cmd[4] << 8) | 69658792Sralph scsicmd->cmd[5]; 69758792Sralph asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 69858792Sralph } 69958792Sralph asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 70058792Sralph asc_logp->target = asc->target; 70158792Sralph asc_logp->state = asc->script - asc_scripts; 70258792Sralph asc_logp->msg = SCSI_DIS_REC_IDENTIFY; 70358792Sralph asc_logp->resid = scsicmd->buflen; 70458792Sralph if (++asc_logp >= &asc_log[NLOG]) 70558792Sralph asc_logp = asc_log; 70658792Sralph #endif 70752889Sbostic 70860301Sralph /* preload the FIFO with the message to be sent */ 70960301Sralph regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 71060301Sralph MachEmptyWriteBuffer(); 71160301Sralph 71258792Sralph /* initialize the DMA */ 71356819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 71452889Sbostic ASC_TC_PUT(regs, len); 71556819Sralph readback(regs->asc_cmd); 71652889Sbostic 71752889Sbostic regs->asc_dbus_id = target; 71856819Sralph readback(regs->asc_dbus_id); 71952889Sbostic regs->asc_syn_p = state->sync_period; 72056819Sralph readback(regs->asc_syn_p); 72152889Sbostic regs->asc_syn_o = state->sync_offset; 72256819Sralph readback(regs->asc_syn_o); 72352889Sbostic 72452889Sbostic if (state->flags & TRY_SYNC) 72553080Sralph regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 72652889Sbostic else 72752889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 72856819Sralph readback(regs->asc_cmd); 72952889Sbostic } 73052889Sbostic 73152889Sbostic /* 73252889Sbostic * Interrupt routine 73352889Sbostic * Take interrupts from the chip 73452889Sbostic * 73552889Sbostic * Implementation: 73652889Sbostic * Move along the current command's script if 73752889Sbostic * all is well, invoke error handler if not. 73852889Sbostic */ 73952889Sbostic void 74052889Sbostic asc_intr(unit) 74152889Sbostic int unit; 74252889Sbostic { 74352889Sbostic register asc_softc_t asc = &asc_softc[unit]; 74452889Sbostic register asc_regmap_t *regs = asc->regs; 74552889Sbostic register State *state; 74652889Sbostic register script_t *scpt; 74752889Sbostic register int ss, ir, status; 74852889Sbostic 74952889Sbostic /* collect ephemeral information */ 75052889Sbostic status = regs->asc_status; 75153080Sralph again: 75252889Sbostic ss = regs->asc_ss; 75352889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 75452889Sbostic scpt = asc->script; 75552889Sbostic 75652889Sbostic #ifdef DEBUG 75752889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 75852889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 75952889Sbostic asc_logp->state = scpt - asc_scripts; 76052889Sbostic asc_logp->msg = -1; 76158658Sralph asc_logp->resid = 0; 76252889Sbostic if (++asc_logp >= &asc_log[NLOG]) 76352889Sbostic asc_logp = asc_log; 76452889Sbostic if (asc_debug > 2) 76552889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 76652889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 76752889Sbostic #endif 76852889Sbostic 76952889Sbostic /* check the expected state */ 77052889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 77152889Sbostic /* 77252889Sbostic * Perform the appropriate operation, then proceed. 77352889Sbostic */ 77452889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 77552889Sbostic regs->asc_cmd = scpt->command; 77656819Sralph readback(regs->asc_cmd); 77752889Sbostic asc->script = scpt->next; 77852889Sbostic } 77952889Sbostic goto done; 78052889Sbostic } 78152889Sbostic 78258658Sralph /* 78358658Sralph * Check for parity error. 78458658Sralph * Hardware will automatically set ATN 78558658Sralph * to request the device for a MSG_OUT phase. 78658658Sralph */ 78758658Sralph if (status & ASC_CSR_PE) { 78858658Sralph printf("asc%d: SCSI device %d: incomming parity error seen\n", 78958658Sralph asc - asc_softc, asc->target); 79058658Sralph asc->st[asc->target].flags |= PARITY_ERR; 79158658Sralph } 79258658Sralph 79358658Sralph /* 79458658Sralph * Check for gross error. 79558658Sralph * Probably a bug in a device driver. 79658658Sralph */ 79758658Sralph if (status & ASC_CSR_GE) { 79858658Sralph printf("asc%d: SCSI device %d: gross error\n", 79958658Sralph asc - asc_softc, asc->target); 80058658Sralph goto abort; 80158658Sralph } 80258658Sralph 80352889Sbostic /* check for message in or out */ 80452889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 80552889Sbostic register int len, fifo; 80652889Sbostic 80752889Sbostic state = &asc->st[asc->target]; 80852889Sbostic switch (ASC_PHASE(status)) { 80953080Sralph case ASC_PHASE_DATAI: 81053080Sralph case ASC_PHASE_DATAO: 81153080Sralph ASC_TC_GET(regs, len); 81253080Sralph fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 81353080Sralph printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 81453080Sralph state->buflen, state->dmalen, len, fifo); 81553080Sralph goto abort; 81653080Sralph 81752889Sbostic case ASC_PHASE_MSG_IN: 81852889Sbostic break; 81952889Sbostic 82052889Sbostic case ASC_PHASE_MSG_OUT: 82158658Sralph /* 82258658Sralph * Check for parity error. 82358658Sralph * Hardware will automatically set ATN 82458658Sralph * to request the device for a MSG_OUT phase. 82558658Sralph */ 82658658Sralph if (state->flags & PARITY_ERR) { 82758658Sralph state->flags &= ~PARITY_ERR; 82858658Sralph state->msg_out = SCSI_MESSAGE_PARITY_ERROR; 82958658Sralph /* reset message in counter */ 83058658Sralph state->msglen = 0; 83158658Sralph } else 83258658Sralph state->msg_out = SCSI_NO_OP; 83352889Sbostic regs->asc_fifo = state->msg_out; 83452889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 83556819Sralph readback(regs->asc_cmd); 83652889Sbostic goto done; 83752889Sbostic 83852889Sbostic case ASC_PHASE_STATUS: 83952889Sbostic /* probably an error in the SCSI command */ 84052889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 84152889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 84256819Sralph readback(regs->asc_cmd); 84352889Sbostic goto done; 84452889Sbostic 84552889Sbostic default: 84652889Sbostic goto abort; 84752889Sbostic } 84852889Sbostic 84952889Sbostic if (state->script) 85052889Sbostic goto abort; 85152889Sbostic 85252889Sbostic /* check for DMA in progress */ 85352889Sbostic ASC_TC_GET(regs, len); 85452889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 85552889Sbostic /* flush any data in the FIFO */ 85652889Sbostic if (fifo) { 85753080Sralph if (state->flags & DMA_OUT) 85853080Sralph len += fifo; 85953080Sralph else if (state->flags & DMA_IN) { 86053080Sralph u_char *cp; 86153080Sralph 86253080Sralph printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 86353080Sralph state->dmalen, len, fifo); /* XXX */ 86453080Sralph len += fifo; 86553080Sralph cp = state->dmaBufAddr + (state->dmalen - len); 86653080Sralph while (fifo-- > 0) 86753080Sralph *cp++ = regs->asc_fifo; 86853080Sralph } else 86953080Sralph printf("asc_intr: dmalen %d len %d fifo %d\n", 87053080Sralph state->dmalen, len, fifo); /* XXX */ 87152889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 87256819Sralph readback(regs->asc_cmd); 87356819Sralph DELAY(2); 87452889Sbostic } 87552889Sbostic if (len) { 87652889Sbostic /* save number of bytes still to be sent or received */ 87752889Sbostic state->dmaresid = len; 87858792Sralph #ifdef DEBUG 87958792Sralph if (asc_logp == asc_log) 88058792Sralph asc_log[NLOG - 1].resid = len; 88158792Sralph else 88258792Sralph asc_logp[-1].resid = len; 88358792Sralph #endif 88452889Sbostic /* setup state to resume to */ 88558792Sralph if (state->flags & DMA_IN) { 88658792Sralph /* 88758792Sralph * Since the ASC_CNFG3_SRB bit of the 88858792Sralph * cnfg3 register bit is not set, 88958792Sralph * we just transferred an extra byte. 89058792Sralph * Since we can't resume on an odd byte 89158792Sralph * boundary, we copy the valid data out 89258792Sralph * and resume DMA at the start address. 89358792Sralph */ 89458792Sralph if (len & 1) { 89558792Sralph printf("asc_intr: msg in len %d (fifo %d)\n", 89658792Sralph len, fifo); 89758792Sralph len = state->dmalen - len; 89858792Sralph goto do_in; 89958792Sralph } 90052889Sbostic state->script = 90152889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 90258792Sralph } else if (state->flags & DMA_OUT) 90352889Sbostic state->script = 90452889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 90552889Sbostic else 90652889Sbostic state->script = asc->script; 90752889Sbostic } else { 90852889Sbostic /* setup state to resume to */ 90952942Sralph if (state->flags & DMA_IN) { 91053080Sralph if (state->flags & DMA_IN_PROGRESS) { 91158792Sralph len = state->dmalen; 91258792Sralph do_in: 91353080Sralph state->flags &= ~DMA_IN_PROGRESS; 91456819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 91552942Sralph bcopy(state->dmaBufAddr, state->buf, 91652942Sralph len); 91752942Sralph state->buf += len; 91852942Sralph state->buflen -= len; 91953080Sralph } 92052942Sralph if (state->buflen) 92152942Sralph state->script = 92252942Sralph &asc_scripts[SCRIPT_RESUME_IN]; 92352942Sralph else 92452942Sralph state->script = 92552942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 92652942Sralph } else if (state->flags & DMA_OUT) { 92752942Sralph /* 92852942Sralph * If this is the last chunk, the next expected 92952942Sralph * state is to get status. 93052942Sralph */ 93153080Sralph if (state->flags & DMA_IN_PROGRESS) { 93253080Sralph state->flags &= ~DMA_IN_PROGRESS; 93356819Sralph (*asc->dma_end)(asc, state, ASCDMA_WRITE); 93453080Sralph len = state->dmalen; 93553080Sralph state->buf += len; 93653080Sralph state->buflen -= len; 93753080Sralph } 93852942Sralph if (state->buflen) 93952942Sralph state->script = 94052942Sralph &asc_scripts[SCRIPT_RESUME_OUT]; 94152942Sralph else 94252942Sralph state->script = 94352942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 94453080Sralph } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 94553080Sralph state->script = 94658658Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 94753080Sralph else 94852889Sbostic state->script = asc->script; 94952889Sbostic } 95052889Sbostic 95152889Sbostic /* setup to receive a message */ 95252889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 95352889Sbostic state->msglen = 0; 95452889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 95556819Sralph readback(regs->asc_cmd); 95652889Sbostic goto done; 95752889Sbostic } 95852889Sbostic 95952889Sbostic /* check for SCSI bus reset */ 96052889Sbostic if (ir & ASC_INT_RESET) { 96152889Sbostic register int i; 96252889Sbostic 96352889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 96452889Sbostic /* need to flush any pending commands */ 96552889Sbostic for (i = 0; i < ASC_NCMD; i++) { 96652889Sbostic if (!asc->cmd[i]) 96752889Sbostic continue; 96852889Sbostic asc->st[i].error = EIO; 96952889Sbostic asc_end(asc, 0, 0, 0); 97052889Sbostic } 97152889Sbostic /* rearbitrate synchronous offset */ 97252889Sbostic for (i = 0; i < ASC_NCMD; i++) { 97352889Sbostic asc->st[i].sync_offset = 0; 97452889Sbostic asc->st[i].flags = 0; 97552889Sbostic } 97652889Sbostic asc->target = -1; 97752889Sbostic return; 97852889Sbostic } 97952889Sbostic 98052889Sbostic /* check for command errors */ 98152889Sbostic if (ir & ASC_INT_ILL) 98252889Sbostic goto abort; 98352889Sbostic 98452889Sbostic /* check for disconnect */ 98552889Sbostic if (ir & ASC_INT_DISC) { 98652889Sbostic state = &asc->st[asc->target]; 98752889Sbostic switch (ASC_SS(ss)) { 98852889Sbostic case 0: /* device did not respond */ 98958658Sralph /* check for one of the starting scripts */ 99058658Sralph switch (asc->script - asc_scripts) { 99158658Sralph case SCRIPT_TRY_SYNC: 99258658Sralph case SCRIPT_SIMPLE: 99358658Sralph case SCRIPT_DATA_IN: 99458658Sralph case SCRIPT_DATA_OUT: 99558658Sralph if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { 99658658Sralph regs->asc_cmd = ASC_CMD_FLUSH; 99758658Sralph readback(regs->asc_cmd); 99858658Sralph } 99958658Sralph state->error = ENXIO; 100058658Sralph asc_end(asc, status, ss, ir); 100158658Sralph return; 100258658Sralph } 100358658Sralph /* FALLTHROUGH */ 100452889Sbostic 100552889Sbostic default: 100658658Sralph printf("asc%d: SCSI device %d: unexpected disconnect\n", 100758658Sralph asc - asc_softc, asc->target); 100857233Sralph /* 100957233Sralph * On rare occasions my RZ24 does a disconnect during 101057233Sralph * data in phase and the following seems to keep it 101157233Sralph * happy. 101257233Sralph * XXX Should a scsi disk ever do this?? 101357233Sralph */ 101457233Sralph asc->script = &asc_scripts[SCRIPT_RESEL]; 101557233Sralph asc->state = ASC_STATE_RESEL; 101657233Sralph state->flags |= DISCONN; 101757233Sralph regs->asc_cmd = ASC_CMD_ENABLE_SEL; 101857233Sralph readback(regs->asc_cmd); 101957233Sralph return; 102052889Sbostic } 102152889Sbostic } 102252889Sbostic 102352889Sbostic /* check for reselect */ 102452889Sbostic if (ir & ASC_INT_RESEL) { 102552889Sbostic unsigned fifo, id, msg; 102652889Sbostic 102752889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 102852889Sbostic if (fifo < 2) 102952889Sbostic goto abort; 103052889Sbostic /* read unencoded SCSI ID and convert to binary */ 103152889Sbostic msg = regs->asc_fifo & asc->myidmask; 103252889Sbostic for (id = 0; (msg & 1) == 0; id++) 103352889Sbostic msg >>= 1; 103452889Sbostic /* read identify message */ 103552889Sbostic msg = regs->asc_fifo; 103652889Sbostic #ifdef DEBUG 103752889Sbostic if (asc_logp == asc_log) 103852889Sbostic asc_log[NLOG - 1].msg = msg; 103952889Sbostic else 104052889Sbostic asc_logp[-1].msg = msg; 104152889Sbostic #endif 104252889Sbostic asc->state = ASC_STATE_BUSY; 104352889Sbostic asc->target = id; 104452889Sbostic state = &asc->st[id]; 104552889Sbostic asc->script = state->script; 104652889Sbostic state->script = (script_t *)0; 104752889Sbostic if (!(state->flags & DISCONN)) 104852889Sbostic goto abort; 104952889Sbostic state->flags &= ~DISCONN; 105053080Sralph regs->asc_syn_p = state->sync_period; 105153080Sralph regs->asc_syn_o = state->sync_offset; 105252889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 105356819Sralph readback(regs->asc_cmd); 105452889Sbostic goto done; 105552889Sbostic } 105652889Sbostic 105752889Sbostic /* check if we are being selected as a target */ 105852889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 105952889Sbostic goto abort; 106052889Sbostic 106158658Sralph /* 106258658Sralph * 'ir' must be just ASC_INT_FC. 106358658Sralph * This is normal if canceling an ASC_ENABLE_SEL. 106458658Sralph */ 106558658Sralph 106652889Sbostic done: 106752889Sbostic MachEmptyWriteBuffer(); 106853080Sralph /* watch out for HW race conditions and setup & hold time violations */ 106953080Sralph ir = regs->asc_status; 107053080Sralph while (ir != (status = regs->asc_status)) 107153080Sralph ir = status; 107253080Sralph if (status & ASC_CSR_INT) 107352889Sbostic goto again; 107452889Sbostic return; 107552889Sbostic 107652889Sbostic abort: 107752889Sbostic #ifdef DEBUG 107852889Sbostic asc_DumpLog("asc_intr"); 107952889Sbostic #endif 108052889Sbostic #if 0 108152889Sbostic panic("asc_intr"); 108252889Sbostic #else 108352889Sbostic for (;;); 108452889Sbostic #endif 108552889Sbostic } 108652889Sbostic 108752889Sbostic /* 108852889Sbostic * All the many little things that the interrupt 108952889Sbostic * routine might switch to. 109052889Sbostic */ 109152889Sbostic 109252889Sbostic /* ARGSUSED */ 109352889Sbostic static int 109452889Sbostic script_nop(asc, status, ss, ir) 109552889Sbostic register asc_softc_t asc; 109652889Sbostic register int status, ss, ir; 109752889Sbostic { 109852889Sbostic return (1); 109952889Sbostic } 110052889Sbostic 110152889Sbostic /* ARGSUSED */ 110252889Sbostic static int 110352889Sbostic asc_get_status(asc, status, ss, ir) 110452889Sbostic register asc_softc_t asc; 110552889Sbostic register int status, ss, ir; 110652889Sbostic { 110752889Sbostic register asc_regmap_t *regs = asc->regs; 110852889Sbostic register int data; 110952889Sbostic 111052889Sbostic /* 111152889Sbostic * Get the last two bytes in the FIFO. 111252889Sbostic */ 111352889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 111452889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 111558658Sralph asc_DumpLog("get_status"); /* XXX */ 111652889Sbostic if (data < 2) { 111752889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 111856819Sralph readback(asc->regs->asc_cmd); 111952889Sbostic return (0); 112052889Sbostic } 112152889Sbostic do { 112252889Sbostic data = regs->asc_fifo; 112352889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 112452889Sbostic } 112552889Sbostic 112652889Sbostic /* save the status byte */ 112752889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 112852889Sbostic #ifdef DEBUG 112952889Sbostic if (asc_logp == asc_log) 113052889Sbostic asc_log[NLOG - 1].msg = data; 113152889Sbostic else 113252889Sbostic asc_logp[-1].msg = data; 113352889Sbostic #endif 113452889Sbostic 113552889Sbostic /* get the (presumed) command_complete message */ 113652889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 113752889Sbostic return (1); 113852889Sbostic 113952889Sbostic #ifdef DEBUG 114052889Sbostic printf("asc_get_status: status %x cmd %x\n", 114152889Sbostic asc->st[asc->target].statusByte, data); 114252889Sbostic asc_DumpLog("asc_get_status"); 114352889Sbostic #endif 114452889Sbostic return (0); 114552889Sbostic } 114652889Sbostic 114752889Sbostic /* ARGSUSED */ 114852889Sbostic static int 114952889Sbostic asc_end(asc, status, ss, ir) 115052889Sbostic register asc_softc_t asc; 115152889Sbostic register int status, ss, ir; 115252889Sbostic { 115352889Sbostic register ScsiCmd *scsicmd; 115452889Sbostic register State *state; 115552889Sbostic register int i, target; 115652889Sbostic 115752889Sbostic asc->state = ASC_STATE_IDLE; 115852889Sbostic target = asc->target; 115952889Sbostic asc->target = -1; 116052889Sbostic scsicmd = asc->cmd[target]; 116152889Sbostic asc->cmd[target] = (ScsiCmd *)0; 116252889Sbostic state = &asc->st[target]; 116352889Sbostic 116452889Sbostic #ifdef DEBUG 116552889Sbostic if (asc_debug > 1) { 116652889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 116752889Sbostic scsicmd->sd->sd_driver->d_name, target, 116852889Sbostic scsicmd->cmd[0], state->error, state->buflen); 116952889Sbostic } 117052889Sbostic #endif 117152889Sbostic #ifdef DIAGNOSTIC 117252889Sbostic if (target < 0 || !scsicmd) 117352889Sbostic panic("asc_end"); 117452889Sbostic #endif 117552889Sbostic 117652889Sbostic /* look for disconnected devices */ 117752889Sbostic for (i = 0; i < ASC_NCMD; i++) { 117852889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 117952889Sbostic continue; 118052889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 118156819Sralph readback(asc->regs->asc_cmd); 118252889Sbostic asc->state = ASC_STATE_RESEL; 118352889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 118452889Sbostic break; 118552889Sbostic } 118652889Sbostic 118758658Sralph /* 118858658Sralph * Look for another device that is ready. 118958658Sralph * May want to keep last one started and increment for fairness 119058658Sralph * rather than always starting at zero. 119158658Sralph */ 119252889Sbostic for (i = 0; i < ASC_NCMD; i++) { 119352889Sbostic /* don't restart a disconnected command */ 119452889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 119552889Sbostic continue; 119652889Sbostic asc_startcmd(asc, i); 119752889Sbostic break; 119852889Sbostic } 119952889Sbostic 120052889Sbostic /* signal device driver that the command is done */ 120152889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 120252889Sbostic state->buflen, state->statusByte); 120352889Sbostic 120452889Sbostic return (0); 120552889Sbostic } 120652889Sbostic 120752889Sbostic /* ARGSUSED */ 120852889Sbostic static int 120952889Sbostic asc_dma_in(asc, status, ss, ir) 121052889Sbostic register asc_softc_t asc; 121152889Sbostic register int status, ss, ir; 121252889Sbostic { 121352889Sbostic register asc_regmap_t *regs = asc->regs; 121452889Sbostic register State *state = &asc->st[asc->target]; 121553080Sralph register int len; 121652889Sbostic 121752889Sbostic /* check for previous chunk in buffer */ 121853080Sralph if (state->flags & DMA_IN_PROGRESS) { 121952889Sbostic /* 122052889Sbostic * Only count bytes that have been copied to memory. 122152889Sbostic * There may be some bytes in the FIFO if synchonous transfers 122252889Sbostic * are in progress. 122352889Sbostic */ 122456819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 122552889Sbostic ASC_TC_GET(regs, len); 122652889Sbostic len = state->dmalen - len; 122752889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 122852889Sbostic state->buf += len; 122952889Sbostic state->buflen -= len; 123053080Sralph } 123152889Sbostic 123252942Sralph /* setup to start reading the next chunk */ 123352889Sbostic len = state->buflen; 123452889Sbostic if (len > state->dmaBufSize) 123552889Sbostic len = state->dmaBufSize; 123652889Sbostic state->dmalen = len; 123756819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 123852889Sbostic ASC_TC_PUT(regs, len); 123952942Sralph #ifdef DEBUG 124052942Sralph if (asc_debug > 2) 124152942Sralph printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 124252942Sralph #endif 124352942Sralph 124452942Sralph /* check for next chunk */ 124553080Sralph state->flags |= DMA_IN_PROGRESS; 124652889Sbostic if (len != state->buflen) { 124752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 124856819Sralph readback(regs->asc_cmd); 124952942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 125052889Sbostic return (0); 125152889Sbostic } 125252889Sbostic return (1); 125352889Sbostic } 125452889Sbostic 125552889Sbostic /* ARGSUSED */ 125652889Sbostic static int 125752889Sbostic asc_last_dma_in(asc, status, ss, ir) 125852889Sbostic register asc_softc_t asc; 125952889Sbostic register int status, ss, ir; 126052889Sbostic { 126152889Sbostic register asc_regmap_t *regs = asc->regs; 126252889Sbostic register State *state = &asc->st[asc->target]; 126352889Sbostic register int len, fifo; 126452889Sbostic 126552889Sbostic /* copy data from buffer to main memory */ 126656819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 126752889Sbostic ASC_TC_GET(regs, len); 126852889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 126952889Sbostic #ifdef DEBUG 127052942Sralph if (asc_debug > 2) 127152889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 127252889Sbostic state->buflen, state->dmalen, len, fifo); 127352889Sbostic #endif 127452889Sbostic if (fifo) { 127552942Sralph /* device must be trying to send more than we expect */ 127652889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 127756819Sralph readback(regs->asc_cmd); 127852889Sbostic } 127953080Sralph state->flags &= ~DMA_IN_PROGRESS; 128052889Sbostic len = state->dmalen - len; 128152889Sbostic state->buflen -= len; 128252889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 128352889Sbostic 128452889Sbostic return (1); 128552889Sbostic } 128652889Sbostic 128752889Sbostic /* ARGSUSED */ 128852889Sbostic static int 128952942Sralph asc_resume_in(asc, status, ss, ir) 129052942Sralph register asc_softc_t asc; 129152942Sralph register int status, ss, ir; 129252942Sralph { 129352942Sralph register asc_regmap_t *regs = asc->regs; 129452942Sralph register State *state = &asc->st[asc->target]; 129552942Sralph register int len; 129652942Sralph 129752942Sralph /* setup to start reading the next chunk */ 129852942Sralph len = state->buflen; 129952942Sralph if (len > state->dmaBufSize) 130052942Sralph len = state->dmaBufSize; 130152942Sralph state->dmalen = len; 130256819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 130352942Sralph ASC_TC_PUT(regs, len); 130452942Sralph #ifdef DEBUG 130552942Sralph if (asc_debug > 2) 130652942Sralph printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 130752942Sralph len); 130852942Sralph #endif 130952942Sralph 131052942Sralph /* check for next chunk */ 131153080Sralph state->flags |= DMA_IN_PROGRESS; 131252942Sralph if (len != state->buflen) { 131352942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 131456819Sralph readback(regs->asc_cmd); 131552942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 131652942Sralph return (0); 131752942Sralph } 131852942Sralph return (1); 131952942Sralph } 132052942Sralph 132152942Sralph /* ARGSUSED */ 132252942Sralph static int 132352889Sbostic asc_resume_dma_in(asc, status, ss, ir) 132452889Sbostic register asc_softc_t asc; 132552889Sbostic register int status, ss, ir; 132652889Sbostic { 132752889Sbostic register asc_regmap_t *regs = asc->regs; 132852889Sbostic register State *state = &asc->st[asc->target]; 132952889Sbostic register int len, off; 133052889Sbostic 133152889Sbostic /* setup to finish reading the current chunk */ 133252889Sbostic len = state->dmaresid; 133352889Sbostic off = state->dmalen - len; 133452889Sbostic if ((off & 1) && state->sync_offset) { 133552889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 133652889Sbostic state->dmalen, len, off); /* XXX */ 133752889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 133852889Sbostic } 133956819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 134052889Sbostic ASC_TC_PUT(regs, len); 134152942Sralph #ifdef DEBUG 134252942Sralph if (asc_debug > 2) 134352942Sralph printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 134452942Sralph state->dmalen, state->buflen, len, off); 134552942Sralph #endif 134652942Sralph 134752942Sralph /* check for next chunk */ 134853080Sralph state->flags |= DMA_IN_PROGRESS; 134952889Sbostic if (state->dmalen != state->buflen) { 135052889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 135156819Sralph readback(regs->asc_cmd); 135252942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 135352889Sbostic return (0); 135452889Sbostic } 135552889Sbostic return (1); 135652889Sbostic } 135752889Sbostic 135852889Sbostic /* ARGSUSED */ 135952889Sbostic static int 136052889Sbostic asc_dma_out(asc, status, ss, ir) 136152889Sbostic register asc_softc_t asc; 136252889Sbostic register int status, ss, ir; 136352889Sbostic { 136452889Sbostic register asc_regmap_t *regs = asc->regs; 136552889Sbostic register State *state = &asc->st[asc->target]; 136652889Sbostic register int len, fifo; 136752889Sbostic 136853080Sralph if (state->flags & DMA_IN_PROGRESS) { 136952889Sbostic /* check to be sure previous chunk was finished */ 137052889Sbostic ASC_TC_GET(regs, len); 137152889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 137252889Sbostic if (len || fifo) 137352889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 137452889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 137552889Sbostic len += fifo; 137652889Sbostic len = state->dmalen - len; 137753080Sralph state->buf += len; 137852889Sbostic state->buflen -= len; 137953080Sralph } 138052889Sbostic 138158792Sralph /* setup for this chunk */ 138253080Sralph len = state->buflen; 138353080Sralph if (len > state->dmaBufSize) 138453080Sralph len = state->dmaBufSize; 138553080Sralph state->dmalen = len; 138653080Sralph bcopy(state->buf, state->dmaBufAddr, len); 138756819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 138852942Sralph ASC_TC_PUT(regs, len); 138952889Sbostic #ifdef DEBUG 139052889Sbostic if (asc_debug > 2) 139152942Sralph printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 139252889Sbostic #endif 139352889Sbostic 139452889Sbostic /* check for next chunk */ 139553080Sralph state->flags |= DMA_IN_PROGRESS; 139652889Sbostic if (len != state->buflen) { 139752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 139856819Sralph readback(regs->asc_cmd); 139952942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 140052889Sbostic return (0); 140152889Sbostic } 140252889Sbostic return (1); 140352889Sbostic } 140452889Sbostic 140552889Sbostic /* ARGSUSED */ 140652889Sbostic static int 140752889Sbostic asc_last_dma_out(asc, status, ss, ir) 140852889Sbostic register asc_softc_t asc; 140952889Sbostic register int status, ss, ir; 141052889Sbostic { 141152889Sbostic register asc_regmap_t *regs = asc->regs; 141252889Sbostic register State *state = &asc->st[asc->target]; 141352889Sbostic register int len, fifo; 141452889Sbostic 141552889Sbostic ASC_TC_GET(regs, len); 141652889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 141752889Sbostic #ifdef DEBUG 141852889Sbostic if (asc_debug > 2) 141952889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 142053080Sralph state->buflen, state->dmalen, len, fifo); 142152942Sralph #endif 142252942Sralph if (fifo) { 142352942Sralph len += fifo; 142452942Sralph regs->asc_cmd = ASC_CMD_FLUSH; 142556819Sralph readback(regs->asc_cmd); 142658792Sralph printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 142758792Sralph state->buflen, state->dmalen, len, fifo); 142852942Sralph } 142953080Sralph state->flags &= ~DMA_IN_PROGRESS; 143052889Sbostic len = state->dmalen - len; 143152889Sbostic state->buflen -= len; 143252889Sbostic return (1); 143352889Sbostic } 143452889Sbostic 143552889Sbostic /* ARGSUSED */ 143652889Sbostic static int 143752942Sralph asc_resume_out(asc, status, ss, ir) 143852942Sralph register asc_softc_t asc; 143952942Sralph register int status, ss, ir; 144052942Sralph { 144152942Sralph register asc_regmap_t *regs = asc->regs; 144252942Sralph register State *state = &asc->st[asc->target]; 144352942Sralph register int len; 144452942Sralph 144558792Sralph /* setup for this chunk */ 144652942Sralph len = state->buflen; 144752942Sralph if (len > state->dmaBufSize) 144852942Sralph len = state->dmaBufSize; 144952942Sralph state->dmalen = len; 145052942Sralph bcopy(state->buf, state->dmaBufAddr, len); 145156819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 145252942Sralph ASC_TC_PUT(regs, len); 145352942Sralph #ifdef DEBUG 145452942Sralph if (asc_debug > 2) 145552942Sralph printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 145652942Sralph len); 145752942Sralph #endif 145852942Sralph 145952942Sralph /* check for next chunk */ 146053080Sralph state->flags |= DMA_IN_PROGRESS; 146152942Sralph if (len != state->buflen) { 146252942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 146356819Sralph readback(regs->asc_cmd); 146452942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 146552942Sralph return (0); 146652942Sralph } 146752942Sralph return (1); 146852942Sralph } 146952942Sralph 147052942Sralph /* ARGSUSED */ 147152942Sralph static int 147252889Sbostic asc_resume_dma_out(asc, status, ss, ir) 147352889Sbostic register asc_softc_t asc; 147452889Sbostic register int status, ss, ir; 147552889Sbostic { 147652889Sbostic register asc_regmap_t *regs = asc->regs; 147752889Sbostic register State *state = &asc->st[asc->target]; 147852889Sbostic register int len, off; 147952889Sbostic 148052889Sbostic /* setup to finish writing this chunk */ 148152889Sbostic len = state->dmaresid; 148252889Sbostic off = state->dmalen - len; 148352889Sbostic if (off & 1) { 148452889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 148552889Sbostic state->dmalen, len, off); /* XXX */ 148652889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 148752889Sbostic off++; 148852889Sbostic len--; 148952889Sbostic } 149056819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 149152889Sbostic ASC_TC_PUT(regs, len); 149252942Sralph #ifdef DEBUG 149352942Sralph if (asc_debug > 2) 149452942Sralph printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 149552942Sralph state->dmalen, state->buflen, len, off); 149652942Sralph #endif 149752942Sralph 149852942Sralph /* check for next chunk */ 149953080Sralph state->flags |= DMA_IN_PROGRESS; 150052889Sbostic if (state->dmalen != state->buflen) { 150152889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 150256819Sralph readback(regs->asc_cmd); 150352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 150452889Sbostic return (0); 150552889Sbostic } 150652889Sbostic return (1); 150752889Sbostic } 150852889Sbostic 150952889Sbostic /* ARGSUSED */ 151052889Sbostic static int 151152889Sbostic asc_sendsync(asc, status, ss, ir) 151252889Sbostic register asc_softc_t asc; 151352889Sbostic register int status, ss, ir; 151452889Sbostic { 151552889Sbostic register asc_regmap_t *regs = asc->regs; 151653080Sralph register State *state = &asc->st[asc->target]; 151752889Sbostic 151853080Sralph /* send the extended synchronous negotiation message */ 151952889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 152052889Sbostic MachEmptyWriteBuffer(); 152152889Sbostic regs->asc_fifo = 3; 152252889Sbostic MachEmptyWriteBuffer(); 152352889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 152452889Sbostic MachEmptyWriteBuffer(); 152552889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 152652889Sbostic MachEmptyWriteBuffer(); 152752889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 152853080Sralph /* state to resume after we see the sync reply message */ 152953080Sralph state->script = asc->script + 2; 153053080Sralph state->msglen = 0; 153152889Sbostic return (1); 153252889Sbostic } 153352889Sbostic 153452889Sbostic /* ARGSUSED */ 153552889Sbostic static int 153652889Sbostic asc_replysync(asc, status, ss, ir) 153752889Sbostic register asc_softc_t asc; 153852889Sbostic register int status, ss, ir; 153952889Sbostic { 154052889Sbostic register asc_regmap_t *regs = asc->regs; 154152889Sbostic register State *state = &asc->st[asc->target]; 154252889Sbostic 154352889Sbostic #ifdef DEBUG 154452889Sbostic if (asc_debug > 2) 154552889Sbostic printf("asc_replysync: %x %x\n", 154656819Sralph asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 154752889Sbostic state->sync_offset); 154852889Sbostic #endif 154952889Sbostic /* send synchronous transfer in response to a request */ 155052889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 155152889Sbostic MachEmptyWriteBuffer(); 155252889Sbostic regs->asc_fifo = 3; 155352889Sbostic MachEmptyWriteBuffer(); 155452889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 155552889Sbostic MachEmptyWriteBuffer(); 155656819Sralph regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 155752889Sbostic MachEmptyWriteBuffer(); 155852889Sbostic regs->asc_fifo = state->sync_offset; 155952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 156056819Sralph readback(regs->asc_cmd); 156152889Sbostic 156252889Sbostic /* return to the appropriate script */ 156352889Sbostic if (!state->script) { 156452889Sbostic #ifdef DEBUG 156552889Sbostic asc_DumpLog("asc_replsync"); 156652889Sbostic #endif 156752889Sbostic panic("asc_replysync"); 156852889Sbostic } 156952889Sbostic asc->script = state->script; 157052889Sbostic state->script = (script_t *)0; 157152889Sbostic return (0); 157252889Sbostic } 157352889Sbostic 157452889Sbostic /* ARGSUSED */ 157552889Sbostic static int 157652942Sralph asc_msg_in(asc, status, ss, ir) 157752889Sbostic register asc_softc_t asc; 157852889Sbostic register int status, ss, ir; 157952889Sbostic { 158052889Sbostic register asc_regmap_t *regs = asc->regs; 158152889Sbostic register State *state = &asc->st[asc->target]; 158252889Sbostic register int msg; 158352889Sbostic int i; 158452889Sbostic 158552889Sbostic /* read one message byte */ 158652889Sbostic msg = regs->asc_fifo; 158752889Sbostic #ifdef DEBUG 158852889Sbostic if (asc_logp == asc_log) 158952889Sbostic asc_log[NLOG - 1].msg = msg; 159052889Sbostic else 159152889Sbostic asc_logp[-1].msg = msg; 159252889Sbostic #endif 159352889Sbostic 159452889Sbostic /* check for multi-byte message */ 159552889Sbostic if (state->msglen != 0) { 159652889Sbostic /* first byte is the message length */ 159752889Sbostic if (state->msglen < 0) { 159852889Sbostic state->msglen = msg; 159952889Sbostic return (1); 160052889Sbostic } 160152889Sbostic if (state->msgcnt >= state->msglen) 160252889Sbostic goto abort; 160352889Sbostic state->msg_in[state->msgcnt++] = msg; 160452889Sbostic 160552889Sbostic /* did we just read the last byte of the message? */ 160652889Sbostic if (state->msgcnt != state->msglen) 160752889Sbostic return (1); 160852889Sbostic 160952889Sbostic /* process an extended message */ 161052889Sbostic #ifdef DEBUG 161152889Sbostic if (asc_debug > 2) 161252942Sralph printf("asc_msg_in: msg %x %x %x\n", 161352889Sbostic state->msg_in[0], 161452889Sbostic state->msg_in[1], 161552889Sbostic state->msg_in[2]); 161652889Sbostic #endif 161752889Sbostic switch (state->msg_in[0]) { 161852889Sbostic case SCSI_SYNCHRONOUS_XFER: 161952889Sbostic state->flags |= DID_SYNC; 162052889Sbostic state->sync_offset = state->msg_in[2]; 162152889Sbostic 162252889Sbostic /* convert SCSI period to ASC period */ 162356819Sralph i = state->msg_in[1] / asc->tb_ticks; 162456819Sralph if (i < asc->min_period) 162556819Sralph i = asc->min_period; 162656819Sralph else if (i >= asc->max_period) { 162752889Sbostic /* can't do sync transfer, period too long */ 162852889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 162952889Sbostic asc - asc_softc, asc->target, i); 163056819Sralph i = asc->max_period; 163152889Sbostic state->sync_offset = 0; 163252889Sbostic } 163356819Sralph if ((i * asc->tb_ticks) != state->msg_in[1]) 163452889Sbostic i++; 163552889Sbostic state->sync_period = i & 0x1F; 163652889Sbostic 163752889Sbostic /* 163852889Sbostic * If this is a request, check minimums and 163952889Sbostic * send back an acknowledge. 164052889Sbostic */ 164152889Sbostic if (!(state->flags & TRY_SYNC)) { 164252889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 164356819Sralph readback(regs->asc_cmd); 164452889Sbostic 164556819Sralph if (state->sync_period < asc->min_period) 164652889Sbostic state->sync_period = 164756819Sralph asc->min_period; 164852889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 164952889Sbostic state->sync_offset = 165052889Sbostic ASC_MAX_OFFSET; 165152889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 165252889Sbostic regs->asc_syn_p = state->sync_period; 165356819Sralph readback(regs->asc_syn_p); 165452889Sbostic regs->asc_syn_o = state->sync_offset; 165556819Sralph readback(regs->asc_syn_o); 165652889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 165756819Sralph readback(regs->asc_cmd); 165852889Sbostic return (0); 165952889Sbostic } 166052889Sbostic 166152889Sbostic regs->asc_syn_p = state->sync_period; 166256819Sralph readback(regs->asc_syn_p); 166352889Sbostic regs->asc_syn_o = state->sync_offset; 166456819Sralph readback(regs->asc_syn_o); 166552889Sbostic goto done; 166652889Sbostic 166752889Sbostic default: 166852889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 166952889Sbostic asc - asc_softc, asc->target, 167052889Sbostic state->msg_in[0]); 167152889Sbostic goto reject; 167252889Sbostic } 167352889Sbostic } 167452889Sbostic 167552889Sbostic /* process first byte of a message */ 167652889Sbostic #ifdef DEBUG 167752889Sbostic if (asc_debug > 2) 167852942Sralph printf("asc_msg_in: msg %x\n", msg); 167952889Sbostic #endif 168052889Sbostic switch (msg) { 168152889Sbostic #if 0 168252889Sbostic case SCSI_MESSAGE_REJECT: 168352889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 168452889Sbostic state->flags |= DID_SYNC; 168552889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 168656819Sralph readback(regs->asc_cmd); 168752889Sbostic status = asc_wait(regs, ASC_CSR_INT); 168852889Sbostic ir = regs->asc_intr; 168952889Sbostic /* some just break out here, some dont */ 169052889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 169152889Sbostic regs->asc_fifo = SCSI_ABORT; 169252889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 169356819Sralph readback(regs->asc_cmd); 169452889Sbostic status = asc_wait(regs, ASC_CSR_INT); 169552889Sbostic ir = regs->asc_intr; 169652889Sbostic } 169752889Sbostic if (ir & ASC_INT_DISC) { 169852889Sbostic asc_end(asc, status, 0, ir); 169952889Sbostic return (0); 170052889Sbostic } 170152889Sbostic goto status; 170252889Sbostic #endif 170352889Sbostic 170452889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 170552889Sbostic /* setup to read message length next */ 170652889Sbostic state->msglen = -1; 170752889Sbostic state->msgcnt = 0; 170852889Sbostic return (1); 170952889Sbostic 171052889Sbostic case SCSI_NO_OP: 171152889Sbostic break; 171252889Sbostic 171352889Sbostic case SCSI_SAVE_DATA_POINTER: 171452889Sbostic /* expect another message */ 171552889Sbostic return (1); 171652889Sbostic 171752889Sbostic case SCSI_RESTORE_POINTERS: 171852889Sbostic /* 171952889Sbostic * Need to do the following if resuming synchonous data in 172052889Sbostic * on an odd byte boundary. 172152889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 172252889Sbostic */ 172352889Sbostic break; 172452889Sbostic 172552889Sbostic case SCSI_DISCONNECT: 172652889Sbostic if (state->flags & DISCONN) 172752889Sbostic goto abort; 172852889Sbostic state->flags |= DISCONN; 172952942Sralph regs->asc_cmd = ASC_CMD_MSG_ACPT; 173056819Sralph readback(regs->asc_cmd); 173152942Sralph asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 173252942Sralph return (0); 173352889Sbostic 173452889Sbostic default: 173552889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 173652889Sbostic asc - asc_softc, asc->target, msg); 173752889Sbostic reject: 173852889Sbostic /* request a message out before acknowledging this message */ 173952889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 174052889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 174156819Sralph readback(regs->asc_cmd); 174252889Sbostic } 174352889Sbostic 174452889Sbostic done: 174552889Sbostic /* return to original script */ 174652889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 174756819Sralph readback(regs->asc_cmd); 174852889Sbostic if (!state->script) { 174952889Sbostic abort: 175052889Sbostic #ifdef DEBUG 175152942Sralph asc_DumpLog("asc_msg_in"); 175252889Sbostic #endif 175352942Sralph panic("asc_msg_in"); 175452889Sbostic } 175552889Sbostic asc->script = state->script; 175652889Sbostic state->script = (script_t *)0; 175752889Sbostic return (0); 175852889Sbostic } 175952889Sbostic 176052942Sralph /* ARGSUSED */ 176152942Sralph static int 176252942Sralph asc_disconnect(asc, status, ss, ir) 176352942Sralph register asc_softc_t asc; 176452942Sralph register int status, ss, ir; 176552942Sralph { 176652942Sralph register State *state = &asc->st[asc->target]; 176752942Sralph 176858658Sralph #ifdef DIAGNOSTIC 176958658Sralph if (!(state->flags & DISCONN)) { 177058658Sralph printf("asc_disconnect: device %d: DISCONN not set!\n", 177158658Sralph asc->target); 177258658Sralph } 177358658Sralph #endif 177452942Sralph asc->target = -1; 177552942Sralph asc->state = ASC_STATE_RESEL; 177652942Sralph return (1); 177752942Sralph } 177852942Sralph 177956819Sralph /* 178058792Sralph * DMA handling routines. For a turbochannel device, just set the dmar. 178158792Sralph * For the I/O ASIC, handle the actual DMA interface. 178256819Sralph */ 178356819Sralph static void 178456819Sralph tb_dma_start(asc, state, cp, flag) 178556819Sralph asc_softc_t asc; 178656819Sralph State *state; 178756819Sralph caddr_t cp; 178856819Sralph int flag; 178956819Sralph { 179056819Sralph 179156819Sralph if (flag == ASCDMA_WRITE) 179256819Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 179356819Sralph else 179456819Sralph *asc->dmar = ASC_DMA_ADDR(cp); 179556819Sralph } 179656819Sralph 179756819Sralph static void 179856819Sralph tb_dma_end(asc, state, flag) 179956819Sralph asc_softc_t asc; 180056819Sralph State *state; 180156819Sralph int flag; 180256819Sralph { 180356819Sralph 180456819Sralph } 180556819Sralph 180656819Sralph static void 180756819Sralph asic_dma_start(asc, state, cp, flag) 180856819Sralph asc_softc_t asc; 180956819Sralph State *state; 181056819Sralph caddr_t cp; 181156819Sralph int flag; 181256819Sralph { 181356819Sralph register volatile u_int *ssr = (volatile u_int *) 181457233Sralph ASIC_REG_CSR(asic_base); 181556819Sralph u_int phys, nphys; 181656819Sralph 181756819Sralph /* stop DMA engine first */ 181856819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 181958658Sralph *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 182056819Sralph 182156819Sralph phys = MACH_CACHED_TO_PHYS(cp); 182256819Sralph cp = (caddr_t)pmax_trunc_page(cp + NBPG); 182356819Sralph nphys = MACH_CACHED_TO_PHYS(cp); 182456819Sralph 182556819Sralph asc->dma_next = cp; 182656819Sralph asc->dma_xfer = state->dmalen - (nphys - phys); 182756819Sralph 182857233Sralph *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 182956819Sralph ASIC_DMA_ADDR(phys); 183057233Sralph *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 183156819Sralph ASIC_DMA_ADDR(nphys); 183256819Sralph if (flag == ASCDMA_READ) 183356819Sralph *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 183456819Sralph else 183556819Sralph *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 183656819Sralph MachEmptyWriteBuffer(); 183756819Sralph } 183856819Sralph 183956819Sralph static void 184056819Sralph asic_dma_end(asc, state, flag) 184156819Sralph asc_softc_t asc; 184256819Sralph State *state; 184356819Sralph int flag; 184456819Sralph { 184556819Sralph register volatile u_int *ssr = (volatile u_int *) 184657233Sralph ASIC_REG_CSR(asic_base); 184760301Sralph register volatile u_int *dmap = (volatile u_int *) 184860301Sralph ASIC_REG_SCSI_DMAPTR(asic_base); 184960301Sralph register u_short *to; 185060301Sralph register int w; 185156819Sralph int nb; 185256819Sralph 185356819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 185460301Sralph to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); 185560301Sralph *dmap = -1; 185657233Sralph *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 185756819Sralph MachEmptyWriteBuffer(); 185856819Sralph 185956819Sralph if (flag == ASCDMA_READ) { 186056819Sralph MachFlushDCache(MACH_PHYS_TO_CACHED( 186156819Sralph MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 186257233Sralph if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 186356819Sralph /* pick up last upto6 bytes, sigh. */ 186456819Sralph 186556819Sralph /* Last byte really xferred is.. */ 186657233Sralph w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 186756819Sralph *to++ = w; 186856819Sralph if (--nb > 0) { 186956819Sralph w >>= 16; 187056819Sralph *to++ = w; 187156819Sralph } 187256819Sralph if (--nb > 0) { 187357233Sralph w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 187456819Sralph *to++ = w; 187556819Sralph } 187656819Sralph } 187756819Sralph } 187856819Sralph } 187956819Sralph 188057233Sralph #ifdef notdef 188156819Sralph /* 188256819Sralph * Called by asic_intr() for scsi dma pointer update interrupts. 188356819Sralph */ 188456819Sralph void 188556819Sralph asc_dma_intr() 188656819Sralph { 188756819Sralph asc_softc_t asc = &asc_softc[0]; 188856819Sralph u_int next_phys; 188956819Sralph 189056819Sralph asc->dma_xfer -= NBPG; 189156819Sralph if (asc->dma_xfer <= -NBPG) { 189256819Sralph volatile u_int *ssr = (volatile u_int *) 189357233Sralph ASIC_REG_CSR(asic_base); 189456819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 189556819Sralph } else { 189656819Sralph asc->dma_next += NBPG; 189756819Sralph next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 189856819Sralph } 189957233Sralph *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 190056819Sralph ASIC_DMA_ADDR(next_phys); 190156819Sralph MachEmptyWriteBuffer(); 190256819Sralph } 190357233Sralph #endif 190456819Sralph 190552889Sbostic #ifdef DEBUG 190652889Sbostic asc_DumpLog(str) 190752889Sbostic char *str; 190852889Sbostic { 190952889Sbostic register struct asc_log *lp; 191052889Sbostic register u_int status; 191152889Sbostic 191252889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 191352889Sbostic asc_debug_bn, asc_debug_sz); 191458570Sralph lp = asc_logp; 191558570Sralph do { 191652889Sbostic status = lp->status; 191758658Sralph printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", 191852889Sbostic status >> 24, 191952889Sbostic lp->target, 192052889Sbostic (status >> 16) & 0xFF, 192152889Sbostic (status >> 8) & 0xFF, 192252889Sbostic status & 0XFF, 192352889Sbostic lp->state, 192452889Sbostic asc_scripts[lp->state].condition, 192558658Sralph lp->msg, lp->resid); 192652889Sbostic if (++lp >= &asc_log[NLOG]) 192752889Sbostic lp = asc_log; 192858570Sralph } while (lp != asc_logp); 192952889Sbostic } 193052889Sbostic #endif 193152889Sbostic 193252889Sbostic #endif /* NASC > 0 */ 1933