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