|
|
1.1 root 1: /*
1.1.1.3 root 2: Hatari - hdc.c
1.1 root 3:
1.1.1.3 root 4: This file is distributed under the GNU Public License, version 2 or at
5: 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 root 35: (For simplicity, the operation is finished immediatly,
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.14! root 500: HDC_GetCount(), nLastBlockAddr, FDC_ReadDMAAddress());
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 */
633: Statusbar_EnableHDLed();
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.7 root 862: /* is HDC emulation enabled? */
863: if (!bAcsiEmuOn)
864: return;
865:
1.1.1.14! root 866: /* command byte sent */
! 867: unsigned char b = IoMem_ReadByte(0xff8605);
! 868:
! 869: /* Extract target and extended mode early, read acsi opcode */
! 870: if (HDCCommand.readCount == 0)
! 871: {
! 872: HDCCommand.target = ((b & 0xE0) >> 5);
! 873: HDCCommand.opcode = (b & 0x1F);
! 874: HDCCommand.extended = (HDCCommand.opcode == 0x1F);
! 875: }
! 876: /* In extended mode, the scsi opcode is at position 1 */
! 877: else if (HDCCommand.extended && HDCCommand.readCount == 1)
! 878: {
! 879: HDCCommand.opcode = (b & 0xFF);
! 880: }
1.1.1.12 root 881:
882: /* We only support one target with ID 0 */
1.1.1.14! root 883: if (HDCCommand.target != 0)
1.1.1.12 root 884: {
885: //FDC_SetDMAStatus(true);
886: //FDC_AcknowledgeInterrupt();
887: //FDCSectorCountRegister = 0;
888: /* If there's no controller, the interrupt line stays high */
889: HDCCommand.returnCode = HD_STATUS_ERROR;
890: MFP_GPIP |= 0x20;
891: return;
892: }
893:
1.1.1.14! root 894: /* Successfully received one byte, so increase the byte-count, but in extended mode skip the first byte */
! 895: if (!HDCCommand.extended || HDCCommand.readCount != 0)
! 896: {
! 897: HDCCommand.command[HDCCommand.byteCount++] = b;
! 898: }
! 899: ++HDCCommand.readCount;
1.1.1.7 root 900:
1.1.1.14! root 901: /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
! 902: if ((HDCCommand.opcode < 0x20 && HDCCommand.byteCount >= 6) ||
! 903: (HDCCommand.opcode < 0x40 && HDCCommand.byteCount >= 10))
1.1.1.7 root 904: {
1.1 root 905: #ifdef HDC_REALLY_VERBOSE
1.1.1.7 root 906: HDC_DebugCommandPacket(stderr);
1.1 root 907: #endif
1.1.1.7 root 908: /* If it's aimed for our drive, emulate it! */
1.1.1.14! root 909: if (HDC_GetDevice() == 0)
1.1.1.7 root 910: {
1.1.1.12 root 911: HDC_EmulateCommandPacket();
1.1.1.7 root 912: }
913: else
914: {
1.1.1.12 root 915: Log_Printf(LOG_WARN, "HDC: Access to non-existing drive.\n");
1.1.1.7 root 916: HDCCommand.returnCode = HD_STATUS_ERROR;
917: }
918:
1.1.1.14! root 919: HDCCommand.readCount = 0;
1.1.1.7 root 920: HDCCommand.byteCount = 0;
921: }
922: else
923: {
1.1.1.12 root 924: FDC_AcknowledgeInterrupt();
925: FDC_SetDMAStatus(false);
926: HDCCommand.returnCode = HD_STATUS_OK;
1.1.1.7 root 927: }
1.1 root 928: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.