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