830b841b2ab84233f4f4d815ac465426cf161426
[gem5.git] / src / dev / arm / ufs_device.cc
1 /*
2 * Copyright (c) 2013-2015 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * 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.
24 *
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.
36 */
37
38 /** @file
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.
60 */
61
62 /**
63 * Reference material can be found at the JEDEC website:
64 * UFS standard
65 * http://www.jedec.org/standards-documents/results/jesd220
66 * UFS HCI specification
67 * http://www.jedec.org/standards-documents/results/jesd223
68 */
69
70 #include "dev/arm/ufs_device.hh"
71
72 /**
73 * Constructor and destructor functions of UFSHCM device
74 */
75 UFSHostDevice::UFSSCSIDevice::UFSSCSIDevice(const UFSHostDeviceParams &p,
76 uint32_t lun_id, const Callback &transfer_cb,
77 const Callback &read_cb):
78 SimObject(p),
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),
86 lunID(lun_id),
87 transferCompleted(false),
88 readCompleted(false),
89 totalRead(0),
90 totalWrite(0),
91 amountOfWriteTransfers(0),
92 amountOfReadTransfers(0)
93 {
94 /**
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.
98 */
99 signalDone = transfer_cb;
100 memReadCallback = [this]() { readCallback(); };
101 deviceReadCallback = read_cb;
102 memWriteCallback = [this]() { SSDWriteDone(); };
103
104 /**
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
107 */
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
118
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",
122 lunID, diskSize);
123 flashDevice->initializeMemory(diskSize, SectorSize);
124 }
125
126
127 /**
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
131 */
132 const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage[3] =
133 {0x01400A0A, 0x00000000,
134 0x0000FFFF};
135 const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage[3] =
136 {0x03800A01, 0x00000000,
137 0xFFFF0003};
138 const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage[5] =
139 {0x00011208, 0x00000000,
140 0x00000000, 0x00000020,
141 0x00000000};
142
143 UFSHostDevice::UFSSCSIDevice::~UFSSCSIDevice() {}
144
145 /**
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})
154 */
155
156 struct UFSHostDevice::SCSIReply
157 UFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg)
158 {
159 struct SCSIReply scsi_out;
160 scsi_out.reset();
161
162 /**
163 * Create the standard SCSI reponse information
164 * These values might changes over the course of a transfer
165 */
166 scsi_out.message.header.dWord0 = UPIUHeaderDataIndWord0 |
167 lunID << 16;
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;
174
175 DPRINTF(UFSHostDevice, "SCSI command:%2x\n", SCSI_msg[4]);
176 /**Determine what the message is and fill the response packet*/
177
178 switch (SCSI_msg[4] & 0xFF) {
179
180 case SCSIInquiry: {
181 /**
182 * SCSI inquiry: tell about this specific logic unit
183 */
184 scsi_out.msgSize = 36;
185 scsi_out.message.dataMsg.resize(9);
186
187 for (uint8_t count = 0; count < 9; count++)
188 scsi_out.message.dataMsg[count] =
189 (reinterpret_cast<uint32_t*> (&lunInfo))[count];
190 } break;
191
192 case SCSIRead6: {
193 /**
194 * Read command. Number indicates the length of the command.
195 */
196 scsi_out.expectMore = 0x02;
197 scsi_out.msgSize = 0;
198
199 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
200
201 /**BE and not nicely aligned. Apart from that it only has
202 * information in five bits of the first byte that is relevant
203 * for this field.
204 */
205 uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
206 uint64_t read_offset = betoh(tmp) & 0x1FFFFF;
207
208 uint32_t read_size = tempptr[4];
209
210
211 scsi_out.msgSize = read_size * blkSize;
212 scsi_out.offset = read_offset * blkSize;
213
214 if ((read_offset + read_size) > diskSize)
215 scsi_out.status = SCSIIllegalRequest;
216
217 DPRINTF(UFSHostDevice, "Read6 offset: 0x%8x, for %d blocks\n",
218 read_offset, read_size);
219
220 /**
221 * Renew status check, for the request may have been illegal
222 */
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 :
226 SCSICheckCondition;
227
228 } break;
229
230 case SCSIRead10: {
231 scsi_out.expectMore = 0x02;
232 scsi_out.msgSize = 0;
233
234 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
235
236 /**BE and not nicely aligned.*/
237 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
238 uint64_t read_offset = betoh(tmp);
239
240 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
241 uint32_t read_size = betoh(tmpsize);
242
243 scsi_out.msgSize = read_size * blkSize;
244 scsi_out.offset = read_offset * blkSize;
245
246 if ((read_offset + read_size) > diskSize)
247 scsi_out.status = SCSIIllegalRequest;
248
249 DPRINTF(UFSHostDevice, "Read10 offset: 0x%8x, for %d blocks\n",
250 read_offset, read_size);
251
252 /**
253 * Renew status check, for the request may have been illegal
254 */
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 :
258 SCSICheckCondition;
259
260 } break;
261
262 case SCSIRead16: {
263 scsi_out.expectMore = 0x02;
264 scsi_out.msgSize = 0;
265
266 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
267
268 /**BE and not nicely aligned.*/
269 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
270 uint64_t read_offset = betoh(tmp);
271
272 tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
273 read_offset = (read_offset << 32) | betoh(tmp);
274
275 tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
276 uint32_t read_size = betoh(tmp);
277
278 scsi_out.msgSize = read_size * blkSize;
279 scsi_out.offset = read_offset * blkSize;
280
281 if ((read_offset + read_size) > diskSize)
282 scsi_out.status = SCSIIllegalRequest;
283
284 DPRINTF(UFSHostDevice, "Read16 offset: 0x%8x, for %d blocks\n",
285 read_offset, read_size);
286
287 /**
288 * Renew status check, for the request may have been illegal
289 */
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 :
293 SCSICheckCondition;
294
295 } break;
296
297 case SCSIReadCapacity10: {
298 /**
299 * read the capacity of the device
300 */
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
306
307 } break;
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
321
322 } break;
323
324 case SCSIReportLUNs: {
325 /**
326 * Find out how many Logic Units this device has.
327 */
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;
332
333 for (uint8_t count = 0; count < lunAvail; count++) {
334 //LUN "count"
335 scsi_out.message.dataMsg[2 + 2 * count] = (count & 0x7F) << 8;
336 scsi_out.message.dataMsg[3 + 2 * count] = 0x00;
337 }
338
339 } break;
340
341 case SCSIStartStop: {
342 //Just acknowledge; not deemed relevant ATM
343 scsi_out.msgSize = 0;
344
345 } break;
346
347 case SCSITestUnitReady: {
348 //Just acknowledge; not deemed relevant ATM
349 scsi_out.msgSize = 0;
350
351 } break;
352
353 case SCSIVerify10: {
354 /**
355 * See if the blocks that the host plans to request are in range of
356 * the device.
357 */
358 scsi_out.msgSize = 0;
359
360 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
361
362 /**BE and not nicely aligned.*/
363 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
364 uint64_t read_offset = betoh(tmp);
365
366 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
367 uint32_t read_size = betoh(tmpsize);
368
369 if ((read_offset + read_size) > diskSize)
370 scsi_out.status = SCSIIllegalRequest;
371
372 /**
373 * Renew status check, for the request may have been illegal
374 */
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 :
378 SCSICheckCondition;
379
380 } break;
381
382 case SCSIWrite6: {
383 /**
384 * Write command.
385 */
386
387 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
388
389 /**BE and not nicely aligned. Apart from that it only has
390 * information in five bits of the first byte that is relevant
391 * for this field.
392 */
393 uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
394 uint64_t write_offset = betoh(tmp) & 0x1FFFFF;
395
396 uint32_t write_size = tempptr[4];
397
398 scsi_out.msgSize = write_size * blkSize;
399 scsi_out.offset = write_offset * blkSize;
400 scsi_out.expectMore = 0x01;
401
402 if ((write_offset + write_size) > diskSize)
403 scsi_out.status = SCSIIllegalRequest;
404
405 DPRINTF(UFSHostDevice, "Write6 offset: 0x%8x, for %d blocks\n",
406 write_offset, write_size);
407
408 /**
409 * Renew status check, for the request may have been illegal
410 */
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 :
414 SCSICheckCondition;
415
416 } break;
417
418 case SCSIWrite10: {
419 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
420
421 /**BE and not nicely aligned.*/
422 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
423 uint64_t write_offset = betoh(tmp);
424
425 uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
426 uint32_t write_size = betoh(tmpsize);
427
428 scsi_out.msgSize = write_size * blkSize;
429 scsi_out.offset = write_offset * blkSize;
430 scsi_out.expectMore = 0x01;
431
432 if ((write_offset + write_size) > diskSize)
433 scsi_out.status = SCSIIllegalRequest;
434
435 DPRINTF(UFSHostDevice, "Write10 offset: 0x%8x, for %d blocks\n",
436 write_offset, write_size);
437
438 /**
439 * Renew status check, for the request may have been illegal
440 */
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 :
444 SCSICheckCondition;
445
446 } break;
447
448 case SCSIWrite16: {
449 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
450
451 /**BE and not nicely aligned.*/
452 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
453 uint64_t write_offset = betoh(tmp);
454
455 tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
456 write_offset = (write_offset << 32) | betoh(tmp);
457
458 tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
459 uint32_t write_size = betoh(tmp);
460
461 scsi_out.msgSize = write_size * blkSize;
462 scsi_out.offset = write_offset * blkSize;
463 scsi_out.expectMore = 0x01;
464
465 if ((write_offset + write_size) > diskSize)
466 scsi_out.status = SCSIIllegalRequest;
467
468 DPRINTF(UFSHostDevice, "Write16 offset: 0x%8x, for %d blocks\n",
469 write_offset, write_size);
470
471 /**
472 * Renew status check, for the request may have been illegal
473 */
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 :
477 SCSICheckCondition;
478
479 } break;
480
481 case SCSIFormatUnit: {//not yet verified
482 scsi_out.msgSize = 0;
483 scsi_out.expectMore = 0x01;
484
485 } break;
486
487 case SCSISendDiagnostic: {//not yet verified
488 scsi_out.msgSize = 0;
489
490 } break;
491
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;
496
497 } break;
498
499 //UFS SCSI additional command set for full functionality
500 case SCSIModeSelect10:
501 //TODO:
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
504 break;
505
506 case SCSIModeSense6: case SCSIModeSense10: {
507 /**
508 * Get more discriptive information about the SCSI functionality
509 * within this logic unit.
510 */
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
515
516 for (uint8_t count = 0; count < 3; count++)
517 scsi_out.message.dataMsg[2 + count] = controlPage[count];
518
519 scsi_out.msgSize = 20;
520 DPRINTF(UFSHostDevice, "CONTROL page\n");
521
522 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
523 scsi_out.message.dataMsg.resize((sizeof(recoveryPage) >> 2)
524 + 2);
525
526 scsi_out.message.dataMsg[0] = 0x00000100;//recovery page code
527 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
528
529 for (uint8_t count = 0; count < 3; count++)
530 scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
531
532 scsi_out.msgSize = 20;
533 DPRINTF(UFSHostDevice, "RECOVERY page\n");
534
535 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x08) {//caching page
536
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
540
541 for (uint8_t count = 0; count < 5; count++)
542 scsi_out.message.dataMsg[2 + count] = cachingPage[count];
543
544 scsi_out.msgSize = 20;
545 DPRINTF(UFSHostDevice, "CACHE page\n");
546
547 } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
548
549 scsi_out.message.dataMsg.resize(((sizeof(controlPage) +
550 sizeof(recoveryPage) +
551 sizeof(cachingPage)) >> 2)
552 + 2);
553 scsi_out.message.dataMsg[0] = 0x00003200;//all page code
554 scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
555
556 for (uint8_t count = 0; count < 3; count++)
557 scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
558
559 for (uint8_t count = 0; count < 5; count++)
560 scsi_out.message.dataMsg[5 + count] = cachingPage[count];
561
562 for (uint8_t count = 0; count < 3; count++)
563 scsi_out.message.dataMsg[10 + count] = controlPage[count];
564
565 scsi_out.msgSize = 52;
566 DPRINTF(UFSHostDevice, "Return ALL the pages!!!\n");
567
568 } else inform("Wrong mode page requested\n");
569
570 scsi_out.message.dataCount = scsi_out.msgSize << 24;
571 } break;
572
573 case SCSIRequestSense: {
574 scsi_out.msgSize = 0;
575
576 } break;
577
578 case SCSIUnmap:break;//not yet verified
579
580 case SCSIWriteBuffer: {
581 scsi_out.expectMore = 0x01;
582
583 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
584
585 /**BE and not nicely aligned.*/
586 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
587 uint64_t write_offset = betoh(tmp) & 0xFFFFFF;
588
589 tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
590 uint32_t write_size = betoh(tmp) & 0xFFFFFF;
591
592 scsi_out.msgSize = write_size;
593 scsi_out.offset = write_offset;
594
595 } break;
596
597 case SCSIReadBuffer: {
598 /**
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.
602 */
603 scsi_out.expectMore = 0x02;
604
605 uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
606
607 /**BE and not nicely aligned.*/
608 uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
609 uint64_t read_offset = betoh(tmp) & 0xFFFFFF;
610
611 tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
612 uint32_t read_size = betoh(tmp) & 0xFFFFFF;
613
614 scsi_out.msgSize = read_size;
615 scsi_out.offset = read_offset;
616
617 if ((read_offset + read_size) > capacityLower * blkSize)
618 scsi_out.status = SCSIIllegalRequest;
619
620 DPRINTF(UFSHostDevice, "Read buffer location: 0x%8x\n",
621 read_offset);
622 DPRINTF(UFSHostDevice, "Number of bytes: 0x%8x\n", read_size);
623
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 :
627 SCSICheckCondition;
628
629 } break;
630
631 case SCSIMaintenanceIn: {
632 /**
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.
637 */
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 :
642 SCSICheckCondition;
643 scsi_out.msgSize = 0;
644 } break;
645
646 default: {
647 statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
648 scsi_out.senseSize = scsi_out.senseCode[0];
649 scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
650 SCSICheckCondition;
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]);
658 } break;
659 }
660
661 return scsi_out;
662 }
663
664 /**
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.
668 */
669
670 void
671 UFSHostDevice::UFSSCSIDevice::statusCheck(uint8_t status,
672 uint8_t* sensecodelist)
673 {
674 for (uint8_t count = 0; count < 19; count++)
675 sensecodelist[count] = 0;
676
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
681 }
682
683 /**
684 * read from the flashdisk
685 */
686
687 void
688 UFSHostDevice::UFSSCSIDevice::readFlash(uint8_t* readaddr, uint64_t offset,
689 uint32_t size)
690 {
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);
695 }
696
697 /**
698 * Write to the flashdisk
699 */
700
701 void
702 UFSHostDevice::UFSSCSIDevice::writeFlash(uint8_t* writeaddr, uint64_t offset,
703 uint32_t size)
704 {
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);
709 }
710
711 /**
712 * Constructor for the UFS Host device
713 */
714
715 UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams &p) :
716 DmaDevice(p),
717 pioAddr(p.pio_addr),
718 pioSize(0x0FFF),
719 pioDelay(p.pio_latency),
720 intNum(p.int_num),
721 gic(p.gic),
722 lunAvail(p.image.size()),
723 UFSSlots(p.ufs_slots - 1),
724 readPendingNum(0),
725 writePendingNum(0),
726 activeDoorbells(0),
727 pendingDoorbells(0),
728 countInt(0),
729 transferTrack(0),
730 taskCommandTrack(0),
731 idlePhaseStart(0),
732 stats(this),
733 SCSIResumeEvent([this]{ SCSIStart(); }, name()),
734 UTPEvent([this]{ finalUTP(); }, name())
735 {
736 DPRINTF(UFSHostDevice, "The hostcontroller hosts %d Logic units\n",
737 lunAvail);
738 UFSDevice.resize(lunAvail);
739
740 for (int count = 0; count < lunAvail; count++) {
741 UFSDevice[count] = new UFSSCSIDevice(p, count,
742 [this]() { LUNSignal(); },
743 [this]() { readCallback(); });
744 }
745
746 if (UFSSlots > 31)
747 warn("UFSSlots = %d, this will results in %d command slots",
748 UFSSlots, (UFSSlots & 0x1F));
749
750 if ((UFSSlots & 0x1F) == 0)
751 fatal("Number of UFS command slots should be between 1 and 32.");
752
753 setValues();
754 }
755
756 UFSHostDevice::
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"),
805 /** Latency*/
806 ADD_STAT(transactionLatency, UNIT_TICK,
807 "Histogram of transaction times"),
808 ADD_STAT(idleTimes, UNIT_TICK, "Histogram of idle times")
809 {
810 using namespace Stats;
811
812 // Register the stats
813 /** Queue lengths */
814 currentSCSIQueue
815 .flags(none);
816 currentReadSSDQueue
817 .flags(none);
818 currentWriteSSDQueue
819 .flags(none);
820
821 /** Amount of data read/written */
822 totalReadSSD
823 .flags(none);
824
825 totalWrittenSSD
826 .flags(none);
827
828 totalReadDiskTransactions
829 .flags(none);
830 totalWriteDiskTransactions
831 .flags(none);
832 totalReadUFSTransactions
833 .flags(none);
834 totalWriteUFSTransactions
835 .flags(none);
836
837 /** Average bandwidth for reads and writes */
838 averageReadSSDBW
839 .flags(nozero);
840
841 averageWriteSSDBW
842 .flags(nozero);
843
844 averageSCSIQueue
845 .flags(nozero);
846 averageReadSSDQueue
847 .flags(nozero);
848 averageWriteSSDQueue
849 .flags(nozero);
850
851 /** Number of doorbells rung*/
852 curDoorbell
853 .flags(none);
854
855 maxDoorbell
856 .flags(none);
857 averageDoorbell
858 .flags(nozero);
859
860 /** Latency*/
861 transactionLatency
862 .init(100)
863 .flags(pdf);
864
865 idleTimes
866 .init(100)
867 .flags(pdf);
868 }
869
870 /**
871 * Register init
872 */
873 void UFSHostDevice::setValues()
874 {
875 /**
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
879 */
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;
893 }
894
895 /**
896 * Determine address ranges
897 */
898
899 AddrRangeList
900 UFSHostDevice::getAddrRanges() const
901 {
902 AddrRangeList ranges;
903 ranges.push_back(RangeSize(pioAddr, pioSize));
904 return ranges;
905 }
906
907 /**
908 * UFSHCD read register. This function allows the system to read the
909 * register entries
910 */
911
912 Tick
913 UFSHostDevice::read(PacketPtr pkt)
914 {
915 uint32_t data = 0;
916
917 switch (pkt->getAddr() & 0xFF)
918 {
919
920 case regControllerCapabilities:
921 data = UFSHCIMem.HCCAP;
922 break;
923
924 case regUFSVersion:
925 data = UFSHCIMem.HCversion;
926 break;
927
928 case regControllerDEVID:
929 data = UFSHCIMem.HCHCDDID;
930 break;
931
932 case regControllerPRODID:
933 data = UFSHCIMem.HCHCPMID;
934 break;
935
936 case regInterruptStatus:
937 data = UFSHCIMem.ORInterruptStatus;
938 UFSHCIMem.ORInterruptStatus = 0x00;
939 //TODO: Revise and extend
940 clearInterrupt();
941 break;
942
943 case regInterruptEnable:
944 data = UFSHCIMem.ORInterruptEnable;
945 break;
946
947 case regControllerStatus:
948 data = UFSHCIMem.ORHostControllerStatus;
949 break;
950
951 case regControllerEnable:
952 data = UFSHCIMem.ORHostControllerEnable;
953 break;
954
955 case regUICErrorCodePHYAdapterLayer:
956 data = UFSHCIMem.ORUECPA;
957 break;
958
959 case regUICErrorCodeDataLinkLayer:
960 data = UFSHCIMem.ORUECDL;
961 break;
962
963 case regUICErrorCodeNetworkLayer:
964 data = UFSHCIMem.ORUECN;
965 break;
966
967 case regUICErrorCodeTransportLayer:
968 data = UFSHCIMem.ORUECT;
969 break;
970
971 case regUICErrorCodeDME:
972 data = UFSHCIMem.ORUECDME;
973 break;
974
975 case regUTPTransferREQINTAGGControl:
976 data = UFSHCIMem.ORUTRIACR;
977 break;
978
979 case regUTPTransferREQListBaseL:
980 data = UFSHCIMem.TRUTRLBA;
981 break;
982
983 case regUTPTransferREQListBaseH:
984 data = UFSHCIMem.TRUTRLBAU;
985 break;
986
987 case regUTPTransferREQDoorbell:
988 data = UFSHCIMem.TRUTRLDBR;
989 break;
990
991 case regUTPTransferREQListClear:
992 data = UFSHCIMem.TRUTRLCLR;
993 break;
994
995 case regUTPTransferREQListRunStop:
996 data = UFSHCIMem.TRUTRLRSR;
997 break;
998
999 case regUTPTaskREQListBaseL:
1000 data = UFSHCIMem.TMUTMRLBA;
1001 break;
1002
1003 case regUTPTaskREQListBaseH:
1004 data = UFSHCIMem.TMUTMRLBAU;
1005 break;
1006
1007 case regUTPTaskREQDoorbell:
1008 data = UFSHCIMem.TMUTMRLDBR;
1009 break;
1010
1011 case regUTPTaskREQListClear:
1012 data = UFSHCIMem.TMUTMRLCLR;
1013 break;
1014
1015 case regUTPTaskREQListRunStop:
1016 data = UFSHCIMem.TMUTMRLRSR;
1017 break;
1018
1019 case regUICCommand:
1020 data = UFSHCIMem.CMDUICCMDR;
1021 break;
1022
1023 case regUICCommandArg1:
1024 data = UFSHCIMem.CMDUCMDARG1;
1025 break;
1026
1027 case regUICCommandArg2:
1028 data = UFSHCIMem.CMDUCMDARG2;
1029 break;
1030
1031 case regUICCommandArg3:
1032 data = UFSHCIMem.CMDUCMDARG3;
1033 break;
1034
1035 default:
1036 data = 0x00;
1037 break;
1038 }
1039
1040 pkt->setLE<uint32_t>(data);
1041 pkt->makeResponse();
1042 return pioDelay;
1043 }
1044
1045 /**
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.
1049 */
1050 Tick
1051 UFSHostDevice::write(PacketPtr pkt)
1052 {
1053 assert(pkt->getSize() <= 4);
1054
1055 const uint32_t data = pkt->getUintX(ByteOrder::little);
1056
1057 switch (pkt->getAddr() & 0xFF)
1058 {
1059 case regControllerCapabilities://you shall not write to this
1060 break;
1061
1062 case regUFSVersion://you shall not write to this
1063 break;
1064
1065 case regControllerDEVID://you shall not write to this
1066 break;
1067
1068 case regControllerPRODID://you shall not write to this
1069 break;
1070
1071 case regInterruptStatus://you shall not write to this
1072 break;
1073
1074 case regInterruptEnable:
1075 UFSHCIMem.ORInterruptEnable = data;
1076 break;
1077
1078 case regControllerStatus:
1079 UFSHCIMem.ORHostControllerStatus = data;
1080 break;
1081
1082 case regControllerEnable:
1083 UFSHCIMem.ORHostControllerEnable = data;
1084 break;
1085
1086 case regUICErrorCodePHYAdapterLayer:
1087 UFSHCIMem.ORUECPA = data;
1088 break;
1089
1090 case regUICErrorCodeDataLinkLayer:
1091 UFSHCIMem.ORUECDL = data;
1092 break;
1093
1094 case regUICErrorCodeNetworkLayer:
1095 UFSHCIMem.ORUECN = data;
1096 break;
1097
1098 case regUICErrorCodeTransportLayer:
1099 UFSHCIMem.ORUECT = data;
1100 break;
1101
1102 case regUICErrorCodeDME:
1103 UFSHCIMem.ORUECDME = data;
1104 break;
1105
1106 case regUTPTransferREQINTAGGControl:
1107 UFSHCIMem.ORUTRIACR = data;
1108 break;
1109
1110 case regUTPTransferREQListBaseL:
1111 UFSHCIMem.TRUTRLBA = data;
1112 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1113 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
1114 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1115 break;
1116
1117 case regUTPTransferREQListBaseH:
1118 UFSHCIMem.TRUTRLBAU = data;
1119 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1120 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1121 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1122 break;
1123
1124 case regUTPTransferREQDoorbell:
1125 if (!(UFSHCIMem.TRUTRLDBR) && data)
1126 stats.idleTimes.sample(curTick() - idlePhaseStart);
1127 UFSHCIMem.TRUTRLDBR |= data;
1128 requestHandler();
1129 break;
1130
1131 case regUTPTransferREQListClear:
1132 UFSHCIMem.TRUTRLCLR = data;
1133 break;
1134
1135 case regUTPTransferREQListRunStop:
1136 UFSHCIMem.TRUTRLRSR = data;
1137 break;
1138
1139 case regUTPTaskREQListBaseL:
1140 UFSHCIMem.TMUTMRLBA = data;
1141 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1142 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1143 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1144 break;
1145
1146 case regUTPTaskREQListBaseH:
1147 UFSHCIMem.TMUTMRLBAU = data;
1148 if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1149 ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1150 UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1151 break;
1152
1153 case regUTPTaskREQDoorbell:
1154 UFSHCIMem.TMUTMRLDBR |= data;
1155 requestHandler();
1156 break;
1157
1158 case regUTPTaskREQListClear:
1159 UFSHCIMem.TMUTMRLCLR = data;
1160 break;
1161
1162 case regUTPTaskREQListRunStop:
1163 UFSHCIMem.TMUTMRLRSR = data;
1164 break;
1165
1166 case regUICCommand:
1167 UFSHCIMem.CMDUICCMDR = data;
1168 requestHandler();
1169 break;
1170
1171 case regUICCommandArg1:
1172 UFSHCIMem.CMDUCMDARG1 = data;
1173 break;
1174
1175 case regUICCommandArg2:
1176 UFSHCIMem.CMDUCMDARG2 = data;
1177 break;
1178
1179 case regUICCommandArg3:
1180 UFSHCIMem.CMDUCMDARG3 = data;
1181 break;
1182
1183 default:break;//nothing happens, you try to access a register that
1184 //does not exist
1185
1186 }
1187
1188 pkt->makeResponse();
1189 return pioDelay;
1190 }
1191
1192 /**
1193 * Request handler. Determines where the request comes from and initiates the
1194 * appropriate actions accordingly.
1195 */
1196
1197 void
1198 UFSHostDevice::requestHandler()
1199 {
1200 Addr address = 0x00;
1201 int mask = 0x01;
1202 int size;
1203 int count = 0;
1204 struct taskStart task_info;
1205 struct transferStart transferstart_info;
1206 transferstart_info.done = 0;
1207
1208 /**
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
1212 */
1213 while (((UFSHCIMem.CMDUICCMDR > 0x00) |
1214 ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
1215 ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
1216
1217 if (UFSHCIMem.CMDUICCMDR > 0x00) {
1218 /**
1219 * Command; general control of the Host controller.
1220 * no DMA transfer needed
1221 */
1222 commandHandler();
1223 UFSHCIMem.ORInterruptStatus |= UICCommandCOMPL;
1224 generateInterrupt();
1225 UFSHCIMem.CMDUICCMDR = 0x00;
1226 return; //command, nothing more we can do
1227
1228 } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
1229 /**
1230 * Task; flow control, meant for the device/Logic unit
1231 * DMA transfer is needed, flash will not be approached
1232 */
1233 size = sizeof(UTPUPIUTaskReq);
1234 /**Find the position that is not handled yet*/
1235 count = findLsbSet((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack));
1236 address = UFSHCIMem.TMUTMRLBAU;
1237 //<-64 bit
1238 address = (count * size) + (address << 32) +
1239 UFSHCIMem.TMUTMRLBA;
1240 taskCommandTrack |= mask << count;
1241
1242 inform("UFSmodel received a task from the system; this might"
1243 " lead to untested behaviour.\n");
1244
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);
1255
1256 } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
1257 /**
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.
1261 */
1262 size = sizeof(UTPTransferReqDesc);
1263 /**Find the position that is not handled yet*/
1264 count = findLsbSet((UFSHCIMem.TRUTRLDBR ^ transferTrack));
1265 address = UFSHCIMem.TRUTRLBAU;
1266 //<-64 bit
1267 address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
1268
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);
1273
1274 transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1275
1276 /**stats**/
1277 transactionStart[count] = curTick(); //note the start time
1278 ++activeDoorbells;
1279 stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
1280 ? activeDoorbells : stats.maxDoorbell.value();
1281 stats.averageDoorbell = stats.maxDoorbell.value();
1282
1283 /**
1284 * step3 start transfer
1285 * step4 register information; allowing the host to respond in
1286 * the end
1287 */
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);
1293
1294 /**Deleted in readDone, queued in finalUTP*/
1295 transferStartInfo.back().destination = new struct
1296 UTPTransferReqDesc;
1297 DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
1298 transferstart_info.done);
1299 transferEventQueue.push_back(
1300 EventFunctionWrapper([this]{ transferStart(); }, name()));
1301
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");
1307 }
1308 }
1309 }
1310 }
1311
1312 /**
1313 * Task start event
1314 */
1315
1316 void
1317 UFSHostDevice::taskStart()
1318 {
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();
1324 }
1325
1326 /**
1327 * Transfer start event
1328 */
1329
1330 void
1331 UFSHostDevice::transferStart()
1332 {
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);
1339
1340 transferStartInfo.pop_front();
1341 DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
1342 "0x%8x\n", transferEventQueue.size());
1343 }
1344
1345 /**
1346 * Handles the commands that are given. At this point in time, not many
1347 * commands have been implemented in the driver.
1348 */
1349
1350 void
1351 UFSHostDevice::commandHandler()
1352 {
1353 if (UFSHCIMem.CMDUICCMDR == 0x16) {
1354 UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
1355 }
1356
1357 }
1358
1359 /**
1360 * Handles the tasks that are given. At this point in time, not many tasks
1361 * have been implemented in the driver.
1362 */
1363
1364 void
1365 UFSHostDevice::taskHandler(struct UTPUPIUTaskReq* request_in,
1366 uint32_t req_pos, Addr finaladdress, uint32_t
1367 finalsize)
1368 {
1369 /**
1370 * For now, just unpack and acknowledge the task without doing anything.
1371 * TODO Implement UFS tasks.
1372 */
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);
1377
1378 request_in->header.dWord2 &= 0xffffff00;
1379
1380 UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
1381 taskCommandTrack &= ~(req_pos);
1382 UFSHCIMem.ORInterruptStatus |= UTPTaskREQCOMPL;
1383
1384 readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
1385 (request_in), true, NULL);
1386
1387 }
1388
1389 /**
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
1393 * by this code.
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.
1398 */
1399
1400 void
1401 UFSHostDevice::transferHandler(struct UTPTransferReqDesc* request_in,
1402 int req_pos, Addr finaladdress, uint32_t
1403 finalsize, uint32_t done)
1404 {
1405
1406 Addr cmd_desc_addr = 0x00;
1407
1408
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;
1419
1420 assert(!SCSIResumeEvent.scheduled());
1421 /**
1422 *Get the UTP command that has the SCSI command
1423 */
1424 cmd_desc_addr = request_in->commandDescBaseAddrHi;
1425 cmd_desc_addr = (cmd_desc_addr << 32) |
1426 (request_in->commandDescBaseAddrLo & 0xffffffff);
1427
1428 writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
1429 SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
1430
1431 DPRINTF(UFSHostDevice, "SCSI scheduled\n");
1432
1433 transferEventQueue.pop_front();
1434 }
1435
1436 /**
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.
1441 */
1442
1443 void
1444 UFSHostDevice::SCSIStart()
1445 {
1446 DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
1447 uint32_t LUN = SCSIInfo.destination[2];
1448 UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
1449
1450 DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
1451 UFSDevice[LUN]->SCSIInfoQueue.size());
1452
1453 /**There are 32 doorbells, so at max there can be 32 transactions*/
1454 if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
1455 SCSIResume(LUN);
1456
1457 else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
1458 panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
1459 SCSIInfoQueue.size());
1460
1461 /**
1462 * First transfer is done, fetch the next;
1463 * At this point, the device is busy, not the HC
1464 */
1465 if (!transferEventQueue.empty()) {
1466
1467 /**
1468 * loading next data packet in case Another LUN
1469 * is approached in the mean time
1470 */
1471 writeDevice(&transferEventQueue.front(), false,
1472 transferStartInfo.front().address,
1473 transferStartInfo.front().size, reinterpret_cast<uint8_t*>
1474 (transferStartInfo.front().destination), 0, 0);
1475
1476 DPRINTF(UFSHostDevice, "Transfer scheduled");
1477 }
1478 }
1479
1480 /**
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
1486 */
1487
1488 void
1489 UFSHostDevice::SCSIResume(uint32_t lun_id)
1490 {
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);
1495
1496 /**old info, lets form it such that we can understand it*/
1497 struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
1498 SCSIInfoQueue.front().RequestIn;
1499
1500 uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
1501
1502 Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
1503 finalAddress;
1504
1505 uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
1506
1507 uint32_t* transfercommand = reinterpret_cast<uint32_t*>
1508 (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
1509
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);
1514
1515 DPRINTF(UFSHostDevice, "LUN: %d\n", request_out_datain.LUN);
1516
1517 /**
1518 * build response stating that it was succesful
1519 * command completion, Logic unit number, and Task tag
1520 */
1521 request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
1522 ? 0x36 : 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;
1535
1536 //data
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];
1540 }
1541
1542 /*
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.
1546 */
1547 struct UFSHCDSGEntry* sglist = reinterpret_cast<UFSHCDSGEntry*>
1548 (&(transfercommand[(request_in->PRDTableOffset)]));
1549
1550 uint32_t length = request_in->PRDTableLength;
1551 DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
1552
1553 Addr response_addr = request_in->commandDescBaseAddrHi;
1554 response_addr = (response_addr << 32) |
1555 ((request_in->commandDescBaseAddrLo +
1556 (request_in->responseUPIULength << 2)) & 0xffffffff);
1557
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;
1567
1568 /**
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
1571 * started.
1572 */
1573 if (request_out_datain.expectMore == 0x01) {
1574 /**write transfer*/
1575 manageWriteTransfer(request_out_datain.LUN, request_out_datain.offset,
1576 length, sglist);
1577
1578 } else if (request_out_datain.expectMore == 0x02) {
1579 /**read transfer*/
1580 manageReadTransfer(request_out_datain.msgSize, request_out_datain.LUN,
1581 request_out_datain.offset, length, sglist);
1582
1583 } else {
1584 /**not disk related transfer, SCSI maintanance*/
1585 uint32_t count = 0;
1586 uint32_t size_accum = 0;
1587 DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1588 request_out_datain.msgSize);
1589
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));
1600 /**
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
1605 * transfered.
1606 */
1607 uint32_t size_to_send = sglist[count].size + 1;
1608
1609 if (request_out_datain.msgSize < (size_to_send + size_accum))
1610 size_to_send = request_out_datain.msgSize - size_accum;
1611
1612 readDevice(false, SCSI_start, size_to_send,
1613 reinterpret_cast<uint8_t*>
1614 (&(request_out_datain.message.dataMsg[size_accum])),
1615 false, NULL);
1616
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),
1620 size_accum);
1621
1622 ++count;
1623 DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
1624 }
1625
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);
1630 }
1631
1632 DPRINTF(UFSHostDevice, "SCSI resume done\n");
1633 }
1634
1635 /**
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.
1639 */
1640 void
1641 UFSHostDevice::LUNSignal()
1642 {
1643 uint8_t this_lun = 0;
1644
1645 //while we haven't found the right lun, keep searching
1646 while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
1647 ++this_lun;
1648
1649 if (this_lun < lunAvail) {
1650 //Clear signal.
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);
1661 }
1662
1663 else
1664 panic("no LUN finished in tick %d\n", curTick());
1665 }
1666
1667 /**
1668 * Transfer done. When the data transfer is done, this function ensures
1669 * that the application is notified.
1670 */
1671
1672 void
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)
1677 {
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);
1682
1683 DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1684 responseStartAddr, sizeof(request_out));
1685
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*>
1692 (destination);
1693 lastinfo.lun_id = lun_id;
1694
1695 transferEnd.push_back(lastinfo);
1696
1697 DPRINTF(UFSHostDevice, "Transfer done start\n");
1698
1699 readDevice(false, responseStartAddr, sizeof(request_out),
1700 reinterpret_cast<uint8_t*>
1701 (&(UFSDevice[lun_id]->transferInfo.requestOut)),
1702 true, &UTPEvent);
1703 }
1704
1705 /**
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.
1709 */
1710
1711 void
1712 UFSHostDevice::finalUTP()
1713 {
1714 uint32_t lun_id = transferEnd.front().lun_id;
1715
1716 UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
1717 DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
1718 UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
1719
1720 /**stats**/
1721 if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
1722 uint8_t count = 0;
1723 while (!(transferEnd.front().mask & (0x1 << count)))
1724 ++count;
1725 stats.transactionLatency.sample(curTick() -
1726 transactionStart[count]);
1727 }
1728
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);
1733
1734 /**clean and ensure that the tracker is updated*/
1735 transferTrack &= ~(transferEnd.front().mask);
1736 --activeDoorbells;
1737 ++pendingDoorbells;
1738 garbage.push_back(transferEnd.front().destination);
1739 transferEnd.pop_front();
1740 DPRINTF(UFSHostDevice, "UTP handled\n");
1741
1742 /**stats**/
1743 stats.averageDoorbell = stats.maxDoorbell.value();
1744
1745 DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
1746 " garbage: %d, TransferEvent: %d\n", activeDoorbells,
1747 pendingDoorbells, garbage.size(), transferEventQueue.size());
1748
1749 /**This is the moment that the device is available again*/
1750 if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
1751 SCSIResume(lun_id);
1752 }
1753
1754 /**
1755 * Read done handling function, is only initiated at the end of a transaction
1756 */
1757 void
1758 UFSHostDevice::readDone()
1759 {
1760 DPRINTF(UFSHostDevice, "Read done start\n");
1761 --readPendingNum;
1762
1763 /**Garbage collection; sort out the allocated UTP descriptor*/
1764 if (garbage.size() > 0) {
1765 delete garbage.front();
1766 garbage.pop_front();
1767 }
1768
1769 /**done, generate interrupt if we havent got one already*/
1770 if (!(UFSHCIMem.ORInterruptStatus & 0x01)) {
1771 UFSHCIMem.ORInterruptStatus |= UTPTransferREQCOMPL;
1772 generateInterrupt();
1773 }
1774
1775
1776 if (!readDoneEvent.empty()) {
1777 readDoneEvent.pop_front();
1778 }
1779 }
1780
1781 /**
1782 * set interrupt and sort out the doorbell register.
1783 */
1784
1785 void
1786 UFSHostDevice::generateInterrupt()
1787 {
1788 /**just to keep track of the transactions*/
1789 countInt++;
1790
1791 /**step5 clear doorbell*/
1792 UFSHCIMem.TRUTRLDBR &= transferTrack;
1793 pendingDoorbells = 0;
1794 DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
1795
1796 checkDrain();
1797
1798 /**step6 raise interrupt*/
1799 gic->sendInt(intNum);
1800 DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
1801 countInt);
1802 }
1803
1804 /**
1805 * Clear interrupt
1806 */
1807
1808 void
1809 UFSHostDevice::clearInterrupt()
1810 {
1811 gic->clearInt(intNum);
1812 DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
1813
1814 checkDrain();
1815
1816 if (!(UFSHCIMem.TRUTRLDBR)) {
1817 idlePhaseStart = curTick();
1818 }
1819 /**end of a transaction*/
1820 }
1821
1822 /**
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.
1837 */
1838
1839
1840 /**
1841 * Dma transaction function: write device. Note that the dma action is
1842 * from a device perspective, while this function is from an initiator
1843 * perspective
1844 */
1845
1846 void
1847 UFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
1848 start, int size, uint8_t* destination, uint64_t
1849 SCSIDiskOffset, uint32_t lun_id)
1850 {
1851 DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
1852 start, size);
1853
1854 /**check whether transfer is all the way to the flash*/
1855 if (toDisk) {
1856 ++writePendingNum;
1857
1858 while (!writeDoneEvent.empty() && (writeDoneEvent.front().when()
1859 < curTick()))
1860 writeDoneEvent.pop_front();
1861
1862 writeDoneEvent.push_back(
1863 EventFunctionWrapper([this]{ writeDone(); },
1864 name()));
1865 assert(!writeDoneEvent.back().scheduled());
1866
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);
1874
1875 /**allocate appropriate buffer*/
1876 SSDWriteinfo.back().buffer.resize(size);
1877
1878 /**transaction*/
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");
1884
1885 } else {
1886 assert(!additional_action->scheduled());
1887 dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1888 additional_action, destination, 0);
1889 DPRINTF(UFSHostDevice, "Write scheduled\n");
1890 }
1891 }
1892
1893 /**
1894 * Manage write transfer. Manages correct transfer flow and makes sure that
1895 * the queues are filled on time
1896 */
1897
1898 void
1899 UFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
1900 sg_table_length, struct UFSHCDSGEntry*
1901 sglist)
1902 {
1903 struct writeToDiskBurst next_packet;
1904
1905 next_packet.SCSIDiskOffset = offset;
1906
1907 UFSDevice[LUN]->setTotalWrite(sg_table_length);
1908
1909 /**
1910 * Break-up the transactions into actions defined by the scatter gather
1911 * list.
1912 */
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",
1919 next_packet.start);
1920 DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
1921 (sglist[count].size + 1));
1922 assert(sglist[count].size > 0);
1923
1924 if (count != 0)
1925 next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
1926 (sglist[count - 1].size + 1);
1927
1928 next_packet.size = sglist[count].size + 1;
1929
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);
1934 else
1935 DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
1936 dmaWriteInfo.size());
1937
1938 dmaWriteInfo.push_back(next_packet);
1939 DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
1940 next_packet.SCSIDiskOffset);
1941
1942 DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
1943
1944 /** stats **/
1945 stats.totalWrittenSSD += (sglist[count].size + 1);
1946 }
1947
1948 /**stats**/
1949 ++stats.totalWriteUFSTransactions;
1950 }
1951
1952 /**
1953 * Write done handling function. Is only initiated when the flash is directly
1954 * approached
1955 */
1956
1957 void
1958 UFSHostDevice::writeDone()
1959 {
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;
1965
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());
1969 /**Write the disk*/
1970 UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
1971 SSDWriteinfo.front().offset,
1972 SSDWriteinfo.front().size);
1973
1974 /**
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
1978 */
1979 UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
1980 SSDWriteinfo.pop_front();
1981
1982 --writePendingNum;
1983 /**so far, only the DMA part has been handled, lets do the disk delay*/
1984 UFSDevice[lun]->SSDWriteStart();
1985
1986 /** stats **/
1987 stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1988 stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1989 ++stats.totalWriteDiskTransactions;
1990
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");
1998 }
1999
2000 /**
2001 * SSD write start. Starts the write action in the timing model
2002 */
2003 void
2004 UFSHostDevice::UFSSCSIDevice::SSDWriteStart()
2005 {
2006 assert(SSDWriteDoneInfo.size() > 0);
2007 flashDevice->writeMemory(
2008 SSDWriteDoneInfo.front().offset,
2009 SSDWriteDoneInfo.front().size, memWriteCallback);
2010
2011 SSDWriteDoneInfo.pop_front();
2012
2013 DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
2014 SSDWriteDoneInfo.size());
2015 }
2016
2017
2018 /**
2019 * SSDisk write done
2020 */
2021
2022 void
2023 UFSHostDevice::UFSSCSIDevice::SSDWriteDone()
2024 {
2025 DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
2026 totalWrite, amountOfWriteTransfers);
2027
2028 //we have done one extra transfer
2029 ++amountOfWriteTransfers;
2030
2031 /**test whether call was correct*/
2032 assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
2033
2034 /**are we there yet? (did we do everything)*/
2035 if (totalWrite == amountOfWriteTransfers) {
2036 DPRINTF(UFSHostDevice, "Write transactions finished\n");
2037 totalWrite = 0;
2038 amountOfWriteTransfers = 0;
2039
2040 //Callback UFS Host
2041 setSignal();
2042 signalDone();
2043 }
2044
2045 }
2046
2047 /**
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
2050 */
2051
2052 void
2053 UFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
2054 uint8_t* destination, bool no_cache, Event*
2055 additional_action)
2056 {
2057 DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2058 start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
2059
2060 /** check wether interrupt is needed */
2061 if (lastTransfer) {
2062 ++readPendingNum;
2063 readDoneEvent.push_back(
2064 EventFunctionWrapper([this]{ readDone(); },
2065 name()));
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.
2070
2071 } else {
2072 if (additional_action != NULL)
2073 assert(!additional_action->scheduled());
2074
2075 dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2076 additional_action, destination, 0);
2077
2078 }
2079
2080 }
2081
2082 /**
2083 * Manage read transfer. Manages correct transfer flow and makes sure that
2084 * the queues are filled on time
2085 */
2086
2087 void
2088 UFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
2089 offset, uint32_t sg_table_length,
2090 struct UFSHCDSGEntry* sglist)
2091 {
2092 uint32_t size_accum = 0;
2093
2094 DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
2095
2096 /**
2097 * Break-up the transactions into actions defined by the scatter gather
2098 * list.
2099 */
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;
2108
2109 DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
2110 new_transfer.offset, new_transfer.size);
2111
2112 UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
2113 UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
2114 + 1);
2115
2116 /**
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
2119 * simulation phase.
2120 */
2121 UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
2122 SSDReadInfo.back().buffer[0],
2123 offset + size_accum,
2124 sglist[count].size + 1);
2125
2126 size_accum += (sglist[count].size + 1);
2127
2128 DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2129 " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
2130
2131 /** stats **/
2132 stats.totalReadSSD += (sglist[count].size + 1);
2133 stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2134 stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2135 }
2136
2137 UFSDevice[LUN]->SSDReadStart(sg_table_length);
2138
2139 /** stats **/
2140 ++stats.totalReadUFSTransactions;
2141
2142 }
2143
2144
2145
2146 /**
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.
2150 */
2151
2152 void
2153 UFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read)
2154 {
2155 totalRead = total_read;
2156 for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
2157 number_handled++) {
2158 /**
2159 * Load all the read request to the Memory device.
2160 * It will call back when done.
2161 */
2162 flashDevice->readMemory(SSDReadInfo.front().filePointer,
2163 SSDReadInfo.front().size, memReadCallback);
2164 }
2165
2166 }
2167
2168
2169 /**
2170 * SSDisk read done
2171 */
2172
2173 void
2174 UFSHostDevice::UFSSCSIDevice::SSDReadDone()
2175 {
2176 DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
2177 " %d so far\n", lunID, totalRead, amountOfReadTransfers);
2178
2179 if (totalRead == amountOfReadTransfers) {
2180 totalRead = 0;
2181 amountOfReadTransfers = 0;
2182
2183 /**Callback: transferdone*/
2184 setSignal();
2185 signalDone();
2186 }
2187
2188 }
2189
2190 /**
2191 * Read callback, on the way from the disk to the DMA. Called by the flash
2192 * layer. Intermediate step to the host layer
2193 */
2194 void
2195 UFSHostDevice::UFSSCSIDevice::readCallback()
2196 {
2197 ++amountOfReadTransfers;
2198
2199 /**Callback; make sure data is transfered upstream:
2200 * UFSHostDevice::readCallback
2201 */
2202 setReadSignal();
2203 deviceReadCallback();
2204
2205 //Are we done yet?
2206 SSDReadDone();
2207 }
2208
2209 /**
2210 * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
2211 * layer.
2212 */
2213
2214 void
2215 UFSHostDevice::readCallback()
2216 {
2217 DPRINTF(UFSHostDevice, "Read Callback\n");
2218 uint8_t this_lun = 0;
2219
2220 //while we haven't found the right lun, keep searching
2221 while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
2222 ++this_lun;
2223
2224 DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
2225 this_lun, SSDReadPending.size());
2226
2227 if (this_lun < lunAvail) {
2228 //Clear signal.
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()));
2234
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());
2240
2241 /**stats*/
2242 ++stats.totalReadDiskTransactions;
2243 }
2244 else
2245 panic("no read finished in tick %d\n", curTick());
2246 }
2247
2248 /**
2249 * After a disk read DMA transfer, the structure needs to be freed. This is
2250 * done in this function.
2251 */
2252 void
2253 UFSHostDevice::readGarbage()
2254 {
2255 DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
2256 SSDReadPending.pop_front();
2257 readGarbageEventQueue.pop_front();
2258 }
2259
2260 /**
2261 * Serialize; needed to make checkpoints
2262 */
2263
2264 void
2265 UFSHostDevice::serialize(CheckpointOut &cp) const
2266 {
2267 DmaDevice::serialize(cp);
2268
2269 const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
2270 SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2271
2272 uint32_t lun_avail = lunAvail;
2273 SERIALIZE_SCALAR(lun_avail);
2274 }
2275
2276
2277 /**
2278 * Unserialize; needed to restore from checkpoints
2279 */
2280
2281 void
2282 UFSHostDevice::unserialize(CheckpointIn &cp)
2283 {
2284 DmaDevice::unserialize(cp);
2285 uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
2286 UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2287
2288 uint32_t lun_avail;
2289 UNSERIALIZE_SCALAR(lun_avail);
2290 assert(lunAvail == lun_avail);
2291 }
2292
2293
2294 /**
2295 * Drain; needed to enable checkpoints
2296 */
2297
2298 DrainState
2299 UFSHostDevice::drain()
2300 {
2301 if (UFSHCIMem.TRUTRLDBR) {
2302 DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
2303 return DrainState::Draining;
2304 } else {
2305 DPRINTF(UFSHostDevice, "UFSDevice drained\n");
2306 return DrainState::Drained;
2307 }
2308 }
2309
2310 /**
2311 * Checkdrain; needed to enable checkpoints
2312 */
2313
2314 void
2315 UFSHostDevice::checkDrain()
2316 {
2317 if (drainState() != DrainState::Draining)
2318 return;
2319
2320 if (UFSHCIMem.TRUTRLDBR) {
2321 DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
2322 " doorbells\n", activeDoorbells);
2323 } else {
2324 DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
2325 signalDrainDone();
2326 }
2327 }