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