From f30e048ad717f648c540a5fbadaf201cbc976b8c Mon Sep 17 00:00:00 2001 From: OBattler Date: Wed, 31 Oct 2018 12:23:49 +0100 Subject: [PATCH] Moved the phase callback handler to hdc_ide.c, where it belongs, rather than in each SCSI(-like) device's code, and made it no longer used when a device's bus type is set to SCSI. --- src/disk/hdc_ide.c | 115 ++++++++++++++++++++++-- src/disk/hdc_ide.h | 5 +- src/disk/zip.c | 197 +++++++---------------------------------- src/scsi/scsi_cdrom.c | 196 +++++++--------------------------------- src/scsi/scsi_device.c | 58 ++++-------- src/scsi/scsi_device.h | 13 +-- src/scsi/scsi_disk.c | 54 ++--------- 7 files changed, 211 insertions(+), 427 deletions(-) diff --git a/src/disk/hdc_ide.c b/src/disk/hdc_ide.c index 84c63d40b..e325c7597 100644 --- a/src/disk/hdc_ide.c +++ b/src/disk/hdc_ide.c @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdc_ide.c 1.0.56 2018/10/28 + * Version: @(#)hdc_ide.c 1.0.57 2018/10/31 * * Authors: Sarah Walker, * Miran Grca, @@ -132,6 +132,7 @@ int ide_ter_enabled = 0, ide_qua_enabled = 0; static uint16_t ide_base_main[4] = { 0x1f0, 0x170, 0x168, 0x1e8 }; static uint16_t ide_side_main[4] = { 0x3f6, 0x376, 0x36e, 0x3ee }; +static void ide_atapi_callback(ide_t *ide); static void ide_callback(void *priv); @@ -941,6 +942,101 @@ ide_set_callback(uint8_t board, int64_t callback) } +static void +ide_atapi_command_bus(ide_t *ide) +{ + ide->sc->status = BUSY_STAT; + ide->sc->phase = 1; + ide->sc->pos = 0; + ide->sc->callback = 1LL * IDE_TIME; + ide_set_callback(ide->board, ide->sc->callback); +} + + +static int +ide_atapi_dma(ide_t *ide, int out) +{ + int ret = 1; + + ret = 0; + + if (out && ide && ide_bus_master_write) { + ret = ide_bus_master_write(ide->board, + ide->sc->temp_buffer, ide->sc->packet_len, + ide_bus_master_priv[ide->board]); + } else if (!out && ide && ide_bus_master_read) { + ret = ide_bus_master_read(ide->board, + ide->sc->temp_buffer, ide->sc->packet_len, + ide_bus_master_priv[ide->board]); + } + + if (ret == 0) { + if (ide->bus_master_error) + ide->bus_master_error(ide->sc); + } else if (ret == 1) { + if (out && ide->phase_data_out) + ret = ide->phase_data_out(ide->sc); + else if (!out && ide->command_stop) + ide->command_stop(ide->sc); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + ide_atapi_callback(ide); + } + + return ret; +} + + +static void +ide_atapi_callback(ide_t *ide) +{ + int ret; + + switch(ide->sc->packet_status) { + case PHASE_IDLE: + ide->sc->pos = 0; + ide->sc->phase = 1; + ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); + return; + case PHASE_COMMAND: + ide->sc->status = BUSY_STAT | (ide->sc->status & ERR_STAT); + if (ide->packet_command) { + ide->packet_command(ide->sc, ide->sc->atapi_cdb); + if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + ide_atapi_callback(ide); + } + return; + case PHASE_COMPLETE: + ide->sc->status = READY_STAT; + ide->sc->phase = 3; + ide->sc->packet_status = PHASE_NONE; + ide_irq_raise(ide); + return; + case PHASE_DATA_IN: + case PHASE_DATA_OUT: + ide->sc->status = READY_STAT | DRQ_STAT | (ide->sc->status & ERR_STAT); + ide->sc->phase = !(ide->sc->packet_status & 0x01) << 1; + ide_irq_raise(ide); + return; + case PHASE_DATA_IN_DMA: + case PHASE_DATA_OUT_DMA: + ret = ide_atapi_dma(ide, ide->sc->packet_status & 0x01); + + if (ret == 2) + ide_atapi_command_bus(ide); + else if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + ide_atapi_callback(ide); + return; + case PHASE_ERROR: + ide->sc->status = READY_STAT | ERR_STAT; + ide->sc->phase = 3; + ide->sc->packet_status = PHASE_NONE; + ide_irq_raise(ide); + return; + } +} + + /* This is the general ATAPI PIO request function. */ static void ide_atapi_pio_request(ide_t *ide, uint8_t out) @@ -957,8 +1053,11 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) dev->pos = dev->request_pos = 0; if (out && ide->phase_data_out) ide->phase_data_out(dev); - else if (ide->command_stop) + else if (!out && ide->command_stop) ide->command_stop(dev); + + if ((ide->sc->packet_status == PHASE_COMPLETE) && !ide->sc->callback) + ide_atapi_callback(ide); } else { ide_log("%i bytes %s, %i bytes are still left\n", dev->pos, out ? "written" : "read", dev->packet_len - dev->pos); @@ -970,12 +1069,11 @@ ide_atapi_pio_request(ide_t *ide, uint8_t out) ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len, dev->max_transfer_len); - dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN; + dev->packet_status = PHASE_DATA_IN | out; dev->status = BSY_STAT; dev->phase = 1; - if (ide->packet_callback) - ide->packet_callback(dev); + ide_atapi_callback(ide); dev->callback = 0LL; ide_set_callback(ide->board >> 1, dev->callback); @@ -1090,8 +1188,7 @@ ide_atapi_packet_write(ide_t *ide, uint32_t val, int length) dev->status = BSY_STAT; dev->packet_status = PHASE_COMMAND; timer_process(); - if (ide->packet_callback) - ide->packet_callback(dev); + ide_atapi_callback(ide); timer_update_outstanding(); } return; @@ -2298,10 +2395,10 @@ ide_callback(void *priv) return; case WIN_PACKETCMD: /* ATAPI Packet */ - if (!ide_drive_is_atapi(ide) || !ide->packet_callback) + if (!ide_drive_is_atapi(ide)) goto abort_cmd; - ide->packet_callback(ide->sc); + ide_atapi_callback(ide); return; case 0xFF: diff --git a/src/disk/hdc_ide.h b/src/disk/hdc_ide.h index e9eddda90..34a6a730e 100644 --- a/src/disk/hdc_ide.h +++ b/src/disk/hdc_ide.h @@ -9,7 +9,7 @@ * Implementation of the IDE emulation for hard disks and ATAPI * CD-ROM devices. * - * Version: @(#)hdd_ide.h 1.0.13 2018/10/28 + * Version: @(#)hdd_ide.h 1.0.14 2018/10/31 * * Authors: Sarah Walker, * Miran Grca, @@ -57,10 +57,11 @@ typedef struct ide_s { int (*get_timings)(int ide_has_dma, int type); void (*identify)(struct ide_s *ide, int ide_has_dma); void (*stop)(scsi_common_t *sc); - void (*packet_callback)(scsi_common_t *sc); + void (*packet_command)(scsi_common_t *sc, uint8_t *cdb); void (*device_reset)(scsi_common_t *sc); uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); + void (*bus_master_error)(scsi_common_t *sc); } ide_t; #endif diff --git a/src/disk/zip.c b/src/disk/zip.c index d8c45740c..f6701b71b 100644 --- a/src/disk/zip.c +++ b/src/disk/zip.c @@ -9,7 +9,7 @@ * Implementation of the Iomega ZIP drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)zip.c 1.0.35 2018/10/30 + * Version: @(#)zip.c 1.0.36 2018/10/31 * * Author: Miran Grca, * @@ -437,8 +437,6 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_changeable = static void zip_command_complete(zip_t *dev); static void zip_init(zip_t *dev); -static void zip_callback(scsi_common_t *sc); - #ifdef ENABLE_ZIP_LOG int zip_do_log = ENABLE_ZIP_LOG; @@ -604,7 +602,7 @@ zip_init(zip_t *dev) } dev->status = READY_STAT | DSC_STAT; dev->pos = 0; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0; } @@ -855,17 +853,6 @@ zip_update_request_length(zip_t *dev, int len, int block_len) } -static void -zip_command_bus(zip_t *dev) -{ - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * ZIP_TIME; - zip_set_callback(dev); -} - - static void zip_command_common(zip_t *dev) { @@ -875,10 +862,9 @@ zip_command_common(zip_t *dev) dev->status = BUSY_STAT; dev->phase = 1; dev->pos = 0; - if (dev->packet_status == PHASE_COMPLETE) { - zip_callback((scsi_common_t *) dev); + if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0LL; - } else { + else { if (dev->drv->bus_type == ZIP_BUS_SCSI) { dev->callback = -1LL; /* Speed depends on SCSI controller */ return; @@ -1011,7 +997,7 @@ zip_cmd_error(zip_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; + dev->packet_status = PHASE_ERROR; dev->callback = 50LL * ZIP_TIME; zip_set_callback(dev); zip_log("ZIP %i: [%02X] ERROR: %02X/%02X/%02X\n", dev->id, dev->current_cdb[0], zip_sense_key, zip_asc, zip_ascq); @@ -1028,7 +1014,7 @@ zip_unit_attention(zip_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; + dev->packet_status = PHASE_ERROR; dev->callback = 50LL * ZIP_TIME; zip_set_callback(dev); zip_log("ZIP %i: UNIT ATTENTION\n", dev->id); @@ -1036,8 +1022,31 @@ zip_unit_attention(zip_t *dev) static void -zip_bus_master_error(zip_t *dev) +zip_buf_alloc(zip_t *dev, uint32_t len) { + zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); +} + + +static void +zip_buf_free(zip_t *dev) +{ + if (dev->buffer) { + zip_log("ZIP %i: Freeing buffer...\n", dev->id); + free(dev->buffer); + dev->buffer = NULL; + } +} + + +static void +zip_bus_master_error(scsi_common_t *sc) +{ + zip_t *dev = (zip_t *) sc; + + zip_buf_free(dev); zip_sense_key = zip_asc = zip_ascq = 0; zip_cmd_error(dev); } @@ -1281,7 +1290,7 @@ zip_reset(scsi_common_t *sc) zip_set_callback(dev); dev->phase = 1; dev->request_length = 0xEB14; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; dev->unit_attention = 0; } @@ -1358,26 +1367,6 @@ zip_set_buf_len(zip_t *dev, int32_t *BufLen, int32_t *src_len) } -static void -zip_buf_alloc(zip_t *dev, uint32_t len) -{ - zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->buffer) - dev->buffer = (uint8_t *) malloc(len); -} - - -static void -zip_buf_free(zip_t *dev) -{ - if (dev->buffer) { - zip_log("ZIP %i: Freeing buffer...\n", dev->id); - free(dev->buffer); - dev->buffer = NULL; - } -} - - static void zip_command(scsi_common_t *sc, uint8_t *cdb) { @@ -2182,125 +2171,6 @@ zip_phase_data_out(scsi_common_t *sc) } -static void -zip_irq_raise(scsi_common_t *sc) -{ - zip_t *dev = (zip_t *) sc; - - if (dev->drv && (dev->drv->bus_type < ZIP_BUS_SCSI)) - ide_irq_raise(ide_drives[dev->drv->ide_channel]); -} - - -static int -zip_dma(zip_t *dev, int out) -{ - int ret = 1; - - if (dev->drv->bus_type == ZIP_BUS_ATAPI) { - ret = 0; - - if (out && dev && ide_bus_master_write) { - ret = ide_bus_master_write(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - } else if (!out && dev && ide_bus_master_read) { - ret = ide_bus_master_read(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - } - } - - if (ret == 0) { - zip_buf_free(dev); - zip_bus_master_error(dev); - } else if (ret == 1) { - if (out) - ret = zip_phase_data_out((scsi_common_t *) dev); - else - zip_command_stop((scsi_common_t *) dev); - } - - return ret; -} - - -static void -zip_callback(scsi_common_t *sc) -{ - zip_t *dev = (zip_t *) sc; - int ret; - - switch(sc->packet_status) { - case PHASE_IDLE: - zip_log("ZIP %i: PHASE_IDLE\n", sc->id); - sc->pos = 0; - sc->phase = 1; - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - return; - case PHASE_COMMAND: - zip_log("ZIP %i: PHASE_COMMAND\n", sc->id); - sc->status = BUSY_STAT | (sc->status & ERR_STAT); - zip_command(sc, sc->atapi_cdb); - return; - case PHASE_COMPLETE: - zip_log("ZIP %i: PHASE_COMPLETE\n", sc->id); - sc->status = READY_STAT; - sc->phase = 3; - sc->packet_status = 0xFF; - ui_sb_update_icon(SB_ZIP | sc->id, 0); - zip_irq_raise(sc); - return; - case PHASE_DATA_OUT: - zip_log("ZIP %i: PHASE_DATA_OUT\n", sc->id); - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - sc->phase = 0; - zip_irq_raise(sc); - return; - case PHASE_DATA_OUT_DMA: - zip_log("ZIP %i: PHASE_DATA_OUT_DMA\n", dev->id); - ret = zip_dma(dev, 1); - - if (ret == 2) { - zip_log("ZIP %i: DMA out not enabled, wait\n", sc->id); - zip_command_bus(dev); -#ifdef ENABLE_ZIP_LOG - } else { - zip_log("ZIP %i: DMA data out phase %s\n", sc->id, ret ? "done" : "failure"); -#endif - } - return; - case PHASE_DATA_IN: - zip_log("ZIP %i: PHASE_DATA_IN\n", sc->id); - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - sc->phase = 2; - zip_irq_raise(sc); - return; - case PHASE_DATA_IN_DMA: - zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", sc->id); - ret = zip_dma(dev, 0); - - if (ret == 2) { - zip_log("ZIP %i: DMA in not enabled, wait\n", sc->id); - zip_command_bus(dev); -#ifdef ENABLE_ZIP_LOG - } else { - zip_log("ZIP %i: DMA data in phase %s\n", sc->id, ret ? "done" : "failure"); -#endif - } - return; - case PHASE_ERROR: - zip_log("ZIP %i: PHASE_ERROR\n", sc->id); - sc->status = READY_STAT | ERR_STAT; - sc->phase = 3; - sc->packet_status = 0xFF; - zip_irq_raise(sc); - ui_sb_update_icon(SB_ZIP | sc->id, 0); - return; - } -} - - /* Peform a master init on the entire module. */ void zip_global_init(void) @@ -2425,9 +2295,9 @@ zip_drive_reset(int c) sd->sc = (scsi_common_t *) dev; sd->command = zip_command; - sd->callback = zip_callback; sd->request_sense = zip_request_sense_for_scsi; sd->reset = zip_reset; + sd->phase_data_out = zip_phase_data_out; sd->command_stop = zip_command_stop; sd->type = SCSI_REMOVABLE_DISK; } else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) { @@ -2442,10 +2312,11 @@ zip_drive_reset(int c) id->get_timings = zip_get_timings; id->identify = zip_identify; id->stop = NULL; - id->packet_callback = zip_callback; + id->packet_command = zip_command; id->device_reset = zip_reset; id->phase_data_out = zip_phase_data_out; id->command_stop = zip_command_stop; + id->bus_master_error = zip_bus_master_error; id->interrupt_drq = 1; ide_atapi_attach(id); diff --git a/src/scsi/scsi_cdrom.c b/src/scsi/scsi_cdrom.c index 8db242d00..ffd40ac5d 100644 --- a/src/scsi/scsi_cdrom.c +++ b/src/scsi/scsi_cdrom.c @@ -9,7 +9,7 @@ * Implementation of the CD-ROM drive with SCSI(-like) * commands, for both ATAPI and SCSI usage. * - * Version: @(#)scsi_cdrom.c 1.0.66 2018/10/30 + * Version: @(#)scsi_cdrom.c 1.0.67 2018/10/31 * * Author: Miran Grca, * @@ -307,8 +307,6 @@ static void scsi_cdrom_mode_sense_load(scsi_cdrom_t *dev); static void scsi_cdrom_init(scsi_cdrom_t *dev); -static void scsi_cdrom_callback(scsi_common_t *sc); - #ifdef ENABLE_SCSI_CDROM_LOG int scsi_cdrom_do_log = ENABLE_SCSI_CDROM_LOG; @@ -361,7 +359,7 @@ scsi_cdrom_init(scsi_cdrom_t *dev) dev->sense[7] = 10; dev->status = READY_STAT | DSC_STAT; dev->pos = 0; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = dev->unit_attention = 0; dev->drv->cur_speed = dev->drv->speed; scsi_cdrom_mode_sense_load(dev); @@ -632,17 +630,6 @@ scsi_cdrom_bus_speed(scsi_cdrom_t *dev) } -static void -scsi_cdrom_command_bus(scsi_cdrom_t *dev) -{ - dev->status = BUSY_STAT; - dev->phase = 1; - dev->pos = 0; - dev->callback = 1LL * CDROM_TIME; - scsi_cdrom_set_callback(dev); -} - - static void scsi_cdrom_command_common(scsi_cdrom_t *dev) { @@ -656,10 +643,9 @@ scsi_cdrom_command_common(scsi_cdrom_t *dev) scsi_cdrom_log("CD-ROM %i: Current speed: %ix\n", dev->id, dev->drv->cur_speed); - if (dev->packet_status == PHASE_COMPLETE) { - scsi_cdrom_callback((scsi_common_t *) dev); + if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0LL; - } else { + else { switch(dev->current_cdb[0]) { case GPCMD_REZERO_UNIT: case 0x0b: @@ -828,7 +814,7 @@ scsi_cdrom_cmd_error(scsi_cdrom_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; + dev->packet_status = PHASE_ERROR; dev->callback = 50LL * CDROM_TIME; scsi_cdrom_set_callback(dev); scsi_cdrom_log("CD-ROM %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_cdrom_sense_key, scsi_cdrom_asc, scsi_cdrom_ascq); @@ -845,7 +831,7 @@ scsi_cdrom_unit_attention(scsi_cdrom_t *dev) dev->status = READY_STAT | ERR_STAT; dev->phase = 3; dev->pos = 0; - dev->packet_status = 0x80; + dev->packet_status = PHASE_ERROR; dev->callback = 50LL * CDROM_TIME; scsi_cdrom_set_callback(dev); scsi_cdrom_log("CD-ROM %i: UNIT ATTENTION\n", dev->id); @@ -853,8 +839,31 @@ scsi_cdrom_unit_attention(scsi_cdrom_t *dev) static void -scsi_cdrom_bus_master_error(scsi_cdrom_t *dev) +scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) { + scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); + if (!dev->buffer) + dev->buffer = (uint8_t *) malloc(len); +} + + +static void +scsi_cdrom_buf_free(scsi_cdrom_t *dev) +{ + if (dev->buffer) { + scsi_cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); + free(dev->buffer); + dev->buffer = NULL; + } +} + + +static void +scsi_cdrom_bus_master_error(scsi_common_t *sc) +{ + scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; + + scsi_cdrom_buf_free(dev); scsi_cdrom_sense_key = scsi_cdrom_asc = scsi_cdrom_ascq = 0; scsi_cdrom_cmd_error(dev); } @@ -1348,7 +1357,7 @@ scsi_cdrom_reset(scsi_common_t *sc) scsi_cdrom_set_callback(dev); dev->phase = 1; dev->request_length = 0xEB14; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; dev->unit_attention = 0xff; } @@ -1429,26 +1438,6 @@ scsi_cdrom_set_buf_len(scsi_cdrom_t *dev, int32_t *BufLen, int32_t *src_len) } -static void -scsi_cdrom_buf_alloc(scsi_cdrom_t *dev, uint32_t len) -{ - scsi_cdrom_log("CD-ROM %i: Allocated buffer length: %i\n", dev->id, len); - if (!dev->buffer) - dev->buffer = (uint8_t *) malloc(len); -} - - -static void -scsi_cdrom_buf_free(scsi_cdrom_t *dev) -{ - if (dev->buffer) { - scsi_cdrom_log("CD-ROM %i: Freeing buffer...\n", dev->id); - free(dev->buffer); - dev->buffer = NULL; - } -} - - static void scsi_cdrom_stop(scsi_common_t *sc) { @@ -2488,124 +2477,6 @@ scsi_cdrom_phase_data_out(scsi_common_t *sc) } -static void -scsi_cdrom_irq_raise(scsi_common_t *sc) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - - if (dev->drv && (dev->drv->bus_type < CDROM_BUS_SCSI)) - ide_irq_raise(ide_drives[dev->drv->ide_channel]); -} - - -static int -scsi_cdrom_dma(scsi_cdrom_t *dev, int out) -{ - int ret = 1; - - if (dev->drv->bus_type == CDROM_BUS_ATAPI) { - ret = 0; - - if (out && dev && ide_bus_master_write) { - ret = ide_bus_master_write(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - } else if (!out && dev && ide_bus_master_read) { - ret = ide_bus_master_read(dev->drv->ide_channel >> 1, - dev->buffer, dev->packet_len, - ide_bus_master_priv[dev->drv->ide_channel >> 1]); - } - } - - if (ret == 0) { - scsi_cdrom_buf_free(dev); - scsi_cdrom_bus_master_error(dev); - } else if (ret == 1) { - if (out) - ret = scsi_cdrom_phase_data_out((scsi_common_t *) dev); - else - scsi_cdrom_command_stop((scsi_common_t *) dev); - } - - return ret; -} - - -static void -scsi_cdrom_callback(scsi_common_t *sc) -{ - scsi_cdrom_t *dev = (scsi_cdrom_t *) sc; - int ret; - - switch(sc->packet_status) { - case PHASE_IDLE: - scsi_cdrom_log("CD-ROM %i: PHASE_IDLE\n", sc->id); - sc->pos = 0; - sc->phase = 1; - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - return; - case PHASE_COMMAND: - scsi_cdrom_log("CD-ROM %i: PHASE_COMMAND\n", dev->id); - sc->status = BUSY_STAT | (dev->status & ERR_STAT); - scsi_cdrom_command(sc, sc->atapi_cdb); - return; - case PHASE_COMPLETE: - scsi_cdrom_log("CD-ROM %i: PHASE_COMPLETE\n", dev->id); - sc->status = READY_STAT; - sc->phase = 3; - sc->packet_status = 0xFF; - ui_sb_update_icon(SB_CDROM | sc->id, 0); - scsi_cdrom_irq_raise(sc); - return; - case PHASE_DATA_OUT: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT\n", dev->id); - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - sc->phase = 0; - scsi_cdrom_irq_raise(sc); - return; - case PHASE_DATA_OUT_DMA: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_OUT_DMA\n", sc->id); - ret = scsi_cdrom_dma(dev, 1); - - if (ret == 2) { - scsi_cdrom_log("CD-ROM %i: DMA out not enabled, wait\n", sc->id); - scsi_cdrom_command_bus(dev); -#ifdef ENABLE_SCSI_CDROM_LOG - } else { - scsi_cdrom_log("CD-ROM %i: DMA data out phase %s\n", sc->id, ret ? "done" : "failure"); -#endif - } - return; - case PHASE_DATA_IN: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN\n", sc->id); - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - sc->phase = 2; - scsi_cdrom_irq_raise(sc); - return; - case PHASE_DATA_IN_DMA: - scsi_cdrom_log("CD-ROM %i: PHASE_DATA_IN_DMA\n", dev->id); - ret = scsi_cdrom_dma(dev, 0); - - if (ret == 2) { - scsi_cdrom_log("CD-ROM %i: DMA in not enabled, wait\n", sc->id); - scsi_cdrom_command_bus(dev); -#ifdef ENABLE_SCSI_CDROM_LOG - } else { - scsi_cdrom_log("CD-ROM %i: DMA data in phase %s\n", sc->id, ret ? "done" : "failure"); -#endif - } - return; - case PHASE_ERROR: - scsi_cdrom_log("CD-ROM %i: PHASE_ERROR\n", sc->id); - sc->status = READY_STAT | ERR_STAT; - sc->phase = 3; - scsi_cdrom_irq_raise(sc); - ui_sb_update_icon(SB_CDROM | sc->id, 0); - return; - } -} - - static void scsi_cdrom_close(void *p) { @@ -2740,9 +2611,9 @@ scsi_cdrom_drive_reset(int c) sd->sc = (scsi_common_t *) dev; sd->command = scsi_cdrom_command; - sd->callback = scsi_cdrom_callback; sd->request_sense = scsi_cdrom_request_sense_for_scsi; sd->reset = scsi_cdrom_reset; + sd->phase_data_out = scsi_cdrom_phase_data_out; sd->command_stop = scsi_cdrom_command_stop; sd->type = SCSI_REMOVABLE_CDROM; @@ -2759,10 +2630,11 @@ scsi_cdrom_drive_reset(int c) id->get_timings = scsi_cdrom_get_timings; id->identify = scsi_cdrom_identify; id->stop = scsi_cdrom_stop; - id->packet_callback = scsi_cdrom_callback; + id->packet_command = scsi_cdrom_command; id->device_reset = scsi_cdrom_reset; id->phase_data_out = scsi_cdrom_phase_data_out; id->command_stop = scsi_cdrom_command_stop; + id->bus_master_error = scsi_cdrom_bus_master_error; id->interrupt_drq = 0; ide_atapi_attach(id); diff --git a/src/scsi/scsi_device.c b/src/scsi/scsi_device.c index b6bfb7b70..fb1a9db89 100644 --- a/src/scsi/scsi_device.c +++ b/src/scsi/scsi_device.c @@ -8,7 +8,7 @@ * * The generic SCSI device command handler. * - * Version: @(#)scsi_device.c 1.0.22 2018/10/28 + * Version: @(#)scsi_device.c 1.0.23 2018/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -47,29 +47,6 @@ scsi_device_target_command(scsi_device_t *dev, uint8_t *cdb) } -static void -scsi_device_target_callback(scsi_device_t *dev) -{ - if (dev->callback) - dev->callback(dev->sc); - - return; -} - - -static int -scsi_device_target_err_stat_to_scsi(scsi_device_t *dev) -{ - if (dev->sc) - if (dev->sc->status & ERR_STAT) - return SCSI_STATUS_CHECK_CONDITION; - else - return SCSI_STATUS_OK; - else - return SCSI_STATUS_CHECK_CONDITION; -} - - int64_t scsi_device_get_callback(scsi_device_t *dev) { @@ -148,12 +125,16 @@ scsi_device_command_phase0(scsi_device_t *dev, uint8_t *cdb) /* Finally, execute the SCSI command immediately and get the transfer length. */ dev->phase = SCSI_PHASE_COMMAND; dev->status = scsi_device_target_command(dev, cdb); +} - if (dev->phase == SCSI_PHASE_STATUS) { - /* Command completed (either OK or error) - call the phase callback to complete the command. */ - scsi_device_target_callback(dev); + +void +scsi_device_command_stop(scsi_device_t *dev) +{ + if (dev->command_stop) { + dev->command_stop(dev->sc); + dev->status = SCSI_STATUS_OK; } - /* If the phase is DATA IN or DATA OUT, finish this here. */ } @@ -164,19 +145,16 @@ scsi_device_command_phase1(scsi_device_t *dev) return; /* Call the second phase. */ - scsi_device_target_callback(dev); - dev->status = scsi_device_target_err_stat_to_scsi(dev); - /* Command second phase complete - call the callback to complete the command. */ - scsi_device_target_callback(dev); -} + if (dev->phase == SCSI_PHASE_DATA_OUT) { + if (dev->phase_data_out) + dev->phase_data_out(dev->sc); + } else + scsi_device_command_stop(dev); - -void -scsi_device_command_stop(scsi_device_t *dev) -{ - if (!dev->command_stop) - dev->command_stop(dev->sc); - scsi_device_target_callback(dev); + if (dev->sc->status & ERR_STAT) + dev->status = SCSI_STATUS_CHECK_CONDITION; + else + dev->status = SCSI_STATUS_OK; } diff --git a/src/scsi/scsi_device.h b/src/scsi/scsi_device.h index 6c5e34327..4c8d982ad 100644 --- a/src/scsi/scsi_device.h +++ b/src/scsi/scsi_device.h @@ -8,7 +8,7 @@ * * Definitions for the generic SCSI device command handler. * - * Version: @(#)scsi_device.h 1.0.15 2018/10/30 + * Version: @(#)scsi_device.h 1.0.16 2018/10/31 * * Authors: Miran Grca, * Fred N. van Kempen, @@ -268,12 +268,13 @@ #define PHASE_IDLE 0x00 #define PHASE_COMMAND 0x01 -#define PHASE_COMPLETE 0x02 -#define PHASE_DATA_IN 0x03 +#define PHASE_DATA_IN 0x02 +#define PHASE_DATA_OUT 0x03 #define PHASE_DATA_IN_DMA 0x04 -#define PHASE_DATA_OUT 0x05 -#define PHASE_DATA_OUT_DMA 0x06 +#define PHASE_DATA_OUT_DMA 0x05 +#define PHASE_COMPLETE 0x06 #define PHASE_ERROR 0x80 +#define PHASE_NONE 0xff #define SCSI_PHASE_DATA_OUT 0 #define SCSI_PHASE_DATA_IN BUS_IO @@ -349,9 +350,9 @@ typedef struct { scsi_common_t *sc; void (*command)(scsi_common_t *sc, uint8_t *cdb); - void (*callback)(scsi_common_t *sc); void (*request_sense)(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length); void (*reset)(scsi_common_t *sc); + uint8_t (*phase_data_out)(scsi_common_t *sc); void (*command_stop)(scsi_common_t *sc); } scsi_device_t; diff --git a/src/scsi/scsi_disk.c b/src/scsi/scsi_disk.c index 35a85dace..24977a460 100644 --- a/src/scsi/scsi_disk.c +++ b/src/scsi/scsi_disk.c @@ -6,7 +6,7 @@ * * Emulation of SCSI fixed disks. * - * Version: @(#)scsi_disk.c 1.0.28 2018/10/28 + * Version: @(#)scsi_disk.c 1.0.29 2018/10/31 * * Author: Miran Grca, * @@ -122,9 +122,6 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable = } }; -static void scsi_disk_callback(scsi_common_t *sc); - - #ifdef ENABLE_SCSI_DISK_LOG int scsi_disk_do_log = ENABLE_SCSI_DISK_LOG; @@ -245,10 +242,9 @@ scsi_disk_command_common(scsi_disk_t *dev) { dev->status = BUSY_STAT; dev->phase = 1; - if (dev->packet_status == PHASE_COMPLETE) { - scsi_disk_callback((scsi_common_t *) dev); + if (dev->packet_status == PHASE_COMPLETE) dev->callback = 0LL; - } else + else dev->callback = -1LL; /* Speed depends on SCSI controller */ } @@ -323,7 +319,7 @@ scsi_disk_cmd_error(scsi_disk_t *dev) dev->error = ((scsi_disk_sense_key & 0xf) << 4) | ABRT_ERR; dev->status = READY_STAT | ERR_STAT; dev->phase = 3; - dev->packet_status = 0x80; + dev->packet_status = PHASE_ERROR; dev->callback = 50 * SCSI_TIME; scsi_disk_log("SCSI HD %i: ERROR: %02X/%02X/%02X\n", dev->id, scsi_disk_sense_key, scsi_disk_asc, scsi_disk_ascq); } @@ -446,7 +442,7 @@ scsi_disk_reset(scsi_common_t *sc) scsi_disk_rezero(dev); dev->status = 0; dev->callback = 0; - dev->packet_status = 0xff; + dev->packet_status = PHASE_NONE; } @@ -1015,7 +1011,7 @@ scsi_disk_command_stop(scsi_common_t *sc) } -static void +static uint8_t scsi_disk_phase_data_out(scsi_common_t *sc) { scsi_disk_t *dev = (scsi_disk_t *) sc; @@ -1030,7 +1026,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) if (!*BufLen) { scsi_disk_set_phase(dev, SCSI_PHASE_STATUS); - return; + return 1; } switch (dev->current_cdb[0]) { @@ -1140,39 +1136,7 @@ scsi_disk_phase_data_out(scsi_common_t *sc) } scsi_disk_command_stop((scsi_common_t *) dev); -} - - -/* If the result is 1, issue an IRQ, otherwise not. */ -static void -scsi_disk_callback(scsi_common_t *sc) -{ - switch(sc->packet_status) { - case PHASE_IDLE: - scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id); - sc->phase = 1; - sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT); - return; - case PHASE_COMPLETE: - scsi_disk_log("SCSI HD %i: PHASE_COMPLETE\n", dev->id); - sc->status = READY_STAT; - sc->phase = 3; - sc->packet_status = 0xFF; - return; - case PHASE_DATA_OUT_DMA: - scsi_disk_log("SCSI HD %i: PHASE_DATA_OUT_DMA\n", dev->id); - scsi_disk_phase_data_out(sc); - return; - case PHASE_DATA_IN_DMA: - scsi_disk_log("SCSI HD %i: PHASE_DATA_IN_DMA\n", dev->id); - scsi_disk_command_stop(sc); - return; - case PHASE_ERROR: - scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id); - sc->status = READY_STAT | ERR_STAT; - sc->phase = 3; - return; - } + return 1; } @@ -1211,9 +1175,9 @@ scsi_disk_hard_reset(void) sd->sc = (scsi_common_t *) dev; sd->command = scsi_disk_command; - sd->callback = scsi_disk_callback; sd->request_sense = scsi_disk_request_sense_for_scsi; sd->reset = scsi_disk_reset; + sd->phase_data_out = scsi_disk_phase_data_out; sd->command_stop = scsi_disk_command_stop; sd->type = SCSI_FIXED_DISK;