Annotation of previous/src/scsi.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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