2 * Copyright (c) 2013-2015 ARM Limited
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.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Authors: Rene de Jong
41 * This is a simulation model for a UFS interface
42 * The UFS interface consists of a host controller and (at least) one device.
43 * The device can contain multiple logic units.
44 * To make this interface as usefull as possible for future development, the
45 * decision has been made to split the UFS functionality from the SCSI
46 * functionality. The class UFS SCSIDevice can therefor be used as a starting
47 * point for creating a more generic SCSI device. This has as a consequence
48 * that the UFSHostDevice class contains functionality from both the host
49 * controller and the device. The current UFS standard (1.1) allows only one
50 * device, and up to 8 logic units. the logic units only handle the SCSI part
51 * of the command, and the device mainly the UFS part. Yet the split between
52 * the SCSIresume function and the SCSICMDHandle might seem a bit awkward.
53 * The SCSICMDHandle function is in essence a SCSI reply generator, and it
54 * distils the essential information from the command. A disktransfer cannot
55 * be made from this position because the scatter gather list is not included
56 * in the SCSI command, but in the Transfer Request descriptor. The device
57 * needs to manage the data transfer. This file is build up as follows: first
58 * the UFSSCSIDevice functions will be presented; then the UFSHostDevice
59 * functions. The UFSHostDevice functions are split in three parts: UFS
60 * transaction flow, data write transfer and data read transfer. The
61 * functions are then ordered in the order in which a transfer takes place.
65 * Reference material can be found at the JEDEC website:
67 * http://www.jedec.org/standards-documents/results/jesd220
68 * UFS HCI specification
69 * http://www.jedec.org/standards-documents/results/jesd223
72 #include "dev/arm/ufs_device.hh"
75 * Constructor and destructor functions of UFSHCM device
77 UFSHostDevice::UFSSCSIDevice::UFSSCSIDevice(const UFSHostDeviceParams
* p
,
78 uint32_t lun_id
, Callback
*transfer_cb
,
81 flashDisk(p
->image
[lun_id
]),
82 flashDevice(p
->internalflash
[lun_id
]),
83 blkSize(p
->img_blk_size
),
84 lunAvail(p
->image
.size()),
85 diskSize(flashDisk
->size()),
86 capacityLower((diskSize
- 1) & 0xffffffff),
87 capacityUpper((diskSize
- SectorSize
) >> 32),
89 transferCompleted(false),
93 amountOfWriteTransfers(0),
94 amountOfReadTransfers(0)
97 * These callbacks are used to communicate the events that are
98 * triggered upstream; e.g. from the Memory Device to the UFS SCSI Device
99 * or from the UFS SCSI device to the UFS host.
101 signalDone
= transfer_cb
;
102 memReadCallback
= new MakeCallback
<UFSSCSIDevice
,
103 &UFSHostDevice::UFSSCSIDevice::readCallback
>(this);
104 deviceReadCallback
= read_cb
;
105 memWriteCallback
= new MakeCallback
<UFSSCSIDevice
,
106 &UFSHostDevice::UFSSCSIDevice::SSDWriteDone
>(this);
109 * make ascii out of lun_id (and add more characters)
110 * UFS allows up to 8 logic units, so the numbering should work out
112 uint32_t temp_id
= ((lun_id
| 0x30) << 24) | 0x3A4449;
113 lunInfo
.dWord0
= 0x02060000; //data
114 lunInfo
.dWord1
= 0x0200001F;
115 lunInfo
.vendor0
= 0x484D5241; //ARMH (HMRA)
116 lunInfo
.vendor1
= 0x424D4143; //CAMB (BMAC)
117 lunInfo
.product0
= 0x356D6567; //gem5 (5meg)
118 lunInfo
.product1
= 0x4D534655; //UFSM (MSFU)
119 lunInfo
.product2
= 0x4C45444F; //ODEL (LEDO)
120 lunInfo
.product3
= temp_id
; // ID:"lun_id" ("lun_id":DI)
121 lunInfo
.productRevision
= 0x01000000; //0x01
123 DPRINTF(UFSHostDevice
, "Logic unit %d assumes that %d logic units are"
124 " present in the system\n", lunID
, lunAvail
);
125 DPRINTF(UFSHostDevice
,"The disksize of lun: %d should be %d blocks\n",
127 flashDevice
->initializeMemory(diskSize
, SectorSize
);
132 * These pages are SCSI specific. For more information refer to:
133 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
134 * http://www.jedec.org/standards-documents/results/jesd220
136 const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage
[3] =
137 {0x01400A0A, 0x00000000,
139 const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage
[3] =
140 {0x03800A01, 0x00000000,
142 const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage
[5] =
143 {0x00011208, 0x00000000,
144 0x00000000, 0x00000020,
147 UFSHostDevice::UFSSCSIDevice::~UFSSCSIDevice() {}
150 * UFS specific SCSI handling function.
151 * The following attributes may still be added: SCSI format unit,
152 * Send diagnostic and UNMAP;
153 * Synchronize Cache and buffer read/write could not be tested yet
154 * All parameters can be found in:
155 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
156 * http://www.jedec.org/standards-documents/results/jesd220
157 * (a JEDEC acount may be required {free of charge})
160 struct UFSHostDevice::SCSIReply
161 UFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg
)
163 struct SCSIReply scsi_out
;
164 memset(&scsi_out
, 0, sizeof(struct SCSIReply
));
167 * Create the standard SCSI reponse information
168 * These values might changes over the course of a transfer
170 scsi_out
.message
.header
.dWord0
= UPIUHeaderDataIndWord0
|
172 scsi_out
.message
.header
.dWord1
= UPIUHeaderDataIndWord1
;
173 scsi_out
.message
.header
.dWord2
= UPIUHeaderDataIndWord2
;
174 statusCheck(SCSIGood
, scsi_out
.senseCode
);
175 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
176 scsi_out
.LUN
= lunID
;
177 scsi_out
.status
= SCSIGood
;
179 DPRINTF(UFSHostDevice
, "SCSI command:%2x\n", SCSI_msg
[4]);
180 /**Determine what the message is and fill the response packet*/
182 switch (SCSI_msg
[4] & 0xFF) {
186 * SCSI inquiry: tell about this specific logic unit
188 scsi_out
.msgSize
= 36;
189 scsi_out
.message
.dataMsg
.resize(9);
191 for (uint8_t count
= 0; count
< 9; count
++)
192 scsi_out
.message
.dataMsg
[count
] =
193 (reinterpret_cast<uint32_t*> (&lunInfo
))[count
];
198 * Read command. Number indicates the length of the command.
200 scsi_out
.expectMore
= 0x02;
201 scsi_out
.msgSize
= 0;
203 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
205 /**BE and not nicely aligned. Apart from that it only has
206 * information in five bits of the first byte that is relevant
209 uint32_t tmp
= *reinterpret_cast<uint32_t*>(tempptr
);
210 uint64_t read_offset
= betoh(tmp
) & 0x1FFFFF;
212 uint32_t read_size
= tempptr
[4];
215 scsi_out
.msgSize
= read_size
* blkSize
;
216 scsi_out
.offset
= read_offset
* blkSize
;
218 if ((read_offset
+ read_size
) > diskSize
)
219 scsi_out
.status
= SCSIIllegalRequest
;
221 DPRINTF(UFSHostDevice
, "Read6 offset: 0x%8x, for %d blocks\n",
222 read_offset
, read_size
);
225 * Renew status check, for the request may have been illegal
227 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
228 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
229 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
235 scsi_out
.expectMore
= 0x02;
236 scsi_out
.msgSize
= 0;
238 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
240 /**BE and not nicely aligned.*/
241 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
242 uint64_t read_offset
= betoh(tmp
);
244 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
245 uint32_t read_size
= betoh(tmpsize
);
247 scsi_out
.msgSize
= read_size
* blkSize
;
248 scsi_out
.offset
= read_offset
* blkSize
;
250 if ((read_offset
+ read_size
) > diskSize
)
251 scsi_out
.status
= SCSIIllegalRequest
;
253 DPRINTF(UFSHostDevice
, "Read10 offset: 0x%8x, for %d blocks\n",
254 read_offset
, read_size
);
257 * Renew status check, for the request may have been illegal
259 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
260 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
261 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
267 scsi_out
.expectMore
= 0x02;
268 scsi_out
.msgSize
= 0;
270 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
272 /**BE and not nicely aligned.*/
273 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
274 uint64_t read_offset
= betoh(tmp
);
276 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[6]);
277 read_offset
= (read_offset
<< 32) | betoh(tmp
);
279 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[10]);
280 uint32_t read_size
= betoh(tmp
);
282 scsi_out
.msgSize
= read_size
* blkSize
;
283 scsi_out
.offset
= read_offset
* blkSize
;
285 if ((read_offset
+ read_size
) > diskSize
)
286 scsi_out
.status
= SCSIIllegalRequest
;
288 DPRINTF(UFSHostDevice
, "Read16 offset: 0x%8x, for %d blocks\n",
289 read_offset
, read_size
);
292 * Renew status check, for the request may have been illegal
294 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
295 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
296 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
301 case SCSIReadCapacity10
: {
303 * read the capacity of the device
305 scsi_out
.msgSize
= 8;
306 scsi_out
.message
.dataMsg
.resize(2);
307 scsi_out
.message
.dataMsg
[0] =
308 betoh(capacityLower
);//last block
309 scsi_out
.message
.dataMsg
[1] = betoh(blkSize
);//blocksize
312 case SCSIReadCapacity16
: {
313 scsi_out
.msgSize
= 32;
314 scsi_out
.message
.dataMsg
.resize(8);
315 scsi_out
.message
.dataMsg
[0] =
316 betoh(capacityUpper
);//last block
317 scsi_out
.message
.dataMsg
[1] =
318 betoh(capacityLower
);//last block
319 scsi_out
.message
.dataMsg
[2] = betoh(blkSize
);//blocksize
320 scsi_out
.message
.dataMsg
[3] = 0x00;//
321 scsi_out
.message
.dataMsg
[4] = 0x00;//reserved
322 scsi_out
.message
.dataMsg
[5] = 0x00;//reserved
323 scsi_out
.message
.dataMsg
[6] = 0x00;//reserved
324 scsi_out
.message
.dataMsg
[7] = 0x00;//reserved
328 case SCSIReportLUNs
: {
330 * Find out how many Logic Units this device has.
332 scsi_out
.msgSize
= (lunAvail
* 8) + 8;//list + overhead
333 scsi_out
.message
.dataMsg
.resize(2 * lunAvail
+ 2);
334 scsi_out
.message
.dataMsg
[0] = (lunAvail
* 8) << 24;//LUN listlength
335 scsi_out
.message
.dataMsg
[1] = 0x00;
337 for (uint8_t count
= 0; count
< lunAvail
; count
++) {
339 scsi_out
.message
.dataMsg
[2 + 2 * count
] = (count
& 0x7F) << 8;
340 scsi_out
.message
.dataMsg
[3 + 2 * count
] = 0x00;
345 case SCSIStartStop
: {
346 //Just acknowledge; not deemed relevant ATM
347 scsi_out
.msgSize
= 0;
351 case SCSITestUnitReady
: {
352 //Just acknowledge; not deemed relevant ATM
353 scsi_out
.msgSize
= 0;
359 * See if the blocks that the host plans to request are in range of
362 scsi_out
.msgSize
= 0;
364 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
366 /**BE and not nicely aligned.*/
367 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
368 uint64_t read_offset
= betoh(tmp
);
370 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
371 uint32_t read_size
= betoh(tmpsize
);
373 if ((read_offset
+ read_size
) > diskSize
)
374 scsi_out
.status
= SCSIIllegalRequest
;
377 * Renew status check, for the request may have been illegal
379 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
380 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
381 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
391 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
393 /**BE and not nicely aligned. Apart from that it only has
394 * information in five bits of the first byte that is relevant
397 uint32_t tmp
= *reinterpret_cast<uint32_t*>(tempptr
);
398 uint64_t write_offset
= betoh(tmp
) & 0x1FFFFF;
400 uint32_t write_size
= tempptr
[4];
402 scsi_out
.msgSize
= write_size
* blkSize
;
403 scsi_out
.offset
= write_offset
* blkSize
;
404 scsi_out
.expectMore
= 0x01;
406 if ((write_offset
+ write_size
) > diskSize
)
407 scsi_out
.status
= SCSIIllegalRequest
;
409 DPRINTF(UFSHostDevice
, "Write6 offset: 0x%8x, for %d blocks\n",
410 write_offset
, write_size
);
413 * Renew status check, for the request may have been illegal
415 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
416 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
417 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
423 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
425 /**BE and not nicely aligned.*/
426 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
427 uint64_t write_offset
= betoh(tmp
);
429 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
430 uint32_t write_size
= betoh(tmpsize
);
432 scsi_out
.msgSize
= write_size
* blkSize
;
433 scsi_out
.offset
= write_offset
* blkSize
;
434 scsi_out
.expectMore
= 0x01;
436 if ((write_offset
+ write_size
) > diskSize
)
437 scsi_out
.status
= SCSIIllegalRequest
;
439 DPRINTF(UFSHostDevice
, "Write10 offset: 0x%8x, for %d blocks\n",
440 write_offset
, write_size
);
443 * Renew status check, for the request may have been illegal
445 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
446 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
447 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
453 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
455 /**BE and not nicely aligned.*/
456 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
457 uint64_t write_offset
= betoh(tmp
);
459 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[6]);
460 write_offset
= (write_offset
<< 32) | betoh(tmp
);
462 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[10]);
463 uint32_t write_size
= betoh(tmp
);
465 scsi_out
.msgSize
= write_size
* blkSize
;
466 scsi_out
.offset
= write_offset
* blkSize
;
467 scsi_out
.expectMore
= 0x01;
469 if ((write_offset
+ write_size
) > diskSize
)
470 scsi_out
.status
= SCSIIllegalRequest
;
472 DPRINTF(UFSHostDevice
, "Write16 offset: 0x%8x, for %d blocks\n",
473 write_offset
, write_size
);
476 * Renew status check, for the request may have been illegal
478 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
479 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
480 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
485 case SCSIFormatUnit
: {//not yet verified
486 scsi_out
.msgSize
= 0;
487 scsi_out
.expectMore
= 0x01;
491 case SCSISendDiagnostic
: {//not yet verified
492 scsi_out
.msgSize
= 0;
496 case SCSISynchronizeCache
: {
497 //do we have cache (we don't have cache at this moment)
498 //TODO: here will synchronization happen when cache is modelled
499 scsi_out
.msgSize
= 0;
503 //UFS SCSI additional command set for full functionality
504 case SCSIModeSelect10
:
506 //scsi_out.expectMore = 0x01;//not supported due to modepage support
507 //code isn't dead, code suggest what is to be done when implemented
510 case SCSIModeSense6
: case SCSIModeSense10
: {
512 * Get more discriptive information about the SCSI functionality
513 * within this logic unit.
515 if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x0A) {//control page
516 scsi_out
.message
.dataMsg
.resize((sizeof(controlPage
) >> 2) + 2);
517 scsi_out
.message
.dataMsg
[0] = 0x00000A00;//control page code
518 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
520 for (uint8_t count
= 0; count
< 3; count
++)
521 scsi_out
.message
.dataMsg
[2 + count
] = controlPage
[count
];
523 scsi_out
.msgSize
= 20;
524 DPRINTF(UFSHostDevice
, "CONTROL page\n");
526 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
527 scsi_out
.message
.dataMsg
.resize((sizeof(recoveryPage
) >> 2)
530 scsi_out
.message
.dataMsg
[0] = 0x00000100;//recovery page code
531 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
533 for (uint8_t count
= 0; count
< 3; count
++)
534 scsi_out
.message
.dataMsg
[2 + count
] = recoveryPage
[count
];
536 scsi_out
.msgSize
= 20;
537 DPRINTF(UFSHostDevice
, "RECOVERY page\n");
539 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x08) {//caching page
541 scsi_out
.message
.dataMsg
.resize((sizeof(cachingPage
) >> 2) + 2);
542 scsi_out
.message
.dataMsg
[0] = 0x00001200;//caching page code
543 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
545 for (uint8_t count
= 0; count
< 5; count
++)
546 scsi_out
.message
.dataMsg
[2 + count
] = cachingPage
[count
];
548 scsi_out
.msgSize
= 20;
549 DPRINTF(UFSHostDevice
, "CACHE page\n");
551 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
553 scsi_out
.message
.dataMsg
.resize(((sizeof(controlPage
) +
554 sizeof(recoveryPage
) +
555 sizeof(cachingPage
)) >> 2)
557 scsi_out
.message
.dataMsg
[0] = 0x00003200;//all page code
558 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
560 for (uint8_t count
= 0; count
< 3; count
++)
561 scsi_out
.message
.dataMsg
[2 + count
] = recoveryPage
[count
];
563 for (uint8_t count
= 0; count
< 5; count
++)
564 scsi_out
.message
.dataMsg
[5 + count
] = cachingPage
[count
];
566 for (uint8_t count
= 0; count
< 3; count
++)
567 scsi_out
.message
.dataMsg
[10 + count
] = controlPage
[count
];
569 scsi_out
.msgSize
= 52;
570 DPRINTF(UFSHostDevice
, "Return ALL the pages!!!\n");
572 } else inform("Wrong mode page requested\n");
574 scsi_out
.message
.dataCount
= scsi_out
.msgSize
<< 24;
577 case SCSIRequestSense
: {
578 scsi_out
.msgSize
= 0;
582 case SCSIUnmap
:break;//not yet verified
584 case SCSIWriteBuffer
: {
585 scsi_out
.expectMore
= 0x01;
587 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
589 /**BE and not nicely aligned.*/
590 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
591 uint64_t write_offset
= betoh(tmp
) & 0xFFFFFF;
593 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[5]);
594 uint32_t write_size
= betoh(tmp
) & 0xFFFFFF;
596 scsi_out
.msgSize
= write_size
;
597 scsi_out
.offset
= write_offset
;
601 case SCSIReadBuffer
: {
603 * less trivial than normal read. Size is in bytes instead
604 * of blocks, and it is assumed (though not guaranteed) that
605 * reading is from cache.
607 scsi_out
.expectMore
= 0x02;
609 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
611 /**BE and not nicely aligned.*/
612 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
613 uint64_t read_offset
= betoh(tmp
) & 0xFFFFFF;
615 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[5]);
616 uint32_t read_size
= betoh(tmp
) & 0xFFFFFF;
618 scsi_out
.msgSize
= read_size
;
619 scsi_out
.offset
= read_offset
;
621 if ((read_offset
+ read_size
) > capacityLower
* blkSize
)
622 scsi_out
.status
= SCSIIllegalRequest
;
624 DPRINTF(UFSHostDevice
, "Read buffer location: 0x%8x\n",
626 DPRINTF(UFSHostDevice
, "Number of bytes: 0x%8x\n", read_size
);
628 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
629 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
630 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
635 case SCSIMaintenanceIn
: {
637 * linux sends this command three times from kernel 3.9 onwards,
638 * UFS does not support it, nor does this model. Linux knows this,
639 * but tries anyway (useful for some SD card types).
640 * Lets make clear we don't want it and just ignore it.
642 DPRINTF(UFSHostDevice
, "Ignoring Maintenance In command\n");
643 statusCheck(SCSIIllegalRequest
, scsi_out
.senseCode
);
644 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
645 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
647 scsi_out
.msgSize
= 0;
651 statusCheck(SCSIIllegalRequest
, scsi_out
.senseCode
);
652 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
653 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
655 scsi_out
.msgSize
= 0;
656 inform("Unsupported scsi message type: %2x\n", SCSI_msg
[4] & 0xFF);
657 inform("0x%8x\n", SCSI_msg
[0]);
658 inform("0x%8x\n", SCSI_msg
[1]);
659 inform("0x%8x\n", SCSI_msg
[2]);
660 inform("0x%8x\n", SCSI_msg
[3]);
661 inform("0x%8x\n", SCSI_msg
[4]);
669 * SCSI status check function. generic device test, creates sense codes
670 * Future versions may include TODO: device checks, which is why this is
671 * in a separate function.
675 UFSHostDevice::UFSSCSIDevice::statusCheck(uint8_t status
,
676 uint8_t* sensecodelist
)
678 for (uint8_t count
= 0; count
< 19; count
++)
679 sensecodelist
[count
] = 0;
681 sensecodelist
[0] = 18; //sense length
682 sensecodelist
[1] = 0x70; //we send a valid frame
683 sensecodelist
[3] = status
& 0xF; //mask to be sure + sensecode
684 sensecodelist
[8] = 0x1F; //data length
688 * read from the flashdisk
692 UFSHostDevice::UFSSCSIDevice::readFlash(uint8_t* readaddr
, uint64_t offset
,
695 /** read from image, and get to memory */
696 for(int count
= 0; count
< (size
/ SectorSize
); count
++)
697 flashDisk
->read(&(readaddr
[SectorSize
*count
]), (offset
/
698 SectorSize
) + count
);
702 * Write to the flashdisk
706 UFSHostDevice::UFSSCSIDevice::writeFlash(uint8_t* writeaddr
, uint64_t offset
,
709 /** Get from fifo and write to image*/
710 for(int count
= 0; count
< (size
/ SectorSize
); count
++)
711 flashDisk
->write(&(writeaddr
[SectorSize
* count
]),
712 (offset
/ SectorSize
) + count
);
716 * Constructor for the UFS Host device
719 UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams
* p
) :
721 pioAddr(p
->pio_addr
),
723 pioDelay(p
->pio_latency
),
726 lunAvail(p
->image
.size()),
727 UFSSlots(p
->ufs_slots
- 1),
737 SCSIResumeEvent(this),
740 DPRINTF(UFSHostDevice
, "The hostcontroller hosts %d Logic units\n",
742 UFSDevice
.resize(lunAvail
);
744 transferDoneCallback
= new MakeCallback
<UFSHostDevice
,
745 &UFSHostDevice::LUNSignal
>(this);
746 memReadCallback
= new MakeCallback
<UFSHostDevice
,
747 &UFSHostDevice::readCallback
>(this);
749 for(int count
= 0; count
< lunAvail
; count
++) {
750 UFSDevice
[count
] = new UFSSCSIDevice(p
, count
, transferDoneCallback
,
755 warn("UFSSlots = %d, this will results in %d command slots",
756 UFSSlots
, (UFSSlots
& 0x1F));
758 if ((UFSSlots
& 0x1F) == 0)
759 fatal("Number of UFS command slots should be between 1 and 32.");
765 * Create the parameters of this device
769 UFSHostDeviceParams::create()
771 return new UFSHostDevice(this);
776 UFSHostDevice::regStats()
778 using namespace Stats
;
780 std::string UFSHost_name
= name() + ".UFSDiskHost";
782 // Register the stats
784 stats
.currentSCSIQueue
785 .name(UFSHost_name
+ ".currentSCSIQueue")
786 .desc("Most up to date length of the command queue")
788 stats
.currentReadSSDQueue
789 .name(UFSHost_name
+ ".currentReadSSDQueue")
790 .desc("Most up to date length of the read SSD queue")
792 stats
.currentWriteSSDQueue
793 .name(UFSHost_name
+ ".currentWriteSSDQueue")
794 .desc("Most up to date length of the write SSD queue")
797 /** Amount of data read/written */
799 .name(UFSHost_name
+ ".totalReadSSD")
800 .desc("Number of bytes read from SSD")
803 stats
.totalWrittenSSD
804 .name(UFSHost_name
+ ".totalWrittenSSD")
805 .desc("Number of bytes written to SSD")
808 stats
.totalReadDiskTransactions
809 .name(UFSHost_name
+ ".totalReadDiskTransactions")
810 .desc("Number of transactions from disk")
812 stats
.totalWriteDiskTransactions
813 .name(UFSHost_name
+ ".totalWriteDiskTransactions")
814 .desc("Number of transactions to disk")
816 stats
.totalReadUFSTransactions
817 .name(UFSHost_name
+ ".totalReadUFSTransactions")
818 .desc("Number of transactions from device")
820 stats
.totalWriteUFSTransactions
821 .name(UFSHost_name
+ ".totalWriteUFSTransactions")
822 .desc("Number of transactions to device")
825 /** Average bandwidth for reads and writes */
826 stats
.averageReadSSDBW
827 .name(UFSHost_name
+ ".averageReadSSDBandwidth")
828 .desc("Average read bandwidth (bytes/s)")
831 stats
.averageReadSSDBW
= stats
.totalReadSSD
/ simSeconds
;
833 stats
.averageWriteSSDBW
834 .name(UFSHost_name
+ ".averageWriteSSDBandwidth")
835 .desc("Average write bandwidth (bytes/s)")
838 stats
.averageWriteSSDBW
= stats
.totalWrittenSSD
/ simSeconds
;
840 stats
.averageSCSIQueue
841 .name(UFSHost_name
+ ".averageSCSIQueueLength")
842 .desc("Average command queue length")
844 stats
.averageReadSSDQueue
845 .name(UFSHost_name
+ ".averageReadSSDQueueLength")
846 .desc("Average read queue length")
848 stats
.averageWriteSSDQueue
849 .name(UFSHost_name
+ ".averageWriteSSDQueueLength")
850 .desc("Average write queue length")
853 /** Number of doorbells rung*/
855 .name(UFSHost_name
+ ".curDoorbell")
856 .desc("Most up to date number of doorbells used")
859 stats
.curDoorbell
= activeDoorbells
;
862 .name(UFSHost_name
+ ".maxDoorbell")
863 .desc("Maximum number of doorbells utilized")
865 stats
.averageDoorbell
866 .name(UFSHost_name
+ ".averageDoorbell")
867 .desc("Average number of Doorbells used")
871 stats
.transactionLatency
873 .name(UFSHost_name
+ ".transactionLatency")
874 .desc("Histogram of transaction times")
879 .name(UFSHost_name
+ ".idlePeriods")
880 .desc("Histogram of idle times")
888 void UFSHostDevice::setValues()
891 * The capability register is built up as follows:
892 * 31-29 RES; Testmode support; O3 delivery; 64 bit addr;
893 * 23-19 RES; 18-16 #TM Req slots; 15-5 RES;4-0 # TR slots
895 UFSHCIMem
.HCCAP
= 0x06070000 | (UFSSlots
& 0x1F);
896 UFSHCIMem
.HCversion
= 0x00010000; //version is 1.0
897 UFSHCIMem
.HCHCDDID
= 0xAA003C3C;// Arbitrary number
898 UFSHCIMem
.HCHCPMID
= 0x41524D48; //ARMH (not an official MIPI number)
899 UFSHCIMem
.TRUTRLDBR
= 0x00;
900 UFSHCIMem
.TMUTMRLDBR
= 0x00;
901 UFSHCIMem
.CMDUICCMDR
= 0x00;
902 // We can process CMD, TM, TR, device present
903 UFSHCIMem
.ORHostControllerStatus
= 0x08;
904 UFSHCIMem
.TRUTRLBA
= 0x00;
905 UFSHCIMem
.TRUTRLBAU
= 0x00;
906 UFSHCIMem
.TMUTMRLBA
= 0x00;
907 UFSHCIMem
.TMUTMRLBAU
= 0x00;
911 * Determine address ranges
915 UFSHostDevice::getAddrRanges() const
917 AddrRangeList ranges
;
918 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
923 * UFSHCD read register. This function allows the system to read the
928 UFSHostDevice::read(PacketPtr pkt
)
932 switch (pkt
->getAddr() & 0xFF)
935 case regControllerCapabilities
:
936 data
= UFSHCIMem
.HCCAP
;
940 data
= UFSHCIMem
.HCversion
;
943 case regControllerDEVID
:
944 data
= UFSHCIMem
.HCHCDDID
;
947 case regControllerPRODID
:
948 data
= UFSHCIMem
.HCHCPMID
;
951 case regInterruptStatus
:
952 data
= UFSHCIMem
.ORInterruptStatus
;
953 UFSHCIMem
.ORInterruptStatus
= 0x00;
954 //TODO: Revise and extend
958 case regInterruptEnable
:
959 data
= UFSHCIMem
.ORInterruptEnable
;
962 case regControllerStatus
:
963 data
= UFSHCIMem
.ORHostControllerStatus
;
966 case regControllerEnable
:
967 data
= UFSHCIMem
.ORHostControllerEnable
;
970 case regUICErrorCodePHYAdapterLayer
:
971 data
= UFSHCIMem
.ORUECPA
;
974 case regUICErrorCodeDataLinkLayer
:
975 data
= UFSHCIMem
.ORUECDL
;
978 case regUICErrorCodeNetworkLayer
:
979 data
= UFSHCIMem
.ORUECN
;
982 case regUICErrorCodeTransportLayer
:
983 data
= UFSHCIMem
.ORUECT
;
986 case regUICErrorCodeDME
:
987 data
= UFSHCIMem
.ORUECDME
;
990 case regUTPTransferREQINTAGGControl
:
991 data
= UFSHCIMem
.ORUTRIACR
;
994 case regUTPTransferREQListBaseL
:
995 data
= UFSHCIMem
.TRUTRLBA
;
998 case regUTPTransferREQListBaseH
:
999 data
= UFSHCIMem
.TRUTRLBAU
;
1002 case regUTPTransferREQDoorbell
:
1003 data
= UFSHCIMem
.TRUTRLDBR
;
1006 case regUTPTransferREQListClear
:
1007 data
= UFSHCIMem
.TRUTRLCLR
;
1010 case regUTPTransferREQListRunStop
:
1011 data
= UFSHCIMem
.TRUTRLRSR
;
1014 case regUTPTaskREQListBaseL
:
1015 data
= UFSHCIMem
.TMUTMRLBA
;
1018 case regUTPTaskREQListBaseH
:
1019 data
= UFSHCIMem
.TMUTMRLBAU
;
1022 case regUTPTaskREQDoorbell
:
1023 data
= UFSHCIMem
.TMUTMRLDBR
;
1026 case regUTPTaskREQListClear
:
1027 data
= UFSHCIMem
.TMUTMRLCLR
;
1030 case regUTPTaskREQListRunStop
:
1031 data
= UFSHCIMem
.TMUTMRLRSR
;
1035 data
= UFSHCIMem
.CMDUICCMDR
;
1038 case regUICCommandArg1
:
1039 data
= UFSHCIMem
.CMDUCMDARG1
;
1042 case regUICCommandArg2
:
1043 data
= UFSHCIMem
.CMDUCMDARG2
;
1046 case regUICCommandArg3
:
1047 data
= UFSHCIMem
.CMDUCMDARG3
;
1055 pkt
->set
<uint32_t>(data
);
1056 pkt
->makeResponse();
1061 * UFSHCD write function. This function allows access to the writeable
1062 * registers. If any function attempts to write value to an unwriteable
1063 * register entry, then the value will not be written.
1066 UFSHostDevice::write(PacketPtr pkt
)
1070 switch (pkt
->getSize()) {
1073 data
= pkt
->get
<uint8_t>();
1077 data
= pkt
->get
<uint16_t>();
1081 data
= pkt
->get
<uint32_t>();
1085 panic("Undefined UFSHCD controller write size!\n");
1089 switch (pkt
->getAddr() & 0xFF)
1091 case regControllerCapabilities
://you shall not write to this
1094 case regUFSVersion
://you shall not write to this
1097 case regControllerDEVID
://you shall not write to this
1100 case regControllerPRODID
://you shall not write to this
1103 case regInterruptStatus
://you shall not write to this
1106 case regInterruptEnable
:
1107 UFSHCIMem
.ORInterruptEnable
= data
;
1110 case regControllerStatus
:
1111 UFSHCIMem
.ORHostControllerStatus
= data
;
1114 case regControllerEnable
:
1115 UFSHCIMem
.ORHostControllerEnable
= data
;
1118 case regUICErrorCodePHYAdapterLayer
:
1119 UFSHCIMem
.ORUECPA
= data
;
1122 case regUICErrorCodeDataLinkLayer
:
1123 UFSHCIMem
.ORUECDL
= data
;
1126 case regUICErrorCodeNetworkLayer
:
1127 UFSHCIMem
.ORUECN
= data
;
1130 case regUICErrorCodeTransportLayer
:
1131 UFSHCIMem
.ORUECT
= data
;
1134 case regUICErrorCodeDME
:
1135 UFSHCIMem
.ORUECDME
= data
;
1138 case regUTPTransferREQINTAGGControl
:
1139 UFSHCIMem
.ORUTRIACR
= data
;
1142 case regUTPTransferREQListBaseL
:
1143 UFSHCIMem
.TRUTRLBA
= data
;
1144 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1145 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
)!= 0x00))
1146 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1149 case regUTPTransferREQListBaseH
:
1150 UFSHCIMem
.TRUTRLBAU
= data
;
1151 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1152 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1153 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1156 case regUTPTransferREQDoorbell
:
1157 if (!(UFSHCIMem
.TRUTRLDBR
) && data
)
1158 stats
.idleTimes
.sample(curTick() - idlePhaseStart
);
1159 UFSHCIMem
.TRUTRLDBR
|= data
;
1163 case regUTPTransferREQListClear
:
1164 UFSHCIMem
.TRUTRLCLR
= data
;
1167 case regUTPTransferREQListRunStop
:
1168 UFSHCIMem
.TRUTRLRSR
= data
;
1171 case regUTPTaskREQListBaseL
:
1172 UFSHCIMem
.TMUTMRLBA
= data
;
1173 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1174 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1175 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1178 case regUTPTaskREQListBaseH
:
1179 UFSHCIMem
.TMUTMRLBAU
= data
;
1180 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1181 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1182 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1185 case regUTPTaskREQDoorbell
:
1186 UFSHCIMem
.TMUTMRLDBR
|= data
;
1190 case regUTPTaskREQListClear
:
1191 UFSHCIMem
.TMUTMRLCLR
= data
;
1194 case regUTPTaskREQListRunStop
:
1195 UFSHCIMem
.TMUTMRLRSR
= data
;
1199 UFSHCIMem
.CMDUICCMDR
= data
;
1203 case regUICCommandArg1
:
1204 UFSHCIMem
.CMDUCMDARG1
= data
;
1207 case regUICCommandArg2
:
1208 UFSHCIMem
.CMDUCMDARG2
= data
;
1211 case regUICCommandArg3
:
1212 UFSHCIMem
.CMDUCMDARG3
= data
;
1215 default:break;//nothing happens, you try to access a register that
1220 pkt
->makeResponse();
1225 * Request handler. Determines where the request comes from and initiates the
1226 * appropriate actions accordingly.
1230 UFSHostDevice::requestHandler()
1232 Addr address
= 0x00;
1236 struct taskStart task_info
;
1237 struct transferStart transferstart_info
;
1238 transferstart_info
.done
= 0;
1241 * step1 determine what called us
1242 * step2 determine where to get it
1243 * Look for any request of which we where not yet aware
1245 while (((UFSHCIMem
.CMDUICCMDR
> 0x00) |
1246 ((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
) > 0x00) |
1247 ((UFSHCIMem
.TRUTRLDBR
^ transferTrack
) > 0x00)) ) {
1249 if (UFSHCIMem
.CMDUICCMDR
> 0x00) {
1251 * Command; general control of the Host controller.
1252 * no DMA transfer needed
1255 UFSHCIMem
.ORInterruptStatus
|= UICCommandCOMPL
;
1256 generateInterrupt();
1257 UFSHCIMem
.CMDUICCMDR
= 0x00;
1258 return; //command, nothing more we can do
1260 } else if ((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
) > 0x00) {
1262 * Task; flow control, meant for the device/Logic unit
1263 * DMA transfer is needed, flash will not be approached
1265 size
= sizeof(UTPUPIUTaskReq
);
1266 /**Find the position that is not handled yet*/
1267 count
= findLsbSet((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
));
1268 address
= UFSHCIMem
.TMUTMRLBAU
;
1270 address
= (count
* size
) + (address
<< 32) +
1271 UFSHCIMem
.TMUTMRLBA
;
1272 taskCommandTrack
|= mask
<< count
;
1274 inform("UFSmodel received a task from the system; this might"
1275 " lead to untested behaviour.\n");
1277 task_info
.mask
= mask
<< count
;
1278 task_info
.address
= address
;
1279 task_info
.size
= size
;
1280 task_info
.done
= UFSHCIMem
.TMUTMRLDBR
;
1281 taskInfo
.push_back(task_info
);
1282 taskEventQueue
.push_back(this);
1283 writeDevice(&taskEventQueue
.back(), false, address
, size
,
1284 reinterpret_cast<uint8_t*>
1285 (&taskInfo
.back().destination
), 0, 0);
1287 } else if ((UFSHCIMem
.TRUTRLDBR
^ transferTrack
) > 0x00) {
1289 * Transfer; Data transfer from or to the disk. There will be DMA
1290 * transfers, and the flash might be approached. Further
1291 * commands, are needed to specify the exact command.
1293 size
= sizeof(UTPTransferReqDesc
);
1294 /**Find the position that is not handled yet*/
1295 count
= findLsbSet((UFSHCIMem
.TRUTRLDBR
^ transferTrack
));
1296 address
= UFSHCIMem
.TRUTRLBAU
;
1298 address
= (count
* size
) + (address
<< 32) + UFSHCIMem
.TRUTRLBA
;
1300 transferTrack
|= mask
<< count
;
1301 DPRINTF(UFSHostDevice
, "Doorbell register: 0x%8x select #:"
1302 " 0x%8x completion info: 0x%8x\n", UFSHCIMem
.TRUTRLDBR
,
1303 count
, transferstart_info
.done
);
1305 transferstart_info
.done
= UFSHCIMem
.TRUTRLDBR
;
1308 transactionStart
[count
] = curTick(); //note the start time
1310 stats
.maxDoorbell
= (stats
.maxDoorbell
.value() < activeDoorbells
)
1311 ? activeDoorbells
: stats
.maxDoorbell
.value();
1312 stats
.averageDoorbell
= stats
.maxDoorbell
.value();
1315 * step3 start transfer
1316 * step4 register information; allowing the host to respond in
1319 transferstart_info
.mask
= mask
<< count
;
1320 transferstart_info
.address
= address
;
1321 transferstart_info
.size
= size
;
1322 transferstart_info
.done
= UFSHCIMem
.TRUTRLDBR
;
1323 transferStartInfo
.push_back(transferstart_info
);
1325 /**Deleted in readDone, queued in finalUTP*/
1326 transferStartInfo
.back().destination
= new struct
1328 DPRINTF(UFSHostDevice
, "Initial transfer start: 0x%8x\n",
1329 transferstart_info
.done
);
1330 transferEventQueue
.push_back(this);
1332 if (transferEventQueue
.size() < 2) {
1333 writeDevice(&transferEventQueue
.front(), false,
1334 address
, size
, reinterpret_cast<uint8_t*>
1335 (transferStartInfo
.front().destination
),0, 0);
1336 DPRINTF(UFSHostDevice
, "Transfer scheduled\n");
1347 UFSHostDevice::taskStart()
1349 DPRINTF(UFSHostDevice
, "Task start");
1350 taskHandler(&taskInfo
.front().destination
, taskInfo
.front().mask
,
1351 taskInfo
.front().address
, taskInfo
.front().size
);
1352 taskInfo
.pop_front();
1353 taskEventQueue
.pop_front();
1357 * Transfer start event
1361 UFSHostDevice::transferStart()
1363 DPRINTF(UFSHostDevice
, "Enter transfer event\n");
1364 transferHandler(transferStartInfo
.front().destination
,
1365 transferStartInfo
.front().mask
,
1366 transferStartInfo
.front().address
,
1367 transferStartInfo
.front().size
,
1368 transferStartInfo
.front().done
);
1370 transferStartInfo
.pop_front();
1371 DPRINTF(UFSHostDevice
, "Transfer queue size at end of event: "
1372 "0x%8x\n", transferEventQueue
.size());
1376 * Handles the commands that are given. At this point in time, not many
1377 * commands have been implemented in the driver.
1381 UFSHostDevice::commandHandler()
1383 if (UFSHCIMem
.CMDUICCMDR
== 0x16) {
1384 UFSHCIMem
.ORHostControllerStatus
|= 0x0F;//link startup
1390 * Handles the tasks that are given. At this point in time, not many tasks
1391 * have been implemented in the driver.
1395 UFSHostDevice::taskHandler(struct UTPUPIUTaskReq
* request_in
,
1396 uint32_t req_pos
, Addr finaladdress
, uint32_t
1400 * For now, just unpack and acknowledge the task without doing anything.
1401 * TODO Implement UFS tasks.
1403 inform("taskHandler\n");
1404 inform("%8x\n", request_in
->header
.dWord0
);
1405 inform("%8x\n", request_in
->header
.dWord1
);
1406 inform("%8x\n", request_in
->header
.dWord2
);
1408 request_in
->header
.dWord2
&= 0xffffff00;
1410 UFSHCIMem
.TMUTMRLDBR
&= ~(req_pos
);
1411 taskCommandTrack
&= ~(req_pos
);
1412 UFSHCIMem
.ORInterruptStatus
|= UTPTaskREQCOMPL
;
1414 readDevice(true, finaladdress
, finalsize
, reinterpret_cast<uint8_t*>
1415 (request_in
), true, NULL
);
1420 * Obtains the SCSI command (if any)
1421 * Two possibilities: if it contains a SCSI command, then it is a usable
1422 * message; if it doesnt contain a SCSI message, then it can't be handeld
1424 * This is the second stage of the transfer. We have the information about
1425 * where the next command can be found and what the type of command is. The
1426 * actions that are needed from the device its side are: get the information
1427 * and store the information such that we can reply.
1431 UFSHostDevice::transferHandler(struct UTPTransferReqDesc
* request_in
,
1432 int req_pos
, Addr finaladdress
, uint32_t
1433 finalsize
, uint32_t done
)
1436 Addr cmd_desc_addr
= 0x00;
1439 //acknowledge handling of the message
1440 DPRINTF(UFSHostDevice
, "SCSI message detected\n");
1441 request_in
->header
.dWord2
&= 0xffffff00;
1442 SCSIInfo
.RequestIn
= request_in
;
1443 SCSIInfo
.reqPos
= req_pos
;
1444 SCSIInfo
.finalAddress
= finaladdress
;
1445 SCSIInfo
.finalSize
= finalsize
;
1446 SCSIInfo
.destination
.resize(request_in
->PRDTableOffset
* 4
1447 + request_in
->PRDTableLength
* sizeof(UFSHCDSGEntry
));
1448 SCSIInfo
.done
= done
;
1450 assert(!SCSIResumeEvent
.scheduled());
1452 *Get the UTP command that has the SCSI command
1454 cmd_desc_addr
= request_in
->commandDescBaseAddrHi
;
1455 cmd_desc_addr
= (cmd_desc_addr
<< 32) |
1456 (request_in
->commandDescBaseAddrLo
& 0xffffffff);
1458 writeDevice(&SCSIResumeEvent
, false, cmd_desc_addr
,
1459 SCSIInfo
.destination
.size(), &SCSIInfo
.destination
[0],0, 0);
1461 DPRINTF(UFSHostDevice
, "SCSI scheduled\n");
1463 transferEventQueue
.pop_front();
1467 * Obtain LUN and put it in the right LUN queue. Each LUN has its own queue
1468 * of commands that need to be executed. This is the first instance where it
1469 * can be determined which Logic unit should handle the transfer. Then check
1470 * wether it should wait and queue or if it can continue.
1474 UFSHostDevice::SCSIStart()
1476 DPRINTF(UFSHostDevice
, "SCSI message on hold until ready\n");
1477 uint32_t LUN
= SCSIInfo
.destination
[2];
1478 UFSDevice
[LUN
]->SCSIInfoQueue
.push_back(SCSIInfo
);
1480 DPRINTF(UFSHostDevice
, "SCSI queue %d has %d elements\n", LUN
,
1481 UFSDevice
[LUN
]->SCSIInfoQueue
.size());
1483 /**There are 32 doorbells, so at max there can be 32 transactions*/
1484 if (UFSDevice
[LUN
]->SCSIInfoQueue
.size() < 2) //LUN is available
1487 else if (UFSDevice
[LUN
]->SCSIInfoQueue
.size() > 32)
1488 panic("SCSI queue is getting too big %d\n", UFSDevice
[LUN
]->
1489 SCSIInfoQueue
.size());
1492 * First transfer is done, fetch the next;
1493 * At this point, the device is busy, not the HC
1495 if (!transferEventQueue
.empty()) {
1498 * loading next data packet in case Another LUN
1499 * is approached in the mean time
1501 writeDevice(&transferEventQueue
.front(), false,
1502 transferStartInfo
.front().address
,
1503 transferStartInfo
.front().size
, reinterpret_cast<uint8_t*>
1504 (transferStartInfo
.front().destination
), 0, 0);
1506 DPRINTF(UFSHostDevice
, "Transfer scheduled");
1511 * Handles the transfer requests that are given.
1512 * There can be three types of transfer. SCSI specific, Reads and writes
1513 * apart from the data transfer, this also generates its own reply (UPIU
1514 * response). Information for this reply is stored in transferInfo and will
1515 * be used in transferDone
1519 UFSHostDevice::SCSIResume(uint32_t lun_id
)
1521 DPRINTF(UFSHostDevice
, "SCSIresume\n");
1522 if (UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1523 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id
,
1524 UFSHCIMem
.TRUTRLDBR
);
1526 /**old info, lets form it such that we can understand it*/
1527 struct UTPTransferReqDesc
* request_in
= UFSDevice
[lun_id
]->
1528 SCSIInfoQueue
.front().RequestIn
;
1530 uint32_t req_pos
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().reqPos
;
1532 Addr finaladdress
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().
1535 uint32_t finalsize
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().finalSize
;
1537 uint32_t* transfercommand
= reinterpret_cast<uint32_t*>
1538 (&(UFSDevice
[lun_id
]->SCSIInfoQueue
.front().destination
[0]));
1540 DPRINTF(UFSHostDevice
, "Task tag: 0x%8x\n", transfercommand
[0]>>24);
1541 /**call logic unit to handle SCSI command*/
1542 request_out_datain
= UFSDevice
[(transfercommand
[0] & 0xFF0000) >> 16]->
1543 SCSICMDHandle(transfercommand
);
1545 DPRINTF(UFSHostDevice
, "LUN: %d\n", request_out_datain
.LUN
);
1548 * build response stating that it was succesful
1549 * command completion, Logic unit number, and Task tag
1551 request_in
->header
.dWord0
= ((request_in
->header
.dWord0
>> 24) == 0x21)
1553 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord0
=
1554 request_in
->header
.dWord0
| (request_out_datain
.LUN
<< 8)
1555 | (transfercommand
[0] & 0xFF000000);
1556 /**SCSI status reply*/
1557 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord1
= 0x00000000 |
1558 (request_out_datain
.status
<< 24);
1559 /**segment size + EHS length (see UFS standard ch7)*/
1560 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord2
= 0x00000000 |
1561 ((request_out_datain
.senseSize
+ 2) << 24) | 0x05;
1562 /**amount of data that will follow*/
1563 UFSDevice
[lun_id
]->transferInfo
.requestOut
.senseDataLen
=
1564 request_out_datain
.senseSize
;
1567 for (uint8_t count
= 0; count
<request_out_datain
.senseSize
; count
++) {
1568 UFSDevice
[lun_id
]->transferInfo
.requestOut
.senseData
[count
] =
1569 request_out_datain
.senseCode
[count
+ 1];
1573 * At position defined by "request_in->PRDTableOffset" (counting 32 bit
1574 * words) in array "transfercommand" we have a scatter gather list, which
1575 * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
1577 struct UFSHCDSGEntry
* sglist
= reinterpret_cast<UFSHCDSGEntry
*>
1578 (&(transfercommand
[(request_in
->PRDTableOffset
)]));
1580 uint32_t length
= request_in
->PRDTableLength
;
1581 DPRINTF(UFSHostDevice
, "# PRDT entries: %d\n", length
);
1583 Addr response_addr
= request_in
->commandDescBaseAddrHi
;
1584 response_addr
= (response_addr
<< 32) |
1585 ((request_in
->commandDescBaseAddrLo
+
1586 (request_in
->responseUPIULength
<< 2)) & 0xffffffff);
1588 /**transferdone information packet filling*/
1589 UFSDevice
[lun_id
]->transferInfo
.responseStartAddr
= response_addr
;
1590 UFSDevice
[lun_id
]->transferInfo
.reqPos
= req_pos
;
1591 UFSDevice
[lun_id
]->transferInfo
.size
= finalsize
;
1592 UFSDevice
[lun_id
]->transferInfo
.address
= finaladdress
;
1593 UFSDevice
[lun_id
]->transferInfo
.destination
= reinterpret_cast<uint8_t*>
1594 (UFSDevice
[lun_id
]->SCSIInfoQueue
.front().RequestIn
);
1595 UFSDevice
[lun_id
]->transferInfo
.finished
= true;
1596 UFSDevice
[lun_id
]->transferInfo
.lunID
= request_out_datain
.LUN
;
1599 * In this part the data that needs to be transfered will be initiated
1600 * and the chain of DMA (and potentially) disk transactions will be
1603 if (request_out_datain
.expectMore
== 0x01) {
1605 manageWriteTransfer(request_out_datain
.LUN
, request_out_datain
.offset
,
1608 } else if (request_out_datain
.expectMore
== 0x02) {
1610 manageReadTransfer(request_out_datain
.msgSize
, request_out_datain
.LUN
,
1611 request_out_datain
.offset
, length
, sglist
);
1614 /**not disk related transfer, SCSI maintanance*/
1616 uint32_t size_accum
= 0;
1617 DPRINTF(UFSHostDevice
, "Data DMA size: 0x%8x\n",
1618 request_out_datain
.msgSize
);
1620 /**Transport the SCSI reponse data according to the SG list*/
1621 while ((length
> count
) && size_accum
1622 < (request_out_datain
.msgSize
- 1) &&
1623 (request_out_datain
.msgSize
!= 0x00)) {
1624 Addr SCSI_start
= sglist
[count
].upperAddr
;
1625 SCSI_start
= (SCSI_start
<< 32) |
1626 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
1627 DPRINTF(UFSHostDevice
, "Data DMA start: 0x%8x\n", SCSI_start
);
1628 DPRINTF(UFSHostDevice
, "Data DMA size: 0x%8x\n",
1629 (sglist
[count
].size
+ 1));
1631 * safetynet; it has been shown that sg list may be optimistic in
1632 * the amount of data allocated, which can potentially lead to
1633 * some garbage data being send over. Hence this construction
1634 * that finds the least amount of data that needs to be
1637 uint32_t size_to_send
= sglist
[count
].size
+ 1;
1639 if (request_out_datain
.msgSize
< (size_to_send
+ size_accum
))
1640 size_to_send
= request_out_datain
.msgSize
- size_accum
;
1642 readDevice(false, SCSI_start
, size_to_send
,
1643 reinterpret_cast<uint8_t*>
1644 (&(request_out_datain
.message
.dataMsg
[size_accum
])),
1647 size_accum
+= size_to_send
;
1648 DPRINTF(UFSHostDevice
, "Total remaining: 0x%8x,accumulated so far"
1649 " : 0x%8x\n", (request_out_datain
.msgSize
- size_accum
),
1653 DPRINTF(UFSHostDevice
, "Transfer #: %d\n", count
);
1656 /**Go to the next stage of the answering process*/
1657 transferDone(response_addr
, req_pos
, UFSDevice
[lun_id
]->
1658 transferInfo
.requestOut
, finalsize
, finaladdress
,
1659 reinterpret_cast<uint8_t*>(request_in
), true, lun_id
);
1662 DPRINTF(UFSHostDevice
, "SCSI resume done\n");
1666 * Find finished transfer. Callback function. One of the LUNs is done with
1667 * the disk transfer and reports back to the controller. This function finds
1668 * out who it was, and calls transferDone.
1671 UFSHostDevice::LUNSignal()
1673 uint8_t this_lun
= 0;
1675 //while we haven't found the right lun, keep searching
1676 while((this_lun
< lunAvail
) && !UFSDevice
[this_lun
]->finishedCommand())
1679 if (this_lun
< lunAvail
) {
1681 UFSDevice
[this_lun
]->clearSignal();
1682 //found it; call transferDone
1683 transferDone(UFSDevice
[this_lun
]->transferInfo
.responseStartAddr
,
1684 UFSDevice
[this_lun
]->transferInfo
.reqPos
,
1685 UFSDevice
[this_lun
]->transferInfo
.requestOut
,
1686 UFSDevice
[this_lun
]->transferInfo
.size
,
1687 UFSDevice
[this_lun
]->transferInfo
.address
,
1688 UFSDevice
[this_lun
]->transferInfo
.destination
,
1689 UFSDevice
[this_lun
]->transferInfo
.finished
,
1690 UFSDevice
[this_lun
]->transferInfo
.lunID
);
1694 panic("no LUN finished in tick %d\n", curTick());
1698 * Transfer done. When the data transfer is done, this function ensures
1699 * that the application is notified.
1703 UFSHostDevice::transferDone(Addr responseStartAddr
, uint32_t req_pos
,
1704 struct UTPUPIURSP request_out
, uint32_t size
,
1705 Addr address
, uint8_t* destination
,
1706 bool finished
, uint32_t lun_id
)
1708 /**Test whether SCSI queue hasn't popped prematurely*/
1709 if (UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1710 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id
,
1711 UFSHCIMem
.TRUTRLDBR
);
1713 DPRINTF(UFSHostDevice
, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1714 responseStartAddr
, sizeof(request_out
));
1716 struct transferStart lastinfo
;
1717 lastinfo
.mask
= req_pos
;
1718 lastinfo
.done
= finished
;
1719 lastinfo
.address
= address
;
1720 lastinfo
.size
= size
;
1721 lastinfo
.destination
= reinterpret_cast<UTPTransferReqDesc
*>
1723 lastinfo
.lun_id
= lun_id
;
1725 transferEnd
.push_back(lastinfo
);
1727 DPRINTF(UFSHostDevice
, "Transfer done start\n");
1729 readDevice(false, responseStartAddr
, sizeof(request_out
),
1730 reinterpret_cast<uint8_t*>
1731 (&(UFSDevice
[lun_id
]->transferInfo
.requestOut
)),
1736 * finalUTP. Second part of the transfer done event.
1737 * this sends the final response: the UTP response. After this transaction
1738 * the doorbell shall be cleared, and the interupt shall be set.
1742 UFSHostDevice::finalUTP()
1744 uint32_t lun_id
= transferEnd
.front().lun_id
;
1746 UFSDevice
[lun_id
]->SCSIInfoQueue
.pop_front();
1747 DPRINTF(UFSHostDevice
, "SCSIInfoQueue size: %d, lun: %d\n",
1748 UFSDevice
[lun_id
]->SCSIInfoQueue
.size(), lun_id
);
1751 if (UFSHCIMem
.TRUTRLDBR
& transferEnd
.front().mask
) {
1753 while (!(transferEnd
.front().mask
& (0x1 << count
)))
1755 stats
.transactionLatency
.sample(curTick() -
1756 transactionStart
[count
]);
1759 /**Last message that will be transfered*/
1760 readDevice(true, transferEnd
.front().address
,
1761 transferEnd
.front().size
, reinterpret_cast<uint8_t*>
1762 (transferEnd
.front().destination
), true, NULL
);
1764 /**clean and ensure that the tracker is updated*/
1765 transferTrack
&= ~(transferEnd
.front().mask
);
1768 garbage
.push_back(transferEnd
.front().destination
);
1769 transferEnd
.pop_front();
1770 DPRINTF(UFSHostDevice
, "UTP handled\n");
1773 stats
.averageDoorbell
= stats
.maxDoorbell
.value();
1775 DPRINTF(UFSHostDevice
, "activeDoorbells: %d, pendingDoorbells: %d,"
1776 " garbage: %d, TransferEvent: %d\n", activeDoorbells
,
1777 pendingDoorbells
, garbage
.size(), transferEventQueue
.size());
1779 /**This is the moment that the device is available again*/
1780 if (!UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1785 * Read done handling function, is only initiated at the end of a transaction
1788 UFSHostDevice::readDone()
1790 DPRINTF(UFSHostDevice
, "Read done start\n");
1793 /**Garbage collection; sort out the allocated UTP descriptor*/
1794 if (garbage
.size() > 0) {
1795 delete garbage
.front();
1796 garbage
.pop_front();
1799 /**done, generate interrupt if we havent got one already*/
1800 if(!(UFSHCIMem
.ORInterruptStatus
& 0x01)) {
1801 UFSHCIMem
.ORInterruptStatus
|= UTPTransferREQCOMPL
;
1802 generateInterrupt();
1806 if(!readDoneEvent
.empty()) {
1807 readDoneEvent
.pop_front();
1812 * set interrupt and sort out the doorbell register.
1816 UFSHostDevice::generateInterrupt()
1818 /**just to keep track of the transactions*/
1821 /**step5 clear doorbell*/
1822 UFSHCIMem
.TRUTRLDBR
&= transferTrack
;
1823 pendingDoorbells
= 0;
1824 DPRINTF(UFSHostDevice
, "Clear doorbell %X\n", UFSHCIMem
.TRUTRLDBR
);
1826 /**step6 raise interrupt*/
1827 gic
->sendInt(intNum
);
1828 DPRINTF(UFSHostDevice
, "Send interrupt @ transaction: 0x%8x!\n",
1837 UFSHostDevice::clearInterrupt()
1839 gic
->clearInt(intNum
);
1840 DPRINTF(UFSHostDevice
, "Clear interrupt: 0x%8x!\n", countInt
);
1842 if (!(UFSHCIMem
.TRUTRLDBR
)) {
1843 idlePhaseStart
= curTick();
1845 /**end of a transaction*/
1849 * Important to understand about the transfer flow:
1850 * We have basically three stages, The "system memory" stage, the "device
1851 * buffer" stage and the "disk" stage. In this model we assume an infinite
1852 * buffer, or a buffer that is big enough to store all the data in the
1853 * biggest transaction. Between the three stages are two queues. Those queues
1854 * store the messages to simulate their transaction from one stage to the
1855 * next. The manage{Action} function fills up one of the queues and triggers
1856 * the first event, which causes a chain reaction of events executed once
1857 * they pass through their queues. For a write action the stages are ordered
1858 * "system memory", "device buffer" and "disk", whereas the read transfers
1859 * happen "disk", "device buffer" and "system memory". The dma action in the
1860 * dma device is written from a bus perspective whereas this model is written
1861 * from a device perspective. To avoid confusion, the translation between the
1862 * two has been made in the writeDevice and readDevice funtions.
1867 * Dma transaction function: write device. Note that the dma action is
1868 * from a device perspective, while this function is from an initiator
1873 UFSHostDevice::writeDevice(Event
* additional_action
, bool toDisk
, Addr
1874 start
, int size
, uint8_t* destination
, uint64_t
1875 SCSIDiskOffset
, uint32_t lun_id
)
1877 DPRINTF(UFSHostDevice
, "Write transaction Start: 0x%8x; Size: %d\n",
1880 /**check whether transfer is all the way to the flash*/
1884 while(!writeDoneEvent
.empty() && (writeDoneEvent
.front().when()
1886 writeDoneEvent
.pop_front();
1888 writeDoneEvent
.push_back(this);
1889 assert(!writeDoneEvent
.back().scheduled());
1891 /**destination is an offset here since we are writing to a disk*/
1892 struct transferInfo new_transfer
;
1893 new_transfer
.offset
= SCSIDiskOffset
;
1894 new_transfer
.size
= size
;
1895 new_transfer
.lunID
= lun_id
;
1896 new_transfer
.filePointer
= 0;
1897 SSDWriteinfo
.push_back(new_transfer
);
1899 /**allocate appropriate buffer*/
1900 SSDWriteinfo
.back().buffer
.resize(size
);
1903 dmaPort
.dmaAction(MemCmd::ReadReq
, start
, size
,
1904 &writeDoneEvent
.back(),
1905 &SSDWriteinfo
.back().buffer
[0], 0);
1906 //yes, a readreq at a write device function is correct.
1907 DPRINTF(UFSHostDevice
, "Write to disk scheduled\n");
1910 assert(!additional_action
->scheduled());
1911 dmaPort
.dmaAction(MemCmd::ReadReq
, start
, size
,
1912 additional_action
, destination
, 0);
1913 DPRINTF(UFSHostDevice
, "Write scheduled\n");
1918 * Manage write transfer. Manages correct transfer flow and makes sure that
1919 * the queues are filled on time
1923 UFSHostDevice::manageWriteTransfer(uint8_t LUN
, uint64_t offset
, uint32_t
1924 sg_table_length
, struct UFSHCDSGEntry
*
1927 struct writeToDiskBurst next_packet
;
1929 next_packet
.SCSIDiskOffset
= offset
;
1931 UFSDevice
[LUN
]->setTotalWrite(sg_table_length
);
1934 * Break-up the transactions into actions defined by the scatter gather
1937 for (uint32_t count
= 0; count
< sg_table_length
; count
++) {
1938 next_packet
.start
= sglist
[count
].upperAddr
;
1939 next_packet
.start
= (next_packet
.start
<< 32) |
1940 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
1941 next_packet
.LUN
= LUN
;
1942 DPRINTF(UFSHostDevice
, "Write data DMA start: 0x%8x\n",
1944 DPRINTF(UFSHostDevice
, "Write data DMA size: 0x%8x\n",
1945 (sglist
[count
].size
+ 1));
1946 assert(sglist
[count
].size
> 0);
1949 next_packet
.SCSIDiskOffset
= next_packet
.SCSIDiskOffset
+
1950 (sglist
[count
- 1].size
+ 1);
1952 next_packet
.size
= sglist
[count
].size
+ 1;
1954 /**If the queue is empty, the transaction should be initiated*/
1955 if (dmaWriteInfo
.empty())
1956 writeDevice(NULL
, true, next_packet
.start
, next_packet
.size
,
1957 NULL
, next_packet
.SCSIDiskOffset
, next_packet
.LUN
);
1959 DPRINTF(UFSHostDevice
, "Write not initiated queue: %d\n",
1960 dmaWriteInfo
.size());
1962 dmaWriteInfo
.push_back(next_packet
);
1963 DPRINTF(UFSHostDevice
, "Write Location: 0x%8x\n",
1964 next_packet
.SCSIDiskOffset
);
1966 DPRINTF(UFSHostDevice
, "Write transfer #: 0x%8x\n", count
+ 1);
1969 stats
.totalWrittenSSD
+= (sglist
[count
].size
+ 1);
1973 ++stats
.totalWriteUFSTransactions
;
1977 * Write done handling function. Is only initiated when the flash is directly
1982 UFSHostDevice::writeDone()
1984 /**DMA is done, information no longer needed*/
1985 assert(dmaWriteInfo
.size() > 0);
1986 dmaWriteInfo
.pop_front();
1987 assert(SSDWriteinfo
.size() > 0);
1988 uint32_t lun
= SSDWriteinfo
.front().lunID
;
1990 /**If there is nothing on the way, we need to start the events*/
1991 DPRINTF(UFSHostDevice
, "Write done entered, queue: %d\n",
1992 UFSDevice
[lun
]->SSDWriteDoneInfo
.size());
1994 UFSDevice
[lun
]->writeFlash(&SSDWriteinfo
.front().buffer
[0],
1995 SSDWriteinfo
.front().offset
,
1996 SSDWriteinfo
.front().size
);
1999 * Move to the second queue, enter the logic unit
2000 * This is where the disk is approached and the flash transaction is
2001 * handled SSDWriteDone will take care of the timing
2003 UFSDevice
[lun
]->SSDWriteDoneInfo
.push_back(SSDWriteinfo
.front());
2004 SSDWriteinfo
.pop_front();
2007 /**so far, only the DMA part has been handled, lets do the disk delay*/
2008 UFSDevice
[lun
]->SSDWriteStart();
2011 stats
.currentWriteSSDQueue
= UFSDevice
[lun
]->SSDWriteDoneInfo
.size();
2012 stats
.averageWriteSSDQueue
= UFSDevice
[lun
]->SSDWriteDoneInfo
.size();
2013 ++stats
.totalWriteDiskTransactions
;
2015 /**initiate the next dma action (if any)*/
2016 if (!dmaWriteInfo
.empty())
2017 writeDevice(NULL
, true, dmaWriteInfo
.front().start
,
2018 dmaWriteInfo
.front().size
, NULL
,
2019 dmaWriteInfo
.front().SCSIDiskOffset
,
2020 dmaWriteInfo
.front().LUN
);
2021 DPRINTF(UFSHostDevice
, "Write done end\n");
2025 * SSD write start. Starts the write action in the timing model
2028 UFSHostDevice::UFSSCSIDevice::SSDWriteStart()
2030 assert(SSDWriteDoneInfo
.size() > 0);
2031 flashDevice
->writeMemory(
2032 SSDWriteDoneInfo
.front().offset
,
2033 SSDWriteDoneInfo
.front().size
, memWriteCallback
);
2035 SSDWriteDoneInfo
.pop_front();
2037 DPRINTF(UFSHostDevice
, "Write is started; left in queue: %d\n",
2038 SSDWriteDoneInfo
.size());
2047 UFSHostDevice::UFSSCSIDevice::SSDWriteDone()
2049 DPRINTF(UFSHostDevice
, "Write disk, aiming for %d messages, %d so far\n",
2050 totalWrite
, amountOfWriteTransfers
);
2052 //we have done one extra transfer
2053 ++amountOfWriteTransfers
;
2055 /**test whether call was correct*/
2056 assert(totalWrite
>= amountOfWriteTransfers
&& totalWrite
!= 0);
2058 /**are we there yet? (did we do everything)*/
2059 if (totalWrite
== amountOfWriteTransfers
) {
2060 DPRINTF(UFSHostDevice
, "Write transactions finished\n");
2062 amountOfWriteTransfers
= 0;
2066 signalDone
->process();
2072 * Dma transaction function: read device. Notice that the dma action is from
2073 * a device perspective, while this function is from an initiator perspective
2077 UFSHostDevice::readDevice(bool lastTransfer
, Addr start
, uint32_t size
,
2078 uint8_t* destination
, bool no_cache
, Event
*
2081 DPRINTF(UFSHostDevice
, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2082 start
, size
, (reinterpret_cast<uint32_t *>(destination
))[0]);
2084 /** check wether interrupt is needed */
2087 readDoneEvent
.push_back(this);
2088 assert(!readDoneEvent
.back().scheduled());
2089 dmaPort
.dmaAction(MemCmd::WriteReq
, start
, size
,
2090 &readDoneEvent
.back(), destination
, 0);
2091 //yes, a writereq at a read device function is correct.
2094 if (additional_action
!= NULL
)
2095 assert(!additional_action
->scheduled());
2097 dmaPort
.dmaAction(MemCmd::WriteReq
, start
, size
,
2098 additional_action
, destination
, 0);
2105 * Manage read transfer. Manages correct transfer flow and makes sure that
2106 * the queues are filled on time
2110 UFSHostDevice::manageReadTransfer(uint32_t size
, uint32_t LUN
, uint64_t
2111 offset
, uint32_t sg_table_length
,
2112 struct UFSHCDSGEntry
* sglist
)
2114 uint32_t size_accum
= 0;
2116 DPRINTF(UFSHostDevice
, "Data READ size: %d\n", size
);
2119 * Break-up the transactions into actions defined by the scatter gather
2122 for (uint32_t count
= 0; count
< sg_table_length
; count
++) {
2123 struct transferInfo new_transfer
;
2124 new_transfer
.offset
= sglist
[count
].upperAddr
;
2125 new_transfer
.offset
= (new_transfer
.offset
<< 32) |
2126 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
2127 new_transfer
.filePointer
= offset
+ size_accum
;
2128 new_transfer
.size
= (sglist
[count
].size
+ 1);
2129 new_transfer
.lunID
= LUN
;
2131 DPRINTF(UFSHostDevice
, "Data READ start: 0x%8x; size: %d\n",
2132 new_transfer
.offset
, new_transfer
.size
);
2134 UFSDevice
[LUN
]->SSDReadInfo
.push_back(new_transfer
);
2135 UFSDevice
[LUN
]->SSDReadInfo
.back().buffer
.resize(sglist
[count
].size
2139 * The disk image is read here; but the action is simultated later
2140 * You can see this as the preparation stage, whereas later is the
2143 UFSDevice
[LUN
]->readFlash(&UFSDevice
[LUN
]->
2144 SSDReadInfo
.back().buffer
[0],
2145 offset
+ size_accum
,
2146 sglist
[count
].size
+ 1);
2148 size_accum
+= (sglist
[count
].size
+ 1);
2150 DPRINTF(UFSHostDevice
, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2151 " 0x%8x\n", (count
+ 1), (size
-size_accum
), size_accum
);
2154 stats
.totalReadSSD
+= (sglist
[count
].size
+ 1);
2155 stats
.currentReadSSDQueue
= UFSDevice
[LUN
]->SSDReadInfo
.size();
2156 stats
.averageReadSSDQueue
= UFSDevice
[LUN
]->SSDReadInfo
.size();
2159 UFSDevice
[LUN
]->SSDReadStart(sg_table_length
);
2162 ++stats
.totalReadUFSTransactions
;
2169 * SSDisk start read; this function was created to keep the interfaces
2170 * between the layers simpler. Without this function UFSHost would need to
2171 * know about the flashdevice.
2175 UFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read
)
2177 totalRead
= total_read
;
2178 for (uint32_t number_handled
= 0; number_handled
< SSDReadInfo
.size();
2181 * Load all the read request to the Memory device.
2182 * It will call back when done.
2184 flashDevice
->readMemory(SSDReadInfo
.front().filePointer
,
2185 SSDReadInfo
.front().size
, memReadCallback
);
2196 UFSHostDevice::UFSSCSIDevice::SSDReadDone()
2198 DPRINTF(UFSHostDevice
, "SSD read done at lun %d, Aiming for %d messages,"
2199 " %d so far\n", lunID
, totalRead
, amountOfReadTransfers
);
2201 if (totalRead
== amountOfReadTransfers
) {
2203 amountOfReadTransfers
= 0;
2205 /**Callback: transferdone*/
2207 signalDone
->process();
2213 * Read callback, on the way from the disk to the DMA. Called by the flash
2214 * layer. Intermediate step to the host layer
2217 UFSHostDevice::UFSSCSIDevice::readCallback()
2219 ++amountOfReadTransfers
;
2221 /**Callback; make sure data is transfered upstream:
2222 * UFSHostDevice::readCallback
2225 deviceReadCallback
->process();
2232 * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
2237 UFSHostDevice::readCallback()
2239 DPRINTF(UFSHostDevice
, "Read Callback\n");
2240 uint8_t this_lun
= 0;
2242 //while we haven't found the right lun, keep searching
2243 while((this_lun
< lunAvail
) && !UFSDevice
[this_lun
]->finishedRead())
2246 DPRINTF(UFSHostDevice
, "Found LUN %d messages pending for clean: %d\n",
2247 this_lun
, SSDReadPending
.size());
2249 if (this_lun
< lunAvail
) {
2251 UFSDevice
[this_lun
]->clearReadSignal();
2252 SSDReadPending
.push_back(UFSDevice
[this_lun
]->SSDReadInfo
.front());
2253 UFSDevice
[this_lun
]->SSDReadInfo
.pop_front();
2254 readGarbageEventQueue
.push_back(this);
2256 //make sure the queue is popped a the end of the dma transaction
2257 readDevice(false, SSDReadPending
.front().offset
,
2258 SSDReadPending
.front().size
,
2259 &SSDReadPending
.front().buffer
[0], false,
2260 &readGarbageEventQueue
.back());
2263 ++stats
.totalReadDiskTransactions
;
2266 panic("no read finished in tick %d\n", curTick());
2270 * After a disk read DMA transfer, the structure needs to be freed. This is
2271 * done in this function.
2274 UFSHostDevice::readGarbage()
2276 DPRINTF(UFSHostDevice
, "Clean read data, %d\n", SSDReadPending
.size());
2277 SSDReadPending
.pop_front();
2278 readGarbageEventQueue
.pop_front();
2282 * Serialize; needed to make checkpoints
2286 UFSHostDevice::serialize(std::ostream
&os
)
2288 DmaDevice::serialize(os
);
2290 uint8_t* temp_HCI_mem
= reinterpret_cast<uint8_t*>(&UFSHCIMem
);
2291 SERIALIZE_ARRAY(temp_HCI_mem
, sizeof(HCIMem
));
2293 uint32_t lun_avail
= lunAvail
;
2294 SERIALIZE_SCALAR(lun_avail
);
2299 * Unserialize; needed to restore from checkpoints
2303 UFSHostDevice::unserialize(Checkpoint
*cp
, const std::string
§ion
)
2305 DmaDevice::unserialize(cp
, section
);
2306 uint8_t* temp_HCI_mem
= reinterpret_cast<uint8_t*>(&UFSHCIMem
);
2307 UNSERIALIZE_ARRAY(temp_HCI_mem
, sizeof(HCIMem
));
2310 UNSERIALIZE_SCALAR(lun_avail
);
2311 assert(lunAvail
== lun_avail
);
2316 * Drain; needed to enable checkpoints
2320 UFSHostDevice::drain(DrainManager
*dm
)
2322 unsigned int count
= 0;
2324 // check pio, dma port, and doorbells
2325 count
= pioPort
.drain(dm
) + dmaPort
.drain(dm
);
2327 if (UFSHCIMem
.TRUTRLDBR
) {
2331 DPRINTF(UFSHostDevice
, "UFSHostDevice in drained state\n");
2335 DPRINTF(UFSHostDevice
, "UFSDevice is draining...\n");
2336 setDrainState(Drainable::Draining
);
2338 DPRINTF(UFSHostDevice
, "UFSDevice drained\n");
2339 setDrainState(Drainable::Drained
);
2345 * Checkdrain; needed to enable checkpoints
2349 UFSHostDevice::checkDrain()
2351 if (drainManager
== NULL
) {
2355 if (UFSHCIMem
.TRUTRLDBR
) {
2356 DPRINTF(UFSHostDevice
, "UFSDevice is still draining; with %d active"
2357 " doorbells\n", activeDoorbells
);
2359 DPRINTF(UFSHostDevice
, "UFSDevice is done draining\n");
2360 drainManager
->signalDrainDone();
2361 drainManager
= NULL
;