152889Sbostic /*- 252889Sbostic * Copyright (c) 1992 The Regents of the University of California. 352889Sbostic * All rights reserved. 452889Sbostic * 552889Sbostic * This code is derived from software contributed to Berkeley by 6*56819Sralph * Ralph Campbell and Rick Macklem. 752889Sbostic * 852889Sbostic * %sccs.include.redist.c% 952889Sbostic * 10*56819Sralph * @(#)asc.c 7.8 (Berkeley) 11/15/92 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 94*56819Sralph #include <asc.h> 9552889Sbostic #if NASC > 0 9652889Sbostic 9756522Sbostic #include <sys/param.h> 9856522Sbostic #include <sys/systm.h> 99*56819Sralph #include <sys/dkstat.h> 100*56819Sralph #include <sys/buf.h> 101*56819Sralph #include <sys/conf.h> 10256522Sbostic #include <sys/errno.h> 10352889Sbostic 104*56819Sralph #include <machine/machConst.h> 105*56819Sralph 10656525Sbostic #include <pmax/dev/device.h> 10756525Sbostic #include <pmax/dev/scsi.h> 10856525Sbostic #include <pmax/dev/ascreg.h> 10952889Sbostic 110*56819Sralph #include <pmax/pmax/asic.h> 111*56819Sralph #include <pmax/pmax/kmin.h> 112*56819Sralph #include <pmax/pmax/pmaxtype.h> 113*56819Sralph 11452889Sbostic #define ASC_OFFSET_53C94 0x0 /* from module base */ 11552889Sbostic #define ASC_OFFSET_DMAR 0x40000 /* DMA Address Register */ 11652889Sbostic #define ASC_OFFSET_RAM 0x80000 /* SRAM Buffer */ 11752889Sbostic #define ASC_OFFSET_ROM 0xc0000 /* Diagnostic ROM */ 11852889Sbostic 11952889Sbostic #define ASC_RAM_SIZE 0x20000 /* 128k (32k*32) */ 12052889Sbostic 121*56819Sralph #define readback(a) { register int foo; foo = (a); } 12252889Sbostic /* 12352889Sbostic * DMA Address Register 12452889Sbostic */ 12552889Sbostic #define ASC_DMAR_MASK 0x1ffff /* 17 bits, 128k */ 12652889Sbostic #define ASC_DMAR_WRITE 0x80000000 /* DMA direction bit */ 12753080Sralph #define ASC_DMA_ADDR(x) ((unsigned)(x) & ASC_DMAR_MASK) 12852889Sbostic 12952889Sbostic /* 13052889Sbostic * Synch xfer parameters, and timing conversions 13152889Sbostic */ 132*56819Sralph #define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */ 133*56819Sralph #define ASC_MIN_PERIOD25 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 134*56819Sralph #define ASC_MIN_PERIOD12 3 /* in CLKS/BYTE, 1 CLK = 80nsecs */ 135*56819Sralph #define ASC_MAX_PERIOD25 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 136*56819Sralph #define ASC_MAX_PERIOD12 18 /* in CLKS/BYTE, 1 CLK = 80nsecs */ 137*56819Sralph #define ASC_MAX_OFFSET 15 /* pure number */ 13852889Sbostic 139*56819Sralph extern int pmax_boardtype; 140*56819Sralph 141*56819Sralph /* 142*56819Sralph * In 4ns ticks. 143*56819Sralph */ 14452889Sbostic int asc_to_scsi_period[] = { 145*56819Sralph 32, 146*56819Sralph 33, 147*56819Sralph 34, 148*56819Sralph 35, 149*56819Sralph 5, 150*56819Sralph 5, 151*56819Sralph 6, 152*56819Sralph 7, 153*56819Sralph 8, 154*56819Sralph 9, 155*56819Sralph 10, 156*56819Sralph 11, 157*56819Sralph 12, 158*56819Sralph 13, 159*56819Sralph 14, 160*56819Sralph 15, 161*56819Sralph 16, 162*56819Sralph 17, 163*56819Sralph 18, 164*56819Sralph 19, 165*56819Sralph 20, 166*56819Sralph 21, 167*56819Sralph 22, 168*56819Sralph 23, 169*56819Sralph 24, 170*56819Sralph 25, 171*56819Sralph 26, 172*56819Sralph 27, 173*56819Sralph 28, 174*56819Sralph 29, 175*56819Sralph 30, 176*56819Sralph 31, 17752889Sbostic }; 17852889Sbostic 17952889Sbostic /* 18052889Sbostic * Internal forward declarations. 18152889Sbostic */ 18252889Sbostic static void asc_reset(); 18352889Sbostic static void asc_startcmd(); 18452889Sbostic 18552889Sbostic #ifdef DEBUG 18652889Sbostic int asc_debug = 1; 18752889Sbostic int asc_debug_cmd; 18852889Sbostic int asc_debug_bn; 18952889Sbostic int asc_debug_sz; 19052889Sbostic #define NLOG 16 19152889Sbostic struct asc_log { 19252889Sbostic u_int status; 19352889Sbostic u_char state; 19452889Sbostic u_char msg; 19552889Sbostic int target; 19652889Sbostic } asc_log[NLOG], *asc_logp = asc_log; 19752889Sbostic #define PACK(unit, status, ss, ir) \ 19852889Sbostic ((unit << 24) | (status << 16) | (ss << 8) | ir) 19952889Sbostic #endif 20052889Sbostic 20152889Sbostic /* 20252889Sbostic * Scripts are entries in a state machine table. 20352889Sbostic * A script has four parts: a pre-condition, an action, a command to the chip, 20452889Sbostic * and an index into asc_scripts for the next state. The first triggers error 20552889Sbostic * handling if not satisfied and in our case it is formed by the 20652889Sbostic * values of the interrupt register and status register, this 20752889Sbostic * basically captures the phase of the bus and the TC and BS 20852889Sbostic * bits. The action part is just a function pointer, and the 20952889Sbostic * command is what the 53C94 should be told to do at the end 21052889Sbostic * of the action processing. This command is only issued and the 21152889Sbostic * script proceeds if the action routine returns TRUE. 21252889Sbostic * See asc_intr() for how and where this is all done. 21352889Sbostic */ 21452889Sbostic typedef struct script { 21552889Sbostic int condition; /* expected state at interrupt time */ 21652889Sbostic int (*action)(); /* extra operations */ 21752889Sbostic int command; /* command to the chip */ 21852889Sbostic struct script *next; /* index into asc_scripts for next state */ 21952889Sbostic } script_t; 22052889Sbostic 22152889Sbostic /* Matching on the condition value */ 22252889Sbostic #define SCRIPT_MATCH(ir, csr) ((ir) | (ASC_PHASE(csr) << 8)) 22352889Sbostic 22452889Sbostic /* forward decls of script actions */ 225*56819Sralph static int script_nop(); /* when nothing needed */ 226*56819Sralph static int asc_end(); /* all come to an end */ 227*56819Sralph static int asc_get_status(); /* get status from target */ 228*56819Sralph static int asc_dma_in(); /* start reading data from target */ 229*56819Sralph static int asc_last_dma_in(); /* cleanup after all data is read */ 230*56819Sralph static int asc_resume_in(); /* resume data in after a message */ 231*56819Sralph static int asc_resume_dma_in(); /* resume DMA after a disconnect */ 232*56819Sralph static int asc_dma_out(); /* send data to target via dma */ 233*56819Sralph static int asc_last_dma_out(); /* cleanup after all data is written */ 234*56819Sralph static int asc_resume_out(); /* resume data out after a message */ 235*56819Sralph static int asc_resume_dma_out(); /* resume DMA after a disconnect */ 236*56819Sralph static int asc_sendsync(); /* negotiate sync xfer */ 237*56819Sralph static int asc_replysync(); /* negotiate sync xfer */ 238*56819Sralph static int asc_msg_in(); /* process a message byte */ 239*56819Sralph static int asc_disconnect(); /* process an expected disconnect */ 24052889Sbostic 24152889Sbostic /* Define the index into asc_scripts for various state transitions */ 24252889Sbostic #define SCRIPT_DATA_IN 0 24352942Sralph #define SCRIPT_CONTINUE_IN 2 24452942Sralph #define SCRIPT_DATA_OUT 3 24552942Sralph #define SCRIPT_CONTINUE_OUT 5 24652942Sralph #define SCRIPT_SIMPLE 6 24752942Sralph #define SCRIPT_GET_STATUS 7 24852942Sralph #define SCRIPT_MSG_IN 9 24952942Sralph #define SCRIPT_REPLY_SYNC 11 25052889Sbostic #define SCRIPT_TRY_SYNC 12 25152942Sralph #define SCRIPT_DISCONNECT 15 25252942Sralph #define SCRIPT_RESEL 16 25352942Sralph #define SCRIPT_RESUME_IN 17 25452942Sralph #define SCRIPT_RESUME_DMA_IN 18 25552942Sralph #define SCRIPT_RESUME_OUT 19 25652942Sralph #define SCRIPT_RESUME_DMA_OUT 20 25752942Sralph #define SCRIPT_RESUME_NO_DATA 21 25852889Sbostic 25952889Sbostic /* 26052889Sbostic * Scripts 26152889Sbostic */ 26252889Sbostic script_t asc_scripts[] = { 26352942Sralph /* start data in */ 26452889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 26552889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 26652942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 26752889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 26852889Sbostic asc_last_dma_in, ASC_CMD_I_COMPLETE, 26952942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 27052889Sbostic 27152942Sralph /* continue data in after a chuck is finished */ 27252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 27352942Sralph asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 27452942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 27552942Sralph 27652942Sralph /* start data out */ 27752942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 27852889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 27952942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 28052942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 28152889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 28252942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 28352889Sbostic 28452942Sralph /* continue data out after a chuck is finished */ 28552942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 28652942Sralph asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 28752942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 28852942Sralph 28952889Sbostic /* simple command with no data transfer */ 29052942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 29152889Sbostic script_nop, ASC_CMD_I_COMPLETE, 29252942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 29352889Sbostic 29452889Sbostic /* get status and finish command */ 29552942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 29652889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 29752942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 29852942Sralph {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 29952889Sbostic asc_end, ASC_CMD_NOP, 30052942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 30152889Sbostic 30252889Sbostic /* message in */ 30352942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 30452942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 30552942Sralph &asc_scripts[SCRIPT_MSG_IN + 1]}, 30652942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 30752889Sbostic script_nop, ASC_CMD_XFER_INFO, 30852942Sralph &asc_scripts[SCRIPT_MSG_IN]}, 30952889Sbostic 31052889Sbostic /* send synchonous negotiation reply */ 31152942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 31252889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 31352942Sralph &asc_scripts[SCRIPT_REPLY_SYNC]}, 31452889Sbostic 31552889Sbostic /* try to negotiate synchonous transfer parameters */ 31652889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 31752889Sbostic asc_sendsync, ASC_CMD_XFER_INFO, 31853080Sralph &asc_scripts[SCRIPT_TRY_SYNC + 1]}, 31953080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ 32052889Sbostic script_nop, ASC_CMD_XFER_INFO, 32153080Sralph &asc_scripts[SCRIPT_MSG_IN]}, 32253080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ 32353080Sralph script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32453080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]}, 32552889Sbostic 32652942Sralph /* handle a disconnect */ 32752942Sralph {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 32852942Sralph asc_disconnect, ASC_CMD_ENABLE_SEL, 32952942Sralph &asc_scripts[SCRIPT_RESEL]}, 33052942Sralph 33152889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 33252942Sralph {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 33352889Sbostic script_nop, ASC_CMD_MSG_ACPT, 33452942Sralph &asc_scripts[SCRIPT_RESEL]}, 33552889Sbostic 33652942Sralph /* resume data in after a message */ 33752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 33852942Sralph asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 33952942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 34052942Sralph 34152942Sralph /* resume partial DMA data in after a message */ 34252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 34352889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 34452942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 34552889Sbostic 34652942Sralph /* resume data out after a message */ 34752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 34852942Sralph asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 34952942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 35052942Sralph 35152942Sralph /* resume partial DMA data out after a message */ 35252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 35352889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 35452942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 35552942Sralph 35652942Sralph /* resume after a message when there is no more data */ 35752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 35852942Sralph script_nop, ASC_CMD_I_COMPLETE, 35952942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 36052889Sbostic }; 36152889Sbostic 36252889Sbostic /* 36352889Sbostic * State kept for each active SCSI device. 36452889Sbostic */ 36552889Sbostic typedef struct scsi_state { 36652889Sbostic script_t *script; /* saved script while processing error */ 36752889Sbostic int statusByte; /* status byte returned during STATUS_PHASE */ 36852889Sbostic int error; /* errno to pass back to device driver */ 36952889Sbostic u_char *dmaBufAddr; /* DMA buffer address */ 37052889Sbostic u_int dmaBufSize; /* DMA buffer size */ 37152889Sbostic int dmalen; /* amount to transfer in this chunk */ 37252889Sbostic int dmaresid; /* amount not transfered if chunk suspended */ 37352889Sbostic int buflen; /* total remaining amount of data to transfer */ 37452889Sbostic char *buf; /* current pointer within scsicmd->buf */ 37552889Sbostic int flags; /* see below */ 37652889Sbostic int msglen; /* number of message bytes to read */ 37752889Sbostic int msgcnt; /* number of message bytes received */ 37852889Sbostic u_char sync_period; /* DMA synchronous period */ 37952889Sbostic u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 38052889Sbostic u_char msg_out; /* next MSG_OUT byte to send */ 38152889Sbostic u_char msg_in[16]; /* buffer for multibyte messages */ 38252889Sbostic } State; 38352889Sbostic 38452889Sbostic /* state flags */ 38552889Sbostic #define DISCONN 0x01 /* true if currently disconnected from bus */ 38653080Sralph #define DMA_IN_PROGRESS 0x02 /* true if data DMA started */ 38752889Sbostic #define DMA_IN 0x04 /* true if reading from SCSI device */ 38852889Sbostic #define DMA_OUT 0x10 /* true if writing to SCSI device */ 38952889Sbostic #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 39052889Sbostic #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 39152889Sbostic 39252889Sbostic #define ASC_NCMD 7 39352889Sbostic /* 39452889Sbostic * State kept for each active SCSI host interface (53C94). 39552889Sbostic */ 39652889Sbostic struct asc_softc { 39752889Sbostic asc_regmap_t *regs; /* chip address */ 39852889Sbostic volatile int *dmar; /* DMA address register address */ 399*56819Sralph u_char *buff; /* RAM buffer address (uncached) */ 40052889Sbostic int myid; /* SCSI ID of this interface */ 40152889Sbostic int myidmask; /* ~(1 << myid) */ 40252889Sbostic int state; /* current SCSI connection state */ 40352889Sbostic int target; /* target SCSI ID if busy */ 40452889Sbostic script_t *script; /* next expected interrupt & action */ 40552889Sbostic ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 40652889Sbostic State st[ASC_NCMD]; /* state info for each active command */ 407*56819Sralph void (*dma_start)(); /* Start dma routine */ 408*56819Sralph void (*dma_end)(); /* End dma routine */ 409*56819Sralph u_char *dma_next; 410*56819Sralph int dma_xfer; /* Dma len still to go */ 411*56819Sralph int min_period; /* Min transfer period clk/byte */ 412*56819Sralph int max_period; /* Max transfer period clk/byte */ 413*56819Sralph int ccf; /* CCF, whatever that really is? */ 414*56819Sralph int timeout_250; /* 250ms timeout */ 415*56819Sralph int tb_ticks; /* 4ns. ticks/tb channel ticks */ 41652889Sbostic } asc_softc[NASC]; 41752889Sbostic 41852889Sbostic #define ASC_STATE_IDLE 0 /* idle state */ 41952889Sbostic #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 42052889Sbostic #define ASC_STATE_TARGET 2 /* currently selected as target */ 42152889Sbostic #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 42252889Sbostic 42352889Sbostic typedef struct asc_softc *asc_softc_t; 42452889Sbostic 42552889Sbostic /* 426*56819Sralph * Dma operations. 427*56819Sralph */ 428*56819Sralph #define ASCDMA_READ 1 429*56819Sralph #define ASCDMA_WRITE 2 430*56819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end(); 431*56819Sralph u_long asc_iobuf[33792]; 432*56819Sralph 433*56819Sralph /* 43452889Sbostic * Definition of the controller for the auto-configuration program. 43552889Sbostic */ 43652889Sbostic int asc_probe(); 43752889Sbostic void asc_start(); 43852889Sbostic void asc_intr(); 43952889Sbostic struct driver ascdriver = { 44052889Sbostic "asc", asc_probe, asc_start, 0, asc_intr, 44152889Sbostic }; 44252889Sbostic 44352889Sbostic /* 44452889Sbostic * Test to see if device is present. 44552889Sbostic * Return true if found and initialized ok. 44652889Sbostic */ 44752889Sbostic asc_probe(cp) 44852889Sbostic register struct pmax_ctlr *cp; 44952889Sbostic { 45052889Sbostic register asc_softc_t asc; 45152889Sbostic register asc_regmap_t *regs; 45252889Sbostic int unit, id, s, i; 453*56819Sralph u_int bufadr; 45452889Sbostic 45552889Sbostic if ((unit = cp->pmax_unit) >= NASC) 45652889Sbostic return (0); 45752889Sbostic if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 45852889Sbostic return (0); 45952889Sbostic asc = &asc_softc[unit]; 46052889Sbostic 46152889Sbostic /* 46252889Sbostic * Initialize hw descriptor, cache some pointers 46352889Sbostic */ 46452889Sbostic asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 46552889Sbostic 466*56819Sralph /* 467*56819Sralph * Set up machine dependencies. 468*56819Sralph * 1) how to do dma 469*56819Sralph * 2) timing based on turbochannel frequency 470*56819Sralph */ 471*56819Sralph switch (pmax_boardtype) { 472*56819Sralph case DS_3MIN: 473*56819Sralph case DS_MAXINE: 474*56819Sralph if (unit == 0) { 475*56819Sralph bufadr = MACH_PHYS_TO_UNCACHED(MACH_CACHED_TO_PHYS(asc_iobuf)); 476*56819Sralph bufadr = (bufadr + NBPG - 1) & ~(NBPG - 1); 477*56819Sralph asc->buff = (u_char *)bufadr; 478*56819Sralph *((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR)) 479*56819Sralph = -1; 480*56819Sralph *((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR)) 481*56819Sralph = -1; 482*56819Sralph *((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR)) = 0; 483*56819Sralph asc->dma_start = asic_dma_start; 484*56819Sralph asc->dma_end = asic_dma_end; 485*56819Sralph break; 486*56819Sralph } 487*56819Sralph /* 488*56819Sralph * Fall through for turbochannel option. 489*56819Sralph */ 490*56819Sralph case DS_3MAX: 491*56819Sralph default: 492*56819Sralph asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 493*56819Sralph asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 494*56819Sralph asc->dma_start = tb_dma_start; 495*56819Sralph asc->dma_end = tb_dma_end; 496*56819Sralph }; 497*56819Sralph /* 498*56819Sralph * Now for timing. The 3max has a 25Mhz tb whereas the 3min and 499*56819Sralph * maxine are 12.5Mhz. 500*56819Sralph */ 501*56819Sralph switch (pmax_boardtype) { 502*56819Sralph case DS_3MAX: 503*56819Sralph asc->min_period = ASC_MIN_PERIOD25; 504*56819Sralph asc->max_period = ASC_MAX_PERIOD25; 505*56819Sralph asc->ccf = ASC_CCF(25); 506*56819Sralph asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf); 507*56819Sralph asc->tb_ticks = 10; 508*56819Sralph break; 509*56819Sralph case DS_3MIN: 510*56819Sralph case DS_MAXINE: 511*56819Sralph default: 512*56819Sralph asc->min_period = ASC_MIN_PERIOD12; 513*56819Sralph asc->max_period = ASC_MAX_PERIOD12; 514*56819Sralph asc->ccf = ASC_CCF(13); 515*56819Sralph asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); 516*56819Sralph asc->tb_ticks = 20; 517*56819Sralph break; 518*56819Sralph }; 519*56819Sralph 52052889Sbostic asc->state = ASC_STATE_IDLE; 52152889Sbostic asc->target = -1; 52252889Sbostic 52352889Sbostic regs = asc->regs; 52452889Sbostic 52552889Sbostic /* 52652889Sbostic * Reset chip, fully. Note that interrupts are already enabled. 52752889Sbostic */ 52852889Sbostic s = splbio(); 52952889Sbostic 53052889Sbostic /* preserve our ID for now */ 53152889Sbostic asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 53252889Sbostic asc->myidmask = ~(1 << asc->myid); 53352889Sbostic 53452889Sbostic asc_reset(asc, regs); 53552889Sbostic 53652889Sbostic /* 53752889Sbostic * Our SCSI id on the bus. 53852889Sbostic * The user can set this via the prom on 3maxen/pmaxen. 53952889Sbostic * If this changes it is easy to fix: make a default that 54052889Sbostic * can be changed as boot arg. 54152889Sbostic */ 54252889Sbostic #ifdef unneeded 54352889Sbostic regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 54452889Sbostic (scsi_initiator_id[unit] & 0x7); 54552889Sbostic #endif 54652889Sbostic id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 54752889Sbostic splx(s); 54852889Sbostic 54952889Sbostic /* 55052889Sbostic * Statically partition the DMA buffer between targets. 55152889Sbostic * This way we will eventually be able to attach/detach 55252889Sbostic * drives on-fly. And 18k/target is plenty for normal use. 55352889Sbostic */ 55452889Sbostic #define PER_TGT_DMA_SIZE ((ASC_RAM_SIZE/7) & ~(sizeof(int)-1)) 55552889Sbostic 55652889Sbostic /* 55752889Sbostic * Give each target its own DMA buffer region. 55852889Sbostic * We may want to try ping ponging buffers later. 55952889Sbostic */ 56052889Sbostic for (i = 0; i < ASC_NCMD; i++) { 56152889Sbostic asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i; 56252889Sbostic asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE; 56352889Sbostic } 56452889Sbostic printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 56552889Sbostic unit, cp->pmax_addr, cp->pmax_pri, id); 56652889Sbostic return (1); 56752889Sbostic } 56852889Sbostic 56952889Sbostic /* 57052889Sbostic * Start activity on a SCSI device. 57152889Sbostic * We maintain information on each device separately since devices can 57252889Sbostic * connect/disconnect during an operation. 57352889Sbostic */ 57452889Sbostic void 57552889Sbostic asc_start(scsicmd) 57652889Sbostic register ScsiCmd *scsicmd; /* command to start */ 57752889Sbostic { 57852889Sbostic register struct scsi_device *sdp = scsicmd->sd; 57952889Sbostic register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 58052889Sbostic int s; 58152889Sbostic 58252889Sbostic s = splbio(); 58352889Sbostic /* 58452889Sbostic * Check if another command is already in progress. 58552889Sbostic * We may have to change this if we allow SCSI devices with 58652889Sbostic * separate LUNs. 58752889Sbostic */ 58852889Sbostic if (asc->cmd[sdp->sd_drive]) { 58952889Sbostic printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 59052889Sbostic sdp->sd_driver->d_name); 59152889Sbostic (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 59252889Sbostic scsicmd->buflen, 0); 59352889Sbostic splx(s); 59452889Sbostic } 59552889Sbostic asc->cmd[sdp->sd_drive] = scsicmd; 59652889Sbostic asc_startcmd(asc, sdp->sd_drive); 59752889Sbostic splx(s); 59852889Sbostic } 59952889Sbostic 60052889Sbostic static void 60152889Sbostic asc_reset(asc, regs) 60252889Sbostic asc_softc_t asc; 60352889Sbostic asc_regmap_t *regs; 60452889Sbostic { 60552889Sbostic 60652889Sbostic /* 60752889Sbostic * Reset chip and wait till done 60852889Sbostic */ 60952889Sbostic regs->asc_cmd = ASC_CMD_RESET; 61052889Sbostic MachEmptyWriteBuffer(); DELAY(25); 61152889Sbostic 61252889Sbostic /* spec says this is needed after reset */ 61352889Sbostic regs->asc_cmd = ASC_CMD_NOP; 61452889Sbostic MachEmptyWriteBuffer(); DELAY(25); 61552889Sbostic 61652889Sbostic /* 61752889Sbostic * Set up various chip parameters 61852889Sbostic */ 619*56819Sralph regs->asc_ccf = asc->ccf; 62052889Sbostic MachEmptyWriteBuffer(); DELAY(25); 621*56819Sralph regs->asc_sel_timo = asc->timeout_250; 62252889Sbostic /* restore our ID */ 62352889Sbostic regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 624*56819Sralph regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_SCSI2; 62552889Sbostic regs->asc_cnfg3 = 0; 62652889Sbostic /* zero anything else */ 62752889Sbostic ASC_TC_PUT(regs, 0); 628*56819Sralph regs->asc_syn_p = asc->min_period; 62952889Sbostic regs->asc_syn_o = 0; /* async for now */ 63052889Sbostic MachEmptyWriteBuffer(); 63152889Sbostic } 63252889Sbostic 63352889Sbostic /* 63452889Sbostic * Start a SCSI command on a target. 63552889Sbostic */ 63652889Sbostic static void 63752889Sbostic asc_startcmd(asc, target) 63852889Sbostic asc_softc_t asc; 63952889Sbostic int target; 64052889Sbostic { 64152889Sbostic register asc_regmap_t *regs; 64252889Sbostic register ScsiCmd *scsicmd; 64352889Sbostic register State *state; 64452889Sbostic int len; 64552889Sbostic 64652889Sbostic /* 64752889Sbostic * See if another target is currently selected on this SCSI bus. 64852889Sbostic */ 64952889Sbostic if (asc->target >= 0) 65052889Sbostic return; 65152889Sbostic 65252889Sbostic regs = asc->regs; 65352889Sbostic 65452889Sbostic /* 65552889Sbostic * Check to see if a reselection is in progress and if so, 65652889Sbostic * try to cancel it or respond to the reselection if it won. 65752889Sbostic */ 65852889Sbostic if (asc->state == ASC_STATE_RESEL) { 65952889Sbostic regs->asc_cmd = ASC_CMD_DISABLE_SEL; 660*56819Sralph readback(regs->asc_cmd); 66152889Sbostic while (!(regs->asc_status & ASC_CSR_INT)) 66252889Sbostic DELAY(1); 66352889Sbostic asc_intr(asc - asc_softc); 66452889Sbostic /* we will be busy if a reselecting device won */ 66552889Sbostic if (asc->state == ASC_STATE_BUSY) 66652889Sbostic return; 66752889Sbostic } 66852889Sbostic 66952889Sbostic asc->state = ASC_STATE_BUSY; 67052889Sbostic asc->target = target; 67152889Sbostic 67252889Sbostic /* cache some pointers */ 67352889Sbostic scsicmd = asc->cmd[target]; 67452889Sbostic state = &asc->st[target]; 67552889Sbostic 67652889Sbostic #ifdef DEBUG 67752889Sbostic if (asc_debug > 1) { 67852889Sbostic printf("asc_startcmd: %s target %d cmd %x len %d\n", 67952889Sbostic scsicmd->sd->sd_driver->d_name, target, 68052889Sbostic scsicmd->cmd[0], scsicmd->buflen); 68152889Sbostic } 68252889Sbostic asc_debug_cmd = scsicmd->cmd[0]; 68352889Sbostic if (scsicmd->cmd[0] == SCSI_READ_EXT) { 68452889Sbostic asc_debug_bn = (scsicmd->cmd[2] << 24) | 68552889Sbostic (scsicmd->cmd[3] << 16) | 68652889Sbostic (scsicmd->cmd[4] << 8) | 68752889Sbostic scsicmd->cmd[5]; 68852889Sbostic asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 68952889Sbostic } 69053080Sralph asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 69152889Sbostic asc_logp->target = asc->target; 69252889Sbostic asc_logp->state = 0; 69353080Sralph asc_logp->msg = 0xff; 69452889Sbostic if (++asc_logp >= &asc_log[NLOG]) 69552889Sbostic asc_logp = asc_log; 69652889Sbostic #endif 69752889Sbostic 69852889Sbostic /* 69952889Sbostic * Init the chip and target state. 70052889Sbostic */ 70152889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 702*56819Sralph readback(regs->asc_cmd); 703*56819Sralph DELAY(2); 70453080Sralph state->flags = state->flags & DID_SYNC; 70552889Sbostic state->error = 0; 70652889Sbostic state->script = (script_t *)0; 70752889Sbostic state->msg_out = SCSI_NO_OP; 70852889Sbostic 70952889Sbostic /* 71052889Sbostic * Copy command data to the DMA buffer. 71152889Sbostic */ 71252889Sbostic len = scsicmd->cmdlen; 71352889Sbostic state->dmalen = len; 71452889Sbostic bcopy(scsicmd->cmd, state->dmaBufAddr, len); 71552889Sbostic 71652889Sbostic /* check for simple SCSI command with no data transfer */ 71752889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 71852889Sbostic /* check for sync negotiation */ 71952889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 72052889Sbostic !(state->flags & DID_SYNC)) { 72152889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 72252889Sbostic state->flags |= TRY_SYNC; 72352889Sbostic } else 72452889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 72552889Sbostic state->buf = (char *)0; 72652889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 72752889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 72853080Sralph state->buf = scsicmd->buf; 72952889Sbostic state->flags |= DMA_OUT; 73052889Sbostic } else { 73152889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 73252889Sbostic state->buf = scsicmd->buf; 73352889Sbostic state->flags |= DMA_IN; 73452889Sbostic } 73552889Sbostic 73652889Sbostic /* preload the FIFO with the message to be sent */ 73752942Sralph regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 738*56819Sralph MachEmptyWriteBuffer(); 73952889Sbostic 74052889Sbostic /* start the asc */ 741*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 74252889Sbostic ASC_TC_PUT(regs, len); 743*56819Sralph readback(regs->asc_cmd); 74452889Sbostic 74552889Sbostic regs->asc_dbus_id = target; 746*56819Sralph readback(regs->asc_dbus_id); 74752889Sbostic regs->asc_syn_p = state->sync_period; 748*56819Sralph readback(regs->asc_syn_p); 74952889Sbostic regs->asc_syn_o = state->sync_offset; 750*56819Sralph readback(regs->asc_syn_o); 75152889Sbostic 75252889Sbostic if (state->flags & TRY_SYNC) 75353080Sralph regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 75452889Sbostic else 75552889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 756*56819Sralph readback(regs->asc_cmd); 75752889Sbostic } 75852889Sbostic 75952889Sbostic /* 76052889Sbostic * Interrupt routine 76152889Sbostic * Take interrupts from the chip 76252889Sbostic * 76352889Sbostic * Implementation: 76452889Sbostic * Move along the current command's script if 76552889Sbostic * all is well, invoke error handler if not. 76652889Sbostic */ 76752889Sbostic void 76852889Sbostic asc_intr(unit) 76952889Sbostic int unit; 77052889Sbostic { 77152889Sbostic register asc_softc_t asc = &asc_softc[unit]; 77252889Sbostic register asc_regmap_t *regs = asc->regs; 77352889Sbostic register State *state; 77452889Sbostic register script_t *scpt; 77552889Sbostic register int ss, ir, status; 77652889Sbostic 77752889Sbostic /* collect ephemeral information */ 77852889Sbostic status = regs->asc_status; 77953080Sralph again: 78052889Sbostic ss = regs->asc_ss; 78152889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 78252889Sbostic scpt = asc->script; 78352889Sbostic 78452889Sbostic #ifdef DEBUG 78552889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 78652889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 78752889Sbostic asc_logp->state = scpt - asc_scripts; 78852889Sbostic asc_logp->msg = -1; 78952889Sbostic if (++asc_logp >= &asc_log[NLOG]) 79052889Sbostic asc_logp = asc_log; 79152889Sbostic if (asc_debug > 2) 79252889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 79352889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 79452889Sbostic #endif 79552889Sbostic 79652889Sbostic /* check the expected state */ 79752889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 79852889Sbostic /* 79952889Sbostic * Perform the appropriate operation, then proceed. 80052889Sbostic */ 80152889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 80252889Sbostic regs->asc_cmd = scpt->command; 803*56819Sralph readback(regs->asc_cmd); 80452889Sbostic asc->script = scpt->next; 80552889Sbostic } 80652889Sbostic goto done; 80752889Sbostic } 80852889Sbostic 80952889Sbostic /* check for message in or out */ 81052889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 81152889Sbostic register int len, fifo; 81252889Sbostic 81352889Sbostic state = &asc->st[asc->target]; 81452889Sbostic switch (ASC_PHASE(status)) { 81553080Sralph case ASC_PHASE_DATAI: 81653080Sralph case ASC_PHASE_DATAO: 81753080Sralph ASC_TC_GET(regs, len); 81853080Sralph fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 81953080Sralph printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 82053080Sralph state->buflen, state->dmalen, len, fifo); 82153080Sralph goto abort; 82253080Sralph 82352889Sbostic case ASC_PHASE_MSG_IN: 82452889Sbostic break; 82552889Sbostic 82652889Sbostic case ASC_PHASE_MSG_OUT: 82752889Sbostic regs->asc_fifo = state->msg_out; 82852889Sbostic state->msg_out = SCSI_NO_OP; 82952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 830*56819Sralph readback(regs->asc_cmd); 83152889Sbostic goto done; 83252889Sbostic 83352889Sbostic case ASC_PHASE_STATUS: 83452889Sbostic /* probably an error in the SCSI command */ 83552889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 83652889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 837*56819Sralph readback(regs->asc_cmd); 83852889Sbostic goto done; 83952889Sbostic 84052889Sbostic default: 84152889Sbostic goto abort; 84252889Sbostic } 84352889Sbostic 84452889Sbostic if (state->script) 84552889Sbostic goto abort; 84652889Sbostic 84752889Sbostic /* check for DMA in progress */ 84852889Sbostic ASC_TC_GET(regs, len); 84952889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 85052889Sbostic /* flush any data in the FIFO */ 85152889Sbostic if (fifo) { 85253080Sralph if (state->flags & DMA_OUT) 85353080Sralph len += fifo; 85453080Sralph else if (state->flags & DMA_IN) { 85553080Sralph u_char *cp; 85653080Sralph 85753080Sralph printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 85853080Sralph state->dmalen, len, fifo); /* XXX */ 85953080Sralph len += fifo; 86053080Sralph cp = state->dmaBufAddr + (state->dmalen - len); 86153080Sralph while (fifo-- > 0) 86253080Sralph *cp++ = regs->asc_fifo; 86353080Sralph } else 86453080Sralph printf("asc_intr: dmalen %d len %d fifo %d\n", 86553080Sralph state->dmalen, len, fifo); /* XXX */ 86652889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 867*56819Sralph readback(regs->asc_cmd); 86852889Sbostic MachEmptyWriteBuffer(); 869*56819Sralph DELAY(2); 87052889Sbostic } 87152889Sbostic if (len) { 87252889Sbostic /* save number of bytes still to be sent or received */ 87352889Sbostic state->dmaresid = len; 87452889Sbostic /* setup state to resume to */ 87552889Sbostic if (state->flags & DMA_IN) 87652889Sbostic state->script = 87752889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 87852889Sbostic else if (state->flags & DMA_OUT) 87952889Sbostic state->script = 88052889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 88152889Sbostic else 88252889Sbostic state->script = asc->script; 88352889Sbostic } else { 88452889Sbostic /* setup state to resume to */ 88552942Sralph if (state->flags & DMA_IN) { 88653080Sralph if (state->flags & DMA_IN_PROGRESS) { 88753080Sralph state->flags &= ~DMA_IN_PROGRESS; 888*56819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 88952942Sralph len = state->dmalen; 89052942Sralph bcopy(state->dmaBufAddr, state->buf, 89152942Sralph len); 89252942Sralph state->buf += len; 89352942Sralph state->buflen -= len; 89453080Sralph } 89552942Sralph if (state->buflen) 89652942Sralph state->script = 89752942Sralph &asc_scripts[SCRIPT_RESUME_IN]; 89852942Sralph else 89952942Sralph state->script = 90052942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 90152942Sralph } else if (state->flags & DMA_OUT) { 90252942Sralph /* 90352942Sralph * If this is the last chunk, the next expected 90452942Sralph * state is to get status. 90552942Sralph */ 90653080Sralph if (state->flags & DMA_IN_PROGRESS) { 90753080Sralph state->flags &= ~DMA_IN_PROGRESS; 908*56819Sralph (*asc->dma_end)(asc, state, ASCDMA_WRITE); 90953080Sralph len = state->dmalen; 91053080Sralph state->buf += len; 91153080Sralph state->buflen -= len; 91253080Sralph } 91352942Sralph if (state->buflen) 91452942Sralph state->script = 91552942Sralph &asc_scripts[SCRIPT_RESUME_OUT]; 91652942Sralph else 91752942Sralph state->script = 91852942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 91953080Sralph } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 92053080Sralph state->script = 92153080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 92253080Sralph else 92352889Sbostic state->script = asc->script; 92452889Sbostic } 92552889Sbostic 92652889Sbostic /* setup to receive a message */ 92752889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 92852889Sbostic state->msglen = 0; 92952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 930*56819Sralph readback(regs->asc_cmd); 93152889Sbostic goto done; 93252889Sbostic } 93352889Sbostic 93452889Sbostic /* check for SCSI bus reset */ 93552889Sbostic if (ir & ASC_INT_RESET) { 93652889Sbostic register int i; 93752889Sbostic 93852889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 93952889Sbostic /* need to flush any pending commands */ 94052889Sbostic for (i = 0; i < ASC_NCMD; i++) { 94152889Sbostic if (!asc->cmd[i]) 94252889Sbostic continue; 94352889Sbostic asc->st[i].error = EIO; 94452889Sbostic asc_end(asc, 0, 0, 0); 94552889Sbostic } 94652889Sbostic /* rearbitrate synchronous offset */ 94752889Sbostic for (i = 0; i < ASC_NCMD; i++) { 94852889Sbostic asc->st[i].sync_offset = 0; 94952889Sbostic asc->st[i].flags = 0; 95052889Sbostic } 95152889Sbostic asc->target = -1; 95252889Sbostic return; 95352889Sbostic } 95452889Sbostic 95552889Sbostic /* check for command errors */ 95652889Sbostic if (ir & ASC_INT_ILL) 95752889Sbostic goto abort; 95852889Sbostic 95952889Sbostic /* check for disconnect */ 96052889Sbostic if (ir & ASC_INT_DISC) { 96152889Sbostic state = &asc->st[asc->target]; 96252889Sbostic switch (ASC_SS(ss)) { 96352889Sbostic case 0: /* device did not respond */ 96452889Sbostic state->error = ENXIO; 96552889Sbostic asc_end(asc, status, ss, ir); 96652889Sbostic return; 96752889Sbostic 96852889Sbostic default: 96952889Sbostic goto abort; 97052889Sbostic } 97152889Sbostic } 97252889Sbostic 97352889Sbostic /* check for reselect */ 97452889Sbostic if (ir & ASC_INT_RESEL) { 97552889Sbostic unsigned fifo, id, msg; 97652889Sbostic 97752889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 97852889Sbostic if (fifo < 2) 97952889Sbostic goto abort; 98052889Sbostic /* read unencoded SCSI ID and convert to binary */ 98152889Sbostic msg = regs->asc_fifo & asc->myidmask; 98252889Sbostic for (id = 0; (msg & 1) == 0; id++) 98352889Sbostic msg >>= 1; 98452889Sbostic /* read identify message */ 98552889Sbostic msg = regs->asc_fifo; 98652889Sbostic #ifdef DEBUG 98752889Sbostic if (asc_logp == asc_log) 98852889Sbostic asc_log[NLOG - 1].msg = msg; 98952889Sbostic else 99052889Sbostic asc_logp[-1].msg = msg; 99152889Sbostic #endif 99252889Sbostic if (asc->state != ASC_STATE_RESEL) 99352889Sbostic goto abort; 99452889Sbostic asc->state = ASC_STATE_BUSY; 99552889Sbostic asc->target = id; 99652889Sbostic state = &asc->st[id]; 99752889Sbostic asc->script = state->script; 99852889Sbostic state->script = (script_t *)0; 99952889Sbostic if (!(state->flags & DISCONN)) 100052889Sbostic goto abort; 100152889Sbostic state->flags &= ~DISCONN; 100253080Sralph regs->asc_syn_p = state->sync_period; 100353080Sralph regs->asc_syn_o = state->sync_offset; 100452889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1005*56819Sralph readback(regs->asc_cmd); 100652889Sbostic goto done; 100752889Sbostic } 100852889Sbostic 100952889Sbostic /* check if we are being selected as a target */ 101052889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 101152889Sbostic goto abort; 101252889Sbostic 101352889Sbostic /* must be just a ASC_INT_FC */ 101452889Sbostic done: 101552889Sbostic MachEmptyWriteBuffer(); 101653080Sralph /* watch out for HW race conditions and setup & hold time violations */ 101753080Sralph ir = regs->asc_status; 101853080Sralph while (ir != (status = regs->asc_status)) 101953080Sralph ir = status; 102053080Sralph if (status & ASC_CSR_INT) 102152889Sbostic goto again; 102252889Sbostic return; 102352889Sbostic 102452889Sbostic abort: 102552889Sbostic #ifdef DEBUG 102652889Sbostic asc_DumpLog("asc_intr"); 102752889Sbostic #endif 102852889Sbostic #if 0 102952889Sbostic panic("asc_intr"); 103052889Sbostic #else 103152889Sbostic for (;;); 103252889Sbostic #endif 103352889Sbostic } 103452889Sbostic 103552889Sbostic /* 103652889Sbostic * All the many little things that the interrupt 103752889Sbostic * routine might switch to. 103852889Sbostic */ 103952889Sbostic 104052889Sbostic /* ARGSUSED */ 104152889Sbostic static int 104252889Sbostic script_nop(asc, status, ss, ir) 104352889Sbostic register asc_softc_t asc; 104452889Sbostic register int status, ss, ir; 104552889Sbostic { 104652889Sbostic return (1); 104752889Sbostic } 104852889Sbostic 104952889Sbostic /* ARGSUSED */ 105052889Sbostic static int 105152889Sbostic asc_get_status(asc, status, ss, ir) 105252889Sbostic register asc_softc_t asc; 105352889Sbostic register int status, ss, ir; 105452889Sbostic { 105552889Sbostic register asc_regmap_t *regs = asc->regs; 105652889Sbostic register int data; 105752889Sbostic 105852889Sbostic /* 105952889Sbostic * Get the last two bytes in the FIFO. 106052889Sbostic */ 106152889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 106252889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 106352889Sbostic if (data < 2) { 106452889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 1065*56819Sralph readback(asc->regs->asc_cmd); 106652889Sbostic return (0); 106752889Sbostic } 106852889Sbostic do { 106952889Sbostic data = regs->asc_fifo; 107052889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 107152889Sbostic } 107252889Sbostic 107352889Sbostic /* save the status byte */ 107452889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 107552889Sbostic #ifdef DEBUG 107652889Sbostic if (asc_logp == asc_log) 107752889Sbostic asc_log[NLOG - 1].msg = data; 107852889Sbostic else 107952889Sbostic asc_logp[-1].msg = data; 108052889Sbostic #endif 108152889Sbostic 108252889Sbostic /* get the (presumed) command_complete message */ 108352889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 108452889Sbostic return (1); 108552889Sbostic 108652889Sbostic #ifdef DEBUG 108752889Sbostic printf("asc_get_status: status %x cmd %x\n", 108852889Sbostic asc->st[asc->target].statusByte, data); 108952889Sbostic asc_DumpLog("asc_get_status"); 109052889Sbostic #endif 109152889Sbostic return (0); 109252889Sbostic } 109352889Sbostic 109452889Sbostic /* ARGSUSED */ 109552889Sbostic static int 109652889Sbostic asc_end(asc, status, ss, ir) 109752889Sbostic register asc_softc_t asc; 109852889Sbostic register int status, ss, ir; 109952889Sbostic { 110052889Sbostic register ScsiCmd *scsicmd; 110152889Sbostic register State *state; 110252889Sbostic register int i, target; 110352889Sbostic 110452889Sbostic asc->state = ASC_STATE_IDLE; 110552889Sbostic target = asc->target; 110652889Sbostic asc->target = -1; 110752889Sbostic scsicmd = asc->cmd[target]; 110852889Sbostic asc->cmd[target] = (ScsiCmd *)0; 110952889Sbostic state = &asc->st[target]; 111052889Sbostic 111152889Sbostic #ifdef DEBUG 111252889Sbostic if (asc_debug > 1) { 111352889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 111452889Sbostic scsicmd->sd->sd_driver->d_name, target, 111552889Sbostic scsicmd->cmd[0], state->error, state->buflen); 111652889Sbostic } 111752889Sbostic #endif 111852889Sbostic #ifdef DIAGNOSTIC 111952889Sbostic if (target < 0 || !scsicmd) 112052889Sbostic panic("asc_end"); 112152889Sbostic #endif 112252889Sbostic 112352889Sbostic /* look for disconnected devices */ 112452889Sbostic for (i = 0; i < ASC_NCMD; i++) { 112552889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 112652889Sbostic continue; 112752889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1128*56819Sralph readback(asc->regs->asc_cmd); 112952889Sbostic asc->state = ASC_STATE_RESEL; 113052889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 113152889Sbostic break; 113252889Sbostic } 113352889Sbostic 113452889Sbostic /* look for another device that is ready */ 113552889Sbostic for (i = 0; i < ASC_NCMD; i++) { 113652889Sbostic /* don't restart a disconnected command */ 113752889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 113852889Sbostic continue; 113952889Sbostic asc_startcmd(asc, i); 114052889Sbostic break; 114152889Sbostic } 114252889Sbostic 114352889Sbostic /* signal device driver that the command is done */ 114452889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 114552889Sbostic state->buflen, state->statusByte); 114652889Sbostic 114752889Sbostic return (0); 114852889Sbostic } 114952889Sbostic 115052889Sbostic /* ARGSUSED */ 115152889Sbostic static int 115252889Sbostic asc_dma_in(asc, status, ss, ir) 115352889Sbostic register asc_softc_t asc; 115452889Sbostic register int status, ss, ir; 115552889Sbostic { 115652889Sbostic register asc_regmap_t *regs = asc->regs; 115752889Sbostic register State *state = &asc->st[asc->target]; 115853080Sralph register int len; 115952889Sbostic 116052889Sbostic /* check for previous chunk in buffer */ 116153080Sralph if (state->flags & DMA_IN_PROGRESS) { 116252889Sbostic /* 116352889Sbostic * Only count bytes that have been copied to memory. 116452889Sbostic * There may be some bytes in the FIFO if synchonous transfers 116552889Sbostic * are in progress. 116652889Sbostic */ 1167*56819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 116852889Sbostic ASC_TC_GET(regs, len); 116952889Sbostic len = state->dmalen - len; 117052889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 117152889Sbostic state->buf += len; 117252889Sbostic state->buflen -= len; 117353080Sralph } 117452889Sbostic 117552942Sralph /* setup to start reading the next chunk */ 117652889Sbostic len = state->buflen; 117752889Sbostic if (len > state->dmaBufSize) 117852889Sbostic len = state->dmaBufSize; 117952889Sbostic state->dmalen = len; 1180*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 118152889Sbostic ASC_TC_PUT(regs, len); 118252942Sralph #ifdef DEBUG 118352942Sralph if (asc_debug > 2) 118452942Sralph printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 118552942Sralph #endif 118652942Sralph 118752942Sralph /* check for next chunk */ 118853080Sralph state->flags |= DMA_IN_PROGRESS; 118952889Sbostic if (len != state->buflen) { 119052889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1191*56819Sralph readback(regs->asc_cmd); 119252942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 119352889Sbostic return (0); 119452889Sbostic } 119552889Sbostic return (1); 119652889Sbostic } 119752889Sbostic 119852889Sbostic /* ARGSUSED */ 119952889Sbostic static int 120052889Sbostic asc_last_dma_in(asc, status, ss, ir) 120152889Sbostic register asc_softc_t asc; 120252889Sbostic register int status, ss, ir; 120352889Sbostic { 120452889Sbostic register asc_regmap_t *regs = asc->regs; 120552889Sbostic register State *state = &asc->st[asc->target]; 120652889Sbostic register int len, fifo; 120752889Sbostic 120852889Sbostic /* copy data from buffer to main memory */ 1209*56819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 121052889Sbostic ASC_TC_GET(regs, len); 121152889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 121252889Sbostic #ifdef DEBUG 121352942Sralph if (asc_debug > 2) 121452889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 121552889Sbostic state->buflen, state->dmalen, len, fifo); 121652889Sbostic #endif 121752889Sbostic if (fifo) { 121852942Sralph /* device must be trying to send more than we expect */ 121952889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 1220*56819Sralph readback(regs->asc_cmd); 122152889Sbostic MachEmptyWriteBuffer(); 122252889Sbostic } 122353080Sralph state->flags &= ~DMA_IN_PROGRESS; 122452889Sbostic len = state->dmalen - len; 122552889Sbostic state->buflen -= len; 122652889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 122752889Sbostic 122852889Sbostic return (1); 122952889Sbostic } 123052889Sbostic 123152889Sbostic /* ARGSUSED */ 123252889Sbostic static int 123352942Sralph asc_resume_in(asc, status, ss, ir) 123452942Sralph register asc_softc_t asc; 123552942Sralph register int status, ss, ir; 123652942Sralph { 123752942Sralph register asc_regmap_t *regs = asc->regs; 123852942Sralph register State *state = &asc->st[asc->target]; 123952942Sralph register int len; 124052942Sralph 124152942Sralph /* setup to start reading the next chunk */ 124252942Sralph len = state->buflen; 124352942Sralph if (len > state->dmaBufSize) 124452942Sralph len = state->dmaBufSize; 124552942Sralph state->dmalen = len; 1246*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 124752942Sralph ASC_TC_PUT(regs, len); 124852942Sralph #ifdef DEBUG 124952942Sralph if (asc_debug > 2) 125052942Sralph printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 125152942Sralph len); 125252942Sralph #endif 125352942Sralph 125452942Sralph /* check for next chunk */ 125553080Sralph state->flags |= DMA_IN_PROGRESS; 125652942Sralph if (len != state->buflen) { 125752942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1258*56819Sralph readback(regs->asc_cmd); 125952942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 126052942Sralph return (0); 126152942Sralph } 126252942Sralph return (1); 126352942Sralph } 126452942Sralph 126552942Sralph /* ARGSUSED */ 126652942Sralph static int 126752889Sbostic asc_resume_dma_in(asc, status, ss, ir) 126852889Sbostic register asc_softc_t asc; 126952889Sbostic register int status, ss, ir; 127052889Sbostic { 127152889Sbostic register asc_regmap_t *regs = asc->regs; 127252889Sbostic register State *state = &asc->st[asc->target]; 127352889Sbostic register int len, off; 127452889Sbostic 127552889Sbostic /* setup to finish reading the current chunk */ 127652889Sbostic len = state->dmaresid; 127752889Sbostic off = state->dmalen - len; 127852889Sbostic if ((off & 1) && state->sync_offset) { 127952889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 128052889Sbostic state->dmalen, len, off); /* XXX */ 128152889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 128252889Sbostic } 1283*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 128452889Sbostic ASC_TC_PUT(regs, len); 128552942Sralph #ifdef DEBUG 128652942Sralph if (asc_debug > 2) 128752942Sralph printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 128852942Sralph state->dmalen, state->buflen, len, off); 128952942Sralph #endif 129052942Sralph 129152942Sralph /* check for next chunk */ 129253080Sralph state->flags |= DMA_IN_PROGRESS; 129352889Sbostic if (state->dmalen != state->buflen) { 129452889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1295*56819Sralph readback(regs->asc_cmd); 129652942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 129752889Sbostic return (0); 129852889Sbostic } 129952889Sbostic return (1); 130052889Sbostic } 130152889Sbostic 130252889Sbostic /* ARGSUSED */ 130352889Sbostic static int 130452889Sbostic asc_dma_out(asc, status, ss, ir) 130552889Sbostic register asc_softc_t asc; 130652889Sbostic register int status, ss, ir; 130752889Sbostic { 130852889Sbostic register asc_regmap_t *regs = asc->regs; 130952889Sbostic register State *state = &asc->st[asc->target]; 131052889Sbostic register int len, fifo; 131152889Sbostic 131253080Sralph if (state->flags & DMA_IN_PROGRESS) { 131352889Sbostic /* check to be sure previous chunk was finished */ 131452889Sbostic ASC_TC_GET(regs, len); 131552889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 131652889Sbostic if (len || fifo) 131752889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 131852889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 131952889Sbostic len += fifo; 132052889Sbostic len = state->dmalen - len; 132153080Sralph state->buf += len; 132252889Sbostic state->buflen -= len; 132353080Sralph } 132452889Sbostic 132553080Sralph /* setup for this chunck */ 132653080Sralph len = state->buflen; 132753080Sralph if (len > state->dmaBufSize) 132853080Sralph len = state->dmaBufSize; 132953080Sralph state->dmalen = len; 133053080Sralph bcopy(state->buf, state->dmaBufAddr, len); 1331*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 133252942Sralph ASC_TC_PUT(regs, len); 133352889Sbostic #ifdef DEBUG 133452889Sbostic if (asc_debug > 2) 133552942Sralph printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 133652889Sbostic #endif 133752889Sbostic 133852889Sbostic /* check for next chunk */ 133953080Sralph state->flags |= DMA_IN_PROGRESS; 134052889Sbostic if (len != state->buflen) { 134152889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1342*56819Sralph readback(regs->asc_cmd); 134352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 134452889Sbostic return (0); 134552889Sbostic } 134652889Sbostic return (1); 134752889Sbostic } 134852889Sbostic 134952889Sbostic /* ARGSUSED */ 135052889Sbostic static int 135152889Sbostic asc_last_dma_out(asc, status, ss, ir) 135252889Sbostic register asc_softc_t asc; 135352889Sbostic register int status, ss, ir; 135452889Sbostic { 135552889Sbostic register asc_regmap_t *regs = asc->regs; 135652889Sbostic register State *state = &asc->st[asc->target]; 135752889Sbostic register int len, fifo; 135852889Sbostic 135952889Sbostic ASC_TC_GET(regs, len); 136052889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 136152889Sbostic #ifdef DEBUG 136252889Sbostic if (asc_debug > 2) 136352889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 136453080Sralph state->buflen, state->dmalen, len, fifo); 136552942Sralph #endif 136652942Sralph if (fifo) { 136752942Sralph len += fifo; 136852942Sralph regs->asc_cmd = ASC_CMD_FLUSH; 1369*56819Sralph readback(regs->asc_cmd); 137052942Sralph MachEmptyWriteBuffer(); 137152942Sralph } 137253080Sralph state->flags &= ~DMA_IN_PROGRESS; 137352889Sbostic len = state->dmalen - len; 137452889Sbostic state->buflen -= len; 137552889Sbostic return (1); 137652889Sbostic } 137752889Sbostic 137852889Sbostic /* ARGSUSED */ 137952889Sbostic static int 138052942Sralph asc_resume_out(asc, status, ss, ir) 138152942Sralph register asc_softc_t asc; 138252942Sralph register int status, ss, ir; 138352942Sralph { 138452942Sralph register asc_regmap_t *regs = asc->regs; 138552942Sralph register State *state = &asc->st[asc->target]; 138652942Sralph register int len; 138752942Sralph 138852942Sralph /* setup for this chunck */ 138952942Sralph len = state->buflen; 139052942Sralph if (len > state->dmaBufSize) 139152942Sralph len = state->dmaBufSize; 139252942Sralph state->dmalen = len; 139352942Sralph bcopy(state->buf, state->dmaBufAddr, len); 1394*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 139552942Sralph ASC_TC_PUT(regs, len); 139652942Sralph #ifdef DEBUG 139752942Sralph if (asc_debug > 2) 139852942Sralph printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 139952942Sralph len); 140052942Sralph #endif 140152942Sralph 140252942Sralph /* check for next chunk */ 140353080Sralph state->flags |= DMA_IN_PROGRESS; 140452942Sralph if (len != state->buflen) { 140552942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1406*56819Sralph readback(regs->asc_cmd); 140752942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 140852942Sralph return (0); 140952942Sralph } 141052942Sralph return (1); 141152942Sralph } 141252942Sralph 141352942Sralph /* ARGSUSED */ 141452942Sralph static int 141552889Sbostic asc_resume_dma_out(asc, status, ss, ir) 141652889Sbostic register asc_softc_t asc; 141752889Sbostic register int status, ss, ir; 141852889Sbostic { 141952889Sbostic register asc_regmap_t *regs = asc->regs; 142052889Sbostic register State *state = &asc->st[asc->target]; 142152889Sbostic register int len, off; 142252889Sbostic 142352889Sbostic /* setup to finish writing this chunk */ 142452889Sbostic len = state->dmaresid; 142552889Sbostic off = state->dmalen - len; 142652889Sbostic if (off & 1) { 142752889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 142852889Sbostic state->dmalen, len, off); /* XXX */ 142952889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 143052889Sbostic off++; 143152889Sbostic len--; 143252889Sbostic } 1433*56819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 143452889Sbostic ASC_TC_PUT(regs, len); 143552942Sralph #ifdef DEBUG 143652942Sralph if (asc_debug > 2) 143752942Sralph printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 143852942Sralph state->dmalen, state->buflen, len, off); 143952942Sralph #endif 144052942Sralph 144152942Sralph /* check for next chunk */ 144253080Sralph state->flags |= DMA_IN_PROGRESS; 144352889Sbostic if (state->dmalen != state->buflen) { 144452889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1445*56819Sralph readback(regs->asc_cmd); 144652942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 144752889Sbostic return (0); 144852889Sbostic } 144952889Sbostic return (1); 145052889Sbostic } 145152889Sbostic 145252889Sbostic /* ARGSUSED */ 145352889Sbostic static int 145452889Sbostic asc_sendsync(asc, status, ss, ir) 145552889Sbostic register asc_softc_t asc; 145652889Sbostic register int status, ss, ir; 145752889Sbostic { 145852889Sbostic register asc_regmap_t *regs = asc->regs; 145953080Sralph register State *state = &asc->st[asc->target]; 146052889Sbostic 146153080Sralph /* send the extended synchronous negotiation message */ 146252889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 146352889Sbostic MachEmptyWriteBuffer(); 146452889Sbostic regs->asc_fifo = 3; 146552889Sbostic MachEmptyWriteBuffer(); 146652889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 146752889Sbostic MachEmptyWriteBuffer(); 146852889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 146952889Sbostic MachEmptyWriteBuffer(); 147052889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 147153080Sralph /* state to resume after we see the sync reply message */ 147253080Sralph state->script = asc->script + 2; 147353080Sralph state->msglen = 0; 147452889Sbostic return (1); 147552889Sbostic } 147652889Sbostic 147752889Sbostic /* ARGSUSED */ 147852889Sbostic static int 147952889Sbostic asc_replysync(asc, status, ss, ir) 148052889Sbostic register asc_softc_t asc; 148152889Sbostic register int status, ss, ir; 148252889Sbostic { 148352889Sbostic register asc_regmap_t *regs = asc->regs; 148452889Sbostic register State *state = &asc->st[asc->target]; 148552889Sbostic 148652889Sbostic #ifdef DEBUG 148752889Sbostic if (asc_debug > 2) 148852889Sbostic printf("asc_replysync: %x %x\n", 1489*56819Sralph asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 149052889Sbostic state->sync_offset); 149152889Sbostic #endif 149252889Sbostic /* send synchronous transfer in response to a request */ 149352889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 149452889Sbostic MachEmptyWriteBuffer(); 149552889Sbostic regs->asc_fifo = 3; 149652889Sbostic MachEmptyWriteBuffer(); 149752889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 149852889Sbostic MachEmptyWriteBuffer(); 1499*56819Sralph regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 150052889Sbostic MachEmptyWriteBuffer(); 150152889Sbostic regs->asc_fifo = state->sync_offset; 150252889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 1503*56819Sralph readback(regs->asc_cmd); 150452889Sbostic 150552889Sbostic /* return to the appropriate script */ 150652889Sbostic if (!state->script) { 150752889Sbostic #ifdef DEBUG 150852889Sbostic asc_DumpLog("asc_replsync"); 150952889Sbostic #endif 151052889Sbostic panic("asc_replysync"); 151152889Sbostic } 151252889Sbostic asc->script = state->script; 151352889Sbostic state->script = (script_t *)0; 151452889Sbostic return (0); 151552889Sbostic } 151652889Sbostic 151752889Sbostic /* ARGSUSED */ 151852889Sbostic static int 151952942Sralph asc_msg_in(asc, status, ss, ir) 152052889Sbostic register asc_softc_t asc; 152152889Sbostic register int status, ss, ir; 152252889Sbostic { 152352889Sbostic register asc_regmap_t *regs = asc->regs; 152452889Sbostic register State *state = &asc->st[asc->target]; 152552889Sbostic register int msg; 152652889Sbostic int i; 152752889Sbostic 152852889Sbostic /* read one message byte */ 152952889Sbostic msg = regs->asc_fifo; 153052889Sbostic #ifdef DEBUG 153152889Sbostic if (asc_logp == asc_log) 153252889Sbostic asc_log[NLOG - 1].msg = msg; 153352889Sbostic else 153452889Sbostic asc_logp[-1].msg = msg; 153552889Sbostic #endif 153652889Sbostic 153752889Sbostic /* check for multi-byte message */ 153852889Sbostic if (state->msglen != 0) { 153952889Sbostic /* first byte is the message length */ 154052889Sbostic if (state->msglen < 0) { 154152889Sbostic state->msglen = msg; 154252889Sbostic return (1); 154352889Sbostic } 154452889Sbostic if (state->msgcnt >= state->msglen) 154552889Sbostic goto abort; 154652889Sbostic state->msg_in[state->msgcnt++] = msg; 154752889Sbostic 154852889Sbostic /* did we just read the last byte of the message? */ 154952889Sbostic if (state->msgcnt != state->msglen) 155052889Sbostic return (1); 155152889Sbostic 155252889Sbostic /* process an extended message */ 155352889Sbostic #ifdef DEBUG 155452889Sbostic if (asc_debug > 2) 155552942Sralph printf("asc_msg_in: msg %x %x %x\n", 155652889Sbostic state->msg_in[0], 155752889Sbostic state->msg_in[1], 155852889Sbostic state->msg_in[2]); 155952889Sbostic #endif 156052889Sbostic switch (state->msg_in[0]) { 156152889Sbostic case SCSI_SYNCHRONOUS_XFER: 156252889Sbostic state->flags |= DID_SYNC; 156352889Sbostic state->sync_offset = state->msg_in[2]; 156452889Sbostic 156552889Sbostic /* convert SCSI period to ASC period */ 1566*56819Sralph i = state->msg_in[1] / asc->tb_ticks; 1567*56819Sralph if (i < asc->min_period) 1568*56819Sralph i = asc->min_period; 1569*56819Sralph else if (i >= asc->max_period) { 157052889Sbostic /* can't do sync transfer, period too long */ 157152889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 157252889Sbostic asc - asc_softc, asc->target, i); 1573*56819Sralph i = asc->max_period; 157452889Sbostic state->sync_offset = 0; 157552889Sbostic } 1576*56819Sralph if ((i * asc->tb_ticks) != state->msg_in[1]) 157752889Sbostic i++; 157852889Sbostic state->sync_period = i & 0x1F; 157952889Sbostic 158052889Sbostic /* 158152889Sbostic * If this is a request, check minimums and 158252889Sbostic * send back an acknowledge. 158352889Sbostic */ 158452889Sbostic if (!(state->flags & TRY_SYNC)) { 158552889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 1586*56819Sralph readback(regs->asc_cmd); 158752889Sbostic MachEmptyWriteBuffer(); 158852889Sbostic 1589*56819Sralph if (state->sync_period < asc->min_period) 159052889Sbostic state->sync_period = 1591*56819Sralph asc->min_period; 159252889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 159352889Sbostic state->sync_offset = 159452889Sbostic ASC_MAX_OFFSET; 159552889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 159652889Sbostic regs->asc_syn_p = state->sync_period; 1597*56819Sralph readback(regs->asc_syn_p); 159852889Sbostic regs->asc_syn_o = state->sync_offset; 1599*56819Sralph readback(regs->asc_syn_o); 160052889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1601*56819Sralph readback(regs->asc_cmd); 160252889Sbostic return (0); 160352889Sbostic } 160452889Sbostic 160552889Sbostic regs->asc_syn_p = state->sync_period; 1606*56819Sralph readback(regs->asc_syn_p); 160752889Sbostic regs->asc_syn_o = state->sync_offset; 1608*56819Sralph readback(regs->asc_syn_o); 160952889Sbostic goto done; 161052889Sbostic 161152889Sbostic default: 161252889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 161352889Sbostic asc - asc_softc, asc->target, 161452889Sbostic state->msg_in[0]); 161552889Sbostic goto reject; 161652889Sbostic } 161752889Sbostic } 161852889Sbostic 161952889Sbostic /* process first byte of a message */ 162052889Sbostic #ifdef DEBUG 162152889Sbostic if (asc_debug > 2) 162252942Sralph printf("asc_msg_in: msg %x\n", msg); 162352889Sbostic #endif 162452889Sbostic switch (msg) { 162552889Sbostic #if 0 162652889Sbostic case SCSI_MESSAGE_REJECT: 162752889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 162852889Sbostic state->flags |= DID_SYNC; 162952889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1630*56819Sralph readback(regs->asc_cmd); 163152889Sbostic status = asc_wait(regs, ASC_CSR_INT); 163252889Sbostic ir = regs->asc_intr; 163352889Sbostic /* some just break out here, some dont */ 163452889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 163552889Sbostic regs->asc_fifo = SCSI_ABORT; 163652889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 1637*56819Sralph readback(regs->asc_cmd); 163852889Sbostic status = asc_wait(regs, ASC_CSR_INT); 163952889Sbostic ir = regs->asc_intr; 164052889Sbostic } 164152889Sbostic if (ir & ASC_INT_DISC) { 164252889Sbostic asc_end(asc, status, 0, ir); 164352889Sbostic return (0); 164452889Sbostic } 164552889Sbostic goto status; 164652889Sbostic #endif 164752889Sbostic 164852889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 164952889Sbostic /* setup to read message length next */ 165052889Sbostic state->msglen = -1; 165152889Sbostic state->msgcnt = 0; 165252889Sbostic return (1); 165352889Sbostic 165452889Sbostic case SCSI_NO_OP: 165552889Sbostic break; 165652889Sbostic 165752889Sbostic case SCSI_SAVE_DATA_POINTER: 165852889Sbostic /* expect another message */ 165952889Sbostic return (1); 166052889Sbostic 166152889Sbostic case SCSI_RESTORE_POINTERS: 166252889Sbostic /* 166352889Sbostic * Need to do the following if resuming synchonous data in 166452889Sbostic * on an odd byte boundary. 166552889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 166652889Sbostic */ 166752889Sbostic break; 166852889Sbostic 166952889Sbostic case SCSI_DISCONNECT: 167052889Sbostic if (state->flags & DISCONN) 167152889Sbostic goto abort; 167252889Sbostic state->flags |= DISCONN; 167352942Sralph regs->asc_cmd = ASC_CMD_MSG_ACPT; 1674*56819Sralph readback(regs->asc_cmd); 167552942Sralph asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 167652942Sralph return (0); 167752889Sbostic 167852889Sbostic default: 167952889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 168052889Sbostic asc - asc_softc, asc->target, msg); 168152889Sbostic reject: 168252889Sbostic /* request a message out before acknowledging this message */ 168352889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 168452889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 1685*56819Sralph readback(regs->asc_cmd); 168652889Sbostic MachEmptyWriteBuffer(); 168752889Sbostic } 168852889Sbostic 168952889Sbostic done: 169052889Sbostic /* return to original script */ 169152889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1692*56819Sralph readback(regs->asc_cmd); 169352889Sbostic if (!state->script) { 169452889Sbostic abort: 169552889Sbostic #ifdef DEBUG 169652942Sralph asc_DumpLog("asc_msg_in"); 169752889Sbostic #endif 169852942Sralph panic("asc_msg_in"); 169952889Sbostic } 170052889Sbostic asc->script = state->script; 170152889Sbostic state->script = (script_t *)0; 170252889Sbostic return (0); 170352889Sbostic } 170452889Sbostic 170552942Sralph /* ARGSUSED */ 170652942Sralph static int 170752942Sralph asc_disconnect(asc, status, ss, ir) 170852942Sralph register asc_softc_t asc; 170952942Sralph register int status, ss, ir; 171052942Sralph { 171152942Sralph register State *state = &asc->st[asc->target]; 171252942Sralph 171352942Sralph asc->target = -1; 171452942Sralph asc->state = ASC_STATE_RESEL; 171552942Sralph return (1); 171652942Sralph } 171752942Sralph 1718*56819Sralph /* 1719*56819Sralph * DMA handling routines. For a turbochannel device, just set the dmar 1720*56819Sralph * for the I/O ASIC, handle the actual DMA interface. 1721*56819Sralph */ 1722*56819Sralph static void 1723*56819Sralph tb_dma_start(asc, state, cp, flag) 1724*56819Sralph asc_softc_t asc; 1725*56819Sralph State *state; 1726*56819Sralph caddr_t cp; 1727*56819Sralph int flag; 1728*56819Sralph { 1729*56819Sralph 1730*56819Sralph if (flag == ASCDMA_WRITE) 1731*56819Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 1732*56819Sralph else 1733*56819Sralph *asc->dmar = ASC_DMA_ADDR(cp); 1734*56819Sralph } 1735*56819Sralph 1736*56819Sralph static void 1737*56819Sralph tb_dma_end(asc, state, flag) 1738*56819Sralph asc_softc_t asc; 1739*56819Sralph State *state; 1740*56819Sralph int flag; 1741*56819Sralph { 1742*56819Sralph 1743*56819Sralph } 1744*56819Sralph 1745*56819Sralph static void 1746*56819Sralph asic_dma_start(asc, state, cp, flag) 1747*56819Sralph asc_softc_t asc; 1748*56819Sralph State *state; 1749*56819Sralph caddr_t cp; 1750*56819Sralph int flag; 1751*56819Sralph { 1752*56819Sralph register volatile u_int *ssr = (volatile u_int *) 1753*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR); 1754*56819Sralph u_int phys, nphys; 1755*56819Sralph 1756*56819Sralph /* stop DMA engine first */ 1757*56819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1758*56819Sralph * ((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR)) = 0; 1759*56819Sralph 1760*56819Sralph phys = MACH_CACHED_TO_PHYS(cp); 1761*56819Sralph cp = (caddr_t)pmax_trunc_page(cp + NBPG); 1762*56819Sralph nphys = MACH_CACHED_TO_PHYS(cp); 1763*56819Sralph 1764*56819Sralph asc->dma_next = cp; 1765*56819Sralph asc->dma_xfer = state->dmalen - (nphys - phys); 1766*56819Sralph 1767*56819Sralph *(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR) = 1768*56819Sralph ASIC_DMA_ADDR(phys); 1769*56819Sralph *(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR) = 1770*56819Sralph ASIC_DMA_ADDR(nphys); 1771*56819Sralph if (flag == ASCDMA_READ) 1772*56819Sralph *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 1773*56819Sralph else 1774*56819Sralph *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 1775*56819Sralph MachEmptyWriteBuffer(); 1776*56819Sralph } 1777*56819Sralph 1778*56819Sralph static void 1779*56819Sralph asic_dma_end(asc, state, flag) 1780*56819Sralph asc_softc_t asc; 1781*56819Sralph State *state; 1782*56819Sralph int flag; 1783*56819Sralph { 1784*56819Sralph register volatile u_int *ssr = (volatile u_int *) 1785*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR); 1786*56819Sralph int nb; 1787*56819Sralph 1788*56819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1789*56819Sralph *((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMAPTR)) = -1; 1790*56819Sralph *((volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR)) = -1; 1791*56819Sralph MachEmptyWriteBuffer(); 1792*56819Sralph 1793*56819Sralph if (flag == ASCDMA_READ) { 1794*56819Sralph MachFlushDCache(MACH_PHYS_TO_CACHED( 1795*56819Sralph MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1796*56819Sralph if (nb = *((int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SCR))) { 1797*56819Sralph /* pick up last upto6 bytes, sigh. */ 1798*56819Sralph register u_short *to; 1799*56819Sralph register int w; 1800*56819Sralph 1801*56819Sralph /* Last byte really xferred is.. */ 1802*56819Sralph to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1)); 1803*56819Sralph w = *(int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SDR0); 1804*56819Sralph *to++ = w; 1805*56819Sralph if (--nb > 0) { 1806*56819Sralph w >>= 16; 1807*56819Sralph *to++ = w; 1808*56819Sralph } 1809*56819Sralph if (--nb > 0) { 1810*56819Sralph w = *(int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_SDR1); 1811*56819Sralph *to++ = w; 1812*56819Sralph } 1813*56819Sralph } 1814*56819Sralph } 1815*56819Sralph } 1816*56819Sralph 1817*56819Sralph /* 1818*56819Sralph * Called by asic_intr() for scsi dma pointer update interrupts. 1819*56819Sralph */ 1820*56819Sralph void 1821*56819Sralph asc_dma_intr() 1822*56819Sralph { 1823*56819Sralph asc_softc_t asc = &asc_softc[0]; 1824*56819Sralph u_int next_phys; 1825*56819Sralph 1826*56819Sralph asc->dma_xfer -= NBPG; 1827*56819Sralph if (asc->dma_xfer <= -NBPG) { 1828*56819Sralph volatile u_int *ssr = (volatile u_int *) 1829*56819Sralph MACH_PHYS_TO_UNCACHED(KMIN_REG_CSR); 1830*56819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1831*56819Sralph } else { 1832*56819Sralph asc->dma_next += NBPG; 1833*56819Sralph next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 1834*56819Sralph } 1835*56819Sralph #ifdef notdef 1836*56819Sralph else 1837*56819Sralph next_phys = MACH_CACHED_TO_PHYS(asc_iobuf); 1838*56819Sralph #endif 1839*56819Sralph *(volatile int *)MACH_PHYS_TO_UNCACHED(KMIN_REG_SCSI_DMANPTR) = 1840*56819Sralph ASIC_DMA_ADDR(next_phys); 1841*56819Sralph MachEmptyWriteBuffer(); 1842*56819Sralph } 1843*56819Sralph 184452889Sbostic #ifdef DEBUG 184552889Sbostic asc_DumpLog(str) 184652889Sbostic char *str; 184752889Sbostic { 184852889Sbostic register struct asc_log *lp; 184952889Sbostic register u_int status; 185052889Sbostic 185152889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 185252889Sbostic asc_debug_bn, asc_debug_sz); 185352889Sbostic lp = asc_logp + 1; 185452889Sbostic if (lp > &asc_log[NLOG]) 185552889Sbostic lp = asc_log; 185652889Sbostic while (lp != asc_logp) { 185752889Sbostic status = lp->status; 185852889Sbostic printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 185952889Sbostic status >> 24, 186052889Sbostic lp->target, 186152889Sbostic (status >> 16) & 0xFF, 186252889Sbostic (status >> 8) & 0xFF, 186352889Sbostic status & 0XFF, 186452889Sbostic lp->state, 186552889Sbostic asc_scripts[lp->state].condition, 186652889Sbostic lp->msg); 186752889Sbostic if (++lp >= &asc_log[NLOG]) 186852889Sbostic lp = asc_log; 186952889Sbostic } 187052889Sbostic } 187152889Sbostic #endif 187252889Sbostic 187352889Sbostic #endif /* NASC > 0 */ 1874