1 /*****************************************************************************
2 ** $Source: /cygdrive/d/Private/_SVNROOT/bluemsx/blueMSX/Src/IoDevice/ScsiDevice.c,v $
3 **
4 ** $Revision: 1.10 $
5 **
6 ** $Date: 2007-03-25 17:05:07 $
7 **
8 ** More info: http://www.bluemsx.com
9 **
10 ** Copyright (C) 2003-2007 Daniel Vik, white cat
11 **
12 ** This program is free software; you can redistribute it and/or modify
13 ** it under the terms of the GNU General Public License as published by
14 ** the Free Software Foundation; either version 2 of the License, or
15 ** (at your option) any later version.
16 **
17 ** This program is distributed in the hope that it will be useful,
18 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 ** GNU General Public License for more details.
21 **
22 ** You should have received a copy of the GNU General Public License
23 ** along with this program; if not, write to the Free Software
24 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 **
26 ******************************************************************************
27 */
28 /*
29  * Notes:
30  *  It follows the SCSI1(CCS) standard or the SCSI2 standard.
31  *  Only the direct access device is supported now.
32  *  Message system might be imperfect.
33  */
34 #include "ScsiDevice.h"
35 #include "ArchCdrom.h"
36 #include "ScsiDefs.h"
37 #include "Disk.h"
38 #include "Board.h"
39 #include "FileHistory.h"
40 #include "Led.h"
41 #include "Properties.h"
42 #include "SaveState.h"
43 #include <stdlib.h>
44 #include <string.h>
45 
46 #define USE_SPECIALCOMMAND
47 
48 // Medium type (value like LS-120)
49 #define MT_UNKNOWN      0x00
50 #define MT_2DD_UN       0x10
51 #define MT_2DD          0x11
52 #define MT_2HD_UN       0x20
53 #define MT_2HD_12_98    0x22
54 #define MT_2HD_12       0x23
55 #define MT_2HD_144      0x24
56 #define MT_LS120        0x31
57 #define MT_NO_DISK      0x70
58 #define MT_DOOR_OPEN    0x71
59 #define MT_FMT_ERROR    0x72
60 
61 struct SCSIDEVICE {
62     int diskId;
63     int scsiId;             // SCSI ID 0..7
64     int deviceType;
65     int mode;
66     int enabled;
67     int reset;              // Unit Attention
68     int motor;              // Reserved
69     int keycode;            // Sense key, ASC, ASCQ
70     int inserted;
71     int changed;            // Enhanced change flag for MEGA-SCSI driver
72     int changeCheck2;       // Disk change control flag
73     int sector;
74     int sectorSize;
75     int length;
76     int message;
77     int lun;
78     ArchCdrom* cdrom;
79     UInt8 cdb[12];          // Command Descriptor Block
80     UInt8* buffer;
81     char* productName;
82     FileProperties disk;
83 };
84 
85 static const UInt8 inqdata[36] = {
86        0,   // bit5-0 device type code.
87        0,   // bit7 = 1 removable device
88        2,   // bit7,6 ISO version. bit5,4,3 ECMA version.
89             // bit2,1,0 ANSI Version (001=SCSI1, 010=SCSI2)
90        2,   // bit7 AENC. bit6 TrmIOP.
91             // bit3-0 Response Data Format. (0000=SCSI1, 0001=CCS, 0010=SCSI2)
92       51,   // addtional length
93        0, 0,// reserved
94        0,   // bit7 RelAdr, bit6 WBus32, bit5 Wbus16, bit4 Sync, bit3 Linked,
95             // bit2 reseved bit1 CmdQue, bit0 SftRe
96      'b', 'l', 'u', 'e', 'M', 'S', 'X', ' ',    // vendor ID (8bytes)
97      'S', 'C', 'S', 'I', '2', ' ', 'H', 'a',    // product ID (16bytes)
98      'r', 'd', 'd', 'i', 's', 'k', ' ', ' ',
99      '0', '1', '0', 'a' };                  // product version (ASCII 4bytes)
100 
101 static const char sdt_name[10][10] =
102 {
103     "Tape      ",
104     "Printer   ",
105     "Processor ",
106     "WORM      ",
107     "CD-ROM    ",
108     "Scanner   ",
109     "MO        ",
110     "Jukebox   ",
111     "COMM      ",
112     "???       "
113 };
114 
115 // for FDSFORM.COM
116 static const char fds120[28]  = "IODATA  LS-120 COSM     0001";
117 
118 /*
119     Log output routine for debug
120 */
121 #ifdef SCSIDEBUG
122 
123 static int logNumber = 0;
124 static FILE* scsiLog = NULL;
125 
scsiDeviceLogCreate()126 FILE* scsiDeviceLogCreate()
127 {
128     if (!logNumber) {
129         scsiLog = fopen(SCSIDEBUG, "w");
130     }
131     logNumber++;
132     return scsiLog;
133 }
134 
scsiDeviceLogFlush()135 void scsiDeviceLogFlush()
136 {
137     fflush(scsiLog);
138 }
139 
scsiDeviceLogClose()140 void scsiDeviceLogClose()
141 {
142     logNumber--;
143     if (!logNumber) {
144         fclose(scsiLog);
145     }
146 }
147 
148 #endif
149 
scsiDeviceCreate(int scsiId,int diskId,UInt8 * buf,char * name,int type,int mode,CdromXferCompCb xferCompCb,void * ref)150 SCSIDEVICE* scsiDeviceCreate(int scsiId, int diskId, UInt8* buf, char* name,
151                   int type, int mode, CdromXferCompCb xferCompCb, void* ref)
152 {
153     SCSIDEVICE* scsi = malloc(sizeof(SCSIDEVICE));
154 
155     scsi->scsiId        = scsiId;
156     scsi->diskId        = diskId;
157     scsi->buffer        = buf;
158     scsi->productName   = name;
159     scsi->deviceType    = type;
160     scsi->mode          = mode;
161     scsi->enabled       = 1;
162     scsi->sectorSize    = 512;
163     scsi->cdrom         = NULL;
164 /*
165     scsi->disk.fileName[0] = 0;
166     scsi->disk.fileNameInZip[0] = 0;
167     scsi->disk.directory[0] = 0;
168     scsi->disk.extensionFilter = 0;
169     scsi->disk.type = 0;
170 */
171     if (type == SDT_CDROM) {
172         scsi->sectorSize = 2048;
173         scsi->cdrom = archCdromCreate(xferCompCb, ref);
174         if (scsi->cdrom == NULL) {
175             scsi->enabled = 0;
176         }
177     }
178     scsiDeviceReset(scsi);
179     return scsi;
180 }
181 
scsiDeviceDestroy(SCSIDEVICE * scsi)182 void scsiDeviceDestroy(SCSIDEVICE* scsi)
183 {
184     SCSILOG1("hdd %d: close\n", scsi->scsiId);
185     if (scsi->deviceType == SDT_CDROM) {
186         archCdromDestroy(scsi->cdrom);
187     }
188     free(scsi);
189 }
190 
scsiDeviceReset(SCSIDEVICE * scsi)191 void scsiDeviceReset(SCSIDEVICE* scsi)
192 {
193     if (scsi->deviceType == SDT_CDROM) {
194         archCdromHwReset(scsi->cdrom);
195     }
196     scsi->changed       = 0;
197     scsi->keycode       = 0;
198     scsi->sector        = 0;
199     scsi->length        = 0;
200     scsi->motor         = 1;
201     scsi->changeCheck2  = 1;    // the first use always
202     scsi->reset         = (scsi->mode & MODE_UNITATTENTION) ? 1 : 0;
203 
204     scsi->disk = propGetGlobalProperties()->media.disks[scsi->diskId];
205     scsi->inserted   = (strlen(scsi->disk.fileName) > 0);
206     if (scsi->inserted) {
207         SCSILOG1("hdd %d: \n", scsi->scsiId);
208         SCSILOG1("filename: %s\n", scsi->disk.fileName);
209         SCSILOG1("     zip: %s\n", scsi->disk.fileNameInZip);
210     }
211     else if ((scsi->mode & MODE_NOVAXIS) && scsi->deviceType != SDT_CDROM) {
212         scsi->enabled = 0;
213     }
214 }
215 
scsiDeviceBusReset(SCSIDEVICE * scsi)216 void scsiDeviceBusReset(SCSIDEVICE* scsi)
217 {
218     SCSILOG1("SCSI %d: bus reset\n", scsi->scsiId);
219     scsi->keycode = 0;
220     scsi->reset = (scsi->mode & MODE_UNITATTENTION) ? 1 : 0;
221     if (scsi->deviceType == SDT_CDROM) {
222         archCdromBusReset(scsi->cdrom);
223     }
224 }
225 
scsiDeviceDisconnect(SCSIDEVICE * scsi)226 void scsiDeviceDisconnect(SCSIDEVICE* scsi)
227 {
228     if (scsi->deviceType != SDT_CDROM) {
229         ledSetHd(0);
230     } else {
231         archCdromDisconnect(scsi->cdrom);
232     }
233 }
234 
scsiDeviceEnable(SCSIDEVICE * scsi,int enable)235 void scsiDeviceEnable(SCSIDEVICE* scsi, int enable)
236 {
237     scsi->enabled = enable;
238 }
239 
240 // Check the initiator in the call origin.
scsiDeviceSelection(SCSIDEVICE * scsi)241 int scsiDeviceSelection(SCSIDEVICE* scsi)
242 {
243     scsi->lun = 0;
244     if (scsi->mode & MODE_REMOVABLE) {
245         if (!scsi->enabled &&
246            (scsi->mode & MODE_NOVAXIS) && scsi->deviceType != SDT_CDROM) {
247             scsi->enabled = diskPresent(scsi->diskId) ? 1 : 0;
248         }
249         return scsi->enabled;
250     }
251     return scsi->enabled && diskPresent(scsi->diskId);
252 }
253 
scsiDeviceGetReady(SCSIDEVICE * scsi)254 static int scsiDeviceGetReady(SCSIDEVICE* scsi)
255 {
256     if (diskPresent(scsi->diskId)) {
257         return 1;
258     }
259     scsi->keycode = SENSE_MEDIUM_NOT_PRESENT;
260     return 0;
261 }
262 
scsiDeviceDiskChanged(SCSIDEVICE * scsi)263 static int scsiDeviceDiskChanged(SCSIDEVICE* scsi)
264 {
265     FileProperties* pDisk;
266     int changed = diskChanged(scsi->diskId);
267 
268     if (changed) {
269         scsi->motor = 1;
270         pDisk = &propGetGlobalProperties()->media.disks[scsi->diskId];
271 
272         if (scsi->changeCheck2) {
273             scsi->changeCheck2 = 0;
274             if (scsi->inserted &&
275                (strcmp(scsi->disk.fileName, pDisk->fileName) == 0) &&
276                (strcmp(scsi->disk.fileNameInZip, pDisk->fileNameInZip) == 0)) {
277                 SCSILOG("Disk change invalidity\n\n");
278                 return 0;
279             }
280         }
281         scsi->changed  = 1;
282         scsi->disk = *pDisk;
283         scsi->inserted = 1;
284 
285         SCSILOG1("hdd %d: disk change\n", scsi->scsiId);
286         SCSILOG1("filename: %s\n", scsi->disk.fileName);
287         SCSILOG1("     zip: %s\n", scsi->disk.fileNameInZip);
288     } else {
289         if (scsi->inserted & !diskPresent(scsi->diskId)) {
290             scsi->inserted = 0;
291             scsi->motor    = 0;
292             scsi->changed  = 1;
293             changed        = 1;
294         }
295     }
296 
297     if (changed && (scsi->mode & MODE_UNITATTENTION)) {
298         scsi->reset = 1;
299     }
300     return changed;
301 }
302 
scsiDeviceTestUnitReady(SCSIDEVICE * scsi)303 static void scsiDeviceTestUnitReady(SCSIDEVICE* scsi)
304 {
305     if ((scsi->mode & MODE_NOVAXIS) == 0) {
306         if (scsiDeviceGetReady(scsi) && scsi->changed && (scsi->mode & MODE_MEGASCSI)) {
307             // Disk change is surely sent for the driver of MEGA-SCSI.
308             scsi->keycode = SENSE_POWER_ON;
309         }
310     }
311     scsi->changed = 0;
312 }
313 
scsiDeviceStartStopUnit(SCSIDEVICE * scsi)314 static void scsiDeviceStartStopUnit(SCSIDEVICE* scsi)
315 {
316     FileProperties* disk = &propGetGlobalProperties()->media.disks[scsi->diskId];
317 
318     switch (scsi->cdb[4]) {
319     case 2:
320         // Eject
321         if (diskPresent(scsi->diskId)) {
322             disk->fileName[0] = 0;
323             disk->fileNameInZip[0] = 0;
324             updateExtendedDiskName(scsi->diskId, disk->fileName, disk->fileNameInZip);
325             boardChangeDiskette(scsi->diskId, NULL, NULL);
326             SCSILOG1("hdd %d eject\n", scsi->scsiId);
327         }
328         break;
329     case 3:
330         // Insert
331         if (!diskPresent(scsi->diskId)) {
332             *disk = scsi->disk;
333             updateExtendedDiskName(scsi->diskId, disk->fileName, disk->fileNameInZip);
334             boardChangeDiskette(scsi->diskId, disk->fileName, disk->fileNameInZip);
335             SCSILOG1("hdd %d insert\n", scsi->scsiId);
336         }
337         break;
338     }
339     scsi->motor = scsi->cdb[4] & 1;
340     SCSILOG2("hdd %d motor: %d\n", scsi->scsiId, scsi->motor);
341 }
342 
scsiDeviceInquiry(SCSIDEVICE * scsi)343 static int scsiDeviceInquiry(SCSIDEVICE* scsi)
344 {
345     int total       = _diskGetTotalSectors(scsi->diskId);
346     int length      = scsi->length;
347     UInt8* buffer   = scsi->buffer;
348     UInt8 type      = (UInt8)(scsi->deviceType & 0xff);
349     UInt8 removable;
350     const char* fileName;
351     int i;
352     int fdsmode = (scsi->mode & MODE_FDS120) && (total > 0) && (total <= 2880);
353 
354     if (length == 0) return 0;
355 
356     if (fdsmode) {
357         memcpy(buffer + 2, inqdata + 2, 6);
358         memcpy(buffer + 8, fds120, 28);
359         removable = 0x80;
360         if (type != SDT_DirectAccess) {
361             type = SDT_Processor;
362         }
363     } else {
364         memcpy(buffer + 2, inqdata + 2, 34);
365         removable = (scsi->mode & MODE_REMOVABLE) ? 0x80 : 0;
366 
367         if (scsi->productName == NULL) {
368             int dt = scsi->deviceType;
369             if (dt != SDT_DirectAccess) {
370                 if (dt > SDT_Communications) {
371                     dt = SDT_Communications + 1;
372                 }
373                 --dt;
374                 memcpy(buffer + 22, sdt_name[dt], 10);
375             }
376         } else {
377             memcpy(buffer + 16, scsi->productName, 16);
378         }
379     }
380 
381     buffer[0] = type;
382     buffer[1] = removable;
383 
384     if (!(scsi->mode & BIT_SCSI2)) {
385         buffer[2]  = 1;
386         buffer[3]  = 1;
387         if (!fdsmode) buffer[20] = '1';
388     } else {
389         if (scsi->mode & BIT_SCSI3) {
390             buffer[2]  = 5;
391             if (!fdsmode) buffer[20] = '3';
392         }
393     }
394 
395     if ((scsi->mode & MODE_CHECK2) && !fdsmode) {
396         buffer[35] = 'A';
397     }
398     if (scsi->mode & BIT_SCSI3) {
399         if (length > 96) length = 96;
400         buffer[4] = 91;
401         if (length > 56) {
402             memset(buffer + 56, 0, 40);
403             buffer[58] = 0x03;
404             buffer[60] = 0x01;
405             buffer[61] = 0x80;
406         }
407     } else {
408         if (length > 56) length = 56;
409     }
410 
411     if (length > 36){
412         buffer += 36;
413         memset(buffer, ' ', 20);
414         fileName = strlen(scsi->disk.fileNameInZip) ? scsi->disk.fileNameInZip : scsi->disk.fileName;
415         fileName = stripPath(fileName);
416         for (i = 0; i < 20; ++i) {
417             if (*fileName == 0) {
418                 break;
419             }
420             *buffer = *fileName;
421             ++buffer;
422             ++fileName;
423         }
424     }
425     return length;
426 }
427 
scsiDeviceModeSense(SCSIDEVICE * scsi)428 static int scsiDeviceModeSense(SCSIDEVICE* scsi)
429 {
430     int length  = scsi->length;
431 
432     if ((length > 0) && (scsi->cdb[2] == 3)) {
433         UInt8* buffer   = scsi->buffer;
434         int total       = _diskGetTotalSectors(scsi->diskId);
435         int media       = MT_UNKNOWN;
436         int sectors     = 64;
437         int blockLength = scsi->sectorSize >> 8;
438         int tracks      = 8;
439         int size        = 4 + 24;
440         int removable   = scsi->mode & MODE_REMOVABLE ? 0xa0 : 0x80;
441 
442         memset(buffer + 2, 0, 34);
443 
444         if (total == 0) {
445             media = MT_NO_DISK;
446         } else {
447             if (scsi->mode & MODE_FDS120) {
448                 if (total == 1440) {
449                     media       = MT_2DD;
450                     sectors     = 9;
451                     blockLength = 2048 >> 8;            // FDS-120 value
452                     tracks      = 160;
453                     removable   = 0xa0;
454                 } else {
455                     if (total == 2880) {
456                         media       = MT_2HD_144;
457                         sectors     = 18;
458                         blockLength = 2048 >> 8;
459                         tracks      = 160;
460                         removable   = 0xa0;
461                     }
462                 }
463             }
464         }
465 
466         // Mode Parameter Header 4bytes
467         buffer[1] = media;              // Medium Type
468         buffer[3] = 8;                  // block descripter length
469         buffer   += 4;
470 
471         // Disable Block Descriptor check
472         if (!(scsi->cdb[1] & 0x08)) {
473             // Block Descriptor 8bytes
474             buffer[1]  = (UInt8)((total >> 16) & 0xff); // 1..3 Number of Blocks
475             buffer[2]  = (UInt8)((total >>  8) & 0xff);
476             buffer[3]  = (UInt8)(total & 0xff);
477             buffer[6]  = (UInt8)(blockLength & 0xff);   // 5..7 Block Length in Bytes
478             buffer    += 8;
479             size      += 8;
480         }
481 
482         // Format Device Page 24bytes
483         buffer[0]  = 3;                 //     0 Page
484         buffer[1]  = 0x16;              //     1 Page Length
485         buffer[3]  = (UInt8)tracks;     //  2, 3 Tracks per Zone
486         buffer[11] = (UInt8)sectors;    // 10,11 Sectors per Track
487         buffer[12] = (UInt8)blockLength;// 12,13 Data Bytes per Physical Sector
488         buffer[20] = removable;         // 20    bit7 Soft Sector bit5 Removable
489 
490         scsi->buffer[0] = size - 1;     // sense data length
491 
492         if (length > size) {
493             length = size;
494         }
495         return length;
496     }
497     scsi->keycode = SENSE_INVALID_COMMAND_CODE;
498     return 0;
499 }
500 
scsiDeviceRequestSense(SCSIDEVICE * scsi)501 static int scsiDeviceRequestSense(SCSIDEVICE* scsi)
502 {
503     int keycode;
504     UInt8* buffer = scsi->buffer;
505     int length = scsi->length;
506 
507     if (scsi->reset) {
508         scsi->reset = 0;
509         keycode = SENSE_POWER_ON;
510     } else {
511         keycode = scsi->keycode;
512     }
513 
514     SCSILOG1("Request Sense: keycode = %X\n", keycode);
515     scsi->keycode = SENSE_NO_SENSE;
516 
517     memset(buffer + 1, 0, 17);
518     if (length == 0) {
519         if (scsi->mode & BIT_SCSI2) {
520             return 0;
521         }
522         buffer[0]    = (UInt8)((keycode >> 8) & 0xff);  // Sense code
523         length = 4;
524     } else {
525         buffer[0]  = 0x70;
526         buffer[2]  = (UInt8)((keycode >> 16) & 0xff);   // Sense key
527         buffer[7]  = 10;                                // Additional sense length
528         buffer[12] = (UInt8)((keycode >> 8) & 0xff);    // Additional sense code
529         buffer[13] = (UInt8)(keycode & 0xff);           // Additional sense code qualifier
530         if (length > 18) length = 18;
531     }
532     return length;
533 }
534 
scsiDeviceCheckReadOnly(SCSIDEVICE * scsi)535 static int scsiDeviceCheckReadOnly(SCSIDEVICE* scsi)
536 {
537     int result = diskReadOnly(scsi->diskId);
538     if (result) {
539         scsi->keycode = SENSE_WRITE_PROTECT;
540     }
541     return result;
542 }
543 
scsiDeviceReadCapacity(SCSIDEVICE * scsi)544 static int scsiDeviceReadCapacity(SCSIDEVICE* scsi)
545 {
546     UInt32 block  = _diskGetTotalSectors(scsi->diskId);
547     UInt8* buffer = scsi->buffer;
548 
549     if (block == 0) {
550         scsi->keycode = SENSE_MEDIUM_NOT_PRESENT;
551         SCSILOG1("hdd %d: drive not ready\n", scsi->scsiId);
552         return 0;
553     }
554 
555     SCSILOG1("total block: %u\n", (unsigned int)block);
556 
557     --block;
558     buffer[0] = (UInt8)((block >> 24) & 0xff);
559     buffer[1] = (UInt8)((block >> 16) & 0xff);
560     buffer[2] = (UInt8)((block >>  8) & 0xff);
561     buffer[3] = (UInt8)(block & 0xff);
562     buffer[4] = 0;
563     buffer[5] = 0;
564     buffer[6] = (UInt8)((scsi->sectorSize >> 8) & 0xff);
565     buffer[7] = 0;
566 
567     return 8;
568 }
569 
570 #ifdef USE_SPECIALCOMMAND
571 
572 // This routine demands 'BUFFER_SIZE' by 1KB or more.
scsiDeviceBlueMSX(SCSIDEVICE * scsi)573 static int scsiDeviceBlueMSX(SCSIDEVICE* scsi)
574 {
575     FileProperties* disk;
576     int length;
577     const char* fileName;
578     const char scsicat[16] = "SCSI-CATblueMSX ";
579     UInt8* buffer = scsi->buffer;
580     int cmd;
581 
582     SCSILOG1("SCSI-CAT %d\n", scsi->scsiId);
583     cmd = (scsi->cdb[4] << 8) + scsi->cdb[5];
584 
585     if (cmd == 0) {
586         // revision
587         memcpy(buffer , scsicat, 16);       // SCSI-CAT(8) + emulator name(8)
588         buffer[16] = (UInt8)(scsi->deviceType & 0xff);  // device type
589         buffer[17] = scsi->mode & MODE_REMOVABLE ? 0x80 : 0;    // removable device
590         buffer[18] = 0;                     // revision MSB
591         buffer[19] = 1;                     // LSB
592         return 20;
593     }
594     if (cmd == 1) {
595         // inserted
596         buffer[0] = diskPresent(scsi->diskId) ? 1 : 0;
597         return 1;
598     }
599     if (cmd < 6) {
600         // file info
601         disk = &scsi->disk;
602         fileName = (cmd < 4) ? disk->fileName : disk->fileNameInZip;
603         if ((cmd & 1) == 0) {
604             fileName = stripPath(fileName);
605         }
606         length = strlen(fileName);
607         buffer[0] = (UInt8)((length >> 8) & 0xff);
608         buffer[1] = (UInt8)(length & 0xff);
609         strcpy(buffer + 2, fileName);
610         SCSILOG1("file info:\n%s\n", buffer + 2);
611         return length + 3;  // + \0
612     }
613     scsi->keycode = SENSE_INVALID_COMMAND_CODE;
614     return 0;
615 }
616 #endif
617 
scsiDeviceCheckAddress(SCSIDEVICE * scsi)618 static int scsiDeviceCheckAddress(SCSIDEVICE* scsi)
619 {
620     int total = _diskGetTotalSectors(scsi->diskId);
621     if (total == 0) {
622         scsi->keycode = SENSE_MEDIUM_NOT_PRESENT;
623         SCSILOG1("hdd %d: drive not ready\n", scsi->scsiId);
624         return 0;
625     }
626 
627     if ((scsi->sector >= 0) && (scsi->length > 0) &&
628             (scsi->sector + scsi->length <= total)) {
629         return 1;
630     }
631     SCSILOG1("hdd %d: IllegalBlockAddress\n", scsi->scsiId);
632     scsi->keycode = SENSE_ILLEGAL_BLOCK_ADDRESS;
633     return 0;
634 }
635 
636 // Execute scsiDeviceCheckAddress previously.
scsiDeviceReadSector(SCSIDEVICE * scsi,int * blocks)637 static int scsiDeviceReadSector(SCSIDEVICE* scsi, int* blocks)
638 {
639     int counter;
640     int numSectors;
641 
642     ledSetHd(1);
643     if (scsi->length >= BUFFER_BLOCK_SIZE) {
644         numSectors  = BUFFER_BLOCK_SIZE;
645         counter     = BUFFER_SIZE;
646     } else {
647         numSectors  = scsi->length;
648         counter     = scsi->length * 512;
649     }
650 
651     //SCSILOG("hdd#%d read sector: %d %d\n", scsi->scsiId, scsi->sector, numSectors);
652     if (_diskRead2(scsi->diskId, scsi->buffer, scsi->sector, numSectors)) {
653         scsi->sector += numSectors;
654         scsi->length -= numSectors;
655         *blocks = scsi->length;
656         return counter;
657     }
658     *blocks = 0;
659     scsi->keycode = SENSE_UNRECOVERED_READ_ERROR;
660     return 0;
661 }
662 
scsiDeviceDataIn(SCSIDEVICE * scsi,int * blocks)663 int scsiDeviceDataIn(SCSIDEVICE* scsi, int* blocks)
664 {
665     int counter;
666 
667     if (scsi->cdb[0] == SCSIOP_READ10) {
668         counter = scsiDeviceReadSector(scsi, blocks);
669         if (counter) {
670             return counter;
671         }
672     }
673     SCSILOG1("datain error %x\n", scsi->cdb[0]);
674     *blocks = 0;
675     return 0;
676 }
677 
678 // Execute scsiDeviceCheckAddress and scsiDeviceCheckReadOnly previously.
scsiDeviceWriteSector(SCSIDEVICE * scsi,int * blocks)679 static int scsiDeviceWriteSector(SCSIDEVICE* scsi, int* blocks)
680 {
681     int counter;
682     int numSectors;
683 
684     ledSetHd(1);
685     if (scsi->length >= BUFFER_BLOCK_SIZE) {
686         numSectors  = BUFFER_BLOCK_SIZE;
687     } else {
688         numSectors  = scsi->length;
689     }
690 
691     SCSILOG3("hdd#%d write sector: %d %d\n", scsi->scsiId, scsi->sector, numSectors);
692     if (_diskWrite2(scsi->diskId, scsi->buffer, scsi->sector, numSectors)) {
693         scsi->sector += numSectors;
694         scsi->length -= numSectors;
695 
696         if (scsi->length >= BUFFER_BLOCK_SIZE) {
697             *blocks = scsi->length - BUFFER_BLOCK_SIZE;
698             counter = BUFFER_SIZE;
699         } else {
700             *blocks = 0;
701             counter = scsi->length * 512;
702         }
703         return counter;
704     }
705     scsi->keycode = SENSE_WRITE_FAULT;
706     *blocks = 0;
707     return 0;
708 }
709 
scsiDeviceDataOut(SCSIDEVICE * scsi,int * blocks)710 int scsiDeviceDataOut(SCSIDEVICE* scsi, int* blocks)
711 {
712     if (scsi->cdb[0] == SCSIOP_WRITE10) {
713         return scsiDeviceWriteSector(scsi, blocks);
714     }
715     SCSILOG1("dataout error %x\n", scsi->cdb[0]);
716     *blocks = 0;
717     return 0;
718 }
719 
720 //  MBR erase only
scsiDeviceFormatUnit(SCSIDEVICE * scsi)721 static void scsiDeviceFormatUnit(SCSIDEVICE* scsi)
722 {
723     if (scsiDeviceGetReady(scsi) && !scsiDeviceCheckReadOnly(scsi)) {
724         memset(scsi->buffer, 0, 512);
725         if (_diskWrite2(scsi->diskId, scsi->buffer, 0, 1)) {
726             scsi->reset   = 1;
727             scsi->changed = 1;
728         } else {
729             scsi->keycode = SENSE_WRITE_FAULT;
730         }
731     }
732 }
733 
scsiDeviceGetStatusCode(SCSIDEVICE * scsi)734 UInt8 scsiDeviceGetStatusCode(SCSIDEVICE* scsi)
735 {
736     UInt8 result;
737     if (scsi->deviceType != SDT_CDROM) {
738         result = scsi->keycode ? SCSIST_CHECK_CONDITION : SCSIST_GOOD;
739     } else {
740         result = archCdromGetStatusCode(scsi->cdrom);
741     }
742     SCSILOG1("SCSI status code: %x\n", result);
743     return result;
744 }
745 
scsiDeviceExecuteCmd(SCSIDEVICE * scsi,UInt8 * cdb,SCSI_PHASE * phase,int * blocks)746 int scsiDeviceExecuteCmd(SCSIDEVICE* scsi, UInt8* cdb, SCSI_PHASE* phase, int* blocks)
747 {
748     int counter;
749 
750     SCSILOG1("SCSI Command: %x\n", cdb[0]);
751     memcpy(scsi->cdb, cdb, 12);
752     scsi->message = 0;
753     *phase = Status;
754     *blocks = 0;
755 
756     if (scsi->deviceType == SDT_CDROM) {
757         int retval;
758         scsi->keycode = SENSE_NO_SENSE;
759         *phase = Execute;
760         retval = archCdromExecCmd(scsi->cdrom, cdb, scsi->buffer, BUFFER_SIZE);
761         switch (retval) {
762         case 0:
763             *phase = Status;
764             break;
765         case -1:
766             break;
767         default:
768             *phase = DataIn;
769             return retval;
770         }
771         return 0;
772     }
773 
774     scsiDeviceDiskChanged(scsi);
775 
776     // check unit attention
777     if (scsi->reset && (scsi->mode & MODE_UNITATTENTION) &&
778        (cdb[0] != SCSIOP_INQUIRY) && (cdb[0] != SCSIOP_REQUEST_SENSE)) {
779         scsi->reset = 0;
780         scsi->keycode = SENSE_POWER_ON;
781         if (cdb[0] == SCSIOP_TEST_UNIT_READY) {
782             scsi->changed = 0;
783         }
784         SCSILOG("Unit Attention. This command is not executed.\n");
785         return 0;
786     }
787 
788     // check LUN
789     if (((cdb[1] & 0xe0) || scsi->lun) && (cdb[0] != SCSIOP_REQUEST_SENSE) &&
790         !(cdb[0] == SCSIOP_INQUIRY && !(scsi->mode & MODE_NOVAXIS))) {
791         scsi->keycode = SENSE_INVALID_LUN;
792         SCSILOG("check LUN error\n");
793         return 0;
794     }
795 
796     if (cdb[0] != SCSIOP_REQUEST_SENSE) {
797         scsi->keycode = SENSE_NO_SENSE;
798     }
799 
800     if (cdb[0] < SCSIOP_GROUP1) {
801         scsi->sector = ((cdb[1] & 0x1f) << 16) |
802                        (cdb[2] << 8) | cdb[3];
803         scsi->length = cdb[4];
804 
805         switch (cdb[0]) {
806         case SCSIOP_TEST_UNIT_READY:
807             SCSILOG("TestUnitReady\n");
808             scsiDeviceTestUnitReady(scsi);
809             return 0;
810 
811         case SCSIOP_INQUIRY:
812             SCSILOG1("Inquiry %d\n", scsi->length);
813             counter = scsiDeviceInquiry(scsi);
814             if (counter) {
815                 *phase = DataIn;
816             }
817             return counter;
818 
819         case SCSIOP_REQUEST_SENSE:
820             SCSILOG("RequestSense\n");
821             counter = scsiDeviceRequestSense(scsi);
822             if (counter) {
823                 *phase = DataIn;
824             }
825             return counter;
826 
827         case SCSIOP_READ6:
828             SCSILOG2("Read6: %d %d\n", scsi->sector, scsi->length);
829             if (scsi->length == 0) {
830                 //scsi->length = scsi->sectorSize >> 1;
831                 scsi->length = 256;
832             }
833             if (scsiDeviceCheckAddress(scsi)) {
834                 counter = scsiDeviceReadSector(scsi, blocks);
835                 if(counter) {
836                     scsi->cdb[0] = SCSIOP_READ10;
837                     *phase = DataIn;
838                     return counter;
839                 }
840             }
841             return 0;
842 
843         case SCSIOP_WRITE6:
844             SCSILOG2("Write6: %d %d\n", scsi->sector, scsi->length);
845             if (scsi->length == 0) {
846                 //scsi->length = scsi->sectorSize >> 1;
847                 scsi->length = 256;
848             }
849             if (scsiDeviceCheckAddress(scsi) && !scsiDeviceCheckReadOnly(scsi)) {
850                 ledSetHd(1);
851                 if (scsi->length >= BUFFER_BLOCK_SIZE) {
852                     *blocks = scsi->length - BUFFER_BLOCK_SIZE;
853                     counter = BUFFER_SIZE;
854                 } else {
855                     counter = scsi->length * 512;
856                 }
857                 scsi->cdb[0] = SCSIOP_WRITE10;
858                 *phase = DataOut;
859                 return counter;
860             }
861             return 0;
862 
863         case SCSIOP_SEEK6:
864             SCSILOG1("Seek6: %d\n", scsi->sector);
865             ledSetHd(1);
866             scsi->length = 1;
867             scsiDeviceCheckAddress(scsi);
868             return 0;
869 
870         case SCSIOP_MODE_SENSE:
871             SCSILOG1("ModeSense: %d\n", scsi->length);
872             counter = scsiDeviceModeSense(scsi);
873             if (counter) {
874                 *phase = DataIn;
875             }
876             return counter;
877 
878         case SCSIOP_FORMAT_UNIT:
879             SCSILOG("FormatUnit\n");
880             scsiDeviceFormatUnit(scsi);
881             return 0;
882 
883         case SCSIOP_START_STOP_UNIT:
884             SCSILOG("StartStopUnit\n");
885             scsiDeviceStartStopUnit(scsi);
886             return 0;
887 
888         case SCSIOP_REZERO_UNIT:
889         case SCSIOP_REASSIGN_BLOCKS:
890         case SCSIOP_RESERVE_UNIT:
891         case SCSIOP_RELEASE_UNIT:
892         case SCSIOP_SEND_DIAGNOSTIC:
893             SCSILOG("SCSI_Group0 dummy\n");
894             return 0;
895         }
896     } else {
897         scsi->sector = (cdb[2] << 24) | (cdb[3] << 16) |
898                        (cdb[4] << 8)  |  cdb[5];
899         scsi->length = (cdb[7] << 8) + cdb[8];
900 
901         switch (cdb[0]) {
902         case SCSIOP_READ10:
903             SCSILOG2("Read10: %d %d\n", scsi->sector, scsi->length);
904 
905             if (scsiDeviceCheckAddress(scsi)) {
906                 counter = scsiDeviceReadSector(scsi, blocks);
907                 if(counter) {
908                     *phase = DataIn;
909                     return counter;
910                 }
911             }
912             return 0;
913 
914         case SCSIOP_WRITE10:
915             SCSILOG2("Write10: %d %d\n", scsi->sector, scsi->length);
916 
917             if (scsiDeviceCheckAddress(scsi) && !scsiDeviceCheckReadOnly(scsi)) {
918                 if (scsi->length >= BUFFER_BLOCK_SIZE) {
919                     *blocks = scsi->length - BUFFER_BLOCK_SIZE;
920                     counter = BUFFER_SIZE;
921                 } else {
922                     counter = scsi->length * 512;
923                 }
924                 *phase = DataOut;
925                 return counter;
926             }
927             return 0;
928 
929         case SCSIOP_READ_CAPACITY:
930             SCSILOG("ReadCapacity\n");
931             counter = scsiDeviceReadCapacity(scsi);
932             if (counter) {
933                 *phase = DataIn;
934             }
935             return counter;
936 
937         case SCSIOP_SEEK10:
938             SCSILOG1("Seek10: %d\n", scsi->sector);
939             ledSetHd(1);
940             scsi->length = 1;
941             scsiDeviceCheckAddress(scsi);
942             return 0;
943 
944 #ifdef USE_SPECIALCOMMAND
945         case SCSIOP_BLUE_MSX:
946             SCSILOG("blueMSX\n");
947             counter = scsiDeviceBlueMSX(scsi);
948             if (counter) {
949                 *phase = DataIn;
950             }
951             return counter;
952 #endif
953         }
954     }
955 
956     SCSILOG1("unsupport command %x\n", cdb[0]);
957     scsi->keycode = SENSE_INVALID_COMMAND_CODE;
958     return 0;
959 }
960 
scsiDeviceExecutingCmd(SCSIDEVICE * scsi,SCSI_PHASE * phase,int * blocks)961 int scsiDeviceExecutingCmd(SCSIDEVICE* scsi, SCSI_PHASE* phase, int* blocks)
962 {
963     int result = 0;
964 
965     if (archCdromIsXferComplete(scsi->cdrom, &result)) {
966         *phase = result ? DataIn : Status;
967     } else {
968         *phase = Execute;
969     }
970     *blocks = 0;
971     return result;
972 }
973 
scsiDeviceMsgIn(SCSIDEVICE * scsi)974 UInt8 scsiDeviceMsgIn(SCSIDEVICE* scsi)
975 {
976     UInt8 result = (UInt8)(scsi->message & 0xff);
977     scsi->message = 0;
978     return result;
979 }
980 
981 /*
982 scsiDeviceMsgOut()
983 Notes:
984     [out]
985           -1: Busfree demand. (Please process it in the call origin.)
986         bit2: Status phase demand. Error happend.
987         bit1: Make it to a busfree if ATN has not been released.
988         bit0: There is a message(MsgIn).
989 */
scsiDeviceMsgOut(SCSIDEVICE * scsi,UInt8 value)990 int scsiDeviceMsgOut(SCSIDEVICE* scsi, UInt8 value)
991 {
992     SCSILOG2("SCSI #%d message out: %x\n", scsi->scsiId, value);
993     if (value & 0x80) {
994         scsi->lun = value & 7;
995         return 0;
996     }
997 
998     switch (value) {
999     case MSG_INITIATOR_DETECT_ERROR:
1000         scsi->keycode = SENSE_INITIATOR_DETECTED_ERR;
1001         return 6;
1002 
1003     case MSG_BUS_DEVICE_RESET:
1004         scsiDeviceBusReset(scsi);
1005     case MSG_ABORT:
1006         return -1;
1007 
1008     case MSG_REJECT:
1009     case MSG_PARITY_ERROR:
1010     case MSG_NO_OPERATION:
1011         return 2;
1012     }
1013     scsi->message = MSG_REJECT;
1014     return ((value >= 0x04) && (value <= 0x11)) ? 3 : 1;
1015 }
1016 
scsiDeviceSaveState(SCSIDEVICE * scsi)1017 void scsiDeviceSaveState(SCSIDEVICE* scsi)
1018 {
1019     SaveState* state = saveStateOpenForWrite("scsidevice");
1020 
1021     saveStateSet(state, "enabled",    scsi->enabled);
1022     saveStateSet(state, "deviceType", scsi->deviceType);
1023     saveStateSet(state, "mode",       scsi->mode);
1024     saveStateSet(state, "reset",      scsi->reset);
1025     saveStateSet(state, "motor",      scsi->motor);
1026     saveStateSet(state, "keycode",    scsi->keycode);
1027     saveStateSet(state, "inserted",   scsi->inserted);
1028     saveStateSet(state, "changed",    scsi->changed);
1029     saveStateSet(state, "sector",     scsi->sector);
1030     saveStateSet(state, "sectorSize", scsi->sectorSize);
1031     saveStateSet(state, "length",     scsi->length);
1032     saveStateSet(state, "lun",        scsi->lun);
1033     saveStateSet(state, "message",    scsi->message);
1034 
1035     saveStateSetBuffer(state, "cdb", scsi->cdb, 12);
1036     saveStateSetBuffer(state, "fileName", scsi->disk.fileName, strlen(scsi->disk.fileName) + 1);
1037     saveStateSetBuffer(state, "fileNameInZip", scsi->disk.fileNameInZip, strlen(scsi->disk.fileNameInZip) + 1);
1038     saveStateClose(state);
1039 
1040     if (scsi->deviceType == SDT_CDROM) {
1041         archCdromSaveState(scsi->cdrom);
1042     }
1043 }
1044 
scsiDeviceLoadState(SCSIDEVICE * scsi)1045 void scsiDeviceLoadState(SCSIDEVICE* scsi)
1046 {
1047     SaveState* state = saveStateOpenForRead("scsidevice");
1048 
1049     scsi->enabled    = saveStateGet(state, "enabled",    1);
1050     scsi->deviceType = saveStateGet(state, "deviceType", 0);
1051     scsi->mode       = saveStateGet(state, "mode",       MODE_UNITATTENTION);
1052     scsi->reset      = saveStateGet(state, "reset",      0);
1053     scsi->motor      = saveStateGet(state, "motor",      1);
1054     scsi->keycode    = saveStateGet(state, "keycode",    0);
1055     scsi->inserted   = saveStateGet(state, "inserted",   0);
1056     scsi->changed    = saveStateGet(state, "changed",    1);
1057     scsi->sector     = saveStateGet(state, "sector",     0);
1058     scsi->sectorSize = saveStateGet(state, "sectorSize", 512);
1059     scsi->length     = saveStateGet(state, "length",     0);
1060     scsi->lun        = saveStateGet(state, "lun",        0);
1061     scsi->message    = saveStateGet(state, "message",    0);
1062 
1063     saveStateGetBuffer(state, "cdb", scsi->cdb, 12);
1064     saveStateGetBuffer(state, "fileName", scsi->disk.fileName, sizeof(scsi->disk.fileName));
1065     saveStateGetBuffer(state, "fileNameInZip", scsi->disk.fileNameInZip, sizeof(scsi->disk.fileNameInZip));
1066     saveStateClose(state);
1067 
1068     scsi->changeCheck2  = scsi->mode & MODE_CHECK2;
1069 
1070     if (scsi->deviceType == SDT_CDROM) {
1071         archCdromLoadState(scsi->cdrom);
1072     }
1073 }
1074 
1075