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