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