Annotation of previous_trunk/src/scsi.c, revision 1.1

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, &sectors);
        !           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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.