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.3 (Berkeley) 07/03/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 asc_DumpLog("get_status"); /* XXX */ 1124 if (data < 2) { 1125 asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 1126 readback(asc->regs->asc_cmd); 1127 return (0); 1128 } 1129 do { 1130 data = regs->asc_fifo; 1131 } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 1132 } 1133 1134 /* save the status byte */ 1135 asc->st[asc->target].statusByte = data = regs->asc_fifo; 1136 #ifdef DEBUG 1137 if (asc_logp == asc_log) 1138 asc_log[NLOG - 1].msg = data; 1139 else 1140 asc_logp[-1].msg = data; 1141 #endif 1142 1143 /* get the (presumed) command_complete message */ 1144 if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 1145 return (1); 1146 1147 #ifdef DEBUG 1148 printf("asc_get_status: status %x cmd %x\n", 1149 asc->st[asc->target].statusByte, data); 1150 asc_DumpLog("asc_get_status"); 1151 #endif 1152 return (0); 1153 } 1154 1155 /* ARGSUSED */ 1156 static int 1157 asc_end(asc, status, ss, ir) 1158 register asc_softc_t asc; 1159 register int status, ss, ir; 1160 { 1161 register ScsiCmd *scsicmd; 1162 register State *state; 1163 register int i, target; 1164 1165 asc->state = ASC_STATE_IDLE; 1166 target = asc->target; 1167 asc->target = -1; 1168 scsicmd = asc->cmd[target]; 1169 asc->cmd[target] = (ScsiCmd *)0; 1170 state = &asc->st[target]; 1171 1172 #ifdef DEBUG 1173 if (asc_debug > 1) { 1174 printf("asc_end: %s target %d cmd %x err %d resid %d\n", 1175 scsicmd->sd->sd_driver->d_name, target, 1176 scsicmd->cmd[0], state->error, state->buflen); 1177 } 1178 #endif 1179 #ifdef DIAGNOSTIC 1180 if (target < 0 || !scsicmd) 1181 panic("asc_end"); 1182 #endif 1183 1184 /* look for disconnected devices */ 1185 for (i = 0; i < ASC_NCMD; i++) { 1186 if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 1187 continue; 1188 asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1189 readback(asc->regs->asc_cmd); 1190 asc->state = ASC_STATE_RESEL; 1191 asc->script = &asc_scripts[SCRIPT_RESEL]; 1192 break; 1193 } 1194 1195 /* 1196 * Look for another device that is ready. 1197 * May want to keep last one started and increment for fairness 1198 * rather than always starting at zero. 1199 */ 1200 for (i = 0; i < ASC_NCMD; i++) { 1201 /* don't restart a disconnected command */ 1202 if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 1203 continue; 1204 asc_startcmd(asc, i); 1205 break; 1206 } 1207 1208 /* signal device driver that the command is done */ 1209 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 1210 state->buflen, state->statusByte); 1211 1212 return (0); 1213 } 1214 1215 /* ARGSUSED */ 1216 static int 1217 asc_dma_in(asc, status, ss, ir) 1218 register asc_softc_t asc; 1219 register int status, ss, ir; 1220 { 1221 register asc_regmap_t *regs = asc->regs; 1222 register State *state = &asc->st[asc->target]; 1223 register int len; 1224 1225 /* check for previous chunk in buffer */ 1226 if (state->flags & DMA_IN_PROGRESS) { 1227 /* 1228 * Only count bytes that have been copied to memory. 1229 * There may be some bytes in the FIFO if synchonous transfers 1230 * are in progress. 1231 */ 1232 (*asc->dma_end)(asc, state, ASCDMA_READ); 1233 ASC_TC_GET(regs, len); 1234 len = state->dmalen - len; 1235 bcopy(state->dmaBufAddr, state->buf, len); 1236 state->buf += len; 1237 state->buflen -= len; 1238 } 1239 1240 /* setup to start reading the next chunk */ 1241 len = state->buflen; 1242 #ifdef DEBUG 1243 if (asc_logp == asc_log) 1244 asc_log[NLOG - 1].resid = len; 1245 else 1246 asc_logp[-1].resid = len; 1247 #endif 1248 if (len > state->dmaBufSize) 1249 len = state->dmaBufSize; 1250 state->dmalen = len; 1251 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1252 ASC_TC_PUT(regs, len); 1253 #ifdef DEBUG 1254 if (asc_debug > 2) 1255 printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1256 #endif 1257 1258 /* check for next chunk */ 1259 state->flags |= DMA_IN_PROGRESS; 1260 if (len != state->buflen) { 1261 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1262 readback(regs->asc_cmd); 1263 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1264 return (0); 1265 } 1266 return (1); 1267 } 1268 1269 /* ARGSUSED */ 1270 static int 1271 asc_last_dma_in(asc, status, ss, ir) 1272 register asc_softc_t asc; 1273 register int status, ss, ir; 1274 { 1275 register asc_regmap_t *regs = asc->regs; 1276 register State *state = &asc->st[asc->target]; 1277 register int len, fifo; 1278 1279 /* copy data from buffer to main memory */ 1280 (*asc->dma_end)(asc, state, ASCDMA_READ); 1281 ASC_TC_GET(regs, len); 1282 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1283 #ifdef DEBUG 1284 if (asc_debug > 2) 1285 printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1286 state->buflen, state->dmalen, len, fifo); 1287 #endif 1288 if (fifo) { 1289 /* device must be trying to send more than we expect */ 1290 regs->asc_cmd = ASC_CMD_FLUSH; 1291 readback(regs->asc_cmd); 1292 } 1293 state->flags &= ~DMA_IN_PROGRESS; 1294 len = state->dmalen - len; 1295 state->buflen -= len; 1296 bcopy(state->dmaBufAddr, state->buf, len); 1297 1298 return (1); 1299 } 1300 1301 /* ARGSUSED */ 1302 static int 1303 asc_resume_in(asc, status, ss, ir) 1304 register asc_softc_t asc; 1305 register int status, ss, ir; 1306 { 1307 register asc_regmap_t *regs = asc->regs; 1308 register State *state = &asc->st[asc->target]; 1309 register int len; 1310 1311 /* setup to start reading the next chunk */ 1312 len = state->buflen; 1313 #ifdef DEBUG 1314 if (asc_logp == asc_log) 1315 asc_log[NLOG - 1].resid = len; 1316 else 1317 asc_logp[-1].resid = len; 1318 #endif 1319 if (len > state->dmaBufSize) 1320 len = state->dmaBufSize; 1321 state->dmalen = len; 1322 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1323 ASC_TC_PUT(regs, len); 1324 #ifdef DEBUG 1325 if (asc_debug > 2) 1326 printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1327 len); 1328 #endif 1329 1330 /* check for next chunk */ 1331 state->flags |= DMA_IN_PROGRESS; 1332 if (len != state->buflen) { 1333 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1334 readback(regs->asc_cmd); 1335 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1336 return (0); 1337 } 1338 return (1); 1339 } 1340 1341 /* ARGSUSED */ 1342 static int 1343 asc_resume_dma_in(asc, status, ss, ir) 1344 register asc_softc_t asc; 1345 register int status, ss, ir; 1346 { 1347 register asc_regmap_t *regs = asc->regs; 1348 register State *state = &asc->st[asc->target]; 1349 register int len, off; 1350 1351 /* setup to finish reading the current chunk */ 1352 len = state->dmaresid; 1353 off = state->dmalen - len; 1354 if ((off & 1) && state->sync_offset) { 1355 printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1356 state->dmalen, len, off); /* XXX */ 1357 regs->asc_res_fifo = state->dmaBufAddr[off]; 1358 } 1359 #ifdef DEBUG 1360 if (asc_logp == asc_log) 1361 asc_log[NLOG - 1].resid = len; 1362 else 1363 asc_logp[-1].resid = len; 1364 #endif 1365 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 1366 ASC_TC_PUT(regs, len); 1367 #ifdef DEBUG 1368 if (asc_debug > 2) 1369 printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1370 state->dmalen, state->buflen, len, off); 1371 #endif 1372 1373 /* check for next chunk */ 1374 state->flags |= DMA_IN_PROGRESS; 1375 if (state->dmalen != state->buflen) { 1376 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1377 readback(regs->asc_cmd); 1378 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1379 return (0); 1380 } 1381 return (1); 1382 } 1383 1384 /* ARGSUSED */ 1385 static int 1386 asc_dma_out(asc, status, ss, ir) 1387 register asc_softc_t asc; 1388 register int status, ss, ir; 1389 { 1390 register asc_regmap_t *regs = asc->regs; 1391 register State *state = &asc->st[asc->target]; 1392 register int len, fifo; 1393 1394 if (state->flags & DMA_IN_PROGRESS) { 1395 /* check to be sure previous chunk was finished */ 1396 ASC_TC_GET(regs, len); 1397 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1398 if (len || fifo) 1399 printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1400 state->buflen, state->dmalen, len, fifo); /* XXX */ 1401 len += fifo; 1402 len = state->dmalen - len; 1403 state->buf += len; 1404 state->buflen -= len; 1405 } 1406 1407 /* setup for this chunk */ 1408 len = state->buflen; 1409 #ifdef DEBUG 1410 if (asc_logp == asc_log) 1411 asc_log[NLOG - 1].resid = len; 1412 else 1413 asc_logp[-1].resid = len; 1414 #endif 1415 if (len > state->dmaBufSize) 1416 len = state->dmaBufSize; 1417 state->dmalen = len; 1418 bcopy(state->buf, state->dmaBufAddr, len); 1419 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1420 ASC_TC_PUT(regs, len); 1421 #ifdef DEBUG 1422 if (asc_debug > 2) 1423 printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 1424 #endif 1425 1426 /* check for next chunk */ 1427 state->flags |= DMA_IN_PROGRESS; 1428 if (len != state->buflen) { 1429 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1430 readback(regs->asc_cmd); 1431 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1432 return (0); 1433 } 1434 return (1); 1435 } 1436 1437 /* ARGSUSED */ 1438 static int 1439 asc_last_dma_out(asc, status, ss, ir) 1440 register asc_softc_t asc; 1441 register int status, ss, ir; 1442 { 1443 register asc_regmap_t *regs = asc->regs; 1444 register State *state = &asc->st[asc->target]; 1445 register int len, fifo; 1446 1447 ASC_TC_GET(regs, len); 1448 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1449 #ifdef DEBUG 1450 if (asc_debug > 2) 1451 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1452 state->buflen, state->dmalen, len, fifo); 1453 #endif 1454 if (fifo) { 1455 len += fifo; 1456 regs->asc_cmd = ASC_CMD_FLUSH; 1457 readback(regs->asc_cmd); 1458 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1459 state->buflen, state->dmalen, len, fifo); 1460 } 1461 state->flags &= ~DMA_IN_PROGRESS; 1462 len = state->dmalen - len; 1463 state->buflen -= len; 1464 return (1); 1465 } 1466 1467 /* ARGSUSED */ 1468 static int 1469 asc_resume_out(asc, status, ss, ir) 1470 register asc_softc_t asc; 1471 register int status, ss, ir; 1472 { 1473 register asc_regmap_t *regs = asc->regs; 1474 register State *state = &asc->st[asc->target]; 1475 register int len; 1476 1477 /* setup for this chunk */ 1478 len = state->buflen; 1479 #ifdef DEBUG 1480 if (asc_logp == asc_log) 1481 asc_log[NLOG - 1].resid = len; 1482 else 1483 asc_logp[-1].resid = len; 1484 #endif 1485 if (len > state->dmaBufSize) 1486 len = state->dmaBufSize; 1487 state->dmalen = len; 1488 bcopy(state->buf, state->dmaBufAddr, len); 1489 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1490 ASC_TC_PUT(regs, len); 1491 #ifdef DEBUG 1492 if (asc_debug > 2) 1493 printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1494 len); 1495 #endif 1496 1497 /* check for next chunk */ 1498 state->flags |= DMA_IN_PROGRESS; 1499 if (len != state->buflen) { 1500 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1501 readback(regs->asc_cmd); 1502 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1503 return (0); 1504 } 1505 return (1); 1506 } 1507 1508 /* ARGSUSED */ 1509 static int 1510 asc_resume_dma_out(asc, status, ss, ir) 1511 register asc_softc_t asc; 1512 register int status, ss, ir; 1513 { 1514 register asc_regmap_t *regs = asc->regs; 1515 register State *state = &asc->st[asc->target]; 1516 register int len, off; 1517 1518 /* setup to finish writing this chunk */ 1519 len = state->dmaresid; 1520 off = state->dmalen - len; 1521 if (off & 1) { 1522 printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1523 state->dmalen, len, off); /* XXX */ 1524 regs->asc_fifo = state->dmaBufAddr[off]; 1525 off++; 1526 len--; 1527 } 1528 #ifdef DEBUG 1529 if (asc_logp == asc_log) 1530 asc_log[NLOG - 1].resid = len; 1531 else 1532 asc_logp[-1].resid = len; 1533 #endif 1534 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 1535 ASC_TC_PUT(regs, len); 1536 #ifdef DEBUG 1537 if (asc_debug > 2) 1538 printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1539 state->dmalen, state->buflen, len, off); 1540 #endif 1541 1542 /* check for next chunk */ 1543 state->flags |= DMA_IN_PROGRESS; 1544 if (state->dmalen != state->buflen) { 1545 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1546 readback(regs->asc_cmd); 1547 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1548 return (0); 1549 } 1550 return (1); 1551 } 1552 1553 /* ARGSUSED */ 1554 static int 1555 asc_sendsync(asc, status, ss, ir) 1556 register asc_softc_t asc; 1557 register int status, ss, ir; 1558 { 1559 register asc_regmap_t *regs = asc->regs; 1560 register State *state = &asc->st[asc->target]; 1561 1562 /* send the extended synchronous negotiation message */ 1563 regs->asc_fifo = SCSI_EXTENDED_MSG; 1564 MachEmptyWriteBuffer(); 1565 regs->asc_fifo = 3; 1566 MachEmptyWriteBuffer(); 1567 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1568 MachEmptyWriteBuffer(); 1569 regs->asc_fifo = SCSI_MIN_PERIOD; 1570 MachEmptyWriteBuffer(); 1571 regs->asc_fifo = ASC_MAX_OFFSET; 1572 /* state to resume after we see the sync reply message */ 1573 state->script = asc->script + 2; 1574 state->msglen = 0; 1575 return (1); 1576 } 1577 1578 /* ARGSUSED */ 1579 static int 1580 asc_replysync(asc, status, ss, ir) 1581 register asc_softc_t asc; 1582 register int status, ss, ir; 1583 { 1584 register asc_regmap_t *regs = asc->regs; 1585 register State *state = &asc->st[asc->target]; 1586 1587 #ifdef DEBUG 1588 if (asc_debug > 2) 1589 printf("asc_replysync: %x %x\n", 1590 asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 1591 state->sync_offset); 1592 #endif 1593 /* send synchronous transfer in response to a request */ 1594 regs->asc_fifo = SCSI_EXTENDED_MSG; 1595 MachEmptyWriteBuffer(); 1596 regs->asc_fifo = 3; 1597 MachEmptyWriteBuffer(); 1598 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1599 MachEmptyWriteBuffer(); 1600 regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 1601 MachEmptyWriteBuffer(); 1602 regs->asc_fifo = state->sync_offset; 1603 regs->asc_cmd = ASC_CMD_XFER_INFO; 1604 readback(regs->asc_cmd); 1605 1606 /* return to the appropriate script */ 1607 if (!state->script) { 1608 #ifdef DEBUG 1609 asc_DumpLog("asc_replsync"); 1610 #endif 1611 panic("asc_replysync"); 1612 } 1613 asc->script = state->script; 1614 state->script = (script_t *)0; 1615 return (0); 1616 } 1617 1618 /* ARGSUSED */ 1619 static int 1620 asc_msg_in(asc, status, ss, ir) 1621 register asc_softc_t asc; 1622 register int status, ss, ir; 1623 { 1624 register asc_regmap_t *regs = asc->regs; 1625 register State *state = &asc->st[asc->target]; 1626 register int msg; 1627 int i; 1628 1629 /* read one message byte */ 1630 msg = regs->asc_fifo; 1631 #ifdef DEBUG 1632 if (asc_logp == asc_log) 1633 asc_log[NLOG - 1].msg = msg; 1634 else 1635 asc_logp[-1].msg = msg; 1636 #endif 1637 1638 /* check for multi-byte message */ 1639 if (state->msglen != 0) { 1640 /* first byte is the message length */ 1641 if (state->msglen < 0) { 1642 state->msglen = msg; 1643 return (1); 1644 } 1645 if (state->msgcnt >= state->msglen) 1646 goto abort; 1647 state->msg_in[state->msgcnt++] = msg; 1648 1649 /* did we just read the last byte of the message? */ 1650 if (state->msgcnt != state->msglen) 1651 return (1); 1652 1653 /* process an extended message */ 1654 #ifdef DEBUG 1655 if (asc_debug > 2) 1656 printf("asc_msg_in: msg %x %x %x\n", 1657 state->msg_in[0], 1658 state->msg_in[1], 1659 state->msg_in[2]); 1660 #endif 1661 switch (state->msg_in[0]) { 1662 case SCSI_SYNCHRONOUS_XFER: 1663 state->flags |= DID_SYNC; 1664 state->sync_offset = state->msg_in[2]; 1665 1666 /* convert SCSI period to ASC period */ 1667 i = state->msg_in[1] / asc->tb_ticks; 1668 if (i < asc->min_period) 1669 i = asc->min_period; 1670 else if (i >= asc->max_period) { 1671 /* can't do sync transfer, period too long */ 1672 printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1673 asc - asc_softc, asc->target, i); 1674 i = asc->max_period; 1675 state->sync_offset = 0; 1676 } 1677 if ((i * asc->tb_ticks) != state->msg_in[1]) 1678 i++; 1679 state->sync_period = i & 0x1F; 1680 1681 /* 1682 * If this is a request, check minimums and 1683 * send back an acknowledge. 1684 */ 1685 if (!(state->flags & TRY_SYNC)) { 1686 regs->asc_cmd = ASC_CMD_SET_ATN; 1687 readback(regs->asc_cmd); 1688 1689 if (state->sync_period < asc->min_period) 1690 state->sync_period = 1691 asc->min_period; 1692 if (state->sync_offset > ASC_MAX_OFFSET) 1693 state->sync_offset = 1694 ASC_MAX_OFFSET; 1695 asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1696 regs->asc_syn_p = state->sync_period; 1697 readback(regs->asc_syn_p); 1698 regs->asc_syn_o = state->sync_offset; 1699 readback(regs->asc_syn_o); 1700 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1701 readback(regs->asc_cmd); 1702 return (0); 1703 } 1704 1705 regs->asc_syn_p = state->sync_period; 1706 readback(regs->asc_syn_p); 1707 regs->asc_syn_o = state->sync_offset; 1708 readback(regs->asc_syn_o); 1709 goto done; 1710 1711 default: 1712 printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1713 asc - asc_softc, asc->target, 1714 state->msg_in[0]); 1715 goto reject; 1716 } 1717 } 1718 1719 /* process first byte of a message */ 1720 #ifdef DEBUG 1721 if (asc_debug > 2) 1722 printf("asc_msg_in: msg %x\n", msg); 1723 #endif 1724 switch (msg) { 1725 #if 0 1726 case SCSI_MESSAGE_REJECT: 1727 printf(" did not like SYNCH xfer "); /* XXX */ 1728 state->flags |= DID_SYNC; 1729 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1730 readback(regs->asc_cmd); 1731 status = asc_wait(regs, ASC_CSR_INT); 1732 ir = regs->asc_intr; 1733 /* some just break out here, some dont */ 1734 if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1735 regs->asc_fifo = SCSI_ABORT; 1736 regs->asc_cmd = ASC_CMD_XFER_INFO; 1737 readback(regs->asc_cmd); 1738 status = asc_wait(regs, ASC_CSR_INT); 1739 ir = regs->asc_intr; 1740 } 1741 if (ir & ASC_INT_DISC) { 1742 asc_end(asc, status, 0, ir); 1743 return (0); 1744 } 1745 goto status; 1746 #endif 1747 1748 case SCSI_EXTENDED_MSG: /* read an extended message */ 1749 /* setup to read message length next */ 1750 state->msglen = -1; 1751 state->msgcnt = 0; 1752 return (1); 1753 1754 case SCSI_NO_OP: 1755 break; 1756 1757 case SCSI_SAVE_DATA_POINTER: 1758 /* expect another message */ 1759 return (1); 1760 1761 case SCSI_RESTORE_POINTERS: 1762 /* 1763 * Need to do the following if resuming synchonous data in 1764 * on an odd byte boundary. 1765 regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1766 */ 1767 break; 1768 1769 case SCSI_DISCONNECT: 1770 if (state->flags & DISCONN) 1771 goto abort; 1772 state->flags |= DISCONN; 1773 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1774 readback(regs->asc_cmd); 1775 asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1776 return (0); 1777 1778 default: 1779 printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1780 asc - asc_softc, asc->target, msg); 1781 reject: 1782 /* request a message out before acknowledging this message */ 1783 state->msg_out = SCSI_MESSAGE_REJECT; 1784 regs->asc_cmd = ASC_CMD_SET_ATN; 1785 readback(regs->asc_cmd); 1786 } 1787 1788 done: 1789 /* return to original script */ 1790 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1791 readback(regs->asc_cmd); 1792 if (!state->script) { 1793 abort: 1794 #ifdef DEBUG 1795 asc_DumpLog("asc_msg_in"); 1796 #endif 1797 panic("asc_msg_in"); 1798 } 1799 asc->script = state->script; 1800 state->script = (script_t *)0; 1801 return (0); 1802 } 1803 1804 /* ARGSUSED */ 1805 static int 1806 asc_disconnect(asc, status, ss, ir) 1807 register asc_softc_t asc; 1808 register int status, ss, ir; 1809 { 1810 register State *state = &asc->st[asc->target]; 1811 1812 #ifdef DIAGNOSTIC 1813 if (!(state->flags & DISCONN)) { 1814 printf("asc_disconnect: device %d: DISCONN not set!\n", 1815 asc->target); 1816 } 1817 #endif 1818 asc->target = -1; 1819 asc->state = ASC_STATE_RESEL; 1820 return (1); 1821 } 1822 1823 /* 1824 * DMA handling routines. For a turbochannel device, just set the dmar. 1825 * For the I/O ASIC, handle the actual DMA interface. 1826 */ 1827 static void 1828 tb_dma_start(asc, state, cp, flag) 1829 asc_softc_t asc; 1830 State *state; 1831 caddr_t cp; 1832 int flag; 1833 { 1834 1835 if (flag == ASCDMA_WRITE) 1836 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 1837 else 1838 *asc->dmar = ASC_DMA_ADDR(cp); 1839 } 1840 1841 static void 1842 tb_dma_end(asc, state, flag) 1843 asc_softc_t asc; 1844 State *state; 1845 int flag; 1846 { 1847 1848 } 1849 1850 static void 1851 asic_dma_start(asc, state, cp, flag) 1852 asc_softc_t asc; 1853 State *state; 1854 caddr_t cp; 1855 int flag; 1856 { 1857 register volatile u_int *ssr = (volatile u_int *) 1858 ASIC_REG_CSR(asic_base); 1859 u_int phys, nphys; 1860 1861 /* stop DMA engine first */ 1862 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1863 *((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 1864 1865 phys = MACH_CACHED_TO_PHYS(cp); 1866 cp = (caddr_t)pmax_trunc_page(cp + NBPG); 1867 nphys = MACH_CACHED_TO_PHYS(cp); 1868 1869 asc->dma_next = cp; 1870 asc->dma_xfer = state->dmalen - (nphys - phys); 1871 1872 *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 1873 ASIC_DMA_ADDR(phys); 1874 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1875 ASIC_DMA_ADDR(nphys); 1876 if (flag == ASCDMA_READ) 1877 *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 1878 else 1879 *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 1880 MachEmptyWriteBuffer(); 1881 } 1882 1883 static void 1884 asic_dma_end(asc, state, flag) 1885 asc_softc_t asc; 1886 State *state; 1887 int flag; 1888 { 1889 register volatile u_int *ssr = (volatile u_int *) 1890 ASIC_REG_CSR(asic_base); 1891 register volatile u_int *dmap = (volatile u_int *) 1892 ASIC_REG_SCSI_DMAPTR(asic_base); 1893 register u_short *to; 1894 register int w; 1895 int nb; 1896 1897 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1898 to = (u_short *)MACH_PHYS_TO_CACHED(*dmap >> 3); 1899 *dmap = -1; 1900 *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 1901 MachEmptyWriteBuffer(); 1902 1903 if (flag == ASCDMA_READ) { 1904 MachFlushDCache(MACH_PHYS_TO_CACHED( 1905 MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1906 if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 1907 /* pick up last upto6 bytes, sigh. */ 1908 1909 /* Last byte really xferred is.. */ 1910 w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 1911 *to++ = w; 1912 if (--nb > 0) { 1913 w >>= 16; 1914 *to++ = w; 1915 } 1916 if (--nb > 0) { 1917 w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 1918 *to++ = w; 1919 } 1920 } 1921 } 1922 } 1923 1924 #ifdef notdef 1925 /* 1926 * Called by asic_intr() for scsi dma pointer update interrupts. 1927 */ 1928 void 1929 asc_dma_intr() 1930 { 1931 asc_softc_t asc = &asc_softc[0]; 1932 u_int next_phys; 1933 1934 asc->dma_xfer -= NBPG; 1935 if (asc->dma_xfer <= -NBPG) { 1936 volatile u_int *ssr = (volatile u_int *) 1937 ASIC_REG_CSR(asic_base); 1938 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1939 } else { 1940 asc->dma_next += NBPG; 1941 next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 1942 } 1943 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1944 ASIC_DMA_ADDR(next_phys); 1945 MachEmptyWriteBuffer(); 1946 } 1947 #endif 1948 1949 #ifdef DEBUG 1950 asc_DumpLog(str) 1951 char *str; 1952 { 1953 register struct asc_log *lp; 1954 register u_int status; 1955 1956 printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1957 asc_debug_bn, asc_debug_sz); 1958 lp = asc_logp; 1959 do { 1960 status = lp->status; 1961 printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x resid %d\n", 1962 status >> 24, 1963 lp->target, 1964 (status >> 16) & 0xFF, 1965 (status >> 8) & 0xFF, 1966 status & 0XFF, 1967 lp->state, 1968 asc_scripts[lp->state].condition, 1969 lp->msg, lp->resid); 1970 if (++lp >= &asc_log[NLOG]) 1971 lp = asc_log; 1972 } while (lp != asc_logp); 1973 } 1974 #endif 1975 1976 #endif /* NASC > 0 */ 1977