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