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