|
|
1.1 ! root 1: /* SCSI Bus and Disk emulation */ ! 2: #include "main.h" ! 3: #include "ioMem.h" ! 4: #include "ioMemTables.h" ! 5: #include "configuration.h" ! 6: #include "sysdeps.h" ! 7: #include "m68000.h" ! 8: #include "statusbar.h" ! 9: #include "scsi.h" ! 10: #include "file.h" ! 11: ! 12: #define LOG_SCSI_LEVEL LOG_DEBUG /* Print debugging messages */ ! 13: ! 14: ! 15: #define COMMAND_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1]) ! 16: #define COMMAND_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2]) ! 17: #define COMMAND_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3]) ! 18: ! 19: ! 20: #define BLOCKSIZE 512 ! 21: ! 22: #define LUN_DISK 0 // for now only LUN 0 is valid for our phys drives ! 23: ! 24: /* Status Codes */ ! 25: #define STAT_GOOD 0x00 ! 26: #define STAT_CHECK_COND 0x02 ! 27: #define STAT_COND_MET 0x04 ! 28: #define STAT_BUSY 0x08 ! 29: #define STAT_INTERMEDIATE 0x10 ! 30: #define STAT_INTER_COND_MET 0x14 ! 31: #define STAT_RESERV_CONFL 0x18 ! 32: ! 33: /* Messages */ ! 34: #define MSG_COMPLETE 0x00 ! 35: #define MSG_SAVE_PTRS 0x02 ! 36: #define MSG_RESTORE_PTRS 0x03 ! 37: #define MSG_DISCONNECT 0x04 ! 38: #define MSG_INITIATOR_ERR 0x05 ! 39: #define MSG_ABORT 0x06 ! 40: #define MSG_MSG_REJECT 0x07 ! 41: #define MSG_NOP 0x08 ! 42: #define MSG_PARITY_ERR 0x09 ! 43: #define MSG_LINK_CMD_CMPLT 0x0A ! 44: #define MSG_LNKCMDCMPLTFLAG 0x0B ! 45: #define MSG_DEVICE_RESET 0x0C ! 46: ! 47: #define MSG_IDENTIFY_MASK 0x80 ! 48: #define MSG_ID_DISCONN 0x40 ! 49: #define MSG_LUNMASK 0x07 ! 50: ! 51: /* Sense Keys */ ! 52: #define SK_NOSENSE 0x00 ! 53: #define SK_RECOVERED 0x01 ! 54: #define SK_NOTREADY 0x02 ! 55: #define SK_MEDIA 0x03 ! 56: #define SK_HARDWARE 0x04 ! 57: #define SK_ILLEGAL_REQ 0x05 ! 58: #define SK_UNIT_ATN 0x06 ! 59: #define SK_DATAPROTECT 0x07 ! 60: #define SK_ABORTED_CMD 0x0B ! 61: #define SK_VOL_OVERFLOW 0x0D ! 62: #define SK_MISCOMPARE 0x0E ! 63: ! 64: /* Additional Sense Codes */ ! 65: #define SC_NO_ERROR 0x00 // 0 ! 66: #define SC_NO_SECTOR 0x01 // 4 ! 67: #define SC_WRITE_FAULT 0x03 // 5 ! 68: #define SC_NOT_READY 0x04 // 2 ! 69: #define SC_INVALID_CMD 0x20 // 5 ! 70: #define SC_INVALID_LBA 0x21 // 5 ! 71: #define SC_INVALID_CDB 0x24 // 5 ! 72: #define SC_INVALID_LUN 0x25 // 5 ! 73: #define SC_WRITE_PROTECT 0x27 // 7 ! 74: ! 75: ! 76: /* SCSI Commands */ ! 77: ! 78: /* The following are multi-sector transfers with seek implied */ ! 79: #define CMD_VERIFY_TRACK 0x05 /* Verify track */ ! 80: #define CMD_FORMAT_TRACK 0x06 /* Format track */ ! 81: #define CMD_READ_SECTOR 0x08 /* Read sector */ ! 82: #define CMD_READ_SECTOR1 0x28 /* Read sector (class 1) */ ! 83: #define CMD_WRITE_SECTOR 0x0A /* Write sector */ ! 84: #define CMD_WRITE_SECTOR1 0x2A /* Write sector (class 1) */ ! 85: ! 86: /* Other codes */ ! 87: #define CMD_TEST_UNIT_RDY 0x00 /* Test unit ready */ ! 88: #define CMD_FORMAT_DRIVE 0x04 /* Format the whole drive */ ! 89: #define CMD_SEEK 0x0B /* Seek */ ! 90: #define CMD_CORRECTION 0x0D /* Correction */ ! 91: #define CMD_INQUIRY 0x12 /* Inquiry */ ! 92: #define CMD_MODESELECT 0x15 /* Mode select */ ! 93: #define CMD_MODESENSE 0x1A /* Mode sense */ ! 94: #define CMD_REQ_SENSE 0x03 /* Request sense */ ! 95: #define CMD_SHIP 0x1B /* Ship drive */ ! 96: #define CMD_READ_CAPACITY1 0x25 /* Read capacity (class 1) */ ! 97: ! 98: void SCSI_Emulate_Command(Uint8 *cdb); ! 99: ! 100: void SCSI_Inquiry(Uint8 *cdb); ! 101: void SCSI_StartStop(Uint8 *cdb); ! 102: void SCSI_TestUnitReady(Uint8 *cdb); ! 103: void SCSI_ReadCapacity(Uint8 *cdb); ! 104: void SCSI_ReadSector(Uint8 *cdb); ! 105: void SCSI_WriteSector(Uint8 *cdb); ! 106: void SCSI_RequestSense(Uint8 *cdb); ! 107: void SCSI_ModeSense(Uint8 *cdb); ! 108: void SCSI_FormatDrive(Uint8 *cdb); ! 109: ! 110: ! 111: /* Helpers */ ! 112: int SCSI_GetCommandLength(Uint8 opcode); ! 113: int SCSI_GetTransferLength(Uint8 opcode, Uint8 *cdb); ! 114: Uint64 SCSI_GetOffset(Uint8 opcode, Uint8 *cdb); ! 115: int SCSI_GetCount(Uint8 opcode, Uint8 *cdb); ! 116: ! 117: void scsi_read_sector(void); ! 118: void scsi_write_sector(void); ! 119: ! 120: ! 121: /* SCSI disk */ ! 122: struct { ! 123: SCSI_DEVTYPE devtype; ! 124: FILE* dsk; ! 125: Uint64 size; ! 126: bool readonly; ! 127: Uint8 lun; ! 128: Uint8 status; ! 129: Uint8 message; ! 130: ! 131: struct { ! 132: Uint8 key; ! 133: Uint8 code; ! 134: bool valid; ! 135: Uint32 info; ! 136: } sense; ! 137: ! 138: Uint32 lba; ! 139: Uint32 blockcounter; ! 140: Uint32 lastlba; ! 141: ! 142: Uint8** shadow; ! 143: } SCSIdisk[ESP_MAX_DEVS]; ! 144: ! 145: ! 146: /* Mode Pages */ ! 147: #define MODEPAGE_MAX_SIZE 24 ! 148: ! 149: typedef struct { ! 150: Uint8 current[MODEPAGE_MAX_SIZE]; ! 151: Uint8 changeable[MODEPAGE_MAX_SIZE]; ! 152: Uint8 modepage[MODEPAGE_MAX_SIZE]; // default values ! 153: Uint8 saved[MODEPAGE_MAX_SIZE]; ! 154: Uint8 pagesize; ! 155: } MODEPAGE; ! 156: ! 157: MODEPAGE SCSI_GetModePage(Uint8 pagecode); ! 158: ! 159: ! 160: /* Initialize/Uninitialize SCSI disks */ ! 161: void SCSI_Init(void) { ! 162: Log_Printf(LOG_WARN, "Loading SCSI disks:\n"); ! 163: ! 164: int i; ! 165: for (i = 0; i < ESP_MAX_DEVS; i++) { ! 166: SCSIdisk[i].devtype = ConfigureParams.SCSI.target[i].nDeviceType; ! 167: SCSI_Insert(i); ! 168: } ! 169: } ! 170: ! 171: void SCSI_Uninit(void) { ! 172: int i; ! 173: for (i = 0; i < ESP_MAX_DEVS; i++) { ! 174: if (SCSIdisk[i].dsk) { ! 175: SCSI_Eject(i); ! 176: } ! 177: } ! 178: } ! 179: ! 180: void SCSI_Reset(void) { ! 181: SCSI_Uninit(); ! 182: SCSI_Init(); ! 183: } ! 184: ! 185: void SCSI_Eject(Uint8 i) { ! 186: File_Close(SCSIdisk[i].dsk); ! 187: SCSIdisk[i].dsk = NULL; ! 188: SCSIdisk[i].size = 0; ! 189: SCSIdisk[i].readonly = false; ! 190: SCSIdisk[i].shadow = NULL; ! 191: } ! 192: ! 193: static void SCSI_EjectDisk(Uint8 i) { ! 194: ConfigureParams.SCSI.target[i].bDiskInserted = false; ! 195: ConfigureParams.SCSI.target[i].szImageName[0] = '\0'; ! 196: ! 197: SCSI_Eject(i); ! 198: } ! 199: ! 200: void SCSI_Insert(Uint8 i) { ! 201: SCSIdisk[i].lun = SCSIdisk[i].status = SCSIdisk[i].message = 0; ! 202: SCSIdisk[i].sense.code = SCSIdisk[i].sense.key = SCSIdisk[i].sense.info = 0; ! 203: SCSIdisk[i].sense.valid = false; ! 204: SCSIdisk[i].lba = SCSIdisk[i].lastlba = SCSIdisk[i].blockcounter = 0; ! 205: ! 206: SCSIdisk[i].shadow = NULL; ! 207: ! 208: Log_Printf(LOG_WARN, "SCSI Disk%i: %s\n",i,ConfigureParams.SCSI.target[i].szImageName); ! 209: ! 210: if (File_Exists(ConfigureParams.SCSI.target[i].szImageName) && ! 211: ConfigureParams.SCSI.target[i].bDiskInserted) { ! 212: if (ConfigureParams.SCSI.target[i].bWriteProtected || ! 213: ConfigureParams.SCSI.target[i].nDeviceType==DEVTYPE_CD) { ! 214: SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb"); ! 215: if (SCSIdisk[i].dsk == NULL) { ! 216: Log_Printf(LOG_WARN, "SCSI Disk%i: Cannot open image file %s\n", ! 217: i, ConfigureParams.SCSI.target[i].szImageName); ! 218: SCSIdisk[i].size = 0; ! 219: SCSIdisk[i].readonly = false; ! 220: if (SCSIdisk[i].devtype == DEVTYPE_HARDDISK) { ! 221: SCSIdisk[i].devtype = DEVTYPE_NONE; ! 222: } ! 223: } else { ! 224: SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); ! 225: SCSIdisk[i].readonly = true; ! 226: } ! 227: } else { ! 228: SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb+"); ! 229: if (SCSIdisk[i].dsk == NULL) { ! 230: SCSIdisk[i].dsk = File_Open(ConfigureParams.SCSI.target[i].szImageName, "rb"); ! 231: if (SCSIdisk[i].dsk == NULL) { ! 232: Log_Printf(LOG_WARN, "SCSI Disk%i: Cannot open image file %s\n", ! 233: i, ConfigureParams.SCSI.target[i].szImageName); ! 234: SCSIdisk[i].size = 0; ! 235: SCSIdisk[i].readonly = false; ! 236: if (SCSIdisk[i].devtype == DEVTYPE_HARDDISK) { ! 237: SCSIdisk[i].devtype = DEVTYPE_NONE; ! 238: } ! 239: } else { ! 240: SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); ! 241: SCSIdisk[i].readonly = true; ! 242: Log_Printf(LOG_WARN, "SCSI Disk%i: Image file is not writable. Enabling write protection.\n", i); ! 243: } ! 244: } else { ! 245: SCSIdisk[i].size = File_Length(ConfigureParams.SCSI.target[i].szImageName); ! 246: SCSIdisk[i].readonly = false; ! 247: } ! 248: } ! 249: } else { ! 250: SCSIdisk[i].size = 0; ! 251: SCSIdisk[i].dsk = NULL; ! 252: SCSIdisk[i].readonly = false; ! 253: } ! 254: } ! 255: ! 256: ! 257: ! 258: /* INQUIRY response data */ ! 259: #define DEVTYPE_DISK 0x00 /* read/write disks */ ! 260: #define DEVTYPE_TAPE 0x01 /* tapes and other sequential devices */ ! 261: #define DEVTYPE_PRINTER 0x02 /* printers */ ! 262: #define DEVTYPE_PROCESSOR 0x03 /* cpus */ ! 263: #define DEVTYPE_WORM 0x04 /* write-once optical disks */ ! 264: #define DEVTYPE_READONLY 0x05 /* cd-roms */ ! 265: #define DEVTYPE_NOTPRESENT 0x7f /* logical unit not present */ ! 266: ! 267: ! 268: static unsigned char inquiry_bytes[] = ! 269: { ! 270: 0x00, /* 0: device type: see above */ ! 271: 0x00, /* 1: &0x7F - device type qualifier 0x00 unsupported, &0x80 - rmb: 0x00 = nonremovable, 0x80 = removable */ ! 272: 0x01, /* 2: ANSI SCSI standard (first release) compliant */ ! 273: 0x02, /* 3: Response format (format of following data): 0x01 SCSI-1 compliant */ ! 274: 0x31, /* 4: additional length of the following data */ ! 275: 0x00, 0x00, /* 5,6: reserved */ ! 276: 0x1C, /* 7: RelAdr=0, Wbus32=0, Wbus16=0, Sync=1, Linked=1, RSVD=1, CmdQue=0, SftRe=0 */ ! 277: 'P','r','e','v','i','o','u','s', /* 8-15: Vendor ASCII */ ! 278: 'H','D','D',' ',' ',' ',' ',' ', /* 16-23: Model ASCII */ ! 279: ' ',' ',' ',' ',' ',' ',' ',' ', /* 24-31: Blank space ASCII */ ! 280: '0','0','0','0','0','0','0','1', /* 32-39: Revision ASCII */ ! 281: '0','0','0','0','0','0','0','0', /* 40-47: Serial Number ASCII */ ! 282: ' ',' ',' ',' ',' ',' ' /* 48-53: Blank space ASCII */ ! 283: }; ! 284: ! 285: ! 286: Uint8 SCSIdisk_Send_Status(void) { ! 287: SCSIbus.phase = PHASE_MI; ! 288: return SCSIdisk[SCSIbus.target].status; ! 289: } ! 290: ! 291: Uint8 SCSIdisk_Send_Message(void) { ! 292: return SCSIdisk[SCSIbus.target].message; ! 293: } ! 294: ! 295: ! 296: bool SCSIdisk_Select(Uint8 target) { ! 297: ! 298: /* If there is no disk drive present, return timeout true */ ! 299: if (SCSIdisk[target].devtype==DEVTYPE_NONE) { ! 300: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Selection timeout, target = %i", target); ! 301: SCSIbus.phase = PHASE_ST; ! 302: return true; ! 303: } else { ! 304: SCSIbus.target = target; ! 305: return false; ! 306: } ! 307: } ! 308: ! 309: ! 310: void SCSIdisk_Receive_Command(Uint8 *cdb, Uint8 identify) { ! 311: Uint8 lun = 0; ! 312: ! 313: /* Get logical unit number */ ! 314: if (identify&MSG_IDENTIFY_MASK) { /* if identify message is valid */ ! 315: lun = identify&MSG_LUNMASK; /* use lun from identify message */ ! 316: } else { ! 317: lun = (cdb[1]&0xE0)>>5; /* use lun specified in CDB */ ! 318: } ! 319: ! 320: SCSIdisk[SCSIbus.target].lun = lun; ! 321: ! 322: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Opcode = $%02x, target = %i, lun = %i\n", cdb[0], SCSIbus.target,lun); ! 323: ! 324: SCSI_Emulate_Command(cdb); ! 325: } ! 326: ! 327: ! 328: void SCSI_Emulate_Command(Uint8 *cdb) { ! 329: Uint8 opcode = cdb[0]; ! 330: Uint8 target = SCSIbus.target; ! 331: ! 332: /* First check for lun-independent commands */ ! 333: switch (opcode) { ! 334: case CMD_INQUIRY: ! 335: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Inquiry\n"); ! 336: SCSI_Inquiry(cdb); ! 337: break; ! 338: case CMD_REQ_SENSE: ! 339: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Request sense\n"); ! 340: SCSI_RequestSense(cdb); ! 341: break; ! 342: /* Check if the specified lun is valid for our disk */ ! 343: default: ! 344: if (SCSIdisk[target].lun!=LUN_DISK) { ! 345: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Invalid lun! Check condition.\n"); ! 346: SCSIbus.phase = PHASE_ST; ! 347: SCSIdisk[target].status = STAT_CHECK_COND; /* status: check condition */ ! 348: SCSIdisk[target].message = MSG_COMPLETE; /* TODO: CHECK THIS! */ ! 349: SCSIdisk[target].sense.code = SC_INVALID_LUN; ! 350: SCSIdisk[target].sense.valid = false; ! 351: return; ! 352: } ! 353: ! 354: /* Then check for lun-dependent commands */ ! 355: switch(opcode) { ! 356: case CMD_TEST_UNIT_RDY: ! 357: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Test unit ready\n"); ! 358: SCSI_TestUnitReady(cdb); ! 359: break; ! 360: case CMD_READ_CAPACITY1: ! 361: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Read capacity\n"); ! 362: SCSI_ReadCapacity(cdb); ! 363: break; ! 364: case CMD_READ_SECTOR: ! 365: case CMD_READ_SECTOR1: ! 366: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Read sector\n"); ! 367: SCSI_ReadSector(cdb); ! 368: break; ! 369: case CMD_WRITE_SECTOR: ! 370: case CMD_WRITE_SECTOR1: ! 371: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Write sector\n"); ! 372: SCSI_WriteSector(cdb); ! 373: break; ! 374: case CMD_SEEK: ! 375: Log_Printf(LOG_WARN, "SCSI command: Seek\n"); ! 376: abort(); ! 377: break; ! 378: case CMD_SHIP: ! 379: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Ship\n"); ! 380: SCSI_StartStop(cdb); ! 381: break; ! 382: case CMD_MODESELECT: ! 383: Log_Printf(LOG_WARN, "SCSI command: Mode select\n"); ! 384: abort(); ! 385: break; ! 386: case CMD_MODESENSE: ! 387: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Mode sense\n"); ! 388: SCSI_ModeSense(cdb); ! 389: break; ! 390: case CMD_FORMAT_DRIVE: ! 391: Log_Printf(LOG_SCSI_LEVEL, "SCSI command: Format drive\n"); ! 392: SCSI_FormatDrive(cdb); ! 393: break; ! 394: /* as of yet unsupported commands */ ! 395: case CMD_VERIFY_TRACK: ! 396: case CMD_FORMAT_TRACK: ! 397: case CMD_CORRECTION: ! 398: default: ! 399: Log_Printf(LOG_WARN, "SCSI command: Unknown Command (%02X)\n",opcode); ! 400: SCSIdisk[target].status = STAT_CHECK_COND; ! 401: SCSIdisk[target].sense.code = SC_INVALID_CMD; ! 402: SCSIdisk[target].sense.valid = false; ! 403: SCSIbus.phase = PHASE_ST; ! 404: break; ! 405: } ! 406: break; ! 407: } ! 408: ! 409: SCSIdisk[target].message = MSG_COMPLETE; ! 410: ! 411: /* Update the led each time a command is processed */ ! 412: Statusbar_BlinkLed(DEVICE_LED_SCSI); ! 413: } ! 414: ! 415: ! 416: /* Helpers */ ! 417: ! 418: int SCSI_GetCommandLength(Uint8 opcode) { ! 419: Uint8 group_code = (opcode&0xE0)>>5; ! 420: switch (group_code) { ! 421: case 0: return 6; ! 422: case 1: return 10; ! 423: case 5: return 12; ! 424: default: ! 425: Log_Printf(LOG_WARN, "[SCSI] Unimplemented Group Code!"); ! 426: return 6; ! 427: } ! 428: } ! 429: ! 430: int SCSI_GetTransferLength(Uint8 opcode, Uint8 *cdb) ! 431: { ! 432: return opcode < 0x20? ! 433: // class 0 ! 434: cdb[4] : ! 435: // class 1 ! 436: COMMAND_ReadInt16(cdb, 7); ! 437: } ! 438: ! 439: Uint64 SCSI_GetOffset(Uint8 opcode, Uint8 *cdb) ! 440: { ! 441: return opcode < 0x20? ! 442: // class 0 ! 443: (COMMAND_ReadInt24(cdb, 1) & 0x1FFFFF) : ! 444: // class 1 ! 445: COMMAND_ReadInt32(cdb, 2); ! 446: } ! 447: ! 448: // get reserved count for SCSI reply ! 449: int SCSI_GetCount(Uint8 opcode, Uint8 *cdb) ! 450: { ! 451: return opcode < 0x20? ! 452: // class 0 ! 453: ((cdb[4]==0)?0x100:cdb[4]) : ! 454: // class 1 ! 455: COMMAND_ReadInt16(cdb, 7); ! 456: } ! 457: ! 458: static void SCSI_GuessGeometry(Uint32 size, Uint32 *cylinders, Uint32 *heads, Uint32 *sectors) ! 459: { ! 460: Uint32 c,h,s; ! 461: ! 462: for (h=16; h>0; h--) { ! 463: for (s=63; s>15; s--) { ! 464: if ((size%(s*h))==0) { ! 465: c=size/(s*h); ! 466: *cylinders=c; ! 467: *heads=h; ! 468: *sectors=s; ! 469: return; ! 470: } ! 471: } ! 472: } ! 473: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Disk geometry: No valid geometry found! Using default."); ! 474: ! 475: h=16; ! 476: s=63; ! 477: c=size/(s*h); ! 478: if ((size%(s*h))!=0) { ! 479: c+=1; ! 480: } ! 481: *cylinders=c; ! 482: *heads=h; ! 483: *sectors=s; ! 484: } ! 485: ! 486: #define SCSI_SEEK_TIME_HD 20000 /* 20 ms max seek time */ ! 487: #define SCSI_SECTOR_TIME_HD 350 /* 1.4 MB/sec */ ! 488: #define SCSI_SEEK_TIME_FD 200000 /* 200 ms max seek time */ ! 489: #define SCSI_SECTOR_TIME_FD 5500 /* 90 kB/sec */ ! 490: #define SCSI_SEEK_TIME_CD 500000 /* 500 ms max seek time */ ! 491: #define SCSI_SECTOR_TIME_CD 3250 /* 150 kB/sec */ ! 492: ! 493: Sint64 SCSI_Seek_Time(void) { ! 494: Uint8 target = SCSIbus.target; ! 495: Sint64 seektime, seekoffset, disksize; ! 496: ! 497: if (scsi_buffer.disk) { ! 498: switch (SCSIdisk[target].devtype) { ! 499: case DEVTYPE_HARDDISK: ! 500: seektime = SCSI_SEEK_TIME_HD; ! 501: break; ! 502: case DEVTYPE_CD: ! 503: seektime = SCSI_SEEK_TIME_CD; ! 504: break; ! 505: case DEVTYPE_FLOPPY: ! 506: seektime = SCSI_SEEK_TIME_FD; ! 507: break; ! 508: default: ! 509: return 0; ! 510: } ! 511: if (SCSIdisk[target].lba < SCSIdisk[target].lastlba) { ! 512: seekoffset = SCSIdisk[target].lastlba - SCSIdisk[target].lba; ! 513: } else { ! 514: seekoffset = SCSIdisk[target].lba - SCSIdisk[target].lastlba; ! 515: } ! 516: disksize = SCSIdisk[target].size/BLOCKSIZE; ! 517: ! 518: if (disksize <= 0) { /* make sure no zero divide occurs */ ! 519: return 0; ! 520: } ! 521: seektime *= seekoffset; ! 522: seektime /= disksize; ! 523: ! 524: if (seektime > 500000) { ! 525: seektime = 500000; ! 526: } ! 527: ! 528: return seektime; ! 529: } else { ! 530: return 0; ! 531: } ! 532: } ! 533: ! 534: Sint64 SCSI_Sector_Time(void) { ! 535: int target = SCSIbus.target; ! 536: Sint64 sectors = SCSIdisk[target].blockcounter; ! 537: ! 538: if (sectors <= 0) { ! 539: sectors = 1; ! 540: } ! 541: ! 542: if (scsi_buffer.disk) { ! 543: switch (SCSIdisk[target].devtype) { ! 544: case DEVTYPE_HARDDISK: ! 545: return sectors * SCSI_SECTOR_TIME_HD; ! 546: case DEVTYPE_CD: ! 547: return sectors * SCSI_SECTOR_TIME_CD; ! 548: case DEVTYPE_FLOPPY: ! 549: return sectors * SCSI_SECTOR_TIME_FD; ! 550: default: ! 551: return 1000; ! 552: } ! 553: } else { ! 554: return 100; ! 555: } ! 556: } ! 557: ! 558: MODEPAGE SCSI_GetModePage(Uint8 pagecode) { ! 559: Uint8 target = SCSIbus.target; ! 560: ! 561: MODEPAGE page; ! 562: ! 563: switch (pagecode) { ! 564: case 0x00: // operating page ! 565: page.pagesize = 4; ! 566: page.modepage[0] = 0x00; // &0x80: page savable? (not supported!), &0x7F: page code = 0x00 ! 567: page.modepage[1] = 0x02; // page length = 2 ! 568: page.modepage[2] = 0x80; // &0x80: usage bit = 1, &0x10: disable unit attention = 0 ! 569: page.modepage[3] = 0x00; // &0x7F: device type qualifier = 0x00, see inquiry! ! 570: break; ! 571: ! 572: case 0x01: // error recovery page ! 573: page.pagesize = 8; ! 574: page.modepage[0] = 0x01; // &0x80: page savable? (not supported!), &0x7F: page code = 0x01 ! 575: page.modepage[1] = 0x06; // page length = 6 ! 576: page.modepage[2] = 0x00; // AWRE, ARRE, TB, RC, EER, PER, DTE, DCR ! 577: page.modepage[3] = 0x1B; // retry count ! 578: page.modepage[4] = 0x0B; // correction span in bits ! 579: page.modepage[5] = 0x00; // head offset count ! 580: page.modepage[6] = 0x00; // data strobe offset count ! 581: page.modepage[7] = 0xFF; // recovery time limit ! 582: break; ! 583: ! 584: case 0x03: // format device page ! 585: page.pagesize = 0; ! 586: Log_Printf(LOG_WARN, "[SCSI] Mode Sense: Page %02x not yet emulated!\n", pagecode); ! 587: //abort(); ! 588: break; ! 589: ! 590: case 0x04: // rigid disc geometry page ! 591: { ! 592: Uint32 num_sectors = SCSIdisk[target].size/BLOCKSIZE; ! 593: ! 594: Uint32 cylinders, heads, sectors; ! 595: ! 596: SCSI_GuessGeometry(num_sectors, &cylinders, &heads, §ors); ! 597: ! 598: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Disk geometry: %i sectors, %i cylinders, %i heads\n", sectors, cylinders, heads); ! 599: ! 600: page.pagesize = 20; ! 601: page.modepage[0] = 0x04; // &0x80: page savable? (not supported!), &0x7F: page code = 0x04 ! 602: page.modepage[1] = 0x12; ! 603: page.modepage[2] = (cylinders >> 16) & 0xFF; ! 604: page.modepage[3] = (cylinders >> 8) & 0xFF; ! 605: page.modepage[4] = cylinders & 0xFF; ! 606: page.modepage[5] = heads; ! 607: page.modepage[6] = 0x00; // 6,7,8: starting cylinder - write precomp (not supported) ! 608: page.modepage[7] = 0x00; ! 609: page.modepage[8] = 0x00; ! 610: page.modepage[9] = 0x00; // 9,10,11: starting cylinder - reduced write current (not supported) ! 611: page.modepage[10] = 0x00; ! 612: page.modepage[11] = 0x00; ! 613: page.modepage[12] = 0x00; // 12,13: drive step rate (not supported) ! 614: page.modepage[13] = 0x00; ! 615: page.modepage[14] = 0x00; // 14,15,16: loading zone cylinder (not supported) ! 616: page.modepage[15] = 0x00; ! 617: page.modepage[16] = 0x00; ! 618: page.modepage[17] = 0x00; // &0x03: rotational position locking ! 619: page.modepage[18] = 0x00; // rotational position lock offset ! 620: page.modepage[19] = 0x00; // reserved ! 621: } ! 622: break; ! 623: ! 624: case 0x02: // disconnect/reconnect page ! 625: case 0x08: // caching page ! 626: case 0x0C: // notch page ! 627: case 0x0D: // power condition page ! 628: case 0x38: // cache control page ! 629: case 0x3C: // soft ID page (EEPROM) ! 630: page.pagesize = 0; ! 631: Log_Printf(LOG_WARN, "[SCSI] Mode Sense: Page %02x not yet emulated!\n", pagecode); ! 632: //abort(); ! 633: break; ! 634: ! 635: default: ! 636: page.pagesize = 0; ! 637: Log_Printf(LOG_WARN, "[SCSI] Mode Sense: Invalid page code: %02x!\n", pagecode); ! 638: break; ! 639: } ! 640: return page; ! 641: } ! 642: ! 643: ! 644: ! 645: /* SCSI Commands */ ! 646: ! 647: void SCSI_TestUnitReady(Uint8 *cdb) { ! 648: Uint8 target = SCSIbus.target; ! 649: ! 650: if (SCSIdisk[target].devtype!=DEVTYPE_NONE && ! 651: SCSIdisk[target].devtype!=DEVTYPE_HARDDISK && ! 652: SCSIdisk[target].dsk==NULL) { /* Empty drive */ ! 653: SCSIdisk[target].status = STAT_CHECK_COND; ! 654: SCSIdisk[target].sense.code = SC_NOT_READY; ! 655: SCSIbus.phase = PHASE_ST; ! 656: } else { ! 657: SCSIdisk[target].status = STAT_GOOD; ! 658: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 659: SCSIbus.phase = PHASE_ST; ! 660: } ! 661: } ! 662: ! 663: void SCSI_ReadCapacity(Uint8 *cdb) { ! 664: Uint8 target = SCSIbus.target; ! 665: ! 666: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Read disk image: size = %llu byte\n", SCSIdisk[target].size); ! 667: ! 668: Uint32 sectors = (SCSIdisk[target].size / BLOCKSIZE) - 1; /* last LBA */ ! 669: ! 670: static Uint8 scsi_disksize[8]; ! 671: ! 672: scsi_disksize[0] = (sectors >> 24) & 0xFF; ! 673: scsi_disksize[1] = (sectors >> 16) & 0xFF; ! 674: scsi_disksize[2] = (sectors >> 8) & 0xFF; ! 675: scsi_disksize[3] = sectors & 0xFF; ! 676: scsi_disksize[4] = (BLOCKSIZE >> 24) & 0xFF; ! 677: scsi_disksize[5] = (BLOCKSIZE >> 16) & 0xFF; ! 678: scsi_disksize[6] = (BLOCKSIZE >> 8) & 0xFF; ! 679: scsi_disksize[7] = BLOCKSIZE & 0xFF; ! 680: ! 681: memcpy(scsi_buffer.data, scsi_disksize, 8); ! 682: scsi_buffer.limit=scsi_buffer.size=8; ! 683: scsi_buffer.disk=false; ! 684: ! 685: SCSIdisk[target].status = STAT_GOOD; ! 686: SCSIbus.phase = PHASE_DI; ! 687: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 688: SCSIdisk[target].sense.valid = false; ! 689: } ! 690: ! 691: void SCSI_WriteSector(Uint8 *cdb) { ! 692: Uint8 target = SCSIbus.target; ! 693: ! 694: SCSIdisk[target].lastlba = SCSIdisk[target].lba; ! 695: SCSIdisk[target].lba = SCSI_GetOffset(cdb[0], cdb); ! 696: SCSIdisk[target].blockcounter = SCSI_GetCount(cdb[0], cdb); ! 697: ! 698: if (SCSIdisk[target].readonly) { ! 699: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Write sector: Disk is write protected! Check condition."); ! 700: SCSIdisk[target].status = STAT_CHECK_COND; ! 701: SCSIdisk[target].sense.code = SC_WRITE_PROTECT; ! 702: SCSIdisk[target].sense.valid = false; ! 703: SCSIbus.phase = PHASE_ST; ! 704: return; ! 705: } ! 706: scsi_buffer.disk=true; ! 707: scsi_buffer.size=0; ! 708: scsi_buffer.limit=BLOCKSIZE; ! 709: SCSIbus.phase = PHASE_DO; ! 710: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Write sector: %i block(s) at offset %i (blocksize: %i byte)", ! 711: SCSIdisk[target].blockcounter, SCSIdisk[target].lba, BLOCKSIZE); ! 712: } ! 713: ! 714: void scsi_write_sector(void) { ! 715: Uint8 target = SCSIbus.target; ! 716: Uint64 offset = 0; ! 717: ! 718: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Writing block at offset %i (%i blocks remaining).", ! 719: SCSIdisk[target].lba,SCSIdisk[target].blockcounter-1); ! 720: ! 721: offset = ((Uint64)SCSIdisk[target].lba)*BLOCKSIZE; ! 722: ! 723: if (offset < SCSIdisk[target].size) { ! 724: if (ConfigureParams.SCSI.nWriteProtection != WRITEPROT_ON) { ! 725: File_Write(scsi_buffer.data, BLOCKSIZE, offset, SCSIdisk[target].dsk); ! 726: } else { ! 727: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] WARNING: File write disabled!"); ! 728: if(SCSIdisk[target].shadow) { ! 729: if(!(SCSIdisk[target].shadow[SCSIdisk[target].lba])) ! 730: SCSIdisk[target].shadow[SCSIdisk[target].lba] = malloc(BLOCKSIZE); ! 731: memcpy(SCSIdisk[target].shadow[SCSIdisk[target].lba], scsi_buffer.data, BLOCKSIZE); ! 732: } else { ! 733: Uint32 blocks = SCSIdisk[target].size / BLOCKSIZE; ! 734: SCSIdisk[target].shadow = malloc(sizeof(Uint8*) * blocks); ! 735: for(int i = blocks; --i >= 0;) ! 736: SCSIdisk[target].shadow[i] = NULL; ! 737: } ! 738: } ! 739: scsi_buffer.limit=BLOCKSIZE; ! 740: scsi_buffer.size=0; ! 741: ! 742: SCSIdisk[target].status = STAT_GOOD; ! 743: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 744: SCSIdisk[target].sense.valid = false; ! 745: SCSIdisk[target].lba++; ! 746: SCSIdisk[target].blockcounter--; ! 747: if (SCSIdisk[target].blockcounter==0) { ! 748: SCSIbus.phase = PHASE_ST; ! 749: } ! 750: } else { ! 751: SCSIdisk[target].status = STAT_CHECK_COND; ! 752: SCSIdisk[target].sense.code = SC_INVALID_LBA; ! 753: SCSIdisk[target].sense.valid = true; ! 754: SCSIdisk[target].sense.info = SCSIdisk[target].lba; ! 755: SCSIbus.phase = PHASE_ST; ! 756: } ! 757: } ! 758: ! 759: void SCSIdisk_Receive_Data(Uint8 val) { ! 760: /* Receive one byte. If the transfer is complete, set status phase ! 761: * and write the buffer contents to the disk. */ ! 762: scsi_buffer.data[scsi_buffer.size]=val; ! 763: scsi_buffer.size++; ! 764: if (scsi_buffer.size==scsi_buffer.limit) { ! 765: if (scsi_buffer.disk==true) { ! 766: scsi_write_sector(); /* sets status phase if done or error */ ! 767: } else { ! 768: SCSIbus.phase = PHASE_ST; ! 769: } ! 770: } ! 771: } ! 772: ! 773: ! 774: void SCSI_ReadSector(Uint8 *cdb) { ! 775: Uint8 target = SCSIbus.target; ! 776: ! 777: SCSIdisk[target].lastlba = SCSIdisk[target].lba; ! 778: SCSIdisk[target].lba = SCSI_GetOffset(cdb[0], cdb); ! 779: SCSIdisk[target].blockcounter = SCSI_GetCount(cdb[0], cdb); ! 780: scsi_buffer.disk=true; ! 781: scsi_buffer.size=0; ! 782: SCSIbus.phase = PHASE_DI; ! 783: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Read sector: %i block(s) at offset %i (blocksize: %i byte)", ! 784: SCSIdisk[target].blockcounter, SCSIdisk[target].lba, BLOCKSIZE); ! 785: scsi_read_sector(); ! 786: } ! 787: ! 788: void scsi_read_sector(void) { ! 789: Uint8 target = SCSIbus.target; ! 790: Uint64 offset = 0; ! 791: ! 792: if (SCSIdisk[target].blockcounter==0) { ! 793: SCSIbus.phase = PHASE_ST; ! 794: return; ! 795: } ! 796: ! 797: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Reading block at offset %i (%i blocks remaining).", ! 798: SCSIdisk[target].lba,SCSIdisk[target].blockcounter-1); ! 799: ! 800: offset = ((Uint64)SCSIdisk[target].lba)*BLOCKSIZE; ! 801: ! 802: if (offset < SCSIdisk[target].size) { ! 803: if (SCSIdisk[target].shadow && SCSIdisk[target].shadow[SCSIdisk[target].lba]) { ! 804: memcpy(scsi_buffer.data, SCSIdisk[target].shadow[SCSIdisk[target].lba], BLOCKSIZE); ! 805: } else { ! 806: File_Read(scsi_buffer.data, BLOCKSIZE, offset, SCSIdisk[target].dsk); ! 807: } ! 808: scsi_buffer.limit=scsi_buffer.size=BLOCKSIZE; ! 809: ! 810: SCSIdisk[target].status = STAT_GOOD; ! 811: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 812: SCSIdisk[target].sense.valid = false; ! 813: SCSIdisk[target].lba++; ! 814: SCSIdisk[target].blockcounter--; ! 815: } else { ! 816: SCSIdisk[target].status = STAT_CHECK_COND; ! 817: SCSIdisk[target].sense.code = SC_INVALID_LBA; ! 818: SCSIdisk[target].sense.valid = true; ! 819: SCSIdisk[target].sense.info = SCSIdisk[target].lba; ! 820: SCSIbus.phase = PHASE_ST; ! 821: } ! 822: } ! 823: ! 824: Uint8 SCSIdisk_Send_Data(void) { ! 825: /* Send one byte. If the transfer is complete, set status phase */ ! 826: Uint8 val=scsi_buffer.data[scsi_buffer.limit-scsi_buffer.size]; ! 827: scsi_buffer.size--; ! 828: if (scsi_buffer.size==0) { ! 829: if (scsi_buffer.disk==true) { ! 830: scsi_read_sector(); /* sets status phase if done or error */ ! 831: } else { ! 832: SCSIbus.phase = PHASE_ST; ! 833: } ! 834: } ! 835: return val; ! 836: } ! 837: ! 838: ! 839: void SCSI_Inquiry (Uint8 *cdb) { ! 840: Uint8 target = SCSIbus.target; ! 841: ! 842: switch (SCSIdisk[target].devtype) { ! 843: case DEVTYPE_HARDDISK: ! 844: inquiry_bytes[0] = DEVTYPE_DISK; ! 845: inquiry_bytes[1] &= ~0x80; ! 846: inquiry_bytes[16] = 'H'; ! 847: inquiry_bytes[17] = 'D'; ! 848: inquiry_bytes[18] = 'D'; ! 849: inquiry_bytes[19] = ' '; ! 850: inquiry_bytes[20] = ' '; ! 851: inquiry_bytes[21] = ' '; ! 852: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Disk is HDD\n"); ! 853: break; ! 854: case DEVTYPE_CD: ! 855: inquiry_bytes[0] = DEVTYPE_READONLY; ! 856: inquiry_bytes[1] |= 0x80; ! 857: inquiry_bytes[16] = 'C'; ! 858: inquiry_bytes[17] = 'D'; ! 859: inquiry_bytes[18] = '-'; ! 860: inquiry_bytes[19] = 'R'; ! 861: inquiry_bytes[20] = 'O'; ! 862: inquiry_bytes[21] = 'M'; ! 863: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Disk is CD-ROM\n"); ! 864: break; ! 865: case DEVTYPE_FLOPPY: ! 866: inquiry_bytes[0] = DEVTYPE_DISK; ! 867: inquiry_bytes[1] |= 0x80; ! 868: inquiry_bytes[16] = 'F'; ! 869: inquiry_bytes[17] = 'L'; ! 870: inquiry_bytes[18] = 'O'; ! 871: inquiry_bytes[19] = 'P'; ! 872: inquiry_bytes[20] = 'P'; ! 873: inquiry_bytes[21] = 'Y'; ! 874: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Disk is Floppy\n"); ! 875: break; ! 876: ! 877: default: ! 878: break; ! 879: } ! 880: ! 881: if (SCSIdisk[target].lun!=LUN_DISK) { ! 882: inquiry_bytes[0] = DEVTYPE_NOTPRESENT; ! 883: } ! 884: ! 885: scsi_buffer.disk=false; ! 886: scsi_buffer.limit = scsi_buffer.size = SCSI_GetTransferLength(cdb[0], cdb); ! 887: if (scsi_buffer.limit > (int)sizeof(inquiry_bytes)) { ! 888: scsi_buffer.limit = scsi_buffer.size = sizeof(inquiry_bytes); ! 889: } ! 890: memcpy(scsi_buffer.data, inquiry_bytes, scsi_buffer.limit); ! 891: ! 892: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Inquiry data length: %d", scsi_buffer.limit); ! 893: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Inquiry Data: %c,%c,%c,%c,%c,%c,%c,%c\n",scsi_buffer.data[8], ! 894: scsi_buffer.data[9],scsi_buffer.data[10],scsi_buffer.data[11],scsi_buffer.data[12], ! 895: scsi_buffer.data[13],scsi_buffer.data[14],scsi_buffer.data[15]); ! 896: ! 897: SCSIdisk[target].status = STAT_GOOD; ! 898: SCSIbus.phase = PHASE_DI; ! 899: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 900: SCSIdisk[target].sense.valid = false; ! 901: } ! 902: ! 903: ! 904: void SCSI_StartStop(Uint8 *cdb) { ! 905: Uint8 target = SCSIbus.target; ! 906: ! 907: switch (cdb[4]&0x03) { ! 908: case 0: ! 909: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Stop disk %i", target); ! 910: break; ! 911: case 1: ! 912: Log_Printf(LOG_SCSI_LEVEL, "[SCSI] Start disk %i", target); ! 913: break; ! 914: case 2: ! 915: Log_Printf(LOG_WARN, "[SCSI] Eject disk %i", target); ! 916: if (SCSIdisk[target].devtype!=DEVTYPE_HARDDISK) { ! 917: SCSI_EjectDisk(target); ! 918: Statusbar_AddMessage("Ejecting SCSI media.", 0); ! 919: } ! 920: break; ! 921: default: ! 922: Log_Printf(LOG_WARN, "[SCSI] Invalid start/stop"); ! 923: break; ! 924: } ! 925: ! 926: SCSIdisk[target].status = STAT_GOOD; ! 927: SCSIbus.phase = PHASE_ST; ! 928: } ! 929: ! 930: ! 931: void SCSI_RequestSense(Uint8 *cdb) { ! 932: Uint8 target = SCSIbus.target; ! 933: ! 934: int nRetLen; ! 935: Uint8 retbuf[22]; ! 936: ! 937: nRetLen = SCSI_GetCount(cdb[0], cdb); ! 938: ! 939: if ((nRetLen<4 && nRetLen!=0) || nRetLen>22) { ! 940: Log_Printf(LOG_WARN, "[SCSI] *** Strange REQUEST SENSE *** len=%d!",nRetLen); ! 941: } ! 942: ! 943: /* Limit to sane length */ ! 944: if (nRetLen <= 0) { ! 945: nRetLen = 4; ! 946: } else if (nRetLen > 22) { ! 947: nRetLen = 22; ! 948: } ! 949: ! 950: Log_Printf(LOG_WARN, "[SCSI] REQ SENSE size = %d %s at %d", nRetLen,__FILE__,__LINE__); ! 951: ! 952: memset(retbuf, 0, nRetLen); ! 953: ! 954: retbuf[0] = 0x70; ! 955: if (SCSIdisk[target].sense.valid) { ! 956: retbuf[0] |= 0x80; ! 957: retbuf[3] = SCSIdisk[target].sense.info >> 24; ! 958: retbuf[4] = SCSIdisk[target].sense.info >> 16; ! 959: retbuf[5] = SCSIdisk[target].sense.info >> 8; ! 960: retbuf[6] = SCSIdisk[target].sense.info; ! 961: } ! 962: switch (SCSIdisk[target].sense.code) { ! 963: case SC_NO_ERROR: ! 964: SCSIdisk[target].sense.key = SK_NOSENSE; ! 965: break; ! 966: case SC_NOT_READY: ! 967: SCSIdisk[target].sense.key = SK_NOTREADY; ! 968: break; ! 969: case SC_WRITE_FAULT: ! 970: case SC_INVALID_CMD: ! 971: case SC_INVALID_LBA: ! 972: case SC_INVALID_CDB: ! 973: case SC_INVALID_LUN: ! 974: SCSIdisk[target].sense.key = SK_ILLEGAL_REQ; ! 975: break; ! 976: case SC_WRITE_PROTECT: ! 977: SCSIdisk[target].sense.key = SK_DATAPROTECT; ! 978: break; ! 979: case SC_NO_SECTOR: ! 980: default: ! 981: SCSIdisk[target].sense.key = SK_HARDWARE; ! 982: break; ! 983: } ! 984: retbuf[2] = SCSIdisk[target].sense.key; ! 985: retbuf[7] = 14; ! 986: retbuf[12] = SCSIdisk[target].sense.code; ! 987: ! 988: scsi_buffer.size=scsi_buffer.limit=nRetLen; ! 989: memcpy(scsi_buffer.data, retbuf, scsi_buffer.limit); ! 990: scsi_buffer.disk=false; ! 991: ! 992: SCSIdisk[target].status = STAT_GOOD; ! 993: SCSIbus.phase = PHASE_DI; ! 994: } ! 995: ! 996: ! 997: void SCSI_ModeSense(Uint8 *cdb) { ! 998: Uint8 target = SCSIbus.target; ! 999: ! 1000: Uint8 retbuf[256]; ! 1001: MODEPAGE page; ! 1002: ! 1003: Uint32 sectors = SCSIdisk[target].size / BLOCKSIZE; ! 1004: ! 1005: Uint8 pagecontrol = (cdb[2] & 0x0C) >> 6; ! 1006: Uint8 pagecode = cdb[2] & 0x3F; ! 1007: Uint8 dbd = cdb[1] & 0x08; // disable block descriptor ! 1008: ! 1009: Log_Printf(LOG_WARN, "[SCSI] Mode Sense: page = %02x, page_control = %i, %s\n", pagecode, pagecontrol, dbd == 0x08 ? "block descriptor disabled" : "block descriptor enabled"); ! 1010: ! 1011: /* Header */ ! 1012: retbuf[0] = 0x00; // length of following data ! 1013: retbuf[1] = 0x00; // medium type (always 0) ! 1014: retbuf[2] = SCSIdisk[target].readonly ? 0x80 : 0x00; // if media is read-only 0x80, else 0x00 ! 1015: retbuf[3] = 0x08; // block descriptor length ! 1016: ! 1017: /* Block descriptor data */ ! 1018: Uint8 header_size = 4; ! 1019: if (!dbd) { ! 1020: retbuf[4] = 0x00; // media density code ! 1021: retbuf[5] = sectors >> 16; // Number of blocks, high (?) ! 1022: retbuf[6] = sectors >> 8; // Number of blocks, med (?) ! 1023: retbuf[7] = sectors; // Number of blocks, low (?) ! 1024: retbuf[8] = 0x00; // reserved ! 1025: retbuf[9] = (BLOCKSIZE >> 16) & 0xFF; // Block size in bytes, high ! 1026: retbuf[10] = (BLOCKSIZE >> 8) & 0xFF; // Block size in bytes, med ! 1027: retbuf[11] = BLOCKSIZE & 0xFF; // Block size in bytes, low ! 1028: header_size = 12; ! 1029: Log_Printf(LOG_WARN, "[SCSI] Mode Sense: Block descriptor data: %s, size = %i blocks, blocksize = %i byte\n", ! 1030: SCSIdisk[target].readonly ? "disk is read-only" : "disk is read/write" , sectors, BLOCKSIZE); ! 1031: } ! 1032: retbuf[0] = header_size - 1; ! 1033: ! 1034: /* Mode Pages */ ! 1035: if (pagecode == 0x3F) { // return all pages! ! 1036: Uint8 offset = header_size; ! 1037: Uint8 counter; ! 1038: for (pagecode = 0; pagecode < 0x3F; pagecode++) { ! 1039: page = SCSI_GetModePage(pagecode); ! 1040: switch (pagecontrol) { ! 1041: case 0: // current values (not supported, using default values) ! 1042: memcpy(page.current, page.modepage, page.pagesize); ! 1043: for (counter = 0; counter < page.pagesize; counter++) { ! 1044: retbuf[counter+offset] = page.current[counter]; ! 1045: } ! 1046: break; ! 1047: case 1: // changeable values (not supported, all 0) ! 1048: memset(page.changeable, 0x00, page.pagesize); ! 1049: for (counter = 0; counter < page.pagesize; counter++) { ! 1050: retbuf[counter+offset] = page.changeable[counter]; ! 1051: } ! 1052: break; ! 1053: case 2: // default values ! 1054: for (counter = 0; counter < page.pagesize; counter++) { ! 1055: retbuf[counter+offset] = page.modepage[counter]; ! 1056: } ! 1057: break; ! 1058: case 3: // saved values (not supported, using default values) ! 1059: memcpy(page.saved, page.modepage, page.pagesize); ! 1060: for (counter = 0; counter < page.pagesize; counter++) { ! 1061: retbuf[counter+offset] = page.saved[counter]; ! 1062: } ! 1063: break; ! 1064: ! 1065: default: ! 1066: break; ! 1067: } ! 1068: offset += page.pagesize; ! 1069: retbuf[0] += page.pagesize; ! 1070: } ! 1071: } else { // return only single requested page ! 1072: page = SCSI_GetModePage(pagecode); ! 1073: ! 1074: Uint8 counter; ! 1075: switch (pagecontrol) { ! 1076: case 0: // current values (not supported, using default values) ! 1077: memcpy(page.current, page.modepage, page.pagesize); ! 1078: for (counter = 0; counter < page.pagesize; counter++) { ! 1079: retbuf[counter+header_size] = page.current[counter]; ! 1080: } ! 1081: break; ! 1082: case 1: // changeable values (not supported, all 0) ! 1083: memset(page.changeable, 0x00, page.pagesize); ! 1084: for (counter = 0; counter < page.pagesize; counter++) { ! 1085: retbuf[counter+header_size] = page.changeable[counter]; ! 1086: } ! 1087: break; ! 1088: case 2: // default values ! 1089: for (counter = 0; counter < page.pagesize; counter++) { ! 1090: retbuf[counter+header_size] = page.modepage[counter]; ! 1091: } ! 1092: break; ! 1093: case 3: // saved values (not supported, using default values) ! 1094: memcpy(page.saved, page.modepage, page.pagesize); ! 1095: for (counter = 0; counter < page.pagesize; counter++) { ! 1096: retbuf[counter+header_size] = page.saved[counter]; ! 1097: } ! 1098: break; ! 1099: ! 1100: default: ! 1101: break; ! 1102: } ! 1103: ! 1104: retbuf[0] += page.pagesize; ! 1105: } ! 1106: ! 1107: scsi_buffer.disk=false; ! 1108: scsi_buffer.limit = scsi_buffer.size = retbuf[0]+1; ! 1109: if (scsi_buffer.limit > SCSI_GetTransferLength(cdb[0], cdb)) { ! 1110: scsi_buffer.limit = scsi_buffer.size = SCSI_GetTransferLength(cdb[0], cdb); ! 1111: } ! 1112: memcpy(scsi_buffer.data, retbuf, scsi_buffer.limit); ! 1113: ! 1114: SCSIdisk[target].status = STAT_GOOD; ! 1115: SCSIbus.phase = PHASE_DI; ! 1116: SCSIdisk[target].sense.code = SC_NO_ERROR; ! 1117: SCSIdisk[target].sense.valid = false; ! 1118: } ! 1119: ! 1120: ! 1121: void SCSI_FormatDrive(Uint8 *cdb) { ! 1122: Uint8 format_data = cdb[1]&0x10; ! 1123: ! 1124: Log_Printf(LOG_WARN, "[SCSI] Format drive command with parameters %02X\n",cdb[1]&0x1F); ! 1125: ! 1126: if (format_data) { ! 1127: Log_Printf(LOG_WARN, "[SCSI] Format drive with format data unsupported!\n"); ! 1128: abort(); ! 1129: } else { ! 1130: SCSIdisk[SCSIbus.target].status = STAT_GOOD; ! 1131: SCSIbus.phase = PHASE_ST; ! 1132: } ! 1133: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.