|
|
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:
1.1.1.17! root 11: #include <errno.h>
! 12:
1.1 root 13: #include "main.h"
1.1.1.3 root 14: #include "configuration.h"
1.1.1.6 root 15: #include "debugui.h"
1.1.1.7 root 16: #include "file.h"
1.1 root 17: #include "fdc.h"
18: #include "hdc.h"
1.1.1.14 root 19: #include "ioMem.h"
1.1.1.7 root 20: #include "log.h"
1.1 root 21: #include "memorySnapShot.h"
22: #include "mfp.h"
23: #include "stMemory.h"
1.1.1.6 root 24: #include "tos.h"
1.1.1.9 root 25: #include "statusbar.h"
26:
1.1 root 27:
28: /*
29: ACSI emulation:
30: ACSI commands are six byte-packets sent to the
31: hard drive controller (which is on the HD unit, not in the ST)
32:
33: While the hard drive is busy, DRQ is high, polling the DRQ during
34: operation interrupts the current operation. The DRQ status can
35: be polled non-destructively in GPIP.
1.1.1.7 root 36:
1.1.1.15 root 37: (For simplicity, the operation is finished immediately,
1.1 root 38: this is a potential bug, but I doubt it is significant,
39: we just appear to have a very fast hard drive.)
40:
41: The ACSI command set is a subset of the SCSI standard.
42: (for details, see the X3T9.2 SCSI draft documents
43: from 1985, for an example of writing ACSI commands,
44: see the TOS DMA boot code)
45: */
46:
1.1.1.7 root 47: // #define DISALLOW_HDC_WRITE
48: // #define HDC_VERBOSE /* display operations */
1.1.1.17! root 49: #define WITH_NCR5380 0
1.1 root 50:
1.1.1.14 root 51: #define HDC_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1])
52: #define HDC_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2])
53: #define HDC_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3])
54:
55: /**
1.1.1.16 root 56: * Information about a ACSI/SCSI drive
1.1.1.14 root 57: */
58: typedef struct {
1.1.1.16 root 59: bool enabled;
60: FILE *image_file;
61: Uint32 nLastBlockAddr; /* The specified sector number */
62: bool bSetLastBlockAddr;
63: Uint8 nLastError;
64: unsigned long hdSize; /* Size of the hard disk in sectors */
65: } SCSI_DEV;
66:
67: /**
68: * Status of the ACSI/SCSI bus/controller including the current command block.
69: */
70: typedef struct {
71: int target;
72: int byteCount; /* number of command bytes received */
73: Uint8 command[16];
74: Uint8 opcode;
75: bool bDmaError;
76: short int returnCode; /* return code from the HDC operation */
1.1.1.17! root 77: Uint8 *resp; /* Response buffer */
! 78: int respbufsize;
! 79: int respcnt;
! 80: int respidx;
1.1.1.16 root 81: SCSI_DEV devs[8];
82: } SCSI_CTRLR;
1.1.1.14 root 83:
1.1 root 84: /* HDC globals */
1.1.1.17! root 85: static SCSI_CTRLR AcsiBus;
! 86: int nAcsiPartitions = 0;
1.1.1.11 root 87: bool bAcsiEmuOn = false;
1.1.1.7 root 88:
1.1.1.17! root 89: #if WITH_NCR5380
! 90: static SCSI_CTRLR ScsiBus;
! 91: #endif
1.1 root 92:
93: /* Our dummy INQUIRY response data */
1.1.1.7 root 94: static unsigned char inquiry_bytes[] =
1.1 root 95: {
1.1.1.7 root 96: 0, /* device type 0 = direct access device */
97: 0, /* device type qualifier (nonremovable) */
1.1.1.16 root 98: 1, /* ACSI/SCSI version */
1.1.1.7 root 99: 0, /* reserved */
1.1.1.16 root 100: 31, /* length of the following data */
101: 0, 0, 0, /* Vendor specific data */
102: 'H','a','t','a','r','i',' ',' ', /* Vendor ID */
103: 'E','m','u','l','a','t','e','d', /* Product ID 1 */
104: 'H','a','r','d','d','i','s','k', /* Product ID 2 */
105: '0','1','8','0', /* Revision */
1.1 root 106: };
107:
1.1.1.7 root 108:
1.1 root 109: /*---------------------------------------------------------------------*/
1.1.1.8 root 110: /**
1.1.1.16 root 111: * Return the LUN (logical unit number) specified in the current
112: * ACSI/SCSI command block.
1.1.1.14 root 113: */
1.1.1.16 root 114: static unsigned char HDC_GetLUN(SCSI_CTRLR *ctr)
1.1.1.14 root 115: {
1.1.1.16 root 116: return (ctr->command[1] & 0xE0) >> 5;
1.1.1.14 root 117: }
118:
119: /**
1.1.1.16 root 120: * Return the start sector (logical block address) specified in the
121: * current ACSI/SCSI command block.
1.1.1.8 root 122: */
1.1.1.16 root 123: static unsigned long HDC_GetLBA(SCSI_CTRLR *ctr)
1.1.1.4 root 124: {
1.1.1.14 root 125: /* offset = logical block address * 512 */
1.1.1.16 root 126: if (ctr->opcode < 0x20) /* Class 0? */
127: return HDC_ReadInt24(ctr->command, 1) & 0x1FFFFF;
128: else
129: return HDC_ReadInt32(ctr->command, 2); /* Class 1 */
1.1.1.14 root 130: }
1.1 root 131:
1.1.1.14 root 132: /**
133: * Return the count specified in the current ACSI command block.
134: */
1.1.1.16 root 135: static int HDC_GetCount(SCSI_CTRLR *ctr)
1.1.1.14 root 136: {
1.1.1.16 root 137: if (ctr->opcode < 0x20)
138: return ctr->command[4]; /* Class 0 */
139: else
140: return HDC_ReadInt16(ctr->command, 7); /* Class 1 */
1.1.1.14 root 141: }
1.1.1.7 root 142:
1.1.1.14 root 143: /**
144: * Return the control byte specified in the current ACSI command block.
145: */
1.1.1.16 root 146: static inline Uint8 HDC_GetControl(SCSI_CTRLR *ctr)
1.1.1.14 root 147: {
1.1.1.16 root 148: if (ctr->opcode < 0x20)
149: return ctr->command[5]; /* Class 0 */
150: else
151: return ctr->command[9]; /* Class 1 */
152: }
153:
154: /**
1.1.1.17! root 155: * Get pointer to response buffer, set up size indicator - and allocate
! 156: * a new buffer if it is not big enough
! 157: */
! 158: static Uint8 *HDC_PrepRespBuf(SCSI_CTRLR *ctr, int size)
! 159: {
! 160: ctr->respcnt = size;
! 161: ctr->respidx = 0;
! 162:
! 163: if (size > ctr->respbufsize)
! 164: {
! 165: ctr->respbufsize = size;
! 166: ctr->resp = realloc(ctr->resp, size);
! 167: }
! 168:
! 169: return ctr->resp;
! 170: }
! 171:
! 172: /**
1.1.1.16 root 173: * Get info string for SCSI/ACSI command packets.
174: */
175: static inline char *HDC_CmdInfoStr(SCSI_CTRLR *ctr)
176: {
177: static char str[80];
178:
179: snprintf(str, sizeof(str), "t=%i, lun=%i, opc=%i, cnt=0x%x, ctrl=0x%x",
180: ctr->target, HDC_GetLUN(ctr), ctr->opcode, HDC_GetCount(ctr),
181: HDC_GetControl(ctr));
182:
183: return str;
1.1 root 184: }
185:
1.1.1.7 root 186:
1.1.1.8 root 187: /**
188: * Seek - move to a sector
189: */
1.1.1.16 root 190: static void HDC_Cmd_Seek(SCSI_CTRLR *ctr)
1.1 root 191: {
1.1.1.16 root 192: SCSI_DEV *dev = &ctr->devs[ctr->target];
193:
194: dev->nLastBlockAddr = HDC_GetLBA(ctr);
195:
1.1.1.17! root 196: LOG_TRACE(TRACE_SCSI_CMD, "HDC: SEEK (%s), LBA=%i",
1.1.1.16 root 197: HDC_CmdInfoStr(ctr), dev->nLastBlockAddr);
1.1 root 198:
1.1.1.16 root 199: if (dev->nLastBlockAddr < dev->hdSize &&
200: fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) == 0)
1.1.1.7 root 201: {
1.1.1.17! root 202: LOG_TRACE(TRACE_SCSI_CMD, " -> OK\n");
1.1.1.16 root 203: ctr->returnCode = HD_STATUS_OK;
204: dev->nLastError = HD_REQSENS_OK;
1.1.1.7 root 205: }
206: else
207: {
1.1.1.17! root 208: LOG_TRACE(TRACE_SCSI_CMD, " -> ERROR\n");
1.1.1.16 root 209: ctr->returnCode = HD_STATUS_ERROR;
210: dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7 root 211: }
1.1 root 212:
1.1.1.16 root 213: dev->bSetLastBlockAddr = true;
1.1 root 214: }
215:
1.1.1.7 root 216:
1.1.1.8 root 217: /**
218: * Inquiry - return some disk information
219: */
1.1.1.16 root 220: static void HDC_Cmd_Inquiry(SCSI_CTRLR *ctr)
1.1.1.7 root 221: {
1.1.1.16 root 222: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root 223: Uint8 *buf;
1.1.1.12 root 224: int count;
225:
1.1.1.16 root 226: count = HDC_GetCount(ctr);
1.1.1.12 root 227:
1.1.1.17! root 228: LOG_TRACE(TRACE_SCSI_CMD, "HDC: INQUIRY (%s)", HDC_CmdInfoStr(ctr));
! 229:
! 230: buf = HDC_PrepRespBuf(ctr, count);
! 231: memcpy(buf, inquiry_bytes, count);
1.1.1.7 root 232:
1.1.1.12 root 233: if (count > (int)sizeof(inquiry_bytes))
234: count = sizeof(inquiry_bytes);
235:
1.1.1.16 root 236: /* For unsupported LUNs set the Peripheral Qualifier and the
237: * Peripheral Device Type according to the SCSI standard */
1.1.1.17! root 238: buf[0] = HDC_GetLUN(ctr) == 0 ? 0 : 0x7F;
1.1.1.16 root 239:
1.1.1.17! root 240: buf[4] = count - 5;
1.1.1.12 root 241:
1.1.1.17! root 242: ctr->returnCode = HD_STATUS_OK;
1.1.1.7 root 243:
1.1.1.16 root 244: dev->nLastError = HD_REQSENS_OK;
245: dev->bSetLastBlockAddr = false;
1.1.1.7 root 246: }
247:
248:
1.1.1.8 root 249: /**
250: * Request sense - return some disk information
251: */
1.1.1.16 root 252: static void HDC_Cmd_RequestSense(SCSI_CTRLR *ctr)
1.1 root 253: {
1.1.1.16 root 254: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.7 root 255: int nRetLen;
1.1.1.17! root 256: Uint8 *retbuf;
1.1.1.7 root 257:
1.1.1.16 root 258: nRetLen = HDC_GetCount(ctr);
1.1.1.7 root 259:
1.1.1.16 root 260: LOG_TRACE(TRACE_SCSI_CMD, "HDC: REQUEST SENSE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7 root 261:
262: if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22)
263: {
1.1.1.9 root 264: Log_Printf(LOG_WARN, "HDC: *** Strange REQUEST SENSE ***!\n");
1.1.1.7 root 265: }
266:
267: /* Limit to sane length */
268: if (nRetLen <= 0)
269: {
270: nRetLen = 4;
271: }
272: else if (nRetLen > 22)
273: {
274: nRetLen = 22;
275: }
276:
1.1.1.17! root 277: retbuf = HDC_PrepRespBuf(ctr, nRetLen);
1.1.1.7 root 278: memset(retbuf, 0, nRetLen);
279:
280: if (nRetLen <= 4)
281: {
1.1.1.16 root 282: retbuf[0] = dev->nLastError;
283: if (dev->bSetLastBlockAddr)
1.1.1.7 root 284: {
285: retbuf[0] |= 0x80;
1.1.1.16 root 286: retbuf[1] = dev->nLastBlockAddr >> 16;
287: retbuf[2] = dev->nLastBlockAddr >> 8;
288: retbuf[3] = dev->nLastBlockAddr;
1.1.1.7 root 289: }
290: }
291: else
292: {
293: retbuf[0] = 0x70;
1.1.1.16 root 294: if (dev->bSetLastBlockAddr)
1.1.1.7 root 295: {
296: retbuf[0] |= 0x80;
1.1.1.16 root 297: retbuf[4] = dev->nLastBlockAddr >> 16;
298: retbuf[5] = dev->nLastBlockAddr >> 8;
299: retbuf[6] = dev->nLastBlockAddr;
1.1.1.7 root 300: }
1.1.1.16 root 301: switch (dev->nLastError)
1.1.1.7 root 302: {
303: case HD_REQSENS_OK: retbuf[2] = 0; break;
304: case HD_REQSENS_OPCODE: retbuf[2] = 5; break;
305: case HD_REQSENS_INVADDR: retbuf[2] = 5; break;
306: case HD_REQSENS_INVARG: retbuf[2] = 5; break;
1.1.1.16 root 307: case HD_REQSENS_INVLUN: retbuf[2] = 5; break;
1.1.1.7 root 308: default: retbuf[2] = 4; break;
309: }
310: retbuf[7] = 14;
1.1.1.16 root 311: retbuf[12] = dev->nLastError;
312: retbuf[19] = dev->nLastBlockAddr >> 16;
313: retbuf[20] = dev->nLastBlockAddr >> 8;
314: retbuf[21] = dev->nLastBlockAddr;
1.1.1.7 root 315: }
316:
317: /*
318: fprintf(stderr,"*** Requested sense packet:\n");
319: int i;
320: for (i = 0; i<nRetLen; i++) fprintf(stderr,"%2x ",retbuf[i]);
321: fprintf(stderr,"\n");
322: */
323:
1.1.1.17! root 324: ctr->returnCode = HD_STATUS_OK;
1.1.1.7 root 325: }
326:
327:
1.1.1.8 root 328: /**
329: * Mode sense - Get parameters from disk.
330: * (Just enough to make the HDX tool from AHDI 5.0 happy)
331: */
1.1.1.16 root 332: static void HDC_Cmd_ModeSense(SCSI_CTRLR *ctr)
1.1.1.7 root 333: {
1.1.1.16 root 334: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root 335: Uint8 *buf;
1.1.1.7 root 336:
1.1.1.16 root 337: LOG_TRACE(TRACE_SCSI_CMD, "HDC: MODE SENSE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7 root 338:
1.1.1.17! root 339: dev->bSetLastBlockAddr = false;
1.1.1.12 root 340:
1.1.1.17! root 341: if (ctr->command[2] != 0 || HDC_GetCount(ctr) != 0x10)
1.1.1.7 root 342: {
1.1.1.9 root 343: Log_Printf(LOG_TODO, "HDC: Unsupported MODE SENSE command\n");
1.1.1.16 root 344: ctr->returnCode = HD_STATUS_ERROR;
345: dev->nLastError = HD_REQSENS_INVARG;
1.1.1.17! root 346: return;
1.1.1.7 root 347: }
348:
1.1.1.17! root 349: buf = HDC_PrepRespBuf(ctr, 16);
! 350:
! 351: buf[0] = 0;
! 352: buf[1] = 0;
! 353: buf[2] = 0;
! 354: buf[3] = 8;
! 355: buf[4] = 0;
! 356:
! 357: buf[5] = dev->hdSize >> 16; // Number of blocks, high
! 358: buf[6] = dev->hdSize >> 8; // Number of blocks, med
! 359: buf[7] = dev->hdSize; // Number of blocks, low
! 360:
! 361: buf[8] = 0;
! 362:
! 363: buf[9] = 0; // Block size in bytes, high
! 364: buf[10] = 2; // Block size in bytes, med
! 365: buf[11] = 0; // Block size in bytes, low
! 366:
! 367: buf[12] = 0;
! 368: buf[13] = 0;
! 369: buf[14] = 0;
! 370: buf[15] = 0;
! 371:
! 372: ctr->returnCode = HD_STATUS_OK;
! 373: dev->nLastError = HD_REQSENS_OK;
1.1.1.7 root 374: }
375:
376:
1.1.1.8 root 377: /**
378: * Format drive.
379: */
1.1.1.16 root 380: static void HDC_Cmd_FormatDrive(SCSI_CTRLR *ctr)
1.1.1.7 root 381: {
1.1.1.16 root 382: SCSI_DEV *dev = &ctr->devs[ctr->target];
383:
384: LOG_TRACE(TRACE_SCSI_CMD, "HDC: FORMAT DRIVE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7 root 385:
386: /* Should erase the whole image file here... */
387:
1.1.1.16 root 388: ctr->returnCode = HD_STATUS_OK;
389: dev->nLastError = HD_REQSENS_OK;
390: dev->bSetLastBlockAddr = false;
1.1 root 391: }
392:
1.1.1.16 root 393:
1.1.1.14 root 394: /**
395: * Read capacity of our disk.
396: */
1.1.1.16 root 397: static void HDC_Cmd_ReadCapacity(SCSI_CTRLR *ctr)
1.1.1.14 root 398: {
1.1.1.16 root 399: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root 400: int nSectors = dev->hdSize - 1;
! 401: Uint8 *buf;
1.1.1.14 root 402:
1.1.1.17! root 403: LOG_TRACE(TRACE_SCSI_CMD, "HDC: READ CAPACITY (%s)\n", HDC_CmdInfoStr(ctr));
1.1.1.14 root 404:
1.1.1.17! root 405: buf = HDC_PrepRespBuf(ctr, 8);
1.1.1.14 root 406:
1.1.1.17! root 407: buf[0] = (nSectors >> 24) & 0xFF;
! 408: buf[1] = (nSectors >> 16) & 0xFF;
! 409: buf[2] = (nSectors >> 8) & 0xFF;
! 410: buf[3] = (nSectors) & 0xFF;
! 411: buf[4] = 0x00;
! 412: buf[5] = 0x00;
! 413: buf[6] = 0x02;
! 414: buf[7] = 0x00;
1.1.1.14 root 415:
1.1.1.17! root 416: ctr->returnCode = HD_STATUS_OK;
! 417: dev->nLastError = HD_REQSENS_OK;
1.1.1.16 root 418: dev->bSetLastBlockAddr = false;
1.1.1.14 root 419: }
420:
1.1.1.7 root 421:
1.1.1.8 root 422: /**
423: * Write a sector off our disk - (seek implied)
424: */
1.1.1.16 root 425: static void HDC_Cmd_WriteSector(SCSI_CTRLR *ctr)
1.1 root 426: {
1.1.1.16 root 427: SCSI_DEV *dev = &ctr->devs[ctr->target];
428: Uint32 nDmaAddr = FDC_GetDMAAddress();
1.1.1.11 root 429: int n = 0;
430:
1.1.1.16 root 431: dev->nLastBlockAddr = HDC_GetLBA(ctr);
432:
1.1.1.17! root 433: LOG_TRACE(TRACE_SCSI_CMD, "HDC: WRITE SECTOR (%s) with LBA 0x%x from 0x%x",
1.1.1.16 root 434: HDC_CmdInfoStr(ctr), dev->nLastBlockAddr, nDmaAddr);
1.1 root 435:
1.1.1.7 root 436: /* seek to the position */
1.1.1.16 root 437: if (dev->nLastBlockAddr >= dev->hdSize ||
438: fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) != 0)
1.1.1.7 root 439: {
1.1.1.16 root 440: ctr->returnCode = HD_STATUS_ERROR;
441: dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7 root 442: }
443: else
444: {
445: /* write - if allowed */
1.1 root 446: #ifndef DISALLOW_HDC_WRITE
1.1.1.17! root 447: if ( STMemory_CheckAreaType ( nDmaAddr , 512 * HDC_GetCount(ctr) , ABFLAG_RAM ) )
1.1.1.13 root 448: {
449: n = fwrite(&STRam[nDmaAddr], 512,
1.1.1.16 root 450: HDC_GetCount(ctr), dev->image_file);
1.1.1.13 root 451: }
452: else
453: {
454: Log_Printf(LOG_WARN, "HDC sector write uses invalid RAM range 0x%x+%i\n",
1.1.1.16 root 455: nDmaAddr, 512 * HDC_GetCount(ctr));
456: ctr->bDmaError = true;
1.1.1.13 root 457: }
1.1 root 458: #endif
1.1.1.16 root 459: if (n == HDC_GetCount(ctr))
1.1.1.11 root 460: {
1.1.1.16 root 461: ctr->returnCode = HD_STATUS_OK;
462: dev->nLastError = HD_REQSENS_OK;
1.1.1.11 root 463: }
464: else
465: {
1.1.1.16 root 466: ctr->returnCode = HD_STATUS_ERROR;
467: dev->nLastError = HD_REQSENS_WRITEERR;
1.1.1.11 root 468: }
469:
1.1.1.9 root 470: /* Update DMA counter */
1.1.1.13 root 471: FDC_WriteDMAAddress(nDmaAddr + 512*n);
1.1.1.7 root 472: }
1.1.1.17! root 473: LOG_TRACE(TRACE_SCSI_CMD, " -> %s (%d)\n",
! 474: ctr->returnCode == HD_STATUS_OK ? "OK" : "ERROR",
! 475: dev->nLastError);
1.1 root 476:
1.1.1.16 root 477: dev->bSetLastBlockAddr = true;
1.1 root 478: }
479:
1.1.1.7 root 480:
1.1.1.8 root 481: /**
482: * Read a sector off our disk - (implied seek)
483: */
1.1.1.16 root 484: static void HDC_Cmd_ReadSector(SCSI_CTRLR *ctr)
1.1 root 485: {
1.1.1.16 root 486: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root 487: Uint8 *buf;
1.1.1.11 root 488: int n;
489:
1.1.1.16 root 490: dev->nLastBlockAddr = HDC_GetLBA(ctr);
1.1 root 491:
1.1.1.17! root 492: LOG_TRACE(TRACE_SCSI_CMD, "HDC: READ SECTOR (%s) with LBA 0x%x",
! 493: HDC_CmdInfoStr(ctr), dev->nLastBlockAddr);
1.1 root 494:
1.1.1.7 root 495: /* seek to the position */
1.1.1.16 root 496: if (dev->nLastBlockAddr >= dev->hdSize ||
497: fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) != 0)
1.1.1.7 root 498: {
1.1.1.16 root 499: ctr->returnCode = HD_STATUS_ERROR;
500: dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7 root 501: }
502: else
503: {
1.1.1.17! root 504: buf = HDC_PrepRespBuf(ctr, 512 * HDC_GetCount(ctr));
! 505: n = fread(buf, 512, HDC_GetCount(ctr), dev->image_file);
1.1.1.16 root 506: if (n == HDC_GetCount(ctr))
1.1.1.11 root 507: {
1.1.1.16 root 508: ctr->returnCode = HD_STATUS_OK;
509: dev->nLastError = HD_REQSENS_OK;
1.1.1.11 root 510: }
511: else
512: {
1.1.1.16 root 513: ctr->returnCode = HD_STATUS_ERROR;
514: dev->nLastError = HD_REQSENS_NOSECTOR;
1.1.1.11 root 515: }
1.1.1.7 root 516: }
1.1.1.17! root 517: LOG_TRACE(TRACE_SCSI_CMD, " -> %s (%d)\n",
! 518: ctr->returnCode == HD_STATUS_OK ? "OK" : "ERROR",
! 519: dev->nLastError);
1.1 root 520:
1.1.1.16 root 521: dev->bSetLastBlockAddr = true;
1.1 root 522: }
523:
1.1.1.7 root 524:
1.1.1.8 root 525: /**
1.1.1.12 root 526: * Test unit ready
527: */
1.1.1.16 root 528: static void HDC_Cmd_TestUnitReady(SCSI_CTRLR *ctr)
1.1.1.12 root 529: {
1.1.1.16 root 530: LOG_TRACE(TRACE_SCSI_CMD, "HDC: TEST UNIT READY (%s).\n", HDC_CmdInfoStr(ctr));
531: ctr->returnCode = HD_STATUS_OK;
1.1.1.12 root 532: }
533:
534:
535: /**
1.1.1.8 root 536: * Emulation routine for HDC command packets.
537: */
1.1.1.16 root 538: static void HDC_EmulateCommandPacket(SCSI_CTRLR *ctr)
1.1 root 539: {
1.1.1.16 root 540: SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1 root 541:
1.1.1.17! root 542: ctr->respcnt = 0;
! 543:
1.1.1.16 root 544: switch (ctr->opcode)
1.1.1.7 root 545: {
1.1.1.12 root 546: case HD_TEST_UNIT_RDY:
1.1.1.16 root 547: HDC_Cmd_TestUnitReady(ctr);
1.1.1.12 root 548: break;
549:
1.1.1.16 root 550: case HD_READ_CAPACITY1:
551: HDC_Cmd_ReadCapacity(ctr);
1.1.1.14 root 552: break;
553:
1.1.1.7 root 554: case HD_READ_SECTOR:
1.1.1.14 root 555: case HD_READ_SECTOR1:
1.1.1.16 root 556: HDC_Cmd_ReadSector(ctr);
1.1.1.7 root 557: break;
1.1.1.14 root 558:
1.1.1.7 root 559: case HD_WRITE_SECTOR:
1.1.1.14 root 560: case HD_WRITE_SECTOR1:
1.1.1.16 root 561: HDC_Cmd_WriteSector(ctr);
1.1.1.7 root 562: break;
563:
564: case HD_INQUIRY:
1.1.1.16 root 565: HDC_Cmd_Inquiry(ctr);
1.1.1.7 root 566: break;
567:
568: case HD_SEEK:
1.1.1.16 root 569: HDC_Cmd_Seek(ctr);
1.1.1.7 root 570: break;
571:
572: case HD_SHIP:
1.1.1.16 root 573: LOG_TRACE(TRACE_SCSI_CMD, "HDC: SHIP (%s).\n", HDC_CmdInfoStr(ctr));
574: ctr->returnCode = 0xFF;
1.1.1.7 root 575: break;
576:
577: case HD_REQ_SENSE:
1.1.1.16 root 578: HDC_Cmd_RequestSense(ctr);
1.1.1.7 root 579: break;
580:
581: case HD_MODESELECT:
1.1.1.16 root 582: LOG_TRACE(TRACE_SCSI_CMD, "HDC: MODE SELECT (%s) TODO!\n", HDC_CmdInfoStr(ctr));
583: ctr->returnCode = HD_STATUS_OK;
584: dev->nLastError = HD_REQSENS_OK;
585: dev->bSetLastBlockAddr = false;
1.1.1.7 root 586: break;
587:
588: case HD_MODESENSE:
1.1.1.16 root 589: HDC_Cmd_ModeSense(ctr);
1.1.1.7 root 590: break;
591:
592: case HD_FORMAT_DRIVE:
1.1.1.16 root 593: HDC_Cmd_FormatDrive(ctr);
1.1.1.7 root 594: break;
595:
596: /* as of yet unsupported commands */
597: case HD_VERIFY_TRACK:
598: case HD_FORMAT_TRACK:
599: case HD_CORRECTION:
600:
601: default:
1.1.1.16 root 602: LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s)!\n", HDC_CmdInfoStr(ctr));
603: ctr->returnCode = HD_STATUS_ERROR;
604: dev->nLastError = HD_REQSENS_OPCODE;
605: dev->bSetLastBlockAddr = false;
1.1.1.7 root 606: break;
607: }
1.1.1.9 root 608:
609: /* Update the led each time a command is processed */
1.1.1.15 root 610: Statusbar_EnableHDLed( LED_STATE_ON );
1.1 root 611: }
612:
1.1.1.7 root 613:
1.1 root 614: /*---------------------------------------------------------------------*/
1.1.1.8 root 615: /**
1.1.1.17! root 616: * Return given image file (primary) partition count and with tracing
! 617: * print also partition table.
! 618: *
! 619: * Supports both DOS and Atari master boot record partition tables
! 620: * (with 4 entries).
! 621: *
! 622: * TODO:
! 623: * - Support also Atari ICD (12 entries, at offset 0x156) and
! 624: * extended partition schemes. Linux kernel has code for those:
! 625: * http://lxr.free-electrons.com/source/block/partitions/atari.c
! 626: * - Support partition tables with other endianess
1.1.1.8 root 627: */
1.1.1.17! root 628: int HDC_PartitionCount(FILE *fp, const Uint64 tracelevel)
1.1 root 629: {
1.1.1.17! root 630: unsigned char *pinfo, bootsector[512];
! 631: Uint32 start, sectors, total = 0;
! 632: int i, parts = 0;
! 633: off_t offset;
1.1 root 634:
1.1.1.17! root 635: if (!fp)
! 636: return 0;
! 637: offset = ftello(fp);
1.1.1.7 root 638:
1.1.1.17! root 639: if (fseeko(fp, 0, SEEK_SET) != 0
! 640: || fread(bootsector, sizeof(bootsector), 1, fp) != 1)
1.1.1.11 root 641: {
1.1.1.17! root 642: perror("HDC_PartitionCount");
! 643: return 0;
1.1.1.11 root 644: }
1.1 root 645:
1.1.1.17! root 646: if (bootsector[0x1FE] == 0x55 && bootsector[0x1FF] == 0xAA)
! 647: {
! 648: int ptype, boot;
1.1 root 649:
1.1.1.17! root 650: LOG_TRACE(tracelevel, "DOS MBR:\n");
! 651: /* first partition table entry */
! 652: pinfo = bootsector + 0x1BE;
! 653: for (i = 0; i < 4; i++, pinfo += 16)
! 654: {
! 655: boot = pinfo[0];
! 656: ptype = pinfo[4];
! 657: start = HDC_ReadInt32(pinfo, 8);
! 658: sectors = HDC_ReadInt32(pinfo, 12);
! 659: total += sectors;
! 660: LOG_TRACE(tracelevel, "- Partition %d: type=0x%02x, start=0x%08x, size=%d MB %s\n",
! 661: i, ptype, start, sectors/2048, boot ? "(boot)" : "");
! 662: if (ptype)
! 663: parts++;
! 664: }
! 665: LOG_TRACE(tracelevel, "- Total size: %i MB in %d partitions\n", total/2048, parts);
! 666: }
! 667: else
! 668: {
! 669: /* Partition table contains hd size + 4 partition entries
! 670: * (composed of flag byte, 3 char ID, start offset
! 671: * and size), this is followed by bad sector list +
! 672: * count and the root sector checksum. Before this
! 673: * there's the boot code.
! 674: */
! 675: char c, pid[4];
! 676: int j, flags;
! 677:
! 678: LOG_TRACE(tracelevel, "ATARI MBR:\n");
! 679: pinfo = bootsector + 0x1C6;
! 680: for (i = 0; i < 4; i++, pinfo += 12)
! 681: {
! 682: flags = pinfo[0];
! 683: for (j = 0; j < 3; j++)
! 684: {
! 685: c = pinfo[j+1];
! 686: if (c < 32 || c >= 127)
! 687: c = '.';
! 688: pid[j] = c;
! 689: }
! 690: pid[3] = '\0';
! 691: start = HDC_ReadInt32(pinfo, 4);
! 692: sectors = HDC_ReadInt32(pinfo, 8);
! 693: LOG_TRACE(tracelevel, "- Partition %d: ID=%s, start=0x%08x, size=%d MB, flags=0x%x\n",
! 694: i, pid, start, sectors/2048, flags);
! 695: if (flags & 0x1)
! 696: parts++;
! 697: }
! 698: total = HDC_ReadInt32(bootsector, 0x1C2);
! 699: LOG_TRACE(tracelevel, "- Total size: %i MB in %d partitions\n", total/2048, parts);
! 700: }
1.1 root 701:
1.1.1.17! root 702: if (fseeko(fp, offset, SEEK_SET) != 0)
! 703: perror("HDC_PartitionCount");
! 704: return parts;
1.1 root 705: }
706:
1.1.1.17! root 707: /**
! 708: * Open a disk image file
! 709: */
! 710: static int HDC_InitDevice(SCSI_DEV *dev, char *filename)
! 711: {
! 712: off_t filesize;
! 713: FILE *fp;
! 714:
! 715: dev->enabled = false;
! 716: Log_Printf(LOG_INFO, "Mounting hard drive image '%s'\n", filename);
! 717:
! 718: /* Check size for sanity - is the length a multiple of 512? */
! 719: filesize = File_Length(filename);
! 720: if (filesize < 0)
! 721: {
! 722: Log_Printf(LOG_ERROR, "ERROR: unable to access/get HD file size!\n");
! 723: return -EINVAL;
! 724: }
! 725: if (filesize <= 0 || (filesize & 0x1ff) != 0)
! 726: {
! 727: Log_Printf(LOG_ERROR, "ERROR: HD file has strange size!\n");
! 728: return -EINVAL;
! 729: }
! 730:
! 731: fp = fopen(filename, "rb+");
! 732: if (fp == NULL)
! 733: {
! 734: Log_Printf(LOG_ERROR, "ERROR: cannot open HD file read/write!\n");
! 735: return -ENOENT;
! 736: }
! 737: if (!File_Lock(fp))
! 738: {
! 739: Log_Printf(LOG_ERROR, "ERROR: cannot lock HD file for writing!\n");
! 740: fclose(fp);
! 741: return -ENOLCK;
! 742: }
! 743:
! 744: dev->hdSize = filesize / 512;
! 745: dev->image_file = fp;
! 746: dev->enabled = true;
! 747:
! 748: return 0;
! 749: }
1.1.1.7 root 750:
1.1.1.8 root 751: /**
752: * Open the disk image file, set partitions.
1.1 root 753: */
1.1.1.12 root 754: bool HDC_Init(void)
1.1 root 755: {
1.1.1.16 root 756: int i;
1.1 root 757:
1.1.1.17! root 758: /* ACSI */
! 759: nAcsiPartitions = 0;
1.1.1.16 root 760: bAcsiEmuOn = false;
1.1.1.17! root 761: memset(&AcsiBus, 0, sizeof(AcsiBus));
! 762: AcsiBus.respbufsize = 512;
! 763: AcsiBus.resp = malloc(AcsiBus.respbufsize);
! 764: if (!AcsiBus.resp)
! 765: {
! 766: perror("HDC_Init");
! 767: return false;
! 768: }
1.1.1.16 root 769: for (i = 0; i < MAX_ACSI_DEVS; i++)
1.1.1.7 root 770: {
1.1.1.16 root 771: if (!ConfigureParams.Acsi[i].bUseDevice)
772: continue;
1.1.1.17! root 773: if (HDC_InitDevice(&AcsiBus.devs[i], ConfigureParams.Acsi[i].sDeviceFile) == 0)
1.1.1.16 root 774: {
1.1.1.17! root 775: bAcsiEmuOn = true;
! 776: nAcsiPartitions += HDC_PartitionCount(AcsiBus.devs[i].image_file, TRACE_SCSI_CMD);
1.1.1.16 root 777: }
1.1.1.17! root 778: }
1.1.1.16 root 779:
1.1.1.17! root 780: /* SCSI */
! 781: #if WITH_NCR5380
! 782: memset(&ScsiBus, 0, sizeof(ScsiBus));
! 783: ScsiBus.respbufsize = 512;
! 784: ScsiBus.resp = malloc(ScsiBus.respbufsize);
! 785: if (!ScsiBus.resp)
! 786: {
! 787: perror("HDC_Init");
! 788: return bAcsiEmuOn;
! 789: }
! 790: for (i = 0; i < MAX_SCSI_DEVS; i++)
! 791: {
! 792: if (!ConfigureParams.Scsi[i].bUseDevice)
1.1.1.16 root 793: continue;
1.1.1.17! root 794: HDC_InitDevice(&ScsiBus.devs[i], ConfigureParams.Scsi[i].sDeviceFile);
1.1.1.16 root 795: }
1.1.1.17! root 796: #endif
1.1.1.7 root 797:
798: /* set number of partitions */
1.1.1.17! root 799: nNumDrives += nAcsiPartitions;
1.1.1.7 root 800:
1.1.1.16 root 801: return bAcsiEmuOn;
1.1 root 802: }
1.1.1.3 root 803:
1.1.1.7 root 804:
1.1 root 805: /*---------------------------------------------------------------------*/
1.1.1.8 root 806: /**
807: * HDC_UnInit - close image file
808: *
1.1 root 809: */
1.1.1.4 root 810: void HDC_UnInit(void)
1.1 root 811: {
1.1.1.16 root 812: int i;
813:
1.1.1.7 root 814: if (!bAcsiEmuOn)
815: return;
816:
1.1.1.16 root 817: for (i = 0; i < MAX_ACSI_DEVS; i++)
818: {
819: if (!AcsiBus.devs[i].enabled)
820: continue;
1.1.1.17! root 821: File_UnLock(AcsiBus.devs[i].image_file);
1.1.1.16 root 822: fclose(AcsiBus.devs[i].image_file);
823: AcsiBus.devs[i].image_file = NULL;
824: AcsiBus.devs[i].enabled = false;
825: }
1.1.1.17! root 826: free(AcsiBus.resp);
! 827: AcsiBus.resp = NULL;
1.1.1.7 root 828:
1.1.1.17! root 829: #if WITH_NCR5380
! 830: for (i = 0; i < MAX_SCSI_DEVS; i++)
! 831: {
! 832: if (!ScsiBus.devs[i].enabled)
! 833: continue;
! 834: File_UnLock(ScsiBus.devs[i].image_file);
! 835: fclose(ScsiBus.devs[i].image_file);
! 836: ScsiBus.devs[i].image_file = NULL;
! 837: ScsiBus.devs[i].enabled = false;
! 838: }
! 839: free(ScsiBus.resp);
! 840: ScsiBus.resp = NULL;
! 841: #endif
! 842:
! 843: nNumDrives -= nAcsiPartitions;
! 844: nAcsiPartitions = 0;
1.1.1.11 root 845: bAcsiEmuOn = false;
1.1 root 846: }
847:
1.1.1.7 root 848:
1.1 root 849: /*---------------------------------------------------------------------*/
1.1.1.8 root 850: /**
1.1.1.14 root 851: * Reset command status.
852: */
853: void HDC_ResetCommandStatus(void)
854: {
1.1.1.16 root 855: if (ConfigureParams.System.nMachineType != MACHINE_FALCON)
856: AcsiBus.returnCode = 0;
1.1.1.14 root 857: }
858:
859:
860: /**
1.1.1.16 root 861: * Process HDC command packets (SCSI/ACSI) bytes.
1.1.1.17! root 862: * @return true if command has been executed.
1.1.1.14 root 863: */
1.1.1.17! root 864: static bool HDC_WriteCommandPacket(SCSI_CTRLR *ctr, Uint8 b)
1.1.1.14 root 865: {
1.1.1.17! root 866: bool bDidCmd = false;
1.1.1.16 root 867: SCSI_DEV *dev = &ctr->devs[ctr->target];
868:
869: /* Abort if the target device is not enabled */
870: if (!dev->enabled)
871: {
872: ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17! root 873: return false;
1.1.1.16 root 874: }
875:
876: /* Extract ACSI/SCSI opcode */
877: if (ctr->byteCount == 0)
878: {
879: ctr->opcode = b;
880: ctr->bDmaError = false;
881: }
1.1.1.14 root 882:
1.1.1.16 root 883: /* Successfully received one byte, and increase the byte-count */
884: if (ctr->byteCount < (int)sizeof(ctr->command))
885: ctr->command[ctr->byteCount] = b;
886: ++ctr->byteCount;
887:
888: /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
889: if ((ctr->opcode < 0x20 && ctr->byteCount >= 6) ||
890: (ctr->opcode < 0x60 && ctr->byteCount >= 10))
891: {
892: /* We currently only support LUN 0, however INQUIRY must
893: * always be handled, see SCSI standard */
894: if (HDC_GetLUN(ctr) == 0 || ctr->opcode == HD_INQUIRY)
895: {
896: HDC_EmulateCommandPacket(ctr);
1.1.1.17! root 897: bDidCmd = true;
1.1.1.16 root 898: }
899: else
900: {
901: Log_Printf(LOG_WARN, "HDC: Access to non-existing LUN."
902: " Command = 0x%02x\n", ctr->opcode);
903: dev->nLastError = HD_REQSENS_INVLUN;
904: /* REQUEST SENSE is still handled for invalid LUNs */
905: if (ctr->opcode == HD_REQ_SENSE)
1.1.1.17! root 906: {
1.1.1.16 root 907: HDC_Cmd_RequestSense(ctr);
1.1.1.17! root 908: bDidCmd = true;
! 909: }
1.1.1.16 root 910: else
1.1.1.17! root 911: {
1.1.1.16 root 912: ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17! root 913: }
1.1.1.16 root 914: }
915:
916: ctr->byteCount = 0;
917: }
918: else if (ctr->opcode >= 0x60)
919: {
920: /* Commands >= 0x60 are not supported right now */
921: ctr->returnCode = HD_STATUS_ERROR;
922: dev->nLastError = HD_REQSENS_OPCODE;
923: dev->bSetLastBlockAddr = false;
924: if (ctr->byteCount == 10)
925: {
926: LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s).\n",
927: HDC_CmdInfoStr(ctr));
928: }
929: }
930: else
931: {
932: ctr->returnCode = HD_STATUS_OK;
933: }
1.1.1.17! root 934:
! 935: return bDidCmd;
1.1.1.16 root 936: }
1.1.1.14 root 937:
938: /*---------------------------------------------------------------------*/
1.1.1.16 root 939:
940: static struct ncr5380_regs
941: {
942: Uint8 initiator_cmd;
943: Uint8 current_bus_status;
944: Uint8 bus_and_status;
945: } ncr_regs;
946:
1.1.1.14 root 947: /**
1.1.1.16 root 948: * Emulate external reset "pin": Clear registers etc.
1.1.1.14 root 949: */
1.1.1.16 root 950: void Ncr5380_Reset(void)
1.1.1.14 root 951: {
1.1.1.16 root 952: ncr_regs.initiator_cmd &= 0x7f;
1.1.1.14 root 953: }
954:
955: /**
1.1.1.16 root 956: * Write a command byte to the NCR 5380 SCSI controller
1.1.1.8 root 957: */
1.1.1.16 root 958: static void Ncr5380_WriteByte(int addr, Uint8 byte)
1.1 root 959: {
1.1.1.17! root 960: #if WITH_NCR5380
1.1.1.16 root 961: switch (addr)
1.1.1.14 root 962: {
1.1.1.16 root 963: case 0: /* Output Data register */
964: ncr_regs.current_bus_status |= 0x40;
965: break;
966: case 1: /* Initiator Command register */
967: ncr_regs.initiator_cmd = byte;
968: break;
969: case 2: /* Mode register */
970: break;
971: case 3: /* Target Command register */
972: break;
973: case 4: /* Select Enable register */
974: break;
975: case 5: /* Start DMA Send register */
976: break;
977: case 6: /* Start DMA Target Receive register */
978: break;
979: case 7: /* Start DMA Initiator Receive register */
980: break;
981: default:
982: fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.14 root 983: }
1.1.1.17! root 984: #endif
1.1.1.16 root 985: }
1.1.1.12 root 986:
1.1.1.16 root 987: /**
988: * Read a command byte from the NCR 5380 SCSI controller
989: */
990: static Uint8 Ncr5380_ReadByte(int addr)
991: {
1.1.1.17! root 992: #if WITH_NCR5380
1.1.1.16 root 993: switch (addr)
1.1.1.12 root 994: {
1.1.1.16 root 995: case 0: /* Current SCSI Data register */
996: break;
997: case 1: /* Initiator Command register */
998: return ncr_regs.initiator_cmd & 0x9f;
999: case 2: /* Mode register */
1000: break;
1001: case 3: /* Target Command register */
1002: break;
1003: case 4: /* Current SCSI Bus Status register */
1004: if (ncr_regs.current_bus_status & 0x40) /* BUSY? */
1005: ncr_regs.current_bus_status |= 0x20;
1006: else
1007: ncr_regs.current_bus_status &= ~0x20;
1008: if (ncr_regs.initiator_cmd & 0x80) /* ASSERT RST? */
1009: ncr_regs.current_bus_status |= 0x80;
1010: else
1011: ncr_regs.current_bus_status &= ~0x80;
1012: if (ncr_regs.initiator_cmd & 0x04) /* ASSERT BUSY? */
1013: ncr_regs.current_bus_status |= 0x40;
1014: else
1015: ncr_regs.current_bus_status &= ~0x40;
1016: return ncr_regs.current_bus_status;
1017: case 5: /* Bus and Status register */
1018: return ncr_regs.bus_and_status;
1019: case 6: /* Input Data register */
1020: break;
1021: case 7: /* Reset Parity/Interrupts register */
1022: /* Reset PARITY ERROR, IRQ REQUEST and BUSY ERROR bits */
1023: ncr_regs.bus_and_status &= 0xcb;
1024: return 0; /* TODO: Is this return value ok? */
1025: default:
1026: fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.12 root 1027: }
1.1.1.17! root 1028: #endif
1.1.1.12 root 1029:
1.1.1.16 root 1030: return 0;
1031: }
1.1.1.7 root 1032:
1.1.1.16 root 1033:
1034: static void Acsi_WriteCommandByte(int addr, Uint8 byte)
1035: {
1.1.1.17! root 1036: /* Clear IRQ initially (will be set again if byte has been accepted) */
! 1037: FDC_ClearHdcIRQ();
! 1038:
! 1039: /* When the A1 pin is pushed to 0, we want to start a new command.
! 1040: * We ignore the pin for the second byte in the packet since this
! 1041: * seems to happen on real hardware too (some buggy driver relies
! 1042: * on this behavior). */
! 1043: if ((addr & 2) == 0 && AcsiBus.byteCount != 1)
1.1.1.7 root 1044: {
1.1.1.16 root 1045: AcsiBus.byteCount = 0;
1046: AcsiBus.target = ((byte & 0xE0) >> 5);
1047: /* Only process the first byte if it is not
1048: * an extended ICD command marker byte */
1049: if ((byte & 0x1F) != 0x1F)
1.1.1.7 root 1050: {
1.1.1.16 root 1051: HDC_WriteCommandPacket(&AcsiBus, byte & 0x1F);
1.1.1.7 root 1052: }
1053: else
1054: {
1.1.1.16 root 1055: AcsiBus.returnCode = HD_STATUS_OK;
1056: AcsiBus.bDmaError = false;
1.1.1.7 root 1057: }
1.1.1.16 root 1058: }
1059: else
1060: {
1061: /* Process normal command byte */
1.1.1.17! root 1062: bool bDidCmd = HDC_WriteCommandPacket(&AcsiBus, byte);
! 1063: if (bDidCmd && AcsiBus.returnCode == HD_STATUS_OK && AcsiBus.respcnt)
! 1064: {
! 1065: /* DMA transfer necessary */
! 1066: Uint32 nDmaAddr = FDC_GetDMAAddress();
! 1067: if (!STMemory_SafeCopy(nDmaAddr, AcsiBus.resp, AcsiBus.respcnt, "ACSI DMA"))
! 1068: {
! 1069: AcsiBus.bDmaError = true;
! 1070: AcsiBus.returnCode = HD_STATUS_ERROR;
! 1071: }
! 1072: FDC_WriteDMAAddress(nDmaAddr + AcsiBus.respcnt);
! 1073: AcsiBus.respcnt = 0;
! 1074: }
1.1.1.16 root 1075: }
1.1.1.7 root 1076:
1.1.1.16 root 1077: if (AcsiBus.devs[AcsiBus.target].enabled)
1078: {
1079: FDC_SetDMAStatus(AcsiBus.bDmaError); /* Mark DMA error */
1080: FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
1.1.1.7 root 1081: }
1.1 root 1082: }
1.1.1.16 root 1083:
1084: /**
1085: * Called when command bytes have been written to $FFFF8606 and
1086: * the HDC (not the FDC) is selected.
1087: */
1088: void HDC_WriteCommandByte(int addr, Uint8 byte)
1089: {
1090: // fprintf(stderr, "HDC: Write cmd byte addr=%i, byte=%02x\n", addr, byte);
1091:
1092: if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
1093: Ncr5380_WriteByte(addr, byte);
1094: else if (bAcsiEmuOn)
1095: Acsi_WriteCommandByte(addr, byte);
1096: }
1097:
1098: /**
1099: * Get command byte.
1100: */
1101: short int HDC_ReadCommandByte(int addr)
1102: {
1103: Uint16 ret;
1104: if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
1105: ret = Ncr5380_ReadByte(addr);
1106: else
1107: ret = AcsiBus.returnCode; /* ACSI status */
1108: return ret;
1109: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.