xref: /qemu/hw/scsi/esp.c (revision 64552b6b)
149ab747fSPaolo Bonzini /*
249ab747fSPaolo Bonzini  * QEMU ESP/NCR53C9x emulation
349ab747fSPaolo Bonzini  *
449ab747fSPaolo Bonzini  * Copyright (c) 2005-2006 Fabrice Bellard
549ab747fSPaolo Bonzini  * Copyright (c) 2012 Herve Poussineau
649ab747fSPaolo Bonzini  *
749ab747fSPaolo Bonzini  * Permission is hereby granted, free of charge, to any person obtaining a copy
849ab747fSPaolo Bonzini  * of this software and associated documentation files (the "Software"), to deal
949ab747fSPaolo Bonzini  * in the Software without restriction, including without limitation the rights
1049ab747fSPaolo Bonzini  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1149ab747fSPaolo Bonzini  * copies of the Software, and to permit persons to whom the Software is
1249ab747fSPaolo Bonzini  * furnished to do so, subject to the following conditions:
1349ab747fSPaolo Bonzini  *
1449ab747fSPaolo Bonzini  * The above copyright notice and this permission notice shall be included in
1549ab747fSPaolo Bonzini  * all copies or substantial portions of the Software.
1649ab747fSPaolo Bonzini  *
1749ab747fSPaolo Bonzini  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1849ab747fSPaolo Bonzini  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1949ab747fSPaolo Bonzini  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2049ab747fSPaolo Bonzini  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2149ab747fSPaolo Bonzini  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2249ab747fSPaolo Bonzini  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2349ab747fSPaolo Bonzini  * THE SOFTWARE.
2449ab747fSPaolo Bonzini  */
2549ab747fSPaolo Bonzini 
26a4ab4792SPeter Maydell #include "qemu/osdep.h"
2749ab747fSPaolo Bonzini #include "hw/sysbus.h"
28*64552b6bSMarkus Armbruster #include "hw/irq.h"
2949ab747fSPaolo Bonzini #include "hw/scsi/esp.h"
3049ab747fSPaolo Bonzini #include "trace.h"
3149ab747fSPaolo Bonzini #include "qemu/log.h"
320b8fa32fSMarkus Armbruster #include "qemu/module.h"
3349ab747fSPaolo Bonzini 
3449ab747fSPaolo Bonzini /*
3549ab747fSPaolo Bonzini  * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
3649ab747fSPaolo Bonzini  * also produced as NCR89C100. See
3749ab747fSPaolo Bonzini  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
3849ab747fSPaolo Bonzini  * and
3949ab747fSPaolo Bonzini  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
4049ab747fSPaolo Bonzini  */
4149ab747fSPaolo Bonzini 
4249ab747fSPaolo Bonzini static void esp_raise_irq(ESPState *s)
4349ab747fSPaolo Bonzini {
4449ab747fSPaolo Bonzini     if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
4549ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] |= STAT_INT;
4649ab747fSPaolo Bonzini         qemu_irq_raise(s->irq);
4749ab747fSPaolo Bonzini         trace_esp_raise_irq();
4849ab747fSPaolo Bonzini     }
4949ab747fSPaolo Bonzini }
5049ab747fSPaolo Bonzini 
5149ab747fSPaolo Bonzini static void esp_lower_irq(ESPState *s)
5249ab747fSPaolo Bonzini {
5349ab747fSPaolo Bonzini     if (s->rregs[ESP_RSTAT] & STAT_INT) {
5449ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_INT;
5549ab747fSPaolo Bonzini         qemu_irq_lower(s->irq);
5649ab747fSPaolo Bonzini         trace_esp_lower_irq();
5749ab747fSPaolo Bonzini     }
5849ab747fSPaolo Bonzini }
5949ab747fSPaolo Bonzini 
6049ab747fSPaolo Bonzini void esp_dma_enable(ESPState *s, int irq, int level)
6149ab747fSPaolo Bonzini {
6249ab747fSPaolo Bonzini     if (level) {
6349ab747fSPaolo Bonzini         s->dma_enabled = 1;
6449ab747fSPaolo Bonzini         trace_esp_dma_enable();
6549ab747fSPaolo Bonzini         if (s->dma_cb) {
6649ab747fSPaolo Bonzini             s->dma_cb(s);
6749ab747fSPaolo Bonzini             s->dma_cb = NULL;
6849ab747fSPaolo Bonzini         }
6949ab747fSPaolo Bonzini     } else {
7049ab747fSPaolo Bonzini         trace_esp_dma_disable();
7149ab747fSPaolo Bonzini         s->dma_enabled = 0;
7249ab747fSPaolo Bonzini     }
7349ab747fSPaolo Bonzini }
7449ab747fSPaolo Bonzini 
7549ab747fSPaolo Bonzini void esp_request_cancelled(SCSIRequest *req)
7649ab747fSPaolo Bonzini {
7749ab747fSPaolo Bonzini     ESPState *s = req->hba_private;
7849ab747fSPaolo Bonzini 
7949ab747fSPaolo Bonzini     if (req == s->current_req) {
8049ab747fSPaolo Bonzini         scsi_req_unref(s->current_req);
8149ab747fSPaolo Bonzini         s->current_req = NULL;
8249ab747fSPaolo Bonzini         s->current_dev = NULL;
8349ab747fSPaolo Bonzini     }
8449ab747fSPaolo Bonzini }
8549ab747fSPaolo Bonzini 
866c1fef6bSPrasad J Pandit static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
8749ab747fSPaolo Bonzini {
8849ab747fSPaolo Bonzini     uint32_t dmalen;
8949ab747fSPaolo Bonzini     int target;
9049ab747fSPaolo Bonzini 
9149ab747fSPaolo Bonzini     target = s->wregs[ESP_WBUSID] & BUSID_DID;
9249ab747fSPaolo Bonzini     if (s->dma) {
9349ab747fSPaolo Bonzini         dmalen = s->rregs[ESP_TCLO];
9449ab747fSPaolo Bonzini         dmalen |= s->rregs[ESP_TCMID] << 8;
9549ab747fSPaolo Bonzini         dmalen |= s->rregs[ESP_TCHI] << 16;
966c1fef6bSPrasad J Pandit         if (dmalen > buflen) {
976c1fef6bSPrasad J Pandit             return 0;
986c1fef6bSPrasad J Pandit         }
9949ab747fSPaolo Bonzini         s->dma_memory_read(s->dma_opaque, buf, dmalen);
10049ab747fSPaolo Bonzini     } else {
10149ab747fSPaolo Bonzini         dmalen = s->ti_size;
102d3cdc491SPrasad J Pandit         if (dmalen > TI_BUFSZ) {
103d3cdc491SPrasad J Pandit             return 0;
104d3cdc491SPrasad J Pandit         }
10549ab747fSPaolo Bonzini         memcpy(buf, s->ti_buf, dmalen);
10649ab747fSPaolo Bonzini         buf[0] = buf[2] >> 5;
10749ab747fSPaolo Bonzini     }
10849ab747fSPaolo Bonzini     trace_esp_get_cmd(dmalen, target);
10949ab747fSPaolo Bonzini 
11049ab747fSPaolo Bonzini     s->ti_size = 0;
11149ab747fSPaolo Bonzini     s->ti_rptr = 0;
11249ab747fSPaolo Bonzini     s->ti_wptr = 0;
11349ab747fSPaolo Bonzini 
11449ab747fSPaolo Bonzini     if (s->current_req) {
11549ab747fSPaolo Bonzini         /* Started a new command before the old one finished.  Cancel it.  */
11649ab747fSPaolo Bonzini         scsi_req_cancel(s->current_req);
11749ab747fSPaolo Bonzini         s->async_len = 0;
11849ab747fSPaolo Bonzini     }
11949ab747fSPaolo Bonzini 
12049ab747fSPaolo Bonzini     s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
12149ab747fSPaolo Bonzini     if (!s->current_dev) {
12249ab747fSPaolo Bonzini         // No such drive
12349ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] = 0;
12449ab747fSPaolo Bonzini         s->rregs[ESP_RINTR] = INTR_DC;
12549ab747fSPaolo Bonzini         s->rregs[ESP_RSEQ] = SEQ_0;
12649ab747fSPaolo Bonzini         esp_raise_irq(s);
12749ab747fSPaolo Bonzini         return 0;
12849ab747fSPaolo Bonzini     }
12949ab747fSPaolo Bonzini     return dmalen;
13049ab747fSPaolo Bonzini }
13149ab747fSPaolo Bonzini 
13249ab747fSPaolo Bonzini static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
13349ab747fSPaolo Bonzini {
13449ab747fSPaolo Bonzini     int32_t datalen;
13549ab747fSPaolo Bonzini     int lun;
13649ab747fSPaolo Bonzini     SCSIDevice *current_lun;
13749ab747fSPaolo Bonzini 
13849ab747fSPaolo Bonzini     trace_esp_do_busid_cmd(busid);
13949ab747fSPaolo Bonzini     lun = busid & 7;
14049ab747fSPaolo Bonzini     current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
14149ab747fSPaolo Bonzini     s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
14249ab747fSPaolo Bonzini     datalen = scsi_req_enqueue(s->current_req);
14349ab747fSPaolo Bonzini     s->ti_size = datalen;
14449ab747fSPaolo Bonzini     if (datalen != 0) {
14549ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] = STAT_TC;
14649ab747fSPaolo Bonzini         s->dma_left = 0;
14749ab747fSPaolo Bonzini         s->dma_counter = 0;
14849ab747fSPaolo Bonzini         if (datalen > 0) {
14949ab747fSPaolo Bonzini             s->rregs[ESP_RSTAT] |= STAT_DI;
15049ab747fSPaolo Bonzini         } else {
15149ab747fSPaolo Bonzini             s->rregs[ESP_RSTAT] |= STAT_DO;
15249ab747fSPaolo Bonzini         }
15349ab747fSPaolo Bonzini         scsi_req_continue(s->current_req);
15449ab747fSPaolo Bonzini     }
15549ab747fSPaolo Bonzini     s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
15649ab747fSPaolo Bonzini     s->rregs[ESP_RSEQ] = SEQ_CD;
15749ab747fSPaolo Bonzini     esp_raise_irq(s);
15849ab747fSPaolo Bonzini }
15949ab747fSPaolo Bonzini 
16049ab747fSPaolo Bonzini static void do_cmd(ESPState *s, uint8_t *buf)
16149ab747fSPaolo Bonzini {
16249ab747fSPaolo Bonzini     uint8_t busid = buf[0];
16349ab747fSPaolo Bonzini 
16449ab747fSPaolo Bonzini     do_busid_cmd(s, &buf[1], busid);
16549ab747fSPaolo Bonzini }
16649ab747fSPaolo Bonzini 
16749ab747fSPaolo Bonzini static void handle_satn(ESPState *s)
16849ab747fSPaolo Bonzini {
16949ab747fSPaolo Bonzini     uint8_t buf[32];
17049ab747fSPaolo Bonzini     int len;
17149ab747fSPaolo Bonzini 
17249ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
17349ab747fSPaolo Bonzini         s->dma_cb = handle_satn;
17449ab747fSPaolo Bonzini         return;
17549ab747fSPaolo Bonzini     }
1766c1fef6bSPrasad J Pandit     len = get_cmd(s, buf, sizeof(buf));
17749ab747fSPaolo Bonzini     if (len)
17849ab747fSPaolo Bonzini         do_cmd(s, buf);
17949ab747fSPaolo Bonzini }
18049ab747fSPaolo Bonzini 
18149ab747fSPaolo Bonzini static void handle_s_without_atn(ESPState *s)
18249ab747fSPaolo Bonzini {
18349ab747fSPaolo Bonzini     uint8_t buf[32];
18449ab747fSPaolo Bonzini     int len;
18549ab747fSPaolo Bonzini 
18649ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
18749ab747fSPaolo Bonzini         s->dma_cb = handle_s_without_atn;
18849ab747fSPaolo Bonzini         return;
18949ab747fSPaolo Bonzini     }
1906c1fef6bSPrasad J Pandit     len = get_cmd(s, buf, sizeof(buf));
19149ab747fSPaolo Bonzini     if (len) {
19249ab747fSPaolo Bonzini         do_busid_cmd(s, buf, 0);
19349ab747fSPaolo Bonzini     }
19449ab747fSPaolo Bonzini }
19549ab747fSPaolo Bonzini 
19649ab747fSPaolo Bonzini static void handle_satn_stop(ESPState *s)
19749ab747fSPaolo Bonzini {
19849ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
19949ab747fSPaolo Bonzini         s->dma_cb = handle_satn_stop;
20049ab747fSPaolo Bonzini         return;
20149ab747fSPaolo Bonzini     }
2026c1fef6bSPrasad J Pandit     s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
20349ab747fSPaolo Bonzini     if (s->cmdlen) {
20449ab747fSPaolo Bonzini         trace_esp_handle_satn_stop(s->cmdlen);
20549ab747fSPaolo Bonzini         s->do_cmd = 1;
20649ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
20749ab747fSPaolo Bonzini         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
20849ab747fSPaolo Bonzini         s->rregs[ESP_RSEQ] = SEQ_CD;
20949ab747fSPaolo Bonzini         esp_raise_irq(s);
21049ab747fSPaolo Bonzini     }
21149ab747fSPaolo Bonzini }
21249ab747fSPaolo Bonzini 
21349ab747fSPaolo Bonzini static void write_response(ESPState *s)
21449ab747fSPaolo Bonzini {
21549ab747fSPaolo Bonzini     trace_esp_write_response(s->status);
21649ab747fSPaolo Bonzini     s->ti_buf[0] = s->status;
21749ab747fSPaolo Bonzini     s->ti_buf[1] = 0;
21849ab747fSPaolo Bonzini     if (s->dma) {
21949ab747fSPaolo Bonzini         s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
22049ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
22149ab747fSPaolo Bonzini         s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
22249ab747fSPaolo Bonzini         s->rregs[ESP_RSEQ] = SEQ_CD;
22349ab747fSPaolo Bonzini     } else {
22449ab747fSPaolo Bonzini         s->ti_size = 2;
22549ab747fSPaolo Bonzini         s->ti_rptr = 0;
226d020aa50SPaolo Bonzini         s->ti_wptr = 2;
22749ab747fSPaolo Bonzini         s->rregs[ESP_RFLAGS] = 2;
22849ab747fSPaolo Bonzini     }
22949ab747fSPaolo Bonzini     esp_raise_irq(s);
23049ab747fSPaolo Bonzini }
23149ab747fSPaolo Bonzini 
23249ab747fSPaolo Bonzini static void esp_dma_done(ESPState *s)
23349ab747fSPaolo Bonzini {
23449ab747fSPaolo Bonzini     s->rregs[ESP_RSTAT] |= STAT_TC;
23549ab747fSPaolo Bonzini     s->rregs[ESP_RINTR] = INTR_BS;
23649ab747fSPaolo Bonzini     s->rregs[ESP_RSEQ] = 0;
23749ab747fSPaolo Bonzini     s->rregs[ESP_RFLAGS] = 0;
23849ab747fSPaolo Bonzini     s->rregs[ESP_TCLO] = 0;
23949ab747fSPaolo Bonzini     s->rregs[ESP_TCMID] = 0;
24049ab747fSPaolo Bonzini     s->rregs[ESP_TCHI] = 0;
24149ab747fSPaolo Bonzini     esp_raise_irq(s);
24249ab747fSPaolo Bonzini }
24349ab747fSPaolo Bonzini 
24449ab747fSPaolo Bonzini static void esp_do_dma(ESPState *s)
24549ab747fSPaolo Bonzini {
24649ab747fSPaolo Bonzini     uint32_t len;
24749ab747fSPaolo Bonzini     int to_device;
24849ab747fSPaolo Bonzini 
24949ab747fSPaolo Bonzini     len = s->dma_left;
25049ab747fSPaolo Bonzini     if (s->do_cmd) {
25149ab747fSPaolo Bonzini         trace_esp_do_dma(s->cmdlen, len);
252926cde5fSPrasad J Pandit         assert (s->cmdlen <= sizeof(s->cmdbuf) &&
253926cde5fSPrasad J Pandit                 len <= sizeof(s->cmdbuf) - s->cmdlen);
25449ab747fSPaolo Bonzini         s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
25549ab747fSPaolo Bonzini         return;
25649ab747fSPaolo Bonzini     }
25749ab747fSPaolo Bonzini     if (s->async_len == 0) {
25849ab747fSPaolo Bonzini         /* Defer until data is available.  */
25949ab747fSPaolo Bonzini         return;
26049ab747fSPaolo Bonzini     }
26149ab747fSPaolo Bonzini     if (len > s->async_len) {
26249ab747fSPaolo Bonzini         len = s->async_len;
26349ab747fSPaolo Bonzini     }
2647f0b6e11SPaolo Bonzini     to_device = (s->ti_size < 0);
26549ab747fSPaolo Bonzini     if (to_device) {
26649ab747fSPaolo Bonzini         s->dma_memory_read(s->dma_opaque, s->async_buf, len);
26749ab747fSPaolo Bonzini     } else {
26849ab747fSPaolo Bonzini         s->dma_memory_write(s->dma_opaque, s->async_buf, len);
26949ab747fSPaolo Bonzini     }
27049ab747fSPaolo Bonzini     s->dma_left -= len;
27149ab747fSPaolo Bonzini     s->async_buf += len;
27249ab747fSPaolo Bonzini     s->async_len -= len;
27349ab747fSPaolo Bonzini     if (to_device)
27449ab747fSPaolo Bonzini         s->ti_size += len;
27549ab747fSPaolo Bonzini     else
27649ab747fSPaolo Bonzini         s->ti_size -= len;
27749ab747fSPaolo Bonzini     if (s->async_len == 0) {
27849ab747fSPaolo Bonzini         scsi_req_continue(s->current_req);
27949ab747fSPaolo Bonzini         /* If there is still data to be read from the device then
28049ab747fSPaolo Bonzini            complete the DMA operation immediately.  Otherwise defer
28149ab747fSPaolo Bonzini            until the scsi layer has completed.  */
28249ab747fSPaolo Bonzini         if (to_device || s->dma_left != 0 || s->ti_size == 0) {
28349ab747fSPaolo Bonzini             return;
28449ab747fSPaolo Bonzini         }
28549ab747fSPaolo Bonzini     }
28649ab747fSPaolo Bonzini 
28749ab747fSPaolo Bonzini     /* Partially filled a scsi buffer. Complete immediately.  */
28849ab747fSPaolo Bonzini     esp_dma_done(s);
28949ab747fSPaolo Bonzini }
29049ab747fSPaolo Bonzini 
291ea84a442SGuenter Roeck static void esp_report_command_complete(ESPState *s, uint32_t status)
29249ab747fSPaolo Bonzini {
29349ab747fSPaolo Bonzini     trace_esp_command_complete();
29449ab747fSPaolo Bonzini     if (s->ti_size != 0) {
29549ab747fSPaolo Bonzini         trace_esp_command_complete_unexpected();
29649ab747fSPaolo Bonzini     }
29749ab747fSPaolo Bonzini     s->ti_size = 0;
29849ab747fSPaolo Bonzini     s->dma_left = 0;
29949ab747fSPaolo Bonzini     s->async_len = 0;
30049ab747fSPaolo Bonzini     if (status) {
30149ab747fSPaolo Bonzini         trace_esp_command_complete_fail();
30249ab747fSPaolo Bonzini     }
30349ab747fSPaolo Bonzini     s->status = status;
30449ab747fSPaolo Bonzini     s->rregs[ESP_RSTAT] = STAT_ST;
30549ab747fSPaolo Bonzini     esp_dma_done(s);
30649ab747fSPaolo Bonzini     if (s->current_req) {
30749ab747fSPaolo Bonzini         scsi_req_unref(s->current_req);
30849ab747fSPaolo Bonzini         s->current_req = NULL;
30949ab747fSPaolo Bonzini         s->current_dev = NULL;
31049ab747fSPaolo Bonzini     }
31149ab747fSPaolo Bonzini }
31249ab747fSPaolo Bonzini 
313ea84a442SGuenter Roeck void esp_command_complete(SCSIRequest *req, uint32_t status,
314ea84a442SGuenter Roeck                           size_t resid)
315ea84a442SGuenter Roeck {
316ea84a442SGuenter Roeck     ESPState *s = req->hba_private;
317ea84a442SGuenter Roeck 
318ea84a442SGuenter Roeck     if (s->rregs[ESP_RSTAT] & STAT_INT) {
319ea84a442SGuenter Roeck         /* Defer handling command complete until the previous
320ea84a442SGuenter Roeck          * interrupt has been handled.
321ea84a442SGuenter Roeck          */
322ea84a442SGuenter Roeck         trace_esp_command_complete_deferred();
323ea84a442SGuenter Roeck         s->deferred_status = status;
324ea84a442SGuenter Roeck         s->deferred_complete = true;
325ea84a442SGuenter Roeck         return;
326ea84a442SGuenter Roeck     }
327ea84a442SGuenter Roeck     esp_report_command_complete(s, status);
328ea84a442SGuenter Roeck }
329ea84a442SGuenter Roeck 
33049ab747fSPaolo Bonzini void esp_transfer_data(SCSIRequest *req, uint32_t len)
33149ab747fSPaolo Bonzini {
33249ab747fSPaolo Bonzini     ESPState *s = req->hba_private;
33349ab747fSPaolo Bonzini 
3347f0b6e11SPaolo Bonzini     assert(!s->do_cmd);
33549ab747fSPaolo Bonzini     trace_esp_transfer_data(s->dma_left, s->ti_size);
33649ab747fSPaolo Bonzini     s->async_len = len;
33749ab747fSPaolo Bonzini     s->async_buf = scsi_req_get_buf(req);
33849ab747fSPaolo Bonzini     if (s->dma_left) {
33949ab747fSPaolo Bonzini         esp_do_dma(s);
34049ab747fSPaolo Bonzini     } else if (s->dma_counter != 0 && s->ti_size <= 0) {
34149ab747fSPaolo Bonzini         /* If this was the last part of a DMA transfer then the
34249ab747fSPaolo Bonzini            completion interrupt is deferred to here.  */
34349ab747fSPaolo Bonzini         esp_dma_done(s);
34449ab747fSPaolo Bonzini     }
34549ab747fSPaolo Bonzini }
34649ab747fSPaolo Bonzini 
34749ab747fSPaolo Bonzini static void handle_ti(ESPState *s)
34849ab747fSPaolo Bonzini {
34949ab747fSPaolo Bonzini     uint32_t dmalen, minlen;
35049ab747fSPaolo Bonzini 
35149ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
35249ab747fSPaolo Bonzini         s->dma_cb = handle_ti;
35349ab747fSPaolo Bonzini         return;
35449ab747fSPaolo Bonzini     }
35549ab747fSPaolo Bonzini 
35649ab747fSPaolo Bonzini     dmalen = s->rregs[ESP_TCLO];
35749ab747fSPaolo Bonzini     dmalen |= s->rregs[ESP_TCMID] << 8;
35849ab747fSPaolo Bonzini     dmalen |= s->rregs[ESP_TCHI] << 16;
35949ab747fSPaolo Bonzini     if (dmalen==0) {
36049ab747fSPaolo Bonzini       dmalen=0x10000;
36149ab747fSPaolo Bonzini     }
36249ab747fSPaolo Bonzini     s->dma_counter = dmalen;
36349ab747fSPaolo Bonzini 
36449ab747fSPaolo Bonzini     if (s->do_cmd)
365926cde5fSPrasad J Pandit         minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
36649ab747fSPaolo Bonzini     else if (s->ti_size < 0)
36749ab747fSPaolo Bonzini         minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
36849ab747fSPaolo Bonzini     else
36949ab747fSPaolo Bonzini         minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
37049ab747fSPaolo Bonzini     trace_esp_handle_ti(minlen);
37149ab747fSPaolo Bonzini     if (s->dma) {
37249ab747fSPaolo Bonzini         s->dma_left = minlen;
37349ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_TC;
37449ab747fSPaolo Bonzini         esp_do_dma(s);
3757f0b6e11SPaolo Bonzini     }
3767f0b6e11SPaolo Bonzini     if (s->do_cmd) {
37749ab747fSPaolo Bonzini         trace_esp_handle_ti_cmd(s->cmdlen);
37849ab747fSPaolo Bonzini         s->ti_size = 0;
37949ab747fSPaolo Bonzini         s->cmdlen = 0;
38049ab747fSPaolo Bonzini         s->do_cmd = 0;
38149ab747fSPaolo Bonzini         do_cmd(s, s->cmdbuf);
38249ab747fSPaolo Bonzini     }
38349ab747fSPaolo Bonzini }
38449ab747fSPaolo Bonzini 
38549ab747fSPaolo Bonzini void esp_hard_reset(ESPState *s)
38649ab747fSPaolo Bonzini {
38749ab747fSPaolo Bonzini     memset(s->rregs, 0, ESP_REGS);
38849ab747fSPaolo Bonzini     memset(s->wregs, 0, ESP_REGS);
389c9cf45c1SHannes Reinecke     s->tchi_written = 0;
39049ab747fSPaolo Bonzini     s->ti_size = 0;
39149ab747fSPaolo Bonzini     s->ti_rptr = 0;
39249ab747fSPaolo Bonzini     s->ti_wptr = 0;
39349ab747fSPaolo Bonzini     s->dma = 0;
39449ab747fSPaolo Bonzini     s->do_cmd = 0;
39549ab747fSPaolo Bonzini     s->dma_cb = NULL;
39649ab747fSPaolo Bonzini 
39749ab747fSPaolo Bonzini     s->rregs[ESP_CFG1] = 7;
39849ab747fSPaolo Bonzini }
39949ab747fSPaolo Bonzini 
40049ab747fSPaolo Bonzini static void esp_soft_reset(ESPState *s)
40149ab747fSPaolo Bonzini {
40249ab747fSPaolo Bonzini     qemu_irq_lower(s->irq);
40349ab747fSPaolo Bonzini     esp_hard_reset(s);
40449ab747fSPaolo Bonzini }
40549ab747fSPaolo Bonzini 
40649ab747fSPaolo Bonzini static void parent_esp_reset(ESPState *s, int irq, int level)
40749ab747fSPaolo Bonzini {
40849ab747fSPaolo Bonzini     if (level) {
40949ab747fSPaolo Bonzini         esp_soft_reset(s);
41049ab747fSPaolo Bonzini     }
41149ab747fSPaolo Bonzini }
41249ab747fSPaolo Bonzini 
41349ab747fSPaolo Bonzini uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
41449ab747fSPaolo Bonzini {
41549ab747fSPaolo Bonzini     uint32_t old_val;
41649ab747fSPaolo Bonzini 
41749ab747fSPaolo Bonzini     trace_esp_mem_readb(saddr, s->rregs[saddr]);
41849ab747fSPaolo Bonzini     switch (saddr) {
41949ab747fSPaolo Bonzini     case ESP_FIFO:
42049ab747fSPaolo Bonzini         if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
42149ab747fSPaolo Bonzini             /* Data out.  */
422ff589551SPrasad J Pandit             qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
42349ab747fSPaolo Bonzini             s->rregs[ESP_FIFO] = 0;
424ff589551SPrasad J Pandit         } else if (s->ti_rptr < s->ti_wptr) {
425ff589551SPrasad J Pandit             s->ti_size--;
42649ab747fSPaolo Bonzini             s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
42749ab747fSPaolo Bonzini         }
428ff589551SPrasad J Pandit         if (s->ti_rptr == s->ti_wptr) {
42949ab747fSPaolo Bonzini             s->ti_rptr = 0;
43049ab747fSPaolo Bonzini             s->ti_wptr = 0;
43149ab747fSPaolo Bonzini         }
43249ab747fSPaolo Bonzini         break;
43349ab747fSPaolo Bonzini     case ESP_RINTR:
43449ab747fSPaolo Bonzini         /* Clear sequence step, interrupt register and all status bits
43549ab747fSPaolo Bonzini            except TC */
43649ab747fSPaolo Bonzini         old_val = s->rregs[ESP_RINTR];
43749ab747fSPaolo Bonzini         s->rregs[ESP_RINTR] = 0;
43849ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_TC;
43949ab747fSPaolo Bonzini         s->rregs[ESP_RSEQ] = SEQ_CD;
44049ab747fSPaolo Bonzini         esp_lower_irq(s);
441ea84a442SGuenter Roeck         if (s->deferred_complete) {
442ea84a442SGuenter Roeck             esp_report_command_complete(s, s->deferred_status);
443ea84a442SGuenter Roeck             s->deferred_complete = false;
444ea84a442SGuenter Roeck         }
44549ab747fSPaolo Bonzini         return old_val;
446c9cf45c1SHannes Reinecke     case ESP_TCHI:
447c9cf45c1SHannes Reinecke         /* Return the unique id if the value has never been written */
448c9cf45c1SHannes Reinecke         if (!s->tchi_written) {
449c9cf45c1SHannes Reinecke             return s->chip_id;
450c9cf45c1SHannes Reinecke         }
45149ab747fSPaolo Bonzini     default:
45249ab747fSPaolo Bonzini         break;
45349ab747fSPaolo Bonzini     }
45449ab747fSPaolo Bonzini     return s->rregs[saddr];
45549ab747fSPaolo Bonzini }
45649ab747fSPaolo Bonzini 
45749ab747fSPaolo Bonzini void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
45849ab747fSPaolo Bonzini {
45949ab747fSPaolo Bonzini     trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
46049ab747fSPaolo Bonzini     switch (saddr) {
461c9cf45c1SHannes Reinecke     case ESP_TCHI:
462c9cf45c1SHannes Reinecke         s->tchi_written = true;
463c9cf45c1SHannes Reinecke         /* fall through */
46449ab747fSPaolo Bonzini     case ESP_TCLO:
46549ab747fSPaolo Bonzini     case ESP_TCMID:
46649ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_TC;
46749ab747fSPaolo Bonzini         break;
46849ab747fSPaolo Bonzini     case ESP_FIFO:
46949ab747fSPaolo Bonzini         if (s->do_cmd) {
470926cde5fSPrasad J Pandit             if (s->cmdlen < ESP_CMDBUF_SZ) {
47149ab747fSPaolo Bonzini                 s->cmdbuf[s->cmdlen++] = val & 0xff;
472c98c6c10SPrasad J Pandit             } else {
473c98c6c10SPrasad J Pandit                 trace_esp_error_fifo_overrun();
474c98c6c10SPrasad J Pandit             }
475ff589551SPrasad J Pandit         } else if (s->ti_wptr == TI_BUFSZ - 1) {
47649ab747fSPaolo Bonzini             trace_esp_error_fifo_overrun();
47749ab747fSPaolo Bonzini         } else {
47849ab747fSPaolo Bonzini             s->ti_size++;
47949ab747fSPaolo Bonzini             s->ti_buf[s->ti_wptr++] = val & 0xff;
48049ab747fSPaolo Bonzini         }
48149ab747fSPaolo Bonzini         break;
48249ab747fSPaolo Bonzini     case ESP_CMD:
48349ab747fSPaolo Bonzini         s->rregs[saddr] = val;
48449ab747fSPaolo Bonzini         if (val & CMD_DMA) {
48549ab747fSPaolo Bonzini             s->dma = 1;
48649ab747fSPaolo Bonzini             /* Reload DMA counter.  */
48749ab747fSPaolo Bonzini             s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
48849ab747fSPaolo Bonzini             s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
48949ab747fSPaolo Bonzini             s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
49049ab747fSPaolo Bonzini         } else {
49149ab747fSPaolo Bonzini             s->dma = 0;
49249ab747fSPaolo Bonzini         }
49349ab747fSPaolo Bonzini         switch(val & CMD_CMD) {
49449ab747fSPaolo Bonzini         case CMD_NOP:
49549ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_nop(val);
49649ab747fSPaolo Bonzini             break;
49749ab747fSPaolo Bonzini         case CMD_FLUSH:
49849ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_flush(val);
49949ab747fSPaolo Bonzini             //s->ti_size = 0;
50049ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = INTR_FC;
50149ab747fSPaolo Bonzini             s->rregs[ESP_RSEQ] = 0;
50249ab747fSPaolo Bonzini             s->rregs[ESP_RFLAGS] = 0;
50349ab747fSPaolo Bonzini             break;
50449ab747fSPaolo Bonzini         case CMD_RESET:
50549ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_reset(val);
50649ab747fSPaolo Bonzini             esp_soft_reset(s);
50749ab747fSPaolo Bonzini             break;
50849ab747fSPaolo Bonzini         case CMD_BUSRESET:
50949ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_bus_reset(val);
51049ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = INTR_RST;
51149ab747fSPaolo Bonzini             if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
51249ab747fSPaolo Bonzini                 esp_raise_irq(s);
51349ab747fSPaolo Bonzini             }
51449ab747fSPaolo Bonzini             break;
51549ab747fSPaolo Bonzini         case CMD_TI:
51649ab747fSPaolo Bonzini             handle_ti(s);
51749ab747fSPaolo Bonzini             break;
51849ab747fSPaolo Bonzini         case CMD_ICCS:
51949ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_iccs(val);
52049ab747fSPaolo Bonzini             write_response(s);
52149ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = INTR_FC;
52249ab747fSPaolo Bonzini             s->rregs[ESP_RSTAT] |= STAT_MI;
52349ab747fSPaolo Bonzini             break;
52449ab747fSPaolo Bonzini         case CMD_MSGACC:
52549ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_msgacc(val);
52649ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = INTR_DC;
52749ab747fSPaolo Bonzini             s->rregs[ESP_RSEQ] = 0;
52849ab747fSPaolo Bonzini             s->rregs[ESP_RFLAGS] = 0;
52949ab747fSPaolo Bonzini             esp_raise_irq(s);
53049ab747fSPaolo Bonzini             break;
53149ab747fSPaolo Bonzini         case CMD_PAD:
53249ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_pad(val);
53349ab747fSPaolo Bonzini             s->rregs[ESP_RSTAT] = STAT_TC;
53449ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = INTR_FC;
53549ab747fSPaolo Bonzini             s->rregs[ESP_RSEQ] = 0;
53649ab747fSPaolo Bonzini             break;
53749ab747fSPaolo Bonzini         case CMD_SATN:
53849ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_satn(val);
53949ab747fSPaolo Bonzini             break;
54049ab747fSPaolo Bonzini         case CMD_RSTATN:
54149ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_rstatn(val);
54249ab747fSPaolo Bonzini             break;
54349ab747fSPaolo Bonzini         case CMD_SEL:
54449ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_sel(val);
54549ab747fSPaolo Bonzini             handle_s_without_atn(s);
54649ab747fSPaolo Bonzini             break;
54749ab747fSPaolo Bonzini         case CMD_SELATN:
54849ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_selatn(val);
54949ab747fSPaolo Bonzini             handle_satn(s);
55049ab747fSPaolo Bonzini             break;
55149ab747fSPaolo Bonzini         case CMD_SELATNS:
55249ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_selatns(val);
55349ab747fSPaolo Bonzini             handle_satn_stop(s);
55449ab747fSPaolo Bonzini             break;
55549ab747fSPaolo Bonzini         case CMD_ENSEL:
55649ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_ensel(val);
55749ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = 0;
55849ab747fSPaolo Bonzini             break;
55949ab747fSPaolo Bonzini         case CMD_DISSEL:
56049ab747fSPaolo Bonzini             trace_esp_mem_writeb_cmd_dissel(val);
56149ab747fSPaolo Bonzini             s->rregs[ESP_RINTR] = 0;
56249ab747fSPaolo Bonzini             esp_raise_irq(s);
56349ab747fSPaolo Bonzini             break;
56449ab747fSPaolo Bonzini         default:
56549ab747fSPaolo Bonzini             trace_esp_error_unhandled_command(val);
56649ab747fSPaolo Bonzini             break;
56749ab747fSPaolo Bonzini         }
56849ab747fSPaolo Bonzini         break;
56949ab747fSPaolo Bonzini     case ESP_WBUSID ... ESP_WSYNO:
57049ab747fSPaolo Bonzini         break;
57149ab747fSPaolo Bonzini     case ESP_CFG1:
57249ab747fSPaolo Bonzini     case ESP_CFG2: case ESP_CFG3:
57349ab747fSPaolo Bonzini     case ESP_RES3: case ESP_RES4:
57449ab747fSPaolo Bonzini         s->rregs[saddr] = val;
57549ab747fSPaolo Bonzini         break;
57649ab747fSPaolo Bonzini     case ESP_WCCF ... ESP_WTEST:
57749ab747fSPaolo Bonzini         break;
57849ab747fSPaolo Bonzini     default:
57949ab747fSPaolo Bonzini         trace_esp_error_invalid_write(val, saddr);
58049ab747fSPaolo Bonzini         return;
58149ab747fSPaolo Bonzini     }
58249ab747fSPaolo Bonzini     s->wregs[saddr] = val;
58349ab747fSPaolo Bonzini }
58449ab747fSPaolo Bonzini 
58549ab747fSPaolo Bonzini static bool esp_mem_accepts(void *opaque, hwaddr addr,
5868372d383SPeter Maydell                             unsigned size, bool is_write,
5878372d383SPeter Maydell                             MemTxAttrs attrs)
58849ab747fSPaolo Bonzini {
58949ab747fSPaolo Bonzini     return (size == 1) || (is_write && size == 4);
59049ab747fSPaolo Bonzini }
59149ab747fSPaolo Bonzini 
59249ab747fSPaolo Bonzini const VMStateDescription vmstate_esp = {
59349ab747fSPaolo Bonzini     .name ="esp",
594cc966774SPaolo Bonzini     .version_id = 4,
59549ab747fSPaolo Bonzini     .minimum_version_id = 3,
59649ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
59749ab747fSPaolo Bonzini         VMSTATE_BUFFER(rregs, ESPState),
59849ab747fSPaolo Bonzini         VMSTATE_BUFFER(wregs, ESPState),
59949ab747fSPaolo Bonzini         VMSTATE_INT32(ti_size, ESPState),
60049ab747fSPaolo Bonzini         VMSTATE_UINT32(ti_rptr, ESPState),
60149ab747fSPaolo Bonzini         VMSTATE_UINT32(ti_wptr, ESPState),
60249ab747fSPaolo Bonzini         VMSTATE_BUFFER(ti_buf, ESPState),
60349ab747fSPaolo Bonzini         VMSTATE_UINT32(status, ESPState),
604ea84a442SGuenter Roeck         VMSTATE_UINT32(deferred_status, ESPState),
605ea84a442SGuenter Roeck         VMSTATE_BOOL(deferred_complete, ESPState),
60649ab747fSPaolo Bonzini         VMSTATE_UINT32(dma, ESPState),
607cc966774SPaolo Bonzini         VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
608cc966774SPaolo Bonzini         VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
60949ab747fSPaolo Bonzini         VMSTATE_UINT32(cmdlen, ESPState),
61049ab747fSPaolo Bonzini         VMSTATE_UINT32(do_cmd, ESPState),
61149ab747fSPaolo Bonzini         VMSTATE_UINT32(dma_left, ESPState),
61249ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
61349ab747fSPaolo Bonzini     }
61449ab747fSPaolo Bonzini };
61549ab747fSPaolo Bonzini 
61649ab747fSPaolo Bonzini static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
61749ab747fSPaolo Bonzini                                  uint64_t val, unsigned int size)
61849ab747fSPaolo Bonzini {
61949ab747fSPaolo Bonzini     SysBusESPState *sysbus = opaque;
62049ab747fSPaolo Bonzini     uint32_t saddr;
62149ab747fSPaolo Bonzini 
62249ab747fSPaolo Bonzini     saddr = addr >> sysbus->it_shift;
62349ab747fSPaolo Bonzini     esp_reg_write(&sysbus->esp, saddr, val);
62449ab747fSPaolo Bonzini }
62549ab747fSPaolo Bonzini 
62649ab747fSPaolo Bonzini static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
62749ab747fSPaolo Bonzini                                     unsigned int size)
62849ab747fSPaolo Bonzini {
62949ab747fSPaolo Bonzini     SysBusESPState *sysbus = opaque;
63049ab747fSPaolo Bonzini     uint32_t saddr;
63149ab747fSPaolo Bonzini 
63249ab747fSPaolo Bonzini     saddr = addr >> sysbus->it_shift;
63349ab747fSPaolo Bonzini     return esp_reg_read(&sysbus->esp, saddr);
63449ab747fSPaolo Bonzini }
63549ab747fSPaolo Bonzini 
63649ab747fSPaolo Bonzini static const MemoryRegionOps sysbus_esp_mem_ops = {
63749ab747fSPaolo Bonzini     .read = sysbus_esp_mem_read,
63849ab747fSPaolo Bonzini     .write = sysbus_esp_mem_write,
63949ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
64049ab747fSPaolo Bonzini     .valid.accepts = esp_mem_accepts,
64149ab747fSPaolo Bonzini };
64249ab747fSPaolo Bonzini 
64349ab747fSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = {
64449ab747fSPaolo Bonzini     .tcq = false,
64549ab747fSPaolo Bonzini     .max_target = ESP_MAX_DEVS,
64649ab747fSPaolo Bonzini     .max_lun = 7,
64749ab747fSPaolo Bonzini 
64849ab747fSPaolo Bonzini     .transfer_data = esp_transfer_data,
64949ab747fSPaolo Bonzini     .complete = esp_command_complete,
65049ab747fSPaolo Bonzini     .cancel = esp_request_cancelled
65149ab747fSPaolo Bonzini };
65249ab747fSPaolo Bonzini 
65349ab747fSPaolo Bonzini static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
65449ab747fSPaolo Bonzini {
65580cac47eSKamil Rytarowski     SysBusESPState *sysbus = ESP_STATE(opaque);
65649ab747fSPaolo Bonzini     ESPState *s = &sysbus->esp;
65749ab747fSPaolo Bonzini 
65849ab747fSPaolo Bonzini     switch (irq) {
65949ab747fSPaolo Bonzini     case 0:
66049ab747fSPaolo Bonzini         parent_esp_reset(s, irq, level);
66149ab747fSPaolo Bonzini         break;
66249ab747fSPaolo Bonzini     case 1:
66349ab747fSPaolo Bonzini         esp_dma_enable(opaque, irq, level);
66449ab747fSPaolo Bonzini         break;
66549ab747fSPaolo Bonzini     }
66649ab747fSPaolo Bonzini }
66749ab747fSPaolo Bonzini 
668b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp)
66949ab747fSPaolo Bonzini {
670b09318caSHu Tao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
67180cac47eSKamil Rytarowski     SysBusESPState *sysbus = ESP_STATE(dev);
67249ab747fSPaolo Bonzini     ESPState *s = &sysbus->esp;
67349ab747fSPaolo Bonzini 
674b09318caSHu Tao     sysbus_init_irq(sbd, &s->irq);
67549ab747fSPaolo Bonzini     assert(sysbus->it_shift != -1);
67649ab747fSPaolo Bonzini 
67749ab747fSPaolo Bonzini     s->chip_id = TCHI_FAS100A;
67829776739SPaolo Bonzini     memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops,
67929776739SPaolo Bonzini                           sysbus, "esp", ESP_REGS << sysbus->it_shift);
680b09318caSHu Tao     sysbus_init_mmio(sbd, &sysbus->iomem);
68149ab747fSPaolo Bonzini 
682b09318caSHu Tao     qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
68349ab747fSPaolo Bonzini 
684b1187b51SAndreas Färber     scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL);
68549ab747fSPaolo Bonzini }
68649ab747fSPaolo Bonzini 
68749ab747fSPaolo Bonzini static void sysbus_esp_hard_reset(DeviceState *dev)
68849ab747fSPaolo Bonzini {
68980cac47eSKamil Rytarowski     SysBusESPState *sysbus = ESP_STATE(dev);
69049ab747fSPaolo Bonzini     esp_hard_reset(&sysbus->esp);
69149ab747fSPaolo Bonzini }
69249ab747fSPaolo Bonzini 
69349ab747fSPaolo Bonzini static const VMStateDescription vmstate_sysbus_esp_scsi = {
69449ab747fSPaolo Bonzini     .name = "sysbusespscsi",
695ea84a442SGuenter Roeck     .version_id = 1,
696ea84a442SGuenter Roeck     .minimum_version_id = 1,
69749ab747fSPaolo Bonzini     .fields = (VMStateField[]) {
69849ab747fSPaolo Bonzini         VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
69949ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
70049ab747fSPaolo Bonzini     }
70149ab747fSPaolo Bonzini };
70249ab747fSPaolo Bonzini 
70349ab747fSPaolo Bonzini static void sysbus_esp_class_init(ObjectClass *klass, void *data)
70449ab747fSPaolo Bonzini {
70549ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
70649ab747fSPaolo Bonzini 
707b09318caSHu Tao     dc->realize = sysbus_esp_realize;
70849ab747fSPaolo Bonzini     dc->reset = sysbus_esp_hard_reset;
70949ab747fSPaolo Bonzini     dc->vmsd = &vmstate_sysbus_esp_scsi;
710125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
71149ab747fSPaolo Bonzini }
71249ab747fSPaolo Bonzini 
71349ab747fSPaolo Bonzini static const TypeInfo sysbus_esp_info = {
714a71c7ec5SHu Tao     .name          = TYPE_ESP,
71549ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
71649ab747fSPaolo Bonzini     .instance_size = sizeof(SysBusESPState),
71749ab747fSPaolo Bonzini     .class_init    = sysbus_esp_class_init,
71849ab747fSPaolo Bonzini };
71949ab747fSPaolo Bonzini 
72049ab747fSPaolo Bonzini static void esp_register_types(void)
72149ab747fSPaolo Bonzini {
72249ab747fSPaolo Bonzini     type_register_static(&sysbus_esp_info);
72349ab747fSPaolo Bonzini }
72449ab747fSPaolo Bonzini 
72549ab747fSPaolo Bonzini type_init(esp_register_types)
726