ufs_device.cc revision 10912:b99a6662d7c2
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 * Authors: Rene de Jong
38 */
39
40/** @file
41 * This is a simulation model for a UFS interface
42 * The UFS interface consists of a host controller and (at least) one device.
43 * The device can contain multiple logic units.
44 * To make this interface as usefull as possible for future development, the
45 * decision has been made to split the UFS functionality from the SCSI
46 * functionality. The class UFS SCSIDevice can therefor be used as a starting
47 * point for creating a more generic SCSI device. This has as a consequence
48 * that the UFSHostDevice class contains functionality from both the host
49 * controller and the device. The current UFS standard (1.1) allows only one
50 * device, and up to 8 logic units. the logic units only handle the SCSI part
51 * of the command, and the device mainly the UFS part. Yet the split between
52 * the SCSIresume function and the SCSICMDHandle might seem a bit awkward.
53 * The SCSICMDHandle function is in essence a SCSI reply generator, and it
54 * distils the essential information from the command. A disktransfer cannot
55 * be made from this position because the scatter gather list is not included
56 * in the SCSI command, but in the Transfer Request descriptor. The device
57 * needs to manage the data transfer. This file is build up as follows: first
58 * the UFSSCSIDevice functions will be presented; then the UFSHostDevice
59 * functions. The UFSHostDevice functions are split in three parts: UFS
60 * transaction flow, data write transfer and data read transfer. The
61 * functions are then ordered in the order in which a transfer takes place.
62 */
63
64/**
65 * Reference material can be found at the JEDEC website:
66 * UFS standard
67 * http://www.jedec.org/standards-documents/results/jesd220
68 * UFS HCI specification
69 * http://www.jedec.org/standards-documents/results/jesd223
70 */
71
72#include "dev/arm/ufs_device.hh"
73
74/**
75 * Constructor and destructor functions of UFSHCM device
76 */
77UFSHostDevice::UFSSCSIDevice::UFSSCSIDevice(const UFSHostDeviceParams* p,
78                             uint32_t lun_id, Callback *transfer_cb,
79                             Callback *read_cb):
80    SimObject(p),
81    flashDisk(p->image[lun_id]),
82    flashDevice(p->internalflash[lun_id]),
83    blkSize(p->img_blk_size),
84    lunAvail(p->image.size()),
85    diskSize(flashDisk->size()),
86    capacityLower((diskSize - 1) & 0xffffffff),
87    capacityUpper((diskSize - SectorSize) >> 32),
88    lunID(lun_id),
89    transferCompleted(false),
90    readCompleted(false),
91    totalRead(0),
92    totalWrite(0),
93    amountOfWriteTransfers(0),
94    amountOfReadTransfers(0)
95{
96    /**
97     * These callbacks are used to communicate the events that are
98     * triggered upstream; e.g. from the Memory Device to the UFS SCSI Device
99     * or from the UFS SCSI device to the UFS host.
100     */
101    signalDone = transfer_cb;
102    memReadCallback = new MakeCallback<UFSSCSIDevice,
103        &UFSHostDevice::UFSSCSIDevice::readCallback>(this);
104    deviceReadCallback = read_cb;
105    memWriteCallback = new MakeCallback<UFSSCSIDevice,
106        &UFSHostDevice::UFSSCSIDevice::SSDWriteDone>(this);
107
108    /**
109     * make ascii out of lun_id (and add more characters)
110     * UFS allows up to 8 logic units, so the numbering should work out
111     */
112    uint32_t temp_id = ((lun_id | 0x30) << 24) | 0x3A4449;
113    lunInfo.dWord0 = 0x02060000;   //data
114    lunInfo.dWord1 = 0x0200001F;
115    lunInfo.vendor0 = 0x484D5241;  //ARMH (HMRA)
116    lunInfo.vendor1 = 0x424D4143;  //CAMB (BMAC)
117    lunInfo.product0 = 0x356D6567; //gem5  (5meg)
118    lunInfo.product1 = 0x4D534655; //UFSM (MSFU)
119    lunInfo.product2 = 0x4C45444F; //ODEL (LEDO)
120    lunInfo.product3 = temp_id;    // ID:"lun_id" ("lun_id":DI)
121    lunInfo.productRevision = 0x01000000; //0x01
122
123    DPRINTF(UFSHostDevice, "Logic unit %d assumes that %d logic units are"
124            " present in the system\n", lunID, lunAvail);
125    DPRINTF(UFSHostDevice,"The disksize of lun: %d should be %d blocks\n",
126            lunID, diskSize);
127    flashDevice->initializeMemory(diskSize, SectorSize);
128}
129
130
131/**
132 * These pages are SCSI specific. For more information refer to:
133 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
134 * http://www.jedec.org/standards-documents/results/jesd220
135 */
136const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage[3] =
137                                                {0x01400A0A, 0x00000000,
138                                                 0x0000FFFF};
139const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage[3] =
140                                                {0x03800A01, 0x00000000,
141                                                 0xFFFF0003};
142const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage[5] =
143                                                {0x00011208, 0x00000000,
144                                                 0x00000000, 0x00000020,
145                                                 0x00000000};
146
147UFSHostDevice::UFSSCSIDevice::~UFSSCSIDevice() {}
148
149/**
150 * UFS specific SCSI handling function.
151 * The following attributes may still be added: SCSI format unit,
152 * Send diagnostic and UNMAP;
153 * Synchronize Cache and buffer read/write could not be tested yet
154 * All parameters can be found in:
155 * Universal Flash Storage (UFS) JESD220 FEB 2011 (JEDEC)
156 * http://www.jedec.org/standards-documents/results/jesd220
157 * (a JEDEC acount may be required {free of charge})
158 */
159
160struct UFSHostDevice::SCSIReply
161UFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg)
162{
163    struct SCSIReply scsi_out;
164    memset(&scsi_out, 0, sizeof(struct SCSIReply));
165
166    /**
167     * Create the standard SCSI reponse information
168     * These values might changes over the course of a transfer
169     */
170    scsi_out.message.header.dWord0 = UPIUHeaderDataIndWord0 |
171        lunID << 16;
172    scsi_out.message.header.dWord1 = UPIUHeaderDataIndWord1;
173    scsi_out.message.header.dWord2 = UPIUHeaderDataIndWord2;
174    statusCheck(SCSIGood, scsi_out.senseCode);
175    scsi_out.senseSize = scsi_out.senseCode[0];
176    scsi_out.LUN = lunID;
177    scsi_out.status = SCSIGood;
178
179    DPRINTF(UFSHostDevice, "SCSI command:%2x\n", SCSI_msg[4]);
180    /**Determine what the message is and fill the response packet*/
181
182    switch (SCSI_msg[4] & 0xFF) {
183
184      case SCSIInquiry: {
185          /**
186           * SCSI inquiry: tell about this specific logic unit
187           */
188          scsi_out.msgSize = 36;
189          scsi_out.message.dataMsg.resize(9);
190
191          for (uint8_t count = 0; count < 9; count++)
192              scsi_out.message.dataMsg[count] =
193                  (reinterpret_cast<uint32_t*> (&lunInfo))[count];
194      } break;
195
196      case SCSIRead6: {
197          /**
198           * Read command. Number indicates the length of the command.
199           */
200          scsi_out.expectMore = 0x02;
201          scsi_out.msgSize = 0;
202
203          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
204
205          /**BE and not nicely aligned. Apart from that it only has
206           * information in five bits of the first byte that is relevant
207           * for this field.
208           */
209          uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
210          uint64_t read_offset = betoh(tmp) & 0x1FFFFF;
211
212          uint32_t read_size = tempptr[4];
213
214
215          scsi_out.msgSize =  read_size * blkSize;
216          scsi_out.offset = read_offset * blkSize;
217
218          if ((read_offset + read_size) > diskSize)
219              scsi_out.status = SCSIIllegalRequest;
220
221          DPRINTF(UFSHostDevice, "Read6 offset: 0x%8x, for %d blocks\n",
222                  read_offset, read_size);
223
224          /**
225           * Renew status check, for the request may have been illegal
226           */
227          statusCheck(scsi_out.status, scsi_out.senseCode);
228          scsi_out.senseSize = scsi_out.senseCode[0];
229          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
230              SCSICheckCondition;
231
232      } break;
233
234      case SCSIRead10: {
235          scsi_out.expectMore = 0x02;
236          scsi_out.msgSize = 0;
237
238          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
239
240          /**BE and not nicely aligned.*/
241          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
242          uint64_t read_offset = betoh(tmp);
243
244          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
245          uint32_t read_size = betoh(tmpsize);
246
247          scsi_out.msgSize =  read_size * blkSize;
248          scsi_out.offset = read_offset * blkSize;
249
250          if ((read_offset + read_size) > diskSize)
251              scsi_out.status = SCSIIllegalRequest;
252
253          DPRINTF(UFSHostDevice, "Read10 offset: 0x%8x, for %d blocks\n",
254                  read_offset, read_size);
255
256          /**
257           * Renew status check, for the request may have been illegal
258           */
259          statusCheck(scsi_out.status, scsi_out.senseCode);
260          scsi_out.senseSize = scsi_out.senseCode[0];
261          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
262              SCSICheckCondition;
263
264      } break;
265
266      case SCSIRead16: {
267          scsi_out.expectMore = 0x02;
268          scsi_out.msgSize = 0;
269
270          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
271
272          /**BE and not nicely aligned.*/
273          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
274          uint64_t read_offset = betoh(tmp);
275
276          tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
277          read_offset = (read_offset << 32) | betoh(tmp);
278
279          tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
280          uint32_t read_size = betoh(tmp);
281
282          scsi_out.msgSize =  read_size * blkSize;
283          scsi_out.offset = read_offset * blkSize;
284
285          if ((read_offset + read_size) > diskSize)
286              scsi_out.status = SCSIIllegalRequest;
287
288          DPRINTF(UFSHostDevice, "Read16 offset: 0x%8x, for %d blocks\n",
289                  read_offset, read_size);
290
291          /**
292           * Renew status check, for the request may have been illegal
293           */
294          statusCheck(scsi_out.status, scsi_out.senseCode);
295          scsi_out.senseSize = scsi_out.senseCode[0];
296          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
297              SCSICheckCondition;
298
299      } break;
300
301      case SCSIReadCapacity10: {
302          /**
303           * read the capacity of the device
304           */
305          scsi_out.msgSize = 8;
306          scsi_out.message.dataMsg.resize(2);
307          scsi_out.message.dataMsg[0] =
308              betoh(capacityLower);//last block
309          scsi_out.message.dataMsg[1] = betoh(blkSize);//blocksize
310
311      } break;
312      case SCSIReadCapacity16: {
313          scsi_out.msgSize = 32;
314          scsi_out.message.dataMsg.resize(8);
315          scsi_out.message.dataMsg[0] =
316              betoh(capacityUpper);//last block
317          scsi_out.message.dataMsg[1] =
318              betoh(capacityLower);//last block
319          scsi_out.message.dataMsg[2] = betoh(blkSize);//blocksize
320          scsi_out.message.dataMsg[3] = 0x00;//
321          scsi_out.message.dataMsg[4] = 0x00;//reserved
322          scsi_out.message.dataMsg[5] = 0x00;//reserved
323          scsi_out.message.dataMsg[6] = 0x00;//reserved
324          scsi_out.message.dataMsg[7] = 0x00;//reserved
325
326      } break;
327
328      case SCSIReportLUNs: {
329          /**
330           * Find out how many Logic Units this device has.
331           */
332          scsi_out.msgSize = (lunAvail * 8) + 8;//list + overhead
333          scsi_out.message.dataMsg.resize(2 * lunAvail + 2);
334          scsi_out.message.dataMsg[0] = (lunAvail * 8) << 24;//LUN listlength
335          scsi_out.message.dataMsg[1] = 0x00;
336
337          for (uint8_t count = 0; count < lunAvail; count++) {
338              //LUN "count"
339              scsi_out.message.dataMsg[2 + 2 * count] = (count & 0x7F) << 8;
340              scsi_out.message.dataMsg[3 + 2 * count] = 0x00;
341          }
342
343      } break;
344
345      case SCSIStartStop: {
346          //Just acknowledge; not deemed relevant ATM
347          scsi_out.msgSize = 0;
348
349      } break;
350
351      case SCSITestUnitReady: {
352          //Just acknowledge; not deemed relevant ATM
353          scsi_out.msgSize = 0;
354
355      } break;
356
357      case SCSIVerify10: {
358          /**
359           * See if the blocks that the host plans to request are in range of
360           * the device.
361           */
362          scsi_out.msgSize = 0;
363
364          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
365
366          /**BE and not nicely aligned.*/
367          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
368          uint64_t read_offset = betoh(tmp);
369
370          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
371          uint32_t read_size = betoh(tmpsize);
372
373          if ((read_offset + read_size) > diskSize)
374              scsi_out.status = SCSIIllegalRequest;
375
376          /**
377           * Renew status check, for the request may have been illegal
378           */
379          statusCheck(scsi_out.status, scsi_out.senseCode);
380          scsi_out.senseSize = scsi_out.senseCode[0];
381          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
382              SCSICheckCondition;
383
384      } break;
385
386      case SCSIWrite6: {
387          /**
388           * Write command.
389           */
390
391          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
392
393          /**BE and not nicely aligned. Apart from that it only has
394           * information in five bits of the first byte that is relevant
395           * for this field.
396           */
397          uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
398          uint64_t write_offset = betoh(tmp) & 0x1FFFFF;
399
400          uint32_t write_size = tempptr[4];
401
402          scsi_out.msgSize =  write_size * blkSize;
403          scsi_out.offset = write_offset * blkSize;
404          scsi_out.expectMore = 0x01;
405
406          if ((write_offset + write_size) > diskSize)
407              scsi_out.status = SCSIIllegalRequest;
408
409          DPRINTF(UFSHostDevice, "Write6 offset: 0x%8x, for %d blocks\n",
410                  write_offset, write_size);
411
412          /**
413           * Renew status check, for the request may have been illegal
414           */
415          statusCheck(scsi_out.status, scsi_out.senseCode);
416          scsi_out.senseSize = scsi_out.senseCode[0];
417          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
418              SCSICheckCondition;
419
420      } break;
421
422      case SCSIWrite10: {
423          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
424
425          /**BE and not nicely aligned.*/
426          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
427          uint64_t write_offset = betoh(tmp);
428
429          uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
430          uint32_t write_size = betoh(tmpsize);
431
432          scsi_out.msgSize =  write_size * blkSize;
433          scsi_out.offset = write_offset * blkSize;
434          scsi_out.expectMore = 0x01;
435
436          if ((write_offset + write_size) > diskSize)
437              scsi_out.status = SCSIIllegalRequest;
438
439          DPRINTF(UFSHostDevice, "Write10 offset: 0x%8x, for %d blocks\n",
440                  write_offset, write_size);
441
442          /**
443           * Renew status check, for the request may have been illegal
444           */
445          statusCheck(scsi_out.status, scsi_out.senseCode);
446          scsi_out.senseSize = scsi_out.senseCode[0];
447          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
448              SCSICheckCondition;
449
450      } break;
451
452      case SCSIWrite16: {
453          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
454
455          /**BE and not nicely aligned.*/
456          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
457          uint64_t write_offset = betoh(tmp);
458
459          tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
460          write_offset = (write_offset << 32) | betoh(tmp);
461
462          tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
463          uint32_t write_size = betoh(tmp);
464
465          scsi_out.msgSize = write_size * blkSize;
466          scsi_out.offset = write_offset * blkSize;
467          scsi_out.expectMore = 0x01;
468
469          if ((write_offset + write_size) > diskSize)
470              scsi_out.status = SCSIIllegalRequest;
471
472          DPRINTF(UFSHostDevice, "Write16 offset: 0x%8x, for %d blocks\n",
473                  write_offset, write_size);
474
475          /**
476           * Renew status check, for the request may have been illegal
477           */
478          statusCheck(scsi_out.status, scsi_out.senseCode);
479          scsi_out.senseSize = scsi_out.senseCode[0];
480          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
481              SCSICheckCondition;
482
483      } break;
484
485      case SCSIFormatUnit: {//not yet verified
486          scsi_out.msgSize = 0;
487          scsi_out.expectMore = 0x01;
488
489      } break;
490
491      case SCSISendDiagnostic: {//not yet verified
492          scsi_out.msgSize = 0;
493
494      } break;
495
496      case SCSISynchronizeCache: {
497          //do we have cache (we don't have cache at this moment)
498          //TODO: here will synchronization happen when cache is modelled
499          scsi_out.msgSize = 0;
500
501      } break;
502
503        //UFS SCSI additional command set for full functionality
504      case SCSIModeSelect10:
505        //TODO:
506        //scsi_out.expectMore = 0x01;//not supported due to modepage support
507        //code isn't dead, code suggest what is to be done when implemented
508        break;
509
510      case SCSIModeSense6: case SCSIModeSense10: {
511          /**
512           * Get more discriptive information about the SCSI functionality
513           * within this logic unit.
514           */
515          if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x0A) {//control page
516              scsi_out.message.dataMsg.resize((sizeof(controlPage) >> 2) + 2);
517              scsi_out.message.dataMsg[0] = 0x00000A00;//control page code
518              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
519
520              for (uint8_t count = 0; count < 3; count++)
521                  scsi_out.message.dataMsg[2 + count] = controlPage[count];
522
523              scsi_out.msgSize = 20;
524              DPRINTF(UFSHostDevice, "CONTROL page\n");
525
526          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
527              scsi_out.message.dataMsg.resize((sizeof(recoveryPage) >> 2)
528                                              + 2);
529
530              scsi_out.message.dataMsg[0] = 0x00000100;//recovery page code
531              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
532
533              for (uint8_t count = 0; count < 3; count++)
534                  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
535
536              scsi_out.msgSize = 20;
537              DPRINTF(UFSHostDevice, "RECOVERY page\n");
538
539          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x08) {//caching page
540
541              scsi_out.message.dataMsg.resize((sizeof(cachingPage) >> 2) + 2);
542              scsi_out.message.dataMsg[0] = 0x00001200;//caching page code
543              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
544
545              for (uint8_t count = 0; count < 5; count++)
546                  scsi_out.message.dataMsg[2 + count] = cachingPage[count];
547
548              scsi_out.msgSize = 20;
549              DPRINTF(UFSHostDevice, "CACHE page\n");
550
551          } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
552
553              scsi_out.message.dataMsg.resize(((sizeof(controlPage) +
554                                                sizeof(recoveryPage) +
555                                                sizeof(cachingPage)) >> 2)
556                                              + 2);
557              scsi_out.message.dataMsg[0] = 0x00003200;//all page code
558              scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
559
560              for (uint8_t count = 0; count < 3; count++)
561                  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
562
563              for (uint8_t count = 0; count < 5; count++)
564                  scsi_out.message.dataMsg[5 + count] = cachingPage[count];
565
566              for (uint8_t count = 0; count < 3; count++)
567                  scsi_out.message.dataMsg[10 + count] = controlPage[count];
568
569              scsi_out.msgSize = 52;
570              DPRINTF(UFSHostDevice, "Return ALL the pages!!!\n");
571
572          } else inform("Wrong mode page requested\n");
573
574          scsi_out.message.dataCount = scsi_out.msgSize << 24;
575      } break;
576
577      case SCSIRequestSense: {
578          scsi_out.msgSize = 0;
579
580      } break;
581
582      case SCSIUnmap:break;//not yet verified
583
584      case SCSIWriteBuffer: {
585          scsi_out.expectMore = 0x01;
586
587          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
588
589          /**BE and not nicely aligned.*/
590          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
591          uint64_t write_offset = betoh(tmp) & 0xFFFFFF;
592
593          tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
594          uint32_t write_size = betoh(tmp) & 0xFFFFFF;
595
596          scsi_out.msgSize =  write_size;
597          scsi_out.offset = write_offset;
598
599      } break;
600
601      case SCSIReadBuffer: {
602          /**
603           * less trivial than normal read. Size is in bytes instead
604           * of blocks, and it is assumed (though not guaranteed) that
605           * reading is from cache.
606           */
607          scsi_out.expectMore = 0x02;
608
609          uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
610
611          /**BE and not nicely aligned.*/
612          uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
613          uint64_t read_offset = betoh(tmp) & 0xFFFFFF;
614
615          tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
616          uint32_t read_size = betoh(tmp) & 0xFFFFFF;
617
618          scsi_out.msgSize = read_size;
619          scsi_out.offset = read_offset;
620
621          if ((read_offset + read_size) > capacityLower * blkSize)
622              scsi_out.status = SCSIIllegalRequest;
623
624          DPRINTF(UFSHostDevice, "Read buffer location: 0x%8x\n",
625                  read_offset);
626          DPRINTF(UFSHostDevice, "Number of bytes: 0x%8x\n", read_size);
627
628          statusCheck(scsi_out.status, scsi_out.senseCode);
629          scsi_out.senseSize = scsi_out.senseCode[0];
630          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
631              SCSICheckCondition;
632
633      } break;
634
635      case SCSIMaintenanceIn: {
636          /**
637           * linux sends this command three times from kernel 3.9 onwards,
638           * UFS does not support it, nor does this model. Linux knows this,
639           * but tries anyway (useful for some SD card types).
640           * Lets make clear we don't want it and just ignore it.
641           */
642          DPRINTF(UFSHostDevice, "Ignoring Maintenance In command\n");
643          statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
644          scsi_out.senseSize = scsi_out.senseCode[0];
645          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
646              SCSICheckCondition;
647          scsi_out.msgSize = 0;
648      } break;
649
650      default: {
651          statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
652          scsi_out.senseSize = scsi_out.senseCode[0];
653          scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
654              SCSICheckCondition;
655          scsi_out.msgSize = 0;
656          inform("Unsupported scsi message type: %2x\n", SCSI_msg[4] & 0xFF);
657          inform("0x%8x\n", SCSI_msg[0]);
658          inform("0x%8x\n", SCSI_msg[1]);
659          inform("0x%8x\n", SCSI_msg[2]);
660          inform("0x%8x\n", SCSI_msg[3]);
661          inform("0x%8x\n", SCSI_msg[4]);
662      } break;
663    }
664
665    return scsi_out;
666}
667
668/**
669 * SCSI status check function. generic device test, creates sense codes
670 * Future versions may include TODO: device checks, which is why this is
671 * in a separate function.
672 */
673
674void
675UFSHostDevice::UFSSCSIDevice::statusCheck(uint8_t status,
676                                uint8_t* sensecodelist)
677{
678    for (uint8_t count = 0; count < 19; count++)
679        sensecodelist[count] = 0;
680
681    sensecodelist[0] = 18; //sense length
682    sensecodelist[1] = 0x70; //we send a valid frame
683    sensecodelist[3] = status & 0xF; //mask to be sure + sensecode
684    sensecodelist[8] = 0x1F; //data length
685}
686
687/**
688 * read from the flashdisk
689 */
690
691void
692UFSHostDevice::UFSSCSIDevice::readFlash(uint8_t* readaddr, uint64_t offset,
693                                   uint32_t size)
694{
695    /** read from image, and get to memory */
696    for(int count = 0; count < (size / SectorSize); count++)
697        flashDisk->read(&(readaddr[SectorSize*count]), (offset /
698                                                        SectorSize) + count);
699}
700
701/**
702 * Write to the flashdisk
703 */
704
705void
706UFSHostDevice::UFSSCSIDevice::writeFlash(uint8_t* writeaddr, uint64_t offset,
707                                    uint32_t size)
708{
709    /** Get from fifo and write to image*/
710    for(int count = 0; count < (size / SectorSize); count++)
711        flashDisk->write(&(writeaddr[SectorSize * count]),
712                         (offset / SectorSize) + count);
713}
714
715/**
716 * Constructor for the UFS Host device
717 */
718
719UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams* p) :
720    DmaDevice(p),
721    pioAddr(p->pio_addr),
722    pioSize(0x0FFF),
723    pioDelay(p->pio_latency),
724    intNum(p->int_num),
725    gic(p->gic),
726    lunAvail(p->image.size()),
727    UFSSlots(p->ufs_slots - 1),
728    readPendingNum(0),
729    writePendingNum(0),
730    activeDoorbells(0),
731    pendingDoorbells(0),
732    countInt(0),
733    transferTrack(0),
734    taskCommandTrack(0),
735    idlePhaseStart(0),
736    drainManager(NULL),
737    SCSIResumeEvent(this),
738    UTPEvent(this)
739{
740    DPRINTF(UFSHostDevice, "The hostcontroller hosts %d Logic units\n",
741            lunAvail);
742    UFSDevice.resize(lunAvail);
743
744    transferDoneCallback = new MakeCallback<UFSHostDevice,
745        &UFSHostDevice::LUNSignal>(this);
746    memReadCallback = new MakeCallback<UFSHostDevice,
747        &UFSHostDevice::readCallback>(this);
748
749    for(int count = 0; count < lunAvail; count++) {
750        UFSDevice[count] = new UFSSCSIDevice(p, count, transferDoneCallback,
751                                             memReadCallback);
752    }
753
754    if (UFSSlots > 31)
755        warn("UFSSlots = %d, this will results in %d command slots",
756             UFSSlots, (UFSSlots & 0x1F));
757
758    if ((UFSSlots & 0x1F) == 0)
759        fatal("Number of UFS command slots should be between 1 and 32.");
760
761    setValues();
762}
763
764/**
765 * Create the parameters of this device
766 */
767
768UFSHostDevice*
769UFSHostDeviceParams::create()
770{
771    return new UFSHostDevice(this);
772}
773
774
775void
776UFSHostDevice::regStats()
777{
778    using namespace Stats;
779
780    std::string UFSHost_name = name() + ".UFSDiskHost";
781
782    // Register the stats
783    /** Queue lengths */
784    stats.currentSCSIQueue
785        .name(UFSHost_name + ".currentSCSIQueue")
786        .desc("Most up to date length of the command queue")
787        .flags(none);
788    stats.currentReadSSDQueue
789        .name(UFSHost_name + ".currentReadSSDQueue")
790        .desc("Most up to date length of the read SSD queue")
791        .flags(none);
792    stats.currentWriteSSDQueue
793        .name(UFSHost_name + ".currentWriteSSDQueue")
794        .desc("Most up to date length of the write SSD queue")
795        .flags(none);
796
797    /** Amount of data read/written */
798    stats.totalReadSSD
799        .name(UFSHost_name + ".totalReadSSD")
800        .desc("Number of bytes read from SSD")
801        .flags(none);
802
803    stats.totalWrittenSSD
804        .name(UFSHost_name + ".totalWrittenSSD")
805        .desc("Number of bytes written to SSD")
806        .flags(none);
807
808    stats.totalReadDiskTransactions
809        .name(UFSHost_name + ".totalReadDiskTransactions")
810        .desc("Number of transactions from disk")
811        .flags(none);
812    stats.totalWriteDiskTransactions
813        .name(UFSHost_name + ".totalWriteDiskTransactions")
814        .desc("Number of transactions to disk")
815        .flags(none);
816    stats.totalReadUFSTransactions
817        .name(UFSHost_name + ".totalReadUFSTransactions")
818        .desc("Number of transactions from device")
819        .flags(none);
820    stats.totalWriteUFSTransactions
821        .name(UFSHost_name + ".totalWriteUFSTransactions")
822        .desc("Number of transactions to device")
823        .flags(none);
824
825    /** Average bandwidth for reads and writes */
826    stats.averageReadSSDBW
827        .name(UFSHost_name + ".averageReadSSDBandwidth")
828        .desc("Average read bandwidth (bytes/s)")
829        .flags(nozero);
830
831    stats.averageReadSSDBW = stats.totalReadSSD / simSeconds;
832
833    stats.averageWriteSSDBW
834        .name(UFSHost_name + ".averageWriteSSDBandwidth")
835        .desc("Average write bandwidth (bytes/s)")
836        .flags(nozero);
837
838    stats.averageWriteSSDBW = stats.totalWrittenSSD / simSeconds;
839
840    stats.averageSCSIQueue
841        .name(UFSHost_name + ".averageSCSIQueueLength")
842        .desc("Average command queue length")
843        .flags(nozero);
844    stats.averageReadSSDQueue
845        .name(UFSHost_name + ".averageReadSSDQueueLength")
846        .desc("Average read queue length")
847        .flags(nozero);
848    stats.averageWriteSSDQueue
849        .name(UFSHost_name + ".averageWriteSSDQueueLength")
850        .desc("Average write queue length")
851        .flags(nozero);
852
853    /** Number of doorbells rung*/
854    stats.curDoorbell
855        .name(UFSHost_name + ".curDoorbell")
856        .desc("Most up to date number of doorbells used")
857        .flags(none);
858
859    stats.curDoorbell = activeDoorbells;
860
861    stats.maxDoorbell
862        .name(UFSHost_name + ".maxDoorbell")
863        .desc("Maximum number of doorbells utilized")
864        .flags(none);
865    stats.averageDoorbell
866        .name(UFSHost_name + ".averageDoorbell")
867        .desc("Average number of Doorbells used")
868        .flags(nozero);
869
870    /** Latency*/
871    stats.transactionLatency
872        .init(100)
873        .name(UFSHost_name + ".transactionLatency")
874        .desc("Histogram of transaction times")
875        .flags(pdf);
876
877    stats.idleTimes
878        .init(100)
879        .name(UFSHost_name + ".idlePeriods")
880        .desc("Histogram of idle times")
881        .flags(pdf);
882
883}
884
885/**
886 * Register init
887 */
888void UFSHostDevice::setValues()
889{
890    /**
891     * The capability register is built up as follows:
892     * 31-29 RES; Testmode support; O3 delivery; 64 bit addr;
893     * 23-19 RES; 18-16 #TM Req slots; 15-5 RES;4-0 # TR slots
894     */
895    UFSHCIMem.HCCAP = 0x06070000 | (UFSSlots & 0x1F);
896    UFSHCIMem.HCversion = 0x00010000; //version is 1.0
897    UFSHCIMem.HCHCDDID = 0xAA003C3C;// Arbitrary number
898    UFSHCIMem.HCHCPMID = 0x41524D48; //ARMH (not an official MIPI number)
899    UFSHCIMem.TRUTRLDBR = 0x00;
900    UFSHCIMem.TMUTMRLDBR = 0x00;
901    UFSHCIMem.CMDUICCMDR = 0x00;
902    // We can process CMD, TM, TR, device present
903    UFSHCIMem.ORHostControllerStatus = 0x08;
904    UFSHCIMem.TRUTRLBA = 0x00;
905    UFSHCIMem.TRUTRLBAU = 0x00;
906    UFSHCIMem.TMUTMRLBA = 0x00;
907    UFSHCIMem.TMUTMRLBAU = 0x00;
908}
909
910/**
911 * Determine address ranges
912 */
913
914AddrRangeList
915UFSHostDevice::getAddrRanges() const
916{
917    AddrRangeList ranges;
918    ranges.push_back(RangeSize(pioAddr, pioSize));
919    return ranges;
920}
921
922/**
923 * UFSHCD read register. This function allows the system to read the
924 * register entries
925 */
926
927Tick
928UFSHostDevice::read(PacketPtr pkt)
929{
930    uint32_t data = 0;
931
932    switch (pkt->getAddr() & 0xFF)
933    {
934
935      case regControllerCapabilities:
936        data = UFSHCIMem.HCCAP;
937        break;
938
939      case regUFSVersion:
940        data = UFSHCIMem.HCversion;
941        break;
942
943      case regControllerDEVID:
944        data = UFSHCIMem.HCHCDDID;
945        break;
946
947      case regControllerPRODID:
948        data = UFSHCIMem.HCHCPMID;
949        break;
950
951      case regInterruptStatus:
952        data = UFSHCIMem.ORInterruptStatus;
953        UFSHCIMem.ORInterruptStatus = 0x00;
954        //TODO: Revise and extend
955        clearInterrupt();
956        break;
957
958      case regInterruptEnable:
959        data = UFSHCIMem.ORInterruptEnable;
960        break;
961
962      case regControllerStatus:
963        data = UFSHCIMem.ORHostControllerStatus;
964        break;
965
966      case regControllerEnable:
967        data = UFSHCIMem.ORHostControllerEnable;
968        break;
969
970      case regUICErrorCodePHYAdapterLayer:
971        data = UFSHCIMem.ORUECPA;
972        break;
973
974      case regUICErrorCodeDataLinkLayer:
975        data = UFSHCIMem.ORUECDL;
976        break;
977
978      case regUICErrorCodeNetworkLayer:
979        data = UFSHCIMem.ORUECN;
980        break;
981
982      case regUICErrorCodeTransportLayer:
983        data = UFSHCIMem.ORUECT;
984        break;
985
986      case regUICErrorCodeDME:
987        data = UFSHCIMem.ORUECDME;
988        break;
989
990      case regUTPTransferREQINTAGGControl:
991        data = UFSHCIMem.ORUTRIACR;
992        break;
993
994      case regUTPTransferREQListBaseL:
995        data = UFSHCIMem.TRUTRLBA;
996        break;
997
998      case regUTPTransferREQListBaseH:
999        data = UFSHCIMem.TRUTRLBAU;
1000        break;
1001
1002      case regUTPTransferREQDoorbell:
1003        data = UFSHCIMem.TRUTRLDBR;
1004        break;
1005
1006      case regUTPTransferREQListClear:
1007        data = UFSHCIMem.TRUTRLCLR;
1008        break;
1009
1010      case regUTPTransferREQListRunStop:
1011        data = UFSHCIMem.TRUTRLRSR;
1012        break;
1013
1014      case regUTPTaskREQListBaseL:
1015        data = UFSHCIMem.TMUTMRLBA;
1016        break;
1017
1018      case regUTPTaskREQListBaseH:
1019        data = UFSHCIMem.TMUTMRLBAU;
1020        break;
1021
1022      case regUTPTaskREQDoorbell:
1023        data = UFSHCIMem.TMUTMRLDBR;
1024        break;
1025
1026      case regUTPTaskREQListClear:
1027        data = UFSHCIMem.TMUTMRLCLR;
1028        break;
1029
1030      case regUTPTaskREQListRunStop:
1031        data = UFSHCIMem.TMUTMRLRSR;
1032        break;
1033
1034      case regUICCommand:
1035        data = UFSHCIMem.CMDUICCMDR;
1036        break;
1037
1038      case regUICCommandArg1:
1039        data = UFSHCIMem.CMDUCMDARG1;
1040        break;
1041
1042      case regUICCommandArg2:
1043        data = UFSHCIMem.CMDUCMDARG2;
1044        break;
1045
1046      case regUICCommandArg3:
1047        data = UFSHCIMem.CMDUCMDARG3;
1048        break;
1049
1050      default:
1051        data = 0x00;
1052        break;
1053    }
1054
1055    pkt->set<uint32_t>(data);
1056    pkt->makeResponse();
1057    return pioDelay;
1058}
1059
1060/**
1061 * UFSHCD write function. This function allows access to the writeable
1062 * registers. If any function attempts to write value to an unwriteable
1063 * register entry, then the value will not be written.
1064 */
1065Tick
1066UFSHostDevice::write(PacketPtr pkt)
1067{
1068    uint32_t data = 0;
1069
1070    switch (pkt->getSize()) {
1071
1072      case 1:
1073        data = pkt->get<uint8_t>();
1074        break;
1075
1076      case 2:
1077        data = pkt->get<uint16_t>();
1078        break;
1079
1080      case 4:
1081        data = pkt->get<uint32_t>();
1082        break;
1083
1084      default:
1085        panic("Undefined UFSHCD controller write size!\n");
1086        break;
1087    }
1088
1089    switch (pkt->getAddr() & 0xFF)
1090    {
1091      case regControllerCapabilities://you shall not write to this
1092        break;
1093
1094      case regUFSVersion://you shall not write to this
1095        break;
1096
1097      case regControllerDEVID://you shall not write to this
1098        break;
1099
1100      case regControllerPRODID://you shall not write to this
1101        break;
1102
1103      case regInterruptStatus://you shall not write to this
1104        break;
1105
1106      case regInterruptEnable:
1107        UFSHCIMem.ORInterruptEnable = data;
1108        break;
1109
1110      case regControllerStatus:
1111        UFSHCIMem.ORHostControllerStatus = data;
1112        break;
1113
1114      case regControllerEnable:
1115        UFSHCIMem.ORHostControllerEnable = data;
1116        break;
1117
1118      case regUICErrorCodePHYAdapterLayer:
1119        UFSHCIMem.ORUECPA = data;
1120        break;
1121
1122      case regUICErrorCodeDataLinkLayer:
1123        UFSHCIMem.ORUECDL = data;
1124        break;
1125
1126      case regUICErrorCodeNetworkLayer:
1127        UFSHCIMem.ORUECN = data;
1128        break;
1129
1130      case regUICErrorCodeTransportLayer:
1131        UFSHCIMem.ORUECT = data;
1132        break;
1133
1134      case regUICErrorCodeDME:
1135        UFSHCIMem.ORUECDME = data;
1136        break;
1137
1138      case regUTPTransferREQINTAGGControl:
1139        UFSHCIMem.ORUTRIACR = data;
1140        break;
1141
1142      case regUTPTransferREQListBaseL:
1143        UFSHCIMem.TRUTRLBA = data;
1144        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1145            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
1146            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1147        break;
1148
1149      case regUTPTransferREQListBaseH:
1150        UFSHCIMem.TRUTRLBAU = data;
1151        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1152            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1153            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1154        break;
1155
1156      case regUTPTransferREQDoorbell:
1157        if (!(UFSHCIMem.TRUTRLDBR) && data)
1158            stats.idleTimes.sample(curTick() - idlePhaseStart);
1159        UFSHCIMem.TRUTRLDBR |= data;
1160        requestHandler();
1161        break;
1162
1163      case regUTPTransferREQListClear:
1164        UFSHCIMem.TRUTRLCLR = data;
1165        break;
1166
1167      case regUTPTransferREQListRunStop:
1168        UFSHCIMem.TRUTRLRSR = data;
1169        break;
1170
1171      case regUTPTaskREQListBaseL:
1172        UFSHCIMem.TMUTMRLBA = data;
1173        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1174            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1175            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1176        break;
1177
1178      case regUTPTaskREQListBaseH:
1179        UFSHCIMem.TMUTMRLBAU = data;
1180        if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1181            ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1182            UFSHCIMem.ORHostControllerStatus |= UICCommandReady;
1183        break;
1184
1185      case regUTPTaskREQDoorbell:
1186        UFSHCIMem.TMUTMRLDBR |= data;
1187        requestHandler();
1188        break;
1189
1190      case regUTPTaskREQListClear:
1191        UFSHCIMem.TMUTMRLCLR = data;
1192        break;
1193
1194      case regUTPTaskREQListRunStop:
1195        UFSHCIMem.TMUTMRLRSR = data;
1196        break;
1197
1198      case regUICCommand:
1199        UFSHCIMem.CMDUICCMDR = data;
1200        requestHandler();
1201        break;
1202
1203      case regUICCommandArg1:
1204        UFSHCIMem.CMDUCMDARG1 = data;
1205        break;
1206
1207      case regUICCommandArg2:
1208        UFSHCIMem.CMDUCMDARG2 = data;
1209        break;
1210
1211      case regUICCommandArg3:
1212        UFSHCIMem.CMDUCMDARG3 = data;
1213        break;
1214
1215      default:break;//nothing happens, you try to access a register that
1216                    //does not exist
1217
1218    }
1219
1220    pkt->makeResponse();
1221    return pioDelay;
1222}
1223
1224/**
1225 * Request handler. Determines where the request comes from and initiates the
1226 * appropriate actions accordingly.
1227 */
1228
1229void
1230UFSHostDevice::requestHandler()
1231{
1232    Addr address = 0x00;
1233    int mask = 0x01;
1234    int size;
1235    int count = 0;
1236    struct taskStart task_info;
1237    struct transferStart transferstart_info;
1238    transferstart_info.done = 0;
1239
1240    /**
1241     * step1 determine what called us
1242     * step2 determine where to get it
1243     * Look for any request of which we where not yet aware
1244     */
1245    while (((UFSHCIMem.CMDUICCMDR > 0x00) |
1246            ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
1247            ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
1248
1249        if (UFSHCIMem.CMDUICCMDR > 0x00) {
1250            /**
1251             * Command; general control of the Host controller.
1252             * no DMA transfer needed
1253             */
1254            commandHandler();
1255            UFSHCIMem.ORInterruptStatus |= UICCommandCOMPL;
1256            generateInterrupt();
1257            UFSHCIMem.CMDUICCMDR = 0x00;
1258            return; //command, nothing more we can do
1259
1260        } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
1261            /**
1262             * Task; flow control, meant for the device/Logic unit
1263             * DMA transfer is needed, flash will not be approached
1264             */
1265            size = sizeof(UTPUPIUTaskReq);
1266            /**Find the position that is not handled yet*/
1267            count = findLsbSet((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack));
1268            address = UFSHCIMem.TMUTMRLBAU;
1269            //<-64 bit
1270            address = (count * size) + (address << 32) +
1271                UFSHCIMem.TMUTMRLBA;
1272            taskCommandTrack |= mask << count;
1273
1274            inform("UFSmodel received a task from the system; this might"
1275                   " lead to untested behaviour.\n");
1276
1277            task_info.mask = mask << count;
1278            task_info.address = address;
1279            task_info.size = size;
1280            task_info.done = UFSHCIMem.TMUTMRLDBR;
1281            taskInfo.push_back(task_info);
1282            taskEventQueue.push_back(this);
1283            writeDevice(&taskEventQueue.back(), false, address, size,
1284                        reinterpret_cast<uint8_t*>
1285                        (&taskInfo.back().destination), 0, 0);
1286
1287        } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
1288            /**
1289             * Transfer; Data transfer from or to the disk. There will be DMA
1290             * transfers, and the flash might be approached. Further
1291             * commands, are needed to specify the exact command.
1292             */
1293            size = sizeof(UTPTransferReqDesc);
1294            /**Find the position that is not handled yet*/
1295            count = findLsbSet((UFSHCIMem.TRUTRLDBR ^ transferTrack));
1296            address = UFSHCIMem.TRUTRLBAU;
1297            //<-64 bit
1298            address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
1299
1300            transferTrack |= mask << count;
1301            DPRINTF(UFSHostDevice, "Doorbell register: 0x%8x select #:"
1302                    " 0x%8x completion info: 0x%8x\n", UFSHCIMem.TRUTRLDBR,
1303                    count, transferstart_info.done);
1304
1305            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1306
1307            /**stats**/
1308            transactionStart[count] = curTick(); //note the start time
1309            ++activeDoorbells;
1310            stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
1311                ? activeDoorbells : stats.maxDoorbell.value();
1312            stats.averageDoorbell = stats.maxDoorbell.value();
1313
1314            /**
1315             * step3 start transfer
1316             * step4 register information; allowing the host to respond in
1317             * the end
1318             */
1319            transferstart_info.mask = mask << count;
1320            transferstart_info.address = address;
1321            transferstart_info.size = size;
1322            transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1323            transferStartInfo.push_back(transferstart_info);
1324
1325            /**Deleted in readDone, queued in finalUTP*/
1326            transferStartInfo.back().destination = new struct
1327                UTPTransferReqDesc;
1328            DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
1329                    transferstart_info.done);
1330            transferEventQueue.push_back(this);
1331
1332            if (transferEventQueue.size() < 2) {
1333                writeDevice(&transferEventQueue.front(), false,
1334                            address, size, reinterpret_cast<uint8_t*>
1335                            (transferStartInfo.front().destination),0, 0);
1336                DPRINTF(UFSHostDevice, "Transfer scheduled\n");
1337            }
1338        }
1339    }
1340}
1341
1342/**
1343 * Task start event
1344 */
1345
1346void
1347UFSHostDevice::taskStart()
1348{
1349    DPRINTF(UFSHostDevice, "Task start");
1350    taskHandler(&taskInfo.front().destination, taskInfo.front().mask,
1351                taskInfo.front().address, taskInfo.front().size);
1352    taskInfo.pop_front();
1353    taskEventQueue.pop_front();
1354}
1355
1356/**
1357 * Transfer start event
1358 */
1359
1360void
1361UFSHostDevice::transferStart()
1362{
1363    DPRINTF(UFSHostDevice, "Enter transfer event\n");
1364    transferHandler(transferStartInfo.front().destination,
1365                    transferStartInfo.front().mask,
1366                    transferStartInfo.front().address,
1367                    transferStartInfo.front().size,
1368                    transferStartInfo.front().done);
1369
1370    transferStartInfo.pop_front();
1371    DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
1372            "0x%8x\n", transferEventQueue.size());
1373}
1374
1375/**
1376 * Handles the commands that are given. At this point in time, not many
1377 * commands have been implemented in the driver.
1378 */
1379
1380void
1381UFSHostDevice::commandHandler()
1382{
1383    if (UFSHCIMem.CMDUICCMDR == 0x16) {
1384        UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
1385    }
1386
1387}
1388
1389/**
1390 * Handles the tasks that are given. At this point in time, not many tasks
1391 * have been implemented in the driver.
1392 */
1393
1394void
1395UFSHostDevice::taskHandler(struct UTPUPIUTaskReq* request_in,
1396                           uint32_t req_pos, Addr finaladdress, uint32_t
1397                           finalsize)
1398{
1399    /**
1400     * For now, just unpack and acknowledge the task without doing anything.
1401     * TODO Implement UFS tasks.
1402     */
1403    inform("taskHandler\n");
1404    inform("%8x\n", request_in->header.dWord0);
1405    inform("%8x\n", request_in->header.dWord1);
1406    inform("%8x\n", request_in->header.dWord2);
1407
1408    request_in->header.dWord2 &= 0xffffff00;
1409
1410    UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
1411    taskCommandTrack &= ~(req_pos);
1412    UFSHCIMem.ORInterruptStatus |= UTPTaskREQCOMPL;
1413
1414    readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
1415               (request_in), true, NULL);
1416
1417}
1418
1419/**
1420 * Obtains the SCSI command (if any)
1421 * Two possibilities: if it contains a SCSI command, then it is a usable
1422 * message; if it doesnt contain a SCSI message, then it can't be handeld
1423 * by this code.
1424 * This is the second stage of the transfer. We have the information about
1425 * where the next command can be found and what the type of command is. The
1426 * actions that are needed from the device its side are: get the information
1427 * and store the information such that we can reply.
1428 */
1429
1430void
1431UFSHostDevice::transferHandler(struct UTPTransferReqDesc* request_in,
1432                               int req_pos, Addr finaladdress, uint32_t
1433                               finalsize, uint32_t done)
1434{
1435
1436    Addr cmd_desc_addr = 0x00;
1437
1438
1439    //acknowledge handling of the message
1440    DPRINTF(UFSHostDevice, "SCSI message detected\n");
1441    request_in->header.dWord2 &= 0xffffff00;
1442    SCSIInfo.RequestIn = request_in;
1443    SCSIInfo.reqPos = req_pos;
1444    SCSIInfo.finalAddress = finaladdress;
1445    SCSIInfo.finalSize = finalsize;
1446    SCSIInfo.destination.resize(request_in->PRDTableOffset * 4
1447        + request_in->PRDTableLength * sizeof(UFSHCDSGEntry));
1448    SCSIInfo.done = done;
1449
1450    assert(!SCSIResumeEvent.scheduled());
1451    /**
1452     *Get the UTP command that has the SCSI command
1453     */
1454    cmd_desc_addr = request_in->commandDescBaseAddrHi;
1455    cmd_desc_addr = (cmd_desc_addr << 32) |
1456        (request_in->commandDescBaseAddrLo & 0xffffffff);
1457
1458    writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
1459                SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
1460
1461    DPRINTF(UFSHostDevice, "SCSI scheduled\n");
1462
1463    transferEventQueue.pop_front();
1464}
1465
1466/**
1467 * Obtain LUN and put it in the right LUN queue. Each LUN has its own queue
1468 * of commands that need to be executed. This is the first instance where it
1469 * can be determined which Logic unit should handle the transfer. Then check
1470 * wether it should wait and queue or if it can continue.
1471 */
1472
1473void
1474UFSHostDevice::SCSIStart()
1475{
1476    DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
1477    uint32_t LUN = SCSIInfo.destination[2];
1478    UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
1479
1480    DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
1481            UFSDevice[LUN]->SCSIInfoQueue.size());
1482
1483    /**There are 32 doorbells, so at max there can be 32 transactions*/
1484    if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
1485        SCSIResume(LUN);
1486
1487    else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
1488        panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
1489              SCSIInfoQueue.size());
1490
1491    /**
1492     * First transfer is done, fetch the next;
1493     * At this point, the device is busy, not the HC
1494     */
1495    if (!transferEventQueue.empty()) {
1496
1497        /**
1498         * loading next data packet in case Another LUN
1499         * is approached in the mean time
1500         */
1501        writeDevice(&transferEventQueue.front(), false,
1502                    transferStartInfo.front().address,
1503                    transferStartInfo.front().size, reinterpret_cast<uint8_t*>
1504                    (transferStartInfo.front().destination), 0, 0);
1505
1506        DPRINTF(UFSHostDevice, "Transfer scheduled");
1507    }
1508}
1509
1510/**
1511 * Handles the transfer requests that are given.
1512 * There can be three types of transfer. SCSI specific, Reads and writes
1513 * apart from the data transfer, this also generates its own reply (UPIU
1514 * response). Information for this reply is stored in transferInfo and will
1515 * be used in transferDone
1516 */
1517
1518void
1519UFSHostDevice::SCSIResume(uint32_t lun_id)
1520{
1521    DPRINTF(UFSHostDevice, "SCSIresume\n");
1522    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1523        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1524              UFSHCIMem.TRUTRLDBR);
1525
1526    /**old info, lets form it such that we can understand it*/
1527    struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
1528        SCSIInfoQueue.front().RequestIn;
1529
1530    uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
1531
1532    Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
1533        finalAddress;
1534
1535    uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
1536
1537    uint32_t* transfercommand = reinterpret_cast<uint32_t*>
1538        (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
1539
1540    DPRINTF(UFSHostDevice, "Task tag: 0x%8x\n", transfercommand[0]>>24);
1541    /**call logic unit to handle SCSI command*/
1542    request_out_datain = UFSDevice[(transfercommand[0] & 0xFF0000) >> 16]->
1543        SCSICMDHandle(transfercommand);
1544
1545    DPRINTF(UFSHostDevice, "LUN: %d\n", request_out_datain.LUN);
1546
1547    /**
1548     * build response stating that it was succesful
1549     * command completion, Logic unit number, and Task tag
1550     */
1551    request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
1552        ? 0x36 : 0x21;
1553    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord0 =
1554        request_in->header.dWord0 | (request_out_datain.LUN << 8)
1555        | (transfercommand[0] & 0xFF000000);
1556    /**SCSI status reply*/
1557    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord1 = 0x00000000 |
1558        (request_out_datain.status << 24);
1559    /**segment size + EHS length (see UFS standard ch7)*/
1560    UFSDevice[lun_id]->transferInfo.requestOut.header.dWord2 = 0x00000000 |
1561        ((request_out_datain.senseSize + 2) << 24) | 0x05;
1562    /**amount of data that will follow*/
1563    UFSDevice[lun_id]->transferInfo.requestOut.senseDataLen =
1564        request_out_datain.senseSize;
1565
1566    //data
1567    for (uint8_t count = 0; count<request_out_datain.senseSize; count++) {
1568        UFSDevice[lun_id]->transferInfo.requestOut.senseData[count] =
1569            request_out_datain.senseCode[count + 1];
1570    }
1571
1572    /*
1573     * At position defined by "request_in->PRDTableOffset" (counting 32 bit
1574     * words) in array "transfercommand" we have a scatter gather list, which
1575     * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
1576     */
1577    struct UFSHCDSGEntry* sglist =  reinterpret_cast<UFSHCDSGEntry*>
1578        (&(transfercommand[(request_in->PRDTableOffset)]));
1579
1580    uint32_t length = request_in->PRDTableLength;
1581    DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
1582
1583    Addr response_addr = request_in->commandDescBaseAddrHi;
1584    response_addr = (response_addr << 32) |
1585        ((request_in->commandDescBaseAddrLo +
1586          (request_in->responseUPIULength << 2)) & 0xffffffff);
1587
1588    /**transferdone information packet filling*/
1589    UFSDevice[lun_id]->transferInfo.responseStartAddr = response_addr;
1590    UFSDevice[lun_id]->transferInfo.reqPos = req_pos;
1591    UFSDevice[lun_id]->transferInfo.size = finalsize;
1592    UFSDevice[lun_id]->transferInfo.address = finaladdress;
1593    UFSDevice[lun_id]->transferInfo.destination = reinterpret_cast<uint8_t*>
1594        (UFSDevice[lun_id]->SCSIInfoQueue.front().RequestIn);
1595    UFSDevice[lun_id]->transferInfo.finished = true;
1596    UFSDevice[lun_id]->transferInfo.lunID = request_out_datain.LUN;
1597
1598    /**
1599     * In this part the data that needs to be transfered will be initiated
1600     * and the chain of DMA (and potentially) disk transactions will be
1601     * started.
1602     */
1603    if (request_out_datain.expectMore == 0x01) {
1604        /**write transfer*/
1605        manageWriteTransfer(request_out_datain.LUN, request_out_datain.offset,
1606                            length, sglist);
1607
1608    } else if (request_out_datain.expectMore == 0x02) {
1609        /**read transfer*/
1610        manageReadTransfer(request_out_datain.msgSize, request_out_datain.LUN,
1611                           request_out_datain.offset, length, sglist);
1612
1613    } else {
1614        /**not disk related transfer, SCSI maintanance*/
1615        uint32_t count = 0;
1616        uint32_t size_accum = 0;
1617        DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1618                request_out_datain.msgSize);
1619
1620        /**Transport the SCSI reponse data according to the SG list*/
1621        while ((length > count) && size_accum
1622               < (request_out_datain.msgSize - 1) &&
1623               (request_out_datain.msgSize != 0x00)) {
1624            Addr SCSI_start = sglist[count].upperAddr;
1625            SCSI_start = (SCSI_start << 32) |
1626                (sglist[count].baseAddr & 0xFFFFFFFF);
1627            DPRINTF(UFSHostDevice, "Data DMA start: 0x%8x\n", SCSI_start);
1628            DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1629                    (sglist[count].size + 1));
1630            /**
1631             * safetynet; it has been shown that sg list may be optimistic in
1632             * the amount of data allocated, which can potentially lead to
1633             * some garbage data being send over. Hence this construction
1634             * that finds the least amount of data that needs to be
1635             * transfered.
1636             */
1637            uint32_t size_to_send = sglist[count].size + 1;
1638
1639            if (request_out_datain.msgSize < (size_to_send + size_accum))
1640                size_to_send = request_out_datain.msgSize - size_accum;
1641
1642            readDevice(false, SCSI_start, size_to_send,
1643                       reinterpret_cast<uint8_t*>
1644                       (&(request_out_datain.message.dataMsg[size_accum])),
1645                       false, NULL);
1646
1647            size_accum += size_to_send;
1648            DPRINTF(UFSHostDevice, "Total remaining: 0x%8x,accumulated so far"
1649                    " : 0x%8x\n", (request_out_datain.msgSize - size_accum),
1650                    size_accum);
1651
1652            ++count;
1653            DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
1654        }
1655
1656        /**Go to the next stage of the answering process*/
1657        transferDone(response_addr, req_pos, UFSDevice[lun_id]->
1658                     transferInfo.requestOut, finalsize, finaladdress,
1659                     reinterpret_cast<uint8_t*>(request_in), true, lun_id);
1660    }
1661
1662    DPRINTF(UFSHostDevice, "SCSI resume done\n");
1663}
1664
1665/**
1666 * Find finished transfer. Callback function. One of the LUNs is done with
1667 * the disk transfer and reports back to the controller. This function finds
1668 * out who it was, and calls transferDone.
1669 */
1670void
1671UFSHostDevice::LUNSignal()
1672{
1673    uint8_t this_lun = 0;
1674
1675    //while we haven't found the right lun, keep searching
1676    while((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
1677        ++this_lun;
1678
1679    if (this_lun < lunAvail) {
1680        //Clear signal.
1681        UFSDevice[this_lun]->clearSignal();
1682        //found it; call transferDone
1683        transferDone(UFSDevice[this_lun]->transferInfo.responseStartAddr,
1684                     UFSDevice[this_lun]->transferInfo.reqPos,
1685                     UFSDevice[this_lun]->transferInfo.requestOut,
1686                     UFSDevice[this_lun]->transferInfo.size,
1687                     UFSDevice[this_lun]->transferInfo.address,
1688                     UFSDevice[this_lun]->transferInfo.destination,
1689                     UFSDevice[this_lun]->transferInfo.finished,
1690                     UFSDevice[this_lun]->transferInfo.lunID);
1691    }
1692
1693    else
1694        panic("no LUN finished in tick %d\n", curTick());
1695}
1696
1697/**
1698 * Transfer done. When the data transfer is done, this function ensures
1699 * that the application is notified.
1700 */
1701
1702void
1703UFSHostDevice::transferDone(Addr responseStartAddr, uint32_t req_pos,
1704                            struct UTPUPIURSP request_out, uint32_t size,
1705                            Addr address, uint8_t* destination,
1706                            bool finished, uint32_t lun_id)
1707{
1708    /**Test whether SCSI queue hasn't popped prematurely*/
1709    if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1710        panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1711              UFSHCIMem.TRUTRLDBR);
1712
1713    DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1714            responseStartAddr, sizeof(request_out));
1715
1716    struct transferStart lastinfo;
1717    lastinfo.mask = req_pos;
1718    lastinfo.done = finished;
1719    lastinfo.address = address;
1720    lastinfo.size = size;
1721    lastinfo.destination = reinterpret_cast<UTPTransferReqDesc*>
1722        (destination);
1723    lastinfo.lun_id = lun_id;
1724
1725    transferEnd.push_back(lastinfo);
1726
1727    DPRINTF(UFSHostDevice, "Transfer done start\n");
1728
1729    readDevice(false, responseStartAddr, sizeof(request_out),
1730               reinterpret_cast<uint8_t*>
1731               (&(UFSDevice[lun_id]->transferInfo.requestOut)),
1732               true, &UTPEvent);
1733}
1734
1735/**
1736 * finalUTP. Second part of the transfer done event.
1737 * this sends the final response: the UTP response. After this transaction
1738 * the doorbell shall be cleared, and the interupt shall be set.
1739 */
1740
1741void
1742UFSHostDevice::finalUTP()
1743{
1744    uint32_t lun_id = transferEnd.front().lun_id;
1745
1746    UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
1747    DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
1748            UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
1749
1750    /**stats**/
1751    if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
1752        uint8_t count = 0;
1753        while (!(transferEnd.front().mask & (0x1 << count)))
1754            ++count;
1755        stats.transactionLatency.sample(curTick() -
1756                                        transactionStart[count]);
1757    }
1758
1759    /**Last message that will be transfered*/
1760    readDevice(true, transferEnd.front().address,
1761               transferEnd.front().size, reinterpret_cast<uint8_t*>
1762               (transferEnd.front().destination), true, NULL);
1763
1764    /**clean and ensure that the tracker is updated*/
1765    transferTrack &= ~(transferEnd.front().mask);
1766    --activeDoorbells;
1767    ++pendingDoorbells;
1768    garbage.push_back(transferEnd.front().destination);
1769    transferEnd.pop_front();
1770    DPRINTF(UFSHostDevice, "UTP handled\n");
1771
1772    /**stats**/
1773    stats.averageDoorbell = stats.maxDoorbell.value();
1774
1775    DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
1776            " garbage: %d, TransferEvent: %d\n", activeDoorbells,
1777            pendingDoorbells, garbage.size(), transferEventQueue.size());
1778
1779    /**This is the moment that the device is available again*/
1780    if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
1781        SCSIResume(lun_id);
1782}
1783
1784/**
1785 * Read done handling function, is only initiated at the end of a transaction
1786 */
1787void
1788UFSHostDevice::readDone()
1789{
1790    DPRINTF(UFSHostDevice, "Read done start\n");
1791    --readPendingNum;
1792
1793    /**Garbage collection; sort out the allocated UTP descriptor*/
1794    if (garbage.size() > 0) {
1795        delete garbage.front();
1796        garbage.pop_front();
1797        }
1798
1799    /**done, generate interrupt if we havent got one already*/
1800    if(!(UFSHCIMem.ORInterruptStatus & 0x01)) {
1801        UFSHCIMem.ORInterruptStatus |= UTPTransferREQCOMPL;
1802        generateInterrupt();
1803    }
1804
1805
1806    if(!readDoneEvent.empty()) {
1807        readDoneEvent.pop_front();
1808    }
1809}
1810
1811/**
1812 * set interrupt and sort out the doorbell register.
1813 */
1814
1815void
1816UFSHostDevice::generateInterrupt()
1817{
1818    /**just to keep track of the transactions*/
1819    countInt++;
1820
1821    /**step5 clear doorbell*/
1822    UFSHCIMem.TRUTRLDBR &= transferTrack;
1823    pendingDoorbells = 0;
1824    DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
1825
1826    /**step6 raise interrupt*/
1827    gic->sendInt(intNum);
1828    DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
1829            countInt);
1830}
1831
1832/**
1833 * Clear interrupt
1834 */
1835
1836void
1837UFSHostDevice::clearInterrupt()
1838{
1839    gic->clearInt(intNum);
1840    DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
1841
1842    if (!(UFSHCIMem.TRUTRLDBR)) {
1843        idlePhaseStart = curTick();
1844    }
1845    /**end of a transaction*/
1846}
1847
1848/**
1849 * Important to understand about the transfer flow:
1850 * We have basically three stages, The "system memory" stage, the "device
1851 * buffer" stage and the "disk" stage. In this model we assume an infinite
1852 * buffer, or a buffer that is big enough to store all the data in the
1853 * biggest transaction. Between the three stages are two queues. Those queues
1854 * store the messages to simulate their transaction from one stage to the
1855 * next. The manage{Action} function fills up one of the queues and triggers
1856 * the first event, which causes a chain reaction of events executed once
1857 * they pass through their queues. For a write action the stages are ordered
1858 * "system memory", "device buffer" and "disk", whereas the read transfers
1859 * happen "disk", "device buffer" and "system memory". The dma action in the
1860 * dma device is written from a bus perspective whereas this model is written
1861 * from a device perspective. To avoid confusion, the translation between the
1862 * two has been made in the writeDevice and readDevice funtions.
1863 */
1864
1865
1866/**
1867 * Dma transaction function: write device. Note that the dma action is
1868 * from a device perspective, while this function is from an initiator
1869 * perspective
1870 */
1871
1872void
1873UFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
1874                           start, int size, uint8_t* destination, uint64_t
1875                           SCSIDiskOffset, uint32_t lun_id)
1876{
1877    DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
1878            start, size);
1879
1880    /**check whether transfer is all the way to the flash*/
1881    if (toDisk) {
1882        ++writePendingNum;
1883
1884        while(!writeDoneEvent.empty() && (writeDoneEvent.front().when()
1885                                          < curTick()))
1886            writeDoneEvent.pop_front();
1887
1888        writeDoneEvent.push_back(this);
1889        assert(!writeDoneEvent.back().scheduled());
1890
1891        /**destination is an offset here since we are writing to a disk*/
1892        struct transferInfo new_transfer;
1893        new_transfer.offset = SCSIDiskOffset;
1894        new_transfer.size = size;
1895        new_transfer.lunID = lun_id;
1896        new_transfer.filePointer = 0;
1897        SSDWriteinfo.push_back(new_transfer);
1898
1899        /**allocate appropriate buffer*/
1900        SSDWriteinfo.back().buffer.resize(size);
1901
1902        /**transaction*/
1903        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1904                          &writeDoneEvent.back(),
1905                          &SSDWriteinfo.back().buffer[0], 0);
1906        //yes, a readreq at a write device function is correct.
1907        DPRINTF(UFSHostDevice, "Write to disk scheduled\n");
1908
1909    } else {
1910        assert(!additional_action->scheduled());
1911        dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1912                          additional_action, destination, 0);
1913        DPRINTF(UFSHostDevice, "Write scheduled\n");
1914    }
1915}
1916
1917/**
1918 * Manage write transfer. Manages correct transfer flow and makes sure that
1919 * the queues are filled on time
1920 */
1921
1922void
1923UFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
1924                                   sg_table_length, struct UFSHCDSGEntry*
1925                                   sglist)
1926{
1927    struct writeToDiskBurst next_packet;
1928
1929    next_packet.SCSIDiskOffset = offset;
1930
1931    UFSDevice[LUN]->setTotalWrite(sg_table_length);
1932
1933    /**
1934     * Break-up the transactions into actions defined by the scatter gather
1935     * list.
1936     */
1937    for (uint32_t count = 0; count < sg_table_length; count++) {
1938        next_packet.start = sglist[count].upperAddr;
1939        next_packet.start = (next_packet.start << 32) |
1940            (sglist[count].baseAddr & 0xFFFFFFFF);
1941        next_packet.LUN = LUN;
1942        DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n",
1943                next_packet.start);
1944        DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
1945                (sglist[count].size + 1));
1946        assert(sglist[count].size > 0);
1947
1948        if (count != 0)
1949            next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
1950                (sglist[count - 1].size + 1);
1951
1952        next_packet.size = sglist[count].size + 1;
1953
1954        /**If the queue is empty, the transaction should be initiated*/
1955        if (dmaWriteInfo.empty())
1956            writeDevice(NULL, true, next_packet.start, next_packet.size,
1957                        NULL, next_packet.SCSIDiskOffset, next_packet.LUN);
1958        else
1959            DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
1960                    dmaWriteInfo.size());
1961
1962        dmaWriteInfo.push_back(next_packet);
1963        DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
1964                next_packet.SCSIDiskOffset);
1965
1966        DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
1967
1968        /** stats **/
1969        stats.totalWrittenSSD += (sglist[count].size + 1);
1970    }
1971
1972    /**stats**/
1973    ++stats.totalWriteUFSTransactions;
1974}
1975
1976/**
1977 * Write done handling function. Is only initiated when the flash is directly
1978 * approached
1979 */
1980
1981void
1982UFSHostDevice::writeDone()
1983{
1984    /**DMA is done, information no longer needed*/
1985    assert(dmaWriteInfo.size() > 0);
1986    dmaWriteInfo.pop_front();
1987    assert(SSDWriteinfo.size() > 0);
1988    uint32_t lun = SSDWriteinfo.front().lunID;
1989
1990    /**If there is nothing on the way, we need to start the events*/
1991    DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n",
1992            UFSDevice[lun]->SSDWriteDoneInfo.size());
1993    /**Write the disk*/
1994    UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
1995                               SSDWriteinfo.front().offset,
1996                               SSDWriteinfo.front().size);
1997
1998    /**
1999     * Move to the second queue, enter the logic unit
2000     * This is where the disk is approached and the flash transaction is
2001     * handled SSDWriteDone will take care of the timing
2002     */
2003    UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
2004    SSDWriteinfo.pop_front();
2005
2006    --writePendingNum;
2007    /**so far, only the DMA part has been handled, lets do the disk delay*/
2008    UFSDevice[lun]->SSDWriteStart();
2009
2010    /** stats **/
2011    stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
2012    stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
2013    ++stats.totalWriteDiskTransactions;
2014
2015    /**initiate the next dma action (if any)*/
2016    if (!dmaWriteInfo.empty())
2017        writeDevice(NULL, true, dmaWriteInfo.front().start,
2018                    dmaWriteInfo.front().size,  NULL,
2019                    dmaWriteInfo.front().SCSIDiskOffset,
2020                    dmaWriteInfo.front().LUN);
2021    DPRINTF(UFSHostDevice, "Write done end\n");
2022}
2023
2024/**
2025 * SSD write start. Starts the write action in the timing model
2026 */
2027void
2028UFSHostDevice::UFSSCSIDevice::SSDWriteStart()
2029{
2030    assert(SSDWriteDoneInfo.size() > 0);
2031    flashDevice->writeMemory(
2032        SSDWriteDoneInfo.front().offset,
2033        SSDWriteDoneInfo.front().size, memWriteCallback);
2034
2035    SSDWriteDoneInfo.pop_front();
2036
2037    DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
2038            SSDWriteDoneInfo.size());
2039}
2040
2041
2042/**
2043 * SSDisk write done
2044 */
2045
2046void
2047UFSHostDevice::UFSSCSIDevice::SSDWriteDone()
2048{
2049    DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
2050            totalWrite, amountOfWriteTransfers);
2051
2052    //we have done one extra transfer
2053    ++amountOfWriteTransfers;
2054
2055    /**test whether call was correct*/
2056    assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
2057
2058    /**are we there yet? (did we do everything)*/
2059    if (totalWrite == amountOfWriteTransfers) {
2060        DPRINTF(UFSHostDevice, "Write transactions finished\n");
2061        totalWrite = 0;
2062        amountOfWriteTransfers = 0;
2063
2064        //Callback UFS Host
2065        setSignal();
2066        signalDone->process();
2067    }
2068
2069}
2070
2071/**
2072 * Dma transaction function: read device. Notice that the dma action is from
2073 * a device perspective, while this function is from an initiator perspective
2074 */
2075
2076void
2077UFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
2078                          uint8_t* destination, bool no_cache, Event*
2079                          additional_action)
2080{
2081    DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2082            start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
2083
2084    /** check wether interrupt is needed */
2085    if (lastTransfer) {
2086        ++readPendingNum;
2087        readDoneEvent.push_back(this);
2088        assert(!readDoneEvent.back().scheduled());
2089        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2090                          &readDoneEvent.back(), destination, 0);
2091        //yes, a writereq at a read device function is correct.
2092
2093    } else {
2094        if (additional_action != NULL)
2095            assert(!additional_action->scheduled());
2096
2097        dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2098                          additional_action, destination, 0);
2099
2100    }
2101
2102}
2103
2104/**
2105 * Manage read transfer. Manages correct transfer flow and makes sure that
2106 * the queues are filled on time
2107 */
2108
2109void
2110UFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
2111                                  offset, uint32_t sg_table_length,
2112                                  struct UFSHCDSGEntry* sglist)
2113{
2114    uint32_t size_accum = 0;
2115
2116    DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
2117
2118    /**
2119     * Break-up the transactions into actions defined by the scatter gather
2120     * list.
2121     */
2122    for (uint32_t count = 0; count < sg_table_length; count++) {
2123        struct transferInfo new_transfer;
2124        new_transfer.offset = sglist[count].upperAddr;
2125        new_transfer.offset = (new_transfer.offset << 32) |
2126            (sglist[count].baseAddr & 0xFFFFFFFF);
2127        new_transfer.filePointer = offset + size_accum;
2128        new_transfer.size = (sglist[count].size + 1);
2129        new_transfer.lunID = LUN;
2130
2131        DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
2132                new_transfer.offset, new_transfer.size);
2133
2134        UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
2135        UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
2136                                                         + 1);
2137
2138        /**
2139         * The disk image is read here; but the action is simultated later
2140         * You can see this as the preparation stage, whereas later is the
2141         * simulation phase.
2142         */
2143        UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
2144                                  SSDReadInfo.back().buffer[0],
2145                                  offset + size_accum,
2146                                  sglist[count].size + 1);
2147
2148        size_accum += (sglist[count].size + 1);
2149
2150        DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2151                " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
2152
2153        /** stats **/
2154        stats.totalReadSSD += (sglist[count].size + 1);
2155        stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2156        stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2157    }
2158
2159    UFSDevice[LUN]->SSDReadStart(sg_table_length);
2160
2161    /** stats **/
2162    ++stats.totalReadUFSTransactions;
2163
2164}
2165
2166
2167
2168/**
2169 * SSDisk start read; this function was created to keep the interfaces
2170 * between the layers simpler. Without this function UFSHost would need to
2171 * know about the flashdevice.
2172 */
2173
2174void
2175UFSHostDevice::UFSSCSIDevice::SSDReadStart(uint32_t total_read)
2176{
2177    totalRead = total_read;
2178    for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
2179         number_handled++) {
2180        /**
2181         * Load all the read request to the Memory device.
2182         * It will call back when done.
2183         */
2184        flashDevice->readMemory(SSDReadInfo.front().filePointer,
2185                                SSDReadInfo.front().size, memReadCallback);
2186    }
2187
2188}
2189
2190
2191/**
2192 * SSDisk read done
2193 */
2194
2195void
2196UFSHostDevice::UFSSCSIDevice::SSDReadDone()
2197{
2198    DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
2199            " %d so far\n", lunID, totalRead, amountOfReadTransfers);
2200
2201    if (totalRead == amountOfReadTransfers) {
2202        totalRead = 0;
2203        amountOfReadTransfers = 0;
2204
2205        /**Callback: transferdone*/
2206        setSignal();
2207        signalDone->process();
2208    }
2209
2210}
2211
2212/**
2213 * Read callback, on the way from the disk to the DMA. Called by the flash
2214 * layer. Intermediate step to the host layer
2215 */
2216void
2217UFSHostDevice::UFSSCSIDevice::readCallback()
2218{
2219    ++amountOfReadTransfers;
2220
2221    /**Callback; make sure data is transfered upstream:
2222     * UFSHostDevice::readCallback
2223     */
2224    setReadSignal();
2225    deviceReadCallback->process();
2226
2227    //Are we done yet?
2228    SSDReadDone();
2229}
2230
2231/**
2232 * Read callback, on the way from the disk to the DMA. Called by the UFSSCSI
2233 * layer.
2234 */
2235
2236void
2237UFSHostDevice::readCallback()
2238{
2239    DPRINTF(UFSHostDevice, "Read Callback\n");
2240    uint8_t this_lun = 0;
2241
2242    //while we haven't found the right lun, keep searching
2243    while((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
2244        ++this_lun;
2245
2246    DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
2247            this_lun, SSDReadPending.size());
2248
2249    if (this_lun < lunAvail) {
2250        //Clear signal.
2251        UFSDevice[this_lun]->clearReadSignal();
2252        SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front());
2253        UFSDevice[this_lun]->SSDReadInfo.pop_front();
2254        readGarbageEventQueue.push_back(this);
2255
2256        //make sure the queue is popped a the end of the dma transaction
2257        readDevice(false, SSDReadPending.front().offset,
2258                   SSDReadPending.front().size,
2259                   &SSDReadPending.front().buffer[0], false,
2260                   &readGarbageEventQueue.back());
2261
2262        /**stats*/
2263        ++stats.totalReadDiskTransactions;
2264    }
2265    else
2266        panic("no read finished in tick %d\n", curTick());
2267}
2268
2269/**
2270 * After a disk read DMA transfer, the structure needs to be freed. This is
2271 * done in this function.
2272 */
2273void
2274UFSHostDevice::readGarbage()
2275{
2276    DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
2277    SSDReadPending.pop_front();
2278    readGarbageEventQueue.pop_front();
2279}
2280
2281/**
2282 * Serialize; needed to make checkpoints
2283 */
2284
2285void
2286UFSHostDevice::serialize(CheckpointOut &cp) const
2287{
2288    DmaDevice::serialize(cp);
2289
2290    const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
2291    SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2292
2293    uint32_t lun_avail = lunAvail;
2294    SERIALIZE_SCALAR(lun_avail);
2295}
2296
2297
2298/**
2299 * Unserialize; needed to restore from checkpoints
2300 */
2301
2302void
2303UFSHostDevice::unserialize(CheckpointIn &cp)
2304{
2305    DmaDevice::unserialize(cp);
2306    uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
2307    UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2308
2309    uint32_t lun_avail;
2310    UNSERIALIZE_SCALAR(lun_avail);
2311    assert(lunAvail == lun_avail);
2312}
2313
2314
2315/**
2316 * Drain; needed to enable checkpoints
2317 */
2318
2319unsigned int
2320UFSHostDevice::drain(DrainManager *dm)
2321{
2322    if (UFSHCIMem.TRUTRLDBR) {
2323        drainManager = dm;
2324        DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
2325        setDrainState(DrainState::Draining);
2326        return 1;
2327    } else {
2328        DPRINTF(UFSHostDevice, "UFSDevice drained\n");
2329        setDrainState(DrainState::Drained);
2330        return 0;
2331    }
2332}
2333
2334/**
2335 * Checkdrain; needed to enable checkpoints
2336 */
2337
2338void
2339UFSHostDevice::checkDrain()
2340{
2341    if (drainManager == NULL) {
2342        return;
2343    }
2344
2345    if (UFSHCIMem.TRUTRLDBR) {
2346        DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
2347            " doorbells\n", activeDoorbells);
2348    } else {
2349        DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
2350        drainManager->signalDrainDone();
2351        drainManager = NULL;
2352    }
2353}
2354