OSDN Git Service

09d254cda55363bceda201a24c75bfb8c9951348
[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         HARDDISK *unit = disk[get_logical_unit_number()];
127         
128         if(!(unit != NULL && unit->mounted())) {
129                 set_sense_code(SCSI_SENSE_NOTREADY);
130                 return false;
131         }
132         while(length > 0) {
133                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
134                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
135                 
136                 if(!unit->read_buffer((long)position, tmp_length, tmp_buffer)) {
137                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
138                         return false;
139                 }
140                 for(int i = 0; i < tmp_length; i++) {
141                         buffer->write(tmp_buffer[i]);
142                 }
143                 length -= tmp_length;
144                 position += tmp_length;
145         }
146         set_sense_code(SCSI_SENSE_NOSENSE);
147         return true;
148 }
149
150 bool SCSI_HDD::write_buffer(int length)
151 {
152         HARDDISK *unit = disk[get_logical_unit_number()];
153         
154         if(!(unit != NULL && unit->mounted())) {
155                 set_sense_code(SCSI_SENSE_NOTREADY);
156                 return false;
157         }
158         while(length > 0) {
159                 uint8_t tmp_buffer[SCSI_BUFFER_SIZE];
160                 int tmp_length = min(length, (int)sizeof(tmp_buffer));
161                 
162                 for(int i = 0; i < tmp_length; i++) {
163                         tmp_buffer[i] = buffer->read();
164                 }
165                 if(!unit->write_buffer((long)position, tmp_length, tmp_buffer)) {
166                         set_sense_code(SCSI_SENSE_ILLGLBLKADDR); //SCSI_SENSE_NORECORDFND
167                         return false;
168                 }
169                 length -= tmp_length;
170                 position += tmp_length;
171         }
172         set_sense_code(SCSI_SENSE_NOSENSE);
173         return true;
174 }
175
176 #define STATE_VERSION   3
177
178 bool SCSI_HDD::process_state(FILEIO* state_fio, bool loading)
179 {
180         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
181                 return false;
182         }
183         if(!state_fio->StateCheckInt32(this_device_id)) {
184                 return false;
185         }
186         /*
187         for(int drv = 0; drv < 8; drv++) {
188                 if(disk[drv] != NULL) {
189                         if(!disk[drv]->process_state(state_fio, loading)) {
190                                 return false;
191                         }
192                 }
193         }
194         */
195         state_fio->StateArray(&image_path[0][0], sizeof(image_path), 1);
196         state_fio->StateArray(sector_size, sizeof(sector_size), 1);
197         return SCSI_DEV::process_state(state_fio, loading);
198 }
199
200 // SASI hard disk drive
201
202 void SASI_HDD::start_command()
203 {
204         switch(command[0]) {
205         case SCSI_CMD_REQ_SENSE:
206                 #ifdef _SCSI_DEBUG_LOG
207                         this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: Request Sense\n"), scsi_id);
208                 #endif
209                 // start position
210                 position = (command[1] & 0x1f) * 0x10000 + command[2] * 0x100 + command[3];
211                 position *= physical_block_size();
212                 // transfer length
213                 remain = 4;
214                 // create sense data table
215                 buffer->clear();
216                 buffer->write(get_sense_code());
217                 buffer->write(((max_logical_block_addr() >> 16) & 0x1f) | (get_logical_unit_number() << 5));
218                 buffer->write(((max_logical_block_addr() >>  8) & 0xff));
219                 buffer->write(((max_logical_block_addr() >>  0) & 0xff));
220                 // change to data in phase
221                 set_dat(buffer->read());
222                 set_phase_delay(SCSI_PHASE_DATA_IN, 10.0);
223                 set_sense_code(SCSI_SENSE_NOSENSE);
224                 return;
225                 
226         case 0xc2:
227                 #ifdef _SCSI_DEBUG_LOG
228                         this->out_debug_log(_T("[SASI_HDD:ID=%d] Command: SASI Command 0xC2\n"), scsi_id);
229                 #endif
230                 // transfer length
231                 remain = 10; // DTC\8cn (\83g\83\89\83\93\83W\83X\83^\8bZ\8fpSPECIAL No.27, P.88)
232                 // clear data buffer
233                 buffer->clear();
234                 // change to data in phase
235                 set_phase_delay(SCSI_PHASE_DATA_OUT, 1.0);
236                 return;
237         }
238         // start standard command
239         SCSI_HDD::start_command();
240 }