1#undef DEBUG 2#undef EVENTS 3#undef NO_SELECTION_TIMEOUT 4#define BIG_ENDIAN 5 6; 53c710 driver. Modified from Drew Eckhardts driver 7; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk] 8; 9; I have left the script for the 53c8xx family in here, as it is likely 10; to be useful to see what I changed when bug hunting. 11 12; NCR 53c810 driver, main script 13; Sponsored by 14; iX Multiuser Multitasking Magazine 15; hm@ix.de 16; 17; Copyright 1993, 1994, 1995 Drew Eckhardt 18; Visionary Computing 19; (Unix and Linux consulting and custom programming) 20; drew@PoohSticks.ORG 21; +1 (303) 786-7975 22; 23; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation. 24; 25; PRE-ALPHA 26; 27; For more information, please consult 28; 29; NCR 53C810 30; PCI-SCSI I/O Processor 31; Data Manual 32; 33; NCR 53C710 34; SCSI I/O Processor 35; Programmers Guide 36; 37; NCR Microelectronics 38; 1635 Aeroplaza Drive 39; Colorado Springs, CO 80916 40; 1+ (719) 578-3400 41; 42; Toll free literature number 43; +1 (800) 334-5454 44; 45; IMPORTANT : This code is self modifying due to the limitations of 46; the NCR53c7,8xx series chips. Persons debugging this code with 47; the remote debugger should take this into account, and NOT set 48; breakpoints in modified instructions. 49; 50; Design: 51; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 52; microcontroller using a simple instruction set. 53; 54; So, to minimize the effects of interrupt latency, and to maximize 55; throughput, this driver offloads the practical maximum amount 56; of processing to the SCSI chip while still maintaining a common 57; structure. 58; 59; Where tradeoffs were needed between efficiency on the older 60; chips and the newer NCR53c800 series, the NCR53c800 series 61; was chosen. 62; 63; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully 64; automate SCSI transfers without host processor intervention, this 65; isn't the case with the NCR53c710 and newer chips which allow 66; 67; - reads and writes to the internal registers from within the SCSI 68; scripts, allowing the SCSI SCRIPTS(tm) code to save processor 69; state so that multiple threads of execution are possible, and also 70; provide an ALU for loop control, etc. 71; 72; - table indirect addressing for some instructions. This allows 73; pointers to be located relative to the DSA ((Data Structure 74; Address) register. 75; 76; These features make it possible to implement a mailbox style interface, 77; where the same piece of code is run to handle I/O for multiple threads 78; at once minimizing our need to relocate code. Since the NCR53c700/ 79; NCR53c800 series have a unique combination of features, making a 80; a standard ingoing/outgoing mailbox system, costly, I've modified it. 81; 82; - Mailboxes are a mixture of code and data. This lets us greatly 83; simplify the NCR53c810 code and do things that would otherwise 84; not be possible. 85; 86; The saved data pointer is now implemented as follows : 87; 88; Control flow has been architected such that if control reaches 89; munge_save_data_pointer, on a restore pointers message or 90; reconnection, a jump to the address formerly in the TEMP register 91; will allow the SCSI command to resume execution. 92; 93 94; 95; Note : the DSA structures must be aligned on 32 bit boundaries, 96; since the source and destination of MOVE MEMORY instructions 97; must share the same alignment and this is the alignment of the 98; NCR registers. 99; 100 101; For some systems (MVME166, for example) dmode is always the same, so don't 102; waste time writing it 103 104#if 1 105#define DMODE_MEMORY_TO_NCR 106#define DMODE_MEMORY_TO_MEMORY 107#define DMODE_NCR_TO_MEMORY 108#else 109#define DMODE_MEMORY_TO_NCR MOVE dmode_memory_to_ncr TO DMODE 110#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE 111#define DMODE_NCR_TO_MEMORY MOVE dmode_ncr_to_memory TO DMODE 112#endif 113 114ABSOLUTE dsa_temp_lun = 0 ; Patch to lun for current dsa 115ABSOLUTE dsa_temp_next = 0 ; Patch to dsa next for current dsa 116ABSOLUTE dsa_temp_addr_next = 0 ; Patch to address of dsa next address 117 ; for current dsa 118ABSOLUTE dsa_temp_sync = 0 ; Patch to address of per-target 119 ; sync routine 120ABSOLUTE dsa_sscf_710 = 0 ; Patch to address of per-target 121 ; sscf value (53c710) 122ABSOLUTE dsa_temp_target = 0 ; Patch to id for current dsa 123ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command 124 ; saved data pointer 125ABSOLUTE dsa_temp_addr_residual = 0 ; Patch to address of per-command 126 ; current residual code 127ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command 128 ; saved residual code 129ABSOLUTE dsa_temp_addr_new_value = 0 ; Address of value for JUMP operand 130ABSOLUTE dsa_temp_addr_array_value = 0 ; Address to copy to 131ABSOLUTE dsa_temp_addr_dsa_value = 0 ; Address of this DSA value 132 133; 134; Once a device has initiated reselection, we need to compare it 135; against the singly linked list of commands which have disconnected 136; and are pending reselection. These commands are maintained in 137; an unordered singly linked list of DSA structures, through the 138; DSA pointers at their 'centers' headed by the reconnect_dsa_head 139; pointer. 140; 141; To avoid complications in removing commands from the list, 142; I minimize the amount of expensive (at eight operations per 143; addition @ 500-600ns each) pointer operations which must 144; be done in the NCR driver by precomputing them on the 145; host processor during dsa structure generation. 146; 147; The fixed-up per DSA code knows how to recognize the nexus 148; associated with the corresponding SCSI command, and modifies 149; the source and destination pointers for the MOVE MEMORY 150; instruction which is executed when reselected_ok is called 151; to remove the command from the list. Similarly, DSA is 152; loaded with the address of the next DSA structure and 153; reselected_check_next is called if a failure occurs. 154; 155; Perhaps more concisely, the net effect of the mess is 156; 157; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, 158; src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) { 159; src = &dsa->next; 160; if (target_id == dsa->id && target_lun == dsa->lun) { 161; *dest = *src; 162; break; 163; } 164; } 165; 166; if (!dsa) 167; error (int_err_unexpected_reselect); 168; else 169; longjmp (dsa->jump_resume, 0); 170; 171; 172 173#if (CHIP != 700) && (CHIP != 70066) 174; Define DSA structure used for mailboxes 175ENTRY dsa_code_template 176dsa_code_template: 177ENTRY dsa_code_begin 178dsa_code_begin: 179; RGH: Don't care about TEMP and DSA here 180 DMODE_MEMORY_TO_NCR 181 MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch 182 DMODE_MEMORY_TO_MEMORY 183#if (CHIP == 710) 184 MOVE MEMORY 4, addr_scratch, saved_dsa 185 ; We are about to go and select the device, so must set SSCF bits 186 MOVE MEMORY 4, dsa_sscf_710, addr_scratch 187#ifdef BIG_ENDIAN 188 MOVE SCRATCH3 TO SFBR 189#else 190 MOVE SCRATCH0 TO SFBR 191#endif 192 MOVE SFBR TO SBCL 193 MOVE MEMORY 4, saved_dsa, addr_dsa 194#else 195 CALL scratch_to_dsa 196#endif 197 CALL select 198; Handle the phase mismatch which may have resulted from the 199; MOVE FROM dsa_msgout if we returned here. The CLEAR ATN 200; may or may not be necessary, and we should update script_asm.pl 201; to handle multiple pieces. 202 CLEAR ATN 203 CLEAR ACK 204 205; Replace second operand with address of JUMP instruction dest operand 206; in schedule table for this DSA. Becomes dsa_jump_dest in 53c7,8xx.c. 207ENTRY dsa_code_fix_jump 208dsa_code_fix_jump: 209 MOVE MEMORY 4, NOP_insn, 0 210 JUMP select_done 211 212; wrong_dsa loads the DSA register with the value of the dsa_next 213; field. 214; 215wrong_dsa: 216#if (CHIP == 710) 217; NOTE DSA is corrupt when we arrive here! 218#endif 219; Patch the MOVE MEMORY INSTRUCTION such that 220; the destination address is the address of the OLD 221; next pointer. 222; 223 MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8 224 DMODE_MEMORY_TO_NCR 225; 226; Move the _contents_ of the next pointer into the DSA register as 227; the next I_T_L or I_T_L_Q tupple to check against the established 228; nexus. 229; 230 MOVE MEMORY 4, dsa_temp_next, addr_scratch 231 DMODE_MEMORY_TO_MEMORY 232#if (CHIP == 710) 233 MOVE MEMORY 4, addr_scratch, saved_dsa 234 MOVE MEMORY 4, saved_dsa, addr_dsa 235#else 236 CALL scratch_to_dsa 237#endif 238 JUMP reselected_check_next 239 240ABSOLUTE dsa_save_data_pointer = 0 241ENTRY dsa_code_save_data_pointer 242dsa_code_save_data_pointer: 243#if (CHIP == 710) 244 ; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt 245 ; We MUST return with DSA correct 246 MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer 247; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h 248 MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual 249 CLEAR ACK 250#ifdef DEBUG 251 INT int_debug_saved 252#endif 253 MOVE MEMORY 4, saved_dsa, addr_dsa 254 JUMP jump_temp 255#else 256 DMODE_NCR_TO_MEMORY 257 MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer 258 DMODE_MEMORY_TO_MEMORY 259; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h 260 MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual 261 CLEAR ACK 262#ifdef DEBUG 263 INT int_debug_saved 264#endif 265 RETURN 266#endif 267ABSOLUTE dsa_restore_pointers = 0 268ENTRY dsa_code_restore_pointers 269dsa_code_restore_pointers: 270#if (CHIP == 710) 271 ; TEMP and DSA are corrupt when we get here, but who cares! 272 MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4 273; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h 274 MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual 275 CLEAR ACK 276 ; Restore DSA, note we don't care about TEMP 277 MOVE MEMORY 4, saved_dsa, addr_dsa 278#ifdef DEBUG 279 INT int_debug_restored 280#endif 281 JUMP jump_temp 282#else 283 DMODE_MEMORY_TO_NCR 284 MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp 285 DMODE_MEMORY_TO_MEMORY 286; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h 287 MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual 288 CLEAR ACK 289#ifdef DEBUG 290 INT int_debug_restored 291#endif 292 RETURN 293#endif 294 295ABSOLUTE dsa_check_reselect = 0 296; dsa_check_reselect determines whether or not the current target and 297; lun match the current DSA 298ENTRY dsa_code_check_reselect 299dsa_code_check_reselect: 300#if (CHIP == 710) 301 /* Arrives here with DSA correct */ 302 /* Assumes we are always ID 7 */ 303 MOVE LCRC TO SFBR ; LCRC has our ID and his ID bits set 304 JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80 305#else 306 MOVE SSID TO SFBR ; SSID contains 3 bit target ID 307; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips 308 JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8 309#endif 310; 311; Hack - move to scratch first, since SFBR is not writeable 312; via the CPU and hence a MOVE MEMORY instruction. 313; 314 DMODE_MEMORY_TO_NCR 315 MOVE MEMORY 1, reselected_identify, addr_scratch 316 DMODE_MEMORY_TO_MEMORY 317#ifdef BIG_ENDIAN 318 ; BIG ENDIAN ON MVME16x 319 MOVE SCRATCH3 TO SFBR 320#else 321 MOVE SCRATCH0 TO SFBR 322#endif 323; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips 324; Are you sure about that? richard@sleepie.demon.co.uk 325 JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8 326; Patch the MOVE MEMORY INSTRUCTION such that 327; the source address is the address of this dsa's 328; next pointer. 329 MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4 330 CALL reselected_ok 331#if (CHIP == 710) 332; Restore DSA following memory moves in reselected_ok 333; dsa_temp_sync doesn't really care about DSA, but it has an 334; optional debug INT so a valid DSA is a good idea. 335 MOVE MEMORY 4, saved_dsa, addr_dsa 336#endif 337 CALL dsa_temp_sync 338; Release ACK on the IDENTIFY message _after_ we've set the synchronous 339; transfer parameters! 340 CLEAR ACK 341; Implicitly restore pointers on reselection, so a RETURN 342; will transfer control back to the right spot. 343 CALL REL (dsa_code_restore_pointers) 344 RETURN 345ENTRY dsa_zero 346dsa_zero: 347ENTRY dsa_code_template_end 348dsa_code_template_end: 349 350; Perform sanity check for dsa_fields_start == dsa_code_template_end - 351; dsa_zero, puke. 352 353ABSOLUTE dsa_fields_start = 0 ; Sanity marker 354 ; pad 48 bytes (fix this RSN) 355ABSOLUTE dsa_next = 48 ; len 4 Next DSA 356 ; del 4 Previous DSA address 357ABSOLUTE dsa_cmnd = 56 ; len 4 Scsi_Cmnd * for this thread. 358ABSOLUTE dsa_select = 60 ; len 4 Device ID, Period, Offset for 359 ; table indirect select 360ABSOLUTE dsa_msgout = 64 ; len 8 table indirect move parameter for 361 ; select message 362ABSOLUTE dsa_cmdout = 72 ; len 8 table indirect move parameter for 363 ; command 364ABSOLUTE dsa_dataout = 80 ; len 4 code pointer for dataout 365ABSOLUTE dsa_datain = 84 ; len 4 code pointer for datain 366ABSOLUTE dsa_msgin = 88 ; len 8 table indirect move for msgin 367ABSOLUTE dsa_status = 96 ; len 8 table indirect move for status byte 368ABSOLUTE dsa_msgout_other = 104 ; len 8 table indirect for normal message out 369 ; (Synchronous transfer negotiation, etc). 370ABSOLUTE dsa_end = 112 371 372ABSOLUTE schedule = 0 ; Array of JUMP dsa_begin or JUMP (next), 373 ; terminated by a call to JUMP wait_reselect 374 375; Linked lists of DSA structures 376ABSOLUTE reconnect_dsa_head = 0 ; Link list of DSAs which can reconnect 377ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing 378 ; address of reconnect_dsa_head 379 380; These select the source and destination of a MOVE MEMORY instruction 381ABSOLUTE dmode_memory_to_memory = 0x0 382ABSOLUTE dmode_memory_to_ncr = 0x0 383ABSOLUTE dmode_ncr_to_memory = 0x0 384 385ABSOLUTE addr_scratch = 0x0 386ABSOLUTE addr_temp = 0x0 387#if (CHIP == 710) 388ABSOLUTE saved_dsa = 0x0 389ABSOLUTE emulfly = 0x0 390ABSOLUTE addr_dsa = 0x0 391#endif 392#endif /* CHIP != 700 && CHIP != 70066 */ 393 394; Interrupts - 395; MSB indicates type 396; 0 handle error condition 397; 1 handle message 398; 2 handle normal condition 399; 3 debugging interrupt 400; 4 testing interrupt 401; Next byte indicates specific error 402 403; XXX not yet implemented, I'm not sure if I want to - 404; Next byte indicates the routine the error occurred in 405; The LSB indicates the specific place the error occurred 406 407ABSOLUTE int_err_unexpected_phase = 0x00000000 ; Unexpected phase encountered 408ABSOLUTE int_err_selected = 0x00010000 ; SELECTED (nee RESELECTED) 409ABSOLUTE int_err_unexpected_reselect = 0x00020000 410ABSOLUTE int_err_check_condition = 0x00030000 411ABSOLUTE int_err_no_phase = 0x00040000 412ABSOLUTE int_msg_wdtr = 0x01000000 ; WDTR message received 413ABSOLUTE int_msg_sdtr = 0x01010000 ; SDTR received 414ABSOLUTE int_msg_1 = 0x01020000 ; single byte special message 415 ; received 416 417ABSOLUTE int_norm_select_complete = 0x02000000 ; Select complete, reprogram 418 ; registers. 419ABSOLUTE int_norm_reselect_complete = 0x02010000 ; Nexus established 420ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete 421ABSOLUTE int_norm_disconnected = 0x02030000 ; Disconnected 422ABSOLUTE int_norm_aborted =0x02040000 ; Aborted *dsa 423ABSOLUTE int_norm_reset = 0x02050000 ; Generated BUS reset. 424ABSOLUTE int_norm_emulateintfly = 0x02060000 ; 53C710 Emulated intfly 425ABSOLUTE int_debug_break = 0x03000000 ; Break point 426#ifdef DEBUG 427ABSOLUTE int_debug_scheduled = 0x03010000 ; new I/O scheduled 428ABSOLUTE int_debug_idle = 0x03020000 ; scheduler is idle 429ABSOLUTE int_debug_dsa_loaded = 0x03030000 ; dsa reloaded 430ABSOLUTE int_debug_reselected = 0x03040000 ; NCR reselected 431ABSOLUTE int_debug_head = 0x03050000 ; issue head overwritten 432ABSOLUTE int_debug_disconnected = 0x03060000 ; disconnected 433ABSOLUTE int_debug_disconnect_msg = 0x03070000 ; got message to disconnect 434ABSOLUTE int_debug_dsa_schedule = 0x03080000 ; in dsa_schedule 435ABSOLUTE int_debug_reselect_check = 0x03090000 ; Check for reselection of DSA 436ABSOLUTE int_debug_reselected_ok = 0x030a0000 ; Reselection accepted 437#endif 438ABSOLUTE int_debug_panic = 0x030b0000 ; Panic driver 439#ifdef DEBUG 440ABSOLUTE int_debug_saved = 0x030c0000 ; save/restore pointers 441ABSOLUTE int_debug_restored = 0x030d0000 442ABSOLUTE int_debug_sync = 0x030e0000 ; Sanity check synchronous 443 ; parameters. 444ABSOLUTE int_debug_datain = 0x030f0000 ; going into data in phase 445 ; now. 446ABSOLUTE int_debug_check_dsa = 0x03100000 ; Sanity check DSA against 447 ; SDID. 448#endif 449 450ABSOLUTE int_test_1 = 0x04000000 ; Test 1 complete 451ABSOLUTE int_test_2 = 0x04010000 ; Test 2 complete 452ABSOLUTE int_test_3 = 0x04020000 ; Test 3 complete 453 454 455; These should start with 0x05000000, with low bits incrementing for 456; each one. 457 458#ifdef EVENTS 459ABSOLUTE int_EVENT_SELECT = 0 460ABSOLUTE int_EVENT_DISCONNECT = 0 461ABSOLUTE int_EVENT_RESELECT = 0 462ABSOLUTE int_EVENT_COMPLETE = 0 463ABSOLUTE int_EVENT_IDLE = 0 464ABSOLUTE int_EVENT_SELECT_FAILED = 0 465ABSOLUTE int_EVENT_BEFORE_SELECT = 0 466ABSOLUTE int_EVENT_RESELECT_FAILED = 0 467#endif 468 469ABSOLUTE NCR53c7xx_msg_abort = 0 ; Pointer to abort message 470ABSOLUTE NCR53c7xx_msg_reject = 0 ; Pointer to reject message 471ABSOLUTE NCR53c7xx_zero = 0 ; long with zero in it, use for source 472ABSOLUTE NCR53c7xx_sink = 0 ; long to dump worthless data in 473ABSOLUTE NOP_insn = 0 ; NOP instruction 474 475; Pointer to message, potentially multi-byte 476ABSOLUTE msg_buf = 0 477 478; Pointer to holding area for reselection information 479ABSOLUTE reselected_identify = 0 480ABSOLUTE reselected_tag = 0 481 482; Request sense command pointer, it's a 6 byte command, should 483; be constant for all commands since we always want 16 bytes of 484; sense and we don't need to change any fields as we did under 485; SCSI-I when we actually cared about the LUN field. 486;EXTERNAL NCR53c7xx_sense ; Request sense command 487 488#if (CHIP != 700) && (CHIP != 70066) 489; dsa_schedule 490; PURPOSE : after a DISCONNECT message has been received, and pointers 491; saved, insert the current DSA structure at the head of the 492; disconnected queue and fall through to the scheduler. 493; 494; CALLS : OK 495; 496; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list 497; of disconnected commands 498; 499; MODIFIES : SCRATCH, reconnect_dsa_head 500; 501; EXITS : always passes control to schedule 502 503ENTRY dsa_schedule 504dsa_schedule: 505#ifdef DEBUG 506 INT int_debug_dsa_schedule 507#endif 508 509; 510; Calculate the address of the next pointer within the DSA 511; structure of the command that is currently disconnecting 512; 513#if (CHIP == 710) 514 ; Read what should be the current DSA from memory - actual DSA 515 ; register is probably corrupt 516 MOVE MEMORY 4, saved_dsa, addr_scratch 517#else 518 CALL dsa_to_scratch 519#endif 520 MOVE SCRATCH0 + dsa_next TO SCRATCH0 521 MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 522 MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 523 MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 524 525; Point the next field of this DSA structure at the current disconnected 526; list 527 DMODE_NCR_TO_MEMORY 528 MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8 529 DMODE_MEMORY_TO_MEMORY 530dsa_schedule_insert: 531 MOVE MEMORY 4, reconnect_dsa_head, 0 532 533; And update the head pointer. 534#if (CHIP == 710) 535 ; Read what should be the current DSA from memory - actual DSA 536 ; register is probably corrupt 537 MOVE MEMORY 4, saved_dsa, addr_scratch 538#else 539 CALL dsa_to_scratch 540#endif 541 DMODE_NCR_TO_MEMORY 542 MOVE MEMORY 4, addr_scratch, reconnect_dsa_head 543 DMODE_MEMORY_TO_MEMORY 544/* Temporarily, see what happens. */ 545#ifndef ORIGINAL 546#if (CHIP != 710) 547 MOVE SCNTL2 & 0x7f TO SCNTL2 548#endif 549 CLEAR ACK 550#endif 551#if (CHIP == 710) 552 ; Time to correct DSA following memory move 553 MOVE MEMORY 4, saved_dsa, addr_dsa 554#endif 555 WAIT DISCONNECT 556#ifdef EVENTS 557 INT int_EVENT_DISCONNECT; 558#endif 559#ifdef DEBUG 560 INT int_debug_disconnected 561#endif 562 JUMP schedule 563#endif 564 565; 566; select 567; 568; PURPOSE : establish a nexus for the SCSI command referenced by DSA. 569; On success, the current DSA structure is removed from the issue 570; queue. Usually, this is entered as a fall-through from schedule, 571; although the contingent allegiance handling code will write 572; the select entry address to the DSP to restart a command as a 573; REQUEST SENSE. A message is sent (usually IDENTIFY, although 574; additional SDTR or WDTR messages may be sent). COMMAND OUT 575; is handled. 576; 577; INPUTS : DSA - SCSI command, issue_dsa_head 578; 579; CALLS : NOT OK 580; 581; MODIFIES : SCRATCH, issue_dsa_head 582; 583; EXITS : on reselection or selection, go to select_failed 584; otherwise, RETURN so control is passed back to 585; dsa_begin. 586; 587 588ENTRY select 589select: 590 591#ifdef EVENTS 592 INT int_EVENT_BEFORE_SELECT 593#endif 594 595#ifdef DEBUG 596 INT int_debug_scheduled 597#endif 598 CLEAR TARGET 599 600; XXX 601; 602; In effect, SELECTION operations are backgrounded, with execution 603; continuing until code which waits for REQ or a fatal interrupt is 604; encountered. 605; 606; So, for more performance, we could overlap the code which removes 607; the command from the NCRs issue queue with the selection, but 608; at this point I don't want to deal with the error recovery. 609; 610 611#if (CHIP != 700) && (CHIP != 70066) 612#if (CHIP == 710) 613 ; Enable selection timer 614#ifdef NO_SELECTION_TIMEOUT 615 MOVE CTEST7 & 0xff TO CTEST7 616#else 617 MOVE CTEST7 & 0xef TO CTEST7 618#endif 619#endif 620 SELECT ATN FROM dsa_select, select_failed 621 JUMP select_msgout, WHEN MSG_OUT 622ENTRY select_msgout 623select_msgout: 624#if (CHIP == 710) 625 ; Disable selection timer 626 MOVE CTEST7 | 0x10 TO CTEST7 627#endif 628 MOVE FROM dsa_msgout, WHEN MSG_OUT 629#else 630ENTRY select_msgout 631 SELECT ATN 0, select_failed 632select_msgout: 633 MOVE 0, 0, WHEN MSGOUT 634#endif 635 636#ifdef EVENTS 637 INT int_EVENT_SELECT 638#endif 639 RETURN 640 641; 642; select_done 643; 644; PURPOSE: continue on to normal data transfer; called as the exit 645; point from dsa_begin. 646; 647; INPUTS: dsa 648; 649; CALLS: OK 650; 651; 652 653select_done: 654#if (CHIP == 710) 655; NOTE DSA is corrupt when we arrive here! 656 MOVE MEMORY 4, saved_dsa, addr_dsa 657#endif 658 659#ifdef DEBUG 660ENTRY select_check_dsa 661select_check_dsa: 662 INT int_debug_check_dsa 663#endif 664 665; After a successful selection, we should get either a CMD phase or 666; some transfer request negotiation message. 667 668 JUMP cmdout, WHEN CMD 669 INT int_err_unexpected_phase, WHEN NOT MSG_IN 670 671select_msg_in: 672 CALL msg_in, WHEN MSG_IN 673 JUMP select_msg_in, WHEN MSG_IN 674 675cmdout: 676 INT int_err_unexpected_phase, WHEN NOT CMD 677#if (CHIP == 700) 678 INT int_norm_selected 679#endif 680ENTRY cmdout_cmdout 681cmdout_cmdout: 682#if (CHIP != 700) && (CHIP != 70066) 683 MOVE FROM dsa_cmdout, WHEN CMD 684#else 685 MOVE 0, 0, WHEN CMD 686#endif /* (CHIP != 700) && (CHIP != 70066) */ 687 688; 689; data_transfer 690; other_out 691; other_in 692; other_transfer 693; 694; PURPOSE : handle the main data transfer for a SCSI command in 695; several parts. In the first part, data_transfer, DATA_IN 696; and DATA_OUT phases are allowed, with the user provided 697; code (usually dynamically generated based on the scatter/gather 698; list associated with a SCSI command) called to handle these 699; phases. 700; 701; After control has passed to one of the user provided 702; DATA_IN or DATA_OUT routines, back calls are made to 703; other_transfer_in or other_transfer_out to handle non-DATA IN 704; and DATA OUT phases respectively, with the state of the active 705; data pointer being preserved in TEMP. 706; 707; On completion, the user code passes control to other_transfer 708; which causes DATA_IN and DATA_OUT to result in unexpected_phase 709; interrupts so that data overruns may be trapped. 710; 711; INPUTS : DSA - SCSI command 712; 713; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in 714; other_transfer 715; 716; MODIFIES : SCRATCH 717; 718; EXITS : if STATUS IN is detected, signifying command completion, 719; the NCR jumps to command_complete. If MSG IN occurs, a 720; CALL is made to msg_in. Otherwise, other_transfer runs in 721; an infinite loop. 722; 723 724ENTRY data_transfer 725data_transfer: 726 JUMP cmdout_cmdout, WHEN CMD 727 CALL msg_in, WHEN MSG_IN 728 INT int_err_unexpected_phase, WHEN MSG_OUT 729 JUMP do_dataout, WHEN DATA_OUT 730 JUMP do_datain, WHEN DATA_IN 731 JUMP command_complete, WHEN STATUS 732 JUMP data_transfer 733ENTRY end_data_transfer 734end_data_transfer: 735 736; 737; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain 738; should be fixed up whenever the nexus changes so it can point to the 739; correct routine for that command. 740; 741 742#if (CHIP != 700) && (CHIP != 70066) 743; Nasty jump to dsa->dataout 744do_dataout: 745#if (CHIP == 710) 746 MOVE MEMORY 4, saved_dsa, addr_scratch 747#else 748 CALL dsa_to_scratch 749#endif 750 MOVE SCRATCH0 + dsa_dataout TO SCRATCH0 751 MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 752 MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 753 MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 754 DMODE_NCR_TO_MEMORY 755 MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4 756 DMODE_MEMORY_TO_MEMORY 757dataout_to_jump: 758 MOVE MEMORY 4, 0, dataout_jump + 4 759#if (CHIP == 710) 760 ; Time to correct DSA following memory move 761 MOVE MEMORY 4, saved_dsa, addr_dsa 762#endif 763dataout_jump: 764 JUMP 0 765 766; Nasty jump to dsa->dsain 767do_datain: 768#if (CHIP == 710) 769 MOVE MEMORY 4, saved_dsa, addr_scratch 770#else 771 CALL dsa_to_scratch 772#endif 773 MOVE SCRATCH0 + dsa_datain TO SCRATCH0 774 MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 775 MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 776 MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 777 DMODE_NCR_TO_MEMORY 778 MOVE MEMORY 4, addr_scratch, datain_to_jump + 4 779 DMODE_MEMORY_TO_MEMORY 780ENTRY datain_to_jump 781datain_to_jump: 782 MOVE MEMORY 4, 0, datain_jump + 4 783#if (CHIP == 710) 784 ; Time to correct DSA following memory move 785 MOVE MEMORY 4, saved_dsa, addr_dsa 786#endif 787#ifdef DEBUG 788 INT int_debug_datain 789#endif 790datain_jump: 791 JUMP 0 792#endif /* (CHIP != 700) && (CHIP != 70066) */ 793 794 795; Note that other_out and other_in loop until a non-data phase 796; is discovered, so we only execute return statements when we 797; can go on to the next data phase block move statement. 798 799ENTRY other_out 800other_out: 801#if 0 802 INT 0x03ffdead 803#endif 804 INT int_err_unexpected_phase, WHEN CMD 805 JUMP msg_in_restart, WHEN MSG_IN 806 INT int_err_unexpected_phase, WHEN MSG_OUT 807 INT int_err_unexpected_phase, WHEN DATA_IN 808 JUMP command_complete, WHEN STATUS 809 JUMP other_out, WHEN NOT DATA_OUT 810#if (CHIP == 710) 811; TEMP should be OK, as we got here from a call in the user dataout code. 812#endif 813 RETURN 814 815ENTRY other_in 816other_in: 817#if 0 818 INT 0x03ffdead 819#endif 820 INT int_err_unexpected_phase, WHEN CMD 821 JUMP msg_in_restart, WHEN MSG_IN 822 INT int_err_unexpected_phase, WHEN MSG_OUT 823 INT int_err_unexpected_phase, WHEN DATA_OUT 824 JUMP command_complete, WHEN STATUS 825 JUMP other_in, WHEN NOT DATA_IN 826#if (CHIP == 710) 827; TEMP should be OK, as we got here from a call in the user datain code. 828#endif 829 RETURN 830 831 832ENTRY other_transfer 833other_transfer: 834 INT int_err_unexpected_phase, WHEN CMD 835 CALL msg_in, WHEN MSG_IN 836 INT int_err_unexpected_phase, WHEN MSG_OUT 837 INT int_err_unexpected_phase, WHEN DATA_OUT 838 INT int_err_unexpected_phase, WHEN DATA_IN 839 JUMP command_complete, WHEN STATUS 840 JUMP other_transfer 841 842; 843; msg_in_restart 844; msg_in 845; munge_msg 846; 847; PURPOSE : process messages from a target. msg_in is called when the 848; caller hasn't read the first byte of the message. munge_message 849; is called when the caller has read the first byte of the message, 850; and left it in SFBR. msg_in_restart is called when the caller 851; hasn't read the first byte of the message, and wishes RETURN 852; to transfer control back to the address of the conditional 853; CALL instruction rather than to the instruction after it. 854; 855; Various int_* interrupts are generated when the host system 856; needs to intervene, as is the case with SDTR, WDTR, and 857; INITIATE RECOVERY messages. 858; 859; When the host system handles one of these interrupts, 860; it can respond by reentering at reject_message, 861; which rejects the message and returns control to 862; the caller of msg_in or munge_msg, accept_message 863; which clears ACK and returns control, or reply_message 864; which sends the message pointed to by the DSA 865; msgout_other table indirect field. 866; 867; DISCONNECT messages are handled by moving the command 868; to the reconnect_dsa_queue. 869#if (CHIP == 710) 870; NOTE: DSA should be valid when we get here - we cannot save both it 871; and TEMP in this routine. 872#endif 873; 874; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg 875; only) 876; 877; CALLS : NO. The TEMP register isn't backed up to allow nested calls. 878; 879; MODIFIES : SCRATCH, DSA on DISCONNECT 880; 881; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS, 882; and normal return from message handlers running under 883; Linux, control is returned to the caller. Receipt 884; of DISCONNECT messages pass control to dsa_schedule. 885; 886ENTRY msg_in_restart 887msg_in_restart: 888; XXX - hackish 889; 890; Since it's easier to debug changes to the statically 891; compiled code, rather than the dynamically generated 892; stuff, such as 893; 894; MOVE x, y, WHEN data_phase 895; CALL other_z, WHEN NOT data_phase 896; MOVE x, y, WHEN data_phase 897; 898; I'd like to have certain routines (notably the message handler) 899; restart on the conditional call rather than the next instruction. 900; 901; So, subtract 8 from the return address 902 903 MOVE TEMP0 + 0xf8 TO TEMP0 904 MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY 905 MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY 906 MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY 907 908ENTRY msg_in 909msg_in: 910 MOVE 1, msg_buf, WHEN MSG_IN 911 912munge_msg: 913 JUMP munge_extended, IF 0x01 ; EXTENDED MESSAGE 914 JUMP munge_2, IF 0x20, AND MASK 0xdf ; two byte message 915; 916; XXX - I've seen a handful of broken SCSI devices which fail to issue 917; a SAVE POINTERS message before disconnecting in the middle of 918; a transfer, assuming that the DATA POINTER will be implicitly 919; restored. 920; 921; Historically, I've often done an implicit save when the DISCONNECT 922; message is processed. We may want to consider having the option of 923; doing that here. 924; 925 JUMP munge_save_data_pointer, IF 0x02 ; SAVE DATA POINTER 926 JUMP munge_restore_pointers, IF 0x03 ; RESTORE POINTERS 927 JUMP munge_disconnect, IF 0x04 ; DISCONNECT 928 INT int_msg_1, IF 0x07 ; MESSAGE REJECT 929 INT int_msg_1, IF 0x0f ; INITIATE RECOVERY 930#ifdef EVENTS 931 INT int_EVENT_SELECT_FAILED 932#endif 933 JUMP reject_message 934 935munge_2: 936 JUMP reject_message 937; 938; The SCSI standard allows targets to recover from transient 939; error conditions by backing up the data pointer with a 940; RESTORE POINTERS message. 941; 942; So, we must save and restore the _residual_ code as well as 943; the current instruction pointer. Because of this messiness, 944; it is simpler to put dynamic code in the dsa for this and to 945; just do a simple jump down there. 946; 947 948munge_save_data_pointer: 949#if (CHIP == 710) 950 ; We have something in TEMP here, so first we must save that 951 MOVE TEMP0 TO SFBR 952 MOVE SFBR TO SCRATCH0 953 MOVE TEMP1 TO SFBR 954 MOVE SFBR TO SCRATCH1 955 MOVE TEMP2 TO SFBR 956 MOVE SFBR TO SCRATCH2 957 MOVE TEMP3 TO SFBR 958 MOVE SFBR TO SCRATCH3 959 MOVE MEMORY 4, addr_scratch, jump_temp + 4 960 ; Now restore DSA 961 MOVE MEMORY 4, saved_dsa, addr_dsa 962#endif 963 MOVE DSA0 + dsa_save_data_pointer TO SFBR 964 MOVE SFBR TO SCRATCH0 965 MOVE DSA1 + 0xff TO SFBR WITH CARRY 966 MOVE SFBR TO SCRATCH1 967 MOVE DSA2 + 0xff TO SFBR WITH CARRY 968 MOVE SFBR TO SCRATCH2 969 MOVE DSA3 + 0xff TO SFBR WITH CARRY 970 MOVE SFBR TO SCRATCH3 971 972 DMODE_NCR_TO_MEMORY 973 MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4 974 DMODE_MEMORY_TO_MEMORY 975jump_dsa_save: 976 JUMP 0 977 978munge_restore_pointers: 979#if (CHIP == 710) 980 ; The code at dsa_restore_pointers will RETURN, but we don't care 981 ; about TEMP here, as it will overwrite it anyway. 982#endif 983 MOVE DSA0 + dsa_restore_pointers TO SFBR 984 MOVE SFBR TO SCRATCH0 985 MOVE DSA1 + 0xff TO SFBR WITH CARRY 986 MOVE SFBR TO SCRATCH1 987 MOVE DSA2 + 0xff TO SFBR WITH CARRY 988 MOVE SFBR TO SCRATCH2 989 MOVE DSA3 + 0xff TO SFBR WITH CARRY 990 MOVE SFBR TO SCRATCH3 991 992 DMODE_NCR_TO_MEMORY 993 MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4 994 DMODE_MEMORY_TO_MEMORY 995jump_dsa_restore: 996 JUMP 0 997 998 999munge_disconnect: 1000#ifdef DEBUG 1001 INT int_debug_disconnect_msg 1002#endif 1003 1004/* 1005 * Before, we overlapped processing with waiting for disconnect, but 1006 * debugging was beginning to appear messy. Temporarily move things 1007 * to just before the WAIT DISCONNECT. 1008 */ 1009 1010#ifdef ORIGINAL 1011#if (CHIP == 710) 1012; Following clears Unexpected Disconnect bit. What do we do? 1013#else 1014 MOVE SCNTL2 & 0x7f TO SCNTL2 1015#endif 1016 CLEAR ACK 1017#endif 1018 1019#if (CHIP != 700) && (CHIP != 70066) 1020 JUMP dsa_schedule 1021#else 1022 WAIT DISCONNECT 1023 INT int_norm_disconnected 1024#endif 1025 1026munge_extended: 1027 CLEAR ACK 1028 INT int_err_unexpected_phase, WHEN NOT MSG_IN 1029 MOVE 1, msg_buf + 1, WHEN MSG_IN 1030 JUMP munge_extended_2, IF 0x02 1031 JUMP munge_extended_3, IF 0x03 1032 JUMP reject_message 1033 1034munge_extended_2: 1035 CLEAR ACK 1036 MOVE 1, msg_buf + 2, WHEN MSG_IN 1037 JUMP reject_message, IF NOT 0x02 ; Must be WDTR 1038 CLEAR ACK 1039 MOVE 1, msg_buf + 3, WHEN MSG_IN 1040 INT int_msg_wdtr 1041 1042munge_extended_3: 1043 CLEAR ACK 1044 MOVE 1, msg_buf + 2, WHEN MSG_IN 1045 JUMP reject_message, IF NOT 0x01 ; Must be SDTR 1046 CLEAR ACK 1047 MOVE 2, msg_buf + 3, WHEN MSG_IN 1048 INT int_msg_sdtr 1049 1050ENTRY reject_message 1051reject_message: 1052 SET ATN 1053 CLEAR ACK 1054 MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT 1055 RETURN 1056 1057ENTRY accept_message 1058accept_message: 1059 CLEAR ATN 1060 CLEAR ACK 1061 RETURN 1062 1063ENTRY respond_message 1064respond_message: 1065 SET ATN 1066 CLEAR ACK 1067 MOVE FROM dsa_msgout_other, WHEN MSG_OUT 1068 RETURN 1069 1070; 1071; command_complete 1072; 1073; PURPOSE : handle command termination when STATUS IN is detected by reading 1074; a status byte followed by a command termination message. 1075; 1076; Normal termination results in an INTFLY instruction, and 1077; the host system can pick out which command terminated by 1078; examining the MESSAGE and STATUS buffers of all currently 1079; executing commands; 1080; 1081; Abnormal (CHECK_CONDITION) termination results in an 1082; int_err_check_condition interrupt so that a REQUEST SENSE 1083; command can be issued out-of-order so that no other command 1084; clears the contingent allegiance condition. 1085; 1086; 1087; INPUTS : DSA - command 1088; 1089; CALLS : OK 1090; 1091; EXITS : On successful termination, control is passed to schedule. 1092; On abnormal termination, the user will usually modify the 1093; DSA fields and corresponding buffers and return control 1094; to select. 1095; 1096 1097ENTRY command_complete 1098command_complete: 1099 MOVE FROM dsa_status, WHEN STATUS 1100#if (CHIP != 700) && (CHIP != 70066) 1101 MOVE SFBR TO SCRATCH0 ; Save status 1102#endif /* (CHIP != 700) && (CHIP != 70066) */ 1103ENTRY command_complete_msgin 1104command_complete_msgin: 1105 MOVE FROM dsa_msgin, WHEN MSG_IN 1106; Indicate that we should be expecting a disconnect 1107#if (CHIP != 710) 1108 MOVE SCNTL2 & 0x7f TO SCNTL2 1109#else 1110 ; Above code cleared the Unexpected Disconnect bit, what do we do? 1111#endif 1112 CLEAR ACK 1113#if (CHIP != 700) && (CHIP != 70066) 1114 WAIT DISCONNECT 1115 1116; 1117; The SCSI specification states that when a UNIT ATTENTION condition 1118; is pending, as indicated by a CHECK CONDITION status message, 1119; the target shall revert to asynchronous transfers. Since 1120; synchronous transfers parameters are maintained on a per INITIATOR/TARGET 1121; basis, and returning control to our scheduler could work on a command 1122; running on another lun on that target using the old parameters, we must 1123; interrupt the host processor to get them changed, or change them ourselves. 1124; 1125; Once SCSI-II tagged queueing is implemented, things will be even more 1126; hairy, since contingent allegiance conditions exist on a per-target/lun 1127; basis, and issuing a new command with a different tag would clear it. 1128; In these cases, we must interrupt the host processor to get a request 1129; added to the HEAD of the queue with the request sense command, or we 1130; must automatically issue the request sense command. 1131 1132#if 0 1133 MOVE SCRATCH0 TO SFBR 1134 JUMP command_failed, IF 0x02 1135#endif 1136#if (CHIP == 710) 1137#if defined(MVME16x_INTFLY) 1138; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software 1139; interrupt (SW7). We can use SCRATCH, as we are about to jump to 1140; schedule, which corrupts it anyway. Will probably remove this later, 1141; but want to check performance effects first. 1142 1143#define INTFLY_ADDR 0xfff40070 1144 1145 MOVE 0 TO SCRATCH0 1146 MOVE 0x80 TO SCRATCH1 1147 MOVE 0 TO SCRATCH2 1148 MOVE 0 TO SCRATCH3 1149 MOVE MEMORY 4, addr_scratch, INTFLY_ADDR 1150#else 1151 INT int_norm_emulateintfly 1152#endif 1153#else 1154 INTFLY 1155#endif 1156#endif /* (CHIP != 700) && (CHIP != 70066) */ 1157#if (CHIP == 710) 1158 ; Time to correct DSA following memory move 1159 MOVE MEMORY 4, saved_dsa, addr_dsa 1160#endif 1161#ifdef EVENTS 1162 INT int_EVENT_COMPLETE 1163#endif 1164#if (CHIP != 700) && (CHIP != 70066) 1165 JUMP schedule 1166command_failed: 1167 INT int_err_check_condition 1168#else 1169 INT int_norm_command_complete 1170#endif 1171 1172; 1173; wait_reselect 1174; 1175; PURPOSE : This is essentially the idle routine, where control lands 1176; when there are no new processes to schedule. wait_reselect 1177; waits for reselection, selection, and new commands. 1178; 1179; When a successful reselection occurs, with the aid 1180; of fixed up code in each DSA, wait_reselect walks the 1181; reconnect_dsa_queue, asking each dsa if the target ID 1182; and LUN match its. 1183; 1184; If a match is found, a call is made back to reselected_ok, 1185; which through the miracles of self modifying code, extracts 1186; the found DSA from the reconnect_dsa_queue and then 1187; returns control to the DSAs thread of execution. 1188; 1189; INPUTS : NONE 1190; 1191; CALLS : OK 1192; 1193; MODIFIES : DSA, 1194; 1195; EXITS : On successful reselection, control is returned to the 1196; DSA which called reselected_ok. If the WAIT RESELECT 1197; was interrupted by a new commands arrival signaled by 1198; SIG_P, control is passed to schedule. If the NCR is 1199; selected, the host system is interrupted with an 1200; int_err_selected which is usually responded to by 1201; setting DSP to the target_abort address. 1202 1203ENTRY wait_reselect 1204wait_reselect: 1205#ifdef EVENTS 1206 int int_EVENT_IDLE 1207#endif 1208#ifdef DEBUG 1209 int int_debug_idle 1210#endif 1211 WAIT RESELECT wait_reselect_failed 1212 1213reselected: 1214#ifdef EVENTS 1215 int int_EVENT_RESELECT 1216#endif 1217 CLEAR TARGET 1218 DMODE_MEMORY_TO_MEMORY 1219 ; Read all data needed to reestablish the nexus - 1220 MOVE 1, reselected_identify, WHEN MSG_IN 1221 ; We used to CLEAR ACK here. 1222#if (CHIP != 700) && (CHIP != 70066) 1223#ifdef DEBUG 1224 int int_debug_reselected 1225#endif 1226 1227 ; Point DSA at the current head of the disconnected queue. 1228 DMODE_MEMORY_TO_NCR 1229 MOVE MEMORY 4, reconnect_dsa_head, addr_scratch 1230 DMODE_MEMORY_TO_MEMORY 1231#if (CHIP == 710) 1232 MOVE MEMORY 4, addr_scratch, saved_dsa 1233#else 1234 CALL scratch_to_dsa 1235#endif 1236 1237 ; Fix the update-next pointer so that the reconnect_dsa_head 1238 ; pointer is the one that will be updated if this DSA is a hit 1239 ; and we remove it from the queue. 1240 1241 MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8 1242#if (CHIP == 710) 1243 ; Time to correct DSA following memory move 1244 MOVE MEMORY 4, saved_dsa, addr_dsa 1245#endif 1246 1247ENTRY reselected_check_next 1248reselected_check_next: 1249#ifdef DEBUG 1250 INT int_debug_reselect_check 1251#endif 1252 ; Check for a NULL pointer. 1253 MOVE DSA0 TO SFBR 1254 JUMP reselected_not_end, IF NOT 0 1255 MOVE DSA1 TO SFBR 1256 JUMP reselected_not_end, IF NOT 0 1257 MOVE DSA2 TO SFBR 1258 JUMP reselected_not_end, IF NOT 0 1259 MOVE DSA3 TO SFBR 1260 JUMP reselected_not_end, IF NOT 0 1261 INT int_err_unexpected_reselect 1262 1263reselected_not_end: 1264 ; 1265 ; XXX the ALU is only eight bits wide, and the assembler 1266 ; wont do the dirt work for us. As long as dsa_check_reselect 1267 ; is negative, we need to sign extend with 1 bits to the full 1268 ; 32 bit width of the address. 1269 ; 1270 ; A potential work around would be to have a known alignment 1271 ; of the DSA structure such that the base address plus 1272 ; dsa_check_reselect doesn't require carrying from bytes 1273 ; higher than the LSB. 1274 ; 1275 1276 MOVE DSA0 TO SFBR 1277 MOVE SFBR + dsa_check_reselect TO SCRATCH0 1278 MOVE DSA1 TO SFBR 1279 MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY 1280 MOVE DSA2 TO SFBR 1281 MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY 1282 MOVE DSA3 TO SFBR 1283 MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY 1284 1285 DMODE_NCR_TO_MEMORY 1286 MOVE MEMORY 4, addr_scratch, reselected_check + 4 1287 DMODE_MEMORY_TO_MEMORY 1288#if (CHIP == 710) 1289 ; Time to correct DSA following memory move 1290 MOVE MEMORY 4, saved_dsa, addr_dsa 1291#endif 1292reselected_check: 1293 JUMP 0 1294 1295 1296; 1297; 1298#if (CHIP == 710) 1299; We have problems here - the memory move corrupts TEMP and DSA. This 1300; routine is called from DSA code, and patched from many places. Scratch 1301; is probably free when it is called. 1302; We have to: 1303; copy temp to scratch, one byte at a time 1304; write scratch to patch a jump in place of the return 1305; do the move memory 1306; jump to the patched in return address 1307; DSA is corrupt when we get here, and can be left corrupt 1308 1309ENTRY reselected_ok 1310reselected_ok: 1311 MOVE TEMP0 TO SFBR 1312 MOVE SFBR TO SCRATCH0 1313 MOVE TEMP1 TO SFBR 1314 MOVE SFBR TO SCRATCH1 1315 MOVE TEMP2 TO SFBR 1316 MOVE SFBR TO SCRATCH2 1317 MOVE TEMP3 TO SFBR 1318 MOVE SFBR TO SCRATCH3 1319 MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4 1320reselected_ok_patch: 1321 MOVE MEMORY 4, 0, 0 1322reselected_ok_jump: 1323 JUMP 0 1324#else 1325ENTRY reselected_ok 1326reselected_ok: 1327reselected_ok_patch: 1328 MOVE MEMORY 4, 0, 0 ; Patched : first word 1329 ; is address of 1330 ; successful dsa_next 1331 ; Second word is last 1332 ; unsuccessful dsa_next, 1333 ; starting with 1334 ; dsa_reconnect_head 1335 ; We used to CLEAR ACK here. 1336#ifdef DEBUG 1337 INT int_debug_reselected_ok 1338#endif 1339#ifdef DEBUG 1340 INT int_debug_check_dsa 1341#endif 1342 RETURN ; Return control to where 1343#endif 1344#else 1345 INT int_norm_reselected 1346#endif /* (CHIP != 700) && (CHIP != 70066) */ 1347 1348selected: 1349 INT int_err_selected; 1350 1351; 1352; A select or reselect failure can be caused by one of two conditions : 1353; 1. SIG_P was set. This will be the case if the user has written 1354; a new value to a previously NULL head of the issue queue. 1355; 1356; 2. The NCR53c810 was selected or reselected by another device. 1357; 1358; 3. The bus was already busy since we were selected or reselected 1359; before starting the command. 1360 1361wait_reselect_failed: 1362#ifdef EVENTS 1363 INT int_EVENT_RESELECT_FAILED 1364#endif 1365; Check selected bit. 1366#if (CHIP == 710) 1367 ; Must work out how to tell if we are selected.... 1368#else 1369 MOVE SIST0 & 0x20 TO SFBR 1370 JUMP selected, IF 0x20 1371#endif 1372; Reading CTEST2 clears the SIG_P bit in the ISTAT register. 1373 MOVE CTEST2 & 0x40 TO SFBR 1374 JUMP schedule, IF 0x40 1375; Check connected bit. 1376; FIXME: this needs to change if we support target mode 1377 MOVE ISTAT & 0x08 TO SFBR 1378 JUMP reselected, IF 0x08 1379; FIXME : Something bogus happened, and we shouldn't fail silently. 1380#if 0 1381 JUMP schedule 1382#else 1383 INT int_debug_panic 1384#endif 1385 1386 1387select_failed: 1388#if (CHIP == 710) 1389 ; Disable selection timer 1390 MOVE CTEST7 | 0x10 TO CTEST7 1391#endif 1392#ifdef EVENTS 1393 int int_EVENT_SELECT_FAILED 1394#endif 1395; Otherwise, mask the selected and reselected bits off SIST0 1396#if (CHIP ==710) 1397 ; Let's assume we don't get selected for now 1398 MOVE SSTAT0 & 0x10 TO SFBR 1399#else 1400 MOVE SIST0 & 0x30 TO SFBR 1401 JUMP selected, IF 0x20 1402#endif 1403 JUMP reselected, IF 0x10 1404; If SIGP is set, the user just gave us another command, and 1405; we should restart or return to the scheduler. 1406; Reading CTEST2 clears the SIG_P bit in the ISTAT register. 1407 MOVE CTEST2 & 0x40 TO SFBR 1408 JUMP select, IF 0x40 1409; Check connected bit. 1410; FIXME: this needs to change if we support target mode 1411; FIXME: is this really necessary? 1412 MOVE ISTAT & 0x08 TO SFBR 1413 JUMP reselected, IF 0x08 1414; FIXME : Something bogus happened, and we shouldn't fail silently. 1415#if 0 1416 JUMP schedule 1417#else 1418 INT int_debug_panic 1419#endif 1420 1421; 1422; test_1 1423; test_2 1424; 1425; PURPOSE : run some verification tests on the NCR. test_1 1426; copies test_src to test_dest and interrupts the host 1427; processor, testing for cache coherency and interrupt 1428; problems in the processes. 1429; 1430; test_2 runs a command with offsets relative to the 1431; DSA on entry, and is useful for miscellaneous experimentation. 1432; 1433 1434; Verify that interrupts are working correctly and that we don't 1435; have a cache invalidation problem. 1436 1437ABSOLUTE test_src = 0, test_dest = 0 1438ENTRY test_1 1439test_1: 1440 MOVE MEMORY 4, test_src, test_dest 1441 INT int_test_1 1442 1443; 1444; Run arbitrary commands, with test code establishing a DSA 1445; 1446 1447ENTRY test_2 1448test_2: 1449 CLEAR TARGET 1450#if (CHIP == 710) 1451 ; Enable selection timer 1452#ifdef NO_SELECTION_TIMEOUT 1453 MOVE CTEST7 & 0xff TO CTEST7 1454#else 1455 MOVE CTEST7 & 0xef TO CTEST7 1456#endif 1457#endif 1458 SELECT ATN FROM 0, test_2_fail 1459 JUMP test_2_msgout, WHEN MSG_OUT 1460ENTRY test_2_msgout 1461test_2_msgout: 1462#if (CHIP == 710) 1463 ; Disable selection timer 1464 MOVE CTEST7 | 0x10 TO CTEST7 1465#endif 1466 MOVE FROM 8, WHEN MSG_OUT 1467 MOVE FROM 16, WHEN CMD 1468 MOVE FROM 24, WHEN DATA_IN 1469 MOVE FROM 32, WHEN STATUS 1470 MOVE FROM 40, WHEN MSG_IN 1471#if (CHIP != 710) 1472 MOVE SCNTL2 & 0x7f TO SCNTL2 1473#endif 1474 CLEAR ACK 1475 WAIT DISCONNECT 1476test_2_fail: 1477#if (CHIP == 710) 1478 ; Disable selection timer 1479 MOVE CTEST7 | 0x10 TO CTEST7 1480#endif 1481 INT int_test_2 1482 1483ENTRY debug_break 1484debug_break: 1485 INT int_debug_break 1486 1487; 1488; initiator_abort 1489; target_abort 1490; 1491; PURPOSE : Abort the currently established nexus from with initiator 1492; or target mode. 1493; 1494; 1495 1496ENTRY target_abort 1497target_abort: 1498 SET TARGET 1499 DISCONNECT 1500 CLEAR TARGET 1501 JUMP schedule 1502 1503ENTRY initiator_abort 1504initiator_abort: 1505 SET ATN 1506; 1507; The SCSI-I specification says that targets may go into MSG out at 1508; their leisure upon receipt of the ATN single. On all versions of the 1509; specification, we can't change phases until REQ transitions true->false, 1510; so we need to sink/source one byte of data to allow the transition. 1511; 1512; For the sake of safety, we'll only source one byte of data in all 1513; cases, but to accommodate the SCSI-I dain bramage, we'll sink an 1514; arbitrary number of bytes. 1515 JUMP spew_cmd, WHEN CMD 1516 JUMP eat_msgin, WHEN MSG_IN 1517 JUMP eat_datain, WHEN DATA_IN 1518 JUMP eat_status, WHEN STATUS 1519 JUMP spew_dataout, WHEN DATA_OUT 1520 JUMP sated 1521spew_cmd: 1522 MOVE 1, NCR53c7xx_zero, WHEN CMD 1523 JUMP sated 1524eat_msgin: 1525 MOVE 1, NCR53c7xx_sink, WHEN MSG_IN 1526 JUMP eat_msgin, WHEN MSG_IN 1527 JUMP sated 1528eat_status: 1529 MOVE 1, NCR53c7xx_sink, WHEN STATUS 1530 JUMP eat_status, WHEN STATUS 1531 JUMP sated 1532eat_datain: 1533 MOVE 1, NCR53c7xx_sink, WHEN DATA_IN 1534 JUMP eat_datain, WHEN DATA_IN 1535 JUMP sated 1536spew_dataout: 1537 MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT 1538sated: 1539#if (CHIP != 710) 1540 MOVE SCNTL2 & 0x7f TO SCNTL2 1541#endif 1542 MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT 1543 WAIT DISCONNECT 1544 INT int_norm_aborted 1545 1546#if (CHIP != 710) 1547; 1548; dsa_to_scratch 1549; scratch_to_dsa 1550; 1551; PURPOSE : 1552; The NCR chips cannot do a move memory instruction with the DSA register 1553; as the source or destination. So, we provide a couple of subroutines 1554; that let us switch between the DSA register and scratch register. 1555; 1556; Memory moves to/from the DSPS register also don't work, but we 1557; don't use them. 1558; 1559; 1560 1561 1562dsa_to_scratch: 1563 MOVE DSA0 TO SFBR 1564 MOVE SFBR TO SCRATCH0 1565 MOVE DSA1 TO SFBR 1566 MOVE SFBR TO SCRATCH1 1567 MOVE DSA2 TO SFBR 1568 MOVE SFBR TO SCRATCH2 1569 MOVE DSA3 TO SFBR 1570 MOVE SFBR TO SCRATCH3 1571 RETURN 1572 1573scratch_to_dsa: 1574 MOVE SCRATCH0 TO SFBR 1575 MOVE SFBR TO DSA0 1576 MOVE SCRATCH1 TO SFBR 1577 MOVE SFBR TO DSA1 1578 MOVE SCRATCH2 TO SFBR 1579 MOVE SFBR TO DSA2 1580 MOVE SCRATCH3 TO SFBR 1581 MOVE SFBR TO DSA3 1582 RETURN 1583#endif 1584 1585#if (CHIP == 710) 1586; Little patched jump, used to overcome problems with TEMP getting 1587; corrupted on memory moves. 1588 1589jump_temp: 1590 JUMP 0 1591#endif 1592