Extensive rework of SCSI and ATAPI devices and numerous bug fixes and cleanups;

Extensive rework of CD-ROM image handling;
The settings save code now forces some devices' (SCSI disk, CD-ROM, etc.) pointers to NULL before resetting the machine - fixes segmentation faults after changing settings;
Added the NCR 53c825A and 53c875 SCSI controllers;
Fixed IDE/ATAPI DMA;
Slight changed to PCI IDE bus master operation.
This commit is contained in:
OBattler
2018-10-30 13:32:25 +01:00
parent 6410e0ac75
commit 3a8bd15b9d
31 changed files with 3116 additions and 3370 deletions

View File

@@ -6,7 +6,7 @@
*
* Emulation of SCSI fixed disks.
*
* Version: @(#)scsi_disk.c 1.0.27 2018/10/27
* Version: @(#)scsi_disk.c 1.0.28 2018/10/28
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
@@ -26,27 +26,13 @@
#include "../piix.h"
#include "../disk/hdd.h"
#include "../disk/hdc.h"
#include "scsi_device.h"
#include "../disk/hdc_ide.h"
#include "../plat.h"
#include "../ui.h"
#include "scsi_device.h"
#include "scsi_disk.h"
/* Bits of 'status' */
#define ERR_STAT 0x01
#define DRQ_STAT 0x08 /* Data request */
#define DSC_STAT 0x10
#define SERVICE_STAT 0x10
#define READY_STAT 0x40
#define BUSY_STAT 0x80
/* Bits of 'error' */
#define ABRT_ERR 0x04 /* Command aborted */
#define MCR_ERR 0x08 /* Media change request */
#define MAX_BLOCKS_AT_ONCE 340
#define scsi_disk_sense_error dev->sense[0]
#define scsi_disk_sense_key dev->sense[2]
#define scsi_disk_asc dev->sense[12]
@@ -136,7 +122,7 @@ static const mode_sense_pages_t scsi_disk_mode_sense_pages_changeable =
} };
static void scsi_disk_callback(void *p);
static void scsi_disk_callback(scsi_common_t *sc);
#ifdef ENABLE_SCSI_DISK_LOG
@@ -159,19 +145,6 @@ scsi_disk_log(const char *fmt, ...)
#endif
/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */
static int
scsi_disk_err_stat_to_scsi(void *p)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
if (dev->status & ERR_STAT)
return SCSI_STATUS_CHECK_CONDITION;
else
return SCSI_STATUS_OK;
}
void
scsi_disk_mode_sense_load(scsi_disk_t *dev)
{
@@ -206,25 +179,6 @@ scsi_disk_mode_sense_save(scsi_disk_t *dev)
}
static int
scsi_disk_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
int size = 0;
size = hdd_image_get_last_sector(dev->id);
memset(buffer, 0, 8);
buffer[0] = (size >> 24) & 0xff;
buffer[1] = (size >> 16) & 0xff;
buffer[2] = (size >> 8) & 0xff;
buffer[3] = size & 0xff;
buffer[6] = 2; /* 512 = 0x0200 */
*len = 8;
return 1;
}
/*SCSI Mode Sense 6/10*/
uint8_t
scsi_disk_mode_sense_read(scsi_disk_t *dev, uint8_t page_control, uint8_t page, uint8_t pos)
@@ -292,7 +246,7 @@ scsi_disk_command_common(scsi_disk_t *dev)
dev->status = BUSY_STAT;
dev->phase = 1;
if (dev->packet_status == PHASE_COMPLETE) {
scsi_disk_callback((void *) dev);
scsi_disk_callback((scsi_common_t *) dev);
dev->callback = 0LL;
} else
dev->callback = -1LL; /* Speed depends on SCSI controller */
@@ -485,9 +439,9 @@ scsi_disk_rezero(scsi_disk_t *dev)
static void
scsi_disk_reset(void *p)
scsi_disk_reset(scsi_common_t *sc)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
scsi_disk_t *dev = (scsi_disk_t *) sc;
scsi_disk_rezero(dev);
dev->status = 0;
@@ -522,9 +476,9 @@ scsi_disk_request_sense(scsi_disk_t *dev, uint8_t *buffer, uint8_t alloc_length,
static void
scsi_disk_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length)
scsi_disk_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
scsi_disk_t *dev = (scsi_disk_t *) sc;
scsi_disk_request_sense(dev, buffer, alloc_length, 0);
}
@@ -544,9 +498,29 @@ scsi_disk_set_buf_len(scsi_disk_t *dev, int32_t *BufLen, int32_t *src_len)
static void
scsi_disk_command(void *p, uint8_t *cdb)
scsi_disk_buf_alloc(scsi_disk_t *dev, uint32_t len)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
scsi_disk_log("SCSI HD %i: Allocated buffer length: %i\n", dev->id, len);
if (!dev->temp_buffer)
dev->temp_buffer = (uint8_t *) malloc(len);
}
static void
scsi_disk_buf_free(scsi_disk_t *dev)
{
if (dev->temp_buffer) {
scsi_disk_log("SCSI HD %i: Freeing buffer...\n", dev->id);
free(dev->temp_buffer);
dev->temp_buffer = NULL;
}
}
static void
scsi_disk_command(scsi_common_t *sc, uint8_t *cdb)
{
scsi_disk_t *dev = (scsi_disk_t *) sc;
#ifdef ENABLE_SCSI_DISK_LOG
uint8_t *hdbufferb;
#endif
@@ -631,6 +605,7 @@ scsi_disk_command(void *p, uint8_t *cdb)
break;
}
scsi_disk_buf_alloc(dev, 256);
scsi_disk_set_buf_len(dev, BufLen, &len);
if (*BufLen < cdb[4])
@@ -638,14 +613,21 @@ scsi_disk_command(void *p, uint8_t *cdb)
len = (cdb[1] & 1) ? 8 : 18;
scsi_disk_request_sense(dev, dev->temp_buffer, *BufLen, cdb[1] & 1);
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
scsi_disk_data_command_finish(dev, len, len, cdb[4], 0);
break;
case GPCMD_MECHANISM_STATUS:
len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
scsi_disk_set_buf_len(dev, BufLen, &len);
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
len = (cdb[8] << 8) | cdb[9];
scsi_disk_buf_alloc(dev, 8);
scsi_disk_set_buf_len(dev, BufLen, &len);
memset(dev->temp_buffer, 0, 8);
dev->temp_buffer[5] = 1;
scsi_disk_data_command_finish(dev, 8, 8, len, 0);
break;
@@ -684,10 +666,17 @@ scsi_disk_command(void *p, uint8_t *cdb)
dev->requested_blocks = max_len;
alloc_length = dev->packet_len = max_len << 9;
scsi_disk_buf_alloc(dev, dev->packet_len);
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_IN);
if ((dev->requested_blocks > 0) && (*BufLen > 0)) {
if (dev->packet_len > (uint32_t) *BufLen)
hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer);
else
hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer);
}
if (dev->requested_blocks > 1)
scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 0);
else
@@ -748,6 +737,7 @@ scsi_disk_command(void *p, uint8_t *cdb)
dev->requested_blocks = max_len;
alloc_length = dev->packet_len = max_len << 9;
scsi_disk_buf_alloc(dev, dev->packet_len);
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
@@ -759,6 +749,9 @@ scsi_disk_command(void *p, uint8_t *cdb)
return;
case GPCMD_WRITE_SAME_10:
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
alloc_length = 512;
if ((cdb[1] & 6) == 6) {
scsi_disk_invalid_field(dev);
return;
@@ -766,7 +759,6 @@ scsi_disk_command(void *p, uint8_t *cdb)
dev->sector_len = (cdb[7] << 8) | cdb[8];
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
scsi_disk_log("SCSI HD %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos);
if ((dev->sector_pos > last_sector) ||
((dev->sector_pos + dev->sector_len - 1) > last_sector)) {
@@ -782,18 +774,15 @@ scsi_disk_command(void *p, uint8_t *cdb)
break;
}
max_len = 1;
dev->requested_blocks = max_len;
alloc_length = dev->packet_len = max_len << 9;
scsi_disk_buf_alloc(dev, alloc_length);
scsi_disk_set_buf_len(dev, BufLen, &alloc_length);
max_len = 1;
dev->requested_blocks = 1;
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
if (dev->requested_blocks > 1)
scsi_disk_data_command_finish(dev, alloc_length, alloc_length / dev->requested_blocks, alloc_length, 1);
else
scsi_disk_data_command_finish(dev, alloc_length, alloc_length, alloc_length, 1);
scsi_disk_data_command_finish(dev, 512, 512, alloc_length, 1);
return;
case GPCMD_MODE_SENSE_6:
@@ -802,16 +791,17 @@ scsi_disk_command(void *p, uint8_t *cdb)
block_desc = ((cdb[1] >> 3) & 1) ? 0 : 1;
if (cdb[0] == GPCMD_MODE_SENSE_6)
if (cdb[0] == GPCMD_MODE_SENSE_6) {
len = cdb[4];
else
scsi_disk_buf_alloc(dev, 256);
} else {
len = (cdb[8] | (cdb[7] << 8));
scsi_disk_buf_alloc(dev, 65536);
}
memset(dev->temp_buffer, 0, len);
alloc_length = len;
dev->temp_buffer = (uint8_t *) malloc(65536);
memset(dev->temp_buffer, 0, 65536);
if (cdb[0] == GPCMD_MODE_SENSE_6) {
len = scsi_disk_mode_sense(dev, dev->temp_buffer, 4, cdb[2], block_desc);
if (len > alloc_length)
@@ -824,8 +814,8 @@ scsi_disk_command(void *p, uint8_t *cdb)
len = scsi_disk_mode_sense(dev, dev->temp_buffer, 8, cdb[2], block_desc);
if (len > alloc_length)
len = alloc_length;
dev->temp_buffer[0]=(len - 2) >> 8;
dev->temp_buffer[1]=(len - 2) & 255;
dev->temp_buffer[0] = (len - 2) >> 8;
dev->temp_buffer[1] = (len - 2) & 255;
dev->temp_buffer[2] = 0;
if (block_desc) {
dev->temp_buffer[6] = 0;
@@ -848,10 +838,13 @@ scsi_disk_command(void *p, uint8_t *cdb)
case GPCMD_MODE_SELECT_10:
scsi_disk_set_phase(dev, SCSI_PHASE_DATA_OUT);
if (cdb[0] == GPCMD_MODE_SELECT_6)
if (cdb[0] == GPCMD_MODE_SELECT_6) {
len = cdb[4];
else
scsi_disk_buf_alloc(dev, 256);
} else {
len = (cdb[7] << 8) | cdb[8];
scsi_disk_buf_alloc(dev, 65536);
}
scsi_disk_set_buf_len(dev, BufLen, &len);
dev->total_length = len;
@@ -872,7 +865,7 @@ scsi_disk_command(void *p, uint8_t *cdb)
break;
}
dev->temp_buffer = malloc(1024);
scsi_disk_buf_alloc(dev, 65536);
if (cdb[1] & 1) {
preamble_len = 4;
@@ -891,8 +884,7 @@ scsi_disk_command(void *p, uint8_t *cdb)
break;
case 0x83:
if (idx + 24 > max_len) {
free(dev->temp_buffer);
dev->temp_buffer = NULL;
scsi_disk_buf_free(dev);
scsi_disk_data_phase_error(dev);
return;
}
@@ -919,9 +911,8 @@ scsi_disk_command(void *p, uint8_t *cdb)
break;
default:
scsi_disk_log("INQUIRY: Invalid page: %02X\n", cdb[2]);
free(dev->temp_buffer);
dev->temp_buffer = NULL;
scsi_disk_invalid_field(dev);
scsi_disk_buf_free(dev);
return;
}
} else {
@@ -988,12 +979,16 @@ atapi_out:
break;
case GPCMD_READ_CDROM_CAPACITY:
dev->temp_buffer = (uint8_t *) malloc(8);
scsi_disk_buf_alloc(dev, 8);
if (scsi_disk_read_capacity(dev, dev->current_cdb, dev->temp_buffer, (uint32_t *) &len) == 0) {
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
return;
}
max_len = hdd_image_get_last_sector(dev->id);
memset(dev->temp_buffer, 0, 8);
dev->temp_buffer[0] = (max_len >> 24) & 0xff;
dev->temp_buffer[1] = (max_len >> 16) & 0xff;
dev->temp_buffer[2] = (max_len >> 8) & 0xff;
dev->temp_buffer[3] = max_len & 0xff;
dev->temp_buffer[6] = 2;
len = 8;
scsi_disk_set_buf_len(dev, BufLen, &len);
@@ -1011,62 +1006,19 @@ atapi_out:
static void
scsi_disk_phase_data_in(scsi_disk_t *dev)
scsi_disk_command_stop(scsi_common_t *sc)
{
uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer;
int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length;
scsi_disk_t *dev = (scsi_disk_t *) sc;
if (!*BufLen) {
scsi_disk_log("scsi_disk_phase_data_in(): Buffer length is 0\n");
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
return;
}
switch (dev->current_cdb[0]) {
case GPCMD_REQUEST_SENSE:
scsi_disk_log("SCSI HDD %i: %08X, %08X\n", dev->id, hdbufferb, *BufLen);
scsi_disk_request_sense(dev, hdbufferb, *BufLen, dev->current_cdb[1] & 1);
break;
case GPCMD_MECHANISM_STATUS:
memset(hdbufferb, 0, *BufLen);
hdbufferb[5] = 1;
break;
case GPCMD_READ_6:
case GPCMD_READ_10:
case GPCMD_READ_12:
if ((dev->requested_blocks > 0) && (*BufLen > 0)) {
if (dev->packet_len > (uint32_t) *BufLen)
hdd_image_read(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb);
else
hdd_image_read(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb);
}
break;
case GPCMD_MODE_SENSE_6:
case GPCMD_MODE_SENSE_10:
case GPCMD_INQUIRY:
case GPCMD_READ_CDROM_CAPACITY:
scsi_disk_log("scsi_disk_phase_data_in(): Filling buffer (%08X, %08X)\n", hdbufferb, dev->temp_buffer);
memcpy(hdbufferb, dev->temp_buffer, *BufLen);
free(dev->temp_buffer);
dev->temp_buffer = NULL;
scsi_disk_log("%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n",
hdbufferb[0], hdbufferb[1], hdbufferb[2], hdbufferb[3], hdbufferb[4], hdbufferb[5], hdbufferb[6], hdbufferb[7],
hdbufferb[8], hdbufferb[9], hdbufferb[10], hdbufferb[11], hdbufferb[12], hdbufferb[13], hdbufferb[14], hdbufferb[15]);
break;
default:
fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]);
break;
}
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
scsi_disk_command_complete(dev);
scsi_disk_buf_free(dev);
}
static void
scsi_disk_phase_data_out(scsi_disk_t *dev)
scsi_disk_phase_data_out(scsi_common_t *sc)
{
uint8_t *hdbufferb = scsi_devices[dev->drv->scsi_id].cmd_buffer;
scsi_disk_t *dev = (scsi_disk_t *) sc;
int i;
int32_t *BufLen = &scsi_devices[dev->drv->scsi_id].buffer_length;
uint32_t last_sector = hdd_image_get_last_sector(dev->id);
@@ -1093,9 +1045,9 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
case GPCMD_WRITE_AND_VERIFY_12:
if ((dev->requested_blocks > 0) && (*BufLen > 0)) {
if (dev->packet_len > (uint32_t) *BufLen)
hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, hdbufferb);
hdd_image_write(dev->id, dev->sector_pos, *BufLen >> 9, dev->temp_buffer);
else
hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, hdbufferb);
hdd_image_write(dev->id, dev->sector_pos, dev->requested_blocks, dev->temp_buffer);
}
break;
case GPCMD_WRITE_SAME_10:
@@ -1106,24 +1058,24 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
for (i = dev->sector_pos; i <= (int) last_to_write; i++) {
if (dev->current_cdb[1] & 2) {
hdbufferb[0] = (i >> 24) & 0xff;
hdbufferb[1] = (i >> 16) & 0xff;
hdbufferb[2] = (i >> 8) & 0xff;
hdbufferb[3] = i & 0xff;
dev->temp_buffer[0] = (i >> 24) & 0xff;
dev->temp_buffer[1] = (i >> 16) & 0xff;
dev->temp_buffer[2] = (i >> 8) & 0xff;
dev->temp_buffer[3] = i & 0xff;
} else if (dev->current_cdb[1] & 4) {
s = (i % dev->drv->spt);
h = ((i - s) / dev->drv->spt) % dev->drv->hpc;
c = ((i - s) / dev->drv->spt) / dev->drv->hpc;
hdbufferb[0] = (c >> 16) & 0xff;
hdbufferb[1] = (c >> 8) & 0xff;
hdbufferb[2] = c & 0xff;
hdbufferb[3] = h & 0xff;
hdbufferb[4] = (s >> 24) & 0xff;
hdbufferb[5] = (s >> 16) & 0xff;
hdbufferb[6] = (s >> 8) & 0xff;
hdbufferb[7] = s & 0xff;
dev->temp_buffer[0] = (c >> 16) & 0xff;
dev->temp_buffer[1] = (c >> 8) & 0xff;
dev->temp_buffer[2] = c & 0xff;
dev->temp_buffer[3] = h & 0xff;
dev->temp_buffer[4] = (s >> 24) & 0xff;
dev->temp_buffer[5] = (s >> 16) & 0xff;
dev->temp_buffer[6] = (s >> 8) & 0xff;
dev->temp_buffer[7] = s & 0xff;
}
hdd_image_write(dev->id, i, 1, hdbufferb);
hdd_image_write(dev->id, i, 1, dev->temp_buffer);
}
break;
case GPCMD_MODE_SELECT_6:
@@ -1134,20 +1086,20 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
hdr_len = 4;
if (dev->current_cdb[0] == GPCMD_MODE_SELECT_6) {
block_desc_len = hdbufferb[2];
block_desc_len = dev->temp_buffer[2];
block_desc_len <<= 8;
block_desc_len |= hdbufferb[3];
block_desc_len |= dev->temp_buffer[3];
} else {
block_desc_len = hdbufferb[6];
block_desc_len = dev->temp_buffer[6];
block_desc_len <<= 8;
block_desc_len |= hdbufferb[7];
block_desc_len |= dev->temp_buffer[7];
}
pos = hdr_len + block_desc_len;
while(1) {
page = hdbufferb[pos] & 0x3F;
page_len = hdbufferb[pos + 1];
page = dev->temp_buffer[pos] & 0x3F;
page_len = dev->temp_buffer[pos + 1];
pos += 2;
@@ -1156,7 +1108,7 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
else {
for (i = 0; i < page_len; i++) {
ch = scsi_disk_mode_sense_pages_changeable.pages[page][i + 2];
val = hdbufferb[pos + i];
val = dev->temp_buffer[pos + i];
old_val = dev->ms_pages_saved.pages[page][i + 2];
if (val != old_val) {
if (ch)
@@ -1177,54 +1129,48 @@ scsi_disk_phase_data_out(scsi_disk_t *dev)
break;
}
if (error)
if (error) {
scsi_disk_buf_free(dev);
scsi_disk_invalid_field_pl(dev);
}
break;
default:
fatal("SCSI HDD %i: Bad Command for phase 2 (%02X)\n", dev->id, dev->current_cdb[0]);
break;
}
scsi_disk_set_phase(dev, SCSI_PHASE_STATUS);
scsi_disk_command_stop((scsi_common_t *) dev);
}
/* If the result is 1, issue an IRQ, otherwise not. */
static void
scsi_disk_callback(void *p)
scsi_disk_callback(scsi_common_t *sc)
{
scsi_disk_t *dev = (scsi_disk_t *) p;
switch(dev->packet_status) {
switch(sc->packet_status) {
case PHASE_IDLE:
scsi_disk_log("SCSI HD %i: PHASE_IDLE\n", dev->id);
dev->phase = 1;
dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT);
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);
dev->status = READY_STAT;
dev->phase = 3;
dev->packet_status = 0xFF;
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(dev);
dev->packet_status = PHASE_COMPLETE;
dev->status = READY_STAT;
dev->phase = 3;
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_phase_data_in(dev);
dev->packet_status = PHASE_COMPLETE;
dev->status = READY_STAT;
dev->phase = 3;
scsi_disk_command_stop(sc);
return;
case PHASE_ERROR:
scsi_disk_log("SCSI HD %i: PHASE_ERROR\n", dev->id);
dev->status = READY_STAT | ERR_STAT;
dev->phase = 3;
sc->status = READY_STAT | ERR_STAT;
sc->phase = 3;
return;
}
}
@@ -1263,13 +1209,12 @@ scsi_disk_hard_reset(void)
/* SCSI disk, attach to the SCSI bus. */
sd = &scsi_devices[hdd[c].scsi_id];
sd->p = dev;
sd->sc = (scsi_common_t *) dev;
sd->command = scsi_disk_command;
sd->callback = scsi_disk_callback;
sd->err_stat_to_scsi = scsi_disk_err_stat_to_scsi;
sd->request_sense = scsi_disk_request_sense_for_scsi;
sd->reset = scsi_disk_reset;
sd->read_capacity = scsi_disk_read_capacity;
sd->command_stop = scsi_disk_command_stop;
sd->type = SCSI_FIXED_DISK;
dev->id = c;
@@ -1290,13 +1235,15 @@ scsi_disk_close(void)
int c;
for (c = 0; c < HDD_NUM; c++) {
dev = hdd[c].priv;
if (dev) {
if (hdd[c].bus == HDD_BUS_SCSI) {
hdd_image_close(c);
free(dev);
hdd[c].priv = NULL;
dev = hdd[c].priv;
if (dev) {
free(dev);
hdd[c].priv = NULL;
}
}
}
}