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