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.
39 * This is a simulation model for a UFS interface
40 * The UFS interface consists of a host controller and (at least) one device.
41 * The device can contain multiple logic units.
42 * To make this interface as usefull as possible for future development, the
43 * decision has been made to split the UFS functionality from the SCSI
44 * functionality. The class UFS SCSIDevice can therefor be used as a starting
45 * point for creating a more generic SCSI device. This has as a consequence
46 * that the UFSHostDevice class contains functionality from both the host
47 * controller and the device. The current UFS standard (1.1) allows only one
48 * device, and up to 8 logic units. the logic units only handle the SCSI part
49 * of the command, and the device mainly the UFS part. Yet the split between
50 * the SCSIresume function and the SCSICMDHandle might seem a bit awkward.
51 * The SCSICMDHandle function is in essence a SCSI reply generator, and it
52 * distils the essential information from the command. A disktransfer cannot
53 * be made from this position because the scatter gather list is not included
54 * in the SCSI command, but in the Transfer Request descriptor. The device
55 * needs to manage the data transfer. This file is build up as follows: first
56 * the UFSSCSIDevice functions will be presented; then the UFSHostDevice
57 * functions. The UFSHostDevice functions are split in three parts: UFS
58 * transaction flow, data write transfer and data read transfer. The
59 * functions are then ordered in the order in which a transfer takes place.
63 * Reference material can be found at the JEDEC website:
65 * http://www.jedec.org/standards-documents/results/jesd220
66 * UFS HCI specification
67 * http://www.jedec.org/standards-documents/results/jesd223
70 #include "dev/arm/ufs_device.hh"
73 * Constructor and destructor functions of UFSHCM device
75 UFSHostDevice::UFSSCSIDevice::UFSSCSIDevice(const UFSHostDeviceParams
&p
,
76 uint32_t lun_id
, const Callback
&transfer_cb
,
77 const Callback
&read_cb
):
79 flashDisk(p
.image
[lun_id
]),
80 flashDevice(p
.internalflash
[lun_id
]),
81 blkSize(p
.img_blk_size
),
82 lunAvail(p
.image
.size()),
83 diskSize(flashDisk
->size()),
84 capacityLower((diskSize
- 1) & 0xffffffff),
85 capacityUpper((diskSize
- SectorSize
) >> 32),
87 transferCompleted(false),
91 amountOfWriteTransfers(0),
92 amountOfReadTransfers(0)
95 * These callbacks are used to communicate the events that are
96 * triggered upstream; e.g. from the Memory Device to the UFS SCSI Device
97 * or from the UFS SCSI device to the UFS host.
99 signalDone
= transfer_cb
;
100 memReadCallback
= [this]() { readCallback(); };
101 deviceReadCallback
= read_cb
;
102 memWriteCallback
= [this]() { SSDWriteDone(); };
105 * make ascii out of lun_id (and add more characters)
106 * UFS allows up to 8 logic units, so the numbering should work out
108 uint32_t temp_id
= ((lun_id
| 0x30) << 24) | 0x3A4449;
109 lunInfo
.dWord0
= 0x02060000; //data
110 lunInfo
.dWord1
= 0x0200001F;
111 lunInfo
.vendor0
= 0x484D5241; //ARMH (HMRA)
112 lunInfo
.vendor1
= 0x424D4143; //CAMB (BMAC)
113 lunInfo
.product0
= 0x356D6567; //gem5 (5meg)
114 lunInfo
.product1
= 0x4D534655; //UFSM (MSFU)
115 lunInfo
.product2
= 0x4C45444F; //ODEL (LEDO)
116 lunInfo
.product3
= temp_id
; // ID:"lun_id" ("lun_id":DI)
117 lunInfo
.productRevision
= 0x01000000; //0x01
119 DPRINTF(UFSHostDevice
, "Logic unit %d assumes that %d logic units are"
120 " present in the system\n", lunID
, lunAvail
);
121 DPRINTF(UFSHostDevice
,"The disksize of lun: %d should be %d blocks\n",
123 flashDevice
->initializeMemory(diskSize
, SectorSize
);
128 * These pages are SCSI specific. For more information refer to:
129 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
130 * http://www.jedec.org/standards-documents/results/jesd220
132 const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage
[3] =
133 {0x01400A0A, 0x00000000,
135 const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage
[3] =
136 {0x03800A01, 0x00000000,
138 const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage
[5] =
139 {0x00011208, 0x00000000,
140 0x00000000, 0x00000020,
143 UFSHostDevice::UFSSCSIDevice::~UFSSCSIDevice() {}
146 * UFS specific SCSI handling function.
147 * The following attributes may still be added: SCSI format unit,
148 * Send diagnostic and UNMAP;
149 * Synchronize Cache and buffer read/write could not be tested yet
150 * All parameters can be found in:
151 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
152 * http://www.jedec.org/standards-documents/results/jesd220
153 * (a JEDEC acount may be required {free of charge})
156 struct UFSHostDevice::SCSIReply
157 UFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg
)
159 struct SCSIReply scsi_out
;
163 * Create the standard SCSI reponse information
164 * These values might changes over the course of a transfer
166 scsi_out
.message
.header
.dWord0
= UPIUHeaderDataIndWord0
|
168 scsi_out
.message
.header
.dWord1
= UPIUHeaderDataIndWord1
;
169 scsi_out
.message
.header
.dWord2
= UPIUHeaderDataIndWord2
;
170 statusCheck(SCSIGood
, scsi_out
.senseCode
);
171 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
172 scsi_out
.LUN
= lunID
;
173 scsi_out
.status
= SCSIGood
;
175 DPRINTF(UFSHostDevice
, "SCSI command:%2x\n", SCSI_msg
[4]);
176 /**Determine what the message is and fill the response packet*/
178 switch (SCSI_msg
[4] & 0xFF) {
182 * SCSI inquiry: tell about this specific logic unit
184 scsi_out
.msgSize
= 36;
185 scsi_out
.message
.dataMsg
.resize(9);
187 for (uint8_t count
= 0; count
< 9; count
++)
188 scsi_out
.message
.dataMsg
[count
] =
189 (reinterpret_cast<uint32_t*> (&lunInfo
))[count
];
194 * Read command. Number indicates the length of the command.
196 scsi_out
.expectMore
= 0x02;
197 scsi_out
.msgSize
= 0;
199 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
201 /**BE and not nicely aligned. Apart from that it only has
202 * information in five bits of the first byte that is relevant
205 uint32_t tmp
= *reinterpret_cast<uint32_t*>(tempptr
);
206 uint64_t read_offset
= betoh(tmp
) & 0x1FFFFF;
208 uint32_t read_size
= tempptr
[4];
211 scsi_out
.msgSize
= read_size
* blkSize
;
212 scsi_out
.offset
= read_offset
* blkSize
;
214 if ((read_offset
+ read_size
) > diskSize
)
215 scsi_out
.status
= SCSIIllegalRequest
;
217 DPRINTF(UFSHostDevice
, "Read6 offset: 0x%8x, for %d blocks\n",
218 read_offset
, read_size
);
221 * Renew status check, for the request may have been illegal
223 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
224 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
225 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
231 scsi_out
.expectMore
= 0x02;
232 scsi_out
.msgSize
= 0;
234 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
236 /**BE and not nicely aligned.*/
237 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
238 uint64_t read_offset
= betoh(tmp
);
240 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
241 uint32_t read_size
= betoh(tmpsize
);
243 scsi_out
.msgSize
= read_size
* blkSize
;
244 scsi_out
.offset
= read_offset
* blkSize
;
246 if ((read_offset
+ read_size
) > diskSize
)
247 scsi_out
.status
= SCSIIllegalRequest
;
249 DPRINTF(UFSHostDevice
, "Read10 offset: 0x%8x, for %d blocks\n",
250 read_offset
, read_size
);
253 * Renew status check, for the request may have been illegal
255 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
256 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
257 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
263 scsi_out
.expectMore
= 0x02;
264 scsi_out
.msgSize
= 0;
266 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
268 /**BE and not nicely aligned.*/
269 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
270 uint64_t read_offset
= betoh(tmp
);
272 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[6]);
273 read_offset
= (read_offset
<< 32) | betoh(tmp
);
275 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[10]);
276 uint32_t read_size
= betoh(tmp
);
278 scsi_out
.msgSize
= read_size
* blkSize
;
279 scsi_out
.offset
= read_offset
* blkSize
;
281 if ((read_offset
+ read_size
) > diskSize
)
282 scsi_out
.status
= SCSIIllegalRequest
;
284 DPRINTF(UFSHostDevice
, "Read16 offset: 0x%8x, for %d blocks\n",
285 read_offset
, read_size
);
288 * Renew status check, for the request may have been illegal
290 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
291 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
292 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
297 case SCSIReadCapacity10
: {
299 * read the capacity of the device
301 scsi_out
.msgSize
= 8;
302 scsi_out
.message
.dataMsg
.resize(2);
303 scsi_out
.message
.dataMsg
[0] =
304 betoh(capacityLower
);//last block
305 scsi_out
.message
.dataMsg
[1] = betoh(blkSize
);//blocksize
308 case SCSIReadCapacity16
: {
309 scsi_out
.msgSize
= 32;
310 scsi_out
.message
.dataMsg
.resize(8);
311 scsi_out
.message
.dataMsg
[0] =
312 betoh(capacityUpper
);//last block
313 scsi_out
.message
.dataMsg
[1] =
314 betoh(capacityLower
);//last block
315 scsi_out
.message
.dataMsg
[2] = betoh(blkSize
);//blocksize
316 scsi_out
.message
.dataMsg
[3] = 0x00;//
317 scsi_out
.message
.dataMsg
[4] = 0x00;//reserved
318 scsi_out
.message
.dataMsg
[5] = 0x00;//reserved
319 scsi_out
.message
.dataMsg
[6] = 0x00;//reserved
320 scsi_out
.message
.dataMsg
[7] = 0x00;//reserved
324 case SCSIReportLUNs
: {
326 * Find out how many Logic Units this device has.
328 scsi_out
.msgSize
= (lunAvail
* 8) + 8;//list + overhead
329 scsi_out
.message
.dataMsg
.resize(2 * lunAvail
+ 2);
330 scsi_out
.message
.dataMsg
[0] = (lunAvail
* 8) << 24;//LUN listlength
331 scsi_out
.message
.dataMsg
[1] = 0x00;
333 for (uint8_t count
= 0; count
< lunAvail
; count
++) {
335 scsi_out
.message
.dataMsg
[2 + 2 * count
] = (count
& 0x7F) << 8;
336 scsi_out
.message
.dataMsg
[3 + 2 * count
] = 0x00;
341 case SCSIStartStop
: {
342 //Just acknowledge; not deemed relevant ATM
343 scsi_out
.msgSize
= 0;
347 case SCSITestUnitReady
: {
348 //Just acknowledge; not deemed relevant ATM
349 scsi_out
.msgSize
= 0;
355 * See if the blocks that the host plans to request are in range of
358 scsi_out
.msgSize
= 0;
360 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
362 /**BE and not nicely aligned.*/
363 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
364 uint64_t read_offset
= betoh(tmp
);
366 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
367 uint32_t read_size
= betoh(tmpsize
);
369 if ((read_offset
+ read_size
) > diskSize
)
370 scsi_out
.status
= SCSIIllegalRequest
;
373 * Renew status check, for the request may have been illegal
375 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
376 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
377 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
387 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
389 /**BE and not nicely aligned. Apart from that it only has
390 * information in five bits of the first byte that is relevant
393 uint32_t tmp
= *reinterpret_cast<uint32_t*>(tempptr
);
394 uint64_t write_offset
= betoh(tmp
) & 0x1FFFFF;
396 uint32_t write_size
= tempptr
[4];
398 scsi_out
.msgSize
= write_size
* blkSize
;
399 scsi_out
.offset
= write_offset
* blkSize
;
400 scsi_out
.expectMore
= 0x01;
402 if ((write_offset
+ write_size
) > diskSize
)
403 scsi_out
.status
= SCSIIllegalRequest
;
405 DPRINTF(UFSHostDevice
, "Write6 offset: 0x%8x, for %d blocks\n",
406 write_offset
, write_size
);
409 * Renew status check, for the request may have been illegal
411 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
412 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
413 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
419 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
421 /**BE and not nicely aligned.*/
422 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
423 uint64_t write_offset
= betoh(tmp
);
425 uint16_t tmpsize
= *reinterpret_cast<uint16_t*>(&tempptr
[7]);
426 uint32_t write_size
= betoh(tmpsize
);
428 scsi_out
.msgSize
= write_size
* blkSize
;
429 scsi_out
.offset
= write_offset
* blkSize
;
430 scsi_out
.expectMore
= 0x01;
432 if ((write_offset
+ write_size
) > diskSize
)
433 scsi_out
.status
= SCSIIllegalRequest
;
435 DPRINTF(UFSHostDevice
, "Write10 offset: 0x%8x, for %d blocks\n",
436 write_offset
, write_size
);
439 * Renew status check, for the request may have been illegal
441 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
442 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
443 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
449 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
451 /**BE and not nicely aligned.*/
452 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
453 uint64_t write_offset
= betoh(tmp
);
455 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[6]);
456 write_offset
= (write_offset
<< 32) | betoh(tmp
);
458 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[10]);
459 uint32_t write_size
= betoh(tmp
);
461 scsi_out
.msgSize
= write_size
* blkSize
;
462 scsi_out
.offset
= write_offset
* blkSize
;
463 scsi_out
.expectMore
= 0x01;
465 if ((write_offset
+ write_size
) > diskSize
)
466 scsi_out
.status
= SCSIIllegalRequest
;
468 DPRINTF(UFSHostDevice
, "Write16 offset: 0x%8x, for %d blocks\n",
469 write_offset
, write_size
);
472 * Renew status check, for the request may have been illegal
474 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
475 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
476 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
481 case SCSIFormatUnit
: {//not yet verified
482 scsi_out
.msgSize
= 0;
483 scsi_out
.expectMore
= 0x01;
487 case SCSISendDiagnostic
: {//not yet verified
488 scsi_out
.msgSize
= 0;
492 case SCSISynchronizeCache
: {
493 //do we have cache (we don't have cache at this moment)
494 //TODO: here will synchronization happen when cache is modelled
495 scsi_out
.msgSize
= 0;
499 //UFS SCSI additional command set for full functionality
500 case SCSIModeSelect10
:
502 //scsi_out.expectMore = 0x01;//not supported due to modepage support
503 //code isn't dead, code suggest what is to be done when implemented
506 case SCSIModeSense6
: case SCSIModeSense10
: {
508 * Get more discriptive information about the SCSI functionality
509 * within this logic unit.
511 if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x0A) {//control page
512 scsi_out
.message
.dataMsg
.resize((sizeof(controlPage
) >> 2) + 2);
513 scsi_out
.message
.dataMsg
[0] = 0x00000A00;//control page code
514 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
516 for (uint8_t count
= 0; count
< 3; count
++)
517 scsi_out
.message
.dataMsg
[2 + count
] = controlPage
[count
];
519 scsi_out
.msgSize
= 20;
520 DPRINTF(UFSHostDevice
, "CONTROL page\n");
522 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
523 scsi_out
.message
.dataMsg
.resize((sizeof(recoveryPage
) >> 2)
526 scsi_out
.message
.dataMsg
[0] = 0x00000100;//recovery page code
527 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
529 for (uint8_t count
= 0; count
< 3; count
++)
530 scsi_out
.message
.dataMsg
[2 + count
] = recoveryPage
[count
];
532 scsi_out
.msgSize
= 20;
533 DPRINTF(UFSHostDevice
, "RECOVERY page\n");
535 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x08) {//caching page
537 scsi_out
.message
.dataMsg
.resize((sizeof(cachingPage
) >> 2) + 2);
538 scsi_out
.message
.dataMsg
[0] = 0x00001200;//caching page code
539 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
541 for (uint8_t count
= 0; count
< 5; count
++)
542 scsi_out
.message
.dataMsg
[2 + count
] = cachingPage
[count
];
544 scsi_out
.msgSize
= 20;
545 DPRINTF(UFSHostDevice
, "CACHE page\n");
547 } else if ((SCSI_msg
[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
549 scsi_out
.message
.dataMsg
.resize(((sizeof(controlPage
) +
550 sizeof(recoveryPage
) +
551 sizeof(cachingPage
)) >> 2)
553 scsi_out
.message
.dataMsg
[0] = 0x00003200;//all page code
554 scsi_out
.message
.dataMsg
[1] = 0x00000000;//See JEDEC220 ch8
556 for (uint8_t count
= 0; count
< 3; count
++)
557 scsi_out
.message
.dataMsg
[2 + count
] = recoveryPage
[count
];
559 for (uint8_t count
= 0; count
< 5; count
++)
560 scsi_out
.message
.dataMsg
[5 + count
] = cachingPage
[count
];
562 for (uint8_t count
= 0; count
< 3; count
++)
563 scsi_out
.message
.dataMsg
[10 + count
] = controlPage
[count
];
565 scsi_out
.msgSize
= 52;
566 DPRINTF(UFSHostDevice
, "Return ALL the pages!!!\n");
568 } else inform("Wrong mode page requested\n");
570 scsi_out
.message
.dataCount
= scsi_out
.msgSize
<< 24;
573 case SCSIRequestSense
: {
574 scsi_out
.msgSize
= 0;
578 case SCSIUnmap
:break;//not yet verified
580 case SCSIWriteBuffer
: {
581 scsi_out
.expectMore
= 0x01;
583 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
585 /**BE and not nicely aligned.*/
586 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
587 uint64_t write_offset
= betoh(tmp
) & 0xFFFFFF;
589 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[5]);
590 uint32_t write_size
= betoh(tmp
) & 0xFFFFFF;
592 scsi_out
.msgSize
= write_size
;
593 scsi_out
.offset
= write_offset
;
597 case SCSIReadBuffer
: {
599 * less trivial than normal read. Size is in bytes instead
600 * of blocks, and it is assumed (though not guaranteed) that
601 * reading is from cache.
603 scsi_out
.expectMore
= 0x02;
605 uint8_t* tempptr
= reinterpret_cast<uint8_t*>(&SCSI_msg
[4]);
607 /**BE and not nicely aligned.*/
608 uint32_t tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[2]);
609 uint64_t read_offset
= betoh(tmp
) & 0xFFFFFF;
611 tmp
= *reinterpret_cast<uint32_t*>(&tempptr
[5]);
612 uint32_t read_size
= betoh(tmp
) & 0xFFFFFF;
614 scsi_out
.msgSize
= read_size
;
615 scsi_out
.offset
= read_offset
;
617 if ((read_offset
+ read_size
) > capacityLower
* blkSize
)
618 scsi_out
.status
= SCSIIllegalRequest
;
620 DPRINTF(UFSHostDevice
, "Read buffer location: 0x%8x\n",
622 DPRINTF(UFSHostDevice
, "Number of bytes: 0x%8x\n", read_size
);
624 statusCheck(scsi_out
.status
, scsi_out
.senseCode
);
625 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
626 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
631 case SCSIMaintenanceIn
: {
633 * linux sends this command three times from kernel 3.9 onwards,
634 * UFS does not support it, nor does this model. Linux knows this,
635 * but tries anyway (useful for some SD card types).
636 * Lets make clear we don't want it and just ignore it.
638 DPRINTF(UFSHostDevice
, "Ignoring Maintenance In command\n");
639 statusCheck(SCSIIllegalRequest
, scsi_out
.senseCode
);
640 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
641 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
643 scsi_out
.msgSize
= 0;
647 statusCheck(SCSIIllegalRequest
, scsi_out
.senseCode
);
648 scsi_out
.senseSize
= scsi_out
.senseCode
[0];
649 scsi_out
.status
= (scsi_out
.status
== SCSIGood
) ? SCSIGood
:
651 scsi_out
.msgSize
= 0;
652 inform("Unsupported scsi message type: %2x\n", SCSI_msg
[4] & 0xFF);
653 inform("0x%8x\n", SCSI_msg
[0]);
654 inform("0x%8x\n", SCSI_msg
[1]);
655 inform("0x%8x\n", SCSI_msg
[2]);
656 inform("0x%8x\n", SCSI_msg
[3]);
657 inform("0x%8x\n", SCSI_msg
[4]);
665 * SCSI status check function. generic device test, creates sense codes
666 * Future versions may include TODO: device checks, which is why this is
667 * in a separate function.
671 UFSHostDevice::UFSSCSIDevice::statusCheck(uint8_t status
,
672 uint8_t* sensecodelist
)
674 for (uint8_t count
= 0; count
< 19; count
++)
675 sensecodelist
[count
] = 0;
677 sensecodelist
[0] = 18; //sense length
678 sensecodelist
[1] = 0x70; //we send a valid frame
679 sensecodelist
[3] = status
& 0xF; //mask to be sure + sensecode
680 sensecodelist
[8] = 0x1F; //data length
684 * read from the flashdisk
688 UFSHostDevice::UFSSCSIDevice::readFlash(uint8_t* readaddr
, uint64_t offset
,
691 /** read from image, and get to memory */
692 for (int count
= 0; count
< (size
/ SectorSize
); count
++)
693 flashDisk
->read(&(readaddr
[SectorSize
*count
]), (offset
/
694 SectorSize
) + count
);
698 * Write to the flashdisk
702 UFSHostDevice::UFSSCSIDevice::writeFlash(uint8_t* writeaddr
, uint64_t offset
,
705 /** Get from fifo and write to image*/
706 for (int count
= 0; count
< (size
/ SectorSize
); count
++)
707 flashDisk
->write(&(writeaddr
[SectorSize
* count
]),
708 (offset
/ SectorSize
) + count
);
712 * Constructor for the UFS Host device
715 UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams
&p
) :
719 pioDelay(p
.pio_latency
),
722 lunAvail(p
.image
.size()),
723 UFSSlots(p
.ufs_slots
- 1),
733 SCSIResumeEvent([this]{ SCSIStart(); }, name()),
734 UTPEvent([this]{ finalUTP(); }, name())
736 DPRINTF(UFSHostDevice
, "The hostcontroller hosts %d Logic units\n",
738 UFSDevice
.resize(lunAvail
);
740 for (int count
= 0; count
< lunAvail
; count
++) {
741 UFSDevice
[count
] = new UFSSCSIDevice(p
, count
,
742 [this]() { LUNSignal(); },
743 [this]() { readCallback(); });
747 warn("UFSSlots = %d, this will results in %d command slots",
748 UFSSlots
, (UFSSlots
& 0x1F));
750 if ((UFSSlots
& 0x1F) == 0)
751 fatal("Number of UFS command slots should be between 1 and 32.");
757 UFSHostDeviceStats::UFSHostDeviceStats(UFSHostDevice
*parent
)
758 : Stats::Group(parent
, "UFSDiskHost"),
759 ADD_STAT(currentSCSIQueue
, UNIT_COUNT
,
760 "Most up to date length of the command queue"),
761 ADD_STAT(currentReadSSDQueue
, UNIT_COUNT
,
762 "Most up to date length of the read SSD queue"),
763 ADD_STAT(currentWriteSSDQueue
, UNIT_COUNT
,
764 "Most up to date length of the write SSD queue"),
765 /** Amount of data read/written */
766 ADD_STAT(totalReadSSD
, UNIT_BYTE
,
767 "Number of bytes read from SSD"),
768 ADD_STAT(totalWrittenSSD
, UNIT_BYTE
,
769 "Number of bytes written to SSD"),
770 ADD_STAT(totalReadDiskTransactions
, UNIT_COUNT
,
771 "Number of transactions from disk"),
772 ADD_STAT(totalWriteDiskTransactions
, UNIT_COUNT
,
773 "Number of transactions to disk"),
774 ADD_STAT(totalReadUFSTransactions
, UNIT_COUNT
,
775 "Number of transactions from device"),
776 ADD_STAT(totalWriteUFSTransactions
, UNIT_COUNT
,
777 "Number of transactions to device"),
778 /** Average bandwidth for reads and writes */
779 ADD_STAT(averageReadSSDBW
,
780 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
781 "Average read bandwidth",
782 totalReadSSD
/ simSeconds
),
783 ADD_STAT(averageWriteSSDBW
,
784 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
785 "Average write bandwidth",
786 totalWrittenSSD
/ simSeconds
),
787 ADD_STAT(averageSCSIQueue
,
788 UNIT_RATE(Stats::Units::Count
, Stats::Units::Tick
),
789 "Average command queue length"),
790 ADD_STAT(averageReadSSDQueue
,
791 UNIT_RATE(Stats::Units::Count
, Stats::Units::Tick
),
792 "Average read queue length"),
793 ADD_STAT(averageWriteSSDQueue
,
794 UNIT_RATE(Stats::Units::Count
, Stats::Units::Tick
),
795 "Average write queue length"),
796 /** Number of doorbells rung*/
797 ADD_STAT(curDoorbell
, UNIT_COUNT
,
798 "Most up to date number of doorbells used",
799 parent
->activeDoorbells
),
800 ADD_STAT(maxDoorbell
, UNIT_COUNT
,
801 "Maximum number of doorbells utilized"),
802 ADD_STAT(averageDoorbell
,
803 UNIT_RATE(Stats::Units::Count
, Stats::Units::Tick
),
804 "Average number of Doorbells used"),
806 ADD_STAT(transactionLatency
, UNIT_TICK
,
807 "Histogram of transaction times"),
808 ADD_STAT(idleTimes
, UNIT_TICK
, "Histogram of idle times")
810 using namespace Stats
;
812 // Register the stats
821 /** Amount of data read/written */
828 totalReadDiskTransactions
830 totalWriteDiskTransactions
832 totalReadUFSTransactions
834 totalWriteUFSTransactions
837 /** Average bandwidth for reads and writes */
851 /** Number of doorbells rung*/
873 void UFSHostDevice::setValues()
876 * The capability register is built up as follows:
877 * 31-29 RES; Testmode support; O3 delivery; 64 bit addr;
878 * 23-19 RES; 18-16 #TM Req slots; 15-5 RES;4-0 # TR slots
880 UFSHCIMem
.HCCAP
= 0x06070000 | (UFSSlots
& 0x1F);
881 UFSHCIMem
.HCversion
= 0x00010000; //version is 1.0
882 UFSHCIMem
.HCHCDDID
= 0xAA003C3C;// Arbitrary number
883 UFSHCIMem
.HCHCPMID
= 0x41524D48; //ARMH (not an official MIPI number)
884 UFSHCIMem
.TRUTRLDBR
= 0x00;
885 UFSHCIMem
.TMUTMRLDBR
= 0x00;
886 UFSHCIMem
.CMDUICCMDR
= 0x00;
887 // We can process CMD, TM, TR, device present
888 UFSHCIMem
.ORHostControllerStatus
= 0x08;
889 UFSHCIMem
.TRUTRLBA
= 0x00;
890 UFSHCIMem
.TRUTRLBAU
= 0x00;
891 UFSHCIMem
.TMUTMRLBA
= 0x00;
892 UFSHCIMem
.TMUTMRLBAU
= 0x00;
896 * Determine address ranges
900 UFSHostDevice::getAddrRanges() const
902 AddrRangeList ranges
;
903 ranges
.push_back(RangeSize(pioAddr
, pioSize
));
908 * UFSHCD read register. This function allows the system to read the
913 UFSHostDevice::read(PacketPtr pkt
)
917 switch (pkt
->getAddr() & 0xFF)
920 case regControllerCapabilities
:
921 data
= UFSHCIMem
.HCCAP
;
925 data
= UFSHCIMem
.HCversion
;
928 case regControllerDEVID
:
929 data
= UFSHCIMem
.HCHCDDID
;
932 case regControllerPRODID
:
933 data
= UFSHCIMem
.HCHCPMID
;
936 case regInterruptStatus
:
937 data
= UFSHCIMem
.ORInterruptStatus
;
938 UFSHCIMem
.ORInterruptStatus
= 0x00;
939 //TODO: Revise and extend
943 case regInterruptEnable
:
944 data
= UFSHCIMem
.ORInterruptEnable
;
947 case regControllerStatus
:
948 data
= UFSHCIMem
.ORHostControllerStatus
;
951 case regControllerEnable
:
952 data
= UFSHCIMem
.ORHostControllerEnable
;
955 case regUICErrorCodePHYAdapterLayer
:
956 data
= UFSHCIMem
.ORUECPA
;
959 case regUICErrorCodeDataLinkLayer
:
960 data
= UFSHCIMem
.ORUECDL
;
963 case regUICErrorCodeNetworkLayer
:
964 data
= UFSHCIMem
.ORUECN
;
967 case regUICErrorCodeTransportLayer
:
968 data
= UFSHCIMem
.ORUECT
;
971 case regUICErrorCodeDME
:
972 data
= UFSHCIMem
.ORUECDME
;
975 case regUTPTransferREQINTAGGControl
:
976 data
= UFSHCIMem
.ORUTRIACR
;
979 case regUTPTransferREQListBaseL
:
980 data
= UFSHCIMem
.TRUTRLBA
;
983 case regUTPTransferREQListBaseH
:
984 data
= UFSHCIMem
.TRUTRLBAU
;
987 case regUTPTransferREQDoorbell
:
988 data
= UFSHCIMem
.TRUTRLDBR
;
991 case regUTPTransferREQListClear
:
992 data
= UFSHCIMem
.TRUTRLCLR
;
995 case regUTPTransferREQListRunStop
:
996 data
= UFSHCIMem
.TRUTRLRSR
;
999 case regUTPTaskREQListBaseL
:
1000 data
= UFSHCIMem
.TMUTMRLBA
;
1003 case regUTPTaskREQListBaseH
:
1004 data
= UFSHCIMem
.TMUTMRLBAU
;
1007 case regUTPTaskREQDoorbell
:
1008 data
= UFSHCIMem
.TMUTMRLDBR
;
1011 case regUTPTaskREQListClear
:
1012 data
= UFSHCIMem
.TMUTMRLCLR
;
1015 case regUTPTaskREQListRunStop
:
1016 data
= UFSHCIMem
.TMUTMRLRSR
;
1020 data
= UFSHCIMem
.CMDUICCMDR
;
1023 case regUICCommandArg1
:
1024 data
= UFSHCIMem
.CMDUCMDARG1
;
1027 case regUICCommandArg2
:
1028 data
= UFSHCIMem
.CMDUCMDARG2
;
1031 case regUICCommandArg3
:
1032 data
= UFSHCIMem
.CMDUCMDARG3
;
1040 pkt
->setLE
<uint32_t>(data
);
1041 pkt
->makeResponse();
1046 * UFSHCD write function. This function allows access to the writeable
1047 * registers. If any function attempts to write value to an unwriteable
1048 * register entry, then the value will not be written.
1051 UFSHostDevice::write(PacketPtr pkt
)
1053 assert(pkt
->getSize() <= 4);
1055 const uint32_t data
= pkt
->getUintX(ByteOrder::little
);
1057 switch (pkt
->getAddr() & 0xFF)
1059 case regControllerCapabilities
://you shall not write to this
1062 case regUFSVersion
://you shall not write to this
1065 case regControllerDEVID
://you shall not write to this
1068 case regControllerPRODID
://you shall not write to this
1071 case regInterruptStatus
://you shall not write to this
1074 case regInterruptEnable
:
1075 UFSHCIMem
.ORInterruptEnable
= data
;
1078 case regControllerStatus
:
1079 UFSHCIMem
.ORHostControllerStatus
= data
;
1082 case regControllerEnable
:
1083 UFSHCIMem
.ORHostControllerEnable
= data
;
1086 case regUICErrorCodePHYAdapterLayer
:
1087 UFSHCIMem
.ORUECPA
= data
;
1090 case regUICErrorCodeDataLinkLayer
:
1091 UFSHCIMem
.ORUECDL
= data
;
1094 case regUICErrorCodeNetworkLayer
:
1095 UFSHCIMem
.ORUECN
= data
;
1098 case regUICErrorCodeTransportLayer
:
1099 UFSHCIMem
.ORUECT
= data
;
1102 case regUICErrorCodeDME
:
1103 UFSHCIMem
.ORUECDME
= data
;
1106 case regUTPTransferREQINTAGGControl
:
1107 UFSHCIMem
.ORUTRIACR
= data
;
1110 case regUTPTransferREQListBaseL
:
1111 UFSHCIMem
.TRUTRLBA
= data
;
1112 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1113 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
)!= 0x00))
1114 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1117 case regUTPTransferREQListBaseH
:
1118 UFSHCIMem
.TRUTRLBAU
= data
;
1119 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1120 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1121 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1124 case regUTPTransferREQDoorbell
:
1125 if (!(UFSHCIMem
.TRUTRLDBR
) && data
)
1126 stats
.idleTimes
.sample(curTick() - idlePhaseStart
);
1127 UFSHCIMem
.TRUTRLDBR
|= data
;
1131 case regUTPTransferREQListClear
:
1132 UFSHCIMem
.TRUTRLCLR
= data
;
1135 case regUTPTransferREQListRunStop
:
1136 UFSHCIMem
.TRUTRLRSR
= data
;
1139 case regUTPTaskREQListBaseL
:
1140 UFSHCIMem
.TMUTMRLBA
= data
;
1141 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1142 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1143 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1146 case regUTPTaskREQListBaseH
:
1147 UFSHCIMem
.TMUTMRLBAU
= data
;
1148 if (((UFSHCIMem
.TRUTRLBA
| UFSHCIMem
.TRUTRLBAU
) != 0x00) &&
1149 ((UFSHCIMem
.TMUTMRLBA
| UFSHCIMem
.TMUTMRLBAU
) != 0x00))
1150 UFSHCIMem
.ORHostControllerStatus
|= UICCommandReady
;
1153 case regUTPTaskREQDoorbell
:
1154 UFSHCIMem
.TMUTMRLDBR
|= data
;
1158 case regUTPTaskREQListClear
:
1159 UFSHCIMem
.TMUTMRLCLR
= data
;
1162 case regUTPTaskREQListRunStop
:
1163 UFSHCIMem
.TMUTMRLRSR
= data
;
1167 UFSHCIMem
.CMDUICCMDR
= data
;
1171 case regUICCommandArg1
:
1172 UFSHCIMem
.CMDUCMDARG1
= data
;
1175 case regUICCommandArg2
:
1176 UFSHCIMem
.CMDUCMDARG2
= data
;
1179 case regUICCommandArg3
:
1180 UFSHCIMem
.CMDUCMDARG3
= data
;
1183 default:break;//nothing happens, you try to access a register that
1188 pkt
->makeResponse();
1193 * Request handler. Determines where the request comes from and initiates the
1194 * appropriate actions accordingly.
1198 UFSHostDevice::requestHandler()
1200 Addr address
= 0x00;
1204 struct taskStart task_info
;
1205 struct transferStart transferstart_info
;
1206 transferstart_info
.done
= 0;
1209 * step1 determine what called us
1210 * step2 determine where to get it
1211 * Look for any request of which we where not yet aware
1213 while (((UFSHCIMem
.CMDUICCMDR
> 0x00) |
1214 ((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
) > 0x00) |
1215 ((UFSHCIMem
.TRUTRLDBR
^ transferTrack
) > 0x00)) ) {
1217 if (UFSHCIMem
.CMDUICCMDR
> 0x00) {
1219 * Command; general control of the Host controller.
1220 * no DMA transfer needed
1223 UFSHCIMem
.ORInterruptStatus
|= UICCommandCOMPL
;
1224 generateInterrupt();
1225 UFSHCIMem
.CMDUICCMDR
= 0x00;
1226 return; //command, nothing more we can do
1228 } else if ((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
) > 0x00) {
1230 * Task; flow control, meant for the device/Logic unit
1231 * DMA transfer is needed, flash will not be approached
1233 size
= sizeof(UTPUPIUTaskReq
);
1234 /**Find the position that is not handled yet*/
1235 count
= findLsbSet((UFSHCIMem
.TMUTMRLDBR
^ taskCommandTrack
));
1236 address
= UFSHCIMem
.TMUTMRLBAU
;
1238 address
= (count
* size
) + (address
<< 32) +
1239 UFSHCIMem
.TMUTMRLBA
;
1240 taskCommandTrack
|= mask
<< count
;
1242 inform("UFSmodel received a task from the system; this might"
1243 " lead to untested behaviour.\n");
1245 task_info
.mask
= mask
<< count
;
1246 task_info
.address
= address
;
1247 task_info
.size
= size
;
1248 task_info
.done
= UFSHCIMem
.TMUTMRLDBR
;
1249 taskInfo
.push_back(task_info
);
1250 taskEventQueue
.push_back(
1251 EventFunctionWrapper([this]{ taskStart(); }, name()));
1252 writeDevice(&taskEventQueue
.back(), false, address
, size
,
1253 reinterpret_cast<uint8_t*>
1254 (&taskInfo
.back().destination
), 0, 0);
1256 } else if ((UFSHCIMem
.TRUTRLDBR
^ transferTrack
) > 0x00) {
1258 * Transfer; Data transfer from or to the disk. There will be DMA
1259 * transfers, and the flash might be approached. Further
1260 * commands, are needed to specify the exact command.
1262 size
= sizeof(UTPTransferReqDesc
);
1263 /**Find the position that is not handled yet*/
1264 count
= findLsbSet((UFSHCIMem
.TRUTRLDBR
^ transferTrack
));
1265 address
= UFSHCIMem
.TRUTRLBAU
;
1267 address
= (count
* size
) + (address
<< 32) + UFSHCIMem
.TRUTRLBA
;
1269 transferTrack
|= mask
<< count
;
1270 DPRINTF(UFSHostDevice
, "Doorbell register: 0x%8x select #:"
1271 " 0x%8x completion info: 0x%8x\n", UFSHCIMem
.TRUTRLDBR
,
1272 count
, transferstart_info
.done
);
1274 transferstart_info
.done
= UFSHCIMem
.TRUTRLDBR
;
1277 transactionStart
[count
] = curTick(); //note the start time
1279 stats
.maxDoorbell
= (stats
.maxDoorbell
.value() < activeDoorbells
)
1280 ? activeDoorbells
: stats
.maxDoorbell
.value();
1281 stats
.averageDoorbell
= stats
.maxDoorbell
.value();
1284 * step3 start transfer
1285 * step4 register information; allowing the host to respond in
1288 transferstart_info
.mask
= mask
<< count
;
1289 transferstart_info
.address
= address
;
1290 transferstart_info
.size
= size
;
1291 transferstart_info
.done
= UFSHCIMem
.TRUTRLDBR
;
1292 transferStartInfo
.push_back(transferstart_info
);
1294 /**Deleted in readDone, queued in finalUTP*/
1295 transferStartInfo
.back().destination
= new struct
1297 DPRINTF(UFSHostDevice
, "Initial transfer start: 0x%8x\n",
1298 transferstart_info
.done
);
1299 transferEventQueue
.push_back(
1300 EventFunctionWrapper([this]{ transferStart(); }, name()));
1302 if (transferEventQueue
.size() < 2) {
1303 writeDevice(&transferEventQueue
.front(), false,
1304 address
, size
, reinterpret_cast<uint8_t*>
1305 (transferStartInfo
.front().destination
),0, 0);
1306 DPRINTF(UFSHostDevice
, "Transfer scheduled\n");
1317 UFSHostDevice::taskStart()
1319 DPRINTF(UFSHostDevice
, "Task start");
1320 taskHandler(&taskInfo
.front().destination
, taskInfo
.front().mask
,
1321 taskInfo
.front().address
, taskInfo
.front().size
);
1322 taskInfo
.pop_front();
1323 taskEventQueue
.pop_front();
1327 * Transfer start event
1331 UFSHostDevice::transferStart()
1333 DPRINTF(UFSHostDevice
, "Enter transfer event\n");
1334 transferHandler(transferStartInfo
.front().destination
,
1335 transferStartInfo
.front().mask
,
1336 transferStartInfo
.front().address
,
1337 transferStartInfo
.front().size
,
1338 transferStartInfo
.front().done
);
1340 transferStartInfo
.pop_front();
1341 DPRINTF(UFSHostDevice
, "Transfer queue size at end of event: "
1342 "0x%8x\n", transferEventQueue
.size());
1346 * Handles the commands that are given. At this point in time, not many
1347 * commands have been implemented in the driver.
1351 UFSHostDevice::commandHandler()
1353 if (UFSHCIMem
.CMDUICCMDR
== 0x16) {
1354 UFSHCIMem
.ORHostControllerStatus
|= 0x0F;//link startup
1360 * Handles the tasks that are given. At this point in time, not many tasks
1361 * have been implemented in the driver.
1365 UFSHostDevice::taskHandler(struct UTPUPIUTaskReq
* request_in
,
1366 uint32_t req_pos
, Addr finaladdress
, uint32_t
1370 * For now, just unpack and acknowledge the task without doing anything.
1371 * TODO Implement UFS tasks.
1373 inform("taskHandler\n");
1374 inform("%8x\n", request_in
->header
.dWord0
);
1375 inform("%8x\n", request_in
->header
.dWord1
);
1376 inform("%8x\n", request_in
->header
.dWord2
);
1378 request_in
->header
.dWord2
&= 0xffffff00;
1380 UFSHCIMem
.TMUTMRLDBR
&= ~(req_pos
);
1381 taskCommandTrack
&= ~(req_pos
);
1382 UFSHCIMem
.ORInterruptStatus
|= UTPTaskREQCOMPL
;
1384 readDevice(true, finaladdress
, finalsize
, reinterpret_cast<uint8_t*>
1385 (request_in
), true, NULL
);
1390 * Obtains the SCSI command (if any)
1391 * Two possibilities: if it contains a SCSI command, then it is a usable
1392 * message; if it doesnt contain a SCSI message, then it can't be handeld
1394 * This is the second stage of the transfer. We have the information about
1395 * where the next command can be found and what the type of command is. The
1396 * actions that are needed from the device its side are: get the information
1397 * and store the information such that we can reply.
1401 UFSHostDevice::transferHandler(struct UTPTransferReqDesc
* request_in
,
1402 int req_pos
, Addr finaladdress
, uint32_t
1403 finalsize
, uint32_t done
)
1406 Addr cmd_desc_addr
= 0x00;
1409 //acknowledge handling of the message
1410 DPRINTF(UFSHostDevice
, "SCSI message detected\n");
1411 request_in
->header
.dWord2
&= 0xffffff00;
1412 SCSIInfo
.RequestIn
= request_in
;
1413 SCSIInfo
.reqPos
= req_pos
;
1414 SCSIInfo
.finalAddress
= finaladdress
;
1415 SCSIInfo
.finalSize
= finalsize
;
1416 SCSIInfo
.destination
.resize(request_in
->PRDTableOffset
* 4
1417 + request_in
->PRDTableLength
* sizeof(UFSHCDSGEntry
));
1418 SCSIInfo
.done
= done
;
1420 assert(!SCSIResumeEvent
.scheduled());
1422 *Get the UTP command that has the SCSI command
1424 cmd_desc_addr
= request_in
->commandDescBaseAddrHi
;
1425 cmd_desc_addr
= (cmd_desc_addr
<< 32) |
1426 (request_in
->commandDescBaseAddrLo
& 0xffffffff);
1428 writeDevice(&SCSIResumeEvent
, false, cmd_desc_addr
,
1429 SCSIInfo
.destination
.size(), &SCSIInfo
.destination
[0],0, 0);
1431 DPRINTF(UFSHostDevice
, "SCSI scheduled\n");
1433 transferEventQueue
.pop_front();
1437 * Obtain LUN and put it in the right LUN queue. Each LUN has its own queue
1438 * of commands that need to be executed. This is the first instance where it
1439 * can be determined which Logic unit should handle the transfer. Then check
1440 * wether it should wait and queue or if it can continue.
1444 UFSHostDevice::SCSIStart()
1446 DPRINTF(UFSHostDevice
, "SCSI message on hold until ready\n");
1447 uint32_t LUN
= SCSIInfo
.destination
[2];
1448 UFSDevice
[LUN
]->SCSIInfoQueue
.push_back(SCSIInfo
);
1450 DPRINTF(UFSHostDevice
, "SCSI queue %d has %d elements\n", LUN
,
1451 UFSDevice
[LUN
]->SCSIInfoQueue
.size());
1453 /**There are 32 doorbells, so at max there can be 32 transactions*/
1454 if (UFSDevice
[LUN
]->SCSIInfoQueue
.size() < 2) //LUN is available
1457 else if (UFSDevice
[LUN
]->SCSIInfoQueue
.size() > 32)
1458 panic("SCSI queue is getting too big %d\n", UFSDevice
[LUN
]->
1459 SCSIInfoQueue
.size());
1462 * First transfer is done, fetch the next;
1463 * At this point, the device is busy, not the HC
1465 if (!transferEventQueue
.empty()) {
1468 * loading next data packet in case Another LUN
1469 * is approached in the mean time
1471 writeDevice(&transferEventQueue
.front(), false,
1472 transferStartInfo
.front().address
,
1473 transferStartInfo
.front().size
, reinterpret_cast<uint8_t*>
1474 (transferStartInfo
.front().destination
), 0, 0);
1476 DPRINTF(UFSHostDevice
, "Transfer scheduled");
1481 * Handles the transfer requests that are given.
1482 * There can be three types of transfer. SCSI specific, Reads and writes
1483 * apart from the data transfer, this also generates its own reply (UPIU
1484 * response). Information for this reply is stored in transferInfo and will
1485 * be used in transferDone
1489 UFSHostDevice::SCSIResume(uint32_t lun_id
)
1491 DPRINTF(UFSHostDevice
, "SCSIresume\n");
1492 if (UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1493 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id
,
1494 UFSHCIMem
.TRUTRLDBR
);
1496 /**old info, lets form it such that we can understand it*/
1497 struct UTPTransferReqDesc
* request_in
= UFSDevice
[lun_id
]->
1498 SCSIInfoQueue
.front().RequestIn
;
1500 uint32_t req_pos
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().reqPos
;
1502 Addr finaladdress
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().
1505 uint32_t finalsize
= UFSDevice
[lun_id
]->SCSIInfoQueue
.front().finalSize
;
1507 uint32_t* transfercommand
= reinterpret_cast<uint32_t*>
1508 (&(UFSDevice
[lun_id
]->SCSIInfoQueue
.front().destination
[0]));
1510 DPRINTF(UFSHostDevice
, "Task tag: 0x%8x\n", transfercommand
[0]>>24);
1511 /**call logic unit to handle SCSI command*/
1512 request_out_datain
= UFSDevice
[(transfercommand
[0] & 0xFF0000) >> 16]->
1513 SCSICMDHandle(transfercommand
);
1515 DPRINTF(UFSHostDevice
, "LUN: %d\n", request_out_datain
.LUN
);
1518 * build response stating that it was succesful
1519 * command completion, Logic unit number, and Task tag
1521 request_in
->header
.dWord0
= ((request_in
->header
.dWord0
>> 24) == 0x21)
1523 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord0
=
1524 request_in
->header
.dWord0
| (request_out_datain
.LUN
<< 8)
1525 | (transfercommand
[0] & 0xFF000000);
1526 /**SCSI status reply*/
1527 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord1
= 0x00000000 |
1528 (request_out_datain
.status
<< 24);
1529 /**segment size + EHS length (see UFS standard ch7)*/
1530 UFSDevice
[lun_id
]->transferInfo
.requestOut
.header
.dWord2
= 0x00000000 |
1531 ((request_out_datain
.senseSize
+ 2) << 24) | 0x05;
1532 /**amount of data that will follow*/
1533 UFSDevice
[lun_id
]->transferInfo
.requestOut
.senseDataLen
=
1534 request_out_datain
.senseSize
;
1537 for (uint8_t count
= 0; count
<request_out_datain
.senseSize
; count
++) {
1538 UFSDevice
[lun_id
]->transferInfo
.requestOut
.senseData
[count
] =
1539 request_out_datain
.senseCode
[count
+ 1];
1543 * At position defined by "request_in->PRDTableOffset" (counting 32 bit
1544 * words) in array "transfercommand" we have a scatter gather list, which
1545 * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
1547 struct UFSHCDSGEntry
* sglist
= reinterpret_cast<UFSHCDSGEntry
*>
1548 (&(transfercommand
[(request_in
->PRDTableOffset
)]));
1550 uint32_t length
= request_in
->PRDTableLength
;
1551 DPRINTF(UFSHostDevice
, "# PRDT entries: %d\n", length
);
1553 Addr response_addr
= request_in
->commandDescBaseAddrHi
;
1554 response_addr
= (response_addr
<< 32) |
1555 ((request_in
->commandDescBaseAddrLo
+
1556 (request_in
->responseUPIULength
<< 2)) & 0xffffffff);
1558 /**transferdone information packet filling*/
1559 UFSDevice
[lun_id
]->transferInfo
.responseStartAddr
= response_addr
;
1560 UFSDevice
[lun_id
]->transferInfo
.reqPos
= req_pos
;
1561 UFSDevice
[lun_id
]->transferInfo
.size
= finalsize
;
1562 UFSDevice
[lun_id
]->transferInfo
.address
= finaladdress
;
1563 UFSDevice
[lun_id
]->transferInfo
.destination
= reinterpret_cast<uint8_t*>
1564 (UFSDevice
[lun_id
]->SCSIInfoQueue
.front().RequestIn
);
1565 UFSDevice
[lun_id
]->transferInfo
.finished
= true;
1566 UFSDevice
[lun_id
]->transferInfo
.lunID
= request_out_datain
.LUN
;
1569 * In this part the data that needs to be transfered will be initiated
1570 * and the chain of DMA (and potentially) disk transactions will be
1573 if (request_out_datain
.expectMore
== 0x01) {
1575 manageWriteTransfer(request_out_datain
.LUN
, request_out_datain
.offset
,
1578 } else if (request_out_datain
.expectMore
== 0x02) {
1580 manageReadTransfer(request_out_datain
.msgSize
, request_out_datain
.LUN
,
1581 request_out_datain
.offset
, length
, sglist
);
1584 /**not disk related transfer, SCSI maintanance*/
1586 uint32_t size_accum
= 0;
1587 DPRINTF(UFSHostDevice
, "Data DMA size: 0x%8x\n",
1588 request_out_datain
.msgSize
);
1590 /**Transport the SCSI reponse data according to the SG list*/
1591 while ((length
> count
) && size_accum
1592 < (request_out_datain
.msgSize
- 1) &&
1593 (request_out_datain
.msgSize
!= 0x00)) {
1594 Addr SCSI_start
= sglist
[count
].upperAddr
;
1595 SCSI_start
= (SCSI_start
<< 32) |
1596 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
1597 DPRINTF(UFSHostDevice
, "Data DMA start: 0x%8x\n", SCSI_start
);
1598 DPRINTF(UFSHostDevice
, "Data DMA size: 0x%8x\n",
1599 (sglist
[count
].size
+ 1));
1601 * safetynet; it has been shown that sg list may be optimistic in
1602 * the amount of data allocated, which can potentially lead to
1603 * some garbage data being send over. Hence this construction
1604 * that finds the least amount of data that needs to be
1607 uint32_t size_to_send
= sglist
[count
].size
+ 1;
1609 if (request_out_datain
.msgSize
< (size_to_send
+ size_accum
))
1610 size_to_send
= request_out_datain
.msgSize
- size_accum
;
1612 readDevice(false, SCSI_start
, size_to_send
,
1613 reinterpret_cast<uint8_t*>
1614 (&(request_out_datain
.message
.dataMsg
[size_accum
])),
1617 size_accum
+= size_to_send
;
1618 DPRINTF(UFSHostDevice
, "Total remaining: 0x%8x,accumulated so far"
1619 " : 0x%8x\n", (request_out_datain
.msgSize
- size_accum
),
1623 DPRINTF(UFSHostDevice
, "Transfer #: %d\n", count
);
1626 /**Go to the next stage of the answering process*/
1627 transferDone(response_addr
, req_pos
, UFSDevice
[lun_id
]->
1628 transferInfo
.requestOut
, finalsize
, finaladdress
,
1629 reinterpret_cast<uint8_t*>(request_in
), true, lun_id
);
1632 DPRINTF(UFSHostDevice
, "SCSI resume done\n");
1636 * Find finished transfer. Callback function. One of the LUNs is done with
1637 * the disk transfer and reports back to the controller. This function finds
1638 * out who it was, and calls transferDone.
1641 UFSHostDevice::LUNSignal()
1643 uint8_t this_lun
= 0;
1645 //while we haven't found the right lun, keep searching
1646 while ((this_lun
< lunAvail
) && !UFSDevice
[this_lun
]->finishedCommand())
1649 if (this_lun
< lunAvail
) {
1651 UFSDevice
[this_lun
]->clearSignal();
1652 //found it; call transferDone
1653 transferDone(UFSDevice
[this_lun
]->transferInfo
.responseStartAddr
,
1654 UFSDevice
[this_lun
]->transferInfo
.reqPos
,
1655 UFSDevice
[this_lun
]->transferInfo
.requestOut
,
1656 UFSDevice
[this_lun
]->transferInfo
.size
,
1657 UFSDevice
[this_lun
]->transferInfo
.address
,
1658 UFSDevice
[this_lun
]->transferInfo
.destination
,
1659 UFSDevice
[this_lun
]->transferInfo
.finished
,
1660 UFSDevice
[this_lun
]->transferInfo
.lunID
);
1664 panic("no LUN finished in tick %d\n", curTick());
1668 * Transfer done. When the data transfer is done, this function ensures
1669 * that the application is notified.
1673 UFSHostDevice::transferDone(Addr responseStartAddr
, uint32_t req_pos
,
1674 struct UTPUPIURSP request_out
, uint32_t size
,
1675 Addr address
, uint8_t* destination
,
1676 bool finished
, uint32_t lun_id
)
1678 /**Test whether SCSI queue hasn't popped prematurely*/
1679 if (UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1680 panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id
,
1681 UFSHCIMem
.TRUTRLDBR
);
1683 DPRINTF(UFSHostDevice
, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1684 responseStartAddr
, sizeof(request_out
));
1686 struct transferStart lastinfo
;
1687 lastinfo
.mask
= req_pos
;
1688 lastinfo
.done
= finished
;
1689 lastinfo
.address
= address
;
1690 lastinfo
.size
= size
;
1691 lastinfo
.destination
= reinterpret_cast<UTPTransferReqDesc
*>
1693 lastinfo
.lun_id
= lun_id
;
1695 transferEnd
.push_back(lastinfo
);
1697 DPRINTF(UFSHostDevice
, "Transfer done start\n");
1699 readDevice(false, responseStartAddr
, sizeof(request_out
),
1700 reinterpret_cast<uint8_t*>
1701 (&(UFSDevice
[lun_id
]->transferInfo
.requestOut
)),
1706 * finalUTP. Second part of the transfer done event.
1707 * this sends the final response: the UTP response. After this transaction
1708 * the doorbell shall be cleared, and the interupt shall be set.
1712 UFSHostDevice::finalUTP()
1714 uint32_t lun_id
= transferEnd
.front().lun_id
;
1716 UFSDevice
[lun_id
]->SCSIInfoQueue
.pop_front();
1717 DPRINTF(UFSHostDevice
, "SCSIInfoQueue size: %d, lun: %d\n",
1718 UFSDevice
[lun_id
]->SCSIInfoQueue
.size(), lun_id
);
1721 if (UFSHCIMem
.TRUTRLDBR
& transferEnd
.front().mask
) {
1723 while (!(transferEnd
.front().mask
& (0x1 << count
)))
1725 stats
.transactionLatency
.sample(curTick() -
1726 transactionStart
[count
]);
1729 /**Last message that will be transfered*/
1730 readDevice(true, transferEnd
.front().address
,
1731 transferEnd
.front().size
, reinterpret_cast<uint8_t*>
1732 (transferEnd
.front().destination
), true, NULL
);
1734 /**clean and ensure that the tracker is updated*/
1735 transferTrack
&= ~(transferEnd
.front().mask
);
1738 garbage
.push_back(transferEnd
.front().destination
);
1739 transferEnd
.pop_front();
1740 DPRINTF(UFSHostDevice
, "UTP handled\n");
1743 stats
.averageDoorbell
= stats
.maxDoorbell
.value();
1745 DPRINTF(UFSHostDevice
, "activeDoorbells: %d, pendingDoorbells: %d,"
1746 " garbage: %d, TransferEvent: %d\n", activeDoorbells
,
1747 pendingDoorbells
, garbage
.size(), transferEventQueue
.size());
1749 /**This is the moment that the device is available again*/
1750 if (!UFSDevice
[lun_id
]->SCSIInfoQueue
.empty())
1755 * Read done handling function, is only initiated at the end of a transaction
1758 UFSHostDevice::readDone()
1760 DPRINTF(UFSHostDevice
, "Read done start\n");
1763 /**Garbage collection; sort out the allocated UTP descriptor*/
1764 if (garbage
.size() > 0) {
1765 delete garbage
.front();
1766 garbage
.pop_front();
1769 /**done, generate interrupt if we havent got one already*/
1770 if (!(UFSHCIMem
.ORInterruptStatus
& 0x01)) {
1771 UFSHCIMem
.ORInterruptStatus
|= UTPTransferREQCOMPL
;
1772 generateInterrupt();
1776 if (!readDoneEvent
.empty()) {
1777 readDoneEvent
.pop_front();
1782 * set interrupt and sort out the doorbell register.
1786 UFSHostDevice::generateInterrupt()
1788 /**just to keep track of the transactions*/
1791 /**step5 clear doorbell*/
1792 UFSHCIMem
.TRUTRLDBR
&= transferTrack
;
1793 pendingDoorbells
= 0;
1794 DPRINTF(UFSHostDevice
, "Clear doorbell %X\n", UFSHCIMem
.TRUTRLDBR
);
1798 /**step6 raise interrupt*/
1799 gic
->sendInt(intNum
);
1800 DPRINTF(UFSHostDevice
, "Send interrupt @ transaction: 0x%8x!\n",
1809 UFSHostDevice::clearInterrupt()
1811 gic
->clearInt(intNum
);
1812 DPRINTF(UFSHostDevice
, "Clear interrupt: 0x%8x!\n", countInt
);
1816 if (!(UFSHCIMem
.TRUTRLDBR
)) {
1817 idlePhaseStart
= curTick();
1819 /**end of a transaction*/
1823 * Important to understand about the transfer flow:
1824 * We have basically three stages, The "system memory" stage, the "device
1825 * buffer" stage and the "disk" stage. In this model we assume an infinite
1826 * buffer, or a buffer that is big enough to store all the data in the
1827 * biggest transaction. Between the three stages are two queues. Those queues
1828 * store the messages to simulate their transaction from one stage to the
1829 * next. The manage{Action} function fills up one of the queues and triggers
1830 * the first event, which causes a chain reaction of events executed once
1831 * they pass through their queues. For a write action the stages are ordered
1832 * "system memory", "device buffer" and "disk", whereas the read transfers
1833 * happen "disk", "device buffer" and "system memory". The dma action in the
1834 * dma device is written from a bus perspective whereas this model is written
1835 * from a device perspective. To avoid confusion, the translation between the
1836 * two has been made in the writeDevice and readDevice funtions.
1841 * Dma transaction function: write device. Note that the dma action is
1842 * from a device perspective, while this function is from an initiator
1847 UFSHostDevice::writeDevice(Event
* additional_action
, bool toDisk
, Addr
1848 start
, int size
, uint8_t* destination
, uint64_t
1849 SCSIDiskOffset
, uint32_t lun_id
)
1851 DPRINTF(UFSHostDevice
, "Write transaction Start: 0x%8x; Size: %d\n",
1854 /**check whether transfer is all the way to the flash*/
1858 while (!writeDoneEvent
.empty() && (writeDoneEvent
.front().when()
1860 writeDoneEvent
.pop_front();
1862 writeDoneEvent
.push_back(
1863 EventFunctionWrapper([this]{ writeDone(); },
1865 assert(!writeDoneEvent
.back().scheduled());
1867 /**destination is an offset here since we are writing to a disk*/
1868 struct transferInfo new_transfer
;
1869 new_transfer
.offset
= SCSIDiskOffset
;
1870 new_transfer
.size
= size
;
1871 new_transfer
.lunID
= lun_id
;
1872 new_transfer
.filePointer
= 0;
1873 SSDWriteinfo
.push_back(new_transfer
);
1875 /**allocate appropriate buffer*/
1876 SSDWriteinfo
.back().buffer
.resize(size
);
1879 dmaPort
.dmaAction(MemCmd::ReadReq
, start
, size
,
1880 &writeDoneEvent
.back(),
1881 &SSDWriteinfo
.back().buffer
[0], 0);
1882 //yes, a readreq at a write device function is correct.
1883 DPRINTF(UFSHostDevice
, "Write to disk scheduled\n");
1886 assert(!additional_action
->scheduled());
1887 dmaPort
.dmaAction(MemCmd::ReadReq
, start
, size
,
1888 additional_action
, destination
, 0);
1889 DPRINTF(UFSHostDevice
, "Write scheduled\n");
1894 * Manage write transfer. Manages correct transfer flow and makes sure that
1895 * the queues are filled on time
1899 UFSHostDevice::manageWriteTransfer(uint8_t LUN
, uint64_t offset
, uint32_t
1900 sg_table_length
, struct UFSHCDSGEntry
*
1903 struct writeToDiskBurst next_packet
;
1905 next_packet
.SCSIDiskOffset
= offset
;
1907 UFSDevice
[LUN
]->setTotalWrite(sg_table_length
);
1910 * Break-up the transactions into actions defined by the scatter gather
1913 for (uint32_t count
= 0; count
< sg_table_length
; count
++) {
1914 next_packet
.start
= sglist
[count
].upperAddr
;
1915 next_packet
.start
= (next_packet
.start
<< 32) |
1916 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
1917 next_packet
.LUN
= LUN
;
1918 DPRINTF(UFSHostDevice
, "Write data DMA start: 0x%8x\n",
1920 DPRINTF(UFSHostDevice
, "Write data DMA size: 0x%8x\n",
1921 (sglist
[count
].size
+ 1));
1922 assert(sglist
[count
].size
> 0);
1925 next_packet
.SCSIDiskOffset
= next_packet
.SCSIDiskOffset
+
1926 (sglist
[count
- 1].size
+ 1);
1928 next_packet
.size
= sglist
[count
].size
+ 1;
1930 /**If the queue is empty, the transaction should be initiated*/
1931 if (dmaWriteInfo
.empty())
1932 writeDevice(NULL
, true, next_packet
.start
, next_packet
.size
,
1933 NULL
, next_packet
.SCSIDiskOffset
, next_packet
.LUN
);
1935 DPRINTF(UFSHostDevice
, "Write not initiated queue: %d\n",
1936 dmaWriteInfo
.size());
1938 dmaWriteInfo
.push_back(next_packet
);
1939 DPRINTF(UFSHostDevice
, "Write Location: 0x%8x\n",
1940 next_packet
.SCSIDiskOffset
);
1942 DPRINTF(UFSHostDevice
, "Write transfer #: 0x%8x\n", count
+ 1);
1945 stats
.totalWrittenSSD
+= (sglist
[count
].size
+ 1);
1949 ++stats
.totalWriteUFSTransactions
;
1953 * Write done handling function. Is only initiated when the flash is directly
1958 UFSHostDevice::writeDone()
1960 /**DMA is done, information no longer needed*/
1961 assert(dmaWriteInfo
.size() > 0);
1962 dmaWriteInfo
.pop_front();
1963 assert(SSDWriteinfo
.size() > 0);
1964 uint32_t lun
= SSDWriteinfo
.front().lunID
;
1966 /**If there is nothing on the way, we need to start the events*/
1967 DPRINTF(UFSHostDevice
, "Write done entered, queue: %d\n",
1968 UFSDevice
[lun
]->SSDWriteDoneInfo
.size());
1970 UFSDevice
[lun
]->writeFlash(&SSDWriteinfo
.front().buffer
[0],
1971 SSDWriteinfo
.front().offset
,
1972 SSDWriteinfo
.front().size
);
1975 * Move to the second queue, enter the logic unit
1976 * This is where the disk is approached and the flash transaction is
1977 * handled SSDWriteDone will take care of the timing
1979 UFSDevice
[lun
]->SSDWriteDoneInfo
.push_back(SSDWriteinfo
.front());
1980 SSDWriteinfo
.pop_front();
1983 /**so far, only the DMA part has been handled, lets do the disk delay*/
1984 UFSDevice
[lun
]->SSDWriteStart();
1987 stats
.currentWriteSSDQueue
= UFSDevice
[lun
]->SSDWriteDoneInfo
.size();
1988 stats
.averageWriteSSDQueue
= UFSDevice
[lun
]->SSDWriteDoneInfo
.size();
1989 ++stats
.totalWriteDiskTransactions
;
1991 /**initiate the next dma action (if any)*/
1992 if (!dmaWriteInfo
.empty())
1993 writeDevice(NULL
, true, dmaWriteInfo
.front().start
,
1994 dmaWriteInfo
.front().size
, NULL
,
1995 dmaWriteInfo
.front().SCSIDiskOffset
,
1996 dmaWriteInfo
.front().LUN
);
1997 DPRINTF(UFSHostDevice
, "Write done end\n");
2001 * SSD write start. Starts the write action in the timing model
2004 UFSHostDevice::UFSSCSIDevice::SSDWriteStart()
2006 assert(SSDWriteDoneInfo
.size() > 0);
2007 flashDevice
->writeMemory(
2008 SSDWriteDoneInfo
.front().offset
,
2009 SSDWriteDoneInfo
.front().size
, memWriteCallback
);
2011 SSDWriteDoneInfo
.pop_front();
2013 DPRINTF(UFSHostDevice
, "Write is started; left in queue: %d\n",
2014 SSDWriteDoneInfo
.size());
2023 UFSHostDevice::UFSSCSIDevice::SSDWriteDone()
2025 DPRINTF(UFSHostDevice
, "Write disk, aiming for %d messages, %d so far\n",
2026 totalWrite
, amountOfWriteTransfers
);
2028 //we have done one extra transfer
2029 ++amountOfWriteTransfers
;
2031 /**test whether call was correct*/
2032 assert(totalWrite
>= amountOfWriteTransfers
&& totalWrite
!= 0);
2034 /**are we there yet? (did we do everything)*/
2035 if (totalWrite
== amountOfWriteTransfers
) {
2036 DPRINTF(UFSHostDevice
, "Write transactions finished\n");
2038 amountOfWriteTransfers
= 0;
2048 * Dma transaction function: read device. Notice that the dma action is from
2049 * a device perspective, while this function is from an initiator perspective
2053 UFSHostDevice::readDevice(bool lastTransfer
, Addr start
, uint32_t size
,
2054 uint8_t* destination
, bool no_cache
, Event
*
2057 DPRINTF(UFSHostDevice
, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2058 start
, size
, (reinterpret_cast<uint32_t *>(destination
))[0]);
2060 /** check wether interrupt is needed */
2063 readDoneEvent
.push_back(
2064 EventFunctionWrapper([this]{ readDone(); },
2066 assert(!readDoneEvent
.back().scheduled());
2067 dmaPort
.dmaAction(MemCmd::WriteReq
, start
, size
,
2068 &readDoneEvent
.back(), destination
, 0);
2069 //yes, a writereq at a read device function is correct.
2072 if (additional_action
!= NULL
)
2073 assert(!additional_action
->scheduled());
2075 dmaPort
.dmaAction(MemCmd::WriteReq
, start
, size
,
2076 additional_action
, destination
, 0);
2083 * Manage read transfer. Manages correct transfer flow and makes sure that
2084 * the queues are filled on time
2088 UFSHostDevice::manageReadTransfer(uint32_t size
, uint32_t LUN
, uint64_t
2089 offset
, uint32_t sg_table_length
,
2090 struct UFSHCDSGEntry
* sglist
)
2092 uint32_t size_accum
= 0;
2094 DPRINTF(UFSHostDevice
, "Data READ size: %d\n", size
);
2097 * Break-up the transactions into actions defined by the scatter gather
2100 for (uint32_t count
= 0; count
< sg_table_length
; count
++) {
2101 struct transferInfo new_transfer
;
2102 new_transfer
.offset
= sglist
[count
].upperAddr
;
2103 new_transfer
.offset
= (new_transfer
.offset
<< 32) |
2104 (sglist
[count
].baseAddr
& 0xFFFFFFFF);
2105 new_transfer
.filePointer
= offset
+ size_accum
;
2106 new_transfer
.size
= (sglist
[count
].size
+ 1);
2107 new_transfer
.lunID
= LUN
;
2109 DPRINTF(UFSHostDevice
, "Data READ start: 0x%8x; size: %d\n",
2110 new_transfer
.offset
, new_transfer
.size
);
2112 UFSDevice
[LUN
]->SSDReadInfo
.push_back(new_transfer
);
2113 UFSDevice
[LUN
]->SSDReadInfo
.back().buffer
.resize(sglist
[count
].size
2117 * The disk image is read here; but the action is simultated later
2118 * You can see this as the preparation stage, whereas later is the
2121 UFSDevice
[LUN
]->readFlash(&UFSDevice
[LUN
]->
2122 SSDReadInfo
.back().buffer
[0],
2123 offset
+ size_accum
,
2124 sglist
[count
].size
+ 1);
2126 size_accum
+= (sglist
[count
].size
+ 1);
2128 DPRINTF(UFSHostDevice
, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2129 " 0x%8x\n", (count
+ 1), (size
-size_accum
), size_accum
);
2132 stats
.totalReadSSD
+= (sglist
[count
].size
+ 1);
2133 stats
.currentReadSSDQueue
= UFSDevice
[LUN
]->SSDReadInfo
.size();
2134 stats
.averageReadSSDQueue
= UFSDevice
[LUN
]->SSDReadInfo
.size();
2137 UFSDevice
[LUN
]->SSDReadStart(sg_table_length
);
2140 ++stats
.totalReadUFSTransactions
;
2147 * SSDisk start read; this function was created to keep the interfaces
2148 * between the layers simpler. Without this function UFSHost would need to
2149 * know about the flashdevice.
2153 UFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read
)
2155 totalRead
= total_read
;
2156 for (uint32_t number_handled
= 0; number_handled
< SSDReadInfo
.size();
2159 * Load all the read request to the Memory device.
2160 * It will call back when done.
2162 flashDevice
->readMemory(SSDReadInfo
.front().filePointer
,
2163 SSDReadInfo
.front().size
, memReadCallback
);
2174 UFSHostDevice::UFSSCSIDevice::SSDReadDone()
2176 DPRINTF(UFSHostDevice
, "SSD read done at lun %d, Aiming for %d messages,"
2177 " %d so far\n", lunID
, totalRead
, amountOfReadTransfers
);
2179 if (totalRead
== amountOfReadTransfers
) {
2181 amountOfReadTransfers
= 0;
2183 /**Callback: transferdone*/
2191 * Read callback, on the way from the disk to the DMA. Called by the flash
2192 * layer. Intermediate step to the host layer
2195 UFSHostDevice::UFSSCSIDevice::readCallback()
2197 ++amountOfReadTransfers
;
2199 /**Callback; make sure data is transfered upstream:
2200 * UFSHostDevice::readCallback
2203 deviceReadCallback();
2210 * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
2215 UFSHostDevice::readCallback()
2217 DPRINTF(UFSHostDevice
, "Read Callback\n");
2218 uint8_t this_lun
= 0;
2220 //while we haven't found the right lun, keep searching
2221 while ((this_lun
< lunAvail
) && !UFSDevice
[this_lun
]->finishedRead())
2224 DPRINTF(UFSHostDevice
, "Found LUN %d messages pending for clean: %d\n",
2225 this_lun
, SSDReadPending
.size());
2227 if (this_lun
< lunAvail
) {
2229 UFSDevice
[this_lun
]->clearReadSignal();
2230 SSDReadPending
.push_back(UFSDevice
[this_lun
]->SSDReadInfo
.front());
2231 UFSDevice
[this_lun
]->SSDReadInfo
.pop_front();
2232 readGarbageEventQueue
.push_back(
2233 EventFunctionWrapper([this]{ readGarbage(); }, name()));
2235 //make sure the queue is popped a the end of the dma transaction
2236 readDevice(false, SSDReadPending
.front().offset
,
2237 SSDReadPending
.front().size
,
2238 &SSDReadPending
.front().buffer
[0], false,
2239 &readGarbageEventQueue
.back());
2242 ++stats
.totalReadDiskTransactions
;
2245 panic("no read finished in tick %d\n", curTick());
2249 * After a disk read DMA transfer, the structure needs to be freed. This is
2250 * done in this function.
2253 UFSHostDevice::readGarbage()
2255 DPRINTF(UFSHostDevice
, "Clean read data, %d\n", SSDReadPending
.size());
2256 SSDReadPending
.pop_front();
2257 readGarbageEventQueue
.pop_front();
2261 * Serialize; needed to make checkpoints
2265 UFSHostDevice::serialize(CheckpointOut
&cp
) const
2267 DmaDevice::serialize(cp
);
2269 const uint8_t* temp_HCI_mem
= reinterpret_cast<const uint8_t*>(&UFSHCIMem
);
2270 SERIALIZE_ARRAY(temp_HCI_mem
, sizeof(HCIMem
));
2272 uint32_t lun_avail
= lunAvail
;
2273 SERIALIZE_SCALAR(lun_avail
);
2278 * Unserialize; needed to restore from checkpoints
2282 UFSHostDevice::unserialize(CheckpointIn
&cp
)
2284 DmaDevice::unserialize(cp
);
2285 uint8_t* temp_HCI_mem
= reinterpret_cast<uint8_t*>(&UFSHCIMem
);
2286 UNSERIALIZE_ARRAY(temp_HCI_mem
, sizeof(HCIMem
));
2289 UNSERIALIZE_SCALAR(lun_avail
);
2290 assert(lunAvail
== lun_avail
);
2295 * Drain; needed to enable checkpoints
2299 UFSHostDevice::drain()
2301 if (UFSHCIMem
.TRUTRLDBR
) {
2302 DPRINTF(UFSHostDevice
, "UFSDevice is draining...\n");
2303 return DrainState::Draining
;
2305 DPRINTF(UFSHostDevice
, "UFSDevice drained\n");
2306 return DrainState::Drained
;
2311 * Checkdrain; needed to enable checkpoints
2315 UFSHostDevice::checkDrain()
2317 if (drainState() != DrainState::Draining
)
2320 if (UFSHCIMem
.TRUTRLDBR
) {
2321 DPRINTF(UFSHostDevice
, "UFSDevice is still draining; with %d active"
2322 " doorbells\n", activeDoorbells
);
2324 DPRINTF(UFSHostDevice
, "UFSDevice is done draining\n");