|
|
1.1 root 1: /*
1.1.1.3 root 2: Hatari - hdc.c
1.1 root 3:
1.1.1.3 root 4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
1.1 root 6:
1.1.1.3 root 7: Low-level hard drive emulation
1.1 root 8: */
1.1.1.6 ! root 9: char HDC_rcsid[] = "Hatari $Id: hdc.c,v 1.9 2005/10/04 15:31:52 thothy Exp $";
1.1 root 10:
11: #include "main.h"
1.1.1.3 root 12: #include "configuration.h"
1.1.1.6 ! root 13: #include "debugui.h"
1.1 root 14: #include "fdc.h"
15: #include "hdc.h"
16: #include "memorySnapShot.h"
17: #include "mfp.h"
18: #include "stMemory.h"
1.1.1.6 ! root 19: #include "tos.h"
1.1 root 20:
21: /*
22: ACSI emulation:
23: ACSI commands are six byte-packets sent to the
24: hard drive controller (which is on the HD unit, not in the ST)
25:
26: While the hard drive is busy, DRQ is high, polling the DRQ during
27: operation interrupts the current operation. The DRQ status can
28: be polled non-destructively in GPIP.
29:
30: (For simplicity, the operation is finished immediatly,
31: this is a potential bug, but I doubt it is significant,
32: we just appear to have a very fast hard drive.)
33:
34: The ACSI command set is a subset of the SCSI standard.
35: (for details, see the X3T9.2 SCSI draft documents
36: from 1985, for an example of writing ACSI commands,
37: see the TOS DMA boot code)
38: */
39:
40: /* #define DISALLOW_HDC_WRITE */
41: /* #define HDC_VERBOSE */ /* display operations */
42: /* #define HDC_REALLY_VERBOSE */ /* display command packets */
43:
44: /* HDC globals */
45: HDCOMMAND HDCCommand;
46: FILE *hd_image_file = NULL;
47: int nPartitions = 0;
48: short int HDCSectorCount;
49:
50: /*
1.1.1.4 root 51: FDC registers used:
52: - FDCSectorCountRegister
1.1.1.6 ! root 53: - DiskControllerStatus_ff8604rd
1.1.1.4 root 54: - DMAModeControl_ff8606wr
1.1 root 55: */
56:
57:
58: /* Our dummy INQUIRY response data */
1.1.1.4 root 59: static unsigned char inquiry_bytes[] =
1.1 root 60: {
61: 0, /* device type 0 = direct access device */
62: 0, /* device type qualifier (nonremovable) */
63: 1, /* ANSI version */
64: 0, /* reserved */
65: 26, /* length of the following data */
66: ' ', ' ', ' ', /* Vendor specific data */
67: 'H','a','t','a','r','i',' ','E', /* Vendor */
68: 'm','u','l','a','t','e','d',' ', /* Model */
69: ' ',' ',' ',' ', /* Revision */
70: 0,0,0,0,0,0,0,0,0,0 /* ?? */
71: };
72:
73: /*---------------------------------------------------------------------*/
74: /*
75: Return the file offset of the sector specified in the current
76: ACSI command block.
77: */
1.1.1.4 root 78: static unsigned long HDC_GetOffset(void)
79: {
1.1 root 80: unsigned long offset;
81:
82: /* construct the logical block adress */
83: offset = ((HD_LBA_MSB(HDCCommand) << 16)
84: | (HD_LBA_MID(HDCCommand) << 8)
85: | (HD_LBA_LSB(HDCCommand))) ;
86:
87: /* return value in bytes */
88: return(offset * 512);
89: }
90:
91: /*---------------------------------------------------------------------*/
92: /*
93: Seek - move to a sector
94: */
1.1.1.4 root 95: static void HDC_Seek(void)
1.1 root 96: {
97:
98: fseek(hd_image_file, HDC_GetOffset(),0);
99:
100: FDC_SetDMAStatus(FALSE); /* no DMA error */
101: FDC_AcknowledgeInterrupt();
102: HDCCommand.returnCode = HD_STATUS_OK;
103: FDCSectorCountRegister = 0;
104: }
105:
106: /*---------------------------------------------------------------------*/
107: /*
108: Inquiry - return some disk information
109: */
1.1.1.4 root 110: static void HDC_Inquiry(void)
1.1 root 111: {
112: inquiry_bytes[4] = HD_SECTORCOUNT(HDCCommand) - 8;
113: memcpy( (char *)((unsigned long)STRam+FDC_ReadDMAAddress()), inquiry_bytes,
114: HD_SECTORCOUNT(HDCCommand));
115:
116: FDC_SetDMAStatus(FALSE); /* no DMA error */
117: FDC_AcknowledgeInterrupt();
118: HDCCommand.returnCode = HD_STATUS_OK;
119: FDCSectorCountRegister = 0;
120: }
121:
122: /*---------------------------------------------------------------------*/
123: /*
124: Write a sector off our disk - (seek implied)
125: */
1.1.1.4 root 126: static void HDC_WriteSector(void)
1.1 root 127: {
128: /* seek to the position */
129: fseek(hd_image_file, HDC_GetOffset(),0);
130:
131: /* write -if allowed */
132: #ifndef DISALLOW_HDC_WRITE
133: fwrite((char *)((unsigned long)STRam+FDC_ReadDMAAddress()),
134: 512*HD_SECTORCOUNT(HDCCommand), 1, hd_image_file);
135: #endif
136:
137: FDC_SetDMAStatus(FALSE); /* no DMA error */
138: FDC_AcknowledgeInterrupt();
139: HDCCommand.returnCode = HD_STATUS_OK;
140: FDCSectorCountRegister = 0;
141: }
142:
143: /*---------------------------------------------------------------------*/
144: /*
145: Read a sector off our disk - (implied seek)
146: */
1.1.1.4 root 147: static void HDC_ReadSector(void)
1.1 root 148: {
149: /* seek to the position */
150: fseek(hd_image_file, HDC_GetOffset(),0);
151:
152: #ifdef HDC_VERBOSE
153: fprintf(stderr,"Reading %i sectors from 0x%lx to addr:%lx\n", HD_SECTORCOUNT(HDCCommand), HDC_GetOffset() ,FDC_ReadDMAAddress());
154: #endif
155:
156: fread((char *)((unsigned long)STRam+FDC_ReadDMAAddress()),
157: 512*HD_SECTORCOUNT(HDCCommand), 1, hd_image_file);
158:
159: FDC_SetDMAStatus(FALSE); /* no DMA error */
160: FDC_AcknowledgeInterrupt();
161: HDCCommand.returnCode = HD_STATUS_OK;
162: FDCSectorCountRegister = 0;
163: }
164:
165: /*---------------------------------------------------------------------*/
166: /*
167: Emulation routine for HDC command packets.
168: */
169: void HDC_EmulateCommandPacket()
170: {
171:
172: switch(HD_OPCODE(HDCCommand)){
173:
174: case HD_READ_SECTOR:
175: HDC_ReadSector();
176: break;
177: case HD_WRITE_SECTOR:
178: HDC_WriteSector();
179: break;
180:
181: case HD_INQUIRY:
182: #ifdef HDC_VERBOSE
183: fprintf(stderr,"Inquiry made.\n");
184: #endif
185: HDC_Inquiry();
186: break;
187:
188: case HD_SEEK:
189: HDC_Seek();
190: break;
191:
192: case HD_SHIP:
193: HDCCommand.returnCode = 0xFF;
194: FDC_AcknowledgeInterrupt();
195: break;
196:
197: /* as of yet unsupported commands */
198: case HD_VERIFY_TRACK:
199: case HD_FORMAT_TRACK:
200: case HD_CORRECTION:
201: case HD_MODESENSE:
202: case HD_REQ_SENSE:
203:
204: default:
205: HDCCommand.returnCode = HD_STATUS_OPCODE;
206: FDC_AcknowledgeInterrupt();
207: break;
208: }
209: }
210:
211: /*---------------------------------------------------------------------*/
212: /*
213: Debug routine for HDC command packets.
214: */
215: void HDC_DebugCommandPacket(FILE *hdlogFile)
216: {
217: switch(HD_OPCODE(HDCCommand)){
218: case HD_VERIFY_TRACK:
219: fprintf(hdlogFile, "OpCode: VERIFY TRACK\n");
220: break;
221: case HD_FORMAT_TRACK:
222: fprintf(hdlogFile, "OpCode: FORMAT TRACK\n");
223: break;
224: case HD_READ_SECTOR:
225: fprintf(hdlogFile, "OpCode: READ SECTOR(S)\n");
226: break;
227: case HD_WRITE_SECTOR:
228: fprintf(hdlogFile, "OpCode: WRITE SECTOR(S)\n");
229: break;
230: case HD_INQUIRY:
231: fprintf(hdlogFile, "OpCode: INQUIRY\n");
232: break;
233: case HD_SEEK:
234: fprintf(hdlogFile, "OpCode: SEEK\n");
235: break;
236: case HD_CORRECTION:
237: fprintf(hdlogFile, "OpCode: CORRECTION\n");
238: break;
239: case HD_MODESENSE:
240: fprintf(hdlogFile, "OpCode: MODESENSE\n");
241: break;
242:
243: case HD_SHIP:
244: fprintf(hdlogFile, "OpCode: SHIP\n");
245: break;
246:
247: case HD_REQ_SENSE:
248: fprintf(hdlogFile, "OpCode: MODESENSE\n");
249: break;
250:
251: default:
252: fprintf(hdlogFile, "Unknown OpCode!! Value = %x\n", HD_OPCODE(HDCCommand));
253: break;
254: }
255: fprintf(hdlogFile, "Controller: %i\n", HD_CONTROLLER(HDCCommand));
256: fprintf(hdlogFile, "Drive: %i\n", HD_DRIVENUM(HDCCommand));
257: fprintf(hdlogFile, "LBA: %lx\n", HDC_GetOffset());
258:
259: fprintf(hdlogFile, "Sector count: %x\n", HD_SECTORCOUNT(HDCCommand));
260: fprintf(hdlogFile, "HDC sector count: %x\n", HDCSectorCount);
261: fprintf(hdlogFile, "FDC sector count: %x\n", FDCSectorCountRegister);
262: fprintf(hdlogFile, "Control byte: %x\n", HD_CONTROL(HDCCommand));
263: }
264:
265: /*---------------------------------------------------------------------*/
266: /*
267: Print data about the hard drive image
268: */
1.1.1.4 root 269: static void HDC_GetInfo(void)
1.1 root 270: {
271: long offset;
272: unsigned char hdinfo[64];
273: int i;
1.1.1.2 root 274: #ifdef HDC_VERBOSE
275: unsigned long size;
276: #endif
1.1 root 277:
278: nPartitions = 0;
279: if(hd_image_file == NULL) return;
280: offset = ftell(hd_image_file);
281:
282: fseek(hd_image_file, 0x1C2, 0);
283: fread(hdinfo, 64, 1, hd_image_file);
284:
285: #ifdef HDC_VERBOSE
286: size = (((unsigned long) hdinfo[0] << 24)
287: | ((unsigned long) hdinfo[1] << 16)
288: | ((unsigned long) hdinfo[2] << 8)
289: | ((unsigned long) hdinfo[3]));
290:
291: fprintf(stderr, "Total disk size %li Mb\n", size>>11);
292: fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No");
293: fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No");
294: fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No");
295: fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No");
296: #endif
297:
298: for(i=0;i<4;i++)
299: if(hdinfo[4 + 12*i]) nPartitions++;
300:
301: fseek(hd_image_file, offset, 0);
302: }
303:
304: /*---------------------------------------------------------------------*/
305: /*
306: Open the disk image file, set partitions.
307: */
308: BOOL HDC_Init(char *filename)
309: {
310: if( (hd_image_file = fopen(filename, "r+")) == NULL)
1.1.1.6 ! root 311: return FALSE;
1.1 root 312:
313: HDC_GetInfo();
314: if(!nPartitions)
315: {
316: fclose( hd_image_file );
317: hd_image_file = NULL;
1.1.1.6 ! root 318: ConfigureParams.HardDisk.bUseHardDiskImage = FALSE;
! 319: return FALSE;
1.1 root 320: }
321: /* set number of partitions */
1.1.1.6 ! root 322: nNumDrives += nPartitions;
1.1.1.3 root 323:
1.1.1.6 ! root 324: return TRUE;
1.1 root 325: }
1.1.1.3 root 326:
1.1 root 327: /*---------------------------------------------------------------------*/
328: /*
329: HDC_UnInit - close image file
330:
331: */
1.1.1.4 root 332: void HDC_UnInit(void)
1.1 root 333: {
334: if(!(ACSI_EMU_ON)) return;
335: fclose(hd_image_file);
336: hd_image_file = NULL;
1.1.1.6 ! root 337: nNumDrives -= nPartitions;
1.1 root 338: nPartitions = 0;
339: }
340:
341: /*---------------------------------------------------------------------*/
342: /*
343: Process HDC command packets, called when bytes are
344: written to $FFFF8606 and the HDC (not the FDC) is selected.
345: */
1.1.1.4 root 346: void HDC_WriteCommandPacket(void)
1.1 root 347: {
348:
349: /* check status byte */
350: if(((DMAModeControl_ff8606wr & 0x0018) != 8)) return;
351:
352: /* is HDC emulation enabled? */
353: if(!(ACSI_EMU_ON)) return;
354:
355: /* command byte sent, store it. */
1.1.1.6 ! root 356: HDCCommand.command[HDCCommand.byteCount++] = (DiskControllerWord_ff8604wr&0xFF);
1.1 root 357:
358: /* have we recived a complete 6-byte packet yet? */
359: if(HDCCommand.byteCount >= 6){
360:
361: #ifdef HDC_REALLY_VERBOSE
362: HDC_DebugCommandPacket(stderr);
363: #endif
364:
365: /* If it's aimed for our drive, emulate it! */
366: if((HD_CONTROLLER(HDCCommand)) == 0)
367: {
368: if(HD_DRIVENUM(HDCCommand) == 0) HDC_EmulateCommandPacket();
369: }
370: else
371: {
372: FDC_SetDMAStatus(FALSE);
373: FDC_AcknowledgeInterrupt();
374: HDCCommand.returnCode = HD_STATUS_NODRIVE;
375: FDCSectorCountRegister = 0;
376: FDC_AcknowledgeInterrupt();
377: }
378:
379: HDCCommand.byteCount = 0;
380: }
381: }
382:
383:
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.