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*52942Sralph * @(#)asc.c 7.2 (Berkeley) 03/14/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 9752889Sbostic #include "param.h" 9852889Sbostic #include "systm.h" 9952889Sbostic #include "dkstat.h" 10052889Sbostic #include "buf.h" 10152889Sbostic #include "conf.h" 10252889Sbostic #include "errno.h" 10352889Sbostic 10452889Sbostic #include "device.h" 10552889Sbostic #include "scsi.h" 10652889Sbostic #include "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 */ 12052889Sbostic #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 */ 21152889Sbostic int script_nop(); /* when nothing needed */ 21252889Sbostic int asc_end(); /* all come to an end */ 21352889Sbostic int asc_get_status(); /* get status from target */ 21452889Sbostic int asc_dma_in(); /* start reading data from target */ 21552889Sbostic int asc_last_dma_in(); /* cleanup after all data is read */ 216*52942Sralph int asc_resume_in(); /* resume data in after a message */ 21752889Sbostic int asc_resume_dma_in(); /* resume DMA after a disconnect */ 21852889Sbostic int asc_dma_out(); /* send data to target via dma */ 21952889Sbostic int asc_last_dma_out(); /* cleanup after all data is written */ 220*52942Sralph int asc_resume_out(); /* resume data out after a message */ 22152889Sbostic int asc_resume_dma_out(); /* resume DMA after a disconnect */ 22252889Sbostic int asc_sendsync(); /* negotiate sync xfer */ 22352889Sbostic int asc_replysync(); /* negotiate sync xfer */ 224*52942Sralph int asc_msg_in(); /* process a message byte */ 225*52942Sralph 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 229*52942Sralph #define SCRIPT_CONTINUE_IN 2 230*52942Sralph #define SCRIPT_DATA_OUT 3 231*52942Sralph #define SCRIPT_CONTINUE_OUT 5 232*52942Sralph #define SCRIPT_SIMPLE 6 233*52942Sralph #define SCRIPT_GET_STATUS 7 234*52942Sralph #define SCRIPT_MSG_IN 9 235*52942Sralph #define SCRIPT_REPLY_SYNC 11 23652889Sbostic #define SCRIPT_TRY_SYNC 12 237*52942Sralph #define SCRIPT_DISCONNECT 15 238*52942Sralph #define SCRIPT_RESEL 16 239*52942Sralph #define SCRIPT_RESUME_IN 17 240*52942Sralph #define SCRIPT_RESUME_DMA_IN 18 241*52942Sralph #define SCRIPT_RESUME_OUT 19 242*52942Sralph #define SCRIPT_RESUME_DMA_OUT 20 243*52942Sralph #define SCRIPT_RESUME_NO_DATA 21 24452889Sbostic 24552889Sbostic /* 24652889Sbostic * Scripts 24752889Sbostic */ 24852889Sbostic script_t asc_scripts[] = { 249*52942Sralph /* 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, 252*52942Sralph &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, 255*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 25652889Sbostic 257*52942Sralph /* continue data in after a chuck is finished */ 258*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 259*52942Sralph asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 260*52942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 261*52942Sralph 262*52942Sralph /* start data out */ 263*52942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 26452889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 265*52942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 266*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 26752889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 268*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 26952889Sbostic 270*52942Sralph /* continue data out after a chuck is finished */ 271*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 272*52942Sralph asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 273*52942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 274*52942Sralph 27552889Sbostic /* simple command with no data transfer */ 276*52942Sralph {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 27752889Sbostic script_nop, ASC_CMD_I_COMPLETE, 278*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 27952889Sbostic 28052889Sbostic /* get status and finish command */ 281*52942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 28252889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 283*52942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 284*52942Sralph {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 28552889Sbostic asc_end, ASC_CMD_NOP, 286*52942Sralph &asc_scripts[SCRIPT_GET_STATUS + 1]}, 28752889Sbostic 28852889Sbostic /* message in */ 289*52942Sralph {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 290*52942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 291*52942Sralph &asc_scripts[SCRIPT_MSG_IN + 1]}, 292*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 29352889Sbostic script_nop, ASC_CMD_XFER_INFO, 294*52942Sralph &asc_scripts[SCRIPT_MSG_IN]}, 29552889Sbostic 29652889Sbostic /* send synchonous negotiation reply */ 297*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 29852889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 299*52942Sralph &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, 304*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 30552889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 13 */ 30652889Sbostic script_nop, ASC_CMD_XFER_INFO, 307*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 30852889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 14 */ 309*52942Sralph asc_msg_in, ASC_CMD_MSG_ACPT, 310*52942Sralph &asc_scripts[SCRIPT_GET_STATUS]}, 31152889Sbostic 312*52942Sralph /* handle a disconnect */ 313*52942Sralph {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 314*52942Sralph asc_disconnect, ASC_CMD_ENABLE_SEL, 315*52942Sralph &asc_scripts[SCRIPT_RESEL]}, 316*52942Sralph 31752889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 318*52942Sralph {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 31952889Sbostic script_nop, ASC_CMD_MSG_ACPT, 320*52942Sralph &asc_scripts[SCRIPT_RESEL]}, 32152889Sbostic 322*52942Sralph /* resume data in after a message */ 323*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 324*52942Sralph asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 325*52942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 326*52942Sralph 327*52942Sralph /* resume partial DMA data in after a message */ 328*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 32952889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 330*52942Sralph &asc_scripts[SCRIPT_DATA_IN + 1]}, 33152889Sbostic 332*52942Sralph /* resume data out after a message */ 333*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 334*52942Sralph asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 335*52942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 336*52942Sralph 337*52942Sralph /* resume partial DMA data out after a message */ 338*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 33952889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 340*52942Sralph &asc_scripts[SCRIPT_DATA_OUT + 1]}, 341*52942Sralph 342*52942Sralph /* resume after a message when there is no more data */ 343*52942Sralph {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 344*52942Sralph script_nop, ASC_CMD_I_COMPLETE, 345*52942Sralph &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 */ 37252889Sbostic #define FIRST_DMA 0x02 /* true if no data DMA started yet */ 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 */ 38552889Sbostic volatile 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); 43452889Sbostic asc->buff = (volatile 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 } 60652889Sbostic asc_logp->status = PACK(asc - asc_softc, 0, 0, 0); 60752889Sbostic asc_logp->target = asc->target; 60852889Sbostic asc_logp->state = 0; 60952889Sbostic if (++asc_logp >= &asc_log[NLOG]) 61052889Sbostic asc_logp = asc_log; 61152889Sbostic #endif 61252889Sbostic 61352889Sbostic /* 61452889Sbostic * Init the chip and target state. 61552889Sbostic */ 61652889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 61752889Sbostic state->flags = FIRST_DMA | (state->flags & DID_SYNC); 61852889Sbostic state->error = 0; 61952889Sbostic state->script = (script_t *)0; 62052889Sbostic state->msg_out = SCSI_NO_OP; 62152889Sbostic 62252889Sbostic /* 62352889Sbostic * Copy command data to the DMA buffer. 62452889Sbostic */ 62552889Sbostic len = scsicmd->cmdlen; 62652889Sbostic state->dmalen = len; 62752889Sbostic bcopy(scsicmd->cmd, state->dmaBufAddr, len); 62852889Sbostic 62952889Sbostic /* check for simple SCSI command with no data transfer */ 63052889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 63152889Sbostic /* check for sync negotiation */ 63252889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 63352889Sbostic !(state->flags & DID_SYNC)) { 63452889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 63552889Sbostic state->flags |= TRY_SYNC; 63652889Sbostic } else 63752889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 63852889Sbostic state->buf = (char *)0; 63952889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 64052889Sbostic int cnt; 64152889Sbostic 64252889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 64352889Sbostic 64452889Sbostic /* setup to write first chunk */ 64552889Sbostic state->flags |= DMA_OUT; 64652889Sbostic state->buf = scsicmd->buf; 64752889Sbostic cnt = state->dmaBufSize - len; 64852889Sbostic if (cnt > state->buflen) 64952889Sbostic cnt = state->buflen; 65052889Sbostic else printf("can't write in one chunk cnt %d buflen %d\n", 65152889Sbostic cnt, state->buflen); /* XXX */ 65252889Sbostic state->dmalen = cnt; 65352889Sbostic bcopy(state->buf, state->dmaBufAddr + len, cnt); 65452889Sbostic } else { 65552889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 65652889Sbostic state->buf = scsicmd->buf; 65752889Sbostic state->flags |= DMA_IN; 65852889Sbostic } 65952889Sbostic 66052889Sbostic /* preload the FIFO with the message to be sent */ 661*52942Sralph regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 66252889Sbostic 66352889Sbostic /* start the asc */ 66452889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 66552889Sbostic ASC_TC_PUT(regs, len); 66652889Sbostic 66752889Sbostic regs->asc_dbus_id = target; 66852889Sbostic regs->asc_syn_p = state->sync_period; 66952889Sbostic regs->asc_syn_o = state->sync_offset; 67052889Sbostic 67152889Sbostic if (state->flags & TRY_SYNC) 67252889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA; 67352889Sbostic else 67452889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 67552889Sbostic } 67652889Sbostic 67752889Sbostic /* 67852889Sbostic * Interrupt routine 67952889Sbostic * Take interrupts from the chip 68052889Sbostic * 68152889Sbostic * Implementation: 68252889Sbostic * Move along the current command's script if 68352889Sbostic * all is well, invoke error handler if not. 68452889Sbostic */ 68552889Sbostic void 68652889Sbostic asc_intr(unit) 68752889Sbostic int unit; 68852889Sbostic { 68952889Sbostic register asc_softc_t asc = &asc_softc[unit]; 69052889Sbostic register asc_regmap_t *regs = asc->regs; 69152889Sbostic register State *state; 69252889Sbostic register script_t *scpt; 69352889Sbostic register int ss, ir, status; 69452889Sbostic 69552889Sbostic again: 69652889Sbostic /* collect ephemeral information */ 69752889Sbostic status = regs->asc_status; 69852889Sbostic ss = regs->asc_ss; 69952889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 70052889Sbostic scpt = asc->script; 70152889Sbostic 70252889Sbostic #ifdef DEBUG 70352889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 70452889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 70552889Sbostic asc_logp->state = scpt - asc_scripts; 70652889Sbostic asc_logp->msg = -1; 70752889Sbostic if (++asc_logp >= &asc_log[NLOG]) 70852889Sbostic asc_logp = asc_log; 70952889Sbostic if (asc_debug > 2) 71052889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 71152889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 71252889Sbostic #endif 71352889Sbostic 71452889Sbostic /* check the expected state */ 71552889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 71652889Sbostic /* 71752889Sbostic * Perform the appropriate operation, then proceed. 71852889Sbostic */ 71952889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 72052889Sbostic regs->asc_cmd = scpt->command; 72152889Sbostic asc->script = scpt->next; 72252889Sbostic } 72352889Sbostic goto done; 72452889Sbostic } 72552889Sbostic 72652889Sbostic /* check for message in or out */ 72752889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 72852889Sbostic register int len, fifo; 72952889Sbostic 73052889Sbostic state = &asc->st[asc->target]; 73152889Sbostic switch (ASC_PHASE(status)) { 73252889Sbostic case ASC_PHASE_MSG_IN: 73352889Sbostic break; 73452889Sbostic 73552889Sbostic case ASC_PHASE_MSG_OUT: 73652889Sbostic regs->asc_fifo = state->msg_out; 73752889Sbostic state->msg_out = SCSI_NO_OP; 73852889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 73952889Sbostic goto done; 74052889Sbostic 74152889Sbostic case ASC_PHASE_STATUS: 742*52942Sralph asc_DumpLog("asc_intr: status"); /* XXX */ 74352889Sbostic /* probably an error in the SCSI command */ 74452889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 74552889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 74652889Sbostic goto done; 74752889Sbostic 74852889Sbostic default: 74952889Sbostic goto abort; 75052889Sbostic } 75152889Sbostic 75252889Sbostic if (state->script) 75352889Sbostic goto abort; 75452889Sbostic 75552889Sbostic /* check for DMA in progress */ 75652889Sbostic ASC_TC_GET(regs, len); 75752889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 75852889Sbostic /* flush any data in the FIFO */ 75952889Sbostic if (fifo) { 76052889Sbostic printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n", 76152889Sbostic state->flags, state->dmalen, 76252889Sbostic len, fifo); /* XXX */ 76352889Sbostic len += fifo; 76452889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 76552889Sbostic MachEmptyWriteBuffer(); 76652889Sbostic } 76752889Sbostic if (len) { 76852889Sbostic /* save number of bytes still to be sent or received */ 76952889Sbostic state->dmaresid = len; 77052889Sbostic /* setup state to resume to */ 77152889Sbostic if (state->flags & DMA_IN) 77252889Sbostic state->script = 77352889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 77452889Sbostic else if (state->flags & DMA_OUT) 77552889Sbostic state->script = 77652889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 77752889Sbostic else 77852889Sbostic state->script = asc->script; 77952889Sbostic } else { 78052889Sbostic /* setup state to resume to */ 781*52942Sralph if (state->flags & DMA_IN) { 782*52942Sralph if (!(state->flags & FIRST_DMA)) { 783*52942Sralph len = state->dmalen; 784*52942Sralph bcopy(state->dmaBufAddr, state->buf, 785*52942Sralph len); 786*52942Sralph state->buf += len; 787*52942Sralph state->buflen -= len; 788*52942Sralph } else 789*52942Sralph state->flags &= ~FIRST_DMA; 790*52942Sralph if (state->buflen) 791*52942Sralph state->script = 792*52942Sralph &asc_scripts[SCRIPT_RESUME_IN]; 793*52942Sralph else 794*52942Sralph state->script = 795*52942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 796*52942Sralph } else if (state->flags & DMA_OUT) { 797*52942Sralph /* 798*52942Sralph * If this is the last chunk, the next expected 799*52942Sralph * state is to get status. 800*52942Sralph */ 801*52942Sralph len = state->dmalen; 802*52942Sralph state->buf += len; 803*52942Sralph state->buflen -= len; 804*52942Sralph if (state->buflen) 805*52942Sralph state->script = 806*52942Sralph &asc_scripts[SCRIPT_RESUME_OUT]; 807*52942Sralph else 808*52942Sralph state->script = 809*52942Sralph &asc_scripts[SCRIPT_RESUME_NO_DATA]; 810*52942Sralph } else 81152889Sbostic state->script = asc->script; 81252889Sbostic } 81352889Sbostic 81452889Sbostic /* setup to receive a message */ 81552889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 81652889Sbostic state->msglen = 0; 81752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 81852889Sbostic goto done; 81952889Sbostic } 82052889Sbostic 82152889Sbostic /* check for SCSI bus reset */ 82252889Sbostic if (ir & ASC_INT_RESET) { 82352889Sbostic register int i; 82452889Sbostic 82552889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 82652889Sbostic /* need to flush any pending commands */ 82752889Sbostic for (i = 0; i < ASC_NCMD; i++) { 82852889Sbostic if (!asc->cmd[i]) 82952889Sbostic continue; 83052889Sbostic asc->st[i].error = EIO; 83152889Sbostic asc_end(asc, 0, 0, 0); 83252889Sbostic } 83352889Sbostic /* rearbitrate synchronous offset */ 83452889Sbostic for (i = 0; i < ASC_NCMD; i++) { 83552889Sbostic asc->st[i].sync_offset = 0; 83652889Sbostic asc->st[i].flags = 0; 83752889Sbostic } 83852889Sbostic asc->target = -1; 83952889Sbostic return; 84052889Sbostic } 84152889Sbostic 84252889Sbostic /* check for command errors */ 84352889Sbostic if (ir & ASC_INT_ILL) 84452889Sbostic goto abort; 84552889Sbostic 84652889Sbostic /* check for disconnect */ 84752889Sbostic if (ir & ASC_INT_DISC) { 84852889Sbostic state = &asc->st[asc->target]; 84952889Sbostic switch (ASC_SS(ss)) { 85052889Sbostic case 0: /* device did not respond */ 85152889Sbostic state->error = ENXIO; 85252889Sbostic asc_end(asc, status, ss, ir); 85352889Sbostic return; 85452889Sbostic 85552889Sbostic default: 85652889Sbostic goto abort; 85752889Sbostic } 85852889Sbostic } 85952889Sbostic 86052889Sbostic /* check for reselect */ 86152889Sbostic if (ir & ASC_INT_RESEL) { 86252889Sbostic unsigned fifo, id, msg; 86352889Sbostic 86452889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 86552889Sbostic if (fifo < 2) 86652889Sbostic goto abort; 86752889Sbostic /* read unencoded SCSI ID and convert to binary */ 86852889Sbostic msg = regs->asc_fifo & asc->myidmask; 86952889Sbostic for (id = 0; (msg & 1) == 0; id++) 87052889Sbostic msg >>= 1; 87152889Sbostic /* read identify message */ 87252889Sbostic msg = regs->asc_fifo; 87352889Sbostic #ifdef DEBUG 87452889Sbostic if (asc_logp == asc_log) 87552889Sbostic asc_log[NLOG - 1].msg = msg; 87652889Sbostic else 87752889Sbostic asc_logp[-1].msg = msg; 87852889Sbostic #endif 87952889Sbostic if (asc->state != ASC_STATE_RESEL) 88052889Sbostic goto abort; 88152889Sbostic asc->state = ASC_STATE_BUSY; 88252889Sbostic asc->target = id; 88352889Sbostic state = &asc->st[id]; 88452889Sbostic asc->script = state->script; 88552889Sbostic state->script = (script_t *)0; 88652889Sbostic if (!(state->flags & DISCONN)) 88752889Sbostic goto abort; 88852889Sbostic state->flags &= ~DISCONN; 88952889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 89052889Sbostic goto done; 89152889Sbostic } 89252889Sbostic 89352889Sbostic /* check if we are being selected as a target */ 89452889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 89552889Sbostic goto abort; 89652889Sbostic 89752889Sbostic /* must be just a ASC_INT_FC */ 89852889Sbostic done: 89952889Sbostic MachEmptyWriteBuffer(); 90052889Sbostic if (regs->asc_status & ASC_CSR_INT) 90152889Sbostic goto again; 90252889Sbostic return; 90352889Sbostic 90452889Sbostic abort: 90552889Sbostic #ifdef DEBUG 90652889Sbostic asc_DumpLog("asc_intr"); 90752889Sbostic #endif 90852889Sbostic #if 0 90952889Sbostic panic("asc_intr"); 91052889Sbostic #else 91152889Sbostic for (;;); 91252889Sbostic #endif 91352889Sbostic } 91452889Sbostic 91552889Sbostic /* 91652889Sbostic * All the many little things that the interrupt 91752889Sbostic * routine might switch to. 91852889Sbostic */ 91952889Sbostic 92052889Sbostic /* ARGSUSED */ 92152889Sbostic static int 92252889Sbostic script_nop(asc, status, ss, ir) 92352889Sbostic register asc_softc_t asc; 92452889Sbostic register int status, ss, ir; 92552889Sbostic { 92652889Sbostic return (1); 92752889Sbostic } 92852889Sbostic 92952889Sbostic /* ARGSUSED */ 93052889Sbostic static int 93152889Sbostic asc_get_status(asc, status, ss, ir) 93252889Sbostic register asc_softc_t asc; 93352889Sbostic register int status, ss, ir; 93452889Sbostic { 93552889Sbostic register asc_regmap_t *regs = asc->regs; 93652889Sbostic register int data; 93752889Sbostic 93852889Sbostic /* 93952889Sbostic * Get the last two bytes in the FIFO. 94052889Sbostic */ 94152889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 94252889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 94352889Sbostic if (data < 2) { 94452889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 94552889Sbostic return (0); 94652889Sbostic } 94752889Sbostic do { 94852889Sbostic data = regs->asc_fifo; 94952889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 95052889Sbostic } 95152889Sbostic 95252889Sbostic /* save the status byte */ 95352889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 95452889Sbostic #ifdef DEBUG 95552889Sbostic if (asc_logp == asc_log) 95652889Sbostic asc_log[NLOG - 1].msg = data; 95752889Sbostic else 95852889Sbostic asc_logp[-1].msg = data; 95952889Sbostic #endif 96052889Sbostic 96152889Sbostic /* get the (presumed) command_complete message */ 96252889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 96352889Sbostic return (1); 96452889Sbostic 96552889Sbostic #ifdef DEBUG 96652889Sbostic printf("asc_get_status: status %x cmd %x\n", 96752889Sbostic asc->st[asc->target].statusByte, data); 96852889Sbostic asc_DumpLog("asc_get_status"); 96952889Sbostic #endif 97052889Sbostic return (0); 97152889Sbostic } 97252889Sbostic 97352889Sbostic /* ARGSUSED */ 97452889Sbostic static int 97552889Sbostic asc_end(asc, status, ss, ir) 97652889Sbostic register asc_softc_t asc; 97752889Sbostic register int status, ss, ir; 97852889Sbostic { 97952889Sbostic register ScsiCmd *scsicmd; 98052889Sbostic register State *state; 98152889Sbostic register int i, target; 98252889Sbostic 98352889Sbostic asc->state = ASC_STATE_IDLE; 98452889Sbostic target = asc->target; 98552889Sbostic asc->target = -1; 98652889Sbostic scsicmd = asc->cmd[target]; 98752889Sbostic asc->cmd[target] = (ScsiCmd *)0; 98852889Sbostic state = &asc->st[target]; 98952889Sbostic 99052889Sbostic #ifdef DEBUG 99152889Sbostic if (asc_debug > 1) { 99252889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 99352889Sbostic scsicmd->sd->sd_driver->d_name, target, 99452889Sbostic scsicmd->cmd[0], state->error, state->buflen); 99552889Sbostic } 99652889Sbostic #endif 99752889Sbostic #ifdef DIAGNOSTIC 99852889Sbostic if (target < 0 || !scsicmd) 99952889Sbostic panic("asc_end"); 100052889Sbostic #endif 100152889Sbostic 100252889Sbostic /* look for disconnected devices */ 100352889Sbostic for (i = 0; i < ASC_NCMD; i++) { 100452889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 100552889Sbostic continue; 100652889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 100752889Sbostic asc->state = ASC_STATE_RESEL; 100852889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 100952889Sbostic break; 101052889Sbostic } 101152889Sbostic 101252889Sbostic /* look for another device that is ready */ 101352889Sbostic for (i = 0; i < ASC_NCMD; i++) { 101452889Sbostic /* don't restart a disconnected command */ 101552889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 101652889Sbostic continue; 101752889Sbostic asc_startcmd(asc, i); 101852889Sbostic break; 101952889Sbostic } 102052889Sbostic 102152889Sbostic /* signal device driver that the command is done */ 102252889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 102352889Sbostic state->buflen, state->statusByte); 102452889Sbostic 102552889Sbostic return (0); 102652889Sbostic } 102752889Sbostic 102852889Sbostic /* ARGSUSED */ 102952889Sbostic static int 103052889Sbostic asc_dma_in(asc, status, ss, ir) 103152889Sbostic register asc_softc_t asc; 103252889Sbostic register int status, ss, ir; 103352889Sbostic { 103452889Sbostic register asc_regmap_t *regs = asc->regs; 103552889Sbostic register State *state = &asc->st[asc->target]; 103652889Sbostic register int len, fifo; 103752889Sbostic 103852889Sbostic /* check for previous chunk in buffer */ 103952889Sbostic if (!(state->flags & FIRST_DMA)) { 104052889Sbostic /* 104152889Sbostic * Only count bytes that have been copied to memory. 104252889Sbostic * There may be some bytes in the FIFO if synchonous transfers 104352889Sbostic * are in progress. 104452889Sbostic */ 104552889Sbostic ASC_TC_GET(regs, len); 104652889Sbostic len = state->dmalen - len; 104752889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 104852889Sbostic state->buf += len; 104952889Sbostic state->buflen -= len; 105052889Sbostic } else 105152889Sbostic state->flags &= ~FIRST_DMA; 105252889Sbostic 1053*52942Sralph /* setup to start reading the next chunk */ 105452889Sbostic len = state->buflen; 105552889Sbostic if (len > state->dmaBufSize) 105652889Sbostic len = state->dmaBufSize; 105752889Sbostic state->dmalen = len; 105852889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 105952889Sbostic ASC_TC_PUT(regs, len); 1060*52942Sralph #ifdef DEBUG 1061*52942Sralph if (asc_debug > 2) 1062*52942Sralph printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1063*52942Sralph #endif 1064*52942Sralph 1065*52942Sralph /* check for next chunk */ 106652889Sbostic if (len != state->buflen) { 106752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1068*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 106952889Sbostic return (0); 107052889Sbostic } 107152889Sbostic return (1); 107252889Sbostic } 107352889Sbostic 107452889Sbostic /* ARGSUSED */ 107552889Sbostic static int 107652889Sbostic asc_last_dma_in(asc, status, ss, ir) 107752889Sbostic register asc_softc_t asc; 107852889Sbostic register int status, ss, ir; 107952889Sbostic { 108052889Sbostic register asc_regmap_t *regs = asc->regs; 108152889Sbostic register State *state = &asc->st[asc->target]; 108252889Sbostic register int len, fifo; 108352889Sbostic 108452889Sbostic /* copy data from buffer to main memory */ 108552889Sbostic ASC_TC_GET(regs, len); 108652889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 108752889Sbostic #ifdef DEBUG 1088*52942Sralph #if 0 1089*52942Sralph if (asc_debug > 2) 1090*52942Sralph #else 109152889Sbostic if (asc_debug > 2 || len || fifo) /* XXX */ 1092*52942Sralph #endif 109352889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 109452889Sbostic state->buflen, state->dmalen, len, fifo); 109552889Sbostic #endif 109652889Sbostic if (fifo) { 1097*52942Sralph /* device must be trying to send more than we expect */ 109852889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 109952889Sbostic MachEmptyWriteBuffer(); 110052889Sbostic } 110152889Sbostic len = state->dmalen - len; 110252889Sbostic state->buflen -= len; 110352889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 110452889Sbostic 110552889Sbostic return (1); 110652889Sbostic } 110752889Sbostic 110852889Sbostic /* ARGSUSED */ 110952889Sbostic static int 1110*52942Sralph asc_resume_in(asc, status, ss, ir) 1111*52942Sralph register asc_softc_t asc; 1112*52942Sralph register int status, ss, ir; 1113*52942Sralph { 1114*52942Sralph register asc_regmap_t *regs = asc->regs; 1115*52942Sralph register State *state = &asc->st[asc->target]; 1116*52942Sralph register int len; 1117*52942Sralph 1118*52942Sralph /* setup to start reading the next chunk */ 1119*52942Sralph len = state->buflen; 1120*52942Sralph if (len > state->dmaBufSize) 1121*52942Sralph len = state->dmaBufSize; 1122*52942Sralph state->dmalen = len; 1123*52942Sralph *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 1124*52942Sralph ASC_TC_PUT(regs, len); 1125*52942Sralph #ifdef DEBUG 1126*52942Sralph if (asc_debug > 2) 1127*52942Sralph printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1128*52942Sralph len); 1129*52942Sralph #endif 1130*52942Sralph 1131*52942Sralph /* check for next chunk */ 1132*52942Sralph if (len != state->buflen) { 1133*52942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1134*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1135*52942Sralph return (0); 1136*52942Sralph } 1137*52942Sralph return (1); 1138*52942Sralph } 1139*52942Sralph 1140*52942Sralph /* ARGSUSED */ 1141*52942Sralph static int 114252889Sbostic asc_resume_dma_in(asc, status, ss, ir) 114352889Sbostic register asc_softc_t asc; 114452889Sbostic register int status, ss, ir; 114552889Sbostic { 114652889Sbostic register asc_regmap_t *regs = asc->regs; 114752889Sbostic register State *state = &asc->st[asc->target]; 114852889Sbostic register int len, off; 114952889Sbostic 115052889Sbostic /* setup to finish reading the current chunk */ 115152889Sbostic len = state->dmaresid; 115252889Sbostic off = state->dmalen - len; 115352889Sbostic if ((off & 1) && state->sync_offset) { 115452889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 115552889Sbostic state->dmalen, len, off); /* XXX */ 115652889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 115752889Sbostic } 115852889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off); 115952889Sbostic ASC_TC_PUT(regs, len); 1160*52942Sralph #ifdef DEBUG 1161*52942Sralph if (asc_debug > 2) 1162*52942Sralph printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1163*52942Sralph state->dmalen, state->buflen, len, off); 1164*52942Sralph #endif 1165*52942Sralph 1166*52942Sralph /* check for next chunk */ 116752889Sbostic if (state->dmalen != state->buflen) { 116852889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1169*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 117052889Sbostic return (0); 117152889Sbostic } 117252889Sbostic return (1); 117352889Sbostic } 117452889Sbostic 117552889Sbostic /* ARGSUSED */ 117652889Sbostic static int 117752889Sbostic asc_dma_out(asc, status, ss, ir) 117852889Sbostic register asc_softc_t asc; 117952889Sbostic register int status, ss, ir; 118052889Sbostic { 118152889Sbostic register asc_regmap_t *regs = asc->regs; 118252889Sbostic register State *state = &asc->st[asc->target]; 118352889Sbostic register int len, fifo; 118452889Sbostic 118552889Sbostic if (!(state->flags & FIRST_DMA)) { 118652889Sbostic /* check to be sure previous chunk was finished */ 118752889Sbostic ASC_TC_GET(regs, len); 118852889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 118952889Sbostic if (len || fifo) 119052889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 119152889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 119252889Sbostic len += fifo; 119352889Sbostic len = state->dmalen - len; 119452889Sbostic state->buflen -= len; 119552889Sbostic state->buf += len; 119652889Sbostic 119752889Sbostic /* setup for this chunck */ 119852889Sbostic len = state->buflen; 119952889Sbostic if (len > state->dmaBufSize) 120052889Sbostic len = state->dmaBufSize; 120152889Sbostic state->dmalen = len; 120252889Sbostic bcopy(state->buf, state->dmaBufAddr, len); 120352889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 120452889Sbostic } else 120552889Sbostic state->flags &= ~FIRST_DMA; 120652889Sbostic 1207*52942Sralph len = state->dmalen; 1208*52942Sralph ASC_TC_PUT(regs, len); 120952889Sbostic #ifdef DEBUG 121052889Sbostic if (asc_debug > 2) 1211*52942Sralph printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 121252889Sbostic #endif 121352889Sbostic 121452889Sbostic /* check for next chunk */ 121552889Sbostic if (len != state->buflen) { 121652889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1217*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 121852889Sbostic return (0); 121952889Sbostic } 122052889Sbostic return (1); 122152889Sbostic } 122252889Sbostic 122352889Sbostic /* ARGSUSED */ 122452889Sbostic static int 122552889Sbostic asc_last_dma_out(asc, status, ss, ir) 122652889Sbostic register asc_softc_t asc; 122752889Sbostic register int status, ss, ir; 122852889Sbostic { 122952889Sbostic register asc_regmap_t *regs = asc->regs; 123052889Sbostic register State *state = &asc->st[asc->target]; 123152889Sbostic register int len, fifo; 123252889Sbostic 123352889Sbostic ASC_TC_GET(regs, len); 123452889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 123552889Sbostic #ifdef DEBUG 1236*52942Sralph #if 0 123752889Sbostic if (asc_debug > 2) 1238*52942Sralph #else 1239*52942Sralph if (asc_debug > 2 || len || fifo) /* XXX */ 124052889Sbostic #endif 124152889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 124252889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 1243*52942Sralph #endif 1244*52942Sralph if (fifo) { 1245*52942Sralph len += fifo; 1246*52942Sralph regs->asc_cmd = ASC_CMD_FLUSH; 1247*52942Sralph MachEmptyWriteBuffer(); 1248*52942Sralph } 124952889Sbostic len = state->dmalen - len; 125052889Sbostic state->buflen -= len; 125152889Sbostic return (1); 125252889Sbostic } 125352889Sbostic 125452889Sbostic /* ARGSUSED */ 125552889Sbostic static int 1256*52942Sralph asc_resume_out(asc, status, ss, ir) 1257*52942Sralph register asc_softc_t asc; 1258*52942Sralph register int status, ss, ir; 1259*52942Sralph { 1260*52942Sralph register asc_regmap_t *regs = asc->regs; 1261*52942Sralph register State *state = &asc->st[asc->target]; 1262*52942Sralph register int len; 1263*52942Sralph 1264*52942Sralph /* setup for this chunck */ 1265*52942Sralph len = state->buflen; 1266*52942Sralph if (len > state->dmaBufSize) 1267*52942Sralph len = state->dmaBufSize; 1268*52942Sralph state->dmalen = len; 1269*52942Sralph bcopy(state->buf, state->dmaBufAddr, len); 1270*52942Sralph *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 1271*52942Sralph ASC_TC_PUT(regs, len); 1272*52942Sralph #ifdef DEBUG 1273*52942Sralph if (asc_debug > 2) 1274*52942Sralph printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1275*52942Sralph len); 1276*52942Sralph #endif 1277*52942Sralph 1278*52942Sralph /* check for next chunk */ 1279*52942Sralph if (len != state->buflen) { 1280*52942Sralph regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1281*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1282*52942Sralph return (0); 1283*52942Sralph } 1284*52942Sralph return (1); 1285*52942Sralph } 1286*52942Sralph 1287*52942Sralph /* ARGSUSED */ 1288*52942Sralph static int 128952889Sbostic asc_resume_dma_out(asc, status, ss, ir) 129052889Sbostic register asc_softc_t asc; 129152889Sbostic register int status, ss, ir; 129252889Sbostic { 129352889Sbostic register asc_regmap_t *regs = asc->regs; 129452889Sbostic register State *state = &asc->st[asc->target]; 129552889Sbostic register int len, off; 129652889Sbostic 129752889Sbostic /* setup to finish writing this chunk */ 129852889Sbostic len = state->dmaresid; 129952889Sbostic off = state->dmalen - len; 130052889Sbostic if (off & 1) { 130152889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 130252889Sbostic state->dmalen, len, off); /* XXX */ 130352889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 130452889Sbostic off++; 130552889Sbostic len--; 130652889Sbostic } 130752889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off); 130852889Sbostic ASC_TC_PUT(regs, len); 1309*52942Sralph #ifdef DEBUG 1310*52942Sralph if (asc_debug > 2) 1311*52942Sralph printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1312*52942Sralph state->dmalen, state->buflen, len, off); 1313*52942Sralph #endif 1314*52942Sralph 1315*52942Sralph /* check for next chunk */ 131652889Sbostic if (state->dmalen != state->buflen) { 131752889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1318*52942Sralph asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 131952889Sbostic return (0); 132052889Sbostic } 132152889Sbostic return (1); 132252889Sbostic } 132352889Sbostic 132452889Sbostic /* ARGSUSED */ 132552889Sbostic static int 132652889Sbostic asc_sendsync(asc, status, ss, ir) 132752889Sbostic register asc_softc_t asc; 132852889Sbostic register int status, ss, ir; 132952889Sbostic { 133052889Sbostic register asc_regmap_t *regs = asc->regs; 133152889Sbostic 133252889Sbostic /* 133352889Sbostic * Phase is MSG_OUT here. 133452889Sbostic * Try sync negotiation, unless prohibited 133552889Sbostic */ 133652889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 133752889Sbostic MachEmptyWriteBuffer(); 133852889Sbostic regs->asc_fifo = 3; 133952889Sbostic MachEmptyWriteBuffer(); 134052889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 134152889Sbostic MachEmptyWriteBuffer(); 134252889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 134352889Sbostic MachEmptyWriteBuffer(); 134452889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 134552889Sbostic return (1); 134652889Sbostic } 134752889Sbostic 134852889Sbostic /* ARGSUSED */ 134952889Sbostic static int 135052889Sbostic asc_replysync(asc, status, ss, ir) 135152889Sbostic register asc_softc_t asc; 135252889Sbostic register int status, ss, ir; 135352889Sbostic { 135452889Sbostic register asc_regmap_t *regs = asc->regs; 135552889Sbostic register State *state = &asc->st[asc->target]; 135652889Sbostic 135752889Sbostic #ifdef DEBUG 135852889Sbostic if (asc_debug > 2) 135952889Sbostic printf("asc_replysync: %x %x\n", 136052889Sbostic asc_to_scsi_period[state->sync_period], 136152889Sbostic state->sync_offset); 136252889Sbostic #endif 136352889Sbostic /* send synchronous transfer in response to a request */ 136452889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 136552889Sbostic MachEmptyWriteBuffer(); 136652889Sbostic regs->asc_fifo = 3; 136752889Sbostic MachEmptyWriteBuffer(); 136852889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 136952889Sbostic MachEmptyWriteBuffer(); 137052889Sbostic regs->asc_fifo = asc_to_scsi_period[state->sync_period]; 137152889Sbostic MachEmptyWriteBuffer(); 137252889Sbostic regs->asc_fifo = state->sync_offset; 137352889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 137452889Sbostic 137552889Sbostic /* return to the appropriate script */ 137652889Sbostic if (!state->script) { 137752889Sbostic #ifdef DEBUG 137852889Sbostic asc_DumpLog("asc_replsync"); 137952889Sbostic #endif 138052889Sbostic panic("asc_replysync"); 138152889Sbostic } 138252889Sbostic asc->script = state->script; 138352889Sbostic state->script = (script_t *)0; 138452889Sbostic return (0); 138552889Sbostic } 138652889Sbostic 138752889Sbostic /* ARGSUSED */ 138852889Sbostic static int 1389*52942Sralph asc_msg_in(asc, status, ss, ir) 139052889Sbostic register asc_softc_t asc; 139152889Sbostic register int status, ss, ir; 139252889Sbostic { 139352889Sbostic register asc_regmap_t *regs = asc->regs; 139452889Sbostic register State *state = &asc->st[asc->target]; 139552889Sbostic register int msg; 139652889Sbostic int i; 139752889Sbostic 139852889Sbostic /* read one message byte */ 139952889Sbostic msg = regs->asc_fifo; 140052889Sbostic #ifdef DEBUG 140152889Sbostic if (asc_logp == asc_log) 140252889Sbostic asc_log[NLOG - 1].msg = msg; 140352889Sbostic else 140452889Sbostic asc_logp[-1].msg = msg; 140552889Sbostic #endif 140652889Sbostic 140752889Sbostic /* check for multi-byte message */ 140852889Sbostic if (state->msglen != 0) { 140952889Sbostic /* first byte is the message length */ 141052889Sbostic if (state->msglen < 0) { 141152889Sbostic state->msglen = msg; 141252889Sbostic return (1); 141352889Sbostic } 141452889Sbostic if (state->msgcnt >= state->msglen) 141552889Sbostic goto abort; 141652889Sbostic state->msg_in[state->msgcnt++] = msg; 141752889Sbostic 141852889Sbostic /* did we just read the last byte of the message? */ 141952889Sbostic if (state->msgcnt != state->msglen) 142052889Sbostic return (1); 142152889Sbostic 142252889Sbostic /* process an extended message */ 142352889Sbostic #ifdef DEBUG 142452889Sbostic if (asc_debug > 2) 1425*52942Sralph printf("asc_msg_in: msg %x %x %x\n", 142652889Sbostic state->msg_in[0], 142752889Sbostic state->msg_in[1], 142852889Sbostic state->msg_in[2]); 142952889Sbostic #endif 143052889Sbostic switch (state->msg_in[0]) { 143152889Sbostic case SCSI_SYNCHRONOUS_XFER: 143252889Sbostic state->flags |= DID_SYNC; 143352889Sbostic state->sync_offset = state->msg_in[2]; 143452889Sbostic 143552889Sbostic /* convert SCSI period to ASC period */ 143652889Sbostic i = state->msg_in[1] / 10; 143752889Sbostic if (i < ASC_MIN_PERIOD) 143852889Sbostic i = ASC_MIN_PERIOD; 143952889Sbostic else if (i >= ASC_MAX_PERIOD) { 144052889Sbostic /* can't do sync transfer, period too long */ 144152889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 144252889Sbostic asc - asc_softc, asc->target, i); 144352889Sbostic i = ASC_MAX_PERIOD; 144452889Sbostic state->sync_offset = 0; 144552889Sbostic } 144652889Sbostic if ((i * 10) != state->msg_in[1]) 144752889Sbostic i++; 144852889Sbostic state->sync_period = i & 0x1F; 144952889Sbostic 145052889Sbostic /* 145152889Sbostic * If this is a request, check minimums and 145252889Sbostic * send back an acknowledge. 145352889Sbostic */ 145452889Sbostic if (!(state->flags & TRY_SYNC)) { 145552889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 145652889Sbostic MachEmptyWriteBuffer(); 145752889Sbostic 145852889Sbostic if (state->sync_period < ASC_MIN_PERIOD) 145952889Sbostic state->sync_period = 146052889Sbostic ASC_MIN_PERIOD; 146152889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 146252889Sbostic state->sync_offset = 146352889Sbostic ASC_MAX_OFFSET; 146452889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 146552889Sbostic regs->asc_syn_p = state->sync_period; 146652889Sbostic regs->asc_syn_o = state->sync_offset; 146752889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 146852889Sbostic return (0); 146952889Sbostic } 147052889Sbostic 147152889Sbostic regs->asc_syn_p = state->sync_period; 147252889Sbostic regs->asc_syn_o = state->sync_offset; 147352889Sbostic goto done; 147452889Sbostic 147552889Sbostic default: 147652889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 147752889Sbostic asc - asc_softc, asc->target, 147852889Sbostic state->msg_in[0]); 147952889Sbostic goto reject; 148052889Sbostic } 148152889Sbostic } 148252889Sbostic 148352889Sbostic /* process first byte of a message */ 148452889Sbostic #ifdef DEBUG 148552889Sbostic if (asc_debug > 2) 1486*52942Sralph printf("asc_msg_in: msg %x\n", msg); 148752889Sbostic #endif 148852889Sbostic switch (msg) { 148952889Sbostic #if 0 149052889Sbostic case SCSI_MESSAGE_REJECT: 149152889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 149252889Sbostic state->flags |= DID_SYNC; 149352889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 149452889Sbostic status = asc_wait(regs, ASC_CSR_INT); 149552889Sbostic ir = regs->asc_intr; 149652889Sbostic /* some just break out here, some dont */ 149752889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 149852889Sbostic regs->asc_fifo = SCSI_ABORT; 149952889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 150052889Sbostic status = asc_wait(regs, ASC_CSR_INT); 150152889Sbostic ir = regs->asc_intr; 150252889Sbostic } 150352889Sbostic if (ir & ASC_INT_DISC) { 150452889Sbostic asc_end(asc, status, 0, ir); 150552889Sbostic return (0); 150652889Sbostic } 150752889Sbostic goto status; 150852889Sbostic #endif 150952889Sbostic 151052889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 151152889Sbostic /* setup to read message length next */ 151252889Sbostic state->msglen = -1; 151352889Sbostic state->msgcnt = 0; 151452889Sbostic return (1); 151552889Sbostic 151652889Sbostic case SCSI_NO_OP: 151752889Sbostic break; 151852889Sbostic 151952889Sbostic case SCSI_SAVE_DATA_POINTER: 152052889Sbostic /* expect another message */ 152152889Sbostic return (1); 152252889Sbostic 152352889Sbostic case SCSI_RESTORE_POINTERS: 152452889Sbostic /* 152552889Sbostic * Need to do the following if resuming synchonous data in 152652889Sbostic * on an odd byte boundary. 152752889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 152852889Sbostic */ 152952889Sbostic break; 153052889Sbostic 153152889Sbostic case SCSI_DISCONNECT: 153252889Sbostic if (state->flags & DISCONN) 153352889Sbostic goto abort; 153452889Sbostic state->flags |= DISCONN; 1535*52942Sralph regs->asc_cmd = ASC_CMD_MSG_ACPT; 1536*52942Sralph asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1537*52942Sralph return (0); 153852889Sbostic 153952889Sbostic default: 154052889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 154152889Sbostic asc - asc_softc, asc->target, msg); 154252889Sbostic reject: 154352889Sbostic /* request a message out before acknowledging this message */ 154452889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 154552889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 154652889Sbostic MachEmptyWriteBuffer(); 154752889Sbostic } 154852889Sbostic 154952889Sbostic done: 155052889Sbostic /* return to original script */ 155152889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 155252889Sbostic if (!state->script) { 155352889Sbostic abort: 155452889Sbostic #ifdef DEBUG 1555*52942Sralph asc_DumpLog("asc_msg_in"); 155652889Sbostic #endif 1557*52942Sralph panic("asc_msg_in"); 155852889Sbostic } 155952889Sbostic asc->script = state->script; 156052889Sbostic state->script = (script_t *)0; 156152889Sbostic return (0); 156252889Sbostic } 156352889Sbostic 1564*52942Sralph /* ARGSUSED */ 1565*52942Sralph static int 1566*52942Sralph asc_disconnect(asc, status, ss, ir) 1567*52942Sralph register asc_softc_t asc; 1568*52942Sralph register int status, ss, ir; 1569*52942Sralph { 1570*52942Sralph register State *state = &asc->st[asc->target]; 1571*52942Sralph 1572*52942Sralph asc->target = -1; 1573*52942Sralph asc->state = ASC_STATE_RESEL; 1574*52942Sralph return (1); 1575*52942Sralph } 1576*52942Sralph 157752889Sbostic #ifdef DEBUG 157852889Sbostic asc_DumpLog(str) 157952889Sbostic char *str; 158052889Sbostic { 158152889Sbostic register struct asc_log *lp; 158252889Sbostic register u_int status; 158352889Sbostic 158452889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 158552889Sbostic asc_debug_bn, asc_debug_sz); 158652889Sbostic lp = asc_logp + 1; 158752889Sbostic if (lp > &asc_log[NLOG]) 158852889Sbostic lp = asc_log; 158952889Sbostic while (lp != asc_logp) { 159052889Sbostic status = lp->status; 159152889Sbostic printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 159252889Sbostic status >> 24, 159352889Sbostic lp->target, 159452889Sbostic (status >> 16) & 0xFF, 159552889Sbostic (status >> 8) & 0xFF, 159652889Sbostic status & 0XFF, 159752889Sbostic lp->state, 159852889Sbostic asc_scripts[lp->state].condition, 159952889Sbostic lp->msg); 160052889Sbostic if (++lp >= &asc_log[NLOG]) 160152889Sbostic lp = asc_log; 160252889Sbostic } 160352889Sbostic } 160452889Sbostic #endif 160552889Sbostic 160652889Sbostic #endif /* NASC > 0 */ 1607