16f7e9aecSbellard /* 267e999beSbellard * QEMU ESP/NCR53C9x emulation 36f7e9aecSbellard * 44e9aec74Spbrook * Copyright (c) 2005-2006 Fabrice Bellard 5fabaaf1dSHervé Poussineau * Copyright (c) 2012 Herve Poussineau 678d68f31SMark Cave-Ayland * Copyright (c) 2023 Mark Cave-Ayland 76f7e9aecSbellard * 86f7e9aecSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 96f7e9aecSbellard * of this software and associated documentation files (the "Software"), to deal 106f7e9aecSbellard * in the Software without restriction, including without limitation the rights 116f7e9aecSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 126f7e9aecSbellard * copies of the Software, and to permit persons to whom the Software is 136f7e9aecSbellard * furnished to do so, subject to the following conditions: 146f7e9aecSbellard * 156f7e9aecSbellard * The above copyright notice and this permission notice shall be included in 166f7e9aecSbellard * all copies or substantial portions of the Software. 176f7e9aecSbellard * 186f7e9aecSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 196f7e9aecSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 206f7e9aecSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 216f7e9aecSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 226f7e9aecSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 236f7e9aecSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 246f7e9aecSbellard * THE SOFTWARE. 256f7e9aecSbellard */ 265d20fa6bSblueswir1 27a4ab4792SPeter Maydell #include "qemu/osdep.h" 2883c9f4caSPaolo Bonzini #include "hw/sysbus.h" 29d6454270SMarkus Armbruster #include "migration/vmstate.h" 3064552b6bSMarkus Armbruster #include "hw/irq.h" 310d09e41aSPaolo Bonzini #include "hw/scsi/esp.h" 32bf4b9889SBlue Swirl #include "trace.h" 331de7afc9SPaolo Bonzini #include "qemu/log.h" 340b8fa32fSMarkus Armbruster #include "qemu/module.h" 356f7e9aecSbellard 3667e999beSbellard /* 375ad6bb97Sblueswir1 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), 385ad6bb97Sblueswir1 * also produced as NCR89C100. See 3967e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt 4067e999beSbellard * and 4167e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt 4274d71ea1SLaurent Vivier * 4374d71ea1SLaurent Vivier * On Macintosh Quadra it is a NCR53C96. 4467e999beSbellard */ 4567e999beSbellard 46c73f96fdSblueswir1 static void esp_raise_irq(ESPState *s) 47c73f96fdSblueswir1 { 48c73f96fdSblueswir1 if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { 49c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_INT; 50c73f96fdSblueswir1 qemu_irq_raise(s->irq); 51bf4b9889SBlue Swirl trace_esp_raise_irq(); 52c73f96fdSblueswir1 } 53c73f96fdSblueswir1 } 54c73f96fdSblueswir1 55c73f96fdSblueswir1 static void esp_lower_irq(ESPState *s) 56c73f96fdSblueswir1 { 57c73f96fdSblueswir1 if (s->rregs[ESP_RSTAT] & STAT_INT) { 58c73f96fdSblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_INT; 59c73f96fdSblueswir1 qemu_irq_lower(s->irq); 60bf4b9889SBlue Swirl trace_esp_lower_irq(); 61c73f96fdSblueswir1 } 62c73f96fdSblueswir1 } 63c73f96fdSblueswir1 6474d71ea1SLaurent Vivier static void esp_raise_drq(ESPState *s) 6574d71ea1SLaurent Vivier { 66442de89aSMark Cave-Ayland if (!(s->drq_state)) { 676dec7c0dSMark Cave-Ayland qemu_irq_raise(s->drq_irq); 68960ebfd9SMark Cave-Ayland trace_esp_raise_drq(); 69442de89aSMark Cave-Ayland s->drq_state = true; 70442de89aSMark Cave-Ayland } 7174d71ea1SLaurent Vivier } 7274d71ea1SLaurent Vivier 7374d71ea1SLaurent Vivier static void esp_lower_drq(ESPState *s) 7474d71ea1SLaurent Vivier { 75442de89aSMark Cave-Ayland if (s->drq_state) { 766dec7c0dSMark Cave-Ayland qemu_irq_lower(s->drq_irq); 77960ebfd9SMark Cave-Ayland trace_esp_lower_drq(); 78442de89aSMark Cave-Ayland s->drq_state = false; 79442de89aSMark Cave-Ayland } 8074d71ea1SLaurent Vivier } 8174d71ea1SLaurent Vivier 822c1017bfSMark Cave-Ayland static const char *esp_phase_names[8] = { 832c1017bfSMark Cave-Ayland "DATA OUT", "DATA IN", "COMMAND", "STATUS", 842c1017bfSMark Cave-Ayland "(reserved)", "(reserved)", "MESSAGE OUT", "MESSAGE IN" 852c1017bfSMark Cave-Ayland }; 862c1017bfSMark Cave-Ayland 872c1017bfSMark Cave-Ayland static void esp_set_phase(ESPState *s, uint8_t phase) 882c1017bfSMark Cave-Ayland { 892c1017bfSMark Cave-Ayland s->rregs[ESP_RSTAT] &= ~7; 902c1017bfSMark Cave-Ayland s->rregs[ESP_RSTAT] |= phase; 912c1017bfSMark Cave-Ayland 922c1017bfSMark Cave-Ayland trace_esp_set_phase(esp_phase_names[phase]); 932c1017bfSMark Cave-Ayland } 942c1017bfSMark Cave-Ayland 952c1017bfSMark Cave-Ayland static uint8_t esp_get_phase(ESPState *s) 962c1017bfSMark Cave-Ayland { 972c1017bfSMark Cave-Ayland return s->rregs[ESP_RSTAT] & 7; 982c1017bfSMark Cave-Ayland } 992c1017bfSMark Cave-Ayland 1009c7e23fcSHervé Poussineau void esp_dma_enable(ESPState *s, int irq, int level) 10173d74342SBlue Swirl { 10273d74342SBlue Swirl if (level) { 10373d74342SBlue Swirl s->dma_enabled = 1; 104bf4b9889SBlue Swirl trace_esp_dma_enable(); 10573d74342SBlue Swirl if (s->dma_cb) { 10673d74342SBlue Swirl s->dma_cb(s); 10773d74342SBlue Swirl s->dma_cb = NULL; 10873d74342SBlue Swirl } 10973d74342SBlue Swirl } else { 110bf4b9889SBlue Swirl trace_esp_dma_disable(); 11173d74342SBlue Swirl s->dma_enabled = 0; 11273d74342SBlue Swirl } 11373d74342SBlue Swirl } 11473d74342SBlue Swirl 1159c7e23fcSHervé Poussineau void esp_request_cancelled(SCSIRequest *req) 11694d3f98aSPaolo Bonzini { 117e6810db8SHervé Poussineau ESPState *s = req->hba_private; 11894d3f98aSPaolo Bonzini 11994d3f98aSPaolo Bonzini if (req == s->current_req) { 12094d3f98aSPaolo Bonzini scsi_req_unref(s->current_req); 12194d3f98aSPaolo Bonzini s->current_req = NULL; 12294d3f98aSPaolo Bonzini s->current_dev = NULL; 123324c8809SMark Cave-Ayland s->async_len = 0; 12494d3f98aSPaolo Bonzini } 12594d3f98aSPaolo Bonzini } 12694d3f98aSPaolo Bonzini 127743d8736SMark Cave-Ayland static void esp_update_drq(ESPState *s) 128743d8736SMark Cave-Ayland { 129743d8736SMark Cave-Ayland bool to_device; 130743d8736SMark Cave-Ayland 131743d8736SMark Cave-Ayland switch (esp_get_phase(s)) { 132743d8736SMark Cave-Ayland case STAT_MO: 133743d8736SMark Cave-Ayland case STAT_CD: 134743d8736SMark Cave-Ayland case STAT_DO: 135743d8736SMark Cave-Ayland to_device = true; 136743d8736SMark Cave-Ayland break; 137743d8736SMark Cave-Ayland 138743d8736SMark Cave-Ayland case STAT_DI: 139743d8736SMark Cave-Ayland case STAT_ST: 140743d8736SMark Cave-Ayland case STAT_MI: 141743d8736SMark Cave-Ayland to_device = false; 142743d8736SMark Cave-Ayland break; 143743d8736SMark Cave-Ayland 144743d8736SMark Cave-Ayland default: 145743d8736SMark Cave-Ayland return; 146743d8736SMark Cave-Ayland } 147743d8736SMark Cave-Ayland 148743d8736SMark Cave-Ayland if (s->dma) { 149743d8736SMark Cave-Ayland /* DMA request so update DRQ according to transfer direction */ 150743d8736SMark Cave-Ayland if (to_device) { 151743d8736SMark Cave-Ayland if (fifo8_num_free(&s->fifo) < 2) { 152743d8736SMark Cave-Ayland esp_lower_drq(s); 153743d8736SMark Cave-Ayland } else { 154743d8736SMark Cave-Ayland esp_raise_drq(s); 155743d8736SMark Cave-Ayland } 156743d8736SMark Cave-Ayland } else { 157743d8736SMark Cave-Ayland if (fifo8_num_used(&s->fifo) < 2) { 158743d8736SMark Cave-Ayland esp_lower_drq(s); 159743d8736SMark Cave-Ayland } else { 160743d8736SMark Cave-Ayland esp_raise_drq(s); 161743d8736SMark Cave-Ayland } 162743d8736SMark Cave-Ayland } 163743d8736SMark Cave-Ayland } else { 164743d8736SMark Cave-Ayland /* Not a DMA request */ 165743d8736SMark Cave-Ayland esp_lower_drq(s); 166743d8736SMark Cave-Ayland } 167743d8736SMark Cave-Ayland } 168743d8736SMark Cave-Ayland 1690e7dbe29SMark Cave-Ayland static void esp_fifo_push(ESPState *s, uint8_t val) 170042879fcSMark Cave-Ayland { 1710e7dbe29SMark Cave-Ayland if (fifo8_num_used(&s->fifo) == s->fifo.capacity) { 172042879fcSMark Cave-Ayland trace_esp_error_fifo_overrun(); 173*ffa3a5f2SMark Cave-Ayland } else { 174*ffa3a5f2SMark Cave-Ayland fifo8_push(&s->fifo, val); 175042879fcSMark Cave-Ayland } 176042879fcSMark Cave-Ayland 177*ffa3a5f2SMark Cave-Ayland esp_update_drq(s); 178042879fcSMark Cave-Ayland } 179c5fef911SMark Cave-Ayland 180266170f9SMark Cave-Ayland static void esp_fifo_push_buf(ESPState *s, uint8_t *buf, int len) 181266170f9SMark Cave-Ayland { 182266170f9SMark Cave-Ayland fifo8_push_all(&s->fifo, buf, len); 183743d8736SMark Cave-Ayland esp_update_drq(s); 184266170f9SMark Cave-Ayland } 185266170f9SMark Cave-Ayland 18661fa150dSMark Cave-Ayland static uint8_t esp_fifo_pop(ESPState *s) 187042879fcSMark Cave-Ayland { 188*ffa3a5f2SMark Cave-Ayland uint8_t val; 189*ffa3a5f2SMark Cave-Ayland 19061fa150dSMark Cave-Ayland if (fifo8_is_empty(&s->fifo)) { 191*ffa3a5f2SMark Cave-Ayland val = 0; 192*ffa3a5f2SMark Cave-Ayland } else { 193*ffa3a5f2SMark Cave-Ayland val = fifo8_pop(&s->fifo); 194042879fcSMark Cave-Ayland } 195042879fcSMark Cave-Ayland 196*ffa3a5f2SMark Cave-Ayland esp_update_drq(s); 197*ffa3a5f2SMark Cave-Ayland return val; 198023666daSMark Cave-Ayland } 199023666daSMark Cave-Ayland 200d103d0dbSMark Cave-Ayland static uint32_t esp_fifo8_pop_buf(Fifo8 *fifo, uint8_t *dest, int maxlen) 2017b320a8eSMark Cave-Ayland { 2027b320a8eSMark Cave-Ayland const uint8_t *buf; 20349c60d16SMark Cave-Ayland uint32_t n, n2; 20449c60d16SMark Cave-Ayland int len; 2057b320a8eSMark Cave-Ayland 2067b320a8eSMark Cave-Ayland if (maxlen == 0) { 2077b320a8eSMark Cave-Ayland return 0; 2087b320a8eSMark Cave-Ayland } 2097b320a8eSMark Cave-Ayland 21049c60d16SMark Cave-Ayland len = maxlen; 21149c60d16SMark Cave-Ayland buf = fifo8_pop_buf(fifo, len, &n); 2127b320a8eSMark Cave-Ayland if (dest) { 2137b320a8eSMark Cave-Ayland memcpy(dest, buf, n); 2147b320a8eSMark Cave-Ayland } 2157b320a8eSMark Cave-Ayland 21649c60d16SMark Cave-Ayland /* Add FIFO wraparound if needed */ 21749c60d16SMark Cave-Ayland len -= n; 21849c60d16SMark Cave-Ayland len = MIN(len, fifo8_num_used(fifo)); 21949c60d16SMark Cave-Ayland if (len) { 22049c60d16SMark Cave-Ayland buf = fifo8_pop_buf(fifo, len, &n2); 22149c60d16SMark Cave-Ayland if (dest) { 22249c60d16SMark Cave-Ayland memcpy(&dest[n], buf, n2); 22349c60d16SMark Cave-Ayland } 22449c60d16SMark Cave-Ayland n += n2; 22549c60d16SMark Cave-Ayland } 22649c60d16SMark Cave-Ayland 2277b320a8eSMark Cave-Ayland return n; 2287b320a8eSMark Cave-Ayland } 2297b320a8eSMark Cave-Ayland 230da838126SMark Cave-Ayland static uint32_t esp_fifo_pop_buf(ESPState *s, uint8_t *dest, int maxlen) 231d103d0dbSMark Cave-Ayland { 232743d8736SMark Cave-Ayland uint32_t len = esp_fifo8_pop_buf(&s->fifo, dest, maxlen); 233743d8736SMark Cave-Ayland 234743d8736SMark Cave-Ayland esp_update_drq(s); 235743d8736SMark Cave-Ayland return len; 236d103d0dbSMark Cave-Ayland } 237d103d0dbSMark Cave-Ayland 238c47b5835SMark Cave-Ayland static uint32_t esp_get_tc(ESPState *s) 239c47b5835SMark Cave-Ayland { 240c47b5835SMark Cave-Ayland uint32_t dmalen; 241c47b5835SMark Cave-Ayland 242c47b5835SMark Cave-Ayland dmalen = s->rregs[ESP_TCLO]; 243c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCMID] << 8; 244c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCHI] << 16; 245c47b5835SMark Cave-Ayland 246c47b5835SMark Cave-Ayland return dmalen; 247c47b5835SMark Cave-Ayland } 248c47b5835SMark Cave-Ayland 249c47b5835SMark Cave-Ayland static void esp_set_tc(ESPState *s, uint32_t dmalen) 250c47b5835SMark Cave-Ayland { 251c5d7df28SMark Cave-Ayland uint32_t old_tc = esp_get_tc(s); 252c5d7df28SMark Cave-Ayland 253c47b5835SMark Cave-Ayland s->rregs[ESP_TCLO] = dmalen; 254c47b5835SMark Cave-Ayland s->rregs[ESP_TCMID] = dmalen >> 8; 255c47b5835SMark Cave-Ayland s->rregs[ESP_TCHI] = dmalen >> 16; 256c5d7df28SMark Cave-Ayland 257c5d7df28SMark Cave-Ayland if (old_tc && dmalen == 0) { 258c5d7df28SMark Cave-Ayland s->rregs[ESP_RSTAT] |= STAT_TC; 259c5d7df28SMark Cave-Ayland } 260c47b5835SMark Cave-Ayland } 261c47b5835SMark Cave-Ayland 262c04ed569SMark Cave-Ayland static uint32_t esp_get_stc(ESPState *s) 263c04ed569SMark Cave-Ayland { 264c04ed569SMark Cave-Ayland uint32_t dmalen; 265c04ed569SMark Cave-Ayland 266c04ed569SMark Cave-Ayland dmalen = s->wregs[ESP_TCLO]; 267c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCMID] << 8; 268c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCHI] << 16; 269c04ed569SMark Cave-Ayland 270c04ed569SMark Cave-Ayland return dmalen; 271c04ed569SMark Cave-Ayland } 272c04ed569SMark Cave-Ayland 273761bef75SMark Cave-Ayland static uint8_t esp_pdma_read(ESPState *s) 274761bef75SMark Cave-Ayland { 2758da90e81SMark Cave-Ayland uint8_t val; 2768da90e81SMark Cave-Ayland 27761fa150dSMark Cave-Ayland val = esp_fifo_pop(s); 2788da90e81SMark Cave-Ayland return val; 279761bef75SMark Cave-Ayland } 280761bef75SMark Cave-Ayland 281761bef75SMark Cave-Ayland static void esp_pdma_write(ESPState *s, uint8_t val) 282761bef75SMark Cave-Ayland { 2838da90e81SMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 2848da90e81SMark Cave-Ayland 2853c421400SMark Cave-Ayland if (dmalen == 0) { 2868da90e81SMark Cave-Ayland return; 2878da90e81SMark Cave-Ayland } 2888da90e81SMark Cave-Ayland 2890e7dbe29SMark Cave-Ayland esp_fifo_push(s, val); 2908da90e81SMark Cave-Ayland 2918da90e81SMark Cave-Ayland dmalen--; 2928da90e81SMark Cave-Ayland esp_set_tc(s, dmalen); 293761bef75SMark Cave-Ayland } 294761bef75SMark Cave-Ayland 295c7bce09cSMark Cave-Ayland static int esp_select(ESPState *s) 2966130b188SLaurent Vivier { 2976130b188SLaurent Vivier int target; 2986130b188SLaurent Vivier 2996130b188SLaurent Vivier target = s->wregs[ESP_WBUSID] & BUSID_DID; 3006130b188SLaurent Vivier 3016130b188SLaurent Vivier s->ti_size = 0; 3029b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_0; 3036130b188SLaurent Vivier 304cf40a5e4SMark Cave-Ayland if (s->current_req) { 305cf40a5e4SMark Cave-Ayland /* Started a new command before the old one finished. Cancel it. */ 306cf40a5e4SMark Cave-Ayland scsi_req_cancel(s->current_req); 307cf40a5e4SMark Cave-Ayland } 308cf40a5e4SMark Cave-Ayland 3096130b188SLaurent Vivier s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 3106130b188SLaurent Vivier if (!s->current_dev) { 3116130b188SLaurent Vivier /* No such drive */ 3126130b188SLaurent Vivier s->rregs[ESP_RSTAT] = 0; 313cf1a7a9bSMark Cave-Ayland s->rregs[ESP_RINTR] = INTR_DC; 3146130b188SLaurent Vivier esp_raise_irq(s); 3156130b188SLaurent Vivier return -1; 3166130b188SLaurent Vivier } 3174e78f3bfSMark Cave-Ayland 3184e78f3bfSMark Cave-Ayland /* 3194e78f3bfSMark Cave-Ayland * Note that we deliberately don't raise the IRQ here: this will be done 320c90b2792SMark Cave-Ayland * either in esp_transfer_data() or esp_command_complete() 3214e78f3bfSMark Cave-Ayland */ 3226130b188SLaurent Vivier return 0; 3236130b188SLaurent Vivier } 3246130b188SLaurent Vivier 3253ee9a475SMark Cave-Ayland static void esp_do_dma(ESPState *s); 3263ee9a475SMark Cave-Ayland static void esp_do_nodma(ESPState *s); 3273ee9a475SMark Cave-Ayland 3284eb86065SPaolo Bonzini static void do_command_phase(ESPState *s) 3299f149aa9Spbrook { 3307b320a8eSMark Cave-Ayland uint32_t cmdlen; 3319f149aa9Spbrook int32_t datalen; 332f48a7a6eSPaolo Bonzini SCSIDevice *current_lun; 3337b320a8eSMark Cave-Ayland uint8_t buf[ESP_CMDFIFO_SZ]; 3349f149aa9Spbrook 3354eb86065SPaolo Bonzini trace_esp_do_command_phase(s->lun); 336023666daSMark Cave-Ayland cmdlen = fifo8_num_used(&s->cmdfifo); 33799545751SMark Cave-Ayland if (!cmdlen || !s->current_dev) { 33899545751SMark Cave-Ayland return; 33999545751SMark Cave-Ayland } 340f87d0487SMark Cave-Ayland esp_fifo8_pop_buf(&s->cmdfifo, buf, cmdlen); 341023666daSMark Cave-Ayland 3424eb86065SPaolo Bonzini current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, s->lun); 343b22f83d8SAlexandra Diupina if (!current_lun) { 344b22f83d8SAlexandra Diupina /* No such drive */ 345b22f83d8SAlexandra Diupina s->rregs[ESP_RSTAT] = 0; 346b22f83d8SAlexandra Diupina s->rregs[ESP_RINTR] = INTR_DC; 347b22f83d8SAlexandra Diupina s->rregs[ESP_RSEQ] = SEQ_0; 348b22f83d8SAlexandra Diupina esp_raise_irq(s); 349b22f83d8SAlexandra Diupina return; 350b22f83d8SAlexandra Diupina } 351b22f83d8SAlexandra Diupina 352fe9d8927SJohn Millikin s->current_req = scsi_req_new(current_lun, 0, s->lun, buf, cmdlen, s); 353c39ce112SPaolo Bonzini datalen = scsi_req_enqueue(s->current_req); 35467e999beSbellard s->ti_size = datalen; 355023666daSMark Cave-Ayland fifo8_reset(&s->cmdfifo); 356c90b2792SMark Cave-Ayland s->data_ready = false; 35767e999beSbellard if (datalen != 0) { 3584e78f3bfSMark Cave-Ayland /* 359c90b2792SMark Cave-Ayland * Switch to DATA phase but wait until initial data xfer is 3604e78f3bfSMark Cave-Ayland * complete before raising the command completion interrupt 3614e78f3bfSMark Cave-Ayland */ 362c90b2792SMark Cave-Ayland if (datalen > 0) { 363abc139cdSMark Cave-Ayland esp_set_phase(s, STAT_DI); 3644f6200f0Sbellard } else { 365abc139cdSMark Cave-Ayland esp_set_phase(s, STAT_DO); 3662f275b8fSbellard } 3674e78f3bfSMark Cave-Ayland scsi_req_continue(s->current_req); 3684e78f3bfSMark Cave-Ayland return; 3694e78f3bfSMark Cave-Ayland } 3704e78f3bfSMark Cave-Ayland } 3712f275b8fSbellard 3724eb86065SPaolo Bonzini static void do_message_phase(ESPState *s) 373f2818f22SArtyom Tarasenko { 3744eb86065SPaolo Bonzini if (s->cmdfifo_cdb_offset) { 3751828000bSMark Cave-Ayland uint8_t message = fifo8_is_empty(&s->cmdfifo) ? 0 : 3761828000bSMark Cave-Ayland fifo8_pop(&s->cmdfifo); 377023666daSMark Cave-Ayland 3784eb86065SPaolo Bonzini trace_esp_do_identify(message); 3794eb86065SPaolo Bonzini s->lun = message & 7; 380023666daSMark Cave-Ayland s->cmdfifo_cdb_offset--; 3814eb86065SPaolo Bonzini } 382f2818f22SArtyom Tarasenko 383799d90d8SMark Cave-Ayland /* Ignore extended messages for now */ 384023666daSMark Cave-Ayland if (s->cmdfifo_cdb_offset) { 3854eb86065SPaolo Bonzini int len = MIN(s->cmdfifo_cdb_offset, fifo8_num_used(&s->cmdfifo)); 3862260402bSMark Cave-Ayland esp_fifo8_pop_buf(&s->cmdfifo, NULL, len); 387023666daSMark Cave-Ayland s->cmdfifo_cdb_offset = 0; 388023666daSMark Cave-Ayland } 3894eb86065SPaolo Bonzini } 390023666daSMark Cave-Ayland 3914eb86065SPaolo Bonzini static void do_cmd(ESPState *s) 3924eb86065SPaolo Bonzini { 3934eb86065SPaolo Bonzini do_message_phase(s); 3944eb86065SPaolo Bonzini assert(s->cmdfifo_cdb_offset == 0); 3954eb86065SPaolo Bonzini do_command_phase(s); 396f2818f22SArtyom Tarasenko } 397f2818f22SArtyom Tarasenko 3989f149aa9Spbrook static void handle_satn(ESPState *s) 3999f149aa9Spbrook { 4001b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 40173d74342SBlue Swirl s->dma_cb = handle_satn; 40273d74342SBlue Swirl return; 40373d74342SBlue Swirl } 404b46a43a2SMark Cave-Ayland 4051bcaf71bSMark Cave-Ayland if (esp_select(s) < 0) { 4061bcaf71bSMark Cave-Ayland return; 4071bcaf71bSMark Cave-Ayland } 4083ee9a475SMark Cave-Ayland 4093ee9a475SMark Cave-Ayland esp_set_phase(s, STAT_MO); 4103ee9a475SMark Cave-Ayland 4113ee9a475SMark Cave-Ayland if (s->dma) { 4123ee9a475SMark Cave-Ayland esp_do_dma(s); 4133ee9a475SMark Cave-Ayland } else { 414d39592ffSMark Cave-Ayland esp_do_nodma(s); 4159f149aa9Spbrook } 41694d5c79dSMark Cave-Ayland } 4179f149aa9Spbrook 418f2818f22SArtyom Tarasenko static void handle_s_without_atn(ESPState *s) 419f2818f22SArtyom Tarasenko { 4201b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 42173d74342SBlue Swirl s->dma_cb = handle_s_without_atn; 42273d74342SBlue Swirl return; 42373d74342SBlue Swirl } 424b46a43a2SMark Cave-Ayland 4251bcaf71bSMark Cave-Ayland if (esp_select(s) < 0) { 4261bcaf71bSMark Cave-Ayland return; 4271bcaf71bSMark Cave-Ayland } 4289ff0fd12SMark Cave-Ayland 429abc139cdSMark Cave-Ayland esp_set_phase(s, STAT_CD); 4309ff0fd12SMark Cave-Ayland s->cmdfifo_cdb_offset = 0; 4319ff0fd12SMark Cave-Ayland 4329ff0fd12SMark Cave-Ayland if (s->dma) { 4339ff0fd12SMark Cave-Ayland esp_do_dma(s); 4349ff0fd12SMark Cave-Ayland } else { 435d39592ffSMark Cave-Ayland esp_do_nodma(s); 436f2818f22SArtyom Tarasenko } 437f2818f22SArtyom Tarasenko } 438f2818f22SArtyom Tarasenko 4399f149aa9Spbrook static void handle_satn_stop(ESPState *s) 4409f149aa9Spbrook { 4411b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 44273d74342SBlue Swirl s->dma_cb = handle_satn_stop; 44373d74342SBlue Swirl return; 44473d74342SBlue Swirl } 445b46a43a2SMark Cave-Ayland 4461bcaf71bSMark Cave-Ayland if (esp_select(s) < 0) { 4471bcaf71bSMark Cave-Ayland return; 4481bcaf71bSMark Cave-Ayland } 449db4d4150SMark Cave-Ayland 450abc139cdSMark Cave-Ayland esp_set_phase(s, STAT_MO); 4515d02add4SMark Cave-Ayland s->cmdfifo_cdb_offset = 0; 452db4d4150SMark Cave-Ayland 453db4d4150SMark Cave-Ayland if (s->dma) { 454db4d4150SMark Cave-Ayland esp_do_dma(s); 455db4d4150SMark Cave-Ayland } else { 456d39592ffSMark Cave-Ayland esp_do_nodma(s); 4579f149aa9Spbrook } 4589f149aa9Spbrook } 4599f149aa9Spbrook 460a6cad7cdSMark Cave-Ayland static void handle_pad(ESPState *s) 461a6cad7cdSMark Cave-Ayland { 462a6cad7cdSMark Cave-Ayland if (s->dma) { 463a6cad7cdSMark Cave-Ayland esp_do_dma(s); 464a6cad7cdSMark Cave-Ayland } else { 465a6cad7cdSMark Cave-Ayland esp_do_nodma(s); 466a6cad7cdSMark Cave-Ayland } 467a6cad7cdSMark Cave-Ayland } 468a6cad7cdSMark Cave-Ayland 4690fc5c15aSpbrook static void write_response(ESPState *s) 4702f275b8fSbellard { 471bf4b9889SBlue Swirl trace_esp_write_response(s->status); 472042879fcSMark Cave-Ayland 4738baa1472SMark Cave-Ayland if (s->dma) { 4748baa1472SMark Cave-Ayland esp_do_dma(s); 4758baa1472SMark Cave-Ayland } else { 47683428f7aSMark Cave-Ayland esp_do_nodma(s); 4772f275b8fSbellard } 4788baa1472SMark Cave-Ayland } 4794f6200f0Sbellard 4805aa0df40SMark Cave-Ayland static bool esp_cdb_ready(ESPState *s) 4815d02add4SMark Cave-Ayland { 4825aa0df40SMark Cave-Ayland int len = fifo8_num_used(&s->cmdfifo) - s->cmdfifo_cdb_offset; 4835d02add4SMark Cave-Ayland const uint8_t *pbuf; 4843cc70889SMark Cave-Ayland uint32_t n; 4855aa0df40SMark Cave-Ayland int cdblen; 4865d02add4SMark Cave-Ayland 4875aa0df40SMark Cave-Ayland if (len <= 0) { 4885aa0df40SMark Cave-Ayland return false; 4895d02add4SMark Cave-Ayland } 4905d02add4SMark Cave-Ayland 4913cc70889SMark Cave-Ayland pbuf = fifo8_peek_buf(&s->cmdfifo, len, &n); 4923cc70889SMark Cave-Ayland if (n < len) { 4933cc70889SMark Cave-Ayland /* 4943cc70889SMark Cave-Ayland * In normal use the cmdfifo should never wrap, but include this check 4953cc70889SMark Cave-Ayland * to prevent a malicious guest from reading past the end of the 4963cc70889SMark Cave-Ayland * cmdfifo data buffer below 4973cc70889SMark Cave-Ayland */ 4983cc70889SMark Cave-Ayland return false; 4993cc70889SMark Cave-Ayland } 5003cc70889SMark Cave-Ayland 5015aa0df40SMark Cave-Ayland cdblen = scsi_cdb_length((uint8_t *)&pbuf[s->cmdfifo_cdb_offset]); 5025d02add4SMark Cave-Ayland 5035aa0df40SMark Cave-Ayland return cdblen < 0 ? false : (len >= cdblen); 5045d02add4SMark Cave-Ayland } 5055d02add4SMark Cave-Ayland 506004826d0SMark Cave-Ayland static void esp_dma_ti_check(ESPState *s) 5074d611c9aSpbrook { 508af74b3c1SMark Cave-Ayland if (esp_get_tc(s) == 0 && fifo8_num_used(&s->fifo) < 2) { 509cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 510c73f96fdSblueswir1 esp_raise_irq(s); 511af74b3c1SMark Cave-Ayland esp_lower_drq(s); 512af74b3c1SMark Cave-Ayland } 5134d611c9aSpbrook } 514a917d384Spbrook 515a917d384Spbrook static void esp_do_dma(ESPState *s) 516a917d384Spbrook { 517023666daSMark Cave-Ayland uint32_t len, cmdlen; 518023666daSMark Cave-Ayland uint8_t buf[ESP_CMDFIFO_SZ]; 519a917d384Spbrook 5206cc88d6bSMark Cave-Ayland len = esp_get_tc(s); 521ad2725afSMark Cave-Ayland 522ad2725afSMark Cave-Ayland switch (esp_get_phase(s)) { 523ad2725afSMark Cave-Ayland case STAT_MO: 52446b0c361SMark Cave-Ayland if (s->dma_memory_read) { 52546b0c361SMark Cave-Ayland len = MIN(len, fifo8_num_free(&s->cmdfifo)); 52646b0c361SMark Cave-Ayland s->dma_memory_read(s->dma_opaque, buf, len); 52746b0c361SMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 52846b0c361SMark Cave-Ayland } else { 529da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 53067ea170eSMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 53167ea170eSMark Cave-Ayland esp_raise_drq(s); 53246b0c361SMark Cave-Ayland } 53346b0c361SMark Cave-Ayland 53467ea170eSMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 53567ea170eSMark Cave-Ayland s->cmdfifo_cdb_offset += len; 53646b0c361SMark Cave-Ayland 5373ee9a475SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 5383ee9a475SMark Cave-Ayland case CMD_SELATN | CMD_DMA: 5393ee9a475SMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) >= 1) { 5403ee9a475SMark Cave-Ayland /* First byte received, switch to command phase */ 5413ee9a475SMark Cave-Ayland esp_set_phase(s, STAT_CD); 5429b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 5433ee9a475SMark Cave-Ayland s->cmdfifo_cdb_offset = 1; 5443ee9a475SMark Cave-Ayland 5453ee9a475SMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) > 1) { 5463ee9a475SMark Cave-Ayland /* Process any additional command phase data */ 5473ee9a475SMark Cave-Ayland esp_do_dma(s); 5483ee9a475SMark Cave-Ayland } 5493ee9a475SMark Cave-Ayland } 5503ee9a475SMark Cave-Ayland break; 5513ee9a475SMark Cave-Ayland 552db4d4150SMark Cave-Ayland case CMD_SELATNS | CMD_DMA: 553db4d4150SMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) == 1) { 554db4d4150SMark Cave-Ayland /* First byte received, stop in message out phase */ 5559b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_MO; 556db4d4150SMark Cave-Ayland s->cmdfifo_cdb_offset = 1; 557db4d4150SMark Cave-Ayland 558db4d4150SMark Cave-Ayland /* Raise command completion interrupt */ 559db4d4150SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 560db4d4150SMark Cave-Ayland esp_raise_irq(s); 561db4d4150SMark Cave-Ayland } 562db4d4150SMark Cave-Ayland break; 563db4d4150SMark Cave-Ayland 5643fd325a2SMark Cave-Ayland case CMD_TI | CMD_DMA: 56546b0c361SMark Cave-Ayland /* ATN remains asserted until TC == 0 */ 56646b0c361SMark Cave-Ayland if (esp_get_tc(s) == 0) { 56746b0c361SMark Cave-Ayland esp_set_phase(s, STAT_CD); 568cb22ce50SMark Cave-Ayland s->rregs[ESP_CMD] = 0; 56946b0c361SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 57046b0c361SMark Cave-Ayland esp_raise_irq(s); 57146b0c361SMark Cave-Ayland } 57246b0c361SMark Cave-Ayland break; 5733fd325a2SMark Cave-Ayland } 5743fd325a2SMark Cave-Ayland break; 57546b0c361SMark Cave-Ayland 576ad2725afSMark Cave-Ayland case STAT_CD: 577023666daSMark Cave-Ayland cmdlen = fifo8_num_used(&s->cmdfifo); 578023666daSMark Cave-Ayland trace_esp_do_dma(cmdlen, len); 57974d71ea1SLaurent Vivier if (s->dma_memory_read) { 5800ebb5fd8SMark Cave-Ayland len = MIN(len, fifo8_num_free(&s->cmdfifo)); 581023666daSMark Cave-Ayland s->dma_memory_read(s->dma_opaque, buf, len); 582023666daSMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 583a0347651SMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 58474d71ea1SLaurent Vivier } else { 585da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 586406e8a3eSMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 587406e8a3eSMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 58874d71ea1SLaurent Vivier esp_raise_drq(s); 5893c7f3c8bSMark Cave-Ayland } 590023666daSMark Cave-Ayland trace_esp_handle_ti_cmd(cmdlen); 59115407433SLaurent Vivier s->ti_size = 0; 59246b0c361SMark Cave-Ayland if (esp_get_tc(s) == 0) { 593799d90d8SMark Cave-Ayland /* Command has been received */ 594c959f218SMark Cave-Ayland do_cmd(s); 595799d90d8SMark Cave-Ayland } 596ad2725afSMark Cave-Ayland break; 5971454dc76SMark Cave-Ayland 5981454dc76SMark Cave-Ayland case STAT_DO: 5990db89536SMark Cave-Ayland if (!s->current_req) { 6000db89536SMark Cave-Ayland return; 6010db89536SMark Cave-Ayland } 6024460b86aSMark Cave-Ayland if (s->async_len == 0 && esp_get_tc(s) && s->ti_size) { 603a917d384Spbrook /* Defer until data is available. */ 604a917d384Spbrook return; 605a917d384Spbrook } 606a917d384Spbrook if (len > s->async_len) { 607a917d384Spbrook len = s->async_len; 608a917d384Spbrook } 6090d17ce82SMark Cave-Ayland 610a6cad7cdSMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 611a6cad7cdSMark Cave-Ayland case CMD_TI | CMD_DMA: 61274d71ea1SLaurent Vivier if (s->dma_memory_read) { 6138b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, s->async_buf, len); 614f3666223SMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 6150d17ce82SMark Cave-Ayland } else { 6160d17ce82SMark Cave-Ayland /* Copy FIFO data to device */ 6170d17ce82SMark Cave-Ayland len = MIN(s->async_len, ESP_FIFO_SZ); 6180d17ce82SMark Cave-Ayland len = MIN(len, fifo8_num_used(&s->fifo)); 619da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, s->async_buf, len); 6200d17ce82SMark Cave-Ayland esp_raise_drq(s); 6210d17ce82SMark Cave-Ayland } 6220d17ce82SMark Cave-Ayland 623f3666223SMark Cave-Ayland s->async_buf += len; 624f3666223SMark Cave-Ayland s->async_len -= len; 625f3666223SMark Cave-Ayland s->ti_size += len; 626a6cad7cdSMark Cave-Ayland break; 627a6cad7cdSMark Cave-Ayland 628a6cad7cdSMark Cave-Ayland case CMD_PAD | CMD_DMA: 629a6cad7cdSMark Cave-Ayland /* Copy TC zero bytes into the incoming stream */ 630a6cad7cdSMark Cave-Ayland if (!s->dma_memory_read) { 631a6cad7cdSMark Cave-Ayland len = MIN(s->async_len, ESP_FIFO_SZ); 632a6cad7cdSMark Cave-Ayland len = MIN(len, fifo8_num_free(&s->fifo)); 633a6cad7cdSMark Cave-Ayland } 634a6cad7cdSMark Cave-Ayland 635a6cad7cdSMark Cave-Ayland memset(s->async_buf, 0, len); 636a6cad7cdSMark Cave-Ayland 637a6cad7cdSMark Cave-Ayland s->async_buf += len; 638a6cad7cdSMark Cave-Ayland s->async_len -= len; 639a6cad7cdSMark Cave-Ayland s->ti_size += len; 640a6cad7cdSMark Cave-Ayland break; 641a6cad7cdSMark Cave-Ayland } 642f3666223SMark Cave-Ayland 643e4e166c8SMark Cave-Ayland if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) { 644e4e166c8SMark Cave-Ayland /* Defer until the scsi layer has completed */ 645f3666223SMark Cave-Ayland scsi_req_continue(s->current_req); 646f3666223SMark Cave-Ayland return; 647f3666223SMark Cave-Ayland } 648f3666223SMark Cave-Ayland 649004826d0SMark Cave-Ayland esp_dma_ti_check(s); 6501454dc76SMark Cave-Ayland break; 6511454dc76SMark Cave-Ayland 6521454dc76SMark Cave-Ayland case STAT_DI: 6531454dc76SMark Cave-Ayland if (!s->current_req) { 6541454dc76SMark Cave-Ayland return; 6551454dc76SMark Cave-Ayland } 6561454dc76SMark Cave-Ayland if (s->async_len == 0 && esp_get_tc(s) && s->ti_size) { 6571454dc76SMark Cave-Ayland /* Defer until data is available. */ 6581454dc76SMark Cave-Ayland return; 6591454dc76SMark Cave-Ayland } 6601454dc76SMark Cave-Ayland if (len > s->async_len) { 6611454dc76SMark Cave-Ayland len = s->async_len; 6621454dc76SMark Cave-Ayland } 663c37cc88eSMark Cave-Ayland 664a6cad7cdSMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 665a6cad7cdSMark Cave-Ayland case CMD_TI | CMD_DMA: 66674d71ea1SLaurent Vivier if (s->dma_memory_write) { 6678b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->async_buf, len); 66874d71ea1SLaurent Vivier } else { 66982141c8bSMark Cave-Ayland /* Copy device data to FIFO */ 670042879fcSMark Cave-Ayland len = MIN(len, fifo8_num_free(&s->fifo)); 671266170f9SMark Cave-Ayland esp_fifo_push_buf(s, s->async_buf, len); 672c37cc88eSMark Cave-Ayland esp_raise_drq(s); 673c37cc88eSMark Cave-Ayland } 674c37cc88eSMark Cave-Ayland 67582141c8bSMark Cave-Ayland s->async_buf += len; 67682141c8bSMark Cave-Ayland s->async_len -= len; 67782141c8bSMark Cave-Ayland s->ti_size -= len; 67882141c8bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 679a6cad7cdSMark Cave-Ayland break; 680a6cad7cdSMark Cave-Ayland 681a6cad7cdSMark Cave-Ayland case CMD_PAD | CMD_DMA: 682a6cad7cdSMark Cave-Ayland /* Drop TC bytes from the incoming stream */ 683a6cad7cdSMark Cave-Ayland if (!s->dma_memory_write) { 684a6cad7cdSMark Cave-Ayland len = MIN(len, fifo8_num_free(&s->fifo)); 685a6cad7cdSMark Cave-Ayland } 686a6cad7cdSMark Cave-Ayland 687a6cad7cdSMark Cave-Ayland s->async_buf += len; 688a6cad7cdSMark Cave-Ayland s->async_len -= len; 689a6cad7cdSMark Cave-Ayland s->ti_size -= len; 690a6cad7cdSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 691a6cad7cdSMark Cave-Ayland break; 692a6cad7cdSMark Cave-Ayland } 693e4e166c8SMark Cave-Ayland 69402a3ce56SMark Cave-Ayland if (s->async_len == 0 && s->ti_size == 0 && esp_get_tc(s)) { 69502a3ce56SMark Cave-Ayland /* If the guest underflows TC then terminate SCSI request */ 69602a3ce56SMark Cave-Ayland scsi_req_continue(s->current_req); 69702a3ce56SMark Cave-Ayland return; 69802a3ce56SMark Cave-Ayland } 69902a3ce56SMark Cave-Ayland 700e4e166c8SMark Cave-Ayland if (s->async_len == 0 && fifo8_num_used(&s->fifo) < 2) { 701e4e166c8SMark Cave-Ayland /* Defer until the scsi layer has completed */ 702e4e166c8SMark Cave-Ayland scsi_req_continue(s->current_req); 703e4e166c8SMark Cave-Ayland return; 704e4e166c8SMark Cave-Ayland } 705e4e166c8SMark Cave-Ayland 706004826d0SMark Cave-Ayland esp_dma_ti_check(s); 7071454dc76SMark Cave-Ayland break; 7088baa1472SMark Cave-Ayland 7098baa1472SMark Cave-Ayland case STAT_ST: 7108baa1472SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 7118baa1472SMark Cave-Ayland case CMD_ICCS | CMD_DMA: 7128baa1472SMark Cave-Ayland len = MIN(len, 1); 7138baa1472SMark Cave-Ayland 7148baa1472SMark Cave-Ayland if (len) { 7158baa1472SMark Cave-Ayland buf[0] = s->status; 7168baa1472SMark Cave-Ayland 7178baa1472SMark Cave-Ayland if (s->dma_memory_write) { 7188baa1472SMark Cave-Ayland s->dma_memory_write(s->dma_opaque, buf, len); 7198baa1472SMark Cave-Ayland } else { 720266170f9SMark Cave-Ayland esp_fifo_push_buf(s, buf, len); 7218baa1472SMark Cave-Ayland } 7228baa1472SMark Cave-Ayland 723421d1ca5SMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 7248baa1472SMark Cave-Ayland esp_set_phase(s, STAT_MI); 7258baa1472SMark Cave-Ayland 7268baa1472SMark Cave-Ayland if (esp_get_tc(s) > 0) { 7278baa1472SMark Cave-Ayland /* Process any message in phase data */ 7288baa1472SMark Cave-Ayland esp_do_dma(s); 7298baa1472SMark Cave-Ayland } 7308baa1472SMark Cave-Ayland } 7318baa1472SMark Cave-Ayland break; 73202a3ce56SMark Cave-Ayland 73302a3ce56SMark Cave-Ayland default: 73402a3ce56SMark Cave-Ayland /* Consume remaining data if the guest underflows TC */ 73502a3ce56SMark Cave-Ayland if (fifo8_num_used(&s->fifo) < 2) { 73602a3ce56SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 73702a3ce56SMark Cave-Ayland esp_raise_irq(s); 73802a3ce56SMark Cave-Ayland esp_lower_drq(s); 73902a3ce56SMark Cave-Ayland } 74002a3ce56SMark Cave-Ayland break; 7418baa1472SMark Cave-Ayland } 7428baa1472SMark Cave-Ayland break; 7438baa1472SMark Cave-Ayland 7448baa1472SMark Cave-Ayland case STAT_MI: 7458baa1472SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 7468baa1472SMark Cave-Ayland case CMD_ICCS | CMD_DMA: 7478baa1472SMark Cave-Ayland len = MIN(len, 1); 7488baa1472SMark Cave-Ayland 7498baa1472SMark Cave-Ayland if (len) { 7508baa1472SMark Cave-Ayland buf[0] = 0; 7518baa1472SMark Cave-Ayland 7528baa1472SMark Cave-Ayland if (s->dma_memory_write) { 7538baa1472SMark Cave-Ayland s->dma_memory_write(s->dma_opaque, buf, len); 7548baa1472SMark Cave-Ayland } else { 755266170f9SMark Cave-Ayland esp_fifo_push_buf(s, buf, len); 7568baa1472SMark Cave-Ayland } 7578baa1472SMark Cave-Ayland 758421d1ca5SMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 759421d1ca5SMark Cave-Ayland 7608baa1472SMark Cave-Ayland /* Raise end of command interrupt */ 7610ee71db4SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 7628baa1472SMark Cave-Ayland esp_raise_irq(s); 7638baa1472SMark Cave-Ayland } 7648baa1472SMark Cave-Ayland break; 7658baa1472SMark Cave-Ayland } 7668baa1472SMark Cave-Ayland break; 76774d71ea1SLaurent Vivier } 768a917d384Spbrook } 769a917d384Spbrook 770a1b8d389SMark Cave-Ayland static void esp_nodma_ti_dataout(ESPState *s) 771a1b8d389SMark Cave-Ayland { 772a1b8d389SMark Cave-Ayland int len; 773a1b8d389SMark Cave-Ayland 774a1b8d389SMark Cave-Ayland if (!s->current_req) { 775a1b8d389SMark Cave-Ayland return; 776a1b8d389SMark Cave-Ayland } 777a1b8d389SMark Cave-Ayland if (s->async_len == 0) { 778a1b8d389SMark Cave-Ayland /* Defer until data is available. */ 779a1b8d389SMark Cave-Ayland return; 780a1b8d389SMark Cave-Ayland } 781a1b8d389SMark Cave-Ayland len = MIN(s->async_len, ESP_FIFO_SZ); 782a1b8d389SMark Cave-Ayland len = MIN(len, fifo8_num_used(&s->fifo)); 783da838126SMark Cave-Ayland esp_fifo_pop_buf(s, s->async_buf, len); 784a1b8d389SMark Cave-Ayland s->async_buf += len; 785a1b8d389SMark Cave-Ayland s->async_len -= len; 786a1b8d389SMark Cave-Ayland s->ti_size += len; 787a1b8d389SMark Cave-Ayland 788a1b8d389SMark Cave-Ayland if (s->async_len == 0) { 789a1b8d389SMark Cave-Ayland scsi_req_continue(s->current_req); 790a1b8d389SMark Cave-Ayland return; 791a1b8d389SMark Cave-Ayland } 792a1b8d389SMark Cave-Ayland 793a1b8d389SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 794a1b8d389SMark Cave-Ayland esp_raise_irq(s); 795a1b8d389SMark Cave-Ayland } 796a1b8d389SMark Cave-Ayland 7971b9e48a5SMark Cave-Ayland static void esp_do_nodma(ESPState *s) 7981b9e48a5SMark Cave-Ayland { 7992572689bSMark Cave-Ayland uint8_t buf[ESP_FIFO_SZ]; 8007b320a8eSMark Cave-Ayland uint32_t cmdlen; 8015a857339SMark Cave-Ayland int len; 8021b9e48a5SMark Cave-Ayland 80383e803deSMark Cave-Ayland switch (esp_get_phase(s)) { 80483e803deSMark Cave-Ayland case STAT_MO: 805215d2579SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 806215d2579SMark Cave-Ayland case CMD_SELATN: 8072572689bSMark Cave-Ayland /* Copy FIFO into cmdfifo */ 808da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 8095a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 8105a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 8112572689bSMark Cave-Ayland 8125d02add4SMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) >= 1) { 8135d02add4SMark Cave-Ayland /* First byte received, switch to command phase */ 8145d02add4SMark Cave-Ayland esp_set_phase(s, STAT_CD); 8159b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 8165d02add4SMark Cave-Ayland s->cmdfifo_cdb_offset = 1; 8175d02add4SMark Cave-Ayland 8185d02add4SMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) > 1) { 8195d02add4SMark Cave-Ayland /* Process any additional command phase data */ 8205d02add4SMark Cave-Ayland esp_do_nodma(s); 8215d02add4SMark Cave-Ayland } 8225d02add4SMark Cave-Ayland } 8235d02add4SMark Cave-Ayland break; 8245d02add4SMark Cave-Ayland 8255d02add4SMark Cave-Ayland case CMD_SELATNS: 826215d2579SMark Cave-Ayland /* Copy one byte from FIFO into cmdfifo */ 8275a50644eSMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, 8285a50644eSMark Cave-Ayland MIN(fifo8_num_used(&s->fifo), 1)); 8295a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 8305a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 831215d2579SMark Cave-Ayland 832d39592ffSMark Cave-Ayland if (fifo8_num_used(&s->cmdfifo) >= 1) { 8335d02add4SMark Cave-Ayland /* First byte received, stop in message out phase */ 8349b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_MO; 8355d02add4SMark Cave-Ayland s->cmdfifo_cdb_offset = 1; 8365d02add4SMark Cave-Ayland 8375d02add4SMark Cave-Ayland /* Raise command completion interrupt */ 8385d02add4SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 8395d02add4SMark Cave-Ayland esp_raise_irq(s); 8405d02add4SMark Cave-Ayland } 8415d02add4SMark Cave-Ayland break; 8425d02add4SMark Cave-Ayland 8435d02add4SMark Cave-Ayland case CMD_TI: 844215d2579SMark Cave-Ayland /* Copy FIFO into cmdfifo */ 845da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 8465a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 8475a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 848215d2579SMark Cave-Ayland 8495d02add4SMark Cave-Ayland /* ATN remains asserted until FIFO empty */ 8501b9e48a5SMark Cave-Ayland s->cmdfifo_cdb_offset = fifo8_num_used(&s->cmdfifo); 851abc139cdSMark Cave-Ayland esp_set_phase(s, STAT_CD); 852cb22ce50SMark Cave-Ayland s->rregs[ESP_CMD] = 0; 8531b9e48a5SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 8541b9e48a5SMark Cave-Ayland esp_raise_irq(s); 85579a6c7c6SMark Cave-Ayland break; 8565d02add4SMark Cave-Ayland } 8575d02add4SMark Cave-Ayland break; 85879a6c7c6SMark Cave-Ayland 85979a6c7c6SMark Cave-Ayland case STAT_CD: 860acdee66dSMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 861acdee66dSMark Cave-Ayland case CMD_TI: 86279a6c7c6SMark Cave-Ayland /* Copy FIFO into cmdfifo */ 863da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 8645a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 8655a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 86679a6c7c6SMark Cave-Ayland 86779a6c7c6SMark Cave-Ayland cmdlen = fifo8_num_used(&s->cmdfifo); 86879a6c7c6SMark Cave-Ayland trace_esp_handle_ti_cmd(cmdlen); 86979a6c7c6SMark Cave-Ayland 8705d02add4SMark Cave-Ayland /* CDB may be transferred in one or more TI commands */ 8715aa0df40SMark Cave-Ayland if (esp_cdb_ready(s)) { 87279a6c7c6SMark Cave-Ayland /* Command has been received */ 87379a6c7c6SMark Cave-Ayland do_cmd(s); 8745d02add4SMark Cave-Ayland } else { 8755d02add4SMark Cave-Ayland /* 8765d02add4SMark Cave-Ayland * If data was transferred from the FIFO then raise bus 8775d02add4SMark Cave-Ayland * service interrupt to indicate transfer complete. Otherwise 8785d02add4SMark Cave-Ayland * defer until the next FIFO write. 8795d02add4SMark Cave-Ayland */ 8805a857339SMark Cave-Ayland if (len) { 8815d02add4SMark Cave-Ayland /* Raise interrupt to indicate transfer complete */ 8825d02add4SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 8835d02add4SMark Cave-Ayland esp_raise_irq(s); 8845d02add4SMark Cave-Ayland } 8855d02add4SMark Cave-Ayland } 8865d02add4SMark Cave-Ayland break; 8875d02add4SMark Cave-Ayland 8888ba32048SMark Cave-Ayland case CMD_SEL | CMD_DMA: 8898ba32048SMark Cave-Ayland case CMD_SELATN | CMD_DMA: 890acdee66dSMark Cave-Ayland /* Copy FIFO into cmdfifo */ 891da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 8925a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 8935a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 894acdee66dSMark Cave-Ayland 8958ba32048SMark Cave-Ayland /* Handle when DMA transfer is terminated by non-DMA FIFO write */ 8965aa0df40SMark Cave-Ayland if (esp_cdb_ready(s)) { 8978ba32048SMark Cave-Ayland /* Command has been received */ 8988ba32048SMark Cave-Ayland do_cmd(s); 8998ba32048SMark Cave-Ayland } 9008ba32048SMark Cave-Ayland break; 9018ba32048SMark Cave-Ayland 9025d02add4SMark Cave-Ayland case CMD_SEL: 9035d02add4SMark Cave-Ayland case CMD_SELATN: 904acdee66dSMark Cave-Ayland /* FIFO already contain entire CDB: copy to cmdfifo and execute */ 905da838126SMark Cave-Ayland len = esp_fifo_pop_buf(s, buf, fifo8_num_used(&s->fifo)); 9065a857339SMark Cave-Ayland len = MIN(fifo8_num_free(&s->cmdfifo), len); 9075a857339SMark Cave-Ayland fifo8_push_all(&s->cmdfifo, buf, len); 908acdee66dSMark Cave-Ayland 9095d02add4SMark Cave-Ayland do_cmd(s); 9105d02add4SMark Cave-Ayland break; 9115d02add4SMark Cave-Ayland } 91283e803deSMark Cave-Ayland break; 9131b9e48a5SMark Cave-Ayland 9149d1aa52bSMark Cave-Ayland case STAT_DO: 9155d02add4SMark Cave-Ayland /* Accumulate data in FIFO until non-DMA TI is executed */ 9169d1aa52bSMark Cave-Ayland break; 9179d1aa52bSMark Cave-Ayland 9189d1aa52bSMark Cave-Ayland case STAT_DI: 9199d1aa52bSMark Cave-Ayland if (!s->current_req) { 9209d1aa52bSMark Cave-Ayland return; 9219d1aa52bSMark Cave-Ayland } 9229d1aa52bSMark Cave-Ayland if (s->async_len == 0) { 9239d1aa52bSMark Cave-Ayland /* Defer until data is available. */ 9249d1aa52bSMark Cave-Ayland return; 9259d1aa52bSMark Cave-Ayland } 9266ef2cabcSMark Cave-Ayland if (fifo8_is_empty(&s->fifo)) { 9271f46d1c3SMark Cave-Ayland esp_fifo_push(s, s->async_buf[0]); 9286ef2cabcSMark Cave-Ayland s->async_buf++; 9296ef2cabcSMark Cave-Ayland s->async_len--; 9306ef2cabcSMark Cave-Ayland s->ti_size--; 9316ef2cabcSMark Cave-Ayland } 9321b9e48a5SMark Cave-Ayland 9331b9e48a5SMark Cave-Ayland if (s->async_len == 0) { 9341b9e48a5SMark Cave-Ayland scsi_req_continue(s->current_req); 9351b9e48a5SMark Cave-Ayland return; 9361b9e48a5SMark Cave-Ayland } 9371b9e48a5SMark Cave-Ayland 9389655f72cSMark Cave-Ayland /* If preloading the FIFO, defer until TI command issued */ 9399655f72cSMark Cave-Ayland if (s->rregs[ESP_CMD] != CMD_TI) { 9409655f72cSMark Cave-Ayland return; 9419655f72cSMark Cave-Ayland } 9429655f72cSMark Cave-Ayland 9431b9e48a5SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 9441b9e48a5SMark Cave-Ayland esp_raise_irq(s); 9459d1aa52bSMark Cave-Ayland break; 94683428f7aSMark Cave-Ayland 94783428f7aSMark Cave-Ayland case STAT_ST: 94883428f7aSMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 94983428f7aSMark Cave-Ayland case CMD_ICCS: 9501f46d1c3SMark Cave-Ayland esp_fifo_push(s, s->status); 95183428f7aSMark Cave-Ayland esp_set_phase(s, STAT_MI); 95283428f7aSMark Cave-Ayland 95383428f7aSMark Cave-Ayland /* Process any message in phase data */ 95483428f7aSMark Cave-Ayland esp_do_nodma(s); 95583428f7aSMark Cave-Ayland break; 95683428f7aSMark Cave-Ayland } 95783428f7aSMark Cave-Ayland break; 95883428f7aSMark Cave-Ayland 95983428f7aSMark Cave-Ayland case STAT_MI: 96083428f7aSMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 96183428f7aSMark Cave-Ayland case CMD_ICCS: 9621f46d1c3SMark Cave-Ayland esp_fifo_push(s, 0); 96383428f7aSMark Cave-Ayland 9640ee71db4SMark Cave-Ayland /* Raise end of command interrupt */ 9650ee71db4SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 96683428f7aSMark Cave-Ayland esp_raise_irq(s); 96783428f7aSMark Cave-Ayland break; 96883428f7aSMark Cave-Ayland } 96983428f7aSMark Cave-Ayland break; 9709d1aa52bSMark Cave-Ayland } 9711b9e48a5SMark Cave-Ayland } 9721b9e48a5SMark Cave-Ayland 9734aaa6ac3SMark Cave-Ayland void esp_command_complete(SCSIRequest *req, size_t resid) 974a917d384Spbrook { 9754aaa6ac3SMark Cave-Ayland ESPState *s = req->hba_private; 9765a83e83eSMark Cave-Ayland int to_device = (esp_get_phase(s) == STAT_DO); 9774aaa6ac3SMark Cave-Ayland 978bf4b9889SBlue Swirl trace_esp_command_complete(); 9796ef2cabcSMark Cave-Ayland 9806ef2cabcSMark Cave-Ayland /* 9816ef2cabcSMark Cave-Ayland * Non-DMA transfers from the target will leave the last byte in 9826ef2cabcSMark Cave-Ayland * the FIFO so don't reset ti_size in this case 9836ef2cabcSMark Cave-Ayland */ 9846ef2cabcSMark Cave-Ayland if (s->dma || to_device) { 985c6df7102SPaolo Bonzini if (s->ti_size != 0) { 986bf4b9889SBlue Swirl trace_esp_command_complete_unexpected(); 987c6df7102SPaolo Bonzini } 9886ef2cabcSMark Cave-Ayland } 9896ef2cabcSMark Cave-Ayland 990a917d384Spbrook s->async_len = 0; 9914aaa6ac3SMark Cave-Ayland if (req->status) { 992bf4b9889SBlue Swirl trace_esp_command_complete_fail(); 993c6df7102SPaolo Bonzini } 9944aaa6ac3SMark Cave-Ayland s->status = req->status; 9956ef2cabcSMark Cave-Ayland 9966ef2cabcSMark Cave-Ayland /* 997cb988199SMark Cave-Ayland * Switch to status phase. For non-DMA transfers from the target the last 998cb988199SMark Cave-Ayland * byte is still in the FIFO 9996ef2cabcSMark Cave-Ayland */ 10008bb22495SMark Cave-Ayland s->ti_size = 0; 10018bb22495SMark Cave-Ayland 10028bb22495SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 10038bb22495SMark Cave-Ayland case CMD_SEL | CMD_DMA: 10048bb22495SMark Cave-Ayland case CMD_SEL: 10058bb22495SMark Cave-Ayland case CMD_SELATN | CMD_DMA: 10068bb22495SMark Cave-Ayland case CMD_SELATN: 1007cb988199SMark Cave-Ayland /* 10088bb22495SMark Cave-Ayland * No data phase for sequencer command so raise deferred bus service 1009c90b2792SMark Cave-Ayland * and function complete interrupt 1010cb988199SMark Cave-Ayland */ 1011c90b2792SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 10129b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 10138bb22495SMark Cave-Ayland break; 1014cb22ce50SMark Cave-Ayland 1015cb22ce50SMark Cave-Ayland case CMD_TI | CMD_DMA: 1016cb22ce50SMark Cave-Ayland case CMD_TI: 1017cb22ce50SMark Cave-Ayland s->rregs[ESP_CMD] = 0; 1018cb22ce50SMark Cave-Ayland break; 10196ef2cabcSMark Cave-Ayland } 10206ef2cabcSMark Cave-Ayland 10218bb22495SMark Cave-Ayland /* Raise bus service interrupt to indicate change to STATUS phase */ 10228bb22495SMark Cave-Ayland esp_set_phase(s, STAT_ST); 10238bb22495SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 10248bb22495SMark Cave-Ayland esp_raise_irq(s); 102502a3ce56SMark Cave-Ayland 102602a3ce56SMark Cave-Ayland /* Ensure DRQ is set correctly for TC underflow or normal completion */ 102702a3ce56SMark Cave-Ayland esp_dma_ti_check(s); 10288bb22495SMark Cave-Ayland 10295c6c0e51SHannes Reinecke if (s->current_req) { 10305c6c0e51SHannes Reinecke scsi_req_unref(s->current_req); 10315c6c0e51SHannes Reinecke s->current_req = NULL; 1032a917d384Spbrook s->current_dev = NULL; 10335c6c0e51SHannes Reinecke } 1034c6df7102SPaolo Bonzini } 1035c6df7102SPaolo Bonzini 10369c7e23fcSHervé Poussineau void esp_transfer_data(SCSIRequest *req, uint32_t len) 1037c6df7102SPaolo Bonzini { 1038e6810db8SHervé Poussineau ESPState *s = req->hba_private; 10396cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 1040c6df7102SPaolo Bonzini 10416cc88d6bSMark Cave-Ayland trace_esp_transfer_data(dmalen, s->ti_size); 1042aba1f023SPaolo Bonzini s->async_len = len; 10430c34459bSPaolo Bonzini s->async_buf = scsi_req_get_buf(req); 10444e78f3bfSMark Cave-Ayland 1045c90b2792SMark Cave-Ayland if (!s->data_ready) { 1046a4608fa0SMark Cave-Ayland s->data_ready = true; 1047a4608fa0SMark Cave-Ayland 1048a4608fa0SMark Cave-Ayland switch (s->rregs[ESP_CMD]) { 1049a4608fa0SMark Cave-Ayland case CMD_SEL | CMD_DMA: 1050a4608fa0SMark Cave-Ayland case CMD_SEL: 1051a4608fa0SMark Cave-Ayland case CMD_SELATN | CMD_DMA: 1052a4608fa0SMark Cave-Ayland case CMD_SELATN: 1053c90b2792SMark Cave-Ayland /* 1054c90b2792SMark Cave-Ayland * Initial incoming data xfer is complete for sequencer command 1055c90b2792SMark Cave-Ayland * so raise deferred bus service and function complete interrupt 1056c90b2792SMark Cave-Ayland */ 1057c90b2792SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 10589b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 1059c90b2792SMark Cave-Ayland break; 1060c90b2792SMark Cave-Ayland 1061a4608fa0SMark Cave-Ayland case CMD_SELATNS | CMD_DMA: 1062a4608fa0SMark Cave-Ayland case CMD_SELATNS: 10634e78f3bfSMark Cave-Ayland /* 10644e78f3bfSMark Cave-Ayland * Initial incoming data xfer is complete so raise command 10654e78f3bfSMark Cave-Ayland * completion interrupt 10664e78f3bfSMark Cave-Ayland */ 10674e78f3bfSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 10689b2cdca2SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_MO; 1069a4608fa0SMark Cave-Ayland break; 1070a4608fa0SMark Cave-Ayland 1071a4608fa0SMark Cave-Ayland case CMD_TI | CMD_DMA: 1072a4608fa0SMark Cave-Ayland case CMD_TI: 1073a4608fa0SMark Cave-Ayland /* 1074a4608fa0SMark Cave-Ayland * Bus service interrupt raised because of initial change to 1075a4608fa0SMark Cave-Ayland * DATA phase 1076a4608fa0SMark Cave-Ayland */ 1077cb22ce50SMark Cave-Ayland s->rregs[ESP_CMD] = 0; 1078a4608fa0SMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 1079a4608fa0SMark Cave-Ayland break; 1080a4608fa0SMark Cave-Ayland } 1081c90b2792SMark Cave-Ayland 1082c90b2792SMark Cave-Ayland esp_raise_irq(s); 10834e78f3bfSMark Cave-Ayland } 10844e78f3bfSMark Cave-Ayland 10851b9e48a5SMark Cave-Ayland /* 10861b9e48a5SMark Cave-Ayland * Always perform the initial transfer upon reception of the next TI 10871b9e48a5SMark Cave-Ayland * command to ensure the DMA/non-DMA status of the command is correct. 10881b9e48a5SMark Cave-Ayland * It is not possible to use s->dma directly in the section below as 10891b9e48a5SMark Cave-Ayland * some OSs send non-DMA NOP commands after a DMA transfer. Hence if the 10901b9e48a5SMark Cave-Ayland * async data transfer is delayed then s->dma is set incorrectly. 10911b9e48a5SMark Cave-Ayland */ 10921b9e48a5SMark Cave-Ayland 109382003450SMark Cave-Ayland if (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA)) { 1094a79e767aSMark Cave-Ayland /* When the SCSI layer returns more data, raise deferred INTR_BS */ 1095004826d0SMark Cave-Ayland esp_dma_ti_check(s); 1096a79e767aSMark Cave-Ayland 1097a79e767aSMark Cave-Ayland esp_do_dma(s); 109882003450SMark Cave-Ayland } else if (s->rregs[ESP_CMD] == CMD_TI) { 10991b9e48a5SMark Cave-Ayland esp_do_nodma(s); 11001b9e48a5SMark Cave-Ayland } 1101a917d384Spbrook } 11022e5d83bbSpbrook 11032f275b8fSbellard static void handle_ti(ESPState *s) 11042f275b8fSbellard { 11051b9e48a5SMark Cave-Ayland uint32_t dmalen; 11062f275b8fSbellard 11077246e160SHervé Poussineau if (s->dma && !s->dma_enabled) { 11087246e160SHervé Poussineau s->dma_cb = handle_ti; 11097246e160SHervé Poussineau return; 11107246e160SHervé Poussineau } 11117246e160SHervé Poussineau 11124f6200f0Sbellard if (s->dma) { 11131b9e48a5SMark Cave-Ayland dmalen = esp_get_tc(s); 1114b76624deSMark Cave-Ayland trace_esp_handle_ti(dmalen); 11154d611c9aSpbrook esp_do_dma(s); 1116799d90d8SMark Cave-Ayland } else { 11171b9e48a5SMark Cave-Ayland trace_esp_handle_ti(s->ti_size); 11181b9e48a5SMark Cave-Ayland esp_do_nodma(s); 11195d02add4SMark Cave-Ayland 11205d02add4SMark Cave-Ayland if (esp_get_phase(s) == STAT_DO) { 11215d02add4SMark Cave-Ayland esp_nodma_ti_dataout(s); 11225d02add4SMark Cave-Ayland } 11234f6200f0Sbellard } 11242f275b8fSbellard } 11252f275b8fSbellard 11269c7e23fcSHervé Poussineau void esp_hard_reset(ESPState *s) 11276f7e9aecSbellard { 11285aca8c3bSblueswir1 memset(s->rregs, 0, ESP_REGS); 11295aca8c3bSblueswir1 memset(s->wregs, 0, ESP_REGS); 1130c9cf45c1SHannes Reinecke s->tchi_written = 0; 11314e9aec74Spbrook s->ti_size = 0; 11323f26c975SMark Cave-Ayland s->async_len = 0; 1133042879fcSMark Cave-Ayland fifo8_reset(&s->fifo); 1134023666daSMark Cave-Ayland fifo8_reset(&s->cmdfifo); 11354e9aec74Spbrook s->dma = 0; 113673d74342SBlue Swirl s->dma_cb = NULL; 11378dea1dd4Sblueswir1 11388dea1dd4Sblueswir1 s->rregs[ESP_CFG1] = 7; 11396f7e9aecSbellard } 11406f7e9aecSbellard 1141a391fdbcSHervé Poussineau static void esp_soft_reset(ESPState *s) 114285948643SBlue Swirl { 114385948643SBlue Swirl qemu_irq_lower(s->irq); 11446dec7c0dSMark Cave-Ayland qemu_irq_lower(s->drq_irq); 1145a391fdbcSHervé Poussineau esp_hard_reset(s); 114685948643SBlue Swirl } 114785948643SBlue Swirl 1148c6e51f1bSJohn Millikin static void esp_bus_reset(ESPState *s) 1149c6e51f1bSJohn Millikin { 11504a5fc890SPeter Maydell bus_cold_reset(BUS(&s->bus)); 1151c6e51f1bSJohn Millikin } 1152c6e51f1bSJohn Millikin 1153a391fdbcSHervé Poussineau static void parent_esp_reset(ESPState *s, int irq, int level) 11542d069babSblueswir1 { 115585948643SBlue Swirl if (level) { 1156a391fdbcSHervé Poussineau esp_soft_reset(s); 115785948643SBlue Swirl } 11582d069babSblueswir1 } 11592d069babSblueswir1 1160f21fe39dSMark Cave-Ayland static void esp_run_cmd(ESPState *s) 1161f21fe39dSMark Cave-Ayland { 1162f21fe39dSMark Cave-Ayland uint8_t cmd = s->rregs[ESP_CMD]; 1163f21fe39dSMark Cave-Ayland 1164f21fe39dSMark Cave-Ayland if (cmd & CMD_DMA) { 1165f21fe39dSMark Cave-Ayland s->dma = 1; 1166f21fe39dSMark Cave-Ayland /* Reload DMA counter. */ 1167f21fe39dSMark Cave-Ayland if (esp_get_stc(s) == 0) { 1168f21fe39dSMark Cave-Ayland esp_set_tc(s, 0x10000); 1169f21fe39dSMark Cave-Ayland } else { 1170f21fe39dSMark Cave-Ayland esp_set_tc(s, esp_get_stc(s)); 1171f21fe39dSMark Cave-Ayland } 1172f21fe39dSMark Cave-Ayland } else { 1173f21fe39dSMark Cave-Ayland s->dma = 0; 1174f21fe39dSMark Cave-Ayland } 1175f21fe39dSMark Cave-Ayland switch (cmd & CMD_CMD) { 1176f21fe39dSMark Cave-Ayland case CMD_NOP: 1177f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_nop(cmd); 1178f21fe39dSMark Cave-Ayland break; 1179f21fe39dSMark Cave-Ayland case CMD_FLUSH: 1180f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_flush(cmd); 1181f21fe39dSMark Cave-Ayland fifo8_reset(&s->fifo); 1182f21fe39dSMark Cave-Ayland break; 1183f21fe39dSMark Cave-Ayland case CMD_RESET: 1184f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_reset(cmd); 1185f21fe39dSMark Cave-Ayland esp_soft_reset(s); 1186f21fe39dSMark Cave-Ayland break; 1187f21fe39dSMark Cave-Ayland case CMD_BUSRESET: 1188f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_bus_reset(cmd); 1189f21fe39dSMark Cave-Ayland esp_bus_reset(s); 1190f21fe39dSMark Cave-Ayland if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { 1191f21fe39dSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_RST; 1192f21fe39dSMark Cave-Ayland esp_raise_irq(s); 1193f21fe39dSMark Cave-Ayland } 1194f21fe39dSMark Cave-Ayland break; 1195f21fe39dSMark Cave-Ayland case CMD_TI: 1196f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_ti(cmd); 1197f21fe39dSMark Cave-Ayland handle_ti(s); 1198f21fe39dSMark Cave-Ayland break; 1199f21fe39dSMark Cave-Ayland case CMD_ICCS: 1200f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_iccs(cmd); 1201f21fe39dSMark Cave-Ayland write_response(s); 1202f21fe39dSMark Cave-Ayland break; 1203f21fe39dSMark Cave-Ayland case CMD_MSGACC: 1204f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_msgacc(cmd); 1205f21fe39dSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_DC; 1206f21fe39dSMark Cave-Ayland s->rregs[ESP_RSEQ] = 0; 1207f21fe39dSMark Cave-Ayland s->rregs[ESP_RFLAGS] = 0; 1208f21fe39dSMark Cave-Ayland esp_raise_irq(s); 1209f21fe39dSMark Cave-Ayland break; 1210f21fe39dSMark Cave-Ayland case CMD_PAD: 1211f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_pad(cmd); 1212a6cad7cdSMark Cave-Ayland handle_pad(s); 1213f21fe39dSMark Cave-Ayland break; 1214f21fe39dSMark Cave-Ayland case CMD_SATN: 1215f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_satn(cmd); 1216f21fe39dSMark Cave-Ayland break; 1217f21fe39dSMark Cave-Ayland case CMD_RSTATN: 1218f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_rstatn(cmd); 1219f21fe39dSMark Cave-Ayland break; 1220f21fe39dSMark Cave-Ayland case CMD_SEL: 1221f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_sel(cmd); 1222f21fe39dSMark Cave-Ayland handle_s_without_atn(s); 1223f21fe39dSMark Cave-Ayland break; 1224f21fe39dSMark Cave-Ayland case CMD_SELATN: 1225f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_selatn(cmd); 1226f21fe39dSMark Cave-Ayland handle_satn(s); 1227f21fe39dSMark Cave-Ayland break; 1228f21fe39dSMark Cave-Ayland case CMD_SELATNS: 1229f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_selatns(cmd); 1230f21fe39dSMark Cave-Ayland handle_satn_stop(s); 1231f21fe39dSMark Cave-Ayland break; 1232f21fe39dSMark Cave-Ayland case CMD_ENSEL: 1233f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_ensel(cmd); 1234f21fe39dSMark Cave-Ayland s->rregs[ESP_RINTR] = 0; 1235f21fe39dSMark Cave-Ayland break; 1236f21fe39dSMark Cave-Ayland case CMD_DISSEL: 1237f21fe39dSMark Cave-Ayland trace_esp_mem_writeb_cmd_dissel(cmd); 1238f21fe39dSMark Cave-Ayland s->rregs[ESP_RINTR] = 0; 1239f21fe39dSMark Cave-Ayland esp_raise_irq(s); 1240f21fe39dSMark Cave-Ayland break; 1241f21fe39dSMark Cave-Ayland default: 1242f21fe39dSMark Cave-Ayland trace_esp_error_unhandled_command(cmd); 1243f21fe39dSMark Cave-Ayland break; 1244f21fe39dSMark Cave-Ayland } 1245f21fe39dSMark Cave-Ayland } 1246f21fe39dSMark Cave-Ayland 12479c7e23fcSHervé Poussineau uint64_t esp_reg_read(ESPState *s, uint32_t saddr) 124873d74342SBlue Swirl { 1249b630c075SMark Cave-Ayland uint32_t val; 125073d74342SBlue Swirl 12516f7e9aecSbellard switch (saddr) { 12525ad6bb97Sblueswir1 case ESP_FIFO: 125361fa150dSMark Cave-Ayland s->rregs[ESP_FIFO] = esp_fifo_pop(s); 1254b630c075SMark Cave-Ayland val = s->rregs[ESP_FIFO]; 12554f6200f0Sbellard break; 12565ad6bb97Sblueswir1 case ESP_RINTR: 125794d5c79dSMark Cave-Ayland /* 125894d5c79dSMark Cave-Ayland * Clear sequence step, interrupt register and all status bits 125994d5c79dSMark Cave-Ayland * except TC 126094d5c79dSMark Cave-Ayland */ 1261b630c075SMark Cave-Ayland val = s->rregs[ESP_RINTR]; 12622814df28SBlue Swirl s->rregs[ESP_RINTR] = 0; 1263d294b77aSMark Cave-Ayland esp_lower_irq(s); 1264d68212cdSMark Cave-Ayland s->rregs[ESP_RSTAT] &= STAT_TC | 7; 1265af947a3dSMark Cave-Ayland /* 1266af947a3dSMark Cave-Ayland * According to the datasheet ESP_RSEQ should be cleared, but as the 1267af947a3dSMark Cave-Ayland * emulation currently defers information transfers to the next TI 1268af947a3dSMark Cave-Ayland * command leave it for now so that pedantic guests such as the old 1269af947a3dSMark Cave-Ayland * Linux 2.6 driver see the correct flags before the next SCSI phase 1270af947a3dSMark Cave-Ayland * transition. 1271af947a3dSMark Cave-Ayland * 1272af947a3dSMark Cave-Ayland * s->rregs[ESP_RSEQ] = SEQ_0; 1273af947a3dSMark Cave-Ayland */ 1274b630c075SMark Cave-Ayland break; 1275c9cf45c1SHannes Reinecke case ESP_TCHI: 1276c9cf45c1SHannes Reinecke /* Return the unique id if the value has never been written */ 1277c9cf45c1SHannes Reinecke if (!s->tchi_written) { 1278b630c075SMark Cave-Ayland val = s->chip_id; 1279b630c075SMark Cave-Ayland } else { 1280b630c075SMark Cave-Ayland val = s->rregs[saddr]; 1281c9cf45c1SHannes Reinecke } 1282b630c075SMark Cave-Ayland break; 1283238ec4d7SMark Cave-Ayland case ESP_RFLAGS: 1284238ec4d7SMark Cave-Ayland /* Bottom 5 bits indicate number of bytes in FIFO */ 1285238ec4d7SMark Cave-Ayland val = fifo8_num_used(&s->fifo); 1286238ec4d7SMark Cave-Ayland break; 12876f7e9aecSbellard default: 1288b630c075SMark Cave-Ayland val = s->rregs[saddr]; 12896f7e9aecSbellard break; 12906f7e9aecSbellard } 1291b630c075SMark Cave-Ayland 1292b630c075SMark Cave-Ayland trace_esp_mem_readb(saddr, val); 1293b630c075SMark Cave-Ayland return val; 12946f7e9aecSbellard } 12956f7e9aecSbellard 12969c7e23fcSHervé Poussineau void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) 12976f7e9aecSbellard { 1298bf4b9889SBlue Swirl trace_esp_mem_writeb(saddr, s->wregs[saddr], val); 12996f7e9aecSbellard switch (saddr) { 1300c9cf45c1SHannes Reinecke case ESP_TCHI: 1301c9cf45c1SHannes Reinecke s->tchi_written = true; 1302c9cf45c1SHannes Reinecke /* fall through */ 13035ad6bb97Sblueswir1 case ESP_TCLO: 13045ad6bb97Sblueswir1 case ESP_TCMID: 13055ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 13064f6200f0Sbellard break; 13075ad6bb97Sblueswir1 case ESP_FIFO: 13082572689bSMark Cave-Ayland if (!fifo8_is_full(&s->fifo)) { 13090e7dbe29SMark Cave-Ayland esp_fifo_push(s, val); 13102572689bSMark Cave-Ayland } 13115d02add4SMark Cave-Ayland esp_do_nodma(s); 13124f6200f0Sbellard break; 13135ad6bb97Sblueswir1 case ESP_CMD: 13144f6200f0Sbellard s->rregs[saddr] = val; 1315f21fe39dSMark Cave-Ayland esp_run_cmd(s); 13166f7e9aecSbellard break; 13175ad6bb97Sblueswir1 case ESP_WBUSID ... ESP_WSYNO: 13184f6200f0Sbellard break; 13195ad6bb97Sblueswir1 case ESP_CFG1: 13209ea73f8bSPaolo Bonzini case ESP_CFG2: case ESP_CFG3: 13219ea73f8bSPaolo Bonzini case ESP_RES3: case ESP_RES4: 13224f6200f0Sbellard s->rregs[saddr] = val; 13234f6200f0Sbellard break; 13245ad6bb97Sblueswir1 case ESP_WCCF ... ESP_WTEST: 13254f6200f0Sbellard break; 13266f7e9aecSbellard default: 13273af4e9aaSHervé Poussineau trace_esp_error_invalid_write(val, saddr); 13288dea1dd4Sblueswir1 return; 13296f7e9aecSbellard } 13302f275b8fSbellard s->wregs[saddr] = val; 13316f7e9aecSbellard } 13326f7e9aecSbellard 1333a8170e5eSAvi Kivity static bool esp_mem_accepts(void *opaque, hwaddr addr, 13348372d383SPeter Maydell unsigned size, bool is_write, 13358372d383SPeter Maydell MemTxAttrs attrs) 133667bb5314SAvi Kivity { 133767bb5314SAvi Kivity return (size == 1) || (is_write && size == 4); 133867bb5314SAvi Kivity } 13396f7e9aecSbellard 13406cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id) 13416cc88d6bSMark Cave-Ayland { 13426cc88d6bSMark Cave-Ayland ESPState *s = ESP(opaque); 13436cc88d6bSMark Cave-Ayland 13446cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 13456cc88d6bSMark Cave-Ayland return version_id < 5; 13466cc88d6bSMark Cave-Ayland } 13476cc88d6bSMark Cave-Ayland 13484e78f3bfSMark Cave-Ayland static bool esp_is_version_5(void *opaque, int version_id) 13494e78f3bfSMark Cave-Ayland { 13504e78f3bfSMark Cave-Ayland ESPState *s = ESP(opaque); 13514e78f3bfSMark Cave-Ayland 13524e78f3bfSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 13530bcd5a18SMark Cave-Ayland return version_id >= 5; 13544e78f3bfSMark Cave-Ayland } 13554e78f3bfSMark Cave-Ayland 13564eb86065SPaolo Bonzini static bool esp_is_version_6(void *opaque, int version_id) 13574eb86065SPaolo Bonzini { 13584eb86065SPaolo Bonzini ESPState *s = ESP(opaque); 13594eb86065SPaolo Bonzini 13604eb86065SPaolo Bonzini version_id = MIN(version_id, s->mig_version_id); 13614eb86065SPaolo Bonzini return version_id >= 6; 13624eb86065SPaolo Bonzini } 13634eb86065SPaolo Bonzini 136482003450SMark Cave-Ayland static bool esp_is_between_version_5_and_6(void *opaque, int version_id) 136582003450SMark Cave-Ayland { 136682003450SMark Cave-Ayland ESPState *s = ESP(opaque); 136782003450SMark Cave-Ayland 136882003450SMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 136982003450SMark Cave-Ayland return version_id >= 5 && version_id <= 6; 137082003450SMark Cave-Ayland } 137182003450SMark Cave-Ayland 1372ff4a1dabSMark Cave-Ayland int esp_pre_save(void *opaque) 13730bd005beSMark Cave-Ayland { 1374ff4a1dabSMark Cave-Ayland ESPState *s = ESP(object_resolve_path_component( 1375ff4a1dabSMark Cave-Ayland OBJECT(opaque), "esp")); 13760bd005beSMark Cave-Ayland 13770bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 13780bd005beSMark Cave-Ayland return 0; 13790bd005beSMark Cave-Ayland } 13800bd005beSMark Cave-Ayland 13810bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id) 13820bd005beSMark Cave-Ayland { 13830bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 1384042879fcSMark Cave-Ayland int len, i; 13850bd005beSMark Cave-Ayland 13866cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 13876cc88d6bSMark Cave-Ayland 13886cc88d6bSMark Cave-Ayland if (version_id < 5) { 13896cc88d6bSMark Cave-Ayland esp_set_tc(s, s->mig_dma_left); 1390042879fcSMark Cave-Ayland 1391042879fcSMark Cave-Ayland /* Migrate ti_buf to fifo */ 1392042879fcSMark Cave-Ayland len = s->mig_ti_wptr - s->mig_ti_rptr; 1393042879fcSMark Cave-Ayland for (i = 0; i < len; i++) { 1394042879fcSMark Cave-Ayland fifo8_push(&s->fifo, s->mig_ti_buf[i]); 1395042879fcSMark Cave-Ayland } 1396023666daSMark Cave-Ayland 1397023666daSMark Cave-Ayland /* Migrate cmdbuf to cmdfifo */ 1398023666daSMark Cave-Ayland for (i = 0; i < s->mig_cmdlen; i++) { 1399023666daSMark Cave-Ayland fifo8_push(&s->cmdfifo, s->mig_cmdbuf[i]); 1400023666daSMark Cave-Ayland } 14016cc88d6bSMark Cave-Ayland } 14026cc88d6bSMark Cave-Ayland 14030bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 14040bd005beSMark Cave-Ayland return 0; 14050bd005beSMark Cave-Ayland } 14060bd005beSMark Cave-Ayland 14079c7e23fcSHervé Poussineau const VMStateDescription vmstate_esp = { 1408cc9952f3SBlue Swirl .name = "esp", 140982003450SMark Cave-Ayland .version_id = 7, 1410cc9952f3SBlue Swirl .minimum_version_id = 3, 14110bd005beSMark Cave-Ayland .post_load = esp_post_load, 14122d7b39a6SRichard Henderson .fields = (const VMStateField[]) { 1413cc9952f3SBlue Swirl VMSTATE_BUFFER(rregs, ESPState), 1414cc9952f3SBlue Swirl VMSTATE_BUFFER(wregs, ESPState), 1415cc9952f3SBlue Swirl VMSTATE_INT32(ti_size, ESPState), 1416042879fcSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_ti_rptr, ESPState, esp_is_before_version_5), 1417042879fcSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_ti_wptr, ESPState, esp_is_before_version_5), 1418042879fcSMark Cave-Ayland VMSTATE_BUFFER_TEST(mig_ti_buf, ESPState, esp_is_before_version_5), 14193944966dSPaolo Bonzini VMSTATE_UINT32(status, ESPState), 14204aaa6ac3SMark Cave-Ayland VMSTATE_UINT32_TEST(mig_deferred_status, ESPState, 14214aaa6ac3SMark Cave-Ayland esp_is_before_version_5), 14224aaa6ac3SMark Cave-Ayland VMSTATE_BOOL_TEST(mig_deferred_complete, ESPState, 14234aaa6ac3SMark Cave-Ayland esp_is_before_version_5), 1424cc9952f3SBlue Swirl VMSTATE_UINT32(dma, ESPState), 1425023666daSMark Cave-Ayland VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 0, 1426023666daSMark Cave-Ayland esp_is_before_version_5, 0, 16), 1427023666daSMark Cave-Ayland VMSTATE_STATIC_BUFFER(mig_cmdbuf, ESPState, 4, 1428023666daSMark Cave-Ayland esp_is_before_version_5, 16, 1429023666daSMark Cave-Ayland sizeof(typeof_field(ESPState, mig_cmdbuf))), 1430023666daSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_cmdlen, ESPState, esp_is_before_version_5), 1431cc9952f3SBlue Swirl VMSTATE_UINT32(do_cmd, ESPState), 14326cc88d6bSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5), 14338dded6deSMark Cave-Ayland VMSTATE_BOOL_TEST(data_ready, ESPState, esp_is_version_5), 1434023666daSMark Cave-Ayland VMSTATE_UINT8_TEST(cmdfifo_cdb_offset, ESPState, esp_is_version_5), 1435042879fcSMark Cave-Ayland VMSTATE_FIFO8_TEST(fifo, ESPState, esp_is_version_5), 1436023666daSMark Cave-Ayland VMSTATE_FIFO8_TEST(cmdfifo, ESPState, esp_is_version_5), 143782003450SMark Cave-Ayland VMSTATE_UINT8_TEST(mig_ti_cmd, ESPState, 143882003450SMark Cave-Ayland esp_is_between_version_5_and_6), 14394eb86065SPaolo Bonzini VMSTATE_UINT8_TEST(lun, ESPState, esp_is_version_6), 1440442de89aSMark Cave-Ayland VMSTATE_BOOL(drq_state, ESPState), 1441cc9952f3SBlue Swirl VMSTATE_END_OF_LIST() 144274d71ea1SLaurent Vivier }, 1443cc9952f3SBlue Swirl }; 14446f7e9aecSbellard 1445a8170e5eSAvi Kivity static void sysbus_esp_mem_write(void *opaque, hwaddr addr, 1446a391fdbcSHervé Poussineau uint64_t val, unsigned int size) 1447a391fdbcSHervé Poussineau { 1448a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 1449eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1450a391fdbcSHervé Poussineau uint32_t saddr; 1451a391fdbcSHervé Poussineau 1452a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 1453eb169c76SMark Cave-Ayland esp_reg_write(s, saddr, val); 1454a391fdbcSHervé Poussineau } 1455a391fdbcSHervé Poussineau 1456a8170e5eSAvi Kivity static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, 1457a391fdbcSHervé Poussineau unsigned int size) 1458a391fdbcSHervé Poussineau { 1459a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 1460eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1461a391fdbcSHervé Poussineau uint32_t saddr; 1462a391fdbcSHervé Poussineau 1463a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 1464eb169c76SMark Cave-Ayland return esp_reg_read(s, saddr); 1465a391fdbcSHervé Poussineau } 1466a391fdbcSHervé Poussineau 1467a391fdbcSHervé Poussineau static const MemoryRegionOps sysbus_esp_mem_ops = { 1468a391fdbcSHervé Poussineau .read = sysbus_esp_mem_read, 1469a391fdbcSHervé Poussineau .write = sysbus_esp_mem_write, 1470a391fdbcSHervé Poussineau .endianness = DEVICE_NATIVE_ENDIAN, 1471a391fdbcSHervé Poussineau .valid.accepts = esp_mem_accepts, 1472a391fdbcSHervé Poussineau }; 1473a391fdbcSHervé Poussineau 147474d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 147574d71ea1SLaurent Vivier uint64_t val, unsigned int size) 147674d71ea1SLaurent Vivier { 147774d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 1478eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 147974d71ea1SLaurent Vivier 1480960ebfd9SMark Cave-Ayland trace_esp_pdma_write(size); 1481960ebfd9SMark Cave-Ayland 148274d71ea1SLaurent Vivier switch (size) { 148374d71ea1SLaurent Vivier case 1: 1484761bef75SMark Cave-Ayland esp_pdma_write(s, val); 148574d71ea1SLaurent Vivier break; 148674d71ea1SLaurent Vivier case 2: 1487761bef75SMark Cave-Ayland esp_pdma_write(s, val >> 8); 1488761bef75SMark Cave-Ayland esp_pdma_write(s, val); 148974d71ea1SLaurent Vivier break; 149074d71ea1SLaurent Vivier } 1491b46a43a2SMark Cave-Ayland esp_do_dma(s); 149274d71ea1SLaurent Vivier } 149374d71ea1SLaurent Vivier 149474d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 149574d71ea1SLaurent Vivier unsigned int size) 149674d71ea1SLaurent Vivier { 149774d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 1498eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 149974d71ea1SLaurent Vivier uint64_t val = 0; 150074d71ea1SLaurent Vivier 1501960ebfd9SMark Cave-Ayland trace_esp_pdma_read(size); 1502960ebfd9SMark Cave-Ayland 150374d71ea1SLaurent Vivier switch (size) { 150474d71ea1SLaurent Vivier case 1: 1505761bef75SMark Cave-Ayland val = esp_pdma_read(s); 150674d71ea1SLaurent Vivier break; 150774d71ea1SLaurent Vivier case 2: 1508761bef75SMark Cave-Ayland val = esp_pdma_read(s); 1509761bef75SMark Cave-Ayland val = (val << 8) | esp_pdma_read(s); 151074d71ea1SLaurent Vivier break; 151174d71ea1SLaurent Vivier } 1512b46a43a2SMark Cave-Ayland esp_do_dma(s); 151374d71ea1SLaurent Vivier return val; 151474d71ea1SLaurent Vivier } 151574d71ea1SLaurent Vivier 1516a7a22088SMark Cave-Ayland static void *esp_load_request(QEMUFile *f, SCSIRequest *req) 1517a7a22088SMark Cave-Ayland { 1518a7a22088SMark Cave-Ayland ESPState *s = container_of(req->bus, ESPState, bus); 1519a7a22088SMark Cave-Ayland 1520a7a22088SMark Cave-Ayland scsi_req_ref(req); 1521a7a22088SMark Cave-Ayland s->current_req = req; 1522a7a22088SMark Cave-Ayland return s; 1523a7a22088SMark Cave-Ayland } 1524a7a22088SMark Cave-Ayland 152574d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = { 152674d71ea1SLaurent Vivier .read = sysbus_esp_pdma_read, 152774d71ea1SLaurent Vivier .write = sysbus_esp_pdma_write, 152874d71ea1SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 152974d71ea1SLaurent Vivier .valid.min_access_size = 1, 1530cf1b8286SMark Cave-Ayland .valid.max_access_size = 4, 1531cf1b8286SMark Cave-Ayland .impl.min_access_size = 1, 1532cf1b8286SMark Cave-Ayland .impl.max_access_size = 2, 153374d71ea1SLaurent Vivier }; 153474d71ea1SLaurent Vivier 1535afd4030cSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = { 1536afd4030cSPaolo Bonzini .tcq = false, 15377e0380b9SPaolo Bonzini .max_target = ESP_MAX_DEVS, 15387e0380b9SPaolo Bonzini .max_lun = 7, 1539afd4030cSPaolo Bonzini 1540a7a22088SMark Cave-Ayland .load_request = esp_load_request, 1541c6df7102SPaolo Bonzini .transfer_data = esp_transfer_data, 154294d3f98aSPaolo Bonzini .complete = esp_command_complete, 154394d3f98aSPaolo Bonzini .cancel = esp_request_cancelled 1544cfdc1bb0SPaolo Bonzini }; 1545cfdc1bb0SPaolo Bonzini 1546a391fdbcSHervé Poussineau static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) 1547cfb9de9cSPaul Brook { 154884fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(opaque); 1549eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1550a391fdbcSHervé Poussineau 1551a391fdbcSHervé Poussineau switch (irq) { 1552a391fdbcSHervé Poussineau case 0: 1553a391fdbcSHervé Poussineau parent_esp_reset(s, irq, level); 1554a391fdbcSHervé Poussineau break; 1555a391fdbcSHervé Poussineau case 1: 1556b86dc5cbSMark Cave-Ayland esp_dma_enable(s, irq, level); 1557a391fdbcSHervé Poussineau break; 1558a391fdbcSHervé Poussineau } 1559a391fdbcSHervé Poussineau } 1560a391fdbcSHervé Poussineau 1561b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp) 1562a391fdbcSHervé Poussineau { 1563b09318caSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 156484fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1565eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1566eb169c76SMark Cave-Ayland 1567eb169c76SMark Cave-Ayland if (!qdev_realize(DEVICE(s), NULL, errp)) { 1568eb169c76SMark Cave-Ayland return; 1569eb169c76SMark Cave-Ayland } 15706f7e9aecSbellard 1571b09318caSHu Tao sysbus_init_irq(sbd, &s->irq); 15726dec7c0dSMark Cave-Ayland sysbus_init_irq(sbd, &s->drq_irq); 1573a391fdbcSHervé Poussineau assert(sysbus->it_shift != -1); 15746f7e9aecSbellard 1575d32e4b3dSHervé Poussineau s->chip_id = TCHI_FAS100A; 157629776739SPaolo Bonzini memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 157774d71ea1SLaurent Vivier sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 1578b09318caSHu Tao sysbus_init_mmio(sbd, &sysbus->iomem); 157974d71ea1SLaurent Vivier memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 1580cf1b8286SMark Cave-Ayland sysbus, "esp-pdma", 4); 158174d71ea1SLaurent Vivier sysbus_init_mmio(sbd, &sysbus->pdma); 15826f7e9aecSbellard 1583b09318caSHu Tao qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 15842d069babSblueswir1 1585739e95f5SPeter Maydell scsi_bus_init(&s->bus, sizeof(s->bus), dev, &esp_scsi_info); 158667e999beSbellard } 1587cfb9de9cSPaul Brook 1588a391fdbcSHervé Poussineau static void sysbus_esp_hard_reset(DeviceState *dev) 1589a391fdbcSHervé Poussineau { 159084fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1591eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1592eb169c76SMark Cave-Ayland 1593eb169c76SMark Cave-Ayland esp_hard_reset(s); 1594eb169c76SMark Cave-Ayland } 1595eb169c76SMark Cave-Ayland 1596eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj) 1597eb169c76SMark Cave-Ayland { 1598eb169c76SMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(obj); 1599eb169c76SMark Cave-Ayland 1600eb169c76SMark Cave-Ayland object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP); 1601a391fdbcSHervé Poussineau } 1602a391fdbcSHervé Poussineau 1603a391fdbcSHervé Poussineau static const VMStateDescription vmstate_sysbus_esp_scsi = { 1604a391fdbcSHervé Poussineau .name = "sysbusespscsi", 16050bd005beSMark Cave-Ayland .version_id = 2, 1606ea84a442SGuenter Roeck .minimum_version_id = 1, 1607ff4a1dabSMark Cave-Ayland .pre_save = esp_pre_save, 16082d7b39a6SRichard Henderson .fields = (const VMStateField[]) { 16090bd005beSMark Cave-Ayland VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2), 1610a391fdbcSHervé Poussineau VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), 1611a391fdbcSHervé Poussineau VMSTATE_END_OF_LIST() 1612a391fdbcSHervé Poussineau } 1613999e12bbSAnthony Liguori }; 1614999e12bbSAnthony Liguori 1615a391fdbcSHervé Poussineau static void sysbus_esp_class_init(ObjectClass *klass, void *data) 1616999e12bbSAnthony Liguori { 161739bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1618999e12bbSAnthony Liguori 1619b09318caSHu Tao dc->realize = sysbus_esp_realize; 1620a391fdbcSHervé Poussineau dc->reset = sysbus_esp_hard_reset; 1621a391fdbcSHervé Poussineau dc->vmsd = &vmstate_sysbus_esp_scsi; 1622125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 162363235df8SBlue Swirl } 1624999e12bbSAnthony Liguori 1625042879fcSMark Cave-Ayland static void esp_finalize(Object *obj) 1626042879fcSMark Cave-Ayland { 1627042879fcSMark Cave-Ayland ESPState *s = ESP(obj); 1628042879fcSMark Cave-Ayland 1629042879fcSMark Cave-Ayland fifo8_destroy(&s->fifo); 1630023666daSMark Cave-Ayland fifo8_destroy(&s->cmdfifo); 1631042879fcSMark Cave-Ayland } 1632042879fcSMark Cave-Ayland 1633042879fcSMark Cave-Ayland static void esp_init(Object *obj) 1634042879fcSMark Cave-Ayland { 1635042879fcSMark Cave-Ayland ESPState *s = ESP(obj); 1636042879fcSMark Cave-Ayland 1637042879fcSMark Cave-Ayland fifo8_create(&s->fifo, ESP_FIFO_SZ); 1638023666daSMark Cave-Ayland fifo8_create(&s->cmdfifo, ESP_CMDFIFO_SZ); 1639042879fcSMark Cave-Ayland } 1640042879fcSMark Cave-Ayland 1641eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data) 1642eb169c76SMark Cave-Ayland { 1643eb169c76SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1644eb169c76SMark Cave-Ayland 1645eb169c76SMark Cave-Ayland /* internal device for sysbusesp/pciespscsi, not user-creatable */ 1646eb169c76SMark Cave-Ayland dc->user_creatable = false; 1647eb169c76SMark Cave-Ayland set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1648eb169c76SMark Cave-Ayland } 1649eb169c76SMark Cave-Ayland 1650499f4089SMark Cave-Ayland static const TypeInfo esp_info_types[] = { 1651499f4089SMark Cave-Ayland { 1652499f4089SMark Cave-Ayland .name = TYPE_SYSBUS_ESP, 1653499f4089SMark Cave-Ayland .parent = TYPE_SYS_BUS_DEVICE, 1654499f4089SMark Cave-Ayland .instance_init = sysbus_esp_init, 1655499f4089SMark Cave-Ayland .instance_size = sizeof(SysBusESPState), 1656499f4089SMark Cave-Ayland .class_init = sysbus_esp_class_init, 1657499f4089SMark Cave-Ayland }, 1658499f4089SMark Cave-Ayland { 1659eb169c76SMark Cave-Ayland .name = TYPE_ESP, 1660eb169c76SMark Cave-Ayland .parent = TYPE_DEVICE, 1661042879fcSMark Cave-Ayland .instance_init = esp_init, 1662042879fcSMark Cave-Ayland .instance_finalize = esp_finalize, 1663eb169c76SMark Cave-Ayland .instance_size = sizeof(ESPState), 1664eb169c76SMark Cave-Ayland .class_init = esp_class_init, 1665499f4089SMark Cave-Ayland }, 1666eb169c76SMark Cave-Ayland }; 1667eb169c76SMark Cave-Ayland 1668499f4089SMark Cave-Ayland DEFINE_TYPES(esp_info_types) 1669