]> git.proxmox.com Git - mirror_qemu.git/blame - hw/scsi/esp.c
Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging
[mirror_qemu.git] / hw / scsi / esp.c
CommitLineData
6f7e9aec 1/*
67e999be 2 * QEMU ESP/NCR53C9x emulation
5fafdf24 3 *
4e9aec74 4 * Copyright (c) 2005-2006 Fabrice Bellard
fabaaf1d 5 * Copyright (c) 2012 Herve Poussineau
5fafdf24 6 *
6f7e9aec
FB
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
5d20fa6b 25
a4ab4792 26#include "qemu/osdep.h"
83c9f4ca 27#include "hw/sysbus.h"
0d09e41a 28#include "hw/scsi/esp.h"
bf4b9889 29#include "trace.h"
1de7afc9 30#include "qemu/log.h"
6f7e9aec 31
67e999be 32/*
5ad6bb97
BS
33 * On Sparc32, this is the ESP (NCR53C90) part of chip STP2000 (Master I/O),
34 * also produced as NCR89C100. See
67e999be
FB
35 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt
36 * and
37 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR53C9X.txt
38 */
39
c73f96fd
BS
40static void esp_raise_irq(ESPState *s)
41{
42 if (!(s->rregs[ESP_RSTAT] & STAT_INT)) {
43 s->rregs[ESP_RSTAT] |= STAT_INT;
44 qemu_irq_raise(s->irq);
bf4b9889 45 trace_esp_raise_irq();
c73f96fd
BS
46 }
47}
48
49static void esp_lower_irq(ESPState *s)
50{
51 if (s->rregs[ESP_RSTAT] & STAT_INT) {
52 s->rregs[ESP_RSTAT] &= ~STAT_INT;
53 qemu_irq_lower(s->irq);
bf4b9889 54 trace_esp_lower_irq();
c73f96fd
BS
55 }
56}
57
9c7e23fc 58void esp_dma_enable(ESPState *s, int irq, int level)
73d74342 59{
73d74342
BS
60 if (level) {
61 s->dma_enabled = 1;
bf4b9889 62 trace_esp_dma_enable();
73d74342
BS
63 if (s->dma_cb) {
64 s->dma_cb(s);
65 s->dma_cb = NULL;
66 }
67 } else {
bf4b9889 68 trace_esp_dma_disable();
73d74342
BS
69 s->dma_enabled = 0;
70 }
71}
72
9c7e23fc 73void esp_request_cancelled(SCSIRequest *req)
94d3f98a 74{
e6810db8 75 ESPState *s = req->hba_private;
94d3f98a
PB
76
77 if (req == s->current_req) {
78 scsi_req_unref(s->current_req);
79 s->current_req = NULL;
80 s->current_dev = NULL;
81 }
82}
83
6c1fef6b 84static uint32_t get_cmd(ESPState *s, uint8_t *buf, uint8_t buflen)
2f275b8f 85{
a917d384 86 uint32_t dmalen;
2f275b8f
FB
87 int target;
88
8dea1dd4 89 target = s->wregs[ESP_WBUSID] & BUSID_DID;
4f6200f0 90 if (s->dma) {
9ea73f8b
PB
91 dmalen = s->rregs[ESP_TCLO];
92 dmalen |= s->rregs[ESP_TCMID] << 8;
93 dmalen |= s->rregs[ESP_TCHI] << 16;
6c1fef6b
PP
94 if (dmalen > buflen) {
95 return 0;
96 }
8b17de88 97 s->dma_memory_read(s->dma_opaque, buf, dmalen);
4f6200f0 98 } else {
fc4d65da 99 dmalen = s->ti_size;
d3cdc491
PP
100 if (dmalen > TI_BUFSZ) {
101 return 0;
102 }
fc4d65da 103 memcpy(buf, s->ti_buf, dmalen);
75ef8496 104 buf[0] = buf[2] >> 5;
4f6200f0 105 }
bf4b9889 106 trace_esp_get_cmd(dmalen, target);
2e5d83bb 107
2f275b8f 108 s->ti_size = 0;
4f6200f0
FB
109 s->ti_rptr = 0;
110 s->ti_wptr = 0;
2f275b8f 111
429bef69 112 if (s->current_req) {
a917d384 113 /* Started a new command before the old one finished. Cancel it. */
94d3f98a 114 scsi_req_cancel(s->current_req);
a917d384
PB
115 s->async_len = 0;
116 }
117
0d3545e7 118 s->current_dev = scsi_device_find(&s->bus, 0, target, 0);
f48a7a6e 119 if (!s->current_dev) {
2e5d83bb 120 // No such drive
c73f96fd 121 s->rregs[ESP_RSTAT] = 0;
5ad6bb97
BS
122 s->rregs[ESP_RINTR] = INTR_DC;
123 s->rregs[ESP_RSEQ] = SEQ_0;
c73f96fd 124 esp_raise_irq(s);
f930d07e 125 return 0;
2f275b8f 126 }
9f149aa9
PB
127 return dmalen;
128}
129
f2818f22 130static void do_busid_cmd(ESPState *s, uint8_t *buf, uint8_t busid)
9f149aa9
PB
131{
132 int32_t datalen;
133 int lun;
f48a7a6e 134 SCSIDevice *current_lun;
9f149aa9 135
bf4b9889 136 trace_esp_do_busid_cmd(busid);
f2818f22 137 lun = busid & 7;
0d3545e7 138 current_lun = scsi_device_find(&s->bus, 0, s->current_dev->id, lun);
e6810db8 139 s->current_req = scsi_req_new(current_lun, 0, lun, buf, s);
c39ce112 140 datalen = scsi_req_enqueue(s->current_req);
67e999be
FB
141 s->ti_size = datalen;
142 if (datalen != 0) {
c73f96fd 143 s->rregs[ESP_RSTAT] = STAT_TC;
a917d384 144 s->dma_left = 0;
6787f5fa 145 s->dma_counter = 0;
2e5d83bb 146 if (datalen > 0) {
5ad6bb97 147 s->rregs[ESP_RSTAT] |= STAT_DI;
2e5d83bb 148 } else {
5ad6bb97 149 s->rregs[ESP_RSTAT] |= STAT_DO;
b9788fc4 150 }
ad3376cc 151 scsi_req_continue(s->current_req);
2f275b8f 152 }
5ad6bb97
BS
153 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
154 s->rregs[ESP_RSEQ] = SEQ_CD;
c73f96fd 155 esp_raise_irq(s);
2f275b8f
FB
156}
157
f2818f22
AT
158static void do_cmd(ESPState *s, uint8_t *buf)
159{
160 uint8_t busid = buf[0];
161
162 do_busid_cmd(s, &buf[1], busid);
163}
164
9f149aa9
PB
165static void handle_satn(ESPState *s)
166{
167 uint8_t buf[32];
168 int len;
169
1b26eaa1 170 if (s->dma && !s->dma_enabled) {
73d74342
BS
171 s->dma_cb = handle_satn;
172 return;
173 }
6c1fef6b 174 len = get_cmd(s, buf, sizeof(buf));
9f149aa9
PB
175 if (len)
176 do_cmd(s, buf);
177}
178
f2818f22
AT
179static void handle_s_without_atn(ESPState *s)
180{
181 uint8_t buf[32];
182 int len;
183
1b26eaa1 184 if (s->dma && !s->dma_enabled) {
73d74342
BS
185 s->dma_cb = handle_s_without_atn;
186 return;
187 }
6c1fef6b 188 len = get_cmd(s, buf, sizeof(buf));
f2818f22
AT
189 if (len) {
190 do_busid_cmd(s, buf, 0);
191 }
192}
193
9f149aa9
PB
194static void handle_satn_stop(ESPState *s)
195{
1b26eaa1 196 if (s->dma && !s->dma_enabled) {
73d74342
BS
197 s->dma_cb = handle_satn_stop;
198 return;
199 }
6c1fef6b 200 s->cmdlen = get_cmd(s, s->cmdbuf, sizeof(s->cmdbuf));
9f149aa9 201 if (s->cmdlen) {
bf4b9889 202 trace_esp_handle_satn_stop(s->cmdlen);
9f149aa9 203 s->do_cmd = 1;
c73f96fd 204 s->rregs[ESP_RSTAT] = STAT_TC | STAT_CD;
5ad6bb97
BS
205 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
206 s->rregs[ESP_RSEQ] = SEQ_CD;
c73f96fd 207 esp_raise_irq(s);
9f149aa9
PB
208 }
209}
210
0fc5c15a 211static void write_response(ESPState *s)
2f275b8f 212{
bf4b9889 213 trace_esp_write_response(s->status);
3944966d 214 s->ti_buf[0] = s->status;
0fc5c15a 215 s->ti_buf[1] = 0;
4f6200f0 216 if (s->dma) {
8b17de88 217 s->dma_memory_write(s->dma_opaque, s->ti_buf, 2);
c73f96fd 218 s->rregs[ESP_RSTAT] = STAT_TC | STAT_ST;
5ad6bb97
BS
219 s->rregs[ESP_RINTR] = INTR_BS | INTR_FC;
220 s->rregs[ESP_RSEQ] = SEQ_CD;
4f6200f0 221 } else {
f930d07e
BS
222 s->ti_size = 2;
223 s->ti_rptr = 0;
d020aa50 224 s->ti_wptr = 2;
5ad6bb97 225 s->rregs[ESP_RFLAGS] = 2;
4f6200f0 226 }
c73f96fd 227 esp_raise_irq(s);
2f275b8f 228}
4f6200f0 229
a917d384
PB
230static void esp_dma_done(ESPState *s)
231{
c73f96fd 232 s->rregs[ESP_RSTAT] |= STAT_TC;
5ad6bb97
BS
233 s->rregs[ESP_RINTR] = INTR_BS;
234 s->rregs[ESP_RSEQ] = 0;
235 s->rregs[ESP_RFLAGS] = 0;
236 s->rregs[ESP_TCLO] = 0;
237 s->rregs[ESP_TCMID] = 0;
9ea73f8b 238 s->rregs[ESP_TCHI] = 0;
c73f96fd 239 esp_raise_irq(s);
a917d384
PB
240}
241
4d611c9a
PB
242static void esp_do_dma(ESPState *s)
243{
67e999be 244 uint32_t len;
4d611c9a 245 int to_device;
a917d384 246
a917d384 247 len = s->dma_left;
4d611c9a 248 if (s->do_cmd) {
bf4b9889 249 trace_esp_do_dma(s->cmdlen, len);
926cde5f
PP
250 assert (s->cmdlen <= sizeof(s->cmdbuf) &&
251 len <= sizeof(s->cmdbuf) - s->cmdlen);
8b17de88 252 s->dma_memory_read(s->dma_opaque, &s->cmdbuf[s->cmdlen], len);
4d611c9a 253 return;
a917d384
PB
254 }
255 if (s->async_len == 0) {
256 /* Defer until data is available. */
257 return;
258 }
259 if (len > s->async_len) {
260 len = s->async_len;
261 }
7f0b6e11 262 to_device = (s->ti_size < 0);
a917d384 263 if (to_device) {
8b17de88 264 s->dma_memory_read(s->dma_opaque, s->async_buf, len);
4d611c9a 265 } else {
8b17de88 266 s->dma_memory_write(s->dma_opaque, s->async_buf, len);
a917d384 267 }
a917d384
PB
268 s->dma_left -= len;
269 s->async_buf += len;
270 s->async_len -= len;
6787f5fa
PB
271 if (to_device)
272 s->ti_size += len;
273 else
274 s->ti_size -= len;
a917d384 275 if (s->async_len == 0) {
ad3376cc
PB
276 scsi_req_continue(s->current_req);
277 /* If there is still data to be read from the device then
278 complete the DMA operation immediately. Otherwise defer
279 until the scsi layer has completed. */
280 if (to_device || s->dma_left != 0 || s->ti_size == 0) {
281 return;
4d611c9a 282 }
a917d384 283 }
ad3376cc
PB
284
285 /* Partially filled a scsi buffer. Complete immediately. */
286 esp_dma_done(s);
4d611c9a
PB
287}
288
9c7e23fc 289void esp_command_complete(SCSIRequest *req, uint32_t status,
01e95455 290 size_t resid)
2e5d83bb 291{
e6810db8 292 ESPState *s = req->hba_private;
2e5d83bb 293
bf4b9889 294 trace_esp_command_complete();
c6df7102 295 if (s->ti_size != 0) {
bf4b9889 296 trace_esp_command_complete_unexpected();
c6df7102
PB
297 }
298 s->ti_size = 0;
299 s->dma_left = 0;
300 s->async_len = 0;
aba1f023 301 if (status) {
bf4b9889 302 trace_esp_command_complete_fail();
c6df7102 303 }
aba1f023 304 s->status = status;
c6df7102
PB
305 s->rregs[ESP_RSTAT] = STAT_ST;
306 esp_dma_done(s);
307 if (s->current_req) {
308 scsi_req_unref(s->current_req);
309 s->current_req = NULL;
310 s->current_dev = NULL;
311 }
312}
313
9c7e23fc 314void esp_transfer_data(SCSIRequest *req, uint32_t len)
c6df7102 315{
e6810db8 316 ESPState *s = req->hba_private;
c6df7102 317
7f0b6e11 318 assert(!s->do_cmd);
bf4b9889 319 trace_esp_transfer_data(s->dma_left, s->ti_size);
aba1f023 320 s->async_len = len;
c6df7102
PB
321 s->async_buf = scsi_req_get_buf(req);
322 if (s->dma_left) {
323 esp_do_dma(s);
324 } else if (s->dma_counter != 0 && s->ti_size <= 0) {
325 /* If this was the last part of a DMA transfer then the
326 completion interrupt is deferred to here. */
a917d384 327 esp_dma_done(s);
4d611c9a 328 }
2e5d83bb
PB
329}
330
2f275b8f
FB
331static void handle_ti(ESPState *s)
332{
4d611c9a 333 uint32_t dmalen, minlen;
2f275b8f 334
7246e160
HP
335 if (s->dma && !s->dma_enabled) {
336 s->dma_cb = handle_ti;
337 return;
338 }
339
9ea73f8b
PB
340 dmalen = s->rregs[ESP_TCLO];
341 dmalen |= s->rregs[ESP_TCMID] << 8;
342 dmalen |= s->rregs[ESP_TCHI] << 16;
db59203d
PB
343 if (dmalen==0) {
344 dmalen=0x10000;
345 }
6787f5fa 346 s->dma_counter = dmalen;
db59203d 347
9f149aa9 348 if (s->do_cmd)
926cde5f 349 minlen = (dmalen < ESP_CMDBUF_SZ) ? dmalen : ESP_CMDBUF_SZ;
67e999be
FB
350 else if (s->ti_size < 0)
351 minlen = (dmalen < -s->ti_size) ? dmalen : -s->ti_size;
9f149aa9
PB
352 else
353 minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
bf4b9889 354 trace_esp_handle_ti(minlen);
4f6200f0 355 if (s->dma) {
4d611c9a 356 s->dma_left = minlen;
5ad6bb97 357 s->rregs[ESP_RSTAT] &= ~STAT_TC;
4d611c9a 358 esp_do_dma(s);
7f0b6e11
PB
359 }
360 if (s->do_cmd) {
bf4b9889 361 trace_esp_handle_ti_cmd(s->cmdlen);
9f149aa9
PB
362 s->ti_size = 0;
363 s->cmdlen = 0;
364 s->do_cmd = 0;
365 do_cmd(s, s->cmdbuf);
9f149aa9 366 }
2f275b8f
FB
367}
368
9c7e23fc 369void esp_hard_reset(ESPState *s)
6f7e9aec 370{
5aca8c3b
BS
371 memset(s->rregs, 0, ESP_REGS);
372 memset(s->wregs, 0, ESP_REGS);
c9cf45c1 373 s->tchi_written = 0;
4e9aec74
PB
374 s->ti_size = 0;
375 s->ti_rptr = 0;
376 s->ti_wptr = 0;
4e9aec74 377 s->dma = 0;
9f149aa9 378 s->do_cmd = 0;
73d74342 379 s->dma_cb = NULL;
8dea1dd4
BS
380
381 s->rregs[ESP_CFG1] = 7;
6f7e9aec
FB
382}
383
a391fdbc 384static void esp_soft_reset(ESPState *s)
85948643 385{
85948643 386 qemu_irq_lower(s->irq);
a391fdbc 387 esp_hard_reset(s);
85948643
BS
388}
389
a391fdbc 390static void parent_esp_reset(ESPState *s, int irq, int level)
2d069bab 391{
85948643 392 if (level) {
a391fdbc 393 esp_soft_reset(s);
85948643 394 }
2d069bab
BS
395}
396
9c7e23fc 397uint64_t esp_reg_read(ESPState *s, uint32_t saddr)
73d74342 398{
a391fdbc 399 uint32_t old_val;
73d74342 400
bf4b9889 401 trace_esp_mem_readb(saddr, s->rregs[saddr]);
6f7e9aec 402 switch (saddr) {
5ad6bb97 403 case ESP_FIFO:
ff589551
PP
404 if ((s->rregs[ESP_RSTAT] & STAT_PIO_MASK) == 0) {
405 /* Data out. */
406 qemu_log_mask(LOG_UNIMP, "esp: PIO data read not implemented\n");
407 s->rregs[ESP_FIFO] = 0;
ff589551 408 } else if (s->ti_rptr < s->ti_wptr) {
f930d07e 409 s->ti_size--;
ff589551 410 s->rregs[ESP_FIFO] = s->ti_buf[s->ti_rptr++];
f930d07e 411 }
ff589551 412 if (s->ti_rptr == s->ti_wptr) {
4f6200f0
FB
413 s->ti_rptr = 0;
414 s->ti_wptr = 0;
415 }
f930d07e 416 break;
5ad6bb97 417 case ESP_RINTR:
2814df28
BS
418 /* Clear sequence step, interrupt register and all status bits
419 except TC */
420 old_val = s->rregs[ESP_RINTR];
421 s->rregs[ESP_RINTR] = 0;
422 s->rregs[ESP_RSTAT] &= ~STAT_TC;
423 s->rregs[ESP_RSEQ] = SEQ_CD;
c73f96fd 424 esp_lower_irq(s);
2814df28
BS
425
426 return old_val;
c9cf45c1
HR
427 case ESP_TCHI:
428 /* Return the unique id if the value has never been written */
429 if (!s->tchi_written) {
430 return s->chip_id;
431 }
6f7e9aec 432 default:
f930d07e 433 break;
6f7e9aec 434 }
2f275b8f 435 return s->rregs[saddr];
6f7e9aec
FB
436}
437
9c7e23fc 438void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
6f7e9aec 439{
bf4b9889 440 trace_esp_mem_writeb(saddr, s->wregs[saddr], val);
6f7e9aec 441 switch (saddr) {
c9cf45c1
HR
442 case ESP_TCHI:
443 s->tchi_written = true;
444 /* fall through */
5ad6bb97
BS
445 case ESP_TCLO:
446 case ESP_TCMID:
447 s->rregs[ESP_RSTAT] &= ~STAT_TC;
4f6200f0 448 break;
5ad6bb97 449 case ESP_FIFO:
9f149aa9 450 if (s->do_cmd) {
926cde5f 451 if (s->cmdlen < ESP_CMDBUF_SZ) {
c98c6c10
PP
452 s->cmdbuf[s->cmdlen++] = val & 0xff;
453 } else {
454 trace_esp_error_fifo_overrun();
455 }
ff589551 456 } else if (s->ti_wptr == TI_BUFSZ - 1) {
3af4e9aa 457 trace_esp_error_fifo_overrun();
2e5d83bb
PB
458 } else {
459 s->ti_size++;
460 s->ti_buf[s->ti_wptr++] = val & 0xff;
461 }
f930d07e 462 break;
5ad6bb97 463 case ESP_CMD:
4f6200f0 464 s->rregs[saddr] = val;
5ad6bb97 465 if (val & CMD_DMA) {
f930d07e 466 s->dma = 1;
6787f5fa 467 /* Reload DMA counter. */
5ad6bb97
BS
468 s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
469 s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
9ea73f8b 470 s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
f930d07e
BS
471 } else {
472 s->dma = 0;
473 }
5ad6bb97
BS
474 switch(val & CMD_CMD) {
475 case CMD_NOP:
bf4b9889 476 trace_esp_mem_writeb_cmd_nop(val);
f930d07e 477 break;
5ad6bb97 478 case CMD_FLUSH:
bf4b9889 479 trace_esp_mem_writeb_cmd_flush(val);
9e61bde5 480 //s->ti_size = 0;
5ad6bb97
BS
481 s->rregs[ESP_RINTR] = INTR_FC;
482 s->rregs[ESP_RSEQ] = 0;
a214c598 483 s->rregs[ESP_RFLAGS] = 0;
f930d07e 484 break;
5ad6bb97 485 case CMD_RESET:
bf4b9889 486 trace_esp_mem_writeb_cmd_reset(val);
a391fdbc 487 esp_soft_reset(s);
f930d07e 488 break;
5ad6bb97 489 case CMD_BUSRESET:
bf4b9889 490 trace_esp_mem_writeb_cmd_bus_reset(val);
5ad6bb97
BS
491 s->rregs[ESP_RINTR] = INTR_RST;
492 if (!(s->wregs[ESP_CFG1] & CFG1_RESREPT)) {
c73f96fd 493 esp_raise_irq(s);
9e61bde5 494 }
f930d07e 495 break;
5ad6bb97 496 case CMD_TI:
f930d07e
BS
497 handle_ti(s);
498 break;
5ad6bb97 499 case CMD_ICCS:
bf4b9889 500 trace_esp_mem_writeb_cmd_iccs(val);
f930d07e 501 write_response(s);
4bf5801d
BS
502 s->rregs[ESP_RINTR] = INTR_FC;
503 s->rregs[ESP_RSTAT] |= STAT_MI;
f930d07e 504 break;
5ad6bb97 505 case CMD_MSGACC:
bf4b9889 506 trace_esp_mem_writeb_cmd_msgacc(val);
5ad6bb97
BS
507 s->rregs[ESP_RINTR] = INTR_DC;
508 s->rregs[ESP_RSEQ] = 0;
4e2a68c1
AT
509 s->rregs[ESP_RFLAGS] = 0;
510 esp_raise_irq(s);
f930d07e 511 break;
0fd0eb21 512 case CMD_PAD:
bf4b9889 513 trace_esp_mem_writeb_cmd_pad(val);
0fd0eb21
BS
514 s->rregs[ESP_RSTAT] = STAT_TC;
515 s->rregs[ESP_RINTR] = INTR_FC;
516 s->rregs[ESP_RSEQ] = 0;
517 break;
5ad6bb97 518 case CMD_SATN:
bf4b9889 519 trace_esp_mem_writeb_cmd_satn(val);
f930d07e 520 break;
6915bff1
HP
521 case CMD_RSTATN:
522 trace_esp_mem_writeb_cmd_rstatn(val);
523 break;
5e1e0a3b 524 case CMD_SEL:
bf4b9889 525 trace_esp_mem_writeb_cmd_sel(val);
f2818f22 526 handle_s_without_atn(s);
5e1e0a3b 527 break;
5ad6bb97 528 case CMD_SELATN:
bf4b9889 529 trace_esp_mem_writeb_cmd_selatn(val);
f930d07e
BS
530 handle_satn(s);
531 break;
5ad6bb97 532 case CMD_SELATNS:
bf4b9889 533 trace_esp_mem_writeb_cmd_selatns(val);
f930d07e
BS
534 handle_satn_stop(s);
535 break;
5ad6bb97 536 case CMD_ENSEL:
bf4b9889 537 trace_esp_mem_writeb_cmd_ensel(val);
e3926838 538 s->rregs[ESP_RINTR] = 0;
74ec6048 539 break;
6fe84c18
HP
540 case CMD_DISSEL:
541 trace_esp_mem_writeb_cmd_dissel(val);
542 s->rregs[ESP_RINTR] = 0;
543 esp_raise_irq(s);
544 break;
f930d07e 545 default:
3af4e9aa 546 trace_esp_error_unhandled_command(val);
f930d07e
BS
547 break;
548 }
549 break;
5ad6bb97 550 case ESP_WBUSID ... ESP_WSYNO:
f930d07e 551 break;
5ad6bb97 552 case ESP_CFG1:
9ea73f8b
PB
553 case ESP_CFG2: case ESP_CFG3:
554 case ESP_RES3: case ESP_RES4:
4f6200f0
FB
555 s->rregs[saddr] = val;
556 break;
5ad6bb97 557 case ESP_WCCF ... ESP_WTEST:
4f6200f0 558 break;
6f7e9aec 559 default:
3af4e9aa 560 trace_esp_error_invalid_write(val, saddr);
8dea1dd4 561 return;
6f7e9aec 562 }
2f275b8f 563 s->wregs[saddr] = val;
6f7e9aec
FB
564}
565
a8170e5e 566static bool esp_mem_accepts(void *opaque, hwaddr addr,
8372d383
PM
567 unsigned size, bool is_write,
568 MemTxAttrs attrs)
67bb5314
AK
569{
570 return (size == 1) || (is_write && size == 4);
571}
6f7e9aec 572
9c7e23fc 573const VMStateDescription vmstate_esp = {
cc9952f3 574 .name ="esp",
cc966774 575 .version_id = 4,
cc9952f3 576 .minimum_version_id = 3,
35d08458 577 .fields = (VMStateField[]) {
cc9952f3
BS
578 VMSTATE_BUFFER(rregs, ESPState),
579 VMSTATE_BUFFER(wregs, ESPState),
580 VMSTATE_INT32(ti_size, ESPState),
581 VMSTATE_UINT32(ti_rptr, ESPState),
582 VMSTATE_UINT32(ti_wptr, ESPState),
583 VMSTATE_BUFFER(ti_buf, ESPState),
3944966d 584 VMSTATE_UINT32(status, ESPState),
cc9952f3 585 VMSTATE_UINT32(dma, ESPState),
cc966774
PB
586 VMSTATE_PARTIAL_BUFFER(cmdbuf, ESPState, 16),
587 VMSTATE_BUFFER_START_MIDDLE_V(cmdbuf, ESPState, 16, 4),
cc9952f3
BS
588 VMSTATE_UINT32(cmdlen, ESPState),
589 VMSTATE_UINT32(do_cmd, ESPState),
590 VMSTATE_UINT32(dma_left, ESPState),
591 VMSTATE_END_OF_LIST()
592 }
593};
6f7e9aec 594
a8170e5e 595static void sysbus_esp_mem_write(void *opaque, hwaddr addr,
a391fdbc
HP
596 uint64_t val, unsigned int size)
597{
598 SysBusESPState *sysbus = opaque;
599 uint32_t saddr;
600
601 saddr = addr >> sysbus->it_shift;
602 esp_reg_write(&sysbus->esp, saddr, val);
603}
604
a8170e5e 605static uint64_t sysbus_esp_mem_read(void *opaque, hwaddr addr,
a391fdbc
HP
606 unsigned int size)
607{
608 SysBusESPState *sysbus = opaque;
609 uint32_t saddr;
610
611 saddr = addr >> sysbus->it_shift;
612 return esp_reg_read(&sysbus->esp, saddr);
613}
614
615static const MemoryRegionOps sysbus_esp_mem_ops = {
616 .read = sysbus_esp_mem_read,
617 .write = sysbus_esp_mem_write,
618 .endianness = DEVICE_NATIVE_ENDIAN,
619 .valid.accepts = esp_mem_accepts,
620};
621
afd4030c
PB
622static const struct SCSIBusInfo esp_scsi_info = {
623 .tcq = false,
7e0380b9
PB
624 .max_target = ESP_MAX_DEVS,
625 .max_lun = 7,
afd4030c 626
c6df7102 627 .transfer_data = esp_transfer_data,
94d3f98a
PB
628 .complete = esp_command_complete,
629 .cancel = esp_request_cancelled
cfdc1bb0
PB
630};
631
a391fdbc 632static void sysbus_esp_gpio_demux(void *opaque, int irq, int level)
cfb9de9c 633{
80cac47e 634 SysBusESPState *sysbus = ESP_STATE(opaque);
a391fdbc
HP
635 ESPState *s = &sysbus->esp;
636
637 switch (irq) {
638 case 0:
639 parent_esp_reset(s, irq, level);
640 break;
641 case 1:
642 esp_dma_enable(opaque, irq, level);
643 break;
644 }
645}
646
b09318ca 647static void sysbus_esp_realize(DeviceState *dev, Error **errp)
a391fdbc 648{
b09318ca 649 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
80cac47e 650 SysBusESPState *sysbus = ESP_STATE(dev);
a391fdbc 651 ESPState *s = &sysbus->esp;
6f7e9aec 652
b09318ca 653 sysbus_init_irq(sbd, &s->irq);
a391fdbc 654 assert(sysbus->it_shift != -1);
6f7e9aec 655
d32e4b3d 656 s->chip_id = TCHI_FAS100A;
29776739
PB
657 memory_region_init_io(&sysbus->iomem, OBJECT(sysbus), &sysbus_esp_mem_ops,
658 sysbus, "esp", ESP_REGS << sysbus->it_shift);
b09318ca 659 sysbus_init_mmio(sbd, &sysbus->iomem);
6f7e9aec 660
b09318ca 661 qdev_init_gpio_in(dev, sysbus_esp_gpio_demux, 2);
2d069bab 662
b1187b51 663 scsi_bus_new(&s->bus, sizeof(s->bus), dev, &esp_scsi_info, NULL);
67e999be 664}
cfb9de9c 665
a391fdbc
HP
666static void sysbus_esp_hard_reset(DeviceState *dev)
667{
80cac47e 668 SysBusESPState *sysbus = ESP_STATE(dev);
a391fdbc
HP
669 esp_hard_reset(&sysbus->esp);
670}
671
672static const VMStateDescription vmstate_sysbus_esp_scsi = {
673 .name = "sysbusespscsi",
674 .version_id = 0,
675 .minimum_version_id = 0,
a391fdbc
HP
676 .fields = (VMStateField[]) {
677 VMSTATE_STRUCT(esp, SysBusESPState, 0, vmstate_esp, ESPState),
678 VMSTATE_END_OF_LIST()
679 }
999e12bb
AL
680};
681
a391fdbc 682static void sysbus_esp_class_init(ObjectClass *klass, void *data)
999e12bb 683{
39bffca2 684 DeviceClass *dc = DEVICE_CLASS(klass);
999e12bb 685
b09318ca 686 dc->realize = sysbus_esp_realize;
a391fdbc
HP
687 dc->reset = sysbus_esp_hard_reset;
688 dc->vmsd = &vmstate_sysbus_esp_scsi;
125ee0ed 689 set_bit(DEVICE_CATEGORY_STORAGE, dc->categories);
999e12bb
AL
690}
691
1f077308 692static const TypeInfo sysbus_esp_info = {
a71c7ec5 693 .name = TYPE_ESP,
39bffca2 694 .parent = TYPE_SYS_BUS_DEVICE,
a391fdbc
HP
695 .instance_size = sizeof(SysBusESPState),
696 .class_init = sysbus_esp_class_init,
63235df8
BS
697};
698
83f7d43a 699static void esp_register_types(void)
cfb9de9c 700{
a391fdbc 701 type_register_static(&sysbus_esp_info);
cfb9de9c
PB
702}
703
83f7d43a 704type_init(esp_register_types)