1 /*- 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. 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 8.1 (Berkeley) 06/10/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; 667 state->dmalen = len; 668 bcopy(scsicmd->cmd, state->dmaBufAddr, len); 669 670 /* check for simple SCSI command with no data transfer */ 671 if ((state->buflen = scsicmd->buflen) == 0) { 672 /* check for sync negotiation */ 673 if ((scsicmd->flags & SCSICMD_USE_SYNC) && 674 !(state->flags & DID_SYNC)) { 675 asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 676 state->flags |= TRY_SYNC; 677 } else 678 asc->script = &asc_scripts[SCRIPT_SIMPLE]; 679 state->buf = (char *)0; 680 } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 681 asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 682 state->buf = scsicmd->buf; 683 state->flags |= DMA_OUT; 684 } else { 685 asc->script = &asc_scripts[SCRIPT_DATA_IN]; 686 state->buf = scsicmd->buf; 687 state->flags |= DMA_IN; 688 } 689 690 #ifdef DEBUG 691 asc_debug_cmd = scsicmd->cmd[0]; 692 if (scsicmd->cmd[0] == SCSI_READ_EXT) { 693 asc_debug_bn = (scsicmd->cmd[2] << 24) | 694 (scsicmd->cmd[3] << 16) | 695 (scsicmd->cmd[4] << 8) | 696 scsicmd->cmd[5]; 697 asc_debug_sz = (scsicmd->cmd[7] << 8) | scsicmd->cmd[8]; 698 } 699 asc_logp->status = PACK(asc - asc_softc, 0, 0, asc_debug_cmd); 700 asc_logp->target = asc->target; 701 asc_logp->state = asc->script - asc_scripts; 702 asc_logp->msg = SCSI_DIS_REC_IDENTIFY; 703 asc_logp->resid = scsicmd->buflen; 704 if (++asc_logp >= &asc_log[NLOG]) 705 asc_logp = asc_log; 706 #endif 707 708 /* preload the FIFO with the message to be sent */ 709 regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 710 MachEmptyWriteBuffer(); 711 712 /* initialize the DMA */ 713 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 714 ASC_TC_PUT(regs, len); 715 readback(regs->asc_cmd); 716 717 regs->asc_dbus_id = target; 718 readback(regs->asc_dbus_id); 719 regs->asc_syn_p = state->sync_period; 720 readback(regs->asc_syn_p); 721 regs->asc_syn_o = state->sync_offset; 722 readback(regs->asc_syn_o); 723 724 if (state->flags & TRY_SYNC) 725 regs->asc_cmd = ASC_CMD_SEL_ATN_STOP; 726 else 727 regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 728 readback(regs->asc_cmd); 729 } 730 731 /* 732 * Interrupt routine 733 * Take interrupts from the chip 734 * 735 * Implementation: 736 * Move along the current command's script if 737 * all is well, invoke error handler if not. 738 */ 739 void 740 asc_intr(unit) 741 int unit; 742 { 743 register asc_softc_t asc = &asc_softc[unit]; 744 register asc_regmap_t *regs = asc->regs; 745 register State *state; 746 register script_t *scpt; 747 register int ss, ir, status; 748 749 /* collect ephemeral information */ 750 status = regs->asc_status; 751 again: 752 ss = regs->asc_ss; 753 ir = regs->asc_intr; /* this resets the previous two */ 754 scpt = asc->script; 755 756 #ifdef DEBUG 757 asc_logp->status = PACK(unit, status, ss, ir); 758 asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 759 asc_logp->state = scpt - asc_scripts; 760 asc_logp->msg = -1; 761 asc_logp->resid = 0; 762 if (++asc_logp >= &asc_log[NLOG]) 763 asc_logp = asc_log; 764 if (asc_debug > 2) 765 printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 766 status, ss, ir, scpt - asc_scripts, scpt->condition); 767 #endif 768 769 /* check the expected state */ 770 if (SCRIPT_MATCH(ir, status) == scpt->condition) { 771 /* 772 * Perform the appropriate operation, then proceed. 773 */ 774 if ((*scpt->action)(asc, status, ss, ir)) { 775 regs->asc_cmd = scpt->command; 776 readback(regs->asc_cmd); 777 asc->script = scpt->next; 778 } 779 goto done; 780 } 781 782 /* 783 * Check for parity error. 784 * Hardware will automatically set ATN 785 * to request the device for a MSG_OUT phase. 786 */ 787 if (status & ASC_CSR_PE) { 788 printf("asc%d: SCSI device %d: incomming parity error seen\n", 789 asc - asc_softc, asc->target); 790 asc->st[asc->target].flags |= PARITY_ERR; 791 } 792 793 /* 794 * Check for gross error. 795 * Probably a bug in a device driver. 796 */ 797 if (status & ASC_CSR_GE) { 798 printf("asc%d: SCSI device %d: gross error\n", 799 asc - asc_softc, asc->target); 800 goto abort; 801 } 802 803 /* check for message in or out */ 804 if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 805 register int len, fifo; 806 807 state = &asc->st[asc->target]; 808 switch (ASC_PHASE(status)) { 809 case ASC_PHASE_DATAI: 810 case ASC_PHASE_DATAO: 811 ASC_TC_GET(regs, len); 812 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 813 printf("asc_intr: data overrun: buflen %d dmalen %d tc %d fifo %d\n", 814 state->buflen, state->dmalen, len, fifo); 815 goto abort; 816 817 case ASC_PHASE_MSG_IN: 818 break; 819 820 case ASC_PHASE_MSG_OUT: 821 /* 822 * Check for parity error. 823 * Hardware will automatically set ATN 824 * to request the device for a MSG_OUT phase. 825 */ 826 if (state->flags & PARITY_ERR) { 827 state->flags &= ~PARITY_ERR; 828 state->msg_out = SCSI_MESSAGE_PARITY_ERROR; 829 /* reset message in counter */ 830 state->msglen = 0; 831 } else 832 state->msg_out = SCSI_NO_OP; 833 regs->asc_fifo = state->msg_out; 834 regs->asc_cmd = ASC_CMD_XFER_INFO; 835 readback(regs->asc_cmd); 836 goto done; 837 838 case ASC_PHASE_STATUS: 839 /* probably an error in the SCSI command */ 840 asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 841 regs->asc_cmd = ASC_CMD_I_COMPLETE; 842 readback(regs->asc_cmd); 843 goto done; 844 845 default: 846 goto abort; 847 } 848 849 if (state->script) 850 goto abort; 851 852 /* check for DMA in progress */ 853 ASC_TC_GET(regs, len); 854 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 855 /* flush any data in the FIFO */ 856 if (fifo) { 857 if (state->flags & DMA_OUT) 858 len += fifo; 859 else if (state->flags & DMA_IN) { 860 u_char *cp; 861 862 printf("asc_intr: IN: dmalen %d len %d fifo %d\n", 863 state->dmalen, len, fifo); /* XXX */ 864 len += fifo; 865 cp = state->dmaBufAddr + (state->dmalen - len); 866 while (fifo-- > 0) 867 *cp++ = regs->asc_fifo; 868 } else 869 printf("asc_intr: dmalen %d len %d fifo %d\n", 870 state->dmalen, len, fifo); /* XXX */ 871 regs->asc_cmd = ASC_CMD_FLUSH; 872 readback(regs->asc_cmd); 873 DELAY(2); 874 } 875 if (len) { 876 /* save number of bytes still to be sent or received */ 877 state->dmaresid = len; 878 #ifdef DEBUG 879 if (asc_logp == asc_log) 880 asc_log[NLOG - 1].resid = len; 881 else 882 asc_logp[-1].resid = len; 883 #endif 884 /* setup state to resume to */ 885 if (state->flags & DMA_IN) { 886 /* 887 * Since the ASC_CNFG3_SRB bit of the 888 * cnfg3 register bit is not set, 889 * we just transferred an extra byte. 890 * Since we can't resume on an odd byte 891 * boundary, we copy the valid data out 892 * and resume DMA at the start address. 893 */ 894 if (len & 1) { 895 printf("asc_intr: msg in len %d (fifo %d)\n", 896 len, fifo); 897 len = state->dmalen - len; 898 goto do_in; 899 } 900 state->script = 901 &asc_scripts[SCRIPT_RESUME_DMA_IN]; 902 } else if (state->flags & DMA_OUT) 903 state->script = 904 &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 905 else 906 state->script = asc->script; 907 } else { 908 /* setup state to resume to */ 909 if (state->flags & DMA_IN) { 910 if (state->flags & DMA_IN_PROGRESS) { 911 len = state->dmalen; 912 do_in: 913 state->flags &= ~DMA_IN_PROGRESS; 914 (*asc->dma_end)(asc, state, ASCDMA_READ); 915 bcopy(state->dmaBufAddr, state->buf, 916 len); 917 state->buf += len; 918 state->buflen -= len; 919 } 920 if (state->buflen) 921 state->script = 922 &asc_scripts[SCRIPT_RESUME_IN]; 923 else 924 state->script = 925 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 926 } else if (state->flags & DMA_OUT) { 927 /* 928 * If this is the last chunk, the next expected 929 * state is to get status. 930 */ 931 if (state->flags & DMA_IN_PROGRESS) { 932 state->flags &= ~DMA_IN_PROGRESS; 933 (*asc->dma_end)(asc, state, ASCDMA_WRITE); 934 len = state->dmalen; 935 state->buf += len; 936 state->buflen -= len; 937 } 938 if (state->buflen) 939 state->script = 940 &asc_scripts[SCRIPT_RESUME_OUT]; 941 else 942 state->script = 943 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 944 } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 945 state->script = 946 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 947 else 948 state->script = asc->script; 949 } 950 951 /* setup to receive a message */ 952 asc->script = &asc_scripts[SCRIPT_MSG_IN]; 953 state->msglen = 0; 954 regs->asc_cmd = ASC_CMD_XFER_INFO; 955 readback(regs->asc_cmd); 956 goto done; 957 } 958 959 /* check for SCSI bus reset */ 960 if (ir & ASC_INT_RESET) { 961 register int i; 962 963 printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 964 /* need to flush any pending commands */ 965 for (i = 0; i < ASC_NCMD; i++) { 966 if (!asc->cmd[i]) 967 continue; 968 asc->st[i].error = EIO; 969 asc_end(asc, 0, 0, 0); 970 } 971 /* rearbitrate synchronous offset */ 972 for (i = 0; i < ASC_NCMD; i++) { 973 asc->st[i].sync_offset = 0; 974 asc->st[i].flags = 0; 975 } 976 asc->target = -1; 977 return; 978 } 979 980 /* check for command errors */ 981 if (ir & ASC_INT_ILL) 982 goto abort; 983 984 /* check for disconnect */ 985 if (ir & ASC_INT_DISC) { 986 state = &asc->st[asc->target]; 987 switch (ASC_SS(ss)) { 988 case 0: /* device did not respond */ 989 /* check for one of the starting scripts */ 990 switch (asc->script - asc_scripts) { 991 case SCRIPT_TRY_SYNC: 992 case SCRIPT_SIMPLE: 993 case SCRIPT_DATA_IN: 994 case SCRIPT_DATA_OUT: 995 if (regs->asc_flags & ASC_FLAGS_FIFO_CNT) { 996 regs->asc_cmd = ASC_CMD_FLUSH; 997 readback(regs->asc_cmd); 998 } 999 state->error = ENXIO; 1000 asc_end(asc, status, ss, ir); 1001 return; 1002 } 1003 /* FALLTHROUGH */ 1004 1005 default: 1006 printf("asc%d: SCSI device %d: unexpected disconnect\n", 1007 asc - asc_softc, asc->target); 1008 /* 1009 * On rare occasions my RZ24 does a disconnect during 1010 * data in phase and the following seems to keep it 1011 * happy. 1012 * XXX Should a scsi disk ever do this?? 1013 */ 1014 asc->script = &asc_scripts[SCRIPT_RESEL]; 1015 asc->state = ASC_STATE_RESEL; 1016 state->flags |= DISCONN; 1017 regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1018 readback(regs->asc_cmd); 1019 return; 1020 } 1021 } 1022 1023 /* check for reselect */ 1024 if (ir & ASC_INT_RESEL) { 1025 unsigned fifo, id, msg; 1026 1027 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1028 if (fifo < 2) 1029 goto abort; 1030 /* read unencoded SCSI ID and convert to binary */ 1031 msg = regs->asc_fifo & asc->myidmask; 1032 for (id = 0; (msg & 1) == 0; id++) 1033 msg >>= 1; 1034 /* read identify message */ 1035 msg = regs->asc_fifo; 1036 #ifdef DEBUG 1037 if (asc_logp == asc_log) 1038 asc_log[NLOG - 1].msg = msg; 1039 else 1040 asc_logp[-1].msg = msg; 1041 #endif 1042 asc->state = ASC_STATE_BUSY; 1043 asc->target = id; 1044 state = &asc->st[id]; 1045 asc->script = state->script; 1046 state->script = (script_t *)0; 1047 if (!(state->flags & DISCONN)) 1048 goto abort; 1049 state->flags &= ~DISCONN; 1050 regs->asc_syn_p = state->sync_period; 1051 regs->asc_syn_o = state->sync_offset; 1052 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1053 readback(regs->asc_cmd); 1054 goto done; 1055 } 1056 1057 /* check if we are being selected as a target */ 1058 if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 1059 goto abort; 1060 1061 /* 1062 * 'ir' must be just ASC_INT_FC. 1063 * This is normal if canceling an ASC_ENABLE_SEL. 1064 */ 1065 1066 done: 1067 MachEmptyWriteBuffer(); 1068 /* watch out for HW race conditions and setup & hold time violations */ 1069 ir = regs->asc_status; 1070 while (ir != (status = regs->asc_status)) 1071 ir = status; 1072 if (status & ASC_CSR_INT) 1073 goto again; 1074 return; 1075 1076 abort: 1077 #ifdef DEBUG 1078 asc_DumpLog("asc_intr"); 1079 #endif 1080 #if 0 1081 panic("asc_intr"); 1082 #else 1083 for (;;); 1084 #endif 1085 } 1086 1087 /* 1088 * All the many little things that the interrupt 1089 * routine might switch to. 1090 */ 1091 1092 /* ARGSUSED */ 1093 static int 1094 script_nop(asc, status, ss, ir) 1095 register asc_softc_t asc; 1096 register int status, ss, ir; 1097 { 1098 return (1); 1099 } 1100 1101 /* ARGSUSED */ 1102 static int 1103 asc_get_status(asc, status, ss, ir) 1104 register asc_softc_t asc; 1105 register int status, ss, ir; 1106 { 1107 register asc_regmap_t *regs = asc->regs; 1108 register int data; 1109 1110 /* 1111 * Get the last two bytes in the FIFO. 1112 */ 1113 if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 1114 printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 1115 asc_DumpLog("get_status"); /* XXX */ 1116 if (data < 2) { 1117 asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 1118 readback(asc->regs->asc_cmd); 1119 return (0); 1120 } 1121 do { 1122 data = regs->asc_fifo; 1123 } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 1124 } 1125 1126 /* save the status byte */ 1127 asc->st[asc->target].statusByte = data = regs->asc_fifo; 1128 #ifdef DEBUG 1129 if (asc_logp == asc_log) 1130 asc_log[NLOG - 1].msg = data; 1131 else 1132 asc_logp[-1].msg = data; 1133 #endif 1134 1135 /* get the (presumed) command_complete message */ 1136 if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 1137 return (1); 1138 1139 #ifdef DEBUG 1140 printf("asc_get_status: status %x cmd %x\n", 1141 asc->st[asc->target].statusByte, data); 1142 asc_DumpLog("asc_get_status"); 1143 #endif 1144 return (0); 1145 } 1146 1147 /* ARGSUSED */ 1148 static int 1149 asc_end(asc, status, ss, ir) 1150 register asc_softc_t asc; 1151 register int status, ss, ir; 1152 { 1153 register ScsiCmd *scsicmd; 1154 register State *state; 1155 register int i, target; 1156 1157 asc->state = ASC_STATE_IDLE; 1158 target = asc->target; 1159 asc->target = -1; 1160 scsicmd = asc->cmd[target]; 1161 asc->cmd[target] = (ScsiCmd *)0; 1162 state = &asc->st[target]; 1163 1164 #ifdef DEBUG 1165 if (asc_debug > 1) { 1166 printf("asc_end: %s target %d cmd %x err %d resid %d\n", 1167 scsicmd->sd->sd_driver->d_name, target, 1168 scsicmd->cmd[0], state->error, state->buflen); 1169 } 1170 #endif 1171 #ifdef DIAGNOSTIC 1172 if (target < 0 || !scsicmd) 1173 panic("asc_end"); 1174 #endif 1175 1176 /* look for disconnected devices */ 1177 for (i = 0; i < ASC_NCMD; i++) { 1178 if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 1179 continue; 1180 asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1181 readback(asc->regs->asc_cmd); 1182 asc->state = ASC_STATE_RESEL; 1183 asc->script = &asc_scripts[SCRIPT_RESEL]; 1184 break; 1185 } 1186 1187 /* 1188 * Look for another device that is ready. 1189 * May want to keep last one started and increment for fairness 1190 * rather than always starting at zero. 1191 */ 1192 for (i = 0; i < ASC_NCMD; i++) { 1193 /* don't restart a disconnected command */ 1194 if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 1195 continue; 1196 asc_startcmd(asc, i); 1197 break; 1198 } 1199 1200 /* signal device driver that the command is done */ 1201 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 1202 state->buflen, state->statusByte); 1203 1204 return (0); 1205 } 1206 1207 /* ARGSUSED */ 1208 static int 1209 asc_dma_in(asc, status, ss, ir) 1210 register asc_softc_t asc; 1211 register int status, ss, ir; 1212 { 1213 register asc_regmap_t *regs = asc->regs; 1214 register State *state = &asc->st[asc->target]; 1215 register int len; 1216 1217 /* check for previous chunk in buffer */ 1218 if (state->flags & DMA_IN_PROGRESS) { 1219 /* 1220 * Only count bytes that have been copied to memory. 1221 * There may be some bytes in the FIFO if synchonous transfers 1222 * are in progress. 1223 */ 1224 (*asc->dma_end)(asc, state, ASCDMA_READ); 1225 ASC_TC_GET(regs, len); 1226 len = state->dmalen - len; 1227 bcopy(state->dmaBufAddr, state->buf, len); 1228 state->buf += len; 1229 state->buflen -= len; 1230 } 1231 1232 /* setup to start reading the next chunk */ 1233 len = state->buflen; 1234 if (len > state->dmaBufSize) 1235 len = state->dmaBufSize; 1236 state->dmalen = len; 1237 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1238 ASC_TC_PUT(regs, len); 1239 #ifdef DEBUG 1240 if (asc_debug > 2) 1241 printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1242 #endif 1243 1244 /* check for next chunk */ 1245 state->flags |= DMA_IN_PROGRESS; 1246 if (len != state->buflen) { 1247 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1248 readback(regs->asc_cmd); 1249 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1250 return (0); 1251 } 1252 return (1); 1253 } 1254 1255 /* ARGSUSED */ 1256 static int 1257 asc_last_dma_in(asc, status, ss, ir) 1258 register asc_softc_t asc; 1259 register int status, ss, ir; 1260 { 1261 register asc_regmap_t *regs = asc->regs; 1262 register State *state = &asc->st[asc->target]; 1263 register int len, fifo; 1264 1265 /* copy data from buffer to main memory */ 1266 (*asc->dma_end)(asc, state, ASCDMA_READ); 1267 ASC_TC_GET(regs, len); 1268 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1269 #ifdef DEBUG 1270 if (asc_debug > 2) 1271 printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1272 state->buflen, state->dmalen, len, fifo); 1273 #endif 1274 if (fifo) { 1275 /* device must be trying to send more than we expect */ 1276 regs->asc_cmd = ASC_CMD_FLUSH; 1277 readback(regs->asc_cmd); 1278 } 1279 state->flags &= ~DMA_IN_PROGRESS; 1280 len = state->dmalen - len; 1281 state->buflen -= len; 1282 bcopy(state->dmaBufAddr, state->buf, len); 1283 1284 return (1); 1285 } 1286 1287 /* ARGSUSED */ 1288 static int 1289 asc_resume_in(asc, status, ss, ir) 1290 register asc_softc_t asc; 1291 register int status, ss, ir; 1292 { 1293 register asc_regmap_t *regs = asc->regs; 1294 register State *state = &asc->st[asc->target]; 1295 register int len; 1296 1297 /* setup to start reading the next chunk */ 1298 len = state->buflen; 1299 if (len > state->dmaBufSize) 1300 len = state->dmaBufSize; 1301 state->dmalen = len; 1302 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1303 ASC_TC_PUT(regs, len); 1304 #ifdef DEBUG 1305 if (asc_debug > 2) 1306 printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1307 len); 1308 #endif 1309 1310 /* check for next chunk */ 1311 state->flags |= DMA_IN_PROGRESS; 1312 if (len != state->buflen) { 1313 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1314 readback(regs->asc_cmd); 1315 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1316 return (0); 1317 } 1318 return (1); 1319 } 1320 1321 /* ARGSUSED */ 1322 static int 1323 asc_resume_dma_in(asc, status, ss, ir) 1324 register asc_softc_t asc; 1325 register int status, ss, ir; 1326 { 1327 register asc_regmap_t *regs = asc->regs; 1328 register State *state = &asc->st[asc->target]; 1329 register int len, off; 1330 1331 /* setup to finish reading the current chunk */ 1332 len = state->dmaresid; 1333 off = state->dmalen - len; 1334 if ((off & 1) && state->sync_offset) { 1335 printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1336 state->dmalen, len, off); /* XXX */ 1337 regs->asc_res_fifo = state->dmaBufAddr[off]; 1338 } 1339 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 1340 ASC_TC_PUT(regs, len); 1341 #ifdef DEBUG 1342 if (asc_debug > 2) 1343 printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1344 state->dmalen, state->buflen, len, off); 1345 #endif 1346 1347 /* check for next chunk */ 1348 state->flags |= DMA_IN_PROGRESS; 1349 if (state->dmalen != state->buflen) { 1350 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1351 readback(regs->asc_cmd); 1352 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1353 return (0); 1354 } 1355 return (1); 1356 } 1357 1358 /* ARGSUSED */ 1359 static int 1360 asc_dma_out(asc, status, ss, ir) 1361 register asc_softc_t asc; 1362 register int status, ss, ir; 1363 { 1364 register asc_regmap_t *regs = asc->regs; 1365 register State *state = &asc->st[asc->target]; 1366 register int len, fifo; 1367 1368 if (state->flags & DMA_IN_PROGRESS) { 1369 /* check to be sure previous chunk was finished */ 1370 ASC_TC_GET(regs, len); 1371 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1372 if (len || fifo) 1373 printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1374 state->buflen, state->dmalen, len, fifo); /* XXX */ 1375 len += fifo; 1376 len = state->dmalen - len; 1377 state->buf += len; 1378 state->buflen -= len; 1379 } 1380 1381 /* setup for this chunk */ 1382 len = state->buflen; 1383 if (len > state->dmaBufSize) 1384 len = state->dmaBufSize; 1385 state->dmalen = len; 1386 bcopy(state->buf, state->dmaBufAddr, len); 1387 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1388 ASC_TC_PUT(regs, len); 1389 #ifdef DEBUG 1390 if (asc_debug > 2) 1391 printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 1392 #endif 1393 1394 /* check for next chunk */ 1395 state->flags |= DMA_IN_PROGRESS; 1396 if (len != state->buflen) { 1397 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1398 readback(regs->asc_cmd); 1399 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1400 return (0); 1401 } 1402 return (1); 1403 } 1404 1405 /* ARGSUSED */ 1406 static int 1407 asc_last_dma_out(asc, status, ss, ir) 1408 register asc_softc_t asc; 1409 register int status, ss, ir; 1410 { 1411 register asc_regmap_t *regs = asc->regs; 1412 register State *state = &asc->st[asc->target]; 1413 register int len, fifo; 1414 1415 ASC_TC_GET(regs, len); 1416 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1417 #ifdef DEBUG 1418 if (asc_debug > 2) 1419 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1420 state->buflen, state->dmalen, len, fifo); 1421 #endif 1422 if (fifo) { 1423 len += fifo; 1424 regs->asc_cmd = ASC_CMD_FLUSH; 1425 readback(regs->asc_cmd); 1426 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1427 state->buflen, state->dmalen, len, fifo); 1428 } 1429 state->flags &= ~DMA_IN_PROGRESS; 1430 len = state->dmalen - len; 1431 state->buflen -= len; 1432 return (1); 1433 } 1434 1435 /* ARGSUSED */ 1436 static int 1437 asc_resume_out(asc, status, ss, ir) 1438 register asc_softc_t asc; 1439 register int status, ss, ir; 1440 { 1441 register asc_regmap_t *regs = asc->regs; 1442 register State *state = &asc->st[asc->target]; 1443 register int len; 1444 1445 /* setup for this chunk */ 1446 len = state->buflen; 1447 if (len > state->dmaBufSize) 1448 len = state->dmaBufSize; 1449 state->dmalen = len; 1450 bcopy(state->buf, state->dmaBufAddr, len); 1451 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1452 ASC_TC_PUT(regs, len); 1453 #ifdef DEBUG 1454 if (asc_debug > 2) 1455 printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1456 len); 1457 #endif 1458 1459 /* check for next chunk */ 1460 state->flags |= DMA_IN_PROGRESS; 1461 if (len != state->buflen) { 1462 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1463 readback(regs->asc_cmd); 1464 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1465 return (0); 1466 } 1467 return (1); 1468 } 1469 1470 /* ARGSUSED */ 1471 static int 1472 asc_resume_dma_out(asc, status, ss, ir) 1473 register asc_softc_t asc; 1474 register int status, ss, ir; 1475 { 1476 register asc_regmap_t *regs = asc->regs; 1477 register State *state = &asc->st[asc->target]; 1478 register int len, off; 1479 1480 /* setup to finish writing this chunk */ 1481 len = state->dmaresid; 1482 off = state->dmalen - len; 1483 if (off & 1) { 1484 printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1485 state->dmalen, len, off); /* XXX */ 1486 regs->asc_fifo = state->dmaBufAddr[off]; 1487 off++; 1488 len--; 1489 } 1490 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 1491 ASC_TC_PUT(regs, len); 1492 #ifdef DEBUG 1493 if (asc_debug > 2) 1494 printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1495 state->dmalen, state->buflen, len, off); 1496 #endif 1497 1498 /* check for next chunk */ 1499 state->flags |= DMA_IN_PROGRESS; 1500 if (state->dmalen != state->buflen) { 1501 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1502 readback(regs->asc_cmd); 1503 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1504 return (0); 1505 } 1506 return (1); 1507 } 1508 1509 /* ARGSUSED */ 1510 static int 1511 asc_sendsync(asc, status, ss, ir) 1512 register asc_softc_t asc; 1513 register int status, ss, ir; 1514 { 1515 register asc_regmap_t *regs = asc->regs; 1516 register State *state = &asc->st[asc->target]; 1517 1518 /* send the extended synchronous negotiation message */ 1519 regs->asc_fifo = SCSI_EXTENDED_MSG; 1520 MachEmptyWriteBuffer(); 1521 regs->asc_fifo = 3; 1522 MachEmptyWriteBuffer(); 1523 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1524 MachEmptyWriteBuffer(); 1525 regs->asc_fifo = SCSI_MIN_PERIOD; 1526 MachEmptyWriteBuffer(); 1527 regs->asc_fifo = ASC_MAX_OFFSET; 1528 /* state to resume after we see the sync reply message */ 1529 state->script = asc->script + 2; 1530 state->msglen = 0; 1531 return (1); 1532 } 1533 1534 /* ARGSUSED */ 1535 static int 1536 asc_replysync(asc, status, ss, ir) 1537 register asc_softc_t asc; 1538 register int status, ss, ir; 1539 { 1540 register asc_regmap_t *regs = asc->regs; 1541 register State *state = &asc->st[asc->target]; 1542 1543 #ifdef DEBUG 1544 if (asc_debug > 2) 1545 printf("asc_replysync: %x %x\n", 1546 asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 1547 state->sync_offset); 1548 #endif 1549 /* send synchronous transfer in response to a request */ 1550 regs->asc_fifo = SCSI_EXTENDED_MSG; 1551 MachEmptyWriteBuffer(); 1552 regs->asc_fifo = 3; 1553 MachEmptyWriteBuffer(); 1554 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1555 MachEmptyWriteBuffer(); 1556 regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 1557 MachEmptyWriteBuffer(); 1558 regs->asc_fifo = state->sync_offset; 1559 regs->asc_cmd = ASC_CMD_XFER_INFO; 1560 readback(regs->asc_cmd); 1561 1562 /* return to the appropriate script */ 1563 if (!state->script) { 1564 #ifdef DEBUG 1565 asc_DumpLog("asc_replsync"); 1566 #endif 1567 panic("asc_replysync"); 1568 } 1569 asc->script = state->script; 1570 state->script = (script_t *)0; 1571 return (0); 1572 } 1573 1574 /* ARGSUSED */ 1575 static int 1576 asc_msg_in(asc, status, ss, ir) 1577 register asc_softc_t asc; 1578 register int status, ss, ir; 1579 { 1580 register asc_regmap_t *regs = asc->regs; 1581 register State *state = &asc->st[asc->target]; 1582 register int msg; 1583 int i; 1584 1585 /* read one message byte */ 1586 msg = regs->asc_fifo; 1587 #ifdef DEBUG 1588 if (asc_logp == asc_log) 1589 asc_log[NLOG - 1].msg = msg; 1590 else 1591 asc_logp[-1].msg = msg; 1592 #endif 1593 1594 /* check for multi-byte message */ 1595 if (state->msglen != 0) { 1596 /* first byte is the message length */ 1597 if (state->msglen < 0) { 1598 state->msglen = msg; 1599 return (1); 1600 } 1601 if (state->msgcnt >= state->msglen) 1602 goto abort; 1603 state->msg_in[state->msgcnt++] = msg; 1604 1605 /* did we just read the last byte of the message? */ 1606 if (state->msgcnt != state->msglen) 1607 return (1); 1608 1609 /* process an extended message */ 1610 #ifdef DEBUG 1611 if (asc_debug > 2) 1612 printf("asc_msg_in: msg %x %x %x\n", 1613 state->msg_in[0], 1614 state->msg_in[1], 1615 state->msg_in[2]); 1616 #endif 1617 switch (state->msg_in[0]) { 1618 case SCSI_SYNCHRONOUS_XFER: 1619 state->flags |= DID_SYNC; 1620 state->sync_offset = state->msg_in[2]; 1621 1622 /* convert SCSI period to ASC period */ 1623 i = state->msg_in[1] / asc->tb_ticks; 1624 if (i < asc->min_period) 1625 i = asc->min_period; 1626 else if (i >= asc->max_period) { 1627 /* can't do sync transfer, period too long */ 1628 printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1629 asc - asc_softc, asc->target, i); 1630 i = asc->max_period; 1631 state->sync_offset = 0; 1632 } 1633 if ((i * asc->tb_ticks) != state->msg_in[1]) 1634 i++; 1635 state->sync_period = i & 0x1F; 1636 1637 /* 1638 * If this is a request, check minimums and 1639 * send back an acknowledge. 1640 */ 1641 if (!(state->flags & TRY_SYNC)) { 1642 regs->asc_cmd = ASC_CMD_SET_ATN; 1643 readback(regs->asc_cmd); 1644 1645 if (state->sync_period < asc->min_period) 1646 state->sync_period = 1647 asc->min_period; 1648 if (state->sync_offset > ASC_MAX_OFFSET) 1649 state->sync_offset = 1650 ASC_MAX_OFFSET; 1651 asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1652 regs->asc_syn_p = state->sync_period; 1653 readback(regs->asc_syn_p); 1654 regs->asc_syn_o = state->sync_offset; 1655 readback(regs->asc_syn_o); 1656 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1657 readback(regs->asc_cmd); 1658 return (0); 1659 } 1660 1661 regs->asc_syn_p = state->sync_period; 1662 readback(regs->asc_syn_p); 1663 regs->asc_syn_o = state->sync_offset; 1664 readback(regs->asc_syn_o); 1665 goto done; 1666 1667 default: 1668 printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1669 asc - asc_softc, asc->target, 1670 state->msg_in[0]); 1671 goto reject; 1672 } 1673 } 1674 1675 /* process first byte of a message */ 1676 #ifdef DEBUG 1677 if (asc_debug > 2) 1678 printf("asc_msg_in: msg %x\n", msg); 1679 #endif 1680 switch (msg) { 1681 #if 0 1682 case SCSI_MESSAGE_REJECT: 1683 printf(" did not like SYNCH xfer "); /* XXX */ 1684 state->flags |= DID_SYNC; 1685 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1686 readback(regs->asc_cmd); 1687 status = asc_wait(regs, ASC_CSR_INT); 1688 ir = regs->asc_intr; 1689 /* some just break out here, some dont */ 1690 if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1691 regs->asc_fifo = SCSI_ABORT; 1692 regs->asc_cmd = ASC_CMD_XFER_INFO; 1693 readback(regs->asc_cmd); 1694 status = asc_wait(regs, ASC_CSR_INT); 1695 ir = regs->asc_intr; 1696 } 1697 if (ir & ASC_INT_DISC) { 1698 asc_end(asc, status, 0, ir); 1699 return (0); 1700 } 1701 goto status; 1702 #endif 1703 1704 case SCSI_EXTENDED_MSG: /* read an extended message */ 1705 /* setup to read message length next */ 1706 state->msglen = -1; 1707 state->msgcnt = 0; 1708 return (1); 1709 1710 case SCSI_NO_OP: 1711 break; 1712 1713 case SCSI_SAVE_DATA_POINTER: 1714 /* expect another message */ 1715 return (1); 1716 1717 case SCSI_RESTORE_POINTERS: 1718 /* 1719 * Need to do the following if resuming synchonous data in 1720 * on an odd byte boundary. 1721 regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1722 */ 1723 break; 1724 1725 case SCSI_DISCONNECT: 1726 if (state->flags & DISCONN) 1727 goto abort; 1728 state->flags |= DISCONN; 1729 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1730 readback(regs->asc_cmd); 1731 asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1732 return (0); 1733 1734 default: 1735 printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1736 asc - asc_softc, asc->target, msg); 1737 reject: 1738 /* request a message out before acknowledging this message */ 1739 state->msg_out = SCSI_MESSAGE_REJECT; 1740 regs->asc_cmd = ASC_CMD_SET_ATN; 1741 readback(regs->asc_cmd); 1742 } 1743 1744 done: 1745 /* return to original script */ 1746 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1747 readback(regs->asc_cmd); 1748 if (!state->script) { 1749 abort: 1750 #ifdef DEBUG 1751 asc_DumpLog("asc_msg_in"); 1752 #endif 1753 panic("asc_msg_in"); 1754 } 1755 asc->script = state->script; 1756 state->script = (script_t *)0; 1757 return (0); 1758 } 1759 1760 /* ARGSUSED */ 1761 static int 1762 asc_disconnect(asc, status, ss, ir) 1763 register asc_softc_t asc; 1764 register int status, ss, ir; 1765 { 1766 register State *state = &asc->st[asc->target]; 1767 1768 #ifdef DIAGNOSTIC 1769 if (!(state->flags & DISCONN)) { 1770 printf("asc_disconnect: device %d: DISCONN not set!\n", 1771 asc->target); 1772 } 1773 #endif 1774 asc->target = -1; 1775 asc->state = ASC_STATE_RESEL; 1776 return (1); 1777 } 1778 1779 /* 1780 * DMA handling routines. For a turbochannel device, just set the dmar. 1781 * For the I/O ASIC, handle the actual DMA interface. 1782 */ 1783 static void 1784 tb_dma_start(asc, state, cp, flag) 1785 asc_softc_t asc; 1786 State *state; 1787 caddr_t cp; 1788 int flag; 1789 { 1790 1791 if (flag == ASCDMA_WRITE) 1792 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 1793 else 1794 *asc->dmar = ASC_DMA_ADDR(cp); 1795 } 1796 1797 static void 1798 tb_dma_end(asc, state, flag) 1799 asc_softc_t asc; 1800 State *state; 1801 int flag; 1802 { 1803 1804 } 1805 1806 static void 1807 asic_dma_start(asc, state, cp, flag) 1808 asc_softc_t asc; 1809 State *state; 1810 caddr_t cp; 1811 int flag; 1812 { 1813 register volatile u_int *ssr = (volatile u_int *) 1814 ASIC_REG_CSR(asic_base); 1815 u_int phys, nphys; 1816 1817 /* stop DMA engine first */ 1818 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1819 *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 1820 1821 phys = MACH_CACHED_TO_PHYS(cp); 1822 cp = (caddr_t)pmax_trunc_page(cp + NBPG); 1823 nphys = MACH_CACHED_TO_PHYS(cp); 1824 1825 asc->dma_next = cp; 1826 asc->dma_xfer = state->dmalen - (nphys - phys); 1827 1828 *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 1829 ASIC_DMA_ADDR(phys); 1830 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1831 ASIC_DMA_ADDR(nphys); 1832 if (flag == ASCDMA_READ) 1833 *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 1834 else 1835 *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 1836 MachEmptyWriteBuffer(); 1837 } 1838 1839 static void 1840 asic_dma_end(asc, state, flag) 1841 asc_softc_t asc; 1842 State *state; 1843 int flag; 1844 { 1845 register volatile u_int *ssr = (volatile u_int *) 1846 ASIC_REG_CSR(asic_base); 1847 register volatile u_int *dmap = (volatile u_int *) 1848 ASIC_REG_SCSI_DMAPTR(asic_base); 1849 register u_short *to; 1850 register int w; 1851 int nb; 1852 1853 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1854 to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); 1855 *dmap = -1; 1856 *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 1857 MachEmptyWriteBuffer(); 1858 1859 if (flag == ASCDMA_READ) { 1860 MachFlushDCache(MACH_PHYS_TO_CACHED( 1861 MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1862 if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 1863 /* pick up last upto6 bytes, sigh. */ 1864 1865 /* Last byte really xferred is.. */ 1866 w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 1867 *to++ = w; 1868 if (--nb > 0) { 1869 w >>= 16; 1870 *to++ = w; 1871 } 1872 if (--nb > 0) { 1873 w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 1874 *to++ = w; 1875 } 1876 } 1877 } 1878 } 1879 1880 #ifdef notdef 1881 /* 1882 * Called by asic_intr() for scsi dma pointer update interrupts. 1883 */ 1884 void 1885 asc_dma_intr() 1886 { 1887 asc_softc_t asc = &asc_softc[0]; 1888 u_int next_phys; 1889 1890 asc->dma_xfer -= NBPG; 1891 if (asc->dma_xfer <= -NBPG) { 1892 volatile u_int *ssr = (volatile u_int *) 1893 ASIC_REG_CSR(asic_base); 1894 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1895 } else { 1896 asc->dma_next += NBPG; 1897 next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 1898 } 1899 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1900 ASIC_DMA_ADDR(next_phys); 1901 MachEmptyWriteBuffer(); 1902 } 1903 #endif 1904 1905 #ifdef DEBUG 1906 asc_DumpLog(str) 1907 char *str; 1908 { 1909 register struct asc_log *lp; 1910 register u_int status; 1911 1912 printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1913 asc_debug_bn, asc_debug_sz); 1914 lp = asc_logp; 1915 do { 1916 status = lp->status; 1917 printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", 1918 status >> 24, 1919 lp->target, 1920 (status >> 16) & 0xFF, 1921 (status >> 8) & 0xFF, 1922 status & 0XFF, 1923 lp->state, 1924 asc_scripts[lp->state].condition, 1925 lp->msg, lp->resid); 1926 if (++lp >= &asc_log[NLOG]) 1927 lp = asc_log; 1928 } while (lp != asc_logp); 1929 } 1930 #endif 1931 1932 #endif /* NASC > 0 */ 1933