|
|
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"); ! 178: // HDC_Cmd_WriteSector(); ! 179: abort(); ! 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: ! 394: ! 395: void SCSI_ReadSector(void) ! 396: { ! 397: int n=0; ! 398: ! 399: nLastBlockAddr = SCSI_GetOffset() * BLOCKSIZE; ! 400: SCSIcommand.transfer_data_len = SCSI_GetCount() * BLOCKSIZE; ! 401: ! 402: ! 403: /* seek to the position */ ! 404: if ((scsidisk==NULL) || (fseek(scsidisk, nLastBlockAddr, SEEK_SET) != 0)) ! 405: { ! 406: SCSIcommand.returnCode = HD_STATUS_ERROR; ! 407: nLastError = HD_REQSENS_INVADDR; ! 408: } ! 409: else ! 410: { ! 411: n = fread(dma_write_buffer, SCSIcommand.transfer_data_len, 1, scsidisk); ! 412: ! 413: /* Test to check if we read correct data */ ! 414: // 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]); ! 415: } ! 416: ! 417: if (n == 1) { ! 418: SCSIcommand.returnCode = HD_STATUS_OK; ! 419: nLastError = HD_REQSENS_OK; ! 420: } ! 421: else ! 422: { ! 423: SCSIcommand.returnCode = HD_STATUS_ERROR; ! 424: nLastError = HD_REQSENS_NOSECTOR; ! 425: } ! 426: ! 427: /* Update DMA counter */ ! 428: // FDC_WriteDMAAddress(nDmaAddr + 512*n); ! 429: // } ! 430: ! 431: // FDC_SetDMAStatus(false); /* no DMA error */ ! 432: // FDC_AcknowledgeInterrupt(); ! 433: bSetLastBlockAddr = true; ! 434: //FDCSectorCountRegister = 0; ! 435: } ! 436: ! 437: ! 438: ! 439: void SCSI_Inquiry (void) { ! 440: ! 441: if (bCDROM) { ! 442: inquiry_bytes[0] = 0x05; ! 443: inquiry_bytes[1] |= 0x80; ! 444: inquiry_bytes[16] = 'C'; ! 445: inquiry_bytes[18] = '-'; ! 446: inquiry_bytes[19] = 'R'; ! 447: inquiry_bytes[20] = 'O'; ! 448: inquiry_bytes[21] = 'M'; ! 449: Log_Printf(LOG_WARN, "Disk is CD-ROM\n"); ! 450: } else { ! 451: inquiry_bytes[0] = 0x00; ! 452: inquiry_bytes[1] &= ~0x80; ! 453: inquiry_bytes[16] = 'H'; ! 454: inquiry_bytes[18] = 'D'; ! 455: inquiry_bytes[19] = ' '; ! 456: inquiry_bytes[20] = ' '; ! 457: inquiry_bytes[21] = ' '; ! 458: Log_Printf(LOG_WARN, "Disk is HDD\n"); ! 459: } ! 460: ! 461: if (SCSIcommand.lun!=LUN_DISC) { inquiry_bytes[0] = 0x1F;} ! 462: ! 463: SCSIcommand.transfer_data_len = SCSI_GetTransferLength(); ! 464: Log_Printf(LOG_WARN, "return length: %d", SCSIcommand.transfer_data_len); ! 465: SCSIcommand.transferdirection_todevice = 0; ! 466: memcpy(dma_write_buffer, inquiry_bytes, SCSIcommand.transfer_data_len); ! 467: ! 468: 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]); ! 469: ! 470: if (SCSIcommand.transfer_data_len > (int)sizeof(inquiry_bytes)) ! 471: SCSIcommand.transfer_data_len = sizeof(inquiry_bytes); ! 472: ! 473: SCSIcommand.returnCode = HD_STATUS_OK; ! 474: nLastError = HD_REQSENS_OK; ! 475: bSetLastBlockAddr = false; ! 476: } ! 477: ! 478: ! 479: void SCSI_StartStop(void) { ! 480: SCSIcommand.transfer_data_len = 0; ! 481: SCSIcommand.transferdirection_todevice = 0; ! 482: SCSIcommand.returnCode = HD_STATUS_OK; ! 483: } ! 484: ! 485: ! 486: void SCSI_RequestSense(void) { ! 487: int nRetLen; ! 488: Uint8 retbuf[22]; ! 489: ! 490: SCSIcommand.returnCode = HD_STATUS_OK; ! 491: ! 492: nRetLen = SCSI_GetCount(); ! 493: ! 494: if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22) ! 495: { ! 496: Log_Printf(LOG_WARN, "SCSI: *** Strange REQUEST SENSE *** len=%d!",nRetLen); ! 497: } ! 498: ! 499: /* Limit to sane length */ ! 500: if (nRetLen <= 0) ! 501: { ! 502: nRetLen = 4; ! 503: } ! 504: else if (nRetLen > 22) ! 505: { ! 506: nRetLen = 22; ! 507: } ! 508: ! 509: Log_Printf(LOG_WARN, "[SCSI] REQ SENSE size = %d %s at %d", nRetLen,__FILE__,__LINE__); ! 510: ! 511: memset(retbuf, 0, nRetLen); ! 512: ! 513: if (nRetLen <= 4) ! 514: { ! 515: retbuf[0] = nLastError; ! 516: if (bSetLastBlockAddr) ! 517: { ! 518: retbuf[0] |= 0x80; ! 519: retbuf[1] = nLastBlockAddr >> 16; ! 520: retbuf[2] = nLastBlockAddr >> 8; ! 521: retbuf[3] = nLastBlockAddr; ! 522: } ! 523: } ! 524: else ! 525: { ! 526: retbuf[0] = 0x70; ! 527: if (bSetLastBlockAddr) ! 528: { ! 529: retbuf[0] |= 0x80; ! 530: retbuf[4] = nLastBlockAddr >> 16; ! 531: retbuf[5] = nLastBlockAddr >> 8; ! 532: retbuf[6] = nLastBlockAddr; ! 533: } ! 534: switch (nLastError) ! 535: { ! 536: case HD_REQSENS_OK: retbuf[2] = 0; break; ! 537: case HD_REQSENS_OPCODE: retbuf[2] = 5; break; ! 538: case HD_REQSENS_INVADDR: retbuf[2] = 5; break; ! 539: case HD_REQSENS_INVARG: retbuf[2] = 5; break; ! 540: case HD_REQSENS_NODRIVE: retbuf[2] = 2; break; ! 541: default: retbuf[2] = 4; break; ! 542: } ! 543: retbuf[7] = 14; ! 544: retbuf[12] = nLastError; ! 545: retbuf[19] = nLastBlockAddr >> 16; ! 546: retbuf[20] = nLastBlockAddr >> 8; ! 547: retbuf[21] = nLastBlockAddr; ! 548: } ! 549: ! 550: SCSIcommand.transfer_data_len = nRetLen; ! 551: memcpy(dma_write_buffer, retbuf, SCSIcommand.transfer_data_len); ! 552: SCSIcommand.returnCode = HD_STATUS_OK; ! 553: } ! 554: ! 555: ! 556: void SCSI_ModeSense(void) { ! 557: Uint8 retbuf[256]; ! 558: MODEPAGE page; ! 559: ! 560: Uint32 sectors = nDiskSize / BLOCKSIZE; ! 561: ! 562: Uint8 pagecontrol = (SCSIcommand.command[2] & 0x0C) >> 6; ! 563: Uint8 pagecode = SCSIcommand.command[2] & 0x3F; ! 564: Uint8 dbd = SCSIcommand.command[1] & 0x08; // disable block descriptor ! 565: ! 566: Log_Printf(LOG_WARN, "Mode Sense: page = %02x, page_control = %i, %s\n", pagecode, pagecontrol, dbd == 0x08 ? "block descriptor disabled" : "block descriptor enabled"); ! 567: ! 568: /* Header */ ! 569: retbuf[0] = 0x00; // length of following data ! 570: retbuf[1] = 0x00; // medium type (always 0) ! 571: retbuf[2] = bCDROM == true ? 0x80 : 0x00; // if media is read-only 0x80, else 0x00 ! 572: retbuf[3] = 0x08; // block descriptor length ! 573: ! 574: /* Block descriptor data */ ! 575: Uint8 header_size = 4; ! 576: if (!dbd) { ! 577: retbuf[4] = 0x00; // media density code ! 578: retbuf[5] = sectors >> 16; // Number of blocks, high (?) ! 579: retbuf[6] = sectors >> 8; // Number of blocks, med (?) ! 580: retbuf[7] = sectors; // Number of blocks, low (?) ! 581: retbuf[8] = 0x00; // reserved ! 582: retbuf[9] = (BLOCKSIZE >> 16) & 0xFF; // Block size in bytes, high ! 583: retbuf[10] = (BLOCKSIZE >> 8) & 0xFF; // Block size in bytes, med ! 584: retbuf[11] = BLOCKSIZE & 0xFF; // Block size in bytes, low ! 585: header_size = 12; ! 586: 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); ! 587: } ! 588: retbuf[0] = header_size - 1; ! 589: ! 590: /* Mode Pages */ ! 591: if (pagecode == 0x3F) { // return all pages! ! 592: Uint8 offset = header_size; ! 593: Uint8 counter; ! 594: for (pagecode = 0; pagecode < 0x3F; pagecode++) { ! 595: page = SCSI_GetModePage(pagecode); ! 596: switch (pagecontrol) { ! 597: case 0: // current values (not supported, using default values) ! 598: memcpy(page.current, page.modepage, page.pagesize); ! 599: for (counter = 0; counter < page.pagesize; counter++) { ! 600: retbuf[counter+offset] = page.current[counter]; ! 601: } ! 602: break; ! 603: case 1: // changeable values (not supported, all 0) ! 604: memset(page.changeable, 0x00, page.pagesize); ! 605: for (counter = 0; counter < page.pagesize; counter++) { ! 606: retbuf[counter+offset] = page.changeable[counter]; ! 607: } ! 608: break; ! 609: case 2: // default values ! 610: for (counter = 0; counter < page.pagesize; counter++) { ! 611: retbuf[counter+offset] = page.modepage[counter]; ! 612: } ! 613: break; ! 614: case 3: // saved values (not supported, using default values) ! 615: memcpy(page.saved, page.modepage, page.pagesize); ! 616: for (counter = 0; counter < page.pagesize; counter++) { ! 617: retbuf[counter+offset] = page.saved[counter]; ! 618: } ! 619: break; ! 620: ! 621: default: ! 622: break; ! 623: } ! 624: offset += page.pagesize; ! 625: retbuf[0] += page.pagesize; ! 626: } ! 627: } else { // return only single requested page ! 628: page = SCSI_GetModePage(pagecode); ! 629: ! 630: Uint8 counter; ! 631: switch (pagecontrol) { ! 632: case 0: // current values (not supported, using default values) ! 633: memcpy(page.current, page.modepage, page.pagesize); ! 634: for (counter = 0; counter < page.pagesize; counter++) { ! 635: retbuf[counter+header_size] = page.current[counter]; ! 636: } ! 637: break; ! 638: case 1: // changeable values (not supported, all 0) ! 639: memset(page.changeable, 0x00, page.pagesize); ! 640: for (counter = 0; counter < page.pagesize; counter++) { ! 641: retbuf[counter+header_size] = page.changeable[counter]; ! 642: } ! 643: break; ! 644: case 2: // default values ! 645: for (counter = 0; counter < page.pagesize; counter++) { ! 646: retbuf[counter+header_size] = page.modepage[counter]; ! 647: } ! 648: break; ! 649: case 3: // saved values (not supported, using default values) ! 650: memcpy(page.saved, page.modepage, page.pagesize); ! 651: for (counter = 0; counter < page.pagesize; counter++) { ! 652: retbuf[counter+header_size] = page.saved[counter]; ! 653: } ! 654: break; ! 655: ! 656: default: ! 657: break; ! 658: } ! 659: ! 660: retbuf[0] += page.pagesize; ! 661: } ! 662: ! 663: ! 664: SCSIcommand.transfer_data_len = retbuf[0] + 1; ! 665: if (SCSIcommand.transfer_data_len > SCSI_GetTransferLength()) ! 666: SCSIcommand.transfer_data_len = SCSI_GetTransferLength(); ! 667: ! 668: memcpy(dma_write_buffer, retbuf, SCSIcommand.transfer_data_len); ! 669: ! 670: SCSIcommand.returnCode = HD_STATUS_OK; ! 671: nLastError = HD_REQSENS_OK; ! 672: ! 673: bSetLastBlockAddr = false; ! 674: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.