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.2 (Berkeley) 03/14/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 int script_nop(); /* when nothing needed */ 212 int asc_end(); /* all come to an end */ 213 int asc_get_status(); /* get status from target */ 214 int asc_dma_in(); /* start reading data from target */ 215 int asc_last_dma_in(); /* cleanup after all data is read */ 216 int asc_resume_in(); /* resume data in after a message */ 217 int asc_resume_dma_in(); /* resume DMA after a disconnect */ 218 int asc_dma_out(); /* send data to target via dma */ 219 int asc_last_dma_out(); /* cleanup after all data is written */ 220 int asc_resume_out(); /* resume data out after a message */ 221 int asc_resume_dma_out(); /* resume DMA after a disconnect */ 222 int asc_sendsync(); /* negotiate sync xfer */ 223 int asc_replysync(); /* negotiate sync xfer */ 224 int asc_msg_in(); /* process a message byte */ 225 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_GET_STATUS]}, 305 {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 13 */ 306 script_nop, ASC_CMD_XFER_INFO, 307 &asc_scripts[SCRIPT_GET_STATUS]}, 308 {SCRIPT_MATCH(ASC_INT_FC, ASC_PHASE_MSG_IN), /* 14 */ 309 asc_msg_in, ASC_CMD_MSG_ACPT, 310 &asc_scripts[SCRIPT_GET_STATUS]}, 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 FIRST_DMA 0x02 /* true if no data DMA started yet */ 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 volatile 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 = (volatile 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, 0); 607 asc_logp->target = asc->target; 608 asc_logp->state = 0; 609 if (++asc_logp >= &asc_log[NLOG]) 610 asc_logp = asc_log; 611 #endif 612 613 /* 614 * Init the chip and target state. 615 */ 616 regs->asc_cmd = ASC_CMD_FLUSH; 617 state->flags = FIRST_DMA | (state->flags & DID_SYNC); 618 state->error = 0; 619 state->script = (script_t *)0; 620 state->msg_out = SCSI_NO_OP; 621 622 /* 623 * Copy command data to the DMA buffer. 624 */ 625 len = scsicmd->cmdlen; 626 state->dmalen = len; 627 bcopy(scsicmd->cmd, state->dmaBufAddr, len); 628 629 /* check for simple SCSI command with no data transfer */ 630 if ((state->buflen = scsicmd->buflen) == 0) { 631 /* check for sync negotiation */ 632 if ((scsicmd->flags & SCSICMD_USE_SYNC) && 633 !(state->flags & DID_SYNC)) { 634 asc->script = &asc_scripts[SCRIPT_TRY_SYNC]; 635 state->flags |= TRY_SYNC; 636 } else 637 asc->script = &asc_scripts[SCRIPT_SIMPLE]; 638 state->buf = (char *)0; 639 } else if (scsicmd->flags & SCSICMD_DATA_TO_DEVICE) { 640 int cnt; 641 642 asc->script = &asc_scripts[SCRIPT_DATA_OUT]; 643 644 /* setup to write first chunk */ 645 state->flags |= DMA_OUT; 646 state->buf = scsicmd->buf; 647 cnt = state->dmaBufSize - len; 648 if (cnt > state->buflen) 649 cnt = state->buflen; 650 else printf("can't write in one chunk cnt %d buflen %d\n", 651 cnt, state->buflen); /* XXX */ 652 state->dmalen = cnt; 653 bcopy(state->buf, state->dmaBufAddr + len, cnt); 654 } else { 655 asc->script = &asc_scripts[SCRIPT_DATA_IN]; 656 state->buf = scsicmd->buf; 657 state->flags |= DMA_IN; 658 } 659 660 /* preload the FIFO with the message to be sent */ 661 regs->asc_fifo = SCSI_DIS_REC_IDENTIFY; 662 663 /* start the asc */ 664 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 665 ASC_TC_PUT(regs, len); 666 667 regs->asc_dbus_id = target; 668 regs->asc_syn_p = state->sync_period; 669 regs->asc_syn_o = state->sync_offset; 670 671 if (state->flags & TRY_SYNC) 672 regs->asc_cmd = ASC_CMD_SEL_ATN_STOP | ASC_CMD_DMA; 673 else 674 regs->asc_cmd = ASC_CMD_SEL_ATN | ASC_CMD_DMA; 675 } 676 677 /* 678 * Interrupt routine 679 * Take interrupts from the chip 680 * 681 * Implementation: 682 * Move along the current command's script if 683 * all is well, invoke error handler if not. 684 */ 685 void 686 asc_intr(unit) 687 int unit; 688 { 689 register asc_softc_t asc = &asc_softc[unit]; 690 register asc_regmap_t *regs = asc->regs; 691 register State *state; 692 register script_t *scpt; 693 register int ss, ir, status; 694 695 again: 696 /* collect ephemeral information */ 697 status = regs->asc_status; 698 ss = regs->asc_ss; 699 ir = regs->asc_intr; /* this resets the previous two */ 700 scpt = asc->script; 701 702 #ifdef DEBUG 703 asc_logp->status = PACK(unit, status, ss, ir); 704 asc_logp->target = (asc->state == ASC_STATE_BUSY) ? asc->target : -1; 705 asc_logp->state = scpt - asc_scripts; 706 asc_logp->msg = -1; 707 if (++asc_logp >= &asc_log[NLOG]) 708 asc_logp = asc_log; 709 if (asc_debug > 2) 710 printf("asc_intr: status %x ss %x ir %x cond %d:%x\n", 711 status, ss, ir, scpt - asc_scripts, scpt->condition); 712 #endif 713 714 /* check the expected state */ 715 if (SCRIPT_MATCH(ir, status) == scpt->condition) { 716 /* 717 * Perform the appropriate operation, then proceed. 718 */ 719 if ((*scpt->action)(asc, status, ss, ir)) { 720 regs->asc_cmd = scpt->command; 721 asc->script = scpt->next; 722 } 723 goto done; 724 } 725 726 /* check for message in or out */ 727 if ((ir & ~ASC_INT_FC) == ASC_INT_BS) { 728 register int len, fifo; 729 730 state = &asc->st[asc->target]; 731 switch (ASC_PHASE(status)) { 732 case ASC_PHASE_MSG_IN: 733 break; 734 735 case ASC_PHASE_MSG_OUT: 736 regs->asc_fifo = state->msg_out; 737 state->msg_out = SCSI_NO_OP; 738 regs->asc_cmd = ASC_CMD_XFER_INFO; 739 goto done; 740 741 case ASC_PHASE_STATUS: 742 asc_DumpLog("asc_intr: status"); /* XXX */ 743 /* probably an error in the SCSI command */ 744 asc->script = &asc_scripts[SCRIPT_GET_STATUS]; 745 regs->asc_cmd = ASC_CMD_I_COMPLETE; 746 goto done; 747 748 default: 749 goto abort; 750 } 751 752 if (state->script) 753 goto abort; 754 755 /* check for DMA in progress */ 756 ASC_TC_GET(regs, len); 757 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 758 /* flush any data in the FIFO */ 759 if (fifo) { 760 printf("asc_intr: suspend flags %x dmalen %d len %d fifo %d\n", 761 state->flags, state->dmalen, 762 len, fifo); /* XXX */ 763 len += fifo; 764 regs->asc_cmd = ASC_CMD_FLUSH; 765 MachEmptyWriteBuffer(); 766 } 767 if (len) { 768 /* save number of bytes still to be sent or received */ 769 state->dmaresid = len; 770 /* setup state to resume to */ 771 if (state->flags & DMA_IN) 772 state->script = 773 &asc_scripts[SCRIPT_RESUME_DMA_IN]; 774 else if (state->flags & DMA_OUT) 775 state->script = 776 &asc_scripts[SCRIPT_RESUME_DMA_OUT]; 777 else 778 state->script = asc->script; 779 } else { 780 /* setup state to resume to */ 781 if (state->flags & DMA_IN) { 782 if (!(state->flags & FIRST_DMA)) { 783 len = state->dmalen; 784 bcopy(state->dmaBufAddr, state->buf, 785 len); 786 state->buf += len; 787 state->buflen -= len; 788 } else 789 state->flags &= ~FIRST_DMA; 790 if (state->buflen) 791 state->script = 792 &asc_scripts[SCRIPT_RESUME_IN]; 793 else 794 state->script = 795 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 796 } else if (state->flags & DMA_OUT) { 797 /* 798 * If this is the last chunk, the next expected 799 * state is to get status. 800 */ 801 len = state->dmalen; 802 state->buf += len; 803 state->buflen -= len; 804 if (state->buflen) 805 state->script = 806 &asc_scripts[SCRIPT_RESUME_OUT]; 807 else 808 state->script = 809 &asc_scripts[SCRIPT_RESUME_NO_DATA]; 810 } else 811 state->script = asc->script; 812 } 813 814 /* setup to receive a message */ 815 asc->script = &asc_scripts[SCRIPT_MSG_IN]; 816 state->msglen = 0; 817 regs->asc_cmd = ASC_CMD_XFER_INFO; 818 goto done; 819 } 820 821 /* check for SCSI bus reset */ 822 if (ir & ASC_INT_RESET) { 823 register int i; 824 825 printf("asc%d: SCSI bus reset!!\n", asc - asc_softc); 826 /* need to flush any pending commands */ 827 for (i = 0; i < ASC_NCMD; i++) { 828 if (!asc->cmd[i]) 829 continue; 830 asc->st[i].error = EIO; 831 asc_end(asc, 0, 0, 0); 832 } 833 /* rearbitrate synchronous offset */ 834 for (i = 0; i < ASC_NCMD; i++) { 835 asc->st[i].sync_offset = 0; 836 asc->st[i].flags = 0; 837 } 838 asc->target = -1; 839 return; 840 } 841 842 /* check for command errors */ 843 if (ir & ASC_INT_ILL) 844 goto abort; 845 846 /* check for disconnect */ 847 if (ir & ASC_INT_DISC) { 848 state = &asc->st[asc->target]; 849 switch (ASC_SS(ss)) { 850 case 0: /* device did not respond */ 851 state->error = ENXIO; 852 asc_end(asc, status, ss, ir); 853 return; 854 855 default: 856 goto abort; 857 } 858 } 859 860 /* check for reselect */ 861 if (ir & ASC_INT_RESEL) { 862 unsigned fifo, id, msg; 863 864 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 865 if (fifo < 2) 866 goto abort; 867 /* read unencoded SCSI ID and convert to binary */ 868 msg = regs->asc_fifo & asc->myidmask; 869 for (id = 0; (msg & 1) == 0; id++) 870 msg >>= 1; 871 /* read identify message */ 872 msg = regs->asc_fifo; 873 #ifdef DEBUG 874 if (asc_logp == asc_log) 875 asc_log[NLOG - 1].msg = msg; 876 else 877 asc_logp[-1].msg = msg; 878 #endif 879 if (asc->state != ASC_STATE_RESEL) 880 goto abort; 881 asc->state = ASC_STATE_BUSY; 882 asc->target = id; 883 state = &asc->st[id]; 884 asc->script = state->script; 885 state->script = (script_t *)0; 886 if (!(state->flags & DISCONN)) 887 goto abort; 888 state->flags &= ~DISCONN; 889 regs->asc_cmd = ASC_CMD_MSG_ACPT; 890 goto done; 891 } 892 893 /* check if we are being selected as a target */ 894 if (ir & (ASC_INT_SEL | ASC_INT_SEL_ATN)) 895 goto abort; 896 897 /* must be just a ASC_INT_FC */ 898 done: 899 MachEmptyWriteBuffer(); 900 if (regs->asc_status & ASC_CSR_INT) 901 goto again; 902 return; 903 904 abort: 905 #ifdef DEBUG 906 asc_DumpLog("asc_intr"); 907 #endif 908 #if 0 909 panic("asc_intr"); 910 #else 911 for (;;); 912 #endif 913 } 914 915 /* 916 * All the many little things that the interrupt 917 * routine might switch to. 918 */ 919 920 /* ARGSUSED */ 921 static int 922 script_nop(asc, status, ss, ir) 923 register asc_softc_t asc; 924 register int status, ss, ir; 925 { 926 return (1); 927 } 928 929 /* ARGSUSED */ 930 static int 931 asc_get_status(asc, status, ss, ir) 932 register asc_softc_t asc; 933 register int status, ss, ir; 934 { 935 register asc_regmap_t *regs = asc->regs; 936 register int data; 937 938 /* 939 * Get the last two bytes in the FIFO. 940 */ 941 if ((data = regs->asc_flags & ASC_FLAGS_FIFO_CNT) != 2) { 942 printf("asc_get_status: fifo cnt %d\n", data); /* XXX */ 943 if (data < 2) { 944 asc->regs->asc_cmd = ASC_CMD_MSG_ACPT; 945 return (0); 946 } 947 do { 948 data = regs->asc_fifo; 949 } while ((regs->asc_flags & ASC_FLAGS_FIFO_CNT) > 2); 950 } 951 952 /* save the status byte */ 953 asc->st[asc->target].statusByte = data = regs->asc_fifo; 954 #ifdef DEBUG 955 if (asc_logp == asc_log) 956 asc_log[NLOG - 1].msg = data; 957 else 958 asc_logp[-1].msg = data; 959 #endif 960 961 /* get the (presumed) command_complete message */ 962 if ((data = regs->asc_fifo) == SCSI_COMMAND_COMPLETE) 963 return (1); 964 965 #ifdef DEBUG 966 printf("asc_get_status: status %x cmd %x\n", 967 asc->st[asc->target].statusByte, data); 968 asc_DumpLog("asc_get_status"); 969 #endif 970 return (0); 971 } 972 973 /* ARGSUSED */ 974 static int 975 asc_end(asc, status, ss, ir) 976 register asc_softc_t asc; 977 register int status, ss, ir; 978 { 979 register ScsiCmd *scsicmd; 980 register State *state; 981 register int i, target; 982 983 asc->state = ASC_STATE_IDLE; 984 target = asc->target; 985 asc->target = -1; 986 scsicmd = asc->cmd[target]; 987 asc->cmd[target] = (ScsiCmd *)0; 988 state = &asc->st[target]; 989 990 #ifdef DEBUG 991 if (asc_debug > 1) { 992 printf("asc_end: %s target %d cmd %x err %d resid %d\n", 993 scsicmd->sd->sd_driver->d_name, target, 994 scsicmd->cmd[0], state->error, state->buflen); 995 } 996 #endif 997 #ifdef DIAGNOSTIC 998 if (target < 0 || !scsicmd) 999 panic("asc_end"); 1000 #endif 1001 1002 /* look for disconnected devices */ 1003 for (i = 0; i < ASC_NCMD; i++) { 1004 if (!asc->cmd[i] || !(asc->st[i].flags & DISCONN)) 1005 continue; 1006 asc->regs->asc_cmd = ASC_CMD_ENABLE_SEL; 1007 asc->state = ASC_STATE_RESEL; 1008 asc->script = &asc_scripts[SCRIPT_RESEL]; 1009 break; 1010 } 1011 1012 /* look for another device that is ready */ 1013 for (i = 0; i < ASC_NCMD; i++) { 1014 /* don't restart a disconnected command */ 1015 if (!asc->cmd[i] || (asc->st[i].flags & DISCONN)) 1016 continue; 1017 asc_startcmd(asc, i); 1018 break; 1019 } 1020 1021 /* signal device driver that the command is done */ 1022 (*scsicmd->sd->sd_driver->d_done)(scsicmd->unit, state->error, 1023 state->buflen, state->statusByte); 1024 1025 return (0); 1026 } 1027 1028 /* ARGSUSED */ 1029 static int 1030 asc_dma_in(asc, status, ss, ir) 1031 register asc_softc_t asc; 1032 register int status, ss, ir; 1033 { 1034 register asc_regmap_t *regs = asc->regs; 1035 register State *state = &asc->st[asc->target]; 1036 register int len, fifo; 1037 1038 /* check for previous chunk in buffer */ 1039 if (!(state->flags & FIRST_DMA)) { 1040 /* 1041 * Only count bytes that have been copied to memory. 1042 * There may be some bytes in the FIFO if synchonous transfers 1043 * are in progress. 1044 */ 1045 ASC_TC_GET(regs, len); 1046 len = state->dmalen - len; 1047 bcopy(state->dmaBufAddr, state->buf, len); 1048 state->buf += len; 1049 state->buflen -= len; 1050 } else 1051 state->flags &= ~FIRST_DMA; 1052 1053 /* setup to start reading the next chunk */ 1054 len = state->buflen; 1055 if (len > state->dmaBufSize) 1056 len = state->dmaBufSize; 1057 state->dmalen = len; 1058 *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 1059 ASC_TC_PUT(regs, len); 1060 #ifdef DEBUG 1061 if (asc_debug > 2) 1062 printf("asc_dma_in: buflen %d, len %d\n", state->buflen, len); 1063 #endif 1064 1065 /* check for next chunk */ 1066 if (len != state->buflen) { 1067 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1068 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1069 return (0); 1070 } 1071 return (1); 1072 } 1073 1074 /* ARGSUSED */ 1075 static int 1076 asc_last_dma_in(asc, status, ss, ir) 1077 register asc_softc_t asc; 1078 register int status, ss, ir; 1079 { 1080 register asc_regmap_t *regs = asc->regs; 1081 register State *state = &asc->st[asc->target]; 1082 register int len, fifo; 1083 1084 /* copy data from buffer to main memory */ 1085 ASC_TC_GET(regs, len); 1086 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1087 #ifdef DEBUG 1088 #if 0 1089 if (asc_debug > 2) 1090 #else 1091 if (asc_debug > 2 || len || fifo) /* XXX */ 1092 #endif 1093 printf("asc_last_dma_in: buflen %d dmalen %d tc %d fifo %d\n", 1094 state->buflen, state->dmalen, len, fifo); 1095 #endif 1096 if (fifo) { 1097 /* device must be trying to send more than we expect */ 1098 regs->asc_cmd = ASC_CMD_FLUSH; 1099 MachEmptyWriteBuffer(); 1100 } 1101 len = state->dmalen - len; 1102 state->buflen -= len; 1103 bcopy(state->dmaBufAddr, state->buf, len); 1104 1105 return (1); 1106 } 1107 1108 /* ARGSUSED */ 1109 static int 1110 asc_resume_in(asc, status, ss, ir) 1111 register asc_softc_t asc; 1112 register int status, ss, ir; 1113 { 1114 register asc_regmap_t *regs = asc->regs; 1115 register State *state = &asc->st[asc->target]; 1116 register int len; 1117 1118 /* setup to start reading the next chunk */ 1119 len = state->buflen; 1120 if (len > state->dmaBufSize) 1121 len = state->dmaBufSize; 1122 state->dmalen = len; 1123 *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr); 1124 ASC_TC_PUT(regs, len); 1125 #ifdef DEBUG 1126 if (asc_debug > 2) 1127 printf("asc_resume_in: buflen %d, len %d\n", state->buflen, 1128 len); 1129 #endif 1130 1131 /* check for next chunk */ 1132 if (len != state->buflen) { 1133 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1134 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1135 return (0); 1136 } 1137 return (1); 1138 } 1139 1140 /* ARGSUSED */ 1141 static int 1142 asc_resume_dma_in(asc, status, ss, ir) 1143 register asc_softc_t asc; 1144 register int status, ss, ir; 1145 { 1146 register asc_regmap_t *regs = asc->regs; 1147 register State *state = &asc->st[asc->target]; 1148 register int len, off; 1149 1150 /* setup to finish reading the current chunk */ 1151 len = state->dmaresid; 1152 off = state->dmalen - len; 1153 if ((off & 1) && state->sync_offset) { 1154 printf("asc_resume_dma_in: odd xfer dmalen %d len %d off %d\n", 1155 state->dmalen, len, off); /* XXX */ 1156 regs->asc_res_fifo = state->dmaBufAddr[off]; 1157 } 1158 *asc->dmar = ASC_DMA_ADDR(state->dmaBufAddr + off); 1159 ASC_TC_PUT(regs, len); 1160 #ifdef DEBUG 1161 if (asc_debug > 2) 1162 printf("asc_resume_dma_in: buflen %d dmalen %d len %d off %d\n", 1163 state->dmalen, state->buflen, len, off); 1164 #endif 1165 1166 /* check for next chunk */ 1167 if (state->dmalen != state->buflen) { 1168 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1169 asc->script = &asc_scripts[SCRIPT_CONTINUE_IN]; 1170 return (0); 1171 } 1172 return (1); 1173 } 1174 1175 /* ARGSUSED */ 1176 static int 1177 asc_dma_out(asc, status, ss, ir) 1178 register asc_softc_t asc; 1179 register int status, ss, ir; 1180 { 1181 register asc_regmap_t *regs = asc->regs; 1182 register State *state = &asc->st[asc->target]; 1183 register int len, fifo; 1184 1185 if (!(state->flags & FIRST_DMA)) { 1186 /* check to be sure previous chunk was finished */ 1187 ASC_TC_GET(regs, len); 1188 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1189 if (len || fifo) 1190 printf("asc_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1191 state->buflen, state->dmalen, len, fifo); /* XXX */ 1192 len += fifo; 1193 len = state->dmalen - len; 1194 state->buflen -= len; 1195 state->buf += len; 1196 1197 /* setup for this chunck */ 1198 len = state->buflen; 1199 if (len > state->dmaBufSize) 1200 len = state->dmaBufSize; 1201 state->dmalen = len; 1202 bcopy(state->buf, state->dmaBufAddr, len); 1203 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 1204 } else 1205 state->flags &= ~FIRST_DMA; 1206 1207 len = state->dmalen; 1208 ASC_TC_PUT(regs, len); 1209 #ifdef DEBUG 1210 if (asc_debug > 2) 1211 printf("asc_dma_out: buflen %d, len %d\n", state->buflen, len); 1212 #endif 1213 1214 /* check for next chunk */ 1215 if (len != state->buflen) { 1216 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1217 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1218 return (0); 1219 } 1220 return (1); 1221 } 1222 1223 /* ARGSUSED */ 1224 static int 1225 asc_last_dma_out(asc, status, ss, ir) 1226 register asc_softc_t asc; 1227 register int status, ss, ir; 1228 { 1229 register asc_regmap_t *regs = asc->regs; 1230 register State *state = &asc->st[asc->target]; 1231 register int len, fifo; 1232 1233 ASC_TC_GET(regs, len); 1234 fifo = regs->asc_flags & ASC_FLAGS_FIFO_CNT; 1235 #ifdef DEBUG 1236 #if 0 1237 if (asc_debug > 2) 1238 #else 1239 if (asc_debug > 2 || len || fifo) /* XXX */ 1240 #endif 1241 printf("asc_last_dma_out: buflen %d dmalen %d tc %d fifo %d\n", 1242 state->buflen, state->dmalen, len, fifo); /* XXX */ 1243 #endif 1244 if (fifo) { 1245 len += fifo; 1246 regs->asc_cmd = ASC_CMD_FLUSH; 1247 MachEmptyWriteBuffer(); 1248 } 1249 len = state->dmalen - len; 1250 state->buflen -= len; 1251 return (1); 1252 } 1253 1254 /* ARGSUSED */ 1255 static int 1256 asc_resume_out(asc, status, ss, ir) 1257 register asc_softc_t asc; 1258 register int status, ss, ir; 1259 { 1260 register asc_regmap_t *regs = asc->regs; 1261 register State *state = &asc->st[asc->target]; 1262 register int len; 1263 1264 /* setup for this chunck */ 1265 len = state->buflen; 1266 if (len > state->dmaBufSize) 1267 len = state->dmaBufSize; 1268 state->dmalen = len; 1269 bcopy(state->buf, state->dmaBufAddr, len); 1270 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr); 1271 ASC_TC_PUT(regs, len); 1272 #ifdef DEBUG 1273 if (asc_debug > 2) 1274 printf("asc_resume_out: buflen %d, len %d\n", state->buflen, 1275 len); 1276 #endif 1277 1278 /* check for next chunk */ 1279 if (len != state->buflen) { 1280 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1281 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1282 return (0); 1283 } 1284 return (1); 1285 } 1286 1287 /* ARGSUSED */ 1288 static int 1289 asc_resume_dma_out(asc, status, ss, ir) 1290 register asc_softc_t asc; 1291 register int status, ss, ir; 1292 { 1293 register asc_regmap_t *regs = asc->regs; 1294 register State *state = &asc->st[asc->target]; 1295 register int len, off; 1296 1297 /* setup to finish writing this chunk */ 1298 len = state->dmaresid; 1299 off = state->dmalen - len; 1300 if (off & 1) { 1301 printf("asc_resume_dma_out: odd xfer dmalen %d len %d off %d\n", 1302 state->dmalen, len, off); /* XXX */ 1303 regs->asc_fifo = state->dmaBufAddr[off]; 1304 off++; 1305 len--; 1306 } 1307 *asc->dmar = ASC_DMAR_WRITE | ASC_DMA_ADDR(state->dmaBufAddr + off); 1308 ASC_TC_PUT(regs, len); 1309 #ifdef DEBUG 1310 if (asc_debug > 2) 1311 printf("asc_resume_dma_out: buflen %d dmalen %d len %d off %d\n", 1312 state->dmalen, state->buflen, len, off); 1313 #endif 1314 1315 /* check for next chunk */ 1316 if (state->dmalen != state->buflen) { 1317 regs->asc_cmd = ASC_CMD_XFER_INFO | ASC_CMD_DMA; 1318 asc->script = &asc_scripts[SCRIPT_CONTINUE_OUT]; 1319 return (0); 1320 } 1321 return (1); 1322 } 1323 1324 /* ARGSUSED */ 1325 static int 1326 asc_sendsync(asc, status, ss, ir) 1327 register asc_softc_t asc; 1328 register int status, ss, ir; 1329 { 1330 register asc_regmap_t *regs = asc->regs; 1331 1332 /* 1333 * Phase is MSG_OUT here. 1334 * Try sync negotiation, unless prohibited 1335 */ 1336 regs->asc_fifo = SCSI_EXTENDED_MSG; 1337 MachEmptyWriteBuffer(); 1338 regs->asc_fifo = 3; 1339 MachEmptyWriteBuffer(); 1340 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1341 MachEmptyWriteBuffer(); 1342 regs->asc_fifo = SCSI_MIN_PERIOD; 1343 MachEmptyWriteBuffer(); 1344 regs->asc_fifo = ASC_MAX_OFFSET; 1345 return (1); 1346 } 1347 1348 /* ARGSUSED */ 1349 static int 1350 asc_replysync(asc, status, ss, ir) 1351 register asc_softc_t asc; 1352 register int status, ss, ir; 1353 { 1354 register asc_regmap_t *regs = asc->regs; 1355 register State *state = &asc->st[asc->target]; 1356 1357 #ifdef DEBUG 1358 if (asc_debug > 2) 1359 printf("asc_replysync: %x %x\n", 1360 asc_to_scsi_period[state->sync_period], 1361 state->sync_offset); 1362 #endif 1363 /* send synchronous transfer in response to a request */ 1364 regs->asc_fifo = SCSI_EXTENDED_MSG; 1365 MachEmptyWriteBuffer(); 1366 regs->asc_fifo = 3; 1367 MachEmptyWriteBuffer(); 1368 regs->asc_fifo = SCSI_SYNCHRONOUS_XFER; 1369 MachEmptyWriteBuffer(); 1370 regs->asc_fifo = asc_to_scsi_period[state->sync_period]; 1371 MachEmptyWriteBuffer(); 1372 regs->asc_fifo = state->sync_offset; 1373 regs->asc_cmd = ASC_CMD_XFER_INFO; 1374 1375 /* return to the appropriate script */ 1376 if (!state->script) { 1377 #ifdef DEBUG 1378 asc_DumpLog("asc_replsync"); 1379 #endif 1380 panic("asc_replysync"); 1381 } 1382 asc->script = state->script; 1383 state->script = (script_t *)0; 1384 return (0); 1385 } 1386 1387 /* ARGSUSED */ 1388 static int 1389 asc_msg_in(asc, status, ss, ir) 1390 register asc_softc_t asc; 1391 register int status, ss, ir; 1392 { 1393 register asc_regmap_t *regs = asc->regs; 1394 register State *state = &asc->st[asc->target]; 1395 register int msg; 1396 int i; 1397 1398 /* read one message byte */ 1399 msg = regs->asc_fifo; 1400 #ifdef DEBUG 1401 if (asc_logp == asc_log) 1402 asc_log[NLOG - 1].msg = msg; 1403 else 1404 asc_logp[-1].msg = msg; 1405 #endif 1406 1407 /* check for multi-byte message */ 1408 if (state->msglen != 0) { 1409 /* first byte is the message length */ 1410 if (state->msglen < 0) { 1411 state->msglen = msg; 1412 return (1); 1413 } 1414 if (state->msgcnt >= state->msglen) 1415 goto abort; 1416 state->msg_in[state->msgcnt++] = msg; 1417 1418 /* did we just read the last byte of the message? */ 1419 if (state->msgcnt != state->msglen) 1420 return (1); 1421 1422 /* process an extended message */ 1423 #ifdef DEBUG 1424 if (asc_debug > 2) 1425 printf("asc_msg_in: msg %x %x %x\n", 1426 state->msg_in[0], 1427 state->msg_in[1], 1428 state->msg_in[2]); 1429 #endif 1430 switch (state->msg_in[0]) { 1431 case SCSI_SYNCHRONOUS_XFER: 1432 state->flags |= DID_SYNC; 1433 state->sync_offset = state->msg_in[2]; 1434 1435 /* convert SCSI period to ASC period */ 1436 i = state->msg_in[1] / 10; 1437 if (i < ASC_MIN_PERIOD) 1438 i = ASC_MIN_PERIOD; 1439 else if (i >= ASC_MAX_PERIOD) { 1440 /* can't do sync transfer, period too long */ 1441 printf("asc%d: SCSI device %d: sync xfer period too long (%d)\n", 1442 asc - asc_softc, asc->target, i); 1443 i = ASC_MAX_PERIOD; 1444 state->sync_offset = 0; 1445 } 1446 if ((i * 10) != state->msg_in[1]) 1447 i++; 1448 state->sync_period = i & 0x1F; 1449 1450 /* 1451 * If this is a request, check minimums and 1452 * send back an acknowledge. 1453 */ 1454 if (!(state->flags & TRY_SYNC)) { 1455 regs->asc_cmd = ASC_CMD_SET_ATN; 1456 MachEmptyWriteBuffer(); 1457 1458 if (state->sync_period < ASC_MIN_PERIOD) 1459 state->sync_period = 1460 ASC_MIN_PERIOD; 1461 if (state->sync_offset > ASC_MAX_OFFSET) 1462 state->sync_offset = 1463 ASC_MAX_OFFSET; 1464 asc->script = &asc_scripts[SCRIPT_REPLY_SYNC]; 1465 regs->asc_syn_p = state->sync_period; 1466 regs->asc_syn_o = state->sync_offset; 1467 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1468 return (0); 1469 } 1470 1471 regs->asc_syn_p = state->sync_period; 1472 regs->asc_syn_o = state->sync_offset; 1473 goto done; 1474 1475 default: 1476 printf("asc%d: SCSI device %d: rejecting extended message 0x%x\n", 1477 asc - asc_softc, asc->target, 1478 state->msg_in[0]); 1479 goto reject; 1480 } 1481 } 1482 1483 /* process first byte of a message */ 1484 #ifdef DEBUG 1485 if (asc_debug > 2) 1486 printf("asc_msg_in: msg %x\n", msg); 1487 #endif 1488 switch (msg) { 1489 #if 0 1490 case SCSI_MESSAGE_REJECT: 1491 printf(" did not like SYNCH xfer "); /* XXX */ 1492 state->flags |= DID_SYNC; 1493 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1494 status = asc_wait(regs, ASC_CSR_INT); 1495 ir = regs->asc_intr; 1496 /* some just break out here, some dont */ 1497 if (ASC_PHASE(status) == ASC_PHASE_MSG_OUT) { 1498 regs->asc_fifo = SCSI_ABORT; 1499 regs->asc_cmd = ASC_CMD_XFER_INFO; 1500 status = asc_wait(regs, ASC_CSR_INT); 1501 ir = regs->asc_intr; 1502 } 1503 if (ir & ASC_INT_DISC) { 1504 asc_end(asc, status, 0, ir); 1505 return (0); 1506 } 1507 goto status; 1508 #endif 1509 1510 case SCSI_EXTENDED_MSG: /* read an extended message */ 1511 /* setup to read message length next */ 1512 state->msglen = -1; 1513 state->msgcnt = 0; 1514 return (1); 1515 1516 case SCSI_NO_OP: 1517 break; 1518 1519 case SCSI_SAVE_DATA_POINTER: 1520 /* expect another message */ 1521 return (1); 1522 1523 case SCSI_RESTORE_POINTERS: 1524 /* 1525 * Need to do the following if resuming synchonous data in 1526 * on an odd byte boundary. 1527 regs->asc_cnfg2 |= ASC_CNFG2_RFB; 1528 */ 1529 break; 1530 1531 case SCSI_DISCONNECT: 1532 if (state->flags & DISCONN) 1533 goto abort; 1534 state->flags |= DISCONN; 1535 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1536 asc->script = &asc_scripts[SCRIPT_DISCONNECT]; 1537 return (0); 1538 1539 default: 1540 printf("asc%d: SCSI device %d: rejecting message 0x%x\n", 1541 asc - asc_softc, asc->target, msg); 1542 reject: 1543 /* request a message out before acknowledging this message */ 1544 state->msg_out = SCSI_MESSAGE_REJECT; 1545 regs->asc_cmd = ASC_CMD_SET_ATN; 1546 MachEmptyWriteBuffer(); 1547 } 1548 1549 done: 1550 /* return to original script */ 1551 regs->asc_cmd = ASC_CMD_MSG_ACPT; 1552 if (!state->script) { 1553 abort: 1554 #ifdef DEBUG 1555 asc_DumpLog("asc_msg_in"); 1556 #endif 1557 panic("asc_msg_in"); 1558 } 1559 asc->script = state->script; 1560 state->script = (script_t *)0; 1561 return (0); 1562 } 1563 1564 /* ARGSUSED */ 1565 static int 1566 asc_disconnect(asc, status, ss, ir) 1567 register asc_softc_t asc; 1568 register int status, ss, ir; 1569 { 1570 register State *state = &asc->st[asc->target]; 1571 1572 asc->target = -1; 1573 asc->state = ASC_STATE_RESEL; 1574 return (1); 1575 } 1576 1577 #ifdef DEBUG 1578 asc_DumpLog(str) 1579 char *str; 1580 { 1581 register struct asc_log *lp; 1582 register u_int status; 1583 1584 printf("asc: %s: cmd %x bn %d cnt %d\n", str, asc_debug_cmd, 1585 asc_debug_bn, asc_debug_sz); 1586 lp = asc_logp + 1; 1587 if (lp > &asc_log[NLOG]) 1588 lp = asc_log; 1589 while (lp != asc_logp) { 1590 status = lp->status; 1591 printf("asc%d tgt %d status %x ss %x ir %x cond %d:%x msg %x\n", 1592 status >> 24, 1593 lp->target, 1594 (status >> 16) & 0xFF, 1595 (status >> 8) & 0xFF, 1596 status & 0XFF, 1597 lp->state, 1598 asc_scripts[lp->state].condition, 1599 lp->msg); 1600 if (++lp >= &asc_log[NLOG]) 1601 lp = asc_log; 1602 } 1603 } 1604 #endif 1605 1606 #endif /* NASC > 0 */ 1607