diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/m68k/q800.c | 16 | ||||
-rw-r--r-- | hw/scsi/lsi53c895a.c | 3 | ||||
-rw-r--r-- | hw/scsi/scsi-disk.c | 96 | ||||
-rw-r--r-- | hw/scsi/trace-events | 3 |
4 files changed, 110 insertions, 8 deletions
diff --git a/hw/m68k/q800.c b/hw/m68k/q800.c index 099a758..101ab0f 100644 --- a/hw/m68k/q800.c +++ b/hw/m68k/q800.c @@ -686,6 +686,21 @@ static void q800_init(MachineState *machine) } } +static GlobalProperty hw_compat_q800[] = { + { "scsi-hd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-hd", "vendor", " SEAGATE" }, + { "scsi-hd", "product", " ST225N" }, + { "scsi-hd", "ver", "1.0 " }, + { "scsi-cd", "quirk_mode_page_apple_vendor", "on"}, + { "scsi-cd", "quirk_mode_sense_rom_use_dbd", "on"}, + { "scsi-cd", "quirk_mode_page_vendor_specific_apple", "on"}, + { "scsi-cd", "quirk_mode_page_truncated", "on"}, + { "scsi-cd", "vendor", "MATSHITA" }, + { "scsi-cd", "product", "CD-ROM CR-8005" }, + { "scsi-cd", "ver", "1.0k" }, +}; +static const size_t hw_compat_q800_len = G_N_ELEMENTS(hw_compat_q800); + static void q800_machine_class_init(ObjectClass *oc, void *data) { MachineClass *mc = MACHINE_CLASS(oc); @@ -695,6 +710,7 @@ static void q800_machine_class_init(ObjectClass *oc, void *data) mc->max_cpus = 1; mc->block_default_type = IF_SCSI; mc->default_ram_id = "m68k_mac.ram"; + compat_props_add(mc->compat_props, hw_compat_q800, hw_compat_q800_len); } static const TypeInfo q800_machine_typeinfo = { diff --git a/hw/scsi/lsi53c895a.c b/hw/scsi/lsi53c895a.c index 99ea42d..ad5f5e5 100644 --- a/hw/scsi/lsi53c895a.c +++ b/hw/scsi/lsi53c895a.c @@ -1030,7 +1030,7 @@ static void lsi_do_msgout(LSIState *s) trace_lsi_do_msgout_abort(current_tag); if (current_req && current_req->req) { scsi_req_cancel(current_req->req); - current_req->req = NULL; + current_req = NULL; } lsi_disconnect(s); break; @@ -1056,6 +1056,7 @@ static void lsi_do_msgout(LSIState *s) /* clear the current I/O process */ if (s->current) { scsi_req_cancel(s->current->req); + current_req = NULL; } /* As the current implemented devices scsi_disk and scsi_generic diff --git a/hw/scsi/scsi-disk.c b/hw/scsi/scsi-disk.c index 91acb5c..f5cdb9a 100644 --- a/hw/scsi/scsi-disk.c +++ b/hw/scsi/scsi-disk.c @@ -94,6 +94,7 @@ struct SCSIDiskState { uint16_t port_index; uint64_t max_unmap_size; uint64_t max_io_size; + uint32_t quirks; QEMUBH *bh; char *version; char *serial; @@ -1078,12 +1079,14 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, int page_control) { static const int mode_sense_valid[0x3f] = { + [MODE_PAGE_VENDOR_SPECIFIC] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_HD_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_FLEXIBLE_DISK_GEOMETRY] = (1 << TYPE_DISK), [MODE_PAGE_CACHING] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_R_W_ERROR] = (1 << TYPE_DISK) | (1 << TYPE_ROM), [MODE_PAGE_AUDIO_CTL] = (1 << TYPE_ROM), [MODE_PAGE_CAPABILITIES] = (1 << TYPE_ROM), + [MODE_PAGE_APPLE_VENDOR] = (1 << TYPE_ROM), }; uint8_t *p = *p_outbuf + 2; @@ -1185,6 +1188,10 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, case MODE_PAGE_R_W_ERROR: length = 10; if (page_control == 1) { /* Changeable Values */ + if (s->qdev.type == TYPE_ROM) { + /* Automatic Write Reallocation Enabled */ + p[0] = 0x80; + } break; } p[0] = 0x80; /* Automatic Write Reallocation Enabled */ @@ -1228,6 +1235,36 @@ static int mode_sense_page(SCSIDiskState *s, int page, uint8_t **p_outbuf, p[19] = (16 * 176) & 0xff; break; + case MODE_PAGE_APPLE_VENDOR: + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR)) { + length = 0x1e; + if (page_control == 1) { /* Changeable Values */ + break; + } + + memset(p, 0, length); + strcpy((char *)p + 8, "APPLE COMPUTER, INC "); + break; + } else { + return -1; + } + + case MODE_PAGE_VENDOR_SPECIFIC: + if (s->qdev.type == TYPE_DISK && (s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + length = 0x2; + if (page_control == 1) { /* Changeable Values */ + p[0] = 0xff; + p[1] = 0xff; + break; + } + p[0] = 0; + p[1] = 0; + break; + } else { + return -1; + } + default: return -1; } @@ -1263,10 +1300,27 @@ static int scsi_disk_emulate_mode_sense(SCSIDiskReq *r, uint8_t *outbuf) dev_specific_param |= 0x80; /* Readonly. */ } } else { - /* MMC prescribes that CD/DVD drives have no block descriptors, - * and defines no device-specific parameter. */ - dev_specific_param = 0x00; - dbd = true; + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD)) { + /* Use DBD from the request... */ + dev_specific_param = 0x00; + + /* + * ... unless we receive a request for MODE_PAGE_APPLE_VENDOR + * which should never return a block descriptor even though DBD is + * not set, otherwise CDROM detection fails in MacOS + */ + if (s->quirks & (1 << SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR) && + page == MODE_PAGE_APPLE_VENDOR) { + dbd = true; + } + } else { + /* + * MMC prescribes that CD/DVD drives have no block descriptors, + * and defines no device-specific parameter. + */ + dev_specific_param = 0x00; + dbd = true; + } } if (r->req.cmd.buf[0] == MODE_SENSE) { @@ -1502,7 +1556,10 @@ static int mode_select_pages(SCSIDiskReq *r, uint8_t *p, int len, bool change) goto invalid_param; } if (page_len > len) { - goto invalid_param_len; + if (!(s->quirks & SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED)) { + goto invalid_param_len; + } + trace_scsi_disk_mode_select_page_truncated(page, page_len, len); } if (!change) { @@ -1537,9 +1594,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) int bd_len; int pass; - /* We only support PF=1, SP=0. */ if ((r->req.cmd.buf[1] & 0x11) != 0x10) { - goto invalid_field; + if (!(s->quirks & + (1 << SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE))) { + /* We only support PF=1, SP=0. */ + goto invalid_field; + } } if (len < hdr_len) { @@ -1556,6 +1616,12 @@ static void scsi_disk_emulate_mode_select(SCSIDiskReq *r, uint8_t *inbuf) goto invalid_param; } + /* Allow changing the block size */ + if (bd_len && p[6] != (s->qdev.blocksize >> 8)) { + s->qdev.blocksize = p[6] << 8; + trace_scsi_disk_mode_select_set_blocksize(s->qdev.blocksize); + } + len -= bd_len; p += bd_len; @@ -2127,6 +2193,9 @@ static int32_t scsi_disk_emulate_command(SCSIRequest *req, uint8_t *buf) trace_scsi_disk_emulate_command_WRITE_SAME( req->cmd.buf[0] == WRITE_SAME_10 ? 10 : 16, r->req.cmd.xfer); break; + case FORMAT_UNIT: + trace_scsi_disk_emulate_command_FORMAT_UNIT(r->req.cmd.xfer); + break; default: trace_scsi_disk_emulate_command_UNKNOWN(buf[0], scsi_command_name(buf[0])); @@ -2532,6 +2601,7 @@ static const SCSIReqOps *const scsi_disk_reqops_dispatch[256] = { [VERIFY_10] = &scsi_disk_emulate_reqops, [VERIFY_12] = &scsi_disk_emulate_reqops, [VERIFY_16] = &scsi_disk_emulate_reqops, + [FORMAT_UNIT] = &scsi_disk_emulate_reqops, [READ_6] = &scsi_disk_dma_reqops, [READ_10] = &scsi_disk_dma_reqops, @@ -3036,6 +3106,9 @@ static Property scsi_hd_properties[] = { DEFINE_PROP_UINT16("rotation_rate", SCSIDiskState, rotation_rate, 0), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), DEFINE_BLOCK_CHS_PROPERTIES(SCSIDiskState, qdev.conf), DEFINE_PROP_END_OF_LIST(), }; @@ -3084,6 +3157,15 @@ static Property scsi_cd_properties[] = { DEFAULT_MAX_IO_SIZE), DEFINE_PROP_INT32("scsi_version", SCSIDiskState, qdev.default_scsi_version, 5), + DEFINE_PROP_BIT("quirk_mode_page_apple_vendor", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_APPLE_VENDOR, 0), + DEFINE_PROP_BIT("quirk_mode_sense_rom_use_dbd", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_SENSE_ROM_USE_DBD, 0), + DEFINE_PROP_BIT("quirk_mode_page_vendor_specific_apple", SCSIDiskState, + quirks, SCSI_DISK_QUIRK_MODE_PAGE_VENDOR_SPECIFIC_APPLE, + 0), + DEFINE_PROP_BIT("quirk_mode_page_truncated", SCSIDiskState, quirks, + SCSI_DISK_QUIRK_MODE_PAGE_TRUNCATED, 0), DEFINE_PROP_END_OF_LIST(), }; diff --git a/hw/scsi/trace-events b/hw/scsi/trace-events index 20fb0dc..ab23829 100644 --- a/hw/scsi/trace-events +++ b/hw/scsi/trace-events @@ -334,10 +334,13 @@ scsi_disk_emulate_command_UNMAP(size_t xfer) "Unmap (len %zd)" scsi_disk_emulate_command_VERIFY(int bytchk) "Verify (bytchk %d)" scsi_disk_emulate_command_WRITE_SAME(int cmd, size_t xfer) "WRITE SAME %d (len %zd)" scsi_disk_emulate_command_UNKNOWN(int cmd, const char *name) "Unknown SCSI command (0x%2.2x=%s)" +scsi_disk_emulate_command_FORMAT_UNIT(size_t xfer) "Format Unit (len %zu)" scsi_disk_dma_command_READ(uint64_t lba, uint32_t len) "Read (sector %" PRId64 ", count %u)" scsi_disk_dma_command_WRITE(const char *cmd, uint64_t lba, int len) "Write %s(sector %" PRId64 ", count %u)" scsi_disk_new_request(uint32_t lun, uint32_t tag, const char *line) "Command: lun=%d tag=0x%x data=%s" scsi_disk_aio_sgio_command(uint32_t tag, uint8_t cmd, uint64_t lba, int len, uint32_t timeout) "disk aio sgio: tag=0x%x cmd=0x%x (sector %" PRId64 ", count %d) timeout=%u" +scsi_disk_mode_select_page_truncated(int page, int len, int page_len) "page %d expected length %d but received length %d" +scsi_disk_mode_select_set_blocksize(int blocksize) "set block size to %d" # scsi-generic.c scsi_generic_command_complete_noio(void *req, uint32_t tag, int statuc) "Command complete %p tag=0x%x status=%d" |