gem5  v22.1.0.0
ufs_device.cc
Go to the documentation of this file.
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 
70 #include "dev/arm/ufs_device.hh"
71 
72 namespace gem5
73 {
74 
79  uint32_t lun_id, const Callback &transfer_cb,
80  const Callback &read_cb):
81  SimObject(p),
82  flashDisk(p.image[lun_id]),
83  flashDevice(p.internalflash[lun_id]),
84  blkSize(p.img_blk_size),
85  lunAvail(p.image.size()),
86  diskSize(flashDisk->size()),
87  capacityLower((diskSize - 1) & 0xffffffff),
88  capacityUpper((diskSize - SectorSize) >> 32),
89  lunID(lun_id),
90  transferCompleted(false),
91  readCompleted(false),
92  totalRead(0),
93  totalWrite(0),
94  amountOfWriteTransfers(0),
95  amountOfReadTransfers(0)
96 {
102  signalDone = transfer_cb;
103  memReadCallback = [this]() { readCallback(); };
104  deviceReadCallback = read_cb;
105  memWriteCallback = [this]() { SSDWriteDone(); };
106 
111  uint32_t temp_id = ((lun_id | 0x30) << 24) | 0x3A4449;
112  lunInfo.dWord0 = 0x02060000; //data
113  lunInfo.dWord1 = 0x0200001F;
114  lunInfo.vendor0 = 0x484D5241; //ARMH (HMRA)
115  lunInfo.vendor1 = 0x424D4143; //CAMB (BMAC)
116  lunInfo.product0 = 0x356D6567; //gem5 (5meg)
117  lunInfo.product1 = 0x4D534655; //UFSM (MSFU)
118  lunInfo.product2 = 0x4C45444F; //ODEL (LEDO)
119  lunInfo.product3 = temp_id; // ID:"lun_id" ("lun_id":DI)
120  lunInfo.productRevision = 0x01000000; //0x01
121 
122  DPRINTF(UFSHostDevice, "Logic unit %d assumes that %d logic units are"
123  " present in the system\n", lunID, lunAvail);
124  DPRINTF(UFSHostDevice,"The disksize of lun: %d should be %d blocks\n",
125  lunID, diskSize);
127 }
128 
129 
135 const unsigned int UFSHostDevice::UFSSCSIDevice::controlPage[3] =
136  {0x01400A0A, 0x00000000,
137  0x0000FFFF};
138 const unsigned int UFSHostDevice::UFSSCSIDevice::recoveryPage[3] =
139  {0x03800A01, 0x00000000,
140  0xFFFF0003};
141 const unsigned int UFSHostDevice::UFSSCSIDevice::cachingPage[5] =
142  {0x00011208, 0x00000000,
143  0x00000000, 0x00000020,
144  0x00000000};
145 
147 
160 UFSHostDevice::UFSSCSIDevice::SCSICMDHandle(uint32_t* SCSI_msg)
161 {
162  struct SCSIReply scsi_out;
163  scsi_out.reset();
164 
169  scsi_out.message.header.dWord0 = UPIUHeaderDataIndWord0 |
170  lunID << 16;
171  scsi_out.message.header.dWord1 = UPIUHeaderDataIndWord1;
172  scsi_out.message.header.dWord2 = UPIUHeaderDataIndWord2;
173  statusCheck(SCSIGood, scsi_out.senseCode);
174  scsi_out.senseSize = scsi_out.senseCode[0];
175  scsi_out.LUN = lunID;
176  scsi_out.status = SCSIGood;
177 
178  DPRINTF(UFSHostDevice, "SCSI command:%2x\n", SCSI_msg[4]);
181  switch (SCSI_msg[4] & 0xFF) {
182 
183  case SCSIInquiry: {
187  scsi_out.msgSize = 36;
188  scsi_out.message.dataMsg.resize(9);
189 
190  for (uint8_t count = 0; count < 9; count++)
191  scsi_out.message.dataMsg[count] =
192  (reinterpret_cast<uint32_t*> (&lunInfo))[count];
193  } break;
194 
195  case SCSIRead6: {
199  scsi_out.expectMore = 0x02;
200  scsi_out.msgSize = 0;
201 
202  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
203 
208  uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
209  uint64_t read_offset = betoh(tmp) & 0x1FFFFF;
210 
211  uint32_t read_size = tempptr[4];
212 
213 
214  scsi_out.msgSize = read_size * blkSize;
215  scsi_out.offset = read_offset * blkSize;
216 
217  if ((read_offset + read_size) > diskSize)
218  scsi_out.status = SCSIIllegalRequest;
219 
220  DPRINTF(UFSHostDevice, "Read6 offset: 0x%8x, for %d blocks\n",
221  read_offset, read_size);
222 
226  statusCheck(scsi_out.status, scsi_out.senseCode);
227  scsi_out.senseSize = scsi_out.senseCode[0];
228  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
229  SCSICheckCondition;
230 
231  } break;
232 
233  case SCSIRead10: {
234  scsi_out.expectMore = 0x02;
235  scsi_out.msgSize = 0;
236 
237  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
238 
240  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
241  uint64_t read_offset = betoh(tmp);
242 
243  uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
244  uint32_t read_size = betoh(tmpsize);
245 
246  scsi_out.msgSize = read_size * blkSize;
247  scsi_out.offset = read_offset * blkSize;
248 
249  if ((read_offset + read_size) > diskSize)
250  scsi_out.status = SCSIIllegalRequest;
251 
252  DPRINTF(UFSHostDevice, "Read10 offset: 0x%8x, for %d blocks\n",
253  read_offset, read_size);
254 
258  statusCheck(scsi_out.status, scsi_out.senseCode);
259  scsi_out.senseSize = scsi_out.senseCode[0];
260  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
261  SCSICheckCondition;
262 
263  } break;
264 
265  case SCSIRead16: {
266  scsi_out.expectMore = 0x02;
267  scsi_out.msgSize = 0;
268 
269  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
270 
272  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
273  uint64_t read_offset = betoh(tmp);
274 
275  tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
276  read_offset = (read_offset << 32) | betoh(tmp);
277 
278  tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
279  uint32_t read_size = betoh(tmp);
280 
281  scsi_out.msgSize = read_size * blkSize;
282  scsi_out.offset = read_offset * blkSize;
283 
284  if ((read_offset + read_size) > diskSize)
285  scsi_out.status = SCSIIllegalRequest;
286 
287  DPRINTF(UFSHostDevice, "Read16 offset: 0x%8x, for %d blocks\n",
288  read_offset, read_size);
289 
293  statusCheck(scsi_out.status, scsi_out.senseCode);
294  scsi_out.senseSize = scsi_out.senseCode[0];
295  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
296  SCSICheckCondition;
297 
298  } break;
299 
300  case SCSIReadCapacity10: {
304  scsi_out.msgSize = 8;
305  scsi_out.message.dataMsg.resize(2);
306  scsi_out.message.dataMsg[0] =
307  betoh(capacityLower);//last block
308  scsi_out.message.dataMsg[1] = betoh(blkSize);//blocksize
309 
310  } break;
311  case SCSIReadCapacity16: {
312  scsi_out.msgSize = 32;
313  scsi_out.message.dataMsg.resize(8);
314  scsi_out.message.dataMsg[0] =
315  betoh(capacityUpper);//last block
316  scsi_out.message.dataMsg[1] =
317  betoh(capacityLower);//last block
318  scsi_out.message.dataMsg[2] = betoh(blkSize);//blocksize
319  scsi_out.message.dataMsg[3] = 0x00;//
320  scsi_out.message.dataMsg[4] = 0x00;//reserved
321  scsi_out.message.dataMsg[5] = 0x00;//reserved
322  scsi_out.message.dataMsg[6] = 0x00;//reserved
323  scsi_out.message.dataMsg[7] = 0x00;//reserved
324 
325  } break;
326 
327  case SCSIReportLUNs: {
331  scsi_out.msgSize = (lunAvail * 8) + 8;//list + overhead
332  scsi_out.message.dataMsg.resize(2 * lunAvail + 2);
333  scsi_out.message.dataMsg[0] = (lunAvail * 8) << 24;//LUN listlength
334  scsi_out.message.dataMsg[1] = 0x00;
335 
336  for (uint8_t count = 0; count < lunAvail; count++) {
337  //LUN "count"
338  scsi_out.message.dataMsg[2 + 2 * count] = (count & 0x7F) << 8;
339  scsi_out.message.dataMsg[3 + 2 * count] = 0x00;
340  }
341 
342  } break;
343 
344  case SCSIStartStop: {
345  //Just acknowledge; not deemed relevant ATM
346  scsi_out.msgSize = 0;
347 
348  } break;
349 
350  case SCSITestUnitReady: {
351  //Just acknowledge; not deemed relevant ATM
352  scsi_out.msgSize = 0;
353 
354  } break;
355 
356  case SCSIVerify10: {
361  scsi_out.msgSize = 0;
362 
363  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
364 
366  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
367  uint64_t read_offset = betoh(tmp);
368 
369  uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
370  uint32_t read_size = betoh(tmpsize);
371 
372  if ((read_offset + read_size) > diskSize)
373  scsi_out.status = SCSIIllegalRequest;
374 
378  statusCheck(scsi_out.status, scsi_out.senseCode);
379  scsi_out.senseSize = scsi_out.senseCode[0];
380  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
381  SCSICheckCondition;
382 
383  } break;
384 
385  case SCSIWrite6: {
390  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
391 
396  uint32_t tmp = *reinterpret_cast<uint32_t*>(tempptr);
397  uint64_t write_offset = betoh(tmp) & 0x1FFFFF;
398 
399  uint32_t write_size = tempptr[4];
400 
401  scsi_out.msgSize = write_size * blkSize;
402  scsi_out.offset = write_offset * blkSize;
403  scsi_out.expectMore = 0x01;
404 
405  if ((write_offset + write_size) > diskSize)
406  scsi_out.status = SCSIIllegalRequest;
407 
408  DPRINTF(UFSHostDevice, "Write6 offset: 0x%8x, for %d blocks\n",
409  write_offset, write_size);
410 
414  statusCheck(scsi_out.status, scsi_out.senseCode);
415  scsi_out.senseSize = scsi_out.senseCode[0];
416  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
417  SCSICheckCondition;
418 
419  } break;
420 
421  case SCSIWrite10: {
422  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
423 
425  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
426  uint64_t write_offset = betoh(tmp);
427 
428  uint16_t tmpsize = *reinterpret_cast<uint16_t*>(&tempptr[7]);
429  uint32_t write_size = betoh(tmpsize);
430 
431  scsi_out.msgSize = write_size * blkSize;
432  scsi_out.offset = write_offset * blkSize;
433  scsi_out.expectMore = 0x01;
434 
435  if ((write_offset + write_size) > diskSize)
436  scsi_out.status = SCSIIllegalRequest;
437 
438  DPRINTF(UFSHostDevice, "Write10 offset: 0x%8x, for %d blocks\n",
439  write_offset, write_size);
440 
444  statusCheck(scsi_out.status, scsi_out.senseCode);
445  scsi_out.senseSize = scsi_out.senseCode[0];
446  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
447  SCSICheckCondition;
448 
449  } break;
450 
451  case SCSIWrite16: {
452  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
453 
455  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
456  uint64_t write_offset = betoh(tmp);
457 
458  tmp = *reinterpret_cast<uint32_t*>(&tempptr[6]);
459  write_offset = (write_offset << 32) | betoh(tmp);
460 
461  tmp = *reinterpret_cast<uint32_t*>(&tempptr[10]);
462  uint32_t write_size = betoh(tmp);
463 
464  scsi_out.msgSize = write_size * blkSize;
465  scsi_out.offset = write_offset * blkSize;
466  scsi_out.expectMore = 0x01;
467 
468  if ((write_offset + write_size) > diskSize)
469  scsi_out.status = SCSIIllegalRequest;
470 
471  DPRINTF(UFSHostDevice, "Write16 offset: 0x%8x, for %d blocks\n",
472  write_offset, write_size);
473 
477  statusCheck(scsi_out.status, scsi_out.senseCode);
478  scsi_out.senseSize = scsi_out.senseCode[0];
479  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
480  SCSICheckCondition;
481 
482  } break;
483 
484  case SCSIFormatUnit: {//not yet verified
485  scsi_out.msgSize = 0;
486  scsi_out.expectMore = 0x01;
487 
488  } break;
489 
490  case SCSISendDiagnostic: {//not yet verified
491  scsi_out.msgSize = 0;
492 
493  } break;
494 
495  case SCSISynchronizeCache: {
496  //do we have cache (we don't have cache at this moment)
497  //TODO: here will synchronization happen when cache is modelled
498  scsi_out.msgSize = 0;
499 
500  } break;
501 
502  //UFS SCSI additional command set for full functionality
503  case SCSIModeSelect10:
504  //TODO:
505  //scsi_out.expectMore = 0x01;//not supported due to modepage support
506  //code isn't dead, code suggest what is to be done when implemented
507  break;
508 
509  case SCSIModeSense6: case SCSIModeSense10: {
514  if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x0A) {//control page
515  scsi_out.message.dataMsg.resize((sizeof(controlPage) >> 2) + 2);
516  scsi_out.message.dataMsg[0] = 0x00000A00;//control page code
517  scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
518 
519  for (uint8_t count = 0; count < 3; count++)
520  scsi_out.message.dataMsg[2 + count] = controlPage[count];
521 
522  scsi_out.msgSize = 20;
523  DPRINTF(UFSHostDevice, "CONTROL page\n");
524 
525  } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x01) {//recovery page
526  scsi_out.message.dataMsg.resize((sizeof(recoveryPage) >> 2)
527  + 2);
528 
529  scsi_out.message.dataMsg[0] = 0x00000100;//recovery page code
530  scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
531 
532  for (uint8_t count = 0; count < 3; count++)
533  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
534 
535  scsi_out.msgSize = 20;
536  DPRINTF(UFSHostDevice, "RECOVERY page\n");
537 
538  } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x08) {//caching page
539 
540  scsi_out.message.dataMsg.resize((sizeof(cachingPage) >> 2) + 2);
541  scsi_out.message.dataMsg[0] = 0x00001200;//caching page code
542  scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
543 
544  for (uint8_t count = 0; count < 5; count++)
545  scsi_out.message.dataMsg[2 + count] = cachingPage[count];
546 
547  scsi_out.msgSize = 20;
548  DPRINTF(UFSHostDevice, "CACHE page\n");
549 
550  } else if ((SCSI_msg[4] & 0x3F0000) >> 16 == 0x3F) {//ALL the pages!
551 
552  scsi_out.message.dataMsg.resize(((sizeof(controlPage) +
553  sizeof(recoveryPage) +
554  sizeof(cachingPage)) >> 2)
555  + 2);
556  scsi_out.message.dataMsg[0] = 0x00003200;//all page code
557  scsi_out.message.dataMsg[1] = 0x00000000;//See JEDEC220 ch8
558 
559  for (uint8_t count = 0; count < 3; count++)
560  scsi_out.message.dataMsg[2 + count] = recoveryPage[count];
561 
562  for (uint8_t count = 0; count < 5; count++)
563  scsi_out.message.dataMsg[5 + count] = cachingPage[count];
564 
565  for (uint8_t count = 0; count < 3; count++)
566  scsi_out.message.dataMsg[10 + count] = controlPage[count];
567 
568  scsi_out.msgSize = 52;
569  DPRINTF(UFSHostDevice, "Return ALL the pages!!!\n");
570 
571  } else inform("Wrong mode page requested\n");
572 
573  scsi_out.message.dataCount = scsi_out.msgSize << 24;
574  } break;
575 
576  case SCSIRequestSense: {
577  scsi_out.msgSize = 0;
578 
579  } break;
580 
581  case SCSIUnmap:break;//not yet verified
582 
583  case SCSIWriteBuffer: {
584  scsi_out.expectMore = 0x01;
585 
586  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
587 
589  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
590  uint64_t write_offset = betoh(tmp) & 0xFFFFFF;
591 
592  tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
593  uint32_t write_size = betoh(tmp) & 0xFFFFFF;
594 
595  scsi_out.msgSize = write_size;
596  scsi_out.offset = write_offset;
597 
598  } break;
599 
600  case SCSIReadBuffer: {
606  scsi_out.expectMore = 0x02;
607 
608  uint8_t* tempptr = reinterpret_cast<uint8_t*>(&SCSI_msg[4]);
609 
611  uint32_t tmp = *reinterpret_cast<uint32_t*>(&tempptr[2]);
612  uint64_t read_offset = betoh(tmp) & 0xFFFFFF;
613 
614  tmp = *reinterpret_cast<uint32_t*>(&tempptr[5]);
615  uint32_t read_size = betoh(tmp) & 0xFFFFFF;
616 
617  scsi_out.msgSize = read_size;
618  scsi_out.offset = read_offset;
619 
620  if ((read_offset + read_size) > capacityLower * blkSize)
621  scsi_out.status = SCSIIllegalRequest;
622 
623  DPRINTF(UFSHostDevice, "Read buffer location: 0x%8x\n",
624  read_offset);
625  DPRINTF(UFSHostDevice, "Number of bytes: 0x%8x\n", read_size);
626 
627  statusCheck(scsi_out.status, scsi_out.senseCode);
628  scsi_out.senseSize = scsi_out.senseCode[0];
629  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
630  SCSICheckCondition;
631 
632  } break;
633 
634  case SCSIMaintenanceIn: {
641  DPRINTF(UFSHostDevice, "Ignoring Maintenance In command\n");
642  statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
643  scsi_out.senseSize = scsi_out.senseCode[0];
644  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
645  SCSICheckCondition;
646  scsi_out.msgSize = 0;
647  } break;
648 
649  default: {
650  statusCheck(SCSIIllegalRequest, scsi_out.senseCode);
651  scsi_out.senseSize = scsi_out.senseCode[0];
652  scsi_out.status = (scsi_out.status == SCSIGood) ? SCSIGood :
653  SCSICheckCondition;
654  scsi_out.msgSize = 0;
655  inform("Unsupported scsi message type: %2x\n", SCSI_msg[4] & 0xFF);
656  inform("0x%8x\n", SCSI_msg[0]);
657  inform("0x%8x\n", SCSI_msg[1]);
658  inform("0x%8x\n", SCSI_msg[2]);
659  inform("0x%8x\n", SCSI_msg[3]);
660  inform("0x%8x\n", SCSI_msg[4]);
661  } break;
662  }
663 
664  return scsi_out;
665 }
666 
673 void
675  uint8_t* sensecodelist)
676 {
677  for (uint8_t count = 0; count < 19; count++)
678  sensecodelist[count] = 0;
679 
680  sensecodelist[0] = 18; //sense length
681  sensecodelist[1] = 0x70; //we send a valid frame
682  sensecodelist[3] = status & 0xF; //mask to be sure + sensecode
683  sensecodelist[8] = 0x1F; //data length
684 }
685 
690 void
692  uint32_t size)
693 {
695  for (int count = 0; count < (size / SectorSize); count++)
696  flashDisk->read(&(readaddr[SectorSize*count]), (offset /
697  SectorSize) + count);
698 }
699 
704 void
706  uint32_t size)
707 {
709  for (int count = 0; count < (size / SectorSize); count++)
710  flashDisk->write(&(writeaddr[SectorSize * count]),
711  (offset / SectorSize) + count);
712 }
713 
718 UFSHostDevice::UFSHostDevice(const UFSHostDeviceParams &p) :
719  DmaDevice(p),
720  pioAddr(p.pio_addr),
721  pioSize(0x0FFF),
722  pioDelay(p.pio_latency),
723  intNum(p.int_num),
724  gic(p.gic),
725  lunAvail(p.image.size()),
726  UFSSlots(p.ufs_slots - 1),
727  readPendingNum(0),
728  writePendingNum(0),
729  activeDoorbells(0),
730  pendingDoorbells(0),
731  countInt(0),
732  transferTrack(0),
733  taskCommandTrack(0),
734  idlePhaseStart(0),
735  stats(this),
736  SCSIResumeEvent([this]{ SCSIStart(); }, name()),
737  UTPEvent([this]{ finalUTP(); }, name())
738 {
739  DPRINTF(UFSHostDevice, "The hostcontroller hosts %d Logic units\n",
740  lunAvail);
741  UFSDevice.resize(lunAvail);
742 
743  for (int count = 0; count < lunAvail; count++) {
744  UFSDevice[count] = new UFSSCSIDevice(p, count,
745  [this]() { LUNSignal(); },
746  [this]() { readCallback(); });
747  }
748 
749  if (UFSSlots > 31)
750  warn("UFSSlots = %d, this will results in %d command slots",
751  UFSSlots, (UFSSlots & 0x1F));
752 
753  if ((UFSSlots & 0x1F) == 0)
754  fatal("Number of UFS command slots should be between 1 and 32.");
755 
756  setValues();
757 }
758 
761  : statistics::Group(parent, "UFSDiskHost"),
762  ADD_STAT(currentSCSIQueue, statistics::units::Count::get(),
763  "Most up to date length of the command queue"),
764  ADD_STAT(currentReadSSDQueue, statistics::units::Count::get(),
765  "Most up to date length of the read SSD queue"),
766  ADD_STAT(currentWriteSSDQueue, statistics::units::Count::get(),
767  "Most up to date length of the write SSD queue"),
769  ADD_STAT(totalReadSSD, statistics::units::Byte::get(),
770  "Number of bytes read from SSD"),
771  ADD_STAT(totalWrittenSSD, statistics::units::Byte::get(),
772  "Number of bytes written to SSD"),
773  ADD_STAT(totalReadDiskTransactions, statistics::units::Count::get(),
774  "Number of transactions from disk"),
775  ADD_STAT(totalWriteDiskTransactions, statistics::units::Count::get(),
776  "Number of transactions to disk"),
777  ADD_STAT(totalReadUFSTransactions, statistics::units::Count::get(),
778  "Number of transactions from device"),
779  ADD_STAT(totalWriteUFSTransactions, statistics::units::Count::get(),
780  "Number of transactions to device"),
782  ADD_STAT(averageReadSSDBW, statistics::units::Rate<
783  statistics::units::Byte, statistics::units::Second>::get(),
784  "Average read bandwidth",
785  totalReadSSD / simSeconds),
786  ADD_STAT(averageWriteSSDBW, statistics::units::Rate<
787  statistics::units::Byte, statistics::units::Second>::get(),
788  "Average write bandwidth",
789  totalWrittenSSD / simSeconds),
790  ADD_STAT(averageSCSIQueue, statistics::units::Rate<
791  statistics::units::Count, statistics::units::Tick>::get(),
792  "Average command queue length"),
793  ADD_STAT(averageReadSSDQueue, statistics::units::Rate<
794  statistics::units::Count, statistics::units::Tick>::get(),
795  "Average read queue length"),
796  ADD_STAT(averageWriteSSDQueue, statistics::units::Rate<
797  statistics::units::Count, statistics::units::Tick>::get(),
798  "Average write queue length"),
800  ADD_STAT(curDoorbell, statistics::units::Count::get(),
801  "Most up to date number of doorbells used",
802  parent->activeDoorbells),
803  ADD_STAT(maxDoorbell, statistics::units::Count::get(),
804  "Maximum number of doorbells utilized"),
805  ADD_STAT(averageDoorbell, statistics::units::Rate<
806  statistics::units::Count, statistics::units::Tick>::get(),
807  "Average number of Doorbells used"),
809  ADD_STAT(transactionLatency, statistics::units::Tick::get(),
810  "Histogram of transaction times"),
811  ADD_STAT(idleTimes, statistics::units::Tick::get(), "Histogram of idle times")
812 {
813  using namespace statistics;
814 
815  // Register the stats
818  .flags(none);
820  .flags(none);
822  .flags(none);
823 
826  .flags(none);
827 
829  .flags(none);
830 
832  .flags(none);
834  .flags(none);
836  .flags(none);
838  .flags(none);
839 
842  .flags(nozero);
843 
845  .flags(nozero);
846 
848  .flags(nozero);
850  .flags(nozero);
852  .flags(nozero);
853 
856  .flags(none);
857 
859  .flags(none);
861  .flags(nozero);
862 
865  .init(100)
866  .flags(pdf);
867 
868  idleTimes
869  .init(100)
870  .flags(pdf);
871 }
872 
877 {
883  UFSHCIMem.HCCAP = 0x06070000 | (UFSSlots & 0x1F);
884  UFSHCIMem.HCversion = 0x00010000; //version is 1.0
885  UFSHCIMem.HCHCDDID = 0xAA003C3C;// Arbitrary number
886  UFSHCIMem.HCHCPMID = 0x41524D48; //ARMH (not an official MIPI number)
887  UFSHCIMem.TRUTRLDBR = 0x00;
888  UFSHCIMem.TMUTMRLDBR = 0x00;
889  UFSHCIMem.CMDUICCMDR = 0x00;
890  // We can process CMD, TM, TR, device present
892  UFSHCIMem.TRUTRLBA = 0x00;
893  UFSHCIMem.TRUTRLBAU = 0x00;
894  UFSHCIMem.TMUTMRLBA = 0x00;
895  UFSHCIMem.TMUTMRLBAU = 0x00;
896 }
897 
904 {
905  AddrRangeList ranges;
906  ranges.push_back(RangeSize(pioAddr, pioSize));
907  return ranges;
908 }
909 
915 Tick
917 {
918  uint32_t data = 0;
919 
920  switch (pkt->getAddr() & 0xFF)
921  {
922 
924  data = UFSHCIMem.HCCAP;
925  break;
926 
927  case regUFSVersion:
929  break;
930 
931  case regControllerDEVID:
933  break;
934 
935  case regControllerPRODID:
937  break;
938 
939  case regInterruptStatus:
942  //TODO: Revise and extend
943  clearInterrupt();
944  break;
945 
946  case regInterruptEnable:
948  break;
949 
950  case regControllerStatus:
952  break;
953 
954  case regControllerEnable:
956  break;
957 
960  break;
961 
964  break;
965 
968  break;
969 
972  break;
973 
974  case regUICErrorCodeDME:
976  break;
977 
980  break;
981 
984  break;
985 
988  break;
989 
992  break;
993 
996  break;
997 
1000  break;
1001 
1004  break;
1005 
1008  break;
1009 
1010  case regUTPTaskREQDoorbell:
1012  break;
1013 
1016  break;
1017 
1020  break;
1021 
1022  case regUICCommand:
1024  break;
1025 
1026  case regUICCommandArg1:
1028  break;
1029 
1030  case regUICCommandArg2:
1032  break;
1033 
1034  case regUICCommandArg3:
1036  break;
1037 
1038  default:
1039  data = 0x00;
1040  break;
1041  }
1042 
1043  pkt->setLE<uint32_t>(data);
1044  pkt->makeResponse();
1045  return pioDelay;
1046 }
1047 
1053 Tick
1055 {
1056  assert(pkt->getSize() <= 4);
1057 
1058  const uint32_t data = pkt->getUintX(ByteOrder::little);
1059 
1060  switch (pkt->getAddr() & 0xFF)
1061  {
1062  case regControllerCapabilities://you shall not write to this
1063  break;
1064 
1065  case regUFSVersion://you shall not write to this
1066  break;
1067 
1068  case regControllerDEVID://you shall not write to this
1069  break;
1070 
1071  case regControllerPRODID://you shall not write to this
1072  break;
1073 
1074  case regInterruptStatus://you shall not write to this
1075  break;
1076 
1077  case regInterruptEnable:
1079  break;
1080 
1081  case regControllerStatus:
1083  break;
1084 
1085  case regControllerEnable:
1087  break;
1088 
1091  break;
1092 
1095  break;
1096 
1098  UFSHCIMem.ORUECN = data;
1099  break;
1100 
1102  UFSHCIMem.ORUECT = data;
1103  break;
1104 
1105  case regUICErrorCodeDME:
1107  break;
1108 
1111  break;
1112 
1115  if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1116  ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU)!= 0x00))
1118  break;
1119 
1122  if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1123  ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1125  break;
1126 
1128  if (!(UFSHCIMem.TRUTRLDBR) && data)
1129  stats.idleTimes.sample(curTick() - idlePhaseStart);
1131  requestHandler();
1132  break;
1133 
1136  break;
1137 
1140  break;
1141 
1144  if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1145  ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1147  break;
1148 
1151  if (((UFSHCIMem.TRUTRLBA | UFSHCIMem.TRUTRLBAU) != 0x00) &&
1152  ((UFSHCIMem.TMUTMRLBA | UFSHCIMem.TMUTMRLBAU) != 0x00))
1154  break;
1155 
1156  case regUTPTaskREQDoorbell:
1158  requestHandler();
1159  break;
1160 
1163  break;
1164 
1167  break;
1168 
1169  case regUICCommand:
1171  requestHandler();
1172  break;
1173 
1174  case regUICCommandArg1:
1176  break;
1177 
1178  case regUICCommandArg2:
1180  break;
1181 
1182  case regUICCommandArg3:
1184  break;
1185 
1186  default:break;//nothing happens, you try to access a register that
1187  //does not exist
1188 
1189  }
1190 
1191  pkt->makeResponse();
1192  return pioDelay;
1193 }
1194 
1200 void
1202 {
1203  Addr address = 0x00;
1204  int mask = 0x01;
1205  int size;
1206  int count = 0;
1207  struct taskStart task_info;
1208  struct transferStart transferstart_info;
1209  transferstart_info.done = 0;
1210 
1216  while (((UFSHCIMem.CMDUICCMDR > 0x00) |
1217  ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) |
1218  ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00)) ) {
1219 
1220  if (UFSHCIMem.CMDUICCMDR > 0x00) {
1225  commandHandler();
1228  UFSHCIMem.CMDUICCMDR = 0x00;
1229  return; //command, nothing more we can do
1230 
1231  } else if ((UFSHCIMem.TMUTMRLDBR ^ taskCommandTrack) > 0x00) {
1236  size = sizeof(UTPUPIUTaskReq);
1239  address = UFSHCIMem.TMUTMRLBAU;
1240  //<-64 bit
1241  address = (count * size) + (address << 32) +
1243  taskCommandTrack |= mask << count;
1244 
1245  inform("UFSmodel received a task from the system; this might"
1246  " lead to untested behaviour.\n");
1247 
1248  task_info.mask = mask << count;
1249  task_info.address = address;
1250  task_info.size = size;
1251  task_info.done = UFSHCIMem.TMUTMRLDBR;
1252  taskInfo.push_back(task_info);
1253  taskEventQueue.push_back(
1254  EventFunctionWrapper([this]{ taskStart(); }, name()));
1255  writeDevice(&taskEventQueue.back(), false, address, size,
1256  reinterpret_cast<uint8_t*>
1257  (&taskInfo.back().destination), 0, 0);
1258 
1259  } else if ((UFSHCIMem.TRUTRLDBR ^ transferTrack) > 0x00) {
1265  size = sizeof(UTPTransferReqDesc);
1268  address = UFSHCIMem.TRUTRLBAU;
1269  //<-64 bit
1270  address = (count * size) + (address << 32) + UFSHCIMem.TRUTRLBA;
1271 
1272  transferTrack |= mask << count;
1273  DPRINTF(UFSHostDevice, "Doorbell register: 0x%8x select #:"
1274  " 0x%8x completion info: 0x%8x\n", UFSHCIMem.TRUTRLDBR,
1275  count, transferstart_info.done);
1276 
1277  transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1278 
1280  transactionStart[count] = curTick(); //note the start time
1281  ++activeDoorbells;
1282  stats.maxDoorbell = (stats.maxDoorbell.value() < activeDoorbells)
1283  ? activeDoorbells : stats.maxDoorbell.value();
1284  stats.averageDoorbell = stats.maxDoorbell.value();
1285 
1291  transferstart_info.mask = mask << count;
1292  transferstart_info.address = address;
1293  transferstart_info.size = size;
1294  transferstart_info.done = UFSHCIMem.TRUTRLDBR;
1295  transferStartInfo.push_back(transferstart_info);
1296 
1298  transferStartInfo.back().destination = new struct
1300  DPRINTF(UFSHostDevice, "Initial transfer start: 0x%8x\n",
1301  transferstart_info.done);
1302  transferEventQueue.push_back(
1303  EventFunctionWrapper([this]{ transferStart(); }, name()));
1304 
1305  if (transferEventQueue.size() < 2) {
1306  writeDevice(&transferEventQueue.front(), false,
1307  address, size, reinterpret_cast<uint8_t*>
1308  (transferStartInfo.front().destination),0, 0);
1309  DPRINTF(UFSHostDevice, "Transfer scheduled\n");
1310  }
1311  }
1312  }
1313 }
1314 
1319 void
1321 {
1322  DPRINTF(UFSHostDevice, "Task start");
1323  taskHandler(&taskInfo.front().destination, taskInfo.front().mask,
1324  taskInfo.front().address, taskInfo.front().size);
1325  taskInfo.pop_front();
1326  taskEventQueue.pop_front();
1327 }
1328 
1333 void
1335 {
1336  DPRINTF(UFSHostDevice, "Enter transfer event\n");
1337  transferHandler(transferStartInfo.front().destination,
1338  transferStartInfo.front().mask,
1339  transferStartInfo.front().address,
1340  transferStartInfo.front().size,
1341  transferStartInfo.front().done);
1342 
1343  transferStartInfo.pop_front();
1344  DPRINTF(UFSHostDevice, "Transfer queue size at end of event: "
1345  "0x%8x\n", transferEventQueue.size());
1346 }
1347 
1353 void
1355 {
1356  if (UFSHCIMem.CMDUICCMDR == 0x16) {
1357  UFSHCIMem.ORHostControllerStatus |= 0x0F;//link startup
1358  }
1359 
1360 }
1361 
1367 void
1369  uint32_t req_pos, Addr finaladdress, uint32_t
1370  finalsize)
1371 {
1376  inform("taskHandler\n");
1377  inform("%8x\n", request_in->header.dWord0);
1378  inform("%8x\n", request_in->header.dWord1);
1379  inform("%8x\n", request_in->header.dWord2);
1380 
1381  request_in->header.dWord2 &= 0xffffff00;
1382 
1383  UFSHCIMem.TMUTMRLDBR &= ~(req_pos);
1384  taskCommandTrack &= ~(req_pos);
1386 
1387  readDevice(true, finaladdress, finalsize, reinterpret_cast<uint8_t*>
1388  (request_in), true, NULL);
1389 
1390 }
1391 
1403 void
1405  int req_pos, Addr finaladdress, uint32_t
1406  finalsize, uint32_t done)
1407 {
1408 
1409  Addr cmd_desc_addr = 0x00;
1410 
1411 
1412  //acknowledge handling of the message
1413  DPRINTF(UFSHostDevice, "SCSI message detected\n");
1414  request_in->header.dWord2 &= 0xffffff00;
1415  SCSIInfo.RequestIn = request_in;
1416  SCSIInfo.reqPos = req_pos;
1417  SCSIInfo.finalAddress = finaladdress;
1418  SCSIInfo.finalSize = finalsize;
1419  SCSIInfo.destination.resize(request_in->PRDTableOffset * 4
1420  + request_in->PRDTableLength * sizeof(UFSHCDSGEntry));
1421  SCSIInfo.done = done;
1422 
1423  assert(!SCSIResumeEvent.scheduled());
1427  cmd_desc_addr = request_in->commandDescBaseAddrHi;
1428  cmd_desc_addr = (cmd_desc_addr << 32) |
1429  (request_in->commandDescBaseAddrLo & 0xffffffff);
1430 
1431  writeDevice(&SCSIResumeEvent, false, cmd_desc_addr,
1432  SCSIInfo.destination.size(), &SCSIInfo.destination[0],0, 0);
1433 
1434  DPRINTF(UFSHostDevice, "SCSI scheduled\n");
1435 
1436  transferEventQueue.pop_front();
1437 }
1438 
1446 void
1448 {
1449  DPRINTF(UFSHostDevice, "SCSI message on hold until ready\n");
1450  uint32_t LUN = SCSIInfo.destination[2];
1451  UFSDevice[LUN]->SCSIInfoQueue.push_back(SCSIInfo);
1452 
1453  DPRINTF(UFSHostDevice, "SCSI queue %d has %d elements\n", LUN,
1454  UFSDevice[LUN]->SCSIInfoQueue.size());
1455 
1457  if (UFSDevice[LUN]->SCSIInfoQueue.size() < 2) //LUN is available
1458  SCSIResume(LUN);
1459 
1460  else if (UFSDevice[LUN]->SCSIInfoQueue.size() > 32)
1461  panic("SCSI queue is getting too big %d\n", UFSDevice[LUN]->
1462  SCSIInfoQueue.size());
1463 
1468  if (!transferEventQueue.empty()) {
1469 
1474  writeDevice(&transferEventQueue.front(), false,
1475  transferStartInfo.front().address,
1476  transferStartInfo.front().size, reinterpret_cast<uint8_t*>
1477  (transferStartInfo.front().destination), 0, 0);
1478 
1479  DPRINTF(UFSHostDevice, "Transfer scheduled");
1480  }
1481 }
1482 
1491 void
1493 {
1494  DPRINTF(UFSHostDevice, "SCSIresume\n");
1495  if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1496  panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1498 
1500  struct UTPTransferReqDesc* request_in = UFSDevice[lun_id]->
1501  SCSIInfoQueue.front().RequestIn;
1502 
1503  uint32_t req_pos = UFSDevice[lun_id]->SCSIInfoQueue.front().reqPos;
1504 
1505  Addr finaladdress = UFSDevice[lun_id]->SCSIInfoQueue.front().
1506  finalAddress;
1507 
1508  uint32_t finalsize = UFSDevice[lun_id]->SCSIInfoQueue.front().finalSize;
1509 
1510  uint32_t* transfercommand = reinterpret_cast<uint32_t*>
1511  (&(UFSDevice[lun_id]->SCSIInfoQueue.front().destination[0]));
1512 
1513  DPRINTF(UFSHostDevice, "Task tag: 0x%8x\n", transfercommand[0]>>24);
1515  request_out_datain = UFSDevice[(transfercommand[0] & 0xFF0000) >> 16]->
1516  SCSICMDHandle(transfercommand);
1517 
1519 
1524  request_in->header.dWord0 = ((request_in->header.dWord0 >> 24) == 0x21)
1525  ? 0x36 : 0x21;
1526  UFSDevice[lun_id]->transferInfo.requestOut.header.dWord0 =
1527  request_in->header.dWord0 | (request_out_datain.LUN << 8)
1528  | (transfercommand[0] & 0xFF000000);
1530  UFSDevice[lun_id]->transferInfo.requestOut.header.dWord1 = 0x00000000 |
1531  (request_out_datain.status << 24);
1533  UFSDevice[lun_id]->transferInfo.requestOut.header.dWord2 = 0x00000000 |
1534  ((request_out_datain.senseSize + 2) << 24) | 0x05;
1536  UFSDevice[lun_id]->transferInfo.requestOut.senseDataLen =
1538 
1539  //data
1540  for (uint8_t count = 0; count<request_out_datain.senseSize; count++) {
1541  UFSDevice[lun_id]->transferInfo.requestOut.senseData[count] =
1543  }
1544 
1545  /*
1546  * At position defined by "request_in->PRDTableOffset" (counting 32 bit
1547  * words) in array "transfercommand" we have a scatter gather list, which
1548  * is usefull to us if we interpreted it as a UFSHCDSGEntry structure.
1549  */
1550  struct UFSHCDSGEntry* sglist = reinterpret_cast<UFSHCDSGEntry*>
1551  (&(transfercommand[(request_in->PRDTableOffset)]));
1552 
1553  uint32_t length = request_in->PRDTableLength;
1554  DPRINTF(UFSHostDevice, "# PRDT entries: %d\n", length);
1555 
1556  Addr response_addr = request_in->commandDescBaseAddrHi;
1557  response_addr = (response_addr << 32) |
1558  ((request_in->commandDescBaseAddrLo +
1559  (request_in->responseUPIULength << 2)) & 0xffffffff);
1560 
1562  UFSDevice[lun_id]->transferInfo.responseStartAddr = response_addr;
1563  UFSDevice[lun_id]->transferInfo.reqPos = req_pos;
1564  UFSDevice[lun_id]->transferInfo.size = finalsize;
1565  UFSDevice[lun_id]->transferInfo.address = finaladdress;
1566  UFSDevice[lun_id]->transferInfo.destination = reinterpret_cast<uint8_t*>
1567  (UFSDevice[lun_id]->SCSIInfoQueue.front().RequestIn);
1568  UFSDevice[lun_id]->transferInfo.finished = true;
1569  UFSDevice[lun_id]->transferInfo.lunID = request_out_datain.LUN;
1570 
1576  if (request_out_datain.expectMore == 0x01) {
1579  length, sglist);
1580 
1581  } else if (request_out_datain.expectMore == 0x02) {
1584  request_out_datain.offset, length, sglist);
1585 
1586  } else {
1588  uint32_t count = 0;
1589  uint32_t size_accum = 0;
1590  DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1592 
1594  while ((length > count) && size_accum
1595  < (request_out_datain.msgSize - 1) &&
1596  (request_out_datain.msgSize != 0x00)) {
1597  Addr SCSI_start = sglist[count].upperAddr;
1598  SCSI_start = (SCSI_start << 32) |
1599  (sglist[count].baseAddr & 0xFFFFFFFF);
1600  DPRINTF(UFSHostDevice, "Data DMA start: 0x%8x\n", SCSI_start);
1601  DPRINTF(UFSHostDevice, "Data DMA size: 0x%8x\n",
1602  (sglist[count].size + 1));
1610  uint32_t size_to_send = sglist[count].size + 1;
1611 
1612  if (request_out_datain.msgSize < (size_to_send + size_accum))
1613  size_to_send = request_out_datain.msgSize - size_accum;
1614 
1615  readDevice(false, SCSI_start, size_to_send,
1616  reinterpret_cast<uint8_t*>
1617  (&(request_out_datain.message.dataMsg[size_accum])),
1618  false, NULL);
1619 
1620  size_accum += size_to_send;
1621  DPRINTF(UFSHostDevice, "Total remaining: 0x%8x,accumulated so far"
1622  " : 0x%8x\n", (request_out_datain.msgSize - size_accum),
1623  size_accum);
1624 
1625  ++count;
1626  DPRINTF(UFSHostDevice, "Transfer #: %d\n", count);
1627  }
1628 
1630  transferDone(response_addr, req_pos, UFSDevice[lun_id]->
1631  transferInfo.requestOut, finalsize, finaladdress,
1632  reinterpret_cast<uint8_t*>(request_in), true, lun_id);
1633  }
1634 
1635  DPRINTF(UFSHostDevice, "SCSI resume done\n");
1636 }
1637 
1643 void
1645 {
1646  uint8_t this_lun = 0;
1647 
1648  //while we haven't found the right lun, keep searching
1649  while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedCommand())
1650  ++this_lun;
1651 
1652  if (this_lun < lunAvail) {
1653  //Clear signal.
1654  UFSDevice[this_lun]->clearSignal();
1655  //found it; call transferDone
1656  transferDone(UFSDevice[this_lun]->transferInfo.responseStartAddr,
1657  UFSDevice[this_lun]->transferInfo.reqPos,
1658  UFSDevice[this_lun]->transferInfo.requestOut,
1659  UFSDevice[this_lun]->transferInfo.size,
1660  UFSDevice[this_lun]->transferInfo.address,
1661  UFSDevice[this_lun]->transferInfo.destination,
1662  UFSDevice[this_lun]->transferInfo.finished,
1663  UFSDevice[this_lun]->transferInfo.lunID);
1664  }
1665 
1666  else
1667  panic("no LUN finished in tick %d\n", curTick());
1668 }
1669 
1675 void
1676 UFSHostDevice::transferDone(Addr responseStartAddr, uint32_t req_pos,
1677  struct UTPUPIURSP request_out, uint32_t size,
1678  Addr address, uint8_t* destination,
1679  bool finished, uint32_t lun_id)
1680 {
1682  if (UFSDevice[lun_id]->SCSIInfoQueue.empty())
1683  panic("No SCSI message scheduled lun:%d Doorbell: 0x%8x", lun_id,
1685 
1686  DPRINTF(UFSHostDevice, "DMA start: 0x%8x; DMA size: 0x%8x\n",
1687  responseStartAddr, sizeof(request_out));
1688 
1689  struct transferStart lastinfo;
1690  lastinfo.mask = req_pos;
1691  lastinfo.done = finished;
1692  lastinfo.address = address;
1693  lastinfo.size = size;
1694  lastinfo.destination = reinterpret_cast<UTPTransferReqDesc*>
1695  (destination);
1696  lastinfo.lun_id = lun_id;
1697 
1698  transferEnd.push_back(lastinfo);
1699 
1700  DPRINTF(UFSHostDevice, "Transfer done start\n");
1701 
1702  readDevice(false, responseStartAddr, sizeof(request_out),
1703  reinterpret_cast<uint8_t*>
1704  (&(UFSDevice[lun_id]->transferInfo.requestOut)),
1705  true, &UTPEvent);
1706 }
1707 
1714 void
1716 {
1717  uint32_t lun_id = transferEnd.front().lun_id;
1718 
1719  UFSDevice[lun_id]->SCSIInfoQueue.pop_front();
1720  DPRINTF(UFSHostDevice, "SCSIInfoQueue size: %d, lun: %d\n",
1721  UFSDevice[lun_id]->SCSIInfoQueue.size(), lun_id);
1722 
1724  if (UFSHCIMem.TRUTRLDBR & transferEnd.front().mask) {
1725  uint8_t count = 0;
1726  while (!(transferEnd.front().mask & (0x1 << count)))
1727  ++count;
1728  stats.transactionLatency.sample(curTick() -
1730  }
1731 
1733  readDevice(true, transferEnd.front().address,
1734  transferEnd.front().size, reinterpret_cast<uint8_t*>
1735  (transferEnd.front().destination), true, NULL);
1736 
1738  transferTrack &= ~(transferEnd.front().mask);
1739  --activeDoorbells;
1740  ++pendingDoorbells;
1741  garbage.push_back(transferEnd.front().destination);
1742  transferEnd.pop_front();
1743  DPRINTF(UFSHostDevice, "UTP handled\n");
1744 
1746  stats.averageDoorbell = stats.maxDoorbell.value();
1747 
1748  DPRINTF(UFSHostDevice, "activeDoorbells: %d, pendingDoorbells: %d,"
1749  " garbage: %d, TransferEvent: %d\n", activeDoorbells,
1750  pendingDoorbells, garbage.size(), transferEventQueue.size());
1751 
1753  if (!UFSDevice[lun_id]->SCSIInfoQueue.empty())
1754  SCSIResume(lun_id);
1755 }
1756 
1760 void
1762 {
1763  DPRINTF(UFSHostDevice, "Read done start\n");
1764  --readPendingNum;
1765 
1767  if (garbage.size() > 0) {
1768  delete garbage.front();
1769  garbage.pop_front();
1770  }
1771 
1773  if (!(UFSHCIMem.ORInterruptStatus & 0x01)) {
1776  }
1777 
1778 
1779  if (!readDoneEvent.empty()) {
1780  readDoneEvent.pop_front();
1781  }
1782 }
1783 
1788 void
1790 {
1792  countInt++;
1793 
1796  pendingDoorbells = 0;
1797  DPRINTF(UFSHostDevice, "Clear doorbell %X\n", UFSHCIMem.TRUTRLDBR);
1798 
1799  checkDrain();
1800 
1802  gic->sendInt(intNum);
1803  DPRINTF(UFSHostDevice, "Send interrupt @ transaction: 0x%8x!\n",
1804  countInt);
1805 }
1806 
1811 void
1813 {
1814  gic->clearInt(intNum);
1815  DPRINTF(UFSHostDevice, "Clear interrupt: 0x%8x!\n", countInt);
1816 
1817  checkDrain();
1818 
1819  if (!(UFSHCIMem.TRUTRLDBR)) {
1820  idlePhaseStart = curTick();
1821  }
1823 }
1824 
1849 void
1850 UFSHostDevice::writeDevice(Event* additional_action, bool toDisk, Addr
1851  start, int size, uint8_t* destination, uint64_t
1852  SCSIDiskOffset, uint32_t lun_id)
1853 {
1854  DPRINTF(UFSHostDevice, "Write transaction Start: 0x%8x; Size: %d\n",
1855  start, size);
1856 
1858  if (toDisk) {
1859  ++writePendingNum;
1860 
1861  while (!writeDoneEvent.empty() && (writeDoneEvent.front().when()
1862  < curTick()))
1863  writeDoneEvent.pop_front();
1864 
1865  writeDoneEvent.push_back(
1866  EventFunctionWrapper([this]{ writeDone(); },
1867  name()));
1868  assert(!writeDoneEvent.back().scheduled());
1869 
1871  struct transferInfo new_transfer;
1872  new_transfer.offset = SCSIDiskOffset;
1873  new_transfer.size = size;
1874  new_transfer.lunID = lun_id;
1875  new_transfer.filePointer = 0;
1876  SSDWriteinfo.push_back(new_transfer);
1877 
1879  SSDWriteinfo.back().buffer.resize(size);
1880 
1882  dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1883  &writeDoneEvent.back(),
1884  &SSDWriteinfo.back().buffer[0], 0);
1885  //yes, a readreq at a write device function is correct.
1886  DPRINTF(UFSHostDevice, "Write to disk scheduled\n");
1887 
1888  } else {
1889  assert(!additional_action->scheduled());
1890  dmaPort.dmaAction(MemCmd::ReadReq, start, size,
1891  additional_action, destination, 0);
1892  DPRINTF(UFSHostDevice, "Write scheduled\n");
1893  }
1894 }
1895 
1901 void
1902 UFSHostDevice::manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t
1903  sg_table_length, struct UFSHCDSGEntry*
1904  sglist)
1905 {
1906  struct writeToDiskBurst next_packet;
1907 
1908  next_packet.SCSIDiskOffset = offset;
1909 
1910  UFSDevice[LUN]->setTotalWrite(sg_table_length);
1911 
1916  for (uint32_t count = 0; count < sg_table_length; count++) {
1917  next_packet.start = sglist[count].upperAddr;
1918  next_packet.start = (next_packet.start << 32) |
1919  (sglist[count].baseAddr & 0xFFFFFFFF);
1920  next_packet.LUN = LUN;
1921  DPRINTF(UFSHostDevice, "Write data DMA start: 0x%8x\n",
1922  next_packet.start);
1923  DPRINTF(UFSHostDevice, "Write data DMA size: 0x%8x\n",
1924  (sglist[count].size + 1));
1925  assert(sglist[count].size > 0);
1926 
1927  if (count != 0)
1928  next_packet.SCSIDiskOffset = next_packet.SCSIDiskOffset +
1929  (sglist[count - 1].size + 1);
1930 
1931  next_packet.size = sglist[count].size + 1;
1932 
1934  if (dmaWriteInfo.empty())
1935  writeDevice(NULL, true, next_packet.start, next_packet.size,
1936  NULL, next_packet.SCSIDiskOffset, next_packet.LUN);
1937  else
1938  DPRINTF(UFSHostDevice, "Write not initiated queue: %d\n",
1939  dmaWriteInfo.size());
1940 
1941  dmaWriteInfo.push_back(next_packet);
1942  DPRINTF(UFSHostDevice, "Write Location: 0x%8x\n",
1943  next_packet.SCSIDiskOffset);
1944 
1945  DPRINTF(UFSHostDevice, "Write transfer #: 0x%8x\n", count + 1);
1946 
1948  stats.totalWrittenSSD += (sglist[count].size + 1);
1949  }
1950 
1952  ++stats.totalWriteUFSTransactions;
1953 }
1954 
1960 void
1962 {
1964  assert(dmaWriteInfo.size() > 0);
1965  dmaWriteInfo.pop_front();
1966  assert(SSDWriteinfo.size() > 0);
1967  uint32_t lun = SSDWriteinfo.front().lunID;
1968 
1970  DPRINTF(UFSHostDevice, "Write done entered, queue: %d\n",
1971  UFSDevice[lun]->SSDWriteDoneInfo.size());
1973  UFSDevice[lun]->writeFlash(&SSDWriteinfo.front().buffer[0],
1974  SSDWriteinfo.front().offset,
1975  SSDWriteinfo.front().size);
1976 
1982  UFSDevice[lun]->SSDWriteDoneInfo.push_back(SSDWriteinfo.front());
1983  SSDWriteinfo.pop_front();
1984 
1985  --writePendingNum;
1987  UFSDevice[lun]->SSDWriteStart();
1988 
1990  stats.currentWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1991  stats.averageWriteSSDQueue = UFSDevice[lun]->SSDWriteDoneInfo.size();
1992  ++stats.totalWriteDiskTransactions;
1993 
1995  if (!dmaWriteInfo.empty())
1996  writeDevice(NULL, true, dmaWriteInfo.front().start,
1997  dmaWriteInfo.front().size, NULL,
1998  dmaWriteInfo.front().SCSIDiskOffset,
1999  dmaWriteInfo.front().LUN);
2000  DPRINTF(UFSHostDevice, "Write done end\n");
2001 }
2002 
2006 void
2008 {
2009  assert(SSDWriteDoneInfo.size() > 0);
2010  flashDevice->writeMemory(
2011  SSDWriteDoneInfo.front().offset,
2012  SSDWriteDoneInfo.front().size, memWriteCallback);
2013 
2014  SSDWriteDoneInfo.pop_front();
2015 
2016  DPRINTF(UFSHostDevice, "Write is started; left in queue: %d\n",
2017  SSDWriteDoneInfo.size());
2018 }
2019 
2020 
2025 void
2027 {
2028  DPRINTF(UFSHostDevice, "Write disk, aiming for %d messages, %d so far\n",
2029  totalWrite, amountOfWriteTransfers);
2030 
2031  //we have done one extra transfer
2032  ++amountOfWriteTransfers;
2033 
2035  assert(totalWrite >= amountOfWriteTransfers && totalWrite != 0);
2036 
2038  if (totalWrite == amountOfWriteTransfers) {
2039  DPRINTF(UFSHostDevice, "Write transactions finished\n");
2040  totalWrite = 0;
2041  amountOfWriteTransfers = 0;
2042 
2043  //Callback UFS Host
2044  setSignal();
2045  signalDone();
2046  }
2047 
2048 }
2049 
2055 void
2056 UFSHostDevice::readDevice(bool lastTransfer, Addr start, uint32_t size,
2057  uint8_t* destination, bool no_cache, Event*
2058  additional_action)
2059 {
2060  DPRINTF(UFSHostDevice, "Read start: 0x%8x; Size: %d, data[0]: 0x%8x\n",
2061  start, size, (reinterpret_cast<uint32_t *>(destination))[0]);
2062 
2064  if (lastTransfer) {
2065  ++readPendingNum;
2066  readDoneEvent.push_back(
2067  EventFunctionWrapper([this]{ readDone(); },
2068  name()));
2069  assert(!readDoneEvent.back().scheduled());
2070  dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2071  &readDoneEvent.back(), destination, 0);
2072  //yes, a writereq at a read device function is correct.
2073 
2074  } else {
2075  if (additional_action != NULL)
2076  assert(!additional_action->scheduled());
2077 
2078  dmaPort.dmaAction(MemCmd::WriteReq, start, size,
2079  additional_action, destination, 0);
2080 
2081  }
2082 
2083 }
2084 
2090 void
2091 UFSHostDevice::manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t
2092  offset, uint32_t sg_table_length,
2093  struct UFSHCDSGEntry* sglist)
2094 {
2095  uint32_t size_accum = 0;
2096 
2097  DPRINTF(UFSHostDevice, "Data READ size: %d\n", size);
2098 
2103  for (uint32_t count = 0; count < sg_table_length; count++) {
2104  struct transferInfo new_transfer;
2105  new_transfer.offset = sglist[count].upperAddr;
2106  new_transfer.offset = (new_transfer.offset << 32) |
2107  (sglist[count].baseAddr & 0xFFFFFFFF);
2108  new_transfer.filePointer = offset + size_accum;
2109  new_transfer.size = (sglist[count].size + 1);
2110  new_transfer.lunID = LUN;
2111 
2112  DPRINTF(UFSHostDevice, "Data READ start: 0x%8x; size: %d\n",
2113  new_transfer.offset, new_transfer.size);
2114 
2115  UFSDevice[LUN]->SSDReadInfo.push_back(new_transfer);
2116  UFSDevice[LUN]->SSDReadInfo.back().buffer.resize(sglist[count].size
2117  + 1);
2118 
2124  UFSDevice[LUN]->readFlash(&UFSDevice[LUN]->
2125  SSDReadInfo.back().buffer[0],
2126  offset + size_accum,
2127  sglist[count].size + 1);
2128 
2129  size_accum += (sglist[count].size + 1);
2130 
2131  DPRINTF(UFSHostDevice, "Transfer %d; Remaining: 0x%8x, Accumulated:"
2132  " 0x%8x\n", (count + 1), (size-size_accum), size_accum);
2133 
2135  stats.totalReadSSD += (sglist[count].size + 1);
2136  stats.currentReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2137  stats.averageReadSSDQueue = UFSDevice[LUN]->SSDReadInfo.size();
2138  }
2139 
2140  UFSDevice[LUN]->SSDReadStart(sg_table_length);
2141 
2143  ++stats.totalReadUFSTransactions;
2144 
2145 }
2146 
2147 
2148 
2155 void
2157 {
2158  totalRead = total_read;
2159  for (uint32_t number_handled = 0; number_handled < SSDReadInfo.size();
2160  number_handled++) {
2165  flashDevice->readMemory(SSDReadInfo.front().filePointer,
2166  SSDReadInfo.front().size, memReadCallback);
2167  }
2168 
2169 }
2170 
2171 
2176 void
2178 {
2179  DPRINTF(UFSHostDevice, "SSD read done at lun %d, Aiming for %d messages,"
2180  " %d so far\n", lunID, totalRead, amountOfReadTransfers);
2181 
2182  if (totalRead == amountOfReadTransfers) {
2183  totalRead = 0;
2184  amountOfReadTransfers = 0;
2185 
2187  setSignal();
2188  signalDone();
2189  }
2190 
2191 }
2192 
2197 void
2199 {
2200  ++amountOfReadTransfers;
2201 
2205  setReadSignal();
2206  deviceReadCallback();
2207 
2208  //Are we done yet?
2209  SSDReadDone();
2210 }
2211 
2217 void
2219 {
2220  DPRINTF(UFSHostDevice, "Read Callback\n");
2221  uint8_t this_lun = 0;
2222 
2223  //while we haven't found the right lun, keep searching
2224  while ((this_lun < lunAvail) && !UFSDevice[this_lun]->finishedRead())
2225  ++this_lun;
2226 
2227  DPRINTF(UFSHostDevice, "Found LUN %d messages pending for clean: %d\n",
2228  this_lun, SSDReadPending.size());
2229 
2230  if (this_lun < lunAvail) {
2231  //Clear signal.
2232  UFSDevice[this_lun]->clearReadSignal();
2233  SSDReadPending.push_back(UFSDevice[this_lun]->SSDReadInfo.front());
2234  UFSDevice[this_lun]->SSDReadInfo.pop_front();
2235  readGarbageEventQueue.push_back(
2236  EventFunctionWrapper([this]{ readGarbage(); }, name()));
2237 
2238  //make sure the queue is popped a the end of the dma transaction
2239  readDevice(false, SSDReadPending.front().offset,
2240  SSDReadPending.front().size,
2241  &SSDReadPending.front().buffer[0], false,
2242  &readGarbageEventQueue.back());
2243 
2245  ++stats.totalReadDiskTransactions;
2246  }
2247  else
2248  panic("no read finished in tick %d\n", curTick());
2249 }
2250 
2255 void
2257 {
2258  DPRINTF(UFSHostDevice, "Clean read data, %d\n", SSDReadPending.size());
2259  SSDReadPending.pop_front();
2260  readGarbageEventQueue.pop_front();
2261 }
2262 
2267 void
2269 {
2271 
2272  const uint8_t* temp_HCI_mem = reinterpret_cast<const uint8_t*>(&UFSHCIMem);
2273  SERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2274 
2275  uint32_t lun_avail = lunAvail;
2276  SERIALIZE_SCALAR(lun_avail);
2277 }
2278 
2279 
2284 void
2286 {
2288  uint8_t* temp_HCI_mem = reinterpret_cast<uint8_t*>(&UFSHCIMem);
2289  UNSERIALIZE_ARRAY(temp_HCI_mem, sizeof(HCIMem));
2290 
2291  uint32_t lun_avail;
2292  UNSERIALIZE_SCALAR(lun_avail);
2293  assert(lunAvail == lun_avail);
2294 }
2295 
2296 
2301 DrainState
2303 {
2304  if (UFSHCIMem.TRUTRLDBR) {
2305  DPRINTF(UFSHostDevice, "UFSDevice is draining...\n");
2306  return DrainState::Draining;
2307  } else {
2308  DPRINTF(UFSHostDevice, "UFSDevice drained\n");
2309  return DrainState::Drained;
2310  }
2311 }
2312 
2317 void
2319 {
2321  return;
2322 
2323  if (UFSHCIMem.TRUTRLDBR) {
2324  DPRINTF(UFSHostDevice, "UFSDevice is still draining; with %d active"
2325  " doorbells\n", activeDoorbells);
2326  } else {
2327  DPRINTF(UFSHostDevice, "UFSDevice is done draining\n");
2328  signalDrainDone();
2329  }
2330 }
2331 
2332 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
virtual void initializeMemory(uint64_t disk_size, uint32_t sector_size)=0
Initialize Memory.
virtual void clearInt(uint32_t num)=0
Clear an interrupt from a device that is connected to the GIC.
virtual void sendInt(uint32_t num)=0
Post an interrupt from a device that is connected to the GIC.
void serialize(CheckpointOut &cp) const override
Serialize an object.
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void dmaAction(Packet::Command cmd, Addr addr, int size, Event *event, uint8_t *data, Tick delay, Request::Flags flag=0)
Definition: dma_device.cc:196
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
void setLE(T v)
Set the value in the data pointer to v as little endian.
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition: packet.hh:1059
unsigned getSize() const
Definition: packet.hh:815
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
Definition: packet.cc:352
Abstract superclass for simulation objects.
Definition: sim_object.hh:148
static const unsigned int cachingPage[5]
Definition: ufs_device.hh:776
void SSDWriteStart()
SSD write start.
Definition: ufs_device.cc:2007
void SSDReadDone()
SSD Read done; Determines if the final callback of the transaction should be made at the end of a rea...
Definition: ufs_device.cc:2177
static const unsigned int controlPage[3]
These pages are SCSI specific.
Definition: ufs_device.hh:774
std::function< void()> Callback
Definition: ufs_device.hh:562
UFSSCSIDevice(const UFSHostDeviceParams &p, uint32_t lun_id, const Callback &transfer_cb, const Callback &read_cb)
Constructor and destructor.
Definition: ufs_device.cc:78
void writeFlash(uint8_t *writeaddr, uint64_t offset, uint32_t size)
Write flash.
Definition: ufs_device.cc:705
void readFlash(uint8_t *readaddr, uint64_t offset, uint32_t size)
Disk access functions.
Definition: ufs_device.cc:691
void statusCheck(uint8_t status, uint8_t *sensecodelist)
Status of SCSI.
Definition: ufs_device.cc:674
Callback signalDone
Callbacks between Host and Device.
Definition: ufs_device.hh:751
Callback memReadCallback
Callbacks between Device and Memory.
Definition: ufs_device.hh:757
static const unsigned int recoveryPage[3]
Definition: ufs_device.hh:775
struct SCSIReply SCSICMDHandle(uint32_t *SCSI_msg)
SCSI command handle function; determines what the command is and returns a reply structure that allow...
Definition: ufs_device.cc:160
struct LUNInfo lunInfo
Logic unit info; needed for SCSI Info messages and LU identification.
Definition: ufs_device.hh:725
void readCallback()
Functions to indicate that the action to the SSD has completed.
Definition: ufs_device.cc:2198
void SSDReadStart(uint32_t total_read)
Start the transactions to (and from) the disk The host will queue all the transactions.
Definition: ufs_device.cc:2156
void SSDWriteDone()
SSD Write Done; This is the callback function for the memory model.
Definition: ufs_device.cc:2026
Host controller layer: This is your Host controller This layer handles the UFS functionality.
Definition: ufs_device.hh:173
int readPendingNum
Track number of DMA transactions in progress.
Definition: ufs_device.hh:1040
void taskHandler(struct UTPUPIUTaskReq *request_in, uint32_t req_pos, Addr finaladdress, uint32_t finalsize)
Task handler function.
Definition: ufs_device.cc:1368
std::deque< EventFunctionWrapper > taskEventQueue
Multiple tasks transfers can be scheduled at once for the device, the only thing we know for sure abo...
Definition: ufs_device.hh:1190
void generateInterrupt()
set interrupt and sort out the doorbell register.
Definition: ufs_device.cc:1789
void writeDone()
Write done After a DMA write with data intended for the disk, this function is called.
Definition: ufs_device.cc:1961
std::deque< struct taskStart > taskInfo
When a task/transfer is started it needs information about the task/transfer it is about to perform.
Definition: ufs_device.hh:1123
std::deque< struct transferInfo > SSDWriteinfo
Information from DMA transaction to disk.
Definition: ufs_device.hh:1134
static const unsigned int UICCommandReady
Definition: ufs_device.hh:1199
std::deque< EventFunctionWrapper > transferEventQueue
Definition: ufs_device.hh:1191
EventFunctionWrapper SCSIResumeEvent
The events that control the functionality.
Definition: ufs_device.hh:1173
void serialize(CheckpointOut &cp) const override
Serialize; needed to make checkpoints.
Definition: ufs_device.cc:2268
void transferHandler(struct UTPTransferReqDesc *request_in, int req_pos, Addr finaladdress, uint32_t finalsize, uint32_t done)
Transfer handler function.
Definition: ufs_device.cc:1404
Tick transactionStart[32]
Helper for latency stats These variables keep track of the latency for every doorbell.
Definition: ufs_device.hh:1080
const Addr pioAddr
Host controller information.
Definition: ufs_device.hh:1024
void commandHandler()
Command handler function.
Definition: ufs_device.cc:1354
HCIMem UFSHCIMem
Host controller memory.
Definition: ufs_device.hh:1035
struct SCSIReply request_out_datain
SCSI reply structure, used for direct answering.
Definition: ufs_device.hh:1095
static const unsigned int UTPTaskREQCOMPL
Definition: ufs_device.hh:1197
void clearInterrupt()
Interrupt control functions.
Definition: ufs_device.cc:1812
static const unsigned int UTPTransferREQCOMPL
Bits of interest within UFS data packages.
Definition: ufs_device.hh:1196
static const unsigned int UICCommandCOMPL
Definition: ufs_device.hh:1198
void writeDevice(Event *additional_action, bool toDisk, Addr start, int size, uint8_t *destination, uint64_t SCSIDiskOffset, uint32_t lun_id)
DMA transfer functions These allow the host to push/pull the data to the memory The provided event in...
Definition: ufs_device.cc:1850
void finalUTP()
final UTP, sends the last acknowledge data structure to the system; prepares the clean up functions.
Definition: ufs_device.cc:1715
std::deque< struct writeToDiskBurst > dmaWriteInfo
Information to get a DMA transaction.
Definition: ufs_device.hh:1129
uint32_t transferTrack
Track the transfer This is allows the driver to "group" certain transfers together by using a tag in ...
Definition: ufs_device.hh:1072
DrainState drain() override
Drain; needed to enable checkpoints.
Definition: ufs_device.cc:2302
void setValues()
Initialization function.
Definition: ufs_device.cc:876
void requestHandler()
Handler functions.
Definition: ufs_device.cc:1201
void unserialize(CheckpointIn &cp) override
Unserialize; needed to restore from checkpoints.
Definition: ufs_device.cc:2285
void manageWriteTransfer(uint8_t LUN, uint64_t offset, uint32_t sg_table_length, struct UFSHCDSGEntry *sglist)
Disk transfer management functions these set up the queues, and initiated them, leading to the data t...
Definition: ufs_device.cc:1902
struct SCSIResumeInfo SCSIInfo
SCSI resume info information structure for SCSI resume.
Definition: ufs_device.hh:1103
Tick read(PacketPtr pkt) override
register access functions
Definition: ufs_device.cc:916
struct UFSHostDeviceStats stats
RequestHandler stats.
Definition: ufs_device.hh:1149
void readGarbage()
Read garbage A read from disk data structure can vary in size and is therefor allocated on creation.
Definition: ufs_device.cc:2256
std::deque< struct transferStart > transferEnd
To finish the transaction one needs information about the original message.
Definition: ufs_device.hh:1112
std::deque< EventFunctionWrapper > readDoneEvent
Transfer flow events Basically these events form two queues, one from memory to UFS device (DMA) and ...
Definition: ufs_device.hh:1160
uint32_t countInt
interrupt verification This keeps track of the number of interrupts generated.
Definition: ufs_device.hh:1062
std::deque< struct UTPTransferReqDesc * > garbage
garbage queue, ensure clearing of the allocated memory
Definition: ufs_device.hh:1144
uint8_t activeDoorbells
Statistics helper variables Active doorbells indicates how many doorbells are in teh process of being...
Definition: ufs_device.hh:1052
void manageReadTransfer(uint32_t size, uint32_t LUN, uint64_t offset, uint32_t sg_table_length, struct UFSHCDSGEntry *sglist)
Manage read transfer.
Definition: ufs_device.cc:2091
std::vector< UFSSCSIDevice * > UFSDevice
logic units connected to the UFS Host device Note again that the "device" as such is represented by o...
Definition: ufs_device.hh:1088
std::deque< struct transferInfo > SSDReadPending
Information from the Disk, waiting to be pushed to the DMA.
Definition: ufs_device.hh:1139
void SCSIResume(uint32_t lun_id)
Starts the scsi handling function in the apropriate Logic unit, prepares the right data transfer sche...
Definition: ufs_device.cc:1492
std::deque< EventFunctionWrapper > writeDoneEvent
Definition: ufs_device.hh:1161
Tick write(PacketPtr pkt) override
UFSHCD write function.
Definition: ufs_device.cc:1054
std::deque< struct transferStart > transferStartInfo
Definition: ufs_device.hh:1124
AddrRangeList getAddrRanges() const override
Address range functions.
Definition: ufs_device.cc:903
std::deque< EventFunctionWrapper > readGarbageEventQueue
Event after a read to clean up the UTP data structures.
Definition: ufs_device.hh:1183
EventFunctionWrapper UTPEvent
Wait for the moment where we can send the last frame.
Definition: ufs_device.hh:1178
void readCallback()
Read callback Call back function for the logic units to indicate the completion of a read action.
Definition: ufs_device.cc:2218
UFSHostDevice(const UFSHostDeviceParams &p)
Constructor for the UFS Host device.
Definition: ufs_device.cc:718
void transferStart()
Transfer Start function.
Definition: ufs_device.cc:1334
void taskStart()
Task Start function.
Definition: ufs_device.cc:1320
void transferDone(Addr responseStartAddr, uint32_t req_pos, struct UTPUPIURSP request_out, uint32_t size, Addr address, uint8_t *destination, bool finished, uint32_t lun_id)
transfer done, the beginning of the final stage of the transfer.
Definition: ufs_device.cc:1676
void LUNSignal()
LU callback function to indicate that the action has completed.
Definition: ufs_device.cc:1644
void readDone()
Read done Started at the end of a transaction after the last read action.
Definition: ufs_device.cc:1761
void readDevice(bool lastTransfer, Addr SCSIStart, uint32_t SCSISize, uint8_t *SCSIDestination, bool no_cache, Event *additional_action)
Dma transaction function: read device.
Definition: ufs_device.cc:2056
void checkDrain()
Checkdrain; needed to enable checkpoints.
Definition: ufs_device.cc:2318
const uint32_t lunAvail
Definition: ufs_device.hh:1029
const uint8_t UFSSlots
Definition: ufs_device.hh:1030
void SCSIStart()
Transfer SCSI function.
Definition: ufs_device.cc:1447
uint32_t taskCommandTrack
Definition: ufs_device.hh:1073
Derived & flags(Flags _flags)
Set the flags and marks this stat to print at the end of simulation.
Definition: statistics.hh:358
Statistics container.
Definition: group.hh:94
std::vector< Info * > stats
Definition: group.hh:221
Histogram & init(size_type size)
Set the parameters of this histogram.
Definition: statistics.hh:2154
#define SectorSize
Definition: disk_image.hh:44
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
AddrRange RangeSize(Addr start, Addr size)
Definition: addr_range.hh:815
constexpr uint64_t mask(unsigned nbits)
Generate a 64-bit mask of 'nbits' 1s, right justified.
Definition: bitfield.hh:63
constexpr int findLsbSet(uint64_t val)
Returns the bit position of the LSB that is set in the input.
Definition: bitfield.hh:296
void signalDrainDone() const
Signal that an object is drained.
Definition: drain.hh:305
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
DrainState
Object drain/handover states.
Definition: drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
@ Drained
Buffers drained, ready for serialization/handover.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:610
#define warn(...)
Definition: logging.hh:246
#define inform(...)
Definition: logging.hh:247
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 5, 0 > status
Definition: misc_types.hh:429
Bitfield< 47, 6 > baseAddr
Definition: pagetable.hh:71
Bitfield< 54 > p
Definition: pagetable.hh:70
const FlagsType pdf
Print the percent of the total that this entry represents.
Definition: info.hh:62
const FlagsType nozero
Don't print if this is zero.
Definition: info.hh:68
const FlagsType none
Nothing extra to print.
Definition: info.hh:54
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
T betoh(T value)
Definition: byteswap.hh:175
uint64_t Tick
Tick count type.
Definition: types.hh:58
statistics::Formula & simSeconds
Definition: stats.cc:45
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
Host Controller Interface This is a set of registers that allow the driver to control the transaction...
Definition: ufs_device.hh:192
uint32_t TMUTMRLBA
Task control registers.
Definition: ufs_device.hh:232
uint32_t TRUTRLBA
Transfer control registers.
Definition: ufs_device.hh:223
uint32_t ORInterruptStatus
Operation and runtime registers.
Definition: ufs_device.hh:204
uint32_t CMDUICCMDR
Command registers.
Definition: ufs_device.hh:241
uint32_t HCCAP
Specify the host capabilities.
Definition: ufs_device.hh:196
SCSI reply structure.
Definition: ufs_device.hh:387
struct UPIUMessage message
Definition: ufs_device.hh:395
struct UTPTransferReqDesc * RequestIn
Definition: ufs_device.hh:495
std::vector< uint8_t > destination
Definition: ufs_device.hh:499
struct UFSHCDSGEntry - UFSHCI PRD Entry baseAddr: Lower 32bit physical address DW-0 upperAddr: Upper ...
Definition: ufs_device.hh:309
statistics::Average averageSCSIQueue
Average Queue lengths.
Definition: ufs_device.hh:540
statistics::Scalar totalWriteUFSTransactions
Definition: ufs_device.hh:533
statistics::Formula averageReadSSDBW
Average bandwidth for reads and writes.
Definition: ufs_device.hh:536
statistics::Scalar totalReadDiskTransactions
Definition: ufs_device.hh:530
statistics::Scalar totalWriteDiskTransactions
Definition: ufs_device.hh:531
UFSHostDeviceStats(UFSHostDevice *parent)
Amount of data read/written.
Definition: ufs_device.cc:760
statistics::Average averageWriteSSDQueue
Definition: ufs_device.hh:542
statistics::Histogram transactionLatency
Histogram of latencies.
Definition: ufs_device.hh:550
statistics::Scalar totalReadSSD
Amount of data read/written.
Definition: ufs_device.hh:528
statistics::Formula curDoorbell
Number of doorbells rung.
Definition: ufs_device.hh:545
statistics::Scalar currentSCSIQueue
Queue lengths.
Definition: ufs_device.hh:523
statistics::Scalar totalReadUFSTransactions
Definition: ufs_device.hh:532
std::vector< uint32_t > dataMsg
Definition: ufs_device.hh:338
struct UTPTransferReqDesc - UTRD structure header: UTRD header DW-0 to DW-3 commandDescBaseAddrLo: UC...
Definition: ufs_device.hh:352
struct gem5::UFSHostDevice::UTPTransferReqDesc::RequestDescHeader header
struct UTPUPIURSP - Response UPIU structure header: UPIU header DW-0 to DW-2 residualTransferCount: R...
Definition: ufs_device.hh:276
struct UTPUPIUTaskReq - Task request UPIU structure header - UPIU header structure DW0 to DW-2 inputP...
Definition: ufs_device.hh:293
Task start information.
Definition: ufs_device.hh:481
Different events, and scenarios require different types of information.
Definition: ufs_device.hh:440
Transfer start information.
Definition: ufs_device.hh:468
struct UTPTransferReqDesc * destination
Definition: ufs_device.hh:469
Disk transfer burst information.
Definition: ufs_device.hh:508
const std::string & name()
Definition: trace.cc:49
This is a base class for UFS devices The UFS interface consists out of one host controller which conn...

Generated on Wed Dec 21 2022 10:22:33 for gem5 by doxygen 1.9.1