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