|
|
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: int i;
1.1.1.2 ! root 279: #ifdef HDC_VERBOSE
! 280: unsigned long size;
! 281: #endif
1.1 root 282:
283: nPartitions = 0;
284: if(hd_image_file == NULL) return;
285: offset = ftell(hd_image_file);
286:
287: fseek(hd_image_file, 0x1C2, 0);
288: fread(hdinfo, 64, 1, hd_image_file);
289:
290: #ifdef HDC_VERBOSE
291: size = (((unsigned long) hdinfo[0] << 24)
292: | ((unsigned long) hdinfo[1] << 16)
293: | ((unsigned long) hdinfo[2] << 8)
294: | ((unsigned long) hdinfo[3]));
295:
296: fprintf(stderr, "Total disk size %li Mb\n", size>>11);
297: fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No");
298: fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No");
299: fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No");
300: fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No");
301: #endif
302:
303: for(i=0;i<4;i++)
304: if(hdinfo[4 + 12*i]) nPartitions++;
305:
306: fseek(hd_image_file, offset, 0);
307: }
308:
309: /*---------------------------------------------------------------------*/
310: /*
311: Open the disk image file, set partitions.
312: */
313: BOOL HDC_Init(char *filename)
314: {
315: if( (hd_image_file = fopen(filename, "r+")) == NULL)
316: return( FALSE );
317:
318: HDC_GetInfo();
319: if(!nPartitions)
320: {
321: fclose( hd_image_file );
322: hd_image_file = NULL;
323: return( FALSE );
324: }
325: /* set number of partitions */
326: ConfigureParams.HardDisc.nDriveList += nPartitions;
327:
328: return( TRUE );
329: }
330: /*---------------------------------------------------------------------*/
331: /*
332: HDC_UnInit - close image file
333:
334: */
335: void HDC_UnInit()
336: {
337: if(!(ACSI_EMU_ON)) return;
338: fclose(hd_image_file);
339: hd_image_file = NULL;
340: nPartitions = 0;
341: }
342:
343: /*---------------------------------------------------------------------*/
344: /*
345: Process HDC command packets, called when bytes are
346: written to $FFFF8606 and the HDC (not the FDC) is selected.
347: */
348: void HDC_WriteCommandPacket()
349: {
350:
351: /* check status byte */
352: if(((DMAModeControl_ff8606wr & 0x0018) != 8)) return;
353:
354: /* is HDC emulation enabled? */
355: if(!(ACSI_EMU_ON)) return;
356:
357: /* command byte sent, store it. */
358: HDCCommand.command[HDCCommand.byteCount++] = (DiscControllerWord_ff8604wr&0xFF);
359:
360: /* have we recived a complete 6-byte packet yet? */
361: if(HDCCommand.byteCount >= 6){
362:
363: #ifdef HDC_REALLY_VERBOSE
364: HDC_DebugCommandPacket(stderr);
365: #endif
366:
367: /* If it's aimed for our drive, emulate it! */
368: if((HD_CONTROLLER(HDCCommand)) == 0)
369: {
370: if(HD_DRIVENUM(HDCCommand) == 0) HDC_EmulateCommandPacket();
371: }
372: else
373: {
374: FDC_SetDMAStatus(FALSE);
375: FDC_AcknowledgeInterrupt();
376: HDCCommand.returnCode = HD_STATUS_NODRIVE;
377: FDCSectorCountRegister = 0;
378: FDC_AcknowledgeInterrupt();
379: }
380:
381: HDCCommand.byteCount = 0;
382: }
383: }
384:
385:
386:
387:
388:
389:
390:
391:
392:
393:
394:
395:
396:
397:
398:
399:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.