OSDN Git Service

[General] Merge Upstream 2018-12-18.
[csp-qt/common_source_project-fm7.git] / source / src / vm / scsi_hdd.cpp
index 43cbcdf..faf03bd 100644 (file)
        Author : Takeda.Toshiya
        Date   : 2016.03.01-
 
-       [ SCSI hard disk drive ]
+       [ SCSI/SASI hard disk drive ]
 */
 
 #include "scsi_hdd.h"
+#include "harddisk.h"
 #include "../fifo.h"
 
-void SCSI_HDD::initialize_max_logical_block_addr()
+void SCSI_HDD::release()
 {
-       if(max_logical_block_addr == 0) {
-               FILEIO* fio = new FILEIO();
-               uint32_t file_size = 0;
-               
-               if(default_drive_size == 0) {
-                       default_drive_size = 0x2800000; // 40MB
+       for(int i = 0; i < 8; i++) {
+               if(disk[i] != NULL) {
+                       disk[i]->close();
+                       delete disk[i];
                }
-               if(FILEIO::IsFileExisting(create_local_path(_T("SCSI%d.DAT"), scsi_id))) {
-                       if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_WRITE_BINARY)) {
-                               if((file_size = fio->FileLength()) == 0) {
-                                       uint32_t remain = (file_size = default_drive_size);
-                                       void *tmp = calloc(1, SCSI_BUFFER_SIZE);
-                                       while(remain > 0) {
-                                               uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
-                                               fio->Fwrite(tmp, length, 1);
-                                               remain -= length;
-                                       }
-                                       free(tmp);
+       }
+       SCSI_DEV::release();
+}
+
+void SCSI_HDD::reset()
+{
+       if(!is_hot_swappable) {
+               for(int drv = 0; drv < 8; drv++) {
+                       if(disk[drv] != NULL) {
+                               if(image_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(image_path[drv])) {
+                                       disk[drv]->open(image_path[drv], sector_size[drv]);
+                               } else {
+                                       disk[drv]->close();
                                }
-                               fio->Fclose();
                        }
+               }
+       }
+       SCSI_DEV::reset();
+}
+
+void SCSI_HDD::open(int drv, const _TCHAR* file_path, int default_sector_size)
+{
+       if(drv < 8 && disk[drv] != NULL) {
+               if(!is_hot_swappable) {
+                       my_tcscpy_s(image_path[drv], _MAX_PATH, file_path);
+                       sector_size[drv] = default_sector_size;
                } else {
-                       if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_WRITE_BINARY)) {
-                               uint32_t remain = (file_size = default_drive_size);
-                               void *tmp = calloc(1, SCSI_BUFFER_SIZE);
-                               while(remain > 0) {
-                                       uint32_t length = min(remain, (uint32_t)SCSI_BUFFER_SIZE);
-                                       fio->Fwrite(tmp, length, 1);
-                                       remain -= length;
-                               }
-                               free(tmp);
-                               fio->Fclose();
-                       }
+                       disk[drv]->open(file_path, default_sector_size);
+               }
+       }
+}
+
+void SCSI_HDD::close(int drv)
+{
+       if(drv < 8 && disk[drv] != NULL) {
+               if(!is_hot_swappable) {
+                       image_path[drv][0] = _T('\0');
+               } else {
+                       disk[drv]->close();
+               }
+       }
+}
+
+bool SCSI_HDD::mounted(int drv)
+{
+       if(drv < 8 && disk[drv] != NULL) {
+               if(!is_hot_swappable) {
+                       return (image_path[drv][0] != _T('\0'));
+               } else {
+                       return disk[drv]->mounted();
+               }
+       }
+       return false;
+}
+
+bool SCSI_HDD::accessed(int drv)
+{
+       if(drv < 8 && disk[drv] != NULL) {
+               return disk[drv]->accessed();
+       }
+       return false;
+}
+
+bool SCSI_HDD::is_device_existing()
+{
+       for(int i = 0; i < 8; i++) {
+               if(disk[i] != NULL && disk[i]->mounted()) {
+                       return true;
+               }
+       }
+       return false;
+}
+
+uint32_t SCSI_HDD::physical_block_size()
+{
+       HARDDISK *unit = disk[get_logical_unit_number()];
+       
+       if(unit != NULL && unit->mounted()) {
+               return unit->sector_size;
+       }
+       return 0;// 512;
+}
+
+uint32_t SCSI_HDD::logical_block_size()
+{
+       HARDDISK *unit = disk[get_logical_unit_number()];
+       
+       if(unit != NULL && unit->mounted()) {
+               return unit->sector_size;
+       }
+       return 0;// 512;
+}
+
+uint32_t SCSI_HDD::max_logical_block_addr()
+{
+       HARDDISK *unit = disk[get_logical_unit_number()];
+       
+       if(unit != NULL && unit->mounted() && unit->sector_num > 0) {
+               return unit->sector_num - 1;
+       }
+       return 0;
+}
+
+bool SCSI_HDD::read_buffer(int length)
+{
+       if(!(command[0] == SCSI_CMD_READ6 || command[0] == SCSI_CMD_READ10 || command[0] == SCSI_CMD_READ12)) {
+               for(int i = 0; i < length; i++) {
+                       buffer->write(0);
+                       position++;
+               }
+               set_sense_code(SCSI_SENSE_NOSENSE);
+               return true;
+       }
+       HARDDISK *unit = disk[get_logical_unit_number()];
+       
+       if(!(unit != NULL && unit->mounted())) {
+               set_sense_code(SCSI_SENSE_NOTREADY);
+               return false;
+       }
+       while(length > 0) {
+               uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
+               int tmp_length = min(length, (int)sizeof(tmp_buffer));
+               
+               if(!unit->read_buffer((long)position, tmp_length, tmp_buffer)) {
+                       set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
+                       return false;
                }
-               if(file_size != 0) {
-                       max_logical_block_addr = (file_size / logical_block_size) - 1;
+               for(int i = 0; i < tmp_length; i++) {
+                       buffer->write(tmp_buffer[i]);
+               }
+               length -= tmp_length;
+               position += tmp_length;
+       }
+       set_sense_code(SCSI_SENSE_NOSENSE);
+       return true;
+}
+
+bool SCSI_HDD::write_buffer(int length)
+{
+       if(!(command[0] == SCSI_CMD_WRITE6 || command[0] == SCSI_CMD_WRITE10 || command[0] == SCSI_CMD_WRITE12)) {
+               for(int i = 0; i < length; i++) {
+                       buffer->read();
+                       position++;
                }
-               delete fio;
+               set_sense_code(SCSI_SENSE_NOSENSE);
+               return true;
+       }
+       HARDDISK *unit = disk[get_logical_unit_number()];
+       
+       if(!(unit != NULL && unit->mounted())) {
+               set_sense_code(SCSI_SENSE_NOTREADY);
+               return false;
        }
+       while(length > 0) {
+               uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
+               int tmp_length = min(length, (int)sizeof(tmp_buffer));
+               
+               for(int i = 0; i < tmp_length; i++) {
+                       tmp_buffer[i] = buffer->read();
+               }
+               if(!unit->write_buffer((long)position, tmp_length, tmp_buffer)) {
+                       set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
+                       return false;
+               }
+               length -= tmp_length;
+               position += tmp_length;
+       }
+       set_sense_code(SCSI_SENSE_NOSENSE);
+       return true;
 }
 
-void SCSI_HDD::start_command()
+#define STATE_VERSION  3
+
+bool SCSI_HDD::process_state(FILEIO* state_fio, bool loading)
+{
+       if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+               return false;
+       }
+       if(!state_fio->StateCheckInt32(this_device_id)) {
+               return false;
+       }
+       /*
+       for(int drv = 0; drv < 8; drv++) {
+               if(disk[drv] != NULL) {
+                       if(!disk[drv]->process_state(state_fio, loading)) {
+                               return false;
+                       }
+               }
+       }
+       */
+       state_fio->StateArray(&image_path[0][0], sizeof(image_path), 1);
+       state_fio->StateArray(sector_size, sizeof(sector_size), 1);
+       return SCSI_DEV::process_state(state_fio, loading);
+}
+
+// SASI hard disk drive
+
+void SASI_HDD::start_command()
 {
        switch(command[0]) {
-       case SCSI_CMD_INQUIRY:
+       case SCSI_CMD_REQ_SENSE:
                #ifdef _SCSI_DEBUG_LOG
-                       emu->out_debug_log(_T("[SCSI_HDD:ID=%d] Command: Inquiry\n"), scsi_id);
+                       this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: Request Sense\n"), scsi_id);
                #endif
                // start position
-               position = ((command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3]) * logical_block_size;
+               position = (command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3];
+               position *= physical_block_size();
                // transfer length
-               remain = 32;
+               remain = 4;
                // create sense data table
                buffer->clear();
-               buffer->write(0x00);
-               buffer->write(0x00);
-               buffer->write(0x02); // ANSI SCSI2
-               buffer->write(0x01); // ANSI-CCS
-               buffer->write(0x1c);
-               buffer->write(0x00);
-               buffer->write(0x00);
-               buffer->write(0x18);
-               for(int i = 0; i < (int)strlen(vendor_id) && i < 8; i++) {
-                       buffer->write(vendor_id[i]);
-               }
-               for(int i = strlen(vendor_id); i < 8; i++) {
-                       buffer->write(0x20);
-               }
-               for(int i = 0; i < (int)strlen(product_id) && i < 16; i++) {
-                       buffer->write(vendor_id[i]);
-               }
-               for(int i = strlen(product_id); i < 16; i++) {
-                       buffer->write(0x20);
-               }
-               // set first data
-               set_dat(buffer->read());
+               buffer->write(get_sense_code());
+               buffer->write(((max_logical_block_addr() >> 16) & 0x1f) | (get_logical_unit_number() << 5));
+               buffer->write(((max_logical_block_addr() >>  8) & 0xff));
+               buffer->write(((max_logical_block_addr() >>  0) & 0xff));
                // change to data in phase
+               set_dat(buffer->read());
                set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
-               break;
+               set_sense_code(SCSI_SENSE_NOSENSE);
+               return;
                
-       case SCSI_CMD_RD_CAPAC:
+       case 0xc2:
                #ifdef _SCSI_DEBUG_LOG
-                       emu->out_debug_log(_T("[SCSI_HDD:ID=%d] Command: Read Capacity\n"), scsi_id);
+                       this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: SASI Command 0xC2\n"), scsi_id);
                #endif
-               // initialize max logical block address
-               initialize_max_logical_block_addr();
-               // start position
-               position = (command[2] * 0x1000000 + command[3] * 0x10000 + command[4] * 0x100 + command[5]) * logical_block_size;
                // transfer length
-               remain = 8;
-               // create capacity data table
+               remain = 10; // DTC\8cn (\83g\83\89\83\93\83W\83X\83^\8bZ\8fpSPECIAL No.27, P.88)
+               // clear data buffer
                buffer->clear();
-               buffer->write((max_logical_block_addr >> 24) & 0xff);
-               buffer->write((max_logical_block_addr >> 16) & 0xff);
-               buffer->write((max_logical_block_addr >>  8) & 0xff);
-               buffer->write((max_logical_block_addr >>  0) & 0xff);
-               buffer->write((    logical_block_size >> 24) & 0xff);
-               buffer->write((    logical_block_size >> 16) & 0xff);
-               buffer->write((    logical_block_size >>  8) & 0xff);
-               buffer->write((    logical_block_size >>  0) & 0xff);
-               // set first data
-               set_dat(buffer->read());
                // change to data in phase
-               set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
-               break;
-               
-       default:
-               SCSI_DEV::start_command();
-               break;
-       }
-}
-
-void SCSI_HDD::read_buffer(int length)
-{
-       // make sure drive size is not zero
-       initialize_max_logical_block_addr();
-       
-       // read blocks
-       FILEIO* fio = new FILEIO();
-       if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_BINARY)) {
-               // FIXME: consider the case that disk size is bigger than MAX_LONG
-               fio->Fseek((long)position, FILEIO_SEEK_SET);
-               while(length > 0) {
-                       uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
-                       int tmp_length = min(length, sizeof(tmp_buffer));
-                       
-                       fio->Fread(tmp_buffer, tmp_length, 1);
-                       for(int i = 0; i < tmp_length; i++) {
-                               buffer->write(tmp_buffer[i]);
-                       }
-                       length -= tmp_length;
-                       position += tmp_length;
-               }
-               fio->Fclose();
-       }
-       delete fio;
-}
-
-void SCSI_HDD::write_buffer(int length)
-{
-       // make sure drive size is not zero
-       initialize_max_logical_block_addr();
-       
-       // write blocks
-       FILEIO* fio = new FILEIO();
-       if(fio->Fopen(create_local_path(_T("SCSI%d.DAT"), scsi_id), FILEIO_READ_WRITE_BINARY)) {
-               // FIXME: consider the case that disk size is bigger than MAX_LONG
-               fio->Fseek((long)position, FILEIO_SEEK_SET);
-               while(length > 0) {
-                       uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
-                       int tmp_length = min(length, sizeof(tmp_buffer));
-                       
-                       for(int i = 0; i < tmp_length; i++) {
-                               tmp_buffer[i] = buffer->read();
-                       }
-                       fio->Fwrite(tmp_buffer, tmp_length, 1);
-                       length -= tmp_length;
-                       position += tmp_length;
-               }
-               fio->Fclose();
+               set_phase_delay(SCSI_PHASE_DATA_OUT, 1.0);
+               return;
        }
-       delete fio;
+       // start standard command
+       SCSI_HDD::start_command();
 }
-