/* pciexp.c Revision 3.0 10/27/93 */ /** * Purpose: 53c8xx Test Software */ /* This software was written by NCR Microelectronics to develop and test new * products. NCR assumes no liability for its use. This software is released * to the public domain to illustrate certain programming techniques for the * 53c700 and 53C800 family. */ #include #include #include #include #include #include #include #include "general.out" /* contains the code for the SCSI SCRIPTS */ #include "types.h" #include "commands.h" #include "siop.h" #include "table.h" #include "tools.h" #include "os.h" #include "pci.h" #include "main.h" /* volatile ubyte far *siop_reg; pointer to SIOP's registers */ uquad *script; /* pointer to SCSI SCRIPTs */ table *buffer_table; /* the table used to table-indirect * references */ char ext_msg[1]; char sync_in[3]; uquad *DSA_storage; /* temporary storage to the DSA register so * that when it is distroyed by a memory to * memory move it can be restored. */ /* Some of this is old 720 code that could probably be changed later. */ /* Since all PCI devices I have seen are always I/O mapped, we will */ /* make this code I/O mapped by defining it here. If it is changed to */ /* memory mapped, make sure you change the Scripts memory moves */ /* that access chip registers appropriately by setting the SIOM and */ /* DIOM bits in the chip. */ unsigned int C7XX_SEG=0xD800; /* SEGMENT of SDMS board */ unsigned int MEM_MAP=TRUE; /* Boolean Switch for I/O vs MEM */ unsigned int seg=0xd800, off=0x7e00; /* Prototypes */ static void init_table(void); static void init_siop(void); static void init_script(void); void HostDependentInit(); void Display_config(); void write_config(); unsigned long GetConfigRegister(); void SetConfigRegister(); unsigned char read_reg(); void write_reg(); main() { printf("NCR PCI-SCSI Sample and Diagnostic Program\n"); HostDependentInit(); os_start(); printf("end program\n"); return 1; } /*************************************************************** Initialize everything ***************************************************************/ void init_system() { uword junk; init_siop(); init_table(); init_script(); /* Run script to init the SIOP. Currently this script does not do * anything, but it could be used to run a test script or to have the * SIOP initilize itself. */ start_script(0, &junk); get_drive_info(); } /******************************************************************* Initialize the SIOP registers. *******************************************************************/ static void init_siop() { /* In order to reset the SIOP we need to abort any currently running scripts before we can reset the chip. */ write_reg(ISTAT, (read_reg(ISTAT) | 0x40)); /* reset SIOP */ write_reg(ISTAT, (read_reg(ISTAT) ^ 0x40)); write_reg(SCID, (read_reg(SCID) | 7)); /* set arbitration ID = 7 */ if (read_reg(RESPID0) == 0) write_reg(RESPID0, 0x80); /* set reselect ID = 7 */ write_reg(SCNTL3, (read_reg(SCNTL3) | 0x33)); /* set clock divide by 2 */ #define RESET #ifdef RESET write_reg(SCNTL1, (read_reg(SCNTL1) | 0x08)); /* Assert SCSI RST/ signal for more than 25 us */ delay(1); write_reg(SCNTL1, (read_reg(SCNTL1) ^ 0x08)); delay(300); /* Allow at least 250 ms reset recovery time. */ #endif write_reg(CTEST0, (read_reg(CTEST0) | 0x80)); /* Cache Burst Disable */ write_reg(DMODE, (read_reg(DMODE) | 0x80)); /* 8 Transfer Burst */ write_reg(SCNTL0, (read_reg(SCNTL0) | 0x0c)); /* Enable Parity checking and generation */ write_reg(SCID, (read_reg(SCID) | 0x60)); /* Enable reselection */ write_reg(STEST2, (read_reg(STEST2) | 0x02)); /* Set Req/Ack filtering */ write_reg(STIME0, 0x0f); /* set timeouts */ } /******************************************************************* Initialize the DSA table used for table indirect operations. *******************************************************************/ static void init_table() { /* Allocate space for the table of addresses used by the table indirect * * commands. This table must be on a 32-bit boundry. */ buffer_table = (table *) my_malloc((10+TABLE_SIZE) * sizeof(table)); if (FP_OFF(buffer_table) & 0x03) { printf("buffer_table not word aligned. Fix program.\n"); printf("buffer_table address = %p\n", buffer_table); exit(1); } printf("buffer_table address = %p\n", buffer_table); write_long_reg(DSA, getPhysAddr(buffer_table)); buffer_table[EXT_BUF].count = 1; buffer_table[EXT_BUF].address = getPhysAddr(ext_msg); buffer_table[SYNC_IN].count = 3; buffer_table[SYNC_IN].address = getPhysAddr(sync_in); } /*************************************************************** Initialize the memory for Scripts storage. ***************************************************************/ static void init_script() { int i; /* Make sure script starts on a 32-bit boundry */ if (FP_OFF(SCRIPT) & 0x03) { script = (uquad *) my_malloc(sizeof(SCRIPT)); if (FP_OFF(script) & 0x03) { printf("script not word aligned. Fix program.\n"); exit(1); } memcpy(script, SCRIPT, sizeof(SCRIPT)); } else { script = SCRIPT; } printf("SCRIPT address = %p\nsize = %d\n", script, sizeof(SCRIPT)); for (i = 0; i < sizeof(E_out_offset_Used) / 4; i++) { script[E_out_offset_Used[i]] = getPhysAddr(script) + Ent_dataout + 4; } for (i = 0; i < sizeof(E_in_offset_Used) / 4; i++) { script[E_in_offset_Used[i]] = getPhysAddr(script) + Ent_datain + 4; } /* Below patches the I/O mapped address of the SCRATCHA register */ /* into the Scripts. */ script[(Ent_datain + 32)/4] = (ULONG)(C7XX_SEG + SCRATCHA); script[(Ent_datain + 72)/4] = (ULONG)(C7XX_SEG + SCRATCHA); script[(Ent_dataout + 32)/4] = (ULONG)(C7XX_SEG + SCRATCHA); script[(Ent_dataout + 72)/4] = (ULONG)(C7XX_SEG + SCRATCHA); } /*********************************************************** This function starts a Script, and contains the interrupt service routine that services any interrupts the Script might generate. The mode variable that is passed to the routine determines where in the Script execution will begin. ***********************************************************/ int start_script(int mode, uword *offperiod) { ubyte addr[4]; int i; ubyte dstat, sist0, sist1, istat; static uquad start_offset[] = { Ent_init_siop, Ent_start_up, Ent_switch }; /* Clear any pending interrupts */ istat = read_reg(ISTAT); if (istat & 1) { dstat = read_reg(DSTAT); } if (istat & 2) { sist0 = read_reg(SIST0); sist1 = read_reg(SIST1); } *ext_msg = 0x00; /* restore table indirect pointers */ script[Ent_dataout / 4 + 1] = DATA_ADR * 8; script[Ent_datain / 4 + 1] = DATA_ADR * 8; write_long_reg(DSP, getPhysAddr(script) + start_offset[mode]); do { istat = read_reg(ISTAT); } while (!(istat & 0x03) && !kbhit()); if (*ext_msg == 3) { /* sync neg occured */ uword period; period = max(sync_in[1], PERIOD); period = period / 10 - 3 - (period % 10 == 0); *offperiod = (period << 12) | (min(sync_in[2], OFFSET) << 8); printf("The period is now %d ns.\n", period * 40 + 160); printf("The offset is now %d.\n", (*offperiod >> 8) & 0x0f); } /* Determine what caused the interrupt and return a unique error number. A * message is also printed for debugging purposes. */ istat = read_reg(ISTAT); if (istat & 1) { dstat = read_reg(DSTAT); if (dstat & 1) { printf("An illegal instruction was detected at script address "); for (i = 0; i < 4; i++) { addr[i] = read_reg(DSP + i); } printf("%x\n", (*((uquad *) addr) - getPhysAddr(script))); return (1); } if (dstat & 2) { printf("A watchdog timeout was detected.\n"); return (2); } if (dstat & 4) { printf("Script interrupt #%02x%02x%02x%02x was received.\n", read_reg(DSPS + 3), read_reg(DSPS + 2), read_reg(DSPS + 1), read_reg(DSPS + 0)); if (read_reg(DSPS) == 9) { printf("disconnect\n"); return (start_script(2, offperiod)); } return ( (read_reg(DSPS + 1) << 8) | read_reg(DSPS) ); } if (dstat & 0x20) { printf("a bus fault occured\n"); return (10); } } if (istat & 2) { sist0 = read_reg(SIST0); if (sist0 & 1) { printf("A parity error has occured.\n"); /* add code to handle this case later */ return (3); } if (sist0 & 2) { printf("A scsi reset was received.\n"); return (4); } if (sist0 & 4) { printf("an unexpected disconnect occured.\n"); return (5); } if (sist0 & 0x80) { static char *phase[] = { "DATA OUT", "DATA IN", "COMMAND", "STATUS", "RES0", "RES1", "MESSAGE OUT", "MESSAGE IN" }; printf("Phase mismatch at script address "); for (i = 0; i < 4; i++) { addr[i] = read_reg(DSP + i); } printf("%x\n", (*((uquad *) addr) - getPhysAddr(script))); printf("Expecting %s phase.\n", phase[read_reg(SBCL) & 0x07]); return (8); } } if (istat & 2) { sist1 = read_reg(SIST0); if (sist1 & 1) { printf("Handshake timer Expired\n"); return(7); } if (sist1 & 2) { printf("General Purpose Timer Expired\n"); return(7); } if (sist1 & 4) { printf("Selection Time-out\n"); return(7); } } return (9); }