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