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.10 (Berkeley) 03/08/93 11 */ 12 13 /* 14 * Mach Operating System 15 * Copyright (c) 1991,1990,1989 Carnegie Mellon University 16 * All Rights Reserved. 17 * 18 * Permission to use, copy, modify and distribute this software and its 19 * documentation is hereby granted, provided that both the copyright 20 * notice and this permission notice appear in all copies of the 21 * software, derivative works or modified versions, and any portions 22 * thereof, and that both notices appear in supporting documentation. 23 * 24 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 25 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 26 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 27 * 28 * Carnegie Mellon requests users of this software to return to 29 * 30 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 31 * School of Computer Science 32 * Carnegie Mellon University 33 * Pittsburgh PA 15213-3890 34 * 35 * any improvements or extensions that they make and grant Carnegie the 36 * rights to redistribute these changes. 37 */ 38 39 /* 40 * HISTORY 41 * $Log: scsi_53C94_hdw.c,v $ 42 * Revision 2.5 91/02/05 17:45:07 mrt 43 * Added author notices 44 * [91/02/04 11:18:43 mrt] 45 * 46 * Changed to use new Mach copyright 47 * [91/02/02 12:17:20 mrt] 48 * 49 * Revision 2.4 91/01/08 15:48:24 rpd 50 * Added continuation argument to thread_block. 51 * [90/12/27 rpd] 52 * 53 * Revision 2.3 90/12/05 23:34:48 af 54 * Recovered from pmax merge.. and from the destruction of a disk. 55 * [90/12/03 23:40:40 af] 56 * 57 * Revision 2.1.1.1 90/11/01 03:39:09 af 58 * Created, from the DEC specs: 59 * "PMAZ-AA TURBOchannel SCSI Module Functional Specification" 60 * Workstation Systems Engineering, Palo Alto, CA. Aug 27, 1990. 61 * And from the NCR data sheets 62 * "NCR 53C94, 53C95, 53C96 Advances SCSI Controller" 63 * [90/09/03 af] 64 */ 65 66 /* 67 * File: scsi_53C94_hdw.h 68 * Author: Alessandro Forin, Carnegie Mellon University 69 * Date: 9/90 70 * 71 * Bottom layer of the SCSI driver: chip-dependent functions 72 * 73 * This file contains the code that is specific to the NCR 53C94 74 * SCSI chip (Host Bus Adapter in SCSI parlance): probing, start 75 * operation, and interrupt routine. 76 */ 77 78 /* 79 * This layer works based on small simple 'scripts' that are installed 80 * at the start of the command and drive the chip to completion. 81 * The idea comes from the specs of the NCR 53C700 'script' processor. 82 * 83 * There are various reasons for this, mainly 84 * - Performance: identify the common (successful) path, and follow it; 85 * at interrupt time no code is needed to find the current status 86 * - Code size: it should be easy to compact common operations 87 * - Adaptability: the code skeleton should adapt to different chips without 88 * terrible complications. 89 * - Error handling: and it is easy to modify the actions performed 90 * by the scripts to cope with strange but well identified sequences 91 * 92 */ 93 94 #include <asc.h> 95 #if NASC > 0 96 97 #include <sys/param.h> 98 #include <sys/systm.h> 99 #include <sys/dkstat.h> 100 #include <sys/buf.h> 101 #include <sys/conf.h> 102 #include <sys/errno.h> 103 104 #include <machine/machConst.h> 105 106 #include <pmax/dev/device.h> 107 #include <pmax/dev/scsi.h> 108 #include <pmax/dev/ascreg.h> 109 110 #include <pmax/pmax/asic.h> 111 #include <pmax/pmax/kmin.h> 112 #include <pmax/pmax/pmaxtype.h> 113 114 #define readback(a) { register int foo; foo = (a); } 115 extern int pmax_boardtype; 116 117 /* 118 * In 4ns ticks. 119 */ 120 int asc_to_scsi_period[] = { 121 32, 122 33, 123 34, 124 35, 125 5, 126 5, 127 6, 128 7, 129 8, 130 9, 131 10, 132 11, 133 12, 134 13, 135 14, 136 15, 137 16, 138 17, 139 18, 140 19, 141 20, 142 21, 143 22, 144 23, 145 24, 146 25, 147 26, 148 27, 149 28, 150 29, 151 30, 152 31, 153 }; 154 155 /* 156 * Internal forward declarations. 157 */ 158 static void asc_reset(); 159 static void asc_startcmd(); 160 161 #ifdef DEBUG 162 int asc_debug = 1; 163 int asc_debug_cmd; 164 int asc_debug_bn; 165 int asc_debug_sz; 166 #define NLOG 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 chunk 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 chunk 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 DELAY(2); 845 } 846 if (len) { 847 /* save number of bytes still to be sent or received */ 848 state->dmaresid = len; 849 /* setup state to resume to */ 850 if (state->flags & DMA_IN) 851 state->script = 852 &asc_scripts[SCRIPT_RESUME_DMA_IN]; 853 else if (state->flags & DMA_OUT) 854 state->script = 855 &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 856 else 857 state->script = asc->script; 858 } else { 859 /* setup state to resume to */ 860 if (state->flags & DMA_IN) { 861 if (state->flags & DMA_IN_PROGRESS) { 862 state->flags &= ~DMA_IN_PROGRESS; 863 (*asc->dma_end)(asc, state, ASCDMA_READ); 864 len = state->dmalen; 865 bcopy(state->dmaBufAddr, state->buf, 866 len); 867 state->buf += len; 868 state->buflen -= len; 869 } 870 if (state->buflen) 871 state->script = 872 &asc_scripts[SCRIPT_RESUME_IN]; 873 else 874 state->script = 875 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 876 } else if (state->flags & DMA_OUT) { 877 /* 878 * If this is the last chunk, the next expected 879 * state is to get status. 880 */ 881 if (state->flags & DMA_IN_PROGRESS) { 882 state->flags &= ~DMA_IN_PROGRESS; 883 (*asc->dma_end)(asc, state, ASCDMA_WRITE); 884 len = state->dmalen; 885 state->buf += len; 886 state->buflen -= len; 887 } 888 if (state->buflen) 889 state->script = 890 &asc_scripts[SCRIPT_RESUME_OUT]; 891 else 892 state->script = 893 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 894 } else if (asc->script == &asc_scripts[SCRIPT_SIMPLE]) 895 state->script = 896 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 897 else 898 state->script = asc->script; 899 } 900 901 /* setup to receive a message */ 902 asc->script = &asc_scripts[SCRIPT_MSG_IN]; 903 state->msglen = 0; 904 regs->asc_cmd = ASC_CMD_XFER_INFO; 905 readback(regs->asc_cmd); 906 goto done; 907 } 908 909 /* check for SCSI bus reset */ 910 if (ir & ASC_INT_RESET) { 911 register int i; 912 913 printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 914 /* need to flush any pending commands */ 915 for (i = 0; i < ASC_NCMD; i++) { 916 if (!asc->cmd[i]) 917 continue; 918 asc->st[i].error = EIO; 919 asc_end(asc, 0, 0, 0); 920 } 921 /* rearbitrate synchronous offset */ 922 for (i = 0; i < ASC_NCMD; i++) { 923 asc->st[i].sync_offset = 0; 924 asc->st[i].flags = 0; 925 } 926 asc->target = -1; 927 return; 928 } 929 930 /* check for command errors */ 931 if (ir & ASC_INT_ILL) 932 goto abort; 933 934 /* check for disconnect */ 935 if (ir & ASC_INT_DISC) { 936 state = &asc->st[asc->target]; 937 switch (ASC_SS(ss)) { 938 case 0: /* device did not respond */ 939 state->error = ENXIO; 940 asc_end(asc, status, ss, ir); 941 return; 942 943 default: 944 /* 945 * On rare occasions my RZ24 does a disconnect during 946 * data in phase and the following seems to keep it 947 * happy. 948 * XXX Should a scsi disk ever do this?? 949 */ 950 asc->script = &asc_scripts[SCRIPT_RESEL]; 951 asc->state = ASC_STATE_RESEL; 952 state->flags |= DISCONN; 953 regs->asc_cmd = ASC_CMD_ENABLE_SEL; 954 readback(regs->asc_cmd); 955 return; 956 } 957 } 958 959 /* check for reselect */ 960 if (ir & ASC_INT_RESEL) { 961 unsigned fifo, id, msg; 962 963 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 964 if (fifo < 2) 965 goto abort; 966 /* read unencoded SCSI ID and convert to binary */ 967 msg = regs->asc_fifo & asc->myidmask; 968 for (id = 0; (msg & 1) == 0; id++) 969 msg >>= 1; 970 /* read identify message */ 971 msg = regs->asc_fifo; 972 #ifdef DEBUG 973 if (asc_logp == asc_log) 974 asc_log[NLOG - 1].msg = msg; 975 else 976 asc_logp[-1].msg = msg; 977 #endif 978 if (asc->state != ASC_STATE_RESEL) 979 goto abort; 980 asc->state = ASC_STATE_BUSY; 981 asc->target = id; 982 state = &asc->st[id]; 983 asc->script = state->script; 984 state->script = (script_t *)0; 985 if (!(state->flags & DISCONN)) 986 goto abort; 987 state->flags &= ~DISCONN; 988 regs->asc_syn_p = state->sync_period; 989 regs->asc_syn_o = state->sync_offset; 990 regs->asc_cmd = ASC_CMD_MSG_ACPT; 991 readback(regs->asc_cmd); 992 goto done; 993 } 994 995 /* check if we are being selected as a target */ 996 if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 997 goto abort; 998 999 /* must be just a ASC_INT_FC */ 1000 done: 1001 MachEmptyWriteBuffer(); 1002 /* watch out for HW race conditions and setup & hold time violations */ 1003 ir = regs->asc_status; 1004 while (ir != (status = regs->asc_status)) 1005 ir = status; 1006 if (status & ASC_CSR_INT) 1007 goto again; 1008 return; 1009 1010 abort: 1011 #ifdef DEBUG 1012 asc_DumpLog("asc_intr"); 1013 #endif 1014 #if 0 1015 panic("asc_intr"); 1016 #else 1017 for (;;); 1018 #endif 1019 } 1020 1021 /* 1022 * All the many little things that the interrupt 1023 * routine might switch to. 1024 */ 1025 1026 /* ARGSUSED */ 1027 static int 1028 script_nop(asc, status, ss, ir) 1029 register asc_softc_t asc; 1030 register int status, ss, ir; 1031 { 1032 return (1); 1033 } 1034 1035 /* ARGSUSED */ 1036 static int 1037 asc_get_status(asc, status, ss, ir) 1038 register asc_softc_t asc; 1039 register int status, ss, ir; 1040 { 1041 register asc_regmap_t *regs = asc->regs; 1042 register int data; 1043 1044 /* 1045 * Get the last two bytes in the FIFO. 1046 */ 1047 if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 1048 printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 1049 if (data < 2) { 1050 asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 1051 readback(asc->regs->asc_cmd); 1052 return (0); 1053 } 1054 do { 1055 data = regs->asc_fifo; 1056 } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 1057 } 1058 1059 /* save the status byte */ 1060 asc->st[asc->target].statusByte = data = regs->asc_fifo; 1061 #ifdef DEBUG 1062 if (asc_logp == asc_log) 1063 asc_log[NLOG - 1].msg = data; 1064 else 1065 asc_logp[-1].msg = data; 1066 #endif 1067 1068 /* get the (presumed) command_complete message */ 1069 if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 1070 return (1); 1071 1072 #ifdef DEBUG 1073 printf("asc_get_status: status %x cmd %x\n", 1074 asc->st[asc->target].statusByte, data); 1075 asc_DumpLog("asc_get_status"); 1076 #endif 1077 return (0); 1078 } 1079 1080 /* ARGSUSED */ 1081 static int 1082 asc_end(asc, status, ss, ir) 1083 register asc_softc_t asc; 1084 register int status, ss, ir; 1085 { 1086 register ScsiCmd *scsicmd; 1087 register State *state; 1088 register int i, target; 1089 1090 asc->state = ASC_STATE_IDLE; 1091 target = asc->target; 1092 asc->target = -1; 1093 scsicmd = asc->cmd[target]; 1094 asc->cmd[target] = (ScsiCmd *)0; 1095 state = &asc->st[target]; 1096 1097 #ifdef DEBUG 1098 if (asc_debug > 1) { 1099 printf("asc_end: %s target %d cmd %x err %d resid %d\n", 1100 scsicmd->sd->sd_driver->d_name, target, 1101 scsicmd->cmd[0], state->error, state->buflen); 1102 } 1103 #endif 1104 #ifdef DIAGNOSTIC 1105 if (target < 0 || !scsicmd) 1106 panic("asc_end"); 1107 #endif 1108 1109 /* look for disconnected devices */ 1110 for (i = 0; i < ASC_NCMD; i++) { 1111 if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 1112 continue; 1113 asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1114 readback(asc->regs->asc_cmd); 1115 asc->state = ASC_STATE_RESEL; 1116 asc->script = &asc_scripts[SCRIPT_RESEL]; 1117 break; 1118 } 1119 1120 /* look for another device that is ready */ 1121 for (i = 0; i < ASC_NCMD; i++) { 1122 /* don't restart a disconnected command */ 1123 if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 1124 continue; 1125 asc_startcmd(asc, i); 1126 break; 1127 } 1128 1129 /* signal device driver that the command is done */ 1130 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 1131 state->buflen, state->statusByte); 1132 1133 return (0); 1134 } 1135 1136 /* ARGSUSED */ 1137 static int 1138 asc_dma_in(asc, status, ss, ir) 1139 register asc_softc_t asc; 1140 register int status, ss, ir; 1141 { 1142 register asc_regmap_t *regs = asc->regs; 1143 register State *state = &asc->st[asc->target]; 1144 register int len; 1145 1146 /* check for previous chunk in buffer */ 1147 if (state->flags & DMA_IN_PROGRESS) { 1148 /* 1149 * Only count bytes that have been copied to memory. 1150 * There may be some bytes in the FIFO if synchonous transfers 1151 * are in progress. 1152 */ 1153 (*asc->dma_end)(asc, state, ASCDMA_READ); 1154 ASC_TC_GET(regs, len); 1155 len = state->dmalen - len; 1156 bcopy(state->dmaBufAddr, state->buf, len); 1157 state->buf += len; 1158 state->buflen -= len; 1159 } 1160 1161 /* setup to start reading the next chunk */ 1162 len = state->buflen; 1163 if (len > state->dmaBufSize) 1164 len = state->dmaBufSize; 1165 state->dmalen = len; 1166 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1167 ASC_TC_PUT(regs, len); 1168 #ifdef DEBUG 1169 if (asc_debug > 2) 1170 printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1171 #endif 1172 1173 /* check for next chunk */ 1174 state->flags |= DMA_IN_PROGRESS; 1175 if (len != state->buflen) { 1176 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1177 readback(regs->asc_cmd); 1178 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1179 return (0); 1180 } 1181 return (1); 1182 } 1183 1184 /* ARGSUSED */ 1185 static int 1186 asc_last_dma_in(asc, status, ss, ir) 1187 register asc_softc_t asc; 1188 register int status, ss, ir; 1189 { 1190 register asc_regmap_t *regs = asc->regs; 1191 register State *state = &asc->st[asc->target]; 1192 register int len, fifo; 1193 1194 /* copy data from buffer to main memory */ 1195 (*asc->dma_end)(asc, state, ASCDMA_READ); 1196 ASC_TC_GET(regs, len); 1197 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1198 #ifdef DEBUG 1199 if (asc_debug > 2) 1200 printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1201 state->buflen, state->dmalen, len, fifo); 1202 #endif 1203 if (fifo) { 1204 /* device must be trying to send more than we expect */ 1205 regs->asc_cmd = ASC_CMD_FLUSH; 1206 readback(regs->asc_cmd); 1207 } 1208 state->flags &= ~DMA_IN_PROGRESS; 1209 len = state->dmalen - len; 1210 state->buflen -= len; 1211 bcopy(state->dmaBufAddr, state->buf, len); 1212 1213 return (1); 1214 } 1215 1216 /* ARGSUSED */ 1217 static int 1218 asc_resume_in(asc, status, ss, ir) 1219 register asc_softc_t asc; 1220 register int status, ss, ir; 1221 { 1222 register asc_regmap_t *regs = asc->regs; 1223 register State *state = &asc->st[asc->target]; 1224 register int len; 1225 1226 /* setup to start reading the next chunk */ 1227 len = state->buflen; 1228 if (len > state->dmaBufSize) 1229 len = state->dmaBufSize; 1230 state->dmalen = len; 1231 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_READ); 1232 ASC_TC_PUT(regs, len); 1233 #ifdef DEBUG 1234 if (asc_debug > 2) 1235 printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1236 len); 1237 #endif 1238 1239 /* check for next chunk */ 1240 state->flags |= DMA_IN_PROGRESS; 1241 if (len != state->buflen) { 1242 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1243 readback(regs->asc_cmd); 1244 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1245 return (0); 1246 } 1247 return (1); 1248 } 1249 1250 /* ARGSUSED */ 1251 static int 1252 asc_resume_dma_in(asc, status, ss, ir) 1253 register asc_softc_t asc; 1254 register int status, ss, ir; 1255 { 1256 register asc_regmap_t *regs = asc->regs; 1257 register State *state = &asc->st[asc->target]; 1258 register int len, off; 1259 1260 /* setup to finish reading the current chunk */ 1261 len = state->dmaresid; 1262 off = state->dmalen - len; 1263 if ((off & 1) && state->sync_offset) { 1264 printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1265 state->dmalen, len, off); /* XXX */ 1266 regs->asc_res_fifo = state->dmaBufAddr[off]; 1267 } 1268 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_READ); 1269 ASC_TC_PUT(regs, len); 1270 #ifdef DEBUG 1271 if (asc_debug > 2) 1272 printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1273 state->dmalen, state->buflen, len, off); 1274 #endif 1275 1276 /* check for next chunk */ 1277 state->flags |= DMA_IN_PROGRESS; 1278 if (state->dmalen != state->buflen) { 1279 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1280 readback(regs->asc_cmd); 1281 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1282 return (0); 1283 } 1284 return (1); 1285 } 1286 1287 /* ARGSUSED */ 1288 static int 1289 asc_dma_out(asc, status, ss, ir) 1290 register asc_softc_t asc; 1291 register int status, ss, ir; 1292 { 1293 register asc_regmap_t *regs = asc->regs; 1294 register State *state = &asc->st[asc->target]; 1295 register int len, fifo; 1296 1297 if (state->flags & DMA_IN_PROGRESS) { 1298 /* check to be sure previous chunk was finished */ 1299 ASC_TC_GET(regs, len); 1300 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1301 if (len || fifo) 1302 printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1303 state->buflen, state->dmalen, len, fifo); /* XXX */ 1304 len += fifo; 1305 len = state->dmalen - len; 1306 state->buf += len; 1307 state->buflen -= len; 1308 } 1309 1310 /* setup for this chunck */ 1311 len = state->buflen; 1312 if (len > state->dmaBufSize) 1313 len = state->dmaBufSize; 1314 state->dmalen = len; 1315 bcopy(state->buf, state->dmaBufAddr, len); 1316 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1317 ASC_TC_PUT(regs, len); 1318 #ifdef DEBUG 1319 if (asc_debug > 2) 1320 printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 1321 #endif 1322 1323 /* check for next chunk */ 1324 state->flags |= DMA_IN_PROGRESS; 1325 if (len != state->buflen) { 1326 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1327 readback(regs->asc_cmd); 1328 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1329 return (0); 1330 } 1331 return (1); 1332 } 1333 1334 /* ARGSUSED */ 1335 static int 1336 asc_last_dma_out(asc, status, ss, ir) 1337 register asc_softc_t asc; 1338 register int status, ss, ir; 1339 { 1340 register asc_regmap_t *regs = asc->regs; 1341 register State *state = &asc->st[asc->target]; 1342 register int len, fifo; 1343 1344 ASC_TC_GET(regs, len); 1345 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1346 #ifdef DEBUG 1347 if (asc_debug > 2) 1348 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1349 state->buflen, state->dmalen, len, fifo); 1350 #endif 1351 if (fifo) { 1352 len += fifo; 1353 regs->asc_cmd = ASC_CMD_FLUSH; 1354 readback(regs->asc_cmd); 1355 } 1356 state->flags &= ~DMA_IN_PROGRESS; 1357 len = state->dmalen - len; 1358 state->buflen -= len; 1359 return (1); 1360 } 1361 1362 /* ARGSUSED */ 1363 static int 1364 asc_resume_out(asc, status, ss, ir) 1365 register asc_softc_t asc; 1366 register int status, ss, ir; 1367 { 1368 register asc_regmap_t *regs = asc->regs; 1369 register State *state = &asc->st[asc->target]; 1370 register int len; 1371 1372 /* setup for this chunck */ 1373 len = state->buflen; 1374 if (len > state->dmaBufSize) 1375 len = state->dmaBufSize; 1376 state->dmalen = len; 1377 bcopy(state->buf, state->dmaBufAddr, len); 1378 (*asc->dma_start)(asc, state, state->dmaBufAddr, ASCDMA_WRITE); 1379 ASC_TC_PUT(regs, len); 1380 #ifdef DEBUG 1381 if (asc_debug > 2) 1382 printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1383 len); 1384 #endif 1385 1386 /* check for next chunk */ 1387 state->flags |= DMA_IN_PROGRESS; 1388 if (len != state->buflen) { 1389 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1390 readback(regs->asc_cmd); 1391 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1392 return (0); 1393 } 1394 return (1); 1395 } 1396 1397 /* ARGSUSED */ 1398 static int 1399 asc_resume_dma_out(asc, status, ss, ir) 1400 register asc_softc_t asc; 1401 register int status, ss, ir; 1402 { 1403 register asc_regmap_t *regs = asc->regs; 1404 register State *state = &asc->st[asc->target]; 1405 register int len, off; 1406 1407 /* setup to finish writing this chunk */ 1408 len = state->dmaresid; 1409 off = state->dmalen - len; 1410 if (off & 1) { 1411 printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1412 state->dmalen, len, off); /* XXX */ 1413 regs->asc_fifo = state->dmaBufAddr[off]; 1414 off++; 1415 len--; 1416 } 1417 (*asc->dma_start)(asc, state, state->dmaBufAddr + off, ASCDMA_WRITE); 1418 ASC_TC_PUT(regs, len); 1419 #ifdef DEBUG 1420 if (asc_debug > 2) 1421 printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1422 state->dmalen, state->buflen, len, off); 1423 #endif 1424 1425 /* check for next chunk */ 1426 state->flags |= DMA_IN_PROGRESS; 1427 if (state->dmalen != state->buflen) { 1428 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1429 readback(regs->asc_cmd); 1430 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1431 return (0); 1432 } 1433 return (1); 1434 } 1435 1436 /* ARGSUSED */ 1437 static int 1438 asc_sendsync(asc, status, ss, ir) 1439 register asc_softc_t asc; 1440 register int status, ss, ir; 1441 { 1442 register asc_regmap_t *regs = asc->regs; 1443 register State *state = &asc->st[asc->target]; 1444 1445 /* send the extended synchronous negotiation message */ 1446 regs->asc_fifo = SCSI_EXTENDED_MSG; 1447 MachEmptyWriteBuffer(); 1448 regs->asc_fifo = 3; 1449 MachEmptyWriteBuffer(); 1450 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1451 MachEmptyWriteBuffer(); 1452 regs->asc_fifo = SCSI_MIN_PERIOD; 1453 MachEmptyWriteBuffer(); 1454 regs->asc_fifo = ASC_MAX_OFFSET; 1455 /* state to resume after we see the sync reply message */ 1456 state->script = asc->script + 2; 1457 state->msglen = 0; 1458 return (1); 1459 } 1460 1461 /* ARGSUSED */ 1462 static int 1463 asc_replysync(asc, status, ss, ir) 1464 register asc_softc_t asc; 1465 register int status, ss, ir; 1466 { 1467 register asc_regmap_t *regs = asc->regs; 1468 register State *state = &asc->st[asc->target]; 1469 1470 #ifdef DEBUG 1471 if (asc_debug > 2) 1472 printf("asc_replysync: %x %x\n", 1473 asc_to_scsi_period[state->sync_period] * asc->tb_ticks, 1474 state->sync_offset); 1475 #endif 1476 /* send synchronous transfer in response to a request */ 1477 regs->asc_fifo = SCSI_EXTENDED_MSG; 1478 MachEmptyWriteBuffer(); 1479 regs->asc_fifo = 3; 1480 MachEmptyWriteBuffer(); 1481 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1482 MachEmptyWriteBuffer(); 1483 regs->asc_fifo = asc_to_scsi_period[state->sync_period] * asc->tb_ticks; 1484 MachEmptyWriteBuffer(); 1485 regs->asc_fifo = state->sync_offset; 1486 regs->asc_cmd = ASC_CMD_XFER_INFO; 1487 readback(regs->asc_cmd); 1488 1489 /* return to the appropriate script */ 1490 if (!state->script) { 1491 #ifdef DEBUG 1492 asc_DumpLog("asc_replsync"); 1493 #endif 1494 panic("asc_replysync"); 1495 } 1496 asc->script = state->script; 1497 state->script = (script_t *)0; 1498 return (0); 1499 } 1500 1501 /* ARGSUSED */ 1502 static int 1503 asc_msg_in(asc, status, ss, ir) 1504 register asc_softc_t asc; 1505 register int status, ss, ir; 1506 { 1507 register asc_regmap_t *regs = asc->regs; 1508 register State *state = &asc->st[asc->target]; 1509 register int msg; 1510 int i; 1511 1512 /* read one message byte */ 1513 msg = regs->asc_fifo; 1514 #ifdef DEBUG 1515 if (asc_logp == asc_log) 1516 asc_log[NLOG - 1].msg = msg; 1517 else 1518 asc_logp[-1].msg = msg; 1519 #endif 1520 1521 /* check for multi-byte message */ 1522 if (state->msglen != 0) { 1523 /* first byte is the message length */ 1524 if (state->msglen < 0) { 1525 state->msglen = msg; 1526 return (1); 1527 } 1528 if (state->msgcnt >= state->msglen) 1529 goto abort; 1530 state->msg_in[state->msgcnt++] = msg; 1531 1532 /* did we just read the last byte of the message? */ 1533 if (state->msgcnt != state->msglen) 1534 return (1); 1535 1536 /* process an extended message */ 1537 #ifdef DEBUG 1538 if (asc_debug > 2) 1539 printf("asc_msg_in: msg %x %x %x\n", 1540 state->msg_in[0], 1541 state->msg_in[1], 1542 state->msg_in[2]); 1543 #endif 1544 switch (state->msg_in[0]) { 1545 case SCSI_SYNCHRONOUS_XFER: 1546 state->flags |= DID_SYNC; 1547 state->sync_offset = state->msg_in[2]; 1548 1549 /* convert SCSI period to ASC period */ 1550 i = state->msg_in[1] / asc->tb_ticks; 1551 if (i < asc->min_period) 1552 i = asc->min_period; 1553 else if (i >= asc->max_period) { 1554 /* can't do sync transfer, period too long */ 1555 printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1556 asc - asc_softc, asc->target, i); 1557 i = asc->max_period; 1558 state->sync_offset = 0; 1559 } 1560 if ((i * asc->tb_ticks) != state->msg_in[1]) 1561 i++; 1562 state->sync_period = i & 0x1F; 1563 1564 /* 1565 * If this is a request, check minimums and 1566 * send back an acknowledge. 1567 */ 1568 if (!(state->flags & TRY_SYNC)) { 1569 regs->asc_cmd = ASC_CMD_SET_ATN; 1570 readback(regs->asc_cmd); 1571 1572 if (state->sync_period < asc->min_period) 1573 state->sync_period = 1574 asc->min_period; 1575 if (state->sync_offset > ASC_MAX_OFFSET) 1576 state->sync_offset = 1577 ASC_MAX_OFFSET; 1578 asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1579 regs->asc_syn_p = state->sync_period; 1580 readback(regs->asc_syn_p); 1581 regs->asc_syn_o = state->sync_offset; 1582 readback(regs->asc_syn_o); 1583 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1584 readback(regs->asc_cmd); 1585 return (0); 1586 } 1587 1588 regs->asc_syn_p = state->sync_period; 1589 readback(regs->asc_syn_p); 1590 regs->asc_syn_o = state->sync_offset; 1591 readback(regs->asc_syn_o); 1592 goto done; 1593 1594 default: 1595 printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1596 asc - asc_softc, asc->target, 1597 state->msg_in[0]); 1598 goto reject; 1599 } 1600 } 1601 1602 /* process first byte of a message */ 1603 #ifdef DEBUG 1604 if (asc_debug > 2) 1605 printf("asc_msg_in: msg %x\n", msg); 1606 #endif 1607 switch (msg) { 1608 #if 0 1609 case SCSI_MESSAGE_REJECT: 1610 printf(" did not like SYNCH xfer "); /* XXX */ 1611 state->flags |= DID_SYNC; 1612 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1613 readback(regs->asc_cmd); 1614 status = asc_wait(regs, ASC_CSR_INT); 1615 ir = regs->asc_intr; 1616 /* some just break out here, some dont */ 1617 if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1618 regs->asc_fifo = SCSI_ABORT; 1619 regs->asc_cmd = ASC_CMD_XFER_INFO; 1620 readback(regs->asc_cmd); 1621 status = asc_wait(regs, ASC_CSR_INT); 1622 ir = regs->asc_intr; 1623 } 1624 if (ir & ASC_INT_DISC) { 1625 asc_end(asc, status, 0, ir); 1626 return (0); 1627 } 1628 goto status; 1629 #endif 1630 1631 case SCSI_EXTENDED_MSG: /* read an extended message */ 1632 /* setup to read message length next */ 1633 state->msglen = -1; 1634 state->msgcnt = 0; 1635 return (1); 1636 1637 case SCSI_NO_OP: 1638 break; 1639 1640 case SCSI_SAVE_DATA_POINTER: 1641 /* expect another message */ 1642 return (1); 1643 1644 case SCSI_RESTORE_POINTERS: 1645 /* 1646 * Need to do the following if resuming synchonous data in 1647 * on an odd byte boundary. 1648 regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1649 */ 1650 break; 1651 1652 case SCSI_DISCONNECT: 1653 if (state->flags & DISCONN) 1654 goto abort; 1655 state->flags |= DISCONN; 1656 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1657 readback(regs->asc_cmd); 1658 asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1659 return (0); 1660 1661 default: 1662 printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1663 asc - asc_softc, asc->target, msg); 1664 reject: 1665 /* request a message out before acknowledging this message */ 1666 state->msg_out = SCSI_MESSAGE_REJECT; 1667 regs->asc_cmd = ASC_CMD_SET_ATN; 1668 readback(regs->asc_cmd); 1669 } 1670 1671 done: 1672 /* return to original script */ 1673 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1674 readback(regs->asc_cmd); 1675 if (!state->script) { 1676 abort: 1677 #ifdef DEBUG 1678 asc_DumpLog("asc_msg_in"); 1679 #endif 1680 panic("asc_msg_in"); 1681 } 1682 asc->script = state->script; 1683 state->script = (script_t *)0; 1684 return (0); 1685 } 1686 1687 /* ARGSUSED */ 1688 static int 1689 asc_disconnect(asc, status, ss, ir) 1690 register asc_softc_t asc; 1691 register int status, ss, ir; 1692 { 1693 register State *state = &asc->st[asc->target]; 1694 1695 asc->target = -1; 1696 asc->state = ASC_STATE_RESEL; 1697 return (1); 1698 } 1699 1700 /* 1701 * DMA handling routines. For a turbochannel device, just set the dmar 1702 * for the I/O ASIC, handle the actual DMA interface. 1703 */ 1704 static void 1705 tb_dma_start(asc, state, cp, flag) 1706 asc_softc_t asc; 1707 State *state; 1708 caddr_t cp; 1709 int flag; 1710 { 1711 1712 if (flag == ASCDMA_WRITE) 1713 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(cp); 1714 else 1715 *asc->dmar = ASC_DMA_ADDR(cp); 1716 } 1717 1718 static void 1719 tb_dma_end(asc, state, flag) 1720 asc_softc_t asc; 1721 State *state; 1722 int flag; 1723 { 1724 1725 } 1726 1727 static void 1728 asic_dma_start(asc, state, cp, flag) 1729 asc_softc_t asc; 1730 State *state; 1731 caddr_t cp; 1732 int flag; 1733 { 1734 register volatile u_int *ssr = (volatile u_int *) 1735 ASIC_REG_CSR(asic_base); 1736 u_int phys, nphys; 1737 1738 /* stop DMA engine first */ 1739 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1740 * ((volatile int *)ASIC_REG_SCSI_SCR(asic_base)) = 0; 1741 1742 phys = MACH_CACHED_TO_PHYS(cp); 1743 cp = (caddr_t)pmax_trunc_page(cp + NBPG); 1744 nphys = MACH_CACHED_TO_PHYS(cp); 1745 1746 asc->dma_next = cp; 1747 asc->dma_xfer = state->dmalen - (nphys - phys); 1748 1749 *(volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base) = 1750 ASIC_DMA_ADDR(phys); 1751 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1752 ASIC_DMA_ADDR(nphys); 1753 if (flag == ASCDMA_READ) 1754 *ssr |= ASIC_CSR_SCSI_DIR | ASIC_CSR_DMAEN_SCSI; 1755 else 1756 *ssr = (*ssr & ~ASIC_CSR_SCSI_DIR) | ASIC_CSR_DMAEN_SCSI; 1757 MachEmptyWriteBuffer(); 1758 } 1759 1760 static void 1761 asic_dma_end(asc, state, flag) 1762 asc_softc_t asc; 1763 State *state; 1764 int flag; 1765 { 1766 register volatile u_int *ssr = (volatile u_int *) 1767 ASIC_REG_CSR(asic_base); 1768 int nb; 1769 1770 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1771 *((volatile int *)ASIC_REG_SCSI_DMAPTR(asic_base)) = -1; 1772 *((volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base)) = -1; 1773 MachEmptyWriteBuffer(); 1774 1775 if (flag == ASCDMA_READ) { 1776 MachFlushDCache(MACH_PHYS_TO_CACHED( 1777 MACH_UNCACHED_TO_PHYS(state->dmaBufAddr)), state->dmalen); 1778 if (nb = *((int *)ASIC_REG_SCSI_SCR(asic_base))) { 1779 /* pick up last upto6 bytes, sigh. */ 1780 register u_short *to; 1781 register int w; 1782 1783 /* Last byte really xferred is.. */ 1784 to = (u_short *)(state->dmaBufAddr + state->dmalen - (nb << 1)); 1785 w = *(int *)ASIC_REG_SCSI_SDR0(asic_base); 1786 *to++ = w; 1787 if (--nb > 0) { 1788 w >>= 16; 1789 *to++ = w; 1790 } 1791 if (--nb > 0) { 1792 w = *(int *)ASIC_REG_SCSI_SDR1(asic_base); 1793 *to++ = w; 1794 } 1795 } 1796 } 1797 } 1798 1799 #ifdef notdef 1800 /* 1801 * Called by asic_intr() for scsi dma pointer update interrupts. 1802 */ 1803 void 1804 asc_dma_intr() 1805 { 1806 asc_softc_t asc = &asc_softc[0]; 1807 u_int next_phys; 1808 1809 asc->dma_xfer -= NBPG; 1810 if (asc->dma_xfer <= -NBPG) { 1811 volatile u_int *ssr = (volatile u_int *) 1812 ASIC_REG_CSR(asic_base); 1813 *ssr &= ~ASIC_CSR_DMAEN_SCSI; 1814 } else { 1815 asc->dma_next += NBPG; 1816 next_phys = MACH_CACHED_TO_PHYS(asc->dma_next); 1817 } 1818 *(volatile int *)ASIC_REG_SCSI_DMANPTR(asic_base) = 1819 ASIC_DMA_ADDR(next_phys); 1820 MachEmptyWriteBuffer(); 1821 } 1822 #endif 1823 1824 #ifdef DEBUG 1825 asc_DumpLog(str) 1826 char *str; 1827 { 1828 register struct asc_log *lp; 1829 register u_int status; 1830 1831 printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1832 asc_debug_bn, asc_debug_sz); 1833 lp = asc_logp; 1834 do { 1835 status = lp->status; 1836 printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 1837 status >> 24, 1838 lp->target, 1839 (status >> 16) & 0xFF, 1840 (status >> 8) & 0xFF, 1841 status & 0XFF, 1842 lp->state, 1843 asc_scripts[lp->state].condition, 1844 lp->msg); 1845 if (++lp >= &asc_log[NLOG]) 1846 lp = asc_log; 1847 } while (lp != asc_logp); 1848 } 1849 #endif 1850 1851 #endif /* NASC > 0 */ 1852