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 656819Sralph * Ralph Campbell and Rick Macklem. 752889Sbostic * 852889Sbostic * %sccs.include.redist.c% 952889Sbostic * 10*57233Sralph * @(#)asc.c 7.9 (Berkeley) 12/20/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 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; 16652889Sbostic #define NLOG 16 16752889Sbostic struct asc_log { 16852889Sbostic u_int status; 16952889Sbostic u_char state; 17052889Sbostic u_char msg; 17152889Sbostic int target; 17252889Sbostic } asc_log[NLOG], *asc_logp = asc_log; 17352889Sbostic #define PACK(unit, status, ss, ir) \ 17452889Sbostic ((unit << 24) | (status << 16) | (ss << 8) | ir) 17552889Sbostic #endif 17652889Sbostic 17752889Sbostic /* 17852889Sbostic * Scripts are entries in a state machine table. 17952889Sbostic * A script has four parts: a pre-condition, an action, a command to the chip, 18052889Sbostic * and an index into asc_scripts for the next state. The first triggers error 18152889Sbostic * handling if not satisfied and in our case it is formed by the 18252889Sbostic * values of the interrupt register and status register, this 18352889Sbostic * basically captures the phase of the bus and the TC and BS 18452889Sbostic * bits. The action part is just a function pointer, and the 18552889Sbostic * command is what the 53C94 should be told to do at the end 18652889Sbostic * of the action processing. This command is only issued and the 18752889Sbostic * script proceeds if the action routine returns TRUE. 18852889Sbostic * See asc_intr() for how and where this is all done. 18952889Sbostic */ 19052889Sbostic typedef struct script { 19152889Sbostic int condition; /* expected state at interrupt time */ 19252889Sbostic int (*action)(); /* extra operations */ 19352889Sbostic int command; /* command to the chip */ 19452889Sbostic struct script *next; /* index into asc_scripts for next state */ 19552889Sbostic } script_t; 19652889Sbostic 19752889Sbostic /* Matching on the condition value */ 19852889Sbostic #define SCRIPT_MATCH(ir, csr) ((ir) | (ASC_PHASE(csr) << 8)) 19952889Sbostic 20052889Sbostic /* forward decls of script actions */ 20156819Sralph static int script_nop(); /* when nothing needed */ 20256819Sralph static int asc_end(); /* all come to an end */ 20356819Sralph static int asc_get_status(); /* get status from target */ 20456819Sralph static int asc_dma_in(); /* start reading data from target */ 20556819Sralph static int asc_last_dma_in(); /* cleanup after all data is read */ 20656819Sralph static int asc_resume_in(); /* resume data in after a message */ 20756819Sralph static int asc_resume_dma_in(); /* resume DMA after a disconnect */ 20856819Sralph static int asc_dma_out(); /* send data to target via dma */ 20956819Sralph static int asc_last_dma_out(); /* cleanup after all data is written */ 21056819Sralph static int asc_resume_out(); /* resume data out after a message */ 21156819Sralph static int asc_resume_dma_out(); /* resume DMA after a disconnect */ 21256819Sralph static int asc_sendsync(); /* negotiate sync xfer */ 21356819Sralph static int asc_replysync(); /* negotiate sync xfer */ 21456819Sralph static int asc_msg_in(); /* process a message byte */ 21556819Sralph static int asc_disconnect(); /* process an expected disconnect */ 21652889Sbostic 21752889Sbostic /* Define the index into asc_scripts for various state transitions */ 21852889Sbostic #define SCRIPT_DATA_IN 0 21952942Sralph #define SCRIPT_CONTINUE_IN 2 22052942Sralph #define SCRIPT_DATA_OUT 3 22152942Sralph #define SCRIPT_CONTINUE_OUT 5 22252942Sralph #define SCRIPT_SIMPLE 6 22352942Sralph #define SCRIPT_GET_STATUS 7 22452942Sralph #define SCRIPT_MSG_IN 9 22552942Sralph #define SCRIPT_REPLY_SYNC 11 22652889Sbostic #define SCRIPT_TRY_SYNC 12 22752942Sralph #define SCRIPT_DISCONNECT 15 22852942Sralph #define SCRIPT_RESEL 16 22952942Sralph #define SCRIPT_RESUME_IN 17 23052942Sralph #define SCRIPT_RESUME_DMA_IN 18 23152942Sralph #define SCRIPT_RESUME_OUT 19 23252942Sralph #define SCRIPT_RESUME_DMA_OUT 20 23352942Sralph #define SCRIPT_RESUME_NO_DATA 21 23452889Sbostic 23552889Sbostic /* 23652889Sbostic * Scripts 23752889Sbostic */ 23852889Sbostic script_t asc_scripts[] = { 23952942Sralph /* start data in */ 24052889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 24152889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 24252942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 24352889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 24452889Sbostic asc_last_dma_in, ASC_CMD_I_COMPLETE, 24552942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 24652889Sbostic 24752942Sralph /* continue data in after a chuck is finished */ 24852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 24952942Sralph asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 25052942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 25152942Sralph 25252942Sralph /* start data out */ 25352942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 25452889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 25552942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 25652942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 25752889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 25852942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 25952889Sbostic 26052942Sralph /* continue data out after a chuck is finished */ 26152942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 26252942Sralph asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 26352942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 26452942Sralph 26552889Sbostic /* simple command with no data transfer */ 26652942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 26752889Sbostic script_nop, ASC_CMD_I_COMPLETE, 26852942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 26952889Sbostic 27052889Sbostic /* get status and finish command */ 27152942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 27252889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 27352942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 27452942Sralph {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 27552889Sbostic asc_end, ASC_CMD_NOP, 27652942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 27752889Sbostic 27852889Sbostic /* message in */ 27952942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 28052942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 28152942Sralph &asc_scripts[SCRIPT_MSG_IN + 1]}, 28252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 28352889Sbostic script_nop, ASC_CMD_XFER_INFO, 28452942Sralph &asc_scripts[SCRIPT_MSG_IN]}, 28552889Sbostic 28652889Sbostic /* send synchonous negotiation reply */ 28752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 28852889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 28952942Sralph &asc_scripts[SCRIPT_REPLY_SYNC]}, 29052889Sbostic 29152889Sbostic /* try to negotiate synchonous transfer parameters */ 29252889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 29352889Sbostic asc_sendsync, ASC_CMD_XFER_INFO, 29453080Sralph &asc_scripts[SCRIPT_TRY_SYNC + 1]}, 29553080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ 29652889Sbostic script_nop, ASC_CMD_XFER_INFO, 29753080Sralph &asc_scripts[SCRIPT_MSG_IN]}, 29853080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ 29953080Sralph script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 30053080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]}, 30152889Sbostic 30252942Sralph /* handle a disconnect */ 30352942Sralph {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 30452942Sralph asc_disconnect, ASC_CMD_ENABLE_SEL, 30552942Sralph &asc_scripts[SCRIPT_RESEL]}, 30652942Sralph 30752889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 30852942Sralph {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 30952889Sbostic script_nop, ASC_CMD_MSG_ACPT, 31052942Sralph &asc_scripts[SCRIPT_RESEL]}, 31152889Sbostic 31252942Sralph /* resume data in after a message */ 31352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 31452942Sralph asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 31552942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 31652942Sralph 31752942Sralph /* resume partial DMA data in after a message */ 31852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 31952889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32052942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 32152889Sbostic 32252942Sralph /* resume data out after a message */ 32352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 32452942Sralph asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32552942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 32652942Sralph 32752942Sralph /* resume partial DMA data out after a message */ 32852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 32952889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 33052942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 33152942Sralph 33252942Sralph /* resume after a message when there is no more data */ 33352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 33452942Sralph script_nop, ASC_CMD_I_COMPLETE, 33552942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 33652889Sbostic }; 33752889Sbostic 33852889Sbostic /* 33952889Sbostic * State kept for each active SCSI device. 34052889Sbostic */ 34152889Sbostic typedef struct scsi_state { 34252889Sbostic script_t *script; /* saved script while processing error */ 34352889Sbostic int statusByte; /* status byte returned during STATUS_PHASE */ 34452889Sbostic int error; /* errno to pass back to device driver */ 34552889Sbostic u_char *dmaBufAddr; /* DMA buffer address */ 34652889Sbostic u_int dmaBufSize; /* DMA buffer size */ 34752889Sbostic int dmalen; /* amount to transfer in this chunk */ 34852889Sbostic int dmaresid; /* amount not transfered if chunk suspended */ 34952889Sbostic int buflen; /* total remaining amount of data to transfer */ 35052889Sbostic char *buf; /* current pointer within scsicmd->buf */ 35152889Sbostic int flags; /* see below */ 35252889Sbostic int msglen; /* number of message bytes to read */ 35352889Sbostic int msgcnt; /* number of message bytes received */ 35452889Sbostic u_char sync_period; /* DMA synchronous period */ 35552889Sbostic u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 35652889Sbostic u_char msg_out; /* next MSG_OUT byte to send */ 35752889Sbostic u_char msg_in[16]; /* buffer for multibyte messages */ 35852889Sbostic } State; 35952889Sbostic 36052889Sbostic /* state flags */ 36152889Sbostic #define DISCONN 0x01 /* true if currently disconnected from bus */ 36253080Sralph #define DMA_IN_PROGRESS 0x02 /* true if data DMA started */ 36352889Sbostic #define DMA_IN 0x04 /* true if reading from SCSI device */ 36452889Sbostic #define DMA_OUT 0x10 /* true if writing to SCSI device */ 36552889Sbostic #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 36652889Sbostic #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 36752889Sbostic 36852889Sbostic /* 36952889Sbostic * State kept for each active SCSI host interface (53C94). 37052889Sbostic */ 37152889Sbostic struct asc_softc { 37252889Sbostic asc_regmap_t *regs; /* chip address */ 37352889Sbostic volatile int *dmar; /* DMA address register address */ 37456819Sralph u_char *buff; /* RAM buffer address (uncached) */ 37552889Sbostic int myid; /* SCSI ID of this interface */ 37652889Sbostic int myidmask; /* ~(1 << myid) */ 37752889Sbostic int state; /* current SCSI connection state */ 37852889Sbostic int target; /* target SCSI ID if busy */ 37952889Sbostic script_t *script; /* next expected interrupt & action */ 38052889Sbostic ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 38152889Sbostic State st[ASC_NCMD]; /* state info for each active command */ 38256819Sralph void (*dma_start)(); /* Start dma routine */ 38356819Sralph void (*dma_end)(); /* End dma routine */ 38456819Sralph u_char *dma_next; 38556819Sralph int dma_xfer; /* Dma len still to go */ 38656819Sralph int min_period; /* Min transfer period clk/byte */ 38756819Sralph int max_period; /* Max transfer period clk/byte */ 38856819Sralph int ccf; /* CCF, whatever that really is? */ 38956819Sralph int timeout_250; /* 250ms timeout */ 39056819Sralph int tb_ticks; /* 4ns. ticks/tb channel ticks */ 39152889Sbostic } asc_softc[NASC]; 39252889Sbostic 39352889Sbostic #define ASC_STATE_IDLE 0 /* idle state */ 39452889Sbostic #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 39552889Sbostic #define ASC_STATE_TARGET 2 /* currently selected as target */ 39652889Sbostic #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 39752889Sbostic 39852889Sbostic typedef struct asc_softc *asc_softc_t; 39952889Sbostic 40052889Sbostic /* 40156819Sralph * Dma operations. 40256819Sralph */ 40356819Sralph #define ASCDMA_READ 1 40456819Sralph #define ASCDMA_WRITE 2 40556819Sralph static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end(); 406*57233Sralph extern u_long asc_iomem; 407*57233Sralph extern u_long asic_base; 40856819Sralph 40956819Sralph /* 41052889Sbostic * Definition of the controller for the auto-configuration program. 41152889Sbostic */ 41252889Sbostic int asc_probe(); 41352889Sbostic void asc_start(); 41452889Sbostic void asc_intr(); 41552889Sbostic struct driver ascdriver = { 41652889Sbostic "asc", asc_probe, asc_start, 0, asc_intr, 41752889Sbostic }; 41852889Sbostic 41952889Sbostic /* 42052889Sbostic * Test to see if device is present. 42152889Sbostic * Return true if found and initialized ok. 42252889Sbostic */ 42352889Sbostic asc_probe(cp) 42452889Sbostic register struct pmax_ctlr *cp; 42552889Sbostic { 42652889Sbostic register asc_softc_t asc; 42752889Sbostic register asc_regmap_t *regs; 42852889Sbostic int unit, id, s, i; 429*57233Sralph int bufsiz; 43052889Sbostic 43152889Sbostic if ((unit = cp->pmax_unit) >= NASC) 43252889Sbostic return (0); 43352889Sbostic if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 43452889Sbostic return (0); 43552889Sbostic asc = &asc_softc[unit]; 43652889Sbostic 43752889Sbostic /* 43852889Sbostic * Initialize hw descriptor, cache some pointers 43952889Sbostic */ 44052889Sbostic asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 44152889Sbostic 44256819Sralph /* 44356819Sralph * Set up machine dependencies. 44456819Sralph * 1) how to do dma 44556819Sralph * 2) timing based on turbochannel frequency 44656819Sralph */ 44756819Sralph switch (pmax_boardtype) { 44856819Sralph case DS_3MIN: 44956819Sralph case DS_MAXINE: 450*57233Sralph case DS_3MAXPLUS: 45156819Sralph if (unit == 0) { 452*57233Sralph asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); 453*57233Sralph bufsiz = 8192; 454*57233Sralph *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 455*57233Sralph *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 456*57233Sralph *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 45756819Sralph asc->dma_start = asic_dma_start; 45856819Sralph asc->dma_end = asic_dma_end; 45956819Sralph break; 46056819Sralph } 46156819Sralph /* 46256819Sralph * Fall through for turbochannel option. 46356819Sralph */ 46456819Sralph case DS_3MAX: 46556819Sralph default: 46656819Sralph asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 46756819Sralph asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 468*57233Sralph bufsiz = PER_TGT_DMA_SIZE; 46956819Sralph asc->dma_start = tb_dma_start; 47056819Sralph asc->dma_end = tb_dma_end; 47156819Sralph }; 47256819Sralph /* 47356819Sralph * Now for timing. The 3max has a 25Mhz tb whereas the 3min and 47456819Sralph * maxine are 12.5Mhz. 47556819Sralph */ 47656819Sralph switch (pmax_boardtype) { 47756819Sralph case DS_3MAX: 478*57233Sralph case DS_3MAXPLUS: 47956819Sralph asc->min_period = ASC_MIN_PERIOD25; 48056819Sralph asc->max_period = ASC_MAX_PERIOD25; 48156819Sralph asc->ccf = ASC_CCF(25); 48256819Sralph asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf); 48356819Sralph asc->tb_ticks = 10; 48456819Sralph break; 48556819Sralph case DS_3MIN: 48656819Sralph case DS_MAXINE: 48756819Sralph default: 48856819Sralph asc->min_period = ASC_MIN_PERIOD12; 48956819Sralph asc->max_period = ASC_MAX_PERIOD12; 49056819Sralph asc->ccf = ASC_CCF(13); 49156819Sralph asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); 49256819Sralph asc->tb_ticks = 20; 49356819Sralph break; 49456819Sralph }; 49556819Sralph 49652889Sbostic asc->state = ASC_STATE_IDLE; 49752889Sbostic asc->target = -1; 49852889Sbostic 49952889Sbostic regs = asc->regs; 50052889Sbostic 50152889Sbostic /* 50252889Sbostic * Reset chip, fully. Note that interrupts are already enabled. 50352889Sbostic */ 50452889Sbostic s = splbio(); 50552889Sbostic 50652889Sbostic /* preserve our ID for now */ 50752889Sbostic asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 50852889Sbostic asc->myidmask = ~(1 << asc->myid); 50952889Sbostic 51052889Sbostic asc_reset(asc, regs); 51152889Sbostic 51252889Sbostic /* 51352889Sbostic * Our SCSI id on the bus. 51452889Sbostic * The user can set this via the prom on 3maxen/pmaxen. 51552889Sbostic * If this changes it is easy to fix: make a default that 51652889Sbostic * can be changed as boot arg. 51752889Sbostic */ 51852889Sbostic #ifdef unneeded 51952889Sbostic regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 52052889Sbostic (scsi_initiator_id[unit] & 0x7); 52152889Sbostic #endif 52252889Sbostic id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 52352889Sbostic splx(s); 52452889Sbostic 52552889Sbostic /* 52652889Sbostic * Statically partition the DMA buffer between targets. 52752889Sbostic * This way we will eventually be able to attach/detach 52852889Sbostic * drives on-fly. And 18k/target is plenty for normal use. 52952889Sbostic */ 53052889Sbostic 53152889Sbostic /* 53252889Sbostic * Give each target its own DMA buffer region. 53352889Sbostic * We may want to try ping ponging buffers later. 53452889Sbostic */ 53552889Sbostic for (i = 0; i < ASC_NCMD; i++) { 536*57233Sralph asc->st[i].dmaBufAddr = asc->buff + bufsiz * i; 537*57233Sralph asc->st[i].dmaBufSize = bufsiz; 53852889Sbostic } 53952889Sbostic printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 54052889Sbostic unit, cp->pmax_addr, cp->pmax_pri, id); 54152889Sbostic return (1); 54252889Sbostic } 54352889Sbostic 54452889Sbostic /* 54552889Sbostic * Start activity on a SCSI device. 54652889Sbostic * We maintain information on each device separately since devices can 54752889Sbostic * connect/disconnect during an operation. 54852889Sbostic */ 54952889Sbostic void 55052889Sbostic asc_start(scsicmd) 55152889Sbostic register ScsiCmd *scsicmd; /* command to start */ 55252889Sbostic { 55352889Sbostic register struct scsi_device *sdp = scsicmd->sd; 55452889Sbostic register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 55552889Sbostic int s; 55652889Sbostic 55752889Sbostic s = splbio(); 55852889Sbostic /* 55952889Sbostic * Check if another command is already in progress. 56052889Sbostic * We may have to change this if we allow SCSI devices with 56152889Sbostic * separate LUNs. 56252889Sbostic */ 56352889Sbostic if (asc->cmd[sdp->sd_drive]) { 56452889Sbostic printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 56552889Sbostic sdp->sd_driver->d_name); 56652889Sbostic (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 56752889Sbostic scsicmd->buflen, 0); 56852889Sbostic splx(s); 56952889Sbostic } 57052889Sbostic asc->cmd[sdp->sd_drive] = scsicmd; 57152889Sbostic asc_startcmd(asc, sdp->sd_drive); 57252889Sbostic splx(s); 57352889Sbostic } 57452889Sbostic 57552889Sbostic static void 57652889Sbostic asc_reset(asc, regs) 57752889Sbostic asc_softc_t asc; 57852889Sbostic asc_regmap_t *regs; 57952889Sbostic { 58052889Sbostic 58152889Sbostic /* 58252889Sbostic * Reset chip and wait till done 58352889Sbostic */ 58452889Sbostic regs->asc_cmd = ASC_CMD_RESET; 58552889Sbostic MachEmptyWriteBuffer(); DELAY(25); 58652889Sbostic 58752889Sbostic /* spec says this is needed after reset */ 58852889Sbostic regs->asc_cmd = ASC_CMD_NOP; 58952889Sbostic MachEmptyWriteBuffer(); DELAY(25); 59052889Sbostic 59152889Sbostic /* 59252889Sbostic * Set up various chip parameters 59352889Sbostic */ 59456819Sralph regs->asc_ccf = asc->ccf; 59552889Sbostic MachEmptyWriteBuffer(); DELAY(25); 59656819Sralph regs->asc_sel_timo = asc->timeout_250; 59752889Sbostic /* restore our ID */ 59852889Sbostic regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 599*57233Sralph /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ 600*57233Sralph regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; 60152889Sbostic regs->asc_cnfg3 = 0; 60252889Sbostic /* zero anything else */ 60352889Sbostic ASC_TC_PUT(regs, 0); 60456819Sralph regs->asc_syn_p = asc->min_period; 60552889Sbostic regs->asc_syn_o = 0; /* async for now */ 60652889Sbostic MachEmptyWriteBuffer(); 60752889Sbostic } 60852889Sbostic 60952889Sbostic /* 61052889Sbostic * Start a SCSI command on a target. 61152889Sbostic */ 61252889Sbostic static void 61352889Sbostic asc_startcmd(asc, target) 61452889Sbostic asc_softc_t asc; 61552889Sbostic int target; 61652889Sbostic { 61752889Sbostic register asc_regmap_t *regs; 61852889Sbostic register ScsiCmd *scsicmd; 61952889Sbostic register State *state; 62052889Sbostic int len; 62152889Sbostic 62252889Sbostic /* 62352889Sbostic * See if another target is currently selected on this SCSI bus. 62452889Sbostic */ 62552889Sbostic if (asc->target >= 0) 62652889Sbostic return; 62752889Sbostic 62852889Sbostic regs = asc->regs; 62952889Sbostic 63052889Sbostic /* 63152889Sbostic * Check to see if a reselection is in progress and if so, 63252889Sbostic * try to cancel it or respond to the reselection if it won. 63352889Sbostic */ 63452889Sbostic if (asc->state == ASC_STATE_RESEL) { 63552889Sbostic regs->asc_cmd = ASC_CMD_DISABLE_SEL; 63656819Sralph readback(regs->asc_cmd); 63752889Sbostic while (!(regs->asc_status & ASC_CSR_INT)) 63852889Sbostic DELAY(1); 63952889Sbostic asc_intr(asc - asc_softc); 64052889Sbostic /* we will be busy if a reselecting device won */ 64152889Sbostic if (asc->state == ASC_STATE_BUSY) 64252889Sbostic return; 64352889Sbostic } 64452889Sbostic 64552889Sbostic asc->state = ASC_STATE_BUSY; 64652889Sbostic asc->target = target; 64752889Sbostic 64852889Sbostic /* cache some pointers */ 64952889Sbostic scsicmd = asc->cmd[target]; 65052889Sbostic state = &asc->st[target]; 65152889Sbostic 65252889Sbostic #ifdef DEBUG 65352889Sbostic if (asc_debug > 1) { 65452889Sbostic printf("asc_startcmd: %s target %d cmd %x len %d\n", 65552889Sbostic scsicmd->sd->sd_driver->d_name, target, 65652889Sbostic scsicmd->cmd[0], scsicmd->buflen); 65752889Sbostic } 65852889Sbostic asc_debug_cmd = scsicmd->cmd[0]; 65952889Sbostic if (scsicmd->cmd[0] == SCSI_READ_EXT) { 66052889Sbostic asc_debug_bn = (scsicmd->cmd[2] << 24) | 66152889Sbostic (scsicmd->cmd[3] << 16) | 66252889Sbostic (scsicmd->cmd[4] << 8) | 66352889Sbostic scsicmd->cmd[5]; 66452889Sbostic asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 66552889Sbostic } 66653080Sralph asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 66752889Sbostic asc_logp->target = asc->target; 66852889Sbostic asc_logp->state = 0; 66953080Sralph asc_logp->msg = 0xff; 67052889Sbostic if (++asc_logp >= &asc_log[NLOG]) 67152889Sbostic asc_logp = asc_log; 67252889Sbostic #endif 67352889Sbostic 67452889Sbostic /* 67552889Sbostic * Init the chip and target state. 67652889Sbostic */ 67752889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 67856819Sralph readback(regs->asc_cmd); 67956819Sralph DELAY(2); 68053080Sralph state->flags = state->flags & DID_SYNC; 68152889Sbostic state->error = 0; 68252889Sbostic state->script = (script_t *)0; 68352889Sbostic state->msg_out = SCSI_NO_OP; 68452889Sbostic 68552889Sbostic /* 68652889Sbostic * Copy command data to the DMA buffer. 68752889Sbostic */ 68852889Sbostic len = scsicmd->cmdlen; 68952889Sbostic state->dmalen = len; 69052889Sbostic bcopy(scsicmd->cmd, state->dmaBufAddr, len); 69152889Sbostic 69252889Sbostic /* check for simple SCSI command with no data transfer */ 69352889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 69452889Sbostic /* check for sync negotiation */ 69552889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 69652889Sbostic !(state->flags & DID_SYNC)) { 69752889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 69852889Sbostic state->flags |= TRY_SYNC; 69952889Sbostic } else 70052889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 70152889Sbostic state->buf = (char *)0; 70252889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 70352889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 70453080Sralph state->buf = scsicmd->buf; 70552889Sbostic state->flags |= DMA_OUT; 70652889Sbostic } else { 70752889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 70852889Sbostic state->buf = scsicmd->buf; 70952889Sbostic state->flags |= DMA_IN; 71052889Sbostic } 71152889Sbostic 71252889Sbostic /* preload the FIFO with the message to be sent */ 71352942Sralph regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 71456819Sralph MachEmptyWriteBuffer(); 71552889Sbostic 71652889Sbostic /* start the asc */ 71756819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 71852889Sbostic ASC_TC_PUT(regs, len); 71956819Sralph readback(regs->asc_cmd); 72052889Sbostic 72152889Sbostic regs->asc_dbus_id = target; 72256819Sralph readback(regs->asc_dbus_id); 72352889Sbostic regs->asc_syn_p = state->sync_period; 72456819Sralph readback(regs->asc_syn_p); 72552889Sbostic regs->asc_syn_o = state->sync_offset; 72656819Sralph readback(regs->asc_syn_o); 72752889Sbostic 72852889Sbostic if (state->flags & TRY_SYNC) 72953080Sralph regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 73052889Sbostic else 73152889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 73256819Sralph readback(regs->asc_cmd); 73352889Sbostic } 73452889Sbostic 73552889Sbostic /* 73652889Sbostic * Interrupt routine 73752889Sbostic * Take interrupts from the chip 73852889Sbostic * 73952889Sbostic * Implementation: 74052889Sbostic * Move along the current command's script if 74152889Sbostic * all is well, invoke error handler if not. 74252889Sbostic */ 74352889Sbostic void 74452889Sbostic asc_intr(unit) 74552889Sbostic int unit; 74652889Sbostic { 74752889Sbostic register asc_softc_t asc = &asc_softc[unit]; 74852889Sbostic register asc_regmap_t *regs = asc->regs; 74952889Sbostic register State *state; 75052889Sbostic register script_t *scpt; 75152889Sbostic register int ss, ir, status; 75252889Sbostic 75352889Sbostic /* collect ephemeral information */ 75452889Sbostic status = regs->asc_status; 75553080Sralph again: 75652889Sbostic ss = regs->asc_ss; 75752889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 75852889Sbostic scpt = asc->script; 75952889Sbostic 76052889Sbostic #ifdef DEBUG 76152889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 76252889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 76352889Sbostic asc_logp->state = scpt - asc_scripts; 76452889Sbostic asc_logp->msg = -1; 76552889Sbostic if (++asc_logp >= &asc_log[NLOG]) 76652889Sbostic asc_logp = asc_log; 76752889Sbostic if (asc_debug > 2) 76852889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 76952889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 77052889Sbostic #endif 77152889Sbostic 77252889Sbostic /* check the expected state */ 77352889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 77452889Sbostic /* 77552889Sbostic * Perform the appropriate operation, then proceed. 77652889Sbostic */ 77752889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 77852889Sbostic regs->asc_cmd = scpt->command; 77956819Sralph readback(regs->asc_cmd); 78052889Sbostic asc->script = scpt->next; 78152889Sbostic } 78252889Sbostic goto done; 78352889Sbostic } 78452889Sbostic 78552889Sbostic /* check for message in or out */ 78652889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 78752889Sbostic register int len, fifo; 78852889Sbostic 78952889Sbostic state = &asc->st[asc->target]; 79052889Sbostic switch (ASC_PHASE(status)) { 79153080Sralph case ASC_PHASE_DATAI: 79253080Sralph case ASC_PHASE_DATAO: 79353080Sralph ASC_TC_GET(regs, len); 79453080Sralph fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 79553080Sralph printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 79653080Sralph state->buflen, state->dmalen, len, fifo); 79753080Sralph goto abort; 79853080Sralph 79952889Sbostic case ASC_PHASE_MSG_IN: 80052889Sbostic break; 80152889Sbostic 80252889Sbostic case ASC_PHASE_MSG_OUT: 80352889Sbostic regs->asc_fifo = state->msg_out; 80452889Sbostic state->msg_out = SCSI_NO_OP; 80552889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 80656819Sralph readback(regs->asc_cmd); 80752889Sbostic goto done; 80852889Sbostic 80952889Sbostic case ASC_PHASE_STATUS: 81052889Sbostic /* probably an error in the SCSI command */ 81152889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 81252889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 81356819Sralph readback(regs->asc_cmd); 81452889Sbostic goto done; 81552889Sbostic 81652889Sbostic default: 81752889Sbostic goto abort; 81852889Sbostic } 81952889Sbostic 82052889Sbostic if (state->script) 82152889Sbostic goto abort; 82252889Sbostic 82352889Sbostic /* check for DMA in progress */ 82452889Sbostic ASC_TC_GET(regs, len); 82552889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 82652889Sbostic /* flush any data in the FIFO */ 82752889Sbostic if (fifo) { 82853080Sralph if (state->flags & DMA_OUT) 82953080Sralph len += fifo; 83053080Sralph else if (state->flags & DMA_IN) { 83153080Sralph u_char *cp; 83253080Sralph 83353080Sralph printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 83453080Sralph state->dmalen, len, fifo); /* XXX */ 83553080Sralph len += fifo; 83653080Sralph cp = state->dmaBufAddr + (state->dmalen - len); 83753080Sralph while (fifo-- > 0) 83853080Sralph *cp++ = regs->asc_fifo; 83953080Sralph } else 84053080Sralph printf("asc_intr: dmalen %d len %d fifo %d\n", 84153080Sralph state->dmalen, len, fifo); /* XXX */ 84252889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 84356819Sralph readback(regs->asc_cmd); 84452889Sbostic MachEmptyWriteBuffer(); 84556819Sralph DELAY(2); 84652889Sbostic } 84752889Sbostic if (len) { 84852889Sbostic /* save number of bytes still to be sent or received */ 84952889Sbostic state->dmaresid = len; 85052889Sbostic /* setup state to resume to */ 85152889Sbostic if (state->flags & DMA_IN) 85252889Sbostic state->script = 85352889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 85452889Sbostic else if (state->flags & DMA_OUT) 85552889Sbostic state->script = 85652889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 85752889Sbostic else 85852889Sbostic state->script = asc->script; 85952889Sbostic } else { 86052889Sbostic /* setup state to resume to */ 86152942Sralph if (state->flags & DMA_IN) { 86253080Sralph if (state->flags & DMA_IN_PROGRESS) { 86353080Sralph state->flags &= ~DMA_IN_PROGRESS; 86456819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 86552942Sralph len = state->dmalen; 86652942Sralph bcopy(state->dmaBufAddr, state->buf, 86752942Sralph len); 86852942Sralph state->buf += len; 86952942Sralph state->buflen -= len; 87053080Sralph } 87152942Sralph if (state->buflen) 87252942Sralph state->script = 87352942Sralph &asc_scripts[SCRIPT_RESUME_IN]; 87452942Sralph else 87552942Sralph state->script = 87652942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 87752942Sralph } else if (state->flags & DMA_OUT) { 87852942Sralph /* 87952942Sralph * If this is the last chunk, the next expected 88052942Sralph * state is to get status. 88152942Sralph */ 88253080Sralph if (state->flags & DMA_IN_PROGRESS) { 88353080Sralph state->flags &= ~DMA_IN_PROGRESS; 88456819Sralph (*asc->dma_end)(asc, state, ASCDMA_WRITE); 88553080Sralph len = state->dmalen; 88653080Sralph state->buf += len; 88753080Sralph state->buflen -= len; 88853080Sralph } 88952942Sralph if (state->buflen) 89052942Sralph state->script = 89152942Sralph &asc_scripts[SCRIPT_RESUME_OUT]; 89252942Sralph else 89352942Sralph state->script = 89452942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 89553080Sralph } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 89653080Sralph state->script = 89753080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 89853080Sralph else 89952889Sbostic state->script = asc->script; 90052889Sbostic } 90152889Sbostic 90252889Sbostic /* setup to receive a message */ 90352889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 90452889Sbostic state->msglen = 0; 90552889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 90656819Sralph readback(regs->asc_cmd); 90752889Sbostic goto done; 90852889Sbostic } 90952889Sbostic 91052889Sbostic /* check for SCSI bus reset */ 91152889Sbostic if (ir & ASC_INT_RESET) { 91252889Sbostic register int i; 91352889Sbostic 91452889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 91552889Sbostic /* need to flush any pending commands */ 91652889Sbostic for (i = 0; i < ASC_NCMD; i++) { 91752889Sbostic if (!asc->cmd[i]) 91852889Sbostic continue; 91952889Sbostic asc->st[i].error = EIO; 92052889Sbostic asc_end(asc, 0, 0, 0); 92152889Sbostic } 92252889Sbostic /* rearbitrate synchronous offset */ 92352889Sbostic for (i = 0; i < ASC_NCMD; i++) { 92452889Sbostic asc->st[i].sync_offset = 0; 92552889Sbostic asc->st[i].flags = 0; 92652889Sbostic } 92752889Sbostic asc->target = -1; 92852889Sbostic return; 92952889Sbostic } 93052889Sbostic 93152889Sbostic /* check for command errors */ 93252889Sbostic if (ir & ASC_INT_ILL) 93352889Sbostic goto abort; 93452889Sbostic 93552889Sbostic /* check for disconnect */ 93652889Sbostic if (ir & ASC_INT_DISC) { 93752889Sbostic state = &asc->st[asc->target]; 93852889Sbostic switch (ASC_SS(ss)) { 93952889Sbostic case 0: /* device did not respond */ 94052889Sbostic state->error = ENXIO; 94152889Sbostic asc_end(asc, status, ss, ir); 94252889Sbostic return; 94352889Sbostic 94452889Sbostic default: 945*57233Sralph /* 946*57233Sralph * On rare occasions my RZ24 does a disconnect during 947*57233Sralph * data in phase and the following seems to keep it 948*57233Sralph * happy. 949*57233Sralph * XXX Should a scsi disk ever do this?? 950*57233Sralph */ 951*57233Sralph asc->script = &asc_scripts[SCRIPT_RESEL]; 952*57233Sralph asc->state = ASC_STATE_RESEL; 953*57233Sralph state->flags |= DISCONN; 954*57233Sralph regs->asc_cmd = ASC_CMD_ENABLE_SEL; 955*57233Sralph readback(regs->asc_cmd); 956*57233Sralph return; 95752889Sbostic } 95852889Sbostic } 95952889Sbostic 96052889Sbostic /* check for reselect */ 96152889Sbostic if (ir & ASC_INT_RESEL) { 96252889Sbostic unsigned fifo, id, msg; 96352889Sbostic 96452889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 96552889Sbostic if (fifo < 2) 96652889Sbostic goto abort; 96752889Sbostic /* read unencoded SCSI ID and convert to binary */ 96852889Sbostic msg = regs->asc_fifo & asc->myidmask; 96952889Sbostic for (id = 0; (msg & 1) == 0; id++) 97052889Sbostic msg >>= 1; 97152889Sbostic /* read identify message */ 97252889Sbostic msg = regs->asc_fifo; 97352889Sbostic #ifdef DEBUG 97452889Sbostic if (asc_logp == asc_log) 97552889Sbostic asc_log[NLOG - 1].msg = msg; 97652889Sbostic else 97752889Sbostic asc_logp[-1].msg = msg; 97852889Sbostic #endif 97952889Sbostic if (asc->state != ASC_STATE_RESEL) 98052889Sbostic goto abort; 98152889Sbostic asc->state = ASC_STATE_BUSY; 98252889Sbostic asc->target = id; 98352889Sbostic state = &asc->st[id]; 98452889Sbostic asc->script = state->script; 98552889Sbostic state->script = (script_t *)0; 98652889Sbostic if (!(state->flags & DISCONN)) 98752889Sbostic goto abort; 98852889Sbostic state->flags &= ~DISCONN; 98953080Sralph regs->asc_syn_p = state->sync_period; 99053080Sralph regs->asc_syn_o = state->sync_offset; 99152889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 99256819Sralph readback(regs->asc_cmd); 99352889Sbostic goto done; 99452889Sbostic } 99552889Sbostic 99652889Sbostic /* check if we are being selected as a target */ 99752889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 99852889Sbostic goto abort; 99952889Sbostic 100052889Sbostic /* must be just a ASC_INT_FC */ 100152889Sbostic done: 100252889Sbostic MachEmptyWriteBuffer(); 100353080Sralph /* watch out for HW race conditions and setup & hold time violations */ 100453080Sralph ir = regs->asc_status; 100553080Sralph while (ir != (status = regs->asc_status)) 100653080Sralph ir = status; 100753080Sralph if (status & ASC_CSR_INT) 100852889Sbostic goto again; 100952889Sbostic return; 101052889Sbostic 101152889Sbostic abort: 101252889Sbostic #ifdef DEBUG 101352889Sbostic asc_DumpLog("asc_intr"); 101452889Sbostic #endif 101552889Sbostic #if 0 101652889Sbostic panic("asc_intr"); 101752889Sbostic #else 101852889Sbostic for (;;); 101952889Sbostic #endif 102052889Sbostic } 102152889Sbostic 102252889Sbostic /* 102352889Sbostic * All the many little things that the interrupt 102452889Sbostic * routine might switch to. 102552889Sbostic */ 102652889Sbostic 102752889Sbostic /* ARGSUSED */ 102852889Sbostic static int 102952889Sbostic script_nop(asc, status, ss, ir) 103052889Sbostic register asc_softc_t asc; 103152889Sbostic register int status, ss, ir; 103252889Sbostic { 103352889Sbostic return (1); 103452889Sbostic } 103552889Sbostic 103652889Sbostic /* ARGSUSED */ 103752889Sbostic static int 103852889Sbostic asc_get_status(asc, status, ss, ir) 103952889Sbostic register asc_softc_t asc; 104052889Sbostic register int status, ss, ir; 104152889Sbostic { 104252889Sbostic register asc_regmap_t *regs = asc->regs; 104352889Sbostic register int data; 104452889Sbostic 104552889Sbostic /* 104652889Sbostic * Get the last two bytes in the FIFO. 104752889Sbostic */ 104852889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 104952889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 105052889Sbostic if (data < 2) { 105152889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 105256819Sralph readback(asc->regs->asc_cmd); 105352889Sbostic return (0); 105452889Sbostic } 105552889Sbostic do { 105652889Sbostic data = regs->asc_fifo; 105752889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 105852889Sbostic } 105952889Sbostic 106052889Sbostic /* save the status byte */ 106152889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 106252889Sbostic #ifdef DEBUG 106352889Sbostic if (asc_logp == asc_log) 106452889Sbostic asc_log[NLOG - 1].msg = data; 106552889Sbostic else 106652889Sbostic asc_logp[-1].msg = data; 106752889Sbostic #endif 106852889Sbostic 106952889Sbostic /* get the (presumed) command_complete message */ 107052889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 107152889Sbostic return (1); 107252889Sbostic 107352889Sbostic #ifdef DEBUG 107452889Sbostic printf("asc_get_status: status %x cmd %x\n", 107552889Sbostic asc->st[asc->target].statusByte, data); 107652889Sbostic asc_DumpLog("asc_get_status"); 107752889Sbostic #endif 107852889Sbostic return (0); 107952889Sbostic } 108052889Sbostic 108152889Sbostic /* ARGSUSED */ 108252889Sbostic static int 108352889Sbostic asc_end(asc, status, ss, ir) 108452889Sbostic register asc_softc_t asc; 108552889Sbostic register int status, ss, ir; 108652889Sbostic { 108752889Sbostic register ScsiCmd *scsicmd; 108852889Sbostic register State *state; 108952889Sbostic register int i, target; 109052889Sbostic 109152889Sbostic asc->state = ASC_STATE_IDLE; 109252889Sbostic target = asc->target; 109352889Sbostic asc->target = -1; 109452889Sbostic scsicmd = asc->cmd[target]; 109552889Sbostic asc->cmd[target] = (ScsiCmd *)0; 109652889Sbostic state = &asc->st[target]; 109752889Sbostic 109852889Sbostic #ifdef DEBUG 109952889Sbostic if (asc_debug > 1) { 110052889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 110152889Sbostic scsicmd->sd->sd_driver->d_name, target, 110252889Sbostic scsicmd->cmd[0], state->error, state->buflen); 110352889Sbostic } 110452889Sbostic #endif 110552889Sbostic #ifdef DIAGNOSTIC 110652889Sbostic if (target < 0 || !scsicmd) 110752889Sbostic panic("asc_end"); 110852889Sbostic #endif 110952889Sbostic 111052889Sbostic /* look for disconnected devices */ 111152889Sbostic for (i = 0; i < ASC_NCMD; i++) { 111252889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 111352889Sbostic continue; 111452889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 111556819Sralph readback(asc->regs->asc_cmd); 111652889Sbostic asc->state = ASC_STATE_RESEL; 111752889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 111852889Sbostic break; 111952889Sbostic } 112052889Sbostic 112152889Sbostic /* look for another device that is ready */ 112252889Sbostic for (i = 0; i < ASC_NCMD; i++) { 112352889Sbostic /* don't restart a disconnected command */ 112452889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 112552889Sbostic continue; 112652889Sbostic asc_startcmd(asc, i); 112752889Sbostic break; 112852889Sbostic } 112952889Sbostic 113052889Sbostic /* signal device driver that the command is done */ 113152889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 113252889Sbostic state->buflen, state->statusByte); 113352889Sbostic 113452889Sbostic return (0); 113552889Sbostic } 113652889Sbostic 113752889Sbostic /* ARGSUSED */ 113852889Sbostic static int 113952889Sbostic asc_dma_in(asc, status, ss, ir) 114052889Sbostic register asc_softc_t asc; 114152889Sbostic register int status, ss, ir; 114252889Sbostic { 114352889Sbostic register asc_regmap_t *regs = asc->regs; 114452889Sbostic register State *state = &asc->st[asc->target]; 114553080Sralph register int len; 114652889Sbostic 114752889Sbostic /* check for previous chunk in buffer */ 114853080Sralph if (state->flags & DMA_IN_PROGRESS) { 114952889Sbostic /* 115052889Sbostic * Only count bytes that have been copied to memory. 115152889Sbostic * There may be some bytes in the FIFO if synchonous transfers 115252889Sbostic * are in progress. 115352889Sbostic */ 115456819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 115552889Sbostic ASC_TC_GET(regs, len); 115652889Sbostic len = state->dmalen - len; 115752889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 115852889Sbostic state->buf += len; 115952889Sbostic state->buflen -= len; 116053080Sralph } 116152889Sbostic 116252942Sralph /* setup to start reading the next chunk */ 116352889Sbostic len = state->buflen; 116452889Sbostic if (len > state->dmaBufSize) 116552889Sbostic len = state->dmaBufSize; 116652889Sbostic state->dmalen = len; 116756819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 116852889Sbostic ASC_TC_PUT(regs, len); 116952942Sralph #ifdef DEBUG 117052942Sralph if (asc_debug > 2) 117152942Sralph printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 117252942Sralph #endif 117352942Sralph 117452942Sralph /* check for next chunk */ 117553080Sralph state->flags |= DMA_IN_PROGRESS; 117652889Sbostic if (len != state->buflen) { 117752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 117856819Sralph readback(regs->asc_cmd); 117952942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 118052889Sbostic return (0); 118152889Sbostic } 118252889Sbostic return (1); 118352889Sbostic } 118452889Sbostic 118552889Sbostic /* ARGSUSED */ 118652889Sbostic static int 118752889Sbostic asc_last_dma_in(asc, status, ss, ir) 118852889Sbostic register asc_softc_t asc; 118952889Sbostic register int status, ss, ir; 119052889Sbostic { 119152889Sbostic register asc_regmap_t *regs = asc->regs; 119252889Sbostic register State *state = &asc->st[asc->target]; 119352889Sbostic register int len, fifo; 119452889Sbostic 119552889Sbostic /* copy data from buffer to main memory */ 119656819Sralph (*asc->dma_end)(asc, state, ASCDMA_READ); 119752889Sbostic ASC_TC_GET(regs, len); 119852889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 119952889Sbostic #ifdef DEBUG 120052942Sralph if (asc_debug > 2) 120152889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 120252889Sbostic state->buflen, state->dmalen, len, fifo); 120352889Sbostic #endif 120452889Sbostic if (fifo) { 120552942Sralph /* device must be trying to send more than we expect */ 120652889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 120756819Sralph readback(regs->asc_cmd); 120852889Sbostic MachEmptyWriteBuffer(); 120952889Sbostic } 121053080Sralph state->flags &= ~DMA_IN_PROGRESS; 121152889Sbostic len = state->dmalen - len; 121252889Sbostic state->buflen -= len; 121352889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 121452889Sbostic 121552889Sbostic return (1); 121652889Sbostic } 121752889Sbostic 121852889Sbostic /* ARGSUSED */ 121952889Sbostic static int 122052942Sralph asc_resume_in(asc, status, ss, ir) 122152942Sralph register asc_softc_t asc; 122252942Sralph register int status, ss, ir; 122352942Sralph { 122452942Sralph register asc_regmap_t *regs = asc->regs; 122552942Sralph register State *state = &asc->st[asc->target]; 122652942Sralph register int len; 122752942Sralph 122852942Sralph /* setup to start reading the next chunk */ 122952942Sralph len = state->buflen; 123052942Sralph if (len > state->dmaBufSize) 123152942Sralph len = state->dmaBufSize; 123252942Sralph state->dmalen = len; 123356819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 123452942Sralph ASC_TC_PUT(regs, len); 123552942Sralph #ifdef DEBUG 123652942Sralph if (asc_debug > 2) 123752942Sralph printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 123852942Sralph len); 123952942Sralph #endif 124052942Sralph 124152942Sralph /* check for next chunk */ 124253080Sralph state->flags |= DMA_IN_PROGRESS; 124352942Sralph if (len != state->buflen) { 124452942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 124556819Sralph readback(regs->asc_cmd); 124652942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 124752942Sralph return (0); 124852942Sralph } 124952942Sralph return (1); 125052942Sralph } 125152942Sralph 125252942Sralph /* ARGSUSED */ 125352942Sralph static int 125452889Sbostic asc_resume_dma_in(asc, status, ss, ir) 125552889Sbostic register asc_softc_t asc; 125652889Sbostic register int status, ss, ir; 125752889Sbostic { 125852889Sbostic register asc_regmap_t *regs = asc->regs; 125952889Sbostic register State *state = &asc->st[asc->target]; 126052889Sbostic register int len, off; 126152889Sbostic 126252889Sbostic /* setup to finish reading the current chunk */ 126352889Sbostic len = state->dmaresid; 126452889Sbostic off = state->dmalen - len; 126552889Sbostic if ((off & 1) && state->sync_offset) { 126652889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 126752889Sbostic state->dmalen, len, off); /* XXX */ 126852889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 126952889Sbostic } 127056819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 127152889Sbostic ASC_TC_PUT(regs, len); 127252942Sralph #ifdef DEBUG 127352942Sralph if (asc_debug > 2) 127452942Sralph printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 127552942Sralph state->dmalen, state->buflen, len, off); 127652942Sralph #endif 127752942Sralph 127852942Sralph /* check for next chunk */ 127953080Sralph state->flags |= DMA_IN_PROGRESS; 128052889Sbostic if (state->dmalen != state->buflen) { 128152889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 128256819Sralph readback(regs->asc_cmd); 128352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 128452889Sbostic return (0); 128552889Sbostic } 128652889Sbostic return (1); 128752889Sbostic } 128852889Sbostic 128952889Sbostic /* ARGSUSED */ 129052889Sbostic static int 129152889Sbostic asc_dma_out(asc, status, ss, ir) 129252889Sbostic register asc_softc_t asc; 129352889Sbostic register int status, ss, ir; 129452889Sbostic { 129552889Sbostic register asc_regmap_t *regs = asc->regs; 129652889Sbostic register State *state = &asc->st[asc->target]; 129752889Sbostic register int len, fifo; 129852889Sbostic 129953080Sralph if (state->flags & DMA_IN_PROGRESS) { 130052889Sbostic /* check to be sure previous chunk was finished */ 130152889Sbostic ASC_TC_GET(regs, len); 130252889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 130352889Sbostic if (len || fifo) 130452889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 130552889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 130652889Sbostic len += fifo; 130752889Sbostic len = state->dmalen - len; 130853080Sralph state->buf += len; 130952889Sbostic state->buflen -= len; 131053080Sralph } 131152889Sbostic 131253080Sralph /* setup for this chunck */ 131353080Sralph len = state->buflen; 131453080Sralph if (len > state->dmaBufSize) 131553080Sralph len = state->dmaBufSize; 131653080Sralph state->dmalen = len; 131753080Sralph bcopy(state->buf, state->dmaBufAddr, len); 131856819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 131952942Sralph ASC_TC_PUT(regs, len); 132052889Sbostic #ifdef DEBUG 132152889Sbostic if (asc_debug > 2) 132252942Sralph printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 132352889Sbostic #endif 132452889Sbostic 132552889Sbostic /* check for next chunk */ 132653080Sralph state->flags |= DMA_IN_PROGRESS; 132752889Sbostic if (len != state->buflen) { 132852889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 132956819Sralph readback(regs->asc_cmd); 133052942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 133152889Sbostic return (0); 133252889Sbostic } 133352889Sbostic return (1); 133452889Sbostic } 133552889Sbostic 133652889Sbostic /* ARGSUSED */ 133752889Sbostic static int 133852889Sbostic asc_last_dma_out(asc, status, ss, ir) 133952889Sbostic register asc_softc_t asc; 134052889Sbostic register int status, ss, ir; 134152889Sbostic { 134252889Sbostic register asc_regmap_t *regs = asc->regs; 134352889Sbostic register State *state = &asc->st[asc->target]; 134452889Sbostic register int len, fifo; 134552889Sbostic 134652889Sbostic ASC_TC_GET(regs, len); 134752889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 134852889Sbostic #ifdef DEBUG 134952889Sbostic if (asc_debug > 2) 135052889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 135153080Sralph state->buflen, state->dmalen, len, fifo); 135252942Sralph #endif 135352942Sralph if (fifo) { 135452942Sralph len += fifo; 135552942Sralph regs->asc_cmd = ASC_CMD_FLUSH; 135656819Sralph readback(regs->asc_cmd); 135752942Sralph MachEmptyWriteBuffer(); 135852942Sralph } 135953080Sralph state->flags &= ~DMA_IN_PROGRESS; 136052889Sbostic len = state->dmalen - len; 136152889Sbostic state->buflen -= len; 136252889Sbostic return (1); 136352889Sbostic } 136452889Sbostic 136552889Sbostic /* ARGSUSED */ 136652889Sbostic static int 136752942Sralph asc_resume_out(asc, status, ss, ir) 136852942Sralph register asc_softc_t asc; 136952942Sralph register int status, ss, ir; 137052942Sralph { 137152942Sralph register asc_regmap_t *regs = asc->regs; 137252942Sralph register State *state = &asc->st[asc->target]; 137352942Sralph register int len; 137452942Sralph 137552942Sralph /* setup for this chunck */ 137652942Sralph len = state->buflen; 137752942Sralph if (len > state->dmaBufSize) 137852942Sralph len = state->dmaBufSize; 137952942Sralph state->dmalen = len; 138052942Sralph bcopy(state->buf, state->dmaBufAddr, len); 138156819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 138252942Sralph ASC_TC_PUT(regs, len); 138352942Sralph #ifdef DEBUG 138452942Sralph if (asc_debug > 2) 138552942Sralph printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 138652942Sralph len); 138752942Sralph #endif 138852942Sralph 138952942Sralph /* check for next chunk */ 139053080Sralph state->flags |= DMA_IN_PROGRESS; 139152942Sralph if (len != state->buflen) { 139252942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 139356819Sralph readback(regs->asc_cmd); 139452942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 139552942Sralph return (0); 139652942Sralph } 139752942Sralph return (1); 139852942Sralph } 139952942Sralph 140052942Sralph /* ARGSUSED */ 140152942Sralph static int 140252889Sbostic asc_resume_dma_out(asc, status, ss, ir) 140352889Sbostic register asc_softc_t asc; 140452889Sbostic register int status, ss, ir; 140552889Sbostic { 140652889Sbostic register asc_regmap_t *regs = asc->regs; 140752889Sbostic register State *state = &asc->st[asc->target]; 140852889Sbostic register int len, off; 140952889Sbostic 141052889Sbostic /* setup to finish writing this chunk */ 141152889Sbostic len = state->dmaresid; 141252889Sbostic off = state->dmalen - len; 141352889Sbostic if (off & 1) { 141452889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 141552889Sbostic state->dmalen, len, off); /* XXX */ 141652889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 141752889Sbostic off++; 141852889Sbostic len--; 141952889Sbostic } 142056819Sralph (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 142152889Sbostic ASC_TC_PUT(regs, len); 142252942Sralph #ifdef DEBUG 142352942Sralph if (asc_debug > 2) 142452942Sralph printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 142552942Sralph state->dmalen, state->buflen, len, off); 142652942Sralph #endif 142752942Sralph 142852942Sralph /* check for next chunk */ 142953080Sralph state->flags |= DMA_IN_PROGRESS; 143052889Sbostic if (state->dmalen != state->buflen) { 143152889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 143256819Sralph readback(regs->asc_cmd); 143352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 143452889Sbostic return (0); 143552889Sbostic } 143652889Sbostic return (1); 143752889Sbostic } 143852889Sbostic 143952889Sbostic /* ARGSUSED */ 144052889Sbostic static int 144152889Sbostic asc_sendsync(asc, status, ss, ir) 144252889Sbostic register asc_softc_t asc; 144352889Sbostic register int status, ss, ir; 144452889Sbostic { 144552889Sbostic register asc_regmap_t *regs = asc->regs; 144653080Sralph register State *state = &asc->st[asc->target]; 144752889Sbostic 144853080Sralph /* send the extended synchronous negotiation message */ 144952889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 145052889Sbostic MachEmptyWriteBuffer(); 145152889Sbostic regs->asc_fifo = 3; 145252889Sbostic MachEmptyWriteBuffer(); 145352889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 145452889Sbostic MachEmptyWriteBuffer(); 145552889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 145652889Sbostic MachEmptyWriteBuffer(); 145752889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 145853080Sralph /* state to resume after we see the sync reply message */ 145953080Sralph state->script = asc->script + 2; 146053080Sralph state->msglen = 0; 146152889Sbostic return (1); 146252889Sbostic } 146352889Sbostic 146452889Sbostic /* ARGSUSED */ 146552889Sbostic static int 146652889Sbostic asc_replysync(asc, status, ss, ir) 146752889Sbostic register asc_softc_t asc; 146852889Sbostic register int status, ss, ir; 146952889Sbostic { 147052889Sbostic register asc_regmap_t *regs = asc->regs; 147152889Sbostic register State *state = &asc->st[asc->target]; 147252889Sbostic 147352889Sbostic #ifdef DEBUG 147452889Sbostic if (asc_debug > 2) 147552889Sbostic printf("asc_replysync: %x %x\n", 147656819Sralph asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 147752889Sbostic state->sync_offset); 147852889Sbostic #endif 147952889Sbostic /* send synchronous transfer in response to a request */ 148052889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 148152889Sbostic MachEmptyWriteBuffer(); 148252889Sbostic regs->asc_fifo = 3; 148352889Sbostic MachEmptyWriteBuffer(); 148452889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 148552889Sbostic MachEmptyWriteBuffer(); 148656819Sralph regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 148752889Sbostic MachEmptyWriteBuffer(); 148852889Sbostic regs->asc_fifo = state->sync_offset; 148952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 149056819Sralph readback(regs->asc_cmd); 149152889Sbostic 149252889Sbostic /* return to the appropriate script */ 149352889Sbostic if (!state->script) { 149452889Sbostic #ifdef DEBUG 149552889Sbostic asc_DumpLog("asc_replsync"); 149652889Sbostic #endif 149752889Sbostic panic("asc_replysync"); 149852889Sbostic } 149952889Sbostic asc->script = state->script; 150052889Sbostic state->script = (script_t *)0; 150152889Sbostic return (0); 150252889Sbostic } 150352889Sbostic 150452889Sbostic /* ARGSUSED */ 150552889Sbostic static int 150652942Sralph asc_msg_in(asc, status, ss, ir) 150752889Sbostic register asc_softc_t asc; 150852889Sbostic register int status, ss, ir; 150952889Sbostic { 151052889Sbostic register asc_regmap_t *regs = asc->regs; 151152889Sbostic register State *state = &asc->st[asc->target]; 151252889Sbostic register int msg; 151352889Sbostic int i; 151452889Sbostic 151552889Sbostic /* read one message byte */ 151652889Sbostic msg = regs->asc_fifo; 151752889Sbostic #ifdef DEBUG 151852889Sbostic if (asc_logp == asc_log) 151952889Sbostic asc_log[NLOG - 1].msg = msg; 152052889Sbostic else 152152889Sbostic asc_logp[-1].msg = msg; 152252889Sbostic #endif 152352889Sbostic 152452889Sbostic /* check for multi-byte message */ 152552889Sbostic if (state->msglen != 0) { 152652889Sbostic /* first byte is the message length */ 152752889Sbostic if (state->msglen < 0) { 152852889Sbostic state->msglen = msg; 152952889Sbostic return (1); 153052889Sbostic } 153152889Sbostic if (state->msgcnt >= state->msglen) 153252889Sbostic goto abort; 153352889Sbostic state->msg_in[state->msgcnt++] = msg; 153452889Sbostic 153552889Sbostic /* did we just read the last byte of the message? */ 153652889Sbostic if (state->msgcnt != state->msglen) 153752889Sbostic return (1); 153852889Sbostic 153952889Sbostic /* process an extended message */ 154052889Sbostic #ifdef DEBUG 154152889Sbostic if (asc_debug > 2) 154252942Sralph printf("asc_msg_in: msg %x %x %x\n", 154352889Sbostic state->msg_in[0], 154452889Sbostic state->msg_in[1], 154552889Sbostic state->msg_in[2]); 154652889Sbostic #endif 154752889Sbostic switch (state->msg_in[0]) { 154852889Sbostic case SCSI_SYNCHRONOUS_XFER: 154952889Sbostic state->flags |= DID_SYNC; 155052889Sbostic state->sync_offset = state->msg_in[2]; 155152889Sbostic 155252889Sbostic /* convert SCSI period to ASC period */ 155356819Sralph i = state->msg_in[1] / asc->tb_ticks; 155456819Sralph if (i < asc->min_period) 155556819Sralph i = asc->min_period; 155656819Sralph else if (i >= asc->max_period) { 155752889Sbostic /* can't do sync transfer, period too long */ 155852889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 155952889Sbostic asc - asc_softc, asc->target, i); 156056819Sralph i = asc->max_period; 156152889Sbostic state->sync_offset = 0; 156252889Sbostic } 156356819Sralph if ((i * asc->tb_ticks) != state->msg_in[1]) 156452889Sbostic i++; 156552889Sbostic state->sync_period = i & 0x1F; 156652889Sbostic 156752889Sbostic /* 156852889Sbostic * If this is a request, check minimums and 156952889Sbostic * send back an acknowledge. 157052889Sbostic */ 157152889Sbostic if (!(state->flags & TRY_SYNC)) { 157252889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 157356819Sralph readback(regs->asc_cmd); 157452889Sbostic MachEmptyWriteBuffer(); 157552889Sbostic 157656819Sralph if (state->sync_period < asc->min_period) 157752889Sbostic state->sync_period = 157856819Sralph asc->min_period; 157952889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 158052889Sbostic state->sync_offset = 158152889Sbostic ASC_MAX_OFFSET; 158252889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 158352889Sbostic regs->asc_syn_p = state->sync_period; 158456819Sralph readback(regs->asc_syn_p); 158552889Sbostic regs->asc_syn_o = state->sync_offset; 158656819Sralph readback(regs->asc_syn_o); 158752889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 158856819Sralph readback(regs->asc_cmd); 158952889Sbostic return (0); 159052889Sbostic } 159152889Sbostic 159252889Sbostic regs->asc_syn_p = state->sync_period; 159356819Sralph readback(regs->asc_syn_p); 159452889Sbostic regs->asc_syn_o = state->sync_offset; 159556819Sralph readback(regs->asc_syn_o); 159652889Sbostic goto done; 159752889Sbostic 159852889Sbostic default: 159952889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 160052889Sbostic asc - asc_softc, asc->target, 160152889Sbostic state->msg_in[0]); 160252889Sbostic goto reject; 160352889Sbostic } 160452889Sbostic } 160552889Sbostic 160652889Sbostic /* process first byte of a message */ 160752889Sbostic #ifdef DEBUG 160852889Sbostic if (asc_debug > 2) 160952942Sralph printf("asc_msg_in: msg %x\n", msg); 161052889Sbostic #endif 161152889Sbostic switch (msg) { 161252889Sbostic #if 0 161352889Sbostic case SCSI_MESSAGE_REJECT: 161452889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 161552889Sbostic state->flags |= DID_SYNC; 161652889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 161756819Sralph readback(regs->asc_cmd); 161852889Sbostic status = asc_wait(regs, ASC_CSR_INT); 161952889Sbostic ir = regs->asc_intr; 162052889Sbostic /* some just break out here, some dont */ 162152889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 162252889Sbostic regs->asc_fifo = SCSI_ABORT; 162352889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 162456819Sralph readback(regs->asc_cmd); 162552889Sbostic status = asc_wait(regs, ASC_CSR_INT); 162652889Sbostic ir = regs->asc_intr; 162752889Sbostic } 162852889Sbostic if (ir & ASC_INT_DISC) { 162952889Sbostic asc_end(asc, status, 0, ir); 163052889Sbostic return (0); 163152889Sbostic } 163252889Sbostic goto status; 163352889Sbostic #endif 163452889Sbostic 163552889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 163652889Sbostic /* setup to read message length next */ 163752889Sbostic state->msglen = -1; 163852889Sbostic state->msgcnt = 0; 163952889Sbostic return (1); 164052889Sbostic 164152889Sbostic case SCSI_NO_OP: 164252889Sbostic break; 164352889Sbostic 164452889Sbostic case SCSI_SAVE_DATA_POINTER: 164552889Sbostic /* expect another message */ 164652889Sbostic return (1); 164752889Sbostic 164852889Sbostic case SCSI_RESTORE_POINTERS: 164952889Sbostic /* 165052889Sbostic * Need to do the following if resuming synchonous data in 165152889Sbostic * on an odd byte boundary. 165252889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 165352889Sbostic */ 165452889Sbostic break; 165552889Sbostic 165652889Sbostic case SCSI_DISCONNECT: 165752889Sbostic if (state->flags & DISCONN) 165852889Sbostic goto abort; 165952889Sbostic state->flags |= DISCONN; 166052942Sralph regs->asc_cmd = ASC_CMD_MSG_ACPT; 166156819Sralph readback(regs->asc_cmd); 166252942Sralph asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 166352942Sralph return (0); 166452889Sbostic 166552889Sbostic default: 166652889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 166752889Sbostic asc - asc_softc, asc->target, msg); 166852889Sbostic reject: 166952889Sbostic /* request a message out before acknowledging this message */ 167052889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 167152889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 167256819Sralph readback(regs->asc_cmd); 167352889Sbostic MachEmptyWriteBuffer(); 167452889Sbostic } 167552889Sbostic 167652889Sbostic done: 167752889Sbostic /* return to original script */ 167852889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 167956819Sralph readback(regs->asc_cmd); 168052889Sbostic if (!state->script) { 168152889Sbostic abort: 168252889Sbostic #ifdef DEBUG 168352942Sralph asc_DumpLog("asc_msg_in"); 168452889Sbostic #endif 168552942Sralph panic("asc_msg_in"); 168652889Sbostic } 168752889Sbostic asc->script = state->script; 168852889Sbostic state->script = (script_t *)0; 168952889Sbostic return (0); 169052889Sbostic } 169152889Sbostic 169252942Sralph /* ARGSUSED */ 169352942Sralph static int 169452942Sralph asc_disconnect(asc, status, ss, ir) 169552942Sralph register asc_softc_t asc; 169652942Sralph register int status, ss, ir; 169752942Sralph { 169852942Sralph register State *state = &asc->st[asc->target]; 169952942Sralph 170052942Sralph asc->target = -1; 170152942Sralph asc->state = ASC_STATE_RESEL; 170252942Sralph return (1); 170352942Sralph } 170452942Sralph 170556819Sralph /* 170656819Sralph * DMA handling routines. For a turbochannel device, just set the dmar 170756819Sralph * for the I/O ASIC, handle the actual DMA interface. 170856819Sralph */ 170956819Sralph static void 171056819Sralph tb_dma_start(asc, state, cp, flag) 171156819Sralph asc_softc_t asc; 171256819Sralph State *state; 171356819Sralph caddr_t cp; 171456819Sralph int flag; 171556819Sralph { 171656819Sralph 171756819Sralph if (flag == ASCDMA_WRITE) 171856819Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 171956819Sralph else 172056819Sralph *asc->dmar = ASC_DMA_ADDR(cp); 172156819Sralph } 172256819Sralph 172356819Sralph static void 172456819Sralph tb_dma_end(asc, state, flag) 172556819Sralph asc_softc_t asc; 172656819Sralph State *state; 172756819Sralph int flag; 172856819Sralph { 172956819Sralph 173056819Sralph } 173156819Sralph 173256819Sralph static void 173356819Sralph asic_dma_start(asc, state, cp, flag) 173456819Sralph asc_softc_t asc; 173556819Sralph State *state; 173656819Sralph caddr_t cp; 173756819Sralph int flag; 173856819Sralph { 173956819Sralph register volatile u_int *ssr = (volatile u_int *) 1740*57233Sralph ASIC_REG_CSR(asic_base); 174156819Sralph u_int phys, nphys; 174256819Sralph 174356819Sralph /* stop DMA engine first */ 174456819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1745*57233Sralph * ((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 174656819Sralph 174756819Sralph phys = MACH_CACHED_TO_PHYS(cp); 174856819Sralph cp = (caddr_t)pmax_trunc_page(cp + NBPG); 174956819Sralph nphys = MACH_CACHED_TO_PHYS(cp); 175056819Sralph 175156819Sralph asc->dma_next = cp; 175256819Sralph asc->dma_xfer = state->dmalen - (nphys - phys); 175356819Sralph 1754*57233Sralph *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 175556819Sralph ASIC_DMA_ADDR(phys); 1756*57233Sralph *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 175756819Sralph ASIC_DMA_ADDR(nphys); 175856819Sralph if (flag == ASCDMA_READ) 175956819Sralph *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 176056819Sralph else 176156819Sralph *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 176256819Sralph MachEmptyWriteBuffer(); 176356819Sralph } 176456819Sralph 176556819Sralph static void 176656819Sralph asic_dma_end(asc, state, flag) 176756819Sralph asc_softc_t asc; 176856819Sralph State *state; 176956819Sralph int flag; 177056819Sralph { 177156819Sralph register volatile u_int *ssr = (volatile u_int *) 1772*57233Sralph ASIC_REG_CSR(asic_base); 177356819Sralph int nb; 177456819Sralph 177556819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1776*57233Sralph *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 1777*57233Sralph *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 177856819Sralph MachEmptyWriteBuffer(); 177956819Sralph 178056819Sralph if (flag == ASCDMA_READ) { 178156819Sralph MachFlushDCache(MACH_PHYS_TO_CACHED( 178256819Sralph MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1783*57233Sralph if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 178456819Sralph /* pick up last upto6 bytes, sigh. */ 178556819Sralph register u_short *to; 178656819Sralph register int w; 178756819Sralph 178856819Sralph /* Last byte really xferred is.. */ 178956819Sralph to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1)); 1790*57233Sralph w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 179156819Sralph *to++ = w; 179256819Sralph if (--nb > 0) { 179356819Sralph w >>= 16; 179456819Sralph *to++ = w; 179556819Sralph } 179656819Sralph if (--nb > 0) { 1797*57233Sralph w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 179856819Sralph *to++ = w; 179956819Sralph } 180056819Sralph } 180156819Sralph } 180256819Sralph } 180356819Sralph 1804*57233Sralph #ifdef notdef 180556819Sralph /* 180656819Sralph * Called by asic_intr() for scsi dma pointer update interrupts. 180756819Sralph */ 180856819Sralph void 180956819Sralph asc_dma_intr() 181056819Sralph { 181156819Sralph asc_softc_t asc = &asc_softc[0]; 181256819Sralph u_int next_phys; 181356819Sralph 181456819Sralph asc->dma_xfer -= NBPG; 181556819Sralph if (asc->dma_xfer <= -NBPG) { 181656819Sralph volatile u_int *ssr = (volatile u_int *) 1817*57233Sralph ASIC_REG_CSR(asic_base); 181856819Sralph *ssr &= ~ASIC_CSR_DMAEN_SCSI; 181956819Sralph } else { 182056819Sralph asc->dma_next += NBPG; 182156819Sralph next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 182256819Sralph } 1823*57233Sralph *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 182456819Sralph ASIC_DMA_ADDR(next_phys); 182556819Sralph MachEmptyWriteBuffer(); 182656819Sralph } 1827*57233Sralph #endif 182856819Sralph 182952889Sbostic #ifdef DEBUG 183052889Sbostic asc_DumpLog(str) 183152889Sbostic char *str; 183252889Sbostic { 183352889Sbostic register struct asc_log *lp; 183452889Sbostic register u_int status; 183552889Sbostic 183652889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 183752889Sbostic asc_debug_bn, asc_debug_sz); 183852889Sbostic lp = asc_logp + 1; 183952889Sbostic if (lp > &asc_log[NLOG]) 184052889Sbostic lp = asc_log; 184152889Sbostic while (lp != asc_logp) { 184252889Sbostic status = lp->status; 184352889Sbostic printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 184452889Sbostic status >> 24, 184552889Sbostic lp->target, 184652889Sbostic (status >> 16) & 0xFF, 184752889Sbostic (status >> 8) & 0xFF, 184852889Sbostic status & 0XFF, 184952889Sbostic lp->state, 185052889Sbostic asc_scripts[lp->state].condition, 185152889Sbostic lp->msg); 185252889Sbostic if (++lp >= &asc_log[NLOG]) 185352889Sbostic lp = asc_log; 185452889Sbostic } 185552889Sbostic } 185652889Sbostic #endif 185752889Sbostic 185852889Sbostic #endif /* NASC > 0 */ 1859