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 652889Sbostic * Ralph Campbell. 752889Sbostic * 852889Sbostic * %sccs.include.redist.c% 952889Sbostic * 10*56525Sbostic * @(#)asc.c 7.6 (Berkeley) 10/11/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 9452889Sbostic #include "asc.h" 9552889Sbostic #if NASC > 0 9652889Sbostic 9756522Sbostic #include <sys/param.h> 9856522Sbostic #include <sys/systm.h> 9956522Sbostic #include <sys/dkstat.h> 10056522Sbostic #include <sys/buf.h> 10156522Sbostic #include <sys/conf.h> 10256522Sbostic #include <sys/errno.h> 10352889Sbostic 104*56525Sbostic #include <pmax/dev/device.h> 105*56525Sbostic #include <pmax/dev/scsi.h> 106*56525Sbostic #include <pmax/dev/ascreg.h> 10752889Sbostic 10852889Sbostic #define ASC_OFFSET_53C94 0x0 /* from module base */ 10952889Sbostic #define ASC_OFFSET_DMAR 0x40000 /* DMA Address Register */ 11052889Sbostic #define ASC_OFFSET_RAM 0x80000 /* SRAM Buffer */ 11152889Sbostic #define ASC_OFFSET_ROM 0xc0000 /* Diagnostic ROM */ 11252889Sbostic 11352889Sbostic #define ASC_RAM_SIZE 0x20000 /* 128k (32k*32) */ 11452889Sbostic 11552889Sbostic /* 11652889Sbostic * DMA Address Register 11752889Sbostic */ 11852889Sbostic #define ASC_DMAR_MASK 0x1ffff /* 17 bits, 128k */ 11952889Sbostic #define ASC_DMAR_WRITE 0x80000000 /* DMA direction bit */ 12053080Sralph #define ASC_DMA_ADDR(x) ((unsigned)(x) & ASC_DMAR_MASK) 12152889Sbostic 12252889Sbostic /* 12352889Sbostic * Synch xfer parameters, and timing conversions 12452889Sbostic */ 12552889Sbostic #define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */ 12652889Sbostic #define ASC_MIN_PERIOD 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 12752889Sbostic #define ASC_MAX_PERIOD 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 12852889Sbostic #define ASC_MAX_OFFSET 15 /* pure number */ 12952889Sbostic 13052889Sbostic int asc_to_scsi_period[] = { 13152889Sbostic 320, 13252889Sbostic 330, 13352889Sbostic 340, 13452889Sbostic 350, 13552889Sbostic 50, 13652889Sbostic 50, 13752889Sbostic 60, 13852889Sbostic 70, 13952889Sbostic 80, 14052889Sbostic 90, 14152889Sbostic 100, 14252889Sbostic 110, 14352889Sbostic 120, 14452889Sbostic 130, 14552889Sbostic 140, 14652889Sbostic 150, 14752889Sbostic 160, 14852889Sbostic 170, 14952889Sbostic 180, 15052889Sbostic 190, 15152889Sbostic 200, 15252889Sbostic 210, 15352889Sbostic 220, 15452889Sbostic 230, 15552889Sbostic 240, 15652889Sbostic 250, 15752889Sbostic 260, 15852889Sbostic 270, 15952889Sbostic 280, 16052889Sbostic 290, 16152889Sbostic 300, 16252889Sbostic 310, 16352889Sbostic }; 16452889Sbostic 16552889Sbostic /* 16652889Sbostic * Internal forward declarations. 16752889Sbostic */ 16852889Sbostic static void asc_reset(); 16952889Sbostic static void asc_startcmd(); 17052889Sbostic 17152889Sbostic #ifdef DEBUG 17252889Sbostic int asc_debug = 1; 17352889Sbostic int asc_debug_cmd; 17452889Sbostic int asc_debug_bn; 17552889Sbostic int asc_debug_sz; 17652889Sbostic #define NLOG 16 17752889Sbostic struct asc_log { 17852889Sbostic u_int status; 17952889Sbostic u_char state; 18052889Sbostic u_char msg; 18152889Sbostic int target; 18252889Sbostic } asc_log[NLOG], *asc_logp = asc_log; 18352889Sbostic #define PACK(unit, status, ss, ir) \ 18452889Sbostic ((unit << 24) | (status << 16) | (ss << 8) | ir) 18552889Sbostic #endif 18652889Sbostic 18752889Sbostic /* 18852889Sbostic * Scripts are entries in a state machine table. 18952889Sbostic * A script has four parts: a pre-condition, an action, a command to the chip, 19052889Sbostic * and an index into asc_scripts for the next state. The first triggers error 19152889Sbostic * handling if not satisfied and in our case it is formed by the 19252889Sbostic * values of the interrupt register and status register, this 19352889Sbostic * basically captures the phase of the bus and the TC and BS 19452889Sbostic * bits. The action part is just a function pointer, and the 19552889Sbostic * command is what the 53C94 should be told to do at the end 19652889Sbostic * of the action processing. This command is only issued and the 19752889Sbostic * script proceeds if the action routine returns TRUE. 19852889Sbostic * See asc_intr() for how and where this is all done. 19952889Sbostic */ 20052889Sbostic typedef struct script { 20152889Sbostic int condition; /* expected state at interrupt time */ 20252889Sbostic int (*action)(); /* extra operations */ 20352889Sbostic int command; /* command to the chip */ 20452889Sbostic struct script *next; /* index into asc_scripts for next state */ 20552889Sbostic } script_t; 20652889Sbostic 20752889Sbostic /* Matching on the condition value */ 20852889Sbostic #define SCRIPT_MATCH(ir, csr) ((ir) | (ASC_PHASE(csr) << 8)) 20952889Sbostic 21052889Sbostic /* forward decls of script actions */ 21154145Sralph static int script_nop(); /* when nothing needed */ 21254145Sralph static int asc_end(); /* all come to an end */ 21354145Sralph static int asc_get_status(); /* get status from target */ 21454145Sralph static int asc_dma_in(); /* start reading data from target */ 21554145Sralph static int asc_last_dma_in(); /* cleanup after all data is read */ 21654145Sralph static int asc_resume_in(); /* resume data in after a message */ 21754145Sralph static int asc_resume_dma_in(); /* resume DMA after a disconnect */ 21854145Sralph static int asc_dma_out(); /* send data to target via dma */ 21954145Sralph static int asc_last_dma_out(); /* cleanup after all data is written */ 22054145Sralph static int asc_resume_out(); /* resume data out after a message */ 22154145Sralph static int asc_resume_dma_out(); /* resume DMA after a disconnect */ 22254145Sralph static int asc_sendsync(); /* negotiate sync xfer */ 22354145Sralph static int asc_replysync(); /* negotiate sync xfer */ 22454145Sralph static int asc_msg_in(); /* process a message byte */ 22554145Sralph static int asc_disconnect(); /* process an expected disconnect */ 22652889Sbostic 22752889Sbostic /* Define the index into asc_scripts for various state transitions */ 22852889Sbostic #define SCRIPT_DATA_IN 0 22952942Sralph #define SCRIPT_CONTINUE_IN 2 23052942Sralph #define SCRIPT_DATA_OUT 3 23152942Sralph #define SCRIPT_CONTINUE_OUT 5 23252942Sralph #define SCRIPT_SIMPLE 6 23352942Sralph #define SCRIPT_GET_STATUS 7 23452942Sralph #define SCRIPT_MSG_IN 9 23552942Sralph #define SCRIPT_REPLY_SYNC 11 23652889Sbostic #define SCRIPT_TRY_SYNC 12 23752942Sralph #define SCRIPT_DISCONNECT 15 23852942Sralph #define SCRIPT_RESEL 16 23952942Sralph #define SCRIPT_RESUME_IN 17 24052942Sralph #define SCRIPT_RESUME_DMA_IN 18 24152942Sralph #define SCRIPT_RESUME_OUT 19 24252942Sralph #define SCRIPT_RESUME_DMA_OUT 20 24352942Sralph #define SCRIPT_RESUME_NO_DATA 21 24452889Sbostic 24552889Sbostic /* 24652889Sbostic * Scripts 24752889Sbostic */ 24852889Sbostic script_t asc_scripts[] = { 24952942Sralph /* start data in */ 25052889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 25152889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 25252942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 25352889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 25452889Sbostic asc_last_dma_in, ASC_CMD_I_COMPLETE, 25552942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 25652889Sbostic 25752942Sralph /* continue data in after a chuck is finished */ 25852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 25952942Sralph asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 26052942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 26152942Sralph 26252942Sralph /* start data out */ 26352942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 26452889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 26552942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 26652942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 26752889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 26852942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 26952889Sbostic 27052942Sralph /* continue data out after a chuck is finished */ 27152942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 27252942Sralph asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 27352942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 27452942Sralph 27552889Sbostic /* simple command with no data transfer */ 27652942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 27752889Sbostic script_nop, ASC_CMD_I_COMPLETE, 27852942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 27952889Sbostic 28052889Sbostic /* get status and finish command */ 28152942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 28252889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 28352942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 28452942Sralph {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 28552889Sbostic asc_end, ASC_CMD_NOP, 28652942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 28752889Sbostic 28852889Sbostic /* message in */ 28952942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 29052942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 29152942Sralph &asc_scripts[SCRIPT_MSG_IN + 1]}, 29252942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 29352889Sbostic script_nop, ASC_CMD_XFER_INFO, 29452942Sralph &asc_scripts[SCRIPT_MSG_IN]}, 29552889Sbostic 29652889Sbostic /* send synchonous negotiation reply */ 29752942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 29852889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 29952942Sralph &asc_scripts[SCRIPT_REPLY_SYNC]}, 30052889Sbostic 30152889Sbostic /* try to negotiate synchonous transfer parameters */ 30252889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 30352889Sbostic asc_sendsync, ASC_CMD_XFER_INFO, 30453080Sralph &asc_scripts[SCRIPT_TRY_SYNC + 1]}, 30553080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ 30652889Sbostic script_nop, ASC_CMD_XFER_INFO, 30753080Sralph &asc_scripts[SCRIPT_MSG_IN]}, 30853080Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ 30953080Sralph script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 31053080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]}, 31152889Sbostic 31252942Sralph /* handle a disconnect */ 31352942Sralph {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 31452942Sralph asc_disconnect, ASC_CMD_ENABLE_SEL, 31552942Sralph &asc_scripts[SCRIPT_RESEL]}, 31652942Sralph 31752889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 31852942Sralph {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 31952889Sbostic script_nop, ASC_CMD_MSG_ACPT, 32052942Sralph &asc_scripts[SCRIPT_RESEL]}, 32152889Sbostic 32252942Sralph /* resume data in after a message */ 32352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 32452942Sralph asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 32552942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 32652942Sralph 32752942Sralph /* resume partial DMA data in after a message */ 32852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 32952889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 33052942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 33152889Sbostic 33252942Sralph /* resume data out after a message */ 33352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 33452942Sralph asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 33552942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 33652942Sralph 33752942Sralph /* resume partial DMA data out after a message */ 33852942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 33952889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 34052942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 34152942Sralph 34252942Sralph /* resume after a message when there is no more data */ 34352942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 34452942Sralph script_nop, ASC_CMD_I_COMPLETE, 34552942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 34652889Sbostic }; 34752889Sbostic 34852889Sbostic /* 34952889Sbostic * State kept for each active SCSI device. 35052889Sbostic */ 35152889Sbostic typedef struct scsi_state { 35252889Sbostic script_t *script; /* saved script while processing error */ 35352889Sbostic int statusByte; /* status byte returned during STATUS_PHASE */ 35452889Sbostic int error; /* errno to pass back to device driver */ 35552889Sbostic u_char *dmaBufAddr; /* DMA buffer address */ 35652889Sbostic u_int dmaBufSize; /* DMA buffer size */ 35752889Sbostic int dmalen; /* amount to transfer in this chunk */ 35852889Sbostic int dmaresid; /* amount not transfered if chunk suspended */ 35952889Sbostic int buflen; /* total remaining amount of data to transfer */ 36052889Sbostic char *buf; /* current pointer within scsicmd->buf */ 36152889Sbostic int flags; /* see below */ 36252889Sbostic int msglen; /* number of message bytes to read */ 36352889Sbostic int msgcnt; /* number of message bytes received */ 36452889Sbostic u_char sync_period; /* DMA synchronous period */ 36552889Sbostic u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 36652889Sbostic u_char msg_out; /* next MSG_OUT byte to send */ 36752889Sbostic u_char msg_in[16]; /* buffer for multibyte messages */ 36852889Sbostic } State; 36952889Sbostic 37052889Sbostic /* state flags */ 37152889Sbostic #define DISCONN 0x01 /* true if currently disconnected from bus */ 37253080Sralph #define DMA_IN_PROGRESS 0x02 /* true if data DMA started */ 37352889Sbostic #define DMA_IN 0x04 /* true if reading from SCSI device */ 37452889Sbostic #define DMA_OUT 0x10 /* true if writing to SCSI device */ 37552889Sbostic #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 37652889Sbostic #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 37752889Sbostic 37852889Sbostic #define ASC_NCMD 7 37952889Sbostic /* 38052889Sbostic * State kept for each active SCSI host interface (53C94). 38152889Sbostic */ 38252889Sbostic struct asc_softc { 38352889Sbostic asc_regmap_t *regs; /* chip address */ 38452889Sbostic volatile int *dmar; /* DMA address register address */ 38554145Sralph u_char *buff; /* RAM buffer address */ 38652889Sbostic int myid; /* SCSI ID of this interface */ 38752889Sbostic int myidmask; /* ~(1 << myid) */ 38852889Sbostic int state; /* current SCSI connection state */ 38952889Sbostic int target; /* target SCSI ID if busy */ 39052889Sbostic script_t *script; /* next expected interrupt & action */ 39152889Sbostic ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 39252889Sbostic State st[ASC_NCMD]; /* state info for each active command */ 39352889Sbostic } asc_softc[NASC]; 39452889Sbostic 39552889Sbostic #define ASC_STATE_IDLE 0 /* idle state */ 39652889Sbostic #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 39752889Sbostic #define ASC_STATE_TARGET 2 /* currently selected as target */ 39852889Sbostic #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 39952889Sbostic 40052889Sbostic typedef struct asc_softc *asc_softc_t; 40152889Sbostic 40252889Sbostic /* 40352889Sbostic * Definition of the controller for the auto-configuration program. 40452889Sbostic */ 40552889Sbostic int asc_probe(); 40652889Sbostic void asc_start(); 40752889Sbostic void asc_intr(); 40852889Sbostic struct driver ascdriver = { 40952889Sbostic "asc", asc_probe, asc_start, 0, asc_intr, 41052889Sbostic }; 41152889Sbostic 41252889Sbostic /* 41352889Sbostic * Test to see if device is present. 41452889Sbostic * Return true if found and initialized ok. 41552889Sbostic */ 41652889Sbostic asc_probe(cp) 41752889Sbostic register struct pmax_ctlr *cp; 41852889Sbostic { 41952889Sbostic register asc_softc_t asc; 42052889Sbostic register asc_regmap_t *regs; 42152889Sbostic int unit, id, s, i; 42252889Sbostic 42352889Sbostic if ((unit = cp->pmax_unit) >= NASC) 42452889Sbostic return (0); 42552889Sbostic if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 42652889Sbostic return (0); 42752889Sbostic asc = &asc_softc[unit]; 42852889Sbostic 42952889Sbostic /* 43052889Sbostic * Initialize hw descriptor, cache some pointers 43152889Sbostic */ 43252889Sbostic asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 43352889Sbostic asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 43454145Sralph asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 43552889Sbostic 43652889Sbostic asc->state = ASC_STATE_IDLE; 43752889Sbostic asc->target = -1; 43852889Sbostic 43952889Sbostic regs = asc->regs; 44052889Sbostic 44152889Sbostic /* 44252889Sbostic * Reset chip, fully. Note that interrupts are already enabled. 44352889Sbostic */ 44452889Sbostic s = splbio(); 44552889Sbostic 44652889Sbostic /* preserve our ID for now */ 44752889Sbostic asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 44852889Sbostic asc->myidmask = ~(1 << asc->myid); 44952889Sbostic 45052889Sbostic asc_reset(asc, regs); 45152889Sbostic 45252889Sbostic /* 45352889Sbostic * Our SCSI id on the bus. 45452889Sbostic * The user can set this via the prom on 3maxen/pmaxen. 45552889Sbostic * If this changes it is easy to fix: make a default that 45652889Sbostic * can be changed as boot arg. 45752889Sbostic */ 45852889Sbostic #ifdef unneeded 45952889Sbostic regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 46052889Sbostic (scsi_initiator_id[unit] & 0x7); 46152889Sbostic #endif 46252889Sbostic id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 46352889Sbostic splx(s); 46452889Sbostic 46552889Sbostic /* 46652889Sbostic * Statically partition the DMA buffer between targets. 46752889Sbostic * This way we will eventually be able to attach/detach 46852889Sbostic * drives on-fly. And 18k/target is plenty for normal use. 46952889Sbostic */ 47052889Sbostic #define PER_TGT_DMA_SIZE ((ASC_RAM_SIZE/7) & ~(sizeof(int)-1)) 47152889Sbostic 47252889Sbostic /* 47352889Sbostic * Give each target its own DMA buffer region. 47452889Sbostic * We may want to try ping ponging buffers later. 47552889Sbostic */ 47652889Sbostic for (i = 0; i < ASC_NCMD; i++) { 47752889Sbostic asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i; 47852889Sbostic asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE; 47952889Sbostic } 48052889Sbostic printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 48152889Sbostic unit, cp->pmax_addr, cp->pmax_pri, id); 48252889Sbostic return (1); 48352889Sbostic } 48452889Sbostic 48552889Sbostic /* 48652889Sbostic * Start activity on a SCSI device. 48752889Sbostic * We maintain information on each device separately since devices can 48852889Sbostic * connect/disconnect during an operation. 48952889Sbostic */ 49052889Sbostic void 49152889Sbostic asc_start(scsicmd) 49252889Sbostic register ScsiCmd *scsicmd; /* command to start */ 49352889Sbostic { 49452889Sbostic register struct scsi_device *sdp = scsicmd->sd; 49552889Sbostic register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 49652889Sbostic int s; 49752889Sbostic 49852889Sbostic s = splbio(); 49952889Sbostic /* 50052889Sbostic * Check if another command is already in progress. 50152889Sbostic * We may have to change this if we allow SCSI devices with 50252889Sbostic * separate LUNs. 50352889Sbostic */ 50452889Sbostic if (asc->cmd[sdp->sd_drive]) { 50552889Sbostic printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 50652889Sbostic sdp->sd_driver->d_name); 50752889Sbostic (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 50852889Sbostic scsicmd->buflen, 0); 50952889Sbostic splx(s); 51052889Sbostic } 51152889Sbostic asc->cmd[sdp->sd_drive] = scsicmd; 51252889Sbostic asc_startcmd(asc, sdp->sd_drive); 51352889Sbostic splx(s); 51452889Sbostic } 51552889Sbostic 51652889Sbostic static void 51752889Sbostic asc_reset(asc, regs) 51852889Sbostic asc_softc_t asc; 51952889Sbostic asc_regmap_t *regs; 52052889Sbostic { 52152889Sbostic 52252889Sbostic /* 52352889Sbostic * Reset chip and wait till done 52452889Sbostic */ 52552889Sbostic regs->asc_cmd = ASC_CMD_RESET; 52652889Sbostic MachEmptyWriteBuffer(); DELAY(25); 52752889Sbostic 52852889Sbostic /* spec says this is needed after reset */ 52952889Sbostic regs->asc_cmd = ASC_CMD_NOP; 53052889Sbostic MachEmptyWriteBuffer(); DELAY(25); 53152889Sbostic 53252889Sbostic /* 53352889Sbostic * Set up various chip parameters 53452889Sbostic */ 53552889Sbostic regs->asc_ccf = ASC_CCF_25MHz; /* 25 MHz clock */ 53652889Sbostic MachEmptyWriteBuffer(); DELAY(25); 53752889Sbostic regs->asc_sel_timo = ASC_TIMEOUT_250; 53852889Sbostic /* restore our ID */ 53952889Sbostic regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 54052889Sbostic regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_EPL; 54152889Sbostic regs->asc_cnfg3 = 0; 54252889Sbostic /* zero anything else */ 54352889Sbostic ASC_TC_PUT(regs, 0); 54452889Sbostic regs->asc_sel_timo = ASC_TIMEOUT_250; 54552889Sbostic regs->asc_syn_p = ASC_MIN_PERIOD; 54652889Sbostic regs->asc_syn_o = 0; /* async for now */ 54752889Sbostic MachEmptyWriteBuffer(); 54852889Sbostic } 54952889Sbostic 55052889Sbostic /* 55152889Sbostic * Start a SCSI command on a target. 55252889Sbostic */ 55352889Sbostic static void 55452889Sbostic asc_startcmd(asc, target) 55552889Sbostic asc_softc_t asc; 55652889Sbostic int target; 55752889Sbostic { 55852889Sbostic register asc_regmap_t *regs; 55952889Sbostic register ScsiCmd *scsicmd; 56052889Sbostic register State *state; 56152889Sbostic int len; 56252889Sbostic 56352889Sbostic /* 56452889Sbostic * See if another target is currently selected on this SCSI bus. 56552889Sbostic */ 56652889Sbostic if (asc->target >= 0) 56752889Sbostic return; 56852889Sbostic 56952889Sbostic regs = asc->regs; 57052889Sbostic 57152889Sbostic /* 57252889Sbostic * Check to see if a reselection is in progress and if so, 57352889Sbostic * try to cancel it or respond to the reselection if it won. 57452889Sbostic */ 57552889Sbostic if (asc->state == ASC_STATE_RESEL) { 57652889Sbostic regs->asc_cmd = ASC_CMD_DISABLE_SEL; 57752889Sbostic while (!(regs->asc_status & ASC_CSR_INT)) 57852889Sbostic DELAY(1); 57952889Sbostic asc_intr(asc - asc_softc); 58052889Sbostic /* we will be busy if a reselecting device won */ 58152889Sbostic if (asc->state == ASC_STATE_BUSY) 58252889Sbostic return; 58352889Sbostic } 58452889Sbostic 58552889Sbostic asc->state = ASC_STATE_BUSY; 58652889Sbostic asc->target = target; 58752889Sbostic 58852889Sbostic /* cache some pointers */ 58952889Sbostic scsicmd = asc->cmd[target]; 59052889Sbostic state = &asc->st[target]; 59152889Sbostic 59252889Sbostic #ifdef DEBUG 59352889Sbostic if (asc_debug > 1) { 59452889Sbostic printf("asc_startcmd: %s target %d cmd %x len %d\n", 59552889Sbostic scsicmd->sd->sd_driver->d_name, target, 59652889Sbostic scsicmd->cmd[0], scsicmd->buflen); 59752889Sbostic } 59852889Sbostic asc_debug_cmd = scsicmd->cmd[0]; 59952889Sbostic if (scsicmd->cmd[0] == SCSI_READ_EXT) { 60052889Sbostic asc_debug_bn = (scsicmd->cmd[2] << 24) | 60152889Sbostic (scsicmd->cmd[3] << 16) | 60252889Sbostic (scsicmd->cmd[4] << 8) | 60352889Sbostic scsicmd->cmd[5]; 60452889Sbostic asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 60552889Sbostic } 60653080Sralph asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 60752889Sbostic asc_logp->target = asc->target; 60852889Sbostic asc_logp->state = 0; 60953080Sralph asc_logp->msg = 0xff; 61052889Sbostic if (++asc_logp >= &asc_log[NLOG]) 61152889Sbostic asc_logp = asc_log; 61252889Sbostic #endif 61352889Sbostic 61452889Sbostic /* 61552889Sbostic * Init the chip and target state. 61652889Sbostic */ 61752889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 61853080Sralph state->flags = state->flags & DID_SYNC; 61952889Sbostic state->error = 0; 62052889Sbostic state->script = (script_t *)0; 62152889Sbostic state->msg_out = SCSI_NO_OP; 62252889Sbostic 62352889Sbostic /* 62452889Sbostic * Copy command data to the DMA buffer. 62552889Sbostic */ 62652889Sbostic len = scsicmd->cmdlen; 62752889Sbostic state->dmalen = len; 62852889Sbostic bcopy(scsicmd->cmd, state->dmaBufAddr, len); 62952889Sbostic 63052889Sbostic /* check for simple SCSI command with no data transfer */ 63152889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 63252889Sbostic /* check for sync negotiation */ 63352889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 63452889Sbostic !(state->flags & DID_SYNC)) { 63552889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 63652889Sbostic state->flags |= TRY_SYNC; 63752889Sbostic } else 63852889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 63952889Sbostic state->buf = (char *)0; 64052889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 64152889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 64253080Sralph state->buf = scsicmd->buf; 64352889Sbostic state->flags |= DMA_OUT; 64452889Sbostic } else { 64552889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 64652889Sbostic state->buf = scsicmd->buf; 64752889Sbostic state->flags |= DMA_IN; 64852889Sbostic } 64952889Sbostic 65052889Sbostic /* preload the FIFO with the message to be sent */ 65152942Sralph regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 65252889Sbostic 65352889Sbostic /* start the asc */ 65452889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 65552889Sbostic ASC_TC_PUT(regs, len); 65652889Sbostic 65752889Sbostic regs->asc_dbus_id = target; 65852889Sbostic regs->asc_syn_p = state->sync_period; 65952889Sbostic regs->asc_syn_o = state->sync_offset; 66052889Sbostic 66152889Sbostic if (state->flags & TRY_SYNC) 66253080Sralph regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 66352889Sbostic else 66452889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 66552889Sbostic } 66652889Sbostic 66752889Sbostic /* 66852889Sbostic * Interrupt routine 66952889Sbostic * Take interrupts from the chip 67052889Sbostic * 67152889Sbostic * Implementation: 67252889Sbostic * Move along the current command's script if 67352889Sbostic * all is well, invoke error handler if not. 67452889Sbostic */ 67552889Sbostic void 67652889Sbostic asc_intr(unit) 67752889Sbostic int unit; 67852889Sbostic { 67952889Sbostic register asc_softc_t asc = &asc_softc[unit]; 68052889Sbostic register asc_regmap_t *regs = asc->regs; 68152889Sbostic register State *state; 68252889Sbostic register script_t *scpt; 68352889Sbostic register int ss, ir, status; 68452889Sbostic 68552889Sbostic /* collect ephemeral information */ 68652889Sbostic status = regs->asc_status; 68753080Sralph again: 68852889Sbostic ss = regs->asc_ss; 68952889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 69052889Sbostic scpt = asc->script; 69152889Sbostic 69252889Sbostic #ifdef DEBUG 69352889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 69452889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 69552889Sbostic asc_logp->state = scpt - asc_scripts; 69652889Sbostic asc_logp->msg = -1; 69752889Sbostic if (++asc_logp >= &asc_log[NLOG]) 69852889Sbostic asc_logp = asc_log; 69952889Sbostic if (asc_debug > 2) 70052889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 70152889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 70252889Sbostic #endif 70352889Sbostic 70452889Sbostic /* check the expected state */ 70552889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 70652889Sbostic /* 70752889Sbostic * Perform the appropriate operation, then proceed. 70852889Sbostic */ 70952889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 71052889Sbostic regs->asc_cmd = scpt->command; 71152889Sbostic asc->script = scpt->next; 71252889Sbostic } 71352889Sbostic goto done; 71452889Sbostic } 71552889Sbostic 71652889Sbostic /* check for message in or out */ 71752889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 71852889Sbostic register int len, fifo; 71952889Sbostic 72052889Sbostic state = &asc->st[asc->target]; 72152889Sbostic switch (ASC_PHASE(status)) { 72253080Sralph case ASC_PHASE_DATAI: 72353080Sralph case ASC_PHASE_DATAO: 72453080Sralph ASC_TC_GET(regs, len); 72553080Sralph fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 72653080Sralph printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 72753080Sralph state->buflen, state->dmalen, len, fifo); 72853080Sralph goto abort; 72953080Sralph 73052889Sbostic case ASC_PHASE_MSG_IN: 73152889Sbostic break; 73252889Sbostic 73352889Sbostic case ASC_PHASE_MSG_OUT: 73452889Sbostic regs->asc_fifo = state->msg_out; 73552889Sbostic state->msg_out = SCSI_NO_OP; 73652889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 73752889Sbostic goto done; 73852889Sbostic 73952889Sbostic case ASC_PHASE_STATUS: 74052889Sbostic /* probably an error in the SCSI command */ 74152889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 74252889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 74352889Sbostic goto done; 74452889Sbostic 74552889Sbostic default: 74652889Sbostic goto abort; 74752889Sbostic } 74852889Sbostic 74952889Sbostic if (state->script) 75052889Sbostic goto abort; 75152889Sbostic 75252889Sbostic /* check for DMA in progress */ 75352889Sbostic ASC_TC_GET(regs, len); 75452889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 75552889Sbostic /* flush any data in the FIFO */ 75652889Sbostic if (fifo) { 75753080Sralph if (state->flags & DMA_OUT) 75853080Sralph len += fifo; 75953080Sralph else if (state->flags & DMA_IN) { 76053080Sralph u_char *cp; 76153080Sralph 76253080Sralph printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 76353080Sralph state->dmalen, len, fifo); /* XXX */ 76453080Sralph len += fifo; 76553080Sralph cp = state->dmaBufAddr + (state->dmalen - len); 76653080Sralph while (fifo-- > 0) 76753080Sralph *cp++ = regs->asc_fifo; 76853080Sralph } else 76953080Sralph printf("asc_intr: dmalen %d len %d fifo %d\n", 77053080Sralph state->dmalen, len, fifo); /* XXX */ 77152889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 77252889Sbostic MachEmptyWriteBuffer(); 77352889Sbostic } 77452889Sbostic if (len) { 77552889Sbostic /* save number of bytes still to be sent or received */ 77652889Sbostic state->dmaresid = len; 77752889Sbostic /* setup state to resume to */ 77852889Sbostic if (state->flags & DMA_IN) 77952889Sbostic state->script = 78052889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 78152889Sbostic else if (state->flags & DMA_OUT) 78252889Sbostic state->script = 78352889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 78452889Sbostic else 78552889Sbostic state->script = asc->script; 78652889Sbostic } else { 78752889Sbostic /* setup state to resume to */ 78852942Sralph if (state->flags & DMA_IN) { 78953080Sralph if (state->flags & DMA_IN_PROGRESS) { 79053080Sralph state->flags &= ~DMA_IN_PROGRESS; 79152942Sralph len = state->dmalen; 79252942Sralph bcopy(state->dmaBufAddr, state->buf, 79352942Sralph len); 79452942Sralph state->buf += len; 79552942Sralph state->buflen -= len; 79653080Sralph } 79752942Sralph if (state->buflen) 79852942Sralph state->script = 79952942Sralph &asc_scripts[SCRIPT_RESUME_IN]; 80052942Sralph else 80152942Sralph state->script = 80252942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 80352942Sralph } else if (state->flags & DMA_OUT) { 80452942Sralph /* 80552942Sralph * If this is the last chunk, the next expected 80652942Sralph * state is to get status. 80752942Sralph */ 80853080Sralph if (state->flags & DMA_IN_PROGRESS) { 80953080Sralph state->flags &= ~DMA_IN_PROGRESS; 81053080Sralph len = state->dmalen; 81153080Sralph state->buf += len; 81253080Sralph state->buflen -= len; 81353080Sralph } 81452942Sralph if (state->buflen) 81552942Sralph state->script = 81652942Sralph &asc_scripts[SCRIPT_RESUME_OUT]; 81752942Sralph else 81852942Sralph state->script = 81952942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 82053080Sralph } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 82153080Sralph state->script = 82253080Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 82353080Sralph else 82452889Sbostic state->script = asc->script; 82552889Sbostic } 82652889Sbostic 82752889Sbostic /* setup to receive a message */ 82852889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 82952889Sbostic state->msglen = 0; 83052889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 83152889Sbostic goto done; 83252889Sbostic } 83352889Sbostic 83452889Sbostic /* check for SCSI bus reset */ 83552889Sbostic if (ir & ASC_INT_RESET) { 83652889Sbostic register int i; 83752889Sbostic 83852889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 83952889Sbostic /* need to flush any pending commands */ 84052889Sbostic for (i = 0; i < ASC_NCMD; i++) { 84152889Sbostic if (!asc->cmd[i]) 84252889Sbostic continue; 84352889Sbostic asc->st[i].error = EIO; 84452889Sbostic asc_end(asc, 0, 0, 0); 84552889Sbostic } 84652889Sbostic /* rearbitrate synchronous offset */ 84752889Sbostic for (i = 0; i < ASC_NCMD; i++) { 84852889Sbostic asc->st[i].sync_offset = 0; 84952889Sbostic asc->st[i].flags = 0; 85052889Sbostic } 85152889Sbostic asc->target = -1; 85252889Sbostic return; 85352889Sbostic } 85452889Sbostic 85552889Sbostic /* check for command errors */ 85652889Sbostic if (ir & ASC_INT_ILL) 85752889Sbostic goto abort; 85852889Sbostic 85952889Sbostic /* check for disconnect */ 86052889Sbostic if (ir & ASC_INT_DISC) { 86152889Sbostic state = &asc->st[asc->target]; 86252889Sbostic switch (ASC_SS(ss)) { 86352889Sbostic case 0: /* device did not respond */ 86452889Sbostic state->error = ENXIO; 86552889Sbostic asc_end(asc, status, ss, ir); 86652889Sbostic return; 86752889Sbostic 86852889Sbostic default: 86952889Sbostic goto abort; 87052889Sbostic } 87152889Sbostic } 87252889Sbostic 87352889Sbostic /* check for reselect */ 87452889Sbostic if (ir & ASC_INT_RESEL) { 87552889Sbostic unsigned fifo, id, msg; 87652889Sbostic 87752889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 87852889Sbostic if (fifo < 2) 87952889Sbostic goto abort; 88052889Sbostic /* read unencoded SCSI ID and convert to binary */ 88152889Sbostic msg = regs->asc_fifo & asc->myidmask; 88252889Sbostic for (id = 0; (msg & 1) == 0; id++) 88352889Sbostic msg >>= 1; 88452889Sbostic /* read identify message */ 88552889Sbostic msg = regs->asc_fifo; 88652889Sbostic #ifdef DEBUG 88752889Sbostic if (asc_logp == asc_log) 88852889Sbostic asc_log[NLOG - 1].msg = msg; 88952889Sbostic else 89052889Sbostic asc_logp[-1].msg = msg; 89152889Sbostic #endif 89252889Sbostic if (asc->state != ASC_STATE_RESEL) 89352889Sbostic goto abort; 89452889Sbostic asc->state = ASC_STATE_BUSY; 89552889Sbostic asc->target = id; 89652889Sbostic state = &asc->st[id]; 89752889Sbostic asc->script = state->script; 89852889Sbostic state->script = (script_t *)0; 89952889Sbostic if (!(state->flags & DISCONN)) 90052889Sbostic goto abort; 90152889Sbostic state->flags &= ~DISCONN; 90253080Sralph regs->asc_syn_p = state->sync_period; 90353080Sralph regs->asc_syn_o = state->sync_offset; 90452889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 90552889Sbostic goto done; 90652889Sbostic } 90752889Sbostic 90852889Sbostic /* check if we are being selected as a target */ 90952889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 91052889Sbostic goto abort; 91152889Sbostic 91252889Sbostic /* must be just a ASC_INT_FC */ 91352889Sbostic done: 91452889Sbostic MachEmptyWriteBuffer(); 91553080Sralph /* watch out for HW race conditions and setup & hold time violations */ 91653080Sralph ir = regs->asc_status; 91753080Sralph while (ir != (status = regs->asc_status)) 91853080Sralph ir = status; 91953080Sralph if (status & ASC_CSR_INT) 92052889Sbostic goto again; 92152889Sbostic return; 92252889Sbostic 92352889Sbostic abort: 92452889Sbostic #ifdef DEBUG 92552889Sbostic asc_DumpLog("asc_intr"); 92652889Sbostic #endif 92752889Sbostic #if 0 92852889Sbostic panic("asc_intr"); 92952889Sbostic #else 93052889Sbostic for (;;); 93152889Sbostic #endif 93252889Sbostic } 93352889Sbostic 93452889Sbostic /* 93552889Sbostic * All the many little things that the interrupt 93652889Sbostic * routine might switch to. 93752889Sbostic */ 93852889Sbostic 93952889Sbostic /* ARGSUSED */ 94052889Sbostic static int 94152889Sbostic script_nop(asc, status, ss, ir) 94252889Sbostic register asc_softc_t asc; 94352889Sbostic register int status, ss, ir; 94452889Sbostic { 94552889Sbostic return (1); 94652889Sbostic } 94752889Sbostic 94852889Sbostic /* ARGSUSED */ 94952889Sbostic static int 95052889Sbostic asc_get_status(asc, status, ss, ir) 95152889Sbostic register asc_softc_t asc; 95252889Sbostic register int status, ss, ir; 95352889Sbostic { 95452889Sbostic register asc_regmap_t *regs = asc->regs; 95552889Sbostic register int data; 95652889Sbostic 95752889Sbostic /* 95852889Sbostic * Get the last two bytes in the FIFO. 95952889Sbostic */ 96052889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 96152889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 96252889Sbostic if (data < 2) { 96352889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 96452889Sbostic return (0); 96552889Sbostic } 96652889Sbostic do { 96752889Sbostic data = regs->asc_fifo; 96852889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 96952889Sbostic } 97052889Sbostic 97152889Sbostic /* save the status byte */ 97252889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 97352889Sbostic #ifdef DEBUG 97452889Sbostic if (asc_logp == asc_log) 97552889Sbostic asc_log[NLOG - 1].msg = data; 97652889Sbostic else 97752889Sbostic asc_logp[-1].msg = data; 97852889Sbostic #endif 97952889Sbostic 98052889Sbostic /* get the (presumed) command_complete message */ 98152889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 98252889Sbostic return (1); 98352889Sbostic 98452889Sbostic #ifdef DEBUG 98552889Sbostic printf("asc_get_status: status %x cmd %x\n", 98652889Sbostic asc->st[asc->target].statusByte, data); 98752889Sbostic asc_DumpLog("asc_get_status"); 98852889Sbostic #endif 98952889Sbostic return (0); 99052889Sbostic } 99152889Sbostic 99252889Sbostic /* ARGSUSED */ 99352889Sbostic static int 99452889Sbostic asc_end(asc, status, ss, ir) 99552889Sbostic register asc_softc_t asc; 99652889Sbostic register int status, ss, ir; 99752889Sbostic { 99852889Sbostic register ScsiCmd *scsicmd; 99952889Sbostic register State *state; 100052889Sbostic register int i, target; 100152889Sbostic 100252889Sbostic asc->state = ASC_STATE_IDLE; 100352889Sbostic target = asc->target; 100452889Sbostic asc->target = -1; 100552889Sbostic scsicmd = asc->cmd[target]; 100652889Sbostic asc->cmd[target] = (ScsiCmd *)0; 100752889Sbostic state = &asc->st[target]; 100852889Sbostic 100952889Sbostic #ifdef DEBUG 101052889Sbostic if (asc_debug > 1) { 101152889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 101252889Sbostic scsicmd->sd->sd_driver->d_name, target, 101352889Sbostic scsicmd->cmd[0], state->error, state->buflen); 101452889Sbostic } 101552889Sbostic #endif 101652889Sbostic #ifdef DIAGNOSTIC 101752889Sbostic if (target < 0 || !scsicmd) 101852889Sbostic panic("asc_end"); 101952889Sbostic #endif 102052889Sbostic 102152889Sbostic /* look for disconnected devices */ 102252889Sbostic for (i = 0; i < ASC_NCMD; i++) { 102352889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 102452889Sbostic continue; 102552889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 102652889Sbostic asc->state = ASC_STATE_RESEL; 102752889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 102852889Sbostic break; 102952889Sbostic } 103052889Sbostic 103152889Sbostic /* look for another device that is ready */ 103252889Sbostic for (i = 0; i < ASC_NCMD; i++) { 103352889Sbostic /* don't restart a disconnected command */ 103452889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 103552889Sbostic continue; 103652889Sbostic asc_startcmd(asc, i); 103752889Sbostic break; 103852889Sbostic } 103952889Sbostic 104052889Sbostic /* signal device driver that the command is done */ 104152889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 104252889Sbostic state->buflen, state->statusByte); 104352889Sbostic 104452889Sbostic return (0); 104552889Sbostic } 104652889Sbostic 104752889Sbostic /* ARGSUSED */ 104852889Sbostic static int 104952889Sbostic asc_dma_in(asc, status, ss, ir) 105052889Sbostic register asc_softc_t asc; 105152889Sbostic register int status, ss, ir; 105252889Sbostic { 105352889Sbostic register asc_regmap_t *regs = asc->regs; 105452889Sbostic register State *state = &asc->st[asc->target]; 105553080Sralph register int len; 105652889Sbostic 105752889Sbostic /* check for previous chunk in buffer */ 105853080Sralph if (state->flags & DMA_IN_PROGRESS) { 105952889Sbostic /* 106052889Sbostic * Only count bytes that have been copied to memory. 106152889Sbostic * There may be some bytes in the FIFO if synchonous transfers 106252889Sbostic * are in progress. 106352889Sbostic */ 106452889Sbostic ASC_TC_GET(regs, len); 106552889Sbostic len = state->dmalen - len; 106652889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 106752889Sbostic state->buf += len; 106852889Sbostic state->buflen -= len; 106953080Sralph } 107052889Sbostic 107152942Sralph /* setup to start reading the next chunk */ 107252889Sbostic len = state->buflen; 107352889Sbostic if (len > state->dmaBufSize) 107452889Sbostic len = state->dmaBufSize; 107552889Sbostic state->dmalen = len; 107652889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 107752889Sbostic ASC_TC_PUT(regs, len); 107852942Sralph #ifdef DEBUG 107952942Sralph if (asc_debug > 2) 108052942Sralph printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 108152942Sralph #endif 108252942Sralph 108352942Sralph /* check for next chunk */ 108453080Sralph state->flags |= DMA_IN_PROGRESS; 108552889Sbostic if (len != state->buflen) { 108652889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 108752942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 108852889Sbostic return (0); 108952889Sbostic } 109052889Sbostic return (1); 109152889Sbostic } 109252889Sbostic 109352889Sbostic /* ARGSUSED */ 109452889Sbostic static int 109552889Sbostic asc_last_dma_in(asc, status, ss, ir) 109652889Sbostic register asc_softc_t asc; 109752889Sbostic register int status, ss, ir; 109852889Sbostic { 109952889Sbostic register asc_regmap_t *regs = asc->regs; 110052889Sbostic register State *state = &asc->st[asc->target]; 110152889Sbostic register int len, fifo; 110252889Sbostic 110352889Sbostic /* copy data from buffer to main memory */ 110452889Sbostic ASC_TC_GET(regs, len); 110552889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 110652889Sbostic #ifdef DEBUG 110752942Sralph if (asc_debug > 2) 110852889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 110952889Sbostic state->buflen, state->dmalen, len, fifo); 111052889Sbostic #endif 111152889Sbostic if (fifo) { 111252942Sralph /* device must be trying to send more than we expect */ 111352889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 111452889Sbostic MachEmptyWriteBuffer(); 111552889Sbostic } 111653080Sralph state->flags &= ~DMA_IN_PROGRESS; 111752889Sbostic len = state->dmalen - len; 111852889Sbostic state->buflen -= len; 111952889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 112052889Sbostic 112152889Sbostic return (1); 112252889Sbostic } 112352889Sbostic 112452889Sbostic /* ARGSUSED */ 112552889Sbostic static int 112652942Sralph asc_resume_in(asc, status, ss, ir) 112752942Sralph register asc_softc_t asc; 112852942Sralph register int status, ss, ir; 112952942Sralph { 113052942Sralph register asc_regmap_t *regs = asc->regs; 113152942Sralph register State *state = &asc->st[asc->target]; 113252942Sralph register int len; 113352942Sralph 113452942Sralph /* setup to start reading the next chunk */ 113552942Sralph len = state->buflen; 113652942Sralph if (len > state->dmaBufSize) 113752942Sralph len = state->dmaBufSize; 113852942Sralph state->dmalen = len; 113952942Sralph *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 114052942Sralph ASC_TC_PUT(regs, len); 114152942Sralph #ifdef DEBUG 114252942Sralph if (asc_debug > 2) 114352942Sralph printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 114452942Sralph len); 114552942Sralph #endif 114652942Sralph 114752942Sralph /* check for next chunk */ 114853080Sralph state->flags |= DMA_IN_PROGRESS; 114952942Sralph if (len != state->buflen) { 115052942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 115152942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 115252942Sralph return (0); 115352942Sralph } 115452942Sralph return (1); 115552942Sralph } 115652942Sralph 115752942Sralph /* ARGSUSED */ 115852942Sralph static int 115952889Sbostic asc_resume_dma_in(asc, status, ss, ir) 116052889Sbostic register asc_softc_t asc; 116152889Sbostic register int status, ss, ir; 116252889Sbostic { 116352889Sbostic register asc_regmap_t *regs = asc->regs; 116452889Sbostic register State *state = &asc->st[asc->target]; 116552889Sbostic register int len, off; 116652889Sbostic 116752889Sbostic /* setup to finish reading the current chunk */ 116852889Sbostic len = state->dmaresid; 116952889Sbostic off = state->dmalen - len; 117052889Sbostic if ((off & 1) && state->sync_offset) { 117152889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 117252889Sbostic state->dmalen, len, off); /* XXX */ 117352889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 117452889Sbostic } 117552889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off); 117652889Sbostic ASC_TC_PUT(regs, len); 117752942Sralph #ifdef DEBUG 117852942Sralph if (asc_debug > 2) 117952942Sralph printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 118052942Sralph state->dmalen, state->buflen, len, off); 118152942Sralph #endif 118252942Sralph 118352942Sralph /* check for next chunk */ 118453080Sralph state->flags |= DMA_IN_PROGRESS; 118552889Sbostic if (state->dmalen != state->buflen) { 118652889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 118752942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 118852889Sbostic return (0); 118952889Sbostic } 119052889Sbostic return (1); 119152889Sbostic } 119252889Sbostic 119352889Sbostic /* ARGSUSED */ 119452889Sbostic static int 119552889Sbostic asc_dma_out(asc, status, ss, ir) 119652889Sbostic register asc_softc_t asc; 119752889Sbostic register int status, ss, ir; 119852889Sbostic { 119952889Sbostic register asc_regmap_t *regs = asc->regs; 120052889Sbostic register State *state = &asc->st[asc->target]; 120152889Sbostic register int len, fifo; 120252889Sbostic 120353080Sralph if (state->flags & DMA_IN_PROGRESS) { 120452889Sbostic /* check to be sure previous chunk was finished */ 120552889Sbostic ASC_TC_GET(regs, len); 120652889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 120752889Sbostic if (len || fifo) 120852889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 120952889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 121052889Sbostic len += fifo; 121152889Sbostic len = state->dmalen - len; 121253080Sralph state->buf += len; 121352889Sbostic state->buflen -= len; 121453080Sralph } 121552889Sbostic 121653080Sralph /* setup for this chunck */ 121753080Sralph len = state->buflen; 121853080Sralph if (len > state->dmaBufSize) 121953080Sralph len = state->dmaBufSize; 122053080Sralph state->dmalen = len; 122153080Sralph bcopy(state->buf, state->dmaBufAddr, len); 122253080Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 122352942Sralph ASC_TC_PUT(regs, len); 122452889Sbostic #ifdef DEBUG 122552889Sbostic if (asc_debug > 2) 122652942Sralph printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 122752889Sbostic #endif 122852889Sbostic 122952889Sbostic /* check for next chunk */ 123053080Sralph state->flags |= DMA_IN_PROGRESS; 123152889Sbostic if (len != state->buflen) { 123252889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 123352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 123452889Sbostic return (0); 123552889Sbostic } 123652889Sbostic return (1); 123752889Sbostic } 123852889Sbostic 123952889Sbostic /* ARGSUSED */ 124052889Sbostic static int 124152889Sbostic asc_last_dma_out(asc, status, ss, ir) 124252889Sbostic register asc_softc_t asc; 124352889Sbostic register int status, ss, ir; 124452889Sbostic { 124552889Sbostic register asc_regmap_t *regs = asc->regs; 124652889Sbostic register State *state = &asc->st[asc->target]; 124752889Sbostic register int len, fifo; 124852889Sbostic 124952889Sbostic ASC_TC_GET(regs, len); 125052889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 125152889Sbostic #ifdef DEBUG 125252889Sbostic if (asc_debug > 2) 125352889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 125453080Sralph state->buflen, state->dmalen, len, fifo); 125552942Sralph #endif 125652942Sralph if (fifo) { 125752942Sralph len += fifo; 125852942Sralph regs->asc_cmd = ASC_CMD_FLUSH; 125952942Sralph MachEmptyWriteBuffer(); 126052942Sralph } 126153080Sralph state->flags &= ~DMA_IN_PROGRESS; 126252889Sbostic len = state->dmalen - len; 126352889Sbostic state->buflen -= len; 126452889Sbostic return (1); 126552889Sbostic } 126652889Sbostic 126752889Sbostic /* ARGSUSED */ 126852889Sbostic static int 126952942Sralph asc_resume_out(asc, status, ss, ir) 127052942Sralph register asc_softc_t asc; 127152942Sralph register int status, ss, ir; 127252942Sralph { 127352942Sralph register asc_regmap_t *regs = asc->regs; 127452942Sralph register State *state = &asc->st[asc->target]; 127552942Sralph register int len; 127652942Sralph 127752942Sralph /* setup for this chunck */ 127852942Sralph len = state->buflen; 127952942Sralph if (len > state->dmaBufSize) 128052942Sralph len = state->dmaBufSize; 128152942Sralph state->dmalen = len; 128252942Sralph bcopy(state->buf, state->dmaBufAddr, len); 128352942Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 128452942Sralph ASC_TC_PUT(regs, len); 128552942Sralph #ifdef DEBUG 128652942Sralph if (asc_debug > 2) 128752942Sralph printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 128852942Sralph len); 128952942Sralph #endif 129052942Sralph 129152942Sralph /* check for next chunk */ 129253080Sralph state->flags |= DMA_IN_PROGRESS; 129352942Sralph if (len != state->buflen) { 129452942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 129552942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 129652942Sralph return (0); 129752942Sralph } 129852942Sralph return (1); 129952942Sralph } 130052942Sralph 130152942Sralph /* ARGSUSED */ 130252942Sralph static int 130352889Sbostic asc_resume_dma_out(asc, status, ss, ir) 130452889Sbostic register asc_softc_t asc; 130552889Sbostic register int status, ss, ir; 130652889Sbostic { 130752889Sbostic register asc_regmap_t *regs = asc->regs; 130852889Sbostic register State *state = &asc->st[asc->target]; 130952889Sbostic register int len, off; 131052889Sbostic 131152889Sbostic /* setup to finish writing this chunk */ 131252889Sbostic len = state->dmaresid; 131352889Sbostic off = state->dmalen - len; 131452889Sbostic if (off & 1) { 131552889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 131652889Sbostic state->dmalen, len, off); /* XXX */ 131752889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 131852889Sbostic off++; 131952889Sbostic len--; 132052889Sbostic } 132152889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off); 132252889Sbostic ASC_TC_PUT(regs, len); 132352942Sralph #ifdef DEBUG 132452942Sralph if (asc_debug > 2) 132552942Sralph printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 132652942Sralph state->dmalen, state->buflen, len, off); 132752942Sralph #endif 132852942Sralph 132952942Sralph /* check for next chunk */ 133053080Sralph state->flags |= DMA_IN_PROGRESS; 133152889Sbostic if (state->dmalen != state->buflen) { 133252889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 133352942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 133452889Sbostic return (0); 133552889Sbostic } 133652889Sbostic return (1); 133752889Sbostic } 133852889Sbostic 133952889Sbostic /* ARGSUSED */ 134052889Sbostic static int 134152889Sbostic asc_sendsync(asc, status, ss, ir) 134252889Sbostic register asc_softc_t asc; 134352889Sbostic register int status, ss, ir; 134452889Sbostic { 134552889Sbostic register asc_regmap_t *regs = asc->regs; 134653080Sralph register State *state = &asc->st[asc->target]; 134752889Sbostic 134853080Sralph /* send the extended synchronous negotiation message */ 134952889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 135052889Sbostic MachEmptyWriteBuffer(); 135152889Sbostic regs->asc_fifo = 3; 135252889Sbostic MachEmptyWriteBuffer(); 135352889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 135452889Sbostic MachEmptyWriteBuffer(); 135552889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 135652889Sbostic MachEmptyWriteBuffer(); 135752889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 135853080Sralph /* state to resume after we see the sync reply message */ 135953080Sralph state->script = asc->script + 2; 136053080Sralph state->msglen = 0; 136152889Sbostic return (1); 136252889Sbostic } 136352889Sbostic 136452889Sbostic /* ARGSUSED */ 136552889Sbostic static int 136652889Sbostic asc_replysync(asc, status, ss, ir) 136752889Sbostic register asc_softc_t asc; 136852889Sbostic register int status, ss, ir; 136952889Sbostic { 137052889Sbostic register asc_regmap_t *regs = asc->regs; 137152889Sbostic register State *state = &asc->st[asc->target]; 137252889Sbostic 137352889Sbostic #ifdef DEBUG 137452889Sbostic if (asc_debug > 2) 137552889Sbostic printf("asc_replysync: %x %x\n", 137652889Sbostic asc_to_scsi_period[state->sync_period], 137752889Sbostic state->sync_offset); 137852889Sbostic #endif 137952889Sbostic /* send synchronous transfer in response to a request */ 138052889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 138152889Sbostic MachEmptyWriteBuffer(); 138252889Sbostic regs->asc_fifo = 3; 138352889Sbostic MachEmptyWriteBuffer(); 138452889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 138552889Sbostic MachEmptyWriteBuffer(); 138652889Sbostic regs->asc_fifo = asc_to_scsi_period[state->sync_period]; 138752889Sbostic MachEmptyWriteBuffer(); 138852889Sbostic regs->asc_fifo = state->sync_offset; 138952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 139052889Sbostic 139152889Sbostic /* return to the appropriate script */ 139252889Sbostic if (!state->script) { 139352889Sbostic #ifdef DEBUG 139452889Sbostic asc_DumpLog("asc_replsync"); 139552889Sbostic #endif 139652889Sbostic panic("asc_replysync"); 139752889Sbostic } 139852889Sbostic asc->script = state->script; 139952889Sbostic state->script = (script_t *)0; 140052889Sbostic return (0); 140152889Sbostic } 140252889Sbostic 140352889Sbostic /* ARGSUSED */ 140452889Sbostic static int 140552942Sralph asc_msg_in(asc, status, ss, ir) 140652889Sbostic register asc_softc_t asc; 140752889Sbostic register int status, ss, ir; 140852889Sbostic { 140952889Sbostic register asc_regmap_t *regs = asc->regs; 141052889Sbostic register State *state = &asc->st[asc->target]; 141152889Sbostic register int msg; 141252889Sbostic int i; 141352889Sbostic 141452889Sbostic /* read one message byte */ 141552889Sbostic msg = regs->asc_fifo; 141652889Sbostic #ifdef DEBUG 141752889Sbostic if (asc_logp == asc_log) 141852889Sbostic asc_log[NLOG - 1].msg = msg; 141952889Sbostic else 142052889Sbostic asc_logp[-1].msg = msg; 142152889Sbostic #endif 142252889Sbostic 142352889Sbostic /* check for multi-byte message */ 142452889Sbostic if (state->msglen != 0) { 142552889Sbostic /* first byte is the message length */ 142652889Sbostic if (state->msglen < 0) { 142752889Sbostic state->msglen = msg; 142852889Sbostic return (1); 142952889Sbostic } 143052889Sbostic if (state->msgcnt >= state->msglen) 143152889Sbostic goto abort; 143252889Sbostic state->msg_in[state->msgcnt++] = msg; 143352889Sbostic 143452889Sbostic /* did we just read the last byte of the message? */ 143552889Sbostic if (state->msgcnt != state->msglen) 143652889Sbostic return (1); 143752889Sbostic 143852889Sbostic /* process an extended message */ 143952889Sbostic #ifdef DEBUG 144052889Sbostic if (asc_debug > 2) 144152942Sralph printf("asc_msg_in: msg %x %x %x\n", 144252889Sbostic state->msg_in[0], 144352889Sbostic state->msg_in[1], 144452889Sbostic state->msg_in[2]); 144552889Sbostic #endif 144652889Sbostic switch (state->msg_in[0]) { 144752889Sbostic case SCSI_SYNCHRONOUS_XFER: 144852889Sbostic state->flags |= DID_SYNC; 144952889Sbostic state->sync_offset = state->msg_in[2]; 145052889Sbostic 145152889Sbostic /* convert SCSI period to ASC period */ 145252889Sbostic i = state->msg_in[1] / 10; 145352889Sbostic if (i < ASC_MIN_PERIOD) 145452889Sbostic i = ASC_MIN_PERIOD; 145552889Sbostic else if (i >= ASC_MAX_PERIOD) { 145652889Sbostic /* can't do sync transfer, period too long */ 145752889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 145852889Sbostic asc - asc_softc, asc->target, i); 145952889Sbostic i = ASC_MAX_PERIOD; 146052889Sbostic state->sync_offset = 0; 146152889Sbostic } 146252889Sbostic if ((i * 10) != state->msg_in[1]) 146352889Sbostic i++; 146452889Sbostic state->sync_period = i & 0x1F; 146552889Sbostic 146652889Sbostic /* 146752889Sbostic * If this is a request, check minimums and 146852889Sbostic * send back an acknowledge. 146952889Sbostic */ 147052889Sbostic if (!(state->flags & TRY_SYNC)) { 147152889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 147252889Sbostic MachEmptyWriteBuffer(); 147352889Sbostic 147452889Sbostic if (state->sync_period < ASC_MIN_PERIOD) 147552889Sbostic state->sync_period = 147652889Sbostic ASC_MIN_PERIOD; 147752889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 147852889Sbostic state->sync_offset = 147952889Sbostic ASC_MAX_OFFSET; 148052889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 148152889Sbostic regs->asc_syn_p = state->sync_period; 148252889Sbostic regs->asc_syn_o = state->sync_offset; 148352889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 148452889Sbostic return (0); 148552889Sbostic } 148652889Sbostic 148752889Sbostic regs->asc_syn_p = state->sync_period; 148852889Sbostic regs->asc_syn_o = state->sync_offset; 148952889Sbostic goto done; 149052889Sbostic 149152889Sbostic default: 149252889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 149352889Sbostic asc - asc_softc, asc->target, 149452889Sbostic state->msg_in[0]); 149552889Sbostic goto reject; 149652889Sbostic } 149752889Sbostic } 149852889Sbostic 149952889Sbostic /* process first byte of a message */ 150052889Sbostic #ifdef DEBUG 150152889Sbostic if (asc_debug > 2) 150252942Sralph printf("asc_msg_in: msg %x\n", msg); 150352889Sbostic #endif 150452889Sbostic switch (msg) { 150552889Sbostic #if 0 150652889Sbostic case SCSI_MESSAGE_REJECT: 150752889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 150852889Sbostic state->flags |= DID_SYNC; 150952889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 151052889Sbostic status = asc_wait(regs, ASC_CSR_INT); 151152889Sbostic ir = regs->asc_intr; 151252889Sbostic /* some just break out here, some dont */ 151352889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 151452889Sbostic regs->asc_fifo = SCSI_ABORT; 151552889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 151652889Sbostic status = asc_wait(regs, ASC_CSR_INT); 151752889Sbostic ir = regs->asc_intr; 151852889Sbostic } 151952889Sbostic if (ir & ASC_INT_DISC) { 152052889Sbostic asc_end(asc, status, 0, ir); 152152889Sbostic return (0); 152252889Sbostic } 152352889Sbostic goto status; 152452889Sbostic #endif 152552889Sbostic 152652889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 152752889Sbostic /* setup to read message length next */ 152852889Sbostic state->msglen = -1; 152952889Sbostic state->msgcnt = 0; 153052889Sbostic return (1); 153152889Sbostic 153252889Sbostic case SCSI_NO_OP: 153352889Sbostic break; 153452889Sbostic 153552889Sbostic case SCSI_SAVE_DATA_POINTER: 153652889Sbostic /* expect another message */ 153752889Sbostic return (1); 153852889Sbostic 153952889Sbostic case SCSI_RESTORE_POINTERS: 154052889Sbostic /* 154152889Sbostic * Need to do the following if resuming synchonous data in 154252889Sbostic * on an odd byte boundary. 154352889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 154452889Sbostic */ 154552889Sbostic break; 154652889Sbostic 154752889Sbostic case SCSI_DISCONNECT: 154852889Sbostic if (state->flags & DISCONN) 154952889Sbostic goto abort; 155052889Sbostic state->flags |= DISCONN; 155152942Sralph regs->asc_cmd = ASC_CMD_MSG_ACPT; 155252942Sralph asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 155352942Sralph return (0); 155452889Sbostic 155552889Sbostic default: 155652889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 155752889Sbostic asc - asc_softc, asc->target, msg); 155852889Sbostic reject: 155952889Sbostic /* request a message out before acknowledging this message */ 156052889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 156152889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 156252889Sbostic MachEmptyWriteBuffer(); 156352889Sbostic } 156452889Sbostic 156552889Sbostic done: 156652889Sbostic /* return to original script */ 156752889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 156852889Sbostic if (!state->script) { 156952889Sbostic abort: 157052889Sbostic #ifdef DEBUG 157152942Sralph asc_DumpLog("asc_msg_in"); 157252889Sbostic #endif 157352942Sralph panic("asc_msg_in"); 157452889Sbostic } 157552889Sbostic asc->script = state->script; 157652889Sbostic state->script = (script_t *)0; 157752889Sbostic return (0); 157852889Sbostic } 157952889Sbostic 158052942Sralph /* ARGSUSED */ 158152942Sralph static int 158252942Sralph asc_disconnect(asc, status, ss, ir) 158352942Sralph register asc_softc_t asc; 158452942Sralph register int status, ss, ir; 158552942Sralph { 158652942Sralph register State *state = &asc->st[asc->target]; 158752942Sralph 158852942Sralph asc->target = -1; 158952942Sralph asc->state = ASC_STATE_RESEL; 159052942Sralph return (1); 159152942Sralph } 159252942Sralph 159352889Sbostic #ifdef DEBUG 159452889Sbostic asc_DumpLog(str) 159552889Sbostic char *str; 159652889Sbostic { 159752889Sbostic register struct asc_log *lp; 159852889Sbostic register u_int status; 159952889Sbostic 160052889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 160152889Sbostic asc_debug_bn, asc_debug_sz); 160252889Sbostic lp = asc_logp + 1; 160352889Sbostic if (lp > &asc_log[NLOG]) 160452889Sbostic lp = asc_log; 160552889Sbostic while (lp != asc_logp) { 160652889Sbostic status = lp->status; 160752889Sbostic printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 160852889Sbostic status >> 24, 160952889Sbostic lp->target, 161052889Sbostic (status >> 16) & 0xFF, 161152889Sbostic (status >> 8) & 0xFF, 161252889Sbostic status & 0XFF, 161352889Sbostic lp->state, 161452889Sbostic asc_scripts[lp->state].condition, 161552889Sbostic lp->msg); 161652889Sbostic if (++lp >= &asc_log[NLOG]) 161752889Sbostic lp = asc_log; 161852889Sbostic } 161952889Sbostic } 162052889Sbostic #endif 162152889Sbostic 162252889Sbostic #endif /* NASC > 0 */ 1623