1 /////////////////////////////////////////////////////////////////////////
2 // $Id: scsi_device.cc 14312 2021-07-12 19:05:25Z vruppert $
3 /////////////////////////////////////////////////////////////////////////
4 //
5 // SCSI emulation layer (ported from QEMU)
6 //
7 // Copyright (C) 2006 CodeSourcery.
8 // Based on code by Fabrice Bellard
9 //
10 // Written by Paul Brook
11 //
12 // Copyright (C) 2007-2021 The Bochs Project
13 //
14 // This library is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Lesser General Public
16 // License as published by the Free Software Foundation; either
17 // version 2 of the License, or (at your option) any later version.
18 //
19 // This library is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Lesser General Public License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public
25 // License along with this library; if not, write to the Free Software
26 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27 /////////////////////////////////////////////////////////////////////////
28
29 // Define BX_PLUGGABLE in files that can be compiled into plugins. For
30 // platforms that require a special tag on exported symbols, BX_PLUGGABLE
31 // is used to know when we are exporting symbols and when we are importing.
32 #define BX_PLUGGABLE
33
34 #include "iodev.h"
35
36 #if BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
37 #include "hdimage/hdimage.h"
38 #include "hdimage/cdrom.h"
39 #include "scsi_device.h"
40
41 #define LOG_THIS
42
43 #define DEVICE_NAME "SCSI drive"
44
45 static SCSIRequest *free_requests = NULL;
46 static Bit32u serial_number = 12345678;
47
scsireq_save_handler(void * class_ptr,bx_param_c * param)48 Bit64s scsireq_save_handler(void *class_ptr, bx_param_c *param)
49 {
50 char fname[BX_PATHNAME_LEN];
51 char path[BX_PATHNAME_LEN+1];
52
53 param->get_param_path(fname, BX_PATHNAME_LEN);
54 if (!strncmp(fname, "bochs.", 6)) {
55 strcpy(fname, fname+6);
56 }
57 if (SIM->get_param_string(BXPN_RESTORE_PATH)->isempty()) {
58 return 0;
59 }
60 sprintf(path, "%s/%s", SIM->get_param_string(BXPN_RESTORE_PATH)->getptr(), fname);
61 return ((scsi_device_t*)class_ptr)->save_requests(path);
62 }
63
scsireq_restore_handler(void * class_ptr,bx_param_c * param,Bit64s value)64 void scsireq_restore_handler(void *class_ptr, bx_param_c *param, Bit64s value)
65 {
66 char fname[BX_PATHNAME_LEN];
67 char path[BX_PATHNAME_LEN+1];
68
69 if (value != 0) {
70 param->get_param_path(fname, BX_PATHNAME_LEN);
71 if (!strncmp(fname, "bochs.", 6)) {
72 strcpy(fname, fname+6);
73 }
74 sprintf(path, "%s/%s", SIM->get_param_string(BXPN_RESTORE_PATH)->getptr(), fname);
75 ((scsi_device_t*)class_ptr)->restore_requests(path);
76 }
77 }
78
scsi_device_t(device_image_t * _hdimage,int _tcq,scsi_completionfn _completion,void * _dev)79 scsi_device_t::scsi_device_t(device_image_t *_hdimage, int _tcq,
80 scsi_completionfn _completion, void *_dev)
81 {
82 type = SCSIDEV_TYPE_DISK;
83 cdrom = NULL;
84 hdimage = _hdimage;
85 requests = NULL;
86 sense = 0;
87 tcq = _tcq;
88 completion = _completion;
89 dev = _dev;
90 block_size = hdimage->sect_size;
91 locked = 0;
92 inserted = 1;
93 max_lba = (hdimage->hd_size / block_size) - 1;
94 curr_lba = max_lba;
95 sprintf(drive_serial_str, "%d", serial_number++);
96 seek_timer_index =
97 DEV_register_timer(this, seek_timer_handler, 1000, 0, 0, "USB HD seek");
98 statusbar_id = bx_gui->register_statusitem("USB-HD", 1);
99
100 put("SCSIHD");
101 }
102
scsi_device_t(cdrom_base_c * _cdrom,int _tcq,scsi_completionfn _completion,void * _dev)103 scsi_device_t::scsi_device_t(cdrom_base_c *_cdrom, int _tcq,
104 scsi_completionfn _completion, void *_dev)
105 {
106 type = SCSIDEV_TYPE_CDROM;
107 cdrom = _cdrom;
108 hdimage = NULL;
109 requests = NULL;
110 sense = 0;
111 tcq = _tcq;
112 completion = _completion;
113 dev = _dev;
114 block_size = 2048;
115 locked = 0;
116 inserted = 0;
117 max_lba = 0;
118 curr_lba = 0;
119 sprintf(drive_serial_str, "%d", serial_number++);
120 seek_timer_index =
121 DEV_register_timer(this, seek_timer_handler, 1000, 0, 0, "USB CD seek");
122 statusbar_id = bx_gui->register_statusitem("USB-CD", 1);
123
124 put("SCSICD");
125 }
126
~scsi_device_t(void)127 scsi_device_t::~scsi_device_t(void)
128 {
129 SCSIRequest *r, *next;
130
131 if (requests) {
132 r = requests;
133 while (r != NULL) {
134 next = r->next;
135 delete [] r->dma_buf;
136 delete r;
137 r = next;
138 }
139 }
140 if (free_requests) {
141 r = free_requests;
142 while (r != NULL) {
143 next = r->next;
144 delete [] r->dma_buf;
145 delete r;
146 r = next;
147 }
148 free_requests = NULL;
149 }
150 bx_gui->unregister_statusitem(statusbar_id);
151 bx_pc_system.deactivate_timer(seek_timer_index);
152 bx_pc_system.unregisterTimer(seek_timer_index);
153 }
154
register_state(bx_list_c * parent,const char * name)155 void scsi_device_t::register_state(bx_list_c *parent, const char *name)
156 {
157 bx_list_c *list = new bx_list_c(parent, name, "");
158 BXRS_DEC_PARAM_SIMPLE(list, sense);
159 BXRS_PARAM_BOOL(list, locked, locked);
160 BXRS_DEC_PARAM_SIMPLE(list, curr_lba);
161 bx_param_bool_c *requests = new bx_param_bool_c(list, "requests", NULL, NULL, 0);
162 requests->set_sr_handlers(this, scsireq_save_handler, scsireq_restore_handler);
163 }
164
165 // SCSI request handling
166
scsi_new_request(Bit32u tag)167 SCSIRequest* scsi_device_t::scsi_new_request(Bit32u tag)
168 {
169 SCSIRequest *r;
170
171 if (free_requests) {
172 r = free_requests;
173 free_requests = r->next;
174 } else {
175 r = new SCSIRequest;
176 r->dma_buf = new Bit8u[SCSI_DMA_BUF_SIZE];
177 }
178 r->tag = tag;
179 r->sector_count = 0;
180 r->write_cmd = 0;
181 r->async_mode = 0;
182 r->seek_pending = 0;
183 r->buf_len = 0;
184 r->status = 0;
185
186 r->next = requests;
187 requests = r;
188 return r;
189 }
190
scsi_remove_request(SCSIRequest * r)191 void scsi_device_t::scsi_remove_request(SCSIRequest *r)
192 {
193 SCSIRequest *last;
194
195 if (requests == r) {
196 requests = r->next;
197 } else {
198 last = requests;
199 while (last != NULL) {
200 if (last->next != r)
201 last = last->next;
202 else
203 break;
204 }
205 if (last) {
206 last->next = r->next;
207 } else {
208 BX_ERROR(("orphaned request"));
209 }
210 }
211 r->next = free_requests;
212 free_requests = r;
213 }
214
scsi_find_request(Bit32u tag)215 SCSIRequest* scsi_device_t::scsi_find_request(Bit32u tag)
216 {
217 SCSIRequest *r = requests;
218 while (r != NULL) {
219 if (r->tag != tag)
220 r = r->next;
221 else
222 break;
223 }
224 return r;
225 }
226
save_requests(const char * path)227 bool scsi_device_t::save_requests(const char *path)
228 {
229 char tmppath[BX_PATHNAME_LEN];
230 FILE *fp, *fp2;
231
232 if (requests != NULL) {
233 fp = fopen(path, "w");
234 if (fp != NULL) {
235 SCSIRequest *r = requests;
236 Bit32u i = 0;
237 while (r != NULL) {
238 fprintf(fp, "%u = {\n", i);
239 fprintf(fp, " tag = %u\n", r->tag);
240 fprintf(fp, " sector = " FMT_LL "u\n", r->sector);
241 fprintf(fp, " sector_count = %u\n", r->sector_count);
242 fprintf(fp, " buf_len = %d\n", r->buf_len);
243 fprintf(fp, " status = %u\n", r->status);
244 fprintf(fp, " write_cmd = %u\n", r->write_cmd);
245 fprintf(fp, " async_mode = %u\n", r->async_mode);
246 fprintf(fp, " seek_pending = %u\n", r->seek_pending);
247 fprintf(fp, "}\n");
248 if (r->buf_len > 0) {
249 sprintf(tmppath, "%s.%u", path, i);
250 fp2 = fopen(tmppath, "wb");
251 if (fp2 != NULL) {
252 fwrite(r->dma_buf, 1, (size_t)r->buf_len, fp2);
253 }
254 fclose(fp2);
255 }
256 r = r->next;
257 i++;
258 }
259 fclose(fp);
260 return 1;
261 } else {
262 return 0;
263 }
264 } else {
265 return 0;
266 }
267 }
268
restore_requests(const char * path)269 void scsi_device_t::restore_requests(const char *path)
270 {
271 char line[512], pname[16], tmppath[BX_PATHNAME_LEN];
272 char *ret, *ptr;
273 FILE *fp, *fp2;
274 int i, reqid = -1;
275 Bit64s value;
276 Bit32u tag = 0;
277 SCSIRequest *r = NULL;
278 bool rrq_error = 0;
279
280 fp = fopen(path, "r");
281 if (fp != NULL) {
282 do {
283 ret = fgets(line, sizeof(line)-1, fp);
284 line[sizeof(line) - 1] = '\0';
285 size_t len = strlen(line);
286 if ((len > 0) && (line[len-1] < ' '))
287 line[len-1] = '\0';
288 i = 0;
289 if ((ret != NULL) && strlen(line) > 0) {
290 ptr = strtok(line, " ");
291 while (ptr) {
292 if (i == 0) {
293 if (!strcmp(ptr, "}")) {
294 if (r != NULL) {
295 if (r->buf_len > 0) {
296 sprintf(tmppath, "%s.%u", path, reqid);
297 fp2 = fopen(tmppath, "wb");
298 if (fp2 != NULL) {
299 fread(r->dma_buf, 1, (size_t)r->buf_len, fp2);
300 }
301 fclose(fp2);
302 }
303 }
304 reqid = -1;
305 r = NULL;
306 tag = 0;
307 break;
308 } else if (reqid < 0) {
309 reqid = (int)strtol(ptr, NULL, 10);
310 break;
311 } else {
312 strcpy(pname, ptr);
313 }
314 } else if (i == 2) {
315 if (reqid >= 0) {
316 if (!strcmp(pname, "tag")) {
317 if (tag == 0) {
318 tag = (Bit32u)strtoul(ptr, NULL, 10);
319 r = scsi_new_request(tag);
320 if (r == NULL) {
321 BX_ERROR(("restore_requests(): cannot create request"));
322 rrq_error = 1;
323 }
324 } else {
325 BX_ERROR(("restore_requests(): data format error"));
326 rrq_error = 1;
327 }
328 } else {
329 value = (Bit64s)strtoll(ptr, NULL, 10);
330 if (!strcmp(pname, "sector")) {
331 r->sector = (Bit64u)value;
332 } else if (!strcmp(pname, "sector_count")) {
333 r->sector_count = (Bit32u)value;
334 } else if (!strcmp(pname, "buf_len")) {
335 r->buf_len = (int)value;
336 } else if (!strcmp(pname, "status")) {
337 r->status = (Bit32u)value;
338 } else if (!strcmp(pname, "write_cmd")) {
339 r->write_cmd = (bool)value;
340 } else if (!strcmp(pname, "async_mode")) {
341 r->async_mode = (bool)value;
342 } else if (!strcmp(pname, "seek_pending")) {
343 r->seek_pending = (Bit8u)value;
344 } else {
345 BX_ERROR(("restore_requests(): data format error"));
346 rrq_error = 1;
347 }
348 }
349 } else {
350 BX_ERROR(("restore_requests(): data format error"));
351 rrq_error = 1;
352 }
353 }
354 i++;
355 ptr = strtok(NULL, " ");
356 }
357 }
358 } while (!feof(fp) && !rrq_error);
359 fclose(fp);
360 } else {
361 BX_ERROR(("restore_requests(): error in file open"));
362 }
363 }
364
365 // SCSI command implementation
366
scsi_command_complete(SCSIRequest * r,int status,int _sense)367 void scsi_device_t::scsi_command_complete(SCSIRequest *r, int status, int _sense)
368 {
369 Bit32u tag;
370 BX_DEBUG(("command complete tag=0x%x status=%d sense=%d", r->tag, status, sense));
371 sense = _sense;
372 tag = r->tag;
373 scsi_remove_request(r);
374 completion(dev, SCSI_REASON_DONE, tag, status);
375 }
376
scsi_cancel_io(Bit32u tag)377 void scsi_device_t::scsi_cancel_io(Bit32u tag)
378 {
379 BX_DEBUG(("cancel tag=0x%x", tag));
380 SCSIRequest *r = scsi_find_request(tag);
381 if (r) {
382 bx_pc_system.deactivate_timer(seek_timer_index);
383 scsi_remove_request(r);
384 }
385 }
386
scsi_read_complete(void * req,int ret)387 void scsi_device_t::scsi_read_complete(void *req, int ret)
388 {
389 SCSIRequest *r = (SCSIRequest *)req;
390
391 if (ret) {
392 BX_ERROR(("IO error"));
393 completion(r, SCSI_REASON_DATA, r->tag, 0);
394 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NO_SENSE);
395 return;
396 }
397 BX_DEBUG(("data ready tag=0x%x len=%d", r->tag, r->buf_len));
398 curr_lba = r->sector;
399
400 completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
401 }
402
scsi_read_data(Bit32u tag)403 void scsi_device_t::scsi_read_data(Bit32u tag)
404 {
405 SCSIRequest *r = scsi_find_request(tag);
406 if (!r) {
407 BX_ERROR(("bad read tag 0x%x", tag));
408 return;
409 }
410 if (r->sector_count == (Bit32u)-1) {
411 BX_DEBUG(("read buf_len=%d", r->buf_len));
412 r->sector_count = 0;
413 completion(dev, SCSI_REASON_DATA, r->tag, r->buf_len);
414 return;
415 }
416 BX_DEBUG(("read sector_count=%d", r->sector_count));
417 if (r->sector_count == 0) {
418 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
419 return;
420 }
421 if ((r->async_mode) && (r->seek_pending == 2)) {
422 start_seek(r);
423 } else if (!r->seek_pending) {
424 seek_complete(r);
425 }
426 }
427
scsi_write_complete(void * req,int ret)428 void scsi_device_t::scsi_write_complete(void *req, int ret)
429 {
430 SCSIRequest *r = (SCSIRequest *)req;
431 Bit32u len;
432
433 if (ret) {
434 BX_ERROR(("IO error"));
435 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
436 return;
437 }
438
439 if (r->sector_count == 0) {
440 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
441 } else {
442 len = r->sector_count * block_size;
443 if (len > SCSI_DMA_BUF_SIZE) {
444 len = SCSI_DMA_BUF_SIZE;
445 }
446 r->buf_len = len;
447 BX_DEBUG(("write complete tag=0x%x more=%d", r->tag, len));
448 curr_lba = r->sector;
449 completion(dev, SCSI_REASON_DATA, r->tag, len);
450 }
451 }
452
scsi_write_data(Bit32u tag)453 void scsi_device_t::scsi_write_data(Bit32u tag)
454 {
455 SCSIRequest *r = scsi_find_request(tag);
456
457 BX_DEBUG(("write data tag=0x%x", tag));
458 if (!r) {
459 BX_ERROR(("bad write tag 0x%x", tag));
460 return;
461 }
462 if (type == SCSIDEV_TYPE_DISK) {
463 if ((r->buf_len / block_size) > 0) {
464 if ((r->async_mode) && (r->seek_pending == 2)) {
465 start_seek(r);
466 } else if (!r->seek_pending) {
467 seek_complete(r);
468 }
469 } else {
470 scsi_write_complete(r, 0);
471 }
472 } else {
473 BX_ERROR(("CD-ROM: write not supported"));
474 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
475 }
476 }
477
scsi_get_buf(Bit32u tag)478 Bit8u* scsi_device_t::scsi_get_buf(Bit32u tag)
479 {
480 SCSIRequest *r = scsi_find_request(tag);
481 if (!r) {
482 BX_ERROR(("bad buffer tag 0x%x", tag));
483 return NULL;
484 }
485 return r->dma_buf;
486 }
487
scsi_send_command(Bit32u tag,Bit8u * buf,int lun,bool async)488 Bit32s scsi_device_t::scsi_send_command(Bit32u tag, Bit8u *buf, int lun, bool async)
489 {
490 Bit64u nb_sectors;
491 Bit64u lba;
492 Bit32s len;
493 //int cmdlen;
494 Bit8u command;
495 Bit8u *outbuf;
496 SCSIRequest *r;
497
498 command = buf[0];
499 r = scsi_find_request(tag);
500 if (r) {
501 BX_ERROR(("tag 0x%x already in use", tag));
502 scsi_cancel_io(tag);
503 }
504 r = scsi_new_request(tag);
505 outbuf = r->dma_buf;
506 BX_DEBUG(("command: lun=%d tag=0x%x data=0x%02x", lun, tag, buf[0]));
507 switch (command >> 5) {
508 case 0:
509 lba = buf[3] | (buf[2] << 8) | ((buf[1] & 0x1f) << 16);
510 len = buf[4];
511 // cmdlen = 6;
512 break;
513 case 1:
514 case 2:
515 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
516 len = buf[8] | (buf[7] << 8);
517 // cmdlen = 10;
518 break;
519 case 4:
520 lba = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24) |
521 ((Bit64u)buf[5] << 32) | ((Bit64u)buf[4] << 40) |
522 ((Bit64u)buf[3] << 48) | ((Bit64u)buf[2] << 56);
523 len = buf[13] | (buf[12] << 8) | (buf[11] << 16) | (buf[10] << 24);
524 // cmdlen = 16;
525 break;
526 case 5:
527 lba = buf[5] | (buf[4] << 8) | (buf[3] << 16) | (buf[2] << 24);
528 len = buf[9] | (buf[8] << 8) | (buf[7] << 16) | (buf[6] << 24);
529 // cmdlen = 12;
530 break;
531 default:
532 BX_ERROR(("Unsupported command length, command %x", command));
533 goto fail;
534 }
535 if (lun || buf[1] >> 5) {
536 BX_ERROR(("unimplemented LUN %d", lun ? lun : buf[1] >> 5));
537 if ((command != 0x03) && (command != 0x12)) // REQUEST SENSE and INQUIRY
538 goto fail;
539 }
540 switch (command) {
541 case 0x0:
542 BX_DEBUG(("Test Unit Ready"));
543 if (!inserted)
544 goto notready;
545 break;
546 case 0x03:
547 BX_DEBUG(("request Sense (len %d)", len));
548 if (len < 4)
549 goto fail;
550 memset(outbuf, 0, 4);
551 r->buf_len = 4;
552 if ((sense == SENSE_NOT_READY) && (len >= 18)) {
553 memset(outbuf, 0, 18);
554 r->buf_len = 18;
555 outbuf[7] = 10;
556 /* asc 0x3a, ascq 0: Medium not present */
557 outbuf[12] = 0x3a;
558 outbuf[13] = 0;
559 }
560 outbuf[0] = 0xf0;
561 outbuf[1] = 0;
562 outbuf[2] = sense;
563 break;
564 case 0x12:
565 BX_DEBUG(("inquiry (len %d)", len));
566 if (buf[1] & 0x2) {
567 // Command support data - optional, not implemented
568 BX_ERROR(("optional INQUIRY command support request not implemented"));
569 goto fail;
570 } else if (buf[1] & 0x1) {
571 // Vital product data
572 Bit8u page_code = buf[2];
573 if (len < 4) {
574 BX_ERROR(("Error: Inquiry (EVPD[%02X]) buffer size %d is less than 4", page_code, len));
575 goto fail;
576 }
577 switch (page_code) {
578 case 0x00:
579 // Supported page codes, mandatory
580 BX_DEBUG(("Inquiry EVPD[Supported pages] buffer size %d", len));
581
582 r->buf_len = 0;
583
584 if (type == SCSIDEV_TYPE_CDROM) {
585 outbuf[r->buf_len++] = 5;
586 } else {
587 outbuf[r->buf_len++] = 0;
588 }
589
590 outbuf[r->buf_len++] = 0x00; // this page
591 outbuf[r->buf_len++] = 0x00;
592 outbuf[r->buf_len++] = 3; // number of pages
593 outbuf[r->buf_len++] = 0x00; // list of supported pages (this page)
594 outbuf[r->buf_len++] = 0x80; // unit serial number
595 outbuf[r->buf_len++] = 0x83; // device identification
596 break;
597
598 case 0x80:
599 {
600 int l;
601
602 // Device serial number, optional
603 if (len < 4) {
604 BX_ERROR(("Error: EVPD[Serial number] Inquiry buffer size %d too small, %d needed", len, 4));
605 goto fail;
606 }
607
608 BX_DEBUG(("Inquiry EVPD[Serial number] buffer size %d\n", len));
609 l = BX_MIN(len, (int)strlen(drive_serial_str));
610
611 r->buf_len = 0;
612
613 // Supported page codes
614 if (type == SCSIDEV_TYPE_CDROM) {
615 outbuf[r->buf_len++] = 5;
616 } else {
617 outbuf[r->buf_len++] = 0;
618 }
619
620 outbuf[r->buf_len++] = 0x80; // this page
621 outbuf[r->buf_len++] = 0x00;
622 outbuf[r->buf_len++] = l;
623 memcpy(&outbuf[r->buf_len], drive_serial_str, l);
624 r->buf_len += l;
625 }
626 break;
627
628 case 0x83:
629 {
630 // Device identification page, mandatory
631 size_t max_len = 255 - 8;
632 size_t id_len = strlen(DEVICE_NAME);
633 if (id_len > max_len)
634 id_len = max_len;
635
636 BX_DEBUG(("Inquiry EVPD[Device identification] buffer size %d", len));
637 r->buf_len = 0;
638 if (type == SCSIDEV_TYPE_CDROM) {
639 outbuf[r->buf_len++] = 5;
640 } else {
641 outbuf[r->buf_len++] = 0;
642 }
643
644 outbuf[r->buf_len++] = 0x83; // this page
645 outbuf[r->buf_len++] = 0x00;
646 outbuf[r->buf_len++] = 3 + (Bit8u)id_len;
647
648 outbuf[r->buf_len++] = 0x2; // ASCII
649 outbuf[r->buf_len++] = 0; // not officially assigned
650 outbuf[r->buf_len++] = 0; // reserved
651 outbuf[r->buf_len++] = (Bit8u)id_len; // length of data following
652
653 memcpy(&outbuf[r->buf_len], DEVICE_NAME, id_len);
654 r->buf_len += (int)id_len;
655 }
656 break;
657
658 default:
659 BX_ERROR(("Error: unsupported Inquiry (EVPD[%02X]) buffer size %d", page_code, len));
660 goto fail;
661 }
662 // done with EVPD
663 break;
664 } else {
665 // Standard INQUIRY data
666 if (buf[2] != 0) {
667 BX_ERROR(("Error: Inquiry (STANDARD) page or code is non-zero [%02X]", buf[2]));
668 goto fail;
669 }
670
671 // PAGE CODE == 0
672 if (len < 5) {
673 BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 5", len));
674 goto fail;
675 }
676
677 if (len < 36) {
678 BX_ERROR(("Error: Inquiry (STANDARD) buffer size %d is less than 36 (TODO: only 5 required)", len));
679 }
680 }
681
682 if(len > SCSI_MAX_INQUIRY_LEN)
683 len = SCSI_MAX_INQUIRY_LEN;
684 memset(outbuf, 0, len);
685 if (lun || buf[1] >> 5) {
686 outbuf[0] = 0x7f; // LUN not supported
687 } else if (type == SCSIDEV_TYPE_CDROM) {
688 outbuf[0] = 5;
689 outbuf[1] = 0x80;
690 memcpy(&outbuf[16], "BOCHS CD-ROM ", 16);
691 } else {
692 outbuf[0] = 0;
693 memcpy(&outbuf[16], "BOCHS HARDDISK ", 16);
694 }
695 memcpy(&outbuf[8], "BOCHS ", 8);
696 memcpy(&outbuf[32], "1.0", 4);
697 // Identify device as SCSI-3 rev 1.
698 // Some later commands are also implemented.
699 outbuf[2] = 3;
700 outbuf[3] = 2; // Format 2
701 outbuf[4] = len - 5; // Additional Length = (Len - 1) - 4
702 // Sync data transfer and TCQ.
703 outbuf[7] = 0x10 | (tcq ? 0x02 : 0);
704 r->buf_len = len;
705 break;
706 case 0x16:
707 BX_INFO(("Reserve(6)"));
708 if (buf[1] & 1)
709 goto fail;
710 break;
711 case 0x17:
712 BX_INFO(("Release(6)"));
713 if (buf[1] & 1)
714 goto fail;
715 break;
716 case 0x1a:
717 case 0x5a:
718 {
719 Bit8u *p;
720 int page;
721
722 page = buf[2] & 0x3f;
723 BX_DEBUG(("mode sense (page %d, len %d)", page, len));
724 p = outbuf;
725 memset(p, 0, 4);
726 outbuf[1] = 0; /* Default media type. */
727 outbuf[3] = 0; /* Block descriptor length. */
728 if (type == SCSIDEV_TYPE_CDROM) {
729 outbuf[2] = 0x80; /* Readonly. */
730 }
731 p += 4;
732 if ((page == 4) || (page == 5)) {
733 BX_ERROR(("mode sense: page %d not implemented", page));
734 }
735 if ((page == 8 || page == 0x3f)) {
736 /* Caching page. */
737 memset(p, 0, 20);
738 p[0] = 8;
739 p[1] = 0x12;
740 p[2] = 4; /* WCE */
741 p += 20;
742 }
743 if ((page == 0x3f || page == 0x2a)
744 && (type == SCSIDEV_TYPE_CDROM)) {
745 /* CD Capabilities and Mechanical Status page. */
746 p[0] = 0x2a;
747 p[1] = 0x14;
748 p[2] = 3; // CD-R & CD-RW read
749 p[3] = 0; // Writing not supported
750 p[4] = 0x7f; /* Audio, composite, digital out,
751 mode 2 form 1&2, multi session */
752 p[5] = 0xff; /* CD DA, DA accurate, RW supported,
753 RW corrected, C2 errors, ISRC,
754 UPC, Bar code */
755 p[6] = 0x2d | (locked ? 2 : 0);
756 /* Locking supported, jumper present, eject, tray */
757 p[7] = 0; /* no volume & mute control, no changer */
758 p[8] = (50 * 176) >> 8; // 50x read speed
759 p[9] = (50 * 176) & 0xff;
760 p[10] = 0 >> 8; // No volume
761 p[11] = 0 & 0xff;
762 p[12] = 2048 >> 8; // 2M buffer
763 p[13] = 2048 & 0xff;
764 p[14] = (16 * 176) >> 8; // 16x read speed current
765 p[15] = (16 * 176) & 0xff;
766 p[18] = (16 * 176) >> 8; // 16x write speed
767 p[19] = (16 * 176) & 0xff;
768 p[20] = (16 * 176) >> 8; // 16x write speed current
769 p[21] = (16 * 176) & 0xff;
770 p += 22;
771 }
772 r->buf_len = (int)(p - outbuf);
773 outbuf[0] = r->buf_len - 4;
774 if (r->buf_len > (int)len)
775 r->buf_len = len;
776 }
777 break;
778 case 0x1b:
779 BX_INFO(("Start Stop Unit"));
780 if (type == SCSIDEV_TYPE_CDROM && (buf[4] & 2)) {
781 if (!(buf[4] & 1)) {
782 // eject medium
783 cdrom->eject_cdrom();
784 inserted = 0;
785 }
786 }
787 break;
788 case 0x1e:
789 BX_INFO(("Prevent Allow Medium Removal (prevent = %d)", buf[4] & 3));
790 locked = buf[4] & 1;
791 break;
792 case 0x25:
793 BX_DEBUG(("Read Capacity"));
794 // The normal LEN field for this command is zero
795 memset(outbuf, 0, 8);
796 if (type == SCSIDEV_TYPE_CDROM) {
797 nb_sectors = max_lba;
798 } else {
799 nb_sectors = hdimage->hd_size / block_size;
800 nb_sectors--;
801 }
802 /* Returned value is the address of the last sector. */
803 if (nb_sectors) {
804 outbuf[0] = (Bit8u)((nb_sectors >> 24) & 0xff);
805 outbuf[1] = (Bit8u)((nb_sectors >> 16) & 0xff);
806 outbuf[2] = (Bit8u)((nb_sectors >> 8) & 0xff);
807 outbuf[3] = (Bit8u)(nb_sectors & 0xff);
808 outbuf[4] = 0;
809 outbuf[5] = 0;
810 outbuf[6] = (block_size >> 8);
811 outbuf[7] = 0;
812 r->buf_len = 8;
813 } else {
814 notready:
815 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_NOT_READY);
816 return 0;
817 }
818 break;
819 case 0x08:
820 case 0x28:
821 case 0x88:
822 BX_DEBUG(("Read (sector " FMT_LL "d, count %d)", lba, len));
823 if (!inserted)
824 goto notready;
825 if (lba > max_lba)
826 goto illegal_lba;
827 r->sector = lba;
828 r->sector_count = len;
829 if (async) {
830 r->seek_pending = 2;
831 }
832 r->async_mode = async;
833 break;
834 case 0x0a:
835 case 0x2a:
836 case 0x8a:
837 BX_DEBUG(("Write (sector " FMT_LL "d, count %d)", lba, len));
838 if (lba > max_lba)
839 goto illegal_lba;
840 r->sector = lba;
841 r->sector_count = len;
842 r->write_cmd = 1;
843 if (async) {
844 r->seek_pending = 2;
845 }
846 r->async_mode = async;
847 break;
848 case 0x35:
849 BX_DEBUG(("Synchronise cache (sector " FMT_LL "d, count %d)", lba, len));
850 // TODO: flush cache
851 break;
852 case 0x43:
853 {
854 int start_track, format, msf, toclen = 0;
855
856 if (type == SCSIDEV_TYPE_CDROM) {
857 if (!inserted)
858 goto notready;
859 msf = buf[1] & 2;
860 format = buf[2] & 0xf;
861 start_track = buf[6];
862 BX_DEBUG(("Read TOC (track %d format %d msf %d)", start_track, format, msf >> 1));
863 cdrom->read_toc(outbuf, &toclen, msf, start_track, format);
864 if (toclen > 0) {
865 if (len > toclen)
866 len = toclen;
867 r->buf_len = len;
868 break;
869 }
870 BX_ERROR(("Read TOC error"));
871 goto fail;
872 } else {
873 goto fail;
874 }
875 }
876 case 0x46:
877 BX_DEBUG(("Get Configuration (rt %d, maxlen %d)", buf[1] & 3, len));
878 memset(outbuf, 0, 8);
879 /* ??? This shoud probably return much more information. For now
880 just return the basic header indicating the CD-ROM profile. */
881 outbuf[7] = 8; // CD-ROM
882 r->buf_len = 8;
883 break;
884 case 0x56:
885 BX_INFO(("Reserve(10)"));
886 if (buf[1] & 3)
887 goto fail;
888 break;
889 case 0x57:
890 BX_INFO(("Release(10)"));
891 if (buf[1] & 3)
892 goto fail;
893 break;
894 case 0xa0:
895 BX_INFO(("Report LUNs (len %d)", len));
896 if (len < 16)
897 goto fail;
898 memset(outbuf, 0, 16);
899 outbuf[3] = 8;
900 r->buf_len = 16;
901 break;
902 case 0x2f:
903 BX_DEBUG(("Verify (sector " FMT_LL "d, count %d)", lba, len));
904 if (lba > max_lba)
905 goto illegal_lba;
906 if (buf[1] & 2) {
907 BX_ERROR(("Verify with ByteChk not implemented yet"));
908 goto fail;
909 }
910 break;
911 case 0x23: {
912 // USBMASS-UFI10.pdf rev 1.0 Section 4.10
913 BX_INFO(("READ FORMAT CAPACITIES (MMC)"));
914
915 unsigned len = (buf[7]<<8) | buf[8];
916 #define OUR_LEN 12
917
918 // Cap List Header
919 outbuf[0] = 0;
920 outbuf[1] = 0;
921 outbuf[2] = 0;
922 outbuf[3] = OUR_LEN;
923
924 // Current/Max Cap Header
925 if (type == SCSIDEV_TYPE_CDROM) {
926 nb_sectors = max_lba;
927 } else {
928 nb_sectors = (hdimage->hd_size / block_size);
929 nb_sectors--;
930 }
931 /* Returned value is the address of the last sector. */
932 outbuf[4] = (Bit8u)((nb_sectors >> 24) & 0xff);
933 outbuf[5] = (Bit8u)((nb_sectors >> 16) & 0xff);
934 outbuf[6] = (Bit8u)((nb_sectors >> 8) & 0xff);
935 outbuf[7] = (Bit8u)(nb_sectors & 0xff);
936 outbuf[8] = 2; // formatted (1 = unformatted)
937 outbuf[9] = 0;
938 outbuf[10] = (block_size >> 8);
939 outbuf[11] = 0;
940
941 r->buf_len = (len < OUR_LEN) ? len : OUR_LEN;
942
943 }
944 break;
945 default:
946 BX_ERROR(("Unknown SCSI command (%2.2x)", buf[0]));
947 fail:
948 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_ILLEGAL_REQUEST);
949 return 0;
950 illegal_lba:
951 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
952 return 0;
953 }
954 if (r->sector_count == 0 && r->buf_len == 0) {
955 scsi_command_complete(r, STATUS_GOOD, SENSE_NO_SENSE);
956 }
957 len = r->sector_count * block_size + r->buf_len;
958 if (r->write_cmd) {
959 return -len;
960 } else {
961 if (!r->sector_count)
962 r->sector_count = (Bit32u) -1;
963 return len;
964 }
965 }
966
set_inserted(bool value)967 void scsi_device_t::set_inserted(bool value)
968 {
969 inserted = value;
970 if (inserted) {
971 max_lba = cdrom->capacity() - 1;
972 curr_lba = max_lba;
973 } else {
974 max_lba = 0;
975 }
976 }
977
start_seek(SCSIRequest * r)978 void scsi_device_t::start_seek(SCSIRequest *r)
979 {
980 Bit64s new_pos, prev_pos, max_pos;
981 Bit32u seek_time;
982 double fSeekBase, fSeekTime;
983
984 max_pos = max_lba;
985 prev_pos = curr_lba;
986 new_pos = r->sector;
987 if (type == SCSIDEV_TYPE_CDROM) {
988 fSeekBase = 80000.0;
989 } else {
990 fSeekBase = 5000.0;
991 }
992 fSeekTime = fSeekBase * (double)abs((int)(new_pos - prev_pos + 1)) / (max_pos + 1);
993 seek_time = 4000 + (Bit32u)fSeekTime;
994 bx_pc_system.activate_timer(seek_timer_index, seek_time, 0);
995 bx_pc_system.setTimerParam(seek_timer_index, r->tag);
996 r->seek_pending = 1;
997 }
998
seek_timer_handler(void * this_ptr)999 void scsi_device_t::seek_timer_handler(void *this_ptr)
1000 {
1001 scsi_device_t *class_ptr = (scsi_device_t *) this_ptr;
1002 class_ptr->seek_timer();
1003 }
1004
seek_timer()1005 void scsi_device_t::seek_timer()
1006 {
1007 Bit32u tag = bx_pc_system.triggeredTimerParam();
1008 SCSIRequest *r = scsi_find_request(tag);
1009
1010 seek_complete(r);
1011 }
1012
seek_complete(SCSIRequest * r)1013 void scsi_device_t::seek_complete(SCSIRequest *r)
1014 {
1015 Bit32u i, n;
1016 int ret = 0;
1017
1018 r->seek_pending = 0;
1019 if (!r->write_cmd) {
1020 bx_gui->statusbar_setitem(statusbar_id, 1);
1021 n = r->sector_count;
1022 if (n > (Bit32u)(SCSI_DMA_BUF_SIZE / block_size))
1023 n = SCSI_DMA_BUF_SIZE / block_size;
1024 r->buf_len = n * block_size;
1025 if (type == SCSIDEV_TYPE_CDROM) {
1026 i = 0;
1027 do {
1028 ret = (int)cdrom->read_block(r->dma_buf + (i * 2048), (Bit32u)(r->sector + i), 2048);
1029 } while ((++i < n) && (ret == 1));
1030 if (ret == 0) {
1031 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_MEDIUM_ERROR);
1032 return;
1033 }
1034 } else {
1035 ret = (int)hdimage->lseek(r->sector * block_size, SEEK_SET);
1036 if (ret < 0) {
1037 BX_ERROR(("could not lseek() hard drive image file"));
1038 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
1039 return;
1040 }
1041 i = 0;
1042 do {
1043 ret = (int)hdimage->read((bx_ptr_t)(r->dma_buf + (i * block_size)),
1044 block_size);
1045 } while ((++i < n) && (ret == block_size));
1046 if (ret != block_size) {
1047 BX_ERROR(("could not read() hard drive image file"));
1048 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
1049 return;
1050 }
1051 }
1052 r->sector += n;
1053 r->sector_count -= n;
1054 scsi_read_complete((void*)r, 0);
1055 } else {
1056 bx_gui->statusbar_setitem(statusbar_id, 1, 1);
1057 n = r->buf_len / block_size;
1058 if (n) {
1059 ret = (int)hdimage->lseek(r->sector * block_size, SEEK_SET);
1060 if (ret < 0) {
1061 BX_ERROR(("could not lseek() hard drive image file"));
1062 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
1063 }
1064 i = 0;
1065 do {
1066 ret = (int)hdimage->write((bx_ptr_t)(r->dma_buf + (i * block_size)),
1067 block_size);
1068 } while ((++i < n) && (ret == block_size));
1069 if (ret != block_size) {
1070 BX_ERROR(("could not write() hard drive image file"));
1071 scsi_command_complete(r, STATUS_CHECK_CONDITION, SENSE_HARDWARE_ERROR);
1072 return;
1073 }
1074 r->sector += n;
1075 r->sector_count -= n;
1076 scsi_write_complete((void*)r, 0);
1077 }
1078 }
1079 }
1080
1081 // Turn on BX_DEBUG messages at connection time
set_debug_mode()1082 void scsi_device_t::set_debug_mode()
1083 {
1084 setonoff(LOGLEV_DEBUG, ACT_REPORT);
1085 }
1086
1087 #endif // BX_SUPPORT_PCI && BX_SUPPORT_PCIUSB
1088