1 /*- 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Ralph Campbell and Rick Macklem. 7 * 8 * %sccs.include.redist.c% 9 * 10 * @(#)asc.c 7.12 (Berkeley) 03/23/93 11 */ 12 13 /* 14 * Mach Operating System 15 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 16 * All Rights Reserved. 17 * 18 * Permission to use, copy, modify and distribute this software and its 19 * documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie the 36 * rights to redistribute these changes. 37 */ 38 39 /* 40 * HISTORY 41 * $Log: scsi_53C94_hdw.c,v $ 42 * Revision 2.5 91/02/05 17:45:07 mrt 43 * Added author notices 44 * [91/02/04 11:18:43 mrt] 45 * 46 * Changed to use new Mach copyright 47 * [91/02/02 12:17:20 mrt] 48 * 49 * Revision 2.4 91/01/08 15:48:24 rpd 50 * Added continuation argument to thread_block. 51 * [90/12/27 rpd] 52 * 53 * Revision 2.3 90/12/05 23:34:48 af 54 * Recovered from pmax merge.. and from the destruction of a disk. 55 * [90/12/03 23:40:40 af] 56 * 57 * Revision 2.1.1.1 90/11/01 03:39:09 af 58 * Created, from the DEC specs: 59 * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" 60 * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. 61 * And from the NCR data sheets 62 * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" 63 * [90/09/03 af] 64 */ 65 66 /* 67 * File: scsi_53C94_hdw.h 68 * Author: Alessandro Forin, Carnegie Mellon University 69 * Date: 9/90 70 * 71 * Bottom layer of the SCSI driver: chip-dependent functions 72 * 73 * This file contains the code that is specific to the NCR 53C94 74 * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start 75 * operation, and interrupt routine. 76 */ 77 78 /* 79 * This layer works based on small simple 'scripts' that are installed 80 * at the start of the command and drive the chip to completion. 81 * The idea comes from the specs of the NCR 53C700 'script' processor. 82 * 83 * There are various reasons for this, mainly 84 * - Performance: identify the common (successful) path, and follow it; 85 * at interrupt time no code is needed to find the current status 86 * - Code size: it should be easy to compact common operations 87 * - Adaptability: the code skeleton should adapt to different chips without 88 * terrible complications. 89 * - Error handling: and it is easy to modify the actions performed 90 * by the scripts to cope with strange but well identified sequences 91 * 92 */ 93 94 #include <asc.h> 95 #if NASC > 0 96 97 #include <sys/param.h> 98 #include <sys/systm.h> 99 #include <sys/dkstat.h> 100 #include <sys/buf.h> 101 #include <sys/conf.h> 102 #include <sys/errno.h> 103 104 #include <machine/machConst.h> 105 106 #include <pmax/dev/device.h> 107 #include <pmax/dev/scsi.h> 108 #include <pmax/dev/ascreg.h> 109 110 #include <pmax/pmax/asic.h> 111 #include <pmax/pmax/kmin.h> 112 #include <pmax/pmax/pmaxtype.h> 113 114 #define readback(a) { register int foo; foo = (a); } 115 extern int pmax_boardtype; 116 117 /* 118 * In 4ns ticks. 119 */ 120 int asc_to_scsi_period[] = { 121 32, 122 33, 123 34, 124 35, 125 5, 126 5, 127 6, 128 7, 129 8, 130 9, 131 10, 132 11, 133 12, 134 13, 135 14, 136 15, 137 16, 138 17, 139 18, 140 19, 141 20, 142 21, 143 22, 144 23, 145 24, 146 25, 147 26, 148 27, 149 28, 150 29, 151 30, 152 31, 153 }; 154 155 /* 156 * Internal forward declarations. 157 */ 158 static void asc_reset(); 159 static void asc_startcmd(); 160 161 #ifdef DEBUG 162 int asc_debug = 1; 163 int asc_debug_cmd; 164 int asc_debug_bn; 165 int asc_debug_sz; 166 #define NLOG 32 167 struct asc_log { 168 u_int status; 169 u_char state; 170 u_char msg; 171 int target; 172 int resid; 173 } asc_log[NLOG], *asc_logp = asc_log; 174 #define PACK(unit, status, ss, ir) \ 175 ((unit << 24) | (status << 16) | (ss << 8) | ir) 176 #endif 177 178 /* 179 * Scripts are entries in a state machine table. 180 * A script has four parts: a pre-condition, an action, a command to the chip, 181 * and an index into asc_scripts for the next state. The first triggers error 182 * handling if not satisfied and in our case it is formed by the 183 * values of the interrupt register and status register, this 184 * basically captures the phase of the bus and the TC and BS 185 * bits. The action part is just a function pointer, and the 186 * command is what the 53C94 should be told to do at the end 187 * of the action processing. This command is only issued and the 188 * script proceeds if the action routine returns TRUE. 189 * See asc_intr() for how and where this is all done. 190 */ 191 typedef struct script { 192 int condition; /* expected state at interrupt time */ 193 int (*action)(); /* extra operations */ 194 int command; /* command to the chip */ 195 struct script *next; /* index into asc_scripts for next state */ 196 } script_t; 197 198 /* Matching on the condition value */ 199 #define SCRIPT_MATCH(ir, csr) ((ir) | (((csr) & 0x67) << 8)) 200 201 /* forward decls of script actions */ 202 static int script_nop(); /* when nothing needed */ 203 static int asc_end(); /* all come to an end */ 204 static int asc_get_status(); /* get status from target */ 205 static int asc_dma_in(); /* start reading data from target */ 206 static int asc_last_dma_in(); /* cleanup after all data is read */ 207 static int asc_resume_in(); /* resume data in after a message */ 208 static int asc_resume_dma_in(); /* resume DMA after a disconnect */ 209 static int asc_dma_out(); /* send data to target via dma */ 210 static int asc_last_dma_out(); /* cleanup after all data is written */ 211 static int asc_resume_out(); /* resume data out after a message */ 212 static int asc_resume_dma_out(); /* resume DMA after a disconnect */ 213 static int asc_sendsync(); /* negotiate sync xfer */ 214 static int asc_replysync(); /* negotiate sync xfer */ 215 static int asc_msg_in(); /* process a message byte */ 216 static int asc_disconnect(); /* process an expected disconnect */ 217 218 /* Define the index into asc_scripts for various state transitions */ 219 #define SCRIPT_DATA_IN 0 220 #define SCRIPT_CONTINUE_IN 2 221 #define SCRIPT_DATA_OUT 3 222 #define SCRIPT_CONTINUE_OUT 5 223 #define SCRIPT_SIMPLE 6 224 #define SCRIPT_GET_STATUS 7 225 #define SCRIPT_MSG_IN 9 226 #define SCRIPT_REPLY_SYNC 11 227 #define SCRIPT_TRY_SYNC 12 228 #define SCRIPT_DISCONNECT 15 229 #define SCRIPT_RESEL 16 230 #define SCRIPT_RESUME_IN 17 231 #define SCRIPT_RESUME_DMA_IN 18 232 #define SCRIPT_RESUME_OUT 19 233 #define SCRIPT_RESUME_DMA_OUT 20 234 #define SCRIPT_RESUME_NO_DATA 21 235 236 /* 237 * Scripts 238 */ 239 script_t asc_scripts[] = { 240 /* start data in */ 241 {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAI), /* 0 */ 242 asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 243 &asc_scripts[SCRIPT_DATA_IN + 1]}, 244 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 1 */ 245 asc_last_dma_in, ASC_CMD_I_COMPLETE, 246 &asc_scripts[SCRIPT_GET_STATUS]}, 247 248 /* continue data in after a chunk is finished */ 249 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 2 */ 250 asc_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 251 &asc_scripts[SCRIPT_DATA_IN + 1]}, 252 253 /* start data out */ 254 {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_DATAO), /* 3 */ 255 asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 256 &asc_scripts[SCRIPT_DATA_OUT + 1]}, 257 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 4 */ 258 asc_last_dma_out, ASC_CMD_I_COMPLETE, 259 &asc_scripts[SCRIPT_GET_STATUS]}, 260 261 /* continue data out after a chunk is finished */ 262 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 5 */ 263 asc_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 264 &asc_scripts[SCRIPT_DATA_OUT + 1]}, 265 266 /* simple command with no data transfer */ 267 {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_STATUS), /* 6 */ 268 script_nop, ASC_CMD_I_COMPLETE, 269 &asc_scripts[SCRIPT_GET_STATUS]}, 270 271 /* get status and finish command */ 272 {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 7 */ 273 asc_get_status, ASC_CMD_MSG_ACPT, 274 &asc_scripts[SCRIPT_GET_STATUS + 1]}, 275 {SCRIPT_MATCH(ASC_INT_DISC, 0), /* 8 */ 276 asc_end, ASC_CMD_NOP, 277 &asc_scripts[SCRIPT_GET_STATUS + 1]}, 278 279 /* message in */ 280 {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 9 */ 281 asc_msg_in, ASC_CMD_MSG_ACPT, 282 &asc_scripts[SCRIPT_MSG_IN + 1]}, 283 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 10 */ 284 script_nop, ASC_CMD_XFER_INFO, 285 &asc_scripts[SCRIPT_MSG_IN]}, 286 287 /* send synchonous negotiation reply */ 288 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 11 */ 289 asc_replysync, ASC_CMD_XFER_INFO, 290 &asc_scripts[SCRIPT_REPLY_SYNC]}, 291 292 /* try to negotiate synchonous transfer parameters */ 293 {SCRIPT_MATCH(ASC_INT_FC | ASC_INT_BS, ASC_PHASE_MSG_OUT), /* 12 */ 294 asc_sendsync, ASC_CMD_XFER_INFO, 295 &asc_scripts[SCRIPT_TRY_SYNC + 1]}, 296 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_MSG_IN), /* 13 */ 297 script_nop, ASC_CMD_XFER_INFO, 298 &asc_scripts[SCRIPT_MSG_IN]}, 299 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_COMMAND), /* 14 */ 300 script_nop, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 301 &asc_scripts[SCRIPT_RESUME_NO_DATA]}, 302 303 /* handle a disconnect */ 304 {SCRIPT_MATCH(ASC_INT_DISC, ASC_PHASE_DATAO), /* 15 */ 305 asc_disconnect, ASC_CMD_ENABLE_SEL, 306 &asc_scripts[SCRIPT_RESEL]}, 307 308 /* reselect sequence: this is just a placeholder so match fails */ 309 {SCRIPT_MATCH(0, ASC_PHASE_MSG_IN), /* 16 */ 310 script_nop, ASC_CMD_MSG_ACPT, 311 &asc_scripts[SCRIPT_RESEL]}, 312 313 /* resume data in after a message */ 314 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 17 */ 315 asc_resume_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 316 &asc_scripts[SCRIPT_DATA_IN + 1]}, 317 318 /* resume partial DMA data in after a message */ 319 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAI), /* 18 */ 320 asc_resume_dma_in, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 321 &asc_scripts[SCRIPT_DATA_IN + 1]}, 322 323 /* resume data out after a message */ 324 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 19 */ 325 asc_resume_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 326 &asc_scripts[SCRIPT_DATA_OUT + 1]}, 327 328 /* resume partial DMA data out after a message */ 329 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_DATAO), /* 20 */ 330 asc_resume_dma_out, ASC_CMD_XFER_INFO | ASC_CMD_DMA, 331 &asc_scripts[SCRIPT_DATA_OUT + 1]}, 332 333 /* resume after a message when there is no more data */ 334 {SCRIPT_MATCH(ASC_INT_BS, ASC_PHASE_STATUS), /* 21 */ 335 script_nop, ASC_CMD_I_COMPLETE, 336 &asc_scripts[SCRIPT_GET_STATUS]}, 337 }; 338 339 /* 340 * State kept for each active SCSI device. 341 */ 342 typedef struct scsi_state { 343 script_t *script; /* saved script while processing error */ 344 int statusByte; /* status byte returned during STATUS_PHASE */ 345 int error; /* errno to pass back to device driver */ 346 u_char *dmaBufAddr; /* DMA buffer address */ 347 u_int dmaBufSize; /* DMA buffer size */ 348 int dmalen; /* amount to transfer in this chunk */ 349 int dmaresid; /* amount not transfered if chunk suspended */ 350 int buflen; /* total remaining amount of data to transfer */ 351 char *buf; /* current pointer within scsicmd->buf */ 352 int flags; /* see below */ 353 int msglen; /* number of message bytes to read */ 354 int msgcnt; /* number of message bytes received */ 355 u_char sync_period; /* DMA synchronous period */ 356 u_char sync_offset; /* DMA synchronous xfer offset or 0 if async */ 357 u_char msg_out; /* next MSG_OUT byte to send */ 358 u_char msg_in[16]; /* buffer for multibyte messages */ 359 } State; 360 361 /* state flags */ 362 #define DISCONN 0x01 /* true if currently disconnected from bus */ 363 #define DMA_IN_PROGRESS 0x02 /* true if data DMA started */ 364 #define DMA_IN 0x04 /* true if reading from SCSI device */ 365 #define DMA_OUT 0x10 /* true if writing to SCSI device */ 366 #define DID_SYNC 0x20 /* true if synchronous offset was negotiated */ 367 #define TRY_SYNC 0x40 /* true if try neg. synchronous offset */ 368 #define PARITY_ERR 0x80 /* true if parity error seen */ 369 370 /* 371 * State kept for each active SCSI host interface (53C94). 372 */ 373 struct asc_softc { 374 asc_regmap_t *regs; /* chip address */ 375 volatile int *dmar; /* DMA address register address */ 376 u_char *buff; /* RAM buffer address (uncached) */ 377 int myid; /* SCSI ID of this interface */ 378 int myidmask; /* ~(1 << myid) */ 379 int state; /* current SCSI connection state */ 380 int target; /* target SCSI ID if busy */ 381 script_t *script; /* next expected interrupt & action */ 382 ScsiCmd *cmd[ASC_NCMD]; /* active command indexed by SCSI ID */ 383 State st[ASC_NCMD]; /* state info for each active command */ 384 void (*dma_start)(); /* Start dma routine */ 385 void (*dma_end)(); /* End dma routine */ 386 u_char *dma_next; 387 int dma_xfer; /* Dma len still to go */ 388 int min_period; /* Min transfer period clk/byte */ 389 int max_period; /* Max transfer period clk/byte */ 390 int ccf; /* CCF, whatever that really is? */ 391 int timeout_250; /* 250ms timeout */ 392 int tb_ticks; /* 4ns. ticks/tb channel ticks */ 393 } asc_softc[NASC]; 394 395 #define ASC_STATE_IDLE 0 /* idle state */ 396 #define ASC_STATE_BUSY 1 /* selecting or currently connected */ 397 #define ASC_STATE_TARGET 2 /* currently selected as target */ 398 #define ASC_STATE_RESEL 3 /* currently waiting for reselect */ 399 400 typedef struct asc_softc *asc_softc_t; 401 402 /* 403 * Dma operations. 404 */ 405 #define ASCDMA_READ 1 406 #define ASCDMA_WRITE 2 407 static void tb_dma_start(), tb_dma_end(), asic_dma_start(), asic_dma_end(); 408 extern u_long asc_iomem; 409 extern u_long asic_base; 410 411 /* 412 * Definition of the controller for the auto-configuration program. 413 */ 414 int asc_probe(); 415 void asc_start(); 416 void asc_intr(); 417 struct driver ascdriver = { 418 "asc", asc_probe, asc_start, 0, asc_intr, 419 }; 420 421 /* 422 * Test to see if device is present. 423 * Return true if found and initialized ok. 424 */ 425 asc_probe(cp) 426 register struct pmax_ctlr *cp; 427 { 428 register asc_softc_t asc; 429 register asc_regmap_t *regs; 430 int unit, id, s, i; 431 int bufsiz; 432 433 if ((unit = cp->pmax_unit) >= NASC) 434 return (0); 435 if (badaddr(cp->pmax_addr + ASC_OFFSET_53C94, 1)) 436 return (0); 437 asc = &asc_softc[unit]; 438 439 /* 440 * Initialize hw descriptor, cache some pointers 441 */ 442 asc->regs = (asc_regmap_t *)(cp->pmax_addr + ASC_OFFSET_53C94); 443 444 /* 445 * Set up machine dependencies. 446 * 1) how to do dma 447 * 2) timing based on turbochannel frequency 448 */ 449 switch (pmax_boardtype) { 450 case DS_3MIN: 451 case DS_MAXINE: 452 case DS_3MAXPLUS: 453 if (unit == 0) { 454 asc->buff = (u_char *)MACH_PHYS_TO_UNCACHED(asc_iomem); 455 bufsiz = 8192; 456 *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 457 *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 458 *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 459 asc->dma_start = asic_dma_start; 460 asc->dma_end = asic_dma_end; 461 break; 462 } 463 /* 464 * Fall through for turbochannel option. 465 */ 466 case DS_3MAX: 467 default: 468 asc->dmar = (volatile int *)(cp->pmax_addr + ASC_OFFSET_DMAR); 469 asc->buff = (u_char *)(cp->pmax_addr + ASC_OFFSET_RAM); 470 bufsiz = PER_TGT_DMA_SIZE; 471 asc->dma_start = tb_dma_start; 472 asc->dma_end = tb_dma_end; 473 }; 474 /* 475 * Now for timing. The 3max has a 25Mhz tb whereas the 3min and 476 * maxine are 12.5Mhz. 477 */ 478 switch (pmax_boardtype) { 479 case DS_3MAX: 480 case DS_3MAXPLUS: 481 asc->min_period = ASC_MIN_PERIOD25; 482 asc->max_period = ASC_MAX_PERIOD25; 483 asc->ccf = ASC_CCF(25); 484 asc->timeout_250 = ASC_TIMEOUT_250(25, asc->ccf); 485 asc->tb_ticks = 10; 486 break; 487 case DS_3MIN: 488 case DS_MAXINE: 489 default: 490 asc->min_period = ASC_MIN_PERIOD12; 491 asc->max_period = ASC_MAX_PERIOD12; 492 asc->ccf = ASC_CCF(13); 493 asc->timeout_250 = ASC_TIMEOUT_250(13, asc->ccf); 494 asc->tb_ticks = 20; 495 break; 496 }; 497 498 asc->state = ASC_STATE_IDLE; 499 asc->target = -1; 500 501 regs = asc->regs; 502 503 /* 504 * Reset chip, fully. Note that interrupts are already enabled. 505 */ 506 s = splbio(); 507 508 /* preserve our ID for now */ 509 asc->myid = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 510 asc->myidmask = ~(1 << asc->myid); 511 512 asc_reset(asc, regs); 513 514 /* 515 * Our SCSI id on the bus. 516 * The user can set this via the prom on 3maxen/pmaxen. 517 * If this changes it is easy to fix: make a default that 518 * can be changed as boot arg. 519 */ 520 #ifdef unneeded 521 regs->asc_cnfg1 = (regs->asc_cnfg1 & ~ASC_CNFG1_MY_BUS_ID) | 522 (scsi_initiator_id[unit] & 0x7); 523 #endif 524 id = regs->asc_cnfg1 & ASC_CNFG1_MY_BUS_ID; 525 splx(s); 526 527 /* 528 * Statically partition the DMA buffer between targets. 529 * This way we will eventually be able to attach/detach 530 * drives on-fly. And 18k/target is plenty for normal use. 531 */ 532 533 /* 534 * Give each target its own DMA buffer region. 535 * We may want to try ping ponging buffers later. 536 */ 537 for (i = 0; i < ASC_NCMD; i++) { 538 asc->st[i].dmaBufAddr = asc->buff + bufsiz * i; 539 asc->st[i].dmaBufSize = bufsiz; 540 } 541 printf("asc%d at nexus0 csr 0x%x priority %d SCSI id %d\n", 542 unit, cp->pmax_addr, cp->pmax_pri, id); 543 return (1); 544 } 545 546 /* 547 * Start activity on a SCSI device. 548 * We maintain information on each device separately since devices can 549 * connect/disconnect during an operation. 550 */ 551 void 552 asc_start(scsicmd) 553 register ScsiCmd *scsicmd; /* command to start */ 554 { 555 register struct scsi_device *sdp = scsicmd->sd; 556 register asc_softc_t asc = &asc_softc[sdp->sd_ctlr]; 557 int s; 558 559 s = splbio(); 560 /* 561 * Check if another command is already in progress. 562 * We may have to change this if we allow SCSI devices with 563 * separate LUNs. 564 */ 565 if (asc->cmd[sdp->sd_drive]) { 566 printf("asc%d: device %s busy at start\n", sdp->sd_ctlr, 567 sdp->sd_driver->d_name); 568 (*sdp->sd_driver->d_done)(scsicmd->unit, EBUSY, 569 scsicmd->buflen, 0); 570 splx(s); 571 } 572 asc->cmd[sdp->sd_drive] = scsicmd; 573 asc_startcmd(asc, sdp->sd_drive); 574 splx(s); 575 } 576 577 static void 578 asc_reset(asc, regs) 579 asc_softc_t asc; 580 asc_regmap_t *regs; 581 { 582 583 /* 584 * Reset chip and wait till done 585 */ 586 regs->asc_cmd = ASC_CMD_RESET; 587 MachEmptyWriteBuffer(); DELAY(25); 588 589 /* spec says this is needed after reset */ 590 regs->asc_cmd = ASC_CMD_NOP; 591 MachEmptyWriteBuffer(); DELAY(25); 592 593 /* 594 * Set up various chip parameters 595 */ 596 regs->asc_ccf = asc->ccf; 597 MachEmptyWriteBuffer(); DELAY(25); 598 regs->asc_sel_timo = asc->timeout_250; 599 /* restore our ID */ 600 regs->asc_cnfg1 = asc->myid | ASC_CNFG1_P_CHECK; 601 /* include ASC_CNFG2_SCSI2 if you want to allow SCSI II commands */ 602 regs->asc_cnfg2 = /* ASC_CNFG2_RFB | ASC_CNFG2_SCSI2 | */ ASC_CNFG2_EPL; 603 regs->asc_cnfg3 = 0; 604 /* zero anything else */ 605 ASC_TC_PUT(regs, 0); 606 regs->asc_syn_p = asc->min_period; 607 regs->asc_syn_o = 0; /* async for now */ 608 MachEmptyWriteBuffer(); 609 } 610 611 /* 612 * Start a SCSI command on a target. 613 */ 614 static void 615 asc_startcmd(asc, target) 616 asc_softc_t asc; 617 int target; 618 { 619 register asc_regmap_t *regs; 620 register ScsiCmd *scsicmd; 621 register State *state; 622 int len; 623 624 /* 625 * See if another target is currently selected on this SCSI bus. 626 */ 627 if (asc->target >= 0) 628 return; 629 630 regs = asc->regs; 631 632 /* 633 * If a reselection is in progress, it is Ok to ignore it since 634 * the ASC will automatically cancel the command and flush 635 * the FIFO if the ASC is reselected before the command starts. 636 * If we try to use ASC_CMD_DISABLE_SEL, we can hang the system if 637 * a reselect occurs before starting the command. 638 */ 639 640 asc->state = ASC_STATE_BUSY; 641 asc->target = target; 642 643 /* cache some pointers */ 644 scsicmd = asc->cmd[target]; 645 state = &asc->st[target]; 646 647 #ifdef DEBUG 648 if (asc_debug > 1) { 649 printf("asc_startcmd: %s target %d cmd %x len %d\n", 650 scsicmd->sd->sd_driver->d_name, target, 651 scsicmd->cmd[0], scsicmd->buflen); 652 } 653 #endif 654 655 /* 656 * Init the chip and target state. 657 */ 658 state->flags = state->flags & DID_SYNC; 659 state->error = 0; 660 state->script = (script_t *)0; 661 state->msg_out = SCSI_NO_OP; 662 663 /* 664 * Copy command data to the DMA buffer. 665 */ 666 len = scsicmd->cmdlen + 1; 667 state->dmalen = len; 668 state->dmaBufAddr[0] = SCSI_DIS_REC_IDENTIFY; 669 bcopy(scsicmd->cmd, state->dmaBufAddr + 1, len); 670 671 /* check for simple SCSI command with no data transfer */ 672 if ((state->buflen = scsicmd->buflen) == 0) { 673 /* check for sync negotiation */ 674 if ((scsicmd->flags & SCSICMD_USE_SYNC) && 675 !(state->flags & DID_SYNC)) { 676 asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 677 state->flags |= TRY_SYNC; 678 } else 679 asc->script = &asc_scripts[SCRIPT_SIMPLE]; 680 state->buf = (char *)0; 681 } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 682 asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 683 state->buf = scsicmd->buf; 684 state->flags |= DMA_OUT; 685 } else { 686 asc->script = &asc_scripts[SCRIPT_DATA_IN]; 687 state->buf = scsicmd->buf; 688 state->flags |= DMA_IN; 689 } 690 691 #ifdef DEBUG 692 asc_debug_cmd = scsicmd->cmd[0]; 693 if (scsicmd->cmd[0] == SCSI_READ_EXT) { 694 asc_debug_bn = (scsicmd->cmd[2] << 24) | 695 (scsicmd->cmd[3] << 16) | 696 (scsicmd->cmd[4] << 8) | 697 scsicmd->cmd[5]; 698 asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 699 } 700 asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 701 asc_logp->target = asc->target; 702 asc_logp->state = asc->script - asc_scripts; 703 asc_logp->msg = SCSI_DIS_REC_IDENTIFY; 704 asc_logp->resid = scsicmd->buflen; 705 if (++asc_logp >= &asc_log[NLOG]) 706 asc_logp = asc_log; 707 #endif 708 709 /* initialize the DMA */ 710 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 711 ASC_TC_PUT(regs, len); 712 readback(regs->asc_cmd); 713 714 regs->asc_dbus_id = target; 715 readback(regs->asc_dbus_id); 716 regs->asc_syn_p = state->sync_period; 717 readback(regs->asc_syn_p); 718 regs->asc_syn_o = state->sync_offset; 719 readback(regs->asc_syn_o); 720 721 if (state->flags & TRY_SYNC) 722 regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 723 else 724 regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 725 readback(regs->asc_cmd); 726 } 727 728 /* 729 * Interrupt routine 730 * Take interrupts from the chip 731 * 732 * Implementation: 733 * Move along the current command's script if 734 * all is well, invoke error handler if not. 735 */ 736 void 737 asc_intr(unit) 738 int unit; 739 { 740 register asc_softc_t asc = &asc_softc[unit]; 741 register asc_regmap_t *regs = asc->regs; 742 register State *state; 743 register script_t *scpt; 744 register int ss, ir, status; 745 746 /* collect ephemeral information */ 747 status = regs->asc_status; 748 again: 749 ss = regs->asc_ss; 750 ir = regs->asc_intr; /* this resets the previous two */ 751 scpt = asc->script; 752 753 #ifdef DEBUG 754 asc_logp->status = PACK(unit, status, ss, ir); 755 asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 756 asc_logp->state = scpt - asc_scripts; 757 asc_logp->msg = -1; 758 asc_logp->resid = 0; 759 if (++asc_logp >= &asc_log[NLOG]) 760 asc_logp = asc_log; 761 if (asc_debug > 2) 762 printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 763 status, ss, ir, scpt - asc_scripts, scpt->condition); 764 #endif 765 766 /* check the expected state */ 767 if (SCRIPT_MATCH(ir, status) == scpt->condition) { 768 /* 769 * Perform the appropriate operation, then proceed. 770 */ 771 if ((*scpt->action)(asc, status, ss, ir)) { 772 regs->asc_cmd = scpt->command; 773 readback(regs->asc_cmd); 774 asc->script = scpt->next; 775 } 776 goto done; 777 } 778 779 /* 780 * Check for parity error. 781 * Hardware will automatically set ATN 782 * to request the device for a MSG_OUT phase. 783 */ 784 if (status & ASC_CSR_PE) { 785 printf("asc%d: SCSI device %d: incomming parity error seen\n", 786 asc - asc_softc, asc->target); 787 asc->st[asc->target].flags |= PARITY_ERR; 788 } 789 790 /* 791 * Check for gross error. 792 * Probably a bug in a device driver. 793 */ 794 if (status & ASC_CSR_GE) { 795 printf("asc%d: SCSI device %d: gross error\n", 796 asc - asc_softc, asc->target); 797 goto abort; 798 } 799 800 /* check for message in or out */ 801 if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 802 register int len, fifo; 803 804 state = &asc->st[asc->target]; 805 switch (ASC_PHASE(status)) { 806 case ASC_PHASE_DATAI: 807 case ASC_PHASE_DATAO: 808 ASC_TC_GET(regs, len); 809 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 810 printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 811 state->buflen, state->dmalen, len, fifo); 812 goto abort; 813 814 case ASC_PHASE_MSG_IN: 815 break; 816 817 case ASC_PHASE_MSG_OUT: 818 /* 819 * Check for parity error. 820 * Hardware will automatically set ATN 821 * to request the device for a MSG_OUT phase. 822 */ 823 if (state->flags & PARITY_ERR) { 824 state->flags &= ~PARITY_ERR; 825 state->msg_out = SCSI_MESSAGE_PARITY_ERROR; 826 /* reset message in counter */ 827 state->msglen = 0; 828 } else 829 state->msg_out = SCSI_NO_OP; 830 regs->asc_fifo = state->msg_out; 831 regs->asc_cmd = ASC_CMD_XFER_INFO; 832 readback(regs->asc_cmd); 833 goto done; 834 835 case ASC_PHASE_STATUS: 836 /* probably an error in the SCSI command */ 837 asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 838 regs->asc_cmd = ASC_CMD_I_COMPLETE; 839 readback(regs->asc_cmd); 840 goto done; 841 842 default: 843 goto abort; 844 } 845 846 if (state->script) 847 goto abort; 848 849 /* check for DMA in progress */ 850 ASC_TC_GET(regs, len); 851 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 852 /* flush any data in the FIFO */ 853 if (fifo) { 854 if (state->flags & DMA_OUT) 855 len += fifo; 856 else if (state->flags & DMA_IN) { 857 u_char *cp; 858 859 printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 860 state->dmalen, len, fifo); /* XXX */ 861 len += fifo; 862 cp = state->dmaBufAddr + (state->dmalen - len); 863 while (fifo-- > 0) 864 *cp++ = regs->asc_fifo; 865 } else 866 printf("asc_intr: dmalen %d len %d fifo %d\n", 867 state->dmalen, len, fifo); /* XXX */ 868 regs->asc_cmd = ASC_CMD_FLUSH; 869 readback(regs->asc_cmd); 870 DELAY(2); 871 } 872 if (len) { 873 /* save number of bytes still to be sent or received */ 874 state->dmaresid = len; 875 #ifdef DEBUG 876 if (asc_logp == asc_log) 877 asc_log[NLOG - 1].resid = len; 878 else 879 asc_logp[-1].resid = len; 880 #endif 881 /* setup state to resume to */ 882 if (state->flags & DMA_IN) { 883 /* 884 * Since the ASC_CNFG3_SRB bit of the 885 * cnfg3 register bit is not set, 886 * we just transferred an extra byte. 887 * Since we can't resume on an odd byte 888 * boundary, we copy the valid data out 889 * and resume DMA at the start address. 890 */ 891 if (len & 1) { 892 printf("asc_intr: msg in len %d (fifo %d)\n", 893 len, fifo); 894 len = state->dmalen - len; 895 goto do_in; 896 } 897 state->script = 898 &asc_scripts[SCRIPT_RESUME_DMA_IN]; 899 } else if (state->flags & DMA_OUT) 900 state->script = 901 &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 902 else 903 state->script = asc->script; 904 } else { 905 /* setup state to resume to */ 906 if (state->flags & DMA_IN) { 907 if (state->flags & DMA_IN_PROGRESS) { 908 len = state->dmalen; 909 do_in: 910 state->flags &= ~DMA_IN_PROGRESS; 911 (*asc->dma_end)(asc, state, ASCDMA_READ); 912 bcopy(state->dmaBufAddr, state->buf, 913 len); 914 state->buf += len; 915 state->buflen -= len; 916 } 917 if (state->buflen) 918 state->script = 919 &asc_scripts[SCRIPT_RESUME_IN]; 920 else 921 state->script = 922 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 923 } else if (state->flags & DMA_OUT) { 924 /* 925 * If this is the last chunk, the next expected 926 * state is to get status. 927 */ 928 if (state->flags & DMA_IN_PROGRESS) { 929 state->flags &= ~DMA_IN_PROGRESS; 930 (*asc->dma_end)(asc, state, ASCDMA_WRITE); 931 len = state->dmalen; 932 state->buf += len; 933 state->buflen -= len; 934 } 935 if (state->buflen) 936 state->script = 937 &asc_scripts[SCRIPT_RESUME_OUT]; 938 else 939 state->script = 940 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 941 } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 942 state->script = 943 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 944 else 945 state->script = asc->script; 946 } 947 948 /* setup to receive a message */ 949 asc->script = &asc_scripts[SCRIPT_MSG_IN]; 950 state->msglen = 0; 951 regs->asc_cmd = ASC_CMD_XFER_INFO; 952 readback(regs->asc_cmd); 953 goto done; 954 } 955 956 /* check for SCSI bus reset */ 957 if (ir & ASC_INT_RESET) { 958 register int i; 959 960 printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 961 /* need to flush any pending commands */ 962 for (i = 0; i < ASC_NCMD; i++) { 963 if (!asc->cmd[i]) 964 continue; 965 asc->st[i].error = EIO; 966 asc_end(asc, 0, 0, 0); 967 } 968 /* rearbitrate synchronous offset */ 969 for (i = 0; i < ASC_NCMD; i++) { 970 asc->st[i].sync_offset = 0; 971 asc->st[i].flags = 0; 972 } 973 asc->target = -1; 974 return; 975 } 976 977 /* check for command errors */ 978 if (ir & ASC_INT_ILL) 979 goto abort; 980 981 /* check for disconnect */ 982 if (ir & ASC_INT_DISC) { 983 state = &asc->st[asc->target]; 984 switch (ASC_SS(ss)) { 985 case 0: /* device did not respond */ 986 /* check for one of the starting scripts */ 987 switch (asc->script - asc_scripts) { 988 case SCRIPT_TRY_SYNC: 989 case SCRIPT_SIMPLE: 990 case SCRIPT_DATA_IN: 991 case SCRIPT_DATA_OUT: 992 if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { 993 regs->asc_cmd = ASC_CMD_FLUSH; 994 readback(regs->asc_cmd); 995 } 996 state->error = ENXIO; 997 asc_end(asc, status, ss, ir); 998 return; 999 } 1000 /* FALLTHROUGH */ 1001 1002 default: 1003 printf("asc%d: SCSI device %d: unexpected disconnect\n", 1004 asc - asc_softc, asc->target); 1005 /* 1006 * On rare occasions my RZ24 does a disconnect during 1007 * data in phase and the following seems to keep it 1008 * happy. 1009 * XXX Should a scsi disk ever do this?? 1010 */ 1011 asc->script = &asc_scripts[SCRIPT_RESEL]; 1012 asc->state = ASC_STATE_RESEL; 1013 state->flags |= DISCONN; 1014 regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1015 readback(regs->asc_cmd); 1016 return; 1017 } 1018 } 1019 1020 /* check for reselect */ 1021 if (ir & ASC_INT_RESEL) { 1022 unsigned fifo, id, msg; 1023 1024 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1025 if (fifo < 2) 1026 goto abort; 1027 /* read unencoded SCSI ID and convert to binary */ 1028 msg = regs->asc_fifo & asc->myidmask; 1029 for (id = 0; (msg & 1) == 0; id++) 1030 msg >>= 1; 1031 /* read identify message */ 1032 msg = regs->asc_fifo; 1033 #ifdef DEBUG 1034 if (asc_logp == asc_log) 1035 asc_log[NLOG - 1].msg = msg; 1036 else 1037 asc_logp[-1].msg = msg; 1038 #endif 1039 asc->state = ASC_STATE_BUSY; 1040 asc->target = id; 1041 state = &asc->st[id]; 1042 asc->script = state->script; 1043 state->script = (script_t *)0; 1044 if (!(state->flags & DISCONN)) 1045 goto abort; 1046 state->flags &= ~DISCONN; 1047 regs->asc_syn_p = state->sync_period; 1048 regs->asc_syn_o = state->sync_offset; 1049 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1050 readback(regs->asc_cmd); 1051 goto done; 1052 } 1053 1054 /* check if we are being selected as a target */ 1055 if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 1056 goto abort; 1057 1058 /* 1059 * 'ir' must be just ASC_INT_FC. 1060 * This is normal if canceling an ASC_ENABLE_SEL. 1061 */ 1062 1063 done: 1064 MachEmptyWriteBuffer(); 1065 /* watch out for HW race conditions and setup & hold time violations */ 1066 ir = regs->asc_status; 1067 while (ir != (status = regs->asc_status)) 1068 ir = status; 1069 if (status & ASC_CSR_INT) 1070 goto again; 1071 return; 1072 1073 abort: 1074 #ifdef DEBUG 1075 asc_DumpLog("asc_intr"); 1076 #endif 1077 #if 0 1078 panic("asc_intr"); 1079 #else 1080 for (;;); 1081 #endif 1082 } 1083 1084 /* 1085 * All the many little things that the interrupt 1086 * routine might switch to. 1087 */ 1088 1089 /* ARGSUSED */ 1090 static int 1091 script_nop(asc, status, ss, ir) 1092 register asc_softc_t asc; 1093 register int status, ss, ir; 1094 { 1095 return (1); 1096 } 1097 1098 /* ARGSUSED */ 1099 static int 1100 asc_get_status(asc, status, ss, ir) 1101 register asc_softc_t asc; 1102 register int status, ss, ir; 1103 { 1104 register asc_regmap_t *regs = asc->regs; 1105 register int data; 1106 1107 /* 1108 * Get the last two bytes in the FIFO. 1109 */ 1110 if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 1111 printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 1112 asc_DumpLog("get_status"); /* XXX */ 1113 if (data < 2) { 1114 asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 1115 readback(asc->regs->asc_cmd); 1116 return (0); 1117 } 1118 do { 1119 data = regs->asc_fifo; 1120 } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 1121 } 1122 1123 /* save the status byte */ 1124 asc->st[asc->target].statusByte = data = regs->asc_fifo; 1125 #ifdef DEBUG 1126 if (asc_logp == asc_log) 1127 asc_log[NLOG - 1].msg = data; 1128 else 1129 asc_logp[-1].msg = data; 1130 #endif 1131 1132 /* get the (presumed) command_complete message */ 1133 if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 1134 return (1); 1135 1136 #ifdef DEBUG 1137 printf("asc_get_status: status %x cmd %x\n", 1138 asc->st[asc->target].statusByte, data); 1139 asc_DumpLog("asc_get_status"); 1140 #endif 1141 return (0); 1142 } 1143 1144 /* ARGSUSED */ 1145 static int 1146 asc_end(asc, status, ss, ir) 1147 register asc_softc_t asc; 1148 register int status, ss, ir; 1149 { 1150 register ScsiCmd *scsicmd; 1151 register State *state; 1152 register int i, target; 1153 1154 asc->state = ASC_STATE_IDLE; 1155 target = asc->target; 1156 asc->target = -1; 1157 scsicmd = asc->cmd[target]; 1158 asc->cmd[target] = (ScsiCmd *)0; 1159 state = &asc->st[target]; 1160 1161 #ifdef DEBUG 1162 if (asc_debug > 1) { 1163 printf("asc_end: %s target %d cmd %x err %d resid %d\n", 1164 scsicmd->sd->sd_driver->d_name, target, 1165 scsicmd->cmd[0], state->error, state->buflen); 1166 } 1167 #endif 1168 #ifdef DIAGNOSTIC 1169 if (target < 0 || !scsicmd) 1170 panic("asc_end"); 1171 #endif 1172 1173 /* look for disconnected devices */ 1174 for (i = 0; i < ASC_NCMD; i++) { 1175 if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 1176 continue; 1177 asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1178 readback(asc->regs->asc_cmd); 1179 asc->state = ASC_STATE_RESEL; 1180 asc->script = &asc_scripts[SCRIPT_RESEL]; 1181 break; 1182 } 1183 1184 /* 1185 * Look for another device that is ready. 1186 * May want to keep last one started and increment for fairness 1187 * rather than always starting at zero. 1188 */ 1189 for (i = 0; i < ASC_NCMD; i++) { 1190 /* don't restart a disconnected command */ 1191 if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 1192 continue; 1193 asc_startcmd(asc, i); 1194 break; 1195 } 1196 1197 /* signal device driver that the command is done */ 1198 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 1199 state->buflen, state->statusByte); 1200 1201 return (0); 1202 } 1203 1204 /* ARGSUSED */ 1205 static int 1206 asc_dma_in(asc, status, ss, ir) 1207 register asc_softc_t asc; 1208 register int status, ss, ir; 1209 { 1210 register asc_regmap_t *regs = asc->regs; 1211 register State *state = &asc->st[asc->target]; 1212 register int len; 1213 1214 /* check for previous chunk in buffer */ 1215 if (state->flags & DMA_IN_PROGRESS) { 1216 /* 1217 * Only count bytes that have been copied to memory. 1218 * There may be some bytes in the FIFO if synchonous transfers 1219 * are in progress. 1220 */ 1221 (*asc->dma_end)(asc, state, ASCDMA_READ); 1222 ASC_TC_GET(regs, len); 1223 len = state->dmalen - len; 1224 bcopy(state->dmaBufAddr, state->buf, len); 1225 state->buf += len; 1226 state->buflen -= len; 1227 } 1228 1229 /* setup to start reading the next chunk */ 1230 len = state->buflen; 1231 if (len > state->dmaBufSize) 1232 len = state->dmaBufSize; 1233 state->dmalen = len; 1234 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1235 ASC_TC_PUT(regs, len); 1236 #ifdef DEBUG 1237 if (asc_debug > 2) 1238 printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1239 #endif 1240 1241 /* check for next chunk */ 1242 state->flags |= DMA_IN_PROGRESS; 1243 if (len != state->buflen) { 1244 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1245 readback(regs->asc_cmd); 1246 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1247 return (0); 1248 } 1249 return (1); 1250 } 1251 1252 /* ARGSUSED */ 1253 static int 1254 asc_last_dma_in(asc, status, ss, ir) 1255 register asc_softc_t asc; 1256 register int status, ss, ir; 1257 { 1258 register asc_regmap_t *regs = asc->regs; 1259 register State *state = &asc->st[asc->target]; 1260 register int len, fifo; 1261 1262 /* copy data from buffer to main memory */ 1263 (*asc->dma_end)(asc, state, ASCDMA_READ); 1264 ASC_TC_GET(regs, len); 1265 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1266 #ifdef DEBUG 1267 if (asc_debug > 2) 1268 printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1269 state->buflen, state->dmalen, len, fifo); 1270 #endif 1271 if (fifo) { 1272 /* device must be trying to send more than we expect */ 1273 regs->asc_cmd = ASC_CMD_FLUSH; 1274 readback(regs->asc_cmd); 1275 } 1276 state->flags &= ~DMA_IN_PROGRESS; 1277 len = state->dmalen - len; 1278 state->buflen -= len; 1279 bcopy(state->dmaBufAddr, state->buf, len); 1280 1281 return (1); 1282 } 1283 1284 /* ARGSUSED */ 1285 static int 1286 asc_resume_in(asc, status, ss, ir) 1287 register asc_softc_t asc; 1288 register int status, ss, ir; 1289 { 1290 register asc_regmap_t *regs = asc->regs; 1291 register State *state = &asc->st[asc->target]; 1292 register int len; 1293 1294 /* setup to start reading the next chunk */ 1295 len = state->buflen; 1296 if (len > state->dmaBufSize) 1297 len = state->dmaBufSize; 1298 state->dmalen = len; 1299 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1300 ASC_TC_PUT(regs, len); 1301 #ifdef DEBUG 1302 if (asc_debug > 2) 1303 printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1304 len); 1305 #endif 1306 1307 /* check for next chunk */ 1308 state->flags |= DMA_IN_PROGRESS; 1309 if (len != state->buflen) { 1310 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1311 readback(regs->asc_cmd); 1312 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1313 return (0); 1314 } 1315 return (1); 1316 } 1317 1318 /* ARGSUSED */ 1319 static int 1320 asc_resume_dma_in(asc, status, ss, ir) 1321 register asc_softc_t asc; 1322 register int status, ss, ir; 1323 { 1324 register asc_regmap_t *regs = asc->regs; 1325 register State *state = &asc->st[asc->target]; 1326 register int len, off; 1327 1328 /* setup to finish reading the current chunk */ 1329 len = state->dmaresid; 1330 off = state->dmalen - len; 1331 if ((off & 1) && state->sync_offset) { 1332 printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1333 state->dmalen, len, off); /* XXX */ 1334 regs->asc_res_fifo = state->dmaBufAddr[off]; 1335 } 1336 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 1337 ASC_TC_PUT(regs, len); 1338 #ifdef DEBUG 1339 if (asc_debug > 2) 1340 printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1341 state->dmalen, state->buflen, len, off); 1342 #endif 1343 1344 /* check for next chunk */ 1345 state->flags |= DMA_IN_PROGRESS; 1346 if (state->dmalen != state->buflen) { 1347 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1348 readback(regs->asc_cmd); 1349 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1350 return (0); 1351 } 1352 return (1); 1353 } 1354 1355 /* ARGSUSED */ 1356 static int 1357 asc_dma_out(asc, status, ss, ir) 1358 register asc_softc_t asc; 1359 register int status, ss, ir; 1360 { 1361 register asc_regmap_t *regs = asc->regs; 1362 register State *state = &asc->st[asc->target]; 1363 register int len, fifo; 1364 1365 if (state->flags & DMA_IN_PROGRESS) { 1366 /* check to be sure previous chunk was finished */ 1367 ASC_TC_GET(regs, len); 1368 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1369 if (len || fifo) 1370 printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1371 state->buflen, state->dmalen, len, fifo); /* XXX */ 1372 len += fifo; 1373 len = state->dmalen - len; 1374 state->buf += len; 1375 state->buflen -= len; 1376 } 1377 1378 /* setup for this chunk */ 1379 len = state->buflen; 1380 if (len > state->dmaBufSize) 1381 len = state->dmaBufSize; 1382 state->dmalen = len; 1383 bcopy(state->buf, state->dmaBufAddr, len); 1384 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1385 ASC_TC_PUT(regs, len); 1386 #ifdef DEBUG 1387 if (asc_debug > 2) 1388 printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 1389 #endif 1390 1391 /* check for next chunk */ 1392 state->flags |= DMA_IN_PROGRESS; 1393 if (len != state->buflen) { 1394 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1395 readback(regs->asc_cmd); 1396 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1397 return (0); 1398 } 1399 return (1); 1400 } 1401 1402 /* ARGSUSED */ 1403 static int 1404 asc_last_dma_out(asc, status, ss, ir) 1405 register asc_softc_t asc; 1406 register int status, ss, ir; 1407 { 1408 register asc_regmap_t *regs = asc->regs; 1409 register State *state = &asc->st[asc->target]; 1410 register int len, fifo; 1411 1412 ASC_TC_GET(regs, len); 1413 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1414 #ifdef DEBUG 1415 if (asc_debug > 2) 1416 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1417 state->buflen, state->dmalen, len, fifo); 1418 #endif 1419 if (fifo) { 1420 len += fifo; 1421 regs->asc_cmd = ASC_CMD_FLUSH; 1422 readback(regs->asc_cmd); 1423 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1424 state->buflen, state->dmalen, len, fifo); 1425 } 1426 state->flags &= ~DMA_IN_PROGRESS; 1427 len = state->dmalen - len; 1428 state->buflen -= len; 1429 return (1); 1430 } 1431 1432 /* ARGSUSED */ 1433 static int 1434 asc_resume_out(asc, status, ss, ir) 1435 register asc_softc_t asc; 1436 register int status, ss, ir; 1437 { 1438 register asc_regmap_t *regs = asc->regs; 1439 register State *state = &asc->st[asc->target]; 1440 register int len; 1441 1442 /* setup for this chunk */ 1443 len = state->buflen; 1444 if (len > state->dmaBufSize) 1445 len = state->dmaBufSize; 1446 state->dmalen = len; 1447 bcopy(state->buf, state->dmaBufAddr, len); 1448 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1449 ASC_TC_PUT(regs, len); 1450 #ifdef DEBUG 1451 if (asc_debug > 2) 1452 printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1453 len); 1454 #endif 1455 1456 /* check for next chunk */ 1457 state->flags |= DMA_IN_PROGRESS; 1458 if (len != state->buflen) { 1459 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1460 readback(regs->asc_cmd); 1461 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1462 return (0); 1463 } 1464 return (1); 1465 } 1466 1467 /* ARGSUSED */ 1468 static int 1469 asc_resume_dma_out(asc, status, ss, ir) 1470 register asc_softc_t asc; 1471 register int status, ss, ir; 1472 { 1473 register asc_regmap_t *regs = asc->regs; 1474 register State *state = &asc->st[asc->target]; 1475 register int len, off; 1476 1477 /* setup to finish writing this chunk */ 1478 len = state->dmaresid; 1479 off = state->dmalen - len; 1480 if (off & 1) { 1481 printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1482 state->dmalen, len, off); /* XXX */ 1483 regs->asc_fifo = state->dmaBufAddr[off]; 1484 off++; 1485 len--; 1486 } 1487 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 1488 ASC_TC_PUT(regs, len); 1489 #ifdef DEBUG 1490 if (asc_debug > 2) 1491 printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1492 state->dmalen, state->buflen, len, off); 1493 #endif 1494 1495 /* check for next chunk */ 1496 state->flags |= DMA_IN_PROGRESS; 1497 if (state->dmalen != state->buflen) { 1498 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1499 readback(regs->asc_cmd); 1500 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1501 return (0); 1502 } 1503 return (1); 1504 } 1505 1506 /* ARGSUSED */ 1507 static int 1508 asc_sendsync(asc, status, ss, ir) 1509 register asc_softc_t asc; 1510 register int status, ss, ir; 1511 { 1512 register asc_regmap_t *regs = asc->regs; 1513 register State *state = &asc->st[asc->target]; 1514 1515 /* send the extended synchronous negotiation message */ 1516 regs->asc_fifo = SCSI_EXTENDED_MSG; 1517 MachEmptyWriteBuffer(); 1518 regs->asc_fifo = 3; 1519 MachEmptyWriteBuffer(); 1520 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1521 MachEmptyWriteBuffer(); 1522 regs->asc_fifo = SCSI_MIN_PERIOD; 1523 MachEmptyWriteBuffer(); 1524 regs->asc_fifo = ASC_MAX_OFFSET; 1525 /* state to resume after we see the sync reply message */ 1526 state->script = asc->script + 2; 1527 state->msglen = 0; 1528 return (1); 1529 } 1530 1531 /* ARGSUSED */ 1532 static int 1533 asc_replysync(asc, status, ss, ir) 1534 register asc_softc_t asc; 1535 register int status, ss, ir; 1536 { 1537 register asc_regmap_t *regs = asc->regs; 1538 register State *state = &asc->st[asc->target]; 1539 1540 #ifdef DEBUG 1541 if (asc_debug > 2) 1542 printf("asc_replysync: %x %x\n", 1543 asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 1544 state->sync_offset); 1545 #endif 1546 /* send synchronous transfer in response to a request */ 1547 regs->asc_fifo = SCSI_EXTENDED_MSG; 1548 MachEmptyWriteBuffer(); 1549 regs->asc_fifo = 3; 1550 MachEmptyWriteBuffer(); 1551 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1552 MachEmptyWriteBuffer(); 1553 regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 1554 MachEmptyWriteBuffer(); 1555 regs->asc_fifo = state->sync_offset; 1556 regs->asc_cmd = ASC_CMD_XFER_INFO; 1557 readback(regs->asc_cmd); 1558 1559 /* return to the appropriate script */ 1560 if (!state->script) { 1561 #ifdef DEBUG 1562 asc_DumpLog("asc_replsync"); 1563 #endif 1564 panic("asc_replysync"); 1565 } 1566 asc->script = state->script; 1567 state->script = (script_t *)0; 1568 return (0); 1569 } 1570 1571 /* ARGSUSED */ 1572 static int 1573 asc_msg_in(asc, status, ss, ir) 1574 register asc_softc_t asc; 1575 register int status, ss, ir; 1576 { 1577 register asc_regmap_t *regs = asc->regs; 1578 register State *state = &asc->st[asc->target]; 1579 register int msg; 1580 int i; 1581 1582 /* read one message byte */ 1583 msg = regs->asc_fifo; 1584 #ifdef DEBUG 1585 if (asc_logp == asc_log) 1586 asc_log[NLOG - 1].msg = msg; 1587 else 1588 asc_logp[-1].msg = msg; 1589 #endif 1590 1591 /* check for multi-byte message */ 1592 if (state->msglen != 0) { 1593 /* first byte is the message length */ 1594 if (state->msglen < 0) { 1595 state->msglen = msg; 1596 return (1); 1597 } 1598 if (state->msgcnt >= state->msglen) 1599 goto abort; 1600 state->msg_in[state->msgcnt++] = msg; 1601 1602 /* did we just read the last byte of the message? */ 1603 if (state->msgcnt != state->msglen) 1604 return (1); 1605 1606 /* process an extended message */ 1607 #ifdef DEBUG 1608 if (asc_debug > 2) 1609 printf("asc_msg_in: msg %x %x %x\n", 1610 state->msg_in[0], 1611 state->msg_in[1], 1612 state->msg_in[2]); 1613 #endif 1614 switch (state->msg_in[0]) { 1615 case SCSI_SYNCHRONOUS_XFER: 1616 state->flags |= DID_SYNC; 1617 state->sync_offset = state->msg_in[2]; 1618 1619 /* convert SCSI period to ASC period */ 1620 i = state->msg_in[1] / asc->tb_ticks; 1621 if (i < asc->min_period) 1622 i = asc->min_period; 1623 else if (i >= asc->max_period) { 1624 /* can't do sync transfer, period too long */ 1625 printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1626 asc - asc_softc, asc->target, i); 1627 i = asc->max_period; 1628 state->sync_offset = 0; 1629 } 1630 if ((i * asc->tb_ticks) != state->msg_in[1]) 1631 i++; 1632 state->sync_period = i & 0x1F; 1633 1634 /* 1635 * If this is a request, check minimums and 1636 * send back an acknowledge. 1637 */ 1638 if (!(state->flags & TRY_SYNC)) { 1639 regs->asc_cmd = ASC_CMD_SET_ATN; 1640 readback(regs->asc_cmd); 1641 1642 if (state->sync_period < asc->min_period) 1643 state->sync_period = 1644 asc->min_period; 1645 if (state->sync_offset > ASC_MAX_OFFSET) 1646 state->sync_offset = 1647 ASC_MAX_OFFSET; 1648 asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1649 regs->asc_syn_p = state->sync_period; 1650 readback(regs->asc_syn_p); 1651 regs->asc_syn_o = state->sync_offset; 1652 readback(regs->asc_syn_o); 1653 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1654 readback(regs->asc_cmd); 1655 return (0); 1656 } 1657 1658 regs->asc_syn_p = state->sync_period; 1659 readback(regs->asc_syn_p); 1660 regs->asc_syn_o = state->sync_offset; 1661 readback(regs->asc_syn_o); 1662 goto done; 1663 1664 default: 1665 printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1666 asc - asc_softc, asc->target, 1667 state->msg_in[0]); 1668 goto reject; 1669 } 1670 } 1671 1672 /* process first byte of a message */ 1673 #ifdef DEBUG 1674 if (asc_debug > 2) 1675 printf("asc_msg_in: msg %x\n", msg); 1676 #endif 1677 switch (msg) { 1678 #if 0 1679 case SCSI_MESSAGE_REJECT: 1680 printf(" did not like SYNCH xfer "); /* XXX */ 1681 state->flags |= DID_SYNC; 1682 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1683 readback(regs->asc_cmd); 1684 status = asc_wait(regs, ASC_CSR_INT); 1685 ir = regs->asc_intr; 1686 /* some just break out here, some dont */ 1687 if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1688 regs->asc_fifo = SCSI_ABORT; 1689 regs->asc_cmd = ASC_CMD_XFER_INFO; 1690 readback(regs->asc_cmd); 1691 status = asc_wait(regs, ASC_CSR_INT); 1692 ir = regs->asc_intr; 1693 } 1694 if (ir & ASC_INT_DISC) { 1695 asc_end(asc, status, 0, ir); 1696 return (0); 1697 } 1698 goto status; 1699 #endif 1700 1701 case SCSI_EXTENDED_MSG: /* read an extended message */ 1702 /* setup to read message length next */ 1703 state->msglen = -1; 1704 state->msgcnt = 0; 1705 return (1); 1706 1707 case SCSI_NO_OP: 1708 break; 1709 1710 case SCSI_SAVE_DATA_POINTER: 1711 /* expect another message */ 1712 return (1); 1713 1714 case SCSI_RESTORE_POINTERS: 1715 /* 1716 * Need to do the following if resuming synchonous data in 1717 * on an odd byte boundary. 1718 regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1719 */ 1720 break; 1721 1722 case SCSI_DISCONNECT: 1723 if (state->flags & DISCONN) 1724 goto abort; 1725 state->flags |= DISCONN; 1726 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1727 readback(regs->asc_cmd); 1728 asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1729 return (0); 1730 1731 default: 1732 printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1733 asc - asc_softc, asc->target, msg); 1734 reject: 1735 /* request a message out before acknowledging this message */ 1736 state->msg_out = SCSI_MESSAGE_REJECT; 1737 regs->asc_cmd = ASC_CMD_SET_ATN; 1738 readback(regs->asc_cmd); 1739 } 1740 1741 done: 1742 /* return to original script */ 1743 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1744 readback(regs->asc_cmd); 1745 if (!state->script) { 1746 abort: 1747 #ifdef DEBUG 1748 asc_DumpLog("asc_msg_in"); 1749 #endif 1750 panic("asc_msg_in"); 1751 } 1752 asc->script = state->script; 1753 state->script = (script_t *)0; 1754 return (0); 1755 } 1756 1757 /* ARGSUSED */ 1758 static int 1759 asc_disconnect(asc, status, ss, ir) 1760 register asc_softc_t asc; 1761 register int status, ss, ir; 1762 { 1763 register State *state = &asc->st[asc->target]; 1764 1765 #ifdef DIAGNOSTIC 1766 if (!(state->flags & DISCONN)) { 1767 printf("asc_disconnect: device %d: DISCONN not set!\n", 1768 asc->target); 1769 } 1770 #endif 1771 asc->target = -1; 1772 asc->state = ASC_STATE_RESEL; 1773 return (1); 1774 } 1775 1776 /* 1777 * DMA handling routines. For a turbochannel device, just set the dmar. 1778 * For the I/O ASIC, handle the actual DMA interface. 1779 */ 1780 static void 1781 tb_dma_start(asc, state, cp, flag) 1782 asc_softc_t asc; 1783 State *state; 1784 caddr_t cp; 1785 int flag; 1786 { 1787 1788 if (flag == ASCDMA_WRITE) 1789 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 1790 else 1791 *asc->dmar = ASC_DMA_ADDR(cp); 1792 } 1793 1794 static void 1795 tb_dma_end(asc, state, flag) 1796 asc_softc_t asc; 1797 State *state; 1798 int flag; 1799 { 1800 1801 } 1802 1803 static void 1804 asic_dma_start(asc, state, cp, flag) 1805 asc_softc_t asc; 1806 State *state; 1807 caddr_t cp; 1808 int flag; 1809 { 1810 register volatile u_int *ssr = (volatile u_int *) 1811 ASIC_REG_CSR(asic_base); 1812 u_int phys, nphys; 1813 1814 /* stop DMA engine first */ 1815 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1816 *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 1817 1818 phys = MACH_CACHED_TO_PHYS(cp); 1819 cp = (caddr_t)pmax_trunc_page(cp + NBPG); 1820 nphys = MACH_CACHED_TO_PHYS(cp); 1821 1822 asc->dma_next = cp; 1823 asc->dma_xfer = state->dmalen - (nphys - phys); 1824 1825 *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 1826 ASIC_DMA_ADDR(phys); 1827 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1828 ASIC_DMA_ADDR(nphys); 1829 if (flag == ASCDMA_READ) 1830 *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 1831 else 1832 *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 1833 MachEmptyWriteBuffer(); 1834 } 1835 1836 static void 1837 asic_dma_end(asc, state, flag) 1838 asc_softc_t asc; 1839 State *state; 1840 int flag; 1841 { 1842 register volatile u_int *ssr = (volatile u_int *) 1843 ASIC_REG_CSR(asic_base); 1844 int nb; 1845 1846 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1847 *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 1848 *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 1849 MachEmptyWriteBuffer(); 1850 1851 if (flag == ASCDMA_READ) { 1852 MachFlushDCache(MACH_PHYS_TO_CACHED( 1853 MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1854 if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 1855 /* pick up last upto6 bytes, sigh. */ 1856 register u_short *to; 1857 register int w; 1858 1859 /* Last byte really xferred is.. */ 1860 to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1)); 1861 w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 1862 *to++ = w; 1863 if (--nb > 0) { 1864 w >>= 16; 1865 *to++ = w; 1866 } 1867 if (--nb > 0) { 1868 w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 1869 *to++ = w; 1870 } 1871 } 1872 } 1873 } 1874 1875 #ifdef notdef 1876 /* 1877 * Called by asic_intr() for scsi dma pointer update interrupts. 1878 */ 1879 void 1880 asc_dma_intr() 1881 { 1882 asc_softc_t asc = &asc_softc[0]; 1883 u_int next_phys; 1884 1885 asc->dma_xfer -= NBPG; 1886 if (asc->dma_xfer <= -NBPG) { 1887 volatile u_int *ssr = (volatile u_int *) 1888 ASIC_REG_CSR(asic_base); 1889 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1890 } else { 1891 asc->dma_next += NBPG; 1892 next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 1893 } 1894 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1895 ASIC_DMA_ADDR(next_phys); 1896 MachEmptyWriteBuffer(); 1897 } 1898 #endif 1899 1900 #ifdef DEBUG 1901 asc_DumpLog(str) 1902 char *str; 1903 { 1904 register struct asc_log *lp; 1905 register u_int status; 1906 1907 printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1908 asc_debug_bn, asc_debug_sz); 1909 lp = asc_logp; 1910 do { 1911 status = lp->status; 1912 printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", 1913 status >> 24, 1914 lp->target, 1915 (status >> 16) & 0xFF, 1916 (status >> 8) & 0xFF, 1917 status & 0XFF, 1918 lp->state, 1919 asc_scripts[lp->state].condition, 1920 lp->msg, lp->resid); 1921 if (++lp >= &asc_log[NLOG]) 1922 lp = asc_log; 1923 } while (lp != asc_logp); 1924 } 1925 #endif 1926 1927 #endif /* NASC > 0 */ 1928