Annotation of previous_trunk/src/scsi.c, revision 1.1.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.