|
|
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
1.1.1.18 root 626: * Normal and extended partition tables are described in:
627: * http://dev-docs.atariforge.org/files/AHDI_3_RN_4-18-1990.pdf
628: * - Support partition tables with other endianness
1.1.1.8 root 629: */
1.1.1.17 root 630: int HDC_PartitionCount(FILE *fp, const Uint64 tracelevel)
1.1 root 631: {
1.1.1.17 root 632: unsigned char *pinfo, bootsector[512];
633: Uint32 start, sectors, total = 0;
634: int i, parts = 0;
635: off_t offset;
1.1 root 636:
1.1.1.17 root 637: if (!fp)
638: return 0;
639: offset = ftello(fp);
1.1.1.7 root 640:
1.1.1.17 root 641: if (fseeko(fp, 0, SEEK_SET) != 0
642: || fread(bootsector, sizeof(bootsector), 1, fp) != 1)
1.1.1.11 root 643: {
1.1.1.17 root 644: perror("HDC_PartitionCount");
645: return 0;
1.1.1.11 root 646: }
1.1 root 647:
1.1.1.17 root 648: if (bootsector[0x1FE] == 0x55 && bootsector[0x1FF] == 0xAA)
649: {
650: int ptype, boot;
1.1 root 651:
1.1.1.17 root 652: LOG_TRACE(tracelevel, "DOS MBR:\n");
653: /* first partition table entry */
654: pinfo = bootsector + 0x1BE;
655: for (i = 0; i < 4; i++, pinfo += 16)
656: {
657: boot = pinfo[0];
658: ptype = pinfo[4];
1.1.1.18 root 659: start = SDL_SwapLE32(*(long*)(pinfo+8));
660: sectors = SDL_SwapLE32(*(long*)(pinfo+12));
1.1.1.17 root 661: total += sectors;
1.1.1.18 root 662: LOG_TRACE(tracelevel, "- Partition %d: type=0x%02x, start=0x%08x, size=%.1f MB %s%s\n",
663: i, ptype, start, sectors/2048.0, boot ? "(boot)" : "", sectors ? "" : "(invalid)");
1.1.1.17 root 664: if (ptype)
665: parts++;
666: }
1.1.1.18 root 667: LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
1.1.1.17 root 668: }
669: else
670: {
671: /* Partition table contains hd size + 4 partition entries
672: * (composed of flag byte, 3 char ID, start offset
673: * and size), this is followed by bad sector list +
674: * count and the root sector checksum. Before this
675: * there's the boot code.
676: */
677: char c, pid[4];
678: int j, flags;
1.1.1.18 root 679: bool extended;
1.1.1.17 root 680:
681: LOG_TRACE(tracelevel, "ATARI MBR:\n");
682: pinfo = bootsector + 0x1C6;
683: for (i = 0; i < 4; i++, pinfo += 12)
684: {
685: flags = pinfo[0];
686: for (j = 0; j < 3; j++)
687: {
688: c = pinfo[j+1];
689: if (c < 32 || c >= 127)
690: c = '.';
691: pid[j] = c;
692: }
693: pid[3] = '\0';
1.1.1.18 root 694: extended = strcmp("XGM", pid) == 0;
1.1.1.17 root 695: start = HDC_ReadInt32(pinfo, 4);
696: sectors = HDC_ReadInt32(pinfo, 8);
1.1.1.18 root 697: LOG_TRACE(tracelevel,
698: "- Partition %d: ID=%s, start=0x%08x, size=%.1f MB, flags=0x%x %s%s\n",
699: i, pid, start, sectors/2048.0, flags,
700: (flags & 0x80) ? "(boot)": "",
701: extended ? "(extended)" : "");
1.1.1.17 root 702: if (flags & 0x1)
703: parts++;
704: }
705: total = HDC_ReadInt32(bootsector, 0x1C2);
1.1.1.18 root 706: LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
1.1.1.17 root 707: }
1.1 root 708:
1.1.1.17 root 709: if (fseeko(fp, offset, SEEK_SET) != 0)
710: perror("HDC_PartitionCount");
711: return parts;
1.1 root 712: }
713:
1.1.1.17 root 714: /**
1.1.1.18 root 715: * Check file size for sane values (non-zero, multiple of 512),
716: * and return the size
1.1.1.17 root 717: */
1.1.1.18 root 718: off_t HDC_CheckAndGetSize(const char *filename)
1.1.1.17 root 719: {
720: off_t filesize;
1.1.1.18 root 721: char shortname[48];
1.1.1.17 root 722:
1.1.1.19! root 723: File_ShrinkName(shortname, filename, sizeof(shortname) - 1);
1.1.1.17 root 724:
725: filesize = File_Length(filename);
726: if (filesize < 0)
727: {
1.1.1.18 root 728: Log_AlertDlg(LOG_ERROR, "Unable to get size of HD image file\n'%s'!",
729: shortname);
730: if (sizeof(off_t) < 8)
731: {
732: Log_Printf(LOG_ERROR, "Note: This version of Hatari has been built"
733: " _without_ support for large files,\n"
734: " so you can not use HD images > 2 GB.\n");
735: }
736: return -EFBIG;
737: }
738: if (filesize == 0)
739: {
740: Log_AlertDlg(LOG_ERROR, "Can not use HD image file\n'%s'\n"
741: "since the file is empty.",
742: shortname);
1.1.1.17 root 743: return -EINVAL;
744: }
1.1.1.18 root 745: if ((filesize & 0x1ff) != 0)
1.1.1.17 root 746: {
1.1.1.18 root 747: Log_AlertDlg(LOG_ERROR, "Can not use the hard disk image file\n"
748: "'%s'\nsince its size is not a multiple"
749: " of 512.",
750: shortname);
1.1.1.17 root 751: return -EINVAL;
752: }
753:
1.1.1.18 root 754: return filesize;
755: }
756:
757: /**
758: * Open a disk image file
759: */
760: static int HDC_InitDevice(SCSI_DEV *dev, char *filename)
761: {
762: off_t filesize;
763: FILE *fp;
764:
765: dev->enabled = false;
766: Log_Printf(LOG_INFO, "Mounting hard drive image '%s'\n", filename);
767:
768: /* Check size for sanity */
769: filesize = HDC_CheckAndGetSize(filename);
770: if (filesize < 0)
771: return filesize;
772:
1.1.1.17 root 773: fp = fopen(filename, "rb+");
774: if (fp == NULL)
775: {
776: Log_Printf(LOG_ERROR, "ERROR: cannot open HD file read/write!\n");
777: return -ENOENT;
778: }
779: if (!File_Lock(fp))
780: {
781: Log_Printf(LOG_ERROR, "ERROR: cannot lock HD file for writing!\n");
782: fclose(fp);
783: return -ENOLCK;
784: }
785:
786: dev->hdSize = filesize / 512;
787: dev->image_file = fp;
788: dev->enabled = true;
789:
790: return 0;
791: }
1.1.1.7 root 792:
1.1.1.8 root 793: /**
794: * Open the disk image file, set partitions.
1.1 root 795: */
1.1.1.12 root 796: bool HDC_Init(void)
1.1 root 797: {
1.1.1.16 root 798: int i;
1.1 root 799:
1.1.1.17 root 800: /* ACSI */
801: nAcsiPartitions = 0;
1.1.1.16 root 802: bAcsiEmuOn = false;
1.1.1.17 root 803: memset(&AcsiBus, 0, sizeof(AcsiBus));
804: AcsiBus.respbufsize = 512;
805: AcsiBus.resp = malloc(AcsiBus.respbufsize);
806: if (!AcsiBus.resp)
807: {
808: perror("HDC_Init");
809: return false;
810: }
1.1.1.16 root 811: for (i = 0; i < MAX_ACSI_DEVS; i++)
1.1.1.7 root 812: {
1.1.1.16 root 813: if (!ConfigureParams.Acsi[i].bUseDevice)
814: continue;
1.1.1.17 root 815: if (HDC_InitDevice(&AcsiBus.devs[i], ConfigureParams.Acsi[i].sDeviceFile) == 0)
1.1.1.16 root 816: {
1.1.1.17 root 817: bAcsiEmuOn = true;
818: nAcsiPartitions += HDC_PartitionCount(AcsiBus.devs[i].image_file, TRACE_SCSI_CMD);
1.1.1.16 root 819: }
1.1.1.17 root 820: }
1.1.1.16 root 821:
1.1.1.17 root 822: /* SCSI */
823: #if WITH_NCR5380
824: memset(&ScsiBus, 0, sizeof(ScsiBus));
825: ScsiBus.respbufsize = 512;
826: ScsiBus.resp = malloc(ScsiBus.respbufsize);
827: if (!ScsiBus.resp)
828: {
829: perror("HDC_Init");
830: return bAcsiEmuOn;
831: }
832: for (i = 0; i < MAX_SCSI_DEVS; i++)
833: {
834: if (!ConfigureParams.Scsi[i].bUseDevice)
1.1.1.16 root 835: continue;
1.1.1.17 root 836: HDC_InitDevice(&ScsiBus.devs[i], ConfigureParams.Scsi[i].sDeviceFile);
1.1.1.16 root 837: }
1.1.1.17 root 838: #endif
1.1.1.7 root 839:
840: /* set number of partitions */
1.1.1.17 root 841: nNumDrives += nAcsiPartitions;
1.1.1.7 root 842:
1.1.1.16 root 843: return bAcsiEmuOn;
1.1 root 844: }
1.1.1.3 root 845:
1.1.1.7 root 846:
1.1 root 847: /*---------------------------------------------------------------------*/
1.1.1.8 root 848: /**
849: * HDC_UnInit - close image file
850: *
1.1 root 851: */
1.1.1.4 root 852: void HDC_UnInit(void)
1.1 root 853: {
1.1.1.16 root 854: int i;
855:
1.1.1.18 root 856: for (i = 0; bAcsiEmuOn && i < MAX_ACSI_DEVS; i++)
1.1.1.16 root 857: {
858: if (!AcsiBus.devs[i].enabled)
859: continue;
1.1.1.17 root 860: File_UnLock(AcsiBus.devs[i].image_file);
1.1.1.16 root 861: fclose(AcsiBus.devs[i].image_file);
862: AcsiBus.devs[i].image_file = NULL;
863: AcsiBus.devs[i].enabled = false;
864: }
1.1.1.17 root 865: free(AcsiBus.resp);
866: AcsiBus.resp = NULL;
1.1.1.7 root 867:
1.1.1.17 root 868: #if WITH_NCR5380
869: for (i = 0; i < MAX_SCSI_DEVS; i++)
870: {
871: if (!ScsiBus.devs[i].enabled)
872: continue;
873: File_UnLock(ScsiBus.devs[i].image_file);
874: fclose(ScsiBus.devs[i].image_file);
875: ScsiBus.devs[i].image_file = NULL;
876: ScsiBus.devs[i].enabled = false;
877: }
878: free(ScsiBus.resp);
879: ScsiBus.resp = NULL;
880: #endif
881:
1.1.1.18 root 882: if (bAcsiEmuOn)
883: nNumDrives -= nAcsiPartitions;
1.1.1.17 root 884: nAcsiPartitions = 0;
1.1.1.11 root 885: bAcsiEmuOn = false;
1.1 root 886: }
887:
1.1.1.7 root 888:
1.1 root 889: /*---------------------------------------------------------------------*/
1.1.1.8 root 890: /**
1.1.1.14 root 891: * Reset command status.
892: */
893: void HDC_ResetCommandStatus(void)
894: {
1.1.1.18 root 895: if (!Config_IsMachineFalcon())
1.1.1.16 root 896: AcsiBus.returnCode = 0;
1.1.1.14 root 897: }
898:
899:
900: /**
1.1.1.16 root 901: * Process HDC command packets (SCSI/ACSI) bytes.
1.1.1.17 root 902: * @return true if command has been executed.
1.1.1.14 root 903: */
1.1.1.17 root 904: static bool HDC_WriteCommandPacket(SCSI_CTRLR *ctr, Uint8 b)
1.1.1.14 root 905: {
1.1.1.17 root 906: bool bDidCmd = false;
1.1.1.16 root 907: SCSI_DEV *dev = &ctr->devs[ctr->target];
908:
909: /* Abort if the target device is not enabled */
910: if (!dev->enabled)
911: {
912: ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17 root 913: return false;
1.1.1.16 root 914: }
915:
916: /* Extract ACSI/SCSI opcode */
917: if (ctr->byteCount == 0)
918: {
919: ctr->opcode = b;
920: ctr->bDmaError = false;
921: }
1.1.1.14 root 922:
1.1.1.16 root 923: /* Successfully received one byte, and increase the byte-count */
924: if (ctr->byteCount < (int)sizeof(ctr->command))
925: ctr->command[ctr->byteCount] = b;
926: ++ctr->byteCount;
927:
928: /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
929: if ((ctr->opcode < 0x20 && ctr->byteCount >= 6) ||
930: (ctr->opcode < 0x60 && ctr->byteCount >= 10))
931: {
932: /* We currently only support LUN 0, however INQUIRY must
933: * always be handled, see SCSI standard */
934: if (HDC_GetLUN(ctr) == 0 || ctr->opcode == HD_INQUIRY)
935: {
936: HDC_EmulateCommandPacket(ctr);
1.1.1.17 root 937: bDidCmd = true;
1.1.1.16 root 938: }
939: else
940: {
941: Log_Printf(LOG_WARN, "HDC: Access to non-existing LUN."
942: " Command = 0x%02x\n", ctr->opcode);
943: dev->nLastError = HD_REQSENS_INVLUN;
944: /* REQUEST SENSE is still handled for invalid LUNs */
945: if (ctr->opcode == HD_REQ_SENSE)
1.1.1.17 root 946: {
1.1.1.16 root 947: HDC_Cmd_RequestSense(ctr);
1.1.1.17 root 948: bDidCmd = true;
949: }
1.1.1.16 root 950: else
1.1.1.17 root 951: {
1.1.1.16 root 952: ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17 root 953: }
1.1.1.16 root 954: }
955:
956: ctr->byteCount = 0;
957: }
958: else if (ctr->opcode >= 0x60)
959: {
960: /* Commands >= 0x60 are not supported right now */
961: ctr->returnCode = HD_STATUS_ERROR;
962: dev->nLastError = HD_REQSENS_OPCODE;
963: dev->bSetLastBlockAddr = false;
964: if (ctr->byteCount == 10)
965: {
966: LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s).\n",
967: HDC_CmdInfoStr(ctr));
968: }
969: }
970: else
971: {
972: ctr->returnCode = HD_STATUS_OK;
973: }
1.1.1.17 root 974:
975: return bDidCmd;
1.1.1.16 root 976: }
1.1.1.14 root 977:
978: /*---------------------------------------------------------------------*/
1.1.1.16 root 979:
980: static struct ncr5380_regs
981: {
982: Uint8 initiator_cmd;
983: Uint8 current_bus_status;
984: Uint8 bus_and_status;
985: } ncr_regs;
986:
1.1.1.14 root 987: /**
1.1.1.16 root 988: * Emulate external reset "pin": Clear registers etc.
1.1.1.14 root 989: */
1.1.1.16 root 990: void Ncr5380_Reset(void)
1.1.1.14 root 991: {
1.1.1.16 root 992: ncr_regs.initiator_cmd &= 0x7f;
1.1.1.14 root 993: }
994:
995: /**
1.1.1.16 root 996: * Write a command byte to the NCR 5380 SCSI controller
1.1.1.8 root 997: */
1.1.1.16 root 998: static void Ncr5380_WriteByte(int addr, Uint8 byte)
1.1 root 999: {
1.1.1.17 root 1000: #if WITH_NCR5380
1.1.1.16 root 1001: switch (addr)
1.1.1.14 root 1002: {
1.1.1.16 root 1003: case 0: /* Output Data register */
1004: ncr_regs.current_bus_status |= 0x40;
1005: break;
1006: case 1: /* Initiator Command register */
1007: ncr_regs.initiator_cmd = byte;
1008: break;
1009: case 2: /* Mode register */
1010: break;
1011: case 3: /* Target Command register */
1012: break;
1013: case 4: /* Select Enable register */
1014: break;
1015: case 5: /* Start DMA Send register */
1016: break;
1017: case 6: /* Start DMA Target Receive register */
1018: break;
1019: case 7: /* Start DMA Initiator Receive register */
1020: break;
1021: default:
1022: fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.14 root 1023: }
1.1.1.17 root 1024: #endif
1.1.1.16 root 1025: }
1.1.1.12 root 1026:
1.1.1.16 root 1027: /**
1028: * Read a command byte from the NCR 5380 SCSI controller
1029: */
1030: static Uint8 Ncr5380_ReadByte(int addr)
1031: {
1.1.1.17 root 1032: #if WITH_NCR5380
1.1.1.16 root 1033: switch (addr)
1.1.1.12 root 1034: {
1.1.1.16 root 1035: case 0: /* Current SCSI Data register */
1036: break;
1037: case 1: /* Initiator Command register */
1038: return ncr_regs.initiator_cmd & 0x9f;
1039: case 2: /* Mode register */
1040: break;
1041: case 3: /* Target Command register */
1042: break;
1043: case 4: /* Current SCSI Bus Status register */
1044: if (ncr_regs.current_bus_status & 0x40) /* BUSY? */
1045: ncr_regs.current_bus_status |= 0x20;
1046: else
1047: ncr_regs.current_bus_status &= ~0x20;
1048: if (ncr_regs.initiator_cmd & 0x80) /* ASSERT RST? */
1049: ncr_regs.current_bus_status |= 0x80;
1050: else
1051: ncr_regs.current_bus_status &= ~0x80;
1052: if (ncr_regs.initiator_cmd & 0x04) /* ASSERT BUSY? */
1053: ncr_regs.current_bus_status |= 0x40;
1054: else
1055: ncr_regs.current_bus_status &= ~0x40;
1056: return ncr_regs.current_bus_status;
1057: case 5: /* Bus and Status register */
1058: return ncr_regs.bus_and_status;
1059: case 6: /* Input Data register */
1060: break;
1061: case 7: /* Reset Parity/Interrupts register */
1062: /* Reset PARITY ERROR, IRQ REQUEST and BUSY ERROR bits */
1063: ncr_regs.bus_and_status &= 0xcb;
1064: return 0; /* TODO: Is this return value ok? */
1065: default:
1066: fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.12 root 1067: }
1.1.1.17 root 1068: #endif
1.1.1.12 root 1069:
1.1.1.16 root 1070: return 0;
1071: }
1.1.1.7 root 1072:
1.1.1.16 root 1073:
1074: static void Acsi_WriteCommandByte(int addr, Uint8 byte)
1075: {
1.1.1.17 root 1076: /* Clear IRQ initially (will be set again if byte has been accepted) */
1077: FDC_ClearHdcIRQ();
1078:
1079: /* When the A1 pin is pushed to 0, we want to start a new command.
1080: * We ignore the pin for the second byte in the packet since this
1081: * seems to happen on real hardware too (some buggy driver relies
1082: * on this behavior). */
1083: if ((addr & 2) == 0 && AcsiBus.byteCount != 1)
1.1.1.7 root 1084: {
1.1.1.16 root 1085: AcsiBus.byteCount = 0;
1086: AcsiBus.target = ((byte & 0xE0) >> 5);
1087: /* Only process the first byte if it is not
1088: * an extended ICD command marker byte */
1089: if ((byte & 0x1F) != 0x1F)
1.1.1.7 root 1090: {
1.1.1.16 root 1091: HDC_WriteCommandPacket(&AcsiBus, byte & 0x1F);
1.1.1.7 root 1092: }
1093: else
1094: {
1.1.1.16 root 1095: AcsiBus.returnCode = HD_STATUS_OK;
1096: AcsiBus.bDmaError = false;
1.1.1.7 root 1097: }
1.1.1.16 root 1098: }
1099: else
1100: {
1101: /* Process normal command byte */
1.1.1.17 root 1102: bool bDidCmd = HDC_WriteCommandPacket(&AcsiBus, byte);
1103: if (bDidCmd && AcsiBus.returnCode == HD_STATUS_OK && AcsiBus.respcnt)
1104: {
1105: /* DMA transfer necessary */
1106: Uint32 nDmaAddr = FDC_GetDMAAddress();
1107: if (!STMemory_SafeCopy(nDmaAddr, AcsiBus.resp, AcsiBus.respcnt, "ACSI DMA"))
1108: {
1109: AcsiBus.bDmaError = true;
1110: AcsiBus.returnCode = HD_STATUS_ERROR;
1111: }
1112: FDC_WriteDMAAddress(nDmaAddr + AcsiBus.respcnt);
1113: AcsiBus.respcnt = 0;
1114: }
1.1.1.16 root 1115: }
1.1.1.7 root 1116:
1.1.1.16 root 1117: if (AcsiBus.devs[AcsiBus.target].enabled)
1118: {
1119: FDC_SetDMAStatus(AcsiBus.bDmaError); /* Mark DMA error */
1120: FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
1.1.1.7 root 1121: }
1.1 root 1122: }
1.1.1.16 root 1123:
1124: /**
1125: * Called when command bytes have been written to $FFFF8606 and
1126: * the HDC (not the FDC) is selected.
1127: */
1128: void HDC_WriteCommandByte(int addr, Uint8 byte)
1129: {
1130: // fprintf(stderr, "HDC: Write cmd byte addr=%i, byte=%02x\n", addr, byte);
1131:
1.1.1.18 root 1132: if (Config_IsMachineFalcon())
1.1.1.16 root 1133: Ncr5380_WriteByte(addr, byte);
1134: else if (bAcsiEmuOn)
1135: Acsi_WriteCommandByte(addr, byte);
1136: }
1137:
1138: /**
1139: * Get command byte.
1140: */
1141: short int HDC_ReadCommandByte(int addr)
1142: {
1143: Uint16 ret;
1.1.1.18 root 1144: if (Config_IsMachineFalcon())
1.1.1.16 root 1145: ret = Ncr5380_ReadByte(addr);
1146: else
1147: ret = AcsiBus.returnCode; /* ACSI status */
1148: return ret;
1149: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.