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