1*52889Sbostic /*- 2*52889Sbostic * Copyright (c) 1992 The Regents of the University of California. 3*52889Sbostic * All rights reserved. 4*52889Sbostic * 5*52889Sbostic * This code is derived from software contributed to Berkeley by 6*52889Sbostic * Ralph Campbell. 7*52889Sbostic * 8*52889Sbostic * %sccs.include.redist.c% 9*52889Sbostic * 10*52889Sbostic * @(#)asc.c 7.1 (Berkeley) 03/09/92 11*52889Sbostic */ 12*52889Sbostic 13*52889Sbostic /* 14*52889Sbostic * Mach Operating System 15*52889Sbostic * Copyright (c) 1991,1990,1989 Carnegie Mellon University 16*52889Sbostic * All Rights Reserved. 17*52889Sbostic * 18*52889Sbostic * Permission to use, copy, modify and distribute this software and its 19*52889Sbostic * documentation is hereby granted, provided that both the copyright 20*52889Sbostic * notice and this permission notice appear in all copies of the 21*52889Sbostic * software, derivative works or modified versions, and any portions 22*52889Sbostic * thereof, and that both notices appear in supporting documentation. 23*52889Sbostic * 24*52889Sbostic * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 25*52889Sbostic * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26*52889Sbostic * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27*52889Sbostic * 28*52889Sbostic * Carnegie Mellon requests users of this software to return to 29*52889Sbostic * 30*52889Sbostic * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31*52889Sbostic * School of Computer Science 32*52889Sbostic * Carnegie Mellon University 33*52889Sbostic * Pittsburgh PA 15213-3890 34*52889Sbostic * 35*52889Sbostic * any improvements or extensions that they make and grant Carnegie the 36*52889Sbostic * rights to redistribute these changes. 37*52889Sbostic */ 38*52889Sbostic 39*52889Sbostic /* 40*52889Sbostic * HISTORY 41*52889Sbostic * $Log: scsi_53C94_hdw.c,v $ 42*52889Sbostic * Revision 2.5 91/02/05 17:45:07 mrt 43*52889Sbostic * Added author notices 44*52889Sbostic * [91/02/04 11:18:43 mrt] 45*52889Sbostic * 46*52889Sbostic * Changed to use new Mach copyright 47*52889Sbostic * [91/02/02 12:17:20 mrt] 48*52889Sbostic * 49*52889Sbostic * Revision 2.4 91/01/08 15:48:24 rpd 50*52889Sbostic * Added continuation argument to thread_block. 51*52889Sbostic * [90/12/27 rpd] 52*52889Sbostic * 53*52889Sbostic * Revision 2.3 90/12/05 23:34:48 af 54*52889Sbostic * Recovered from pmax merge.. and from the destruction of a disk. 55*52889Sbostic * [90/12/03 23:40:40 af] 56*52889Sbostic * 57*52889Sbostic * Revision 2.1.1.1 90/11/01 03:39:09 af 58*52889Sbostic * Created, from the DEC specs: 59*52889Sbostic * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" 60*52889Sbostic * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. 61*52889Sbostic * And from the NCR data sheets 62*52889Sbostic * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" 63*52889Sbostic * [90/09/03 af] 64*52889Sbostic */ 65*52889Sbostic 66*52889Sbostic /* 67*52889Sbostic * File: scsi_53C94_hdw.h 68*52889Sbostic * Author: Alessandro Forin, Carnegie Mellon University 69*52889Sbostic * Date: 9/90 70*52889Sbostic * 71*52889Sbostic * Bottom layer of the SCSI driver: chip-dependent functions 72*52889Sbostic * 73*52889Sbostic * This file contains the code that is specific to the NCR 53C94 74*52889Sbostic * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start 75*52889Sbostic * operation, and interrupt routine. 76*52889Sbostic */ 77*52889Sbostic 78*52889Sbostic /* 79*52889Sbostic * This layer works based on small simple 'scripts' that are installed 80*52889Sbostic * at the start of the command and drive the chip to completion. 81*52889Sbostic * The idea comes from the specs of the NCR 53C700 'script' processor. 82*52889Sbostic * 83*52889Sbostic * There are various reasons for this, mainly 84*52889Sbostic * - Performance: identify the common (successful) path, and follow it; 85*52889Sbostic * at interrupt time no code is needed to find the current status 86*52889Sbostic * - Code size: it should be easy to compact common operations 87*52889Sbostic * - Adaptability: the code skeleton should adapt to different chips without 88*52889Sbostic * terrible complications. 89*52889Sbostic * - Error handling: and it is easy to modify the actions performed 90*52889Sbostic * by the scripts to cope with strange but well identified sequences 91*52889Sbostic * 92*52889Sbostic */ 93*52889Sbostic 94*52889Sbostic #include "asc.h" 95*52889Sbostic #if NASC > 0 96*52889Sbostic 97*52889Sbostic #include "param.h" 98*52889Sbostic #include "systm.h" 99*52889Sbostic #include "dkstat.h" 100*52889Sbostic #include "buf.h" 101*52889Sbostic #include "conf.h" 102*52889Sbostic #include "errno.h" 103*52889Sbostic 104*52889Sbostic #include "device.h" 105*52889Sbostic #include "scsi.h" 106*52889Sbostic #include "ascreg.h" 107*52889Sbostic 108*52889Sbostic #define ASC_OFFSET_53C94 0x0 /* from module base */ 109*52889Sbostic #define ASC_OFFSET_DMAR 0x40000 /* DMA Address Register */ 110*52889Sbostic #define ASC_OFFSET_RAM 0x80000 /* SRAM Buffer */ 111*52889Sbostic #define ASC_OFFSET_ROM 0xc0000 /* Diagnostic ROM */ 112*52889Sbostic 113*52889Sbostic #define ASC_RAM_SIZE 0x20000 /* 128k (32k*32) */ 114*52889Sbostic 115*52889Sbostic /* 116*52889Sbostic * DMA Address Register 117*52889Sbostic */ 118*52889Sbostic #define ASC_DMAR_MASK 0x1ffff /* 17 bits, 128k */ 119*52889Sbostic #define ASC_DMAR_WRITE 0x80000000 /* DMA direction bit */ 120*52889Sbostic #define ASC_DMA_ADDR(x) ((unsigned)(x)) & ASC_DMAR_MASK 121*52889Sbostic 122*52889Sbostic /* 123*52889Sbostic * Synch xfer parameters, and timing conversions 124*52889Sbostic */ 125*52889Sbostic #define SCSI_MIN_PERIOD 50 /* in 4 nsecs units */ 126*52889Sbostic #define ASC_MIN_PERIOD 5 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 127*52889Sbostic #define ASC_MAX_PERIOD 35 /* in CLKS/BYTE, 1 CLK = 40nsecs */ 128*52889Sbostic #define ASC_MAX_OFFSET 15 /* pure number */ 129*52889Sbostic 130*52889Sbostic int asc_to_scsi_period[] = { 131*52889Sbostic 320, 132*52889Sbostic 330, 133*52889Sbostic 340, 134*52889Sbostic 350, 135*52889Sbostic 50, 136*52889Sbostic 50, 137*52889Sbostic 60, 138*52889Sbostic 70, 139*52889Sbostic 80, 140*52889Sbostic 90, 141*52889Sbostic 100, 142*52889Sbostic 110, 143*52889Sbostic 120, 144*52889Sbostic 130, 145*52889Sbostic 140, 146*52889Sbostic 150, 147*52889Sbostic 160, 148*52889Sbostic 170, 149*52889Sbostic 180, 150*52889Sbostic 190, 151*52889Sbostic 200, 152*52889Sbostic 210, 153*52889Sbostic 220, 154*52889Sbostic 230, 155*52889Sbostic 240, 156*52889Sbostic 250, 157*52889Sbostic 260, 158*52889Sbostic 270, 159*52889Sbostic 280, 160*52889Sbostic 290, 161*52889Sbostic 300, 162*52889Sbostic 310, 163*52889Sbostic }; 164*52889Sbostic 165*52889Sbostic /* 166*52889Sbostic * Internal forward declarations. 167*52889Sbostic */ 168*52889Sbostic static void asc_reset(); 169*52889Sbostic static void asc_startcmd(); 170*52889Sbostic 171*52889Sbostic #ifdef DEBUG 172*52889Sbostic int asc_debug = 1; 173*52889Sbostic int asc_debug_cmd; 174*52889Sbostic int asc_debug_bn; 175*52889Sbostic int asc_debug_sz; 176*52889Sbostic #define NLOG 16 177*52889Sbostic struct asc_log { 178*52889Sbostic u_int status; 179*52889Sbostic u_char state; 180*52889Sbostic u_char msg; 181*52889Sbostic int target; 182*52889Sbostic } asc_log[NLOG], *asc_logp = asc_log; 183*52889Sbostic #define PACK(unit, status, ss, ir) \ 184*52889Sbostic ((unit << 24) | (status << 16) | (ss << 8) | ir) 185*52889Sbostic #endif 186*52889Sbostic 187*52889Sbostic /* 188*52889Sbostic * Scripts are entries in a state machine table. 189*52889Sbostic * A script has four parts: a pre-condition, an action, a command to the chip, 190*52889Sbostic * and an index into asc_scripts for the next state. The first triggers error 191*52889Sbostic * handling if not satisfied and in our case it is formed by the 192*52889Sbostic * values of the interrupt register and status register, this 193*52889Sbostic * basically captures the phase of the bus and the TC and BS 194*52889Sbostic * bits. The action part is just a function pointer, and the 195*52889Sbostic * command is what the 53C94 should be told to do at the end 196*52889Sbostic * of the action processing. This command is only issued and the 197*52889Sbostic * script proceeds if the action routine returns TRUE. 198*52889Sbostic * See asc_intr() for how and where this is all done. 199*52889Sbostic */ 200*52889Sbostic typedef struct script { 201*52889Sbostic int condition; /* expected state at interrupt time */ 202*52889Sbostic int (*action)(); /* extra operations */ 203*52889Sbostic int command; /* command to the chip */ 204*52889Sbostic struct script *next; /* index into asc_scripts for next state */ 205*52889Sbostic } script_t; 206*52889Sbostic 207*52889Sbostic /* Matching on the condition value */ 208*52889Sbostic #define SCRIPT_MATCH(ir, csr) ((ir) | (ASC_PHASE(csr) << 8)) 209*52889Sbostic 210*52889Sbostic /* forward decls of script actions */ 211*52889Sbostic int script_nop(); /* when nothing needed */ 212*52889Sbostic int asc_end(); /* all come to an end */ 213*52889Sbostic int asc_get_status(); /* get status from target */ 214*52889Sbostic int asc_dma_in(); /* start reading data from target */ 215*52889Sbostic int asc_last_dma_in(); /* cleanup after all data is read */ 216*52889Sbostic int asc_resume_dma_in(); /* resume DMA after a disconnect */ 217*52889Sbostic int asc_dma_out(); /* send data to target via dma */ 218*52889Sbostic int asc_last_dma_out(); /* cleanup after all data is written */ 219*52889Sbostic int asc_resume_dma_out(); /* resume DMA after a disconnect */ 220*52889Sbostic int asc_sendsync(); /* negotiate sync xfer */ 221*52889Sbostic int asc_replysync(); /* negotiate sync xfer */ 222*52889Sbostic int asc_recvmsg(); /* process a message byte */ 223*52889Sbostic 224*52889Sbostic /* Define the index into asc_scripts for various state transitions */ 225*52889Sbostic #define SCRIPT_DATA_IN 0 226*52889Sbostic #define SCRIPT_DATA_OUT 2 227*52889Sbostic #define SCRIPT_SIMPLE 4 228*52889Sbostic #define SCRIPT_GET_STATUS 5 229*52889Sbostic #define SCRIPT_MSG_IN 7 230*52889Sbostic #define SCRIPT_REPLY_SYNC 9 231*52889Sbostic #define SCRIPT_RESUME_IN 10 232*52889Sbostic #define SCRIPT_RESUME_OUT 11 233*52889Sbostic #define SCRIPT_TRY_SYNC 12 234*52889Sbostic #define SCRIPT_RESEL 15 235*52889Sbostic #define SCRIPT_RESUME_DMA_IN 16 236*52889Sbostic #define SCRIPT_RESUME_DMA_OUT 17 237*52889Sbostic 238*52889Sbostic /* 239*52889Sbostic * Scripts 240*52889Sbostic */ 241*52889Sbostic script_t asc_scripts[] = { 242*52889Sbostic /* data in */ 243*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 244*52889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 245*52889Sbostic &asc_scripts[SCRIPT_DATA_IN + 1] }, 246*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 247*52889Sbostic asc_last_dma_in, ASC_CMD_I_COMPLETE, 248*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 249*52889Sbostic 250*52889Sbostic /* data out */ 251*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 2 */ 252*52889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 253*52889Sbostic &asc_scripts[SCRIPT_DATA_OUT + 1] }, 254*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 3 */ 255*52889Sbostic asc_last_dma_out, ASC_CMD_I_COMPLETE, 256*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 257*52889Sbostic 258*52889Sbostic /* simple command with no data transfer */ 259*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 260*52889Sbostic script_nop, ASC_CMD_I_COMPLETE, 261*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 262*52889Sbostic 263*52889Sbostic /* get status and finish command */ 264*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 5 */ 265*52889Sbostic asc_get_status, ASC_CMD_MSG_ACPT, 266*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS + 1] }, 267*52889Sbostic {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 6 */ 268*52889Sbostic asc_end, ASC_CMD_NOP, 269*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS + 1] }, 270*52889Sbostic 271*52889Sbostic /* message in */ 272*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 273*52889Sbostic asc_recvmsg, ASC_CMD_MSG_ACPT, 274*52889Sbostic &asc_scripts[SCRIPT_MSG_IN + 1] }, 275*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 8 */ 276*52889Sbostic script_nop, ASC_CMD_XFER_INFO, 277*52889Sbostic &asc_scripts[SCRIPT_MSG_IN] }, 278*52889Sbostic 279*52889Sbostic /* send synchonous negotiation reply */ 280*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 9 */ 281*52889Sbostic asc_replysync, ASC_CMD_XFER_INFO, 282*52889Sbostic &asc_scripts[SCRIPT_REPLY_SYNC] }, 283*52889Sbostic 284*52889Sbostic /* resume data in after a message */ 285*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 10 */ 286*52889Sbostic asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 287*52889Sbostic &asc_scripts[SCRIPT_DATA_IN + 1] }, 288*52889Sbostic 289*52889Sbostic /* resume data out after a message */ 290*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 11 */ 291*52889Sbostic asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 292*52889Sbostic &asc_scripts[SCRIPT_DATA_OUT + 1] }, 293*52889Sbostic 294*52889Sbostic /* try to negotiate synchonous transfer parameters */ 295*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 296*52889Sbostic asc_sendsync, ASC_CMD_XFER_INFO, 297*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 298*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 13 */ 299*52889Sbostic script_nop, ASC_CMD_XFER_INFO, 300*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 301*52889Sbostic {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 14 */ 302*52889Sbostic asc_recvmsg, ASC_CMD_MSG_ACPT, 303*52889Sbostic &asc_scripts[SCRIPT_GET_STATUS] }, 304*52889Sbostic 305*52889Sbostic /* reselect sequence: this is just a placeholder so match fails */ 306*52889Sbostic {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 15 */ 307*52889Sbostic script_nop, ASC_CMD_MSG_ACPT, 308*52889Sbostic &asc_scripts[SCRIPT_RESEL] }, 309*52889Sbostic 310*52889Sbostic /* resume data in after a disconnect */ 311*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 16 */ 312*52889Sbostic asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 313*52889Sbostic &asc_scripts[SCRIPT_DATA_IN + 1] }, 314*52889Sbostic 315*52889Sbostic /* resume data out after a disconnect */ 316*52889Sbostic {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 17 */ 317*52889Sbostic asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 318*52889Sbostic &asc_scripts[SCRIPT_DATA_OUT + 1] }, 319*52889Sbostic }; 320*52889Sbostic 321*52889Sbostic /* 322*52889Sbostic * State kept for each active SCSI device. 323*52889Sbostic */ 324*52889Sbostic typedef struct scsi_state { 325*52889Sbostic script_t *script; /* saved script while processing error */ 326*52889Sbostic int statusByte; /* status byte returned during STATUS_PHASE */ 327*52889Sbostic int error; /* errno to pass back to device driver */ 328*52889Sbostic u_char *dmaBufAddr; /* DMA buffer address */ 329*52889Sbostic u_int dmaBufSize; /* DMA buffer size */ 330*52889Sbostic int dmalen; /* amount to transfer in this chunk */ 331*52889Sbostic int dmaresid; /* amount not transfered if chunk suspended */ 332*52889Sbostic int buflen; /* total remaining amount of data to transfer */ 333*52889Sbostic char *buf; /* current pointer within scsicmd->buf */ 334*52889Sbostic int flags; /* see below */ 335*52889Sbostic int msglen; /* number of message bytes to read */ 336*52889Sbostic int msgcnt; /* number of message bytes received */ 337*52889Sbostic u_char sync_period; /* DMA synchronous period */ 338*52889Sbostic u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 339*52889Sbostic u_char msg_out; /* next MSG_OUT byte to send */ 340*52889Sbostic u_char msg_in[16]; /* buffer for multibyte messages */ 341*52889Sbostic } State; 342*52889Sbostic 343*52889Sbostic /* state flags */ 344*52889Sbostic #define DISCONN 0x01 /* true if currently disconnected from bus */ 345*52889Sbostic #define FIRST_DMA 0x02 /* true if no data DMA started yet */ 346*52889Sbostic #define DMA_IN 0x04 /* true if reading from SCSI device */ 347*52889Sbostic #define DMA_OUT 0x10 /* true if writing to SCSI device */ 348*52889Sbostic #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 349*52889Sbostic #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 350*52889Sbostic 351*52889Sbostic #define ASC_NCMD 7 352*52889Sbostic /* 353*52889Sbostic * State kept for each active SCSI host interface (53C94). 354*52889Sbostic */ 355*52889Sbostic struct asc_softc { 356*52889Sbostic asc_regmap_t *regs; /* chip address */ 357*52889Sbostic volatile int *dmar; /* DMA address register address */ 358*52889Sbostic volatile u_char *buff; /* RAM buffer address */ 359*52889Sbostic int myid; /* SCSI ID of this interface */ 360*52889Sbostic int myidmask; /* ~(1 << myid) */ 361*52889Sbostic int state; /* current SCSI connection state */ 362*52889Sbostic int target; /* target SCSI ID if busy */ 363*52889Sbostic script_t *script; /* next expected interrupt & action */ 364*52889Sbostic ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 365*52889Sbostic State st[ASC_NCMD]; /* state info for each active command */ 366*52889Sbostic } asc_softc[NASC]; 367*52889Sbostic 368*52889Sbostic #define ASC_STATE_IDLE 0 /* idle state */ 369*52889Sbostic #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 370*52889Sbostic #define ASC_STATE_TARGET 2 /* currently selected as target */ 371*52889Sbostic #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 372*52889Sbostic 373*52889Sbostic typedef struct asc_softc *asc_softc_t; 374*52889Sbostic 375*52889Sbostic /* 376*52889Sbostic * Definition of the controller for the auto-configuration program. 377*52889Sbostic */ 378*52889Sbostic int asc_probe(); 379*52889Sbostic void asc_start(); 380*52889Sbostic void asc_intr(); 381*52889Sbostic struct driver ascdriver = { 382*52889Sbostic "asc", asc_probe, asc_start, 0, asc_intr, 383*52889Sbostic }; 384*52889Sbostic 385*52889Sbostic /* 386*52889Sbostic * Test to see if device is present. 387*52889Sbostic * Return true if found and initialized ok. 388*52889Sbostic */ 389*52889Sbostic asc_probe(cp) 390*52889Sbostic register struct pmax_ctlr *cp; 391*52889Sbostic { 392*52889Sbostic register asc_softc_t asc; 393*52889Sbostic register asc_regmap_t *regs; 394*52889Sbostic int unit, id, s, i; 395*52889Sbostic 396*52889Sbostic if ((unit = cp->pmax_unit) >= NASC) 397*52889Sbostic return (0); 398*52889Sbostic if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 399*52889Sbostic return (0); 400*52889Sbostic asc = &asc_softc[unit]; 401*52889Sbostic 402*52889Sbostic /* 403*52889Sbostic * Initialize hw descriptor, cache some pointers 404*52889Sbostic */ 405*52889Sbostic asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 406*52889Sbostic asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 407*52889Sbostic asc->buff = (volatile u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 408*52889Sbostic 409*52889Sbostic asc->state = ASC_STATE_IDLE; 410*52889Sbostic asc->target = -1; 411*52889Sbostic 412*52889Sbostic regs = asc->regs; 413*52889Sbostic 414*52889Sbostic /* 415*52889Sbostic * Reset chip, fully. Note that interrupts are already enabled. 416*52889Sbostic */ 417*52889Sbostic s = splbio(); 418*52889Sbostic 419*52889Sbostic /* preserve our ID for now */ 420*52889Sbostic asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 421*52889Sbostic asc->myidmask = ~(1 << asc->myid); 422*52889Sbostic 423*52889Sbostic asc_reset(asc, regs); 424*52889Sbostic 425*52889Sbostic /* 426*52889Sbostic * Our SCSI id on the bus. 427*52889Sbostic * The user can set this via the prom on 3maxen/pmaxen. 428*52889Sbostic * If this changes it is easy to fix: make a default that 429*52889Sbostic * can be changed as boot arg. 430*52889Sbostic */ 431*52889Sbostic #ifdef unneeded 432*52889Sbostic regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 433*52889Sbostic (scsi_initiator_id[unit] & 0x7); 434*52889Sbostic #endif 435*52889Sbostic id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 436*52889Sbostic splx(s); 437*52889Sbostic 438*52889Sbostic /* 439*52889Sbostic * Statically partition the DMA buffer between targets. 440*52889Sbostic * This way we will eventually be able to attach/detach 441*52889Sbostic * drives on-fly. And 18k/target is plenty for normal use. 442*52889Sbostic */ 443*52889Sbostic #define PER_TGT_DMA_SIZE ((ASC_RAM_SIZE/7) & ~(sizeof(int)-1)) 444*52889Sbostic 445*52889Sbostic /* 446*52889Sbostic * Give each target its own DMA buffer region. 447*52889Sbostic * We may want to try ping ponging buffers later. 448*52889Sbostic */ 449*52889Sbostic for (i = 0; i < ASC_NCMD; i++) { 450*52889Sbostic asc->st[i].dmaBufAddr = asc->buff + PER_TGT_DMA_SIZE * i; 451*52889Sbostic asc->st[i].dmaBufSize = PER_TGT_DMA_SIZE; 452*52889Sbostic } 453*52889Sbostic printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 454*52889Sbostic unit, cp->pmax_addr, cp->pmax_pri, id); 455*52889Sbostic return (1); 456*52889Sbostic } 457*52889Sbostic 458*52889Sbostic /* 459*52889Sbostic * Start activity on a SCSI device. 460*52889Sbostic * We maintain information on each device separately since devices can 461*52889Sbostic * connect/disconnect during an operation. 462*52889Sbostic */ 463*52889Sbostic void 464*52889Sbostic asc_start(scsicmd) 465*52889Sbostic register ScsiCmd *scsicmd; /* command to start */ 466*52889Sbostic { 467*52889Sbostic register struct scsi_device *sdp = scsicmd->sd; 468*52889Sbostic register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 469*52889Sbostic int s; 470*52889Sbostic 471*52889Sbostic s = splbio(); 472*52889Sbostic /* 473*52889Sbostic * Check if another command is already in progress. 474*52889Sbostic * We may have to change this if we allow SCSI devices with 475*52889Sbostic * separate LUNs. 476*52889Sbostic */ 477*52889Sbostic if (asc->cmd[sdp->sd_drive]) { 478*52889Sbostic printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 479*52889Sbostic sdp->sd_driver->d_name); 480*52889Sbostic (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 481*52889Sbostic scsicmd->buflen, 0); 482*52889Sbostic splx(s); 483*52889Sbostic } 484*52889Sbostic asc->cmd[sdp->sd_drive] = scsicmd; 485*52889Sbostic asc_startcmd(asc, sdp->sd_drive); 486*52889Sbostic splx(s); 487*52889Sbostic } 488*52889Sbostic 489*52889Sbostic static void 490*52889Sbostic asc_reset(asc, regs) 491*52889Sbostic asc_softc_t asc; 492*52889Sbostic asc_regmap_t *regs; 493*52889Sbostic { 494*52889Sbostic 495*52889Sbostic /* 496*52889Sbostic * Reset chip and wait till done 497*52889Sbostic */ 498*52889Sbostic regs->asc_cmd = ASC_CMD_RESET; 499*52889Sbostic MachEmptyWriteBuffer(); DELAY(25); 500*52889Sbostic 501*52889Sbostic /* spec says this is needed after reset */ 502*52889Sbostic regs->asc_cmd = ASC_CMD_NOP; 503*52889Sbostic MachEmptyWriteBuffer(); DELAY(25); 504*52889Sbostic 505*52889Sbostic /* 506*52889Sbostic * Set up various chip parameters 507*52889Sbostic */ 508*52889Sbostic regs->asc_ccf = ASC_CCF_25MHz; /* 25 MHz clock */ 509*52889Sbostic MachEmptyWriteBuffer(); DELAY(25); 510*52889Sbostic regs->asc_sel_timo = ASC_TIMEOUT_250; 511*52889Sbostic /* restore our ID */ 512*52889Sbostic regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 513*52889Sbostic regs->asc_cnfg2 = /* ASC_CNFG2_RFB | */ ASC_CNFG2_EPL; 514*52889Sbostic regs->asc_cnfg3 = 0; 515*52889Sbostic /* zero anything else */ 516*52889Sbostic ASC_TC_PUT(regs, 0); 517*52889Sbostic regs->asc_sel_timo = ASC_TIMEOUT_250; 518*52889Sbostic regs->asc_syn_p = ASC_MIN_PERIOD; 519*52889Sbostic regs->asc_syn_o = 0; /* async for now */ 520*52889Sbostic MachEmptyWriteBuffer(); 521*52889Sbostic } 522*52889Sbostic 523*52889Sbostic /* 524*52889Sbostic * Start a SCSI command on a target. 525*52889Sbostic */ 526*52889Sbostic static void 527*52889Sbostic asc_startcmd(asc, target) 528*52889Sbostic asc_softc_t asc; 529*52889Sbostic int target; 530*52889Sbostic { 531*52889Sbostic register asc_regmap_t *regs; 532*52889Sbostic register ScsiCmd *scsicmd; 533*52889Sbostic register State *state; 534*52889Sbostic int len; 535*52889Sbostic 536*52889Sbostic /* 537*52889Sbostic * See if another target is currently selected on this SCSI bus. 538*52889Sbostic */ 539*52889Sbostic if (asc->target >= 0) 540*52889Sbostic return; 541*52889Sbostic 542*52889Sbostic regs = asc->regs; 543*52889Sbostic 544*52889Sbostic /* 545*52889Sbostic * Check to see if a reselection is in progress and if so, 546*52889Sbostic * try to cancel it or respond to the reselection if it won. 547*52889Sbostic */ 548*52889Sbostic if (asc->state == ASC_STATE_RESEL) { 549*52889Sbostic regs->asc_cmd = ASC_CMD_DISABLE_SEL; 550*52889Sbostic while (!(regs->asc_status & ASC_CSR_INT)) 551*52889Sbostic DELAY(1); 552*52889Sbostic asc_intr(asc - asc_softc); 553*52889Sbostic /* we will be busy if a reselecting device won */ 554*52889Sbostic if (asc->state == ASC_STATE_BUSY) 555*52889Sbostic return; 556*52889Sbostic } 557*52889Sbostic 558*52889Sbostic asc->state = ASC_STATE_BUSY; 559*52889Sbostic asc->target = target; 560*52889Sbostic 561*52889Sbostic /* cache some pointers */ 562*52889Sbostic scsicmd = asc->cmd[target]; 563*52889Sbostic state = &asc->st[target]; 564*52889Sbostic 565*52889Sbostic #ifdef DEBUG 566*52889Sbostic if (asc_debug > 1) { 567*52889Sbostic printf("asc_startcmd: %s target %d cmd %x len %d\n", 568*52889Sbostic scsicmd->sd->sd_driver->d_name, target, 569*52889Sbostic scsicmd->cmd[0], scsicmd->buflen); 570*52889Sbostic } 571*52889Sbostic asc_debug_cmd = scsicmd->cmd[0]; 572*52889Sbostic if (scsicmd->cmd[0] == SCSI_READ_EXT) { 573*52889Sbostic asc_debug_bn = (scsicmd->cmd[2] << 24) | 574*52889Sbostic (scsicmd->cmd[3] << 16) | 575*52889Sbostic (scsicmd->cmd[4] << 8) | 576*52889Sbostic scsicmd->cmd[5]; 577*52889Sbostic asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 578*52889Sbostic } 579*52889Sbostic asc_logp->status = PACK(asc - asc_softc, 0, 0, 0); 580*52889Sbostic asc_logp->target = asc->target; 581*52889Sbostic asc_logp->state = 0; 582*52889Sbostic if (++asc_logp >= &asc_log[NLOG]) 583*52889Sbostic asc_logp = asc_log; 584*52889Sbostic #endif 585*52889Sbostic 586*52889Sbostic /* 587*52889Sbostic * Init the chip and target state. 588*52889Sbostic */ 589*52889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 590*52889Sbostic state->flags = FIRST_DMA | (state->flags & DID_SYNC); 591*52889Sbostic state->error = 0; 592*52889Sbostic state->script = (script_t *)0; 593*52889Sbostic state->msg_out = SCSI_NO_OP; 594*52889Sbostic 595*52889Sbostic /* 596*52889Sbostic * Copy command data to the DMA buffer. 597*52889Sbostic */ 598*52889Sbostic len = scsicmd->cmdlen; 599*52889Sbostic state->dmalen = len; 600*52889Sbostic bcopy(scsicmd->cmd, state->dmaBufAddr, len); 601*52889Sbostic 602*52889Sbostic /* check for simple SCSI command with no data transfer */ 603*52889Sbostic if ((state->buflen = scsicmd->buflen) == 0) { 604*52889Sbostic /* check for sync negotiation */ 605*52889Sbostic if ((scsicmd->flags & SCSICMD_USE_SYNC) && 606*52889Sbostic !(state->flags & DID_SYNC)) { 607*52889Sbostic asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 608*52889Sbostic state->flags |= TRY_SYNC; 609*52889Sbostic } else 610*52889Sbostic asc->script = &asc_scripts[SCRIPT_SIMPLE]; 611*52889Sbostic state->buf = (char *)0; 612*52889Sbostic } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 613*52889Sbostic int cnt; 614*52889Sbostic 615*52889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 616*52889Sbostic 617*52889Sbostic /* setup to write first chunk */ 618*52889Sbostic state->flags |= DMA_OUT; 619*52889Sbostic state->buf = scsicmd->buf; 620*52889Sbostic cnt = state->dmaBufSize - len; 621*52889Sbostic if (cnt > state->buflen) 622*52889Sbostic cnt = state->buflen; 623*52889Sbostic else printf("can't write in one chunk cnt %d buflen %d\n", 624*52889Sbostic cnt, state->buflen); /* XXX */ 625*52889Sbostic state->dmalen = cnt; 626*52889Sbostic bcopy(state->buf, state->dmaBufAddr + len, cnt); 627*52889Sbostic } else { 628*52889Sbostic asc->script = &asc_scripts[SCRIPT_DATA_IN]; 629*52889Sbostic state->buf = scsicmd->buf; 630*52889Sbostic state->flags |= DMA_IN; 631*52889Sbostic } 632*52889Sbostic 633*52889Sbostic /* preload the FIFO with the message to be sent */ 634*52889Sbostic regs->asc_fifo = /* SCSI_IDENTIFY */ SCSI_DIS_REC_IDENTIFY; 635*52889Sbostic 636*52889Sbostic /* start the asc */ 637*52889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 638*52889Sbostic ASC_TC_PUT(regs, len); 639*52889Sbostic 640*52889Sbostic regs->asc_dbus_id = target; 641*52889Sbostic regs->asc_syn_p = state->sync_period; 642*52889Sbostic regs->asc_syn_o = state->sync_offset; 643*52889Sbostic 644*52889Sbostic if (state->flags & TRY_SYNC) 645*52889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA; 646*52889Sbostic else 647*52889Sbostic regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 648*52889Sbostic } 649*52889Sbostic 650*52889Sbostic /* 651*52889Sbostic * Interrupt routine 652*52889Sbostic * Take interrupts from the chip 653*52889Sbostic * 654*52889Sbostic * Implementation: 655*52889Sbostic * Move along the current command's script if 656*52889Sbostic * all is well, invoke error handler if not. 657*52889Sbostic */ 658*52889Sbostic void 659*52889Sbostic asc_intr(unit) 660*52889Sbostic int unit; 661*52889Sbostic { 662*52889Sbostic register asc_softc_t asc = &asc_softc[unit]; 663*52889Sbostic register asc_regmap_t *regs = asc->regs; 664*52889Sbostic register State *state; 665*52889Sbostic register script_t *scpt; 666*52889Sbostic register int ss, ir, status; 667*52889Sbostic 668*52889Sbostic again: 669*52889Sbostic /* collect ephemeral information */ 670*52889Sbostic status = regs->asc_status; 671*52889Sbostic ss = regs->asc_ss; 672*52889Sbostic ir = regs->asc_intr; /* this resets the previous two */ 673*52889Sbostic scpt = asc->script; 674*52889Sbostic 675*52889Sbostic #ifdef DEBUG 676*52889Sbostic asc_logp->status = PACK(unit, status, ss, ir); 677*52889Sbostic asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 678*52889Sbostic asc_logp->state = scpt - asc_scripts; 679*52889Sbostic asc_logp->msg = -1; 680*52889Sbostic if (++asc_logp >= &asc_log[NLOG]) 681*52889Sbostic asc_logp = asc_log; 682*52889Sbostic if (asc_debug > 2) 683*52889Sbostic printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 684*52889Sbostic status, ss, ir, scpt - asc_scripts, scpt->condition); 685*52889Sbostic #endif 686*52889Sbostic 687*52889Sbostic /* check the expected state */ 688*52889Sbostic if (SCRIPT_MATCH(ir, status) == scpt->condition) { 689*52889Sbostic /* 690*52889Sbostic * Perform the appropriate operation, then proceed. 691*52889Sbostic */ 692*52889Sbostic if ((*scpt->action)(asc, status, ss, ir)) { 693*52889Sbostic regs->asc_cmd = scpt->command; 694*52889Sbostic asc->script = scpt->next; 695*52889Sbostic } 696*52889Sbostic goto done; 697*52889Sbostic } 698*52889Sbostic 699*52889Sbostic /* check for message in or out */ 700*52889Sbostic if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 701*52889Sbostic register int len, fifo; 702*52889Sbostic 703*52889Sbostic state = &asc->st[asc->target]; 704*52889Sbostic switch (ASC_PHASE(status)) { 705*52889Sbostic case ASC_PHASE_MSG_IN: 706*52889Sbostic break; 707*52889Sbostic 708*52889Sbostic case ASC_PHASE_MSG_OUT: 709*52889Sbostic regs->asc_fifo = state->msg_out; 710*52889Sbostic state->msg_out = SCSI_NO_OP; 711*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 712*52889Sbostic goto done; 713*52889Sbostic 714*52889Sbostic case ASC_PHASE_STATUS: 715*52889Sbostic /* probably an error in the SCSI command */ 716*52889Sbostic asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 717*52889Sbostic regs->asc_cmd = ASC_CMD_I_COMPLETE; 718*52889Sbostic goto done; 719*52889Sbostic 720*52889Sbostic default: 721*52889Sbostic goto abort; 722*52889Sbostic } 723*52889Sbostic 724*52889Sbostic if (state->script) 725*52889Sbostic goto abort; 726*52889Sbostic 727*52889Sbostic /* check for DMA in progress */ 728*52889Sbostic ASC_TC_GET(regs, len); 729*52889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 730*52889Sbostic /* flush any data in the FIFO */ 731*52889Sbostic if (fifo) { 732*52889Sbostic printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n", 733*52889Sbostic state->flags, state->dmalen, 734*52889Sbostic len, fifo); /* XXX */ 735*52889Sbostic len += fifo; 736*52889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 737*52889Sbostic MachEmptyWriteBuffer(); 738*52889Sbostic } 739*52889Sbostic if (len) { 740*52889Sbostic /* save number of bytes still to be sent or received */ 741*52889Sbostic state->dmaresid = len; 742*52889Sbostic /* setup state to resume to */ 743*52889Sbostic if (state->flags & DMA_IN) 744*52889Sbostic state->script = 745*52889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_IN]; 746*52889Sbostic else if (state->flags & DMA_OUT) 747*52889Sbostic state->script = 748*52889Sbostic &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 749*52889Sbostic else 750*52889Sbostic state->script = asc->script; 751*52889Sbostic } else { 752*52889Sbostic /* setup state to resume to */ 753*52889Sbostic if (state->flags & DMA_IN) 754*52889Sbostic state->script = &asc_scripts[SCRIPT_RESUME_IN]; 755*52889Sbostic else if (state->flags & DMA_OUT) 756*52889Sbostic state->script = &asc_scripts[SCRIPT_RESUME_OUT]; 757*52889Sbostic else 758*52889Sbostic state->script = asc->script; 759*52889Sbostic } 760*52889Sbostic 761*52889Sbostic /* setup to receive a message */ 762*52889Sbostic asc->script = &asc_scripts[SCRIPT_MSG_IN]; 763*52889Sbostic state->msglen = 0; 764*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 765*52889Sbostic goto done; 766*52889Sbostic } 767*52889Sbostic 768*52889Sbostic /* check for SCSI bus reset */ 769*52889Sbostic if (ir & ASC_INT_RESET) { 770*52889Sbostic register int i; 771*52889Sbostic 772*52889Sbostic printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 773*52889Sbostic /* need to flush any pending commands */ 774*52889Sbostic for (i = 0; i < ASC_NCMD; i++) { 775*52889Sbostic if (!asc->cmd[i]) 776*52889Sbostic continue; 777*52889Sbostic asc->st[i].error = EIO; 778*52889Sbostic asc_end(asc, 0, 0, 0); 779*52889Sbostic } 780*52889Sbostic /* rearbitrate synchronous offset */ 781*52889Sbostic for (i = 0; i < ASC_NCMD; i++) { 782*52889Sbostic asc->st[i].sync_offset = 0; 783*52889Sbostic asc->st[i].flags = 0; 784*52889Sbostic } 785*52889Sbostic asc->target = -1; 786*52889Sbostic return; 787*52889Sbostic } 788*52889Sbostic 789*52889Sbostic /* check for command errors */ 790*52889Sbostic if (ir & ASC_INT_ILL) 791*52889Sbostic goto abort; 792*52889Sbostic 793*52889Sbostic /* check for disconnect */ 794*52889Sbostic if (ir & ASC_INT_DISC) { 795*52889Sbostic state = &asc->st[asc->target]; 796*52889Sbostic if (state->flags & DISCONN) { 797*52889Sbostic if (state->script) 798*52889Sbostic goto abort; 799*52889Sbostic state->script = asc->script; 800*52889Sbostic asc->target = -1; 801*52889Sbostic asc->state = ASC_STATE_RESEL; 802*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 803*52889Sbostic regs->asc_cmd = ASC_CMD_ENABLE_SEL; 804*52889Sbostic goto done; 805*52889Sbostic } 806*52889Sbostic 807*52889Sbostic switch (ASC_SS(ss)) { 808*52889Sbostic case 0: /* device did not respond */ 809*52889Sbostic state->error = ENXIO; 810*52889Sbostic asc_end(asc, status, ss, ir); 811*52889Sbostic return; 812*52889Sbostic 813*52889Sbostic default: 814*52889Sbostic goto abort; 815*52889Sbostic } 816*52889Sbostic } 817*52889Sbostic 818*52889Sbostic /* check for reselect */ 819*52889Sbostic if (ir & ASC_INT_RESEL) { 820*52889Sbostic unsigned fifo, id, msg; 821*52889Sbostic 822*52889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 823*52889Sbostic if (fifo < 2) 824*52889Sbostic goto abort; 825*52889Sbostic /* read unencoded SCSI ID and convert to binary */ 826*52889Sbostic msg = regs->asc_fifo & asc->myidmask; 827*52889Sbostic for (id = 0; (msg & 1) == 0; id++) 828*52889Sbostic msg >>= 1; 829*52889Sbostic /* read identify message */ 830*52889Sbostic msg = regs->asc_fifo; 831*52889Sbostic #ifdef DEBUG 832*52889Sbostic if (asc_logp == asc_log) 833*52889Sbostic asc_log[NLOG - 1].msg = msg; 834*52889Sbostic else 835*52889Sbostic asc_logp[-1].msg = msg; 836*52889Sbostic #endif 837*52889Sbostic if (asc->state != ASC_STATE_RESEL) 838*52889Sbostic goto abort; 839*52889Sbostic asc->state = ASC_STATE_BUSY; 840*52889Sbostic asc->target = id; 841*52889Sbostic state = &asc->st[id]; 842*52889Sbostic asc->script = state->script; 843*52889Sbostic state->script = (script_t *)0; 844*52889Sbostic if (!(state->flags & DISCONN)) 845*52889Sbostic goto abort; 846*52889Sbostic state->flags &= ~DISCONN; 847*52889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 848*52889Sbostic goto done; 849*52889Sbostic } 850*52889Sbostic 851*52889Sbostic /* check if we are being selected as a target */ 852*52889Sbostic if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 853*52889Sbostic goto abort; 854*52889Sbostic 855*52889Sbostic /* must be just a ASC_INT_FC */ 856*52889Sbostic done: 857*52889Sbostic MachEmptyWriteBuffer(); 858*52889Sbostic if (regs->asc_status & ASC_CSR_INT) 859*52889Sbostic goto again; 860*52889Sbostic return; 861*52889Sbostic 862*52889Sbostic abort: 863*52889Sbostic #ifdef DEBUG 864*52889Sbostic asc_DumpLog("asc_intr"); 865*52889Sbostic #endif 866*52889Sbostic #if 0 867*52889Sbostic panic("asc_intr"); 868*52889Sbostic #else 869*52889Sbostic for (;;); 870*52889Sbostic #endif 871*52889Sbostic } 872*52889Sbostic 873*52889Sbostic /* 874*52889Sbostic * All the many little things that the interrupt 875*52889Sbostic * routine might switch to. 876*52889Sbostic */ 877*52889Sbostic 878*52889Sbostic /* ARGSUSED */ 879*52889Sbostic static int 880*52889Sbostic script_nop(asc, status, ss, ir) 881*52889Sbostic register asc_softc_t asc; 882*52889Sbostic register int status, ss, ir; 883*52889Sbostic { 884*52889Sbostic return (1); 885*52889Sbostic } 886*52889Sbostic 887*52889Sbostic /* ARGSUSED */ 888*52889Sbostic static int 889*52889Sbostic asc_get_status(asc, status, ss, ir) 890*52889Sbostic register asc_softc_t asc; 891*52889Sbostic register int status, ss, ir; 892*52889Sbostic { 893*52889Sbostic register asc_regmap_t *regs = asc->regs; 894*52889Sbostic register int data; 895*52889Sbostic 896*52889Sbostic /* 897*52889Sbostic * Get the last two bytes in the FIFO. 898*52889Sbostic */ 899*52889Sbostic if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 900*52889Sbostic printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 901*52889Sbostic if (data < 2) { 902*52889Sbostic asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 903*52889Sbostic return (0); 904*52889Sbostic } 905*52889Sbostic do { 906*52889Sbostic data = regs->asc_fifo; 907*52889Sbostic } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 908*52889Sbostic } 909*52889Sbostic 910*52889Sbostic /* save the status byte */ 911*52889Sbostic asc->st[asc->target].statusByte = data = regs->asc_fifo; 912*52889Sbostic #ifdef DEBUG 913*52889Sbostic if (asc_logp == asc_log) 914*52889Sbostic asc_log[NLOG - 1].msg = data; 915*52889Sbostic else 916*52889Sbostic asc_logp[-1].msg = data; 917*52889Sbostic #endif 918*52889Sbostic 919*52889Sbostic /* get the (presumed) command_complete message */ 920*52889Sbostic if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 921*52889Sbostic return (1); 922*52889Sbostic 923*52889Sbostic #ifdef DEBUG 924*52889Sbostic printf("asc_get_status: status %x cmd %x\n", 925*52889Sbostic asc->st[asc->target].statusByte, data); 926*52889Sbostic asc_DumpLog("asc_get_status"); 927*52889Sbostic #endif 928*52889Sbostic return (0); 929*52889Sbostic } 930*52889Sbostic 931*52889Sbostic /* ARGSUSED */ 932*52889Sbostic static int 933*52889Sbostic asc_end(asc, status, ss, ir) 934*52889Sbostic register asc_softc_t asc; 935*52889Sbostic register int status, ss, ir; 936*52889Sbostic { 937*52889Sbostic register ScsiCmd *scsicmd; 938*52889Sbostic register State *state; 939*52889Sbostic register int i, target; 940*52889Sbostic 941*52889Sbostic asc->state = ASC_STATE_IDLE; 942*52889Sbostic target = asc->target; 943*52889Sbostic asc->target = -1; 944*52889Sbostic scsicmd = asc->cmd[target]; 945*52889Sbostic asc->cmd[target] = (ScsiCmd *)0; 946*52889Sbostic state = &asc->st[target]; 947*52889Sbostic 948*52889Sbostic #ifdef DEBUG 949*52889Sbostic if (asc_debug > 1) { 950*52889Sbostic printf("asc_end: %s target %d cmd %x err %d resid %d\n", 951*52889Sbostic scsicmd->sd->sd_driver->d_name, target, 952*52889Sbostic scsicmd->cmd[0], state->error, state->buflen); 953*52889Sbostic } 954*52889Sbostic #endif 955*52889Sbostic #ifdef DIAGNOSTIC 956*52889Sbostic if (target < 0 || !scsicmd) 957*52889Sbostic panic("asc_end"); 958*52889Sbostic #endif 959*52889Sbostic 960*52889Sbostic /* look for disconnected devices */ 961*52889Sbostic for (i = 0; i < ASC_NCMD; i++) { 962*52889Sbostic if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 963*52889Sbostic continue; 964*52889Sbostic asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 965*52889Sbostic asc->state = ASC_STATE_RESEL; 966*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESEL]; 967*52889Sbostic break; 968*52889Sbostic } 969*52889Sbostic 970*52889Sbostic /* look for another device that is ready */ 971*52889Sbostic for (i = 0; i < ASC_NCMD; i++) { 972*52889Sbostic /* don't restart a disconnected command */ 973*52889Sbostic if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 974*52889Sbostic continue; 975*52889Sbostic asc_startcmd(asc, i); 976*52889Sbostic break; 977*52889Sbostic } 978*52889Sbostic 979*52889Sbostic /* signal device driver that the command is done */ 980*52889Sbostic (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 981*52889Sbostic state->buflen, state->statusByte); 982*52889Sbostic 983*52889Sbostic return (0); 984*52889Sbostic } 985*52889Sbostic 986*52889Sbostic /* ARGSUSED */ 987*52889Sbostic static int 988*52889Sbostic asc_dma_in(asc, status, ss, ir) 989*52889Sbostic register asc_softc_t asc; 990*52889Sbostic register int status, ss, ir; 991*52889Sbostic { 992*52889Sbostic register asc_regmap_t *regs = asc->regs; 993*52889Sbostic register State *state = &asc->st[asc->target]; 994*52889Sbostic register int len, fifo; 995*52889Sbostic 996*52889Sbostic /* check for previous chunk in buffer */ 997*52889Sbostic if (!(state->flags & FIRST_DMA)) { 998*52889Sbostic /* 999*52889Sbostic * Only count bytes that have been copied to memory. 1000*52889Sbostic * There may be some bytes in the FIFO if synchonous transfers 1001*52889Sbostic * are in progress. 1002*52889Sbostic */ 1003*52889Sbostic ASC_TC_GET(regs, len); 1004*52889Sbostic len = state->dmalen - len; 1005*52889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 1006*52889Sbostic state->buf += len; 1007*52889Sbostic state->buflen -= len; 1008*52889Sbostic } else 1009*52889Sbostic state->flags &= ~FIRST_DMA; 1010*52889Sbostic 1011*52889Sbostic /* setup to start reading next chunk */ 1012*52889Sbostic len = state->buflen; 1013*52889Sbostic if (len > state->dmaBufSize) 1014*52889Sbostic len = state->dmaBufSize; 1015*52889Sbostic state->dmalen = len; 1016*52889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 1017*52889Sbostic ASC_TC_PUT(regs, len); 1018*52889Sbostic if (len != state->buflen) { 1019*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1020*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESUME_IN]; 1021*52889Sbostic return (0); 1022*52889Sbostic } 1023*52889Sbostic return (1); 1024*52889Sbostic } 1025*52889Sbostic 1026*52889Sbostic /* ARGSUSED */ 1027*52889Sbostic static int 1028*52889Sbostic asc_last_dma_in(asc, status, ss, ir) 1029*52889Sbostic register asc_softc_t asc; 1030*52889Sbostic register int status, ss, ir; 1031*52889Sbostic { 1032*52889Sbostic register asc_regmap_t *regs = asc->regs; 1033*52889Sbostic register State *state = &asc->st[asc->target]; 1034*52889Sbostic register int len, fifo; 1035*52889Sbostic 1036*52889Sbostic /* copy data from buffer to main memory */ 1037*52889Sbostic ASC_TC_GET(regs, len); 1038*52889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1039*52889Sbostic #ifdef DEBUG 1040*52889Sbostic if (asc_debug > 2 || len || fifo) /* XXX */ 1041*52889Sbostic printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1042*52889Sbostic state->buflen, state->dmalen, len, fifo); 1043*52889Sbostic #endif 1044*52889Sbostic if (fifo) { 1045*52889Sbostic regs->asc_cmd = ASC_CMD_FLUSH; 1046*52889Sbostic MachEmptyWriteBuffer(); 1047*52889Sbostic } 1048*52889Sbostic len = state->dmalen - len; 1049*52889Sbostic state->buflen -= len; 1050*52889Sbostic bcopy(state->dmaBufAddr, state->buf, len); 1051*52889Sbostic 1052*52889Sbostic return (1); 1053*52889Sbostic } 1054*52889Sbostic 1055*52889Sbostic /* ARGSUSED */ 1056*52889Sbostic static int 1057*52889Sbostic asc_resume_dma_in(asc, status, ss, ir) 1058*52889Sbostic register asc_softc_t asc; 1059*52889Sbostic register int status, ss, ir; 1060*52889Sbostic { 1061*52889Sbostic register asc_regmap_t *regs = asc->regs; 1062*52889Sbostic register State *state = &asc->st[asc->target]; 1063*52889Sbostic register int len, off; 1064*52889Sbostic 1065*52889Sbostic /* setup to finish reading the current chunk */ 1066*52889Sbostic len = state->dmaresid; 1067*52889Sbostic off = state->dmalen - len; 1068*52889Sbostic if ((off & 1) && state->sync_offset) { 1069*52889Sbostic printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1070*52889Sbostic state->dmalen, len, off); /* XXX */ 1071*52889Sbostic regs->asc_res_fifo = state->dmaBufAddr[off]; 1072*52889Sbostic } 1073*52889Sbostic *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off); 1074*52889Sbostic ASC_TC_PUT(regs, len); 1075*52889Sbostic if (state->dmalen != state->buflen) { 1076*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1077*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESUME_IN]; 1078*52889Sbostic return (0); 1079*52889Sbostic } 1080*52889Sbostic return (1); 1081*52889Sbostic } 1082*52889Sbostic 1083*52889Sbostic /* ARGSUSED */ 1084*52889Sbostic static int 1085*52889Sbostic asc_dma_out(asc, status, ss, ir) 1086*52889Sbostic register asc_softc_t asc; 1087*52889Sbostic register int status, ss, ir; 1088*52889Sbostic { 1089*52889Sbostic register asc_regmap_t *regs = asc->regs; 1090*52889Sbostic register State *state = &asc->st[asc->target]; 1091*52889Sbostic register int len, fifo; 1092*52889Sbostic 1093*52889Sbostic if (!(state->flags & FIRST_DMA)) { 1094*52889Sbostic /* check to be sure previous chunk was finished */ 1095*52889Sbostic ASC_TC_GET(regs, len); 1096*52889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1097*52889Sbostic if (len || fifo) 1098*52889Sbostic printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1099*52889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 1100*52889Sbostic len += fifo; 1101*52889Sbostic len = state->dmalen - len; 1102*52889Sbostic state->buflen -= len; 1103*52889Sbostic state->buf += len; 1104*52889Sbostic 1105*52889Sbostic /* setup for this chunck */ 1106*52889Sbostic len = state->buflen; 1107*52889Sbostic if (len > state->dmaBufSize) 1108*52889Sbostic len = state->dmaBufSize; 1109*52889Sbostic state->dmalen = len; 1110*52889Sbostic bcopy(state->buf, state->dmaBufAddr, len); 1111*52889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 1112*52889Sbostic } else 1113*52889Sbostic state->flags &= ~FIRST_DMA; 1114*52889Sbostic 1115*52889Sbostic #ifdef DEBUG 1116*52889Sbostic if (asc_debug > 2) 1117*52889Sbostic printf("asc_dma_out: dmalen %d fifo %d\n", 1118*52889Sbostic state->dmalen, 1119*52889Sbostic regs->asc_flags & ASC_FLAGS_FIFO_CNT); 1120*52889Sbostic #endif 1121*52889Sbostic len = state->dmalen; 1122*52889Sbostic ASC_TC_PUT(regs, len); 1123*52889Sbostic 1124*52889Sbostic /* check for next chunk */ 1125*52889Sbostic if (len != state->buflen) { 1126*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1127*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESUME_OUT]; 1128*52889Sbostic return (0); 1129*52889Sbostic } 1130*52889Sbostic return (1); 1131*52889Sbostic } 1132*52889Sbostic 1133*52889Sbostic /* ARGSUSED */ 1134*52889Sbostic static int 1135*52889Sbostic asc_last_dma_out(asc, status, ss, ir) 1136*52889Sbostic register asc_softc_t asc; 1137*52889Sbostic register int status, ss, ir; 1138*52889Sbostic { 1139*52889Sbostic register asc_regmap_t *regs = asc->regs; 1140*52889Sbostic register State *state = &asc->st[asc->target]; 1141*52889Sbostic register int len, fifo; 1142*52889Sbostic 1143*52889Sbostic len = state->dmalen; 1144*52889Sbostic ASC_TC_GET(regs, len); 1145*52889Sbostic fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1146*52889Sbostic 1147*52889Sbostic #ifdef DEBUG 1148*52889Sbostic if (asc_debug > 2) 1149*52889Sbostic printf("asc_last_dma_out: dmalen %d tc %d fifo %d\n", 1150*52889Sbostic state->dmalen, len, fifo); 1151*52889Sbostic #endif 1152*52889Sbostic 1153*52889Sbostic if (len || fifo) 1154*52889Sbostic printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1155*52889Sbostic state->buflen, state->dmalen, len, fifo); /* XXX */ 1156*52889Sbostic len += fifo; 1157*52889Sbostic len = state->dmalen - len; 1158*52889Sbostic state->buflen -= len; 1159*52889Sbostic return (1); 1160*52889Sbostic } 1161*52889Sbostic 1162*52889Sbostic /* ARGSUSED */ 1163*52889Sbostic static int 1164*52889Sbostic asc_resume_dma_out(asc, status, ss, ir) 1165*52889Sbostic register asc_softc_t asc; 1166*52889Sbostic register int status, ss, ir; 1167*52889Sbostic { 1168*52889Sbostic register asc_regmap_t *regs = asc->regs; 1169*52889Sbostic register State *state = &asc->st[asc->target]; 1170*52889Sbostic register int len, off; 1171*52889Sbostic 1172*52889Sbostic /* setup to finish writing this chunk */ 1173*52889Sbostic len = state->dmaresid; 1174*52889Sbostic off = state->dmalen - len; 1175*52889Sbostic if (off & 1) { 1176*52889Sbostic printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1177*52889Sbostic state->dmalen, len, off); /* XXX */ 1178*52889Sbostic regs->asc_fifo = state->dmaBufAddr[off]; 1179*52889Sbostic off++; 1180*52889Sbostic len--; 1181*52889Sbostic } 1182*52889Sbostic *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off); 1183*52889Sbostic ASC_TC_PUT(regs, len); 1184*52889Sbostic if (state->dmalen != state->buflen) { 1185*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1186*52889Sbostic asc->script = &asc_scripts[SCRIPT_RESUME_OUT]; 1187*52889Sbostic return (0); 1188*52889Sbostic } 1189*52889Sbostic return (1); 1190*52889Sbostic } 1191*52889Sbostic 1192*52889Sbostic /* ARGSUSED */ 1193*52889Sbostic static int 1194*52889Sbostic asc_sendsync(asc, status, ss, ir) 1195*52889Sbostic register asc_softc_t asc; 1196*52889Sbostic register int status, ss, ir; 1197*52889Sbostic { 1198*52889Sbostic register asc_regmap_t *regs = asc->regs; 1199*52889Sbostic 1200*52889Sbostic /* 1201*52889Sbostic * Phase is MSG_OUT here. 1202*52889Sbostic * Try sync negotiation, unless prohibited 1203*52889Sbostic */ 1204*52889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 1205*52889Sbostic MachEmptyWriteBuffer(); 1206*52889Sbostic regs->asc_fifo = 3; 1207*52889Sbostic MachEmptyWriteBuffer(); 1208*52889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1209*52889Sbostic MachEmptyWriteBuffer(); 1210*52889Sbostic regs->asc_fifo = SCSI_MIN_PERIOD; 1211*52889Sbostic MachEmptyWriteBuffer(); 1212*52889Sbostic regs->asc_fifo = ASC_MAX_OFFSET; 1213*52889Sbostic return (1); 1214*52889Sbostic } 1215*52889Sbostic 1216*52889Sbostic /* ARGSUSED */ 1217*52889Sbostic static int 1218*52889Sbostic asc_replysync(asc, status, ss, ir) 1219*52889Sbostic register asc_softc_t asc; 1220*52889Sbostic register int status, ss, ir; 1221*52889Sbostic { 1222*52889Sbostic register asc_regmap_t *regs = asc->regs; 1223*52889Sbostic register State *state = &asc->st[asc->target]; 1224*52889Sbostic 1225*52889Sbostic #ifdef DEBUG 1226*52889Sbostic if (asc_debug > 2) 1227*52889Sbostic printf("asc_replysync: %x %x\n", 1228*52889Sbostic asc_to_scsi_period[state->sync_period], 1229*52889Sbostic state->sync_offset); 1230*52889Sbostic #endif 1231*52889Sbostic /* send synchronous transfer in response to a request */ 1232*52889Sbostic regs->asc_fifo = SCSI_EXTENDED_MSG; 1233*52889Sbostic MachEmptyWriteBuffer(); 1234*52889Sbostic regs->asc_fifo = 3; 1235*52889Sbostic MachEmptyWriteBuffer(); 1236*52889Sbostic regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1237*52889Sbostic MachEmptyWriteBuffer(); 1238*52889Sbostic regs->asc_fifo = asc_to_scsi_period[state->sync_period]; 1239*52889Sbostic MachEmptyWriteBuffer(); 1240*52889Sbostic regs->asc_fifo = state->sync_offset; 1241*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 1242*52889Sbostic 1243*52889Sbostic /* return to the appropriate script */ 1244*52889Sbostic if (!state->script) { 1245*52889Sbostic #ifdef DEBUG 1246*52889Sbostic asc_DumpLog("asc_replsync"); 1247*52889Sbostic #endif 1248*52889Sbostic panic("asc_replysync"); 1249*52889Sbostic } 1250*52889Sbostic asc->script = state->script; 1251*52889Sbostic state->script = (script_t *)0; 1252*52889Sbostic return (0); 1253*52889Sbostic } 1254*52889Sbostic 1255*52889Sbostic /* ARGSUSED */ 1256*52889Sbostic static int 1257*52889Sbostic asc_recvmsg(asc, status, ss, ir) 1258*52889Sbostic register asc_softc_t asc; 1259*52889Sbostic register int status, ss, ir; 1260*52889Sbostic { 1261*52889Sbostic register asc_regmap_t *regs = asc->regs; 1262*52889Sbostic register State *state = &asc->st[asc->target]; 1263*52889Sbostic register int msg; 1264*52889Sbostic int i; 1265*52889Sbostic 1266*52889Sbostic /* read one message byte */ 1267*52889Sbostic msg = regs->asc_fifo; 1268*52889Sbostic #ifdef DEBUG 1269*52889Sbostic if (asc_logp == asc_log) 1270*52889Sbostic asc_log[NLOG - 1].msg = msg; 1271*52889Sbostic else 1272*52889Sbostic asc_logp[-1].msg = msg; 1273*52889Sbostic #endif 1274*52889Sbostic 1275*52889Sbostic /* check for multi-byte message */ 1276*52889Sbostic if (state->msglen != 0) { 1277*52889Sbostic /* first byte is the message length */ 1278*52889Sbostic if (state->msglen < 0) { 1279*52889Sbostic state->msglen = msg; 1280*52889Sbostic return (1); 1281*52889Sbostic } 1282*52889Sbostic if (state->msgcnt >= state->msglen) 1283*52889Sbostic goto abort; 1284*52889Sbostic state->msg_in[state->msgcnt++] = msg; 1285*52889Sbostic 1286*52889Sbostic /* did we just read the last byte of the message? */ 1287*52889Sbostic if (state->msgcnt != state->msglen) 1288*52889Sbostic return (1); 1289*52889Sbostic 1290*52889Sbostic /* process an extended message */ 1291*52889Sbostic #ifdef DEBUG 1292*52889Sbostic if (asc_debug > 2) 1293*52889Sbostic printf("asc_recvmsg: msg %x %x %x\n", 1294*52889Sbostic state->msg_in[0], 1295*52889Sbostic state->msg_in[1], 1296*52889Sbostic state->msg_in[2]); 1297*52889Sbostic #endif 1298*52889Sbostic switch (state->msg_in[0]) { 1299*52889Sbostic case SCSI_SYNCHRONOUS_XFER: 1300*52889Sbostic state->flags |= DID_SYNC; 1301*52889Sbostic state->sync_offset = state->msg_in[2]; 1302*52889Sbostic 1303*52889Sbostic /* convert SCSI period to ASC period */ 1304*52889Sbostic i = state->msg_in[1] / 10; 1305*52889Sbostic if (i < ASC_MIN_PERIOD) 1306*52889Sbostic i = ASC_MIN_PERIOD; 1307*52889Sbostic else if (i >= ASC_MAX_PERIOD) { 1308*52889Sbostic /* can't do sync transfer, period too long */ 1309*52889Sbostic printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1310*52889Sbostic asc - asc_softc, asc->target, i); 1311*52889Sbostic i = ASC_MAX_PERIOD; 1312*52889Sbostic state->sync_offset = 0; 1313*52889Sbostic } 1314*52889Sbostic if ((i * 10) != state->msg_in[1]) 1315*52889Sbostic i++; 1316*52889Sbostic state->sync_period = i & 0x1F; 1317*52889Sbostic 1318*52889Sbostic /* 1319*52889Sbostic * If this is a request, check minimums and 1320*52889Sbostic * send back an acknowledge. 1321*52889Sbostic */ 1322*52889Sbostic if (!(state->flags & TRY_SYNC)) { 1323*52889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 1324*52889Sbostic MachEmptyWriteBuffer(); 1325*52889Sbostic 1326*52889Sbostic if (state->sync_period < ASC_MIN_PERIOD) 1327*52889Sbostic state->sync_period = 1328*52889Sbostic ASC_MIN_PERIOD; 1329*52889Sbostic if (state->sync_offset > ASC_MAX_OFFSET) 1330*52889Sbostic state->sync_offset = 1331*52889Sbostic ASC_MAX_OFFSET; 1332*52889Sbostic asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1333*52889Sbostic regs->asc_syn_p = state->sync_period; 1334*52889Sbostic regs->asc_syn_o = state->sync_offset; 1335*52889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1336*52889Sbostic return (0); 1337*52889Sbostic } 1338*52889Sbostic 1339*52889Sbostic regs->asc_syn_p = state->sync_period; 1340*52889Sbostic regs->asc_syn_o = state->sync_offset; 1341*52889Sbostic goto done; 1342*52889Sbostic 1343*52889Sbostic default: 1344*52889Sbostic printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1345*52889Sbostic asc - asc_softc, asc->target, 1346*52889Sbostic state->msg_in[0]); 1347*52889Sbostic goto reject; 1348*52889Sbostic } 1349*52889Sbostic } 1350*52889Sbostic 1351*52889Sbostic /* process first byte of a message */ 1352*52889Sbostic #ifdef DEBUG 1353*52889Sbostic if (asc_debug > 2) 1354*52889Sbostic printf("asc_recvmsg: msg %x\n", msg); 1355*52889Sbostic #endif 1356*52889Sbostic switch (msg) { 1357*52889Sbostic #if 0 1358*52889Sbostic case SCSI_MESSAGE_REJECT: 1359*52889Sbostic printf(" did not like SYNCH xfer "); /* XXX */ 1360*52889Sbostic state->flags |= DID_SYNC; 1361*52889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1362*52889Sbostic status = asc_wait(regs, ASC_CSR_INT); 1363*52889Sbostic ir = regs->asc_intr; 1364*52889Sbostic /* some just break out here, some dont */ 1365*52889Sbostic if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1366*52889Sbostic regs->asc_fifo = SCSI_ABORT; 1367*52889Sbostic regs->asc_cmd = ASC_CMD_XFER_INFO; 1368*52889Sbostic status = asc_wait(regs, ASC_CSR_INT); 1369*52889Sbostic ir = regs->asc_intr; 1370*52889Sbostic } 1371*52889Sbostic if (ir & ASC_INT_DISC) { 1372*52889Sbostic asc_end(asc, status, 0, ir); 1373*52889Sbostic return (0); 1374*52889Sbostic } 1375*52889Sbostic goto status; 1376*52889Sbostic #endif 1377*52889Sbostic 1378*52889Sbostic case SCSI_EXTENDED_MSG: /* read an extended message */ 1379*52889Sbostic /* setup to read message length next */ 1380*52889Sbostic state->msglen = -1; 1381*52889Sbostic state->msgcnt = 0; 1382*52889Sbostic return (1); 1383*52889Sbostic 1384*52889Sbostic case SCSI_NO_OP: 1385*52889Sbostic break; 1386*52889Sbostic 1387*52889Sbostic case SCSI_SAVE_DATA_POINTER: 1388*52889Sbostic /* expect another message */ 1389*52889Sbostic return (1); 1390*52889Sbostic 1391*52889Sbostic case SCSI_RESTORE_POINTERS: 1392*52889Sbostic /* 1393*52889Sbostic * Need to do the following if resuming synchonous data in 1394*52889Sbostic * on an odd byte boundary. 1395*52889Sbostic regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1396*52889Sbostic */ 1397*52889Sbostic break; 1398*52889Sbostic 1399*52889Sbostic case SCSI_DISCONNECT: 1400*52889Sbostic if (state->flags & DISCONN) 1401*52889Sbostic goto abort; 1402*52889Sbostic state->flags |= DISCONN; 1403*52889Sbostic break; 1404*52889Sbostic 1405*52889Sbostic default: 1406*52889Sbostic printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1407*52889Sbostic asc - asc_softc, asc->target, msg); 1408*52889Sbostic reject: 1409*52889Sbostic /* request a message out before acknowledging this message */ 1410*52889Sbostic state->msg_out = SCSI_MESSAGE_REJECT; 1411*52889Sbostic regs->asc_cmd = ASC_CMD_SET_ATN; 1412*52889Sbostic MachEmptyWriteBuffer(); 1413*52889Sbostic } 1414*52889Sbostic 1415*52889Sbostic done: 1416*52889Sbostic /* return to original script */ 1417*52889Sbostic regs->asc_cmd = ASC_CMD_MSG_ACPT; 1418*52889Sbostic if (!state->script) { 1419*52889Sbostic abort: 1420*52889Sbostic #ifdef DEBUG 1421*52889Sbostic asc_DumpLog("asc_recvmsg"); 1422*52889Sbostic #endif 1423*52889Sbostic panic("asc_recvmsg"); 1424*52889Sbostic } 1425*52889Sbostic asc->script = state->script; 1426*52889Sbostic state->script = (script_t *)0; 1427*52889Sbostic return (0); 1428*52889Sbostic } 1429*52889Sbostic 1430*52889Sbostic #ifdef DEBUG 1431*52889Sbostic asc_DumpLog(str) 1432*52889Sbostic char *str; 1433*52889Sbostic { 1434*52889Sbostic register struct asc_log *lp; 1435*52889Sbostic register u_int status; 1436*52889Sbostic 1437*52889Sbostic printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1438*52889Sbostic asc_debug_bn, asc_debug_sz); 1439*52889Sbostic lp = asc_logp + 1; 1440*52889Sbostic if (lp > &asc_log[NLOG]) 1441*52889Sbostic lp = asc_log; 1442*52889Sbostic while (lp != asc_logp) { 1443*52889Sbostic status = lp->status; 1444*52889Sbostic printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 1445*52889Sbostic status >> 24, 1446*52889Sbostic lp->target, 1447*52889Sbostic (status >> 16) & 0xFF, 1448*52889Sbostic (status >> 8) & 0xFF, 1449*52889Sbostic status & 0XFF, 1450*52889Sbostic lp->state, 1451*52889Sbostic asc_scripts[lp->state].condition, 1452*52889Sbostic lp->msg); 1453*52889Sbostic if (++lp >= &asc_log[NLOG]) 1454*52889Sbostic lp = asc_log; 1455*52889Sbostic } 1456*52889Sbostic } 1457*52889Sbostic #endif 1458*52889Sbostic 1459*52889Sbostic #endif /* NASC > 0 */ 1460