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