xref: /qemu/hw/scsi/esp.c (revision 8dded6de)
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"
28d6454270SMarkus Armbruster #include "migration/vmstate.h"
2964552b6bSMarkus Armbruster #include "hw/irq.h"
3049ab747fSPaolo Bonzini #include "hw/scsi/esp.h"
3149ab747fSPaolo Bonzini #include "trace.h"
3249ab747fSPaolo Bonzini #include "qemu/log.h"
330b8fa32fSMarkus Armbruster #include "qemu/module.h"
3449ab747fSPaolo Bonzini 
3549ab747fSPaolo Bonzini /*
3649ab747fSPaolo Bonzini  * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
3749ab747fSPaolo Bonzini  * also produced as NCR89C100. See
3849ab747fSPaolo Bonzini  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
3949ab747fSPaolo Bonzini  * and
4049ab747fSPaolo Bonzini  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
4174d71ea1SLaurent Vivier  *
4274d71ea1SLaurent Vivier  * On Macintosh Quadra it is a NCR53C96.
4349ab747fSPaolo Bonzini  */
4449ab747fSPaolo Bonzini 
4549ab747fSPaolo Bonzini static void esp_raise_irq(ESPState *s)
4649ab747fSPaolo Bonzini {
4749ab747fSPaolo Bonzini     if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
4849ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] |= STAT_INT;
4949ab747fSPaolo Bonzini         qemu_irq_raise(s->irq);
5049ab747fSPaolo Bonzini         trace_esp_raise_irq();
5149ab747fSPaolo Bonzini     }
5249ab747fSPaolo Bonzini }
5349ab747fSPaolo Bonzini 
5449ab747fSPaolo Bonzini static void esp_lower_irq(ESPState *s)
5549ab747fSPaolo Bonzini {
5649ab747fSPaolo Bonzini     if (s->rregs[ESP_RSTAT] & STAT_INT) {
5749ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_INT;
5849ab747fSPaolo Bonzini         qemu_irq_lower(s->irq);
5949ab747fSPaolo Bonzini         trace_esp_lower_irq();
6049ab747fSPaolo Bonzini     }
6149ab747fSPaolo Bonzini }
6249ab747fSPaolo Bonzini 
6374d71ea1SLaurent Vivier static void esp_raise_drq(ESPState *s)
6474d71ea1SLaurent Vivier {
6574d71ea1SLaurent Vivier     qemu_irq_raise(s->irq_data);
66960ebfd9SMark Cave-Ayland     trace_esp_raise_drq();
6774d71ea1SLaurent Vivier }
6874d71ea1SLaurent Vivier 
6974d71ea1SLaurent Vivier static void esp_lower_drq(ESPState *s)
7074d71ea1SLaurent Vivier {
7174d71ea1SLaurent Vivier     qemu_irq_lower(s->irq_data);
72960ebfd9SMark Cave-Ayland     trace_esp_lower_drq();
7374d71ea1SLaurent Vivier }
7474d71ea1SLaurent Vivier 
7549ab747fSPaolo Bonzini void esp_dma_enable(ESPState *s, int irq, int level)
7649ab747fSPaolo Bonzini {
7749ab747fSPaolo Bonzini     if (level) {
7849ab747fSPaolo Bonzini         s->dma_enabled = 1;
7949ab747fSPaolo Bonzini         trace_esp_dma_enable();
8049ab747fSPaolo Bonzini         if (s->dma_cb) {
8149ab747fSPaolo Bonzini             s->dma_cb(s);
8249ab747fSPaolo Bonzini             s->dma_cb = NULL;
8349ab747fSPaolo Bonzini         }
8449ab747fSPaolo Bonzini     } else {
8549ab747fSPaolo Bonzini         trace_esp_dma_disable();
8649ab747fSPaolo Bonzini         s->dma_enabled = 0;
8749ab747fSPaolo Bonzini     }
8849ab747fSPaolo Bonzini }
8949ab747fSPaolo Bonzini 
9049ab747fSPaolo Bonzini void esp_request_cancelled(SCSIRequest *req)
9149ab747fSPaolo Bonzini {
9249ab747fSPaolo Bonzini     ESPState *s = req->hba_private;
9349ab747fSPaolo Bonzini 
9449ab747fSPaolo Bonzini     if (req == s->current_req) {
9549ab747fSPaolo Bonzini         scsi_req_unref(s->current_req);
9649ab747fSPaolo Bonzini         s->current_req = NULL;
9749ab747fSPaolo Bonzini         s->current_dev = NULL;
98324c8809SMark Cave-Ayland         s->async_len = 0;
9949ab747fSPaolo Bonzini     }
10049ab747fSPaolo Bonzini }
10149ab747fSPaolo Bonzini 
102e5455b8cSMark Cave-Ayland static void esp_fifo_push(Fifo8 *fifo, uint8_t val)
103042879fcSMark Cave-Ayland {
104e5455b8cSMark Cave-Ayland     if (fifo8_num_used(fifo) == fifo->capacity) {
105042879fcSMark Cave-Ayland         trace_esp_error_fifo_overrun();
106042879fcSMark Cave-Ayland         return;
107042879fcSMark Cave-Ayland     }
108042879fcSMark Cave-Ayland 
109e5455b8cSMark Cave-Ayland     fifo8_push(fifo, val);
110042879fcSMark Cave-Ayland }
111c5fef911SMark Cave-Ayland 
112c5fef911SMark Cave-Ayland static uint8_t esp_fifo_pop(Fifo8 *fifo)
113042879fcSMark Cave-Ayland {
114c5fef911SMark Cave-Ayland     if (fifo8_is_empty(fifo)) {
115042879fcSMark Cave-Ayland         return 0;
116042879fcSMark Cave-Ayland     }
117042879fcSMark Cave-Ayland 
118c5fef911SMark Cave-Ayland     return fifo8_pop(fifo);
119023666daSMark Cave-Ayland }
120023666daSMark Cave-Ayland 
1217b320a8eSMark Cave-Ayland static uint32_t esp_fifo_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen)
1227b320a8eSMark Cave-Ayland {
1237b320a8eSMark Cave-Ayland     const uint8_t *buf;
12449c60d16SMark Cave-Ayland     uint32_t n, n2;
12549c60d16SMark Cave-Ayland     int len;
1267b320a8eSMark Cave-Ayland 
1277b320a8eSMark Cave-Ayland     if (maxlen == 0) {
1287b320a8eSMark Cave-Ayland         return 0;
1297b320a8eSMark Cave-Ayland     }
1307b320a8eSMark Cave-Ayland 
13149c60d16SMark Cave-Ayland     len = maxlen;
13249c60d16SMark Cave-Ayland     buf = fifo8_pop_buf(fifo, len, &n);
1337b320a8eSMark Cave-Ayland     if (dest) {
1347b320a8eSMark Cave-Ayland         memcpy(dest, buf, n);
1357b320a8eSMark Cave-Ayland     }
1367b320a8eSMark Cave-Ayland 
13749c60d16SMark Cave-Ayland     /* Add FIFO wraparound if needed */
13849c60d16SMark Cave-Ayland     len -= n;
13949c60d16SMark Cave-Ayland     len = MIN(len, fifo8_num_used(fifo));
14049c60d16SMark Cave-Ayland     if (len) {
14149c60d16SMark Cave-Ayland         buf = fifo8_pop_buf(fifo, len, &n2);
14249c60d16SMark Cave-Ayland         if (dest) {
14349c60d16SMark Cave-Ayland             memcpy(&dest[n], buf, n2);
14449c60d16SMark Cave-Ayland         }
14549c60d16SMark Cave-Ayland         n += n2;
14649c60d16SMark Cave-Ayland     }
14749c60d16SMark Cave-Ayland 
1487b320a8eSMark Cave-Ayland     return n;
1497b320a8eSMark Cave-Ayland }
1507b320a8eSMark Cave-Ayland 
151c47b5835SMark Cave-Ayland static uint32_t esp_get_tc(ESPState *s)
152c47b5835SMark Cave-Ayland {
153c47b5835SMark Cave-Ayland     uint32_t dmalen;
154c47b5835SMark Cave-Ayland 
155c47b5835SMark Cave-Ayland     dmalen = s->rregs[ESP_TCLO];
156c47b5835SMark Cave-Ayland     dmalen |= s->rregs[ESP_TCMID] << 8;
157c47b5835SMark Cave-Ayland     dmalen |= s->rregs[ESP_TCHI] << 16;
158c47b5835SMark Cave-Ayland 
159c47b5835SMark Cave-Ayland     return dmalen;
160c47b5835SMark Cave-Ayland }
161c47b5835SMark Cave-Ayland 
162c47b5835SMark Cave-Ayland static void esp_set_tc(ESPState *s, uint32_t dmalen)
163c47b5835SMark Cave-Ayland {
164c5d7df28SMark Cave-Ayland     uint32_t old_tc = esp_get_tc(s);
165c5d7df28SMark Cave-Ayland 
166c47b5835SMark Cave-Ayland     s->rregs[ESP_TCLO] = dmalen;
167c47b5835SMark Cave-Ayland     s->rregs[ESP_TCMID] = dmalen >> 8;
168c47b5835SMark Cave-Ayland     s->rregs[ESP_TCHI] = dmalen >> 16;
169c5d7df28SMark Cave-Ayland 
170c5d7df28SMark Cave-Ayland     if (old_tc && dmalen == 0) {
171c5d7df28SMark Cave-Ayland         s->rregs[ESP_RSTAT] |= STAT_TC;
172c5d7df28SMark Cave-Ayland     }
173c47b5835SMark Cave-Ayland }
174c47b5835SMark Cave-Ayland 
175c04ed569SMark Cave-Ayland static uint32_t esp_get_stc(ESPState *s)
176c04ed569SMark Cave-Ayland {
177c04ed569SMark Cave-Ayland     uint32_t dmalen;
178c04ed569SMark Cave-Ayland 
179c04ed569SMark Cave-Ayland     dmalen = s->wregs[ESP_TCLO];
180c04ed569SMark Cave-Ayland     dmalen |= s->wregs[ESP_TCMID] << 8;
181c04ed569SMark Cave-Ayland     dmalen |= s->wregs[ESP_TCHI] << 16;
182c04ed569SMark Cave-Ayland 
183c04ed569SMark Cave-Ayland     return dmalen;
184c04ed569SMark Cave-Ayland }
185c04ed569SMark Cave-Ayland 
186abc139cdSMark Cave-Ayland static const char *esp_phase_names[8] = {
187abc139cdSMark Cave-Ayland     "DATA OUT", "DATA IN", "COMMAND", "STATUS",
188abc139cdSMark Cave-Ayland     "(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN"
189abc139cdSMark Cave-Ayland };
190abc139cdSMark Cave-Ayland 
191abc139cdSMark Cave-Ayland static void esp_set_phase(ESPState *s, uint8_t phase)
192abc139cdSMark Cave-Ayland {
193abc139cdSMark Cave-Ayland     s->rregs[ESP_RSTAT] &= ~7;
194abc139cdSMark Cave-Ayland     s->rregs[ESP_RSTAT] |= phase;
195abc139cdSMark Cave-Ayland 
196abc139cdSMark Cave-Ayland     trace_esp_set_phase(esp_phase_names[phase]);
197abc139cdSMark Cave-Ayland }
198abc139cdSMark Cave-Ayland 
1995a83e83eSMark Cave-Ayland static uint8_t esp_get_phase(ESPState *s)
2005a83e83eSMark Cave-Ayland {
2015a83e83eSMark Cave-Ayland     return s->rregs[ESP_RSTAT] & 7;
2025a83e83eSMark Cave-Ayland }
2035a83e83eSMark Cave-Ayland 
204761bef75SMark Cave-Ayland static uint8_t esp_pdma_read(ESPState *s)
205761bef75SMark Cave-Ayland {
2068da90e81SMark Cave-Ayland     uint8_t val;
2078da90e81SMark Cave-Ayland 
208c5fef911SMark Cave-Ayland     val = esp_fifo_pop(&s->fifo);
2098da90e81SMark Cave-Ayland     return val;
210761bef75SMark Cave-Ayland }
211761bef75SMark Cave-Ayland 
212761bef75SMark Cave-Ayland static void esp_pdma_write(ESPState *s, uint8_t val)
213761bef75SMark Cave-Ayland {
2148da90e81SMark Cave-Ayland     uint32_t dmalen = esp_get_tc(s);
2158da90e81SMark Cave-Ayland 
2163c421400SMark Cave-Ayland     if (dmalen == 0) {
2178da90e81SMark Cave-Ayland         return;
2188da90e81SMark Cave-Ayland     }
2198da90e81SMark Cave-Ayland 
220e5455b8cSMark Cave-Ayland     esp_fifo_push(&s->fifo, val);
2218da90e81SMark Cave-Ayland 
2228da90e81SMark Cave-Ayland     dmalen--;
2238da90e81SMark Cave-Ayland     esp_set_tc(s, dmalen);
224761bef75SMark Cave-Ayland }
225761bef75SMark Cave-Ayland 
226c7bce09cSMark Cave-Ayland static int esp_select(ESPState *s)
2276130b188SLaurent Vivier {
2286130b188SLaurent Vivier     int target;
2296130b188SLaurent Vivier 
2306130b188SLaurent Vivier     target = s->wregs[ESP_WBUSID] & BUSID_DID;
2316130b188SLaurent Vivier 
2326130b188SLaurent Vivier     s->ti_size = 0;
2336130b188SLaurent Vivier 
234cf40a5e4SMark Cave-Ayland     if (s->current_req) {
235cf40a5e4SMark Cave-Ayland         /* Started a new command before the old one finished. Cancel it. */
236cf40a5e4SMark Cave-Ayland         scsi_req_cancel(s->current_req);
237cf40a5e4SMark Cave-Ayland     }
238cf40a5e4SMark Cave-Ayland 
2396130b188SLaurent Vivier     s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
2406130b188SLaurent Vivier     if (!s->current_dev) {
2416130b188SLaurent Vivier         /* No such drive */
2426130b188SLaurent Vivier         s->rregs[ESP_RSTAT] = 0;
243cf1a7a9bSMark Cave-Ayland         s->rregs[ESP_RINTR] = INTR_DC;
2446130b188SLaurent Vivier         s->rregs[ESP_RSEQ] = SEQ_0;
2456130b188SLaurent Vivier         esp_raise_irq(s);
2466130b188SLaurent Vivier         return -1;
2476130b188SLaurent Vivier     }
2484e78f3bfSMark Cave-Ayland 
2494e78f3bfSMark Cave-Ayland     /*
2504e78f3bfSMark Cave-Ayland      * Note that we deliberately don't raise the IRQ here: this will be done
2514eb86065SPaolo Bonzini      * either in do_command_phase() for DATA OUT transfers or by the deferred
2524e78f3bfSMark Cave-Ayland      * IRQ mechanism in esp_transfer_data() for DATA IN transfers
2534e78f3bfSMark Cave-Ayland      */
2544e78f3bfSMark Cave-Ayland     s->rregs[ESP_RINTR] |= INTR_FC;
2554e78f3bfSMark Cave-Ayland     s->rregs[ESP_RSEQ] = SEQ_CD;
2566130b188SLaurent Vivier     return 0;
2576130b188SLaurent Vivier }
2586130b188SLaurent Vivier 
2593ee9a475SMark Cave-Ayland static void esp_do_dma(ESPState *s);
2603ee9a475SMark Cave-Ayland static void esp_do_nodma(ESPState *s);
2613ee9a475SMark Cave-Ayland 
26220c8d2edSMark Cave-Ayland static uint32_t get_cmd(ESPState *s, uint32_t maxlen)
26349ab747fSPaolo Bonzini {
264023666daSMark Cave-Ayland     uint8_t buf[ESP_CMDFIFO_SZ];
265042879fcSMark Cave-Ayland     uint32_t dmalen, n;
26649ab747fSPaolo Bonzini     int target;
26749ab747fSPaolo Bonzini 
26849ab747fSPaolo Bonzini     target = s->wregs[ESP_WBUSID] & BUSID_DID;
26949ab747fSPaolo Bonzini     if (s->dma) {
27020c8d2edSMark Cave-Ayland         dmalen = MIN(esp_get_tc(s), maxlen);
27120c8d2edSMark Cave-Ayland         if (dmalen == 0) {
2726c1fef6bSPrasad J Pandit             return 0;
2736c1fef6bSPrasad J Pandit         }
27474d71ea1SLaurent Vivier         if (s->dma_memory_read) {
27549ab747fSPaolo Bonzini             s->dma_memory_read(s->dma_opaque, buf, dmalen);
276fbc6510eSMark Cave-Ayland             dmalen = MIN(fifo8_num_free(&s->cmdfifo), dmalen);
277023666daSMark Cave-Ayland             fifo8_push_all(&s->cmdfifo, buf, dmalen);
278a0347651SMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - dmalen);
27949ab747fSPaolo Bonzini         } else {
28074d71ea1SLaurent Vivier             return 0;
28174d71ea1SLaurent Vivier         }
28274d71ea1SLaurent Vivier     } else {
283023666daSMark Cave-Ayland         dmalen = MIN(fifo8_num_used(&s->fifo), maxlen);
28420c8d2edSMark Cave-Ayland         if (dmalen == 0) {
285d3cdc491SPrasad J Pandit             return 0;
286d3cdc491SPrasad J Pandit         }
2877b320a8eSMark Cave-Ayland         n = esp_fifo_pop_buf(&s->fifo, buf, dmalen);
288fbc6510eSMark Cave-Ayland         n = MIN(fifo8_num_free(&s->cmdfifo), n);
2897b320a8eSMark Cave-Ayland         fifo8_push_all(&s->cmdfifo, buf, n);
29020c8d2edSMark Cave-Ayland     }
29149ab747fSPaolo Bonzini     trace_esp_get_cmd(dmalen, target);
29249ab747fSPaolo Bonzini 
29349ab747fSPaolo Bonzini     return dmalen;
29449ab747fSPaolo Bonzini }
29549ab747fSPaolo Bonzini 
2964eb86065SPaolo Bonzini static void do_command_phase(ESPState *s)
29749ab747fSPaolo Bonzini {
2987b320a8eSMark Cave-Ayland     uint32_t cmdlen;
29949ab747fSPaolo Bonzini     int32_t datalen;
30049ab747fSPaolo Bonzini     SCSIDevice *current_lun;
3017b320a8eSMark Cave-Ayland     uint8_t buf[ESP_CMDFIFO_SZ];
30249ab747fSPaolo Bonzini 
3034eb86065SPaolo Bonzini     trace_esp_do_command_phase(s->lun);
304023666daSMark Cave-Ayland     cmdlen = fifo8_num_used(&s->cmdfifo);
30599545751SMark Cave-Ayland     if (!cmdlen || !s->current_dev) {
30699545751SMark Cave-Ayland         return;
30799545751SMark Cave-Ayland     }
3087b320a8eSMark Cave-Ayland     esp_fifo_pop_buf(&s->cmdfifo, buf, cmdlen);
309023666daSMark Cave-Ayland 
3104eb86065SPaolo Bonzini     current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun);
311b22f83d8SAlexandra Diupina     if (!current_lun) {
312b22f83d8SAlexandra Diupina         /* No such drive */
313b22f83d8SAlexandra Diupina         s->rregs[ESP_RSTAT] = 0;
314b22f83d8SAlexandra Diupina         s->rregs[ESP_RINTR] = INTR_DC;
315b22f83d8SAlexandra Diupina         s->rregs[ESP_RSEQ] = SEQ_0;
316b22f83d8SAlexandra Diupina         esp_raise_irq(s);
317b22f83d8SAlexandra Diupina         return;
318b22f83d8SAlexandra Diupina     }
319b22f83d8SAlexandra Diupina 
320fe9d8927SJohn Millikin     s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s);
32149ab747fSPaolo Bonzini     datalen = scsi_req_enqueue(s->current_req);
32249ab747fSPaolo Bonzini     s->ti_size = datalen;
323023666daSMark Cave-Ayland     fifo8_reset(&s->cmdfifo);
32449ab747fSPaolo Bonzini     if (datalen != 0) {
3251b9e48a5SMark Cave-Ayland         s->ti_cmd = 0;
32649ab747fSPaolo Bonzini         if (datalen > 0) {
3274e78f3bfSMark Cave-Ayland             /*
3284e78f3bfSMark Cave-Ayland              * Switch to DATA IN phase but wait until initial data xfer is
3294e78f3bfSMark Cave-Ayland              * complete before raising the command completion interrupt
3304e78f3bfSMark Cave-Ayland              */
331*8dded6deSMark Cave-Ayland             s->data_ready = false;
332abc139cdSMark Cave-Ayland             esp_set_phase(s, STAT_DI);
33349ab747fSPaolo Bonzini         } else {
334abc139cdSMark Cave-Ayland             esp_set_phase(s, STAT_DO);
335cf47a41eSMark Cave-Ayland             s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
33649ab747fSPaolo Bonzini             esp_raise_irq(s);
33782141c8bSMark Cave-Ayland             esp_lower_drq(s);
33849ab747fSPaolo Bonzini         }
3394e78f3bfSMark Cave-Ayland         scsi_req_continue(s->current_req);
3404e78f3bfSMark Cave-Ayland         return;
3414e78f3bfSMark Cave-Ayland     }
3424e78f3bfSMark Cave-Ayland }
34349ab747fSPaolo Bonzini 
3444eb86065SPaolo Bonzini static void do_message_phase(ESPState *s)
34549ab747fSPaolo Bonzini {
3464eb86065SPaolo Bonzini     if (s->cmdfifo_cdb_offset) {
3474eb86065SPaolo Bonzini         uint8_t message = esp_fifo_pop(&s->cmdfifo);
348023666daSMark Cave-Ayland 
3494eb86065SPaolo Bonzini         trace_esp_do_identify(message);
3504eb86065SPaolo Bonzini         s->lun = message & 7;
351023666daSMark Cave-Ayland         s->cmdfifo_cdb_offset--;
3524eb86065SPaolo Bonzini     }
35349ab747fSPaolo Bonzini 
354799d90d8SMark Cave-Ayland     /* Ignore extended messages for now */
355023666daSMark Cave-Ayland     if (s->cmdfifo_cdb_offset) {
3564eb86065SPaolo Bonzini         int len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo));
357fa7505c1SMark Cave-Ayland         esp_fifo_pop_buf(&s->cmdfifo, NULL, len);
358023666daSMark Cave-Ayland         s->cmdfifo_cdb_offset = 0;
359023666daSMark Cave-Ayland     }
3604eb86065SPaolo Bonzini }
361023666daSMark Cave-Ayland 
3624eb86065SPaolo Bonzini static void do_cmd(ESPState *s)
3634eb86065SPaolo Bonzini {
3644eb86065SPaolo Bonzini     do_message_phase(s);
3654eb86065SPaolo Bonzini     assert(s->cmdfifo_cdb_offset == 0);
3664eb86065SPaolo Bonzini     do_command_phase(s);
36749ab747fSPaolo Bonzini }
36849ab747fSPaolo Bonzini 
36949ab747fSPaolo Bonzini static void handle_satn(ESPState *s)
37049ab747fSPaolo Bonzini {
37149ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
37249ab747fSPaolo Bonzini         s->dma_cb = handle_satn;
37349ab747fSPaolo Bonzini         return;
37449ab747fSPaolo Bonzini     }
375b46a43a2SMark Cave-Ayland 
3761bcaf71bSMark Cave-Ayland     if (esp_select(s) < 0) {
3771bcaf71bSMark Cave-Ayland         return;
3781bcaf71bSMark Cave-Ayland     }
3793ee9a475SMark Cave-Ayland 
3803ee9a475SMark Cave-Ayland     esp_set_phase(s, STAT_MO);
3813ee9a475SMark Cave-Ayland 
3823ee9a475SMark Cave-Ayland     if (s->dma) {
3833ee9a475SMark Cave-Ayland         esp_do_dma(s);
3843ee9a475SMark Cave-Ayland     } else {
3853ee9a475SMark Cave-Ayland         if (get_cmd(s, ESP_CMDFIFO_SZ)) {
386023666daSMark Cave-Ayland             s->cmdfifo_cdb_offset = 1;
387c959f218SMark Cave-Ayland             do_cmd(s);
3881bcaf71bSMark Cave-Ayland         }
38949ab747fSPaolo Bonzini     }
39094d5c79dSMark Cave-Ayland }
39149ab747fSPaolo Bonzini 
39249ab747fSPaolo Bonzini static void handle_s_without_atn(ESPState *s)
39349ab747fSPaolo Bonzini {
39449ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
39549ab747fSPaolo Bonzini         s->dma_cb = handle_s_without_atn;
39649ab747fSPaolo Bonzini         return;
39749ab747fSPaolo Bonzini     }
398b46a43a2SMark Cave-Ayland 
3991bcaf71bSMark Cave-Ayland     if (esp_select(s) < 0) {
4001bcaf71bSMark Cave-Ayland         return;
4011bcaf71bSMark Cave-Ayland     }
4029ff0fd12SMark Cave-Ayland 
403abc139cdSMark Cave-Ayland     esp_set_phase(s, STAT_CD);
4049ff0fd12SMark Cave-Ayland     s->rregs[ESP_RSEQ] = SEQ_CD;
4059ff0fd12SMark Cave-Ayland     s->cmdfifo_cdb_offset = 0;
4069ff0fd12SMark Cave-Ayland 
4079ff0fd12SMark Cave-Ayland     if (s->dma) {
4089ff0fd12SMark Cave-Ayland         esp_do_dma(s);
4099ff0fd12SMark Cave-Ayland     } else {
4109ff0fd12SMark Cave-Ayland         if (get_cmd(s, ESP_CMDFIFO_SZ)) {
4119ff0fd12SMark Cave-Ayland             do_cmd(s);
4129ff0fd12SMark Cave-Ayland         }
41349ab747fSPaolo Bonzini     }
41449ab747fSPaolo Bonzini }
41549ab747fSPaolo Bonzini 
41649ab747fSPaolo Bonzini static void handle_satn_stop(ESPState *s)
41749ab747fSPaolo Bonzini {
41849ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
41949ab747fSPaolo Bonzini         s->dma_cb = handle_satn_stop;
42049ab747fSPaolo Bonzini         return;
42149ab747fSPaolo Bonzini     }
422b46a43a2SMark Cave-Ayland 
4231bcaf71bSMark Cave-Ayland     if (esp_select(s) < 0) {
4241bcaf71bSMark Cave-Ayland         return;
4251bcaf71bSMark Cave-Ayland     }
426db4d4150SMark Cave-Ayland 
427abc139cdSMark Cave-Ayland     esp_set_phase(s, STAT_MO);
428db4d4150SMark Cave-Ayland     s->rregs[ESP_RSEQ] = SEQ_MO;
429db4d4150SMark Cave-Ayland 
430db4d4150SMark Cave-Ayland     if (s->dma) {
431db4d4150SMark Cave-Ayland         esp_do_dma(s);
432db4d4150SMark Cave-Ayland     } else {
433db4d4150SMark Cave-Ayland         if (get_cmd(s, 1)) {
434db4d4150SMark Cave-Ayland             trace_esp_handle_satn_stop(fifo8_num_used(&s->cmdfifo));
435db4d4150SMark Cave-Ayland 
436db4d4150SMark Cave-Ayland             /* Raise command completion interrupt */
437cf47a41eSMark Cave-Ayland             s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
438799d90d8SMark Cave-Ayland             s->rregs[ESP_RSEQ] = SEQ_MO;
43949ab747fSPaolo Bonzini             esp_raise_irq(s);
4401bcaf71bSMark Cave-Ayland         }
44149ab747fSPaolo Bonzini     }
44249ab747fSPaolo Bonzini }
44349ab747fSPaolo Bonzini 
44449ab747fSPaolo Bonzini static void write_response(ESPState *s)
44549ab747fSPaolo Bonzini {
446e3922557SMark Cave-Ayland     uint8_t buf[2];
447042879fcSMark Cave-Ayland 
44849ab747fSPaolo Bonzini     trace_esp_write_response(s->status);
449042879fcSMark Cave-Ayland 
4508baa1472SMark Cave-Ayland     if (s->dma) {
4518baa1472SMark Cave-Ayland         esp_do_dma(s);
4528baa1472SMark Cave-Ayland     } else {
453e3922557SMark Cave-Ayland         buf[0] = s->status;
454e3922557SMark Cave-Ayland         buf[1] = 0;
455042879fcSMark Cave-Ayland 
456e3922557SMark Cave-Ayland         fifo8_reset(&s->fifo);
457e3922557SMark Cave-Ayland         fifo8_push_all(&s->fifo, buf, 2);
45849ab747fSPaolo Bonzini         s->rregs[ESP_RFLAGS] = 2;
45949ab747fSPaolo Bonzini         esp_raise_irq(s);
46049ab747fSPaolo Bonzini     }
4618baa1472SMark Cave-Ayland }
46249ab747fSPaolo Bonzini 
463004826d0SMark Cave-Ayland static void esp_dma_ti_check(ESPState *s)
46449ab747fSPaolo Bonzini {
465af74b3c1SMark Cave-Ayland     if (esp_get_tc(s) == 0 && fifo8_num_used(&s->fifo) < 2) {
466cf47a41eSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
46749ab747fSPaolo Bonzini         esp_raise_irq(s);
468af74b3c1SMark Cave-Ayland         esp_lower_drq(s);
469af74b3c1SMark Cave-Ayland     }
47049ab747fSPaolo Bonzini }
47149ab747fSPaolo Bonzini 
47249ab747fSPaolo Bonzini static void esp_do_dma(ESPState *s)
47349ab747fSPaolo Bonzini {
474023666daSMark Cave-Ayland     uint32_t len, cmdlen;
475023666daSMark Cave-Ayland     uint8_t buf[ESP_CMDFIFO_SZ];
47619e9afb1SMark Cave-Ayland     int n;
47749ab747fSPaolo Bonzini 
4786cc88d6bSMark Cave-Ayland     len = esp_get_tc(s);
479ad2725afSMark Cave-Ayland 
480ad2725afSMark Cave-Ayland     switch (esp_get_phase(s)) {
481ad2725afSMark Cave-Ayland     case STAT_MO:
48246b0c361SMark Cave-Ayland         if (s->dma_memory_read) {
48346b0c361SMark Cave-Ayland             len = MIN(len, fifo8_num_free(&s->cmdfifo));
48446b0c361SMark Cave-Ayland             s->dma_memory_read(s->dma_opaque, buf, len);
48546b0c361SMark Cave-Ayland             fifo8_push_all(&s->cmdfifo, buf, len);
48646b0c361SMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - len);
48746b0c361SMark Cave-Ayland             s->cmdfifo_cdb_offset += len;
48846b0c361SMark Cave-Ayland         } else {
48946b0c361SMark Cave-Ayland             n = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
49046b0c361SMark Cave-Ayland             n = MIN(fifo8_num_free(&s->cmdfifo), n);
49146b0c361SMark Cave-Ayland             fifo8_push_all(&s->cmdfifo, buf, n);
49246b0c361SMark Cave-Ayland             s->cmdfifo_cdb_offset += n;
49346b0c361SMark Cave-Ayland         }
49446b0c361SMark Cave-Ayland 
49546b0c361SMark Cave-Ayland         esp_raise_drq(s);
49646b0c361SMark Cave-Ayland 
4973ee9a475SMark Cave-Ayland         switch (s->rregs[ESP_CMD]) {
4983ee9a475SMark Cave-Ayland         case CMD_SELATN | CMD_DMA:
4993ee9a475SMark Cave-Ayland             if (fifo8_num_used(&s->cmdfifo) >= 1) {
5003ee9a475SMark Cave-Ayland                 /* First byte received, switch to command phase */
5013ee9a475SMark Cave-Ayland                 esp_set_phase(s, STAT_CD);
5023ee9a475SMark Cave-Ayland                 s->cmdfifo_cdb_offset = 1;
5033ee9a475SMark Cave-Ayland 
5043ee9a475SMark Cave-Ayland                 if (fifo8_num_used(&s->cmdfifo) > 1) {
5053ee9a475SMark Cave-Ayland                     /* Process any additional command phase data */
5063ee9a475SMark Cave-Ayland                     esp_do_dma(s);
5073ee9a475SMark Cave-Ayland                 }
5083ee9a475SMark Cave-Ayland             }
5093ee9a475SMark Cave-Ayland             break;
5103ee9a475SMark Cave-Ayland 
511db4d4150SMark Cave-Ayland         case CMD_SELATNS | CMD_DMA:
512db4d4150SMark Cave-Ayland             if (fifo8_num_used(&s->cmdfifo) == 1) {
513db4d4150SMark Cave-Ayland                 /* First byte received, stop in message out phase */
514db4d4150SMark Cave-Ayland                 s->cmdfifo_cdb_offset = 1;
515db4d4150SMark Cave-Ayland 
516db4d4150SMark Cave-Ayland                 /* Raise command completion interrupt */
517db4d4150SMark Cave-Ayland                 s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
518db4d4150SMark Cave-Ayland                 s->rregs[ESP_RSEQ] = SEQ_CD;
519db4d4150SMark Cave-Ayland                 esp_raise_irq(s);
520db4d4150SMark Cave-Ayland             }
521db4d4150SMark Cave-Ayland             break;
522db4d4150SMark Cave-Ayland 
5233fd325a2SMark Cave-Ayland         case CMD_TI | CMD_DMA:
52446b0c361SMark Cave-Ayland             /* ATN remains asserted until TC == 0 */
52546b0c361SMark Cave-Ayland             if (esp_get_tc(s) == 0) {
52646b0c361SMark Cave-Ayland                 esp_set_phase(s, STAT_CD);
52746b0c361SMark Cave-Ayland                 s->rregs[ESP_RSEQ] = SEQ_CD;
52846b0c361SMark Cave-Ayland                 s->rregs[ESP_RINTR] |= INTR_BS;
52946b0c361SMark Cave-Ayland                 esp_raise_irq(s);
53046b0c361SMark Cave-Ayland             }
53146b0c361SMark Cave-Ayland             break;
5323fd325a2SMark Cave-Ayland         }
5333fd325a2SMark Cave-Ayland         break;
53446b0c361SMark Cave-Ayland 
535ad2725afSMark Cave-Ayland     case STAT_CD:
536023666daSMark Cave-Ayland         cmdlen = fifo8_num_used(&s->cmdfifo);
537023666daSMark Cave-Ayland         trace_esp_do_dma(cmdlen, len);
53874d71ea1SLaurent Vivier         if (s->dma_memory_read) {
5390ebb5fd8SMark Cave-Ayland             len = MIN(len, fifo8_num_free(&s->cmdfifo));
540023666daSMark Cave-Ayland             s->dma_memory_read(s->dma_opaque, buf, len);
541023666daSMark Cave-Ayland             fifo8_push_all(&s->cmdfifo, buf, len);
542a0347651SMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - len);
54374d71ea1SLaurent Vivier         } else {
5443c7f3c8bSMark Cave-Ayland             n = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
5453c7f3c8bSMark Cave-Ayland             n = MIN(fifo8_num_free(&s->cmdfifo), n);
5463c7f3c8bSMark Cave-Ayland             fifo8_push_all(&s->cmdfifo, buf, n);
5473c7f3c8bSMark Cave-Ayland 
54874d71ea1SLaurent Vivier             esp_raise_drq(s);
5493c7f3c8bSMark Cave-Ayland         }
550023666daSMark Cave-Ayland         trace_esp_handle_ti_cmd(cmdlen);
55115407433SLaurent Vivier         s->ti_size = 0;
55246b0c361SMark Cave-Ayland         if (esp_get_tc(s) == 0) {
553799d90d8SMark Cave-Ayland             /* Command has been received */
554c959f218SMark Cave-Ayland             do_cmd(s);
555799d90d8SMark Cave-Ayland         }
556ad2725afSMark Cave-Ayland         break;
5571454dc76SMark Cave-Ayland 
5581454dc76SMark Cave-Ayland     case STAT_DO:
5590db89536SMark Cave-Ayland         if (!s->current_req) {
5600db89536SMark Cave-Ayland             return;
5610db89536SMark Cave-Ayland         }
5624460b86aSMark Cave-Ayland         if (s->async_len == 0 && esp_get_tc(s) && s->ti_size) {
56349ab747fSPaolo Bonzini             /* Defer until data is available.  */
56449ab747fSPaolo Bonzini             return;
56549ab747fSPaolo Bonzini         }
56649ab747fSPaolo Bonzini         if (len > s->async_len) {
56749ab747fSPaolo Bonzini             len = s->async_len;
56849ab747fSPaolo Bonzini         }
56974d71ea1SLaurent Vivier         if (s->dma_memory_read) {
57049ab747fSPaolo Bonzini             s->dma_memory_read(s->dma_opaque, s->async_buf, len);
571f3666223SMark Cave-Ayland 
572f3666223SMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - len);
573f3666223SMark Cave-Ayland             s->async_buf += len;
574f3666223SMark Cave-Ayland             s->async_len -= len;
575f3666223SMark Cave-Ayland             s->ti_size += len;
576f3666223SMark Cave-Ayland 
577e4e166c8SMark Cave-Ayland             if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
578e4e166c8SMark Cave-Ayland                 /* Defer until the scsi layer has completed */
579f3666223SMark Cave-Ayland                 scsi_req_continue(s->current_req);
580f3666223SMark Cave-Ayland                 return;
581f3666223SMark Cave-Ayland             }
582f3666223SMark Cave-Ayland 
583004826d0SMark Cave-Ayland             esp_dma_ti_check(s);
58449ab747fSPaolo Bonzini         } else {
58519e9afb1SMark Cave-Ayland             /* Copy FIFO data to device */
58619e9afb1SMark Cave-Ayland             len = MIN(s->async_len, ESP_FIFO_SZ);
58719e9afb1SMark Cave-Ayland             len = MIN(len, fifo8_num_used(&s->fifo));
58819e9afb1SMark Cave-Ayland             n = esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
58919e9afb1SMark Cave-Ayland             s->async_buf += n;
59019e9afb1SMark Cave-Ayland             s->async_len -= n;
59119e9afb1SMark Cave-Ayland             s->ti_size += n;
59219e9afb1SMark Cave-Ayland 
59374d71ea1SLaurent Vivier             esp_raise_drq(s);
594e4e166c8SMark Cave-Ayland 
595e4e166c8SMark Cave-Ayland             if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
596e4e166c8SMark Cave-Ayland                 /* Defer until the scsi layer has completed */
597e4e166c8SMark Cave-Ayland                 scsi_req_continue(s->current_req);
598e4e166c8SMark Cave-Ayland                 return;
599e4e166c8SMark Cave-Ayland             }
600e4e166c8SMark Cave-Ayland 
601004826d0SMark Cave-Ayland             esp_dma_ti_check(s);
60274d71ea1SLaurent Vivier         }
6031454dc76SMark Cave-Ayland         break;
6041454dc76SMark Cave-Ayland 
6051454dc76SMark Cave-Ayland     case STAT_DI:
6061454dc76SMark Cave-Ayland         if (!s->current_req) {
6071454dc76SMark Cave-Ayland             return;
6081454dc76SMark Cave-Ayland         }
6091454dc76SMark Cave-Ayland         if (s->async_len == 0 && esp_get_tc(s) && s->ti_size) {
6101454dc76SMark Cave-Ayland             /* Defer until data is available.  */
6111454dc76SMark Cave-Ayland             return;
6121454dc76SMark Cave-Ayland         }
6131454dc76SMark Cave-Ayland         if (len > s->async_len) {
6141454dc76SMark Cave-Ayland             len = s->async_len;
6151454dc76SMark Cave-Ayland         }
61674d71ea1SLaurent Vivier         if (s->dma_memory_write) {
61749ab747fSPaolo Bonzini             s->dma_memory_write(s->dma_opaque, s->async_buf, len);
618f3666223SMark Cave-Ayland 
619f3666223SMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - len);
620f3666223SMark Cave-Ayland             s->async_buf += len;
621f3666223SMark Cave-Ayland             s->async_len -= len;
622f3666223SMark Cave-Ayland             s->ti_size -= len;
623f3666223SMark Cave-Ayland 
624e4e166c8SMark Cave-Ayland             if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
625e4e166c8SMark Cave-Ayland                 /* Defer until the scsi layer has completed */
626f3666223SMark Cave-Ayland                 scsi_req_continue(s->current_req);
627fabcba49SMark Cave-Ayland                 return;
628f3666223SMark Cave-Ayland             }
629f3666223SMark Cave-Ayland 
630004826d0SMark Cave-Ayland             esp_dma_ti_check(s);
63174d71ea1SLaurent Vivier         } else {
63282141c8bSMark Cave-Ayland             /* Copy device data to FIFO */
633042879fcSMark Cave-Ayland             len = MIN(len, fifo8_num_free(&s->fifo));
634042879fcSMark Cave-Ayland             fifo8_push_all(&s->fifo, s->async_buf, len);
63582141c8bSMark Cave-Ayland             s->async_buf += len;
63682141c8bSMark Cave-Ayland             s->async_len -= len;
63782141c8bSMark Cave-Ayland             s->ti_size -= len;
63882141c8bSMark Cave-Ayland             esp_set_tc(s, esp_get_tc(s) - len);
63974d71ea1SLaurent Vivier             esp_raise_drq(s);
640e4e166c8SMark Cave-Ayland 
641e4e166c8SMark Cave-Ayland             if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) {
642e4e166c8SMark Cave-Ayland                 /* Defer until the scsi layer has completed */
643e4e166c8SMark Cave-Ayland                 scsi_req_continue(s->current_req);
644e4e166c8SMark Cave-Ayland                 return;
645e4e166c8SMark Cave-Ayland             }
646e4e166c8SMark Cave-Ayland 
647004826d0SMark Cave-Ayland             esp_dma_ti_check(s);
648e4e166c8SMark Cave-Ayland         }
6491454dc76SMark Cave-Ayland         break;
6508baa1472SMark Cave-Ayland 
6518baa1472SMark Cave-Ayland     case STAT_ST:
6528baa1472SMark Cave-Ayland         switch (s->rregs[ESP_CMD]) {
6538baa1472SMark Cave-Ayland         case CMD_ICCS | CMD_DMA:
6548baa1472SMark Cave-Ayland             len = MIN(len, 1);
6558baa1472SMark Cave-Ayland 
6568baa1472SMark Cave-Ayland             if (len) {
6578baa1472SMark Cave-Ayland                 buf[0] = s->status;
6588baa1472SMark Cave-Ayland 
6598baa1472SMark Cave-Ayland                 if (s->dma_memory_write) {
6608baa1472SMark Cave-Ayland                     s->dma_memory_write(s->dma_opaque, buf, len);
6618baa1472SMark Cave-Ayland                     esp_set_tc(s, esp_get_tc(s) - len);
6628baa1472SMark Cave-Ayland                 } else {
6638baa1472SMark Cave-Ayland                     fifo8_push_all(&s->fifo, buf, len);
6648baa1472SMark Cave-Ayland                     esp_set_tc(s, esp_get_tc(s) - len);
6658baa1472SMark Cave-Ayland                 }
6668baa1472SMark Cave-Ayland 
6678baa1472SMark Cave-Ayland                 esp_set_phase(s, STAT_MI);
6688baa1472SMark Cave-Ayland 
6698baa1472SMark Cave-Ayland                 if (esp_get_tc(s) > 0) {
6708baa1472SMark Cave-Ayland                     /* Process any message in phase data */
6718baa1472SMark Cave-Ayland                     esp_do_dma(s);
6728baa1472SMark Cave-Ayland                 }
6738baa1472SMark Cave-Ayland             }
6748baa1472SMark Cave-Ayland             break;
6758baa1472SMark Cave-Ayland         }
6768baa1472SMark Cave-Ayland         break;
6778baa1472SMark Cave-Ayland 
6788baa1472SMark Cave-Ayland     case STAT_MI:
6798baa1472SMark Cave-Ayland         switch (s->rregs[ESP_CMD]) {
6808baa1472SMark Cave-Ayland         case CMD_ICCS | CMD_DMA:
6818baa1472SMark Cave-Ayland             len = MIN(len, 1);
6828baa1472SMark Cave-Ayland 
6838baa1472SMark Cave-Ayland             if (len) {
6848baa1472SMark Cave-Ayland                 buf[0] = 0;
6858baa1472SMark Cave-Ayland 
6868baa1472SMark Cave-Ayland                 if (s->dma_memory_write) {
6878baa1472SMark Cave-Ayland                     s->dma_memory_write(s->dma_opaque, buf, len);
6888baa1472SMark Cave-Ayland                     esp_set_tc(s, esp_get_tc(s) - len);
6898baa1472SMark Cave-Ayland                 } else {
6908baa1472SMark Cave-Ayland                     fifo8_push_all(&s->fifo, buf, len);
6918baa1472SMark Cave-Ayland                     esp_set_tc(s, esp_get_tc(s) - len);
6928baa1472SMark Cave-Ayland                 }
6938baa1472SMark Cave-Ayland 
6948baa1472SMark Cave-Ayland                 /* Raise end of command interrupt */
6958baa1472SMark Cave-Ayland                 s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC;
6968baa1472SMark Cave-Ayland                 s->rregs[ESP_RSEQ] = SEQ_CD;
6978baa1472SMark Cave-Ayland                 esp_raise_irq(s);
6988baa1472SMark Cave-Ayland             }
6998baa1472SMark Cave-Ayland             break;
7008baa1472SMark Cave-Ayland         }
7018baa1472SMark Cave-Ayland         break;
70274d71ea1SLaurent Vivier     }
70349ab747fSPaolo Bonzini }
70449ab747fSPaolo Bonzini 
7051b9e48a5SMark Cave-Ayland static void esp_do_nodma(ESPState *s)
7061b9e48a5SMark Cave-Ayland {
7072572689bSMark Cave-Ayland     uint8_t buf[ESP_FIFO_SZ];
7087b320a8eSMark Cave-Ayland     uint32_t cmdlen;
7092572689bSMark Cave-Ayland     int len, n;
7101b9e48a5SMark Cave-Ayland 
71183e803deSMark Cave-Ayland     switch (esp_get_phase(s)) {
71283e803deSMark Cave-Ayland     case STAT_MO:
7132572689bSMark Cave-Ayland         /* Copy FIFO into cmdfifo */
7142572689bSMark Cave-Ayland         n = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
7152572689bSMark Cave-Ayland         n = MIN(fifo8_num_free(&s->cmdfifo), n);
7162572689bSMark Cave-Ayland         fifo8_push_all(&s->cmdfifo, buf, n);
71779a6c7c6SMark Cave-Ayland         s->cmdfifo_cdb_offset += n;
7182572689bSMark Cave-Ayland 
7191b9e48a5SMark Cave-Ayland         /*
7201b9e48a5SMark Cave-Ayland          * Extra message out bytes received: update cmdfifo_cdb_offset
7212cb40d44SStefan Weil          * and then switch to command phase
7221b9e48a5SMark Cave-Ayland          */
7231b9e48a5SMark Cave-Ayland         s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo);
724abc139cdSMark Cave-Ayland         esp_set_phase(s, STAT_CD);
7251b9e48a5SMark Cave-Ayland         s->rregs[ESP_RSEQ] = SEQ_CD;
7261b9e48a5SMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
7271b9e48a5SMark Cave-Ayland         esp_raise_irq(s);
72879a6c7c6SMark Cave-Ayland         break;
72979a6c7c6SMark Cave-Ayland 
73079a6c7c6SMark Cave-Ayland     case STAT_CD:
73179a6c7c6SMark Cave-Ayland         /* Copy FIFO into cmdfifo */
73279a6c7c6SMark Cave-Ayland         n = esp_fifo_pop_buf(&s->fifo, buf, fifo8_num_used(&s->fifo));
73379a6c7c6SMark Cave-Ayland         n = MIN(fifo8_num_free(&s->cmdfifo), n);
73479a6c7c6SMark Cave-Ayland         fifo8_push_all(&s->cmdfifo, buf, n);
73579a6c7c6SMark Cave-Ayland 
73679a6c7c6SMark Cave-Ayland         cmdlen = fifo8_num_used(&s->cmdfifo);
73779a6c7c6SMark Cave-Ayland         trace_esp_handle_ti_cmd(cmdlen);
73879a6c7c6SMark Cave-Ayland         s->ti_size = 0;
73979a6c7c6SMark Cave-Ayland 
74079a6c7c6SMark Cave-Ayland         /* No command received */
74179a6c7c6SMark Cave-Ayland         if (s->cmdfifo_cdb_offset == fifo8_num_used(&s->cmdfifo)) {
74279a6c7c6SMark Cave-Ayland             return;
7431b9e48a5SMark Cave-Ayland         }
74479a6c7c6SMark Cave-Ayland 
74579a6c7c6SMark Cave-Ayland         /* Command has been received */
74679a6c7c6SMark Cave-Ayland         do_cmd(s);
74783e803deSMark Cave-Ayland         break;
7481b9e48a5SMark Cave-Ayland 
7499d1aa52bSMark Cave-Ayland     case STAT_DO:
7500db89536SMark Cave-Ayland         if (!s->current_req) {
7510db89536SMark Cave-Ayland             return;
7520db89536SMark Cave-Ayland         }
7531b9e48a5SMark Cave-Ayland         if (s->async_len == 0) {
7541b9e48a5SMark Cave-Ayland             /* Defer until data is available.  */
7551b9e48a5SMark Cave-Ayland             return;
7561b9e48a5SMark Cave-Ayland         }
75777668e4bSMark Cave-Ayland         len = MIN(s->async_len, ESP_FIFO_SZ);
75877668e4bSMark Cave-Ayland         len = MIN(len, fifo8_num_used(&s->fifo));
7597b320a8eSMark Cave-Ayland         esp_fifo_pop_buf(&s->fifo, s->async_buf, len);
7601b9e48a5SMark Cave-Ayland         s->async_buf += len;
7611b9e48a5SMark Cave-Ayland         s->async_len -= len;
7621b9e48a5SMark Cave-Ayland         s->ti_size += len;
7639d1aa52bSMark Cave-Ayland 
7649d1aa52bSMark Cave-Ayland         if (s->async_len == 0) {
7659d1aa52bSMark Cave-Ayland             scsi_req_continue(s->current_req);
7669d1aa52bSMark Cave-Ayland             return;
7679d1aa52bSMark Cave-Ayland         }
7689d1aa52bSMark Cave-Ayland 
7699d1aa52bSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
7709d1aa52bSMark Cave-Ayland         esp_raise_irq(s);
7719d1aa52bSMark Cave-Ayland         break;
7729d1aa52bSMark Cave-Ayland 
7739d1aa52bSMark Cave-Ayland     case STAT_DI:
7749d1aa52bSMark Cave-Ayland         if (!s->current_req) {
7759d1aa52bSMark Cave-Ayland             return;
7769d1aa52bSMark Cave-Ayland         }
7779d1aa52bSMark Cave-Ayland         if (s->async_len == 0) {
7789d1aa52bSMark Cave-Ayland             /* Defer until data is available.  */
7799d1aa52bSMark Cave-Ayland             return;
7809d1aa52bSMark Cave-Ayland         }
7816ef2cabcSMark Cave-Ayland         if (fifo8_is_empty(&s->fifo)) {
7826ef2cabcSMark Cave-Ayland             fifo8_push(&s->fifo, s->async_buf[0]);
7836ef2cabcSMark Cave-Ayland             s->async_buf++;
7846ef2cabcSMark Cave-Ayland             s->async_len--;
7856ef2cabcSMark Cave-Ayland             s->ti_size--;
7866ef2cabcSMark Cave-Ayland         }
7871b9e48a5SMark Cave-Ayland 
7881b9e48a5SMark Cave-Ayland         if (s->async_len == 0) {
7891b9e48a5SMark Cave-Ayland             scsi_req_continue(s->current_req);
7901b9e48a5SMark Cave-Ayland             return;
7911b9e48a5SMark Cave-Ayland         }
7921b9e48a5SMark Cave-Ayland 
7931b9e48a5SMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
7941b9e48a5SMark Cave-Ayland         esp_raise_irq(s);
7959d1aa52bSMark Cave-Ayland         break;
7969d1aa52bSMark Cave-Ayland     }
7971b9e48a5SMark Cave-Ayland }
7981b9e48a5SMark Cave-Ayland 
7994aaa6ac3SMark Cave-Ayland void esp_command_complete(SCSIRequest *req, size_t resid)
80049ab747fSPaolo Bonzini {
8014aaa6ac3SMark Cave-Ayland     ESPState *s = req->hba_private;
8025a83e83eSMark Cave-Ayland     int to_device = (esp_get_phase(s) == STAT_DO);
8034aaa6ac3SMark Cave-Ayland 
80449ab747fSPaolo Bonzini     trace_esp_command_complete();
8056ef2cabcSMark Cave-Ayland 
8066ef2cabcSMark Cave-Ayland     /*
8076ef2cabcSMark Cave-Ayland      * Non-DMA transfers from the target will leave the last byte in
8086ef2cabcSMark Cave-Ayland      * the FIFO so don't reset ti_size in this case
8096ef2cabcSMark Cave-Ayland      */
8106ef2cabcSMark Cave-Ayland     if (s->dma || to_device) {
81149ab747fSPaolo Bonzini         if (s->ti_size != 0) {
81249ab747fSPaolo Bonzini             trace_esp_command_complete_unexpected();
81349ab747fSPaolo Bonzini         }
8146ef2cabcSMark Cave-Ayland     }
8156ef2cabcSMark Cave-Ayland 
81649ab747fSPaolo Bonzini     s->async_len = 0;
8174aaa6ac3SMark Cave-Ayland     if (req->status) {
81849ab747fSPaolo Bonzini         trace_esp_command_complete_fail();
81949ab747fSPaolo Bonzini     }
8204aaa6ac3SMark Cave-Ayland     s->status = req->status;
8216ef2cabcSMark Cave-Ayland 
8226ef2cabcSMark Cave-Ayland     /*
823cb988199SMark Cave-Ayland      * Switch to status phase. For non-DMA transfers from the target the last
824cb988199SMark Cave-Ayland      * byte is still in the FIFO
8256ef2cabcSMark Cave-Ayland      */
826abc139cdSMark Cave-Ayland     esp_set_phase(s, STAT_ST);
827cb988199SMark Cave-Ayland     if (s->ti_size == 0) {
828cb988199SMark Cave-Ayland         /*
829cb988199SMark Cave-Ayland          * Transfer complete: force TC to zero just in case a TI command was
830cb988199SMark Cave-Ayland          * requested for more data than the command returns (Solaris 8 does
831cb988199SMark Cave-Ayland          * this)
832cb988199SMark Cave-Ayland          */
833cb988199SMark Cave-Ayland         esp_set_tc(s, 0);
834004826d0SMark Cave-Ayland         esp_dma_ti_check(s);
835cb988199SMark Cave-Ayland     } else {
836cb988199SMark Cave-Ayland         /*
837cb988199SMark Cave-Ayland          * Transfer truncated: raise INTR_BS to indicate early change of
838cb988199SMark Cave-Ayland          * phase
839cb988199SMark Cave-Ayland          */
840cb988199SMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
841cb988199SMark Cave-Ayland         esp_raise_irq(s);
842cb988199SMark Cave-Ayland         s->ti_size = 0;
8436ef2cabcSMark Cave-Ayland     }
8446ef2cabcSMark Cave-Ayland 
84549ab747fSPaolo Bonzini     if (s->current_req) {
84649ab747fSPaolo Bonzini         scsi_req_unref(s->current_req);
84749ab747fSPaolo Bonzini         s->current_req = NULL;
84849ab747fSPaolo Bonzini         s->current_dev = NULL;
84949ab747fSPaolo Bonzini     }
85049ab747fSPaolo Bonzini }
85149ab747fSPaolo Bonzini 
85249ab747fSPaolo Bonzini void esp_transfer_data(SCSIRequest *req, uint32_t len)
85349ab747fSPaolo Bonzini {
85449ab747fSPaolo Bonzini     ESPState *s = req->hba_private;
8555a83e83eSMark Cave-Ayland     int to_device = (esp_get_phase(s) == STAT_DO);
8566cc88d6bSMark Cave-Ayland     uint32_t dmalen = esp_get_tc(s);
85749ab747fSPaolo Bonzini 
8586cc88d6bSMark Cave-Ayland     trace_esp_transfer_data(dmalen, s->ti_size);
85949ab747fSPaolo Bonzini     s->async_len = len;
86049ab747fSPaolo Bonzini     s->async_buf = scsi_req_get_buf(req);
8614e78f3bfSMark Cave-Ayland 
862*8dded6deSMark Cave-Ayland     if (!to_device && !s->data_ready) {
8634e78f3bfSMark Cave-Ayland         /*
8644e78f3bfSMark Cave-Ayland          * Initial incoming data xfer is complete so raise command
8654e78f3bfSMark Cave-Ayland          * completion interrupt
8664e78f3bfSMark Cave-Ayland          */
867*8dded6deSMark Cave-Ayland         s->data_ready = true;
8684e78f3bfSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_BS;
8694e78f3bfSMark Cave-Ayland         esp_raise_irq(s);
8704e78f3bfSMark Cave-Ayland     }
8714e78f3bfSMark Cave-Ayland 
8721b9e48a5SMark Cave-Ayland     /*
8731b9e48a5SMark Cave-Ayland      * Always perform the initial transfer upon reception of the next TI
8741b9e48a5SMark Cave-Ayland      * command to ensure the DMA/non-DMA status of the command is correct.
8751b9e48a5SMark Cave-Ayland      * It is not possible to use s->dma directly in the section below as
8761b9e48a5SMark Cave-Ayland      * some OSs send non-DMA NOP commands after a DMA transfer. Hence if the
8771b9e48a5SMark Cave-Ayland      * async data transfer is delayed then s->dma is set incorrectly.
8781b9e48a5SMark Cave-Ayland      */
8791b9e48a5SMark Cave-Ayland 
880880d3089SMark Cave-Ayland     if (s->ti_cmd == (CMD_TI | CMD_DMA)) {
881a79e767aSMark Cave-Ayland         /* When the SCSI layer returns more data, raise deferred INTR_BS */
882004826d0SMark Cave-Ayland         esp_dma_ti_check(s);
883a79e767aSMark Cave-Ayland 
884a79e767aSMark Cave-Ayland         esp_do_dma(s);
885880d3089SMark Cave-Ayland     } else if (s->ti_cmd == CMD_TI) {
8861b9e48a5SMark Cave-Ayland         esp_do_nodma(s);
8871b9e48a5SMark Cave-Ayland     }
88849ab747fSPaolo Bonzini }
88949ab747fSPaolo Bonzini 
89049ab747fSPaolo Bonzini static void handle_ti(ESPState *s)
89149ab747fSPaolo Bonzini {
8921b9e48a5SMark Cave-Ayland     uint32_t dmalen;
89349ab747fSPaolo Bonzini 
89449ab747fSPaolo Bonzini     if (s->dma && !s->dma_enabled) {
89549ab747fSPaolo Bonzini         s->dma_cb = handle_ti;
89649ab747fSPaolo Bonzini         return;
89749ab747fSPaolo Bonzini     }
89849ab747fSPaolo Bonzini 
8991b9e48a5SMark Cave-Ayland     s->ti_cmd = s->rregs[ESP_CMD];
90049ab747fSPaolo Bonzini     if (s->dma) {
9011b9e48a5SMark Cave-Ayland         dmalen = esp_get_tc(s);
902b76624deSMark Cave-Ayland         trace_esp_handle_ti(dmalen);
90349ab747fSPaolo Bonzini         esp_do_dma(s);
904799d90d8SMark Cave-Ayland     } else {
9051b9e48a5SMark Cave-Ayland         trace_esp_handle_ti(s->ti_size);
9061b9e48a5SMark Cave-Ayland         esp_do_nodma(s);
90749ab747fSPaolo Bonzini     }
90849ab747fSPaolo Bonzini }
90949ab747fSPaolo Bonzini 
91049ab747fSPaolo Bonzini void esp_hard_reset(ESPState *s)
91149ab747fSPaolo Bonzini {
91249ab747fSPaolo Bonzini     memset(s->rregs, 0, ESP_REGS);
91349ab747fSPaolo Bonzini     memset(s->wregs, 0, ESP_REGS);
914c9cf45c1SHannes Reinecke     s->tchi_written = 0;
91549ab747fSPaolo Bonzini     s->ti_size = 0;
9163f26c975SMark Cave-Ayland     s->async_len = 0;
917042879fcSMark Cave-Ayland     fifo8_reset(&s->fifo);
918023666daSMark Cave-Ayland     fifo8_reset(&s->cmdfifo);
91949ab747fSPaolo Bonzini     s->dma = 0;
92049ab747fSPaolo Bonzini     s->dma_cb = NULL;
92149ab747fSPaolo Bonzini 
92249ab747fSPaolo Bonzini     s->rregs[ESP_CFG1] = 7;
92349ab747fSPaolo Bonzini }
92449ab747fSPaolo Bonzini 
92549ab747fSPaolo Bonzini static void esp_soft_reset(ESPState *s)
92649ab747fSPaolo Bonzini {
92749ab747fSPaolo Bonzini     qemu_irq_lower(s->irq);
92874d71ea1SLaurent Vivier     qemu_irq_lower(s->irq_data);
92949ab747fSPaolo Bonzini     esp_hard_reset(s);
93049ab747fSPaolo Bonzini }
93149ab747fSPaolo Bonzini 
932c6e51f1bSJohn Millikin static void esp_bus_reset(ESPState *s)
933c6e51f1bSJohn Millikin {
9344a5fc890SPeter Maydell     bus_cold_reset(BUS(&s->bus));
935c6e51f1bSJohn Millikin }
936c6e51f1bSJohn Millikin 
93749ab747fSPaolo Bonzini static void parent_esp_reset(ESPState *s, int irq, int level)
93849ab747fSPaolo Bonzini {
93949ab747fSPaolo Bonzini     if (level) {
94049ab747fSPaolo Bonzini         esp_soft_reset(s);
94149ab747fSPaolo Bonzini     }
94249ab747fSPaolo Bonzini }
94349ab747fSPaolo Bonzini 
944f21fe39dSMark Cave-Ayland static void esp_run_cmd(ESPState *s)
945f21fe39dSMark Cave-Ayland {
946f21fe39dSMark Cave-Ayland     uint8_t cmd = s->rregs[ESP_CMD];
947f21fe39dSMark Cave-Ayland 
948f21fe39dSMark Cave-Ayland     if (cmd & CMD_DMA) {
949f21fe39dSMark Cave-Ayland         s->dma = 1;
950f21fe39dSMark Cave-Ayland         /* Reload DMA counter.  */
951f21fe39dSMark Cave-Ayland         if (esp_get_stc(s) == 0) {
952f21fe39dSMark Cave-Ayland             esp_set_tc(s, 0x10000);
953f21fe39dSMark Cave-Ayland         } else {
954f21fe39dSMark Cave-Ayland             esp_set_tc(s, esp_get_stc(s));
955f21fe39dSMark Cave-Ayland         }
956f21fe39dSMark Cave-Ayland     } else {
957f21fe39dSMark Cave-Ayland         s->dma = 0;
958f21fe39dSMark Cave-Ayland     }
959f21fe39dSMark Cave-Ayland     switch (cmd & CMD_CMD) {
960f21fe39dSMark Cave-Ayland     case CMD_NOP:
961f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_nop(cmd);
962f21fe39dSMark Cave-Ayland         break;
963f21fe39dSMark Cave-Ayland     case CMD_FLUSH:
964f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_flush(cmd);
965f21fe39dSMark Cave-Ayland         fifo8_reset(&s->fifo);
966f21fe39dSMark Cave-Ayland         break;
967f21fe39dSMark Cave-Ayland     case CMD_RESET:
968f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_reset(cmd);
969f21fe39dSMark Cave-Ayland         esp_soft_reset(s);
970f21fe39dSMark Cave-Ayland         break;
971f21fe39dSMark Cave-Ayland     case CMD_BUSRESET:
972f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_bus_reset(cmd);
973f21fe39dSMark Cave-Ayland         esp_bus_reset(s);
974f21fe39dSMark Cave-Ayland         if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
975f21fe39dSMark Cave-Ayland             s->rregs[ESP_RINTR] |= INTR_RST;
976f21fe39dSMark Cave-Ayland             esp_raise_irq(s);
977f21fe39dSMark Cave-Ayland         }
978f21fe39dSMark Cave-Ayland         break;
979f21fe39dSMark Cave-Ayland     case CMD_TI:
980f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_ti(cmd);
981f21fe39dSMark Cave-Ayland         handle_ti(s);
982f21fe39dSMark Cave-Ayland         break;
983f21fe39dSMark Cave-Ayland     case CMD_ICCS:
984f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_iccs(cmd);
985f21fe39dSMark Cave-Ayland         write_response(s);
986f21fe39dSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_FC;
987abc139cdSMark Cave-Ayland         esp_set_phase(s, STAT_MI);
988f21fe39dSMark Cave-Ayland         break;
989f21fe39dSMark Cave-Ayland     case CMD_MSGACC:
990f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_msgacc(cmd);
991f21fe39dSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_DC;
992f21fe39dSMark Cave-Ayland         s->rregs[ESP_RSEQ] = 0;
993f21fe39dSMark Cave-Ayland         s->rregs[ESP_RFLAGS] = 0;
994f21fe39dSMark Cave-Ayland         esp_raise_irq(s);
995f21fe39dSMark Cave-Ayland         break;
996f21fe39dSMark Cave-Ayland     case CMD_PAD:
997f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_pad(cmd);
998f21fe39dSMark Cave-Ayland         s->rregs[ESP_RSTAT] = STAT_TC;
999f21fe39dSMark Cave-Ayland         s->rregs[ESP_RINTR] |= INTR_FC;
1000f21fe39dSMark Cave-Ayland         s->rregs[ESP_RSEQ] = 0;
1001f21fe39dSMark Cave-Ayland         break;
1002f21fe39dSMark Cave-Ayland     case CMD_SATN:
1003f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_satn(cmd);
1004f21fe39dSMark Cave-Ayland         break;
1005f21fe39dSMark Cave-Ayland     case CMD_RSTATN:
1006f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_rstatn(cmd);
1007f21fe39dSMark Cave-Ayland         break;
1008f21fe39dSMark Cave-Ayland     case CMD_SEL:
1009f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_sel(cmd);
1010f21fe39dSMark Cave-Ayland         handle_s_without_atn(s);
1011f21fe39dSMark Cave-Ayland         break;
1012f21fe39dSMark Cave-Ayland     case CMD_SELATN:
1013f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_selatn(cmd);
1014f21fe39dSMark Cave-Ayland         handle_satn(s);
1015f21fe39dSMark Cave-Ayland         break;
1016f21fe39dSMark Cave-Ayland     case CMD_SELATNS:
1017f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_selatns(cmd);
1018f21fe39dSMark Cave-Ayland         handle_satn_stop(s);
1019f21fe39dSMark Cave-Ayland         break;
1020f21fe39dSMark Cave-Ayland     case CMD_ENSEL:
1021f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_ensel(cmd);
1022f21fe39dSMark Cave-Ayland         s->rregs[ESP_RINTR] = 0;
1023f21fe39dSMark Cave-Ayland         break;
1024f21fe39dSMark Cave-Ayland     case CMD_DISSEL:
1025f21fe39dSMark Cave-Ayland         trace_esp_mem_writeb_cmd_dissel(cmd);
1026f21fe39dSMark Cave-Ayland         s->rregs[ESP_RINTR] = 0;
1027f21fe39dSMark Cave-Ayland         esp_raise_irq(s);
1028f21fe39dSMark Cave-Ayland         break;
1029f21fe39dSMark Cave-Ayland     default:
1030f21fe39dSMark Cave-Ayland         trace_esp_error_unhandled_command(cmd);
1031f21fe39dSMark Cave-Ayland         break;
1032f21fe39dSMark Cave-Ayland     }
1033f21fe39dSMark Cave-Ayland }
1034f21fe39dSMark Cave-Ayland 
103549ab747fSPaolo Bonzini uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
103649ab747fSPaolo Bonzini {
1037b630c075SMark Cave-Ayland     uint32_t val;
103849ab747fSPaolo Bonzini 
103949ab747fSPaolo Bonzini     switch (saddr) {
104049ab747fSPaolo Bonzini     case ESP_FIFO:
10411b9e48a5SMark Cave-Ayland         if (s->dma_memory_read && s->dma_memory_write &&
10421b9e48a5SMark Cave-Ayland                 (s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
104349ab747fSPaolo Bonzini             /* Data out.  */
1044ff589551SPrasad J Pandit             qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
104549ab747fSPaolo Bonzini             s->rregs[ESP_FIFO] = 0;
1046042879fcSMark Cave-Ayland         } else {
10475a83e83eSMark Cave-Ayland             if (esp_get_phase(s) == STAT_DI) {
10486ef2cabcSMark Cave-Ayland                 if (s->ti_size) {
10496ef2cabcSMark Cave-Ayland                     esp_do_nodma(s);
10506ef2cabcSMark Cave-Ayland                 } else {
10516ef2cabcSMark Cave-Ayland                     /*
10526ef2cabcSMark Cave-Ayland                      * The last byte of a non-DMA transfer has been read out
10536ef2cabcSMark Cave-Ayland                      * of the FIFO so switch to status phase
10546ef2cabcSMark Cave-Ayland                      */
1055abc139cdSMark Cave-Ayland                     esp_set_phase(s, STAT_ST);
10566ef2cabcSMark Cave-Ayland                 }
10576ef2cabcSMark Cave-Ayland             }
1058c5fef911SMark Cave-Ayland             s->rregs[ESP_FIFO] = esp_fifo_pop(&s->fifo);
105949ab747fSPaolo Bonzini         }
1060b630c075SMark Cave-Ayland         val = s->rregs[ESP_FIFO];
106149ab747fSPaolo Bonzini         break;
106249ab747fSPaolo Bonzini     case ESP_RINTR:
106394d5c79dSMark Cave-Ayland         /*
106494d5c79dSMark Cave-Ayland          * Clear sequence step, interrupt register and all status bits
106594d5c79dSMark Cave-Ayland          * except TC
106694d5c79dSMark Cave-Ayland          */
1067b630c075SMark Cave-Ayland         val = s->rregs[ESP_RINTR];
106849ab747fSPaolo Bonzini         s->rregs[ESP_RINTR] = 0;
106949ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_TC;
1070af947a3dSMark Cave-Ayland         /*
1071af947a3dSMark Cave-Ayland          * According to the datasheet ESP_RSEQ should be cleared, but as the
1072af947a3dSMark Cave-Ayland          * emulation currently defers information transfers to the next TI
1073af947a3dSMark Cave-Ayland          * command leave it for now so that pedantic guests such as the old
1074af947a3dSMark Cave-Ayland          * Linux 2.6 driver see the correct flags before the next SCSI phase
1075af947a3dSMark Cave-Ayland          * transition.
1076af947a3dSMark Cave-Ayland          *
1077af947a3dSMark Cave-Ayland          * s->rregs[ESP_RSEQ] = SEQ_0;
1078af947a3dSMark Cave-Ayland          */
107949ab747fSPaolo Bonzini         esp_lower_irq(s);
1080b630c075SMark Cave-Ayland         break;
1081c9cf45c1SHannes Reinecke     case ESP_TCHI:
1082c9cf45c1SHannes Reinecke         /* Return the unique id if the value has never been written */
1083c9cf45c1SHannes Reinecke         if (!s->tchi_written) {
1084b630c075SMark Cave-Ayland             val = s->chip_id;
1085b630c075SMark Cave-Ayland         } else {
1086b630c075SMark Cave-Ayland             val = s->rregs[saddr];
1087c9cf45c1SHannes Reinecke         }
1088b630c075SMark Cave-Ayland         break;
1089238ec4d7SMark Cave-Ayland      case ESP_RFLAGS:
1090238ec4d7SMark Cave-Ayland         /* Bottom 5 bits indicate number of bytes in FIFO */
1091238ec4d7SMark Cave-Ayland         val = fifo8_num_used(&s->fifo);
1092238ec4d7SMark Cave-Ayland         break;
109349ab747fSPaolo Bonzini     default:
1094b630c075SMark Cave-Ayland         val = s->rregs[saddr];
109549ab747fSPaolo Bonzini         break;
109649ab747fSPaolo Bonzini     }
1097b630c075SMark Cave-Ayland 
1098b630c075SMark Cave-Ayland     trace_esp_mem_readb(saddr, val);
1099b630c075SMark Cave-Ayland     return val;
110049ab747fSPaolo Bonzini }
110149ab747fSPaolo Bonzini 
110249ab747fSPaolo Bonzini void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
110349ab747fSPaolo Bonzini {
110449ab747fSPaolo Bonzini     trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
110549ab747fSPaolo Bonzini     switch (saddr) {
1106c9cf45c1SHannes Reinecke     case ESP_TCHI:
1107c9cf45c1SHannes Reinecke         s->tchi_written = true;
1108c9cf45c1SHannes Reinecke         /* fall through */
110949ab747fSPaolo Bonzini     case ESP_TCLO:
111049ab747fSPaolo Bonzini     case ESP_TCMID:
111149ab747fSPaolo Bonzini         s->rregs[ESP_RSTAT] &= ~STAT_TC;
111249ab747fSPaolo Bonzini         break;
111349ab747fSPaolo Bonzini     case ESP_FIFO:
1114df91fd4eSMark Cave-Ayland         if (esp_get_phase(s) == STAT_MO || esp_get_phase(s) == STAT_CD) {
11152572689bSMark Cave-Ayland             if (!fifo8_is_full(&s->fifo)) {
11162572689bSMark Cave-Ayland                 esp_fifo_push(&s->fifo, val);
11172572689bSMark Cave-Ayland                 esp_fifo_push(&s->cmdfifo, fifo8_pop(&s->fifo));
11182572689bSMark Cave-Ayland             }
11196ef2cabcSMark Cave-Ayland 
11206ef2cabcSMark Cave-Ayland             /*
11216ef2cabcSMark Cave-Ayland              * If any unexpected message out/command phase data is
11226ef2cabcSMark Cave-Ayland              * transferred using non-DMA, raise the interrupt
11236ef2cabcSMark Cave-Ayland              */
11246ef2cabcSMark Cave-Ayland             if (s->rregs[ESP_CMD] == CMD_TI) {
11256ef2cabcSMark Cave-Ayland                 s->rregs[ESP_RINTR] |= INTR_BS;
11266ef2cabcSMark Cave-Ayland                 esp_raise_irq(s);
11276ef2cabcSMark Cave-Ayland             }
112849ab747fSPaolo Bonzini         } else {
1129e5455b8cSMark Cave-Ayland             esp_fifo_push(&s->fifo, val);
113049ab747fSPaolo Bonzini         }
113149ab747fSPaolo Bonzini         break;
113249ab747fSPaolo Bonzini     case ESP_CMD:
113349ab747fSPaolo Bonzini         s->rregs[saddr] = val;
1134f21fe39dSMark Cave-Ayland         esp_run_cmd(s);
113549ab747fSPaolo Bonzini         break;
113649ab747fSPaolo Bonzini     case ESP_WBUSID ... ESP_WSYNO:
113749ab747fSPaolo Bonzini         break;
113849ab747fSPaolo Bonzini     case ESP_CFG1:
113949ab747fSPaolo Bonzini     case ESP_CFG2: case ESP_CFG3:
114049ab747fSPaolo Bonzini     case ESP_RES3: case ESP_RES4:
114149ab747fSPaolo Bonzini         s->rregs[saddr] = val;
114249ab747fSPaolo Bonzini         break;
114349ab747fSPaolo Bonzini     case ESP_WCCF ... ESP_WTEST:
114449ab747fSPaolo Bonzini         break;
114549ab747fSPaolo Bonzini     default:
114649ab747fSPaolo Bonzini         trace_esp_error_invalid_write(val, saddr);
114749ab747fSPaolo Bonzini         return;
114849ab747fSPaolo Bonzini     }
114949ab747fSPaolo Bonzini     s->wregs[saddr] = val;
115049ab747fSPaolo Bonzini }
115149ab747fSPaolo Bonzini 
115249ab747fSPaolo Bonzini static bool esp_mem_accepts(void *opaque, hwaddr addr,
11538372d383SPeter Maydell                             unsigned size, bool is_write,
11548372d383SPeter Maydell                             MemTxAttrs attrs)
115549ab747fSPaolo Bonzini {
115649ab747fSPaolo Bonzini     return (size == 1) || (is_write && size == 4);
115749ab747fSPaolo Bonzini }
115849ab747fSPaolo Bonzini 
11596cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id)
11606cc88d6bSMark Cave-Ayland {
11616cc88d6bSMark Cave-Ayland     ESPState *s = ESP(opaque);
11626cc88d6bSMark Cave-Ayland 
11636cc88d6bSMark Cave-Ayland     version_id = MIN(version_id, s->mig_version_id);
11646cc88d6bSMark Cave-Ayland     return version_id < 5;
11656cc88d6bSMark Cave-Ayland }
11666cc88d6bSMark Cave-Ayland 
11674e78f3bfSMark Cave-Ayland static bool esp_is_version_5(void *opaque, int version_id)
11684e78f3bfSMark Cave-Ayland {
11694e78f3bfSMark Cave-Ayland     ESPState *s = ESP(opaque);
11704e78f3bfSMark Cave-Ayland 
11714e78f3bfSMark Cave-Ayland     version_id = MIN(version_id, s->mig_version_id);
11720bcd5a18SMark Cave-Ayland     return version_id >= 5;
11734e78f3bfSMark Cave-Ayland }
11744e78f3bfSMark Cave-Ayland 
11754eb86065SPaolo Bonzini static bool esp_is_version_6(void *opaque, int version_id)
11764eb86065SPaolo Bonzini {
11774eb86065SPaolo Bonzini     ESPState *s = ESP(opaque);
11784eb86065SPaolo Bonzini 
11794eb86065SPaolo Bonzini     version_id = MIN(version_id, s->mig_version_id);
11804eb86065SPaolo Bonzini     return version_id >= 6;
11814eb86065SPaolo Bonzini }
11824eb86065SPaolo Bonzini 
1183ff4a1dabSMark Cave-Ayland int esp_pre_save(void *opaque)
11840bd005beSMark Cave-Ayland {
1185ff4a1dabSMark Cave-Ayland     ESPState *s = ESP(object_resolve_path_component(
1186ff4a1dabSMark Cave-Ayland                       OBJECT(opaque), "esp"));
11870bd005beSMark Cave-Ayland 
11880bd005beSMark Cave-Ayland     s->mig_version_id = vmstate_esp.version_id;
11890bd005beSMark Cave-Ayland     return 0;
11900bd005beSMark Cave-Ayland }
11910bd005beSMark Cave-Ayland 
11920bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id)
11930bd005beSMark Cave-Ayland {
11940bd005beSMark Cave-Ayland     ESPState *s = ESP(opaque);
1195042879fcSMark Cave-Ayland     int len, i;
11960bd005beSMark Cave-Ayland 
11976cc88d6bSMark Cave-Ayland     version_id = MIN(version_id, s->mig_version_id);
11986cc88d6bSMark Cave-Ayland 
11996cc88d6bSMark Cave-Ayland     if (version_id < 5) {
12006cc88d6bSMark Cave-Ayland         esp_set_tc(s, s->mig_dma_left);
1201042879fcSMark Cave-Ayland 
1202042879fcSMark Cave-Ayland         /* Migrate ti_buf to fifo */
1203042879fcSMark Cave-Ayland         len = s->mig_ti_wptr - s->mig_ti_rptr;
1204042879fcSMark Cave-Ayland         for (i = 0; i < len; i++) {
1205042879fcSMark Cave-Ayland             fifo8_push(&s->fifo, s->mig_ti_buf[i]);
1206042879fcSMark Cave-Ayland         }
1207023666daSMark Cave-Ayland 
1208023666daSMark Cave-Ayland         /* Migrate cmdbuf to cmdfifo */
1209023666daSMark Cave-Ayland         for (i = 0; i < s->mig_cmdlen; i++) {
1210023666daSMark Cave-Ayland             fifo8_push(&s->cmdfifo, s->mig_cmdbuf[i]);
1211023666daSMark Cave-Ayland         }
12126cc88d6bSMark Cave-Ayland     }
12136cc88d6bSMark Cave-Ayland 
12140bd005beSMark Cave-Ayland     s->mig_version_id = vmstate_esp.version_id;
12150bd005beSMark Cave-Ayland     return 0;
12160bd005beSMark Cave-Ayland }
12170bd005beSMark Cave-Ayland 
121849ab747fSPaolo Bonzini const VMStateDescription vmstate_esp = {
121949ab747fSPaolo Bonzini     .name = "esp",
12204eb86065SPaolo Bonzini     .version_id = 6,
122149ab747fSPaolo Bonzini     .minimum_version_id = 3,
12220bd005beSMark Cave-Ayland     .post_load = esp_post_load,
12232d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
122449ab747fSPaolo Bonzini         VMSTATE_BUFFER(rregs, ESPState),
122549ab747fSPaolo Bonzini         VMSTATE_BUFFER(wregs, ESPState),
122649ab747fSPaolo Bonzini         VMSTATE_INT32(ti_size, ESPState),
1227042879fcSMark Cave-Ayland         VMSTATE_UINT32_TEST(mig_ti_rptr, ESPState, esp_is_before_version_5),
1228042879fcSMark Cave-Ayland         VMSTATE_UINT32_TEST(mig_ti_wptr, ESPState, esp_is_before_version_5),
1229042879fcSMark Cave-Ayland         VMSTATE_BUFFER_TEST(mig_ti_buf, ESPState, esp_is_before_version_5),
123049ab747fSPaolo Bonzini         VMSTATE_UINT32(status, ESPState),
12314aaa6ac3SMark Cave-Ayland         VMSTATE_UINT32_TEST(mig_deferred_status, ESPState,
12324aaa6ac3SMark Cave-Ayland                             esp_is_before_version_5),
12334aaa6ac3SMark Cave-Ayland         VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState,
12344aaa6ac3SMark Cave-Ayland                           esp_is_before_version_5),
123549ab747fSPaolo Bonzini         VMSTATE_UINT32(dma, ESPState),
1236023666daSMark Cave-Ayland         VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 0,
1237023666daSMark Cave-Ayland                               esp_is_before_version_5, 0, 16),
1238023666daSMark Cave-Ayland         VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 4,
1239023666daSMark Cave-Ayland                               esp_is_before_version_5, 16,
1240023666daSMark Cave-Ayland                               sizeof(typeof_field(ESPState, mig_cmdbuf))),
1241023666daSMark Cave-Ayland         VMSTATE_UINT32_TEST(mig_cmdlen, ESPState, esp_is_before_version_5),
124249ab747fSPaolo Bonzini         VMSTATE_UINT32(do_cmd, ESPState),
12436cc88d6bSMark Cave-Ayland         VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5),
1244*8dded6deSMark Cave-Ayland         VMSTATE_BOOL_TEST(data_ready, ESPState, esp_is_version_5),
1245023666daSMark Cave-Ayland         VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5),
1246042879fcSMark Cave-Ayland         VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5),
1247023666daSMark Cave-Ayland         VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5),
12481b9e48a5SMark Cave-Ayland         VMSTATE_UINT8_TEST(ti_cmd, ESPState, esp_is_version_5),
12494eb86065SPaolo Bonzini         VMSTATE_UINT8_TEST(lun, ESPState, esp_is_version_6),
125049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
125174d71ea1SLaurent Vivier     },
125249ab747fSPaolo Bonzini };
125349ab747fSPaolo Bonzini 
125449ab747fSPaolo Bonzini static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
125549ab747fSPaolo Bonzini                                  uint64_t val, unsigned int size)
125649ab747fSPaolo Bonzini {
125749ab747fSPaolo Bonzini     SysBusESPState *sysbus = opaque;
1258eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
125949ab747fSPaolo Bonzini     uint32_t saddr;
126049ab747fSPaolo Bonzini 
126149ab747fSPaolo Bonzini     saddr = addr >> sysbus->it_shift;
1262eb169c76SMark Cave-Ayland     esp_reg_write(s, saddr, val);
126349ab747fSPaolo Bonzini }
126449ab747fSPaolo Bonzini 
126549ab747fSPaolo Bonzini static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
126649ab747fSPaolo Bonzini                                     unsigned int size)
126749ab747fSPaolo Bonzini {
126849ab747fSPaolo Bonzini     SysBusESPState *sysbus = opaque;
1269eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
127049ab747fSPaolo Bonzini     uint32_t saddr;
127149ab747fSPaolo Bonzini 
127249ab747fSPaolo Bonzini     saddr = addr >> sysbus->it_shift;
1273eb169c76SMark Cave-Ayland     return esp_reg_read(s, saddr);
127449ab747fSPaolo Bonzini }
127549ab747fSPaolo Bonzini 
127649ab747fSPaolo Bonzini static const MemoryRegionOps sysbus_esp_mem_ops = {
127749ab747fSPaolo Bonzini     .read = sysbus_esp_mem_read,
127849ab747fSPaolo Bonzini     .write = sysbus_esp_mem_write,
127949ab747fSPaolo Bonzini     .endianness = DEVICE_NATIVE_ENDIAN,
128049ab747fSPaolo Bonzini     .valid.accepts = esp_mem_accepts,
128149ab747fSPaolo Bonzini };
128249ab747fSPaolo Bonzini 
128374d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr,
128474d71ea1SLaurent Vivier                                   uint64_t val, unsigned int size)
128574d71ea1SLaurent Vivier {
128674d71ea1SLaurent Vivier     SysBusESPState *sysbus = opaque;
1287eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
128874d71ea1SLaurent Vivier 
1289960ebfd9SMark Cave-Ayland     trace_esp_pdma_write(size);
1290960ebfd9SMark Cave-Ayland 
129174d71ea1SLaurent Vivier     switch (size) {
129274d71ea1SLaurent Vivier     case 1:
1293761bef75SMark Cave-Ayland         esp_pdma_write(s, val);
129474d71ea1SLaurent Vivier         break;
129574d71ea1SLaurent Vivier     case 2:
1296761bef75SMark Cave-Ayland         esp_pdma_write(s, val >> 8);
1297761bef75SMark Cave-Ayland         esp_pdma_write(s, val);
129874d71ea1SLaurent Vivier         break;
129974d71ea1SLaurent Vivier     }
1300b46a43a2SMark Cave-Ayland     esp_do_dma(s);
130174d71ea1SLaurent Vivier }
130274d71ea1SLaurent Vivier 
130374d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr,
130474d71ea1SLaurent Vivier                                      unsigned int size)
130574d71ea1SLaurent Vivier {
130674d71ea1SLaurent Vivier     SysBusESPState *sysbus = opaque;
1307eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
130874d71ea1SLaurent Vivier     uint64_t val = 0;
130974d71ea1SLaurent Vivier 
1310960ebfd9SMark Cave-Ayland     trace_esp_pdma_read(size);
1311960ebfd9SMark Cave-Ayland 
131274d71ea1SLaurent Vivier     switch (size) {
131374d71ea1SLaurent Vivier     case 1:
1314761bef75SMark Cave-Ayland         val = esp_pdma_read(s);
131574d71ea1SLaurent Vivier         break;
131674d71ea1SLaurent Vivier     case 2:
1317761bef75SMark Cave-Ayland         val = esp_pdma_read(s);
1318761bef75SMark Cave-Ayland         val = (val << 8) | esp_pdma_read(s);
131974d71ea1SLaurent Vivier         break;
132074d71ea1SLaurent Vivier     }
1321b46a43a2SMark Cave-Ayland     esp_do_dma(s);
132274d71ea1SLaurent Vivier     return val;
132374d71ea1SLaurent Vivier }
132474d71ea1SLaurent Vivier 
1325a7a22088SMark Cave-Ayland static void *esp_load_request(QEMUFile *f, SCSIRequest *req)
1326a7a22088SMark Cave-Ayland {
1327a7a22088SMark Cave-Ayland     ESPState *s = container_of(req->bus, ESPState, bus);
1328a7a22088SMark Cave-Ayland 
1329a7a22088SMark Cave-Ayland     scsi_req_ref(req);
1330a7a22088SMark Cave-Ayland     s->current_req = req;
1331a7a22088SMark Cave-Ayland     return s;
1332a7a22088SMark Cave-Ayland }
1333a7a22088SMark Cave-Ayland 
133474d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = {
133574d71ea1SLaurent Vivier     .read = sysbus_esp_pdma_read,
133674d71ea1SLaurent Vivier     .write = sysbus_esp_pdma_write,
133774d71ea1SLaurent Vivier     .endianness = DEVICE_NATIVE_ENDIAN,
133874d71ea1SLaurent Vivier     .valid.min_access_size = 1,
1339cf1b8286SMark Cave-Ayland     .valid.max_access_size = 4,
1340cf1b8286SMark Cave-Ayland     .impl.min_access_size = 1,
1341cf1b8286SMark Cave-Ayland     .impl.max_access_size = 2,
134274d71ea1SLaurent Vivier };
134374d71ea1SLaurent Vivier 
134449ab747fSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = {
134549ab747fSPaolo Bonzini     .tcq = false,
134649ab747fSPaolo Bonzini     .max_target = ESP_MAX_DEVS,
134749ab747fSPaolo Bonzini     .max_lun = 7,
134849ab747fSPaolo Bonzini 
1349a7a22088SMark Cave-Ayland     .load_request = esp_load_request,
135049ab747fSPaolo Bonzini     .transfer_data = esp_transfer_data,
135149ab747fSPaolo Bonzini     .complete = esp_command_complete,
135249ab747fSPaolo Bonzini     .cancel = esp_request_cancelled
135349ab747fSPaolo Bonzini };
135449ab747fSPaolo Bonzini 
135549ab747fSPaolo Bonzini static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
135649ab747fSPaolo Bonzini {
135784fbefedSMark Cave-Ayland     SysBusESPState *sysbus = SYSBUS_ESP(opaque);
1358eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
135949ab747fSPaolo Bonzini 
136049ab747fSPaolo Bonzini     switch (irq) {
136149ab747fSPaolo Bonzini     case 0:
136249ab747fSPaolo Bonzini         parent_esp_reset(s, irq, level);
136349ab747fSPaolo Bonzini         break;
136449ab747fSPaolo Bonzini     case 1:
1365b86dc5cbSMark Cave-Ayland         esp_dma_enable(s, irq, level);
136649ab747fSPaolo Bonzini         break;
136749ab747fSPaolo Bonzini     }
136849ab747fSPaolo Bonzini }
136949ab747fSPaolo Bonzini 
1370b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp)
137149ab747fSPaolo Bonzini {
1372b09318caSHu Tao     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
137384fbefedSMark Cave-Ayland     SysBusESPState *sysbus = SYSBUS_ESP(dev);
1374eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
1375eb169c76SMark Cave-Ayland 
1376eb169c76SMark Cave-Ayland     if (!qdev_realize(DEVICE(s), NULL, errp)) {
1377eb169c76SMark Cave-Ayland         return;
1378eb169c76SMark Cave-Ayland     }
137949ab747fSPaolo Bonzini 
1380b09318caSHu Tao     sysbus_init_irq(sbd, &s->irq);
138174d71ea1SLaurent Vivier     sysbus_init_irq(sbd, &s->irq_data);
138249ab747fSPaolo Bonzini     assert(sysbus->it_shift != -1);
138349ab747fSPaolo Bonzini 
138449ab747fSPaolo Bonzini     s->chip_id = TCHI_FAS100A;
138529776739SPaolo Bonzini     memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops,
138674d71ea1SLaurent Vivier                           sysbus, "esp-regs", ESP_REGS << sysbus->it_shift);
1387b09318caSHu Tao     sysbus_init_mmio(sbd, &sysbus->iomem);
138874d71ea1SLaurent Vivier     memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops,
1389cf1b8286SMark Cave-Ayland                           sysbus, "esp-pdma", 4);
139074d71ea1SLaurent Vivier     sysbus_init_mmio(sbd, &sysbus->pdma);
139149ab747fSPaolo Bonzini 
1392b09318caSHu Tao     qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
139349ab747fSPaolo Bonzini 
1394739e95f5SPeter Maydell     scsi_bus_init(&s->bus, sizeof(s->bus), dev, &esp_scsi_info);
139549ab747fSPaolo Bonzini }
139649ab747fSPaolo Bonzini 
139749ab747fSPaolo Bonzini static void sysbus_esp_hard_reset(DeviceState *dev)
139849ab747fSPaolo Bonzini {
139984fbefedSMark Cave-Ayland     SysBusESPState *sysbus = SYSBUS_ESP(dev);
1400eb169c76SMark Cave-Ayland     ESPState *s = ESP(&sysbus->esp);
1401eb169c76SMark Cave-Ayland 
1402eb169c76SMark Cave-Ayland     esp_hard_reset(s);
1403eb169c76SMark Cave-Ayland }
1404eb169c76SMark Cave-Ayland 
1405eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj)
1406eb169c76SMark Cave-Ayland {
1407eb169c76SMark Cave-Ayland     SysBusESPState *sysbus = SYSBUS_ESP(obj);
1408eb169c76SMark Cave-Ayland 
1409eb169c76SMark Cave-Ayland     object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP);
141049ab747fSPaolo Bonzini }
141149ab747fSPaolo Bonzini 
141249ab747fSPaolo Bonzini static const VMStateDescription vmstate_sysbus_esp_scsi = {
141349ab747fSPaolo Bonzini     .name = "sysbusespscsi",
14140bd005beSMark Cave-Ayland     .version_id = 2,
1415ea84a442SGuenter Roeck     .minimum_version_id = 1,
1416ff4a1dabSMark Cave-Ayland     .pre_save = esp_pre_save,
14172d7b39a6SRichard Henderson     .fields = (const VMStateField[]) {
14180bd005beSMark Cave-Ayland         VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2),
141949ab747fSPaolo Bonzini         VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
142049ab747fSPaolo Bonzini         VMSTATE_END_OF_LIST()
142149ab747fSPaolo Bonzini     }
142249ab747fSPaolo Bonzini };
142349ab747fSPaolo Bonzini 
142449ab747fSPaolo Bonzini static void sysbus_esp_class_init(ObjectClass *klass, void *data)
142549ab747fSPaolo Bonzini {
142649ab747fSPaolo Bonzini     DeviceClass *dc = DEVICE_CLASS(klass);
142749ab747fSPaolo Bonzini 
1428b09318caSHu Tao     dc->realize = sysbus_esp_realize;
142949ab747fSPaolo Bonzini     dc->reset = sysbus_esp_hard_reset;
143049ab747fSPaolo Bonzini     dc->vmsd = &vmstate_sysbus_esp_scsi;
1431125ee0edSMarcel Apfelbaum     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
143249ab747fSPaolo Bonzini }
143349ab747fSPaolo Bonzini 
143449ab747fSPaolo Bonzini static const TypeInfo sysbus_esp_info = {
143584fbefedSMark Cave-Ayland     .name          = TYPE_SYSBUS_ESP,
143649ab747fSPaolo Bonzini     .parent        = TYPE_SYS_BUS_DEVICE,
1437eb169c76SMark Cave-Ayland     .instance_init = sysbus_esp_init,
143849ab747fSPaolo Bonzini     .instance_size = sizeof(SysBusESPState),
143949ab747fSPaolo Bonzini     .class_init    = sysbus_esp_class_init,
144049ab747fSPaolo Bonzini };
144149ab747fSPaolo Bonzini 
1442042879fcSMark Cave-Ayland static void esp_finalize(Object *obj)
1443042879fcSMark Cave-Ayland {
1444042879fcSMark Cave-Ayland     ESPState *s = ESP(obj);
1445042879fcSMark Cave-Ayland 
1446042879fcSMark Cave-Ayland     fifo8_destroy(&s->fifo);
1447023666daSMark Cave-Ayland     fifo8_destroy(&s->cmdfifo);
1448042879fcSMark Cave-Ayland }
1449042879fcSMark Cave-Ayland 
1450042879fcSMark Cave-Ayland static void esp_init(Object *obj)
1451042879fcSMark Cave-Ayland {
1452042879fcSMark Cave-Ayland     ESPState *s = ESP(obj);
1453042879fcSMark Cave-Ayland 
1454042879fcSMark Cave-Ayland     fifo8_create(&s->fifo, ESP_FIFO_SZ);
1455023666daSMark Cave-Ayland     fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ);
1456042879fcSMark Cave-Ayland }
1457042879fcSMark Cave-Ayland 
1458eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data)
1459eb169c76SMark Cave-Ayland {
1460eb169c76SMark Cave-Ayland     DeviceClass *dc = DEVICE_CLASS(klass);
1461eb169c76SMark Cave-Ayland 
1462eb169c76SMark Cave-Ayland     /* internal device for sysbusesp/pciespscsi, not user-creatable */
1463eb169c76SMark Cave-Ayland     dc->user_creatable = false;
1464eb169c76SMark Cave-Ayland     set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
1465eb169c76SMark Cave-Ayland }
1466eb169c76SMark Cave-Ayland 
1467eb169c76SMark Cave-Ayland static const TypeInfo esp_info = {
1468eb169c76SMark Cave-Ayland     .name = TYPE_ESP,
1469eb169c76SMark Cave-Ayland     .parent = TYPE_DEVICE,
1470042879fcSMark Cave-Ayland     .instance_init = esp_init,
1471042879fcSMark Cave-Ayland     .instance_finalize = esp_finalize,
1472eb169c76SMark Cave-Ayland     .instance_size = sizeof(ESPState),
1473eb169c76SMark Cave-Ayland     .class_init = esp_class_init,
1474eb169c76SMark Cave-Ayland };
1475eb169c76SMark Cave-Ayland 
147649ab747fSPaolo Bonzini static void esp_register_types(void)
147749ab747fSPaolo Bonzini {
147849ab747fSPaolo Bonzini     type_register_static(&sysbus_esp_info);
1479eb169c76SMark Cave-Ayland     type_register_static(&esp_info);
148049ab747fSPaolo Bonzini }
148149ab747fSPaolo Bonzini 
148249ab747fSPaolo Bonzini type_init(esp_register_types)
1483