|
|
1.1 root 1: /* 1.1.1.3 root 2: Hatari - hdc.c 1.1 root 3: 1.1.1.15! root 4: This file is distributed under the GNU General Public License, version 2 ! 5: or at your option any later version. Read the file gpl.txt for details. 1.1 root 6: 1.1.1.3 root 7: Low-level hard drive emulation 1.1 root 8: */ 1.1.1.10 root 9: const char HDC_fileid[] = "Hatari hdc.c : " __DATE__ " " __TIME__; 1.1 root 10: 11: #include "main.h" 1.1.1.3 root 12: #include "configuration.h" 1.1.1.6 root 13: #include "debugui.h" 1.1.1.7 root 14: #include "file.h" 1.1 root 15: #include "fdc.h" 16: #include "hdc.h" 1.1.1.14 root 17: #include "ioMem.h" 1.1.1.7 root 18: #include "log.h" 1.1 root 19: #include "memorySnapShot.h" 20: #include "mfp.h" 21: #include "stMemory.h" 1.1.1.6 root 22: #include "tos.h" 1.1.1.9 root 23: #include "statusbar.h" 24: 1.1 root 25: 26: /* 27: ACSI emulation: 28: ACSI commands are six byte-packets sent to the 29: hard drive controller (which is on the HD unit, not in the ST) 30: 31: While the hard drive is busy, DRQ is high, polling the DRQ during 32: operation interrupts the current operation. The DRQ status can 33: be polled non-destructively in GPIP. 1.1.1.7 root 34: 1.1.1.15! root 35: (For simplicity, the operation is finished immediately, 1.1 root 36: this is a potential bug, but I doubt it is significant, 37: we just appear to have a very fast hard drive.) 38: 39: The ACSI command set is a subset of the SCSI standard. 40: (for details, see the X3T9.2 SCSI draft documents 41: from 1985, for an example of writing ACSI commands, 42: see the TOS DMA boot code) 43: */ 44: 1.1.1.7 root 45: // #define DISALLOW_HDC_WRITE 46: // #define HDC_VERBOSE /* display operations */ 47: // #define HDC_REALLY_VERBOSE /* display command packets */ 1.1 root 48: 1.1.1.14 root 49: #define HDC_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1]) 50: #define HDC_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2]) 51: #define HDC_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3]) 52: 53: /** 54: * Structure representing an ACSI command block. 55: */ 56: typedef struct { 57: int readCount; /* count of number of command bytes written */ 58: unsigned char target; 59: unsigned char opcode; 60: bool extended; 61: 62: int byteCount; /* count of number of command bytes written */ 63: unsigned char command[10]; 64: short int returnCode; /* return code from the HDC operation */ 65: } HDCOMMAND; 66: 1.1 root 67: /* HDC globals */ 68: HDCOMMAND HDCCommand; 69: int nPartitions = 0; 1.1.1.14 root 70: unsigned long hdSize = 0; 1.1 root 71: short int HDCSectorCount; 1.1.1.11 root 72: bool bAcsiEmuOn = false; 1.1.1.7 root 73: 1.1.1.12 root 74: static FILE *hd_image_file = NULL; 1.1.1.7 root 75: static Uint32 nLastBlockAddr; 1.1.1.9 root 76: static bool bSetLastBlockAddr; 1.1.1.7 root 77: static Uint8 nLastError; 1.1 root 78: 1.1.1.7 root 79: /* 1.1.1.4 root 80: FDC registers used: 81: - FDCSectorCountRegister 1.1 root 82: */ 83: 84: 85: /* Our dummy INQUIRY response data */ 1.1.1.7 root 86: static unsigned char inquiry_bytes[] = 1.1 root 87: { 1.1.1.7 root 88: 0, /* device type 0 = direct access device */ 89: 0, /* device type qualifier (nonremovable) */ 90: 1, /* ANSI version */ 91: 0, /* reserved */ 92: 26, /* length of the following data */ 93: ' ', ' ', ' ', /* Vendor specific data */ 1.1.1.12 root 94: 'H','a','t','a','r','i',' ',' ', /* Vendor */ 95: 'E','m','u','l','a','t','e','d', /* Model */ 1.1.1.7 root 96: ' ',' ',' ',' ', /* Revision */ 97: 0,0,0,0,0,0,0,0,0,0 /* ?? */ 1.1 root 98: }; 99: 1.1.1.7 root 100: 1.1 root 101: /*---------------------------------------------------------------------*/ 1.1.1.8 root 102: /** 1.1.1.14 root 103: * Return the device specified in the current ACSI command block. 104: */ 105: static unsigned char HDC_GetDevice(void) 106: { 107: return (HDCCommand.command[1] & 0xE0) >> 5; 108: } 109: 110: /** 111: * Return the file offset of the sector specified in the current ACSI command block. 1.1.1.8 root 112: */ 1.1.1.4 root 113: static unsigned long HDC_GetOffset(void) 114: { 1.1.1.14 root 115: /* offset = logical block address * 512 */ 116: return HDCCommand.opcode < 0x20? 117: // class 0 118: (HDC_ReadInt24(HDCCommand.command, 1) & 0x1FFFFF) << 9 : 119: // class 1 120: HDC_ReadInt32(HDCCommand.command, 2) << 9; 121: } 1.1 root 122: 1.1.1.14 root 123: /** 124: * Return the count specified in the current ACSI command block. 125: */ 126: static int HDC_GetCount(void) 127: { 128: return HDCCommand.opcode < 0x20? 129: // class 0 130: HDCCommand.command[4] : 131: // class1 132: HDC_ReadInt16(HDCCommand.command, 7); 133: } 1.1.1.7 root 134: 1.1.1.14 root 135: /** 136: * Return the control byte specified in the current ACSI command block. 137: */ 138: #ifdef HDC_REALLY_VERBOSE 139: static unsigned char HDC_GetControl(void) 140: { 141: return HDCCommand.opcode < 0x20? 142: // class 0 143: HDCCommand.command[5] : 144: // class1 145: HDCCommand.command[9]; 1.1 root 146: } 1.1.1.14 root 147: #endif 1.1 root 148: 1.1.1.7 root 149: 1.1 root 150: /*---------------------------------------------------------------------*/ 1.1.1.8 root 151: /** 152: * Seek - move to a sector 153: */ 1.1.1.7 root 154: static void HDC_Cmd_Seek(void) 1.1 root 155: { 1.1.1.7 root 156: nLastBlockAddr = HDC_GetOffset(); 1.1 root 157: 1.1.1.7 root 158: if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) == 0) 159: { 160: HDCCommand.returnCode = HD_STATUS_OK; 161: nLastError = HD_REQSENS_OK; 162: } 163: else 164: { 165: HDCCommand.returnCode = HD_STATUS_ERROR; 166: nLastError = HD_REQSENS_INVADDR; 167: } 1.1 root 168: 1.1.1.11 root 169: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 170: FDC_AcknowledgeInterrupt(); 1.1.1.11 root 171: bSetLastBlockAddr = true; 1.1.1.7 root 172: //FDCSectorCountRegister = 0; 1.1 root 173: } 174: 1.1.1.7 root 175: 1.1 root 176: /*---------------------------------------------------------------------*/ 1.1.1.8 root 177: /** 178: * Inquiry - return some disk information 179: */ 1.1.1.7 root 180: static void HDC_Cmd_Inquiry(void) 181: { 1.1.1.12 root 182: Uint32 nDmaAddr; 183: int count; 184: 1.1.1.14 root 185: nDmaAddr = FDC_GetDMAAddress(); 186: count = HDC_GetCount(); 1.1.1.12 root 187: 1.1.1.7 root 188: #ifdef HDC_VERBOSE 1.1.1.12 root 189: fprintf(stderr,"HDC: Inquiry, %i bytes to 0x%x.\n", count, nDmaAddr); 1.1.1.7 root 190: #endif 191: 1.1.1.12 root 192: if (count > (int)sizeof(inquiry_bytes)) 193: count = sizeof(inquiry_bytes); 194: 195: inquiry_bytes[4] = count - 8; 196: 1.1.1.13 root 197: if (STMemory_SafeCopy(nDmaAddr, inquiry_bytes, count, "HDC DMA inquiry")) 198: HDCCommand.returnCode = HD_STATUS_OK; 199: else 200: HDCCommand.returnCode = HD_STATUS_ERROR; 201: 1.1.1.12 root 202: FDC_WriteDMAAddress(nDmaAddr + count); 1.1.1.7 root 203: 1.1.1.11 root 204: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 205: FDC_AcknowledgeInterrupt(); 206: nLastError = HD_REQSENS_OK; 1.1.1.11 root 207: bSetLastBlockAddr = false; 1.1.1.7 root 208: //FDCSectorCountRegister = 0; 209: } 210: 211: 212: /*---------------------------------------------------------------------*/ 1.1.1.8 root 213: /** 214: * Request sense - return some disk information 215: */ 1.1.1.7 root 216: static void HDC_Cmd_RequestSense(void) 1.1 root 217: { 1.1.1.7 root 218: Uint32 nDmaAddr; 219: int nRetLen; 220: Uint8 retbuf[22]; 221: 222: #ifdef HDC_VERBOSE 223: fprintf(stderr,"HDC: Request Sense.\n"); 224: #endif 225: 1.1.1.14 root 226: nRetLen = HDC_GetCount(); 1.1.1.7 root 227: 228: if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22) 229: { 1.1.1.9 root 230: Log_Printf(LOG_WARN, "HDC: *** Strange REQUEST SENSE ***!\n"); 1.1.1.7 root 231: } 232: 233: /* Limit to sane length */ 234: if (nRetLen <= 0) 235: { 236: nRetLen = 4; 237: } 238: else if (nRetLen > 22) 239: { 240: nRetLen = 22; 241: } 242: 1.1.1.14 root 243: nDmaAddr = FDC_GetDMAAddress(); 1.1.1.7 root 244: 245: memset(retbuf, 0, nRetLen); 246: 247: if (nRetLen <= 4) 248: { 249: retbuf[0] = nLastError; 250: if (bSetLastBlockAddr) 251: { 252: retbuf[0] |= 0x80; 253: retbuf[1] = nLastBlockAddr >> 16; 254: retbuf[2] = nLastBlockAddr >> 8; 255: retbuf[3] = nLastBlockAddr; 256: } 257: } 258: else 259: { 260: retbuf[0] = 0x70; 261: if (bSetLastBlockAddr) 262: { 263: retbuf[0] |= 0x80; 264: retbuf[4] = nLastBlockAddr >> 16; 265: retbuf[5] = nLastBlockAddr >> 8; 266: retbuf[6] = nLastBlockAddr; 267: } 268: switch (nLastError) 269: { 270: case HD_REQSENS_OK: retbuf[2] = 0; break; 271: case HD_REQSENS_OPCODE: retbuf[2] = 5; break; 272: case HD_REQSENS_INVADDR: retbuf[2] = 5; break; 273: case HD_REQSENS_INVARG: retbuf[2] = 5; break; 274: case HD_REQSENS_NODRIVE: retbuf[2] = 2; break; 275: default: retbuf[2] = 4; break; 276: } 277: retbuf[7] = 14; 278: retbuf[12] = nLastError; 279: retbuf[19] = nLastBlockAddr >> 16; 280: retbuf[20] = nLastBlockAddr >> 8; 281: retbuf[21] = nLastBlockAddr; 282: } 283: 284: /* 285: fprintf(stderr,"*** Requested sense packet:\n"); 286: int i; 287: for (i = 0; i<nRetLen; i++) fprintf(stderr,"%2x ",retbuf[i]); 288: fprintf(stderr,"\n"); 289: */ 290: 1.1.1.13 root 291: if (STMemory_SafeCopy(nDmaAddr, retbuf, nRetLen, "HDC request sense")) 292: HDCCommand.returnCode = HD_STATUS_OK; 293: else 294: HDCCommand.returnCode = HD_STATUS_ERROR; 295: 1.1.1.12 root 296: FDC_WriteDMAAddress(nDmaAddr + nRetLen); 1.1.1.7 root 297: 1.1.1.11 root 298: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 299: FDC_AcknowledgeInterrupt(); 300: //FDCSectorCountRegister = 0; 301: } 302: 303: 304: /*---------------------------------------------------------------------*/ 1.1.1.8 root 305: /** 306: * Mode sense - Get parameters from disk. 307: * (Just enough to make the HDX tool from AHDI 5.0 happy) 308: */ 1.1.1.7 root 309: static void HDC_Cmd_ModeSense(void) 310: { 311: Uint32 nDmaAddr; 312: 313: #ifdef HDC_VERBOSE 314: fprintf(stderr,"HDC: Mode Sense.\n"); 315: #endif 316: 1.1.1.14 root 317: nDmaAddr = FDC_GetDMAAddress(); 1.1.1.7 root 318: 1.1.1.13 root 319: if (!STMemory_ValidArea(nDmaAddr, 16)) 320: { 321: Log_Printf(LOG_WARN, "HCD mode sense uses invalid RAM range 0x%x+%i\n", nDmaAddr, 16); 322: HDCCommand.returnCode = HD_STATUS_ERROR; 323: } 1.1.1.14 root 324: else if (HDCCommand.command[2] == 0 && HDC_GetCount() == 0x10) 1.1.1.7 root 325: { 326: size_t blocks; 327: blocks = File_Length(ConfigureParams.HardDisk.szHardDiskImage) / 512; 328: 329: STRam[nDmaAddr+0] = 0; 330: STRam[nDmaAddr+1] = 0; 331: STRam[nDmaAddr+2] = 0; 332: STRam[nDmaAddr+3] = 8; 333: STRam[nDmaAddr+4] = 0; 334: 335: STRam[nDmaAddr+5] = blocks >> 16; // Number of blocks, high (?) 336: STRam[nDmaAddr+6] = blocks >> 8; // Number of blocks, med (?) 337: STRam[nDmaAddr+7] = blocks; // Number of blocks, low (?) 338: 339: STRam[nDmaAddr+8] = 0; 340: 341: STRam[nDmaAddr+9] = 0; // Block size in bytes, high 342: STRam[nDmaAddr+10] = 2; // Block size in bytes, med 343: STRam[nDmaAddr+11] = 0; // Block size in bytes, low 344: 345: STRam[nDmaAddr+12] = 0; 346: STRam[nDmaAddr+13] = 0; 347: STRam[nDmaAddr+14] = 0; 348: STRam[nDmaAddr+15] = 0; 349: 1.1.1.12 root 350: FDC_WriteDMAAddress(nDmaAddr + 16); 351: 1.1.1.7 root 352: HDCCommand.returnCode = HD_STATUS_OK; 353: nLastError = HD_REQSENS_OK; 354: } 355: else 356: { 1.1.1.9 root 357: Log_Printf(LOG_TODO, "HDC: Unsupported MODE SENSE command\n"); 1.1.1.7 root 358: HDCCommand.returnCode = HD_STATUS_ERROR; 359: nLastError = HD_REQSENS_INVARG; 360: } 361: 1.1.1.11 root 362: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 363: FDC_AcknowledgeInterrupt(); 1.1.1.11 root 364: bSetLastBlockAddr = false; 1.1.1.7 root 365: //FDCSectorCountRegister = 0; 366: } 367: 368: 369: /*---------------------------------------------------------------------*/ 1.1.1.8 root 370: /** 371: * Format drive. 372: */ 1.1.1.7 root 373: static void HDC_Cmd_FormatDrive(void) 374: { 375: #ifdef HDC_VERBOSE 376: fprintf(stderr,"HDC: Format drive!\n"); 377: #endif 378: 379: /* Should erase the whole image file here... */ 380: 1.1.1.11 root 381: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 382: FDC_AcknowledgeInterrupt(); 383: HDCCommand.returnCode = HD_STATUS_OK; 384: nLastError = HD_REQSENS_OK; 1.1.1.11 root 385: bSetLastBlockAddr = false; 1.1.1.7 root 386: //FDCSectorCountRegister = 0; 1.1 root 387: } 388: 1.1.1.14 root 389: /*---------------------------------------------------------------------*/ 390: /** 391: * Read capacity of our disk. 392: */ 393: static void HDC_Cmd_ReadCapacity(void) 394: { 395: Uint32 nDmaAddr = FDC_GetDMAAddress(); 396: 397: #ifdef HDC_VERBOSE 398: fprintf(stderr,"Reading 8 bytes capacity data to addr: 0x%x\n", nDmaAddr); 399: #endif 400: 401: /* seek to the position */ 402: if (STMemory_ValidArea(nDmaAddr, 8)) 403: { 404: int nSectors = hdSize / 512; 405: STRam[nDmaAddr++] = (nSectors >> 24) & 0xFF; 406: STRam[nDmaAddr++] = (nSectors >> 16) & 0xFF; 407: STRam[nDmaAddr++] = (nSectors >> 8) & 0xFF; 408: STRam[nDmaAddr++] = (nSectors) & 0xFF; 409: STRam[nDmaAddr++] = 0x00; 410: STRam[nDmaAddr++] = 0x00; 411: STRam[nDmaAddr++] = 0x02; 412: STRam[nDmaAddr++] = 0x00; 413: 414: /* Update DMA counter */ 415: FDC_WriteDMAAddress(nDmaAddr + 8); 416: 417: HDCCommand.returnCode = HD_STATUS_OK; 418: nLastError = HD_REQSENS_OK; 419: } 420: else 421: { 422: Log_Printf(LOG_WARN, "HDC capacity read uses invalid RAM range 0x%x+%i\n", nDmaAddr, 8); 423: HDCCommand.returnCode = HD_STATUS_ERROR; 424: nLastError = HD_REQSENS_NOSECTOR; 425: } 426: 427: FDC_SetDMAStatus(false); /* no DMA error */ 428: FDC_AcknowledgeInterrupt(); 429: bSetLastBlockAddr = false; 430: //FDCSectorCountRegister = 0; 431: } 432: 1.1.1.7 root 433: 1.1 root 434: /*---------------------------------------------------------------------*/ 1.1.1.8 root 435: /** 436: * Write a sector off our disk - (seek implied) 437: */ 1.1.1.7 root 438: static void HDC_Cmd_WriteSector(void) 1.1 root 439: { 1.1.1.11 root 440: int n = 0; 441: 1.1.1.7 root 442: nLastBlockAddr = HDC_GetOffset(); 1.1 root 443: 1.1.1.7 root 444: /* seek to the position */ 445: if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) != 0) 446: { 447: HDCCommand.returnCode = HD_STATUS_ERROR; 448: nLastError = HD_REQSENS_INVADDR; 449: } 450: else 451: { 452: /* write - if allowed */ 1.1.1.14 root 453: Uint32 nDmaAddr = FDC_GetDMAAddress(); 1.1 root 454: #ifndef DISALLOW_HDC_WRITE 1.1.1.14 root 455: if (STMemory_ValidArea(nDmaAddr, 512*HDC_GetCount())) 1.1.1.13 root 456: { 457: n = fwrite(&STRam[nDmaAddr], 512, 1.1.1.14 root 458: HDC_GetCount(), hd_image_file); 1.1.1.13 root 459: } 460: else 461: { 462: Log_Printf(LOG_WARN, "HDC sector write uses invalid RAM range 0x%x+%i\n", 1.1.1.14 root 463: nDmaAddr, 512*HDC_GetCount()); 1.1.1.13 root 464: } 1.1 root 465: #endif 1.1.1.14 root 466: if (n == HDC_GetCount()) 1.1.1.11 root 467: { 468: HDCCommand.returnCode = HD_STATUS_OK; 469: nLastError = HD_REQSENS_OK; 470: } 471: else 472: { 473: HDCCommand.returnCode = HD_STATUS_ERROR; 474: nLastError = HD_REQSENS_WRITEERR; 475: } 476: 1.1.1.9 root 477: /* Update DMA counter */ 1.1.1.13 root 478: FDC_WriteDMAAddress(nDmaAddr + 512*n); 1.1.1.7 root 479: } 1.1 root 480: 1.1.1.11 root 481: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 482: FDC_AcknowledgeInterrupt(); 1.1.1.11 root 483: bSetLastBlockAddr = true; 1.1.1.7 root 484: //FDCSectorCountRegister = 0; 1.1 root 485: } 486: 1.1.1.7 root 487: 1.1 root 488: /*---------------------------------------------------------------------*/ 1.1.1.8 root 489: /** 490: * Read a sector off our disk - (implied seek) 491: */ 1.1.1.7 root 492: static void HDC_Cmd_ReadSector(void) 1.1 root 493: { 1.1.1.11 root 494: int n; 495: 1.1.1.7 root 496: nLastBlockAddr = HDC_GetOffset(); 1.1 root 497: 498: #ifdef HDC_VERBOSE 1.1.1.7 root 499: fprintf(stderr,"Reading %i sectors from 0x%x to addr: 0x%x\n", 1.1.1.15! root 500: HDC_GetCount(), nLastBlockAddr, FDC_GetDMAAddress()); 1.1 root 501: #endif 502: 1.1.1.7 root 503: /* seek to the position */ 504: if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) != 0) 505: { 506: HDCCommand.returnCode = HD_STATUS_ERROR; 507: nLastError = HD_REQSENS_INVADDR; 508: } 509: else 510: { 1.1.1.14 root 511: Uint32 nDmaAddr = FDC_GetDMAAddress(); 512: if (STMemory_ValidArea(nDmaAddr, 512*HDC_GetCount())) 1.1.1.13 root 513: { 514: n = fread(&STRam[nDmaAddr], 512, 1.1.1.14 root 515: HDC_GetCount(), hd_image_file); 1.1.1.13 root 516: } 517: else 518: { 519: Log_Printf(LOG_WARN, "HDC sector read uses invalid RAM range 0x%x+%i\n", 1.1.1.14 root 520: nDmaAddr, 512*HDC_GetCount()); 1.1.1.13 root 521: n = 0; 522: } 1.1.1.14 root 523: if (n == HDC_GetCount()) 1.1.1.11 root 524: { 525: HDCCommand.returnCode = HD_STATUS_OK; 526: nLastError = HD_REQSENS_OK; 527: } 528: else 529: { 530: HDCCommand.returnCode = HD_STATUS_ERROR; 531: nLastError = HD_REQSENS_NOSECTOR; 532: } 1.1.1.9 root 533: 534: /* Update DMA counter */ 1.1.1.13 root 535: FDC_WriteDMAAddress(nDmaAddr + 512*n); 1.1.1.7 root 536: } 1.1 root 537: 1.1.1.11 root 538: FDC_SetDMAStatus(false); /* no DMA error */ 1.1.1.7 root 539: FDC_AcknowledgeInterrupt(); 1.1.1.11 root 540: bSetLastBlockAddr = true; 1.1.1.7 root 541: //FDCSectorCountRegister = 0; 1.1 root 542: } 543: 1.1.1.7 root 544: 1.1 root 545: /*---------------------------------------------------------------------*/ 1.1.1.8 root 546: /** 1.1.1.12 root 547: * Test unit ready 548: */ 549: static void HDC_Cmd_TestUnitReady(void) 550: { 551: FDC_SetDMAStatus(false); /* no DMA error */ 552: FDC_AcknowledgeInterrupt(); 553: HDCCommand.returnCode = HD_STATUS_OK; 554: } 555: 556: 557: /*---------------------------------------------------------------------*/ 558: /** 1.1.1.8 root 559: * Emulation routine for HDC command packets. 560: */ 1.1.1.12 root 561: static void HDC_EmulateCommandPacket(void) 1.1 root 562: { 563: 1.1.1.14 root 564: switch(HDCCommand.opcode) 1.1.1.7 root 565: { 1.1 root 566: 1.1.1.12 root 567: case HD_TEST_UNIT_RDY: 568: HDC_Cmd_TestUnitReady(); 569: break; 570: 1.1.1.14 root 571: case HD_READ_CAPACITY1: 572: HDC_Cmd_ReadCapacity(); 573: break; 574: 1.1.1.7 root 575: case HD_READ_SECTOR: 1.1.1.14 root 576: case HD_READ_SECTOR1: 1.1.1.7 root 577: HDC_Cmd_ReadSector(); 578: break; 1.1.1.14 root 579: 1.1.1.7 root 580: case HD_WRITE_SECTOR: 1.1.1.14 root 581: case HD_WRITE_SECTOR1: 1.1.1.7 root 582: HDC_Cmd_WriteSector(); 583: break; 584: 585: case HD_INQUIRY: 586: HDC_Cmd_Inquiry(); 587: break; 588: 589: case HD_SEEK: 590: HDC_Cmd_Seek(); 591: break; 592: 593: case HD_SHIP: 594: HDCCommand.returnCode = 0xFF; 595: FDC_AcknowledgeInterrupt(); 596: break; 597: 598: case HD_REQ_SENSE: 599: HDC_Cmd_RequestSense(); 600: break; 601: 602: case HD_MODESELECT: 1.1.1.9 root 603: Log_Printf(LOG_TODO, "HDC: MODE SELECT call not implemented yet.\n"); 1.1.1.7 root 604: HDCCommand.returnCode = HD_STATUS_OK; 605: nLastError = HD_REQSENS_OK; 1.1.1.11 root 606: bSetLastBlockAddr = false; 607: FDC_SetDMAStatus(false); 1.1.1.7 root 608: FDC_AcknowledgeInterrupt(); 609: break; 610: 611: case HD_MODESENSE: 612: HDC_Cmd_ModeSense(); 613: break; 614: 615: case HD_FORMAT_DRIVE: 616: HDC_Cmd_FormatDrive(); 617: break; 618: 619: /* as of yet unsupported commands */ 620: case HD_VERIFY_TRACK: 621: case HD_FORMAT_TRACK: 622: case HD_CORRECTION: 623: 624: default: 625: HDCCommand.returnCode = HD_STATUS_ERROR; 626: nLastError = HD_REQSENS_OPCODE; 1.1.1.11 root 627: bSetLastBlockAddr = false; 1.1.1.7 root 628: FDC_AcknowledgeInterrupt(); 629: break; 630: } 1.1.1.9 root 631: 632: /* Update the led each time a command is processed */ 1.1.1.15! root 633: Statusbar_EnableHDLed( LED_STATE_ON ); 1.1 root 634: } 635: 1.1.1.7 root 636: 1.1 root 637: /*---------------------------------------------------------------------*/ 1.1.1.8 root 638: /** 639: * Debug routine for HDC command packets. 640: */ 1.1.1.7 root 641: #ifdef HDC_REALLY_VERBOSE 1.1.1.12 root 642: static void HDC_DebugCommandPacket(FILE *hdlogFile) 1.1 root 643: { 1.1.1.7 root 644: int opcode; 645: static const char *psComNames[] = 646: { 1.1.1.14 root 647: "TEST UNIT READY", // 0x00 648: "REZERO", // 0x01 649: "???", // 0x02 650: "REQUEST SENSE", // 0x03 651: "FORMAT DRIVE", // 0x04 652: "VERIFY TRACK (?)", // 0x05 653: "FORMAT TRACK (?)", // 0x06 654: "REASSIGN BLOCK", // 0x07 655: "READ SECTOR(S)", // 0x08 656: "???", // 0x09 657: "WRITE SECTOR(S)", // 0x0A 658: "SEEK", // 0x0B 659: "???", // 0x0C 660: "CORRECTION", // 0x0D 661: "???", // 0x0E 662: "TRANSLATE", // 0x0F 663: "SET ERROR THRESHOLD", // 0x10 664: "USAGE COUNTERS", // 0x11 665: "INQUIRY", // 0x12 666: "WRITE DATA BUFFER", // 0x13 667: "READ DATA BUFFER", // 0x14 668: "MODE SELECT", // 0x15 669: "???", // 0x16 670: "???", // 0x17 671: "EXTENDED READ", // 0x18 672: "READ TOC", // 0x19 673: "MODE SENSE", // 0x1A 674: "SHIP", // 0x1B 675: "RECEIVE DIAGNOSTICS", // 0x1C 676: "SEND DIAGNOSTICS", // 0x1D 677: "???", // 0x1E 678: "SET TARGET (EXTENDED)", // 0x1F 679: "???", // 0x20 680: "???", // 0x21 681: "???", // 0x22 682: "???", // 0x23 683: "???", // 0x24 684: "READ CAPACITY", // 0x25 685: "???", // 0x26 686: "???", // 0x27 687: "READ SECTOR(S)", // 0x28 688: "???", // 0x29 689: "WRITE SECTOR(S)", // 0x2A 1.1.1.7 root 690: }; 691: 1.1.1.14 root 692: opcode = HDCCommand.opcode; 1.1.1.7 root 693: 694: fprintf(hdlogFile,"----\n"); 695: 696: if (opcode >= 0 && opcode <= (int)(sizeof(psComNames)/sizeof(psComNames[0]))) 697: { 698: fprintf(hdlogFile, "HDC opcode 0x%x : %s\n",opcode,psComNames[opcode]); 699: } 700: else 701: { 702: fprintf(hdlogFile, "Unknown HDC opcode!! Value = 0x%x\n", opcode); 703: } 704: 1.1.1.14 root 705: fprintf(hdlogFile, "Target: %i\n", HDCCommand.target); 706: fprintf(hdlogFile, "Device: %i\n", HDC_GetDevice()); 1.1.1.12 root 707: fprintf(hdlogFile, "LBA: 0x%lx\n", HDC_GetOffset()/512); 1.1.1.7 root 708: 1.1.1.14 root 709: fprintf(hdlogFile, "Sector count: 0x%x\n", HDC_GetCount()); 1.1.1.7 root 710: fprintf(hdlogFile, "HDC sector count: 0x%x\n", HDCSectorCount); 711: //fprintf(hdlogFile, "FDC sector count: 0x%x\n", FDCSectorCountRegister); 1.1.1.14 root 712: fprintf(hdlogFile, "Control byte: 0x%x\n", HDC_GetControl()); 1.1 root 713: } 1.1.1.7 root 714: #endif 715: 1.1 root 716: 717: /*---------------------------------------------------------------------*/ 1.1.1.8 root 718: /** 719: * Print data about the hard drive image 720: */ 1.1.1.4 root 721: static void HDC_GetInfo(void) 1.1 root 722: { 1.1.1.7 root 723: /* Partition table contains hd size + 4 partition entries 724: * (composed of flag byte, 3 char ID, start offset and size), 725: * this is followed by bad sector list + count and the root sector checksum. 726: * Before this there's the boot code and with ICD hd driver additional 8 727: * partition entries (at offset 0x156). 728: */ 729: #define HD_PARTITIONTABLE_SIZE (4+4*12) 730: #define HD_PARTITIONTABLE_OFFSET 0x1C2 731: long offset; 732: unsigned char hdinfo[HD_PARTITIONTABLE_SIZE]; 733: int i; 1.1 root 734: 1.1.1.7 root 735: nPartitions = 0; 736: if (hd_image_file == NULL) 737: return; 738: offset = ftell(hd_image_file); 739: 740: fseek(hd_image_file, HD_PARTITIONTABLE_OFFSET, 0); 1.1.1.11 root 741: if (fread(hdinfo, HD_PARTITIONTABLE_SIZE, 1, hd_image_file) != 1) 742: { 743: perror("HDC_GetInfo"); 744: return; 745: } 1.1 root 746: 1.1.1.14 root 747: hdSize = HDC_ReadInt32(hdinfo, 0); 1.1.1.7 root 748: 1.1.1.14 root 749: #ifdef HDC_VERBOSE 750: fprintf(stderr, "Total disk size %li Mb\n", hdSize>>11); 1.1.1.7 root 751: /* flags for each partition entry are zero if they are not valid */ 752: fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No"); 753: fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No"); 754: fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No"); 755: fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No"); 1.1 root 756: #endif 757: 1.1.1.7 root 758: for(i=0;i<4;i++) 759: if(hdinfo[4 + 12*i]) 760: nPartitions++; 1.1 root 761: 1.1.1.7 root 762: fseek(hd_image_file, offset, 0); 1.1 root 763: } 764: 1.1.1.7 root 765: 1.1 root 766: /*---------------------------------------------------------------------*/ 1.1.1.8 root 767: /** 768: * Open the disk image file, set partitions. 1.1 root 769: */ 1.1.1.12 root 770: bool HDC_Init(void) 1.1 root 771: { 1.1.1.12 root 772: char *filename; 1.1.1.11 root 773: bAcsiEmuOn = false; 1.1 root 774: 1.1.1.12 root 775: if (!ConfigureParams.HardDisk.bUseHardDiskImage) 776: return false; 777: filename = ConfigureParams.HardDisk.szHardDiskImage; 778: 1.1.1.7 root 779: /* Sanity check - is file length a multiple of 512? */ 780: if (File_Length(filename) & 0x1ff) 781: { 782: Log_Printf(LOG_ERROR, "HD file '%s' has strange size!\n", filename); 1.1.1.11 root 783: return false; 1.1.1.7 root 784: } 1.1.1.3 root 785: 1.1.1.7 root 786: if ((hd_image_file = fopen(filename, "rb+")) == NULL) 787: { 788: Log_Printf(LOG_ERROR, "Can not open HD file '%s'!\n", filename); 1.1.1.11 root 789: return false; 1.1.1.7 root 790: } 791: 792: HDC_GetInfo(); 793: 794: /* set number of partitions */ 795: nNumDrives += nPartitions; 796: 1.1.1.11 root 797: bAcsiEmuOn = true; 1.1.1.14 root 798: HDCCommand.readCount = 0; 1.1.1.12 root 799: HDCCommand.byteCount = 0; 1.1.1.7 root 800: 1.1.1.12 root 801: printf("Hard drive image %s mounted.\n", filename); 1.1.1.11 root 802: return true; 1.1 root 803: } 1.1.1.3 root 804: 1.1.1.7 root 805: 1.1 root 806: /*---------------------------------------------------------------------*/ 1.1.1.8 root 807: /** 808: * HDC_UnInit - close image file 809: * 1.1 root 810: */ 1.1.1.4 root 811: void HDC_UnInit(void) 1.1 root 812: { 1.1.1.7 root 813: if (!bAcsiEmuOn) 814: return; 815: 816: fclose(hd_image_file); 817: hd_image_file = NULL; 818: 819: nNumDrives -= nPartitions; 820: nPartitions = 0; 1.1.1.11 root 821: bAcsiEmuOn = false; 1.1 root 822: } 823: 1.1.1.7 root 824: 1.1 root 825: /*---------------------------------------------------------------------*/ 1.1.1.8 root 826: /** 1.1.1.14 root 827: * Reset command status. 828: */ 829: void HDC_ResetCommandStatus(void) 830: { 831: /*HDCCommand.byteCount = 0;*/ /* Not done on real ST? */ 832: HDCCommand.returnCode = 0; 833: } 834: 835: 836: /** 837: * Get command status. 838: */ 839: short int HDC_GetCommandStatus(void) 840: { 841: return HDCCommand.returnCode; 842: } 843: 844: 845: /*---------------------------------------------------------------------*/ 846: /** 847: * Get sector count. 848: */ 849: short int HDC_GetSectorCount(void) 850: { 851: return HDCSectorCount; 852: } 853: 854: 855: /*---------------------------------------------------------------------*/ 856: /** 1.1.1.8 root 857: * Process HDC command packets, called when bytes are 858: * written to $FFFF8606 and the HDC (not the FDC) is selected. 859: */ 1.1.1.4 root 860: void HDC_WriteCommandPacket(void) 1.1 root 861: { 1.1.1.15! root 862: unsigned char b; ! 863: 1.1.1.7 root 864: /* is HDC emulation enabled? */ 865: if (!bAcsiEmuOn) 866: return; 867: 1.1.1.14 root 868: /* command byte sent */ 1.1.1.15! root 869: b = IoMem_ReadByte(0xff8605); 1.1.1.14 root 870: 871: /* Extract target and extended mode early, read acsi opcode */ 872: if (HDCCommand.readCount == 0) 873: { 874: HDCCommand.target = ((b & 0xE0) >> 5); 875: HDCCommand.opcode = (b & 0x1F); 876: HDCCommand.extended = (HDCCommand.opcode == 0x1F); 877: } 878: /* In extended mode, the scsi opcode is at position 1 */ 879: else if (HDCCommand.extended && HDCCommand.readCount == 1) 880: { 881: HDCCommand.opcode = (b & 0xFF); 882: } 1.1.1.12 root 883: 884: /* We only support one target with ID 0 */ 1.1.1.14 root 885: if (HDCCommand.target != 0) 1.1.1.12 root 886: { 887: //FDC_SetDMAStatus(true); 888: //FDC_AcknowledgeInterrupt(); 889: //FDCSectorCountRegister = 0; 890: /* If there's no controller, the interrupt line stays high */ 891: HDCCommand.returnCode = HD_STATUS_ERROR; 892: MFP_GPIP |= 0x20; 893: return; 894: } 895: 1.1.1.14 root 896: /* Successfully received one byte, so increase the byte-count, but in extended mode skip the first byte */ 897: if (!HDCCommand.extended || HDCCommand.readCount != 0) 898: { 899: HDCCommand.command[HDCCommand.byteCount++] = b; 900: } 901: ++HDCCommand.readCount; 1.1.1.7 root 902: 1.1.1.14 root 903: /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */ 904: if ((HDCCommand.opcode < 0x20 && HDCCommand.byteCount >= 6) || 905: (HDCCommand.opcode < 0x40 && HDCCommand.byteCount >= 10)) 1.1.1.7 root 906: { 1.1 root 907: #ifdef HDC_REALLY_VERBOSE 1.1.1.7 root 908: HDC_DebugCommandPacket(stderr); 1.1 root 909: #endif 1.1.1.7 root 910: /* If it's aimed for our drive, emulate it! */ 1.1.1.14 root 911: if (HDC_GetDevice() == 0) 1.1.1.7 root 912: { 1.1.1.12 root 913: HDC_EmulateCommandPacket(); 1.1.1.7 root 914: } 915: else 916: { 1.1.1.12 root 917: Log_Printf(LOG_WARN, "HDC: Access to non-existing drive.\n"); 1.1.1.7 root 918: HDCCommand.returnCode = HD_STATUS_ERROR; 919: } 920: 1.1.1.14 root 921: HDCCommand.readCount = 0; 1.1.1.7 root 922: HDCCommand.byteCount = 0; 923: } 924: else 925: { 1.1.1.12 root 926: FDC_AcknowledgeInterrupt(); 927: FDC_SetDMAStatus(false); 928: HDCCommand.returnCode = HD_STATUS_OK; 1.1.1.7 root 929: } 1.1 root 930: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.