|
|
1.1 ! root 1: /* Emulation of NCR53C90(A) ! 2: Includes informations from QEMU-NeXT ! 3: */ ! 4: ! 5: #include "ioMem.h" ! 6: #include "ioMemTables.h" ! 7: #include "m68000.h" ! 8: #include "configuration.h" ! 9: #include "esp.h" ! 10: #include "sysReg.h" ! 11: #include "dma.h" ! 12: #include "scsi.h" ! 13: ! 14: #define LOG_ESPDMA_LEVEL LOG_DEBUG /* Print debugging messages for ESP DMA registers */ ! 15: #define LOG_ESPCMD_LEVEL LOG_DEBUG /* Print debugging messages for ESP commands */ ! 16: #define LOG_ESPREG_LEVEL LOG_DEBUG /* Print debugging messages for ESP registers */ ! 17: #define LOG_ESPFIFO_LEVEL LOG_DEBUG /* Print debugging messages for ESP FIFO */ ! 18: ! 19: ! 20: #define IO_SEG_MASK 0x1FFFF ! 21: ! 22: typedef enum { ! 23: DISCONNECTED, ! 24: INITIATOR, ! 25: TARGET ! 26: } SCSI_STATE; ! 27: ! 28: SCSI_STATE esp_state; ! 29: ! 30: ! 31: /* ESP FIFO */ ! 32: #define ESP_FIFO_SIZE 16 ! 33: Uint8 esp_fifo_read(void); ! 34: void esp_fifo_write(Uint8 val); ! 35: void esp_fifo_clear(void); ! 36: ! 37: /* ESP Command Register */ ! 38: Uint8 esp_cmd_state; ! 39: #define ESP_CMD_INPROGRESS 0x01 ! 40: #define ESP_CMD_WAITING 0x02 ! 41: void esp_start_command(Uint8 cmd); ! 42: void esp_finish_command(void); ! 43: void esp_command_clear(void); ! 44: void esp_command_write(Uint8 cmd); ! 45: ! 46: /* ESP Registers */ ! 47: Uint8 writetranscountl; ! 48: Uint8 writetranscounth; ! 49: Uint8 fifo[ESP_FIFO_SIZE]; ! 50: Uint8 command[2]; ! 51: Uint8 status; ! 52: Uint8 selectbusid; ! 53: Uint8 intstatus; ! 54: Uint8 selecttimeout; ! 55: Uint8 seqstep; ! 56: Uint8 syncperiod; ! 57: Uint8 fifoflags; ! 58: Uint8 syncoffset; ! 59: Uint8 configuration; ! 60: Uint8 clockconv; ! 61: Uint8 esptest; ! 62: ! 63: Uint32 esp_counter; ! 64: ! 65: ! 66: /* Command Register */ ! 67: #define CMD_DMA 0x80 ! 68: #define CMD_CMD 0x7f ! 69: ! 70: #define CMD_TYP_MASK 0x70 ! 71: #define CMD_TYP_MSC 0x00 ! 72: #define CMD_TYP_TGT 0x20 ! 73: #define CMD_TYP_INR 0x10 ! 74: #define CMD_TYP_DIS 0x40 ! 75: ! 76: /* Miscellaneous Commands */ ! 77: #define CMD_NOP 0x00 ! 78: #define CMD_FLUSH 0x01 ! 79: #define CMD_RESET 0x02 ! 80: #define CMD_BUSRESET 0x03 ! 81: /* Initiator Commands */ ! 82: #define CMD_TI 0x10 ! 83: #define CMD_ICCS 0x11 ! 84: #define CMD_MSGACC 0x12 ! 85: #define CMD_PAD 0x18 ! 86: #define CMD_SATN 0x1a ! 87: /* Disconnected Commands */ ! 88: #define CMD_RESEL 0x40 ! 89: #define CMD_SEL 0x41 ! 90: #define CMD_SELATN 0x42 ! 91: #define CMD_SELATNS 0x43 ! 92: #define CMD_ENSEL 0x44 ! 93: #define CMD_DISSEL 0x45 ! 94: /* Target Commands */ ! 95: #define CMD_SEMSG 0x20 ! 96: #define CMD_SESTAT 0x21 ! 97: #define CMD_SEDAT 0x22 ! 98: #define CMD_DISSEQ 0x23 ! 99: #define CMD_TERMSEQ 0x24 ! 100: #define CMD_TCCS 0x25 ! 101: #define CMD_DIS 0x27 ! 102: #define CMD_RMSGSEQ 0x28 ! 103: #define CMD_RCOMM 0x29 ! 104: #define CMD_RDATA 0x2A ! 105: #define CMD_RCSEQ 0x2B ! 106: ! 107: /* Status Register */ ! 108: #define STAT_MASK 0xF8 ! 109: #define STAT_PHASE 0x07 ! 110: ! 111: #define STAT_VGC 0x08 ! 112: #define STAT_TC 0x10 ! 113: #define STAT_PE 0x20 ! 114: #define STAT_GE 0x40 ! 115: #define STAT_INT 0x80 ! 116: ! 117: /* Bus ID Register */ ! 118: #define BUSID_DID 0x07 ! 119: ! 120: /* Interrupt Status Register */ ! 121: #define INTR_SEL 0x01 ! 122: #define INTR_SELATN 0x02 ! 123: #define INTR_RESEL 0x04 ! 124: #define INTR_FC 0x08 ! 125: #define INTR_BS 0x10 ! 126: #define INTR_DC 0x20 ! 127: #define INTR_ILL 0x40 ! 128: #define INTR_RST 0x80 ! 129: ! 130: /* Sequence Step Register */ ! 131: #define SEQ_0 0x00 ! 132: #define SEQ_SELTIMEOUT 0x02 ! 133: #define SEQ_CD 0x04 ! 134: ! 135: /* Configuration Register */ ! 136: #define CFG1_RESREPT 0x40 ! 137: ! 138: ! 139: /* ESP Status Variables */ ! 140: Uint8 mode_dma; ! 141: ! 142: /* Experimental */ ! 143: #define ESP_CLOCK_FREQ 20 /* ESP is clocked at 20 MHz */ ! 144: #define ESP_DELAY 100 /* Standard wait time for ESP interrupt (except bus reset and selection timeout) */ ! 145: ! 146: ! 147: /* ESP DMA control and status registers */ ! 148: ! 149: void ESP_DMA_CTRL_Read(void) { ! 150: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_dma.control; ! 151: Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA control read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 152: } ! 153: ! 154: void ESP_DMA_CTRL_Write(void) { ! 155: Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA control write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 156: esp_dma.control = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 157: ! 158: if (esp_dma.control&ESPCTRL_FLUSH) { ! 159: Log_Printf(LOG_ESPDMA_LEVEL, "flush DMA buffer\n"); ! 160: if (ConfigureParams.System.bTurbo) { ! 161: tdma_flush_buffer(0); ! 162: } else { ! 163: dma_esp_flush_buffer(); ! 164: } ! 165: } ! 166: if (esp_dma.control&ESPCTRL_CHIP_TYPE) { ! 167: Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is WD33C92\n"); ! 168: } else { ! 169: Log_Printf(LOG_ESPDMA_LEVEL, "SCSI controller is NCR53C90\n"); ! 170: } ! 171: if (esp_dma.control&ESPCTRL_RESET) { ! 172: Log_Printf(LOG_ESPDMA_LEVEL, "reset SCSI controller\n"); ! 173: esp_reset_hard(); ! 174: } ! 175: if (esp_dma.control&ESPCTRL_DMA_READ) { ! 176: Log_Printf(LOG_ESPDMA_LEVEL, "DMA from SCSI to mem\n"); ! 177: } else { ! 178: Log_Printf(LOG_ESPDMA_LEVEL, "DMA from mem to SCSI\n"); ! 179: } ! 180: if (esp_dma.control&ESPCTRL_MODE_DMA) { ! 181: Log_Printf(LOG_ESPDMA_LEVEL, "mode DMA\n"); ! 182: } else { ! 183: Log_Printf(LOG_ESPDMA_LEVEL, "mode PIO\n"); ! 184: } ! 185: if (esp_dma.control&ESPCTRL_ENABLE_INT) { ! 186: Log_Printf(LOG_ESPDMA_LEVEL, "Enable ESP interrupt"); ! 187: if (status&STAT_INT) { ! 188: set_interrupt(INT_SCSI, SET_INT); ! 189: } ! 190: } else { ! 191: Log_Printf(LOG_ESPDMA_LEVEL, "Block ESP interrupt"); ! 192: set_interrupt(INT_SCSI, RELEASE_INT); ! 193: } ! 194: switch (esp_dma.control&ESPCTRL_CLKMASK) { ! 195: case ESPCTRL_CLK10MHz: ! 196: Log_Printf(LOG_ESPDMA_LEVEL, "10 MHz clock\n"); ! 197: break; ! 198: case ESPCTRL_CLK12MHz: ! 199: Log_Printf(LOG_ESPDMA_LEVEL, "12.5 MHz clock\n"); ! 200: break; ! 201: case ESPCTRL_CLK16MHz: ! 202: Log_Printf(LOG_ESPDMA_LEVEL, "16.6 MHz clock\n"); ! 203: break; ! 204: case ESPCTRL_CLK20MHz: ! 205: Log_Printf(LOG_ESPDMA_LEVEL, "20 MHz clock\n"); ! 206: break; ! 207: default: ! 208: break; ! 209: } ! 210: } ! 211: ! 212: void ESP_DMA_FIFO_STAT_Read(void) { ! 213: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_dma.status; ! 214: Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA FIFO status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 215: } ! 216: ! 217: void ESP_DMA_FIFO_STAT_Write(void) { ! 218: Log_Printf(LOG_ESPDMA_LEVEL,"ESP DMA FIFO status write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 219: esp_dma.status = IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 220: } ! 221: ! 222: void ESP_DMA_set_status(void) { /* this is just a guess */ ! 223: if ((esp_dma.status&ESPSTAT_STATE_MASK) == ESPSTAT_STATE_D0S1) { ! 224: //Log_Printf(LOG_WARN,"DMA in buffer 0, SCSI in buffer 1\n"); ! 225: esp_dma.status = (esp_dma.status&~ESPSTAT_STATE_MASK)|ESPSTAT_STATE_D1S0; ! 226: } else { ! 227: //Log_Printf(LOG_WARN,"DMA in buffer 1, SCSI in buffer 0\n"); ! 228: esp_dma.status = (esp_dma.status&~ESPSTAT_STATE_MASK)|ESPSTAT_STATE_D0S1; ! 229: } ! 230: } ! 231: ! 232: /* ESP Registers */ ! 233: ! 234: void ESP_TransCountL_Read(void) { // 0x02014000 ! 235: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=esp_counter&0xFF; ! 236: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountL read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 237: } ! 238: ! 239: void ESP_TransCountL_Write(void) { ! 240: writetranscountl=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 241: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountL write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 242: } ! 243: ! 244: void ESP_TransCountH_Read(void) { // 0x02014001 ! 245: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=(esp_counter>>8)&0xFF; ! 246: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCoundH read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 247: } ! 248: ! 249: void ESP_TransCountH_Write(void) { ! 250: writetranscounth=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 251: Log_Printf(LOG_ESPREG_LEVEL,"ESP TransCountH write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 252: } ! 253: ! 254: void ESP_FIFO_Read(void) { // 0x02014002 ! 255: IoMem[IoAccessCurrentAddress & IO_SEG_MASK] = esp_fifo_read(); ! 256: Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFO read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 257: } ! 258: ! 259: void ESP_FIFO_Write(void) { ! 260: esp_fifo_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]); ! 261: Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFO write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 262: } ! 263: ! 264: void ESP_Command_Read(void) { // 0x02014003 ! 265: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=command[0]; ! 266: Log_Printf(LOG_ESPREG_LEVEL,"ESP Command read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 267: } ! 268: ! 269: void ESP_Command_Write(void) { ! 270: esp_command_write(IoMem[IoAccessCurrentAddress & IO_SEG_MASK]); ! 271: Log_Printf(LOG_ESPREG_LEVEL,"ESP Command write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 272: } ! 273: ! 274: void ESP_Status_Read(void) { // 0x02014004 ! 275: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=(status&STAT_MASK)|(SCSIbus.phase&STAT_PHASE); ! 276: Log_Printf(LOG_ESPREG_LEVEL,"ESP Status read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 277: } ! 278: ! 279: void ESP_SelectBusID_Write(void) { ! 280: selectbusid=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 281: Log_Printf(LOG_ESPREG_LEVEL,"ESP SelectBusID write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 282: } ! 283: ! 284: void ESP_IntStatus_Read(void) { // 0x02014005 ! 285: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=intstatus; ! 286: Log_Printf(LOG_ESPREG_LEVEL,"ESP IntStatus read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 287: ! 288: if (status&STAT_INT) { ! 289: intstatus = 0x00; ! 290: status &= ~(STAT_VGC | STAT_PE | STAT_GE); ! 291: //seqstep = 0x00; /* FIXME: Is the data sheet really wrong with this? */ ! 292: esp_lower_irq(); ! 293: } ! 294: } ! 295: ! 296: void ESP_SelectTimeout_Write(void) { ! 297: selecttimeout=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 298: Log_Printf(LOG_ESPREG_LEVEL,"ESP SelectTimeout write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 299: } ! 300: ! 301: void ESP_SeqStep_Read(void) { // 0x02014006 ! 302: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=seqstep; ! 303: Log_Printf(LOG_ESPREG_LEVEL,"ESP SeqStep read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 304: } ! 305: ! 306: void ESP_SyncPeriod_Write(void) { ! 307: syncperiod=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 308: Log_Printf(LOG_ESPREG_LEVEL,"ESP SyncPeriod write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 309: } ! 310: ! 311: void ESP_FIFOflags_Read(void) { // 0x02014007 ! 312: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=fifoflags; ! 313: Log_Printf(LOG_ESPREG_LEVEL,"ESP FIFOflags read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 314: } ! 315: ! 316: void ESP_SyncOffset_Write(void) { ! 317: syncoffset=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 318: Log_Printf(LOG_ESPREG_LEVEL,"ESP SyncOffset write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 319: } ! 320: ! 321: void ESP_Configuration_Read(void) { // 0x02014008 ! 322: IoMem[IoAccessCurrentAddress & IO_SEG_MASK]=configuration; ! 323: Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 324: } ! 325: ! 326: void ESP_Configuration_Write(void) { ! 327: configuration=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 328: Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 329: } ! 330: ! 331: void ESP_ClockConv_Write(void) { // 0x02014009 ! 332: clockconv=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 333: Log_Printf(LOG_ESPREG_LEVEL,"ESP ClockConv write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 334: } ! 335: ! 336: void ESP_Test_Write(void) { // 0x0201400a ! 337: esptest=IoMem[IoAccessCurrentAddress & IO_SEG_MASK]; ! 338: Log_Printf(LOG_ESPREG_LEVEL,"ESP Test write at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 339: } ! 340: ! 341: /* System reads this register to check if we use old or new SCSI controller. ! 342: * Return 0 to report old chip. */ ! 343: void ESP_Conf2_Read(void) { // 0x0201400b ! 344: if (ConfigureParams.System.nSCSI == NCR53C90) ! 345: IoMem[IoAccessCurrentAddress&IO_SEG_MASK] = 0x00; ! 346: Log_Printf(LOG_ESPREG_LEVEL,"ESP Configuration2 read at $%08x val=$%02x PC=$%08x\n", IoAccessCurrentAddress, IoMem[IoAccessCurrentAddress & IO_SEG_MASK], m68k_getpc()); ! 347: } ! 348: ! 349: ! 350: /* Helper functions */ ! 351: ! 352: /* Functions for reading and writing ESP FIFO */ ! 353: Uint8 esp_fifo_read(void) { ! 354: int i; ! 355: Uint8 val; ! 356: ! 357: if (fifoflags > 0) { ! 358: val = fifo[0]; ! 359: for (i=0; i<(ESP_FIFO_SIZE-1); i++) ! 360: fifo[i]=fifo[i+1]; ! 361: fifo[ESP_FIFO_SIZE-1] = 0x00; ! 362: fifoflags--; ! 363: Log_Printf(LOG_ESPFIFO_LEVEL,"ESP FIFO: Reading byte, val=%02x, size = %i", val, fifoflags); ! 364: } else { ! 365: val = 0x00; ! 366: Log_Printf(LOG_WARN, "ESP FIFO read: FIFO is empty!\n"); ! 367: } ! 368: return val; ! 369: } ! 370: ! 371: void esp_fifo_write(Uint8 val) { ! 372: if (fifoflags==ESP_FIFO_SIZE) { ! 373: Log_Printf(LOG_WARN, "ESP FIFO write: FIFO overflow! Top of FIFO overwritten\n"); ! 374: fifo[fifoflags-1] = val; ! 375: status |= STAT_GE; ! 376: } else { ! 377: fifoflags++; ! 378: fifo[fifoflags-1] = val; ! 379: Log_Printf(LOG_ESPFIFO_LEVEL,"ESP FIFO: Writing byte %i, val=%02x", fifoflags-1, fifo[fifoflags-1]); ! 380: } ! 381: } ! 382: ! 383: void esp_fifo_clear(void) { ! 384: int i; ! 385: for (i=0; i<ESP_FIFO_SIZE; i++) { ! 386: fifo[i] = 0; ! 387: } ! 388: fifoflags &= 0xE0; ! 389: } ! 390: ! 391: /* Functions for handling dual ranked command register */ ! 392: void esp_command_write(Uint8 cmd) { ! 393: if ((command[1]&CMD_CMD)==CMD_RESET && (cmd&CMD_CMD)!=CMD_NOP) { ! 394: Log_Printf(LOG_WARN, "ESP command write: Chip reset in command register, not executing command.\n"); ! 395: } else { ! 396: command[1] = cmd; ! 397: ! 398: if (esp_cmd_state&ESP_CMD_WAITING) { ! 399: Log_Printf(LOG_WARN, "ESP command write: Error! Top of command register overwritten.\n"); ! 400: status |= STAT_GE; ! 401: } ! 402: } ! 403: ! 404: if ((command[1]&CMD_CMD)==CMD_RESET || (command[1]&CMD_CMD)==CMD_BUSRESET) { ! 405: esp_start_command(command[1]); ! 406: return; ! 407: } ! 408: ! 409: if (esp_cmd_state&ESP_CMD_INPROGRESS) { ! 410: esp_cmd_state |= ESP_CMD_WAITING; ! 411: } else { ! 412: command[0] = command[1]; ! 413: command[1] = 0x00; ! 414: esp_start_command(command[0]); ! 415: } ! 416: } ! 417: ! 418: void esp_command_clear(void) { ! 419: command[0] = 0x00; ! 420: if ((command[1]&CMD_CMD)!=CMD_RESET) { ! 421: command[1] = 0x00; ! 422: esp_cmd_state &= ~ESP_CMD_WAITING; ! 423: } ! 424: } ! 425: ! 426: void esp_finish_command(void) { ! 427: esp_cmd_state &= ~ESP_CMD_INPROGRESS; ! 428: if (esp_cmd_state&ESP_CMD_WAITING) { ! 429: command[0] = command[1]; ! 430: command[1] = 0x00; ! 431: esp_cmd_state &= ~ESP_CMD_WAITING; ! 432: esp_start_command(command[0]); ! 433: } ! 434: } ! 435: ! 436: void esp_start_command(Uint8 cmd) { ! 437: esp_cmd_state |= ESP_CMD_INPROGRESS; ! 438: ! 439: /* Check if command is valid for actual state */ ! 440: if ((cmd&CMD_TYP_MASK)!=CMD_TYP_MSC) { ! 441: if ((esp_state==TARGET && !(cmd&CMD_TYP_TGT)) || ! 442: (esp_state==INITIATOR && !(cmd&CMD_TYP_INR)) || ! 443: (esp_state==DISCONNECTED && !(cmd&CMD_TYP_DIS))) { ! 444: Log_Printf(LOG_WARN, "ESP Command: Illegal command for actual ESP state ($%02X)!\n",cmd); ! 445: esp_command_clear(); ! 446: intstatus |= INTR_ILL; ! 447: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 448: return; ! 449: } ! 450: } ! 451: ! 452: /* Check if the command is a DMA command */ ! 453: if (cmd & CMD_DMA) { ! 454: /* Load the internal counter on every DMA command, do not decrement actual registers! */ ! 455: esp_counter = writetranscountl | (writetranscounth << 8); ! 456: if (esp_counter == 0) { /* 0 means maximum value */ ! 457: esp_counter = 0x10000; ! 458: } ! 459: status &= ~STAT_TC; ! 460: mode_dma = 1; ! 461: } else { ! 462: mode_dma = 0; ! 463: } ! 464: ! 465: switch (cmd & CMD_CMD) { ! 466: /* Miscellaneous */ ! 467: case CMD_NOP: ! 468: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: NOP\n"); ! 469: esp_finish_command(); ! 470: break; ! 471: case CMD_FLUSH: ! 472: Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: flush FIFO\n"); ! 473: esp_flush_fifo(); ! 474: break; ! 475: case CMD_RESET: ! 476: Log_Printf(LOG_ESPCMD_LEVEL,"ESP Command: reset chip\n"); ! 477: esp_reset_hard(); ! 478: break; ! 479: case CMD_BUSRESET: ! 480: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: reset SCSI bus\n"); ! 481: esp_bus_reset(); ! 482: break; ! 483: /* Disconnected */ ! 484: case CMD_RESEL: ! 485: Log_Printf(LOG_WARN, "ESP Command: reselect sequence\n"); ! 486: abort(); ! 487: break; ! 488: case CMD_SEL: ! 489: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select without ATN sequence\n"); ! 490: esp_select(false); ! 491: break; ! 492: case CMD_SELATN: ! 493: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: select with ATN sequence\n"); ! 494: esp_select(true); ! 495: break; ! 496: case CMD_SELATNS: ! 497: Log_Printf(LOG_WARN, "ESP Command: select with ATN and stop sequence\n"); ! 498: abort(); ! 499: break; ! 500: case CMD_ENSEL: ! 501: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: enable selection/reselection\n"); ! 502: esp_finish_command(); /* Our disk doesn't do reselections */ ! 503: break; ! 504: case CMD_DISSEL: ! 505: Log_Printf(LOG_WARN, "ESP Command: disable selection/reselection\n"); ! 506: abort(); ! 507: break; ! 508: /* Initiator */ ! 509: case CMD_TI: ! 510: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer information\n"); ! 511: esp_transfer_info(); ! 512: break; ! 513: case CMD_ICCS: ! 514: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: initiator command complete sequence\n"); ! 515: esp_initiator_command_complete(); ! 516: break; ! 517: case CMD_MSGACC: ! 518: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: message accepted\n"); ! 519: esp_message_accepted(); ! 520: break; ! 521: case CMD_PAD: ! 522: Log_Printf(LOG_ESPCMD_LEVEL, "ESP Command: transfer pad\n"); ! 523: esp_transfer_pad(); ! 524: break; ! 525: case CMD_SATN: ! 526: Log_Printf(LOG_WARN, "ESP Command: set ATN\n"); ! 527: abort(); ! 528: break; ! 529: /* Target */ ! 530: case CMD_SEMSG: ! 531: case CMD_SESTAT: ! 532: case CMD_SEDAT: ! 533: case CMD_DISSEQ: ! 534: case CMD_TERMSEQ: ! 535: case CMD_TCCS: ! 536: case CMD_RMSGSEQ: ! 537: case CMD_RCOMM: ! 538: case CMD_RDATA: ! 539: case CMD_RCSEQ: ! 540: Log_Printf(LOG_WARN, "ESP Command: Target commands not emulated!\n"); ! 541: abort(); ! 542: break; ! 543: case CMD_DIS: ! 544: Log_Printf(LOG_WARN, "ESP Command: DISCONNECT not emulated!\n"); ! 545: abort(); ! 546: SCSIbus.phase = PHASE_ST; ! 547: intstatus = INTR_DC; ! 548: seqstep = SEQ_0; ! 549: break; ! 550: ! 551: default: ! 552: Log_Printf(LOG_WARN, "ESP Command: Illegal command!\n"); ! 553: esp_command_clear(); ! 554: intstatus |= INTR_ILL; ! 555: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 556: break; ! 557: } ! 558: } ! 559: ! 560: ! 561: /* This is the handler function for ESP delayed interrupts */ ! 562: void ESP_InterruptHandler(void) { ! 563: CycInt_AcknowledgeInterrupt(); ! 564: esp_raise_irq(); ! 565: } ! 566: ! 567: ! 568: void esp_raise_irq(void) { ! 569: if(!(status & STAT_INT)) { ! 570: status |= STAT_INT; ! 571: ! 572: if (esp_dma.control&ESPCTRL_ENABLE_INT) { ! 573: set_interrupt(INT_SCSI, SET_INT); ! 574: } ! 575: ! 576: if (LOG_ESPCMD_LEVEL == LOG_WARN) { ! 577: printf("[ESP] Raise IRQ: state="); ! 578: switch (esp_state) { ! 579: case DISCONNECTED: printf("disconnected"); break; ! 580: case INITIATOR: printf("initiator"); break; ! 581: case TARGET: printf("target"); break; ! 582: default: printf("unknown"); break; ! 583: } ! 584: printf(", phase="); ! 585: switch (SCSIbus.phase&STAT_PHASE) { ! 586: case PHASE_DO: printf("data out"); break; ! 587: case PHASE_DI: printf("data in"); break; ! 588: case PHASE_CD: printf("command"); break; ! 589: case PHASE_ST: printf("status"); break; ! 590: case PHASE_MI: printf("msg in"); break; ! 591: case PHASE_MO: printf("msg out"); break; ! 592: default: printf("unknown"); break; ! 593: } ! 594: if (status&STAT_TC) { ! 595: printf(", transfer complete"); ! 596: } else { ! 597: printf(", transfer not complete"); ! 598: } ! 599: printf(", sequence step=%i", seqstep); ! 600: printf(", interrupt status:\n"); ! 601: if (intstatus&INTR_RST) printf("bus reset\n"); ! 602: if (intstatus&INTR_BS) printf("bus service\n"); ! 603: if (intstatus&INTR_DC) printf("disconnected\n"); ! 604: if (intstatus&INTR_FC) printf("function complete\n"); ! 605: if (intstatus&INTR_ILL) printf("illegal command\n"); ! 606: if (intstatus&INTR_RESEL) printf("reselected\n"); ! 607: if (intstatus&INTR_SEL) printf("selected\n"); ! 608: if (intstatus&INTR_SELATN) printf("selected with ATN\n"); ! 609: } ! 610: } ! 611: } ! 612: ! 613: void esp_lower_irq(void) { ! 614: if (status & STAT_INT) { ! 615: status &= ~STAT_INT; ! 616: ! 617: set_interrupt(INT_SCSI, RELEASE_INT); ! 618: ! 619: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Lower IRQ\n"); ! 620: ! 621: esp_finish_command(); ! 622: } ! 623: } ! 624: ! 625: /* Functions */ ! 626: ! 627: /* Reset chip */ ! 628: void esp_reset_hard(void) { ! 629: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Hard reset\n"); ! 630: ! 631: clockconv = 0x02; ! 632: configuration &= ~0xF8; // clear chip test mode, parity enable, parity test, scsi request/int disable, slow cable mode ! 633: esp_fifo_clear(); ! 634: syncperiod = 0x05; ! 635: syncoffset = 0x00; ! 636: status &= ~STAT_INT; // release interrupt ! 637: set_interrupt(INT_SCSI, RELEASE_INT); ! 638: intstatus = 0x00; ! 639: status &= ~(STAT_VGC | STAT_PE | STAT_GE); // clear transfer complete aka valid group code, parity error, gross error ! 640: esp_reset_soft(); ! 641: esp_finish_command(); ! 642: } ! 643: ! 644: ! 645: ! 646: void esp_reset_soft(void) { ! 647: status &= ~STAT_TC; /* clear transfer count zero */ ! 648: ! 649: /* check, if this is complete */ ! 650: mode_dma = 0; ! 651: esp_counter = 0; /* reset counter, but not actual registers! */ ! 652: ! 653: seqstep = 0x00; ! 654: ! 655: /* writetranscountl, writetranscounth, selectbusid, selecttimeout are not initialized by reset */ ! 656: ! 657: /* This part is "disconnect reset" */ ! 658: esp_command_clear(); ! 659: esp_state = DISCONNECTED; ! 660: } ! 661: ! 662: ! 663: /* Reset SCSI bus */ ! 664: void esp_bus_reset(void) { ! 665: ! 666: esp_reset_soft(); ! 667: if (!(configuration & CFG1_RESREPT)) { ! 668: intstatus = INTR_RST; ! 669: SCSIbus.phase = PHASE_MI; /* CHECK: why message in phase? */ ! 670: Log_Printf(LOG_ESPCMD_LEVEL,"[ESP] SCSI bus reset raising IRQ (configuration=$%02X)\n",configuration); ! 671: CycInt_AddRelativeInterruptUs(500, 0, INTERRUPT_ESP); /* CHECK: how is this delay defined? */ ! 672: } else { ! 673: Log_Printf(LOG_ESPCMD_LEVEL,"[ESP] SCSI bus reset not interrupting (configuration=$%02X)\n",configuration); ! 674: esp_finish_command(); ! 675: } ! 676: } ! 677: ! 678: ! 679: /* Flush FIFO */ ! 680: void esp_flush_fifo(void) { ! 681: esp_fifo_clear(); ! 682: esp_finish_command(); ! 683: } ! 684: ! 685: ! 686: /* Select with or without ATN */ ! 687: void esp_select(bool atn) { ! 688: int cmd_size; ! 689: Uint8 identify_msg = 0; ! 690: Uint8 commandbuf[SCSI_CDB_MAX_SIZE]; ! 691: ! 692: seqstep = 0; ! 693: ! 694: /* First select our target */ ! 695: Uint8 target = selectbusid & BUSID_DID; /* Get bus ID from register */ ! 696: bool timeout = SCSIdisk_Select(target); ! 697: if (timeout) { ! 698: /* If a timeout occurs, generate disconnect interrupt */ ! 699: intstatus = INTR_DC; ! 700: esp_command_clear(); ! 701: esp_state = DISCONNECTED; ! 702: int seltout = (selecttimeout * 8192 * clockconv) / ESP_CLOCK_FREQ; /* timeout in microseconds */ ! 703: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Target %i, timeout after %i microseconds",target,seltout); ! 704: CycInt_AddRelativeInterruptUs(seltout, 0, INTERRUPT_ESP); ! 705: return; ! 706: } ! 707: ! 708: /* Next get our command */ ! 709: if(mode_dma == 1) { ! 710: cmd_size = esp_counter; ! 711: Log_Printf(LOG_WARN, "[ESP] Select: Reading command using DMA, size %i byte (not implemented!)",cmd_size); ! 712: abort(); ! 713: } else { ! 714: if (atn) { /* Read identify message from FIFO */ ! 715: SCSIbus.phase = PHASE_MO; ! 716: seqstep = 1; ! 717: identify_msg = esp_fifo_read(); ! 718: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Reading message from FIFO"); ! 719: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Identify Message: $%02X",identify_msg); ! 720: } ! 721: ! 722: /* Read command from FIFO */ ! 723: SCSIbus.phase = PHASE_CD; ! 724: seqstep = 3; ! 725: for (cmd_size = 0; cmd_size < SCSI_CDB_MAX_SIZE && fifoflags > 0; cmd_size++) { ! 726: commandbuf[cmd_size] = esp_fifo_read(); ! 727: } ! 728: ! 729: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Reading command from FIFO, size: %i byte",cmd_size); ! 730: } ! 731: ! 732: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Select: Target: %i",target); ! 733: ! 734: SCSIdisk_Receive_Command(commandbuf, identify_msg); ! 735: seqstep = 4; ! 736: esp_command_clear(); ! 737: ! 738: intstatus = INTR_BS | INTR_FC; ! 739: ! 740: esp_state = INITIATOR; ! 741: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 742: } ! 743: ! 744: ! 745: /* DMA done: this is called as part of transfer info or transfer pad ! 746: * after DMA transfer has completed. */ ! 747: ! 748: enum { ! 749: ESP_IO_STATE_TRANSFERING, ! 750: ESP_IO_STATE_FLUSHING, ! 751: ESP_IO_STATE_DONE ! 752: } esp_io_state; ! 753: ! 754: bool esp_transfer_done(bool write) { ! 755: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer done: ESP counter = %i, SCSI residual bytes: %i", ! 756: esp_counter,scsi_buffer.size); ! 757: ! 758: if (esp_counter == 0) { /* Transfer done */ ! 759: intstatus = INTR_FC; ! 760: status |= STAT_TC; ! 761: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 762: return true; ! 763: } else if ((write && SCSIbus.phase!=PHASE_DI) || (!write && SCSIbus.phase!=PHASE_DO)) { /* Phase change detected */ ! 764: esp_command_clear(); ! 765: intstatus = INTR_BS; ! 766: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 767: return true; ! 768: } /* else continue transfering data, no interrupt */ ! 769: return false; ! 770: } ! 771: ! 772: ! 773: /* Transfer information */ ! 774: void esp_transfer_info(void) { ! 775: if(mode_dma) { ! 776: esp_io_state=ESP_IO_STATE_TRANSFERING; ! 777: CycInt_AddRelativeInterruptUs(SCSI_Seek_Time() + SCSI_Sector_Time(), 100, INTERRUPT_ESP_IO); ! 778: } else { ! 779: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] start PIO transfer"); ! 780: switch (SCSIbus.phase) { ! 781: case PHASE_DI: ! 782: esp_fifo_write(SCSIdisk_Send_Data()); ! 783: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP); ! 784: break; ! 785: case PHASE_MI: ! 786: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP); ! 787: break; ! 788: case PHASE_ST: ! 789: /* FIXME: What should happen here? */ ! 790: Log_Printf(LOG_WARN, "[ESP] Error! Transfer info status phase"); ! 791: CycInt_AddRelativeInterruptCycles(20, INTERRUPT_ESP); ! 792: break; ! 793: default: ! 794: Log_Printf(LOG_WARN, "[ESP] PIO transfer (unimplemented)"); ! 795: abort(); ! 796: break; ! 797: } ! 798: } ! 799: } ! 800: void ESP_IO_Handler(void) { ! 801: CycInt_AcknowledgeInterrupt(); ! 802: ! 803: switch (esp_io_state) { ! 804: case ESP_IO_STATE_TRANSFERING: ! 805: switch (SCSIbus.phase) { ! 806: case PHASE_DI: ! 807: dma_esp_write_memory(); ! 808: if (esp_transfer_done(true)) { ! 809: esp_io_state=ESP_IO_STATE_FLUSHING; ! 810: } ! 811: break; ! 812: case PHASE_DO: ! 813: dma_esp_read_memory(); ! 814: if (esp_transfer_done(false)) { ! 815: return; ! 816: } ! 817: break; ! 818: ! 819: default: ! 820: break; ! 821: } ! 822: break; ! 823: case ESP_IO_STATE_FLUSHING: ! 824: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer done: Flushing DMA buffer."); ! 825: dma_esp_write_memory(); ! 826: return; ! 827: ! 828: default: ! 829: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer: Unkown state (%i).",esp_io_state); ! 830: return; ! 831: } ! 832: ! 833: CycInt_AddRelativeInterruptUs(100, 0, INTERRUPT_ESP_IO); ! 834: } ! 835: ! 836: ! 837: /* Transfer padding */ ! 838: void esp_transfer_pad(void) { ! 839: Log_Printf(LOG_ESPCMD_LEVEL, "[ESP] Transfer padding, ESP counter: %i bytes, SCSI resid: %i bytes\n", ! 840: esp_counter, scsi_buffer.size); ! 841: ! 842: switch (SCSIbus.phase) { ! 843: case PHASE_DI: ! 844: while (SCSIbus.phase==PHASE_DI && esp_counter>0) { ! 845: SCSIdisk_Send_Data(); ! 846: esp_counter--; ! 847: } ! 848: esp_transfer_done(true); ! 849: break; ! 850: case PHASE_DO: ! 851: while (SCSIbus.phase==PHASE_DO && esp_counter>0) { ! 852: SCSIdisk_Receive_Data(0); ! 853: esp_counter--; ! 854: } ! 855: esp_transfer_done(false); ! 856: break; ! 857: ! 858: default: ! 859: abort(); ! 860: break; ! 861: } ! 862: } ! 863: ! 864: ! 865: /* Initiator command complete */ ! 866: void esp_initiator_command_complete(void) { ! 867: ! 868: if(mode_dma == 1) { ! 869: Log_Printf(LOG_WARN, "ESP initiator command complete via DMA not implemented!"); ! 870: abort(); ! 871: } else { ! 872: /* Receive status byte */ ! 873: esp_fifo_write(SCSIdisk_Send_Status()); /* Disk sets phase to msg in after status send */ ! 874: ! 875: if (SCSIbus.phase!=PHASE_MI) { /* Stop sequence if no phase change to msg in occured */ ! 876: esp_command_clear(); ! 877: intstatus = INTR_BS; ! 878: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 879: return; ! 880: } ! 881: ! 882: /* Receive message byte */ ! 883: esp_fifo_write(SCSIdisk_Send_Message()); /* 0x00 = command complete */ ! 884: } ! 885: ! 886: intstatus = INTR_FC; ! 887: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 888: } ! 889: ! 890: ! 891: /* Message accepted */ ! 892: void esp_message_accepted(void) { ! 893: SCSIbus.phase = PHASE_ST; /* set at the end of iccs? */ ! 894: intstatus = INTR_BS; ! 895: esp_state = DISCONNECTED; /* CHECK: only disconnected if message was cmd complete? */ ! 896: CycInt_AddRelativeInterruptUs(ESP_DELAY, 20, INTERRUPT_ESP); ! 897: } ! 898: ! 899: ! 900: ! 901: #if 0 /* this is for target commands! */ ! 902: /* Decode command to determine the command group and thus the ! 903: * length of the incoming command. Set "valid group code" bit ! 904: * in status register if the group is 0, 1, 5, 6, or 7 (group ! 905: * 2 is also valid on NCR53C90A). ! 906: */ ! 907: Uint8 scsi_command_group = (commandbuf[0] & 0xE0) >> 5; ! 908: if(scsi_command_group < 3 || scsi_command_group > 4) { ! 909: if(ConfigureParams.System.nSCSI == NCR53C90 && scsi_command_group == 2) { ! 910: Log_Printf(LOG_WARN, "[ESP] Select: Invalid command group %i on NCR53C90\n", scsi_command_group); ! 911: status &= ~STAT_VGC; ! 912: } else { ! 913: status |= STAT_VGC; ! 914: } ! 915: } else { ! 916: Log_Printf(LOG_WARN, "[ESP] Select: Invalid command group %i on NCR53C90A\n", scsi_command_group); ! 917: status &= ~STAT_VGC; ! 918: } ! 919: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.