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