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