Revision 042ec49d hw/lsi53c895a.c
b/hw/lsi53c895a.c | ||
---|---|---|
173 | 173 |
/* Flag set if this is a tagged command. */ |
174 | 174 |
#define LSI_TAG_VALID (1 << 16) |
175 | 175 |
|
176 |
typedef struct { |
|
176 |
typedef struct lsi_request {
|
|
177 | 177 |
uint32_t tag; |
178 | 178 |
uint32_t pending; |
179 | 179 |
int out; |
180 |
} lsi_queue; |
|
180 |
QTAILQ_ENTRY(lsi_request) next; |
|
181 |
} lsi_request; |
|
181 | 182 |
|
182 | 183 |
typedef struct { |
183 | 184 |
PCIDevice dev; |
... | ... | |
205 | 206 |
uint32_t current_dma_len; |
206 | 207 |
int command_complete; |
207 | 208 |
uint8_t *dma_buf; |
208 |
lsi_queue *queue; |
|
209 |
int queue_len; |
|
210 |
int active_commands; |
|
209 |
QTAILQ_HEAD(, lsi_request) queue; |
|
211 | 210 |
|
212 | 211 |
uint32_t dsa; |
213 | 212 |
uint32_t temp; |
... | ... | |
391 | 390 |
|
392 | 391 |
static void lsi_update_irq(LSIState *s) |
393 | 392 |
{ |
394 |
int i; |
|
395 | 393 |
int level; |
396 | 394 |
static int last_level; |
395 |
lsi_request *p; |
|
397 | 396 |
|
398 | 397 |
/* It's unclear whether the DIP/SIP bits should be cleared when the |
399 | 398 |
Interrupt Status Registers are cleared or when istat0 is read. |
... | ... | |
427 | 426 |
if (!level && lsi_irq_on_rsl(s) && !(s->scntl1 & LSI_SCNTL1_CON)) { |
428 | 427 |
DPRINTF("Handled IRQs & disconnected, looking for pending " |
429 | 428 |
"processes\n"); |
430 |
for (i = 0; i < s->active_commands; i++) {
|
|
431 |
if (s->queue[i].pending) {
|
|
432 |
lsi_reselect(s, s->queue[i].tag);
|
|
429 |
QTAILQ_FOREACH(p, &s->queue, next) {
|
|
430 |
if (p->pending) {
|
|
431 |
lsi_reselect(s, p->tag);
|
|
433 | 432 |
break; |
434 | 433 |
} |
435 | 434 |
} |
... | ... | |
563 | 562 |
/* Add a command to the queue. */ |
564 | 563 |
static void lsi_queue_command(LSIState *s) |
565 | 564 |
{ |
566 |
lsi_queue *p;
|
|
565 |
lsi_request *p;
|
|
567 | 566 |
|
568 | 567 |
DPRINTF("Queueing tag=0x%x\n", s->current_tag); |
569 |
if (s->queue_len == s->active_commands) { |
|
570 |
s->queue_len++; |
|
571 |
s->queue = qemu_realloc(s->queue, s->queue_len * sizeof(lsi_queue)); |
|
572 |
} |
|
573 |
p = &s->queue[s->active_commands++]; |
|
568 |
p = qemu_mallocz(sizeof(*p)); |
|
569 |
QTAILQ_INSERT_TAIL(&s->queue, p, next); |
|
574 | 570 |
p->tag = s->current_tag; |
575 | 571 |
p->pending = 0; |
576 | 572 |
p->out = (s->sstat1 & PHASE_MASK) == PHASE_DO; |
... | ... | |
590 | 586 |
/* Perform reselection to continue a command. */ |
591 | 587 |
static void lsi_reselect(LSIState *s, uint32_t tag) |
592 | 588 |
{ |
593 |
lsi_queue *p; |
|
594 |
int n; |
|
589 |
lsi_request *p; |
|
595 | 590 |
int id; |
596 | 591 |
|
597 |
p = NULL; |
|
598 |
for (n = 0; n < s->active_commands; n++) { |
|
599 |
p = &s->queue[n]; |
|
592 |
QTAILQ_FOREACH(p, &s->queue, next) { |
|
600 | 593 |
if (p->tag == tag) |
601 | 594 |
break; |
602 | 595 |
} |
603 |
if (n == s->active_commands) {
|
|
596 |
if (p == NULL) {
|
|
604 | 597 |
BADF("Reselected non-existant command tag=0x%x\n", tag); |
605 | 598 |
return; |
606 | 599 |
} |
... | ... | |
624 | 617 |
lsi_add_msg_byte(s, tag & 0xff); |
625 | 618 |
} |
626 | 619 |
|
627 |
s->active_commands--; |
|
628 |
if (n != s->active_commands) { |
|
629 |
s->queue[n] = s->queue[s->active_commands]; |
|
630 |
} |
|
620 |
QTAILQ_REMOVE(&s->queue, p, next); |
|
621 |
qemu_free(p); |
|
631 | 622 |
|
632 | 623 |
if (lsi_irq_on_rsl(s)) { |
633 | 624 |
lsi_script_scsi_interrupt(s, LSI_SIST0_RSL, 0); |
... | ... | |
638 | 629 |
the device was reselected, nonzero if the IO is deferred. */ |
639 | 630 |
static int lsi_queue_tag(LSIState *s, uint32_t tag, uint32_t arg) |
640 | 631 |
{ |
641 |
lsi_queue *p; |
|
642 |
int i; |
|
643 |
for (i = 0; i < s->active_commands; i++) { |
|
644 |
p = &s->queue[i]; |
|
632 |
lsi_request *p; |
|
633 |
|
|
634 |
QTAILQ_FOREACH(p, &s->queue, next) { |
|
645 | 635 |
if (p->tag == tag) { |
646 | 636 |
if (p->pending) { |
647 | 637 |
BADF("Multiple IO pending for tag %d\n", tag); |
... | ... | |
659 | 649 |
lsi_reselect(s, tag); |
660 | 650 |
return 0; |
661 | 651 |
} else { |
662 |
DPRINTF("Queueing IO tag=0x%x\n", tag); |
|
652 |
DPRINTF("Queueing IO tag=0x%x\n", tag);
|
|
663 | 653 |
p->pending = arg; |
664 | 654 |
return 1; |
665 | 655 |
} |
... | ... | |
905 | 895 |
|
906 | 896 |
static void lsi_wait_reselect(LSIState *s) |
907 | 897 |
{ |
908 |
int i; |
|
898 |
lsi_request *p; |
|
899 |
|
|
909 | 900 |
DPRINTF("Wait Reselect\n"); |
910 | 901 |
if (s->current_dma_len) |
911 | 902 |
BADF("Reselect with pending DMA\n"); |
912 |
for (i = 0; i < s->active_commands; i++) { |
|
913 |
if (s->queue[i].pending) { |
|
914 |
lsi_reselect(s, s->queue[i].tag); |
|
903 |
|
|
904 |
QTAILQ_FOREACH(p, &s->queue, next) { |
|
905 |
if (p->pending) { |
|
906 |
lsi_reselect(s, p->tag); |
|
915 | 907 |
break; |
916 | 908 |
} |
917 | 909 |
} |
... | ... | |
2008 | 2000 |
|
2009 | 2001 |
assert(s->dma_buf == NULL); |
2010 | 2002 |
assert(s->current_dma_len == 0); |
2011 |
assert(s->active_commands == 0);
|
|
2003 |
assert(QTAILQ_EMPTY(&s->queue));
|
|
2012 | 2004 |
} |
2013 | 2005 |
|
2014 | 2006 |
static const VMStateDescription vmstate_lsi_scsi = { |
... | ... | |
2101 | 2093 |
cpu_unregister_io_memory(s->mmio_io_addr); |
2102 | 2094 |
cpu_unregister_io_memory(s->ram_io_addr); |
2103 | 2095 |
|
2104 |
qemu_free(s->queue); |
|
2105 |
|
|
2106 | 2096 |
return 0; |
2107 | 2097 |
} |
2108 | 2098 |
|
... | ... | |
2140 | 2130 |
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_mmio_mapfunc); |
2141 | 2131 |
pci_register_bar((struct PCIDevice *)s, 2, 0x2000, |
2142 | 2132 |
PCI_BASE_ADDRESS_SPACE_MEMORY, lsi_ram_mapfunc); |
2143 |
s->queue = qemu_malloc(sizeof(lsi_queue)); |
|
2144 |
s->queue_len = 1; |
|
2145 |
s->active_commands = 0; |
|
2133 |
QTAILQ_INIT(&s->queue); |
|
2146 | 2134 |
|
2147 | 2135 |
lsi_soft_reset(s); |
2148 | 2136 |
|
Also available in: Unified diff