|
|
1.1 root 1: /* SCSI Bus and Disk emulation */
2: #include "main.h"
3: #include "ioMem.h"
4: #include "ioMemTables.h"
5: #include "video.h"
6: #include "configuration.h"
7: #include "sysdeps.h"
8: #include "m68000.h"
9: #include "sysReg.h"
10: #include "statusbar.h"
11: #include "scsi.h"
12: #include "dma.h"
13: #include "esp.h"
14: #include "dialog.h"
15: #include "file.h"
16:
17:
18: #define COMMAND_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1])
19: #define COMMAND_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2])
20: #define COMMAND_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3])
21:
22:
23: #define BLOCKSIZE 512
24:
25: #define LUN_DISC 0 // for now only LUN 0 is valid for our phys drives
26:
27: static Uint32 nLastBlockAddr;
28: static bool bSetLastBlockAddr;
29: static Uint8 nLastError;
30:
31: /* Disk Infos */
32:
33: bool bCDROM;
34: bool bTargetDevice;
35: Uint32 nDiskSize;
36:
37:
38: static FILE *scsidisk = NULL;
39:
40: FILE* scsiimage[ESP_MAX_DEVS];
41: Uint32 nFileSize[ESP_MAX_DEVS];
42:
43:
44: /* Initialize/Uninitialize SCSI disks */
45: void SCSI_Init(void) {
46: Log_Printf(LOG_WARN, "CALL SCSI INIT\n");
47:
48: /* Check if files exist. Present dialog to re-select missing files. */
49: int target;
50: for (target = 0; target < ESP_MAX_DEVS; target++) {
51: if (File_Exists(ConfigureParams.SCSI.target[target].szImageName) && ConfigureParams.SCSI.target[target].bAttached) {
52: nFileSize[target] = File_Length(ConfigureParams.SCSI.target[target].szImageName);
53: scsiimage[target] = ConfigureParams.SCSI.target[target].bCDROM == true ? File_Open(ConfigureParams.SCSI.target[target].szImageName, "r") : File_Open(ConfigureParams.SCSI.target[target].szImageName, "r+");
54: } else {
55: nFileSize[target] = 0;
56: scsiimage[target]=NULL;
57: }
58: }
59:
60: for (target = 0; target < ESP_MAX_DEVS; target++) {
61: Log_Printf(LOG_WARN, "Disk0: %s\n", ConfigureParams.SCSI.target[target].szImageName);
62: }
63: }
64:
65: void SCSI_Uninit(void) {
66: int target;
67: for (target = 0; target < ESP_MAX_DEVS; target++) {
68: if (scsiimage[target])
69: File_Close(scsiimage[target]);
70: }
71:
72: scsidisk = NULL;
73: }
74:
75: void SCSI_Reset(void) {
76: SCSI_Uninit();
77: SCSI_Init();
78: }
79:
80:
81:
82: /* INQUIRY response data */
83: static unsigned char inquiry_bytes[] =
84: {
85: 0x00, /* 0: device type: 0x00 = direct access device, 0x05 = cd-rom, 0x07 = mo-disk */
86: 0x00, /* 1: &0x7F - device type qulifier 0x00 unsupported, &0x80 - rmb: 0x00 = nonremovable, 0x80 = removable */
87: 0x01, /* 2: ANSI SCSI standard (first release) compliant */
88: 0x02, /* 3: Restponse format (format of following data): 0x01 SCSI-1 compliant */
89: 0x31, /* 4: additional length of the following data */
90: 0x00, 0x00, /* 5,6: reserved */
91: 0x1C, /* 7: RelAdr=0, Wbus32=0, Wbus16=0, Sync=1, Linked=1, RSVD=1, CmdQue=0, SftRe=0 */
92: 'P','r','e','v','i','o','u','s', /* 8-15: Vendor ASCII */
93: 'H','D','D',' ',' ',' ',' ',' ', /* 16-23: Model ASCII */
94: ' ',' ',' ',' ',' ',' ',' ',' ', /* 24-31: Blank space ASCII */
95: '0','0','0','0','0','0','0','1', /* 32-39: Revision ASCII */
96: '0','0','0','0','0','0','0','0', /* 40-47: Serial Number ASCII */
97: ' ',' ',' ',' ',' ',' ' /* 48-53: Blank space ASCII */
98: };
99:
100:
101:
102: void scsi_command_analyzer(Uint8 commandbuf[], int size, int target, int lun) {
103: int i;
104: SCSIcommand.source_busid = commandbuf[0];
105: for (i = 1; i < size; i++) {
106: SCSIcommand.command[i-1] = commandbuf[i];
107: }
108:
109: SCSIcommand.opcode = SCSIcommand.command[0];
110: if (target >= ESP_MAX_DEVS) {
111: Log_Printf(LOG_WARN, "Invalid target: %i!\n", target);
112: abort();
113: }
114: SCSIcommand.target = target;
115: SCSIcommand.lun = lun;
116: Log_Printf(LOG_WARN, "SCSI command: Length = %i, Opcode = $%02x, target = %i, lun=%i\n", size, SCSIcommand.opcode, SCSIcommand.target,SCSIcommand.lun);
117:
118: scsidisk = scsiimage[target];
119: nDiskSize = nFileSize[target];
120: bCDROM = ConfigureParams.SCSI.target[target].bCDROM;
121: bTargetDevice = ConfigureParams.SCSI.target[target].bAttached;
122:
123: //bTargetDevice |= bCDROM; // handle empty cd-rom drive - does not work yet!
124: if(scsidisk) { // experimental!
125: SCSIcommand.nodevice = false;
126: SCSIcommand.timeout = false;
127: if ((SCSIcommand.lun!=LUN_DISC) && (SCSIcommand.opcode!=HD_REQ_SENSE) && (SCSIcommand.opcode!=HD_INQUIRY))
128: {
129: Log_Printf(LOG_WARN, "SCSI command: No device at target %i\n", SCSIcommand.target);
130: SCSIcommand.nodevice = true;
131: SCSIcommand.timeout = false;
132: SCSIcommand.transferdirection_todevice = 0;
133: SCSIcommand.transfer_data_len=0;
134: SCSIcommand.returnCode = HD_STATUS_ERROR;
135: nLastError= HD_REQSENS_NODRIVE;
136: return;
137: }
138: SCSI_Emulate_Command();
139: } else {
140: // hacks for NeXT (to be tested on real life...)
141: // question is : what an SCSI controler should answer for missing drives (and if SCSI controler is aware of SCSI opcodes)
142: // if (SCSIcommand.opcode==HD_TEST_UNIT_RDY) {SCSI_TestMissingUnitReady();SCSIcommand.nodevice = false;return;}
143: // SCSIcommand.nodevice = false;
144: // SCSIcommand.timeout = false;
145: // if (SCSIcommand.opcode==HD_REQ_SENSE) {SCSI_Emulate_Command();return;}
146: Log_Printf(LOG_WARN, "SCSI command: No target %i %s at %d", SCSIcommand.target,__FILE__,__LINE__);
147: SCSIcommand.nodevice = false;
148: SCSIcommand.timeout = true;
149: SCSIcommand.transferdirection_todevice = 0;
150: }
151: }
152:
153: void SCSI_Emulate_Command(void)
154: {
155:
156: switch(SCSIcommand.opcode)
157: {
158:
159: case HD_TEST_UNIT_RDY:
160: Log_Printf(LOG_WARN, "SCSI command: Test unit ready\n");
161: SCSI_TestUnitReady();
162: break;
163:
164: case HD_READ_CAPACITY1:
165: Log_Printf(LOG_WARN, "SCSI command: Read capacity\n");
166: SCSI_ReadCapacity();
167: break;
168:
169: case HD_READ_SECTOR:
170: case HD_READ_SECTOR1:
171: Log_Printf(LOG_WARN, "SCSI command: Read sector\n");
172: SCSI_ReadSector();
173: break;
174:
175: case HD_WRITE_SECTOR:
176: case HD_WRITE_SECTOR1:
177: Log_Printf(LOG_WARN, "SCSI command: Write sector\n");
1.1.1.2 ! root 178: SCSI_WriteSector();
! 179: // abort();
1.1 root 180: break;
181:
182: case HD_INQUIRY:
183: Log_Printf(LOG_WARN, "SCSI command: Inquiry\n");
184: SCSI_Inquiry();
185: break;
186:
187: case HD_SEEK:
188: Log_Printf(LOG_WARN, "SCSI command: Seek\n");
189: // HDC_Cmd_Seek();
190: abort();
191: break;
192:
193: case HD_SHIP:
194: Log_Printf(LOG_WARN, "SCSI command: Ship\n");
195: SCSI_StartStop();
196: break;
197:
198: case HD_REQ_SENSE:
199: Log_Printf(LOG_WARN, "SCSI command: Request sense\n");
200: SCSI_RequestSense();
201: break;
202:
203: case HD_MODESELECT:
204: Log_Printf(LOG_WARN, "MODE SELECT call not implemented yet.\n");
205: SCSIcommand.returnCode = HD_STATUS_OK;
206: nLastError = HD_REQSENS_OK;
207: bSetLastBlockAddr = false;
208: // FDC_SetDMAStatus(false);
209: // FDC_AcknowledgeInterrupt();
210: abort();
211: break;
212:
213: case HD_MODESENSE:
214: Log_Printf(LOG_WARN, "SCSI command: Mode sense\n");
215: SCSI_ModeSense();
216: break;
217:
218: case HD_FORMAT_DRIVE:
219: Log_Printf(LOG_WARN, "SCSI command: Format drive\n");
220: // HDC_Cmd_FormatDrive();
221: abort();
222: break;
223:
224: /* as of yet unsupported commands */
225: case HD_VERIFY_TRACK:
226: case HD_FORMAT_TRACK:
227: case HD_CORRECTION:
228:
229: default:
230: Log_Printf(LOG_WARN, "Unknown Command\n");
231: SCSIcommand.returnCode = HD_STATUS_ERROR;
232: nLastError = HD_REQSENS_OPCODE;
233: bSetLastBlockAddr = false;
234: // FDC_AcknowledgeInterrupt();
235: break;
236: }
237: esp_command_complete();
238:
239: /* Update the led each time a command is processed */
240: Statusbar_EnableHDLed();
241: }
242:
243:
244: /* Helpers */
245:
246: int SCSI_GetTransferLength(void)
247: {
248: return SCSIcommand.opcode < 0x20?
249: // class 0
250: SCSIcommand.command[4] :
251: // class 1
252: COMMAND_ReadInt16(SCSIcommand.command, 7);
253: }
254:
255: unsigned long SCSI_GetOffset(void)
256: {
257: return SCSIcommand.opcode < 0x20?
258: // class 0
259: (COMMAND_ReadInt24(SCSIcommand.command, 1) & 0x1FFFFF) :
260: // class 1
261: COMMAND_ReadInt32(SCSIcommand.command, 2);
262: }
263:
264: // get reserved count for SCSI reply
265: int SCSI_GetCount(void)
266: {
267: return SCSIcommand.opcode < 0x20?
268: // class 0
269: SCSIcommand.command[4] :
270: // class 1
271: COMMAND_ReadInt16(SCSIcommand.command, 7);
272: }
273:
274: MODEPAGE SCSI_GetModePage(Uint8 pagecode) {
275: MODEPAGE page;
276: Uint32 sectors;
277: Uint32 cylinders;
278: Uint8 heads;
279:
280: switch (pagecode) {
281: case 0x01: // error recovery page
282: page.pagesize = 8;
283: page.modepage[0] = 0x01; // &0x80: page savable? (not supported!), &0x7F: page code = 0x01
284: page.modepage[1] = 0x06; // page length = 6
285: page.modepage[2] = 0x00; // AWRE, ARRE, TB, RC, EER, PER, DTE, DCR
286: page.modepage[3] = 0x1B; // retry count
287: page.modepage[4] = 0x0B; // correction span in bits
288: page.modepage[5] = 0x00; // head offset count
289: page.modepage[6] = 0x00; // data strobe offset count
290: page.modepage[7] = 0xFF; // recovery time limit
291: break;
292:
293: case 0x02: // disconnect/reconnect page
294: case 0x03: // format device page
295: page.pagesize = 0;
296: Log_Printf(LOG_WARN, "Mode Sense: Page %02x not yet emulated!\n", pagecode);
297: break;
298:
299: case 0x04: // rigid disc geometry page
300: sectors = nDiskSize / BLOCKSIZE;
301: heads = 16; // max heads per cylinder: 16
302: cylinders = sectors / (63 * heads); // max sectors per track: 63
303: if ((sectors % (63 * heads)) != 0) {
304: cylinders += 1;
305: }
306: Log_Printf(LOG_WARN, "Disk geometry: %i sectors, %i cylinders, %i heads\n", sectors, cylinders, heads);
307:
308: page.pagesize = 0; //20;
309: Log_Printf(LOG_WARN, "Disk geometry page disabled!\n"); abort();
310: page.modepage[0] = 0x04; // &0x80: page savable? (not supported!), &0x7F: page code = 0x04
311: page.modepage[1] = 0x12;
312: page.modepage[2] = (cylinders >> 16) & 0xFF;
313: page.modepage[3] = (cylinders >> 8) & 0xFF;
314: page.modepage[4] = cylinders & 0xFF;
315: page.modepage[5] = heads;
316: page.modepage[6] = 0x00; // 6,7,8: starting cylinder - write precomp (not supported)
317: page.modepage[7] = 0x00;
318: page.modepage[8] = 0x00;
319: page.modepage[9] = 0x00; // 9,10,11: starting cylinder - reduced write current (not supported)
320: page.modepage[10] = 0x00;
321: page.modepage[11] = 0x00;
322: page.modepage[12] = 0x00; // 12,13: drive step rate (not supported)
323: page.modepage[13] = 0x00;
324: page.modepage[14] = 0x00; // 14,15,16: loading zone cylinder (not supported)
325: page.modepage[15] = 0x00;
326: page.modepage[16] = 0x00;
327: page.modepage[17] = 0x00; // &0x03: rotational position locking
328: page.modepage[18] = 0x00; // rotational position lock offset
329: page.modepage[19] = 0x00; // reserved
330: break;
331:
332: case 0x08: // caching page
333: case 0x0C: // notch page
334: case 0x0D: // power condition page
335: case 0x38: // cache control page
336: case 0x3C: // soft ID page (EEPROM)
337: page.pagesize = 0;
338: Log_Printf(LOG_WARN, "Mode Sense: Page %02x not yet emulated!\n", pagecode);
339: break;
340:
341: case 0x00: // operating page
342: page.pagesize = 4;
343: page.modepage[0] = 0x00; // &0x80: page savable? (not supported!), &0x7F: page code = 0x00
344: page.modepage[1] = 0x02; // page length = 2
345: page.modepage[2] = 0x80; // &0x80: usage bit = 1, &0x10: disable unit attention = 0
346: page.modepage[3] = 0x00; // &0x7F: device type qualifier = 0x00, see inquiry!
347: break;
348:
349: default:
350: page.pagesize = 0;
351: Log_Printf(LOG_WARN, "Mode Sense: Invalid page code: %02x!\n", pagecode);
352: break;
353: }
354: return page;
355: }
356:
357:
358:
359: /* SCSI Commands */
360:
361: void SCSI_TestUnitReady(void)
362: {
363: SCSIcommand.transfer_data_len = 0;
364: SCSIcommand.returnCode = HD_STATUS_OK;
365: }
366:
367:
368: void SCSI_ReadCapacity(void)
369: {
370: Log_Printf(LOG_WARN, "Read disk image: size = %i\n", nDiskSize);
371:
372: SCSIcommand.transfer_data_len = 8;
373:
374: Uint32 sectors = nDiskSize / BLOCKSIZE;
375:
376: static Uint8 scsi_disksize[8];
377:
378: scsi_disksize[0] = (sectors >> 24) & 0xFF;
379: scsi_disksize[1] = (sectors >> 16) & 0xFF;
380: scsi_disksize[2] = (sectors >> 8) & 0xFF;
381: scsi_disksize[3] = sectors & 0xFF;
382: scsi_disksize[4] = (BLOCKSIZE >> 24) & 0xFF;
383: scsi_disksize[5] = (BLOCKSIZE >> 16) & 0xFF;
384: scsi_disksize[6] = (BLOCKSIZE >> 8) & 0xFF;
385: scsi_disksize[7] = BLOCKSIZE & 0xFF;
386:
387: memcpy(dma_write_buffer, scsi_disksize, SCSIcommand.transfer_data_len);
388: SCSIcommand.returnCode = HD_STATUS_OK;
389: nLastError = HD_REQSENS_OK;
390:
391: bSetLastBlockAddr = false;
392: }
393:
1.1.1.2 ! root 394: void SCSI_WriteSector(void) {
! 395: int n=0;
! 396:
! 397: nLastBlockAddr = SCSI_GetOffset() * BLOCKSIZE;
! 398: SCSIcommand.transfer_data_len = SCSI_GetCount() * BLOCKSIZE;
! 399:
! 400:
! 401: /* seek to the position */
! 402: if ((scsidisk==NULL) || (fseek(scsidisk, nLastBlockAddr, SEEK_SET) != 0))
! 403: {
! 404: SCSIcommand.returnCode = HD_STATUS_ERROR;
! 405: nLastError = HD_REQSENS_INVADDR;
! 406: }
! 407: else
! 408: {
! 409: if (1 == 1) {
! 410: // fixme : for now writes are error
! 411: SCSIcommand.returnCode = HD_STATUS_OK;
! 412: nLastError = HD_REQSENS_OK;
! 413: }
! 414: }
! 415: }
1.1 root 416:
417: void SCSI_ReadSector(void)
418: {
419: int n=0;
420:
421: nLastBlockAddr = SCSI_GetOffset() * BLOCKSIZE;
422: SCSIcommand.transfer_data_len = SCSI_GetCount() * BLOCKSIZE;
423:
424:
425: /* seek to the position */
426: if ((scsidisk==NULL) || (fseek(scsidisk, nLastBlockAddr, SEEK_SET) != 0))
427: {
428: SCSIcommand.returnCode = HD_STATUS_ERROR;
429: nLastError = HD_REQSENS_INVADDR;
430: }
431: else
432: {
433: n = fread(dma_write_buffer, SCSIcommand.transfer_data_len, 1, scsidisk);
434:
435: /* Test to check if we read correct data */
436: // Log_Printf(LOG_WARN, "Disk Read Test: $%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x,$%02x\n", dma_write_buffer[0],dma_write_buffer[1],dma_write_buffer[2],dma_write_buffer[3],dma_write_buffer[4],dma_write_buffer[5],dma_write_buffer[6],dma_write_buffer[07]);
437: }
438:
439: if (n == 1) {
440: SCSIcommand.returnCode = HD_STATUS_OK;
441: nLastError = HD_REQSENS_OK;
442: }
443: else
444: {
445: SCSIcommand.returnCode = HD_STATUS_ERROR;
446: nLastError = HD_REQSENS_NOSECTOR;
447: }
448:
449: /* Update DMA counter */
450: // FDC_WriteDMAAddress(nDmaAddr + 512*n);
451: // }
452:
453: // FDC_SetDMAStatus(false); /* no DMA error */
454: // FDC_AcknowledgeInterrupt();
455: bSetLastBlockAddr = true;
456: //FDCSectorCountRegister = 0;
457: }
458:
459:
460:
461: void SCSI_Inquiry (void) {
462:
463: if (bCDROM) {
464: inquiry_bytes[0] = 0x05;
465: inquiry_bytes[1] |= 0x80;
466: inquiry_bytes[16] = 'C';
467: inquiry_bytes[18] = '-';
468: inquiry_bytes[19] = 'R';
469: inquiry_bytes[20] = 'O';
470: inquiry_bytes[21] = 'M';
471: Log_Printf(LOG_WARN, "Disk is CD-ROM\n");
472: } else {
473: inquiry_bytes[0] = 0x00;
474: inquiry_bytes[1] &= ~0x80;
475: inquiry_bytes[16] = 'H';
476: inquiry_bytes[18] = 'D';
477: inquiry_bytes[19] = ' ';
478: inquiry_bytes[20] = ' ';
479: inquiry_bytes[21] = ' ';
480: Log_Printf(LOG_WARN, "Disk is HDD\n");
481: }
482:
483: if (SCSIcommand.lun!=LUN_DISC) { inquiry_bytes[0] = 0x1F;}
484:
485: SCSIcommand.transfer_data_len = SCSI_GetTransferLength();
486: Log_Printf(LOG_WARN, "return length: %d", SCSIcommand.transfer_data_len);
487: SCSIcommand.transferdirection_todevice = 0;
488: memcpy(dma_write_buffer, inquiry_bytes, SCSIcommand.transfer_data_len);
489:
490: Log_Printf(LOG_WARN, "Inquiry Data: %c,%c,%c,%c,%c,%c,%c,%c\n",dma_write_buffer[8],dma_write_buffer[9],dma_write_buffer[10],dma_write_buffer[11],dma_write_buffer[12],dma_write_buffer[13],dma_write_buffer[14],dma_write_buffer[15]);
491:
492: if (SCSIcommand.transfer_data_len > (int)sizeof(inquiry_bytes))
493: SCSIcommand.transfer_data_len = sizeof(inquiry_bytes);
494:
495: SCSIcommand.returnCode = HD_STATUS_OK;
496: nLastError = HD_REQSENS_OK;
497: bSetLastBlockAddr = false;
498: }
499:
500:
501: void SCSI_StartStop(void) {
502: SCSIcommand.transfer_data_len = 0;
503: SCSIcommand.transferdirection_todevice = 0;
504: SCSIcommand.returnCode = HD_STATUS_OK;
505: }
506:
507:
508: void SCSI_RequestSense(void) {
509: int nRetLen;
510: Uint8 retbuf[22];
511:
512: SCSIcommand.returnCode = HD_STATUS_OK;
513:
514: nRetLen = SCSI_GetCount();
515:
516: if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22)
517: {
518: Log_Printf(LOG_WARN, "SCSI: *** Strange REQUEST SENSE *** len=%d!",nRetLen);
519: }
520:
521: /* Limit to sane length */
522: if (nRetLen <= 0)
523: {
524: nRetLen = 4;
525: }
526: else if (nRetLen > 22)
527: {
528: nRetLen = 22;
529: }
530:
531: Log_Printf(LOG_WARN, "[SCSI] REQ SENSE size = %d %s at %d", nRetLen,__FILE__,__LINE__);
532:
533: memset(retbuf, 0, nRetLen);
534:
535: if (nRetLen <= 4)
536: {
537: retbuf[0] = nLastError;
538: if (bSetLastBlockAddr)
539: {
540: retbuf[0] |= 0x80;
541: retbuf[1] = nLastBlockAddr >> 16;
542: retbuf[2] = nLastBlockAddr >> 8;
543: retbuf[3] = nLastBlockAddr;
544: }
545: }
546: else
547: {
548: retbuf[0] = 0x70;
549: if (bSetLastBlockAddr)
550: {
551: retbuf[0] |= 0x80;
552: retbuf[4] = nLastBlockAddr >> 16;
553: retbuf[5] = nLastBlockAddr >> 8;
554: retbuf[6] = nLastBlockAddr;
555: }
556: switch (nLastError)
557: {
558: case HD_REQSENS_OK: retbuf[2] = 0; break;
559: case HD_REQSENS_OPCODE: retbuf[2] = 5; break;
560: case HD_REQSENS_INVADDR: retbuf[2] = 5; break;
561: case HD_REQSENS_INVARG: retbuf[2] = 5; break;
562: case HD_REQSENS_NODRIVE: retbuf[2] = 2; break;
563: default: retbuf[2] = 4; break;
564: }
565: retbuf[7] = 14;
566: retbuf[12] = nLastError;
567: retbuf[19] = nLastBlockAddr >> 16;
568: retbuf[20] = nLastBlockAddr >> 8;
569: retbuf[21] = nLastBlockAddr;
570: }
571:
572: SCSIcommand.transfer_data_len = nRetLen;
573: memcpy(dma_write_buffer, retbuf, SCSIcommand.transfer_data_len);
574: SCSIcommand.returnCode = HD_STATUS_OK;
575: }
576:
577:
578: void SCSI_ModeSense(void) {
579: Uint8 retbuf[256];
580: MODEPAGE page;
581:
582: Uint32 sectors = nDiskSize / BLOCKSIZE;
583:
584: Uint8 pagecontrol = (SCSIcommand.command[2] & 0x0C) >> 6;
585: Uint8 pagecode = SCSIcommand.command[2] & 0x3F;
586: Uint8 dbd = SCSIcommand.command[1] & 0x08; // disable block descriptor
587:
588: Log_Printf(LOG_WARN, "Mode Sense: page = %02x, page_control = %i, %s\n", pagecode, pagecontrol, dbd == 0x08 ? "block descriptor disabled" : "block descriptor enabled");
589:
590: /* Header */
591: retbuf[0] = 0x00; // length of following data
592: retbuf[1] = 0x00; // medium type (always 0)
593: retbuf[2] = bCDROM == true ? 0x80 : 0x00; // if media is read-only 0x80, else 0x00
594: retbuf[3] = 0x08; // block descriptor length
595:
596: /* Block descriptor data */
597: Uint8 header_size = 4;
598: if (!dbd) {
599: retbuf[4] = 0x00; // media density code
600: retbuf[5] = sectors >> 16; // Number of blocks, high (?)
601: retbuf[6] = sectors >> 8; // Number of blocks, med (?)
602: retbuf[7] = sectors; // Number of blocks, low (?)
603: retbuf[8] = 0x00; // reserved
604: retbuf[9] = (BLOCKSIZE >> 16) & 0xFF; // Block size in bytes, high
605: retbuf[10] = (BLOCKSIZE >> 8) & 0xFF; // Block size in bytes, med
606: retbuf[11] = BLOCKSIZE & 0xFF; // Block size in bytes, low
607: header_size = 12;
608: Log_Printf(LOG_WARN, "Mode Sense: Block descriptor data: %s, size = %i blocks, blocksize = %i byte\n", bCDROM == true ? "disk is read-only" : "disk is read/write" , sectors, BLOCKSIZE);
609: }
610: retbuf[0] = header_size - 1;
611:
612: /* Mode Pages */
613: if (pagecode == 0x3F) { // return all pages!
614: Uint8 offset = header_size;
615: Uint8 counter;
616: for (pagecode = 0; pagecode < 0x3F; pagecode++) {
617: page = SCSI_GetModePage(pagecode);
618: switch (pagecontrol) {
619: case 0: // current values (not supported, using default values)
620: memcpy(page.current, page.modepage, page.pagesize);
621: for (counter = 0; counter < page.pagesize; counter++) {
622: retbuf[counter+offset] = page.current[counter];
623: }
624: break;
625: case 1: // changeable values (not supported, all 0)
626: memset(page.changeable, 0x00, page.pagesize);
627: for (counter = 0; counter < page.pagesize; counter++) {
628: retbuf[counter+offset] = page.changeable[counter];
629: }
630: break;
631: case 2: // default values
632: for (counter = 0; counter < page.pagesize; counter++) {
633: retbuf[counter+offset] = page.modepage[counter];
634: }
635: break;
636: case 3: // saved values (not supported, using default values)
637: memcpy(page.saved, page.modepage, page.pagesize);
638: for (counter = 0; counter < page.pagesize; counter++) {
639: retbuf[counter+offset] = page.saved[counter];
640: }
641: break;
642:
643: default:
644: break;
645: }
646: offset += page.pagesize;
647: retbuf[0] += page.pagesize;
648: }
649: } else { // return only single requested page
650: page = SCSI_GetModePage(pagecode);
651:
652: Uint8 counter;
653: switch (pagecontrol) {
654: case 0: // current values (not supported, using default values)
655: memcpy(page.current, page.modepage, page.pagesize);
656: for (counter = 0; counter < page.pagesize; counter++) {
657: retbuf[counter+header_size] = page.current[counter];
658: }
659: break;
660: case 1: // changeable values (not supported, all 0)
661: memset(page.changeable, 0x00, page.pagesize);
662: for (counter = 0; counter < page.pagesize; counter++) {
663: retbuf[counter+header_size] = page.changeable[counter];
664: }
665: break;
666: case 2: // default values
667: for (counter = 0; counter < page.pagesize; counter++) {
668: retbuf[counter+header_size] = page.modepage[counter];
669: }
670: break;
671: case 3: // saved values (not supported, using default values)
672: memcpy(page.saved, page.modepage, page.pagesize);
673: for (counter = 0; counter < page.pagesize; counter++) {
674: retbuf[counter+header_size] = page.saved[counter];
675: }
676: break;
677:
678: default:
679: break;
680: }
681:
682: retbuf[0] += page.pagesize;
683: }
684:
685:
686: SCSIcommand.transfer_data_len = retbuf[0] + 1;
687: if (SCSIcommand.transfer_data_len > SCSI_GetTransferLength())
688: SCSIcommand.transfer_data_len = SCSI_GetTransferLength();
689:
690: memcpy(dma_write_buffer, retbuf, SCSIcommand.transfer_data_len);
691:
692: SCSIcommand.returnCode = HD_STATUS_OK;
693: nLastError = HD_REQSENS_OK;
694:
695: bSetLastBlockAddr = false;
696: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.