提交 64d56409 编写于 作者: J Jan Kiszka 提交者: Anthony Liguori

lsi: Handle removal of selected devices

We must not store references to selected devices as they may be
hot-removed. Instead, look up the device based on its tag right before
using it. If the device disappeared, throw an interrupt and disconnect.
Signed-off-by: NJan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: NAnthony Liguori <aliguori@us.ibm.com>
上级 12aa6dd6
...@@ -175,7 +175,6 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0) ...@@ -175,7 +175,6 @@ do { fprintf(stderr, "lsi_scsi: error: " fmt , ## __VA_ARGS__);} while (0)
typedef struct lsi_request { typedef struct lsi_request {
uint32_t tag; uint32_t tag;
SCSIDevice *dev;
uint32_t dma_len; uint32_t dma_len;
uint8_t *dma_buf; uint8_t *dma_buf;
uint32_t pending; uint32_t pending;
...@@ -202,7 +201,6 @@ typedef struct { ...@@ -202,7 +201,6 @@ typedef struct {
* 3 if a DMA operation is in progress. */ * 3 if a DMA operation is in progress. */
int waiting; int waiting;
SCSIBus bus; SCSIBus bus;
SCSIDevice *select_dev;
int current_lun; int current_lun;
/* The tag is a combination of the device ID and the SCSI tag. */ /* The tag is a combination of the device ID and the SCSI tag. */
uint32_t select_tag; uint32_t select_tag;
...@@ -518,11 +516,25 @@ static void lsi_resume_script(LSIState *s) ...@@ -518,11 +516,25 @@ static void lsi_resume_script(LSIState *s)
} }
} }
static void lsi_disconnect(LSIState *s)
{
s->scntl1 &= ~LSI_SCNTL1_CON;
s->sstat1 &= ~PHASE_MASK;
}
static void lsi_bad_selection(LSIState *s, uint32_t id)
{
DPRINTF("Selected absent target %d\n", id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
}
/* Initiate a SCSI layer data transfer. */ /* Initiate a SCSI layer data transfer. */
static void lsi_do_dma(LSIState *s, int out) static void lsi_do_dma(LSIState *s, int out)
{ {
uint32_t count; uint32_t count, id;
target_phys_addr_t addr; target_phys_addr_t addr;
SCSIDevice *dev;
assert(s->current); assert(s->current);
if (!s->current->dma_len) { if (!s->current->dma_len) {
...@@ -531,6 +543,13 @@ static void lsi_do_dma(LSIState *s, int out) ...@@ -531,6 +543,13 @@ static void lsi_do_dma(LSIState *s, int out)
return; return;
} }
id = s->current->tag >> 8;
dev = s->bus.devs[id];
if (!dev) {
lsi_bad_selection(s, id);
return;
}
count = s->dbc; count = s->dbc;
if (count > s->current->dma_len) if (count > s->current->dma_len)
count = s->current->dma_len; count = s->current->dma_len;
...@@ -550,8 +569,7 @@ static void lsi_do_dma(LSIState *s, int out) ...@@ -550,8 +569,7 @@ static void lsi_do_dma(LSIState *s, int out)
s->dbc -= count; s->dbc -= count;
if (s->current->dma_buf == NULL) { if (s->current->dma_buf == NULL) {
s->current->dma_buf = s->current->dev->info->get_buf(s->current->dev, s->current->dma_buf = dev->info->get_buf(dev, s->current->tag);
s->current->tag);
} }
/* ??? Set SFBR to first data byte. */ /* ??? Set SFBR to first data byte. */
...@@ -565,10 +583,10 @@ static void lsi_do_dma(LSIState *s, int out) ...@@ -565,10 +583,10 @@ static void lsi_do_dma(LSIState *s, int out)
s->current->dma_buf = NULL; s->current->dma_buf = NULL;
if (out) { if (out) {
/* Write the data. */ /* Write the data. */
s->current->dev->info->write_data(s->current->dev, s->current->tag); dev->info->write_data(dev, s->current->tag);
} else { } else {
/* Request any remaining data. */ /* Request any remaining data. */
s->current->dev->info->read_data(s->current->dev, s->current->tag); dev->info->read_data(dev, s->current->tag);
} }
} else { } else {
s->current->dma_buf += count; s->current->dma_buf += count;
...@@ -715,7 +733,9 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag, ...@@ -715,7 +733,9 @@ static void lsi_command_complete(SCSIBus *bus, int reason, uint32_t tag,
static void lsi_do_command(LSIState *s) static void lsi_do_command(LSIState *s)
{ {
SCSIDevice *dev;
uint8_t buf[16]; uint8_t buf[16];
uint32_t id;
int n; int n;
DPRINTF("Send command len=%d\n", s->dbc); DPRINTF("Send command len=%d\n", s->dbc);
...@@ -725,19 +745,24 @@ static void lsi_do_command(LSIState *s) ...@@ -725,19 +745,24 @@ static void lsi_do_command(LSIState *s)
s->sfbr = buf[0]; s->sfbr = buf[0];
s->command_complete = 0; s->command_complete = 0;
id = s->select_tag >> 8;
dev = s->bus.devs[id];
if (!dev) {
lsi_bad_selection(s, id);
return;
}
assert(s->current == NULL); assert(s->current == NULL);
s->current = qemu_mallocz(sizeof(lsi_request)); s->current = qemu_mallocz(sizeof(lsi_request));
s->current->tag = s->select_tag; s->current->tag = s->select_tag;
s->current->dev = s->select_dev;
n = s->current->dev->info->send_command(s->current->dev, s->current->tag, buf, n = dev->info->send_command(dev, s->current->tag, buf, s->current_lun);
s->current_lun);
if (n > 0) { if (n > 0) {
lsi_set_phase(s, PHASE_DI); lsi_set_phase(s, PHASE_DI);
s->current->dev->info->read_data(s->current->dev, s->current->tag); dev->info->read_data(dev, s->current->tag);
} else if (n < 0) { } else if (n < 0) {
lsi_set_phase(s, PHASE_DO); lsi_set_phase(s, PHASE_DO);
s->current->dev->info->write_data(s->current->dev, s->current->tag); dev->info->write_data(dev, s->current->tag);
} }
if (!s->command_complete) { if (!s->command_complete) {
...@@ -771,12 +796,6 @@ static void lsi_do_status(LSIState *s) ...@@ -771,12 +796,6 @@ static void lsi_do_status(LSIState *s)
lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */ lsi_add_msg_byte(s, 0); /* COMMAND COMPLETE */
} }
static void lsi_disconnect(LSIState *s)
{
s->scntl1 &= ~LSI_SCNTL1_CON;
s->sstat1 &= ~PHASE_MASK;
}
static void lsi_do_msgin(LSIState *s) static void lsi_do_msgin(LSIState *s)
{ {
int len; int len;
...@@ -1092,9 +1111,7 @@ again: ...@@ -1092,9 +1111,7 @@ again:
s->sstat0 |= LSI_SSTAT0_WOA; s->sstat0 |= LSI_SSTAT0_WOA;
s->scntl1 &= ~LSI_SCNTL1_IARB; s->scntl1 &= ~LSI_SCNTL1_IARB;
if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) { if (id >= LSI_MAX_DEVS || !s->bus.devs[id]) {
DPRINTF("Selected absent target %d\n", id); lsi_bad_selection(s, id);
lsi_script_scsi_interrupt(s, 0, LSI_SIST1_STO);
lsi_disconnect(s);
break; break;
} }
DPRINTF("Selected target %d%s\n", DPRINTF("Selected target %d%s\n",
...@@ -1102,7 +1119,6 @@ again: ...@@ -1102,7 +1119,6 @@ again:
/* ??? Linux drivers compain when this is set. Maybe /* ??? Linux drivers compain when this is set. Maybe
it only applies in low-level mode (unimplemented). it only applies in low-level mode (unimplemented).
lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */ lsi_script_scsi_interrupt(s, LSI_SIST0_CMP, 0); */
s->select_dev = s->bus.devs[id];
s->select_tag = id << 8; s->select_tag = id << 8;
s->scntl1 |= LSI_SCNTL1_CON; s->scntl1 |= LSI_SCNTL1_CON;
if (insn & (1 << 3)) { if (insn & (1 << 3)) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册