ide_disk.cc (11522:348411ec525a) ide_disk.cc (11980:56d16946ed95)
1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Andrew Schultz
41 * Ali Saidi
42 */
43
44/** @file
45 * Device model implementation for an IDE disk
46 */
47
48#include "dev/storage/ide_disk.hh"
49
50#include <cerrno>
51#include <cstring>
52#include <deque>
53#include <string>
54
55#include "arch/isa_traits.hh"
56#include "base/chunk_generator.hh"
57#include "base/cprintf.hh" // csprintf
58#include "base/trace.hh"
59#include "config/the_isa.hh"
60#include "debug/IdeDisk.hh"
61#include "dev/storage/disk_image.hh"
62#include "dev/storage/ide_ctrl.hh"
63#include "sim/core.hh"
64#include "sim/sim_object.hh"
65
66using namespace std;
67using namespace TheISA;
68
69IdeDisk::IdeDisk(const Params *p)
70 : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
71 dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
72 dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
73 dmaReadEvent(this), dmaWriteEvent(this)
74{
75 // Reset the device state
76 reset(p->driveID);
77
78 // fill out the drive ID structure
79 memset(&driveID, 0, sizeof(struct ataparams));
80
81 // Calculate LBA and C/H/S values
82 uint16_t cylinders;
83 uint8_t heads;
84 uint8_t sectors;
85
86 uint32_t lba_size = image->size();
87 if (lba_size >= 16383*16*63) {
88 cylinders = 16383;
89 heads = 16;
90 sectors = 63;
91 } else {
92 if (lba_size >= 63)
93 sectors = 63;
94 else if (lba_size == 0)
95 panic("Bad IDE image size: 0\n");
96 else
97 sectors = lba_size;
98
99 if ((lba_size / sectors) >= 16)
100 heads = 16;
101 else
102 heads = (lba_size / sectors);
103
104 cylinders = lba_size / (heads * sectors);
105 }
106
107 // Setup the model name
108 strncpy((char *)driveID.atap_model, "5MI EDD si k",
109 sizeof(driveID.atap_model));
110 // Set the maximum multisector transfer size
111 driveID.atap_multi = MAX_MULTSECT;
112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
113 driveID.atap_capabilities1 = 0x7;
114 // UDMA support, EIDE support
115 driveID.atap_extensions = 0x6;
116 // Setup default C/H/S settings
117 driveID.atap_cylinders = cylinders;
118 driveID.atap_sectors = sectors;
119 driveID.atap_heads = heads;
120 // Setup the current multisector transfer size
121 driveID.atap_curmulti = MAX_MULTSECT;
122 driveID.atap_curmulti_valid = 0x1;
123 // Number of sectors on disk
124 driveID.atap_capacity = lba_size;
125 // Multiword DMA mode 2 and below supported
126 driveID.atap_dmamode_supp = 0x4;
127 // Set PIO mode 4 and 3 supported
128 driveID.atap_piomode_supp = 0x3;
129 // Set DMA mode 4 and below supported
130 driveID.atap_udmamode_supp = 0x1f;
131 // Statically set hardware config word
132 driveID.atap_hwreset_res = 0x4001;
133
134 //arbitrary for now...
135 driveID.atap_ata_major = WDC_VER_ATA7;
136}
137
138IdeDisk::~IdeDisk()
139{
140 // destroy the data buffer
141 delete [] dataBuffer;
142}
143
144void
145IdeDisk::reset(int id)
146{
147 // initialize the data buffer and shadow registers
148 dataBuffer = new uint8_t[MAX_DMA_SIZE];
149
150 memset(dataBuffer, 0, MAX_DMA_SIZE);
151 memset(&cmdReg, 0, sizeof(CommandReg_t));
152 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
153
154 curPrdAddr = 0;
155 curSector = 0;
156 cmdBytes = 0;
157 cmdBytesLeft = 0;
158 drqBytesLeft = 0;
159 dmaRead = false;
160 intrPending = false;
161 dmaAborted = false;
162
163 // set the device state to idle
164 dmaState = Dma_Idle;
165
166 if (id == DEV0) {
167 devState = Device_Idle_S;
168 devID = DEV0;
169 } else if (id == DEV1) {
170 devState = Device_Idle_NS;
171 devID = DEV1;
172 } else {
173 panic("Invalid device ID: %#x\n", id);
174 }
175
176 // set the device ready bit
177 status = STATUS_DRDY_BIT;
178
179 /* The error register must be set to 0x1 on start-up to
180 indicate that no diagnostic error was detected */
181 cmdReg.error = 0x1;
182}
183
184////
185// Utility functions
186////
187
188bool
189IdeDisk::isDEVSelect()
190{
191 return ctrl->isDiskSelected(this);
192}
193
194Addr
195IdeDisk::pciToDma(Addr pciAddr)
196{
197 if (ctrl)
198 return ctrl->pciToDma(pciAddr);
199 else
200 panic("Access to unset controller!\n");
201}
202
203////
204// Device registers read/write
205////
206
207void
208IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
209{
210 if (offset == DATA_OFFSET) {
211 if (size == sizeof(uint16_t)) {
212 *(uint16_t *)data = cmdReg.data;
213 } else if (size == sizeof(uint32_t)) {
214 *(uint16_t *)data = cmdReg.data;
215 updateState(ACT_DATA_READ_SHORT);
216 *((uint16_t *)data + 1) = cmdReg.data;
217 } else {
218 panic("Data read of unsupported size %d.\n", size);
219 }
220 updateState(ACT_DATA_READ_SHORT);
221 return;
222 }
223 assert(size == sizeof(uint8_t));
224 switch (offset) {
225 case ERROR_OFFSET:
226 *data = cmdReg.error;
227 break;
228 case NSECTOR_OFFSET:
229 *data = cmdReg.sec_count;
230 break;
231 case SECTOR_OFFSET:
232 *data = cmdReg.sec_num;
233 break;
234 case LCYL_OFFSET:
235 *data = cmdReg.cyl_low;
236 break;
237 case HCYL_OFFSET:
238 *data = cmdReg.cyl_high;
239 break;
240 case DRIVE_OFFSET:
241 *data = cmdReg.drive;
242 break;
243 case STATUS_OFFSET:
244 *data = status;
245 updateState(ACT_STAT_READ);
246 break;
247 default:
248 panic("Invalid IDE command register offset: %#x\n", offset);
249 }
250 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
251}
252
253void
254IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
255{
256 assert(size == sizeof(uint8_t));
257 *data = status;
258 if (offset != ALTSTAT_OFFSET)
259 panic("Invalid IDE control register offset: %#x\n", offset);
260 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
261}
262
263void
264IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
265{
266 if (offset == DATA_OFFSET) {
267 if (size == sizeof(uint16_t)) {
268 cmdReg.data = *(const uint16_t *)data;
269 } else if (size == sizeof(uint32_t)) {
270 cmdReg.data = *(const uint16_t *)data;
271 updateState(ACT_DATA_WRITE_SHORT);
272 cmdReg.data = *((const uint16_t *)data + 1);
273 } else {
274 panic("Data write of unsupported size %d.\n", size);
275 }
276 updateState(ACT_DATA_WRITE_SHORT);
277 return;
278 }
279
280 assert(size == sizeof(uint8_t));
281 switch (offset) {
282 case FEATURES_OFFSET:
283 break;
284 case NSECTOR_OFFSET:
285 cmdReg.sec_count = *data;
286 break;
287 case SECTOR_OFFSET:
288 cmdReg.sec_num = *data;
289 break;
290 case LCYL_OFFSET:
291 cmdReg.cyl_low = *data;
292 break;
293 case HCYL_OFFSET:
294 cmdReg.cyl_high = *data;
295 break;
296 case DRIVE_OFFSET:
297 cmdReg.drive = *data;
298 updateState(ACT_SELECT_WRITE);
299 break;
300 case COMMAND_OFFSET:
301 cmdReg.command = *data;
302 updateState(ACT_CMD_WRITE);
303 break;
304 default:
305 panic("Invalid IDE command register offset: %#x\n", offset);
306 }
307 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
308 (uint32_t)*data);
309}
310
311void
312IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
313{
314 if (offset != CONTROL_OFFSET)
315 panic("Invalid IDE control register offset: %#x\n", offset);
316
317 if (*data & CONTROL_RST_BIT) {
318 // force the device into the reset state
319 devState = Device_Srst;
320 updateState(ACT_SRST_SET);
321 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
322 updateState(ACT_SRST_CLEAR);
323 }
324
325 nIENBit = *data & CONTROL_IEN_BIT;
326
327 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
328 (uint32_t)*data);
329}
330
331////
332// Perform DMA transactions
333////
334
335void
336IdeDisk::doDmaTransfer()
337{
338 if (dmaAborted) {
339 DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
340 updateState(ACT_CMD_ERROR);
341 return;
342 }
343
344 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
345 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
346 dmaState, devState);
347
348 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
349 schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
350 return;
351 } else
352 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
353 (uint8_t*)&curPrd.entry);
354}
355
356void
357IdeDisk::dmaPrdReadDone()
358{
359 if (dmaAborted) {
360 DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
361 updateState(ACT_CMD_ERROR);
362 return;
363 }
364
365 DPRINTF(IdeDisk,
366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
368 curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
369 curPrd.getEOT(), curSector);
370
371 // the prd pointer has already been translated, so just do an increment
372 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
373
374 if (dmaRead)
375 doDmaDataRead();
376 else
377 doDmaDataWrite();
378}
379
380void
381IdeDisk::doDmaDataRead()
382{
383 /** @todo we need to figure out what the delay actually will be */
384 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
385
386 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387 diskDelay, totalDiskDelay);
388
389 schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
390}
391
392void
393IdeDisk::regStats()
394{
395 SimObject::regStats();
396
397 using namespace Stats;
398 dmaReadFullPages
399 .name(name() + ".dma_read_full_pages")
400 .desc("Number of full page size DMA reads (not PRD).")
401 ;
402 dmaReadBytes
403 .name(name() + ".dma_read_bytes")
404 .desc("Number of bytes transfered via DMA reads (not PRD).")
405 ;
406 dmaReadTxs
407 .name(name() + ".dma_read_txs")
408 .desc("Number of DMA read transactions (not PRD).")
409 ;
410
411 dmaWriteFullPages
412 .name(name() + ".dma_write_full_pages")
413 .desc("Number of full page size DMA writes.")
414 ;
415 dmaWriteBytes
416 .name(name() + ".dma_write_bytes")
417 .desc("Number of bytes transfered via DMA writes.")
418 ;
419 dmaWriteTxs
420 .name(name() + ".dma_write_txs")
421 .desc("Number of DMA write transactions.")
422 ;
423}
424
425void
426IdeDisk::doDmaRead()
427{
428 if (dmaAborted) {
429 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
430 if (dmaReadCG)
431 delete dmaReadCG;
432 dmaReadCG = NULL;
433 updateState(ACT_CMD_ERROR);
434 return;
435 }
436
437 if (!dmaReadCG) {
438 // clear out the data buffer
439 memset(dataBuffer, 0, MAX_DMA_SIZE);
440 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
441 curPrd.getByteCount(), TheISA::PageBytes);
442
443 }
444 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
445 schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
446 return;
447 } else if (!dmaReadCG->done()) {
448 assert(dmaReadCG->complete() < MAX_DMA_SIZE);
449 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
450 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
451 dmaReadBytes += dmaReadCG->size();
452 dmaReadTxs++;
453 if (dmaReadCG->size() == TheISA::PageBytes)
454 dmaReadFullPages++;
455 dmaReadCG->next();
456 } else {
457 assert(dmaReadCG->done());
458 delete dmaReadCG;
459 dmaReadCG = NULL;
460 dmaReadDone();
461 }
462}
463
464void
465IdeDisk::dmaReadDone()
466{
467 uint32_t bytesWritten = 0;
468
469 // write the data to the disk image
470 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
471 bytesWritten += SectorSize) {
472
473 cmdBytesLeft -= SectorSize;
474 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
475 }
476
477 // check for the EOT
478 if (curPrd.getEOT()) {
479 assert(cmdBytesLeft == 0);
480 dmaState = Dma_Idle;
481 updateState(ACT_DMA_DONE);
482 } else {
483 doDmaTransfer();
484 }
485}
486
487void
488IdeDisk::doDmaDataWrite()
489{
490 /** @todo we need to figure out what the delay actually will be */
491 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
492 uint32_t bytesRead = 0;
493
494 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
495 diskDelay, totalDiskDelay);
496
497 memset(dataBuffer, 0, MAX_DMA_SIZE);
498 assert(cmdBytesLeft <= MAX_DMA_SIZE);
499 while (bytesRead < curPrd.getByteCount()) {
500 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
501 bytesRead += SectorSize;
502 cmdBytesLeft -= SectorSize;
503 }
504 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
505 bytesRead, cmdBytesLeft);
506
507 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
508}
509
510void
511IdeDisk::doDmaWrite()
512{
513 if (dmaAborted) {
514 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
515 if (dmaWriteCG)
516 delete dmaWriteCG;
517 dmaWriteCG = NULL;
518 updateState(ACT_CMD_ERROR);
519 return;
520 }
521 if (!dmaWriteCG) {
522 // clear out the data buffer
523 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
524 curPrd.getByteCount(), TheISA::PageBytes);
525 }
526 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
527 schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
528 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
529 return;
530 } else if (!dmaWriteCG->done()) {
531 assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
532 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
533 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
534 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
535 curPrd.getByteCount(), curPrd.getEOT());
536 dmaWriteBytes += dmaWriteCG->size();
537 dmaWriteTxs++;
538 if (dmaWriteCG->size() == TheISA::PageBytes)
539 dmaWriteFullPages++;
540 dmaWriteCG->next();
541 } else {
542 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
543 curPrd.getByteCount(), curPrd.getEOT());
544 assert(dmaWriteCG->done());
545 delete dmaWriteCG;
546 dmaWriteCG = NULL;
547 dmaWriteDone();
548 }
549}
550
551void
552IdeDisk::dmaWriteDone()
553{
554 DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
555 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
556 // check for the EOT
557 if (curPrd.getEOT()) {
558 assert(cmdBytesLeft == 0);
559 dmaState = Dma_Idle;
560 updateState(ACT_DMA_DONE);
561 } else {
562 doDmaTransfer();
563 }
564}
565
566////
567// Disk utility routines
568///
569
570void
571IdeDisk::readDisk(uint32_t sector, uint8_t *data)
572{
573 uint32_t bytesRead = image->read(data, sector);
574
575 if (bytesRead != SectorSize)
576 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
577 name(), bytesRead, SectorSize, errno);
578}
579
580void
581IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
582{
583 uint32_t bytesWritten = image->write(data, sector);
584
585 if (bytesWritten != SectorSize)
586 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
587 name(), bytesWritten, SectorSize, errno);
588}
589
590////
591// Setup and handle commands
592////
593
594void
595IdeDisk::startDma(const uint32_t &prdTableBase)
596{
597 if (dmaState != Dma_Start)
598 panic("Inconsistent DMA state, should be in Dma_Start!\n");
599
600 if (devState != Transfer_Data_Dma)
601 panic("Inconsistent device state for DMA start!\n");
602
603 // PRD base address is given by bits 31:2
604 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
605
606 dmaState = Dma_Transfer;
607
608 // schedule dma transfer (doDmaTransfer)
609 schedule(dmaTransferEvent, curTick() + 1);
610}
611
612void
613IdeDisk::abortDma()
614{
615 if (dmaState == Dma_Idle)
616 panic("Inconsistent DMA state, should be Start or Transfer!");
617
618 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
619 panic("Inconsistent device state, should be Transfer or Prepare!\n");
620
621 updateState(ACT_CMD_ERROR);
622}
623
624void
625IdeDisk::startCommand()
626{
627 DevAction_t action = ACT_NONE;
628 uint32_t size = 0;
629 dmaRead = false;
630
631 // Decode commands
632 switch (cmdReg.command) {
633 // Supported non-data commands
634 case WDSF_READ_NATIVE_MAX:
635 size = (uint32_t)image->size() - 1;
636 cmdReg.sec_num = (size & 0xff);
637 cmdReg.cyl_low = ((size & 0xff00) >> 8);
638 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
639 cmdReg.head = ((size & 0xf000000) >> 24);
640
641 devState = Command_Execution;
642 action = ACT_CMD_COMPLETE;
643 break;
644
645 case WDCC_RECAL:
646 case WDCC_IDP:
647 case WDCC_STANDBY_IMMED:
648 case WDCC_FLUSHCACHE:
649 case WDSF_VERIFY:
650 case WDSF_SEEK:
651 case SET_FEATURES:
652 case WDCC_SETMULTI:
653 case WDCC_IDLE:
654 devState = Command_Execution;
655 action = ACT_CMD_COMPLETE;
656 break;
657
658 // Supported PIO data-in commands
659 case WDCC_IDENTIFY:
1/*
2 * Copyright (c) 2013 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 * Authors: Andrew Schultz
41 * Ali Saidi
42 */
43
44/** @file
45 * Device model implementation for an IDE disk
46 */
47
48#include "dev/storage/ide_disk.hh"
49
50#include <cerrno>
51#include <cstring>
52#include <deque>
53#include <string>
54
55#include "arch/isa_traits.hh"
56#include "base/chunk_generator.hh"
57#include "base/cprintf.hh" // csprintf
58#include "base/trace.hh"
59#include "config/the_isa.hh"
60#include "debug/IdeDisk.hh"
61#include "dev/storage/disk_image.hh"
62#include "dev/storage/ide_ctrl.hh"
63#include "sim/core.hh"
64#include "sim/sim_object.hh"
65
66using namespace std;
67using namespace TheISA;
68
69IdeDisk::IdeDisk(const Params *p)
70 : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
71 dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
72 dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
73 dmaReadEvent(this), dmaWriteEvent(this)
74{
75 // Reset the device state
76 reset(p->driveID);
77
78 // fill out the drive ID structure
79 memset(&driveID, 0, sizeof(struct ataparams));
80
81 // Calculate LBA and C/H/S values
82 uint16_t cylinders;
83 uint8_t heads;
84 uint8_t sectors;
85
86 uint32_t lba_size = image->size();
87 if (lba_size >= 16383*16*63) {
88 cylinders = 16383;
89 heads = 16;
90 sectors = 63;
91 } else {
92 if (lba_size >= 63)
93 sectors = 63;
94 else if (lba_size == 0)
95 panic("Bad IDE image size: 0\n");
96 else
97 sectors = lba_size;
98
99 if ((lba_size / sectors) >= 16)
100 heads = 16;
101 else
102 heads = (lba_size / sectors);
103
104 cylinders = lba_size / (heads * sectors);
105 }
106
107 // Setup the model name
108 strncpy((char *)driveID.atap_model, "5MI EDD si k",
109 sizeof(driveID.atap_model));
110 // Set the maximum multisector transfer size
111 driveID.atap_multi = MAX_MULTSECT;
112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
113 driveID.atap_capabilities1 = 0x7;
114 // UDMA support, EIDE support
115 driveID.atap_extensions = 0x6;
116 // Setup default C/H/S settings
117 driveID.atap_cylinders = cylinders;
118 driveID.atap_sectors = sectors;
119 driveID.atap_heads = heads;
120 // Setup the current multisector transfer size
121 driveID.atap_curmulti = MAX_MULTSECT;
122 driveID.atap_curmulti_valid = 0x1;
123 // Number of sectors on disk
124 driveID.atap_capacity = lba_size;
125 // Multiword DMA mode 2 and below supported
126 driveID.atap_dmamode_supp = 0x4;
127 // Set PIO mode 4 and 3 supported
128 driveID.atap_piomode_supp = 0x3;
129 // Set DMA mode 4 and below supported
130 driveID.atap_udmamode_supp = 0x1f;
131 // Statically set hardware config word
132 driveID.atap_hwreset_res = 0x4001;
133
134 //arbitrary for now...
135 driveID.atap_ata_major = WDC_VER_ATA7;
136}
137
138IdeDisk::~IdeDisk()
139{
140 // destroy the data buffer
141 delete [] dataBuffer;
142}
143
144void
145IdeDisk::reset(int id)
146{
147 // initialize the data buffer and shadow registers
148 dataBuffer = new uint8_t[MAX_DMA_SIZE];
149
150 memset(dataBuffer, 0, MAX_DMA_SIZE);
151 memset(&cmdReg, 0, sizeof(CommandReg_t));
152 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
153
154 curPrdAddr = 0;
155 curSector = 0;
156 cmdBytes = 0;
157 cmdBytesLeft = 0;
158 drqBytesLeft = 0;
159 dmaRead = false;
160 intrPending = false;
161 dmaAborted = false;
162
163 // set the device state to idle
164 dmaState = Dma_Idle;
165
166 if (id == DEV0) {
167 devState = Device_Idle_S;
168 devID = DEV0;
169 } else if (id == DEV1) {
170 devState = Device_Idle_NS;
171 devID = DEV1;
172 } else {
173 panic("Invalid device ID: %#x\n", id);
174 }
175
176 // set the device ready bit
177 status = STATUS_DRDY_BIT;
178
179 /* The error register must be set to 0x1 on start-up to
180 indicate that no diagnostic error was detected */
181 cmdReg.error = 0x1;
182}
183
184////
185// Utility functions
186////
187
188bool
189IdeDisk::isDEVSelect()
190{
191 return ctrl->isDiskSelected(this);
192}
193
194Addr
195IdeDisk::pciToDma(Addr pciAddr)
196{
197 if (ctrl)
198 return ctrl->pciToDma(pciAddr);
199 else
200 panic("Access to unset controller!\n");
201}
202
203////
204// Device registers read/write
205////
206
207void
208IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
209{
210 if (offset == DATA_OFFSET) {
211 if (size == sizeof(uint16_t)) {
212 *(uint16_t *)data = cmdReg.data;
213 } else if (size == sizeof(uint32_t)) {
214 *(uint16_t *)data = cmdReg.data;
215 updateState(ACT_DATA_READ_SHORT);
216 *((uint16_t *)data + 1) = cmdReg.data;
217 } else {
218 panic("Data read of unsupported size %d.\n", size);
219 }
220 updateState(ACT_DATA_READ_SHORT);
221 return;
222 }
223 assert(size == sizeof(uint8_t));
224 switch (offset) {
225 case ERROR_OFFSET:
226 *data = cmdReg.error;
227 break;
228 case NSECTOR_OFFSET:
229 *data = cmdReg.sec_count;
230 break;
231 case SECTOR_OFFSET:
232 *data = cmdReg.sec_num;
233 break;
234 case LCYL_OFFSET:
235 *data = cmdReg.cyl_low;
236 break;
237 case HCYL_OFFSET:
238 *data = cmdReg.cyl_high;
239 break;
240 case DRIVE_OFFSET:
241 *data = cmdReg.drive;
242 break;
243 case STATUS_OFFSET:
244 *data = status;
245 updateState(ACT_STAT_READ);
246 break;
247 default:
248 panic("Invalid IDE command register offset: %#x\n", offset);
249 }
250 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
251}
252
253void
254IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
255{
256 assert(size == sizeof(uint8_t));
257 *data = status;
258 if (offset != ALTSTAT_OFFSET)
259 panic("Invalid IDE control register offset: %#x\n", offset);
260 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
261}
262
263void
264IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
265{
266 if (offset == DATA_OFFSET) {
267 if (size == sizeof(uint16_t)) {
268 cmdReg.data = *(const uint16_t *)data;
269 } else if (size == sizeof(uint32_t)) {
270 cmdReg.data = *(const uint16_t *)data;
271 updateState(ACT_DATA_WRITE_SHORT);
272 cmdReg.data = *((const uint16_t *)data + 1);
273 } else {
274 panic("Data write of unsupported size %d.\n", size);
275 }
276 updateState(ACT_DATA_WRITE_SHORT);
277 return;
278 }
279
280 assert(size == sizeof(uint8_t));
281 switch (offset) {
282 case FEATURES_OFFSET:
283 break;
284 case NSECTOR_OFFSET:
285 cmdReg.sec_count = *data;
286 break;
287 case SECTOR_OFFSET:
288 cmdReg.sec_num = *data;
289 break;
290 case LCYL_OFFSET:
291 cmdReg.cyl_low = *data;
292 break;
293 case HCYL_OFFSET:
294 cmdReg.cyl_high = *data;
295 break;
296 case DRIVE_OFFSET:
297 cmdReg.drive = *data;
298 updateState(ACT_SELECT_WRITE);
299 break;
300 case COMMAND_OFFSET:
301 cmdReg.command = *data;
302 updateState(ACT_CMD_WRITE);
303 break;
304 default:
305 panic("Invalid IDE command register offset: %#x\n", offset);
306 }
307 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
308 (uint32_t)*data);
309}
310
311void
312IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
313{
314 if (offset != CONTROL_OFFSET)
315 panic("Invalid IDE control register offset: %#x\n", offset);
316
317 if (*data & CONTROL_RST_BIT) {
318 // force the device into the reset state
319 devState = Device_Srst;
320 updateState(ACT_SRST_SET);
321 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
322 updateState(ACT_SRST_CLEAR);
323 }
324
325 nIENBit = *data & CONTROL_IEN_BIT;
326
327 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
328 (uint32_t)*data);
329}
330
331////
332// Perform DMA transactions
333////
334
335void
336IdeDisk::doDmaTransfer()
337{
338 if (dmaAborted) {
339 DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
340 updateState(ACT_CMD_ERROR);
341 return;
342 }
343
344 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
345 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
346 dmaState, devState);
347
348 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
349 schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD);
350 return;
351 } else
352 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
353 (uint8_t*)&curPrd.entry);
354}
355
356void
357IdeDisk::dmaPrdReadDone()
358{
359 if (dmaAborted) {
360 DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
361 updateState(ACT_CMD_ERROR);
362 return;
363 }
364
365 DPRINTF(IdeDisk,
366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
368 curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
369 curPrd.getEOT(), curSector);
370
371 // the prd pointer has already been translated, so just do an increment
372 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
373
374 if (dmaRead)
375 doDmaDataRead();
376 else
377 doDmaDataWrite();
378}
379
380void
381IdeDisk::doDmaDataRead()
382{
383 /** @todo we need to figure out what the delay actually will be */
384 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
385
386 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387 diskDelay, totalDiskDelay);
388
389 schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
390}
391
392void
393IdeDisk::regStats()
394{
395 SimObject::regStats();
396
397 using namespace Stats;
398 dmaReadFullPages
399 .name(name() + ".dma_read_full_pages")
400 .desc("Number of full page size DMA reads (not PRD).")
401 ;
402 dmaReadBytes
403 .name(name() + ".dma_read_bytes")
404 .desc("Number of bytes transfered via DMA reads (not PRD).")
405 ;
406 dmaReadTxs
407 .name(name() + ".dma_read_txs")
408 .desc("Number of DMA read transactions (not PRD).")
409 ;
410
411 dmaWriteFullPages
412 .name(name() + ".dma_write_full_pages")
413 .desc("Number of full page size DMA writes.")
414 ;
415 dmaWriteBytes
416 .name(name() + ".dma_write_bytes")
417 .desc("Number of bytes transfered via DMA writes.")
418 ;
419 dmaWriteTxs
420 .name(name() + ".dma_write_txs")
421 .desc("Number of DMA write transactions.")
422 ;
423}
424
425void
426IdeDisk::doDmaRead()
427{
428 if (dmaAborted) {
429 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
430 if (dmaReadCG)
431 delete dmaReadCG;
432 dmaReadCG = NULL;
433 updateState(ACT_CMD_ERROR);
434 return;
435 }
436
437 if (!dmaReadCG) {
438 // clear out the data buffer
439 memset(dataBuffer, 0, MAX_DMA_SIZE);
440 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
441 curPrd.getByteCount(), TheISA::PageBytes);
442
443 }
444 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
445 schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
446 return;
447 } else if (!dmaReadCG->done()) {
448 assert(dmaReadCG->complete() < MAX_DMA_SIZE);
449 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
450 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
451 dmaReadBytes += dmaReadCG->size();
452 dmaReadTxs++;
453 if (dmaReadCG->size() == TheISA::PageBytes)
454 dmaReadFullPages++;
455 dmaReadCG->next();
456 } else {
457 assert(dmaReadCG->done());
458 delete dmaReadCG;
459 dmaReadCG = NULL;
460 dmaReadDone();
461 }
462}
463
464void
465IdeDisk::dmaReadDone()
466{
467 uint32_t bytesWritten = 0;
468
469 // write the data to the disk image
470 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
471 bytesWritten += SectorSize) {
472
473 cmdBytesLeft -= SectorSize;
474 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
475 }
476
477 // check for the EOT
478 if (curPrd.getEOT()) {
479 assert(cmdBytesLeft == 0);
480 dmaState = Dma_Idle;
481 updateState(ACT_DMA_DONE);
482 } else {
483 doDmaTransfer();
484 }
485}
486
487void
488IdeDisk::doDmaDataWrite()
489{
490 /** @todo we need to figure out what the delay actually will be */
491 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
492 uint32_t bytesRead = 0;
493
494 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
495 diskDelay, totalDiskDelay);
496
497 memset(dataBuffer, 0, MAX_DMA_SIZE);
498 assert(cmdBytesLeft <= MAX_DMA_SIZE);
499 while (bytesRead < curPrd.getByteCount()) {
500 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
501 bytesRead += SectorSize;
502 cmdBytesLeft -= SectorSize;
503 }
504 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
505 bytesRead, cmdBytesLeft);
506
507 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
508}
509
510void
511IdeDisk::doDmaWrite()
512{
513 if (dmaAborted) {
514 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
515 if (dmaWriteCG)
516 delete dmaWriteCG;
517 dmaWriteCG = NULL;
518 updateState(ACT_CMD_ERROR);
519 return;
520 }
521 if (!dmaWriteCG) {
522 // clear out the data buffer
523 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
524 curPrd.getByteCount(), TheISA::PageBytes);
525 }
526 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
527 schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD);
528 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
529 return;
530 } else if (!dmaWriteCG->done()) {
531 assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
532 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
533 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
534 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
535 curPrd.getByteCount(), curPrd.getEOT());
536 dmaWriteBytes += dmaWriteCG->size();
537 dmaWriteTxs++;
538 if (dmaWriteCG->size() == TheISA::PageBytes)
539 dmaWriteFullPages++;
540 dmaWriteCG->next();
541 } else {
542 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
543 curPrd.getByteCount(), curPrd.getEOT());
544 assert(dmaWriteCG->done());
545 delete dmaWriteCG;
546 dmaWriteCG = NULL;
547 dmaWriteDone();
548 }
549}
550
551void
552IdeDisk::dmaWriteDone()
553{
554 DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
555 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
556 // check for the EOT
557 if (curPrd.getEOT()) {
558 assert(cmdBytesLeft == 0);
559 dmaState = Dma_Idle;
560 updateState(ACT_DMA_DONE);
561 } else {
562 doDmaTransfer();
563 }
564}
565
566////
567// Disk utility routines
568///
569
570void
571IdeDisk::readDisk(uint32_t sector, uint8_t *data)
572{
573 uint32_t bytesRead = image->read(data, sector);
574
575 if (bytesRead != SectorSize)
576 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
577 name(), bytesRead, SectorSize, errno);
578}
579
580void
581IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
582{
583 uint32_t bytesWritten = image->write(data, sector);
584
585 if (bytesWritten != SectorSize)
586 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
587 name(), bytesWritten, SectorSize, errno);
588}
589
590////
591// Setup and handle commands
592////
593
594void
595IdeDisk::startDma(const uint32_t &prdTableBase)
596{
597 if (dmaState != Dma_Start)
598 panic("Inconsistent DMA state, should be in Dma_Start!\n");
599
600 if (devState != Transfer_Data_Dma)
601 panic("Inconsistent device state for DMA start!\n");
602
603 // PRD base address is given by bits 31:2
604 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
605
606 dmaState = Dma_Transfer;
607
608 // schedule dma transfer (doDmaTransfer)
609 schedule(dmaTransferEvent, curTick() + 1);
610}
611
612void
613IdeDisk::abortDma()
614{
615 if (dmaState == Dma_Idle)
616 panic("Inconsistent DMA state, should be Start or Transfer!");
617
618 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
619 panic("Inconsistent device state, should be Transfer or Prepare!\n");
620
621 updateState(ACT_CMD_ERROR);
622}
623
624void
625IdeDisk::startCommand()
626{
627 DevAction_t action = ACT_NONE;
628 uint32_t size = 0;
629 dmaRead = false;
630
631 // Decode commands
632 switch (cmdReg.command) {
633 // Supported non-data commands
634 case WDSF_READ_NATIVE_MAX:
635 size = (uint32_t)image->size() - 1;
636 cmdReg.sec_num = (size & 0xff);
637 cmdReg.cyl_low = ((size & 0xff00) >> 8);
638 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
639 cmdReg.head = ((size & 0xf000000) >> 24);
640
641 devState = Command_Execution;
642 action = ACT_CMD_COMPLETE;
643 break;
644
645 case WDCC_RECAL:
646 case WDCC_IDP:
647 case WDCC_STANDBY_IMMED:
648 case WDCC_FLUSHCACHE:
649 case WDSF_VERIFY:
650 case WDSF_SEEK:
651 case SET_FEATURES:
652 case WDCC_SETMULTI:
653 case WDCC_IDLE:
654 devState = Command_Execution;
655 action = ACT_CMD_COMPLETE;
656 break;
657
658 // Supported PIO data-in commands
659 case WDCC_IDENTIFY:
660 case ATAPI_IDENTIFY_DEVICE:
660 cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
661 devState = Prepare_Data_In;
662 action = ACT_DATA_READY;
663 break;
664
665 case WDCC_READMULTI:
666 case WDCC_READ:
667 if (!(cmdReg.drive & DRIVE_LBA_BIT))
668 panic("Attempt to perform CHS access, only supports LBA\n");
669
670 if (cmdReg.sec_count == 0)
671 cmdBytes = cmdBytesLeft = (256 * SectorSize);
672 else
673 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
674
675 curSector = getLBABase();
676
677 /** @todo make this a scheduled event to simulate disk delay */
678 devState = Prepare_Data_In;
679 action = ACT_DATA_READY;
680 break;
681
682 // Supported PIO data-out commands
683 case WDCC_WRITEMULTI:
684 case WDCC_WRITE:
685 if (!(cmdReg.drive & DRIVE_LBA_BIT))
686 panic("Attempt to perform CHS access, only supports LBA\n");
687
688 if (cmdReg.sec_count == 0)
689 cmdBytes = cmdBytesLeft = (256 * SectorSize);
690 else
691 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
692 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
693 curSector = getLBABase();
694
695 devState = Prepare_Data_Out;
696 action = ACT_DATA_READY;
697 break;
698
699 // Supported DMA commands
700 case WDCC_WRITEDMA:
701 dmaRead = true; // a write to the disk is a DMA read from memory
702 case WDCC_READDMA:
703 if (!(cmdReg.drive & DRIVE_LBA_BIT))
704 panic("Attempt to perform CHS access, only supports LBA\n");
705
706 if (cmdReg.sec_count == 0)
707 cmdBytes = cmdBytesLeft = (256 * SectorSize);
708 else
709 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
710 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
711
712 curSector = getLBABase();
713
714 devState = Prepare_Data_Dma;
715 action = ACT_DMA_READY;
716 break;
717
718 default:
719 panic("Unsupported ATA command: %#x\n", cmdReg.command);
720 }
721
722 if (action != ACT_NONE) {
723 // set the BSY bit
724 status |= STATUS_BSY_BIT;
725 // clear the DRQ bit
726 status &= ~STATUS_DRQ_BIT;
727 // clear the DF bit
728 status &= ~STATUS_DF_BIT;
729
730 updateState(action);
731 }
732}
733
734////
735// Handle setting and clearing interrupts
736////
737
738void
739IdeDisk::intrPost()
740{
741 DPRINTF(IdeDisk, "Posting Interrupt\n");
742 if (intrPending)
743 panic("Attempt to post an interrupt with one pending\n");
744
745 intrPending = true;
746
747 // talk to controller to set interrupt
748 if (ctrl) {
749 ctrl->intrPost();
750 }
751}
752
753void
754IdeDisk::intrClear()
755{
756 DPRINTF(IdeDisk, "Clearing Interrupt\n");
757 if (!intrPending)
758 panic("Attempt to clear a non-pending interrupt\n");
759
760 intrPending = false;
761
762 // talk to controller to clear interrupt
763 if (ctrl)
764 ctrl->intrClear();
765}
766
767////
768// Manage the device internal state machine
769////
770
771void
772IdeDisk::updateState(DevAction_t action)
773{
774 switch (devState) {
775 case Device_Srst:
776 if (action == ACT_SRST_SET) {
777 // set the BSY bit
778 status |= STATUS_BSY_BIT;
779 } else if (action == ACT_SRST_CLEAR) {
780 // clear the BSY bit
781 status &= ~STATUS_BSY_BIT;
782
783 // reset the device state
784 reset(devID);
785 }
786 break;
787
788 case Device_Idle_S:
789 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
790 devState = Device_Idle_NS;
791 } else if (action == ACT_CMD_WRITE) {
792 startCommand();
793 }
794
795 break;
796
797 case Device_Idle_SI:
798 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
799 devState = Device_Idle_NS;
800 intrClear();
801 } else if (action == ACT_STAT_READ || isIENSet()) {
802 devState = Device_Idle_S;
803 intrClear();
804 } else if (action == ACT_CMD_WRITE) {
805 intrClear();
806 startCommand();
807 }
808
809 break;
810
811 case Device_Idle_NS:
812 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
813 if (!isIENSet() && intrPending) {
814 devState = Device_Idle_SI;
815 intrPost();
816 }
817 if (isIENSet() || !intrPending) {
818 devState = Device_Idle_S;
819 }
820 }
821 break;
822
823 case Command_Execution:
824 if (action == ACT_CMD_COMPLETE) {
825 // clear the BSY bit
826 setComplete();
827
828 if (!isIENSet()) {
829 devState = Device_Idle_SI;
830 intrPost();
831 } else {
832 devState = Device_Idle_S;
833 }
834 }
835 break;
836
837 case Prepare_Data_In:
838 if (action == ACT_CMD_ERROR) {
839 // clear the BSY bit
840 setComplete();
841
842 if (!isIENSet()) {
843 devState = Device_Idle_SI;
844 intrPost();
845 } else {
846 devState = Device_Idle_S;
847 }
848 } else if (action == ACT_DATA_READY) {
849 // clear the BSY bit
850 status &= ~STATUS_BSY_BIT;
851 // set the DRQ bit
852 status |= STATUS_DRQ_BIT;
853
854 // copy the data into the data buffer
661 cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
662 devState = Prepare_Data_In;
663 action = ACT_DATA_READY;
664 break;
665
666 case WDCC_READMULTI:
667 case WDCC_READ:
668 if (!(cmdReg.drive & DRIVE_LBA_BIT))
669 panic("Attempt to perform CHS access, only supports LBA\n");
670
671 if (cmdReg.sec_count == 0)
672 cmdBytes = cmdBytesLeft = (256 * SectorSize);
673 else
674 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
675
676 curSector = getLBABase();
677
678 /** @todo make this a scheduled event to simulate disk delay */
679 devState = Prepare_Data_In;
680 action = ACT_DATA_READY;
681 break;
682
683 // Supported PIO data-out commands
684 case WDCC_WRITEMULTI:
685 case WDCC_WRITE:
686 if (!(cmdReg.drive & DRIVE_LBA_BIT))
687 panic("Attempt to perform CHS access, only supports LBA\n");
688
689 if (cmdReg.sec_count == 0)
690 cmdBytes = cmdBytesLeft = (256 * SectorSize);
691 else
692 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
693 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
694 curSector = getLBABase();
695
696 devState = Prepare_Data_Out;
697 action = ACT_DATA_READY;
698 break;
699
700 // Supported DMA commands
701 case WDCC_WRITEDMA:
702 dmaRead = true; // a write to the disk is a DMA read from memory
703 case WDCC_READDMA:
704 if (!(cmdReg.drive & DRIVE_LBA_BIT))
705 panic("Attempt to perform CHS access, only supports LBA\n");
706
707 if (cmdReg.sec_count == 0)
708 cmdBytes = cmdBytesLeft = (256 * SectorSize);
709 else
710 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
711 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
712
713 curSector = getLBABase();
714
715 devState = Prepare_Data_Dma;
716 action = ACT_DMA_READY;
717 break;
718
719 default:
720 panic("Unsupported ATA command: %#x\n", cmdReg.command);
721 }
722
723 if (action != ACT_NONE) {
724 // set the BSY bit
725 status |= STATUS_BSY_BIT;
726 // clear the DRQ bit
727 status &= ~STATUS_DRQ_BIT;
728 // clear the DF bit
729 status &= ~STATUS_DF_BIT;
730
731 updateState(action);
732 }
733}
734
735////
736// Handle setting and clearing interrupts
737////
738
739void
740IdeDisk::intrPost()
741{
742 DPRINTF(IdeDisk, "Posting Interrupt\n");
743 if (intrPending)
744 panic("Attempt to post an interrupt with one pending\n");
745
746 intrPending = true;
747
748 // talk to controller to set interrupt
749 if (ctrl) {
750 ctrl->intrPost();
751 }
752}
753
754void
755IdeDisk::intrClear()
756{
757 DPRINTF(IdeDisk, "Clearing Interrupt\n");
758 if (!intrPending)
759 panic("Attempt to clear a non-pending interrupt\n");
760
761 intrPending = false;
762
763 // talk to controller to clear interrupt
764 if (ctrl)
765 ctrl->intrClear();
766}
767
768////
769// Manage the device internal state machine
770////
771
772void
773IdeDisk::updateState(DevAction_t action)
774{
775 switch (devState) {
776 case Device_Srst:
777 if (action == ACT_SRST_SET) {
778 // set the BSY bit
779 status |= STATUS_BSY_BIT;
780 } else if (action == ACT_SRST_CLEAR) {
781 // clear the BSY bit
782 status &= ~STATUS_BSY_BIT;
783
784 // reset the device state
785 reset(devID);
786 }
787 break;
788
789 case Device_Idle_S:
790 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
791 devState = Device_Idle_NS;
792 } else if (action == ACT_CMD_WRITE) {
793 startCommand();
794 }
795
796 break;
797
798 case Device_Idle_SI:
799 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
800 devState = Device_Idle_NS;
801 intrClear();
802 } else if (action == ACT_STAT_READ || isIENSet()) {
803 devState = Device_Idle_S;
804 intrClear();
805 } else if (action == ACT_CMD_WRITE) {
806 intrClear();
807 startCommand();
808 }
809
810 break;
811
812 case Device_Idle_NS:
813 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
814 if (!isIENSet() && intrPending) {
815 devState = Device_Idle_SI;
816 intrPost();
817 }
818 if (isIENSet() || !intrPending) {
819 devState = Device_Idle_S;
820 }
821 }
822 break;
823
824 case Command_Execution:
825 if (action == ACT_CMD_COMPLETE) {
826 // clear the BSY bit
827 setComplete();
828
829 if (!isIENSet()) {
830 devState = Device_Idle_SI;
831 intrPost();
832 } else {
833 devState = Device_Idle_S;
834 }
835 }
836 break;
837
838 case Prepare_Data_In:
839 if (action == ACT_CMD_ERROR) {
840 // clear the BSY bit
841 setComplete();
842
843 if (!isIENSet()) {
844 devState = Device_Idle_SI;
845 intrPost();
846 } else {
847 devState = Device_Idle_S;
848 }
849 } else if (action == ACT_DATA_READY) {
850 // clear the BSY bit
851 status &= ~STATUS_BSY_BIT;
852 // set the DRQ bit
853 status |= STATUS_DRQ_BIT;
854
855 // copy the data into the data buffer
855 if (cmdReg.command == WDCC_IDENTIFY) {
856 if (cmdReg.command == WDCC_IDENTIFY ||
857 cmdReg.command == ATAPI_IDENTIFY_DEVICE) {
856 // Reset the drqBytes for this block
857 drqBytesLeft = sizeof(struct ataparams);
858
859 memcpy((void *)dataBuffer, (void *)&driveID,
860 sizeof(struct ataparams));
861 } else {
862 // Reset the drqBytes for this block
863 drqBytesLeft = SectorSize;
864
865 readDisk(curSector++, dataBuffer);
866 }
867
868 // put the first two bytes into the data register
869 memcpy((void *)&cmdReg.data, (void *)dataBuffer,
870 sizeof(uint16_t));
871
872 if (!isIENSet()) {
873 devState = Data_Ready_INTRQ_In;
874 intrPost();
875 } else {
876 devState = Transfer_Data_In;
877 }
878 }
879 break;
880
881 case Data_Ready_INTRQ_In:
882 if (action == ACT_STAT_READ) {
883 devState = Transfer_Data_In;
884 intrClear();
885 }
886 break;
887
888 case Transfer_Data_In:
889 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
890 if (action == ACT_DATA_READ_BYTE) {
891 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
892 } else {
893 drqBytesLeft -= 2;
894 cmdBytesLeft -= 2;
895
896 // copy next short into data registers
897 if (drqBytesLeft)
898 memcpy((void *)&cmdReg.data,
899 (void *)&dataBuffer[SectorSize - drqBytesLeft],
900 sizeof(uint16_t));
901 }
902
903 if (drqBytesLeft == 0) {
904 if (cmdBytesLeft == 0) {
905 // Clear the BSY bit
906 setComplete();
907 devState = Device_Idle_S;
908 } else {
909 devState = Prepare_Data_In;
910 // set the BSY_BIT
911 status |= STATUS_BSY_BIT;
912 // clear the DRQ_BIT
913 status &= ~STATUS_DRQ_BIT;
914
915 /** @todo change this to a scheduled event to simulate
916 disk delay */
917 updateState(ACT_DATA_READY);
918 }
919 }
920 }
921 break;
922
923 case Prepare_Data_Out:
924 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
925 // clear the BSY bit
926 setComplete();
927
928 if (!isIENSet()) {
929 devState = Device_Idle_SI;
930 intrPost();
931 } else {
932 devState = Device_Idle_S;
933 }
934 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
935 // clear the BSY bit
936 status &= ~STATUS_BSY_BIT;
937 // set the DRQ bit
938 status |= STATUS_DRQ_BIT;
939
940 // clear the data buffer to get it ready for writes
941 memset(dataBuffer, 0, MAX_DMA_SIZE);
942
943 // reset the drqBytes for this block
944 drqBytesLeft = SectorSize;
945
946 if (cmdBytesLeft == cmdBytes || isIENSet()) {
947 devState = Transfer_Data_Out;
948 } else {
949 devState = Data_Ready_INTRQ_Out;
950 intrPost();
951 }
952 }
953 break;
954
955 case Data_Ready_INTRQ_Out:
956 if (action == ACT_STAT_READ) {
957 devState = Transfer_Data_Out;
958 intrClear();
959 }
960 break;
961
962 case Transfer_Data_Out:
963 if (action == ACT_DATA_WRITE_BYTE ||
964 action == ACT_DATA_WRITE_SHORT) {
965
966 if (action == ACT_DATA_READ_BYTE) {
967 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
968 } else {
969 // copy the latest short into the data buffer
970 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
971 (void *)&cmdReg.data,
972 sizeof(uint16_t));
973
974 drqBytesLeft -= 2;
975 cmdBytesLeft -= 2;
976 }
977
978 if (drqBytesLeft == 0) {
979 // copy the block to the disk
980 writeDisk(curSector++, dataBuffer);
981
982 // set the BSY bit
983 status |= STATUS_BSY_BIT;
984 // set the seek bit
985 status |= STATUS_SEEK_BIT;
986 // clear the DRQ bit
987 status &= ~STATUS_DRQ_BIT;
988
989 devState = Prepare_Data_Out;
990
991 /** @todo change this to a scheduled event to simulate
992 disk delay */
993 updateState(ACT_DATA_READY);
994 }
995 }
996 break;
997
998 case Prepare_Data_Dma:
999 if (action == ACT_CMD_ERROR) {
1000 // clear the BSY bit
1001 setComplete();
1002
1003 if (!isIENSet()) {
1004 devState = Device_Idle_SI;
1005 intrPost();
1006 } else {
1007 devState = Device_Idle_S;
1008 }
1009 } else if (action == ACT_DMA_READY) {
1010 // clear the BSY bit
1011 status &= ~STATUS_BSY_BIT;
1012 // set the DRQ bit
1013 status |= STATUS_DRQ_BIT;
1014
1015 devState = Transfer_Data_Dma;
1016
1017 if (dmaState != Dma_Idle)
1018 panic("Inconsistent DMA state, should be Dma_Idle\n");
1019
1020 dmaState = Dma_Start;
1021 // wait for the write to the DMA start bit
1022 }
1023 break;
1024
1025 case Transfer_Data_Dma:
1026 if (action == ACT_CMD_ERROR) {
1027 dmaAborted = true;
1028 devState = Device_Dma_Abort;
1029 } else if (action == ACT_DMA_DONE) {
1030 // clear the BSY bit
1031 setComplete();
1032 // set the seek bit
1033 status |= STATUS_SEEK_BIT;
1034 // clear the controller state for DMA transfer
1035 ctrl->setDmaComplete(this);
1036
1037 if (!isIENSet()) {
1038 devState = Device_Idle_SI;
1039 intrPost();
1040 } else {
1041 devState = Device_Idle_S;
1042 }
1043 }
1044 break;
1045
1046 case Device_Dma_Abort:
1047 if (action == ACT_CMD_ERROR) {
1048 setComplete();
1049 status |= STATUS_SEEK_BIT;
1050 ctrl->setDmaComplete(this);
1051 dmaAborted = false;
1052 dmaState = Dma_Idle;
1053
1054 if (!isIENSet()) {
1055 devState = Device_Idle_SI;
1056 intrPost();
1057 } else {
1058 devState = Device_Idle_S;
1059 }
1060 } else {
1061 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1062 }
1063 break;
1064
1065 default:
1066 panic("Unknown IDE device state: %#x\n", devState);
1067 }
1068}
1069
1070void
1071IdeDisk::serialize(CheckpointOut &cp) const
1072{
1073 // Check all outstanding events to see if they are scheduled
1074 // these are all mutually exclusive
1075 Tick reschedule = 0;
1076 Events_t event = None;
1077
1078 int eventCount = 0;
1079
1080 if (dmaTransferEvent.scheduled()) {
1081 reschedule = dmaTransferEvent.when();
1082 event = Transfer;
1083 eventCount++;
1084 }
1085 if (dmaReadWaitEvent.scheduled()) {
1086 reschedule = dmaReadWaitEvent.when();
1087 event = ReadWait;
1088 eventCount++;
1089 }
1090 if (dmaWriteWaitEvent.scheduled()) {
1091 reschedule = dmaWriteWaitEvent.when();
1092 event = WriteWait;
1093 eventCount++;
1094 }
1095 if (dmaPrdReadEvent.scheduled()) {
1096 reschedule = dmaPrdReadEvent.when();
1097 event = PrdRead;
1098 eventCount++;
1099 }
1100 if (dmaReadEvent.scheduled()) {
1101 reschedule = dmaReadEvent.when();
1102 event = DmaRead;
1103 eventCount++;
1104 }
1105 if (dmaWriteEvent.scheduled()) {
1106 reschedule = dmaWriteEvent.when();
1107 event = DmaWrite;
1108 eventCount++;
1109 }
1110
1111 assert(eventCount <= 1);
1112
1113 SERIALIZE_SCALAR(reschedule);
1114 SERIALIZE_ENUM(event);
1115
1116 // Serialize device registers
1117 SERIALIZE_SCALAR(cmdReg.data);
1118 SERIALIZE_SCALAR(cmdReg.sec_count);
1119 SERIALIZE_SCALAR(cmdReg.sec_num);
1120 SERIALIZE_SCALAR(cmdReg.cyl_low);
1121 SERIALIZE_SCALAR(cmdReg.cyl_high);
1122 SERIALIZE_SCALAR(cmdReg.drive);
1123 SERIALIZE_SCALAR(cmdReg.command);
1124 SERIALIZE_SCALAR(status);
1125 SERIALIZE_SCALAR(nIENBit);
1126 SERIALIZE_SCALAR(devID);
1127
1128 // Serialize the PRD related information
1129 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1130 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1131 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1132 SERIALIZE_SCALAR(curPrdAddr);
1133
1134 /** @todo need to serialized chunk generator stuff!! */
1135 // Serialize current transfer related information
1136 SERIALIZE_SCALAR(cmdBytesLeft);
1137 SERIALIZE_SCALAR(cmdBytes);
1138 SERIALIZE_SCALAR(drqBytesLeft);
1139 SERIALIZE_SCALAR(curSector);
1140 SERIALIZE_SCALAR(dmaRead);
1141 SERIALIZE_SCALAR(intrPending);
1142 SERIALIZE_SCALAR(dmaAborted);
1143 SERIALIZE_ENUM(devState);
1144 SERIALIZE_ENUM(dmaState);
1145 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1146}
1147
1148void
1149IdeDisk::unserialize(CheckpointIn &cp)
1150{
1151 // Reschedule events that were outstanding
1152 // these are all mutually exclusive
1153 Tick reschedule = 0;
1154 Events_t event = None;
1155
1156 UNSERIALIZE_SCALAR(reschedule);
1157 UNSERIALIZE_ENUM(event);
1158
1159 switch (event) {
1160 case None : break;
1161 case Transfer : schedule(dmaTransferEvent, reschedule); break;
1162 case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1163 case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1164 case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1165 case DmaRead : schedule(dmaReadEvent, reschedule); break;
1166 case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1167 }
1168
1169 // Unserialize device registers
1170 UNSERIALIZE_SCALAR(cmdReg.data);
1171 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1172 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1173 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1174 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1175 UNSERIALIZE_SCALAR(cmdReg.drive);
1176 UNSERIALIZE_SCALAR(cmdReg.command);
1177 UNSERIALIZE_SCALAR(status);
1178 UNSERIALIZE_SCALAR(nIENBit);
1179 UNSERIALIZE_SCALAR(devID);
1180
1181 // Unserialize the PRD related information
1182 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1183 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1184 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1185 UNSERIALIZE_SCALAR(curPrdAddr);
1186
1187 /** @todo need to serialized chunk generator stuff!! */
1188 // Unserialize current transfer related information
1189 UNSERIALIZE_SCALAR(cmdBytes);
1190 UNSERIALIZE_SCALAR(cmdBytesLeft);
1191 UNSERIALIZE_SCALAR(drqBytesLeft);
1192 UNSERIALIZE_SCALAR(curSector);
1193 UNSERIALIZE_SCALAR(dmaRead);
1194 UNSERIALIZE_SCALAR(intrPending);
1195 UNSERIALIZE_SCALAR(dmaAborted);
1196 UNSERIALIZE_ENUM(devState);
1197 UNSERIALIZE_ENUM(dmaState);
1198 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1199}
1200
1201IdeDisk *
1202IdeDiskParams::create()
1203{
1204 return new IdeDisk(this);
1205}
858 // Reset the drqBytes for this block
859 drqBytesLeft = sizeof(struct ataparams);
860
861 memcpy((void *)dataBuffer, (void *)&driveID,
862 sizeof(struct ataparams));
863 } else {
864 // Reset the drqBytes for this block
865 drqBytesLeft = SectorSize;
866
867 readDisk(curSector++, dataBuffer);
868 }
869
870 // put the first two bytes into the data register
871 memcpy((void *)&cmdReg.data, (void *)dataBuffer,
872 sizeof(uint16_t));
873
874 if (!isIENSet()) {
875 devState = Data_Ready_INTRQ_In;
876 intrPost();
877 } else {
878 devState = Transfer_Data_In;
879 }
880 }
881 break;
882
883 case Data_Ready_INTRQ_In:
884 if (action == ACT_STAT_READ) {
885 devState = Transfer_Data_In;
886 intrClear();
887 }
888 break;
889
890 case Transfer_Data_In:
891 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
892 if (action == ACT_DATA_READ_BYTE) {
893 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
894 } else {
895 drqBytesLeft -= 2;
896 cmdBytesLeft -= 2;
897
898 // copy next short into data registers
899 if (drqBytesLeft)
900 memcpy((void *)&cmdReg.data,
901 (void *)&dataBuffer[SectorSize - drqBytesLeft],
902 sizeof(uint16_t));
903 }
904
905 if (drqBytesLeft == 0) {
906 if (cmdBytesLeft == 0) {
907 // Clear the BSY bit
908 setComplete();
909 devState = Device_Idle_S;
910 } else {
911 devState = Prepare_Data_In;
912 // set the BSY_BIT
913 status |= STATUS_BSY_BIT;
914 // clear the DRQ_BIT
915 status &= ~STATUS_DRQ_BIT;
916
917 /** @todo change this to a scheduled event to simulate
918 disk delay */
919 updateState(ACT_DATA_READY);
920 }
921 }
922 }
923 break;
924
925 case Prepare_Data_Out:
926 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
927 // clear the BSY bit
928 setComplete();
929
930 if (!isIENSet()) {
931 devState = Device_Idle_SI;
932 intrPost();
933 } else {
934 devState = Device_Idle_S;
935 }
936 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
937 // clear the BSY bit
938 status &= ~STATUS_BSY_BIT;
939 // set the DRQ bit
940 status |= STATUS_DRQ_BIT;
941
942 // clear the data buffer to get it ready for writes
943 memset(dataBuffer, 0, MAX_DMA_SIZE);
944
945 // reset the drqBytes for this block
946 drqBytesLeft = SectorSize;
947
948 if (cmdBytesLeft == cmdBytes || isIENSet()) {
949 devState = Transfer_Data_Out;
950 } else {
951 devState = Data_Ready_INTRQ_Out;
952 intrPost();
953 }
954 }
955 break;
956
957 case Data_Ready_INTRQ_Out:
958 if (action == ACT_STAT_READ) {
959 devState = Transfer_Data_Out;
960 intrClear();
961 }
962 break;
963
964 case Transfer_Data_Out:
965 if (action == ACT_DATA_WRITE_BYTE ||
966 action == ACT_DATA_WRITE_SHORT) {
967
968 if (action == ACT_DATA_READ_BYTE) {
969 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
970 } else {
971 // copy the latest short into the data buffer
972 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
973 (void *)&cmdReg.data,
974 sizeof(uint16_t));
975
976 drqBytesLeft -= 2;
977 cmdBytesLeft -= 2;
978 }
979
980 if (drqBytesLeft == 0) {
981 // copy the block to the disk
982 writeDisk(curSector++, dataBuffer);
983
984 // set the BSY bit
985 status |= STATUS_BSY_BIT;
986 // set the seek bit
987 status |= STATUS_SEEK_BIT;
988 // clear the DRQ bit
989 status &= ~STATUS_DRQ_BIT;
990
991 devState = Prepare_Data_Out;
992
993 /** @todo change this to a scheduled event to simulate
994 disk delay */
995 updateState(ACT_DATA_READY);
996 }
997 }
998 break;
999
1000 case Prepare_Data_Dma:
1001 if (action == ACT_CMD_ERROR) {
1002 // clear the BSY bit
1003 setComplete();
1004
1005 if (!isIENSet()) {
1006 devState = Device_Idle_SI;
1007 intrPost();
1008 } else {
1009 devState = Device_Idle_S;
1010 }
1011 } else if (action == ACT_DMA_READY) {
1012 // clear the BSY bit
1013 status &= ~STATUS_BSY_BIT;
1014 // set the DRQ bit
1015 status |= STATUS_DRQ_BIT;
1016
1017 devState = Transfer_Data_Dma;
1018
1019 if (dmaState != Dma_Idle)
1020 panic("Inconsistent DMA state, should be Dma_Idle\n");
1021
1022 dmaState = Dma_Start;
1023 // wait for the write to the DMA start bit
1024 }
1025 break;
1026
1027 case Transfer_Data_Dma:
1028 if (action == ACT_CMD_ERROR) {
1029 dmaAborted = true;
1030 devState = Device_Dma_Abort;
1031 } else if (action == ACT_DMA_DONE) {
1032 // clear the BSY bit
1033 setComplete();
1034 // set the seek bit
1035 status |= STATUS_SEEK_BIT;
1036 // clear the controller state for DMA transfer
1037 ctrl->setDmaComplete(this);
1038
1039 if (!isIENSet()) {
1040 devState = Device_Idle_SI;
1041 intrPost();
1042 } else {
1043 devState = Device_Idle_S;
1044 }
1045 }
1046 break;
1047
1048 case Device_Dma_Abort:
1049 if (action == ACT_CMD_ERROR) {
1050 setComplete();
1051 status |= STATUS_SEEK_BIT;
1052 ctrl->setDmaComplete(this);
1053 dmaAborted = false;
1054 dmaState = Dma_Idle;
1055
1056 if (!isIENSet()) {
1057 devState = Device_Idle_SI;
1058 intrPost();
1059 } else {
1060 devState = Device_Idle_S;
1061 }
1062 } else {
1063 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1064 }
1065 break;
1066
1067 default:
1068 panic("Unknown IDE device state: %#x\n", devState);
1069 }
1070}
1071
1072void
1073IdeDisk::serialize(CheckpointOut &cp) const
1074{
1075 // Check all outstanding events to see if they are scheduled
1076 // these are all mutually exclusive
1077 Tick reschedule = 0;
1078 Events_t event = None;
1079
1080 int eventCount = 0;
1081
1082 if (dmaTransferEvent.scheduled()) {
1083 reschedule = dmaTransferEvent.when();
1084 event = Transfer;
1085 eventCount++;
1086 }
1087 if (dmaReadWaitEvent.scheduled()) {
1088 reschedule = dmaReadWaitEvent.when();
1089 event = ReadWait;
1090 eventCount++;
1091 }
1092 if (dmaWriteWaitEvent.scheduled()) {
1093 reschedule = dmaWriteWaitEvent.when();
1094 event = WriteWait;
1095 eventCount++;
1096 }
1097 if (dmaPrdReadEvent.scheduled()) {
1098 reschedule = dmaPrdReadEvent.when();
1099 event = PrdRead;
1100 eventCount++;
1101 }
1102 if (dmaReadEvent.scheduled()) {
1103 reschedule = dmaReadEvent.when();
1104 event = DmaRead;
1105 eventCount++;
1106 }
1107 if (dmaWriteEvent.scheduled()) {
1108 reschedule = dmaWriteEvent.when();
1109 event = DmaWrite;
1110 eventCount++;
1111 }
1112
1113 assert(eventCount <= 1);
1114
1115 SERIALIZE_SCALAR(reschedule);
1116 SERIALIZE_ENUM(event);
1117
1118 // Serialize device registers
1119 SERIALIZE_SCALAR(cmdReg.data);
1120 SERIALIZE_SCALAR(cmdReg.sec_count);
1121 SERIALIZE_SCALAR(cmdReg.sec_num);
1122 SERIALIZE_SCALAR(cmdReg.cyl_low);
1123 SERIALIZE_SCALAR(cmdReg.cyl_high);
1124 SERIALIZE_SCALAR(cmdReg.drive);
1125 SERIALIZE_SCALAR(cmdReg.command);
1126 SERIALIZE_SCALAR(status);
1127 SERIALIZE_SCALAR(nIENBit);
1128 SERIALIZE_SCALAR(devID);
1129
1130 // Serialize the PRD related information
1131 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1132 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1133 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1134 SERIALIZE_SCALAR(curPrdAddr);
1135
1136 /** @todo need to serialized chunk generator stuff!! */
1137 // Serialize current transfer related information
1138 SERIALIZE_SCALAR(cmdBytesLeft);
1139 SERIALIZE_SCALAR(cmdBytes);
1140 SERIALIZE_SCALAR(drqBytesLeft);
1141 SERIALIZE_SCALAR(curSector);
1142 SERIALIZE_SCALAR(dmaRead);
1143 SERIALIZE_SCALAR(intrPending);
1144 SERIALIZE_SCALAR(dmaAborted);
1145 SERIALIZE_ENUM(devState);
1146 SERIALIZE_ENUM(dmaState);
1147 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1148}
1149
1150void
1151IdeDisk::unserialize(CheckpointIn &cp)
1152{
1153 // Reschedule events that were outstanding
1154 // these are all mutually exclusive
1155 Tick reschedule = 0;
1156 Events_t event = None;
1157
1158 UNSERIALIZE_SCALAR(reschedule);
1159 UNSERIALIZE_ENUM(event);
1160
1161 switch (event) {
1162 case None : break;
1163 case Transfer : schedule(dmaTransferEvent, reschedule); break;
1164 case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1165 case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1166 case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1167 case DmaRead : schedule(dmaReadEvent, reschedule); break;
1168 case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1169 }
1170
1171 // Unserialize device registers
1172 UNSERIALIZE_SCALAR(cmdReg.data);
1173 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1174 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1175 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1176 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1177 UNSERIALIZE_SCALAR(cmdReg.drive);
1178 UNSERIALIZE_SCALAR(cmdReg.command);
1179 UNSERIALIZE_SCALAR(status);
1180 UNSERIALIZE_SCALAR(nIENBit);
1181 UNSERIALIZE_SCALAR(devID);
1182
1183 // Unserialize the PRD related information
1184 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1185 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1186 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1187 UNSERIALIZE_SCALAR(curPrdAddr);
1188
1189 /** @todo need to serialized chunk generator stuff!! */
1190 // Unserialize current transfer related information
1191 UNSERIALIZE_SCALAR(cmdBytes);
1192 UNSERIALIZE_SCALAR(cmdBytesLeft);
1193 UNSERIALIZE_SCALAR(drqBytesLeft);
1194 UNSERIALIZE_SCALAR(curSector);
1195 UNSERIALIZE_SCALAR(dmaRead);
1196 UNSERIALIZE_SCALAR(intrPending);
1197 UNSERIALIZE_SCALAR(dmaAborted);
1198 UNSERIALIZE_ENUM(devState);
1199 UNSERIALIZE_ENUM(dmaState);
1200 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1201}
1202
1203IdeDisk *
1204IdeDiskParams::create()
1205{
1206 return new IdeDisk(this);
1207}