16f7e9aecSbellard /* 267e999beSbellard * QEMU ESP/NCR53C9x emulation 36f7e9aecSbellard * 44e9aec74Spbrook * Copyright (c) 2005-2006 Fabrice Bellard 5fabaaf1dSHervé Poussineau * Copyright (c) 2012 Herve Poussineau 66f7e9aecSbellard * 76f7e9aecSbellard * Permission is hereby granted, free of charge, to any person obtaining a copy 86f7e9aecSbellard * of this software and associated documentation files (the "Software"), to deal 96f7e9aecSbellard * in the Software without restriction, including without limitation the rights 106f7e9aecSbellard * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 116f7e9aecSbellard * copies of the Software, and to permit persons to whom the Software is 126f7e9aecSbellard * furnished to do so, subject to the following conditions: 136f7e9aecSbellard * 146f7e9aecSbellard * The above copyright notice and this permission notice shall be included in 156f7e9aecSbellard * all copies or substantial portions of the Software. 166f7e9aecSbellard * 176f7e9aecSbellard * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 186f7e9aecSbellard * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 196f7e9aecSbellard * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 206f7e9aecSbellard * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 216f7e9aecSbellard * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 226f7e9aecSbellard * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 236f7e9aecSbellard * THE SOFTWARE. 246f7e9aecSbellard */ 255d20fa6bSblueswir1 26a4ab4792SPeter Maydell #include "qemu/osdep.h" 2783c9f4caSPaolo Bonzini #include "hw/sysbus.h" 28d6454270SMarkus Armbruster #include "migration/vmstate.h" 2964552b6bSMarkus Armbruster #include "hw/irq.h" 300d09e41aSPaolo Bonzini #include "hw/scsi/esp.h" 31bf4b9889SBlue Swirl #include "trace.h" 321de7afc9SPaolo Bonzini #include "qemu/log.h" 330b8fa32fSMarkus Armbruster #include "qemu/module.h" 346f7e9aecSbellard 3567e999beSbellard /* 365ad6bb97Sblueswir1 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O), 375ad6bb97Sblueswir1 * also produced as NCR89C100. See 3867e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt 3967e999beSbellard * and 4067e999beSbellard * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt 4174d71ea1SLaurent Vivier * 4274d71ea1SLaurent Vivier * On Macintosh Quadra it is a NCR53C96. 4367e999beSbellard */ 4467e999beSbellard 45c73f96fdSblueswir1 static void esp_raise_irq(ESPState *s) 46c73f96fdSblueswir1 { 47c73f96fdSblueswir1 if (!(s->rregs[ESP_RSTAT] & STAT_INT)) { 48c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_INT; 49c73f96fdSblueswir1 qemu_irq_raise(s->irq); 50bf4b9889SBlue Swirl trace_esp_raise_irq(); 51c73f96fdSblueswir1 } 52c73f96fdSblueswir1 } 53c73f96fdSblueswir1 54c73f96fdSblueswir1 static void esp_lower_irq(ESPState *s) 55c73f96fdSblueswir1 { 56c73f96fdSblueswir1 if (s->rregs[ESP_RSTAT] & STAT_INT) { 57c73f96fdSblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_INT; 58c73f96fdSblueswir1 qemu_irq_lower(s->irq); 59bf4b9889SBlue Swirl trace_esp_lower_irq(); 60c73f96fdSblueswir1 } 61c73f96fdSblueswir1 } 62c73f96fdSblueswir1 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 759c7e23fcSHervé Poussineau void esp_dma_enable(ESPState *s, int irq, int level) 7673d74342SBlue Swirl { 7773d74342SBlue Swirl if (level) { 7873d74342SBlue Swirl s->dma_enabled = 1; 79bf4b9889SBlue Swirl trace_esp_dma_enable(); 8073d74342SBlue Swirl if (s->dma_cb) { 8173d74342SBlue Swirl s->dma_cb(s); 8273d74342SBlue Swirl s->dma_cb = NULL; 8373d74342SBlue Swirl } 8473d74342SBlue Swirl } else { 85bf4b9889SBlue Swirl trace_esp_dma_disable(); 8673d74342SBlue Swirl s->dma_enabled = 0; 8773d74342SBlue Swirl } 8873d74342SBlue Swirl } 8973d74342SBlue Swirl 909c7e23fcSHervé Poussineau void esp_request_cancelled(SCSIRequest *req) 9194d3f98aSPaolo Bonzini { 92e6810db8SHervé Poussineau ESPState *s = req->hba_private; 9394d3f98aSPaolo Bonzini 9494d3f98aSPaolo Bonzini if (req == s->current_req) { 9594d3f98aSPaolo Bonzini scsi_req_unref(s->current_req); 9694d3f98aSPaolo Bonzini s->current_req = NULL; 9794d3f98aSPaolo Bonzini s->current_dev = NULL; 9894d3f98aSPaolo Bonzini } 9994d3f98aSPaolo Bonzini } 10094d3f98aSPaolo Bonzini 101c47b5835SMark Cave-Ayland static uint32_t esp_get_tc(ESPState *s) 102c47b5835SMark Cave-Ayland { 103c47b5835SMark Cave-Ayland uint32_t dmalen; 104c47b5835SMark Cave-Ayland 105c47b5835SMark Cave-Ayland dmalen = s->rregs[ESP_TCLO]; 106c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCMID] << 8; 107c47b5835SMark Cave-Ayland dmalen |= s->rregs[ESP_TCHI] << 16; 108c47b5835SMark Cave-Ayland 109c47b5835SMark Cave-Ayland return dmalen; 110c47b5835SMark Cave-Ayland } 111c47b5835SMark Cave-Ayland 112c47b5835SMark Cave-Ayland static void esp_set_tc(ESPState *s, uint32_t dmalen) 113c47b5835SMark Cave-Ayland { 114c47b5835SMark Cave-Ayland s->rregs[ESP_TCLO] = dmalen; 115c47b5835SMark Cave-Ayland s->rregs[ESP_TCMID] = dmalen >> 8; 116c47b5835SMark Cave-Ayland s->rregs[ESP_TCHI] = dmalen >> 16; 117c47b5835SMark Cave-Ayland } 118c47b5835SMark Cave-Ayland 119c04ed569SMark Cave-Ayland static uint32_t esp_get_stc(ESPState *s) 120c04ed569SMark Cave-Ayland { 121c04ed569SMark Cave-Ayland uint32_t dmalen; 122c04ed569SMark Cave-Ayland 123c04ed569SMark Cave-Ayland dmalen = s->wregs[ESP_TCLO]; 124c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCMID] << 8; 125c04ed569SMark Cave-Ayland dmalen |= s->wregs[ESP_TCHI] << 16; 126c04ed569SMark Cave-Ayland 127c04ed569SMark Cave-Ayland return dmalen; 128c04ed569SMark Cave-Ayland } 129c04ed569SMark Cave-Ayland 130761bef75SMark Cave-Ayland static uint8_t esp_pdma_read(ESPState *s) 131761bef75SMark Cave-Ayland { 1328da90e81SMark Cave-Ayland uint8_t val; 1338da90e81SMark Cave-Ayland 13402abe246SMark Cave-Ayland if (s->do_cmd) { 135bb0bc7bbSMark Cave-Ayland val = s->cmdbuf[s->cmdlen++]; 13602abe246SMark Cave-Ayland } else { 13702abe246SMark Cave-Ayland val = s->ti_buf[s->ti_rptr++]; 13802abe246SMark Cave-Ayland } 1398da90e81SMark Cave-Ayland 1408da90e81SMark Cave-Ayland return val; 141761bef75SMark Cave-Ayland } 142761bef75SMark Cave-Ayland 143761bef75SMark Cave-Ayland static void esp_pdma_write(ESPState *s, uint8_t val) 144761bef75SMark Cave-Ayland { 1458da90e81SMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 1468da90e81SMark Cave-Ayland 1473c421400SMark Cave-Ayland if (dmalen == 0) { 1488da90e81SMark Cave-Ayland return; 1498da90e81SMark Cave-Ayland } 1508da90e81SMark Cave-Ayland 15102abe246SMark Cave-Ayland if (s->do_cmd) { 152bb0bc7bbSMark Cave-Ayland s->cmdbuf[s->cmdlen++] = val; 15302abe246SMark Cave-Ayland } else { 15402abe246SMark Cave-Ayland s->ti_buf[s->ti_wptr++] = val; 15502abe246SMark Cave-Ayland } 1568da90e81SMark Cave-Ayland 1578da90e81SMark Cave-Ayland dmalen--; 1588da90e81SMark Cave-Ayland esp_set_tc(s, dmalen); 159761bef75SMark Cave-Ayland } 160761bef75SMark Cave-Ayland 161c7bce09cSMark Cave-Ayland static int esp_select(ESPState *s) 1626130b188SLaurent Vivier { 1636130b188SLaurent Vivier int target; 1646130b188SLaurent Vivier 1656130b188SLaurent Vivier target = s->wregs[ESP_WBUSID] & BUSID_DID; 1666130b188SLaurent Vivier 1676130b188SLaurent Vivier s->ti_size = 0; 1686130b188SLaurent Vivier s->ti_rptr = 0; 1696130b188SLaurent Vivier s->ti_wptr = 0; 1706130b188SLaurent Vivier 1716130b188SLaurent Vivier if (s->current_req) { 1726130b188SLaurent Vivier /* Started a new command before the old one finished. Cancel it. */ 1736130b188SLaurent Vivier scsi_req_cancel(s->current_req); 1746130b188SLaurent Vivier s->async_len = 0; 1756130b188SLaurent Vivier } 1766130b188SLaurent Vivier 1776130b188SLaurent Vivier s->current_dev = scsi_device_find(&s->bus, 0, target, 0); 1786130b188SLaurent Vivier if (!s->current_dev) { 1796130b188SLaurent Vivier /* No such drive */ 1806130b188SLaurent Vivier s->rregs[ESP_RSTAT] = 0; 181cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_DC; 1826130b188SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_0; 1836130b188SLaurent Vivier esp_raise_irq(s); 1846130b188SLaurent Vivier return -1; 1856130b188SLaurent Vivier } 186*4e78f3bfSMark Cave-Ayland 187*4e78f3bfSMark Cave-Ayland /* 188*4e78f3bfSMark Cave-Ayland * Note that we deliberately don't raise the IRQ here: this will be done 189*4e78f3bfSMark Cave-Ayland * either in do_busid_cmd() for DATA OUT transfers or by the deferred 190*4e78f3bfSMark Cave-Ayland * IRQ mechanism in esp_transfer_data() for DATA IN transfers 191*4e78f3bfSMark Cave-Ayland */ 192*4e78f3bfSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 193*4e78f3bfSMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 1946130b188SLaurent Vivier return 0; 1956130b188SLaurent Vivier } 1966130b188SLaurent Vivier 197cfcea0f9SMark Cave-Ayland static uint32_t get_cmd(ESPState *s) 1982f275b8fSbellard { 199cfcea0f9SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 200a917d384Spbrook uint32_t dmalen; 2012f275b8fSbellard int target; 2022f275b8fSbellard 2038dea1dd4Sblueswir1 target = s->wregs[ESP_WBUSID] & BUSID_DID; 2044f6200f0Sbellard if (s->dma) { 205c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 206cfcea0f9SMark Cave-Ayland if (dmalen > ESP_CMDBUF_SZ) { 2076c1fef6bSPrasad J Pandit return 0; 2086c1fef6bSPrasad J Pandit } 20974d71ea1SLaurent Vivier if (s->dma_memory_read) { 2108b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, buf, dmalen); 2114f6200f0Sbellard } else { 21249691315SMark Cave-Ayland if (esp_select(s) < 0) { 21349691315SMark Cave-Ayland return -1; 21449691315SMark Cave-Ayland } 21574d71ea1SLaurent Vivier esp_raise_drq(s); 21674d71ea1SLaurent Vivier return 0; 21774d71ea1SLaurent Vivier } 21874d71ea1SLaurent Vivier } else { 219fc4d65daSblueswir1 dmalen = s->ti_size; 220d3cdc491SPrasad J Pandit if (dmalen > TI_BUFSZ) { 221d3cdc491SPrasad J Pandit return 0; 222d3cdc491SPrasad J Pandit } 223fc4d65daSblueswir1 memcpy(buf, s->ti_buf, dmalen); 22475ef8496SHervé Poussineau buf[0] = buf[2] >> 5; 2254f6200f0Sbellard } 226bf4b9889SBlue Swirl trace_esp_get_cmd(dmalen, target); 2272e5d83bbSpbrook 228c7bce09cSMark Cave-Ayland if (esp_select(s) < 0) { 22949691315SMark Cave-Ayland return -1; 2302f275b8fSbellard } 2319f149aa9Spbrook return dmalen; 2329f149aa9Spbrook } 2339f149aa9Spbrook 234f2818f22SArtyom Tarasenko static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid) 2359f149aa9Spbrook { 2369f149aa9Spbrook int32_t datalen; 2379f149aa9Spbrook int lun; 238f48a7a6eSPaolo Bonzini SCSIDevice *current_lun; 2399f149aa9Spbrook 240bf4b9889SBlue Swirl trace_esp_do_busid_cmd(busid); 241f2818f22SArtyom Tarasenko lun = busid & 7; 2420d3545e7SPaolo Bonzini current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun); 243e6810db8SHervé Poussineau s->current_req = scsi_req_new(current_lun, 0, lun, buf, s); 244c39ce112SPaolo Bonzini datalen = scsi_req_enqueue(s->current_req); 24567e999beSbellard s->ti_size = datalen; 24667e999beSbellard if (datalen != 0) { 247c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC; 248*4e78f3bfSMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 2496cc88d6bSMark Cave-Ayland esp_set_tc(s, 0); 2502e5d83bbSpbrook if (datalen > 0) { 251*4e78f3bfSMark Cave-Ayland /* 252*4e78f3bfSMark Cave-Ayland * Switch to DATA IN phase but wait until initial data xfer is 253*4e78f3bfSMark Cave-Ayland * complete before raising the command completion interrupt 254*4e78f3bfSMark Cave-Ayland */ 255*4e78f3bfSMark Cave-Ayland s->data_in_ready = false; 2565ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DI; 2574f6200f0Sbellard } else { 2585ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] |= STAT_DO; 259cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 260c73f96fdSblueswir1 esp_raise_irq(s); 26182141c8bSMark Cave-Ayland esp_lower_drq(s); 2622f275b8fSbellard } 263*4e78f3bfSMark Cave-Ayland scsi_req_continue(s->current_req); 264*4e78f3bfSMark Cave-Ayland return; 265*4e78f3bfSMark Cave-Ayland } 266*4e78f3bfSMark Cave-Ayland } 2672f275b8fSbellard 268c959f218SMark Cave-Ayland static void do_cmd(ESPState *s) 269f2818f22SArtyom Tarasenko { 270c959f218SMark Cave-Ayland uint8_t *buf = s->cmdbuf; 271f2818f22SArtyom Tarasenko uint8_t busid = buf[0]; 272f2818f22SArtyom Tarasenko 273f2818f22SArtyom Tarasenko do_busid_cmd(s, &buf[1], busid); 274f2818f22SArtyom Tarasenko } 275f2818f22SArtyom Tarasenko 27674d71ea1SLaurent Vivier static void satn_pdma_cb(ESPState *s) 27774d71ea1SLaurent Vivier { 278bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 279bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 280c959f218SMark Cave-Ayland do_cmd(s); 28174d71ea1SLaurent Vivier } 28274d71ea1SLaurent Vivier } 28374d71ea1SLaurent Vivier 2849f149aa9Spbrook static void handle_satn(ESPState *s) 2859f149aa9Spbrook { 28649691315SMark Cave-Ayland int32_t cmdlen; 28749691315SMark Cave-Ayland 2881b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 28973d74342SBlue Swirl s->dma_cb = handle_satn; 29073d74342SBlue Swirl return; 29173d74342SBlue Swirl } 29274d71ea1SLaurent Vivier s->pdma_cb = satn_pdma_cb; 29349691315SMark Cave-Ayland cmdlen = get_cmd(s); 29449691315SMark Cave-Ayland if (cmdlen > 0) { 29549691315SMark Cave-Ayland s->cmdlen = cmdlen; 296c959f218SMark Cave-Ayland do_cmd(s); 29749691315SMark Cave-Ayland } else if (cmdlen == 0) { 29849691315SMark Cave-Ayland s->cmdlen = 0; 299bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 30049691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 30149691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 30249691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 3039f149aa9Spbrook } 30494d5c79dSMark Cave-Ayland } 3059f149aa9Spbrook 30674d71ea1SLaurent Vivier static void s_without_satn_pdma_cb(ESPState *s) 30774d71ea1SLaurent Vivier { 308bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 309bb0bc7bbSMark Cave-Ayland if (s->cmdlen) { 3102c573cfeSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 31174d71ea1SLaurent Vivier } 31274d71ea1SLaurent Vivier } 31374d71ea1SLaurent Vivier 314f2818f22SArtyom Tarasenko static void handle_s_without_atn(ESPState *s) 315f2818f22SArtyom Tarasenko { 31649691315SMark Cave-Ayland int32_t cmdlen; 31749691315SMark Cave-Ayland 3181b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 31973d74342SBlue Swirl s->dma_cb = handle_s_without_atn; 32073d74342SBlue Swirl return; 32173d74342SBlue Swirl } 32274d71ea1SLaurent Vivier s->pdma_cb = s_without_satn_pdma_cb; 32349691315SMark Cave-Ayland cmdlen = get_cmd(s); 32449691315SMark Cave-Ayland if (cmdlen > 0) { 32549691315SMark Cave-Ayland s->cmdlen = cmdlen; 326bb0bc7bbSMark Cave-Ayland do_busid_cmd(s, s->cmdbuf, 0); 32749691315SMark Cave-Ayland } else if (cmdlen == 0) { 32849691315SMark Cave-Ayland s->cmdlen = 0; 329bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 33049691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 33149691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 33249691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 333f2818f22SArtyom Tarasenko } 334f2818f22SArtyom Tarasenko } 335f2818f22SArtyom Tarasenko 33674d71ea1SLaurent Vivier static void satn_stop_pdma_cb(ESPState *s) 33774d71ea1SLaurent Vivier { 338bb0bc7bbSMark Cave-Ayland s->do_cmd = 0; 33974d71ea1SLaurent Vivier if (s->cmdlen) { 34074d71ea1SLaurent Vivier trace_esp_handle_satn_stop(s->cmdlen); 34174d71ea1SLaurent Vivier s->do_cmd = 1; 34274d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD; 343cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 34474d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 34574d71ea1SLaurent Vivier esp_raise_irq(s); 34674d71ea1SLaurent Vivier } 34774d71ea1SLaurent Vivier } 34874d71ea1SLaurent Vivier 3499f149aa9Spbrook static void handle_satn_stop(ESPState *s) 3509f149aa9Spbrook { 35149691315SMark Cave-Ayland int32_t cmdlen; 35249691315SMark Cave-Ayland 3531b26eaa1SHervé Poussineau if (s->dma && !s->dma_enabled) { 35473d74342SBlue Swirl s->dma_cb = handle_satn_stop; 35573d74342SBlue Swirl return; 35673d74342SBlue Swirl } 357c62c1fa0SPhilippe Mathieu-Daudé s->pdma_cb = satn_stop_pdma_cb; 35849691315SMark Cave-Ayland cmdlen = get_cmd(s); 35949691315SMark Cave-Ayland if (cmdlen > 0) { 360bf4b9889SBlue Swirl trace_esp_handle_satn_stop(s->cmdlen); 36149691315SMark Cave-Ayland s->cmdlen = cmdlen; 3629f149aa9Spbrook s->do_cmd = 1; 363cf47a41eSMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 364cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 3655ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 366c73f96fdSblueswir1 esp_raise_irq(s); 36749691315SMark Cave-Ayland } else if (cmdlen == 0) { 36849691315SMark Cave-Ayland s->cmdlen = 0; 369bb0bc7bbSMark Cave-Ayland s->do_cmd = 1; 37049691315SMark Cave-Ayland /* Target present, but no cmd yet - switch to command phase */ 37149691315SMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_CD; 37249691315SMark Cave-Ayland s->rregs[ESP_RSTAT] = STAT_CD; 3739f149aa9Spbrook } 3749f149aa9Spbrook } 3759f149aa9Spbrook 37674d71ea1SLaurent Vivier static void write_response_pdma_cb(ESPState *s) 37774d71ea1SLaurent Vivier { 37874d71ea1SLaurent Vivier s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 379cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 38074d71ea1SLaurent Vivier s->rregs[ESP_RSEQ] = SEQ_CD; 38174d71ea1SLaurent Vivier esp_raise_irq(s); 38274d71ea1SLaurent Vivier } 38374d71ea1SLaurent Vivier 3840fc5c15aSpbrook static void write_response(ESPState *s) 3852f275b8fSbellard { 386bf4b9889SBlue Swirl trace_esp_write_response(s->status); 3873944966dSPaolo Bonzini s->ti_buf[0] = s->status; 3880fc5c15aSpbrook s->ti_buf[1] = 0; 3894f6200f0Sbellard if (s->dma) { 39074d71ea1SLaurent Vivier if (s->dma_memory_write) { 3918b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->ti_buf, 2); 392c73f96fdSblueswir1 s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST; 393cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS | INTR_FC; 3945ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = SEQ_CD; 3954f6200f0Sbellard } else { 39674d71ea1SLaurent Vivier s->pdma_cb = write_response_pdma_cb; 39774d71ea1SLaurent Vivier esp_raise_drq(s); 39874d71ea1SLaurent Vivier return; 39974d71ea1SLaurent Vivier } 40074d71ea1SLaurent Vivier } else { 4010fc5c15aSpbrook s->ti_size = 2; 4024f6200f0Sbellard s->ti_rptr = 0; 403d020aa50SPaolo Bonzini s->ti_wptr = 2; 4045ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 2; 4054f6200f0Sbellard } 406c73f96fdSblueswir1 esp_raise_irq(s); 4072f275b8fSbellard } 4084f6200f0Sbellard 409a917d384Spbrook static void esp_dma_done(ESPState *s) 4104d611c9aSpbrook { 411c73f96fdSblueswir1 s->rregs[ESP_RSTAT] |= STAT_TC; 412cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 4135ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 4145ad6bb97Sblueswir1 s->rregs[ESP_RFLAGS] = 0; 415c47b5835SMark Cave-Ayland esp_set_tc(s, 0); 416c73f96fdSblueswir1 esp_raise_irq(s); 4174d611c9aSpbrook } 418a917d384Spbrook 41974d71ea1SLaurent Vivier static void do_dma_pdma_cb(ESPState *s) 42074d71ea1SLaurent Vivier { 4214ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 42282141c8bSMark Cave-Ayland int len; 4236cc88d6bSMark Cave-Ayland 42474d71ea1SLaurent Vivier if (s->do_cmd) { 42574d71ea1SLaurent Vivier s->ti_size = 0; 42674d71ea1SLaurent Vivier s->cmdlen = 0; 42774d71ea1SLaurent Vivier s->do_cmd = 0; 428c959f218SMark Cave-Ayland do_cmd(s); 42982141c8bSMark Cave-Ayland esp_lower_drq(s); 43074d71ea1SLaurent Vivier return; 43174d71ea1SLaurent Vivier } 43282141c8bSMark Cave-Ayland 43382141c8bSMark Cave-Ayland if (to_device) { 43482141c8bSMark Cave-Ayland /* Copy FIFO data to device */ 43582141c8bSMark Cave-Ayland len = MIN(s->ti_wptr, TI_BUFSZ); 43682141c8bSMark Cave-Ayland memcpy(s->async_buf, s->ti_buf, len); 43782141c8bSMark Cave-Ayland s->ti_wptr = 0; 43882141c8bSMark Cave-Ayland s->ti_rptr = 0; 43982141c8bSMark Cave-Ayland s->async_buf += len; 44082141c8bSMark Cave-Ayland s->async_len -= len; 44182141c8bSMark Cave-Ayland s->ti_size += len; 44274d71ea1SLaurent Vivier if (s->async_len == 0) { 44374d71ea1SLaurent Vivier scsi_req_continue(s->current_req); 44482141c8bSMark Cave-Ayland return; 44582141c8bSMark Cave-Ayland } 44682141c8bSMark Cave-Ayland 44782141c8bSMark Cave-Ayland if (esp_get_tc(s) == 0) { 44882141c8bSMark Cave-Ayland esp_lower_drq(s); 44982141c8bSMark Cave-Ayland esp_dma_done(s); 45082141c8bSMark Cave-Ayland } 45182141c8bSMark Cave-Ayland 45282141c8bSMark Cave-Ayland return; 45382141c8bSMark Cave-Ayland } else { 45482141c8bSMark Cave-Ayland if (s->async_len == 0) { 45582141c8bSMark Cave-Ayland if (s->current_req) { 456*4e78f3bfSMark Cave-Ayland /* Defer until the scsi layer has completed */ 45782141c8bSMark Cave-Ayland scsi_req_continue(s->current_req); 458*4e78f3bfSMark Cave-Ayland s->data_in_ready = false; 45982141c8bSMark Cave-Ayland } 46074d71ea1SLaurent Vivier return; 46174d71ea1SLaurent Vivier } 46274d71ea1SLaurent Vivier 46382141c8bSMark Cave-Ayland if (esp_get_tc(s) != 0) { 46482141c8bSMark Cave-Ayland /* Copy device data to FIFO */ 46582141c8bSMark Cave-Ayland s->ti_wptr = 0; 46682141c8bSMark Cave-Ayland s->ti_rptr = 0; 46782141c8bSMark Cave-Ayland len = MIN(s->async_len, TI_BUFSZ); 46882141c8bSMark Cave-Ayland memcpy(s->ti_buf, s->async_buf, len); 46982141c8bSMark Cave-Ayland s->ti_wptr += len; 47082141c8bSMark Cave-Ayland s->async_buf += len; 47182141c8bSMark Cave-Ayland s->async_len -= len; 47282141c8bSMark Cave-Ayland s->ti_size -= len; 47382141c8bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 47482141c8bSMark Cave-Ayland return; 47582141c8bSMark Cave-Ayland } 47682141c8bSMark Cave-Ayland 47774d71ea1SLaurent Vivier /* Partially filled a scsi buffer. Complete immediately. */ 47882141c8bSMark Cave-Ayland esp_lower_drq(s); 47974d71ea1SLaurent Vivier esp_dma_done(s); 48074d71ea1SLaurent Vivier } 48182141c8bSMark Cave-Ayland } 48274d71ea1SLaurent Vivier 483a917d384Spbrook static void esp_do_dma(ESPState *s) 484a917d384Spbrook { 48567e999beSbellard uint32_t len; 4864ca2ba6fSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 487a917d384Spbrook 4886cc88d6bSMark Cave-Ayland len = esp_get_tc(s); 489a917d384Spbrook if (s->do_cmd) { 49015407433SLaurent Vivier /* 49115407433SLaurent Vivier * handle_ti_cmd() case: esp_do_dma() is called only from 49215407433SLaurent Vivier * handle_ti_cmd() with do_cmd != NULL (see the assert()) 49315407433SLaurent Vivier */ 494bf4b9889SBlue Swirl trace_esp_do_dma(s->cmdlen, len); 495926cde5fSPrasad J Pandit assert(s->cmdlen <= sizeof(s->cmdbuf) && 496926cde5fSPrasad J Pandit len <= sizeof(s->cmdbuf) - s->cmdlen); 49774d71ea1SLaurent Vivier if (s->dma_memory_read) { 4988b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len); 49974d71ea1SLaurent Vivier } else { 50074d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 50174d71ea1SLaurent Vivier esp_raise_drq(s); 50274d71ea1SLaurent Vivier return; 50374d71ea1SLaurent Vivier } 50415407433SLaurent Vivier trace_esp_handle_ti_cmd(s->cmdlen); 50515407433SLaurent Vivier s->ti_size = 0; 50615407433SLaurent Vivier s->cmdlen = 0; 50715407433SLaurent Vivier s->do_cmd = 0; 508c959f218SMark Cave-Ayland do_cmd(s); 509a917d384Spbrook return; 510a917d384Spbrook } 511a917d384Spbrook if (s->async_len == 0) { 512a917d384Spbrook /* Defer until data is available. */ 513a917d384Spbrook return; 514a917d384Spbrook } 515a917d384Spbrook if (len > s->async_len) { 516a917d384Spbrook len = s->async_len; 517a917d384Spbrook } 518a917d384Spbrook if (to_device) { 51974d71ea1SLaurent Vivier if (s->dma_memory_read) { 5208b17de88Sblueswir1 s->dma_memory_read(s->dma_opaque, s->async_buf, len); 521a917d384Spbrook } else { 52274d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 52374d71ea1SLaurent Vivier esp_raise_drq(s); 52474d71ea1SLaurent Vivier return; 52574d71ea1SLaurent Vivier } 52674d71ea1SLaurent Vivier } else { 52774d71ea1SLaurent Vivier if (s->dma_memory_write) { 5288b17de88Sblueswir1 s->dma_memory_write(s->dma_opaque, s->async_buf, len); 52974d71ea1SLaurent Vivier } else { 53082141c8bSMark Cave-Ayland /* Copy device data to FIFO */ 53182141c8bSMark Cave-Ayland len = MIN(len, TI_BUFSZ - s->ti_wptr); 53282141c8bSMark Cave-Ayland memcpy(&s->ti_buf[s->ti_wptr], s->async_buf, len); 53382141c8bSMark Cave-Ayland s->ti_wptr += len; 53482141c8bSMark Cave-Ayland s->async_buf += len; 53582141c8bSMark Cave-Ayland s->async_len -= len; 53682141c8bSMark Cave-Ayland s->ti_size -= len; 53782141c8bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 53874d71ea1SLaurent Vivier s->pdma_cb = do_dma_pdma_cb; 53974d71ea1SLaurent Vivier esp_raise_drq(s); 54082141c8bSMark Cave-Ayland 54182141c8bSMark Cave-Ayland /* Indicate transfer to FIFO is complete */ 54282141c8bSMark Cave-Ayland s->rregs[ESP_RSTAT] |= STAT_TC; 54374d71ea1SLaurent Vivier return; 54474d71ea1SLaurent Vivier } 545a917d384Spbrook } 5466cc88d6bSMark Cave-Ayland esp_set_tc(s, esp_get_tc(s) - len); 547a917d384Spbrook s->async_buf += len; 548a917d384Spbrook s->async_len -= len; 54994d5c79dSMark Cave-Ayland if (to_device) { 5506787f5faSpbrook s->ti_size += len; 55194d5c79dSMark Cave-Ayland } else { 5526787f5faSpbrook s->ti_size -= len; 55394d5c79dSMark Cave-Ayland } 554a917d384Spbrook if (s->async_len == 0) { 555ad3376ccSPaolo Bonzini scsi_req_continue(s->current_req); 55694d5c79dSMark Cave-Ayland /* 55794d5c79dSMark Cave-Ayland * If there is still data to be read from the device then 55894d5c79dSMark Cave-Ayland * complete the DMA operation immediately. Otherwise defer 55994d5c79dSMark Cave-Ayland * until the scsi layer has completed. 56094d5c79dSMark Cave-Ayland */ 5616cc88d6bSMark Cave-Ayland if (to_device || esp_get_tc(s) != 0 || s->ti_size == 0) { 562ad3376ccSPaolo Bonzini return; 563a917d384Spbrook } 564a917d384Spbrook } 565ad3376ccSPaolo Bonzini 5666787f5faSpbrook /* Partially filled a scsi buffer. Complete immediately. */ 567a917d384Spbrook esp_dma_done(s); 56882141c8bSMark Cave-Ayland esp_lower_drq(s); 569a917d384Spbrook } 570a917d384Spbrook 571ea84a442SGuenter Roeck static void esp_report_command_complete(ESPState *s, uint32_t status) 572a917d384Spbrook { 573bf4b9889SBlue Swirl trace_esp_command_complete(); 574c6df7102SPaolo Bonzini if (s->ti_size != 0) { 575bf4b9889SBlue Swirl trace_esp_command_complete_unexpected(); 576c6df7102SPaolo Bonzini } 577a917d384Spbrook s->ti_size = 0; 578a917d384Spbrook s->async_len = 0; 579aba1f023SPaolo Bonzini if (status) { 580bf4b9889SBlue Swirl trace_esp_command_complete_fail(); 581c6df7102SPaolo Bonzini } 582aba1f023SPaolo Bonzini s->status = status; 5835ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] = STAT_ST; 584a917d384Spbrook esp_dma_done(s); 58582141c8bSMark Cave-Ayland esp_lower_drq(s); 5865c6c0e51SHannes Reinecke if (s->current_req) { 5875c6c0e51SHannes Reinecke scsi_req_unref(s->current_req); 5885c6c0e51SHannes Reinecke s->current_req = NULL; 589a917d384Spbrook s->current_dev = NULL; 5905c6c0e51SHannes Reinecke } 591c6df7102SPaolo Bonzini } 592c6df7102SPaolo Bonzini 59317ea26c2SHannes Reinecke void esp_command_complete(SCSIRequest *req, size_t resid) 594ea84a442SGuenter Roeck { 595ea84a442SGuenter Roeck ESPState *s = req->hba_private; 596ea84a442SGuenter Roeck 597ea84a442SGuenter Roeck if (s->rregs[ESP_RSTAT] & STAT_INT) { 59894d5c79dSMark Cave-Ayland /* 59994d5c79dSMark Cave-Ayland * Defer handling command complete until the previous 600ea84a442SGuenter Roeck * interrupt has been handled. 601ea84a442SGuenter Roeck */ 602ea84a442SGuenter Roeck trace_esp_command_complete_deferred(); 60317ea26c2SHannes Reinecke s->deferred_status = req->status; 604ea84a442SGuenter Roeck s->deferred_complete = true; 605ea84a442SGuenter Roeck return; 606ea84a442SGuenter Roeck } 60717ea26c2SHannes Reinecke esp_report_command_complete(s, req->status); 608ea84a442SGuenter Roeck } 609ea84a442SGuenter Roeck 6109c7e23fcSHervé Poussineau void esp_transfer_data(SCSIRequest *req, uint32_t len) 611c6df7102SPaolo Bonzini { 612e6810db8SHervé Poussineau ESPState *s = req->hba_private; 613*4e78f3bfSMark Cave-Ayland int to_device = ((s->rregs[ESP_RSTAT] & 7) == STAT_DO); 6146cc88d6bSMark Cave-Ayland uint32_t dmalen = esp_get_tc(s); 615c6df7102SPaolo Bonzini 6167f0b6e11SPaolo Bonzini assert(!s->do_cmd); 6176cc88d6bSMark Cave-Ayland trace_esp_transfer_data(dmalen, s->ti_size); 618aba1f023SPaolo Bonzini s->async_len = len; 6190c34459bSPaolo Bonzini s->async_buf = scsi_req_get_buf(req); 620*4e78f3bfSMark Cave-Ayland 621*4e78f3bfSMark Cave-Ayland if (!to_device && !s->data_in_ready) { 622*4e78f3bfSMark Cave-Ayland /* 623*4e78f3bfSMark Cave-Ayland * Initial incoming data xfer is complete so raise command 624*4e78f3bfSMark Cave-Ayland * completion interrupt 625*4e78f3bfSMark Cave-Ayland */ 626*4e78f3bfSMark Cave-Ayland s->data_in_ready = true; 627*4e78f3bfSMark Cave-Ayland s->rregs[ESP_RSTAT] |= STAT_TC; 628*4e78f3bfSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_BS; 629*4e78f3bfSMark Cave-Ayland esp_raise_irq(s); 630*4e78f3bfSMark Cave-Ayland 631*4e78f3bfSMark Cave-Ayland /* 632*4e78f3bfSMark Cave-Ayland * If data is ready to transfer and the TI command has already 633*4e78f3bfSMark Cave-Ayland * been executed, start DMA immediately. Otherwise DMA will start 634*4e78f3bfSMark Cave-Ayland * when host sends the TI command 635*4e78f3bfSMark Cave-Ayland */ 636*4e78f3bfSMark Cave-Ayland if (s->ti_size && (s->rregs[ESP_CMD] == (CMD_TI | CMD_DMA))) { 637*4e78f3bfSMark Cave-Ayland esp_do_dma(s); 638*4e78f3bfSMark Cave-Ayland } 639*4e78f3bfSMark Cave-Ayland return; 640*4e78f3bfSMark Cave-Ayland } 641*4e78f3bfSMark Cave-Ayland 6426cc88d6bSMark Cave-Ayland if (dmalen) { 643a917d384Spbrook esp_do_dma(s); 6445eb7a23fSMark Cave-Ayland } else if (s->ti_size <= 0) { 64594d5c79dSMark Cave-Ayland /* 64694d5c79dSMark Cave-Ayland * If this was the last part of a DMA transfer then the 64794d5c79dSMark Cave-Ayland * completion interrupt is deferred to here. 64894d5c79dSMark Cave-Ayland */ 6496787f5faSpbrook esp_dma_done(s); 65082141c8bSMark Cave-Ayland esp_lower_drq(s); 6516787f5faSpbrook } 652a917d384Spbrook } 6532e5d83bbSpbrook 6542f275b8fSbellard static void handle_ti(ESPState *s) 6552f275b8fSbellard { 656b76624deSMark Cave-Ayland uint32_t dmalen; 6572f275b8fSbellard 6587246e160SHervé Poussineau if (s->dma && !s->dma_enabled) { 6597246e160SHervé Poussineau s->dma_cb = handle_ti; 6607246e160SHervé Poussineau return; 6617246e160SHervé Poussineau } 6627246e160SHervé Poussineau 663c47b5835SMark Cave-Ayland dmalen = esp_get_tc(s); 6644f6200f0Sbellard if (s->dma) { 665b76624deSMark Cave-Ayland trace_esp_handle_ti(dmalen); 6665ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 6674d611c9aSpbrook esp_do_dma(s); 66815407433SLaurent Vivier } else if (s->do_cmd) { 669bf4b9889SBlue Swirl trace_esp_handle_ti_cmd(s->cmdlen); 6709f149aa9Spbrook s->ti_size = 0; 6719f149aa9Spbrook s->cmdlen = 0; 6729f149aa9Spbrook s->do_cmd = 0; 673c959f218SMark Cave-Ayland do_cmd(s); 6744f6200f0Sbellard } 6752f275b8fSbellard } 6762f275b8fSbellard 6779c7e23fcSHervé Poussineau void esp_hard_reset(ESPState *s) 6786f7e9aecSbellard { 6795aca8c3bSblueswir1 memset(s->rregs, 0, ESP_REGS); 6805aca8c3bSblueswir1 memset(s->wregs, 0, ESP_REGS); 681c9cf45c1SHannes Reinecke s->tchi_written = 0; 6824e9aec74Spbrook s->ti_size = 0; 6834e9aec74Spbrook s->ti_rptr = 0; 6844e9aec74Spbrook s->ti_wptr = 0; 6854e9aec74Spbrook s->dma = 0; 6869f149aa9Spbrook s->do_cmd = 0; 68773d74342SBlue Swirl s->dma_cb = NULL; 6888dea1dd4Sblueswir1 6898dea1dd4Sblueswir1 s->rregs[ESP_CFG1] = 7; 6906f7e9aecSbellard } 6916f7e9aecSbellard 692a391fdbcSHervé Poussineau static void esp_soft_reset(ESPState *s) 69385948643SBlue Swirl { 69485948643SBlue Swirl qemu_irq_lower(s->irq); 69574d71ea1SLaurent Vivier qemu_irq_lower(s->irq_data); 696a391fdbcSHervé Poussineau esp_hard_reset(s); 69785948643SBlue Swirl } 69885948643SBlue Swirl 699a391fdbcSHervé Poussineau static void parent_esp_reset(ESPState *s, int irq, int level) 7002d069babSblueswir1 { 70185948643SBlue Swirl if (level) { 702a391fdbcSHervé Poussineau esp_soft_reset(s); 70385948643SBlue Swirl } 7042d069babSblueswir1 } 7052d069babSblueswir1 7069c7e23fcSHervé Poussineau uint64_t esp_reg_read(ESPState *s, uint32_t saddr) 70773d74342SBlue Swirl { 708b630c075SMark Cave-Ayland uint32_t val; 70973d74342SBlue Swirl 7106f7e9aecSbellard switch (saddr) { 7115ad6bb97Sblueswir1 case ESP_FIFO: 7125ad6bb97Sblueswir1 if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) { 7138dea1dd4Sblueswir1 /* Data out. */ 714ff589551SPrasad J Pandit qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n"); 7155ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = 0; 716ff589551SPrasad J Pandit } else if (s->ti_rptr < s->ti_wptr) { 717ff589551SPrasad J Pandit s->ti_size--; 7185ad6bb97Sblueswir1 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++]; 7194f6200f0Sbellard } 720ff589551SPrasad J Pandit if (s->ti_rptr == s->ti_wptr) { 7214f6200f0Sbellard s->ti_rptr = 0; 7224f6200f0Sbellard s->ti_wptr = 0; 7234f6200f0Sbellard } 724b630c075SMark Cave-Ayland val = s->rregs[ESP_FIFO]; 7254f6200f0Sbellard break; 7265ad6bb97Sblueswir1 case ESP_RINTR: 72794d5c79dSMark Cave-Ayland /* 72894d5c79dSMark Cave-Ayland * Clear sequence step, interrupt register and all status bits 72994d5c79dSMark Cave-Ayland * except TC 73094d5c79dSMark Cave-Ayland */ 731b630c075SMark Cave-Ayland val = s->rregs[ESP_RINTR]; 7322814df28SBlue Swirl s->rregs[ESP_RINTR] = 0; 7332814df28SBlue Swirl s->rregs[ESP_RSTAT] &= ~STAT_TC; 734cf47a41eSMark Cave-Ayland s->rregs[ESP_RSEQ] = SEQ_0; 735c73f96fdSblueswir1 esp_lower_irq(s); 736ea84a442SGuenter Roeck if (s->deferred_complete) { 737ea84a442SGuenter Roeck esp_report_command_complete(s, s->deferred_status); 738ea84a442SGuenter Roeck s->deferred_complete = false; 739ea84a442SGuenter Roeck } 740b630c075SMark Cave-Ayland break; 741c9cf45c1SHannes Reinecke case ESP_TCHI: 742c9cf45c1SHannes Reinecke /* Return the unique id if the value has never been written */ 743c9cf45c1SHannes Reinecke if (!s->tchi_written) { 744b630c075SMark Cave-Ayland val = s->chip_id; 745b630c075SMark Cave-Ayland } else { 746b630c075SMark Cave-Ayland val = s->rregs[saddr]; 747c9cf45c1SHannes Reinecke } 748b630c075SMark Cave-Ayland break; 7496f7e9aecSbellard default: 750b630c075SMark Cave-Ayland val = s->rregs[saddr]; 7516f7e9aecSbellard break; 7526f7e9aecSbellard } 753b630c075SMark Cave-Ayland 754b630c075SMark Cave-Ayland trace_esp_mem_readb(saddr, val); 755b630c075SMark Cave-Ayland return val; 7566f7e9aecSbellard } 7576f7e9aecSbellard 7589c7e23fcSHervé Poussineau void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val) 7596f7e9aecSbellard { 760bf4b9889SBlue Swirl trace_esp_mem_writeb(saddr, s->wregs[saddr], val); 7616f7e9aecSbellard switch (saddr) { 762c9cf45c1SHannes Reinecke case ESP_TCHI: 763c9cf45c1SHannes Reinecke s->tchi_written = true; 764c9cf45c1SHannes Reinecke /* fall through */ 7655ad6bb97Sblueswir1 case ESP_TCLO: 7665ad6bb97Sblueswir1 case ESP_TCMID: 7675ad6bb97Sblueswir1 s->rregs[ESP_RSTAT] &= ~STAT_TC; 7684f6200f0Sbellard break; 7695ad6bb97Sblueswir1 case ESP_FIFO: 7709f149aa9Spbrook if (s->do_cmd) { 771926cde5fSPrasad J Pandit if (s->cmdlen < ESP_CMDBUF_SZ) { 7729f149aa9Spbrook s->cmdbuf[s->cmdlen++] = val & 0xff; 773c98c6c10SPrasad J Pandit } else { 774c98c6c10SPrasad J Pandit trace_esp_error_fifo_overrun(); 775c98c6c10SPrasad J Pandit } 776ff589551SPrasad J Pandit } else if (s->ti_wptr == TI_BUFSZ - 1) { 7773af4e9aaSHervé Poussineau trace_esp_error_fifo_overrun(); 7782e5d83bbSpbrook } else { 7794f6200f0Sbellard s->ti_size++; 7804f6200f0Sbellard s->ti_buf[s->ti_wptr++] = val & 0xff; 7812e5d83bbSpbrook } 7824f6200f0Sbellard break; 7835ad6bb97Sblueswir1 case ESP_CMD: 7844f6200f0Sbellard s->rregs[saddr] = val; 7855ad6bb97Sblueswir1 if (val & CMD_DMA) { 7864f6200f0Sbellard s->dma = 1; 7876787f5faSpbrook /* Reload DMA counter. */ 78896676c2fSMark Cave-Ayland if (esp_get_stc(s) == 0) { 78996676c2fSMark Cave-Ayland esp_set_tc(s, 0x10000); 79096676c2fSMark Cave-Ayland } else { 791c04ed569SMark Cave-Ayland esp_set_tc(s, esp_get_stc(s)); 79296676c2fSMark Cave-Ayland } 7934f6200f0Sbellard } else { 7944f6200f0Sbellard s->dma = 0; 7954f6200f0Sbellard } 7965ad6bb97Sblueswir1 switch (val & CMD_CMD) { 7975ad6bb97Sblueswir1 case CMD_NOP: 798bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_nop(val); 7992f275b8fSbellard break; 8005ad6bb97Sblueswir1 case CMD_FLUSH: 801bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_flush(val); 80294d5c79dSMark Cave-Ayland /*s->ti_size = 0;*/ 803bb27b13dSMark Cave-Ayland s->ti_wptr = 0; 804bb27b13dSMark Cave-Ayland s->ti_rptr = 0; 8056f7e9aecSbellard break; 8065ad6bb97Sblueswir1 case CMD_RESET: 807bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_reset(val); 808a391fdbcSHervé Poussineau esp_soft_reset(s); 8096f7e9aecSbellard break; 8105ad6bb97Sblueswir1 case CMD_BUSRESET: 811bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_bus_reset(val); 8125ad6bb97Sblueswir1 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) { 813cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_RST; 814c73f96fdSblueswir1 esp_raise_irq(s); 8159e61bde5Sbellard } 8162f275b8fSbellard break; 8175ad6bb97Sblueswir1 case CMD_TI: 8180097d3ecSMark Cave-Ayland trace_esp_mem_writeb_cmd_ti(val); 8192f275b8fSbellard handle_ti(s); 8202f275b8fSbellard break; 8215ad6bb97Sblueswir1 case CMD_ICCS: 822bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_iccs(val); 8230fc5c15aSpbrook write_response(s); 824cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 8254bf5801dSblueswir1 s->rregs[ESP_RSTAT] |= STAT_MI; 8262f275b8fSbellard break; 8275ad6bb97Sblueswir1 case CMD_MSGACC: 828bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_msgacc(val); 829cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_DC; 8305ad6bb97Sblueswir1 s->rregs[ESP_RSEQ] = 0; 8314e2a68c1SArtyom Tarasenko s->rregs[ESP_RFLAGS] = 0; 8324e2a68c1SArtyom Tarasenko esp_raise_irq(s); 8336f7e9aecSbellard break; 8340fd0eb21SBlue Swirl case CMD_PAD: 835bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_pad(val); 8360fd0eb21SBlue Swirl s->rregs[ESP_RSTAT] = STAT_TC; 837cf47a41eSMark Cave-Ayland s->rregs[ESP_RINTR] |= INTR_FC; 8380fd0eb21SBlue Swirl s->rregs[ESP_RSEQ] = 0; 8390fd0eb21SBlue Swirl break; 8405ad6bb97Sblueswir1 case CMD_SATN: 841bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_satn(val); 8426f7e9aecSbellard break; 8436915bff1SHervé Poussineau case CMD_RSTATN: 8446915bff1SHervé Poussineau trace_esp_mem_writeb_cmd_rstatn(val); 8456915bff1SHervé Poussineau break; 8465e1e0a3bSBlue Swirl case CMD_SEL: 847bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_sel(val); 848f2818f22SArtyom Tarasenko handle_s_without_atn(s); 8495e1e0a3bSBlue Swirl break; 8505ad6bb97Sblueswir1 case CMD_SELATN: 851bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatn(val); 8522f275b8fSbellard handle_satn(s); 8532f275b8fSbellard break; 8545ad6bb97Sblueswir1 case CMD_SELATNS: 855bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_selatns(val); 8569f149aa9Spbrook handle_satn_stop(s); 8572f275b8fSbellard break; 8585ad6bb97Sblueswir1 case CMD_ENSEL: 859bf4b9889SBlue Swirl trace_esp_mem_writeb_cmd_ensel(val); 860e3926838Sblueswir1 s->rregs[ESP_RINTR] = 0; 86174ec6048Sblueswir1 break; 8626fe84c18SHervé Poussineau case CMD_DISSEL: 8636fe84c18SHervé Poussineau trace_esp_mem_writeb_cmd_dissel(val); 8646fe84c18SHervé Poussineau s->rregs[ESP_RINTR] = 0; 8656fe84c18SHervé Poussineau esp_raise_irq(s); 8666fe84c18SHervé Poussineau break; 8672f275b8fSbellard default: 8683af4e9aaSHervé Poussineau trace_esp_error_unhandled_command(val); 8696f7e9aecSbellard break; 8706f7e9aecSbellard } 8716f7e9aecSbellard break; 8725ad6bb97Sblueswir1 case ESP_WBUSID ... ESP_WSYNO: 8734f6200f0Sbellard break; 8745ad6bb97Sblueswir1 case ESP_CFG1: 8759ea73f8bSPaolo Bonzini case ESP_CFG2: case ESP_CFG3: 8769ea73f8bSPaolo Bonzini case ESP_RES3: case ESP_RES4: 8774f6200f0Sbellard s->rregs[saddr] = val; 8784f6200f0Sbellard break; 8795ad6bb97Sblueswir1 case ESP_WCCF ... ESP_WTEST: 8804f6200f0Sbellard break; 8816f7e9aecSbellard default: 8823af4e9aaSHervé Poussineau trace_esp_error_invalid_write(val, saddr); 8838dea1dd4Sblueswir1 return; 8846f7e9aecSbellard } 8852f275b8fSbellard s->wregs[saddr] = val; 8866f7e9aecSbellard } 8876f7e9aecSbellard 888a8170e5eSAvi Kivity static bool esp_mem_accepts(void *opaque, hwaddr addr, 8898372d383SPeter Maydell unsigned size, bool is_write, 8908372d383SPeter Maydell MemTxAttrs attrs) 89167bb5314SAvi Kivity { 89267bb5314SAvi Kivity return (size == 1) || (is_write && size == 4); 89367bb5314SAvi Kivity } 8946f7e9aecSbellard 8956cc88d6bSMark Cave-Ayland static bool esp_is_before_version_5(void *opaque, int version_id) 8966cc88d6bSMark Cave-Ayland { 8976cc88d6bSMark Cave-Ayland ESPState *s = ESP(opaque); 8986cc88d6bSMark Cave-Ayland 8996cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 9006cc88d6bSMark Cave-Ayland return version_id < 5; 9016cc88d6bSMark Cave-Ayland } 9026cc88d6bSMark Cave-Ayland 903*4e78f3bfSMark Cave-Ayland static bool esp_is_version_5(void *opaque, int version_id) 904*4e78f3bfSMark Cave-Ayland { 905*4e78f3bfSMark Cave-Ayland ESPState *s = ESP(opaque); 906*4e78f3bfSMark Cave-Ayland 907*4e78f3bfSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 908*4e78f3bfSMark Cave-Ayland return version_id == 5; 909*4e78f3bfSMark Cave-Ayland } 910*4e78f3bfSMark Cave-Ayland 9110bd005beSMark Cave-Ayland static int esp_pre_save(void *opaque) 9120bd005beSMark Cave-Ayland { 9130bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 9140bd005beSMark Cave-Ayland 9150bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 9160bd005beSMark Cave-Ayland return 0; 9170bd005beSMark Cave-Ayland } 9180bd005beSMark Cave-Ayland 9190bd005beSMark Cave-Ayland static int esp_post_load(void *opaque, int version_id) 9200bd005beSMark Cave-Ayland { 9210bd005beSMark Cave-Ayland ESPState *s = ESP(opaque); 9220bd005beSMark Cave-Ayland 9236cc88d6bSMark Cave-Ayland version_id = MIN(version_id, s->mig_version_id); 9246cc88d6bSMark Cave-Ayland 9256cc88d6bSMark Cave-Ayland if (version_id < 5) { 9266cc88d6bSMark Cave-Ayland esp_set_tc(s, s->mig_dma_left); 9276cc88d6bSMark Cave-Ayland } 9286cc88d6bSMark Cave-Ayland 9290bd005beSMark Cave-Ayland s->mig_version_id = vmstate_esp.version_id; 9300bd005beSMark Cave-Ayland return 0; 9310bd005beSMark Cave-Ayland } 9320bd005beSMark Cave-Ayland 9339c7e23fcSHervé Poussineau const VMStateDescription vmstate_esp = { 934cc9952f3SBlue Swirl .name = "esp", 9350bd005beSMark Cave-Ayland .version_id = 5, 936cc9952f3SBlue Swirl .minimum_version_id = 3, 9370bd005beSMark Cave-Ayland .pre_save = esp_pre_save, 9380bd005beSMark Cave-Ayland .post_load = esp_post_load, 939cc9952f3SBlue Swirl .fields = (VMStateField[]) { 940cc9952f3SBlue Swirl VMSTATE_BUFFER(rregs, ESPState), 941cc9952f3SBlue Swirl VMSTATE_BUFFER(wregs, ESPState), 942cc9952f3SBlue Swirl VMSTATE_INT32(ti_size, ESPState), 943cc9952f3SBlue Swirl VMSTATE_UINT32(ti_rptr, ESPState), 944cc9952f3SBlue Swirl VMSTATE_UINT32(ti_wptr, ESPState), 945cc9952f3SBlue Swirl VMSTATE_BUFFER(ti_buf, ESPState), 9463944966dSPaolo Bonzini VMSTATE_UINT32(status, ESPState), 947ea84a442SGuenter Roeck VMSTATE_UINT32(deferred_status, ESPState), 948ea84a442SGuenter Roeck VMSTATE_BOOL(deferred_complete, ESPState), 949cc9952f3SBlue Swirl VMSTATE_UINT32(dma, ESPState), 950cc966774SPaolo Bonzini VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16), 951cc966774SPaolo Bonzini VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4), 952cc9952f3SBlue Swirl VMSTATE_UINT32(cmdlen, ESPState), 953cc9952f3SBlue Swirl VMSTATE_UINT32(do_cmd, ESPState), 9546cc88d6bSMark Cave-Ayland VMSTATE_UINT32_TEST(mig_dma_left, ESPState, esp_is_before_version_5), 955*4e78f3bfSMark Cave-Ayland VMSTATE_BOOL_TEST(data_in_ready, ESPState, esp_is_version_5), 956cc9952f3SBlue Swirl VMSTATE_END_OF_LIST() 95774d71ea1SLaurent Vivier }, 958cc9952f3SBlue Swirl }; 9596f7e9aecSbellard 960a8170e5eSAvi Kivity static void sysbus_esp_mem_write(void *opaque, hwaddr addr, 961a391fdbcSHervé Poussineau uint64_t val, unsigned int size) 962a391fdbcSHervé Poussineau { 963a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 964eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 965a391fdbcSHervé Poussineau uint32_t saddr; 966a391fdbcSHervé Poussineau 967a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 968eb169c76SMark Cave-Ayland esp_reg_write(s, saddr, val); 969a391fdbcSHervé Poussineau } 970a391fdbcSHervé Poussineau 971a8170e5eSAvi Kivity static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr, 972a391fdbcSHervé Poussineau unsigned int size) 973a391fdbcSHervé Poussineau { 974a391fdbcSHervé Poussineau SysBusESPState *sysbus = opaque; 975eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 976a391fdbcSHervé Poussineau uint32_t saddr; 977a391fdbcSHervé Poussineau 978a391fdbcSHervé Poussineau saddr = addr >> sysbus->it_shift; 979eb169c76SMark Cave-Ayland return esp_reg_read(s, saddr); 980a391fdbcSHervé Poussineau } 981a391fdbcSHervé Poussineau 982a391fdbcSHervé Poussineau static const MemoryRegionOps sysbus_esp_mem_ops = { 983a391fdbcSHervé Poussineau .read = sysbus_esp_mem_read, 984a391fdbcSHervé Poussineau .write = sysbus_esp_mem_write, 985a391fdbcSHervé Poussineau .endianness = DEVICE_NATIVE_ENDIAN, 986a391fdbcSHervé Poussineau .valid.accepts = esp_mem_accepts, 987a391fdbcSHervé Poussineau }; 988a391fdbcSHervé Poussineau 98974d71ea1SLaurent Vivier static void sysbus_esp_pdma_write(void *opaque, hwaddr addr, 99074d71ea1SLaurent Vivier uint64_t val, unsigned int size) 99174d71ea1SLaurent Vivier { 99274d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 993eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 9943c421400SMark Cave-Ayland uint32_t dmalen; 99574d71ea1SLaurent Vivier 996960ebfd9SMark Cave-Ayland trace_esp_pdma_write(size); 997960ebfd9SMark Cave-Ayland 99874d71ea1SLaurent Vivier switch (size) { 99974d71ea1SLaurent Vivier case 1: 1000761bef75SMark Cave-Ayland esp_pdma_write(s, val); 100174d71ea1SLaurent Vivier break; 100274d71ea1SLaurent Vivier case 2: 1003761bef75SMark Cave-Ayland esp_pdma_write(s, val >> 8); 1004761bef75SMark Cave-Ayland esp_pdma_write(s, val); 100574d71ea1SLaurent Vivier break; 100674d71ea1SLaurent Vivier } 10073c421400SMark Cave-Ayland dmalen = esp_get_tc(s); 100882141c8bSMark Cave-Ayland if (dmalen == 0 || (s->ti_wptr == TI_BUFSZ)) { 100974d71ea1SLaurent Vivier s->pdma_cb(s); 101074d71ea1SLaurent Vivier } 101174d71ea1SLaurent Vivier } 101274d71ea1SLaurent Vivier 101374d71ea1SLaurent Vivier static uint64_t sysbus_esp_pdma_read(void *opaque, hwaddr addr, 101474d71ea1SLaurent Vivier unsigned int size) 101574d71ea1SLaurent Vivier { 101674d71ea1SLaurent Vivier SysBusESPState *sysbus = opaque; 1017eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 101874d71ea1SLaurent Vivier uint64_t val = 0; 101974d71ea1SLaurent Vivier 1020960ebfd9SMark Cave-Ayland trace_esp_pdma_read(size); 1021960ebfd9SMark Cave-Ayland 102274d71ea1SLaurent Vivier switch (size) { 102374d71ea1SLaurent Vivier case 1: 1024761bef75SMark Cave-Ayland val = esp_pdma_read(s); 102574d71ea1SLaurent Vivier break; 102674d71ea1SLaurent Vivier case 2: 1027761bef75SMark Cave-Ayland val = esp_pdma_read(s); 1028761bef75SMark Cave-Ayland val = (val << 8) | esp_pdma_read(s); 102974d71ea1SLaurent Vivier break; 103074d71ea1SLaurent Vivier } 103182141c8bSMark Cave-Ayland if (s->ti_rptr == s->ti_wptr) { 103282141c8bSMark Cave-Ayland s->ti_wptr = 0; 103382141c8bSMark Cave-Ayland s->ti_rptr = 0; 103474d71ea1SLaurent Vivier s->pdma_cb(s); 103574d71ea1SLaurent Vivier } 103674d71ea1SLaurent Vivier return val; 103774d71ea1SLaurent Vivier } 103874d71ea1SLaurent Vivier 103974d71ea1SLaurent Vivier static const MemoryRegionOps sysbus_esp_pdma_ops = { 104074d71ea1SLaurent Vivier .read = sysbus_esp_pdma_read, 104174d71ea1SLaurent Vivier .write = sysbus_esp_pdma_write, 104274d71ea1SLaurent Vivier .endianness = DEVICE_NATIVE_ENDIAN, 104374d71ea1SLaurent Vivier .valid.min_access_size = 1, 1044cf1b8286SMark Cave-Ayland .valid.max_access_size = 4, 1045cf1b8286SMark Cave-Ayland .impl.min_access_size = 1, 1046cf1b8286SMark Cave-Ayland .impl.max_access_size = 2, 104774d71ea1SLaurent Vivier }; 104874d71ea1SLaurent Vivier 1049afd4030cSPaolo Bonzini static const struct SCSIBusInfo esp_scsi_info = { 1050afd4030cSPaolo Bonzini .tcq = false, 10517e0380b9SPaolo Bonzini .max_target = ESP_MAX_DEVS, 10527e0380b9SPaolo Bonzini .max_lun = 7, 1053afd4030cSPaolo Bonzini 1054c6df7102SPaolo Bonzini .transfer_data = esp_transfer_data, 105594d3f98aSPaolo Bonzini .complete = esp_command_complete, 105694d3f98aSPaolo Bonzini .cancel = esp_request_cancelled 1057cfdc1bb0SPaolo Bonzini }; 1058cfdc1bb0SPaolo Bonzini 1059a391fdbcSHervé Poussineau static void sysbus_esp_gpio_demux(void *opaque, int irq, int level) 1060cfb9de9cSPaul Brook { 106184fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(opaque); 1062eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1063a391fdbcSHervé Poussineau 1064a391fdbcSHervé Poussineau switch (irq) { 1065a391fdbcSHervé Poussineau case 0: 1066a391fdbcSHervé Poussineau parent_esp_reset(s, irq, level); 1067a391fdbcSHervé Poussineau break; 1068a391fdbcSHervé Poussineau case 1: 1069a391fdbcSHervé Poussineau esp_dma_enable(opaque, irq, level); 1070a391fdbcSHervé Poussineau break; 1071a391fdbcSHervé Poussineau } 1072a391fdbcSHervé Poussineau } 1073a391fdbcSHervé Poussineau 1074b09318caSHu Tao static void sysbus_esp_realize(DeviceState *dev, Error **errp) 1075a391fdbcSHervé Poussineau { 1076b09318caSHu Tao SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 107784fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1078eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1079eb169c76SMark Cave-Ayland 1080eb169c76SMark Cave-Ayland if (!qdev_realize(DEVICE(s), NULL, errp)) { 1081eb169c76SMark Cave-Ayland return; 1082eb169c76SMark Cave-Ayland } 10836f7e9aecSbellard 1084b09318caSHu Tao sysbus_init_irq(sbd, &s->irq); 108574d71ea1SLaurent Vivier sysbus_init_irq(sbd, &s->irq_data); 1086a391fdbcSHervé Poussineau assert(sysbus->it_shift != -1); 10876f7e9aecSbellard 1088d32e4b3dSHervé Poussineau s->chip_id = TCHI_FAS100A; 108929776739SPaolo Bonzini memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops, 109074d71ea1SLaurent Vivier sysbus, "esp-regs", ESP_REGS << sysbus->it_shift); 1091b09318caSHu Tao sysbus_init_mmio(sbd, &sysbus->iomem); 109274d71ea1SLaurent Vivier memory_region_init_io(&sysbus->pdma, OBJECT(sysbus), &sysbus_esp_pdma_ops, 1093cf1b8286SMark Cave-Ayland sysbus, "esp-pdma", 4); 109474d71ea1SLaurent Vivier sysbus_init_mmio(sbd, &sysbus->pdma); 10956f7e9aecSbellard 1096b09318caSHu Tao qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2); 10972d069babSblueswir1 1098b1187b51SAndreas Färber scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL); 109967e999beSbellard } 1100cfb9de9cSPaul Brook 1101a391fdbcSHervé Poussineau static void sysbus_esp_hard_reset(DeviceState *dev) 1102a391fdbcSHervé Poussineau { 110384fbefedSMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(dev); 1104eb169c76SMark Cave-Ayland ESPState *s = ESP(&sysbus->esp); 1105eb169c76SMark Cave-Ayland 1106eb169c76SMark Cave-Ayland esp_hard_reset(s); 1107eb169c76SMark Cave-Ayland } 1108eb169c76SMark Cave-Ayland 1109eb169c76SMark Cave-Ayland static void sysbus_esp_init(Object *obj) 1110eb169c76SMark Cave-Ayland { 1111eb169c76SMark Cave-Ayland SysBusESPState *sysbus = SYSBUS_ESP(obj); 1112eb169c76SMark Cave-Ayland 1113eb169c76SMark Cave-Ayland object_initialize_child(obj, "esp", &sysbus->esp, TYPE_ESP); 1114a391fdbcSHervé Poussineau } 1115a391fdbcSHervé Poussineau 1116a391fdbcSHervé Poussineau static const VMStateDescription vmstate_sysbus_esp_scsi = { 1117a391fdbcSHervé Poussineau .name = "sysbusespscsi", 11180bd005beSMark Cave-Ayland .version_id = 2, 1119ea84a442SGuenter Roeck .minimum_version_id = 1, 1120a391fdbcSHervé Poussineau .fields = (VMStateField[]) { 11210bd005beSMark Cave-Ayland VMSTATE_UINT8_V(esp.mig_version_id, SysBusESPState, 2), 1122a391fdbcSHervé Poussineau VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState), 1123a391fdbcSHervé Poussineau VMSTATE_END_OF_LIST() 1124a391fdbcSHervé Poussineau } 1125999e12bbSAnthony Liguori }; 1126999e12bbSAnthony Liguori 1127a391fdbcSHervé Poussineau static void sysbus_esp_class_init(ObjectClass *klass, void *data) 1128999e12bbSAnthony Liguori { 112939bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass); 1130999e12bbSAnthony Liguori 1131b09318caSHu Tao dc->realize = sysbus_esp_realize; 1132a391fdbcSHervé Poussineau dc->reset = sysbus_esp_hard_reset; 1133a391fdbcSHervé Poussineau dc->vmsd = &vmstate_sysbus_esp_scsi; 1134125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 113563235df8SBlue Swirl } 1136999e12bbSAnthony Liguori 11371f077308SHervé Poussineau static const TypeInfo sysbus_esp_info = { 113884fbefedSMark Cave-Ayland .name = TYPE_SYSBUS_ESP, 113939bffca2SAnthony Liguori .parent = TYPE_SYS_BUS_DEVICE, 1140eb169c76SMark Cave-Ayland .instance_init = sysbus_esp_init, 1141a391fdbcSHervé Poussineau .instance_size = sizeof(SysBusESPState), 1142a391fdbcSHervé Poussineau .class_init = sysbus_esp_class_init, 114363235df8SBlue Swirl }; 114463235df8SBlue Swirl 1145eb169c76SMark Cave-Ayland static void esp_class_init(ObjectClass *klass, void *data) 1146eb169c76SMark Cave-Ayland { 1147eb169c76SMark Cave-Ayland DeviceClass *dc = DEVICE_CLASS(klass); 1148eb169c76SMark Cave-Ayland 1149eb169c76SMark Cave-Ayland /* internal device for sysbusesp/pciespscsi, not user-creatable */ 1150eb169c76SMark Cave-Ayland dc->user_creatable = false; 1151eb169c76SMark Cave-Ayland set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); 1152eb169c76SMark Cave-Ayland } 1153eb169c76SMark Cave-Ayland 1154eb169c76SMark Cave-Ayland static const TypeInfo esp_info = { 1155eb169c76SMark Cave-Ayland .name = TYPE_ESP, 1156eb169c76SMark Cave-Ayland .parent = TYPE_DEVICE, 1157eb169c76SMark Cave-Ayland .instance_size = sizeof(ESPState), 1158eb169c76SMark Cave-Ayland .class_init = esp_class_init, 1159eb169c76SMark Cave-Ayland }; 1160eb169c76SMark Cave-Ayland 116183f7d43aSAndreas Färber static void esp_register_types(void) 1162cfb9de9cSPaul Brook { 1163a391fdbcSHervé Poussineau type_register_static(&sysbus_esp_info); 1164eb169c76SMark Cave-Ayland type_register_static(&esp_info); 1165cfb9de9cSPaul Brook } 1166cfb9de9cSPaul Brook 116783f7d43aSAndreas Färber type_init(esp_register_types) 1168