OSDN Git Service

[VM][DEVICE][I386] Add bios_call_far_ia32() and bios_int_ia32() because BIOS calling...
[csp-qt/common_source_project-fm7.git] / source / src / vm / scsi_hdd.cpp
1 /*
2         Skelton for retropc emulator
3
4         Author : Takeda.Toshiya
5         Date   : 2016.03.01-
6
7         [ SCSI/SASI hard disk drive ]
8 */
9
10 #include "scsi_hdd.h"
11 #include "harddisk.h"
12 #include "../fifo.h"
13
14 void SCSI_HDD::release()
15 {
16         for(int i = 0; i < 8; i++) {
17                 if(disk[i] != NULL) {
18                         disk[i]->close();
19                         delete disk[i];
20                 }
21         }
22         SCSI_DEV::release();
23 }
24
25 void SCSI_HDD::reset()
26 {
27         if(!is_hot_swappable) {
28                 for(int drv = 0; drv < 8; drv++) {
29                         if(disk[drv] != NULL) {
30                                 if(image_path[drv][0] != _T('\0') && FILEIO::IsFileExisting(image_path[drv])) {
31                                         disk[drv]->open(image_path[drv], sector_size[drv]);
32                                 } else {
33                                         disk[drv]->close();
34                                 }
35                         }
36                 }
37         }
38         SCSI_DEV::reset();
39 }
40
41 void SCSI_HDD::open(int drv, const _TCHAR* file_path, int default_sector_size)
42 {
43         if(drv < 8 && disk[drv] != NULL) {
44                 if(!is_hot_swappable) {
45                         my_tcscpy_s(image_path[drv], _MAX_PATH, file_path);
46                         sector_size[drv] = default_sector_size;
47                 } else {
48                         disk[drv]->open(file_path, default_sector_size);
49                 }
50         }
51 }
52
53 void SCSI_HDD::close(int drv)
54 {
55         if(drv < 8 && disk[drv] != NULL) {
56                 if(!is_hot_swappable) {
57                         image_path[drv][0] = _T('\0');
58                 } else {
59                         disk[drv]->close();
60                 }
61         }
62 }
63
64 bool SCSI_HDD::mounted(int drv)
65 {
66         if(drv < 8 && disk[drv] != NULL) {
67                 if(!is_hot_swappable) {
68                         return (image_path[drv][0] != _T('\0'));
69                 } else {
70                         return disk[drv]->mounted();
71                 }
72         }
73         return false;
74 }
75
76 bool SCSI_HDD::accessed(int drv)
77 {
78         if(drv < 8 && disk[drv] != NULL) {
79                 return disk[drv]->accessed();
80         }
81         return false;
82 }
83
84 bool SCSI_HDD::is_device_existing()
85 {
86         for(int i = 0; i < 8; i++) {
87                 if(disk[i] != NULL && disk[i]->mounted()) {
88                         return true;
89                 }
90         }
91         return false;
92 }
93
94 uint32_t SCSI_HDD::physical_block_size()
95 {
96         HARDDISK *unit = disk[get_logical_unit_number()];
97         
98         if(unit != NULL && unit->mounted()) {
99                 return unit->sector_size;
100         }
101         return 0;// 512;
102 }
103
104 uint32_t SCSI_HDD::logical_block_size()
105 {
106         HARDDISK *unit = disk[get_logical_unit_number()];
107         
108         if(unit != NULL && unit->mounted()) {
109                 return unit->sector_size;
110         }
111         return 0;// 512;
112 }
113
114 uint32_t SCSI_HDD::max_logical_block_addr()
115 {
116         HARDDISK *unit = disk[get_logical_unit_number()];
117         
118         if(unit != NULL && unit->mounted() && unit->sector_num > 0) {
119                 return unit->sector_num - 1;
120         }
121         return 0;
122 }
123
124 bool SCSI_HDD::read_buffer(int length)
125 {
126         if(!(command[0] == SCSI_CMD_READ6 || command[0] == SCSI_CMD_READ10 || command[0] == SCSI_CMD_READ12)) {
127                 for(int i = 0; i < length; i++) {
128                         buffer->write(0);
129                         position++;
130                 }
131                 set_sense_code(SCSI_SENSE_NOSENSE);
132                 return true;
133         }
134         HARDDISK *unit = disk[get_logical_unit_number()];
135         
136         if(!(unit != NULL && unit->mounted())) {
137                 set_sense_code(SCSI_SENSE_NOTREADY);
138                 return false;
139         }
140         while(length > 0) {
141                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
142                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
143                 
144                 if(!unit->read_buffer((long)position, tmp_length, tmp_buffer)) {
145                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
146                         return false;
147                 }
148                 for(int i = 0; i < tmp_length; i++) {
149                         buffer->write(tmp_buffer[i]);
150                 }
151                 length -= tmp_length;
152                 position += tmp_length;
153         }
154         set_sense_code(SCSI_SENSE_NOSENSE);
155         return true;
156 }
157
158 bool SCSI_HDD::write_buffer(int length)
159 {
160         if(!(command[0] == SCSI_CMD_WRITE6 || command[0] == SCSI_CMD_WRITE10 || command[0] == SCSI_CMD_WRITE12)) {
161                 for(int i = 0; i < length; i++) {
162                         buffer->read();
163                         position++;
164                 }
165                 set_sense_code(SCSI_SENSE_NOSENSE);
166                 return true;
167         }
168         HARDDISK *unit = disk[get_logical_unit_number()];
169         
170         if(!(unit != NULL && unit->mounted())) {
171                 set_sense_code(SCSI_SENSE_NOTREADY);
172                 return false;
173         }
174         while(length > 0) {
175                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
176                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
177                 
178                 for(int i = 0; i < tmp_length; i++) {
179                         tmp_buffer[i] = buffer->read();
180                 }
181                 if(!unit->write_buffer((long)position, tmp_length, tmp_buffer)) {
182                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
183                         return false;
184                 }
185                 length -= tmp_length;
186                 position += tmp_length;
187         }
188         set_sense_code(SCSI_SENSE_NOSENSE);
189         return true;
190 }
191
192 #define STATE_VERSION   3
193
194 bool SCSI_HDD::process_state(FILEIO* state_fio, bool loading)
195 {
196         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
197                 return false;
198         }
199         if(!state_fio->StateCheckInt32(this_device_id)) {
200                 return false;
201         }
202         /*
203         for(int drv = 0; drv < 8; drv++) {
204                 if(disk[drv] != NULL) {
205                         if(!disk[drv]->process_state(state_fio, loading)) {
206                                 return false;
207                         }
208                 }
209         }
210         */
211         state_fio->StateArray(&image_path[0][0], sizeof(image_path), 1);
212         state_fio->StateArray(sector_size, sizeof(sector_size), 1);
213         return SCSI_DEV::process_state(state_fio, loading);
214 }
215
216 // SASI hard disk drive
217
218 void SASI_HDD::start_command()
219 {
220         switch(command[0]) {
221         case SCSI_CMD_REQ_SENSE:
222                 #ifdef _SCSI_DEBUG_LOG
223                         this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: Request Sense\n"), scsi_id);
224                 #endif
225                 // start position
226                 position = (command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3];
227                 position *= physical_block_size();
228                 // transfer length
229                 remain = 4;
230                 // create sense data table
231                 buffer->clear();
232                 buffer->write(get_sense_code());
233                 buffer->write(((max_logical_block_addr() >> 16) & 0x1f) | (get_logical_unit_number() << 5));
234                 buffer->write(((max_logical_block_addr() >>  8) & 0xff));
235                 buffer->write(((max_logical_block_addr() >>  0) & 0xff));
236                 // change to data in phase
237                 set_dat(buffer->read());
238                 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
239                 set_sense_code(SCSI_SENSE_NOSENSE);
240                 return;
241                 
242         case 0xc2:
243                 #ifdef _SCSI_DEBUG_LOG
244                         this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: SASI Command 0xC2\n"), scsi_id);
245                 #endif
246                 // transfer length
247                 remain = 10; // DTC\8cn (\83g\83\89\83\93\83W\83X\83^\8bZ\8fpSPECIAL No.27, P.88)
248                 // clear data buffer
249                 buffer->clear();
250                 // change to data in phase
251                 set_phase_delay(SCSI_PHASE_DATA_OUT, 1.0);
252                 return;
253         }
254         // start standard command
255         SCSI_HDD::start_command();
256 }